@@ -317,6 +317,7 @@ bool FgNhgOrch::createFineGrainedNextHopGroup(FGNextHopGroupEntry &syncd_fg_rout
317317bool 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
10961192bool 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 )
0 commit comments