📄 aggregateipflows.cc
字号:
/* * aggregateipflows.{cc,hh} -- set aggregate annotation based on TCP/UDP flow * Eddie Kohler * * Copyright (c) 2001-2003 International Computer Science Institute * Copyright (c) 2005-2008 Regents of the University of California * * 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 "aggregateipflows.hh"#include <click/error.hh>#include <click/hashmap.hh>#include <click/straccum.hh>#include <click/confparse.hh>#include <clicknet/ip.h>#include <clicknet/tcp.h>#include <clicknet/udp.h>#include <clicknet/icmp.h>#include <click/packet_anno.hh>#include <click/handlercall.hh>CLICK_DECLS#define SEC_OLDER(s1, s2) ((int)(s1 - s2) < 0)// operations on host pairs and ports valuesstatic inline const click_ip *good_ip_header(const Packet *p){ // called when we already know the packet is good const click_ip *iph = p->ip_header(); if (iph->ip_p == IP_PROTO_ICMP) return reinterpret_cast<const click_ip *>(p->icmp_header() + 1); // know it exists else return iph;}static inline booloperator==(const AggregateIPFlows::HostPair &a, const AggregateIPFlows::HostPair &b){ return a.a == b.a && a.b == b.b;}inline hashcode_tAggregateIPFlows::HostPair::hashcode() const{ return (a << 12) + b + ((a >> 20) & 0x1F);}static inline boolports_reverse_order(uint32_t ports){ return (int32_t) ((ports << 16) - ports) < 0;}static inline uint32_tflip_ports(uint32_t ports){ return ((ports >> 16) & 0xFFFF) | (ports << 16);}// actual AggregateIPFlows operationsAggregateIPFlows::AggregateIPFlows()#if CLICK_USERLEVEL : _traceinfo_file(0), _packet_source(0), _filepos_h(0)#endif{}AggregateIPFlows::~AggregateIPFlows(){}void *AggregateIPFlows::cast(const char *n){ if (strcmp(n, "AggregateNotifier") == 0) return (AggregateNotifier *)this; else if (strcmp(n, "AggregateIPFlows") == 0) return (Element *)this; else return Element::cast(n);}intAggregateIPFlows::configure(Vector<String> &conf, ErrorHandler *errh){ _tcp_timeout = 24 * 60 * 60; _tcp_done_timeout = 30; _udp_timeout = 60; _fragment_timeout = 30; _gc_interval = 20 * 60; _fragments = 2; bool handle_icmp_errors = false; bool gave_fragments = false, fragments = true; if (cp_va_kparse(conf, this, errh, "TCP_TIMEOUT", 0, cpSeconds, &_tcp_timeout, "TCP_DONE_TIMEOUT", 0, cpSeconds, &_tcp_done_timeout, "UDP_TIMEOUT", 0, cpSeconds, &_udp_timeout, "FRAGMENT_TIMEOUT", 0, cpSeconds, &_fragment_timeout, "REAP", 0, cpSeconds, &_gc_interval, "ICMP", 0, cpBool, &handle_icmp_errors,#if CLICK_USERLEVEL "TRACEINFO", 0, cpFilename, &_traceinfo_filename, "SOURCE", 0, cpElement, &_packet_source,#endif "FRAGMENTS", cpkC, &gave_fragments, cpBool, &fragments, cpEnd) < 0) return -1; _smallest_timeout = (_tcp_timeout < _tcp_done_timeout ? _tcp_timeout : _tcp_done_timeout); _smallest_timeout = (_smallest_timeout < _udp_timeout ? _smallest_timeout : _udp_timeout); _handle_icmp_errors = handle_icmp_errors; if (gave_fragments) _fragments = fragments; return 0;}intAggregateIPFlows::initialize(ErrorHandler *errh){ _next = 1; _active_sec = _gc_sec = 0; _timestamp_warning = false;#if CLICK_USERLEVEL if (_traceinfo_filename == "-") _traceinfo_file = stdout; else if (_traceinfo_filename && !(_traceinfo_file = fopen(_traceinfo_filename.c_str(), "w"))) return errh->error("%s: %s", _traceinfo_filename.c_str(), strerror(errno)); if (_traceinfo_file) { fprintf(_traceinfo_file, "<?xml version='1.0' standalone='yes'?>\n\<trace"); if (_packet_source) { if (String s = HandlerCall::call_read(_packet_source, "filename").trim_space()) fprintf(_traceinfo_file, " file='%s'", s.c_str()); (void) HandlerCall::reset_read(_filepos_h, _packet_source, "packet_filepos"); } fprintf(_traceinfo_file, ">\n"); }#endif if (_fragments == 2) _fragments = !input_is_pull(0); else if (_fragments == 1 && input_is_pull(0)) return errh->error("'FRAGMENTS true' is incompatible with pull; run this element in a push context"); return 0;}voidAggregateIPFlows::cleanup(CleanupStage){ clean_map(_tcp_map); clean_map(_udp_map);#if CLICK_USERLEVEL if (_traceinfo_file && _traceinfo_file != stdout) { fprintf(_traceinfo_file, "</trace>\n"); fclose(_traceinfo_file); } delete _filepos_h;#endif}inline voidAggregateIPFlows::delete_flowinfo(const HostPair &hp, FlowInfo *finfo, bool really_delete){#if CLICK_USERLEVEL if (_traceinfo_file) { StatFlowInfo *sinfo = static_cast<StatFlowInfo *>(finfo); IPAddress src(sinfo->reverse() ? hp.b : hp.a); int sport = (ntohl(sinfo->_ports) >> (sinfo->reverse() ? 0 : 16)) & 0xFFFF; IPAddress dst(sinfo->reverse() ? hp.a : hp.b); int dport = (ntohl(sinfo->_ports) >> (sinfo->reverse() ? 16 : 0)) & 0xFFFF; Timestamp duration = sinfo->_last_timestamp - sinfo->_first_timestamp; fprintf(_traceinfo_file, "<flow aggregate='%u' src='%s' sport='%d' dst='%s' dport='%d' begin='" PRITIMESTAMP "' duration='" PRITIMESTAMP "'", sinfo->_aggregate, src.unparse().c_str(), sport, dst.unparse().c_str(), dport, sinfo->_first_timestamp.sec(), sinfo->_first_timestamp.subsec(), duration.sec(), duration.subsec()); if (sinfo->_filepos) fprintf(_traceinfo_file, " filepos='%u'", sinfo->_filepos); fprintf(_traceinfo_file, ">\n\ <stream dir='0' packets='%d' /><stream dir='1' packets='%d' />\n\</flow>\n", sinfo->_packets[0], sinfo->_packets[1]); if (really_delete) delete sinfo; } else#endif if (really_delete) delete finfo;}voidAggregateIPFlows::clean_map(Map &table){ // free completed flows and emit fragments for (Map::iterator iter = table.begin(); iter.live(); iter++) { HostPairInfo *hpinfo = &iter.value(); while (Packet *p = hpinfo->_fragment_head) { hpinfo->_fragment_head = p->next(); p->kill(); } while (FlowInfo *f = hpinfo->_flows) { hpinfo->_flows = f->_next; delete_flowinfo(iter.key(), f); } }}#if CLICK_USERLEVELvoidAggregateIPFlows::stat_new_flow_hook(const Packet *p, FlowInfo *finfo){ StatFlowInfo *sinfo = static_cast<StatFlowInfo *>(finfo); sinfo->_first_timestamp = p->timestamp_anno(); sinfo->_filepos = 0; if (_filepos_h) (void) cp_integer(_filepos_h->call_read().trim_space(), &sinfo->_filepos);}#endifinline voidAggregateIPFlows::packet_emit_hook(const Packet *p, const click_ip *iph, FlowInfo *finfo){ // account for timestamp finfo->_last_timestamp = p->timestamp_anno(); // check whether this indicates the flow is over if (iph->ip_p == IP_PROTO_TCP && IP_FIRSTFRAG(iph) /* 3.Feb.2004 - NLANR dumps do not contain full TCP headers! So relax the following length check to just make sure the flags are there. */ && p->transport_length() >= 14 && PAINT_ANNO(p) < 2) { // ignore ICMP errors if (p->tcp_header()->th_flags & TH_RST) finfo->_flow_over = 3; else if (p->tcp_header()->th_flags & TH_FIN) finfo->_flow_over |= (1 << PAINT_ANNO(p)); else if (p->tcp_header()->th_flags & TH_SYN) finfo->_flow_over = 0; }#if CLICK_USERLEVEL // count packets if (stats() && PAINT_ANNO(p) < 2) { StatFlowInfo *sinfo = static_cast<StatFlowInfo *>(finfo); sinfo->_packets[PAINT_ANNO(p)]++; }#endif}voidAggregateIPFlows::reap_map(Map &table, uint32_t timeout, uint32_t done_timeout){ timeout = _active_sec - timeout; done_timeout = _active_sec - done_timeout; int frag_timeout = _active_sec - _fragment_timeout; // free completed flows and emit fragments for (Map::iterator iter = table.begin(); iter.live(); iter++) { HostPairInfo *hpinfo = &iter.value(); Packet *head; // fragments while ((head = hpinfo->_fragment_head) && (head->timestamp_anno().sec() < frag_timeout || !IP_ISFRAG(good_ip_header(head)))) emit_fragment_head(hpinfo); // can't delete any flows if there are fragments if (hpinfo->_fragment_head) continue; // completed flows FlowInfo **pprev = &hpinfo->_flows; FlowInfo *f = *pprev; while (f) { // circular comparison if (SEC_OLDER(f->_last_timestamp.sec(), (f->_flow_over == 3 ? done_timeout : timeout))) { notify(f->_aggregate, AggregateListener::DELETE_AGG, 0); *pprev = f->_next; delete_flowinfo(iter.key(), f); } else pprev = &f->_next; f = *pprev; } // XXX never free host pairs }}voidAggregateIPFlows::reap()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -