]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_bsm.c
pimd: Parse the grp2rp mapping from BSM pkt and add to partial rp list
[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 */
22#include "if.h"
23#include "pimd.h"
24#include "pim_iface.h"
361b5843 25#include "pim_instance.h"
26#include "pim_rpf.h"
27#include "pim_hello.h"
28#include "pim_pim.h"
29#include "pim_nht.h"
30#include "pim_bsm.h"
31#include "pim_time.h"
32
33/* Functions forward declaration */
34static void pim_bs_timer_start(struct bsm_scope *scope, int bs_timeout);
a5164e97 35static void pim_g2rp_timer_start(struct bsm_rpinfo *bsrp, int hold_time);
36static inline void pim_g2rp_timer_restart(struct bsm_rpinfo *bsrp,
37 int hold_time);
23255dfd 38
39/* Memory Types */
40DEFINE_MTYPE_STATIC(PIMD, PIM_BSGRP_NODE, "PIM BSR advertised grp info")
41DEFINE_MTYPE_STATIC(PIMD, PIM_BSRP_NODE, "PIM BSR advertised RP info")
42DEFINE_MTYPE_STATIC(PIMD, PIM_BSM_INFO, "PIM BSM Info")
43DEFINE_MTYPE_STATIC(PIMD, PIM_BSM_PKT_VAR_MEM, "PIM BSM Packet")
361b5843 44
16c926c8 45/* pim_bsm_write_config - Write the interface pim bsm configuration.*/
d0e418b4 46void pim_bsm_write_config(struct vty *vty, struct interface *ifp)
16c926c8 47{
48 struct pim_interface *pim_ifp = ifp->info;
49
50 if (pim_ifp) {
51 if (!pim_ifp->bsm_enable)
52 vty_out(vty, " no ip pim bsm\n");
53 if (!pim_ifp->ucast_bsm_accept)
54 vty_out(vty, " no ip pim unicast-bsm\n");
55 }
56}
57
d0e418b4 58static void pim_free_bsgrp_data(struct bsgrp_node *bsgrp_node)
361b5843 59{
60 if (bsgrp_node->bsrp_list)
61 list_delete(&bsgrp_node->bsrp_list);
62 if (bsgrp_node->partial_bsrp_list)
63 list_delete(&bsgrp_node->partial_bsrp_list);
361b5843 64 XFREE(MTYPE_PIM_BSGRP_NODE, bsgrp_node);
65}
66
c295e391 67static void pim_free_bsgrp_node(struct route_table *rt, struct prefix *grp)
68{
69 struct route_node *rn;
70
71 rn = route_node_lookup(rt, grp);
72 if (rn) {
73 rn->info = NULL;
74 route_unlock_node(rn);
75 route_unlock_node(rn);
76 }
77}
78
361b5843 79static void pim_bsm_node_free(struct bsm_info *bsm)
80{
81 if (bsm->bsm)
82 XFREE(MTYPE_PIM_BSM_PKT_VAR_MEM, bsm->bsm);
83 XFREE(MTYPE_PIM_BSM_INFO, bsm);
84}
85
7b3e6ba1 86static int pim_g2rp_list_compare(struct bsm_rpinfo *node1,
87 struct bsm_rpinfo *node2)
88{
89 /* RP election Algo :
90 * Step-1 : Loweset Rp priority will have higher precedance.
91 * Step-2 : If priority same then higher hash val will have
92 * higher precedance.
93 * Step-3 : If Hash val is same then highest rp address will
94 * become elected RP.
95 */
96 if (node1->rp_prio < node2->rp_prio)
97 return -1;
98 if (node1->rp_prio > node2->rp_prio)
99 return 1;
100 if (node1->hash < node2->hash)
101 return 1;
102 if (node1->hash > node2->hash)
103 return -1;
104 if (node1->rp_address.s_addr < node2->rp_address.s_addr)
105 return 1;
106 if (node1->rp_address.s_addr > node2->rp_address.s_addr)
107 return -1;
108 return 0;
109}
110
111static void pim_free_bsrp_node(struct bsm_rpinfo *bsrp_info)
112{
113 if (bsrp_info->g2rp_timer)
114 THREAD_OFF(bsrp_info->g2rp_timer);
115 XFREE(MTYPE_PIM_BSRP_NODE, bsrp_info);
116}
117
118static struct list *pim_alloc_bsrp_list(void)
119{
120 struct list *new_list = NULL;
121
122 new_list = list_new();
123
124 if (!new_list)
125 return NULL;
126
127 new_list->cmp = (int (*)(void *, void *))pim_g2rp_list_compare;
128 new_list->del = (void (*)(void *))pim_free_bsrp_node;
129
130 return new_list;
131}
132
133static struct bsgrp_node *pim_bsm_new_bsgrp_node(struct route_table *rt,
134 struct prefix *grp)
135{
136 struct route_node *rn;
137 struct bsgrp_node *bsgrp;
138
139 rn = route_node_get(rt, grp);
140 if (!rn) {
141 zlog_warn("%s: route node creation failed",
142 __PRETTY_FUNCTION__);
143 return NULL;
144 }
145 bsgrp = XCALLOC(MTYPE_PIM_BSGRP_NODE, sizeof(struct bsgrp_node));
146
147 if (!bsgrp) {
148 if (PIM_DEBUG_BSM)
149 zlog_debug("%s: bsgrp alloc failed",
150 __PRETTY_FUNCTION__);
151 route_unlock_node(rn);
152 return NULL;
153 }
154
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
5acde1cf 407static bool pim_bsr_rpf_check(struct pim_instance *pim, struct in_addr bsr,
408 struct in_addr ip_src_addr)
409{
410 struct pim_nexthop nexthop;
411 int result;
412
413 memset(&nexthop, 0, sizeof(nexthop));
414
415 /* New BSR recived */
416 if (bsr.s_addr != pim->global_scope.current_bsr.s_addr) {
417 result = pim_nexthop_match(pim, bsr, ip_src_addr);
418
419 /* Nexthop lookup pass for the new BSR address */
420 if (result)
421 return true;
422
423 if (PIM_DEBUG_BSM) {
424 char bsr_str[INET_ADDRSTRLEN];
425
426 pim_inet4_dump("<bsr?>", bsr, bsr_str, sizeof(bsr_str));
427 zlog_debug("%s : No route to BSR address %s",
428 __PRETTY_FUNCTION__, bsr_str);
429 }
430 return false;
431 }
432
433 return pim_nexthop_match_nht_cache(pim, bsr, ip_src_addr);
434}
435
436static bool is_preferred_bsr(struct pim_instance *pim, struct in_addr bsr,
437 uint32_t bsr_prio)
438{
439 if (bsr.s_addr == pim->global_scope.current_bsr.s_addr)
440 return true;
441
442 if (bsr_prio > pim->global_scope.current_bsr_prio)
443 return true;
444
445 else if (bsr_prio == pim->global_scope.current_bsr_prio) {
446 if (bsr.s_addr >= pim->global_scope.current_bsr.s_addr)
447 return true;
448 else
449 return false;
450 } else
451 return false;
452}
453
454static void pim_bsm_update(struct pim_instance *pim, struct in_addr bsr,
455 uint32_t bsr_prio)
456{
457 struct pim_nexthop_cache pnc;
458
459 if (bsr.s_addr != pim->global_scope.current_bsr.s_addr) {
460 struct prefix nht_p;
461 char buf[PREFIX2STR_BUFFER];
462 bool is_bsr_tracking = true;
463
464 /* De-register old BSR and register new BSR with Zebra NHT */
465 nht_p.family = AF_INET;
466 nht_p.prefixlen = IPV4_MAX_BITLEN;
467
468 if (pim->global_scope.current_bsr.s_addr != INADDR_ANY) {
469 nht_p.u.prefix4 = pim->global_scope.current_bsr;
470 if (PIM_DEBUG_BSM) {
471 prefix2str(&nht_p, buf, sizeof(buf));
472 zlog_debug(
473 "%s: Deregister BSR addr %s with Zebra NHT",
474 __PRETTY_FUNCTION__, buf);
475 }
476 pim_delete_tracked_nexthop(pim, &nht_p, NULL, NULL,
477 is_bsr_tracking);
478 }
479
480 nht_p.u.prefix4 = bsr;
481 if (PIM_DEBUG_BSM) {
482 prefix2str(&nht_p, buf, sizeof(buf));
483 zlog_debug(
484 "%s: NHT Register BSR addr %s with Zebra NHT",
485 __PRETTY_FUNCTION__, buf);
486 }
487
488 memset(&pnc, 0, sizeof(struct pim_nexthop_cache));
489 pim_find_or_track_nexthop(pim, &nht_p, NULL, NULL,
490 is_bsr_tracking, &pnc);
491 pim->global_scope.current_bsr = bsr;
492 pim->global_scope.current_bsr_first_ts =
493 pim_time_monotonic_sec();
494 pim->global_scope.state = ACCEPT_PREFERRED;
495 }
496 pim->global_scope.current_bsr_prio = bsr_prio;
497 pim->global_scope.current_bsr_last_ts = pim_time_monotonic_sec();
498}
499
d0e418b4 500struct bsgrp_node *pim_bsm_get_bsgrp_node(struct bsm_scope *scope,
501 struct prefix *grp)
502{
503 struct route_node *rn;
504 struct bsgrp_node *bsgrp;
505
506 rn = route_node_lookup(scope->bsrp_table, grp);
507 if (!rn) {
508 if (PIM_DEBUG_BSM)
509 zlog_debug("%s: Route node doesn't exist for the group",
510 __PRETTY_FUNCTION__);
511 return NULL;
512 }
513 bsgrp = rn->info;
514 route_unlock_node(rn);
515
516 return bsgrp;
517}
5acde1cf 518
7b3e6ba1 519static uint32_t hash_calc_on_grp_rp(struct prefix group, struct in_addr rp,
520 uint8_t hashmasklen)
521{
522 uint64_t temp;
523 uint32_t hash;
524 uint32_t grpaddr;
525 uint32_t rp_add;
526 uint32_t mask = 0xffffffff;
527
528 /* mask to be made zero if hashmasklen is 0 because mask << 32
529 * may not give 0. hashmasklen can be 0 to 32.
530 */
531 if (hashmasklen == 0)
532 mask = 0;
533
534 /* in_addr stores ip in big endian, hence network byte order
535 * convert to uint32 before processing hash
536 */
537 grpaddr = ntohl(group.u.prefix4.s_addr);
538 /* Avoid shifting by 32 bit on a 32 bit register */
539 if (hashmasklen)
540 grpaddr = grpaddr & ((mask << (32 - hashmasklen)));
541 else
542 grpaddr = grpaddr & mask;
543 rp_add = ntohl(rp.s_addr);
544 temp = 1103515245 * ((1103515245 * grpaddr + 12345) ^ rp_add) + 12345;
545 hash = temp & (0x7fffffff);
546 return hash;
547}
548
549static bool pim_install_bsm_grp_rp(struct pim_instance *pim,
550 struct bsgrp_node *grpnode,
551 struct bsmmsg_rpinfo *rp)
552{
553 struct bsm_rpinfo *bsm_rpinfo;
554 uint8_t hashMask_len = pim->global_scope.hashMasklen;
555
556 /*memory allocation for bsm_rpinfo */
557 bsm_rpinfo = XCALLOC(MTYPE_PIM_BSRP_NODE, sizeof(*bsm_rpinfo));
558
559 if (!bsm_rpinfo) {
560 if (PIM_DEBUG_BSM)
561 zlog_debug("%s, Memory allocation failed.\r\n",
562 __PRETTY_FUNCTION__);
563 return false;
564 }
565
566 bsm_rpinfo->rp_prio = rp->rp_pri;
567 bsm_rpinfo->rp_holdtime = rp->rp_holdtime;
568 memcpy(&bsm_rpinfo->rp_address, &rp->rpaddr.addr,
569 sizeof(struct in_addr));
570 bsm_rpinfo->elapse_time = 0;
571
572 /* Back pointer to the group node. */
573 bsm_rpinfo->bsgrp_node = grpnode;
574
575 /* update hash for this rp node */
576 bsm_rpinfo->hash = hash_calc_on_grp_rp(grpnode->group, rp->rpaddr.addr,
577 hashMask_len);
578 if (listnode_add_sort_nodup(grpnode->partial_bsrp_list, bsm_rpinfo)) {
579 if (PIM_DEBUG_BSM)
580 zlog_debug(
581 "%s, bs_rpinfo node added to the partial bs_rplist.\r\n",
582 __PRETTY_FUNCTION__);
583 return true;
584 }
585
586 if (PIM_DEBUG_BSM)
587 zlog_debug("%s: list node not added\n", __PRETTY_FUNCTION__);
588
589 XFREE(MTYPE_PIM_BSRP_NODE, bsm_rpinfo);
590 return false;
591}
592
593static void pim_update_pending_rp_cnt(struct bsm_scope *sz,
594 struct bsgrp_node *bsgrp,
595 uint16_t bsm_frag_tag,
596 uint32_t total_rp_count)
597{
598 if (bsgrp->pend_rp_cnt) {
599 /* received bsm is different packet ,
600 * it is not same fragment.
601 */
602 if (bsm_frag_tag != bsgrp->frag_tag) {
603 if (PIM_DEBUG_BSM)
604 zlog_debug(
605 "%s,Received a new BSM ,so clear the pending bs_rpinfo list.\r\n",
606 __PRETTY_FUNCTION__);
607 list_delete_all_node(bsgrp->partial_bsrp_list);
608 bsgrp->pend_rp_cnt = total_rp_count;
609 }
610 } else
611 bsgrp->pend_rp_cnt = total_rp_count;
612
613 bsgrp->frag_tag = bsm_frag_tag;
614}
615
616/* Parsing BSR packet and adding to partial list of corresponding bsgrp node */
617static bool pim_bsm_parse_install_g2rp(struct bsm_scope *scope, uint8_t *buf,
618 int buflen, uint16_t bsm_frag_tag)
619{
620 struct bsmmsg_grpinfo grpinfo;
621 struct bsmmsg_rpinfo rpinfo;
622 struct prefix group;
623 struct bsgrp_node *bsgrp = NULL;
624 int frag_rp_cnt = 0;
625 int offset = 0;
626 int ins_count = 0;
627
628 while (buflen > offset) {
629 /* Extract Group tlv from BSM */
630 memcpy(&grpinfo, buf, sizeof(struct bsmmsg_grpinfo));
631
632 if (PIM_DEBUG_BSM) {
633 char grp_str[INET_ADDRSTRLEN];
634
635 pim_inet4_dump("<Group?>", grpinfo.group.addr, grp_str,
636 sizeof(grp_str));
637 zlog_debug(
638 "%s, Group %s Rpcount:%d Fragment-Rp-count:%d\r\n",
639 __PRETTY_FUNCTION__, grp_str, grpinfo.rp_count,
640 grpinfo.frag_rp_count);
641 }
642
643 buf += sizeof(struct bsmmsg_grpinfo);
644 offset += sizeof(struct bsmmsg_grpinfo);
645
646 if (grpinfo.rp_count == 0) {
647 if (PIM_DEBUG_BSM) {
648 char grp_str[INET_ADDRSTRLEN];
649
650 pim_inet4_dump("<Group?>", grpinfo.group.addr,
651 grp_str, sizeof(grp_str));
652 zlog_debug(
653 "%s, Rp count is zero for group: %s\r\n",
654 __PRETTY_FUNCTION__, grp_str);
655 }
656 return false;
657 }
658
659 group.family = AF_INET;
660 group.prefixlen = grpinfo.group.mask;
661 group.u.prefix4.s_addr = grpinfo.group.addr.s_addr;
662
663 /* Get the Group node for the BSM rp table */
664 bsgrp = pim_bsm_get_bsgrp_node(scope, &group);
665
666 if (!bsgrp) {
667 if (PIM_DEBUG_BSM)
668 zlog_debug(
669 "%s, Create new BSM Group node.\r\n",
670 __PRETTY_FUNCTION__);
671
672 /* create a new node to be added to the tree. */
673 bsgrp = pim_bsm_new_bsgrp_node(scope->bsrp_table,
674 &group);
675
676 if (!bsgrp) {
677 zlog_debug(
678 "%s, Failed to get the BSM group node.\r\n",
679 __PRETTY_FUNCTION__);
680 continue;
681 }
682
683 bsgrp->scope = scope;
684 }
685
686 pim_update_pending_rp_cnt(scope, bsgrp, bsm_frag_tag,
687 grpinfo.rp_count);
688 frag_rp_cnt = grpinfo.frag_rp_count;
689 ins_count = 0;
690
691 while (frag_rp_cnt--) {
692 /* Extract RP address tlv from BSM */
693 memcpy(&rpinfo, buf, sizeof(struct bsmmsg_rpinfo));
694 rpinfo.rp_holdtime = ntohs(rpinfo.rp_holdtime);
695 buf += sizeof(struct bsmmsg_rpinfo);
696 offset += sizeof(struct bsmmsg_rpinfo);
697
698 if (PIM_DEBUG_BSM) {
699 char rp_str[INET_ADDRSTRLEN];
700
701 pim_inet4_dump("<Rpaddr?>", rpinfo.rpaddr.addr,
702 rp_str, sizeof(rp_str));
703 zlog_debug(
704 "%s, Rp address - %s; pri:%d hold:%d\r\n",
705 __PRETTY_FUNCTION__, rp_str,
706 rpinfo.rp_pri, rpinfo.rp_holdtime);
707 }
708
709 /* Call Install api to update grp-rp mappings */
710 if (pim_install_bsm_grp_rp(scope->pim, bsgrp, &rpinfo))
711 ins_count++;
712 }
713
714 bsgrp->pend_rp_cnt -= ins_count;
715
716 if (!bsgrp->pend_rp_cnt) {
717 if (PIM_DEBUG_BSM)
718 zlog_debug(
719 "%s, Recvd all the rps for this group, so bsrp list with penidng rp list.",
720 __PRETTY_FUNCTION__);
721 /* replace the bsrp_list with pending list - TODO */
722 }
723 }
724 return true;
725}
726
5acde1cf 727int pim_bsm_process(struct interface *ifp, struct ip *ip_hdr, uint8_t *buf,
728 uint32_t buf_size, bool no_fwd)
729{
730 struct bsm_hdr *bshdr;
731 struct bsmmsg_grpinfo *msg_grp;
732 struct pim_interface *pim_ifp = NULL;
733 struct pim_instance *pim;
734 char bsr_str[INET_ADDRSTRLEN];
735 uint16_t frag_tag;
736 bool empty_bsm = FALSE;
737
738 /* BSM Packet acceptance validation */
739 pim_ifp = ifp->info;
740 if (!pim_ifp) {
741 if (PIM_DEBUG_BSM)
742 zlog_debug("%s: multicast not enabled on interface %s",
743 __PRETTY_FUNCTION__, ifp->name);
744 return -1;
745 }
746
747 pim_ifp->pim_ifstat_bsm_rx++;
748 pim = pim_ifp->pim;
749 pim->bsm_rcvd++;
750
751 /* Drop if bsm processing is disabled on interface */
752 if (!pim_ifp->bsm_enable) {
753 zlog_warn("%s: BSM not enabled on interface %s",
754 __PRETTY_FUNCTION__, ifp->name);
755 pim_ifp->pim_ifstat_bsm_cfg_miss++;
756 pim->bsm_dropped++;
757 return -1;
758 }
759
760 bshdr = (struct bsm_hdr *)(buf + PIM_MSG_HEADER_LEN);
761 pim_inet4_dump("<bsr?>", bshdr->bsr_addr.addr, bsr_str,
762 sizeof(bsr_str));
763 pim->global_scope.hashMasklen = bshdr->hm_len;
764 frag_tag = ntohs(bshdr->frag_tag);
765
766 /* Identify empty BSM */
767 if ((buf_size - PIM_BSM_HDR_LEN - PIM_MSG_HEADER_LEN) < PIM_BSM_GRP_LEN)
768 empty_bsm = true;
769
770 if (!empty_bsm) {
771 msg_grp = (struct bsmmsg_grpinfo *)(buf + PIM_MSG_HEADER_LEN
772 + PIM_BSM_HDR_LEN);
773 /* Currently we don't support scope zoned BSM */
774 if (msg_grp->group.sz) {
775 if (PIM_DEBUG_BSM)
776 zlog_debug(
777 "%s : Administratively scoped range BSM received",
778 __PRETTY_FUNCTION__);
779 pim_ifp->pim_ifstat_bsm_invalid_sz++;
780 pim->bsm_dropped++;
781 return -1;
782 }
783 }
784
785 /* Drop if bsr is not preferred bsr */
786 if (!is_preferred_bsr(pim, bshdr->bsr_addr.addr, bshdr->bsr_prio)) {
787 if (PIM_DEBUG_BSM)
788 zlog_debug("%s : Received a non-preferred BSM",
789 __PRETTY_FUNCTION__);
790 pim->bsm_dropped++;
791 return -1;
792 }
793
794 if (no_fwd) {
795 /* only accept no-forward BSM if quick refresh on startup */
796 if ((pim->global_scope.accept_nofwd_bsm)
797 || (frag_tag == pim->global_scope.bsm_frag_tag)) {
798 pim->global_scope.accept_nofwd_bsm = false;
799 } else {
800 if (PIM_DEBUG_BSM)
801 zlog_debug(
802 "%s : nofwd_bsm received on %s when accpt_nofwd_bsm false",
803 __PRETTY_FUNCTION__, bsr_str);
804 pim->bsm_dropped++;
805 pim_ifp->pim_ifstat_ucast_bsm_cfg_miss++;
806 return -1;
807 }
808 }
809
810 /* Mulicast BSM received */
811 if (ip_hdr->ip_dst.s_addr == qpim_all_pim_routers_addr.s_addr) {
812 if (!no_fwd) {
813 if (!pim_bsr_rpf_check(pim, bshdr->bsr_addr.addr,
814 ip_hdr->ip_src)) {
815 if (PIM_DEBUG_BSM)
816 zlog_debug(
817 "%s : RPF check fail for BSR address %s",
818 __PRETTY_FUNCTION__, bsr_str);
819 pim->bsm_dropped++;
820 return -1;
821 }
822 }
823 } else if (if_lookup_exact_address(&ip_hdr->ip_dst, AF_INET,
824 pim->vrf_id)) {
825 /* Unicast BSM received - if ucast bsm not enabled on
826 * the interface, drop it
827 */
828 if (!pim_ifp->ucast_bsm_accept) {
829 if (PIM_DEBUG_BSM)
830 zlog_debug(
831 "%s : Unicast BSM not enabled on interface %s",
832 __PRETTY_FUNCTION__, ifp->name);
833 pim_ifp->pim_ifstat_ucast_bsm_cfg_miss++;
834 pim->bsm_dropped++;
835 return -1;
836 }
837
838 } else {
839 if (PIM_DEBUG_BSM)
840 zlog_debug("%s : Invalid destination address",
841 __PRETTY_FUNCTION__);
842 pim->bsm_dropped++;
843 return -1;
844 }
845
846 if (empty_bsm) {
847 if (PIM_DEBUG_BSM)
848 zlog_debug("%s : Empty Pref BSM received",
849 __PRETTY_FUNCTION__);
850 }
7b3e6ba1 851 /* Parse Update bsm rp table and install/uninstall rp if required */
852 if (!pim_bsm_parse_install_g2rp(
853 &pim_ifp->pim->global_scope,
854 (buf + PIM_BSM_HDR_LEN + PIM_MSG_HEADER_LEN),
855 (buf_size - PIM_BSM_HDR_LEN - PIM_MSG_HEADER_LEN),
856 frag_tag)) {
857 if (PIM_DEBUG_BSM) {
858 zlog_debug("%s, Parsing BSM failed.\r\n",
859 __PRETTY_FUNCTION__);
860 }
861 pim->bsm_dropped++;
862 return -1;
863 }
5acde1cf 864 /* Restart the bootstrap timer */
865 pim_bs_timer_restart(&pim_ifp->pim->global_scope,
866 PIM_BSR_DEFAULT_TIMEOUT);
867
868 /* If new BSM received, clear the old bsm database */
869 if (pim_ifp->pim->global_scope.bsm_frag_tag != frag_tag) {
870 if (PIM_DEBUG_BSM) {
871 zlog_debug("%s: Current frag tag: %d Frag teg rcvd: %d",
872 __PRETTY_FUNCTION__,
873 pim_ifp->pim->global_scope.bsm_frag_tag,
874 frag_tag);
875 }
876 list_delete_all_node(pim_ifp->pim->global_scope.bsm_list);
877 pim_ifp->pim->global_scope.bsm_frag_tag = frag_tag;
878 }
879
880 /* update the scope information from bsm */
881 pim_bsm_update(pim, bshdr->bsr_addr.addr, bshdr->bsr_prio);
882 return 0;
883}