@@ -317,6 +317,7 @@ bool FgNhgOrch::createFineGrainedNextHopGroup(FGNextHopGroupEntry &syncd_fg_rout
317
317
bool FgNhgOrch::removeFineGrainedNextHopGroup (FGNextHopGroupEntry *syncd_fg_route_entry)
318
318
{
319
319
SWSS_LOG_ENTER ();
320
+
320
321
sai_status_t status;
321
322
322
323
for (auto nhgm : syncd_fg_route_entry->nhopgroup_members )
@@ -337,6 +338,34 @@ bool FgNhgOrch::removeFineGrainedNextHopGroup(FGNextHopGroupEntry *syncd_fg_rout
337
338
338
339
if (!gRouteOrch ->removeFineGrainedNextHopGroup (syncd_fg_route_entry->next_hop_group_id ))
339
340
{
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);
340
369
return false ;
341
370
}
342
371
@@ -385,22 +414,56 @@ bool FgNhgOrch::validNextHopInNextHopGroup(const NextHopKey& nexthop)
385
414
return true ;
386
415
}
387
416
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 )
389
418
{
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
+ }
392
428
}
393
429
394
430
bank_member_changes[fgNhgEntry->next_hops [nexthop.ip_address ].bank ].
395
431
nhs_to_add.push_back (nexthop);
396
432
nhopgroup_members_set[nexthop] = m_neighOrch->getNextHopId (nexthop);
397
433
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 )
400
435
{
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
+ }
404
467
}
405
468
406
469
m_neighOrch->increaseNextHopRefCount (nexthop);
@@ -760,14 +823,46 @@ bool FgNhgOrch::setInactiveBankToNextAvailableActiveBank(FGNextHopGroupEntry *sy
760
823
761
824
if (new_bank_idx == bank_member_changes.size ())
762
825
{
763
- SWSS_LOG_NOTICE (" All banks of FG next-hops are down for prefix %s" ,
764
- ipPrefix.to_string ().c_str ());
765
826
/* 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.
769
833
*/
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
+ }
771
866
}
772
867
773
868
return true ;
@@ -1017,6 +1112,7 @@ bool FgNhgOrch::setNewNhgMembers(FGNextHopGroupEntry &syncd_fg_route_entry, FgNh
1017
1112
{
1018
1113
m_recoveryMap.erase (nexthopsMap);
1019
1114
}
1115
+ syncd_fg_route_entry.points_to_rif = false ;
1020
1116
1021
1117
return true ;
1022
1118
}
@@ -1094,13 +1190,13 @@ bool FgNhgOrch::syncdContainsFgNhg(sai_object_id_t vrf_id, const IpPrefix &ipPre
1094
1190
1095
1191
1096
1192
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 )
1098
1194
{
1099
1195
SWSS_LOG_ENTER ();
1100
1196
1101
- /* default prevNhgWasFineGrained to true so that sai route is unaffected
1197
+ /* default isNextHopIdChanged to false so that sai route is unaffected
1102
1198
* when we return early with success */
1103
- prevNhgWasFineGrained = true ;
1199
+ isNextHopIdChanged = false ;
1104
1200
FgNhgEntry *fgNhgEntry = 0 ;
1105
1201
set<NextHopKey> next_hop_set = nextHops.getNextHops ();
1106
1202
auto prefix_entry = m_fgNhgPrefixes.find (ipPrefix);
@@ -1123,7 +1219,7 @@ bool FgNhgOrch::setFgNhg(sai_object_id_t vrf_id, const IpPrefix &ipPrefix, const
1123
1219
break ;
1124
1220
}
1125
1221
}
1126
-
1222
+
1127
1223
if (m_syncdFGRouteTables.find (vrf_id) != m_syncdFGRouteTables.end () &&
1128
1224
m_syncdFGRouteTables.at (vrf_id).find (ipPrefix) != m_syncdFGRouteTables.at (vrf_id).end () &&
1129
1225
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
1150
1246
*/
1151
1247
for (auto it : fgNhgEntry->next_hops )
1152
1248
{
1153
- while (bank_member_changes.size () <= it.second .bank )
1249
+ while (bank_member_changes.size () <= it.second .bank )
1154
1250
{
1155
1251
bank_member_changes.push_back (BankMemberChanges ());
1156
1252
}
@@ -1202,6 +1298,7 @@ bool FgNhgOrch::setFgNhg(sai_object_id_t vrf_id, const IpPrefix &ipPrefix, const
1202
1298
{
1203
1299
bank_member_changes[fgNhgEntry->next_hops [nhk.ip_address ].bank ].
1204
1300
nhs_to_add.push_back (nhk);
1301
+ next_hop_to_add = true ;
1205
1302
}
1206
1303
}
1207
1304
@@ -1211,54 +1308,81 @@ bool FgNhgOrch::setFgNhg(sai_object_id_t vrf_id, const IpPrefix &ipPrefix, const
1211
1308
1212
1309
if (syncd_fg_route_entry_it != m_syncdFGRouteTables.at (vrf_id).end ())
1213
1310
{
1311
+ /* Route exists and nh was associated in the past */
1214
1312
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 )
1217
1315
{
1218
- if (nhopgroup_members_set. find (nhk) == nhopgroup_members_set. end () )
1316
+ if (next_hop_to_add )
1219
1317
{
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
+ }
1222
1328
}
1223
- else
1329
+ }
1330
+ else
1331
+ {
1332
+ /* Update FG ECMP group in SAI */
1333
+ for (auto nhk : syncd_fg_route_entry->active_nexthops )
1224
1334
{
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
+ }
1227
1345
}
1228
- }
1229
1346
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
+ }
1234
1352
}
1235
1353
}
1236
1354
else
1237
1355
{
1238
1356
/* 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 ;
1248
1358
FGNextHopGroupEntry syncd_fg_route_entry;
1249
- if (! createFineGrainedNextHopGroup (syncd_fg_route_entry, fgNhgEntry, nextHops) )
1359
+ if (next_hop_to_add )
1250
1360
{
1251
- return false ;
1252
- }
1361
+ if (!createFineGrainedNextHopGroup (syncd_fg_route_entry, fgNhgEntry, nextHops))
1362
+ {
1363
+ return false ;
1364
+ }
1253
1365
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
1255
1372
{
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 ;
1257
1383
}
1258
1384
1259
1385
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 ());
1262
1386
}
1263
1387
m_syncdFGRouteTables[vrf_id][ipPrefix].nhg_key = nextHops;
1264
1388
@@ -1310,19 +1434,22 @@ bool FgNhgOrch::removeFgNhg(sai_object_id_t vrf_id, const IpPrefix &ipPrefix)
1310
1434
}
1311
1435
1312
1436
FGNextHopGroupEntry *syncd_fg_route_entry = &(it_route->second );
1313
- if (!removeFineGrainedNextHopGroup ( syncd_fg_route_entry) )
1437
+ if (!syncd_fg_route_entry-> points_to_rif )
1314
1438
{
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
+ }
1318
1444
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
+ }
1323
1449
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
+ }
1326
1453
1327
1454
it_route_table->second .erase (it_route);
1328
1455
if (it_route_table->second .size () == 0 )
0 commit comments