mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-11-04 06:21:15 +02:00
feat(iol): anchor IOL runner containers on persistent TAPs
IOL runner containers (IOLDockerVM, GNS3_IOL_RUNNER) had no kernel datapath: their guest leg is the runner's AF_UNIX socket pairs, so every link rode the uBridge relay. Their Ethernet bays now own persistent TAP anchors (gx names, the iol_docker key of the shared naming contract — born at node start like IOU's, before any link, so the switch fast path's deferred join can never miss them), and the per-port bridge's topology leg swaps between UDP (relay) and the anchor (kernel link) through the frozen stop -> delete -> add -> start contract — the unix binding never re-binds across a swap. - iol_docker_vm: KernelDatapathMixin hooks, the anchor lifecycle (_prepare_tap_datapath at _start_ubridge: probe ubridge_bridge_tap + ubridge_tap, sweep leftover, tap create born down), the kernel attach (ensure-then-add — tap create is strictly create-only, IFF_TUN_EXCL, so the ensure checks /sys/class/net first: an unconditional create answers EBUSY on the device the start loop just made), the release (port bridge stop + delete_nio_tap before the shared teardown) and the stop order the fd holders dictate (port bridges first, then tap delete, then the per-link bridges — all before the hypervisor stops). - vendor_docker_vm: the port-bridge creation factored into _ensure_unix_port_bridge (idempotent on the registered name), keeping the NIOBridge rejection for the generic unix-socket containers. - docker_vm: the three _kernel_veths lookups go through the _kernel_host_ifc hook — behavior-identical for DockerVM, and it is what lets the subclass route without overriding the binding methods. - kernel_anchor: the iol_docker key (gx) and kernel_anchor_type, the controller-side mapping for naming an IOL runner's anchor on the switch fast path (the marker check stays inline: this module sits below everything and must not import the controller package).
This commit is contained in:
7 files changed
+773
-31
No files matched your search
@@ -1807,16 +1807,17 @@ class DockerVM(DockerKernelDatapathMixin, BaseNode):
|
||||
|
||||
async def _connect_nio(self, adapter_number, nio, port_number=0):
|
||||
|
||||
host_ifc = self._kernel_veths.get((adapter_number, port_number))
|
||||
host_ifc = self._kernel_host_ifc(adapter_number, port_number)
|
||||
|
||||
if isinstance(nio, NIOBridge):
|
||||
if host_ifc is None:
|
||||
# Only reachable for containers started before the
|
||||
# unified-veth change (or unix-socket vendor containers,
|
||||
# rejected earlier): the kernel path needs the veth host end.
|
||||
# rejected earlier): the kernel path needs an anchor — the
|
||||
# veth host end, or the persistent TAP of an IOL runner.
|
||||
raise DockerError(
|
||||
"Adapter {adapter_number} port {port_number} of container '{name}' has no veth "
|
||||
"interface (it was started before the unified-veth datapath); "
|
||||
"Adapter {adapter_number} port {port_number} of container '{name}' has no host-side "
|
||||
"anchor interface (it was started before the unified-veth datapath); "
|
||||
"restart the node to attach a kernel link to it".format(
|
||||
adapter_number=adapter_number, port_number=port_number, name=self.name
|
||||
)
|
||||
@@ -1894,7 +1895,7 @@ class DockerVM(DockerKernelDatapathMixin, BaseNode):
|
||||
if self.ubridge:
|
||||
if isinstance(nio, NIOBridge):
|
||||
if self.status == "started":
|
||||
host_ifc = self._kernel_veths.get((adapter_number, port_number))
|
||||
host_ifc = self._kernel_host_ifc(adapter_number, port_number)
|
||||
if host_ifc is not None:
|
||||
# Incremental marker + filter reconcile on the anchor
|
||||
# — the relay-datapath equivalent of the branch below.
|
||||
@@ -2008,9 +2009,11 @@ class DockerVM(DockerKernelDatapathMixin, BaseNode):
|
||||
nio = self._ethernet_adapters[adapter_number].get_nio(port_number)
|
||||
if isinstance(nio, NIOBridge):
|
||||
# Kernel datapath: no relay bridge exists — capture via uBridge's
|
||||
# AF_PACKET module bound to the veth host end. Single capture per
|
||||
# uBridge process: a concurrent second one returns EALREADY.
|
||||
host_ifc = self._kernel_veths.get((adapter_number, port_number))
|
||||
# AF_PACKET module bound to the anchor (a veth host end for the
|
||||
# standard container, a persistent TAP for an IOL runner).
|
||||
# Single capture per uBridge process: a concurrent second one
|
||||
# returns EALREADY.
|
||||
host_ifc = self._kernel_host_ifc(adapter_number, port_number)
|
||||
await self._ubridge_send(f'capture start_kernel {host_ifc} "{output_file}"')
|
||||
return
|
||||
# Relay datapath (even though the adapter interface is a veth, the
|
||||
|
||||
Reference in new issue
Block a user