Click programmers spend most of their time writing elements, which are subclasses of class Element. Element provides functionality of its own, particularly the input() and output() methods and associated Element::Port objects. More important, however, is the set of functions that derived classes override to define element behavior. Good Click programmers understand how the Click system uses these functions to manipulate and initialize elements. These functions fall into several categories:
Here is the simplest possible element definition.
class MyNothingElement : public Element { public: MyNothingElement() { } ~MyNothingElement() { } const char *class_name() const { return "MyNothingElement"; } };
This element has no ports and accepts no configuration arguments; it does nothing. The required class_name() function informs Click's infrastructure of the element's class name.
Although this element definition is complete, Click's compilation process requires that a real element come with a bit more boilerplate. In particular, both a header file and a source file are required. Here's a possible definition of our nothing element, including all boilerplate:
// ================== elements/local/mynothingelement.hh ================== #ifndef CLICK_MYNOTHINGELEMENT_HH #define CLICK_MYNOTHINGELEMENT_HH #include <click/element.hh> CLICK_DECLS class MyNothingElement : public Element { public: MyNothingElement() { } ~MyNothingElement() { } const char *class_name() const { return "MyNothingElement"; } }; CLICK_ENDDECLS #endif // ================== elements/local/mynothingelement.cc ================== #include <click/config.h> #include "mynothingelement.hh" CLICK_DECLS // Non-inline element code would go here. CLICK_ENDDECLS EXPORT_ELEMENT(MyNothingElement)
Some things to notice:
CLICK_DECLS and CLICK_ENDDECLS. These are required for the NS and FreeBSD kernel drivers. Note that #include statements go outside the CLICK_DECLS/CLICK_ENDDECLS pair.#include <click/config.h>. This is mandatory.EXPORT_ELEMENT(NameOfC++ClassForElement). Click's compilation process will ignore your element unless there's a line like this.This slightly more complex example illustrates some more of Click's element infrastructure.
class MyNullElement : public Element { public: MyNullElement() { } ~MyNullElement() { } const char *class_name() const { return "MyNullElement"; } const char *port_count() const { return PORTS_1_1; } const char *processing() const { return PUSH; } void push(int port, Packet *p) { output(0).push(p); } };
This element processes packets in push mode, much like the standard PushNull element.
As a result, the push() method can assume that port == 0, that output(0) exists, and that output(0).push(p) is valid.
Elements must not push null packet pointers, either, so the push() method can assume that p != 0.
There is no harm in verifying these invariants with assertions, since bogus element code can violate them (by passing a bad value for port or p, for example), but such errors are rare in practice. The elements that we write mostly assume that the invariants hold.
Element run-time methods, such as push(), pull(), run_task(), and run_timer(), must always obey the following rules:
Beginning Click programmers often violate these rules. Here are some examples to make them concrete.
This incorrect version of Click's Tee element attempts to duplicate a packet and send the duplicates to two different outputs.
A single packet pointer p has been pushed to two different outputs. This is always illegal; the rest of the configuration may have modified or even freed the packet before returning control to BadTee, so output(1).push(p) would probably touch freed memory! This situation requires the Packet::clone() method, which makes a copy of a packet:
However, BetterTee would fail if the router ran out of memory for packet clones. p->clone() would return null, and passing a null pointer to another element's push() method isn't allowed. Here's how to fix this:
void BestTee::push(int port, Packet *p) { if (Packet *clone = p->clone()) output(0).push(clone); output(1).push(p); }
Here's an example of a push() method with an obvious leak:
void LeakyCounter::push(int port, Packet *p) { _counter++; }
The method doesn't do anything with p, so its memory will never be reclaimed. Instead, it should either free the packet or pass it on to another element:
void BetterCounter1::push(int port, Packet *p) { _counter++; p->kill(); // free packet } void BetterCounter2::push(int port, Packet *p) { _counter++; output(0).push(p); // push packet on }
Leaks involving error conditions are more common in practice. For instance, this push() method counts IP packets. The programmer has defensively checked whether or not the input packet's network header pointer is set.
void LeakyIPCounter::push(int port, Packet *p) { if (!p->has_network_header()) return; _counter++; output(0).push(p); }
Close, but no cigar: if the input packet has no network header pointer, the packet will leak. Here are some better versions.
void BetterIPCounter1::push(int port, Packet *p) { // In this version, non-IP packets are dropped. This is closest to LeakyIPCounter's intended functionality. if (!p->has_network_header()) { p->kill(); return; } _counter++; output(0).push(p); } void BetterIPCounter2::push(int port, Packet *p) { // This programmer thinks non-IP packets are serious errors and should cause a crash. assert(p->has_network_header()); _counter++; output(0).push(p); } void BetterIPCounter3::push(int port, Packet *p) { // This programmer passes non-IP packets through without counting them. if (p->has_network_header()) _counter++; output(0).push(p); }
The Click infrastructure calls element initialization functions in a specific order during router initialization. Errors at any stage prevent later stages from running.
Router cleanup takes place as follows. Click:
Public Types | |
| enum | ConfigurePhase { CONFIGURE_PHASE_FIRST = 0, CONFIGURE_PHASE_INFO = 20, CONFIGURE_PHASE_PRIVILEGED = 90, CONFIGURE_PHASE_DEFAULT = 100, CONFIGURE_PHASE_LAST = 2000 } |
| enum | CleanupStage { CLEANUP_NO_ROUTER, CLEANUP_BEFORE_CONFIGURE = CLEANUP_NO_ROUTER, CLEANUP_CONFIGURE_FAILED, CLEANUP_CONFIGURED, CLEANUP_INITIALIZE_FAILED, CLEANUP_INITIALIZED, CLEANUP_ROUTER_INITIALIZED, CLEANUP_MANUAL } |
| enum | { SELECT_READ = 1, SELECT_WRITE = 2 } |
Public Member Functions | |
| Element () | |
| Construct an Element. | |
| virtual void | push (int port, Packet *p) |
| Push packet p onto push input port. | |
| virtual Packet * | pull (int port) |
| Pull a packet from pull output port. | |
| virtual Packet * | simple_action (Packet *p) |
| Process a packet for a simple packet filter. | |
| virtual bool | run_task (Task *task) |
| Run the element's task. | |
| virtual void | run_timer (Timer *timer) |
| Run the element's timer. | |
| virtual void | selected (int fd) |
| Handle a file descriptor event. | |
| void | checked_output_push (int port, Packet *p) const |
| Push packet p to output port, or kill it if port is out of range. | |
| virtual const char * | class_name () const=0 |
| Return the element's class name. | |
| virtual const char * | port_count () const |
| Return the element's port count specifier. | |
| virtual const char * | processing () const |
| Return the element's processing specifier. | |
| virtual const char * | flow_code () const |
| Return the element's internal packet flow specifier (its flow code). | |
| virtual const char * | flags () const |
| Return the element's flags. | |
| int | flag_value (int flag) const |
| Return the flag value for flag in flags(). | |
| virtual void * | cast (const char *name) |
| Attempt to cast the element to a named type. | |
| virtual void * | port_cast (bool isoutput, int port, const char *name) |
| Attempt to cast an element's port to a named type. | |
| virtual int | configure_phase () const |
| Return the element's configure phase, which determines the order in which elements are configured and initialized. | |
| virtual int | configure (Vector< String > &conf, ErrorHandler *errh) |
| Parse the element's configuration arguments. | |
| virtual void | add_handlers () |
| Install the element's handlers. | |
| virtual int | initialize (ErrorHandler *errh) |
| Initialize the element. | |
| virtual void | take_state (Element *old_element, ErrorHandler *errh) |
| Initialize the element for hotswap, where the element should take old_element's state, if possible. | |
| virtual Element * | hotswap_element () const |
| Return a compatible element in the hotswap router. | |
| virtual void | cleanup (CleanupStage stage) |
| Clean up the element's state. | |
| String | name () const |
| Return the element's name. | |
| String | landmark () const |
| Return a string describing where the element was declared. | |
| virtual String | declaration () const |
| Return a string giving the element's name and class name. | |
| Router * | router () const |
| Return the element's router. | |
| int | eindex () const |
| Return the element's index within its router. | |
| int | eindex (Router *r) const |
| Return the element's index within router r. | |
| Master * | master () const |
| Return the element's master. | |
| void | attach_router (Router *r, int eindex) |
| int | nports (bool isoutput) const |
| Return the number of input or output ports. | |
| int | ninputs () const |
| Return the number of input ports. | |
| int | noutputs () const |
| Return the number of output ports. | |
| const Port & | port (bool isoutput, int port) const |
| Return one of the element's ports. | |
| const Port & | input (int port) const |
| Return one of the element's input ports. | |
| const Port & | output (int port) const |
| Return one of the element's output ports. | |
| bool | port_active (bool isoutput, int port) const |
| Check whether a port is active. | |
| bool | input_is_push (int port) const |
| Check whether input port is push. | |
| bool | input_is_pull (int port) const |
| Check whether input port is pull. | |
| bool | output_is_push (int port) const |
| Check whether output port is push. | |
| bool | output_is_pull (int port) const |
| Check whether output port is pull. | |
| void | port_flow (bool isoutput, int port, Bitvector *) const |
| Analyze internal packet flow with respect to port p. | |
| String | configuration () const |
| Return the element's current configuration string. | |
| virtual bool | can_live_reconfigure () const |
| Return whether an element supports live reconfiguration. | |
| virtual int | live_reconfigure (Vector< String > &, ErrorHandler *) |
| Reconfigure the element while the router is running. | |
| int | add_select (int fd, int mask) |
| Register interest in mask events on file descriptor fd. | |
| int | remove_select (int fd, int mask) |
| Remove interest in mask events on file descriptor fd. | |
| void | add_read_handler (const String &name, ReadHandlerCallback read_callback, const void *user_data=0, uint32_t flags=0) |
| Register a read handler named name. | |
| void | add_read_handler (const String &name, ReadHandlerCallback read_callback, int user_data, uint32_t flags=0) |
| Register a read handler named name. | |
| void | add_write_handler (const String &name, WriteHandlerCallback write_callback, const void *user_data=0, uint32_t flags=0) |
| Register a write handler named name. | |
| void | add_write_handler (const String &name, WriteHandlerCallback write_callback, int user_data, uint32_t flags=0) |
| Register a write handler named name. | |
| void | set_handler (const String &name, int flags, HandlerCallback callback, const void *user_data1=0, const void *user_data2=0) |
| Register a comprehensive handler named name. | |
| void | set_handler (const String &name, int flags, HandlerCallback callback, int user_data1, int user_data2=0) |
| Register a comprehensive handler named name. | |
| int | set_handler_flags (const String &name, int set_flags, int clear_flags=0) |
| Set flags for the handler named name. | |
| void | add_task_handlers (Task *task, const String &prefix=String()) |
| Register handlers for a task. | |
| void | add_data_handlers (const String &name, int flags, uint8_t *data) |
| Register read and/or write handlers accessing data. | |
| void | add_data_handlers (const String &name, int flags, bool *data) |
| void | add_data_handlers (const String &name, int flags, int *data) |
| void | add_data_handlers (const String &name, int flags, unsigned *data) |
| void | add_data_handlers (const String &name, int flags, atomic_uint32_t *data) |
| void | add_data_handlers (const String &name, int flags, long *data) |
| void | add_data_handlers (const String &name, int flags, unsigned long *data) |
| void | add_data_handlers (const String &name, int flags, double *data) |
| void | add_data_handlers (const String &name, int flags, String *data) |
| Register read and/or write handlers accessing data. | |
| void | add_data_handlers (const String &name, int flags, IPAddress *data) |
| void | add_data_handlers (const String &name, int flags, EtherAddress *data) |
| virtual int | llrpc (unsigned command, void *arg) |
| Handle a low-level remote procedure call. | |
| int | local_llrpc (unsigned command, void *arg) |
| Execute an LLRPC from within the configuration. | |
| String | id () const |
| Return the element's name (deprecated). | |
| virtual bool | run_task () CLICK_ELEMENT_DEPRECATED |
| Run the element's task (deprecated). | |
| virtual void | run_timer () CLICK_ELEMENT_DEPRECATED |
| Run the element's timer (deprecated). | |
Static Public Member Functions | |
| static void | static_initialize () |
| Initialize static data for this element class. | |
| static void | static_cleanup () |
| Clean up static data for this element class. | |
| static String | read_positional_handler (Element *, void *) |
| Standard read handler returning a positional argument. | |
| static String | read_keyword_handler (Element *, void *) |
| Standard read handler returning a keyword argument. | |
| static int | reconfigure_positional_handler (const String &, Element *, void *, ErrorHandler *) |
| Standard write handler for reconfiguring an element by changing one of its positional arguments. | |
| static int | reconfigure_keyword_handler (const String &, Element *, void *, ErrorHandler *) |
| Standard write handler for reconfiguring an element by changing one of its keyword arguments. | |
Static Public Attributes | |
| static int | nelements_allocated |
| static const char | PORTS_0_0 [] |
| static const char | PORTS_0_1 [] |
| static const char | PORTS_1_0 [] |
| static const char | PORTS_1_1 [] |
| static const char | PORTS_1_1X2 [] |
| static const char | AGNOSTIC [] |
| static const char | PUSH [] |
| static const char | PULL [] |
| static const char | PUSH_TO_PULL [] |
| static const char | PULL_TO_PUSH [] |
| static const char | PROCESSING_A_AH [] |
| static const char | COMPLETE_FLOW [] |
Classes | |
| class | Port |
| An Element's ports. More... | |
| Element::Element | ( | ) |
Construct an Element.
| void Element::push | ( | int | port, | |
| Packet * | p | |||
| ) | [virtual] |
Push packet p onto push input port.
| port | the input port number on which the packet arrives | |
| p | the packet |
The default implementation calls simple_action().
| Packet * Element::pull | ( | int | port | ) | [virtual] |
Pull a packet from pull output port.
| port | the output port number receiving the pull request. |
Often, pull() methods will request packets from upstream using input(i).pull(). The default implementation calls simple_action().
Process a packet for a simple packet filter.
| p | the input packet |
simple_action() must account for p, either by returning it, by freeing it, or by emitting it on some alternate push output port. (An optional second push output port 1 is often used to emit erroneous packets.)
simple_action() works equally well for push or pull port pairs. The default push() method calls simple_action() this way:
if ((p = simple_action(p))) output(0).push(p);
The default pull() method calls it this way instead:
if (Packet *p = input(0).pull()) if ((p = simple_action(p))) return p; return 0;
An element that implements its processing with simple_action() should have a processing() code like AGNOSTIC or "a/ah", and a flow_code() like COMPLETE_FLOW or "x/x" indicating that packets can flow between the first input and the first output.
For technical branch prediction-related reasons, elements that use simple_action() can perform quite a bit slower than elements that use push() and pull() directly. The devirtualizer (click-devirtualize) can mitigate this effect.
| bool Element::run_task | ( | Task * | task | ) | [virtual] |
Run the element's task.
| void Element::run_timer | ( | Timer * | timer | ) | [virtual] |
Run the element's timer.
| timer | the timer object that fired |
| void Element::selected | ( | int | fd | ) | [virtual] |
Handle a file descriptor event.
| fd | the file descriptor |
The element must have previously registered interest in fd with add_select().
| void Element::checked_output_push | ( | int | port, | |
| Packet * | p | |||
| ) | const [inline] |
Push packet p to output port, or kill it if port is out of range.
| port | output port number | |
| p | packet to push |
| Element::class_name | ( | ) | const [pure virtual] |
Return the element's class name.
Each element class must override this function to return its class name.
Click tools extract class names from the source. For Click to find a class name, the function definition must appear inline, on a single line, inside the element class's declaration, and must return a C string constant. It should also have public accessibility. Here's an acceptable class_name() definition:
const char *class_name() const { return "ARPQuerier"; }
| const char * Element::port_count | ( | ) | const [virtual] |
Return the element's port count specifier.
An element class overrides this virtual function to return a C string describing its port counts. The string gives acceptable input and output ranges, separated by a slash. Examples:
"1/1" "1-2/0" "1/-6" "2-/-" "3" "1-/=" "1-/=+" These ranges help Click determine whether a configuration uses too few or too many ports, and lead to errors such as "'e' has no input 3" and "'e' input 3 unused".
Click extracts port count specifiers from the source for use by tools. For Click to find a port count specifier, the function definition must appear inline, on a single line, inside the element class's declaration, and must return a C string constant. It should also have public accessibility. Here's an acceptable port_count() definition:
const char *port_count() const { return "1/1"; }
The default port_count() method returns "0/0".
The following names are available for common port count specifiers.
PORTS_0_0 for "0/0" PORTS_0_1 for "0/1" PORTS_1_0 for "1/0" PORTS_1_1 for "1/1" PORTS_1_1X2 for "1/1-2" | const char * Element::processing | ( | ) | const [virtual] |
Return the element's processing specifier.
An element class overrides this virtual function to return a C string describing which of its ports are push, pull, or agnostic. The string gives acceptable input and output ranges, separated by a slash; the characters "h", "l", and "a" indicate push, pull, and agnostic ports, respectively. Examples:
"h/h" All input and output ports are push. "h/l" Push input ports and pull output ports. "a/ah" All input ports are agnostic. The first output port is also agnostic, but the second and subsequent output ports are push. "hl/hlh" Input port 0 and output port 0 are push. Input port 1 and output port 1 are pull. All remaining inputs are pull; all remaining outputs are push. "a" All input and output ports are agnostic. (If no slash appears, the text is used for both input and output ports.)Click extracts processing specifiers from the source for use by tools. For Click to find a processing specifier, the function definition must appear inline, on a single line, inside the element class's declaration, and must return a C string constant. It should also have public accessibility. Here's an acceptable processing() definition:
const char *processing() const { return "a/ah"; }
The default processing() method returns "a/a", which sets all ports to agnostic.
The following names are available for common processing specifiers.
AGNOSTIC for "a/a" PUSH for "h/h" PULL for "l/l" PUSH_TO_PULL for "h/l" PULL_TO_PUSH for "l/h" PROCESSING_A_AH for "a/ah" | const char * Element::flow_code | ( | ) | const [virtual] |
Return the element's internal packet flow specifier (its flow code).
An element class overrides this virtual function to return a C string describing how packets flow within the element. That is, can packets that arrive on input port X be emitted on output port Y, for all X and Y? This information helps Click answer questions such as "What Queues are downstream of this element?" and "Should this agnostic port be push or pull?". See below for more.
A flow code string consists of an input specification and an output specification, separated by a slash. Each specification is a sequence of port codes. Packets can travel from an input port to an output port only if the port codes match.
The simplest port code is a single case-sensitive letter. For example, the flow code "x/x" says that packets can travel from the element's input port to its output port, while "x/y" says that packets never travel between ports.
A port code may also be a sequence of letters in brackets, such as [abz]. Two port codes match iff they have at least one letter in common, so [abz] matches a, but [abz] and [cde] do not match. The opening bracket may be followed by a caret ^; this makes the port code match letters not mentioned between the brackets. Thus, the port code [^bc] is equivalent to [ABC...XYZadef...xyz].
Finally, the # character is also a valid port code, and may be used within brackets. One # matches another # only when they represent the same port number -- for example, when one # corresponds to input port 2 and the other to output port 2. # never matches any letter. Thus, for an element with exactly 2 inputs and 2 outputs, the flow code "##/##" behaves like "xy/xy".
The last code in each specification is duplicated as many times as necessary, and any extra codes are ignored. The flow codes "[x#][x#][x#]/x######" and "[x#]/x#" behave identically.
Here are some example flow codes.
"x/x"
"xy/x"
"x/y"
"#/#"
"#/[^#]" Click extracts flow codes from the source for use by tools. For Click to find a flow code, the function definition must appear inline, on a single line, inside the element class's declaration, and must return a C string constant. It should also have public accessibility. Here's an acceptable flow_code() definition:
const char *flow_code() const { return "xy/x"; }
The default flow_code() method returns "x/x", which indicates that packets may travel from any input to any output. This default is acceptable for the vast majority of elements.
The following name is available for a common flow code.
COMPLETE_FLOW for "x/x"
What does it mean for a packet to travel from one port to another? To pick the right flow code for an element, consider how a flow code would affect a simple router.
Given an element E with input port M and output port N, imagine this simple configuration (or a similar configuration):
... -> RED -> [M] E [N] -> Queue -> ...;
Now, should the RED element include the Queue element in its queue length calculation? If so, then the flow code's Mth input port code and Nth output port code should match. If not, they shouldn't.
For example, consider ARPQuerier's second input port. On receiving an ARP response on that input, ARPQuerier may emit a held-over IP packet to its first output. However, a RED element upstream of that second input port probably wouldn't count the downstream Queue in its queue length calculation. After all, the ARP responses are effectively dropped; packets emitted onto the Queue originally came from ARPQuerier's first input port. Therefore, ARPQuerier's flow code, "xy/x", specifies that packets arriving on the second input port are not emitted on any output port.
The ARPResponder element provides a contrasting example. It has one input port, which receives ARP queries, and one output port, which emits the corresponding ARP responses. A RED element upstream of ARPResponder probably would want to include a downstream Queue, since queries received by ARPResponder are effectively transmuted into emitted responses. Thus, ARPResponder's flow code, "x/x" (the default), specifies that packets travel through it, even though the packets it emits are completely different from the packets it receives.
If you find this confusing, don't fret. It is perfectly fine to be conservative when assigning flow codes, and the vast majority of the Click distribution's elements use COMPLETE_FLOW.
| const char * Element::flags | ( | ) | const [virtual] |
Return the element's flags.
A A-flagged elements.
S0 S0 flag. As a result, degenerate paths like "RoundRobinSched -> ToDevice", where RoundRobinSched has 0 inputs, are idle rather than busy, and waste no CPU time.
| int Element::flag_value | ( | int | flag | ) | const |
| void * Element::cast | ( | const char * | name | ) | [virtual] |
Attempt to cast the element to a named type.
| name | name of the type being cast to |
dynamic_cast operator. (dynamic_cast itself is not available in the Linux kernel, so we rolled our own.) The function should return a pointer to the named object, or a null pointer if this element doesn't have that type. name can name an element class or another type of interface, such as "Storage" or Notifier::EMPTY_NOTIFIER.The default implementation returns this element if name equals class_name(), and null otherwise.
You should override cast() if your element inherits from another element (and you want to expose that inheritance to Click); the resulting cast() method will check both class names. For example, if element Derived inherited from element Base, Derived::cast() might be defined like this:
void *Derived::cast(const char *name) { if (strcmp(name, "Derived") == 0) return (Derived *) this; else if (strcmp(name, "Base") == 0) return (Base *) this; else return Base::cast(name); }
The recursive call to Base::cast() is useful in case Base itself overrides cast(). The explicit check for the name "Base" is necessary in case Base did not override cast(): the default cast() implementation compares against class_name(), which in this case is "Derived". Always explicitly cast this to the correct type before returning it.
You should also override cast() if your element provides another interface, such as Storage or a Notifier.
| void * Element::port_cast | ( | bool | isoutput, | |
| int | port, | |||
| const char * | name | |||
| ) | [virtual] |
Attempt to cast an element's port to a named type.
| isoutput | false for input ports, true for output ports | |
| port | port number | |
| name | name of the type being cast to |
"Storage" or Notifier::EMPTY_NOTIFIER.The default implementation returns the result of cast(), ignoring the isoutput and port arguments.
The cast() method suffices for most purposes, but some Click functionality, such as Notifiers, can use the additional precision of port_cast().
| int Element::configure_phase | ( | ) | const [virtual] |
Return the element's configure phase, which determines the order in which elements are configured and initialized.
Click configures and initializes elements in increasing order of configure_phase(). An element with configure phase 1 will always be configured (have its configure() method called) before an element with configure phase 2. Thus, if two element classes must be configured in a given order, they should define configure_phase() functions to enforce that order. For example, the AddressInfo element defines address abbreviations for other elements to use; it should thus be configured before other elements, and its configure_phase() method returns a low value.
Configure phases should be defined relative to the following constants, which are listed in increasing order.
CONFIGURE_PHASE_FIRST
CONFIGURE_PHASE_INFO
CONFIGURE_PHASE_PRIVILEGED CONFIGURE_PHASE_PRIVILEGED + 1.
CONFIGURE_PHASE_DEFAULT CONFIGURE_PHASE_DEFAULT, so most elements are configured at this phase. Appropriate for most elements.
CONFIGURE_PHASE_LAST
The body of a configure_phase() method should consist of a single return statement returning some constant. Although it shouldn't matter when it's called, it is called before configure().
| int Element::configure | ( | Vector< String > & | conf, | |
| ErrorHandler * | errh | |||
| ) | [virtual] |
Parse the element's configuration arguments.
| conf | configuration arguments | |
| errh | error handler |
The conf argument is the element's configuration string, divided into configuration arguments by splitting at commas and removing comments and leading and trailing whitespace (see cp_argvec()). If conf is empty, the element was not supplied with a configuration string (or its configuration string contained only comments and whitespace). It is safe to modify conf; modifications will be thrown away when the function returns.
Any errors, warnings, or messages should be reported to errh. Messages need not specify the element name or type, since this information will be provided as context.
configure() should return a negative number if configuration fails. Returning a negative number prevents the router from initializing. The default configure() method succeeds if and only if there are no configuration arguments.
configure() methods are called in order of configure_phase(). All elements' configure() methods are called, even if an early configure() method fails; this is to report all relevant error messages to the user, rather than just the first.
configure() is called early in the initialization process, and cannot check whether a named handler exists. That function must be left for initialize(). Assuming all router connections are valid and all configure() methods succeed, the add_handlers() functions will be called next.
A configure() method should avoid potentially harmful actions, such as truncating files or attaching to devices. These actions should be left for the initialize() method, which is called later. This avoids harm if another element cannot be configured, or if the router is incorrectly connected, since in those cases initialize() will never be called.
Elements that support live reconfiguration (see can_live_reconfigure()) should expect configure() to be called at run time, when a user writes to the element's config handler. In that case, configure() must be careful not to disturb the existing configuration unless the new configuration is error-free.
| void Element::add_handlers | ( | ) | [virtual] |
Install the element's handlers.
The add_handlers() method should install any handlers the element provides by calling add_read_handler(), add_write_handler(), and set_handler(). These functions may also be called from configure(), initialize(), or even later, during router execution. However, it is better in most cases to initialize handlers in configure() or add_handlers(), since elements that depend on other handlers often check in initialize() whether those handlers exist.
add_handlers() is called after configure() and before initialize(). When it runs, it is guaranteed that every configure() method succeeded and that all connections are correct (push and pull match up correctly and there are no unused or badly-connected ports).
Most add_handlers() methods simply call add_read_handler(), add_write_handler(), add_task_handlers(), and possibly set_handler() one or more times. The default add_handlers() method does nothing.
Click automatically provides five handlers for each element: class, name, config, ports, and handlers. There is no need to provide these yourself.
| int Element::initialize | ( | ErrorHandler * | errh | ) | [virtual] |
Initialize the element.
| errh | error handler |
initialize() should return zero if initialization succeeds, or a negative number if it fails. Returning a negative number prevents the router from initializing. The default initialize() method always returns zero (success).
initialize() methods are called in order of configure_phase(), using the same order as for configure(). When an initialize() method fails, router initialization stops immediately, and no more initialize() methods are called. Thus, at most one initialize() method can fail per router configuration.
initialize() is called after add_handlers() and before take_state(). When it runs, it is guaranteed that every configure() method succeeded, that all connections are correct (push and pull match up correctly and there are no unused or badly-connected ports), and that every add_handlers() method has been called.
If every element's initialize() method succeeds, then the router is installed, and will remain installed until another router replaces it. Any errors that occur later than initialize() -- during take_state(), push(), or pull(), for example -- will not take the router off line.
Strictly speaking, the only task that must go in initialize() is checking whether a handler exists, since that information isn't available at configure() time. It's often convenient, however, to put other functionality in initialize(). For example, opening files for writing fits well in initialize(): if the configuration has errors before the relevant element is initialized, any existing file will be left as is. Common tasks performed in initialize() methods include:
In previous releases, configure() could not determine whether a port was push or pull or query the router for information about neighboring elements, so those tasks were relegated to initialize() methods. In the current release, configure() can perform these tasks too.
| void Element::take_state | ( | Element * | old_element, | |
| ErrorHandler * | errh | |||
| ) | [virtual] |
Initialize the element for hotswap, where the element should take old_element's state, if possible.
| old_element | element in the old configuration; result of hotswap_element() | |
| errh | error handler |
take_state() is called only when a configuration is hotswapped in. The default take_state() implementation does nothing; there's no need to override it unless your element has state you want preserved across hotswaps.
The old_element argument is an element from the old configuration (that is, from router()->hotswap_router()) obtained by calling hotswap_element(). If hotswap_element() returns null, take_state() will not be called. The default hotswap_element() returns an old_element has the same name() as this element. This is often too loose; for instance, old_element might have a completely different class. Thus, most take_state() methods begin by attempting to cast() old_element to a compatible class, and silently returning if the result is null. Alternatively, you can override hotswap_element() and put the check there.
Errors and warnings should be reported to errh, but the router will be installed whether or not there are errors. take_state() should always leave this element in a state that's safe to run, and old_element in a state that's safe to cleanup().
take_state() is called after initialize(). When it runs, it is guaranteed that this element's configuration will shortly be installed. Every configure() and initialize() method succeeded, all connections are correct (push and pull match up correctly and there are no unused or badly-connected ports), and every add_handlers() method has been called. It is also guaranteed that the old configuration (of which old_element is a part) had been successfully installed, but that none of its tasks are running at the moment.
| Element * Element::hotswap_element | ( | ) | const [virtual] |
Return a compatible element in the hotswap router.
hotswap_element() searches the hotswap router, router()->hotswap_router(), for an element compatible with this element. It returns that element, if any. If there's no compatible element, or no hotswap router, then it returns 0.
The default implementation searches for an element with the same name as this element. Thus, it returns 0 or an element that satisfies this constraint: hotswap_element()->name() == name().
Generally, this constraint is too loose. A Queue element can't hotswap state from an ARPResponder, even if they do have the same name. Most elements also check that hotswap_element() has the right class, using the cast() function. This