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