LCOV - code coverage report
Current view: top level - plugins/vrrp - vrrp_periodic.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 53 91 58.2 %
Date: 2023-10-26 01:39:38 Functions: 6 8 75.0 %

          Line data    Source code
       1             : /*
       2             :  * vrrp_periodic.c - vrrp plug-in periodic function
       3             :  *
       4             :  * Copyright 2019-2020 Rubicon Communications, LLC (Netgate)
       5             :  *
       6             :  * SPDX-License-Identifier: Apache-2.0
       7             :  *
       8             :  */
       9             : 
      10             : #include <vlib/vlib.h>
      11             : #include <vppinfra/error.h>
      12             : #include <vrrp/vrrp.h>
      13             : #include <vrrp/vrrp_packet.h>
      14             : 
      15             : static int
      16           0 : vrrp_vr_timer_compare (const void *v1, const void *v2)
      17             : {
      18           0 :   vrrp_main_t *vmp = &vrrp_main;
      19             :   const u32 *idx1, *idx2;
      20             :   vrrp_vr_timer_t *timer1, *timer2;
      21             : 
      22           0 :   idx1 = v1;
      23           0 :   idx2 = v2;
      24             : 
      25           0 :   timer1 = pool_elt_at_index (vmp->vr_timers, *idx1);
      26           0 :   timer2 = pool_elt_at_index (vmp->vr_timers, *idx2);
      27             : 
      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           0 :   if (timer1->expire_time > timer2->expire_time)
      32           0 :     return -1;
      33             :   else
      34           0 :     return 1;
      35             : }
      36             : 
      37             : static u32
      38           4 : vrrp_vr_timer_get_next (void)
      39             : {
      40           4 :   vrrp_main_t *vmp = &vrrp_main;
      41             :   int n_timers;
      42             : 
      43           4 :   n_timers = vec_len (vmp->pending_timers);
      44             : 
      45           4 :   if (!n_timers)
      46           2 :     return ~0;
      47             : 
      48           2 :   return vec_elt (vmp->pending_timers, n_timers - 1);
      49             : }
      50             : 
      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.
      56             :  */
      57             : void
      58           4 : vrrp_vr_timer_cancel (vrrp_vr_t * vr)
      59             : {
      60           4 :   vrrp_main_t *vmp = &vrrp_main;
      61             :   u32 *t;
      62             : 
      63             :   /* don't search for a timer that was already canceled or never set */
      64           4 :   if (vr->runtime.timer_index == ~0)
      65           2 :     return;
      66             : 
      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           2 :   if (vmp->pending_timers)
      70           2 :     vec_foreach_backwards (t, vmp->pending_timers)
      71             :     {
      72           2 :       if (*t == vr->runtime.timer_index)
      73             :         {
      74           2 :           vec_delete (vmp->pending_timers, 1, t - vmp->pending_timers);
      75           2 :           break;
      76             :         }
      77             :     }
      78             : 
      79           2 :   if (!pool_is_free_index (vmp->vr_timers, vr->runtime.timer_index))
      80           2 :     pool_put_index (vmp->vr_timers, vr->runtime.timer_index);
      81             : 
      82           2 :   vr->runtime.timer_index = ~0;
      83             : 
      84           2 :   vlib_process_signal_event (vmp->vlib_main, vrrp_periodic_node.index,
      85             :                              VRRP_EVENT_VR_TIMER_UPDATE, 0);
      86             : }
      87             : 
      88             : void
      89           2 : vrrp_vr_timer_set (vrrp_vr_t * vr, vrrp_vr_timer_type_t type)
      90             : {
      91           2 :   vrrp_main_t *vmp = &vrrp_main;
      92           2 :   vlib_main_t *vm = vlib_get_main ();
      93             :   vrrp_vr_timer_t *timer;
      94             :   f64 now;
      95             : 
      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.
      98             :    */
      99           2 :   if (vr->runtime.timer_index != ~0)
     100           0 :     vrrp_vr_timer_cancel (vr);
     101             : 
     102           2 :   pool_get (vmp->vr_timers, timer);
     103           2 :   vr->runtime.timer_index = timer - vmp->vr_timers;
     104             : 
     105           2 :   timer->vr_index = vr - vmp->vrs;
     106           2 :   timer->type = type;
     107             : 
     108           2 :   now = vlib_time_now (vm);
     109             : 
     110             :   /* RFC 5798 specifies that timers are in centiseconds, so x / 100.0 */
     111           2 :   switch (type)
     112             :     {
     113           2 :     case VRRP_VR_TIMER_ADV:
     114           2 :       timer->expire_time = now + (vr->config.adv_interval / 100.0);
     115           2 :       break;
     116           0 :     case VRRP_VR_TIMER_MASTER_DOWN:
     117           0 :       timer->expire_time = now + (vr->runtime.master_down_int / 100.0);
     118           0 :       break;
     119           0 :     default:
     120             :       /* should never reach here */
     121           0 :       clib_warning ("Unrecognized VRRP timer type (%d)", type);
     122           0 :       return;
     123             :     }
     124             : 
     125           2 :   vec_add1 (vmp->pending_timers, vr->runtime.timer_index);
     126             : 
     127           2 :   vec_sort_with_function (vmp->pending_timers, vrrp_vr_timer_compare);
     128             : 
     129           2 :   vlib_process_signal_event (vmp->vlib_main, vrrp_periodic_node.index,
     130             :                              VRRP_EVENT_VR_TIMER_UPDATE, 0);
     131             : }
     132             : 
     133             : void
     134           0 : vrrp_vr_timer_timeout (u32 timer_index)
     135             : {
     136           0 :   vrrp_main_t *vmp = &vrrp_main;
     137             :   vrrp_vr_timer_t *timer;
     138             :   vrrp_vr_t *vr;
     139             : 
     140           0 :   if (pool_is_free_index (vmp->vr_timers, timer_index))
     141             :     {
     142           0 :       clib_warning ("Timeout on free timer index %u", timer_index);
     143           0 :       return;
     144             :     }
     145             : 
     146           0 :   timer = pool_elt_at_index (vmp->vr_timers, timer_index);
     147           0 :   vr = pool_elt_at_index (vmp->vrs, timer->vr_index);
     148             : 
     149           0 :   switch (timer->type)
     150             :     {
     151           0 :     case VRRP_VR_TIMER_ADV:
     152           0 :       vrrp_adv_send (vr, 0);
     153           0 :       vrrp_vr_timer_set (vr, VRRP_VR_TIMER_ADV);
     154           0 :       break;
     155           0 :     case VRRP_VR_TIMER_MASTER_DOWN:
     156           0 :       vrrp_vr_transition (vr, VRRP_VR_STATE_MASTER, NULL);
     157           0 :       break;
     158           0 :     default:
     159           0 :       clib_warning ("Unrecognized timer type %d", timer->type);
     160           0 :       return;
     161             :     }
     162             : 
     163             : }
     164             : 
     165             : static uword
     166         575 : vrrp_periodic_process (vlib_main_t * vm,
     167             :                        vlib_node_runtime_t * rt, vlib_frame_t * f)
     168             : {
     169         575 :   vrrp_main_t *pm = &vrrp_main;
     170             :   f64 now;
     171         575 :   f64 timeout = 10.0;
     172         575 :   uword *event_data = 0;
     173             :   uword event_type;
     174         575 :   u32 next_timer = ~0;
     175             :   vrrp_vr_timer_t *timer;
     176             : 
     177             :   while (1)
     178             :     {
     179         579 :       now = vlib_time_now (vm);
     180             : 
     181         579 :       if (next_timer == ~0)
     182             :         {
     183         577 :           vlib_process_wait_for_event (vm);
     184             :         }
     185             :       else
     186             :         {
     187           2 :           timer = pool_elt_at_index (pm->vr_timers, next_timer);
     188           2 :           timeout = timer->expire_time - now;
     189             : 
     190           2 :           vlib_process_wait_for_event_or_clock (vm, timeout);
     191             :         }
     192             : 
     193           4 :       event_type = vlib_process_get_events (vm, (uword **) & event_data);
     194             : 
     195           4 :       switch (event_type)
     196             :         {
     197             :           /* Handle VRRP_EVENT_VR_TIMER_UPDATE */
     198           4 :         case VRRP_EVENT_VR_TIMER_UPDATE:
     199           4 :           next_timer = vrrp_vr_timer_get_next ();
     200           4 :           break;
     201             : 
     202             :           /* Handle periodic timeouts */
     203           0 :         case ~0:
     204           0 :           vrrp_vr_timer_timeout (next_timer);
     205           0 :           next_timer = vrrp_vr_timer_get_next ();
     206           0 :           break;
     207             :         }
     208           4 :       vec_reset_length (event_data);
     209             :     }
     210             :   return 0;
     211             : }
     212             : 
     213             : /* *INDENT-OFF* */
     214       13247 : VLIB_REGISTER_NODE (vrrp_periodic_node) = {
     215             :   .function = vrrp_periodic_process,
     216             :   .type = VLIB_NODE_TYPE_PROCESS,
     217             :   .name = "vrrp-periodic-process",
     218             :   .process_log2_n_stack_bytes = 17,
     219             : };
     220             : /* *INDENT-ON* */
     221             : 
     222             : /*
     223             :  * fd.io coding-style-patch-verification: ON
     224             :  *
     225             :  * Local Variables:
     226             :  * eval: (c-set-style "gnu")
     227             :  * End:
     228             :  */

Generated by: LCOV version 1.14