feat(docker): wire Docker-to-Docker links through a kernel bridge

Eligible links (both endpoints Docker, same compute, no filters/markers,
stopped nodes, no unix-socket NIO containers) are wired as veth pairs
enslaved into a per-link Linux kernel bridge (gns3 + 11 hex of the link
id, filling IFNAMSIZ) instead of the uBridge UDP relay, so frames flow
entirely in the kernel.

- NIOBridge NIO type: the controller decides the datapath in
  UDPLink._prepare and both computes enslave their deterministic gv*/gc*
  veth pair via uBridge's docker/brctl modules
- carrier/suspend = host-end admin state; both endpoints race-safely
  create/delete the bridge (EEXIST/EBUSY/ENOENT tolerated)
- veth adapters can still attach relay (UDP) links on a running node:
  lazy relay bridge over AF_PACKET on the host end (add_nio_ethernet)
- filters/markers/capture are rejected with explicit errors on this
  datapath (they live in the uBridge relay); vendor unix-socket
  containers are excluded; Server.enable_kernel_datapath is the
  kill-switch (default on)
- host-end veths survive container death and are removed on stop plus
  swept by name on the next start (crash/stale recovery)
This commit is contained in:
YueGuobin committed 2026-10-06 00:21:07 +08:00
1 parent 65c858d455
commit 37d7b9121e
13 files changed
+1031 -21

No files matched your search

@@ -260,12 +260,13 @@ async def duplicate_docker_node(
@router.post(
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=schemas.UDPNIO,
response_model=Union[schemas.UDPNIO, schemas.BridgeNIO],
dependencies=[Depends(compute_authentication)],
)
async def create_docker_node_nio(
adapter_number: int, port_number: int, nio_data: schemas.UDPNIO, node: DockerVM = Depends(dep_node)
) -> schemas.UDPNIO:
adapter_number: int, port_number: int, nio_data: Union[schemas.UDPNIO, schemas.BridgeNIO],
node: DockerVM = Depends(dep_node)
) -> Union[schemas.UDPNIO, schemas.BridgeNIO]:
"""
Add a NIO (Network Input/Output) to the node.
The port number on the Docker node is always 0.
@@ -279,12 +280,13 @@ async def create_docker_node_nio(
@router.put(
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=schemas.UDPNIO,
response_model=Union[schemas.UDPNIO, schemas.BridgeNIO],
dependencies=[Depends(compute_authentication)],
)
async def update_docker_node_nio(
adapter_number: int, port_number: int, nio_data: schemas.UDPNIO, node: DockerVM = Depends(dep_node)
) -> schemas.UDPNIO:
adapter_number: int, port_number: int, nio_data: Union[schemas.UDPNIO, schemas.BridgeNIO],
node: DockerVM = Depends(dep_node)
) -> Union[schemas.UDPNIO, schemas.BridgeNIO]:
"""
Update a NIO (Network Input/Output) on the node.
The port number on the Docker node is always 0.