Line data Source code
1 : /*
2 : *------------------------------------------------------------------
3 : * Copyright (c) 2017 Cisco and/or its affiliates.
4 : * Licensed under the Apache License, Version 2.0 (the "License");
5 : * you may not use this file except in compliance with the License.
6 : * You may obtain a copy of the License at:
7 : *
8 : * http://www.apache.org/licenses/LICENSE-2.0
9 : *
10 : * Unless required by applicable law or agreed to in writing, software
11 : * distributed under the License is distributed on an "AS IS" BASIS,
12 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 : * See the License for the specific language governing permissions and
14 : * limitations under the License.
15 : *------------------------------------------------------------------
16 : */
17 :
18 : #include <igmp/igmp_timer.h>
19 : #include <igmp/igmp.h>
20 :
21 : /**
22 : * Default timer values as per RFC
23 : */
24 :
25 : static igmp_timer_type_t igmp_default_timer_values[] = {
26 : [IGMP_TIMER_QUERY] = 60,
27 : [IGMP_TIMER_SRC] = (3 * 60),
28 : [IGMP_TIMER_LEAVE] = 60,
29 : [IGMP_TIMER_REPORT_INTERVAL] = 1,
30 : };
31 :
32 : #define IGMP_N_TIMERS (IGMP_TIMER_REPORT_INTERVAL+1)
33 :
34 : /**
35 : * Timer
36 : */
37 : typedef struct igmp_timer_t_
38 : {
39 : /** Expiration timer */
40 : f64 exp_time;
41 :
42 : /** Call-back function to invoke on expiry */
43 : igmp_timer_function_t func;
44 :
45 : /** index of the object that scheduled the timer */
46 : u32 obj;
47 :
48 : /** Data registered by the client and passed back when the timer expires */
49 : void *data;
50 : } igmp_timer_t;
51 :
52 : enum
53 : {
54 : IGMP_PROCESS_EVENT_UPDATE_TIMER = 1,
55 : } igmp_process_event_t;
56 :
57 : /**
58 : * pool of timers
59 : */
60 : static igmp_timer_t *timer_pool;
61 :
62 : /**
63 : * Vector of pending timers
64 : */
65 : static u32 *pending_timers;
66 :
67 : u32
68 46 : igmp_timer_type_get (igmp_timer_type_t t)
69 : {
70 46 : ASSERT (t < IGMP_N_TIMERS);
71 46 : return (igmp_default_timer_values[t]);
72 : }
73 :
74 : void
75 6 : igmp_timer_type_set (igmp_timer_type_t t, u32 v)
76 : {
77 6 : ASSERT (t < IGMP_N_TIMERS);
78 6 : igmp_default_timer_values[t] = v;
79 6 : }
80 :
81 :
82 : static int
83 85 : igmp_timer_compare (const void *_v1, const void *_v2)
84 : {
85 85 : const u32 *i1 = _v1, *i2 = _v2;
86 : const igmp_timer_t *t1, *t2;
87 : f64 dt;
88 :
89 85 : t1 = pool_elt_at_index (timer_pool, *i1);
90 85 : t2 = pool_elt_at_index (timer_pool, *i2);
91 :
92 85 : dt = t2->exp_time - t1->exp_time;
93 :
94 85 : return (dt < 0 ? -1 : (dt > 0 ? +1 : 0));
95 : }
96 :
97 : /** \brief igmp get next timer
98 :
99 : Get next timer.
100 : */
101 : u32
102 127 : igmp_get_next_timer (void)
103 : {
104 127 : if (0 == vec_len (pending_timers))
105 44 : return (IGMP_TIMER_ID_INVALID);
106 :
107 83 : return (pending_timers[vec_len (pending_timers) - 1]);
108 : }
109 :
110 : void *
111 2 : igmp_timer_get_data (igmp_timer_id_t tid)
112 : {
113 : igmp_timer_t *timer;
114 :
115 2 : timer = pool_elt_at_index (timer_pool, tid);
116 :
117 2 : return (timer->data);
118 : }
119 :
120 : void
121 2 : igmp_timer_set_data (igmp_timer_id_t tid, void *data)
122 : {
123 : igmp_timer_t *timer;
124 :
125 2 : timer = pool_elt_at_index (timer_pool, tid);
126 :
127 2 : timer->data = data;
128 2 : }
129 :
130 : int
131 0 : igmp_timer_is_running (igmp_timer_id_t tid)
132 : {
133 0 : return (IGMP_TIMER_ID_INVALID == tid);
134 : }
135 :
136 : /** \brief igmp timer process
137 : @param vm - vlib main
138 : @param rt - vlib runtime node
139 : @param f - vlib frame
140 :
141 : Handle igmp timers.
142 : */
143 : static uword
144 575 : igmp_timer_process (vlib_main_t * vm, vlib_node_runtime_t * rt,
145 : vlib_frame_t * f)
146 : {
147 575 : uword *event_data = 0, event_type;
148 : igmp_timer_id_t tid;
149 : igmp_timer_t *timer;
150 :
151 575 : tid = IGMP_TIMER_ID_INVALID;
152 :
153 : while (1)
154 : {
155 : /* suspend util timer expires */
156 702 : if (IGMP_TIMER_ID_INVALID != tid)
157 : {
158 83 : timer = pool_elt_at_index (timer_pool, tid);
159 83 : vlib_process_wait_for_event_or_clock
160 83 : (vm, timer->exp_time - vlib_time_now (vm));
161 : }
162 : else
163 619 : vlib_process_wait_for_event (vm);
164 :
165 127 : event_type = vlib_process_get_events (vm, &event_data);
166 127 : vec_reset_length (event_data);
167 :
168 127 : if (event_type == IGMP_PROCESS_EVENT_UPDATE_TIMER)
169 83 : goto next_timer;
170 :
171 : /* timer expired */
172 44 : ASSERT (tid != IGMP_TIMER_ID_INVALID);
173 :
174 44 : timer = pool_elt_at_index (timer_pool, tid);
175 44 : ASSERT (timer->func != NULL);
176 44 : timer->func (timer->obj, timer->data);
177 :
178 127 : next_timer:
179 127 : tid = igmp_get_next_timer ();
180 : }
181 : return 0;
182 : }
183 :
184 : /* *INDENT-OFF* */
185 128492 : VLIB_REGISTER_NODE (igmp_timer_process_node) =
186 : {
187 : .function = igmp_timer_process,
188 : .type = VLIB_NODE_TYPE_PROCESS,
189 : .name = "igmp-timer-process",
190 : .n_next_nodes = 0,
191 : };
192 : /* *INDENT-ON* */
193 :
194 : igmp_timer_id_t
195 57 : igmp_timer_schedule (f64 when, u32 obj, igmp_timer_function_t fn, void *data)
196 : {
197 : igmp_timer_t *timer;
198 : vlib_main_t *vm;
199 :
200 57 : ASSERT (fn);
201 :
202 57 : vm = vlib_get_main ();
203 57 : pool_get (timer_pool, timer);
204 :
205 57 : timer->exp_time = vlib_time_now (vm) + when;
206 57 : timer->obj = obj;
207 57 : timer->func = fn;
208 57 : timer->data = data;
209 :
210 57 : vec_add1 (pending_timers, timer - timer_pool);
211 :
212 57 : vec_sort_with_function (pending_timers, igmp_timer_compare);
213 :
214 57 : vlib_process_signal_event (vm, igmp_timer_process_node.index,
215 : IGMP_PROCESS_EVENT_UPDATE_TIMER, 0);
216 :
217 57 : return (timer - timer_pool);
218 : }
219 :
220 : void
221 600 : igmp_timer_retire (igmp_timer_id_t * tid)
222 : {
223 600 : if (IGMP_TIMER_ID_INVALID == *tid)
224 543 : return;
225 109 : vec_del1 (pending_timers, vec_search (pending_timers, *tid));
226 57 : pool_put_index (timer_pool, *tid);
227 57 : *tid = IGMP_TIMER_ID_INVALID;
228 :
229 57 : vlib_process_signal_event (vlib_get_main (),
230 57 : igmp_timer_process_node.index,
231 : IGMP_PROCESS_EVENT_UPDATE_TIMER, 0);
232 : }
233 :
234 : u8 *
235 2 : format_igmp_timer_id (u8 * s, va_list * args)
236 : {
237 2 : igmp_timer_id_t tid = va_arg (*args, igmp_timer_id_t);
238 : igmp_timer_t *timer;
239 :
240 2 : if (IGMP_TIMER_ID_INVALID == tid)
241 : {
242 2 : s = format (s, "not-running");
243 : }
244 : else
245 : {
246 0 : timer = pool_elt_at_index (timer_pool, tid);
247 :
248 : s =
249 0 : format (s, "[expires-in:%f]",
250 0 : timer->exp_time - vlib_time_now (vlib_get_main ()));
251 : }
252 :
253 2 : return (s);
254 : }
255 :
256 : /*
257 : * fd.io coding-style-patch-verification: ON
258 : *
259 : * Local Variables:
260 : * eval: (c-set-style "gnu")
261 : * End:
262 : */
|