summaryrefslogtreecommitdiffstats
path: root/src/plugins/igmp/igmp_timer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/igmp/igmp_timer.c')
-rw-r--r--src/plugins/igmp/igmp_timer.c241
1 files changed, 241 insertions, 0 deletions
diff --git a/src/plugins/igmp/igmp_timer.c b/src/plugins/igmp/igmp_timer.c
new file mode 100644
index 00000000000..278b7db917e
--- /dev/null
+++ b/src/plugins/igmp/igmp_timer.c
@@ -0,0 +1,241 @@
+/*
+ *------------------------------------------------------------------
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#include <igmp/igmp_timer.h>
+#include <igmp/igmp.h>
+
+/**
+ * Default timer values as per RFC
+ */
+
+static igmp_timer_type_t igmp_default_timer_values[] = {
+ [IGMP_TIMER_QUERY] = 60,
+ [IGMP_TIMER_SRC] = (3 * 60),
+ [IGMP_TIMER_LEAVE] = 60,
+ [IGMP_TIMER_REPORT_INTERVAL] = 1,
+};
+
+#define IGMP_N_TIMERS (IGMP_TIMER_REPORT_INTERVAL+1)
+
+/**
+ * Timer
+ */
+typedef struct igmp_timer_t_
+{
+ /** Expiration timer */
+ f64 exp_time;
+
+ /** Call-back function to invoke on expiry */
+ igmp_timer_function_t func;
+
+ /** index of the object that scheduled the timer */
+ u32 obj;
+
+ /** Data registered by the client and passed back when the timer expires */
+ void *data;
+} igmp_timer_t;
+
+enum
+{
+ IGMP_PROCESS_EVENT_UPDATE_TIMER = 1,
+} igmp_process_event_t;
+
+/**
+ * pool of timers
+ */
+static igmp_timer_t *timer_pool;
+
+/**
+ * Vector of pending timers
+ */
+static u32 *pending_timers;
+
+u32
+igmp_timer_type_get (igmp_timer_type_t t)
+{
+ ASSERT (t < IGMP_N_TIMERS);
+ return (igmp_default_timer_values[t]);
+}
+
+void
+igmp_timer_type_set (igmp_timer_type_t t, u32 v)
+{
+ ASSERT (t < IGMP_N_TIMERS);
+ igmp_default_timer_values[t] = v;
+}
+
+
+static int
+igmp_timer_compare (const void *_v1, const void *_v2)
+{
+ const u32 *i1 = _v1, *i2 = _v2;
+ const igmp_timer_t *t1, *t2;
+ f64 dt;
+
+ t1 = pool_elt_at_index (timer_pool, *i1);
+ t2 = pool_elt_at_index (timer_pool, *i2);
+
+ dt = t2->exp_time - t1->exp_time;
+
+ return (dt < 0 ? -1 : (dt > 0 ? +1 : 0));
+}
+
+/** \brief igmp get next timer
+ @param im - igmp main
+
+ Get next timer.
+*/
+u32
+igmp_get_next_timer (void)
+{
+ if (0 == vec_len (pending_timers))
+ return (IGMP_TIMER_ID_INVALID);
+
+ return (pending_timers[vec_len (pending_timers) - 1]);
+}
+
+void *
+igmp_timer_get_data (igmp_timer_id_t tid)
+{
+ igmp_timer_t *timer;
+
+ timer = pool_elt_at_index (timer_pool, tid);
+
+ return (timer->data);
+}
+
+void
+igmp_timer_set_data (igmp_timer_id_t tid, void *data)
+{
+ igmp_timer_t *timer;
+
+ timer = pool_elt_at_index (timer_pool, tid);
+
+ timer->data = data;
+}
+
+int
+igmp_timer_is_running (igmp_timer_id_t tid)
+{
+ return (IGMP_TIMER_ID_INVALID == tid);
+}
+
+/** \brief igmp timer process
+ @param vm - vlib main
+ @param rt - vlib runtime node
+ @param f - vlib frame
+
+ Handle igmp timers.
+*/
+static uword
+igmp_timer_process (vlib_main_t * vm, vlib_node_runtime_t * rt,
+ vlib_frame_t * f)
+{
+ uword *event_data = 0, event_type;
+ igmp_timer_id_t tid;
+ igmp_timer_t *timer;
+
+ tid = IGMP_TIMER_ID_INVALID;
+
+ while (1)
+ {
+ /* suspend util timer expires */
+ if (IGMP_TIMER_ID_INVALID != tid)
+ {
+ timer = pool_elt_at_index (timer_pool, tid);
+ vlib_process_wait_for_event_or_clock
+ (vm, timer->exp_time - vlib_time_now (vm));
+ }
+ else
+ vlib_process_wait_for_event (vm);
+
+ event_type = vlib_process_get_events (vm, &event_data);
+ vec_reset_length (event_data);
+
+ if (event_type == IGMP_PROCESS_EVENT_UPDATE_TIMER)
+ goto next_timer;
+
+ /* timer expired */
+ ASSERT (tid != IGMP_TIMER_ID_INVALID);
+
+ timer = pool_elt_at_index (timer_pool, tid);
+ ASSERT (timer->func != NULL);
+ timer->func (timer->obj, timer->data);
+
+ next_timer:
+ tid = igmp_get_next_timer ();
+ }
+ return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (igmp_timer_process_node) =
+{
+ .function = igmp_timer_process,
+ .type = VLIB_NODE_TYPE_PROCESS,
+ .name = "igmp-timer-process",
+ .n_next_nodes = 0,
+};
+/* *INDENT-ON* */
+
+igmp_timer_id_t
+igmp_timer_schedule (f64 when, u32 obj, igmp_timer_function_t fn, void *data)
+{
+ igmp_timer_t *timer;
+ vlib_main_t *vm;
+
+ ASSERT (fn);
+
+ vm = vlib_get_main ();
+ pool_get (timer_pool, timer);
+
+ timer->exp_time = vlib_time_now (vm) + when;
+ timer->obj = obj;
+ timer->func = fn;
+ timer->data = data;
+
+ vec_add1 (pending_timers, timer - timer_pool);
+
+ vec_sort_with_function (pending_timers, igmp_timer_compare);
+
+ vlib_process_signal_event (vm, igmp_timer_process_node.index,
+ IGMP_PROCESS_EVENT_UPDATE_TIMER, 0);
+
+ return (timer - timer_pool);
+}
+
+void
+igmp_timer_retire (igmp_timer_id_t * tid)
+{
+ if (IGMP_TIMER_ID_INVALID == *tid)
+ return;
+ vec_del1 (pending_timers, vec_search (pending_timers, *tid));
+ pool_put_index (timer_pool, *tid);
+ *tid = IGMP_TIMER_ID_INVALID;
+
+ vlib_process_signal_event (vlib_get_main (),
+ igmp_timer_process_node.index,
+ IGMP_PROCESS_EVENT_UPDATE_TIMER, 0);
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */