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
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);
16 /*________________--------------------------__________________
17 ________________ sfl_agent_init __________________
18 ----------------__________________________------------------
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 */
32 /* first clear everything */
33 memset(agent, 0, sizeof(*agent));
34 /* now copy in the parameters */
35 agent->myIP = *myIP; /* structure copy */
37 agent->bootTime = bootTime;
40 agent->allocFn = allocFn;
41 agent->freeFn = freeFn;
42 agent->errorFn = errorFn;
43 agent->sendFn = sendFn;
45 #ifdef SFLOW_DO_SOCKET
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");
56 /*_________________---------------------------__________________
57 _________________ sfl_agent_release __________________
58 -----------------___________________________------------------
61 void sfl_agent_release(SFLAgent *agent)
63 /* release and free the samplers, pollers and receivers */
64 SFLSampler *sm = agent->samplers;
65 SFLPoller *pl = agent->pollers;
66 SFLReceiver *rcv = agent->receivers;
69 SFLSampler *nextSm = sm->nxt;
73 agent->samplers = NULL;
76 SFLPoller *nextPl = pl->nxt;
80 agent->pollers = NULL;
82 for(; rcv != NULL; ) {
83 SFLReceiver *nextRcv = rcv->nxt;
87 agent->receivers = NULL;
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);
97 /*_________________---------------------------__________________
98 _________________ sfl_agent_set_* __________________
99 -----------------___________________________------------------
102 void sfl_agent_set_agentAddress(SFLAgent *agent, SFLAddress *addr)
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? */
111 void sfl_agent_set_agentSubId(SFLAgent *agent, u_int32_t subId)
113 if(subId != agent->subId) {
114 /* change of subId */
115 agent->subId = subId;
116 /* reset sequence numbers here? */
120 /*_________________---------------------------__________________
121 _________________ sfl_agent_tick __________________
122 -----------------___________________________------------------
125 void sfl_agent_tick(SFLAgent *agent, time_t now)
127 SFLReceiver *rcv = agent->receivers;
128 SFLSampler *sm = agent->samplers;
129 SFLPoller *pl = agent->pollers;
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);
139 /*_________________---------------------------__________________
140 _________________ sfl_agent_addReceiver __________________
141 -----------------___________________________------------------
144 SFLReceiver *sfl_agent_addReceiver(SFLAgent *agent)
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 */
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;
159 /*_________________---------------------------__________________
160 _________________ sfl_dsi_compare __________________
161 -----------------___________________________------------------
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"
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;
179 /*_________________---------------------------__________________
180 _________________ sfl_agent_addSampler __________________
181 -----------------___________________________------------------
184 SFLSampler *sfl_agent_addSampler(SFLAgent *agent, SFLDataSource_instance *pdsi)
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 */
193 /* either we found the insert point, or reached the end of the list...*/
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;
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);
210 if(test == NULL) sfl_agent_jumpTableAdd(agent, newsm);
216 /*_________________---------------------------__________________
217 _________________ sfl_agent_addPoller __________________
218 -----------------___________________________------------------
221 SFLPoller *sfl_agent_addPoller(SFLAgent *agent,
222 SFLDataSource_instance *pdsi,
223 void *magic, /* ptr to pass back in getCountersFn() */
224 getCountersFn_t getCountersFn)
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 */
233 /* either we found the insert point, or reached the end of the list... */
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;
244 /*_________________---------------------------__________________
245 _________________ sfl_agent_removeSampler __________________
246 -----------------___________________________------------------
249 int sfl_agent_removeSampler(SFLAgent *agent, SFLDataSource_instance *pdsi)
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);
266 /*_________________---------------------------__________________
267 _________________ sfl_agent_removePoller __________________
268 -----------------___________________________------------------
271 int sfl_agent_removePoller(SFLAgent *agent, SFLDataSource_instance *pdsi)
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;
287 /*_________________--------------------------------__________________
288 _________________ sfl_agent_jumpTableAdd __________________
289 -----------------________________________________------------------
292 static void sfl_agent_jumpTableAdd(SFLAgent *agent, SFLSampler *sampler)
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;
299 /*_________________--------------------------------__________________
300 _________________ sfl_agent_jumpTableRemove __________________
301 -----------------________________________________------------------
304 static void sfl_agent_jumpTableRemove(SFLAgent *agent, SFLSampler *sampler)
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;
311 if(prev) prev->hash_nxt = search->hash_nxt;
312 else agent->jumpTable[hashIndex] = search->hash_nxt;
313 search->hash_nxt = NULL;
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.
329 SFLSampler *sfl_agent_getSamplerByIfIndex(SFLAgent *agent, u_int32_t ifIndex)
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;
336 /*_________________---------------------------__________________
337 _________________ sfl_agent_getSampler __________________
338 -----------------___________________________------------------
341 SFLSampler *sfl_agent_getSampler(SFLAgent *agent, SFLDataSource_instance *pdsi)
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;
351 /*_________________---------------------------__________________
352 _________________ sfl_agent_getPoller __________________
353 -----------------___________________________------------------
356 SFLPoller *sfl_agent_getPoller(SFLAgent *agent, SFLDataSource_instance *pdsi)
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;
366 /*_________________-----------------------------------__________________
367 _________________ sfl_agent_getPollerByBridgePort __________________
368 -----------------___________________________________------------------
371 SFLPoller *sfl_agent_getPollerByBridgePort(SFLAgent *agent, uint32_t port_no)
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;
381 /*_________________---------------------------__________________
382 _________________ sfl_agent_getReceiver __________________
383 -----------------___________________________------------------
386 SFLReceiver *sfl_agent_getReceiver(SFLAgent *agent, u_int32_t receiverIndex)
388 u_int32_t rcvIdx = 0;
389 SFLReceiver *rcv = agent->receivers;
390 for(; rcv != NULL; rcv = rcv->nxt)
391 if(receiverIndex == ++rcvIdx) return rcv;
393 /* not found - ran off the end of the table */
397 /*_________________---------------------------__________________
398 _________________ sfl_agent_getNextSampler __________________
399 -----------------___________________________------------------
402 SFLSampler *sfl_agent_getNextSampler(SFLAgent *agent, SFLDataSource_instance *pdsi)
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;
410 /*_________________---------------------------__________________
411 _________________ sfl_agent_getNextPoller __________________
412 -----------------___________________________------------------
415 SFLPoller *sfl_agent_getNextPoller(SFLAgent *agent, SFLDataSource_instance *pdsi)
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;
423 /*_________________---------------------------__________________
424 _________________ sfl_agent_getNextReceiver __________________
425 -----------------___________________________------------------
428 SFLReceiver *sfl_agent_getNextReceiver(SFLAgent *agent, u_int32_t receiverIndex)
430 return sfl_agent_getReceiver(agent, receiverIndex + 1);
434 /*_________________---------------------------__________________
435 _________________ sfl_agent_resetReceiver __________________
436 -----------------___________________________------------------
439 void sfl_agent_resetReceiver(SFLAgent *agent, SFLReceiver *receiver)
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;
452 for(; sm != NULL; sm = sm->nxt)
453 if(sfl_sampler_get_sFlowFsReceiver(sm) == rcvIdx) sfl_sampler_set_sFlowFsReceiver(sm, 0);
455 for(; pl != NULL; pl = pl->nxt)
456 if(sfl_poller_get_sFlowCpReceiver(pl) == rcvIdx) sfl_poller_set_sFlowCpReceiver(pl, 0);
463 /*_________________---------------------------__________________
464 _________________ sfl_agent_error __________________
465 -----------------___________________________------------------
467 #define MAX_ERRMSG_LEN 1000
469 void sfl_agent_error(SFLAgent *agent, char *modName, char *msg)
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);
475 fprintf(stderr, "%s\n", errm);
480 /*_________________---------------------------__________________
481 _________________ sfl_agent_sysError __________________
482 -----------------___________________________------------------
485 void sfl_agent_sysError(SFLAgent *agent, char *modName, char *msg)
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);
491 fprintf(stderr, "%s\n", errm);
497 /*_________________---------------------------__________________
498 _________________ alloc and free __________________
499 -----------------___________________________------------------
502 static void * sflAlloc(SFLAgent *agent, size_t bytes)
504 if(agent->allocFn) return (*agent->allocFn)(agent->magic, agent, bytes);
505 else return SFL_ALLOC(bytes);
508 static void sflFree(SFLAgent *agent, void *obj)
510 if(agent->freeFn) (*agent->freeFn)(agent->magic, agent, obj);