mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-07 13:13:08 +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_CONFIG, "long-lived configuration memory")
|
||||||
DEFINE_MTYPE_STATIC(BFDD, BFDD_SESSION_OBSERVER, "Session observer")
|
DEFINE_MTYPE_STATIC(BFDD, BFDD_SESSION_OBSERVER, "Session observer")
|
||||||
DEFINE_MTYPE_STATIC(BFDD, BFDD_VRF, "BFD VRF")
|
DEFINE_MTYPE_STATIC(BFDD, BFDD_VRF, "BFD VRF")
|
||||||
DEFINE_QOBJ_TYPE(bfd_session)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prototypes
|
* 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 uint32_t ptm_bfd_gen_ID(void);
|
||||||
static void ptm_bfd_echo_xmt_TO(struct bfd_session *bfd);
|
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,
|
static struct bfd_session *bfd_find_disc(struct sockaddr_any *sa,
|
||||||
uint32_t ldisc);
|
uint32_t ldisc);
|
||||||
static int bfd_session_update(struct bfd_session *bs, struct bfd_peer_cfg *bpc);
|
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));
|
strlcpy(key->ifname, ifname, sizeof(key->ifname));
|
||||||
if (vrfname && vrfname[0])
|
if (vrfname && vrfname[0])
|
||||||
strlcpy(key->vrfname, vrfname, sizeof(key->vrfname));
|
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)
|
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. */
|
/* Search for session without using discriminator. */
|
||||||
ifp = if_lookup_by_index(ifindex, vrfid);
|
ifp = if_lookup_by_index(ifindex, vrfid);
|
||||||
if (vrfid == VRF_DEFAULT) {
|
if (vrfid != VRF_DEFAULT)
|
||||||
/*
|
|
||||||
* Don't use the default vrf, otherwise we won't find
|
|
||||||
* sessions that doesn't specify it.
|
|
||||||
*/
|
|
||||||
vrf = NULL;
|
|
||||||
} else
|
|
||||||
vrf = vrf_lookup_by_id(vrfid);
|
vrf = vrf_lookup_by_id(vrfid);
|
||||||
|
else
|
||||||
|
vrf = NULL;
|
||||||
|
|
||||||
gen_bfd_key(&key, peer, local, is_mhop, ifp ? ifp->name : 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. */
|
/* XXX maybe remoteDiscr should be checked for remoteHeard cases. */
|
||||||
return bfd_key_lookup(key);
|
return bfd_key_lookup(key);
|
||||||
@ -469,14 +460,12 @@ int bfd_echo_recvtimer_cb(struct thread *t)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct bfd_session *bfd_session_new(void)
|
struct bfd_session *bfd_session_new(void)
|
||||||
{
|
{
|
||||||
struct bfd_session *bs;
|
struct bfd_session *bs;
|
||||||
|
|
||||||
bs = XCALLOC(MTYPE_BFDD_CONFIG, sizeof(*bs));
|
bs = XCALLOC(MTYPE_BFDD_CONFIG, sizeof(*bs));
|
||||||
|
|
||||||
QOBJ_REG(bs, bfd_session);
|
|
||||||
|
|
||||||
bs->timers.desired_min_tx = BFD_DEFDESIREDMINTX;
|
bs->timers.desired_min_tx = BFD_DEFDESIREDMINTX;
|
||||||
bs->timers.required_min_rx = BFD_DEFREQUIREDMINRX;
|
bs->timers.required_min_rx = BFD_DEFREQUIREDMINRX;
|
||||||
bs->timers.required_min_echo = BFD_DEF_REQ_MIN_ECHO;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bfd_session_free(struct bfd_session *bs)
|
void bfd_session_free(struct bfd_session *bs)
|
||||||
{
|
{
|
||||||
struct bfd_session_observer *bso;
|
struct bfd_session_observer *bso;
|
||||||
|
|
||||||
@ -650,7 +639,6 @@ static void bfd_session_free(struct bfd_session *bs)
|
|||||||
|
|
||||||
pl_free(bs->pl);
|
pl_free(bs->pl);
|
||||||
|
|
||||||
QOBJ_UNREG(bs);
|
|
||||||
XFREE(MTYPE_BFDD_CONFIG, 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)
|
if (bpc->bpc_has_vrfname)
|
||||||
strlcpy(bfd->key.vrfname, bpc->bpc_vrfname,
|
strlcpy(bfd->key.vrfname, bpc->bpc_vrfname,
|
||||||
sizeof(bfd->key.vrfname));
|
sizeof(bfd->key.vrfname));
|
||||||
|
else
|
||||||
|
strlcpy(bfd->key.vrfname, VRF_DEFAULT_NAME,
|
||||||
|
sizeof(bfd->key.vrfname));
|
||||||
|
|
||||||
/* Copy remaining data. */
|
/* Copy remaining data. */
|
||||||
if (bpc->bpc_ipv4 == false)
|
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;
|
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. */
|
/* Registrate session into data structures. */
|
||||||
bfd_key_insert(bfd);
|
bfd_key_insert(bfd);
|
||||||
bfd->discrs.my_discr = ptm_bfd_gen_ID();
|
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)
|
if (bfd->key.ifname[0] || bfd->key.vrfname[0] || bfd->sock == -1)
|
||||||
bs_observer_add(bfd);
|
bs_observer_add(bfd);
|
||||||
|
|
||||||
/* Apply other configurations. */
|
|
||||||
_bfd_session_update(bfd, bpc);
|
|
||||||
|
|
||||||
log_info("session-new: %s", bs_to_string(bfd));
|
log_info("session-new: %s", bs_to_string(bfd));
|
||||||
|
|
||||||
control_notify_config(BCM_NOTIFY_CONFIG_ADD, bfd);
|
control_notify_config(BCM_NOTIFY_CONFIG_ADD, bfd);
|
||||||
@ -1342,9 +1341,10 @@ struct bfd_key_walk_partial_lookup {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* ignore some parameters */
|
/* 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_key_walk_partial_lookup *)data;
|
||||||
struct bfd_session *given = ctx->given;
|
struct bfd_session *given = ctx->given;
|
||||||
struct bfd_session *parsed = b->data;
|
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;
|
return HASHWALK_CONTINUE;
|
||||||
if (given->key.mhop != parsed->key.mhop)
|
if (given->key.mhop != parsed->key.mhop)
|
||||||
return HASHWALK_CONTINUE;
|
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;
|
return HASHWALK_CONTINUE;
|
||||||
if (memcmp(given->key.vrfname, parsed->key.vrfname, MAXNAMELEN))
|
if (memcmp(given->key.vrfname, parsed->key.vrfname, MAXNAMELEN))
|
||||||
return HASHWALK_CONTINUE;
|
return HASHWALK_CONTINUE;
|
||||||
@ -1531,6 +1532,94 @@ void bfd_shutdown(void)
|
|||||||
hash_free(bfd_key_hash);
|
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)
|
static int bfd_vrf_new(struct vrf *vrf)
|
||||||
{
|
{
|
||||||
log_debug("VRF Created: %s(%u)", vrf->name, vrf->vrf_id);
|
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;
|
struct bfd_timers remote_timers;
|
||||||
|
|
||||||
uint64_t refcount; /* number of pointers referencing this. */
|
uint64_t refcount; /* number of pointers referencing this. */
|
||||||
|
|
||||||
/* VTY context data. */
|
|
||||||
QOBJ_FIELDS
|
|
||||||
};
|
};
|
||||||
DECLARE_QOBJ_TYPE(bfd_session)
|
|
||||||
|
|
||||||
struct peer_label {
|
struct peer_label {
|
||||||
TAILQ_ENTRY(peer_label) pl_entry;
|
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 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 */
|
/* BFD hash data structures interface */
|
||||||
void bfd_initialize(void);
|
void bfd_initialize(void);
|
||||||
void bfd_shutdown(void);
|
void bfd_shutdown(void);
|
||||||
@ -584,6 +590,37 @@ extern struct in6_addr zero_addr;
|
|||||||
void bfdd_vty_init(void);
|
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
|
* ptm_adapter.c
|
||||||
*/
|
*/
|
||||||
@ -596,4 +633,12 @@ void bfdd_sessions_disable_vrf(struct vrf *vrf);
|
|||||||
|
|
||||||
int ptm_bfd_notify(struct bfd_session *bs);
|
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_ */
|
#endif /* _BFD_H_ */
|
||||||
|
24
bfdd/bfdd.c
24
bfdd/bfdd.c
@ -39,6 +39,9 @@ struct thread_master *master;
|
|||||||
/* BFDd privileges */
|
/* BFDd privileges */
|
||||||
static zebra_capabilities_t _caps_p[] = {ZCAP_BIND, ZCAP_SYS_ADMIN, ZCAP_NET_RAW};
|
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)
|
void socket_close(int *s)
|
||||||
{
|
{
|
||||||
if (*s <= 0)
|
if (*s <= 0)
|
||||||
@ -78,6 +81,14 @@ static void sigterm_handler(void)
|
|||||||
exit(0);
|
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[] = {
|
static struct quagga_signal_t bfd_signals[] = {
|
||||||
{
|
{
|
||||||
.signal = SIGUSR1,
|
.signal = SIGUSR1,
|
||||||
@ -91,12 +102,23 @@ static struct quagga_signal_t bfd_signals[] = {
|
|||||||
.signal = SIGINT,
|
.signal = SIGINT,
|
||||||
.handler = &sigterm_handler,
|
.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,
|
FRR_DAEMON_INFO(bfdd, BFD, .vty_port = 2617,
|
||||||
.proghelp = "Implementation of the BFD protocol.",
|
.proghelp = "Implementation of the BFD protocol.",
|
||||||
.signals = bfd_signals, .n_signals = array_size(bfd_signals),
|
.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
|
#define OPTION_CTLSOCK 1001
|
||||||
static struct option longopts[] = {
|
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/command.h"
|
||||||
#include "lib/json.h"
|
#include "lib/json.h"
|
||||||
#include "lib/log.h"
|
#include "lib/log.h"
|
||||||
|
#include "lib/northbound_cli.h"
|
||||||
#include "lib/vty.h"
|
#include "lib/vty.h"
|
||||||
|
|
||||||
#include "bfd.h"
|
#include "bfd.h"
|
||||||
@ -34,8 +35,6 @@
|
|||||||
/*
|
/*
|
||||||
* Commands help string definitions.
|
* 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_IPV4_STR "IPv4 peer address\n"
|
||||||
#define PEER_IPV6_STR "IPv6 peer address\n"
|
#define PEER_IPV6_STR "IPv6 peer address\n"
|
||||||
#define MHOP_STR "Configure multihop\n"
|
#define MHOP_STR "Configure multihop\n"
|
||||||
@ -43,16 +42,10 @@
|
|||||||
#define LOCAL_IPV4_STR "IPv4 local address\n"
|
#define LOCAL_IPV4_STR "IPv4 local address\n"
|
||||||
#define LOCAL_IPV6_STR "IPv6 local address\n"
|
#define LOCAL_IPV6_STR "IPv6 local address\n"
|
||||||
#define LOCAL_INTF_STR "Configure local interface name to use\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
|
* 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,
|
static int bfd_configure_peer(struct bfd_peer_cfg *bpc, bool mhop,
|
||||||
const struct sockaddr_any *peer,
|
const struct sockaddr_any *peer,
|
||||||
const struct sockaddr_any *local,
|
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 *local_str, const char *ifname,
|
||||||
const char *vrfname);
|
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
|
* Show commands helper functions
|
||||||
@ -956,12 +669,6 @@ static int bfd_configure_peer(struct bfd_peer_cfg *bpc, bool mhop,
|
|||||||
|
|
||||||
/* Handle interface specification configuration. */
|
/* Handle interface specification configuration. */
|
||||||
if (ifname) {
|
if (ifname) {
|
||||||
if (bpc->bpc_mhop) {
|
|
||||||
snprintf(ebuf, ebuflen,
|
|
||||||
"multihop doesn't accept interface names");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bpc->bpc_has_localif = true;
|
bpc->bpc_has_localif = true;
|
||||||
if (strlcpy(bpc->bpc_localif, ifname, sizeof(bpc->bpc_localif))
|
if (strlcpy(bpc->bpc_localif, ifname, sizeof(bpc->bpc_localif))
|
||||||
> 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;
|
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,
|
DEFUN_NOSH(show_debugging_bfd,
|
||||||
show_debugging_bfd_cmd,
|
show_debugging_bfd_cmd,
|
||||||
@ -1049,24 +702,6 @@ DEFUN_NOSH(show_debugging_bfd,
|
|||||||
return CMD_SUCCESS;
|
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 = {
|
struct cmd_node bfd_node = {
|
||||||
BFD_NODE,
|
BFD_NODE,
|
||||||
"%s(config-bfd)# ",
|
"%s(config-bfd)# ",
|
||||||
@ -1079,29 +714,35 @@ struct cmd_node bfd_peer_node = {
|
|||||||
1,
|
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)
|
void bfdd_vty_init(void)
|
||||||
{
|
{
|
||||||
install_element(ENABLE_NODE, &bfd_show_peers_counters_cmd);
|
install_element(ENABLE_NODE, &bfd_show_peers_counters_cmd);
|
||||||
install_element(ENABLE_NODE, &bfd_show_peer_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_peers_cmd);
|
||||||
install_element(ENABLE_NODE, &bfd_show_peer_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_element(ENABLE_NODE, &show_debugging_bfd_cmd);
|
||||||
|
|
||||||
/* Install BFD node and commands. */
|
/* Install BFD node and commands. */
|
||||||
install_node(&bfd_node, bfdd_write_config);
|
install_node(&bfd_node, bfdd_write_config);
|
||||||
install_default(BFD_NODE);
|
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 BFD peer node. */
|
||||||
install_node(&bfd_peer_node, bfdd_peer_write_config);
|
install_node(&bfd_peer_node, NULL);
|
||||||
install_default(BFD_PEER_NODE);
|
install_default(BFD_PEER_NODE);
|
||||||
install_element(BFD_PEER_NODE, &bfd_peer_detectmultiplier_cmd);
|
|
||||||
install_element(BFD_PEER_NODE, &bfd_peer_recvinterval_cmd);
|
bfdd_cli_init();
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
@ -7,12 +7,15 @@ noinst_LIBRARIES += bfdd/libbfd.a
|
|||||||
sbin_PROGRAMS += bfdd/bfdd
|
sbin_PROGRAMS += bfdd/bfdd
|
||||||
dist_examples_DATA += bfdd/bfdd.conf.sample
|
dist_examples_DATA += bfdd/bfdd.conf.sample
|
||||||
vtysh_scan += $(top_srcdir)/bfdd/bfdd_vty.c
|
vtysh_scan += $(top_srcdir)/bfdd/bfdd_vty.c
|
||||||
|
vtysh_scan += $(top_srcdir)/bfdd/bfdd_cli.c
|
||||||
man8 += $(MANBUILD)/bfdd.8
|
man8 += $(MANBUILD)/bfdd.8
|
||||||
endif
|
endif
|
||||||
|
|
||||||
bfdd_libbfd_a_SOURCES = \
|
bfdd_libbfd_a_SOURCES = \
|
||||||
bfdd/bfd.c \
|
bfdd/bfd.c \
|
||||||
|
bfdd/bfdd_northbound.c \
|
||||||
bfdd/bfdd_vty.c \
|
bfdd/bfdd_vty.c \
|
||||||
|
bfdd/bfdd_cli.c \
|
||||||
bfdd/bfd_packet.c \
|
bfdd/bfd_packet.c \
|
||||||
bfdd/config.c \
|
bfdd/config.c \
|
||||||
bfdd/control.c \
|
bfdd/control.c \
|
||||||
@ -24,10 +27,17 @@ bfdd_libbfd_a_SOURCES = \
|
|||||||
bfdd/bfdd_vty_clippy.c: $(CLIPPY_DEPS)
|
bfdd/bfdd_vty_clippy.c: $(CLIPPY_DEPS)
|
||||||
bfdd/bfdd_vty.$(OBJEXT): bfdd/bfdd_vty_clippy.c
|
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 += \
|
noinst_HEADERS += \
|
||||||
bfdd/bfdctl.h \
|
bfdd/bfdctl.h \
|
||||||
bfdd/bfd.h \
|
bfdd/bfd.h \
|
||||||
# end
|
# end
|
||||||
|
|
||||||
|
nodist_bfdd_bfdd_SOURCES = \
|
||||||
|
yang/frr-bfdd.yang.c \
|
||||||
|
# end
|
||||||
|
|
||||||
bfdd_bfdd_SOURCES = bfdd/bfdd.c
|
bfdd_bfdd_SOURCES = bfdd/bfdd.c
|
||||||
bfdd_bfdd_LDADD = bfdd/libbfd.a lib/libfrr.la
|
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,
|
void (*cli_show)(struct vty *vty, struct lyd_node *dnode,
|
||||||
bool show_defaults);
|
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;
|
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,
|
void nb_cli_show_dnode_cmds(struct vty *vty, struct lyd_node *root,
|
||||||
bool with_defaults)
|
bool with_defaults)
|
||||||
{
|
{
|
||||||
struct lyd_node *next, *child;
|
struct lyd_node *next, *child, *parent;
|
||||||
|
|
||||||
LY_TREE_DFS_BEGIN (root, next, child) {
|
LY_TREE_DFS_BEGIN (root, next, child) {
|
||||||
struct nb_node *nb_node;
|
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);
|
(*nb_node->cbs.cli_show)(vty, child, with_defaults);
|
||||||
next:
|
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);
|
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-interface.yang
|
||||||
dist_yangmodels_DATA += yang/frr-route-types.yang
|
dist_yangmodels_DATA += yang/frr-route-types.yang
|
||||||
|
|
||||||
|
if BFDD
|
||||||
|
dist_yangmodels_DATA += yang/frr-bfdd.yang
|
||||||
|
endif
|
||||||
|
|
||||||
if RIPD
|
if RIPD
|
||||||
dist_yangmodels_DATA += yang/frr-ripd.yang
|
dist_yangmodels_DATA += yang/frr-ripd.yang
|
||||||
endif
|
endif
|
||||||
|
Loading…
Reference in New Issue
Block a user