Skip to content

Commit 4c9e478

Browse files
authored
[vnetorch] Prevent route deletion in default VRF upon conflicting route creation in non default VNET (#4029)
What I did Modified vnetorch to not delete conflicting route space in default vrf if the vnet scope is non default Why I did it To support conflicting IP spaces How I verified it SWSS UT which shows that conflicting IP space is no longer deleted, and manual testing on device which shows this as well Details if related ASIC DB route deleteion issue can be seen below(which is fixed by this PR): Route entry on switch:
1 parent dabbd57 commit 4c9e478

File tree

5 files changed

+99
-14
lines changed

5 files changed

+99
-14
lines changed

orchagent/routeorch.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2964,12 +2964,10 @@ bool RouteOrch::removeRoutePost(const RouteBulkContext& ctx)
29642964
return true;
29652965
}
29662966

2967-
bool RouteOrch::isRouteExists(const IpPrefix& prefix)
2967+
bool RouteOrch::isRouteExists(sai_object_id_t vrf_id, const IpPrefix& prefix)
29682968
{
29692969
SWSS_LOG_ENTER();
29702970

2971-
sai_object_id_t& vrf_id = gVirtualRouterId;
2972-
29732971
sai_route_entry_t route_entry;
29742972
route_entry.vr_id = vrf_id;
29752973
route_entry.switch_id = gSwitchId;
@@ -2978,7 +2976,7 @@ bool RouteOrch::isRouteExists(const IpPrefix& prefix)
29782976
if (it_route_table == m_syncdRoutes.end())
29792977
{
29802978
SWSS_LOG_INFO("Failed to find route table, vrf_id 0x%" PRIx64 "\n", vrf_id);
2981-
return true;
2979+
return false;
29822980
}
29832981
auto it_route = it_route_table->second.find(prefix);
29842982
size_t creating = gRouteBulker.creating_entries_count(route_entry);

orchagent/routeorch.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ class RouteOrch : public ZmqOrch, public Subject
253253
const NextHopGroupKey getSyncdRouteNhgKey(sai_object_id_t vrf_id, const IpPrefix& ipPrefix);
254254
bool createFineGrainedNextHopGroup(sai_object_id_t &next_hop_group_id, vector<sai_attribute_t> &nhg_attrs);
255255
bool removeFineGrainedNextHopGroup(sai_object_id_t &next_hop_group_id);
256-
bool isRouteExists(const IpPrefix& prefix);
256+
bool isRouteExists(sai_object_id_t vrf_id, const IpPrefix& prefix);
257257
bool removeRoutePrefix(const IpPrefix& prefix);
258258

259259
void addLinkLocalRouteToMe(sai_object_id_t vrf_id, IpPrefix linklocal_prefix);

orchagent/vnetorch.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1197,7 +1197,7 @@ bool VNetRouteOrch::doRouteTask<VNetVrfObject>(const string& vnet, IpPrefix& ipP
11971197
prefixToRemove = adv_prefix;
11981198
}
11991199
auto prefixSubnet = prefixToRemove.getSubnet();
1200-
if(gRouteOrch && gRouteOrch->isRouteExists(prefixSubnet))
1200+
if(gRouteOrch && gRouteOrch->isRouteExists(vr_id, prefixSubnet))
12011201
{
12021202
if (!gRouteOrch->removeRoutePrefix(prefixSubnet))
12031203
{
@@ -2519,7 +2519,9 @@ void VNetRouteOrch::updateVnetTunnel(const BfdUpdate& update)
25192519
ipPrefixsubnet = adv_prefix.getSubnet();
25202520
}
25212521
}
2522-
if(gRouteOrch && gRouteOrch->isRouteExists(ipPrefixsubnet))
2522+
2523+
sai_object_id_t vr_id = vrf_obj->getVRidIngress();
2524+
if(gRouteOrch && gRouteOrch->isRouteExists(vr_id, ipPrefixsubnet))
25232525
{
25242526
if (!gRouteOrch->removeRoutePrefix(ipPrefixsubnet))
25252527
{
@@ -2767,7 +2769,7 @@ void VNetRouteOrch::updateVnetTunnelCustomMonitor(const MonitorUpdate& update)
27672769
}
27682770
}
27692771
auto prefixsubnet = prefixToUse.getSubnet();
2770-
if (gRouteOrch && gRouteOrch->isRouteExists(prefixsubnet))
2772+
if (gRouteOrch && gRouteOrch->isRouteExists(vr_id, prefixsubnet))
27712773
{
27722774
if (!gRouteOrch->removeRoutePrefix(prefixsubnet))
27732775
{

tests/test_vnet2.py

Lines changed: 63 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,8 @@ def test_vnet_orch_1(self, dvs, testlog):
106106

107107
# create vxlan tunnel and verfiy it
108108
create_vxlan_tunnel(dvs, tunnel_name, '9.9.9.9')
109-
create_vnet_entry(dvs, vnet_name, tunnel_name, '1001', "")
110-
vnet_obj.check_vnet_entry(dvs, vnet_name)
109+
create_vnet_entry(dvs, vnet_name, tunnel_name, '1001', "", scope="default")
110+
vnet_obj.check_default_vnet_entry(dvs, vnet_name)
111111
vnet_obj.check_vxlan_tunnel_entry(dvs, tunnel_name, vnet_name, '1001')
112112
vnet_obj.check_vxlan_tunnel(dvs, tunnel_name, '9.9.9.9')
113113

@@ -240,8 +240,8 @@ def test_vnet_orch_2(self, dvs, testlog):
240240

241241
# create vxlan tunnel and verfiy it
242242
create_vxlan_tunnel(dvs, tunnel_name, '9.8.8.9')
243-
create_vnet_entry(dvs, vnet_name, tunnel_name, '1002', "")
244-
vnet_obj.check_vnet_entry(dvs, vnet_name)
243+
create_vnet_entry(dvs, vnet_name, tunnel_name, '1002', "", scope="default")
244+
vnet_obj.check_default_vnet_entry(dvs, vnet_name)
245245
vnet_obj.check_vxlan_tunnel_entry(dvs, tunnel_name, vnet_name, '1002')
246246
vnet_obj.check_vxlan_tunnel(dvs, tunnel_name, '9.8.8.9')
247247
vnet_obj.fetch_exist_entries(dvs)
@@ -342,8 +342,8 @@ def test_vnet_orch_3(self, dvs, testlog):
342342

343343
# create vxlan tunnel and verfiy it
344344
create_vxlan_tunnel(dvs, tunnel_name, '19.19.19.19')
345-
create_vnet_entry(dvs, vnet_name, tunnel_name, '1003', "", '', advertise_prefix=True, overlay_dmac="22:33:33:44:44:66")
346-
vnet_obj.check_vnet_entry(dvs, vnet_name)
345+
create_vnet_entry(dvs, vnet_name, tunnel_name, '1003', "", 'default', advertise_prefix=True, overlay_dmac="22:33:33:44:44:66")
346+
vnet_obj.check_default_vnet_entry(dvs, vnet_name)
347347
vnet_obj.check_vxlan_tunnel_entry(dvs, tunnel_name, vnet_name, '1003')
348348
vnet_obj.check_vxlan_tunnel(dvs, tunnel_name, '19.19.19.19')
349349

@@ -420,6 +420,63 @@ def test_vnet_orch_3(self, dvs, testlog):
420420
vnet_obj.check_del_vnet_entry(dvs, vnet_name)
421421
delete_vxlan_tunnel(dvs, tunnel_name)
422422

423+
'''
424+
Test 4 - Test that conflicting IP space does not result in deletion on default VRF for vnets which are not in default scope
425+
'''
426+
def test_vnet_orch_conflicting_route_non_default_vnet(self, dvs, testlog):
427+
vnet_obj = self.get_vnet_obj()
428+
429+
tunnel_name = 'tunnel_1'
430+
vnet_name = 'Vnet1'
431+
self.setup_db(dvs)
432+
vnet_obj.fetch_exist_entries(dvs)
433+
# create l3 interface and bring it up
434+
self.create_l3_intf("Ethernet0", "")
435+
self.add_ip_address("Ethernet0", "20.20.20.1/24")
436+
self.set_admin_status("Ethernet0", "down")
437+
time.sleep(1)
438+
self.set_admin_status("Ethernet0", "up")
439+
440+
# set ip address and default route
441+
dvs.servers[0].runcmd("ip address add 20.20.20.5/24 dev eth0")
442+
dvs.servers[0].runcmd("ip route add default via 20.20.20.1")
443+
444+
# create vxlan tunnel and verify it
445+
create_vxlan_tunnel(dvs, tunnel_name, '9.9.9.9')
446+
create_vnet_entry(dvs, vnet_name, tunnel_name, '1001', "")
447+
vnet_obj.check_vnet_entry(dvs, vnet_name)
448+
vnet_obj.check_vxlan_tunnel_entry(dvs, tunnel_name, vnet_name, '1001')
449+
vnet_obj.check_vxlan_tunnel(dvs, tunnel_name, '9.9.9.9')
450+
451+
# add conflicting route
452+
dvs.runcmd("vtysh -c \"configure terminal\" -c \"ip route 106.100.1.1/32 20.20.20.5\"")
453+
# check ASIC route database
454+
self.check_route_entries(["106.100.1.1/32"])
455+
vnet_obj.fetch_exist_entries(dvs)
456+
457+
create_vnet_routes(dvs, "106.100.1.1/32", vnet_name, '9.8.0.1,9.8.0.2,9.8.0.3')
458+
# Default vrf route should be present
459+
vnet_obj.check_default_vrf_route(dvs, "106.100.1.1/32")
460+
# State DB route should show non existent endpoints as bfd state is down
461+
check_state_db_routes(dvs, vnet_name, "106.100.1.1/32", ['9.8.0.1', '9.8.0.2', '9.8.0.3'])
462+
463+
vnet_obj.check_vnet_ecmp_routes(dvs, vnet_name, ['9.8.0.1','9.8.0.2', '9.8.0.3'], tunnel_name)
464+
465+
# Default vrf route should still be present
466+
vnet_obj.check_default_vrf_route(dvs, "106.100.1.1/32")
467+
468+
delete_vnet_routes(dvs, "106.100.1.1/32", vnet_name)
469+
vnet_obj.check_del_vnet_route_in_vnet(dvs, vnet_name, "106.100.1.1/32")
470+
check_remove_state_db_routes(dvs, vnet_name, "106.100.1.1/32")
471+
472+
# Default vrf route should still be present
473+
vnet_obj.check_default_vrf_route(dvs, "106.100.1.1/32")
474+
dvs.runcmd("vtysh -c \"configure terminal\" -c \"no ip route 106.100.1.1/32\"")
475+
self.check_route_entries(["106.100.1.1/32"], absent=True)
476+
delete_vnet_entry(dvs, vnet_name)
477+
vnet_obj.check_del_vnet_entry(dvs, vnet_name)
478+
delete_vxlan_tunnel(dvs, tunnel_name)
479+
423480
# Add Dummy always-pass test at end as workaroud
424481
# for issue when Flaky fail on final test it invokes module tear-down before retrying
425482
def test_nonflaky_dummy():

tests/vnet_lib.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -959,6 +959,21 @@ def check_del_router_interface(self, dvs, name):
959959

960960
self.rifs.remove(old_rif[0])
961961

962+
def check_default_vrf_route(self, dvs, ip_pref):
963+
global def_vr_id
964+
965+
def _access_function():
966+
route_entries = get_exist_entries(dvs, self.ASIC_ROUTE_ENTRY)
967+
for route_entry in route_entries:
968+
json_rt_entry = json.loads(route_entry)
969+
if (json_rt_entry["dest"] == ip_pref and json_rt_entry['vr'] == def_vr_id):
970+
return (True, None)
971+
else:
972+
continue
973+
return (False, None)
974+
975+
wait_for_result(_access_function)
976+
962977
def check_vnet_local_routes(self, dvs, name, vlan_subnet_route=False):
963978
asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0)
964979

@@ -1275,6 +1290,19 @@ def check_priority_vnet_ecmp_routes(self, dvs, name, endpoints_primary, tunnel,
12751290
del self.nhg_ids[endpoint_str_primary]
12761291
return new_route
12771292

1293+
def check_del_vnet_route_in_vnet(self, dvs, vnet_name, prefix):
1294+
vr_id = self.vr_map[vnet_name].get('ing')
1295+
1296+
def _access_function():
1297+
route_entries = get_exist_entries(dvs, self.ASIC_ROUTE_ENTRY)
1298+
for route_entry in route_entries:
1299+
rt_json = json.loads(route_entry)
1300+
if rt_json['vr'] == vr_id:
1301+
if rt_json['dest'] == prefix:
1302+
return (False, None)
1303+
return (True, None)
1304+
wait_for_result(_access_function)
1305+
12781306
def check_del_vnet_routes(self, dvs, name, prefixes=[], absent=False):
12791307
# TODO: Implement for VRF VNET
12801308

0 commit comments

Comments
 (0)