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_getReceiver __________________
368 -----------------___________________________------------------
371 SFLReceiver *sfl_agent_getReceiver(SFLAgent *agent, u_int32_t receiverIndex)
373 u_int32_t rcvIdx = 0;
374 SFLReceiver *rcv = agent->receivers;
375 for(; rcv != NULL; rcv = rcv->nxt)
376 if(receiverIndex == ++rcvIdx) return rcv;
378 /* not found - ran off the end of the table */
382 /*_________________---------------------------__________________
383 _________________ sfl_agent_getNextSampler __________________
384 -----------------___________________________------------------
387 SFLSampler *sfl_agent_getNextSampler(SFLAgent *agent, SFLDataSource_instance *pdsi)
389 /* return the one lexograpically just after it - assume they are sorted
390 correctly according to the lexographical ordering of the object ids */
391 SFLSampler *sm = sfl_agent_getSampler(agent, pdsi);
392 return sm ? sm->nxt : NULL;
395 /*_________________---------------------------__________________
396 _________________ sfl_agent_getNextPoller __________________
397 -----------------___________________________------------------
400 SFLPoller *sfl_agent_getNextPoller(SFLAgent *agent, SFLDataSource_instance *pdsi)
402 /* return the one lexograpically just after it - assume they are sorted
403 correctly according to the lexographical ordering of the object ids */
404 SFLPoller *pl = sfl_agent_getPoller(agent, pdsi);
405 return pl ? pl->nxt : NULL;
408 /*_________________---------------------------__________________
409 _________________ sfl_agent_getNextReceiver __________________
410 -----------------___________________________------------------
413 SFLReceiver *sfl_agent_getNextReceiver(SFLAgent *agent, u_int32_t receiverIndex)
415 return sfl_agent_getReceiver(agent, receiverIndex + 1);
419 /*_________________---------------------------__________________
420 _________________ sfl_agent_resetReceiver __________________
421 -----------------___________________________------------------
424 void sfl_agent_resetReceiver(SFLAgent *agent, SFLReceiver *receiver)
426 /* tell samplers and pollers to stop sending to this receiver */
427 /* first get his receiverIndex */
428 u_int32_t rcvIdx = 0;
429 SFLReceiver *rcv = agent->receivers;
430 for(; rcv != NULL; rcv = rcv->nxt) {
431 rcvIdx++; /* thanks to Diego Valverde for pointing out this bugfix */
432 if(rcv == receiver) {
433 /* now tell anyone that is using it to stop */
434 SFLSampler *sm = agent->samplers;
435 SFLPoller *pl = agent->pollers;
437 for(; sm != NULL; sm = sm->nxt)
438 if(sfl_sampler_get_sFlowFsReceiver(sm) == rcvIdx) sfl_sampler_set_sFlowFsReceiver(sm, 0);
440 for(; pl != NULL; pl = pl->nxt)
441 if(sfl_poller_get_sFlowCpReceiver(pl) == rcvIdx) sfl_poller_set_sFlowCpReceiver(pl, 0);
448 /*_________________---------------------------__________________
449 _________________ sfl_agent_error __________________
450 -----------------___________________________------------------
452 #define MAX_ERRMSG_LEN 1000
454 void sfl_agent_error(SFLAgent *agent, char *modName, char *msg)
456 char errm[MAX_ERRMSG_LEN];
457 snprintf(errm, sizeof errm, "sfl_agent_error: %s: %s\n", modName, msg);
458 if(agent->errorFn) (*agent->errorFn)(agent->magic, agent, errm);
460 fprintf(stderr, "%s\n", errm);
465 /*_________________---------------------------__________________
466 _________________ sfl_agent_sysError __________________
467 -----------------___________________________------------------
470 void sfl_agent_sysError(SFLAgent *agent, char *modName, char *msg)
472 char errm[MAX_ERRMSG_LEN];
473 snprintf(errm, sizeof errm, "sfl_agent_sysError: %s: %s (errno = %d - %s)\n", modName, msg, errno, ovs_strerror(errno));
474 if(agent->errorFn) (*agent->errorFn)(agent->magic, agent, errm);
476 fprintf(stderr, "%s\n", errm);
482 /*_________________---------------------------__________________
483 _________________ alloc and free __________________
484 -----------------___________________________------------------
487 static void * sflAlloc(SFLAgent *agent, size_t bytes)
489 if(agent->allocFn) return (*agent->allocFn)(agent->magic, agent, bytes);
490 else return SFL_ALLOC(bytes);
493 static void sflFree(SFLAgent *agent, void *obj)
495 if(agent->freeFn) (*agent->freeFn)(agent->magic, agent, obj);