DataHoarder
704df5b09d
Implemented extra missing fields, added VPD hash match Add extra configuration required for external port tagging, maybe do it via config
834 lines
36 KiB
C++
834 lines
36 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},
|
|
};
|
|
|
|
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, 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 == "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_seq()){
|
|
|
|
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;
|
|
}
|