7136 Commits

Author SHA1 Message Date
YueGuobin
f2360f85fc
feat(marker): add project-level marker aggregation endpoint
Add a read-only `markers` property on Project that flattens every link's
markers into a single dict keyed by "{link_id}/{name}", each entry
carrying the parent link_id and capture-side node_id. Expose it via
GET /projects/{pid}/markers (Project.Audit) so the frontend can fetch all
markers in one round-trip instead of enumerating links first.

Also surface a marker count in project.stats().
2026-07-16 00:39:51 +08:00
YueGuobin
ab5b7444d4
feat(marker): add IOU node marker support via iol_bridge
IOU uses iol_bridge (not bridge) with extra bay/unit positional
arguments in add_packet_filter. Add _ubridge_apply_markers override
that mirrors the existing _ubridge_apply_filters pattern, called at
the same three sites: _networking, adapter_add_nio_binding, and
adapter_update_nio_binding.
2026-07-16 00:39:51 +08:00
YueGuobin
c62b9b0283
refactor(marker): converge to filter single-path model, remove dual-apply endpoints
Markers now follow exactly the same apply pattern as packet filters:
state lives in Link._markers, application goes through NIO
(update() -> PUT /nio -> _ubridge_apply_markers). The former
immediate-apply REST endpoints (/markers/start, /markers/stop on
the compute side) and the per-node start_marker/stop_marker methods
are removed — they were a legacy of the original capture-inspired
design and have been superseded by the NIO flow.

Changes:
- controller/udp_link: start_marker/stop_marker/update_marker now
  set _markers state + call self.update() (mirrors update_filters).
  Removed _marker_capture_nodes runtime dict and its helpers.
- controller/project: _create_link_from_topology_data restores
  _markers directly from persisted data (with BPF validation,
  like filter reload). No long calls start_marker during load.
- compute: _ubridge_apply_markers swallows BPF compile errors
  (warn+skip), matching _ubridge_apply_filters behaviour so a
  single bad expression cannot break link creation / node restart.
- Removed: /markers/start,stop endpoints (6 handlers across
  vpcs/qemu/docker route files), node start_marker/stop_marker
  methods (3 VM files), _ubridge_delete_marker_filter,
  _marker_capture_nodes, MarkerDelete schema.

Net: ~280 lines of dead code removed; marker and packet filter now
share a single, unified apply path via the NIO.
2026-07-16 00:39:51 +08:00
YueGuobin
88c03d1431
fix(marker): restore markers from topology on project load
_create_link_from_topology_data now restores traffic-insight markers
(mirroring how filters are restored via update_filters), so markers —
including their color — survive project close/reopen and server restart.

Guard start_marker's uBridge POST with 'if self._created' (exactly as
update_filters guards its update() call): during project load the link
is not yet created, so only _markers state is recorded and the marker
is applied once via the NIO flow in create()/_ubridge_apply_markers —
no double application.
2026-07-16 00:39:51 +08:00
YueGuobin
3f15ac38f6
feat(marker): add optional color field to marker data model
Add a user-chosen hex color (e.g. '#ff5722') to each marker, stored in
Link._markers alongside bpf/tag/enabled. The color:

- Is serialized with the link (asdict) and persisted in the topology, so
  it survives project reload and is consistent across devices.
- Never reaches uBridge (compute ignores it) — it is purely a Web UI
  concern.
- Can be updated independently of the BPF (color-only changes skip the
  ubridge round-trip).

MarkerCreate schema gains color: Optional[str]; start_marker and
update_marker carry it through; REST create/update endpoints pass it.

The marker.match WebSocket event stays lean (no color) — the Web UI maps
filter -> color from the link state it already holds.
2026-07-16 00:39:51 +08:00
YueGuobin
b8f49696cc
fix(marker): use allowlist in _choose_marker_side, align with _get_filter_node
Replace the complex tier-based fallback (which leaked into unsupported
switch types on the final tiers) with a simple allowlist of
_MARKER_CAPABLE_TYPES, mirroring _get_filter_node in link.py.

Also accept stopped nodes — like packet filters, markers are stored on
the NIO and applied when the node starts via _ubridge_apply_markers.
2026-07-16 00:39:51 +08:00
YueGuobin
239f42f5aa
fix(marker): stop auto-deleting markers on node stop in node_updated
Markers are persistent link-scoped features (like packet filters), not
transient runtime features (like capture).  Tearing them down on every
node stop breaks stop/start restore: the NIO-based re-application in
_ubridge_apply_markers works correctly on restart, but node_updated
was prematurely calling stop_marker which erased _markers state and
dumped an empty topology.

Now markers survive node stop transparently — the ubridge filter dies
with the process but is re-added from nio.markers in
add_ubridge_udp_connection when the node starts again, mirroring
exactly how packet filters behave.
2026-07-16 00:39:51 +08:00
YueGuobin
7c90fa9e64
fix(marker): ride markers on NIO so they survive node restart and project reload
Mirror the packet-filter lifecycle: marker specs now live on the NIO
(next to filters), ride in link_data from controller to compute on
every NIO create/update, and are reapplied by _ubridge_apply_markers
in add_ubridge_udp_connection (bridge creation / node restart) and
update_ubridge_udp_connection (NIO update — following the preceding
reset_packet_filters so markers survive filter changes).

Changes:
- NIO / NIOUDP: _markers property + asdict
- schemas/compute/nios.py: UDPNIO.markers field
- base_manager.create_nio: nio.markers from settings
- PUT /nio routes (vpcs/qemu/docker): nio.markers update
- base_node: _ubridge_apply_markers(bridge_name, nio) iterates
  nio.markers, computes pcap path, calls _ubridge_add_marker_filter
  + MarkerManager.register; called after _ubridge_apply_filters
- controller udp_link: _get_node_markers + _markers_for_node (route
  by capture_node_id); markers in create() and update() link_data
- /markers/start,stop endpoints: mirror spec onto nio.markers so
  the marker survives a subsequent node stop/start without a PUT
- tests: add markers field to NIO data expectations

This covers:
- Node restart: NIO persists, add_ubridge_udp_connection re-applies
- Filter update: reset wipes markers, _ubridge_apply_markers re-adds
- Project reload: create() carries markers in link_data → create_nio
- Immediate create: endpoint sets nio.markers immediately
2026-07-16 00:39:51 +08:00
YueGuobin
540e1c5678
config: set marker_listen_port default to 3070 and document in config templates
Change the marker UDP sink default from port=0 (OS-chosen) to 3070 for
predictable firewall/debugging/monitoring.

Add marker_listen_host and marker_listen_port with documentation to
config_samples/gns3_server.conf and scripts/gns3_server.conf.
2026-07-16 00:39:51 +08:00
YueGuobin
88465e872c
fix(marker): add _choose_marker_side to exclude non-uBridge node types
_choose_capture_side prefers BUILTIN_NODE_TYPES which includes
ethernet_switch/ethernet_hub/NAT etc. — nodes that do not use uBridge
and therefore have no bridge for a marker filter to attach to.

Add _choose_marker_side with a _MARKER_UNSUPPORTED_TYPES blocklist
so marker capture-side selection skips NIO-only switches and picks
the uBridge-backed node (VPCS/QEMU/Docker/etc.) instead.

Verified end-to-end: PC1↔Switch↔PC2 links with arp markers correctly
pick VPCS nodes; MARK signals flow through to WebSocket and pcaps
are written.
2026-07-16 00:39:51 +08:00
YueGuobin
d2e9823e6c
feat: implement traffic insight marker backend (ubridge mark filter)
Add compute-side marker subsystem that receives ubridge UDP MARK signals
and forwards them as project-scoped notifications to the web UI for
real-time traffic coloring. Matched packets are always saved to per-link
pcaps for future replay.

Key components:
- gns3server/compute/marker/: MarkerManager (singleton, UDP listener +
  O(1) registry keyed by (node_id, filter_name)) + MarkerListener
  (DatagramProtocol parsing MARK lines per ubridge integration contract)
- gns3server/compute/base_node.py: marker sink/node config at ubridge
  startup; shared _ubridge_add_marker_filter / _ubridge_delete_marker_filter
- Per-node start_marker/stop_marker: VPCS (VPCS-{id}), QEMU
  (QEMU-{id}-{adapter}), Docker (bridge{adapter})
- Compute REST /markers/start + /markers/stop (vpcs/qemu/docker route files)
- Controller Link._markers state + UDPLink.start_marker/stop_marker/
  update_marker (mirror capture pattern: BPF validation, _choose_capture_side,
  node.post forwarding, topology persistence)
- Controller REST GET/POST/DELETE/PUT /v3/projects/{p}/links/{l}/markers
- Config: marker_listen_host / marker_listen_port in ServerSettings
- Signal routing: creation-time registry O(1) lookup, no node-table scan;
  project-scoped WS stream (not global); event payload always carries
  project_id for frontend scoping

Tests: 14 unit tests (registry, listener parsing, UDP round-trip);
562 existing tests pass with zero regressions.
2026-07-16 00:39:51 +08:00
grossmj
01d72aed9a
Merge branch '2.2' into 3.1
# Conflicts:
#	gns3server/controller/__init__.py
#	gns3server/controller/project.py
2026-07-13 09:32:07 +02:00
Jeremy Grossmann
b256d5a5f6
Merge pull request #2812 from GNS3/bugfix/2788
fix: gns3-server crashes on startup if "Open this project in the background" is active but there is a problem with that project
2026-07-12 13:50:11 +02:00
grossmj
ea09cc2724
fix: gns3-server crashes on startup if "Open this project in the background" is active but there is a problem with that project 2026-07-12 13:46:12 +02:00
grossmj
e3e0a511b6
Handle HTTPNotFound exception when retrieving compute status 2026-07-12 11:08:13 +02:00
grossmj
0ecaab4da0
Replace ControllerForbiddenError with aiohttp.web.HTTPForbidden for project deletion error handling 2026-07-12 11:05:15 +02:00
YueGuobin
40644f33e6
Fix: Check compute connectivity before open() during project deletion
Previously the disconnected compute check ran after open(), which would
block for 120s trying to connect to unreachable remote computes before
rejecting the deletion. Now reads the topology file directly to extract
compute IDs and checks connectivity before calling open(), enabling
immediate rejection of deletions involving offline computes.

Also removes the redundant post-open() check since the early check
covers both opened and closed project states.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-07-12 10:57:56 +02:00
grossmj
a9cce209d7
Development on 3.1.0.dev5 2026-07-10 10:01:35 +02:00
Jeremy Grossmann
94a131dab3
Merge pull request #2810 from yueguobin/feature/cloud-host-interface-ip-addresses
Expose full host interface IP addresses and link state in cloud node API
2026-07-10 09:19:54 +02:00
YueGuobin
0ed1715fe6
Use typed InterfaceStatus enum and simplify stats fallback in interfaces()
- Change `status: str` to `status: InterfaceStatus` (str Enum) in the
  HostInterface schema, matching the existing IPAddressFamily pattern.
- Use default-then-override pattern in interfaces() to eliminate the
  `else` branch and deduplicate defaults.
2026-07-10 14:55:21 +08:00
YueGuobin
9721660cc3
Expose full interface address list and link state in cloud node API
Each host interface surfaced by the cloud node now reports:
- ip_addresses: every IPv4 and IPv6 address (previously only a single
  IPv4 was collected internally and then dropped before the response)
- status / speed / mtu / flags: operational state and link attributes
  sourced from psutil.net_if_stats(), with flags normalized to a list

The legacy ip_address / netmask / mac_address fields are preserved so
existing callers (compute link detection, GNS3 VM, VMware, has_netmask)
keep working. The new fields travel through the existing interfaces
payload that the controller forwards verbatim, so no controller-side
change is required and the PUT / ports_mapping flow is unaffected.
2026-07-10 13:56:07 +08:00
grossmj
a66740e154
Add script to create and push annotated git tags from version.py 2026-07-09 11:02:33 +02:00
grossmj
913d021705
Release v3.1.0a4 v3.1.0a4 2026-07-09 10:40:38 +02:00
grossmj
d64fdd71a9
Bundle web-ui v3.1.0a4 2026-07-09 08:40:05 +02:00
Jeremy Grossmann
bdd73be6d6
Merge pull request #2808 from yueguobin/docs/jwt-refresh-token-config-example
Add jwt_refresh_token_expire_minutes to sample configuration
2026-07-09 08:34:25 +02:00
Guobin Yue
61ce59788b
Merge branch '3.1' into docs/jwt-refresh-token-config-example 2026-07-09 14:19:14 +08:00
YueGuobin
cccc3e5b77
Add jwt_refresh_token_expire_minutes to sample configuration
The sample gns3_server.conf documented jwt_access_token_expire_minutes but omitted jwt_refresh_token_expire_minutes (default 43200 minutes, 30 days) defined in ControllerSettings. Add it for parity with the schema.
2026-07-09 14:15:49 +08:00
grossmj
6fba497734
Remove deleted web-ui files from git 2026-07-08 22:40:27 +02:00
grossmj
54540e7ef7
Merge remote-tracking branch 'origin/3.1' into 3.1 2026-07-08 21:49:20 +02:00
grossmj
5992a284c9
Bundle web-ui v3.1.0a4 2026-07-08 21:48:48 +02:00
grossmj
a2ee5389af
Bundle web-ui v3.1.0a4 2026-07-08 20:11:59 +02:00
grossmj
4548d9053a
Sync appliances 2026-07-08 18:45:07 +02:00
grossmj
2d3bb89e58
Merge remote-tracking branch 'origin/2.2' into 3.1 2026-07-08 10:33:00 +02:00
grossmj
809d4cc609
Merge branch 'master' into 2.2
# Conflicts:
#	.github/workflows/docker-build.yml
2026-07-08 10:30:53 +02:00
Jeremy Grossmann
89e4e836c9
Merge pull request #2806 from my-code-is-grey/2798-dockerhub
#2798 - DockerHub adjustments
2026-07-08 05:17:04 +02:00
my-code-is-grey
69ddcf553f .dockerignore ignore .dockerignore 2026-07-07 22:37:24 -04:00
my-code-is-grey
1e1ec5aae8 typo made me reconsider and move out to env 2026-07-07 21:58:49 -04:00
my-code-is-grey
e30e6435ca defaulted DOCKERHUB_ORG repository variable 2026-07-07 21:48:13 -04:00
my-code-is-grey
77700f361c 2798 2026-07-07 01:30:58 -04:00
grossmj
424ae55c38
Revert "Update dependencies"
This reverts commit b6793a50f318b47c4d12fa80f19875ba13a2aae9.
2026-07-06 18:38:48 +02:00
grossmj
b6793a50f3
Update dependencies 2026-07-06 18:31:52 +02:00
grossmj
562108748a
Remove API docs from 2.2 after merging 2026-07-06 18:17:00 +02:00
grossmj
d54b16df53
Merge branch '2.2' into 3.1
# Conflicts:
#	gns3server/handlers/api/controller/template_handler.py
#	tests/handlers/api/controller/test_template.py
2026-07-06 18:13:17 +02:00
Jeremy Grossmann
ad4aa1d49b
Merge pull request #2803 from GNS3/update-ga-workflows
Update GitHub Actions workflows
2026-07-06 18:10:17 +02:00
grossmj
8499ed3d65
Update GitHub Actions workflows 2026-07-06 18:05:28 +02:00
Jeremy Grossmann
a0ca8761c0
Merge pull request #2802 from yueguobin/fix-web-wireshark-docker-xpra6.x
Fix web-wireshark docker build broken by xpra 6.5 release
2026-07-06 17:32:31 +02:00
Guobin Yue
277640a335
Merge branch '3.1' into fix-web-wireshark-docker-xpra6.x 2026-07-06 13:35:44 +08:00
YueGuobin
f5a72532ac
Fix web-wireshark docker build broken by xpra 6.5 release
Replace the `xpra=6.4*` version clamp on the apt-get install command
line with APT pinning via /etc/apt/preferences.d/pin-xpra.

The previous specifier stopped resolving once xpra 6.5 was released:
the xpra metapackage was pinned to 6.4 while its sub-packages
(xpra-client, xpra-server, xpra-codecs, ...) were unconstrained and
defaulted to 6.5, so apt could not satisfy the dependency graph and
the "Build Docker images" action failed.

Pinning all xpra* packages at the preferences level constrains the
whole set consistently (xpra-html5 is handled separately since it
follows a different version scheme, locked to v19). Blocking every
other version with priority -1 ensures that, if the pinned version
ever disappears from the repository, apt fails loudly instead of
silently upgrading to the latest release.

Fixes GNS3/gns3-registry#1044
2026-07-06 13:31:07 +08:00
Jeremy Grossmann
7650409ab6
Merge pull request #2797 from yueguobin/feature/optional-ai-support-2794
Make AI features (AI Copilot + MCP) optional via [ai-features] extra
2026-06-27 19:44:27 +02:00
YueGuobin
e0ef63ebc1
Update CI to install [ai-features,dev] instead of [ai-copilot,dev]
The [ai-copilot] extra has been replaced by [ai-features] which
includes both AI Copilot and MCP dependencies.
2026-06-27 22:19:39 +08:00