Skip to content

Commit 9ee49cd

Browse files
authored
Fix SONiC format 400G to 4x100G breakout detection (#1792)
Extends the 400G breakout detection to SONiC format interfaces (Ethernet0, Ethernet2, Ethernet4, Ethernet6), completing the implementation started in ea885fb. The previous commit added 400G breakout support for EthX/Y/Z format interfaces but missed adding the same logic to the SONiC format detection section. This caused devices configured with SONiC-style interface names to not generate proper BREAKOUT_CFG entries. Key changes: - Detect SONiC 400G breakout pattern (ports increment by 2) - Validate 8-lane master port in port_config before processing - Check for 100G speed on each breakout port - Generate correct BREAKOUT_CFG with "4x100G" mode - Calculate physical port using (base_port // 8) + 1 logic - Add debug logging for 400G breakout detection Technical implementation: - Base port calculation: (port_num // 8) * 8 - Port iteration: Ethernet0, 2, 4, 6 (i * 2 increment) - Speed validation: 100000 Mbps per port - Unique group_key: "sonic_400g_{base}" vs "sonic_std_{base}" - Maintains backward compatibility with standard breakout (≤50G) Fixes detection for devices like Accton-AS9726-32D with 400G ports broken out to 4x100G in NetBox. AI-assisted: Claude Code Signed-off-by: Christian Berendt <[email protected]>
1 parent 0d60825 commit 9ee49cd

File tree

1 file changed

+81
-2
lines changed

1 file changed

+81
-2
lines changed

osism/tasks/conductor/sonic/interface.py

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -789,9 +789,88 @@ def detect_breakout_ports(device):
789789
sonic_match = re.match(r"Ethernet(\d+)", interface_name)
790790
if sonic_match:
791791
port_num = int(sonic_match.group(1))
792+
793+
# Try 400G breakout pattern first (increment by 2: Ethernet0, 2, 4, 6)
794+
# 400G ports have 8 lanes and break into 4x100G ports
795+
base_port_400g = (port_num // 8) * 8
796+
group_key_400g = f"sonic_400g_{base_port_400g}"
797+
798+
if group_key_400g not in processed_groups:
799+
# Check if master port has 8 lanes in port_config
800+
master_port_400g = f"Ethernet{base_port_400g}"
801+
if master_port_400g in port_config:
802+
master_lanes = port_config[master_port_400g]["lanes"]
803+
if "," in master_lanes:
804+
lanes_list = [
805+
lane.strip() for lane in master_lanes.split(",")
806+
]
807+
if len(lanes_list) == 8:
808+
# This is an 8-lane master port - check for 400G breakout
809+
# Look for Ethernet0, 2, 4, 6 (or 8, 10, 12, 14, etc.) with 100G speed
810+
sonic_400g_breakout_group = []
811+
for i in range(4):
812+
ethernet_name = (
813+
f"Ethernet{base_port_400g + (i * 2)}"
814+
)
815+
for iface in interfaces:
816+
if iface.name == ethernet_name:
817+
# Check if this interface has 100G speed
818+
iface_speed = getattr(iface, "speed", None)
819+
if (
820+
not iface_speed
821+
and hasattr(iface, "type")
822+
and iface.type
823+
):
824+
iface_speed = get_speed_from_port_type(
825+
iface.type.value
826+
)
827+
828+
# 400G breakout uses 100G per port
829+
if iface_speed == 100000:
830+
sonic_400g_breakout_group.append(
831+
(base_port_400g + (i * 2), iface)
832+
)
833+
break
834+
835+
# If we found 4 interfaces with increment of 2 and 100G speed
836+
if len(sonic_400g_breakout_group) == 4:
837+
processed_groups.add(group_key_400g)
838+
master_port = f"Ethernet{base_port_400g}"
839+
brkout_mode = "4x100G"
840+
841+
# Calculate physical port number for 400G ports
842+
# Ethernet0-7 -> port 1/1, Ethernet8-15 -> port 1/2, etc.
843+
physical_port_index = (base_port_400g // 8) + 1
844+
physical_port_num = f"1/{physical_port_index}"
845+
846+
# Add breakout config for master port
847+
breakout_cfgs[master_port] = {
848+
"breakout_owner": "MANUAL",
849+
"brkout_mode": brkout_mode,
850+
"port": physical_port_num,
851+
}
852+
853+
# Add all ports to breakout_ports
854+
for (
855+
port_num_400g,
856+
iface,
857+
) in sonic_400g_breakout_group:
858+
port_name = f"Ethernet{port_num_400g}"
859+
breakout_ports[port_name] = {
860+
"master": master_port
861+
}
862+
863+
logger.debug(
864+
f"Detected SONiC 400G breakout group: Ethernet{base_port_400g},{base_port_400g+2},{base_port_400g+4},{base_port_400g+6} -> {master_port} ({brkout_mode})"
865+
)
866+
867+
# Skip standard breakout check for this port
868+
continue
869+
870+
# Standard breakout pattern (increment by 1: Ethernet0, 1, 2, 3)
792871
# Check if this could be part of a breakout group (consecutive Ethernet ports)
793872
base_port = (port_num // 4) * 4
794-
group_key = f"sonic_{base_port}"
873+
group_key = f"sonic_std_{base_port}"
795874

796875
if group_key in processed_groups:
797876
continue
@@ -859,7 +938,7 @@ def detect_breakout_ports(device):
859938
breakout_ports[port_name] = {"master": master_port}
860939

861940
logger.debug(
862-
f"Detected SONiC breakout group: Ethernet{base_port}-{base_port + 3} -> {master_port} ({brkout_mode})"
941+
f"Detected SONiC standard breakout group: Ethernet{base_port}-{base_port + 3} -> {master_port} ({brkout_mode})"
863942
)
864943

865944
except Exception as e:

0 commit comments

Comments
 (0)