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