nixos/containers: allow containers with long names to create private networks

Launching a container with a private network requires creating a
dedicated networking interface for it; name of that interface is derived
from the container name itself - e.g. a container named `foo` gets
attached to an interface named `ve-foo`.

An interface name can span up to IFNAMSIZ characters, which means that a
container name must contain at most IFNAMSIZ - 3 - 1 = 11 characters;
it's a limit that we validate using a build-time assertion.

This limit has been upgraded with Linux 5.8, as it allows for an
interface to contain a so-called altname, which can be much longer,
while remaining treated as a first-class citizen.

Since altnames have been supported natively by systemd for a while now,
due diligence on our side ends with dropping the name-assertion on newer
kernels.

This commit closes #38509.

systemd/systemd#14467
systemd/systemd#17220
https://lwn.net/Articles/794289/

Changed files
+46 -4
nixos
+8 -4
nixos/modules/virtualisation/nixos-containers.nix
···
DeviceAllow = map (d: "${d.node} ${d.modifier}") cfg.allowedDevices;
};
-
system = config.nixpkgs.localSystem.system;
+
kernelVersion = config.boot.kernelPackages.kernel.version;
bindMountOpts = { name, ... }: {
···
};
};
};
-
mkBindFlag = d:
let flagPrefix = if d.isReadOnly then " --bind-ro=" else " --bind=";
···
networking.useDHCP = false;
assertions = [
{
-
assertion = config.privateNetwork -> stringLength name < 12;
+
assertion =
+
(builtins.compareVersions kernelVersion "5.8" <= 0)
+
-> config.privateNetwork
+
-> stringLength name <= 11;
message = ''
Container name `${name}` is too long: When `privateNetwork` is enabled, container names can
not be longer than 11 characters, because the container's interface name is derived from it.
-
This might be fixed in the future. See https://github.com/NixOS/nixpkgs/issues/38509
+
You should either make the container name shorter or upgrade to a more recent kernel that
+
supports interface altnames (i.e. at least Linux 5.8 - please see https://github.com/NixOS/nixpkgs/issues/38509
+
for details).
'';
}
];
+1
nixos/tests/all-tests.nix
···
containers-imperative = handleTest ./containers-imperative.nix {};
containers-ip = handleTest ./containers-ip.nix {};
containers-macvlans = handleTest ./containers-macvlans.nix {};
+
containers-names = handleTest ./containers-names.nix {};
containers-physical_interfaces = handleTest ./containers-physical_interfaces.nix {};
containers-portforward = handleTest ./containers-portforward.nix {};
containers-reloadable = handleTest ./containers-reloadable.nix {};
+37
nixos/tests/containers-names.nix
···
+
import ./make-test-python.nix ({ pkgs, lib, ... }: {
+
name = "containers-names";
+
meta = {
+
maintainers = with lib.maintainers; [ patryk27 ];
+
};
+
+
machine = { ... }: {
+
# We're using the newest kernel, so that we can test containers with long names.
+
# Please see https://github.com/NixOS/nixpkgs/issues/38509 for details.
+
boot.kernelPackages = pkgs.linuxPackages_latest;
+
+
containers = let
+
container = subnet: {
+
autoStart = true;
+
privateNetwork = true;
+
hostAddress = "192.168.${subnet}.1";
+
localAddress = "192.168.${subnet}.2";
+
config = { };
+
};
+
+
in {
+
first = container "1";
+
second = container "2";
+
really-long-name = container "3";
+
really-long-long-name-2 = container "4";
+
};
+
};
+
+
testScript = ''
+
machine.wait_for_unit("default.target")
+
+
machine.succeed("ip link show | grep ve-first")
+
machine.succeed("ip link show | grep ve-second")
+
machine.succeed("ip link show | grep ve-really-lFYWO")
+
machine.succeed("ip link show | grep ve-really-l3QgY")
+
'';
+
})