mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-05 15:10:38 +00:00
bfdd: add vty shell commands
Implement vty shell integration and allow `bfdd` to be configured through FRR's vtysh. Signed-off-by: Rafael Zalamena <rzalamena@opensourcerouting.org>
This commit is contained in:
parent
7134904b1f
commit
c2f29cf3d7
@ -582,6 +582,14 @@ int bfd_xmt_cb(struct thread *t);
|
||||
int bfd_echo_xmt_cb(struct thread *t);
|
||||
|
||||
|
||||
/*
|
||||
* bfdd_vty.c
|
||||
*
|
||||
* BFD daemon vty shell commands.
|
||||
*/
|
||||
void bfdd_vty_init(void);
|
||||
|
||||
|
||||
/*
|
||||
* OS compatibility functions.
|
||||
*/
|
||||
|
@ -224,6 +224,9 @@ int main(int argc, char *argv[])
|
||||
thread_add_read(master, control_accept, NULL, bglobal.bg_csock,
|
||||
&bglobal.bg_csockev);
|
||||
|
||||
/* Install commands. */
|
||||
bfdd_vty_init();
|
||||
|
||||
/* read configuration file and daemonize */
|
||||
frr_config_fork();
|
||||
|
||||
|
843
bfdd/bfdd_vty.c
Normal file
843
bfdd/bfdd_vty.c
Normal file
@ -0,0 +1,843 @@
|
||||
/*
|
||||
* BFD daemon code
|
||||
* Copyright (C) 2018 Network Device Education Foundation, Inc. ("NetDEF")
|
||||
*
|
||||
* FRR is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* FRR is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with FRR; see the file COPYING. If not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <zebra.h>
|
||||
|
||||
#include "lib/command.h"
|
||||
#include "lib/json.h"
|
||||
#include "lib/log.h"
|
||||
#include "lib/vty.h"
|
||||
|
||||
#include "bfd.h"
|
||||
|
||||
#ifndef VTYSH_EXTRACT_PL
|
||||
#include "bfdd/bfdd_vty_clippy.c"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Commands help string definitions.
|
||||
*/
|
||||
#define PEER_STR "Configure peer\n"
|
||||
#define INTERFACE_NAME_STR "Configure interface name to use\n"
|
||||
#define PEER_IPV4_STR "IPv4 peer address\n"
|
||||
#define PEER_IPV6_STR "IPv6 peer address\n"
|
||||
#define MHOP_STR "Configure multihop\n"
|
||||
#define LOCAL_STR "Configure local address\n"
|
||||
#define LOCAL_IPV4_STR "IPv4 local address\n"
|
||||
#define LOCAL_IPV6_STR "IPv6 local address\n"
|
||||
#define LOCAL_INTF_STR "Configure local interface name to use\n"
|
||||
#define VRF_STR "Configure VRF\n"
|
||||
#define VRF_NAME_STR "Configure VRF name\n"
|
||||
|
||||
/*
|
||||
* Prototypes
|
||||
*/
|
||||
static int bfdd_write_config(struct vty *vty);
|
||||
static int bfdd_peer_write_config(struct vty *vty);
|
||||
static void _bfdd_peer_write_config(struct hash_backet *hb, void *arg);
|
||||
static int bfd_configure_peer(struct bfd_peer_cfg *bpc, bool mhop,
|
||||
const struct sockaddr_any *peer,
|
||||
const struct sockaddr_any *local,
|
||||
const char *ifname, const char *vrfname,
|
||||
char *ebuf, size_t ebuflen);
|
||||
|
||||
static struct json_object *__display_peer_json(struct bfd_session *bs);
|
||||
static void _display_peer_json(struct vty *vty, struct bfd_session *bs);
|
||||
static void _display_peer(struct vty *vty, struct bfd_session *bs);
|
||||
static void _display_all_peers(struct vty *vty, bool use_json);
|
||||
static void _display_peer_iter(struct hash_backet *hb, void *arg);
|
||||
static void _display_peer_json_iter(struct hash_backet *hb, void *arg);
|
||||
|
||||
|
||||
/*
|
||||
* Commands definition.
|
||||
*/
|
||||
DEFUN_NOSH(bfd_enter, bfd_enter_cmd, "bfd", "Configure BFD peers\n")
|
||||
{
|
||||
vty->node = BFD_NODE;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN_NOSH(
|
||||
bfd_peer_enter, bfd_peer_enter_cmd,
|
||||
"peer <A.B.C.D|X:X::X:X> [{multihop|local-address <A.B.C.D|X:X::X:X>|interface IFNAME|vrf NAME}]",
|
||||
PEER_STR PEER_IPV4_STR PEER_IPV6_STR
|
||||
MHOP_STR
|
||||
LOCAL_STR LOCAL_IPV4_STR LOCAL_IPV6_STR
|
||||
INTERFACE_STR
|
||||
LOCAL_INTF_STR
|
||||
VRF_STR VRF_NAME_STR)
|
||||
{
|
||||
bool mhop;
|
||||
int idx;
|
||||
struct bfd_session *bs;
|
||||
const char *peer, *ifname, *local, *vrfname;
|
||||
struct bfd_peer_cfg bpc;
|
||||
struct sockaddr_any psa, lsa, *lsap;
|
||||
char errormsg[128];
|
||||
|
||||
vrfname = peer = ifname = local = NULL;
|
||||
|
||||
/* Gather all provided information. */
|
||||
peer = argv[1]->arg;
|
||||
|
||||
idx = 0;
|
||||
mhop = argv_find(argv, argc, "multihop", &idx);
|
||||
|
||||
idx = 0;
|
||||
if (argv_find(argv, argc, "interface", &idx))
|
||||
ifname = argv[idx + 1]->arg;
|
||||
|
||||
idx = 0;
|
||||
if (argv_find(argv, argc, "local-address", &idx))
|
||||
local = argv[idx + 1]->arg;
|
||||
|
||||
idx = 0;
|
||||
if (argv_find(argv, argc, "vrf", &idx))
|
||||
vrfname = argv[idx + 1]->arg;
|
||||
|
||||
if (vrfname && ifname) {
|
||||
vty_out(vty, "%% VRF is not mixable with interface\n");
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
}
|
||||
|
||||
strtosa(peer, &psa);
|
||||
if (local) {
|
||||
strtosa(local, &lsa);
|
||||
lsap = &lsa;
|
||||
} else
|
||||
lsap = NULL;
|
||||
|
||||
if (bfd_configure_peer(&bpc, mhop, &psa, lsap, ifname, vrfname,
|
||||
errormsg, sizeof(errormsg))
|
||||
!= 0) {
|
||||
vty_out(vty, "%% Invalid peer configuration: %s\n", errormsg);
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
}
|
||||
|
||||
bs = bs_peer_find(&bpc);
|
||||
if (bs == NULL) {
|
||||
bs = ptm_bfd_sess_new(&bpc);
|
||||
if (bs == NULL) {
|
||||
vty_out(vty, "%% Failed to add peer.\n");
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
VTY_PUSH_CONTEXT(BFD_PEER_NODE, bs);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFPY(bfd_peer_detectmultiplier, bfd_peer_detectmultiplier_cmd,
|
||||
"detect-multiplier (2-255)$multiplier",
|
||||
"Configure peer detection multiplier\n"
|
||||
"Configure peer detection multiplier value\n")
|
||||
{
|
||||
struct bfd_session *bs;
|
||||
|
||||
bs = VTY_GET_CONTEXT(bfd_session);
|
||||
bs->detect_mult = multiplier;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFPY(bfd_peer_recvinterval, bfd_peer_recvinterval_cmd,
|
||||
"receive-interval (10-60000)$interval",
|
||||
"Configure peer receive interval\n"
|
||||
"Configure peer receive interval value in milliseconds\n")
|
||||
{
|
||||
struct bfd_session *bs;
|
||||
|
||||
bs = VTY_GET_CONTEXT(bfd_session);
|
||||
bs->timers.required_min_rx = interval * 1000;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFPY(bfd_peer_txinterval, bfd_peer_txinterval_cmd,
|
||||
"transmit-interval (10-60000)$interval",
|
||||
"Configure peer transmit interval\n"
|
||||
"Configure peer transmit interval value in milliseconds\n")
|
||||
{
|
||||
struct bfd_session *bs;
|
||||
|
||||
bs = VTY_GET_CONTEXT(bfd_session);
|
||||
bs->up_min_tx = interval * 1000;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFPY(bfd_peer_echointerval, bfd_peer_echointerval_cmd,
|
||||
"echo-interval (10-60000)$interval",
|
||||
"Configure peer echo interval\n"
|
||||
"Configure peer echo interval value in milliseconds\n")
|
||||
{
|
||||
struct bfd_session *bs;
|
||||
|
||||
bs = VTY_GET_CONTEXT(bfd_session);
|
||||
bs->timers.required_min_echo = interval * 1000;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFPY(bfd_peer_shutdown, bfd_peer_shutdown_cmd, "[no] shutdown",
|
||||
NO_STR "Disable BFD peer")
|
||||
{
|
||||
struct bfd_session *bs;
|
||||
|
||||
bs = VTY_GET_CONTEXT(bfd_session);
|
||||
if (no) {
|
||||
if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
|
||||
return CMD_SUCCESS;
|
||||
|
||||
BFD_UNSET_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN);
|
||||
|
||||
/* Change and notify state change. */
|
||||
bs->ses_state = PTM_BFD_DOWN;
|
||||
control_notify(bs);
|
||||
|
||||
/* Enable all timers. */
|
||||
bfd_recvtimer_update(bs);
|
||||
bfd_xmttimer_update(bs, bs->xmt_TO);
|
||||
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO)) {
|
||||
bfd_echo_recvtimer_update(bs);
|
||||
bfd_echo_xmttimer_update(bs, bs->echo_xmt_TO);
|
||||
}
|
||||
} else {
|
||||
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
|
||||
return CMD_SUCCESS;
|
||||
|
||||
BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN);
|
||||
|
||||
/* Disable all events. */
|
||||
bfd_recvtimer_delete(bs);
|
||||
bfd_echo_recvtimer_delete(bs);
|
||||
bfd_xmttimer_delete(bs);
|
||||
bfd_echo_xmttimer_delete(bs);
|
||||
|
||||
/* Change and notify state change. */
|
||||
bs->ses_state = PTM_BFD_ADM_DOWN;
|
||||
control_notify(bs);
|
||||
|
||||
ptm_bfd_snd(bs, 0);
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFPY(bfd_peer_echo, bfd_peer_echo_cmd, "[no] echo-mode",
|
||||
NO_STR "Configure echo mode\n")
|
||||
{
|
||||
struct bfd_session *bs;
|
||||
|
||||
bs = VTY_GET_CONTEXT(bfd_session);
|
||||
if (no) {
|
||||
if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
|
||||
return CMD_SUCCESS;
|
||||
|
||||
BFD_UNSET_FLAG(bs->flags, BFD_SESS_FLAG_ECHO);
|
||||
ptm_bfd_echo_stop(bs, 0);
|
||||
} else {
|
||||
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
|
||||
return CMD_SUCCESS;
|
||||
|
||||
BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_ECHO);
|
||||
/* Apply setting immediately. */
|
||||
if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN)) {
|
||||
ptm_bfd_echo_start(bs);
|
||||
bfd_echo_recvtimer_update(bs);
|
||||
}
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFPY(bfd_peer_label, bfd_peer_label_cmd, "label WORD$label",
|
||||
"Register peer label\n"
|
||||
"Register peer label identification\n")
|
||||
{
|
||||
struct bfd_session *bs;
|
||||
|
||||
/* Validate label length. */
|
||||
if (strlen(label) >= MAXNAMELEN) {
|
||||
vty_out(vty, "%% Label name is too long\n");
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
}
|
||||
|
||||
bs = VTY_GET_CONTEXT(bfd_session);
|
||||
if (bfd_session_update_label(bs, label) == -1) {
|
||||
vty_out(vty, "%% Failed to update peer label.\n");
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFPY(bfd_no_peer, bfd_no_peer_cmd,
|
||||
"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}]",
|
||||
NO_STR
|
||||
PEER_STR PEER_IPV4_STR PEER_IPV6_STR
|
||||
MHOP_STR
|
||||
LOCAL_STR LOCAL_IPV4_STR LOCAL_IPV6_STR
|
||||
INTERFACE_STR
|
||||
LOCAL_INTF_STR
|
||||
VRF_STR VRF_NAME_STR)
|
||||
{
|
||||
int idx;
|
||||
bool mhop;
|
||||
struct bfd_peer_cfg bpc;
|
||||
struct sockaddr_any psa, lsa, *lsap;
|
||||
char errormsg[128];
|
||||
|
||||
strtosa(peer_str, &psa);
|
||||
if (local) {
|
||||
strtosa(local_str, &lsa);
|
||||
lsap = &lsa;
|
||||
} else {
|
||||
lsap = NULL;
|
||||
}
|
||||
|
||||
idx = 0;
|
||||
mhop = argv_find(argv, argc, "multihop", &idx);
|
||||
|
||||
if (bfd_configure_peer(&bpc, mhop, &psa, lsap, ifname, vrfname,
|
||||
errormsg, sizeof(errormsg))
|
||||
!= 0) {
|
||||
vty_out(vty, "%% Invalid peer configuration: %s\n", errormsg);
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
}
|
||||
|
||||
if (ptm_bfd_ses_del(&bpc) != 0) {
|
||||
vty_out(vty, "%% Failed to remove peer.\n");
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Show commands helper functions
|
||||
*/
|
||||
static void _display_peer(struct vty *vty, struct bfd_session *bs)
|
||||
{
|
||||
char buf[256];
|
||||
time_t now;
|
||||
|
||||
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
|
||||
vty_out(vty, "\tpeer %s", satostr(&bs->mhop.peer));
|
||||
vty_out(vty, " multihop");
|
||||
vty_out(vty, " local-address %s", satostr(&bs->mhop.local));
|
||||
if (bs->mhop.vrf_name[0])
|
||||
vty_out(vty, " vrf %s", bs->mhop.vrf_name);
|
||||
vty_out(vty, "\n");
|
||||
} else {
|
||||
vty_out(vty, "\tpeer %s", satostr(&bs->mhop.peer));
|
||||
if (bs->shop.port_name[0])
|
||||
vty_out(vty, " interface %s", bs->shop.port_name);
|
||||
vty_out(vty, "\n");
|
||||
}
|
||||
|
||||
if (bs->pl)
|
||||
vty_out(vty, "\t\tlabel: %s\n", bs->pl->pl_label);
|
||||
|
||||
vty_out(vty, "\t\tID: %u\n", bs->discrs.my_discr);
|
||||
vty_out(vty, "\t\tRemote ID: %u\n", bs->discrs.remote_discr);
|
||||
|
||||
vty_out(vty, "\t\tStatus: ");
|
||||
switch (bs->ses_state) {
|
||||
case PTM_BFD_ADM_DOWN:
|
||||
vty_out(vty, "shutdown\n");
|
||||
break;
|
||||
case PTM_BFD_DOWN:
|
||||
vty_out(vty, "down\n");
|
||||
|
||||
now = monotime(NULL);
|
||||
integer2timestr(now - bs->uptime.tv_sec, buf, sizeof(buf));
|
||||
vty_out(vty, "\t\tDowntime: %s\n", buf);
|
||||
break;
|
||||
case PTM_BFD_INIT:
|
||||
vty_out(vty, "init\n");
|
||||
break;
|
||||
case PTM_BFD_UP:
|
||||
vty_out(vty, "up\n");
|
||||
|
||||
now = monotime(NULL);
|
||||
integer2timestr(now - bs->uptime.tv_sec, buf, sizeof(buf));
|
||||
vty_out(vty, "\t\tUptime: %s\n", buf);
|
||||
break;
|
||||
|
||||
default:
|
||||
vty_out(vty, "unknown\n");
|
||||
break;
|
||||
}
|
||||
|
||||
vty_out(vty, "\t\tDiagnostics: %s\n", diag2str(bs->local_diag));
|
||||
vty_out(vty, "\t\tRemote diagnostics: %s\n", diag2str(bs->remote_diag));
|
||||
|
||||
vty_out(vty, "\t\tLocal timers:\n");
|
||||
vty_out(vty, "\t\t\tReceive interval: %" PRIu32 "ms\n",
|
||||
bs->timers.required_min_rx / 1000);
|
||||
vty_out(vty, "\t\t\tTransmission interval: %" PRIu32 "ms\n",
|
||||
bs->timers.desired_min_tx / 1000);
|
||||
|
||||
vty_out(vty, "\t\t\tEcho transmission interval: ");
|
||||
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
|
||||
vty_out(vty, "%" PRIu32 "ms\n",
|
||||
bs->timers.required_min_echo / 1000);
|
||||
else
|
||||
vty_out(vty, "disabled\n");
|
||||
|
||||
vty_out(vty, "\t\tRemote timers:\n");
|
||||
vty_out(vty, "\t\t\tReceive interval: %" PRIu32 "ms\n",
|
||||
bs->remote_timers.required_min_rx / 1000);
|
||||
vty_out(vty, "\t\t\tTransmission interval: %" PRIu32 "ms\n",
|
||||
bs->remote_timers.desired_min_tx / 1000);
|
||||
vty_out(vty, "\t\t\tEcho transmission interval: %" PRIu32 "ms\n",
|
||||
bs->remote_timers.required_min_echo / 1000);
|
||||
|
||||
vty_out(vty, "\n");
|
||||
}
|
||||
|
||||
static struct json_object *__display_peer_json(struct bfd_session *bs)
|
||||
{
|
||||
struct json_object *jo = json_object_new_object();
|
||||
|
||||
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
|
||||
json_object_boolean_true_add(jo, "multihop");
|
||||
json_object_string_add(jo, "peer", satostr(&bs->mhop.peer));
|
||||
json_object_string_add(jo, "local", satostr(&bs->mhop.local));
|
||||
if (bs->mhop.vrf_name[0])
|
||||
json_object_string_add(jo, "vrf", bs->mhop.vrf_name);
|
||||
} else {
|
||||
json_object_boolean_false_add(jo, "multihop");
|
||||
json_object_string_add(jo, "peer", satostr(&bs->shop.peer));
|
||||
if (bs->shop.port_name[0])
|
||||
json_object_string_add(jo, "interface",
|
||||
bs->shop.port_name);
|
||||
}
|
||||
|
||||
if (bs->pl)
|
||||
json_object_string_add(jo, "label", bs->pl->pl_label);
|
||||
|
||||
json_object_int_add(jo, "id", bs->discrs.my_discr);
|
||||
json_object_int_add(jo, "remote-id", bs->discrs.remote_discr);
|
||||
|
||||
switch (bs->ses_state) {
|
||||
case PTM_BFD_ADM_DOWN:
|
||||
json_object_string_add(jo, "status", "shutdown");
|
||||
break;
|
||||
case PTM_BFD_DOWN:
|
||||
json_object_string_add(jo, "status", "down");
|
||||
json_object_int_add(jo, "downtime",
|
||||
monotime(NULL) - bs->uptime.tv_sec);
|
||||
break;
|
||||
case PTM_BFD_INIT:
|
||||
json_object_string_add(jo, "status", "init");
|
||||
break;
|
||||
case PTM_BFD_UP:
|
||||
json_object_string_add(jo, "status", "up");
|
||||
json_object_int_add(jo, "uptime",
|
||||
monotime(NULL) - bs->uptime.tv_sec);
|
||||
break;
|
||||
|
||||
default:
|
||||
json_object_string_add(jo, "status", "unknown");
|
||||
break;
|
||||
}
|
||||
|
||||
json_object_string_add(jo, "diagnostic", diag2str(bs->local_diag));
|
||||
json_object_string_add(jo, "remote-diagnostic",
|
||||
diag2str(bs->remote_diag));
|
||||
|
||||
json_object_int_add(jo, "receive-interval",
|
||||
bs->timers.required_min_rx / 1000);
|
||||
json_object_int_add(jo, "transmit-interval",
|
||||
bs->timers.desired_min_tx / 1000);
|
||||
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
|
||||
json_object_int_add(jo, "echo-interval",
|
||||
bs->timers.required_min_echo / 1000);
|
||||
else
|
||||
json_object_int_add(jo, "echo-interval", 0);
|
||||
|
||||
json_object_int_add(jo, "remote-receive-interval",
|
||||
bs->remote_timers.required_min_rx / 1000);
|
||||
json_object_int_add(jo, "remote-transmit-interval",
|
||||
bs->remote_timers.desired_min_tx / 1000);
|
||||
json_object_int_add(jo, "remote-echo-interval",
|
||||
bs->remote_timers.required_min_echo / 1000);
|
||||
|
||||
return jo;
|
||||
}
|
||||
|
||||
static void _display_peer_json(struct vty *vty, struct bfd_session *bs)
|
||||
{
|
||||
struct json_object *jo = __display_peer_json(bs);
|
||||
|
||||
vty_out(vty, "%s\n", json_object_to_json_string_ext(jo, 0));
|
||||
json_object_free(jo);
|
||||
}
|
||||
|
||||
static void _display_peer_iter(struct hash_backet *hb, void *arg)
|
||||
{
|
||||
struct vty *vty = arg;
|
||||
struct bfd_session *bs = hb->data;
|
||||
|
||||
_display_peer(vty, bs);
|
||||
}
|
||||
|
||||
static void _display_peer_json_iter(struct hash_backet *hb, void *arg)
|
||||
{
|
||||
struct json_object *jo = arg, *jon = NULL;
|
||||
struct bfd_session *bs = hb->data;
|
||||
|
||||
jon = __display_peer_json(bs);
|
||||
if (jon == NULL) {
|
||||
log_warning("%s: not enough memory", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
json_object_array_add(jo, jon);
|
||||
}
|
||||
|
||||
static void _display_all_peers(struct vty *vty, bool use_json)
|
||||
{
|
||||
struct json_object *jo;
|
||||
|
||||
if (use_json == false) {
|
||||
bfd_id_iterate(_display_peer_iter, vty);
|
||||
return;
|
||||
}
|
||||
|
||||
jo = json_object_new_array();
|
||||
bfd_id_iterate(_display_peer_json_iter, jo);
|
||||
|
||||
vty_out(vty, "%s\n", json_object_to_json_string_ext(jo, 0));
|
||||
json_object_free(jo);
|
||||
}
|
||||
|
||||
DEFPY(bfd_show_peers, bfd_show_peers_cmd, "show bfd peers [json]",
|
||||
SHOW_STR
|
||||
"Bidirection Forwarding Detection\n"
|
||||
"BFD peers status\n"
|
||||
JSON_STR)
|
||||
{
|
||||
bool json = use_json(argc, argv);
|
||||
|
||||
if (json) {
|
||||
_display_all_peers(vty, true);
|
||||
} else {
|
||||
vty_out(vty, "BFD Peers:\n");
|
||||
_display_all_peers(vty, false);
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFPY(bfd_show_peer, bfd_show_peer_cmd,
|
||||
"show bfd 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|vrf NAME$vrfname}]> [json]",
|
||||
SHOW_STR
|
||||
"Bidirection Forwarding Detection\n"
|
||||
"BFD peers status\n"
|
||||
"Peer label\n"
|
||||
PEER_IPV4_STR PEER_IPV6_STR
|
||||
MHOP_STR
|
||||
LOCAL_STR LOCAL_IPV4_STR LOCAL_IPV6_STR
|
||||
INTERFACE_STR
|
||||
LOCAL_INTF_STR
|
||||
VRF_STR VRF_NAME_STR
|
||||
JSON_STR)
|
||||
{
|
||||
int idx;
|
||||
bool mhop;
|
||||
struct bfd_session *bs = NULL;
|
||||
struct peer_label *pl;
|
||||
struct bfd_peer_cfg bpc;
|
||||
struct sockaddr_any psa, lsa, *lsap;
|
||||
char errormsg[128];
|
||||
|
||||
/* Look up the BFD peer. */
|
||||
if (label) {
|
||||
pl = pl_find(label);
|
||||
if (pl)
|
||||
bs = pl->pl_bs;
|
||||
} else {
|
||||
strtosa(peer_str, &psa);
|
||||
if (local) {
|
||||
strtosa(local_str, &lsa);
|
||||
lsap = &lsa;
|
||||
} else
|
||||
lsap = NULL;
|
||||
|
||||
idx = 0;
|
||||
mhop = argv_find(argv, argc, "multihop", &idx);
|
||||
|
||||
if (bfd_configure_peer(&bpc, mhop, &psa, lsap, ifname, vrfname,
|
||||
errormsg, sizeof(errormsg))
|
||||
!= 0) {
|
||||
vty_out(vty, "%% Invalid peer configuration: %s\n",
|
||||
errormsg);
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
}
|
||||
|
||||
bs = bs_peer_find(&bpc);
|
||||
}
|
||||
|
||||
/* Find peer data. */
|
||||
if (bs == NULL) {
|
||||
vty_out(vty, "%% Unable to find 'peer %s",
|
||||
label ? label : peer_str);
|
||||
if (ifname)
|
||||
vty_out(vty, " interface %s", ifname);
|
||||
if (local)
|
||||
vty_out(vty, " local-address %s", local_str);
|
||||
if (vrfname)
|
||||
vty_out(vty, " vrf %s", vrfname);
|
||||
vty_out(vty, "'\n");
|
||||
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
}
|
||||
|
||||
if (use_json(argc, argv)) {
|
||||
_display_peer_json(vty, bs);
|
||||
} else {
|
||||
vty_out(vty, "BFD Peer:\n");
|
||||
_display_peer(vty, bs);
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Function definitions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Configuration rules:
|
||||
*
|
||||
* Single hop:
|
||||
* peer + (optional vxlan or interface name)
|
||||
*
|
||||
* Multi hop:
|
||||
* peer + local + (optional vrf)
|
||||
*
|
||||
* Anything else is misconfiguration.
|
||||
*/
|
||||
static int bfd_configure_peer(struct bfd_peer_cfg *bpc, bool mhop,
|
||||
const struct sockaddr_any *peer,
|
||||
const struct sockaddr_any *local,
|
||||
const char *ifname, const char *vrfname,
|
||||
char *ebuf, size_t ebuflen)
|
||||
{
|
||||
memset(bpc, 0, sizeof(*bpc));
|
||||
|
||||
/* Defaults */
|
||||
bpc->bpc_shutdown = true;
|
||||
bpc->bpc_detectmultiplier = BPC_DEF_DETECTMULTIPLIER;
|
||||
bpc->bpc_recvinterval = BPC_DEF_RECEIVEINTERVAL;
|
||||
bpc->bpc_txinterval = BPC_DEF_TRANSMITINTERVAL;
|
||||
bpc->bpc_echointerval = BPC_DEF_ECHOINTERVAL;
|
||||
bpc->bpc_lastevent = monotime(NULL);
|
||||
|
||||
/* Safety check: when no error buf is provided len must be zero. */
|
||||
if (ebuf == NULL)
|
||||
ebuflen = 0;
|
||||
|
||||
/* Peer is always mandatory. */
|
||||
if (peer == NULL) {
|
||||
snprintf(ebuf, ebuflen, "peer must not be empty");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Validate address families. */
|
||||
if (peer->sa_sin.sin_family == AF_INET) {
|
||||
if (local && local->sa_sin.sin_family != AF_INET) {
|
||||
snprintf(ebuf, ebuflen,
|
||||
"local is IPv6, but peer is IPv4");
|
||||
return -1;
|
||||
}
|
||||
|
||||
bpc->bpc_ipv4 = true;
|
||||
} else if (peer->sa_sin.sin_family == AF_INET6) {
|
||||
if (local && local->sa_sin.sin_family != AF_INET6) {
|
||||
snprintf(ebuf, ebuflen,
|
||||
"local is IPv4, but peer is IPv6");
|
||||
return -1;
|
||||
}
|
||||
|
||||
bpc->bpc_ipv4 = false;
|
||||
} else {
|
||||
snprintf(ebuf, ebuflen, "invalid peer address family");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Copy local and/or peer addresses. */
|
||||
if (local)
|
||||
bpc->bpc_local = *local;
|
||||
|
||||
if (peer) {
|
||||
bpc->bpc_peer = *peer;
|
||||
} else {
|
||||
/* Peer configuration is mandatory. */
|
||||
snprintf(ebuf, ebuflen, "no peer configured");
|
||||
return -1;
|
||||
}
|
||||
|
||||
bpc->bpc_mhop = mhop;
|
||||
|
||||
#if 0
|
||||
/* Handle VxLAN configuration. */
|
||||
if (vxlan >= 0) {
|
||||
if (vxlan > ((1 << 24) - 1)) {
|
||||
snprintf(ebuf, ebuflen, "invalid VxLAN %d", vxlan);
|
||||
return -1;
|
||||
}
|
||||
if (bpc->bpc_mhop) {
|
||||
snprintf(ebuf, ebuflen,
|
||||
"multihop doesn't accept VxLAN");
|
||||
return -1;
|
||||
}
|
||||
|
||||
bpc->bpc_vxlan = vxlan;
|
||||
}
|
||||
#endif /* VxLAN */
|
||||
|
||||
/* Handle interface specification configuration. */
|
||||
if (ifname) {
|
||||
if (bpc->bpc_mhop) {
|
||||
snprintf(ebuf, ebuflen,
|
||||
"multihop doesn't accept interface names");
|
||||
return -1;
|
||||
}
|
||||
|
||||
bpc->bpc_has_localif = true;
|
||||
if (strlcpy(bpc->bpc_localif, ifname, sizeof(bpc->bpc_localif))
|
||||
> sizeof(bpc->bpc_localif)) {
|
||||
snprintf(ebuf, ebuflen, "interface name too long");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle VRF configuration. */
|
||||
if (vrfname) {
|
||||
bpc->bpc_has_vrfname = true;
|
||||
if (strlcpy(bpc->bpc_vrfname, vrfname, sizeof(bpc->bpc_vrfname))
|
||||
> sizeof(bpc->bpc_vrfname)) {
|
||||
snprintf(ebuf, ebuflen, "vrf name too long");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
static int bfdd_write_config(struct vty *vty)
|
||||
{
|
||||
vty_out(vty, "bfd\n");
|
||||
vty_out(vty, "!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _bfdd_peer_write_config(struct hash_backet *hb, void *arg)
|
||||
{
|
||||
struct vty *vty = arg;
|
||||
struct bfd_session *bs = hb->data;
|
||||
|
||||
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
|
||||
vty_out(vty, " peer %s", satostr(&bs->mhop.peer));
|
||||
vty_out(vty, " multihop");
|
||||
vty_out(vty, " local-address %s", satostr(&bs->mhop.local));
|
||||
if (bs->mhop.vrf_name[0])
|
||||
vty_out(vty, " vrf %s", bs->mhop.vrf_name);
|
||||
vty_out(vty, "\n");
|
||||
} else {
|
||||
vty_out(vty, " peer %s", satostr(&bs->shop.peer));
|
||||
if (bs->local_address.sa_sin.sin_family != AF_UNSPEC)
|
||||
vty_out(vty, " local-address %s",
|
||||
satostr(&bs->local_address));
|
||||
if (bs->shop.port_name[0])
|
||||
vty_out(vty, " interface %s", bs->shop.port_name);
|
||||
vty_out(vty, "\n");
|
||||
}
|
||||
|
||||
if (bs->detect_mult != BPC_DEF_DETECTMULTIPLIER)
|
||||
vty_out(vty, " detect-multiplier %d\n", bs->detect_mult);
|
||||
if (bs->timers.required_min_rx != (BPC_DEF_RECEIVEINTERVAL * 1000))
|
||||
vty_out(vty, " receive-interval %" PRIu32 "\n",
|
||||
bs->timers.required_min_rx / 1000);
|
||||
if (bs->timers.desired_min_tx != (BPC_DEF_TRANSMITINTERVAL * 1000))
|
||||
vty_out(vty, " transmit-interval %" PRIu32 "\n",
|
||||
bs->timers.desired_min_tx / 1000);
|
||||
if (bs->timers.required_min_echo != (BPC_DEF_ECHOINTERVAL * 1000))
|
||||
vty_out(vty, " echo-interval %" PRIu32 "\n",
|
||||
bs->timers.required_min_echo / 1000);
|
||||
if (bs->pl)
|
||||
vty_out(vty, " label %s\n", bs->pl->pl_label);
|
||||
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
|
||||
vty_out(vty, " echo-mode\n");
|
||||
|
||||
vty_out(vty, " %sshutdown\n",
|
||||
BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN) ? "" : "no ");
|
||||
|
||||
vty_out(vty, " !\n");
|
||||
}
|
||||
|
||||
static int bfdd_peer_write_config(struct vty *vty)
|
||||
{
|
||||
bfd_id_iterate(_bfdd_peer_write_config, vty);
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct cmd_node bfd_node = {
|
||||
BFD_NODE,
|
||||
"%s(config-bfd)# ",
|
||||
1,
|
||||
};
|
||||
|
||||
struct cmd_node bfd_peer_node = {
|
||||
BFD_PEER_NODE,
|
||||
"%s(config-bfd-peer)# ",
|
||||
1,
|
||||
};
|
||||
|
||||
void bfdd_vty_init(void)
|
||||
{
|
||||
install_element(ENABLE_NODE, &bfd_show_peers_cmd);
|
||||
install_element(ENABLE_NODE, &bfd_show_peer_cmd);
|
||||
install_element(CONFIG_NODE, &bfd_enter_cmd);
|
||||
|
||||
/* Install BFD node and commands. */
|
||||
install_node(&bfd_node, bfdd_write_config);
|
||||
install_default(BFD_NODE);
|
||||
install_element(BFD_NODE, &bfd_peer_enter_cmd);
|
||||
install_element(BFD_NODE, &bfd_no_peer_cmd);
|
||||
|
||||
/* Install BFD peer node. */
|
||||
install_node(&bfd_peer_node, bfdd_peer_write_config);
|
||||
install_default(BFD_PEER_NODE);
|
||||
install_element(BFD_PEER_NODE, &bfd_peer_detectmultiplier_cmd);
|
||||
install_element(BFD_PEER_NODE, &bfd_peer_recvinterval_cmd);
|
||||
install_element(BFD_PEER_NODE, &bfd_peer_txinterval_cmd);
|
||||
install_element(BFD_PEER_NODE, &bfd_peer_echointerval_cmd);
|
||||
install_element(BFD_PEER_NODE, &bfd_peer_shutdown_cmd);
|
||||
install_element(BFD_PEER_NODE, &bfd_peer_echo_cmd);
|
||||
install_element(BFD_PEER_NODE, &bfd_peer_label_cmd);
|
||||
}
|
@ -10,6 +10,7 @@ endif
|
||||
|
||||
bfdd_libbfd_a_SOURCES = \
|
||||
bfdd/bfd.c \
|
||||
bfdd/bfdd_vty.c \
|
||||
bfdd/bfd_packet.c \
|
||||
bfdd/bsd.c \
|
||||
bfdd/config.c \
|
||||
@ -19,6 +20,9 @@ bfdd_libbfd_a_SOURCES = \
|
||||
bfdd/log.c \
|
||||
# end
|
||||
|
||||
bfdd/bfdd_vty_clippy.c: $(CLIPPY_DEPS)
|
||||
bfdd/bfdd_vty.$(OBJEXT): bfdd/bfdd_vty_clippy.c
|
||||
|
||||
noinst_HEADERS += \
|
||||
bfdd/bfdctl.h \
|
||||
bfdd/bfd.h \
|
||||
|
@ -143,6 +143,8 @@ const char *node_names[] = {
|
||||
*/
|
||||
"bgp ipv6 flowspec", /* BGP_FLOWSPECV6_NODE
|
||||
*/
|
||||
"bfd", /* BFD_NODE */
|
||||
"bfd peer", /* BFD_PEER_NODE */
|
||||
};
|
||||
/* clang-format on */
|
||||
|
||||
@ -987,6 +989,9 @@ enum node_type node_parent(enum node_type node)
|
||||
case LDP_PSEUDOWIRE_NODE:
|
||||
ret = LDP_L2VPN_NODE;
|
||||
break;
|
||||
case BFD_PEER_NODE:
|
||||
ret = BFD_NODE;
|
||||
break;
|
||||
default:
|
||||
ret = CONFIG_NODE;
|
||||
break;
|
||||
@ -1433,6 +1438,7 @@ void cmd_exit(struct vty *vty)
|
||||
case RMAP_NODE:
|
||||
case PBRMAP_NODE:
|
||||
case VTY_NODE:
|
||||
case BFD_NODE:
|
||||
vty->node = CONFIG_NODE;
|
||||
break;
|
||||
case BGP_IPV4_NODE:
|
||||
@ -1474,6 +1480,9 @@ void cmd_exit(struct vty *vty)
|
||||
case LINK_PARAMS_NODE:
|
||||
vty->node = INTERFACE_NODE;
|
||||
break;
|
||||
case BFD_PEER_NODE:
|
||||
vty->node = BFD_NODE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -1544,6 +1553,8 @@ DEFUN (config_end,
|
||||
case KEYCHAIN_KEY_NODE:
|
||||
case VTY_NODE:
|
||||
case LINK_PARAMS_NODE:
|
||||
case BFD_NODE:
|
||||
case BFD_PEER_NODE:
|
||||
vty_config_unlock(vty);
|
||||
vty->node = ENABLE_NODE;
|
||||
break;
|
||||
|
@ -139,6 +139,8 @@ enum node_type {
|
||||
connections.*/
|
||||
BGP_FLOWSPECV4_NODE, /* BGP IPv4 FLOWSPEC Address-Family */
|
||||
BGP_FLOWSPECV6_NODE, /* BGP IPv6 FLOWSPEC Address-Family */
|
||||
BFD_NODE, /* BFD protocol mode. */
|
||||
BFD_PEER_NODE, /* BFD peer configuration mode. */
|
||||
NODE_TYPE_MAX, /* maximum */
|
||||
};
|
||||
|
||||
|
@ -814,6 +814,8 @@ static void vty_end_config(struct vty *vty)
|
||||
case KEYCHAIN_KEY_NODE:
|
||||
case VTY_NODE:
|
||||
case BGP_EVPN_VNI_NODE:
|
||||
case BFD_NODE:
|
||||
case BFD_PEER_NODE:
|
||||
vty_config_unlock(vty);
|
||||
vty->node = ENABLE_NODE;
|
||||
break;
|
||||
@ -1210,6 +1212,8 @@ static void vty_stop_input(struct vty *vty)
|
||||
case KEYCHAIN_NODE:
|
||||
case KEYCHAIN_KEY_NODE:
|
||||
case VTY_NODE:
|
||||
case BFD_NODE:
|
||||
case BFD_PEER_NODE:
|
||||
vty_config_unlock(vty);
|
||||
vty->node = ENABLE_NODE;
|
||||
break;
|
||||
|
@ -150,6 +150,10 @@ if STATICD
|
||||
vtysh_scan += $(top_srcdir)/staticd/static_vty.c
|
||||
endif
|
||||
|
||||
if BFDD
|
||||
vtysh_scan += $(top_srcdir)/bfdd/bfdd_vty.c
|
||||
endif
|
||||
|
||||
vtysh_cmd_FILES = $(vtysh_scan) \
|
||||
$(top_srcdir)/lib/keychain.c $(top_srcdir)/lib/routemap.c \
|
||||
$(top_srcdir)/lib/filter.c $(top_srcdir)/lib/plist.c \
|
||||
|
@ -134,6 +134,7 @@ struct vtysh_client vtysh_client[] = {
|
||||
{.fd = -1, .name = "watchfrr", .flag = VTYSH_WATCHFRR, .next = NULL},
|
||||
{.fd = -1, .name = "pbrd", .flag = VTYSH_PBRD, .next = NULL},
|
||||
{.fd = -1, .name = "staticd", .flag = VTYSH_STATICD, .next = NULL},
|
||||
{.fd = -1, .name = "bfdd", .flag = VTYSH_BFDD, .next = NULL},
|
||||
};
|
||||
|
||||
enum vtysh_write_integrated vtysh_write_integrated =
|
||||
@ -1254,6 +1255,18 @@ struct cmd_node link_params_node = {
|
||||
static struct cmd_node rpki_node = {RPKI_NODE, "%s(config-rpki)# ", 1};
|
||||
#endif
|
||||
|
||||
#if HAVE_BFDD > 0
|
||||
static struct cmd_node bfd_node = {
|
||||
BFD_NODE,
|
||||
"%s(config-bfd)# ",
|
||||
};
|
||||
|
||||
static struct cmd_node bfd_peer_node = {
|
||||
BFD_PEER_NODE,
|
||||
"%s(config-bfd-peer)# ",
|
||||
};
|
||||
#endif /* HAVE_BFDD */
|
||||
|
||||
/* Defined in lib/vty.c */
|
||||
extern struct cmd_node vty_node;
|
||||
|
||||
@ -1680,6 +1693,32 @@ DEFUNSH(VTYSH_PBRD, vtysh_pbr_map, vtysh_pbr_map_cmd,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
#if HAVE_BFDD > 0
|
||||
DEFUNSH(VTYSH_BFDD, bfd_enter, bfd_enter_cmd, "bfd", "Configure BFD peers\n")
|
||||
{
|
||||
vty->node = BFD_NODE;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUNSH(VTYSH_BFDD, bfd_peer_enter, bfd_peer_enter_cmd,
|
||||
"peer <A.B.C.D|X:X::X:X> [{multihop|local-address <A.B.C.D|X:X::X:X>|interface IFNAME|vrf NAME}]",
|
||||
"Configure peer\n"
|
||||
"IPv4 peer address\n"
|
||||
"IPv6 peer address\n"
|
||||
"Configure multihop\n"
|
||||
"Configure local address\n"
|
||||
"IPv4 local address\n"
|
||||
"IPv6 local address\n"
|
||||
INTERFACE_STR
|
||||
"Configure interface name to use\n"
|
||||
"Configure VRF\n"
|
||||
"Configure VRF name\n")
|
||||
{
|
||||
vty->node = BFD_PEER_NODE;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
#endif /* HAVE_BFDD */
|
||||
|
||||
DEFSH(VTYSH_PBRD, vtysh_no_pbr_map_cmd, "no pbr-map WORD [seq (1-700)]",
|
||||
NO_STR
|
||||
"Delete pbr-map\n"
|
||||
@ -1749,6 +1788,7 @@ static int vtysh_exit(struct vty *vty)
|
||||
case PBRMAP_NODE:
|
||||
case VTY_NODE:
|
||||
case KEYCHAIN_NODE:
|
||||
case BFD_NODE:
|
||||
vtysh_execute("end");
|
||||
vtysh_execute("configure terminal");
|
||||
vty->node = CONFIG_NODE;
|
||||
@ -1792,6 +1832,9 @@ static int vtysh_exit(struct vty *vty)
|
||||
case LINK_PARAMS_NODE:
|
||||
vty->node = INTERFACE_NODE;
|
||||
break;
|
||||
case BFD_PEER_NODE:
|
||||
vty->node = BFD_NODE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -1988,6 +2031,17 @@ DEFUNSH(VTYSH_ISISD, vtysh_quit_isisd, vtysh_quit_isisd_cmd, "quit",
|
||||
return vtysh_exit_isisd(self, vty, argc, argv);
|
||||
}
|
||||
|
||||
#if HAVE_BFDD > 0
|
||||
DEFUNSH(VTYSH_BFDD, vtysh_exit_bfdd, vtysh_exit_bfdd_cmd, "exit",
|
||||
"Exit current mode and down to previous mode\n")
|
||||
{
|
||||
return vtysh_exit(vty);
|
||||
}
|
||||
|
||||
ALIAS(vtysh_exit_bfdd, vtysh_quit_bfdd_cmd, "quit",
|
||||
"Exit current mode and down to previous mode\n")
|
||||
#endif
|
||||
|
||||
DEFUNSH(VTYSH_ALL, vtysh_exit_line_vty, vtysh_exit_line_vty_cmd, "exit",
|
||||
"Exit current mode and down to previous mode\n")
|
||||
{
|
||||
@ -3440,6 +3494,10 @@ void vtysh_init_vty(void)
|
||||
#if defined(HAVE_RPKI)
|
||||
install_node(&rpki_node, NULL);
|
||||
#endif
|
||||
#if HAVE_BFDD > 0
|
||||
install_node(&bfd_node, NULL);
|
||||
install_node(&bfd_peer_node, NULL);
|
||||
#endif /* HAVE_BFDD */
|
||||
|
||||
struct cmd_node *node;
|
||||
for (unsigned int i = 0; i < vector_active(cmdvec); i++) {
|
||||
@ -3534,6 +3592,21 @@ void vtysh_init_vty(void)
|
||||
install_element(RMAP_NODE, &vtysh_quit_rmap_cmd);
|
||||
install_element(PBRMAP_NODE, &vtysh_exit_pbr_map_cmd);
|
||||
install_element(PBRMAP_NODE, &vtysh_quit_pbr_map_cmd);
|
||||
#if HAVE_BFDD > 0
|
||||
/* Enter node. */
|
||||
install_element(CONFIG_NODE, &bfd_enter_cmd);
|
||||
install_element(BFD_NODE, &bfd_peer_enter_cmd);
|
||||
|
||||
/* Exit/quit node. */
|
||||
install_element(BFD_NODE, &vtysh_exit_bfdd_cmd);
|
||||
install_element(BFD_NODE, &vtysh_quit_bfdd_cmd);
|
||||
install_element(BFD_PEER_NODE, &vtysh_exit_bfdd_cmd);
|
||||
install_element(BFD_PEER_NODE, &vtysh_quit_bfdd_cmd);
|
||||
|
||||
/* End/exit all. */
|
||||
install_element(BFD_NODE, &vtysh_end_all_cmd);
|
||||
install_element(BFD_PEER_NODE, &vtysh_end_all_cmd);
|
||||
#endif /* HAVE_BFDD */
|
||||
install_element(VTY_NODE, &vtysh_exit_line_vty_cmd);
|
||||
install_element(VTY_NODE, &vtysh_quit_line_vty_cmd);
|
||||
|
||||
|
@ -24,22 +24,23 @@
|
||||
#include "memory.h"
|
||||
DECLARE_MGROUP(MVTYSH)
|
||||
|
||||
#define VTYSH_ZEBRA 0x0001
|
||||
#define VTYSH_RIPD 0x0002
|
||||
#define VTYSH_RIPNGD 0x0004
|
||||
#define VTYSH_OSPFD 0x0008
|
||||
#define VTYSH_OSPF6D 0x0010
|
||||
#define VTYSH_BGPD 0x0020
|
||||
#define VTYSH_ISISD 0x0040
|
||||
#define VTYSH_PIMD 0x0080
|
||||
#define VTYSH_LDPD 0x0100
|
||||
#define VTYSH_WATCHFRR 0x0200
|
||||
#define VTYSH_NHRPD 0x0400
|
||||
#define VTYSH_EIGRPD 0x0800
|
||||
#define VTYSH_BABELD 0x1000
|
||||
#define VTYSH_SHARPD 0x2000
|
||||
#define VTYSH_PBRD 0x4000
|
||||
#define VTYSH_STATICD 0x8000
|
||||
#define VTYSH_ZEBRA 0x00001
|
||||
#define VTYSH_RIPD 0x00002
|
||||
#define VTYSH_RIPNGD 0x00004
|
||||
#define VTYSH_OSPFD 0x00008
|
||||
#define VTYSH_OSPF6D 0x00010
|
||||
#define VTYSH_BGPD 0x00020
|
||||
#define VTYSH_ISISD 0x00040
|
||||
#define VTYSH_PIMD 0x00080
|
||||
#define VTYSH_LDPD 0x00100
|
||||
#define VTYSH_WATCHFRR 0x00200
|
||||
#define VTYSH_NHRPD 0x00400
|
||||
#define VTYSH_EIGRPD 0x00800
|
||||
#define VTYSH_BABELD 0x01000
|
||||
#define VTYSH_SHARPD 0x02000
|
||||
#define VTYSH_PBRD 0x04000
|
||||
#define VTYSH_STATICD 0x08000
|
||||
#define VTYSH_BFDD 0x10000
|
||||
|
||||
#define VTYSH_WAS_ACTIVE (-2)
|
||||
|
||||
@ -48,7 +49,7 @@ DECLARE_MGROUP(MVTYSH)
|
||||
/* watchfrr is not in ALL since library CLI functions should not be
|
||||
* run on it (logging & co. should stay in a fixed/frozen config, and
|
||||
* things like prefix lists are not even initialised) */
|
||||
#define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_SHARPD|VTYSH_PBRD|VTYSH_STATICD
|
||||
#define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_SHARPD|VTYSH_PBRD|VTYSH_STATICD|VTYSH_BFDD
|
||||
#define VTYSH_RMAP VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_EIGRPD|VTYSH_SHARPD
|
||||
#define VTYSH_INTERFACE VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_PBRD
|
||||
#define VTYSH_NS VTYSH_ZEBRA
|
||||
|
@ -318,6 +318,8 @@ void vtysh_config_parse_line(void *arg, const char *line)
|
||||
config = config_get(PROTOCOL_NODE, line);
|
||||
else if (strncmp(line, "mpls", strlen("mpls")) == 0)
|
||||
config = config_get(MPLS_NODE, line);
|
||||
else if (strncmp(line, "bfd", strlen("bfd")) == 0)
|
||||
config = config_get(BFD_NODE, line);
|
||||
else {
|
||||
if (strncmp(line, "log", strlen("log")) == 0
|
||||
|| strncmp(line, "hostname", strlen("hostname"))
|
||||
|
Loading…
Reference in New Issue
Block a user