Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions orchagent/port.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,8 @@ class Port
sai_object_id_t m_hif_id = 0;
sai_object_id_t m_lag_id = 0;
sai_object_id_t m_lag_member_id = 0;
/* PHY port admin state is overriden by parent LAG admin-down */
bool m_lag_forced_admin_down = false;
sai_object_id_t m_tunnel_id = 0;
sai_object_id_t m_ingress_acl_table_group_id = 0;
sai_object_id_t m_egress_acl_table_group_id = 0;
Expand Down
192 changes: 192 additions & 0 deletions orchagent/portsorch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5459,6 +5459,15 @@ void PortsOrch::doPortTask(Consumer &consumer)
pCfg.admin_status.value = admin_status;
}

/* This is a guard to suppress admin-up of port if parent LAG is admin-down */
if (pCfg.admin_status.is_set && pCfg.admin_status.value && p.m_lag_forced_admin_down)
{
SWSS_LOG_NOTICE("Port %s: suppressing admin-up from APP_DB "
"(forced admin-down by parent LAG)",
p.m_alias.c_str());
pCfg.admin_status.is_set = false;
}

/* Last step set port admin status */
if (pCfg.admin_status.is_set)
{
Expand Down Expand Up @@ -6020,6 +6029,7 @@ void PortsOrch::doLagTask(Consumer &consumer)
int32_t switch_id = -1;
string tpid_string;
uint16_t tpid = 0;
string admin_status_str;

for (auto i : kfvFieldsValues(t))
{
Expand Down Expand Up @@ -6067,6 +6077,10 @@ void PortsOrch::doLagTask(Consumer &consumer)
tpid = (uint16_t)stoi(tpid_string, 0, 16);
SWSS_LOG_DEBUG("reading TPID string:%s to uint16: 0x%x", tpid_string.c_str(), tpid);
}
else if (fvField(i) == "admin_status")
{
admin_status_str = fvValue(i);
}
}

if (table_name == CHASSIS_APP_LAG_TABLE_NAME)
Expand Down Expand Up @@ -6164,6 +6178,22 @@ void PortsOrch::doLagTask(Consumer &consumer)
SWSS_LOG_NOTICE("Saved to set port %s learn mode %s", alias.c_str(), learn_mode_str.c_str());
}
}

/* Detect admin status transition and propagate to members */
if (!admin_status_str.empty())
{
bool newAdminUp = (admin_status_str == "up");

if (l.m_admin_state_up != newAdminUp)
{
SWSS_LOG_NOTICE("LAG %s admin status changed to %s",
alias.c_str(),
newAdminUp ? "up" : "down");
l.m_admin_state_up = newAdminUp;
cascadeLagAdminStatusToMembers(l, newAdminUp);
m_portList[alias] = l;
}
}
}

it = consumer.m_toSync.erase(it);
Expand All @@ -6178,6 +6208,12 @@ void PortsOrch::doLagTask(Consumer &consumer)
continue;
}

/* If LAG is admin-down, restore member states before deleting the LAG */
if (!lag.m_admin_state_up)
{
cascadeLagAdminStatusToMembers(lag, true);
}

if (removeLag(lag))
it = consumer.m_toSync.erase(it);
else
Expand All @@ -6191,6 +6227,92 @@ void PortsOrch::doLagTask(Consumer &consumer)
}
}

void PortsOrch::cascadeLagAdminStatusToMembers(Port &lag, bool bringLagMembersUp)
{
/* This cascades the status of the LAG being up/down to its individual members.
* If the LAG is up or down, members are brought up or down accordingly.
* Note: Before deleting a LAG, we bring the members up if they were down already.
*/
SWSS_LOG_ENTER();

for (const auto &memberAlias : lag.m_members)
{
auto memberIt = m_portList.find(memberAlias);
if (memberIt == m_portList.end())
{
SWSS_LOG_WARN("LAG %s member %s not found in portList",
lag.m_alias.c_str(), memberAlias.c_str());
continue;
}

Port &member = memberIt->second;

if (member.m_type == Port::SYSTEM)
continue;

if (!bringLagMembersUp)
{
/* LAG going admin-down: flag all members and force them down */
member.m_lag_forced_admin_down = true;
if (member.m_admin_state_up)
{
if (!setPortAdminStatus(member, false))
{
SWSS_LOG_ERROR("LAG %s: failed to force member %s admin-down",
lag.m_alias.c_str(), memberAlias.c_str());
member.m_lag_forced_admin_down = false;
continue;
}
member.m_admin_state_up = false;
SWSS_LOG_NOTICE("LAG %s admin-down: forced member %s admin-down",
lag.m_alias.c_str(), memberAlias.c_str());
}
}
else
{
/* LAG going admin-up: restore member states */
if (!member.m_lag_forced_admin_down)
continue;

member.m_lag_forced_admin_down = false;

/* Read the port's configured admin_status from APP_DB */
string cfgAdminStatus;
vector<FieldValueTuple> tuples;
if (m_portTable->get(memberAlias, tuples))
{
for (const auto &fv : tuples)
{
if (fvField(fv) == "admin_status")
{
cfgAdminStatus = fvValue(fv);
break;
}
}
}

bool shouldBeUp = (cfgAdminStatus == "up");
if (shouldBeUp && !member.m_admin_state_up)
{
if (!setPortAdminStatus(member, true))
{
SWSS_LOG_ERROR("LAG %s: failed to restore member %s admin-up",
lag.m_alias.c_str(), memberAlias.c_str());
continue;
}
member.m_admin_state_up = true;
SWSS_LOG_NOTICE("LAG %s admin-up: restored member %s admin-up",
lag.m_alias.c_str(), memberAlias.c_str());
}
else if (!shouldBeUp)
{
SWSS_LOG_NOTICE("LAG %s admin-up: member %s stays admin-down (configured down)",
lag.m_alias.c_str(), memberAlias.c_str());
}
}
}
}

void PortsOrch::doLagMemberTask(Consumer &consumer)
{
SWSS_LOG_ENTER();
Expand Down Expand Up @@ -6303,6 +6425,33 @@ void PortsOrch::doLagMemberTask(Consumer &consumer)
it++;
continue;
}

/* If the parent LAG is admin-down, force the new member down */
if (!lag.m_admin_state_up)
{
Port updatedMember;
if (getPort(port_alias, updatedMember) &&
updatedMember.m_type != Port::SYSTEM)
{
updatedMember.m_lag_forced_admin_down = true;
if (updatedMember.m_admin_state_up)
{
if (setPortAdminStatus(updatedMember, false))
{
updatedMember.m_admin_state_up = false;
SWSS_LOG_NOTICE("LAG %s admin-down: forced new member %s admin-down",
lag_alias.c_str(), port_alias.c_str());
}
else
{
SWSS_LOG_ERROR("LAG %s: failed to force new member %s admin-down",
lag_alias.c_str(), port_alias.c_str());
updatedMember.m_lag_forced_admin_down = false;
}
}
m_portList[port_alias] = updatedMember;
}
}
}

if (isChassisDbInUse() && (port.m_type != Port::SYSTEM))
Expand Down Expand Up @@ -6362,6 +6511,49 @@ void PortsOrch::doLagMemberTask(Consumer &consumer)

if (removeLagMember(lag, port))
{
/* Restore admin state if it was forced down by parent LAG.
* Check configured admin-status to decide if port should
* come up. */
{
Port updatedMember;
if (getPort(port_alias, updatedMember) &&
updatedMember.m_lag_forced_admin_down)
{
updatedMember.m_lag_forced_admin_down = false;

string cfgAdminStatus;
vector<FieldValueTuple> tuples;
if (m_portTable->get(port_alias, tuples))
{
for (const auto &fv : tuples)
{
if (fvField(fv) == "admin_status")
{
cfgAdminStatus = fvValue(fv);
break;
}
}
}

bool shouldBeUp = (cfgAdminStatus == "up");
if (shouldBeUp && !updatedMember.m_admin_state_up)
{
if (setPortAdminStatus(updatedMember, true))
{
updatedMember.m_admin_state_up = true;
SWSS_LOG_NOTICE("Restored member %s admin-up after removal from LAG %s",
port_alias.c_str(), lag_alias.c_str());
}
else
{
SWSS_LOG_ERROR("Failed to restore member %s admin-up after removal from LAG %s",
port_alias.c_str(), lag_alias.c_str());
}
}
m_portList[port_alias] = updatedMember;
}
}

it = consumer.m_toSync.erase(it);
}
else
Expand Down
3 changes: 3 additions & 0 deletions orchagent/portsorch.h
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,9 @@ class PortsOrch : public Orch, public Subject
bool setCollectionOnLagMember(Port &lagMember, bool enableCollection);
bool setDistributionOnLagMember(Port &lagMember, bool enableDistribution);

/* Propagate LAG admin status changes to member ports */
void cascadeLagAdminStatusToMembers(Port &lag, bool adminUp);

sai_status_t removePort(sai_object_id_t port_id);
bool initExistingPort(const PortConfig &port);
bool initPortsBulk(std::vector<Port>& ports);
Expand Down
Loading
Loading