mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-10-27 18:52:23 +02:00
docs(ubridge): the fifth L2-only creator, and the call site that used it
The spec's B table grows its fifth row: bridge add_nio_tap mints a transient TAP when the name is free and hardens it at creation, while an attach to an existing device (possibly a user-owned TAP with addresses) is left untouched. The rule paragraph spells out attach-is-not-a-creation. Delivery: uBridge fb72758, closing the gap the new e2e assertions found (live: the switch's gns3*-0 relay TAP carried fe80::). The server issues no link l2only of its own -- the switch call site now documents that the TAP is minted-and-hardened by add_nio_tap, and the ESW feature doc describes the uBridge-side close instead of a server workaround.
This commit is contained in:
parent
30cb7119e5
commit
f13da59f23
@ -4,10 +4,11 @@ See LICENSE file for licensing information.
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
> Frozen requirements spec for the **uBridge** project. Status: **delivered**
|
> Frozen requirements spec for the **uBridge** project. Status: **delivered**
|
||||||
> (uBridge `e2e3155` — `link l2only` plus the creators that apply it) and
|
> (uBridge `e2e3155` — `link l2only` plus the creators that apply it;
|
||||||
> verified from the server side: anchors and per-link bridges report
|
> `fb72758` — the fifth creator: the TAP `bridge add_nio_tap` creates for a
|
||||||
> `addrgenmode none`, `ip -4/-6 addr` are empty, and an idle anchor is silent
|
> free name) and verified from the server side: anchors and per-link bridges
|
||||||
> once the one-shot membership burst of §0 has settled.
|
> report `addrgenmode none`, `ip -4/-6 addr` are empty, and an idle anchor is
|
||||||
|
> silent once the one-shot membership burst of §0 has settled.
|
||||||
>
|
>
|
||||||
> **Residual, accepted (measured after delivery):** enslaving a port still
|
> **Residual, accepted (measured after delivery):** enslaving a port still
|
||||||
> makes the *bridge device* announce its multicast memberships — one IGMPv3
|
> makes the *bridge device* announce its multicast memberships — one IGMPv3
|
||||||
@ -141,10 +142,16 @@ directly, and a caller cannot forget it:
|
|||||||
| `docker create_veth <host> <guest>` | the **host** end only | the guest end moves into a container netns and is deliberately untouched |
|
| `docker create_veth <host> <guest>` | the **host** end only | the guest end moves into a container netns and is deliberately untouched |
|
||||||
| `link veth <name> <peer>` | both ends | both ends are host-side |
|
| `link veth <name> <peer>` | both ends | both ends are host-side |
|
||||||
| `brctl create <bridge>` | the bridge device itself | the fabric the anchors are enslaved to; the bridge's own link-local floods to every port |
|
| `brctl create <bridge>` | the bridge device itself | the fabric the anchors are enslaved to; the bridge's own link-local floods to every port |
|
||||||
|
| `bridge add_nio_tap <br> <name>` | the TAP it **creates** (name free) | by-name `TUNSETIFF` creates a transient device when the name is free — cloud's bridge interfaces, and the relay swap's create-if-missing path. Hardened at creation; an attach to an existing device is left untouched (the caller may name a user-owned TAP that has addresses). |
|
||||||
|
|
||||||
Rule for future creators: any command that creates a host-side device for the
|
Rule for future creators: any command that creates a host-side device for the
|
||||||
data plane hardens it, and the acceptance checks in §E apply to it.
|
data plane hardens it, and the acceptance checks in §E apply to it.
|
||||||
|
|
||||||
|
An **attach** is not a creation: `bridge add_nio_tap` (and every other open
|
||||||
|
of a TAP that already exists) must leave that device's addresses alone. The
|
||||||
|
transient TAP `bridge add_nio_tap` creates for a free name is a creation and
|
||||||
|
is hardened like the rest — best-effort, before the NIO is handed back.
|
||||||
|
|
||||||
## C. Implementation notes (netlink, not `/proc`)
|
## C. Implementation notes (netlink, not `/proc`)
|
||||||
|
|
||||||
- Use `RTM_SETLINK` with `IFLA_AF_SPEC{ AF_INET6, IFLA_INET6_ADDR_GEN_MODE =
|
- Use `RTM_SETLINK` with `IFLA_AF_SPEC{ AF_INET6, IFLA_INET6_ADDR_GEN_MODE =
|
||||||
@ -198,17 +205,35 @@ data plane hardens it, and the acceptance checks in §E apply to it.
|
|||||||
|
|
||||||
## gns3-server alignment (informational — not uBridge scope)
|
## gns3-server alignment (informational — not uBridge scope)
|
||||||
|
|
||||||
- **Call sites unchanged**: the four creators harden the devices; the server does
|
- **Call sites**: the creators harden the devices; the server issues no
|
||||||
not issue `link l2only`, and no NIO/JSON schema, filter or MCP tool description
|
`link l2only` itself, and no NIO/JSON schema, filter or MCP tool
|
||||||
changes. This is host-side hygiene only.
|
description changes. This is host-side hygiene only.
|
||||||
- **e2e assertions to add** (kernel-datapath suites, alongside the existing
|
- **The fifth creator was found by these servers' e2e assertions**: on a
|
||||||
capture/marker/filter checks):
|
build predating `fb72758`, the Ethernet switch's relay port TAPs
|
||||||
- anchors and per-link bridges have no IPv4/IPv6 addresses (§E.1);
|
(`gns3{id}-N`, created implicitly by `bridge add_nio_tap`) carried a live
|
||||||
- an idle anchor captures zero frames in 5 s (§E.2);
|
`fe80::` — the §E.1 assertion failed on exactly that device, live. The
|
||||||
|
close is uBridge-side (§B table row 5): the transient TAP is hardened at
|
||||||
|
creation, attaches stay untouched. The server side needed no change for
|
||||||
|
it — the assertion alone caught it, and it now guards the fixed build.
|
||||||
|
- **e2e assertions** (landed in `tests/e2e/harness.py`, asserted by the
|
||||||
|
kernel-datapath suites alongside the existing capture/marker/filter checks):
|
||||||
|
- anchors and per-link bridges have no IPv4/IPv6 addresses, addrgenmode
|
||||||
|
`none` (`assert_pure_l2`, §E.1) — on the kernel scenarios' anchors and
|
||||||
|
bridges, and on relay-mode anchors/switch TAPs alike (the hardening is a
|
||||||
|
creation-time property, not a datapath one). The switch relay-TAP
|
||||||
|
assertion is what exercises the fifth creator end-to-end (the same
|
||||||
|
uBridge creation path cloud's transient TAPs take);
|
||||||
|
- an idle link stays silent for 5 s after the settle window
|
||||||
|
(`assert_idle_silence`, §E.2) — measured with the guest interfaces shut
|
||||||
|
(silencing IOS's own CDP/keepalives) over the anchors and the bridge;
|
||||||
- a silent-failure guard found while validating this spec: after attach, every
|
- a silent-failure guard found while validating this spec: after attach, every
|
||||||
bridge port reports `brport/state == 3` (forwarding). A bridge device left
|
bridge port reports `brport/state == 3` (forwarding) (`assert_forwarding`).
|
||||||
DOWN keeps its ports `DISABLED` (`state == 0`) and forwards nothing — with
|
A bridge device left DOWN keeps its ports `DISABLED` (`state == 0`) and
|
||||||
no error anywhere, so the assertion is the only signal.
|
forwards nothing — with no error anywhere, so the assertion is the only
|
||||||
|
signal.
|
||||||
- **Rollout**: with a uBridge that lacks the command the anchors keep today's
|
- **Rollout**: with a uBridge that lacks the command the anchors keep today's
|
||||||
behaviour (noise present). The e2e assertions skip when `link l2only` answers
|
behaviour (noise present). The e2e assertions skip when `link l2only` answers
|
||||||
`202-Unknown command`, mirroring the existing tc-capability degradation.
|
`202-Unknown command` (`harness.l2only_supported()` probes a throwaway
|
||||||
|
uBridge once), mirroring the existing tc-capability degradation. A build
|
||||||
|
that has the command but predates `fb72758` fails the switch relay-TAP
|
||||||
|
assertion instead of skipping: the gap is exactly what it exists to catch.
|
||||||
|
|||||||
@ -41,6 +41,15 @@ on the relay:
|
|||||||
`GNS3_UNIX_SOCKET_NIO` containers);
|
`GNS3_UNIX_SOCKET_NIO` containers);
|
||||||
* cross-compute links, non-Ethernet ports: the common rules.
|
* cross-compute links, non-Ethernet ports: the common rules.
|
||||||
|
|
||||||
|
**Relay port TAPs.** The switch's own relay-path port TAPs (the
|
||||||
|
`gns3{id}-N` devices) are created *implicitly* by uBridge's
|
||||||
|
`bridge add_nio_tap` — a name that is free is minted as a transient TAP,
|
||||||
|
and uBridge hardens it L2-only at creation (the fifth creator of
|
||||||
|
`docs/design/ubridge-l2-anchor-spec.md` §B, uBridge `fb72758`). The server
|
||||||
|
issues nothing extra: without that hardening the device would take a
|
||||||
|
kernel-default IPv6 identity whose DAD/MLD noise floods the segment, which
|
||||||
|
is exactly what the e2e's relay-control §E.1 assertion guards against.
|
||||||
|
|
||||||
## The wire format: one NIO names the other end's interface
|
## The wire format: one NIO names the other end's interface
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
@ -386,7 +386,10 @@ class EthernetSwitch(KernelDatapathMixin, BaseNode):
|
|||||||
ubridge_bridge = self._ubridge_bridge_name(port_number)
|
ubridge_bridge = self._ubridge_bridge_name(port_number)
|
||||||
tap = self._tap_name(port_number)
|
tap = self._tap_name(port_number)
|
||||||
|
|
||||||
# per-port uBridge relay -- uBridge holds the TAP fd
|
# per-port uBridge relay -- uBridge holds the TAP fd. Nothing created
|
||||||
|
# this TAP before: add_nio_tap mints it (transient, a free name) and
|
||||||
|
# hardens it L2-only at creation (ubridge-l2-anchor-spec §B, the fifth
|
||||||
|
# creator — the server issues no link l2only of its own).
|
||||||
await self._ubridge_send(f"bridge create {ubridge_bridge}")
|
await self._ubridge_send(f"bridge create {ubridge_bridge}")
|
||||||
await self._ubridge_send(f'bridge add_nio_tap {ubridge_bridge} "{tap}"')
|
await self._ubridge_send(f'bridge add_nio_tap {ubridge_bridge} "{tap}"')
|
||||||
# enslave the same TAP to the kernel bridge (the cloud.py::_add_linux_ethernet move)
|
# enslave the same TAP to the kernel bridge (the cloud.py::_add_linux_ethernet move)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user