mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-11-03 05:51:15 +02:00
feat(docker): eBPF stateful packet filters on kernel links
Consume the eBPF impairment classifier delivered in uBridge feature/tc-precision: frequency_drop becomes the exact every-Nth mode (tc nth_drop; -1 = drop everything maps to every 1st) and the new kernel-only quota type is the byte-cap mode (tc quota_drop, 100 = hard cutoff). KERNEL_UNSUPPORTED_FILTERS is gone entirely — kernel/relay eligibility is now purely topological. Both modes gate on ebpf=1 from the per-process tc capabilities probe (error names the setcap fix); the cleanup path (modes off) only talks to the eBPF commands when the probe reported them. Reconcile is a plain re-set: the netem reset-before-set already detaches the program and clears uBridge's per-interface registry, so a mode set after it is a fresh load+attach. Documented semantic difference: the relay counts both directions through one bridge counter, the kernel counts per direction — N=3 round-trip loss is 1-(2/3)^2 = 55.6% on kernel vs ~1/N on relay (measured 57%). window_drop is NOT exposed: the delivered implementation advances the window with no gap, making 'outside the window packets pass' unreachable (needs outage/period fields — recorded in the spec); flow_drop awaits a parameter-shape decision. Also fixes a pre-existing restart bug the e2e exposed: _bridges (relay bridge names) was never cleared on stop, so restarting a node with a relay link skipped 'bridge create' and failed on add_nio_udp. e2e (isolated instance): 13/13 — pref-1 tc_impair classifier on both veths, 57% round-trip for N=3, -1 = exact 100%, quota hard cutoff, delay coexistence, clean teardown, suspend/resume, node restart, relay-leg frequency_drop regression through an Ethernet switch. Full suite: 1925 passed.
This commit is contained in:
11 files changed
+449
-159
No files matched your search
@@ -165,11 +165,10 @@ class UDPLink(Link):
|
||||
"""
|
||||
Whether this link can be wired on the kernel datapath (veth pairs
|
||||
enslaved into a per-link Linux bridge) instead of the uBridge UDP
|
||||
relay. Impairment filters with a tc netem equivalent (delay,
|
||||
packet_loss, corrupt, bpf via cls_bpf, and the netem extensions
|
||||
rate/reorder/gemodel/duplicate/seed/limit) are served on the veth
|
||||
host end; frequency_drop only exists in the uBridge relay and
|
||||
disqualifies the kernel path. Capture and markers are served by
|
||||
relay. Every GNS3 filter type has a kernel equivalent — netem for
|
||||
delay/packet_loss/corrupt and the netem extensions, cls_bpf for bpf,
|
||||
the eBPF stateful classifier for frequency_drop — so filters no
|
||||
longer disqualify the kernel path. Capture and markers are served by
|
||||
uBridge's AF_PACKET modules on the veth host end.
|
||||
|
||||
Docker adapters are born as veth pairs (unified interface), so the
|
||||
@@ -185,12 +184,6 @@ class UDPLink(Link):
|
||||
return False
|
||||
if node1.compute.id != node2.compute.id:
|
||||
return False
|
||||
# Look at the *stored* filters, not get_active_filters(): a suspended
|
||||
# link reports the synthetic frequency_drop emulation, which is
|
||||
# relay-only mechanics and must not flip a kernel link to the relay
|
||||
# on reopen/reset.
|
||||
if KERNEL_UNSUPPORTED_FILTERS.intersection(self._filters or {}):
|
||||
return False
|
||||
if _is_unix_socket_docker(node1) or _is_unix_socket_docker(node2):
|
||||
return False
|
||||
return True
|
||||
@@ -229,10 +222,10 @@ class UDPLink(Link):
|
||||
# Markers ride the NIO like on the relay datapath, routed by
|
||||
# capture node; they attach to the veth host end via uBridge's
|
||||
# AF_PACKET marker module instead of a relay `mark` filter.
|
||||
# Filters (delay/packet_loss/corrupt plus the netem extensions
|
||||
# rate/reorder/gemodel/duplicate/seed/limit — eligibility
|
||||
# guarantees frequency_drop is absent) become one tc netem qdisc
|
||||
# per veth host end, pushed to both endpoints.
|
||||
# Filters become one tc netem qdisc per veth host end (the netem
|
||||
# surface and its extensions), plus cls_bpf match-drop (bpf) and
|
||||
# the eBPF stateful classifier (frequency_drop, quota) — every
|
||||
# GNS3 filter type has a kernel equivalent now.
|
||||
bridge_name = "gns3" + self._id.replace("-", "")[:11]
|
||||
node1_filters, node2_filters = self._get_node_filters(node1, node2, kernel=True)
|
||||
node1_markers, node2_markers = self._get_node_markers(node1, node2)
|
||||
|
||||
Reference in new issue
Block a user