WiP: routing, ACL
All checks were successful
continuous-integration/drone/push Build is passing

Add pause frames
This commit is contained in:
DataHoarder 2021-11-15 19:32:03 +01:00
parent ea9346da22
commit 53abacd806
6 changed files with 690 additions and 18 deletions

View file

@ -14,7 +14,7 @@ platform:
# Required to have working double VLAN tagging on PCIe ports
#- ["api.port.allowFtagVlanTagging", "bool", "true"]
#- ["api.platform.config.debug", "text", "CONFIG,MOD_STATE,MOD_LED,MOD_INTR,MOD_TYPE,PLAT_LOG"]
#- ["api.platform.config.debug", "text", "MOD_STATE,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"]
@ -33,6 +33,171 @@ platform:
#- ["api.platform.config.switch.0.portIndex.7.ethernetMode", "text", "10GBase-SR"]
#- ["api.platform.config.switch.0.portIndex.8.ethernetMode", "text", "10GBase-SR"]
router:
attributes:
mac:
# The MAC address of the physical router. Default is 0x000000000000.
# This MAC address is used for virtual router 0.
#real: 0x100000000000
# The Mac address of the virtual router. Default is 0x000000000000.
# This MAC address is used for virtual routers 1 -255.
# The least significant 8 bits are ignored and are replaced by the virtual router number, as used in routes, ARPs, etc.
#virtual1: 0x200000000000
# The second Mac address of the virtual router. Default is 0x000000000000.
# This MAC address may be used for virtual routers 1 -255.
# In order to configure a virtual router to use the second MAC address its MAC mode needs to be updated by ''fmSetRouterMacMode''
#virtual2: 0x300000000000
#routers:
#-
# 0 for real, 1+ for virtual
#kind: 0
# physical, virtual1, virtual2, virtual12
#mac_mode: physical
#routes:
#-
# unicast, TODO: unicast_ecmp, multicast
#type: unicast
# Destination IP address
#destination: 12.12.12.0
# Mask prefix length
#mask: 24
# Next hop IP address.
#next_hop: 10.0.1.1
# Next hop Interface IP address.
#interface: 10.0.2.1
# Next hop Vlan. Only used if interface == 0
#vlan: 1
acls:
#-
#acl: 1
# bitmask of matching scenario values.
# Allowed:
# default: FRAME_ANY | ROUTING_ANY
# FRAME_NONIP, FRAME_IPV4, FRAME_IPV6, FRAME_ANY
# ROUTING_SWITCHED, ROUTING_UNICAST, ROUTING_MULTICAST, ROUTING_ANY
# GLORT_SWITCHED, GLORT_UNICAST, GLORT_MULTICAST, GLORT_ANY
# SPECIAL_GLORT_FTYPE
#scenarios: [FRAME_ANY, ROUTING_ANY]
# Range 0-7(max). Default 4
#precedence: 4
#rules:
#-
# Rule number, also used as rule precedence. Higher numbers have higher precedence.
#rule: 100
# Any conditions specified will be matched against. This will also set the mask. Set in the form of [value, mask] or just value to have mask set to equal. Leave empty to match all.
#match:
#logical:
#switch_priority
# See ''ACL Scenario Flags''
#scenario_flags
# Single logical source port
#src_port
#l2:
# Match the source/destination MAC address.
#src_mac:
#dst_mac:
# Match the Ethernet type.
#ethertype:
# Match the VLAN ID.
#vlan:
# Match the VLAN priority
#priority:
#vlan2
#priority2
#isl_ftype
#isl_user
#l3:
# Match the source/destination IP address
#src_ip:
#dst_ip:
# Match the TTL field in an IPv4 header or Hop Limit in an IPv6 header.
#ttl:
# Match the L4 protocol (IPv4) or Next Header (IPv6).
#protocol:
# 1: An IP option was flagged
# 2: The Don't Fragment bit from the IPv4 header.
# 4: The frame is the first fragment.
# 8: The frame is not the last fragment.
#flags:
# Match the differentiated services code point - the six most significant bits of the Type of Service octet (IPv4) or Traffic Class octet (IPv6).
#dscp
# Hex data and mask, DPI
#non_ip_payload:
# Match the Type of Service octet (IPv4) or Traffic Class octet (IPv6).
#tos
# non_ip, ipv4, ipv6
#frame_type
#l4:
# must be paired with l3.protocol, DPI
#tcp_flags:
# Match on a TCP/UDP source/destination port with a mask.
#src_port
#dst_port
# see L4DeepInspectionExt. Continues off non_ip_payload
#dpi:
# TODO:
# Match on ingress logical port set.
#logical_ingress_port_set: TODO
#vlan_tag_type TODO
#source_port_map
#protocol_map
#l4_src_port_map:
#l4_dst_port_map:
#src_mac_map:
#dst_mac_map:
#eth_type_map:
#ip_length_map
#src_ip_map:
#dst_ip_map:
#src_glort
#frag
#vlan_map
# See ''ACL Extended Action Masks''
# permit, deny, trap, log, count, trap_always, noroute, pop_vlan, capture_egress_timestamp
#action: [permit]
#set:
#police: TODO
#vlan:
#priority:
#switch_priority:
#dscp:
#user:
#user_mask:
#load_balance:
#redirect:
#flood_destination:
#route_ecmp:
#mirror_group:
#precedence:
#push_vlan:
#trig_id: WHAT??? TODO
#redirect_tunnel: WHAT??? TODO
#update_or_add_vlan:
switch:
attributes:
# Frame timeout in milliseconds. see FM_FRAME_AGING_TIME_MSEC
@ -47,6 +212,9 @@ switch:
# shared (default), per_vlan, multiple (not supported?)
#stp_mode: shared
qos:
#auto_pause: true
lag:
# static (default, static groups, discard), dynamic (pass to application)
#mode: static
@ -54,14 +222,14 @@ switch:
vlan_learning:
# VLAN learning mode. Values: independent (default), shared
mode: independent
#mode: independent
# The VLAN to learn on when mode is shared (default 1)
vlan: 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
#cpu_mac: 0x000000000000
#8021x: true
#bpdu: true
#lacp: true
@ -71,19 +239,19 @@ switch:
# Broadcast flooding control. Values: forward, discard, forward_without_cpu (default), per_port
broadcast_flooding: forward
#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
#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.
# For FM10000 devices, this attribute must be set to ''forward'' to ensure that the VLAN information retrieved from a packet received from a PEP port is properly forwarded in the FTAG of the egress packet going to the CPU port.
# If the ''port.unicast.flooding'' port attribute is used instead to forward unknown unicast packets to the CPU port, the VLAN information will not be preserved when such packets are forwarded to the CPU port.
# Unicast flooding control. Values: forward, discard, forward_without_cpu (default), per_port
unicast_flooding: forward
#unicast_flooding: forward
# Must create vlans so they exist
vlans:
@ -100,8 +268,6 @@ vlans:
# Default false
routable: false
#TODO: trap_igmp + FM_PORT_PARSER
-
id: 2
attributes:
@ -176,9 +342,9 @@ ports:
parser:
# How far in OSI model packets are parsed before stopping.
# l2 (default)
# l2
# 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.
# l4 - Set 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.
@ -188,6 +354,10 @@ ports:
# Setting to true sends the VID2 first, then VID1 second.
# Setting to false (default) sends the VID1 first, VID2 second.
#first_vid2: false
pause:
# default disabled
#rx: true
#tx: 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.
@ -276,6 +446,7 @@ ports:
max_frame_size: 9036
# none (default), sgmii, clause37, clause73
#autonegotiation: clause73
#eth_mode: 40G-SR4
-
# CPU port definitions

View file

@ -5,6 +5,7 @@
#include <chrono>
#include <thread>
#include <iostream>
#include <netdb.h>
#include "ryml.hpp"
#include "c4/std/string.hpp"
#include "IES_SDK.h"
@ -84,6 +85,10 @@ void FM10K::FM10K::wait(uint32_t microseconds) {
std::this_thread::sleep_for(std::chrono::microseconds(microseconds));
}
void FM10K::FM10K::wait_ms(uint32_t milliseconds) {
std::this_thread::sleep_for(std::chrono::milliseconds (milliseconds));
}
void FM10K::FM10K::wait_ns(uint32_t nanoseconds) {
std::this_thread::sleep_for(std::chrono::nanoseconds (nanoseconds));
}
@ -240,11 +245,153 @@ static std::unordered_map<std::string, fm_int> AUTONEG_MAP = {
{"clause73", FM_PORT_AUTONEG_CLAUSE_73},
};
static std::unordered_map<std::string, fm_int> ETHMODE_MAP = {
{"10G-SR", FM_ETH_MODE_10GBASE_SR},
{"25G-SR", FM_ETH_MODE_25GBASE_SR},
{"40G-SR4", FM_ETH_MODE_40GBASE_SR4},
{"100G-SR4", FM_ETH_MODE_100GBASE_SR4},
};
static std::unordered_map<std::string, fm_int> ROUTE_ENTRY_TYPE_MAP = {
{"unicast", FM_ROUTE_TYPE_UNICAST},
{"unicast_ecmp", FM_ROUTE_TYPE_UNICAST_ECMP},
{"multicast", FM_ROUTE_TYPE_MULTICAST},
};
static std::unordered_map<std::string, fm_int> ROUTER_MAC_MODE_MAP = {
{"physical", FM_ROUTER_MAC_MODE_PHYSICAL_MAC_ADDRESS},
{"virtual1", FM_ROUTER_MAC_MODE_VIRTUAL_MAC_ADDRESS_1},
{"virtual2", FM_ROUTER_MAC_MODE_VIRTUAL_MAC_ADDRESS_1},
{"virtual12", FM_ROUTER_MAC_MODE_VIRTUAL_MAC_ADDRESS_1_AND_2},
};
static std::unordered_map<std::string, fm_int> ACL_FRAME_TYPE_MAP = {
{"non_ip", FM_ACL_FRAME_TYPE_NON_IP},
{"ipv4", FM_ACL_FRAME_TYPE_IPV4},
{"ipv6", FM_ACL_FRAME_TYPE_IPV6},
};
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);
}
fm_ipAddr stringToIpAddr(const char* ip){
struct addrinfo* addr;
if(getaddrinfo(ip, nullptr, nullptr, &addr) != 0){
throw std::runtime_error("Invalid address");
}
if(addr->ai_next != nullptr || (addr->ai_family != AF_INET && addr->ai_family != AF_INET6)){
freeaddrinfo(addr);
throw std::runtime_error("Invalid address type");
}
fm_ipAddr result;
result.isIPv6 = addr->ai_family == AF_INET6;
if(result.isIPv6){
auto ip6 = reinterpret_cast<struct sockaddr_in6*>(addr->ai_addr);
result.addr[0] = ip6->sin6_addr.s6_addr32[0];
result.addr[1] = ip6->sin6_addr.s6_addr32[1];
result.addr[2] = ip6->sin6_addr.s6_addr32[2];
result.addr[3] = ip6->sin6_addr.s6_addr32[3];
}else{
auto ip4 = reinterpret_cast<struct sockaddr_in*>(addr->ai_addr);
result.addr[0] = ip4->sin_addr.s_addr;
}
freeaddrinfo(addr);
return result;
}
std::vector<uint8_t> HexToBytes(const std::string& hex) {
std::vector<uint8_t> bytes;
for (unsigned int i = 0; i < hex.length(); i += 2) {
std::string byteString = hex.substr(i, 2);
char byte = (char) strtol(byteString.c_str(), NULL, 16);
bytes.push_back(byte);
}
return std::move(bytes);
}
template <typename T>
void setACLMatchValueMask(const ryml::NodeRef& node, T& value, T& mask){
if(node.is_seq()){
if constexpr(std::is_same_v<T, fm_ipAddr>){
value = static_cast<T>(stringToIpAddr(getYAMLString(node[0]).c_str()));
mask = static_cast<T>(stringToIpAddr(getYAMLString(node[1]).c_str()));
}else if constexpr(std::is_array<T>::value && std::is_same_v<std::remove_extent<T>, uint8_t>) {
auto data = HexToBytes(getYAMLString(node[0]));
auto mask_v = HexToBytes(getYAMLString(node[1]));
assert((data.size() / sizeof(std::remove_extent<T>)) < sizeof(T));
assert((mask_v.size() / sizeof(std::remove_extent<T>)) < sizeof(T));
for(auto i = 0; i < sizeof(T); ++i){
value[i] = i < data.size() ? data[i] : 0;
mask[i] = i < mask_v.size() ? mask_v[i] : 0;
}
}else if constexpr( sizeof(T) == 1){
value = static_cast<T>(getYAMLUnsignedInteger(node[0]) & 0xFF);
mask = static_cast<T>(getYAMLUnsignedInteger(node[1]) & 0xFF);
}else if constexpr( sizeof(T) == 2){
value = static_cast<T>(getYAMLUnsignedInteger(node[0]) & 0xFFFF);
mask = static_cast<T>(getYAMLUnsignedInteger(node[1]) & 0xFFFF);
}else if constexpr( sizeof(T) == 4){
value = static_cast<T>(getYAMLUnsignedInteger(node[0]));
mask = static_cast<T>(getYAMLUnsignedInteger(node[1]));
}else if constexpr (sizeof(T) == 8){
value = static_cast<T>(getYAMLUnsignedInteger64(node[0]));
mask = static_cast<T>(getYAMLUnsignedInteger64(node[1]));
}else{
std::abort();
}
}else{
//No mask set
if constexpr(std::is_same_v<T, fm_ipAddr>){
value = static_cast<T>(stringToIpAddr(getYAMLString(node).c_str()));
auto ptr = reinterpret_cast<unsigned char*>(&mask.addr);
std::fill(ptr, ptr + sizeof(mask), 0xFF);
mask.isIPv6 = value.isIPv6;
}else if constexpr(std::is_array<T>::value && std::is_same_v<std::remove_extent<T>, uint8_t>) {
auto data = HexToBytes(getYAMLString(node));
assert((data.size() / sizeof(std::remove_extent<T>)) < sizeof(T));
for(auto i = 0; i < sizeof(T); ++i){
value[i] = i < data.size() ? data[i] : 0;
mask[i] = 0xFF;
}
}else if constexpr( sizeof(T) == 1){
auto ptr = reinterpret_cast<unsigned char*>(&mask);
std::fill(ptr, ptr + sizeof(mask), 0xFF);
value = static_cast<T>(getYAMLUnsignedInteger(node) & 0xFF);
}else if constexpr( sizeof(T) == 2){
auto ptr = reinterpret_cast<unsigned char*>(&mask);
std::fill(ptr, ptr + sizeof(mask), 0xFF);
value = static_cast<T>(getYAMLUnsignedInteger(node) & 0xFFFF);
}else if constexpr( sizeof(T) == 4){
auto ptr = reinterpret_cast<unsigned char*>(&mask);
std::fill(ptr, ptr + sizeof(mask), 0xFF);
value = static_cast<T>(getYAMLUnsignedInteger(node));
}else if constexpr (sizeof(T) == 8){
auto ptr = reinterpret_cast<unsigned char*>(&mask);
std::fill(ptr, ptr + sizeof(mask), 0xFF);
value = static_cast<T>(getYAMLUnsignedInteger64(node));
}else{
std::abort();
}
}
}
bool FM10K::FM10K::initialize(const ryml::Tree& tree) const {
auto& ies = IES::getInstance();
@ -366,6 +513,8 @@ bool FM10K::FM10K::initialize(const ryml::Tree& tree) const {
ies.fmSetPortAttribute(logicalPort, FM_PORT_ROUTABLE, getYAMLBool(attr, isSpecialPort));
}else if(key == "autonegotiation" && isEplPort){
ies.fmSetPortAttribute(logicalPort, FM_PORT_AUTONEG, getMapState(getYAMLString(attr, "none"), AUTONEG_MAP));
}else if(key == "eth_mode" && isEplPort){
ies.fmSetPortAttribute(logicalPort, FM_PORT_ETHERNET_INTERFACE_MODE, getMapState(getYAMLString(attr, "none"), ETHMODE_MAP));
}else if (key == "tagging" && attr.is_map()){
for(auto attr2 : attr){
std::string key2;
@ -428,7 +577,18 @@ bool FM10K::FM10K::initialize(const ryml::Tree& tree) const {
}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));
ies.fmSetPortAttribute(logicalPort, FM_PORT_PARSER, getMapState(getYAMLString(attr2, "l4"), PARSER_MODE_MAP));
}
}
}else if (key == "pause" && attr.is_map()){
for(auto attr2 : attr){
std::string key2;
c4::from_chars(attr2.key(), &key2);
if(key2 == "rx"){
ies.fmSetPortAttribute(logicalPort, FM_PORT_RX_PAUSE, getYAMLBool(attr2, false));
}else if(key2 == "tx"){
ies.fmSetPortAttribute(logicalPort, FM_PORT_TX_PAUSE, getYAMLBool(attr2, false));
}
}
}else if (key == "update" && attr.is_map()){
@ -528,9 +688,9 @@ bool FM10K::FM10K::initialize(const ryml::Tree& tree) const {
<< (isCpuPort ? " cpu" : "")
<< std::endl;
if(!isInternalPort){
ies.fmSetPortState(logicalPort, FM_PORT_STATE_UP, 0);
}
ies.fmSetPortState(logicalPort, FM_PORT_STATE_UP, 0);
wait_ms(1000);
for(const auto& entryKind : std::vector<std::string>({"default", "eth", "pcie", "special", "internal", "cpu"})){
if(entryKind != "internal" && isInternalPort){
@ -633,6 +793,18 @@ bool FM10K::FM10K::initialize(const ryml::Tree& tree) const {
}
}else if(key == "stp_mode"){
ies.fmSetSwitchAttribute(FM_SPANNING_TREE_MODE, getMapState(getYAMLString(attr, "shared"), STP_MODE));
}else if(key == "qos"){
for(auto attr2 : attr){
std::string key2;
c4::from_chars(attr2.key(), &key2);
if(key2 == "auto_pause"){
auto val = getYAMLBool(attr2, true);
if(fmSetSwitchQOS(ies.fmGetSwitch(), FM_AUTO_PAUSE_MODE, 0, &val) != FM_OK){
std::abort();
}
}
}
}
}
}
@ -641,6 +813,304 @@ bool FM10K::FM10K::initialize(const ryml::Tree& tree) const {
}
if(!root["acls"].is_seed() && root["acls"].is_map()){
for(auto aclEntry : root["acls"]){
auto acl = getYAMLInteger(aclEntry["acl"], 1);
fm_uint32 scenarios = FM_ACL_SCENARIO_ANY_FRAME_TYPE | FM_ACL_SCENARIO_ANY_ROUTING_TYPE;
if(!aclEntry["scenarios"].is_seed() && aclEntry["scenarios"].is_seq()){
for(auto s : aclEntry["scenarios"]){
if(s == "FRAME_NONIP"){
scenarios |= FM_ACL_SCENARIO_NONIP;
}else if(s == "FRAME_IPV4"){
scenarios |= FM_ACL_SCENARIO_IPv4;
}else if(s == "FRAME_IPV6"){
scenarios |= FM_ACL_SCENARIO_IPv6;
}else if(s == "FRAME_ANY"){
scenarios |= FM_ACL_SCENARIO_ANY_FRAME_TYPE;
}else if(s == "ROUTING_SWITCHED"){
scenarios |= FM_ACL_SCENARIO_SWITCHED;
}else if(s == "ROUTING_UNICAST"){
scenarios |= FM_ACL_SCENARIO_UNICAST_ROUTED;
}else if(s == "ROUTING_MULTICAST"){
scenarios |= FM_ACL_SCENARIO_MULTICAST_ROUTED;
}else if(s == "ROUTING_ANY"){
scenarios |= FM_ACL_SCENARIO_ANY_ROUTING_TYPE;
}else if(s == "GLORT_SWITCHED"){
scenarios |= FM_ACL_SCENARIO_SWITCHED_GLORT;
}else if(s == "GLORT_UNICAST"){
scenarios |= FM_ACL_SCENARIO_UCAST_ROUTED_GLORT;
}else if(s == "GLORT_MULTICAST"){
scenarios |= FM_ACL_SCENARIO_MCAST_ROUTED_GLORT;
}else if(s == "GLORT_ANY"){
scenarios |= FM_ACL_SCENARIO_ANY_ROUTING_GLORT_TYPE;
}else if(s == "SPECIAL_GLORT_FTYPE"){
scenarios |= FM_ACL_SCENARIO_SPECIAL_GLORT;
}
}
}
auto precedence = getYAMLInteger(aclEntry["precedence"], FM_ACL_DEFAULT_PRECEDENCE);
if(fmCreateACLExt(ies.fmGetSwitch(), acl, scenarios, precedence) != FM_OK){
std::abort();
}
if (!aclEntry["rules"].is_seed() && aclEntry["rules"].is_seq()){
for(auto ruleEntry : aclEntry["rules"]){
auto rule = getYAMLInteger(ruleEntry["rule"]);
fm_aclCondition condition{};
fm_aclValue value{};
fm_aclActionExt action{};
fm_aclParamExt param{};
#define ACL_VMASK(c, k) \
condition |= c; \
setACLMatchValueMask(attr2, value. k, value. k ## Mask);
for(auto attr : ruleEntry["match"]) {
std::string key;
c4::from_chars(attr.key(), &key);
if (key == "logical" && attr.is_map()){
for(auto attr2 : attr){
std::string key2;
c4::from_chars(attr2.key(), &key2);
if(key2 == "switch_priority"){
ACL_VMASK(FM_ACL_MATCH_SWITCH_PRIORITY, switchPri);
}else if(key2 == "scenario_flags"){
ACL_VMASK(FM_ACL_MATCH_SCENARIO_FLAGS, scenarioFlags);
}else if(key2 == "src_port"){
condition |= FM_ACL_MATCH_SRC_PORT;
typeof(value.logicalPort) mask;//[sizeof(value.fType) / sizeof(std::remove_extent<typeof(value.fType)>)];
setACLMatchValueMask(attr2, value.logicalPort, mask);
}
}
}else if (key == "l2" && attr.is_map()){
for(auto attr2 : attr){
std::string key2;
c4::from_chars(attr2.key(), &key2);
if(key2 == "src_mac"){
ACL_VMASK(FM_ACL_MATCH_SRC_MAC, src);
}else if(key2 == "dst_mac"){
ACL_VMASK(FM_ACL_MATCH_DST_MAC, dst);
}else if(key2 == "ethertype"){
ACL_VMASK(FM_ACL_MATCH_ETHERTYPE, ethType);
}else if(key2 == "vlan"){
ACL_VMASK(FM_ACL_MATCH_VLAN, vlanId);
}else if(key2 == "priority"){
ACL_VMASK(FM_ACL_MATCH_PRIORITY, vlanPri);
}else if(key2 == "vlan2"){
ACL_VMASK(FM_ACL_MATCH_VLAN2, vlanId2);
}else if(key2 == "priority2"){
ACL_VMASK(FM_ACL_MATCH_PRIORITY2, vlanPri2);
}else if(key2 == "isl_ftype"){
condition |= FM_ACL_MATCH_ISL_FTYPE;
typeof(value.fType) mask;//[sizeof(value.fType) / sizeof(std::remove_extent<typeof(value.fType)>)];
setACLMatchValueMask(attr2, value.fType, mask);
}else if(key2 == "isl_user"){
ACL_VMASK(FM_ACL_MATCH_ISL_USER, islUser);
}
}
}else if (key == "l3" && attr.is_map()){
for(auto attr2 : attr){
std::string key2;
c4::from_chars(attr2.key(), &key2);
if(key2 == "src_ip"){
ACL_VMASK(FM_ACL_MATCH_SRC_IP, srcIp);
}else if(key2 == "dst_ip"){
ACL_VMASK(FM_ACL_MATCH_DST_IP, dstIp);
}else if(key2 == "ttl"){
ACL_VMASK(FM_ACL_MATCH_TTL, ttl);
}else if(key2 == "protocol"){
ACL_VMASK(FM_ACL_MATCH_PROTOCOL, protocol);
}else if(key2 == "flags"){
ACL_VMASK(FM_ACL_MATCH_FLAGS, flags);
}else if(key2 == "dscp"){
ACL_VMASK(FM_ACL_MATCH_DSCP, dscp);
}else if(key2 == "non_ip_payload"){
ACL_VMASK(FM_ACL_MATCH_NON_IP_PAYLOAD, nonIPPayload);
}else if(key2 == "dpi"){
ACL_VMASK(FM_ACL_MATCH_L4_DEEP_INSPECTION_EXT, L4DeepInspectionExt);
}else if(key2 == "frame_type"){
condition |= FM_ACL_MATCH_FRAME_TYPE;
value.frameType = (fm_aclFrameType) getMapState(getYAMLString(attr2), ACL_FRAME_TYPE_MAP);
}
}
}else if (key == "l4" && attr.is_map()){
for(auto attr2 : attr){
std::string key2;
c4::from_chars(attr2.key(), &key2);
if(key2 == "src_port"){
condition |= FM_ACL_MATCH_L4_SRC_PORT_WITH_MASK;
setACLMatchValueMask(attr2, value.L4SrcStart, value.L4SrcMask);
}else if(key2 == "dst_port"){
condition |= FM_ACL_MATCH_L4_DST_PORT_WITH_MASK;
setACLMatchValueMask(attr2, value.L4DstStart, value.L4DstMask);
}else if(key2 == "tcp_flags"){
ACL_VMASK(FM_ACL_MATCH_TCP_FLAGS, tcpFlags);
}else if(key2 == "non_ip_payload"){
ACL_VMASK(FM_ACL_MATCH_NON_IP_PAYLOAD, nonIPPayload);
}
}
}
}
if(!ruleEntry["action"].is_seed() && ruleEntry["action"].is_seq()){
for(auto v : ruleEntry["action"]) {
if(v == "permit" || v == "allow"){
action |= FM_ACL_ACTIONEXT_PERMIT;
}else if(v == "deny"){
action |= FM_ACL_ACTIONEXT_DENY;
}else if(v == "trap"){
action |= FM_ACL_ACTIONEXT_TRAP;
}else if(v == "log"){
action |= FM_ACL_ACTIONEXT_LOG;
}else if(v == "count"){
action |= FM_ACL_ACTIONEXT_COUNT;
}else if(v == "trap_always"){
action |= FM_ACL_ACTIONEXT_TRAP_ALWAYS;
}else if(v == "noroute"){
action |= FM_ACL_ACTIONEXT_NOROUTE;
}else if(v == "pop_vlan"){
action |= FM_ACL_ACTIONEXT_POP_VLAN;
}else if(v == "capture_egress_timestamp"){
action |= FM_ACL_ACTIONEXT_CAPTURE_EGRESS_TIMESTAMP;
}
}
}
if(ruleEntry["set"].is_seed() && ruleEntry["set"].is_map()){
for(auto attr : ruleEntry["action"]) {
std::string key;
c4::from_chars(attr.key(), &key);
if(key == "police"){
action |= FM_ACL_ACTIONEXT_POLICE;
param.policer = getYAMLInteger(attr);
}else if(key == "vlan"){
action |= FM_ACL_ACTIONEXT_SET_VLAN;
param.vlan = getYAMLInteger(attr);
}else if(key == "priority"){
action |= FM_ACL_ACTIONEXT_SET_VLAN_PRIORITY;
param.vlanPriority = getYAMLInteger(attr);
}else if(key == "switch_priority"){
action |= FM_ACL_ACTIONEXT_SET_SWITCH_PRIORITY;
param.switchPriority = getYAMLInteger(attr);
}else if(key == "dscp"){
action |= FM_ACL_ACTIONEXT_SET_DSCP;
param.dscp = getYAMLInteger(attr);
}else if(key == "user"){
action |= FM_ACL_ACTIONEXT_SET_USER;
param.user = getYAMLInteger(attr);
}else if(key == "user_mask"){
action |= FM_ACL_ACTIONEXT_SET_USER;
param.userMask = getYAMLInteger(attr);
}else if(key == "load_balance"){
action |= FM_ACL_ACTIONEXT_LOAD_BALANCE;
param.lbgNumber = getYAMLInteger(attr);
}else if(key == "redirect"){
action |= FM_ACL_ACTIONEXT_REDIRECT;
param.logicalPort = getYAMLInteger(attr);
}else if(key == "flood_destination"){
action |= FM_ACL_ACTIONEXT_SET_FLOOD_DEST;
param.logicalPort = getYAMLInteger(attr);
}else if(key == "route_ecmp"){
action |= FM_ACL_ACTIONEXT_ROUTE;
param.groupId = getYAMLInteger(attr);
}else if(key == "mirror_group"){
action |= FM_ACL_ACTIONEXT_MIRROR_GRP;
param.mirrorGrp = getYAMLInteger(attr);
}else if(key == "precedence"){
action |= FM_ACL_ACTIONEXT_SET_PRECEDENCE;
param.precedence = getYAMLInteger(attr);
}else if(key == "push_vlan"){
action |= FM_ACL_ACTIONEXT_PUSH_VLAN;
param.vlan = getYAMLInteger(attr);
}else if(key == "update_or_add_vlan"){
action |= FM_ACL_ACTIONEXT_UPD_OR_ADD_VLAN;
param.vlan = getYAMLInteger(attr);
}
}
}
if(fmAddACLRuleExt(ies.fmGetSwitch(), acl, rule, condition, &value, action, &param) != FM_OK){
std::abort();
}
}
#undef ACL_VMASK
}
}
}
if(!root["router"].is_seed() && root["router"].is_map()){
if(!root["router"]["attributes"].is_seed() && root["router"]["attributes"].is_map()){
for(auto attr : root["router"]["attributes"]) {
std::string key;
c4::from_chars(attr.key(), &key);
if (key == "mac" && attr.is_map()){
for(auto attr2 : attr){
std::string key2;
c4::from_chars(attr2.key(), &key2);
if(key2 == "real"){
ies.fmSetRouterAttribute(FM_ROUTER_PHYSICAL_MAC_ADDRESS, static_cast<fm_macaddr>(getYAMLUnsignedInteger64(attr2, 0x000000000000)));
}else if(key2 == "virtual1"){
ies.fmSetRouterAttribute(FM_ROUTER_VIRTUAL_MAC_ADDRESS, static_cast<fm_macaddr>(getYAMLUnsignedInteger64(attr2, 0x000000000000)));
}else if(key2 == "virtual2"){
ies.fmSetRouterAttribute(FM_ROUTER_VIRTUAL_MAC_ADDRESS_2, static_cast<fm_macaddr>(getYAMLUnsignedInteger64(attr2, 0x000000000000)));
}
}
}
}
}
if(!root["router"]["routers"].is_seed() && root["router"]["routers"].is_seq()){
for(auto routerEntry : root["switch"]["routers"]) {
auto vrid = getYAMLInteger(routerEntry["kind"], 0);
if(vrid != 0){
if(fmCreateVirtualRouter(ies.fmGetSwitch(), vrid) != FM_OK){
std::abort();
}
}
if(!routerEntry["mac_mode"].is_seed()){
if(fmSetRouterMacMode(ies.fmGetSwitch(), vrid, (fm_routerMacMode) getMapState(getYAMLString(routerEntry["mac_mode"]), ROUTER_MAC_MODE_MAP)) != FM_OK){
std::abort();
}
}
if(!routerEntry["routes"].is_seed() && routerEntry["routes"].is_seq()){
for(auto routeEntry : routerEntry["routes"]) {
fm_routeEntry entry;
entry.routeType = (fm_routeType) getMapState(getYAMLString(routeEntry["type"], "unicast"), ROUTE_ENTRY_TYPE_MAP);
entry.data.unicast.dstAddr = stringToIpAddr(getYAMLString(routeEntry["destination"]).c_str());
entry.data.unicast.prefixLength = getYAMLInteger(routeEntry["mask"], entry.data.unicast.dstAddr.isIPv6 ? 64 : 32);
entry.data.unicast.nextHop = stringToIpAddr(getYAMLString(routeEntry["next_hop"]).c_str());
entry.data.unicast.interfaceAddr = stringToIpAddr(getYAMLString(routeEntry["interface"]).c_str());
entry.data.unicast.vlan = getYAMLInteger(routeEntry["vlan"], 0);
entry.data.unicast.vrid = vrid;
if(fmAddRoute(ies.fmGetSwitch(), &entry, FM_ROUTE_STATE_UP) != FM_OK){
std::abort();
}
}
}
}
}
}
std::cout << "Switch is UP, all ports are now enabled" << std::endl;
return true;

View file

@ -107,6 +107,7 @@ namespace FM10K{
std::string getHardwareInformationString() const;
static void wait(uint32_t microseconds);
static void wait_ms(uint32_t milliseconds);
static void wait_ns(uint32_t nanoseconds);
Port& addPort(uint32_t logicalPort, uint32_t physicalPort){

View file

@ -92,6 +92,10 @@ bool FM10K::IES::init() {
fm_timestamp wait = {3, 0};
fmCaptureSemaphore(&IES_Static::semaphore, &wait);
if(fmGetSwitchFirst(&IES_Static::sw) != FM_OK){
std::abort();
}
if(fmSetSwitchState(IES_Static::sw, true) != FM_OK){
std::abort();
}
@ -341,6 +345,24 @@ T FM10K::IES::fmGetSwitchAttribute(int attribute) const {
return parameter;
}
template<typename T>
void FM10K::IES::fmSetRouterAttribute(int attribute, T value) const {
auto status = ::fmSetRouterAttribute(IES_Static::sw, attribute, &value);
if(status != FM_OK){
throw IESException(status);
}
}
template<typename T>
T FM10K::IES::fmGetRouterAttribute(int attribute) const {
T parameter{};
auto status = ::fmGetRouterAttribute(IES_Static::sw, attribute, &parameter);
if(status != FM_OK){
throw IESException(status);
}
return parameter;
}
struct _fm_switchInfo FM10K::IES::fmGetSwitchInfo() const {
fm_switchInfo info{};
auto status = ::fmGetSwitchInfo(IES_Static::sw, &info);
@ -432,7 +454,7 @@ void FM10K::IES::iteratePorts(const std::function<void(int logicalPort, int phys
if(err != FM_OK){
std::abort();
}
for(fm_int cpi = 0; cpi < swInfo.numCardPorts; ++cpi){
for(fm_int cpi = 1; cpi < swInfo.numCardPorts; ++cpi){
fm_int logicalPort;
fm_int physicalPort;
if(::fmMapCardinalPort(IES_Static::sw, cpi, &logicalPort, &physicalPort) != FM_OK){
@ -470,7 +492,9 @@ 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;
template T FM10K::IES::fmGetSwitchAttribute(int attribute) const; \
template void FM10K::IES::fmSetRouterAttribute(int attribute, T value) const; \
template T FM10K::IES::fmGetRouterAttribute(int attribute) const;
CREATE_ATTRIBUTE_TYPE(bool)
CREATE_ATTRIBUTE_TYPE(fm_int)

View file

@ -86,6 +86,12 @@ namespace FM10K {
template<typename T>
T fmGetSwitchAttribute(int attribute) const;
template<typename T>
void fmSetRouterAttribute(int attribute, T value) const;
template<typename T>
T fmGetRouterAttribute(int attribute) const;
int fmGetSwitch() const;
private:

View file

@ -111,7 +111,7 @@ int main(int argc, char *argv[]) {
do{
std::this_thread::yield();
//TODO: check work
FM10K::FM10K::wait(1000);
FM10K::FM10K::wait_ms(1000);
} while (!stopLoop);
break;
}else{