From c42c118d2a62c8fc9fcc1f77812550e9bf645617 Mon Sep 17 00:00:00 2001 From: Prince Sunny Date: Wed, 1 Dec 2021 09:10:23 -0800 Subject: [PATCH 1/2] Update default route status to state DB (#2009) * Orchagent update of IPv4 and IPv6 default route status. If there is a valid default route, it shall be updated as state:ok. If there is no valid default route (with packet action drop), state db shall be updated as state:na - Schema ("ROUTE_TABLE|0.0.0.0/0") --- orchagent/routeorch.cpp | 22 +++++++++++++++++- orchagent/routeorch.h | 5 +++++ tests/test_route.py | 50 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 1 deletion(-) diff --git a/orchagent/routeorch.cpp b/orchagent/routeorch.cpp index 9eccfd2b70f..74da77eb3f2 100644 --- a/orchagent/routeorch.cpp +++ b/orchagent/routeorch.cpp @@ -75,7 +75,11 @@ RouteOrch::RouteOrch(DBConnector *db, string tableName, SwitchOrch *switchOrch, SWSS_LOG_NOTICE("Maximum number of ECMP groups supported is %d", m_maxNextHopGroupCount); + m_stateDb = shared_ptr(new DBConnector("STATE_DB", 0)); + m_stateDefaultRouteTb = unique_ptr(new Table(m_stateDb.get(), STATE_ROUTE_TABLE_NAME)); + IpPrefix default_ip_prefix("0.0.0.0/0"); + updateDefRouteState("0.0.0.0/0"); sai_route_entry_t unicast_route_entry; unicast_route_entry.vr_id = gVirtualRouterId; @@ -101,6 +105,7 @@ RouteOrch::RouteOrch(DBConnector *db, string tableName, SwitchOrch *switchOrch, SWSS_LOG_NOTICE("Create IPv4 default route with packet action drop"); IpPrefix v6_default_ip_prefix("::/0"); + updateDefRouteState("::/0"); copy(unicast_route_entry.destination, v6_default_ip_prefix); subnet(unicast_route_entry.destination, unicast_route_entry.destination); @@ -205,6 +210,16 @@ void RouteOrch::addLinkLocalRouteToMe(sai_object_id_t vrf_id, IpPrefix linklocal SWSS_LOG_NOTICE("Created link local ipv6 route %s to cpu", linklocal_prefix.to_string().c_str()); } +void RouteOrch::updateDefRouteState(string ip, bool add) +{ + vector tuples; + string state = add?"ok":"na"; + FieldValueTuple tuple("state", state); + tuples.push_back(tuple); + + m_stateDefaultRouteTb->set(ip, tuples); +} + bool RouteOrch::hasNextHopGroup(const NextHopGroupKey& nexthops) const { return m_syncdNextHopGroups.find(nexthops) != m_syncdNextHopGroups.end(); @@ -1898,7 +1913,10 @@ bool RouteOrch::addRoutePost(const RouteBulkContext& ctx, const NextHopGroupKey } } - m_syncdRoutes[vrf_id][ipPrefix] = nextHops; + if (ipPrefix.isDefaultRoute()) + { + updateDefRouteState(ipPrefix.to_string(), true); + } notifyNextHopChangeObservers(vrf_id, ipPrefix, nextHops, true); return true; @@ -2007,6 +2025,8 @@ bool RouteOrch::removeRoutePost(const RouteBulkContext& ctx) } } + updateDefRouteState(ipPrefix.to_string()); + SWSS_LOG_INFO("Set route %s next hop ID to NULL", ipPrefix.to_string().c_str()); } else diff --git a/orchagent/routeorch.h b/orchagent/routeorch.h index bab773da30b..3370df5a53f 100644 --- a/orchagent/routeorch.h +++ b/orchagent/routeorch.h @@ -148,6 +148,9 @@ class RouteOrch : public Orch, public Subject int m_maxNextHopGroupCount; bool m_resync; + shared_ptr m_stateDb; + unique_ptr m_stateDefaultRouteTb; + RouteTables m_syncdRoutes; NextHopGroupTable m_syncdNextHopGroups; NextHopRouteTable m_nextHops; @@ -168,6 +171,8 @@ class RouteOrch : public Orch, public Subject std::string getLinkLocalEui64Addr(void); void addLinkLocalRouteToMe(sai_object_id_t vrf_id, IpPrefix linklocal_prefix); + void updateDefRouteState(string ip, bool add=false); + void doTask(Consumer& consumer); }; diff --git a/tests/test_route.py b/tests/test_route.py index 56d3af5c5b9..34530c1d73e 100644 --- a/tests/test_route.py +++ b/tests/test_route.py @@ -12,6 +12,7 @@ def setup_db(self, dvs): self.pdb = dvs.get_app_db() self.adb = dvs.get_asic_db() self.cdb = dvs.get_config_db() + self.sdb = dvs.get_state_db() def set_admin_status(self, interface, status): self.cdb.update_entry("PORT", interface, {"admin_status": status}) @@ -62,6 +63,23 @@ def _access_function(): wait_for_result(_access_function) + def check_route_state(self, prefix, value): + found = False + + route_entries = self.sdb.get_keys("ROUTE_TABLE") + for key in route_entries: + if key != prefix: + continue + found = True + fvs = self.sdb.get_entry("ROUTE_TABLE", key) + + assert fvs != {} + + for f,v in fvs.items(): + if f == "state": + assert v == value + assert found + def get_asic_db_key(self, destination): route_entries = self.adb.get_keys("ASIC_STATE:SAI_OBJECT_TYPE_ROUTE_ENTRY") for route_entry in route_entries: @@ -123,6 +141,9 @@ def test_RouteAddRemoveIpv4Route(self, dvs, testlog): self.create_l3_intf("Ethernet0", "") self.create_l3_intf("Ethernet4", "") + # check STATE route database, initial state shall be "na" + self.check_route_state("0.0.0.0/0", "na") + # set ip address self.add_ip_address("Ethernet0", "10.0.0.0/31") self.add_ip_address("Ethernet4", "10.0.0.2/31") @@ -144,15 +165,25 @@ def test_RouteAddRemoveIpv4Route(self, dvs, testlog): # add route entry dvs.runcmd("vtysh -c \"configure terminal\" -c \"ip route 2.2.2.0/24 10.0.0.1\"") + # add default route entry + fieldValues = {"nexthop": "10.0.0.1", "ifname": "Ethernet0"} + self.create_route_entry("0.0.0.0/0", fieldValues) + # check application database self.pdb.wait_for_entry("ROUTE_TABLE", "2.2.2.0/24") # check ASIC route database self.check_route_entries(["2.2.2.0/24"]) + # check STATE route database + self.check_route_state("0.0.0.0/0", "ok") + # remove route entry dvs.runcmd("vtysh -c \"configure terminal\" -c \"no ip route 2.2.2.0/24 10.0.0.1\"") + # remove default route entry + self.remove_route_entry("0.0.0.0/0") + # check application database self.pdb.wait_for_deleted_entry("ROUTE_TABLE", "2.2.2.0/24") @@ -170,6 +201,9 @@ def test_RouteAddRemoveIpv4Route(self, dvs, testlog): self.set_admin_status("Ethernet0", "down") self.set_admin_status("Ethernet4", "down") + # check STATE route database, state set to "na" after deleting the default route + self.check_route_state("0.0.0.0/0", "na") + # remove ip address and default route dvs.servers[0].runcmd("ip route del default dev eth0") dvs.servers[0].runcmd("ip address del 10.0.0.1/31 dev eth0") @@ -184,6 +218,9 @@ def test_RouteAddRemoveIpv6Route(self, dvs, testlog): self.create_l3_intf("Ethernet0", "") self.create_l3_intf("Ethernet4", "") + # check STATE route database, initial state shall be "na" + self.check_route_state("::/0", "na") + # bring up interface self.set_admin_status("Ethernet0", "up") self.set_admin_status("Ethernet4", "up") @@ -207,15 +244,25 @@ def test_RouteAddRemoveIpv6Route(self, dvs, testlog): # add route entry dvs.runcmd("vtysh -c \"configure terminal\" -c \"ipv6 route 3000::0/64 2000::2\"") + # add default route entry + fieldValues = {"nexthop": "2000::2", "ifname": "Ethernet0"} + self.create_route_entry("::/0", fieldValues) + # check application database self.pdb.wait_for_entry("ROUTE_TABLE", "3000::/64") # check ASIC route database self.check_route_entries(["3000::/64"]) + # check STATE route database + self.check_route_state("::/0", "ok") + # remove route entry dvs.runcmd("vtysh -c \"configure terminal\" -c \"no ipv6 route 3000::0/64 2000::2\"") + # remove default route entry + self.remove_route_entry("::/0") + # check application database self.pdb.wait_for_deleted_entry("ROUTE_TABLE", "3000::/64") @@ -233,6 +280,9 @@ def test_RouteAddRemoveIpv6Route(self, dvs, testlog): self.set_admin_status("Ethernet0", "down") self.set_admin_status("Ethernet4", "down") + # check STATE route database, state set to "na" after deleting the default route + self.check_route_state("::/0", "na") + # remove ip address and default route dvs.servers[0].runcmd("ip -6 route del default dev eth0") dvs.servers[0].runcmd("ip -6 address del 2000::2/64 dev eth0") From 507a0c3442e1e59bb081fe5618a61ed5785f6fc9 Mon Sep 17 00:00:00 2001 From: Prince Date: Mon, 6 Dec 2021 22:56:33 +0000 Subject: [PATCH 2/2] Fix cherry-pick --- orchagent/routeorch.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/orchagent/routeorch.cpp b/orchagent/routeorch.cpp index 74da77eb3f2..02de369e80d 100644 --- a/orchagent/routeorch.cpp +++ b/orchagent/routeorch.cpp @@ -1918,6 +1918,8 @@ bool RouteOrch::addRoutePost(const RouteBulkContext& ctx, const NextHopGroupKey updateDefRouteState(ipPrefix.to_string(), true); } + m_syncdRoutes[vrf_id][ipPrefix] = nextHops; + notifyNextHopChangeObservers(vrf_id, ipPrefix, nextHops, true); return true; }