fboss/agent/Platform.h (126 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.
*
*/
#pragma once
#include <folly/Conv.h>
#include <folly/MacAddress.h>
#include <folly/io/async/EventBase.h>
#include <memory>
#include <unordered_map>
#include "fboss/agent/PlatformPort.h"
#include "fboss/agent/if/gen-cpp2/ctrl_types.h"
#include "fboss/agent/platforms/common/PlatformMapping.h"
#include "fboss/agent/types.h"
#include "fboss/lib/phy/gen-cpp2/phy_types.h"
DECLARE_bool(skip_xphy_programming);
namespace facebook::fboss {
class AgentConfig;
class HwSwitch;
class SwSwitch;
class ThriftHandler;
struct ProductInfo;
class HwAsic;
class PlatformProductInfo;
class QsfpCache;
enum class PlatformMode : char;
class PhyInterfaceHandler;
/*
* Platform represents a specific switch/router platform.
*
* Note that Platform is somewhat similar to the HwSwitch class--both contain
* hardware-specific details. However, HwSwitch contains data only about the
* switching logic, while Platform contains all platform specific information,
* beyond just the switching logic. The Platform class itself isn't involved
* in switching, it simply knows what type of HwSwitch to instantiate for this
* platform.
*
* In general, multiple platforms may share the same HwSwitch implementation.
* For instance, the BcmSwitch class is a HwSwitch implementation for systems
* based on a single Broadcom ASIC. Any platform with a single Broadcom ASIC
* may use BcmSwitch, but they will likely each have their own Platform
* implementation.
*/
class Platform {
public:
explicit Platform(
std::unique_ptr<PlatformProductInfo> productInfo,
std::unique_ptr<PlatformMapping> platformMapping,
folly::MacAddress localMac);
virtual ~Platform();
/*
* Initialize this platform. We use a two-phase initialization
* scheme since we often need fine grained control of when to
* initialized the platform.
*
* The platform should also store an owning reference of the config
* passed in. Passing it in through init makes it possible to
* control platform initialization using the same config mechanism
* as other parts of the agent.
*/
void init(std::unique_ptr<AgentConfig> config, uint32_t hwFeaturesDesired);
/*
* Allows the platorm to run any necessary cleanup steps like
* stopping threads.
*/
virtual void stop() = 0;
/*
* Two ways to get the configuration of the switch. config() will
* pull current running config, reload( ) will also reload the
* latest config from the default source for this platform before
* returning.
*/
const AgentConfig* config();
const AgentConfig* reloadConfig();
void setConfig(std::unique_ptr<AgentConfig> config);
const std::map<int32_t, cfg::PlatformPortEntry>& getPlatformPorts() const;
/*
* Get supported port speed profile config based on
* PlatformPortProfileConfigMatcher
* Return std::nullopt if the platform doesn't match profile.
*/
virtual const std::optional<phy::PortProfileConfig> getPortProfileConfig(
PlatformPortProfileConfigMatcher profileMatcher) const;
/*
* Get supported data plane phy chip based on chip name.
* Return std::nullopt if the platform doesn't support such phy chip.
*/
const std::optional<phy::DataPlanePhyChip> getDataPlanePhyChip(
std::string chipName) const;
const std::map<std::string, phy::DataPlanePhyChip>& getDataPlanePhyChips()
const;
/*
* Get port max speed based on the platform rather than hw switch.
*/
cfg::PortSpeed getPortMaxSpeed(PortID portID) const;
/*
* Get the HwSwitch for this platform.
*
* The HwSwitch object returned should be owned by the Platform, and must
* remain valid for the lifetime of the Platform object.
*/
virtual HwSwitch* getHwSwitch() const = 0;
/*
* Get the product information
*/
void getProductInfo(ProductInfo& info);
bool isProductInfoExist() {
if (!productInfo_) {
return false;
}
return true;
}
/*
* Get the product mode
*/
PlatformMode getMode() const;
/*
* preHwInitialized() will be called before HwSwitch object has been
* initialized. Platform-specific initialization that requires setup before
* HwSwitch creation can be performed here.
*/
virtual void preHwInitialized() {}
/*
* onHwInitialized() will be called once the HwSwitch object has been
* initialized. Platform-specific initialization that requires access to the
* HwSwitch can be performed here.
*/
virtual void onHwInitialized(SwSwitch* sw) = 0;
/*
* onInitialConfigApplied() will be called after the initial
* configuration has been applied. Platform-specific initialization
* that needs to happen after this can be performed here.
*/
virtual void onInitialConfigApplied(SwSwitch* sw) = 0;
/*
* Create the ThriftHandler.
*
* This will be invoked by fbossMain() during the initialization process.
*/
virtual std::unique_ptr<ThriftHandler> createHandler(SwSwitch* sw) = 0;
/*
* Get the local MAC address for the switch.
*
* This method must be thread safe. It may be called simultaneously from
* various different threads.
* TODO(joseph5wu) Will use private const localMac_ directly
*/
folly::MacAddress getLocalMac() const {
return localMac_;
}
/*
* Get the path to a directory where persistent state can be stored.
*
* Files written to this directory should be preserved across system reboots.
*/
virtual std::string getPersistentStateDir() const = 0;
/*
* Get the path to a directory where volatile state can be stored.
*
* Files written to this directory should be preserved across controller
* restarts, but must be removed across system restarts.
*
* For instance, these files could be stored in a ramdisk. Alternatively,
* these could be stored in persistent storage with an init script that
* empties the directory on reboot.
*/
virtual std::string getVolatileStateDir() const = 0;
/*
* Get the directory where we will dump info when there is a crash.
*
* The directory is in persistent storage.
*/
std::string getCrashInfoDir() const {
return getPersistentStateDir() + "/crash";
}
/*
* Directory where we store info about state updates that led to a crash
*/
std::string getCrashBadStateUpdateDir() const {
return getCrashInfoDir() + "/bad_update";
}
std::string getCrashBadStateUpdateOldStateFile() const {
return getCrashBadStateUpdateDir() + "/old_state";
}
std::string getCrashBadStateUpdateNewStateFile() const {
return getCrashBadStateUpdateDir() + "/new_state";
}
/*
* Get location we dump the running config of the switch
*/
std::string getRunningConfigDumpFile() const {
return getPersistentStateDir() + "/running-agent.conf";
}
/*
* Get the directory where warm boot state is stored.
*/
std::string getWarmBootDir() const {
return getVolatileStateDir() + "/warm_boot";
}
/*
* Get filename for where we dump hw state on crash
*/
std::string getCrashHwStateFile() const;
/*
* Get filename for where we dump switch state on crash
*/
std::string getCrashSwitchStateFile() const;
/*
* For a specific logical port, return the transceiver and channel
* it represents if available
*/
virtual TransceiverIdxThrift getPortMapping(PortID port, cfg::PortSpeed speed)
const = 0;
virtual PlatformPort* getPlatformPort(PortID port) const = 0;
virtual HwAsic* getAsic() const = 0;
/*
* initPorts() will be called during port initialization.
*/
virtual void initPorts() = 0;
virtual QsfpCache* getQsfpCache() const = 0;
virtual bool supportsAddRemovePort() const {
return false;
}
const PlatformMapping* getPlatformMapping() const {
return platformMapping_.get();
}
/*
* The override transceiver map functions are only used for testing
*/
void setOverrideTransceiverInfo(
const TransceiverInfo& overrideTransceiverInfo);
std::optional<TransceiverInfo> getOverrideTransceiverInfo(PortID port) const;
std::optional<std::unordered_map<TransceiverID, TransceiverInfo>>
getOverrideTransceiverInfos() const;
int getLaneCount(cfg::PortProfileID profile) const;
// Whether or not we need the Transceiver spec when programming ports.
// currently we only use this on yamp
virtual bool needTransceiverInfo() const {
return false;
}
virtual uint32_t getMMUCellBytes() const;
virtual PhyInterfaceHandler* getPhyInterfaceHandler() = 0;
virtual uint64_t getIntrCount() {
return 0;
}
virtual uint64_t getIntrTimeoutCount() {
return 0;
}
virtual void setIntrTimeout([[maybe_unused]] int intrTimeout) {}
virtual uint64_t getIntrTimeout() {
return 0;
}
private:
/*
* Subclasses can override this to do custom initialization. This is
* called from init() and will be invoked before trying to
* initialize SwSwitch or other objects. Usually this is where
* vendor-specific APIs are instantiated and where a platform
* creates the HwSwitch instance it must serve back to SwSwitch.
*/
virtual void initImpl(uint32_t hwFeaturesDesired) = 0;
std::unique_ptr<AgentConfig> config_;
// Forbidden copy constructor and assignment operator
Platform(Platform const&) = delete;
Platform& operator=(Platform const&) = delete;
const std::unique_ptr<PlatformProductInfo> productInfo_;
const std::unique_ptr<PlatformMapping> platformMapping_;
const folly::MacAddress localMac_;
// The map of override version of TransceiverInfo.
// This is to be used only for HwTests under test environment,
// qsfp may be unavailable and this override version is to mock possible
// transceiver info data qsfp may returns
std::optional<std::unordered_map<TransceiverID, TransceiverInfo>>
overrideTransceiverInfos_;
};
} // namespace facebook::fboss