Yureka Lilian 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 > Signed-off-by: Yureka Lilian > Signed-off-by: Demi Marie Obenour > --- > 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 > +# SPDX-FileCopyrightText: 2025 Yureka Lilian > > 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 > +# SPDX-FileCopyrightText: 2025 Demi Marie Obenour > + > +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') > +