Skip to content

Commit

Permalink
[mirrororch] ERSPAN supports LAG as a destination port.
Browse files Browse the repository at this point in the history
[portsorch] Add a function to return a linked-up member of an input LAG.

- What I did
    Support LAG as a destination port in a erspan session.
    In this case, detect the LAG member that is linked down and switch the destination port to a LAG member that is linked up.

- Why I did it
    Current ERSPAN does not support LAG as a destination port in a mirror session.
    The mirrororch is unaware of the LAG member port link up or down.

- How to verify it
    The community tests and manual tests pass.

Signed-off-by: sdn@inspur.com
  • Loading branch information
inspurSDN authored and waynelai committed Nov 24, 2022
1 parent dca78d8 commit 2741b7f
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 24 deletions.
162 changes: 138 additions & 24 deletions orchagent/mirrororch.cpp
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,12 @@ void MirrorOrch::update(SubjectType type, void *cntx)
updateVlanMember(*update);
break;
}
case SUBJECT_TYPE_PORT_OPER_STATE_CHANGE:
{
PortOperStateUpdate *update = static_cast<PortOperStateUpdate *>(cntx);
updateLagMemberOperChange(*update);
break;
}
default:
// Received update in which we are not interested
// Ignore it
Expand Down Expand Up @@ -277,7 +283,7 @@ bool MirrorOrch::validateDstPort(const string& dstPort)
SWSS_LOG_ERROR("Not supported port %s type %d", dstPort.c_str(), port.m_type);
return false;
}
if (port.m_type != Port::PHY)
if (port.m_type != Port::PHY && port.m_type != Port::LAG)
{
SWSS_LOG_ERROR("Not supported port %s", dstPort.c_str());
return false;
Expand Down Expand Up @@ -590,11 +596,11 @@ void MirrorOrch::setSessionState(const string& name, const MirrorEntry& session,
SWSS_LOG_ERROR("Failed to get recirc port for mirror session %s", name.c_str());
return;
}
}
else
{
m_portsOrch->getPort(session.neighborInfo.portId, port);
}
}
else
{
m_portsOrch->getPort(session.neighborInfo.portId, port);
}
fvVector.emplace_back(MIRROR_SESSION_MONITOR_PORT, port.m_alias);
}

Expand Down Expand Up @@ -692,12 +698,13 @@ bool MirrorOrch::getNeighborInfo(const string& name, MirrorEntry& session)
}
else
{
// Get the first member of the LAG
Port member;
string first_member_alias = *session.neighborInfo.port.m_members.begin();
m_portsOrch->getPort(first_member_alias, member);

session.neighborInfo.portId = member.m_port_id;
// Get the first linked up member of the LAG
Port upPort;
if (!m_portsOrch->getUpLagMember(session.neighborInfo.port, upPort))
{
return false;
}
session.neighborInfo.portId = upPort.m_port_id;
}

return true;
Expand Down Expand Up @@ -734,7 +741,24 @@ bool MirrorOrch::getNeighborInfo(const string& name, MirrorEntry& session)
else
{
// Update monitor port
session.neighborInfo.portId = member.m_port_id;
if (member.m_type == Port::LAG)
{
if (member.m_members.empty())
{
return false;
}

Port upPort;
if (!m_portsOrch->getUpLagMember(member, upPort))
{
return false;
}
session.neighborInfo.portId = upPort.m_port_id;
}
else
{
session.neighborInfo.portId = member.m_port_id;
}
}
}

Expand Down Expand Up @@ -929,7 +953,22 @@ bool MirrorOrch::activateSession(const string& name, MirrorEntry& session)
}

attr.id = SAI_MIRROR_SESSION_ATTR_MONITOR_PORT;
attr.value.oid = dst_port.m_port_id;
// Allowed portchannel to be dst_port of mirror session
if (dst_port.m_type == Port::PHY)
{
attr.value.oid = dst_port.m_port_id;
SWSS_LOG_INFO("Destination port object id: %lu", attr.value.oid);
}
else if (dst_port.m_type == Port::LAG)
{
attr.value.oid = dst_port.m_lag_id;
SWSS_LOG_INFO("Destination port object id: %lu", attr.value.oid);
}
else
{
SWSS_LOG_ERROR("Type of Port %s is incorrect.", session.dst_port.c_str());
return false;
}
attrs.push_back(attr);

attr.id = SAI_MIRROR_SESSION_ATTR_TYPE;
Expand Down Expand Up @@ -1480,11 +1519,12 @@ void MirrorOrch::updateLagMember(const LagMemberUpdate& update)
if (!session.status)
{
assert(!update.lag.m_members.empty());
const string& member_name = *update.lag.m_members.begin();
Port member;
m_portsOrch->getPort(member_name, member);

session.neighborInfo.portId = member.m_port_id;
Port upPort;
if (!m_portsOrch->getUpLagMember(update.lag, upPort))
{
continue;
}
session.neighborInfo.portId = upPort.m_port_id;
activateSession(name, session);
}
}
Expand All @@ -1502,11 +1542,12 @@ void MirrorOrch::updateLagMember(const LagMemberUpdate& update)
// Switch to a new member of the LAG
else
{
const string& member_name = *update.lag.m_members.begin();
Port member;
m_portsOrch->getPort(member_name, member);

session.neighborInfo.portId = member.m_port_id;
Port upPort;
if (!m_portsOrch->getUpLagMember(update.lag, upPort))
{
continue;
}
session.neighborInfo.portId = upPort.m_port_id;
// The destination MAC remains the same
updateSessionDstPort(name, session);
}
Expand Down Expand Up @@ -1546,6 +1587,79 @@ void MirrorOrch::updateVlanMember(const VlanMemberUpdate& update)
}
}

/* Handle the case when the member of the LAG is up or down.
This function is called when SUBJECT_TYPE_PORT_OPER_STATE_CHANGE is received. */
void MirrorOrch::updateLagMemberOperChange(const PortOperStateUpdate& update)
{
SWSS_LOG_ENTER();

/* Check the following two conditions:
1) The update port is PHY port.
2) The update port belongs to a LAG. */
Port lag;
if (update.port.m_type != Port::PHY ||
!m_portsOrch->getPort(update.port.m_lag_id, lag))
{
return;
}

for (auto it = m_syncdMirrors.begin(); it != m_syncdMirrors.end(); it++)
{
const auto& name = it->first;
auto& session = it->second;

/* Check the following two conditions:
1) the neighbor is LAG.
2) the neighbor LAG matches the update LAG. */
if (session.neighborInfo.port.m_type != Port::LAG ||
session.neighborInfo.port != lag)
{
continue;
}

Port cur_dst_port;
if (!m_portsOrch->getPort(session.neighborInfo.portId, cur_dst_port))
{
SWSS_LOG_ERROR("Failed to locate Port/LAG %s", session.dst_port.c_str());
continue;
}

if (update.operStatus == SAI_PORT_OPER_STATUS_UP)
{
/* Activate mirror session if it was deactivated due to the reason
that previously there was no active member in the LAG. If the mirror
session is already activated, no further action is needed. */
if (!session.status)
{
session.neighborInfo.portId = update.port.m_port_id;
activateSession(name, session);
}
}
else
{
// shutdown a LAG member
if (session.status)
{
// If the shoutdown port is the current dst port, try to switch to a new member of the LAG.
if (update.port == cur_dst_port)
{
Port upPort;
if (m_portsOrch->getUpLagMember(lag, upPort, update.port.m_alias))
{
session.neighborInfo.portId = upPort.m_port_id;
updateSessionDstPort(name, session);
}
else
{
session.neighborInfo.portId = SAI_NULL_OBJECT_ID;
deactivateSession(name, session);
}
}
}
}
}
}

void MirrorOrch::doTask(Consumer& consumer)
{
SWSS_LOG_ENTER();
Expand Down
1 change: 1 addition & 0 deletions orchagent/mirrororch.h
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ class MirrorOrch : public Orch, public Observer, public Subject
void updateFdb(const FdbUpdate&);
void updateLagMember(const LagMemberUpdate&);
void updateVlanMember(const VlanMemberUpdate&);
void updateLagMemberOperChange(const PortOperStateUpdate&);

bool checkPortExistsInSrcPortList(const string& port, const string& srcPortList);
bool validateSrcPortList(const string& srcPort);
Expand Down
19 changes: 19 additions & 0 deletions orchagent/portsorch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5785,6 +5785,25 @@ void PortsOrch::getLagMember(Port &lag, vector<Port> &portv)
}
}

/* Get the first linked up member of the LAG,
and notice that the return value from getPort() is still stale if triggered by SUBJECT_TYPE_PORT_OPER_STATE_CHANGE.
To avoid getting stale information, pass a port_alias as a filter.
*/
bool PortsOrch::getUpLagMember(Port &lag, Port &upPort, const string &aliasExclude)
{
vector<Port> portv;
getLagMember(lag, portv);
for (const auto p : portv)
{
if (p.m_oper_status == SAI_PORT_OPER_STATUS_UP && p.m_alias != aliasExclude)
{
upPort = p;
return true;
}
}
return false;
}

bool PortsOrch::addLagMember(Port &lag, Port &port, bool enableForwarding)
{
SWSS_LOG_ENTER();
Expand Down
1 change: 1 addition & 0 deletions orchagent/portsorch.h
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ class PortsOrch : public Orch, public Subject
bool removeSubPort(const string &alias);
bool updateL3VniStatus(uint16_t vlan_id, bool status);
void getLagMember(Port &lag, vector<Port> &portv);
bool getUpLagMember(Port &lag, Port &upPort, const string &aliasExclude = "");
void updateChildPortsMtu(const Port &p, const uint32_t mtu);

bool addTunnel(string tunnel,sai_object_id_t, bool learning=true);
Expand Down

0 comments on commit 2741b7f

Please sign in to comment.