]> git.proxmox.com Git - mirror_frr.git/blob - lib/bfd.c
Merge pull request #9649 from proelbtn/add-support-for-end-dt4
[mirror_frr.git] / lib / bfd.c
1 /**
2 * bfd.c: BFD handling routines
3 *
4 * @copyright Copyright (C) 2015 Cumulus Networks, Inc.
5 *
6 * This file is part of GNU Zebra.
7 *
8 * GNU Zebra is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2, or (at your option) any
11 * later version.
12 *
13 * GNU Zebra is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; see the file COPYING; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 #include <zebra.h>
24
25 #include "command.h"
26 #include "memory.h"
27 #include "prefix.h"
28 #include "thread.h"
29 #include "stream.h"
30 #include "vrf.h"
31 #include "zclient.h"
32 #include "table.h"
33 #include "vty.h"
34 #include "bfd.h"
35
36 DEFINE_MTYPE_STATIC(LIB, BFD_INFO, "BFD info");
37
38 /**
39 * BFD protocol integration configuration.
40 */
41
42 /** Events definitions. */
43 enum bfd_session_event {
44 /** Remove the BFD session configuration. */
45 BSE_UNINSTALL,
46 /** Install the BFD session configuration. */
47 BSE_INSTALL,
48 };
49
50 /**
51 * Data structure to do the necessary tricks to hide the BFD protocol
52 * integration internals.
53 */
54 struct bfd_session_params {
55 /** Contains the session parameters and more. */
56 struct bfd_session_arg args;
57 /** Contains the session state. */
58 struct bfd_session_status bss;
59 /** Protocol implementation status update callback. */
60 bsp_status_update updatecb;
61 /** Protocol implementation custom data pointer. */
62 void *arg;
63
64 /**
65 * Next event.
66 *
67 * This variable controls what action to execute when the command batch
68 * finishes. Normally we'd use `thread_add_event` value, however since
69 * that function is going to be called multiple times and the value
70 * might be different we'll use this variable to keep track of it.
71 */
72 enum bfd_session_event lastev;
73 /**
74 * BFD session configuration event.
75 *
76 * Multiple actions might be asked during a command batch (either via
77 * configuration load or northbound batch), so we'll use this to
78 * install/uninstall the BFD session parameters only once.
79 */
80 struct thread *installev;
81
82 /** BFD session installation state. */
83 bool installed;
84
85 /** Global BFD paramaters list. */
86 TAILQ_ENTRY(bfd_session_params) entry;
87 };
88
89 struct bfd_sessions_global {
90 /**
91 * Global BFD session parameters list for (re)installation and update
92 * without code duplication among daemons.
93 */
94 TAILQ_HEAD(bsplist, bfd_session_params) bsplist;
95
96 /** Pointer to FRR's event manager. */
97 struct thread_master *tm;
98 /** Pointer to zebra client data structure. */
99 struct zclient *zc;
100
101 /** Debugging state. */
102 bool debugging;
103 /** Is shutting down? */
104 bool shutting_down;
105 };
106
107 /** Global configuration variable. */
108 static struct bfd_sessions_global bsglobal;
109
110 /** Global empty address for IPv4/IPv6. */
111 static const struct in6_addr i6a_zero;
112
113 /*
114 * bfd_get_peer_info - Extract the Peer information for which the BFD session
115 * went down from the message sent from Zebra to clients.
116 */
117 static struct interface *bfd_get_peer_info(struct stream *s, struct prefix *dp,
118 struct prefix *sp, int *status,
119 int *remote_cbit, vrf_id_t vrf_id)
120 {
121 unsigned int ifindex;
122 struct interface *ifp = NULL;
123 int plen;
124 int local_remote_cbit;
125
126 /*
127 * If the ifindex lookup fails the
128 * rest of the data in the stream is
129 * not read. All examples of this function
130 * call immediately use the dp->family which
131 * is not good. Ensure we are not using
132 * random data
133 */
134 memset(dp, 0, sizeof(*dp));
135 memset(sp, 0, sizeof(*sp));
136
137 /* Get interface index. */
138 STREAM_GETL(s, ifindex);
139
140 /* Lookup index. */
141 if (ifindex != 0) {
142 ifp = if_lookup_by_index(ifindex, vrf_id);
143 if (ifp == NULL) {
144 if (bsglobal.debugging)
145 zlog_debug(
146 "%s: Can't find interface by ifindex: %d ",
147 __func__, ifindex);
148 return NULL;
149 }
150 }
151
152 /* Fetch destination address. */
153 STREAM_GETC(s, dp->family);
154
155 plen = prefix_blen(dp);
156 STREAM_GET(&dp->u.prefix, s, plen);
157 STREAM_GETC(s, dp->prefixlen);
158
159 /* Get BFD status. */
160 STREAM_GETL(s, (*status));
161
162 STREAM_GETC(s, sp->family);
163
164 plen = prefix_blen(sp);
165 STREAM_GET(&sp->u.prefix, s, plen);
166 STREAM_GETC(s, sp->prefixlen);
167
168 STREAM_GETC(s, local_remote_cbit);
169 if (remote_cbit)
170 *remote_cbit = local_remote_cbit;
171 return ifp;
172
173 stream_failure:
174 /*
175 * Clean dp and sp because caller
176 * will immediately check them valid or not
177 */
178 memset(dp, 0, sizeof(*dp));
179 memset(sp, 0, sizeof(*sp));
180 return NULL;
181 }
182
183 /*
184 * bfd_get_status_str - Convert BFD status to a display string.
185 */
186 const char *bfd_get_status_str(int status)
187 {
188 switch (status) {
189 case BFD_STATUS_DOWN:
190 return "Down";
191 case BFD_STATUS_UP:
192 return "Up";
193 case BFD_STATUS_ADMIN_DOWN:
194 return "Admin Down";
195 case BFD_STATUS_UNKNOWN:
196 default:
197 return "Unknown";
198 }
199 }
200
201 /*
202 * bfd_last_update - Calculate the last BFD update time and convert it
203 * into a dd:hh:mm:ss display format.
204 */
205 static void bfd_last_update(time_t last_update, char *buf, size_t len)
206 {
207 time_t curr;
208 time_t diff;
209 struct tm tm;
210 struct timeval tv;
211
212 /* If no BFD status update has ever been received, print `never'. */
213 if (last_update == 0) {
214 snprintf(buf, len, "never");
215 return;
216 }
217
218 /* Get current time. */
219 monotime(&tv);
220 curr = tv.tv_sec;
221 diff = curr - last_update;
222 gmtime_r(&diff, &tm);
223
224 snprintf(buf, len, "%d:%02d:%02d:%02d", tm.tm_yday, tm.tm_hour,
225 tm.tm_min, tm.tm_sec);
226 }
227
228 /*
229 * bfd_client_sendmsg - Format and send a client register
230 * command to Zebra to be forwarded to BFD
231 */
232 void bfd_client_sendmsg(struct zclient *zclient, int command,
233 vrf_id_t vrf_id)
234 {
235 struct stream *s;
236 enum zclient_send_status ret;
237
238 /* Check socket. */
239 if (!zclient || zclient->sock < 0) {
240 if (bsglobal.debugging)
241 zlog_debug(
242 "%s: Can't send BFD client register, Zebra client not established",
243 __func__);
244 return;
245 }
246
247 s = zclient->obuf;
248 stream_reset(s);
249 zclient_create_header(s, command, vrf_id);
250
251 stream_putl(s, getpid());
252
253 stream_putw_at(s, 0, stream_get_endp(s));
254
255 ret = zclient_send_message(zclient);
256
257 if (ret == ZCLIENT_SEND_FAILURE) {
258 if (bsglobal.debugging)
259 zlog_debug(
260 "%s: %ld: zclient_send_message() failed",
261 __func__, (long)getpid());
262 return;
263 }
264
265 return;
266 }
267
268 int zclient_bfd_command(struct zclient *zc, struct bfd_session_arg *args)
269 {
270 struct stream *s;
271 size_t addrlen;
272
273 /* Individual reg/dereg messages are suppressed during shutdown. */
274 if (bsglobal.shutting_down) {
275 if (bsglobal.debugging)
276 zlog_debug(
277 "%s: Suppressing BFD peer reg/dereg messages",
278 __func__);
279 return -1;
280 }
281
282 /* Check socket. */
283 if (!zc || zc->sock < 0) {
284 if (bsglobal.debugging)
285 zlog_debug("%s: zclient unavailable", __func__);
286 return -1;
287 }
288
289 s = zc->obuf;
290 stream_reset(s);
291
292 /* Create new message. */
293 zclient_create_header(s, args->command, args->vrf_id);
294 stream_putl(s, getpid());
295
296 /* Encode destination address. */
297 stream_putw(s, args->family);
298 addrlen = (args->family == AF_INET) ? sizeof(struct in_addr)
299 : sizeof(struct in6_addr);
300 stream_put(s, &args->dst, addrlen);
301
302 /*
303 * For more BFD integration protocol details, see function
304 * `_ptm_msg_read` in `bfdd/ptm_adapter.c`.
305 */
306 #if HAVE_BFDD > 0
307 /* Session timers. */
308 stream_putl(s, args->min_rx);
309 stream_putl(s, args->min_tx);
310 stream_putc(s, args->detection_multiplier);
311
312 /* Is multi hop? */
313 stream_putc(s, args->mhop != 0);
314
315 /* Source address. */
316 stream_putw(s, args->family);
317 stream_put(s, &args->src, addrlen);
318
319 /* Send the expected hops. */
320 stream_putc(s, args->hops);
321
322 /* Send interface name if any. */
323 if (args->mhop) {
324 /* Don't send interface. */
325 stream_putc(s, 0);
326 if (bsglobal.debugging && args->ifnamelen)
327 zlog_debug("%s: multi hop is configured, not sending interface",
328 __func__);
329 } else {
330 stream_putc(s, args->ifnamelen);
331 if (args->ifnamelen)
332 stream_put(s, args->ifname, args->ifnamelen);
333 }
334
335 /* Send the C bit indicator. */
336 stream_putc(s, args->cbit);
337
338 /* Send profile name if any. */
339 stream_putc(s, args->profilelen);
340 if (args->profilelen)
341 stream_put(s, args->profile, args->profilelen);
342 #else /* PTM BFD */
343 /* Encode timers if this is a registration message. */
344 if (args->command != ZEBRA_BFD_DEST_DEREGISTER) {
345 stream_putl(s, args->min_rx);
346 stream_putl(s, args->min_tx);
347 stream_putc(s, args->detection_multiplier);
348 }
349
350 if (args->mhop) {
351 /* Multi hop indicator. */
352 stream_putc(s, 1);
353
354 /* Multi hop always sends the source address. */
355 stream_putw(s, args->family);
356 stream_put(s, &args->src, addrlen);
357
358 /* Send the expected hops. */
359 stream_putc(s, args->hops);
360 } else {
361 /* Multi hop indicator. */
362 stream_putc(s, 0);
363
364 /* Single hop only sends the source address when IPv6. */
365 if (args->family == AF_INET6) {
366 stream_putw(s, args->family);
367 stream_put(s, &args->src, addrlen);
368 }
369
370 /* Send interface name if any. */
371 stream_putc(s, args->ifnamelen);
372 if (args->ifnamelen)
373 stream_put(s, args->ifname, args->ifnamelen);
374 }
375
376 /* Send the C bit indicator. */
377 stream_putc(s, args->cbit);
378 #endif /* HAVE_BFDD */
379
380 /* Finish the message by writing the size. */
381 stream_putw_at(s, 0, stream_get_endp(s));
382
383 /* Send message to zebra. */
384 if (zclient_send_message(zc) == ZCLIENT_SEND_FAILURE) {
385 if (bsglobal.debugging)
386 zlog_debug("%s: zclient_send_message failed", __func__);
387 return -1;
388 }
389
390 return 0;
391 }
392
393 struct bfd_session_params *bfd_sess_new(bsp_status_update updatecb, void *arg)
394 {
395 struct bfd_session_params *bsp;
396
397 bsp = XCALLOC(MTYPE_BFD_INFO, sizeof(*bsp));
398
399 /* Save application data. */
400 bsp->updatecb = updatecb;
401 bsp->arg = arg;
402
403 /* Set defaults. */
404 bsp->args.detection_multiplier = BFD_DEF_DETECT_MULT;
405 bsp->args.hops = 1;
406 bsp->args.min_rx = BFD_DEF_MIN_RX;
407 bsp->args.min_tx = BFD_DEF_MIN_TX;
408 bsp->args.vrf_id = VRF_DEFAULT;
409
410 /* Register in global list. */
411 TAILQ_INSERT_TAIL(&bsglobal.bsplist, bsp, entry);
412
413 return bsp;
414 }
415
416 static bool _bfd_sess_valid(const struct bfd_session_params *bsp)
417 {
418 /* Peer/local address not configured. */
419 if (bsp->args.family == 0)
420 return false;
421
422 /* Address configured but invalid. */
423 if (bsp->args.family != AF_INET && bsp->args.family != AF_INET6) {
424 if (bsglobal.debugging)
425 zlog_debug("%s: invalid session family: %d", __func__,
426 bsp->args.family);
427 return false;
428 }
429
430 /* Invalid address. */
431 if (memcmp(&bsp->args.dst, &i6a_zero, sizeof(i6a_zero)) == 0) {
432 if (bsglobal.debugging) {
433 if (bsp->args.family == AF_INET)
434 zlog_debug("%s: invalid address: %pI4",
435 __func__,
436 (struct in_addr *)&bsp->args.dst);
437 else
438 zlog_debug("%s: invalid address: %pI6",
439 __func__, &bsp->args.dst);
440 }
441 return false;
442 }
443
444 /* Multi hop requires local address. */
445 if (bsp->args.mhop
446 && memcmp(&i6a_zero, &bsp->args.src, sizeof(i6a_zero)) == 0) {
447 if (bsglobal.debugging)
448 zlog_debug(
449 "%s: multi hop but no local address provided",
450 __func__);
451 return false;
452 }
453
454 /* Check VRF ID. */
455 if (bsp->args.vrf_id == VRF_UNKNOWN) {
456 if (bsglobal.debugging)
457 zlog_debug("%s: asked for unknown VRF", __func__);
458 return false;
459 }
460
461 return true;
462 }
463
464 static int _bfd_sess_send(struct thread *t)
465 {
466 struct bfd_session_params *bsp = THREAD_ARG(t);
467 int rv;
468
469 /* Validate configuration before trying to send bogus data. */
470 if (!_bfd_sess_valid(bsp))
471 return 0;
472
473 if (bsp->lastev == BSE_INSTALL) {
474 bsp->args.command = bsp->installed ? ZEBRA_BFD_DEST_UPDATE
475 : ZEBRA_BFD_DEST_REGISTER;
476 } else
477 bsp->args.command = ZEBRA_BFD_DEST_DEREGISTER;
478
479 /* If not installed and asked for uninstall, do nothing. */
480 if (!bsp->installed && bsp->args.command == ZEBRA_BFD_DEST_DEREGISTER)
481 return 0;
482
483 rv = zclient_bfd_command(bsglobal.zc, &bsp->args);
484 /* Command was sent successfully. */
485 if (rv == 0) {
486 /* Update installation status. */
487 if (bsp->args.command == ZEBRA_BFD_DEST_DEREGISTER)
488 bsp->installed = false;
489 else if (bsp->args.command == ZEBRA_BFD_DEST_REGISTER)
490 bsp->installed = true;
491 } else {
492 struct ipaddr src, dst;
493
494 src.ipa_type = bsp->args.family;
495 src.ipaddr_v6 = bsp->args.src;
496 dst.ipa_type = bsp->args.family;
497 dst.ipaddr_v6 = bsp->args.dst;
498
499 zlog_err(
500 "%s: BFD session %pIA -> %pIA interface %s VRF %s(%u) was not %s",
501 __func__, &src, &dst,
502 bsp->args.ifnamelen ? bsp->args.ifname : "*",
503 vrf_id_to_name(bsp->args.vrf_id), bsp->args.vrf_id,
504 bsp->lastev == BSE_INSTALL ? "installed"
505 : "uninstalled");
506 }
507
508 return 0;
509 }
510
511 static void _bfd_sess_remove(struct bfd_session_params *bsp)
512 {
513 /* Not installed, nothing to do. */
514 if (!bsp->installed)
515 return;
516
517 /* Cancel any pending installation request. */
518 THREAD_OFF(bsp->installev);
519
520 /* Send request to remove any session. */
521 bsp->lastev = BSE_UNINSTALL;
522 thread_execute(bsglobal.tm, _bfd_sess_send, bsp, 0);
523 }
524
525 void bfd_sess_free(struct bfd_session_params **bsp)
526 {
527 if (*bsp == NULL)
528 return;
529
530 /* Remove any installed session. */
531 _bfd_sess_remove(*bsp);
532
533 /* Remove from global list. */
534 TAILQ_REMOVE(&bsglobal.bsplist, (*bsp), entry);
535
536 /* Free the memory and point to NULL. */
537 XFREE(MTYPE_BFD_INFO, (*bsp));
538 }
539
540 static bool bfd_sess_address_changed(const struct bfd_session_params *bsp,
541 uint32_t family,
542 const struct in6_addr *src,
543 const struct in6_addr *dst)
544 {
545 size_t addrlen;
546
547 if (bsp->args.family != family)
548 return true;
549
550 addrlen = (family == AF_INET) ? sizeof(struct in_addr)
551 : sizeof(struct in6_addr);
552 if ((src == NULL && memcmp(&bsp->args.src, &i6a_zero, addrlen))
553 || (src && memcmp(src, &bsp->args.src, addrlen))
554 || memcmp(dst, &bsp->args.dst, addrlen))
555 return true;
556
557 return false;
558 }
559
560 void bfd_sess_set_ipv4_addrs(struct bfd_session_params *bsp,
561 const struct in_addr *src,
562 const struct in_addr *dst)
563 {
564 if (!bfd_sess_address_changed(bsp, AF_INET, (struct in6_addr *)src,
565 (struct in6_addr *)dst))
566 return;
567
568 /* If already installed, remove the old setting. */
569 _bfd_sess_remove(bsp);
570
571 bsp->args.family = AF_INET;
572
573 /* Clean memory, set zero value and avoid static analyser warnings. */
574 memset(&bsp->args.src, 0, sizeof(bsp->args.src));
575 memset(&bsp->args.dst, 0, sizeof(bsp->args.dst));
576
577 /* Copy the equivalent of IPv4 to arguments structure. */
578 if (src)
579 memcpy(&bsp->args.src, src, sizeof(struct in_addr));
580
581 assert(dst);
582 memcpy(&bsp->args.dst, dst, sizeof(struct in_addr));
583 }
584
585 void bfd_sess_set_ipv6_addrs(struct bfd_session_params *bsp,
586 const struct in6_addr *src,
587 const struct in6_addr *dst)
588 {
589 if (!bfd_sess_address_changed(bsp, AF_INET6, src, dst))
590 return;
591
592 /* If already installed, remove the old setting. */
593 _bfd_sess_remove(bsp);
594
595 bsp->args.family = AF_INET6;
596
597 /* Clean memory, set zero value and avoid static analyser warnings. */
598 memset(&bsp->args.src, 0, sizeof(bsp->args.src));
599
600 if (src)
601 bsp->args.src = *src;
602
603 assert(dst);
604 bsp->args.dst = *dst;
605 }
606
607 void bfd_sess_set_interface(struct bfd_session_params *bsp, const char *ifname)
608 {
609 if ((ifname == NULL && bsp->args.ifnamelen == 0)
610 || (ifname && strcmp(bsp->args.ifname, ifname) == 0))
611 return;
612
613 /* If already installed, remove the old setting. */
614 _bfd_sess_remove(bsp);
615
616 if (ifname == NULL) {
617 bsp->args.ifname[0] = 0;
618 bsp->args.ifnamelen = 0;
619 return;
620 }
621
622 if (strlcpy(bsp->args.ifname, ifname, sizeof(bsp->args.ifname))
623 > sizeof(bsp->args.ifname))
624 zlog_warn("%s: interface name truncated: %s", __func__, ifname);
625
626 bsp->args.ifnamelen = strlen(bsp->args.ifname);
627 }
628
629 void bfd_sess_set_profile(struct bfd_session_params *bsp, const char *profile)
630 {
631 if (profile == NULL) {
632 bsp->args.profile[0] = 0;
633 bsp->args.profilelen = 0;
634 return;
635 }
636
637 if (strlcpy(bsp->args.profile, profile, sizeof(bsp->args.profile))
638 > sizeof(bsp->args.profile))
639 zlog_warn("%s: profile name truncated: %s", __func__, profile);
640
641 bsp->args.profilelen = strlen(bsp->args.profile);
642 }
643
644 void bfd_sess_set_vrf(struct bfd_session_params *bsp, vrf_id_t vrf_id)
645 {
646 if (bsp->args.vrf_id == vrf_id)
647 return;
648
649 /* If already installed, remove the old setting. */
650 _bfd_sess_remove(bsp);
651
652 bsp->args.vrf_id = vrf_id;
653 }
654
655 void bfd_sess_set_hop_count(struct bfd_session_params *bsp, uint8_t hops)
656 {
657 if (bsp->args.hops == hops)
658 return;
659
660 /* If already installed, remove the old setting. */
661 _bfd_sess_remove(bsp);
662
663 bsp->args.hops = hops;
664 bsp->args.mhop = (hops > 1);
665 }
666
667
668 void bfd_sess_set_cbit(struct bfd_session_params *bsp, bool enable)
669 {
670 bsp->args.cbit = enable;
671 }
672
673 void bfd_sess_set_timers(struct bfd_session_params *bsp,
674 uint8_t detection_multiplier, uint32_t min_rx,
675 uint32_t min_tx)
676 {
677 bsp->args.detection_multiplier = detection_multiplier;
678 bsp->args.min_rx = min_rx;
679 bsp->args.min_tx = min_tx;
680 }
681
682 void bfd_sess_install(struct bfd_session_params *bsp)
683 {
684 bsp->lastev = BSE_INSTALL;
685 thread_add_event(bsglobal.tm, _bfd_sess_send, bsp, 0, &bsp->installev);
686 }
687
688 void bfd_sess_uninstall(struct bfd_session_params *bsp)
689 {
690 bsp->lastev = BSE_UNINSTALL;
691 thread_add_event(bsglobal.tm, _bfd_sess_send, bsp, 0, &bsp->installev);
692 }
693
694 enum bfd_session_state bfd_sess_status(const struct bfd_session_params *bsp)
695 {
696 return bsp->bss.state;
697 }
698
699 uint8_t bfd_sess_hop_count(const struct bfd_session_params *bsp)
700 {
701 return bsp->args.hops;
702 }
703
704 const char *bfd_sess_profile(const struct bfd_session_params *bsp)
705 {
706 return bsp->args.profilelen ? bsp->args.profile : NULL;
707 }
708
709 void bfd_sess_addresses(const struct bfd_session_params *bsp, int *family,
710 struct in6_addr *src, struct in6_addr *dst)
711 {
712 *family = bsp->args.family;
713 if (src)
714 *src = bsp->args.src;
715 if (dst)
716 *dst = bsp->args.dst;
717 }
718
719 const char *bfd_sess_interface(const struct bfd_session_params *bsp)
720 {
721 if (bsp->args.ifnamelen)
722 return bsp->args.ifname;
723
724 return NULL;
725 }
726
727 const char *bfd_sess_vrf(const struct bfd_session_params *bsp)
728 {
729 return vrf_id_to_name(bsp->args.vrf_id);
730 }
731
732 vrf_id_t bfd_sess_vrf_id(const struct bfd_session_params *bsp)
733 {
734 return bsp->args.vrf_id;
735 }
736
737 bool bfd_sess_cbit(const struct bfd_session_params *bsp)
738 {
739 return bsp->args.cbit;
740 }
741
742 void bfd_sess_timers(const struct bfd_session_params *bsp,
743 uint8_t *detection_multiplier, uint32_t *min_rx,
744 uint32_t *min_tx)
745 {
746 *detection_multiplier = bsp->args.detection_multiplier;
747 *min_rx = bsp->args.min_rx;
748 *min_tx = bsp->args.min_tx;
749 }
750
751 void bfd_sess_show(struct vty *vty, struct json_object *json,
752 struct bfd_session_params *bsp)
753 {
754 json_object *json_bfd = NULL;
755 char time_buf[64];
756
757 if (!bsp)
758 return;
759
760 /* Show type. */
761 if (json) {
762 json_bfd = json_object_new_object();
763 if (bsp->args.mhop)
764 json_object_string_add(json_bfd, "type", "multi hop");
765 else
766 json_object_string_add(json_bfd, "type", "single hop");
767 } else
768 vty_out(vty, " BFD: Type: %s\n",
769 bsp->args.mhop ? "multi hop" : "single hop");
770
771 /* Show configuration. */
772 if (json) {
773 json_object_int_add(json_bfd, "detectMultiplier",
774 bsp->args.detection_multiplier);
775 json_object_int_add(json_bfd, "rxMinInterval",
776 bsp->args.min_rx);
777 json_object_int_add(json_bfd, "txMinInterval",
778 bsp->args.min_tx);
779 } else {
780 vty_out(vty,
781 " Detect Multiplier: %d, Min Rx interval: %d, Min Tx interval: %d\n",
782 bsp->args.detection_multiplier, bsp->args.min_rx,
783 bsp->args.min_tx);
784 }
785
786 bfd_last_update(bsp->bss.last_event, time_buf, sizeof(time_buf));
787 if (json) {
788 json_object_string_add(json_bfd, "status",
789 bfd_get_status_str(bsp->bss.state));
790 json_object_string_add(json_bfd, "lastUpdate", time_buf);
791 } else
792 vty_out(vty, " Status: %s, Last update: %s\n",
793 bfd_get_status_str(bsp->bss.state), time_buf);
794
795 if (json)
796 json_object_object_add(json, "peerBfdInfo", json_bfd);
797 else
798 vty_out(vty, "\n");
799 }
800
801 /*
802 * Zebra communication related.
803 */
804
805 /**
806 * Callback for reinstallation of all registered BFD sessions.
807 *
808 * Use this as `zclient` `bfd_dest_replay` callback.
809 */
810 int zclient_bfd_session_replay(ZAPI_CALLBACK_ARGS)
811 {
812 struct bfd_session_params *bsp;
813
814 if (!zclient->bfd_integration)
815 return 0;
816
817 /* Do nothing when shutting down. */
818 if (bsglobal.shutting_down)
819 return 0;
820
821 if (bsglobal.debugging)
822 zlog_debug("%s: sending all sessions registered", __func__);
823
824 /* Send the client registration */
825 bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id);
826
827 /* Replay all activated peers. */
828 TAILQ_FOREACH (bsp, &bsglobal.bsplist, entry) {
829 /* Skip not installed sessions. */
830 if (!bsp->installed)
831 continue;
832
833 /* We are reconnecting, so we must send installation. */
834 bsp->installed = false;
835
836 /* Cancel any pending installation request. */
837 THREAD_OFF(bsp->installev);
838
839 /* Ask for installation. */
840 bsp->lastev = BSE_INSTALL;
841 thread_execute(bsglobal.tm, _bfd_sess_send, bsp, 0);
842 }
843
844 return 0;
845 }
846
847 int zclient_bfd_session_update(ZAPI_CALLBACK_ARGS)
848 {
849 struct bfd_session_params *bsp, *bspn;
850 size_t sessions_updated = 0;
851 struct interface *ifp;
852 int remote_cbit = false;
853 int state = BFD_STATUS_UNKNOWN;
854 time_t now;
855 size_t addrlen;
856 struct prefix dp;
857 struct prefix sp;
858 char ifstr[128], cbitstr[32];
859
860 if (!zclient->bfd_integration)
861 return 0;
862
863 /* Do nothing when shutting down. */
864 if (bsglobal.shutting_down)
865 return 0;
866
867 ifp = bfd_get_peer_info(zclient->ibuf, &dp, &sp, &state, &remote_cbit,
868 vrf_id);
869 /*
870 * When interface lookup fails or an invalid stream is read, we must
871 * not proceed otherwise it will trigger an assertion while checking
872 * family type below.
873 */
874 if (dp.family == 0 || sp.family == 0)
875 return 0;
876
877 if (bsglobal.debugging) {
878 ifstr[0] = 0;
879 if (ifp)
880 snprintf(ifstr, sizeof(ifstr), " (interface %s)",
881 ifp->name);
882
883 snprintf(cbitstr, sizeof(cbitstr), " (CPI bit %s)",
884 remote_cbit ? "yes" : "no");
885
886 zlog_debug("%s: %pFX -> %pFX%s VRF %s(%u)%s: %s", __func__, &sp,
887 &dp, ifstr, vrf_id_to_name(vrf_id), vrf_id, cbitstr,
888 bfd_get_status_str(state));
889 }
890
891 switch (dp.family) {
892 case AF_INET:
893 addrlen = sizeof(struct in_addr);
894 break;
895 case AF_INET6:
896 addrlen = sizeof(struct in6_addr);
897 break;
898
899 default:
900 /* Unexpected value. */
901 assert(0);
902 break;
903 }
904
905 /* Cache current time to avoid multiple monotime clock calls. */
906 now = monotime(NULL);
907
908 /* Notify all matching sessions about update. */
909 TAILQ_FOREACH_SAFE (bsp, &bsglobal.bsplist, entry, bspn) {
910 /* Skip not installed entries. */
911 if (!bsp->installed)
912 continue;
913 /* Skip different VRFs. */
914 if (bsp->args.vrf_id != vrf_id)
915 continue;
916 /* Skip different families. */
917 if (bsp->args.family != dp.family)
918 continue;
919 /* Skip different interface. */
920 if (bsp->args.ifnamelen && ifp
921 && strcmp(bsp->args.ifname, ifp->name) != 0)
922 continue;
923 /* Skip non matching destination addresses. */
924 if (memcmp(&bsp->args.dst, &dp.u, addrlen) != 0)
925 continue;
926 /*
927 * Source comparison test:
928 * We will only compare source if BFD daemon provided the
929 * source address and the protocol set a source address in
930 * the configuration otherwise we'll just skip it.
931 */
932 if (sp.family && memcmp(&bsp->args.src, &i6a_zero, addrlen) != 0
933 && memcmp(&sp.u, &i6a_zero, addrlen) != 0
934 && memcmp(&bsp->args.src, &sp.u, addrlen) != 0)
935 continue;
936 /* No session state change. */
937 if ((int)bsp->bss.state == state)
938 continue;
939
940 bsp->bss.last_event = now;
941 bsp->bss.previous_state = bsp->bss.state;
942 bsp->bss.state = state;
943 bsp->bss.remote_cbit = remote_cbit;
944 bsp->updatecb(bsp, &bsp->bss, bsp->arg);
945 sessions_updated++;
946 }
947
948 if (bsglobal.debugging)
949 zlog_debug("%s: sessions updated: %zu", __func__,
950 sessions_updated);
951
952 return 0;
953 }
954
955 void bfd_protocol_integration_init(struct zclient *zc, struct thread_master *tm)
956 {
957 /* Initialize data structure. */
958 TAILQ_INIT(&bsglobal.bsplist);
959
960 /* Copy pointers. */
961 bsglobal.zc = zc;
962 bsglobal.tm = tm;
963
964 /* Enable BFD callbacks. */
965 zc->bfd_integration = true;
966
967 /* Send the client registration */
968 bfd_client_sendmsg(zc, ZEBRA_BFD_CLIENT_REGISTER, VRF_DEFAULT);
969 }
970
971 void bfd_protocol_integration_set_debug(bool enable)
972 {
973 bsglobal.debugging = enable;
974 }
975
976 void bfd_protocol_integration_set_shutdown(bool enable)
977 {
978 bsglobal.shutting_down = enable;
979 }
980
981 bool bfd_protocol_integration_debug(void)
982 {
983 return bsglobal.debugging;
984 }
985
986 bool bfd_protocol_integration_shutting_down(void)
987 {
988 return bsglobal.shutting_down;
989 }