Merge pull request #4437 from opensourcerouting/bfdd-northbound

bfdd: migrate to northbound
This commit is contained in:
Russ White 2019-07-09 11:15:51 -04:00 committed by GitHub
commit af13de0af6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 2282 additions and 409 deletions

View File

@ -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);

View File

@ -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_ */

View File

@ -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
View 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

File diff suppressed because it is too large Load Diff

View File

@ -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();
}

View File

@ -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

View File

@ -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);
};
/*

View File

@ -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
View 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;
}
}
}
}
}
}

View File

@ -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