diff --git a/configure.ac b/configure.ac index 8f14f83c789..a33396cd3c9 100644 --- a/configure.ac +++ b/configure.ac @@ -39,6 +39,11 @@ esac],[gtest=false]) AM_CONDITIONAL(GTEST, test x$gtest = xtrue) CFLAGS_COMMON="-std=c++11 -Wall -fPIC -Wno-write-strings -I/usr/include/libnl3 -I/usr/include/swss" + +AM_CONDITIONAL(sonic_asic_platform_barefoot, test x$CONFIGURED_PLATFORM = xbarefoot) +AM_COND_IF([sonic_asic_platform_barefoot], + [CFLAGS_COMMON+=" -I/opt/bfn/install/include/switchsai"]) + CFLAGS_COMMON+=" -Werror" CFLAGS_COMMON+=" -Wno-reorder" CFLAGS_COMMON+=" -Wcast-align" diff --git a/orchagent/Makefile.am b/orchagent/Makefile.am index 9327136c9ee..998d2926fe7 100644 --- a/orchagent/Makefile.am +++ b/orchagent/Makefile.am @@ -7,6 +7,7 @@ swssdir = $(datadir)/swss dist_swss_DATA = \ pfc_detect_mellanox.lua \ pfc_detect_broadcom.lua \ + pfc_detect_barefoot.lua \ pfc_restore.lua bin_PROGRAMS = orchagent routeresync diff --git a/orchagent/orch.h b/orchagent/orch.h index dc804c74487..b6ab60d8d5f 100644 --- a/orchagent/orch.h +++ b/orchagent/orch.h @@ -29,6 +29,7 @@ const char config_db_key_delimiter = '|'; #define MLNX_PLATFORM_SUBSTRING "mellanox" #define BRCM_PLATFORM_SUBSTRING "broadcom" +#define BFN_PLATFORM_SUBSTRING "barefoot" #define CONFIGDB_KEY_SEPARATOR "|" #define DEFAULT_KEY_SEPARATOR ":" diff --git a/orchagent/pfc_detect_barefoot.lua b/orchagent/pfc_detect_barefoot.lua new file mode 100644 index 00000000000..892be8b5fcb --- /dev/null +++ b/orchagent/pfc_detect_barefoot.lua @@ -0,0 +1,91 @@ +-- KEYS - queue IDs +-- ARGV[1] - counters db index +-- ARGV[2] - counters table name +-- ARGV[3] - poll time interval +-- return queue Ids that satisfy criteria + +local counters_db = ARGV[1] +local counters_table_name = ARGV[2] +local poll_time = tonumber(ARGV[3]) + +local rets = {} + +redis.call('SELECT', counters_db) + +-- Iterate through each queue +local n = table.getn(KEYS) +for i = n, 1, -1 do + local counter_keys = redis.call('HKEYS', counters_table_name .. ':' .. KEYS[i]) + local counter_num = 0 + local old_counter_num = 0 + local is_deadlock = false + local pfc_wd_status = redis.call('HGET', counters_table_name .. ':' .. KEYS[i], 'PFC_WD_STATUS') + local pfc_wd_action = redis.call('HGET', counters_table_name .. ':' .. KEYS[i], 'PFC_WD_ACTION') + if pfc_wd_status == 'operational' or pfc_wd_action == 'alert' then + local detection_time = tonumber(redis.call('HGET', counters_table_name .. ':' .. KEYS[i], 'PFC_WD_DETECTION_TIME')) + local time_left = redis.call('HGET', counters_table_name .. ':' .. KEYS[i], 'PFC_WD_DETECTION_TIME_LEFT') + if not time_left then + time_left = detection_time + else + time_left = tonumber(time_left) + end + + local queue_index = redis.call('HGET', 'COUNTERS_QUEUE_INDEX_MAP', KEYS[i]) + local port_id = redis.call('HGET', 'COUNTERS_QUEUE_PORT_MAP', KEYS[i]) + local pfc_rx_pkt_key = 'SAI_PORT_STAT_PFC_' .. queue_index .. '_RX_PKTS' + local pfc_on2off_key = 'SAI_PORT_STAT_PFC_' .. queue_index .. '_ON2OFF_RX_PKTS' + + + -- Get all counters + local occupancy_bytes = tonumber(redis.call('HGET', counters_table_name .. ':' .. KEYS[i], 'SAI_QUEUE_STAT_CURR_OCCUPANCY_BYTES')) + local packets = tonumber(redis.call('HGET', counters_table_name .. ':' .. KEYS[i], 'SAI_QUEUE_STAT_PACKETS')) + local pfc_rx_packets = tonumber(redis.call('HGET', counters_table_name .. ':' .. port_id, pfc_rx_pkt_key)) + local pfc_on2off = tonumber(redis.call('HGET', counters_table_name .. ':' .. port_id, pfc_on2off_key)) + local queue_pause_status = redis.call('HGET', counters_table_name .. ':' .. KEYS[i], 'SAI_QUEUE_ATTR_PAUSE_STATUS') + + local packets_last = redis.call('HGET', counters_table_name .. ':' .. KEYS[i], 'SAI_QUEUE_STAT_PACKETS_last') + local pfc_rx_packets_last = redis.call('HGET', counters_table_name .. ':' .. port_id, pfc_rx_pkt_key .. '_last') + local pfc_on2off_last = redis.call('HGET', counters_table_name .. ':' .. port_id, pfc_on2off_key .. '_last') + local queue_pause_status_last = redis.call('HGET', counters_table_name .. ':' .. KEYS[i], 'SAI_QUEUE_ATTR_PAUSE_STATUS_last') + + -- DEBUG CODE START. Uncomment to enable + local debug_storm = redis.call('HGET', counters_table_name .. ':' .. KEYS[i], 'DEBUG_STORM') + -- DEBUG CODE END. + + -- If this is not a first run, then we have last values available + if packets_last and pfc_rx_packets_last and pfc_on2off_last and queue_pause_status_last then + packets_last = tonumber(packets_last) + pfc_rx_packets_last = tonumber(pfc_rx_packets_last) + pfc_on2off_last = tonumber(pfc_on2off_last) + + -- Check actual condition of queue being in PFC storm + if (occupancy_bytes > 0 and packets - packets_last == 0 and pfc_rx_packets - pfc_rx_packets_last > 0) or + -- DEBUG CODE START. Uncomment to enable + (debug_storm == "enabled") or + -- DEBUG CODE END. + (occupancy_bytes == 0 and pfc_rx_packets - pfc_rx_packets_last > 0 and pfc_on2off - pfc_on2off_last == 0 and queue_pause_status_last == 'true' and queue_pause_status == 'true') then + if time_left <= poll_time then + redis.call('PUBLISH', 'PFC_WD', '["' .. KEYS[i] .. '","storm"]') + is_deadlock = true + time_left = detection_time + else + time_left = time_left - poll_time + end + else + if pfc_wd_action == 'alert' and pfc_wd_status ~= 'operational' then + redis.call('PUBLISH', 'PFC_WD', '["' .. KEYS[i] .. '","restore"]') + end + time_left = detection_time + end + end + + -- Save values for next run + redis.call('HSET', counters_table_name .. ':' .. KEYS[i], 'SAI_QUEUE_ATTR_PAUSE_STATUS_last', queue_pause_status) + redis.call('HSET', counters_table_name .. ':' .. KEYS[i], 'SAI_QUEUE_STAT_PACKETS_last', packets) + redis.call('HSET', counters_table_name .. ':' .. KEYS[i], 'PFC_WD_DETECTION_TIME_LEFT', time_left) + redis.call('HSET', counters_table_name .. ':' .. port_id, pfc_rx_pkt_key .. '_last', pfc_rx_packets) + redis.call('HSET', counters_table_name .. ':' .. port_id, pfc_on2off_key .. '_last', pfc_on2off) + end +end + +return rets diff --git a/orchagent/portsorch.cpp b/orchagent/portsorch.cpp index 853b925c5cd..cab6c4df047 100644 --- a/orchagent/portsorch.cpp +++ b/orchagent/portsorch.cpp @@ -16,7 +16,6 @@ #include "converter.h" #include "saiserialize.h" -#include "saiserialize.h" extern sai_switch_api_t *sai_switch_api; extern sai_bridge_api_t *sai_bridge_api; @@ -665,7 +664,6 @@ bool PortsOrch::validatePortSpeed(sai_object_id_t port_id, sai_uint32_t speed) bool PortsOrch::setPortSpeed(sai_object_id_t port_id, sai_uint32_t speed) { SWSS_LOG_ENTER(); - sai_attribute_t attr; sai_status_t status; @@ -728,6 +726,32 @@ bool PortsOrch::getQueueType(sai_object_id_t queue_id, string &type) return true; } +bool PortsOrch::setPortAutoNeg(sai_object_id_t id, int an) +{ + SWSS_LOG_ENTER(); + + sai_attribute_t attr; + attr.id = SAI_PORT_ATTR_AUTO_NEG_MODE; + switch(an) { + case 1: + attr.value.booldata = true; + break; + case 0: + default: + attr.value.booldata = false; + break; + } + + sai_status_t status = sai_port_api->set_port_attribute(id, &attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to set AN %u to port pid:%lx", attr.value.u32, id); + return false; + } + SWSS_LOG_INFO("Set AN %u to port pid:%lx", attr.value.u32, id); + return true; +} + bool PortsOrch::setHostIntfsOperStatus(sai_object_id_t port_id, bool up) { SWSS_LOG_ENTER(); @@ -771,7 +795,7 @@ void PortsOrch::updateDbPortOperStatus(sai_object_id_t id, sai_port_oper_status_ } } -bool PortsOrch::addPort(const set &lane_set, uint32_t speed) +bool PortsOrch::addPort(const set &lane_set, uint32_t speed, int an, string fec_mode) { SWSS_LOG_ENTER(); @@ -789,6 +813,20 @@ bool PortsOrch::addPort(const set &lane_set, uint32_t speed) attr.value.u32list.count = static_cast(lanes.size()); attrs.push_back(attr); + if (an == true) + { + attr.id = SAI_PORT_ATTR_AUTO_NEG_MODE; + attr.value.booldata = true; + attrs.push_back(attr); + } + + if (fec_mode != "") + { + attr.id = SAI_PORT_ATTR_FEC_MODE; + attr.value.u32 = fec_mode_map[fec_mode]; + attrs.push_back(attr); + } + sai_object_id_t port_id; sai_status_t status = sai_port_api->create_port(&port_id, gSwitchId, static_cast(attrs.size()), attrs.data()); if (status != SAI_STATUS_SUCCESS) @@ -939,6 +977,7 @@ void PortsOrch::doPortTask(Consumer &consumer) string fec_mode; uint32_t mtu = 0; uint32_t speed = 0; + int an = -1; for (auto i : kfvFieldsValues(t)) { @@ -953,6 +992,7 @@ void PortsOrch::doPortTask(Consumer &consumer) int lane = stoi(lane_str); lane_set.insert(lane); } + } /* Set port admin status */ @@ -970,12 +1010,16 @@ void PortsOrch::doPortTask(Consumer &consumer) /* Set port fec */ if (fvField(i) == "fec") fec_mode = fvValue(i); + + /* Set autoneg */ + if (fvField(i) == "autoneg") + an = (int)stoul(fvValue(i)); } /* Collect information about all received ports */ if (lane_set.size()) { - m_lanesAliasSpeedMap[lane_set] = make_tuple(alias, speed); + m_lanesAliasSpeedMap[lane_set] = make_tuple(alias, speed, an, fec_mode); } /* Once all ports received, go through the each port and perform appropriate actions: @@ -990,7 +1034,7 @@ void PortsOrch::doPortTask(Consumer &consumer) if (m_lanesAliasSpeedMap.find(it->first) == m_lanesAliasSpeedMap.end()) { char *platform = getenv("platform"); - if (platform && strstr(platform, MLNX_PLATFORM_SUBSTRING)) + if (platform && (strstr(platform, BFN_PLATFORM_SUBSTRING) || strstr(platform, MLNX_PLATFORM_SUBSTRING))) { if (!removePort(it->second)) { @@ -1019,9 +1063,9 @@ void PortsOrch::doPortTask(Consumer &consumer) // work around to avoid syncd termination on SAI error due missing create_port SAI API // can be removed when SAI redis return NotImplemented error char *platform = getenv("platform"); - if (platform && strstr(platform, MLNX_PLATFORM_SUBSTRING)) + if (platform && (strstr(platform, BFN_PLATFORM_SUBSTRING) || strstr(platform, MLNX_PLATFORM_SUBSTRING))) { - if (!addPort(it->first, get<1>(it->second))) + if (!addPort(it->first, get<1>(it->second), get<2>(it->second), get<3>(it->second))) { throw runtime_error("PortsOrch initialization failure."); } @@ -1138,6 +1182,21 @@ void PortsOrch::doPortTask(Consumer &consumer) } } + + if (an != -1) + { + if (setPortAutoNeg(p.m_port_id, an)) + { + SWSS_LOG_NOTICE("Set port %s AN to %u", alias.c_str(), an); + } + else + { + SWSS_LOG_ERROR("Failed to set port %s AN to %u", alias.c_str(), an); + it++; + continue; + } + } + if (fec_mode != "") { if (fec_mode_map.find(fec_mode) != fec_mode_map.end()) diff --git a/orchagent/portsorch.h b/orchagent/portsorch.h index 279833e214b..e5ed688eac7 100644 --- a/orchagent/portsorch.h +++ b/orchagent/portsorch.h @@ -15,6 +15,7 @@ typedef std::vector PortSupportedSpeeds; + static const map oper_status_strings = { { SAI_PORT_OPER_STATUS_UNKNOWN, "unknown" }, @@ -79,7 +80,7 @@ class PortsOrch : public Orch, public Subject bool m_portConfigDone = false; sai_uint32_t m_portCount; map, sai_object_id_t> m_portListLaneMap; - map, tuple> m_lanesAliasSpeedMap; + map, tuple> m_lanesAliasSpeedMap; map m_portList; void doTask(Consumer &consumer); @@ -113,7 +114,7 @@ class PortsOrch : public Orch, public Subject bool removeLagMember(Port &lag, Port &port); void getLagMember(Port &lag, vector &portv); - bool addPort(const set &lane_set, uint32_t speed); + bool addPort(const set &lane_set, uint32_t speed, int an=0, string fec=""); bool removePort(sai_object_id_t port_id); bool initPort(const string &alias, const set &lane_set); @@ -130,6 +131,9 @@ class PortsOrch : public Orch, public Subject bool getPortSpeed(sai_object_id_t port_id, sai_uint32_t &speed); bool getQueueType(sai_object_id_t queue_id, string &type); + + bool setPortAutoNeg(sai_object_id_t id, int an); + bool setPortFecMode(sai_object_id_t id, int fec); }; #endif /* SWSS_PORTSORCH_H */ diff --git a/portsyncd/portsyncd.cpp b/portsyncd/portsyncd.cpp index 943725f609a..32386eff89c 100644 --- a/portsyncd/portsyncd.cpp +++ b/portsyncd/portsyncd.cpp @@ -199,7 +199,7 @@ void handlePortConfigFile(ProducerStateTable &p, string file) throw "Port configuration file not found!"; } - list header = {"name", "lanes", "alias", "speed"}; + list header = {"name", "lanes", "alias", "speed", "autoneg", "fec"}; string line; while (getline(infile, line)) { @@ -254,6 +254,18 @@ void handlePortConfigFile(ProducerStateTable &p, string file) attrs.push_back(speed_attr); } + if ((entry.find("autoneg") != entry.end()) && (entry["autoneg"] != "")) + { + FieldValueTuple autoneg_attr("autoneg", entry["autoneg"]); + attrs.push_back(autoneg_attr); + } + + if ((entry.find("fec") != entry.end()) && (entry["fec"] != "")) + { + FieldValueTuple fec_attr("fec", entry["fec"]); + attrs.push_back(fec_attr); + } + p.set(entry["name"], attrs); g_portSet.insert(entry["name"]); diff --git a/tests/README.md b/tests/README.md index a18c1d906bb..6d051748630 100644 --- a/tests/README.md +++ b/tests/README.md @@ -12,8 +12,9 @@ SWSS Integration tests runs on docker-sonic-vs which runs on top of SAI virtual sudo pip install --system pytest==3.3.0 ``` - Compile and install swss common library - ```` + ``` cd sonic-swss-common + ./autogen.sh dpkg-buildpackage -us -uc -b dpkg -i ../libswsscommon_1.0.0_amd64.deb dpkg -i ../python-swsscommon_1.0.0_amd64.deb