Skip to content

Commit d01524d

Browse files
authored
[fgnhgorch] Enable packet flow when no FG ECMP neighbors are resolved (#1900)
*Added ability to set the FG route's next-hop as the RIF, the packets will trap to the kernel and be neighbor resolved via the kernel. Further, added the ability to set the next-hop to a fine grained ECMP next-hop after the 1st neighbor resolution occurs.
1 parent 8cf355d commit d01524d

File tree

4 files changed

+226
-66
lines changed

4 files changed

+226
-66
lines changed

orchagent/fgnhgorch.cpp

+185-58
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,7 @@ bool FgNhgOrch::createFineGrainedNextHopGroup(FGNextHopGroupEntry &syncd_fg_rout
317317
bool FgNhgOrch::removeFineGrainedNextHopGroup(FGNextHopGroupEntry *syncd_fg_route_entry)
318318
{
319319
SWSS_LOG_ENTER();
320+
320321
sai_status_t status;
321322

322323
for (auto nhgm : syncd_fg_route_entry->nhopgroup_members)
@@ -337,6 +338,34 @@ bool FgNhgOrch::removeFineGrainedNextHopGroup(FGNextHopGroupEntry *syncd_fg_rout
337338

338339
if (!gRouteOrch->removeFineGrainedNextHopGroup(syncd_fg_route_entry->next_hop_group_id))
339340
{
341+
SWSS_LOG_ERROR("Failed to remove nhgid %" PRIx64 " return failure",
342+
syncd_fg_route_entry->next_hop_group_id);
343+
return false;
344+
}
345+
346+
return true;
347+
}
348+
349+
350+
bool FgNhgOrch::modifyRoutesNextHopId(sai_object_id_t vrf_id, const IpPrefix &ipPrefix, sai_object_id_t next_hop_id)
351+
{
352+
SWSS_LOG_ENTER();
353+
354+
sai_route_entry_t route_entry;
355+
sai_attribute_t route_attr;
356+
357+
route_entry.vr_id = vrf_id;
358+
route_entry.switch_id = gSwitchId;
359+
copy(route_entry.destination, ipPrefix);
360+
361+
route_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID;
362+
route_attr.value.oid = next_hop_id;
363+
364+
sai_status_t status = sai_route_api->set_route_entry_attribute(&route_entry, &route_attr);
365+
if (status != SAI_STATUS_SUCCESS)
366+
{
367+
SWSS_LOG_ERROR("Failed to set route %s with packet action forward, %d",
368+
ipPrefix.to_string().c_str(), status);
340369
return false;
341370
}
342371

@@ -385,22 +414,56 @@ bool FgNhgOrch::validNextHopInNextHopGroup(const NextHopKey& nexthop)
385414
return true;
386415
}
387416

388-
for (auto active_nh : syncd_fg_route_entry->active_nexthops)
417+
if (fgNhgEntry->hash_bucket_indices.size() == 0 && syncd_fg_route_entry->points_to_rif)
389418
{
390-
bank_member_changes[fgNhgEntry->next_hops[active_nh.ip_address].bank].
391-
active_nhs.push_back(active_nh);
419+
/* Only happens the 1st time when hash_bucket_indices are not inited
420+
*/
421+
for (auto it : fgNhgEntry->next_hops)
422+
{
423+
while (bank_member_changes.size() <= it.second.bank)
424+
{
425+
bank_member_changes.push_back(BankMemberChanges());
426+
}
427+
}
392428
}
393429

394430
bank_member_changes[fgNhgEntry->next_hops[nexthop.ip_address].bank].
395431
nhs_to_add.push_back(nexthop);
396432
nhopgroup_members_set[nexthop] = m_neighOrch->getNextHopId(nexthop);
397433

398-
if (!computeAndSetHashBucketChanges(syncd_fg_route_entry, fgNhgEntry,
399-
bank_member_changes, nhopgroup_members_set, route_table.first))
434+
if (syncd_fg_route_entry->points_to_rif)
400435
{
401-
SWSS_LOG_ERROR("Failed to set fine grained next hop %s",
402-
nexthop.to_string().c_str());
403-
return false;
436+
// RIF route is now neigh resolved: create Fine Grained ECMP
437+
if (!createFineGrainedNextHopGroup(*syncd_fg_route_entry, fgNhgEntry, syncd_fg_route_entry->nhg_key))
438+
{
439+
return false;
440+
}
441+
442+
if (!setNewNhgMembers(*syncd_fg_route_entry, fgNhgEntry, bank_member_changes, nhopgroup_members_set, route_table.first))
443+
{
444+
return false;
445+
}
446+
447+
if (!modifyRoutesNextHopId(route_tables.first, route_table.first, syncd_fg_route_entry->next_hop_group_id))
448+
{
449+
return false;
450+
}
451+
}
452+
else
453+
{
454+
for (auto active_nh : syncd_fg_route_entry->active_nexthops)
455+
{
456+
bank_member_changes[fgNhgEntry->next_hops[active_nh.ip_address].bank].
457+
active_nhs.push_back(active_nh);
458+
}
459+
460+
if (!computeAndSetHashBucketChanges(syncd_fg_route_entry, fgNhgEntry,
461+
bank_member_changes, nhopgroup_members_set, route_table.first))
462+
{
463+
SWSS_LOG_ERROR("Failed to set fine grained next hop %s",
464+
nexthop.to_string().c_str());
465+
return false;
466+
}
404467
}
405468

406469
m_neighOrch->increaseNextHopRefCount(nexthop);
@@ -760,14 +823,46 @@ bool FgNhgOrch::setInactiveBankToNextAvailableActiveBank(FGNextHopGroupEntry *sy
760823

761824
if (new_bank_idx == bank_member_changes.size())
762825
{
763-
SWSS_LOG_NOTICE("All banks of FG next-hops are down for prefix %s",
764-
ipPrefix.to_string().c_str());
765826
/* Case where there are no active banks */
766-
/* Note: There is no way to set a NULL OID to the now inactive next-hops
767-
* so we leave the next-hops as is in SAI, and future route/neighbor changes
768-
* will take care of setting the next-hops to the correctly active nhs
827+
SWSS_LOG_NOTICE("All banks of FG next-hops are down for prefix %s",
828+
ipPrefix.to_string().c_str());
829+
830+
/* This may occur when there are no neigh entries available any more
831+
* set route pointing to rif to allow for neigh resolution in kernel.
832+
* If route already points to rif then we are done.
769833
*/
770-
syncd_fg_route_entry->syncd_fgnhg_map[bank].clear();
834+
if (!syncd_fg_route_entry->points_to_rif)
835+
{
836+
std::string interface_alias = syncd_fg_route_entry->nhg_key.getNextHops().begin()->alias;
837+
sai_object_id_t rif_next_hop_id = m_intfsOrch->getRouterIntfsId(interface_alias);
838+
if (rif_next_hop_id == SAI_NULL_OBJECT_ID)
839+
{
840+
SWSS_LOG_INFO("Failed to get rif next hop for %s", interface_alias.c_str());
841+
return false;
842+
}
843+
if (!modifyRoutesNextHopId(gVirtualRouterId, ipPrefix, rif_next_hop_id))
844+
{
845+
SWSS_LOG_ERROR("Failed to modify route nexthopid to rif");
846+
return false;
847+
}
848+
849+
if (!removeFineGrainedNextHopGroup(syncd_fg_route_entry))
850+
{
851+
SWSS_LOG_ERROR("Failed to delete Fine Grained next hop group");
852+
return false;
853+
}
854+
855+
syncd_fg_route_entry->points_to_rif = true;
856+
syncd_fg_route_entry->next_hop_group_id = rif_next_hop_id;
857+
858+
// remove state_db entry
859+
m_stateWarmRestartRouteTable.del(ipPrefix.to_string());
860+
// Clear data structures
861+
syncd_fg_route_entry->syncd_fgnhg_map.clear();
862+
syncd_fg_route_entry->active_nexthops.clear();
863+
syncd_fg_route_entry->inactive_to_active_map.clear();
864+
syncd_fg_route_entry->nhopgroup_members.clear();
865+
}
771866
}
772867

773868
return true;
@@ -1017,6 +1112,7 @@ bool FgNhgOrch::setNewNhgMembers(FGNextHopGroupEntry &syncd_fg_route_entry, FgNh
10171112
{
10181113
m_recoveryMap.erase(nexthopsMap);
10191114
}
1115+
syncd_fg_route_entry.points_to_rif = false;
10201116

10211117
return true;
10221118
}
@@ -1094,13 +1190,13 @@ bool FgNhgOrch::syncdContainsFgNhg(sai_object_id_t vrf_id, const IpPrefix &ipPre
10941190

10951191

10961192
bool FgNhgOrch::setFgNhg(sai_object_id_t vrf_id, const IpPrefix &ipPrefix, const NextHopGroupKey &nextHops,
1097-
sai_object_id_t &next_hop_id, bool &prevNhgWasFineGrained)
1193+
sai_object_id_t &next_hop_id, bool &isNextHopIdChanged)
10981194
{
10991195
SWSS_LOG_ENTER();
11001196

1101-
/* default prevNhgWasFineGrained to true so that sai route is unaffected
1197+
/* default isNextHopIdChanged to false so that sai route is unaffected
11021198
* when we return early with success */
1103-
prevNhgWasFineGrained = true;
1199+
isNextHopIdChanged = false;
11041200
FgNhgEntry *fgNhgEntry = 0;
11051201
set<NextHopKey> next_hop_set = nextHops.getNextHops();
11061202
auto prefix_entry = m_fgNhgPrefixes.find(ipPrefix);
@@ -1123,7 +1219,7 @@ bool FgNhgOrch::setFgNhg(sai_object_id_t vrf_id, const IpPrefix &ipPrefix, const
11231219
break;
11241220
}
11251221
}
1126-
1222+
11271223
if (m_syncdFGRouteTables.find(vrf_id) != m_syncdFGRouteTables.end() &&
11281224
m_syncdFGRouteTables.at(vrf_id).find(ipPrefix) != m_syncdFGRouteTables.at(vrf_id).end() &&
11291225
m_syncdFGRouteTables.at(vrf_id).at(ipPrefix).nhg_key == nextHops)
@@ -1150,7 +1246,7 @@ bool FgNhgOrch::setFgNhg(sai_object_id_t vrf_id, const IpPrefix &ipPrefix, const
11501246
*/
11511247
for (auto it : fgNhgEntry->next_hops)
11521248
{
1153-
while(bank_member_changes.size() <= it.second.bank)
1249+
while (bank_member_changes.size() <= it.second.bank)
11541250
{
11551251
bank_member_changes.push_back(BankMemberChanges());
11561252
}
@@ -1202,6 +1298,7 @@ bool FgNhgOrch::setFgNhg(sai_object_id_t vrf_id, const IpPrefix &ipPrefix, const
12021298
{
12031299
bank_member_changes[fgNhgEntry->next_hops[nhk.ip_address].bank].
12041300
nhs_to_add.push_back(nhk);
1301+
next_hop_to_add = true;
12051302
}
12061303
}
12071304

@@ -1211,54 +1308,81 @@ bool FgNhgOrch::setFgNhg(sai_object_id_t vrf_id, const IpPrefix &ipPrefix, const
12111308

12121309
if (syncd_fg_route_entry_it != m_syncdFGRouteTables.at(vrf_id).end())
12131310
{
1311+
/* Route exists and nh was associated in the past */
12141312
FGNextHopGroupEntry *syncd_fg_route_entry = &(syncd_fg_route_entry_it->second);
1215-
/* Route exists, update FG ECMP group in SAI */
1216-
for (auto nhk : syncd_fg_route_entry->active_nexthops)
1313+
1314+
if (syncd_fg_route_entry->points_to_rif)
12171315
{
1218-
if (nhopgroup_members_set.find(nhk) == nhopgroup_members_set.end())
1316+
if (next_hop_to_add)
12191317
{
1220-
bank_member_changes[fgNhgEntry->next_hops[nhk.ip_address].bank].
1221-
nhs_to_del.push_back(nhk);
1318+
isNextHopIdChanged = true;
1319+
if (!createFineGrainedNextHopGroup(*syncd_fg_route_entry, fgNhgEntry, nextHops))
1320+
{
1321+
return false;
1322+
}
1323+
1324+
if (!setNewNhgMembers(*syncd_fg_route_entry, fgNhgEntry, bank_member_changes, nhopgroup_members_set, ipPrefix))
1325+
{
1326+
return false;
1327+
}
12221328
}
1223-
else
1329+
}
1330+
else
1331+
{
1332+
/* Update FG ECMP group in SAI */
1333+
for (auto nhk : syncd_fg_route_entry->active_nexthops)
12241334
{
1225-
bank_member_changes[fgNhgEntry->next_hops[nhk.ip_address].bank].
1226-
active_nhs.push_back(nhk);
1335+
if (nhopgroup_members_set.find(nhk) == nhopgroup_members_set.end())
1336+
{
1337+
bank_member_changes[fgNhgEntry->next_hops[nhk.ip_address].bank].
1338+
nhs_to_del.push_back(nhk);
1339+
}
1340+
else
1341+
{
1342+
bank_member_changes[fgNhgEntry->next_hops[nhk.ip_address].bank].
1343+
active_nhs.push_back(nhk);
1344+
}
12271345
}
1228-
}
12291346

1230-
if (!computeAndSetHashBucketChanges(syncd_fg_route_entry, fgNhgEntry, bank_member_changes,
1231-
nhopgroup_members_set, ipPrefix))
1232-
{
1233-
return false;
1347+
if (!computeAndSetHashBucketChanges(syncd_fg_route_entry, fgNhgEntry, bank_member_changes,
1348+
nhopgroup_members_set, ipPrefix))
1349+
{
1350+
return false;
1351+
}
12341352
}
12351353
}
12361354
else
12371355
{
12381356
/* New route + nhg addition */
1239-
prevNhgWasFineGrained = false;
1240-
if (next_hop_to_add == false)
1241-
{
1242-
SWSS_LOG_INFO("There were no valid next-hops to add %s:%s", ipPrefix.to_string().c_str(),
1243-
nextHops.to_string().c_str());
1244-
/* Let the route retry logic(upon false rc) take care of this case */
1245-
return false;
1246-
}
1247-
1357+
isNextHopIdChanged = true;
12481358
FGNextHopGroupEntry syncd_fg_route_entry;
1249-
if (!createFineGrainedNextHopGroup(syncd_fg_route_entry, fgNhgEntry, nextHops))
1359+
if (next_hop_to_add)
12501360
{
1251-
return false;
1252-
}
1361+
if (!createFineGrainedNextHopGroup(syncd_fg_route_entry, fgNhgEntry, nextHops))
1362+
{
1363+
return false;
1364+
}
12531365

1254-
if (!setNewNhgMembers(syncd_fg_route_entry, fgNhgEntry, bank_member_changes, nhopgroup_members_set, ipPrefix))
1366+
if (!setNewNhgMembers(syncd_fg_route_entry, fgNhgEntry, bank_member_changes, nhopgroup_members_set, ipPrefix))
1367+
{
1368+
return false;
1369+
}
1370+
}
1371+
else
12551372
{
1256-
return false;
1373+
sai_object_id_t rif_next_hop_id = m_intfsOrch->getRouterIntfsId(next_hop_set.begin()->alias);
1374+
if (rif_next_hop_id == SAI_NULL_OBJECT_ID)
1375+
{
1376+
SWSS_LOG_INFO("Failed to get rif next hop %s for %s",
1377+
nextHops.to_string().c_str(), ipPrefix.to_string().c_str());
1378+
return false;
1379+
}
1380+
1381+
syncd_fg_route_entry.next_hop_group_id = rif_next_hop_id;
1382+
syncd_fg_route_entry.points_to_rif = true;
12571383
}
12581384

12591385
m_syncdFGRouteTables[vrf_id][ipPrefix] = syncd_fg_route_entry;
1260-
1261-
SWSS_LOG_NOTICE("Created route %s:%s", ipPrefix.to_string().c_str(), nextHops.to_string().c_str());
12621386
}
12631387
m_syncdFGRouteTables[vrf_id][ipPrefix].nhg_key = nextHops;
12641388

@@ -1310,19 +1434,22 @@ bool FgNhgOrch::removeFgNhg(sai_object_id_t vrf_id, const IpPrefix &ipPrefix)
13101434
}
13111435

13121436
FGNextHopGroupEntry *syncd_fg_route_entry = &(it_route->second);
1313-
if (!removeFineGrainedNextHopGroup(syncd_fg_route_entry))
1437+
if (!syncd_fg_route_entry->points_to_rif)
13141438
{
1315-
SWSS_LOG_ERROR("Failed to clean-up fine grained ECMP SAI group");
1316-
return false;
1317-
}
1439+
if (!removeFineGrainedNextHopGroup(syncd_fg_route_entry))
1440+
{
1441+
SWSS_LOG_ERROR("Failed to clean-up fine grained ECMP SAI group");
1442+
return false;
1443+
}
13181444

1319-
for (auto nh : syncd_fg_route_entry->active_nexthops)
1320-
{
1321-
m_neighOrch->decreaseNextHopRefCount(nh);
1322-
}
1445+
for (auto nh : syncd_fg_route_entry->active_nexthops)
1446+
{
1447+
m_neighOrch->decreaseNextHopRefCount(nh);
1448+
}
13231449

1324-
// remove state_db entry
1325-
m_stateWarmRestartRouteTable.del(ipPrefix.to_string());
1450+
// remove state_db entry
1451+
m_stateWarmRestartRouteTable.del(ipPrefix.to_string());
1452+
}
13261453

13271454
it_route_table->second.erase(it_route);
13281455
if (it_route_table->second.size() == 0)

orchagent/fgnhgorch.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ struct FGNextHopGroupEntry
3030
BankFGNextHopGroupMap syncd_fgnhg_map; // Map of (bank) -> (nexthops) -> (index in nhopgroup_members)
3131
NextHopGroupKey nhg_key; // Full next hop group key
3232
InactiveBankMapsToBank inactive_to_active_map; // Maps an inactive bank to an active one in terms of hash bkts
33+
bool points_to_rif; // Flag to identify that route is currently pointing to a rif
3334
};
3435

3536
struct FGNextHopInfo
@@ -104,7 +105,7 @@ class FgNhgOrch : public Orch, public Observer
104105
bool syncdContainsFgNhg(sai_object_id_t vrf_id, const IpPrefix &ipPrefix);
105106
bool validNextHopInNextHopGroup(const NextHopKey&);
106107
bool invalidNextHopInNextHopGroup(const NextHopKey&);
107-
bool setFgNhg(sai_object_id_t vrf_id, const IpPrefix &ipPrefix, const NextHopGroupKey &nextHops, sai_object_id_t &next_hop_id, bool &prevNhgWasFineGrained);
108+
bool setFgNhg(sai_object_id_t vrf_id, const IpPrefix &ipPrefix, const NextHopGroupKey &nextHops, sai_object_id_t &next_hop_id, bool &isNextHopIdChanged);
108109
bool removeFgNhg(sai_object_id_t vrf_id, const IpPrefix &ipPrefix);
109110

110111
// warm reboot support
@@ -150,10 +151,10 @@ class FgNhgOrch : public Orch, public Observer
150151
void setStateDbRouteEntry(const IpPrefix&, uint32_t index, NextHopKey nextHop);
151152
bool writeHashBucketChange(FGNextHopGroupEntry *syncd_fg_route_entry, uint32_t index, sai_object_id_t nh_oid,
152153
const IpPrefix &ipPrefix, NextHopKey nextHop);
154+
bool modifyRoutesNextHopId(sai_object_id_t vrf_id, const IpPrefix &ipPrefix, sai_object_id_t next_hop_id);
153155
bool createFineGrainedNextHopGroup(FGNextHopGroupEntry &syncd_fg_route_entry, FgNhgEntry *fgNhgEntry,
154156
const NextHopGroupKey &nextHops);
155157
bool removeFineGrainedNextHopGroup(FGNextHopGroupEntry *syncd_fg_route_entry);
156-
157158
vector<FieldValueTuple> generateRouteTableFromNhgKey(NextHopGroupKey nhg);
158159
void cleanupIpInLinkToIpMap(const string &link, const IpAddress &ip, FgNhgEntry &fgNhg_entry);
159160

0 commit comments

Comments
 (0)