feat: model IOL adapters as 4-port units like the IOU node type

IOL interfaces come in 4-port units (Ethernet0/0-3, Ethernet1/0-3, ...),
addressed like IOU as (adapter_number, port_number 0-3):

- IOLDockerVM builds EthernetAdapter(interfaces=4) per adapter and asks
  the runner for adapters x 4 interfaces (num-eth).
- DockerVM threads port_number through the NIO/capture API (the compute
  routes parsed it from the URL but dropped it); single-port adapters
  keep the historical bridge{N} names and command sequence, multi-port
  adapters get one bridge per port (bridge{a}_{p}).
- The unix-socket NIO wiring addresses sockets flat across adapters:
  adapter x ports-per-adapter + port, so single-port images keep their
  exact socket layout.
- The controller port list for GNS3_IOL_RUNNER docker nodes is generated
  by StandardPortFactory with the IOU naming (Ethernet{segment0}/{port0},
  segment size 4); plain docker nodes keep eth{N}.
This commit is contained in:
YueGuobin committed 2026-09-05 21:54:51 +08:00
1 parent 9b55164064
commit 0ca9ccc637
9 files changed
+267 -110

No files matched your search

+17 -13
View File
@@ -377,14 +377,17 @@ class VendorDockerVM(DockerVM):
await super().delete()
self._remove_unix_socket_host_dir()
async def _add_ubridge_connection(self, nio, adapter_number):
async def _add_ubridge_connection(self, nio, adapter_number, port_number=0):
"""
Override: with GNS3_UNIX_SOCKET_NIO, bridge the adapter through the
image's AF_UNIX datagram socket pair (raw Ethernet frames) instead of
a TAP interface moved into the container's network namespace.
Override: with GNS3_UNIX_SOCKET_NIO, bridge the adapter port through
the image's AF_UNIX datagram socket pair (raw Ethernet frames)
instead of a TAP interface moved into the container's network
namespace.
Per adapter N the image's network agent is expected to create, inside
GNS3_UNIX_SOCKET_DIR:
Ports are addressed flat across adapters: interface index = adapter
number × ports-per-adapter + port number (single-port adapters
reduce to the adapter number). Per interface N the image's network
agent is expected to create, inside GNS3_UNIX_SOCKET_DIR:
* ``s{N:02d}.sock`` — its receive socket; frames sent there are
injected into guest interface N;
@@ -398,7 +401,7 @@ class VendorDockerVM(DockerVM):
"""
if not self._unix_socket_nio:
return await super()._add_ubridge_connection(nio, adapter_number)
return await super()._add_ubridge_connection(nio, adapter_number, port_number)
try:
adapter = self._ethernet_adapters[adapter_number]
@@ -409,14 +412,15 @@ class VendorDockerVM(DockerVM):
)
)
bridge_name = f"bridge{adapter_number}"
interface_number = adapter_number * adapter.interfaces + port_number
bridge_name = self._bridge_name(adapter_number, port_number)
try:
await self._ubridge_send(f"bridge create {bridge_name}")
self._bridges.add(bridge_name)
wiring_dir = self._unix_socket_wiring_dir()
local_sock = os.path.join(wiring_dir, f"c{adapter_number:02d}.sock")
remote_sock = os.path.join(wiring_dir, f"s{adapter_number:02d}.sock")
local_sock = os.path.join(wiring_dir, f"c{interface_number:02d}.sock")
remote_sock = os.path.join(wiring_dir, f"s{interface_number:02d}.sock")
# A c-socket left over from a previous ubridge run would fail its bind.
with contextlib.suppress(OSError):
@@ -443,12 +447,12 @@ class VendorDockerVM(DockerVM):
raise
adapter.host_ifc = local_sock # bookkeeping / removal logging only
log.debug(
"Adapter %d of container '%s' wired via unix sockets %s <-> %s",
adapter_number, self._name, local_sock, remote_sock,
"Adapter %d port %d of container '%s' wired via unix sockets %s <-> %s",
adapter_number, port_number, self._name, local_sock, remote_sock,
)
if nio:
await self._connect_nio(adapter_number, nio)
await self._connect_nio(adapter_number, nio, port_number)
def _cleanup_console_resources(self):
"""