📄 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 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;}static inline uint32_thashcode(const AggregateIPFlows::HostPair &a){ return (a.a << 12) + a.b + ((a.a >> 20) & 0x1F);}static inline uint32_tflip_ports(uint32_t ports){ return ((ports >> 16) & 0xFFFF) | (ports << 16);}// actual AggregateIPFlows operationsAggregateIPFlows::AggregateIPFlows() : Element(1, 1), _traceinfo_file(0), _packet_source(0), _filepos_h(0){}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);}voidAggregateIPFlows::notify_noutputs(int n){ set_noutputs(n <= 1 ? 1 : 2);}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_parse(conf, this, errh, cpKeywords, "TCP_TIMEOUT", cpSeconds, "timeout for active TCP connections", &_tcp_timeout, "TCP_DONE_TIMEOUT", cpSeconds, "timeout for completed TCP connections", &_tcp_done_timeout, "UDP_TIMEOUT", cpSeconds, "timeout for UDP connections", &_udp_timeout, "FRAGMENT_TIMEOUT", cpSeconds, "timeout for fragment collection", &_fragment_timeout, "REAP", cpSeconds, "garbage collection interval", &_gc_interval, "ICMP", cpBool, "handle ICMP errors?", &handle_icmp_errors, "TRACEINFO", cpFilename, "filename for connection info file", &_traceinfo_filename, "SOURCE", cpElement, "packet source element", &_packet_source, cpConfirmKeywords, "FRAGMENTS", cpBool, "handle fragmented packets?", &gave_fragments, &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 (_traceinfo_filename == "-") _traceinfo_file = stdout; else if (_traceinfo_filename && !(_traceinfo_file = fopen(_traceinfo_filename.cc(), "w"))) return errh->error("%s: %s", _traceinfo_filename.cc(), 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.cc()); (void) HandlerCall::reset_read(_filepos_h, _packet_source, "packet_filepos"); } fprintf(_traceinfo_file, ">\n"); } 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 (_traceinfo_file && _traceinfo_file != stdout) { fprintf(_traceinfo_file, "</trace>\n"); fclose(_traceinfo_file); } delete _filepos_h;}inline voidAggregateIPFlows::delete_flowinfo(const HostPair &hp, FlowInfo *finfo, bool really_delete){ 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.s().cc(), sport, dst.s().cc(), 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 if (really_delete) delete finfo;}voidAggregateIPFlows::clean_map(Map &table){ // free completed flows and emit fragments for (Map::iterator iter = table.begin(); iter; 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); } }}voidAggregateIPFlows::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_unsigned(_filepos_h->call_read().trim_space(), &sinfo->_filepos);}inline voidAggregateIPFlows::packet_emit_hook(const Packet *p, const click_ip *iph, FlowInfo *finfo){ // 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; } // count packets if (stats() && PAINT_ANNO(p) < 2) { StatFlowInfo *sinfo = static_cast<StatFlowInfo *>(finfo); sinfo->_packets[PAINT_ANNO(p)]++; }}voidAggregateIPFlows::assign_aggregate(Map &table, HostPairInfo *hpinfo, int emit_before_sec){ Packet *first = hpinfo->_fragment_head; uint16_t want_ip_id = good_ip_header(first)->ip_id; // find FlowInfo FlowInfo *finfo = 0; if (AGGREGATE_ANNO(first)) { for (finfo = hpinfo->_flows; finfo && finfo->_aggregate != AGGREGATE_ANNO(first); finfo = finfo->_next) /* nada */; } else { for (Packet *p = first; !finfo && p; p = p->next()) { const click_ip *iph = good_ip_header(p); if (iph->ip_id == want_ip_id) { if (IP_FIRSTFRAG(iph)) { uint32_t ports = *(reinterpret_cast<const uint32_t *>(reinterpret_cast<const uint8_t *>(iph) + (iph->ip_hl << 2))); if (PAINT_ANNO(p) & 1) ports = flip_ports(ports); finfo = find_flow_info(table, hpinfo, ports, PAINT_ANNO(p) & 1, p); } } } } // if no FlowInfo found, delete packet if (!finfo) { hpinfo->_fragment_head = first->next(); first->kill(); return; } // emit packets at the beginning of the list that have the same IP ID const click_ip *iph; while (first && (iph = good_ip_header(first)) && iph->ip_id == want_ip_id && (SEC_OLDER(first->timestamp_anno().sec(), emit_before_sec) || !IP_ISFRAG(iph))) { Packet *p = first; hpinfo->_fragment_head = first = p->next(); p->set_next(0); bool was_fragment = IP_ISFRAG(iph); SET_AGGREGATE_ANNO(p, finfo->aggregate()); // actually emit packet if (finfo->reverse()) SET_PAINT_ANNO(p, PAINT_ANNO(p) ^ 1); finfo->_last_timestamp = p->timestamp_anno(); packet_emit_hook(p, iph, finfo);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -