summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_evpn_mh.h5
-rw-r--r--bgpd/bgp_mplsvpn.c19
-rw-r--r--bgpd/bgp_route.c21
-rw-r--r--bgpd/bgp_zebra.c6
-rw-r--r--bgpd/bgp_zebra.h2
-rw-r--r--doc/user/routemap.rst8
-rw-r--r--lib/sockopt.c3
-rw-r--r--lib/vty.h4
-rw-r--r--mgmtd/mgmt_fe_adapter.c3
-rw-r--r--mgmtd/mgmt_txn.c28
-rw-r--r--mgmtd/subdir.am1
-rw-r--r--nhrpd/netlink_arp.c5
-rw-r--r--ospfd/ospf_ri.c6
-rw-r--r--staticd/static_nht.c34
-rw-r--r--staticd/static_routes.c63
-rw-r--r--staticd/static_routes.h1
-rw-r--r--staticd/static_zebra.c2
-rw-r--r--tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf20_ipv4.json2
-rw-r--r--tests/topotests/bgp_vrf_route_leak_basic/r1/bgpd.conf17
-rw-r--r--tests/topotests/bgp_vrf_route_leak_basic/r1/zebra.conf10
-rw-r--r--tests/topotests/bgp_vrf_route_leak_basic/setup_vrfs1
-rw-r--r--tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py313
-rw-r--r--tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-default.txt2
-rw-r--r--tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-default.txt2
-rw-r--r--tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-ray.txt4
-rw-r--r--tests/topotests/static_vrf/r1/frr.conf18
-rw-r--r--tests/topotests/static_vrf/test_static_vrf.py126
-rw-r--r--vtysh/vtysh.c30
-rw-r--r--vtysh/vtysh_config.c10
-rw-r--r--zebra/zebra_evpn_mh.h2
30 files changed, 595 insertions, 153 deletions
diff --git a/bgpd/bgp_evpn_mh.h b/bgpd/bgp_evpn_mh.h
index ee1f74989b..cebabb9fd0 100644
--- a/bgpd/bgp_evpn_mh.h
+++ b/bgpd/bgp_evpn_mh.h
@@ -388,11 +388,6 @@ static inline bool bgp_evpn_attr_is_local_es(struct attr *attr)
return attr ? !!(attr->es_flags & ATTR_ES_IS_LOCAL) : false;
}
-static inline uint32_t bgp_evpn_attr_get_df_pref(struct attr *attr)
-{
- return (attr) ? attr->df_pref : 0;
-}
-
static inline bool bgp_evpn_local_es_is_active(struct bgp_evpn_es *es)
{
return (es->flags & BGP_EVPNES_OPER_UP)
diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
index 32436861f4..cd5cf5be54 100644
--- a/bgpd/bgp_mplsvpn.c
+++ b/bgpd/bgp_mplsvpn.c
@@ -2209,12 +2209,22 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
/* If the path has accept-own community and the source VRF
* is valid, reset next-hop to self, to allow importing own
* routes between different VRFs on the same node.
- * Set the nh ifindex to VRF's interface, not the real interface.
+ */
+
+ if (src_bgp)
+ subgroup_announce_reset_nhop(nhfamily, &static_attr);
+
+ bpi_ultimate = bgp_get_imported_bpi_ultimate(path_vpn);
+
+ /* The nh ifindex may not be defined (when the route is
+ * imported from the network statement => BGP_ROUTE_STATIC)
+ * or to the real interface.
+ * Rewrite the nh ifindex to VRF's interface.
* Let the kernel to decide with double lookup the real next-hop
* interface when installing the route.
*/
- if (src_bgp) {
- subgroup_announce_reset_nhop(nhfamily, &static_attr);
+ if (src_bgp || bpi_ultimate->sub_type == BGP_ROUTE_STATIC ||
+ bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE) {
ifp = if_get_vrf_loopback(src_vrf->vrf_id);
if (ifp)
static_attr.nh_ifindex = ifp->ifindex;
@@ -2300,9 +2310,6 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
*/
if (!CHECK_FLAG(to_bgp->af_flags[afi][safi],
BGP_CONFIG_VRF_TO_VRF_IMPORT)) {
- /* work back to original route */
- bpi_ultimate = bgp_get_imported_bpi_ultimate(path_vpn);
-
/*
* if original route was unicast,
* then it did not arrive over vpn
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 46f7f9b22f..32d822aad7 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -3520,7 +3520,8 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest,
*/
if (old_select &&
is_route_parent_evpn(old_select))
- bgp_zebra_withdraw(p, old_select, bgp, safi);
+ bgp_zebra_withdraw(p, old_select, bgp, afi,
+ safi);
bgp_zebra_announce(dest, p, new_select, bgp, afi, safi);
} else {
@@ -3530,7 +3531,8 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest,
|| old_select->sub_type == BGP_ROUTE_AGGREGATE
|| old_select->sub_type == BGP_ROUTE_IMPORTED))
- bgp_zebra_withdraw(p, old_select, bgp, safi);
+ bgp_zebra_withdraw(p, old_select, bgp, afi,
+ safi);
}
}
@@ -4427,7 +4429,7 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
if (pi && pi->attr->rmap_table_id != new_attr.rmap_table_id) {
if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED))
/* remove from RIB previous entry */
- bgp_zebra_withdraw(p, pi, bgp, safi);
+ bgp_zebra_withdraw(p, pi, bgp, afi, safi);
}
if (peer->sort == BGP_PEER_EBGP) {
@@ -6029,7 +6031,7 @@ bool bgp_inbound_policy_exists(struct peer *peer, struct bgp_filter *filter)
}
static void bgp_cleanup_table(struct bgp *bgp, struct bgp_table *table,
- safi_t safi)
+ afi_t afi, safi_t safi)
{
struct bgp_dest *dest;
struct bgp_path_info *pi;
@@ -6053,7 +6055,8 @@ static void bgp_cleanup_table(struct bgp *bgp, struct bgp_table *table,
|| pi->sub_type == BGP_ROUTE_IMPORTED)) {
if (bgp_fibupd_safi(safi))
- bgp_zebra_withdraw(p, pi, bgp, safi);
+ bgp_zebra_withdraw(p, pi, bgp, afi,
+ safi);
}
dest = bgp_path_info_reap(dest, pi);
@@ -6071,7 +6074,7 @@ void bgp_cleanup_routes(struct bgp *bgp)
for (afi = AFI_IP; afi < AFI_MAX; ++afi) {
if (afi == AFI_L2VPN)
continue;
- bgp_cleanup_table(bgp, bgp->rib[afi][SAFI_UNICAST],
+ bgp_cleanup_table(bgp, bgp->rib[afi][SAFI_UNICAST], afi,
SAFI_UNICAST);
/*
* VPN and ENCAP and EVPN tables are two-level (RD is top level)
@@ -6083,7 +6086,7 @@ void bgp_cleanup_routes(struct bgp *bgp)
dest = bgp_route_next(dest)) {
table = bgp_dest_get_bgp_table_info(dest);
if (table != NULL) {
- bgp_cleanup_table(bgp, table, safi);
+ bgp_cleanup_table(bgp, table, afi, safi);
bgp_table_finish(&table);
bgp_dest_set_bgp_table_info(dest, NULL);
dest = bgp_dest_unlock_node(dest);
@@ -6096,7 +6099,7 @@ void bgp_cleanup_routes(struct bgp *bgp)
dest = bgp_route_next(dest)) {
table = bgp_dest_get_bgp_table_info(dest);
if (table != NULL) {
- bgp_cleanup_table(bgp, table, safi);
+ bgp_cleanup_table(bgp, table, afi, safi);
bgp_table_finish(&table);
bgp_dest_set_bgp_table_info(dest, NULL);
dest = bgp_dest_unlock_node(dest);
@@ -6110,7 +6113,7 @@ void bgp_cleanup_routes(struct bgp *bgp)
dest = bgp_route_next(dest)) {
table = bgp_dest_get_bgp_table_info(dest);
if (table != NULL) {
- bgp_cleanup_table(bgp, table, SAFI_EVPN);
+ bgp_cleanup_table(bgp, table, afi, SAFI_EVPN);
bgp_table_finish(&table);
bgp_dest_set_bgp_table_info(dest, NULL);
dest = bgp_dest_unlock_node(dest);
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 0db0ac4873..dcbb87e969 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -1724,7 +1724,7 @@ void bgp_zebra_announce_table_all_subtypes(struct bgp *bgp, afi_t afi,
}
void bgp_zebra_withdraw(const struct prefix *p, struct bgp_path_info *info,
- struct bgp *bgp, safi_t safi)
+ struct bgp *bgp, afi_t afi, safi_t safi)
{
struct zapi_route api;
struct peer *peer;
@@ -1743,7 +1743,7 @@ void bgp_zebra_withdraw(const struct prefix *p, struct bgp_path_info *info,
if (safi == SAFI_FLOWSPEC) {
peer = info->peer;
- bgp_pbr_update_entry(peer->bgp, p, info, AFI_IP, safi, false);
+ bgp_pbr_update_entry(peer->bgp, p, info, afi, safi, false);
return;
}
@@ -1784,7 +1784,7 @@ void bgp_zebra_withdraw_table_all_subtypes(struct bgp *bgp, afi_t afi, safi_t sa
if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)
&& (pi->type == ZEBRA_ROUTE_BGP))
bgp_zebra_withdraw(bgp_dest_get_prefix(dest),
- pi, bgp, safi);
+ pi, bgp, afi, safi);
}
}
}
diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h
index 4696e4dc44..396c8335f8 100644
--- a/bgpd/bgp_zebra.h
+++ b/bgpd/bgp_zebra.h
@@ -34,7 +34,7 @@ extern void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
extern void bgp_zebra_announce_table(struct bgp *bgp, afi_t afi, safi_t safi);
extern void bgp_zebra_withdraw(const struct prefix *p,
struct bgp_path_info *path, struct bgp *bgp,
- safi_t safi);
+ afi_t afi, safi_t safi);
/* Announce routes of any bgp subtype of a table to zebra */
extern void bgp_zebra_announce_table_all_subtypes(struct bgp *bgp, afi_t afi,
diff --git a/doc/user/routemap.rst b/doc/user/routemap.rst
index 18a261d940..791762aa7b 100644
--- a/doc/user/routemap.rst
+++ b/doc/user/routemap.rst
@@ -380,13 +380,13 @@ Route Map Exit Action Command
.. clicmd:: on-match next
-.. clicmd:: continue
-
Proceed on to the next entry in the route-map.
-.. clicmd:: on-match goto N
+.. clicmd:: continue (1-65535)
-.. clicmd:: continue N
+ Proceed to the specified sequence in the route-map.
+
+.. clicmd:: on-match goto N
Proceed processing the route-map at the first entry whose order is >= N
diff --git a/lib/sockopt.c b/lib/sockopt.c
index b9b9a71167..74bc034ccd 100644
--- a/lib/sockopt.c
+++ b/lib/sockopt.c
@@ -672,6 +672,9 @@ int sockopt_tcp_mss_get(int sock)
int tcp_maxseg = 0;
socklen_t tcp_maxseg_len = sizeof(tcp_maxseg);
+ if (sock < 0)
+ return 0;
+
ret = getsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, &tcp_maxseg,
&tcp_maxseg_len);
if (ret != 0) {
diff --git a/lib/vty.h b/lib/vty.h
index 06973da916..a59ac7a652 100644
--- a/lib/vty.h
+++ b/lib/vty.h
@@ -232,10 +232,6 @@ struct vty {
uintptr_t mgmt_req_pending_data;
bool mgmt_locked_candidate_ds;
bool mgmt_locked_running_ds;
- /* Need to track when we file-lock in vtysh to re-lock on end/conf t
- * workaround
- */
- bool vtysh_file_locked;
};
static inline void vty_push_context(struct vty *vty, int node, uint64_t id)
diff --git a/mgmtd/mgmt_fe_adapter.c b/mgmtd/mgmt_fe_adapter.c
index 001da7680b..ec8e773354 100644
--- a/mgmtd/mgmt_fe_adapter.c
+++ b/mgmtd/mgmt_fe_adapter.c
@@ -711,9 +711,6 @@ mgmt_fe_session_handle_setcfg_req_msg(struct mgmt_fe_session_ctx *session,
}
if (session->cfg_txn_id == MGMTD_TXN_ID_NONE) {
- /* as we have the lock no-one else should have a config txn */
- assert(!mgmt_config_txn_in_progress());
-
/* Start a CONFIG Transaction (if not started already) */
session->cfg_txn_id = mgmt_create_txn(session->session_id,
MGMTD_TXN_TYPE_CONFIG);
diff --git a/mgmtd/mgmt_txn.c b/mgmtd/mgmt_txn.c
index df2a1d852d..664f42f4ba 100644
--- a/mgmtd/mgmt_txn.c
+++ b/mgmtd/mgmt_txn.c
@@ -105,6 +105,7 @@ struct mgmt_commit_cfg_req {
uint8_t abort : 1;
uint8_t implicit : 1;
uint8_t rollback : 1;
+ uint8_t init : 1;
/* Track commit phases */
enum mgmt_commit_phase phase;
@@ -750,6 +751,14 @@ static int mgmt_txn_send_commit_cfg_reply(struct mgmt_txn_ctx *txn,
mgmt_history_rollback_complete(success);
}
+ if (txn->commit_cfg_req->req.commit_cfg.init) {
+ /*
+ * This is the backend init request.
+ * We need to unlock the running datastore.
+ */
+ mgmt_ds_unlock(txn->commit_cfg_req->req.commit_cfg.dst_ds_ctx);
+ }
+
txn->commit_cfg_req->req.commit_cfg.cmt_stats = NULL;
mgmt_txn_req_free(&txn->commit_cfg_req);
@@ -2081,15 +2090,26 @@ int mgmt_txn_notify_be_adapter_conn(struct mgmt_be_client_adapter *adapter,
struct mgmt_commit_cfg_req *cmtcfg_req;
static struct mgmt_commit_stats dummy_stats;
struct nb_config_cbs *adapter_cfgs = NULL;
+ struct mgmt_ds_ctx *ds_ctx;
memset(&dummy_stats, 0, sizeof(dummy_stats));
if (connect) {
- /* Get config for this single backend client */
+ ds_ctx = mgmt_ds_get_ctx_by_id(mm, MGMTD_DS_RUNNING);
+ assert(ds_ctx);
+
+ /*
+ * Lock the running datastore to prevent any changes while we
+ * are initializing the backend.
+ */
+ if (mgmt_ds_lock(ds_ctx, 0) != 0)
+ return -1;
+ /* Get config for this single backend client */
mgmt_be_get_adapter_config(adapter, &adapter_cfgs);
if (!adapter_cfgs || RB_EMPTY(nb_config_cbs, adapter_cfgs)) {
SET_FLAG(adapter->flags,
MGMTD_BE_ADAPTER_FLAGS_CFG_SYNCED);
+ mgmt_ds_unlock(ds_ctx);
return 0;
}
@@ -2101,6 +2121,7 @@ int mgmt_txn_notify_be_adapter_conn(struct mgmt_be_client_adapter *adapter,
if (!txn) {
__log_err("Failed to create CONFIG Transaction for downloading CONFIGs for client '%s'",
adapter->name);
+ mgmt_ds_unlock(ds_ctx);
nb_config_diff_del_changes(adapter_cfgs);
return -1;
}
@@ -2114,10 +2135,11 @@ int mgmt_txn_notify_be_adapter_conn(struct mgmt_be_client_adapter *adapter,
txn_req = mgmt_txn_req_alloc(txn, 0, MGMTD_TXN_PROC_COMMITCFG);
txn_req->req.commit_cfg.src_ds_id = MGMTD_DS_NONE;
txn_req->req.commit_cfg.src_ds_ctx = 0;
- txn_req->req.commit_cfg.dst_ds_id = MGMTD_DS_NONE;
- txn_req->req.commit_cfg.dst_ds_ctx = 0;
+ txn_req->req.commit_cfg.dst_ds_id = MGMTD_DS_RUNNING;
+ txn_req->req.commit_cfg.dst_ds_ctx = ds_ctx;
txn_req->req.commit_cfg.validate_only = false;
txn_req->req.commit_cfg.abort = false;
+ txn_req->req.commit_cfg.init = true;
txn_req->req.commit_cfg.cmt_stats = &dummy_stats;
txn_req->req.commit_cfg.cfg_chgs = adapter_cfgs;
diff --git a/mgmtd/subdir.am b/mgmtd/subdir.am
index 3eaa9567ab..1624c6e4f9 100644
--- a/mgmtd/subdir.am
+++ b/mgmtd/subdir.am
@@ -19,7 +19,6 @@ mgmtd_libmgmt_be_nb_la_SOURCES = \
zebra/zebra_cli.c \
# end
nodist_mgmtd_libmgmt_be_nb_la_SOURCES = \
- lib/affinitymap_cli.c \
# end
mgmtd_libmgmt_be_nb_la_CFLAGS = $(AM_CFLAGS) -DINCLUDE_MGMTD_CMDDEFS_ONLY
mgmtd_libmgmt_be_nb_la_CPPFLAGS = $(AM_CPPFLAGS) -DINCLUDE_MGMTD_CMDDEFS_ONLY
diff --git a/nhrpd/netlink_arp.c b/nhrpd/netlink_arp.c
index 88628999ab..be909c862a 100644
--- a/nhrpd/netlink_arp.c
+++ b/nhrpd/netlink_arp.c
@@ -191,6 +191,11 @@ int nhrp_neighbor_operation(ZAPI_CALLBACK_ARGS)
"Netlink: update binding for %pSU dev %s from c %pSU peer.vc.nbma %pSU to lladdr %pSU",
&addr, ifp->name, &c->cur.remote_nbma_natoa,
&c->cur.peer->vc->remote.nbma, &lladdr);
+
+ if (lladdr.sa.sa_family == AF_UNSPEC)
+ /* nothing from zebra, so use nhrp peer */
+ lladdr = c->cur.peer->vc->remote.nbma;
+
/* In case of shortcuts, nbma is given by lladdr, not
* vc->remote.nbma.
*/
diff --git a/ospfd/ospf_ri.c b/ospfd/ospf_ri.c
index c6aaf3f5a0..723ccf59af 100644
--- a/ospfd/ospf_ri.c
+++ b/ospfd/ospf_ri.c
@@ -1723,9 +1723,11 @@ DEFUN (router_info,
DEFUN (no_router_info,
no_router_info_cmd,
- "no router-info",
+ "no router-info [<area|as>]",
NO_STR
- "Disable the Router Information functionality\n")
+ "Disable the Router Information functionality\n"
+ "Disable the Router Information functionality with AS flooding scope\n"
+ "Disable the Router Information functionality with Area flooding scope\n")
{
if (!OspfRI.enabled)
diff --git a/staticd/static_nht.c b/staticd/static_nht.c
index ebc5ea16cc..6be598434d 100644
--- a/staticd/static_nht.c
+++ b/staticd/static_nht.c
@@ -18,8 +18,7 @@
#include "static_nht.h"
static void static_nht_update_path(struct static_path *pn, struct prefix *nhp,
- uint32_t nh_num, vrf_id_t nh_vrf_id,
- struct vrf *vrf)
+ uint32_t nh_num, vrf_id_t nh_vrf_id)
{
struct static_nexthop *nh;
@@ -49,18 +48,13 @@ static void static_nht_update_path(struct static_path *pn, struct prefix *nhp,
static void static_nht_update_safi(struct prefix *sp, struct prefix *nhp,
uint32_t nh_num, afi_t afi, safi_t safi,
- struct vrf *vrf, vrf_id_t nh_vrf_id)
+ struct static_vrf *svrf, vrf_id_t nh_vrf_id)
{
struct route_table *stable;
- struct static_vrf *svrf;
struct route_node *rn;
struct static_path *pn;
struct static_route_info *si;
- svrf = vrf->info;
- if (!svrf)
- return;
-
stable = static_vrf_static_table(afi, safi, svrf);
if (!stable)
return;
@@ -71,7 +65,7 @@ static void static_nht_update_safi(struct prefix *sp, struct prefix *nhp,
si = static_route_info_from_rnode(rn);
frr_each(static_path_list, &si->path_list, pn) {
static_nht_update_path(pn, nhp, nh_num,
- nh_vrf_id, vrf);
+ nh_vrf_id);
}
route_unlock_node(rn);
}
@@ -83,7 +77,7 @@ static void static_nht_update_safi(struct prefix *sp, struct prefix *nhp,
if (!si)
continue;
frr_each(static_path_list, &si->path_list, pn) {
- static_nht_update_path(pn, nhp, nh_num, nh_vrf_id, vrf);
+ static_nht_update_path(pn, nhp, nh_num, nh_vrf_id);
}
}
}
@@ -91,29 +85,23 @@ static void static_nht_update_safi(struct prefix *sp, struct prefix *nhp,
void static_nht_update(struct prefix *sp, struct prefix *nhp, uint32_t nh_num,
afi_t afi, safi_t safi, vrf_id_t nh_vrf_id)
{
+ struct static_vrf *svrf;
- struct vrf *vrf;
-
- RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name)
- static_nht_update_safi(sp, nhp, nh_num, afi, safi, vrf,
+ RB_FOREACH (svrf, svrf_name_head, &svrfs)
+ static_nht_update_safi(sp, nhp, nh_num, afi, safi, svrf,
nh_vrf_id);
}
static void static_nht_reset_start_safi(struct prefix *nhp, afi_t afi,
- safi_t safi, struct vrf *vrf,
+ safi_t safi, struct static_vrf *svrf,
vrf_id_t nh_vrf_id)
{
- struct static_vrf *svrf;
struct route_table *stable;
struct static_nexthop *nh;
struct static_path *pn;
struct route_node *rn;
struct static_route_info *si;
- svrf = vrf->info;
- if (!svrf)
- return;
-
stable = static_vrf_static_table(afi, safi, svrf);
if (!stable)
return;
@@ -153,10 +141,10 @@ static void static_nht_reset_start_safi(struct prefix *nhp, afi_t afi,
void static_nht_reset_start(struct prefix *nhp, afi_t afi, safi_t safi,
vrf_id_t nh_vrf_id)
{
- struct vrf *vrf;
+ struct static_vrf *svrf;
- RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name)
- static_nht_reset_start_safi(nhp, afi, safi, vrf, nh_vrf_id);
+ RB_FOREACH (svrf, svrf_name_head, &svrfs)
+ static_nht_reset_start_safi(nhp, afi, safi, svrf, nh_vrf_id);
}
static void static_nht_mark_state_safi(struct prefix *sp, afi_t afi,
diff --git a/staticd/static_routes.c b/staticd/static_routes.c
index db3fc32fd8..cba38183bb 100644
--- a/staticd/static_routes.c
+++ b/staticd/static_routes.c
@@ -87,11 +87,6 @@ void zebra_stable_node_cleanup(struct route_table *table,
/* Install static path into rib. */
void static_install_path(struct static_path *pn)
{
- struct static_nexthop *nh;
-
- frr_each(static_nexthop_list, &pn->nexthop_list, nh)
- static_zebra_nht_register(nh, true);
-
if (static_nexthop_list_count(&pn->nexthop_list))
static_zebra_route_add(pn, true);
}
@@ -377,6 +372,17 @@ void static_install_nexthop(struct static_nexthop *nh)
}
}
+void static_uninstall_nexthop(struct static_nexthop *nh)
+{
+ struct static_path *pn = nh->pn;
+
+ if (nh->nh_vrf_id == VRF_UNKNOWN)
+ return;
+
+ static_zebra_nht_register(nh, false);
+ static_uninstall_path(pn);
+}
+
void static_delete_nexthop(struct static_nexthop *nh)
{
struct static_path *pn = nh->pn;
@@ -386,17 +392,8 @@ void static_delete_nexthop(struct static_nexthop *nh)
/* Remove BFD session/configuration if any. */
bfd_sess_free(&nh->bsp);
- if (nh->nh_vrf_id == VRF_UNKNOWN)
- goto EXIT;
+ static_uninstall_nexthop(nh);
- static_zebra_nht_register(nh, false);
- /*
- * If we have other si nodes then route replace
- * else delete the route
- */
- static_uninstall_path(pn);
-
-EXIT:
route_unlock_node(rn);
/* Free static route configuration. */
XFREE(MTYPE_STATIC_NEXTHOP, nh);
@@ -490,7 +487,6 @@ static void static_fixup_vrf(struct vrf *vrf, struct route_table *stable,
continue;
nh->nh_vrf_id = vrf->vrf_id;
- nh->nh_registered = false;
if (nh->ifname[0]) {
ifp = if_lookup_by_name(nh->ifname,
nh->nh_vrf_id);
@@ -500,7 +496,7 @@ static void static_fixup_vrf(struct vrf *vrf, struct route_table *stable,
continue;
}
- static_install_path(pn);
+ static_install_nexthop(nh);
}
}
}
@@ -518,8 +514,6 @@ static void static_fixup_vrf(struct vrf *vrf, struct route_table *stable,
static void static_enable_vrf(struct route_table *stable, afi_t afi, safi_t safi)
{
struct route_node *rn;
- struct static_nexthop *nh;
- struct interface *ifp;
struct static_path *pn;
struct static_route_info *si;
@@ -527,22 +521,8 @@ static void static_enable_vrf(struct route_table *stable, afi_t afi, safi_t safi
si = static_route_info_from_rnode(rn);
if (!si)
continue;
- frr_each(static_path_list, &si->path_list, pn) {
- frr_each(static_nexthop_list, &pn->nexthop_list, nh) {
- if (nh->nh_vrf_id == VRF_UNKNOWN)
- continue;
- if (nh->ifname[0]) {
- ifp = if_lookup_by_name(nh->ifname,
- nh->nh_vrf_id);
- if (ifp)
- nh->ifindex = ifp->ifindex;
- else
- continue;
- }
-
- static_install_path(pn);
- }
- }
+ frr_each(static_path_list, &si->path_list, pn)
+ static_install_path(pn);
}
}
@@ -604,7 +584,7 @@ static void static_cleanup_vrf(struct vrf *vrf, struct route_table *stable,
if (strcmp(vrf->name, nh->nh_vrfname) != 0)
continue;
- static_uninstall_path(pn);
+ static_uninstall_nexthop(nh);
nh->nh_vrf_id = VRF_UNKNOWN;
nh->ifindex = IFINDEX_INTERNAL;
@@ -625,7 +605,6 @@ static void static_disable_vrf(struct route_table *stable,
afi_t afi, safi_t safi)
{
struct route_node *rn;
- struct static_nexthop *nh;
struct static_path *pn;
struct static_route_info *si;
@@ -633,14 +612,8 @@ static void static_disable_vrf(struct route_table *stable,
si = static_route_info_from_rnode(rn);
if (!si)
continue;
- frr_each(static_path_list, &si->path_list, pn) {
- frr_each(static_nexthop_list, &pn->nexthop_list, nh) {
- if (nh->nh_vrf_id == VRF_UNKNOWN)
- continue;
-
- static_uninstall_path(pn);
- }
- }
+ frr_each(static_path_list, &si->path_list, pn)
+ static_uninstall_path(pn);
}
}
diff --git a/staticd/static_routes.h b/staticd/static_routes.h
index d88ed29364..2e2e4986c3 100644
--- a/staticd/static_routes.h
+++ b/staticd/static_routes.h
@@ -207,6 +207,7 @@ static_add_nexthop(struct static_path *pn, enum static_nh_type type,
struct ipaddr *ipaddr, const char *ifname,
const char *nh_vrf, uint32_t color);
extern void static_install_nexthop(struct static_nexthop *nh);
+extern void static_uninstall_nexthop(struct static_nexthop *nh);
extern void static_delete_nexthop(struct static_nexthop *nh);
diff --git a/staticd/static_zebra.c b/staticd/static_zebra.c
index a635cccb09..c4efc14a9d 100644
--- a/staticd/static_zebra.c
+++ b/staticd/static_zebra.c
@@ -390,7 +390,7 @@ extern void static_zebra_route_add(struct static_path *pn, bool install)
struct zapi_route api;
uint32_t nh_num = 0;
- if (!si->svrf->vrf)
+ if (!si->svrf->vrf || si->svrf->vrf->vrf_id == VRF_UNKNOWN)
return;
p = src_pp = NULL;
diff --git a/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf20_ipv4.json b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf20_ipv4.json
index 9f78447255..2ce936b291 100644
--- a/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf20_ipv4.json
+++ b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf20_ipv4.json
@@ -12,7 +12,7 @@
{
"fib": true,
"directlyConnected": true,
- "interfaceName": "eth0",
+ "interfaceName": "vrf10",
"vrf": "vrf10",
"active": true
}
diff --git a/tests/topotests/bgp_vrf_route_leak_basic/r1/bgpd.conf b/tests/topotests/bgp_vrf_route_leak_basic/r1/bgpd.conf
index 03dfbf9322..f52f56b0e0 100644
--- a/tests/topotests/bgp_vrf_route_leak_basic/r1/bgpd.conf
+++ b/tests/topotests/bgp_vrf_route_leak_basic/r1/bgpd.conf
@@ -1,10 +1,19 @@
hostname r1
+router bgp 99
+ no bgp ebgp-requires-policy
+ address-family ipv4 unicast
+ redistribute connected
+ import vrf DONNA
+ !
+!
router bgp 99 vrf DONNA
no bgp ebgp-requires-policy
address-family ipv4 unicast
redistribute connected
import vrf EVA
+ import vrf NOTEXISTING
+ import vrf default
!
!
router bgp 99 vrf EVA
@@ -12,5 +21,13 @@ router bgp 99 vrf EVA
address-family ipv4 unicast
redistribute connected
import vrf DONNA
+ import vrf NOTEXISTING
+ !
+!
+router bgp 99 vrf NOTEXISTING
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ address-family ipv4 unicast
+ network 172.16.101.0/24
!
!
diff --git a/tests/topotests/bgp_vrf_route_leak_basic/r1/zebra.conf b/tests/topotests/bgp_vrf_route_leak_basic/r1/zebra.conf
index 35038557df..4de9e895a2 100644
--- a/tests/topotests/bgp_vrf_route_leak_basic/r1/zebra.conf
+++ b/tests/topotests/bgp_vrf_route_leak_basic/r1/zebra.conf
@@ -1,5 +1,9 @@
hostname r1
+int dummy0
+ ip address 10.0.4.1/24
+ no shut
+!
int dummy1
ip address 10.0.0.1/24
no shut
@@ -16,3 +20,9 @@ int dummy4
ip address 10.0.3.1/24
no shut
!
+int EVA
+ no shut
+!
+int DONNA
+ no shut
+!
diff --git a/tests/topotests/bgp_vrf_route_leak_basic/setup_vrfs b/tests/topotests/bgp_vrf_route_leak_basic/setup_vrfs
index fb67953fe3..f62c5cd211 100644
--- a/tests/topotests/bgp_vrf_route_leak_basic/setup_vrfs
+++ b/tests/topotests/bgp_vrf_route_leak_basic/setup_vrfs
@@ -3,6 +3,7 @@
ip link add DONNA type vrf table 1001
ip link add EVA type vrf table 1002
+ip link add dummy0 type dummy # vrf default
ip link add dummy1 type dummy
ip link add dummy2 type dummy
ip link add dummy3 type dummy
diff --git a/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py b/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py
index fd7ffff17c..ef813e9541 100644
--- a/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py
+++ b/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py
@@ -64,7 +64,7 @@ def teardown_module(mod):
tgen.stop_topology()
-def test_vrf_route_leak():
+def test_vrf_route_leak_donna():
logger.info("Ensure that routes are leaked back and forth")
tgen = get_topogen()
# Don't run this test if we have any failure.
@@ -81,11 +81,59 @@ def test_vrf_route_leak():
}
],
"10.0.1.0/24": [
- {"protocol": "bgp", "selected": True, "nexthops": [{"fib": True}]}
+ {
+ "protocol": "bgp",
+ "selected": True,
+ "nexthops": [
+ {
+ "fib": True,
+ "interfaceName": "EVA",
+ "vrf": "EVA",
+ "active": True,
+ },
+ ],
+ },
],
"10.0.2.0/24": [{"protocol": "connected"}],
"10.0.3.0/24": [
- {"protocol": "bgp", "selected": True, "nexthops": [{"fib": True}]}
+ {
+ "protocol": "bgp",
+ "selected": True,
+ "nexthops": [
+ {
+ "fib": True,
+ "interfaceName": "EVA",
+ "vrf": "EVA",
+ "active": True,
+ },
+ ],
+ },
+ ],
+ "10.0.4.0/24": [
+ {
+ "protocol": "bgp",
+ "selected": True,
+ "nexthops": [
+ {
+ "fib": True,
+ "interfaceName": "lo",
+ "vrf": "default",
+ "active": True,
+ },
+ ],
+ },
+ ],
+ "172.16.101.0/24": [
+ {
+ "protocol": "bgp",
+ "nexthops": [
+ {
+ "interfaceIndex": 0,
+ "interfaceName": "unknown",
+ "vrf": "Unknown",
+ },
+ ],
+ },
],
}
@@ -95,10 +143,31 @@ def test_vrf_route_leak():
result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
assert result, "BGP VRF DONNA check failed:\n{}".format(diff)
+
+def test_vrf_route_leak_eva():
+ logger.info("Ensure that routes are leaked back and forth")
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"]
+
# Test EVA VRF.
expect = {
"10.0.0.0/24": [
- {"protocol": "bgp", "selected": True, "nexthops": [{"fib": True}]}
+ {
+ "protocol": "bgp",
+ "selected": True,
+ "nexthops": [
+ {
+ "fib": True,
+ "interfaceName": "DONNA",
+ "vrf": "DONNA",
+ "active": True,
+ },
+ ],
+ },
],
"10.0.1.0/24": [
{
@@ -106,13 +175,36 @@ def test_vrf_route_leak():
}
],
"10.0.2.0/24": [
- {"protocol": "bgp", "selected": True, "nexthops": [{"fib": True}]}
+ {
+ "protocol": "bgp",
+ "selected": True,
+ "nexthops": [
+ {
+ "fib": True,
+ "interfaceName": "DONNA",
+ "vrf": "DONNA",
+ "active": True,
+ },
+ ],
+ },
],
"10.0.3.0/24": [
{
"protocol": "connected",
}
],
+ "172.16.101.0/24": [
+ {
+ "protocol": "bgp",
+ "nexthops": [
+ {
+ "interfaceIndex": 0,
+ "interfaceName": "unknown",
+ "vrf": "Unknown",
+ },
+ ],
+ },
+ ],
}
test_func = partial(
@@ -122,6 +214,217 @@ def test_vrf_route_leak():
assert result, "BGP VRF EVA check failed:\n{}".format(diff)
+def test_vrf_route_leak_donna():
+ logger.info("Ensure that routes are leaked back and forth")
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"]
+
+ # Test DONNA VRF.
+ expect = {
+ "10.0.0.0/24": [
+ {
+ "protocol": "connected",
+ }
+ ],
+ "10.0.1.0/24": [
+ {
+ "protocol": "bgp",
+ "selected": True,
+ "nexthops": [
+ {
+ "fib": True,
+ "interfaceName": "EVA",
+ "vrf": "EVA",
+ "active": True,
+ },
+ ],
+ },
+ ],
+ "10.0.2.0/24": [{"protocol": "connected"}],
+ "10.0.3.0/24": [
+ {
+ "protocol": "bgp",
+ "selected": True,
+ "nexthops": [
+ {
+ "fib": True,
+ "interfaceName": "EVA",
+ "vrf": "EVA",
+ "active": True,
+ },
+ ],
+ },
+ ],
+ "10.0.4.0/24": [
+ {
+ "protocol": "bgp",
+ "selected": True,
+ "nexthops": [
+ {
+ "fib": True,
+ "interfaceName": "lo",
+ "vrf": "default",
+ "active": True,
+ },
+ ],
+ },
+ ],
+ "172.16.101.0/24": [
+ {
+ "protocol": "bgp",
+ "nexthops": [
+ {
+ "interfaceIndex": 0,
+ "interfaceName": "unknown",
+ "vrf": "Unknown",
+ },
+ ],
+ },
+ ],
+ }
+
+ test_func = partial(
+ topotest.router_json_cmp, r1, "show ip route vrf DONNA json", expect
+ )
+ result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
+ assert result, "BGP VRF DONNA check failed:\n{}".format(diff)
+
+
+def test_vrf_route_leak_eva():
+ logger.info("Ensure that routes are leaked back and forth")
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"]
+
+ # Test EVA VRF.
+ expect = {
+ "10.0.0.0/24": [
+ {
+ "protocol": "bgp",
+ "selected": True,
+ "nexthops": [
+ {
+ "fib": True,
+ "interfaceName": "DONNA",
+ "vrf": "DONNA",
+ "active": True,
+ },
+ ],
+ },
+ ],
+ "10.0.1.0/24": [
+ {
+ "protocol": "connected",
+ }
+ ],
+ "10.0.2.0/24": [
+ {
+ "protocol": "bgp",
+ "selected": True,
+ "nexthops": [
+ {
+ "fib": True,
+ "interfaceName": "DONNA",
+ "vrf": "DONNA",
+ "active": True,
+ },
+ ],
+ },
+ ],
+ "10.0.3.0/24": [
+ {
+ "protocol": "connected",
+ }
+ ],
+ "172.16.101.0/24": [
+ {
+ "protocol": "bgp",
+ "nexthops": [
+ {
+ "interfaceIndex": 0,
+ "interfaceName": "unknown",
+ "vrf": "Unknown",
+ },
+ ],
+ },
+ ],
+ }
+
+
+def test_vrf_route_leak_default():
+ logger.info("Ensure that routes are leaked back and forth")
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"]
+
+ # Test default VRF.
+ expect = {
+ "10.0.0.0/24": [
+ {
+ "protocol": "bgp",
+ "selected": True,
+ "nexthops": [
+ {
+ "fib": True,
+ "interfaceName": "DONNA",
+ "vrf": "DONNA",
+ "active": True,
+ },
+ ],
+ },
+ ],
+ "10.0.2.0/24": [
+ {
+ "protocol": "bgp",
+ "selected": True,
+ "nexthops": [
+ {
+ "fib": True,
+ "interfaceName": "DONNA",
+ "vrf": "DONNA",
+ "active": True,
+ },
+ ],
+ },
+ ],
+ "10.0.4.0/24": [
+ {
+ "protocol": "connected",
+ }
+ ],
+ }
+
+ test_func = partial(topotest.router_json_cmp, r1, "show ip route json", expect)
+ result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
+ assert result, "BGP VRF default check failed:\n{}".format(diff)
+
+
+def test_ping():
+ "Simple ping tests"
+
+ tgen = get_topogen()
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"]
+
+ logger.info("Ping from default to DONNA")
+ output = r1.run("ping -c 4 -w 4 -I 10.0.4.1 10.0.0.1")
+ assert " 0% packet loss" in output, "Ping default->DONNA FAILED"
+
+
def test_memory_leak():
"Run the memory leak test and report results."
tgen = get_topogen()
diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-default.txt b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-default.txt
index ca9ca77bf5..248375dc6c 100644
--- a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-default.txt
+++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-default.txt
@@ -7,5 +7,5 @@ O>* 10.0.4.0/24 [110/20] via 10.0.20.2, r1-eth1, weight 1, XX:XX:XX
O 10.0.20.0/24 [110/10] is directly connected, r1-eth1, weight 1, XX:XX:XX
C>* 10.0.20.0/24 is directly connected, r1-eth1, XX:XX:XX
L>* 10.0.20.1/32 is directly connected, r1-eth1, XX:XX:XX
-B>* 10.0.30.0/24 [20/0] is directly connected, r1-eth2 (vrf neno), weight 1, XX:XX:XX
+B>* 10.0.30.0/24 [20/0] is directly connected, neno (vrf neno), weight 1, XX:XX:XX
O>* 10.0.40.0/24 [110/20] via 10.0.20.2, r1-eth1, weight 1, XX:XX:XX
diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-default.txt b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-default.txt
index 70ae987894..d7d31434c6 100644
--- a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-default.txt
+++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-default.txt
@@ -9,4 +9,4 @@ O 10.0.20.0/24 [110/10] is directly connected, r2-eth1, weight 1, XX:XX:XX
C>* 10.0.20.0/24 is directly connected, r2-eth1, XX:XX:XX
L>* 10.0.20.2/32 is directly connected, r2-eth1, XX:XX:XX
O>* 10.0.30.0/24 [110/20] via 10.0.20.1, r2-eth1, weight 1, XX:XX:XX
-B>* 10.0.40.0/24 [20/0] is directly connected, r2-eth2 (vrf ray), weight 1, XX:XX:XX
+B>* 10.0.40.0/24 [20/0] is directly connected, ray (vrf ray), weight 1, XX:XX:XX
diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-ray.txt b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-ray.txt
index 1495c88936..6ab1bb8f92 100644
--- a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-ray.txt
+++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-ray.txt
@@ -1,9 +1,9 @@
VRF ray:
B 10.0.1.0/24 [20/20] via 10.0.20.1, r2-eth1 (vrf default) inactive, weight 1, XX:XX:XX
-B 10.0.2.0/24 [20/0] is directly connected, r2-eth0 (vrf default) inactive, weight 1, XX:XX:XX
+B 10.0.2.0/24 [20/0] is directly connected, lo (vrf default) inactive, weight 1, XX:XX:XX
B>* 10.0.3.0/24 [20/20] via 10.0.20.1, r2-eth1 (vrf default), weight 1, XX:XX:XX
O>* 10.0.4.0/24 [110/20] via 10.0.40.4, r2-eth2, weight 1, XX:XX:XX
-B 10.0.20.0/24 [20/0] is directly connected, r2-eth1 (vrf default) inactive, weight 1, XX:XX:XX
+B 10.0.20.0/24 [20/0] is directly connected, lo (vrf default) inactive, weight 1, XX:XX:XX
B>* 10.0.30.0/24 [20/20] via 10.0.20.1, r2-eth1 (vrf default), weight 1, XX:XX:XX
O 10.0.40.0/24 [110/10] is directly connected, r2-eth2, weight 1, XX:XX:XX
C>* 10.0.40.0/24 is directly connected, r2-eth2, XX:XX:XX
diff --git a/tests/topotests/static_vrf/r1/frr.conf b/tests/topotests/static_vrf/r1/frr.conf
new file mode 100644
index 0000000000..bb373b962a
--- /dev/null
+++ b/tests/topotests/static_vrf/r1/frr.conf
@@ -0,0 +1,18 @@
+interface r1-eth0 vrf red
+ ip address 192.0.2.1/23
+exit
+
+interface r1-eth1 vrf blue
+ ip address 192.0.2.129/24
+exit
+
+ip route 198.51.100.1/32 192.0.2.2 nexthop-vrf red
+ip route 198.51.100.1/32 192.0.2.130 nexthop-vrf blue
+ip route 198.51.100.2/32 r1-eth0 nexthop-vrf red
+ip route 198.51.100.2/32 r1-eth1 nexthop-vrf blue
+
+ip route 203.0.113.1/32 192.0.2.130 vrf red nexthop-vrf blue
+ip route 203.0.113.2/32 r1-eth1 vrf red nexthop-vrf blue
+
+ip route 203.0.113.129/32 192.0.2.2 vrf blue nexthop-vrf red
+ip route 203.0.113.130/32 r1-eth0 vrf blue nexthop-vrf red
diff --git a/tests/topotests/static_vrf/test_static_vrf.py b/tests/topotests/static_vrf/test_static_vrf.py
new file mode 100644
index 0000000000..97c0800133
--- /dev/null
+++ b/tests/topotests/static_vrf/test_static_vrf.py
@@ -0,0 +1,126 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 eval: (blacken-mode 1) -*-
+# SPDX-License-Identifier: ISC
+#
+# Copyright (c) 2024 NFWare Inc.
+#
+# noqa: E501
+#
+"""
+Test static route functionality
+"""
+
+import ipaddress
+
+import pytest
+from lib.topogen import Topogen
+from lib.common_config import retry
+
+pytestmark = [pytest.mark.staticd, pytest.mark.mgmtd]
+
+
+@pytest.fixture(scope="module")
+def tgen(request):
+ "Setup/Teardown the environment and provide tgen argument to tests"
+
+ topodef = {"s1": ("r1",), "s2": ("r1",)}
+
+ tgen = Topogen(topodef, request.module.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+ for rname, router in router_list.items():
+ # Setup VRF red
+ router.net.add_l3vrf("red", 10)
+ router.net.attach_iface_to_l3vrf(rname + "-eth0", "red")
+ # Setup VRF blue
+ router.net.add_l3vrf("blue", 20)
+ router.net.attach_iface_to_l3vrf(rname + "-eth1", "blue")
+ # Load configuration
+ router.load_frr_config("frr.conf")
+
+ tgen.start_router()
+ yield tgen
+ tgen.stop_topology()
+
+
+@retry(retry_timeout=1, initial_wait=0.1)
+def check_kernel(r1, prefix, nexthops, vrf, expected_p=True, expected_nh=True):
+ vrfstr = f" vrf {vrf}" if vrf else ""
+
+ net = ipaddress.ip_network(prefix)
+ if net.version == 6:
+ kernel = r1.run(f"ip -6 route show{vrfstr} {prefix}")
+ else:
+ kernel = r1.run(f"ip -4 route show{vrfstr} {prefix}")
+
+ if expected_p:
+ assert prefix in kernel, f"Failed to find \n'{prefix}'\n in \n'{kernel:.1920}'"
+ else:
+ assert (
+ prefix not in kernel
+ ), f"Failed found \n'{prefix}'\n in \n'{kernel:.1920}'"
+
+ if not expected_p:
+ return
+
+ for nh in nexthops:
+ if expected_nh:
+ assert f"{nh}" in kernel, f"Failed to find \n'{nh}'\n in \n'{kernel:.1920}'"
+ else:
+ assert (
+ f"{nh}" not in kernel
+ ), f"Failed found \n'{nh}'\n in \n'{kernel:.1920}'"
+
+
+def test_static_vrf(tgen):
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"]
+
+ # Check initial configuration
+ check_kernel(r1, "198.51.100.1", ["192.0.2.2", "192.0.2.130"], None)
+ check_kernel(r1, "198.51.100.2", ["r1-eth0", "r1-eth1"], None)
+ check_kernel(r1, "203.0.113.1", ["192.0.2.130"], "red")
+ check_kernel(r1, "203.0.113.2", ["r1-eth1"], "red")
+ check_kernel(r1, "203.0.113.129", ["192.0.2.2"], "blue")
+ check_kernel(r1, "203.0.113.130", ["r1-eth0"], "blue")
+
+ # Delete VRF red
+ r1.net.del_iface("red")
+
+ # Check that "red" nexthops are removed, "blue" nexthops are still there
+ check_kernel(r1, "198.51.100.1", ["192.0.2.2"], None, expected_nh=False)
+ check_kernel(r1, "198.51.100.1", ["192.0.2.130"], None)
+ check_kernel(r1, "198.51.100.2", ["r1-eth0"], None, expected_nh=False)
+ check_kernel(r1, "198.51.100.2", ["r1-eth1"], None)
+ check_kernel(r1, "203.0.113.129", ["192.0.2.2"], "blue", expected_p=False)
+ check_kernel(r1, "203.0.113.130", ["r1-eth0"], "blue", expected_p=False)
+
+ # Delete VRF blue
+ r1.net.del_iface("blue")
+
+ # Check that "blue" nexthops are removed
+ check_kernel(r1, "198.51.100.1", ["192.0.2.130"], None, expected_p=False)
+ check_kernel(r1, "198.51.100.2", ["r1-eth1"], None, expected_p=False)
+
+ # Add VRF red back, attach "eth0" to it
+ r1.net.add_l3vrf("red", 10)
+ r1.net.attach_iface_to_l3vrf("r1-eth0", "red")
+
+ # Check that "red" nexthops are restored
+ check_kernel(r1, "198.51.100.1", ["192.0.2.2"], None)
+ check_kernel(r1, "198.51.100.2", ["r1-eth0"], None)
+
+ # Add VRF blue back, attach "eth1" to it
+ r1.net.add_l3vrf("blue", 20)
+ r1.net.attach_iface_to_l3vrf("r1-eth1", "blue")
+
+ # Check that everything is restored
+ check_kernel(r1, "198.51.100.1", ["192.0.2.2", "192.0.2.130"], None)
+ check_kernel(r1, "198.51.100.2", ["r1-eth0", "r1-eth1"], None)
+ check_kernel(r1, "203.0.113.1", ["192.0.2.130"], "red")
+ check_kernel(r1, "203.0.113.2", ["r1-eth1"], "red")
+ check_kernel(r1, "203.0.113.129", ["192.0.2.2"], "blue")
+ check_kernel(r1, "203.0.113.130", ["r1-eth0"], "blue")
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index 4cb46b87a5..3290c8d54a 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -1669,7 +1669,6 @@ static int vtysh_end(void)
/* Nothing to do. */
break;
default:
- vty->vtysh_file_locked = false;
vty->node = ENABLE_NODE;
break;
}
@@ -2393,23 +2392,12 @@ DEFUNSH(VTYSH_REALLYALL, vtysh_disable, vtysh_disable_cmd, "disable",
}
DEFUNSH(VTYSH_REALLYALL, vtysh_config_terminal, vtysh_config_terminal_cmd,
- "configure [terminal]",
- "Configuration from vty interface\n"
- "Configuration terminal\n")
-{
- vty->node = CONFIG_NODE;
- return CMD_SUCCESS;
-}
-
-DEFUNSH(VTYSH_REALLYALL, vtysh_config_terminal_file_lock,
- vtysh_config_terminal_file_lock_cmd,
- "configure terminal file-lock",
+ "configure [terminal [file-lock]]",
"Configuration from vty interface\n"
"Configuration terminal\n"
"Configuration with locked datastores\n")
{
vty->node = CONFIG_NODE;
- vty->vtysh_file_locked = true;
return CMD_SUCCESS;
}
@@ -2424,21 +2412,6 @@ static int vtysh_exit(struct vty *vty)
if (cnode->parent_node)
vty->node = cnode->parent_node;
- if (vty->node == CONFIG_NODE) {
- bool locked = vty->vtysh_file_locked;
-
- /* resync in case one of the daemons is somewhere else */
- vtysh_execute("end");
- /* NOTE: a rather expensive thing to do, can we avoid it? */
-
- if (locked)
- vtysh_execute("configure terminal file-lock");
- else
- vtysh_execute("configure terminal");
- } else if (vty->node == ENABLE_NODE) {
- vty->vtysh_file_locked = false;
- }
-
return CMD_SUCCESS;
}
@@ -5125,7 +5098,6 @@ void vtysh_init_vty(void)
if (!user_mode)
install_element(VIEW_NODE, &vtysh_enable_cmd);
install_element(ENABLE_NODE, &vtysh_config_terminal_cmd);
- install_element(ENABLE_NODE, &vtysh_config_terminal_file_lock_cmd);
install_element(ENABLE_NODE, &vtysh_disable_cmd);
/* "exit" command. */
diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c
index 888f6a8c21..c207e4d427 100644
--- a/vtysh/vtysh_config.c
+++ b/vtysh/vtysh_config.c
@@ -616,8 +616,13 @@ static int vtysh_read_file(FILE *confp, bool dry_run)
vty->node = CONFIG_NODE;
vtysh_execute_no_pager("enable");
- vtysh_execute_no_pager("conf term file-lock");
- vty->vtysh_file_locked = true;
+ /*
+ * When reading the config, we need to wait until the lock is acquired.
+ * If we ignore the failure and continue without the lock, the config
+ * will be fully ignored.
+ */
+ while (vtysh_execute_no_pager("conf term file-lock") == CMD_WARNING_CONFIG_FAILED)
+ usleep(100000);
if (!dry_run)
vtysh_execute_no_pager("XFRR_start_configuration");
@@ -629,7 +634,6 @@ static int vtysh_read_file(FILE *confp, bool dry_run)
vtysh_execute_no_pager("XFRR_end_configuration");
vtysh_execute_no_pager("end");
- vty->vtysh_file_locked = false;
vtysh_execute_no_pager("disable");
vty_close(vty);
diff --git a/zebra/zebra_evpn_mh.h b/zebra/zebra_evpn_mh.h
index 6080048976..34ef79f155 100644
--- a/zebra/zebra_evpn_mh.h
+++ b/zebra/zebra_evpn_mh.h
@@ -154,7 +154,7 @@ struct zebra_evpn_es_vtep {
/* Parameters for DF election */
uint8_t df_alg;
- uint32_t df_pref;
+ uint16_t df_pref;
/* XXX - maintain a backpointer to struct zebra_vtep */
};