From 007b0d78bbc29a406711faded3772a10bbd3b0ea Mon Sep 17 00:00:00 2001 From: Daniel Noland Date: Mon, 26 Jan 2026 15:35:33 +0000 Subject: [PATCH 01/16] build(nix): shell.nix support Signed-off-by: Daniel Noland --- shell.nix | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/shell.nix b/shell.nix index 112c4b8a4..a63e8f9e7 100644 --- a/shell.nix +++ b/shell.nix @@ -1,17 +1,11 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright Open Network Fabric Authors { - pkgs ? import { }, -}: -(pkgs.buildFHSEnv { - name = "dataplane-shell"; - targetPkgs = - pkgs: - (with pkgs; [ - # dev tools - bash - direnv - just - nil - nixd - wget - ]); -}).env + platform ? "x86-64-v3", + libc ? "gnu", + profile ? "debug", + instrumentation ? "none", + sanitize ? "", + tag ? "latest", +}@inputs: +(import ./default.nix inputs).devenv From 056a7697b9a10a3c17615dac05283d90b6cefefc Mon Sep 17 00:00:00 2001 From: Daniel Noland Date: Mon, 26 Jan 2026 14:59:33 +0000 Subject: [PATCH 02/16] build(nix): phase out rust-toolchain.toml Signed-off-by: Daniel Noland --- default.nix | 9 +++++++++ nix/overlays/llvm.nix | 46 +++++++++++++++++++++++++++++++++---------- rust-toolchain.toml | 27 ------------------------- 3 files changed, 45 insertions(+), 37 deletions(-) delete mode 100644 rust-toolchain.toml diff --git a/default.nix b/default.nix index a0c5dcd84..b2cf2070c 100644 --- a/default.nix +++ b/default.nix @@ -54,6 +54,15 @@ let overlays.dataplane ]; }).pkgsCross.${platform'.info.nixarch}; + frr-pkgs = + (import sources.nixpkgs { + overlays = [ + overlays.rust + overlays.llvm + overlays.dataplane + overlays.frr + ]; + }).pkgsCross.${platform'.info.nixarch}; sysroot = pkgs.pkgsHostHost.symlinkJoin { name = "sysroot"; paths = with pkgs.pkgsHostHost; [ diff --git a/nix/overlays/llvm.nix b/nix/overlays/llvm.nix index a48cd4267..b82dde347 100644 --- a/nix/overlays/llvm.nix +++ b/nix/overlays/llvm.nix @@ -1,6 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright Open Network Fabric Authors { + sources, platform, profile, ... @@ -14,25 +15,45 @@ let with builtins; (mapAttrs (var: val: (toString (orig.${var} or "")) + " " + (toString val)) new) ); adapt = final.stdenvAdapters; - bintools = final.pkgsBuildHost.llvmPackages.bintools; - lld = final.pkgsBuildHost.llvmPackages.lld; + bintools = final.pkgsBuildHost.llvmPackages'.bintools; + lld = final.pkgsBuildHost.llvmPackages'.lld; added-to-env = helpers.addToEnv platform.override.stdenv.env profile; stdenv' = adapt.addAttrsToDerivation (orig: { doCheck = false; - separateDebugInfo = true; + # separateDebugInfo = true; env = helpers.addToEnv added-to-env (orig.env or { }); nativeBuildInputs = (orig.nativeBuildInputs or [ ]) ++ [ bintools lld ]; - }) final.llvmPackages.stdenv; + }) final.llvmPackages'.stdenv; # note: rust-bin comes from oxa's overlay, not nixpkgs. This overlay only works if you have a rust overlay as well. - rust-toolchain = prev.rust-bin.fromRustupToolchainFile ../../rust-toolchain.toml; - rustPlatform' = prev.makeRustPlatform { + rust-toolchain = final.rust-bin.fromRustupToolchain { + channel = sources.rust.version; + components = [ + "rustc" + "cargo" + "rust-std" + "rust-docs" + "rustfmt" + "clippy" + "rust-analyzer" + "rust-src" + ]; + targets = [ + platform.info.target + ]; + }; + rustPlatform' = final.makeRustPlatform { stdenv = stdenv'; cargo = rust-toolchain; rustc = rust-toolchain; }; + rustPlatform'-dev = final.makeRustPlatform { + stdenv = final.llvmPackages'.stdenv; + cargo = rust-toolchain; + rustc = rust-toolchain; + }; # It is essential that we always use the same version of llvm that our rustc is backed by. # To minimize maintenance burden, we explicitly compute the version of LLVM we need by asking rustc # which version it is using. @@ -40,11 +61,11 @@ let # every time rust updates. # Unfortunately, this is also IFD, so it slows down the nix build a bit :shrug: llvm-version = builtins.readFile ( - prev.runCommand "llvm-version-for-our-rustc" + final.runCommand "llvm-version-for-our-rustc" { RUSTC = "${rust-toolchain.out}/bin/rustc"; - GREP = "${prev.pkgsBuildHost.gnugrep}/bin/grep"; - SED = "${prev.pkgsBuildHost.gnused}/bin/sed"; + GREP = "${final.pkgsBuildHost.gnugrep}/bin/grep"; + SED = "${final.pkgsBuildHost.gnused}/bin/sed"; } '' $RUSTC --version --verbose | \ @@ -54,6 +75,11 @@ let ); in { - inherit rust-toolchain rustPlatform' stdenv'; + inherit + rust-toolchain + rustPlatform' + rustPlatform'-dev + stdenv' + ; llvmPackages' = prev."llvmPackages_${llvm-version}"; } diff --git a/rust-toolchain.toml b/rust-toolchain.toml deleted file mode 100644 index 63ed2cf8b..000000000 --- a/rust-toolchain.toml +++ /dev/null @@ -1,27 +0,0 @@ -[toolchain] -# NOTE: you can and should manually update this on new rust releases -channel = "1.93.0" - -components = [ - "rustc", - "cargo", - "rust-std", - "rust-docs", - "rustfmt", - "clippy", - "rust-analyzer", - "rust-src", - - ## disabled components ## - # "rust-mingw", # not relevant to us - # "llvm-tools", # we already have a full llvm in the npins, no need for another - # "miri", # not yet functional for us - # "rustc-codegen-cranelift-preview" # not relevant to us -] - -targets = [ - "x86_64-unknown-linux-gnu", - "x86_64-unknown-linux-musl", - "aarch64-unknown-linux-gnu", - "aarch64-unknown-linux-musl" -] From 44b010c54a9faca475915b366ee39ddf4bf02e3a Mon Sep 17 00:00:00 2001 From: Daniel Noland Date: Mon, 26 Jan 2026 15:02:13 +0000 Subject: [PATCH 03/16] build(nix): frr build Signed-off-by: Daniel Noland --- nix/overlays/default.nix | 1 + nix/overlays/frr.nix | 159 ++++++++++++++++ nix/pkgs/frr/clippy-helper.nix | 62 ++++++ nix/pkgs/frr/default.nix | 219 ++++++++++++++++++++++ nix/pkgs/frr/patches/xrelifo.py.fix.patch | 22 +++ nix/pkgs/frr/patches/yang-hack.patch | 17 ++ 6 files changed, 480 insertions(+) create mode 100644 nix/overlays/frr.nix create mode 100644 nix/pkgs/frr/clippy-helper.nix create mode 100644 nix/pkgs/frr/default.nix create mode 100644 nix/pkgs/frr/patches/xrelifo.py.fix.patch create mode 100644 nix/pkgs/frr/patches/yang-hack.patch diff --git a/nix/overlays/default.nix b/nix/overlays/default.nix index 19045bb38..4ccdeae5c 100644 --- a/nix/overlays/default.nix +++ b/nix/overlays/default.nix @@ -11,4 +11,5 @@ inputs@{ llvm = import ./llvm.nix inputs; # requires rust dataplane-dev = import ./dataplane-dev.nix inputs; # requires llvm dataplane = import ./dataplane.nix inputs; # requires llvm + frr = import ./frr.nix inputs; # requires dataplane } diff --git a/nix/overlays/frr.nix b/nix/overlays/frr.nix new file mode 100644 index 000000000..61a408c68 --- /dev/null +++ b/nix/overlays/frr.nix @@ -0,0 +1,159 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright Open Network Fabric Authors +{ + sources, + sanitizers, + platform, + profile, + ... +}: +final: prev: +let + dep = pkg: pkg.override { stdenv = final.stdenv'; }; + frr-build = + frrSrc: + (dep ( + final.callPackage ../pkgs/frr ( + final.fancy + // { + stdenv = final.stdenv'; + inherit frrSrc; + } + ) + )).overrideAttrs + (orig: { + LDFLAGS = + (orig.LDFLAGS or "") + + " -L${final.fancy.libxcrypt}/lib -lcrypt " + + " -L${final.fancy.pcre2}/lib -lpcre2-8 " + + " -L${final.fancy.xxHash}/lib -lxxhash "; + configureFlags = orig.configureFlags ++ [ + "--enable-shared" + "--enable-static" + "--enable-static-bin" + ]; + }); +in +{ + fancy = prev.fancy // { + xxHash = (dep prev.xxHash).overrideAttrs (orig: { + cmakeFlags = (orig.cmakeFlags or [ ]) ++ [ + "-DBUILD_SHARED_LIBS=OFF" + "-DXXH_STATIC_LINKING_ONLY=ON" + ]; + }); + libyang = ( + (prev.libyang.override { + stdenv = final.stdenv'; + pcre2 = final.fancy.pcre2; + xxHash = final.fancy.xxHash; + }).overrideAttrs + (orig: { + cmakeFlags = (orig.cmakeFlags or [ ]) ++ [ "-DBUILD_SHARED_LIBS=OFF" ]; + propagatedBuildInputs = [ + final.fancy.pcre2 + final.fancy.xxHash + ]; + }) + ); + libcap = ( + (prev.libcap.override { + stdenv = final.stdenv'; + usePam = false; + withGo = false; + }).overrideAttrs + (orig: { + doCheck = false; # tests require privileges + separateDebugInfo = false; + CFLAGS = "-ffat-lto-objects -fsplit-lto-unit"; + makeFlags = [ + "lib=lib" + "PAM_CAP=no" + "CC:=clang" + "SHARED=no" + "LIBCSTATIC=no" + "GOLANG=no" + ]; + configureFlags = (orig.configureFlags or [ ]) ++ [ "--enable-static" ]; + postInstall = orig.postInstall + '' + # extant postInstall removes .a files for no reason + cp ./libcap/*.a $lib/lib; + ''; + }) + ); + json_c = ( + (dep prev.json_c).overrideAttrs (orig: { + cmakeFlags = (orig.cmakeFlags or [ ]) ++ [ + "-DENABLE_STATIC=1" + ]; + postInstall = (orig.postInstall or "") + '' + mkdir -p $dev/lib + $RANLIB libjson-c.a; + cp libjson-c.a $out/lib; + ''; + }) + ); + rtrlib = dep ( + prev.rtrlib.overrideAttrs (orig: { + cmakeFlags = (orig.cmakeFlags or [ ]) ++ [ "-DENABLE_STATIC=1" ]; + }) + ); + abseil-cpp = dep prev.abseil-cpp; + zlib = ( + prev.zlib.override { + stdenv = final.stdenv'; + static = true; + shared = false; + } + ); + pcre2 = dep ( + prev.pcre2.overrideAttrs (orig: { + configureFlags = (orig.configureFlags or [ ]) ++ [ + "--enable-static" + "--disable-shared" + ]; + }) + ); + ncurses = ( + prev.ncurses.override { + stdenv = final.stdenv'; + enableStatic = true; + withCxx = false; + } + ); + readline = ( + prev.readline.override { + stdenv = final.stdenv'; + ncurses = final.fancy.ncurses; + } + ); + libxcrypt = (dep prev.libxcrypt).overrideAttrs (orig: { + configureFlags = (orig.configureFlags or [ ]) ++ [ + "--enable-static" + "--disable-shared" + ]; + }); + libgccjit = + (prev.libgccjit.override { + # TODO: debug issue preventing clang build + # stdenv = final.stdenv'; + libxcrypt = final.fancy.libxcrypt; + }).overrideAttrs + (orig: { + configureFlags = (orig.configureFlags or [ ]) ++ [ + "--enable-static" + "--disable-shared" + ]; + }); + c-ares = dep ( + prev.c-ares.overrideAttrs (orig: { + cmakeFlags = (orig.cmakeFlags or [ ]) ++ [ + "-DCARES_SHARED=OFF" + "-DCARES_STATIC=ON" + ]; + }) + ); + frr.host = frr-build sources.frr; + frr.dataplane = frr-build sources.frr-dp; + }; +} diff --git a/nix/pkgs/frr/clippy-helper.nix b/nix/pkgs/frr/clippy-helper.nix new file mode 100644 index 000000000..384523730 --- /dev/null +++ b/nix/pkgs/frr/clippy-helper.nix @@ -0,0 +1,62 @@ +{ + lib, + stdenv, + frrSrc, + + # build time + autoreconfHook, + flex, + bison, + pkg-config, + elfutils, + perl, + python3Minimal, + +}: + +stdenv.mkDerivation { + pname = "frr-clippy-helper"; + version = frrSrc.branch; + src = frrSrc.outPath; + + nativeBuildInputs = [ + autoreconfHook + bison + flex + perl + pkg-config + ]; + + buildInputs = [ + python3Minimal + ] + ++ lib.optionals (lib.meta.availableOn stdenv.hostPlatform elfutils) [ + elfutils + ]; + + configureFlags = [ + "--enable-clippy-only" + ]; + + installPhase = '' + mkdir -p $out/bin + cp lib/clippy $out/bin + ''; + + enableParallelBuilding = true; + + meta = with lib; { + homepage = "https://frrouting.org/"; + description = "FRR routing daemon suite: CLI helper tool clippy"; + longDescription = '' + This small tool is used to support generating CLI code for FRR. It is split out here, + to support cross-compiling, because it needs to be compiled with the build system toolchain + and not the target host one. + ''; + license = with licenses; [ + gpl2Plus + lgpl21Plus + ]; + platforms = platforms.unix; + }; +} diff --git a/nix/pkgs/frr/default.nix b/nix/pkgs/frr/default.nix new file mode 100644 index 000000000..660416e56 --- /dev/null +++ b/nix/pkgs/frr/default.nix @@ -0,0 +1,219 @@ +{ + frrSrc, + lib, + stdenv, + + # build time + autoreconfHook, + bison, + buildPackages, + flex, + perl, + pkg-config, + python3Minimal, + + c-ares, + elfutils, + json_c, + libcap, + libxcrypt, + libyang, + pcre2, + readline, + rtrlib, + # xz, + libgccjit, + + # tests + nixosTests, + + # other general options besides snmp support + numMultipath ? 8, + + # routing daemon options + bgpdSupport ? true, + bfddSupport ? true, + staticdSupport ? true, + ospfdSupport ? false, + isisdSupport ? false, + + babeldSupport ? false, + eigrpdSupport ? false, + fabricdSupport ? false, + ldpdSupport ? false, + nhrpdSupport ? false, + ospf6dSupport ? false, + pathdSupport ? false, + pbrdSupport ? false, + pim6dSupport ? false, + pimdSupport ? false, + ripdSupport ? false, + ripngdSupport ? false, + sharpdSupport ? false, + vrrpdSupport ? false, + + # BGP options + bgpAnnounce ? true, + bgpBmp ? true, + bgpVnc ? false, + bgpRpki ? false, + + # OSPF options + ospfApi ? false, + + vtysh-extensions ? false, + + ... +}: + +stdenv.mkDerivation (finalAttrs: { + pname = "frr"; + version = frrSrc.branch; + dontPatchShebangs = false; + dontFixup = false; + dontPatchElf = false; + + outputs = [ + "out" + "build" + ]; + + src = frrSrc.outPath; + + # Without the std explicitly set, we may run into abseil-cpp + # compilation errors. + CXXFLAGS = "-std=gnu++23"; + + nativeBuildInputs = [ + autoreconfHook + bison + elfutils + flex + perl + pkg-config + python3Minimal + ]; + + buildInputs = [ + c-ares + json_c + libcap + libgccjit + libxcrypt + libyang + pcre2 + python3Minimal + readline + ] + ++ lib.optionals bgpRpki [ rtrlib ]; + + # cross-compiling: clippy is compiled with the build host toolchain, split it out to ease + # navigation in dependency hell + clippy-helper = buildPackages.callPackage ./clippy-helper.nix { + inherit frrSrc; + }; + + configureFlags = [ + "--enable-python-runtime" + "--enable-fpm=netlink" # try to disable later + "--with-moduledir=/lib/frr/modules" + # rpath causes confusion in module linking where bmp gets linked to /build (which is broken). + # dontPatchElf and dontFixup are both set to false, so nix will adjust to rpath correctly for us after + # the initial linking step. + "--enable-rpath=no" + + "--enable-configfile-mask=0640" + "--enable-logfile-mask=0640" + "--enable-user=frr" + "--enable-group=frr" + "--enable-vty-group=frrvty" + + "--enable-config-rollbacks=no" + "--disable-doc" + "--disable-doc-html" + "--enable-grpc=no" + "--enable-protobuf=no" + "--enable-scripting=no" + "--enable-sysrepo=no" + "--enable-zeromq=no" + + "--with-libpam=no" + + "--disable-silent-rules" + "--enable-configfile-mask=0640" + "--enable-logfile-mask=0640" + "--enable-multipath=${toString numMultipath}" + "--localstatedir=/run/frr" + "--includedir=/include" + "--sbindir=/libexec/frr" + "--bindir=/bin" + "--libdir=/lib" + "--prefix=/frr" + "--sysconfdir=/etc" + "--with-clippy=${finalAttrs.clippy-helper}/bin/clippy" + # general options + "--enable-irdp=no" + "--enable-mgmtd=yes" + "--enable-rtadv=yes" + "--enable-watchfrr=yes" + + "--enable-shared" + "--enable-static" + "--enable-static-bin" + + # routing protocols + (lib.strings.enableFeature babeldSupport "babeld") + (lib.strings.enableFeature bfddSupport "bfdd") + (lib.strings.enableFeature bgpdSupport "bgpd") + (lib.strings.enableFeature eigrpdSupport "eigrpd") + (lib.strings.enableFeature fabricdSupport "fabricd") + (lib.strings.enableFeature isisdSupport "isisd") + (lib.strings.enableFeature ldpdSupport "ldpd") + (lib.strings.enableFeature nhrpdSupport "nhrpd") + (lib.strings.enableFeature ospf6dSupport "ospf6d") + (lib.strings.enableFeature ospfdSupport "ospfd") + (lib.strings.enableFeature pathdSupport "pathd") + (lib.strings.enableFeature pbrdSupport "pbrd") + (lib.strings.enableFeature pim6dSupport "pim6d") + (lib.strings.enableFeature pimdSupport "pimd") + (lib.strings.enableFeature ripdSupport "ripd") + (lib.strings.enableFeature ripngdSupport "ripngd") + (lib.strings.enableFeature sharpdSupport "sharpd") + (lib.strings.enableFeature staticdSupport "staticd") + (lib.strings.enableFeature vrrpdSupport "vrrpd") + # BGP options + (lib.strings.enableFeature bgpAnnounce "bgp-announce") + (lib.strings.enableFeature bgpBmp "bgp-bmp") + (lib.strings.enableFeature bgpRpki "rpki") + (lib.strings.enableFeature bgpVnc "bgp-vnc") + # OSPF options + (lib.strings.enableFeature ospfApi "ospfapi") + # Cumulus options + "--enable-cumulus=no" + "--disable-cumulus" + ]; + + patches = [ + ./patches/yang-hack.patch + ./patches/xrelifo.py.fix.patch + ] + ++ lib.optionals vtysh-extensions [ + ./patches/vtysh-extensions.h.patch + ]; + + buildPhase = '' + make "-j$(nproc)"; + ''; + + installPhase = '' + make DESTDIR=$out install; + mkdir -p $build/src/ + cp -r . $build/src/frr + ''; + + doCheck = false; + + enableParallelBuilding = true; + + passthru.tests = { inherit (nixosTests) frr; }; +}) diff --git a/nix/pkgs/frr/patches/xrelifo.py.fix.patch b/nix/pkgs/frr/patches/xrelifo.py.fix.patch new file mode 100644 index 000000000..9cd75c208 --- /dev/null +++ b/nix/pkgs/frr/patches/xrelifo.py.fix.patch @@ -0,0 +1,22 @@ +Index: python/xrelfo.py +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +diff --git a/python/xrelfo.py b/python/xrelfo.py +--- a/python/xrelfo.py (revision Staged) ++++ b/python/xrelfo.py (date 1745108075027) +@@ -479,13 +479,9 @@ + try: + xrelfo.load_file(fn) + except: +- errors += 1 + sys.stderr.write("while processing %s:\n" % (fn)) + traceback.print_exc() + +- if xrelfo.note_warn and args.Werror: +- errors += 1 +- + for option in dir(args): + if option.startswith("W") and option != "Werror": + checks = sorted(xrelfo.check(args)) diff --git a/nix/pkgs/frr/patches/yang-hack.patch b/nix/pkgs/frr/patches/yang-hack.patch new file mode 100644 index 000000000..d875cad45 --- /dev/null +++ b/nix/pkgs/frr/patches/yang-hack.patch @@ -0,0 +1,17 @@ +Index: configure.ac +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +diff --git a/configure.ac b/configure.ac +--- a/configure.ac (revision Staged) ++++ b/configure.ac (date 1745108464300) +@@ -2091,8 +2091,6 @@ + ]) + ], [[#include ]]) + +-AC_CHECK_LIB([yang],[lyd_find_xpath3],[],[AC_MSG_ERROR([m4_normalize([ +-libyang missing lyd_find_xpath3])])]) + dnl -- don't add lyd_new_list3 to this list unless bug is fixed upstream + dnl -- https://github.com/CESNET/libyang/issues/2149 + AC_CHECK_FUNCS([ly_strerrcode ly_strvecode lyd_trim_xpath]) From 8ff7b761cf0de7691fdd63652a60b30fb4a97c85 Mon Sep 17 00:00:00 2001 From: Daniel Noland Date: Mon, 26 Jan 2026 15:12:02 +0000 Subject: [PATCH 04/16] fix(build): remove gc-sections and as-needed Frr does not like these options sadly. Signed-off-by: Daniel Noland --- nix/profiles.nix | 2 -- 1 file changed, 2 deletions(-) diff --git a/nix/profiles.nix b/nix/profiles.nix index 98af3083c..ab5c90dfe 100644 --- a/nix/profiles.nix +++ b/nix/profiles.nix @@ -50,8 +50,6 @@ let ]; optimize-for.performance.NIX_CFLAGS_LINK = optimize-for.performance.NIX_CXXFLAGS_COMPILE ++ [ "-Wl,--lto-whole-program-visibility" - "-Wl,--gc-sections" - "-Wl,--as-needed" ]; optimize-for.performance.RUSTFLAGS = [ "-Clinker-plugin-lto" From 92aef8c65db1f7cd8e2c83eb22de28ff3609c1a4 Mon Sep 17 00:00:00 2001 From: Daniel Noland Date: Mon, 26 Jan 2026 15:05:17 +0000 Subject: [PATCH 05/16] build: rework build.rs scripts Remove un-needed build.rs files and adjust extant build.rs files to work with nix build system. Note that network access is not possible within a nix build. Signed-off-by: Daniel Noland --- cli/build.rs | 8 -- dataplane/build.rs | 5 +- dpdk-sys/build.rs | 25 +++--- dpdk/build.rs | 4 +- hardware/build.rs | 4 +- init/Cargo.toml | 6 +- init/build.rs | 5 +- k8s-intf/Cargo.toml | 3 +- k8s-intf/build.rs | 180 ++++++++++++-------------------------------- sysfs/build.rs | 8 -- 10 files changed, 71 insertions(+), 177 deletions(-) delete mode 100644 cli/build.rs delete mode 100644 sysfs/build.rs diff --git a/cli/build.rs b/cli/build.rs deleted file mode 100644 index 52f5b0197..000000000 --- a/cli/build.rs +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright Open Network Fabric Authors - -fn main() { - let sysroot = dpdk_sysroot_helper::get_sysroot(); - println!("cargo:rustc-link-search=all={sysroot}/lib"); - println!("cargo:rustc-link-arg=--sysroot={sysroot}"); -} diff --git a/dataplane/build.rs b/dataplane/build.rs index 52f5b0197..78e28dd9f 100644 --- a/dataplane/build.rs +++ b/dataplane/build.rs @@ -2,7 +2,6 @@ // Copyright Open Network Fabric Authors fn main() { - let sysroot = dpdk_sysroot_helper::get_sysroot(); - println!("cargo:rustc-link-search=all={sysroot}/lib"); - println!("cargo:rustc-link-arg=--sysroot={sysroot}"); + #[cfg(feature = "dpdk")] + dpdk_sysroot_helper::use_sysroot(); } diff --git a/dpdk-sys/build.rs b/dpdk-sys/build.rs index 556af520a..e0c5a219c 100644 --- a/dpdk-sys/build.rs +++ b/dpdk-sys/build.rs @@ -20,7 +20,8 @@ impl ParseCallbacks for Cb { } } -fn bind(path: &Path, sysroot: &str) { +fn bind(path: &Path) { + let sysroot = dpdk_sysroot_helper::get_sysroot(); let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); let static_fn_path = out_path.join("generated.h"); bindgen::Builder::default() @@ -47,7 +48,6 @@ fn bind(path: &Path, sysroot: &str) { .default_enum_style(bindgen::EnumVariation::ModuleConsts) .blocklist_item("rte_atomic.*") .allowlist_item("rte.*") - .allowlist_item("wrte_.*") .allowlist_item("RTE.*") .blocklist_item("__*") .clang_macro_fallback() @@ -68,15 +68,9 @@ fn bind(path: &Path, sysroot: &str) { } fn main() { + dpdk_sysroot_helper::use_sysroot(); let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); - let sysroot = dpdk_sysroot_helper::get_sysroot(); - - println!("cargo:rustc-link-arg=--sysroot={sysroot}"); - println!("cargo:rustc-link-search=all={sysroot}/lib"); - // NOTE: DPDK absolutely requires whole-archive in the linking command. - // While I find this very questionable, it is what it is. - // It is just more work for the LTO later on I suppose ¯\_(ツ)_/¯ let depends = [ "dpdk_wrapper", "rte_net_virtio", @@ -100,6 +94,7 @@ fn main() { "rte_rcu", "rte_ring", "rte_eal", + "rte_argparse", "rte_kvargs", "rte_telemetry", "rte_log", @@ -109,6 +104,7 @@ fn main() { "efa", "hns", "mana", + "ionic", "bnxt_re-rdmav59", "cxgb4-rdmav59", "erdma-rdmav59", @@ -126,12 +122,11 @@ fn main() { "numa", ]; - for dep in &depends { + // NOTE: DPDK absolutely requires whole-archive in the linking command. + // While I find this very questionable, it is what it is. + // It is just more work for the LTO later on I suppose ¯\_(ツ)_/¯ + for dep in depends { println!("cargo:rustc-link-lib=static:+whole-archive,+bundle={dep}"); } - let rerun_if_changed = ["build.rs", "../scripts/dpdk-sys.env"]; - for file in &rerun_if_changed { - println!("cargo:rerun-if-changed={file}"); - } - bind(&out_path, sysroot.as_str()); + bind(&out_path); } diff --git a/dpdk/build.rs b/dpdk/build.rs index 52f5b0197..236576084 100644 --- a/dpdk/build.rs +++ b/dpdk/build.rs @@ -2,7 +2,5 @@ // Copyright Open Network Fabric Authors fn main() { - let sysroot = dpdk_sysroot_helper::get_sysroot(); - println!("cargo:rustc-link-search=all={sysroot}/lib"); - println!("cargo:rustc-link-arg=--sysroot={sysroot}"); + dpdk_sysroot_helper::use_sysroot(); } diff --git a/hardware/build.rs b/hardware/build.rs index 52f5b0197..236576084 100644 --- a/hardware/build.rs +++ b/hardware/build.rs @@ -2,7 +2,5 @@ // Copyright Open Network Fabric Authors fn main() { - let sysroot = dpdk_sysroot_helper::get_sysroot(); - println!("cargo:rustc-link-search=all={sysroot}/lib"); - println!("cargo:rustc-link-arg=--sysroot={sysroot}"); + dpdk_sysroot_helper::use_sysroot(); } diff --git a/init/Cargo.toml b/init/Cargo.toml index 0b8f2a8ac..cfea1672a 100644 --- a/init/Cargo.toml +++ b/init/Cargo.toml @@ -5,6 +5,10 @@ license.workspace = true publish.workspace = true version.workspace = true +[features] +default = ["sysroot"] +sysroot = ["dep:dpdk-sysroot-helper"] + [dependencies] # internal hardware = { workspace = true, features = ["serde", "scan"] } @@ -27,6 +31,6 @@ tracing-subscriber = { workspace = true, features = ["fmt"] } [build-dependencies] # internal -dpdk-sysroot-helper = { workspace = true } +dpdk-sysroot-helper = { workspace = true, optional = true } # external diff --git a/init/build.rs b/init/build.rs index 52f5b0197..1fc109eb8 100644 --- a/init/build.rs +++ b/init/build.rs @@ -2,7 +2,6 @@ // Copyright Open Network Fabric Authors fn main() { - let sysroot = dpdk_sysroot_helper::get_sysroot(); - println!("cargo:rustc-link-search=all={sysroot}/lib"); - println!("cargo:rustc-link-arg=--sysroot={sysroot}"); + #[cfg(feature = "sysroot")] + dpdk_sysroot_helper::use_sysroot(); } diff --git a/k8s-intf/Cargo.toml b/k8s-intf/Cargo.toml index 87325a162..51836cddb 100644 --- a/k8s-intf/Cargo.toml +++ b/k8s-intf/Cargo.toml @@ -38,5 +38,4 @@ lpm = { workspace = true, features = [] } net = { workspace = true, features = ["bolero", "test_buffer"] } [build-dependencies] -dotenvy = { workspace = true, features = [] } -ureq = { workspace = true, features = ["rustls", "gzip"] } +dpdk-sysroot-helper = { workspace = true } diff --git a/k8s-intf/build.rs b/k8s-intf/build.rs index 039653f21..02a159106 100644 --- a/k8s-intf/build.rs +++ b/k8s-intf/build.rs @@ -1,91 +1,10 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright Open Network Fabric Authors -use std::env; use std::fs; +use std::io::Read; use std::path::PathBuf; -fn workspace_root() -> PathBuf { - PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set")) - .ancestors() - .nth(1) - .expect("Workspace root not found") - .to_path_buf() -} - -fn env_file_name() -> PathBuf { - workspace_root().join("scripts").join("k8s-crd.env") -} - -#[derive(Default)] -struct EnvConfig { - version: Option, - url: Option, - local_path: Option, -} - -fn read_env_config() -> EnvConfig { - let env_file_path = env_file_name(); - let env_file = - dotenvy::from_path_iter(env_file_path).expect("Failed to read scripts/k8s-crd.env"); - - let mut config = EnvConfig::default(); - env_file.filter_map(Result::ok).for_each(|(key, value)| { - match key.as_str() { - "K8S_GATEWAY_AGENT_REF" => { - if !value.is_empty() { - config.version = Some(value); - } - } - "K8S_GATEWAY_AGENT_CRD_URL" => { - if !value.is_empty() { - config.url = Some(value); - } - } - "K8S_GATEWAY_AGENT_CRD_PATH" => { - if !value.is_empty() { - config.local_path = Some(value); - } - } - _ => { /* ignore undeclared variables */ } - } - }); - - // don't set version if we'll build from local crd spec - if config.local_path.is_some() { - config.version.take(); - } - - config -} - -fn fetch_crd(url: &str) -> String { - println!("cargo:note=Fetching CRD from: {url}"); - ureq::get(url) - .call() - .expect("Failed to fetch agent CRD from url") - .body_mut() - .read_to_string() - .expect("Failed to read response body") -} - -fn fetch_crd_from_file(path: &str) -> String { - println!("cargo:note=Fetching CRD from file at {path}"); - match fs::read_to_string(path) { - Ok(crd) => crd, - Err(e) => panic!("Failed to read CRD from {path}: {e}"), - } -} - -const LICENSE_PREAMBLE: &str = "// SPDX-License-Identifier: Apache-2.0 -// Copyright Open Network Fabric Authors - -"; - -fn fixup_signed_types(raw: String) -> String { - raw.replace("i64", "u64").replace("i32", "u32") -} - /// Fixup the types in the generated Rust code /// /// This is gross, but needed. OpenAPI v3 does not have any unsigned types @@ -94,31 +13,26 @@ fn fixup_signed_types(raw: String) -> String { /// /// By rewriting the types, serde_json used by kube-rs should parse the /// json correctly. +/// +/// TODO: replace this with a proc macro as the text replacement is likely fragile fn fixup_types(raw: String) -> String { - let raw = fixup_signed_types(raw); raw.replace("asn: Option", "asn: Option") - .replace("workers: Option", "workers: Option") // Gateway Go code says this is a u8 + // This should get both vtep_mtu and plain mtu + .replace("mtu: Option", "mtu: Option") + .replace("vni: Option", "vni: Option") + .replace("workers: Option", "workers: Option") // Gateway Go code says this is a u8 .replace( "idle_timeout: Option", - "idle_timeout: Option", + "idle_timeout: Option", ) - .replace( - "last_applied_gen: Option", - "last_applied_gen: Option", - ) - // fixme: we should consider to use u64 for generation Ids? -} - -fn gen_version_const(version: &Option) -> String { - let version = version - .as_ref() - .map(|v| format!("Some(\"{v}\")")) - .unwrap_or("None".to_string()); - - format!("pub const GW_API_VERSION: Option<&str> = {version};\n\n") + .replace("b: Option", "b: Option") + .replace("d: Option", "d: Option") + .replace("p: Option", "p: Option") + .replace("priority: Option", "priority: Option") + .replace("priority: i32", "priority: u32") } -fn generate_rust_for_crd(crd_content: &str, version: &Option) -> String { +fn generate_rust_for_crd(crd_content: &str) -> String { // Run kopium with stdin input let mut child = std::process::Command::new("kopium") .args(["-D", "PartialEq", "-Af", "-"]) @@ -147,14 +61,13 @@ fn generate_rust_for_crd(crd_content: &str, version: &Option) -> String let raw = String::from_utf8(output.stdout).expect("Failed to convert kopium output to string"); - LICENSE_PREAMBLE.to_string() + gen_version_const(version).as_str() + &fixup_types(raw) + fixup_types(raw) } -const GENERATED_OUTPUT_DIR: &str = "src/generated"; -const KOPIUM_OUTPUT_FILE: &str = "gateway_agent_crd.rs"; +const KOPIUM_OUTPUT_FILE: &str = "generated.rs"; fn kopium_output_path() -> PathBuf { - PathBuf::from(GENERATED_OUTPUT_DIR).join(KOPIUM_OUTPUT_FILE) + PathBuf::from(std::env::var("OUT_DIR").unwrap()).join(KOPIUM_OUTPUT_FILE) } fn code_needs_regen(new_code: &str) -> bool { @@ -171,45 +84,50 @@ fn code_needs_regen(new_code: &str) -> bool { true } -fn rerun() { - println!("cargo:rerun-if-changed={}", env_file_name().display()); -} - fn main() { - rerun(); - - // get config from env file - let config = read_env_config(); - - // get CRD spec from local path or URL - let crd_spec = if let Some(agent_crd_file) = config.local_path { - fetch_crd_from_file(&agent_crd_file) - } else if let Some(agent_crd_url) = config.url { - fetch_crd(&agent_crd_url) - } else { - panic!("No CRD path or URL is set in env file"); + let agent_crd_contents = { + let agent_crd_path = + PathBuf::from(std::env::var("GW_CRD_PATH").expect("GW_CRD_PATH var unset")) + .join("gwint.githedgehog.com_gatewayagents.yaml"); + let mut agent_crd_file = std::fs::OpenOptions::new() + .read(true) + .write(false) + .open(&agent_crd_path) + .unwrap_or_else(|e| { + panic!( + "failed to open {path}: {e}", + path = agent_crd_path.to_str().expect("non unicode crd path") + ) + }); + let mut contents = String::with_capacity( + agent_crd_file + .metadata() + .expect("unable to get crd metadata") + .len() as usize, + ); + agent_crd_file + .read_to_string(&mut contents) + .unwrap_or_else(|e| panic!("unable to read crd data into string: {e}")); + contents }; + let agent_generated_code = generate_rust_for_crd(&agent_crd_contents); - // CRD spec can't be empty - if crd_spec.is_empty() { - panic!("Empty CRD specification"); - } - - // generate rust types from the read crd_spec - let agent_generated_code = generate_rust_for_crd(&crd_spec, &config.version); if !code_needs_regen(&agent_generated_code) { println!("cargo:note=No changes to code generated from CRD"); return; } - // Write the generated code - let output_dir = PathBuf::from(GENERATED_OUTPUT_DIR); - fs::create_dir_all(&output_dir).expect("Failed to create output directory"); - let output_file = kopium_output_path(); fs::write(&output_file, agent_generated_code) .expect("Failed to write generated agent CRD code"); + let sysroot = dpdk_sysroot_helper::get_sysroot(); + + let rerun_if_changed = ["build.rs", sysroot.as_str()]; + for file in rerun_if_changed { + println!("cargo:rerun-if-changed={file}"); + } + println!( "cargo:note=Generated gateway agent CRD types written to {:?}", output_file diff --git a/sysfs/build.rs b/sysfs/build.rs deleted file mode 100644 index 52f5b0197..000000000 --- a/sysfs/build.rs +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright Open Network Fabric Authors - -fn main() { - let sysroot = dpdk_sysroot_helper::get_sysroot(); - println!("cargo:rustc-link-search=all={sysroot}/lib"); - println!("cargo:rustc-link-arg=--sysroot={sysroot}"); -} From b6b8fa978f02af449d3abfbfc6e501093b0af802 Mon Sep 17 00:00:00 2001 From: Daniel Noland Date: Mon, 26 Jan 2026 15:06:31 +0000 Subject: [PATCH 06/16] build(nix): clean up dpdk build Signed-off-by: Daniel Noland --- cli/Cargo.toml | 1 - dataplane/Cargo.toml | 8 ++++++-- dataplane/src/drivers/dpdk.rs | 1 + dpdk-sysroot-helper/src/lib.rs | 33 ++++++++++++++------------------- dpdk/src/lcore.rs | 2 +- nix/overlays/dataplane-dev.nix | 2 +- nix/overlays/dataplane.nix | 10 +++++++++- nix/overlays/default.nix | 4 +--- nix/pkgs/dpdk/default.nix | 21 +++++++-------------- sysfs/Cargo.toml | 1 - 10 files changed, 40 insertions(+), 43 deletions(-) diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 533308327..06df70ee1 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -22,6 +22,5 @@ thiserror = { workspace = true } [build-dependencies] # internal -dpdk-sysroot-helper = { workspace = true } # external diff --git a/dataplane/Cargo.toml b/dataplane/Cargo.toml index dcd605dec..70d8807e8 100644 --- a/dataplane/Cargo.toml +++ b/dataplane/Cargo.toml @@ -5,6 +5,10 @@ license.workspace = true publish.workspace = true version.workspace = true +[features] +default = ["dpdk"] +dpdk = ["dep:dpdk", "dep:dpdk-sysroot-helper"] + [dependencies] afpacket = { workspace = true, features = ["async-tokio"] } args = { workspace = true } @@ -14,7 +18,7 @@ axum-server = { workspace = true } concurrency = { workspace = true } config = { workspace = true } ctrlc = { workspace = true, features = ["termination"] } -dpdk = { workspace = true } +dpdk = { workspace = true, optional = true } dyn-iter = { workspace = true } flow-entry = { workspace = true } flow-filter = { workspace = true } @@ -61,6 +65,6 @@ tracing-subscriber = { workspace = true } [build-dependencies] # internal -dpdk-sysroot-helper = { workspace = true } +dpdk-sysroot-helper = { workspace = true, optional = true } # external diff --git a/dataplane/src/drivers/dpdk.rs b/dataplane/src/drivers/dpdk.rs index f5f9b2a57..0f1903220 100644 --- a/dataplane/src/drivers/dpdk.rs +++ b/dataplane/src/drivers/dpdk.rs @@ -3,6 +3,7 @@ //! DPDK dataplane driver +#![cfg(feature = "dpdk")] #![allow(unused)] use dpdk::dev::{Dev, TxOffloadConfig}; diff --git a/dpdk-sysroot-helper/src/lib.rs b/dpdk-sysroot-helper/src/lib.rs index 8c5b81f37..337267a7e 100644 --- a/dpdk-sysroot-helper/src/lib.rs +++ b/dpdk-sysroot-helper/src/lib.rs @@ -29,27 +29,22 @@ pub fn get_target_name() -> String { .to_string() } -#[must_use] -pub fn get_project_root() -> String { - env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set") -} - -#[must_use] -pub fn get_compile_env() -> String { - env::var("COMPILE_ENV").expect("COMPILE_ENV not set") -} - #[must_use] pub fn get_sysroot() -> String { - let compile_env = env::var("COMPILE_ENV").expect("COMPILE_ENV not set"); - let sysroot_env = format!("{compile_env}/sysroot"); - let target = get_target_name(); - let profile = get_profile_name(); - let expected_sysroot = format!("{sysroot_env}/{target}/{profile}"); - let expected_sysroot_path = Path::new(&expected_sysroot); - if expected_sysroot_path.exists() { - expected_sysroot + let sysroot_env = env::var("DATAPLANE_SYSROOT").expect("DATAPLANE_SYSROOT not set"); + let sysroot_path = Path::new(&sysroot_env); + if sysroot_path.exists() { + sysroot_env } else { - panic!("sysroot not found at {expected_sysroot}") + panic!("sysroot not found at {sysroot_env}") + } +} + +pub fn use_sysroot() { + let sysroot = get_sysroot(); + println!("cargo:rustc-link-search=all={sysroot}/lib"); + let rerun_if_changed = ["build.rs", sysroot.as_str()]; + for file in rerun_if_changed { + println!("cargo:rerun-if-changed={file}"); } } diff --git a/dpdk/src/lcore.rs b/dpdk/src/lcore.rs index 7c35c7b97..12a4dbc48 100644 --- a/dpdk/src/lcore.rs +++ b/dpdk/src/lcore.rs @@ -237,7 +237,7 @@ impl LCoreId { #[tracing::instrument(level = "trace")] pub fn current() -> LCoreId { - LCoreId(unsafe { dpdk_sys::rte_lcore_id_w() }) + LCoreId(unsafe { dpdk_sys::rte_lcore_id() }) } #[tracing::instrument(level = "trace")] diff --git a/nix/overlays/dataplane-dev.nix b/nix/overlays/dataplane-dev.nix index e548ef9e8..51d4ac572 100644 --- a/nix/overlays/dataplane-dev.nix +++ b/nix/overlays/dataplane-dev.nix @@ -7,7 +7,7 @@ final: prev: let override-packages = { - stdenv = final.llvmPackages.stdenv; + stdenv = final.llvmPackages'.stdenv; rustPlatform = final.rustPlatform'-dev; }; in diff --git a/nix/overlays/dataplane.nix b/nix/overlays/dataplane.nix index 45be4326f..8c65996d8 100644 --- a/nix/overlays/dataplane.nix +++ b/nix/overlays/dataplane.nix @@ -3,6 +3,8 @@ { sources, sanitizers, + platform, + profile, ... }: final: prev: @@ -193,7 +195,13 @@ in # Also, while this library has a respectable security track record, this is also a very strong candidate for # cfi, safe-stack, and cf-protection. fancy.dpdk = dataplane-dep ( - final.callPackage ../pkgs/dpdk (final.fancy // { src = sources.dpdk; }) + final.callPackage ../pkgs/dpdk ( + final.fancy + // { + inherit platform profile; + src = sources.dpdk; + } + ) ); # DPDK is largely composed of static-inline functions. diff --git a/nix/overlays/default.nix b/nix/overlays/default.nix index 4ccdeae5c..4ead96840 100644 --- a/nix/overlays/default.nix +++ b/nix/overlays/default.nix @@ -2,12 +2,10 @@ # Copyright Open Network Fabric Authors inputs@{ sources, - platform, - profile, - sanitizers, ... }: { + rust = import sources.rust-overlay; llvm = import ./llvm.nix inputs; # requires rust dataplane-dev = import ./dataplane-dev.nix inputs; # requires llvm dataplane = import ./dataplane.nix inputs; # requires llvm diff --git a/nix/pkgs/dpdk/default.nix b/nix/pkgs/dpdk/default.nix index 8e41adf26..68f0837c5 100644 --- a/nix/pkgs/dpdk/default.nix +++ b/nix/pkgs/dpdk/default.nix @@ -12,17 +12,11 @@ rdma-core, libnl, python3, - build-params ? { - lto = "true"; - build-type = "release"; # "debug" | "release" - platform = "bluefield3"; - }, writeText, platform, ... }: - stdenv.mkDerivation { pname = "dpdk"; version = src.branch; @@ -270,19 +264,19 @@ stdenv.mkDerivation { cpu = '${cpu}' endian = '${endian}' [properties] - platform = '${build-params.platform}' + platform = '${platform.name}' libc = '${libc-vendor}' ''; in - with build-params; [ - "--buildtype=${build-type}" - "-Dauto_features=disabled" - "-Db_colorout=never" - "-Db_lto=${lto}" + "--buildtype=release" + "-Db_lto=true" "-Db_lundef=false" "-Db_pgo=off" "-Db_pie=true" + "-Dauto_features=disabled" + "-Db_colorout=never" + "-Db_lundef=false" # normally I would enable undef symbol checks, but it breaks sanitizer builds "-Dbackend=ninja" "-Ddefault_library=static" "-Denable_docs=false" @@ -290,14 +284,13 @@ stdenv.mkDerivation { "-Dmax_numa_nodes=${toString platform.numa.max-nodes}" "-Dtests=false" # Running DPDK tests in CI is usually silly "-Duse_hpet=false" - "-Ddebug=false" ''-Ddisable_drivers=${lib.concatStringsSep "," disabledDrivers}'' ''-Denable_drivers=${lib.concatStringsSep "," enabledDrivers}'' ''-Denable_libs=${lib.concatStringsSep "," enabledLibs}'' ''-Ddisable_apps=*'' ''-Ddisable_libs=${lib.concatStringsSep "," disabledLibs}'' ] - ++ (if isCrossCompile then [ ''--cross-file=${cross-file}'' ] else [ ]); + ++ (if isCrossCompile then [ "--cross-file=${cross-file}" ] else [ ]); outputs = [ "dev" diff --git a/sysfs/Cargo.toml b/sysfs/Cargo.toml index 0ad73dde9..4c73687c4 100644 --- a/sysfs/Cargo.toml +++ b/sysfs/Cargo.toml @@ -22,6 +22,5 @@ n-vm = { workspace = true } [build-dependencies] # internal -dpdk-sysroot-helper = { workspace = true } # external From 29d1e57421851af98eb4cc085c4e5b5b31b72fb3 Mon Sep 17 00:00:00 2001 From: Daniel Noland Date: Mon, 26 Jan 2026 15:11:31 +0000 Subject: [PATCH 07/16] fix(build): wrong bluefield2 platform Signed-off-by: Daniel Noland --- nix/platforms.nix | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/nix/platforms.nix b/nix/platforms.nix index b6b54310c..9d8fc92c7 100644 --- a/nix/platforms.nix +++ b/nix/platforms.nix @@ -82,6 +82,16 @@ lib.fix ( final: platforms.${platform} // { + # NOTE: sadly, bluefield2 compiles with the name bluefield in DPDK (for some DPDK specific reason). + # That said, we generate the correct cross compile file for bluefield2 (unlike the soc defn + # in the dpdk meson.build file, which only goes half way and picks armv8-a instead of 8.2-a, or, better yet + # cortex-a72, which is the actual CPU of bluefield 2). + # We don't currently expect to meaningfully support BF2, but it is a handy test target for the build tooling. + name = + { + bluefield2 = "bluefield"; + } + .${platform} or platform; info = { x86_64 = { From 515571b61cf4583b9c7537fac41b091832ce4575 Mon Sep 17 00:00:00 2001 From: Daniel Noland Date: Mon, 26 Jan 2026 15:08:55 +0000 Subject: [PATCH 08/16] build(nix): fix missing prime in libunwind build Signed-off-by: Daniel Noland --- nix/overlays/dataplane.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nix/overlays/dataplane.nix b/nix/overlays/dataplane.nix index 8c65996d8..49bcb26fe 100644 --- a/nix/overlays/dataplane.nix +++ b/nix/overlays/dataplane.nix @@ -220,7 +220,7 @@ in } ); - fancy.libunwind = (dataplane-dep final.llvmPackages.libunwind).override { enableShared = false; }; + fancy.libunwind = (dataplane-dep final.llvmPackages'.libunwind).override { enableShared = false; }; # TODO: consistent packages, min deps fancy.hwloc = From bd3307df20819eb033a5e8cdb552e617a968cfbd Mon Sep 17 00:00:00 2001 From: Daniel Noland Date: Mon, 26 Jan 2026 15:09:08 +0000 Subject: [PATCH 09/16] build(nix): formatting Signed-off-by: Daniel Noland --- nix/overlays/dataplane.nix | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/nix/overlays/dataplane.nix b/nix/overlays/dataplane.nix index 49bcb26fe..1bf1d4831 100644 --- a/nix/overlays/dataplane.nix +++ b/nix/overlays/dataplane.nix @@ -246,7 +246,5 @@ in }); # This isn't directly required by dataplane, - fancy.perftest = dataplane-dep ( - final.callPackage ../pkgs/perftest final.fancy // { src = sources.perftest; } - ); + fancy.perftest = dataplane-dep (final.callPackage ../pkgs/perftest { src = sources.perftest; }); } From 8a978de447e95ea1a236059745585625b49bda4f Mon Sep 17 00:00:00 2001 From: Daniel Noland Date: Fri, 9 Jan 2026 21:41:13 +0000 Subject: [PATCH 10/16] build(nix): dataplane debug contianer Signed-off-by: Daniel Noland --- default.nix | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/default.nix b/default.nix index b2cf2070c..4e423e807 100644 --- a/default.nix +++ b/default.nix @@ -477,11 +477,39 @@ let }; + containers.dataplane-debugger = pkgs.dockerTools.buildLayeredImage { + name = "dataplane-debugger"; + tag = "latest"; + contents = pkgs.buildEnv { + name = "dataplane-debugger-env"; + pathsToLink = [ + "/bin" + "/etc" + "/var" + "/lib" + ]; + paths = [ + pkgs.pkgsBuildHost.gdb + pkgs.pkgsBuildHost.rr + pkgs.pkgsBuildHost.coreutils + pkgs.pkgsBuildHost.bashInteractive + pkgs.pkgsBuildHost.iproute2 + pkgs.pkgsBuildHost.ethtool + + pkgs.pkgsHostHost.libc.debug + workspace.cli.debug + workspace.dataplane.debug + workspace.init.debug + ]; + }; + }; + in { inherit clippy dataplane-tar + containers dev-pkgs devroot devenv From 568330b123229d07fa4064541e9eba1713b2fc0e Mon Sep 17 00:00:00 2001 From: Daniel Noland Date: Mon, 26 Jan 2026 15:09:31 +0000 Subject: [PATCH 11/16] build(nix): add minimal gdb build Needed for gdbserver in debug container Signed-off-by: Daniel Noland --- nix/overlays/dataplane-dev.nix | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/nix/overlays/dataplane-dev.nix b/nix/overlays/dataplane-dev.nix index 51d4ac572..dd957a603 100644 --- a/nix/overlays/dataplane-dev.nix +++ b/nix/overlays/dataplane-dev.nix @@ -34,4 +34,16 @@ in executable = false; destination = "/src/gateway/${p}"; }; + + gdb' = prev.gdb.overrideAttrs (orig: { + CFLAGS = "-Os -flto"; + CXXFLAGS = "-Os -flto"; + LDFLAGS = "-flto -Wl,--as-needed,--gc-sections -static-libstdc++ -static-libgcc"; + buildInputs = (orig.buildInputs or [ ]); + configureFlags = (orig.configureFlags or [ ]) ++ [ + "--enable-static" + "--disable-inprocess-agent" + "--disable-source-highlight" # breaks static compile + ]; + }); } From e8d42006c871dd92fbc8d995d5d19b44ab0d8b99 Mon Sep 17 00:00:00 2001 From: Daniel Noland Date: Mon, 26 Jan 2026 15:12:54 +0000 Subject: [PATCH 12/16] fix(build): incorrect tokio features in dev-depends Signed-off-by: Daniel Noland --- routing/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/routing/Cargo.toml b/routing/Cargo.toml index 1b4d5d975..c19d7d179 100644 --- a/routing/Cargo.toml +++ b/routing/Cargo.toml @@ -51,4 +51,5 @@ concurrency = { workspace = true } lpm = { workspace = true, features = ["testing"] } net = { workspace = true, features = ["test_buffer"] } rand = { workspace = true, default-features = false, features = ["thread_rng"] } +tokio = { workspace = true, features = ["full"] } tracing-test = { workspace = true, features = [] } From b2fd9e81ec1ff60758f283e732e114ec306d1f69 Mon Sep 17 00:00:00 2001 From: Daniel Noland Date: Mon, 26 Jan 2026 15:02:50 +0000 Subject: [PATCH 13/16] fix(doc): typo Signed-off-by: Daniel Noland --- hardware/src/os/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hardware/src/os/mod.rs b/hardware/src/os/mod.rs index b9b13fe8d..75c136926 100644 --- a/hardware/src/os/mod.rs +++ b/hardware/src/os/mod.rs @@ -2,7 +2,7 @@ // Copyright Open Network Fabric Authors #![doc = include_str!("README.md")] -#![allow(clippy::doc_markdown)] // abbreviations were trigging spurious backtick lints +#![allow(clippy::doc_markdown)] // abbreviations were triggering spurious backtick lints /// Type of operating system device. /// From ff5e0d8b528be4bbb250f06862fe21d95fd5ef2f Mon Sep 17 00:00:00 2001 From: Daniel Noland Date: Mon, 26 Jan 2026 15:38:10 +0000 Subject: [PATCH 14/16] chore(docs): clean up pointless include for link Signed-off-by: Daniel Noland --- net/src/buffer/test_buffer.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/net/src/buffer/test_buffer.rs b/net/src/buffer/test_buffer.rs index 1b6829a06..f50ba01b6 100644 --- a/net/src/buffer/test_buffer.rs +++ b/net/src/buffer/test_buffer.rs @@ -14,16 +14,14 @@ use crate::buffer::{ }; use tracing::trace; -// only included for doc ref -#[cfg(doc)] -use crate::buffer::PacketBuffer; - // Caution: do not implement Clone for `TestBuffer`. // Clone would significantly deviate from the actual mechanics of a DPDK mbuf. /// Toy data structure which implements [`PacketBuffer`] /// /// The core function of this structure is to facilitate testing by "faking" many useful properties /// of a real DPDK mbuf (without the need to spin up a full EAL). +/// +/// [`PacketBuffer`]: crate::buffer::PacketBuffer #[derive(Debug, Clone)] pub struct TestBuffer { buffer: Vec, From 19b885903cc0eb10bcf788175063a3986c4fb095 Mon Sep 17 00:00:00 2001 From: Daniel Noland Date: Mon, 26 Jan 2026 15:41:23 +0000 Subject: [PATCH 15/16] roll over to new build Signed-off-by: Daniel Noland --- .cargo/config.toml | 17 ++++---- .envrc | 48 +-------------------- Cargo.lock | 102 +++++++-------------------------------------- scripts/rust.env | 25 ++--------- 4 files changed, 28 insertions(+), 164 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 5cafed729..ccaba00e2 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,13 +1,10 @@ [env] -COMPILE_ENV = { value = "compile-env", relative = true, force = false } -PATH = { value = "compile-env/bin", relative = true, force = true } -LIBCLANG_PATH = { value = "compile-env/lib", relative = true, force = true } -PKG_CONFIG_PATH = { value = "compile-env/sysroot/x86_64-unknown-linux-gnu/release/lib/pkgconfig", relative = true, force = true } +DATAPLANE_SYSROOT = { value = "sysroot", relative = true, force = false } +C_INCLUDE_PATH = { value = "sysroot/include", relative = true, force = false } +LIBRARY_PATH = { value = "sysroot/lib", relative = true, force = false } +GW_CRD_PATH = { value = "devroot/src/gateway/config/crd/bases", relative = true, force = false } +PKG_CONFIG_PATH = { value = "sysroot/lib/pkgconfig", relative = true, force = false } +LIBCLANG_PATH = { value = "devroot/lib", relative = true, force = false } [build] -target = "x86_64-unknown-linux-gnu" -rustc = "compile-env/bin/rustc" -rustflags = ["--cfg", "tokio_unstable"] - -[target.x86_64-unknown-linux-gnu] -runner = ["scripts/test-runner.sh"] +rustflags = ["--cfg=tokio_unstable"] diff --git a/.envrc b/.envrc index 41bfc8c5d..44f9d5363 100644 --- a/.envrc +++ b/.envrc @@ -1,46 +1,2 @@ -export PROJECT_DIR="$(pwd)" - -if [ -h "${PROJECT_DIR}/compile-env" ] || [ -d "${PROJECT_DIR}/compile-env" ]; then - export PATH="${PROJECT_DIR}/compile-env/bin:$PATH" - export LIBCLANG_PATH="${PROJECT_DIR}/compile-env/bin" - export COMPILE_ENV="${PROJECT_DIR}/compile-env" -else - >&2 echo "no compile environment found" - exit 0 -fi - -export NEXTEST_EXPERIMENTAL_LIBTEST_JSON=1 - -CRT="-C target-feature=-crt-static" -DEBUG="-C debuginfo=full -C split-debuginfo=off -C dwarf-version=5" -LINKER="-C linker=${COMPILE_ENV}/bin/clang -C link-arg=--ld-path=${COMPILE_ENV}/bin/ld.lld" -RELRO="-C relro-level=full" -TARGET_CPU="-C target-cpu=x86-64-v3" - -RUSTFLAGS="${CRT} ${DEBUG} ${LINKER} ${RELRO} ${TARGET_CPU}" - -OPTIMIZE="-C opt-level=3 -C linker-plugin-lto -C lto=thin -C embed-bitcode=yes -C codegen-units=1" - -case ${PROFILE:-DEBUG} in - fuzz|FUZZ) - COVERAGE="-C instrument-coverage" - DEBUG_ASSERTIONS="-C debug-assertions=on" - OVERFLOW_CHECK="-C overflow-checks=on" - RUSTFLAGS="${RUSTFLAGS} ${COVERAGE} ${DEBUG_ASSERTIONS} ${OVERFLOW_CHECK}" - ;; - release|RELEASE) - RUSTFLAGS="${RUSTFLAGS} ${OPTIMIZE}" - ;; - debug|DEBUG) - DEBUG_ASSERTIONS="-C debug-assertions=on" - OPTIMIZE="-C opt-level=0" - OVERFLOW_CHECK="-C overflow-checks=on" - RUSTFLAGS="${RUSTFLAGS} ${OPTIMIZE} ${DEBUG_ASSERTIONS} ${OVERFLOW_CHECK}" - ;; - *) - >&2 echo "unknown profile" - exit 1 - ;; -esac - -export RUSTFLAGS +export RUSTC_BOOTSTRAP=1 +export PATH=$(pwd)/devroot/bin:$PATH diff --git a/Cargo.lock b/Cargo.lock index 2b5ba8113..440a79cb1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -738,9 +738,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.54" +version = "4.5.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394" +checksum = "3e34525d5bbbd55da2bb745d34b36121baac88d07619a9a09cfcf4a6c0832785" dependencies = [ "clap_builder", "clap_derive", @@ -748,9 +748,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.54" +version = "4.5.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00" +checksum = "59a20016a20a3da95bef50ec7238dbd09baeef4311dcdd38ec15aba69812fb61" dependencies = [ "anstream", "anstyle", @@ -760,9 +760,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.49" +version = "4.5.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" +checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -1213,7 +1213,6 @@ dependencies = [ "bincode2", "clap", "colored", - "dataplane-dpdk-sysroot-helper", "log", "rustyline", "serde", @@ -1420,11 +1419,11 @@ name = "dataplane-k8s-intf" version = "0.10.0" dependencies = [ "bolero", + "dataplane-dpdk-sysroot-helper", "dataplane-hardware", "dataplane-lpm", "dataplane-net", "dataplane-tracectl", - "dotenvy", "futures", "k8s-openapi", "kube", @@ -1438,7 +1437,6 @@ dependencies = [ "thiserror 2.0.18", "tokio", "tracing", - "ureq", ] [[package]] @@ -1659,7 +1657,6 @@ dependencies = [ name = "dataplane-sysfs" version = "0.10.0" dependencies = [ - "dataplane-dpdk-sysroot-helper", "n-vm", "nix 0.31.1", "procfs", @@ -1899,12 +1896,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "dotenvy" -version = "0.15.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" - [[package]] name = "downcast-rs" version = "2.0.2" @@ -2116,16 +2107,6 @@ dependencies = [ "syn 2.0.114", ] -[[package]] -name = "flate2" -version = "1.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b375d6465b98090a5f25b1c7703f3859783755aa9a80433b36e0379a3ec2f369" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - [[package]] name = "fnv" version = "1.0.7" @@ -2628,9 +2609,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.64" +version = "0.1.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -3374,7 +3355,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", - "simd-adler32", ] [[package]] @@ -4725,7 +4705,6 @@ dependencies = [ "aws-lc-rs", "log", "once_cell", - "ring", "rustls-pki-types", "rustls-webpki", "subtle", @@ -5149,12 +5128,6 @@ dependencies = [ "libc 0.2.180", ] -[[package]] -name = "simd-adler32" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" - [[package]] name = "simdutf8" version = "0.1.5" @@ -5163,9 +5136,9 @@ checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" [[package]] name = "siphasher" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" +checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" [[package]] name = "sketches-ddsketch" @@ -5542,6 +5515,7 @@ dependencies = [ "bytes", "libc 0.2.180", "mio", + "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", @@ -5898,35 +5872,6 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" -[[package]] -name = "ureq" -version = "3.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d39cb1dbab692d82a977c0392ffac19e188bd9186a9f32806f0aaa859d75585a" -dependencies = [ - "base64 0.22.1", - "flate2", - "log", - "percent-encoding", - "rustls", - "rustls-pki-types", - "ureq-proto", - "utf-8", - "webpki-roots", -] - -[[package]] -name = "ureq-proto" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d81f9efa9df032be5934a46a068815a10a042b494b6a58cb0a1a97bb5467ed6f" -dependencies = [ - "base64 0.22.1", - "http 1.4.0", - "httparse", - "log", -] - [[package]] name = "url" version = "2.5.8" @@ -5940,12 +5885,6 @@ dependencies = [ "serde_derive", ] -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - [[package]] name = "utf8_iter" version = "1.0.4" @@ -6113,15 +6052,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki-roots" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12bed680863276c63889429bfd6cab3b99943659923822de1c8a39c49e4d722c" -dependencies = [ - "rustls-pki-types", -] - [[package]] name = "winapi" version = "0.3.9" @@ -6444,18 +6374,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.34" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71ddd76bcebeed25db614f82bf31a9f4222d3fbba300e6fb6c00afa26cbd4d9d" +checksum = "fdea86ddd5568519879b8187e1cf04e24fce28f7fe046ceecbce472ff19a2572" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.34" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8187381b52e32220d50b255276aa16a084ec0a9017a0ca2152a1f55c539758d" +checksum = "0c15e1b46eff7c6c91195752e0eeed8ef040e391cdece7c25376957d5f15df22" dependencies = [ "proc-macro2", "quote", diff --git a/scripts/rust.env b/scripts/rust.env index 823c85e94..9e9644e4e 100644 --- a/scripts/rust.env +++ b/scripts/rust.env @@ -1,24 +1,5 @@ RUSTC_BOOTSTRAP=1 -NEXTEST_EXPERIMENTAL_LIBTEST_JSON=1 -LINKER="-C linker=./compile-env/bin/clang -C link-arg=--ld-path=./compile-env/bin/ld.lld" -RELRO="-C relro-level=full" -CRT_STATIC="-C target-feature=+crt-static" -CRT_DYNAMIC="-C target-feature=-crt-static" -DEBUG="-C debuginfo=full -C split-debuginfo=off -C dwarf-version=5 -Z embed-source" -DEBUG_ASSERTIONS_ON="-C debug-assertions=on" -DEBUG_ASSERTIONS_OFF="-C debug-assertions=off" -OVERFLOW_CHECK_ON="-C overflow-checks=on" -OVERFLOW_CHECK_OFF="-C overflow-checks=off" -LTO="-C linker-plugin-lto -C lto=thin -C embed-bitcode=yes -C codegen-units=1" -COVERAGE="-C instrument-coverage" -OPTIMIZE_OFF="${DEBUG_ASSERTIONS_ON} ${OVERFLOW_CHECK_ON}" -OPTIMIZE_ON="-C opt-level=3 ${LTO} ${DEBUG_ASSERTIONS_OFF} ${OVERFLOW_CHECK_OFF}" -OPTIMIZE_FUZZ="-C opt-level=3 ${LTO} ${DEBUG_ASSERTIONS_ON} ${OVERFLOW_CHECK_ON}" -TARGET_CPU_DEBUG="-C target-cpu=generic" -TARGET_CPU_RELEASE="-C target-cpu=x86-64-v3" -TOKIO_UNSTABLE="--cfg tokio_unstable" -COMMON="${LINKER} ${RELRO} ${DEBUG}" -RUSTFLAGS_DEBUG="${COMMON} ${OPTIMIZE_OFF} ${TARGET_CPU_DEBUG} ${CRT_DYNAMIC} ${TOKIO_UNSTABLE}" -RUSTFLAGS_RELEASE="${COMMON} ${OPTIMIZE_ON} ${TARGET_CPU_RELEASE} ${CRT_DYNAMIC} ${TOKIO_UNSTABLE}" -RUSTFLAGS_FUZZ="${COMMON} ${OPTIMIZE_FUZZ} ${TARGET_CPU_RELEASE} ${CRT_DYNAMIC} ${TOKIO_UNSTABLE}" +RUSTFLAGS_DEBUG="" +RUSTFLAGS_RELEASE="" +RUSTFLAGS_FUZZ="" From 5c80d390766c0379944487961fee4cad2907ed09 Mon Sep 17 00:00:00 2001 From: Daniel Noland Date: Mon, 26 Jan 2026 15:42:32 +0000 Subject: [PATCH 16/16] wip Signed-off-by: Daniel Noland --- .cargo/cross/aarch64/gnu.toml | 8 ++ .cargo/cross/aarch64/musl.toml | 8 ++ .cargo/cross/x86_64/gnu.toml | 8 ++ .cargo/cross/x86_64/musl.toml | 8 ++ .clangd | 1 + .config/nix/nix.conf | 5 + .github/workflows/scratch.yml | 172 +++++++++++++++++++++++++++++++++ Containerfile | 7 ++ default.nix | 157 ++++++++++++++++++++++-------- scripts/acks2.yml | 108 +++++++++++++++++++++ scripts/sbom.sh | 11 +++ scripts/sbom2.jq | 66 +++++++++++++ 12 files changed, 521 insertions(+), 38 deletions(-) create mode 100644 .cargo/cross/aarch64/gnu.toml create mode 100644 .cargo/cross/aarch64/musl.toml create mode 100644 .cargo/cross/x86_64/gnu.toml create mode 100644 .cargo/cross/x86_64/musl.toml create mode 120000 .clangd create mode 100644 .config/nix/nix.conf create mode 100644 .github/workflows/scratch.yml create mode 100644 Containerfile create mode 100644 scripts/acks2.yml create mode 100644 scripts/sbom.sh create mode 100644 scripts/sbom2.jq diff --git a/.cargo/cross/aarch64/gnu.toml b/.cargo/cross/aarch64/gnu.toml new file mode 100644 index 000000000..fce26c56a --- /dev/null +++ b/.cargo/cross/aarch64/gnu.toml @@ -0,0 +1,8 @@ +[env] +CC = { value = "aarch64-unknown-linux-gnu-clang", relative = false, force = true } + +[build] +target = "aarch64-unknown-linux-gnu" + +[target.aarch64-unknown-linux-gnu] +rustflags = ["--cfg=tokio_unstable", "-Clinker=aarch64-unknown-linux-gnu-clang", "-Clink-arg=-fuse-ld=lld"] diff --git a/.cargo/cross/aarch64/musl.toml b/.cargo/cross/aarch64/musl.toml new file mode 100644 index 000000000..173243792 --- /dev/null +++ b/.cargo/cross/aarch64/musl.toml @@ -0,0 +1,8 @@ +[env] +CC = { value = "aarch64-unknown-linux-musl-clang", relative = false, force = true } + +[build] +target = "aarch64-unknown-linux-musl" + +[target.aarch64-unknown-linux-musl] +rustflags = ["--cfg=tokio_unstable", "-Clinker=aarch64-unknown-linux-musl-clang", "-Clink-arg=-fuse-ld=lld"] diff --git a/.cargo/cross/x86_64/gnu.toml b/.cargo/cross/x86_64/gnu.toml new file mode 100644 index 000000000..ce5b95740 --- /dev/null +++ b/.cargo/cross/x86_64/gnu.toml @@ -0,0 +1,8 @@ +[env] +CC = { value = "x86_64-unknown-linux-gnu-clang", relative = false, force = true } + +[build] +target = "x86_64-unknown-linux-gnu" + +[target.x86_64-unknown-linux-gnu] +rustflags = ["--cfg=tokio_unstable", "-Clinker=x86_64-unknown-linux-gnu-clang", "-Clink-arg=-fuse-ld=lld"] diff --git a/.cargo/cross/x86_64/musl.toml b/.cargo/cross/x86_64/musl.toml new file mode 100644 index 000000000..17985dc60 --- /dev/null +++ b/.cargo/cross/x86_64/musl.toml @@ -0,0 +1,8 @@ +[env] +CC = { value = "x86_64-unknown-linux-musl-clang", relative = false, force = true } + +[build] +target = "x86_64-unknown-linux-musl" + +[target.x86_64-unknown-linux-musl] +rustflags = ["--cfg=tokio_unstable", "-Clinker=x86_64-unknown-linux-musl-clang", "-Clink-arg=-fuse-ld=lld"] diff --git a/.clangd b/.clangd new file mode 120000 index 000000000..748224bb4 --- /dev/null +++ b/.clangd @@ -0,0 +1 @@ +devroot/.clangd \ No newline at end of file diff --git a/.config/nix/nix.conf b/.config/nix/nix.conf new file mode 100644 index 000000000..145e6ce59 --- /dev/null +++ b/.config/nix/nix.conf @@ -0,0 +1,5 @@ +max-jobs = 4 +experimental-features = nix-command +substituters = https://dnoland-test-cache.cachix.org/ https://cache.nixos.org https://cache.nixos.org/ +trusted-public-keys = dnoland-test-cache.cachix.org-1:AsVLS3c7NGIJbUHW5xOlK69zPEzY5jNF+ax0jd1LKUA= cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= +always-allow-substitutes = true diff --git a/.github/workflows/scratch.yml b/.github/workflows/scratch.yml new file mode 100644 index 000000000..36f8ed521 --- /dev/null +++ b/.github/workflows/scratch.yml @@ -0,0 +1,172 @@ +name: "scratch.yml" + +on: + pull_request: {} + push: + branches: + - "main" + tags: + - "v*" + merge_group: + types: ["checks_requested"] + workflow_dispatch: + inputs: + debug_enabled: + type: "boolean" + description: "Run with tmate enabled" + required: false + default: false + debug_justfile: + type: "boolean" + description: "enable to see debug statements from just recipes" + required: false + default: false + skip_vlab_tests: + type: "boolean" + description: "Skip VLAB tests (they run by default)" + required: false + default: false + run_hlab_tests: + type: "boolean" + description: "Run hybrid HLAB tests" + required: false + default: false + enable_release_tests: + type: "boolean" + description: "Enable release tests for VLAB/HLAB tests" + required: false + default: false + +concurrency: + group: "${{ github.workflow }}:${{ github.event.pull_request.number || github.event.after || github.event.merge_group && github.run_id }}" + cancel-in-progress: true + +permissions: + contents: "read" + packages: "write" + id-token: "write" + +jobs: + check: + env: + CACHE_REGISTRY: "run.h.hhdev.io:30000" + UPSTREAM_REGISTRY: "ghcr.io" + USER: "runner" + permissions: + checks: "write" + pull-requests: "write" + contents: "read" + packages: "write" + id-token: "write" + strategy: + fail-fast: false + matrix: + profile: + - name: "debug" + cargo_name: "dev" + - name: "release" + cargo_name: "release" + debug_justfile: + - "${{ inputs.debug_justfile || false }}" + name: "${{matrix.profile.name}}" + runs-on: "lab" + timeout-minutes: 120 + steps: + - name: "install nix" + uses: "cachix/install-nix-action@v31" + with: + nix_path: nixpkgs=channel:nixpkgs-unstable + + - name: "login to ghcr.io" + uses: "docker/login-action@v3" + with: + registry: "${{ env.UPSTREAM_REGISTRY }}" + username: "${{ github.actor }}" + password: "${{ secrets.GITHUB_TOKEN }}" + + - name: "login to image cache" + uses: "docker/login-action@v3" + with: + registry: "${{ env.CACHE_REGISTRY }}" + username: "${{ secrets.LAB_REGISTRY_USERNAME }}" + password: "${{ secrets.LAB_REGISTRY_TOKEN }}" + + - name: "Checkout" + uses: "actions/checkout@v6" + with: + persist-credentials: "false" + fetch-depth: "0" + + - name: "log into cachix" + uses: cachix/cachix-action@v14 + with: + name: "${{ vars.CACHIX_CACHE_NAME }}" + authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" + signingKey: "${{ secrets.CACHIX_SIGNING_KEY }}" + useDaemon: true + + - name: "sysroot" + run: | + nix build \ + --log-format raw \ + --argstr profile ${{matrix.profile.name}} \ + --show-trace \ + --max-jobs 3 \ + --file default.nix \ + sysroot \ + --out-link sysroot + + - name: "devroot" + run: | + nix build \ + --log-format raw \ + --argstr profile ${{matrix.profile.name}} \ + --show-trace \ + --max-jobs 3 \ + --file default.nix \ + devroot \ + --out-link devroot + + - name: "bins" + run: | + for pkg in dataplane cli init; do + nix build --file default.nix \ + --log-format raw \ + --argstr profile ${{matrix.profile.name}} \ + --show-trace \ + --max-jobs 3 \ + packages.dataplane \ + --out-link "packages.${pkg}" + done + + - name: "cargo nextest" + run: | + export PATH="$(pwd)/devroot/bin:$PATH" + nix shell --file default.nix devroot --command \ + cargo nextest archive --cargo-profile ${{matrix.profile.cargo_name}} --archive-file tests.tar.zst + # nix shell --file default.nix devroot --command \ + # cargo nextest run --archive-file tests.tar.zst + + - name: "run doctests" + run: | + nix shell --file default.nix devroot --command \ + cargo test --profile=${{matrix.profile.cargo_name}} --doc + + - id: "clippy" + name: "run clippy" + run: | + nix shell --file default.nix shell --command \ + cargo clippy --profile ${{matrix.profile.cargo_name}} --all-targets --all-features -- -D warnings + + - id: "docs" + name: "run rustdoc" + run: | + nix shell --file default.nix devroot --command \ + sh -c 'RUSTDOCFLAGS="-D warnings" cargo doc --profile=${{matrix.profile_name}} --no-deps' + + - name: "Setup tmate session for debug" + # if: ${{ failure() && github.event_name == 'workflow_dispatch' && inputs.debug_enabled }} + uses: "mxschmitt/action-tmate@v3" + timeout-minutes: 120 + with: + limit-access-to-actor: true diff --git a/Containerfile b/Containerfile new file mode 100644 index 000000000..c62728ced --- /dev/null +++ b/Containerfile @@ -0,0 +1,7 @@ +FROM scratch AS dataplane +ADD ./dataplane.tar / +CMD [ "/bin/dataplane" ] + +FROM dataplane as dataplane-debug +ADD ./gdbserver.tar / +ENTRYPOINT [ "/bin/gdbserver", "--no-startup-with-shell", "127.0.0.99:9999" ] diff --git a/default.nix b/default.nix index 4e423e807..212876f1d 100644 --- a/default.nix +++ b/default.nix @@ -332,50 +332,63 @@ let pname ? null, cargoArtifacts ? null, }: + let + pname' = if pname == null then "workspace" else pname; + in pkgs.callPackage invoke { builder = craneLib.mkCargoDerivation; args = { - inherit pname cargoArtifacts; + inherit cargoArtifacts; + pname = pname'; buildPhaseCargoCommand = builtins.concatStringsSep " " ( [ "mkdir -p $out;" "cargo" "nextest" "archive" - "--archive-file" - "$out/${pname}.tar.zst" "--cargo-profile=${cargo-profile}" - "--package=${pname}" ] ++ cargo-cmd-prefix + ++ (if pname == null then [ ] else [ "--package=${pname'}" ]) + ++ [ + "--archive-file" + "$out/${pname'}.tar.zst" + ] ); }; }; - tests = builtins.mapAttrs ( - dir: pname: - test-builder { - inherit pname; - } - ) package-list; + tests = + (builtins.mapAttrs ( + dir: pname: + test-builder { + inherit pname; + } + ) package-list) + // { + workspace = test-builder { }; + }; clippy-builder = { pname ? null, }: + let + pname' = if pname == null then "workspace" else pname; + in pkgs.callPackage invoke { builder = craneLib.mkCargoDerivation; args = { - inherit pname; + pname = pname'; cargoArtifacts = null; buildPhaseCargoCommand = builtins.concatStringsSep " " ( [ "cargo" "clippy" "--profile=${cargo-profile}" - "--package=${pname}" ] ++ cargo-cmd-prefix + ++ (if pname == null then [ ] else [ "--package=${pname}" ]) ++ [ "--" "-D warnings" @@ -384,12 +397,16 @@ let }; }; - clippy = builtins.mapAttrs ( - dir: pname: - clippy-builder { - inherit pname; - } - ) package-list; + clippy = + (builtins.mapAttrs ( + dir: pname: + clippy-builder { + inherit pname; + } + ) package-list) + // { + workspace = clippy-builder { }; + }; dataplane-tar = pkgs.stdenv'.mkDerivation { pname = "dataplane-tar"; @@ -471,38 +488,100 @@ let --file "$out" \ \ . \ - ${pkgs.pkgsHostHost.libc.out} \ + ${libc.out} \ ${if builtins.elem "thread" sanitizers then pkgs.pkgsHostHost.glibc.libgcc or "" else ""} \ ''; }; - containers.dataplane-debugger = pkgs.dockerTools.buildLayeredImage { - name = "dataplane-debugger"; - tag = "latest"; - contents = pkgs.buildEnv { - name = "dataplane-debugger-env"; + gdbserver-tar = dev-pkgs.stdenv'.mkDerivation { + pname = "gdbserver-tar"; + inherit version; + dontUnpack = true; + src = null; + buildPhase = + let + gdb = dev-pkgs.gdb'; + in + '' + tmp="$(mktemp -d)" + mkdir -p "$tmp/bin" + cp --dereference ${gdb}/bin/gdbserver "$tmp/bin" + cd "$tmp" + # we take some care to make the tar file reproducible here + tar \ + --create \ + \ + --sort=name \ + \ + --clamp-mtime \ + --mtime=0 \ + \ + --format=posix \ + --numeric-owner \ + --owner=0 \ + --group=0 \ + \ + `# anybody editing the files shipped in the container image is up to no good, block all of that.` \ + `# More, we expressly forbid setuid / setgid anything. May as well toss in the sticky bit as well.` \ + --mode='u-sw,go=' \ + \ + `# acls / setcap / selinux isn't going to be reliably copied into the image; skip to make more reproducible` \ + --no-acls \ + --no-xattrs \ + --no-selinux \ + \ + --verbose \ + --file "$out" \ + \ + . + ''; + + }; + + containers.dataplane-debugger = + let pathsToLink = [ "/bin" "/etc" "/var" "/lib" + "/lib/debug" + "/lib/debug/.build-id" ]; - paths = [ - pkgs.pkgsBuildHost.gdb - pkgs.pkgsBuildHost.rr - pkgs.pkgsBuildHost.coreutils - pkgs.pkgsBuildHost.bashInteractive - pkgs.pkgsBuildHost.iproute2 - pkgs.pkgsBuildHost.ethtool + in - pkgs.pkgsHostHost.libc.debug - workspace.cli.debug - workspace.dataplane.debug - workspace.init.debug - ]; + pkgs.dockerTools.buildImage { + name = "dataplane-debugger"; + tag = "latest"; + fromImage = pkgs.dockerTools.buildLayeredImage { + name = "dataplane-debugger-base"; + tag = "latest"; + contents = pkgs.buildEnv { + name = "dataplane-debugger-env"; + inherit pathsToLink; + paths = [ + dev-pkgs.bashInteractive + dev-pkgs.coreutils + dev-pkgs.pkgsBuildHost.gdb + dev-pkgs.pkgsBuildHost.python3Minimal + dev-pkgs.pkgsBuildHost.rr + + pkgs.pkgsHostHost.libc.debug + pkgs.pkgsHostHost.libc.out + ]; + }; + }; + copyToRoot = pkgs.buildEnv { + name = "dataplane-debugger-env"; + inherit pathsToLink; + paths = [ + workspace.cli.debug + workspace.dataplane.debug + workspace.init.debug + ]; + }; }; - }; in { @@ -511,8 +590,9 @@ in dataplane-tar containers dev-pkgs - devroot devenv + devroot + gdbserver-tar package-list pkgs sources @@ -520,6 +600,7 @@ in tests workspace ; + frr = frr-pkgs; profile = profile'; platform = platform'; } diff --git a/scripts/acks2.yml b/scripts/acks2.yml new file mode 100644 index 000000000..c36129752 --- /dev/null +++ b/scripts/acks2.yml @@ -0,0 +1,108 @@ +# TODO: add fields for suggested actions / mitigations + +CVE-2025-1153: + package: binutils + description: | + A vulnerability classified as problematic was found in GNU Binutils 2.43/2.44. Affected by this vulnerability is + the function bfd_set_format of the file format.c. The manipulation leads to memory corruption. The attack can be + launched remotely. The complexity of an attack is rather high. The exploitation appears to be difficult. + Upgrading to version 2.45 is able to address this issue. The identifier of the patch is + 8d97c1a53f3dc9fd8e1ccdb039b8a33d50133150. It is recommended to upgrade the affected component. + note: &we-do-not-ship-binutils | + We do not ship binutils in the Hedgehog Dataplane at this time. This vulnerability is only picked up by the + scanner because binutils is a build dependency. We will upgrade to 2.45 when nixpkgs does. + +CVE-2025-3198: + package: binutils + description: | + A vulnerability has been found in GNU Binutils 2.43/2.44 and classified as problematic. Affected by this + vulnerability is the function display_info of the file binutils/bucomm.c of the component objdump. The + manipulation leads to memory leak. An attack has to be approached locally. The exploit has been disclosed to the + public and may be used. The patch is named ba6ad3a18cb26b79e0e3b84c39f707535bbc344d. It is recommended to apply + a patch to fix this issue. + note: *we-do-not-ship-binutils + +CVE-2025-8224: + package: binutils + description: | + A vulnerability has been found in GNU Binutils 2.44 and classified as problematic. This vulnerability affects + the function bfd_elf_get_str_section of the file bfd/elf.c of the component BFD Library. The manipulation leads + to null pointer dereference. Local access is required to approach this attack. The exploit has been disclosed to + the public and may be used. The name of the patch is db856d41004301b3a56438efd957ef5cabb91530. It is recommended + to apply a patch to fix this issue. + note: *we-do-not-ship-binutils + +CVE-2025-8225: + package: binutils + description: | + A vulnerability was found in GNU Binutils 2.44 and classified as problematic. This issue affects the function + process_debug_info of the file binutils/dwarf.c of the component DWARF Section Handler. The manipulation leads + to memory leak. Attacking locally is a requirement. The identifier of the patch is + e51fdff7d2e538c0e5accdd65649ac68e6e0ddd4. It is recommended to apply a patch to fix this issue. + note: *we-do-not-ship-binutils + +CVE-2023-4039: + package: gcc + description: | + **DISPUTED** + + A failure in the -fstack-protector feature in GCC-based toolchains + that target AArch64 allows an attacker to exploit an existing buffer + overflow in dynamically-sized local variables in your application + without this being detected. This stack-protector failure only applies + to C99-style dynamically-sized local variables or those created using + alloca(). The stack-protector operates as intended for statically-sized + local variables. + + The default behavior when the stack-protector + detects an overflow is to terminate your application, resulting in + controlled loss of availability. An attacker who can exploit a buffer + overflow without triggering the stack-protector might be able to change + program flow control to cause an uncontrolled loss of availability or to + go further and affect confidentiality or integrity. + + NOTE: The GCC project argues that this is a missed hardening bug and not a vulnerability by itself. + note: | + This vulnerability does not affect the Hedgehog Dataplane because we do not use gcc to build anything we ship + (save glibc). All dependencies (save glibc) are compiled with LLVM. + + Further, I agree with the GCC project's position that this is a missed hardening opportunity. + We will update to a version of glibc compiled by a fixed version of GCC when both are available in nixpkgs. + No action can or should be taken for now regarding this CVE. + +CVE-2025-5702: + package: glibc + description: | + The strcmp implementation optimized for the Power10 processor in the GNU C Library version 2.39 and later writes + to vector registers v20 to v31 without saving contents from the caller (those registers are defined as + non-volatile registers by the powerpc64le ABI), resulting in overwriting of its contents and potentially + altering control flow of the caller, or leaking the input strings to the function to other parts of the program. + note: &we-do-not-support-power-10 | + We don't currently support Power10 so this CVE simply does not apply to the Hedgehog Dataplane. + +CVE-2025-5745: + package: glibc + description: | + The strncmp implementation optimized for the Power10 processor in the GNU C Library version 2.40 and later + writes to vector registers v20 to v31 without saving contents from the caller (those registers are defined as + non-volatile registers by the powerpc64le ABI), resulting in overwriting of its contents and potentially + altering control flow of the caller, or leaking the input strings to the function to other parts of the program. + note: *we-do-not-support-power-10 + +CVE-2023-6992: + package: zlib + description: | + Cloudflare version of zlib library was found to be vulnerable to memory corruption issues affecting the + deflation algorithm implementation (deflate.c). The issues resulted from improper input validation and + heap-based buffer overflow. A local attacker could exploit the problem during compression using a crafted + malicious file potentially leading to denial of service of the software. + + Patches: The issue has been patched in commit 8352d10 + https://github.com/cloudflare/zlib/commit/8352d108c05db1bdc5ac3bdf834dad641694c13c . + + The upstream repository is not affected. + note: | + This vulnerability does not apply to the Hedgehog Dataplane. + + While do depend on zlib we do not reference Cloudflare's zlib fork in any way. + This CVE is spuriously detected by the scanner (which is conservative by design). diff --git a/scripts/sbom.sh b/scripts/sbom.sh new file mode 100644 index 000000000..43e24865b --- /dev/null +++ b/scripts/sbom.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +set -euo pipefail + +pushd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null + +vulnix \ + --closure \ + --json \ + --show-description /tmp/dataplane-tar | \ +jq --slurpfile acks <(yq . ./acks2.yml) --raw-output -f sbom2.jq diff --git a/scripts/sbom2.jq b/scripts/sbom2.jq new file mode 100644 index 000000000..39fa3f2e9 --- /dev/null +++ b/scripts/sbom2.jq @@ -0,0 +1,66 @@ +def rate_icon: + . as $score | + if $score >= 9.0 then ":fire:" + elif $score >= 8.0 then ":rotating_light:" + elif $score >= 6.0 then ":warning:" + elif $score >= 4.0 then ":orange_circle:" + elif $score >= 3.0 then ":yellow_circle:" + else ":white_square_button:" + end +; + +def md_for_cve(cve; prog): + "### " + (prog.cvssv3_basescore[cve] | rate_icon) + "[" + cve + "](https://nvd.nist.gov/vuln/detail/" + cve + ")\n" + + "\n" + + "| Package | Version | CVSSv3 |\n" + + "|:--------|:--------|:-------|\n" + + "| " + prog.pname + " | " + (prog.version | tostring) + " | " + (prog.cvssv3_basescore[cve] | tostring) + " |\n" + + "\n" + + if ($acks[][cve]?.description) then ( + $acks[][cve].description + ) else ( + prog.description[cve] + ) end + + "\n\n" + + if ($acks[][cve].note) then ( + "#### Impact on Hedgehog Dataplane\n" + + "\n" + + $acks[][cve].note + + "\n" + ) else ( + "" + ) end +; + +def all_cves: + . as $stream | + if ($stream == null) then [] else $stream end | + $stream[] as $prog | + $prog.affected_by as $cves | + $cves[] | + { cve: ., prog: $prog } +; + +def main: + . as $input | + [$input | all_cves] | sort_by(.prog.cvssv3_basescore[.cve]) | reverse | map({ key: .cve, value: .prog}) as $all_cves | + $all_cves | map(select(.key | in($acks[]) | not)) as $new_cves | + $all_cves | map(select(.key | in($acks[]))) as $acked_cves | + "# Security Scan\n\n" + + (now | todate) + "\n\n" + + if ($new_cves == []) then + "## No newly reported CVEs\n\n" + else + "## Newly reported CVEs\n\n" + + ($new_cves | map(md_for_cve(.key; .value)) | join("---\n\n")) + end + + + if ($acked_cves == []) then + "## No previously reported CVEs\n\n" + else + "## Previously reported CVEs\n\n" + + ($acked_cves | map(md_for_cve(.key; .value)) | join("---\n\n")) + end +; + +main