in fboss/agent/hw/bcm/BcmSwitch.cpp [764:954]
HwInitResult BcmSwitch::init(
Callback* callback,
bool /*failHwCallsOnWarmboot*/) {
HwInitResult ret;
ret.rib = std::make_unique<RoutingInformationBase>();
std::lock_guard<std::mutex> g(lock_);
steady_clock::time_point begin = steady_clock::now();
CHECK(!unitObject_);
unitObject_ = BcmAPI::createOnlyUnit(platform_);
unit_ = unitObject_->getNumber();
unitObject_->setCookie(this);
BcmAPI::initUnit(unit_, platform_);
bootType_ = platform_->getWarmBootHelper()->canWarmBoot()
? BootType::WARM_BOOT
: BootType::COLD_BOOT;
auto warmBoot = bootType_ == BootType::WARM_BOOT;
callback_ = callback;
ret.initializedTime =
duration_cast<duration<float>>(steady_clock::now() - begin).count();
XLOG(INFO) << "Initializing BcmSwitch for unit " << unit_;
// Add callbacks for unit and parity errors as early as possible to handle
// critical events
BcmSwitchEventUtils::initUnit(unit_, this);
auto fatalCob = make_shared<BcmSwitchEventUnitFatalErrorCallback>();
auto nonFatalCob = make_shared<BcmSwitchEventUnitNonFatalErrorCallback>();
BcmSwitchEventUtils::registerSwitchEventCallback(
unit_, BCM_SWITCH_EVENT_STABLE_FULL, fatalCob);
BcmSwitchEventUtils::registerSwitchEventCallback(
unit_, BCM_SWITCH_EVENT_STABLE_ERROR, fatalCob);
BcmSwitchEventUtils::registerSwitchEventCallback(
unit_, BCM_SWITCH_EVENT_UNCONTROLLED_SHUTDOWN, fatalCob);
BcmSwitchEventUtils::registerSwitchEventCallback(
unit_, BCM_SWITCH_EVENT_WARM_BOOT_DOWNGRADE, fatalCob);
BcmSwitchEventUtils::registerSwitchEventCallback(
unit_, BCM_SWITCH_EVENT_PARITY_ERROR, nonFatalCob);
// Create bcmStatUpdater to cache the stat ids
bcmStatUpdater_ = std::make_unique<BcmStatUpdater>(this);
XLOG(INFO) << " Is ALPM enabled: " << BcmAPI::isAlpmEnabled();
// Additional switch configuration
auto state = make_shared<SwitchState>();
bcm_port_config_t pcfg;
bcm_port_config_t_init(&pcfg);
auto rv = bcm_port_config_get(unit_, &pcfg);
bcmCheckError(rv, "failed to get port configuration");
if (!warmBoot) {
LOG(INFO) << " Performing cold boot ";
/* initialize mirroring module */
initMirrorModule();
/* initialize MPLS */
initMplsModule();
} else {
LOG(INFO) << "Performing warm boot ";
// This dumps debug info about initial sdk state. Useful after warm boot.
dumpState(platform_->getWarmBootHelper()->startupSdkDumpFile());
}
// If the platform doesn't support auto enabling l3 egress mode
if (!platform_->getAsic()->isSupported(
HwAsic::Feature::L3_EGRESS_MODE_AUTO_ENABLED)) {
rv = bcm_switch_control_set(unit_, bcmSwitchL3EgressMode, 1);
bcmCheckError(rv, "failed to set L3 egress mode");
}
if (getPlatform()->getAsic()->getAsicType() ==
HwAsic::AsicType::ASIC_TYPE_TOMAHAWK4) {
rv = bcm_l3_enable_set(unit_, 1);
bcmCheckError(rv, "failed to enable l3");
}
// Trap IPv4 Address Resolution Protocol (ARP) packets.
// TODO: We may want to trap ARP on a per-port or per-VLAN basis.
rv = bcm_switch_control_set(unit_, bcmSwitchArpRequestToCpu, 1);
bcmCheckError(rv, "failed to set ARP request trapping");
rv = bcm_switch_control_set(unit_, bcmSwitchArpReplyToCpu, 1);
bcmCheckError(rv, "failed to set ARP reply trapping");
// Trap IP header TTL or hoplimit 1 to CPU
rv = bcm_switch_control_set(unit_, bcmSwitchL3UcastTtl1ToCpu, 1);
bcmCheckError(rv, "failed to set L3 header error trapping");
// Trap DHCP packets to CPU
rv = bcm_switch_control_set(unit_, bcmSwitchDhcpPktToCpu, 1);
bcmCheckError(rv, "failed to set DHCP packet trapping");
// Trap Dest miss
rv = bcm_switch_control_set(unit_, bcmSwitchUnknownL3DestToCpu, 1);
bcmCheckError(rv, "failed to set destination miss trapping");
rv = bcm_switch_control_set(unit_, bcmSwitchV6L3DstMissToCpu, 1);
bcmCheckError(rv, "failed to set IPv6 destination miss trapping");
// Trap IPv6 Neighbor Discovery Protocol (NDP) packets.
// TODO: We may want to trap NDP on a per-port or per-VLAN basis.
rv = bcm_switch_control_set(unit_, bcmSwitchNdPktToCpu, 1);
bcmCheckError(rv, "failed to set NDP trapping");
disableHotSwap();
if (FLAGS_force_init_fp || !warmBoot || haveMissingOrQSetChangedFPGroups()) {
initFieldProcessor();
setupFPGroups();
}
dropDhcpPackets();
setL3MtuFailPackets();
mmuState_ = BcmAPI::getMmuState();
// enable IPv4 and IPv6 on CPU port
bcm_port_t idx;
BCM_PBMP_ITER(pcfg.cpu, idx) {
rv = bcm_port_control_set(unit_, idx, bcmPortControlIP4, 1);
bcmCheckError(rv, "failed to enable IPv4 on cpu port ", idx);
rv = bcm_port_control_set(unit_, idx, bcmPortControlIP6, 1);
bcmCheckError(rv, "failed to enable IPv6 on cpu port ", idx);
XLOG(DBG2) << "Enabled IPv4/IPv6 on CPU port " << idx;
}
// Setup the default drop egress
BcmEgress::setupDefaultDropEgress(unit_, getDropEgressId());
setupCos();
folly::dynamic switchStateJson;
if (warmBoot) {
// This needs to be done after we have set
// bcmSwitchL3EgressMode else the egress ids
// in the host table don't show up correctly.
switchStateJson = getPlatform()->getWarmBootHelper()->getWarmBootState();
warmBootCache_->populate(switchStateJson);
}
setupToCpuEgress();
portTable_->initPorts(&pcfg, warmBoot);
bstStatsMgr_->startBufferStatCollection();
// Set the spanning tree state of all ports to forwarding.
// TODO: Eventually the spanning tree state should be part of the Port
// state, and this should be handled in applyConfig().
//
// Spanning tree group settings
// TODO: This should eventually be done as part of applyConfig()
bcm_stg_t stg = 1;
BCM_PBMP_ITER(pcfg.port, idx) {
rv = bcm_stg_stp_set(unit_, stg, idx, BCM_STG_STP_FORWARD);
bcmCheckError(rv, "failed to set spanning tree state on port ", idx);
}
ret.bootType = bootType_;
if (warmBoot) {
ret.switchState = warmBootCache_->getDumpedSwSwitchState().clone();
getPlatform()->preWarmbootStateApplied();
if (switchStateJson.find(kRib) != switchStateJson.items().end()) {
ret.rib = RoutingInformationBase::fromFollyDynamic(
switchStateJson[kRib],
ret.switchState->getFibs(),
ret.switchState->getLabelForwardingInformationBase());
}
stateChangedImpl(StateDelta(make_shared<SwitchState>(), ret.switchState));
hostTable_->warmBootHostEntriesSynced();
// Done with warm boot, clear warm boot cache
warmBootCache_->clear();
if (getPlatform()->getAsic()->getAsicType() ==
HwAsic::AsicType::ASIC_TYPE_TRIDENT2) {
for (auto ip : {folly::IPAddress("0.0.0.0"), folly::IPAddress("::")}) {
bcm_l3_route_t rt;
bcm_l3_route_t_init(&rt);
rt.l3a_flags |= ip.isV6() ? BCM_L3_IP6 : 0;
bcm_l3_route_get(getUnit(), &rt);
rt.l3a_flags |= BCM_L3_REPLACE;
bcm_l3_route_add(getUnit(), &rt);
}
}
} else {
ret.switchState = getColdBootSwitchState();
setMacAging(std::chrono::seconds(
ret.switchState->getSwitchSettings()->getL2AgeTimerSeconds()));
}
macTable_ = std::make_unique<BcmMacTable>(this);
ret.bootTime =
duration_cast<duration<float>>(steady_clock::now() - begin).count();
ret.switchState->publish();
return ret;
}