treewide: Remove trailing whitespace
[sliver-openvswitch.git] / lib / sflow_poller.c
1 /* Copyright (c) 2002-2009 InMon Corp. Licensed under the terms of the InMon sFlow licence: */
2 /* http://www.inmon.com/technology/sflowlicense.txt */
3
4 #include "sflow_api.h"
5
6 /*_________________--------------------------__________________
7   _________________    sfl_poller_init       __________________
8   -----------------__________________________------------------
9 */
10
11 void sfl_poller_init(SFLPoller *poller,
12                      SFLAgent *agent,
13                      SFLDataSource_instance *pdsi,
14                      void *magic,         /* ptr to pass back in getCountersFn() */
15                      getCountersFn_t getCountersFn)
16 {
17     /* copy the dsi in case it points to poller->dsi, which we are about to clear */
18     SFLDataSource_instance dsi = *pdsi;
19
20     /* preserve the *nxt pointer too, in case we are resetting this poller and it is
21        already part of the agent's linked list (thanks to Matt Woodly for pointing this out) */
22     SFLPoller *nxtPtr = poller->nxt;
23
24     /* clear everything */
25     memset(poller, 0, sizeof(*poller));
26
27     /* restore the linked list ptr */
28     poller->nxt = nxtPtr;
29
30     /* now copy in the parameters */
31     poller->agent = agent;
32     poller->dsi = dsi; /* structure copy */
33     poller->magic = magic;
34     poller->getCountersFn = getCountersFn;
35 }
36
37 /*_________________--------------------------__________________
38   _________________       reset              __________________
39   -----------------__________________________------------------
40 */
41
42 static void reset(SFLPoller *poller)
43 {
44     SFLDataSource_instance dsi = poller->dsi;
45     sfl_poller_init(poller, poller->agent, &dsi, poller->magic, poller->getCountersFn);
46 }
47
48 /*_________________---------------------------__________________
49   _________________      MIB access           __________________
50   -----------------___________________________------------------
51 */
52 u_int32_t sfl_poller_get_sFlowCpReceiver(SFLPoller *poller) {
53     return poller->sFlowCpReceiver;
54 }
55
56 void sfl_poller_set_sFlowCpReceiver(SFLPoller *poller, u_int32_t sFlowCpReceiver) {
57     poller->sFlowCpReceiver = sFlowCpReceiver;
58     if(sFlowCpReceiver == 0) reset(poller);
59     else {
60         /* retrieve and cache a direct pointer to my receiver */
61         poller->myReceiver = sfl_agent_getReceiver(poller->agent, poller->sFlowCpReceiver);
62     }
63 }
64
65 u_int32_t sfl_poller_get_sFlowCpInterval(SFLPoller *poller) {
66     return poller->sFlowCpInterval;
67 }
68
69 void sfl_poller_set_sFlowCpInterval(SFLPoller *poller, u_int32_t sFlowCpInterval) {
70     poller->sFlowCpInterval = sFlowCpInterval;
71     if(sFlowCpInterval) {
72         /* Set the countersCountdown to be a randomly selected value between 1 and
73            sFlowCpInterval. That way the counter polling will be desynchronised
74            (on a 200-port switch, polling all the counters in one second could be harmful).
75            In a large network, even this might not be ideal if time-synchroniziation
76            between devices is close and counters are always polled on second boundaries. If
77            1000 different devices all send an sFlow datagram on the same second boundary
78            it could result in an antisocial burst.
79            However when counter-samples are packed into the export datagram they do not
80            always result in that datagram being sent immediately. It is more likely that
81            a subsequent packet-sample will be the one that triggers the datagram to be sent.
82            The packet-sample events are not sychronized to any clock, so that results in
83            excellent desynchronization (http://blog.sflow.com/2009/05/measurement-traffic.html).
84            Another smoothing factor is that the tick() function called here is usually
85            driven from a fairly "soft" polling loop rather than a hard real-time event.
86         */
87         poller->countersCountdown = 1 + (random() % sFlowCpInterval);
88     }
89     else {
90         /* Setting sFlowCpInterval to 0 disables counter polling altogether.  Thanks to
91            Andy Kitchingman for spotting this ommission. */
92         poller->countersCountdown = 0;
93     }
94 }
95
96 /*_________________---------------------------------__________________
97   _________________          bridge port            __________________
98   -----------------_________________________________------------------
99   May need a separate number to reference the local bridge port
100   to get counters if it is not the same as the global ifIndex.
101 */
102
103 void sfl_poller_set_bridgePort(SFLPoller *poller, u_int32_t port_no) {
104     poller->bridgePort = port_no;
105 }
106
107 u_int32_t sfl_poller_get_bridgePort(SFLPoller *poller) {
108     return poller->bridgePort;
109 }
110
111 /*_________________---------------------------------__________________
112   _________________   sequence number reset         __________________
113   -----------------_________________________________------------------
114   Used to indicate a counter discontinuity
115   so that the sflow collector will know to ignore the next delta.
116 */
117 void sfl_poller_resetCountersSeqNo(SFLPoller *poller) {  poller->countersSampleSeqNo = 0; }
118
119 /*_________________---------------------------__________________
120   _________________    sfl_poller_tick        __________________
121   -----------------___________________________------------------
122 */
123
124 void sfl_poller_tick(SFLPoller *poller, time_t now)
125 {
126     if(poller->countersCountdown == 0) return; /* counters retrieval was not enabled */
127     if(poller->sFlowCpReceiver == 0) return;
128
129     if(--poller->countersCountdown == 0) {
130         if(poller->getCountersFn != NULL) {
131             /* call out for counters */
132             SFL_COUNTERS_SAMPLE_TYPE cs;
133             memset(&cs, 0, sizeof(cs));
134             poller->getCountersFn(poller->magic, poller, &cs);
135             /* this countersFn is expected to fill in some counter block elements
136                and then call sfl_poller_writeCountersSample(poller, &cs); */
137         }
138         /* reset the countdown */
139         poller->countersCountdown = poller->sFlowCpInterval;
140     }
141 }
142
143 /*_________________---------------------------------__________________
144   _________________ sfl_poller_writeCountersSample  __________________
145   -----------------_________________________________------------------
146 */
147
148 void sfl_poller_writeCountersSample(SFLPoller *poller, SFL_COUNTERS_SAMPLE_TYPE *cs)
149 {
150     /* fill in the rest of the header fields, and send to the receiver */
151     cs->sequence_number = ++poller->countersSampleSeqNo;
152 #ifdef SFL_USE_32BIT_INDEX
153     cs->ds_class = SFL_DS_CLASS(poller->dsi);
154     cs->ds_index = SFL_DS_INDEX(poller->dsi);
155 #else
156     cs->source_id = SFL_DS_DATASOURCE(poller->dsi);
157 #endif
158     /* sent to my receiver */
159     if(poller->myReceiver) sfl_receiver_writeCountersSample(poller->myReceiver, cs);
160 }
161