2#ifndef CLICK_FLOWELEMENT_HH
3#define CLICK_FLOWELEMENT_HH
4#include <click/glue.hh>
7#include <click/batchelement.hh>
9#include <click/pair.hh>
19class VirtualFlowManager;
32class FlowElement :
public BatchElement {
43 virtual FlowType getContext(
int port);
45 virtual bool stopClassifier() {
return false; };
48 inline void fcb_acquire(
int count = 1) {
49 fcb_stack->acquire(count);
51 inline void fcb_update(
int count) {
53 fcb_stack->acquire(count);
55 fcb_stack->release(-count);
58 inline void fcb_release(
int count = 1) {
59 fcb_stack->release(count);
62 inline void fcb_acquire(
int count = 1) {
65 inline void fcb_update(
int) {}
66 inline void fcb_release(
int count = 1) {
76class VirtualFlowSpaceElement :
public FlowElement {
78 VirtualFlowSpaceElement();
80 virtual const size_t flow_data_size()
const = 0;
81 virtual const int flow_data_index()
const {
84 virtual const int flow_announce_manager(VirtualFlowManager* manager,
ErrorHandler* errh)
const {
87 inline void set_flow_data_offset(
int offset) {_flow_data_offset = offset; }
88 inline int flow_data_offset() {
return _flow_data_offset; }
90 int configure_phase()
const {
return CONFIGURE_PHASE_DEFAULT + 5; }
92 void *cast(
const char *name)
override;
95#if HAVE_CTX_GLOBAL_TIMEOUT
96 inline void ctx_acquire_timeout(
int nmsec) {
98 if ((fcb_stack->flags & FLOW_TIMEOUT) && (nmsec <= (
int)(fcb_stack->flags >> FLOW_TIMEOUT_SHIFT))) {
99#if DEBUG_CLASSIFIER_TIMEOUT > 1
100 click_chatter(
"Acquiring timeout of %p, not changing it, flag %d",
this,fcb_stack->flags);
104#if DEBUG_CLASSIFIER_TIMEOUT > 1
105 click_chatter(
"Acquiring timeout of %p to %d, flag %d",
this,nmsec,fcb_stack->flags);
107 fcb_stack->flags = (nmsec << FLOW_TIMEOUT_SHIFT) | FLOW_TIMEOUT | ((fcb_stack->flags & FLOW_TIMEOUT_INLIST) ? FLOW_TIMEOUT_INLIST : 0);
110 inline void ctx_release_timeout() {
111#if DEBUG_CLASSIFIER_TIMEOUT > 1
112 click_chatter(
"Releasing timeout of %p",
this);
115 if (fcb_stack->flags & FLOW_TIMEOUT_INLIST)
116 assert(fcb_stack->flags & FLOW_TIMEOUT);
117 if ((fcb_stack->flags & FLOW_TIMEOUT) && (fcb_stack->flags & FLOW_TIMEOUT_INLIST))
118 fcb_stack->flags = 0 | FLOW_TIMEOUT | FLOW_TIMEOUT_INLIST;
120 fcb_stack->flags = 0;
123 inline void ctx_acquire_timeout(
int nmsec) {
128 inline void ctx_release_timeout() {
134 inline void fcb_set_release_fnt(
struct FlowReleaseChain* fcb_chain, SubFlowRealeaseFnt fnt) {
135 fcb_chain->previous_fnt = fcb_stack->release_fnt;
136 fcb_chain->previous_thunk = fcb_stack->thunk;
137 fcb_stack->release_fnt = fnt;
138 fcb_stack->thunk =
this;
139#if DEBUG_CLASSIFIER_RELEASE
140 click_chatter(
"Release fnt set to %p, was %p",fcb_stack->release_fnt,fcb_chain->previous_fnt);
143 inline void fcb_remove_release_fnt(
struct FlowReleaseChain* fcb_chain, SubFlowRealeaseFnt fnt) {
144 debug_flow(
"Release fnt remove %p",fnt);
145 if (likely(fcb_stack->release_fnt == fnt)) {
146 fcb_stack->release_fnt = fcb_chain->previous_fnt;
147 fcb_stack->thunk = fcb_chain->previous_thunk;
148 debug_flow(
"Release removed is now to %p",fcb_stack->release_fnt);
150 SubFlowRealeaseFnt chain_fnt = fcb_stack->release_fnt;
151 VirtualFlowSpaceElement* fe =
static_cast<VirtualFlowSpaceElement*
>(fcb_stack->thunk);
152 FlowReleaseChain* frc;
155 click_chatter(
"BAD ERROR : Trying to remove a timeout flow function that is not set...");
159 frc =
reinterpret_cast<FlowReleaseChain*
>(&fcb_stack->data[fe->_flow_data_offset]);
160 chain_fnt = frc->previous_fnt;
161 if (chain_fnt == 0) {
162 click_chatter(
"ERROR : Trying to remove a timeout flow function that is not set...");
165 fe =
static_cast<VirtualFlowSpaceElement*
>(frc->previous_thunk);
166 }
while (chain_fnt != fnt);
167 frc->previous_fnt = fcb_chain->previous_fnt;
168 frc->previous_thunk = fcb_chain->previous_thunk;
172 inline void fcb_set_release_fnt(
struct FlowReleaseChain*, SubFlowRealeaseFnt) {
173 click_chatter(
"ERROR: YOU MUST HAVE DYNAMIC FLOW RELEASE FNT fct setted !");
179 virtual PacketBatch* pull_batch(
int port,
unsigned max)
override final {
180 click_chatter(
"ERROR : Flow Elements do not support pull");
184 int initialize(
ErrorHandler *errh)
override CLICK_COLD {
190 int _flow_data_offset;
191 friend class FlowBufferVisitor;
192 friend class VirtualFlowManager;
195# if HAVE_FLOW_DYNAMIC
199 Element *from_e,
int from_port,
int distance);
212class CounterInitFuture :
public Router::ChildrenFuture {
public:
214 CounterInitFuture(
String name, std::function<
void(
void)> on_reached);
216 virtual void notifyParent(InitFuture* future)
override;
218 virtual int solve_initialize(
ErrorHandler* errh)
override;
230class VirtualFlowManager :
public FlowElement {
public:
231 VirtualFlowManager();
233 static CounterInitFuture* fcb_builded_init_future() {
234 return &_fcb_builded_init_future;
237 static CounterInitFuture _fcb_builded_init_future;
242 typedef Pair<Element*,int> EDPair;
248 void find_children(
int verbose = 0);
250 static void _build_fcb(
int verbose,
bool ordered);
251 static void build_fcb();
252 virtual void fcb_built() {
256 bool stopClassifier() {
return true; };
258 friend class CTXElement;
262template<
typename T>
class FlowSpaceElement :
public VirtualFlowSpaceElement {
266 FlowSpaceElement() CLICK_COLD;
268 void fcb_set_init_data(FlowControlBlock* fcb, const T data) CLICK_COLD;
270 virtual const
size_t flow_data_size()
const override {
return sizeof(T); }
276 inline T* fcb_data_for(FlowControlBlock* fcb) {
277 T* flowdata =
static_cast<T*
>((
void*)&fcb->data[_flow_data_offset]);
284 inline T* fcb_data() {
285 return fcb_data_for(fcb_stack);
288 void push_batch(
int port,
PacketBatch* head)
final {
289 push_flow(port, fcb_data(), head);
292 virtual void push_flow(
int port, T* flowdata,
PacketBatch* head) = 0;
295class DefaultChecker {
public:
299 static inline bool seen(
void*, str* s) {
302 static inline void mark_seen(
void*, str* s) {
305 static inline void release(
void*, str* s) {
321template<
class Derived,
typename T,
typename Checker = DefaultChecker>
class FlowStateElement :
public VirtualFlowSpaceElement {
322 struct AT :
public FlowReleaseChain {
324 typename Checker::str str;
328 typedef FlowStateElement<Derived, T, Checker> derived;
330 FlowStateElement() CLICK_COLD;
332 virtual const
size_t flow_data_size()
const {
return sizeof(AT); }
334 if (Derived::timeout > 0) {
335 if (manager->
cast(
"CTXManager") == 0) {
336 errh->
warning(
"The timeout of %dms of %p{element} is ignored, only the flow manager %p{element} timeout is prevalent.", Derived::timeout,
this, manager);
345 inline bool new_flow(T*,
Packet*) {
349 inline FlowControlBlock* stack_from_flow(
void* ptr) {
350 return (FlowControlBlock*)(((uint8_t*)ptr) - _flow_data_offset -
sizeof(FlowControlBlock));
356 inline T* fcb_data_for(FlowControlBlock* fcb) {
357 AT* flowdata =
static_cast<AT*
>((
void*)&fcb->data[_flow_data_offset]);
364 inline T* fcb_data() {
365 return fcb_data_for(fcb_stack);
368 static void release_fnt(FlowControlBlock* fcb,
void* thunk ) {
369 Derived* derived =
static_cast<Derived*
>(thunk);
370 AT* my_fcb =
reinterpret_cast<AT*
>(&fcb->data[derived->_flow_data_offset]);
371 derived->release_flow(&my_fcb->v);
372 if (my_fcb->previous_fnt)
373 my_fcb->previous_fnt(fcb, my_fcb->previous_thunk);
377 auto my_fcb = my_fcb_data();
378 if (!Checker::seen(&my_fcb->v, &my_fcb->str)) {
379 if (
static_cast<Derived*
>(
this)->new_flow(&my_fcb->v, head->first())) {
380 Checker::mark_seen(&my_fcb->v, &my_fcb->str);
381 if (Derived::timeout > 0)
382 this->ctx_acquire_timeout(Derived::timeout);
384 this->fcb_set_release_fnt(my_fcb, &release_fnt);
391 static_cast<Derived*
>(
this)->push_flow(port, &my_fcb->v, head);
395 if (Derived::timeout > 0) {
396 this->ctx_release_timeout();
399 this->fcb_remove_release_fnt(my_fcb_data(), &release_fnt);
401 Checker::release(&my_fcb_data()->v, &my_fcb_data()->str);
405 inline AT* my_fcb_data() {
406 return static_cast<AT*
>((
void*)&fcb_stack->data[_flow_data_offset]);
412template<
typename T,
int index>
class FlowSharedBufferElement :
public FlowSpaceElement<T> {
416 FlowSharedBufferElement() : FlowSpaceElement<T>() {
420 const size_t flow_data_size() const final {
return sizeof(T); }
421 const int flow_data_index() const final {
return index; }
426#define DefineFlowSharedBuffer(name,type,index) class FlowSharedBuffer ## name ## Element : public FlowSharedBufferElement<type,index>{ };
428DefineFlowSharedBuffer(Paint,
int,0);
429#define NR_SHARED_FLOW 1
434 FlowElementVisitor(
Element* e) : origin(e) {
445 Element *from_e,
int from_port,
int distance) {
449 FlowElement* dispatcher =
dynamic_cast<FlowElement*
>(e);
450 if (dispatcher != NULL) {
451 if (dispatcher == origin)
453 struct inputref ref = {.elem = dispatcher, .iport = port};
475FlowSpaceElement<T>::FlowSpaceElement() : VirtualFlowSpaceElement() {
480void FlowSpaceElement<T>::fcb_set_init_data(FlowControlBlock* fcb,
const T data) {
481 for (
int i = 0; i <
sizeof(T); i++) {
482 if (fcb->data[FCBPool::init_data_size() + _flow_data_offset + i] && fcb->data[_flow_data_offset + i] != ((uint8_t*)&data)[i]) {
483 click_chatter(
"In %p{element} for offset %d :",
this, _flow_data_offset+i);
484 click_chatter(
"Index [%d] : Cannot set data to %d, as it is already %d",i,*((T*)(&fcb->data[_flow_data_offset])),data);
485 click_chatter(
"Is marked as set : %d", fcb->data[FCBPool::init_data_size() + _flow_data_offset + i]);
486 fcb->reverse_print();
488 click_chatter(
"It generally means your graph is messed up");
491 fcb->data[FCBPool::init_data_size() + _flow_data_offset + i] = 0xff;
493 *((T*)(&fcb->data[_flow_data_offset])) = data;
501template<
class Derived,
typename T,
typename Checker>
502FlowStateElement<Derived, T, Checker>::FlowStateElement() : VirtualFlowSpaceElement() {
512#define DEFAULT_4TUPLE "12/0/ffffffff:HASH-3 16/0/ffffffff:HASH-3 20/0/ffffffff:HASH-3"
515#define TCP_SESSION "9/06! 12/0/ffffffff:HASH-3 16/0/ffffffff:HASH-3 20/0/ffffffff:HASH-3"
516#define UDP_SESSION "9/11! 12/0/ffffffff:HASH-3 16/0/ffffffff:HASH-3 20/0/ffffffff:HASH-3"
523#define FLOW_ELEMENT_DEFINE_CONTEXT(ft) \
524FlowNode* get_table(int iport, Vector<FlowElement*> context) override CLICK_COLD {\
525 context.push_back(this);\
526 return FlowElement::get_table(iport, context);\
528virtual FlowType getContext(int) override {\
535#define FLOW_ELEMENT_DEFINE_SESSION_CONTEXT(rule,ft) \
536FlowNode* get_table(int iport, Vector<FlowElement*> contextStack) override CLICK_COLD {\
538 contextStack.push_back(this);\
539 FlowNode* down = FlowElement::get_table(iport,contextStack); \
540 FlowNode* my = FlowClassificationTable::parse(this,rule).root;\
541 return my->combine(down, true, true, true, this);\
543virtual FlowType getContext(int) override {\
550#define FLOW_ELEMENT_DEFINE_SESSION(rule) \
551 FLOW_ELEMENT_DEFINE_SESSION_CONTEXT(rule,FLOW_NONE)
556#define FLOW_ELEMENT_DEFINE_SESSION_DUAL(ruleA,ruleB) \
557FlowNode* get_table(int iport, Vector<FlowElement*> context) override CLICK_COLD {\
558 return FlowClassificationTable::parse(this,ruleA).root->combine(FlowClassificationTable::parse(this,ruleB).root,false,false,true,this)->combine(FlowElement::get_table(iport,context), true, true, true, this);\
564#define FLOW_ELEMENT_DEFINE_PORT_SESSION_CONTEXT(port_num,rule,ft) \
565FlowNode* get_table(int iport, Vector<FlowElement*> contextStack) override {\
566 if (iport == port_num) {\
567 return FlowClassificationTable::parse(this,rule).root->combine(FlowElement::get_table(iport,contextStack), true, true, true, this);\
570 contextStack.push_back(this);\
571 return FlowElement::get_table(iport,contextStack);\
573virtual FlowType getContext(int) override {\
579typedef BatchElement FlowElement;
581#if !defined(HAVE_CTX)
582#define FLOW_ELEMENT_DEFINE_SESSION(rule,context)
583#define FLOW_ELEMENT_DEFINE_PORT_CONTEXT(port,rule,context)
584#define FLOW_ELEMENT_DEFINE_SESSION_DUAL(ruleA,ruleB)
585#define FLOW_ELEMENT_DEFINE_SESSION_CONTEXT(rule,context)
586#define FLOW_ELEMENT_DEFINE_PORT_SESSION_CONTEXT(port,rule,context)
Base class for Click elements.
Definition element.hh:42
virtual void * cast(const char *name)
Attempt to cast the element to a named type.
Definition element.cc:515
Error reporting class.
Definition error.hh:90
int warning(const char *fmt,...)
Print a warning message (level el_warning).
Definition error.cc:815
Definition packetbatch.hh:415
A network packet.
Definition packet.hh:68
Base class for router configuration visitors.
Definition routervisitor.hh:17
virtual bool visit(Element *e, bool isoutput, int port, Element *from_e, int from_port, int distance)
Visit an element.
Definition routervisitor.cc:29
A string of characters.
Definition string.hh:22
Vector template.
Definition vector.hh:111
void push_back(value_argument_type v)
Append element v.
Definition vector.hh:399
Router configuration visitors for finding elements and ports.
Click's vector container template.