Skip to content

[macsec]: Disable LAG member forwarding on MACsec session down - #4744

Open
karthik-nexthop wants to merge 4 commits into
sonic-net:masterfrom
nexthop-ai:disable-lag-member-forwarding-on-macsec
Open

[macsec]: Disable LAG member forwarding on MACsec session down#4744
karthik-nexthop wants to merge 4 commits into
sonic-net:masterfrom
nexthop-ai:disable-lag-member-forwarding-on-macsec

Conversation

@karthik-nexthop

@karthik-nexthop karthik-nexthop commented Jul 10, 2026

Copy link
Copy Markdown

What I did

  • Added m_macsec_sa_active on Port (orchagent/port.h) to track MACsec data-plane intent in-memory.
  • Added PortsOrch::setLagMemberState() (orchagent/portsorch.cpp/.h) that:
    • On MACsec down for a LAG member: flaps hostif oper-status (forces teamd to deselect the member without ~90s LACP timeout, without holding carrier down permanently so EAPOL/MKA can still flow), then disables ingress/egress collection+distribution directly via SAI.
    • On MACsec up: clears the suppression flag only; lets teamsyncd's APP_LAG_MEMBER_TABLE status=enabled drive SAI re-enable after LACP completes.
    • Skips hostif flap and SAI LAG writes on non-LAG ports (only persists the flag).
  • In doLagMemberTask: suppresses teamsyncd-driven re-enable when m_macsec_sa_active is false.
  • In setMACsecEnabledState: calls setLagMemberState(p, !enabled) when MACsec is enabled/disabled on a port.
  • In macsecorch: hooks createMACsecSA / deleteMACsecSA to call setLagMemberState only when both ingress and egress directions are up/down (bothDirectionsUp / bothDirectionsDown), so asymmetric rekey teardown does not drop the member prematurely.
  • Added unit tests in tests/mock_tests/portsorch_ut.cpp:
    • MacsecDownDisablesLagMemberAndSuppressesTeamdReEnable
    • MacsecDownDoesNotFlapNonLagPort

Why I did it

  • Fix issue #19254
    When an MKA/MACsec session expires on a PortChannel member (e.g. EAPOL blocked, keepalive timeout), the MACsec data plane goes down but the LAG member can remain selected by teamd. Traffic may continue to hash to that member, causing black-holed or ICV-failed frames instead of failing over to healthy members.
    After orchagent disables the member's collection/distribution, a routine teamsyncd refresh of APP_LAG_MEMBER_TABLE with status=enabled can silently re-enable forwarding while MACsec is still down.

How I verified it
Unit tests:

make -C tests/mock_tests portsorch_ut
./tests/mock_tests/portsorch_ut --gtest_filter='*MacsecDown*'

Related sonic-mgmt coverage:
tests/macsec/test_fault_handling.py::test_eapol_block_brings_lag_member_down.

Details if related
macsec_changes_explained.md

Signed-off-by: karthik-nexthop <karthik@nexthop.ai>
@linux-foundation-easycla

linux-foundation-easycla Bot commented Jul 10, 2026

Copy link
Copy Markdown

CLA Signed
The committers listed above are authorized under a signed CLA.

  • ✅ login: karthik-nexthop / name: Karthik Siruvalam (34399b4)
  • ✅ login: karthik-nexthop / name: karthik-nexthop (24fb817)

@mssonicbld

Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@mssonicbld

Copy link
Copy Markdown
Collaborator

Hi, there are workflow run(s) waiting for approval, you may be first-time contributor. I will notify maintainers to help approve once PR is approved. Thanks!

---Powered by SONiC BuildBot

Keep m_lag_forced_admin_down and m_macsec_sa_active Port members added
for MACsec LAG member forwarding control.
Signed-off-by: Karthik Siruvalam <karthik@nexthop.ai>
@karthik-nexthop
karthik-nexthop force-pushed the disable-lag-member-forwarding-on-macsec branch from 34399b4 to e799b7d Compare July 15, 2026 05:49
@mssonicbld

Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

Comment thread orchagent/portsorch.cpp
Comment thread orchagent/port.h Outdated
@abdosi

abdosi commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

@karthik-nexthop : we need to add one test case that can verify continuous flaps of macsec sessionn and it's impact on teamd to make sure their is no is no race condition for this for APP_DB and SAI programming.

Add MacsecContinuousFlapNoAppDbSaiRace to cover APP_DB/SAI races under
repeated MACsec session flaps. Remove unused m_lag_forced_admin_down
left over from a cherry-pick conflict (not present on upstream master).

Signed-off-by: Karthik Siruvalam <karthik@nexthop.ai>
@mssonicbld

Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

@karthik-nexthop

Copy link
Copy Markdown
Author

/azp run

@azure-pipelines

Copy link
Copy Markdown
Commenter does not have sufficient privileges for PR 4744 in repo sonic-net/sonic-swss

@saravanan-nexthop

Copy link
Copy Markdown
Contributor

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

saksarav-nokia
saksarav-nokia previously approved these changes Jul 29, 2026
mlok-nokia
mlok-nokia previously approved these changes Jul 29, 2026
Comment thread orchagent/portsorch.cpp Outdated
judyjoseph
judyjoseph previously approved these changes Aug 5, 2026
@rlhui

rlhui commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

@prsunny , would we please review/merge? thanks

Comment thread orchagent/portsorch.cpp Outdated
setLagMemberState(p, !enabled);
}

void PortsOrch::setLagMemberState(Port &port, bool enabled)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though this method is invoked in MacSec path, this name is very generic. Could you rename it?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will update it.

Comment thread orchagent/portsorch.cpp Outdated
it->second.m_macsec_sa_active = enabled;
}

const bool is_lag_member = (port.m_lag_member_id != SAI_NULL_OBJECT_ID);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should move this check to the start of the method and bypass if this port is not a member of a lag.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll move the LAG-member check up and return early for non-members so we skip hostif/SAI work immediately.

Comment thread orchagent/portsorch.cpp
/* MACsec data plane is up again. Clear the suppression flag and let
* teamsyncd's status=enabled refresh drive SAI re-enable once LACP
* completes, avoiding hashing to a member before teamd selects it. */
SWSS_LOG_NOTICE("MACsec SA active on %s; awaiting teamsyncd to re-enable LAG member",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which module sets setDistributionOnLagMember and setCollectionOnLagMember to true? Will be good to update in this section.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

setLagMemberState(true) itself does not re-enable SAI collection/distribution — it only clears m_macsec_sa_active.

Re-enable is driven by teamsyncd. Will update the comment.

ASSERT_FALSE(ingressDisable) << "cycle " << i;
}

// Rapid down/up without an intervening teamsyncd enable: final intent wins.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you also check with LAG+min_links of LAG configuration?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That part is covered in the companion sonic-mgmt PR (#26062) — test_macsec_down_disables_lag_member reads CONFIG_DB min_links and gates the PortChannel/BGP checks on it. This mock UT doesn’t run teamd, so I didn’t try to cover min_links here


// Rapid down/up without an intervening teamsyncd enable: final intent wins.
Port rapid;
ASSERT_TRUE(gPortsOrch->getPort(memberAlias, rapid));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check if LAG goes down(with min-links as total members) when one member's MAC sec fails

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes — that’s covered in sonic-mgmt.

Comment thread orchagent/port.h
* orchagent/swss restarts (e.g. warm reboot) while MACsec is down, the
* member comes back enabled before its SAs are re-established. It is not
* reconciled from STATE_DB MACsec SA presence on init. */
bool m_macsec_sa_active = true;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This changes the behavior after orchagent restart and not specific to warmboot. This can impact security, please check.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is not specific to warmboot. m_macsec_sa_active is in-memory only and defaults to true, so any orchagent restart loses the prior intent. I’ll correct the comment.

Comment thread orchagent/portsorch.cpp

if (!collection_ok || !distribution_ok)
{
SWSS_LOG_ERROR("Failed to disable collection/distribution on LAG member %s",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we reset port.m_macsec_sa_active for any SAI call failures?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We set m_macsec_sa_active = false before the SAI calls specifically so doLagMemberTask will suppress a later teamsyncd status=enabled refresh.

If the SAI disable fails, the hardware may still be forwarding on that member — we log that as an error, and I agree that risk remains. But reverting the flag on failure would let orchagent re-enable collection/distribution from APP_DB while MACsec is still down, which makes the failure mode worse. Leaving the suppress flag set is the more conservative choice; a retry of the SAI disable would be a separate improvement if we want one.

Rename setLagMemberState to setLagMemberMacsecSaActive, early-return for
non-LAG members after persisting m_macsec_sa_active, and document the
teamsyncd/doLagMemberTask re-enable path plus any-orchagent-restart
limitation for the in-memory flag.

Signed-off-by: Karthik Siruvalam <karthik@nexthop.ai>
@mssonicbld

Copy link
Copy Markdown
Collaborator

/azp run

1 similar comment
@mssonicbld

Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

1 similar comment
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

Comment thread orchagent/portsorch.cpp
{
SWSS_LOG_NOTICE("Flapping host interface %s to force teamd LACP reset due to MACsec down",
port.m_alias.c_str());
setHostIntfsOperStatus(port, false);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

setHostIntfsOperStatus has a single production caller today — updatePortOperStatus in the SAI port-oper-status notification path — where it mirrors a real hardware link event to the kernel. Using it here to synthesize a fake link flap has a few side effects:

  • Spurious telemetry: each call publishes an if-state event via event_publish, so monitoring systems will see two false link-flap events.
  • State divergence: updatePortOperStatus also updates m_oper_status, DB oper status, flap counters, nexthop reachability, gearbox state, and VoQ sync. Calling setHostIntfsOperStatus directly skips all of that, so orchagent's internal state won't reflect the kernel-visible flap.
  • Timing: back-to-back down/up with no delay risks the kernel coalescing the two netlink carrier events, in which case teamd never sees the down and never deselects the member — breaking the recovery path.
    It would be probably cleaner to drive teamd deselection through a teamd-native mechanism (e.g. teamdctl runner port disable, or writing to the teamd control socket) rather than faking a link event through the SAI hostif layer?

@prabhataravind prabhataravind left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR introduces a second control plane for LAG member selection — macsecorch directly manipulates SAI LAG member state and mutes teamd via a suppression guard — which conflicts with SONiC's established architecture where teamd/LACP exclusively owns member selection through APP_LAG_MEMBER_TABLE.

The setHostIntfsOperStatus down/up flap here compounds the issue: this function's sole production caller is updatePortOperStatus (line 10064), where it mirrors real hardware link events. Using it synthetically to trick teamd into deselecting the member (a) publishes two false if-state telemetry events, (b) skips flap-count/nexthop/gearbox/VoQ state updates that updatePortOperStatus performs, and (c) depends on the kernel not coalescing the back-to-back netlink carrier events — an undocumented timing assumption.

Consider having macsecorch signal teamd directly (e.g. teamdctl port config update or a D-Bus/control-socket message) to deselect the member. Teamd would then write status=disabled to APP_LAG_MEMBER_TABLE, doLagMemberTask would disable collection/distribution through the normal path, and the suppression guard, hostif flap, and m_macsec_sa_active flag all become unnecessary.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

10 participants