Merge "sflow" into "master".
[openvswitch] / 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     /* Set the countersCountdown to be a randomly selected value between 1 and
72        sFlowCpInterval. That way the counter polling would be desynchronised
73        (on a 200-port switch, polling all the counters in one second could be harmful). */
74     poller->countersCountdown = 1 + (random() % sFlowCpInterval);
75 }
76
77 /*_________________---------------------------------__________________
78   _________________          bridge port            __________________
79   -----------------_________________________________------------------
80   May need a separate number to reference the local bridge port
81   to get counters if it is not the same as the global ifIndex.
82 */
83
84 void sfl_poller_set_bridgePort(SFLPoller *poller, u_int32_t port_no) {
85     poller->bridgePort = port_no;
86 }
87
88 u_int32_t sfl_poller_get_bridgePort(SFLPoller *poller) {
89     return poller->bridgePort;
90 }
91
92 /*_________________---------------------------------__________________
93   _________________   sequence number reset         __________________
94   -----------------_________________________________------------------
95   Used to indicate a counter discontinuity
96   so that the sflow collector will know to ignore the next delta.
97 */
98 void sfl_poller_resetCountersSeqNo(SFLPoller *poller) {  poller->countersSampleSeqNo = 0; }
99
100 /*_________________---------------------------__________________
101   _________________    sfl_poller_tick        __________________
102   -----------------___________________________------------------
103 */
104
105 void sfl_poller_tick(SFLPoller *poller, time_t now)
106 {
107     if(poller->countersCountdown == 0) return; /* counters retrieval was not enabled */
108     if(poller->sFlowCpReceiver == 0) return;
109
110     if(--poller->countersCountdown == 0) {
111         if(poller->getCountersFn != NULL) {
112             /* call out for counters */
113             SFL_COUNTERS_SAMPLE_TYPE cs;
114             memset(&cs, 0, sizeof(cs));
115             poller->getCountersFn(poller->magic, poller, &cs);
116             /* this countersFn is expected to fill in some counter block elements
117                and then call sfl_poller_writeCountersSample(poller, &cs); */
118         }
119         /* reset the countdown */
120         poller->countersCountdown = poller->sFlowCpInterval;
121     }
122 }
123
124 /*_________________---------------------------------__________________
125   _________________ sfl_poller_writeCountersSample  __________________
126   -----------------_________________________________------------------
127 */
128
129 void sfl_poller_writeCountersSample(SFLPoller *poller, SFL_COUNTERS_SAMPLE_TYPE *cs)
130 {
131     /* fill in the rest of the header fields, and send to the receiver */
132     cs->sequence_number = ++poller->countersSampleSeqNo;
133 #ifdef SFL_USE_32BIT_INDEX
134     cs->ds_class = SFL_DS_CLASS(poller->dsi);
135     cs->ds_index = SFL_DS_INDEX(poller->dsi);
136 #else
137     cs->source_id = SFL_DS_DATASOURCE(poller->dsi);
138 #endif
139     /* sent to my receiver */
140     if(poller->myReceiver) sfl_receiver_writeCountersSample(poller->myReceiver, cs);
141 }
142