diff --git a/orchagent/routeorch.cpp b/orchagent/routeorch.cpp index 8337e6cba151..d3a48cb5aa06 100644 --- a/orchagent/routeorch.cpp +++ b/orchagent/routeorch.cpp @@ -80,7 +80,11 @@ RouteOrch::RouteOrch(DBConnector *db, vector &tableNames, 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; @@ -106,6 +110,7 @@ RouteOrch::RouteOrch(DBConnector *db, vector &tableNames, 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); @@ -231,6 +236,16 @@ void RouteOrch::delLinkLocalRouteToMe(sai_object_id_t vrf_id, IpPrefix linklocal SWSS_LOG_NOTICE("Deleted 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(); @@ -2147,6 +2162,11 @@ bool RouteOrch::addRoutePost(const RouteBulkContext& ctx, const NextHopGroupKey } } + if (ipPrefix.isDefaultRoute()) + { + updateDefRouteState(ipPrefix.to_string(), true); + } + m_syncdRoutes[vrf_id][ipPrefix] = RouteNhg(nextHops, ctx.nhg_index); notifyNextHopChangeObservers(vrf_id, ipPrefix, nextHops, true); @@ -2262,6 +2282,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 74cd4c4442e7..22756ad176f3 100644 --- a/orchagent/routeorch.h +++ b/orchagent/routeorch.h @@ -225,6 +225,9 @@ class RouteOrch : public Orch, public Subject unsigned int m_maxNextHopGroupCount; bool m_resync; + shared_ptr m_stateDb; + unique_ptr m_stateDefaultRouteTb; + RouteTables m_syncdRoutes; LabelRouteTables m_syncdLabelRoutes; NextHopGroupTable m_syncdNextHopGroups; @@ -251,6 +254,8 @@ class RouteOrch : public Orch, public Subject bool addLabelRoutePost(const LabelRouteBulkContext& ctx, const NextHopGroupKey &nextHops); bool removeLabelRoutePost(const LabelRouteBulkContext& ctx); + void updateDefRouteState(string ip, bool add=false); + void doTask(Consumer& consumer); void doLabelTask(Consumer& consumer); diff --git a/tests/test_route.py b/tests/test_route.py index bae9865a6573..9c56ef52a834 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")