mac-learning: Fix serious performance bug in the learning table.
[sliver-openvswitch.git] / lib / sflow_agent.c
1 /* Copyright (c) 2002-2009 InMon Corp. Licensed under the terms of the InMon sFlow licence: */
2 /* http://www.inmon.com/technology/sflowlicense.txt */
3
4 #include "sflow_api.h"
5
6 static void * sflAlloc(SFLAgent *agent, size_t bytes);
7 static void sflFree(SFLAgent *agent, void *obj);
8 static void sfl_agent_jumpTableAdd(SFLAgent *agent, SFLSampler *sampler);
9 static void sfl_agent_jumpTableRemove(SFLAgent *agent, SFLSampler *sampler);
10
11 /*________________--------------------------__________________
12   ________________    sfl_agent_init        __________________
13   ----------------__________________________------------------
14 */
15
16 void sfl_agent_init(SFLAgent *agent,
17                     SFLAddress *myIP, /* IP address of this agent in net byte order */
18                     u_int32_t subId,  /* agent_sub_id */
19                     time_t bootTime,  /* agent boot time */
20                     time_t now,       /* time now */
21                     void *magic,      /* ptr to pass back in logging and alloc fns */
22                     allocFn_t allocFn,
23                     freeFn_t freeFn,
24                     errorFn_t errorFn,
25                     sendFn_t sendFn)
26 {
27     /* first clear everything */
28     memset(agent, 0, sizeof(*agent));
29     /* now copy in the parameters */
30     agent->myIP = *myIP; /* structure copy */
31     agent->subId = subId;
32     agent->bootTime = bootTime;
33     agent->now = now;
34     agent->magic = magic;
35     agent->allocFn = allocFn;
36     agent->freeFn = freeFn;
37     agent->errorFn = errorFn;
38     agent->sendFn = sendFn;
39
40 #ifdef SFLOW_DO_SOCKET
41     if(sendFn == NULL) {
42         /* open the socket - really need one for v4 and another for v6? */
43         if((agent->receiverSocket4 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
44             sfl_agent_sysError(agent, "agent", "IPv4 socket open failed");
45         if((agent->receiverSocket6 = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) == -1)
46             sfl_agent_sysError(agent, "agent", "IPv6 socket open failed");
47     }
48 #endif
49 }
50
51 /*_________________---------------------------__________________
52   _________________   sfl_agent_release       __________________
53   -----------------___________________________------------------
54 */
55
56 void sfl_agent_release(SFLAgent *agent)
57 {
58     /* release and free the samplers, pollers and receivers */
59     SFLSampler *sm = agent->samplers;
60     SFLPoller *pl = agent->pollers;
61     SFLReceiver *rcv = agent->receivers;
62
63     for(; sm != NULL; ) {
64         SFLSampler *nextSm = sm->nxt;
65         sflFree(agent, sm);
66         sm = nextSm;
67     }
68     agent->samplers = NULL;
69
70     for(; pl != NULL; ) {
71         SFLPoller *nextPl = pl->nxt;
72         sflFree(agent, pl);
73         pl = nextPl;
74     }
75     agent->pollers = NULL;
76
77     for(; rcv != NULL; ) {
78         SFLReceiver *nextRcv = rcv->nxt;
79         sflFree(agent, rcv);
80         rcv = nextRcv;
81     }
82     agent->receivers = NULL;
83
84 #ifdef SFLOW_DO_SOCKET
85     /* close the sockets */
86     if(agent->receiverSocket4 > 0) close(agent->receiverSocket4);
87     if(agent->receiverSocket6 > 0) close(agent->receiverSocket6);
88 #endif
89 }
90
91
92 /*_________________---------------------------__________________
93   _________________   sfl_agent_set_*         __________________
94   -----------------___________________________------------------
95 */
96
97 void sfl_agent_set_agentAddress(SFLAgent *agent, SFLAddress *addr)
98 {
99     if(addr && memcmp(addr, &agent->myIP, sizeof(agent->myIP)) != 0) {
100         /* change of address */
101         agent->myIP = *addr; /* structure copy */
102         /* reset sequence numbers here? */
103     }
104 }
105
106 void sfl_agent_set_agentSubId(SFLAgent *agent, u_int32_t subId)
107 {
108     if(subId != agent->subId) {
109         /* change of subId */
110         agent->subId = subId;
111         /* reset sequence numbers here? */
112     }
113 }
114
115 /*_________________---------------------------__________________
116   _________________   sfl_agent_tick          __________________
117   -----------------___________________________------------------
118 */
119
120 void sfl_agent_tick(SFLAgent *agent, time_t now)
121 {
122     SFLReceiver *rcv = agent->receivers;
123     SFLSampler *sm = agent->samplers;
124     SFLPoller *pl = agent->pollers;
125     agent->now = now;
126     /* receivers use ticks to flush send data */
127     for(; rcv != NULL; rcv = rcv->nxt) sfl_receiver_tick(rcv, now);
128     /* samplers use ticks to decide when they are sampling too fast */
129     for(; sm != NULL; sm = sm->nxt) sfl_sampler_tick(sm, now);
130     /* pollers use ticks to decide when to ask for counters */
131     for(; pl != NULL; pl = pl->nxt) sfl_poller_tick(pl, now);
132 }
133
134 /*_________________---------------------------__________________
135   _________________   sfl_agent_addReceiver   __________________
136   -----------------___________________________------------------
137 */
138
139 SFLReceiver *sfl_agent_addReceiver(SFLAgent *agent)
140 {
141     SFLReceiver *rcv = (SFLReceiver *)sflAlloc(agent, sizeof(SFLReceiver));
142     sfl_receiver_init(rcv, agent);
143     /* add to end of list - to preserve the receiver index numbers for existing receivers */
144     {
145         SFLReceiver *r, *prev = NULL;
146         for(r = agent->receivers; r != NULL; prev = r, r = r->nxt);
147         if(prev) prev->nxt = rcv;
148         else agent->receivers = rcv;
149         rcv->nxt = NULL;
150     }
151     return rcv;
152 }
153
154 /*_________________---------------------------__________________
155   _________________     sfl_dsi_compare       __________________
156   -----------------___________________________------------------
157
158   Note that if there is a mixture of ds_classes for this agent, then
159   the simple numeric comparison may not be correct - the sort order (for
160   the purposes of the SNMP MIB) should really be determined by the OID
161   that these numeric ds_class numbers are a shorthand for.  For example,
162   ds_class == 0 means ifIndex, which is the oid "1.3.6.1.2.1.2.2.1"
163 */
164
165 static inline int sfl_dsi_compare(SFLDataSource_instance *pdsi1, SFLDataSource_instance *pdsi2) {
166     /* could have used just memcmp(),  but not sure if that would
167        give the right answer on little-endian platforms. Safer to be explicit... */
168     int cmp = pdsi2->ds_class - pdsi1->ds_class;
169     if(cmp == 0) cmp = pdsi2->ds_index - pdsi1->ds_index;
170     if(cmp == 0) cmp = pdsi2->ds_instance - pdsi1->ds_instance;
171     return cmp;
172 }
173
174 /*_________________---------------------------__________________
175   _________________   sfl_agent_addSampler    __________________
176   -----------------___________________________------------------
177 */
178
179 SFLSampler *sfl_agent_addSampler(SFLAgent *agent, SFLDataSource_instance *pdsi)
180 {
181     /* Keep the list sorted. */
182     SFLSampler *prev = NULL, *sm = agent->samplers;
183     for(; sm != NULL; prev = sm, sm = sm->nxt) {
184         int64_t cmp = sfl_dsi_compare(pdsi, &sm->dsi);
185         if(cmp == 0) return sm;  /* found - return existing one */
186         if(cmp < 0) break;       /* insert here */
187     }
188     /* either we found the insert point, or reached the end of the list...*/
189
190     {
191         SFLSampler *newsm = (SFLSampler *)sflAlloc(agent, sizeof(SFLSampler));
192         sfl_sampler_init(newsm, agent, pdsi);
193         if(prev) prev->nxt = newsm;
194         else agent->samplers = newsm;
195         newsm->nxt = sm;
196
197         /* see if we should go in the ifIndex jumpTable */
198         if(SFL_DS_CLASS(newsm->dsi) == 0) {
199             SFLSampler *test = sfl_agent_getSamplerByIfIndex(agent, SFL_DS_INDEX(newsm->dsi));
200             if(test && (SFL_DS_INSTANCE(newsm->dsi) < SFL_DS_INSTANCE(test->dsi))) {
201                 /* replace with this new one because it has a lower ds_instance number */
202                 sfl_agent_jumpTableRemove(agent, test);
203                 test = NULL;
204             }
205             if(test == NULL) sfl_agent_jumpTableAdd(agent, newsm);
206         }
207         return newsm;
208     }
209 }
210
211 /*_________________---------------------------__________________
212   _________________   sfl_agent_addPoller     __________________
213   -----------------___________________________------------------
214 */
215
216 SFLPoller *sfl_agent_addPoller(SFLAgent *agent,
217                                SFLDataSource_instance *pdsi,
218                                void *magic,         /* ptr to pass back in getCountersFn() */
219                                getCountersFn_t getCountersFn)
220 {
221     /* keep the list sorted */
222     SFLPoller *prev = NULL, *pl = agent->pollers;
223     for(; pl != NULL; prev = pl, pl = pl->nxt) {
224         int64_t cmp = sfl_dsi_compare(pdsi, &pl->dsi);
225         if(cmp == 0) return pl;  /* found - return existing one */
226         if(cmp < 0) break;       /* insert here */
227     }
228     /* either we found the insert point, or reached the end of the list... */
229     {
230         SFLPoller *newpl = (SFLPoller *)sflAlloc(agent, sizeof(SFLPoller));
231         sfl_poller_init(newpl, agent, pdsi, magic, getCountersFn);
232         if(prev) prev->nxt = newpl;
233         else agent->pollers = newpl;
234         newpl->nxt = pl;
235         return newpl;
236     }
237 }
238
239 /*_________________---------------------------__________________
240   _________________  sfl_agent_removeSampler  __________________
241   -----------------___________________________------------------
242 */
243
244 int sfl_agent_removeSampler(SFLAgent *agent, SFLDataSource_instance *pdsi)
245 {
246     /* find it, unlink it and free it */
247     SFLSampler *prev = NULL, *sm = agent->samplers;
248     for(; sm != NULL; prev = sm, sm = sm->nxt) {
249         if(sfl_dsi_compare(pdsi, &sm->dsi) == 0) {
250             if(prev == NULL) agent->samplers = sm->nxt;
251             else prev->nxt = sm->nxt;
252             sfl_agent_jumpTableRemove(agent, sm);
253             sflFree(agent, sm);
254             return 1;
255         }
256     }
257     /* not found */
258     return 0;
259 }
260
261 /*_________________---------------------------__________________
262   _________________  sfl_agent_removePoller   __________________
263   -----------------___________________________------------------
264 */
265
266 int sfl_agent_removePoller(SFLAgent *agent, SFLDataSource_instance *pdsi)
267 {
268     /* find it, unlink it and free it */
269     SFLPoller *prev = NULL, *pl = agent->pollers;
270     for(; pl != NULL; prev = pl, pl = pl->nxt) {
271         if(sfl_dsi_compare(pdsi, &pl->dsi) == 0) {
272             if(prev == NULL) agent->pollers = pl->nxt;
273             else prev->nxt = pl->nxt;
274             sflFree(agent, pl);
275             return 1;
276         }
277     }
278     /* not found */
279     return 0;
280 }
281
282 /*_________________--------------------------------__________________
283   _________________  sfl_agent_jumpTableAdd        __________________
284   -----------------________________________________------------------
285 */
286
287 static void sfl_agent_jumpTableAdd(SFLAgent *agent, SFLSampler *sampler)
288 {
289     u_int32_t hashIndex = SFL_DS_INDEX(sampler->dsi) % SFL_HASHTABLE_SIZ;
290     sampler->hash_nxt = agent->jumpTable[hashIndex];
291     agent->jumpTable[hashIndex] = sampler;
292 }
293
294 /*_________________--------------------------------__________________
295   _________________  sfl_agent_jumpTableRemove     __________________
296   -----------------________________________________------------------
297 */
298
299 static void sfl_agent_jumpTableRemove(SFLAgent *agent, SFLSampler *sampler)
300 {
301     u_int32_t hashIndex = SFL_DS_INDEX(sampler->dsi) % SFL_HASHTABLE_SIZ;
302     SFLSampler *search = agent->jumpTable[hashIndex], *prev = NULL;
303     for( ; search != NULL; prev = search, search = search->hash_nxt) if(search == sampler) break;
304     if(search) {
305         // found - unlink
306         if(prev) prev->hash_nxt = search->hash_nxt;
307         else agent->jumpTable[hashIndex] = search->hash_nxt;
308         search->hash_nxt = NULL;
309     }
310 }
311
312 /*_________________--------------------------------__________________
313   _________________  sfl_agent_getSamplerByIfIndex __________________
314   -----------------________________________________------------------
315   fast lookup (pointers cached in hash table).  If there are multiple
316   sampler instances for a given ifIndex, then this fn will return
317   the one with the lowest instance number.  Since the samplers
318   list is sorted, this means the other instances will be accesible
319   by following the sampler->nxt pointer (until the ds_class
320   or ds_index changes).  This is helpful if you need to offer
321   the same flowSample to multiple samplers.
322 */
323
324 SFLSampler *sfl_agent_getSamplerByIfIndex(SFLAgent *agent, u_int32_t ifIndex)
325 {
326     SFLSampler *search = agent->jumpTable[ifIndex % SFL_HASHTABLE_SIZ];
327     for( ; search != NULL; search = search->hash_nxt) if(SFL_DS_INDEX(search->dsi) == ifIndex) break;
328     return search;
329 }
330
331 /*_________________---------------------------__________________
332   _________________  sfl_agent_getSampler     __________________
333   -----------------___________________________------------------
334 */
335
336 SFLSampler *sfl_agent_getSampler(SFLAgent *agent, SFLDataSource_instance *pdsi)
337 {
338     /* find it and return it */
339     SFLSampler *sm = agent->samplers;
340     for(; sm != NULL; sm = sm->nxt)
341         if(sfl_dsi_compare(pdsi, &sm->dsi) == 0) return sm;
342     /* not found */
343     return NULL;
344 }
345
346 /*_________________---------------------------__________________
347   _________________  sfl_agent_getPoller      __________________
348   -----------------___________________________------------------
349 */
350
351 SFLPoller *sfl_agent_getPoller(SFLAgent *agent, SFLDataSource_instance *pdsi)
352 {
353     /* find it and return it */
354     SFLPoller *pl = agent->pollers;
355     for(; pl != NULL; pl = pl->nxt)
356         if(sfl_dsi_compare(pdsi, &pl->dsi) == 0) return pl;
357     /* not found */
358     return NULL;
359 }
360
361 /*_________________---------------------------__________________
362   _________________  sfl_agent_getReceiver    __________________
363   -----------------___________________________------------------
364 */
365
366 SFLReceiver *sfl_agent_getReceiver(SFLAgent *agent, u_int32_t receiverIndex)
367 {
368     u_int32_t rcvIdx = 0;
369     SFLReceiver *rcv = agent->receivers;
370     for(;  rcv != NULL; rcv = rcv->nxt)
371         if(receiverIndex == ++rcvIdx) return rcv;
372
373     /* not found - ran off the end of the table */
374     return NULL;
375 }
376
377 /*_________________---------------------------__________________
378   _________________ sfl_agent_getNextSampler  __________________
379   -----------------___________________________------------------
380 */
381
382 SFLSampler *sfl_agent_getNextSampler(SFLAgent *agent, SFLDataSource_instance *pdsi)
383 {
384     /* return the one lexograpically just after it - assume they are sorted
385        correctly according to the lexographical ordering of the object ids */
386     SFLSampler *sm = sfl_agent_getSampler(agent, pdsi);
387     return sm ? sm->nxt : NULL;
388 }
389
390 /*_________________---------------------------__________________
391   _________________ sfl_agent_getNextPoller   __________________
392   -----------------___________________________------------------
393 */
394
395 SFLPoller *sfl_agent_getNextPoller(SFLAgent *agent, SFLDataSource_instance *pdsi)
396 {
397     /* return the one lexograpically just after it - assume they are sorted
398        correctly according to the lexographical ordering of the object ids */
399     SFLPoller *pl = sfl_agent_getPoller(agent, pdsi);
400     return pl ? pl->nxt : NULL;
401 }
402
403 /*_________________---------------------------__________________
404   _________________ sfl_agent_getNextReceiver __________________
405   -----------------___________________________------------------
406 */
407
408 SFLReceiver *sfl_agent_getNextReceiver(SFLAgent *agent, u_int32_t receiverIndex)
409 {
410     return sfl_agent_getReceiver(agent, receiverIndex + 1);
411 }
412
413
414 /*_________________---------------------------__________________
415   _________________ sfl_agent_resetReceiver   __________________
416   -----------------___________________________------------------
417 */
418
419 void sfl_agent_resetReceiver(SFLAgent *agent, SFLReceiver *receiver)
420 {
421     /* tell samplers and pollers to stop sending to this receiver */
422     /* first get his receiverIndex */
423     u_int32_t rcvIdx = 0;
424     SFLReceiver *rcv = agent->receivers;
425     for(; rcv != NULL; rcv = rcv->nxt) {
426         rcvIdx++; /* thanks to Diego Valverde for pointing out this bugfix */
427         if(rcv == receiver) {
428             /* now tell anyone that is using it to stop */
429             SFLSampler *sm = agent->samplers;
430             SFLPoller *pl = agent->pollers;
431
432             for(; sm != NULL; sm = sm->nxt)
433                 if(sfl_sampler_get_sFlowFsReceiver(sm) == rcvIdx) sfl_sampler_set_sFlowFsReceiver(sm, 0);
434
435             for(; pl != NULL; pl = pl->nxt)
436                 if(sfl_poller_get_sFlowCpReceiver(pl) == rcvIdx) sfl_poller_set_sFlowCpReceiver(pl, 0);
437
438             break;
439         }
440     }
441 }
442
443 /*_________________---------------------------__________________
444   _________________     sfl_agent_error       __________________
445   -----------------___________________________------------------
446 */
447 #define MAX_ERRMSG_LEN 1000
448
449 void sfl_agent_error(SFLAgent *agent, char *modName, char *msg)
450 {
451     char errm[MAX_ERRMSG_LEN];
452     sprintf(errm, "sfl_agent_error: %s: %s\n", modName, msg);
453     if(agent->errorFn) (*agent->errorFn)(agent->magic, agent, errm);
454     else {
455         fprintf(stderr, "%s\n", errm);
456         fflush(stderr);
457     }
458 }
459
460 /*_________________---------------------------__________________
461   _________________     sfl_agent_sysError    __________________
462   -----------------___________________________------------------
463 */
464
465 void sfl_agent_sysError(SFLAgent *agent, char *modName, char *msg)
466 {
467     char errm[MAX_ERRMSG_LEN];
468     sprintf(errm, "sfl_agent_sysError: %s: %s (errno = %d - %s)\n", modName, msg, errno, strerror(errno));
469     if(agent->errorFn) (*agent->errorFn)(agent->magic, agent, errm);
470     else {
471         fprintf(stderr, "%s\n", errm);
472         fflush(stderr);
473     }
474 }
475
476
477 /*_________________---------------------------__________________
478   _________________       alloc and free      __________________
479   -----------------___________________________------------------
480 */
481
482 static void * sflAlloc(SFLAgent *agent, size_t bytes)
483 {
484     if(agent->allocFn) return (*agent->allocFn)(agent->magic, agent, bytes);
485     else return SFL_ALLOC(bytes);
486 }
487
488 static void sflFree(SFLAgent *agent, void *obj)
489 {
490     if(agent->freeFn) (*agent->freeFn)(agent->magic, agent, obj);
491     else SFL_FREE(obj);
492 }