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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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 *------------------------------------------------------------------
18 #include <igmp/igmp_timer.h>
19 #include <igmp/igmp.h>
22 * Default timer values as per RFC
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,
32 #define IGMP_N_TIMERS (IGMP_TIMER_REPORT_INTERVAL+1)
37 typedef struct igmp_timer_t_
39 /** Expiration timer */
42 /** Call-back function to invoke on expiry */
43 igmp_timer_function_t func;
45 /** index of the object that scheduled the timer */
48 /** Data registered by the client and passed back when the timer expires */
54 IGMP_PROCESS_EVENT_UPDATE_TIMER = 1,
55 } igmp_process_event_t;
60 static igmp_timer_t *timer_pool;
63 * Vector of pending timers
65 static u32 *pending_timers;
68 igmp_timer_type_get (igmp_timer_type_t t)
70 ASSERT (t < IGMP_N_TIMERS);
71 return (igmp_default_timer_values[t]);
75 igmp_timer_type_set (igmp_timer_type_t t, u32 v)
77 ASSERT (t < IGMP_N_TIMERS);
78 igmp_default_timer_values[t] = v;
83 igmp_timer_compare (const void *_v1, const void *_v2)
85 const u32 *i1 = _v1, *i2 = _v2;
86 const igmp_timer_t *t1, *t2;
89 t1 = pool_elt_at_index (timer_pool, *i1);
90 t2 = pool_elt_at_index (timer_pool, *i2);
92 dt = t2->exp_time - t1->exp_time;
94 return (dt < 0 ? -1 : (dt > 0 ? +1 : 0));
97 /** \brief igmp get next timer
102 igmp_get_next_timer (void)
104 if (0 == vec_len (pending_timers))
105 return (IGMP_TIMER_ID_INVALID);
107 return (pending_timers[vec_len (pending_timers) - 1]);
111 igmp_timer_get_data (igmp_timer_id_t tid)
115 timer = pool_elt_at_index (timer_pool, tid);
117 return (timer->data);
121 igmp_timer_set_data (igmp_timer_id_t tid, void *data)
125 timer = pool_elt_at_index (timer_pool, tid);
131 igmp_timer_is_running (igmp_timer_id_t tid)
133 return (IGMP_TIMER_ID_INVALID == tid);
136 /** \brief igmp timer process
137 @param vm - vlib main
138 @param rt - vlib runtime node
139 @param f - vlib frame
144 igmp_timer_process (vlib_main_t * vm, vlib_node_runtime_t * rt,
147 uword *event_data = 0, event_type;
151 tid = IGMP_TIMER_ID_INVALID;
155 /* suspend util timer expires */
156 if (IGMP_TIMER_ID_INVALID != tid)
158 timer = pool_elt_at_index (timer_pool, tid);
159 vlib_process_wait_for_event_or_clock
160 (vm, timer->exp_time - vlib_time_now (vm));
163 vlib_process_wait_for_event (vm);
165 event_type = vlib_process_get_events (vm, &event_data);
166 vec_reset_length (event_data);
168 if (event_type == IGMP_PROCESS_EVENT_UPDATE_TIMER)
172 ASSERT (tid != IGMP_TIMER_ID_INVALID);
174 timer = pool_elt_at_index (timer_pool, tid);
175 ASSERT (timer->func != NULL);
176 timer->func (timer->obj, timer->data);
179 tid = igmp_get_next_timer ();
184 VLIB_REGISTER_NODE (igmp_timer_process_node) =
186 .function = igmp_timer_process,
187 .type = VLIB_NODE_TYPE_PROCESS,
188 .name = "igmp-timer-process",
193 igmp_timer_schedule (f64 when, u32 obj, igmp_timer_function_t fn, void *data)
200 vm = vlib_get_main ();
201 pool_get (timer_pool, timer);
203 timer->exp_time = vlib_time_now (vm) + when;
208 vec_add1 (pending_timers, timer - timer_pool);
210 vec_sort_with_function (pending_timers, igmp_timer_compare);
212 vlib_process_signal_event (vm, igmp_timer_process_node.index,
213 IGMP_PROCESS_EVENT_UPDATE_TIMER, 0);
215 return (timer - timer_pool);
219 igmp_timer_retire (igmp_timer_id_t * tid)
221 if (IGMP_TIMER_ID_INVALID == *tid)
223 vec_del1 (pending_timers, vec_search (pending_timers, *tid));
224 pool_put_index (timer_pool, *tid);
225 *tid = IGMP_TIMER_ID_INVALID;
227 vlib_process_signal_event (vlib_get_main (),
228 igmp_timer_process_node.index,
229 IGMP_PROCESS_EVENT_UPDATE_TIMER, 0);
233 format_igmp_timer_id (u8 * s, va_list * args)
235 igmp_timer_id_t tid = va_arg (*args, igmp_timer_id_t);
238 if (IGMP_TIMER_ID_INVALID == tid)
240 s = format (s, "not-running");
244 timer = pool_elt_at_index (timer_pool, tid);
247 format (s, "[expires-in:%f]",
248 timer->exp_time - vlib_time_now (vlib_get_main ()));
255 * fd.io coding-style-patch-verification: ON
258 * eval: (c-set-style "gnu")