Skip to content

Commit 9561455

Browse files
authored
[routeorch] Add support for blackhole routes (sonic-net#1723)
Allow route orch to add/remove routes blackhole routes and add dvs tests.
1 parent 328abd8 commit 9561455

2 files changed

Lines changed: 122 additions & 10 deletions

File tree

orchagent/routeorch.cpp

Lines changed: 61 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,7 @@ void RouteOrch::doTask(Consumer& consumer)
513513
string remote_macs;
514514
bool& excp_intfs_flag = ctx.excp_intfs_flag;
515515
bool overlay_nh = false;
516+
bool blackhole = false;
516517

517518
for (auto i : kfvFieldsValues(t))
518519
{
@@ -529,6 +530,9 @@ void RouteOrch::doTask(Consumer& consumer)
529530

530531
if (fvField(i) == "router_mac")
531532
remote_macs = fvValue(i);
533+
534+
if (fvField(i) == "blackhole")
535+
blackhole = fvValue(i) == "true";
532536
}
533537

534538
vector<string>& ipv = ctx.ipv;
@@ -544,7 +548,7 @@ void RouteOrch::doTask(Consumer& consumer)
544548

545549
/* Resize the ip vector to match ifname vector
546550
* as tokenize(",", ',') will miss the last empty segment. */
547-
if (alsv.size() == 0)
551+
if (alsv.size() == 0 && !blackhole)
548552
{
549553
SWSS_LOG_WARN("Skip the route %s, for it has an empty ifname field.", key.c_str());
550554
it = consumer.m_toSync.erase(it);
@@ -597,7 +601,11 @@ void RouteOrch::doTask(Consumer& consumer)
597601
string nhg_str = "";
598602
NextHopGroupKey& nhg = ctx.nhg;
599603

600-
if (overlay_nh == false)
604+
if (blackhole)
605+
{
606+
nhg = NextHopGroupKey();
607+
}
608+
else if (overlay_nh == false)
601609
{
602610
if (alsv[0] == "tun0" && !(IpAddress(ipv[0]).isZero()))
603611
{
@@ -630,10 +638,8 @@ void RouteOrch::doTask(Consumer& consumer)
630638

631639
if (ipv.size() == 1 && IpAddress(ipv[0]).isZero())
632640
{
633-
/* blackhole to be done */
634641
if (alsv[0] == "unknown")
635642
{
636-
/* add addBlackholeRoute or addRoute support empty nhg */
637643
it = consumer.m_toSync.erase(it);
638644
}
639645
/* skip direct routes to tun0 */
@@ -1349,6 +1355,7 @@ bool RouteOrch::addRoute(RouteBulkContext& ctx, const NextHopGroupKey &nextHops)
13491355
bool status = false;
13501356
bool curNhgIsFineGrained = false;
13511357
bool prevNhgWasFineGrained = false;
1358+
bool blackhole = false;
13521359

13531360
if (m_syncdRoutes.find(vrf_id) == m_syncdRoutes.end())
13541361
{
@@ -1377,6 +1384,11 @@ bool RouteOrch::addRoute(RouteBulkContext& ctx, const NextHopGroupKey &nextHops)
13771384
return false;
13781385
}
13791386
}
1387+
else if (nextHops.getSize() == 0)
1388+
{
1389+
/* The route is pointing to a blackhole */
1390+
blackhole = true;
1391+
}
13801392
else if (nextHops.getSize() == 1)
13811393
{
13821394
/* The route is pointing to a next hop */
@@ -1544,8 +1556,16 @@ bool RouteOrch::addRoute(RouteBulkContext& ctx, const NextHopGroupKey &nextHops)
15441556
*/
15451557
if (it_route == m_syncdRoutes.at(vrf_id).end())
15461558
{
1547-
route_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID;
1548-
route_attr.value.oid = next_hop_id;
1559+
if (blackhole)
1560+
{
1561+
route_attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION;
1562+
route_attr.value.s32 = SAI_PACKET_ACTION_DROP;
1563+
}
1564+
else
1565+
{
1566+
route_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID;
1567+
route_attr.value.oid = next_hop_id;
1568+
}
15491569

15501570
/* Default SAI_ROUTE_ATTR_PACKET_ACTION is SAI_PACKET_ACTION_FORWARD */
15511571
object_statuses.emplace_back();
@@ -1559,8 +1579,8 @@ bool RouteOrch::addRoute(RouteBulkContext& ctx, const NextHopGroupKey &nextHops)
15591579
}
15601580
else
15611581
{
1562-
/* Set the packet action to forward when there was no next hop (dropped) */
1563-
if (it_route->second.getSize() == 0)
1582+
/* Set the packet action to forward when there was no next hop (dropped) and not pointing to blackhole*/
1583+
if (it_route->second.getSize() == 0 && !blackhole)
15641584
{
15651585
route_attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION;
15661586
route_attr.value.s32 = SAI_PACKET_ACTION_FORWARD;
@@ -1584,6 +1604,15 @@ bool RouteOrch::addRoute(RouteBulkContext& ctx, const NextHopGroupKey &nextHops)
15841604
object_statuses.emplace_back();
15851605
gRouteBulker.set_entry_attribute(&object_statuses.back(), &route_entry, &route_attr);
15861606
}
1607+
1608+
if (blackhole)
1609+
{
1610+
route_attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION;
1611+
route_attr.value.s32 = SAI_PACKET_ACTION_DROP;
1612+
1613+
object_statuses.emplace_back();
1614+
gRouteBulker.set_entry_attribute(&object_statuses.back(), &route_entry, &route_attr);
1615+
}
15871616
}
15881617
return false;
15891618
}
@@ -1595,6 +1624,7 @@ bool RouteOrch::addRoutePost(const RouteBulkContext& ctx, const NextHopGroupKey
15951624
const sai_object_id_t& vrf_id = ctx.vrf_id;
15961625
const IpPrefix& ipPrefix = ctx.ip_prefix;
15971626
bool isFineGrained = false;
1627+
bool blackhole = false;
15981628

15991629
const auto& object_statuses = ctx.object_statuses;
16001630

@@ -1612,6 +1642,11 @@ bool RouteOrch::addRoutePost(const RouteBulkContext& ctx, const NextHopGroupKey
16121642
/* Route is pointing to Fine Grained ECMP nexthop group */
16131643
isFineGrained = true;
16141644
}
1645+
else if (nextHops.getSize() == 0)
1646+
{
1647+
/* The route is pointing to a blackhole */
1648+
blackhole = true;
1649+
}
16151650
else if (nextHops.getSize() == 1)
16161651
{
16171652
/* The route is pointing to a next hop */
@@ -1739,8 +1774,8 @@ bool RouteOrch::addRoutePost(const RouteBulkContext& ctx, const NextHopGroupKey
17391774
{
17401775
sai_status_t status;
17411776

1742-
/* Set the packet action to forward when there was no next hop (dropped) */
1743-
if (it_route->second.getSize() == 0)
1777+
/* Set the packet action to forward when there was no next hop (dropped) and not pointing to blackhole */
1778+
if (it_route->second.getSize() == 0 && !blackhole)
17441779
{
17451780
status = *it_status++;
17461781
if (status != SAI_STATUS_SUCCESS)
@@ -1790,6 +1825,22 @@ bool RouteOrch::addRoutePost(const RouteBulkContext& ctx, const NextHopGroupKey
17901825
}
17911826
}
17921827

1828+
if (blackhole)
1829+
{
1830+
/* Set the packet action to drop for blackhole routes */
1831+
status = *it_status++;
1832+
if (status != SAI_STATUS_SUCCESS)
1833+
{
1834+
SWSS_LOG_ERROR("Failed to set blackhole route %s with packet action drop, %d",
1835+
ipPrefix.to_string().c_str(), status);
1836+
task_process_status handle_status = handleSaiSetStatus(SAI_API_ROUTE, status);
1837+
if (handle_status != task_success)
1838+
{
1839+
return parseHandleSaiStatusFailure(handle_status);
1840+
}
1841+
}
1842+
}
1843+
17931844
SWSS_LOG_INFO("Post set route %s with next hop(s) %s",
17941845
ipPrefix.to_string().c_str(), nextHops.to_string().c_str());
17951846
}

tests/test_route.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,13 @@ def _access_function():
6262

6363
wait_for_result(_access_function)
6464

65+
def get_asic_db_key(self, destination):
66+
route_entries = self.adb.get_keys("ASIC_STATE:SAI_OBJECT_TYPE_ROUTE_ENTRY")
67+
for route_entry in route_entries:
68+
if json.loads(route_entry)["dest"] == destination:
69+
return route_entry
70+
return None
71+
6572
def check_route_entries_with_vrf(self, destinations, vrf_oids):
6673
def _access_function():
6774
route_entries = self.adb.get_keys("ASIC_STATE:SAI_OBJECT_TYPE_ROUTE_ENTRY")
@@ -839,6 +846,60 @@ def test_RouteAndNexthopInDifferentVrf(self, dvs, testlog):
839846
dvs.servers[3].runcmd("ip route del default dev eth0")
840847
dvs.servers[3].runcmd("ip address del 20.0.1.2/24 dev eth0")
841848

849+
def test_RouteAddRemoveIpv4BlackholeRoute(self, dvs, testlog):
850+
self.setup_db(dvs)
851+
852+
self.clear_srv_config(dvs)
853+
854+
# add route entry
855+
dvs.runcmd("vtysh -c \"configure terminal\" -c \"ip route 2.2.2.0/24 blackhole\"")
856+
857+
# check application database
858+
self.pdb.wait_for_entry("ROUTE_TABLE", "2.2.2.0/24")
859+
860+
# check ASIC route database
861+
self.check_route_entries(["2.2.2.0/24"])
862+
key = self.get_asic_db_key("2.2.2.0/24")
863+
assert key
864+
fvs = self.adb.get_entry("ASIC_STATE:SAI_OBJECT_TYPE_ROUTE_ENTRY", key)
865+
assert fvs.get("SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION") == "SAI_PACKET_ACTION_DROP"
866+
867+
# remove route entry
868+
dvs.runcmd("vtysh -c \"configure terminal\" -c \"no ip route 2.2.2.0/24 blackhole\"")
869+
870+
# check application database
871+
self.pdb.wait_for_deleted_entry("ROUTE_TABLE", "2.2.2.0/24")
872+
873+
# check ASIC route database
874+
self.check_deleted_route_entries(["2.2.2.0/24"])
875+
876+
def test_RouteAddRemoveIpv6BlackholeRoute(self, dvs, testlog):
877+
self.setup_db(dvs)
878+
879+
self.clear_srv_config(dvs)
880+
881+
# add route entry
882+
dvs.runcmd("vtysh -c \"configure terminal\" -c \"ipv6 route 3000::0/64 blackhole\"")
883+
884+
# check application database
885+
self.pdb.wait_for_entry("ROUTE_TABLE", "3000::/64")
886+
887+
# check ASIC route database
888+
self.check_route_entries(["3000::/64"])
889+
key = self.get_asic_db_key("3000::/64")
890+
assert key
891+
fvs = self.adb.get_entry("ASIC_STATE:SAI_OBJECT_TYPE_ROUTE_ENTRY", key)
892+
assert fvs.get("SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION") == "SAI_PACKET_ACTION_DROP"
893+
894+
# remove route entry
895+
dvs.runcmd("vtysh -c \"configure terminal\" -c \"no ipv6 route 3000::0/64 blackhole\"")
896+
897+
# check application database
898+
self.pdb.wait_for_deleted_entry("ROUTE_TABLE", "3000::/64")
899+
900+
# check ASIC route database
901+
self.check_deleted_route_entries(["3000::/64"])
902+
842903
class TestRoutePerf(TestRouteBase):
843904
""" Performance tests for route """
844905
def test_PerfAddRemoveRoute(self, dvs, testlog):

0 commit comments

Comments
 (0)