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