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