summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bfdd/bfd.c261
-rw-r--r--bfdd/bfd.h34
-rw-r--r--bfdd/bfd_packet.c180
-rw-r--r--bfdd/bfdd.c71
-rw-r--r--bfdd/bfdd_vty.c128
-rw-r--r--bfdd/bsd.c48
-rw-r--r--bfdd/config.c2
-rw-r--r--bfdd/linux.c52
-rw-r--r--bfdd/ptm_adapter.c110
-rw-r--r--bfdd/subdir.am2
-rw-r--r--bgpd/bgp_bfd.c7
-rw-r--r--bgpd/bgp_zebra.c2
-rw-r--r--doc/user/bfd.rst16
-rw-r--r--isisd/isis_bfd.c4
-rw-r--r--lib/bfd.c5
-rw-r--r--lib/bfd.h3
-rw-r--r--lib/vrf.c8
-rw-r--r--ospf6d/ospf6_bfd.c2
-rw-r--r--ospf6d/ospf6_zebra.c2
-rw-r--r--ospfd/ospf_bfd.c2
-rw-r--r--ospfd/ospf_zebra.c2
-rw-r--r--pimd/pim_bfd.c2
-rw-r--r--pimd/pim_zebra.c2
-rw-r--r--tests/topotests/bfd-vrf-topo1/__init__.py0
-rw-r--r--tests/topotests/bfd-vrf-topo1/r1/bfdd.conf6
-rw-r--r--tests/topotests/bfd-vrf-topo1/r1/bgp_prefixes.json52
-rw-r--r--tests/topotests/bfd-vrf-topo1/r1/bgp_summary.json11
-rw-r--r--tests/topotests/bfd-vrf-topo1/r1/bgpd.conf8
-rw-r--r--tests/topotests/bfd-vrf-topo1/r1/peers.json8
-rw-r--r--tests/topotests/bfd-vrf-topo1/r1/zebra.conf3
-rw-r--r--tests/topotests/bfd-vrf-topo1/r2/bfdd.conf12
-rw-r--r--tests/topotests/bfd-vrf-topo1/r2/bgp_prefixes.json52
-rw-r--r--tests/topotests/bfd-vrf-topo1/r2/bgp_summary.json19
-rw-r--r--tests/topotests/bfd-vrf-topo1/r2/bgpd.conf11
-rw-r--r--tests/topotests/bfd-vrf-topo1/r2/peers.json17
-rw-r--r--tests/topotests/bfd-vrf-topo1/r2/zebra.conf9
-rw-r--r--tests/topotests/bfd-vrf-topo1/r3/bfdd.conf7
-rw-r--r--tests/topotests/bfd-vrf-topo1/r3/bgp_prefixes.json52
-rw-r--r--tests/topotests/bfd-vrf-topo1/r3/bgp_summary.json11
-rw-r--r--tests/topotests/bfd-vrf-topo1/r3/bgpd.conf7
-rw-r--r--tests/topotests/bfd-vrf-topo1/r3/peers.json6
-rw-r--r--tests/topotests/bfd-vrf-topo1/r3/zebra.conf3
-rw-r--r--tests/topotests/bfd-vrf-topo1/r4/bfdd.conf7
-rw-r--r--tests/topotests/bfd-vrf-topo1/r4/bgp_prefixes.json52
-rw-r--r--tests/topotests/bfd-vrf-topo1/r4/bgp_summary.json11
-rw-r--r--tests/topotests/bfd-vrf-topo1/r4/bgpd.conf7
-rw-r--r--tests/topotests/bfd-vrf-topo1/r4/peers.json6
-rw-r--r--tests/topotests/bfd-vrf-topo1/r4/zebra.conf3
-rw-r--r--tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.dot73
-rw-r--r--tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.jpgbin0 -> 25713 bytes
-rwxr-xr-xtests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.py292
-rw-r--r--zebra/zebra_ptm.c18
52 files changed, 1354 insertions, 354 deletions
diff --git a/bfdd/bfd.c b/bfdd/bfd.c
index e9645824f..a2e84e928 100644
--- a/bfdd/bfd.c
+++ b/bfdd/bfd.c
@@ -128,15 +128,8 @@ int bfd_session_enable(struct bfd_session *bs)
* If the interface or VRF doesn't exist, then we must register
* the session but delay its start.
*/
- if (bs->key.ifname[0]) {
- ifp = if_lookup_by_name_all_vrf(bs->key.ifname);
- if (ifp == NULL) {
- log_error(
- "session-enable: specified interface doesn't exists.");
- return 0;
- }
-
- vrf = vrf_lookup_by_id(ifp->vrf_id);
+ if (bs->key.vrfname[0]) {
+ vrf = vrf_lookup_by_name(bs->key.vrfname);
if (vrf == NULL) {
log_error(
"session-enable: specified VRF doesn't exists.");
@@ -144,13 +137,24 @@ int bfd_session_enable(struct bfd_session *bs)
}
}
- if (bs->key.vrfname[0]) {
- vrf = vrf_lookup_by_name(bs->key.vrfname);
- if (vrf == NULL) {
+ if (bs->key.ifname[0]) {
+ if (vrf)
+ ifp = if_lookup_by_name(bs->key.ifname, vrf->vrf_id);
+ else
+ ifp = if_lookup_by_name_all_vrf(bs->key.ifname);
+ if (ifp == NULL) {
log_error(
- "session-enable: specified VRF doesn't exists.");
+ "session-enable: specified interface doesn't exists.");
return 0;
}
+ if (bs->key.ifname[0] && !vrf) {
+ vrf = vrf_lookup_by_id(ifp->vrf_id);
+ if (vrf == NULL) {
+ log_error(
+ "session-enable: specified VRF doesn't exists.");
+ return 0;
+ }
+ }
}
/* Assign interface/VRF pointers. */
@@ -164,7 +168,7 @@ int bfd_session_enable(struct bfd_session *bs)
/* Sanity check: don't leak open sockets. */
if (bs->sock != -1) {
- zlog_debug("session-enable: previous socket open");
+ log_debug("session-enable: previous socket open");
close(bs->sock);
bs->sock = -1;
}
@@ -291,7 +295,7 @@ void ptm_bfd_echo_start(struct bfd_session *bfd)
ptm_bfd_echo_xmt_TO(bfd);
}
-void ptm_bfd_ses_up(struct bfd_session *bfd)
+void ptm_bfd_sess_up(struct bfd_session *bfd)
{
int old_state = bfd->ses_state;
@@ -315,7 +319,7 @@ void ptm_bfd_ses_up(struct bfd_session *bfd)
}
}
-void ptm_bfd_ses_dn(struct bfd_session *bfd, uint8_t diag)
+void ptm_bfd_sess_dn(struct bfd_session *bfd, uint8_t diag)
{
int old_state = bfd->ses_state;
@@ -432,7 +436,7 @@ int bfd_recvtimer_cb(struct thread *t)
switch (bs->ses_state) {
case PTM_BFD_INIT:
case PTM_BFD_UP:
- ptm_bfd_ses_dn(bs, BD_CONTROL_EXPIRED);
+ ptm_bfd_sess_dn(bs, BD_CONTROL_EXPIRED);
bfd_recvtimer_update(bs);
break;
@@ -455,7 +459,7 @@ int bfd_echo_recvtimer_cb(struct thread *t)
switch (bs->ses_state) {
case PTM_BFD_INIT:
case PTM_BFD_UP:
- ptm_bfd_ses_dn(bs, BD_ECHO_FAILED);
+ ptm_bfd_sess_dn(bs, BD_ECHO_FAILED);
break;
}
@@ -725,7 +729,7 @@ struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc)
return bfd;
}
-int ptm_bfd_ses_del(struct bfd_peer_cfg *bpc)
+int ptm_bfd_sess_del(struct bfd_peer_cfg *bpc)
{
struct bfd_session *bs;
@@ -805,7 +809,7 @@ static void bs_down_handler(struct bfd_session *bs, int nstate)
* Remote peer told us his path is up, lets turn
* activate the session.
*/
- ptm_bfd_ses_up(bs);
+ ptm_bfd_sess_up(bs);
break;
default:
@@ -832,7 +836,7 @@ static void bs_init_handler(struct bfd_session *bs, int nstate)
case PTM_BFD_INIT:
case PTM_BFD_UP:
/* We agreed on the settings and the path is up. */
- ptm_bfd_ses_up(bs);
+ ptm_bfd_sess_up(bs);
break;
default:
@@ -847,7 +851,7 @@ static void bs_up_handler(struct bfd_session *bs, int nstate)
case PTM_BFD_ADM_DOWN:
case PTM_BFD_DOWN:
/* Peer lost or asked to shutdown connection. */
- ptm_bfd_ses_dn(bs, BD_NEIGHBOR_DOWN);
+ ptm_bfd_sess_dn(bs, BD_NEIGHBOR_DOWN);
break;
case PTM_BFD_INIT:
@@ -1197,10 +1201,6 @@ int bs_observer_add(struct bfd_session *bs)
if (bso->bso_isinterface)
strlcpy(bso->bso_entryname, bs->key.ifname,
sizeof(bso->bso_entryname));
- else
- strlcpy(bso->bso_entryname, bs->key.vrfname,
- sizeof(bso->bso_entryname));
-
/* Handle socket binding failures caused by missing local addresses. */
if (bs->sock == -1) {
bso->bso_isaddress = true;
@@ -1322,32 +1322,105 @@ struct bfd_session *bfd_id_lookup(uint32_t id)
return hash_lookup(bfd_id_hash, &bs);
}
+struct bfd_key_walk_partial_lookup {
+ struct bfd_session *given;
+ struct bfd_session *result;
+};
+
+/* ignore some parameters */
+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 *)data;
+ struct bfd_session *given = ctx->given;
+ struct bfd_session *parsed = b->data;
+
+ if (given->key.family != parsed->key.family)
+ 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)))
+ return HASHWALK_CONTINUE;
+ if (memcmp(given->key.vrfname, parsed->key.vrfname, MAXNAMELEN))
+ return HASHWALK_CONTINUE;
+ ctx->result = parsed;
+ /* ignore localaddr or interface */
+ return HASHWALK_ABORT;
+}
+
struct bfd_session *bfd_key_lookup(struct bfd_key key)
{
struct bfd_session bs, *bsp;
+ struct bfd_key_walk_partial_lookup ctx;
+ char peer_buf[INET6_ADDRSTRLEN];
bs.key = key;
bsp = hash_lookup(bfd_key_hash, &bs);
+ if (bsp)
+ return bsp;
+ inet_ntop(bs.key.family, &bs.key.peer, peer_buf,
+ sizeof(peer_buf));
/* Handle cases where local-address is optional. */
- if (bsp == NULL && bs.key.family == AF_INET) {
+ if (bs.key.family == AF_INET) {
memset(&bs.key.local, 0, sizeof(bs.key.local));
bsp = hash_lookup(bfd_key_hash, &bs);
+ if (bsp) {
+ char addr_buf[INET6_ADDRSTRLEN];
+
+ inet_ntop(bs.key.family, &key.local, addr_buf,
+ sizeof(addr_buf));
+ log_debug(" peer %s found, but loc-addr %s ignored",
+ peer_buf, addr_buf);
+ return bsp;
+ }
}
- /* Handle cases where ifname is optional. */
bs.key = key;
- if (bsp == NULL && bs.key.ifname[0]) {
+ /* Handle cases where ifname is optional. */
+ if (bs.key.ifname[0]) {
memset(bs.key.ifname, 0, sizeof(bs.key.ifname));
bsp = hash_lookup(bfd_key_hash, &bs);
+ if (bsp) {
+ log_debug(" peer %s found, but ifp %s ignored",
+ peer_buf, key.ifname);
+ return bsp;
+ }
+ }
- /* Handle cases where local-address and ifname are optional. */
- if (bsp == NULL && bs.key.family == AF_INET) {
- memset(&bs.key.local, 0, sizeof(bs.key.local));
- bsp = hash_lookup(bfd_key_hash, &bs);
+ /* Handle cases where local-address and ifname are optional. */
+ if (bs.key.family == AF_INET) {
+ memset(&bs.key.local, 0, sizeof(bs.key.local));
+ bsp = hash_lookup(bfd_key_hash, &bs);
+ if (bsp) {
+ char addr_buf[INET6_ADDRSTRLEN];
+
+ inet_ntop(bs.key.family, &bs.key.local, addr_buf,
+ sizeof(addr_buf));
+ log_debug(" peer %s found, but ifp %s"
+ " and loc-addr %s ignored",
+ peer_buf, key.ifname,
+ addr_buf);
+ return bsp;
}
}
+ bs.key = key;
+ /* Handle case where a context more complex ctx is present.
+ * input has no iface nor local-address, but a context may
+ * exist
+ */
+ ctx.result = NULL;
+ ctx.given = &bs;
+ hash_walk(bfd_key_hash,
+ &bfd_key_lookup_ignore_partial_walker,
+ &ctx);
+ /* change key */
+ if (ctx.result) {
+ bsp = ctx.result;
+ log_debug(" peer %s found, but ifp"
+ " and/or loc-addr params ignored");
+ }
return bsp;
}
@@ -1443,3 +1516,125 @@ void bfd_shutdown(void)
hash_free(bfd_id_hash);
hash_free(bfd_key_hash);
}
+
+static int bfd_vrf_new(struct vrf *vrf)
+{
+ log_debug("VRF Created: %s(%u)", vrf->name, vrf->vrf_id);
+ return 0;
+}
+
+static int bfd_vrf_delete(struct vrf *vrf)
+{
+ log_debug("VRF Deletion: %s(%u)", vrf->name, vrf->vrf_id);
+ return 0;
+}
+
+static int bfd_vrf_enable(struct vrf *vrf)
+{
+ struct bfd_vrf_global *bvrf;
+
+ /* a different name */
+ if (!vrf->info) {
+ bvrf = XCALLOC(MTYPE_BFDD_VRF, sizeof(struct bfd_vrf_global));
+ bvrf->vrf = vrf;
+ vrf->info = (void *)bvrf;
+ } else
+ bvrf = vrf->info;
+ log_debug("VRF enable add %s id %u", vrf->name, vrf->vrf_id);
+
+ /* create sockets if needed */
+ if (!bvrf->bg_shop)
+ bvrf->bg_shop = bp_udp_shop(vrf->vrf_id);
+ if (!bvrf->bg_mhop)
+ bvrf->bg_mhop = bp_udp_mhop(vrf->vrf_id);
+ if (!bvrf->bg_shop6)
+ bvrf->bg_shop6 = bp_udp6_shop(vrf->vrf_id);
+ if (!bvrf->bg_mhop6)
+ bvrf->bg_mhop6 = bp_udp6_mhop(vrf->vrf_id);
+ if (!bvrf->bg_echo)
+ bvrf->bg_echo = bp_echo_socket(vrf->vrf_id);
+ if (!bvrf->bg_echov6)
+ bvrf->bg_echov6 = bp_echov6_socket(vrf->vrf_id);
+
+ /* Add descriptors to the event loop. */
+ if (!bvrf->bg_ev[0])
+ thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_shop,
+ &bvrf->bg_ev[0]);
+ if (!bvrf->bg_ev[1])
+ thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_mhop,
+ &bvrf->bg_ev[1]);
+ if (!bvrf->bg_ev[2])
+ thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_shop6,
+ &bvrf->bg_ev[2]);
+ if (!bvrf->bg_ev[3])
+ thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_mhop6,
+ &bvrf->bg_ev[3]);
+ if (!bvrf->bg_ev[4])
+ thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_echo,
+ &bvrf->bg_ev[4]);
+ if (!bvrf->bg_ev[5])
+ thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_echov6,
+ &bvrf->bg_ev[5]);
+
+ if (vrf->vrf_id != VRF_DEFAULT) {
+ bfdd_zclient_register(vrf->vrf_id);
+ bfdd_sessions_enable_vrf(vrf);
+ }
+ return 0;
+}
+
+static int bfd_vrf_disable(struct vrf *vrf)
+{
+ struct bfd_vrf_global *bvrf;
+
+ if (!vrf->info)
+ return 0;
+ bvrf = vrf->info;
+
+ if (vrf->vrf_id != VRF_DEFAULT) {
+ bfdd_sessions_disable_vrf(vrf);
+ bfdd_zclient_unregister(vrf->vrf_id);
+ }
+
+ log_debug("VRF disable %s id %d", vrf->name, vrf->vrf_id);
+ /* Close all descriptors. */
+ socket_close(&bvrf->bg_echo);
+ socket_close(&bvrf->bg_shop);
+ socket_close(&bvrf->bg_mhop);
+ socket_close(&bvrf->bg_shop6);
+ socket_close(&bvrf->bg_mhop6);
+
+ /* free context */
+ XFREE(MTYPE_BFDD_VRF, bvrf);
+ vrf->info = NULL;
+
+ return 0;
+}
+
+void bfd_vrf_init(void)
+{
+ vrf_init(bfd_vrf_new, bfd_vrf_enable, bfd_vrf_disable,
+ bfd_vrf_delete, NULL);
+}
+
+void bfd_vrf_terminate(void)
+{
+ vrf_terminate();
+}
+
+struct bfd_vrf_global *bfd_vrf_look_by_session(struct bfd_session *bfd)
+{
+ struct vrf *vrf;
+
+ if (!vrf_is_backend_netns()) {
+ vrf = vrf_lookup_by_id(VRF_DEFAULT);
+ if (vrf)
+ return (struct bfd_vrf_global *)vrf->info;
+ return NULL;
+ }
+ if (!bfd)
+ return NULL;
+ if (!bfd->vrf)
+ return NULL;
+ return bfd->vrf->info;
+}
diff --git a/bfdd/bfd.h b/bfdd/bfd.h
index e08a1ff72..3f3d60383 100644
--- a/bfdd/bfd.h
+++ b/bfdd/bfd.h
@@ -48,6 +48,7 @@ DECLARE_MTYPE(BFDD_LABEL);
DECLARE_MTYPE(BFDD_CONTROL);
DECLARE_MTYPE(BFDD_SESSION_OBSERVER);
DECLARE_MTYPE(BFDD_NOTIFICATION);
+DECLARE_MTYPE(BFDD_VRF);
struct bfd_timers {
uint32_t desired_min_tx;
@@ -379,15 +380,19 @@ int control_accept(struct thread *t);
*
* Daemon specific code.
*/
-struct bfd_global {
+struct bfd_vrf_global {
int bg_shop;
int bg_mhop;
int bg_shop6;
int bg_mhop6;
int bg_echo;
int bg_echov6;
+ struct vrf *vrf;
+
struct thread *bg_ev[6];
+};
+struct bfd_global {
int bg_csock;
struct thread *bg_csockev;
struct bcslist bg_bcslist;
@@ -395,6 +400,8 @@ struct bfd_global {
struct pllist bg_pllist;
struct obslist bg_obslist;
+
+ struct zebra_privs_t bfdd_privs;
};
extern struct bfd_global bglobal;
extern struct bfd_diag_str_list diag_list[];
@@ -459,14 +466,14 @@ int bp_set_tosv6(int sd, uint8_t value);
int bp_set_tos(int sd, uint8_t value);
int bp_bind_dev(int sd, const char *dev);
-int bp_udp_shop(void);
-int bp_udp_mhop(void);
-int bp_udp6_shop(void);
-int bp_udp6_mhop(void);
+int bp_udp_shop(vrf_id_t vrf_id);
+int bp_udp_mhop(vrf_id_t vrf_id);
+int bp_udp6_shop(vrf_id_t vrf_id);
+int bp_udp6_mhop(vrf_id_t vrf_id);
int bp_peer_socket(const struct bfd_session *bs);
int bp_peer_socketv6(const struct bfd_session *bs);
-int bp_echo_socket(void);
-int bp_echov6_socket(void);
+int bp_echo_socket(vrf_id_t vrf_id);
+int bp_echov6_socket(vrf_id_t vrf_id);
void ptm_bfd_snd(struct bfd_session *bfd, int fbit);
void ptm_bfd_echo_snd(struct bfd_session *bfd);
@@ -505,9 +512,9 @@ void bfd_echo_xmttimer_assign(struct bfd_session *bs, bfd_ev_cb cb);
int bfd_session_enable(struct bfd_session *bs);
void bfd_session_disable(struct bfd_session *bs);
struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc);
-int ptm_bfd_ses_del(struct bfd_peer_cfg *bpc);
-void ptm_bfd_ses_dn(struct bfd_session *bfd, uint8_t diag);
-void ptm_bfd_ses_up(struct bfd_session *bfd);
+int ptm_bfd_sess_del(struct bfd_peer_cfg *bpc);
+void ptm_bfd_sess_dn(struct bfd_session *bfd, uint8_t diag);
+void ptm_bfd_sess_up(struct bfd_session *bfd);
void ptm_bfd_echo_stop(struct bfd_session *bfd);
void ptm_bfd_echo_start(struct bfd_session *bfd);
void ptm_bfd_xmt_TO(struct bfd_session *bfd, int fbit);
@@ -539,6 +546,9 @@ void bs_to_bpc(struct bfd_session *bs, struct bfd_peer_cfg *bpc);
/* BFD hash data structures interface */
void bfd_initialize(void);
void bfd_shutdown(void);
+void bfd_vrf_init(void);
+void bfd_vrf_terminate(void);
+struct bfd_vrf_global *bfd_vrf_look_by_session(struct bfd_session *bfd);
struct bfd_session *bfd_id_lookup(uint32_t id);
struct bfd_session *bfd_key_lookup(struct bfd_key key);
@@ -576,6 +586,10 @@ void bfdd_vty_init(void);
*/
void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv);
void bfdd_zclient_stop(void);
+void bfdd_zclient_unregister(vrf_id_t vrf_id);
+void bfdd_zclient_register(vrf_id_t vrf_id);
+void bfdd_sessions_enable_vrf(struct vrf *vrf);
+void bfdd_sessions_disable_vrf(struct vrf *vrf);
int ptm_bfd_notify(struct bfd_session *bs);
diff --git a/bfdd/bfd_packet.c b/bfdd/bfd_packet.c
index 93677ec85..8edba05d1 100644
--- a/bfdd/bfd_packet.c
+++ b/bfdd/bfd_packet.c
@@ -37,15 +37,14 @@
#include "bfd.h"
-
/*
* Prototypes
*/
-static int ptm_bfd_process_echo_pkt(int s);
+static int ptm_bfd_process_echo_pkt(struct bfd_vrf_global *bvrf, int s);
int _ptm_bfd_send(struct bfd_session *bs, uint16_t *port, const void *data,
size_t datalen);
-static void bfd_sd_reschedule(int sd);
+static void bfd_sd_reschedule(struct bfd_vrf_global *bvrf, int sd);
ssize_t bfd_recv_ipv4(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl,
ifindex_t *ifindex, struct sockaddr_any *local,
struct sockaddr_any *peer);
@@ -54,7 +53,8 @@ ssize_t bfd_recv_ipv6(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl,
struct sockaddr_any *peer);
int bp_udp_send(int sd, uint8_t ttl, uint8_t *data, size_t datalen,
struct sockaddr *to, socklen_t tolen);
-int bp_bfd_echo_in(int sd, uint8_t *ttl, uint32_t *my_discr);
+int bp_bfd_echo_in(struct bfd_vrf_global *bvrf, int sd,
+ uint8_t *ttl, uint32_t *my_discr);
/* socket related prototypes */
static void bp_set_ipopts(int sd);
@@ -129,7 +129,10 @@ void ptm_bfd_echo_snd(struct bfd_session *bfd)
struct bfd_echo_pkt bep;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
+ struct bfd_vrf_global *bvrf = bfd_vrf_look_by_session(bfd);
+ if (!bvrf)
+ return;
if (!BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE))
BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE);
@@ -139,7 +142,7 @@ void ptm_bfd_echo_snd(struct bfd_session *bfd)
bep.my_discr = htonl(bfd->discrs.my_discr);
if (BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_IPV6)) {
- sd = bglobal.bg_echov6;
+ sd = bvrf->bg_echov6;
memset(&sin6, 0, sizeof(sin6));
sin6.sin6_family = AF_INET6;
memcpy(&sin6.sin6_addr, &bfd->key.peer, sizeof(sin6.sin6_addr));
@@ -154,7 +157,7 @@ void ptm_bfd_echo_snd(struct bfd_session *bfd)
sa = (struct sockaddr *)&sin6;
salen = sizeof(sin6);
} else {
- sd = bglobal.bg_echo;
+ sd = bvrf->bg_echo;
memset(&sin6, 0, sizeof(sin6));
sin.sin_family = AF_INET;
memcpy(&sin.sin_addr, &bfd->key.peer, sizeof(sin.sin_addr));
@@ -174,14 +177,14 @@ void ptm_bfd_echo_snd(struct bfd_session *bfd)
bfd->stats.tx_echo_pkt++;
}
-static int ptm_bfd_process_echo_pkt(int s)
+static int ptm_bfd_process_echo_pkt(struct bfd_vrf_global *bvrf, int s)
{
struct bfd_session *bfd;
uint32_t my_discr = 0;
uint8_t ttl = 0;
/* Receive and parse echo packet. */
- if (bp_bfd_echo_in(s, &ttl, &my_discr) == -1)
+ if (bp_bfd_echo_in(bvrf, s, &ttl, &my_discr) == -1)
return 0;
/* Your discriminator not zero - use it to find session */
@@ -441,32 +444,32 @@ ssize_t bfd_recv_ipv6(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl,
return mlen;
}
-static void bfd_sd_reschedule(int sd)
+static void bfd_sd_reschedule(struct bfd_vrf_global *bvrf, int sd)
{
- if (sd == bglobal.bg_shop) {
- THREAD_OFF(bglobal.bg_ev[0]);
- thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_shop,
- &bglobal.bg_ev[0]);
- } else if (sd == bglobal.bg_mhop) {
- THREAD_OFF(bglobal.bg_ev[1]);
- thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_mhop,
- &bglobal.bg_ev[1]);
- } else if (sd == bglobal.bg_shop6) {
- THREAD_OFF(bglobal.bg_ev[2]);
- thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_shop6,
- &bglobal.bg_ev[2]);
- } else if (sd == bglobal.bg_mhop6) {
- THREAD_OFF(bglobal.bg_ev[3]);
- thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_mhop6,
- &bglobal.bg_ev[3]);
- } else if (sd == bglobal.bg_echo) {
- THREAD_OFF(bglobal.bg_ev[4]);
- thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_echo,
- &bglobal.bg_ev[4]);
- } else if (sd == bglobal.bg_echov6) {
- THREAD_OFF(bglobal.bg_ev[5]);
- thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_echov6,
- &bglobal.bg_ev[5]);
+ if (sd == bvrf->bg_shop) {
+ THREAD_OFF(bvrf->bg_ev[0]);
+ thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_shop,
+ &bvrf->bg_ev[0]);
+ } else if (sd == bvrf->bg_mhop) {
+ THREAD_OFF(bvrf->bg_ev[1]);
+ thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_mhop,
+ &bvrf->bg_ev[1]);
+ } else if (sd == bvrf->bg_shop6) {
+ THREAD_OFF(bvrf->bg_ev[2]);
+ thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_shop6,
+ &bvrf->bg_ev[2]);
+ } else if (sd == bvrf->bg_mhop6) {
+ THREAD_OFF(bvrf->bg_ev[3]);
+ thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_mhop6,
+ &bvrf->bg_ev[3]);
+ } else if (sd == bvrf->bg_echo) {
+ THREAD_OFF(bvrf->bg_ev[4]);
+ thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_echo,
+ &bvrf->bg_ev[4]);
+ } else if (sd == bvrf->bg_echov6) {
+ THREAD_OFF(bvrf->bg_ev[5]);
+ thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_echov6,
+ &bvrf->bg_ev[5]);
}
}
@@ -518,13 +521,16 @@ int bfd_recv_cb(struct thread *t)
ifindex_t ifindex = IFINDEX_INTERNAL;
struct sockaddr_any local, peer;
uint8_t msgbuf[1516];
+ struct bfd_vrf_global *bvrf = THREAD_ARG(t);
+ if (bvrf)
+ vrfid = bvrf->vrf->vrf_id;
/* Schedule next read. */
- bfd_sd_reschedule(sd);
+ bfd_sd_reschedule(bvrf, sd);
/* Handle echo packets. */
- if (sd == bglobal.bg_echo || sd == bglobal.bg_echov6) {
- ptm_bfd_process_echo_pkt(sd);
+ if (sd == bvrf->bg_echo || sd == bvrf->bg_echov6) {
+ ptm_bfd_process_echo_pkt(bvrf, sd);
return 0;
}
@@ -534,12 +540,12 @@ int bfd_recv_cb(struct thread *t)
/* Handle control packets. */
is_mhop = false;
- if (sd == bglobal.bg_shop || sd == bglobal.bg_mhop) {
- is_mhop = sd == bglobal.bg_mhop;
+ if (sd == bvrf->bg_shop || sd == bvrf->bg_mhop) {
+ is_mhop = sd == bvrf->bg_mhop;
mlen = bfd_recv_ipv4(sd, msgbuf, sizeof(msgbuf), &ttl, &ifindex,
&local, &peer);
- } else if (sd == bglobal.bg_shop6 || sd == bglobal.bg_mhop6) {
- is_mhop = sd == bglobal.bg_mhop6;
+ } else if (sd == bvrf->bg_shop6 || sd == bvrf->bg_mhop6) {
+ is_mhop = sd == bvrf->bg_mhop6;
mlen = bfd_recv_ipv6(sd, msgbuf, sizeof(msgbuf), &ttl, &ifindex,
&local, &peer);
}
@@ -682,7 +688,8 @@ int bfd_recv_cb(struct thread *t)
*
* Returns -1 on error or loopback or 0 on success.
*/
-int bp_bfd_echo_in(int sd, uint8_t *ttl, uint32_t *my_discr)
+int bp_bfd_echo_in(struct bfd_vrf_global *bvrf, int sd,
+ uint8_t *ttl, uint32_t *my_discr)
{
struct bfd_echo_pkt *bep;
ssize_t rlen;
@@ -691,7 +698,7 @@ int bp_bfd_echo_in(int sd, uint8_t *ttl, uint32_t *my_discr)
vrf_id_t vrfid = VRF_DEFAULT;
uint8_t msgbuf[1516];
- if (sd == bglobal.bg_echo)
+ if (sd == bvrf->bg_echo)
rlen = bfd_recv_ipv4(sd, msgbuf, sizeof(msgbuf), ttl, &ifindex,
&local, &peer);
else
@@ -709,7 +716,7 @@ int bp_bfd_echo_in(int sd, uint8_t *ttl, uint32_t *my_discr)
if (*ttl == BFD_TTL_VAL) {
bp_udp_send(sd, *ttl - 1, msgbuf, rlen,
(struct sockaddr *)&peer,
- (sd == bglobal.bg_echo) ? sizeof(peer.sa_sin)
+ (sd == bvrf->bg_echo) ? sizeof(peer.sa_sin)
: sizeof(peer.sa_sin6));
return -1;
}
@@ -872,25 +879,28 @@ static void bp_bind_ip(int sd, uint16_t port)
log_fatal("bind-ip: bind: %s", strerror(errno));
}
-int bp_udp_shop(void)
+int bp_udp_shop(vrf_id_t vrf_id)
{
int sd;
- sd = socket(AF_INET, SOCK_DGRAM, PF_UNSPEC);
+ frr_elevate_privs(&bglobal.bfdd_privs) {
+ sd = vrf_socket(AF_INET, SOCK_DGRAM, PF_UNSPEC, vrf_id, NULL);
+ }
if (sd == -1)
log_fatal("udp-shop: socket: %s", strerror(errno));
bp_set_ipopts(sd);
bp_bind_ip(sd, BFD_DEFDESTPORT);
-
return sd;
}
-int bp_udp_mhop(void)
+int bp_udp_mhop(vrf_id_t vrf_id)
{
int sd;
- sd = socket(AF_INET, SOCK_DGRAM, PF_UNSPEC);
+ frr_elevate_privs(&bglobal.bfdd_privs) {
+ sd = vrf_socket(AF_INET, SOCK_DGRAM, PF_UNSPEC, vrf_id, NULL);
+ }
if (sd == -1)
log_fatal("udp-mhop: socket: %s", strerror(errno));
@@ -905,8 +915,18 @@ int bp_peer_socket(const struct bfd_session *bs)
int sd, pcount;
struct sockaddr_in sin;
static int srcPort = BFD_SRCPORTINIT;
+ const char *device_to_bind = NULL;
+
+ if (bs->key.ifname[0])
+ device_to_bind = (const char *)bs->key.ifname;
+ else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)
+ && bs->key.vrfname[0])
+ device_to_bind = (const char *)bs->key.vrfname;
- sd = socket(AF_INET, SOCK_DGRAM, PF_UNSPEC);
+ frr_elevate_privs(&bglobal.bfdd_privs) {
+ sd = vrf_socket(AF_INET, SOCK_DGRAM, PF_UNSPEC,
+ bs->vrf->vrf_id, device_to_bind);
+ }
if (sd == -1) {
log_error("ipv4-new: failed to create socket: %s",
strerror(errno));
@@ -925,19 +945,6 @@ int bp_peer_socket(const struct bfd_session *bs)
return -1;
}
- if (bs->key.ifname[0]) {
- if (bp_bind_dev(sd, bs->key.ifname) != 0) {
- close(sd);
- return -1;
- }
- } else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)
- && bs->key.vrfname[0]) {
- if (bp_bind_dev(sd, bs->key.vrfname) != 0) {
- close(sd);
- return -1;
- }
- }
-
/* Find an available source port in the proper range */
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
@@ -975,8 +982,18 @@ int bp_peer_socketv6(const struct bfd_session *bs)
int sd, pcount;
struct sockaddr_in6 sin6;
static int srcPort = BFD_SRCPORTINIT;
+ const char *device_to_bind = NULL;
- sd = socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC);
+ if (bs->key.ifname[0])
+ device_to_bind = (const char *)bs->key.ifname;
+ else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)
+ && bs->key.vrfname[0])
+ device_to_bind = (const char *)bs->key.vrfname;
+
+ frr_elevate_privs(&bglobal.bfdd_privs) {
+ sd = vrf_socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC,
+ bs->vrf->vrf_id, device_to_bind);
+ }
if (sd == -1) {
log_error("ipv6-new: failed to create socket: %s",
strerror(errno));
@@ -1005,19 +1022,6 @@ int bp_peer_socketv6(const struct bfd_session *bs)
if (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr))
sin6.sin6_scope_id = bs->ifp->ifindex;
- if (bs->key.ifname[0]) {
- if (bp_bind_dev(sd, bs->key.ifname) != 0) {
- close(sd);
- return -1;
- }
- } else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)
- && bs->key.vrfname[0]) {
- if (bp_bind_dev(sd, bs->key.vrfname) != 0) {
- close(sd);
- return -1;
- }
- }
-
pcount = 0;
do {
if ((++pcount) > (BFD_SRCPORTMAX - BFD_SRCPORTINIT)) {
@@ -1102,11 +1106,13 @@ static void bp_bind_ipv6(int sd, uint16_t port)
log_fatal("bind-ipv6: bind: %s", strerror(errno));
}
-int bp_udp6_shop(void)
+int bp_udp6_shop(vrf_id_t vrf_id)
{
int sd;
- sd = socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC);
+ frr_elevate_privs(&bglobal.bfdd_privs) {
+ sd = vrf_socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC, vrf_id, NULL);
+ }
if (sd == -1)
log_fatal("udp6-shop: socket: %s", strerror(errno));
@@ -1116,11 +1122,13 @@ int bp_udp6_shop(void)
return sd;
}
-int bp_udp6_mhop(void)
+int bp_udp6_mhop(vrf_id_t vrf_id)
{
int sd;
- sd = socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC);
+ frr_elevate_privs(&bglobal.bfdd_privs) {
+ sd = vrf_socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC, vrf_id, NULL);
+ }
if (sd == -1)
log_fatal("udp6-mhop: socket: %s", strerror(errno));
@@ -1130,11 +1138,13 @@ int bp_udp6_mhop(void)
return sd;
}
-int bp_echo_socket(void)
+int bp_echo_socket(vrf_id_t vrf_id)
{
int s;
- s = socket(AF_INET, SOCK_DGRAM, 0);
+ frr_elevate_privs(&bglobal.bfdd_privs) {
+ s = vrf_socket(AF_INET, SOCK_DGRAM, 0, vrf_id, NULL);
+ }
if (s == -1)
log_fatal("echo-socket: socket: %s", strerror(errno));
@@ -1144,11 +1154,13 @@ int bp_echo_socket(void)
return s;
}
-int bp_echov6_socket(void)
+int bp_echov6_socket(vrf_id_t vrf_id)
{
int s;
- s = socket(AF_INET6, SOCK_DGRAM, 0);
+ frr_elevate_privs(&bglobal.bfdd_privs) {
+ s = vrf_socket(AF_INET6, SOCK_DGRAM, 0, vrf_id, NULL);
+ }
if (s == -1)
log_fatal("echov6-socket: socket: %s", strerror(errno));
diff --git a/bfdd/bfdd.c b/bfdd/bfdd.c
index 6023b5e4f..218f0883c 100644
--- a/bfdd/bfdd.c
+++ b/bfdd/bfdd.c
@@ -34,25 +34,13 @@ DEFINE_MTYPE(BFDD, BFDD_LABEL, "long-lived label memory");
DEFINE_MTYPE(BFDD, BFDD_CONTROL, "long-lived control socket memory");
DEFINE_MTYPE(BFDD, BFDD_SESSION_OBSERVER, "Session observer");
DEFINE_MTYPE(BFDD, BFDD_NOTIFICATION, "short-lived control notification data");
+DEFINE_MTYPE(BFDD, BFDD_VRF, "BFD VRF");
/* Master of threads. */
struct thread_master *master;
/* BFDd privileges */
-static zebra_capabilities_t _caps_p[] = {ZCAP_BIND};
-
-struct zebra_privs_t bfdd_privs = {
-#if defined(FRR_USER) && defined(FRR_GROUP)
- .user = FRR_USER,
- .group = FRR_GROUP,
-#endif
-#if defined(VTY_GROUP)
- .vty_group = VTY_GROUP,
-#endif
- .caps_p = _caps_p,
- .cap_num_p = array_size(_caps_p),
- .cap_num_i = 0,
-};
+static zebra_capabilities_t _caps_p[] = {ZCAP_BIND, ZCAP_SYS_ADMIN, ZCAP_NET_RAW};
void socket_close(int *s)
{
@@ -85,12 +73,7 @@ static void sigterm_handler(void)
/* Shutdown and free all protocol related memory. */
bfd_shutdown();
- /* Close all descriptors. */
- socket_close(&bglobal.bg_echo);
- socket_close(&bglobal.bg_shop);
- socket_close(&bglobal.bg_mhop);
- socket_close(&bglobal.bg_shop6);
- socket_close(&bglobal.bg_mhop6);
+ bfd_vrf_terminate();
/* Terminate and free() FRR related memory. */
frr_fini();
@@ -116,7 +99,7 @@ static struct quagga_signal_t bfd_signals[] = {
FRR_DAEMON_INFO(bfdd, BFD, .vty_port = 2617,
.proghelp = "Implementation of the BFD protocol.",
.signals = bfd_signals, .n_signals = array_size(bfd_signals),
- .privs = &bfdd_privs)
+ .privs = &bglobal.bfdd_privs)
#define OPTION_CTLSOCK 1001
static struct option longopts[] = {
@@ -153,15 +136,24 @@ struct bfd_state_str_list state_list[] = {
static void bg_init(void)
{
+ struct zebra_privs_t bfdd_privs = {
+#if defined(FRR_USER) && defined(FRR_GROUP)
+ .user = FRR_USER,
+ .group = FRR_GROUP,
+#endif
+#if defined(VTY_GROUP)
+ .vty_group = VTY_GROUP,
+#endif
+ .caps_p = _caps_p,
+ .cap_num_p = array_size(_caps_p),
+ .cap_num_i = 0,
+ };
+
TAILQ_INIT(&bglobal.bg_bcslist);
TAILQ_INIT(&bglobal.bg_obslist);
- bglobal.bg_shop = bp_udp_shop();
- bglobal.bg_mhop = bp_udp_mhop();
- bglobal.bg_shop6 = bp_udp6_shop();
- bglobal.bg_mhop6 = bp_udp6_mhop();
- bglobal.bg_echo = bp_echo_socket();
- bglobal.bg_echov6 = bp_echov6_socket();
+ memcpy(&bglobal.bfdd_privs, &bfdd_privs,
+ sizeof(bfdd_privs));
}
int main(int argc, char *argv[])
@@ -169,6 +161,9 @@ int main(int argc, char *argv[])
const char *ctl_path = BFDD_CONTROL_SOCKET;
int opt;
+ /* Initialize system sockets. */
+ bg_init();
+
frr_preinit(&bfdd_di, argc, argv);
frr_opt_add("", longopts,
" --bfdctl Specify bfdd control socket\n");
@@ -196,9 +191,6 @@ int main(int argc, char *argv[])
/* Initialize logging API. */
log_init(1, BLOG_DEBUG, &bfdd_di);
- /* Initialize system sockets. */
- bg_init();
-
/* Initialize control socket. */
control_init(ctl_path);
@@ -208,22 +200,11 @@ int main(int argc, char *argv[])
/* Initialize BFD data structures. */
bfd_initialize();
+ bfd_vrf_init();
+
/* Initialize zebra connection. */
- bfdd_zclient_init(&bfdd_privs);
-
- /* Add descriptors to the event loop. */
- thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_shop,
- &bglobal.bg_ev[0]);
- thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_mhop,
- &bglobal.bg_ev[1]);
- thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_shop6,
- &bglobal.bg_ev[2]);
- thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_mhop6,
- &bglobal.bg_ev[3]);
- thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_echo,
- &bglobal.bg_ev[4]);
- thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_echov6,
- &bglobal.bg_ev[5]);
+ bfdd_zclient_init(&bglobal.bfdd_privs);
+
thread_add_read(master, control_accept, NULL, bglobal.bg_csock,
&bglobal.bg_csockev);
diff --git a/bfdd/bfdd_vty.c b/bfdd/bfdd_vty.c
index 4efdd817c..75f6632db 100644
--- a/bfdd/bfdd_vty.c
+++ b/bfdd/bfdd_vty.c
@@ -64,7 +64,7 @@ static struct json_object *__display_peer_json(struct bfd_session *bs);
static struct json_object *_peer_json_header(struct bfd_session *bs);
static void _display_peer_json(struct vty *vty, struct bfd_session *bs);
static void _display_peer(struct vty *vty, struct bfd_session *bs);
-static void _display_all_peers(struct vty *vty, bool use_json);
+static void _display_all_peers(struct vty *vty, char *vrfname, bool use_json);
static void _display_peer_iter(struct hash_bucket *hb, void *arg);
static void _display_peer_json_iter(struct hash_bucket *hb, void *arg);
static void _display_peer_counter(struct vty *vty, struct bfd_session *bs);
@@ -72,7 +72,7 @@ static struct json_object *__display_peer_counters_json(struct bfd_session *bs);
static void _display_peer_counters_json(struct vty *vty, struct bfd_session *bs);
static void _display_peer_counter_iter(struct hash_bucket *hb, void *arg);
static void _display_peer_counter_json_iter(struct hash_bucket *hb, void *arg);
-static void _display_peers_counter(struct vty *vty, bool use_json);
+static void _display_peers_counter(struct vty *vty, char *vrfname, bool use_json);
static struct bfd_session *
_find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv,
const char *label, const char *peer_str,
@@ -90,7 +90,7 @@ DEFUN_NOSH(bfd_enter, bfd_enter_cmd, "bfd", "Configure BFD peers\n")
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 <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
@@ -126,15 +126,6 @@ DEFUN_NOSH(
if (argv_find(argv, argc, "vrf", &idx))
vrfname = argv[idx + 1]->arg;
- if (vrfname && ifname) {
- vty_out(vty, "%% VRF is not mixable with interface\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- if (vrfname && !mhop) {
- vty_out(vty, "%% VRF only applies with multihop.\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
strtosa(peer, &psa);
if (local) {
strtosa(local, &lsa);
@@ -360,7 +351,7 @@ DEFPY(bfd_no_peer, bfd_no_peer_cmd,
return CMD_WARNING_CONFIG_FAILED;
}
- if (ptm_bfd_ses_del(&bpc) != 0) {
+ if (ptm_bfd_sess_del(&bpc) != 0) {
vty_out(vty, "%% Failed to remove peer.\n");
return CMD_WARNING_CONFIG_FAILED;
}
@@ -549,19 +540,46 @@ static void _display_peer_json(struct vty *vty, struct bfd_session *bs)
json_object_free(jo);
}
+struct bfd_vrf_tuple {
+ char *vrfname;
+ struct vty *vty;
+ struct json_object *jo;
+};
+
static void _display_peer_iter(struct hash_bucket *hb, void *arg)
{
- struct vty *vty = arg;
+ struct bfd_vrf_tuple *bvt = (struct bfd_vrf_tuple *)arg;
+ struct vty *vty;
struct bfd_session *bs = hb->data;
+ if (!bvt)
+ return;
+ vty = bvt->vty;
+
+ if (bvt->vrfname) {
+ if (!bs->key.vrfname[0] ||
+ !strmatch(bs->key.vrfname, bvt->vrfname))
+ return;
+ }
_display_peer(vty, bs);
}
static void _display_peer_json_iter(struct hash_bucket *hb, void *arg)
{
- struct json_object *jo = arg, *jon = NULL;
+ struct bfd_vrf_tuple *bvt = (struct bfd_vrf_tuple *)arg;
+ struct json_object *jo, *jon = NULL;
struct bfd_session *bs = hb->data;
+ if (!bvt)
+ return;
+ jo = bvt->jo;
+
+ if (bvt->vrfname) {
+ if (!bs->key.vrfname[0] ||
+ !strmatch(bs->key.vrfname, bvt->vrfname))
+ return;
+ }
+
jon = __display_peer_json(bs);
if (jon == NULL) {
log_warning("%s: not enough memory", __func__);
@@ -571,18 +589,24 @@ static void _display_peer_json_iter(struct hash_bucket *hb, void *arg)
json_object_array_add(jo, jon);
}
-static void _display_all_peers(struct vty *vty, bool use_json)
+static void _display_all_peers(struct vty *vty, char *vrfname, bool use_json)
{
struct json_object *jo;
+ struct bfd_vrf_tuple bvt;
+
+ memset(&bvt, 0, sizeof(bvt));
+ bvt.vrfname = vrfname;
if (!use_json) {
+ bvt.vty = vty;
vty_out(vty, "BFD Peers:\n");
- bfd_id_iterate(_display_peer_iter, vty);
+ bfd_id_iterate(_display_peer_iter, &bvt);
return;
}
jo = json_object_new_array();
- bfd_id_iterate(_display_peer_json_iter, jo);
+ bvt.jo = jo;
+ bfd_id_iterate(_display_peer_json_iter, &bvt);
vty_out(vty, "%s\n", json_object_to_json_string_ext(jo, 0));
json_object_free(jo);
@@ -634,16 +658,38 @@ static void _display_peer_counters_json(struct vty *vty, struct bfd_session *bs)
static void _display_peer_counter_iter(struct hash_bucket *hb, void *arg)
{
- struct vty *vty = arg;
+ struct bfd_vrf_tuple *bvt = arg;
+ struct vty *vty;
struct bfd_session *bs = hb->data;
+ if (!bvt)
+ return;
+ vty = bvt->vty;
+
+ if (bvt->vrfname) {
+ if (!bs->key.vrfname[0] ||
+ !strmatch(bs->key.vrfname, bvt->vrfname))
+ return;
+ }
+
_display_peer_counter(vty, bs);
}
static void _display_peer_counter_json_iter(struct hash_bucket *hb, void *arg)
{
- struct json_object *jo = arg, *jon = NULL;
+ struct json_object *jo, *jon = NULL;
struct bfd_session *bs = hb->data;
+ struct bfd_vrf_tuple *bvt = arg;
+
+ if (!bvt)
+ return;
+ jo = bvt->jo;
+
+ if (bvt->vrfname) {
+ if (!bs->key.vrfname[0] ||
+ !strmatch(bs->key.vrfname, bvt->vrfname))
+ return;
+ }
jon = __display_peer_counters_json(bs);
if (jon == NULL) {
@@ -654,17 +700,22 @@ static void _display_peer_counter_json_iter(struct hash_bucket *hb, void *arg)
json_object_array_add(jo, jon);
}
-static void _display_peers_counter(struct vty *vty, bool use_json)
+static void _display_peers_counter(struct vty *vty, char *vrfname, bool use_json)
{
struct json_object *jo;
+ struct bfd_vrf_tuple bvt;
+ memset(&bvt, 0, sizeof(struct bfd_vrf_tuple));
+ bvt.vrfname = vrfname;
if (!use_json) {
+ bvt.vty = vty;
vty_out(vty, "BFD Peers:\n");
- bfd_id_iterate(_display_peer_counter_iter, vty);
+ bfd_id_iterate(_display_peer_counter_iter, &bvt);
return;
}
jo = json_object_new_array();
+ bvt.jo = jo;
bfd_id_iterate(_display_peer_counter_json_iter, jo);
vty_out(vty, "%s\n", json_object_to_json_string_ext(jo, 0));
@@ -734,24 +785,31 @@ _find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv,
/*
* Show commands.
*/
-DEFPY(bfd_show_peers, bfd_show_peers_cmd, "show bfd peers [json]",
+DEFPY(bfd_show_peers, bfd_show_peers_cmd, "show bfd [vrf <NAME>] peers [json]",
SHOW_STR
"Bidirection Forwarding Detection\n"
+ VRF_CMD_HELP_STR
"BFD peers status\n" JSON_STR)
{
- _display_all_peers(vty, use_json(argc, argv));
+ char *vrf_name = NULL;
+ int idx_vrf = 0;
+
+ if (argv_find(argv, argc, "vrf", &idx_vrf))
+ vrf_name = argv[idx_vrf + 1]->arg;
+
+ _display_all_peers(vty, vrf_name, use_json(argc, argv));
return CMD_SUCCESS;
}
DEFPY(bfd_show_peer, bfd_show_peer_cmd,
- "show bfd peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname|vrf NAME$vrfname}]> [json]",
+ "show bfd [vrf <NAME$vrfname>] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> [json]",
SHOW_STR
"Bidirection Forwarding Detection\n"
+ VRF_CMD_HELP_STR
"BFD peers status\n"
"Peer label\n" PEER_IPV4_STR PEER_IPV6_STR MHOP_STR LOCAL_STR
- LOCAL_IPV4_STR LOCAL_IPV6_STR INTERFACE_STR LOCAL_INTF_STR VRF_STR
- VRF_NAME_STR JSON_STR)
+ LOCAL_IPV4_STR LOCAL_IPV6_STR INTERFACE_STR LOCAL_INTF_STR JSON_STR)
{
struct bfd_session *bs;
@@ -772,9 +830,10 @@ DEFPY(bfd_show_peer, bfd_show_peer_cmd,
}
DEFPY(bfd_show_peer_counters, bfd_show_peer_counters_cmd,
- "show bfd peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname|vrf NAME$vrfname}]> counters [json]",
+ "show bfd [vrf <NAME$vrfname>] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> counters [json]",
SHOW_STR
"Bidirection Forwarding Detection\n"
+ VRF_CMD_HELP_STR
"BFD peers status\n"
"Peer label\n"
PEER_IPV4_STR
@@ -785,8 +844,6 @@ DEFPY(bfd_show_peer_counters, bfd_show_peer_counters_cmd,
LOCAL_IPV6_STR
INTERFACE_STR
LOCAL_INTF_STR
- VRF_STR
- VRF_NAME_STR
"Show BFD peer counters information\n"
JSON_STR)
{
@@ -807,14 +864,21 @@ DEFPY(bfd_show_peer_counters, bfd_show_peer_counters_cmd,
}
DEFPY(bfd_show_peers_counters, bfd_show_peers_counters_cmd,
- "show bfd peers counters [json]",
+ "show bfd [vrf <NAME>] peers counters [json]",
SHOW_STR
"Bidirection Forwarding Detection\n"
+ VRF_CMD_HELP_STR
"BFD peers status\n"
"Show BFD peer counters information\n"
JSON_STR)
{
- _display_peers_counter(vty, use_json(argc, argv));
+ char *vrf_name = NULL;
+ int idx_vrf = 0;
+
+ if (argv_find(argv, argc, "vrf", &idx_vrf))
+ vrf_name = argv[idx_vrf + 1]->arg;
+
+ _display_peers_counter(vty, vrf_name, use_json(argc, argv));
return CMD_SUCCESS;
}
diff --git a/bfdd/bsd.c b/bfdd/bsd.c
deleted file mode 100644
index 923fbd909..000000000
--- a/bfdd/bsd.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * *BSD specific code
- *
- * Copyright (C) 2018 Network Device Education Foundation, Inc. ("NetDEF")
- *
- * FRR is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * FRR is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with FRR; see the file COPYING. If not, write to the Free
- * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <zebra.h>
-
-#ifdef BFD_BSD
-
-#include <net/if.h>
-#include <net/if_types.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-
-#include <ifaddrs.h>
-
-#include "bfd.h"
-
-/*
- * Definitions.
- */
-int bp_bind_dev(int sd, const char *dev)
-{
- /*
- * *BSDs don't support `SO_BINDTODEVICE`, instead you must
- * manually specify the main address of the interface or use
- * BPF on the socket descriptor.
- */
- return 0;
-}
-
-#endif /* BFD_BSD */
diff --git a/bfdd/config.c b/bfdd/config.c
index cd57ea9fe..74e7d63d0 100644
--- a/bfdd/config.c
+++ b/bfdd/config.c
@@ -68,7 +68,7 @@ static int config_add(struct bfd_peer_cfg *bpc,
static int config_del(struct bfd_peer_cfg *bpc,
void *arg __attribute__((unused)))
{
- return ptm_bfd_ses_del(bpc) != 0;
+ return ptm_bfd_sess_del(bpc) != 0;
}
static int parse_config_json(struct json_object *jo, bpc_handle h, void *arg)
diff --git a/bfdd/linux.c b/bfdd/linux.c
deleted file mode 100644
index 3a76b459d..000000000
--- a/bfdd/linux.c
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Linux specific code
- *
- * Copyright (C) 2018 Network Device Education Foundation, Inc. ("NetDEF")
- *
- * FRR is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * FRR is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with FRR; see the file COPYING. If not, write to the Free
- * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <zebra.h>
-
-#ifdef BFD_LINUX
-
-#include "bfd.h"
-
-
-/*
- * Definitions.
- */
-int bp_bind_dev(int sd __attribute__((__unused__)),
- const char *dev __attribute__((__unused__)))
-{
- /*
- * TODO: implement this differently. It is not possible to
- * SO_BINDTODEVICE after the daemon has dropped its privileges.
- */
-#if 0
- size_t devlen = strlen(dev) + 1;
-
- if (setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, dev, devlen) == -1) {
- log_warning("%s: setsockopt(SO_BINDTODEVICE, \"%s\"): %s",
- __func__, dev, strerror(errno));
- return -1;
- }
-#endif
-
- return 0;
-}
-
-#endif /* BFD_LINUX */
diff --git a/bfdd/ptm_adapter.c b/bfdd/ptm_adapter.c
index 6f76a15a5..a12a3c196 100644
--- a/bfdd/ptm_adapter.c
+++ b/bfdd/ptm_adapter.c
@@ -58,7 +58,7 @@ static struct zclient *zclient;
static int _ptm_msg_address(struct stream *msg, int family, const void *addr);
static void _ptm_msg_read_address(struct stream *msg, struct sockaddr_any *sa);
-static int _ptm_msg_read(struct stream *msg, int command,
+static int _ptm_msg_read(struct stream *msg, int command, vrf_id_t vrf_id,
struct bfd_peer_cfg *bpc, struct ptm_client **pc);
static struct ptm_client *pc_lookup(uint32_t pid);
@@ -72,8 +72,8 @@ static struct ptm_client_notification *pcn_lookup(struct ptm_client *pc,
static void pcn_free(struct ptm_client_notification *pcn);
-static void bfdd_dest_register(struct stream *msg);
-static void bfdd_dest_deregister(struct stream *msg);
+static void bfdd_dest_register(struct stream *msg, vrf_id_t vrf_id);
+static void bfdd_dest_deregister(struct stream *msg, vrf_id_t vrf_id);
static void bfdd_client_register(struct stream *msg);
static void bfdd_client_deregister(struct stream *msg);
@@ -182,7 +182,10 @@ int ptm_bfd_notify(struct bfd_session *bs)
stream_reset(msg);
/* TODO: VRF handling */
- zclient_create_header(msg, ZEBRA_BFD_DEST_REPLAY, VRF_DEFAULT);
+ if (bs->vrf)
+ zclient_create_header(msg, ZEBRA_BFD_DEST_REPLAY, bs->vrf->vrf_id);
+ else
+ zclient_create_header(msg, ZEBRA_BFD_DEST_REPLAY, VRF_DEFAULT);
/* This header will be handled by `zebra_ptm.c`. */
stream_putl(msg, ZEBRA_INTERFACE_BFD_DEST_UPDATE);
@@ -256,7 +259,7 @@ stream_failure:
memset(sa, 0, sizeof(*sa));
}
-static int _ptm_msg_read(struct stream *msg, int command,
+static int _ptm_msg_read(struct stream *msg, int command, vrf_id_t vrf_id,
struct bfd_peer_cfg *bpc, struct ptm_client **pc)
{
uint32_t pid;
@@ -355,6 +358,18 @@ static int _ptm_msg_read(struct stream *msg, int command,
bpc->bpc_localif[ifnamelen] = 0;
}
}
+ if (vrf_id != VRF_DEFAULT) {
+ struct vrf *vrf;
+
+ vrf = vrf_lookup_by_id(vrf_id);
+ if (vrf) {
+ bpc->bpc_has_vrfname = true;
+ strlcpy(bpc->bpc_vrfname, vrf->name, sizeof(bpc->bpc_vrfname));
+ } else {
+ log_error("ptm-read: vrf id %u could not be identified", vrf_id);
+ return -1;
+ }
+ }
/* Sanity check: peer and local address must match IP types. */
if (bpc->bpc_local.sa_sin.sin_family != 0
@@ -370,7 +385,7 @@ stream_failure:
return -1;
}
-static void bfdd_dest_register(struct stream *msg)
+static void bfdd_dest_register(struct stream *msg, vrf_id_t vrf_id)
{
struct ptm_client *pc;
struct ptm_client_notification *pcn;
@@ -378,7 +393,7 @@ static void bfdd_dest_register(struct stream *msg)
struct bfd_peer_cfg bpc;
/* Read the client context and peer data. */
- if (_ptm_msg_read(msg, ZEBRA_BFD_DEST_REGISTER, &bpc, &pc) == -1)
+ if (_ptm_msg_read(msg, ZEBRA_BFD_DEST_REGISTER, vrf_id, &bpc, &pc) == -1)
return;
DEBUG_PRINTBPC(&bpc);
@@ -408,7 +423,7 @@ static void bfdd_dest_register(struct stream *msg)
ptm_bfd_notify(bs);
}
-static void bfdd_dest_deregister(struct stream *msg)
+static void bfdd_dest_deregister(struct stream *msg, vrf_id_t vrf_id)
{
struct ptm_client *pc;
struct ptm_client_notification *pcn;
@@ -416,7 +431,7 @@ static void bfdd_dest_deregister(struct stream *msg)
struct bfd_peer_cfg bpc;
/* Read the client context and peer data. */
- if (_ptm_msg_read(msg, ZEBRA_BFD_DEST_DEREGISTER, &bpc, &pc) == -1)
+ if (_ptm_msg_read(msg, ZEBRA_BFD_DEST_DEREGISTER, vrf_id, &bpc, &pc) == -1)
return;
DEBUG_PRINTBPC(&bpc);
@@ -434,7 +449,7 @@ static void bfdd_dest_deregister(struct stream *msg)
if (bs->refcount ||
BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG))
return;
- ptm_bfd_ses_del(&bpc);
+ ptm_bfd_sess_del(&bpc);
}
/*
@@ -497,10 +512,10 @@ static int bfdd_replay(ZAPI_CALLBACK_ARGS)
switch (rcmd) {
case ZEBRA_BFD_DEST_REGISTER:
case ZEBRA_BFD_DEST_UPDATE:
- bfdd_dest_register(msg);
+ bfdd_dest_register(msg, vrf_id);
break;
case ZEBRA_BFD_DEST_DEREGISTER:
- bfdd_dest_deregister(msg);
+ bfdd_dest_deregister(msg, vrf_id);
break;
case ZEBRA_BFD_CLIENT_REGISTER:
bfdd_client_register(msg);
@@ -548,15 +563,21 @@ static void bfdd_sessions_enable_interface(struct interface *ifp)
{
struct bfd_session_observer *bso;
struct bfd_session *bs;
+ struct vrf *vrf;
TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
+ bs = bso->bso_bs;
if (bso->bso_isinterface == false)
continue;
-
/* Interface name mismatch. */
- bs = bso->bso_bs;
if (strcmp(ifp->name, bs->key.ifname))
continue;
+ vrf = vrf_lookup_by_id(ifp->vrf_id);
+ if (!vrf)
+ continue;
+ if (bs->key.vrfname[0] &&
+ strcmp(vrf->name, bs->key.vrfname))
+ continue;
/* Skip enabled sessions. */
if (bs->sock != -1)
continue;
@@ -586,7 +607,52 @@ static void bfdd_sessions_disable_interface(struct interface *ifp)
/* Try to enable it. */
bfd_session_disable(bs);
- TAILQ_INSERT_HEAD(&bglobal.bg_obslist, bso, bso_entry);
+ }
+}
+
+void bfdd_sessions_enable_vrf(struct vrf *vrf)
+{
+ struct bfd_session_observer *bso;
+ struct bfd_session *bs;
+
+ /* it may affect configs without interfaces */
+ TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
+ bs = bso->bso_bs;
+ if (bs->vrf)
+ continue;
+ if (bs->key.vrfname[0] &&
+ strcmp(vrf->name, bs->key.vrfname))
+ continue;
+ /* need to update the vrf information on
+ * bs so that callbacks are handled
+ */
+ bs->vrf = vrf;
+ /* Skip enabled sessions. */
+ if (bs->sock != -1)
+ continue;
+ /* Try to enable it. */
+ bfd_session_enable(bs);
+ }
+}
+
+void bfdd_sessions_disable_vrf(struct vrf *vrf)
+{
+ struct bfd_session_observer *bso;
+ struct bfd_session *bs;
+
+ TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
+ if (bso->bso_isinterface)
+ continue;
+ bs = bso->bso_bs;
+ if (bs->key.vrfname[0] &&
+ strcmp(vrf->name, bs->key.vrfname))
+ continue;
+ /* Skip disabled sessions. */
+ if (bs->sock == -1)
+ continue;
+
+ /* Try to enable it. */
+ bfd_session_disable(bs);
}
}
@@ -701,6 +767,20 @@ void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv)
zclient->interface_address_delete = bfdd_interface_address_update;
}
+void bfdd_zclient_register(vrf_id_t vrf_id)
+{
+ if (!zclient || zclient->sock < 0)
+ return;
+ zclient_send_reg_requests(zclient, vrf_id);
+}
+
+void bfdd_zclient_unregister(vrf_id_t vrf_id)
+{
+ if (!zclient || zclient->sock < 0)
+ return;
+ zclient_send_dereg_requests(zclient, vrf_id);
+}
+
void bfdd_zclient_stop(void)
{
zclient_stop(zclient);
diff --git a/bfdd/subdir.am b/bfdd/subdir.am
index 334e974b0..e88b982ec 100644
--- a/bfdd/subdir.am
+++ b/bfdd/subdir.am
@@ -14,11 +14,9 @@ bfdd_libbfd_a_SOURCES = \
bfdd/bfd.c \
bfdd/bfdd_vty.c \
bfdd/bfd_packet.c \
- bfdd/bsd.c \
bfdd/config.c \
bfdd/control.c \
bfdd/event.c \
- bfdd/linux.c \
bfdd/log.c \
bfdd/ptm_adapter.c \
# end
diff --git a/bgpd/bgp_bfd.c b/bgpd/bgp_bfd.c
index 45e45977a..a9c30acaf 100644
--- a/bgpd/bgp_bfd.c
+++ b/bgpd/bgp_bfd.c
@@ -96,13 +96,12 @@ int bgp_bfd_is_peer_multihop(struct peer *peer)
static void bgp_bfd_peer_sendmsg(struct peer *peer, int command)
{
struct bfd_info *bfd_info;
- vrf_id_t vrf_id = VRF_DEFAULT;
int multihop;
+ vrf_id_t vrf_id;
bfd_info = (struct bfd_info *)peer->bfd_info;
- if (peer->bgp->inst_type == BGP_INSTANCE_TYPE_VRF)
- vrf_id = peer->bgp->vrf_id;
+ vrf_id = peer->bgp->vrf_id;
if (command == ZEBRA_BFD_DEST_DEREGISTER) {
multihop =
@@ -244,7 +243,7 @@ static int bgp_bfd_dest_replay(ZAPI_CALLBACK_ARGS)
zlog_debug("Zebra: BFD Dest replay request");
/* Send the client registration */
- bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER);
+ bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id);
/* Replay the peer, if BFD is enabled in BGP */
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index d47c1f963..a45480fdc 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -2441,7 +2441,7 @@ static void bgp_zebra_connected(struct zclient *zclient)
bgp_zebra_instance_register(bgp);
/* Send the client registration */
- bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER);
+ bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, bgp->vrf_id);
/* tell label pool that zebra is connected */
bgp_lp_event_zebra_up();
diff --git a/doc/user/bfd.rst b/doc/user/bfd.rst
index 986d1494a..a7c5cf28b 100644
--- a/doc/user/bfd.rst
+++ b/doc/user/bfd.rst
@@ -72,8 +72,7 @@ BFDd Commands
peer listener to and the address we should use to send the packets.
This option is mandatory for IPv6.
- `interface` selects which interface we should use. This option
- conflicts with `vrf`.
+ `interface` selects which interface we should use.
`vrf` selects which domain we want to use.
@@ -82,13 +81,13 @@ BFDd Commands
Stops and removes the selected peer.
-.. index:: show bfd peers [json]
-.. clicmd:: show bfd peers [json]
+.. index:: show bfd [vrf NAME] peers [json]
+.. clicmd:: show bfd [vrf NAME] peers [json]
Show all configured BFD peers information and current status.
-.. index:: show bfd peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname|vrf NAME$vrfname}]> [json]
-.. clicmd:: show bfd peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname|vrf NAME$vrfname}]> [json]
+.. index:: show bfd [vrf NAME$vrfname] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> [json]
+.. clicmd:: show bfd [vrf NAME$vrfname] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> [json]
Show status for a specific BFD peer.
@@ -296,6 +295,11 @@ Here are the available peer configurations:
shutdown
!
+ ! configure a peer on an interface from a separate vrf
+ peer 192.168.0.5 interface eth1 vrf vrf2
+ no shutdown
+ !
+
! remove a peer
no peer 192.168.0.3 vrf foo
diff --git a/isisd/isis_bfd.c b/isisd/isis_bfd.c
index a98c44eeb..fccef0169 100644
--- a/isisd/isis_bfd.c
+++ b/isisd/isis_bfd.c
@@ -139,7 +139,7 @@ static int isis_bfd_interface_dest_update(ZAPI_CALLBACK_ARGS)
static int isis_bfd_nbr_replay(ZAPI_CALLBACK_ARGS)
{
- bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER);
+ bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id);
struct listnode *anode;
struct isis_area *area;
@@ -167,7 +167,7 @@ static void isis_bfd_zebra_connected(struct zclient *zclient)
if (orig_zebra_connected)
orig_zebra_connected(zclient);
- bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER);
+ bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, VRF_DEFAULT);
}
static void bfd_debug(struct in_addr *dst, struct in_addr *src,
diff --git a/lib/bfd.c b/lib/bfd.c
index 7e27a64de..a8956c315 100644
--- a/lib/bfd.c
+++ b/lib/bfd.c
@@ -433,7 +433,8 @@ void bfd_show_info(struct vty *vty, struct bfd_info *bfd_info, int multihop,
* bfd_client_sendmsg - Format and send a client register
* command to Zebra to be forwarded to BFD
*/
-void bfd_client_sendmsg(struct zclient *zclient, int command)
+void bfd_client_sendmsg(struct zclient *zclient, int command,
+ vrf_id_t vrf_id)
{
struct stream *s;
int ret;
@@ -450,7 +451,7 @@ void bfd_client_sendmsg(struct zclient *zclient, int command)
s = zclient->obuf;
stream_reset(s);
- zclient_create_header(s, command, VRF_DEFAULT);
+ zclient_create_header(s, command, vrf_id);
stream_putl(s, getpid());
diff --git a/lib/bfd.h b/lib/bfd.h
index a93875c4c..d02110a99 100644
--- a/lib/bfd.h
+++ b/lib/bfd.h
@@ -102,7 +102,8 @@ extern void bfd_show_info(struct vty *vty, struct bfd_info *bfd_info,
int multihop, int extra_space, bool use_json,
json_object *json_obj);
-extern void bfd_client_sendmsg(struct zclient *zclient, int command);
+extern void bfd_client_sendmsg(struct zclient *zclient, int command,
+ vrf_id_t vrf_id);
extern void bfd_gbl_init(void);
diff --git a/lib/vrf.c b/lib/vrf.c
index 6d9ac2e1e..6ec3cc8e0 100644
--- a/lib/vrf.c
+++ b/lib/vrf.c
@@ -904,10 +904,16 @@ vrf_id_t vrf_get_default_id(void)
int vrf_bind(vrf_id_t vrf_id, int fd, const char *name)
{
int ret = 0;
+ struct interface *ifp;
if (fd < 0 || name == NULL)
return fd;
- if (vrf_is_backend_netns())
+ /* the device should exist
+ * otherwise we should return
+ * case ifname = vrf in netns mode => return
+ */
+ ifp = if_lookup_by_name(name, vrf_id);
+ if (!ifp)
return fd;
#ifdef SO_BINDTODEVICE
ret = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, name, strlen(name)+1);
diff --git a/ospf6d/ospf6_bfd.c b/ospf6d/ospf6_bfd.c
index 3394bd75d..7a26af1f0 100644
--- a/ospf6d/ospf6_bfd.c
+++ b/ospf6d/ospf6_bfd.c
@@ -151,7 +151,7 @@ static int ospf6_bfd_nbr_replay(ZAPI_CALLBACK_ARGS)
zlog_debug("Zebra: BFD Dest replay request");
/* Send the client registration */
- bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER);
+ bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id);
/* Replay the neighbor, if BFD is enabled on the interface*/
FOR_ALL_INTERFACES (vrf, ifp) {
diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c
index 8db4ffef1..af16c5aa7 100644
--- a/ospf6d/ospf6_zebra.c
+++ b/ospf6d/ospf6_zebra.c
@@ -571,7 +571,7 @@ uint8_t ospf6_distance_apply(struct prefix_ipv6 *p, struct ospf6_route * or)
static void ospf6_zebra_connected(struct zclient *zclient)
{
/* Send the client registration */
- bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER);
+ bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, VRF_DEFAULT);
zclient_send_reg_requests(zclient, VRF_DEFAULT);
}
diff --git a/ospfd/ospf_bfd.c b/ospfd/ospf_bfd.c
index 6bff5b8dd..c8ad6d04f 100644
--- a/ospfd/ospf_bfd.c
+++ b/ospfd/ospf_bfd.c
@@ -156,7 +156,7 @@ static int ospf_bfd_nbr_replay(ZAPI_CALLBACK_ARGS)
}
/* Send the client registration */
- bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER);
+ bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id);
/* Replay the neighbor, if BFD is enabled in OSPF */
for (ALL_LIST_ELEMENTS(om->ospf, node, onode, ospf)) {
diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c
index 16796e68f..c178e367d 100644
--- a/ospfd/ospf_zebra.c
+++ b/ospfd/ospf_zebra.c
@@ -1565,7 +1565,7 @@ void ospf_zebra_vrf_deregister(struct ospf *ospf)
static void ospf_zebra_connected(struct zclient *zclient)
{
/* Send the client registration */
- bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER);
+ bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, VRF_DEFAULT);
zclient_send_reg_requests(zclient, VRF_DEFAULT);
}
diff --git a/pimd/pim_bfd.c b/pimd/pim_bfd.c
index 82087c4c5..300261e5a 100644
--- a/pimd/pim_bfd.c
+++ b/pimd/pim_bfd.c
@@ -297,7 +297,7 @@ static int pim_bfd_nbr_replay(ZAPI_CALLBACK_ARGS)
struct vrf *vrf = NULL;
/* Send the client registration */
- bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER);
+ bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id);
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
FOR_ALL_INTERFACES (vrf, ifp) {
diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c
index b27d2e058..25ac307ac 100644
--- a/pimd/pim_zebra.c
+++ b/pimd/pim_zebra.c
@@ -780,7 +780,7 @@ void sched_rpf_cache_refresh(struct pim_instance *pim)
static void pim_zebra_connected(struct zclient *zclient)
{
/* Send the client registration */
- bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER);
+ bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, router->vrf_id);
zclient_send_reg_requests(zclient, router->vrf_id);
}
diff --git a/tests/topotests/bfd-vrf-topo1/__init__.py b/tests/topotests/bfd-vrf-topo1/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/bfd-vrf-topo1/__init__.py
diff --git a/tests/topotests/bfd-vrf-topo1/r1/bfdd.conf b/tests/topotests/bfd-vrf-topo1/r1/bfdd.conf
new file mode 100644
index 000000000..3466e6a3c
--- /dev/null
+++ b/tests/topotests/bfd-vrf-topo1/r1/bfdd.conf
@@ -0,0 +1,6 @@
+bfd
+ peer 192.168.0.2 vrf r1-cust1
+ echo-mode
+ no shutdown
+ !
+!
diff --git a/tests/topotests/bfd-vrf-topo1/r1/bgp_prefixes.json b/tests/topotests/bfd-vrf-topo1/r1/bgp_prefixes.json
new file mode 100644
index 000000000..4b2cc1ad6
--- /dev/null
+++ b/tests/topotests/bfd-vrf-topo1/r1/bgp_prefixes.json
@@ -0,0 +1,52 @@
+{
+ "routes": {
+ "10.254.254.2/32": [
+ {
+ "aspath": "102",
+ "prefix": "10.254.254.2",
+ "valid": true,
+ "peerId": "192.168.0.2",
+ "prefixLen": 32,
+ "nexthops": [
+ {
+ "ip": "192.168.0.2",
+ "used": true,
+ "afi": "ipv4"
+ }
+ ]
+ }
+ ],
+ "10.254.254.3/32": [
+ {
+ "aspath": "102 103",
+ "prefix": "10.254.254.3",
+ "valid": true,
+ "peerId": "192.168.0.2",
+ "prefixLen": 32,
+ "nexthops": [
+ {
+ "ip": "192.168.0.2",
+ "used": true,
+ "afi": "ipv4"
+ }
+ ]
+ }
+ ],
+ "10.254.254.4/32": [
+ {
+ "aspath": "102 104",
+ "prefix": "10.254.254.4",
+ "valid": true,
+ "peerId": "192.168.0.2",
+ "prefixLen": 32,
+ "nexthops": [
+ {
+ "ip": "192.168.0.2",
+ "used": true,
+ "afi": "ipv4"
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/bfd-vrf-topo1/r1/bgp_summary.json b/tests/topotests/bfd-vrf-topo1/r1/bgp_summary.json
new file mode 100644
index 000000000..fa07d60df
--- /dev/null
+++ b/tests/topotests/bfd-vrf-topo1/r1/bgp_summary.json
@@ -0,0 +1,11 @@
+{
+ "ipv4Unicast": {
+ "as": 101,
+ "peers": {
+ "192.168.0.2": {
+ "remoteAs": 102,
+ "state": "Established"
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bfd-vrf-topo1/r1/bgpd.conf b/tests/topotests/bfd-vrf-topo1/r1/bgpd.conf
new file mode 100644
index 000000000..7ad4e2bd7
--- /dev/null
+++ b/tests/topotests/bfd-vrf-topo1/r1/bgpd.conf
@@ -0,0 +1,8 @@
+router bgp 101 vrf r1-cust1
+ neighbor 192.168.0.2 remote-as 102
+! neighbor 192.168.0.2 ebgp-multihop 10
+ neighbor 192.168.0.2 bfd
+ address-family ipv4 unicast
+ network 10.254.254.1/32
+ exit-address-family
+!
diff --git a/tests/topotests/bfd-vrf-topo1/r1/peers.json b/tests/topotests/bfd-vrf-topo1/r1/peers.json
new file mode 100644
index 000000000..f49768ff7
--- /dev/null
+++ b/tests/topotests/bfd-vrf-topo1/r1/peers.json
@@ -0,0 +1,8 @@
+[
+ {
+ "remote-receive-interval": 1000,
+ "remote-transmit-interval": 500,
+ "peer": "192.168.0.2",
+ "status": "up"
+ }
+]
diff --git a/tests/topotests/bfd-vrf-topo1/r1/zebra.conf b/tests/topotests/bfd-vrf-topo1/r1/zebra.conf
new file mode 100644
index 000000000..fcd1e7db1
--- /dev/null
+++ b/tests/topotests/bfd-vrf-topo1/r1/zebra.conf
@@ -0,0 +1,3 @@
+interface r1-eth0 vrf r1-cust1
+ ip address 192.168.0.1/24
+!
diff --git a/tests/topotests/bfd-vrf-topo1/r2/bfdd.conf b/tests/topotests/bfd-vrf-topo1/r2/bfdd.conf
new file mode 100644
index 000000000..3481ea8c8
--- /dev/null
+++ b/tests/topotests/bfd-vrf-topo1/r2/bfdd.conf
@@ -0,0 +1,12 @@
+bfd
+ peer 192.168.0.1 vrf r2-cust1
+ receive-interval 1000
+ transmit-interval 500
+ echo-mode
+ no shutdown
+ !
+ peer 192.168.1.1 vrf r2-cust1
+ echo-mode
+ no shutdown
+ !
+!
diff --git a/tests/topotests/bfd-vrf-topo1/r2/bgp_prefixes.json b/tests/topotests/bfd-vrf-topo1/r2/bgp_prefixes.json
new file mode 100644
index 000000000..39f3c0a83
--- /dev/null
+++ b/tests/topotests/bfd-vrf-topo1/r2/bgp_prefixes.json
@@ -0,0 +1,52 @@
+{
+ "routes": {
+ "10.254.254.1/32": [
+ {
+ "aspath": "101",
+ "prefix": "10.254.254.1",
+ "valid": true,
+ "peerId": "192.168.0.1",
+ "prefixLen": 32,
+ "nexthops": [
+ {
+ "ip": "192.168.0.1",
+ "used": true,
+ "afi": "ipv4"
+ }
+ ]
+ }
+ ],
+ "10.254.254.3/32": [
+ {
+ "aspath": "103",
+ "prefix": "10.254.254.3",
+ "valid": true,
+ "peerId": "192.168.1.1",
+ "prefixLen": 32,
+ "nexthops": [
+ {
+ "ip": "192.168.1.1",
+ "used": true,
+ "afi": "ipv4"
+ }
+ ]
+ }
+ ],
+ "10.254.254.4/32": [
+ {
+ "aspath": "104",
+ "prefix": "10.254.254.4",
+ "valid": true,
+ "peerId": "192.168.2.1",
+ "prefixLen": 32,
+ "nexthops": [
+ {
+ "ip": "192.168.2.1",
+ "used": true,
+ "afi": "ipv4"
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/bfd-vrf-topo1/r2/bgp_summary.json b/tests/topotests/bfd-vrf-topo1/r2/bgp_summary.json
new file mode 100644
index 000000000..c0ef11ac5
--- /dev/null
+++ b/tests/topotests/bfd-vrf-topo1/r2/bgp_summary.json
@@ -0,0 +1,19 @@
+{
+ "ipv4Unicast": {
+ "as": 102,
+ "peers": {
+ "192.168.0.1": {
+ "remoteAs": 101,
+ "state": "Established"
+ },
+ "192.168.1.1": {
+ "remoteAs": 103,
+ "state": "Established"
+ },
+ "192.168.2.1": {
+ "remoteAs": 104,
+ "state": "Established"
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bfd-vrf-topo1/r2/bgpd.conf b/tests/topotests/bfd-vrf-topo1/r2/bgpd.conf
new file mode 100644
index 000000000..0715ea32a
--- /dev/null
+++ b/tests/topotests/bfd-vrf-topo1/r2/bgpd.conf
@@ -0,0 +1,11 @@
+router bgp 102 vrf r2-cust1
+ neighbor 192.168.0.1 remote-as 101
+ neighbor 192.168.0.1 bfd
+ neighbor 192.168.1.1 remote-as 103
+ neighbor 192.168.1.1 bfd
+ neighbor 192.168.2.1 remote-as 104
+ neighbor 192.168.2.1 bfd
+ address-family ipv4 unicast
+ network 10.254.254.2/32
+ exit-address-family
+!
diff --git a/tests/topotests/bfd-vrf-topo1/r2/peers.json b/tests/topotests/bfd-vrf-topo1/r2/peers.json
new file mode 100644
index 000000000..5035d643c
--- /dev/null
+++ b/tests/topotests/bfd-vrf-topo1/r2/peers.json
@@ -0,0 +1,17 @@
+[
+ {
+ "peer": "192.168.0.1",
+ "status": "up"
+ },
+ {
+ "remote-echo-interval": 100,
+ "peer": "192.168.1.1",
+ "status": "up"
+ },
+ {
+ "remote-transmit-interval": 2000,
+ "remote-receive-interval": 2000,
+ "peer": "192.168.2.1",
+ "status": "up"
+ }
+]
diff --git a/tests/topotests/bfd-vrf-topo1/r2/zebra.conf b/tests/topotests/bfd-vrf-topo1/r2/zebra.conf
new file mode 100644
index 000000000..daffd1912
--- /dev/null
+++ b/tests/topotests/bfd-vrf-topo1/r2/zebra.conf
@@ -0,0 +1,9 @@
+interface r2-eth0 vrf r2-cust1
+ ip address 192.168.0.2/24
+!
+interface r2-eth1 vrf r2-cust1
+ ip address 192.168.1.2/24
+!
+interface r2-eth2 vrf r2-cust1
+ ip address 192.168.2.2/24
+!
diff --git a/tests/topotests/bfd-vrf-topo1/r3/bfdd.conf b/tests/topotests/bfd-vrf-topo1/r3/bfdd.conf
new file mode 100644
index 000000000..f6921b781
--- /dev/null
+++ b/tests/topotests/bfd-vrf-topo1/r3/bfdd.conf
@@ -0,0 +1,7 @@
+bfd
+ peer 192.168.1.2 vrf r3-cust1
+ echo-interval 100
+ echo-mode
+ no shutdown
+ !
+!
diff --git a/tests/topotests/bfd-vrf-topo1/r3/bgp_prefixes.json b/tests/topotests/bfd-vrf-topo1/r3/bgp_prefixes.json
new file mode 100644
index 000000000..c92d4e052
--- /dev/null
+++ b/tests/topotests/bfd-vrf-topo1/r3/bgp_prefixes.json
@@ -0,0 +1,52 @@
+{
+ "routes": {
+ "10.254.254.1/32": [
+ {
+ "aspath": "102 101",
+ "prefix": "10.254.254.1",
+ "valid": true,
+ "peerId": "192.168.1.2",
+ "prefixLen": 32,
+ "nexthops": [
+ {
+ "ip": "192.168.1.2",
+ "used": true,
+ "afi": "ipv4"
+ }
+ ]
+ }
+ ],
+ "10.254.254.2/32": [
+ {
+ "aspath": "102",
+ "prefix": "10.254.254.2",
+ "valid": true,
+ "peerId": "192.168.1.2",
+ "prefixLen": 32,
+ "nexthops": [
+ {
+ "ip": "192.168.1.2",
+ "used": true,
+ "afi": "ipv4"
+ }
+ ]
+ }
+ ],
+ "10.254.254.4/32": [
+ {
+ "aspath": "102 104",
+ "prefix": "10.254.254.4",
+ "valid": true,
+ "peerId": "192.168.1.2",
+ "prefixLen": 32,
+ "nexthops": [
+ {
+ "ip": "192.168.1.2",
+ "used": true,
+ "afi": "ipv4"
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/bfd-vrf-topo1/r3/bgp_summary.json b/tests/topotests/bfd-vrf-topo1/r3/bgp_summary.json
new file mode 100644
index 000000000..d47833377
--- /dev/null
+++ b/tests/topotests/bfd-vrf-topo1/r3/bgp_summary.json
@@ -0,0 +1,11 @@
+{
+ "ipv4Unicast": {
+ "as": 103,
+ "peers": {
+ "192.168.1.2": {
+ "remoteAs": 102,
+ "state": "Established"
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bfd-vrf-topo1/r3/bgpd.conf b/tests/topotests/bfd-vrf-topo1/r3/bgpd.conf
new file mode 100644
index 000000000..277f027d5
--- /dev/null
+++ b/tests/topotests/bfd-vrf-topo1/r3/bgpd.conf
@@ -0,0 +1,7 @@
+router bgp 103 vrf r3-cust1
+ neighbor 192.168.1.2 remote-as 102
+ neighbor 192.168.1.2 bfd
+ address-family ipv4 unicast
+ network 10.254.254.3/32
+ exit-address-family
+!
diff --git a/tests/topotests/bfd-vrf-topo1/r3/peers.json b/tests/topotests/bfd-vrf-topo1/r3/peers.json
new file mode 100644
index 000000000..ef3800864
--- /dev/null
+++ b/tests/topotests/bfd-vrf-topo1/r3/peers.json
@@ -0,0 +1,6 @@
+[
+ {
+ "peer": "192.168.1.2",
+ "status": "up"
+ }
+]
diff --git a/tests/topotests/bfd-vrf-topo1/r3/zebra.conf b/tests/topotests/bfd-vrf-topo1/r3/zebra.conf
new file mode 100644
index 000000000..f727c2d63
--- /dev/null
+++ b/tests/topotests/bfd-vrf-topo1/r3/zebra.conf
@@ -0,0 +1,3 @@
+interface r3-eth0 vrf r3-cust1
+ ip address 192.168.1.1/24
+!
diff --git a/tests/topotests/bfd-vrf-topo1/r4/bfdd.conf b/tests/topotests/bfd-vrf-topo1/r4/bfdd.conf
new file mode 100644
index 000000000..a56a3a0d3
--- /dev/null
+++ b/tests/topotests/bfd-vrf-topo1/r4/bfdd.conf
@@ -0,0 +1,7 @@
+bfd
+ peer 192.168.2.2 vrf r4-cust1
+ transmit-interval 2000
+ receive-interval 2000
+ no shutdown
+ !
+!
diff --git a/tests/topotests/bfd-vrf-topo1/r4/bgp_prefixes.json b/tests/topotests/bfd-vrf-topo1/r4/bgp_prefixes.json
new file mode 100644
index 000000000..cc8510dd6
--- /dev/null
+++ b/tests/topotests/bfd-vrf-topo1/r4/bgp_prefixes.json
@@ -0,0 +1,52 @@
+{
+ "routes": {
+ "10.254.254.1/32": [
+ {
+ "aspath": "102 101",
+ "prefix": "10.254.254.1",
+ "valid": true,
+ "peerId": "192.168.2.2",
+ "prefixLen": 32,
+ "nexthops": [
+ {
+ "ip": "192.168.2.2",
+ "used": true,
+ "afi": "ipv4"
+ }
+ ]
+ }
+ ],
+ "10.254.254.2/32": [
+ {
+ "aspath": "102",
+ "prefix": "10.254.254.2",
+ "valid": true,
+ "peerId": "192.168.2.2",
+ "prefixLen": 32,
+ "nexthops": [
+ {
+ "ip": "192.168.2.2",
+ "used": true,
+ "afi": "ipv4"
+ }
+ ]
+ }
+ ],
+ "10.254.254.3/32": [
+ {
+ "aspath": "102 103",
+ "prefix": "10.254.254.3",
+ "valid": true,
+ "peerId": "192.168.2.2",
+ "prefixLen": 32,
+ "nexthops": [
+ {
+ "ip": "192.168.2.2",
+ "used": true,
+ "afi": "ipv4"
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/bfd-vrf-topo1/r4/bgp_summary.json b/tests/topotests/bfd-vrf-topo1/r4/bgp_summary.json
new file mode 100644
index 000000000..7d81784b5
--- /dev/null
+++ b/tests/topotests/bfd-vrf-topo1/r4/bgp_summary.json
@@ -0,0 +1,11 @@
+{
+ "ipv4Unicast": {
+ "as": 104,
+ "peers": {
+ "192.168.2.2": {
+ "remoteAs": 102,
+ "state": "Established"
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bfd-vrf-topo1/r4/bgpd.conf b/tests/topotests/bfd-vrf-topo1/r4/bgpd.conf
new file mode 100644
index 000000000..66bf28587
--- /dev/null
+++ b/tests/topotests/bfd-vrf-topo1/r4/bgpd.conf
@@ -0,0 +1,7 @@
+router bgp 104 vrf r4-cust1
+ neighbor 192.168.2.2 remote-as 102
+ neighbor 192.168.2.2 bfd
+ address-family ipv4 unicast
+ network 10.254.254.4/32
+ exit-address-family
+!
diff --git a/tests/topotests/bfd-vrf-topo1/r4/peers.json b/tests/topotests/bfd-vrf-topo1/r4/peers.json
new file mode 100644
index 000000000..37140089e
--- /dev/null
+++ b/tests/topotests/bfd-vrf-topo1/r4/peers.json
@@ -0,0 +1,6 @@
+[
+ {
+ "peer": "192.168.2.2",
+ "status": "up"
+ }
+]
diff --git a/tests/topotests/bfd-vrf-topo1/r4/zebra.conf b/tests/topotests/bfd-vrf-topo1/r4/zebra.conf
new file mode 100644
index 000000000..69770dd2b
--- /dev/null
+++ b/tests/topotests/bfd-vrf-topo1/r4/zebra.conf
@@ -0,0 +1,3 @@
+interface r4-eth0 vrf r4-cust1
+ ip address 192.168.2.1/24
+!
diff --git a/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.dot b/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.dot
new file mode 100644
index 000000000..c84ace278
--- /dev/null
+++ b/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.dot
@@ -0,0 +1,73 @@
+## Color coding:
+#########################
+## Main FRR: #f08080 red
+## Switches: #d0e0d0 gray
+## RIP: #19e3d9 Cyan
+## RIPng: #fcb314 dark yellow
+## OSPFv2: #32b835 Green
+## OSPFv3: #19e3d9 Cyan
+## ISIS IPv4 #fcb314 dark yellow
+## ISIS IPv6 #9a81ec purple
+## BGP IPv4 #eee3d3 beige
+## BGP IPv6 #fdff00 yellow
+##### Colors (see http://www.color-hex.com/)
+
+graph template {
+ label="bfd-topo1";
+
+ # Routers
+ r1 [
+ shape=doubleoctagon,
+ label="r1",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r2 [
+ shape=doubleoctagon
+ label="r2",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r3 [
+ shape=doubleoctagon
+ label="r3",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r4 [
+ shape=doubleoctagon
+ label="r4",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+
+ # Switches
+ sw1 [
+ shape=oval,
+ label="sw1\n192.168.0.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ sw2 [
+ shape=oval,
+ label="sw2\n192.168.1.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ sw3 [
+ shape=oval,
+ label="sw3\n192.168.2.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+
+ # Connections
+ r1 -- sw1 [label="eth0\n.1"];
+ r2 -- sw1 [label="eth0\n.2"];
+
+ r3 -- sw2 [label="eth0\n.1"];
+ r2 -- sw2 [label="eth1\n.2"];
+
+ r4 -- sw3 [label="eth0\n.1"];
+ r2 -- sw3 [label="eth2\n.2"];
+}
diff --git a/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.jpg b/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.jpg
new file mode 100644
index 000000000..4d6d56e07
--- /dev/null
+++ b/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.jpg
Binary files differ
diff --git a/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.py b/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.py
new file mode 100755
index 000000000..e2933820b
--- /dev/null
+++ b/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.py
@@ -0,0 +1,292 @@
+#!/usr/bin/env python
+
+#
+# test_bfd_vrf_topo1.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2018 by
+# Network Device Education Foundation, Inc. ("NetDEF")
+# Copyright (c) 2019 by 6WIND
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+test_bfd_vrf_topo1.py: Test the FRR/Quagga BFD daemon.
+"""
+
+import os
+import sys
+import json
+from functools import partial
+import pytest
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, '../'))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+# Required to instantiate the topology builder class.
+from mininet.topo import Topo
+
+class BFDTopo(Topo):
+ "Test topology builder"
+ def build(self, *_args, **_opts):
+ "Build function"
+ tgen = get_topogen(self)
+
+ # Create 4 routers
+ for routern in range(1, 5):
+ tgen.add_router('r{}'.format(routern))
+
+ switch = tgen.add_switch('s1')
+ switch.add_link(tgen.gears['r1'])
+ switch.add_link(tgen.gears['r2'])
+
+ switch = tgen.add_switch('s2')
+ switch.add_link(tgen.gears['r2'])
+ switch.add_link(tgen.gears['r3'])
+
+ switch = tgen.add_switch('s3')
+ switch.add_link(tgen.gears['r2'])
+ switch.add_link(tgen.gears['r4'])
+
+
+def setup_module(mod):
+ "Sets up the pytest environment"
+ tgen = Topogen(BFDTopo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ # check for zebra capability
+ for rname, router in router_list.iteritems():
+ if router.check_capability(
+ TopoRouter.RD_ZEBRA,
+ '--vrfwnetns'
+ ) == False:
+ return pytest.skip('Skipping BFD Topo1 VRF NETNS feature. VRF NETNS backend not available on FRR')
+
+ if os.system('ip netns list') != 0:
+ return pytest.skip('Skipping BFD Topo1 VRF NETNS Test. NETNS not available on System')
+
+ logger.info('Testing with VRF Namespace support')
+
+ cmds = ['if [ -e /var/run/netns/{0}-cust1 ] ; then ip netns del {0}-cust1 ; fi',
+ 'ip netns add {0}-cust1',
+ 'ip link set dev {0}-eth0 netns {0}-cust1',
+ 'ip netns exec {0}-cust1 ifconfig {0}-eth0 up']
+ cmds2 = ['ip link set dev {0}-eth1 netns {0}-cust1',
+ 'ip netns exec {0}-cust1 ifconfig {0}-eth1 up',
+ 'ip link set dev {0}-eth2 netns {0}-cust1',
+ 'ip netns exec {0}-cust1 ifconfig {0}-eth2 up']
+
+ for rname, router in router_list.iteritems():
+ # create VRF rx-cust1 and link rx-eth0 to rx-cust1
+ for cmd in cmds:
+ output = tgen.net[rname].cmd(cmd.format(rname))
+ if rname == 'r2':
+ for cmd in cmds2:
+ output = tgen.net[rname].cmd(cmd.format(rname))
+
+ for rname, router in router_list.iteritems():
+ router.load_config(
+ TopoRouter.RD_ZEBRA,
+ os.path.join(CWD, '{}/zebra.conf'.format(rname)),
+ '--vrfwnetns'
+ )
+ router.load_config(
+ TopoRouter.RD_BFD,
+ os.path.join(CWD, '{}/bfdd.conf'.format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP,
+ os.path.join(CWD, '{}/bgpd.conf'.format(rname))
+ )
+
+ # Initialize all routers.
+ tgen.start_router()
+
+ # Verify that we are using the proper version and that the BFD
+ # daemon exists.
+ for router in router_list.values():
+ # Check for Version
+ if router.has_version('<', '5.1'):
+ tgen.set_error('Unsupported FRR version')
+ break
+
+def teardown_module(_mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+ # move back rx-eth0 to default VRF
+ # delete rx-vrf
+ cmds = ['ip netns exec {0}-cust1 ip link set {0}-eth0 netns 1',
+ 'ip netns delete {0}-cust1']
+ cmds2 = ['ip netns exec {0}-cust1 ip link set {0}-eth1 netns 1',
+ 'ip netns exec {0}-cust2 ip link set {0}-eth1 netns 1']
+
+ router_list = tgen.routers()
+ for rname, router in router_list.iteritems():
+ if rname == 'r2':
+ for cmd in cmds2:
+ tgen.net[rname].cmd(cmd.format(rname))
+ for cmd in cmds:
+ tgen.net[rname].cmd(cmd.format(rname))
+ tgen.stop_topology()
+
+def test_bfd_connection():
+ "Assert that the BFD peers can find themselves."
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info('waiting for bfd peers to go up')
+ for router in tgen.routers().values():
+ json_file = '{}/{}/peers.json'.format(CWD, router.name)
+ expected = json.loads(open(json_file).read())
+
+ test_func = partial(topotest.router_json_cmp,
+ router, 'show bfd peers json', expected)
+ _, result = topotest.run_and_expect(test_func, None, count=8, wait=0.5)
+ assertmsg = '"{}" JSON output mismatches'.format(router.name)
+ assert result is None, assertmsg
+
+
+def test_bgp_convergence():
+ "Assert that BGP is converging."
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info('waiting for bgp peers to go up')
+
+ for router in tgen.routers().values():
+ ref_file = '{}/{}/bgp_summary.json'.format(CWD, router.name)
+ expected = json.loads(open(ref_file).read())
+ test_func = partial(topotest.router_json_cmp,
+ router, 'show ip bgp vrf {}-cust1 summary json'.format(router.name), expected)
+ _, res = topotest.run_and_expect(test_func, None, count=125, wait=1.0)
+ assertmsg = '{}: bgp did not converge'.format(router.name)
+ assert res is None, assertmsg
+
+
+def test_bgp_fast_convergence():
+ "Assert that BGP is converging before setting a link down."
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info('waiting for bgp peers converge')
+
+ for router in tgen.routers().values():
+ ref_file = '{}/{}/bgp_prefixes.json'.format(CWD, router.name)
+ expected = json.loads(open(ref_file).read())
+ test_func = partial(topotest.router_json_cmp,
+ router, 'show ip bgp vrf {}-cust1 json'.format(router.name), expected)
+ _, res = topotest.run_and_expect(test_func, None, count=40, wait=0.5)
+ assertmsg = '{}: bgp did not converge'.format(router.name)
+ assert res is None, assertmsg
+
+
+def test_bfd_fast_convergence():
+ """
+ Assert that BFD notices the link down after simulating network
+ failure.
+ """
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Disable r2-eth0 link
+ router2 = tgen.gears['r2']
+ topotest.interface_set_status(router2, 'r2-eth0', ifaceaction=False, vrf_name='r2-cust1')
+
+ # Wait the minimum time we can before checking that BGP/BFD
+ # converged.
+ logger.info('waiting for BFD converge')
+
+ # Check that BGP converged quickly.
+ for router in tgen.routers().values():
+ json_file = '{}/{}/peers.json'.format(CWD, router.name)
+ expected = json.loads(open(json_file).read())
+
+ # Load the same file as previous test, but expect R1 to be down.
+ if router.name == 'r1':
+ for peer in expected:
+ if peer['peer'] == '192.168.0.2':
+ peer['status'] = 'down'
+ else:
+ for peer in expected:
+ if peer['peer'] == '192.168.0.1':
+ peer['status'] = 'down'
+
+ test_func = partial(topotest.router_json_cmp,
+ router, 'show bfd peers json', expected)
+ _, res = topotest.run_and_expect(test_func, None, count=20, wait=0.5)
+ assertmsg = '"{}" JSON output mismatches'.format(router.name)
+ assert res is None, assertmsg
+
+
+def test_bgp_fast_reconvergence():
+ "Assert that BGP is converging after setting a link down."
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info('waiting for BGP re convergence')
+
+ # Check that BGP converged quickly.
+ for router in tgen.routers().values():
+ ref_file = '{}/{}/bgp_prefixes.json'.format(CWD, router.name)
+ expected = json.loads(open(ref_file).read())
+
+ # Load the same file as previous test, but set networks to None
+ # to test absence.
+ if router.name == 'r1':
+ expected['routes']['10.254.254.2/32'] = None
+ expected['routes']['10.254.254.3/32'] = None
+ expected['routes']['10.254.254.4/32'] = None
+ else:
+ expected['routes']['10.254.254.1/32'] = None
+
+ test_func = partial(topotest.router_json_cmp,
+ router, 'show ip bgp vrf {}-cust1 json'.format(router.name), expected)
+ _, res = topotest.run_and_expect(
+ test_func,
+ None,
+ count=3,
+ wait=1
+ )
+ assertmsg = '{}: bgp did not converge'.format(router.name)
+ assert res is None, assertmsg
+
+
+def test_memory_leak():
+ "Run the memory leak test and report results."
+ tgen = get_topogen()
+ if not tgen.is_memleak_enabled():
+ pytest.skip('Memory leak test/report is disabled')
+
+ tgen.report_memory_leaks()
+
+
+if __name__ == '__main__':
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/zebra/zebra_ptm.c b/zebra/zebra_ptm.c
index bb352dc2f..d3ecd3695 100644
--- a/zebra/zebra_ptm.c
+++ b/zebra/zebra_ptm.c
@@ -1188,8 +1188,8 @@ static void pp_free_all(void);
static void zebra_ptm_send_bfdd(struct stream *msg);
static void zebra_ptm_send_clients(struct stream *msg);
static int _zebra_ptm_bfd_client_deregister(struct zserv *zs);
-static void _zebra_ptm_reroute(struct zserv *zs, struct stream *msg,
- uint32_t command);
+static void _zebra_ptm_reroute(struct zserv *zs, struct zebra_vrf *zvrf,
+ struct stream *msg, uint32_t command);
/*
@@ -1392,8 +1392,8 @@ void zebra_ptm_finish(void)
/*
* Message handling.
*/
-static void _zebra_ptm_reroute(struct zserv *zs, struct stream *msg,
- uint32_t command)
+static void _zebra_ptm_reroute(struct zserv *zs, struct zebra_vrf *zvrf,
+ struct stream *msg, uint32_t command)
{
struct stream *msgc;
size_t zmsglen, zhdrlen;
@@ -1420,7 +1420,7 @@ static void _zebra_ptm_reroute(struct zserv *zs, struct stream *msg,
* one callback at the `bfdd` side, however the real command
* number will be included right after the zebra header.
*/
- zclient_create_header(msgc, ZEBRA_BFD_DEST_REPLAY, 0);
+ zclient_create_header(msgc, ZEBRA_BFD_DEST_REPLAY, zvrf->vrf->vrf_id);
stream_putl(msgc, command);
/* Update the data pointers. */
@@ -1446,7 +1446,7 @@ void zebra_ptm_bfd_dst_register(ZAPI_HANDLER_ARGS)
zlog_debug("bfd_dst_register msg from client %s: length=%d",
zebra_route_string(client->proto), hdr->length);
- _zebra_ptm_reroute(client, msg, ZEBRA_BFD_DEST_REGISTER);
+ _zebra_ptm_reroute(client, zvrf, msg, ZEBRA_BFD_DEST_REGISTER);
}
void zebra_ptm_bfd_dst_deregister(ZAPI_HANDLER_ARGS)
@@ -1455,7 +1455,7 @@ void zebra_ptm_bfd_dst_deregister(ZAPI_HANDLER_ARGS)
zlog_debug("bfd_dst_deregister msg from client %s: length=%d",
zebra_route_string(client->proto), hdr->length);
- _zebra_ptm_reroute(client, msg, ZEBRA_BFD_DEST_DEREGISTER);
+ _zebra_ptm_reroute(client, zvrf, msg, ZEBRA_BFD_DEST_DEREGISTER);
}
void zebra_ptm_bfd_client_register(ZAPI_HANDLER_ARGS)
@@ -1464,7 +1464,7 @@ void zebra_ptm_bfd_client_register(ZAPI_HANDLER_ARGS)
zlog_debug("bfd_client_register msg from client %s: length=%d",
zebra_route_string(client->proto), hdr->length);
- _zebra_ptm_reroute(client, msg, ZEBRA_BFD_CLIENT_REGISTER);
+ _zebra_ptm_reroute(client, zvrf, msg, ZEBRA_BFD_CLIENT_REGISTER);
}
void zebra_ptm_bfd_dst_replay(ZAPI_HANDLER_ARGS)
@@ -1488,7 +1488,7 @@ void zebra_ptm_bfd_dst_replay(ZAPI_HANDLER_ARGS)
* special treatment.
*/
if (client->proto != ZEBRA_ROUTE_BFD) {
- _zebra_ptm_reroute(client, msg, ZEBRA_BFD_DEST_REPLAY);
+ _zebra_ptm_reroute(client, zvrf, msg, ZEBRA_BFD_DEST_REPLAY);
return;
}