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