diff --git a/lib/default.nix b/lib/default.nix index 7387e9d9f1f..43b9ab5930c 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -67,7 +67,7 @@ let inherit (trivial) id const pipe concat or and bitAnd bitOr bitXor bitNot boolToString mergeAttrs flip mapNullable inNixShell min max importJSON warn info showWarnings nixpkgsVersion version mod compare - splitByAndCompare functionArgs setFunctionArgs isFunction; + splitByAndCompare functionArgs setFunctionArgs isFunction toHexString toBaseDigits; inherit (fixedPoints) fix fix' converge extends composeExtensions makeExtensible makeExtensibleWithCustomName; inherit (attrsets) attrByPath hasAttrByPath setAttrByPath diff --git a/lib/tests/misc.nix b/lib/tests/misc.nix index 36ddd186d7b..b066f577f32 100644 --- a/lib/tests/misc.nix +++ b/lib/tests/misc.nix @@ -102,6 +102,16 @@ runTests { expected = 9; }; + testToHexString = { + expr = toHexString 250; + expected = "FA"; + }; + + testToBaseDigits = { + expr = toBaseDigits 2 6; + expected = [ 1 1 0 ]; + }; + # STRINGS testConcatMapStrings = { diff --git a/lib/trivial.nix b/lib/trivial.nix index 5788dd435e5..6eb1fb3a5b1 100644 --- a/lib/trivial.nix +++ b/lib/trivial.nix @@ -332,4 +332,55 @@ rec { */ isFunction = f: builtins.isFunction f || (f ? __functor && isFunction (f.__functor f)); + + /* Convert the given positive integer to a string of its hexadecimal + representation. For example: + + toHexString 0 => "0" + + toHexString 16 => "10" + + toHexString 250 => "FA" + */ + toHexString = i: + let + toHexDigit = d: + if d < 10 + then toString d + else + { + "10" = "A"; + "11" = "B"; + "12" = "C"; + "13" = "D"; + "14" = "E"; + "15" = "F"; + }.${toString d}; + in + lib.concatMapStrings toHexDigit (toBaseDigits 16 i); + + /* `toBaseDigits base i` converts the positive integer i to a list of its + digits in the given base. For example: + + toBaseDigits 10 123 => [ 1 2 3 ] + + toBaseDigits 2 6 => [ 1 1 0 ] + + toBaseDigits 16 250 => [ 15 10 ] + */ + toBaseDigits = base: i: + let + go = i: + if i < base + then [i] + else + let + r = i - ((i / base) * base); + q = (i - r) / base; + in + [r] ++ go q; + in + assert (base >= 2); + assert (i >= 0); + lib.reverseList (go i); } diff --git a/nixos/lib/qemu-flags.nix b/nixos/lib/qemu-flags.nix index 859d9e975fe..0cf6977af4b 100644 --- a/nixos/lib/qemu-flags.nix +++ b/nixos/lib/qemu-flags.nix @@ -2,13 +2,18 @@ { pkgs }: let - zeroPad = n: if n < 10 then "0${toString n}" else toString n; + zeroPad = n: + pkgs.lib.optionalString (n < 16) "0" + + (if n > 255 + then throw "Can't have more than 255 nets or nodes!" + else pkgs.lib.toHexString n); in -{ +rec { + qemuNicMac = net: machine: "52:54:00:12:${zeroPad net}:${zeroPad machine}"; qemuNICFlags = nic: net: machine: - [ "-device virtio-net-pci,netdev=vlan${toString nic},mac=52:54:00:12:${zeroPad net}:${zeroPad machine}" + [ "-device virtio-net-pci,netdev=vlan${toString nic},mac=${qemuNicMac net machine}" "-netdev vde,id=vlan${toString nic},sock=$QEMU_VDE_SOCKET_${toString net}" ]; diff --git a/nixos/tests/networking.nix b/nixos/tests/networking.nix index 3d8ab761a44..ebebbf90eb1 100644 --- a/nixos/tests/networking.nix +++ b/nixos/tests/networking.nix @@ -8,7 +8,9 @@ with import ../lib/testing-python.nix { inherit system pkgs; }; with pkgs.lib; let - router = { config, pkgs, ... }: + qemu-flags = import ../lib/qemu-flags.nix { inherit pkgs; }; + + router = { config, pkgs, lib, ... }: with pkgs.lib; let vlanIfs = range 1 (length config.virtualisation.vlans); @@ -31,16 +33,19 @@ let enable = true; interfaces = map (n: "eth${toString n}") vlanIfs; extraConfig = '' - authoritative; '' + flip concatMapStrings vlanIfs (n: '' subnet 192.168.${toString n}.0 netmask 255.255.255.0 { option routers 192.168.${toString n}.1; - # XXX: technically it's _not guaranteed_ that IP addresses will be - # issued from the first item in range onwards! We assume that in - # our tests however. - range 192.168.${toString n}.2 192.168.${toString n}.254; } - ''); + '') + ; + machines = lib.flip map vlanIfs (vlan: + { + hostName = "client${toString vlan}"; + ethernetAddress = qemu-flags.qemuNicMac vlan 1; + ipAddress = "192.168.${toString vlan}.2"; + } + ); }; services.radvd = { enable = true;