diff --git a/.claude/memory/MEMORY.md b/.claude/memory/MEMORY.md index 7956d4d04..dbc0f3b8d 100644 --- a/.claude/memory/MEMORY.md +++ b/.claude/memory/MEMORY.md @@ -24,6 +24,7 @@ ### uBridge Permission - **[uBridge Permission Issue](./gns3-ubridge-permission.md)** - Docker containers fail to start due to missing CAP_NET_ADMIN/CAP_NET_RAW capabilities on uBridge +- **[Docker iptables FORWARD blocks bridge](./docker-iptables-forward-bridge.md)** - Docker sets FORWARD chain to DROP, blocking kernel bridge forwarding; `sudo iptables -P FORWARD ACCEPT` to fix ### Docker Container Stop Delay - **[Docker Container Stop Delay](./docker-container-stop-delay.md)** - Some containers take ~5s to stop because they don't handle SIGTERM (AlpiNet, OstinatoWireshark) diff --git a/.claude/memory/docker-iptables-forward-bridge.md b/.claude/memory/docker-iptables-forward-bridge.md new file mode 100644 index 000000000..2716fe7ab --- /dev/null +++ b/.claude/memory/docker-iptables-forward-bridge.md @@ -0,0 +1,38 @@ +--- +name: docker-iptables-forward-bridge +description: Docker iptables FORWARD DROP blocks kernel bridge forwarding, fix and symptoms +metadata: + type: reference +--- + +Docker sets the iptables `FORWARD` chain default policy to `DROP` when the +Docker daemon starts. This blocks **all** forwarded traffic through Linux +kernel bridges on the host — including `gns3br{N}` bridges created by the +builtin Ethernet Switch (ubridge `brctl`). + +## Symptoms + +- Nodes connected to the switch can send frames into the bridge (visible in + `tcpdump -i gns3br{N}`) but never receive forwarded unicast frames. +- `bridge fdb show` may fail to learn MAC addresses (frames dropped before + the bridge learning path). +- ARP and multicast/broadcast may appear to work because they flood, but + unicast replies never reach the destination. +- OSPF Hello / CDP visible on both sides but ICMP echo reply never returns. +- `ubridge bridge get_stats` shows symmetric IN/OUT counts (relay is fine), + `bridge fdb show` shows learned MACs, `bridge link show` shows `state forwarding` + on all ports — yet unicast still doesn't work. + +## Fix + +Run once per host boot, or make persistent via iptables-persistent / firewall config: + +```bash +sudo iptables -P FORWARD ACCEPT +``` + +## Related + +- [[ethernet-switch-ubridge-brctl-migration]] — the kernel bridge that hits this +- [[gns3-server-linux-only]] — datapath constraint +- [[gns3-ubridge-permission]] — another host-level prerequisite (CAP_NET_ADMIN) diff --git a/gns3server/compute/builtin/nodes/ethernet_switch.py b/gns3server/compute/builtin/nodes/ethernet_switch.py index 3f1fd263a..71ab22977 100644 --- a/gns3server/compute/builtin/nodes/ethernet_switch.py +++ b/gns3server/compute/builtin/nodes/ethernet_switch.py @@ -227,6 +227,8 @@ class EthernetSwitch(BaseNode): return self._bridge_name = self._free_iface("gns3br") await self._ubridge_send(f'brctl create "{self._bridge_name}"') + # ``brctl create`` leaves the bridge DOWN; bring it UP so it forwards. + await self._ubridge_send(f'link set "{self._bridge_name}" up') await self._ubridge_send(f'brctl vlanfiltering "{self._bridge_name}" on') self._bridge_created = True await self._apply_bridge_proto_if_needed() diff --git a/tests/api/routes/compute/test_ethernet_switch_nodes.py b/tests/api/routes/compute/test_ethernet_switch_nodes.py index 52154c2ae..40ac32ad0 100644 --- a/tests/api/routes/compute/test_ethernet_switch_nodes.py +++ b/tests/api/routes/compute/test_ethernet_switch_nodes.py @@ -85,6 +85,7 @@ class TestEthernetSwitchNodesRoutes: br = node._bridge_name node._ubridge_send.assert_has_calls([ call(f'brctl create "{br}"'), + call(f'link set "{br}" up'), call(f'brctl vlanfiltering "{br}" on'), ])