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