2 Commits

Author SHA1 Message Date
YueGuobin
c3c025ab2a
fix: resolve the code-review findings on the kernel datapath
Compute:
- Track the anchor that owns uBridge's single AF_PACKET capture slot: a
  second kernel port's capture is refused with a clear error (its flag
  rolled back), a failed start no longer wedges the port, and only the
  owning port's stop issues the process-wide `capture stop_kernel`
  (docker/qemu/iou/dynamips/switch, via the mixin's slot helpers).
- Unwind failed starts instead of leaking uBridge and the anchor TAPs:
  QEMU's stop body runs under try/finally, QEMU and IOU start the datapath
  inside the launch try, Dynamips undoes a half-attached port (the retry
  used to be short-circuited into a silent black hole), and Docker deletes
  the veth pair when the namespace move fails.
- Restore the relay filter guard on IOU (kernel-only filters raise
  NodeError, an uncompilable BPF line degrades to a warning), validate the
  eBPF/quota/window/bpf filter shapes before touching the bridge (short or
  non-numeric values surfaced as 500s after partial state), and refuse a
  second NIO on an occupied Docker/QEMU port (the guard IOU and Dynamips
  already had).
- Probe fixes: `_probe_bridge_tap` survives a failing uBridge start, and
  the probe caches key on ctime too, so a chmod/setcap remedy re-probes.

Controller:
- Parse GNS3_UNIX_SOCKET_NIO like the compute does (line-anchored, truthy
  value) and mirror the compute's class selection in kernel_anchor_type.
- Read partial capability reports defensively; make BridgeNIO.bridge
  required-but-nullable so an omitted key is a 422 rather than a KeyError.
- Strip the packet_loss correlation slot even when it is zero: the relay
  filter takes exactly one argument and rejected `packet_loss 10 0`.

Ethernet switch: skip ports whose absorbed anchor does not exist yet (the
join is deferred by design) and roll the ports_mapping back when the VLAN
reconcile fails, so a retry still diffs against the old mapping.

Agent: reject device config entries without a device_name instead of
silently dropping them (a malformed batch used to execute partially while
reporting success).

Also split the netem builder to clear C901 and drop the two per-file ruff
ignores the PR had added, keeping the remove-only policy.
2026-10-06 19:55:21 +08:00
YueGuobin
e13e5f3804
fix(tools): merge same-device entries before device command execution
A batch carrying the same device twice lost all but the last entry's
commands: the per-device command map kept only the last entry while
result processing iterated every original entry, so each row reported
the last entry's output under its own command list.

c3c78f99a consolidated the merge into the MCP template renderer, but
that only runs when a template is passed — the MCP direct-commands
path and gns3-copilot's direct _run path were left uncovered.
Normalize once in each tool's _run (single point covering all entry
paths, restoring the c42b3a59b coverage) and keep the renderer merge
as boundary normalization. Blocked-command info now also accumulates
across same-device entries instead of last-winning in the per-device
map.
2026-10-06 00:21:11 +08:00