2 * vrrp_periodic.c - vrrp plug-in periodic function
4 * Copyright 2019-2020 Rubicon Communications, LLC (Netgate)
6 * SPDX-License-Identifier: Apache-2.0
10 #include <vlib/vlib.h>
11 #include <vppinfra/error.h>
12 #include <vrrp/vrrp.h>
13 #include <vrrp/vrrp_packet.h>
16 vrrp_vr_timer_compare (const void *v1, const void *v2)
18 vrrp_main_t *vmp = &vrrp_main;
19 const u32 *idx1, *idx2;
20 vrrp_vr_timer_t *timer1, *timer2;
25 timer1 = pool_elt_at_index (vmp->vr_timers, *idx1);
26 timer2 = pool_elt_at_index (vmp->vr_timers, *idx2);
28 /* don't check equality, they are unlikely to be exactly equal and
29 * if it occurs, it won't matter what order they were in.
30 * sort the list in reverse so we can pick the next timer off the end */
31 if (timer1->expire_time > timer2->expire_time)
38 vrrp_vr_timer_get_next (void)
40 vrrp_main_t *vmp = &vrrp_main;
43 n_timers = vec_len (vmp->pending_timers);
48 return vec_elt (vmp->pending_timers, n_timers - 1);
51 /* cancel an existing timer. This could happen because:
52 * - adv timer expired on master. another adv should be scheduled.
53 * - a shutdown event is received
54 * - a master is preempted by a higher priority master
55 * - adv received on backup. master down timer should be rescheduled.
58 vrrp_vr_timer_cancel (vrrp_vr_t * vr)
60 vrrp_main_t *vmp = &vrrp_main;
63 /* don't search for a timer that was already canceled or never set */
64 if (vr->runtime.timer_index == ~0)
67 /* timers stored in descending order, start at the end of the list */
68 /* vec_foreach_backwards does not deal with 0 pointers, check first */
69 if (vmp->pending_timers)
70 vec_foreach_backwards (t, vmp->pending_timers)
72 if (*t == vr->runtime.timer_index)
74 vec_delete (vmp->pending_timers, 1, t - vmp->pending_timers);
79 if (!pool_is_free_index (vmp->vr_timers, vr->runtime.timer_index))
80 pool_put_index (vmp->vr_timers, vr->runtime.timer_index);
82 vr->runtime.timer_index = ~0;
84 vlib_process_signal_event (vmp->vlib_main, vrrp_periodic_node.index,
85 VRRP_EVENT_VR_TIMER_UPDATE, 0);
89 vrrp_vr_timer_set (vrrp_vr_t * vr, vrrp_vr_timer_type_t type)
91 vrrp_main_t *vmp = &vrrp_main;
92 vlib_main_t *vm = vlib_get_main ();
93 vrrp_vr_timer_t *timer;
96 /* Each VR should be waiting on at most 1 timer at any given time.
97 * If there is already a timer set for this VR, cancel it.
99 if (vr->runtime.timer_index != ~0)
100 vrrp_vr_timer_cancel (vr);
102 pool_get (vmp->vr_timers, timer);
103 vr->runtime.timer_index = timer - vmp->vr_timers;
105 timer->vr_index = vr - vmp->vrs;
108 now = vlib_time_now (vm);
110 /* RFC 5798 specifies that timers are in centiseconds, so x / 100.0 */
113 case VRRP_VR_TIMER_ADV:
114 timer->expire_time = now + (vr->config.adv_interval / 100.0);
116 case VRRP_VR_TIMER_MASTER_DOWN:
117 timer->expire_time = now + (vr->runtime.master_down_int / 100.0);
120 /* should never reach here */
121 clib_warning ("Unrecognized VRRP timer type (%d)", type);
125 vec_add1 (vmp->pending_timers, vr->runtime.timer_index);
127 vec_sort_with_function (vmp->pending_timers, vrrp_vr_timer_compare);
129 vlib_process_signal_event (vmp->vlib_main, vrrp_periodic_node.index,
130 VRRP_EVENT_VR_TIMER_UPDATE, 0);
134 vrrp_vr_timer_timeout (u32 timer_index)
136 vrrp_main_t *vmp = &vrrp_main;
137 vrrp_vr_timer_t *timer;
140 if (pool_is_free_index (vmp->vr_timers, timer_index))
142 clib_warning ("Timeout on free timer index %u", timer_index);
146 timer = pool_elt_at_index (vmp->vr_timers, timer_index);
147 vr = pool_elt_at_index (vmp->vrs, timer->vr_index);
151 case VRRP_VR_TIMER_ADV:
152 vrrp_adv_send (vr, 0);
153 vrrp_vr_timer_set (vr, VRRP_VR_TIMER_ADV);
155 case VRRP_VR_TIMER_MASTER_DOWN:
156 vrrp_vr_transition (vr, VRRP_VR_STATE_MASTER, NULL);
159 clib_warning ("Unrecognized timer type %d", timer->type);
166 vrrp_periodic_process (vlib_main_t * vm,
167 vlib_node_runtime_t * rt, vlib_frame_t * f)
169 vrrp_main_t *pm = &vrrp_main;
172 uword *event_data = 0;
175 vrrp_vr_timer_t *timer;
179 now = vlib_time_now (vm);
181 if (next_timer == ~0)
183 vlib_process_wait_for_event (vm);
187 timer = pool_elt_at_index (pm->vr_timers, next_timer);
188 timeout = timer->expire_time - now;
190 vlib_process_wait_for_event_or_clock (vm, timeout);
193 event_type = vlib_process_get_events (vm, (uword **) & event_data);
197 /* Handle VRRP_EVENT_VR_TIMER_UPDATE */
198 case VRRP_EVENT_VR_TIMER_UPDATE:
199 next_timer = vrrp_vr_timer_get_next ();
202 /* Handle periodic timeouts */
204 vrrp_vr_timer_timeout (next_timer);
205 next_timer = vrrp_vr_timer_get_next ();
208 vec_reset_length (event_data);
213 VLIB_REGISTER_NODE (vrrp_periodic_node) = {
214 .function = vrrp_periodic_process,
215 .type = VLIB_NODE_TYPE_PROCESS,
216 .name = "vrrp-periodic-process",
217 .process_log2_n_stack_bytes = 17,
221 * fd.io coding-style-patch-verification: ON
224 * eval: (c-set-style "gnu")