Title: Click Modular Router
1Click Modular Router
- Userlevel Click Development
- Bart Braem Michael Voorhaen
- firstname.lastname_at_ua.ac.be
2Writing your own element header
- Necessary in the header
- Macros
- Include-guards
- Click element macros
- Include click/element.hh
- The class declaration
- containing 3 special methods
- const char class_name() const
- const char port_count() const
- const char processing() const
3simplepushelement.hh
- ifndef CLICK_SIMPLEPUSHELEMENT_HH
- define CLICK_SIMPLEPUSHELEMENT_HH
- include ltclick/element.hhgt
- CLICK_DECLS
- class SimplePushElement public Element
- public
- SimplePushElement()
- SimplePushElement()
-
- const char class_name() const return
"SimplePushElement" - const char port_count() const return 1/1
- const char processing() const return PUSH
- int configure(VectorltStringgt, ErrorHandler)
-
- void push(int, Packet )
- private
- uint32_t maxSize
-
4Writing your own element
- Necessary in the source file
- Include click/config.hh first!!
- Macros
- CLICK_DECLS
- CLICK_ENDDECLS
- EXPORT_ELEMENT
- Implementations of the methods
5simplepushelement.cc
- include ltclick/config.hgt
- include ltclick/confparse.hhgt
- include ltclick/error.hhgt
- include "simplepushelement.hh"
- CLICK_DECLS
- SimplePushElementSimplePushElement()
- SimplePushElement SimplePushElement()
- int SimplePushElement configure(VectorltStringgt
conf, ErrorHandler errh) - if (cp_va_parse(conf, this, errh, cpKeywords,
"MAX_SIZE", cpInteger, "maximum packet size",
maxSize, cpEnd) lt 0) return -1 - if (maxSize lt 0) return errh-gterror("maxsize
should be larger than 0") - return 0
-
- void SimplePushElement push(int, Packet p)
- if (p-gtlength() gt maxSize) p-gtkill()
- else output(0).push(p)
-
6simplepullelement
- simplepullelement.hh
- class SimplePullElement public Element
- public
- const char processing() const return PULL
- Packet pull(int)
-
- simplepullelement.cc
- Packet SimplePullElementpull(int)
- Packet p input(0).pull()
- if (p-gtlength() gt maxSize) p-gtkill()
- return p
-
7simpleagnosticelement1
- simpleagnosticelement1.hh
- class SimpleAgnosticElement1 public Element
- public
- const char processing() const return
AGNOSTIC - Packet simple_action(Packet )
-
- simpleagnosticelement1.cc
- Packet SimpleAgnosticElement1simple_action(Pack
et p) - if (p-gtlength() gt maxSize)
- p-gtkill()
- return 0
- else
- return p
-
8simpleagnosticelement2
- simpleagnosticelement2.hh
- class SimpleAgnosticElement2 public Element
- public
- const char processing() const return
AGNOSTIC - void push(int, Packet )
- Packet pull(int)
-
- simpleagnosticelement2.cc
- void SimpleAgnosticElement2push(int, Packet
p) - if (p-gtlength() gt maxSize) p-gtkill()
- else output(0).push(p)
-
- Packet SimpleAgnosticElement2pull(int)
- Packet p input(0).pull()
- if (p-gtlength() gt maxSize) p-gtkill()
- return p
9Portcount
- Defined by const char port_count() const
- can return
- "1/1" one input port, one output port
- "1/2" one input port, two output ports
- Or more complicated
- "1-2/0" one or two input ports and zero output
ports. - "1/-6" One input port and up to six output
ports. - "2-/-" At least two input ports and any number
of output ports. - "3" Exactly three input and output ports. (If no
slash appears, the text is used for both input
and output ranges.) - "1-/" At least one input port and the same
number of output ports. - "1-/" At least one input port and one more
output port than there are input ports.
10Parsing configurations
- Required arguments
- First in cp_va_parse
- Optional arguments
- After cpOptional
- Arguments by keyword
- After cpKeywords
- Optional if after cpOptional
- Much clearer
- Lots of types parsed
- Integers (cpInteger)
- Strings (cpString)
- Elements (cpElement)
- IP addresses (cpIPAddress)
11Parsing configurations examples
- cp_va_parse(conf, this, errh,
- cpString, "packet data", data,
- cpOptional,
- cpUnsigned, "sending rate (packets/s)", rate,
- cpKeywords,
- "DATASIZE", cpInteger, "minimum packet size",
datasize, - "ACTIVE", cpBool, "active?", active,
- SOURCE", cpIPAddress, source ip", source,
- cpEnd)
- SimpleElement(data,800,DATASIZE -67, SOURCE
1.2.3.4) - SimpleElement(data)
- SimpleElement(data,ACTIVE false)
- SimpleElement(data,800)
- SimpleElement(data,ACTIVE false, 800)
12Parsing configurations elements
- Elements might need other elements
- Pass them in the configuration
- Check their name and type
- Calling public methods and accessing public
members is possible - Click script
- SimpleElement(IPRouteTable)or
- myIpRouteTableIPRouteTable
- SimpleElement(myIpRouteTable)
13Parsing configurations elements (2)
- Add an element to the header
-
- include usedelement.hh
-
- class ElementUser public Element
-
- private
-
- UsedElement used
-
- Use the element in the C code
- ElementUserpush() used-gtdoSomething()
14Parsing configurations elements (3)
- Check and configure the element in the configure
function - int ElementUserconfigure(VectorltStringgt conf,
ErrorHandler errh) - Element tempUsedElement
- int res cp_va_parse(conf, this, errh,
cpElement, Used element", tempUsedElement, 0) - if(res lt 0) return res // parsing failed
- if (tempUsedElement-gtclass_name() !
UsedElement") - return errh-gterror("Supplied element is not a
UsedElement element but a s", UsedElement-gtclass_
name()) -
- if (!(used (UsedElement ) UsedElement))
- return errh-gterror("Supplied element is not a
valid UsedElement element (cast failed)") -
15Click library functions
- The C STL cannot be used in the kernel
- Click provides its own implementation, use it
- Equivalents to most STL datastructures available
- E.g. vector, hashmap,
- Additional types
- Timers and tasks (schedule actions)
- Additional functions
- Manipulate strings
- Manipulate packets
- E.g. click_gettimeofday(struct timeval tv)
16Using Click STL example
- ifndef AODVSETRREPHEADERS_HH
- define AODVSETRREPHEADERS_HH
- include ltclick/element.hhgt
- CLICK_DECLS
- typedef HashMapltPacket, IPAddressgt
DestinationMap - class AODVSetRREPHeaders public Element
- public
-
- virtual void push (int, Packet )
- void addRREP(Packet,IPAddress )
- private
- DestinationMap destinations
-
- CLICK_ENDDECLS
- endif
17Usign Click STL example (2)
- AODVSetRREPHeadersAODVSetRREPHeaders()
destinations() -
- void AODVSetRREPHeaderspush (int port, Packet
p) -
- // packet should be in destinations
- DestinationMapPair pair destinations.find_p
air(packet) - assert(pair)
- IPAddress destination pair-gtvalue
- // do something with destination
- delete pair-gtvalue // free memory properly
- destinations.remove(packet) // then remove from
map -
-
- void AODVSetRREPHeadersaddRREP(Packet rrep,
IPAddress ip) - destinations.insert(rrep,ip)
-
- // macro magic to use bighashmap
- include ltclick/bighashmap.ccgt
18Creating and destroying packets
- You want to make your own packets, heres how
- Format closely mirrors RFCs
- Use structs
- Fill them with signed/unsigned ints, in_addr,
- Easy packet manipulation
- Avoids dirty operations with chars and bytes
- Define those in shared headers for reuse
- Create your packet format
- struct MyPacketFormat
- uint8_t type // 8 bit 1 byte
- uint32_t lifetime // 32 bit 4 bytes
- in_addr destination // IP address
19Creating and destroying packets (2)
- Provide headroom and tailroom to
Packetmake(unsigned headroom, const unsigned
char data, unsigned len, unsigned tailroom) - int tailroom 0
- int packetsize sizeof(MyPacketFormat)
- int headroom sizeof(click_ip)sizeof(click_udp)
sizeof(click_eth) - WritablePacket packet Packetmake(headroom,0,
packetsize, tailroom) - if (packet 0 )return click_chatter( "cannot
make packet!") - memset(packet-gtdata(), 0, packet-gtlength())
- MyPacketFormat format (MyPacketFormat)
packet-gtdata() - format-gttype 0
- format-gtlifetime htonl(counter)
- format-gtdestination ip.in_addr()
- Destroy with packet-gtkill()
- Frees your memory!
20Processing packets
- Cast the packet data to the right format
- my_header head (my_header ) (packet-gtdata()
someoffset) - Use the format to read from and write to
- if (head-gtsomefield 2)head-gtotherfield
htons(38) - Only write to writable packets!
21Manipulating packets
- Add data with push(unsigned len)
- Inserts the data at the beginning of the packet
- Create enough headroom, otherwise expensive push!
- Remove data with pull(unsigned len)
- Removes the data at the beginning of the packet
- Frees headroom
- Equivalents at tail of packet put and take
22Packet headers
- Get IP header
- packet-gtip_header()
- Set IP header of length len
- packet-gtset_ip_header(const click_ip header,
unsigned len) - Both operations require header annotations, set
by the MarkIPHeader element! - Similar operations exist for TCP and UDP headers
23Timers (simple, without extra data)
- Runs the run_timer function upon expiry
- class MyElement public Element
public void run_timer()private ... Timer
timer - MyElementMyElement() timer(this)int
MyElement configure(VectorltStringgt conf,
ErrorHandler errh) timer.initialize(this)
timer.schedule_after_ms(1000) return 0void
MyElement run_timer() click_chatter(we are
now 1 second later) timer.schedule_after_ms(100
0)
24Timers (with extra data)
- Run your callback function upon expiry, with data
- Because you want to know some context information
- Code is a little bit harder
- class MyElement public Element private struc
t TimerData // callback data MyElement
me Something s static void
handleExpiry(Timer, void ) // callback
function void expire(const MyElement ,
TimerData )
25Timers (with extra data) (2)
- void MyElementsomeFunction() TimerData
timerdata new TimerData() timerdata-gts new
Something() timerdata-gtme this Timer t
new Timer(MyElementhandleExpiry,timerdata) t-
gtinitialize(this) t-gtschedule_after_ms(2500)
void MyElementhandleExpiry(Timer, void
data) TimerData timerdata (TimerData)
data assert(timerdata) // the cast must be
good timerdata-gtme-gtexpire(timerdata-gts,timerdat
a)void MyElementexpire(const Something
s, TimerData timerdata) // do things with
Something // timerdata passed to free memory
after timer expiry
26Handlers basics
- Like function calls to an element
- ReadHandler
- Request a value from an element
- Or WriteHandler
- Pass a string to an element
- You can parse the string with cp_va_parse!
- There is no ReadWriteHandler
- You cant call a ReadHandler with arguments
- Can be called from other elements or through
socket - Take a look at Pokehandlers!
27Handlers Write implementation
- class WriteElement public Element public
static int handle(const String conf, Element
e, void thunk, ErrorHandler errh) void
add_handlers() - int WriteElementhandle(const String conf,
Element e, void thunk, ErrorHandler
errh) WriteElement me (WriteElement )
e if(cp_va_parse(conf, me, errh, , cpEnd) lt 0)
return -1 me-gtdoSomethingWithParsed() return
0 - void WriteElementadd_handlers() add_write_hand
ler(a_handle", handle, (void )0)
28Handlers Read implementation
- class ReadElement public Element public
static int handle(const String conf, Element
e, void thunk, ErrorHandler errh) void
add_handlers() - String ReadElementhandle(Element e, void
thunk) ReadElement me (ReadElement )
e return me-gtgiveSomeValue()void
ReadElementadd_handlers() add_read_handler(a_
handle", handle, (void )0)
29Handlers calling
- Start click
- click p ltport_nrgt ltclick_scriptgt
- click p 10000 somescript.click
- Connect to click with telnet
- telnet localhost 10000
- read ltelementnamegt.lthandlernamegt
- read rt.table
- write ltelementnamegt.lthandlernamegt ltvaluesgt
- write arptable.insert 0050BA8584B1 10.0.1.2
30References
- Click website http//www.read.cs.ucla.edu/click/
- Element documentation (by name or category)
- Programming Concepts
- Doxygen documentation
- Click thesis (online publications, Ph.D. thesis)
- Comprehensive documentation of every concept
- Interesting chapters
- Introduction
- Architecture elements, packets, connections,
push and pull, packet storage, element
implementation - Language syntax, configuration strings, compound
elements - Click source code
- /elements/ dozens of elements, some more trivial
than others - /include/ the Click STL headers