5825 Commits

Author SHA1 Message Date
YueGuobin
c7ffe919dc
feat: VPCS kernel datapath
A VPCS node's single adapter anchors on a persistent TAP the server
creates (tap create + set_owner via uBridge) and the vpcs process
attaches to by name: -e -d <gp{id8}e0p0> -n, the same
server-creates/guest-attaches shape as QEMU's netdev. -n (a vpcs fork
feature) keeps the guest's ip command from ifconfig'ing the anchor on
the host; the vpcs build is probed once per binary identity
(vpcs_tap capability, usage scan) and gates kernel links together
with ubridge_tap — anything else keeps the node on the relay (the
legacy local UDP tunnel on a stock binary, an AF_PACKET endpoint on
the anchor with a capable one).

VPCSVM takes KernelDatapathMixin: _connect_nio dispatches kernel
(enslave into the per-link bridge) / relay-on-anchor / legacy,
captures pick capture start_kernel vs the bridge engine, stop runs
under an execute lock and terminates the process before deleting the
anchor TAPs (a held device refuses deletion), and the duplicate-port
guard backstops the controller's. The NIO routes accept nio_bridge
and write suspend back on update.

_delete_anchor_taps verifies each tap is gone from sysfs and retries
a bounded three times: a holder can release its fd a moment after its
process was reaped (vpcs's daemon parent kills its console child and
exits first), so the unconditional delete raced EBUSY and leaked the
anchor intermittently.

The vpcs side needs IFNAMSIZ (16) instead of its own IFNAMESIZ (12)
for the -d name buffer — anchor names are 14 chars and truncated to a
nonexistent device, which TUNSETIFF then tries to create without
CAP_NET_ADMIN (fixed in the vpcs fork).

e2e (tests/e2e/test_vpcs_kernel_datapath.py): kernel and relay
scenarios green against the real binary — real ICMP both ways, §E.1/§
E.2 on the anchors, delay/suspend/capture, link delete/re-create,
node stop/restart self-heal, zero leftovers; the relay control passes
with both the fork binary and a stock one.
2026-10-12 17:19:57 +08:00
grossmj
dff5fbfd7d
fix: enable Layer 1 keepalives by default at the template level 2026-10-11 16:50:14 +07:00
grossmj
a437d46138
Revert "fix: enable Layer 1 keepalives by default. Ref #2975"
This reverts commit e4c25549f0d366aa9b04862d1237aa7d8a9e4120.
2026-10-11 16:44:07 +07:00
grossmj
e4c25549f0
fix: enable Layer 1 keepalives by default. Ref #2975 2026-10-11 16:34:44 +07:00
grossmj
6aaa0c578c
fix: update error logging to handle exceptions in WebSockets 2026-10-10 17:32:44 +07:00
YueGuobin
23f117de51
style: apply ruff format to drawing builder files 2026-10-10 14:34:28 +08:00
Guobin Yue
cff42e32e8
Merge branch '3.1' into feat/mcp-text-drawing-tool 2026-10-10 14:22:47 +08:00
Jeremy Grossmann
11c10dd85c
Merge branch '3.1' into fix/node-lifecycle-status-flood 2026-10-10 06:49:50 +02:00
Jeremy Grossmann
2bf35c31e4
Merge branch '3.1' into feat/mcp-text-drawing-tool 2026-10-10 06:49:24 +02:00
grossmj
4fc601e919
refactor: remove unused link filter schemas and fix test_add_v8_version_appliance 2026-10-10 06:40:52 +02:00
grossmj
6004e06499
Merge branch '3.1' into fork/markparonyan/api-issue-10-0eztih
# Conflicts:
#	gns3server/schemas/__init__.py
2026-10-10 06:39:15 +02:00
YueGuobin
82015dcb5c
fix(controller): stop flooding clients with transitional node statuses
Every node lifecycle call (start/stop) emitted a "starting"/"stopping"
node.updated notification on entry, and for the whole duration of the
call asdict() masked the real status with the transitional one — every
compute event forwarded in that window was re-emitted as a duplicate
transitional status.

Stop-all/start-all on a 13-node project pushed two transitional events
per node before the final state. Clients that do not render these
transitional statuses (the Web UI) showed nodes flickering through an
unexpected suspended-looking state before reaching started/stopped.

Remove the transitional notification and the status masking: clients
see the real statuses again (started/stopped), from the forwarded
compute events plus the controller-side confirmation. The wait option
on the lifecycle routes, the strict stop error handling and
wait_for_status() are unchanged.
2026-10-10 00:24:20 +08:00
Guobin Yue
7df7ce1c96
Merge branch '3.1' into fix/duplicate-device-configs-merge 2026-10-09 21:23:38 +08:00
Jeremy Grossmann
fbe93c4c4e
Merge pull request #2954 from markparonyan/api-issue-05-2xftmd
feat(api): add strict_names and batch node and link creation
2026-10-09 14:39:10 +02:00
grossmj
4195f3b7c1
fix: remove incorrectly merged code 2026-10-09 14:29:04 +02:00
grossmj
868973bb7c
Revert "fix: "LinkFilterParameter" already defined"
This reverts commit 8fee1d4c364b1cbbf1f67ca51ba60b8b5e3f7899.
2026-10-09 13:22:41 +02:00
YueGuobin
4de6758e2f
refactor(mcp): drop the raw drawing_create tool
The templated drawing_create_text/_rectangle/_ellipse tools cover the
LLM-relevant creation paths, and line/image/curve creation is not
needed from MCP or copilot for now. The management tools stay, so
existing drawings (including images and lines created in the Web UI)
remain fully manageable; drawing_update's raw svg parameter remains
the escape hatch for edits.
2026-10-09 11:12:18 +08:00
YueGuobin
5e8272fdd8
feat(agent): share Web UI compatible drawing builders between MCP and copilot
The text drawing tool was MCP-only; the copilot needs the same
capability and its area-annotation helper carried the same Web UI
compat bugs. Split into three layers with a single implementation:

- gns3server/utils/drawings.py: pure SVG builders (text, rectangle,
  ellipse) with full input validation (ValueError) — the Web UI
  format knowledge lives in core utils next to picture.py
- api_handlers.py: shared REST handlers (create_text_drawing_handler
  moved here, create_rectangle/ellipse_drawing_handler added) — the
  layer both consumers already share
- thin shells: MCP tools (drawing_create_text unchanged, plus new
  drawing_create_rectangle/_ellipse) and three LangChain tools
  (tools_v2/gns3_create_drawing.py) registered in both copilot mode
  lists

Shape builder details:

- rectangle: solid fill or "none", stroke block emitted only when a
  stroke is given, rx corner radius, dasharray validated against the
  Web UI's Qt remap table (QtDasharrayFixer rewrites those patterns)
- ellipse: bounding-box API; cx/cy derived as offsets inside the
  drawing box (the Web UI treats them as box-relative, not canvas
  coordinates); odd sizes round down and the actual size is returned

gns3_drawing_utils now delegates to the shared builders, fixing the
px-blind sizing, the ignored text-anchor/x/y centering and the
missing XML escaping in the area-annotation path.
2026-10-09 11:12:18 +08:00
YueGuobin
73cbb0387c
feat(mcp): add drawing_create_text tool with Web UI compatible SVG assembly
The Web UI re-parses drawing SVG into its own element model instead of
rendering it raw, which makes hand-assembled SVG error-prone for LLM
callers. The new tool assembles the SVG server-side, mirroring what the
Web UI itself serializes for text drawings:

- XML-escaped text content, validated color (#RGB/#RGBA/#RRGGBB/
  #RRGGBBAA) and font family (attribute-safe charset)
- multi-line support: literal newlines render as stacked lines in the
  Web UI (tspan split), width/height computed from the longest line
- pt-aware sizing: the Web UI renders font-size in pt (1pt = 4/3 px),
  so width uses a 0.8/char factor for monospace (1.0 proportional) and
  line height 1.9 x font_size, instead of the px-based 0.62 estimate
- ET.fromstring pre-check so bad input fails loudly instead of hitting
  the controller's silent drop of unparseable 500+ char SVG
- computed width/height/line_height returned for label layout

Also correct the raw drawing_create docstring: root width/height are
required (the parser reads them for the selection box), x/y on rect are
ignored, <g> is unsupported, <path> is re-interpreted as a freehand
curve, and the old examples lacked the mandatory root dimensions.
2026-10-09 11:12:18 +08:00
YueGuobin
1e0d123f4b
Merge branch '3.1' into fix/duplicate-device-configs-merge
Resolve conflicts against the upstream wave (PRs #2952-#2965, incl. the
typed-response/schema hardening and the drop of Python 3.10):

- controller/node.py: keep upstream's _transitioning/_confirm_status
  lifecycle guard; the kernel-anchor link wiring (node_started) runs
  after the transition completes.
- controller/link.py: keep upstream's add_node rollback (release_ports
  on create failure) and delete via release_ports; release_ports now
  resolves ports live (same staleness reason as _bind_members) and
  discards the node link unconditionally.
- schemas/controller/links.py: extend LinkFilterType with the eight
  kernel-datapath filter types and LinkFilterParameter.type with "str"
  so the newly typed /available_filters response validates; Link.filters
  stays a free-form dict — the vocabulary is capability-gated per link
  and validated by the controller (409), not by a strict request schema.
- schemas/controller/topology.py: drop the type: ignore made redundant
  by the dict filters field.
- tests: route-level filter validation now expects the controller's 409
  (unknown types, out-of-range values); packet_loss correlation is a
  valid kernel parameter (positive test added); OpenAPI assertions match
  the free-form filters property.
2026-10-09 10:03:50 +08:00
Jeremy Grossmann
aab707a48e
Merge branch '3.1' into api-issue-10-0eztih 2026-10-08 19:31:48 +02:00
grossmj
8fee1d4c36
fix: "LinkFilterParameter" already defined 2026-10-08 19:31:25 +02:00
Mark Paronyan
719d9cc667
refactor: ruff fixes 2026-10-08 20:25:20 +03:00
Jeremy Grossmann
aeac649c7f
Merge branch '3.1' into api-issue-10-0eztih 2026-10-08 19:21:07 +02:00
grossmj
34266d9d7b
style: reorder imports for comply with lint 2026-10-08 19:16:57 +02:00
Jeremy Grossmann
2dd1652e8a
Merge branch '3.1' into api-issue-07-x7z6we 2026-10-08 19:10:42 +02:00
Jeremy Grossmann
57e4d1632d
Merge branch '3.1' into api-issue-05-2xftmd 2026-10-08 19:04:36 +02:00
Jeremy Grossmann
7a3a34d3fc
Merge branch '3.1' into api-issue-06-8s9swu 2026-10-08 19:01:57 +02:00
Jeremy Grossmann
24634b8f0d
Merge pull request #2965 from GNS3/drop-python-3.10
Drop Python 3.10 support
2026-10-08 19:01:34 +02:00
grossmj
e0260f27c7
fix(rbac): annotate query variables with Select type for better type checking 2026-10-08 18:39:20 +02:00
Jeremy Grossmann
8dd438190d
Merge pull request #2960 from markparonyan/api-issue-12-cu0jkp
feat(api): add discriminators to link iface, appliance version and template settings schemas
2026-10-08 17:17:02 +02:00
grossmj
f50653107b
style: fix import and lint errors after merging 2026-10-08 16:57:41 +02:00
Jeremy Grossmann
48ac1ee5b7
Merge branch '3.1' into drop-python-3.10 2026-10-08 16:56:36 +02:00
Jeremy Grossmann
cea858acc4
Merge branch '3.1' into api-issue-12-cu0jkp 2026-10-08 16:46:37 +02:00
Jeremy Grossmann
029983260c
Merge branch '3.1' into api-issue-15-r12z73 2026-10-08 16:42:57 +02:00
grossmj
57286c4f09
style: fix lint errors 2026-10-08 16:01:51 +02:00
Jeremy Grossmann
ddcf661e11
Merge branch '3.1' into api-issue-07-x7z6we 2026-10-08 15:51:11 +02:00
grossmj
2642345b0a
fix: import errors 2026-10-08 15:33:53 +02:00
grossmj
811b45f863
fix: drop Python 3.10 and add Python 3.15 support 2026-10-08 15:14:34 +02:00
Jeremy Grossmann
3187828325
Merge branch '3.1' into api-issue-06-8s9swu 2026-10-08 15:02:51 +02:00
Jeremy Grossmann
71da996362
Merge branch '3.1' into api-issue-05-2xftmd 2026-10-08 14:40:53 +02:00
Jeremy Grossmann
53f3169107
Fix module list after merging 2026-10-08 14:17:07 +02:00
Jeremy Grossmann
a32f466183
Merge branch '3.1' into api-issue-04-burx2g 2026-10-08 13:59:00 +02:00
YueGuobin
d640050d4b
docs(features): quantify the kernel netem correl bias that collapses small rates
The kernel's correlated-random generator (get_crandom, sch_netem.c) truncates
instead of wrapping, starving both edges of the stationary distribution: an
event threshold below the correlation value is almost never reached. Measured
with stock iproute2 on this kernel — uBridge's netlink encoding is identical:
loss 1% + correl 25% drops nothing over 2000 pings (expected ~2%), 10%/25%
measures ~1.8% one way, only the 50% symmetry point survives. duplicate and
reorder correl share the same comparison structure and collapse the same way;
gemodel is immune (Markov chain over plain uniform draws) and is the honest
tool for bursty loss at a chosen mean rate.

Documented in the packet-filters correlation-bias bullet, and surfaced in the
two machine-facing descriptions (MCP link_update packet_loss note, controller
filter schema) so agents and clients stop walking into the trap.
2026-10-08 19:42:18 +08:00
Jeremy Grossmann
48b6257410
Merge pull request #2952 from markparonyan/api-issue-02-rp8mx3
feat(api): return node and add wait option on node lifecycle calls
2026-10-08 11:05:28 +02:00
Jeremy Grossmann
5055664456
Merge pull request #2957 from markparonyan/api-issue-08-67pip0
feat(api): add machine-readable error codes and align OpenAPI error schemas
2026-10-08 09:30:13 +02:00
Jeremy Grossmann
ed8b0c3e20
Merge pull request #2958 from markparonyan/api-issue-09-aef9as
feat(api): return token lifetimes and document API keys as bearer tokens
2026-10-08 04:35:19 +02:00
Jeremy Grossmann
dc57c95f1c
Merge pull request #2963 from markparonyan/api-issue-16-0gmylm
feat(api): add Snapshot.created and type NodeFile timestamps as date-time
2026-10-08 04:15:01 +02:00
Jeremy Grossmann
d797069921
Merge pull request #2964 from markparonyan/api-issue-17-asr039
feat: add optional ETag/If-Match concurrency for projects, nodes and links
2026-10-08 04:14:04 +02:00
Jeremy Grossmann
0a78a2bf12
Merge pull request #2961 from markparonyan/api-issue-13-bfbm9z
feat(api): add Notification schema and document notification streams
2026-10-08 04:11:14 +02:00