1 /*
2  * aggregateipflows.{cc,hh} -- set aggregate annotation based on IP addr pair
3  * Eddie Kohler
4  *
5  * Copyright (c) 2001-2003 International Computer Science Institute
6  * Copyright (c) 2005 Regents of the University of California
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a
9  * copy of this software and associated documentation files (the "Software"),
10  * to deal in the Software without restriction, subject to the conditions
11  * listed in the Click LICENSE file. These conditions include: you must
12  * preserve this copyright notice, and you cannot mention the copyright
13  * holders in advertising related to the Software without their permission.
14  * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
15  * notice is a summary of the Click LICENSE file; the license in that file is
16  * legally binding.
17  */
18 
19 #include <click/config.h>
20 #include "aggregateipaddrpair.hh"
21 #include <click/error.hh>
22 #include <click/straccum.hh>
23 #include <click/args.hh>
24 #include <clicknet/ip.h>
25 #include <clicknet/tcp.h>
26 #include <clicknet/udp.h>
27 #include <clicknet/icmp.h>
28 #include <click/packet_anno.hh>
29 #include <click/handlercall.hh>
30 CLICK_DECLS
31 
32 #define SEC_OLDER(s1, s2)	((int)(s1 - s2) < 0)
33 
34 
35 static inline bool
operator ==(const AggregateIPAddrPair::HostPair & a,const AggregateIPAddrPair::HostPair & b)36 operator==(const AggregateIPAddrPair::HostPair &a, const AggregateIPAddrPair::HostPair &b)
37 {
38     return a.a == b.a && a.b == b.b;
39 }
40 
41 inline hashcode_t
hashcode() const42 AggregateIPAddrPair::HostPair::hashcode() const
43 {
44     return (a << 12) + b + ((a >> 20) & 0x1F);
45 }
46 
47 
48 // actual AggregateIPAddrPair operations
49 
AggregateIPAddrPair()50 AggregateIPAddrPair::AggregateIPAddrPair()
51 {
52 }
53 
~AggregateIPAddrPair()54 AggregateIPAddrPair::~AggregateIPAddrPair()
55 {
56 }
57 
58 void *
cast(const char * n)59 AggregateIPAddrPair::cast(const char *n)
60 {
61     if (strcmp(n, "AggregateNotifier") == 0)
62         return (AggregateNotifier *)this;
63     else if (strcmp(n, "AggregateIPAddrPair") == 0)
64 	return (Element *)this;
65     else
66 	return Element::cast(n);
67 }
68 
69 int
configure(Vector<String> & conf,ErrorHandler * errh)70 AggregateIPAddrPair::configure(Vector<String> &conf, ErrorHandler *errh)
71 {
72     _timeout = 0;
73     _gc_interval = 20 * 60;
74 
75     if (Args(conf, this, errh)
76 	.read("TIMEOUT", SecondsArg(), _timeout)
77 	.read("REAP", SecondsArg(), _gc_interval)
78 	.complete() < 0)
79 	return -1;
80 
81     return 0;
82 }
83 
84 int
initialize(ErrorHandler *)85 AggregateIPAddrPair::initialize(ErrorHandler *)
86 {
87     _next = 1;
88     _active_sec = _gc_sec = 0;
89     _timestamp_warning = false;
90 
91     return 0;
92 }
93 
94 void
reap()95 AggregateIPAddrPair::reap()
96 {
97     if (_gc_sec) {
98 	uint32_t timeout = _active_sec - _timeout;
99 
100 	Vector<uint32_t> to_free;
101 	for (Map::iterator iter = _map.begin(); iter.live(); iter++) {
102 	    FlowInfo *finfo = &iter.value();
103 	    if (SEC_OLDER(finfo->last_timestamp.sec(), timeout)) {
104 		notify(finfo->aggregate, AggregateListener::DELETE_AGG, 0);
105 		to_free.push_back(iter.key().a);
106 		to_free.push_back(iter.key().b);
107 	    }
108 	}
109 
110 	for (uint32_t *u = to_free.begin(); u < to_free.end(); u += 2)
111 	    _map.erase(*(const HostPair *)u);
112     }
113     _gc_sec = _active_sec + _gc_interval;
114 }
115 
116 // XXX timing when fragments are merged back in?
117 
118 Packet *
simple_action(Packet * p)119 AggregateIPAddrPair::simple_action(Packet *p)
120 {
121     if (p->has_network_header()) {
122 	const click_ip *iph = p->ip_header();
123 	HostPair hosts(iph->ip_src.s_addr, iph->ip_dst.s_addr);
124 	FlowInfo *finfo = &_map[hosts];
125 
126 	if (_timeout > 0) {
127 	    // assign timestamp if no timestamp given
128 	    if (!p->timestamp_anno()) {
129 		if (!_timestamp_warning) {
130 		    click_chatter("%p{element}: warning: packet received without timestamp", this);
131 		    _timestamp_warning = true;
132 		}
133 		p->timestamp_anno().assign_now();
134 	    }
135 
136 	    if (finfo->aggregate && SEC_OLDER(finfo->last_timestamp.sec(), p->timestamp_anno().sec() - _timeout)) {
137 		notify(finfo->aggregate, AggregateListener::DELETE_AGG, 0);
138 		finfo->aggregate = 0;
139 	    }
140 	}
141 
142 	if (!finfo->aggregate) {
143 	    finfo->aggregate = _next;
144 	    finfo->reverse = (hosts.a != iph->ip_src.s_addr);
145 	    if (++_next == 0)
146 		++_next;
147 	    notify(finfo->aggregate, AggregateListener::NEW_AGG, p);
148 	}
149 
150 	if (_timeout > 0) {
151 	    finfo->last_timestamp = p->timestamp_anno();
152 	    _active_sec = p->timestamp_anno().sec();
153 	    if (_active_sec > _gc_sec)
154 		reap();
155 	}
156 
157 	SET_AGGREGATE_ANNO(p, finfo->aggregate);
158 	int paint = finfo->reverse ^ (hosts.a != iph->ip_src.s_addr);
159 	SET_PAINT_ANNO(p, paint);
160 	return p;
161 
162     } else {
163 	checked_output_push(1, p);
164 	return 0;
165     }
166 }
167 
168 enum { H_CLEAR };
169 
170 int
write_handler(const String &,Element * e,void * thunk,ErrorHandler *)171 AggregateIPAddrPair::write_handler(const String &, Element *e, void *thunk, ErrorHandler *)
172 {
173     AggregateIPAddrPair *af = static_cast<AggregateIPAddrPair *>(e);
174     switch ((intptr_t)thunk) {
175       case H_CLEAR: {
176 	  int active_sec = af->_active_sec, gc_sec = af->_gc_sec;
177 	  af->_active_sec = af->_gc_sec = 0x7FFFFFFF;
178 	  af->reap();
179 	  af->_active_sec = active_sec, af->_gc_sec = gc_sec;
180 	  return 0;
181       }
182       default:
183 	return -1;
184     }
185 }
186 
187 void
add_handlers()188 AggregateIPAddrPair::add_handlers()
189 {
190     add_write_handler("clear", write_handler, H_CLEAR);
191 }
192 
193 ELEMENT_REQUIRES(userlevel AggregateNotifier)
194 EXPORT_ELEMENT(AggregateIPAddrPair)
195 CLICK_ENDDECLS
196