3 * Copyright (C) 2018 Network Device Education Foundation, Inc. ("NetDEF")
5 * FRR is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2, or (at your option) any
10 * FRR is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with FRR; see the file COPYING. If not, write to the Free
17 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
23 #include "lib/command.h"
30 #ifndef VTYSH_EXTRACT_PL
31 #include "bfdd/bfdd_vty_clippy.c"
35 * Commands help string definitions.
37 #define PEER_STR "Configure peer\n"
38 #define INTERFACE_NAME_STR "Configure interface name to use\n"
39 #define PEER_IPV4_STR "IPv4 peer address\n"
40 #define PEER_IPV6_STR "IPv6 peer address\n"
41 #define MHOP_STR "Configure multihop\n"
42 #define LOCAL_STR "Configure local address\n"
43 #define LOCAL_IPV4_STR "IPv4 local address\n"
44 #define LOCAL_IPV6_STR "IPv6 local address\n"
45 #define LOCAL_INTF_STR "Configure local interface name to use\n"
46 #define VRF_STR "Configure VRF\n"
47 #define VRF_NAME_STR "Configure VRF name\n"
52 static int bfdd_write_config(struct vty
*vty
);
53 static int bfdd_peer_write_config(struct vty
*vty
);
54 static void _bfdd_peer_write_config(struct vty
*vty
, struct bfd_session
*bs
);
55 static void _bfdd_peer_write_config_iter(struct hash_bucket
*hb
, void *arg
);
56 static int bfd_configure_peer(struct bfd_peer_cfg
*bpc
, bool mhop
,
57 const struct sockaddr_any
*peer
,
58 const struct sockaddr_any
*local
,
59 const char *ifname
, const char *vrfname
,
60 char *ebuf
, size_t ebuflen
);
62 static void _display_peer_header(struct vty
*vty
, struct bfd_session
*bs
);
63 static struct json_object
*__display_peer_json(struct bfd_session
*bs
);
64 static struct json_object
*_peer_json_header(struct bfd_session
*bs
);
65 static void _display_peer_json(struct vty
*vty
, struct bfd_session
*bs
);
66 static void _display_peer(struct vty
*vty
, struct bfd_session
*bs
);
67 static void _display_all_peers(struct vty
*vty
, char *vrfname
, bool use_json
);
68 static void _display_peer_iter(struct hash_bucket
*hb
, void *arg
);
69 static void _display_peer_json_iter(struct hash_bucket
*hb
, void *arg
);
70 static void _display_peer_counter(struct vty
*vty
, struct bfd_session
*bs
);
71 static struct json_object
*__display_peer_counters_json(struct bfd_session
*bs
);
72 static void _display_peer_counters_json(struct vty
*vty
, struct bfd_session
*bs
);
73 static void _display_peer_counter_iter(struct hash_bucket
*hb
, void *arg
);
74 static void _display_peer_counter_json_iter(struct hash_bucket
*hb
, void *arg
);
75 static void _display_peers_counter(struct vty
*vty
, char *vrfname
, bool use_json
);
76 static struct bfd_session
*
77 _find_peer_or_error(struct vty
*vty
, int argc
, struct cmd_token
**argv
,
78 const char *label
, const char *peer_str
,
79 const char *local_str
, const char *ifname
,
83 * Commands definition.
85 DEFUN_NOSH(bfd_enter
, bfd_enter_cmd
, "bfd", "Configure BFD peers\n")
92 bfd_peer_enter
, bfd_peer_enter_cmd
,
93 "peer <A.B.C.D|X:X::X:X> [{multihop|local-address <A.B.C.D|X:X::X:X>|interface IFNAME|vrf NAME}]",
94 PEER_STR PEER_IPV4_STR PEER_IPV6_STR
96 LOCAL_STR LOCAL_IPV4_STR LOCAL_IPV6_STR
103 struct bfd_session
*bs
;
104 const char *peer
, *ifname
, *local
, *vrfname
;
105 struct bfd_peer_cfg bpc
;
106 struct sockaddr_any psa
, lsa
, *lsap
;
109 vrfname
= peer
= ifname
= local
= NULL
;
111 /* Gather all provided information. */
115 mhop
= argv_find(argv
, argc
, "multihop", &idx
);
118 if (argv_find(argv
, argc
, "interface", &idx
))
119 ifname
= argv
[idx
+ 1]->arg
;
122 if (argv_find(argv
, argc
, "local-address", &idx
))
123 local
= argv
[idx
+ 1]->arg
;
126 if (argv_find(argv
, argc
, "vrf", &idx
))
127 vrfname
= argv
[idx
+ 1]->arg
;
131 strtosa(local
, &lsa
);
136 if (bfd_configure_peer(&bpc
, mhop
, &psa
, lsap
, ifname
, vrfname
,
137 errormsg
, sizeof(errormsg
))
139 vty_out(vty
, "%% Invalid peer configuration: %s\n", errormsg
);
140 return CMD_WARNING_CONFIG_FAILED
;
143 bs
= bs_peer_find(&bpc
);
145 bs
= ptm_bfd_sess_new(&bpc
);
147 vty_out(vty
, "%% Failed to add peer.\n");
148 return CMD_WARNING_CONFIG_FAILED
;
152 if (!BFD_CHECK_FLAG(bs
->flags
, BFD_SESS_FLAG_CONFIG
)) {
154 vty_out(vty
, "%% session peer is now configurable via bfd daemon.\n");
155 BFD_SET_FLAG(bs
->flags
, BFD_SESS_FLAG_CONFIG
);
158 VTY_PUSH_CONTEXT(BFD_PEER_NODE
, bs
);
163 DEFPY(bfd_peer_detectmultiplier
, bfd_peer_detectmultiplier_cmd
,
164 "detect-multiplier (2-255)$multiplier",
165 "Configure peer detection multiplier\n"
166 "Configure peer detection multiplier value\n")
168 struct bfd_session
*bs
;
170 bs
= VTY_GET_CONTEXT(bfd_session
);
171 if (bs
->detect_mult
== multiplier
)
174 bs
->detect_mult
= multiplier
;
179 DEFPY(bfd_peer_recvinterval
, bfd_peer_recvinterval_cmd
,
180 "receive-interval (10-60000)$interval",
181 "Configure peer receive interval\n"
182 "Configure peer receive interval value in milliseconds\n")
184 struct bfd_session
*bs
;
186 bs
= VTY_GET_CONTEXT(bfd_session
);
187 if (bs
->timers
.required_min_rx
== (uint32_t)(interval
* 1000))
190 bs
->timers
.required_min_rx
= interval
* 1000;
196 DEFPY(bfd_peer_txinterval
, bfd_peer_txinterval_cmd
,
197 "transmit-interval (10-60000)$interval",
198 "Configure peer transmit interval\n"
199 "Configure peer transmit interval value in milliseconds\n")
201 struct bfd_session
*bs
;
203 bs
= VTY_GET_CONTEXT(bfd_session
);
204 if (bs
->timers
.desired_min_tx
== (uint32_t)(interval
* 1000))
207 bs
->timers
.desired_min_tx
= interval
* 1000;
213 DEFPY(bfd_peer_echointerval
, bfd_peer_echointerval_cmd
,
214 "echo-interval (10-60000)$interval",
215 "Configure peer echo interval\n"
216 "Configure peer echo interval value in milliseconds\n")
218 struct bfd_session
*bs
;
220 bs
= VTY_GET_CONTEXT(bfd_session
);
221 if (bs
->timers
.required_min_echo
== (uint32_t)(interval
* 1000))
224 bs
->timers
.required_min_echo
= interval
* 1000;
229 DEFPY(bfd_peer_shutdown
, bfd_peer_shutdown_cmd
, "[no] shutdown",
230 NO_STR
"Disable BFD peer")
232 struct bfd_session
*bs
;
234 bs
= VTY_GET_CONTEXT(bfd_session
);
236 if (!BFD_CHECK_FLAG(bs
->flags
, BFD_SESS_FLAG_SHUTDOWN
))
239 BFD_UNSET_FLAG(bs
->flags
, BFD_SESS_FLAG_SHUTDOWN
);
241 /* Change and notify state change. */
242 bs
->ses_state
= PTM_BFD_DOWN
;
245 /* Enable all timers. */
246 bfd_recvtimer_update(bs
);
247 bfd_xmttimer_update(bs
, bs
->xmt_TO
);
248 if (BFD_CHECK_FLAG(bs
->flags
, BFD_SESS_FLAG_ECHO
)) {
249 bfd_echo_recvtimer_update(bs
);
250 bfd_echo_xmttimer_update(bs
, bs
->echo_xmt_TO
);
253 if (BFD_CHECK_FLAG(bs
->flags
, BFD_SESS_FLAG_SHUTDOWN
))
256 BFD_SET_FLAG(bs
->flags
, BFD_SESS_FLAG_SHUTDOWN
);
258 /* Disable all events. */
259 bfd_recvtimer_delete(bs
);
260 bfd_echo_recvtimer_delete(bs
);
261 bfd_xmttimer_delete(bs
);
262 bfd_echo_xmttimer_delete(bs
);
264 /* Change and notify state change. */
265 bs
->ses_state
= PTM_BFD_ADM_DOWN
;
274 DEFPY(bfd_peer_echo
, bfd_peer_echo_cmd
, "[no] echo-mode",
275 NO_STR
"Configure echo mode\n")
277 struct bfd_session
*bs
;
279 bs
= VTY_GET_CONTEXT(bfd_session
);
281 if (!BFD_CHECK_FLAG(bs
->flags
, BFD_SESS_FLAG_ECHO
))
284 BFD_UNSET_FLAG(bs
->flags
, BFD_SESS_FLAG_ECHO
);
285 ptm_bfd_echo_stop(bs
);
287 if (BFD_CHECK_FLAG(bs
->flags
, BFD_SESS_FLAG_ECHO
))
290 BFD_SET_FLAG(bs
->flags
, BFD_SESS_FLAG_ECHO
);
291 /* Apply setting immediately. */
292 if (!BFD_CHECK_FLAG(bs
->flags
, BFD_SESS_FLAG_SHUTDOWN
))
293 bs_echo_timer_handler(bs
);
299 DEFPY(bfd_peer_label
, bfd_peer_label_cmd
, "label WORD$label",
300 "Register peer label\n"
301 "Register peer label identification\n")
303 struct bfd_session
*bs
;
305 /* Validate label length. */
306 if (strlen(label
) >= MAXNAMELEN
) {
307 vty_out(vty
, "%% Label name is too long\n");
308 return CMD_WARNING_CONFIG_FAILED
;
311 bs
= VTY_GET_CONTEXT(bfd_session
);
312 if (bfd_session_update_label(bs
, label
) == -1) {
313 vty_out(vty
, "%% Failed to update peer label.\n");
314 return CMD_WARNING_CONFIG_FAILED
;
320 DEFPY(bfd_no_peer
, bfd_no_peer_cmd
,
321 "no peer <A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname|vrf NAME$vrfname}]",
323 PEER_STR PEER_IPV4_STR PEER_IPV6_STR
325 LOCAL_STR LOCAL_IPV4_STR LOCAL_IPV6_STR
328 VRF_STR VRF_NAME_STR
)
332 struct bfd_peer_cfg bpc
;
333 struct sockaddr_any psa
, lsa
, *lsap
;
336 strtosa(peer_str
, &psa
);
338 strtosa(local_str
, &lsa
);
345 mhop
= argv_find(argv
, argc
, "multihop", &idx
);
347 if (bfd_configure_peer(&bpc
, mhop
, &psa
, lsap
, ifname
, vrfname
,
348 errormsg
, sizeof(errormsg
))
350 vty_out(vty
, "%% Invalid peer configuration: %s\n", errormsg
);
351 return CMD_WARNING_CONFIG_FAILED
;
354 if (ptm_bfd_sess_del(&bpc
) != 0) {
355 vty_out(vty
, "%% Failed to remove peer.\n");
356 return CMD_WARNING_CONFIG_FAILED
;
364 * Show commands helper functions
366 static void _display_peer_header(struct vty
*vty
, struct bfd_session
*bs
)
368 char addr_buf
[INET6_ADDRSTRLEN
];
370 vty_out(vty
, "\tpeer %s",
371 inet_ntop(bs
->key
.family
, &bs
->key
.peer
, addr_buf
,
374 if (BFD_CHECK_FLAG(bs
->flags
, BFD_SESS_FLAG_MH
))
375 vty_out(vty
, " multihop");
377 if (memcmp(&bs
->key
.local
, &zero_addr
, sizeof(bs
->key
.local
)))
378 vty_out(vty
, " local-address %s",
379 inet_ntop(bs
->key
.family
, &bs
->key
.local
, addr_buf
,
382 if (bs
->key
.vrfname
[0])
383 vty_out(vty
, " vrf %s", bs
->key
.vrfname
);
384 if (bs
->key
.ifname
[0])
385 vty_out(vty
, " interface %s", bs
->key
.ifname
);
389 vty_out(vty
, "\t\tlabel: %s\n", bs
->pl
->pl_label
);
392 static void _display_peer(struct vty
*vty
, struct bfd_session
*bs
)
397 _display_peer_header(vty
, bs
);
399 vty_out(vty
, "\t\tID: %u\n", bs
->discrs
.my_discr
);
400 vty_out(vty
, "\t\tRemote ID: %u\n", bs
->discrs
.remote_discr
);
402 vty_out(vty
, "\t\tStatus: ");
403 switch (bs
->ses_state
) {
404 case PTM_BFD_ADM_DOWN
:
405 vty_out(vty
, "shutdown\n");
408 vty_out(vty
, "down\n");
410 now
= monotime(NULL
);
411 integer2timestr(now
- bs
->downtime
.tv_sec
, buf
, sizeof(buf
));
412 vty_out(vty
, "\t\tDowntime: %s\n", buf
);
415 vty_out(vty
, "init\n");
418 vty_out(vty
, "up\n");
420 now
= monotime(NULL
);
421 integer2timestr(now
- bs
->uptime
.tv_sec
, buf
, sizeof(buf
));
422 vty_out(vty
, "\t\tUptime: %s\n", buf
);
426 vty_out(vty
, "unknown\n");
430 vty_out(vty
, "\t\tDiagnostics: %s\n", diag2str(bs
->local_diag
));
431 vty_out(vty
, "\t\tRemote diagnostics: %s\n", diag2str(bs
->remote_diag
));
433 vty_out(vty
, "\t\tLocal timers:\n");
434 vty_out(vty
, "\t\t\tReceive interval: %" PRIu32
"ms\n",
435 bs
->timers
.required_min_rx
/ 1000);
436 vty_out(vty
, "\t\t\tTransmission interval: %" PRIu32
"ms\n",
437 bs
->timers
.desired_min_tx
/ 1000);
438 vty_out(vty
, "\t\t\tEcho transmission interval: %" PRIu32
"ms\n",
439 bs
->timers
.required_min_echo
/ 1000);
441 vty_out(vty
, "\t\tRemote timers:\n");
442 vty_out(vty
, "\t\t\tReceive interval: %" PRIu32
"ms\n",
443 bs
->remote_timers
.required_min_rx
/ 1000);
444 vty_out(vty
, "\t\t\tTransmission interval: %" PRIu32
"ms\n",
445 bs
->remote_timers
.desired_min_tx
/ 1000);
446 vty_out(vty
, "\t\t\tEcho transmission interval: %" PRIu32
"ms\n",
447 bs
->remote_timers
.required_min_echo
/ 1000);
452 static struct json_object
*_peer_json_header(struct bfd_session
*bs
)
454 struct json_object
*jo
= json_object_new_object();
455 char addr_buf
[INET6_ADDRSTRLEN
];
458 json_object_boolean_true_add(jo
, "multihop");
460 json_object_boolean_false_add(jo
, "multihop");
462 json_object_string_add(jo
, "peer",
463 inet_ntop(bs
->key
.family
, &bs
->key
.peer
,
464 addr_buf
, sizeof(addr_buf
)));
465 if (memcmp(&bs
->key
.local
, &zero_addr
, sizeof(bs
->key
.local
)))
466 json_object_string_add(jo
, "local",
467 inet_ntop(bs
->key
.family
, &bs
->key
.local
,
468 addr_buf
, sizeof(addr_buf
)));
470 if (bs
->key
.vrfname
[0])
471 json_object_string_add(jo
, "vrf", bs
->key
.vrfname
);
472 if (bs
->key
.ifname
[0])
473 json_object_string_add(jo
, "interface", bs
->key
.ifname
);
476 json_object_string_add(jo
, "label", bs
->pl
->pl_label
);
481 static struct json_object
*__display_peer_json(struct bfd_session
*bs
)
483 struct json_object
*jo
= _peer_json_header(bs
);
485 json_object_int_add(jo
, "id", bs
->discrs
.my_discr
);
486 json_object_int_add(jo
, "remote-id", bs
->discrs
.remote_discr
);
488 switch (bs
->ses_state
) {
489 case PTM_BFD_ADM_DOWN
:
490 json_object_string_add(jo
, "status", "shutdown");
493 json_object_string_add(jo
, "status", "down");
494 json_object_int_add(jo
, "downtime",
495 monotime(NULL
) - bs
->downtime
.tv_sec
);
498 json_object_string_add(jo
, "status", "init");
501 json_object_string_add(jo
, "status", "up");
502 json_object_int_add(jo
, "uptime",
503 monotime(NULL
) - bs
->uptime
.tv_sec
);
507 json_object_string_add(jo
, "status", "unknown");
511 json_object_string_add(jo
, "diagnostic", diag2str(bs
->local_diag
));
512 json_object_string_add(jo
, "remote-diagnostic",
513 diag2str(bs
->remote_diag
));
515 json_object_int_add(jo
, "receive-interval",
516 bs
->timers
.required_min_rx
/ 1000);
517 json_object_int_add(jo
, "transmit-interval",
518 bs
->timers
.desired_min_tx
/ 1000);
519 if (BFD_CHECK_FLAG(bs
->flags
, BFD_SESS_FLAG_ECHO
))
520 json_object_int_add(jo
, "echo-interval",
521 bs
->timers
.required_min_echo
/ 1000);
523 json_object_int_add(jo
, "echo-interval", 0);
525 json_object_int_add(jo
, "remote-receive-interval",
526 bs
->remote_timers
.required_min_rx
/ 1000);
527 json_object_int_add(jo
, "remote-transmit-interval",
528 bs
->remote_timers
.desired_min_tx
/ 1000);
529 json_object_int_add(jo
, "remote-echo-interval",
530 bs
->remote_timers
.required_min_echo
/ 1000);
535 static void _display_peer_json(struct vty
*vty
, struct bfd_session
*bs
)
537 struct json_object
*jo
= __display_peer_json(bs
);
539 vty_out(vty
, "%s\n", json_object_to_json_string_ext(jo
, 0));
540 json_object_free(jo
);
543 struct bfd_vrf_tuple
{
546 struct json_object
*jo
;
549 static void _display_peer_iter(struct hash_bucket
*hb
, void *arg
)
551 struct bfd_vrf_tuple
*bvt
= (struct bfd_vrf_tuple
*)arg
;
553 struct bfd_session
*bs
= hb
->data
;
560 if (!bs
->key
.vrfname
[0] ||
561 !strmatch(bs
->key
.vrfname
, bvt
->vrfname
))
564 _display_peer(vty
, bs
);
567 static void _display_peer_json_iter(struct hash_bucket
*hb
, void *arg
)
569 struct bfd_vrf_tuple
*bvt
= (struct bfd_vrf_tuple
*)arg
;
570 struct json_object
*jo
, *jon
= NULL
;
571 struct bfd_session
*bs
= hb
->data
;
578 if (!bs
->key
.vrfname
[0] ||
579 !strmatch(bs
->key
.vrfname
, bvt
->vrfname
))
583 jon
= __display_peer_json(bs
);
585 log_warning("%s: not enough memory", __func__
);
589 json_object_array_add(jo
, jon
);
592 static void _display_all_peers(struct vty
*vty
, char *vrfname
, bool use_json
)
594 struct json_object
*jo
;
595 struct bfd_vrf_tuple bvt
;
597 memset(&bvt
, 0, sizeof(bvt
));
598 bvt
.vrfname
= vrfname
;
602 vty_out(vty
, "BFD Peers:\n");
603 bfd_id_iterate(_display_peer_iter
, &bvt
);
607 jo
= json_object_new_array();
609 bfd_id_iterate(_display_peer_json_iter
, &bvt
);
611 vty_out(vty
, "%s\n", json_object_to_json_string_ext(jo
, 0));
612 json_object_free(jo
);
615 static void _display_peer_counter(struct vty
*vty
, struct bfd_session
*bs
)
617 _display_peer_header(vty
, bs
);
619 vty_out(vty
, "\t\tControl packet input: %" PRIu64
" packets\n",
620 bs
->stats
.rx_ctrl_pkt
);
621 vty_out(vty
, "\t\tControl packet output: %" PRIu64
" packets\n",
622 bs
->stats
.tx_ctrl_pkt
);
623 vty_out(vty
, "\t\tEcho packet input: %" PRIu64
" packets\n",
624 bs
->stats
.rx_echo_pkt
);
625 vty_out(vty
, "\t\tEcho packet output: %" PRIu64
" packets\n",
626 bs
->stats
.tx_echo_pkt
);
627 vty_out(vty
, "\t\tSession up events: %" PRIu64
"\n",
628 bs
->stats
.session_up
);
629 vty_out(vty
, "\t\tSession down events: %" PRIu64
"\n",
630 bs
->stats
.session_down
);
631 vty_out(vty
, "\t\tZebra notifications: %" PRIu64
"\n",
632 bs
->stats
.znotification
);
636 static struct json_object
*__display_peer_counters_json(struct bfd_session
*bs
)
638 struct json_object
*jo
= _peer_json_header(bs
);
640 json_object_int_add(jo
, "control-packet-input", bs
->stats
.rx_ctrl_pkt
);
641 json_object_int_add(jo
, "control-packet-output", bs
->stats
.tx_ctrl_pkt
);
642 json_object_int_add(jo
, "echo-packet-input", bs
->stats
.rx_echo_pkt
);
643 json_object_int_add(jo
, "echo-packet-output", bs
->stats
.tx_echo_pkt
);
644 json_object_int_add(jo
, "session-up", bs
->stats
.session_up
);
645 json_object_int_add(jo
, "session-down", bs
->stats
.session_down
);
646 json_object_int_add(jo
, "zebra-notifications", bs
->stats
.znotification
);
651 static void _display_peer_counters_json(struct vty
*vty
, struct bfd_session
*bs
)
653 struct json_object
*jo
= __display_peer_counters_json(bs
);
655 vty_out(vty
, "%s\n", json_object_to_json_string_ext(jo
, 0));
656 json_object_free(jo
);
659 static void _display_peer_counter_iter(struct hash_bucket
*hb
, void *arg
)
661 struct bfd_vrf_tuple
*bvt
= arg
;
663 struct bfd_session
*bs
= hb
->data
;
670 if (!bs
->key
.vrfname
[0] ||
671 !strmatch(bs
->key
.vrfname
, bvt
->vrfname
))
675 _display_peer_counter(vty
, bs
);
678 static void _display_peer_counter_json_iter(struct hash_bucket
*hb
, void *arg
)
680 struct json_object
*jo
, *jon
= NULL
;
681 struct bfd_session
*bs
= hb
->data
;
682 struct bfd_vrf_tuple
*bvt
= arg
;
689 if (!bs
->key
.vrfname
[0] ||
690 !strmatch(bs
->key
.vrfname
, bvt
->vrfname
))
694 jon
= __display_peer_counters_json(bs
);
696 log_warning("%s: not enough memory", __func__
);
700 json_object_array_add(jo
, jon
);
703 static void _display_peers_counter(struct vty
*vty
, char *vrfname
, bool use_json
)
705 struct json_object
*jo
;
706 struct bfd_vrf_tuple bvt
;
708 memset(&bvt
, 0, sizeof(struct bfd_vrf_tuple
));
709 bvt
.vrfname
= vrfname
;
712 vty_out(vty
, "BFD Peers:\n");
713 bfd_id_iterate(_display_peer_counter_iter
, &bvt
);
717 jo
= json_object_new_array();
719 bfd_id_iterate(_display_peer_counter_json_iter
, jo
);
721 vty_out(vty
, "%s\n", json_object_to_json_string_ext(jo
, 0));
722 json_object_free(jo
);
725 static struct bfd_session
*
726 _find_peer_or_error(struct vty
*vty
, int argc
, struct cmd_token
**argv
,
727 const char *label
, const char *peer_str
,
728 const char *local_str
, const char *ifname
,
733 struct bfd_session
*bs
= NULL
;
734 struct peer_label
*pl
;
735 struct bfd_peer_cfg bpc
;
736 struct sockaddr_any psa
, lsa
, *lsap
;
739 /* Look up the BFD peer. */
745 strtosa(peer_str
, &psa
);
747 strtosa(local_str
, &lsa
);
753 mhop
= argv_find(argv
, argc
, "multihop", &idx
);
755 if (bfd_configure_peer(&bpc
, mhop
, &psa
, lsap
, ifname
, vrfname
,
756 errormsg
, sizeof(errormsg
))
758 vty_out(vty
, "%% Invalid peer configuration: %s\n",
763 bs
= bs_peer_find(&bpc
);
766 /* Find peer data. */
768 vty_out(vty
, "%% Unable to find 'peer %s",
769 label
? label
: peer_str
);
771 vty_out(vty
, " interface %s", ifname
);
773 vty_out(vty
, " local-address %s", local_str
);
775 vty_out(vty
, " vrf %s", vrfname
);
788 DEFPY(bfd_show_peers
, bfd_show_peers_cmd
, "show bfd [vrf <NAME>] peers [json]",
790 "Bidirection Forwarding Detection\n"
792 "BFD peers status\n" JSON_STR
)
794 char *vrf_name
= NULL
;
797 if (argv_find(argv
, argc
, "vrf", &idx_vrf
))
798 vrf_name
= argv
[idx_vrf
+ 1]->arg
;
800 _display_all_peers(vty
, vrf_name
, use_json(argc
, argv
));
805 DEFPY(bfd_show_peer
, bfd_show_peer_cmd
,
806 "show bfd [vrf <NAME$vrfname>] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> [json]",
808 "Bidirection Forwarding Detection\n"
811 "Peer label\n" PEER_IPV4_STR PEER_IPV6_STR MHOP_STR LOCAL_STR
812 LOCAL_IPV4_STR LOCAL_IPV6_STR INTERFACE_STR LOCAL_INTF_STR JSON_STR
)
814 struct bfd_session
*bs
;
816 /* Look up the BFD peer. */
817 bs
= _find_peer_or_error(vty
, argc
, argv
, label
, peer_str
, local_str
,
820 return CMD_WARNING_CONFIG_FAILED
;
822 if (use_json(argc
, argv
)) {
823 _display_peer_json(vty
, bs
);
825 vty_out(vty
, "BFD Peer:\n");
826 _display_peer(vty
, bs
);
832 DEFPY(bfd_show_peer_counters
, bfd_show_peer_counters_cmd
,
833 "show bfd [vrf <NAME$vrfname>] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> counters [json]",
835 "Bidirection Forwarding Detection\n"
847 "Show BFD peer counters information\n"
850 struct bfd_session
*bs
;
852 /* Look up the BFD peer. */
853 bs
= _find_peer_or_error(vty
, argc
, argv
, label
, peer_str
, local_str
,
856 return CMD_WARNING_CONFIG_FAILED
;
858 if (use_json(argc
, argv
))
859 _display_peer_counters_json(vty
, bs
);
861 _display_peer_counter(vty
, bs
);
866 DEFPY(bfd_show_peers_counters
, bfd_show_peers_counters_cmd
,
867 "show bfd [vrf <NAME>] peers counters [json]",
869 "Bidirection Forwarding Detection\n"
872 "Show BFD peer counters information\n"
875 char *vrf_name
= NULL
;
878 if (argv_find(argv
, argc
, "vrf", &idx_vrf
))
879 vrf_name
= argv
[idx_vrf
+ 1]->arg
;
881 _display_peers_counter(vty
, vrf_name
, use_json(argc
, argv
));
888 * Function definitions.
892 * Configuration rules:
895 * peer + (interface name)
898 * peer + local + (optional vrf)
900 * Anything else is misconfiguration.
902 static int bfd_configure_peer(struct bfd_peer_cfg
*bpc
, bool mhop
,
903 const struct sockaddr_any
*peer
,
904 const struct sockaddr_any
*local
,
905 const char *ifname
, const char *vrfname
,
906 char *ebuf
, size_t ebuflen
)
908 memset(bpc
, 0, sizeof(*bpc
));
911 bpc
->bpc_shutdown
= true;
912 bpc
->bpc_detectmultiplier
= BPC_DEF_DETECTMULTIPLIER
;
913 bpc
->bpc_recvinterval
= BPC_DEF_RECEIVEINTERVAL
;
914 bpc
->bpc_txinterval
= BPC_DEF_TRANSMITINTERVAL
;
915 bpc
->bpc_echointerval
= BPC_DEF_ECHOINTERVAL
;
916 bpc
->bpc_lastevent
= monotime(NULL
);
918 /* Safety check: when no error buf is provided len must be zero. */
922 /* Peer is always mandatory. */
924 snprintf(ebuf
, ebuflen
, "peer must not be empty");
928 /* Validate address families. */
929 if (peer
->sa_sin
.sin_family
== AF_INET
) {
930 if (local
&& local
->sa_sin
.sin_family
!= AF_INET
) {
931 snprintf(ebuf
, ebuflen
,
932 "local is IPv6, but peer is IPv4");
936 bpc
->bpc_ipv4
= true;
937 } else if (peer
->sa_sin
.sin_family
== AF_INET6
) {
938 if (local
&& local
->sa_sin
.sin_family
!= AF_INET6
) {
939 snprintf(ebuf
, ebuflen
,
940 "local is IPv4, but peer is IPv6");
944 bpc
->bpc_ipv4
= false;
946 snprintf(ebuf
, ebuflen
, "invalid peer address family");
950 /* Copy local and/or peer addresses. */
952 bpc
->bpc_local
= *local
;
954 bpc
->bpc_peer
= *peer
;
955 bpc
->bpc_mhop
= mhop
;
957 /* Handle interface specification configuration. */
960 snprintf(ebuf
, ebuflen
,
961 "multihop doesn't accept interface names");
965 bpc
->bpc_has_localif
= true;
966 if (strlcpy(bpc
->bpc_localif
, ifname
, sizeof(bpc
->bpc_localif
))
967 > sizeof(bpc
->bpc_localif
)) {
968 snprintf(ebuf
, ebuflen
, "interface name too long");
973 /* Handle VRF configuration. */
975 bpc
->bpc_has_vrfname
= true;
976 if (strlcpy(bpc
->bpc_vrfname
, vrfname
, sizeof(bpc
->bpc_vrfname
))
977 > sizeof(bpc
->bpc_vrfname
)) {
978 snprintf(ebuf
, ebuflen
, "vrf name too long");
985 static int bfdd_write_config(struct vty
*vty
)
987 vty_out(vty
, "bfd\n");
992 static void _bfdd_peer_write_config(struct vty
*vty
, struct bfd_session
*bs
)
994 char addr_buf
[INET6_ADDRSTRLEN
];
996 vty_out(vty
, " peer %s",
997 inet_ntop(bs
->key
.family
, &bs
->key
.peer
, addr_buf
,
1001 vty_out(vty
, " multihop");
1003 if (memcmp(&bs
->key
.local
, &zero_addr
, sizeof(bs
->key
.local
)))
1004 vty_out(vty
, " local-address %s",
1005 inet_ntop(bs
->key
.family
, &bs
->key
.local
, addr_buf
,
1008 if (bs
->key
.vrfname
[0])
1009 vty_out(vty
, " vrf %s", bs
->key
.vrfname
);
1010 if (bs
->key
.ifname
[0])
1011 vty_out(vty
, " interface %s", bs
->key
.ifname
);
1016 " ! vrf, interface or local-address doesn't exist\n");
1018 if (bs
->detect_mult
!= BPC_DEF_DETECTMULTIPLIER
)
1019 vty_out(vty
, " detect-multiplier %d\n", bs
->detect_mult
);
1020 if (bs
->timers
.required_min_rx
!= (BPC_DEF_RECEIVEINTERVAL
* 1000))
1021 vty_out(vty
, " receive-interval %" PRIu32
"\n",
1022 bs
->timers
.required_min_rx
/ 1000);
1023 if (bs
->timers
.desired_min_tx
!= (BPC_DEF_TRANSMITINTERVAL
* 1000))
1024 vty_out(vty
, " transmit-interval %" PRIu32
"\n",
1025 bs
->timers
.desired_min_tx
/ 1000);
1026 if (bs
->timers
.required_min_echo
!= (BPC_DEF_ECHOINTERVAL
* 1000))
1027 vty_out(vty
, " echo-interval %" PRIu32
"\n",
1028 bs
->timers
.required_min_echo
/ 1000);
1030 vty_out(vty
, " label %s\n", bs
->pl
->pl_label
);
1031 if (BFD_CHECK_FLAG(bs
->flags
, BFD_SESS_FLAG_ECHO
))
1032 vty_out(vty
, " echo-mode\n");
1034 vty_out(vty
, " %sshutdown\n",
1035 BFD_CHECK_FLAG(bs
->flags
, BFD_SESS_FLAG_SHUTDOWN
) ? "" : "no ");
1037 vty_out(vty
, " !\n");
1040 DEFUN_NOSH(show_debugging_bfd
,
1041 show_debugging_bfd_cmd
,
1042 "show debugging [bfd]",
1047 vty_out(vty
, "BFD debugging status:\n");
1052 static void _bfdd_peer_write_config_iter(struct hash_bucket
*hb
, void *arg
)
1054 struct vty
*vty
= arg
;
1055 struct bfd_session
*bs
= hb
->data
;
1057 if (!BFD_CHECK_FLAG(bs
->flags
, BFD_SESS_FLAG_CONFIG
))
1060 _bfdd_peer_write_config(vty
, bs
);
1063 static int bfdd_peer_write_config(struct vty
*vty
)
1065 bfd_id_iterate(_bfdd_peer_write_config_iter
, vty
);
1070 struct cmd_node bfd_node
= {
1076 struct cmd_node bfd_peer_node
= {
1078 "%s(config-bfd-peer)# ",
1082 void bfdd_vty_init(void)
1084 install_element(ENABLE_NODE
, &bfd_show_peers_counters_cmd
);
1085 install_element(ENABLE_NODE
, &bfd_show_peer_counters_cmd
);
1086 install_element(ENABLE_NODE
, &bfd_show_peers_cmd
);
1087 install_element(ENABLE_NODE
, &bfd_show_peer_cmd
);
1088 install_element(CONFIG_NODE
, &bfd_enter_cmd
);
1089 install_element(ENABLE_NODE
, &show_debugging_bfd_cmd
);
1091 /* Install BFD node and commands. */
1092 install_node(&bfd_node
, bfdd_write_config
);
1093 install_default(BFD_NODE
);
1094 install_element(BFD_NODE
, &bfd_peer_enter_cmd
);
1095 install_element(BFD_NODE
, &bfd_no_peer_cmd
);
1097 /* Install BFD peer node. */
1098 install_node(&bfd_peer_node
, bfdd_peer_write_config
);
1099 install_default(BFD_PEER_NODE
);
1100 install_element(BFD_PEER_NODE
, &bfd_peer_detectmultiplier_cmd
);
1101 install_element(BFD_PEER_NODE
, &bfd_peer_recvinterval_cmd
);
1102 install_element(BFD_PEER_NODE
, &bfd_peer_txinterval_cmd
);
1103 install_element(BFD_PEER_NODE
, &bfd_peer_echointerval_cmd
);
1104 install_element(BFD_PEER_NODE
, &bfd_peer_shutdown_cmd
);
1105 install_element(BFD_PEER_NODE
, &bfd_peer_echo_cmd
);
1106 install_element(BFD_PEER_NODE
, &bfd_peer_label_cmd
);