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