-
Notifications
You must be signed in to change notification settings - Fork 324
/
element.cc
3006 lines (2780 loc) · 102 KB
/
element.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// -*- c-basic-offset: 4; related-file-name: "../include/click/element.hh" -*-
/*
* element.{cc,hh} -- the Element base class
* Eddie Kohler
* statistics: Robert Morris
*
* Copyright (c) 1999-2000 Massachusetts Institute of Technology
* Copyright (c) 2004-2011 Regents of the University of California
* Copyright (c) 2010 Meraki, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software")
* to deal in the Software without restriction, subject to the conditions
* listed in the Click LICENSE file. These conditions include: you must
* preserve this copyright notice, and you cannot mention the copyright
* holders in advertising related to the Software without their permission.
* The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
* notice is a summary of the Click LICENSE file; the license in that file is
* legally binding.
*/
#include <click/config.h>
#define CLICK_ELEMENT_DEPRECATED /* Avoid warnings in this file */
#include <click/glue.hh>
#include <click/element.hh>
#include <click/bitvector.hh>
#include <click/args.hh>
#include <click/error.hh>
#include <click/router.hh>
#include <click/master.hh>
#include <click/straccum.hh>
#include <click/etheraddress.hh>
#if CLICK_DEBUG_SCHEDULING
# include <click/notifier.hh>
#endif
#if CLICK_LINUXMODULE
# include <click/cxxprotect.h>
CLICK_CXX_PROTECT
# include <asm/types.h>
# include <asm/uaccess.h>
CLICK_CXX_UNPROTECT
# include <click/cxxunprotect.h>
#elif CLICK_BSDMODULE
# include <click/cxxprotect.h>
CLICK_CXX_PROTECT
# include <sys/types.h>
# include <sys/limits.h>
CLICK_CXX_UNPROTECT
# include <click/cxxunprotect.h>
#endif
CLICK_DECLS
const char Element::PORTS_0_0[] = "0";
const char Element::PORTS_0_1[] = "0/1";
const char Element::PORTS_1_0[] = "1/0";
const char Element::PORTS_1_1[] = "1";
const char Element::PORTS_1_1X2[] = "1/1-2";
const char Element::AGNOSTIC[] = "a";
const char Element::PUSH[] = "h";
const char Element::PULL[] = "l";
const char Element::PUSH_TO_PULL[] = "h/l";
const char Element::PULL_TO_PUSH[] = "l/h";
const char Element::PROCESSING_A_AH[] = "a/ah";
const char Element::COMPLETE_FLOW[] = "x/x";
int Element::nelements_allocated = 0;
/** @mainpage Click
* @section Introduction
*
* The Click modular router is a system for developing network packet
* processors. This documentation describes Click's internal programming
* interfaces, which you will use if you want to write new packet processing
* modules (which we call <em>elements</em>).
*
* Most documented Click classes can be found under the "Classes" tab. Get
* started by looking at the Element class, or the args.hh header file
* for configuration string parsing.
*
* <a href='http://www.read.cs.ucla.edu/click/'>Main Click page</a>
*/
/** @class Element
@brief Base class for Click elements.
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:
<dl>
<dt>Behavior specifications</dt>
<dd>These functions return static constants that describe element
properties, such as class names, valid numbers of ports, and port processing
types. Their values are automatically extracted from element source code
for use by tools, so your source code should follow a specific syntax.
Examples: class_name(), port_count(), processing(), flow_code(), flags().</dd>
<dt>Configuration, initialization, and cleanup</dt>
<dd>Configuration and initialization functions are called to set up an
element as a router is initialized (or when the element itself is
reconfigured). Most of the functions are passed an ErrorHandler argument,
to which they should report any errors. By returning negative values, they
can prevent the router from initializing. Other functions clean up elements
when a router is removed and reconfigure an element as the router runs.
Examples: cast(), configure(), configure_phase(), add_handlers(),
initialize(), take_state(), cleanup(), can_live_reconfigure(),
live_reconfigure().</dd>
<dt>Packet and event processing</dt>
<dd>These functions are called as the router runs to process packets and
other events. Examples: push(), pull(), simple_action(), run_task(),
run_timer(), selected().</dd>
</dl>
<h3>Examples</h3>
Here is the simplest possible element definition.
@code
class MyNothingElement : public Element { public:
MyNothingElement() { }
~MyNothingElement() { }
const char *class_name() const { return "MyNothingElement"; }
};
@endcode
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 is code-complete, Click's build process requires a bit
more boilerplate, like so:
@code
// ================== 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)
@endcode
Some things to notice:
- The element class must be defined in a header file and a source file.
- The header file is protected from multiple inclusion. A common error is
to copy and paste another element's header file, but forget to change the
header protection symbol (here, CLICK_MYNOTHINGELEMENT_HH).
- All Click declarations are enclosed within a macro pair,
<tt>CLICK_DECLS</tt> and <tt>CLICK_ENDDECLS</tt>. These are required for
the NS and FreeBSD kernel drivers. Note that <tt>\#include</tt> statements
go @em outside the <tt>CLICK_DECLS/CLICK_ENDDECLS</tt> pair.
- The element's C++ class is defined in the header file.
- The first thing the source file does is <tt>\#include
<click/config.h></tt>. <strong>This is mandatory.</strong>
- The source file must contain a line like
<tt>EXPORT_ELEMENT(NameOfC++ClassForElement)</tt>. 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.
@code
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);
}
};
@endcode
This element processes packets in push mode, much like the standard @e
PushNull element.
<ul>
<li>The port_count() method tells Click that this element has one input and
one output. See port_count() for more.</li>
<li>The processing() method tells Click that this element's ports are in push
mode. See processing() for more.</li>
<li>The element doesn't define a configure() or initialize() method, so the
defaults are used: the element takes no configuration arguments, and
always initializes successfully.</li>
<li>The element has just one function called after router initialization,
namely push(). This function is called when another element pushes a
packet to this element. The implementation here simply pushes the packet
to the element's first output port.</li>
<li><strong>Invariants:</strong> Click's initialization process checks for
many kinds of errors, allowing the push() method to assume several
invariants. In particular, port_count() and processing() specify that
this element has one push input and one push output. Click therefore
ensures that the element's first input is used in a connection at least
once; that its first output is used in a connection
<em>exactly</em> once; that its other inputs and outputs are not
used at all; and that all connections involving the element's ports are
push.
As a result, the push() method can assume that <tt>port == 0</tt>, that
<tt>output(0)</tt> exists, and that <tt>output(0).push(p)</tt> is valid.
Elements must not push null packet pointers, either, so the push() method
can assume that <tt>p != 0</tt>.
There is no harm in verifying these invariants with assertions, since
bogus element code can violate them (by passing a bad value for
<tt>port</tt> or <tt>p</tt>, for example), but such errors are rare in
practice. Our elements mostly assume that the invariants
hold.</li>
</ul>
<h3>Packet Accounting</h3>
Element run-time methods, such as push(), pull(), run_task(), and
run_timer(), must always obey the following rules:
- Each Packet pointer is used by at most one element at a time.
- An element that obtains a Packet pointer must eventually free it or pass
it to another element. This avoids memory leaks.
Beginning Click programmers often violate these rules. Here are some
examples to make them concrete.
This incorrect version of Click's @e Tee element attempts to duplicate a
packet and send the duplicates to two different outputs.
@code
void BadTee::push(int port, Packet *p) {
output(0).push(p);
output(1).push(p);
}
@endcode
A single packet pointer @c 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 @e BadTee, so
<tt>output(1).push(p)</tt> would probably touch freed memory! This situation
requires the Packet::clone() method, which makes a copy of a packet:
@code
void BetterTee::push(int port, Packet *p) {
output(0).push(p->clone());
output(1).push(p);
}
@endcode
However, @e BetterTee would fail if the router ran out of memory for packet
clones. @c 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:
@code
void BestTee::push(int port, Packet *p) {
if (Packet *clone = p->clone())
output(0).push(clone);
output(1).push(p);
}
@endcode
Here's an example of a push() method with an obvious leak:
@code
void LeakyCounter::push(int port, Packet *p) {
_counter++;
}
@endcode
The method doesn't do anything with @c p, so its memory will never be
reclaimed. Instead, it should either free the packet or pass it on to another
element:
@code
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
}
@endcode
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.
@code
void LeakyIPCounter::push(int port, Packet *p) {
if (!p->has_network_header())
return;
_counter++;
output(0).push(p);
}
@endcode
Close, but no cigar: if the input packet has no network header pointer, the
packet will leak. Here are some better versions.
@code
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);
}
@endcode
<h3>Initialization Phases</h3>
The Click infrastructure calls element initialization functions in a
specific order during router initialization. Errors at any stage prevent
later stages from running.
-# Collects element properties, specifically configure_phase(),
port_count(), flow_code(), processing(), and can_live_reconfigure().
-# Calculates how many of each element's input and output ports are used in
the configuration. There is an error if port_count() doesn't allow the
result.
-# Calculates each port's push or pull status. This depends on processing()
values, and for agnostic ports, a constraint satisfaction algorithm that
uses flow_code().
-# Checks that every connection is between two push ports or two pull ports;
that there are no agnostic port conflicts (each port is used as push or
pull, never both); that no port goes unused; and that push output ports
and pull input ports are connected exactly once. Violations cause an
error.
-# Sorts the elements by configure_phase() to construct a configuration
order.
-# Calls each element's configure() method in order, passing its
configuration arguments and an ErrorHandler. All configure() functions
are called, even if a prior configure() function returns an error.
-# Calls every element's add_handlers() method.
-# Calls every element's initialize() method in configuration order.
Initialization is aborted as soon as any method returns an error
(i.e., some initialize() methods might not be called).
-# At this point, the router will definitely be installed. If the router
was installed with a hotswap option, then Click searches the old and new
router for potentially compatible pairs using hotswap_element(), and
calls take_state() for each pair. Any errors are ignored.
-# Installs the router.
Router cleanup takes place as follows. Click:
-# Removes all element handlers.
-# Calls each element's cleanup() function in reverse configuration order.
The argument to cleanup() indicates where the initialization process
completed for that element. See cleanup() for the specific constant
names.
-# Deletes each element. This step might be delayed relative to cleanup()
to allow the programmer to examine an erroneous router's state.
*/
/** @class Element::Port
* @brief An Element's ports.
*
* Each of an element's ports has an associated Port object, accessible via
* the Element::port(), Element::input(), and Element::output() functions.
* Each @em active port knows, and can transfer a packet with, the single
* complementary port to which it is connected. Thus, each push output knows
* its connected input, and can push a packet there; and each pull input can
* pull a packet from its connected output. Inactive ports -- push inputs and
* pull outputs -- can be connected multiple times. Their corresponding Port
* objects have very little functionality.
*
* Element authors generally encounter Port objects only in two stylized
* formulations. First, to push a packet @c p out on push output port @c i:
*
* @code
* output(i).push(p);
* @endcode
*
* And second, to pull a packet @c p from pull input port @c i:
*
* @code
* Packet *p = input(i).pull();
* @endcode
*
* @sa Element::checked_output_push() */
/** @brief Construct an Element. */
Element::Element()
: _router(0), _eindex(-1)
{
nelements_allocated++;
_ports[0] = _ports[1] = &_inline_ports[0];
_nports[0] = _nports[1] = 0;
#if CLICK_STATS >= 2
reset_cycles();
#endif
}
Element::~Element()
{
nelements_allocated--;
if (_ports[0] < _inline_ports || _ports[0] > _inline_ports + INLINE_PORTS)
delete[] _ports[0];
if (_ports[1] < _inline_ports || _ports[1] > _inline_ports + INLINE_PORTS)
delete[] _ports[1];
}
// CHARACTERISTICS
/** @fn Element::class_name() const
* @brief 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:
*
* @code
* const char *class_name() const { return "ARPQuerier"; }
* @endcode
*/
/** @brief Attempt to cast the element to a named type.
* @param name name of the type being cast to
*
* Click calls this function to see whether this element has a given type,
* identified by @a name. Thus, cast() is Click's version of the C++ @c
* dynamic_cast operator. (@c 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. @a name can name an element class or another type of interface, such
* as @c "Storage" or Notifier::EMPTY_NOTIFIER.
*
* The default implementation returns this element if @a 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 @a Derived
* inherited from element @a Base, Derived::cast() might be defined like this:
*
* @code
* 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);
* }
* @endcode
*
* The recursive call to Base::cast() is useful in case @e Base itself
* overrides cast(). The explicit check for the name @c "Base" is necessary
* in case @e Base did @e not override cast(): the default cast()
* implementation compares against class_name(), which in this case is @c
* "Derived". Always explicitly cast @c 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.
*
* @sa port_cast
*/
void *
Element::cast(const char *name)
{
const char *my_name = class_name();
if (my_name && name && strcmp(my_name, name) == 0)
return this;
else
return 0;
}
/** @brief Attempt to cast an element's port to a named type.
* @param isoutput false for input ports, true for output ports
* @param port port number
* @param name name of the type being cast to
*
* Click calls this function to see whether a port corresponds to an object of
* the type called @a name. The function should return a pointer to the named
* object, or a null pointer if this port doesn't have that type. @a name can
* name an element class or another type of interface, such as @c "Storage" or
* Notifier::EMPTY_NOTIFIER.
*
* The default implementation returns the result of cast(), ignoring the @a
* isoutput and @a port arguments.
*
* The cast() method suffices for most purposes, but some Click functionality,
* such as Notifiers, can use the additional precision of port_cast().
*
* @sa cast
*/
void *
Element::port_cast(bool isoutput, int port, const char *name)
{
(void) isoutput, (void) port;
return cast(name);
}
/** @brief Return the element's name.
*
* This is the name used to declare the element in the router configuration,
* with all compound elements expanded. */
String
Element::name() const
{
String s;
if (Router *r = router())
s = r->ename(_eindex);
return (s ? s : String::make_stable("<unknown>", 9));
}
/** @cond never */
/** @brief Return the element's name (deprecated).
*
* @deprecated This function is deprecated; use name() instead. */
String
Element::id() const
{
return name();
}
/** @brief Return a string describing where the element was declared.
*
* The string generally has the form
* "<em>filename</em>:<em>linenumber</em>". */
String
Element::landmark() const
{
String s;
if (Router *r = router())
s = r->elandmark(_eindex);
return (s ? s : String::make_stable("<unknown>", 9));
}
/** @endcond never */
/** @brief Return a string giving the element's name and class name.
*
* The result has the form "@e name :: @e class_name". Element
* classes can override this function to supply additional important
* information, if desired; for example, @e FromDump returns a string "@e
* name :: @e class_name(@e filename)".
*/
String
Element::declaration() const
{
return name() + " :: " + class_name();
}
// INPUTS AND OUTPUTS
int
Element::set_nports(int new_ninputs, int new_noutputs)
{
// exit on bad counts, or if already initialized
if (new_ninputs < 0 || new_noutputs < 0)
return -EINVAL;
if (_router && _router->_have_connections) {
if (_router->_state >= Router::ROUTER_PREINITIALIZE)
return -EBUSY;
_router->_have_connections = false;
}
// decide if inputs & outputs were inlined
bool old_in_inline =
(_ports[0] >= _inline_ports && _ports[0] <= _inline_ports + INLINE_PORTS);
bool old_out_inline =
(_ports[1] >= _inline_ports && _ports[1] <= _inline_ports + INLINE_PORTS);
bool prefer_pull = (processing() == PULL);
// decide if inputs & outputs should be inlined
bool new_in_inline =
(new_ninputs == 0
|| new_ninputs + new_noutputs <= INLINE_PORTS
|| (new_ninputs <= INLINE_PORTS && new_noutputs > INLINE_PORTS)
|| (new_ninputs <= INLINE_PORTS && prefer_pull));
bool new_out_inline =
(new_noutputs == 0
|| new_ninputs + new_noutputs <= INLINE_PORTS
|| (new_noutputs <= INLINE_PORTS && !new_in_inline));
// create new port arrays
Port *new_inputs;
if (new_in_inline)
new_inputs = _inline_ports + (!new_out_inline || prefer_pull ? 0 : new_noutputs);
else if (!(new_inputs = new Port[new_ninputs]))
return -ENOMEM;
Port *new_outputs;
if (new_out_inline)
new_outputs = _inline_ports + (!new_in_inline || !prefer_pull ? 0 : new_ninputs);
else if (!(new_outputs = new Port[new_noutputs])) {
if (!new_in_inline)
delete[] new_inputs;
return -ENOMEM;
}
// install information
if (!old_in_inline)
delete[] _ports[0];
if (!old_out_inline)
delete[] _ports[1];
_ports[0] = new_inputs;
_ports[1] = new_outputs;
_nports[0] = new_ninputs;
_nports[1] = new_noutputs;
return 0;
}
/** @brief 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:
*
* <dl>
* <dt><tt>"1/1"</tt></dt> <dd>The element has exactly one input port and one
* output port.</dd>
* <dt><tt>"1-2/0"</tt></dt> <dd>One or two input ports and zero output
* ports.</dd>
* <dt><tt>"1/-6"</tt></dt> <dd>One input port and up to six output ports.</dd>
* <dt><tt>"2-/-"</tt></dt> <dd>At least two input ports and any number of
* output ports.</dd>
* <dt><tt>"3"</tt></dt> <dd>Exactly three input and output ports. (If no
* slash appears, the text is used for both input and output ranges.)</dd>
* <dt><tt>"1-/="</tt></dt> <dd>At least one input port and @e the @e same
* number of output ports.</dd>
* <dt><tt>"1-/=+"</tt></dt> <dd>At least one input port and @e one @e more
* output port than there are input ports.</dd>
* </dl>
*
* Port counts are used to 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 (or a name below). It should also have public
* accessibility. Here's an acceptable port_count() definition:
*
* @code
* const char *port_count() const { return "1/1"; }
* @endcode
*
* The default port_count() method returns @c "0/0".
*
* The following names are available for common port count specifiers.
*
* @arg @c PORTS_0_0 for @c "0/0"
* @arg @c PORTS_0_1 for @c "0/1"
* @arg @c PORTS_1_0 for @c "1/0"
* @arg @c PORTS_1_1 for @c "1/1"
* @arg @c PORTS_1_1X2 for @c "1/1-2"
*
* Since port_count() should simply return a C string constant, it shouldn't
* matter when it's called; nevertheless, it is called before configure().
*/
const char *
Element::port_count() const
{
return PORTS_0_0;
}
static int
notify_nports_pair(const char *&s, const char *ends, int &lo, int &hi)
{
if (s == ends || *s == '-')
lo = 0;
else if (isdigit((unsigned char) *s))
s = cp_integer(s, ends, 10, &lo);
else
return -1;
if (s < ends && *s == '-') {
s++;
if (s < ends && isdigit((unsigned char) *s))
s = cp_integer(s, ends, 10, &hi);
else
hi = INT_MAX;
} else
hi = lo;
return 0;
}
int
Element::notify_nports(int ninputs, int noutputs, ErrorHandler *errh)
{
// Another version of this function is in tools/lib/processingt.cc.
// Make sure you keep them in sync.
const char *s_in = port_count();
const char *s = s_in, *ends = s + strlen(s);
int ninlo, ninhi, noutlo, nouthi, equal = 0;
if (notify_nports_pair(s, ends, ninlo, ninhi) < 0)
goto parse_error;
if (s == ends)
s = s_in;
else if (*s == '/')
s++;
else
goto parse_error;
if (*s == '=') {
const char *plus = s + 1;
do {
equal++;
} while (plus != ends && *plus++ == '+');
if (plus != ends)
equal = 0;
}
if (!equal)
if (notify_nports_pair(s, ends, noutlo, nouthi) < 0 || s != ends)
goto parse_error;
if (ninputs < ninlo)
ninputs = ninlo;
else if (ninputs > ninhi)
ninputs = ninhi;
if (equal)
noutputs = ninputs + equal - 1;
else if (noutputs < noutlo)
noutputs = noutlo;
else if (noutputs > nouthi)
noutputs = nouthi;
set_nports(ninputs, noutputs);
return 0;
parse_error:
if (errh)
errh->error("%p{element}: bad port count", this);
return -1;
}
void
Element::initialize_ports(const int *in_v, const int *out_v)
{
for (int i = 0; i < ninputs(); i++) {
// allowed iff in_v[i] == VPULL
int port = (in_v[i] == VPULL ? 0 : -1);
_ports[0][i].assign(false, this, 0, port);
}
for (int o = 0; o < noutputs(); o++) {
// allowed iff out_v[o] != VPULL
int port = (out_v[o] == VPULL ? -1 : 0);
_ports[1][o].assign(true, this, 0, port);
}
}
int
Element::connect_port(bool isoutput, int port, Element* e, int e_port)
{
if (port_active(isoutput, port)) {
_ports[isoutput][port].assign(isoutput, this, e, e_port);
return 0;
} else
return -1;
}
// FLOW
/** @brief Return the element's internal packet flow specifier (its
* <em>flow code</em>).
*
* 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? 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
* @e port @e 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 @c "x/x" says that packets can travel from the element's input
* port to its output port, while @c "x/y" says that packets never travel
* between ports.
*
* A port code may also be a sequence of letters in brackets, such as
* <tt>[abz]</tt>. Two port codes match iff they have at least one letter in
* common, so <tt>[abz]</tt> matches <tt>a</tt>, but <tt>[abz]</tt> and
* <tt>[cde]</tt> do not match. If a caret <tt>^</tt> appears after the open
* bracket, the port code will match all letters @e except for
* those after the caret. Thus, the port code <tt>[^bc]</tt> is equivalent to
* <tt>[ABC...XYZadef...xyz]</tt>.
*
* Finally, the @c # character is also a valid port code, and may be used
* within brackets. One @c # matches another @c # only when they represent
* the same port number -- for example, when one @c # corresponds to input
* port 2 and the other to output port 2. @c # never matches any letter.
* Thus, for an element with exactly 2 inputs and 2 outputs, the flow code @c
* "##/##" behaves like @c "xy/xy".
*
* The last code in each specification is duplicated as many times as
* necessary, and any extra codes are ignored. The flow codes @c
* "[x#][x#][x#]/x######" and @c "[x#]/x#" behave identically.
*
* Here are some example flow codes.
*
* <dl>
* <dt><tt>"x/x"</tt></dt>
* <dd>Packets may travel from any input port to any output port. Most
* elements use this flow code.</dd>
*
* <dt><tt>"xy/x"</tt></dt>
* <dd>Packets arriving on input port 0 may travel to any output port, but
* those arriving on other input ports will not be emitted on any output.
* @e ARPQuerier uses this flow code.</dd>
*
* <dt><tt>"x/y"</tt></dt> <dd>Packets never travel between input and output
* ports. @e Idle and @e Error use this flow code. So does @e KernelTun,
* since its input port and output port are decoupled (packets received on its
* input are sent to the kernel; packets received from the kernel are sent to
* its output).</dd>
*
* <dt><tt>"#/#"</tt></dt> <dd>Packets arriving on input port @e K may travel
* only to output port @e K. @e Suppressor uses this flow code.</dd>
*
* <dt><tt>"#/[^#]"</tt></dt> <dd>Packets arriving on input port @e K may
* travel to any output port except @e K. @e EtherSwitch uses this flow
* code.</dd>
*
* <dt><tt>"xy/[xy]x"</tt></dt> <dd>Packets arriving on input port 0 may
* travel to any output port. Packet arriving on any other input port can
* <em>only</em> travel to output port 0. @e Bypass uses this flow code.</dd>
*
* </dl>
*
* 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:
*
* @code
* const char *flow_code() const { return "xy/x"; }
* @endcode
*
* The default flow_code() method returns @c "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.
*
* @arg @c COMPLETE_FLOW for @c "x/x"
*
* Since flow_code() should simply return a C string constant, it shouldn't
* matter when it's called; nevertheless, it is called before configure().
*
* <h3>Determining an element's flow code</h3>
*
* To pick the right flow code for an element, consider how a flow code would
* affect a simple router.
*
* Given an element @e E with input port @e M and output port @e N, imagine
* this simple configuration (or a similar configuration):
*
* <tt>... -> RED -> [@e M] E [@e N] -> Queue -> ...;</tt>
*
* Now, should the @e RED element include the @e Queue element in its queue
* length calculation? If so, then the flow code's <em>M</em>th input port
* code and <em>N</em>th output port code should match. If not, they
* shouldn't.
*
* For example, consider @e ARPQuerier's second input port. On receiving an
* ARP response on that input, @e ARPQuerier may emit a held-over IP packet to
* its first output. However, a @e RED element upstream of that second input
* port probably wouldn't count the downstream @e Queue in its queue length
* calculation. After all, the ARP responses are effectively dropped; packets
* emitted onto the @e Queue originally came from @e ARPQuerier's first input
* port. Therefore, @e ARPQuerier's flow code, <tt>"xy/x"</tt>, specifies
* that packets arriving on the second input port are not emitted on any
* output port.
*
* The @e 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 @e RED element upstream of @e
* ARPResponder probably @e would want to include a downstream @e Queue, since
* queries received by @e ARPResponder are effectively transmuted into emitted
* responses. Thus, @e ARPResponder's flow code, <tt>"x/x"</tt> (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 @c COMPLETE_FLOW.
*/
const char *
Element::flow_code() const
{
return COMPLETE_FLOW;
}
static void
skip_flow_code(const char*& p)
{
if (*p != '/' && *p != 0) {
if (*p == '[') {
for (p++; *p != ']' && *p; p++)
/* nada */;
if (*p)
p++;
} else
p++;
}
}
static int
next_flow_code(const char*& p, int port, Bitvector& code, ErrorHandler* errh, const Element* e)
{
if (*p == '/' || *p == 0) {
// back up to last code character
if (p[-1] == ']') {
for (p -= 2; *p != '['; p--)
/* nada */;
} else
p--;
}
code.assign(256, false);
if (*p == '[') {
bool negated = false;
if (p[1] == '^')
negated = true, p++;
for (p++; *p != ']' && *p; p++) {
// no isalpha: avoid locale and signed char dependencies
if ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z'))
code[*p] = true;
else if (*p == '#')
code[port + 128] = true;
else if (errh)
errh->error("%<%p{element}%> flow code: invalid character %<%c%>", e, *p);
}
if (negated)
code.flip();
if (!*p) {
if (errh)
errh->error("%<%p{element}%> flow code: missing %<]%>", e);
p--; // don't skip over final '\0'
}
} else if ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z'))
code[*p] = true;
else if (*p == '#')
code[port + 128] = true;
else {
if (errh)
errh->error("%<%p{element}%> flow code: invalid character %<%c%>", e, *p);
p++;
return -1;
}
p++;
return 0;
}
/** @brief Analyze internal packet flow with respect to port @a p.