Skip to content
Merged
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
27 changes: 27 additions & 0 deletions osism/tasks/conductor/sonic/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -915,6 +915,33 @@ def detect_breakout_ports(device):
if len(sonic_breakout_group) == 4:
master_port = f"Ethernet{base_port}"

# Topology gate: only treat consecutive EthernetN ports as a
# breakout when the port_config confirms a single multi-lane
# master whose intermediate lanes are absent — they only
# materialize when the cage is broken out. Four separate
# single-lane entries are native ports, not a breakout cage.
# This prevents native low-speed switches (e.g. AS5835-54T
# 10G, DellEMC-S5212f / AS7326-56X 25G) from being
# misdetected as a 4xNG breakout. Unlike EthX/Y/Z, the bare
# EthernetN name carries no explicit breakout signal, so the
# port_config topology is the only local evidence available.
master_cfg = port_config.get(master_port)
if not master_cfg or "," not in master_cfg.get("lanes", ""):
logger.debug(
f"Skipping SONiC breakout for {master_port}: master "
f"is not a multi-lane port in port_config (native port)"
)
continue
if any(
f"Ethernet{base_port + offset}" in port_config
for offset in (1, 2, 3)
):
logger.debug(
f"Skipping SONiC breakout for {master_port}: "
f"intermediate ports present in port_config (native ports)"
)
continue

# Determine breakout mode based on speed; the membership
# filter above (<= 50G) limits this path to 4x10G, 4x25G
# and 4x50G
Expand Down
28 changes: 28 additions & 0 deletions tests/unit/tasks/conductor/sonic/test_breakout_detection.py
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,34 @@ def test_detect_breakout_ports_sonic_standard_only_three_interfaces(
}


def test_detect_breakout_ports_sonic_standard_native_ports_not_breakout(
patch_breakout_helpers,
):
# Four consecutive single-lane 25G ports that are each their own
# port_config entry are NATIVE ports, not a breakout cage, and must not be
# misdetected as a 4x25G breakout. A real breakout is a single multi-lane
# master with the intermediate lanes absent (they materialize only when the
# cage is broken out). This guards native low-speed switches such as
# DellEMC-S5212f / AS7326-56X (25G) and AS5835-54T (10G).
device = _make_sonic_device()
interfaces = [_make_iface(f"Ethernet{n}", speed=25_000_000) for n in range(4)]
port_config = {
f"Ethernet{n}": {
"lanes": str(29 + n), # one lane each -> native ports
"alias": f"twentyfiveGigE1/{n + 1}",
"index": str(n + 1),
"speed": "25000",
}
for n in range(4)
}
patch_breakout_helpers(interfaces=interfaces, port_config=port_config)

assert detect_breakout_ports(device) == {
"breakout_cfgs": {},
"breakout_ports": {},
}


def test_detect_breakout_ports_sonic_standard_speed_resolved_from_port_type(
patch_breakout_helpers,
):
Expand Down