fboss/agent/platforms/wedge/WedgePlatform.cpp (180 lines of code) (raw):

/* * Copyright (c) 2004-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * */ #include "fboss/agent/platforms/wedge/WedgePlatform.h" #include <folly/Memory.h> #include <folly/logging/xlog.h> #include "fboss/agent/SwSwitch.h" #include "fboss/agent/SysError.h" #include "fboss/agent/hw/bcm/BcmAPI.h" #include "fboss/agent/hw/bcm/BcmConfig.h" #include "fboss/agent/hw/bcm/BcmPortTable.h" #include "fboss/agent/hw/bcm/BcmSwitch.h" #include "fboss/agent/hw/bcm/BcmWarmBootHelper.h" #include "fboss/agent/hw/switch_asics/HwAsic.h" #include "fboss/agent/platforms/common/PlatformMapping.h" #include "fboss/agent/platforms/wedge/WedgePort.h" #include "fboss/agent/platforms/wedge/WedgePortMapping.h" #include "fboss/agent/state/Port.h" #include "fboss/agent/state/SwitchState.h" #include "fboss/lib/platforms/PlatformProductInfo.h" #include "fboss/lib/usb/UsbError.h" #include "fboss/lib/usb/WedgeI2CBus.h" #include "fboss/qsfp_service/lib/QsfpCache.h" #include <future> DEFINE_string( fabric_location, "", "Provides location of fabric , LEFT or RIGHT"); using folly::MacAddress; using std::make_unique; using std::string; namespace facebook::fboss { WedgePlatform::WedgePlatform( std::unique_ptr<PlatformProductInfo> productInfo, std::unique_ptr<PlatformMapping> platformMapping, folly::MacAddress localMac) : BcmPlatform(std::move(productInfo), std::move(platformMapping), localMac), qsfpCache_(std::make_unique<AutoInitQsfpCache>()) {} void WedgePlatform::initImpl(uint32_t hwFeaturesDesired) { if (getAsic()->isSupported(HwAsic::Feature::HSDK)) { BcmAPI::initHSDK(loadYamlConfig()); } else { BcmAPI::init(loadConfig()); } hw_.reset(new BcmSwitch(this, hwFeaturesDesired)); } WedgePlatform::~WedgePlatform() { BcmAPI::shutdown(); hw_.reset(); } void WedgePlatform::initPorts() { portMapping_ = createPortMapping(); } WedgePlatform::BcmPlatformPortMap WedgePlatform::getPlatformPortMap() { if (portMapping_ == nullptr) { throw FbossError( "Platform port mapping is empty, need to initPorts() first"); } BcmPlatformPortMap mapping; for (const auto& kv : *portMapping_) { bcm_port_t id = kv.first; mapping[id] = kv.second.get(); } return mapping; } void WedgePlatform::stop() { // destroying the cache will cause it to stop the QsfpCacheThread qsfpCache_.reset(); } void WedgePlatform::onHwInitialized(SwSwitch* sw) { // could populate with initial ports here, but should get taken care // of through state changes sent to the stateUpdated method. initLEDs(); // Make sure the initial status of the LEDs reflects the current port // settings. for (const auto& entry : *portMapping_) { // As some platform allows add/remove port at the first time applying the // config, we should skip those ports which doesn't exist in hw. if (!hw_->getPortTable()->getBcmPortIf(entry.first)) { continue; } bool up = hw_->isPortUp(entry.first); entry.second->linkStatusChanged(up, true); } sw->registerStateObserver(this, "WedgePlatform"); } void WedgePlatform::stateUpdated(const StateDelta& delta) { updatePorts(delta); updateQsfpCache(delta); } void WedgePlatform::updateQsfpCache(const StateDelta& delta) { QsfpCache::PortMapThrift changedPorts; auto portsDelta = delta.getPortsDelta(); for (const auto& entry : portsDelta) { auto newPort = entry.getNew(); if (newPort) { auto platformPort = getPort(newPort->getID()); if (platformPort->supportsTransceiver()) { changedPorts[newPort->getID()] = platformPort->toThrift(newPort); } } } qsfpCache_->portsChanged(changedPorts); for (const auto& entry : portsDelta) { auto newPort = entry.getNew(); if (newPort) { // clear cached port profile config that depends on transceiver info auto platformPort = getPort(newPort->getID()); platformPort->clearCachedProfileConfig(); } } } void WedgePlatform::updatePorts(const StateDelta& delta) { for (const auto& entry : delta.getPortsDelta()) { const auto newPort = entry.getNew(); if (newPort) { getPort(newPort->getID())->portChanged(newPort); } } } HwSwitch* WedgePlatform::getHwSwitch() const { return hw_.get(); } string WedgePlatform::getVolatileStateDir() const { return FLAGS_volatile_state_dir; } string WedgePlatform::getPersistentStateDir() const { return FLAGS_persistent_state_dir; } void WedgePlatform::onUnitCreate(int unit) { warmBootHelper_ = std::make_unique<BcmWarmBootHelper>(unit, getWarmBootDir()); } void WedgePlatform::onUnitAttach(int /*unit*/) {} void WedgePlatform::preWarmbootStateApplied() { // Update QsfpCache with the existing ports QsfpCache::PortMapThrift changedPorts; for (const auto& entry : *portMapping_) { // As some platform allows add/remove port at the first time applying the // config, we should skip those ports which doesn't exist in hw. auto bcmPortIf = hw_->getPortTable()->getBcmPortIf(entry.first); if (!bcmPortIf) { XLOG(WARNING) << "Port:" << entry.first << " is not in hw port table."; continue; } if (entry.second->supportsTransceiver()) { PortStatus s; *s.enabled() = bcmPortIf->isEnabled(); *s.up() = bcmPortIf->isUp(); *s.speedMbps() = static_cast<int>(bcmPortIf->getSpeed()); s.transceiverIdx() = entry.second->getTransceiverMapping(); changedPorts[entry.first] = s; } } XLOG(INFO) << "[preWarmbootStateApplied]: Will update " << changedPorts.size() << " ports to qsfp cache."; qsfpCache_->portsChanged(changedPorts); } std::unique_ptr<BaseWedgeI2CBus> WedgePlatform::getI2CBus() { return make_unique<WedgeI2CBus>(); } TransceiverIdxThrift WedgePlatform::getPortMapping( PortID portId, cfg::PortSpeed /* speed */) const { return getPort(portId)->getTransceiverMapping(); } WedgePort* WedgePlatform::getPort(PortID id) const { return portMapping_->getPort(id); } std::vector<WedgePort*> WedgePlatform::getPortsByTransceiverID( TransceiverID id) const { return portMapping_->getPortsByTransceiverID(id); } PlatformPort* WedgePlatform::getPlatformPort(const PortID port) const { return getPort(port); } std::map<std::string, std::string> WedgePlatform::loadConfig() { auto cfg = config(); if (cfg) { return *cfg->thrift.platform()->chip()->get_bcm().config(); } return BcmConfig::loadDefaultConfig(); } std::string WedgePlatform::loadYamlConfig() { auto cfg = config(); if (!cfg) { // TODO(josep5wu) Need to revisit whether we should generate a default // yaml config just like WedgePlatform::loadConfig() throw FbossError("Failed to get agent config"); } if (auto yamlConfig = cfg->thrift.platform()->chip()->get_bcm().yamlConfig()) { return *yamlConfig; } throw FbossError("Failed to get bcm yaml config from agent config"); } } // namespace facebook::fboss