]> git.proxmox.com Git - ovs.git/blame - lib/sflow_agent.c
json: Fix error message for corner case in json_string_unescape().
[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;
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);
137}
138
139/*_________________---------------------------__________________
140 _________________ sfl_agent_addReceiver __________________
141 -----------------___________________________------------------
142*/
143
144SFLReceiver *sfl_agent_addReceiver(SFLAgent *agent)
145{
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 */
149 {
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;
154 rcv->nxt = NULL;
155 }
156 return rcv;
157}
158
159/*_________________---------------------------__________________
160 _________________ sfl_dsi_compare __________________
161 -----------------___________________________------------------
162
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"
168*/
169
170static 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;
176 return cmp;
177}
178
179/*_________________---------------------------__________________
180 _________________ sfl_agent_addSampler __________________
181 -----------------___________________________------------------
182*/
183
184SFLSampler *sfl_agent_addSampler(SFLAgent *agent, SFLDataSource_instance *pdsi)
185{
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 */
192 }
193 /* either we found the insert point, or reached the end of the list...*/
d295e8e9 194
c72e245a
BP
195 {
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;
200 newsm->nxt = sm;
d295e8e9 201
c72e245a
BP
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);
208 test = NULL;
209 }
210 if(test == NULL) sfl_agent_jumpTableAdd(agent, newsm);
211 }
212 return newsm;
213 }
214}
215
216/*_________________---------------------------__________________
217 _________________ sfl_agent_addPoller __________________
218 -----------------___________________________------------------
219*/
220
221SFLPoller *sfl_agent_addPoller(SFLAgent *agent,
222 SFLDataSource_instance *pdsi,
223 void *magic, /* ptr to pass back in getCountersFn() */
224 getCountersFn_t getCountersFn)
225{
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 */
232 }
233 /* either we found the insert point, or reached the end of the list... */
234 {
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;
239 newpl->nxt = pl;
240 return newpl;
241 }
242}
243
244/*_________________---------------------------__________________
245 _________________ sfl_agent_removeSampler __________________
246 -----------------___________________________------------------
247*/
248
249int sfl_agent_removeSampler(SFLAgent *agent, SFLDataSource_instance *pdsi)
250{
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);
258 sflFree(agent, sm);
259 return 1;
260 }
261 }
262 /* not found */
263 return 0;
264}
265
266/*_________________---------------------------__________________
267 _________________ sfl_agent_removePoller __________________
268 -----------------___________________________------------------
269*/
270
271int sfl_agent_removePoller(SFLAgent *agent, SFLDataSource_instance *pdsi)
272{
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;
279 sflFree(agent, pl);
280 return 1;
281 }
282 }
283 /* not found */
284 return 0;
285}
286
287/*_________________--------------------------------__________________
288 _________________ sfl_agent_jumpTableAdd __________________
289 -----------------________________________________------------------
290*/
291
292static void sfl_agent_jumpTableAdd(SFLAgent *agent, SFLSampler *sampler)
293{
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;
297}
298
299/*_________________--------------------------------__________________
300 _________________ sfl_agent_jumpTableRemove __________________
301 -----------------________________________________------------------
302*/
303
304static void sfl_agent_jumpTableRemove(SFLAgent *agent, SFLSampler *sampler)
305{
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;
309 if(search) {
310 // found - unlink
311 if(prev) prev->hash_nxt = search->hash_nxt;
312 else agent->jumpTable[hashIndex] = search->hash_nxt;
313 search->hash_nxt = NULL;
314 }
315}
316
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.
327*/
328
329SFLSampler *sfl_agent_getSamplerByIfIndex(SFLAgent *agent, u_int32_t ifIndex)
330{
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;
333 return search;
334}
335
336/*_________________---------------------------__________________
337 _________________ sfl_agent_getSampler __________________
338 -----------------___________________________------------------
339*/
340
341SFLSampler *sfl_agent_getSampler(SFLAgent *agent, SFLDataSource_instance *pdsi)
342{
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;
347 /* not found */
348 return NULL;
349}
350
351/*_________________---------------------------__________________
352 _________________ sfl_agent_getPoller __________________
353 -----------------___________________________------------------
354*/
355
356SFLPoller *sfl_agent_getPoller(SFLAgent *agent, SFLDataSource_instance *pdsi)
357{
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;
362 /* not found */
363 return NULL;
364}
365
50b9699f
NM
366/*_________________-----------------------------------__________________
367 _________________ sfl_agent_getPollerByBridgePort __________________
368 -----------------___________________________________------------------
369*/
370
371SFLPoller *sfl_agent_getPollerByBridgePort(SFLAgent *agent, uint32_t port_no)
372{
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;
377 /* not found */
378 return NULL;
379}
380
c72e245a
BP
381/*_________________---------------------------__________________
382 _________________ sfl_agent_getReceiver __________________
383 -----------------___________________________------------------
384*/
385
386SFLReceiver *sfl_agent_getReceiver(SFLAgent *agent, u_int32_t receiverIndex)
387{
388 u_int32_t rcvIdx = 0;
389 SFLReceiver *rcv = agent->receivers;
390 for(; rcv != NULL; rcv = rcv->nxt)
391 if(receiverIndex == ++rcvIdx) return rcv;
392
393 /* not found - ran off the end of the table */
394 return NULL;
395}
396
397/*_________________---------------------------__________________
398 _________________ sfl_agent_getNextSampler __________________
399 -----------------___________________________------------------
400*/
401
402SFLSampler *sfl_agent_getNextSampler(SFLAgent *agent, SFLDataSource_instance *pdsi)
403{
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;
408}
409
410/*_________________---------------------------__________________
411 _________________ sfl_agent_getNextPoller __________________
412 -----------------___________________________------------------
413*/
414
415SFLPoller *sfl_agent_getNextPoller(SFLAgent *agent, SFLDataSource_instance *pdsi)
416{
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;
421}
422
423/*_________________---------------------------__________________
424 _________________ sfl_agent_getNextReceiver __________________
425 -----------------___________________________------------------
426*/
427
428SFLReceiver *sfl_agent_getNextReceiver(SFLAgent *agent, u_int32_t receiverIndex)
429{
430 return sfl_agent_getReceiver(agent, receiverIndex + 1);
431}
432
433
434/*_________________---------------------------__________________
435 _________________ sfl_agent_resetReceiver __________________
436 -----------------___________________________------------------
437*/
438
439void sfl_agent_resetReceiver(SFLAgent *agent, SFLReceiver *receiver)
440{
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;
451
452 for(; sm != NULL; sm = sm->nxt)
453 if(sfl_sampler_get_sFlowFsReceiver(sm) == rcvIdx) sfl_sampler_set_sFlowFsReceiver(sm, 0);
d295e8e9 454
c72e245a
BP
455 for(; pl != NULL; pl = pl->nxt)
456 if(sfl_poller_get_sFlowCpReceiver(pl) == rcvIdx) sfl_poller_set_sFlowCpReceiver(pl, 0);
457
458 break;
459 }
460 }
461}
d295e8e9 462
c72e245a
BP
463/*_________________---------------------------__________________
464 _________________ sfl_agent_error __________________
465 -----------------___________________________------------------
466*/
467#define MAX_ERRMSG_LEN 1000
468
469void sfl_agent_error(SFLAgent *agent, char *modName, char *msg)
470{
471 char errm[MAX_ERRMSG_LEN];
fe13b0e7 472 snprintf(errm, sizeof errm, "sfl_agent_error: %s: %s\n", modName, msg);
c72e245a
BP
473 if(agent->errorFn) (*agent->errorFn)(agent->magic, agent, errm);
474 else {
475 fprintf(stderr, "%s\n", errm);
476 fflush(stderr);
477 }
478}
479
480/*_________________---------------------------__________________
481 _________________ sfl_agent_sysError __________________
482 -----------------___________________________------------------
483*/
484
485void sfl_agent_sysError(SFLAgent *agent, char *modName, char *msg)
486{
487 char errm[MAX_ERRMSG_LEN];
10a89ef0 488 snprintf(errm, sizeof errm, "sfl_agent_sysError: %s: %s (errno = %d - %s)\n", modName, msg, errno, ovs_strerror(errno));
c72e245a
BP
489 if(agent->errorFn) (*agent->errorFn)(agent->magic, agent, errm);
490 else {
491 fprintf(stderr, "%s\n", errm);
492 fflush(stderr);
493 }
494}
495
496
497/*_________________---------------------------__________________
498 _________________ alloc and free __________________
499 -----------------___________________________------------------
500*/
501
502static void * sflAlloc(SFLAgent *agent, size_t bytes)
503{
504 if(agent->allocFn) return (*agent->allocFn)(agent->magic, agent, bytes);
505 else return SFL_ALLOC(bytes);
506}
507
508static void sflFree(SFLAgent *agent, void *obj)
509{
510 if(agent->freeFn) (*agent->freeFn)(agent->magic, agent, obj);
511 else SFL_FREE(obj);
512}