in fboss/agent/hw/bcm/BcmWarmBootCache.cpp [218:415]
void BcmWarmBootCache::populateFromWarmBootState(
const folly::dynamic& warmBootState) {
dumpedSwSwitchState_ =
SwitchState::uniquePtrFromFollyDynamic(warmBootState[kSwSwitch]);
dumpedSwSwitchState_->publish();
CHECK(dumpedSwSwitchState_)
<< "Was not able to recover software state after warmboot";
// Extract ecmps for dumped host table
auto& hostTable = warmBootState[kHwSwitch][kHostTable];
for (const auto& ecmpEntry : hostTable[kEcmpHosts]) {
auto ecmpEgressId = ecmpEntry[kEcmpEgressId].asInt();
if (ecmpEgressId == BcmEgressBase::INVALID) {
continue;
}
// If the entry is valid, then there must be paths associated with it.
for (auto path : ecmpEntry[kEcmpEgress][kPaths]) {
EgressId e = path.asInt();
hwSwitchEcmp2EgressIds_[ecmpEgressId][e]++;
}
}
// Extract ecmps from dumped warm boot cache. We
// may have shut down before a FIB sync
auto& ecmpObjects = warmBootState[kHwSwitch][kWarmBootCache][kEcmpObjects];
for (const auto& ecmpEntry : ecmpObjects) {
auto ecmpEgressId = ecmpEntry[kEcmpEgressId].asInt();
CHECK(ecmpEgressId != BcmEgressBase::INVALID);
for (const auto& path : ecmpEntry[kPaths]) {
EgressId e = path.asInt();
hwSwitchEcmp2EgressIds_[ecmpEgressId][e]++;
}
}
XLOG(DBG1) << "Reconstructed following ecmp path map ";
for (auto& ecmpIdAndEgress : hwSwitchEcmp2EgressIds_) {
XLOG(DBG1) << ecmpIdAndEgress.first << " (from warmboot file) ==> "
<< toEgressId2WeightStr(ecmpIdAndEgress.second);
}
auto& wbCache = warmBootState[kHwSwitch][kWarmBootCache];
if (auto it = wbCache.find(kTrunks); it != wbCache.items().end()) {
auto& trunks = it->second;
for (const auto& e : trunks.items()) {
trunks_[AggregatePortID(e.first.asInt())] = e.second.asInt();
}
XLOG(DBG1) << "Reconstructed following list of trunks ";
for (const auto& e : trunks_) {
XLOG(DBG0) << "Aggregate port " << e.first << " => trunk ID " << e.second;
}
}
if (wbCache.find(BcmRouteCounterTableBase::kRouteCounters) !=
wbCache.items().end()) {
auto& routeCounterInfo = wbCache[BcmRouteCounterTableBase::kRouteCounters];
if (routeCounterInfo.find(BcmRouteCounterTable::kGlobalModeId) !=
routeCounterInfo.items().end()) {
routeCounterModeId_ =
routeCounterInfo[BcmRouteCounterTable::kGlobalModeId].asInt();
XLOG(DBG2) << "Found route counter mode id " << routeCounterModeId_;
}
if (routeCounterInfo.find(BcmRouteFlexCounterTable::kFlexCounterActionV6) !=
routeCounterInfo.items().end()) {
v6FlexCounterAction_ =
routeCounterInfo[BcmRouteFlexCounterTable::kFlexCounterActionV6]
.asInt();
XLOG(DBG2) << "Found v6 route flex counter action id "
<< v6FlexCounterAction_;
}
auto& routeCounterIDs =
routeCounterInfo[BcmRouteCounterTableBase::kRouteCounterIDs];
for (const auto& e : routeCounterIDs.items()) {
auto counterId = e.second;
if (counterId.type() == folly::dynamic::Type::OBJECT) {
routeCounterIDs_[e.first.asString()] =
BcmRouteCounterID::fromFollyDynamic(counterId);
} else {
routeCounterIDs_[e.first.asString()] =
BcmRouteCounterID(counterId.asInt(), 0);
}
}
for (const auto& e : routeCounterIDs_) {
XLOG(DBG2) << "Found route counter id " << e.first << " Hwid "
<< e.second.str();
}
}
// Extract BcmHost and its egress object from the warm boot file
for (const auto& hostEntry : hostTable[kHosts]) {
auto egressId = hostEntry[kEgressId].asInt();
if (egressId == BcmEgressBase::INVALID) {
continue;
}
egressId2WeightInWarmBootFile_[egressId]++;
std::optional<bcm_if_t> intf{std::nullopt};
auto ip = folly::IPAddress(hostEntry[kIp].stringPiece());
if (ip.isV6() && ip.isLinkLocal()) {
auto egressIt = hostEntry.find(kEgress);
if (egressIt != hostEntry.items().end()) {
// check if kIntfId is part of the key, if not. That means it is an ECMP
// egress object. No interface in this case.
auto intfIt = egressIt->second.find(kIntfId);
if (intfIt != egressIt->second.items().end()) {
intf = intfIt->second.asInt();
}
}
}
auto vrf = hostEntry[kVrf].asInt();
auto key = std::make_tuple(vrf, ip, intf);
vrfIp2EgressFromBcmHostInWarmBootFile_[key] = egressId;
int classID = 0;
if (hostEntry.find(kClassID) != hostEntry.items().end()) {
classID = hostEntry[kClassID].asInt();
}
XLOG(DBG1) << "Construct a host entry (vrf=" << vrf << ",ip=" << ip
<< ",intf="
<< (intf.has_value() ? folly::to<std::string>(intf.value())
: "None")
<< ") pointing to the egress entry, id=" << egressId
<< " classID: " << classID;
}
// extract MPLS next hop and its egress object from the warm boot file
const auto& mplsNextHops = (warmBootState[kHwSwitch].find(kMplsNextHops) !=
warmBootState[kHwSwitch].items().end())
? warmBootState[kHwSwitch][kMplsNextHops]
: folly::dynamic::array();
for (const auto& mplsNextHop : mplsNextHops) {
auto egressId = mplsNextHop[kEgressId].asInt();
if (egressId == BcmEgressBase::INVALID) {
continue;
}
egressId2WeightInWarmBootFile_[egressId]++;
auto vrf = mplsNextHop[kVrf].asInt();
auto ip = folly::IPAddress(mplsNextHop[kIp].stringPiece());
auto intfID = InterfaceID(mplsNextHop[kIntf].asInt());
if (mplsNextHop.items().end() != mplsNextHop.find(kLabel)) {
// labeled egress
auto label = mplsNextHop[kLabel].asInt();
mplsNextHops2EgressIdInWarmBootFile_.emplace(
BcmLabeledHostKey(vrf, label, ip, intfID), egressId);
} else {
// tunneled egress
CHECK(mplsNextHop.items().end() != mplsNextHop.find(kStack));
CHECK(mplsNextHop[kStack].isArray());
LabelForwardingAction::LabelStack labels;
std::for_each(
std::begin(mplsNextHop[kStack]),
std::end(mplsNextHop[kStack]),
[&labels](const auto& label) { labels.push_back(label.asInt()); });
mplsNextHops2EgressIdInWarmBootFile_.emplace(
BcmLabeledHostKey(vrf, std::move(labels), ip, intfID), egressId);
}
}
// get l3 intfs for each known vlan in warmboot state file
// TODO(pshaikh): in earlier warm boot state file, kIntfTable could be
// absent after two pushes this condition can be removed
const auto& intfTable = (warmBootState[kHwSwitch].find(kIntfTable) !=
warmBootState[kHwSwitch].items().end())
? warmBootState[kHwSwitch][kIntfTable]
: folly::dynamic::array();
for (const auto& intfTableEntry : intfTable) {
vlan2BcmIfIdInWarmBootFile_.emplace(
VlanID(intfTableEntry[kVlan].asInt()), intfTableEntry[kIntfId].asInt());
}
// TODO(pshaikh): in earlier warm boot state file, kQosPolicyTable could be
// absent after two pushes this condition can be removed
const auto& qosPolicyTable =
(warmBootState[kHwSwitch].find(kQosPolicyTable) !=
warmBootState[kHwSwitch].items().end())
? warmBootState[kHwSwitch][kQosPolicyTable]
: folly::dynamic::object();
for (const auto& qosPolicy : qosPolicyTable.keys()) {
auto policyName = qosPolicy.asString();
if (qosPolicyTable[policyName].find(kInDscp) !=
qosPolicyTable[policyName].items().end()) {
qosMapKey2QosMapId_.emplace(
std::make_pair(policyName, BcmQosMap::Type::IP_INGRESS),
qosPolicyTable[policyName][kInDscp].asInt());
}
if (qosPolicyTable[policyName].find(kInExp) !=
qosPolicyTable[policyName].items().end()) {
qosMapKey2QosMapId_.emplace(
std::make_pair(policyName, BcmQosMap::Type::MPLS_INGRESS),
qosPolicyTable[policyName][kInExp].asInt());
}
if (qosPolicyTable[policyName].find(kOutExp) !=
qosPolicyTable[policyName].items().end()) {
qosMapKey2QosMapId_.emplace(
std::make_pair(policyName, BcmQosMap::Type::MPLS_EGRESS),
qosPolicyTable[policyName][kOutExp].asInt());
}
}
}