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