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