Yureka Lilian <yureka@cyberchaos.dev> writes:
The xdp-forwarder's purpose is implementing the functionality needed within the net-vm (a VM running the Linux drivers for any physical interfaces on the spectrum system).
In the future, the net-vm will load the included XDP programs on the passed-through physical interfaces as well as the downstream virtio interface going into the router (recognized by its special MAC address).
The net-vm needs to multiplex between the physical interfaces, as there might be several interfaces in the same IOMMU-group.
For this, the XDP program loaded on the physical interfaces (`prog_physical.o`) applies a VLAN tag corresponding to the interface id and redirects the packets to the router interface (identified by the `router_iface` bpf map). In the other direction the XDP program loaded on the router interface (`prog_router.o`) removes one layer of VLAN tagging and redirects the packets to the interface read from the VLAN tag.
The helper program `set_router_iface` is used to update the `router_iface` bpf map to point to the interface passed as argument to the program.
Co-authored-by: Demi Marie Obenour <demiobenour@gmail.com> Signed-off-by: Yureka Lilian <yureka@cyberchaos.dev> Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- pkgs/default.nix | 4 + release/checks/pkg-tests.nix | 1 + tools/default.nix | 21 +- tools/meson.build | 4 + tools/meson_options.txt | 3 + tools/xdp-forwarder/meson.build | 48 +++++ tools/xdp-forwarder/parsing_helpers.h | 274 +++++++++++++++++++++++++ tools/xdp-forwarder/prog_physical.c | 39 ++++ tools/xdp-forwarder/prog_router.c | 42 ++++ tools/xdp-forwarder/rewrite_helpers.h | 146 +++++++++++++ tools/xdp-forwarder/set_router_iface.c | 30 +++ 11 files changed, 608 insertions(+), 4 deletions(-) create mode 100644 tools/xdp-forwarder/meson.build create mode 100644 tools/xdp-forwarder/parsing_helpers.h create mode 100644 tools/xdp-forwarder/prog_physical.c create mode 100644 tools/xdp-forwarder/prog_router.c create mode 100644 tools/xdp-forwarder/rewrite_helpers.h create mode 100644 tools/xdp-forwarder/set_router_iface.c
diff --git a/pkgs/default.nix b/pkgs/default.nix index 2472218..df3cfdc 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -42,6 +42,10 @@ let appSupport = false; hostSupport = true; }; + spectrum-driver-tools = self.callSpectrumPackage ../tools { + appSupport = false; + driverSupport = true; + }; xdg-desktop-portal-spectrum-host = self.callSpectrumPackage ../tools/xdg-desktop-portal-spectrum-host {};
diff --git a/release/checks/pkg-tests.nix b/release/checks/pkg-tests.nix index d7be42b..b1a048f 100644 --- a/release/checks/pkg-tests.nix +++ b/release/checks/pkg-tests.nix @@ -14,5 +14,6 @@ import ../../lib/call-package.nix ( tools = lib.recurseIntoAttrs (callSpectrumPackage ../../tools { appSupport = true; hostSupport = true; + driverSupport = true; }).tests; }) (_: {}) diff --git a/tools/default.nix b/tools/default.nix index 201afae..0e43997 100644 --- a/tools/default.nix +++ b/tools/default.nix @@ -1,13 +1,17 @@ # SPDX-License-Identifier: MIT # SPDX-FileCopyrightText: 2022-2025 Alyssa Ross <hi@alyssa.is> +# SPDX-FileCopyrightText: 2025 Yureka Lilian <yureka@cyberchaos.dev>
import ../lib/call-package.nix ( { src, lib, stdenv, fetchCrate, fetchurl, runCommand, buildPackages , meson, ninja, pkg-config, rustc , clang-tools, clippy , dbus +# clang 19 (current nixpkgs default) is too old to support -fwrapv-pointer +, clang_21, libbpf , appSupport ? true , hostSupport ? false +, driverSupport ? false }:
let @@ -70,15 +74,18 @@ stdenv.mkDerivation (finalAttrs: { ./lsvm ./start-vmm ./subprojects + ] ++ lib.optionals driverSupport [ + ./xdp-forwarder ])); }; sourceRoot = "source/tools";
depsBuildBuild = lib.optionals hostSupport [ buildPackages.stdenv.cc ]; nativeBuildInputs = [ meson ninja ] - ++ lib.optionals appSupport [ pkg-config ] - ++ lib.optionals hostSupport [ rustc ]; - buildInputs = lib.optionals appSupport [ dbus ]; + ++ lib.optionals (appSupport || driverSupport) [ pkg-config ] + ++ lib.optionals hostSupport [ rustc ] + ++ lib.optionals driverSupport [ clang_21 ]; + buildInputs = lib.optionals appSupport [ dbus ] ++ lib.optionals driverSupport [ libbpf ];
postPatch = lib.optionals hostSupport (lib.concatMapStringsSep "\n" (crate: '' mkdir -p subprojects/packagecache @@ -88,12 +95,16 @@ stdenv.mkDerivation (finalAttrs: { mesonFlags = [ (lib.mesonBool "app" appSupport) (lib.mesonBool "host" hostSupport) + (lib.mesonBool "driver" driverSupport) "-Dhostfsrootdir=/run/virtiofs/virtiofs0" "-Dtests=false" "-Dunwind=false" "-Dwerror=true" ];
+ # Not supported for target bpf + hardeningDisable = lib.optionals driverSupport [ "zerocallusedregs" ]; + passthru.tests = { clang-tidy = finalAttrs.finalPackage.overrideAttrs ( { name, src, nativeBuildInputs ? [], ... }: @@ -105,7 +116,9 @@ stdenv.mkDerivation (finalAttrs: { fileset = lib.fileset.union (lib.fileset.fromSource src) ../.clang-tidy; };
- nativeBuildInputs = nativeBuildInputs ++ [ clang-tools ]; + # clang-tools needs to be before clang, otherwise it will not use + # the Nix include path correctly and fail to find headers + nativeBuildInputs = [ clang-tools ] ++ nativeBuildInputs;
buildPhase = '' clang-tidy --warnings-as-errors='*' ../**/*.c diff --git a/tools/meson.build b/tools/meson.build index e8b0cf2..059baeb 100644 --- a/tools/meson.build +++ b/tools/meson.build @@ -26,3 +26,7 @@ endif if get_option('app') subdir('xdg-desktop-portal-spectrum') endif + +if get_option('driver') + subdir('xdp-forwarder') +endif diff --git a/tools/meson_options.txt b/tools/meson_options.txt index fb520ae..7b46739 100644 --- a/tools/meson_options.txt +++ b/tools/meson_options.txt @@ -7,6 +7,9 @@ option('host', type : 'boolean', value : false, option('app', type : 'boolean', description : 'Build tools for Spectrum app VMs')
+option('driver', type : 'boolean', value : false, + description : 'Build tools for Spectrum driver VMs') + option('hostfsrootdir', type : 'string', value : '/run/host', description : 'Path where the virtio-fs provided by the host will be mounted')
diff --git a/tools/xdp-forwarder/meson.build b/tools/xdp-forwarder/meson.build new file mode 100644 index 0000000..9b70ce3 --- /dev/null +++ b/tools/xdp-forwarder/meson.build @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: EUPL-1.2+ +# SPDX-FileCopyrightText: 2025 Yureka Lilian <yureka@cyberchaos.dev> +# SPDX-FileCopyrightText: 2025 Demi Marie Obenour <demiobenour@gmail.com> + +libbpf = dependency('libbpf', version : '1.6.2') + +executable('set-router-iface', 'set_router_iface.c', + dependencies : libbpf, + install : true) + +clang = find_program('clang', native: true) + +bpf_o_cmd = [ + clang.full_path(), + '-fno-stack-protector', + '-fno-strict-aliasing', + '-fwrapv', '-fwrapv-pointer', + '-Wall', + '-Wextra', + '-O2', + '-target', 'bpf', + '-I', meson.current_source_dir() + '/include', + '-g', + '-c', + '-o', '@OUTPUT@', + '-MD', + '-MP', + '-MF', '@DEPFILE@',
Demi: you suggested these arguments, but the Meson default is -MD -MQ $out -MF $DEPFILE, as far as I can tell. Why the difference?
+ '--', + '@INPUT@', +] + +prog_router_o = custom_target( + input : 'prog_router.c', + output : 'prog_router.o', + depfile : 'prog_router.o.dep', + command : bpf_o_cmd, + install: true, + install_dir: 'lib/xdp') + +prog_physical_o = custom_target( + input : 'prog_physical.c', + output : 'prog_physical.o', + depfile : 'prog_physical.o.dep', + command : bpf_o_cmd, + install: true, + install_dir: 'lib/xdp') +