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