]> git.proxmox.com Git - mirror_ovs.git/blame - lib/sflow_agent.c
ovsdb-idl: Fix iteration over tracked rows with no actual data.
[mirror_ovs.git] / lib / sflow_agent.c
CommitLineData
7dd32dff
NM
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 */
c72e245a
BP
7
8#include "sflow_api.h"
10a89ef0 9#include "util.h"
c72e245a
BP
10
11static void * sflAlloc(SFLAgent *agent, size_t bytes);
12static void sflFree(SFLAgent *agent, void *obj);
13static void sfl_agent_jumpTableAdd(SFLAgent *agent, SFLSampler *sampler);
14static void sfl_agent_jumpTableRemove(SFLAgent *agent, SFLSampler *sampler);
15
16/*________________--------------------------__________________
17 ________________ sfl_agent_init __________________
18 ----------------__________________________------------------
19*/
20
21void 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
d295e8e9 45#ifdef SFLOW_DO_SOCKET
c72e245a
BP
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
61void 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
102void 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
111void 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
125void 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;
c72e245a
BP
131 /* samplers use ticks to decide when they are sampling too fast */
132 for(; sm != NULL; sm = sm->nxt) sfl_sampler_tick(sm, now);
133 /* pollers use ticks to decide when to ask for counters */
134 for(; pl != NULL; pl = pl->nxt) sfl_poller_tick(pl, now);
784bf5d4
NM
135 /* receivers use ticks to flush send data. By doing this
136 * step last we ensure that fresh counters polled during
137 * sfl_poller_tick() above will be flushed promptly.
138 */
139 for(; rcv != NULL; rcv = rcv->nxt) sfl_receiver_tick(rcv, now);
c72e245a
BP
140}
141
142/*_________________---------------------------__________________
143 _________________ sfl_agent_addReceiver __________________
144 -----------------___________________________------------------
145*/
146
147SFLReceiver *sfl_agent_addReceiver(SFLAgent *agent)
148{
149 SFLReceiver *rcv = (SFLReceiver *)sflAlloc(agent, sizeof(SFLReceiver));
150 sfl_receiver_init(rcv, agent);
151 /* add to end of list - to preserve the receiver index numbers for existing receivers */
152 {
153 SFLReceiver *r, *prev = NULL;
154 for(r = agent->receivers; r != NULL; prev = r, r = r->nxt);
155 if(prev) prev->nxt = rcv;
156 else agent->receivers = rcv;
157 rcv->nxt = NULL;
158 }
159 return rcv;
160}
161
162/*_________________---------------------------__________________
163 _________________ sfl_dsi_compare __________________
164 -----------------___________________________------------------
165
166 Note that if there is a mixture of ds_classes for this agent, then
167 the simple numeric comparison may not be correct - the sort order (for
168 the purposes of the SNMP MIB) should really be determined by the OID
169 that these numeric ds_class numbers are a shorthand for. For example,
170 ds_class == 0 means ifIndex, which is the oid "1.3.6.1.2.1.2.2.1"
171*/
172
173static inline int sfl_dsi_compare(SFLDataSource_instance *pdsi1, SFLDataSource_instance *pdsi2) {
174 /* could have used just memcmp(), but not sure if that would
175 give the right answer on little-endian platforms. Safer to be explicit... */
176 int cmp = pdsi2->ds_class - pdsi1->ds_class;
177 if(cmp == 0) cmp = pdsi2->ds_index - pdsi1->ds_index;
178 if(cmp == 0) cmp = pdsi2->ds_instance - pdsi1->ds_instance;
179 return cmp;
180}
181
182/*_________________---------------------------__________________
183 _________________ sfl_agent_addSampler __________________
184 -----------------___________________________------------------
185*/
186
187SFLSampler *sfl_agent_addSampler(SFLAgent *agent, SFLDataSource_instance *pdsi)
188{
189 /* Keep the list sorted. */
190 SFLSampler *prev = NULL, *sm = agent->samplers;
191 for(; sm != NULL; prev = sm, sm = sm->nxt) {
192 int64_t cmp = sfl_dsi_compare(pdsi, &sm->dsi);
193 if(cmp == 0) return sm; /* found - return existing one */
194 if(cmp < 0) break; /* insert here */
195 }
196 /* either we found the insert point, or reached the end of the list...*/
d295e8e9 197
c72e245a
BP
198 {
199 SFLSampler *newsm = (SFLSampler *)sflAlloc(agent, sizeof(SFLSampler));
200 sfl_sampler_init(newsm, agent, pdsi);
201 if(prev) prev->nxt = newsm;
202 else agent->samplers = newsm;
203 newsm->nxt = sm;
d295e8e9 204
c72e245a
BP
205 /* see if we should go in the ifIndex jumpTable */
206 if(SFL_DS_CLASS(newsm->dsi) == 0) {
207 SFLSampler *test = sfl_agent_getSamplerByIfIndex(agent, SFL_DS_INDEX(newsm->dsi));
208 if(test && (SFL_DS_INSTANCE(newsm->dsi) < SFL_DS_INSTANCE(test->dsi))) {
209 /* replace with this new one because it has a lower ds_instance number */
210 sfl_agent_jumpTableRemove(agent, test);
211 test = NULL;
212 }
213 if(test == NULL) sfl_agent_jumpTableAdd(agent, newsm);
214 }
215 return newsm;
216 }
217}
218
219/*_________________---------------------------__________________
220 _________________ sfl_agent_addPoller __________________
221 -----------------___________________________------------------
222*/
223
224SFLPoller *sfl_agent_addPoller(SFLAgent *agent,
225 SFLDataSource_instance *pdsi,
226 void *magic, /* ptr to pass back in getCountersFn() */
227 getCountersFn_t getCountersFn)
228{
229 /* keep the list sorted */
230 SFLPoller *prev = NULL, *pl = agent->pollers;
231 for(; pl != NULL; prev = pl, pl = pl->nxt) {
232 int64_t cmp = sfl_dsi_compare(pdsi, &pl->dsi);
233 if(cmp == 0) return pl; /* found - return existing one */
234 if(cmp < 0) break; /* insert here */
235 }
236 /* either we found the insert point, or reached the end of the list... */
237 {
238 SFLPoller *newpl = (SFLPoller *)sflAlloc(agent, sizeof(SFLPoller));
239 sfl_poller_init(newpl, agent, pdsi, magic, getCountersFn);
240 if(prev) prev->nxt = newpl;
241 else agent->pollers = newpl;
242 newpl->nxt = pl;
243 return newpl;
244 }
245}
246
247/*_________________---------------------------__________________
248 _________________ sfl_agent_removeSampler __________________
249 -----------------___________________________------------------
250*/
251
252int sfl_agent_removeSampler(SFLAgent *agent, SFLDataSource_instance *pdsi)
253{
254 /* find it, unlink it and free it */
255 SFLSampler *prev = NULL, *sm = agent->samplers;
256 for(; sm != NULL; prev = sm, sm = sm->nxt) {
257 if(sfl_dsi_compare(pdsi, &sm->dsi) == 0) {
258 if(prev == NULL) agent->samplers = sm->nxt;
259 else prev->nxt = sm->nxt;
260 sfl_agent_jumpTableRemove(agent, sm);
261 sflFree(agent, sm);
262 return 1;
263 }
264 }
265 /* not found */
266 return 0;
267}
268
269/*_________________---------------------------__________________
270 _________________ sfl_agent_removePoller __________________
271 -----------------___________________________------------------
272*/
273
274int sfl_agent_removePoller(SFLAgent *agent, SFLDataSource_instance *pdsi)
275{
276 /* find it, unlink it and free it */
277 SFLPoller *prev = NULL, *pl = agent->pollers;
278 for(; pl != NULL; prev = pl, pl = pl->nxt) {
279 if(sfl_dsi_compare(pdsi, &pl->dsi) == 0) {
280 if(prev == NULL) agent->pollers = pl->nxt;
281 else prev->nxt = pl->nxt;
282 sflFree(agent, pl);
283 return 1;
284 }
285 }
286 /* not found */
287 return 0;
288}
289
290/*_________________--------------------------------__________________
291 _________________ sfl_agent_jumpTableAdd __________________
292 -----------------________________________________------------------
293*/
294
295static void sfl_agent_jumpTableAdd(SFLAgent *agent, SFLSampler *sampler)
296{
297 u_int32_t hashIndex = SFL_DS_INDEX(sampler->dsi) % SFL_HASHTABLE_SIZ;
298 sampler->hash_nxt = agent->jumpTable[hashIndex];
299 agent->jumpTable[hashIndex] = sampler;
300}
301
302/*_________________--------------------------------__________________
303 _________________ sfl_agent_jumpTableRemove __________________
304 -----------------________________________________------------------
305*/
306
307static void sfl_agent_jumpTableRemove(SFLAgent *agent, SFLSampler *sampler)
308{
309 u_int32_t hashIndex = SFL_DS_INDEX(sampler->dsi) % SFL_HASHTABLE_SIZ;
310 SFLSampler *search = agent->jumpTable[hashIndex], *prev = NULL;
311 for( ; search != NULL; prev = search, search = search->hash_nxt) if(search == sampler) break;
312 if(search) {
313 // found - unlink
314 if(prev) prev->hash_nxt = search->hash_nxt;
315 else agent->jumpTable[hashIndex] = search->hash_nxt;
316 search->hash_nxt = NULL;
317 }
318}
319
320/*_________________--------------------------------__________________
321 _________________ sfl_agent_getSamplerByIfIndex __________________
322 -----------------________________________________------------------
323 fast lookup (pointers cached in hash table). If there are multiple
324 sampler instances for a given ifIndex, then this fn will return
325 the one with the lowest instance number. Since the samplers
326 list is sorted, this means the other instances will be accesible
327 by following the sampler->nxt pointer (until the ds_class
328 or ds_index changes). This is helpful if you need to offer
329 the same flowSample to multiple samplers.
330*/
331
332SFLSampler *sfl_agent_getSamplerByIfIndex(SFLAgent *agent, u_int32_t ifIndex)
333{
334 SFLSampler *search = agent->jumpTable[ifIndex % SFL_HASHTABLE_SIZ];
335 for( ; search != NULL; search = search->hash_nxt) if(SFL_DS_INDEX(search->dsi) == ifIndex) break;
336 return search;
337}
338
339/*_________________---------------------------__________________
340 _________________ sfl_agent_getSampler __________________
341 -----------------___________________________------------------
342*/
343
344SFLSampler *sfl_agent_getSampler(SFLAgent *agent, SFLDataSource_instance *pdsi)
345{
346 /* find it and return it */
347 SFLSampler *sm = agent->samplers;
348 for(; sm != NULL; sm = sm->nxt)
349 if(sfl_dsi_compare(pdsi, &sm->dsi) == 0) return sm;
350 /* not found */
351 return NULL;
352}
353
354/*_________________---------------------------__________________
355 _________________ sfl_agent_getPoller __________________
356 -----------------___________________________------------------
357*/
358
359SFLPoller *sfl_agent_getPoller(SFLAgent *agent, SFLDataSource_instance *pdsi)
360{
361 /* find it and return it */
362 SFLPoller *pl = agent->pollers;
363 for(; pl != NULL; pl = pl->nxt)
364 if(sfl_dsi_compare(pdsi, &pl->dsi) == 0) return pl;
365 /* not found */
366 return NULL;
367}
368
50b9699f
NM
369/*_________________-----------------------------------__________________
370 _________________ sfl_agent_getPollerByBridgePort __________________
371 -----------------___________________________________------------------
372*/
373
374SFLPoller *sfl_agent_getPollerByBridgePort(SFLAgent *agent, uint32_t port_no)
375{
376 /* find it and return it */
377 SFLPoller *pl = agent->pollers;
378 for(; pl != NULL; pl = pl->nxt)
379 if(pl->bridgePort == port_no) return pl;
380 /* not found */
381 return NULL;
382}
383
c72e245a
BP
384/*_________________---------------------------__________________
385 _________________ sfl_agent_getReceiver __________________
386 -----------------___________________________------------------
387*/
388
389SFLReceiver *sfl_agent_getReceiver(SFLAgent *agent, u_int32_t receiverIndex)
390{
391 u_int32_t rcvIdx = 0;
392 SFLReceiver *rcv = agent->receivers;
393 for(; rcv != NULL; rcv = rcv->nxt)
394 if(receiverIndex == ++rcvIdx) return rcv;
395
396 /* not found - ran off the end of the table */
397 return NULL;
398}
399
400/*_________________---------------------------__________________
401 _________________ sfl_agent_getNextSampler __________________
402 -----------------___________________________------------------
403*/
404
405SFLSampler *sfl_agent_getNextSampler(SFLAgent *agent, SFLDataSource_instance *pdsi)
406{
407 /* return the one lexograpically just after it - assume they are sorted
408 correctly according to the lexographical ordering of the object ids */
409 SFLSampler *sm = sfl_agent_getSampler(agent, pdsi);
410 return sm ? sm->nxt : NULL;
411}
412
413/*_________________---------------------------__________________
414 _________________ sfl_agent_getNextPoller __________________
415 -----------------___________________________------------------
416*/
417
418SFLPoller *sfl_agent_getNextPoller(SFLAgent *agent, SFLDataSource_instance *pdsi)
419{
420 /* return the one lexograpically just after it - assume they are sorted
421 correctly according to the lexographical ordering of the object ids */
422 SFLPoller *pl = sfl_agent_getPoller(agent, pdsi);
423 return pl ? pl->nxt : NULL;
424}
425
426/*_________________---------------------------__________________
427 _________________ sfl_agent_getNextReceiver __________________
428 -----------------___________________________------------------
429*/
430
431SFLReceiver *sfl_agent_getNextReceiver(SFLAgent *agent, u_int32_t receiverIndex)
432{
433 return sfl_agent_getReceiver(agent, receiverIndex + 1);
434}
435
436
437/*_________________---------------------------__________________
438 _________________ sfl_agent_resetReceiver __________________
439 -----------------___________________________------------------
440*/
441
442void sfl_agent_resetReceiver(SFLAgent *agent, SFLReceiver *receiver)
443{
444 /* tell samplers and pollers to stop sending to this receiver */
445 /* first get his receiverIndex */
446 u_int32_t rcvIdx = 0;
447 SFLReceiver *rcv = agent->receivers;
448 for(; rcv != NULL; rcv = rcv->nxt) {
449 rcvIdx++; /* thanks to Diego Valverde for pointing out this bugfix */
450 if(rcv == receiver) {
451 /* now tell anyone that is using it to stop */
452 SFLSampler *sm = agent->samplers;
453 SFLPoller *pl = agent->pollers;
454
455 for(; sm != NULL; sm = sm->nxt)
456 if(sfl_sampler_get_sFlowFsReceiver(sm) == rcvIdx) sfl_sampler_set_sFlowFsReceiver(sm, 0);
d295e8e9 457
c72e245a
BP
458 for(; pl != NULL; pl = pl->nxt)
459 if(sfl_poller_get_sFlowCpReceiver(pl) == rcvIdx) sfl_poller_set_sFlowCpReceiver(pl, 0);
460
461 break;
462 }
463 }
464}
d295e8e9 465
c72e245a
BP
466/*_________________---------------------------__________________
467 _________________ sfl_agent_error __________________
468 -----------------___________________________------------------
469*/
470#define MAX_ERRMSG_LEN 1000
471
472void sfl_agent_error(SFLAgent *agent, char *modName, char *msg)
473{
474 char errm[MAX_ERRMSG_LEN];
fe13b0e7 475 snprintf(errm, sizeof errm, "sfl_agent_error: %s: %s\n", modName, msg);
c72e245a
BP
476 if(agent->errorFn) (*agent->errorFn)(agent->magic, agent, errm);
477 else {
478 fprintf(stderr, "%s\n", errm);
479 fflush(stderr);
480 }
481}
482
483/*_________________---------------------------__________________
484 _________________ sfl_agent_sysError __________________
485 -----------------___________________________------------------
486*/
487
488void sfl_agent_sysError(SFLAgent *agent, char *modName, char *msg)
489{
490 char errm[MAX_ERRMSG_LEN];
10a89ef0 491 snprintf(errm, sizeof errm, "sfl_agent_sysError: %s: %s (errno = %d - %s)\n", modName, msg, errno, ovs_strerror(errno));
c72e245a
BP
492 if(agent->errorFn) (*agent->errorFn)(agent->magic, agent, errm);
493 else {
494 fprintf(stderr, "%s\n", errm);
495 fflush(stderr);
496 }
497}
498
499
500/*_________________---------------------------__________________
501 _________________ alloc and free __________________
502 -----------------___________________________------------------
503*/
504
505static void * sflAlloc(SFLAgent *agent, size_t bytes)
506{
507 if(agent->allocFn) return (*agent->allocFn)(agent->magic, agent, bytes);
508 else return SFL_ALLOC(bytes);
509}
510
511static void sflFree(SFLAgent *agent, void *obj)
512{
513 if(agent->freeFn) (*agent->freeFn)(agent->magic, agent, obj);
514 else SFL_FREE(obj);
515}