-
Notifications
You must be signed in to change notification settings - Fork 14
Verify auto-negotiated speed/duplex #1059
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| speed_duplex_copper.adoc |
34 changes: 34 additions & 0 deletions
34
test/case/ietf_interfaces/speed_duplex_copper/speed_duplex_copper.adoc
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| === Interface Speed Duplex (Copper) | ||
| ==== Description | ||
| Verify that auto-negotiation results in expected speed/duplex mode. | ||
|
|
||
| ==== Topology | ||
| ifdef::topdoc[] | ||
| image::{topdoc}../../test/case/ietf_interfaces/speed_duplex_copper/topology.svg[Interface Speed Duplex (Copper) topology] | ||
| endif::topdoc[] | ||
| ifndef::topdoc[] | ||
| ifdef::testgroup[] | ||
| image::speed_duplex_copper/topology.svg[Interface Speed Duplex (Copper) topology] | ||
| endif::testgroup[] | ||
| ifndef::testgroup[] | ||
| image::topology.svg[Interface Speed Duplex (Copper) topology] | ||
| endif::testgroup[] | ||
| endif::topdoc[] | ||
| ==== Test sequence | ||
| . Set up topology and attach to target DUT | ||
| . Enable target interface | ||
| . Set fixed 10/full | ||
| . Set fixed 10/half | ||
| . Set fixed 100/full | ||
| . Set fixed 100/half | ||
| . Switch to auto-negotiation mode for target and host | ||
| . Configure host to advertise 10/Full only | ||
| . Configure host to advertise 10/Half only | ||
| . Configure host to advertise 100/Full only | ||
| . Configure host to advertise 100/Half only | ||
| . Configure host to advertise 10/half + 10/full + 100/half | ||
| . Configure host to advertise 10/half + 10/full + 100/half + 100/full + 1000/full | ||
|
|
||
|
|
||
| <<< | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,216 @@ | ||
| #!/usr/bin/env python3 | ||
| """ | ||
| Interface Speed Duplex (Copper) | ||
|
|
||
| Verify that auto-negotiation results in expected speed/duplex mode. | ||
| """ | ||
|
|
||
| import infamy | ||
| import subprocess | ||
| from infamy.util import until | ||
|
|
||
| ADVERTISE_MODES = { | ||
| # Values from ethtool's ETHTOOL_LINK_MODE bit positions | ||
| # See: https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/ethtool.h | ||
| "10half": 0x0001, | ||
| "10full": 0x0002, | ||
| "100half": 0x0004, | ||
| "100full": 0x0008, | ||
| "1000full": 0x0020 | ||
| } | ||
|
|
||
| def advertise_host_modes(interface, modes): | ||
| mask = 0 | ||
| for mode in modes: | ||
| mask |= ADVERTISE_MODES[mode] | ||
| try: | ||
| subprocess.run([ | ||
| "ethtool", "-s", interface, | ||
| "advertise", hex(mask) | ||
| ], check=True) | ||
| except subprocess.CalledProcessError as e: | ||
| raise RuntimeError(f"Failed to advertise modes via ethtool: {e}") | ||
|
|
||
| def get_target_speed_duplex(target, interface): | ||
| data = target.get_data(f"/ietf-interfaces:interfaces/interface[name='{interface}']") \ | ||
| ["interfaces"]["interface"][interface] | ||
| eth = data.get("ethernet", {}) | ||
|
|
||
| return eth.get("speed"), eth.get("duplex") | ||
|
|
||
| def set_target_speed_duplex(target, interface, speed, duplex): | ||
| target.put_config_dicts({ | ||
| "ietf-interfaces": { | ||
| "interfaces": { | ||
| "interface": [{ | ||
| "name": interface, | ||
| "ethernet": { | ||
| "auto-negotiation": { | ||
| "enable": False | ||
| }, | ||
| "speed": speed / 1000, | ||
| "duplex": duplex | ||
| } | ||
| }] | ||
| } | ||
| } | ||
| }) | ||
axkar marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| def set_host_speed_duplex(interface, speed, duplex): | ||
| try: | ||
| subprocess.run([ | ||
| "ethtool", "-s", interface, | ||
| "speed", str(speed), | ||
| "duplex", duplex, | ||
| "autoneg", "off" | ||
| ], check=True) | ||
| except subprocess.CalledProcessError as e: | ||
| raise RuntimeError(f"Failed to set speed/duplex via ethtool: {e}") | ||
|
|
||
| def verify_speed_duplex(target, ns, interface, exp_speed, exp_duplex): | ||
| until(lambda: speed_duplex_present(target, interface)) | ||
| act_speed, act_duplex = get_target_speed_duplex(target, interface) | ||
| if act_speed is None or act_duplex is None: | ||
| print(f"Could not fetch speed or duplex from target for interface {interface}") | ||
| test.fail() | ||
|
|
||
| exp_speed_gbps = exp_speed / 1000 | ||
| if float(act_speed) != exp_speed_gbps: | ||
| print(f"act_speed: {act_speed}, exp_speed: {exp_speed_gbps}") | ||
| test.fail() | ||
|
|
||
| if act_duplex.lower() != exp_duplex.lower(): | ||
| print(f"act_duplex: {act_duplex}, exp_duplex: {exp_duplex}") | ||
| test.fail() | ||
|
|
||
| ns.must_reach("10.0.0.2") | ||
|
|
||
| print(f"Verified: {interface} is operating at {act_speed} Gbps, {act_duplex} duplex") | ||
axkar marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| def speed_duplex_present(target, interface): | ||
| speed, duplex = get_target_speed_duplex(target, interface) | ||
| return speed is not None and duplex is not None | ||
|
|
||
| def enable_target_interface(target, interface): | ||
| target.put_config_dicts({ | ||
| "ietf-interfaces": { | ||
| "interfaces": { | ||
| "interface": [{ | ||
| "name": interface, | ||
| "enabled": True, | ||
| "ipv4": { | ||
| "address": [ | ||
| { | ||
| "ip": "10.0.0.2", | ||
| "prefix-length": 24 | ||
| } | ||
| ] | ||
| } | ||
| }] | ||
| } | ||
| } | ||
| }) | ||
|
|
||
| def enable_target_autoneg(target, interface): | ||
| target.put_config_dicts({ | ||
| "ietf-interfaces": { | ||
| "interfaces": { | ||
| "interface": [{ | ||
| "name": interface, | ||
| "ethernet": { | ||
| "auto-negotiation": { | ||
| "enable": True | ||
| } | ||
| } | ||
| }] | ||
| } | ||
| } | ||
| }) | ||
|
|
||
| def enable_host_autoneg(interface): | ||
| subprocess.run(["ethtool", "-s", interface, "autoneg", "on"], check=True) | ||
|
|
||
| def cleanup(target, hdata, tdata): | ||
| """ | ||
| Restore both host and target interfaces to autonegotiation mode | ||
| to ensure clean state for future tests. | ||
| """ | ||
|
|
||
| print("Restoring interfaces to default (autoneg on)") | ||
| try: | ||
| enable_host_autoneg(hdata) | ||
| except Exception as e: | ||
| print(f"Host autoneg restore failed: {e}") | ||
| try: | ||
| enable_target_interface(target, tdata) | ||
| enable_target_autoneg(target, tdata) | ||
| except Exception as e: | ||
| print(f"Target autoneg restore failed: {e}") | ||
|
|
||
| with infamy.Test() as test: | ||
| with test.step("Set up topology and attach to target DUT"): | ||
| env = infamy.Env() | ||
| target = env.attach("target", "mgmt") | ||
| _, hdata = env.ltop.xlate("host", "data") | ||
| _, tdata = env.ltop.xlate("target", "data") | ||
|
|
||
| # Append a test cleanup function | ||
| test.push_test_cleanup(lambda: cleanup(target, hdata, tdata)) | ||
|
|
||
| with test.step("Enable target interface"): | ||
| enable_target_interface(target, tdata) | ||
|
|
||
| with infamy.IsolatedMacVlan(hdata) as ns: | ||
| ns.addip("10.0.0.1") | ||
|
|
||
| # Fixed mode tests | ||
| with test.step("Set fixed 10/full"): | ||
| set_host_speed_duplex(hdata, 10, "full") | ||
| set_target_speed_duplex(target, tdata, 10, "full") | ||
| verify_speed_duplex(target, ns, tdata, 10, "full") | ||
|
|
||
| with test.step("Set fixed 10/half"): | ||
| set_host_speed_duplex(hdata, 10, "half") | ||
| set_target_speed_duplex(target, tdata, 10, "half") | ||
| verify_speed_duplex(target, ns, tdata, 10, "half") | ||
|
|
||
| with test.step("Set fixed 100/full"): | ||
| set_host_speed_duplex(hdata, 100, "full") | ||
| set_target_speed_duplex(target, tdata, 100, "full") | ||
| verify_speed_duplex(target, ns, tdata, 100, "full") | ||
|
|
||
| with test.step("Set fixed 100/half"): | ||
| set_host_speed_duplex(hdata, 100, "half") | ||
| set_target_speed_duplex(target, tdata, 100, "half") | ||
| verify_speed_duplex(target, ns, tdata, 100, "half") | ||
|
|
||
| # Auto-negotiation tests: host advertises, Infix negotiates | ||
| with test.step("Switch to auto-negotiation mode for target and host"): | ||
| enable_host_autoneg(hdata) | ||
| enable_target_autoneg(target, tdata) | ||
|
|
||
| with test.step("Configure host to advertise 10/Full only"): | ||
| advertise_host_modes(hdata, ["10full"]) | ||
| verify_speed_duplex(target, ns, tdata, 10, "full") | ||
|
|
||
| with test.step("Configure host to advertise 10/Half only"): | ||
| advertise_host_modes(hdata, ["10half"]) | ||
| verify_speed_duplex(target, ns, tdata, 10, "half") | ||
|
|
||
| with test.step("Configure host to advertise 100/Full only"): | ||
| advertise_host_modes(hdata, ["100full"]) | ||
| verify_speed_duplex(target, ns, tdata, 100, "full") | ||
|
|
||
| with test.step("Configure host to advertise 100/Half only"): | ||
| advertise_host_modes(hdata, ["100half"]) | ||
| verify_speed_duplex(target, ns, tdata, 100, "half") | ||
|
|
||
| with test.step("Configure host to advertise 10/half + 10/full + 100/half"): | ||
| advertise_host_modes(hdata, ["10half", "10full", "100half"]) | ||
| verify_speed_duplex(target, ns, tdata, 100, "half") | ||
|
|
||
| with test.step("Configure host to advertise 10/half + 10/full + 100/half + 100/full + 1000/full"): | ||
| advertise_host_modes(hdata, ["10half", "10full", "100half", "100full", "1000full"]) | ||
| verify_speed_duplex(target, ns, tdata, 1000, "full") | ||
|
|
||
| test.succeed() | ||
24 changes: 24 additions & 0 deletions
24
test/case/ietf_interfaces/speed_duplex_copper/topology.dot
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| graph "1x2" { | ||
| layout="neato"; | ||
| overlap="false"; | ||
| esep="+80"; | ||
|
|
||
| node [shape=record, fontname="DejaVu Sans Mono, Book"]; | ||
| edge [color="cornflowerblue", penwidth="2", fontname="DejaVu Serif, Book"]; | ||
|
|
||
| host [ | ||
| label="host | { <mgmt> mgmt | <data> data }", | ||
| pos="0,12!", | ||
| requires="controller", | ||
| ]; | ||
|
|
||
| target [ | ||
| label="{ <mgmt> mgmt | <data> data } | target", | ||
| pos="10,12!", | ||
|
|
||
| requires="infix", | ||
| ]; | ||
|
|
||
| host:mgmt -- target:mgmt [requires="mgmt", color=lightgrey] | ||
| host:data -- target:data [color=black, requires="link-ctrl copper"] | ||
| } |
42 changes: 42 additions & 0 deletions
42
test/case/ietf_interfaces/speed_duplex_copper/topology.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.