summaryrefslogtreecommitdiff
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_attr.c73
-rw-r--r--bgpd/bgp_attr.h3
-rw-r--r--bgpd/bgp_bfd.c7
-rw-r--r--bgpd/bgp_evpn_vty.c46
-rw-r--r--bgpd/bgp_packet.c11
-rw-r--r--bgpd/bgp_routemap.c2
-rw-r--r--bgpd/bgp_zebra.c2
-rw-r--r--bgpd/rfapi/bgp_rfapi_cfg.c22
-rw-r--r--doc/developer/building-frr-for-ubuntu1804.rst4
-rw-r--r--doc/developer/topotests.rst9
-rw-r--r--doc/user/bfd.rst16
-rw-r--r--doc/user/ospf6d.rst4
-rw-r--r--isisd/isis_bfd.c4
-rw-r--r--lib/bfd.c5
-rw-r--r--lib/bfd.h3
-rw-r--r--lib/grammar_sandbox_main.c2
-rw-r--r--lib/openbsd-tree.c12
-rw-r--r--lib/openbsd-tree.h54
-rw-r--r--lib/routemap.c55
-rw-r--r--lib/routemap.h10
-rw-r--r--lib/vrf.c8
-rw-r--r--ospf6d/ospf6_asbr.c2
-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_routemap.c2
-rw-r--r--ospfd/ospf_zebra.c2
-rw-r--r--pimd/pim_bfd.c2
-rw-r--r--pimd/pim_routemap.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/redistribute.c2
-rw-r--r--zebra/rib.h4
-rw-r--r--zebra/rt.h6
-rw-r--r--zebra/rt_netlink.c2
-rw-r--r--zebra/rtadv.c138
-rw-r--r--zebra/rtadv.h4
-rw-r--r--zebra/zapi_msg.c2
-rw-r--r--zebra/zebra_dplane.c9
-rw-r--r--zebra/zebra_fpm_netlink.c1
-rw-r--r--zebra/zebra_ns.c8
-rw-r--r--zebra/zebra_ptm.c18
-rw-r--r--zebra/zebra_rib.c8
-rw-r--r--zebra/zebra_routemap.c3
-rw-r--r--zebra/zebra_router.h5
-rw-r--r--zebra/zebra_vrf.c9
-rw-r--r--zebra/zebra_vrf.h4
-rw-r--r--zebra/zebra_vty.c4
-rw-r--r--zebra/zebra_vxlan.c16
86 files changed, 1656 insertions, 590 deletions
diff --git a/bfdd/bfd.c b/bfdd/bfd.c
index e9645824f2..a2e84e928d 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 e08a1ff724..3f3d603832 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 93677ec85a..8edba05d12 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 6023b5e4f0..218f0883c5 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 4efdd817c1..75f6632db0 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 923fbd909e..0000000000
--- 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 cd57ea9fe3..74e7d63d0c 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 3a76b459d7..0000000000
--- 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 6f76a15a57..a12a3c196b 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 334e974b04..e88b982ec3 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_attr.c b/bgpd/bgp_attr.c
index 0699c8adfa..0e9d387153 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -1255,6 +1255,32 @@ static int bgp_attr_as4_path(struct bgp_attr_parser_args *args,
return BGP_ATTR_PARSE_PROCEED;
}
+/*
+ * Check that the nexthop attribute is valid.
+ */
+bgp_attr_parse_ret_t
+bgp_attr_nexthop_valid(struct peer *peer, struct attr *attr)
+{
+ in_addr_t nexthop_h;
+
+ nexthop_h = ntohl(attr->nexthop.s_addr);
+ if ((IPV4_NET0(nexthop_h) || IPV4_NET127(nexthop_h)
+ || IPV4_CLASS_DE(nexthop_h))
+ && !BGP_DEBUG(allow_martians, ALLOW_MARTIANS)) {
+ char buf[INET_ADDRSTRLEN];
+
+ inet_ntop(AF_INET, &attr->nexthop.s_addr, buf,
+ INET_ADDRSTRLEN);
+ flog_err(EC_BGP_ATTR_MARTIAN_NH, "Martian nexthop %s",
+ buf);
+ bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP);
+ return BGP_ATTR_PARSE_ERROR;
+ }
+
+ return BGP_ATTR_PARSE_PROCEED;
+}
+
/* Nexthop attribute. */
static bgp_attr_parse_ret_t bgp_attr_nexthop(struct bgp_attr_parser_args *args)
{
@@ -1262,8 +1288,6 @@ static bgp_attr_parse_ret_t bgp_attr_nexthop(struct bgp_attr_parser_args *args)
struct attr *const attr = args->attr;
const bgp_size_t length = args->length;
- in_addr_t nexthop_h, nexthop_n;
-
/* Check nexthop attribute length. */
if (length != 4) {
flog_err(EC_BGP_ATTR_LEN,
@@ -1273,30 +1297,7 @@ static bgp_attr_parse_ret_t bgp_attr_nexthop(struct bgp_attr_parser_args *args)
args->total);
}
- /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP
- attribute must result in a NOTIFICATION message (this is implemented
- below).
- At the same time, semantically incorrect NEXT_HOP is more likely to
- be just
- logged locally (this is implemented somewhere else). The UPDATE
- message
- gets ignored in any of these cases. */
- nexthop_n = stream_get_ipv4(peer->curr);
- nexthop_h = ntohl(nexthop_n);
- if ((IPV4_NET0(nexthop_h) || IPV4_NET127(nexthop_h)
- || IPV4_CLASS_DE(nexthop_h))
- && !BGP_DEBUG(
- allow_martians,
- ALLOW_MARTIANS)) /* loopbacks may be used in testing */
- {
- char buf[INET_ADDRSTRLEN];
- inet_ntop(AF_INET, &nexthop_n, buf, INET_ADDRSTRLEN);
- flog_err(EC_BGP_ATTR_MARTIAN_NH, "Martian nexthop %s", buf);
- return bgp_attr_malformed(
- args, BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP, args->total);
- }
-
- attr->nexthop.s_addr = nexthop_n;
+ attr->nexthop.s_addr = stream_get_ipv4(peer->curr);
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
return BGP_ATTR_PARSE_PROCEED;
@@ -2684,6 +2685,26 @@ bgp_attr_parse_ret_t bgp_attr_parse(struct peer *peer, struct attr *attr,
return BGP_ATTR_PARSE_ERROR;
}
+ /*
+ * RFC4271: If the NEXT_HOP attribute field is syntactically incorrect,
+ * then the Error Subcode MUST be set to Invalid NEXT_HOP Attribute.
+ * This is implemented below and will result in a NOTIFICATION. If the
+ * NEXT_HOP attribute is semantically incorrect, the error SHOULD be
+ * logged, and the route SHOULD be ignored. In this case, a NOTIFICATION
+ * message SHOULD NOT be sent. This is implemented elsewhere.
+ *
+ * RFC4760: An UPDATE message that carries no NLRI, other than the one
+ * encoded in the MP_REACH_NLRI attribute, SHOULD NOT carry the NEXT_HOP
+ * attribute. If such a message contains the NEXT_HOP attribute, the BGP
+ * speaker that receives the message SHOULD ignore this attribute.
+ */
+ if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP))
+ && !CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI))) {
+ if (bgp_attr_nexthop_valid(peer, attr) < 0) {
+ return BGP_ATTR_PARSE_ERROR;
+ }
+ }
+
/* Check all mandatory well-known attributes are present */
if ((ret = bgp_attr_check(peer, attr)) < 0) {
if (as4_path)
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index 3518f1accb..a6fdac9ebf 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -348,6 +348,9 @@ extern void bgp_packet_mpunreach_prefix(struct stream *s, struct prefix *p,
uint32_t, int, uint32_t, struct attr *);
extern void bgp_packet_mpunreach_end(struct stream *s, size_t attrlen_pnt);
+extern bgp_attr_parse_ret_t bgp_attr_nexthop_valid(struct peer *peer,
+ struct attr *attr);
+
static inline int bgp_rmap_nhop_changed(uint32_t out_rmap_flags,
uint32_t in_rmap_flags)
{
diff --git a/bgpd/bgp_bfd.c b/bgpd/bgp_bfd.c
index 45e45977a4..a9c30acafb 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_evpn_vty.c b/bgpd/bgp_evpn_vty.c
index 1bd153639b..4296604c4a 100644
--- a/bgpd/bgp_evpn_vty.c
+++ b/bgpd/bgp_evpn_vty.c
@@ -1048,7 +1048,20 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd,
rd_header = 1;
tbl_ver = table->version;
- for (rm = bgp_table_top(table); rm; rm = bgp_route_next(rm))
+ for (rm = bgp_table_top(table); rm; rm = bgp_route_next(rm)) {
+ if (use_json) {
+ json_array = json_object_new_array();
+ json_prefix_info = json_object_new_object();
+
+ json_object_string_add(json_prefix_info,
+ "prefix", bgp_evpn_route2str(
+ (struct prefix_evpn *)&rm->p, buf,
+ BUFSIZ));
+
+ json_object_int_add(json_prefix_info,
+ "prefixLen", rm->p.prefixlen);
+ }
+
for (pi = bgp_node_get_bgp_path_info(rm); pi;
pi = pi->next) {
total_count++;
@@ -1121,10 +1134,6 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd,
if (use_json) {
json_nroute =
json_object_new_object();
- json_prefix_info =
- json_object_new_object();
- json_array =
- json_object_new_array();
if (type == RD_TYPE_AS
|| type == RD_TYPE_AS4)
sprintf(rd_str, "%u:%d",
@@ -1140,18 +1149,6 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd,
"rd",
rd_str);
- json_object_string_add(
- json_prefix_info,
- "prefix",
- bgp_evpn_route2str(
- (struct prefix_evpn *)
- &rm->p, buf, BUFSIZ));
-
- json_object_int_add(
- json_prefix_info,
- "prefixLen",
- rm->p.prefixlen);
-
} else {
vty_out(vty,
"Route Distinguisher: ");
@@ -1174,6 +1171,7 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd,
}
rd_header = 0;
}
+
if (option == SHOW_DISPLAY_TAGS)
route_vty_out_tag(vty, &rm->p, pi, 0,
SAFI_EVPN,
@@ -1186,14 +1184,16 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd,
SAFI_EVPN, json_array);
output_count++;
}
+ if (use_json) {
+ json_object_object_add(json_prefix_info,
+ "paths", json_array);
+ json_object_object_add(json_nroute, buf,
+ json_prefix_info);
+ }
+ }
- if (use_json) {
- json_object_object_add(json_prefix_info, "paths",
- json_array);
- json_object_object_add(json_nroute, buf,
- json_prefix_info);
+ if (use_json)
json_object_object_add(json, rd_str, json_nroute);
- }
}
if (use_json) {
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index 130e06a6cf..b5934fb56e 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -1533,6 +1533,17 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size)
nlris[NLRI_UPDATE].nlri = stream_pnt(s);
nlris[NLRI_UPDATE].length = update_len;
stream_forward_getp(s, update_len);
+
+ if (CHECK_FLAG(attr.flag, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI))) {
+ /*
+ * We skipped nexthop attribute validation earlier so
+ * validate the nexthop now.
+ */
+ if (bgp_attr_nexthop_valid(peer, &attr) < 0) {
+ bgp_attr_unintern_sub(&attr);
+ return BGP_Stop;
+ }
+ }
}
if (BGP_DEBUG(update, UPDATE_IN))
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index 0da9a84b56..9ff4196dae 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -3447,7 +3447,7 @@ static void bgp_route_map_delete(const char *rmap_name)
route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_DELETED);
}
-static void bgp_route_map_event(route_map_event_t event, const char *rmap_name)
+static void bgp_route_map_event(const char *rmap_name)
{
if (route_map_mark_updated(rmap_name) == 0)
bgp_route_map_mark_update(rmap_name);
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index d47c1f9638..a45480fdc2 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/bgpd/rfapi/bgp_rfapi_cfg.c b/bgpd/rfapi/bgp_rfapi_cfg.c
index 2220f0ed9a..cad33404fa 100644
--- a/bgpd/rfapi/bgp_rfapi_cfg.c
+++ b/bgpd/rfapi/bgp_rfapi_cfg.c
@@ -2208,24 +2208,6 @@ void vnc_routemap_update(struct bgp *bgp, const char *unused)
vnc_zlog_debug_verbose("%s done", __func__);
}
-#if 0 /* superseded */
-static void vnc_routemap_event(route_map_event_t type, /* ignored */
- const char *rmap_name) /* ignored */
-{
- struct listnode *mnode, *mnnode;
- struct bgp *bgp;
-
- vnc_zlog_debug_verbose("%s(event type=%d)", __func__, type);
- if (bm->bgp == NULL) /* may be called during cleanup */
- return;
-
- for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp))
- vnc_routemap_update(bgp, rmap_name);
-
- vnc_zlog_debug_verbose("%s: done", __func__);
-}
-#endif
-
/*-------------------------------------------------------------------------
* nve-group
*-----------------------------------------------------------------------*/
@@ -3699,10 +3681,6 @@ bgp_rfapi_get_ecommunity_by_lni_label(struct bgp *bgp, uint32_t is_import,
void bgp_rfapi_cfg_init(void)
{
- /* main bgpd code does not use this hook, but vnc does */
- /* superseded by bgp_route_map_process_update_cb() */
- /* bgp_route_map_event_hook_add(vnc_routemap_event); */
-
install_node(&bgp_vnc_defaults_node, NULL);
install_node(&bgp_vnc_nve_group_node, NULL);
install_node(&bgp_vrf_policy_node, NULL);
diff --git a/doc/developer/building-frr-for-ubuntu1804.rst b/doc/developer/building-frr-for-ubuntu1804.rst
index 1320bda577..8bdc2b9c76 100644
--- a/doc/developer/building-frr-for-ubuntu1804.rst
+++ b/doc/developer/building-frr-for-ubuntu1804.rst
@@ -104,6 +104,10 @@ And load the kernel modules on the running system:
sudo modprobe mpls-router mpls-iptunnel
+If the above command returns an error, you may need to install the appropriate
+or latest linux-modules-extra-<kernel-version>-generic package. For example
+``apt-get install linux-modules-extra-`uname -r`-generic``
+
Enable MPLS Forwarding
""""""""""""""""""""""
diff --git a/doc/developer/topotests.rst b/doc/developer/topotests.rst
index 605b9c9a0c..1e165a2444 100644
--- a/doc/developer/topotests.rst
+++ b/doc/developer/topotests.rst
@@ -105,6 +105,8 @@ Execute all tests with output to console
py.test -s -v --tb=no
+The above command must be executed from inside the topotests directory.
+
All test\_\* scripts in subdirectories are detected and executed (unless
disabled in ``pytest.ini`` file).
@@ -119,6 +121,13 @@ Execute single test
cd test_to_be_run
./test_to_be_run.py
+For example, and assuming you are inside the frr directory:
+
+.. code:: shell
+
+ cd tests/topotests/bgp_l3vpn_to_bgp_vrf
+ ./test_bgp_l3vpn_to_bgp_vrf.py
+
For further options, refer to pytest documentation.
Test will set exit code which can be used with ``git bisect``.
diff --git a/doc/user/bfd.rst b/doc/user/bfd.rst
index 986d1494a5..a7c5cf28bc 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/doc/user/ospf6d.rst b/doc/user/ospf6d.rst
index 71bc047720..6413c62995 100644
--- a/doc/user/ospf6d.rst
+++ b/doc/user/ospf6d.rst
@@ -15,8 +15,8 @@ OSPF6 router
.. index:: router ospf6
.. clicmd:: router ospf6
-.. index:: router-id A.B.C.D
-.. clicmd:: router-id A.B.C.D
+.. index:: ospf6 router-id A.B.C.D
+.. clicmd:: ospf6 router-id A.B.C.D
Set router's Router-ID.
diff --git a/isisd/isis_bfd.c b/isisd/isis_bfd.c
index a98c44eeb0..fccef0169e 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 7e27a64de7..a8956c315c 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 a93875c4cf..d02110a997 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/grammar_sandbox_main.c b/lib/grammar_sandbox_main.c
index c9c942f9bf..38494fb007 100644
--- a/lib/grammar_sandbox_main.c
+++ b/lib/grammar_sandbox_main.c
@@ -58,6 +58,8 @@ int main(int argc, char **argv)
vty_init(master);
memory_init();
+ yang_init();
+ nb_init(master, NULL, 0);
vty_stdio(vty_do_exit);
diff --git a/lib/openbsd-tree.c b/lib/openbsd-tree.c
index eadef9902b..ddcc59fa8f 100644
--- a/lib/openbsd-tree.c
+++ b/lib/openbsd-tree.c
@@ -435,7 +435,8 @@ void *_rb_insert(const struct rb_type *t, struct rbt_tree *rbt, void *elm)
}
/* Finds the node with the same key as elm */
-void *_rb_find(const struct rb_type *t, struct rbt_tree *rbt, const void *key)
+void *_rb_find(const struct rb_type *t, const struct rbt_tree *rbt,
+ const void *key)
{
struct rb_entry *tmp = RBH_ROOT(rbt);
void *node;
@@ -456,7 +457,8 @@ void *_rb_find(const struct rb_type *t, struct rbt_tree *rbt, const void *key)
}
/* Finds the first node greater than or equal to the search key */
-void *_rb_nfind(const struct rb_type *t, struct rbt_tree *rbt, const void *key)
+void *_rb_nfind(const struct rb_type *t, const struct rbt_tree *rbt,
+ const void *key)
{
struct rb_entry *tmp = RBH_ROOT(rbt);
void *node;
@@ -522,14 +524,14 @@ void *_rb_prev(const struct rb_type *t, void *elm)
return (rbe == NULL ? NULL : rb_e2n(t, rbe));
}
-void *_rb_root(const struct rb_type *t, struct rbt_tree *rbt)
+void *_rb_root(const struct rb_type *t, const struct rbt_tree *rbt)
{
struct rb_entry *rbe = RBH_ROOT(rbt);
return (rbe == NULL ? rbe : rb_e2n(t, rbe));
}
-void *_rb_min(const struct rb_type *t, struct rbt_tree *rbt)
+void *_rb_min(const struct rb_type *t, const struct rbt_tree *rbt)
{
struct rb_entry *rbe = RBH_ROOT(rbt);
struct rb_entry *parent = NULL;
@@ -542,7 +544,7 @@ void *_rb_min(const struct rb_type *t, struct rbt_tree *rbt)
return (parent == NULL ? NULL : rb_e2n(t, parent));
}
-void *_rb_max(const struct rb_type *t, struct rbt_tree *rbt)
+void *_rb_max(const struct rb_type *t, const struct rbt_tree *rbt)
{
struct rb_entry *rbe = RBH_ROOT(rbt);
struct rb_entry *parent = NULL;
diff --git a/lib/openbsd-tree.h b/lib/openbsd-tree.h
index d2f0781333..832a10141e 100644
--- a/lib/openbsd-tree.h
+++ b/lib/openbsd-tree.h
@@ -364,18 +364,18 @@ static inline void _rb_init(struct rbt_tree *rbt)
rbt->rbt_root = NULL;
}
-static inline int _rb_empty(struct rbt_tree *rbt)
+static inline int _rb_empty(const struct rbt_tree *rbt)
{
return (rbt->rbt_root == NULL);
}
void *_rb_insert(const struct rb_type *, struct rbt_tree *, void *);
void *_rb_remove(const struct rb_type *, struct rbt_tree *, void *);
-void *_rb_find(const struct rb_type *, struct rbt_tree *, const void *);
-void *_rb_nfind(const struct rb_type *, struct rbt_tree *, const void *);
-void *_rb_root(const struct rb_type *, struct rbt_tree *);
-void *_rb_min(const struct rb_type *, struct rbt_tree *);
-void *_rb_max(const struct rb_type *, struct rbt_tree *);
+void *_rb_find(const struct rb_type *, const struct rbt_tree *, const void *);
+void *_rb_nfind(const struct rb_type *, const struct rbt_tree *, const void *);
+void *_rb_root(const struct rb_type *, const struct rbt_tree *);
+void *_rb_min(const struct rb_type *, const struct rbt_tree *);
+void *_rb_max(const struct rb_type *, const struct rbt_tree *);
void *_rb_next(const struct rb_type *, void *);
void *_rb_prev(const struct rb_type *, void *);
void *_rb_left(const struct rb_type *, void *);
@@ -401,56 +401,58 @@ int _rb_check(const struct rb_type *, void *, unsigned long);
__attribute__((__unused__)) static inline struct _type \
*_name##_RB_INSERT(struct _name *head, struct _type *elm) \
{ \
- return (struct _type *)_rb_insert( \
- _name##_RB_TYPE, &head->rbh_root, elm); \
+ return (struct _type *)_rb_insert(_name##_RB_TYPE, \
+ &head->rbh_root, elm); \
} \
\
__attribute__((__unused__)) static inline struct _type \
*_name##_RB_REMOVE(struct _name *head, struct _type *elm) \
{ \
- return (struct _type *)_rb_remove( \
- _name##_RB_TYPE, &head->rbh_root, elm); \
+ return (struct _type *)_rb_remove(_name##_RB_TYPE, \
+ &head->rbh_root, elm); \
} \
\
__attribute__((__unused__)) static inline struct _type \
- *_name##_RB_FIND(struct _name *head, const struct _type *key) \
+ *_name##_RB_FIND(const struct _name *head, \
+ const struct _type *key) \
{ \
- return (struct _type *)_rb_find( \
- _name##_RB_TYPE, &head->rbh_root, key); \
+ return (struct _type *)_rb_find(_name##_RB_TYPE, \
+ &head->rbh_root, key); \
} \
\
__attribute__((__unused__)) static inline struct _type \
- *_name##_RB_NFIND(struct _name *head, const struct _type *key) \
+ *_name##_RB_NFIND(const struct _name *head, \
+ const struct _type *key) \
{ \
- return (struct _type *)_rb_nfind( \
- _name##_RB_TYPE, &head->rbh_root, key); \
+ return (struct _type *)_rb_nfind(_name##_RB_TYPE, \
+ &head->rbh_root, key); \
} \
\
__attribute__((__unused__)) static inline struct _type \
- *_name##_RB_ROOT(struct _name *head) \
+ *_name##_RB_ROOT(const struct _name *head) \
{ \
- return (struct _type *)_rb_root( \
- _name##_RB_TYPE, &head->rbh_root); \
+ return (struct _type *)_rb_root(_name##_RB_TYPE, \
+ &head->rbh_root); \
} \
\
__attribute__((__unused__)) static inline int _name##_RB_EMPTY( \
- struct _name *head) \
+ const struct _name *head) \
{ \
return _rb_empty(&head->rbh_root); \
} \
\
__attribute__((__unused__)) static inline struct _type \
- *_name##_RB_MIN(struct _name *head) \
+ *_name##_RB_MIN(const struct _name *head) \
{ \
- return (struct _type *)_rb_min( \
- _name##_RB_TYPE, &head->rbh_root); \
+ return (struct _type *)_rb_min(_name##_RB_TYPE, \
+ &head->rbh_root); \
} \
\
__attribute__((__unused__)) static inline struct _type \
- *_name##_RB_MAX(struct _name *head) \
+ *_name##_RB_MAX(const struct _name *head) \
{ \
- return (struct _type *)_rb_max( \
- _name##_RB_TYPE, &head->rbh_root); \
+ return (struct _type *)_rb_max(_name##_RB_TYPE, \
+ &head->rbh_root); \
} \
\
__attribute__((__unused__)) static inline struct _type \
diff --git a/lib/routemap.c b/lib/routemap.c
index e8bdaa68fb..0c75be3323 100644
--- a/lib/routemap.c
+++ b/lib/routemap.c
@@ -616,7 +616,7 @@ struct route_map_list {
void (*add_hook)(const char *);
void (*delete_hook)(const char *);
- void (*event_hook)(route_map_event_t, const char *);
+ void (*event_hook)(const char *);
};
/* Master list of route map. */
@@ -902,7 +902,7 @@ static const char *route_map_type_str(enum route_map_type type)
case RMAP_DENY:
return "deny";
break;
- default:
+ case RMAP_ANY:
return "";
break;
}
@@ -1077,8 +1077,7 @@ static void route_map_index_delete(struct route_map_index *index, int notify)
/* Execute event hook. */
if (route_map_master.event_hook && notify) {
- (*route_map_master.event_hook)(RMAP_EVENT_INDEX_DELETED,
- index->map->name);
+ (*route_map_master.event_hook)(index->map->name);
route_map_notify_dependencies(index->map->name,
RMAP_EVENT_CALL_ADDED);
}
@@ -1137,8 +1136,7 @@ route_map_index_add(struct route_map *map, enum route_map_type type, int pref)
/* Execute event hook. */
if (route_map_master.event_hook) {
- (*route_map_master.event_hook)(RMAP_EVENT_INDEX_ADDED,
- map->name);
+ (*route_map_master.event_hook)(map->name);
route_map_notify_dependencies(map->name, RMAP_EVENT_CALL_ADDED);
}
return index;
@@ -1337,10 +1335,7 @@ int route_map_add_match(struct route_map_index *index, const char *match_name,
/* Execute event hook. */
if (route_map_master.event_hook) {
- (*route_map_master.event_hook)(
- replaced ? RMAP_EVENT_MATCH_REPLACED
- : RMAP_EVENT_MATCH_ADDED,
- index->map->name);
+ (*route_map_master.event_hook)(index->map->name);
route_map_notify_dependencies(index->map->name,
RMAP_EVENT_CALL_ADDED);
}
@@ -1365,9 +1360,7 @@ int route_map_delete_match(struct route_map_index *index,
route_map_rule_delete(&index->match_list, rule);
/* Execute event hook. */
if (route_map_master.event_hook) {
- (*route_map_master.event_hook)(
- RMAP_EVENT_MATCH_DELETED,
- index->map->name);
+ (*route_map_master.event_hook)(index->map->name);
route_map_notify_dependencies(
index->map->name,
RMAP_EVENT_CALL_ADDED);
@@ -1425,10 +1418,7 @@ int route_map_add_set(struct route_map_index *index, const char *set_name,
/* Execute event hook. */
if (route_map_master.event_hook) {
- (*route_map_master.event_hook)(replaced
- ? RMAP_EVENT_SET_REPLACED
- : RMAP_EVENT_SET_ADDED,
- index->map->name);
+ (*route_map_master.event_hook)(index->map->name);
route_map_notify_dependencies(index->map->name,
RMAP_EVENT_CALL_ADDED);
}
@@ -1452,9 +1442,7 @@ int route_map_delete_set(struct route_map_index *index, const char *set_name,
route_map_rule_delete(&index->set_list, rule);
/* Execute event hook. */
if (route_map_master.event_hook) {
- (*route_map_master.event_hook)(
- RMAP_EVENT_SET_DELETED,
- index->map->name);
+ (*route_map_master.event_hook)(index->map->name);
route_map_notify_dependencies(
index->map->name,
RMAP_EVENT_CALL_ADDED);
@@ -1651,7 +1639,7 @@ void route_map_delete_hook(void (*func)(const char *))
route_map_master.delete_hook = func;
}
-void route_map_event_hook(void (*func)(route_map_event_t, const char *))
+void route_map_event_hook(void (*func)(const char *name))
{
route_map_master.event_hook = func;
}
@@ -1795,7 +1783,14 @@ static int route_map_dep_update(struct hash *dephash, const char *dep_name,
dep = NULL;
}
break;
- default:
+ case RMAP_EVENT_SET_ADDED:
+ case RMAP_EVENT_SET_DELETED:
+ case RMAP_EVENT_SET_REPLACED:
+ case RMAP_EVENT_MATCH_ADDED:
+ case RMAP_EVENT_MATCH_DELETED:
+ case RMAP_EVENT_MATCH_REPLACED:
+ case RMAP_EVENT_INDEX_ADDED:
+ case RMAP_EVENT_INDEX_DELETED:
break;
}
@@ -1846,7 +1841,18 @@ static struct hash *route_map_get_dep_hash(route_map_event_t event)
case RMAP_EVENT_FILTER_DELETED:
upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_FILTER];
break;
- default:
+ /*
+ * Should we actually be ignoring these?
+ * I am not sure but at this point in time, let
+ * us get them into this switch and we can peel
+ * them into the appropriate place in the future
+ */
+ case RMAP_EVENT_SET_ADDED:
+ case RMAP_EVENT_SET_DELETED:
+ case RMAP_EVENT_SET_REPLACED:
+ case RMAP_EVENT_MATCH_REPLACED:
+ case RMAP_EVENT_INDEX_ADDED:
+ case RMAP_EVENT_INDEX_DELETED:
upd8_hash = NULL;
break;
}
@@ -1856,13 +1862,12 @@ static struct hash *route_map_get_dep_hash(route_map_event_t event)
static void route_map_process_dependency(struct hash_bucket *bucket, void *data)
{
char *rmap_name = (char *)bucket->data;
- route_map_event_t type = (route_map_event_t)(ptrdiff_t)data;
if (rmap_debug)
zlog_debug("%s: Notifying %s of dependency",
__FUNCTION__, rmap_name);
if (route_map_master.event_hook)
- (*route_map_master.event_hook)(type, rmap_name);
+ (*route_map_master.event_hook)(rmap_name);
}
void route_map_upd8_dependency(route_map_event_t type, const char *arg,
diff --git a/lib/routemap.h b/lib/routemap.h
index e43e74a633..9969936a6b 100644
--- a/lib/routemap.h
+++ b/lib/routemap.h
@@ -238,7 +238,15 @@ extern route_map_result_t route_map_apply(struct route_map *map,
extern void route_map_add_hook(void (*func)(const char *));
extern void route_map_delete_hook(void (*func)(const char *));
-extern void route_map_event_hook(void (*func)(route_map_event_t, const char *));
+
+/*
+ * This is the callback for when something has changed about a
+ * route-map. The interested parties can register to receive
+ * this data.
+ *
+ * name - Is the name of the changed route-map
+ */
+extern void route_map_event_hook(void (*func)(const char *name));
extern int route_map_mark_updated(const char *name);
extern void route_map_walk_update_list(void (*update_fn)(char *name));
extern void route_map_upd8_dependency(route_map_event_t type, const char *arg,
diff --git a/lib/vrf.c b/lib/vrf.c
index 6d9ac2e1e4..6ec3cc8e0d 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_asbr.c b/ospf6d/ospf6_asbr.c
index 2795bb9abd..946bbf8cc9 100644
--- a/ospf6d/ospf6_asbr.c
+++ b/ospf6d/ospf6_asbr.c
@@ -956,7 +956,7 @@ static void ospf6_asbr_routemap_update(const char *mapname)
}
}
-static void ospf6_asbr_routemap_event(route_map_event_t event, const char *name)
+static void ospf6_asbr_routemap_event(const char *name)
{
int type;
diff --git a/ospf6d/ospf6_bfd.c b/ospf6d/ospf6_bfd.c
index 3394bd75db..7a26af1f09 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 8db4ffef18..af16c5aa7c 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 6bff5b8ddb..c8ad6d04f4 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_routemap.c b/ospfd/ospf_routemap.c
index 30b2a50bb3..ab2d5ae584 100644
--- a/ospfd/ospf_routemap.c
+++ b/ospfd/ospf_routemap.c
@@ -97,7 +97,7 @@ static void ospf_route_map_update(const char *name)
}
}
-static void ospf_route_map_event(route_map_event_t event, const char *name)
+static void ospf_route_map_event(const char *name)
{
struct ospf *ospf;
int type;
diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c
index 16796e68fb..c178e367d3 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 82087c4c56..300261e5a9 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_routemap.c b/pimd/pim_routemap.c
index 4230c127ad..2de94e9031 100644
--- a/pimd/pim_routemap.c
+++ b/pimd/pim_routemap.c
@@ -36,7 +36,7 @@ static void pim_route_map_delete(const char *rmap_name)
route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_DELETED);
}
-static void pim_route_map_event(route_map_event_t event, const char *rmap_name)
+static void pim_route_map_event(const char *rmap_name)
{
route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED);
}
diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c
index b27d2e0581..25ac307ac4 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 0000000000..e69de29bb2
--- /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 0000000000..3466e6a3ca
--- /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 0000000000..4b2cc1ad62
--- /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 0000000000..fa07d60df9
--- /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 0000000000..7ad4e2bd74
--- /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 0000000000..f49768ff75
--- /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 0000000000..fcd1e7db17
--- /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 0000000000..3481ea8c87
--- /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 0000000000..39f3c0a835
--- /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 0000000000..c0ef11ac5f
--- /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 0000000000..0715ea32a5
--- /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 0000000000..5035d643c5
--- /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 0000000000..daffd1912e
--- /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 0000000000..f6921b7818
--- /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 0000000000..c92d4e052a
--- /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 0000000000..d47833377b
--- /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 0000000000..277f027d5b
--- /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 0000000000..ef38008643
--- /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 0000000000..f727c2d633
--- /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 0000000000..a56a3a0d37
--- /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 0000000000..cc8510dd61
--- /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 0000000000..7d81784b56
--- /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 0000000000..66bf28587d
--- /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 0000000000..37140089e1
--- /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 0000000000..69770dd2bf
--- /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 0000000000..c84ace2780
--- /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 0000000000..4d6d56e072
--- /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 0000000000..e2933820bd
--- /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/redistribute.c b/zebra/redistribute.c
index 0071e001c6..fe064f847a 100644
--- a/zebra/redistribute.c
+++ b/zebra/redistribute.c
@@ -614,7 +614,7 @@ int zebra_add_import_table_entry(struct route_node *rn, struct route_entry *re,
newre->mtu = re->mtu;
newre->table = 0;
newre->nexthop_num = 0;
- newre->uptime = time(NULL);
+ newre->uptime = monotime(NULL);
newre->instance = re->table;
route_entry_copy_nexthops(newre, re->ng.nexthop);
diff --git a/zebra/rib.h b/zebra/rib.h
index 8a59cea6d0..c39abaffcc 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -148,6 +148,10 @@ struct route_entry {
uint32_t dplane_sequence;
};
+#define RIB_SYSTEM_ROUTE(R) RSYSTEM_ROUTE((R)->type)
+
+#define RIB_KERNEL_ROUTE(R) RKERNEL_ROUTE((R)->type)
+
/* meta-queue structure:
* sub-queue 0: connected, kernel
* sub-queue 1: static
diff --git a/zebra/rt.h b/zebra/rt.h
index 08b51fcc0b..04576671fe 100644
--- a/zebra/rt.h
+++ b/zebra/rt.h
@@ -35,8 +35,10 @@
extern "C" {
#endif
-#define RSYSTEM_ROUTE(type) \
- ((type) == ZEBRA_ROUTE_KERNEL || (type) == ZEBRA_ROUTE_CONNECT)
+#define RKERNEL_ROUTE(type) ((type) == ZEBRA_ROUTE_KERNEL)
+
+#define RSYSTEM_ROUTE(type) \
+ ((RKERNEL_ROUTE(type)) || (type) == ZEBRA_ROUTE_CONNECT)
/*
* Update or delete a route, LSP, or pseudowire from the kernel,
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 289ed5a15b..def5bf7d88 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -583,7 +583,7 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
re->vrf_id = vrf_id;
re->table = table;
re->nexthop_num = 0;
- re->uptime = time(NULL);
+ re->uptime = monotime(NULL);
re->tag = tag;
for (;;) {
diff --git a/zebra/rtadv.c b/zebra/rtadv.c
index 5088e2e8e1..817c65bf28 100644
--- a/zebra/rtadv.c
+++ b/zebra/rtadv.c
@@ -42,7 +42,6 @@
#include "zebra/debug.h"
#include "zebra/rib.h"
#include "zebra/zapi_msg.h"
-#include "zebra/zebra_ns.h"
#include "zebra/zebra_vrf.h"
#include "zebra/zebra_errors.h"
#include "zebra/zebra_router.h"
@@ -81,18 +80,25 @@ enum rtadv_event {
RTADV_READ
};
-static void rtadv_event(struct zebra_ns *, enum rtadv_event, int);
+static void rtadv_event(struct zebra_vrf *, enum rtadv_event, int);
static int if_join_all_router(int, struct interface *);
static int if_leave_all_router(int, struct interface *);
-static int rtadv_increment_received(struct zebra_ns *zns, ifindex_t *ifindex)
+static int rtadv_get_socket(struct zebra_vrf *zvrf)
+{
+ if (zvrf->rtadv.sock >= 0)
+ return zvrf->rtadv.sock;
+ return zrouter.rtadv_sock;
+}
+
+static int rtadv_increment_received(struct zebra_vrf *zvrf, ifindex_t *ifindex)
{
int ret = -1;
struct interface *iface;
struct zebra_if *zif;
- iface = if_lookup_by_index_per_ns(zns, *ifindex);
+ iface = if_lookup_by_index(*ifindex, zvrf->vrf->vrf_id);
if (iface && iface->info) {
zif = iface->info;
zif->ra_rcvd++;
@@ -101,7 +107,7 @@ static int rtadv_increment_received(struct zebra_ns *zns, ifindex_t *ifindex)
return ret;
}
-static int rtadv_recv_packet(struct zebra_ns *zns, int sock, uint8_t *buf,
+static int rtadv_recv_packet(struct zebra_vrf *zvrf, int sock, uint8_t *buf,
int buflen, struct sockaddr_in6 *from,
ifindex_t *ifindex, int *hoplimit)
{
@@ -149,7 +155,7 @@ static int rtadv_recv_packet(struct zebra_ns *zns, int sock, uint8_t *buf,
}
}
- rtadv_increment_received(zns, ifindex);
+ rtadv_increment_received(zvrf, ifindex);
return ret;
}
@@ -461,19 +467,19 @@ no_more_opts:
static int rtadv_timer(struct thread *thread)
{
- struct zebra_ns *zns = THREAD_ARG(thread);
+ struct zebra_vrf *zvrf = THREAD_ARG(thread);
struct vrf *vrf;
struct interface *ifp;
struct zebra_if *zif;
int period;
- zrouter.rtadv.ra_timer = NULL;
- if (zrouter.rtadv.adv_msec_if_count == 0) {
+ zvrf->rtadv.ra_timer = NULL;
+ if (zvrf->rtadv.adv_msec_if_count == 0) {
period = 1000; /* 1 s */
- rtadv_event(zns, RTADV_TIMER, 1 /* 1 s */);
+ rtadv_event(zvrf, RTADV_TIMER, 1 /* 1 s */);
} else {
period = 10; /* 10 ms */
- rtadv_event(zns, RTADV_TIMER_MSEC, 10 /* 10 ms */);
+ rtadv_event(zvrf, RTADV_TIMER_MSEC, 10 /* 10 ms */);
}
RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id)
@@ -500,7 +506,7 @@ static int rtadv_timer(struct thread *thread)
"Fast RA Rexmit on interface %s",
ifp->name);
- rtadv_send_packet(zrouter.rtadv.sock,
+ rtadv_send_packet(rtadv_get_socket(zvrf),
ifp);
} else {
zif->rtadv.AdvIntervalTimer -= period;
@@ -514,8 +520,8 @@ static int rtadv_timer(struct thread *thread)
zif->rtadv
.MaxRtrAdvInterval;
rtadv_send_packet(
- zrouter.rtadv.sock,
- ifp);
+ rtadv_get_socket(zvrf),
+ ifp);
}
}
}
@@ -527,10 +533,9 @@ static int rtadv_timer(struct thread *thread)
static void rtadv_process_solicit(struct interface *ifp)
{
struct zebra_vrf *zvrf = vrf_info_lookup(ifp->vrf_id);
- struct zebra_ns *zns = zvrf->zns;
- assert(zns);
- rtadv_send_packet(zrouter.rtadv.sock, ifp);
+ assert(zvrf);
+ rtadv_send_packet(rtadv_get_socket(zvrf), ifp);
}
/*
@@ -652,7 +657,7 @@ static void rtadv_process_advert(uint8_t *msg, unsigned int len,
static void rtadv_process_packet(uint8_t *buf, unsigned int len,
ifindex_t ifindex, int hoplimit,
struct sockaddr_in6 *from,
- struct zebra_ns *zns)
+ struct zebra_vrf *zvrf)
{
struct icmp6_hdr *icmph;
struct interface *ifp;
@@ -662,7 +667,7 @@ static void rtadv_process_packet(uint8_t *buf, unsigned int len,
inet_ntop(AF_INET6, &from->sin6_addr, addr_str, INET6_ADDRSTRLEN);
/* Interface search. */
- ifp = if_lookup_by_index_per_ns(zns, ifindex);
+ ifp = if_lookup_by_index(ifindex, zvrf->vrf->vrf_id);
if (ifp == NULL) {
flog_warn(EC_ZEBRA_UNKNOWN_INTERFACE,
"RA/RS received on unknown IF %u from %s", ifindex,
@@ -724,15 +729,15 @@ static int rtadv_read(struct thread *thread)
struct sockaddr_in6 from;
ifindex_t ifindex = 0;
int hoplimit = -1;
- struct zebra_ns *zns = THREAD_ARG(thread);
+ struct zebra_vrf *zvrf = THREAD_ARG(thread);
sock = THREAD_FD(thread);
- zrouter.rtadv.ra_read = NULL;
+ zvrf->rtadv.ra_read = NULL;
/* Register myself. */
- rtadv_event(zns, RTADV_READ, sock);
+ rtadv_event(zvrf, RTADV_READ, sock);
- len = rtadv_recv_packet(zns, sock, buf, sizeof(buf), &from, &ifindex,
+ len = rtadv_recv_packet(zvrf, sock, buf, sizeof(buf), &from, &ifindex,
&hoplimit);
if (len < 0) {
@@ -742,7 +747,7 @@ static int rtadv_read(struct thread *thread)
return len;
}
- rtadv_process_packet(buf, (unsigned)len, ifindex, hoplimit, &from, zns);
+ rtadv_process_packet(buf, (unsigned)len, ifindex, hoplimit, &from, zvrf);
return 0;
}
@@ -875,29 +880,27 @@ static void ipv6_nd_suppress_ra_set(struct interface *ifp,
{
struct zebra_if *zif;
struct zebra_vrf *zvrf;
- struct zebra_ns *zns;
zif = ifp->info;
zvrf = vrf_info_lookup(ifp->vrf_id);
- zns = zvrf->zns;
if (status == RA_SUPPRESS) {
/* RA is currently enabled */
if (zif->rtadv.AdvSendAdvertisements) {
zif->rtadv.AdvSendAdvertisements = 0;
zif->rtadv.AdvIntervalTimer = 0;
- zrouter.rtadv.adv_if_count--;
+ zvrf->rtadv.adv_if_count--;
- if_leave_all_router(zrouter.rtadv.sock, ifp);
+ if_leave_all_router(rtadv_get_socket(zvrf), ifp);
- if (zrouter.rtadv.adv_if_count == 0)
- rtadv_event(zns, RTADV_STOP, 0);
+ if (zvrf->rtadv.adv_if_count == 0)
+ rtadv_event(zvrf, RTADV_STOP, 0);
}
} else {
if (!zif->rtadv.AdvSendAdvertisements) {
zif->rtadv.AdvSendAdvertisements = 1;
zif->rtadv.AdvIntervalTimer = 0;
- zrouter.rtadv.adv_if_count++;
+ zvrf->rtadv.adv_if_count++;
if (zif->rtadv.MaxRtrAdvInterval >= 1000) {
/* Enable Fast RA only when RA interval is in
@@ -907,11 +910,11 @@ static void ipv6_nd_suppress_ra_set(struct interface *ifp,
RTADV_NUM_FAST_REXMITS;
}
- if_join_all_router(zrouter.rtadv.sock, ifp);
+ if_join_all_router(rtadv_get_socket(zvrf), ifp);
- if (zrouter.rtadv.adv_if_count == 1)
- rtadv_event(zns, RTADV_START,
- zrouter.rtadv.sock);
+ if (zvrf->rtadv.adv_if_count == 1)
+ rtadv_event(zvrf, RTADV_START,
+ rtadv_get_socket(zvrf));
}
}
}
@@ -944,7 +947,7 @@ static void zebra_interface_radv_set(ZAPI_HANDLER_ARGS, int enable)
zebra_route_string(client->proto), ra_interval);
/* Locate interface and check VRF match. */
- ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT), ifindex);
+ ifp = if_lookup_by_index(ifindex, zvrf->vrf->vrf_id);
if (!ifp) {
flog_warn(EC_ZEBRA_UNKNOWN_INTERFACE,
"%u: IF %u RA %s client %s - interface unknown",
@@ -1051,6 +1054,9 @@ DEFUN (ipv6_nd_ra_interval_msec,
VTY_DECLVAR_CONTEXT(interface, ifp);
unsigned interval;
struct zebra_if *zif = ifp->info;
+ struct zebra_vrf *zvrf;
+
+ zvrf = vrf_info_lookup(ifp->vrf_id);
interval = strtoul(argv[idx_number]->arg, NULL, 10);
if ((zif->rtadv.AdvDefaultLifetime != -1
@@ -1061,10 +1067,10 @@ DEFUN (ipv6_nd_ra_interval_msec,
}
if (zif->rtadv.MaxRtrAdvInterval % 1000)
- zrouter.rtadv.adv_msec_if_count--;
+ zvrf->rtadv.adv_msec_if_count--;
if (interval % 1000)
- zrouter.rtadv.adv_msec_if_count++;
+ zvrf->rtadv.adv_msec_if_count++;
SET_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED);
zif->rtadv.MaxRtrAdvInterval = interval;
@@ -1086,6 +1092,9 @@ DEFUN (ipv6_nd_ra_interval,
VTY_DECLVAR_CONTEXT(interface, ifp);
unsigned interval;
struct zebra_if *zif = ifp->info;
+ struct zebra_vrf *zvrf;
+
+ zvrf = vrf_info_lookup(ifp->vrf_id);
interval = strtoul(argv[idx_number]->arg, NULL, 10);
if ((zif->rtadv.AdvDefaultLifetime != -1
@@ -1096,7 +1105,7 @@ DEFUN (ipv6_nd_ra_interval,
}
if (zif->rtadv.MaxRtrAdvInterval % 1000)
- zrouter.rtadv.adv_msec_if_count--;
+ zvrf->rtadv.adv_msec_if_count--;
/* convert to milliseconds */
interval = interval * 1000;
@@ -1122,9 +1131,12 @@ DEFUN (no_ipv6_nd_ra_interval,
{
VTY_DECLVAR_CONTEXT(interface, ifp);
struct zebra_if *zif = ifp->info;
+ struct zebra_vrf *zvrf = NULL;
+
+ zvrf = vrf_info_lookup(ifp->vrf_id);
if (zif->rtadv.MaxRtrAdvInterval % 1000)
- zrouter.rtadv.adv_msec_if_count--;
+ zvrf->rtadv.adv_msec_if_count--;
UNSET_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED);
@@ -2094,15 +2106,15 @@ static int rtadv_config_write(struct vty *vty, struct interface *ifp)
}
-static void rtadv_event(struct zebra_ns *zns, enum rtadv_event event, int val)
+static void rtadv_event(struct zebra_vrf *zvrf, enum rtadv_event event, int val)
{
- struct rtadv *rtadv = &zrouter.rtadv;
+ struct rtadv *rtadv = &zvrf->rtadv;
switch (event) {
case RTADV_START:
- thread_add_read(zrouter.master, rtadv_read, zns, val,
+ thread_add_read(zrouter.master, rtadv_read, zvrf, val,
&rtadv->ra_read);
- thread_add_event(zrouter.master, rtadv_timer, zns, 0,
+ thread_add_event(zrouter.master, rtadv_timer, zvrf, 0,
&rtadv->ra_timer);
break;
case RTADV_STOP:
@@ -2116,15 +2128,15 @@ static void rtadv_event(struct zebra_ns *zns, enum rtadv_event event, int val)
}
break;
case RTADV_TIMER:
- thread_add_timer(zrouter.master, rtadv_timer, zns, val,
+ thread_add_timer(zrouter.master, rtadv_timer, zvrf, val,
&rtadv->ra_timer);
break;
case RTADV_TIMER_MSEC:
- thread_add_timer_msec(zrouter.master, rtadv_timer, zns, val,
+ thread_add_timer_msec(zrouter.master, rtadv_timer, zvrf, val,
&rtadv->ra_timer);
break;
case RTADV_READ:
- thread_add_read(zrouter.master, rtadv_read, zns, val,
+ thread_add_read(zrouter.master, rtadv_read, zvrf, val,
&rtadv->ra_read);
break;
default:
@@ -2133,21 +2145,29 @@ static void rtadv_event(struct zebra_ns *zns, enum rtadv_event event, int val)
return;
}
-void rtadv_init(struct zebra_ns *zns)
+void rtadv_init(struct zebra_vrf *zvrf)
{
- zrouter.rtadv.sock = rtadv_make_socket(zns->ns_id);
+ if (vrf_is_backend_netns()) {
+ zvrf->rtadv.sock = rtadv_make_socket(zvrf->zns->ns_id);
+ zrouter.rtadv_sock = -1;
+ } else if (!zrouter.rtadv_sock) {
+ zvrf->rtadv.sock = -1;
+ zrouter.rtadv_sock = rtadv_make_socket(zvrf->zns->ns_id);
+ }
}
-void rtadv_terminate(struct zebra_ns *zns)
+void rtadv_terminate(struct zebra_vrf *zvrf)
{
- rtadv_event(zns, RTADV_STOP, 0);
- if (zrouter.rtadv.sock >= 0) {
- close(zrouter.rtadv.sock);
- zrouter.rtadv.sock = -1;
+ rtadv_event(zvrf, RTADV_STOP, 0);
+ if (zvrf->rtadv.sock >= 0) {
+ close(zvrf->rtadv.sock);
+ zvrf->rtadv.sock = -1;
+ } else if (zrouter.rtadv_sock >= 0) {
+ close(zrouter.rtadv_sock);
+ zrouter.rtadv_sock = -1;
}
-
- zrouter.rtadv.adv_if_count = 0;
- zrouter.rtadv.adv_msec_if_count = 0;
+ zvrf->rtadv.adv_if_count = 0;
+ zvrf->rtadv.adv_msec_if_count = 0;
}
void rtadv_cmd_init(void)
@@ -2243,11 +2263,11 @@ static int if_leave_all_router(int sock, struct interface *ifp)
}
#else
-void rtadv_init(struct zebra_ns *zns)
+void rtadv_init(struct zebra_vrf *zvrf)
{
/* Empty.*/;
}
-void rtadv_terminate(struct zebra_ns *zns)
+void rtadv_terminate(struct zebra_vrf *zvrf)
{
/* Empty.*/;
}
diff --git a/zebra/rtadv.h b/zebra/rtadv.h
index 53c497fc09..8ad3de7f17 100644
--- a/zebra/rtadv.h
+++ b/zebra/rtadv.h
@@ -135,8 +135,8 @@ typedef enum {
RA_SUPPRESS,
} ipv6_nd_suppress_ra_status;
-extern void rtadv_init(struct zebra_ns *);
-extern void rtadv_terminate(struct zebra_ns *);
+extern void rtadv_init(struct zebra_vrf *);
+extern void rtadv_terminate(struct zebra_vrf *);
extern void rtadv_cmd_init(void);
extern void zebra_interface_radv_disable(ZAPI_HANDLER_ARGS);
extern void zebra_interface_radv_enable(ZAPI_HANDLER_ARGS);
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index 7f6af82018..974cc9de30 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -1388,7 +1388,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
re->type = api.type;
re->instance = api.instance;
re->flags = api.flags;
- re->uptime = time(NULL);
+ re->uptime = monotime(NULL);
re->vrf_id = vrf_id;
if (api.tableid && vrf_id == VRF_DEFAULT)
re->table = api.tableid;
diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c
index ae52762c5a..6fc62147c8 100644
--- a/zebra/zebra_dplane.c
+++ b/zebra/zebra_dplane.c
@@ -1574,8 +1574,7 @@ done:
else {
atomic_fetch_add_explicit(&zdplane_info.dg_lsp_errors, 1,
memory_order_relaxed);
- if (ctx)
- dplane_ctx_free(&ctx);
+ dplane_ctx_free(&ctx);
}
return result;
@@ -1609,8 +1608,7 @@ done:
else {
atomic_fetch_add_explicit(&zdplane_info.dg_pw_errors, 1,
memory_order_relaxed);
- if (ctx)
- dplane_ctx_free(&ctx);
+ dplane_ctx_free(&ctx);
}
return result;
@@ -1737,8 +1735,7 @@ static enum zebra_dplane_result intf_addr_update_internal(
/* Error counter */
atomic_fetch_add_explicit(&zdplane_info.dg_intf_addr_errors,
1, memory_order_relaxed);
- if (ctx)
- dplane_ctx_free(&ctx);
+ dplane_ctx_free(&ctx);
}
return result;
diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c
index bdc1dcdff3..16459b606a 100644
--- a/zebra/zebra_fpm_netlink.c
+++ b/zebra/zebra_fpm_netlink.c
@@ -270,7 +270,6 @@ static int netlink_route_info_fill(netlink_route_info_t *ri, int cmd,
ri->rtm_type = RTN_BLACKHOLE;
break;
}
- return 1;
}
if ((cmd == RTM_NEWROUTE
diff --git a/zebra/zebra_ns.c b/zebra/zebra_ns.c
index 0c743d8678..db4f9d0015 100644
--- a/zebra/zebra_ns.c
+++ b/zebra/zebra_ns.c
@@ -27,7 +27,6 @@
#include "lib/prefix.h"
#include "lib/memory.h"
-#include "rtadv.h"
#include "zebra_ns.h"
#include "zebra_vrf.h"
#include "zebra_memory.h"
@@ -122,10 +121,6 @@ int zebra_ns_enable(ns_id_t ns_id, void **info)
zns->ns_id = ns_id;
-#if defined(HAVE_RTADV)
- rtadv_init(zns);
-#endif
-
kernel_init(zns);
interface_list(zns);
route_read(zns);
@@ -142,9 +137,6 @@ int zebra_ns_enable(ns_id_t ns_id, void **info)
static int zebra_ns_disable_internal(struct zebra_ns *zns, bool complete)
{
route_table_finish(zns->if_table);
-#if defined(HAVE_RTADV)
- rtadv_terminate(zns);
-#endif
kernel_terminate(zns, complete);
diff --git a/zebra/zebra_ptm.c b/zebra/zebra_ptm.c
index bb352dc2ff..d3ecd3695a 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;
}
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 3623852afd..eddf6c8158 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -797,12 +797,6 @@ struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p, vrf_id_t vrf_id)
return NULL;
}
-#define RIB_SYSTEM_ROUTE(R) \
- ((R)->type == ZEBRA_ROUTE_KERNEL || (R)->type == ZEBRA_ROUTE_CONNECT)
-
-#define RIB_KERNEL_ROUTE(R) \
- ((R)->type == ZEBRA_ROUTE_KERNEL)
-
/* This function verifies reachability of one given nexthop, which can be
* numbered or unnumbered, IPv4 or IPv6. The result is unconditionally stored
* in nexthop->flags field. The nexthop->ifindex will be updated
@@ -3003,7 +2997,7 @@ int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
re->table = table_id;
re->vrf_id = vrf_id;
re->nexthop_num = 0;
- re->uptime = time(NULL);
+ re->uptime = monotime(NULL);
re->tag = tag;
/* Add nexthop. */
diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c
index 5d1cbbe781..5355fa062e 100644
--- a/zebra/zebra_routemap.c
+++ b/zebra/zebra_routemap.c
@@ -1798,8 +1798,7 @@ static void zebra_route_map_delete(const char *rmap_name)
route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_DELETED);
}
-static void zebra_route_map_event(route_map_event_t event,
- const char *rmap_name)
+static void zebra_route_map_event(const char *rmap_name)
{
if (route_map_mark_updated(rmap_name) == 0)
zebra_route_map_mark_update(rmap_name);
diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h
index b316b91d0d..c1f07397d0 100644
--- a/zebra/zebra_router.h
+++ b/zebra/zebra_router.h
@@ -82,9 +82,8 @@ struct zebra_router {
struct hash *iptable_hash;
-#if defined(HAVE_RTADV)
- struct rtadv rtadv;
-#endif /* HAVE_RTADV */
+ /* used if vrf backend is not network namespace */
+ int rtadv_sock;
/* A sequence number used for tracking routes */
_Atomic uint32_t sequence_num;
diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c
index 5a18534ac4..1f2ff63286 100644
--- a/zebra/zebra_vrf.c
+++ b/zebra/zebra_vrf.c
@@ -29,6 +29,7 @@
#include "vty.h"
#include "zebra/zebra_router.h"
+#include "zebra/rtadv.h"
#include "zebra/debug.h"
#include "zebra/zapi_msg.h"
#include "zebra/rib.h"
@@ -114,6 +115,10 @@ static int zebra_vrf_enable(struct vrf *vrf)
zvrf->zns = zebra_ns_lookup((ns_id_t)vrf->vrf_id);
else
zvrf->zns = zebra_ns_lookup(NS_DEFAULT);
+#if defined(HAVE_RTADV)
+ rtadv_init(zvrf);
+#endif
+
/* Inform clients that the VRF is now active. This is an
* add for the clients.
*/
@@ -156,6 +161,10 @@ static int zebra_vrf_disable(struct vrf *vrf)
/* Stop any VxLAN-EVPN processing. */
zebra_vxlan_vrf_disable(zvrf);
+#if defined(HAVE_RTADV)
+ rtadv_terminate(zvrf);
+#endif
+
/* Inform clients that the VRF is now inactive. This is a
* delete for the clients.
*/
diff --git a/zebra/zebra_vrf.h b/zebra/zebra_vrf.h
index c7a64d300a..2dd47b5561 100644
--- a/zebra/zebra_vrf.h
+++ b/zebra/zebra_vrf.h
@@ -155,6 +155,10 @@ struct zebra_vrf {
uint64_t lsp_removals_queued;
uint64_t lsp_installs;
uint64_t lsp_removals;
+
+#if defined(HAVE_RTADV)
+ struct rtadv rtadv;
+#endif /* HAVE_RTADV */
};
#define PROTO_RM_NAME(zvrf, afi, rtype) zvrf->proto_rm[afi][rtype].name
#define NHT_RM_NAME(zvrf, afi, rtype) zvrf->nht_rm[afi][rtype].name
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index 77795c6152..c4249b6366 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -230,7 +230,7 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn,
time_t uptime;
struct tm *tm;
- uptime = time(NULL);
+ uptime = monotime(NULL);
uptime -= re->uptime;
tm = gmtime(&uptime);
@@ -385,7 +385,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
struct tm *tm;
rib_dest_t *dest = rib_dest_from_rnode(rn);
- uptime = time(NULL);
+ uptime = monotime(NULL);
uptime -= re->uptime;
tm = gmtime(&uptime);
diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c
index baa050c9b9..605e9eae66 100644
--- a/zebra/zebra_vxlan.c
+++ b/zebra/zebra_vxlan.c
@@ -7505,9 +7505,9 @@ int zebra_vxlan_check_del_local_mac(struct interface *ifp,
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
- "Add/update remote MAC %s intf %s(%u) VNI %u - del local",
+ "Add/update remote MAC %s intf %s(%u) VNI %u flags 0x%x - del local",
prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name,
- ifp->ifindex, vni);
+ ifp->ifindex, vni, mac->flags);
/* Remove MAC from BGP. */
zvni_mac_send_del_to_client(zvni->vni, macaddr);
@@ -7520,6 +7520,7 @@ int zebra_vxlan_check_del_local_mac(struct interface *ifp,
zvni_mac_del(zvni, mac);
} else {
UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
+ UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
}
@@ -7603,11 +7604,6 @@ int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if,
return -1;
}
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("DEL MAC %s intf %s(%u) VID %u -> VNI %u",
- prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name,
- ifp->ifindex, vid, zvni->vni);
-
/* If entry doesn't exist, nothing to do. */
mac = zvni_mac_lookup(zvni, macaddr);
if (!mac)
@@ -7617,6 +7613,11 @@ int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if,
if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL))
return 0;
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("DEL MAC %s intf %s(%u) VID %u -> VNI %u flags 0x%x",
+ prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name,
+ ifp->ifindex, vid, zvni->vni, mac->flags);
+
/* Update all the neigh entries associated with this mac */
zvni_process_neigh_on_local_mac_del(zvni, mac);
@@ -7631,6 +7632,7 @@ int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if,
zvni_mac_del(zvni, mac);
} else {
UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
+ UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
}