c2b4556cf6ee505ce242781abab64a05be6420a6
[sliver-openvswitch.git] / lib / sflow_sampler.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 /*_________________--------------------------__________________
8   _________________   sfl_sampler_init       __________________
9   -----------------__________________________------------------
10 */
11
12 void sfl_sampler_init(SFLSampler *sampler, SFLAgent *agent, SFLDataSource_instance *pdsi)
13 {
14     /* copy the dsi in case it points to sampler->dsi, which we are about to clear.
15        (Thanks to Jagjit Choudray of Force 10 Networks for pointing out this bug) */
16     SFLDataSource_instance dsi = *pdsi;
17
18     /* preserve the *nxt pointer too, in case we are resetting this poller and it is
19        already part of the agent's linked list (thanks to Matt Woodly for pointing this out,
20        and to Andy Kitchingman for pointing out that it applies to the hash_nxt ptr too) */
21     SFLSampler *nxtPtr = sampler->nxt;
22     SFLSampler *hashPtr = sampler->hash_nxt;
23   
24     /* clear everything */
25     memset(sampler, 0, sizeof(*sampler));
26   
27     /* restore the linked list and hash-table ptr */
28     sampler->nxt = nxtPtr;
29     sampler->hash_nxt = hashPtr;
30   
31     /* now copy in the parameters */
32     sampler->agent = agent;
33     sampler->dsi = dsi;
34   
35     /* set defaults */
36     sampler->sFlowFsMaximumHeaderSize = SFL_DEFAULT_HEADER_SIZE;
37     sampler->sFlowFsPacketSamplingRate = SFL_DEFAULT_SAMPLING_RATE;
38 }
39
40 /*_________________--------------------------__________________
41   _________________       reset              __________________
42   -----------------__________________________------------------
43 */
44
45 static void reset(SFLSampler *sampler)
46 {
47     SFLDataSource_instance dsi = sampler->dsi;
48     sfl_sampler_init(sampler, sampler->agent, &dsi);
49 }
50
51 /*_________________---------------------------__________________
52   _________________      MIB access           __________________
53   -----------------___________________________------------------
54 */
55 u_int32_t sfl_sampler_get_sFlowFsReceiver(SFLSampler *sampler) {
56     return sampler->sFlowFsReceiver;
57 }
58 void sfl_sampler_set_sFlowFsReceiver(SFLSampler *sampler, u_int32_t sFlowFsReceiver) {
59     sampler->sFlowFsReceiver = sFlowFsReceiver;
60     if(sFlowFsReceiver == 0) reset(sampler);
61     else {
62         /* retrieve and cache a direct pointer to my receiver */
63         sampler->myReceiver = sfl_agent_getReceiver(sampler->agent, sampler->sFlowFsReceiver);
64     }
65 }
66 u_int32_t sfl_sampler_get_sFlowFsPacketSamplingRate(SFLSampler *sampler) {
67     return sampler->sFlowFsPacketSamplingRate;
68 }
69 void sfl_sampler_set_sFlowFsPacketSamplingRate(SFLSampler *sampler, u_int32_t sFlowFsPacketSamplingRate) {
70     sampler->sFlowFsPacketSamplingRate = sFlowFsPacketSamplingRate;
71 }
72 u_int32_t sfl_sampler_get_sFlowFsMaximumHeaderSize(SFLSampler *sampler) {
73     return sampler->sFlowFsMaximumHeaderSize;
74 }
75 void sfl_sampler_set_sFlowFsMaximumHeaderSize(SFLSampler *sampler, u_int32_t sFlowFsMaximumHeaderSize) {
76     sampler->sFlowFsMaximumHeaderSize = sFlowFsMaximumHeaderSize;
77 }
78
79 /* call this to set a maximum samples-per-second threshold. If the sampler reaches this
80    threshold it will automatically back off the sampling rate. A value of 0 disables the
81    mechanism */
82 void sfl_sampler_set_backoffThreshold(SFLSampler *sampler, u_int32_t samplesPerSecond) {
83     sampler->backoffThreshold = samplesPerSecond;
84 }
85 u_int32_t sfl_sampler_get_backoffThreshold(SFLSampler *sampler) {
86     return sampler->backoffThreshold;
87 }
88 u_int32_t sfl_sampler_get_samplesLastTick(SFLSampler *sampler) {
89     return sampler->samplesLastTick;
90 }
91
92 /*_________________---------------------------------__________________
93   _________________   sequence number reset         __________________
94   -----------------_________________________________------------------
95   Used by the agent to indicate a samplePool discontinuity
96   so that the sflow collector will know to ignore the next delta.
97 */
98 void sfl_sampler_resetFlowSeqNo(SFLSampler *sampler) { sampler->flowSampleSeqNo = 0; }
99
100
101 /*_________________---------------------------__________________
102   _________________    sfl_sampler_tick       __________________
103   -----------------___________________________------------------
104 */
105
106 void sfl_sampler_tick(SFLSampler *sampler, time_t now)
107 {
108     if(sampler->backoffThreshold && sampler->samplesThisTick > sampler->backoffThreshold) {
109         /* automatic backoff.  If using hardware sampling then this is where you have to
110          * call out to change the sampling rate and make sure that any other registers/variables
111          * that hold this value are updated.
112          */
113         sampler->sFlowFsPacketSamplingRate *= 2;
114     }
115     sampler->samplesLastTick = sampler->samplesThisTick;
116     sampler->samplesThisTick = 0;
117 }
118
119
120
121 /*_________________------------------------------__________________
122   _________________ sfl_sampler_writeFlowSample  __________________
123   -----------------______________________________------------------
124 */
125
126 void sfl_sampler_writeFlowSample(SFLSampler *sampler, SFL_FLOW_SAMPLE_TYPE *fs)
127 {
128     if(fs == NULL) return;
129     sampler->samplesThisTick++;
130     /* increment the sequence number */
131     fs->sequence_number = ++sampler->flowSampleSeqNo;
132     /* copy the other header fields in */
133 #ifdef SFL_USE_32BIT_INDEX
134     fs->ds_class = SFL_DS_CLASS(sampler->dsi);
135     fs->ds_index = SFL_DS_INDEX(sampler->dsi);
136 #else
137     fs->source_id = SFL_DS_DATASOURCE(sampler->dsi);
138 #endif
139     /* the sampling rate may have been set already. */
140     if(fs->sampling_rate == 0) fs->sampling_rate = sampler->sFlowFsPacketSamplingRate;
141     /* the samplePool may be maintained upstream too. */
142     if( fs->sample_pool == 0) fs->sample_pool = sampler->samplePool;
143     /* sent to my receiver */
144     if(sampler->myReceiver) sfl_receiver_writeFlowSample(sampler->myReceiver, fs);
145 }
146
147 #ifdef SFLOW_SOFTWARE_SAMPLING
148
149 /* ================== software sampling ========================*/
150
151 /*_________________---------------------------__________________
152   _________________     nextRandomSkip        __________________
153   -----------------___________________________------------------
154 */
155
156 inline static u_int32_t nextRandomSkip(u_int32_t mean)
157 {
158     if(mean == 0 || mean == 1) return 1;
159     return ((random() % ((2 * mean) - 1)) + 1);
160
161
162 /*_________________---------------------------__________________
163   _________________  sfl_sampler_takeSample   __________________
164   -----------------___________________________------------------
165 */
166
167 int sfl_sampler_takeSample(SFLSampler *sampler)
168 {
169     if(sampler->skip == 0) {
170         /* first time - seed the random number generator */
171         srandom(SFL_DS_INDEX(sampler->dsi));
172         sampler->skip = nextRandomSkip(sampler->sFlowFsPacketSamplingRate);
173     }
174
175     /* increment the samplePool */
176     sampler->samplePool++;
177
178     if(--sampler->skip == 0) {
179         /* reached zero. Set the next skip and return true. */
180         sampler->skip = nextRandomSkip(sampler->sFlowFsPacketSamplingRate);
181         return 1;
182     }
183     return 0;
184 }
185
186 #endif /* SFLOW_SOFTWARE_SAMPLING */