From 704df5b09d32031c926c7682e222816b6486b560 Mon Sep 17 00:00:00 2001 From: WeebDataHoarder <57538841+WeebDataHoarder@users.noreply.github.com> Date: Wed, 10 Nov 2021 19:32:29 +0100 Subject: [PATCH] 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 --- .drone.yml | 2 +- .gitignore | 2 +- .gitmodules | 9 + CMakeLists.txt | 43 ++- build-deps.sh | 42 +++ build-ies.sh | 20 -- config.example.yml | 288 ++++++++++++++++++ deps/argparse | 1 + deps/rapidyaml | 1 + deps/sha2 | 1 + src/device/PCIEDevice.cpp | 25 ++ src/device/PCIEDevice.h | 3 + src/fm10k/FM10K.cpp | 542 ++++++++++++++++++++++++++++++++- src/fm10k/FM10K.h | 6 +- src/fm10k/IES.cpp | 367 ++++++++++------------ src/fm10k/IES.h | 47 +++ src/fm10k/IES_CONFIGURATIONS.h | 331 +++++++++++++++++++- src/fsmd.cpp | 62 +++- 18 files changed, 1541 insertions(+), 251 deletions(-) create mode 100755 build-deps.sh delete mode 100755 build-ies.sh create mode 100644 config.example.yml create mode 160000 deps/argparse create mode 160000 deps/rapidyaml create mode 160000 deps/sha2 diff --git a/.drone.yml b/.drone.yml index 3278bc0..c8f14e1 100644 --- a/.drone.yml +++ b/.drone.yml @@ -18,6 +18,6 @@ steps: commands: - apt update - DEBIAN_FRONTEND=noninteractive apt install -y clang cmake autoconf automake libtool-bin - - ./build-ies.sh + - ./build-deps.sh - ./build.sh ... \ No newline at end of file diff --git a/.gitignore b/.gitignore index 018114a..dbd93d4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -/cmake-build-debug +/cmake-build-* /build .idea /deps/IES/build \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index b66982b..b12d2d9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,12 @@ [submodule "deps/IES"] path = deps/IES url = https://git.gammaspectra.live/FM10K/IES +[submodule "deps/argparse"] + path = deps/argparse + url = https://github.com/p-ranav/argparse +[submodule "deps/rapidyaml"] + path = deps/rapidyaml + url = https://github.com/biojppm/rapidyaml +[submodule "deps/sha2"] + path = deps/sha2 + url = https://github.com/ogay/sha2.git diff --git a/CMakeLists.txt b/CMakeLists.txt index f19d7b9..2c78559 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,29 +1,44 @@ cmake_minimum_required(VERSION 3.13) project(fsm) -set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-exceptions -frtti -D_FM_ARCH_64 -DFM_SUPPORT_FM10000 -D_GNU_SOURCE") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions -frtti -D_FM_ARCH_64 -DFM_SUPPORT_FM10000 -D_GNU_SOURCE") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fexceptions -fPIC -frtti -D_FM_ARCH_64 -DFM_SUPPORT_FM10000 -D_GNU_SOURCE") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions -fPIC -frtti -D_FM_ARCH_64 -DFM_SUPPORT_FM10000 -D_GNU_SOURCE") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_GLIBCXX_DEBUG") -set(CMAKE_LD_FLAGS "${CMAKE_LD_FLAGS} -Wl,--no-as-needed") set(CMAKE_INSTALL_RPATH "$ORIGIN") set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) -include_directories(src) +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif() -include_directories(deps/IES/build/include) -include_directories(deps/IES/build/include/alos) -include_directories(deps/IES/build/include/alos/linux) -include_directories(deps/IES/build/include/std/intel) -include_directories(deps/IES/build/include/common) -include_directories(deps/IES/build/include/platforms) -include_directories(deps/IES/build/include/platforms/libertyTrail) +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -ggdb -O0") +set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3") + +include_directories(src) find_library(libFocalpointSDK NAMES FocalpointSDK PATHS ${PROJECT_SOURCE_DIR}/deps/IES/build/lib NO_DEFAULT_PATH REQUIRED) find_library(libLTStdPlatform NAMES LTStdPlatform PATHS ${PROJECT_SOURCE_DIR}/deps/IES/build/lib NO_DEFAULT_PATH REQUIRED) +find_library(libryml NAMES ryml PATHS ${PROJECT_SOURCE_DIR}/deps/rapidyaml/install/lib NO_DEFAULT_PATH REQUIRED) -add_executable(fsmd src/fsmd.cpp src/device/PCIEDevice.cpp src/fm10k/FM10K.cpp src/fm10k/Functions.cpp src/fm10k/Port.cpp src/fm10k/IES.cpp) +add_executable(fsmd src/fsmd.cpp deps/sha2/sha2.c src/device/PCIEDevice.cpp src/fm10k/FM10K.cpp src/fm10k/Functions.cpp src/fm10k/Port.cpp src/fm10k/IES.cpp) add_executable(fsm src/fsm.cpp) -target_link_libraries(fsmd ${libFocalpointSDK} ${libLTStdPlatform} dl) \ No newline at end of file + +target_include_directories(fsmd PUBLIC + deps/IES/build/include + deps/IES/build/include/alos + deps/IES/build/include/alos/linux + deps/IES/build/include/std/intel + deps/IES/build/include/common + deps/IES/build/include/platforms + deps/IES/build/include/platforms/libertyTrail + deps/sha2 + deps/rapidyaml/install/include + deps/argparse/include + ) + +target_link_options(fsmd PRIVATE -static-libgcc -static-libstdc++ "LINKER:--as-needed") +target_link_libraries(fsmd "${libryml}" "${libFocalpointSDK}" "${libLTStdPlatform}" dl) diff --git a/build-deps.sh b/build-deps.sh new file mode 100755 index 0000000..89d3e13 --- /dev/null +++ b/build-deps.sh @@ -0,0 +1,42 @@ +#!/bin/bash +set -ex + +pushd "${0%/*}" + + +export CC=clang +export CXX=clang++ + +pushd deps +pushd IES +if [[ -d "build" ]]; then + rm -r build +fi +mkdir build +if command -v git &> /dev/null; then + git clean -f -d -x +fi +export CFLAGS="-ggdb -O0" +export CXXFLAGS="-ggdb -O0" +./autogen.sh +./configure --enable-shared --prefix "$(pwd)/build" +make clean +make -j$(nproc) +make install + +popd +pushd rapidyaml +if [[ -d "build" ]]; then + rm -r build +fi +if [[ -d "install" ]]; then + rm -r install +fi +mkdir build +mkdir install +pushd build +export CFLAGS="-D_GNU_SOURCE -ggdb -O2" +export CXXFLAGS="-D_GNU_SOURCE -ggdb -O2" +cmake .. -DRYML_BUILD_TESTS=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_CXX_STANDARD=17 -DCMAKE_INSTALL_PREFIX="$(pwd)/../install" +make -j$(nproc) +make install \ No newline at end of file diff --git a/build-ies.sh b/build-ies.sh deleted file mode 100755 index 0f98d65..0000000 --- a/build-ies.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -set -ex - -pushd "${0%/*}" - -pushd deps/IES -if [[ -d "build" ]]; then - rm -r build -fi -mkdir build -export CC=clang -export CXX=clang++ -export CFLAGS="-ggdb -O0" -export CXXFLAGS="-ggdb -O0" -git clean -f -d -x -./autogen.sh -./configure --enable-shared --prefix "$(pwd)/build" -make clean -make -j$(nproc) -make install \ No newline at end of file diff --git a/config.example.yml b/config.example.yml new file mode 100644 index 0000000..0860a97 --- /dev/null +++ b/config.example.yml @@ -0,0 +1,288 @@ +platform: + # Device to match configuration against. Program will exit if model does not match + device: "FM10840_B0" + # Device VPD hash to match against. Use this when multiple FM10K with different serial numbers exist on system. + #device_vpd_hash: "d3effea257d1348331a212d60d0b96ec1225c69a93c7e9fa1689b7f445c7d489" + #device_vpd_hash: "f67978856fa13d7e2ce4f0af8971bfbe633447f91ca5791ec5add3c6860fc70d" + configuration: + # A preset to use, if any + preset: "FM10840_B0_2x100G" + #preset: "FM10840_B0_8x25G" + + # Extra configuration entries (or whole file) follow here in order + entries: + # Required to have working VLAN tagging (802.1Q) + - ["api.port.allowFtagVlanTagging", "bool", "true"] + + #- ["api.platform.config.debug", "text", "CONFIG,MOD_STATE,MOD_LED,MOD_INTR,MOD_TYPE,PLAT_LOG"] + #- ["api.platform.lib.config.debug", "text", "I2C_RW,I2C_MUX,PORT_LED"] + + #- ["api.platform.config.switch.0.portIndex.1.ethernetMode", "text", "40GBase-SR4"] + #- ["api.platform.config.switch.0.portIndex.2.ethernetMode", "text", "40GBase-SR4"] + + # Override 100G ports to 10G + #- ["api.platform.config.switch.0.portIndex.1.ethernetMode", "text", "10GBase-SR"] + #- ["api.platform.config.switch.0.portIndex.2.ethernetMode", "text", "10GBase-SR"] + # Override 25G ports to 10G + #- ["api.platform.config.switch.0.portIndex.1.ethernetMode", "text", "10GBase-SR"] + #- ["api.platform.config.switch.0.portIndex.2.ethernetMode", "text", "10GBase-SR"] + #- ["api.platform.config.switch.0.portIndex.3.ethernetMode", "text", "10GBase-SR"] + #- ["api.platform.config.switch.0.portIndex.4.ethernetMode", "text", "10GBase-SR"] + #- ["api.platform.config.switch.0.portIndex.5.ethernetMode", "text", "10GBase-SR"] + #- ["api.platform.config.switch.0.portIndex.6.ethernetMode", "text", "10GBase-SR"] + #- ["api.platform.config.switch.0.portIndex.7.ethernetMode", "text", "10GBase-SR"] + #- ["api.platform.config.switch.0.portIndex.8.ethernetMode", "text", "10GBase-SR"] + +switch: + attributes: + # Frame timeout in milliseconds. see FM_FRAME_AGING_TIME_MSEC + #frame_aging_milliseconds: + + # Specifies which logical port to redirect CPU traffic to. + # The logical port can be a physical port or a LAG port. + # FM_REDIRECT_CPU_TRAFFIC + # Defaults to api.platform.config.switch.0.cpuPort + #cpu_port: + + # shared (default), per_vlan, multiple (not supported?) + stp_mode: shared + + lag: + # static (default, static groups, discard), dynamic (pass to application) + #mode: static + #pruning: true + + vlan_learning: + # VLAN learning mode. Values: independent (default), shared + mode: independent + # The VLAN to learn on when mode is shared (default 1) + vlan: 1 + trap: + # The 48-bit CPU MAC address (default: 0x000000000000). + # Frames received by the switch with this destination MAC address will + # be automatically trapped to the CPU. + cpu_mac: 0x000000000000 + 8021x: true + bpdu: true + lacp: true + garp: true + # This trap is only valid for routed frames. + mtu_violation: true + + + # Broadcast flooding control. Values: forward, discard, forward_without_cpu (default), per_port + broadcast_flooding: forward + + # Flood all multicast frames for which the multicast address is unknown on lookup to all ports including the CPU. + # Note that the CPU will only receive unknown multicast frames on VLANs for which the CPU port is a member. + # Multicast flooding control. Values: forward, discard, forward_without_cpu (default), per_port + multicast_flooding: forward + + # Flood all unicast frames for which the destination address is unknown on lookup. + # Note that the CPU will only receive unknown unicast frames on VLANs for which the CPU port is a member. + # Unicast flooding control. Values: forward, discard, forward_without_cpu (default), per_port + unicast_flooding: forward + +# Must create vlans so they exist +vlans: + - + id: 1 + attributes: + # If enabled, then a frame may be sent out the VLAN it came in on. + # On FM10000 devices, disabling reflection on a VLAN disables switching + # frames on this VLAN between Virtual Functions on the same PCIe port. + reflect: true + + # A VLAN must have this attribute enabled in order for traffic ingressing on the VLAN to be routed. + # When this attribute is disabled, ingressing traffic will only be switched at layer 2. + # Default false + routable: false + - + id: 2 + attributes: + reflect: true + routable: false + +# Definitions here share keys. First default, eth, pcie, special, cpu entries are applied, then specific port numbers +ports: + - + # Default port definitions, except internal + port: default + attributes: + tagging: + # Selects the port tagging mode for this port. Values (see fm_portTaggingMode struct): 8021q (default), 8021ad_customer, 8021ad_provider, pseudo1, pseudo2 + mode: 8021q + # The port's default VLAN. Tagging rules still apply from VLAN definition. The default value is 1. + vid: 1 + # The port's default priority (0 - 7). The default value is 0. + priority: 0 + + # The port's default second VLAN. The default value is 1. + #vid2: 1 + # The port's default second priority (0 - 7). The default value is 0. + #priority2: 0 + + # Whether the ingress VLAN-tagged frame's VLAN fields should be replaced with the port's default VLAN fields, + # as specified by the ''tagging.vid'', ''tagging.priority'', and ''tagging.cfi'' attributes. Default false + # + # Note that this attribute does not affect the selection of the internal switch priority of the frame (in the case of SWPRI being chosen from VLAN priority), + # as SWPRI is chosen before the port's default VLAN values are applied. See ''FM_PORT_SWPRI_SOURCE'' and ''FM_PORT_SWPRI_DSCP_PREF'' for details on the selection of SWPRI. + replace: false + + # The port's default CFI (0 - 1). The default value is 0. + # Also known as Drop eligible indicator (DEI). May be used separately or in conjunction with PCP to indicate frames eligible to be dropped in the presence of congestion. + cfi: 0 + # The port's default DSCP (0 - 63). Default value is 0. + dscp: 0 + # Defines the type of ISL tag (if any) present on frames ingressing on this port. + # On FM10000, this attribute supports f56 or none (default) on Ethernet ports, but only none is supported for PCIe and TE ports. + # Values: none, f56 + #isl_format: + # The port's default internal switch priority (0 - 15). Default value is 0. + switch_priority: 0 + + drop: + # Dropping frames that incur an ingress VLAN boundary violation. Default false + boundary_violation: false + + # Dropping of untagged frames on ingress. Default false. See notes for FM_PORT_DROP_UNTAGGED + untagged: false + + # Dropping of tagged frames on ingress. Default false. See notes for FM_PORT_DROP_TAGGED + tagged: false + + loopback: + # Internal loopback control. Frames emitted from the switch fabric towards an egress port are processed all the way + # through the Ethernet port logic, then looped back from transmit to receive at the SerDes level, complete with preamble and IFG. + # Can only be set on eth ports. Values: off (default), tx2rx, rx2tx + mode: off + + # Whether frames emitted out of the switch fabric toward an egress port are instead looped back into the fabric. + # Since such frames do not touch the Ethernet port logic of the chip, they will not have a preamble, nor do they invoke an IFG. + # The associated port logic will be put in a standby mode so that any frames received at the port will not enter the switch fabric. + # Values: off (default), tx2rx, rx2tx + fabric: off + # Indicates whether loopback suppression is enabled or disabled for a port. + # Value is either true (default) or false (default for TE ports). + # Note that this attribute has no effect when a port is a member of a link aggregation group. + #suppression: true + + + + parser: + # How far in OSI model packets are parsed before stopping. + # l2 (default) + # l3 - Set to this value to enable any L3 features, such as IGMP snooping, routing, IGMP storm control and L3 ACLs. + # l4 - Set FM_PORT_PARSER to this value to enable L4 ACLs (default for TE ports), in addition to L3 features. + # all + mode: l2 + # When two VLAN tags are present and identical in a packet, then this attribute defines which one is considered as first. + # Setting to false (default) makes VLAN1 first, VLAN2 second. + #first_vlan2: false + # Whether VID2 (VLAN ID in the second VLAN tag) is sent before VID1 (VLAN ID in the first VLAN tag) or after VID1. + # Setting to true sends the VID2 first, then VID1 second. + # Setting to false (default) sends the VID1 first, VID2 second. + #first_vid2: false + + # A port must have this attribute enabled in order for traffic ingressing on the port to be routed. + # When this attribute is disabled, ingressing traffic will only be switched at layer 2. + routable: false + + # Egress updating of fields + update: + # Defines whether the port should decrement the TTL field on outgoing routed frames. Default true + #ttl: true + + # Defines whether the port may modify the DSCP field on outgoing routed frames. Default true + #dscp: true + + # Defines whether the port should modify the VLAN priority field on egress. Default false + #vlan_priority: false + + # Defines whether the port should modify the VLAN2 priority field on egress. Default false + #vlan2_priority: false + + # A bit mask indicating the fields that will be updated on a routed frame. + # The mask consists of the OR of any of the following fields: DMAC, SMAC, VLAN + # Default is [DMAC, SMAC, VLAN] + routed: [DMAC, SMAC, VLAN] + + + + broadcast: + # Whether a port is to prune flooded broadcast frames + #pruning: false + # Flooding control for per_port switch value. Values: forward_without_cpu, trap, forward, discard + #flooding: forward_without_cpu + + multicast: + # Whether a port is to prune flooded broadcast frames + #pruning: false + # Flooding control for per_port switch value. Values: forward_without_cpu, trap, forward, discard + #flooding: forward_without_cpu + + unicast: + # Whether a port is to prune flooded broadcast frames + #pruning: false + # Flooding control for per_port switch value. Values: forward_without_cpu, trap, forward, discard + #flooding: forward_without_cpu + + # Indicates whether the port is an internal port in a multi-switch environment (port connects the switch to another switch). + # Value is either FM_ENABLED or FM_DISABLED (default). + # On FM10000, this attribute is always FM_DISABLED for PCIe ports and FM_ENABLED for TE ports. + #internal: false + + vlans: + - + id: 1 + # Tag egressing frames or not with ISL tag format, or VLAN other tagging mode defined, default false + tag: false + # Values: disabled, listening, learning, forwarding, blocking + stp: forwarding + - + id: 2 + tag: true + stp: forwarding + + - + # Default PCIe port definitions + port: pcie + attributes: + - + # Default port definitions + port: [special, eth, cpu] + attributes: + # Learning of source addresses on this port: true (default) or false (default for PEP and TE ports). + # Note: This attribute must be enabled for the address table security features to apply to frames received on the port. + learning: true + + - + # Default epl/ETH port definitions + port: eth + attributes: + # Maximum frame size in bytes, ranging from 0 to 15360 for FM10000 + # For FM10000, default value for an Ethernet port is 1536 and PCIE port is 15360. + # Note that a specified value will be rounded up to the nearest multiple of 4. + # + # In FM10000, frame size is computed from DMAC till the end of FCS. + # Hence the maximum frame size is actually MTU plus size of L2 header and FCS. + # E.g., if the non-vlan tagged netdev interface (of PCIE) on the host has MTU 15342, + # then the corresponding Max Frame Size is 15342 + 14 (L2 header) + 4 (FCS) = 15360. + max_frame_size: 9036 + + - + # CPU port definitions + port: cpu + attributes: + + - + # Port 1 definitions. As defined on platform configuration. This should be one of the QSFP (#1?) ports + port: 1 + attributes: + # The N-bit egress port mask to use when this port is the ingress port. + # A one bit in the mask indicates that frames from this port can be forwarded to the port represented by the bit. + # Each bit position corresponds to the logical port number of the egress port. + # To allow, for example, ports 0, 1, 2, 3 to communicate here, use either raw mask value (0xf) or list form [0, 1, 2, 3]. -1 to allow all known but self + #mask: -1 + + diff --git a/deps/argparse b/deps/argparse new file mode 160000 index 0000000..b9583b4 --- /dev/null +++ b/deps/argparse @@ -0,0 +1 @@ +Subproject commit b9583b42ab64aa6b985997fa88d1834d6de03a31 diff --git a/deps/rapidyaml b/deps/rapidyaml new file mode 160000 index 0000000..6993a7c --- /dev/null +++ b/deps/rapidyaml @@ -0,0 +1 @@ +Subproject commit 6993a7c56f4d064997a4df63fc16380ef6381d68 diff --git a/deps/sha2 b/deps/sha2 new file mode 160000 index 0000000..79116b5 --- /dev/null +++ b/deps/sha2 @@ -0,0 +1 @@ +Subproject commit 79116b5d5d449311c27a24e16c99d8bccb4d1301 diff --git a/src/device/PCIEDevice.cpp b/src/device/PCIEDevice.cpp index 29db492..f9b55c9 100644 --- a/src/device/PCIEDevice.cpp +++ b/src/device/PCIEDevice.cpp @@ -7,6 +7,7 @@ #include #include "PCIEDevice.h" #include "fm10k/FM10K.h" +#include "sha2.h" std::vector get_file_contents(const std::string& path){ std::ifstream file; @@ -89,6 +90,25 @@ std::vector PCIEDevice::DeviceEntry::find() { return entries; } +std::string PCIEDevice::DeviceEntry::getVPDHash() const { + static char syms[] = "0123456789abcdef"; + unsigned char digest[SHA256_DIGEST_SIZE]; + memset(digest,0, sizeof(digest)); + + std::string data; + data.resize(SHA256_DIGEST_SIZE * 2); + + auto& vpd = getVPD().get("Product Name"); + sha256(vpd.data(), vpd.size(), digest); + + for(auto i = 0; i < SHA256_DIGEST_SIZE; ++i){ + data[i * 2] = syms[(digest[i] >> 4) & 0xf]; + data[i * 2 + 1] = syms[digest[i] & 0xf]; + } + + return data; +} + PCIEDevice::PCIEDevice(const PCIEDevice::DeviceEntry& device) : m_device (device){ m_bar4Resource = open(m_device.getPath().c_str(), O_RDWR); if(m_bar4Resource <= 0){ @@ -196,6 +216,11 @@ void PCIEDevice::VitalProductData::fillFromEntry(const std::vector &v, m_vpd.emplace(std::move(keyword), std::move(data)); } +const std::vector& PCIEDevice::VitalProductData::get(const std::string &key) const { + static std::vector NOT_FOUND; + return m_vpd.find(key) != m_vpd.end() ? m_vpd.at(key) : NOT_FOUND; +} + PCIEDevice::VitalProductData::ResourceType::ResourceType(const std::vector& s, size_t& offset) { uint8_t h = s[offset++]; diff --git a/src/device/PCIEDevice.h b/src/device/PCIEDevice.h index a4b8cd7..a336bc7 100644 --- a/src/device/PCIEDevice.h +++ b/src/device/PCIEDevice.h @@ -38,6 +38,7 @@ public: explicit VitalProductData(const std::vector& s); + const std::vector& get(const std::string& key) const; private: void fillFromEntry(const std::vector& v, size_t& offset); @@ -71,6 +72,8 @@ public: return m_vpd; } + std::string getVPDHash() const; + uint16_t getVendor() const{ return m_vendor; } diff --git a/src/fm10k/FM10K.cpp b/src/fm10k/FM10K.cpp index 2135764..f85509a 100644 --- a/src/fm10k/FM10K.cpp +++ b/src/fm10k/FM10K.cpp @@ -4,6 +4,10 @@ #include "device/PCIEDevice.h" #include #include +#include +#include "ryml.hpp" +#include "c4/std/string.hpp" +#include "IES_SDK.h" FM10K::FM10K::FM10K(std::unique_ptr device) : m_device(std::move(device)) { @@ -276,10 +280,188 @@ void FM10K::FM10K::wait_ns(uint32_t nanoseconds) { std::this_thread::sleep_for(std::chrono::nanoseconds (nanoseconds)); } -bool FM10K::FM10K::initialize() const { +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 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 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 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 LOOPBACK_MODE_MAP = { + {"off", FM_PORT_LOOPBACK_OFF}, + {"rx2tx", FM_PORT_LOOPBACK_RX2TX}, + {"tx2rx", FM_PORT_LOOPBACK_TX2RX}, +}; + + +static std::unordered_map 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 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 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 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 VLAN_LEARNING_MODE = { + {"independent", FM_VLAN_LEARNING_MODE_INDEPENDENT}, + {"shared", FM_VLAN_LEARNING_MODE_SHARED} +}; + + +static std::unordered_map STP_MODE = { + {"shared", FM_SPANNING_TREE_SHARED}, + {"per_vlan", FM_SPANNING_TREE_PER_VLAN}, + {"multiple", FM_SPANNING_TREE_MULTIPLE}, +}; + + +static std::unordered_map LAG_MODE = { + {"static", FM_MODE_STATIC}, + {"dynamic", FM_MODE_DYNAMIC}, +}; + +fm_int getMapState(const std::string& k, const std::unordered_map& m){ + assert(m.find(k) != m.end()); + return m.at(k); +} + +bool FM10K::FM10K::initialize(const ryml::Tree& tree) const { auto& ies = IES::getInstance(); - if(!ies.loadKnownConfiguration(getHardwareInformationString() + "_AUTO_100G")){ - return false; + + 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(m_device.get()); @@ -295,5 +477,357 @@ bool FM10K::FM10K::initialize() const { //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"); - return ies.init(); + 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({"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_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(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; } diff --git a/src/fm10k/FM10K.h b/src/fm10k/FM10K.h index 704a7af..b2654ac 100644 --- a/src/fm10k/FM10K.h +++ b/src/fm10k/FM10K.h @@ -25,6 +25,10 @@ __f->fields. f = v auto __f = FM10K_MAP_REGISTER(i, t, o); \ __f->fields. f = v +namespace c4::yml { + class Tree; +} + namespace FM10K{ class FM10K { @@ -114,7 +118,7 @@ namespace FM10K{ return portIndex < m_ports.size() ? &m_ports.back() : nullptr; } - bool initialize() const; + bool initialize(const c4::yml::Tree& tree) const; bool isPEPEnabled(uint8_t pep) const; diff --git a/src/fm10k/IES.cpp b/src/fm10k/IES.cpp index 3344b15..36b9d33 100644 --- a/src/fm10k/IES.cpp +++ b/src/fm10k/IES.cpp @@ -61,20 +61,23 @@ bool FM10K::IES::init() { 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(); @@ -92,202 +95,6 @@ bool FM10K::IES::init() { std::abort(); } - uint32_t defaultVlan = 1; - - //Initialize VLANs - for(uint32_t vlan = 0; vlan < FM10000_MAX_VLAN; ++vlan){ - fmCreateVlan(IES_Static::sw, vlan); - } - - { - fm_bool vr = FM_ENABLED; - fmSetVlanAttribute(IES_Static::sw, 0, FM_VLAN_REFLECT, &vr); - } - - { - fm_status err; - fm_int port; - fm_switchInfo swInfo; - fm_bool pi = FM_DISABLED; - fm_bool vr = FM_ENABLED; - fmGetSwitchInfo(IES_Static::sw, &swInfo); - /* init non cpu ports and put them into their own vlan, make sure */ - /* the parser goes to l4, no vlan boundary check, and routable */ - for(fm_int cpi = 1; cpi < swInfo.numCardPorts; ++cpi){ - err = fmMapCardinalPort(IES_Static::sw, cpi, &port, nullptr); - if(err != FM_OK){ - std::abort(); - } - printf("cpi=%d, port=%d\n", cpi, port); - - - err = fmGetPortAttribute(IES_Static::sw, port, FM_PORT_INTERNAL, &pi); - if (err != FM_OK) { - printf("skip port %d\n", port); - continue; - } - if (pi == FM_ENABLED) { - printf("skip internal port %d\n", port); - continue; - } - - fm_bool is_pcie = FALSE; - fm_bool is_fibm = FALSE; - err = fmIsPciePort(IES_Static::sw, port, &is_pcie); - if (err != FM_OK){ - std::abort(); - } - - err = fmIsSpecialPort(IES_Static::sw, port, &is_fibm); - if (err != FM_OK){ - std::abort(); - } - - err = fmSetVlanAttribute(IES_Static::sw, defaultVlan, FM_VLAN_REFLECT, &vr); - if (err != FM_OK){ - std::abort(); - } - - err = fmSetPortState(IES_Static::sw, port, FM_PORT_STATE_UP, 0); - if (err != FM_OK){ - std::abort(); - } - - printf("set port %d to UP\n", port); - - err = fmAddVlanPort(IES_Static::sw, defaultVlan, port, FALSE); - if (err != FM_OK){ - std::abort(); - } - printf("add port %d to default vlan %u\n", port, defaultVlan); - - err = fmSetVlanPortState(IES_Static::sw, defaultVlan, port, FM_STP_STATE_FORWARDING); - if (err != FM_OK){ - std::abort(); - } - printf("set STP state of port %d in vlan %u to forwarding\n", port, defaultVlan); - - err = fmSetPortAttribute(IES_Static::sw, port, FM_PORT_DEF_VLAN, &defaultVlan); - if (err != FM_OK){ - std::abort(); - } - printf("set pvid for port %d to vlan %u\n", port, defaultVlan); - - - //This drops unknown vlans that violate constraints - fm_bool bv = FM_DISABLED; - err = fmSetPortAttribute(IES_Static::sw, port, FM_PORT_DROP_BV, &bv); - if (err != FM_OK){ - std::abort(); - } - printf("set FM_PORT_DROP_BV for port %d to %d\n", port, bv); - - { - fm_int pc = FM_PORT_PARSER_STOP_AFTER_L2;//FM_PORT_PARSER_STOP_AFTER_L4; - err = fmSetPortAttribute(IES_Static::sw, port, FM_PORT_PARSER, &pc); - if (err != FM_OK){ - std::abort(); - } - printf("set FM_PORT_PARSER for port %d to %d\n", port, pc); - } - - { - //Only switch, not routing - fm_bool re = FM_DISABLED; - err = fmSetPortAttribute(IES_Static::sw, port, FM_PORT_ROUTABLE, &re); - if (err != FM_OK){ - std::abort(); - } - printf("set FM_PORT_ROUTABLE for port %d to %d\n", port, re); - } - { - if(!is_fibm && !is_pcie){ - fm_int fs = 10000; - err = fmSetPortAttribute(IES_Static::sw, port, FM_PORT_MAX_FRAME_SIZE, &fs); - if (err != FM_OK){ - std::abort(); - } - printf("set FM_PORT_MAX_FRAME_SIZE for port %d to %d\n", port, fs); - } - } - { - // enable learning only for Ethernet ports - fm_int le = !is_pcie; - err = fmSetPortAttribute(IES_Static::sw, port, FM_PORT_LEARNING, &le); - if (err != FM_OK){ - std::abort(); - } - - printf("set FM_PORT_LEARNING for port %d to %d\n", port, le); - } - } - } - - /* port cpu port on default vlan */ - { - fm_int port; - auto err = fmGetCpuPort(IES_Static::sw, &port); - if(err != FM_OK){ - std::abort(); - } - printf("find cpu port %d\n", port); - - err = fmAddVlanPort(IES_Static::sw, defaultVlan, port, FALSE); - if(err != FM_OK){ - std::abort(); - } - printf("add port %d to default vlan %u\n", port, defaultVlan); - - err = fmSetPortAttribute(IES_Static::sw, port, FM_PORT_DEF_VLAN, &defaultVlan); - if(err != FM_OK){ - std::abort(); - } - printf("set pvid for port %d to vlan %u\n", port, defaultVlan); - - { - fm_int pc = FM_PORT_PARSER_STOP_AFTER_L2;//FM_PORT_PARSER_STOP_AFTER_L4; - err = fmSetPortAttribute(IES_Static::sw, port, FM_PORT_PARSER, &pc); - if (err != FM_OK){ - std::abort(); - } - printf("set FM_PORT_PARSER for port %d to %d\n", port, pc); - } - { - fm_int le = FM_ENABLED; - err = fmSetPortAttribute(IES_Static::sw, port, FM_PORT_LEARNING, &le); - if (err != FM_OK){ - std::abort(); - } - - printf("set FM_PORT_LEARNING for port %d to %d\n", port, le); - } - } - - - { - - fm_int bf = FM_BCAST_FWD; - fm_int mf = FM_MCAST_FWD; - fm_int uf = FM_UCAST_FWD; - auto err = fmSetSwitchAttribute(IES_Static::sw, FM_BCAST_FLOODING, &bf); - if (err != FM_OK){ - std::abort(); - } - err = fmSetSwitchAttribute(IES_Static::sw, FM_MCAST_FLOODING, &mf); - if (err != FM_OK){ - std::abort(); - } - err = fmSetSwitchAttribute(IES_Static::sw, FM_UCAST_FLOODING, &uf); - if (err != FM_OK){ - std::abort(); - } - } - - printf("Switch is UP, all ports are now enabled\n"); - - //TODO: setup routing - - //Restore cwd if(chdir(tempcwd) != 0){ std::abort(); @@ -491,4 +298,168 @@ void FM10K::IES::teardown() { } } +template +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 +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 +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 +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 +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 +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& 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(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) \ No newline at end of file diff --git a/src/fm10k/IES.h b/src/fm10k/IES.h index 6895de4..b9dde7d 100644 --- a/src/fm10k/IES.h +++ b/src/fm10k/IES.h @@ -5,8 +5,10 @@ #include #include #include +#include struct _fm_eventPort; +struct _fm_switchInfo; namespace FM10K { @@ -51,6 +53,40 @@ namespace FM10K { bool init(); void teardown(); + struct _fm_switchInfo fmGetSwitchInfo() const; + + void iteratePorts(const std::function& callback) const; + + bool fmIsPciePort(int port) const; + bool fmIsSpecialPort(int port) const; + bool fmIsEplPort(int port) const; + + void fmSetPortState(int port, int mode, int submode) const; + + void fmCreateVlan(uint16_t vlan) const; + void fmAddVlanPort(uint16_t vlan, int port, bool tagVlan) const; + void fmSetVlanPortState(uint16_t vlan, int port, int state) const; + + template + void fmSetVlanAttribute(uint16_t vlan, int attribute, T value) const; + + template + T fmGetVlanAttribute(uint16_t vlan, int attribute) const; + + template + void fmSetPortAttribute(int port, int attribute, T value) const; + + template + T fmGetPortAttribute(int port, int attribute) const; + + template + void fmSetSwitchAttribute(int attribute, T value) const; + + template + T fmGetSwitchAttribute(int attribute) const; + + int fmGetSwitch() const; + private: IES(); @@ -69,3 +105,14 @@ namespace FM10K { } +class IESException : public std::exception{ +public: + explicit IESException(int status); + + const char* what() const noexcept override + { + return m_msg.c_str(); + } + + const std::string m_msg; +}; \ No newline at end of file diff --git a/src/fm10k/IES_CONFIGURATIONS.h b/src/fm10k/IES_CONFIGURATIONS.h index c50fbc3..27b7260 100644 --- a/src/fm10k/IES_CONFIGURATIONS.h +++ b/src/fm10k/IES_CONFIGURATIONS.h @@ -17,21 +17,21 @@ namespace FM10K { namespace IES_Static { using TlvType = FM10K::IES::TlvType; static std::unordered_map>>> knownConfigurations = { - {"FM10840_B0_AUTO_100G", { + {"FM10840_B0_2x100G", { {"api.platform.config.numSwitches", {TlvType::Integer, "1"}}, {"api.platform.config.platformName", {TlvType::Text, "rrc_2x100gm"}}, - {"api.platform.config.debug", {TlvType::Text, "CONFIG,MOD_STATE,MOD_LED,MOD_INTR,MOD_TYPE,PLAT_LOG"}}, + //{"api.platform.config.debug", {TlvType::Text, "CONFIG,MOD_STATE,MOD_LED,MOD_INTR,MOD_TYPE,PLAT_LOG"}}, //{"api.platform.lib.config.debug", {TlvType::Text, "I2C_RW,I2C_MUX,PORT_LED"}}, {"api.platform.config.switch.0.switchNumber", {TlvType::Integer, "0"}}, - {"api.platform.config.switch.0.uioDevName", {TlvType::Text, "/dev/uio0"}}, //TODO: delete this if not in use + {"api.platform.config.switch.0.uioDevName", {TlvType::Text, "/dev/uio0"}}, - {"api.platform.config.switch.0.resource4DevName", {TlvType::Text, ""}}, //TODO: delete this if not in use + {"api.platform.config.switch.0.resource4DevName", {TlvType::Text, ""}}, {"api.platform.config.switch.0.msiEnabled", {TlvType::Boolean, "true"}}, @@ -304,6 +304,328 @@ namespace FM10K { {"api.platform.config.switch.0.VDDS.hwResourceId", {TlvType::Integer, "2"}}, + {"api.platform.lib.config.hwResourceId.3.type", {TlvType::Text, "VRM"}}, + {"api.platform.lib.config.hwResourceId.3.vrm.busSelType", {TlvType::Text, "PCAMUX"}}, + {"api.platform.lib.config.hwResourceId.3.vrm.bus", {TlvType::Integer, "0"}}, + {"api.platform.lib.config.hwResourceId.3.vrm.model", {TlvType::Text, "IR"}}, + {"api.platform.lib.config.hwResourceId.3.vrm.addr", {TlvType::Integer, "0x08"}}, + {"api.platform.lib.config.hwResourceId.3.vrm.pcaMux.index", {TlvType::Integer, "0"}}, + {"api.platform.lib.config.hwResourceId.3.vrm.pcaMux.value", {TlvType::Integer, "0x04"}}, + + {"api.platform.config.switch.0.VDDF.hwResourceId", {TlvType::Integer, "259"}}, + }}, + + {"FM10840_B0_8x25G", { + {"api.platform.config.numSwitches", {TlvType::Integer, "1"}}, + + {"api.platform.config.platformName", {TlvType::Text, "rrc_2x100gm"}}, + + {"api.platform.config.switch.0.switchNumber", {TlvType::Integer, "0"}}, + + {"api.platform.config.switch.0.uioDevName", {TlvType::Text, "/dev/uio0"}}, + + {"api.platform.config.switch.0.resource4DevName", {TlvType::Text, ""}}, + + {"api.platform.config.switch.0.msiEnabled", {TlvType::Boolean, "true"}}, + + + {"api.platform.config.switch.0.ledPollPeriodMsec", {TlvType::Integer, "200"}}, + {"api.platform.config.switch.0.ledBlinkMode", {TlvType::Text, "HW_ASSISTED"}}, + + {"api.platform.config.switch.0.i2cClkDivider", {TlvType::Integer, "52"}}, + {"api.platform.config.switch.0.i2cResetGpio", {TlvType::Integer, "5"}}, + + + {"api.platform.config.switch.0.xcvrPollPeriodMsec", {TlvType::Integer, "1000"}}, + + + {"api.platform.config.switch.0.numPorts", {TlvType::Integer, "13"}}, + + + {"api.platform.config.switch.0.cpuPort", {TlvType::Integer, "12"}}, + {"api.platform.config.switch.0.bootCfg.mgmtPep", {TlvType::Integer, "-1"}}, + {"api.platform.config.switch.0.bootCfg.pep.0.mode", {TlvType::Boolean, "0"}}, + {"api.platform.config.switch.0.bootCfg.pep.2.mode", {TlvType::Boolean, "0"}}, + {"api.platform.config.switch.0.bootCfg.pep.4.mode", {TlvType::Boolean, "0"}}, + {"api.platform.config.switch.0.bootCfg.pep.6.mode", {TlvType::Boolean, "0"}}, + + {"api.platform.config.switch.0.bootCfg.pep.0.enable", {TlvType::Boolean, "1"}}, + {"api.platform.config.switch.0.bootCfg.pep.2.enable", {TlvType::Boolean, "1"}}, + {"api.platform.config.switch.0.bootCfg.pep.4.enable", {TlvType::Boolean, "1"}}, + {"api.platform.config.switch.0.bootCfg.pep.6.enable", {TlvType::Boolean, "1"}}, + {"api.platform.config.switch.0.bootCfg.pep.8.enable", {TlvType::Boolean, "0"}}, + + {"api.platform.config.switch.0.bootCfg.pep.0.bar4Allowed", {TlvType::Boolean, "1"}}, + {"api.platform.config.switch.0.bootCfg.pep.2.bar4Allowed", {TlvType::Boolean, "1"}}, + {"api.platform.config.switch.0.bootCfg.pep.4.bar4Allowed", {TlvType::Boolean, "1"}}, + {"api.platform.config.switch.0.bootCfg.pep.6.bar4Allowed", {TlvType::Boolean, "1"}}, + + + {"api.platform.config.switch.0.portIndex.0.portMapping", {TlvType::Text, "\"LOG=0 PCIE=8\""}}, + + + {"api.platform.config.switch.0.portIndex.1.portMapping", {TlvType::Text, "\"LOG=1 EPL=1 LANE=0\""}}, + {"api.platform.config.switch.0.portIndex.2.portMapping", {TlvType::Text, "\"LOG=2 EPL=1 LANE=1\""}}, + {"api.platform.config.switch.0.portIndex.3.portMapping", {TlvType::Text, "\"LOG=3 EPL=1 LANE=2\""}}, + {"api.platform.config.switch.0.portIndex.4.portMapping", {TlvType::Text, "\"LOG=4 EPL=1 LANE=3\""}}, + + + {"api.platform.config.switch.0.portIndex.5.portMapping", {TlvType::Text, "\"LOG=5 EPL=7 LANE=0\""}}, + {"api.platform.config.switch.0.portIndex.6.portMapping", {TlvType::Text, "\"LOG=6 EPL=7 LANE=1\""}}, + {"api.platform.config.switch.0.portIndex.7.portMapping", {TlvType::Text, "\"LOG=7 EPL=7 LANE=2\""}}, + {"api.platform.config.switch.0.portIndex.8.portMapping", {TlvType::Text, "\"LOG=8 EPL=7 LANE=3\""}}, + + + {"api.platform.config.switch.0.portIndex.9.portMapping", {TlvType::Text, "\"LOG=9 PCIE=0\""}}, + {"api.platform.config.switch.0.portIndex.10.portMapping", {TlvType::Text, "\"LOG=10 PCIE=2\""}}, + {"api.platform.config.switch.0.portIndex.11.portMapping", {TlvType::Text, "\"LOG=11 PCIE=4\""}}, + {"api.platform.config.switch.0.portIndex.12.portMapping", {TlvType::Text, "\"LOG=12 PCIE=6\""}}, + + + {"api.platform.config.switch.0.port.default.interfaceType", {TlvType::Text, "NONE"}}, + + {"api.platform.config.switch.0.portIndex.1.interfaceType", {TlvType::Text, "QSFP_LANE0"}}, + {"api.platform.config.switch.0.portIndex.2.interfaceType", {TlvType::Text, "QSFP_LANE1"}}, + {"api.platform.config.switch.0.portIndex.3.interfaceType", {TlvType::Text, "QSFP_LANE2"}}, + {"api.platform.config.switch.0.portIndex.4.interfaceType", {TlvType::Text, "QSFP_LANE3"}}, + {"api.platform.config.switch.0.portIndex.5.interfaceType", {TlvType::Text, "QSFP_LANE0"}}, + {"api.platform.config.switch.0.portIndex.6.interfaceType", {TlvType::Text, "QSFP_LANE1"}}, + {"api.platform.config.switch.0.portIndex.7.interfaceType", {TlvType::Text, "QSFP_LANE2"}}, + {"api.platform.config.switch.0.portIndex.8.interfaceType", {TlvType::Text, "QSFP_LANE3"}}, + + + {"api.platform.config.switch.0.portIndex.0.speed", {TlvType::Integer, SPEED_10G}}, + + {"api.platform.config.switch.0.portIndex.1.speed", {TlvType::Integer, SPEED_25G}}, + {"api.platform.config.switch.0.portIndex.2.speed", {TlvType::Integer, SPEED_25G}}, + {"api.platform.config.switch.0.portIndex.3.speed", {TlvType::Integer, SPEED_25G}}, + {"api.platform.config.switch.0.portIndex.4.speed", {TlvType::Integer, SPEED_25G}}, + {"api.platform.config.switch.0.portIndex.5.speed", {TlvType::Integer, SPEED_25G}}, + {"api.platform.config.switch.0.portIndex.6.speed", {TlvType::Integer, SPEED_25G}}, + {"api.platform.config.switch.0.portIndex.7.speed", {TlvType::Integer, SPEED_25G}}, + {"api.platform.config.switch.0.portIndex.8.speed", {TlvType::Integer, SPEED_25G}}, + + {"api.platform.config.switch.0.portIndex.9.speed", {TlvType::Integer, SPEED_50G}}, + {"api.platform.config.switch.0.portIndex.10.speed", {TlvType::Integer, SPEED_50G}}, + {"api.platform.config.switch.0.portIndex.11.speed", {TlvType::Integer, SPEED_50G}}, //? second PCIe group + {"api.platform.config.switch.0.portIndex.12.speed", {TlvType::Integer, SPEED_50G}}, //? second PCIe group + + {"api.platform.config.switch.0.port.default.ethernetMode", {TlvType::Text, "DISABLED"}}, + + + {"api.platform.config.switch.0.portIndex.1.ethernetMode", {TlvType::Text, "AUTODETECT"}}, + {"api.platform.config.switch.0.portIndex.2.ethernetMode", {TlvType::Text, "AUTODETECT"}}, + {"api.platform.config.switch.0.portIndex.3.ethernetMode", {TlvType::Text, "AUTODETECT"}}, + {"api.platform.config.switch.0.portIndex.4.ethernetMode", {TlvType::Text, "AUTODETECT"}}, + {"api.platform.config.switch.0.portIndex.5.ethernetMode", {TlvType::Text, "AUTODETECT"}}, + {"api.platform.config.switch.0.portIndex.6.ethernetMode", {TlvType::Text, "AUTODETECT"}}, + {"api.platform.config.switch.0.portIndex.7.ethernetMode", {TlvType::Text, "AUTODETECT"}}, + {"api.platform.config.switch.0.portIndex.8.ethernetMode", {TlvType::Text, "AUTODETECT"}}, + + + {"api.platform.config.switch.0.port.default.capability", {TlvType::Text, "NONE"}}, + + {"api.platform.config.switch.0.portIndex.1.capability",{TlvType::Text, "LAG,ROUTE,10G,25G,SW_LED"}}, + {"api.platform.config.switch.0.portIndex.2.capability",{TlvType::Text, "LAG,ROUTE,10G,25G,SW_LED"}}, + {"api.platform.config.switch.0.portIndex.3.capability",{TlvType::Text, "LAG,ROUTE,10G,25G,SW_LED"}}, + {"api.platform.config.switch.0.portIndex.4.capability",{TlvType::Text, "LAG,ROUTE,10G,25G,SW_LED"}}, + {"api.platform.config.switch.0.portIndex.5.capability",{TlvType::Text, "LAG,ROUTE,10G,25G,SW_LED"}}, + {"api.platform.config.switch.0.portIndex.6.capability",{TlvType::Text, "LAG,ROUTE,10G,25G,SW_LED"}}, + {"api.platform.config.switch.0.portIndex.7.capability",{TlvType::Text, "LAG,ROUTE,10G,25G,SW_LED"}}, + {"api.platform.config.switch.0.portIndex.8.capability",{TlvType::Text, "LAG,ROUTE,10G,25G,SW_LED"}}, + + + {"api.platform.config.switch.0.port.default.lanePolarity", {TlvType::Text, "INVERT_NONE"}}, + + + {"api.platform.config.switch.0.port.default.preCursorCopper", {TlvType::Integer, "0"}}, + + + {"api.platform.config.switch.0.sharedLibraryName", {TlvType::Text, "libLTStdPlatform.so"}}, + + + {"api.platform.config.switch.0.sharedLibrary.disable", {TlvType::Text, "GetPortIntrPending,EnablePortIntr"}}, + + + {"api.platform.lib.config.bus0.i2cDevName", {TlvType::Text, "switchI2C"}}, + + {"api.platform.lib.config.pcaMux.count", {TlvType::Integer, "1"}}, + + {"api.platform.lib.config.pcaMux.0.model", {TlvType::Text, "PCA9545"}}, + {"api.platform.lib.config.pcaMux.0.addr", {TlvType::Integer, "0x58"}}, + {"api.platform.lib.config.pcaMux.0.bus", {TlvType::Integer, "0"}}, + + + {"api.platform.lib.config.pcaIo.count", {TlvType::Integer, "6"}}, + + + {"api.platform.lib.config.pcaIo.0.model", {TlvType::Text, "PCA9538"}}, + {"api.platform.lib.config.pcaIo.0.bus", {TlvType::Integer, "0"}}, + {"api.platform.lib.config.pcaIo.0.addr", {TlvType::Integer, "0x60"}}, + + {"api.platform.lib.config.pcaIo.1.model", {TlvType::Text, "PCA9538"}}, + {"api.platform.lib.config.pcaIo.1.bus", {TlvType::Integer, "0"}}, + {"api.platform.lib.config.pcaIo.1.addr", {TlvType::Integer, "0x61"}}, + + {"api.platform.lib.config.pcaIo.2.model", {TlvType::Text, "PCA9538"}}, + {"api.platform.lib.config.pcaIo.2.bus", {TlvType::Integer, "0"}}, + {"api.platform.lib.config.pcaIo.2.addr", {TlvType::Integer, "0x62"}}, + + {"api.platform.lib.config.pcaIo.3.model", {TlvType::Text, "PCA9538"}}, + {"api.platform.lib.config.pcaIo.3.bus", {TlvType::Integer, "0"}}, + {"api.platform.lib.config.pcaIo.3.addr", {TlvType::Integer, "0x64"}}, + + {"api.platform.lib.config.pcaIo.4.model", {TlvType::Text, "PCA9538"}}, + {"api.platform.lib.config.pcaIo.4.bus", {TlvType::Integer, "0"}}, + {"api.platform.lib.config.pcaIo.4.addr", {TlvType::Integer, "0x65"}}, + + {"api.platform.lib.config.pcaIo.5.model", {TlvType::Text, "PCA9538"}}, + {"api.platform.lib.config.pcaIo.5.bus", {TlvType::Integer, "0"}}, + {"api.platform.lib.config.pcaIo.5.addr", {TlvType::Integer, "0x66"}}, + + + {"api.platform.lib.config.xcvrState.default.modPrsL.pin", {TlvType::Integer, "2"}}, + {"api.platform.lib.config.xcvrState.default.intL.pin", {TlvType::Integer, "1"}}, + {"api.platform.lib.config.xcvrState.default.resetL.pin", {TlvType::Integer, "3"}}, + {"api.platform.lib.config.xcvrState.default.lpMode.pin", {TlvType::Integer, "0"}}, + + + {"api.platform.lib.config.hwResourceId.count", {TlvType::Integer, "4"}}, + + {"api.platform.config.switch.0.portIndex.1.hwResourceId", {TlvType::Integer, "0"}}, + {"api.platform.config.switch.0.portIndex.2.hwResourceId", {TlvType::Integer, "0"}}, + {"api.platform.config.switch.0.portIndex.3.hwResourceId", {TlvType::Integer, "0"}}, + {"api.platform.config.switch.0.portIndex.4.hwResourceId", {TlvType::Integer, "0"}}, + {"api.platform.config.switch.0.portIndex.5.hwResourceId", {TlvType::Integer, "1"}}, + {"api.platform.config.switch.0.portIndex.6.hwResourceId", {TlvType::Integer, "1"}}, + {"api.platform.config.switch.0.portIndex.7.hwResourceId", {TlvType::Integer, "1"}}, + {"api.platform.config.switch.0.portIndex.8.hwResourceId", {TlvType::Integer, "1"}}, + + + {"api.platform.lib.config.hwResourceId.0.interfaceType", {TlvType::Text, "QSFP"}}, + {"api.platform.lib.config.hwResourceId.0.xcvrI2C.busSelType", {TlvType::Text, "PCAMUX"}}, + + {"api.platform.lib.config.hwResourceId.0.xcvrI2C.pcaMux.index", {TlvType::Integer, "0"}}, + {"api.platform.lib.config.hwResourceId.0.xcvrI2C.pcaMux.value", {TlvType::Integer, "1"}}, + + {"api.platform.lib.config.hwResourceId.0.xcvrState.pcaIo.index", {TlvType::Integer, "0"}}, + {"api.platform.lib.config.hwResourceId.0.xcvrState.pcaIo.basePin", {TlvType::Integer, "0"}}, + + {"api.platform.lib.config.hwResourceId.0.xcvrState.pcaIo.modPrsL.pin", {TlvType::Integer, "0"}}, + {"api.platform.lib.config.hwResourceId.0.xcvrState.pcaIo.intL.pin", {TlvType::Integer, "1"}}, + {"api.platform.lib.config.hwResourceId.0.xcvrState.pcaIo.resetL.pin", {TlvType::Integer, "4"}}, + {"api.platform.lib.config.hwResourceId.0.xcvrState.pcaIo.lpMode.pin", {TlvType::Integer, "5"}}, + + {"api.platform.lib.config.hwResourceId.0.portLed.0.type", {TlvType::Text, "PCA"}}, + {"api.platform.lib.config.hwResourceId.0.portLed.0.pcaIo.index", {TlvType::Integer, "2"}}, + + {"api.platform.lib.config.hwResourceId.0.portLed.0.0.pcaIo.pin", {TlvType::Integer, "0"}}, + {"api.platform.lib.config.hwResourceId.0.portLed.0.0.pcaIo.usage", {TlvType::Text, "LINK,10G"}}, + + {"api.platform.lib.config.hwResourceId.0.portLed.0.1.pcaIo.pin", {TlvType::Integer, "1"}}, + {"api.platform.lib.config.hwResourceId.0.portLed.0.1.pcaIo.usage", {TlvType::Text, "LINK,40G"}}, + + {"api.platform.lib.config.hwResourceId.0.portLed.0.2.pcaIo.pin", {TlvType::Integer, "2"}}, + {"api.platform.lib.config.hwResourceId.0.portLed.0.2.pcaIo.usage", {TlvType::Text, "LINK,25G"}}, + + {"api.platform.lib.config.hwResourceId.0.portLed.0.3.pcaIo.pin", {TlvType::Integer, "3"}}, + {"api.platform.lib.config.hwResourceId.0.portLed.0.3.pcaIo.usage",{TlvType::Text, "LINK,100G"}}, + + {"api.platform.lib.config.hwResourceId.0.portLed.1.type", {TlvType::Text, "PCA"}}, + {"api.platform.lib.config.hwResourceId.0.portLed.1.pcaIo.index", {TlvType::Integer, "2"}}, + + {"api.platform.lib.config.hwResourceId.0.portLed.1.0.pcaIo.pin", {TlvType::Integer, "4"}}, + {"api.platform.lib.config.hwResourceId.0.portLed.1.0.pcaIo.usage", {TlvType::Text, "LINK,10G"}}, + + {"api.platform.lib.config.hwResourceId.0.portLed.1.1.pcaIo.pin", {TlvType::Integer, "5"}}, + {"api.platform.lib.config.hwResourceId.0.portLed.1.1.pcaIo.usage", {TlvType::Text, "LINK,25G"}}, + + {"api.platform.lib.config.hwResourceId.0.portLed.2.type", {TlvType::Text, "PCA"}}, + {"api.platform.lib.config.hwResourceId.0.portLed.2.pcaIo.index", {TlvType::Integer, "2"}}, + + {"api.platform.lib.config.hwResourceId.0.portLed.2.0.pcaIo.pin", {TlvType::Integer, "6"}}, + {"api.platform.lib.config.hwResourceId.0.portLed.2.0.pcaIo.usage", {TlvType::Text, "LINK,10G"}}, + + {"api.platform.lib.config.hwResourceId.0.portLed.2.1.pcaIo.pin", {TlvType::Integer, "7"}}, + {"api.platform.lib.config.hwResourceId.0.portLed.2.1.pcaIo.usage", {TlvType::Text, "LINK,25G"}}, + + {"api.platform.lib.config.hwResourceId.0.portLed.3.type", {TlvType::Text, "PCA"}}, + {"api.platform.lib.config.hwResourceId.0.portLed.3.pcaIo.index", {TlvType::Integer, "4"}}, + + {"api.platform.lib.config.hwResourceId.0.portLed.3.0.pcaIo.pin", {TlvType::Integer, "0"}}, + {"api.platform.lib.config.hwResourceId.0.portLed.3.0.pcaIo.usage", {TlvType::Text, "LINK,10G"}}, + + {"api.platform.lib.config.hwResourceId.0.portLed.3.1.pcaIo.pin", {TlvType::Integer, "1"}}, + {"api.platform.lib.config.hwResourceId.0.portLed.3.1.pcaIo.usage", {TlvType::Text, "LINK,25G"}}, + + + {"api.platform.lib.config.hwResourceId.1.interfaceType", {TlvType::Text, "QSFP"}}, + {"api.platform.lib.config.hwResourceId.1.xcvrI2C.busSelType", {TlvType::Text, "PCAMUX"}}, + + {"api.platform.lib.config.hwResourceId.1.xcvrI2C.pcaMux.index", {TlvType::Integer, "0"}}, + {"api.platform.lib.config.hwResourceId.1.xcvrI2C.pcaMux.value", {TlvType::Integer, "2"}}, + + {"api.platform.lib.config.hwResourceId.1.xcvrState.pcaIo.index", {TlvType::Integer, "1"}}, + {"api.platform.lib.config.hwResourceId.1.xcvrState.pcaIo.basePin", {TlvType::Integer, "0"}}, + + {"api.platform.lib.config.hwResourceId.1.xcvrState.pcaIo.modPrsL.pin", {TlvType::Integer, "0"}}, + {"api.platform.lib.config.hwResourceId.1.xcvrState.pcaIo.intL.pin", {TlvType::Integer, "1"}}, + {"api.platform.lib.config.hwResourceId.1.xcvrState.pcaIo.resetL.pin", {TlvType::Integer, "4"}}, + {"api.platform.lib.config.hwResourceId.1.xcvrState.pcaIo.lpMode.pin", {TlvType::Integer, "5"}}, + + {"api.platform.lib.config.hwResourceId.1.portLed.0.type", {TlvType::Text, "PCA"}}, + {"api.platform.lib.config.hwResourceId.1.portLed.0.pcaIo.index", {TlvType::Integer, "5"}}, + + {"api.platform.lib.config.hwResourceId.1.portLed.0.0.pcaIo.pin", {TlvType::Integer, "0"}}, + {"api.platform.lib.config.hwResourceId.1.portLed.0.0.pcaIo.usage", {TlvType::Text, "LINK,10G"}}, + + {"api.platform.lib.config.hwResourceId.1.portLed.0.1.pcaIo.pin", {TlvType::Integer, "1"}}, + {"api.platform.lib.config.hwResourceId.1.portLed.0.1.pcaIo.usage", {TlvType::Text, "LINK,40G"}}, + + {"api.platform.lib.config.hwResourceId.1.portLed.0.2.pcaIo.pin", {TlvType::Integer, "2"}}, + {"api.platform.lib.config.hwResourceId.1.portLed.0.2.pcaIo.usage", {TlvType::Text, "LINK,25G"}}, + + {"api.platform.lib.config.hwResourceId.1.portLed.0.3.pcaIo.pin", {TlvType::Integer, "3"}}, + {"api.platform.lib.config.hwResourceId.1.portLed.0.3.pcaIo.usage", {TlvType::Text, "LINK,100G"}}, + + {"api.platform.lib.config.hwResourceId.1.portLed.1.type", {TlvType::Text, "PCA"}}, + {"api.platform.lib.config.hwResourceId.1.portLed.1.pcaIo.index", {TlvType::Integer, "5"}}, + + {"api.platform.lib.config.hwResourceId.1.portLed.1.0.pcaIo.pin", {TlvType::Integer, "4"}}, + {"api.platform.lib.config.hwResourceId.1.portLed.1.0.pcaIo.usage", {TlvType::Text, "LINK,10G"}}, + + {"api.platform.lib.config.hwResourceId.1.portLed.1.1.pcaIo.pin", {TlvType::Integer, "5"}}, + {"api.platform.lib.config.hwResourceId.1.portLed.1.1.pcaIo.usage", {TlvType::Text, "LINK,25G"}}, + + {"api.platform.lib.config.hwResourceId.1.portLed.2.type", {TlvType::Text, "PCA"}}, + {"api.platform.lib.config.hwResourceId.1.portLed.2.pcaIo.index", {TlvType::Integer, "5"}}, + + {"api.platform.lib.config.hwResourceId.1.portLed.2.0.pcaIo.pin", {TlvType::Integer, "6"}}, + {"api.platform.lib.config.hwResourceId.1.portLed.2.0.pcaIo.usage", {TlvType::Text, "LINK,10G"}}, + + {"api.platform.lib.config.hwResourceId.1.portLed.2.1.pcaIo.pin", {TlvType::Integer, "7"}}, + {"api.platform.lib.config.hwResourceId.1.portLed.2.1.pcaIo.usage", {TlvType::Text, "LINK,25G"}}, + + {"api.platform.lib.config.hwResourceId.1.portLed.3.type", {TlvType::Text, "PCA"}}, + {"api.platform.lib.config.hwResourceId.1.portLed.3.pcaIo.index", {TlvType::Integer, "4"}}, + + {"api.platform.lib.config.hwResourceId.1.portLed.3.0.pcaIo.pin", {TlvType::Integer, "2"}}, + {"api.platform.lib.config.hwResourceId.1.portLed.3.0.pcaIo.usage", {TlvType::Text, "LINK,10G"}}, + + {"api.platform.lib.config.hwResourceId.1.portLed.3.1.pcaIo.pin", {TlvType::Integer, "3"}}, + {"api.platform.lib.config.hwResourceId.1.portLed.3.1.pcaIo.usage", {TlvType::Text, "LINK,25G"}}, + + {"api.platform.lib.config.hwResourceId.2.type", {TlvType::Text, "VRM"}}, + {"api.platform.lib.config.hwResourceId.2.vrm.busSelType", {TlvType::Text, "PCAMUX"}}, + {"api.platform.lib.config.hwResourceId.2.vrm.bus", {TlvType::Integer, "0"}}, + {"api.platform.lib.config.hwResourceId.2.vrm.model", {TlvType::Text, "IR"}}, + {"api.platform.lib.config.hwResourceId.2.vrm.addr", {TlvType::Integer, "0x08"}}, + {"api.platform.lib.config.hwResourceId.2.vrm.pcaMux.index", {TlvType::Integer, "0"}}, + {"api.platform.lib.config.hwResourceId.2.vrm.pcaMux.value", {TlvType::Integer, "0x04"}}, + + {"api.platform.config.switch.0.VDDS.hwResourceId", {TlvType::Integer, "2"}}, + + {"api.platform.lib.config.hwResourceId.3.type", {TlvType::Text, "VRM"}}, {"api.platform.lib.config.hwResourceId.3.vrm.busSelType", {TlvType::Text, "PCAMUX"}}, {"api.platform.lib.config.hwResourceId.3.vrm.bus", {TlvType::Integer, "0"}}, @@ -314,6 +636,7 @@ namespace FM10K { {"api.platform.config.switch.0.VDDF.hwResourceId", {TlvType::Integer, "259"}}, }} + }; } } diff --git a/src/fsmd.cpp b/src/fsmd.cpp index a46b17c..0705395 100644 --- a/src/fsmd.cpp +++ b/src/fsmd.cpp @@ -5,10 +5,14 @@ #include #include #include +#include #include "device/PCIEDevice.h" #include "fm10k/FM10K.h" #include "fm10k/registers/Register.h" #include "fm10k/IES.h" +#include "argparse/argparse.hpp" +#include "ryml.hpp" +#include "c4/std/string.hpp" template std::string tohex(T v){ std::stringstream o; @@ -24,7 +28,40 @@ static void int_handler(int sig){ std::cout << "STOPPING DUE TO SIGNAL " << sig << std::endl; } -int main() { +int main(int argc, char *argv[]) { + argparse::ArgumentParser program("fsmd", "0.1.0"); + program.add_argument("-c", "--config").help("Path to YAML switch configuration.").default_value("config.yml"); + program.add_argument("-v", "--verbose").help("Enable verbose mode").default_value(false).implicit_value(true); + + try{ + program.parse_args(argc, argv); + }catch(const std::runtime_error& err){ + std::cerr << err.what() << std::endl; + std::cerr << program; + std::exit(1); + } + + ryml::Tree config; + try{ + std::ifstream f; + std::stringstream buffer; + f.open(program.get("--config")); + + buffer << f.rdbuf(); + + config = ryml::parse(ryml::to_csubstr(buffer.str())); + }catch(const std::runtime_error& err){ + std::cerr << err.what() << std::endl; + std::cerr << program; + std::exit(1); + } + + if(config.empty()){ + std::cerr << "Empty config file" << std::endl; + std::cerr << program; + std::exit(1); + } + auto entries = PCIEDevice::DeviceEntry::find(); std::cout << "Found " << entries.size() << " FM10K management device(s)." << std::endl; @@ -35,11 +72,23 @@ int main() { std::cout << "dev.path: " << dev->getDeviceEntry().getPath() << std::endl; std::cout << "dev.vendor: " << tohex(dev->getDeviceEntry().getVendor()) << std::endl; std::cout << "dev.class: " << tohex(dev->getDeviceEntry().getClass()) << std::endl; + auto vpdHash = dev->getDeviceEntry().getVPDHash(); + std::cout << "dev.vpd_hash: " << vpdHash << std::endl; FM10K::FM10K fm10k(std::move(dev)); std::cout << "Device Model_Stepping: " << fm10k.getHardwareInformationString() << std::endl; + auto p = config.rootref()["platform"]; + if(p.is_map()){ //Match value + if(!p["device"].is_seed() && p["device"].val() != fm10k.getHardwareInformationString()){ + continue; + } + if(!p["device_vpd_hash"].is_seed() && p["device_vpd_hash"].val() != vpdHash){ + continue; + } + } + auto fuseData_0 = fm10k.mapRegister(); std::cout << "FUSE_DATA_0: " << tohex(fuseData_0->value) << std::endl; std::cout << "FUSE_DATA_0.VDDF_VRM: " << FM10K::VR12_VID_to_Millivolts(fuseData_0->fields.VDDS_VRM) << std::endl; @@ -48,29 +97,26 @@ int main() { auto deviceCfg = fm10k.mapRegister(); std::cout << "DEVICE_CFG: " << tohex(deviceCfg->value) << std::endl; - std::cout << "trying to initialize: "; + std::cout << "trying to initialize: " << std::endl; auto& port = fm10k.addPort(1, 1); port.m_portType = Port::PortType::EPL; port.m_interfaceType = Port::InterfaceType::QSFP_LANE0; - if(fm10k.initialize()){ + if(fm10k.initialize(config)){ std::cout << "success" << std::endl; signal(SIGINT, int_handler); signal(SIGTERM, int_handler); do{ - using namespace std::chrono_literals; std::this_thread::yield(); //TODO: check work - std::this_thread::sleep_for(1000ms); + FM10K::FM10K::wait(1000); } while (!stopLoop); - + break; }else{ std::cout << "fail" << std::endl; } - - break; } FM10K::IES::getInstance().teardown();