fix(iou): carry suspend from the NIO update body

The IOU NIO update route never copied the body's suspend flag onto the
NIO; the Docker and QEMU routes always did. Harmless on the relay, where
suspend is emulated by the synthetic frequency_drop filter the controller
injects, but fatal on a kernel link, whose suspend *is* the anchor's
admin state: a suspended link kept forwarding traffic, and the resume
looked like it worked because nothing had ever stopped.
This commit is contained in:
YueGuobin 2026-10-01 00:59:53 +08:00
parent 806afec0d8
commit f23c3bb6e6
No known key found for this signature in database
2 changed files with 38 additions and 1 deletions

View File

@ -228,8 +228,11 @@ async def update_iou_node_nio(
if isinstance(nio_data, schemas.UDPNIO) and nio_data.filters:
nio.filters = nio_data.filters
# NIO type is a Union (Ethernet/TAP/UDP/bridge); only UDPNIO and
# BridgeNIO carry markers.
# BridgeNIO carry markers and suspend. Suspend is what the compute turns
# into an admin-down anchor on a kernel link (native carrier), so it must
# reach the NIO like it does on the Docker/QEMU routes.
nio.markers = getattr(nio_data, "markers", None) or {}
nio.suspend = getattr(nio_data, "suspend", None) or False
await node.adapter_update_nio_binding(adapter_number, port_number, nio)
return nio.asdict()

View File

@ -297,6 +297,40 @@ class TestIOUNodesRoutes:
assert response.json()["type"] == "nio_udp"
assert response.json()["filters"] == {}
async def test_iou_nio_update_carries_suspend_and_bridge(
self, app: FastAPI, compute_client: AsyncClient, vm: dict
) -> None:
"""
A kernel-datapath NIO (nio_bridge) is accepted on the IOU routes, and
the update body's suspend flag reaches the NIO — the compute turns it
into an admin-down anchor, so a dropped suspend would leave a
"suspended" link forwarding traffic.
"""
url = app.url_path_for(
"compute:create_iou_node_nio",
project_id=vm["project_id"],
node_id=vm["node_id"],
adapter_number="1",
port_number="0",
)
params = {"type": "nio_bridge", "bridge": "gns3a1b2c3d4e5f"}
response = await compute_client.post(url, json=params)
assert response.status_code == status.HTTP_201_CREATED
assert response.json()["type"] == "nio_bridge"
url = app.url_path_for(
"compute:update_iou_node_nio",
project_id=vm["project_id"],
node_id=vm["node_id"],
adapter_number="1",
port_number="0",
)
params["suspend"] = True
response = await compute_client.put(url, json=params)
assert response.status_code == status.HTTP_201_CREATED
assert response.json()["suspend"] is True
async def test_iou_nio_create_ethernet(
self, app: FastAPI, compute_client: AsyncClient, vm: dict, ethernet_device: str
) -> None: