void BcmWarmBootCache::populateFromWarmBootState()

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());
    }
  }
}