mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-05 01:14:48 +00:00
Merge pull request #4437 from opensourcerouting/bfdd-northbound
bfdd: migrate to northbound
This commit is contained in:
commit
af13de0af6
141
bfdd/bfd.c
141
bfdd/bfd.c
@ -34,19 +34,12 @@
|
||||
DEFINE_MTYPE_STATIC(BFDD, BFDD_CONFIG, "long-lived configuration memory")
|
||||
DEFINE_MTYPE_STATIC(BFDD, BFDD_SESSION_OBSERVER, "Session observer")
|
||||
DEFINE_MTYPE_STATIC(BFDD, BFDD_VRF, "BFD VRF")
|
||||
DEFINE_QOBJ_TYPE(bfd_session)
|
||||
|
||||
/*
|
||||
* Prototypes
|
||||
*/
|
||||
void gen_bfd_key(struct bfd_key *key, struct sockaddr_any *peer,
|
||||
struct sockaddr_any *local, bool mhop, const char *ifname,
|
||||
const char *vrfname);
|
||||
|
||||
static uint32_t ptm_bfd_gen_ID(void);
|
||||
static void ptm_bfd_echo_xmt_TO(struct bfd_session *bfd);
|
||||
static void bfd_session_free(struct bfd_session *bs);
|
||||
static struct bfd_session *bfd_session_new(void);
|
||||
static struct bfd_session *bfd_find_disc(struct sockaddr_any *sa,
|
||||
uint32_t ldisc);
|
||||
static int bfd_session_update(struct bfd_session *bs, struct bfd_peer_cfg *bpc);
|
||||
@ -91,6 +84,8 @@ void gen_bfd_key(struct bfd_key *key, struct sockaddr_any *peer,
|
||||
strlcpy(key->ifname, ifname, sizeof(key->ifname));
|
||||
if (vrfname && vrfname[0])
|
||||
strlcpy(key->vrfname, vrfname, sizeof(key->vrfname));
|
||||
else
|
||||
strlcpy(key->vrfname, VRF_DEFAULT_NAME, sizeof(key->vrfname));
|
||||
}
|
||||
|
||||
struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc)
|
||||
@ -396,17 +391,13 @@ struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp,
|
||||
|
||||
/* Search for session without using discriminator. */
|
||||
ifp = if_lookup_by_index(ifindex, vrfid);
|
||||
if (vrfid == VRF_DEFAULT) {
|
||||
/*
|
||||
* Don't use the default vrf, otherwise we won't find
|
||||
* sessions that doesn't specify it.
|
||||
*/
|
||||
vrf = NULL;
|
||||
} else
|
||||
if (vrfid != VRF_DEFAULT)
|
||||
vrf = vrf_lookup_by_id(vrfid);
|
||||
else
|
||||
vrf = NULL;
|
||||
|
||||
gen_bfd_key(&key, peer, local, is_mhop, ifp ? ifp->name : NULL,
|
||||
vrf ? vrf->name : NULL);
|
||||
vrf ? vrf->name : VRF_DEFAULT_NAME);
|
||||
|
||||
/* XXX maybe remoteDiscr should be checked for remoteHeard cases. */
|
||||
return bfd_key_lookup(key);
|
||||
@ -469,14 +460,12 @@ int bfd_echo_recvtimer_cb(struct thread *t)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct bfd_session *bfd_session_new(void)
|
||||
struct bfd_session *bfd_session_new(void)
|
||||
{
|
||||
struct bfd_session *bs;
|
||||
|
||||
bs = XCALLOC(MTYPE_BFDD_CONFIG, sizeof(*bs));
|
||||
|
||||
QOBJ_REG(bs, bfd_session);
|
||||
|
||||
bs->timers.desired_min_tx = BFD_DEFDESIREDMINTX;
|
||||
bs->timers.required_min_rx = BFD_DEFREQUIREDMINRX;
|
||||
bs->timers.required_min_echo = BFD_DEF_REQ_MIN_ECHO;
|
||||
@ -629,7 +618,7 @@ static int bfd_session_update(struct bfd_session *bs, struct bfd_peer_cfg *bpc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bfd_session_free(struct bfd_session *bs)
|
||||
void bfd_session_free(struct bfd_session *bs)
|
||||
{
|
||||
struct bfd_session_observer *bso;
|
||||
|
||||
@ -650,7 +639,6 @@ static void bfd_session_free(struct bfd_session *bs)
|
||||
|
||||
pl_free(bs->pl);
|
||||
|
||||
QOBJ_UNREG(bs);
|
||||
XFREE(MTYPE_BFDD_CONFIG, bs);
|
||||
}
|
||||
|
||||
@ -686,6 +674,9 @@ struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc)
|
||||
if (bpc->bpc_has_vrfname)
|
||||
strlcpy(bfd->key.vrfname, bpc->bpc_vrfname,
|
||||
sizeof(bfd->key.vrfname));
|
||||
else
|
||||
strlcpy(bfd->key.vrfname, VRF_DEFAULT_NAME,
|
||||
sizeof(bfd->key.vrfname));
|
||||
|
||||
/* Copy remaining data. */
|
||||
if (bpc->bpc_ipv4 == false)
|
||||
@ -717,6 +708,17 @@ struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc)
|
||||
|
||||
bfd->key.mhop = bpc->bpc_mhop;
|
||||
|
||||
if (bs_registrate(bfd) == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Apply other configurations. */
|
||||
_bfd_session_update(bfd, bpc);
|
||||
|
||||
return bfd;
|
||||
}
|
||||
|
||||
struct bfd_session *bs_registrate(struct bfd_session *bfd)
|
||||
{
|
||||
/* Registrate session into data structures. */
|
||||
bfd_key_insert(bfd);
|
||||
bfd->discrs.my_discr = ptm_bfd_gen_ID();
|
||||
@ -733,9 +735,6 @@ struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc)
|
||||
if (bfd->key.ifname[0] || bfd->key.vrfname[0] || bfd->sock == -1)
|
||||
bs_observer_add(bfd);
|
||||
|
||||
/* Apply other configurations. */
|
||||
_bfd_session_update(bfd, bpc);
|
||||
|
||||
log_info("session-new: %s", bs_to_string(bfd));
|
||||
|
||||
control_notify_config(BCM_NOTIFY_CONFIG_ADD, bfd);
|
||||
@ -1342,9 +1341,10 @@ struct bfd_key_walk_partial_lookup {
|
||||
};
|
||||
|
||||
/* ignore some parameters */
|
||||
static int bfd_key_lookup_ignore_partial_walker(struct hash_bucket *b, void *data)
|
||||
static int bfd_key_lookup_ignore_partial_walker(struct hash_bucket *b,
|
||||
void *data)
|
||||
{
|
||||
struct bfd_key_walk_partial_lookup *ctx =
|
||||
struct bfd_key_walk_partial_lookup *ctx =
|
||||
(struct bfd_key_walk_partial_lookup *)data;
|
||||
struct bfd_session *given = ctx->given;
|
||||
struct bfd_session *parsed = b->data;
|
||||
@ -1353,7 +1353,8 @@ static int bfd_key_lookup_ignore_partial_walker(struct hash_bucket *b, void *dat
|
||||
return HASHWALK_CONTINUE;
|
||||
if (given->key.mhop != parsed->key.mhop)
|
||||
return HASHWALK_CONTINUE;
|
||||
if (memcmp(&given->key.peer, &parsed->key.peer, sizeof(struct in6_addr)))
|
||||
if (memcmp(&given->key.peer, &parsed->key.peer,
|
||||
sizeof(struct in6_addr)))
|
||||
return HASHWALK_CONTINUE;
|
||||
if (memcmp(given->key.vrfname, parsed->key.vrfname, MAXNAMELEN))
|
||||
return HASHWALK_CONTINUE;
|
||||
@ -1531,6 +1532,94 @@ void bfd_shutdown(void)
|
||||
hash_free(bfd_key_hash);
|
||||
}
|
||||
|
||||
struct bfd_session_iterator {
|
||||
int bsi_stop;
|
||||
bool bsi_mhop;
|
||||
const struct bfd_session *bsi_bs;
|
||||
};
|
||||
|
||||
static int _bfd_session_next(struct hash_bucket *hb, void *arg)
|
||||
{
|
||||
struct bfd_session_iterator *bsi = arg;
|
||||
struct bfd_session *bs = hb->data;
|
||||
|
||||
/* Previous entry signaled stop. */
|
||||
if (bsi->bsi_stop == 1) {
|
||||
/* Match the single/multi hop sessions. */
|
||||
if (bs->key.mhop != bsi->bsi_mhop)
|
||||
return HASHWALK_CONTINUE;
|
||||
|
||||
bsi->bsi_bs = bs;
|
||||
return HASHWALK_ABORT;
|
||||
}
|
||||
|
||||
/* We found the current item, stop in the next one. */
|
||||
if (bsi->bsi_bs == hb->data) {
|
||||
bsi->bsi_stop = 1;
|
||||
/* Set entry to NULL to signal end of list. */
|
||||
bsi->bsi_bs = NULL;
|
||||
} else if (bsi->bsi_bs == NULL && bsi->bsi_mhop == bs->key.mhop) {
|
||||
/* We want the first list item. */
|
||||
bsi->bsi_stop = 1;
|
||||
bsi->bsi_bs = hb->data;
|
||||
return HASHWALK_ABORT;
|
||||
}
|
||||
|
||||
return HASHWALK_CONTINUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* bfd_session_next: uses the current session to find the next.
|
||||
*
|
||||
* `bs` might point to NULL to get the first item of the data structure.
|
||||
*/
|
||||
const struct bfd_session *bfd_session_next(const struct bfd_session *bs,
|
||||
bool mhop)
|
||||
{
|
||||
struct bfd_session_iterator bsi;
|
||||
|
||||
bsi.bsi_stop = 0;
|
||||
bsi.bsi_bs = bs;
|
||||
bsi.bsi_mhop = mhop;
|
||||
hash_walk(bfd_key_hash, _bfd_session_next, &bsi);
|
||||
if (bsi.bsi_stop == 0)
|
||||
return NULL;
|
||||
|
||||
return bsi.bsi_bs;
|
||||
}
|
||||
|
||||
static void _bfd_session_remove_manual(struct hash_bucket *hb,
|
||||
void *arg __attribute__((__unused__)))
|
||||
{
|
||||
struct bfd_session *bs = hb->data;
|
||||
|
||||
/* Delete only manually configured sessions. */
|
||||
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG) == 0)
|
||||
return;
|
||||
|
||||
bs->refcount--;
|
||||
BFD_UNSET_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG);
|
||||
|
||||
/* Don't delete sessions still in use. */
|
||||
if (bs->refcount != 0)
|
||||
return;
|
||||
|
||||
bfd_session_free(bs);
|
||||
}
|
||||
|
||||
/*
|
||||
* bfd_sessions_remove_manual: remove all manually configured sessions.
|
||||
*
|
||||
* NOTE: this function doesn't remove automatically created sessions.
|
||||
*/
|
||||
void bfd_sessions_remove_manual(void)
|
||||
{
|
||||
hash_iterate(bfd_key_hash, _bfd_session_remove_manual, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* VRF related functions.
|
||||
*/
|
||||
static int bfd_vrf_new(struct vrf *vrf)
|
||||
{
|
||||
log_debug("VRF Created: %s(%u)", vrf->name, vrf->vrf_id);
|
||||
|
53
bfdd/bfd.h
53
bfdd/bfd.h
@ -252,11 +252,7 @@ struct bfd_session {
|
||||
struct bfd_timers remote_timers;
|
||||
|
||||
uint64_t refcount; /* number of pointers referencing this. */
|
||||
|
||||
/* VTY context data. */
|
||||
QOBJ_FIELDS
|
||||
};
|
||||
DECLARE_QOBJ_TYPE(bfd_session)
|
||||
|
||||
struct peer_label {
|
||||
TAILQ_ENTRY(peer_label) pl_entry;
|
||||
@ -546,6 +542,16 @@ void bs_observer_del(struct bfd_session_observer *bso);
|
||||
|
||||
void bs_to_bpc(struct bfd_session *bs, struct bfd_peer_cfg *bpc);
|
||||
|
||||
void gen_bfd_key(struct bfd_key *key, struct sockaddr_any *peer,
|
||||
struct sockaddr_any *local, bool mhop, const char *ifname,
|
||||
const char *vrfname);
|
||||
struct bfd_session *bfd_session_new(void);
|
||||
struct bfd_session *bs_registrate(struct bfd_session *bs);
|
||||
void bfd_session_free(struct bfd_session *bs);
|
||||
const struct bfd_session *bfd_session_next(const struct bfd_session *bs,
|
||||
bool mhop);
|
||||
void bfd_sessions_remove_manual(void);
|
||||
|
||||
/* BFD hash data structures interface */
|
||||
void bfd_initialize(void);
|
||||
void bfd_shutdown(void);
|
||||
@ -584,6 +590,37 @@ extern struct in6_addr zero_addr;
|
||||
void bfdd_vty_init(void);
|
||||
|
||||
|
||||
/*
|
||||
* bfdd_cli.c
|
||||
*
|
||||
* BFD daemon CLI implementation.
|
||||
*/
|
||||
void bfdd_cli_init(void);
|
||||
|
||||
void bfd_cli_show_header(struct vty *vty, struct lyd_node *dnode,
|
||||
bool show_defaults);
|
||||
void bfd_cli_show_header_end(struct vty *vty, struct lyd_node *dnode);
|
||||
void bfd_cli_show_single_hop_peer(struct vty *vty,
|
||||
struct lyd_node *dnode,
|
||||
bool show_defaults);
|
||||
void bfd_cli_show_multi_hop_peer(struct vty *vty,
|
||||
struct lyd_node *dnode,
|
||||
bool show_defaults);
|
||||
void bfd_cli_show_peer_end(struct vty *vty, struct lyd_node *dnode);
|
||||
void bfd_cli_show_mult(struct vty *vty, struct lyd_node *dnode,
|
||||
bool show_defaults);
|
||||
void bfd_cli_show_tx(struct vty *vty, struct lyd_node *dnode,
|
||||
bool show_defaults);
|
||||
void bfd_cli_show_rx(struct vty *vty, struct lyd_node *dnode,
|
||||
bool show_defaults);
|
||||
void bfd_cli_show_shutdown(struct vty *vty, struct lyd_node *dnode,
|
||||
bool show_defaults);
|
||||
void bfd_cli_show_echo(struct vty *vty, struct lyd_node *dnode,
|
||||
bool show_defaults);
|
||||
void bfd_cli_show_echo_interval(struct vty *vty, struct lyd_node *dnode,
|
||||
bool show_defaults);
|
||||
|
||||
|
||||
/*
|
||||
* ptm_adapter.c
|
||||
*/
|
||||
@ -596,4 +633,12 @@ void bfdd_sessions_disable_vrf(struct vrf *vrf);
|
||||
|
||||
int ptm_bfd_notify(struct bfd_session *bs);
|
||||
|
||||
|
||||
/*
|
||||
* bfdd_northbound.c
|
||||
*
|
||||
* BFD northbound callbacks.
|
||||
*/
|
||||
extern const struct frr_yang_module_info frr_bfdd_info;
|
||||
|
||||
#endif /* _BFD_H_ */
|
||||
|
24
bfdd/bfdd.c
24
bfdd/bfdd.c
@ -39,6 +39,9 @@ struct thread_master *master;
|
||||
/* BFDd privileges */
|
||||
static zebra_capabilities_t _caps_p[] = {ZCAP_BIND, ZCAP_SYS_ADMIN, ZCAP_NET_RAW};
|
||||
|
||||
/* BFD daemon information. */
|
||||
static struct frr_daemon_info bfdd_di;
|
||||
|
||||
void socket_close(int *s)
|
||||
{
|
||||
if (*s <= 0)
|
||||
@ -78,6 +81,14 @@ static void sigterm_handler(void)
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static void sighup_handler(void)
|
||||
{
|
||||
zlog_info("SIGHUP received");
|
||||
|
||||
/* Reload config file. */
|
||||
vty_read_config(NULL, bfdd_di.config_file, config_default);
|
||||
}
|
||||
|
||||
static struct quagga_signal_t bfd_signals[] = {
|
||||
{
|
||||
.signal = SIGUSR1,
|
||||
@ -91,12 +102,23 @@ static struct quagga_signal_t bfd_signals[] = {
|
||||
.signal = SIGINT,
|
||||
.handler = &sigterm_handler,
|
||||
},
|
||||
{
|
||||
.signal = SIGHUP,
|
||||
.handler = &sighup_handler,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct frr_yang_module_info *bfdd_yang_modules[] = {
|
||||
&frr_interface_info,
|
||||
&frr_bfdd_info,
|
||||
};
|
||||
|
||||
FRR_DAEMON_INFO(bfdd, BFD, .vty_port = 2617,
|
||||
.proghelp = "Implementation of the BFD protocol.",
|
||||
.signals = bfd_signals, .n_signals = array_size(bfd_signals),
|
||||
.privs = &bglobal.bfdd_privs)
|
||||
.privs = &bglobal.bfdd_privs,
|
||||
.yang_modules = bfdd_yang_modules,
|
||||
.n_yang_modules = array_size(bfdd_yang_modules))
|
||||
|
||||
#define OPTION_CTLSOCK 1001
|
||||
static struct option longopts[] = {
|
||||
|
412
bfdd/bfdd_cli.c
Normal file
412
bfdd/bfdd_cli.c
Normal file
@ -0,0 +1,412 @@
|
||||
/*
|
||||
* BFD daemon CLI implementation.
|
||||
*
|
||||
* Copyright (C) 2019 Network Device Education Foundation, Inc. ("NetDEF")
|
||||
* Rafael Zalamena
|
||||
*
|
||||
* This program 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 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <zebra.h>
|
||||
|
||||
#include "lib/command.h"
|
||||
#include "lib/log.h"
|
||||
#include "lib/northbound_cli.h"
|
||||
|
||||
#ifndef VTYSH_EXTRACT_PL
|
||||
#include "bfdd/bfdd_cli_clippy.c"
|
||||
#endif /* VTYSH_EXTRACT_PL */
|
||||
|
||||
#include "bfd.h"
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Functions.
|
||||
*/
|
||||
DEFPY_NOSH(
|
||||
bfd_enter, bfd_enter_cmd,
|
||||
"bfd",
|
||||
"Configure BFD peers\n")
|
||||
{
|
||||
int ret;
|
||||
|
||||
nb_cli_enqueue_change(vty, "/frr-bfdd:bfdd/bfd", NB_OP_CREATE, NULL);
|
||||
ret = nb_cli_apply_changes(vty, NULL);
|
||||
if (ret == CMD_SUCCESS)
|
||||
VTY_PUSH_XPATH(BFD_NODE, "/frr-bfdd:bfdd/bfd");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
DEFUN(
|
||||
bfd_config_reset, bfd_config_reset_cmd,
|
||||
"no bfd",
|
||||
NO_STR
|
||||
"Configure BFD peers\n")
|
||||
{
|
||||
nb_cli_enqueue_change(vty, "/frr-bfdd:bfdd/bfd", NB_OP_DESTROY, NULL);
|
||||
return nb_cli_apply_changes(vty, NULL);
|
||||
}
|
||||
|
||||
void bfd_cli_show_header(struct vty *vty,
|
||||
struct lyd_node *dnode __attribute__((__unused__)),
|
||||
bool show_defaults __attribute__((__unused__)))
|
||||
{
|
||||
vty_out(vty, "!\nbfd\n");
|
||||
}
|
||||
|
||||
void bfd_cli_show_header_end(struct vty *vty,
|
||||
struct lyd_node *dnode __attribute__((__unused__)))
|
||||
{
|
||||
vty_out(vty, "!\n");
|
||||
}
|
||||
|
||||
DEFPY_NOSH(
|
||||
bfd_peer_enter, bfd_peer_enter_cmd,
|
||||
"peer <A.B.C.D|X:X::X:X> [{multihop$multihop|local-address <A.B.C.D|X:X::X:X>|interface IFNAME$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)
|
||||
{
|
||||
int ret, slen;
|
||||
char source_str[INET6_ADDRSTRLEN];
|
||||
char xpath[XPATH_MAXLEN], xpath_srcaddr[XPATH_MAXLEN + 32];
|
||||
|
||||
if (multihop)
|
||||
snprintf(source_str, sizeof(source_str), "[source-addr='%s']",
|
||||
local_address_str);
|
||||
else
|
||||
source_str[0] = 0;
|
||||
|
||||
slen = snprintf(xpath, sizeof(xpath),
|
||||
"/frr-bfdd:bfdd/bfd/sessions/%s%s[dest-addr='%s']",
|
||||
multihop ? "multi-hop" : "single-hop", source_str,
|
||||
peer_str);
|
||||
if (ifname)
|
||||
slen += snprintf(xpath + slen, sizeof(xpath) - slen,
|
||||
"[interface='%s']", ifname);
|
||||
else
|
||||
slen += snprintf(xpath + slen, sizeof(xpath) - slen,
|
||||
"[interface='']");
|
||||
if (vrf)
|
||||
snprintf(xpath + slen, sizeof(xpath) - slen, "[vrf='%s']", vrf);
|
||||
else
|
||||
snprintf(xpath + slen, sizeof(xpath) - slen, "[vrf='%s']",
|
||||
VRF_DEFAULT_NAME);
|
||||
|
||||
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
|
||||
if (multihop == NULL && local_address_str != NULL) {
|
||||
snprintf(xpath_srcaddr, sizeof(xpath_srcaddr),
|
||||
"%s/source-addr", xpath);
|
||||
nb_cli_enqueue_change(vty, xpath_srcaddr, NB_OP_MODIFY,
|
||||
local_address_str);
|
||||
}
|
||||
|
||||
/* Apply settings immediately. */
|
||||
ret = nb_cli_apply_changes(vty, NULL);
|
||||
if (ret == CMD_SUCCESS)
|
||||
VTY_PUSH_XPATH(BFD_PEER_NODE, xpath);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
DEFPY(
|
||||
bfd_no_peer, bfd_no_peer_cmd,
|
||||
"no peer <A.B.C.D|X:X::X:X> [{multihop$multihop|local-address <A.B.C.D|X:X::X:X>|interface IFNAME$ifname|vrf NAME}]",
|
||||
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 slen;
|
||||
char xpath[XPATH_MAXLEN];
|
||||
char source_str[INET6_ADDRSTRLEN];
|
||||
|
||||
if (multihop)
|
||||
snprintf(source_str, sizeof(source_str), "[source-addr='%s']",
|
||||
local_address_str);
|
||||
else
|
||||
source_str[0] = 0;
|
||||
|
||||
slen = snprintf(xpath, sizeof(xpath),
|
||||
"/frr-bfdd:bfdd/bfd/sessions/%s%s[dest-addr='%s']",
|
||||
multihop ? "multi-hop" : "single-hop", source_str,
|
||||
peer_str);
|
||||
if (ifname)
|
||||
slen += snprintf(xpath + slen, sizeof(xpath) - slen,
|
||||
"[interface='%s']", ifname);
|
||||
else
|
||||
slen += snprintf(xpath + slen, sizeof(xpath) - slen,
|
||||
"[interface='']");
|
||||
if (vrf)
|
||||
snprintf(xpath + slen, sizeof(xpath) - slen, "[vrf='%s']", vrf);
|
||||
else
|
||||
snprintf(xpath + slen, sizeof(xpath) - slen, "[vrf='%s']",
|
||||
VRF_DEFAULT_NAME);
|
||||
|
||||
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
|
||||
|
||||
/* Apply settings immediatly. */
|
||||
return nb_cli_apply_changes(vty, NULL);
|
||||
}
|
||||
|
||||
static void _bfd_cli_show_peer(struct vty *vty, struct lyd_node *dnode,
|
||||
bool show_defaults __attribute__((__unused__)),
|
||||
bool mhop)
|
||||
{
|
||||
const char *vrf = yang_dnode_get_string(dnode, "./vrf");
|
||||
const char *ifname = yang_dnode_get_string(dnode, "./interface");
|
||||
|
||||
vty_out(vty, " peer %s",
|
||||
yang_dnode_get_string(dnode, "./dest-addr"));
|
||||
|
||||
if (mhop)
|
||||
vty_out(vty, " multihop");
|
||||
|
||||
if (yang_dnode_exists(dnode, "./source-addr"))
|
||||
vty_out(vty, " local-address %s",
|
||||
yang_dnode_get_string(dnode, "./source-addr"));
|
||||
|
||||
if (strcmp(vrf, VRF_DEFAULT_NAME))
|
||||
vty_out(vty, " vrf %s", vrf);
|
||||
|
||||
if (ifname[0])
|
||||
vty_out(vty, " interface %s", ifname);
|
||||
|
||||
vty_out(vty, "\n");
|
||||
}
|
||||
|
||||
void bfd_cli_show_single_hop_peer(struct vty *vty,
|
||||
struct lyd_node *dnode,
|
||||
bool show_defaults)
|
||||
{
|
||||
_bfd_cli_show_peer(vty, dnode, show_defaults, false);
|
||||
}
|
||||
|
||||
void bfd_cli_show_multi_hop_peer(struct vty *vty,
|
||||
struct lyd_node *dnode,
|
||||
bool show_defaults)
|
||||
{
|
||||
_bfd_cli_show_peer(vty, dnode, show_defaults, true);
|
||||
}
|
||||
|
||||
void bfd_cli_show_peer_end(struct vty *vty,
|
||||
struct lyd_node *dnode __attribute__((__unused__)))
|
||||
{
|
||||
vty_out(vty, " !\n");
|
||||
}
|
||||
|
||||
DEFPY(
|
||||
bfd_peer_shutdown, bfd_peer_shutdown_cmd,
|
||||
"[no] shutdown",
|
||||
NO_STR
|
||||
"Disable BFD peer\n")
|
||||
{
|
||||
nb_cli_enqueue_change(vty, "./administrative-down", NB_OP_MODIFY,
|
||||
no ? "false" : "true");
|
||||
return nb_cli_apply_changes(vty, NULL);
|
||||
}
|
||||
|
||||
void bfd_cli_show_shutdown(struct vty *vty, struct lyd_node *dnode,
|
||||
bool show_defaults)
|
||||
{
|
||||
if (show_defaults)
|
||||
vty_out(vty, " shutdown\n");
|
||||
else
|
||||
vty_out(vty, " %sshutdown\n",
|
||||
yang_dnode_get_bool(dnode, NULL) ? "" : "no ");
|
||||
}
|
||||
|
||||
DEFPY(
|
||||
bfd_peer_mult, bfd_peer_mult_cmd,
|
||||
"detect-multiplier (2-255)$multiplier",
|
||||
"Configure peer detection multiplier\n"
|
||||
"Configure peer detection multiplier value\n")
|
||||
{
|
||||
nb_cli_enqueue_change(vty, "./detection-multiplier", NB_OP_MODIFY,
|
||||
multiplier_str);
|
||||
return nb_cli_apply_changes(vty, NULL);
|
||||
}
|
||||
|
||||
void bfd_cli_show_mult(struct vty *vty, struct lyd_node *dnode,
|
||||
bool show_defaults)
|
||||
{
|
||||
if (show_defaults)
|
||||
vty_out(vty, " detect-multiplier %d\n",
|
||||
BFD_DEFDETECTMULT);
|
||||
else
|
||||
vty_out(vty, " detect-multiplier %s\n",
|
||||
yang_dnode_get_string(dnode, NULL));
|
||||
}
|
||||
|
||||
DEFPY(
|
||||
bfd_peer_rx, bfd_peer_rx_cmd,
|
||||
"receive-interval (10-60000)$interval",
|
||||
"Configure peer receive interval\n"
|
||||
"Configure peer receive interval value in milliseconds\n")
|
||||
{
|
||||
char value[32];
|
||||
|
||||
snprintf(value, sizeof(value), "%ld", interval * 1000);
|
||||
nb_cli_enqueue_change(vty, "./required-receive-interval", NB_OP_MODIFY,
|
||||
value);
|
||||
|
||||
return nb_cli_apply_changes(vty, NULL);
|
||||
}
|
||||
|
||||
void bfd_cli_show_rx(struct vty *vty, struct lyd_node *dnode,
|
||||
bool show_defaults)
|
||||
{
|
||||
uint32_t value;
|
||||
|
||||
if (show_defaults)
|
||||
vty_out(vty, " receive-interval %d\n",
|
||||
BFD_DEFREQUIREDMINRX);
|
||||
else {
|
||||
value = yang_dnode_get_uint32(dnode, NULL);
|
||||
vty_out(vty, " receive-interval %" PRIu32 "\n", value / 1000);
|
||||
}
|
||||
}
|
||||
|
||||
DEFPY(
|
||||
bfd_peer_tx, bfd_peer_tx_cmd,
|
||||
"transmit-interval (10-60000)$interval",
|
||||
"Configure peer transmit interval\n"
|
||||
"Configure peer transmit interval value in milliseconds\n")
|
||||
{
|
||||
char value[32];
|
||||
|
||||
snprintf(value, sizeof(value), "%ld", interval * 1000);
|
||||
nb_cli_enqueue_change(vty, "./desired-transmission-interval",
|
||||
NB_OP_MODIFY, value);
|
||||
|
||||
return nb_cli_apply_changes(vty, NULL);
|
||||
}
|
||||
|
||||
void bfd_cli_show_tx(struct vty *vty, struct lyd_node *dnode,
|
||||
bool show_defaults)
|
||||
{
|
||||
uint32_t value;
|
||||
|
||||
if (show_defaults)
|
||||
vty_out(vty, " transmit-interval %d\n",
|
||||
BFD_DEFDESIREDMINTX);
|
||||
else {
|
||||
value = yang_dnode_get_uint32(dnode, NULL);
|
||||
vty_out(vty, " transmit-interval %" PRIu32 "\n", value / 1000);
|
||||
}
|
||||
}
|
||||
|
||||
DEFPY(
|
||||
bfd_peer_echo, bfd_peer_echo_cmd,
|
||||
"[no] echo-mode",
|
||||
NO_STR
|
||||
"Configure echo mode\n")
|
||||
{
|
||||
nb_cli_enqueue_change(vty, "./echo-mode", NB_OP_MODIFY,
|
||||
no ? "false" : "true");
|
||||
return nb_cli_apply_changes(vty, NULL);
|
||||
}
|
||||
|
||||
void bfd_cli_show_echo(struct vty *vty, struct lyd_node *dnode,
|
||||
bool show_defaults)
|
||||
{
|
||||
if (show_defaults)
|
||||
vty_out(vty, " no echo-mode\n");
|
||||
else
|
||||
vty_out(vty, " %secho-mode\n",
|
||||
yang_dnode_get_bool(dnode, NULL) ? "" : "no ");
|
||||
}
|
||||
|
||||
DEFPY(
|
||||
bfd_peer_echo_interval, bfd_peer_echo_interval_cmd,
|
||||
"echo-interval (10-60000)$interval",
|
||||
"Configure peer echo interval\n"
|
||||
"Configure peer echo interval value in milliseconds\n")
|
||||
{
|
||||
char value[32];
|
||||
|
||||
snprintf(value, sizeof(value), "%ld", interval * 1000);
|
||||
nb_cli_enqueue_change(vty, "./desired-echo-transmission-interval",
|
||||
NB_OP_MODIFY, value);
|
||||
|
||||
return nb_cli_apply_changes(vty, NULL);
|
||||
}
|
||||
|
||||
void bfd_cli_show_echo_interval(struct vty *vty, struct lyd_node *dnode,
|
||||
bool show_defaults)
|
||||
{
|
||||
uint32_t value;
|
||||
|
||||
if (show_defaults)
|
||||
vty_out(vty, " echo-interval %d\n",
|
||||
BFD_DEF_REQ_MIN_ECHO);
|
||||
else {
|
||||
value = yang_dnode_get_uint32(dnode, NULL);
|
||||
vty_out(vty, " echo-interval %" PRIu32 "\n", value / 1000);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bfdd_cli_init(void)
|
||||
{
|
||||
install_element(CONFIG_NODE, &bfd_enter_cmd);
|
||||
install_element(CONFIG_NODE, &bfd_config_reset_cmd);
|
||||
|
||||
install_element(BFD_NODE, &bfd_peer_enter_cmd);
|
||||
install_element(BFD_NODE, &bfd_no_peer_cmd);
|
||||
|
||||
install_element(BFD_PEER_NODE, &bfd_peer_shutdown_cmd);
|
||||
install_element(BFD_PEER_NODE, &bfd_peer_mult_cmd);
|
||||
install_element(BFD_PEER_NODE, &bfd_peer_rx_cmd);
|
||||
install_element(BFD_PEER_NODE, &bfd_peer_tx_cmd);
|
||||
install_element(BFD_PEER_NODE, &bfd_peer_echo_cmd);
|
||||
install_element(BFD_PEER_NODE, &bfd_peer_echo_interval_cmd);
|
||||
}
|
1210
bfdd/bfdd_northbound.c
Normal file
1210
bfdd/bfdd_northbound.c
Normal file
File diff suppressed because it is too large
Load Diff
395
bfdd/bfdd_vty.c
395
bfdd/bfdd_vty.c
@ -23,6 +23,7 @@
|
||||
#include "lib/command.h"
|
||||
#include "lib/json.h"
|
||||
#include "lib/log.h"
|
||||
#include "lib/northbound_cli.h"
|
||||
#include "lib/vty.h"
|
||||
|
||||
#include "bfd.h"
|
||||
@ -34,8 +35,6 @@
|
||||
/*
|
||||
* 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"
|
||||
@ -43,16 +42,10 @@
|
||||
#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 vty *vty, struct bfd_session *bs);
|
||||
static void _bfdd_peer_write_config_iter(struct hash_bucket *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,
|
||||
@ -79,286 +72,6 @@ _find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv,
|
||||
const char *local_str, const char *ifname,
|
||||
const char *vrfname);
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG)) {
|
||||
if (bs->refcount)
|
||||
vty_out(vty, "%% session peer is now configurable via bfd daemon.\n");
|
||||
BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG);
|
||||
}
|
||||
|
||||
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);
|
||||
if (bs->detect_mult == multiplier)
|
||||
return CMD_SUCCESS;
|
||||
|
||||
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);
|
||||
if (bs->timers.required_min_rx == (uint32_t)(interval * 1000))
|
||||
return CMD_SUCCESS;
|
||||
|
||||
bs->timers.required_min_rx = interval * 1000;
|
||||
bfd_set_polling(bs);
|
||||
|
||||
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);
|
||||
if (bs->timers.desired_min_tx == (uint32_t)(interval * 1000))
|
||||
return CMD_SUCCESS;
|
||||
|
||||
bs->timers.desired_min_tx = interval * 1000;
|
||||
bfd_set_polling(bs);
|
||||
|
||||
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);
|
||||
if (bs->timers.required_min_echo == (uint32_t)(interval * 1000))
|
||||
return CMD_SUCCESS;
|
||||
|
||||
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);
|
||||
} 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))
|
||||
bs_echo_timer_handler(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_sess_del(&bpc) != 0) {
|
||||
vty_out(vty, "%% Failed to remove peer.\n");
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Show commands helper functions
|
||||
@ -956,12 +669,6 @@ static int bfd_configure_peer(struct bfd_peer_cfg *bpc, bool mhop,
|
||||
|
||||
/* 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)) {
|
||||
@ -982,60 +689,6 @@ static int bfd_configure_peer(struct bfd_peer_cfg *bpc, bool mhop,
|
||||
|
||||
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 vty *vty, struct bfd_session *bs)
|
||||
{
|
||||
char addr_buf[INET6_ADDRSTRLEN];
|
||||
|
||||
vty_out(vty, " peer %s",
|
||||
inet_ntop(bs->key.family, &bs->key.peer, addr_buf,
|
||||
sizeof(addr_buf)));
|
||||
|
||||
if (bs->key.mhop)
|
||||
vty_out(vty, " multihop");
|
||||
|
||||
if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local)))
|
||||
vty_out(vty, " local-address %s",
|
||||
inet_ntop(bs->key.family, &bs->key.local, addr_buf,
|
||||
sizeof(addr_buf)));
|
||||
|
||||
if (bs->key.vrfname[0])
|
||||
vty_out(vty, " vrf %s", bs->key.vrfname);
|
||||
if (bs->key.ifname[0])
|
||||
vty_out(vty, " interface %s", bs->key.ifname);
|
||||
vty_out(vty, "\n");
|
||||
|
||||
if (bs->sock == -1)
|
||||
vty_out(vty,
|
||||
" ! vrf, interface or local-address doesn't exist\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");
|
||||
}
|
||||
|
||||
DEFUN_NOSH(show_debugging_bfd,
|
||||
show_debugging_bfd_cmd,
|
||||
@ -1049,24 +702,6 @@ DEFUN_NOSH(show_debugging_bfd,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static void _bfdd_peer_write_config_iter(struct hash_bucket *hb, void *arg)
|
||||
{
|
||||
struct vty *vty = arg;
|
||||
struct bfd_session *bs = hb->data;
|
||||
|
||||
if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG))
|
||||
return;
|
||||
|
||||
_bfdd_peer_write_config(vty, bs);
|
||||
}
|
||||
|
||||
static int bfdd_peer_write_config(struct vty *vty)
|
||||
{
|
||||
bfd_id_iterate(_bfdd_peer_write_config_iter, vty);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct cmd_node bfd_node = {
|
||||
BFD_NODE,
|
||||
"%s(config-bfd)# ",
|
||||
@ -1079,29 +714,35 @@ struct cmd_node bfd_peer_node = {
|
||||
1,
|
||||
};
|
||||
|
||||
static int bfdd_write_config(struct vty *vty)
|
||||
{
|
||||
struct lyd_node *dnode;
|
||||
int written = 0;
|
||||
|
||||
dnode = yang_dnode_get(running_config->dnode, "/frr-bfdd:bfdd");
|
||||
if (dnode) {
|
||||
nb_cli_show_dnode_cmds(vty, dnode, false);
|
||||
written = 1;
|
||||
}
|
||||
|
||||
return written;
|
||||
}
|
||||
|
||||
void bfdd_vty_init(void)
|
||||
{
|
||||
install_element(ENABLE_NODE, &bfd_show_peers_counters_cmd);
|
||||
install_element(ENABLE_NODE, &bfd_show_peer_counters_cmd);
|
||||
install_element(ENABLE_NODE, &bfd_show_peers_cmd);
|
||||
install_element(ENABLE_NODE, &bfd_show_peer_cmd);
|
||||
install_element(CONFIG_NODE, &bfd_enter_cmd);
|
||||
install_element(ENABLE_NODE, &show_debugging_bfd_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_node(&bfd_peer_node, NULL);
|
||||
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);
|
||||
|
||||
bfdd_cli_init();
|
||||
}
|
||||
|
@ -7,12 +7,15 @@ noinst_LIBRARIES += bfdd/libbfd.a
|
||||
sbin_PROGRAMS += bfdd/bfdd
|
||||
dist_examples_DATA += bfdd/bfdd.conf.sample
|
||||
vtysh_scan += $(top_srcdir)/bfdd/bfdd_vty.c
|
||||
vtysh_scan += $(top_srcdir)/bfdd/bfdd_cli.c
|
||||
man8 += $(MANBUILD)/bfdd.8
|
||||
endif
|
||||
|
||||
bfdd_libbfd_a_SOURCES = \
|
||||
bfdd/bfd.c \
|
||||
bfdd/bfdd_northbound.c \
|
||||
bfdd/bfdd_vty.c \
|
||||
bfdd/bfdd_cli.c \
|
||||
bfdd/bfd_packet.c \
|
||||
bfdd/config.c \
|
||||
bfdd/control.c \
|
||||
@ -24,10 +27,17 @@ bfdd_libbfd_a_SOURCES = \
|
||||
bfdd/bfdd_vty_clippy.c: $(CLIPPY_DEPS)
|
||||
bfdd/bfdd_vty.$(OBJEXT): bfdd/bfdd_vty_clippy.c
|
||||
|
||||
bfdd/bfdd_cli_clippy.c: $(CLIPPY_DEPS)
|
||||
bfdd/bfdd_cli.$(OBJEXT): bfdd/bfdd_cli_clippy.c
|
||||
|
||||
noinst_HEADERS += \
|
||||
bfdd/bfdctl.h \
|
||||
bfdd/bfd.h \
|
||||
# end
|
||||
|
||||
nodist_bfdd_bfdd_SOURCES = \
|
||||
yang/frr-bfdd.yang.c \
|
||||
# end
|
||||
|
||||
bfdd_bfdd_SOURCES = bfdd/bfdd.c
|
||||
bfdd_bfdd_LDADD = bfdd/libbfd.a lib/libfrr.la
|
||||
|
@ -337,6 +337,27 @@ struct nb_callbacks {
|
||||
*/
|
||||
void (*cli_show)(struct vty *vty, struct lyd_node *dnode,
|
||||
bool show_defaults);
|
||||
|
||||
/*
|
||||
* Optional callback to show the CLI node end for lists or containers.
|
||||
*
|
||||
* vty
|
||||
* The vty terminal to dump the configuration to.
|
||||
*
|
||||
* dnode
|
||||
* libyang data node that should be shown in the form of a CLI
|
||||
* command.
|
||||
*
|
||||
* show_defaults
|
||||
* Specify whether to display default configuration values or not.
|
||||
* This parameter can be ignored most of the time since the
|
||||
* northbound doesn't call this callback for default leaves or
|
||||
* non-presence containers that contain only default child nodes.
|
||||
* The exception are commands associated to multiple configuration
|
||||
* nodes, in which case it might be desirable to hide one or more
|
||||
* parts of the command when this parameter is set to false.
|
||||
*/
|
||||
void (*cli_show_end)(struct vty *vty, struct lyd_node *dnode);
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -434,10 +434,29 @@ static int nb_cli_candidate_load_transaction(struct vty *vty,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* ly_iter_next_is_up: detects when iterating up on the yang model.
|
||||
*
|
||||
* This function detects whether next node in the iteration is upwards,
|
||||
* then return the node otherwise return NULL.
|
||||
*/
|
||||
static struct lyd_node *ly_iter_next_up(const struct lyd_node *elem)
|
||||
{
|
||||
/* Are we going downwards? Is this still not a leaf? */
|
||||
if (!(elem->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)))
|
||||
return NULL;
|
||||
|
||||
/* Are there still leaves in this branch? */
|
||||
if (elem->next != NULL)
|
||||
return NULL;
|
||||
|
||||
return elem->parent;
|
||||
}
|
||||
|
||||
void nb_cli_show_dnode_cmds(struct vty *vty, struct lyd_node *root,
|
||||
bool with_defaults)
|
||||
{
|
||||
struct lyd_node *next, *child;
|
||||
struct lyd_node *next, *child, *parent;
|
||||
|
||||
LY_TREE_DFS_BEGIN (root, next, child) {
|
||||
struct nb_node *nb_node;
|
||||
@ -452,6 +471,19 @@ void nb_cli_show_dnode_cmds(struct vty *vty, struct lyd_node *root,
|
||||
|
||||
(*nb_node->cbs.cli_show)(vty, child, with_defaults);
|
||||
next:
|
||||
/*
|
||||
* When transiting upwards in the yang model we should
|
||||
* give the previous container/list node a chance to
|
||||
* print its close vty output (e.g. "!" or "end-family"
|
||||
* etc...).
|
||||
*/
|
||||
parent = ly_iter_next_up(child);
|
||||
if (parent != NULL) {
|
||||
nb_node = parent->schema->priv;
|
||||
if (nb_node->cbs.cli_show_end)
|
||||
(*nb_node->cbs.cli_show_end)(vty, parent);
|
||||
}
|
||||
|
||||
LY_TREE_DFS_END(root, next, child);
|
||||
}
|
||||
}
|
||||
|
387
yang/frr-bfdd.yang
Normal file
387
yang/frr-bfdd.yang
Normal file
@ -0,0 +1,387 @@
|
||||
module frr-bfdd {
|
||||
yang-version 1.1;
|
||||
namespace "http://frrouting.org/yang/bfdd";
|
||||
prefix frr-bfdd;
|
||||
|
||||
import ietf-inet-types {
|
||||
prefix inet;
|
||||
}
|
||||
import ietf-yang-types {
|
||||
prefix yang;
|
||||
}
|
||||
import frr-interface {
|
||||
prefix frr-interface;
|
||||
}
|
||||
import frr-route-types {
|
||||
prefix frr-route-types;
|
||||
}
|
||||
|
||||
organization "Free Range Routing";
|
||||
contact
|
||||
"FRR Users List: <mailto:frog@lists.frrouting.org>
|
||||
FRR Development List: <mailto:dev@lists.frrouting.org>";
|
||||
description
|
||||
"This module defines a model for managing FRR bfdd daemon.";
|
||||
|
||||
revision 2019-05-09 {
|
||||
description "Initial revision.";
|
||||
reference
|
||||
"RFC 5880: Bidirectional Forwarding Detection (BFD).
|
||||
RFC 5881: Bidirectional Forwarding Detection (BFD)
|
||||
for IPv4 and IPv6 (Single Hop).
|
||||
RFC 5882: Bidirectional Forwarding Detection (BFD) for Multihop Paths.";
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* BFD types declaration.
|
||||
*/
|
||||
typedef multiplier {
|
||||
description "Detection multiplier";
|
||||
type uint8 {
|
||||
range 2..255;
|
||||
}
|
||||
}
|
||||
|
||||
typedef discriminator {
|
||||
description "BFD session identification";
|
||||
type uint32 {
|
||||
range 1..4294967295;
|
||||
}
|
||||
}
|
||||
|
||||
typedef state {
|
||||
description "BFD session state";
|
||||
type enumeration {
|
||||
enum admin-down {
|
||||
value 0;
|
||||
description "Administratively down";
|
||||
}
|
||||
enum down {
|
||||
value 1;
|
||||
description "Down";
|
||||
}
|
||||
enum init {
|
||||
value 2;
|
||||
description "Initializing";
|
||||
}
|
||||
enum up {
|
||||
value 3;
|
||||
description "Up";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef diagnostic {
|
||||
description "BFD session diagnostic";
|
||||
type enumeration {
|
||||
enum ok {
|
||||
value 0;
|
||||
description "Ok";
|
||||
}
|
||||
enum control-expired {
|
||||
value 1;
|
||||
description "Control timer expired";
|
||||
}
|
||||
enum echo-failed {
|
||||
value 2;
|
||||
description "Echo function failed";
|
||||
}
|
||||
enum neighbor-down {
|
||||
value 3;
|
||||
description "Neighbor signaled session down";
|
||||
}
|
||||
enum forwarding-reset {
|
||||
value 4;
|
||||
description "Forwarding plane reset";
|
||||
}
|
||||
enum path-down {
|
||||
value 5;
|
||||
description "Path down";
|
||||
}
|
||||
enum concatenated-path-down {
|
||||
value 6;
|
||||
description "Concatenated path down";
|
||||
}
|
||||
enum administratively-down {
|
||||
value 7;
|
||||
description "Administratively down";
|
||||
}
|
||||
enum reverse-concat-path-down {
|
||||
value 8;
|
||||
description "Reverse concatenated path down";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Shared BFD items.
|
||||
*/
|
||||
grouping session-common {
|
||||
description "Common BFD session settings";
|
||||
|
||||
leaf detection-multiplier {
|
||||
type multiplier;
|
||||
default 3;
|
||||
description "Local session detection multiplier";
|
||||
}
|
||||
|
||||
leaf desired-transmission-interval {
|
||||
type uint32;
|
||||
units microseconds;
|
||||
default 300000;
|
||||
description "Minimum desired control packet transmission interval";
|
||||
}
|
||||
|
||||
leaf required-receive-interval {
|
||||
type uint32;
|
||||
units microseconds;
|
||||
default 300000;
|
||||
description "Minimum required control packet receive interval";
|
||||
}
|
||||
|
||||
leaf administrative-down {
|
||||
type boolean;
|
||||
default true;
|
||||
description "Disables or enables the session administratively";
|
||||
}
|
||||
}
|
||||
|
||||
grouping session-echo {
|
||||
description "BFD session echo settings";
|
||||
|
||||
leaf echo-mode {
|
||||
type boolean;
|
||||
default false;
|
||||
description "Use echo packets to detect failures";
|
||||
}
|
||||
|
||||
leaf desired-echo-transmission-interval {
|
||||
type uint32;
|
||||
units microseconds;
|
||||
default 50000;
|
||||
description "Minimum desired control packet transmission interval";
|
||||
}
|
||||
}
|
||||
|
||||
grouping session-states {
|
||||
/*
|
||||
* Local settings.
|
||||
*/
|
||||
leaf local-discriminator {
|
||||
type discriminator;
|
||||
description "Local session identifier";
|
||||
}
|
||||
|
||||
leaf local-state {
|
||||
type state;
|
||||
description "Local session state";
|
||||
}
|
||||
|
||||
leaf local-diagnostic {
|
||||
type diagnostic;
|
||||
description "Local session diagnostic";
|
||||
}
|
||||
|
||||
leaf local-multiplier {
|
||||
type multiplier;
|
||||
description "Local session current multiplier";
|
||||
}
|
||||
|
||||
/*
|
||||
* Remote settings.
|
||||
*/
|
||||
leaf remote-discriminator {
|
||||
type discriminator;
|
||||
description "Remote session identifier";
|
||||
}
|
||||
|
||||
leaf remote-state {
|
||||
type state;
|
||||
description "Remote session state";
|
||||
}
|
||||
|
||||
leaf remote-diagnostic {
|
||||
type diagnostic;
|
||||
description "Local session diagnostic";
|
||||
}
|
||||
|
||||
leaf remote-multiplier {
|
||||
type multiplier;
|
||||
description "Remote session detection multiplier";
|
||||
}
|
||||
|
||||
/*
|
||||
* Negotiated settings.
|
||||
*/
|
||||
leaf negotiated-transmission-interval {
|
||||
description "Negotiated transmit interval";
|
||||
type uint32;
|
||||
units microseconds;
|
||||
}
|
||||
|
||||
leaf negotiated-receive-interval {
|
||||
description "Negotiated receive interval";
|
||||
type uint32;
|
||||
units microseconds;
|
||||
}
|
||||
|
||||
leaf detection-mode {
|
||||
description "Detection mode";
|
||||
|
||||
type enumeration {
|
||||
enum async-with-echo {
|
||||
value "1";
|
||||
description "Async with echo";
|
||||
}
|
||||
enum async-without-echo {
|
||||
value "2";
|
||||
description "Async without echo";
|
||||
}
|
||||
enum demand-with-echo {
|
||||
value "3";
|
||||
description "Demand with echo";
|
||||
}
|
||||
enum demand-without-echo {
|
||||
value "4";
|
||||
description "Demand without echo";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Statistics.
|
||||
*/
|
||||
leaf last-down-time {
|
||||
type yang:date-and-time;
|
||||
description "Time and date of the last time session was down";
|
||||
}
|
||||
|
||||
leaf last-up-time {
|
||||
type yang:date-and-time;
|
||||
description "Time and date of the last time session was up";
|
||||
}
|
||||
|
||||
leaf session-down-count {
|
||||
type uint32;
|
||||
description "Amount of times the session went down";
|
||||
}
|
||||
|
||||
leaf session-up-count {
|
||||
type uint32;
|
||||
description "Amount of times the session went up";
|
||||
}
|
||||
|
||||
leaf control-packet-input-count {
|
||||
type uint64;
|
||||
description "Amount of control packets received";
|
||||
}
|
||||
|
||||
leaf control-packet-output-count {
|
||||
type uint64;
|
||||
description "Amount of control packets sent";
|
||||
}
|
||||
|
||||
/*
|
||||
* Echo mode operational data.
|
||||
*/
|
||||
leaf negotiated-echo-transmission-interval {
|
||||
type uint32;
|
||||
units microseconds;
|
||||
description "Negotiated echo transmit interval";
|
||||
}
|
||||
|
||||
/*
|
||||
* Statistics.
|
||||
*/
|
||||
leaf echo-packet-input-count {
|
||||
type uint64;
|
||||
description "Amount of echo packets received";
|
||||
}
|
||||
|
||||
leaf echo-packet-output-count {
|
||||
type uint64;
|
||||
description "Amount of echo packets sent";
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* BFD operational.
|
||||
*/
|
||||
container bfdd {
|
||||
container bfd {
|
||||
presence "Present if the BFD protocol is enabled";
|
||||
|
||||
container sessions {
|
||||
list single-hop {
|
||||
key "dest-addr interface vrf";
|
||||
description "List of single hop sessions";
|
||||
|
||||
leaf dest-addr {
|
||||
type inet:ip-address;
|
||||
description "IP address of the peer";
|
||||
}
|
||||
|
||||
leaf interface {
|
||||
type string {
|
||||
length "0..16";
|
||||
}
|
||||
description "Interface to use to contact peer";
|
||||
}
|
||||
|
||||
leaf vrf {
|
||||
type string;
|
||||
description "Virtual Routing Domain name";
|
||||
}
|
||||
|
||||
leaf source-addr {
|
||||
type inet:ip-address;
|
||||
description "Local IP address";
|
||||
}
|
||||
|
||||
uses session-common;
|
||||
uses session-echo;
|
||||
|
||||
container stats {
|
||||
uses session-states;
|
||||
config false;
|
||||
}
|
||||
}
|
||||
|
||||
list multi-hop {
|
||||
key "source-addr dest-addr interface vrf";
|
||||
description "List of multi hop sessions";
|
||||
|
||||
leaf source-addr {
|
||||
type inet:ip-address;
|
||||
description "Local IP address";
|
||||
}
|
||||
|
||||
leaf dest-addr {
|
||||
type inet:ip-address;
|
||||
description "IP address of the peer";
|
||||
}
|
||||
|
||||
leaf interface {
|
||||
type string {
|
||||
length "0..16";
|
||||
}
|
||||
description "Interface to use to contact peer";
|
||||
}
|
||||
|
||||
leaf vrf {
|
||||
type string;
|
||||
description "Virtual Routing Domain name";
|
||||
}
|
||||
|
||||
uses session-common;
|
||||
|
||||
container stats {
|
||||
uses session-states;
|
||||
config false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -24,6 +24,10 @@ dist_yangmodels_DATA += yang/frr-test-module.yang
|
||||
dist_yangmodels_DATA += yang/frr-interface.yang
|
||||
dist_yangmodels_DATA += yang/frr-route-types.yang
|
||||
|
||||
if BFDD
|
||||
dist_yangmodels_DATA += yang/frr-bfdd.yang
|
||||
endif
|
||||
|
||||
if RIPD
|
||||
dist_yangmodels_DATA += yang/frr-ripd.yang
|
||||
endif
|
||||
|
Loading…
Reference in New Issue
Block a user