625 lines
19 KiB
C++
625 lines
19 KiB
C++
// -*- c-basic-offset: 4; related-file-name: "../../lib/router.cc" -*-
|
|
#ifndef CLICK_ROUTER_HH
|
|
#define CLICK_ROUTER_HH
|
|
#include <click/element.hh>
|
|
#include <click/timer.hh>
|
|
#include <click/sync.hh>
|
|
#include <click/task.hh>
|
|
#include <click/standard/threadsched.hh>
|
|
#if CLICK_NS
|
|
# include <click/simclick.h>
|
|
#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<Element*>& 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<Element*> &result) CLICK_DEPRECATED;
|
|
int upstream_elements(Element *e, int port, ElementFilter *filter, Vector<Element*> &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<int> &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<Vector<int> *> _listenvecs;
|
|
Vector<int>* 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<Element *> _elements;
|
|
Vector<String> _element_names;
|
|
Vector<String> _element_configurations;
|
|
Vector<uint32_t> _element_landmarkids;
|
|
mutable Vector<int> _element_home_thread_ids;
|
|
|
|
struct element_landmark_t {
|
|
uint32_t first_landmarkid;
|
|
String filename;
|
|
};
|
|
Vector<element_landmark_t> _element_landmarks;
|
|
uint32_t _last_landmarkid;
|
|
|
|
mutable Vector<int> _element_name_sorter;
|
|
Vector<int> _element_gport_offset[2];
|
|
Vector<int> _element_configure_order;
|
|
|
|
mutable Vector<Connection> _conn;
|
|
mutable Vector<int> _conn_output_sorter;
|
|
|
|
Vector<String> _requirements;
|
|
|
|
Vector<int> _ehandler_first_by_element;
|
|
Vector<int> _ehandler_to_handler;
|
|
Vector<int> _ehandler_next;
|
|
|
|
Vector<int> _handler_first_by_name;
|
|
|
|
enum { HANDLER_BUFSIZ = 256 };
|
|
Handler** _handler_bufs;
|
|
int _nhandlers_bufs;
|
|
int _free_handler;
|
|
|
|
Vector<String> _attachment_names;
|
|
Vector<void*> _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<int> _flow_code_override_eindex;
|
|
Vector<String> _flow_code_override;
|
|
|
|
Router* _next_router;
|
|
|
|
#if CLICK_LINUXMODULE
|
|
Vector<struct module*> _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<Element*>&
|
|
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
|
|
* "<tt>no element named 'name'</tt>". 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
|