]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_bsm.c
pimd: PIM Bootstrap packet processing
[mirror_frr.git] / pimd / pim_bsm.c
1 /*
2 * pim_bsm.c: PIM BSM handling routines
3 *
4 * Copyright (C) 2018-19 Vmware, Inc.
5 * Saravanan K
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; see the file COPYING; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
20 * MA 02110-1301 USA
21 */
22 #include "if.h"
23 #include "pimd.h"
24 #include "pim_iface.h"
25 #include "pim_instance.h"
26 #include "pim_rpf.h"
27 #include "pim_hello.h"
28 #include "pim_pim.h"
29 #include "pim_nht.h"
30 #include "pim_bsm.h"
31 #include "pim_time.h"
32
33 /* Functions forward declaration */
34 static void pim_bs_timer_start(struct bsm_scope *scope, int bs_timeout);
35 static void pim_g2rp_timer_start(struct bsm_rpinfo *bsrp, int hold_time);
36 static inline void pim_g2rp_timer_restart(struct bsm_rpinfo *bsrp,
37 int hold_time);
38
39 /* Memory Types */
40 DEFINE_MTYPE_STATIC(PIMD, PIM_BSGRP_NODE, "PIM BSR advertised grp info")
41 DEFINE_MTYPE_STATIC(PIMD, PIM_BSRP_NODE, "PIM BSR advertised RP info")
42 DEFINE_MTYPE_STATIC(PIMD, PIM_BSM_INFO, "PIM BSM Info")
43 DEFINE_MTYPE_STATIC(PIMD, PIM_BSM_PKT_VAR_MEM, "PIM BSM Packet")
44
45 /* pim_bsm_write_config - Write the interface pim bsm configuration.*/
46 void pim_bsm_write_config(struct vty *vty, struct interface *ifp)
47 {
48 struct pim_interface *pim_ifp = ifp->info;
49
50 if (pim_ifp) {
51 if (!pim_ifp->bsm_enable)
52 vty_out(vty, " no ip pim bsm\n");
53 if (!pim_ifp->ucast_bsm_accept)
54 vty_out(vty, " no ip pim unicast-bsm\n");
55 }
56 }
57
58 static void pim_free_bsgrp_data(struct bsgrp_node *bsgrp_node)
59 {
60 if (bsgrp_node->bsrp_list)
61 list_delete(&bsgrp_node->bsrp_list);
62 if (bsgrp_node->partial_bsrp_list)
63 list_delete(&bsgrp_node->partial_bsrp_list);
64 XFREE(MTYPE_PIM_BSGRP_NODE, bsgrp_node);
65 }
66
67 static void pim_free_bsgrp_node(struct route_table *rt, struct prefix *grp)
68 {
69 struct route_node *rn;
70
71 rn = route_node_lookup(rt, grp);
72 if (rn) {
73 rn->info = NULL;
74 route_unlock_node(rn);
75 route_unlock_node(rn);
76 }
77 }
78
79 static void pim_bsm_node_free(struct bsm_info *bsm)
80 {
81 if (bsm->bsm)
82 XFREE(MTYPE_PIM_BSM_PKT_VAR_MEM, bsm->bsm);
83 XFREE(MTYPE_PIM_BSM_INFO, bsm);
84 }
85
86 static int pim_on_bs_timer(struct thread *t)
87 {
88 struct route_node *rn;
89 struct bsm_scope *scope;
90 struct bsgrp_node *bsgrp_node;
91 struct bsm_rpinfo *bsrp;
92 struct prefix nht_p;
93 char buf[PREFIX2STR_BUFFER];
94 bool is_bsr_tracking = true;
95
96 scope = THREAD_ARG(t);
97 THREAD_OFF(scope->bs_timer);
98
99 if (PIM_DEBUG_BSM)
100 zlog_debug("%s: Bootstrap Timer expired for scope: %d",
101 __PRETTY_FUNCTION__, scope->sz_id);
102
103 /* Remove next hop tracking for the bsr */
104 nht_p.family = AF_INET;
105 nht_p.prefixlen = IPV4_MAX_BITLEN;
106 nht_p.u.prefix4 = scope->current_bsr;
107 if (PIM_DEBUG_BSM) {
108 prefix2str(&nht_p, buf, sizeof(buf));
109 zlog_debug("%s: Deregister BSR addr %s with Zebra NHT",
110 __PRETTY_FUNCTION__, buf);
111 }
112 pim_delete_tracked_nexthop(scope->pim, &nht_p, NULL, NULL,
113 is_bsr_tracking);
114
115 /* Reset scope zone data */
116 scope->accept_nofwd_bsm = false;
117 scope->state = ACCEPT_ANY;
118 scope->current_bsr.s_addr = INADDR_ANY;
119 scope->current_bsr_prio = 0;
120 scope->current_bsr_first_ts = 0;
121 scope->current_bsr_last_ts = 0;
122 scope->bsm_frag_tag = 0;
123 list_delete_all_node(scope->bsm_list);
124
125 for (rn = route_top(scope->bsrp_table); rn; rn = route_next(rn)) {
126
127 bsgrp_node = (struct bsgrp_node *)rn->info;
128 if (!bsgrp_node) {
129 if (PIM_DEBUG_BSM)
130 zlog_debug("%s: bsgrp_node is null",
131 __PRETTY_FUNCTION__);
132 continue;
133 }
134 /* Give grace time for rp to continue for another hold time */
135 if ((bsgrp_node->bsrp_list) && (bsgrp_node->bsrp_list->count)) {
136 bsrp = listnode_head(bsgrp_node->bsrp_list);
137 pim_g2rp_timer_restart(bsrp, bsrp->rp_holdtime);
138 }
139 /* clear pending list */
140 if ((bsgrp_node->partial_bsrp_list)
141 && (bsgrp_node->partial_bsrp_list->count)) {
142 list_delete_all_node(bsgrp_node->partial_bsrp_list);
143 bsgrp_node->pend_rp_cnt = 0;
144 }
145 }
146 return 0;
147 }
148
149 static void pim_bs_timer_stop(struct bsm_scope *scope)
150 {
151 if (PIM_DEBUG_BSM)
152 zlog_debug("%s : BS timer being stopped of sz: %d",
153 __PRETTY_FUNCTION__, scope->sz_id);
154 THREAD_OFF(scope->bs_timer);
155 }
156
157 static void pim_bs_timer_start(struct bsm_scope *scope, int bs_timeout)
158 {
159 if (!scope) {
160 if (PIM_DEBUG_BSM)
161 zlog_debug("%s : Invalid scope(NULL).",
162 __PRETTY_FUNCTION__);
163 return;
164 }
165 THREAD_OFF(scope->bs_timer);
166 if (PIM_DEBUG_BSM)
167 zlog_debug("%s : starting bs timer for scope %d with timeout %d secs",
168 __PRETTY_FUNCTION__, scope->sz_id, bs_timeout);
169 thread_add_timer(router->master, pim_on_bs_timer, scope, bs_timeout,
170 &scope->bs_timer);
171 }
172
173 static inline void pim_bs_timer_restart(struct bsm_scope *scope, int bs_timeout)
174 {
175 pim_bs_timer_start(scope, bs_timeout);
176 }
177
178 void pim_bsm_proc_init(struct pim_instance *pim)
179 {
180 memset(&pim->global_scope, 0, sizeof(struct bsm_scope));
181
182 pim->global_scope.sz_id = PIM_GBL_SZ_ID;
183 pim->global_scope.bsrp_table = route_table_init();
184 pim->global_scope.accept_nofwd_bsm = true;
185 pim->global_scope.state = NO_INFO;
186 pim->global_scope.pim = pim;
187 pim->global_scope.bsm_list = list_new();
188 pim->global_scope.bsm_list->del = (void (*)(void *))pim_bsm_node_free;
189 pim_bs_timer_start(&pim->global_scope, PIM_BS_TIME);
190 }
191
192 void pim_bsm_proc_free(struct pim_instance *pim)
193 {
194 struct route_node *rn;
195 struct bsgrp_node *bsgrp;
196
197 pim_bs_timer_stop(&pim->global_scope);
198
199 if (pim->global_scope.bsm_list)
200 list_delete(&pim->global_scope.bsm_list);
201
202 for (rn = route_top(pim->global_scope.bsrp_table); rn;
203 rn = route_next(rn)) {
204 bsgrp = rn->info;
205 if (!bsgrp)
206 continue;
207 pim_free_bsgrp_data(bsgrp);
208 }
209
210 if (pim->global_scope.bsrp_table)
211 route_table_finish(pim->global_scope.bsrp_table);
212 }
213
214 static bool is_hold_time_elapsed(void *data)
215 {
216 struct bsm_rpinfo *bsrp;
217
218 bsrp = data;
219
220 if (bsrp->elapse_time < bsrp->rp_holdtime)
221 return false;
222 else
223 return true;
224 }
225
226 static int pim_on_g2rp_timer(struct thread *t)
227 {
228 struct bsm_rpinfo *bsrp;
229 struct bsm_rpinfo *bsrp_node;
230 struct bsgrp_node *bsgrp_node;
231 struct listnode *bsrp_ln;
232 struct pim_instance *pim;
233 struct rp_info *rp_info;
234 struct route_node *rn;
235 uint16_t elapse;
236 struct in_addr bsrp_addr;
237
238 bsrp = THREAD_ARG(t);
239 THREAD_OFF(bsrp->g2rp_timer);
240 bsgrp_node = bsrp->bsgrp_node;
241
242 /* elapse time is the hold time of expired node */
243 elapse = bsrp->rp_holdtime;
244 bsrp_addr = bsrp->rp_address;
245
246 /* update elapse for all bsrp nodes */
247 for (ALL_LIST_ELEMENTS_RO(bsgrp_node->bsrp_list, bsrp_ln, bsrp_node))
248 bsrp_node->elapse_time += elapse;
249
250 /* remove the expired nodes from the list */
251 list_filter_out_nodes(bsgrp_node->bsrp_list, is_hold_time_elapsed);
252
253 /* Get the next elected rp node */
254 bsrp = listnode_head(bsgrp_node->bsrp_list);
255 pim = bsgrp_node->scope->pim;
256 rn = route_node_lookup(pim->rp_table, &bsgrp_node->group);
257
258 if (!rn) {
259 zlog_warn("%s: Route node doesn't exist", __PRETTY_FUNCTION__);
260 return 0;
261 }
262
263 rp_info = (struct rp_info *)rn->info;
264
265 if (!rp_info) {
266 route_unlock_node(rn);
267 return 0;
268 }
269
270 if (rp_info->rp_src != RP_SRC_STATIC) {
271 /* If new rp available, change it else delete the existing */
272 if (bsrp) {
273 bsrp_addr = bsrp->rp_address;
274 pim_g2rp_timer_start(
275 bsrp, (bsrp->rp_holdtime - bsrp->elapse_time));
276 pim_rp_change(pim, bsrp_addr, bsgrp_node->group,
277 RP_SRC_BSR);
278 } else {
279 pim_rp_del(pim, bsrp_addr, bsgrp_node->group, NULL,
280 RP_SRC_BSR);
281 }
282 }
283
284 if ((!bsgrp_node->bsrp_list->count)
285 && (!bsgrp_node->partial_bsrp_list->count)) {
286 pim_free_bsgrp_node(pim->global_scope.bsrp_table,
287 &bsgrp_node->group);
288 pim_free_bsgrp_data(bsgrp_node);
289 }
290
291 return 0;
292 }
293
294 static void pim_g2rp_timer_start(struct bsm_rpinfo *bsrp, int hold_time)
295 {
296 if (!bsrp) {
297 if (PIM_DEBUG_BSM)
298 zlog_debug("%s : Invalid brsp(NULL).",
299 __PRETTY_FUNCTION__);
300 return;
301 }
302 THREAD_OFF(bsrp->g2rp_timer);
303 if (PIM_DEBUG_BSM) {
304 char buf[48];
305
306 zlog_debug(
307 "%s : starting g2rp timer for grp: %s - rp: %s with timeout %d secs(Actual Hold time : %d secs)",
308 __PRETTY_FUNCTION__,
309 prefix2str(&bsrp->bsgrp_node->group, buf, 48),
310 inet_ntoa(bsrp->rp_address), hold_time,
311 bsrp->rp_holdtime);
312 }
313
314 thread_add_timer(router->master, pim_on_g2rp_timer, bsrp, hold_time,
315 &bsrp->g2rp_timer);
316 }
317
318 static inline void pim_g2rp_timer_restart(struct bsm_rpinfo *bsrp,
319 int hold_time)
320 {
321 pim_g2rp_timer_start(bsrp, hold_time);
322 }
323
324 static bool pim_bsr_rpf_check(struct pim_instance *pim, struct in_addr bsr,
325 struct in_addr ip_src_addr)
326 {
327 struct pim_nexthop nexthop;
328 int result;
329
330 memset(&nexthop, 0, sizeof(nexthop));
331
332 /* New BSR recived */
333 if (bsr.s_addr != pim->global_scope.current_bsr.s_addr) {
334 result = pim_nexthop_match(pim, bsr, ip_src_addr);
335
336 /* Nexthop lookup pass for the new BSR address */
337 if (result)
338 return true;
339
340 if (PIM_DEBUG_BSM) {
341 char bsr_str[INET_ADDRSTRLEN];
342
343 pim_inet4_dump("<bsr?>", bsr, bsr_str, sizeof(bsr_str));
344 zlog_debug("%s : No route to BSR address %s",
345 __PRETTY_FUNCTION__, bsr_str);
346 }
347 return false;
348 }
349
350 return pim_nexthop_match_nht_cache(pim, bsr, ip_src_addr);
351 }
352
353 static bool is_preferred_bsr(struct pim_instance *pim, struct in_addr bsr,
354 uint32_t bsr_prio)
355 {
356 if (bsr.s_addr == pim->global_scope.current_bsr.s_addr)
357 return true;
358
359 if (bsr_prio > pim->global_scope.current_bsr_prio)
360 return true;
361
362 else if (bsr_prio == pim->global_scope.current_bsr_prio) {
363 if (bsr.s_addr >= pim->global_scope.current_bsr.s_addr)
364 return true;
365 else
366 return false;
367 } else
368 return false;
369 }
370
371 static void pim_bsm_update(struct pim_instance *pim, struct in_addr bsr,
372 uint32_t bsr_prio)
373 {
374 struct pim_nexthop_cache pnc;
375
376 if (bsr.s_addr != pim->global_scope.current_bsr.s_addr) {
377 struct prefix nht_p;
378 char buf[PREFIX2STR_BUFFER];
379 bool is_bsr_tracking = true;
380
381 /* De-register old BSR and register new BSR with Zebra NHT */
382 nht_p.family = AF_INET;
383 nht_p.prefixlen = IPV4_MAX_BITLEN;
384
385 if (pim->global_scope.current_bsr.s_addr != INADDR_ANY) {
386 nht_p.u.prefix4 = pim->global_scope.current_bsr;
387 if (PIM_DEBUG_BSM) {
388 prefix2str(&nht_p, buf, sizeof(buf));
389 zlog_debug(
390 "%s: Deregister BSR addr %s with Zebra NHT",
391 __PRETTY_FUNCTION__, buf);
392 }
393 pim_delete_tracked_nexthop(pim, &nht_p, NULL, NULL,
394 is_bsr_tracking);
395 }
396
397 nht_p.u.prefix4 = bsr;
398 if (PIM_DEBUG_BSM) {
399 prefix2str(&nht_p, buf, sizeof(buf));
400 zlog_debug(
401 "%s: NHT Register BSR addr %s with Zebra NHT",
402 __PRETTY_FUNCTION__, buf);
403 }
404
405 memset(&pnc, 0, sizeof(struct pim_nexthop_cache));
406 pim_find_or_track_nexthop(pim, &nht_p, NULL, NULL,
407 is_bsr_tracking, &pnc);
408 pim->global_scope.current_bsr = bsr;
409 pim->global_scope.current_bsr_first_ts =
410 pim_time_monotonic_sec();
411 pim->global_scope.state = ACCEPT_PREFERRED;
412 }
413 pim->global_scope.current_bsr_prio = bsr_prio;
414 pim->global_scope.current_bsr_last_ts = pim_time_monotonic_sec();
415 }
416
417 struct bsgrp_node *pim_bsm_get_bsgrp_node(struct bsm_scope *scope,
418 struct prefix *grp)
419 {
420 struct route_node *rn;
421 struct bsgrp_node *bsgrp;
422
423 rn = route_node_lookup(scope->bsrp_table, grp);
424 if (!rn) {
425 if (PIM_DEBUG_BSM)
426 zlog_debug("%s: Route node doesn't exist for the group",
427 __PRETTY_FUNCTION__);
428 return NULL;
429 }
430 bsgrp = rn->info;
431 route_unlock_node(rn);
432
433 return bsgrp;
434 }
435
436 int pim_bsm_process(struct interface *ifp, struct ip *ip_hdr, uint8_t *buf,
437 uint32_t buf_size, bool no_fwd)
438 {
439 struct bsm_hdr *bshdr;
440 struct bsmmsg_grpinfo *msg_grp;
441 struct pim_interface *pim_ifp = NULL;
442 struct pim_instance *pim;
443 char bsr_str[INET_ADDRSTRLEN];
444 uint16_t frag_tag;
445 bool empty_bsm = FALSE;
446
447 /* BSM Packet acceptance validation */
448 pim_ifp = ifp->info;
449 if (!pim_ifp) {
450 if (PIM_DEBUG_BSM)
451 zlog_debug("%s: multicast not enabled on interface %s",
452 __PRETTY_FUNCTION__, ifp->name);
453 return -1;
454 }
455
456 pim_ifp->pim_ifstat_bsm_rx++;
457 pim = pim_ifp->pim;
458 pim->bsm_rcvd++;
459
460 /* Drop if bsm processing is disabled on interface */
461 if (!pim_ifp->bsm_enable) {
462 zlog_warn("%s: BSM not enabled on interface %s",
463 __PRETTY_FUNCTION__, ifp->name);
464 pim_ifp->pim_ifstat_bsm_cfg_miss++;
465 pim->bsm_dropped++;
466 return -1;
467 }
468
469 bshdr = (struct bsm_hdr *)(buf + PIM_MSG_HEADER_LEN);
470 pim_inet4_dump("<bsr?>", bshdr->bsr_addr.addr, bsr_str,
471 sizeof(bsr_str));
472 pim->global_scope.hashMasklen = bshdr->hm_len;
473 frag_tag = ntohs(bshdr->frag_tag);
474
475 /* Identify empty BSM */
476 if ((buf_size - PIM_BSM_HDR_LEN - PIM_MSG_HEADER_LEN) < PIM_BSM_GRP_LEN)
477 empty_bsm = true;
478
479 if (!empty_bsm) {
480 msg_grp = (struct bsmmsg_grpinfo *)(buf + PIM_MSG_HEADER_LEN
481 + PIM_BSM_HDR_LEN);
482 /* Currently we don't support scope zoned BSM */
483 if (msg_grp->group.sz) {
484 if (PIM_DEBUG_BSM)
485 zlog_debug(
486 "%s : Administratively scoped range BSM received",
487 __PRETTY_FUNCTION__);
488 pim_ifp->pim_ifstat_bsm_invalid_sz++;
489 pim->bsm_dropped++;
490 return -1;
491 }
492 }
493
494 /* Drop if bsr is not preferred bsr */
495 if (!is_preferred_bsr(pim, bshdr->bsr_addr.addr, bshdr->bsr_prio)) {
496 if (PIM_DEBUG_BSM)
497 zlog_debug("%s : Received a non-preferred BSM",
498 __PRETTY_FUNCTION__);
499 pim->bsm_dropped++;
500 return -1;
501 }
502
503 if (no_fwd) {
504 /* only accept no-forward BSM if quick refresh on startup */
505 if ((pim->global_scope.accept_nofwd_bsm)
506 || (frag_tag == pim->global_scope.bsm_frag_tag)) {
507 pim->global_scope.accept_nofwd_bsm = false;
508 } else {
509 if (PIM_DEBUG_BSM)
510 zlog_debug(
511 "%s : nofwd_bsm received on %s when accpt_nofwd_bsm false",
512 __PRETTY_FUNCTION__, bsr_str);
513 pim->bsm_dropped++;
514 pim_ifp->pim_ifstat_ucast_bsm_cfg_miss++;
515 return -1;
516 }
517 }
518
519 /* Mulicast BSM received */
520 if (ip_hdr->ip_dst.s_addr == qpim_all_pim_routers_addr.s_addr) {
521 if (!no_fwd) {
522 if (!pim_bsr_rpf_check(pim, bshdr->bsr_addr.addr,
523 ip_hdr->ip_src)) {
524 if (PIM_DEBUG_BSM)
525 zlog_debug(
526 "%s : RPF check fail for BSR address %s",
527 __PRETTY_FUNCTION__, bsr_str);
528 pim->bsm_dropped++;
529 return -1;
530 }
531 }
532 } else if (if_lookup_exact_address(&ip_hdr->ip_dst, AF_INET,
533 pim->vrf_id)) {
534 /* Unicast BSM received - if ucast bsm not enabled on
535 * the interface, drop it
536 */
537 if (!pim_ifp->ucast_bsm_accept) {
538 if (PIM_DEBUG_BSM)
539 zlog_debug(
540 "%s : Unicast BSM not enabled on interface %s",
541 __PRETTY_FUNCTION__, ifp->name);
542 pim_ifp->pim_ifstat_ucast_bsm_cfg_miss++;
543 pim->bsm_dropped++;
544 return -1;
545 }
546
547 } else {
548 if (PIM_DEBUG_BSM)
549 zlog_debug("%s : Invalid destination address",
550 __PRETTY_FUNCTION__);
551 pim->bsm_dropped++;
552 return -1;
553 }
554
555 if (empty_bsm) {
556 if (PIM_DEBUG_BSM)
557 zlog_debug("%s : Empty Pref BSM received",
558 __PRETTY_FUNCTION__);
559 }
560 /* Restart the bootstrap timer */
561 pim_bs_timer_restart(&pim_ifp->pim->global_scope,
562 PIM_BSR_DEFAULT_TIMEOUT);
563
564 /* If new BSM received, clear the old bsm database */
565 if (pim_ifp->pim->global_scope.bsm_frag_tag != frag_tag) {
566 if (PIM_DEBUG_BSM) {
567 zlog_debug("%s: Current frag tag: %d Frag teg rcvd: %d",
568 __PRETTY_FUNCTION__,
569 pim_ifp->pim->global_scope.bsm_frag_tag,
570 frag_tag);
571 }
572 list_delete_all_node(pim_ifp->pim->global_scope.bsm_list);
573 pim_ifp->pim->global_scope.bsm_frag_tag = frag_tag;
574 }
575
576 /* update the scope information from bsm */
577 pim_bsm_update(pim, bshdr->bsr_addr.addr, bshdr->bsr_prio);
578 return 0;
579 }