DataHoarder
704df5b09d
Implemented extra missing fields, added VPD hash match Add extra configuration required for external port tagging, maybe do it via config
465 lines
12 KiB
C++
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, ¶meter);
|
|
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) |