mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-11-03 05:51:15 +02:00
marker: let callers pin the capture node via capture_node_id
A marker is single-sided — only the chosen capture node's uBridge installs the mark filter — and dir=tx|rx is interpreted from that node's perspective. Until now the observer was always auto-picked (_choose_marker_side), so dir=tx meant "the auto-chosen endpoint is sending", which is unpredictable and makes the direction filter hard to render meaningfully in the Web UI. Add an optional create-only capture_node_id to MarkerCreate: when set, the marker is pinned to that endpoint's uBridge (validated as a link endpoint and a marker-capable type); when omitted, behavior is unchanged (auto-pick). The chosen id is already echoed back as capture_node_id and in MARK signals, so the UI can always render the observer regardless of who picked it. capture_node_id is create-only (changing it would silently flip the meaning of stored direction; recreate instead) and is not accepted on project-level definitions — they are link-agnostic and have no endpoints, so inherited markers keep auto-picking per link. Plumbed through REST create_marker, the MCP link_marker tool, and base Link.start_marker. update_marker does not forward it.
This commit is contained in:
8 files changed
+112
-6
No files matched your search
@@ -98,6 +98,40 @@ async def test_start_marker_stores_entry(project):
|
||||
assert "inherited_from" not in entry
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_start_marker_pins_capture_node(project):
|
||||
# Auto-pick would choose node1 (first endpoint); pin to node2 explicitly.
|
||||
with _valid_bpf():
|
||||
link = await _make_link(project)
|
||||
chosen = link._nodes[1]["node"].id
|
||||
auto = link._nodes[0]["node"].id
|
||||
assert chosen != auto # sanity: the pin must actually mean something
|
||||
await link.start_marker("icmp", "icmp", capture_node_id=chosen)
|
||||
|
||||
assert link.markers["icmp"]["capture_node_id"] == chosen
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_start_marker_rejects_non_endpoint_capture_node(project):
|
||||
|
||||
with _valid_bpf():
|
||||
link = await _make_link(project)
|
||||
with pytest.raises(ControllerNotFoundError):
|
||||
await link.start_marker("icmp", "icmp", capture_node_id="11111111-2222-3333-4444-555555555555")
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_start_marker_capture_node_ignored_for_inherited(project):
|
||||
# Definitions are link-agnostic: an inherited marker must auto-pick even
|
||||
# if a capture_node_id leaks through, never trusting the caller's pin.
|
||||
with _valid_bpf():
|
||||
link = await _make_link(project)
|
||||
leaked = link._nodes[1]["node"].id
|
||||
await link.start_marker("m", "icmp", capture_node_id=leaked, inherited_from="arp")
|
||||
|
||||
assert link.markers["m"]["capture_node_id"] == link._nodes[0]["node"].id
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_start_marker_rejects_duplicate(project):
|
||||
|
||||
|
||||
Reference in new issue
Block a user