172 Commits

Author SHA1 Message Date
YueGuobin
1542a222f4
refactor: share the anchor-TAP lifecycle in the kernel-datapath mixin
The persistent-TAP lifecycle — probe, sweep, create, register, delete —
was implemented four times, once per node type, and the copies had drifted
(probe mechanism, _tap_datapath reset, keep-vs-recreate policy). The
mechanical half moves into KernelDatapathMixin:

- _probe_persistent_taps(probe_name): the scratch-TAP probe, returning the
  refusal for the caller's own warning (QEMU, Dynamips);
- _create_anchor_taps(ports, set_owner, keep_existing): sweep + create +
  optional ownership handover + carrier down + registry, with the ports
  enumerated by the node type and named through the new _tap_name hook;
- _delete_anchor_taps(): the suppressed tap sweep + per-link bridge
  cleanup + registry clear.

Each node type keeps what its fd holder dictates: the release step before
the tap sweep (the QEMU process, the IOL bridge, the hypervisor's NIO
bindings, the container port bridges), its probe policy, and its registry
lifetime. QEMU's now-unconditional registry clear aligns it with the other
three; everything else is behavior-preserving.
2026-10-06 21:17:50 +08:00
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
87ca2138e3
chore(lint): apply the 3.1 f-string wave to the kernel-datapath code
The rebase onto 65c858d45 brought upstream's UP032 enforcement; the
conflict resolution kept this branch's semantics on the overlapping
lines, so their .format() calls needed the conversion afterwards
(ruff check --fix, 41 sites) plus the formatter's rewrap (7 files).

Replicates the CI recipe locally: pip check, ruff check/format, mypy
2.3.1 (clean, 434 files), unit suite 2216 passed.
2026-10-06 00:28:06 +08:00
YueGuobin
7d04d08dba
fix: repair imports lost in the 3.1 rebase and meet the new lint baseline
The rebase onto upstream 3.1 (mypy + ruff I001/F401 waves) left the tree
short of the newly enforced baselines in three ways:

* contextlib / UbridgeError imports dropped as false duplicates during
  conflict resolution left NameErrors in iou_vm and qemu_vm (F821);
  the Dynamips router grabbed the compute-level NIOTAP instead of the
  hypervisor one, breaking TAP anchoring (test failure).
* unused imports (KERNEL_UNSUPPORTED_FILTERS, UbridgeError, List) and
  unsorted blocks left behind where the stack's later commits moved the
  last usage elsewhere — ruff I001/F401/RUF022 now enforce these.
* mypy, now baseline-free: cache dict annotations in tc_probe, the
  locators candidate list, the resolved-params None branch in the MCP
  runner, and validate_bpf_syntax keeps the upstream Dict[str, Any]
  return (the strict Optional[str] was wrong for the "valid" bool entry).

The e2e raw-frame probe resolves its compiler via shutil.which (S607)
and zips with strict= (B905); the remaining subprocess call is S603 by
nature and gets a per-file ignore like other test files.

ruff check/format clean, mypy at upstream parity (no new errors),
full unit suite 2167 passed.
2026-10-06 00:21:11 +08:00
YueGuobin
6e36b58a5d
fix(compute): refuse a duplicate port NIO and wire before bookkeeping
The compute-side backstop of the controller's duplicate-port guard
(keep-port-links + live-port bind made the controller guard reliable;
this is the layer under it). IOU and Dynamips bound the adapter NIO
before the uBridge/hypervisor attach: a failed attach left the port's
binding replaced — the link that still owned the port lost its handle
and its host state leaked (the IOU EBUSY incident's 8 orphan TAPs).
Dynamips was worse: its wiring idempotence check silently skipped the
attach on a second binding and rebound only the bookkeeping. A port
that already carries an NIO is now refused, and both types bind the
NIO only after the wiring succeeded.
2026-10-06 00:21:10 +08:00
YueGuobin
c343ce0b8f
feat(esw): wire peer anchors straight into the switch bridge
The Ethernet switch's kernel fast path: instead of a link crossing the
switch's per-port uBridge relay, the switch absorbs the peer's anchor into
its own kernel bridge. The peer's interface (Docker veth host end, QEMU
TAP, IOU port TAP, Dynamips port TAP) becomes the switch port, and frames
cross anchor -> switch bridge -> switch ports entirely in the kernel.

Wire format: the switch end receives nio_anchor ('join this interface to
my own bridge' — the mirror of nio_bridge), the peer end nio_bridge with a
null bridge ('your anchor is bridged elsewhere': carrier, markers and
impairments only — never bridge membership, and never a bridge delete, on
an interface this node does not own). Anchor names come from the shared
naming contract (utils.kernel_anchor), a pure function of node type, id,
adapter and port — the controller computes the peer's anchor while the
node may be stopped, which is what makes links to stopped nodes wireable.

Stopped peers defer the join; after any node of a link starts
(UDPLink.node_started) the controller re-pushes the switch NIO, and the
switch completes — or repairs, when a peer restart replaced its interface
under the same name — the join against the kernel's actual membership
instead of assuming it.

VLAN changes now edit membership in place: only the ports whose mode/VLAN
actually changed are touched, each losing exactly the previous mode's
entries the new mode does not want (the dot1q admits-all entry is one
range operation in both directions), and no port ever leaves the bridge to
change its VLANs. This replaces the old 'reset by re-enslaving' shortcut
(delif+addif on every wired port, added when the ports were the switch's
own TAPs): on absorbed anchors, re-enslaving an interface owned by another
node is where live testing watched links die — anchors occasionally lost
their bridge membership right after a ports_mapping update (later updates
then failed with delif EINVAL), reproducibly with qemu, IOU and Dynamips
peers and never with Docker's veths.

Eligibility: the switch side needs no capability of its own (its bridge
exists by construction); the peer must be able to anchor. Switch-to-switch
cascades stay on the relay — a kernel interface belongs to one bridge, and
joining two bridges needs a veth pair, deferred.

Verified live on a real server: qemu peers through four VLAN cycles with
both anchors enslaved throughout; a mixed switch (2 IOU + 2 Dynamips, four
kernel ports); Docker peers with real ICMP isolating and recovering (with
both anchors still enslaved); VPCS relay ports likewise in place.
2026-10-06 00:21:09 +08:00
YueGuobin
7201a870da
feat(dynamips): anchor every Ethernet port on a persistent TAP
Dynamips links can now ride the kernel datapath like Docker, QEMU and IOU:
each Ethernet slot/port gets a persistent TAP anchor (gd{id}e{slot}p{port}),
created through uBridge's tap module, and the Dynamips hypervisor opens it
with nio create_tap — the hypervisor holds the fd, exactly QEMU's shape.
Links attach the anchor to their per-link kernel bridge; the legacy UDP
tunnel remains the relay datapath for every other port.

Anchor lifecycle: born at node start (tap module probed with one
create/delete cycle, sweep of stale devices, ownership handed to the server
user, born down); a kernel link opens the anchor in the hypervisor, binds
the slot/port and enslaves it; removing the link releases the fd again
(nio delete) and detaches. A link bound while the router is stopped is
wired by the next start (deferred wiring). Node close follows QEMU's stop
order — the hypervisor's TAP NIOs go before tap delete, since it is
Dynamips, not uBridge, that holds the fds.

Stop is not close: vm stop only halts the emulated router, so the
hypervisor, the TAP fds, the bindings and the per-link bridges all survive
a stop/start untouched (attach skips ports that still hold their TAP NIO).

Port selection follows the adapter registry: ETHERNET_ADAPTERS and
ETHERNET_WICS name the models whose ports carry Ethernet frames (WIC-1ENET
included, at its Dynamips port number); serial, ATM and POS ports never
anchor, and a kernel link there errors with the relay-datapath message
instead of half-wiring. Adapters hot-added to a running router (OIR) get
their anchors at once.

The compute NIO routes accept nio_bridge alongside nio_udp (the same
widening QEMU needed), carry the endpoint's suspend flag on update (it is
the anchor's admin state on a kernel link), skip the hypervisor delete for
a kernel NIO (its TAP NIO was already released by the slot removal), and
the close path leaves NIOBridge instances to _stop_ubridge.
2026-10-06 00:21:09 +08:00
Mark Paronyan
bbebf20825
refactor: use f-strings in dynamips manager 2026-10-03 19:44:01 +03:00
Mark Paronyan
c458459626
refactor: use f-strings in dynamips NIO modules 2026-10-03 19:44:01 +03:00
Mark Paronyan
fba3ecc5fc
refactor: use f-strings in dynamips nodes 2026-10-03 19:44:00 +03:00
Mark Paronyan
a5d2bca921
refactor: use f-strings in dynamips router node 2026-10-03 19:44:00 +03:00
Mark Paronyan
306d8fbde4
refactor: remove unused imports 2026-10-03 19:43:58 +03:00
Mark Paronyan
38e9ddca09 style: sort imports in compute node modules 2026-10-02 12:43:26 +03:00
Mark Paronyan
c5b5091f5e
refactor: use explicit conversion in f-strings 2026-10-01 19:57:41 +03:00
Mark Paronyan
1babf7bcce
fix(typing): resolve mypy errors in compute.dynamips.nodes.router 2026-09-29 09:38:24 +03:00
Mark Paronyan
a0450b6bce
refactor: ruff autofixes 2026-09-27 15:55:10 +03:00
YueGuobin
f9f1a4d4d8
log: demote all per-node lifecycle INFO logs to DEBUG
Extend the docker_vm / base_node demotion to the remaining node types
and supporting layers:

  qemu_vm: MAC, adapters, disk image, RAM, priority, NIO added, created
  iou_vm:  application ID, adapters, serial, image, RAM, NIO added
  dynamips router: created, adapter, RAM, NVRAM, IOS, idle-PC, disk,
    MAC, NIO bound; hypervisor create/start/connect; nio_udp created
  builtin: ethernet_switch/hub, cloud, nat — created, NIO bound
  ubridge: hypervisor start/connect

At multi-node scale these per-node lines flood the log. Only the
project-open progress summary (loaded N nodes / creating N links)
now remains at INFO alongside genuinely exceptional events.
2026-08-11 01:05:53 +08:00
YueGuobin
d3527c00de
fix(marker): extend marker support to dynamips and cloud nodes
Dynamips needed its own NIO base class extended with a `_markers`
attribute and `markers` property (mirroring the existing `filters`
pattern), plus marker propagation from the controller-supplied NIO
settings through NIOUDP.create/update to the common destination
NIO that base_node._ubridge_apply_markers reads.

Cloud simply needed the missing _ubridge_apply_markers calls after
_ubridge_apply_filters in its two ubridge connection methods, same
pattern as the earlier docker fix.

Both types are now added back to _MARKER_CAPABLE_TYPES.
2026-07-16 00:39:51 +08:00
Jeremy Grossmann
c3d202abc9
Merge branch '3.0' into ssh-console-support 2026-05-02 22:10:28 +08:00
YueGuobin
ba220780a9
fix: improve hostname validation error messages with allowed characters
When a hostname validation fails, the error message now includes
the allowed character set to help users provide valid names.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-02 13:09:04 +08:00
Cristi
e6de7cb60a feat(compute): Fix Dynamips to listen on the internal port when ssh is used for auxiliary console 2026-04-30 23:50:15 +03:00
Cristi
cc05eb5850 feat(compute): Fix missing SSH wrapping for auxiliary console 2026-04-30 17:47:54 +03:00
Cristi
d64eca0418 feat(compute): add SSH console type support 2026-04-30 15:52:47 +03:00
grossmj
4f863f3767
Fix typo 2026-03-17 12:51:36 +08:00
grossmj
0aa6566e50
Prevent router to be duplicated when running and add tests 2026-03-17 12:49:38 +08:00
UmmmAGoodName
95bd76a212 Fixed issue #1605 regarding Cisco slots causing configs to break 2026-03-16 19:09:32 +01:00
grossmj
967c7d066d
Delete old code after merging 2024-09-22 22:02:14 +07:00
grossmj
7619080a50
Merge branch '2.2' into 3.0
# Conflicts:
#	gns3server/compute/base_node.py
#	gns3server/compute/docker/docker_vm.py
#	gns3server/compute/dynamips/nodes/c1700.py
#	gns3server/compute/dynamips/nodes/c2600.py
#	gns3server/compute/dynamips/nodes/c2691.py
#	gns3server/compute/dynamips/nodes/c3600.py
#	gns3server/compute/dynamips/nodes/c3725.py
#	gns3server/compute/dynamips/nodes/c3745.py
#	gns3server/compute/dynamips/nodes/c7200.py
#	gns3server/compute/dynamips/nodes/router.py
#	gns3server/compute/qemu/qemu_vm.py
#	gns3server/controller/node.py
#	gns3server/handlers/api/compute/docker_handler.py
#	gns3server/handlers/api/compute/dynamips_vm_handler.py
#	gns3server/handlers/api/compute/qemu_handler.py
#	gns3server/schemas/docker.py
#	gns3server/schemas/docker_template.py
#	gns3server/schemas/dynamips_template.py
#	gns3server/schemas/dynamips_vm.py
#	gns3server/schemas/node.py
#	gns3server/schemas/qemu.py
#	gns3server/schemas/qemu_template.py
2024-09-22 22:01:06 +07:00
grossmj
74782d413f
Change method to allocate AUX console for existing Dynamips nodes 2024-09-22 21:41:10 +07:00
grossmj
c41c11eb34
Backport auxiliary console support for Qemu, Docker and Dynamips nodes 2024-09-22 18:29:04 +07:00
grossmj
6f2b12c218
Fix to allow changing the auxiliary console for IOS router nodes. 2024-05-18 23:43:50 +07:00
grossmj
08ee40548f
Add custom executable paths on Windows 2024-01-28 12:13:08 +11:00
grossmj
bc1016474e Merge branch '2.2' into 3.0
# Conflicts:
#	gns3server/compute/base_node.py
2023-12-05 22:15:50 +10:00
grossmj
24bb0ca419 Add custom executable paths on Windows 2023-12-05 21:24:40 +10:00
grossmj
061ee1491d Disable IOS hostname check for Dynamips ghost instances 2023-11-22 18:47:05 +10:00
grossmj
267c4cbbbb Merge branch '2.2' into 3.0
# Conflicts:
#	README.md
#	gns3server/compute/base_node.py
#	gns3server/compute/dynamips/__init__.py
#	gns3server/compute/dynamips/hypervisor.py
#	gns3server/compute/qemu/__init__.py
#	gns3server/compute/qemu/qemu_vm.py
#	gns3server/controller/__init__.py
#	gns3server/crash_report.py
#	gns3server/handlers/api/controller/node_handler.py
#	gns3server/schemas/qemu_template.py
#	gns3server/static/web-ui/index.html
#	gns3server/static/web-ui/main.11410ae4eaf4d4c08cd0.js
#	gns3server/version.py
#	requirements.txt
2023-03-17 17:44:32 +10:00
grossmj
8ef59c7832 Fix c7200_i0_log.txt is created in the current directory. Fixes #2191 2023-02-27 22:58:52 +10:00
grossmj
c57b0cbb53 Find Dynamips version before hypervisor launch and do not require Dynamips v0.2.23 2023-01-16 18:04:46 +08:00
grossmj
27d9063e56 Merge 2.2 2023-01-05 12:38:00 +08:00
grossmj
5459543eb5 Fix issue when detecting Dynamips version (version is not set until after Dynamips has started) 2023-01-04 18:21:17 +08:00
grossmj
da7c7d16e4 Fix starting Dynamips on Windows 2023-01-04 15:12:09 +08:00
grossmj
771a9a5ddb Require Dynamips 0.2.23 and bind Dynamips hypervisor on 127.0.0.1 2023-01-02 15:26:59 +08:00
grossmj
1148dbc48e Fix issue when calling reset_console with running VPCS and Qemu nodes. Ref #1619 2022-12-30 20:54:37 +08:00
grossmj
17e0b2e259 Stricter checks to create/update an Ethernet switch and add tests 2022-12-24 08:20:51 +08:00
grossmj
80f5ca0c3f Checks for valid hostname on server side for Dynamips, IOU, Qemu and Docker nodes 2022-07-17 11:51:29 +02:00
grossmj
e50bed5bee Support delete Qemu disk image from API
Return the real disk image name in the 'hdx_disk_image_backed' property for Qemu VMs
2022-04-14 17:01:54 +07:00
grossmj
74c675d5b0 Drop Windows support 2022-01-19 22:28:36 +10:30
grossmj
cefab8d362 Rename __json__() to asdict() 2021-04-17 23:34:28 +09:30
grossmj
44074ff7c9 Some cleaning. 2021-04-17 18:36:32 +09:30
grossmj
c021e21309 Use black with -l 120 param. 2021-04-13 18:46:50 +09:30