// -*- c-basic-offset: 4; related-file-name: "../../lib/router.cc" -*- #ifndef CLICK_ROUTER_HH #define CLICK_ROUTER_HH #include #include #include #include #include #if CLICK_NS # include #endif CLICK_DECLS class Master; class ElementFilter; class RouterVisitor; class RouterThread; class HashMap_ArenaFactory; class NotifierSignal; class ThreadSched; class Handler; class NameInfo; class Router { public: /** @name Public Member Functions */ //@{ // MASTER inline Master* master() const; // STATUS inline bool initialized() const; inline bool handlers_ready() const; inline bool running() const; inline bool dying() const; // RUNCOUNT AND RUNCLASS enum { STOP_RUNCOUNT = -2147483647 - 1 }; inline int32_t runcount() const; void adjust_runcount(int32_t delta); void set_runcount(int32_t rc); inline void please_stop_driver(); // ELEMENTS inline const Vector& elements() const; inline int nelements() const; inline Element* element(int i) const; inline Element* root_element() const; static Element* element(const Router *router, int i); const String& ename(int i) const; String ename_context(int i) const; String elandmark(int i) const; const String& econfiguration(int i) const; void set_econfiguration(int i, const String& conf); Element* find(const String& name, ErrorHandler* errh = 0) const; Element* find(const String& name, String context, ErrorHandler* errh = 0) const; Element* find(const String& name, const Element* context, ErrorHandler* errh = 0) const; int visit(Element *e, bool isoutput, int port, RouterVisitor *visitor) const; int visit_downstream(Element *e, int port, RouterVisitor *visitor) const; int visit_upstream(Element *e, int port, RouterVisitor *visitor) const; int downstream_elements(Element *e, int port, ElementFilter *filter, Vector &result) CLICK_DEPRECATED; int upstream_elements(Element *e, int port, ElementFilter *filter, Vector &result) CLICK_DEPRECATED; inline const char *flow_code_override(int eindex) const; void set_flow_code_override(int eindex, const String &flow_code); // HANDLERS // 'const Handler *' results last until that element/handlername modified static const Handler *handler(const Element *e, const String &hname); static void add_read_handler(const Element *e, const String &hname, ReadHandlerCallback callback, void *user_data, uint32_t flags = 0); static void add_write_handler(const Element *e, const String &hname, WriteHandlerCallback callback, void *user_data, uint32_t flags = 0); static void set_handler(const Element *e, const String &hname, uint32_t flags, HandlerCallback callback, void *read_user_data = 0, void *write_user_data = 0); static int set_handler_flags(const Element *e, const String &hname, uint32_t set_flags, uint32_t clear_flags = 0); enum { FIRST_GLOBAL_HANDLER = 0x40000000 }; static int hindex(const Element *e, const String &hname); static const Handler *handler(const Router *router, int hindex); static void element_hindexes(const Element *e, Vector &result); // ATTACHMENTS AND REQUIREMENTS void* attachment(const String& aname) const; void*& force_attachment(const String& aname); void* set_attachment(const String& aname, void* value); ErrorHandler* chatter_channel(const String& channel_name) const; HashMap_ArenaFactory* arena_factory() const; inline ThreadSched* thread_sched() const; inline void set_thread_sched(ThreadSched* scheduler); inline int home_thread_id(const Element* e) const; inline void set_home_thread_id(const Element* e, int home_thread); /** @cond never */ // Needs to be public for NameInfo, but not useful outside inline NameInfo* name_info() const; NameInfo* force_name_info(); /** @endcond never */ // UNPARSING String configuration_string() const; void unparse(StringAccum& sa, const String& indent = String()) const; void unparse_requirements(StringAccum& sa, const String& indent = String()) const; void unparse_declarations(StringAccum& sa, const String& indent = String()) const; void unparse_connections(StringAccum& sa, const String& indent = String()) const; String element_ports_string(const Element *e) const; //@} // INITIALIZATION /** @name Internal Functions */ //@{ Router(const String& configuration, Master* master); ~Router(); static void static_initialize(); static void static_cleanup(); inline void use(); void unuse(); void add_requirement(const String &type, const String &value); int add_element(Element *e, const String &name, const String &conf, const String &filename, unsigned lineno); int add_connection(int from_idx, int from_port, int to_idx, int to_port); #if CLICK_LINUXMODULE int add_module_ref(struct module* module); #endif inline Router* hotswap_router() const; void set_hotswap_router(Router* router); int initialize(ErrorHandler* errh); void activate(bool foreground, ErrorHandler* errh); inline void activate(ErrorHandler* errh); inline void set_foreground(bool foreground); int new_notifier_signal(const char *name, NotifierSignal &signal); String notifier_signal_name(const atomic_uint32_t *signal) const; //@} /** @cond never */ // Needs to be public for Lexer, etc., but not useful outside struct Port { int idx; int port; Port() { } Port(int i, int p) : idx(i), port(p) { } bool operator==(const Port &x) const { return idx == x.idx && port == x.port; } bool operator!=(const Port &x) const { return idx != x.idx || port != x.port; } bool operator<(const Port &x) const { return idx < x.idx || (idx == x.idx && port < x.port); } bool operator<=(const Port &x) const { return idx < x.idx || (idx == x.idx && port <= x.port); } }; struct Connection { Port p[2]; Connection() { } Connection(int from_idx, int from_port, int to_idx, int to_port) { p[0] = Port(to_idx, to_port); p[1] = Port(from_idx, from_port); } const Port &operator[](int i) const { assert(i >= 0 && i < 2); return p[i]; } Port &operator[](int i) { assert(i >= 0 && i < 2); return p[i]; } bool operator==(const Connection &x) const { return p[0] == x.p[0] && p[1] == x.p[1]; } bool operator<(const Connection &x) const { return p[0] < x.p[0] || (p[0] == x.p[0] && p[1] < x.p[1]); } }; /** @endcond never */ #if CLICK_NS simclick_node_t *simnode() const; int sim_get_ifid(const char* ifname); int sim_listen(int ifid, int element); int sim_if_ready(int ifid); int sim_write(int ifid, int ptype, const unsigned char *, int len, simclick_simpacketinfo *pinfo); int sim_incoming_packet(int ifid, int ptype, const unsigned char *, int len, simclick_simpacketinfo* pinfo); void sim_trace(const char* event); int sim_get_node_id(); int sim_get_next_pkt_id(); int sim_if_promisc(int ifid); protected: Vector *> _listenvecs; Vector* sim_listenvec(int ifid); #endif private: class RouterContextErrh; enum { ROUTER_NEW, ROUTER_PRECONFIGURE, ROUTER_PREINITIALIZE, ROUTER_LIVE, ROUTER_DEAD // order is important }; enum { RUNNING_DEAD = -2, RUNNING_INACTIVE = -1, RUNNING_PREPARING = 0, RUNNING_BACKGROUND = 1, RUNNING_ACTIVE = 2 }; Master* _master; atomic_uint32_t _runcount; volatile int _state; bool _have_connections : 1; mutable bool _conn_sorted : 1; bool _have_configuration : 1; volatile int _running; atomic_uint32_t _refcount; Vector _elements; Vector _element_names; Vector _element_configurations; Vector _element_landmarkids; mutable Vector _element_home_thread_ids; struct element_landmark_t { uint32_t first_landmarkid; String filename; }; Vector _element_landmarks; uint32_t _last_landmarkid; mutable Vector _element_name_sorter; Vector _element_gport_offset[2]; Vector _element_configure_order; mutable Vector _conn; mutable Vector _conn_output_sorter; Vector _requirements; Vector _ehandler_first_by_element; Vector _ehandler_to_handler; Vector _ehandler_next; Vector _handler_first_by_name; enum { HANDLER_BUFSIZ = 256 }; Handler** _handler_bufs; int _nhandlers_bufs; int _free_handler; Vector _attachment_names; Vector _attachments; Element* _root_element; String _configuration; struct notifier_signals_t { enum { capacity = 4096 }; String name; int nsig; atomic_uint32_t sig[capacity / 32]; notifier_signals_t *next; notifier_signals_t(const String &n, notifier_signals_t *nx) : name(n), nsig(0), next(nx) { memset(&sig[0], 0, sizeof(sig)); } }; notifier_signals_t *_notifier_signals; HashMap_ArenaFactory* _arena_factory; Router* _hotswap_router; ThreadSched* _thread_sched; mutable NameInfo* _name_info; Vector _flow_code_override_eindex; Vector _flow_code_override; Router* _next_router; #if CLICK_LINUXMODULE Vector _modules; #endif Router(const Router&); Router& operator=(const Router&); Connection *remove_connection(Connection *cp); void hookup_error(const Port &p, bool isoutput, const char *message, ErrorHandler *errh, bool active = false); int check_hookup_elements(ErrorHandler*); int check_hookup_range(ErrorHandler*); int check_hookup_completeness(ErrorHandler*); const char *hard_flow_code_override(int e) const; int processing_error(const Connection &conn, bool, int, ErrorHandler*); int check_push_and_pull(ErrorHandler*); void set_connections(); void sort_connections() const; int connindex_lower_bound(bool isoutput, const Port &port) const; void make_gports(); inline int ngports(bool isout) const { return _element_gport_offset[isout].back(); } inline int gport(bool isoutput, const Port &port) const; int hard_home_thread_id(const Element *e) const; int element_lerror(ErrorHandler*, Element*, const char*, ...) const; // private handler methods void initialize_handlers(bool, bool); inline Handler* xhandler(int) const; int find_ehandler(int, const String&, bool allow_star) const; static inline Handler fetch_handler(const Element*, const String&); void store_local_handler(int eindex, Handler &h); static void store_global_handler(Handler &h); static inline void store_handler(const Element *element, Handler &h); // global handlers static String router_read_handler(Element *e, void *user_data); static int router_write_handler(const String &str, Element *e, void *user_data, ErrorHandler *errh); /** @cond never */ friend class Master; friend class Task; friend int Element::set_nports(int, int); /** @endcond never */ }; /** @brief Increment the router's reference count. * * Routers are reference counted objects. A Router is created with one * reference, which is held by its Master object. Normally the Router and * all its elements will be deleted when the Master drops this reference, but * you can preserve the Router for longer by adding a reference yourself. */ inline void Router::use() { _refcount++; } /** @brief Return true iff the router is currently running. * * A running router has been successfully initialized (so running() implies * initialized()), and has not stopped yet. */ inline bool Router::running() const { return _running > 0; } /** @brief Return true iff the router is in the process of being killed. */ inline bool Router::dying() const { return _running == RUNNING_DEAD; } /** @brief Return true iff the router has been successfully initialized. */ inline bool Router::initialized() const { return _state == ROUTER_LIVE; } /** @brief Return true iff the router's handlers have been initialized. * * handlers_ready() returns false until each element's * Element::add_handlers() method has been called. This happens after * Element::configure(), but before Element::initialize(). */ inline bool Router::handlers_ready() const { return _state > ROUTER_PRECONFIGURE; } /** @brief Returns a vector containing all the router's elements. * @invariant elements()[i] == element(i) for all i in range. */ inline const Vector& Router::elements() const { return _elements; } /** @brief Returns the number of elements in the router. */ inline int Router::nelements() const { return _elements.size(); } /** @brief Returns the element with index @a i. * @param i element index, or -1 for root_element() * @invariant If element(i) isn't null, then element(i)->@link Element::eindex eindex@endlink() == i. * * This function returns the element with index @a i. If @a i == * -1, returns root_element(). If @a i is otherwise out of range, * returns null. */ inline Element* Router::element(int i) const { return element(this, i); } /** @brief Returns this router's root element. * * Every router has a root Element. This element has Element::eindex() -1 and * name "". It is not configured or initialized, and doesn't appear in the * configuration; it exists only for convenience, when other Click code needs * to refer to some arbitrary element at the top level of the compound * element hierarchy. */ inline Element* Router::root_element() const { return _root_element; } inline ThreadSched* Router::thread_sched() const { return _thread_sched; } inline void Router::set_thread_sched(ThreadSched* ts) { _thread_sched = ts; } inline int Router::home_thread_id(const Element* e) const { if (initialized()) return _element_home_thread_ids[e->eindex() + 1]; else return hard_home_thread_id(e); } inline void Router::set_home_thread_id(const Element* e, int home_thread_id) { _element_home_thread_ids[e->eindex() + 1] = home_thread_id; } /** @cond never */ /** @brief Return the NameInfo object for this router, if it exists. * * Users never need to call this. */ inline NameInfo* Router::name_info() const { return _name_info; } /** @endcond never */ /** @brief Return the Master object for this router. */ inline Master* Router::master() const { return _master; } /** @brief Return the router's runcount. * * The runcount is an integer that determines whether the router is running. * A running router has positive runcount. Decrementing the router's runcount * to zero or below will cause the router to stop, although elements like * DriverManager can intercept the stop request and continue processing. * * Elements request that the router stop its processing by calling * adjust_runcount() or please_stop_driver(). */ inline int32_t Router::runcount() const { return _runcount.value(); } /** @brief Request a driver stop by adjusting the runcount by -1. * @note Equivalent to adjust_runcount(-1). */ inline void Router::please_stop_driver() { adjust_runcount(-1); } /** @brief Returns the overriding flow code for element @a e, if any. * @param eindex element index * @return The flow code, or null if none has been set. */ inline const char * Router::flow_code_override(int eindex) const { if (_flow_code_override.size()) return hard_flow_code_override(eindex); else return 0; } inline void Router::activate(ErrorHandler* errh) { activate(true, errh); } inline void Router::set_foreground(bool foreground) { assert(_running >= RUNNING_BACKGROUND); _running = foreground ? RUNNING_ACTIVE : RUNNING_BACKGROUND; } /** @brief Finds an element named @a name. * @param name element name * @param errh optional error handler * * Returns the unique element named @a name, if any. If no element named @a * name is found, reports an error to @a errh and returns null. The error is * "no element named 'name'". If @a errh is null, no error is * reported. * * This function is equivalent to find(const String&, String, ErrorHandler*) * with a context argument of the empty string. */ inline Element * Router::find(const String& name, ErrorHandler *errh) const { return find(name, "", errh); } /** @brief Traverse the router configuration downstream of @a e[@a port]. * @param e element to start search * @param port output port (or -1 to search all output ports) * @param visitor RouterVisitor traversal object * @return 0 on success, -1 in early router configuration stages * * Calls @a visitor ->@link RouterVisitor::visit visit() @endlink on each * reachable input port starting from the output port @a e[@a port]. Follows * connections and traverses inside elements from port to port by * Element::flow_code(). The visitor can stop a traversal path by returning * false from visit(). * * @sa visit_upstream(), visit() */ inline int Router::visit_downstream(Element *e, int port, RouterVisitor *visitor) const { return visit(e, true, port, visitor); } /** @brief Traverse the router configuration upstream of [@a port]@a e. * @param e element to start search * @param port input port (or -1 to search all input ports) * @param visitor RouterVisitor traversal object * @return 0 on success, -1 in early router configuration stages * * Calls @a visitor ->@link RouterVisitor::visit visit() @endlink on each * reachable output port starting from the input port [@a port]@a e. Follows * connections and traverses inside elements from port to port by * Element::flow_code(). The visitor can stop a traversal path by returning * false from visit(). * * @sa visit_downstream(), visit() */ inline int Router::visit_upstream(Element *e, int port, RouterVisitor *visitor) const { return visit(e, false, port, visitor); } inline HashMap_ArenaFactory* Router::arena_factory() const { return _arena_factory; } /** @brief Returns the currently-installed router this router will eventually * replace. * * This function is only meaningful during a router's initialization. If this * router was installed with the hotswap option, then hotswap_router() will * return the currently-installed router that this router will eventually * replace (assuming error-free initialization). Otherwise, hotswap_router() * will return 0. */ inline Router* Router::hotswap_router() const { return _hotswap_router; } inline Handler::Handler(const String &name) : _name(name), _read_user_data(0), _write_user_data(0), _flags(0), _use_count(0), _next_by_name(-1) { _read_hook.r = 0; _write_hook.w = 0; } CLICK_ENDDECLS #endif