Skip to content

[bug] Generation of SONiC Config Breakout Port speed from Port Type fails #2478

Description

@ZoTA02

OSISM release version

latest

What's the problem?

The problem occurs with osism --version: osism 0.20260615.1
The problem was not present in osism --version: osism 0.20260414.1

We found the issue with the switch type Edgecore 9726-32DB-O-AC-F. 400G interfaces are broken out into 4x100G interfaces, which works.
However, in the 100G interface definition, the interface speed is wrong and the switch cannot apply the configuration file.

Expected example output from older versions:

    "Ethernet118": {
      "admin_status": "down",
      "alias": "Eth1/15/7",
      "index": "15",
      "lanes": "151,152",
      "speed": "100000",
      "mtu": "9100",
      "adv_speeds": "all",
      "autoneg": "off",
      "link_training": "off",
      "unreliable_los": "auto",
      "valid_speeds": "100000,50000,25000,10000,1000"
    },

Current, faulty output:

    "Ethernet118": {
      "admin_status": "down",
      "alias": "Eth1/15/7",
      "index": "15",
      "lanes": "151,152",
      "speed": "100",
      "mtu": "9100",
      "adv_speeds": "all",
      "autoneg": "off",
      "link_training": "off",
      "unreliable_los": "auto",
      "valid_speeds": "100,10000,1000"
    },

The issue seems to be that interface speeds from netbox can be in two different units (mbit/kbit) depending on the source (interface type/explicit).
The issue seems to have been introduced in #2328.

Disclaimer: We partly used AI (Claude Opus 4.8) to analyze the issue. I add the full output, which includes suggested fixes and references to the code, below.

Complete AI output

============ Start of AI output ============

Your speed of 100 (instead of 100000) comes from a unit-conversion bug in the breakout-port branch of _add_port_configurations. The value gets divided by 1000 when it shouldn't be.

Two different sources feed netbox_interfaces[port_name]["speed"], and they use different units:

  1. In config_generator.py, when the NetBox interface has an explicit speed, that value is in kbps (NetBox convention).
  2. When interface.speed is unset, the code falls back to get_speed_from_port_type(...), which returns Mbps (interface.py — e.g. 100gbase-x-qsfp28100000 Mbps).

The speed_explicit flag is captured precisely to tell these two cases apart. But the breakout branch ignores it and always divides by 1000:

if port_name in netbox_interfaces and netbox_interfaces[port_name]["speed"]:
    # Convert NetBox speed (kbps) to SONiC speed (Mbps)
    netbox_speed = netbox_interfaces[port_name]["speed"]
    port_speed = str(int(netbox_speed) // 1000)   # <-- wrong when speed came from port type

For your Ethernet118 (a 100G breakout off a 400G port), the interface has no explicit speed in NetBox, so the port type resolves to 100000 Mbps, and 100000 // 1000 = 100. That wrong 100 then flows into _get_breakout_port_valid_speeds, which hits the else branch and produces "100,10000,1000" — exactly your bad valid_speeds.

The non-breakout branch just above (lines 528-544) has the same latent issue: it also divides derived (Mbps) speeds by 1000 in the elif not port_speed or port_speed == "0" path.

What the fix would be

Only divide by 1000 when the speed was explicitly set in NetBox (kbps); use it as-is when it was derived from the port type (already Mbps). For the breakout branch:

if port_name in netbox_interfaces and netbox_interfaces[port_name]["speed"]:
    netbox_speed = netbox_interfaces[port_name]["speed"]
    if netbox_interfaces[port_name].get("speed_explicit", False):
        # Explicit NetBox speed is kbps -> convert to Mbps
        port_speed = str(int(netbox_speed) // 1000)
    else:
        # Derived from port type -> already Mbps
        port_speed = str(int(netbox_speed))

The same speed_explicit guard should be applied in:

  • _add_missing_breakout_ports (lines ~715-725), which has an identical // 1000 on the derived speed.
  • The non-breakout elif not port_speed or port_speed == "0" branch, to be fully correct.

Note on the tests

Several existing tests actually encode the buggy assumption — e.g. test_breakout_port_speed_from_netbox passes speed=25000, speed_explicit=True and asserts "25", and test_derived_netbox_speed_only_used_when_port_speed_empty expects a derived 25000 to become "25". Those would need revisiting: with speed_explicit=True, 25000 kbps → "25" is correct, but the derived cases (speed_explicit=False) should keep the Mbps value rather than dividing.

============ End of AI output ============

References to existing reports

References to existing bug reports, mailing lists, ...

Severity

high

Urgency

medium

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Fields

No fields configured for issues without a type.

Projects

Status
Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions