fsm/src/fm10k/FM10K.cpp
DataHoarder 6472e5e412
All checks were successful
continuous-integration/drone/push Build is passing
Fix switch configuration setting
2021-11-16 16:26:33 +01:00

844 lines
37 KiB
C++

#include "FM10K.h"
#include "registers/Register.h"
#include "IES.h"
#include "device/PCIEDevice.h"
#include <chrono>
#include <thread>
#include <iostream>
#include "ryml.hpp"
#include "c4/std/string.hpp"
#include "IES_SDK.h"
FM10K::FM10K::FM10K(std::unique_ptr<Device> device) : m_device(std::move(device)) {
if(valid()){
auto vpd = mapRegister<registers::MGMT::VITAL_PRODUCT_DATA>();
auto chipVersion = mapRegister<registers::MGMT::CHIP_VERSION>();
auto fuseData = mapRegister<registers::MGMT::FUSE_DATA_0>();
m_hwInfo = {
static_cast<HardwareInformation::Family>(vpd->fields.PartNumber),
static_cast<HardwareInformation::Model>(fuseData->fields.SKU),
static_cast<HardwareInformation::ChipVersion>(chipVersion->fields.Version),
};
}
}
const FM10K::FM10K::HardwareInformation& FM10K::FM10K::getHardwareInformation() const {
return m_hwInfo;
}
std::string FM10K::FM10K::getHardwareInformationString() const {
auto& info = getHardwareInformation();
std::string s;
s.reserve(2);
if(info.family != HardwareInformation::Family::FM10000){
return "unknown";
}
switch (info.model) {
default:
s += "FM10000-unknown";
break;
case HardwareInformation::Model::FM10840:
s += "FM10840";
break;
case HardwareInformation::Model::FM10420:
s += "FM10420";
break;
case HardwareInformation::Model::FM10824:
s += "FM10824";
break;
case HardwareInformation::Model::FM10064:
s += "FM10064";
break;
case HardwareInformation::Model::FM10036:
s += "FM10036";
break;
}
switch (info.chipVersion) {
default:
s += "_unknown";
break;
case HardwareInformation::ChipVersion::A0:
s += "_A0";
break;
case HardwareInformation::ChipVersion::B0:
s += "_B0";
break;
}
return s;
}
/*
bool FM10K::FM10K::initializationSequence() const {
if(mapRegister<registers::MGMT::SOFT_RESET>()->fields.ColdReset){
//Not yet initialized from cold reset
return false;
}
if(mapRegister<registers::MGMT::SOFT_RESET>()->fields.SwitchReady == 1){
return true; //Already initialized
}
{
//5.4.3.1 Clear Switch Memories
//this needs to be done before step 19
//All BIST-accessible memories in the FM10000 are cleared as part of the recommended chip initialization
//(refer to Section 4.1.3.11), so the following step need not be repeated during the first switch
//initialization after bring-up.
auto bistCtrl = mapRegister<registers::MGMT::BIST_CTRL>();
bistCtrl->fields.BistMode_FABRIC = 1;
bistCtrl->fields.BistRun_FABRIC = 1;
wait(800); //Sleep 0.8ms
bistCtrl->fields.BistMode_FABRIC = 0;
bistCtrl->fields.BistRun_FABRIC = 0;
}
//Following from step 19 of Table 4-3 on 4.1.3.11 Initialization Sequence section
//Step 19
mapRegister<registers::MGMT::SOFT_RESET>()->fields.SwitchReset = 0;
wait_ns(100);
//Step 20
auto scanDataIn = mapRegister<registers::MGMT::SCAN_DATA_IN>();
registers::MGMT::SCAN_DATA_IN scanDataIn_copy{scanDataIn->value};
scanDataIn_copy.value = 0;
scanDataIn->fields.UpdateNodes = 1;
scanDataIn->fields.Passthru = 1;
scanDataIn->value = scanDataIn_copy.value;
//Step 22
//Step 21.1
for(uint32_t pep = 0; pep < PEP_COUNT; ++pep){
if(isPEPEnabled(pep)){
mapRegister<registers::PCIE_PF::PCIE_CTRL_EXT>(registers::PCIE_PF::PCIE_PF_OFFSET * pep)->fields.SwitchLoopback = 0;
}
}
//Step 21.2
for(uint32_t epl = 0; epl < EPL_COUNT; ++epl){
mapRegister<registers::EPL::EPL_CFG_A>(registers::EPL::EPL_OFFSET * epl)->fields.Active = 0xF;
}
//Step 21.3
mapRegister<registers::TE::TE_CFG>(registers::TE::TE_OFFSET * 0)->fields.SwitchLoopbackDisable = 1;
mapRegister<registers::TE::TE_CFG>(registers::TE::TE_OFFSET * 1)->fields.SwitchLoopbackDisable = 1;
//Step 22 (TODO add L2/L3 switching/routing here)
//Step 22.1
//TODO enable Congestion Management.
auto cmGlobalCfg = mapRegister<registers::CM_USAGE::CM_GLOBAL_CFG>();
//Step 22.2
//TODO Set CM_GLOBAL_WM as specified in Section 5.7.10.4, “Memory Usage Tracking and Watermarks Application”.
auto cmGlobalWm = mapRegister<registers::CM_USAGE::CM_GLOBAL_WM>();
//Figure 5-29 shows the global usage tracking and watermarks. Any frame received is counted in the
//CM_GLOBAL_USAGE. At the start of each frame, the CM_GLOBAL_USAGE is compared to the
//CM_GLOBAL_WM, which is used to limit the total number of frames allowed enter the device. Normally,
//the CM_GLOBAL_WM should be set to the maximum number of segments possible (24,576), minus the
//number of ports enabled x (numbers of segments per maximum size frame), minus 256 reserved
//segments.
//Step 22.3
mapRegister<registers::L2_LOOKUP_TCN::MA_TCN_IM>()->value = 0;
mapRegister<registers::HANDLER_TAIL::FH_TAIL_IM>()->fields.TCN = 0;
for(uint32_t pep = 0; pep < PEP_COUNT; ++pep){
if(isPEPEnabled(pep)){
mapRegister<registers::MGMT::INTERRUPT_MASK_PCIE>(pep * 2)->fields.FH_TAIL = 0;
}
}
//mapRegister<registers::MGMT::INTERRUPT_MASK_INT>()->fields.FH_TAIL = 0;
//mapRegister<registers::MGMT::INTERRUPT_MASK_FIBM>()->fields.FH_TAIL = 0;
//mapRegister<registers::MGMT::INTERRUPT_MASK_BSM>()->fields.FH_TAIL = 0;
//Step 23 (based on 5.4.3 Scheduler Initialization)
//5.4.3.1 Clear Switch Memories
for(uint32_t _class = 0; _class < registers::CM_USAGE::CLASS_ENTRIES; ++_class){
for(auto i = 0; i < 4; ++i){ //128-bit registers
setValue(registers::CM_USAGE::CM_EGRESS_PAUSE_COUNT__Address + 4 * _class + i, 0);
}
}
//5.4.3.2 Initialization of RXQ_MCAST List
for(auto i = 0; i < registers::SCHED::SCHED_RXQ_STORAGE_POINTERS__Entries; ++i){
auto pointer = mapRegister<registers::SCHED::SCHED_RXQ_STORAGE_POINTERS>(i);
pointer->fields.HeadPage = i;
pointer->fields.TailPage = i;
pointer->fields.HeadIdx = 0;
pointer->fields.TailIdx = 0;
pointer->fields.NextPage = 0;
}
for(auto i = 0; i < (1024 - registers::SCHED::SCHED_RXQ_STORAGE_POINTERS__Entries); ++i){
//TODO: check how compiler optimizes this
mapRegister<registers::SCHED::SCHED_RXQ_FREELIST_INIT>()->fields.Address = registers::SCHED::SCHED_RXQ_STORAGE_POINTERS__Entries + i;
}
//5.4.3.3 Initialization of TXQ List
//Note: All XXX_PERQ registers are indexed [0..383] which is equal to PORT*8+TC.
for(auto i = 0; i < registers::SCHED::SCHED_TXQ_HEAD_PERQ__Entries; ++i){
mapRegister<registers::SCHED::SCHED_TXQ_HEAD_PERQ>(i)->fields.Head = i;
mapRegister<registers::SCHED::SCHED_TXQ_TAIL0_PERQ>(i)->fields.Tail = i;
mapRegister<registers::SCHED::SCHED_TXQ_TAIL1_PERQ>(i)->fields.Tail = i;
}
for(auto i = 0; i < (24576 - registers::SCHED::SCHED_TXQ_HEAD_PERQ__Entries); ++i){
//TODO: check how compiler optimizes this
mapRegister<registers::SCHED::SCHED_TXQ_FREELIST_INIT>()->fields.Address = registers::SCHED::SCHED_TXQ_HEAD_PERQ__Entries + i;
}
//5.4.3.4 Initialization of FREE Segment List
for(auto i = 0; i < registers::SCHED::SCHED_SSCHED_RX_PERPORT__Entries; ++i){
mapRegister<registers::SCHED::SCHED_SSCHED_RX_PERPORT>(i)->fields.Next = i;
}
for(auto i = 0; i < (24576 - registers::SCHED::SCHED_SSCHED_RX_PERPORT__Entries); ++i){
//TODO: check how compiler optimizes this
mapRegister<registers::SCHED::SCHED_FREELIST_INIT>()->fields.Address = registers::SCHED::SCHED_SSCHED_RX_PERPORT__Entries + i;
}
//5.4.3.5 Initialization of Scheduler Polling Schedule
// The TX and RX schedule must be initialized according to the relative speed of each port.
//Step 24
mapRegister<registers::MGMT::LED_CFG>()->fields.LEDEnable = 1;
//Step 25 (based on 9.9.1 Initialization of System Time)
auto softReset = mapRegister<registers::MGMT::SOFT_RESET>();
auto prevActive = softReset->fields.PCIeActive;
softReset->fields.PCIeActive = mapRegister<registers::MGMT::DEVICE_CFG>()->fields.PCIeEnable;
//TODO: set SYSTIME_CFG for IEEE-1588 support
//PCIE_SYSTIME_CFG.Step = SYSTIME_CFG.Step
//TE_SYSTIME_CFG.Step = SYSTIME_CFG.Step
//TODO: set SYSTIME0
softReset->fields.PCIeActive = prevActive;
//De-assert the external IEEE1588_RESET_N pin (toggle from low to high) to initialize all SYSTIME
//registers to SYSTIME0 and begin counting time
//Step 26
mapRegister<registers::MGMT::SOFT_RESET>()->fields.SwitchReady = 1; //Allow traffic flow
return true;
}
*/
bool FM10K::FM10K::isPEPEnabled(uint8_t pep) const {
return (mapRegister<registers::MGMT::DEVICE_CFG>()->fields.PCIeEnable & (1 << pep)) > 0;
}
void FM10K::FM10K::wait(uint32_t microseconds) {
std::this_thread::sleep_for(std::chrono::microseconds(microseconds));
}
void FM10K::FM10K::wait_ns(uint32_t nanoseconds) {
std::this_thread::sleep_for(std::chrono::nanoseconds (nanoseconds));
}
std::string getYAMLString(c4::yml::NodeRef ref, const std::string& def = ""){
if(ref.valid() && !ref.is_seed() && ref.has_val()){
std::string s;
c4::from_chars(ref.val(), &s);
return s;
}
return def;
}
int32_t getYAMLInteger(c4::yml::NodeRef ref, int32_t def = 0){
if(ref.valid() && !ref.is_seed() && ref.has_val() && ref.val().is_integer()){
int32_t s;
if(atoi_first(ref.val(), &s)){
return s;
}
}
return def;
}
int64_t getYAMLInteger64(c4::yml::NodeRef ref, int64_t def = 0){
if(ref.valid() && !ref.is_seed() && ref.has_val() && ref.val().is_integer()){
int64_t s;
if(atoi_first(ref.val(), &s)){
return s;
}
}
return def;
}
uint32_t getYAMLUnsignedInteger(c4::yml::NodeRef ref, uint32_t def = 0){
if(ref.valid() && !ref.is_seed() && ref.has_val() && ref.val().is_integer()){
uint32_t s;
if(atou_first(ref.val(), &s)){
return s;
}
}
return def;
}
uint64_t getYAMLUnsignedInteger64(c4::yml::NodeRef ref, uint64_t def = 0){
if(ref.valid() && !ref.is_seed() && ref.has_val() && ref.val().is_integer()){
uint64_t s;
if(atou_first(ref.val(), &s)){
return s;
}
}
return def;
}
bool getYAMLBool(c4::yml::NodeRef ref, bool def = false){
if(ref.valid() && !ref.is_seed() && ref.has_val()){
if(ref.val() == "true"){
return true;
} else if(ref.val() == "false"){
return false;
}
}
return def;
}
static std::unordered_map<std::string, fm_int> STP_STATE_MAP = {
{"disabled", FM_STP_STATE_DISABLED},
{"listening", FM_STP_STATE_LISTENING},
{"learning", FM_STP_STATE_LEARNING},
{"forwarding", FM_STP_STATE_FORWARDING},
{"blocking", FM_STP_STATE_BLOCKING},
};
static std::unordered_map<std::string, fm_int> TAGGING_MODE_MAP = {
{"8021q", FM_PORT_TAGGING_8021Q},
{"8021ad_customer", FM_PORT_TAGGING_8021AD_CUST},
{"8021ad_provider", FM_PORT_TAGGING_8021AD_PROV},
{"pseudo1", FM_PORT_TAGGING_PSEUDO1},
{"pseudo2", FM_PORT_TAGGING_PSEUDO2},
};
static std::unordered_map<std::string, fm_int> ISL_FORMAT_MAP = {
{"none", FM_ISL_TAG_NONE},
{"f32", FM_ISL_TAG_F32},
{"f56", FM_ISL_TAG_F56},
{"f64", FM_ISL_TAG_F64},
{"f96", FM_ISL_TAG_F96},
{"other_32", FM_ISL_TAG_OTHER_32B},
{"other_64", FM_ISL_TAG_OTHER_64B},
{"other_96", FM_ISL_TAG_OTHER_96B},
};
static std::unordered_map<std::string, fm_int> LOOPBACK_MODE_MAP = {
{"off", FM_PORT_LOOPBACK_OFF},
{"rx2tx", FM_PORT_LOOPBACK_RX2TX},
{"tx2rx", FM_PORT_LOOPBACK_TX2RX},
};
static std::unordered_map<std::string, fm_int> PARSER_MODE_MAP = {
{"l2", FM_PORT_PARSER_STOP_AFTER_L2},
{"l3", FM_PORT_PARSER_STOP_AFTER_L3},
{"l4", FM_PORT_PARSER_STOP_AFTER_L4},
{"all", FM_PORT_PARSER_PARSE_ALL},
};
static std::unordered_map<std::string, fm_int> BFLOOD_MODE_MAP = {
{"forward_without_cpu", FM_PORT_BCAST_FWD_EXCPU},
{"forward", FM_PORT_BCAST_FWD},
{"discard", FM_PORT_BCAST_DISCARD},
{"trap", FM_PORT_BCAST_TRAP},
};
static std::unordered_map<std::string, fm_int> MFLOOD_MODE_MAP = {
{"forward_without_cpu", FM_PORT_MCAST_FWD_EXCPU},
{"forward", FM_PORT_MCAST_FWD},
{"discard", FM_PORT_MCAST_DISCARD},
{"trap", FM_PORT_MCAST_TRAP},
};
static std::unordered_map<std::string, fm_int> UFLOOD_MODE_MAP = {
{"forward_without_cpu", FM_PORT_UCAST_FWD_EXCPU},
{"forward", FM_PORT_UCAST_FWD},
{"discard", FM_PORT_UCAST_DISCARD},
{"trap", FM_PORT_UCAST_TRAP},
};
static std::unordered_map<std::string, fm_int> VLAN_LEARNING_MODE = {
{"independent", FM_VLAN_LEARNING_MODE_INDEPENDENT},
{"shared", FM_VLAN_LEARNING_MODE_SHARED}
};
static std::unordered_map<std::string, fm_int> STP_MODE = {
{"shared", FM_SPANNING_TREE_SHARED},
{"per_vlan", FM_SPANNING_TREE_PER_VLAN},
{"multiple", FM_SPANNING_TREE_MULTIPLE},
};
static std::unordered_map<std::string, fm_int> LAG_MODE = {
{"static", FM_MODE_STATIC},
{"dynamic", FM_MODE_DYNAMIC},
};
static std::unordered_map<std::string, fm_int> AUTONEG_MAP = {
{"none", FM_PORT_AUTONEG_NONE},
{"sgmii", FM_PORT_AUTONEG_SGMII},
{"clause37", FM_PORT_AUTONEG_CLAUSE_37},
{"clause73", FM_PORT_AUTONEG_CLAUSE_73},
};
fm_int getMapState(const std::string& k, const std::unordered_map<std::string, fm_int>& m){
assert(m.find(k) != m.end());
return m.at(k);
}
bool FM10K::FM10K::initialize(const ryml::Tree& tree) const {
auto& ies = IES::getInstance();
auto root = tree.rootref();
if(!root["platform"].is_seed() && root["platform"].is_map()){
if(!root["platform"]["configuration"]["preset"].is_seed()){
auto conf = getYAMLString(root["platform"]["configuration"]["preset"]);
std::cout << "Loading know configuration " << conf << std::endl;
if(!ies.loadKnownConfiguration(conf)){
return false;
}
}
if(!root["platform"]["configuration"]["entries"].is_seed() && root["platform"]["configuration"]["entries"].is_seq()){
for(auto e : root["platform"]["configuration"]["entries"]){
if(e.is_seq() && e.num_children() == 3){ //Conf mapping
auto key = getYAMLString(e[0]);
auto type = e[1];
auto value = getYAMLString(e[2]);
if(type == "text"){
ies.replaceConfigEntry(key, IES::TlvType::Text, value);
}else if(type == "int"){
ies.replaceConfigEntry(key, IES::TlvType::Integer, value);
}else if(type == "bool"){
ies.replaceConfigEntry(key, IES::TlvType::Boolean, value);
}else if(type == "null"){
ies.replaceConfigEntry(key, IES::TlvType::Null, value);
}else{
std::abort();
}
}
}
}
}
auto pcieDevice = dynamic_cast<PCIEDevice*>(m_device.get());
if(pcieDevice != nullptr){
ies.replaceConfigEntry("api.platform.config.switch.0.uioDevName", IES::TlvType::Null, "");
ies.replaceConfigEntry("api.platform.config.switch.0.resource4DevName", IES::TlvType::Text, pcieDevice->getDeviceEntry().getPath());
}else{
return false;
}
//TODO UIO support
//ies.addConfigEntry("api.platform.lib.config.debug", IES::TlvType::Text, "I2C_RW,I2C_MUX,DUMP_CFG");
//ies.addConfigEntry("api.debug.initLoggingCategories", IES::TlvType::Text, "FM_LOG_CAT_LOGGING|FM_LOG_CAT_LINK_STATE|FM_LOG_CAT_ALOS|FM_LOG_CAT_DEBUG|FM_LOG_CAT_PHY|FM_LOG_CAT_PLATFORM|FM_LOG_CAT_EVENT|FM_LOG_CAT_SWITCH|FM_LOG_CAT_MAILBOX|FM_LOG_CAT_PORT|FM_LOG_CAT_SERDES|FM_LOG_CAT_EVENT_INTR|FM_LOG_CAT_STATE_MACHINE|FM_LOG_CAT_GENERAL|FM_LOG_CAT_API|FM_LOG_CAT_PORT_AUTONEG");
if(ies.init()){
if(!root["vlans"].is_seed() && root["vlans"].is_seq()){
for(auto vlan : root["vlans"]){
if(!vlan.is_map()){
std::abort();
}
auto vid = getYAMLUnsignedInteger(vlan["id"], 0xFFFF);
if(vid == 0xFFFF){
std::abort();
}
std::cout << "Creating VLAN " << vid;
ies.fmCreateVlan(vid);
if(!vlan["attributes"].is_seed() && vlan["attributes"].is_map()){
for(auto attr : vlan["attributes"]){
std::string key;
c4::from_chars(attr.key(), &key);
if(key == "reflect"){
auto val = getYAMLBool(attr, true);
std::cout << " " << key << " = " << (val ? "true" : "false");
ies.fmSetVlanAttribute(vid, FM_VLAN_REFLECT, val);
}else if(key == "routable"){
auto val = getYAMLBool(attr, true);
std::cout << " " << key << " = " << (val ? "true" : "false");
ies.fmSetVlanAttribute(vid, FM_VLAN_ROUTABLE, val);
}
}
}
std::cout << std::endl;
}
}
if(!root["ports"].is_seed() && root["ports"].is_seq()){
auto ports = root["ports"];
auto applyPortSettings = [&ies](c4::yml::NodeRef portEntry, int logicalPort, int physicalPort, int cpi, bool isInternalPort, bool isPCIePort, bool isSpecialPort, bool isEplPort, bool isCpuPort){
if(!portEntry["internal"].is_seed()){
ies.fmSetPortAttribute(logicalPort, FM_PORT_INTERNAL, getYAMLBool(portEntry["internal"], false));
}
if(!portEntry["vlans"].is_seed() && portEntry["vlans"].is_seq()){
for (auto portVlan : portEntry["vlans"]) {
auto vid = getYAMLUnsignedInteger(portVlan["id"], 0xFFFF);
if(vid == 0xFFFF){
std::abort();
}
std::cout << "Add port " << logicalPort << " to vlan " << vid << std::endl;
ies.fmAddVlanPort(vid, logicalPort, !isPCIePort && getYAMLBool(portVlan["tag"], true));
ies.fmSetVlanPortState(vid, logicalPort, getMapState(getYAMLString(portVlan["stp"], "forwarding"), STP_STATE_MAP));
}
}
if(!portEntry["attributes"].is_seed() && portEntry["attributes"].is_map()){
for (auto attr : portEntry["attributes"]) {
std::string key;
c4::from_chars(attr.key(), &key);
if(key == "learning"){
ies.fmSetPortAttribute(logicalPort, FM_PORT_LEARNING, getYAMLBool(attr, !(isPCIePort || isSpecialPort)));
}else if(key == "learning"){
ies.fmSetPortAttribute(logicalPort, FM_PORT_MAX_FRAME_SIZE, getYAMLUnsignedInteger(attr, FM10000_PCIE_MAX_FRAME_SIZE));
}else if(key == "switch_priority"){
ies.fmSetPortAttribute(logicalPort, FM_PORT_DEF_SWPRI, getYAMLUnsignedInteger(attr, 0));
}else if(key == "routable"){
ies.fmSetPortAttribute(logicalPort, FM_PORT_ROUTABLE, getYAMLBool(attr, isSpecialPort));
}else if(key == "autonegotiation" && isEplPort){
ies.fmSetPortAttribute(logicalPort, FM_PORT_AUTONEG, getMapState(getYAMLString(attr, "none"), AUTONEG_MAP));
}else if (key == "tagging" && attr.is_map()){
for(auto attr2 : attr){
std::string key2;
c4::from_chars(attr2.key(), &key2);
if(key2 == "mode"){
ies.fmSetPortAttribute(logicalPort, FM_PORT_TAGGING_MODE, getMapState(getYAMLString(attr2), TAGGING_MODE_MAP));
}else if(key2 == "vid"){
ies.fmSetPortAttribute(logicalPort, FM_PORT_DEF_VLAN, getYAMLUnsignedInteger(attr2, 1));
}else if(key2 == "priority"){
ies.fmSetPortAttribute(logicalPort, FM_PORT_DEF_PRI, getYAMLUnsignedInteger(attr2, 0));
}else if(key2 == "vid2"){
ies.fmSetPortAttribute(logicalPort, FM_PORT_DEF_VLAN2, getYAMLUnsignedInteger(attr2, 1));
}else if(key2 == "priority2"){
ies.fmSetPortAttribute(logicalPort, FM_PORT_DEF_PRI2, getYAMLUnsignedInteger(attr2, 0));
}else if(key2 == "replace"){
ies.fmSetPortAttribute(logicalPort, FM_PORT_REPLACE_VLAN_FIELDS, getYAMLBool(attr2, false));
}else if(key2 == "cfi"){
ies.fmSetPortAttribute(logicalPort, FM_PORT_DEF_CFI, getYAMLUnsignedInteger(attr2, 0));
}else if(key2 == "dscp"){
ies.fmSetPortAttribute(logicalPort, FM_PORT_DEF_DSCP, getYAMLUnsignedInteger(attr2, 0));
}else if(key2 == "isl_format"){
ies.fmSetPortAttribute(logicalPort, FM_PORT_ISL_TAG_FORMAT, getMapState(getYAMLString(attr2, "none"), ISL_FORMAT_MAP));
}
}
}else if (key == "drop" && attr.is_map()){
for(auto attr2 : attr){
std::string key2;
c4::from_chars(attr2.key(), &key2);
if(key2 == "boundary_violation"){
ies.fmSetPortAttribute(logicalPort, FM_PORT_DROP_BV, getYAMLBool(attr2, false));
}else if(key2 == "untagged"){
ies.fmSetPortAttribute(logicalPort, FM_PORT_DROP_UNTAGGED, getYAMLBool(attr2, false));
}else if(key2 == "tagged"){
ies.fmSetPortAttribute(logicalPort, FM_PORT_DROP_TAGGED, getYAMLBool(attr2, false));
}
}
}else if (key == "loopback" && attr.is_map()){
for(auto attr2 : attr){
std::string key2;
c4::from_chars(attr2.key(), &key2);
if(key2 == "suppression"){
ies.fmSetPortAttribute(logicalPort, FM_PORT_LOOPBACK_SUPPRESSION, getYAMLBool(attr2, true));
}else if(key2 == "mode" && isEplPort){
ies.fmSetPortAttribute(logicalPort, FM_PORT_LOOPBACK, getMapState(getYAMLString(attr2, "off"), LOOPBACK_MODE_MAP));
}else if(key2 == "fabric"){
ies.fmSetPortAttribute(logicalPort, FM_PORT_FABRIC_LOOPBACK, getMapState(getYAMLString(attr2, "off"), LOOPBACK_MODE_MAP));
}
}
}else if (key == "parser" && attr.is_map()){
for(auto attr2 : attr){
std::string key2;
c4::from_chars(attr2.key(), &key2);
if(key2 == "first_vlan2"){
ies.fmSetPortAttribute(logicalPort, FM_PORT_PARSER_VLAN2_FIRST, getYAMLBool(attr2, false));
}else if(key2 == "first_vid2"){
ies.fmSetPortAttribute(logicalPort, FM_PORT_MODIFY_VID2_FIRST, getYAMLBool(attr2, false));
}else if(key2 == "mode"){
ies.fmSetPortAttribute(logicalPort, FM_PORT_PARSER, getMapState(getYAMLString(attr2, "l2"), PARSER_MODE_MAP));
}
}
}else if (key == "update" && attr.is_map()){
for(auto attr2 : attr){
std::string key2;
c4::from_chars(attr2.key(), &key2);
if(key2 == "ttl"){
ies.fmSetPortAttribute(logicalPort, FM_PORT_UPDATE_TTL, getYAMLBool(attr2, true));
}else if(key2 == "dscp"){
ies.fmSetPortAttribute(logicalPort, FM_PORT_UPDATE_DSCP, getYAMLBool(attr2, true));
}else if(key2 == "vlan_priority"){
ies.fmSetPortAttribute(logicalPort, FM_PORT_TXVPRI, getYAMLBool(attr2, false));
}else if(key2 == "vlan_priority2"){
ies.fmSetPortAttribute(logicalPort, FM_PORT_TXVPRI2, getYAMLBool(attr2, false));
}else if(key2 == "routed" && attr2.is_seq()){
fm_uint32 f = 0;
for(auto s : attr2){
if(s == "DMAC"){
f |= FM_PORT_ROUTED_FRAME_UPDATE_DMAC;
}else if(s == "SMAC"){
f |= FM_PORT_ROUTED_FRAME_UPDATE_SMAC;
}else if(s == "VLAN"){
f |= FM_PORT_ROUTED_FRAME_UPDATE_VLAN;
}
}
ies.fmSetPortAttribute(logicalPort, FM_PORT_ROUTED_FRAME_UPDATE_FIELDS, f);
}
}
}else if (key == "broadcast" && attr.is_map()){
for(auto attr2 : attr){
std::string key2;
c4::from_chars(attr2.key(), &key2);
if(key2 == "pruning"){
ies.fmSetPortAttribute(logicalPort, FM_PORT_BCAST_PRUNING, getYAMLBool(attr2, false));
}else if(key2 == "flooding"){
ies.fmSetPortAttribute(logicalPort, FM_PORT_BCAST_FLOODING, getMapState(getYAMLString(attr2, "forward_without_cpu"), BFLOOD_MODE_MAP));
}
}
}else if (key == "multicast" && attr.is_map()){
for(auto attr2 : attr){
std::string key2;
c4::from_chars(attr2.key(), &key2);
if(key2 == "pruning"){
ies.fmSetPortAttribute(logicalPort, FM_PORT_MCAST_PRUNING, getYAMLBool(attr2, false));
}else if(key2 == "flooding"){
ies.fmSetPortAttribute(logicalPort, FM_PORT_MCAST_FLOODING, getMapState(getYAMLString(attr2, "forward_without_cpu"), MFLOOD_MODE_MAP));
}
}
}else if (key == "unicast" && attr.is_map()){
for(auto attr2 : attr){
std::string key2;
c4::from_chars(attr2.key(), &key2);
if(key2 == "pruning"){
ies.fmSetPortAttribute(logicalPort, FM_PORT_UCAST_PRUNING, getYAMLBool(attr2, false));
}else if(key2 == "flooding"){
ies.fmSetPortAttribute(logicalPort, FM_PORT_UCAST_FLOODING, getMapState(getYAMLString(attr2, "forward_without_cpu"), UFLOOD_MODE_MAP));
}
}
}else if(key == "mask"){
auto switchInfo = ies.fmGetSwitchInfo();
fm_bitArray bitArray;
if(fmCreateBitArray(&bitArray, switchInfo.numCardPorts) != FM_OK){
std::abort();
}
if(attr.is_seq()){
for(auto b : attr){
fmSetBitArrayBit(&bitArray, getYAMLInteger(b), 1);
}
}else if(attr.val() == "-1"){
for(auto i = 0; i < switchInfo.numCardPorts; ++i){
if(i != logicalPort){
fmSetBitArrayBit(&bitArray, i, 1);
}
}
}
if(::fmSetPortAttribute(ies.fmGetSwitch(), logicalPort, FM_PORT_MASK_WIDE, &bitArray) != FM_OK){
std::abort();
}
fmDeleteBitArray(&bitArray);
}
}
}
};
ies.iteratePorts([&ies, &ports, &applyPortSettings](int logicalPort, int physicalPort, int cpi, bool isInternalPort, bool isPCIePort, bool isSpecialPort, bool isEplPort, bool isCpuPort){
std::cout << "port#" << logicalPort << " phys#" << physicalPort << " cpi#" << cpi
<< (isInternalPort ? " internal" : "")
<< (isPCIePort ? " pcie" : "")
<< (isSpecialPort ? " special" : "")
<< (isEplPort ? " epl" : "")
<< (isCpuPort ? " cpu" : "")
<< std::endl;
if(!isInternalPort){
ies.fmSetPortState(logicalPort, FM_PORT_STATE_UP, 0);
}
for(const auto& entryKind : std::vector<std::string>({"default", "eth", "pcie", "special", "internal", "cpu"})){
if(entryKind != "internal" && isInternalPort){
//Specifically disallow setting internal in "default"
continue;
}else if(entryKind == "eth" && !isEplPort){
continue;
}else if(entryKind == "pcie" && !isPCIePort){
continue;
}else if(entryKind == "special" && !isSpecialPort){
continue;
}else if(entryKind == "cpu" && !isCpuPort){
continue;
}
std::cout << "Applying " << entryKind << " settings" << std::endl;
for(auto portEntry : ports){
if(portEntry["port"].is_seq()){
for(auto e : portEntry["port"]){
if(e.val() == entryKind){
applyPortSettings(portEntry, logicalPort, physicalPort, cpi, isInternalPort, isPCIePort, isSpecialPort, isEplPort, isCpuPort);
}
}
}else if(portEntry["port"].val() == entryKind){
applyPortSettings(portEntry, logicalPort, physicalPort, cpi, isInternalPort, isPCIePort, isSpecialPort, isEplPort, isCpuPort);
}
}
}
for(auto portEntry : ports){
if(portEntry["port"].is_seq()){
for(auto e : portEntry["port"]){
if(e.val().is_integer() && getYAMLUnsignedInteger(e) == logicalPort){
applyPortSettings(portEntry, logicalPort, physicalPort, cpi, isInternalPort, isPCIePort, isSpecialPort, isEplPort, isCpuPort);
}
}
}else if(portEntry["port"].val().is_integer() && getYAMLUnsignedInteger(portEntry["port"]) == logicalPort){
std::cout << "Applying port# " << logicalPort << " settings" << std::endl;
applyPortSettings(portEntry, logicalPort, physicalPort, cpi, isInternalPort, isPCIePort, isSpecialPort, isEplPort, isCpuPort);
}
}
});
}
if(!root["switch"].is_seed() && root["switch"].is_map()){
if(!root["switch"]["attributes"].is_seed() && root["switch"]["attributes"].is_map()){
for(auto attr : root["switch"]["attributes"]){
std::string key;
c4::from_chars(attr.key(), &key);
if(key == "broadcast_flooding"){
ies.fmSetSwitchAttribute(FM_BCAST_FLOODING, getMapState(getYAMLString(attr, "forward_without_cpu"), BFLOOD_MODE_MAP));
}else if(key == "multicast_flooding"){
ies.fmSetSwitchAttribute(FM_MCAST_FLOODING, getMapState(getYAMLString(attr, "forward_without_cpu"), MFLOOD_MODE_MAP));
}else if(key == "unicast_flooding"){
ies.fmSetSwitchAttribute(FM_UCAST_FLOODING, getMapState(getYAMLString(attr, "forward_without_cpu"), UFLOOD_MODE_MAP));
}else if(key == "cpu_port"){
ies.fmSetSwitchAttribute(FM_REDIRECT_CPU_TRAFFIC, getYAMLInteger(attr));
}else if(key == "frame_aging_milliseconds"){
ies.fmSetSwitchAttribute(FM_FRAME_AGING_TIME_MSEC, getYAMLInteger(attr));
}else if (key == "vlan_learning" && attr.is_map()){
for(auto attr2 : attr){
std::string key2;
c4::from_chars(attr2.key(), &key2);
if(key2 == "vlan" && ies.fmGetSwitchAttribute<fm_int>(FM_VLAN_LEARNING_SHARED_VLAN) == FM_VLAN_LEARNING_MODE_SHARED){
ies.fmSetSwitchAttribute(FM_VLAN_LEARNING_SHARED_VLAN, getYAMLUnsignedInteger(attr2, 1));
}else if(key2 == "mode"){
ies.fmSetSwitchAttribute(FM_VLAN_LEARNING_MODE, getMapState(getYAMLString(attr2, "independent"), VLAN_LEARNING_MODE));
}
}
}else if (key == "lag" && attr.is_map()){
for(auto attr2 : attr){
std::string key2;
c4::from_chars(attr2.key(), &key2);
if(key2 == "mode"){
ies.fmSetSwitchAttribute(FM_LAG_MODE, getMapState(getYAMLString(attr2, "static"), LAG_MODE));
}else if(key2 == "pruning"){
ies.fmSetSwitchAttribute(FM_LAG_PRUNING, getYAMLBool(attr2, true));
}
}
}else if (key == "trap" && attr.is_map()){
for(auto attr2 : attr){
std::string key2;
c4::from_chars(attr2.key(), &key2);
if(key2 == "cpu_mac"){
ies.fmSetSwitchAttribute(FM_CPU_MAC, static_cast<fm_macaddr>(getYAMLUnsignedInteger64(attr2, 0x000000000000)));
}else if(key2 == "8021x"){
ies.fmSetSwitchAttribute(FM_TRAP_IEEE_8021X, getYAMLBool(attr2, true));
}else if(key2 == "bpdu"){
ies.fmSetSwitchAttribute(FM_TRAP_IEEE_BPDU, getYAMLBool(attr2, true));
}else if(key2 == "lacp"){
ies.fmSetSwitchAttribute(FM_TRAP_IEEE_LACP, getYAMLBool(attr2, true));
}else if(key2 == "garp"){
ies.fmSetSwitchAttribute(FM_TRAP_IEEE_GARP, getYAMLBool(attr2, true));
}else if(key2 == "mtu_violation"){
ies.fmSetSwitchAttribute(FM_TRAP_MTU_VIOLATIONS, getYAMLBool(attr2, true));
}
}
}else if(key == "stp_mode"){
ies.fmSetSwitchAttribute(FM_SPANNING_TREE_MODE, getMapState(getYAMLString(attr, "shared"), STP_MODE));
}
}
}
std::cout << std::endl;
}
std::cout << "Switch is UP, all ports are now enabled" << std::endl;
return true;
}
return false;
}