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,
24 #include "pim_iface.h"
25 #include "pim_instance.h"
27 #include "pim_hello.h"
33 /* Functions forward declaration */
34 static void pim_bs_timer_start(struct bsm_scope
*scope
, int bs_timeout
);
35 static void pim_g2rp_timer_start(struct bsm_rpinfo
*bsrp
, int hold_time
);
36 static inline void pim_g2rp_timer_restart(struct bsm_rpinfo
*bsrp
,
40 DEFINE_MTYPE_STATIC(PIMD
, PIM_BSGRP_NODE
, "PIM BSR advertised grp info")
41 DEFINE_MTYPE_STATIC(PIMD
, PIM_BSRP_NODE
, "PIM BSR advertised RP info")
42 DEFINE_MTYPE_STATIC(PIMD
, PIM_BSM_INFO
, "PIM BSM Info")
43 DEFINE_MTYPE_STATIC(PIMD
, PIM_BSM_PKT_VAR_MEM
, "PIM BSM Packet")
45 /* pim_bsm_write_config - Write the interface pim bsm configuration.*/
46 void pim_bsm_write_config(struct vty
*vty
, struct interface
*ifp
)
48 struct pim_interface
*pim_ifp
= ifp
->info
;
51 if (!pim_ifp
->bsm_enable
)
52 vty_out(vty
, " no ip pim bsm\n");
53 if (!pim_ifp
->ucast_bsm_accept
)
54 vty_out(vty
, " no ip pim unicast-bsm\n");
58 static void pim_free_bsgrp_data(struct bsgrp_node
*bsgrp_node
)
60 if (bsgrp_node
->bsrp_list
)
61 list_delete(&bsgrp_node
->bsrp_list
);
62 if (bsgrp_node
->partial_bsrp_list
)
63 list_delete(&bsgrp_node
->partial_bsrp_list
);
64 XFREE(MTYPE_PIM_BSGRP_NODE
, bsgrp_node
);
67 static void pim_free_bsgrp_node(struct route_table
*rt
, struct prefix
*grp
)
69 struct route_node
*rn
;
71 rn
= route_node_lookup(rt
, grp
);
74 route_unlock_node(rn
);
75 route_unlock_node(rn
);
79 static void pim_bsm_node_free(struct bsm_info
*bsm
)
82 XFREE(MTYPE_PIM_BSM_PKT_VAR_MEM
, bsm
->bsm
);
83 XFREE(MTYPE_PIM_BSM_INFO
, bsm
);
86 static int pim_on_bs_timer(struct thread
*t
)
88 struct route_node
*rn
;
89 struct bsm_scope
*scope
;
90 struct bsgrp_node
*bsgrp_node
;
91 struct bsm_rpinfo
*bsrp
;
93 char buf
[PREFIX2STR_BUFFER
];
94 bool is_bsr_tracking
= true;
96 scope
= THREAD_ARG(t
);
97 THREAD_OFF(scope
->bs_timer
);
100 zlog_debug("%s: Bootstrap Timer expired for scope: %d",
101 __PRETTY_FUNCTION__
, scope
->sz_id
);
103 /* Remove next hop tracking for the bsr */
104 nht_p
.family
= AF_INET
;
105 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
106 nht_p
.u
.prefix4
= scope
->current_bsr
;
108 prefix2str(&nht_p
, buf
, sizeof(buf
));
109 zlog_debug("%s: Deregister BSR addr %s with Zebra NHT",
110 __PRETTY_FUNCTION__
, buf
);
112 pim_delete_tracked_nexthop(scope
->pim
, &nht_p
, NULL
, NULL
,
115 /* Reset scope zone data */
116 scope
->accept_nofwd_bsm
= false;
117 scope
->state
= ACCEPT_ANY
;
118 scope
->current_bsr
.s_addr
= INADDR_ANY
;
119 scope
->current_bsr_prio
= 0;
120 scope
->current_bsr_first_ts
= 0;
121 scope
->current_bsr_last_ts
= 0;
122 scope
->bsm_frag_tag
= 0;
123 list_delete_all_node(scope
->bsm_list
);
125 for (rn
= route_top(scope
->bsrp_table
); rn
; rn
= route_next(rn
)) {
127 bsgrp_node
= (struct bsgrp_node
*)rn
->info
;
130 zlog_debug("%s: bsgrp_node is null",
131 __PRETTY_FUNCTION__
);
134 /* Give grace time for rp to continue for another hold time */
135 if ((bsgrp_node
->bsrp_list
) && (bsgrp_node
->bsrp_list
->count
)) {
136 bsrp
= listnode_head(bsgrp_node
->bsrp_list
);
137 pim_g2rp_timer_restart(bsrp
, bsrp
->rp_holdtime
);
139 /* clear pending list */
140 if ((bsgrp_node
->partial_bsrp_list
)
141 && (bsgrp_node
->partial_bsrp_list
->count
)) {
142 list_delete_all_node(bsgrp_node
->partial_bsrp_list
);
143 bsgrp_node
->pend_rp_cnt
= 0;
149 static void pim_bs_timer_stop(struct bsm_scope
*scope
)
152 zlog_debug("%s : BS timer being stopped of sz: %d",
153 __PRETTY_FUNCTION__
, scope
->sz_id
);
154 THREAD_OFF(scope
->bs_timer
);
157 static void pim_bs_timer_start(struct bsm_scope
*scope
, int bs_timeout
)
161 zlog_debug("%s : Invalid scope(NULL).",
162 __PRETTY_FUNCTION__
);
165 THREAD_OFF(scope
->bs_timer
);
167 zlog_debug("%s : starting bs timer for scope %d with timeout %d secs",
168 __PRETTY_FUNCTION__
, scope
->sz_id
, bs_timeout
);
169 thread_add_timer(router
->master
, pim_on_bs_timer
, scope
, bs_timeout
,
173 static inline void pim_bs_timer_restart(struct bsm_scope
*scope
, int bs_timeout
)
175 pim_bs_timer_start(scope
, bs_timeout
);
178 void pim_bsm_proc_init(struct pim_instance
*pim
)
180 memset(&pim
->global_scope
, 0, sizeof(struct bsm_scope
));
182 pim
->global_scope
.sz_id
= PIM_GBL_SZ_ID
;
183 pim
->global_scope
.bsrp_table
= route_table_init();
184 pim
->global_scope
.accept_nofwd_bsm
= true;
185 pim
->global_scope
.state
= NO_INFO
;
186 pim
->global_scope
.pim
= pim
;
187 pim
->global_scope
.bsm_list
= list_new();
188 pim
->global_scope
.bsm_list
->del
= (void (*)(void *))pim_bsm_node_free
;
189 pim_bs_timer_start(&pim
->global_scope
, PIM_BS_TIME
);
192 void pim_bsm_proc_free(struct pim_instance
*pim
)
194 struct route_node
*rn
;
195 struct bsgrp_node
*bsgrp
;
197 pim_bs_timer_stop(&pim
->global_scope
);
199 if (pim
->global_scope
.bsm_list
)
200 list_delete(&pim
->global_scope
.bsm_list
);
202 for (rn
= route_top(pim
->global_scope
.bsrp_table
); rn
;
203 rn
= route_next(rn
)) {
207 pim_free_bsgrp_data(bsgrp
);
210 if (pim
->global_scope
.bsrp_table
)
211 route_table_finish(pim
->global_scope
.bsrp_table
);
214 static bool is_hold_time_elapsed(void *data
)
216 struct bsm_rpinfo
*bsrp
;
220 if (bsrp
->elapse_time
< bsrp
->rp_holdtime
)
226 static int pim_on_g2rp_timer(struct thread
*t
)
228 struct bsm_rpinfo
*bsrp
;
229 struct bsm_rpinfo
*bsrp_node
;
230 struct bsgrp_node
*bsgrp_node
;
231 struct listnode
*bsrp_ln
;
232 struct pim_instance
*pim
;
233 struct rp_info
*rp_info
;
234 struct route_node
*rn
;
236 struct in_addr bsrp_addr
;
238 bsrp
= THREAD_ARG(t
);
239 THREAD_OFF(bsrp
->g2rp_timer
);
240 bsgrp_node
= bsrp
->bsgrp_node
;
242 /* elapse time is the hold time of expired node */
243 elapse
= bsrp
->rp_holdtime
;
244 bsrp_addr
= bsrp
->rp_address
;
246 /* update elapse for all bsrp nodes */
247 for (ALL_LIST_ELEMENTS_RO(bsgrp_node
->bsrp_list
, bsrp_ln
, bsrp_node
))
248 bsrp_node
->elapse_time
+= elapse
;
250 /* remove the expired nodes from the list */
251 list_filter_out_nodes(bsgrp_node
->bsrp_list
, is_hold_time_elapsed
);
253 /* Get the next elected rp node */
254 bsrp
= listnode_head(bsgrp_node
->bsrp_list
);
255 pim
= bsgrp_node
->scope
->pim
;
256 rn
= route_node_lookup(pim
->rp_table
, &bsgrp_node
->group
);
259 zlog_warn("%s: Route node doesn't exist", __PRETTY_FUNCTION__
);
263 rp_info
= (struct rp_info
*)rn
->info
;
266 route_unlock_node(rn
);
270 if (rp_info
->rp_src
!= RP_SRC_STATIC
) {
271 /* If new rp available, change it else delete the existing */
273 bsrp_addr
= bsrp
->rp_address
;
274 pim_g2rp_timer_start(
275 bsrp
, (bsrp
->rp_holdtime
- bsrp
->elapse_time
));
276 pim_rp_change(pim
, bsrp_addr
, bsgrp_node
->group
,
279 pim_rp_del(pim
, bsrp_addr
, bsgrp_node
->group
, NULL
,
284 if ((!bsgrp_node
->bsrp_list
->count
)
285 && (!bsgrp_node
->partial_bsrp_list
->count
)) {
286 pim_free_bsgrp_node(pim
->global_scope
.bsrp_table
,
288 pim_free_bsgrp_data(bsgrp_node
);
294 static void pim_g2rp_timer_start(struct bsm_rpinfo
*bsrp
, int hold_time
)
298 zlog_debug("%s : Invalid brsp(NULL).",
299 __PRETTY_FUNCTION__
);
302 THREAD_OFF(bsrp
->g2rp_timer
);
307 "%s : starting g2rp timer for grp: %s - rp: %s with timeout %d secs(Actual Hold time : %d secs)",
309 prefix2str(&bsrp
->bsgrp_node
->group
, buf
, 48),
310 inet_ntoa(bsrp
->rp_address
), hold_time
,
314 thread_add_timer(router
->master
, pim_on_g2rp_timer
, bsrp
, hold_time
,
318 static inline void pim_g2rp_timer_restart(struct bsm_rpinfo
*bsrp
,
321 pim_g2rp_timer_start(bsrp
, hold_time
);
324 static bool pim_bsr_rpf_check(struct pim_instance
*pim
, struct in_addr bsr
,
325 struct in_addr ip_src_addr
)
327 struct pim_nexthop nexthop
;
330 memset(&nexthop
, 0, sizeof(nexthop
));
332 /* New BSR recived */
333 if (bsr
.s_addr
!= pim
->global_scope
.current_bsr
.s_addr
) {
334 result
= pim_nexthop_match(pim
, bsr
, ip_src_addr
);
336 /* Nexthop lookup pass for the new BSR address */
341 char bsr_str
[INET_ADDRSTRLEN
];
343 pim_inet4_dump("<bsr?>", bsr
, bsr_str
, sizeof(bsr_str
));
344 zlog_debug("%s : No route to BSR address %s",
345 __PRETTY_FUNCTION__
, bsr_str
);
350 return pim_nexthop_match_nht_cache(pim
, bsr
, ip_src_addr
);
353 static bool is_preferred_bsr(struct pim_instance
*pim
, struct in_addr bsr
,
356 if (bsr
.s_addr
== pim
->global_scope
.current_bsr
.s_addr
)
359 if (bsr_prio
> pim
->global_scope
.current_bsr_prio
)
362 else if (bsr_prio
== pim
->global_scope
.current_bsr_prio
) {
363 if (bsr
.s_addr
>= pim
->global_scope
.current_bsr
.s_addr
)
371 static void pim_bsm_update(struct pim_instance
*pim
, struct in_addr bsr
,
374 struct pim_nexthop_cache pnc
;
376 if (bsr
.s_addr
!= pim
->global_scope
.current_bsr
.s_addr
) {
378 char buf
[PREFIX2STR_BUFFER
];
379 bool is_bsr_tracking
= true;
381 /* De-register old BSR and register new BSR with Zebra NHT */
382 nht_p
.family
= AF_INET
;
383 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
385 if (pim
->global_scope
.current_bsr
.s_addr
!= INADDR_ANY
) {
386 nht_p
.u
.prefix4
= pim
->global_scope
.current_bsr
;
388 prefix2str(&nht_p
, buf
, sizeof(buf
));
390 "%s: Deregister BSR addr %s with Zebra NHT",
391 __PRETTY_FUNCTION__
, buf
);
393 pim_delete_tracked_nexthop(pim
, &nht_p
, NULL
, NULL
,
397 nht_p
.u
.prefix4
= bsr
;
399 prefix2str(&nht_p
, buf
, sizeof(buf
));
401 "%s: NHT Register BSR addr %s with Zebra NHT",
402 __PRETTY_FUNCTION__
, buf
);
405 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
406 pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, NULL
,
407 is_bsr_tracking
, &pnc
);
408 pim
->global_scope
.current_bsr
= bsr
;
409 pim
->global_scope
.current_bsr_first_ts
=
410 pim_time_monotonic_sec();
411 pim
->global_scope
.state
= ACCEPT_PREFERRED
;
413 pim
->global_scope
.current_bsr_prio
= bsr_prio
;
414 pim
->global_scope
.current_bsr_last_ts
= pim_time_monotonic_sec();
417 struct bsgrp_node
*pim_bsm_get_bsgrp_node(struct bsm_scope
*scope
,
420 struct route_node
*rn
;
421 struct bsgrp_node
*bsgrp
;
423 rn
= route_node_lookup(scope
->bsrp_table
, grp
);
426 zlog_debug("%s: Route node doesn't exist for the group",
427 __PRETTY_FUNCTION__
);
431 route_unlock_node(rn
);
436 int pim_bsm_process(struct interface
*ifp
, struct ip
*ip_hdr
, uint8_t *buf
,
437 uint32_t buf_size
, bool no_fwd
)
439 struct bsm_hdr
*bshdr
;
440 struct bsmmsg_grpinfo
*msg_grp
;
441 struct pim_interface
*pim_ifp
= NULL
;
442 struct pim_instance
*pim
;
443 char bsr_str
[INET_ADDRSTRLEN
];
445 bool empty_bsm
= FALSE
;
447 /* BSM Packet acceptance validation */
451 zlog_debug("%s: multicast not enabled on interface %s",
452 __PRETTY_FUNCTION__
, ifp
->name
);
456 pim_ifp
->pim_ifstat_bsm_rx
++;
460 /* Drop if bsm processing is disabled on interface */
461 if (!pim_ifp
->bsm_enable
) {
462 zlog_warn("%s: BSM not enabled on interface %s",
463 __PRETTY_FUNCTION__
, ifp
->name
);
464 pim_ifp
->pim_ifstat_bsm_cfg_miss
++;
469 bshdr
= (struct bsm_hdr
*)(buf
+ PIM_MSG_HEADER_LEN
);
470 pim_inet4_dump("<bsr?>", bshdr
->bsr_addr
.addr
, bsr_str
,
472 pim
->global_scope
.hashMasklen
= bshdr
->hm_len
;
473 frag_tag
= ntohs(bshdr
->frag_tag
);
475 /* Identify empty BSM */
476 if ((buf_size
- PIM_BSM_HDR_LEN
- PIM_MSG_HEADER_LEN
) < PIM_BSM_GRP_LEN
)
480 msg_grp
= (struct bsmmsg_grpinfo
*)(buf
+ PIM_MSG_HEADER_LEN
482 /* Currently we don't support scope zoned BSM */
483 if (msg_grp
->group
.sz
) {
486 "%s : Administratively scoped range BSM received",
487 __PRETTY_FUNCTION__
);
488 pim_ifp
->pim_ifstat_bsm_invalid_sz
++;
494 /* Drop if bsr is not preferred bsr */
495 if (!is_preferred_bsr(pim
, bshdr
->bsr_addr
.addr
, bshdr
->bsr_prio
)) {
497 zlog_debug("%s : Received a non-preferred BSM",
498 __PRETTY_FUNCTION__
);
504 /* only accept no-forward BSM if quick refresh on startup */
505 if ((pim
->global_scope
.accept_nofwd_bsm
)
506 || (frag_tag
== pim
->global_scope
.bsm_frag_tag
)) {
507 pim
->global_scope
.accept_nofwd_bsm
= false;
511 "%s : nofwd_bsm received on %s when accpt_nofwd_bsm false",
512 __PRETTY_FUNCTION__
, bsr_str
);
514 pim_ifp
->pim_ifstat_ucast_bsm_cfg_miss
++;
519 /* Mulicast BSM received */
520 if (ip_hdr
->ip_dst
.s_addr
== qpim_all_pim_routers_addr
.s_addr
) {
522 if (!pim_bsr_rpf_check(pim
, bshdr
->bsr_addr
.addr
,
526 "%s : RPF check fail for BSR address %s",
527 __PRETTY_FUNCTION__
, bsr_str
);
532 } else if (if_lookup_exact_address(&ip_hdr
->ip_dst
, AF_INET
,
534 /* Unicast BSM received - if ucast bsm not enabled on
535 * the interface, drop it
537 if (!pim_ifp
->ucast_bsm_accept
) {
540 "%s : Unicast BSM not enabled on interface %s",
541 __PRETTY_FUNCTION__
, ifp
->name
);
542 pim_ifp
->pim_ifstat_ucast_bsm_cfg_miss
++;
549 zlog_debug("%s : Invalid destination address",
550 __PRETTY_FUNCTION__
);
557 zlog_debug("%s : Empty Pref BSM received",
558 __PRETTY_FUNCTION__
);
560 /* Restart the bootstrap timer */
561 pim_bs_timer_restart(&pim_ifp
->pim
->global_scope
,
562 PIM_BSR_DEFAULT_TIMEOUT
);
564 /* If new BSM received, clear the old bsm database */
565 if (pim_ifp
->pim
->global_scope
.bsm_frag_tag
!= frag_tag
) {
567 zlog_debug("%s: Current frag tag: %d Frag teg rcvd: %d",
569 pim_ifp
->pim
->global_scope
.bsm_frag_tag
,
572 list_delete_all_node(pim_ifp
->pim
->global_scope
.bsm_list
);
573 pim_ifp
->pim
->global_scope
.bsm_frag_tag
= frag_tag
;
576 /* update the scope information from bsm */
577 pim_bsm_update(pim
, bshdr
->bsr_addr
.addr
, bshdr
->bsr_prio
);