Branch data Line data Source code
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 : : */
7 : :
8 : : #include "sflow_api.h"
9 : :
10 : : /*_________________--------------------------__________________
11 : : _________________ sfl_poller_init __________________
12 : : -----------------__________________________------------------
13 : : */
14 : :
15 : 14 : void sfl_poller_init(SFLPoller *poller,
16 : : SFLAgent *agent,
17 : : SFLDataSource_instance *pdsi,
18 : : void *magic, /* ptr to pass back in getCountersFn() */
19 : : getCountersFn_t getCountersFn)
20 : : {
21 : : /* copy the dsi in case it points to poller->dsi, which we are about to clear */
22 : 14 : SFLDataSource_instance dsi = *pdsi;
23 : :
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 : 14 : SFLPoller *nxtPtr = poller->nxt;
27 : :
28 : : /* clear everything */
29 : 14 : memset(poller, 0, sizeof(*poller));
30 : :
31 : : /* restore the linked list ptr */
32 : 14 : poller->nxt = nxtPtr;
33 : :
34 : : /* now copy in the parameters */
35 : 14 : poller->agent = agent;
36 : 14 : poller->dsi = dsi; /* structure copy */
37 : 14 : poller->magic = magic;
38 : 14 : poller->getCountersFn = getCountersFn;
39 : 14 : }
40 : :
41 : : /*_________________--------------------------__________________
42 : : _________________ reset __________________
43 : : -----------------__________________________------------------
44 : : */
45 : :
46 : 0 : static void reset(SFLPoller *poller)
47 : : {
48 : 0 : SFLDataSource_instance dsi = poller->dsi;
49 : 0 : sfl_poller_init(poller, poller->agent, &dsi, poller->magic, poller->getCountersFn);
50 : 0 : }
51 : :
52 : : /*_________________---------------------------__________________
53 : : _________________ MIB access __________________
54 : : -----------------___________________________------------------
55 : : */
56 : 0 : u_int32_t sfl_poller_get_sFlowCpReceiver(SFLPoller *poller) {
57 : 0 : return poller->sFlowCpReceiver;
58 : : }
59 : :
60 : 14 : void sfl_poller_set_sFlowCpReceiver(SFLPoller *poller, u_int32_t sFlowCpReceiver) {
61 : 14 : poller->sFlowCpReceiver = sFlowCpReceiver;
62 [ - + ]: 14 : if(sFlowCpReceiver == 0) reset(poller);
63 : : else {
64 : : /* retrieve and cache a direct pointer to my receiver */
65 : 14 : poller->myReceiver = sfl_agent_getReceiver(poller->agent, poller->sFlowCpReceiver);
66 : : }
67 : 14 : }
68 : :
69 : 0 : u_int32_t sfl_poller_get_sFlowCpInterval(SFLPoller *poller) {
70 : 0 : return poller->sFlowCpInterval;
71 : : }
72 : :
73 : 14 : void sfl_poller_set_sFlowCpInterval(SFLPoller *poller, u_int32_t sFlowCpInterval) {
74 : 14 : poller->sFlowCpInterval = sFlowCpInterval;
75 [ + + ]: 14 : if(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.
90 : : */
91 : 10 : poller->countersCountdown = 1 + (random() % sFlowCpInterval);
92 : : }
93 : : else {
94 : : /* Setting sFlowCpInterval to 0 disables counter polling altogether. Thanks to
95 : : Andy Kitchingman for spotting this ommission. */
96 : 4 : poller->countersCountdown = 0;
97 : : }
98 : 14 : }
99 : :
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.
105 : : */
106 : :
107 : 8 : void sfl_poller_set_bridgePort(SFLPoller *poller, u_int32_t port_no) {
108 : 8 : poller->bridgePort = port_no;
109 : 8 : }
110 : :
111 : 0 : u_int32_t sfl_poller_get_bridgePort(SFLPoller *poller) {
112 : 0 : return poller->bridgePort;
113 : : }
114 : :
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.
120 : : */
121 : 0 : void sfl_poller_resetCountersSeqNo(SFLPoller *poller) { poller->countersSampleSeqNo = 0; }
122 : :
123 : : /*_________________---------------------------__________________
124 : : _________________ sfl_poller_tick __________________
125 : : -----------------___________________________------------------
126 : : */
127 : :
128 : 32 : void sfl_poller_tick(SFLPoller *poller, time_t now)
129 : : {
130 [ + + ]: 32 : if(poller->countersCountdown == 0) return; /* counters retrieval was not enabled */
131 [ - + ]: 20 : if(poller->sFlowCpReceiver == 0) return;
132 : :
133 [ + - ]: 20 : if(--poller->countersCountdown == 0) {
134 [ + - ]: 20 : if(poller->getCountersFn != NULL) {
135 : : /* call out for counters */
136 : : SFL_COUNTERS_SAMPLE_TYPE cs;
137 : 20 : memset(&cs, 0, sizeof(cs));
138 : 20 : 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); */
141 : : }
142 : : /* reset the countdown */
143 : 20 : poller->countersCountdown = poller->sFlowCpInterval;
144 : : }
145 : : }
146 : :
147 : : /*_________________---------------------------------__________________
148 : : _________________ sfl_poller_writeCountersSample __________________
149 : : -----------------_________________________________------------------
150 : : */
151 : :
152 : 20 : void sfl_poller_writeCountersSample(SFLPoller *poller, SFL_COUNTERS_SAMPLE_TYPE *cs)
153 : : {
154 : : /* fill in the rest of the header fields, and send to the receiver */
155 : 20 : 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);
159 : : #else
160 : 20 : cs->source_id = SFL_DS_DATASOURCE(poller->dsi);
161 : : #endif
162 : : /* sent to my receiver */
163 [ + - ]: 20 : if(poller->myReceiver) sfl_receiver_writeCountersSample(poller->myReceiver, cs);
164 : 20 : }
165 : :
|