2 * pim_bsm.c: PIM BSM handling routines
4 * Copyright (C) 2018-19 Vmware, Inc.
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.
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.
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,
29 #include "pim_iface.h"
30 #include "pim_instance.h"
31 #include "pim_neighbor.h"
33 #include "pim_hello.h"
38 #include "pim_zebra.h"
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
,
48 DEFINE_MTYPE_STATIC(PIMD
, PIM_BSGRP_NODE
, "PIM BSR advertised grp info");
49 DEFINE_MTYPE_STATIC(PIMD
, PIM_BSRP_INFO
, "PIM BSR advertised RP info");
50 DEFINE_MTYPE_STATIC(PIMD
, PIM_BSM_FRAG
, "PIM BSM fragment");
51 DEFINE_MTYPE_STATIC(PIMD
, PIM_BSM_PKT_VAR_MEM
, "PIM BSM Packet");
53 /* All bsm packets forwarded shall be fit within ip mtu less iphdr(max) */
54 #define MAX_IP_HDR_LEN 24
56 /* pim_bsm_write_config - Write the interface pim bsm configuration.*/
57 void pim_bsm_write_config(struct vty
*vty
, struct interface
*ifp
)
59 struct pim_interface
*pim_ifp
= ifp
->info
;
62 if (!pim_ifp
->bsm_enable
)
63 vty_out(vty
, " no " PIM_AF_NAME
" pim bsm\n");
64 if (!pim_ifp
->ucast_bsm_accept
)
65 vty_out(vty
, " no " PIM_AF_NAME
" pim unicast-bsm\n");
69 static void pim_bsm_rpinfo_free(struct bsm_rpinfo
*bsrp_info
)
71 THREAD_OFF(bsrp_info
->g2rp_timer
);
72 XFREE(MTYPE_PIM_BSRP_INFO
, bsrp_info
);
75 static void pim_bsm_rpinfos_free(struct bsm_rpinfos_head
*head
)
77 struct bsm_rpinfo
*bsrp_info
;
79 while ((bsrp_info
= bsm_rpinfos_pop(head
)))
80 pim_bsm_rpinfo_free(bsrp_info
);
83 static void pim_free_bsgrp_data(struct bsgrp_node
*bsgrp_node
)
85 pim_bsm_rpinfos_free(bsgrp_node
->bsrp_list
);
86 pim_bsm_rpinfos_free(bsgrp_node
->partial_bsrp_list
);
87 XFREE(MTYPE_PIM_BSGRP_NODE
, bsgrp_node
);
90 static void pim_free_bsgrp_node(struct route_table
*rt
, struct prefix
*grp
)
92 struct route_node
*rn
;
94 rn
= route_node_lookup(rt
, grp
);
97 route_unlock_node(rn
);
98 route_unlock_node(rn
);
102 static void pim_bsm_frag_free(struct bsm_frag
*bsfrag
)
104 XFREE(MTYPE_PIM_BSM_FRAG
, bsfrag
);
107 static void pim_bsm_frags_free(struct bsm_scope
*scope
)
109 struct bsm_frag
*bsfrag
;
111 while ((bsfrag
= bsm_frags_pop(scope
->bsm_frags
)))
112 pim_bsm_frag_free(bsfrag
);
115 int pim_bsm_rpinfo_cmp(const struct bsm_rpinfo
*node1
,
116 const struct bsm_rpinfo
*node2
)
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
122 * Step-3 : If Hash val is same then highest rp address will
125 if (node1
->rp_prio
< node2
->rp_prio
)
127 if (node1
->rp_prio
> node2
->rp_prio
)
129 if (node1
->hash
< node2
->hash
)
131 if (node1
->hash
> node2
->hash
)
133 if (node1
->rp_address
.s_addr
< node2
->rp_address
.s_addr
)
135 if (node1
->rp_address
.s_addr
> node2
->rp_address
.s_addr
)
140 static struct bsgrp_node
*pim_bsm_new_bsgrp_node(struct route_table
*rt
,
143 struct route_node
*rn
;
144 struct bsgrp_node
*bsgrp
;
146 rn
= route_node_get(rt
, grp
);
148 zlog_warn("%s: route node creation failed", __func__
);
151 bsgrp
= XCALLOC(MTYPE_PIM_BSGRP_NODE
, sizeof(struct bsgrp_node
));
154 bsm_rpinfos_init(bsgrp
->bsrp_list
);
155 bsm_rpinfos_init(bsgrp
->partial_bsrp_list
);
157 prefix_copy(&bsgrp
->group
, grp
);
161 static void pim_on_bs_timer(struct thread
*t
)
163 struct route_node
*rn
;
164 struct bsm_scope
*scope
;
165 struct bsgrp_node
*bsgrp_node
;
166 struct bsm_rpinfo
*bsrp
;
168 scope
= THREAD_ARG(t
);
169 THREAD_OFF(scope
->bs_timer
);
172 zlog_debug("%s: Bootstrap Timer expired for scope: %d",
173 __func__
, scope
->sz_id
);
175 pim_nht_bsr_del(scope
->pim
, scope
->current_bsr
);
177 /* Reset scope zone data */
178 scope
->accept_nofwd_bsm
= false;
179 scope
->state
= ACCEPT_ANY
;
180 scope
->current_bsr
.s_addr
= INADDR_ANY
;
181 scope
->current_bsr_prio
= 0;
182 scope
->current_bsr_first_ts
= 0;
183 scope
->current_bsr_last_ts
= 0;
184 scope
->bsm_frag_tag
= 0;
185 pim_bsm_frags_free(scope
);
187 for (rn
= route_top(scope
->bsrp_table
); rn
; rn
= route_next(rn
)) {
189 bsgrp_node
= (struct bsgrp_node
*)rn
->info
;
192 zlog_debug("%s: bsgrp_node is null", __func__
);
195 /* Give grace time for rp to continue for another hold time */
196 bsrp
= bsm_rpinfos_first(bsgrp_node
->bsrp_list
);
198 pim_g2rp_timer_restart(bsrp
, bsrp
->rp_holdtime
);
200 /* clear pending list */
201 pim_bsm_rpinfos_free(bsgrp_node
->partial_bsrp_list
);
202 bsgrp_node
->pend_rp_cnt
= 0;
206 static void pim_bs_timer_stop(struct bsm_scope
*scope
)
209 zlog_debug("%s : BS timer being stopped of sz: %d", __func__
,
211 THREAD_OFF(scope
->bs_timer
);
214 static void pim_bs_timer_start(struct bsm_scope
*scope
, int bs_timeout
)
218 zlog_debug("%s : Invalid scope(NULL).", __func__
);
221 THREAD_OFF(scope
->bs_timer
);
224 "%s : starting bs timer for scope %d with timeout %d secs",
225 __func__
, scope
->sz_id
, bs_timeout
);
226 thread_add_timer(router
->master
, pim_on_bs_timer
, scope
, bs_timeout
,
230 static inline void pim_bs_timer_restart(struct bsm_scope
*scope
, int bs_timeout
)
232 pim_bs_timer_start(scope
, bs_timeout
);
235 void pim_bsm_proc_init(struct pim_instance
*pim
)
237 memset(&pim
->global_scope
, 0, sizeof(struct bsm_scope
));
239 pim
->global_scope
.sz_id
= PIM_GBL_SZ_ID
;
240 pim
->global_scope
.bsrp_table
= route_table_init();
241 pim
->global_scope
.accept_nofwd_bsm
= true;
242 pim
->global_scope
.state
= NO_INFO
;
243 pim
->global_scope
.pim
= pim
;
244 bsm_frags_init(pim
->global_scope
.bsm_frags
);
245 pim_bs_timer_start(&pim
->global_scope
, PIM_BS_TIME
);
248 void pim_bsm_proc_free(struct pim_instance
*pim
)
250 struct route_node
*rn
;
251 struct bsgrp_node
*bsgrp
;
253 pim_bs_timer_stop(&pim
->global_scope
);
254 pim_bsm_frags_free(&pim
->global_scope
);
256 for (rn
= route_top(pim
->global_scope
.bsrp_table
); rn
;
257 rn
= route_next(rn
)) {
261 pim_free_bsgrp_data(bsgrp
);
264 route_table_finish(pim
->global_scope
.bsrp_table
);
267 static bool is_hold_time_elapsed(void *data
)
269 struct bsm_rpinfo
*bsrp
;
273 if (bsrp
->elapse_time
< bsrp
->rp_holdtime
)
279 static void pim_on_g2rp_timer(struct thread
*t
)
281 struct bsm_rpinfo
*bsrp
;
282 struct bsm_rpinfo
*bsrp_node
;
283 struct bsgrp_node
*bsgrp_node
;
284 struct pim_instance
*pim
;
285 struct rp_info
*rp_info
;
286 struct route_node
*rn
;
290 bsrp
= THREAD_ARG(t
);
291 THREAD_OFF(bsrp
->g2rp_timer
);
292 bsgrp_node
= bsrp
->bsgrp_node
;
294 /* elapse time is the hold time of expired node */
295 elapse
= bsrp
->rp_holdtime
;
296 bsrp_addr
= bsrp
->rp_address
;
298 /* update elapse for all bsrp nodes */
299 frr_each_safe (bsm_rpinfos
, bsgrp_node
->bsrp_list
, bsrp_node
) {
300 bsrp_node
->elapse_time
+= elapse
;
302 if (is_hold_time_elapsed(bsrp_node
)) {
303 bsm_rpinfos_del(bsgrp_node
->bsrp_list
, bsrp_node
);
304 pim_bsm_rpinfo_free(bsrp_node
);
308 /* Get the next elected rp node */
309 bsrp
= bsm_rpinfos_first(bsgrp_node
->bsrp_list
);
310 pim
= bsgrp_node
->scope
->pim
;
311 rn
= route_node_lookup(pim
->rp_table
, &bsgrp_node
->group
);
314 zlog_warn("%s: Route node doesn't exist", __func__
);
318 rp_info
= (struct rp_info
*)rn
->info
;
321 route_unlock_node(rn
);
325 if (rp_info
->rp_src
!= RP_SRC_STATIC
) {
326 /* If new rp available, change it else delete the existing */
328 pim_g2rp_timer_start(
329 bsrp
, (bsrp
->rp_holdtime
- bsrp
->elapse_time
));
330 pim_rp_change(pim
, bsrp
->rp_address
, bsgrp_node
->group
,
333 pim_rp_del(pim
, bsrp_addr
, bsgrp_node
->group
, NULL
,
338 if (!bsm_rpinfos_count(bsgrp_node
->bsrp_list
)
339 && !bsm_rpinfos_count(bsgrp_node
->partial_bsrp_list
)) {
340 pim_free_bsgrp_node(pim
->global_scope
.bsrp_table
,
342 pim_free_bsgrp_data(bsgrp_node
);
346 static void pim_g2rp_timer_start(struct bsm_rpinfo
*bsrp
, int hold_time
)
350 zlog_debug("%s : Invalid brsp(NULL).", __func__
);
353 THREAD_OFF(bsrp
->g2rp_timer
);
356 "%s : starting g2rp timer for grp: %pFX - rp: %pI4 with timeout %d secs(Actual Hold time : %d secs)",
357 __func__
, &bsrp
->bsgrp_node
->group
,
358 &bsrp
->rp_address
, hold_time
,
361 thread_add_timer(router
->master
, pim_on_g2rp_timer
, bsrp
, hold_time
,
365 static inline void pim_g2rp_timer_restart(struct bsm_rpinfo
*bsrp
,
368 pim_g2rp_timer_start(bsrp
, hold_time
);
371 static void pim_g2rp_timer_stop(struct bsm_rpinfo
*bsrp
)
377 zlog_debug("%s : stopping g2rp timer for grp: %pFX - rp: %pI4",
378 __func__
, &bsrp
->bsgrp_node
->group
,
381 THREAD_OFF(bsrp
->g2rp_timer
);
384 static bool is_hold_time_zero(void *data
)
386 struct bsm_rpinfo
*bsrp
;
390 if (bsrp
->rp_holdtime
)
396 static void pim_instate_pend_list(struct bsgrp_node
*bsgrp_node
)
398 struct bsm_rpinfo
*active
;
399 struct bsm_rpinfo
*pend
;
400 struct rp_info
*rp_info
;
401 struct route_node
*rn
;
402 struct pim_instance
*pim
;
403 struct rp_info
*rp_all
;
404 struct prefix group_all
;
405 bool had_rp_node
= true;
407 pim
= bsgrp_node
->scope
->pim
;
408 active
= bsm_rpinfos_first(bsgrp_node
->bsrp_list
);
410 /* Remove nodes with hold time 0 & check if list still has a head */
411 frr_each_safe (bsm_rpinfos
, bsgrp_node
->partial_bsrp_list
, pend
) {
412 if (is_hold_time_zero(pend
)) {
413 bsm_rpinfos_del(bsgrp_node
->partial_bsrp_list
, pend
);
414 pim_bsm_rpinfo_free(pend
);
418 pend
= bsm_rpinfos_first(bsgrp_node
->partial_bsrp_list
);
420 if (!pim_get_all_mcast_group(&group_all
))
423 rp_all
= pim_rp_find_match_group(pim
, &group_all
);
424 rn
= route_node_lookup(pim
->rp_table
, &bsgrp_node
->group
);
427 pim_g2rp_timer_start(pend
, pend
->rp_holdtime
);
429 /* if rp node doesn't exist or exist but not configured(rp_all),
430 * install the rp from head(if exists) of partial list. List is
431 * is sorted such that head is the elected RP for the group.
433 if (!rn
|| (prefix_same(&rp_all
->group
, &bsgrp_node
->group
) &&
434 pim_rpf_addr_is_inaddr_any(&rp_all
->rp
))) {
436 zlog_debug("%s: Route node doesn't exist", __func__
);
438 pim_rp_new(pim
, pend
->rp_address
, bsgrp_node
->group
,
442 rp_info
= (struct rp_info
*)rn
->info
;
444 route_unlock_node(rn
);
446 pim_rp_new(pim
, pend
->rp_address
,
447 bsgrp_node
->group
, NULL
, RP_SRC_BSR
);
452 /* We didn't have rp node and pending list is empty(unlikely), cleanup*/
453 if ((!had_rp_node
) && (!pend
)) {
454 pim_free_bsgrp_node(bsgrp_node
->scope
->bsrp_table
,
456 pim_free_bsgrp_data(bsgrp_node
);
460 if ((had_rp_node
) && (rp_info
->rp_src
!= RP_SRC_STATIC
)) {
461 /* This means we searched and got rp node, needs unlock */
462 route_unlock_node(rn
);
464 if (active
&& pend
) {
465 if ((active
->rp_address
.s_addr
466 != pend
->rp_address
.s_addr
))
467 pim_rp_change(pim
, pend
->rp_address
,
468 bsgrp_node
->group
, RP_SRC_BSR
);
471 /* Possible when the first BSM has group with 0 rp count */
472 if ((!active
) && (!pend
)) {
475 "%s: Both bsrp and partial list are empty",
478 pim_free_bsgrp_node(bsgrp_node
->scope
->bsrp_table
,
480 pim_free_bsgrp_data(bsgrp_node
);
484 /* Possible when a group with 0 rp count received in BSM */
485 if ((active
) && (!pend
)) {
486 pim_rp_del(pim
, active
->rp_address
, bsgrp_node
->group
,
488 pim_free_bsgrp_node(bsgrp_node
->scope
->bsrp_table
,
491 zlog_debug("%s:Pend List is null,del grp node",
494 pim_free_bsgrp_data(bsgrp_node
);
499 if ((had_rp_node
) && (rp_info
->rp_src
== RP_SRC_STATIC
)) {
500 /* We need to unlock rn this case */
501 route_unlock_node(rn
);
502 /* there is a chance that static rp exist and bsrp cleaned
503 * so clean bsgrp node if pending list empty
508 "%s: Partial list is empty, static rp exists",
510 pim_free_bsgrp_node(bsgrp_node
->scope
->bsrp_table
,
512 pim_free_bsgrp_data(bsgrp_node
);
517 /* swap the list & delete all nodes in partial list (old bsrp_list)
519 * active is head of bsrp list
520 * pend is head of partial list
522 * active is head of partial list
523 * pend is head of bsrp list
524 * So check appriate head after swap and clean the new partial list
526 bsm_rpinfos_swap_all(bsgrp_node
->bsrp_list
,
527 bsgrp_node
->partial_bsrp_list
);
530 pim_g2rp_timer_stop(active
);
531 pim_bsm_rpinfos_free(bsgrp_node
->partial_bsrp_list
);
534 static bool is_preferred_bsr(struct pim_instance
*pim
, struct in_addr bsr
,
537 if (bsr
.s_addr
== pim
->global_scope
.current_bsr
.s_addr
)
540 if (bsr_prio
> pim
->global_scope
.current_bsr_prio
)
543 else if (bsr_prio
== pim
->global_scope
.current_bsr_prio
) {
544 if (ntohl(bsr
.s_addr
)
545 >= ntohl(pim
->global_scope
.current_bsr
.s_addr
))
553 static void pim_bsm_update(struct pim_instance
*pim
, struct in_addr bsr
,
556 if (bsr
.s_addr
!= pim
->global_scope
.current_bsr
.s_addr
) {
557 pim_nht_bsr_del(pim
, pim
->global_scope
.current_bsr
);
558 pim_nht_bsr_add(pim
, bsr
);
560 pim
->global_scope
.current_bsr
= bsr
;
561 pim
->global_scope
.current_bsr_first_ts
=
562 pim_time_monotonic_sec();
563 pim
->global_scope
.state
= ACCEPT_PREFERRED
;
565 pim
->global_scope
.current_bsr_prio
= bsr_prio
;
566 pim
->global_scope
.current_bsr_last_ts
= pim_time_monotonic_sec();
569 void pim_bsm_clear(struct pim_instance
*pim
)
571 struct route_node
*rn
;
572 struct route_node
*rpnode
;
573 struct bsgrp_node
*bsgrp
;
576 struct rp_info
*rp_all
;
577 struct pim_upstream
*up
;
578 struct rp_info
*rp_info
;
579 bool upstream_updated
= false;
581 pim_nht_bsr_del(pim
, pim
->global_scope
.current_bsr
);
583 /* Reset scope zone data */
584 pim
->global_scope
.accept_nofwd_bsm
= false;
585 pim
->global_scope
.state
= ACCEPT_ANY
;
586 pim
->global_scope
.current_bsr
.s_addr
= INADDR_ANY
;
587 pim
->global_scope
.current_bsr_prio
= 0;
588 pim
->global_scope
.current_bsr_first_ts
= 0;
589 pim
->global_scope
.current_bsr_last_ts
= 0;
590 pim
->global_scope
.bsm_frag_tag
= 0;
591 pim_bsm_frags_free(&pim
->global_scope
);
593 pim_bs_timer_stop(&pim
->global_scope
);
595 for (rn
= route_top(pim
->global_scope
.bsrp_table
); rn
;
596 rn
= route_next(rn
)) {
601 rpnode
= route_node_lookup(pim
->rp_table
, &bsgrp
->group
);
604 pim_free_bsgrp_node(bsgrp
->scope
->bsrp_table
,
606 pim_free_bsgrp_data(bsgrp
);
610 rp_info
= (struct rp_info
*)rpnode
->info
;
612 if ((!rp_info
) || (rp_info
->rp_src
!= RP_SRC_BSR
)) {
613 pim_free_bsgrp_node(bsgrp
->scope
->bsrp_table
,
615 pim_free_bsgrp_data(bsgrp
);
619 /* Deregister addr with Zebra NHT */
620 nht_p
.family
= AF_INET
;
621 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
622 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
624 if (PIM_DEBUG_PIM_NHT_RP
) {
625 zlog_debug("%s: Deregister RP addr %pFX with Zebra ",
629 pim_delete_tracked_nexthop(pim
, &nht_p
, NULL
, rp_info
);
631 if (!pim_get_all_mcast_group(&g_all
))
634 rp_all
= pim_rp_find_match_group(pim
, &g_all
);
636 if (rp_all
== rp_info
) {
637 pim_addr_to_prefix(&rp_all
->rp
.rpf_addr
, PIMADDR_ANY
);
640 /* Delete the rp_info from rp-list */
641 listnode_delete(pim
->rp_list
, rp_info
);
643 /* Delete the rp node from rp_table */
645 route_unlock_node(rpnode
);
646 route_unlock_node(rpnode
);
647 XFREE(MTYPE_PIM_RP
, rp_info
);
650 pim_free_bsgrp_node(bsgrp
->scope
->bsrp_table
, &bsgrp
->group
);
651 pim_free_bsgrp_data(bsgrp
);
653 pim_rp_refresh_group_to_rp_mapping(pim
);
656 frr_each (rb_pim_upstream
, &pim
->upstream_head
, up
) {
657 /* Find the upstream (*, G) whose upstream address is same as
660 if (!pim_addr_is_any(up
->sg
.src
))
664 struct rp_info
*trp_info
;
666 pim_addr_to_prefix(&grp
, up
->sg
.grp
);
667 trp_info
= pim_rp_find_match_group(pim
, &grp
);
669 /* RP not found for the group grp */
670 if (pim_rpf_addr_is_inaddr_any(&trp_info
->rp
)) {
671 pim_upstream_rpf_clear(pim
, up
);
672 pim_rp_set_upstream_addr(pim
, &up
->upstream_addr
,
673 up
->sg
.src
, up
->sg
.grp
);
675 /* RP found for the group grp */
676 pim_upstream_update(pim
, up
);
677 upstream_updated
= true;
681 if (upstream_updated
)
682 pim_zebra_update_all_interfaces(pim
);
685 static bool pim_bsm_send_intf(uint8_t *buf
, int len
, struct interface
*ifp
,
688 struct pim_interface
*pim_ifp
;
694 zlog_debug("%s: Pim interface not available for %s",
695 __func__
, ifp
->name
);
699 if (pim_ifp
->pim_sock_fd
== -1) {
701 zlog_debug("%s: Pim sock not available for %s",
702 __func__
, ifp
->name
);
706 if (pim_msg_send(pim_ifp
->pim_sock_fd
, pim_ifp
->primary_address
,
707 dst_addr
, buf
, len
, ifp
->name
)) {
708 zlog_warn("%s: Could not send BSM message on interface: %s",
709 __func__
, ifp
->name
);
713 pim_ifp
->pim_ifstat_bsm_tx
++;
714 pim_ifp
->pim
->bsm_sent
++;
718 static bool pim_bsm_frag_send(uint8_t *buf
, uint32_t len
, struct interface
*ifp
,
719 uint32_t pim_mtu
, pim_addr dst_addr
, bool no_fwd
)
721 struct pim_interface
*pim_ifp
= ifp
->info
;
722 struct bsmmsg_grpinfo
*grpinfo
, *curgrp
;
723 uint8_t *firstgrp_ptr
;
726 uint32_t parsed_len
= 0;
727 uint32_t this_pkt_rem
;
728 uint32_t copy_byte_count
;
729 uint32_t this_pkt_len
;
730 uint8_t total_rp_cnt
;
734 bool pak_pending
= false;
736 /* MTU passed here is PIM MTU (IP MTU less IP Hdr) */
737 if (pim_mtu
< (PIM_MIN_BSM_LEN
)) {
739 "%s: mtu(pim mtu: %d) size less than minimum bootstrap len",
743 "%s: mtu (pim mtu:%d) less than minimum bootstrap len",
748 pak_start
= XCALLOC(MTYPE_PIM_BSM_PKT_VAR_MEM
, pim_mtu
);
752 /* Fill PIM header later before sending packet to calc checksum */
753 pkt
+= PIM_MSG_HEADER_LEN
;
754 buf
+= PIM_MSG_HEADER_LEN
;
756 /* copy bsm header to new packet at offset of pim hdr */
757 memcpy(pkt
, buf
, PIM_BSM_HDR_LEN
);
758 pkt
+= PIM_BSM_HDR_LEN
;
759 buf
+= PIM_BSM_HDR_LEN
;
760 parsed_len
+= (PIM_MSG_HEADER_LEN
+ PIM_BSM_HDR_LEN
);
762 /* Store the position of first grp ptr, which can be reused for
763 * next packet to start filling group. old bsm header and pim hdr
764 * remains. So need not be filled again for next packet onwards.
768 /* we received mtu excluding IP hdr len as param
769 * now this_pkt_rem is mtu excluding
770 * PIM_BSM_HDR_LEN + PIM_MSG_HEADER_LEN
772 this_pkt_rem
= pim_mtu
- (PIM_BSM_HDR_LEN
+ PIM_MSG_HEADER_LEN
);
774 /* For each group till the packet length parsed */
775 while (parsed_len
< len
) {
776 /* pkt ---> fragment's current pointer
777 * buf ---> input buffer's current pointer
778 * mtu ---> size of the pim packet - PIM header
779 * curgrp ---> current group on the fragment
780 * grpinfo ---> current group on the input buffer
781 * this_pkt_rem ---> bytes remaing on the current fragment
782 * rp_fit_cnt ---> num of rp for current grp that
784 * total_rp_cnt ---> total rp present for the group in the buf
785 * frag_rp_cnt ---> no of rp for the group to be fit in
787 * this_rp_cnt ---> how many rp have we parsed
789 grpinfo
= (struct bsmmsg_grpinfo
*)buf
;
790 memcpy(pkt
, buf
, PIM_BSM_GRP_LEN
);
791 curgrp
= (struct bsmmsg_grpinfo
*)pkt
;
792 parsed_len
+= PIM_BSM_GRP_LEN
;
793 pkt
+= PIM_BSM_GRP_LEN
;
794 buf
+= PIM_BSM_GRP_LEN
;
795 this_pkt_rem
-= PIM_BSM_GRP_LEN
;
797 /* initialize rp count and total_rp_cnt before the rp loop */
799 total_rp_cnt
= grpinfo
->frag_rp_count
;
801 /* Loop till all RPs for the group parsed */
802 while (this_rp_cnt
< total_rp_cnt
) {
803 /* All RP from a group processed here.
804 * group is pointed by grpinfo.
805 * At this point make sure buf pointing to a RP
808 rp_fit_cnt
= this_pkt_rem
/ PIM_BSM_RP_LEN
;
810 /* calculate how many rp am i going to copy in
813 if (rp_fit_cnt
> (total_rp_cnt
- this_rp_cnt
))
814 frag_rp_cnt
= total_rp_cnt
- this_rp_cnt
;
816 frag_rp_cnt
= rp_fit_cnt
;
818 /* populate the frag rp count for the current grp */
819 curgrp
->frag_rp_count
= frag_rp_cnt
;
820 copy_byte_count
= frag_rp_cnt
* PIM_BSM_RP_LEN
;
822 /* copy all the rp that we are fitting in this
825 memcpy(pkt
, buf
, copy_byte_count
);
826 this_rp_cnt
+= frag_rp_cnt
;
827 buf
+= copy_byte_count
;
828 pkt
+= copy_byte_count
;
829 parsed_len
+= copy_byte_count
;
830 this_pkt_rem
-= copy_byte_count
;
832 /* Either we couldn't fit all rp for the group or the
835 if ((this_rp_cnt
< total_rp_cnt
)
837 < (PIM_BSM_GRP_LEN
+ PIM_BSM_RP_LEN
))) {
838 /* No space to fit in more rp, send this pkt */
839 this_pkt_len
= pim_mtu
- this_pkt_rem
;
840 pim_msg_build_header(
841 pim_ifp
->primary_address
, dst_addr
,
842 pak_start
, this_pkt_len
,
843 PIM_MSG_TYPE_BOOTSTRAP
, no_fwd
);
844 pim_bsm_send_intf(pak_start
, this_pkt_len
, ifp
,
847 /* Construct next fragment. Reuse old packet */
849 this_pkt_rem
= pim_mtu
- (PIM_BSM_HDR_LEN
850 + PIM_MSG_HEADER_LEN
);
852 /* If pkt can't accommodate next group + at
853 * least one rp, we must break out of this inner
854 * loop and process next RP
856 if (total_rp_cnt
== this_rp_cnt
)
859 /* If some more RPs for the same group pending,
862 memcpy(pkt
, (uint8_t *)grpinfo
,
864 curgrp
= (struct bsmmsg_grpinfo
*)pkt
;
865 pkt
+= PIM_BSM_GRP_LEN
;
866 this_pkt_rem
-= PIM_BSM_GRP_LEN
;
869 /* We filled something but not yet sent out */
872 } /* while RP count */
873 } /*while parsed len */
875 /* Send if we have any unsent packet */
877 this_pkt_len
= pim_mtu
- this_pkt_rem
;
878 pim_msg_build_header(pim_ifp
->primary_address
, dst_addr
,
879 pak_start
, this_pkt_len
,
880 PIM_MSG_TYPE_BOOTSTRAP
, no_fwd
);
881 pim_bsm_send_intf(pak_start
, (pim_mtu
- this_pkt_rem
), ifp
,
884 XFREE(MTYPE_PIM_BSM_PKT_VAR_MEM
, pak_start
);
888 static void pim_bsm_fwd_whole_sz(struct pim_instance
*pim
, uint8_t *buf
,
889 uint32_t len
, int sz
)
891 struct interface
*ifp
;
892 struct pim_interface
*pim_ifp
;
898 /* For now only global scope zone is supported, so send on all
899 * pim interfaces in the vrf
901 dst_addr
= qpim_all_pim_routers_addr
;
902 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
904 if ((!pim_ifp
) || (!pim_ifp
->bsm_enable
))
909 * When a Bootstrap message is forwarded, it is forwarded out
910 * of every multicast-capable interface that has PIM neighbors.
912 * So skipping pim interfaces with no neighbors.
914 if (listcount(pim_ifp
->pim_neighbor_list
) == 0)
917 pim_hello_require(ifp
);
918 pim_mtu
= ifp
->mtu
- MAX_IP_HDR_LEN
;
920 ret
= pim_bsm_frag_send(buf
, len
, ifp
, pim_mtu
,
923 zlog_debug("%s: pim_bsm_frag_send returned %s",
924 __func__
, ret
? "TRUE" : "FALSE");
926 pim_msg_build_header(pim_ifp
->primary_address
, dst_addr
,
927 buf
, len
, PIM_MSG_TYPE_BOOTSTRAP
,
929 if (!pim_bsm_send_intf(buf
, len
, ifp
, dst_addr
)) {
932 "%s: pim_bsm_send_intf returned false",
939 bool pim_bsm_new_nbr_fwd(struct pim_neighbor
*neigh
, struct interface
*ifp
)
942 struct pim_interface
*pim_ifp
;
943 struct bsm_scope
*scope
;
944 struct bsm_frag
*bsfrag
;
945 char neigh_src_str
[INET_ADDRSTRLEN
];
951 zlog_debug("%s: New neighbor %pPA seen on %s", __func__
,
952 &neigh
->source_addr
, ifp
->name
);
956 /* DR only forwards BSM packet */
957 if (!pim_addr_cmp(pim_ifp
->pim_dr_addr
, pim_ifp
->primary_address
)) {
960 "%s: It is not DR, so don't forward BSM packet",
964 if (!pim_ifp
->bsm_enable
) {
966 zlog_debug("%s: BSM proc not enabled on %s", __func__
,
971 scope
= &pim_ifp
->pim
->global_scope
;
973 if (!bsm_frags_count(scope
->bsm_frags
)) {
975 zlog_debug("%s: BSM list for the scope is empty",
980 if (!pim_ifp
->ucast_bsm_accept
) {
981 dst_addr
= qpim_all_pim_routers_addr
;
983 zlog_debug("%s: Sending BSM mcast to %s", __func__
,
986 dst_addr
= neigh
->source_addr
;
988 zlog_debug("%s: Sending BSM ucast to %s", __func__
,
991 pim_mtu
= ifp
->mtu
- MAX_IP_HDR_LEN
;
992 pim_hello_require(ifp
);
994 frr_each (bsm_frags
, scope
->bsm_frags
, bsfrag
) {
995 if (pim_mtu
< bsfrag
->size
) {
996 ret
= pim_bsm_frag_send(bsfrag
->data
, bsfrag
->size
, ifp
,
997 pim_mtu
, dst_addr
, no_fwd
);
1001 "%s: pim_bsm_frag_send failed",
1005 /* Pim header needs to be constructed */
1006 pim_msg_build_header(pim_ifp
->primary_address
, dst_addr
,
1007 bsfrag
->data
, bsfrag
->size
,
1008 PIM_MSG_TYPE_BOOTSTRAP
, no_fwd
);
1009 ret
= pim_bsm_send_intf(bsfrag
->data
, bsfrag
->size
, ifp
,
1014 "%s: pim_bsm_frag_send failed",
1022 struct bsgrp_node
*pim_bsm_get_bsgrp_node(struct bsm_scope
*scope
,
1025 struct route_node
*rn
;
1026 struct bsgrp_node
*bsgrp
;
1028 rn
= route_node_lookup(scope
->bsrp_table
, grp
);
1031 zlog_debug("%s: Route node doesn't exist for the group",
1036 route_unlock_node(rn
);
1041 static uint32_t hash_calc_on_grp_rp(struct prefix group
, struct in_addr rp
,
1042 uint8_t hashmasklen
)
1048 uint32_t mask
= 0xffffffff;
1050 /* mask to be made zero if hashmasklen is 0 because mask << 32
1051 * may not give 0. hashmasklen can be 0 to 32.
1053 if (hashmasklen
== 0)
1056 /* in_addr stores ip in big endian, hence network byte order
1057 * convert to uint32 before processing hash
1059 grpaddr
= ntohl(group
.u
.prefix4
.s_addr
);
1060 /* Avoid shifting by 32 bit on a 32 bit register */
1062 grpaddr
= grpaddr
& ((mask
<< (32 - hashmasklen
)));
1064 grpaddr
= grpaddr
& mask
;
1065 rp_add
= ntohl(rp
.s_addr
);
1066 temp
= 1103515245 * ((1103515245 * (uint64_t)grpaddr
+ 12345) ^ rp_add
)
1068 hash
= temp
& (0x7fffffff);
1072 static bool pim_install_bsm_grp_rp(struct pim_instance
*pim
,
1073 struct bsgrp_node
*grpnode
,
1074 struct bsmmsg_rpinfo
*rp
)
1076 struct bsm_rpinfo
*bsm_rpinfo
;
1077 uint8_t hashMask_len
= pim
->global_scope
.hashMasklen
;
1079 /*memory allocation for bsm_rpinfo */
1080 bsm_rpinfo
= XCALLOC(MTYPE_PIM_BSRP_INFO
, sizeof(*bsm_rpinfo
));
1082 bsm_rpinfo
->rp_prio
= rp
->rp_pri
;
1083 bsm_rpinfo
->rp_holdtime
= rp
->rp_holdtime
;
1084 memcpy(&bsm_rpinfo
->rp_address
, &rp
->rpaddr
.addr
,
1085 sizeof(struct in_addr
));
1086 bsm_rpinfo
->elapse_time
= 0;
1088 /* Back pointer to the group node. */
1089 bsm_rpinfo
->bsgrp_node
= grpnode
;
1091 /* update hash for this rp node */
1092 bsm_rpinfo
->hash
= hash_calc_on_grp_rp(grpnode
->group
, rp
->rpaddr
.addr
,
1094 if (bsm_rpinfos_add(grpnode
->partial_bsrp_list
, bsm_rpinfo
) == NULL
) {
1097 "%s, bs_rpinfo node added to the partial bs_rplist.",
1103 zlog_debug("%s: list node not added", __func__
);
1105 XFREE(MTYPE_PIM_BSRP_INFO
, bsm_rpinfo
);
1109 static void pim_update_pending_rp_cnt(struct bsm_scope
*sz
,
1110 struct bsgrp_node
*bsgrp
,
1111 uint16_t bsm_frag_tag
,
1112 uint32_t total_rp_count
)
1114 if (bsgrp
->pend_rp_cnt
) {
1115 /* received bsm is different packet ,
1116 * it is not same fragment.
1118 if (bsm_frag_tag
!= bsgrp
->frag_tag
) {
1121 "%s,Received a new BSM ,so clear the pending bs_rpinfo list.",
1123 pim_bsm_rpinfos_free(bsgrp
->partial_bsrp_list
);
1124 bsgrp
->pend_rp_cnt
= total_rp_count
;
1127 bsgrp
->pend_rp_cnt
= total_rp_count
;
1129 bsgrp
->frag_tag
= bsm_frag_tag
;
1132 /* Parsing BSR packet and adding to partial list of corresponding bsgrp node */
1133 static bool pim_bsm_parse_install_g2rp(struct bsm_scope
*scope
, uint8_t *buf
,
1134 int buflen
, uint16_t bsm_frag_tag
)
1136 struct bsmmsg_grpinfo grpinfo
;
1137 struct bsmmsg_rpinfo rpinfo
;
1138 struct prefix group
;
1139 struct bsgrp_node
*bsgrp
= NULL
;
1140 int frag_rp_cnt
= 0;
1144 while (buflen
> offset
) {
1145 if (offset
+ (int)sizeof(struct bsmmsg_grpinfo
) > buflen
) {
1148 "%s: buflen received %d is less than the internal data structure of the packet would suggest",
1152 /* Extract Group tlv from BSM */
1153 memcpy(&grpinfo
, buf
, sizeof(struct bsmmsg_grpinfo
));
1155 if (PIM_DEBUG_BSM
) {
1156 char grp_str
[INET_ADDRSTRLEN
];
1158 pim_inet4_dump("<Group?>", grpinfo
.group
.addr
, grp_str
,
1161 "%s, Group %s Rpcount:%d Fragment-Rp-count:%d",
1162 __func__
, grp_str
, grpinfo
.rp_count
,
1163 grpinfo
.frag_rp_count
);
1166 buf
+= sizeof(struct bsmmsg_grpinfo
);
1167 offset
+= sizeof(struct bsmmsg_grpinfo
);
1169 group
.family
= AF_INET
;
1170 if (grpinfo
.group
.mask
> IPV4_MAX_BITLEN
) {
1173 "%s, v4 prefix length specified: %d is too long",
1174 __func__
, grpinfo
.group
.mask
);
1177 group
.prefixlen
= grpinfo
.group
.mask
;
1178 group
.u
.prefix4
.s_addr
= grpinfo
.group
.addr
.s_addr
;
1180 /* Get the Group node for the BSM rp table */
1181 bsgrp
= pim_bsm_get_bsgrp_node(scope
, &group
);
1183 if (grpinfo
.rp_count
== 0) {
1184 struct bsm_rpinfo
*old_rpinfo
;
1186 /* BSR explicitly no longer has RPs for this group */
1190 if (PIM_DEBUG_BSM
) {
1191 char grp_str
[INET_ADDRSTRLEN
];
1193 pim_inet4_dump("<Group?>", grpinfo
.group
.addr
,
1194 grp_str
, sizeof(grp_str
));
1195 zlog_debug("%s, Rp count is zero for group: %s",
1199 old_rpinfo
= bsm_rpinfos_first(bsgrp
->bsrp_list
);
1201 pim_rp_del(scope
->pim
, old_rpinfo
->rp_address
,
1202 group
, NULL
, RP_SRC_BSR
);
1204 pim_free_bsgrp_node(scope
->bsrp_table
, &bsgrp
->group
);
1205 pim_free_bsgrp_data(bsgrp
);
1211 zlog_debug("%s, Create new BSM Group node.",
1214 /* create a new node to be added to the tree. */
1215 bsgrp
= pim_bsm_new_bsgrp_node(scope
->bsrp_table
,
1220 "%s, Failed to get the BSM group node.",
1225 bsgrp
->scope
= scope
;
1228 pim_update_pending_rp_cnt(scope
, bsgrp
, bsm_frag_tag
,
1230 frag_rp_cnt
= grpinfo
.frag_rp_count
;
1233 while (frag_rp_cnt
--) {
1234 if (offset
+ (int)sizeof(struct bsmmsg_rpinfo
)
1238 "%s, buflen received: %u is less than the internal data structure of the packet would suggest",
1243 /* Extract RP address tlv from BSM */
1244 memcpy(&rpinfo
, buf
, sizeof(struct bsmmsg_rpinfo
));
1245 rpinfo
.rp_holdtime
= ntohs(rpinfo
.rp_holdtime
);
1246 buf
+= sizeof(struct bsmmsg_rpinfo
);
1247 offset
+= sizeof(struct bsmmsg_rpinfo
);
1249 if (PIM_DEBUG_BSM
) {
1250 char rp_str
[INET_ADDRSTRLEN
];
1252 pim_inet4_dump("<Rpaddr?>", rpinfo
.rpaddr
.addr
,
1253 rp_str
, sizeof(rp_str
));
1255 "%s, Rp address - %s; pri:%d hold:%d",
1256 __func__
, rp_str
, rpinfo
.rp_pri
,
1257 rpinfo
.rp_holdtime
);
1260 /* Call Install api to update grp-rp mappings */
1261 if (pim_install_bsm_grp_rp(scope
->pim
, bsgrp
, &rpinfo
))
1265 bsgrp
->pend_rp_cnt
-= ins_count
;
1267 if (!bsgrp
->pend_rp_cnt
) {
1270 "%s, Recvd all the rps for this group, so bsrp list with penidng rp list.",
1272 /* replace the bsrp_list with pending list */
1273 pim_instate_pend_list(bsgrp
);
1279 int pim_bsm_process(struct interface
*ifp
, pim_sgaddr
*sg
, uint8_t *buf
,
1280 uint32_t buf_size
, bool no_fwd
)
1282 struct bsm_hdr
*bshdr
;
1283 int sz
= PIM_GBL_SZ_ID
;
1284 struct bsmmsg_grpinfo
*msg_grp
;
1285 struct pim_interface
*pim_ifp
= NULL
;
1286 struct bsm_frag
*bsfrag
;
1287 struct pim_instance
*pim
;
1288 char bsr_str
[INET_ADDRSTRLEN
];
1290 bool empty_bsm
= false;
1292 /* BSM Packet acceptance validation */
1293 pim_ifp
= ifp
->info
;
1296 zlog_debug("%s: multicast not enabled on interface %s",
1297 __func__
, ifp
->name
);
1301 pim_ifp
->pim_ifstat_bsm_rx
++;
1305 /* Drop if bsm processing is disabled on interface */
1306 if (!pim_ifp
->bsm_enable
) {
1307 zlog_warn("%s: BSM not enabled on interface %s", __func__
,
1309 pim_ifp
->pim_ifstat_bsm_cfg_miss
++;
1314 if (buf_size
< (PIM_MSG_HEADER_LEN
+ sizeof(struct bsm_hdr
))) {
1317 "%s: received buffer length of %d which is too small to properly decode",
1318 __func__
, buf_size
);
1322 bshdr
= (struct bsm_hdr
*)(buf
+ PIM_MSG_HEADER_LEN
);
1323 pim_inet4_dump("<bsr?>", bshdr
->bsr_addr
.addr
, bsr_str
,
1325 if (bshdr
->hm_len
> IPV4_MAX_BITLEN
) {
1326 zlog_warn("Bad hashmask length for IPv4; got %hhu, expected value in range 0-32",
1331 pim
->global_scope
.hashMasklen
= bshdr
->hm_len
;
1332 frag_tag
= ntohs(bshdr
->frag_tag
);
1334 /* Identify empty BSM */
1335 if ((buf_size
- PIM_BSM_HDR_LEN
- PIM_MSG_HEADER_LEN
) < PIM_BSM_GRP_LEN
)
1339 msg_grp
= (struct bsmmsg_grpinfo
*)(buf
+ PIM_MSG_HEADER_LEN
1341 /* Currently we don't support scope zoned BSM */
1342 if (msg_grp
->group
.sz
) {
1345 "%s : Administratively scoped range BSM received",
1347 pim_ifp
->pim_ifstat_bsm_invalid_sz
++;
1353 /* Drop if bsr is not preferred bsr */
1354 if (!is_preferred_bsr(pim
, bshdr
->bsr_addr
.addr
, bshdr
->bsr_prio
)) {
1356 zlog_debug("%s : Received a non-preferred BSM",
1363 /* only accept no-forward BSM if quick refresh on startup */
1364 if ((pim
->global_scope
.accept_nofwd_bsm
)
1365 || (frag_tag
== pim
->global_scope
.bsm_frag_tag
)) {
1366 pim
->global_scope
.accept_nofwd_bsm
= false;
1370 "%s : nofwd_bsm received on %s when accpt_nofwd_bsm false",
1373 pim_ifp
->pim_ifstat_ucast_bsm_cfg_miss
++;
1379 if (!pim_addr_cmp(sg
->grp
, qpim_all_pim_routers_addr
))
1384 /* Multicast BSMs are only accepted if source interface & IP
1385 * match RPF towards the BSR's IP address, or they have
1388 if (!no_fwd
&& !pim_nht_bsr_rpf_check(pim
, bshdr
->bsr_addr
.addr
,
1392 "BSM check: RPF to BSR %s is not %pPA%%%s",
1393 bsr_str
, &sg
->src
, ifp
->name
);
1397 } else if (if_address_is_local(&sg
->grp
, PIM_AF
, pim
->vrf
->vrf_id
)) {
1398 /* Unicast BSM received - if ucast bsm not enabled on
1399 * the interface, drop it
1401 if (!pim_ifp
->ucast_bsm_accept
) {
1404 "%s : Unicast BSM not enabled on interface %s",
1405 __func__
, ifp
->name
);
1406 pim_ifp
->pim_ifstat_ucast_bsm_cfg_miss
++;
1413 zlog_debug("%s : Invalid destination address",
1421 zlog_debug("%s : Empty Pref BSM received", __func__
);
1423 /* Parse Update bsm rp table and install/uninstall rp if required */
1424 if (!pim_bsm_parse_install_g2rp(
1425 &pim_ifp
->pim
->global_scope
,
1426 (buf
+ PIM_BSM_HDR_LEN
+ PIM_MSG_HEADER_LEN
),
1427 (buf_size
- PIM_BSM_HDR_LEN
- PIM_MSG_HEADER_LEN
),
1429 if (PIM_DEBUG_BSM
) {
1430 zlog_debug("%s, Parsing BSM failed.", __func__
);
1435 /* Restart the bootstrap timer */
1436 pim_bs_timer_restart(&pim_ifp
->pim
->global_scope
,
1437 PIM_BSR_DEFAULT_TIMEOUT
);
1439 /* If new BSM received, clear the old bsm database */
1440 if (pim_ifp
->pim
->global_scope
.bsm_frag_tag
!= frag_tag
) {
1441 if (PIM_DEBUG_BSM
) {
1442 zlog_debug("%s: Current frag tag: %d Frag teg rcvd: %d",
1444 pim_ifp
->pim
->global_scope
.bsm_frag_tag
,
1447 pim_bsm_frags_free(&pim_ifp
->pim
->global_scope
);
1448 pim_ifp
->pim
->global_scope
.bsm_frag_tag
= frag_tag
;
1451 /* update the scope information from bsm */
1452 pim_bsm_update(pim
, bshdr
->bsr_addr
.addr
, bshdr
->bsr_prio
);
1455 pim_bsm_fwd_whole_sz(pim_ifp
->pim
, buf
, buf_size
, sz
);
1456 bsfrag
= XCALLOC(MTYPE_PIM_BSM_FRAG
,
1457 sizeof(struct bsm_frag
) + buf_size
);
1459 bsfrag
->size
= buf_size
;
1460 memcpy(bsfrag
->data
, buf
, buf_size
);
1461 bsm_frags_add_tail(pim_ifp
->pim
->global_scope
.bsm_frags
,