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/
master
Patryk Wychowaniec 2021-02-26 17:14:08 +01:00
parent 5f1345a303
commit 336ef2de99
No known key found for this signature in database
GPG Key ID: F62547D075E09767
3 changed files with 46 additions and 4 deletions

View File

@ -271,8 +271,8 @@ let
DeviceAllow = map (d: "${d.node} ${d.modifier}") cfg.allowedDevices; DeviceAllow = map (d: "${d.node} ${d.modifier}") cfg.allowedDevices;
}; };
system = config.nixpkgs.localSystem.system; system = config.nixpkgs.localSystem.system;
kernelVersion = config.boot.kernelPackages.kernel.version;
bindMountOpts = { name, ... }: { bindMountOpts = { name, ... }: {
@ -321,7 +321,6 @@ let
}; };
}; };
mkBindFlag = d: mkBindFlag = d:
let flagPrefix = if d.isReadOnly then " --bind-ro=" else " --bind="; let flagPrefix = if d.isReadOnly then " --bind-ro=" else " --bind=";
mountstr = if d.hostPath != null then "${d.hostPath}:${d.mountPoint}" else "${d.mountPoint}"; mountstr = if d.hostPath != null then "${d.hostPath}:${d.mountPoint}" else "${d.mountPoint}";
@ -482,11 +481,16 @@ in
networking.useDHCP = false; networking.useDHCP = false;
assertions = [ assertions = [
{ {
assertion = config.privateNetwork -> stringLength name < 12; assertion =
(builtins.compareVersions kernelVersion "5.8" <= 0)
-> config.privateNetwork
-> stringLength name <= 11;
message = '' message = ''
Container name `${name}` is too long: When `privateNetwork` is enabled, container names can 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. 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).
''; '';
} }
]; ];

View File

@ -72,6 +72,7 @@ in
containers-imperative = handleTest ./containers-imperative.nix {}; containers-imperative = handleTest ./containers-imperative.nix {};
containers-ip = handleTest ./containers-ip.nix {}; containers-ip = handleTest ./containers-ip.nix {};
containers-macvlans = handleTest ./containers-macvlans.nix {}; containers-macvlans = handleTest ./containers-macvlans.nix {};
containers-names = handleTest ./containers-names.nix {};
containers-physical_interfaces = handleTest ./containers-physical_interfaces.nix {}; containers-physical_interfaces = handleTest ./containers-physical_interfaces.nix {};
containers-portforward = handleTest ./containers-portforward.nix {}; containers-portforward = handleTest ./containers-portforward.nix {};
containers-reloadable = handleTest ./containers-reloadable.nix {}; containers-reloadable = handleTest ./containers-reloadable.nix {};

View File

@ -0,0 +1,37 @@
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")
'';
})