Skip to content

Commit

Permalink
Update default route status to state DB (#2009)
Browse files Browse the repository at this point in the history
* 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")
  • Loading branch information
prsunny committed Dec 1, 2021
1 parent 24a64d6 commit d352d5a
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 0 deletions.
22 changes: 22 additions & 0 deletions orchagent/routeorch.cpp
Expand Up @@ -80,7 +80,11 @@ RouteOrch::RouteOrch(DBConnector *db, vector<table_name_with_pri_t> &tableNames,

SWSS_LOG_NOTICE("Maximum number of ECMP groups supported is %d", m_maxNextHopGroupCount);

m_stateDb = shared_ptr<DBConnector>(new DBConnector("STATE_DB", 0));
m_stateDefaultRouteTb = unique_ptr<swss::Table>(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;
Expand All @@ -106,6 +110,7 @@ RouteOrch::RouteOrch(DBConnector *db, vector<table_name_with_pri_t> &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);
Expand Down Expand Up @@ -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<FieldValueTuple> 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();
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions orchagent/routeorch.h
Expand Up @@ -225,6 +225,9 @@ class RouteOrch : public Orch, public Subject
unsigned int m_maxNextHopGroupCount;
bool m_resync;

shared_ptr<DBConnector> m_stateDb;
unique_ptr<swss::Table> m_stateDefaultRouteTb;

RouteTables m_syncdRoutes;
LabelRouteTables m_syncdLabelRoutes;
NextHopGroupTable m_syncdNextHopGroups;
Expand All @@ -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);

Expand Down
50 changes: 50 additions & 0 deletions tests/test_route.py
Expand Up @@ -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})
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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")
Expand All @@ -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")

Expand All @@ -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")
Expand All @@ -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")
Expand All @@ -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")

Expand All @@ -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")
Expand Down

0 comments on commit d352d5a

Please sign in to comment.