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