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
10 /*_________________--------------------------__________________
11 _________________ sfl_poller_init __________________
12 -----------------__________________________------------------
15 void sfl_poller_init(SFLPoller *poller,
17 SFLDataSource_instance *pdsi,
18 void *magic, /* ptr to pass back in getCountersFn() */
19 getCountersFn_t getCountersFn)
21 /* copy the dsi in case it points to poller->dsi, which we are about to clear */
22 SFLDataSource_instance dsi = *pdsi;
24 /* preserve the *nxt pointer too, in case we are resetting this poller and it is
25 already part of the agent's linked list (thanks to Matt Woodly for pointing this out) */
26 SFLPoller *nxtPtr = poller->nxt;
28 /* clear everything */
29 memset(poller, 0, sizeof(*poller));
31 /* restore the linked list ptr */
34 /* now copy in the parameters */
35 poller->agent = agent;
36 poller->dsi = dsi; /* structure copy */
37 poller->magic = magic;
38 poller->getCountersFn = getCountersFn;
41 /*_________________--------------------------__________________
42 _________________ reset __________________
43 -----------------__________________________------------------
46 static void reset(SFLPoller *poller)
48 SFLDataSource_instance dsi = poller->dsi;
49 sfl_poller_init(poller, poller->agent, &dsi, poller->magic, poller->getCountersFn);
52 /*_________________---------------------------__________________
53 _________________ MIB access __________________
54 -----------------___________________________------------------
56 u_int32_t sfl_poller_get_sFlowCpReceiver(SFLPoller *poller) {
57 return poller->sFlowCpReceiver;
60 void sfl_poller_set_sFlowCpReceiver(SFLPoller *poller, u_int32_t sFlowCpReceiver) {
61 poller->sFlowCpReceiver = sFlowCpReceiver;
62 if(sFlowCpReceiver == 0) reset(poller);
64 /* retrieve and cache a direct pointer to my receiver */
65 poller->myReceiver = sfl_agent_getReceiver(poller->agent, poller->sFlowCpReceiver);
69 u_int32_t sfl_poller_get_sFlowCpInterval(SFLPoller *poller) {
70 return poller->sFlowCpInterval;
73 void sfl_poller_set_sFlowCpInterval(SFLPoller *poller, u_int32_t sFlowCpInterval) {
74 poller->sFlowCpInterval = sFlowCpInterval;
76 /* Set the countersCountdown to be a randomly selected value between 1 and
77 sFlowCpInterval. That way the counter polling will be desynchronised
78 (on a 200-port switch, polling all the counters in one second could be harmful).
79 In a large network, even this might not be ideal if time-synchroniziation
80 between devices is close and counters are always polled on second boundaries. If
81 1000 different devices all send an sFlow datagram on the same second boundary
82 it could result in an antisocial burst.
83 However when counter-samples are packed into the export datagram they do not
84 always result in that datagram being sent immediately. It is more likely that
85 a subsequent packet-sample will be the one that triggers the datagram to be sent.
86 The packet-sample events are not sychronized to any clock, so that results in
87 excellent desynchronization (http://blog.sflow.com/2009/05/measurement-traffic.html).
88 Another smoothing factor is that the tick() function called here is usually
89 driven from a fairly "soft" polling loop rather than a hard real-time event.
91 poller->countersCountdown = 1 + (random() % sFlowCpInterval);
94 /* Setting sFlowCpInterval to 0 disables counter polling altogether. Thanks to
95 Andy Kitchingman for spotting this ommission. */
96 poller->countersCountdown = 0;
100 /*_________________---------------------------------__________________
101 _________________ bridge port __________________
102 -----------------_________________________________------------------
103 May need a separate number to reference the local bridge port
104 to get counters if it is not the same as the global ifIndex.
107 void sfl_poller_set_bridgePort(SFLPoller *poller, u_int32_t port_no) {
108 poller->bridgePort = port_no;
111 u_int32_t sfl_poller_get_bridgePort(SFLPoller *poller) {
112 return poller->bridgePort;
115 /*_________________---------------------------------__________________
116 _________________ sequence number reset __________________
117 -----------------_________________________________------------------
118 Used to indicate a counter discontinuity
119 so that the sflow collector will know to ignore the next delta.
121 void sfl_poller_resetCountersSeqNo(SFLPoller *poller) { poller->countersSampleSeqNo = 0; }
123 /*_________________---------------------------__________________
124 _________________ sfl_poller_tick __________________
125 -----------------___________________________------------------
128 void sfl_poller_tick(SFLPoller *poller, time_t now)
130 if(poller->countersCountdown == 0) return; /* counters retrieval was not enabled */
131 if(poller->sFlowCpReceiver == 0) return;
133 if(--poller->countersCountdown == 0) {
134 if(poller->getCountersFn != NULL) {
135 /* call out for counters */
136 SFL_COUNTERS_SAMPLE_TYPE cs;
137 memset(&cs, 0, sizeof(cs));
138 poller->getCountersFn(poller->magic, poller, &cs);
139 /* this countersFn is expected to fill in some counter block elements
140 and then call sfl_poller_writeCountersSample(poller, &cs); */
142 /* reset the countdown */
143 poller->countersCountdown = poller->sFlowCpInterval;
147 /*_________________---------------------------------__________________
148 _________________ sfl_poller_writeCountersSample __________________
149 -----------------_________________________________------------------
152 void sfl_poller_writeCountersSample(SFLPoller *poller, SFL_COUNTERS_SAMPLE_TYPE *cs)
154 /* fill in the rest of the header fields, and send to the receiver */
155 cs->sequence_number = ++poller->countersSampleSeqNo;
156 #ifdef SFL_USE_32BIT_INDEX
157 cs->ds_class = SFL_DS_CLASS(poller->dsi);
158 cs->ds_index = SFL_DS_INDEX(poller->dsi);
160 cs->source_id = SFL_DS_DATASOURCE(poller->dsi);
162 /* sent to my receiver */
163 if(poller->myReceiver) sfl_receiver_writeCountersSample(poller->myReceiver, cs);