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 /* 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
);
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.
139 for(; rcv
!= NULL
; rcv
= rcv
->nxt
) sfl_receiver_tick(rcv
, now
);
142 /*_________________---------------------------__________________
143 _________________ sfl_agent_addReceiver __________________
144 -----------------___________________________------------------
147 SFLReceiver
*sfl_agent_addReceiver(SFLAgent
*agent
)
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 */
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
;
162 /*_________________---------------------------__________________
163 _________________ sfl_dsi_compare __________________
164 -----------------___________________________------------------
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"
173 static 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
;
182 /*_________________---------------------------__________________
183 _________________ sfl_agent_addSampler __________________
184 -----------------___________________________------------------
187 SFLSampler
*sfl_agent_addSampler(SFLAgent
*agent
, SFLDataSource_instance
*pdsi
)
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 */
196 /* either we found the insert point, or reached the end of the list...*/
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
;
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
);
213 if(test
== NULL
) sfl_agent_jumpTableAdd(agent
, newsm
);
219 /*_________________---------------------------__________________
220 _________________ sfl_agent_addPoller __________________
221 -----------------___________________________------------------
224 SFLPoller
*sfl_agent_addPoller(SFLAgent
*agent
,
225 SFLDataSource_instance
*pdsi
,
226 void *magic
, /* ptr to pass back in getCountersFn() */
227 getCountersFn_t getCountersFn
)
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 */
236 /* either we found the insert point, or reached the end of the list... */
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
;
247 /*_________________---------------------------__________________
248 _________________ sfl_agent_removeSampler __________________
249 -----------------___________________________------------------
252 int sfl_agent_removeSampler(SFLAgent
*agent
, SFLDataSource_instance
*pdsi
)
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
);
269 /*_________________---------------------------__________________
270 _________________ sfl_agent_removePoller __________________
271 -----------------___________________________------------------
274 int sfl_agent_removePoller(SFLAgent
*agent
, SFLDataSource_instance
*pdsi
)
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
;
290 /*_________________--------------------------------__________________
291 _________________ sfl_agent_jumpTableAdd __________________
292 -----------------________________________________------------------
295 static void sfl_agent_jumpTableAdd(SFLAgent
*agent
, SFLSampler
*sampler
)
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
;
302 /*_________________--------------------------------__________________
303 _________________ sfl_agent_jumpTableRemove __________________
304 -----------------________________________________------------------
307 static void sfl_agent_jumpTableRemove(SFLAgent
*agent
, SFLSampler
*sampler
)
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;
314 if(prev
) prev
->hash_nxt
= search
->hash_nxt
;
315 else agent
->jumpTable
[hashIndex
] = search
->hash_nxt
;
316 search
->hash_nxt
= NULL
;
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.
332 SFLSampler
*sfl_agent_getSamplerByIfIndex(SFLAgent
*agent
, u_int32_t ifIndex
)
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;
339 /*_________________---------------------------__________________
340 _________________ sfl_agent_getSampler __________________
341 -----------------___________________________------------------
344 SFLSampler
*sfl_agent_getSampler(SFLAgent
*agent
, SFLDataSource_instance
*pdsi
)
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
;
354 /*_________________---------------------------__________________
355 _________________ sfl_agent_getPoller __________________
356 -----------------___________________________------------------
359 SFLPoller
*sfl_agent_getPoller(SFLAgent
*agent
, SFLDataSource_instance
*pdsi
)
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
;
369 /*_________________-----------------------------------__________________
370 _________________ sfl_agent_getPollerByBridgePort __________________
371 -----------------___________________________________------------------
374 SFLPoller
*sfl_agent_getPollerByBridgePort(SFLAgent
*agent
, uint32_t port_no
)
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
;
384 /*_________________---------------------------__________________
385 _________________ sfl_agent_getReceiver __________________
386 -----------------___________________________------------------
389 SFLReceiver
*sfl_agent_getReceiver(SFLAgent
*agent
, u_int32_t receiverIndex
)
391 u_int32_t rcvIdx
= 0;
392 SFLReceiver
*rcv
= agent
->receivers
;
393 for(; rcv
!= NULL
; rcv
= rcv
->nxt
)
394 if(receiverIndex
== ++rcvIdx
) return rcv
;
396 /* not found - ran off the end of the table */
400 /*_________________---------------------------__________________
401 _________________ sfl_agent_getNextSampler __________________
402 -----------------___________________________------------------
405 SFLSampler
*sfl_agent_getNextSampler(SFLAgent
*agent
, SFLDataSource_instance
*pdsi
)
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
;
413 /*_________________---------------------------__________________
414 _________________ sfl_agent_getNextPoller __________________
415 -----------------___________________________------------------
418 SFLPoller
*sfl_agent_getNextPoller(SFLAgent
*agent
, SFLDataSource_instance
*pdsi
)
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
;
426 /*_________________---------------------------__________________
427 _________________ sfl_agent_getNextReceiver __________________
428 -----------------___________________________------------------
431 SFLReceiver
*sfl_agent_getNextReceiver(SFLAgent
*agent
, u_int32_t receiverIndex
)
433 return sfl_agent_getReceiver(agent
, receiverIndex
+ 1);
437 /*_________________---------------------------__________________
438 _________________ sfl_agent_resetReceiver __________________
439 -----------------___________________________------------------
442 void sfl_agent_resetReceiver(SFLAgent
*agent
, SFLReceiver
*receiver
)
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
;
455 for(; sm
!= NULL
; sm
= sm
->nxt
)
456 if(sfl_sampler_get_sFlowFsReceiver(sm
) == rcvIdx
) sfl_sampler_set_sFlowFsReceiver(sm
, 0);
458 for(; pl
!= NULL
; pl
= pl
->nxt
)
459 if(sfl_poller_get_sFlowCpReceiver(pl
) == rcvIdx
) sfl_poller_set_sFlowCpReceiver(pl
, 0);
466 /*_________________---------------------------__________________
467 _________________ sfl_agent_error __________________
468 -----------------___________________________------------------
470 #define MAX_ERRMSG_LEN 1000
472 void sfl_agent_error(SFLAgent
*agent
, char *modName
, char *msg
)
474 char errm
[MAX_ERRMSG_LEN
];
475 snprintf(errm
, sizeof errm
, "sfl_agent_error: %s: %s\n", modName
, msg
);
476 if(agent
->errorFn
) (*agent
->errorFn
)(agent
->magic
, agent
, errm
);
478 fprintf(stderr
, "%s\n", errm
);
483 /*_________________---------------------------__________________
484 _________________ sfl_agent_sysError __________________
485 -----------------___________________________------------------
488 void sfl_agent_sysError(SFLAgent
*agent
, char *modName
, char *msg
)
490 char errm
[MAX_ERRMSG_LEN
];
491 snprintf(errm
, sizeof errm
, "sfl_agent_sysError: %s: %s (errno = %d - %s)\n", modName
, msg
, errno
, ovs_strerror(errno
));
492 if(agent
->errorFn
) (*agent
->errorFn
)(agent
->magic
, agent
, errm
);
494 fprintf(stderr
, "%s\n", errm
);
500 /*_________________---------------------------__________________
501 _________________ alloc and free __________________
502 -----------------___________________________------------------
505 static void * sflAlloc(SFLAgent
*agent
, size_t bytes
)
507 if(agent
->allocFn
) return (*agent
->allocFn
)(agent
->magic
, agent
, bytes
);
508 else return SFL_ALLOC(bytes
);
511 static void sflFree(SFLAgent
*agent
, void *obj
)
513 if(agent
->freeFn
) (*agent
->freeFn
)(agent
->magic
, agent
, obj
);