Direction field in marker.match events
=======================================
Read ubridge dir=<tx|rx> from MARK signal datagrams and forward it
as a "dir" key in the marker.match notification event. The field is
additive -- older ubridge builds omit it and the parser leaves it null,
so consumers fall back to undirected rendering with no version coupling.
Semantics are relative to the capture node (the signal's node=<id>):
tx = capture node is sending (ingressed device-side NIO), rx = it is
receiving (ingressed link-side NIO).
Per-marker direction filter (opt-in, server-side pipeline)
==========================================================
Add a direction field to MarkerCreate and MarkerDefinitionCreate
schemas ("tx" | "rx" | null). Plumb it through the full pipeline:
Schema -> controller (start_marker/update_marker, marker_entry,
_markers_for_node, update_marker_definition sync)
-> REST/MCP handlers -> compute _ubridge_add_marker_filter +
IOU _ubridge_apply_markers -> bridge add_packet_filter dir <tx|rx>
When set, ubridge only fires the mark handler (signal + pcap) for
packets matching the chosen direction. null (default/legacy) = both
directions -- zero behavioural change for existing markers.
Docs and tests
==============
- docs/features/marker-traffic-insight.md: signal format updated,
new Direction section with NIO mapping, arrow mapping, and additive
compatibility note.
- tests/compute/marker/test_marker_manager.py: 3 new parser tests
(dir tx/rx/absent) plus existing test extended to assert dir=None.
13 files, +123/-22, 72 tests pass (zero breakage)
Use the node id (UUID) instead of an incrementing counter for the unix
control socket name, so each socket identifies its owning node at a glance
(one ubridge per node => node_id is unique). Falls back to the counter only
when no node id is supplied. A single UUID fits sun_path's 107-byte cap
(~69 bytes), so no project_id is needed.
start() now checks whether ubridge exited immediately after launch. An
old ubridge build that does not understand -U exits with a non-zero code
right away; surface the reason from ubridge.log instead of waiting for
connect() to time out 10s later with a confusing "couldn't connect" error.
Add ubridge_control_transport to [Server] config (default "tcp", fully
backward compatible). Selecting "unix" switches the uBridge hypervisor
control channel from the unauthenticated TCP listener (-H) to an AF_UNIX
socket (-U) authenticated in-kernel via SO_PEERCRED.
- UBridgeHypervisor: supports both socket_path (AF_UNIX) and host/port
(TCP); a new `endpoint` property unifies log/error strings for both
- Hypervisor: unix mode allocates a short socket path under a 0700
private runtime dir and unlinks it on stop; tcp mode restores the
original getaddrinfo ephemeral-port allocation
- base_node: reads the transport from config and passes host through
- schemas/config.py + config_samples/gns3_server.conf: new option
Default deployments are unchanged. "unix" requires a ubridge build that
understands -U.
Project.delete() calls open() to rebuild the internal data structures
needed for cleanup. open() schedules start_all() when the project has
auto_start enabled, so deleting an auto-start project actually launched
every node process, allocating ports and consuming resources, only for
close() to kill them moments later.
open() now takes an auto_start argument (default True, so normal opens
are unchanged) and delete() passes auto_start=False.
Fixes#2784
The condition 'state != "stopped" or state != "exited"' is a tautology,
so the state check was a no-op and a stop request was sent even for a
container that had already exited.
_get_container_state() never returns "stopped" (only "running",
"paused" or "exited"), so the intended negation of the condition used in
_fix_permissions() requires 'and', not 'or' (De Morgan's law).
Added a regression test asserting no stop query is issued for an
already-exited container.
Filter out host interfaces whose name starts with 'gns3' (e.g.
EthernetSwitch kernel bridges) from Cloud.asdict() interfaces list.
Other special interfaces (virbr0, docker0, etc.) remain visible.
NAT now includes an 'interfaces' field in its response, filtered to
contain only the mapped NAT interface (virbr0 on Linux, vmnet8 on
macOS/Windows). This lets connected nodes discover the NAT subnet
and gateway address without needing to list all host interfaces.
The field format mirrors Cloud.asdict(): name, type, special, and
ip_addresses list (both IPv4 and IPv6).
Cloud and NAT nodes need live host network interface data. Previously,
GET /projects/{project_id}/nodes/{node_id} returned cached properties
from creation time, so newly added host interfaces (e.g. kernel bridges
created by EthernetSwitch nodes) were invisible until the node was
deleted and recreated.
Now the controller fetches fresh data from the compute node before
returning the response, so host interface changes are reflected
immediately. Falls back to cached data if compute is unreachable.
Replace psutil.net_if_addrs() scan with a deterministic name derived from
the switch's node UUID: gns3 + first 6 hex chars (10 chars, fits kernel
IFNAMSIZ limit of 15). Taps: <bridge>-<port> (12-13 chars).
Crash recovery: brctl delete the bridge first (best-effort), then create
fresh. Stale bridges from abnormal gns3server shutdown are automatically
reclaimed on the next start — no EEXIST or leaked interfaces.
Remove _free_iface helper and psutil import (no longer needed).
brctl create leaves the bridge administratively DOWN. Add link set up
so the bridge actually forwards frames between enslaved ports.
Also record Docker iptables FORWARD DROP pitfall in project memory.
Replace the builtin EthernetSwitch stub with a Linux kernel bridge backed
by uBridge's brctl module. Each switch node creates one kernel bridge
(gns3br{N}) with VLAN filtering; each port is a persistent TAP enslaved to
the bridge, relayed by a per-port uBridge bridge (nio_tap <-> nio_udp).
- Access/dot1q/qinq port modes translated to brctl vlan primitives
- Compute router repointed from Dynamips to Builtin manager
- Tests updated: 21 router-level tests + 215 surrounding tests pass
- Real-kernel e2e verified: access 100 PVID untagged, dot1q trunk
VIDs 1-4094 + native 1, qinq 802.1ad proto + 200 PVID
Ethertype 0x9100/0x9200 handling and port-count guard relaxation are
deferred pending resolution.