back to topotato report
topotato coverage report
Current view: top level - pimd - pim_bsm.c (source / functions) Hit Total Coverage
Test: aggregated run ( view descriptions ) Lines: 169 739 22.9 %
Date: 2023-02-24 14:41:08 Functions: 20 38 52.6 %

          Line data    Source code
       1             : /*
       2             :  * pim_bsm.c: PIM BSM handling routines
       3             :  *
       4             :  * Copyright (C) 2018-19 Vmware, Inc.
       5             :  * Saravanan K
       6             :  *
       7             :  * This program is free software; you can redistribute it and/or modify
       8             :  * it under the terms of the GNU General Public License as published by
       9             :  * the Free Software Foundation; either version 2 of the License, or
      10             :  * (at your option) any later version.
      11             :  *
      12             :  * This program is distributed in the hope that it will be useful, but
      13             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15             :  * General Public License for more details.
      16             :  *
      17             :  * You should have received a copy of the GNU General Public License
      18             :  * along with this program; see the file COPYING; if not, write to the
      19             :  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
      20             :  * MA 02110-1301 USA
      21             :  */
      22             : 
      23             : #ifdef HAVE_CONFIG_H
      24             : #include "config.h"
      25             : #endif
      26             : 
      27             : #include "if.h"
      28             : #include "pimd.h"
      29             : #include "pim_iface.h"
      30             : #include "pim_instance.h"
      31             : #include "pim_neighbor.h"
      32             : #include "pim_rpf.h"
      33             : #include "pim_hello.h"
      34             : #include "pim_pim.h"
      35             : #include "pim_nht.h"
      36             : #include "pim_bsm.h"
      37             : #include "pim_time.h"
      38             : #include "pim_zebra.h"
      39             : #include "pim_util.h"
      40             : 
      41             : /* Functions forward declaration */
      42             : static void pim_bs_timer_start(struct bsm_scope *scope, int bs_timeout);
      43             : static void pim_g2rp_timer_start(struct bsm_rpinfo *bsrp, int hold_time);
      44             : static inline void pim_g2rp_timer_restart(struct bsm_rpinfo *bsrp,
      45             :                                           int hold_time);
      46             : 
      47             : /* Memory Types */
      48          78 : DEFINE_MTYPE_STATIC(PIMD, PIM_BSGRP_NODE, "PIM BSR advertised grp info");
      49          78 : DEFINE_MTYPE_STATIC(PIMD, PIM_BSRP_INFO, "PIM BSR advertised RP info");
      50          78 : DEFINE_MTYPE_STATIC(PIMD, PIM_BSM_FRAG, "PIM BSM fragment");
      51          78 : DEFINE_MTYPE_STATIC(PIMD, PIM_BSM_PKT_VAR_MEM, "PIM BSM Packet");
      52             : 
      53             : /* All bsm packets forwarded shall be fit within ip mtu less iphdr(max) */
      54             : #define MAX_IP_HDR_LEN 24
      55             : 
      56             : /* pim_bsm_write_config - Write the interface pim bsm configuration.*/
      57           0 : void pim_bsm_write_config(struct vty *vty, struct interface *ifp)
      58             : {
      59           0 :         struct pim_interface *pim_ifp = ifp->info;
      60             : 
      61           0 :         if (pim_ifp) {
      62           0 :                 if (!pim_ifp->bsm_enable)
      63           0 :                         vty_out(vty, " no " PIM_AF_NAME " pim bsm\n");
      64           0 :                 if (!pim_ifp->ucast_bsm_accept)
      65           0 :                         vty_out(vty, " no " PIM_AF_NAME " pim unicast-bsm\n");
      66             :         }
      67           0 : }
      68             : 
      69           0 : static void pim_bsm_rpinfo_free(struct bsm_rpinfo *bsrp_info)
      70             : {
      71           0 :         THREAD_OFF(bsrp_info->g2rp_timer);
      72           0 :         XFREE(MTYPE_PIM_BSRP_INFO, bsrp_info);
      73           0 : }
      74             : 
      75           0 : static void pim_bsm_rpinfos_free(struct bsm_rpinfos_head *head)
      76             : {
      77           0 :         struct bsm_rpinfo *bsrp_info;
      78             : 
      79           0 :         while ((bsrp_info = bsm_rpinfos_pop(head)))
      80           0 :                 pim_bsm_rpinfo_free(bsrp_info);
      81           0 : }
      82             : 
      83           0 : static void pim_free_bsgrp_data(struct bsgrp_node *bsgrp_node)
      84             : {
      85           0 :         pim_bsm_rpinfos_free(bsgrp_node->bsrp_list);
      86           0 :         pim_bsm_rpinfos_free(bsgrp_node->partial_bsrp_list);
      87           0 :         XFREE(MTYPE_PIM_BSGRP_NODE, bsgrp_node);
      88           0 : }
      89             : 
      90           0 : static void pim_free_bsgrp_node(struct route_table *rt, struct prefix *grp)
      91             : {
      92           0 :         struct route_node *rn;
      93             : 
      94           0 :         rn = route_node_lookup(rt, grp);
      95           0 :         if (rn) {
      96           0 :                 rn->info = NULL;
      97           0 :                 route_unlock_node(rn);
      98           0 :                 route_unlock_node(rn);
      99             :         }
     100           0 : }
     101             : 
     102           8 : static void pim_bsm_frag_free(struct bsm_frag *bsfrag)
     103             : {
     104           8 :         XFREE(MTYPE_PIM_BSM_FRAG, bsfrag);
     105           8 : }
     106             : 
     107          34 : static void pim_bsm_frags_free(struct bsm_scope *scope)
     108             : {
     109          34 :         struct bsm_frag *bsfrag;
     110             : 
     111          76 :         while ((bsfrag = bsm_frags_pop(scope->bsm_frags)))
     112          50 :                 pim_bsm_frag_free(bsfrag);
     113          34 : }
     114             : 
     115           0 : int pim_bsm_rpinfo_cmp(const struct bsm_rpinfo *node1,
     116             :                        const struct bsm_rpinfo *node2)
     117             : {
     118             :         /* RP election Algo :
     119             :          * Step-1 : Loweset Rp priority  will have higher precedance.
     120             :          * Step-2 : If priority same then higher hash val will have
     121             :          *          higher precedance.
     122             :          * Step-3 : If Hash val is same then highest rp address will
     123             :          *          become elected RP.
     124             :          */
     125           0 :         if (node1->rp_prio < node2->rp_prio)
     126             :                 return -1;
     127           0 :         if (node1->rp_prio > node2->rp_prio)
     128             :                 return 1;
     129           0 :         if (node1->hash < node2->hash)
     130             :                 return 1;
     131           0 :         if (node1->hash > node2->hash)
     132             :                 return -1;
     133           0 :         return pim_addr_cmp(node2->rp_address, node1->rp_address);
     134             : }
     135             : 
     136           0 : static struct bsgrp_node *pim_bsm_new_bsgrp_node(struct route_table *rt,
     137             :                                                  struct prefix *grp)
     138             : {
     139           0 :         struct route_node *rn;
     140           0 :         struct bsgrp_node *bsgrp;
     141             : 
     142           0 :         rn = route_node_get(rt, grp);
     143           0 :         if (!rn) {
     144           0 :                 zlog_warn("%s: route node creation failed", __func__);
     145           0 :                 return NULL;
     146             :         }
     147           0 :         bsgrp = XCALLOC(MTYPE_PIM_BSGRP_NODE, sizeof(struct bsgrp_node));
     148             : 
     149           0 :         rn->info = bsgrp;
     150           0 :         bsm_rpinfos_init(bsgrp->bsrp_list);
     151           0 :         bsm_rpinfos_init(bsgrp->partial_bsrp_list);
     152             : 
     153           0 :         prefix_copy(&bsgrp->group, grp);
     154           0 :         return bsgrp;
     155             : }
     156             : 
     157           0 : static void pim_on_bs_timer(struct thread *t)
     158             : {
     159           0 :         struct route_node *rn;
     160           0 :         struct bsm_scope *scope;
     161           0 :         struct bsgrp_node *bsgrp_node;
     162           0 :         struct bsm_rpinfo *bsrp;
     163             : 
     164           0 :         scope = THREAD_ARG(t);
     165           0 :         THREAD_OFF(scope->bs_timer);
     166             : 
     167           0 :         if (PIM_DEBUG_BSM)
     168           0 :                 zlog_debug("%s: Bootstrap Timer expired for scope: %d",
     169             :                            __func__, scope->sz_id);
     170             : 
     171           0 :         pim_nht_bsr_del(scope->pim, scope->current_bsr);
     172             :         /* Reset scope zone data */
     173           0 :         scope->accept_nofwd_bsm = false;
     174           0 :         scope->state = ACCEPT_ANY;
     175           0 :         scope->current_bsr = PIMADDR_ANY;
     176           0 :         scope->current_bsr_prio = 0;
     177           0 :         scope->current_bsr_first_ts = 0;
     178           0 :         scope->current_bsr_last_ts = 0;
     179           0 :         scope->bsm_frag_tag = 0;
     180           0 :         pim_bsm_frags_free(scope);
     181             : 
     182           0 :         for (rn = route_top(scope->bsrp_table); rn; rn = route_next(rn)) {
     183             : 
     184           0 :                 bsgrp_node = (struct bsgrp_node *)rn->info;
     185           0 :                 if (!bsgrp_node) {
     186           0 :                         if (PIM_DEBUG_BSM)
     187           0 :                                 zlog_debug("%s: bsgrp_node is null", __func__);
     188           0 :                         continue;
     189             :                 }
     190             :                 /* Give grace time for rp to continue for another hold time */
     191           0 :                 bsrp = bsm_rpinfos_first(bsgrp_node->bsrp_list);
     192           0 :                 if (bsrp)
     193           0 :                         pim_g2rp_timer_restart(bsrp, bsrp->rp_holdtime);
     194             : 
     195             :                 /* clear pending list */
     196           0 :                 pim_bsm_rpinfos_free(bsgrp_node->partial_bsrp_list);
     197           0 :                 bsgrp_node->pend_rp_cnt = 0;
     198             :         }
     199           0 : }
     200             : 
     201          26 : static void pim_bs_timer_stop(struct bsm_scope *scope)
     202             : {
     203          26 :         if (PIM_DEBUG_BSM)
     204           6 :                 zlog_debug("%s : BS timer being stopped of sz: %d", __func__,
     205             :                            scope->sz_id);
     206          26 :         THREAD_OFF(scope->bs_timer);
     207          26 : }
     208             : 
     209          34 : static void pim_bs_timer_start(struct bsm_scope *scope, int bs_timeout)
     210             : {
     211          34 :         if (!scope) {
     212           0 :                 if (PIM_DEBUG_BSM)
     213           0 :                         zlog_debug("%s : Invalid scope(NULL).", __func__);
     214           0 :                 return;
     215             :         }
     216          34 :         THREAD_OFF(scope->bs_timer);
     217          34 :         if (PIM_DEBUG_BSM)
     218           8 :                 zlog_debug(
     219             :                         "%s : starting bs timer for scope %d with timeout %d secs",
     220             :                         __func__, scope->sz_id, bs_timeout);
     221          34 :         thread_add_timer(router->master, pim_on_bs_timer, scope, bs_timeout,
     222             :                          &scope->bs_timer);
     223             : }
     224             : 
     225           8 : static inline void pim_bs_timer_restart(struct bsm_scope *scope, int bs_timeout)
     226             : {
     227           8 :         pim_bs_timer_start(scope, bs_timeout);
     228             : }
     229             : 
     230          26 : void pim_bsm_proc_init(struct pim_instance *pim)
     231             : {
     232          26 :         memset(&pim->global_scope, 0, sizeof(struct bsm_scope));
     233             : 
     234          26 :         pim->global_scope.sz_id = PIM_GBL_SZ_ID;
     235          26 :         pim->global_scope.bsrp_table = route_table_init();
     236          26 :         pim->global_scope.accept_nofwd_bsm = true;
     237          26 :         pim->global_scope.state = NO_INFO;
     238          26 :         pim->global_scope.pim = pim;
     239          26 :         bsm_frags_init(pim->global_scope.bsm_frags);
     240          26 :         pim_bs_timer_start(&pim->global_scope, PIM_BS_TIME);
     241          26 : }
     242             : 
     243          26 : void pim_bsm_proc_free(struct pim_instance *pim)
     244             : {
     245          26 :         struct route_node *rn;
     246          26 :         struct bsgrp_node *bsgrp;
     247             : 
     248          26 :         pim_bs_timer_stop(&pim->global_scope);
     249          26 :         pim_bsm_frags_free(&pim->global_scope);
     250             : 
     251          26 :         for (rn = route_top(pim->global_scope.bsrp_table); rn;
     252           0 :              rn = route_next(rn)) {
     253           0 :                 bsgrp = rn->info;
     254           0 :                 if (!bsgrp)
     255           0 :                         continue;
     256           0 :                 pim_free_bsgrp_data(bsgrp);
     257             :         }
     258             : 
     259          26 :         route_table_finish(pim->global_scope.bsrp_table);
     260          26 : }
     261             : 
     262           0 : static bool is_hold_time_elapsed(void *data)
     263             : {
     264           0 :         struct bsm_rpinfo *bsrp;
     265             : 
     266           0 :         bsrp = data;
     267             : 
     268           0 :         if (bsrp->elapse_time < bsrp->rp_holdtime)
     269             :                 return false;
     270             :         else
     271           0 :                 return true;
     272             : }
     273             : 
     274           0 : static void pim_on_g2rp_timer(struct thread *t)
     275             : {
     276           0 :         struct bsm_rpinfo *bsrp;
     277           0 :         struct bsm_rpinfo *bsrp_node;
     278           0 :         struct bsgrp_node *bsgrp_node;
     279           0 :         struct pim_instance *pim;
     280           0 :         struct rp_info *rp_info;
     281           0 :         struct route_node *rn;
     282           0 :         uint16_t elapse;
     283           0 :         pim_addr bsrp_addr;
     284             : 
     285           0 :         bsrp = THREAD_ARG(t);
     286           0 :         THREAD_OFF(bsrp->g2rp_timer);
     287           0 :         bsgrp_node = bsrp->bsgrp_node;
     288             : 
     289             :         /* elapse time is the hold time of expired node */
     290           0 :         elapse = bsrp->rp_holdtime;
     291           0 :         bsrp_addr = bsrp->rp_address;
     292             : 
     293             :         /* update elapse for all bsrp nodes */
     294           0 :         frr_each_safe (bsm_rpinfos, bsgrp_node->bsrp_list, bsrp_node) {
     295           0 :                 bsrp_node->elapse_time += elapse;
     296             : 
     297           0 :                 if (is_hold_time_elapsed(bsrp_node)) {
     298           0 :                         bsm_rpinfos_del(bsgrp_node->bsrp_list, bsrp_node);
     299           0 :                         pim_bsm_rpinfo_free(bsrp_node);
     300             :                 }
     301             :         }
     302             : 
     303             :         /* Get the next elected rp node */
     304           0 :         bsrp = bsm_rpinfos_first(bsgrp_node->bsrp_list);
     305           0 :         pim = bsgrp_node->scope->pim;
     306           0 :         rn = route_node_lookup(pim->rp_table, &bsgrp_node->group);
     307             : 
     308           0 :         if (!rn) {
     309           0 :                 zlog_warn("%s: Route node doesn't exist", __func__);
     310           0 :                 return;
     311             :         }
     312             : 
     313           0 :         rp_info = (struct rp_info *)rn->info;
     314             : 
     315           0 :         if (!rp_info) {
     316           0 :                 route_unlock_node(rn);
     317           0 :                 return;
     318             :         }
     319             : 
     320           0 :         if (rp_info->rp_src != RP_SRC_STATIC) {
     321             :                 /* If new rp available, change it else delete the existing */
     322           0 :                 if (bsrp) {
     323           0 :                         pim_g2rp_timer_start(
     324           0 :                                 bsrp, (bsrp->rp_holdtime - bsrp->elapse_time));
     325           0 :                         pim_rp_change(pim, bsrp->rp_address, bsgrp_node->group,
     326             :                                       RP_SRC_BSR);
     327             :                 } else {
     328           0 :                         pim_rp_del(pim, bsrp_addr, bsgrp_node->group, NULL,
     329             :                                    RP_SRC_BSR);
     330             :                 }
     331             :         }
     332             : 
     333           0 :         if (!bsm_rpinfos_count(bsgrp_node->bsrp_list)
     334           0 :             && !bsm_rpinfos_count(bsgrp_node->partial_bsrp_list)) {
     335           0 :                 pim_free_bsgrp_node(pim->global_scope.bsrp_table,
     336             :                                     &bsgrp_node->group);
     337           0 :                 pim_free_bsgrp_data(bsgrp_node);
     338             :         }
     339             : }
     340             : 
     341           0 : static void pim_g2rp_timer_start(struct bsm_rpinfo *bsrp, int hold_time)
     342             : {
     343           0 :         if (!bsrp) {
     344           0 :                 if (PIM_DEBUG_BSM)
     345           0 :                         zlog_debug("%s : Invalid brsp(NULL).", __func__);
     346           0 :                 return;
     347             :         }
     348           0 :         THREAD_OFF(bsrp->g2rp_timer);
     349           0 :         if (PIM_DEBUG_BSM)
     350           0 :                 zlog_debug(
     351             :                         "%s : starting g2rp timer for grp: %pFX - rp: %pPAs with timeout  %d secs(Actual Hold time : %d secs)",
     352             :                         __func__, &bsrp->bsgrp_node->group, &bsrp->rp_address,
     353             :                         hold_time, bsrp->rp_holdtime);
     354             : 
     355           0 :         thread_add_timer(router->master, pim_on_g2rp_timer, bsrp, hold_time,
     356             :                          &bsrp->g2rp_timer);
     357             : }
     358             : 
     359           0 : static inline void pim_g2rp_timer_restart(struct bsm_rpinfo *bsrp,
     360             :                                           int hold_time)
     361             : {
     362           0 :         pim_g2rp_timer_start(bsrp, hold_time);
     363           0 : }
     364             : 
     365           0 : static void pim_g2rp_timer_stop(struct bsm_rpinfo *bsrp)
     366             : {
     367           0 :         if (!bsrp)
     368             :                 return;
     369             : 
     370           0 :         if (PIM_DEBUG_BSM)
     371           0 :                 zlog_debug("%s : stopping g2rp timer for grp: %pFX - rp: %pPAs",
     372             :                            __func__, &bsrp->bsgrp_node->group,
     373             :                            &bsrp->rp_address);
     374             : 
     375           0 :         THREAD_OFF(bsrp->g2rp_timer);
     376             : }
     377             : 
     378           0 : static bool is_hold_time_zero(void *data)
     379             : {
     380           0 :         struct bsm_rpinfo *bsrp;
     381             : 
     382           0 :         bsrp = data;
     383             : 
     384           0 :         if (bsrp->rp_holdtime)
     385             :                 return false;
     386             :         else
     387           0 :                 return true;
     388             : }
     389             : 
     390           0 : static void pim_instate_pend_list(struct bsgrp_node *bsgrp_node)
     391             : {
     392           0 :         struct bsm_rpinfo *active;
     393           0 :         struct bsm_rpinfo *pend;
     394           0 :         struct rp_info *rp_info;
     395           0 :         struct route_node *rn;
     396           0 :         struct pim_instance *pim;
     397           0 :         struct rp_info *rp_all;
     398           0 :         struct prefix group_all;
     399           0 :         bool had_rp_node = true;
     400             : 
     401           0 :         pim = bsgrp_node->scope->pim;
     402           0 :         active = bsm_rpinfos_first(bsgrp_node->bsrp_list);
     403             : 
     404             :         /* Remove nodes with hold time 0 & check if list still has a head */
     405           0 :         frr_each_safe (bsm_rpinfos, bsgrp_node->partial_bsrp_list, pend) {
     406           0 :                 if (is_hold_time_zero(pend)) {
     407           0 :                         bsm_rpinfos_del(bsgrp_node->partial_bsrp_list, pend);
     408           0 :                         pim_bsm_rpinfo_free(pend);
     409             :                 }
     410             :         }
     411             : 
     412           0 :         pend = bsm_rpinfos_first(bsgrp_node->partial_bsrp_list);
     413             : 
     414           0 :         if (!pim_get_all_mcast_group(&group_all))
     415           0 :                 return;
     416             : 
     417           0 :         rp_all = pim_rp_find_match_group(pim, &group_all);
     418           0 :         rn = route_node_lookup(pim->rp_table, &bsgrp_node->group);
     419             : 
     420           0 :         if (pend)
     421           0 :                 pim_g2rp_timer_start(pend, pend->rp_holdtime);
     422             : 
     423             :         /* if rp node doesn't exist or exist but not configured(rp_all),
     424             :          * install the rp from head(if exists) of partial list. List is
     425             :          * is sorted such that head is the elected RP for the group.
     426             :          */
     427           0 :         if (!rn || (prefix_same(&rp_all->group, &bsgrp_node->group) &&
     428           0 :                     pim_rpf_addr_is_inaddr_any(&rp_all->rp))) {
     429           0 :                 if (PIM_DEBUG_BSM)
     430           0 :                         zlog_debug("%s: Route node doesn't exist", __func__);
     431           0 :                 if (pend)
     432           0 :                         pim_rp_new(pim, pend->rp_address, bsgrp_node->group,
     433             :                                    NULL, RP_SRC_BSR);
     434             :                 had_rp_node = false;
     435             :         } else {
     436           0 :                 rp_info = (struct rp_info *)rn->info;
     437           0 :                 if (!rp_info) {
     438           0 :                         route_unlock_node(rn);
     439           0 :                         if (pend)
     440           0 :                                 pim_rp_new(pim, pend->rp_address,
     441             :                                            bsgrp_node->group, NULL, RP_SRC_BSR);
     442             :                         had_rp_node = false;
     443             :                 }
     444             :         }
     445             : 
     446             :         /* We didn't have rp node and pending list is empty(unlikely), cleanup*/
     447           0 :         if ((!had_rp_node) && (!pend)) {
     448           0 :                 pim_free_bsgrp_node(bsgrp_node->scope->bsrp_table,
     449             :                                     &bsgrp_node->group);
     450           0 :                 pim_free_bsgrp_data(bsgrp_node);
     451           0 :                 return;
     452             :         }
     453             : 
     454           0 :         if ((had_rp_node) && (rp_info->rp_src != RP_SRC_STATIC)) {
     455             :                 /* This means we searched and got rp node, needs unlock */
     456           0 :                 route_unlock_node(rn);
     457             : 
     458           0 :                 if (active && pend) {
     459           0 :                         if (pim_addr_cmp(active->rp_address, pend->rp_address))
     460           0 :                                 pim_rp_change(pim, pend->rp_address,
     461             :                                               bsgrp_node->group, RP_SRC_BSR);
     462             :                 }
     463             : 
     464             :                 /* Possible when the first BSM has group with 0 rp count */
     465           0 :                 if ((!active) && (!pend)) {
     466           0 :                         if (PIM_DEBUG_BSM) {
     467           0 :                                 zlog_debug(
     468             :                                         "%s: Both bsrp and partial list are empty",
     469             :                                         __func__);
     470             :                         }
     471           0 :                         pim_free_bsgrp_node(bsgrp_node->scope->bsrp_table,
     472             :                                             &bsgrp_node->group);
     473           0 :                         pim_free_bsgrp_data(bsgrp_node);
     474           0 :                         return;
     475             :                 }
     476             : 
     477             :                 /* Possible when a group with 0 rp count received in BSM */
     478           0 :                 if ((active) && (!pend)) {
     479           0 :                         pim_rp_del(pim, active->rp_address, bsgrp_node->group,
     480             :                                    NULL, RP_SRC_BSR);
     481           0 :                         pim_free_bsgrp_node(bsgrp_node->scope->bsrp_table,
     482             :                                             &bsgrp_node->group);
     483           0 :                         if (PIM_DEBUG_BSM) {
     484           0 :                                 zlog_debug("%s:Pend List is null,del grp node",
     485             :                                            __func__);
     486             :                         }
     487           0 :                         pim_free_bsgrp_data(bsgrp_node);
     488           0 :                         return;
     489             :                 }
     490             :         }
     491             : 
     492           0 :         if ((had_rp_node) && (rp_info->rp_src == RP_SRC_STATIC)) {
     493             :                 /* We need to unlock rn this case */
     494           0 :                 route_unlock_node(rn);
     495             :                 /* there is a chance that static rp exist and bsrp cleaned
     496             :                  * so clean bsgrp node if pending list empty
     497             :                  */
     498           0 :                 if (!pend) {
     499           0 :                         if (PIM_DEBUG_BSM)
     500           0 :                                 zlog_debug(
     501             :                                         "%s: Partial list is empty, static rp exists",
     502             :                                         __func__);
     503           0 :                         pim_free_bsgrp_node(bsgrp_node->scope->bsrp_table,
     504             :                                             &bsgrp_node->group);
     505           0 :                         pim_free_bsgrp_data(bsgrp_node);
     506           0 :                         return;
     507             :                 }
     508             :         }
     509             : 
     510             :         /* swap the list & delete all nodes in partial list (old bsrp_list)
     511             :          * before swap
     512             :          *    active is head of bsrp list
     513             :          *    pend is head of partial list
     514             :          * After swap
     515             :          *    active is head of partial list
     516             :          *    pend is head of bsrp list
     517             :          * So check appriate head after swap and clean the new partial list
     518             :          */
     519           0 :         bsm_rpinfos_swap_all(bsgrp_node->bsrp_list,
     520             :                              bsgrp_node->partial_bsrp_list);
     521             : 
     522           0 :         if (active)
     523           0 :                 pim_g2rp_timer_stop(active);
     524           0 :         pim_bsm_rpinfos_free(bsgrp_node->partial_bsrp_list);
     525             : }
     526             : 
     527          24 : static bool is_preferred_bsr(struct pim_instance *pim, pim_addr bsr,
     528             :                              uint32_t bsr_prio)
     529             : {
     530          24 :         if (!pim_addr_cmp(bsr, pim->global_scope.current_bsr))
     531             :                 return true;
     532             : 
     533          12 :         if (bsr_prio > pim->global_scope.current_bsr_prio)
     534             :                 return true;
     535             : 
     536           0 :         else if (bsr_prio == pim->global_scope.current_bsr_prio) {
     537           0 :                 if (pim_addr_cmp(bsr, pim->global_scope.current_bsr) >= 0)
     538             :                         return true;
     539             :                 else
     540             :                         return false;
     541             :         } else
     542             :                 return false;
     543             : }
     544             : 
     545           8 : static void pim_bsm_update(struct pim_instance *pim, pim_addr bsr,
     546             :                            uint32_t bsr_prio)
     547             : {
     548           8 :         if (pim_addr_cmp(bsr, pim->global_scope.current_bsr)) {
     549           4 :                 pim_nht_bsr_del(pim, pim->global_scope.current_bsr);
     550           4 :                 pim_nht_bsr_add(pim, bsr);
     551             : 
     552           4 :                 pim->global_scope.current_bsr = bsr;
     553           8 :                 pim->global_scope.current_bsr_first_ts =
     554           4 :                         pim_time_monotonic_sec();
     555           4 :                 pim->global_scope.state = ACCEPT_PREFERRED;
     556             :         }
     557           8 :         pim->global_scope.current_bsr_prio = bsr_prio;
     558           8 :         pim->global_scope.current_bsr_last_ts = pim_time_monotonic_sec();
     559           8 : }
     560             : 
     561           0 : void pim_bsm_clear(struct pim_instance *pim)
     562             : {
     563           0 :         struct route_node *rn;
     564           0 :         struct route_node *rpnode;
     565           0 :         struct bsgrp_node *bsgrp;
     566           0 :         pim_addr nht_p;
     567           0 :         struct prefix g_all;
     568           0 :         struct rp_info *rp_all;
     569           0 :         struct pim_upstream *up;
     570           0 :         struct rp_info *rp_info;
     571           0 :         bool upstream_updated = false;
     572             : 
     573           0 :         pim_nht_bsr_del(pim, pim->global_scope.current_bsr);
     574             : 
     575             :         /* Reset scope zone data */
     576           0 :         pim->global_scope.accept_nofwd_bsm = false;
     577           0 :         pim->global_scope.state = ACCEPT_ANY;
     578           0 :         pim->global_scope.current_bsr = PIMADDR_ANY;
     579           0 :         pim->global_scope.current_bsr_prio = 0;
     580           0 :         pim->global_scope.current_bsr_first_ts = 0;
     581           0 :         pim->global_scope.current_bsr_last_ts = 0;
     582           0 :         pim->global_scope.bsm_frag_tag = 0;
     583           0 :         pim_bsm_frags_free(&pim->global_scope);
     584             : 
     585           0 :         pim_bs_timer_stop(&pim->global_scope);
     586             : 
     587           0 :         for (rn = route_top(pim->global_scope.bsrp_table); rn;
     588           0 :              rn = route_next(rn)) {
     589           0 :                 bsgrp = rn->info;
     590           0 :                 if (!bsgrp)
     591           0 :                         continue;
     592             : 
     593           0 :                 rpnode = route_node_lookup(pim->rp_table, &bsgrp->group);
     594             : 
     595           0 :                 if (!rpnode) {
     596           0 :                         pim_free_bsgrp_node(bsgrp->scope->bsrp_table,
     597             :                                             &bsgrp->group);
     598           0 :                         pim_free_bsgrp_data(bsgrp);
     599           0 :                         continue;
     600             :                 }
     601             : 
     602           0 :                 rp_info = (struct rp_info *)rpnode->info;
     603             : 
     604           0 :                 if ((!rp_info) || (rp_info->rp_src != RP_SRC_BSR)) {
     605           0 :                         pim_free_bsgrp_node(bsgrp->scope->bsrp_table,
     606             :                                             &bsgrp->group);
     607           0 :                         pim_free_bsgrp_data(bsgrp);
     608           0 :                         continue;
     609             :                 }
     610             : 
     611             :                 /* Deregister addr with Zebra NHT */
     612           0 :                 nht_p = rp_info->rp.rpf_addr;
     613             : 
     614           0 :                 if (PIM_DEBUG_PIM_NHT_RP) {
     615           0 :                         zlog_debug("%s: Deregister RP addr %pPA with Zebra ",
     616             :                                    __func__, &nht_p);
     617             :                 }
     618             : 
     619           0 :                 pim_delete_tracked_nexthop(pim, nht_p, NULL, rp_info);
     620             : 
     621           0 :                 if (!pim_get_all_mcast_group(&g_all))
     622           0 :                         return;
     623             : 
     624           0 :                 rp_all = pim_rp_find_match_group(pim, &g_all);
     625             : 
     626           0 :                 if (rp_all == rp_info) {
     627           0 :                         rp_all->rp.rpf_addr = PIMADDR_ANY;
     628           0 :                         rp_all->i_am_rp = 0;
     629             :                 } else {
     630             :                         /* Delete the rp_info from rp-list */
     631           0 :                         listnode_delete(pim->rp_list, rp_info);
     632             : 
     633             :                         /* Delete the rp node from rp_table */
     634           0 :                         rpnode->info = NULL;
     635           0 :                         route_unlock_node(rpnode);
     636           0 :                         route_unlock_node(rpnode);
     637           0 :                         XFREE(MTYPE_PIM_RP, rp_info);
     638             :                 }
     639             : 
     640           0 :                 pim_free_bsgrp_node(bsgrp->scope->bsrp_table, &bsgrp->group);
     641           0 :                 pim_free_bsgrp_data(bsgrp);
     642             :         }
     643           0 :         pim_rp_refresh_group_to_rp_mapping(pim);
     644             : 
     645             : 
     646           0 :         frr_each (rb_pim_upstream, &pim->upstream_head, up) {
     647             :                 /* Find the upstream (*, G) whose upstream address is same as
     648             :                  * the RP
     649             :                  */
     650           0 :                 if (!pim_addr_is_any(up->sg.src))
     651           0 :                         continue;
     652             : 
     653           0 :                 struct prefix grp;
     654           0 :                 struct rp_info *trp_info;
     655             : 
     656           0 :                 pim_addr_to_prefix(&grp, up->sg.grp);
     657           0 :                 trp_info = pim_rp_find_match_group(pim, &grp);
     658             : 
     659             :                 /* RP not found for the group grp */
     660           0 :                 if (pim_rpf_addr_is_inaddr_any(&trp_info->rp)) {
     661           0 :                         pim_upstream_rpf_clear(pim, up);
     662           0 :                         pim_rp_set_upstream_addr(pim, &up->upstream_addr,
     663             :                                                  up->sg.src, up->sg.grp);
     664             :                 } else {
     665             :                         /* RP found for the group grp */
     666           0 :                         pim_upstream_update(pim, up);
     667           0 :                         upstream_updated = true;
     668             :                 }
     669             :         }
     670             : 
     671           0 :         if (upstream_updated)
     672           0 :                 pim_zebra_update_all_interfaces(pim);
     673             : }
     674             : 
     675           8 : static bool pim_bsm_send_intf(uint8_t *buf, int len, struct interface *ifp,
     676             :                               pim_addr dst_addr)
     677             : {
     678           8 :         struct pim_interface *pim_ifp;
     679             : 
     680           8 :         pim_ifp = ifp->info;
     681             : 
     682           8 :         if (!pim_ifp) {
     683           0 :                 if (PIM_DEBUG_BSM)
     684           0 :                         zlog_debug("%s: Pim interface not available for %s",
     685             :                                    __func__, ifp->name);
     686           0 :                 return false;
     687             :         }
     688             : 
     689           8 :         if (pim_ifp->pim_sock_fd == -1) {
     690           0 :                 if (PIM_DEBUG_BSM)
     691           0 :                         zlog_debug("%s: Pim sock not available for %s",
     692             :                                    __func__, ifp->name);
     693           0 :                 return false;
     694             :         }
     695             : 
     696           8 :         if (pim_msg_send(pim_ifp->pim_sock_fd, pim_ifp->primary_address,
     697             :                          dst_addr, buf, len, ifp)) {
     698           0 :                 zlog_warn("%s: Could not send BSM message on interface: %s",
     699             :                           __func__, ifp->name);
     700           0 :                 return false;
     701             :         }
     702             : 
     703           8 :         if (!pim_ifp->pim_passive_enable)
     704           8 :                 pim_ifp->pim_ifstat_bsm_tx++;
     705             : 
     706           8 :         pim_ifp->pim->bsm_sent++;
     707           8 :         return true;
     708             : }
     709             : 
     710           0 : static bool pim_bsm_frag_send(uint8_t *buf, uint32_t len, struct interface *ifp,
     711             :                               uint32_t pim_mtu, pim_addr dst_addr, bool no_fwd)
     712             : {
     713           0 :         struct pim_interface *pim_ifp = ifp->info;
     714           0 :         struct bsmmsg_grpinfo *grpinfo, *curgrp;
     715           0 :         uint8_t *firstgrp_ptr;
     716           0 :         uint8_t *pkt;
     717           0 :         uint8_t *pak_start;
     718           0 :         uint32_t parsed_len = 0;
     719           0 :         uint32_t this_pkt_rem;
     720           0 :         uint32_t copy_byte_count;
     721           0 :         uint32_t this_pkt_len;
     722           0 :         uint8_t total_rp_cnt;
     723           0 :         uint8_t this_rp_cnt;
     724           0 :         uint8_t frag_rp_cnt;
     725           0 :         uint8_t rp_fit_cnt;
     726           0 :         bool pak_pending = false;
     727             : 
     728             :         /* MTU  passed here is PIM MTU (IP MTU less IP Hdr) */
     729           0 :         if (pim_mtu < (PIM_MIN_BSM_LEN)) {
     730           0 :                 zlog_warn(
     731             :                         "%s: mtu(pim mtu: %d) size less than minimum bootstrap len",
     732             :                         __func__, pim_mtu);
     733           0 :                 if (PIM_DEBUG_BSM)
     734           0 :                         zlog_debug(
     735             :                                 "%s: mtu (pim mtu:%d) less than minimum bootstrap len",
     736             :                                 __func__, pim_mtu);
     737           0 :                 return false;
     738             :         }
     739             : 
     740           0 :         pak_start = XCALLOC(MTYPE_PIM_BSM_PKT_VAR_MEM, pim_mtu);
     741             : 
     742           0 :         pkt = pak_start;
     743             : 
     744             :         /* Fill PIM header later before sending packet to calc checksum */
     745           0 :         pkt += PIM_MSG_HEADER_LEN;
     746           0 :         buf += PIM_MSG_HEADER_LEN;
     747             : 
     748             :         /* copy bsm header to new packet at offset of pim hdr */
     749           0 :         memcpy(pkt, buf, PIM_BSM_HDR_LEN);
     750           0 :         pkt += PIM_BSM_HDR_LEN;
     751           0 :         buf += PIM_BSM_HDR_LEN;
     752           0 :         parsed_len += (PIM_MSG_HEADER_LEN + PIM_BSM_HDR_LEN);
     753             : 
     754             :         /* Store the position of first grp ptr, which can be reused for
     755             :          * next packet to start filling group. old bsm header and pim hdr
     756             :          * remains. So need not be filled again for next packet onwards.
     757             :          */
     758           0 :         firstgrp_ptr = pkt;
     759             : 
     760             :         /* we received mtu excluding IP hdr len as param
     761             :          * now this_pkt_rem is mtu excluding
     762             :          * PIM_BSM_HDR_LEN + PIM_MSG_HEADER_LEN
     763             :          */
     764           0 :         this_pkt_rem = pim_mtu - (PIM_BSM_HDR_LEN + PIM_MSG_HEADER_LEN);
     765             : 
     766             :         /* For each group till the packet length parsed */
     767           0 :         while (parsed_len < len) {
     768             :                 /* pkt            ---> fragment's current pointer
     769             :                  * buf            ---> input buffer's current pointer
     770             :                  * mtu            ---> size of the pim packet - PIM header
     771             :                  * curgrp         ---> current group on the fragment
     772             :                  * grpinfo        ---> current group on the input buffer
     773             :                  * this_pkt_rem   ---> bytes remaing on the current fragment
     774             :                  * rp_fit_cnt     ---> num of rp for current grp that
     775             :                  *                     fits this frag
     776             :                  * total_rp_cnt   ---> total rp present for the group in the buf
     777             :                  * frag_rp_cnt    ---> no of rp for the group to be fit in
     778             :                  *                     the frag
     779             :                  * this_rp_cnt    ---> how many rp have we parsed
     780             :                  */
     781           0 :                 grpinfo = (struct bsmmsg_grpinfo *)buf;
     782           0 :                 memcpy(pkt, buf, PIM_BSM_GRP_LEN);
     783           0 :                 curgrp = (struct bsmmsg_grpinfo *)pkt;
     784           0 :                 parsed_len += PIM_BSM_GRP_LEN;
     785           0 :                 pkt += PIM_BSM_GRP_LEN;
     786           0 :                 buf += PIM_BSM_GRP_LEN;
     787           0 :                 this_pkt_rem -= PIM_BSM_GRP_LEN;
     788             : 
     789             :                 /* initialize rp count and total_rp_cnt before the rp loop */
     790           0 :                 this_rp_cnt = 0;
     791           0 :                 total_rp_cnt = grpinfo->frag_rp_count;
     792             : 
     793             :                 /* Loop till all RPs for the group parsed */
     794           0 :                 while (this_rp_cnt < total_rp_cnt) {
     795             :                         /* All RP from a group processed here.
     796             :                          * group is pointed by grpinfo.
     797             :                          * At this point make sure buf pointing to a RP
     798             :                          * within a group
     799             :                          */
     800           0 :                         rp_fit_cnt = this_pkt_rem / PIM_BSM_RP_LEN;
     801             : 
     802             :                         /* calculate how many rp am i going to copy in
     803             :                          * this frag
     804             :                          */
     805           0 :                         if (rp_fit_cnt > (total_rp_cnt - this_rp_cnt))
     806           0 :                                 frag_rp_cnt = total_rp_cnt - this_rp_cnt;
     807             :                         else
     808             :                                 frag_rp_cnt = rp_fit_cnt;
     809             : 
     810             :                         /* populate the frag rp count for the current grp */
     811           0 :                         curgrp->frag_rp_count = frag_rp_cnt;
     812           0 :                         copy_byte_count = frag_rp_cnt * PIM_BSM_RP_LEN;
     813             : 
     814             :                         /* copy all the rp that we are fitting in this
     815             :                          * frag for the grp
     816             :                          */
     817           0 :                         memcpy(pkt, buf, copy_byte_count);
     818           0 :                         this_rp_cnt += frag_rp_cnt;
     819           0 :                         buf += copy_byte_count;
     820           0 :                         pkt += copy_byte_count;
     821           0 :                         parsed_len += copy_byte_count;
     822           0 :                         this_pkt_rem -= copy_byte_count;
     823             : 
     824             :                         /* Either we couldn't fit all rp for the group or the
     825             :                          * mtu reached
     826             :                          */
     827           0 :                         if ((this_rp_cnt < total_rp_cnt)
     828           0 :                             || (this_pkt_rem
     829           0 :                                 < (PIM_BSM_GRP_LEN + PIM_BSM_RP_LEN))) {
     830             :                                 /* No space to fit in more rp, send this pkt */
     831           0 :                                 this_pkt_len = pim_mtu - this_pkt_rem;
     832           0 :                                 pim_msg_build_header(
     833             :                                         pim_ifp->primary_address, dst_addr,
     834             :                                         pak_start, this_pkt_len,
     835             :                                         PIM_MSG_TYPE_BOOTSTRAP, no_fwd);
     836           0 :                                 pim_bsm_send_intf(pak_start, this_pkt_len, ifp,
     837             :                                                   dst_addr);
     838             : 
     839             :                                 /* Construct next fragment. Reuse old packet */
     840           0 :                                 pkt = firstgrp_ptr;
     841           0 :                                 this_pkt_rem = pim_mtu - (PIM_BSM_HDR_LEN
     842             :                                                           + PIM_MSG_HEADER_LEN);
     843             : 
     844             :                                 /* If pkt can't accommodate next group + at
     845             :                                  * least one rp, we must break out of this inner
     846             :                                  * loop and process next RP
     847             :                                  */
     848           0 :                                 if (total_rp_cnt == this_rp_cnt)
     849             :                                         break;
     850             : 
     851             :                                 /* If some more RPs for the same group pending,
     852             :                                  * fill grp hdr
     853             :                                  */
     854           0 :                                 memcpy(pkt, (uint8_t *)grpinfo,
     855             :                                        PIM_BSM_GRP_LEN);
     856           0 :                                 curgrp = (struct bsmmsg_grpinfo *)pkt;
     857           0 :                                 pkt += PIM_BSM_GRP_LEN;
     858           0 :                                 this_pkt_rem -= PIM_BSM_GRP_LEN;
     859           0 :                                 pak_pending = false;
     860             :                         } else {
     861             :                                 /* We filled something but not yet sent out */
     862             :                                 pak_pending = true;
     863             :                         }
     864             :                 } /* while RP count */
     865             :         }        /*while parsed len */
     866             : 
     867             :         /* Send if we have any unsent packet */
     868           0 :         if (pak_pending) {
     869           0 :                 this_pkt_len = pim_mtu - this_pkt_rem;
     870           0 :                 pim_msg_build_header(pim_ifp->primary_address, dst_addr,
     871             :                                      pak_start, this_pkt_len,
     872             :                                      PIM_MSG_TYPE_BOOTSTRAP, no_fwd);
     873           0 :                 pim_bsm_send_intf(pak_start, (pim_mtu - this_pkt_rem), ifp,
     874             :                                   dst_addr);
     875             :         }
     876           0 :         XFREE(MTYPE_PIM_BSM_PKT_VAR_MEM, pak_start);
     877           0 :         return true;
     878             : }
     879             : 
     880           8 : static void pim_bsm_fwd_whole_sz(struct pim_instance *pim, uint8_t *buf,
     881             :                                  uint32_t len, int sz)
     882             : {
     883           8 :         struct interface *ifp;
     884           8 :         struct pim_interface *pim_ifp;
     885           8 :         pim_addr dst_addr;
     886           8 :         uint32_t pim_mtu;
     887           8 :         bool no_fwd = false;
     888           8 :         bool ret = false;
     889             : 
     890             :         /* For now only global scope zone is supported, so send on all
     891             :          * pim interfaces in the vrf
     892             :          */
     893           8 :         dst_addr = qpim_all_pim_routers_addr;
     894          40 :         FOR_ALL_INTERFACES (pim->vrf, ifp) {
     895          24 :                 pim_ifp = ifp->info;
     896          24 :                 if ((!pim_ifp) || (!pim_ifp->bsm_enable))
     897           0 :                         continue;
     898             : 
     899             :                 /*
     900             :                  * RFC 5059 Sec 3.4:
     901             :                  * When a Bootstrap message is forwarded, it is forwarded out
     902             :                  * of every multicast-capable interface that has PIM neighbors.
     903             :                  *
     904             :                  * So skipping pim interfaces with no neighbors.
     905             :                  */
     906          24 :                 if (listcount(pim_ifp->pim_neighbor_list) == 0)
     907          16 :                         continue;
     908             : 
     909           8 :                 pim_hello_require(ifp);
     910           8 :                 pim_mtu = ifp->mtu - MAX_IP_HDR_LEN;
     911           8 :                 if (pim_mtu < len) {
     912           0 :                         ret = pim_bsm_frag_send(buf, len, ifp, pim_mtu,
     913             :                                                 dst_addr, no_fwd);
     914           0 :                         if (PIM_DEBUG_BSM)
     915           0 :                                 zlog_debug("%s: pim_bsm_frag_send returned %s",
     916             :                                            __func__, ret ? "TRUE" : "FALSE");
     917             :                 } else {
     918           8 :                         pim_msg_build_header(pim_ifp->primary_address, dst_addr,
     919             :                                              buf, len, PIM_MSG_TYPE_BOOTSTRAP,
     920             :                                              no_fwd);
     921           8 :                         if (!pim_bsm_send_intf(buf, len, ifp, dst_addr)) {
     922           0 :                                 if (PIM_DEBUG_BSM)
     923          24 :                                         zlog_debug(
     924             :                                                 "%s: pim_bsm_send_intf returned false",
     925             :                                                 __func__);
     926             :                         }
     927             :                 }
     928             :         }
     929           8 : }
     930             : 
     931          38 : bool pim_bsm_new_nbr_fwd(struct pim_neighbor *neigh, struct interface *ifp)
     932             : {
     933          38 :         pim_addr dst_addr;
     934          38 :         struct pim_interface *pim_ifp;
     935          38 :         struct bsm_scope *scope;
     936          38 :         struct bsm_frag *bsfrag;
     937          38 :         uint32_t pim_mtu;
     938          38 :         bool no_fwd = true;
     939          38 :         bool ret = false;
     940             : 
     941          38 :         if (PIM_DEBUG_BSM)
     942          12 :                 zlog_debug("%s: New neighbor %pPA seen on %s", __func__,
     943             :                            &neigh->source_addr, ifp->name);
     944             : 
     945          38 :         pim_ifp = ifp->info;
     946             : 
     947             :         /* DR only forwards BSM packet */
     948          38 :         if (!pim_addr_cmp(pim_ifp->pim_dr_addr, pim_ifp->primary_address)) {
     949          17 :                 if (PIM_DEBUG_BSM)
     950           4 :                         zlog_debug(
     951             :                                 "%s: It is not DR, so don't forward BSM packet",
     952             :                                 __func__);
     953             :         }
     954             : 
     955          38 :         if (!pim_ifp->bsm_enable) {
     956           0 :                 if (PIM_DEBUG_BSM)
     957           0 :                         zlog_debug("%s: BSM proc not enabled on %s", __func__,
     958             :                                    ifp->name);
     959           0 :                 return ret;
     960             :         }
     961             : 
     962          38 :         scope = &pim_ifp->pim->global_scope;
     963             : 
     964          38 :         if (!bsm_frags_count(scope->bsm_frags)) {
     965          38 :                 if (PIM_DEBUG_BSM)
     966          12 :                         zlog_debug("%s: BSM list for the scope is empty",
     967             :                                    __func__);
     968          38 :                 return ret;
     969             :         }
     970             : 
     971           0 :         if (!pim_ifp->ucast_bsm_accept) {
     972           0 :                 dst_addr = qpim_all_pim_routers_addr;
     973           0 :                 if (PIM_DEBUG_BSM)
     974           0 :                         zlog_debug("%s: Sending BSM mcast to %pPA", __func__,
     975             :                                    &neigh->source_addr);
     976             :         } else {
     977           0 :                 dst_addr = neigh->source_addr;
     978           0 :                 if (PIM_DEBUG_BSM)
     979           0 :                         zlog_debug("%s: Sending BSM ucast to %pPA", __func__,
     980             :                                    &neigh->source_addr);
     981             :         }
     982           0 :         pim_mtu = ifp->mtu - MAX_IP_HDR_LEN;
     983           0 :         pim_hello_require(ifp);
     984             : 
     985           0 :         frr_each (bsm_frags, scope->bsm_frags, bsfrag) {
     986           0 :                 if (pim_mtu < bsfrag->size) {
     987           0 :                         ret = pim_bsm_frag_send(bsfrag->data, bsfrag->size, ifp,
     988             :                                                 pim_mtu, dst_addr, no_fwd);
     989           0 :                         if (!ret) {
     990           0 :                                 if (PIM_DEBUG_BSM)
     991           0 :                                         zlog_debug(
     992             :                                                 "%s: pim_bsm_frag_send failed",
     993             :                                                 __func__);
     994             :                         }
     995             :                 } else {
     996             :                         /* Pim header needs to be constructed */
     997           0 :                         pim_msg_build_header(pim_ifp->primary_address, dst_addr,
     998           0 :                                              bsfrag->data, bsfrag->size,
     999             :                                              PIM_MSG_TYPE_BOOTSTRAP, no_fwd);
    1000           0 :                         ret = pim_bsm_send_intf(bsfrag->data, bsfrag->size, ifp,
    1001             :                                                 dst_addr);
    1002           0 :                         if (!ret) {
    1003           0 :                                 if (PIM_DEBUG_BSM)
    1004           0 :                                         zlog_debug(
    1005             :                                                 "%s: pim_bsm_frag_send failed",
    1006             :                                                 __func__);
    1007             :                         }
    1008             :                 }
    1009             :         }
    1010             :         return ret;
    1011             : }
    1012             : 
    1013           0 : struct bsgrp_node *pim_bsm_get_bsgrp_node(struct bsm_scope *scope,
    1014             :                                           struct prefix *grp)
    1015             : {
    1016           0 :         struct route_node *rn;
    1017           0 :         struct bsgrp_node *bsgrp;
    1018             : 
    1019           0 :         rn = route_node_lookup(scope->bsrp_table, grp);
    1020           0 :         if (!rn) {
    1021           0 :                 if (PIM_DEBUG_BSM)
    1022           0 :                         zlog_debug("%s: Route node doesn't exist for the group",
    1023             :                                    __func__);
    1024           0 :                 return NULL;
    1025             :         }
    1026           0 :         bsgrp = rn->info;
    1027           0 :         route_unlock_node(rn);
    1028             : 
    1029           0 :         return bsgrp;
    1030             : }
    1031             : 
    1032           0 : static uint32_t hash_calc_on_grp_rp(struct prefix group, pim_addr rp,
    1033             :                                     uint8_t hashmasklen)
    1034             : {
    1035           0 :         uint64_t temp;
    1036           0 :         uint32_t hash;
    1037           0 :         uint32_t grpaddr;
    1038           0 :         uint32_t rp_add;
    1039           0 :         uint32_t mask = 0xffffffff;
    1040             : 
    1041             :         /* mask to be made zero if hashmasklen is 0 because mask << 32
    1042             :          * may not give 0. hashmasklen can be 0 to 32.
    1043             :          */
    1044           0 :         if (hashmasklen == 0)
    1045           0 :                 mask = 0;
    1046             : 
    1047             :         /* in_addr stores ip in big endian, hence network byte order
    1048             :          * convert to uint32 before processing hash
    1049             :          */
    1050             : #if PIM_IPV == 4
    1051           0 :         grpaddr = ntohl(group.u.prefix4.s_addr);
    1052             : #else
    1053           0 :         grpaddr = group.u.prefix6.s6_addr32[0] ^ group.u.prefix6.s6_addr32[1] ^
    1054           0 :                   group.u.prefix6.s6_addr32[2] ^ group.u.prefix6.s6_addr32[3];
    1055             : #endif
    1056             :         /* Avoid shifting by 32 bit on a 32 bit register */
    1057           0 :         if (hashmasklen)
    1058           0 :                 grpaddr = grpaddr & ((mask << (32 - hashmasklen)));
    1059             :         else
    1060           0 :                 grpaddr = grpaddr & mask;
    1061             : 
    1062             : #if PIM_IPV == 4
    1063           0 :         rp_add = ntohl(rp.s_addr);
    1064             : #else
    1065           0 :         rp_add = rp.s6_addr32[0] ^ rp.s6_addr32[1] ^ rp.s6_addr32[2] ^
    1066           0 :                  rp.s6_addr32[3];
    1067             : #endif
    1068           0 :         temp = 1103515245 * ((1103515245 * (uint64_t)grpaddr + 12345) ^ rp_add)
    1069             :                + 12345;
    1070           0 :         hash = temp & (0x7fffffff);
    1071           0 :         return hash;
    1072             : }
    1073             : 
    1074           0 : static bool pim_install_bsm_grp_rp(struct pim_instance *pim,
    1075             :                                    struct bsgrp_node *grpnode,
    1076             :                                    struct bsmmsg_rpinfo *rp)
    1077             : {
    1078           0 :         struct bsm_rpinfo *bsm_rpinfo;
    1079           0 :         uint8_t hashMask_len = pim->global_scope.hashMasklen;
    1080             : 
    1081             :         /*memory allocation for bsm_rpinfo */
    1082           0 :         bsm_rpinfo = XCALLOC(MTYPE_PIM_BSRP_INFO, sizeof(*bsm_rpinfo));
    1083             : 
    1084           0 :         bsm_rpinfo->rp_prio = rp->rp_pri;
    1085           0 :         bsm_rpinfo->rp_holdtime = rp->rp_holdtime;
    1086           0 :         bsm_rpinfo->rp_address = rp->rpaddr.addr;
    1087           0 :         bsm_rpinfo->elapse_time = 0;
    1088             : 
    1089             :         /* Back pointer to the group node. */
    1090           0 :         bsm_rpinfo->bsgrp_node = grpnode;
    1091             : 
    1092             :         /* update hash for this rp node */
    1093           0 :         bsm_rpinfo->hash = hash_calc_on_grp_rp(grpnode->group, rp->rpaddr.addr,
    1094             :                                                hashMask_len);
    1095           0 :         if (bsm_rpinfos_add(grpnode->partial_bsrp_list, bsm_rpinfo) == NULL) {
    1096           0 :                 if (PIM_DEBUG_BSM)
    1097           0 :                         zlog_debug(
    1098             :                                 "%s, bs_rpinfo node added to the partial bs_rplist.",
    1099             :                                 __func__);
    1100           0 :                 return true;
    1101             :         }
    1102             : 
    1103           0 :         if (PIM_DEBUG_BSM)
    1104           0 :                 zlog_debug("%s: list node not added", __func__);
    1105             : 
    1106           0 :         XFREE(MTYPE_PIM_BSRP_INFO, bsm_rpinfo);
    1107           0 :         return false;
    1108             : }
    1109             : 
    1110           0 : static void pim_update_pending_rp_cnt(struct bsm_scope *sz,
    1111             :                                       struct bsgrp_node *bsgrp,
    1112             :                                       uint16_t bsm_frag_tag,
    1113             :                                       uint32_t total_rp_count)
    1114             : {
    1115           0 :         if (bsgrp->pend_rp_cnt) {
    1116             :                 /* received bsm is different packet ,
    1117             :                  * it is not same fragment.
    1118             :                  */
    1119           0 :                 if (bsm_frag_tag != bsgrp->frag_tag) {
    1120           0 :                         if (PIM_DEBUG_BSM)
    1121           0 :                                 zlog_debug(
    1122             :                                         "%s,Received a new BSM ,so clear the pending bs_rpinfo list.",
    1123             :                                         __func__);
    1124           0 :                         pim_bsm_rpinfos_free(bsgrp->partial_bsrp_list);
    1125           0 :                         bsgrp->pend_rp_cnt = total_rp_count;
    1126             :                 }
    1127             :         } else
    1128           0 :                 bsgrp->pend_rp_cnt = total_rp_count;
    1129             : 
    1130           0 :         bsgrp->frag_tag = bsm_frag_tag;
    1131           0 : }
    1132             : 
    1133             : /* Parsing BSR packet and adding to partial list of corresponding bsgrp node */
    1134           8 : static bool pim_bsm_parse_install_g2rp(struct bsm_scope *scope, uint8_t *buf,
    1135             :                                        int buflen, uint16_t bsm_frag_tag)
    1136             : {
    1137           8 :         struct bsmmsg_grpinfo grpinfo;
    1138           8 :         struct bsmmsg_rpinfo rpinfo;
    1139           8 :         struct prefix group;
    1140           8 :         struct bsgrp_node *bsgrp = NULL;
    1141           8 :         int frag_rp_cnt = 0;
    1142           8 :         int offset = 0;
    1143           8 :         int ins_count = 0;
    1144           8 :         pim_addr grp_addr;
    1145             : 
    1146           8 :         while (buflen > offset) {
    1147           0 :                 if (offset + (int)sizeof(struct bsmmsg_grpinfo) > buflen) {
    1148           0 :                         if (PIM_DEBUG_BSM)
    1149           0 :                                 zlog_debug(
    1150             :                                         "%s: buflen received %d is less than the internal data structure of the packet would suggest",
    1151             :                                         __func__, buflen);
    1152           0 :                         return false;
    1153             :                 }
    1154             :                 /* Extract Group tlv from BSM */
    1155           0 :                 memcpy(&grpinfo, buf, sizeof(struct bsmmsg_grpinfo));
    1156           0 :                 grp_addr = grpinfo.group.addr;
    1157             : 
    1158           0 :                 if (PIM_DEBUG_BSM)
    1159           0 :                         zlog_debug(
    1160             :                                 "%s, Group %pPAs  Rpcount:%d Fragment-Rp-count:%d",
    1161             :                                 __func__, &grp_addr, grpinfo.rp_count,
    1162             :                                 grpinfo.frag_rp_count);
    1163             : 
    1164           0 :                 buf += sizeof(struct bsmmsg_grpinfo);
    1165           0 :                 offset += sizeof(struct bsmmsg_grpinfo);
    1166             : 
    1167           0 :                 group.family = PIM_AF;
    1168           0 :                 if (grpinfo.group.mask > PIM_MAX_BITLEN) {
    1169           0 :                         if (PIM_DEBUG_BSM)
    1170           0 :                                 zlog_debug(
    1171             :                                         "%s, prefix length specified: %d is too long",
    1172             :                                         __func__, grpinfo.group.mask);
    1173           0 :                         return false;
    1174             :                 }
    1175             : 
    1176           0 :                 pim_addr_to_prefix(&group, grp_addr);
    1177           0 :                 group.prefixlen = grpinfo.group.mask;
    1178             : 
    1179             :                 /* Get the Group node for the BSM rp table */
    1180           0 :                 bsgrp = pim_bsm_get_bsgrp_node(scope, &group);
    1181             : 
    1182           0 :                 if (grpinfo.rp_count == 0) {
    1183           0 :                         struct bsm_rpinfo *old_rpinfo;
    1184             : 
    1185             :                         /* BSR explicitly no longer has RPs for this group */
    1186           0 :                         if (!bsgrp)
    1187           0 :                                 continue;
    1188             : 
    1189           0 :                         if (PIM_DEBUG_BSM)
    1190           0 :                                 zlog_debug(
    1191             :                                         "%s, Rp count is zero for group: %pPAs",
    1192             :                                         __func__, &grp_addr);
    1193             : 
    1194           0 :                         old_rpinfo = bsm_rpinfos_first(bsgrp->bsrp_list);
    1195           0 :                         if (old_rpinfo)
    1196           0 :                                 pim_rp_del(scope->pim, old_rpinfo->rp_address,
    1197             :                                            group, NULL, RP_SRC_BSR);
    1198             : 
    1199           0 :                         pim_free_bsgrp_node(scope->bsrp_table, &bsgrp->group);
    1200           0 :                         pim_free_bsgrp_data(bsgrp);
    1201           0 :                         continue;
    1202             :                 }
    1203             : 
    1204           0 :                 if (!bsgrp) {
    1205           0 :                         if (PIM_DEBUG_BSM)
    1206           0 :                                 zlog_debug("%s, Create new  BSM Group node.",
    1207             :                                            __func__);
    1208             : 
    1209             :                         /* create a new node to be added to the tree. */
    1210           0 :                         bsgrp = pim_bsm_new_bsgrp_node(scope->bsrp_table,
    1211             :                                                        &group);
    1212             : 
    1213           0 :                         if (!bsgrp) {
    1214           0 :                                 zlog_debug(
    1215             :                                         "%s, Failed to get the BSM group node.",
    1216             :                                         __func__);
    1217           0 :                                 continue;
    1218             :                         }
    1219             : 
    1220           0 :                         bsgrp->scope = scope;
    1221             :                 }
    1222             : 
    1223           0 :                 pim_update_pending_rp_cnt(scope, bsgrp, bsm_frag_tag,
    1224             :                                           grpinfo.rp_count);
    1225           0 :                 frag_rp_cnt = grpinfo.frag_rp_count;
    1226           0 :                 ins_count = 0;
    1227             : 
    1228           0 :                 while (frag_rp_cnt--) {
    1229           0 :                         if (offset + (int)sizeof(struct bsmmsg_rpinfo)
    1230           0 :                             > buflen) {
    1231           0 :                                 if (PIM_DEBUG_BSM)
    1232           0 :                                         zlog_debug(
    1233             :                                                 "%s, buflen received: %u is less than the internal data structure of the packet would suggest",
    1234             :                                                 __func__, buflen);
    1235           0 :                                 return false;
    1236             :                         }
    1237             : 
    1238             :                         /* Extract RP address tlv from BSM */
    1239           0 :                         memcpy(&rpinfo, buf, sizeof(struct bsmmsg_rpinfo));
    1240           0 :                         rpinfo.rp_holdtime = ntohs(rpinfo.rp_holdtime);
    1241           0 :                         buf += sizeof(struct bsmmsg_rpinfo);
    1242           0 :                         offset += sizeof(struct bsmmsg_rpinfo);
    1243             : 
    1244           0 :                         if (PIM_DEBUG_BSM) {
    1245           0 :                                 pim_addr rp_addr;
    1246             : 
    1247           0 :                                 rp_addr = rpinfo.rpaddr.addr;
    1248           0 :                                 zlog_debug(
    1249             :                                         "%s, Rp address - %pPAs; pri:%d hold:%d",
    1250             :                                         __func__, &rp_addr, rpinfo.rp_pri,
    1251             :                                         rpinfo.rp_holdtime);
    1252             :                         }
    1253             : 
    1254             :                         /* Call Install api to update grp-rp mappings */
    1255           0 :                         if (pim_install_bsm_grp_rp(scope->pim, bsgrp, &rpinfo))
    1256           0 :                                 ins_count++;
    1257             :                 }
    1258             : 
    1259           0 :                 bsgrp->pend_rp_cnt -= ins_count;
    1260             : 
    1261           0 :                 if (!bsgrp->pend_rp_cnt) {
    1262           0 :                         if (PIM_DEBUG_BSM)
    1263           0 :                                 zlog_debug(
    1264             :                                         "%s, Recvd all the rps for this group, so bsrp list with penidng rp list.",
    1265             :                                         __func__);
    1266             :                         /* replace the bsrp_list with pending list */
    1267           0 :                         pim_instate_pend_list(bsgrp);
    1268             :                 }
    1269             :         }
    1270             :         return true;
    1271             : }
    1272             : 
    1273          24 : int pim_bsm_process(struct interface *ifp, pim_sgaddr *sg, uint8_t *buf,
    1274             :                     uint32_t buf_size, bool no_fwd)
    1275             : {
    1276          24 :         struct bsm_hdr *bshdr;
    1277          24 :         int sz = PIM_GBL_SZ_ID;
    1278          24 :         struct bsmmsg_grpinfo *msg_grp;
    1279          24 :         struct pim_interface *pim_ifp = NULL;
    1280          24 :         struct bsm_frag *bsfrag;
    1281          24 :         struct pim_instance *pim;
    1282          24 :         uint16_t frag_tag;
    1283          24 :         pim_addr bsr_addr;
    1284          24 :         bool empty_bsm = false;
    1285             : 
    1286             :         /* BSM Packet acceptance validation */
    1287          24 :         pim_ifp = ifp->info;
    1288          24 :         if (!pim_ifp) {
    1289           0 :                 if (PIM_DEBUG_BSM)
    1290           0 :                         zlog_debug("%s: multicast not enabled on interface %s",
    1291             :                                    __func__, ifp->name);
    1292           0 :                 return -1;
    1293             :         }
    1294             : 
    1295          24 :         if (pim_ifp->pim_passive_enable) {
    1296           0 :                 if (PIM_DEBUG_PIM_PACKETS)
    1297           0 :                         zlog_debug(
    1298             :                                 "skip receiving PIM message on passive interface %s",
    1299             :                                 ifp->name);
    1300           0 :                 return 0;
    1301             :         }
    1302             : 
    1303          24 :         pim_ifp->pim_ifstat_bsm_rx++;
    1304          24 :         pim = pim_ifp->pim;
    1305          24 :         pim->bsm_rcvd++;
    1306             : 
    1307             :         /* Drop if bsm processing is disabled on interface */
    1308          24 :         if (!pim_ifp->bsm_enable) {
    1309           0 :                 zlog_warn("%s: BSM not enabled on interface %s", __func__,
    1310             :                           ifp->name);
    1311           0 :                 pim_ifp->pim_ifstat_bsm_cfg_miss++;
    1312           0 :                 pim->bsm_dropped++;
    1313           0 :                 return -1;
    1314             :         }
    1315             : 
    1316          24 :         if (buf_size < (PIM_MSG_HEADER_LEN + sizeof(struct bsm_hdr))) {
    1317           0 :                 if (PIM_DEBUG_BSM)
    1318           0 :                         zlog_debug(
    1319             :                                 "%s: received buffer length of %d which is too small to properly decode",
    1320             :                                 __func__, buf_size);
    1321           0 :                 return -1;
    1322             :         }
    1323             : 
    1324          24 :         bshdr = (struct bsm_hdr *)(buf + PIM_MSG_HEADER_LEN);
    1325          24 :         if (bshdr->hm_len > PIM_MAX_BITLEN) {
    1326           0 :                 zlog_warn(
    1327             :                         "Bad hashmask length for %s; got %hhu, expected value in range 0-32",
    1328             :                         PIM_AF_NAME, bshdr->hm_len);
    1329           0 :                 pim->bsm_dropped++;
    1330           0 :                 return -1;
    1331             :         }
    1332          24 :         pim->global_scope.hashMasklen = bshdr->hm_len;
    1333          24 :         frag_tag = ntohs(bshdr->frag_tag);
    1334             :         /* NB: bshdr->bsr_addr.addr is packed/unaligned => memcpy */
    1335          24 :         memcpy(&bsr_addr, &bshdr->bsr_addr.addr, sizeof(bsr_addr));
    1336             : 
    1337             :         /* Identify empty BSM */
    1338          24 :         if ((buf_size - PIM_BSM_HDR_LEN - PIM_MSG_HEADER_LEN) < PIM_BSM_GRP_LEN)
    1339             :                 empty_bsm = true;
    1340             : 
    1341           0 :         if (!empty_bsm) {
    1342           0 :                 msg_grp = (struct bsmmsg_grpinfo *)(buf + PIM_MSG_HEADER_LEN
    1343             :                                                     + PIM_BSM_HDR_LEN);
    1344             :                 /* Currently we don't support scope zoned BSM */
    1345           0 :                 if (msg_grp->group.sz) {
    1346           0 :                         if (PIM_DEBUG_BSM)
    1347           0 :                                 zlog_debug(
    1348             :                                         "%s : Administratively scoped range BSM received",
    1349             :                                         __func__);
    1350           0 :                         pim_ifp->pim_ifstat_bsm_invalid_sz++;
    1351           0 :                         pim->bsm_dropped++;
    1352           0 :                         return -1;
    1353             :                 }
    1354             :         }
    1355             : 
    1356             :         /* Drop if bsr is not preferred bsr */
    1357          24 :         if (!is_preferred_bsr(pim, bsr_addr, bshdr->bsr_prio)) {
    1358           0 :                 if (PIM_DEBUG_BSM)
    1359           0 :                         zlog_debug("%s : Received a non-preferred BSM",
    1360             :                                    __func__);
    1361           0 :                 pim->bsm_dropped++;
    1362           0 :                 return -1;
    1363             :         }
    1364             : 
    1365          24 :         if (no_fwd) {
    1366             :                 /* only accept no-forward BSM if quick refresh on startup */
    1367           0 :                 if ((pim->global_scope.accept_nofwd_bsm)
    1368           0 :                     || (frag_tag == pim->global_scope.bsm_frag_tag)) {
    1369           0 :                         pim->global_scope.accept_nofwd_bsm = false;
    1370             :                 } else {
    1371           0 :                         if (PIM_DEBUG_BSM)
    1372           0 :                                 zlog_debug(
    1373             :                                         "%s : nofwd_bsm received on %pPAs when accpt_nofwd_bsm false",
    1374             :                                         __func__, &bsr_addr);
    1375           0 :                         pim->bsm_dropped++;
    1376           0 :                         pim_ifp->pim_ifstat_ucast_bsm_cfg_miss++;
    1377           0 :                         return -1;
    1378             :                 }
    1379             :         }
    1380             : 
    1381          24 :         if (!pim_addr_cmp(sg->grp, qpim_all_pim_routers_addr)) {
    1382             :                 /* Multicast BSMs are only accepted if source interface & IP
    1383             :                  * match RPF towards the BSR's IP address, or they have
    1384             :                  * no-forward set
    1385             :                  */
    1386          48 :                 if (!no_fwd &&
    1387          24 :                     !pim_nht_bsr_rpf_check(pim, bsr_addr, ifp, sg->src)) {
    1388          16 :                         if (PIM_DEBUG_BSM)
    1389          16 :                                 zlog_debug(
    1390             :                                         "BSM check: RPF to BSR %pPAs is not %pPA%%%s",
    1391             :                                         &bsr_addr, &sg->src, ifp->name);
    1392          16 :                         pim->bsm_dropped++;
    1393          16 :                         return -1;
    1394             :                 }
    1395           0 :         } else if (if_address_is_local(&sg->grp, PIM_AF, pim->vrf->vrf_id)) {
    1396             :                 /* Unicast BSM received - if ucast bsm not enabled on
    1397             :                  * the interface, drop it
    1398             :                  */
    1399           0 :                 if (!pim_ifp->ucast_bsm_accept) {
    1400           0 :                         if (PIM_DEBUG_BSM)
    1401           0 :                                 zlog_debug(
    1402             :                                         "%s : Unicast BSM not enabled on interface %s",
    1403             :                                         __func__, ifp->name);
    1404           0 :                         pim_ifp->pim_ifstat_ucast_bsm_cfg_miss++;
    1405           0 :                         pim->bsm_dropped++;
    1406           0 :                         return -1;
    1407             :                 }
    1408             : 
    1409             :         } else {
    1410           0 :                 if (PIM_DEBUG_BSM)
    1411           0 :                         zlog_debug("%s : Invalid destination address",
    1412             :                                    __func__);
    1413           0 :                 pim->bsm_dropped++;
    1414           0 :                 return -1;
    1415             :         }
    1416             : 
    1417           8 :         if (empty_bsm) {
    1418           8 :                 if (PIM_DEBUG_BSM)
    1419           8 :                         zlog_debug("%s : Empty Pref BSM received", __func__);
    1420             :         }
    1421             :         /* Parse Update bsm rp table and install/uninstall rp if required */
    1422           8 :         if (!pim_bsm_parse_install_g2rp(
    1423           8 :                     &pim_ifp->pim->global_scope,
    1424             :                     (buf + PIM_BSM_HDR_LEN + PIM_MSG_HEADER_LEN),
    1425           8 :                     (buf_size - PIM_BSM_HDR_LEN - PIM_MSG_HEADER_LEN),
    1426             :                     frag_tag)) {
    1427           0 :                 if (PIM_DEBUG_BSM) {
    1428           0 :                         zlog_debug("%s, Parsing BSM failed.", __func__);
    1429             :                 }
    1430           0 :                 pim->bsm_dropped++;
    1431           0 :                 return -1;
    1432             :         }
    1433             :         /* Restart the bootstrap timer */
    1434           8 :         pim_bs_timer_restart(&pim_ifp->pim->global_scope,
    1435             :                              PIM_BSR_DEFAULT_TIMEOUT);
    1436             : 
    1437             :         /* If new BSM received, clear the old bsm database */
    1438           8 :         if (pim_ifp->pim->global_scope.bsm_frag_tag != frag_tag) {
    1439           8 :                 if (PIM_DEBUG_BSM) {
    1440           8 :                         zlog_debug("%s: Current frag tag: %d Frag teg rcvd: %d",
    1441             :                                    __func__,
    1442             :                                    pim_ifp->pim->global_scope.bsm_frag_tag,
    1443             :                                    frag_tag);
    1444             :                 }
    1445           8 :                 pim_bsm_frags_free(&pim_ifp->pim->global_scope);
    1446           8 :                 pim_ifp->pim->global_scope.bsm_frag_tag = frag_tag;
    1447             :         }
    1448             : 
    1449             :         /* update the scope information from bsm */
    1450           8 :         pim_bsm_update(pim, bsr_addr, bshdr->bsr_prio);
    1451             : 
    1452           8 :         if (!no_fwd) {
    1453           8 :                 pim_bsm_fwd_whole_sz(pim_ifp->pim, buf, buf_size, sz);
    1454           8 :                 bsfrag = XCALLOC(MTYPE_PIM_BSM_FRAG,
    1455             :                                  sizeof(struct bsm_frag) + buf_size);
    1456             : 
    1457           8 :                 bsfrag->size = buf_size;
    1458           8 :                 memcpy(bsfrag->data, buf, buf_size);
    1459           8 :                 bsm_frags_add_tail(pim_ifp->pim->global_scope.bsm_frags,
    1460             :                                    bsfrag);
    1461             :         }
    1462             : 
    1463             :         return 0;
    1464             : }

Generated by: LCOV version v1.16-topotato