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"
26 #include "lib/northbound_cli.h"
31 #ifndef VTYSH_EXTRACT_PL
32 #include "bfdd/bfdd_vty_clippy.c"
36 * Commands help string definitions.
38 #define PEER_IPV4_STR "IPv4 peer address\n"
39 #define PEER_IPV6_STR "IPv6 peer address\n"
40 #define MHOP_STR "Configure multihop\n"
41 #define LOCAL_STR "Configure local address\n"
42 #define LOCAL_IPV4_STR "IPv4 local address\n"
43 #define LOCAL_IPV6_STR "IPv6 local address\n"
44 #define LOCAL_INTF_STR "Configure local interface name to use\n"
49 static int bfd_configure_peer(struct bfd_peer_cfg
*bpc
, bool mhop
,
50 const struct sockaddr_any
*peer
,
51 const struct sockaddr_any
*local
,
52 const char *ifname
, const char *vrfname
,
53 char *ebuf
, size_t ebuflen
);
55 static void _display_peer_header(struct vty
*vty
, struct bfd_session
*bs
);
56 static struct json_object
*__display_peer_json(struct bfd_session
*bs
);
57 static struct json_object
*_peer_json_header(struct bfd_session
*bs
);
58 static void _display_peer_json(struct vty
*vty
, struct bfd_session
*bs
);
59 static void _display_peer(struct vty
*vty
, struct bfd_session
*bs
);
60 static void _display_all_peers(struct vty
*vty
, char *vrfname
, bool use_json
);
61 static void _display_peer_iter(struct hash_bucket
*hb
, void *arg
);
62 static void _display_peer_json_iter(struct hash_bucket
*hb
, void *arg
);
63 static void _display_peer_counter(struct vty
*vty
, struct bfd_session
*bs
);
64 static struct json_object
*__display_peer_counters_json(struct bfd_session
*bs
);
65 static void _display_peer_counters_json(struct vty
*vty
, struct bfd_session
*bs
);
66 static void _display_peer_counter_iter(struct hash_bucket
*hb
, void *arg
);
67 static void _display_peer_counter_json_iter(struct hash_bucket
*hb
, void *arg
);
68 static void _display_peers_counter(struct vty
*vty
, char *vrfname
, bool use_json
);
69 static struct bfd_session
*
70 _find_peer_or_error(struct vty
*vty
, int argc
, struct cmd_token
**argv
,
71 const char *label
, const char *peer_str
,
72 const char *local_str
, const char *ifname
,
77 * Show commands helper functions
79 static void _display_peer_header(struct vty
*vty
, struct bfd_session
*bs
)
81 char addr_buf
[INET6_ADDRSTRLEN
];
83 vty_out(vty
, "\tpeer %s",
84 inet_ntop(bs
->key
.family
, &bs
->key
.peer
, addr_buf
,
87 if (BFD_CHECK_FLAG(bs
->flags
, BFD_SESS_FLAG_MH
))
88 vty_out(vty
, " multihop");
90 if (memcmp(&bs
->key
.local
, &zero_addr
, sizeof(bs
->key
.local
)))
91 vty_out(vty
, " local-address %s",
92 inet_ntop(bs
->key
.family
, &bs
->key
.local
, addr_buf
,
95 if (bs
->key
.vrfname
[0])
96 vty_out(vty
, " vrf %s", bs
->key
.vrfname
);
97 if (bs
->key
.ifname
[0])
98 vty_out(vty
, " interface %s", bs
->key
.ifname
);
102 vty_out(vty
, "\t\tlabel: %s\n", bs
->pl
->pl_label
);
105 static void _display_peer(struct vty
*vty
, struct bfd_session
*bs
)
110 _display_peer_header(vty
, bs
);
112 vty_out(vty
, "\t\tID: %u\n", bs
->discrs
.my_discr
);
113 vty_out(vty
, "\t\tRemote ID: %u\n", bs
->discrs
.remote_discr
);
115 vty_out(vty
, "\t\tStatus: ");
116 switch (bs
->ses_state
) {
117 case PTM_BFD_ADM_DOWN
:
118 vty_out(vty
, "shutdown\n");
121 vty_out(vty
, "down\n");
123 now
= monotime(NULL
);
124 integer2timestr(now
- bs
->downtime
.tv_sec
, buf
, sizeof(buf
));
125 vty_out(vty
, "\t\tDowntime: %s\n", buf
);
128 vty_out(vty
, "init\n");
131 vty_out(vty
, "up\n");
133 now
= monotime(NULL
);
134 integer2timestr(now
- bs
->uptime
.tv_sec
, buf
, sizeof(buf
));
135 vty_out(vty
, "\t\tUptime: %s\n", buf
);
139 vty_out(vty
, "unknown\n");
143 vty_out(vty
, "\t\tDiagnostics: %s\n", diag2str(bs
->local_diag
));
144 vty_out(vty
, "\t\tRemote diagnostics: %s\n", diag2str(bs
->remote_diag
));
146 vty_out(vty
, "\t\tLocal timers:\n");
147 vty_out(vty
, "\t\t\tReceive interval: %" PRIu32
"ms\n",
148 bs
->timers
.required_min_rx
/ 1000);
149 vty_out(vty
, "\t\t\tTransmission interval: %" PRIu32
"ms\n",
150 bs
->timers
.desired_min_tx
/ 1000);
151 vty_out(vty
, "\t\t\tEcho transmission interval: %" PRIu32
"ms\n",
152 bs
->timers
.required_min_echo
/ 1000);
154 vty_out(vty
, "\t\tRemote timers:\n");
155 vty_out(vty
, "\t\t\tReceive interval: %" PRIu32
"ms\n",
156 bs
->remote_timers
.required_min_rx
/ 1000);
157 vty_out(vty
, "\t\t\tTransmission interval: %" PRIu32
"ms\n",
158 bs
->remote_timers
.desired_min_tx
/ 1000);
159 vty_out(vty
, "\t\t\tEcho transmission interval: %" PRIu32
"ms\n",
160 bs
->remote_timers
.required_min_echo
/ 1000);
165 static struct json_object
*_peer_json_header(struct bfd_session
*bs
)
167 struct json_object
*jo
= json_object_new_object();
168 char addr_buf
[INET6_ADDRSTRLEN
];
171 json_object_boolean_true_add(jo
, "multihop");
173 json_object_boolean_false_add(jo
, "multihop");
175 json_object_string_add(jo
, "peer",
176 inet_ntop(bs
->key
.family
, &bs
->key
.peer
,
177 addr_buf
, sizeof(addr_buf
)));
178 if (memcmp(&bs
->key
.local
, &zero_addr
, sizeof(bs
->key
.local
)))
179 json_object_string_add(jo
, "local",
180 inet_ntop(bs
->key
.family
, &bs
->key
.local
,
181 addr_buf
, sizeof(addr_buf
)));
183 if (bs
->key
.vrfname
[0])
184 json_object_string_add(jo
, "vrf", bs
->key
.vrfname
);
185 if (bs
->key
.ifname
[0])
186 json_object_string_add(jo
, "interface", bs
->key
.ifname
);
189 json_object_string_add(jo
, "label", bs
->pl
->pl_label
);
194 static struct json_object
*__display_peer_json(struct bfd_session
*bs
)
196 struct json_object
*jo
= _peer_json_header(bs
);
198 json_object_int_add(jo
, "id", bs
->discrs
.my_discr
);
199 json_object_int_add(jo
, "remote-id", bs
->discrs
.remote_discr
);
201 switch (bs
->ses_state
) {
202 case PTM_BFD_ADM_DOWN
:
203 json_object_string_add(jo
, "status", "shutdown");
206 json_object_string_add(jo
, "status", "down");
207 json_object_int_add(jo
, "downtime",
208 monotime(NULL
) - bs
->downtime
.tv_sec
);
211 json_object_string_add(jo
, "status", "init");
214 json_object_string_add(jo
, "status", "up");
215 json_object_int_add(jo
, "uptime",
216 monotime(NULL
) - bs
->uptime
.tv_sec
);
220 json_object_string_add(jo
, "status", "unknown");
224 json_object_string_add(jo
, "diagnostic", diag2str(bs
->local_diag
));
225 json_object_string_add(jo
, "remote-diagnostic",
226 diag2str(bs
->remote_diag
));
228 json_object_int_add(jo
, "receive-interval",
229 bs
->timers
.required_min_rx
/ 1000);
230 json_object_int_add(jo
, "transmit-interval",
231 bs
->timers
.desired_min_tx
/ 1000);
232 if (BFD_CHECK_FLAG(bs
->flags
, BFD_SESS_FLAG_ECHO
))
233 json_object_int_add(jo
, "echo-interval",
234 bs
->timers
.required_min_echo
/ 1000);
236 json_object_int_add(jo
, "echo-interval", 0);
238 json_object_int_add(jo
, "remote-receive-interval",
239 bs
->remote_timers
.required_min_rx
/ 1000);
240 json_object_int_add(jo
, "remote-transmit-interval",
241 bs
->remote_timers
.desired_min_tx
/ 1000);
242 json_object_int_add(jo
, "remote-echo-interval",
243 bs
->remote_timers
.required_min_echo
/ 1000);
248 static void _display_peer_json(struct vty
*vty
, struct bfd_session
*bs
)
250 struct json_object
*jo
= __display_peer_json(bs
);
252 vty_out(vty
, "%s\n", json_object_to_json_string_ext(jo
, 0));
253 json_object_free(jo
);
256 struct bfd_vrf_tuple
{
259 struct json_object
*jo
;
262 static void _display_peer_iter(struct hash_bucket
*hb
, void *arg
)
264 struct bfd_vrf_tuple
*bvt
= (struct bfd_vrf_tuple
*)arg
;
266 struct bfd_session
*bs
= hb
->data
;
273 if (!bs
->key
.vrfname
[0] ||
274 !strmatch(bs
->key
.vrfname
, bvt
->vrfname
))
277 _display_peer(vty
, bs
);
280 static void _display_peer_json_iter(struct hash_bucket
*hb
, void *arg
)
282 struct bfd_vrf_tuple
*bvt
= (struct bfd_vrf_tuple
*)arg
;
283 struct json_object
*jo
, *jon
= NULL
;
284 struct bfd_session
*bs
= hb
->data
;
291 if (!bs
->key
.vrfname
[0] ||
292 !strmatch(bs
->key
.vrfname
, bvt
->vrfname
))
296 jon
= __display_peer_json(bs
);
298 log_warning("%s: not enough memory", __func__
);
302 json_object_array_add(jo
, jon
);
305 static void _display_all_peers(struct vty
*vty
, char *vrfname
, bool use_json
)
307 struct json_object
*jo
;
308 struct bfd_vrf_tuple bvt
;
310 memset(&bvt
, 0, sizeof(bvt
));
311 bvt
.vrfname
= vrfname
;
315 vty_out(vty
, "BFD Peers:\n");
316 bfd_id_iterate(_display_peer_iter
, &bvt
);
320 jo
= json_object_new_array();
322 bfd_id_iterate(_display_peer_json_iter
, &bvt
);
324 vty_out(vty
, "%s\n", json_object_to_json_string_ext(jo
, 0));
325 json_object_free(jo
);
328 static void _display_peer_counter(struct vty
*vty
, struct bfd_session
*bs
)
330 _display_peer_header(vty
, bs
);
332 vty_out(vty
, "\t\tControl packet input: %" PRIu64
" packets\n",
333 bs
->stats
.rx_ctrl_pkt
);
334 vty_out(vty
, "\t\tControl packet output: %" PRIu64
" packets\n",
335 bs
->stats
.tx_ctrl_pkt
);
336 vty_out(vty
, "\t\tEcho packet input: %" PRIu64
" packets\n",
337 bs
->stats
.rx_echo_pkt
);
338 vty_out(vty
, "\t\tEcho packet output: %" PRIu64
" packets\n",
339 bs
->stats
.tx_echo_pkt
);
340 vty_out(vty
, "\t\tSession up events: %" PRIu64
"\n",
341 bs
->stats
.session_up
);
342 vty_out(vty
, "\t\tSession down events: %" PRIu64
"\n",
343 bs
->stats
.session_down
);
344 vty_out(vty
, "\t\tZebra notifications: %" PRIu64
"\n",
345 bs
->stats
.znotification
);
349 static struct json_object
*__display_peer_counters_json(struct bfd_session
*bs
)
351 struct json_object
*jo
= _peer_json_header(bs
);
353 json_object_int_add(jo
, "control-packet-input", bs
->stats
.rx_ctrl_pkt
);
354 json_object_int_add(jo
, "control-packet-output", bs
->stats
.tx_ctrl_pkt
);
355 json_object_int_add(jo
, "echo-packet-input", bs
->stats
.rx_echo_pkt
);
356 json_object_int_add(jo
, "echo-packet-output", bs
->stats
.tx_echo_pkt
);
357 json_object_int_add(jo
, "session-up", bs
->stats
.session_up
);
358 json_object_int_add(jo
, "session-down", bs
->stats
.session_down
);
359 json_object_int_add(jo
, "zebra-notifications", bs
->stats
.znotification
);
364 static void _display_peer_counters_json(struct vty
*vty
, struct bfd_session
*bs
)
366 struct json_object
*jo
= __display_peer_counters_json(bs
);
368 vty_out(vty
, "%s\n", json_object_to_json_string_ext(jo
, 0));
369 json_object_free(jo
);
372 static void _display_peer_counter_iter(struct hash_bucket
*hb
, void *arg
)
374 struct bfd_vrf_tuple
*bvt
= arg
;
376 struct bfd_session
*bs
= hb
->data
;
383 if (!bs
->key
.vrfname
[0] ||
384 !strmatch(bs
->key
.vrfname
, bvt
->vrfname
))
388 _display_peer_counter(vty
, bs
);
391 static void _display_peer_counter_json_iter(struct hash_bucket
*hb
, void *arg
)
393 struct json_object
*jo
, *jon
= NULL
;
394 struct bfd_session
*bs
= hb
->data
;
395 struct bfd_vrf_tuple
*bvt
= arg
;
402 if (!bs
->key
.vrfname
[0] ||
403 !strmatch(bs
->key
.vrfname
, bvt
->vrfname
))
407 jon
= __display_peer_counters_json(bs
);
409 log_warning("%s: not enough memory", __func__
);
413 json_object_array_add(jo
, jon
);
416 static void _display_peers_counter(struct vty
*vty
, char *vrfname
, bool use_json
)
418 struct json_object
*jo
;
419 struct bfd_vrf_tuple bvt
;
421 memset(&bvt
, 0, sizeof(struct bfd_vrf_tuple
));
422 bvt
.vrfname
= vrfname
;
425 vty_out(vty
, "BFD Peers:\n");
426 bfd_id_iterate(_display_peer_counter_iter
, &bvt
);
430 jo
= json_object_new_array();
432 bfd_id_iterate(_display_peer_counter_json_iter
, jo
);
434 vty_out(vty
, "%s\n", json_object_to_json_string_ext(jo
, 0));
435 json_object_free(jo
);
438 static struct bfd_session
*
439 _find_peer_or_error(struct vty
*vty
, int argc
, struct cmd_token
**argv
,
440 const char *label
, const char *peer_str
,
441 const char *local_str
, const char *ifname
,
446 struct bfd_session
*bs
= NULL
;
447 struct peer_label
*pl
;
448 struct bfd_peer_cfg bpc
;
449 struct sockaddr_any psa
, lsa
, *lsap
;
452 /* Look up the BFD peer. */
458 strtosa(peer_str
, &psa
);
460 strtosa(local_str
, &lsa
);
466 mhop
= argv_find(argv
, argc
, "multihop", &idx
);
468 if (bfd_configure_peer(&bpc
, mhop
, &psa
, lsap
, ifname
, vrfname
,
469 errormsg
, sizeof(errormsg
))
471 vty_out(vty
, "%% Invalid peer configuration: %s\n",
476 bs
= bs_peer_find(&bpc
);
479 /* Find peer data. */
481 vty_out(vty
, "%% Unable to find 'peer %s",
482 label
? label
: peer_str
);
484 vty_out(vty
, " interface %s", ifname
);
486 vty_out(vty
, " local-address %s", local_str
);
488 vty_out(vty
, " vrf %s", vrfname
);
501 DEFPY(bfd_show_peers
, bfd_show_peers_cmd
, "show bfd [vrf <NAME>] peers [json]",
503 "Bidirection Forwarding Detection\n"
505 "BFD peers status\n" JSON_STR
)
507 char *vrf_name
= NULL
;
510 if (argv_find(argv
, argc
, "vrf", &idx_vrf
))
511 vrf_name
= argv
[idx_vrf
+ 1]->arg
;
513 _display_all_peers(vty
, vrf_name
, use_json(argc
, argv
));
518 DEFPY(bfd_show_peer
, bfd_show_peer_cmd
,
519 "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]",
521 "Bidirection Forwarding Detection\n"
524 "Peer label\n" PEER_IPV4_STR PEER_IPV6_STR MHOP_STR LOCAL_STR
525 LOCAL_IPV4_STR LOCAL_IPV6_STR INTERFACE_STR LOCAL_INTF_STR JSON_STR
)
527 struct bfd_session
*bs
;
529 /* Look up the BFD peer. */
530 bs
= _find_peer_or_error(vty
, argc
, argv
, label
, peer_str
, local_str
,
533 return CMD_WARNING_CONFIG_FAILED
;
535 if (use_json(argc
, argv
)) {
536 _display_peer_json(vty
, bs
);
538 vty_out(vty
, "BFD Peer:\n");
539 _display_peer(vty
, bs
);
545 DEFPY(bfd_show_peer_counters
, bfd_show_peer_counters_cmd
,
546 "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]",
548 "Bidirection Forwarding Detection\n"
560 "Show BFD peer counters information\n"
563 struct bfd_session
*bs
;
565 /* Look up the BFD peer. */
566 bs
= _find_peer_or_error(vty
, argc
, argv
, label
, peer_str
, local_str
,
569 return CMD_WARNING_CONFIG_FAILED
;
571 if (use_json(argc
, argv
))
572 _display_peer_counters_json(vty
, bs
);
574 _display_peer_counter(vty
, bs
);
579 DEFPY(bfd_show_peers_counters
, bfd_show_peers_counters_cmd
,
580 "show bfd [vrf <NAME>] peers counters [json]",
582 "Bidirection Forwarding Detection\n"
585 "Show BFD peer counters information\n"
588 char *vrf_name
= NULL
;
591 if (argv_find(argv
, argc
, "vrf", &idx_vrf
))
592 vrf_name
= argv
[idx_vrf
+ 1]->arg
;
594 _display_peers_counter(vty
, vrf_name
, use_json(argc
, argv
));
601 * Function definitions.
605 * Configuration rules:
608 * peer + (interface name)
611 * peer + local + (optional vrf)
613 * Anything else is misconfiguration.
615 static int bfd_configure_peer(struct bfd_peer_cfg
*bpc
, bool mhop
,
616 const struct sockaddr_any
*peer
,
617 const struct sockaddr_any
*local
,
618 const char *ifname
, const char *vrfname
,
619 char *ebuf
, size_t ebuflen
)
621 memset(bpc
, 0, sizeof(*bpc
));
624 bpc
->bpc_shutdown
= true;
625 bpc
->bpc_detectmultiplier
= BPC_DEF_DETECTMULTIPLIER
;
626 bpc
->bpc_recvinterval
= BPC_DEF_RECEIVEINTERVAL
;
627 bpc
->bpc_txinterval
= BPC_DEF_TRANSMITINTERVAL
;
628 bpc
->bpc_echointerval
= BPC_DEF_ECHOINTERVAL
;
629 bpc
->bpc_lastevent
= monotime(NULL
);
631 /* Safety check: when no error buf is provided len must be zero. */
635 /* Peer is always mandatory. */
637 snprintf(ebuf
, ebuflen
, "peer must not be empty");
641 /* Validate address families. */
642 if (peer
->sa_sin
.sin_family
== AF_INET
) {
643 if (local
&& local
->sa_sin
.sin_family
!= AF_INET
) {
644 snprintf(ebuf
, ebuflen
,
645 "local is IPv6, but peer is IPv4");
649 bpc
->bpc_ipv4
= true;
650 } else if (peer
->sa_sin
.sin_family
== AF_INET6
) {
651 if (local
&& local
->sa_sin
.sin_family
!= AF_INET6
) {
652 snprintf(ebuf
, ebuflen
,
653 "local is IPv4, but peer is IPv6");
657 bpc
->bpc_ipv4
= false;
659 snprintf(ebuf
, ebuflen
, "invalid peer address family");
663 /* Copy local and/or peer addresses. */
665 bpc
->bpc_local
= *local
;
667 bpc
->bpc_peer
= *peer
;
668 bpc
->bpc_mhop
= mhop
;
670 /* Handle interface specification configuration. */
672 bpc
->bpc_has_localif
= true;
673 if (strlcpy(bpc
->bpc_localif
, ifname
, sizeof(bpc
->bpc_localif
))
674 > sizeof(bpc
->bpc_localif
)) {
675 snprintf(ebuf
, ebuflen
, "interface name too long");
680 /* Handle VRF configuration. */
682 bpc
->bpc_has_vrfname
= true;
683 if (strlcpy(bpc
->bpc_vrfname
, vrfname
, sizeof(bpc
->bpc_vrfname
))
684 > sizeof(bpc
->bpc_vrfname
)) {
685 snprintf(ebuf
, ebuflen
, "vrf name too long");
693 DEFUN_NOSH(show_debugging_bfd
,
694 show_debugging_bfd_cmd
,
695 "show debugging [bfd]",
700 vty_out(vty
, "BFD debugging status:\n");
705 struct cmd_node bfd_node
= {
711 struct cmd_node bfd_peer_node
= {
713 "%s(config-bfd-peer)# ",
717 static int bfdd_write_config(struct vty
*vty
)
719 struct lyd_node
*dnode
;
722 dnode
= yang_dnode_get(running_config
->dnode
, "/frr-bfdd:bfdd");
724 nb_cli_show_dnode_cmds(vty
, dnode
, false);
731 void bfdd_vty_init(void)
733 install_element(ENABLE_NODE
, &bfd_show_peers_counters_cmd
);
734 install_element(ENABLE_NODE
, &bfd_show_peer_counters_cmd
);
735 install_element(ENABLE_NODE
, &bfd_show_peers_cmd
);
736 install_element(ENABLE_NODE
, &bfd_show_peer_cmd
);
737 install_element(ENABLE_NODE
, &show_debugging_bfd_cmd
);
739 /* Install BFD node and commands. */
740 install_node(&bfd_node
, bfdd_write_config
);
741 install_default(BFD_NODE
);
743 /* Install BFD peer node. */
744 install_node(&bfd_peer_node
, NULL
);
745 install_default(BFD_PEER_NODE
);