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