about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--nixos/modules/tasks/network-interfaces-scripted.nix33
-rw-r--r--nixos/modules/tasks/network-interfaces.nix13
-rw-r--r--nixos/release.nix1
-rw-r--r--nixos/tests/containers-physical_interfaces.nix66
4 files changed, 101 insertions, 12 deletions
diff --git a/nixos/modules/tasks/network-interfaces-scripted.nix b/nixos/modules/tasks/network-interfaces-scripted.nix
index 6a8f20bab5b62..4bbb5a3a16692 100644
--- a/nixos/modules/tasks/network-interfaces-scripted.nix
+++ b/nixos/modules/tasks/network-interfaces-scripted.nix
@@ -46,6 +46,23 @@ in
     systemd.services =
       let
 
+        deviceDependency = dev:
+          if (config.boot.isContainer == false)
+          then
+            # Trust udev when not in the container
+            [ (subsystemDevice dev) ]
+          else
+            # When in the container, check whether the interface is built from other definitions
+            if (hasAttr dev cfg.bridges) ||
+               (hasAttr dev cfg.bonds) ||
+               (hasAttr dev cfg.macvlans) ||
+               (hasAttr dev cfg.sits) ||
+               (hasAttr dev cfg.vlans) ||
+               (hasAttr dev cfg.vswitches) ||
+               (hasAttr dev cfg.wlanInterfaces)
+            then [ "${dev}-netdev.service" ]
+            else [];
+
         networkLocalCommands = {
           after = [ "network-setup.service" ];
           bindsTo = [ "network-setup.service" ];
@@ -120,8 +137,8 @@ in
             # order before network-setup because the routes that are configured
             # there may need ip addresses configured
             before = [ "network-setup.service" ];
-            bindsTo = [ (subsystemDevice i.name) ];
-            after = [ (subsystemDevice i.name) "network-pre.target" ];
+            bindsTo = deviceDependency i.name;
+            after = [ "network-pre.target" ] ++ (deviceDependency i.name);
             serviceConfig.Type = "oneshot";
             serviceConfig.RemainAfterExit = true;
             path = [ pkgs.iproute ];
@@ -179,7 +196,7 @@ in
 
         createBridgeDevice = n: v: nameValuePair "${n}-netdev"
           (let
-            deps = map subsystemDevice v.interfaces;
+            deps = if config.boot.isContainer then [] else map subsystemDevice v.interfaces;
           in
           { description = "Bridge Interface ${n}";
             wantedBy = [ "network-setup.service" (subsystemDevice n) ];
@@ -220,7 +237,7 @@ in
 
         createVswitchDevice = n: v: nameValuePair "${n}-netdev"
           (let
-            deps = map subsystemDevice v.interfaces;
+            deps = if config.boot.isContainer then [] else map subsystemDevice v.interfaces;
             ofRules = pkgs.writeText "vswitch-${n}-openFlowRules" v.openFlowRules;
           in
           { description = "Open vSwitch Interface ${n}";
@@ -253,7 +270,7 @@ in
 
         createBondDevice = n: v: nameValuePair "${n}-netdev"
           (let
-            deps = map subsystemDevice v.interfaces;
+            deps = if config.boot.isContainer then [] else map subsystemDevice v.interfaces;
           in
           { description = "Bond Interface ${n}";
             wantedBy = [ "network-setup.service" (subsystemDevice n) ];
@@ -291,7 +308,7 @@ in
 
         createMacvlanDevice = n: v: nameValuePair "${n}-netdev"
           (let
-            deps = [ (subsystemDevice v.interface) ];
+            deps = deviceDependency v.interface;
           in
           { description = "Vlan Interface ${n}";
             wantedBy = [ "network-setup.service" (subsystemDevice n) ];
@@ -316,7 +333,7 @@ in
 
         createSitDevice = n: v: nameValuePair "${n}-netdev"
           (let
-            deps = optional (v.dev != null) (subsystemDevice v.dev);
+            deps = optional (v.dev != null) (deviceDependency v.dev);
           in
           { description = "6-to-4 Tunnel Interface ${n}";
             wantedBy = [ "network-setup.service" (subsystemDevice n) ];
@@ -344,7 +361,7 @@ in
 
         createVlanDevice = n: v: nameValuePair "${n}-netdev"
           (let
-            deps = [ (subsystemDevice v.interface) ];
+            deps = deviceDependency v.interface;
           in
           { description = "Vlan Interface ${n}";
             wantedBy = [ "network-setup.service" (subsystemDevice n) ];
diff --git a/nixos/modules/tasks/network-interfaces.nix b/nixos/modules/tasks/network-interfaces.nix
index cac7e6b02eba2..aae4dc5fdadfa 100644
--- a/nixos/modules/tasks/network-interfaces.nix
+++ b/nixos/modules/tasks/network-interfaces.nix
@@ -310,9 +310,9 @@ in
         generate a random 32-bit ID using the following commands:
 
         <literal>cksum /etc/machine-id | while read c rest; do printf "%x" $c; done</literal>
-        
+
         (this derives it from the machine-id that systemd generates) or
-        
+
         <literal>head -c4 /dev/urandom | od -A none -t x4</literal>
       '';
     };
@@ -972,12 +972,17 @@ in
         '';
       };
     } // (listToAttrs (flip map interfaces (i:
+      let
+        deviceDependency = if config.boot.isContainer
+          then []
+          else [ (subsystemDevice i.name) ];
+      in
       nameValuePair "network-link-${i.name}"
       { description = "Link configuration of ${i.name}";
         wantedBy = [ "network-interfaces.target" ];
         before = [ "network-interfaces.target" ];
-        bindsTo = [ (subsystemDevice i.name) ];
-        after = [ (subsystemDevice i.name) "network-pre.target" ];
+        bindsTo = deviceDependency;
+        after = [ "network-pre.target" ] ++ deviceDependency;
         path = [ pkgs.iproute ];
         serviceConfig = {
           Type = "oneshot";
diff --git a/nixos/release.nix b/nixos/release.nix
index bff17da607f30..10c624afebc7d 100644
--- a/nixos/release.nix
+++ b/nixos/release.nix
@@ -227,6 +227,7 @@ in rec {
   tests.containers-bridge = callTest tests/containers-bridge.nix {};
   tests.containers-imperative = callTest tests/containers-imperative.nix {};
   tests.containers-extra_veth = callTest tests/containers-extra_veth.nix {};
+  tests.containers-physical_interfaces = callTest tests/containers-physical_interfaces.nix {};
   tests.docker = hydraJob (import tests/docker.nix { system = "x86_64-linux"; });
   tests.dnscrypt-proxy = callTest tests/dnscrypt-proxy.nix { system = "x86_64-linux"; };
   tests.ecryptfs = callTest tests/ecryptfs.nix {};
diff --git a/nixos/tests/containers-physical_interfaces.nix b/nixos/tests/containers-physical_interfaces.nix
new file mode 100644
index 0000000000000..4a53f8c824f5b
--- /dev/null
+++ b/nixos/tests/containers-physical_interfaces.nix
@@ -0,0 +1,66 @@
+
+import ./make-test.nix ({ pkgs, ...} : {
+  name = "containers-physical_interfaces";
+  meta = with pkgs.stdenv.lib.maintainers; {
+    maintainers = [ kampfschlaefer ];
+  };
+
+  nodes = {
+    server = { config, pkgs, ... }:
+      {
+        virtualisation.memorySize = 256;
+        virtualisation.vlans = [ 1 ];
+
+        containers.server = {
+          privateNetwork = true;
+          interfaces = [ "eth1" ];
+
+          config = {
+            networking.interfaces.eth1 = {
+              ip4 = [ { address = "10.10.0.1"; prefixLength = 24; } ];
+            };
+            networking.firewall.enable = false;
+          };
+        };
+      };
+    client = { config, pkgs, ... }: {
+      virtualisation.memorySize = 256;
+      virtualisation.vlans = [ 1 ];
+
+      containers.client = {
+        privateNetwork = true;
+        interfaces = [ "eth1" ];
+
+        config = {
+          networking.bridges.br0.interfaces = [ "eth1" ];
+          networking.interfaces.br0 = {
+            ip4 = [ { address = "10.10.0.2"; prefixLength = 24; } ];
+          };
+          networking.firewall.enable = false;
+        };
+      };
+    };
+  };
+
+  testScript = ''
+    startAll;
+
+    $server->waitForUnit("default.target");
+    $server->execute("ip link >&2");
+
+    $server->succeed("ip link show dev eth1 >&2");
+
+    $server->succeed("nixos-container start server");
+    $server->waitForUnit("container\@server");
+    $server->succeed("systemctl -M server list-dependencies network-addresses-eth1.service >&2");
+
+    $server->succeed("nixos-container run server -- ip a show dev eth1 >&2");
+
+    $client->waitForUnit("default.target");
+    $client->succeed("nixos-container start client");
+    $client->waitForUnit("container\@client");
+    $client->succeed("systemctl -M client list-dependencies network-addresses-br0.service >&2");
+    $client->succeed("systemctl -M client status -n 30 -l network-addresses-br0.service");
+    $client->succeed("nixos-container run client -- ping -w 10 -c 1 -n 10.10.0.1");
+  '';
+})