LCOV - code coverage report
Current view: top level - vnsw/agent/services/multicast/grpmgmt - gmpr_intf.c (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 233 296 78.7 %
Date: 2026-08-03 02:19:58 Functions: 22 24 91.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* $Id: gmpr_intf.c 514187 2012-05-06 12:25:25Z ib-builder $
       2             :  *
       3             :  * gmpr_intf.c - IGMP/MLD Router-Side Interface Routines
       4             :  *
       5             :  * Dave Katz, March 2008
       6             :  *
       7             :  * Copyright (c) 2008, Juniper Networks, Inc.
       8             :  * All rights reserved.
       9             :  */
      10             : #include "gmpx_basic_types.h"
      11             : #include "gmp.h"
      12             : #include "gmpx_environment.h"
      13             : #include "gmp_private.h"
      14             : #include "gmp_router.h"
      15             : #include "gmpr_private.h"
      16             : #include "gmpr_trace.h"
      17             : /* Global tree of all interfaces, per protocol. */
      18             : 
      19             : gmpx_patroot *gmpr_global_intf_tree[GMP_NUM_PROTOS];
      20             : 
      21             : /* Forward references */
      22             : 
      23             : static void gmpr_intf_query_timer_expiry(gmpx_timer *timer, void *context);
      24             : 
      25             : /*
      26             :  * gmpr_next_instance_intf
      27             :  *
      28             :  * Returns the next interface on an instance, given the previous one.
      29             :  * If the previous pointer is NULL, returns the first interface on the
      30             :  * instance.
      31             :  *
      32             :  * Returns a pointer to the interface, or NULL if there are no more
      33             :  * interfaces.
      34             :  */
      35             : gmpr_intf *
      36         381 : gmpr_next_instance_intf (gmpr_instance *instance, gmpr_intf *prev_intf)
      37             : {
      38             :     gmpr_intf *next_intf;
      39             :     gmpx_patnode *node;
      40             : 
      41             :     /* Look up the node. */
      42             : 
      43         381 :     if (prev_intf) {
      44           6 :         node = gmpx_patricia_get_next(instance->rinst_intfs,
      45             :                                       &prev_intf->rintf_inst_patnode);
      46             :     } else {
      47         375 :         node = gmpx_patricia_lookup_least(instance->rinst_intfs);
      48             :     }
      49             : 
      50             :     /* Convert to a intf pointer.  The pointer may be NULL. */
      51             : 
      52         381 :     next_intf = gmpr_inst_patnode_to_intf(node);
      53             : 
      54         381 :     return next_intf;
      55             : }
      56             : 
      57             : 
      58             : /*
      59             :  * gmpr_intf_lookup
      60             :  *
      61             :  * Look up an interface, given the instance and interface ID.
      62             :  *
      63             :  * Returns a pointer to the interface structure, or NULL if not there.
      64             :  */
      65             : gmpr_intf *
      66        6887 : gmpr_intf_lookup (gmpr_instance *instance, gmpx_intf_id intf_id)
      67             : {
      68             :     gmpr_intf *intf;
      69             :     gmpx_patnode *node;
      70             : 
      71             :     /* Look up the interface in the tree. */
      72             : 
      73        6887 :     node = gmpx_patricia_lookup(instance->rinst_intfs, &intf_id);
      74        6887 :     intf = gmpr_inst_patnode_to_intf(node);
      75             : 
      76        6887 :     return intf;
      77             : }
      78             : 
      79             : 
      80             : /*
      81             :  * gmpr_intf_lookup_global
      82             :  *
      83             :  * Look up an interface, given the protocol and interface ID.
      84             :  *
      85             :  * Returns a pointer to the interface structure, or NULL if not there.
      86             :  */
      87             : gmpr_intf *
      88        5390 : gmpr_intf_lookup_global (gmp_proto proto, gmpx_intf_id intf_id)
      89             : {
      90             :     gmpr_intf *intf;
      91             :     gmpx_patnode *node;
      92             : 
      93             :     /* Look up the interface in the tree. */
      94             : 
      95        5390 :     gmpx_assert(proto < GMP_NUM_PROTOS);
      96        5390 :     node = gmpx_patricia_lookup(gmpr_global_intf_tree[proto], &intf_id);
      97        5390 :     intf = gmpr_global_patnode_to_intf(node);
      98             : 
      99        5390 :     return intf;
     100             : }
     101             : 
     102             : 
     103             : /*
     104             :  * gmpr_destroy_intf
     105             :  *
     106             :  * Free an interface.
     107             :  */
     108             : static void
     109        1708 : gmpr_destroy_intf (gmpr_intf *intf)
     110             : {
     111             :     gmpr_instance *instance;
     112             : 
     113             :     /* Toss the input group tree.  It better be empty. */
     114             : 
     115        1708 :     gmpx_assert(gmpx_patricia_lookup_least(intf->rintf_group_root) == NULL);
     116        1708 :     gmpx_patroot_destroy(intf->rintf_group_root);
     117        1708 :     intf->rintf_group_root = NULL;
     118             : 
     119             :     /* Toss the output group tree.  It better be empty. */
     120             : 
     121        1708 :     gmpx_assert(gmpx_patricia_lookup_least(intf->rintf_oif_group_root) ==
     122             :                 NULL);
     123        1708 :     gmpx_patroot_destroy(intf->rintf_oif_group_root);
     124        1708 :     intf->rintf_oif_group_root = NULL;
     125             : 
     126             :     /* Toss the host tree.  It better be empty. */
     127             : 
     128        1708 :     gmpx_assert(gmpx_patricia_lookup_least(intf->rintf_host_root) == NULL);
     129        1708 :     gmpx_patroot_destroy(intf->rintf_host_root);
     130        1708 :     intf->rintf_host_root = NULL;
     131             : 
     132             :     /* The group transmit thread better be empty. */
     133             : 
     134        1708 :     gmpx_assert(thread_circular_thread_empty(&intf->rintf_xmit_head));
     135             : 
     136             :     /* Destroy the timers. */
     137             : 
     138        1708 :     gmpx_destroy_timer(intf->rintf_query_timer);
     139        1708 :     gmpx_destroy_timer(intf->rintf_other_querier_present);
     140             : 
     141             :     /* Delete the interface from the threads. */
     142             : 
     143        1708 :     instance = intf->rintf_instance;
     144        1708 :     gmpx_assert(gmpx_patricia_delete(instance->rinst_intfs,
     145             :                                      &intf->rintf_inst_patnode));
     146        1708 :     gmpx_assert(
     147             :         gmpx_patricia_delete(gmpr_global_intf_tree[instance->rinst_proto],
     148             :                              &intf->rintf_global_patnode));
     149        1708 :     thread_remove(&intf->rintf_startup_thread);
     150             : 
     151             :     /* Free the interface entry itself. */
     152             : 
     153        1708 :     gmpx_free_block(gmpr_intf_tag, intf);
     154        1708 : }
     155             : 
     156             : 
     157             : /*
     158             :  * gmpr_destroy_instance_intfs
     159             :  *
     160             :  * Destroy all interfaces bound to an instance.  This is all quite
     161             :  * unceremonious;  we simply blast all of the state.
     162             :  */
     163             : void
     164         125 : gmpr_destroy_instance_intfs (gmpr_instance *instance)
     165             : {
     166             :     gmpr_intf *intf;
     167             : 
     168             :     /* Walk each interface on the instance and destroy it. */
     169             : 
     170             :     while (TRUE) {
     171             : 
     172         125 :         intf = gmpr_next_instance_intf(instance, NULL);
     173         125 :         if (!intf)
     174         125 :             break;                      /* All done */
     175             : 
     176             :         /* Got an interface.  Blast all the hosts on it. */
     177             : 
     178           0 :         gmpr_destroy_intf_hosts(intf);
     179             : 
     180             :         /* Blast all the groups on it. */
     181             : 
     182           0 :         gmpr_destroy_intf_groups(intf);
     183             : 
     184             :         /* Now blast the interface itself. */
     185             : 
     186           0 :         gmpr_destroy_intf(intf);
     187             :     }
     188         125 : }
     189             : 
     190             : 
     191             : /*
     192             :  * gmpr_intf_update_gmi
     193             :  *
     194             :  * Update the group membership interval
     195             :  */
     196             : static void
     197       10248 : gmpr_intf_update_gmi (gmpr_intf *intf)
     198             : {
     199       10248 :     intf->rintf_group_membership_ivl =
     200       10248 :         (intf->rintf_robustness * intf->rintf_query_ivl) +
     201       10248 :         intf->rintf_query_resp_ivl;
     202       10248 : }
     203             : 
     204             : 
     205             : /*
     206             :  * gmpr_intf_update_other_querier_interval
     207             :  *
     208             :  * Update the other-querier-present interval.
     209             :  */
     210             : static void
     211       10248 : gmpr_intf_update_other_querier_interval (gmpr_intf *intf)
     212             : {
     213       10248 :     intf->rintf_other_querier_ivl =
     214       10248 :         (intf->rintf_robustness * intf->rintf_query_ivl) +
     215       10248 :         (intf->rintf_query_resp_ivl / 2);
     216       10248 : }
     217             : 
     218             : 
     219             : /*
     220             :  * gmpr_intf_update_lmqt
     221             :  *
     222             :  * Update the Last Member Query Time.  The spec says to make it twice the
     223             :  * query interval, but this means that the timers will expire just before
     224             :  * the last query is sent, so we add half of a query interval as well.
     225             :  */
     226             : static void
     227        3416 : gmpr_intf_update_lmqt (gmpr_intf *intf)
     228             : {
     229        3416 :     intf->rintf_lmqt = (intf->rintf_lmq_ivl * intf->rintf_lmq_count) +
     230        3416 :         (intf->rintf_lmq_ivl / 2);
     231        3416 : }
     232             : 
     233             : 
     234             : /*
     235             :  * gmpr_update_lmq_count
     236             :  *
     237             :  * Update the LMQ count variable.
     238             :  */
     239             : static void
     240        1708 : gmpr_intf_update_lmq_count (gmpr_intf *intf)
     241             : {
     242             :     /* Use the robustness variable. */
     243             : 
     244        1708 :     intf->rintf_lmq_count = intf->rintf_robustness;
     245             : 
     246             :     /* Update dependent variables. */
     247             : 
     248        1708 :     gmpr_intf_update_lmqt(intf);
     249        1708 : }
     250             : 
     251             : 
     252             : /*
     253             :  * gmp_intf_update_robustness
     254             :  *
     255             :  * Update the robustness variable.
     256             :  */
     257             : void
     258        1708 : gmpr_intf_update_robustness (gmpr_intf *intf, uint32_t robustness)
     259             : {
     260             :     /* If the value is zero, use the local value. */
     261             : 
     262        1708 :     if (robustness == 0)
     263           0 :         robustness = intf->rintf_local_robustness;
     264             : 
     265             :     /* Save the new value. */
     266             : 
     267        1708 :     intf->rintf_robustness = robustness;
     268             : 
     269             :     /* Update dependent variables. */
     270             : 
     271        1708 :     gmpr_intf_update_lmq_count(intf);
     272        1708 :     gmpr_intf_update_gmi(intf);
     273        1708 :     gmpr_intf_update_other_querier_interval(intf);
     274        1708 : }
     275             : 
     276             : 
     277             : /*
     278             :  * gmpr_intf_update_query_resp_ivl
     279             :  *
     280             :  * Update the query response interval variable.
     281             :  */
     282             : static void
     283        3416 : gmpr_intf_update_query_resp_ivl (gmpr_intf *intf)
     284             : {
     285             :     uint32_t ivl;
     286             :     uint32_t ivl_target;
     287             :     gmpr_instance *instance;
     288             : 
     289        3416 :     instance = intf->rintf_instance;
     290             : 
     291             :     /* Try the local value first. */
     292             : 
     293        3416 :     ivl = intf->rintf_local_query_resp_ivl;
     294             : 
     295             :     /*
     296             :      * The value must be at least a second less than the query
     297             :      * interval.  Adjust it accordingly.
     298             :      */
     299        3416 :     if (intf->rintf_query_ivl > MSECS_PER_SEC)
     300        3416 :         ivl_target = intf->rintf_query_ivl - MSECS_PER_SEC;
     301             :     else
     302           0 :         ivl_target = intf->rintf_query_ivl / 2;
     303             : 
     304        3416 :     if (ivl > ivl_target)
     305           0 :         ivl = ivl_target;
     306             : 
     307             :     /* It also has to be at least the minimum for the protocol. */
     308             : 
     309        3416 :     if (ivl < instance->rinst_min_max_resp)
     310           0 :         ivl = instance->rinst_min_max_resp;
     311             : 
     312             :     /* Save the updated value. */
     313             : 
     314        3416 :     intf->rintf_query_resp_ivl = ivl;
     315             : 
     316             :     /* Update dependent variables. */
     317             : 
     318        3416 :     gmpr_intf_update_gmi(intf);
     319        3416 :     gmpr_intf_update_other_querier_interval(intf);
     320        3416 : }
     321             : 
     322             : 
     323             : /*
     324             :  * gmpr_intf_update_query_ivl
     325             :  *
     326             :  * Update the query interval variable.
     327             :  */
     328             : void
     329        3416 : gmpr_intf_update_query_ivl (gmpr_intf *intf, uint32_t query_ivl)
     330             : {
     331             :     /* If the value is zero, use the default value. */
     332             : 
     333        3416 :     if (query_ivl == 0)
     334           0 :         query_ivl = GMPR_QUERY_IVL_DEFAULT;
     335             : 
     336             :     /* Save the new value. */
     337             : 
     338        3416 :     intf->rintf_query_ivl = query_ivl;
     339             : 
     340             :     /* Update dependent variables. */
     341             : 
     342        3416 :     gmpr_intf_update_query_resp_ivl(intf);
     343        3416 :     gmpr_intf_update_gmi(intf);
     344        3416 :     gmpr_intf_update_other_querier_interval(intf);
     345        3416 : }
     346             : 
     347             : 
     348             : /*
     349             :  * gmpr_other_querier_present_expiry
     350             :  *
     351             :  * The other-querier-present timer has expired, which means that we're the
     352             :  * querier again.  Send a general query.
     353             :  */
     354             : static void
     355           0 : gmpr_other_querier_present_expiry (gmpx_timer *timer, void *context)
     356             : {
     357             :     gmpr_intf *intf;
     358             : 
     359           0 :     gmpx_stop_timer(timer);
     360           0 :     intf = context;
     361             : 
     362           0 :     gmpr_update_querier(intf, &intf->rintf_local_addr, TRUE);
     363           0 :     gmpx_start_timer(intf->rintf_query_timer, 0, 0);
     364           0 : }
     365             : 
     366             : 
     367             : /*
     368             :  * gmpr_restart_query_timer
     369             :  *
     370             :  * Restart (or stop) the query timer for an interface.  We stop it if
     371             :  * general queries are suppressed, unless the gen_query_requested flag
     372             :  * is set.
     373             :  */
     374             : static void
     375        2583 : gmpr_restart_query_timer (gmpr_intf *intf)
     376             : {
     377             :     gmpr_instance *instance;
     378             :     uint32_t ivl;
     379             :     int intf_count;
     380             :     task_thread *thread_ptr;
     381             : 
     382        2583 :     instance = intf->rintf_instance;
     383             : 
     384             :     /*
     385             :      * If queries are being suppressed and are not being explicitly
     386             :      * requested, stop the timer, clean up, and bail.
     387             :      */
     388        2583 :     if (intf->rintf_suppress_gen_query && !intf->rintf_gen_query_requested) {
     389           0 :         gmpx_stop_timer(intf->rintf_query_timer);
     390           0 :         thread_remove(&intf->rintf_startup_thread);
     391           0 :         intf->rintf_startup_query_count = 0;
     392           0 :         intf->rintf_first_query_pending = FALSE;
     393           0 :         return;
     394             :     }
     395             : 
     396             :     /*
     397             :      * We need to start the timer.  See if we're sending the first packet
     398             :      * in a startup sequence (which generally happens very quickly.)
     399             :      */
     400        2583 :     if (intf->rintf_first_query_pending) {
     401             : 
     402             :         /*
     403             :          * First packet in the sequence.  See if there are a lot
     404             :          * of interfaces all queued up at the same time.
     405             :          */
     406        1708 :         intf->rintf_first_query_pending = FALSE;
     407        1708 :         intf_count = GMPX_MANY_INTFS + 1;
     408        5365 :         FOR_ALL_CIRCULAR_THREAD_ENTRIES(&instance->rinst_startup_intf_thread,
     409             :                                         thread_ptr) {
     410        3657 :             intf_count--;
     411        3657 :             if (intf_count == 0)
     412           0 :                 break;
     413             :         }
     414             : 
     415             :         /*
     416             :          * If there are lots of interfaces starting up
     417             :          * simultaneously, use the standard query interval.  If
     418             :          * not, use a very short interval to speed things up.
     419             :          * Jitter is unnecessary, since we are going to smear the
     420             :          * timers after setting them.
     421             :          */
     422        1708 :         if (intf_count == 0) {          /* Too many interfaces */
     423           0 :             ivl = intf->rintf_query_ivl;
     424             :         } else {
     425        1708 :             ivl = GMPR_INIT_FIRST_QUERY_IVL;
     426             :         }
     427             : 
     428         875 :     } else if (intf->rintf_startup_query_count) {
     429             : 
     430             :         /*
     431             :          * Not the first packet in the sequence.  If we're still part
     432             :          * of the startup sequence, send this one with a fairly short
     433             :          * fixed interval.
     434             :          */
     435         832 :         ivl = GMPR_INIT_LATER_QUERY_IVL;
     436             : 
     437             :     } else {
     438             : 
     439             :         /* Not part of a startup sequence.  Use the regular interval. */
     440             : 
     441          43 :         ivl = intf->rintf_query_ivl;
     442             :     }
     443             : 
     444             :     /* Start the timer. */
     445             : 
     446        2583 :     gmpx_start_timer(intf->rintf_query_timer, ivl, 0);
     447             : }
     448             : 
     449             : 
     450             : /*
     451             :  * gmpr_setup_initial_query_timer_internal
     452             :  *
     453             :  * Set up the query timer to send a sequence of queries.  The number
     454             :  * of queries in the sequence is provided by the caller.
     455             :  *
     456             :  * If general queries are being suppressed, this will stop the query
     457             :  * timer unless the gen_query_requested flag is set (meaning that the
     458             :  * client really really really wants queries sent.)
     459             :  *
     460             :  * If there aren't too many interfaces starting up simultaneously,
     461             :  * start it with a short interval.  If there are lots, start it on its
     462             :  * regular interval to avoid bunching.  (The timers will be smeared to
     463             :  * smooth things out.)
     464             :  */
     465             : static void
     466        3484 : gmpr_setup_initial_query_timer_internal (gmpr_intf *intf, uint32_t query_count)
     467             : {
     468             : 
     469             :     gmpr_instance *instance;
     470             : 
     471        3484 :     instance = intf->rintf_instance;
     472             : 
     473             :     /*
     474             :      * Bail if there's already a query sequence being transmitted and
     475             :      * the number of pending queries is at least as large as that
     476             :      * being requested, as there's no reason to start another.
     477             :      */
     478        3484 :     if (intf->rintf_startup_query_count >= query_count)
     479        1776 :         return;
     480             : 
     481             :     /* Set the startup query count and set the "first_query" flag. */
     482             : 
     483        1708 :     intf->rintf_startup_query_count = query_count;
     484        1708 :     intf->rintf_first_query_pending = TRUE;
     485             : 
     486             :     /*
     487             :      * Put the interface on the thread of startup interfaces.  This will
     488             :      * make us throttle the rate at which we send queries if the interface
     489             :      * count is high.
     490             :      */
     491        1708 :     thread_remove(&intf->rintf_startup_thread);  /* Just in case. */
     492        1708 :     thread_circular_add_top(&instance->rinst_startup_intf_thread,
     493             :                             &intf->rintf_startup_thread);
     494             : 
     495             :     /* Restart (or stop) the query timer. */
     496             : 
     497        1708 :     gmpr_restart_query_timer(intf);
     498             : 
     499             :     /* Schedule a smearing of the query timers. */
     500             : 
     501        1708 :     gmpr_accelerate_query_smear(instance);
     502             : }
     503             : 
     504             : 
     505             : /*
     506             :  * gmpr_setup_initial_query_timer
     507             :  *
     508             :  * Set up the query timer to send a sequence of queries.  This is done
     509             :  * when an interface is first created, or when the client requests it,
     510             :  * or when the query interval is changed (and probably other times as
     511             :  * well).
     512             :  */
     513             : void
     514        3484 : gmpr_setup_initial_query_timer (gmpr_intf *intf)
     515             : {
     516        3484 :     gmpr_setup_initial_query_timer_internal(intf, intf->rintf_robustness);
     517        3484 : }
     518             : 
     519             : 
     520             : /*
     521             :  * gmpr_trigger_one_query
     522             :  *
     523             :  * Trigger the transmission of a single fast query.  We simulate a startup
     524             :  * sequence with a single packet, so it will be throttled appropriately if
     525             :  * there are lots of interfaces starting up.
     526             :  */
     527             : void
     528           0 : gmpr_trigger_one_query (gmpr_intf *intf)
     529             : {
     530           0 :     gmpr_setup_initial_query_timer_internal(intf, 1);
     531           0 : }
     532             : 
     533             : /*
     534             :  * gmpr_create_intf
     535             :  *
     536             :  * Create an interface structure and add it to the instance tree.
     537             :  *
     538             :  * Returns a pointer to the interface structure, or NULL if no memory.
     539             :  */
     540             : static gmpr_intf *
     541        1708 : gmpr_create_intf (gmpr_instance *instance, gmpx_intf_id intf_id)
     542             : {
     543             :     gmpr_intf *intf;
     544             : 
     545             :     /* Allocate the block. */
     546             : 
     547        1708 :     intf = gmpx_malloc_block(gmpr_intf_tag);
     548        1708 :     if (!intf)
     549           0 :         return NULL;
     550             : 
     551             :     /* Initialize the input group tree. */
     552             : 
     553        1708 :     intf->rintf_group_root = 
     554        1708 :         gmpx_patroot_init(instance->rinst_addrlen,
     555             :                           GMPX_PATRICIA_OFFSET(gmpr_group, rgroup_intf_patnode,
     556             :                                                rgroup_addr));
     557        1708 :     if (!intf->rintf_group_root) { /* No memory */
     558           0 :         gmpx_free_block(gmpr_intf_tag, intf);
     559           0 :         return NULL;
     560             :     }
     561             : 
     562             :     /* Initialize the output group tree. */
     563             : 
     564        1708 :     intf->rintf_oif_group_root = 
     565        1708 :         gmpx_patroot_init(instance->rinst_addrlen,
     566             :                           GMPX_PATRICIA_OFFSET(gmpr_ogroup,
     567             :                                                rogroup_intf_patnode,
     568             :                                                rogroup_addr));
     569        1708 :     if (!intf->rintf_oif_group_root) { /* No memory */
     570           0 :         gmpx_patroot_destroy(intf->rintf_group_root);
     571           0 :         gmpx_free_block(gmpr_intf_tag, intf);
     572           0 :         return NULL;
     573             :     }
     574             : 
     575             :     /* Create the host tree. */
     576             : 
     577        1708 :     intf->rintf_host_root = 
     578        1708 :         gmpx_patroot_init(instance->rinst_addrlen,
     579             :                           GMPX_PATRICIA_OFFSET(gmpr_host, rhost_node,
     580             :                                                rhost_addr));
     581        1708 :     if (!intf->rintf_host_root) { /* No memory */
     582           0 :         gmpx_patroot_destroy(intf->rintf_group_root);
     583           0 :         gmpx_patroot_destroy(intf->rintf_oif_group_root);
     584           0 :         gmpx_free_block(gmpr_intf_tag, intf);
     585           0 :         return NULL;
     586             :     }
     587             : 
     588             :     /* Initialize the transmit queue. */
     589             : 
     590        1708 :     thread_new_circular_thread(&intf->rintf_xmit_head);
     591             : 
     592             :     /* Put the interface into the instance tree. */
     593             : 
     594        1708 :     intf->rintf_id = intf_id;
     595        1708 :     gmpx_assert(gmpx_patricia_add(instance->rinst_intfs,
     596             :                                   &intf->rintf_inst_patnode));
     597             : 
     598             :     /* Put the interface into the global tree. */
     599             : 
     600        1708 :     gmpx_assert(
     601             :         gmpx_patricia_add(gmpr_global_intf_tree[instance->rinst_proto],
     602             :                           &intf->rintf_global_patnode));
     603             : 
     604             :     /* Initialize a few more things. */
     605             : 
     606        1708 :     intf->rintf_instance = instance;
     607        1708 :     intf->rintf_ver = GMP_VERSION_DEFAULT;
     608        1708 :     intf->rintf_query_ivl = GMPR_QUERY_IVL_DEFAULT;
     609        1708 :     intf->rintf_local_query_ivl = GMPR_QUERY_IVL_DEFAULT;
     610        1708 :     intf->rintf_query_resp_ivl = GMPR_QUERY_RESP_IVL_DEFAULT;
     611        1708 :     intf->rintf_local_query_resp_ivl = GMPR_QUERY_RESP_IVL_DEFAULT;
     612        1708 :     intf->rintf_robustness = GMP_ROBUSTNESS_DEFAULT;
     613        1708 :     intf->rintf_local_robustness = GMP_ROBUSTNESS_DEFAULT;
     614        1708 :     intf->rintf_lmq_ivl = GMPR_LMQI_DEFAULT;
     615        1708 :     intf->rintf_lmq_count = GMP_ROBUSTNESS_DEFAULT;
     616        1708 :     intf->rintf_querier = FALSE;
     617        1708 :     intf->rintf_querier_enabled = TRUE;
     618             : 
     619             :     /* Update the group membership interval. */
     620             : 
     621        1708 :     gmpr_intf_update_gmi(intf);
     622             : 
     623             :     /* Update the other querier present interval. */
     624             : 
     625        1708 :     gmpr_intf_update_other_querier_interval(intf);
     626             : 
     627             :     /* Update the Last Member Query Time. */
     628             : 
     629        1708 :     gmpr_intf_update_lmqt(intf);
     630             : 
     631             :     /* Create the timers. */
     632             : 
     633        1708 :     intf->rintf_query_timer =
     634        1708 :         gmpx_create_grouped_timer(GMP_TIMER_GROUP_GEN_QUERY,
     635             :                                   instance->rinst_context,
     636             :                                   "GMP router general query",
     637             :                                   gmpr_intf_query_timer_expiry, intf);
     638        1708 :     intf->rintf_other_querier_present =
     639        1708 :         gmpx_create_timer(instance->rinst_context,
     640             :                           "GMP router other querier present",
     641             :                           gmpr_other_querier_present_expiry, intf);
     642             :     
     643             :     /* Initialized to null, will be created if log-interval is configured */
     644             : 
     645             :     /* Set up the query timer. */
     646             : 
     647        1708 :     gmpr_setup_initial_query_timer(intf);
     648             : 
     649        1708 :     return intf;
     650             : }
     651             : 
     652             : 
     653             : /*
     654             :  * gmpr_attach_intf_internal
     655             :  *
     656             :  * Create an interface entry based on the instance and interface ID.
     657             :  *
     658             :  * Returns 0 if all OK, -1 if out of memory, or 1 if the interface already
     659             :  * exists.
     660             :  */
     661             : int
     662        1708 : gmpr_attach_intf_internal (gmpr_instance *instance, gmpx_intf_id intf_id)
     663             : {
     664             :     gmpr_intf *intf;
     665             : 
     666             :     /* Look up the interface.  Bail if it's already there. */
     667             : 
     668        1708 :     intf = gmpr_intf_lookup_global(instance->rinst_proto, intf_id);
     669        1708 :     if (intf)
     670           0 :         return 1;                       /* Already exists */
     671             : 
     672             :     /* Create a new one. */
     673             : 
     674        1708 :     intf = gmpr_create_intf(instance, intf_id);
     675        1708 :     if (!intf)
     676           0 :         return -1;                      /* Out of memory */
     677             : 
     678        1708 :     return 0;
     679             : }
     680             : 
     681             : 
     682             : /*
     683             :  * gmpr_detach_intf_internal
     684             :  *
     685             :  * Get rid of an interface.  Under normal circumstances, the interface will
     686             :  * be inactive, but we tolerate unceremonious deletions by cleaning up all
     687             :  * of the attached state.
     688             :  *
     689             :  * Returns 0 if all OK, or 1 if the interface doesn't exist.
     690             :  */
     691             : int
     692        1708 : gmpr_detach_intf_internal (gmpr_instance *instance, gmpx_intf_id intf_id)
     693             : {
     694             :     gmpr_intf *intf;
     695             : 
     696             :     /* Look up the interface.  Bail if it doesn't exist. */
     697             : 
     698        1708 :     intf = gmpr_intf_lookup(instance, intf_id);
     699        1708 :     if (!intf)
     700           0 :         return 1;                       /* Doesn't exist */
     701             : 
     702             :     /* Blast all of the groups on the interface. */
     703             : 
     704        1708 :     gmpr_destroy_intf_groups(intf);
     705             : 
     706             :     /* Blast all of the hosts on the interface. */
     707             : 
     708        1708 :     gmpr_destroy_intf_hosts(intf);
     709             : 
     710             :     /* Should be clean now.  Destroy the interface. */
     711             : 
     712        1708 :     gmpr_destroy_intf(intf);
     713             : 
     714        1708 :     return 0;
     715             : }
     716             : 
     717             : /*
     718             :  * gmpr_intf_set_params
     719             :  *
     720             :  * Set parameters for an interface.
     721             :  *
     722             :  * Returns 0 if OK, -1 if out of memory, or 1 if the interface doesn't exist.
     723             :  */
     724             : int
     725        1708 : gmpr_intf_set_params (gmpr_instance *instance, gmpx_intf_id intf_id,
     726             :                       gmpr_intf_params *params)
     727             : {
     728             :     gmpr_intf *intf;
     729             :     gmpr_group *group;
     730             :     boolean version_changed;
     731             :     gmp_version new_version;
     732             :     uint32_t old_query_ivl;
     733             :     uint32_t old_robustness;
     734             :     boolean send_query;
     735             : 
     736             :     /* Get the interface. */
     737             : 
     738        1708 :     intf = gmpr_intf_lookup(instance, intf_id);
     739        1708 :     if (!intf)
     740           0 :         return 1;                       /* Doesn't exist. */
     741             : 
     742             :     /* Set the parameters. */
     743             : 
     744        1708 :     new_version = gmp_translate_version(instance->rinst_proto,
     745        1708 :                                         params->gmpr_ifparm_version);
     746        1708 :     version_changed = (intf->rintf_ver != new_version);
     747        1708 :     intf->rintf_ver = new_version;
     748             : 
     749             :     /* If the version changed, update all group versions. */
     750             : 
     751        1708 :     if (version_changed) {
     752             : 
     753             :         /* Walk all groups on the interface. */
     754             : 
     755          32 :         group = NULL;
     756             : 
     757             :         while (TRUE) {
     758          32 :             group = gmpr_next_intf_group(intf, group);
     759             : 
     760             :             /* Bail if done. */
     761             : 
     762          32 :             if (!group)
     763          32 :                 break;
     764             : 
     765             :             /* Update the compatibility mode. */
     766             : 
     767           0 :             gmpr_evaluate_group_version(group);
     768             :         }
     769             :     }
     770             : 
     771             :     /* Remember if the suppression parameters are changing. */
     772             : 
     773        1708 :     send_query = FALSE;
     774        1708 :     if (intf->rintf_suppress_gen_query !=
     775        1708 :             params->gmpr_ifparm_suppress_gen_query) {
     776           0 :         send_query = TRUE;
     777             :     }
     778             : 
     779             :     /* Set the parameters. */
     780             : 
     781        1708 :     old_query_ivl = intf->rintf_local_query_ivl;
     782        1708 :     intf->rintf_local_query_ivl = params->gmpr_ifparm_qivl;
     783        1708 :     intf->rintf_local_query_resp_ivl = params->gmpr_ifparm_qrivl;
     784        1708 :     intf->rintf_lmq_ivl = params->gmpr_ifparm_lmqi;
     785        1708 :     intf->rintf_fast_leaves = params->gmpr_ifparm_fast_leave;
     786        1708 :     intf->rintf_channel_limit = params->gmpr_ifparm_chan_limit;
     787             :     
     788        1708 :     if(intf->rintf_channel_count > intf->rintf_channel_limit)
     789           0 :         intf->rintf_limit_state = GMPR_ABOVE_LIMIT;
     790             :     else
     791        1708 :         intf->rintf_limit_state = GMPR_BELOW_THRESHOLD;
     792             : 
     793             :     /* threshold and log-interval can be configured only
     794             :        when channel_limit is configured */
     795             : 
     796        1708 :     if(intf->rintf_channel_limit) {
     797           0 :         intf->rintf_channel_threshold = params->gmpr_ifparm_chan_threshold;
     798           0 :         intf->rintf_log_interval = params->gmpr_ifparm_log_interval;
     799           0 :         if(intf->rintf_channel_count > intf->rintf_channel_threshold)
     800           0 :             intf->rintf_limit_state = GMPR_ABOVE_THRESHOLD_BELOW_LIMIT;
     801             :         else
     802           0 :             intf->rintf_limit_state = GMPR_BELOW_THRESHOLD;
     803             :     } else {
     804             :         /* Threshold and log interval does not have a significance without limit */
     805        1708 :         intf->rintf_channel_threshold = 0 ;
     806        1708 :         intf->rintf_log_interval = 0;
     807             :     }
     808             :     
     809        1708 :     intf->rintf_passive_receive = params->gmpr_ifparm_passive_receive;
     810        1708 :     intf->rintf_suppress_gen_query = params->gmpr_ifparm_suppress_gen_query;
     811        1708 :     intf->rintf_suppress_gs_query = params->gmpr_ifparm_suppress_gs_query;
     812        1708 :     intf->rintf_local_robustness = params->gmpr_ifparm_robustness;
     813             : 
     814             :     /* If we're doing fast leaves, force host tracking. */
     815             : 
     816        1708 :     if (intf->rintf_fast_leaves)
     817           0 :         instance->rinst_host_tracking = TRUE;
     818             : 
     819             :     /* Update dependent parameters. */
     820             : 
     821        1708 :     old_robustness = intf->rintf_robustness;
     822        1708 :     gmpr_intf_update_robustness(intf, params->gmpr_ifparm_robustness);
     823        1708 :     gmpr_intf_update_query_ivl(intf, params->gmpr_ifparm_qivl);
     824             : 
     825             :     /* Restart the query timer if the interval changed. */
     826             : 
     827        1708 :     if (old_query_ivl != intf->rintf_local_query_ivl)
     828          68 :         send_query = TRUE;
     829             : 
     830             :     /*
     831             :      * If the channel limit is now less than the number of channels on the
     832             :      * interface, blow away the interface state and issue a query to rebuild
     833             :      * it.
     834             :      */
     835        1708 :     if (intf->rintf_channel_limit &&
     836           0 :         intf->rintf_channel_count > intf->rintf_channel_limit) {
     837             : 
     838             :         /* Walk all groups on the interface. */
     839           0 :         intf->rintf_limit_state = GMPR_ABOVE_LIMIT;
     840           0 :         group = NULL;
     841             : 
     842             :         while (TRUE) {
     843           0 :             group = gmpr_next_intf_group(intf, group);
     844             : 
     845             :             /* Bail if done. */
     846             : 
     847           0 :             if (!group)
     848           0 :                 break;
     849             : 
     850             :             /* Make the group go away. */
     851             : 
     852           0 :             gmpr_timeout_group(group);
     853             :         }
     854           0 :         send_query = TRUE;
     855        1708 :     } else if(intf->rintf_channel_limit &&
     856           0 :               intf->rintf_channel_count > intf->rintf_channel_threshold *
     857           0 :                                            intf->rintf_channel_limit/100 ) {
     858           0 :         intf->rintf_limit_state = GMPR_ABOVE_THRESHOLD_BELOW_LIMIT;
     859             :     } else {
     860        1708 :         intf->rintf_limit_state = GMPR_BELOW_THRESHOLD;
     861             :     }
     862             :    
     863             :     /*
     864             :      * If queries are suppressed, zap the startup query counter,
     865             :      * since it isn't relevant and may get in the way later.
     866             :      */
     867        1708 :     if (intf->rintf_suppress_gen_query)
     868           0 :         intf->rintf_startup_query_count = 0;
     869             : 
     870             :     /*
     871             :      * Kick the query timer if necessary (which may stop it.)
     872             :      * If the robustness variable changed, send a whole query sequence
     873             :      * instead.
     874             :      */
     875        1708 :     if (old_robustness != intf->rintf_robustness) {
     876          68 :         gmpr_setup_initial_query_timer(intf);
     877        1640 :     } else if (send_query) {
     878           0 :         gmpr_trigger_one_query(intf);
     879             :     }
     880             : 
     881        1708 :     return 0;
     882             : }
     883             : 
     884             : 
     885             : /*
     886             :  * gmpr_intf_query_timer_expiry
     887             :  *
     888             :  * The interface general query timer has expired.
     889             :  */
     890             : static void
     891         875 : gmpr_intf_query_timer_expiry (gmpx_timer *timer GMPX_UNUSED, void *context)
     892             : {
     893             :     gmpr_intf *intf;
     894             : 
     895         875 :     intf = context;
     896             : 
     897             :     /*
     898             :      * Set the flag saying that we need to send a query, and kick the
     899             :      * transmitter.
     900             :      */
     901         875 :     intf->rintf_send_gen_query = TRUE;
     902         875 :     gmpr_kick_xmit(intf);
     903             : 
     904             :     /* If we're in an initial query sequence, drop the query count. */
     905             : 
     906         875 :     if (intf->rintf_startup_query_count)
     907         867 :         intf->rintf_startup_query_count--;
     908             : 
     909             :     /*
     910             :      * If the startup query count is zero, clear the "query requested"
     911             :      * flag, as any requested query sequence is complete.  Likewise,
     912             :      * take the interface off of the startup thread.
     913             :      */
     914         875 :     if (!intf->rintf_startup_query_count) {
     915          43 :         intf->rintf_gen_query_requested = FALSE;
     916          43 :         thread_remove(&intf->rintf_startup_thread);
     917             :     }
     918         875 :     gmpr_restart_query_timer(intf);
     919         875 : }
     920             : 
     921             : 
     922             : /*
     923             :  * gmpr_kick_xmit
     924             :  *
     925             :  * Kick the transmission state machinery for an interface.
     926             :  */
     927             : void
     928        2627 : gmpr_kick_xmit (gmpr_intf *intf)
     929             : {
     930             :     /*
     931             :      * Do it only if we don't have a pending transmission and the
     932             :      * interface is up.
     933             :      */
     934             : 
     935        2627 :     if (!intf->rintf_xmit_pending && intf->rintf_up) {
     936             : 
     937             :         /* Set the flag and kick the I/O. */
     938             : 
     939        2627 :         intf->rintf_xmit_pending = TRUE;
     940        2627 :         gmpp_start_xmit(GMP_ROLE_ROUTER, intf->rintf_instance->rinst_proto,
     941             :                         intf->rintf_id);
     942             :     }
     943        2627 : }
     944             : 
     945             : 
     946             : /*
     947             :  * gmpr_update_querier
     948             :  *
     949             :  * Update querier status on this interface.  If it's changing, post a
     950             :  * notification if enabled.
     951             :  *
     952             :  * The address parameter will be NULL if we're the querier.
     953             :  */
     954             : void
     955        1708 : gmpr_update_querier (gmpr_intf *intf, gmp_addr_string *addr, boolean querier)
     956             : {
     957             :     gmpr_instance *instance;
     958             :     gmpr_client *client;
     959             :     task_thread *thread_ptr;
     960             : 
     961        1708 :     instance = intf->rintf_instance;
     962             : 
     963             :     /* Bail if nothing has changed. */
     964             : 
     965        1708 :     if (querier == intf->rintf_querier &&
     966           0 :         (!addr || !memcmp(addr->gmp_addr, intf->rintf_querier_addr.gmp_addr,
     967           0 :             instance->rinst_addrlen))) {
     968           0 :         return;
     969             :     }
     970             : 
     971             :     /* Update the status. */
     972             : 
     973        1708 :     intf->rintf_querier = querier;
     974        1708 :     memmove(intf->rintf_querier_addr.gmp_addr, addr->gmp_addr,
     975        1708 :         instance->rinst_addrlen);
     976             : 
     977             :     /*
     978             :      * If we're becoming querier, update the query interval to the
     979             :      * configured value.
     980             :      */
     981        1708 :     if (querier)
     982        1708 :         gmpr_intf_update_query_ivl(intf, intf->rintf_local_query_ivl);
     983             : 
     984             :     /* Call the callback for any client, if present. */
     985             : 
     986        3416 :     FOR_ALL_CIRCULAR_THREAD_ENTRIES(&instance->rinst_client_thread,
     987             :                                     thread_ptr) {
     988        1708 :         client = gmpr_thread_to_client(thread_ptr);
     989        1708 :         if (client->rclient_cb_context.rctx_querier_cb)
     990        1708 :             (*client->rclient_cb_context.rctx_querier_cb)(
     991             :                                           instance->rinst_context,
     992             :                                           intf->rintf_id,
     993             :                                           intf->rintf_querier,
     994        1708 :                                           intf->rintf_querier_addr.gmp_addr);
     995             :     }
     996             : }

Generated by: LCOV version 1.14