Skip to content

Commit b128dc4

Browse files
Dynamic FDB entries should be skipped during warm boot if aged out in h/w
Signed-off-by: Vishrant Vasavada <vvasavada@nexthop.ai>
1 parent 52407a3 commit b128dc4

6 files changed

Lines changed: 84 additions & 8 deletions

File tree

fboss/agent/hw/sai/api/FdbApi.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,12 @@ SAI_ATTRIBUTE_NAME(Fdb, Metadata)
102102
template <>
103103
struct IsSaiEntryStruct<SaiFdbTraits::FdbEntry> : public std::true_type {};
104104

105+
// Dynamic FDB entries age out in hardware on their own, so an entry FBOSS
106+
// tracks - in the store, or in a warm boot state written moments earlier - may
107+
// already be gone from HW.
108+
template <>
109+
struct SaiObjectMayBeMissingInHw<SaiFdbTraits> : public std::true_type {};
110+
105111
class FdbApi : public SaiApi<FdbApi> {
106112
public:
107113
static constexpr sai_api_t ApiType = SAI_API_FDB;

fboss/agent/hw/sai/api/Traits.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,14 @@ concept SaiAttributeTuple =
488488
template <typename SaiObjectTraits>
489489
struct IsSaiObjectOwnedByAdapter : public std::false_type {};
490490

491+
/*
492+
* Hardware can delete objects of some types on its own, without the agent
493+
* asking. For those, an object FBOSS still tracks may already be gone from
494+
* hardware, so ITEM_NOT_FOUND is an expected outcome rather than a fatal one.
495+
*/
496+
template <typename SaiObjectTraits>
497+
struct SaiObjectMayBeMissingInHw : public std::false_type {};
498+
491499
template <typename SaiObjectTraits>
492500
struct SaiObjectHasStats : public std::false_type {};
493501

fboss/agent/hw/sai/store/SaiObject.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -536,7 +536,8 @@ class SaiObject {
536536
bool ownedByAdapter_{IsSaiObjectOwnedByAdapter<SaiObjectTraits>::value};
537537
// For some object types we can ignore missing in HW errors
538538
// on when deleting.
539-
bool ignoreMissingInHwOnDelete_{false};
539+
bool ignoreMissingInHwOnDelete_{
540+
SaiObjectMayBeMissingInHw<SaiObjectTraits>::value};
540541
// For some object types we want to skip remove call when deleting
541542
bool skipRemove_{false};
542543
typename SaiObjectTraits::AdapterKey adapterKey_;

fboss/agent/hw/sai/store/SaiStore.h

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -184,10 +184,13 @@ class SaiObjectStore {
184184
keys.end());
185185
}
186186
for (const auto& k : keys) {
187-
ObjectType obj = getObject(k, adapterKeys2AdapterHostKey);
188-
auto adapterHostKey = obj.adapterHostKey();
189-
XLOGF(DBG5, "SaiStore reloaded {}", obj);
190-
auto ins = objects_.refOrInsert(adapterHostKey, std::move(obj));
187+
auto obj = getObjectIfInHw(k, adapterKeys2AdapterHostKey);
188+
if (!obj) {
189+
continue;
190+
}
191+
auto adapterHostKey = obj->adapterHostKey();
192+
XLOGF(DBG5, "SaiStore reloaded {}", *obj);
193+
auto ins = objects_.refOrInsert(adapterHostKey, std::move(*obj));
191194
if (!ins.second) {
192195
XLOG(FATAL) << "[" << saiObjectTypeToString(SaiObjectTraits::ObjectType)
193196
<< "]" << " Unexpected duplicate adapterHostKey";
@@ -495,6 +498,37 @@ class SaiObjectStore {
495498
});
496499
}
497500

501+
/*
502+
* Warm boot reloads objects from adapter keys saved at graceful exit. For
503+
* object types hardware can delete on its own, that snapshot is only a best
504+
* effort: e.g. a dynamic FDB entry can age out after the keys are written, or
505+
* after an age event the agent never got to process. Skip such keys instead
506+
* of letting the missing object abort warm boot - switch state replays
507+
* whatever is still needed, and removeUnclaimedDynanicEntries() cleans up the
508+
* rest.
509+
*/
510+
std::optional<ObjectType> getObjectIfInHw(
511+
const typename SaiObjectTraits::AdapterKey& key,
512+
const folly::dynamic* adapterKeys2AdapterHostKey) {
513+
if constexpr (SaiObjectMayBeMissingInHw<SaiObjectTraits>::value) {
514+
try {
515+
return getObject(key, adapterKeys2AdapterHostKey);
516+
} catch (const SaiApiError& e) {
517+
if (e.getSaiStatus() != SAI_STATUS_ITEM_NOT_FOUND) {
518+
throw;
519+
}
520+
XLOGF(
521+
WARN,
522+
"[{}] skipping {} on reload, no longer present in hardware",
523+
objectTypeName().str(),
524+
key);
525+
return std::nullopt;
526+
}
527+
} else {
528+
return getObject(key, adapterKeys2AdapterHostKey);
529+
}
530+
}
531+
498532
ObjectType getObject(
499533
typename ObjectTraits::AdapterKey key,
500534
const folly::dynamic* adapterKey2AdapterHostKey) {

fboss/agent/hw/sai/store/tests/FdbStoreTest.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,33 @@ TEST_F(SaiStoreTest, fdbSetBridgePort) {
8080
EXPECT_EQ(GET_OPT_ATTR(Fdb, Metadata, obj->attributes()), 23);
8181
}
8282

83+
// Hardware ages dynamic FDB entries out on its own, so an entry saved in warm
84+
// boot state can be gone by the time the store reloads it. Reload must skip it
85+
// rather than let ITEM_NOT_FOUND abort warm boot.
86+
TEST_F(SaiStoreTest, fdbAgedOutBeforeReload) {
87+
auto& fdbApi = saiApiTable->fdbApi();
88+
SaiFdbTraits::FdbEntry present(0, 10, folly::MacAddress{"42:42:42:42:42:42"});
89+
SaiFdbTraits::FdbEntry aged(0, 10, folly::MacAddress{"42:42:42:42:42:43"});
90+
fdbApi.create<SaiFdbTraits>(present, {SAI_FDB_ENTRY_TYPE_STATIC, 42, 24});
91+
fdbApi.create<SaiFdbTraits>(aged, {SAI_FDB_ENTRY_TYPE_DYNAMIC, 42, 24});
92+
93+
// Warm boot state is written with both entries in it
94+
folly::dynamic adapterKeys;
95+
{
96+
SaiStore preWarmBoot(0);
97+
preWarmBoot.reload();
98+
adapterKeys = preWarmBoot.adapterKeysFollyDynamic();
99+
}
100+
// ... and HW ages the dynamic one out while the agent is down
101+
fdbApi.remove(aged);
102+
103+
SaiStore postWarmBoot(0);
104+
postWarmBoot.reload(&adapterKeys);
105+
auto& store = postWarmBoot.get<SaiFdbTraits>();
106+
EXPECT_NE(store.get(present), nullptr);
107+
EXPECT_EQ(store.get(aged), nullptr);
108+
}
109+
83110
TEST_F(SaiStoreTest, fdbSerDeser) {
84111
auto& fdbApi = saiApiTable->fdbApi();
85112
folly::MacAddress mac{"42:42:42:42:42:42"};

fboss/agent/hw/sai/switch/SaiFdbManager.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,14 @@ void ManagedFdbEntry::createObject(PublisherObjects objects) {
5252
SaiFdbTraits::CreateAttributes attributes{type_, bridgePortId, metadata_};
5353

5454
auto fdbEntry = manager_->createSaiObject(entry, attributes, intfIDAndMac_);
55-
// For FDB entry, on delete, Ignore error if entry was already removed from
56-
// HW. One scenario where this can occur is the following
55+
// Missing in HW is tolerated for FDB entries on delete and on warm boot
56+
// reload - see SaiObjectMayBeMissingInHw<SaiFdbTraits>. One scenario where
57+
// this can occur is the following
5758
// - We learn a MAC and install it in HW
5859
// - Later we get a state update to transform this into a STATIC FDB entry
5960
// - Meanwhile the dynamic MAC ages out and gets deleted
6061
// - While processing the state delta for changed MAC entry, we try to
6162
// delete the dynamic entry before adding static entry
62-
fdbEntry->setIgnoreMissingInHwOnDelete(true);
6363
// If pending_L2_entry is not supported, dynamic l2 entry is already deleted
6464
// from HW table upon receiving the l2 age event. Therefore, no need to make
6565
// the remove call down to SDK layer.

0 commit comments

Comments
 (0)