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