/* * aggregateip.{cc,hh} -- set aggregate annotation based on IP field * Eddie Kohler * * Copyright (c) 2001-2003 International Computer Science Institute * Copyright (c) 2005-2006 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 #include "aggregateip.hh" #include #include #include #include #include #include #include #include CLICK_DECLS AggregateIP::AggregateIP() { } AggregateIP::~AggregateIP() { } int AggregateIP::configure(Vector &conf, ErrorHandler *errh) { String arg; _incremental = _unshift_ip_addr = false; if (cp_va_parse(conf, this, errh, cpArgument, "field specification", &arg, cpKeywords, "INCREMENTAL", cpBool, "incremental?", &_incremental, "UNSHIFT_IP_ADDR", cpBool, "unshift IP address fields?", &_unshift_ip_addr, cpEnd) < 0) return -1; const char *end = IPField::parse(arg.begin(), arg.end(), -1, &_f, errh, this); if (end == arg.begin()) return -1; else if (end != arg.end()) return errh->error("garbage after field specification"); int32_t right = _f.bit_offset() + _f.bit_length() - 1; if ((_f.bit_offset() / 32) != (right / 32)) return errh->error("field specification does not fit within a single word"); if (_f.bit_length() > 32) return errh->error("too many aggregates: field length too large, max 32"); else if (_f.bit_length() == 32 && _incremental) return errh->error("'INCREMENTAL' is incompatible with field length 32"); if (_f.bit_length() == 32) _mask = 0xFFFFFFFFU; else _mask = (1 << _f.bit_length()) - 1; _offset = (_f.bit_offset() / 32) * 4; if (!_unshift_ip_addr || _f.proto() != 0 || _f.bit_offset() < 12*8 || _f.bit_offset() >= 20*8) _shift = 31 - right % 32; else { _mask <<= 31 - right % 32; _shift = 0; } return 0; } Packet * AggregateIP::bad_packet(Packet *p) { if (noutputs() == 2) output(1).push(p); else p->kill(); return 0; } Packet * AggregateIP::handle_packet(Packet *p) { const click_ip *iph = p->ip_header(); if (!iph) return bad_packet(p); int offset = p->length(); switch (_f.proto()) { case 0: offset = p->network_header_offset(); break; case IP_PROTO_TCP_OR_UDP: if (IP_FIRSTFRAG(iph) && (iph->ip_p == IP_PROTO_TCP || iph->ip_p == IP_PROTO_UDP)) offset = p->transport_header_offset(); break; case IP_PROTO_TRANSP: if (IP_FIRSTFRAG(iph)) offset = p->transport_header_offset(); break; case IP_PROTO_PAYLOAD: if (!IP_FIRSTFRAG(iph)) /* bad; will be thrown away below */; else if (iph->ip_p == IPPROTO_TCP && p->transport_header_offset() + sizeof(click_tcp) <= p->length()) { const click_tcp *tcph = (const click_tcp *)p->transport_header(); offset = p->transport_header_offset() + (tcph->th_off << 2); } else if (iph->ip_p == IPPROTO_UDP) offset = p->transport_header_offset() + sizeof(click_udp); break; default: if (IP_FIRSTFRAG(iph) && iph->ip_p == _f.proto()) offset = p->transport_header_offset(); break; } offset += _offset; if (offset + 4 > (int)p->length()) return bad_packet(p); uint32_t udata = *((const uint32_t *)(p->data() + offset)); uint32_t agg = (ntohl(udata) >> _shift) & _mask; if (_incremental) SET_AGGREGATE_ANNO(p, (AGGREGATE_ANNO(p) << _f.bit_length()) + agg); else SET_AGGREGATE_ANNO(p, agg); return p; } void AggregateIP::push(int, Packet *p) { if (Packet *q = handle_packet(p)) output(0).push(q); } Packet * AggregateIP::pull(int) { Packet *p = input(0).pull(); if (p) p = handle_packet(p); return p; } String AggregateIP::read_handler(Element *e, void *thunk) { AggregateIP *aip = static_cast(e); switch ((intptr_t)thunk) { case 0: return NameInfo::revquery_int(NameInfo::T_IP_PROTO, e, aip->_f.proto()); case 1: return String(aip->_f.bit_offset()); case 2: return String(aip->_f.bit_length()); case 3: return aip->_f.unparse(e, false); default: return ""; } } void AggregateIP::add_handlers() { add_read_handler("header", read_handler, (void *)0); add_read_handler("bit_offset", read_handler, (void *)1); add_read_handler("bit_length", read_handler, (void *)2); add_read_handler("field", read_handler, (void *)3); } ELEMENT_REQUIRES(userlevel IPFieldInfo) EXPORT_ELEMENT(AggregateIP) #include CLICK_ENDDECLS