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"
32 #include "pim_hello.h"
38 /* Functions forward declaration */
39 static void pim_bs_timer_start(struct bsm_scope
*scope
, int bs_timeout
);
40 static void pim_g2rp_timer_start(struct bsm_rpinfo
*bsrp
, int hold_time
);
41 static inline void pim_g2rp_timer_restart(struct bsm_rpinfo
*bsrp
,
45 DEFINE_MTYPE_STATIC(PIMD
, PIM_BSGRP_NODE
, "PIM BSR advertised grp info")
46 DEFINE_MTYPE_STATIC(PIMD
, PIM_BSRP_NODE
, "PIM BSR advertised RP info")
47 DEFINE_MTYPE_STATIC(PIMD
, PIM_BSM_INFO
, "PIM BSM Info")
48 DEFINE_MTYPE_STATIC(PIMD
, PIM_BSM_PKT_VAR_MEM
, "PIM BSM Packet")
50 /* All bsm packets forwarded shall be fit within ip mtu less iphdr(max) */
51 #define MAX_IP_HDR_LEN 24
53 /* pim_bsm_write_config - Write the interface pim bsm configuration.*/
54 void pim_bsm_write_config(struct vty
*vty
, struct interface
*ifp
)
56 struct pim_interface
*pim_ifp
= ifp
->info
;
59 if (!pim_ifp
->bsm_enable
)
60 vty_out(vty
, " no ip pim bsm\n");
61 if (!pim_ifp
->ucast_bsm_accept
)
62 vty_out(vty
, " no ip pim unicast-bsm\n");
66 static void pim_free_bsgrp_data(struct bsgrp_node
*bsgrp_node
)
68 if (bsgrp_node
->bsrp_list
)
69 list_delete(&bsgrp_node
->bsrp_list
);
70 if (bsgrp_node
->partial_bsrp_list
)
71 list_delete(&bsgrp_node
->partial_bsrp_list
);
72 XFREE(MTYPE_PIM_BSGRP_NODE
, bsgrp_node
);
75 static void pim_free_bsgrp_node(struct route_table
*rt
, struct prefix
*grp
)
77 struct route_node
*rn
;
79 rn
= route_node_lookup(rt
, grp
);
82 route_unlock_node(rn
);
83 route_unlock_node(rn
);
87 static void pim_bsm_node_free(struct bsm_info
*bsm
)
90 XFREE(MTYPE_PIM_BSM_PKT_VAR_MEM
, bsm
->bsm
);
91 XFREE(MTYPE_PIM_BSM_INFO
, bsm
);
94 static int pim_g2rp_list_compare(struct bsm_rpinfo
*node1
,
95 struct bsm_rpinfo
*node2
)
98 * Step-1 : Loweset Rp priority will have higher precedance.
99 * Step-2 : If priority same then higher hash val will have
101 * Step-3 : If Hash val is same then highest rp address will
104 if (node1
->rp_prio
< node2
->rp_prio
)
106 if (node1
->rp_prio
> node2
->rp_prio
)
108 if (node1
->hash
< node2
->hash
)
110 if (node1
->hash
> node2
->hash
)
112 if (node1
->rp_address
.s_addr
< node2
->rp_address
.s_addr
)
114 if (node1
->rp_address
.s_addr
> node2
->rp_address
.s_addr
)
119 static void pim_free_bsrp_node(struct bsm_rpinfo
*bsrp_info
)
121 if (bsrp_info
->g2rp_timer
)
122 THREAD_OFF(bsrp_info
->g2rp_timer
);
123 XFREE(MTYPE_PIM_BSRP_NODE
, bsrp_info
);
126 static struct list
*pim_alloc_bsrp_list(void)
128 struct list
*new_list
= NULL
;
130 new_list
= list_new();
135 new_list
->cmp
= (int (*)(void *, void *))pim_g2rp_list_compare
;
136 new_list
->del
= (void (*)(void *))pim_free_bsrp_node
;
141 static struct bsgrp_node
*pim_bsm_new_bsgrp_node(struct route_table
*rt
,
144 struct route_node
*rn
;
145 struct bsgrp_node
*bsgrp
;
147 rn
= route_node_get(rt
, grp
);
149 zlog_warn("%s: route node creation failed",
150 __PRETTY_FUNCTION__
);
153 bsgrp
= XCALLOC(MTYPE_PIM_BSGRP_NODE
, sizeof(struct bsgrp_node
));
156 bsgrp
->bsrp_list
= pim_alloc_bsrp_list();
157 bsgrp
->partial_bsrp_list
= pim_alloc_bsrp_list();
159 if ((!bsgrp
->bsrp_list
) || (!bsgrp
->partial_bsrp_list
)) {
160 route_unlock_node(rn
);
161 pim_free_bsgrp_data(bsgrp
);
165 prefix_copy(&bsgrp
->group
, grp
);
169 static int pim_on_bs_timer(struct thread
*t
)
171 struct route_node
*rn
;
172 struct bsm_scope
*scope
;
173 struct bsgrp_node
*bsgrp_node
;
174 struct bsm_rpinfo
*bsrp
;
176 char buf
[PREFIX2STR_BUFFER
];
177 bool is_bsr_tracking
= true;
179 scope
= THREAD_ARG(t
);
180 THREAD_OFF(scope
->bs_timer
);
183 zlog_debug("%s: Bootstrap Timer expired for scope: %d",
184 __PRETTY_FUNCTION__
, scope
->sz_id
);
186 /* Remove next hop tracking for the bsr */
187 nht_p
.family
= AF_INET
;
188 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
189 nht_p
.u
.prefix4
= scope
->current_bsr
;
191 prefix2str(&nht_p
, buf
, sizeof(buf
));
192 zlog_debug("%s: Deregister BSR addr %s with Zebra NHT",
193 __PRETTY_FUNCTION__
, buf
);
195 pim_delete_tracked_nexthop(scope
->pim
, &nht_p
, NULL
, NULL
,
198 /* Reset scope zone data */
199 scope
->accept_nofwd_bsm
= false;
200 scope
->state
= ACCEPT_ANY
;
201 scope
->current_bsr
.s_addr
= INADDR_ANY
;
202 scope
->current_bsr_prio
= 0;
203 scope
->current_bsr_first_ts
= 0;
204 scope
->current_bsr_last_ts
= 0;
205 scope
->bsm_frag_tag
= 0;
206 list_delete_all_node(scope
->bsm_list
);
208 for (rn
= route_top(scope
->bsrp_table
); rn
; rn
= route_next(rn
)) {
210 bsgrp_node
= (struct bsgrp_node
*)rn
->info
;
213 zlog_debug("%s: bsgrp_node is null",
214 __PRETTY_FUNCTION__
);
217 /* Give grace time for rp to continue for another hold time */
218 if ((bsgrp_node
->bsrp_list
) && (bsgrp_node
->bsrp_list
->count
)) {
219 bsrp
= listnode_head(bsgrp_node
->bsrp_list
);
220 pim_g2rp_timer_restart(bsrp
, bsrp
->rp_holdtime
);
222 /* clear pending list */
223 if ((bsgrp_node
->partial_bsrp_list
)
224 && (bsgrp_node
->partial_bsrp_list
->count
)) {
225 list_delete_all_node(bsgrp_node
->partial_bsrp_list
);
226 bsgrp_node
->pend_rp_cnt
= 0;
232 static void pim_bs_timer_stop(struct bsm_scope
*scope
)
235 zlog_debug("%s : BS timer being stopped of sz: %d",
236 __PRETTY_FUNCTION__
, scope
->sz_id
);
237 THREAD_OFF(scope
->bs_timer
);
240 static void pim_bs_timer_start(struct bsm_scope
*scope
, int bs_timeout
)
244 zlog_debug("%s : Invalid scope(NULL).",
245 __PRETTY_FUNCTION__
);
248 THREAD_OFF(scope
->bs_timer
);
250 zlog_debug("%s : starting bs timer for scope %d with timeout %d secs",
251 __PRETTY_FUNCTION__
, scope
->sz_id
, bs_timeout
);
252 thread_add_timer(router
->master
, pim_on_bs_timer
, scope
, bs_timeout
,
256 static inline void pim_bs_timer_restart(struct bsm_scope
*scope
, int bs_timeout
)
258 pim_bs_timer_start(scope
, bs_timeout
);
261 void pim_bsm_proc_init(struct pim_instance
*pim
)
263 memset(&pim
->global_scope
, 0, sizeof(struct bsm_scope
));
265 pim
->global_scope
.sz_id
= PIM_GBL_SZ_ID
;
266 pim
->global_scope
.bsrp_table
= route_table_init();
267 pim
->global_scope
.accept_nofwd_bsm
= true;
268 pim
->global_scope
.state
= NO_INFO
;
269 pim
->global_scope
.pim
= pim
;
270 pim
->global_scope
.bsm_list
= list_new();
271 pim
->global_scope
.bsm_list
->del
= (void (*)(void *))pim_bsm_node_free
;
272 pim_bs_timer_start(&pim
->global_scope
, PIM_BS_TIME
);
275 void pim_bsm_proc_free(struct pim_instance
*pim
)
277 struct route_node
*rn
;
278 struct bsgrp_node
*bsgrp
;
280 pim_bs_timer_stop(&pim
->global_scope
);
282 if (pim
->global_scope
.bsm_list
)
283 list_delete(&pim
->global_scope
.bsm_list
);
285 for (rn
= route_top(pim
->global_scope
.bsrp_table
); rn
;
286 rn
= route_next(rn
)) {
290 pim_free_bsgrp_data(bsgrp
);
293 route_table_finish(pim
->global_scope
.bsrp_table
);
296 static bool is_hold_time_elapsed(void *data
)
298 struct bsm_rpinfo
*bsrp
;
302 if (bsrp
->elapse_time
< bsrp
->rp_holdtime
)
308 static int pim_on_g2rp_timer(struct thread
*t
)
310 struct bsm_rpinfo
*bsrp
;
311 struct bsm_rpinfo
*bsrp_node
;
312 struct bsgrp_node
*bsgrp_node
;
313 struct listnode
*bsrp_ln
;
314 struct pim_instance
*pim
;
315 struct rp_info
*rp_info
;
316 struct route_node
*rn
;
318 struct in_addr bsrp_addr
;
320 bsrp
= THREAD_ARG(t
);
321 THREAD_OFF(bsrp
->g2rp_timer
);
322 bsgrp_node
= bsrp
->bsgrp_node
;
324 /* elapse time is the hold time of expired node */
325 elapse
= bsrp
->rp_holdtime
;
326 bsrp_addr
= bsrp
->rp_address
;
328 /* update elapse for all bsrp nodes */
329 for (ALL_LIST_ELEMENTS_RO(bsgrp_node
->bsrp_list
, bsrp_ln
, bsrp_node
))
330 bsrp_node
->elapse_time
+= elapse
;
332 /* remove the expired nodes from the list */
333 list_filter_out_nodes(bsgrp_node
->bsrp_list
, is_hold_time_elapsed
);
335 /* Get the next elected rp node */
336 bsrp
= listnode_head(bsgrp_node
->bsrp_list
);
337 pim
= bsgrp_node
->scope
->pim
;
338 rn
= route_node_lookup(pim
->rp_table
, &bsgrp_node
->group
);
341 zlog_warn("%s: Route node doesn't exist", __PRETTY_FUNCTION__
);
345 rp_info
= (struct rp_info
*)rn
->info
;
348 route_unlock_node(rn
);
352 if (rp_info
->rp_src
!= RP_SRC_STATIC
) {
353 /* If new rp available, change it else delete the existing */
355 bsrp_addr
= bsrp
->rp_address
;
356 pim_g2rp_timer_start(
357 bsrp
, (bsrp
->rp_holdtime
- bsrp
->elapse_time
));
358 pim_rp_change(pim
, bsrp_addr
, bsgrp_node
->group
,
361 pim_rp_del(pim
, bsrp_addr
, bsgrp_node
->group
, NULL
,
366 if ((!bsgrp_node
->bsrp_list
->count
)
367 && (!bsgrp_node
->partial_bsrp_list
->count
)) {
368 pim_free_bsgrp_node(pim
->global_scope
.bsrp_table
,
370 pim_free_bsgrp_data(bsgrp_node
);
376 static void pim_g2rp_timer_start(struct bsm_rpinfo
*bsrp
, int hold_time
)
380 zlog_debug("%s : Invalid brsp(NULL).",
381 __PRETTY_FUNCTION__
);
384 THREAD_OFF(bsrp
->g2rp_timer
);
389 "%s : starting g2rp timer for grp: %s - rp: %s with timeout %d secs(Actual Hold time : %d secs)",
391 prefix2str(&bsrp
->bsgrp_node
->group
, buf
, 48),
392 inet_ntoa(bsrp
->rp_address
), hold_time
,
396 thread_add_timer(router
->master
, pim_on_g2rp_timer
, bsrp
, hold_time
,
400 static inline void pim_g2rp_timer_restart(struct bsm_rpinfo
*bsrp
,
403 pim_g2rp_timer_start(bsrp
, hold_time
);
406 static void pim_g2rp_timer_stop(struct bsm_rpinfo
*bsrp
)
414 zlog_debug("%s : stopping g2rp timer for grp: %s - rp: %s",
416 prefix2str(&bsrp
->bsgrp_node
->group
, buf
, 48),
417 inet_ntoa(bsrp
->rp_address
));
420 THREAD_OFF(bsrp
->g2rp_timer
);
423 static bool is_hold_time_zero(void *data
)
425 struct bsm_rpinfo
*bsrp
;
429 if (bsrp
->rp_holdtime
)
435 static void pim_instate_pend_list(struct bsgrp_node
*bsgrp_node
)
437 struct bsm_rpinfo
*active
;
438 struct bsm_rpinfo
*pend
;
440 struct rp_info
*rp_info
;
441 struct route_node
*rn
;
442 struct pim_instance
*pim
;
443 struct rp_info
*rp_all
;
444 struct prefix group_all
;
445 bool had_rp_node
= true;
447 pim
= bsgrp_node
->scope
->pim
;
448 active
= listnode_head(bsgrp_node
->bsrp_list
);
450 /* Remove nodes with hold time 0 & check if list still has a head */
451 list_filter_out_nodes(bsgrp_node
->partial_bsrp_list
, is_hold_time_zero
);
452 pend
= listnode_head(bsgrp_node
->partial_bsrp_list
);
454 if (!str2prefix("224.0.0.0/4", &group_all
))
457 rp_all
= pim_rp_find_match_group(pim
, &group_all
);
458 rn
= route_node_lookup(pim
->rp_table
, &bsgrp_node
->group
);
461 pim_g2rp_timer_start(pend
, pend
->rp_holdtime
);
463 /* if rp node doesn't exist or exist but not configured(rp_all),
464 * install the rp from head(if exists) of partial list. List is
465 * is sorted such that head is the elected RP for the group.
467 if (!rn
|| (prefix_same(&rp_all
->group
, &bsgrp_node
->group
)
468 && pim_rpf_addr_is_inaddr_none(&rp_all
->rp
))) {
470 zlog_debug("%s: Route node doesn't exist",
471 __PRETTY_FUNCTION__
);
473 pim_rp_new(pim
, pend
->rp_address
, bsgrp_node
->group
,
477 rp_info
= (struct rp_info
*)rn
->info
;
479 route_unlock_node(rn
);
481 pim_rp_new(pim
, pend
->rp_address
,
482 bsgrp_node
->group
, NULL
, RP_SRC_BSR
);
487 /* We didn't have rp node and pending list is empty(unlikely), cleanup*/
488 if ((!had_rp_node
) && (!pend
)) {
489 pim_free_bsgrp_node(bsgrp_node
->scope
->bsrp_table
,
491 pim_free_bsgrp_data(bsgrp_node
);
495 if ((had_rp_node
) && (rp_info
->rp_src
!= RP_SRC_STATIC
)) {
496 /* This means we searched and got rp node, needs unlock */
497 route_unlock_node(rn
);
499 if (active
&& pend
) {
500 if ((active
->rp_address
.s_addr
501 != pend
->rp_address
.s_addr
))
502 pim_rp_change(pim
, pend
->rp_address
,
503 bsgrp_node
->group
, RP_SRC_BSR
);
506 /* Possible when the first BSM has group with 0 rp count */
507 if ((!active
) && (!pend
)) {
510 "%s: Both bsrp and partial list are empty",
511 __PRETTY_FUNCTION__
);
513 pim_free_bsgrp_node(bsgrp_node
->scope
->bsrp_table
,
515 pim_free_bsgrp_data(bsgrp_node
);
519 /* Possible when a group with 0 rp count received in BSM */
520 if ((active
) && (!pend
)) {
521 pim_rp_del(pim
, active
->rp_address
, bsgrp_node
->group
,
523 pim_free_bsgrp_node(bsgrp_node
->scope
->bsrp_table
,
526 zlog_debug("%s:Pend List is null,del grp node",
527 __PRETTY_FUNCTION__
);
529 pim_free_bsgrp_data(bsgrp_node
);
534 if ((had_rp_node
) && (rp_info
->rp_src
== RP_SRC_STATIC
)) {
535 /* We need to unlock rn this case */
536 route_unlock_node(rn
);
537 /* there is a chance that static rp exist and bsrp cleaned
538 * so clean bsgrp node if pending list empty
543 "%s: Partial list is empty, static rp exists",
544 __PRETTY_FUNCTION__
);
545 pim_free_bsgrp_node(bsgrp_node
->scope
->bsrp_table
,
547 pim_free_bsgrp_data(bsgrp_node
);
552 /* swap the list & delete all nodes in partial list (old bsrp_list)
554 * active is head of bsrp list
555 * pend is head of partial list
557 * active is head of partial list
558 * pend is head of bsrp list
559 * So check appriate head after swap and clean the new partial list
561 temp
= bsgrp_node
->bsrp_list
;
562 bsgrp_node
->bsrp_list
= bsgrp_node
->partial_bsrp_list
;
563 bsgrp_node
->partial_bsrp_list
= temp
;
566 pim_g2rp_timer_stop(active
);
567 list_delete_all_node(bsgrp_node
->partial_bsrp_list
);
571 static bool pim_bsr_rpf_check(struct pim_instance
*pim
, struct in_addr bsr
,
572 struct in_addr ip_src_addr
)
574 struct pim_nexthop nexthop
;
577 memset(&nexthop
, 0, sizeof(nexthop
));
579 /* New BSR recived */
580 if (bsr
.s_addr
!= pim
->global_scope
.current_bsr
.s_addr
) {
581 result
= pim_nexthop_match(pim
, bsr
, ip_src_addr
);
583 /* Nexthop lookup pass for the new BSR address */
588 char bsr_str
[INET_ADDRSTRLEN
];
590 pim_inet4_dump("<bsr?>", bsr
, bsr_str
, sizeof(bsr_str
));
591 zlog_debug("%s : No route to BSR address %s",
592 __PRETTY_FUNCTION__
, bsr_str
);
597 return pim_nexthop_match_nht_cache(pim
, bsr
, ip_src_addr
);
600 static bool is_preferred_bsr(struct pim_instance
*pim
, struct in_addr bsr
,
603 if (bsr
.s_addr
== pim
->global_scope
.current_bsr
.s_addr
)
606 if (bsr_prio
> pim
->global_scope
.current_bsr_prio
)
609 else if (bsr_prio
== pim
->global_scope
.current_bsr_prio
) {
610 if (bsr
.s_addr
>= pim
->global_scope
.current_bsr
.s_addr
)
618 static void pim_bsm_update(struct pim_instance
*pim
, struct in_addr bsr
,
621 struct pim_nexthop_cache pnc
;
623 if (bsr
.s_addr
!= pim
->global_scope
.current_bsr
.s_addr
) {
625 char buf
[PREFIX2STR_BUFFER
];
626 bool is_bsr_tracking
= true;
628 /* De-register old BSR and register new BSR with Zebra NHT */
629 nht_p
.family
= AF_INET
;
630 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
632 if (pim
->global_scope
.current_bsr
.s_addr
!= INADDR_ANY
) {
633 nht_p
.u
.prefix4
= pim
->global_scope
.current_bsr
;
635 prefix2str(&nht_p
, buf
, sizeof(buf
));
637 "%s: Deregister BSR addr %s with Zebra NHT",
638 __PRETTY_FUNCTION__
, buf
);
640 pim_delete_tracked_nexthop(pim
, &nht_p
, NULL
, NULL
,
644 nht_p
.u
.prefix4
= bsr
;
646 prefix2str(&nht_p
, buf
, sizeof(buf
));
648 "%s: NHT Register BSR addr %s with Zebra NHT",
649 __PRETTY_FUNCTION__
, buf
);
652 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
653 pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, NULL
,
654 is_bsr_tracking
, &pnc
);
655 pim
->global_scope
.current_bsr
= bsr
;
656 pim
->global_scope
.current_bsr_first_ts
=
657 pim_time_monotonic_sec();
658 pim
->global_scope
.state
= ACCEPT_PREFERRED
;
660 pim
->global_scope
.current_bsr_prio
= bsr_prio
;
661 pim
->global_scope
.current_bsr_last_ts
= pim_time_monotonic_sec();
664 static bool pim_bsm_send_intf(uint8_t *buf
, int len
, struct interface
*ifp
,
665 struct in_addr dst_addr
)
667 struct pim_interface
*pim_ifp
;
673 zlog_debug("%s: Pim interface not available for %s",
674 __PRETTY_FUNCTION__
, ifp
->name
);
678 if (pim_ifp
->pim_sock_fd
== -1) {
680 zlog_debug("%s: Pim sock not available for %s",
681 __PRETTY_FUNCTION__
, ifp
->name
);
685 if (pim_msg_send(pim_ifp
->pim_sock_fd
, pim_ifp
->primary_address
,
686 dst_addr
, buf
, len
, ifp
->name
)) {
687 zlog_warn("%s: Could not send BSM message on interface: %s",
688 __PRETTY_FUNCTION__
, ifp
->name
);
692 pim_ifp
->pim_ifstat_bsm_tx
++;
693 pim_ifp
->pim
->bsm_sent
++;
697 static bool pim_bsm_frag_send(uint8_t *buf
, uint32_t len
, struct interface
*ifp
,
698 uint32_t pim_mtu
, struct in_addr dst_addr
,
701 struct bsmmsg_grpinfo
*grpinfo
, *curgrp
;
702 uint8_t *firstgrp_ptr
;
705 uint32_t parsed_len
= 0;
706 uint32_t this_pkt_rem
;
707 uint32_t copy_byte_count
;
708 uint32_t this_pkt_len
;
709 uint8_t total_rp_cnt
;
713 bool pak_pending
= false;
715 /* MTU passed here is PIM MTU (IP MTU less IP Hdr) */
716 if (pim_mtu
< (PIM_MIN_BSM_LEN
)) {
718 "%s: mtu(pim mtu: %d) size less than minimum bootstrap len",
719 __PRETTY_FUNCTION__
, pim_mtu
);
722 "%s: mtu (pim mtu:%d) less than minimum bootstrap len",
723 __PRETTY_FUNCTION__
, pim_mtu
);
727 pak_start
= XCALLOC(MTYPE_PIM_BSM_PKT_VAR_MEM
, pim_mtu
);
731 /* Fill PIM header later before sending packet to calc checksum */
732 pkt
+= PIM_MSG_HEADER_LEN
;
733 buf
+= PIM_MSG_HEADER_LEN
;
735 /* copy bsm header to new packet at offset of pim hdr */
736 memcpy(pkt
, buf
, PIM_BSM_HDR_LEN
);
737 pkt
+= PIM_BSM_HDR_LEN
;
738 buf
+= PIM_BSM_HDR_LEN
;
739 parsed_len
+= (PIM_MSG_HEADER_LEN
+ PIM_BSM_HDR_LEN
);
741 /* Store the position of first grp ptr, which can be reused for
742 * next packet to start filling group. old bsm header and pim hdr
743 * remains. So need not be filled again for next packet onwards.
747 /* we received mtu excluding IP hdr len as param
748 * now this_pkt_rem is mtu excluding
749 * PIM_BSM_HDR_LEN + PIM_MSG_HEADER_LEN
751 this_pkt_rem
= pim_mtu
- (PIM_BSM_HDR_LEN
+ PIM_MSG_HEADER_LEN
);
753 /* For each group till the packet length parsed */
754 while (parsed_len
< len
) {
755 /* pkt ---> fragment's current pointer
756 * buf ---> input buffer's current pointer
757 * mtu ---> size of the pim packet - PIM header
758 * curgrp ---> current group on the fragment
759 * grpinfo ---> current group on the input buffer
760 * this_pkt_rem ---> bytes remaing on the current fragment
761 * rp_fit_cnt ---> num of rp for current grp that
763 * total_rp_cnt ---> total rp present for the group in the buf
764 * frag_rp_cnt ---> no of rp for the group to be fit in
766 * this_rp_cnt ---> how many rp have we parsed
768 grpinfo
= (struct bsmmsg_grpinfo
*)buf
;
769 memcpy(pkt
, buf
, PIM_BSM_GRP_LEN
);
770 curgrp
= (struct bsmmsg_grpinfo
*)pkt
;
771 parsed_len
+= PIM_BSM_GRP_LEN
;
772 pkt
+= PIM_BSM_GRP_LEN
;
773 buf
+= PIM_BSM_GRP_LEN
;
774 this_pkt_rem
-= PIM_BSM_GRP_LEN
;
776 /* initialize rp count and total_rp_cnt before the rp loop */
778 total_rp_cnt
= grpinfo
->frag_rp_count
;
780 /* Loop till all RPs for the group parsed */
781 while (this_rp_cnt
< total_rp_cnt
) {
782 /* All RP from a group processed here.
783 * group is pointed by grpinfo.
784 * At this point make sure buf pointing to a RP
787 rp_fit_cnt
= this_pkt_rem
/ PIM_BSM_RP_LEN
;
789 /* calculate how many rp am i going to copy in
792 if (rp_fit_cnt
> (total_rp_cnt
- this_rp_cnt
))
793 frag_rp_cnt
= total_rp_cnt
- this_rp_cnt
;
795 frag_rp_cnt
= rp_fit_cnt
;
797 /* populate the frag rp count for the current grp */
798 curgrp
->frag_rp_count
= frag_rp_cnt
;
799 copy_byte_count
= frag_rp_cnt
* PIM_BSM_RP_LEN
;
801 /* copy all the rp that we are fitting in this
804 memcpy(pkt
, buf
, copy_byte_count
);
805 this_rp_cnt
+= frag_rp_cnt
;
806 buf
+= copy_byte_count
;
807 pkt
+= copy_byte_count
;
808 parsed_len
+= copy_byte_count
;
809 this_pkt_rem
-= copy_byte_count
;
811 /* Either we couldn't fit all rp for the group or the
814 if ((this_rp_cnt
< total_rp_cnt
)
816 < (PIM_BSM_GRP_LEN
+ PIM_BSM_RP_LEN
))) {
817 /* No space to fit in more rp, send this pkt */
818 this_pkt_len
= pim_mtu
- this_pkt_rem
;
819 pim_msg_build_header(pak_start
, this_pkt_len
,
820 PIM_MSG_TYPE_BOOTSTRAP
,
822 pim_bsm_send_intf(pak_start
, this_pkt_len
, ifp
,
825 /* Construct next fragment. Reuse old packet */
827 this_pkt_rem
= pim_mtu
- (PIM_BSM_HDR_LEN
828 + PIM_MSG_HEADER_LEN
);
830 /* If pkt can't accomodate next group + atleast
831 * one rp, we must break out of this inner loop
832 * and process next RP
834 if (total_rp_cnt
== this_rp_cnt
)
837 /* If some more RPs for the same group pending,
840 memcpy(pkt
, (uint8_t *)grpinfo
,
842 curgrp
= (struct bsmmsg_grpinfo
*)pkt
;
843 pkt
+= PIM_BSM_GRP_LEN
;
844 this_pkt_rem
-= PIM_BSM_GRP_LEN
;
847 /* We filled something but not yet sent out */
850 } /* while RP count */
851 } /*while parsed len */
853 /* Send if we have any unsent packet */
855 this_pkt_len
= pim_mtu
- this_pkt_rem
;
856 pim_msg_build_header(pak_start
, this_pkt_len
,
857 PIM_MSG_TYPE_BOOTSTRAP
, no_fwd
);
858 pim_bsm_send_intf(pak_start
, (pim_mtu
- this_pkt_rem
), ifp
,
861 XFREE(MTYPE_PIM_BSM_PKT_VAR_MEM
, pak_start
);
865 static void pim_bsm_fwd_whole_sz(struct pim_instance
*pim
, uint8_t *buf
,
866 uint32_t len
, int sz
)
868 struct interface
*ifp
;
869 struct pim_interface
*pim_ifp
;
870 struct in_addr dst_addr
;
875 /* For now only global scope zone is supported, so send on all
876 * pim interfaces in the vrf
878 dst_addr
= qpim_all_pim_routers_addr
;
879 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
881 if ((!pim_ifp
) || (!pim_ifp
->bsm_enable
))
883 pim_hello_require(ifp
);
884 pim_mtu
= ifp
->mtu
- MAX_IP_HDR_LEN
;
886 ret
= pim_bsm_frag_send(buf
, len
, ifp
, pim_mtu
,
889 zlog_debug("%s: pim_bsm_frag_send returned %s",
891 ret
? "TRUE" : "FALSE");
893 pim_msg_build_header(buf
, len
, PIM_MSG_TYPE_BOOTSTRAP
,
895 if (!pim_bsm_send_intf(buf
, len
, ifp
, dst_addr
)) {
898 "%s: pim_bsm_send_intf returned false",
899 __PRETTY_FUNCTION__
);
905 bool pim_bsm_new_nbr_fwd(struct pim_neighbor
*neigh
, struct interface
*ifp
)
907 struct in_addr dst_addr
;
908 struct pim_interface
*pim_ifp
;
909 struct bsm_scope
*scope
;
910 struct listnode
*bsm_ln
;
911 struct bsm_info
*bsminfo
;
912 char neigh_src_str
[INET_ADDRSTRLEN
];
918 pim_inet4_dump("<src?>", neigh
->source_addr
, neigh_src_str
,
919 sizeof(neigh_src_str
));
920 zlog_debug("%s: New neighbor %s seen on %s",
921 __PRETTY_FUNCTION__
, neigh_src_str
, ifp
->name
);
926 /* DR only forwards BSM packet */
927 if (pim_ifp
->pim_dr_addr
.s_addr
== pim_ifp
->primary_address
.s_addr
) {
930 "%s: It is not DR, so don't forward BSM packet",
931 __PRETTY_FUNCTION__
);
934 if (!pim_ifp
->bsm_enable
) {
936 zlog_debug("%s: BSM proc not enabled on %s",
937 __PRETTY_FUNCTION__
, ifp
->name
);
941 scope
= &pim_ifp
->pim
->global_scope
;
943 if (!scope
->bsm_list
->count
) {
945 zlog_debug("%s: BSM list for the scope is empty",
946 __PRETTY_FUNCTION__
);
950 if (!pim_ifp
->ucast_bsm_accept
) {
951 dst_addr
= qpim_all_pim_routers_addr
;
953 zlog_debug("%s: Sending BSM mcast to %s",
954 __PRETTY_FUNCTION__
, neigh_src_str
);
956 dst_addr
= neigh
->source_addr
;
958 zlog_debug("%s: Sending BSM ucast to %s",
959 __PRETTY_FUNCTION__
, neigh_src_str
);
961 pim_mtu
= ifp
->mtu
- MAX_IP_HDR_LEN
;
962 pim_hello_require(ifp
);
964 for (ALL_LIST_ELEMENTS_RO(scope
->bsm_list
, bsm_ln
, bsminfo
)) {
965 if (pim_mtu
< bsminfo
->size
) {
966 ret
= pim_bsm_frag_send(bsminfo
->bsm
, bsminfo
->size
,
967 ifp
, pim_mtu
, dst_addr
, no_fwd
);
971 "%s: pim_bsm_frag_send failed",
972 __PRETTY_FUNCTION__
);
975 /* Pim header needs to be constructed */
976 pim_msg_build_header(bsminfo
->bsm
, bsminfo
->size
,
977 PIM_MSG_TYPE_BOOTSTRAP
, no_fwd
);
978 ret
= pim_bsm_send_intf(bsminfo
->bsm
, bsminfo
->size
,
983 "%s: pim_bsm_frag_send failed",
984 __PRETTY_FUNCTION__
);
991 struct bsgrp_node
*pim_bsm_get_bsgrp_node(struct bsm_scope
*scope
,
994 struct route_node
*rn
;
995 struct bsgrp_node
*bsgrp
;
997 rn
= route_node_lookup(scope
->bsrp_table
, grp
);
1000 zlog_debug("%s: Route node doesn't exist for the group",
1001 __PRETTY_FUNCTION__
);
1005 route_unlock_node(rn
);
1010 static uint32_t hash_calc_on_grp_rp(struct prefix group
, struct in_addr rp
,
1011 uint8_t hashmasklen
)
1017 uint32_t mask
= 0xffffffff;
1019 /* mask to be made zero if hashmasklen is 0 because mask << 32
1020 * may not give 0. hashmasklen can be 0 to 32.
1022 if (hashmasklen
== 0)
1025 /* in_addr stores ip in big endian, hence network byte order
1026 * convert to uint32 before processing hash
1028 grpaddr
= ntohl(group
.u
.prefix4
.s_addr
);
1029 /* Avoid shifting by 32 bit on a 32 bit register */
1031 grpaddr
= grpaddr
& ((mask
<< (32 - hashmasklen
)));
1033 grpaddr
= grpaddr
& mask
;
1034 rp_add
= ntohl(rp
.s_addr
);
1035 temp
= 1103515245 * ((1103515245 * (uint64_t)grpaddr
+ 12345) ^ rp_add
)
1037 hash
= temp
& (0x7fffffff);
1041 static bool pim_install_bsm_grp_rp(struct pim_instance
*pim
,
1042 struct bsgrp_node
*grpnode
,
1043 struct bsmmsg_rpinfo
*rp
)
1045 struct bsm_rpinfo
*bsm_rpinfo
;
1046 uint8_t hashMask_len
= pim
->global_scope
.hashMasklen
;
1048 /*memory allocation for bsm_rpinfo */
1049 bsm_rpinfo
= XCALLOC(MTYPE_PIM_BSRP_NODE
, sizeof(*bsm_rpinfo
));
1051 bsm_rpinfo
->rp_prio
= rp
->rp_pri
;
1052 bsm_rpinfo
->rp_holdtime
= rp
->rp_holdtime
;
1053 memcpy(&bsm_rpinfo
->rp_address
, &rp
->rpaddr
.addr
,
1054 sizeof(struct in_addr
));
1055 bsm_rpinfo
->elapse_time
= 0;
1057 /* Back pointer to the group node. */
1058 bsm_rpinfo
->bsgrp_node
= grpnode
;
1060 /* update hash for this rp node */
1061 bsm_rpinfo
->hash
= hash_calc_on_grp_rp(grpnode
->group
, rp
->rpaddr
.addr
,
1063 if (listnode_add_sort_nodup(grpnode
->partial_bsrp_list
, bsm_rpinfo
)) {
1066 "%s, bs_rpinfo node added to the partial bs_rplist.\r\n",
1067 __PRETTY_FUNCTION__
);
1072 zlog_debug("%s: list node not added\n", __PRETTY_FUNCTION__
);
1074 XFREE(MTYPE_PIM_BSRP_NODE
, bsm_rpinfo
);
1078 static void pim_update_pending_rp_cnt(struct bsm_scope
*sz
,
1079 struct bsgrp_node
*bsgrp
,
1080 uint16_t bsm_frag_tag
,
1081 uint32_t total_rp_count
)
1083 if (bsgrp
->pend_rp_cnt
) {
1084 /* received bsm is different packet ,
1085 * it is not same fragment.
1087 if (bsm_frag_tag
!= bsgrp
->frag_tag
) {
1090 "%s,Received a new BSM ,so clear the pending bs_rpinfo list.\r\n",
1091 __PRETTY_FUNCTION__
);
1092 list_delete_all_node(bsgrp
->partial_bsrp_list
);
1093 bsgrp
->pend_rp_cnt
= total_rp_count
;
1096 bsgrp
->pend_rp_cnt
= total_rp_count
;
1098 bsgrp
->frag_tag
= bsm_frag_tag
;
1101 /* Parsing BSR packet and adding to partial list of corresponding bsgrp node */
1102 static bool pim_bsm_parse_install_g2rp(struct bsm_scope
*scope
, uint8_t *buf
,
1103 int buflen
, uint16_t bsm_frag_tag
)
1105 struct bsmmsg_grpinfo grpinfo
;
1106 struct bsmmsg_rpinfo rpinfo
;
1107 struct prefix group
;
1108 struct bsgrp_node
*bsgrp
= NULL
;
1109 int frag_rp_cnt
= 0;
1113 while (buflen
> offset
) {
1114 if (offset
+ (int)sizeof(struct bsmmsg_grpinfo
) > buflen
) {
1117 "%s: buflen received %d is less than the internal data structure of the packet would suggest",
1118 __PRETTY_FUNCTION__
, buflen
);
1121 /* Extract Group tlv from BSM */
1122 memcpy(&grpinfo
, buf
, sizeof(struct bsmmsg_grpinfo
));
1124 if (PIM_DEBUG_BSM
) {
1125 char grp_str
[INET_ADDRSTRLEN
];
1127 pim_inet4_dump("<Group?>", grpinfo
.group
.addr
, grp_str
,
1130 "%s, Group %s Rpcount:%d Fragment-Rp-count:%d\r\n",
1131 __PRETTY_FUNCTION__
, grp_str
, grpinfo
.rp_count
,
1132 grpinfo
.frag_rp_count
);
1135 buf
+= sizeof(struct bsmmsg_grpinfo
);
1136 offset
+= sizeof(struct bsmmsg_grpinfo
);
1138 if (grpinfo
.rp_count
== 0) {
1139 if (PIM_DEBUG_BSM
) {
1140 char grp_str
[INET_ADDRSTRLEN
];
1142 pim_inet4_dump("<Group?>", grpinfo
.group
.addr
,
1143 grp_str
, sizeof(grp_str
));
1145 "%s, Rp count is zero for group: %s\r\n",
1146 __PRETTY_FUNCTION__
, grp_str
);
1151 group
.family
= AF_INET
;
1152 if (grpinfo
.group
.mask
> IPV4_MAX_BITLEN
) {
1154 zlog_debug("%s, v4 prefix length specified: %d is too long",
1155 __PRETTY_FUNCTION__
, grpinfo
.group
.mask
);
1158 group
.prefixlen
= grpinfo
.group
.mask
;
1159 group
.u
.prefix4
.s_addr
= grpinfo
.group
.addr
.s_addr
;
1161 /* Get the Group node for the BSM rp table */
1162 bsgrp
= pim_bsm_get_bsgrp_node(scope
, &group
);
1167 "%s, Create new BSM Group node.\r\n",
1168 __PRETTY_FUNCTION__
);
1170 /* create a new node to be added to the tree. */
1171 bsgrp
= pim_bsm_new_bsgrp_node(scope
->bsrp_table
,
1176 "%s, Failed to get the BSM group node.\r\n",
1177 __PRETTY_FUNCTION__
);
1181 bsgrp
->scope
= scope
;
1184 pim_update_pending_rp_cnt(scope
, bsgrp
, bsm_frag_tag
,
1186 frag_rp_cnt
= grpinfo
.frag_rp_count
;
1189 while (frag_rp_cnt
--) {
1190 if (offset
+ (int)sizeof(struct bsmmsg_rpinfo
)
1194 "%s, buflen received: %u is less than the internal data structure of the packet would suggest",
1195 __PRETTY_FUNCTION__
, buflen
);
1199 /* Extract RP address tlv from BSM */
1200 memcpy(&rpinfo
, buf
, sizeof(struct bsmmsg_rpinfo
));
1201 rpinfo
.rp_holdtime
= ntohs(rpinfo
.rp_holdtime
);
1202 buf
+= sizeof(struct bsmmsg_rpinfo
);
1203 offset
+= sizeof(struct bsmmsg_rpinfo
);
1205 if (PIM_DEBUG_BSM
) {
1206 char rp_str
[INET_ADDRSTRLEN
];
1208 pim_inet4_dump("<Rpaddr?>", rpinfo
.rpaddr
.addr
,
1209 rp_str
, sizeof(rp_str
));
1211 "%s, Rp address - %s; pri:%d hold:%d\r\n",
1212 __PRETTY_FUNCTION__
, rp_str
,
1213 rpinfo
.rp_pri
, rpinfo
.rp_holdtime
);
1216 /* Call Install api to update grp-rp mappings */
1217 if (pim_install_bsm_grp_rp(scope
->pim
, bsgrp
, &rpinfo
))
1221 bsgrp
->pend_rp_cnt
-= ins_count
;
1223 if (!bsgrp
->pend_rp_cnt
) {
1226 "%s, Recvd all the rps for this group, so bsrp list with penidng rp list.",
1227 __PRETTY_FUNCTION__
);
1228 /* replace the bsrp_list with pending list */
1229 pim_instate_pend_list(bsgrp
);
1235 int pim_bsm_process(struct interface
*ifp
, struct ip
*ip_hdr
, uint8_t *buf
,
1236 uint32_t buf_size
, bool no_fwd
)
1238 struct bsm_hdr
*bshdr
;
1239 int sz
= PIM_GBL_SZ_ID
;
1240 struct bsmmsg_grpinfo
*msg_grp
;
1241 struct pim_interface
*pim_ifp
= NULL
;
1242 struct bsm_info
*bsminfo
;
1243 struct pim_instance
*pim
;
1244 char bsr_str
[INET_ADDRSTRLEN
];
1246 bool empty_bsm
= false;
1248 /* BSM Packet acceptance validation */
1249 pim_ifp
= ifp
->info
;
1252 zlog_debug("%s: multicast not enabled on interface %s",
1253 __PRETTY_FUNCTION__
, ifp
->name
);
1257 pim_ifp
->pim_ifstat_bsm_rx
++;
1261 /* Drop if bsm processing is disabled on interface */
1262 if (!pim_ifp
->bsm_enable
) {
1263 zlog_warn("%s: BSM not enabled on interface %s",
1264 __PRETTY_FUNCTION__
, ifp
->name
);
1265 pim_ifp
->pim_ifstat_bsm_cfg_miss
++;
1270 if (buf_size
< (PIM_MSG_HEADER_LEN
+ sizeof(struct bsm_hdr
))) {
1272 zlog_debug("%s: received buffer length of %d which is too small to properly decode",
1273 __PRETTY_FUNCTION__
, buf_size
);
1277 bshdr
= (struct bsm_hdr
*)(buf
+ PIM_MSG_HEADER_LEN
);
1278 pim_inet4_dump("<bsr?>", bshdr
->bsr_addr
.addr
, bsr_str
,
1280 pim
->global_scope
.hashMasklen
= bshdr
->hm_len
;
1281 frag_tag
= ntohs(bshdr
->frag_tag
);
1283 /* Identify empty BSM */
1284 if ((buf_size
- PIM_BSM_HDR_LEN
- PIM_MSG_HEADER_LEN
) < PIM_BSM_GRP_LEN
)
1288 msg_grp
= (struct bsmmsg_grpinfo
*)(buf
+ PIM_MSG_HEADER_LEN
1290 /* Currently we don't support scope zoned BSM */
1291 if (msg_grp
->group
.sz
) {
1294 "%s : Administratively scoped range BSM received",
1295 __PRETTY_FUNCTION__
);
1296 pim_ifp
->pim_ifstat_bsm_invalid_sz
++;
1302 /* Drop if bsr is not preferred bsr */
1303 if (!is_preferred_bsr(pim
, bshdr
->bsr_addr
.addr
, bshdr
->bsr_prio
)) {
1305 zlog_debug("%s : Received a non-preferred BSM",
1306 __PRETTY_FUNCTION__
);
1312 /* only accept no-forward BSM if quick refresh on startup */
1313 if ((pim
->global_scope
.accept_nofwd_bsm
)
1314 || (frag_tag
== pim
->global_scope
.bsm_frag_tag
)) {
1315 pim
->global_scope
.accept_nofwd_bsm
= false;
1319 "%s : nofwd_bsm received on %s when accpt_nofwd_bsm false",
1320 __PRETTY_FUNCTION__
, bsr_str
);
1322 pim_ifp
->pim_ifstat_ucast_bsm_cfg_miss
++;
1327 /* Mulicast BSM received */
1328 if (ip_hdr
->ip_dst
.s_addr
== qpim_all_pim_routers_addr
.s_addr
) {
1330 if (!pim_bsr_rpf_check(pim
, bshdr
->bsr_addr
.addr
,
1334 "%s : RPF check fail for BSR address %s",
1335 __PRETTY_FUNCTION__
, bsr_str
);
1340 } else if (if_lookup_exact_address(&ip_hdr
->ip_dst
, AF_INET
,
1342 /* Unicast BSM received - if ucast bsm not enabled on
1343 * the interface, drop it
1345 if (!pim_ifp
->ucast_bsm_accept
) {
1348 "%s : Unicast BSM not enabled on interface %s",
1349 __PRETTY_FUNCTION__
, ifp
->name
);
1350 pim_ifp
->pim_ifstat_ucast_bsm_cfg_miss
++;
1357 zlog_debug("%s : Invalid destination address",
1358 __PRETTY_FUNCTION__
);
1365 zlog_debug("%s : Empty Pref BSM received",
1366 __PRETTY_FUNCTION__
);
1368 /* Parse Update bsm rp table and install/uninstall rp if required */
1369 if (!pim_bsm_parse_install_g2rp(
1370 &pim_ifp
->pim
->global_scope
,
1371 (buf
+ PIM_BSM_HDR_LEN
+ PIM_MSG_HEADER_LEN
),
1372 (buf_size
- PIM_BSM_HDR_LEN
- PIM_MSG_HEADER_LEN
),
1374 if (PIM_DEBUG_BSM
) {
1375 zlog_debug("%s, Parsing BSM failed.\r\n",
1376 __PRETTY_FUNCTION__
);
1381 /* Restart the bootstrap timer */
1382 pim_bs_timer_restart(&pim_ifp
->pim
->global_scope
,
1383 PIM_BSR_DEFAULT_TIMEOUT
);
1385 /* If new BSM received, clear the old bsm database */
1386 if (pim_ifp
->pim
->global_scope
.bsm_frag_tag
!= frag_tag
) {
1387 if (PIM_DEBUG_BSM
) {
1388 zlog_debug("%s: Current frag tag: %d Frag teg rcvd: %d",
1389 __PRETTY_FUNCTION__
,
1390 pim_ifp
->pim
->global_scope
.bsm_frag_tag
,
1393 list_delete_all_node(pim_ifp
->pim
->global_scope
.bsm_list
);
1394 pim_ifp
->pim
->global_scope
.bsm_frag_tag
= frag_tag
;
1397 /* update the scope information from bsm */
1398 pim_bsm_update(pim
, bshdr
->bsr_addr
.addr
, bshdr
->bsr_prio
);
1401 pim_bsm_fwd_whole_sz(pim_ifp
->pim
, buf
, buf_size
, sz
);
1402 bsminfo
= XCALLOC(MTYPE_PIM_BSM_INFO
, sizeof(struct bsm_info
));
1404 bsminfo
->bsm
= XCALLOC(MTYPE_PIM_BSM_PKT_VAR_MEM
, buf_size
);
1406 bsminfo
->size
= buf_size
;
1407 memcpy(bsminfo
->bsm
, buf
, buf_size
);
1408 listnode_add(pim_ifp
->pim
->global_scope
.bsm_list
, bsminfo
);