YueGuobin 187201a08c
feat(controller): offer QEMU the kernel datapath, gated per compute
Kernel eligibility becomes "both endpoints on one compute, each able to
anchor": Docker always (adapters are born as veth pairs), QEMU when that
compute's uBridge can create the persistent TAPs its adapters anchor on. The
question is asked per compute, because the link needs both ends anchored --
so a mixed or half-upgraded deployment degrades to the relay instead of
failing an attach.

probe_tap_support() creates and deletes one throwaway persistent TAP through a
scratch uBridge, cached by binary identity like the tc report; /capabilities
exposes `ubridge_tap` (absent = unknown, which keeps links on the relay).

The compute route for a QEMU adapter NIO took UDPNIO only, so a kernel link
was rejected with 422: its body and response now accept
Union[UDPNIO, BridgeNIO] exactly like Docker's.

Stale "Docker-to-Docker" wording in the config, link and MCP descriptions now
talks about anchors, and docs/features/qemu-kernel-datapath.md documents the
datapath -- verified end-to-end on a real instance: 32/32 kernel-datapath
checks and 29/29 on the relay variant.
2026-10-06 00:21:08 +08:00

58 lines
2.3 KiB
Python

#
# Copyright (C) 2020 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from typing import List, Optional
from pydantic import BaseModel, Field
from .nodes import NodeType
class UbridgeTcCapabilities(BaseModel):
"""
uBridge tc-module capabilities (kernel-datapath packet filters), probed
by the compute as its own user.
"""
netem: List[str] = Field(..., description="netem keywords supported by this uBridge's tc module")
ebpf: bool = Field(..., description="Whether the eBPF stateful classifier loads on this host")
ebpf_modes: List[str] = Field(
..., description="eBPF classifier modes usable on this host (ebpf is on and the mode token is declared)"
)
cbpf: bool = Field(..., description="Whether classic-BPF match-drop classifiers are available")
class Capabilities(BaseModel):
"""
Capabilities properties.
"""
version: str = Field(..., description="Compute version number")
node_types: List[NodeType] = Field(..., description="Node types supported by the compute")
platform: str = Field(..., description="Platform where the compute is running")
cpus: int = Field(..., description="Number of CPUs on this compute")
memory: int = Field(..., description="Amount of memory on this compute")
disk_size: int = Field(..., description="Disk size on this compute")
ubridge_tc: Optional[UbridgeTcCapabilities] = Field(
None, description="uBridge tc-module capabilities; absent when the probe failed or uBridge has no tc module"
)
ubridge_tap: Optional[bool] = Field(
None,
description="Whether uBridge can create the persistent TAPs a QEMU adapter anchors on "
"(needed to wire QEMU links on the kernel datapath); absent when the probe failed",
)