fsm/src/fm10k/IES.cpp
DataHoarder 704df5b09d
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
Implement data-driven YAML switch/port/vlan configuration
Implemented extra missing fields, added VPD hash match

Add extra configuration required for external port tagging, maybe do it via config
2021-11-13 00:18:13 +01:00

465 lines
12 KiB
C++

#include "IES.h"
#include <unordered_map>
#include <sys/param.h>
#include <fstream>
#include "IES_SDK.h"
#include "IES_CONFIGURATIONS.h"
namespace FM10K{
namespace IES_Static{
static fm_semaphore semaphore;
static fm_int sw = 0;
}
}
std::unique_ptr<FM10K::IES> FM10K::IES::instance = nullptr;
bool FM10K::IES::init() {
if(m_initialized){ //TODO: override
return true;
}
if(!writePlatformConfiguration()){
std::abort();
}
//Override platform configuration for fmInitialize()
//set FM_LIBERTY_TRAIL_CONFIG_FILE to NVM_NAME ("NVM") to load config from Non-Volatile Memory of FM10K
//can also set FM_API_ATTR_FILE to override, local_attributes.cfg
//other env FM_API_SHM_KEY, INSTRUMENT_LOG_FILE
//it also loads "fm_api_attributes.cfg" by default for current working directory
if(setenv("FM_LIBERTY_TRAIL_CONFIG_FILE", getPlatformConfigurationPath().c_str(), true) != 0){
std::abort();
}
//Temporarily switch cwd
char tempcwd[MAXPATHLEN];
if(getcwd(tempcwd, sizeof(tempcwd)) == nullptr){
std::abort();
}
if(chdir(getTempPath().c_str()) != 0){
std::abort();
}
if(fmOSInitialize() != FM_OK){
std::abort();
}
/*
if(fmSetLoggingType(FM_LOG_TYPE_CONSOLE, 0, nullptr) != FM_OK){
std::abort();
}*/
if(fmSetLoggingVerbosity(FM_LOG_VERBOSITY_DEFAULT | FM_LOG_VERBOSITY_FILE) != FM_OK){
std::abort();
}
//if(fmEnableLoggingLevel(FM_LOG_LEVEL_ALL_VERBOSE) != FM_OK){
/*
if(fmEnableLoggingLevel(FM_LOG_LEVEL_ALL) != FM_OK){
std::abort();
}
*/
//if(fmEnableLoggingCategory(FM_LOG_CAT_ALL) != FM_OK){
//must remove "api.platform.lib.config.debug"
/*
if(fmSetLoggingFilter(FM_LOG_CAT_SWITCH | FM_LOG_CAT_PLATFORM, FM_LOG_LEVEL_ALL_VERBOSE,
nullptr, nullptr) != FM_OK){
std::abort();
}
*/
if(fmCreateSemaphore("seq", FM_SEM_BINARY, &IES_Static::semaphore, 0) != FM_OK){
std::abort();
}
if(fmInitialize(eventHandler) != FM_OK){
std::abort();
}
fm_timestamp wait = {3, 0};
fmCaptureSemaphore(&IES_Static::semaphore, &wait);
if(fmSetSwitchState(IES_Static::sw, true) != FM_OK){
std::abort();
}
//Restore cwd
if(chdir(tempcwd) != 0){
std::abort();
}
m_initialized = true;
return true;
}
void FM10K::IES::eventHandler(int event, int sw, void *ptr) {
if(!instance){
return;
}
switch (event) {
case FM_EVENT_SWITCH_INSERTED:
getInstance().handleSwitchInsertedEvent(sw);
break;
case FM_EVENT_PORT:
if(ptr){
getInstance().handlePortEvent(sw, *static_cast<fm_eventPort*>(ptr));
}
break;
case FM_EVENT_PKT_RECV:
printf("packet received\n");
break;
}
}
FM10K::IES &FM10K::IES::getInstance() {
if(!instance){
instance = std::unique_ptr<IES>(new IES());
}
return *instance;
}
void FM10K::IES::handleSwitchInsertedEvent(int sw) {
printf("Switch #%d inserted!\n", sw);
if (sw == IES_Static::sw){
fmReleaseSemaphore(&IES_Static::semaphore);
}
}
void FM10K::IES::handlePortEvent(int sw, _fm_eventPort& portEvent) {
printf("port event: port %d is %s\n", portEvent.port, (portEvent.linkStatus ? "up" : "down"));
}
bool FM10K::IES::replaceConfigEntry(const std::string &key, FM10K::IES::TlvType type, const std::string &value) {
if(m_initialized){
return false;
}
for(auto& e : m_configuration){
if(e.first == key){
e.second = {type, value};
return true;
}
}
m_configuration.push_back({key, {type, value}});
return true;
}
bool FM10K::IES::addConfigEntry(const std::string &key, FM10K::IES::TlvType type, const std::string &value) {
if(m_initialized){
return false;
}
for(auto& e : m_configuration){
if(e.first == key){
return false;
}
}
m_configuration.push_back({key, {type, value}});
return true;
}
bool FM10K::IES::addConfigEntry(const std::string &key, const std::string &value) {
return addConfigEntry(key, TlvType::Text, value);
}
bool FM10K::IES::addConfigEntry(const std::string &key, int32_t value) {
return addConfigEntry(key, TlvType::Integer, std::to_string(value));
}
bool FM10K::IES::addConfigEntry(const std::string &key, uint32_t value) {
return addConfigEntry(key, TlvType::UnsignedInteger, std::to_string(value));
}
bool FM10K::IES::addConfigEntry(const std::string &key, uint64_t value) {
return addConfigEntry(key, TlvType::UnsignedInteger64, std::to_string(value));
}
bool FM10K::IES::addConfigEntry(const std::string &key, bool value) {
return addConfigEntry(key, TlvType::Boolean, value ? "true" : "false");
}
std::string FM10K::IES::getPlatformConfiguration() const {
std::string output;
output.reserve(1024 * 8); //Reserve 8 KiB by default
output += "# Autogenerated file. Do not edit, changes WILL NOT be preserved.\n\n";
for(auto& it : m_configuration){
if(it.second.first == TlvType::Null){
continue;
}
output += it.first;
output += " ";
switch (it.second.first) {
case TlvType::Text:
output += "text";
break;
case TlvType::Integer:
case TlvType::UnsignedInteger:
case TlvType::UnsignedInteger64:
output += "int";
break;
case TlvType::Boolean:
output += "bool";
break;
case TlvType::Null:
break;
}
output += " ";
output += it.second.second;
output += "\n";
}
return output;
}
bool FM10K::IES::loadKnownConfiguration(const std::string &key) {
if(IES_Static::knownConfigurations.find(key) == IES_Static::knownConfigurations.end()){
return false;
}
for(auto& it : IES_Static::knownConfigurations.at(key)){
if(!addConfigEntry(it.first, it.second.first, it.second.second)){
return false;
}
}
return true;
}
FM10K::IES::~IES() {
if(!m_tempPath.empty()){
remove((m_tempPath + "/fm_platform_attributes.cfg").c_str());
rmdir(m_tempPath.c_str());
m_tempPath.clear();
}
teardown();
}
const std::string &FM10K::IES::getTempPath() {
if(m_tempPath.empty()){
const char * const tmplt = "/tmp/fsmd_XXXXXX";
char buffer[MAXPATHLEN] = {0};
strncpy(buffer, tmplt, strlen(tmplt));
if(mkdtemp(buffer) == nullptr){
std::abort();
}
m_tempPath = buffer;
}
return m_tempPath;
}
bool FM10K::IES::writePlatformConfiguration() {
std::ofstream f;
f.open(getPlatformConfigurationPath(), std::ios::out | std::ios::binary | std::ios::trunc);
if(f.fail()){
return false;
}
f << getPlatformConfiguration();
if(f.fail()){
return false;
}
f.close();
return true;
}
std::string FM10K::IES::getPlatformConfigurationPath() {
return getTempPath() + "/fm_platform_attributes.cfg";
}
void FM10K::IES::teardown() {
if(m_initialized){
fmTerminate();
m_initialized = false;
}
}
template<typename T>
void FM10K::IES::fmSetVlanAttribute(uint16_t vlan, int attribute, T value) const {
auto status = ::fmSetVlanAttribute(IES_Static::sw, vlan, attribute, &value);
if(status != FM_OK){
throw IESException(status);
}
}
template<typename T>
void FM10K::IES::fmSetPortAttribute(int port, int attribute, T value) const {
auto status = ::fmSetPortAttribute(IES_Static::sw, port, attribute, &value);
if(status != FM_OK){
throw IESException(status);
}
}
template<typename T>
void FM10K::IES::fmSetSwitchAttribute(int attribute, T value) const {
auto status = ::fmSetSwitchAttribute(IES_Static::sw, attribute, &value);
if(status != FM_OK){
throw IESException(status);
}
}
template<typename T>
T FM10K::IES::fmGetSwitchAttribute(int attribute) const {
T parameter{};
auto status = ::fmGetSwitchAttribute(IES_Static::sw, attribute, &parameter);
if(status != FM_OK){
throw IESException(status);
}
return parameter;
}
struct _fm_switchInfo FM10K::IES::fmGetSwitchInfo() const {
fm_switchInfo info{};
auto status = ::fmGetSwitchInfo(IES_Static::sw, &info);
if(status != FM_OK){
throw IESException(status);
}
return info;
}
void FM10K::IES::fmSetPortState(int port, int mode, int submode) const {
auto status = ::fmSetPortState(IES_Static::sw, port, mode, submode);
if(status != FM_OK){
throw IESException(status);
}
}
void FM10K::IES::fmCreateVlan(uint16_t vlan) const {
auto status = ::fmCreateVlan(IES_Static::sw, vlan);
if(status != FM_OK){
throw IESException(status);
}
}
void FM10K::IES::fmAddVlanPort(uint16_t vlan, int port, bool tagVlan) const {
auto status = ::fmAddVlanPort(IES_Static::sw, vlan, port, tagVlan);
if(status != FM_OK){
throw IESException(status);
}
}
void FM10K::IES::fmSetVlanPortState(uint16_t vlan, int port, int state) const {
auto status = ::fmSetVlanPortState(IES_Static::sw, vlan, port, state);
if(status != FM_OK){
throw IESException(status);
}
}
template<typename T>
T FM10K::IES::fmGetPortAttribute(int port, int attribute) const {
T value{};
auto status = ::fmGetPortAttribute(IES_Static::sw, port, attribute, &value);
if(status != FM_OK){
throw IESException(status);
}
return value;
}
template<typename T>
T FM10K::IES::fmGetVlanAttribute(uint16_t vlan, int attribute) const {
T value{};
auto status = ::fmGetVlanAttribute(IES_Static::sw, vlan, attribute, &value);
if(status != FM_OK){
throw IESException(status);
}
return value;
}
bool FM10K::IES::fmIsPciePort(int port) const {
fm_bool value{};
auto status = ::fmIsPciePort(IES_Static::sw, port, &value);
if(status != FM_OK){
throw IESException(status);
}
return value;
}
bool FM10K::IES::fmIsSpecialPort(int port) const {
fm_bool value{};
auto status = ::fmIsSpecialPort(IES_Static::sw, port, &value);
if(status != FM_OK){
throw IESException(status);
}
return value;
}
bool FM10K::IES::fmIsEplPort(int port) const {
fm_bool value{};
auto status = ::fmIsEplPort(IES_Static::sw, port, &value);
if(status != FM_OK){
throw IESException(status);
}
return value;
}
void FM10K::IES::iteratePorts(const std::function<void(int logicalPort, int physicalPort, int cpi, bool isInternalPort, bool isPCIePort, bool isSpecialPort, bool isEplPort, bool isCpuPort)>& callback) const {
auto swInfo = fmGetSwitchInfo();
fm_int cpuPort;
auto err = fmGetCpuPort(IES_Static::sw, &cpuPort);
if(err != FM_OK){
std::abort();
}
for(fm_int cpi = 0; cpi < swInfo.numCardPorts; ++cpi){
fm_int logicalPort;
fm_int physicalPort;
if(::fmMapCardinalPort(IES_Static::sw, cpi, &logicalPort, &physicalPort) != FM_OK){
std::abort();
}
bool isInternalPort;
try{
isInternalPort = fmGetPortAttribute<fm_bool>(logicalPort, FM_PORT_INTERNAL);
}catch (const IESException& e){
continue;
}
callback(logicalPort, physicalPort, cpi, isInternalPort, fmIsPciePort(logicalPort), fmIsSpecialPort(logicalPort), fmIsEplPort(logicalPort), cpuPort == logicalPort);
}
}
int FM10K::IES::fmGetSwitch() const {
return IES_Static::sw;
}
FM10K::IES::IES() = default;
IESException::IESException(int status) : m_msg(fmErrorMsg(status)) {
}
#define CREATE_ATTRIBUTE_TYPE(T) \
template void FM10K::IES::fmSetVlanAttribute(uint16_t vlan, int attribute, T value) const; \
template T FM10K::IES::fmGetVlanAttribute(uint16_t vlan, int attribute) const; \
template void FM10K::IES::fmSetPortAttribute(int port, int attribute, T value) const; \
template T FM10K::IES::fmGetPortAttribute(int port, int attribute) const; \
template void FM10K::IES::fmSetSwitchAttribute(int attribute, T value) const; \
template T FM10K::IES::fmGetSwitchAttribute(int attribute) const;
CREATE_ATTRIBUTE_TYPE(bool)
CREATE_ATTRIBUTE_TYPE(fm_int)
CREATE_ATTRIBUTE_TYPE(fm_uint)
CREATE_ATTRIBUTE_TYPE(fm_macaddr)