LCOV - code coverage report
Current view: top level - plugins/igmp - igmp_timer.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 68 73 93.2 %
Date: 2023-10-26 01:39:38 Functions: 12 13 92.3 %

          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             :  */

Generated by: LCOV version 1.14