From 60e2bbbbbb61635c06689c3f6d4f7b00de0a9fa8 Mon Sep 17 00:00:00 2001 From: YueGuobin Date: Tue, 4 Aug 2026 22:59:12 +0800 Subject: [PATCH] marker: point directional defs at BPF, refresh implementation doc The 409 on a tx/rx definition now recommends encoding direction in the BPF (e.g. icmp[icmptype]==8) as the primary fix, with per-link markers as the single-link fallback. Doc updated: per-def rejects tx/rx (why + BPF), the pause section no longer claims bpf changes reset+reapply (they rebuild one filter), and a new Capture files section covers pcap cleanup + reset-preserves-mark. --- docs/features/marker-traffic-insight.md | 22 ++++++++++++++++++++-- gns3server/controller/project.py | 19 ++++++++++++------- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/docs/features/marker-traffic-insight.md b/docs/features/marker-traffic-insight.md index 1995b414d..e468e6faa 100644 --- a/docs/features/marker-traffic-insight.md +++ b/docs/features/marker-traffic-insight.md @@ -147,6 +147,13 @@ observer would silently flip the meaning of stored `direction`, so recreate the instead). It is not accepted on project-level definitions — a definition is link-agnostic and has no endpoints to choose from, so inherited markers always auto-pick per link. +For the same reason, a definition **rejects `direction: tx|rx`** (HTTP 409): each inherited +copy auto-picks its capture node, so a fixed tx/rx would denote different session directions +on different links. A definition is `both` only; encode the direction you want in the BPF +instead — e.g. `icmp and icmp[icmptype]==8` for echo requests, a packet-intrinsic property +that is consistent on every link regardless of capture node. tx/rx remains available on +per-link markers, where the capture node is fixed. + ## Pause & resume Two levels of silencing, both instant (no NIO rebuild, no pcap flush): @@ -156,8 +163,10 @@ Two levels of silencing, both instant (no NIO rebuild, no pcap flush): `enable_packet_filter … off`): no signal, no pcap, but traffic still relays — a paused `mark` is a no-op tap, not a drop. `{"enabled": true}` flips it back. A change to `enabled` alone is a single command (the pcap identity and emitted - counter are preserved); changing `bpf` or other fields still goes through a - reset+reapply. + counter are preserved). Changing `bpf`, `tag`, or `direction` rebuilds just that + one filter (`delete_packet_filter` + add) — only that marker's own pcap reopens + (a new capture session for the new BPF); changing `color`/`highlight_duration` + is UI-only, nothing is pushed to uBridge. - **Per-definition (inherited)** — `POST /v3/projects/{pid}/marker-definitions/{name}/pause` and `/resume` toggle **every** inherited `global-{name}` copy across all links at once (same `enable_packet_filter on|off`, fanned out per copy). Use to @@ -172,6 +181,15 @@ Two levels of silencing, both instant (no NIO rebuild, no pcap flush): | per-def `pause` (all `global-{name}` copies) | stop | stop | n/a | | per-def `resume` | resume | resume | n/a | +## Capture files + +Each marker appends matches to `/project-files/markers/__.pcap`. +Removing a marker — per-link `DELETE .../markers/{name}` or deleting a definition (which +removes every inherited copy) — deletes that marker's pcap too, even with the capture node +stopped (the filter is removed with `delete_packet_filter`, the file is unlinked). uBridge's +`reset_packet_filters` (run on NIO/filter changes) preserves mark filters, so unrelated +changes no longer close/reopen any marker's pcap. + ## API Endpoints All endpoints require a JWT bearer token (`POST /v3/access/users/authenticate`). The diff --git a/gns3server/controller/project.py b/gns3server/controller/project.py index bb3f5f103..8a2eb1590 100644 --- a/gns3server/controller/project.py +++ b/gns3server/controller/project.py @@ -967,17 +967,22 @@ class Project: def _validate_marker_definition_direction(self, name, direction): """ - Reject tx/rx on a marker definition: a definition auto-selects its - capture node per link (``_choose_marker_side``), while tx/rx is - interpreted from that node's perspective, so a fixed direction has no - stable meaning project-wide. Only 'both' (the default, = ``None``) is - allowed — use a per-link marker if a directional filter is needed. + Reject tx/rx on a marker definition: a definition fans out to every link + and auto-selects its capture node on each (``_choose_marker_side``), + while tx/rx is relative to that node, so a fixed direction has no + consistent meaning across links. Only 'both' (the default, = ``None``) + is allowed — encode the direction in the BPF instead (e.g. + ``icmp[icmptype]==8`` for echo requests), or use a per-link marker whose + capture node is pinned. """ if direction in ("tx", "rx"): raise ControllerError( f"Marker definition '{name}': direction '{direction}' is not allowed. " - "A definition auto-selects its capture node per link and tx/rx is " - "relative to that node — use 'both' (the default), or a per-link marker." + "A definition fans out to every link and auto-selects its capture node on each, " + "but tx/rx is relative to that node, so a fixed direction has no consistent " + "meaning across links. Keep 'both' (the default) and encode the direction in " + "the BPF instead, e.g. 'icmp and icmp[icmptype]==8' for echo requests only. " + "For a capture-node-relative direction on a single link, use a per-link marker." ) async def create_marker_definition(self, name, bpf, tag=None, direction=None, color=None, highlight_duration=None):