1#ifndef CLICK_FLOWCOMMON_HH
2#define CLICK_FLOWCOMMON_HH
3#include <click/ring.hh>
4#include <click/multithread.hh>
6#include <click/allocator.hh>
11#define DEBUG_CLASSIFIER_MATCH 0
12#define DEBUG_CLASSIFIER_RELEASE 0
13#define DEBUG_CLASSIFIER_TIMEOUT 0
14#define DEBUG_CLASSIFIER_TIMEOUT_CHECK 0
15#define DEBUG_CLASSIFIER 0
17#define HAVE_STATIC_CLASSIFICATION 0 || !HAVE_FLOW_DYNAMIC
19#define RELEASE_RESET 0
21#define RELEASE_EPOCH 2
23#define DEBUG_CLASSIFIER_CHECK 0
25#if DEBUG_CLASSIFIER > 1
26 #define debug_flow_2(...) click_chatter(__VA_ARGS__);
27 #define debug_flow(...) click_chatter(__VA_ARGS__);
29 #define debug_flow(...) click_chatter(__VA_ARGS__);
30 #define debug_flow_2(...)
32 #define debug_flow(...)
33 #define debug_flow_2(...)
36#if DEBUG_CLASSIFIER_CHECK || DEBUG_CLASSIFIER
37 #define flow_assert(...) assert(__VA_ARGS__);
38 #define FLOW_INDEX(table,index) table[index]
40 #define flow_assert(...)
41 #define FLOW_INDEX(table,index) table.unchecked_at(index)
44class FlowControlBlock;
53#if HAVE_LONG_CLASSIFICATION
58 explicit FlowNodeData() :
59#if HAVE_LONG_CLASSIFICATION
66#if HAVE_LONG_CLASSIFICATION
67 explicit FlowNodeData(uint8_t d) : data_64(d) {};
68 explicit FlowNodeData(uint16_t d) : data_64(d) {};
69 explicit FlowNodeData(uint32_t d) : data_64(d) {};
70 explicit FlowNodeData(uint64_t d) : data_64(d) {};
72 explicit FlowNodeData(uint8_t d) : data_32(d) {};
73 explicit FlowNodeData(uint16_t d) : data_32(d) {};
74 explicit FlowNodeData(uint32_t d) : data_32(d) {};
75 explicit FlowNodeData(uint64_t d) : data_32((uint32_t)d) {};
78 inline bool equals(
const FlowNodeData &other) {
79#if HAVE_LONG_CLASSIFICATION
80 return data_64 == other.data_64;
82 return data_32 == other.data_32;
86 inline uint64_t get_long()
const {
87#if HAVE_LONG_CLASSIFICATION
95typedef void (*SubFlowRealeaseFnt)(FlowControlBlock* fcb,
void* thunk);
98struct FlowReleaseChain {
99 SubFlowRealeaseFnt previous_fnt;
100 void* previous_thunk;
103struct FlowReleaseChain {
107class FlowControlBlock {
111 #ifdef FLOW_ATOMIC_USE_COUNT
124#if HAVE_CTX_GLOBAL_TIMEOUT
130 #define FLOW_TIMEOUT_INLIST 0x40
131 #define FLOW_TIMEOUT 0x80
132 #define FLOW_TIMEOUT_SHIFT 8
133 #define FLOW_TIMEOUT_MASK 0x000000ff
135 FlowControlBlock* next;
137 inline bool hasTimeout()
const {
138 return flags & FLOW_TIMEOUT;
141 inline bool timeoutPassed(
Timestamp now)
const {
142 unsigned t = (flags >> FLOW_TIMEOUT_SHIFT);
143 return t == 0 || (now - lastseen).msecval() > t;
147 #define FLOW_EARLY_DROP 0x20
150 inline void set_early_drop(
bool set=
true) {
152 flags |= FLOW_EARLY_DROP;
154 flags &= ~FLOW_EARLY_DROP;
157 inline bool is_early_drop()
const {
158 return flags & FLOW_EARLY_DROP;
164 SubFlowRealeaseFnt release_fnt ;
175 FlowNodeData node_data[0];
177 inline FlowNodeData& get_data() {
182 bool combine_data(uint8_t* data,
Element* origin);
183 inline void initialize() {
195#if HAVE_CTX_GLOBAL_TIMEOUT
202 inline void acquire(
int packets_nr = 1);
203 inline void release(
int packets_nr = 1);
205 inline void _do_release();
207 inline unsigned count()
const {
211 inline void reset_count(
unsigned n) {
215 inline void acquire(
int packets_nr = 1) {
218 inline void release(
int packets_nr = 1) {
221 inline int count()
const {
225 FlowControlBlock* duplicate(
unsigned use_count);
226 inline FCBPool* get_pool()
const;
228 void print(
String prefix,
int data_offset =-1,
bool show_ptr=
false)
const;
229 void reverse_print();
230 FlowNode* find_root();
240 int hashcode()
const;
243class FlowControlBlockRef {
public:
245 FlowControlBlock* _ref;
247 FlowControlBlockRef(FlowControlBlock* ref) {
251 typedef FlowControlBlockRef key_type;
252 typedef const FlowControlBlockRef &key_const_reference;
254 key_const_reference hashkey()
const {
255 return const_cast<key_const_reference
>(*this);
258 inline int hashcode()
const {
259 return _ref->hashcode();
263bool operator==(
const FlowControlBlockRef &ra,
const FlowControlBlockRef &rb);
265class FlowTableHolder;
267extern __thread FlowControlBlock* fcb_stack;
268extern __thread FlowTableHolder* fcb_table;
271#define SFCB_STACK_PUSH() FlowControlBlock* fcb_save = fcb_stack;fcb_stack=0;
272#define SFCB_STACK_POP() fcb_stack=fcb_save;
273#define SFCB_STACK(fnt) \
274 {SFCB_STACK_PUSH();fnt;SFCB_STACK_POP();}
277#define CLICK_DEBUG_FCBPOOL 0
279#define SFCB_POOL_COUNT 32
280#define SFCB_POOL_SIZE 2048
285 FlowControlBlock* _p;
289 operator int()
const {
return _count; }
291 SFCBList (
int c) : _p(0), _count( c ) {
294 SFCBList() : _p(0), _count(0) {
297 inline void reset() {
302 inline void assign(SFCBList list) {
303 flow_assert(_p == NULL);
304 flow_assert(_count == 0);
305 _count = list._count;
309 inline int count()
const {
313 inline void add(FlowControlBlock* fcb) {
315#if CLICK_DEBUG_FCBPOOL
316 assert(*(((uint64_t*)fcb) + 1) != ALLOCATOR_POISON);
317 assert(fcb->count() == 0);
318 *(((uint64_t*)fcb) + 1) = ALLOCATOR_POISON;
320 *((FlowControlBlock**)fcb) = _p;
325 inline FlowControlBlock* get() {
326 FlowControlBlock* fcb = _p;
328#if CLICK_DEBUG_FCBPOOL
329 assert(*(((uint64_t*)fcb) + 1) == ALLOCATOR_POISON);
330 *(((uint64_t*)fcb) + 1) = 0;
332 _p = *((FlowControlBlock**)fcb);
340 inline FlowControlBlock* alloc_new() {
341 FlowControlBlock* fcb = (FlowControlBlock*)CLICK_LALLOC(
sizeof(FlowControlBlock) + _data_size);
351 typedef MPMCRing<SFCBList,SFCB_POOL_COUNT> SFCBListRing;
353 SFCBListRing global_fcb_list_ring;
357 per_thread_oread<SFCBList> lists;
359 static FCBPool* biggest_pool;
360 static int initialized;
361 static int init_data_size() {
362 return biggest_pool->data_size();
365 static FlowControlBlock* init_allocate();
366 static void init_release(FlowControlBlock*);
368 FCBPool() : _data_size(0), lists() {
394 void initialize(
size_t data_size, FlowTableHolder* table) {
395 _data_size = data_size;
396 if (!biggest_pool || biggest_pool->data_size() < data_size) {
400 FCBPool::initialized++;
405 inline FlowControlBlock* allocate() {
406 if (lists->count() > 0)
411 newlist = global_fcb_list_ring.extract();
412 if (newlist.count()) {
413 lists->assign(newlist);
414 FlowControlBlock* fcb = lists->get();
417 FlowControlBlock* fcb = alloc_new();
423 inline FlowControlBlock* allocate_empty() {
424 FlowControlBlock* fcb = allocate();
425 bzero(fcb->data +
sizeof(FlowNodeData), data_size() -
sizeof(FlowNodeData));
429 inline void release(FlowControlBlock* fcb) {
430 if (lists->count() >= SFCB_POOL_SIZE) {
431 global_fcb_list_ring.insert(lists.get());
437 static void pool_release_fnt(FlowControlBlock* fcb,
void* thunk) {
438 static_cast<FCBPool*
>(thunk)->release(fcb);
446class FlowTableHolder {
452 FCBPool* get_pool() {
457#if HAVE_CTX_GLOBAL_TIMEOUT
458 void delete_all_flows();
460 void set_release_fnt(SubFlowRealeaseFnt pool_release_fnt,
void* thunk);
463 inline void release(FlowControlBlock* fcb) {
464 if (likely(_classifier_release_fnt))
465 _classifier_release_fnt(fcb, _classifier_thunk);
469#if HAVE_CTX_GLOBAL_TIMEOUT
470 void release_later(FlowControlBlock* fcb);
471 bool check_release();
473 static const unsigned DEFAULT_THRESH = 64;
474 fcb_list() : _next(0), _count(0), _count_thresh(DEFAULT_THRESH) {
477 FlowControlBlock* _next;
479 unsigned _count_thresh;
481 unsigned count()
const {
485 inline FlowControlBlock* find(FlowControlBlock* fcb) {
486 FlowControlBlock* head = _next;
487 #if DEBUG_CLASSIFIER_TIMEOUT > 3
488 click_chatter(
"FIND head %p",head);
494 flow_assert(head != head->next);
496 #if DEBUG_CLASSIFIER_TIMEOUT > 5
497 click_chatter(
"FIND next %p",head);
503 inline int find_count() {
504 FlowControlBlock* head = _next;
519 SubFlowRealeaseFnt _classifier_release_fnt;
520 void* _classifier_thunk;
526extern __thread FlowTableHolder* fcb_table;
534 inline FCBPool* FlowControlBlock::get_pool()
const {
535 return fcb_table->get_pool();
540 void FlowControlBlock::acquire(
int packets_nr) {
542 if (thread != -1 && thread != click_current_cpu_id()) {
543 click_chatter(
"Read FCB %p for thread %d from thread %d",
this, thread, click_current_cpu_id());
547 use_count += packets_nr;
548#if DEBUG_CLASSIFIER_RELEASE > 1
549 click_chatter(
"Acquire %d to %p, total is %d", packets_nr,
this, use_count);
553inline void FlowControlBlock::_do_release() {
554#if DEBUG_CLASSIFIER && HAVE_CTX_GLOBAL_TIMEOUT
555 flow_assert(!(flags & FLOW_TIMEOUT_INLIST));
557 flow_assert(thread == click_current_cpu_id());
562 release_fnt(
this, thunk);
566 fcb_table->release(
this);
570inline void FlowControlBlock::release(
int packets_nr) {
571 flow_assert(thread == -1 || thread == click_current_cpu_id());
573 if ((
int)use_count - packets_nr < 0) {
574 click_chatter(
"ERROR : negative release : release %p, use_count = %d, releasing %d",
this,use_count,packets_nr);
578 use_count -= packets_nr;
580#if DEBUG_CLASSIFIER_RELEASE > 1
581 click_chatter(
"Release %d to %p, total is %d",packets_nr,
this,use_count);
584 if (use_count == 0) {
585 debug_flow_2(
"[%d] Release fcb %p, uc 0, hc %d",click_current_cpu_id(),
this,hasTimeout());
587#if HAVE_CTX_GLOBAL_TIMEOUT
588 if (this->hasTimeout()) {
589 if (this->flags & FLOW_TIMEOUT_INLIST) {
590#if DEBUG_CLASSIFIER_TIMEOUT > 2
591 click_chatter(
"Not releasing %p because timeout is in list, uc %d",
this,use_count);
593#if DEBUG_CLASSIFIER_TIMEOUT_CHECK > 1
594 assert(fcb_table->old_flows.get().find(
this));
598#if DEBUG_CLASSIFIER_TIMEOUT_CHECK > 1
599 assert(!fcb_table->old_flows.get().find(
this));
603#if DEBUG_CLASSIFIER_TIMEOUT > 2
604 click_chatter(
"Not releasing %p because timeout is not passed. Adding to the list",
this);
607 fcb_table->release_later(
this);
610#if DEBUG_CLASSIFIER_TIMEOUT > 2
611 unsigned t = (flags >> FLOW_TIMEOUT_SHIFT);
616#if DEBUG_CLASSIFIER_TIMEOUT > 2
617 click_chatter(
"No timeout for fcb %p",
this);
624#if DEBUG_CLASSIFIER_RELEASE
626 click_chatter(
"NO RELEASE, fcb %p, uc %d",
this,this->use_count);
633#define SFCB_STACK(fnt) \
Vector of bits.
Definition bitvector.hh:21
Base class for Click elements.
Definition element.hh:42
A string of characters.
Definition string.hh:22
Represents a moment or interval in time.
Definition timestamp.hh:125
static Timestamp recent_steady()
Return a recent steady-clock time.
Definition timestamp.hh:1000
A 32-bit integer with support for atomic operations.
Definition atomic.hh:71