mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-09-08 11:05:33 +03:00
fix: derive per-node IOL app id so linked routers get distinct MACs
IOL derives interface MACs from its application ID. With a constant local-app every node shared the same MACs, and linked routers dropped each other's frames as MAC loops — ARP never resolved and pings were 100% lost even though the whole uBridge datapath was forwarding. Derive local-app from the node UUID (stable across restarts, kept in 1..1022) and align remote-app with the netiomux convention CML uses (1023). Verified end to end: two iol-xe nodes, Ethernet0/0 link, ARP resolves both ways, ping 4/5 (first loss = ARP), graceful stop/start keeps the NVRAM config.
This commit is contained in:
parent
0ca9ccc637
commit
b17d021bf6
@ -137,7 +137,10 @@ diagnosing wiring issues).
|
||||
`GNS3_IOL_MEMORY` (default 2048 MB). Keep container memory at IOL memory
|
||||
+ ~512 MB headroom or the OOM-killer will shoot the router.
|
||||
* **MAC addresses**: the `mac_address` template field and per-adapter custom
|
||||
MACs are ignored — IOL derives its own scheme (`aabb.cc00.0XY0`).
|
||||
MACs are ignored — IOL derives its own scheme from the node's application
|
||||
ID (`aabb.cc{app}{iface}`), e.g. `aabb.cc03.0400`. The ID is derived from
|
||||
the node UUID so linked routers always get distinct MACs (nodes sharing an
|
||||
ID would silently drop each other's frames as MAC loops).
|
||||
* **Interface names are IOL-style `Ethernet0/0`**, not `GigabitEthernet0/0`
|
||||
(4 ports per unit, matching the adapter-count granularity) — startup
|
||||
configs addressing `GigabitEthernet…` are rejected by the parser.
|
||||
|
||||
@ -29,9 +29,8 @@ netiomux exposes per-interface AF_UNIX datagram sockets in the container's
|
||||
``/tmp`` (``s%02d.sock`` receive, ``c%02d.sock`` send — raw Ethernet frames),
|
||||
wired by the generic ``GNS3_UNIX_SOCKET_NIO`` capability of VendorDockerVM
|
||||
(uBridge reaches them through a per-node runtime directory bound at /tmp —
|
||||
see ``VendorDockerVM._unix_socket_host_dir``). Because the netio bus
|
||||
directory is private to the node, the application IDs are fixed constants
|
||||
with no cross-node collisions.
|
||||
see ``VendorDockerVM._unix_socket_host_dir``). The local application ID is
|
||||
derived from the node ID so that linked nodes get distinct MACs.
|
||||
|
||||
This class is selected by the ``GNS3_IOL_RUNNER=1`` environment marker.
|
||||
"""
|
||||
@ -194,8 +193,13 @@ class IOLDockerVM(VendorDockerVM):
|
||||
"memory": self._iol_memory,
|
||||
"num-eth": self.adapters * 4, # every adapter is a 4-port unit
|
||||
"num-serial": 0, # GNS3 docker adapters are ethernet-only
|
||||
"local-app": 1,
|
||||
"remote-app": 2,
|
||||
# IOL derives interface MACs from the local application ID
|
||||
# (aabb.cc00.0<app><iface>0); every node needs a distinct one or
|
||||
# linked routers share MACs and drop each other's frames as loops.
|
||||
# Derived from the node ID: stable across restarts, unique enough
|
||||
# (CML allocates per-lab sequential IDs for the same reason).
|
||||
"local-app": int(self.id.replace("-", ""), 16) % 1022 + 1,
|
||||
"remote-app": 1023, # netiomux's fake peer application ID
|
||||
"user-id": os.getuid(),
|
||||
"group-id": os.getgid(),
|
||||
}
|
||||
|
||||
@ -261,14 +261,25 @@ async def test_start_writes_iol_config(compute_project, manager):
|
||||
assert config["binary"] == "/binary.iol"
|
||||
assert config["num-eth"] == 16 # 4 adapters, each a 4-port unit
|
||||
assert config["num-serial"] == 0
|
||||
assert config["local-app"] == 1
|
||||
assert config["remote-app"] == 2
|
||||
assert config["local-app"] == int(vm.id.replace("-", ""), 16) % 1022 + 1
|
||||
assert config["remote-app"] == 1023
|
||||
assert config["memory"] == 2048
|
||||
assert config["user-id"] == os.getuid()
|
||||
assert config["group-id"] == os.getgid()
|
||||
assert vm.status == "started"
|
||||
|
||||
|
||||
def test_local_app_is_distinct_per_node(compute_project, manager):
|
||||
# IOL derives interface MACs from the app ID: two nodes sharing one would
|
||||
# drop each other's frames as MAC loops, so IDs must differ per node.
|
||||
vm1 = _make_vm(compute_project, manager)
|
||||
vm2 = _make_vm(compute_project, manager)
|
||||
id1 = int(vm1.id.replace("-", ""), 16) % 1022 + 1
|
||||
id2 = int(vm2.id.replace("-", ""), 16) % 1022 + 1
|
||||
assert id1 != id2
|
||||
assert 1 <= id1 <= 1022 and 1 <= id2 <= 1022
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_start_rewrites_config_on_adapter_change(compute_project, manager):
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user