link fix
All checks were successful
Build and Deploy MITM Webserver / traffic_target (push) Successful in 1s
Build and Deploy MITM Webserver / build (push) Successful in 10s

This commit is contained in:
2026-03-09 17:37:51 +01:00
parent b836bf3f02
commit ce53ef5101
2 changed files with 69 additions and 35 deletions

View File

@@ -552,58 +552,87 @@ class BridgeLinkStateWatcher:
if source_profile is None or target_profile is None or source_profile == target_profile:
return None
cmd = [_ETHTOOL_BIN, "-s", target_ifname]
change_summary: Optional[str] = None
commands: list[tuple[list[str], str]] = []
if source_profile.autoneg is True:
if source_profile.speed_mbps is not None and source_profile.duplex is not None:
# A remote peer can pull this port down to a lower negotiated speed while autoneg
# stays enabled locally. Mirror that effective mode while keeping autoneg enabled
# on the sibling so its far-end peer can still negotiate successfully.
cmd.extend(
commands.append(
(
[
_ETHTOOL_BIN,
"-s",
target_ifname,
"speed",
str(source_profile.speed_mbps),
"duplex",
source_profile.duplex,
"autoneg",
"on",
]
)
change_summary = (
],
(
f"{target_ifname} link={source_profile.speed_mbps}Mb/"
f"{source_profile.duplex}/autoneg-on"
),
)
)
else:
cmd.extend(["autoneg", "on"])
change_summary = f"{target_ifname} link=autoneg-on"
commands.append(([_ETHTOOL_BIN, "-s", target_ifname, "autoneg", "on"], f"{target_ifname} link=autoneg-on"))
elif source_profile.autoneg is False and source_profile.speed_mbps is not None and source_profile.duplex is not None:
cmd.extend(
# Do not force autoneg off on sibling ports. The far-end peer on that segment may
# still rely on autoneg, and forcing a fixed mode here can leave the link down.
commands.append(
(
[
_ETHTOOL_BIN,
"-s",
target_ifname,
"speed",
str(source_profile.speed_mbps),
"duplex",
source_profile.duplex,
"autoneg",
"off",
]
)
change_summary = (
"on",
],
(
f"{target_ifname} link={source_profile.speed_mbps}Mb/"
f"{source_profile.duplex}/autoneg-off"
f"{source_profile.duplex}/autoneg-on-safe"
),
)
)
commands.append(
(
[_ETHTOOL_BIN, "-s", target_ifname, "autoneg", "on"],
f"{target_ifname} link=autoneg-on-safe",
)
)
else:
return None
last_error: Optional[Exception] = None
for cmd, summary in commands:
try:
subprocess.run(cmd, capture_output=True, text=True, check=True)
change_summary = summary
break
except (FileNotFoundError, subprocess.CalledProcessError) as exc:
last_error = exc
logger.debug(
"Failed to synchronize ethtool profile from %s to %s on bridge=%s: %s",
"Failed to synchronize ethtool profile from %s to %s on bridge=%s with %s: %s",
source_ifname,
target_ifname,
self.bridge_name,
cmd,
exc,
)
if change_summary is None:
if last_error is not None:
self._set_last_action(
f"failed to sync link profile from {source_ifname} to {target_ifname}: {last_error}"
)
return None
self._mark_managed_change(target_ifname)

View File

@@ -1,4 +1,4 @@
import { DeleteOutlined, PlusOutlined, ReloadOutlined } from '@ant-design/icons';
import { DeleteOutlined, RedoOutlined, PlusOutlined, ReloadOutlined } from '@ant-design/icons';
import {
Button,
Card,
@@ -242,7 +242,12 @@ export default function Network() {
okText="Reset"
cancelText="Cancel"
>
<Button loading={resetBusyInterface === record.name}>Reset defaults</Button>
<Button
icon={<RedoOutlined />}
loading={resetBusyInterface === record.name}
aria-label={`Reset ${record.name} to defaults`}
title={`Reset ${record.name} to defaults`}
/>
</Popconfirm>
),
},