Skip to content

Commit

Permalink
Add support for recirc port and everflow (sonic-net#1530)
Browse files Browse the repository at this point in the history
This PR adds recirc port and Everflow support in distributed VOQ chassis.

What I did

Recirc prot changes:

portsyncd includes recirc ports in total port count.
portsyncd does not add recirc ports to g_portSet because no host intfs are created for recirc ports.
portsorch discovers recirc ports by checking port role setting and adds them correspondingly.
intforch supports adding rif for recirc ports.
Everflow changes:

mirrororch allows mirror dst port to be system port.
mirrororch sets mirror dst port to recirc port in voq switch.
mirrororch sets router mac as mirror dst mac in voq switch.
  • Loading branch information
ysmanman authored and raphaelt-nvidia committed Oct 5, 2021
1 parent 327b490 commit 98157b8
Show file tree
Hide file tree
Showing 4 changed files with 218 additions and 9 deletions.
31 changes: 29 additions & 2 deletions orchagent/mirrororch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ extern sai_port_api_t *sai_port_api;

extern sai_object_id_t gSwitchId;
extern PortsOrch* gPortsOrch;
extern string gMySwitchType;

using namespace std::rel_ops;

Expand Down Expand Up @@ -661,6 +662,10 @@ bool MirrorOrch::getNeighborInfo(const string& name, MirrorEntry& session)

return true;
}
case Port::SYSTEM:
{
return true;
}
default:
{
return false;
Expand Down Expand Up @@ -857,7 +862,21 @@ bool MirrorOrch::activateSession(const string& name, MirrorEntry& session)
else
{
attr.id = SAI_MIRROR_SESSION_ATTR_MONITOR_PORT;
attr.value.oid = session.neighborInfo.portId;
// Set monitor port to recirc port in voq switch.
if (gMySwitchType == "voq")
{
Port recirc_port;
if (!m_portsOrch->getRecircPort(recirc_port, "Rec"))
{
SWSS_LOG_ERROR("Failed to get recirc prot");
return false;
}
attr.value.oid = recirc_port.m_port_id;
}
else
{
attr.value.oid = session.neighborInfo.portId;
}
attrs.push_back(attr);

attr.id = SAI_MIRROR_SESSION_ATTR_TYPE;
Expand Down Expand Up @@ -919,7 +938,15 @@ bool MirrorOrch::activateSession(const string& name, MirrorEntry& session)
attrs.push_back(attr);

attr.id = SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS;
memcpy(attr.value.mac, session.neighborInfo.mac.getMac(), sizeof(sai_mac_t));
// Use router mac as mirror dst mac in voq switch.
if (gMySwitchType == "voq")
{
memcpy(attr.value.mac, gMacAddress.getMac(), sizeof(sai_mac_t));
}
else
{
memcpy(attr.value.mac, session.neighborInfo.mac.getMac(), sizeof(sai_mac_t));
}
attrs.push_back(attr);

attr.id = SAI_MIRROR_SESSION_ATTR_GRE_PROTOCOL_TYPE;
Expand Down
114 changes: 111 additions & 3 deletions orchagent/portsorch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2231,10 +2231,15 @@ string PortsOrch::getPriorityGroupDropPacketsFlexCounterTableKey(string key)
return string(PG_DROP_STAT_COUNTER_FLEX_COUNTER_GROUP) + ":" + key;
}

bool PortsOrch::initPort(const string &alias, const int index, const set<int> &lane_set)
bool PortsOrch::initPort(const string &alias, const string &role, const int index, const set<int> &lane_set)
{
SWSS_LOG_ENTER();

if (role == "Rec" || role == "Inb")
{
return doProcessRecircPort(alias, role, lane_set, SET_COMMAND);
}

/* Determine if the lane combination exists in switch */
if (m_portListLaneMap.find(lane_set) != m_portListLaneMap.end())
{
Expand Down Expand Up @@ -2491,6 +2496,7 @@ void PortsOrch::doPortTask(Consumer &consumer)
string an_str;
int an = -1;
int index = -1;
string role;
string adv_speeds_str;
string interface_type_str;
string adv_interface_types_str;
Expand Down Expand Up @@ -2648,12 +2654,18 @@ void PortsOrch::doPortTask(Consumer &consumer)
getPortSerdesVal(fvValue(i), attr_val);
serdes_attr.insert(serdes_attr_pair(SAI_PORT_SERDES_ATTR_TX_FIR_ATTN, attr_val));
}

/* Get port role */
if (fvField(i) == "role")
{
role = fvValue(i);
}
}

/* Collect information about all received ports */
if (lane_set.size())
{
m_lanesAliasSpeedMap[lane_set] = make_tuple(alias, speed, an, fec_mode, index);
m_lanesAliasSpeedMap[lane_set] = make_tuple(alias, speed, an, fec_mode, index, role);
}

// TODO:
Expand Down Expand Up @@ -2695,7 +2707,7 @@ void PortsOrch::doPortTask(Consumer &consumer)
}
}

if (!initPort(get<0>(it->second), get<4>(it->second), it->first))
if (!initPort(get<0>(it->second), get<5>(it->second), get<4>(it->second), it->first))
{
throw runtime_error("PortsOrch initialization failure.");
}
Expand Down Expand Up @@ -2739,6 +2751,15 @@ void PortsOrch::doPortTask(Consumer &consumer)
}
else
{
/* Skip configuring recirc port for now because the current SAI implementation of some vendors
* have limiited support for recirc port. This check can be removed once SAI implementation
* is enhanced/changed in the future.
*/
if (m_recircPortRole.find(alias) != m_recircPortRole.end())
{
it = consumer.m_toSync.erase(it);
continue;
}

if (!an_str.empty())
{
Expand Down Expand Up @@ -5870,6 +5891,93 @@ bool PortsOrch::getSystemPorts()
return true;
}

bool PortsOrch::getRecircPort(Port &port, string role)
{
for (auto it = m_recircPortRole.begin(); it != m_recircPortRole.end(); it++)
{
if (it->second == role)
{
return getPort(it->first, port);
}
}
SWSS_LOG_ERROR("Failed to find recirc port with role %s", role.c_str());
return false;
}

bool PortsOrch::doProcessRecircPort(string alias, string role, set<int> lane_set, string op)
{
SWSS_LOG_ENTER();

if (op == SET_COMMAND)
{
if (m_recircPortRole.find(alias) != m_recircPortRole.end())
{
SWSS_LOG_DEBUG("Recirc port %s already added", alias.c_str());
return true;
}

/* Find pid of recirc port */
sai_object_id_t port_id = SAI_NULL_OBJECT_ID;
if (m_portListLaneMap.find(lane_set) != m_portListLaneMap.end())
{
port_id = m_portListLaneMap[lane_set];
}

if (port_id == SAI_NULL_OBJECT_ID)
{
SWSS_LOG_ERROR("Failed to find port id for recirc port %s", alias.c_str());
return false;
}

Port p(alias, Port::PHY);
p.m_port_id = port_id;
p.m_init = true;
m_recircPortRole[alias] = role;
setPort(alias, p);

string lane_str = "";
for (auto lane : lane_set)
{
lane_str += to_string(lane) + " ";
}
SWSS_LOG_NOTICE("Added recirc port %s, pid:%" PRIx64 " lanes:%s",
alias.c_str(), port_id, lane_str.c_str());

/* Create host intf for recirc port */
if(addHostIntfs(p, p.m_alias, p.m_hif_id))
{
SWSS_LOG_NOTICE("Created host intf for recycle port %s", p.m_alias.c_str());
}
else
{
SWSS_LOG_ERROR("Failed to Create host intf for recirc port %s", p.m_alias.c_str());
}

if(setHostIntfsOperStatus(p, true))
{
SWSS_LOG_NOTICE("Set host intf oper status UP for recirc port %s", p.m_alias.c_str());
}
else
{
SWSS_LOG_ERROR("Failed to set host intf oper status for recirc port %s", p.m_alias.c_str());
}

PortUpdate update = { p, true };
notify(SUBJECT_TYPE_PORT_CHANGE, static_cast<void *>(&update));
return true;
}
else if (op == DEL_COMMAND)
{
SWSS_LOG_ERROR("Delete recirc port is not supported.");
return false;
}
else
{
SWSS_LOG_ERROR("Unknown operation type %s", op.c_str());
return false;
}
}

bool PortsOrch::addSystemPorts()
{
vector<string> keys;
Expand Down
11 changes: 7 additions & 4 deletions orchagent/portsorch.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ class PortsOrch : public Orch, public Subject
bool isInbandPort(const string &alias);
bool setVoqInbandIntf(string &alias, string &type);

bool getRecircPort(Port &p, string role);

private:
unique_ptr<Table> m_counterTable;
unique_ptr<Table> m_counterLagTable;
Expand Down Expand Up @@ -209,7 +211,7 @@ class PortsOrch : public Orch, public Subject
port_config_state_t m_portConfigState = PORT_CONFIG_MISSING;
sai_uint32_t m_portCount;
map<set<int>, sai_object_id_t> m_portListLaneMap;
map<set<int>, tuple<string, uint32_t, int, string, int>> m_lanesAliasSpeedMap;
map<set<int>, tuple<string, uint32_t, int, string, int, string>> m_lanesAliasSpeedMap;
map<string, Port> m_portList;
unordered_map<sai_object_id_t, int> m_portOidToIndex;
map<string, uint32_t> m_port_ref_count;
Expand Down Expand Up @@ -255,7 +257,7 @@ class PortsOrch : public Orch, public Subject

bool addPort(const set<int> &lane_set, uint32_t speed, int an=0, string fec="");
sai_status_t removePort(sai_object_id_t port_id);
bool initPort(const string &alias, const int index, const set<int> &lane_set);
bool initPort(const string &alias, const string &role, const int index, const set<int> &lane_set);
void deInitPort(string alias, sai_object_id_t port_id);

bool setPortAdminStatus(Port &port, bool up);
Expand Down Expand Up @@ -315,8 +317,9 @@ class PortsOrch : public Orch, public Subject
void initGearbox();
bool initGearboxPort(Port &port);



map<string, string> m_recircPortRole;
bool doProcessRecircPort(string alias, string role, set<int> laneSet, string op);

//map key is tuple of <attached_switch_id, core_index, core_port_index>
map<tuple<int, int, int>, sai_object_id_t> m_systemPortOidMap;
sai_uint32_t m_systemPortCount;
Expand Down
71 changes: 71 additions & 0 deletions tests/test_port_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import pytest

from swsscommon import swsscommon
from dvslib.dvs_common import wait_for_result, PollingConfig


@pytest.yield_fixture
Expand Down Expand Up @@ -154,6 +155,76 @@ def test_port_breakout(self, dvs, port_config):
assert hw_lane_value, "Can't get hw_lane list"
assert hw_lane_value == "1:%s" % (new_lanes[i])

def test_recirc_port(self, dvs):

# Get port config from configDB
cfg_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0)
cfg_port_tbl = swsscommon.Table(cfg_db, swsscommon.CFG_PORT_TABLE_NAME)

indexes = []
lanes = []
keys = cfg_port_tbl.getKeys()
for port in keys:
(status, fvs) = cfg_port_tbl.get(port)
assert(status == True)

for fv in fvs:
if fv[0] == "index":
indexes.append(int(fv[1]))
if fv[0] == "lanes":
lanes.extend([int(lane) for lane in fv[1].split(",")])

# Stop swss before modifing the configDB
dvs.stop_swss()
time.sleep(1)

recirc_port_lane_base = max(lanes) + 1
recirc_port_index_base = max(indexes) + 1

# Add recirc ports to port config in configDB
recirc_port_lane_name_map = {}
for i in range(2):
name = alias = "Ethernet-Rec%s" % i
fvs = swsscommon.FieldValuePairs([("role", "Rec" if i % 2 == 0 else "Inb"),
("alias", alias),
("lanes", str(recirc_port_lane_base + i)),
("speed", "10000"),
("index", str(recirc_port_index_base + i))])
cfg_port_tbl.set(name, fvs)

# Start swss
dvs.start_swss()
time.sleep(5)

polling_config = PollingConfig(polling_interval=0.1, timeout=15, strict=True)

# Verify recirc ports in port table in applDB
for i in range(2):
name = alias = "Ethernet-Rec%s" % i
dvs.get_app_db().wait_for_field_match(swsscommon.APP_PORT_TABLE_NAME, name,
{"role" : "Rec" if i % 2 == 0 else "Inb",
"alias" : name,
"lanes" : str(recirc_port_lane_base + i),
"speed" : "10000",
"index" : str(recirc_port_index_base + i) },
polling_config=polling_config)

# Verify recirc port lanes in asicDB
asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0)
asic_db_lanes_tbl = swsscommon.Table(asic_db, "LANES")

def _access_function():
lanes = asic_db_lanes_tbl.get('')[1]
if len(lanes) == 0:
return (False, None)

recirc_port_lanes = [recirc_port_lane_base, recirc_port_lane_base + 1]
for lane in lanes:
lane_num = int(lane[0])
if int(lane_num) in recirc_port_lanes:
recirc_port_lanes.remove( lane_num )
return (not recirc_port_lanes, None)
wait_for_result(_access_function, polling_config=polling_config)



Expand Down

0 comments on commit 98157b8

Please sign in to comment.