📄 aggcounter.cc
字号:
/* * aggcounter.{cc,hh} -- count packets/bytes with given aggregate * Eddie Kohler after Greg Minshall * * Copyright (c) 2001 International Computer Science Institute * * 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>#include "aggcounter.hh"#include <click/handlercall.hh>#include <click/confparse.hh>#include <click/error.hh>#include <click/packet_anno.hh>#include <click/integers.hh> // for first_bit_set#include <click/router.hh>CLICK_DECLSAggregateCounter::AggregateCounter() : Element(1, 1), _root(0), _free(0), _call_nnz_h(0), _call_count_h(0){}AggregateCounter::~AggregateCounter(){}AggregateCounter::Node *AggregateCounter::new_node_block(){ assert(!_free); int block_size = 1024; Node *block = new Node[block_size]; if (!block) return 0; _blocks.push_back(block); for (int i = 1; i < block_size - 1; i++) block[i].child[0] = &block[i+1]; block[block_size - 1].child[0] = 0; _free = &block[1]; return &block[0];}voidAggregateCounter::notify_ninputs(int n){ set_ninputs(n <= 1 ? 1 : 2);}voidAggregateCounter::notify_noutputs(int n){ set_noutputs(n <= 1 ? 1 : 2);}intAggregateCounter::configure(Vector<String> &conf, ErrorHandler *errh){ bool bytes = false; bool ip_bytes = false; bool packet_count = true; bool extra_length = true; uint32_t freeze_nnz, stop_nnz; uint64_t freeze_count, stop_count; String call_nnz, call_count; freeze_nnz = stop_nnz = _call_nnz = (uint32_t)(-1); freeze_count = stop_count = _call_count = (uint64_t)(-1); if (cp_va_parse(conf, this, errh, cpKeywords, "BYTES", cpBool, "count bytes?", &bytes, "IP_BYTES", cpBool, "do not count link header bytes?", &ip_bytes, "MULTIPACKET", cpBool, "use packet count annotation?", &packet_count, "EXTRA_LENGTH", cpBool, "use extra length annotation?", &extra_length, "AGGREGATE_FREEZE", cpUnsigned, "freeze after N nonzero aggregates", &freeze_nnz, "COUNT_FREEZE", cpUnsigned64, "freeze after count reaches N", &freeze_count, "AGGREGATE_STOP", cpUnsigned, "stop router after N nonzero aggregates", &stop_nnz, "COUNT_STOP", cpUnsigned64, "stop router after count reaches N", &stop_count, "AGGREGATE_CALL", cpArgument, "call handler after N nonzero aggregates", &call_nnz, "COUNT_CALL", cpArgument, "call handler after count reaches N", &call_count, "BANNER", cpString, "output banner", &_output_banner, cpEnd) < 0) return -1; _bytes = bytes; _ip_bytes = ip_bytes; _use_packet_count = packet_count; _use_extra_length = extra_length; if ((freeze_nnz != (uint32_t)(-1)) + (stop_nnz != (uint32_t)(-1)) + ((bool)call_nnz) > 1) return errh->error("'AGGREGATE_FREEZE', 'AGGREGATE_STOP', and 'AGGREGATE_CALL' are mutually exclusive"); else if (freeze_nnz != (uint32_t)(-1)) { _call_nnz = freeze_nnz; _call_nnz_h = new HandlerCall(id() + ".freeze true"); } else if (stop_nnz != (uint32_t)(-1)) { _call_nnz = stop_nnz; _call_nnz_h = new HandlerCall(id() + ".stop"); } else if (call_nnz) { if (!cp_unsigned(cp_pop_spacevec(call_nnz), &_call_nnz)) return errh->error("'AGGREGATE_CALL' first word should be unsigned (number of aggregates)"); _call_nnz_h = new HandlerCall(call_nnz); } if ((freeze_count != (uint64_t)(-1)) + (stop_count != (uint64_t)(-1)) + ((bool)call_count) > 1) return errh->error("'COUNT_FREEZE', 'COUNT_STOP', and 'COUNT_CALL' are mutually exclusive"); else if (freeze_count != (uint64_t)(-1)) { _call_count = freeze_count; _call_count_h = new HandlerCall(id() + ".freeze true"); } else if (stop_count != (uint64_t)(-1)) { _call_count = stop_count; _call_count_h = new HandlerCall(id() + ".stop"); } else if (call_count) { if (!cp_unsigned64(cp_pop_spacevec(call_count), &_call_count)) return errh->error("'COUNT_CALL' first word should be unsigned (count)"); _call_count_h = new HandlerCall(call_count); } return 0;}intAggregateCounter::initialize(ErrorHandler *errh){ if (_call_nnz_h && _call_nnz_h->initialize_write(this, errh) < 0) return -1; if (_call_count_h && _call_count_h->initialize_write(this, errh) < 0) return -1; if (clear(errh) < 0) return -1; _frozen = false; _active = true; return 0;}voidAggregateCounter::cleanup(CleanupStage){ for (int i = 0; i < _blocks.size(); i++) delete[] _blocks[i]; _blocks.clear(); delete _call_nnz_h; delete _call_count_h; _call_nnz_h = _call_count_h = 0;}AggregateCounter::Node *AggregateCounter::make_peer(uint32_t a, Node *n, bool frozen){ /* * become a peer * algo: create two nodes, the two peers. leave orig node as * the parent of the two new ones. */ if (frozen) return 0; Node *down[2]; if (!(down[0] = new_node())) return 0; if (!(down[1] = new_node())) { free_node(down[0]); return 0; } // swivel is first bit 'a' and 'old->input' differ int swivel = ffs_msb(a ^ n->aggregate); // bitvalue is the value of that bit of 'a' int bitvalue = (a >> (32 - swivel)) & 1; // mask masks off all bits before swivel uint32_t mask = (swivel == 1 ? 0 : (0xFFFFFFFFU << (33 - swivel))); down[bitvalue]->aggregate = a; down[bitvalue]->count = 0; down[bitvalue]->child[0] = down[bitvalue]->child[1] = 0; *down[1 - bitvalue] = *n; /* copy orig node down one level */ n->aggregate = (down[0]->aggregate & mask); if (down[0]->aggregate == n->aggregate) { n->count = down[0]->count; down[0]->count = 0; } else n->count = 0; n->child[0] = down[0]; /* point to children */ n->child[1] = down[1]; return (n->aggregate == a ? n : down[bitvalue]);}AggregateCounter::Node *AggregateCounter::find_node(uint32_t a, bool frozen){ // straight outta tcpdpriv Node *n = _root; while (n) { if (n->aggregate == a) return (n->count || !frozen ? n : 0); if (!n->child[0]) n = make_peer(a, n, frozen); else { // swivel is the first bit in which the two children differ int swivel = ffs_msb(n->child[0]->aggregate ^ n->child[1]->aggregate); if (ffs_msb(a ^ n->aggregate) < swivel) // input differs earlier n = make_peer(a, n, frozen); else if (a & (1 << (32 - swivel))) n = n->child[1]; else n = n->child[0]; } } if (!frozen) click_chatter("AggregateCounter: out of memory!"); return 0;}inline boolAggregateCounter::update(Packet *p, bool frozen){ if (!_active) return false; // AGGREGATE_ANNO is already in host byte order! uint32_t agg = AGGREGATE_ANNO(p); Node *n = find_node(agg, frozen); if (!n) return false; uint32_t amount; if (!_bytes) amount = 1 + (_use_packet_count ? EXTRA_PACKETS_ANNO(p) : 0); else { amount = p->length() + (_use_extra_length ? EXTRA_LENGTH_ANNO(p) : 0); if (_ip_bytes && p->network_header()) amount -= p->network_header_offset(); } // update _num_nonzero; possibly call handler if (amount && !n->count) { if (_num_nonzero >= _call_nnz) { _call_nnz = (uint32_t)(-1); _call_nnz_h->call_write(); // handler may have changed our state; reupdate return update(p, frozen || _frozen); } _num_nonzero++; } n->count += amount; _count += amount; if (_count >= _call_count) { _call_count = (uint64_t)(-1); _call_count_h->call_write(); } return true;}voidAggregateCounter::push(int port, Packet *p){ port = !update(p, _frozen || (port == 1)); output(noutputs() == 1 ? 0 : port).push(p);}Packet *AggregateCounter::pull(int port){ Packet *p = input(ninputs() == 1 ? 0 : port).pull(); if (p && _active) update(p, _frozen || (port == 1)); return p;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -