1 /* Copyright (c) 2002-2009 InMon Corp. Licensed under the terms of the InMon sFlow licence: */
2 /* http://www.inmon.com/technology/sflowlicense.txt */
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);
11 /*________________--------------------------__________________
12 ________________ sfl_agent_init __________________
13 ----------------__________________________------------------
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 */
27 /* first clear everything */
28 memset(agent, 0, sizeof(*agent));
29 /* now copy in the parameters */
30 agent->myIP = *myIP; /* structure copy */
32 agent->bootTime = bootTime;
35 agent->allocFn = allocFn;
36 agent->freeFn = freeFn;
37 agent->errorFn = errorFn;
38 agent->sendFn = sendFn;
40 #ifdef SFLOW_DO_SOCKET
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");
51 /*_________________---------------------------__________________
52 _________________ sfl_agent_release __________________
53 -----------------___________________________------------------
56 void sfl_agent_release(SFLAgent *agent)
58 /* release and free the samplers, pollers and receivers */
59 SFLSampler *sm = agent->samplers;
60 SFLPoller *pl = agent->pollers;
61 SFLReceiver *rcv = agent->receivers;
64 SFLSampler *nextSm = sm->nxt;
68 agent->samplers = NULL;
71 SFLPoller *nextPl = pl->nxt;
75 agent->pollers = NULL;
77 for(; rcv != NULL; ) {
78 SFLReceiver *nextRcv = rcv->nxt;
82 agent->receivers = NULL;
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);
92 /*_________________---------------------------__________________
93 _________________ sfl_agent_set_* __________________
94 -----------------___________________________------------------
97 void sfl_agent_set_agentAddress(SFLAgent *agent, SFLAddress *addr)
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? */
106 void sfl_agent_set_agentSubId(SFLAgent *agent, u_int32_t subId)
108 if(subId != agent->subId) {
109 /* change of subId */
110 agent->subId = subId;
111 /* reset sequence numbers here? */
115 /*_________________---------------------------__________________
116 _________________ sfl_agent_tick __________________
117 -----------------___________________________------------------
120 void sfl_agent_tick(SFLAgent *agent, time_t now)
122 SFLReceiver *rcv = agent->receivers;
123 SFLSampler *sm = agent->samplers;
124 SFLPoller *pl = agent->pollers;
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);
134 /*_________________---------------------------__________________
135 _________________ sfl_agent_addReceiver __________________
136 -----------------___________________________------------------
139 SFLReceiver *sfl_agent_addReceiver(SFLAgent *agent)
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 */
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;
154 /*_________________---------------------------__________________
155 _________________ sfl_dsi_compare __________________
156 -----------------___________________________------------------
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"
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;
174 /*_________________---------------------------__________________
175 _________________ sfl_agent_addSampler __________________
176 -----------------___________________________------------------
179 SFLSampler *sfl_agent_addSampler(SFLAgent *agent, SFLDataSource_instance *pdsi)
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 */
188 /* either we found the insert point, or reached the end of the list...*/
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;
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);
205 if(test == NULL) sfl_agent_jumpTableAdd(agent, newsm);
211 /*_________________---------------------------__________________
212 _________________ sfl_agent_addPoller __________________
213 -----------------___________________________------------------
216 SFLPoller *sfl_agent_addPoller(SFLAgent *agent,
217 SFLDataSource_instance *pdsi,
218 void *magic, /* ptr to pass back in getCountersFn() */
219 getCountersFn_t getCountersFn)
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 */
228 /* either we found the insert point, or reached the end of the list... */
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;
239 /*_________________---------------------------__________________
240 _________________ sfl_agent_removeSampler __________________
241 -----------------___________________________------------------
244 int sfl_agent_removeSampler(SFLAgent *agent, SFLDataSource_instance *pdsi)
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);
261 /*_________________---------------------------__________________
262 _________________ sfl_agent_removePoller __________________
263 -----------------___________________________------------------
266 int sfl_agent_removePoller(SFLAgent *agent, SFLDataSource_instance *pdsi)
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;
282 /*_________________--------------------------------__________________
283 _________________ sfl_agent_jumpTableAdd __________________
284 -----------------________________________________------------------
287 static void sfl_agent_jumpTableAdd(SFLAgent *agent, SFLSampler *sampler)
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;
294 /*_________________--------------------------------__________________
295 _________________ sfl_agent_jumpTableRemove __________________
296 -----------------________________________________------------------
299 static void sfl_agent_jumpTableRemove(SFLAgent *agent, SFLSampler *sampler)
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;
306 if(prev) prev->hash_nxt = search->hash_nxt;
307 else agent->jumpTable[hashIndex] = search->hash_nxt;
308 search->hash_nxt = NULL;
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.
324 SFLSampler *sfl_agent_getSamplerByIfIndex(SFLAgent *agent, u_int32_t ifIndex)
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;
331 /*_________________---------------------------__________________
332 _________________ sfl_agent_getSampler __________________
333 -----------------___________________________------------------
336 SFLSampler *sfl_agent_getSampler(SFLAgent *agent, SFLDataSource_instance *pdsi)
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;
346 /*_________________---------------------------__________________
347 _________________ sfl_agent_getPoller __________________
348 -----------------___________________________------------------
351 SFLPoller *sfl_agent_getPoller(SFLAgent *agent, SFLDataSource_instance *pdsi)
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;
361 /*_________________---------------------------__________________
362 _________________ sfl_agent_getReceiver __________________
363 -----------------___________________________------------------
366 SFLReceiver *sfl_agent_getReceiver(SFLAgent *agent, u_int32_t receiverIndex)
368 u_int32_t rcvIdx = 0;
369 SFLReceiver *rcv = agent->receivers;
370 for(; rcv != NULL; rcv = rcv->nxt)
371 if(receiverIndex == ++rcvIdx) return rcv;
373 /* not found - ran off the end of the table */
377 /*_________________---------------------------__________________
378 _________________ sfl_agent_getNextSampler __________________
379 -----------------___________________________------------------
382 SFLSampler *sfl_agent_getNextSampler(SFLAgent *agent, SFLDataSource_instance *pdsi)
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;
390 /*_________________---------------------------__________________
391 _________________ sfl_agent_getNextPoller __________________
392 -----------------___________________________------------------
395 SFLPoller *sfl_agent_getNextPoller(SFLAgent *agent, SFLDataSource_instance *pdsi)
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;
403 /*_________________---------------------------__________________
404 _________________ sfl_agent_getNextReceiver __________________
405 -----------------___________________________------------------
408 SFLReceiver *sfl_agent_getNextReceiver(SFLAgent *agent, u_int32_t receiverIndex)
410 return sfl_agent_getReceiver(agent, receiverIndex + 1);
414 /*_________________---------------------------__________________
415 _________________ sfl_agent_resetReceiver __________________
416 -----------------___________________________------------------
419 void sfl_agent_resetReceiver(SFLAgent *agent, SFLReceiver *receiver)
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;
432 for(; sm != NULL; sm = sm->nxt)
433 if(sfl_sampler_get_sFlowFsReceiver(sm) == rcvIdx) sfl_sampler_set_sFlowFsReceiver(sm, 0);
435 for(; pl != NULL; pl = pl->nxt)
436 if(sfl_poller_get_sFlowCpReceiver(pl) == rcvIdx) sfl_poller_set_sFlowCpReceiver(pl, 0);
443 /*_________________---------------------------__________________
444 _________________ sfl_agent_error __________________
445 -----------------___________________________------------------
447 #define MAX_ERRMSG_LEN 1000
449 void sfl_agent_error(SFLAgent *agent, char *modName, char *msg)
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);
455 fprintf(stderr, "%s\n", errm);
460 /*_________________---------------------------__________________
461 _________________ sfl_agent_sysError __________________
462 -----------------___________________________------------------
465 void sfl_agent_sysError(SFLAgent *agent, char *modName, char *msg)
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);
471 fprintf(stderr, "%s\n", errm);
477 /*_________________---------------------------__________________
478 _________________ alloc and free __________________
479 -----------------___________________________------------------
482 static void * sflAlloc(SFLAgent *agent, size_t bytes)
484 if(agent->allocFn) return (*agent->allocFn)(agent->magic, agent, bytes);
485 else return SFL_ALLOC(bytes);
488 static void sflFree(SFLAgent *agent, void *obj)
490 if(agent->freeFn) (*agent->freeFn)(agent->magic, agent, obj);