about summary refs log tree commit diff
path: root/nixos
diff options
context:
space:
mode:
Diffstat (limited to 'nixos')
-rw-r--r--nixos/doc/manual/development/running-nixos-tests.xml32
-rw-r--r--nixos/modules/config/networking.nix117
-rw-r--r--nixos/modules/hardware/all-firmware.nix8
-rw-r--r--nixos/modules/hardware/video/bumblebee.nix2
-rw-r--r--nixos/modules/installer/tools/nixos-generate-config.pl2
-rw-r--r--nixos/modules/misc/ids.nix3
-rwxr-xr-xnixos/modules/module-list.nix5
-rw-r--r--nixos/modules/programs/environment.nix1
-rw-r--r--nixos/modules/programs/virtualbox-host.nix72
-rw-r--r--nixos/modules/programs/virtualbox.nix54
-rw-r--r--nixos/modules/rename.nix6
-rw-r--r--nixos/modules/security/ca.nix2
-rw-r--r--nixos/modules/services/backup/almir.nix1
-rw-r--r--nixos/modules/services/misc/mesos-master.nix21
-rw-r--r--nixos/modules/services/misc/nix-daemon.nix22
-rw-r--r--nixos/modules/services/networking/chrony.nix11
-rw-r--r--nixos/modules/services/networking/dhcpcd.nix20
-rw-r--r--nixos/modules/services/networking/dnsmasq.nix2
-rw-r--r--nixos/modules/services/networking/firewall.nix5
-rw-r--r--nixos/modules/services/networking/gogoclient.nix3
-rw-r--r--nixos/modules/services/networking/networkmanager.nix1
-rw-r--r--nixos/modules/services/networking/ntpd.nix10
-rw-r--r--nixos/modules/services/networking/openntpd.nix3
-rw-r--r--nixos/modules/services/networking/ssh/sshd.nix21
-rw-r--r--nixos/modules/services/printing/cupsd.nix15
-rw-r--r--nixos/modules/services/torrent/peerflix.nix63
-rw-r--r--nixos/modules/system/boot/stage-2-init.sh2
-rw-r--r--nixos/modules/system/boot/systemd-unit-options.nix537
-rw-r--r--nixos/modules/system/boot/systemd.nix266
-rw-r--r--nixos/modules/tasks/filesystems/nfs.nix12
-rw-r--r--nixos/modules/tasks/network-interfaces-scripted.nix342
-rw-r--r--nixos/modules/tasks/network-interfaces-systemd.nix174
-rw-r--r--nixos/modules/tasks/network-interfaces.nix474
-rw-r--r--nixos/modules/virtualisation/docker.nix10
-rw-r--r--nixos/modules/virtualisation/kubernetes.nix461
-rw-r--r--nixos/modules/virtualisation/virtualbox-guest.nix4
-rw-r--r--nixos/modules/virtualisation/virtualbox-image.nix2
-rw-r--r--nixos/release-combined.nix8
-rw-r--r--nixos/release.nix25
-rw-r--r--nixos/tests/docker.nix24
-rw-r--r--nixos/tests/kubernetes.nix176
-rw-r--r--nixos/tests/networking-proxy.nix109
-rw-r--r--nixos/tests/networking.nix381
-rw-r--r--nixos/tests/nfs.nix3
-rw-r--r--nixos/tests/peerflix.nix21
-rw-r--r--nixos/tests/printing.nix13
46 files changed, 3042 insertions, 504 deletions
diff --git a/nixos/doc/manual/development/running-nixos-tests.xml b/nixos/doc/manual/development/running-nixos-tests.xml
index d9be761eb01d..156dcd205a55 100644
--- a/nixos/doc/manual/development/running-nixos-tests.xml
+++ b/nixos/doc/manual/development/running-nixos-tests.xml
@@ -39,24 +39,13 @@ $ firefox result/log.html
 
 </para>
 
-<para>It is also possible to run the test environment interactively,
-allowing you to experiment with the VMs.  For example:
+<title>Running Tests interactively</title>
 
-<screen>
-$ nix-build login.nix -A driver
-$ ./result/bin/nixos-run-vms
-</screen>
-
-The script <command>nixos-run-vms</command> starts the virtual
-machines defined by test.  The root file system of the VMs is created
-on the fly and kept across VM restarts in
-<filename>./</filename><varname>hostname</varname><filename>.qcow2</filename>.</para>
-
-<para>Finally, the test itself can be run interactively.  This is
+<para>The test itself can be run interactively.  This is
 particularly useful when developing or debugging a test:
 
 <screen>
-$ nix-build tests/ -A nfs.driver
+$ nix-build nixos/tests/login.nix -A driver
 $ ./result/bin/nixos-test-driver
 starting VDE switch for network 1
 &gt;
@@ -66,6 +55,7 @@ You can then take any Perl statement, e.g.
 
 <screen>
 &gt; startAll
+&gt; testScript
 &gt; $machine->succeed("touch /tmp/foo")
 </screen>
 
@@ -74,4 +64,16 @@ script and drops you back into the test driver command line upon its
 completion.  This allows you to inspect the state of the VMs after the
 test (e.g. to debug the test script).</para>
 
-</section>
\ No newline at end of file
+<para>To just start and experiment with the VMs, run:
+
+<screen>
+$ nix-build nixos/tests/login.nix -A driver
+$ ./result/bin/nixos-run-vms
+</screen>
+
+The script <command>nixos-run-vms</command> starts the virtual
+machines defined by test.  The root file system of the VMs is created
+on the fly and kept across VM restarts in
+<filename>./</filename><varname>hostname</varname><filename>.qcow2</filename>.</para>
+
+</section>
diff --git a/nixos/modules/config/networking.nix b/nixos/modules/config/networking.nix
index 136a5bda7459..77e55fddf693 100644
--- a/nixos/modules/config/networking.nix
+++ b/nixos/modules/config/networking.nix
@@ -39,6 +39,73 @@ in
       '';
     };
 
+    networking.proxy = {
+
+      default = lib.mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = ''
+          This option specifies the default value for httpProxy, httpsProxy, ftpProxy and rsyncProxy.
+        '';
+        example = "http://127.0.0.1:3128";
+      };
+
+      httpProxy = lib.mkOption {
+        type = types.nullOr types.str;
+        default = cfg.proxy.default;
+        description = ''
+          This option specifies the http_proxy environment variable.
+        '';
+        example = "http://127.0.0.1:3128";
+      };
+
+      httpsProxy = lib.mkOption {
+        type = types.nullOr types.str;
+        default = cfg.proxy.default;
+        description = ''
+          This option specifies the https_proxy environment variable.
+        '';
+        example = "http://127.0.0.1:3128";
+      };
+
+      ftpProxy = lib.mkOption {
+        type = types.nullOr types.str;
+        default = cfg.proxy.default;
+        description = ''
+          This option specifies the ftp_proxy environment variable.
+        '';
+        example = "http://127.0.0.1:3128";
+      };
+
+      rsyncProxy = lib.mkOption {
+        type = types.nullOr types.str;
+        default = cfg.proxy.default;
+        description = ''
+          This option specifies the rsync_proxy environment variable.
+        '';
+        example = "http://127.0.0.1:3128";
+      };
+
+      noProxy = lib.mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = ''
+          This option specifies the no_proxy environment variable.
+          If a default proxy is used and noProxy is null,
+          then noProxy will be set to 127.0.0.1,localhost.
+        '';
+        example = "127.0.0.1,localhost,.localdomain";
+      };
+
+      envVars = lib.mkOption {
+        type = types.attrs;
+        internal = true;
+        default = {};
+        description = ''
+          Environment variables used for the network proxy.
+        '';
+      };
+    };
   };
 
   config = {
@@ -84,13 +151,59 @@ in
               dnsmasq_conf=/etc/dnsmasq-conf.conf
               dnsmasq_resolv=/etc/dnsmasq-resolv.conf
             '';
-      };
+
+      } // (optionalAttrs config.services.resolved.enable (
+        if dnsmasqResolve then {
+          "dnsmasq-resolv.conf".source = "/run/systemd/resolve/resolv.conf";
+        } else {
+          "resolv.conf".source = "/run/systemd/resolve/resolv.conf";
+        }
+      ));
+
+      networking.proxy.envVars =
+        optionalAttrs (cfg.proxy.default != null) {
+          # other options already fallback to proxy.default
+          no_proxy = "127.0.0.1,localhost";
+        } // optionalAttrs (cfg.proxy.httpProxy != null) {
+          http_proxy  = cfg.proxy.httpProxy;
+        } // optionalAttrs (cfg.proxy.httpsProxy != null) {
+          https_proxy = cfg.proxy.httpsProxy;
+        } // optionalAttrs (cfg.proxy.rsyncProxy != null) {
+          rsync_proxy = cfg.proxy.rsyncProxy;
+        } // optionalAttrs (cfg.proxy.ftpProxy != null) {
+          ftp_proxy   = cfg.proxy.ftpProxy;
+        } // optionalAttrs (cfg.proxy.noProxy != null) {
+          no_proxy    = cfg.proxy.noProxy;
+        };
+
+    # Install the proxy environment variables
+    environment.sessionVariables = cfg.proxy.envVars;
 
     # The ‘ip-up’ target is started when we have IP connectivity.  So
     # services that depend on IP connectivity (like ntpd) should be
     # pulled in by this target.
     systemd.targets.ip-up.description = "Services Requiring IP Connectivity";
 
+    # This is needed when /etc/resolv.conf is being overriden by networkd
+    # and other configurations. If the file is destroyed by an environment
+    # activation then it must be rebuilt so that applications which interface
+    # with /etc/resolv.conf directly don't break.
+    system.activationScripts.resolvconf = stringAfter [ "etc" "tmpfs" "var" ]
+      ''
+        # Systemd resolved controls its own resolv.conf
+        rm -f /run/resolvconf/interfaces/systemd
+        ${optionalString config.services.resolved.enable ''
+          rm -rf /run/resolvconf/interfaces
+          mkdir -p /run/resolvconf/interfaces
+          ln -s /run/systemd/resolve/resolv.conf /run/resolvconf/interfaces/systemd
+        ''}
+
+        # Make sure resolv.conf is up to date if not managed by systemd
+        ${optionalString (!config.services.resolved.enable) ''
+          ${pkgs.openresolv}/bin/resolvconf -u
+        ''}
+      '';
+
   };
 
-}
+  }
diff --git a/nixos/modules/hardware/all-firmware.nix b/nixos/modules/hardware/all-firmware.nix
index 3820a95b12e2..a3821e9738a6 100644
--- a/nixos/modules/hardware/all-firmware.nix
+++ b/nixos/modules/hardware/all-firmware.nix
@@ -12,7 +12,8 @@ with lib;
       default = false;
       type = types.bool;
       description = ''
-        Turn on this option if you want to enable all the firmware shipped with Debian/Ubuntu.
+        Turn on this option if you want to enable all the firmware shipped with Debian/Ubuntu
+        and iwlwifi.
       '';
     };
 
@@ -22,7 +23,10 @@ with lib;
   ###### implementation
 
   config = mkIf config.hardware.enableAllFirmware {
-    hardware.firmware = [ "${pkgs.firmwareLinuxNonfree}/lib/firmware" ];
+    hardware.firmware = [
+      "${pkgs.firmwareLinuxNonfree}/lib/firmware"
+      "${pkgs.iwlwifi}/lib/firmware"
+    ];
   };
 
 }
diff --git a/nixos/modules/hardware/video/bumblebee.nix b/nixos/modules/hardware/video/bumblebee.nix
index 52dea798f87a..7b48d9d1fcf5 100644
--- a/nixos/modules/hardware/video/bumblebee.nix
+++ b/nixos/modules/hardware/video/bumblebee.nix
@@ -30,7 +30,7 @@ with lib;
     boot.kernelModules = [ "bbswitch" ];
     boot.extraModulePackages = [ kernel.bbswitch kernel.nvidia_x11 ];
 
-    environment.systemPackages = [ pkgs.bumblebee ];
+    environment.systemPackages = [ pkgs.bumblebee pkgs.primus ];
 
     systemd.services.bumblebeed = {
       description = "Bumblebee Hybrid Graphics Switcher";
diff --git a/nixos/modules/installer/tools/nixos-generate-config.pl b/nixos/modules/installer/tools/nixos-generate-config.pl
index 7178c4b1dfb7..a3b763a8a946 100644
--- a/nixos/modules/installer/tools/nixos-generate-config.pl
+++ b/nixos/modules/installer/tools/nixos-generate-config.pl
@@ -235,7 +235,7 @@ chomp $virt;
 # Check if we're a VirtualBox guest.  If so, enable the guest
 # additions.
 if ($virt eq "oracle") {
-    push @attrs, "services.virtualbox.enable = true;"
+    push @attrs, "services.virtualboxGuest.enable = true;"
 }
 
 
diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix
index 4d91e266d85b..687e26279e60 100644
--- a/nixos/modules/misc/ids.nix
+++ b/nixos/modules/misc/ids.nix
@@ -169,6 +169,8 @@
       opentsdb = 159;
       scollector = 160;
       bosun = 161;
+      kubernetes = 162;
+      peerflix = 163;
 
       # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399!
 
@@ -302,6 +304,7 @@
       liquidsoap = 155;
       scollector = 156;
       bosun = 157;
+      kubernetes = 158;
 
       # When adding a gid, make sure it doesn't match an existing uid. And don't use gids above 399!
 
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index 85afcb824fb7..9f4f33d137f6 100755
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -67,6 +67,7 @@
   ./programs/ssmtp.nix
   ./programs/uim.nix
   ./programs/venus.nix
+  ./programs/virtualbox-host.nix
   ./programs/wvdial.nix
   ./programs/freetds.nix
   ./programs/zsh/zsh.nix
@@ -308,6 +309,7 @@
   ./services/system/nscd.nix
   ./services/system/uptimed.nix
   ./services/torrent/deluge.nix
+  ./services/torrent/peerflix.nix
   ./services/torrent/transmission.nix
   ./services/ttys/agetty.nix
   ./services/ttys/gpm.nix
@@ -387,6 +389,8 @@
   ./tasks/kbd.nix
   ./tasks/lvm.nix
   ./tasks/network-interfaces.nix
+  ./tasks/network-interfaces-systemd.nix
+  ./tasks/network-interfaces-scripted.nix
   ./tasks/scsi-link-power-management.nix
   ./tasks/swraid.nix
   ./tasks/trackpoint.nix
@@ -394,6 +398,7 @@
   ./virtualisation/container-config.nix
   ./virtualisation/containers.nix
   ./virtualisation/docker.nix
+  ./virtualisation/kubernetes.nix
   ./virtualisation/libvirtd.nix
   ./virtualisation/lxc.nix
   #./virtualisation/nova.nix
diff --git a/nixos/modules/programs/environment.nix b/nixos/modules/programs/environment.nix
index d79aff5dc553..a5ec387df647 100644
--- a/nixos/modules/programs/environment.nix
+++ b/nixos/modules/programs/environment.nix
@@ -40,7 +40,6 @@ in
     # TODO: move most of these elsewhere
     environment.profileRelativeEnvVars =
       { PATH = [ "/bin" "/sbin" "/lib/kde4/libexec" ];
-        MANPATH = [ "/man" "/share/man" ];
         INFOPATH = [ "/info" "/share/info" ];
         PKG_CONFIG_PATH = [ "/lib/pkgconfig" ];
         TERMINFO_DIRS = [ "/share/terminfo" ];
diff --git a/nixos/modules/programs/virtualbox-host.nix b/nixos/modules/programs/virtualbox-host.nix
new file mode 100644
index 000000000000..ea962d5d6cee
--- /dev/null
+++ b/nixos/modules/programs/virtualbox-host.nix
@@ -0,0 +1,72 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  virtualbox = config.boot.kernelPackages.virtualbox;
+in
+
+{
+  options = {
+    services.virtualboxHost.enable = mkEnableOption "VirtualBox Host support";
+  };
+
+  config = mkIf config.services.virtualboxHost.enable {
+    boot.kernelModules = [ "vboxdrv" "vboxnetadp" "vboxnetflt" ];
+    boot.extraModulePackages = [ virtualbox ];
+    environment.systemPackages = [ virtualbox ];
+
+    security.setuidOwners = let
+      mkVboxStub = program: {
+        inherit program;
+        owner = "root";
+        group = "vboxusers";
+        setuid = true;
+      };
+    in map mkVboxStub [
+      "VBoxBFE"
+      "VBoxBalloonCtrl"
+      "VBoxHeadless"
+      "VBoxManage"
+      "VBoxSDL"
+      "VirtualBox"
+    ];
+
+    users.extraGroups.vboxusers.gid = config.ids.gids.vboxusers;
+
+    services.udev.extraRules =
+      ''
+        KERNEL=="vboxdrv",    OWNER="root", GROUP="vboxusers", MODE="0660", TAG+="systemd"
+        KERNEL=="vboxdrvu",   OWNER="root", GROUP="root",      MODE="0666", TAG+="systemd"
+        KERNEL=="vboxnetctl", OWNER="root", GROUP="vboxusers", MODE="0660", TAG+="systemd"
+        SUBSYSTEM=="usb_device", ACTION=="add", RUN+="${virtualbox}/libexec/virtualbox/VBoxCreateUSBNode.sh $major $minor $attr{bDeviceClass}"
+        SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", RUN+="${virtualbox}/libexec/virtualbox/VBoxCreateUSBNode.sh $major $minor $attr{bDeviceClass}"
+        SUBSYSTEM=="usb_device", ACTION=="remove", RUN+="${virtualbox}/libexec/virtualbox/VBoxCreateUSBNode.sh --remove $major $minor"
+        SUBSYSTEM=="usb", ACTION=="remove", ENV{DEVTYPE}=="usb_device", RUN+="${virtualbox}/libexec/virtualbox/VBoxCreateUSBNode.sh --remove $major $minor"
+      '';
+
+    # Since we lack the right setuid binaries, set up a host-only network by default.
+
+    systemd.services."vboxnet0" =
+      { description = "VirtualBox vboxnet0 Interface";
+        requires = [ "dev-vboxnetctl.device" ];
+        after = [ "dev-vboxnetctl.device" ];
+        wantedBy = [ "network.target" "sys-subsystem-net-devices-vboxnet0.device" ];
+        path = [ virtualbox ];
+        serviceConfig.RemainAfterExit = true;
+        serviceConfig.Type = "oneshot";
+        script =
+          ''
+            if ! [ -e /sys/class/net/vboxnet0 ]; then
+              VBoxManage hostonlyif create
+            fi
+          '';
+        postStop =
+          ''
+            VBoxManage hostonlyif remove vboxnet0
+          '';
+      };
+
+    networking.interfaces.vboxnet0.ip4 = [ { address = "192.168.56.1"; prefixLength = 24; } ];
+  };
+}
diff --git a/nixos/modules/programs/virtualbox.nix b/nixos/modules/programs/virtualbox.nix
index 1a190573e943..a00b1e5f64d0 100644
--- a/nixos/modules/programs/virtualbox.nix
+++ b/nixos/modules/programs/virtualbox.nix
@@ -1,48 +1,8 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
-
-let virtualbox = config.boot.kernelPackages.virtualbox; in
-
-{
-  boot.kernelModules = [ "vboxdrv" "vboxnetadp" "vboxnetflt" ];
-  boot.extraModulePackages = [ virtualbox ];
-  environment.systemPackages = [ virtualbox ];
-
-  users.extraGroups.vboxusers.gid = config.ids.gids.vboxusers;
-
-  services.udev.extraRules =
-    ''
-      KERNEL=="vboxdrv",    OWNER="root", GROUP="vboxusers", MODE="0660", TAG+="systemd"
-      KERNEL=="vboxdrvu",   OWNER="root", GROUP="root",      MODE="0666", TAG+="systemd"
-      KERNEL=="vboxnetctl", OWNER="root", GROUP="vboxusers", MODE="0660", TAG+="systemd"
-      SUBSYSTEM=="usb_device", ACTION=="add", RUN+="${virtualbox}/libexec/virtualbox/VBoxCreateUSBNode.sh $major $minor $attr{bDeviceClass}"
-      SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", RUN+="${virtualbox}/libexec/virtualbox/VBoxCreateUSBNode.sh $major $minor $attr{bDeviceClass}"
-      SUBSYSTEM=="usb_device", ACTION=="remove", RUN+="${virtualbox}/libexec/virtualbox/VBoxCreateUSBNode.sh --remove $major $minor"
-      SUBSYSTEM=="usb", ACTION=="remove", ENV{DEVTYPE}=="usb_device", RUN+="${virtualbox}/libexec/virtualbox/VBoxCreateUSBNode.sh --remove $major $minor"
-    '';
-
-  # Since we lack the right setuid binaries, set up a host-only network by default.
-
-  systemd.services."vboxnet0" =
-    { description = "VirtualBox vboxnet0 Interface";
-      requires = [ "dev-vboxnetctl.device" ];
-      after = [ "dev-vboxnetctl.device" ];
-      wantedBy = [ "network.target" "sys-subsystem-net-devices-vboxnet0.device" ];
-      path = [ virtualbox ];
-      serviceConfig.RemainAfterExit = true;
-      serviceConfig.Type = "oneshot";
-      script =
-        ''
-          if ! [ -e /sys/class/net/vboxnet0 ]; then
-            VBoxManage hostonlyif create
-          fi
-        '';
-      postStop =
-        ''
-          VBoxManage hostonlyif remove vboxnet0
-        '';
-    };
-
-  networking.interfaces.vboxnet0.ip4 = [ { address = "192.168.56.1"; prefixLength = 24; } ];
+let
+  msg = "Importing <nixpkgs/nixos/modules/programs/virtualbox.nix> is "
+      + "deprecated, please use `services.virtualboxHost.enable = true' "
+      + "instead.";
+in {
+  config.warnings = [ msg ];
+  config.services.virtualboxHost.enable = true;
 }
diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix
index ea7d9763ce64..b29a3d0354c9 100644
--- a/nixos/modules/rename.nix
+++ b/nixos/modules/rename.nix
@@ -107,6 +107,12 @@ in zipModules ([]
 ++ obsolete [ "services" "xserver" "startOpenSSHAgent" ] [ "programs" "ssh" "startAgent" ]
 ++ obsolete [ "services" "xserver" "windowManager" "xbmc" ] [ "services" "xserver" "desktopManager" "xbmc" ]
 
+# VirtualBox
+++ obsolete [ "services" "virtualbox" "enable" ] [ "services" "virtualboxGuest" "enable" ]
+
+# proxy
+++ obsolete [ "nix" "proxy" ] [ "networking" "proxy" "default" ]
+
 # KDE
 ++ deprecated [ "kde" "extraPackages" ] [ "environment" "kdePackages" ]
 # ++ obsolete [ "environment" "kdePackages" ] [ "environment" "systemPackages" ] # !!! doesn't work!
diff --git a/nixos/modules/security/ca.nix b/nixos/modules/security/ca.nix
index e17ad448f401..f430a5a6339f 100644
--- a/nixos/modules/security/ca.nix
+++ b/nixos/modules/security/ca.nix
@@ -16,6 +16,8 @@ with lib;
       { SSL_CERT_FILE          = "/etc/ssl/certs/ca-bundle.crt";
         # FIXME: unneeded - remove eventually.
         OPENSSL_X509_CERT_FILE = "/etc/ssl/certs/ca-bundle.crt";
+        # FIXME: unneeded - remove eventually.
+        GIT_SSL_CAINFO         = "/etc/ssl/certs/ca-bundle.crt";
       };
 
   };
diff --git a/nixos/modules/services/backup/almir.nix b/nixos/modules/services/backup/almir.nix
index 5ce215c5c4b5..ec39a997028a 100644
--- a/nixos/modules/services/backup/almir.nix
+++ b/nixos/modules/services/backup/almir.nix
@@ -109,6 +109,7 @@ in {
       };
 
       sqlalchemy_engine_url = mkOption {
+        default = "postgresql:///bacula";
         example = ''
           postgresql://bacula:bacula@localhost:5432/bacula
           mysql+mysqlconnector://<user>:<password>@<hostname>/<database>'
diff --git a/nixos/modules/services/misc/mesos-master.nix b/nixos/modules/services/misc/mesos-master.nix
index bdf88d427c5d..5609cf75bb5c 100644
--- a/nixos/modules/services/misc/mesos-master.nix
+++ b/nixos/modules/services/misc/mesos-master.nix
@@ -4,11 +4,11 @@ with lib;
 
 let
   cfg = config.services.mesos.master;
-  
+
 in {
 
   options.services.mesos = {
-    
+
     master = {
       enable = mkOption {
         description = "Whether to enable the Mesos Master.";
@@ -31,36 +31,36 @@ in {
         '';
         type = types.str;
       };
-      
+
       workDir = mkOption {
         description = "The Mesos work directory.";
         default = "/var/lib/mesos/master";
         type = types.str;
       };
-      
+
       extraCmdLineOptions = mkOption {
         description = ''
 	  Extra command line options for Mesos Master.
-	  
+
 	  See https://mesos.apache.org/documentation/latest/configuration/
 	'';
         default = [ "" ];
         type = types.listOf types.string;
         example = [ "--credentials=VALUE" ];
       };
-      
+
       quorum = mkOption {
         description = ''
           The size of the quorum of replicas when using 'replicated_log' based
           registry. It is imperative to set this value to be a majority of
           masters i.e., quorum > (number of masters)/2.
-          
+
           If 0 will fall back to --registry=in_memory.
         '';
         default = 0;
         type = types.int;
       };
-      
+
       logLevel = mkOption {
         description = ''
           The logging level used. Possible values:
@@ -86,11 +86,12 @@ in {
 	  ${pkgs.mesos}/bin/mesos-master \
 	    --port=${toString cfg.port} \
 	    --zk=${cfg.zk} \
-	    ${if cfg.quorum == 0 then "--registry=in_memory" else "--registry=replicated_log --quorum=${cfg.quorum}"} \
+	    ${if cfg.quorum == 0 then "--registry=in_memory" else "--registry=replicated_log --quorum=${toString cfg.quorum}"} \
 	    --work_dir=${cfg.workDir} \
 	    --logging_level=${cfg.logLevel} \
 	    ${toString cfg.extraCmdLineOptions}
 	'';
+	Restart = "on-failure";
 	PermissionsStartOnly = true;
       };
       preStart = ''
@@ -98,6 +99,6 @@ in {
       '';
     };
   };
-  
+
 }
 
diff --git a/nixos/modules/services/misc/nix-daemon.nix b/nixos/modules/services/misc/nix-daemon.nix
index 4b398979fbaa..d041c5664ef6 100644
--- a/nixos/modules/services/misc/nix-daemon.nix
+++ b/nixos/modules/services/misc/nix-daemon.nix
@@ -193,17 +193,6 @@ in
         '';
       };
 
-      proxy = mkOption {
-        type = types.str;
-        default = "";
-        description = ''
-          This option specifies the proxy to use for fetchurl. The real effect
-          is just exporting http_proxy, https_proxy and ftp_proxy with that
-          value.
-        '';
-        example = "http://127.0.0.1:3128";
-      };
-
       # Environment variables for running Nix.
       envVars = mkOption {
         type = types.attrs;
@@ -292,7 +281,9 @@ in
       { path = [ nix pkgs.openssl pkgs.utillinux pkgs.openssh ]
           ++ optionals cfg.distributedBuilds [ pkgs.gzip ];
 
-        environment = cfg.envVars // { CURL_CA_BUNDLE = "/etc/ssl/certs/ca-bundle.crt"; };
+        environment = cfg.envVars
+          // { CURL_CA_BUNDLE = "/etc/ssl/certs/ca-bundle.crt"; }
+          // config.networking.proxy.envVars;
 
         serviceConfig =
           { Nice = cfg.daemonNiceLevel;
@@ -317,13 +308,6 @@ in
         NIX_BUILD_HOOK = "${nix}/libexec/nix/build-remote.pl";
         NIX_REMOTE_SYSTEMS = "/etc/nix/machines";
         NIX_CURRENT_LOAD = "/run/nix/current-load";
-      }
-
-      # !!! These should not be defined here, but in some general proxy configuration module!
-      // optionalAttrs (cfg.proxy != "") {
-        http_proxy = cfg.proxy;
-        https_proxy = cfg.proxy;
-        ftp_proxy = cfg.proxy;
       };
 
     # Set up the environment variables for running Nix.
diff --git a/nixos/modules/services/networking/chrony.nix b/nixos/modules/services/networking/chrony.nix
index d1684dd9f05d..fe062b30e4b7 100644
--- a/nixos/modules/services/networking/chrony.nix
+++ b/nixos/modules/services/networking/chrony.nix
@@ -48,9 +48,10 @@ in
 
       servers = mkOption {
         default = [
-          "0.pool.ntp.org"
-          "1.pool.ntp.org"
-          "2.pool.ntp.org"
+          "0.nixos.pool.ntp.org"
+          "1.nixos.pool.ntp.org"
+          "2.nixos.pool.ntp.org"
+          "3.nixos.pool.ntp.org"
         ];
         description = ''
           The set of NTP servers from which to synchronise.
@@ -99,8 +100,8 @@ in
     jobs.chronyd =
       { description = "chrony daemon";
 
-        wantedBy = [ "ip-up.target" ];
-        partOf = [ "ip-up.target" ];
+        wantedBy = [ "multi-user.target" ];
+        after = [ "network.target" ];
 
         path = [ chrony ];
 
diff --git a/nixos/modules/services/networking/dhcpcd.nix b/nixos/modules/services/networking/dhcpcd.nix
index 15dbf80a987e..1ad8cbae15cf 100644
--- a/nixos/modules/services/networking/dhcpcd.nix
+++ b/nixos/modules/services/networking/dhcpcd.nix
@@ -8,15 +8,29 @@ let
 
   cfg = config.networking.dhcpcd;
 
+  interfaces = attrValues config.networking.interfaces;
+
+  enableDHCP = config.networking.useDHCP || any (i: i.useDHCP == true) interfaces;
+
   # Don't start dhcpcd on explicitly configured interfaces or on
   # interfaces that are part of a bridge, bond or sit device.
   ignoredInterfaces =
-    map (i: i.name) (filter (i: i.ip4 != [ ] || i.ipAddress != null) (attrValues config.networking.interfaces))
+    map (i: i.name) (filter (i: if i.useDHCP != null then !i.useDHCP else i.ip4 != [ ] || i.ipAddress != null) interfaces)
     ++ mapAttrsToList (i: _: i) config.networking.sits
     ++ concatLists (attrValues (mapAttrs (n: v: v.interfaces) config.networking.bridges))
     ++ concatLists (attrValues (mapAttrs (n: v: v.interfaces) config.networking.bonds))
     ++ config.networking.dhcpcd.denyInterfaces;
 
+  arrayAppendOrNull = a1: a2: if a1 == null && a2 == null then null
+    else if a1 == null then a2 else if a2 == null then a1
+      else a1 ++ a2;
+
+  # If dhcp is disabled but explicit interfaces are enabled,
+  # we need to provide dhcp just for those interfaces.
+  allowInterfaces = arrayAppendOrNull cfg.allowInterfaces
+    (if !config.networking.useDHCP && enableDHCP then
+      map (i: i.name) (filter (i: i.useDHCP == true) interfaces) else null);
+
   # Config file adapted from the one that ships with dhcpcd.
   dhcpcdConf = pkgs.writeText "dhcpcd.conf"
     ''
@@ -41,7 +55,7 @@ let
       denyinterfaces ${toString ignoredInterfaces} lo peth* vif* tap* tun* virbr* vnet* vboxnet* sit*
 
       # Use the list of allowed interfaces if specified
-      ${optionalString (cfg.allowInterfaces != null) "allowinterfaces ${toString cfg.allowInterfaces}"}
+      ${optionalString (allowInterfaces != null) "allowinterfaces ${toString allowInterfaces}"}
 
       ${cfg.extraConfig}
     '';
@@ -132,7 +146,7 @@ in
 
   ###### implementation
 
-  config = mkIf config.networking.useDHCP {
+  config = mkIf enableDHCP {
 
     systemd.services.dhcpcd =
       { description = "DHCP Client";
diff --git a/nixos/modules/services/networking/dnsmasq.nix b/nixos/modules/services/networking/dnsmasq.nix
index 5c68dd89fb12..fbb211911f1c 100644
--- a/nixos/modules/services/networking/dnsmasq.nix
+++ b/nixos/modules/services/networking/dnsmasq.nix
@@ -82,7 +82,7 @@ in
 
     systemd.services.dnsmasq = {
         description = "dnsmasq daemon";
-        after = [ "network.target" ];
+        after = [ "network.target" "systemd-resolved.conf" ];
         wantedBy = [ "multi-user.target" ];
         path = [ dnsmasq ];
         preStart = ''
diff --git a/nixos/modules/services/networking/firewall.nix b/nixos/modules/services/networking/firewall.nix
index 51e1679ce4de..b129727087aa 100644
--- a/nixos/modules/services/networking/firewall.nix
+++ b/nixos/modules/services/networking/firewall.nix
@@ -458,8 +458,9 @@ in
 
     systemd.services.firewall = {
       description = "Firewall";
-      wantedBy = [ "network.target" ];
-      after = [ "network-interfaces.target" "systemd-modules-load.service" ];
+      wantedBy = [ "network-pre.target" ];
+      before = [ "network-pre.target" ];
+      after = [ "systemd-modules-load.service" ];
 
       path = [ pkgs.iptables ];
 
diff --git a/nixos/modules/services/networking/gogoclient.nix b/nixos/modules/services/networking/gogoclient.nix
index 416007941976..9d16f0efb435 100644
--- a/nixos/modules/services/networking/gogoclient.nix
+++ b/nixos/modules/services/networking/gogoclient.nix
@@ -76,8 +76,7 @@ in
         exec ${pkgs.gogoclient}/bin/gogoc -y -f /var/lib/gogoc/gogoc.conf
       '';
     } // optionalAttrs cfg.autorun {
-      wantedBy = [ "ip-up.target" ];
-      partOf = [ "ip-up.target" ];
+      wantedBy = [ "multi-user.target" ];
     };
 
   };
diff --git a/nixos/modules/services/networking/networkmanager.nix b/nixos/modules/services/networking/networkmanager.nix
index 39e83e7b4272..37bc1df2361b 100644
--- a/nixos/modules/services/networking/networkmanager.nix
+++ b/nixos/modules/services/networking/networkmanager.nix
@@ -52,6 +52,7 @@ let
     #!/bin/sh
     if test "$2" = "up"; then
       ${config.systemd.package}/bin/systemctl start ip-up.target
+      ${config.systemd.package}/bin/systemctl start network-online.target
     fi
   '';
 
diff --git a/nixos/modules/services/networking/ntpd.nix b/nixos/modules/services/networking/ntpd.nix
index 2f638904406b..8f4bf26d411d 100644
--- a/nixos/modules/services/networking/ntpd.nix
+++ b/nixos/modules/services/networking/ntpd.nix
@@ -45,9 +45,10 @@ in
 
       servers = mkOption {
         default = [
-          "0.pool.ntp.org"
-          "1.pool.ntp.org"
-          "2.pool.ntp.org"
+          "0.nixos.pool.ntp.org"
+          "1.nixos.pool.ntp.org"
+          "2.nixos.pool.ntp.org"
+          "3.nixos.pool.ntp.org"
         ];
         description = ''
           The set of NTP servers from which to synchronise.
@@ -76,8 +77,7 @@ in
     jobs.ntpd =
       { description = "NTP Daemon";
 
-        wantedBy = [ "ip-up.target" ];
-        partOf = [ "ip-up.target" ];
+        wantedBy = [ "multi-user.target" ];
 
         path = [ ntp ];
 
diff --git a/nixos/modules/services/networking/openntpd.nix b/nixos/modules/services/networking/openntpd.nix
index bd8a7a04a2af..2f9031481d1d 100644
--- a/nixos/modules/services/networking/openntpd.nix
+++ b/nixos/modules/services/networking/openntpd.nix
@@ -41,8 +41,7 @@ in
 
     systemd.services.openntpd = {
       description = "OpenNTP Server";
-      wantedBy = [ "ip-up.target" ];
-      partOf = [ "ip-up.target" ];
+      wantedBy = [ "multi-user.target" ];
       serviceConfig.ExecStart = "${package}/sbin/ntpd -d -f ${cfgFile}";
     };
   };
diff --git a/nixos/modules/services/networking/ssh/sshd.nix b/nixos/modules/services/networking/ssh/sshd.nix
index fee1bace0460..4db8d1e25450 100644
--- a/nixos/modules/services/networking/ssh/sshd.nix
+++ b/nixos/modules/services/networking/ssh/sshd.nix
@@ -17,11 +17,13 @@ let
 
   knownHosts = map (h: getAttr h cfg.knownHosts) (attrNames cfg.knownHosts);
 
-  knownHostsFile = pkgs.writeText "ssh_known_hosts" (
-    flip concatMapStrings knownHosts (h: ''
-      ${concatStringsSep "," h.hostNames} ${if h.publicKey != null then h.publicKey else readFile h.publicKeyFile}
-    '')
-  );
+  knownHostsFile = pkgs.runCommand "ssh_known_hosts" {} ''
+    touch "$out"
+    ${flip concatMapStrings knownHosts (h: ''
+      pubkeyfile=${builtins.toFile "host.pub" (if h.publicKey == null then readFile h.publicKeyFile else h.publicKey)}
+      ${pkgs.gnused}/bin/sed 's/^/${concatStringsSep "," h.hostNames} /' $pubkeyfile >> "$out"
+    '')}
+  '';
 
   userOptions = {
 
@@ -254,7 +256,10 @@ in
             description = ''
               The public key data for the host. You can fetch a public key
               from a running SSH server with the <command>ssh-keyscan</command>
-              command.
+              command. The public key should not include any host names, only
+              the key type and the key itself. It is allowed to add several
+              lines here, each line will be treated as type/key pair and the
+              host names will be prepended to each line.
             '';
           };
           publicKeyFile = mkOption {
@@ -264,7 +269,9 @@ in
               The path to the public key file for the host. The public
               key file is read at build time and saved in the Nix store.
               You can fetch a public key file from a running SSH server
-              with the <command>ssh-keyscan</command> command.
+              with the <command>ssh-keyscan</command> command. The content
+              of the file should follow the same format as described for
+              the <literal>publicKey</literal> option.
             '';
           };
         };
diff --git a/nixos/modules/services/printing/cupsd.nix b/nixos/modules/services/printing/cupsd.nix
index 9c289f685124..226677394943 100644
--- a/nixos/modules/services/printing/cupsd.nix
+++ b/nixos/modules/services/printing/cupsd.nix
@@ -90,6 +90,20 @@ in
         '';
       };
 
+      extraConf = mkOption {
+        type = types.lines;
+        default = "";
+        example =
+          ''
+            BrowsePoll cups.example.com
+            LogLevel debug
+          '';
+        description = ''
+          Extra contents of the configuration file of the CUPS daemon
+          (<filename>cupsd.conf</filename>).
+        '';
+      };
+
       clientConf = mkOption {
         type = types.lines;
         default = "";
@@ -258,6 +272,7 @@ in
             Order deny,allow
           </Limit>
         </Policy>
+        ${cfg.extraConf}
       '';
 
     security.pam.services.cups = {};
diff --git a/nixos/modules/services/torrent/peerflix.nix b/nixos/modules/services/torrent/peerflix.nix
new file mode 100644
index 000000000000..e9f5439ffa39
--- /dev/null
+++ b/nixos/modules/services/torrent/peerflix.nix
@@ -0,0 +1,63 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.peerflix;
+
+  configFile = pkgs.writeText "peerflix-config.json" ''
+    {
+      "connections": 50,
+      "tmp": "${cfg.downloadDir}"
+    }
+  '';
+
+in {
+
+  ###### interface
+
+  options.services.peerflix = {
+    enable = mkOption {
+      description = "Whether to enable graphite web frontend.";
+      default = false;
+      type = types.uniq types.bool;
+    };
+
+    stateDir = mkOption {
+      description = "Peerflix state directory.";
+      default = "/var/lib/peerflix";
+      type = types.path;
+    };
+
+    downloadDir = mkOption {
+      description = "Peerflix temporary download directory.";
+      default = "${cfg.stateDir}/torrents";
+      type = types.path;
+    };
+  };
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+    systemd.services.peerflix = {
+      description = "Peerflix Daemon";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network-interfaces.target" ];
+      environment.HOME = cfg.stateDir;
+
+      preStart = ''
+        mkdir -p "${cfg.stateDir}"/{torrents,.config/peerflix-server}
+        if [ "$(id -u)" = 0 ]; then chown -R peerflix "${cfg.stateDir}"; fi
+        ln -fs "${configFile}" "${cfg.stateDir}/.config/peerflix-server/config.json"
+      '';
+
+      serviceConfig = {
+        ExecStart = "${pkgs.nodePackages.peerflix-server}/bin/peerflix-server";
+        PermissionsStartOnly = true;
+        User = "peerflix";
+      };
+    };
+
+    users.extraUsers.peerflix.uid = config.ids.uids.peerflix;
+  };
+}
diff --git a/nixos/modules/system/boot/stage-2-init.sh b/nixos/modules/system/boot/stage-2-init.sh
index 6fff776f8581..3762bda94a5c 100644
--- a/nixos/modules/system/boot/stage-2-init.sh
+++ b/nixos/modules/system/boot/stage-2-init.sh
@@ -141,8 +141,6 @@ fi
 # Use /etc/resolv.conf supplied by systemd-nspawn, if applicable.
 if [ -n "@useHostResolvConf@" -a -e /etc/resolv.conf ]; then
     cat /etc/resolv.conf | resolvconf -m 1000 -a host
-else
-    touch /etc/resolv.conf
 fi
 
 
diff --git a/nixos/modules/system/boot/systemd-unit-options.nix b/nixos/modules/system/boot/systemd-unit-options.nix
index 07f3cb9e952c..20851c626d75 100644
--- a/nixos/modules/system/boot/systemd-unit-options.nix
+++ b/nixos/modules/system/boot/systemd-unit-options.nix
@@ -4,15 +4,184 @@ with lib;
 
 let
 
-  checkService = v:
-    let assertValueOneOf = name: values: attr:
-          let val = attr.${name};
-          in optional (attr ? ${name} && !elem val values) "Systemd service field `${name}' cannot have value `${val}'.";
-        checkType = assertValueOneOf "Type" ["simple" "forking" "oneshot" "dbus" "notify" "idle"];
-        checkRestart = assertValueOneOf "Restart" ["no" "on-success" "on-failure" "on-abort" "always"];
-        errors = concatMap (c: c v) [checkType checkRestart];
-    in if errors == [] then true
-       else builtins.trace (concatStringsSep "\n" errors) false;
+  boolValues = [true false "yes" "no"];
+
+  assertValueOneOf = name: values: group: attr:
+    optional (attr ? ${name} && !elem attr.${name} values)
+      "Systemd ${group} field `${name}' cannot have value `${attr.${name}}'.";
+
+  assertHasField = name: group: attr:
+    optional (!(attr ? ${name}))
+      "Systemd ${group} field `${name}' must exist.";
+
+  assertOnlyFields = fields: group: attr:
+    let badFields = filter (name: ! elem name fields) (attrNames attr); in
+    optional (badFields != [ ])
+      "Systemd ${group} has extra fields [${concatStringsSep " " badFields}].";
+
+  assertRange = name: min: max: group: attr:
+    optional (attr ? ${name} && !(min <= attr.${name} && max >= attr.${name}))
+      "Systemd ${group} field `${name}' is outside the range [${toString min},${toString max}]";
+
+  digits = map toString (range 0 9);
+
+  isByteFormat = s:
+    let
+      l = reverseList (stringToCharacters s);
+      suffix = head l;
+      nums = tail l;
+    in elem suffix (["K" "M" "G" "T"] ++ digits)
+      && all (num: elem num digits) nums;
+
+  assertByteFormat = name: group: attr:
+    optional (attr ? ${name} && ! isByteFormat attr.${name})
+      "Systemd ${group} field `${name}' must be in byte format [0-9]+[KMGT].";
+
+  hexChars = stringToCharacters "0123456789abcdefABCDEF";
+
+  isMacAddress = s: stringLength s == 17
+    && flip all (splitString ":" s) (bytes:
+      all (byte: elem byte hexChars) (stringToCharacters bytes)
+    );
+
+  assertMacAddress = name: group: attr:
+    optional (attr ? ${name} && ! isMacAddress attr.${name})
+      "Systemd ${group} field `${name}' must be a valid mac address.";
+
+  checkUnitConfig = group: checks: v:
+    let errors = concatMap (c: c group v) checks; in
+    if errors == [] then true
+      else builtins.trace (concatStringsSep "\n" errors) false;
+
+  checkService = checkUnitConfig "Service" [
+    (assertValueOneOf "Type" [
+      "simple" "forking" "oneshot" "dbus" "notify" "idle"
+    ])
+    (assertValueOneOf "Restart" [
+      "no" "on-success" "on-failure" "on-abort" "always"
+    ])
+  ];
+
+  checkLink = checkUnitConfig "Link" [
+    (assertOnlyFields [
+      "Description" "Alias" "MACAddressPolicy" "MACAddress" "NamePolicy" "Name"
+      "MTUBytes" "BitsPerSecond" "Duplex" "WakeOnLan"
+    ])
+    (assertValueOneOf "MACAddressPolicy" ["persistent" "random"])
+    (assertMacAddress "MACAddress")
+    (assertValueOneOf "NamePolicy" [
+      "kernel" "database" "onboard" "slot" "path" "mac"
+    ])
+    (assertByteFormat "MTUBytes")
+    (assertByteFormat "BitsPerSecond")
+    (assertValueOneOf "Duplex" ["half" "full"])
+    (assertValueOneOf "WakeOnLan" ["phy" "magic" "off"])
+  ];
+
+  checkNetdev = checkUnitConfig "Netdev" [
+    (assertOnlyFields [
+      "Description" "Name" "Kind" "MTUBytes" "MACAddress"
+    ])
+    (assertHasField "Name")
+    (assertHasField "Kind")
+    (assertValueOneOf "Kind" [
+      "bridge" "bond" "vlan" "macvlan" "vxlan" "ipip"
+      "gre" "sit" "vti" "veth" "tun" "tap" "dummy"
+    ])
+    (assertByteFormat "MTUBytes")
+    (assertMacAddress "MACAddress")
+  ];
+
+  checkVlan = checkUnitConfig "VLAN" [
+    (assertOnlyFields ["Id"])
+    (assertRange "Id" 0 4094)
+  ];
+
+  checkMacvlan = checkUnitConfig "MACVLAN" [
+    (assertOnlyFields ["Mode"])
+    (assertValueOneOf "Mode" ["private" "vepa" "bridge" "passthru"])
+  ];
+
+  checkVxlan = checkUnitConfig "VXLAN" [
+    (assertOnlyFields ["Id" "Group" "TOS" "TTL" "MacLearning"])
+    (assertRange "TTL" 0 255)
+    (assertValueOneOf "MacLearning" boolValues)
+  ];
+
+  checkTunnel = checkUnitConfig "Tunnel" [
+    (assertOnlyFields ["Local" "Remote" "TOS" "TTL" "DiscoverPathMTU"])
+    (assertRange "TTL" 0 255)
+    (assertValueOneOf "DiscoverPathMTU" boolValues)
+  ];
+
+  checkPeer = checkUnitConfig "Peer" [
+    (assertOnlyFields ["Name" "MACAddress"])
+    (assertMacAddress "MACAddress")
+  ];
+
+  tunTapChecks = [
+    (assertOnlyFields ["OneQueue" "MultiQueue" "PacketInfo" "User" "Group"])
+    (assertValueOneOf "OneQueue" boolValues)
+    (assertValueOneOf "MultiQueue" boolValues)
+    (assertValueOneOf "PacketInfo" boolValues)
+  ];
+
+  checkTun = checkUnitConfig "Tun" tunTapChecks;
+
+  checkTap = checkUnitConfig "Tap" tunTapChecks;
+
+  checkBond = checkUnitConfig "Bond" [
+    (assertOnlyFields [
+      "Mode" "TransmitHashPolicy" "LACPTransmitRate" "MIIMonitorSec"
+      "UpDelaySec" "DownDelaySec"
+    ])
+    (assertValueOneOf "Mode" [
+      "balance-rr" "active-backup" "balance-xor"
+      "broadcast" "802.3ad" "balance-tlb" "balance-alb"
+    ])
+    (assertValueOneOf "TransmitHashPolicy" [
+      "layer2" "layer3+4" "layer2+3" "encap2+3" "802.3ad" "encap3+4"
+    ])
+    (assertValueOneOf "LACPTransmitRate" ["slow" "fast"])
+  ];
+
+  checkNetwork = checkUnitConfig "Network" [
+    (assertOnlyFields [
+      "Description" "DHCP" "DHCPServer" "IPv4LL" "IPv4LLRoute"
+      "LLMNR" "Domains" "Bridge" "Bond"
+    ])
+    (assertValueOneOf "DHCP" ["both" "none" "v4" "v6"])
+    (assertValueOneOf "DHCPServer" boolValues)
+    (assertValueOneOf "IPv4LL" boolValues)
+    (assertValueOneOf "IPv4LLRoute" boolValues)
+    (assertValueOneOf "LLMNR" boolValues)
+  ];
+
+  checkAddress = checkUnitConfig "Address" [
+    (assertOnlyFields ["Address" "Peer" "Broadcast" "Label"])
+    (assertHasField "Address")
+  ];
+
+  checkRoute = checkUnitConfig "Route" [
+    (assertOnlyFields ["Gateway" "Destination" "Metric"])
+    (assertHasField "Gateway")
+  ];
+
+  checkDhcp = checkUnitConfig "DHCP" [
+    (assertOnlyFields [
+      "UseDNS" "UseMTU" "SendHostname" "UseHostname" "UseDomains" "UseRoutes"
+      "CriticalConnections" "VendorClassIdentifier" "RequestBroadcast"
+      "RouteMetric"
+    ])
+    (assertValueOneOf "UseDNS" boolValues)
+    (assertValueOneOf "UseMTU" boolValues)
+    (assertValueOneOf "SendHostname" boolValues)
+    (assertValueOneOf "UseHostname" boolValues)
+    (assertValueOneOf "UseDomains" boolValues)
+    (assertValueOneOf "UseRoutes" boolValues)
+    (assertValueOneOf "CriticalConnections" boolValues)
+    (assertValueOneOf "RequestBroadcast" boolValues)
+  ];
 
   unitOption = mkOptionType {
     name = "systemd option";
@@ -140,6 +309,15 @@ in rec {
       '';
     };
 
+    requisite = mkOption {
+      default = [];
+      type = types.listOf types.str;
+      description = ''
+        Similar to requires. However if the units listed are not started,
+        they will not be started and the transaction will fail.
+      '';
+    };
+
     unitConfig = mkOption {
       default = {};
       example = { RequiresMountsFor = "/data"; };
@@ -441,4 +619,345 @@ in rec {
 
   targetOptions = commonUnitOptions;
 
+  commonNetworkOptions = {
+
+    enable = mkOption {
+      default = true;
+      type = types.bool;
+      description = ''
+        If set to false, this unit will be a symlink to
+        /dev/null.
+      '';
+    };
+
+    matchConfig = mkOption {
+      default = {};
+      example = { Name = "eth0"; };
+      type = types.attrsOf unitOption;
+      description = ''
+        Each attribute in this set specifies an option in the
+        <literal>[Match]</literal> section of the unit.  See
+        <citerefentry><refentrytitle>systemd.link</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+        <citerefentry><refentrytitle>systemd.netdev</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+        <citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+        for details.
+      '';
+    };
+
+  };
+
+  linkOptions = commonNetworkOptions // {
+
+    linkConfig = mkOption {
+      default = {};
+      example = { MACAddress = "00:ff:ee:aa:cc:dd"; };
+      type = types.addCheck (types.attrsOf unitOption) checkLink;
+      description = ''
+        Each attribute in this set specifies an option in the
+        <literal>[Link]</literal> section of the unit.  See
+        <citerefentry><refentrytitle>systemd.link</refentrytitle>
+        <manvolnum>5</manvolnum></citerefentry> for details.
+      '';
+    };
+
+  };
+
+  netdevOptions = commonNetworkOptions // {
+
+    netdevConfig = mkOption {
+      default = {};
+      example = { Name = "mybridge"; Kind = "bridge"; };
+      type = types.addCheck (types.attrsOf unitOption) checkNetdev;
+      description = ''
+        Each attribute in this set specifies an option in the
+        <literal>[Netdev]</literal> section of the unit.  See
+        <citerefentry><refentrytitle>systemd.netdev</refentrytitle>
+        <manvolnum>5</manvolnum></citerefentry> for details.
+      '';
+    };
+
+    vlanConfig = mkOption {
+      default = {};
+      example = { Id = "4"; };
+      type = types.addCheck (types.attrsOf unitOption) checkVlan;
+      description = ''
+        Each attribute in this set specifies an option in the
+        <literal>[VLAN]</literal> section of the unit.  See
+        <citerefentry><refentrytitle>systemd.netdev</refentrytitle>
+        <manvolnum>5</manvolnum></citerefentry> for details.
+      '';
+    };
+
+    macvlanConfig = mkOption {
+      default = {};
+      example = { Mode = "private"; };
+      type = types.addCheck (types.attrsOf unitOption) checkMacvlan;
+      description = ''
+        Each attribute in this set specifies an option in the
+        <literal>[MACVLAN]</literal> section of the unit.  See
+        <citerefentry><refentrytitle>systemd.netdev</refentrytitle>
+        <manvolnum>5</manvolnum></citerefentry> for details.
+      '';
+    };
+
+    vxlanConfig = mkOption {
+      default = {};
+      example = { Id = "4"; };
+      type = types.addCheck (types.attrsOf unitOption) checkVxlan;
+      description = ''
+        Each attribute in this set specifies an option in the
+        <literal>[VXLAN]</literal> section of the unit.  See
+        <citerefentry><refentrytitle>systemd.netdev</refentrytitle>
+        <manvolnum>5</manvolnum></citerefentry> for details.
+      '';
+    };
+
+    tunnelConfig = mkOption {
+      default = {};
+      example = { Remote = "192.168.1.1"; };
+      type = types.addCheck (types.attrsOf unitOption) checkTunnel;
+      description = ''
+        Each attribute in this set specifies an option in the
+        <literal>[Tunnel]</literal> section of the unit.  See
+        <citerefentry><refentrytitle>systemd.netdev</refentrytitle>
+        <manvolnum>5</manvolnum></citerefentry> for details.
+      '';
+    };
+
+    peerConfig = mkOption {
+      default = {};
+      example = { Name = "veth2"; };
+      type = types.addCheck (types.attrsOf unitOption) checkPeer;
+      description = ''
+        Each attribute in this set specifies an option in the
+        <literal>[Peer]</literal> section of the unit.  See
+        <citerefentry><refentrytitle>systemd.netdev</refentrytitle>
+        <manvolnum>5</manvolnum></citerefentry> for details.
+      '';
+    };
+
+    tunConfig = mkOption {
+      default = {};
+      example = { User = "openvpn"; };
+      type = types.addCheck (types.attrsOf unitOption) checkTun;
+      description = ''
+        Each attribute in this set specifies an option in the
+        <literal>[Tun]</literal> section of the unit.  See
+        <citerefentry><refentrytitle>systemd.netdev</refentrytitle>
+        <manvolnum>5</manvolnum></citerefentry> for details.
+      '';
+    };
+
+    tapConfig = mkOption {
+      default = {};
+      example = { User = "openvpn"; };
+      type = types.addCheck (types.attrsOf unitOption) checkTap;
+      description = ''
+        Each attribute in this set specifies an option in the
+        <literal>[Tap]</literal> section of the unit.  See
+        <citerefentry><refentrytitle>systemd.netdev</refentrytitle>
+        <manvolnum>5</manvolnum></citerefentry> for details.
+      '';
+    };
+
+    bondConfig = mkOption {
+      default = {};
+      example = { Mode = "802.3ad"; };
+      type = types.addCheck (types.attrsOf unitOption) checkBond;
+      description = ''
+        Each attribute in this set specifies an option in the
+        <literal>[Bond]</literal> section of the unit.  See
+        <citerefentry><refentrytitle>systemd.netdev</refentrytitle>
+        <manvolnum>5</manvolnum></citerefentry> for details.
+      '';
+    };
+
+  };
+
+  addressOptions = {
+
+    addressConfig = mkOption {
+      default = {};
+      example = { Address = "192.168.0.100/24"; };
+      type = types.addCheck (types.attrsOf unitOption) checkAddress;
+      description = ''
+        Each attribute in this set specifies an option in the
+        <literal>[Address]</literal> section of the unit.  See
+        <citerefentry><refentrytitle>systemd.network</refentrytitle>
+        <manvolnum>5</manvolnum></citerefentry> for details.
+      '';
+    };
+
+  };
+
+  routeOptions = {
+
+    routeConfig = mkOption {
+      default = {};
+      example = { Gateway = "192.168.0.1"; };
+      type = types.addCheck (types.attrsOf unitOption) checkRoute;
+      description = ''
+        Each attribute in this set specifies an option in the
+        <literal>[Route]</literal> section of the unit.  See
+        <citerefentry><refentrytitle>systemd.network</refentrytitle>
+        <manvolnum>5</manvolnum></citerefentry> for details.
+      '';
+    };
+
+  };
+
+  networkOptions = commonNetworkOptions // {
+
+    networkConfig = mkOption {
+      default = {};
+      example = { Description = "My Network"; };
+      type = types.addCheck (types.attrsOf unitOption) checkNetwork;
+      description = ''
+        Each attribute in this set specifies an option in the
+        <literal>[Network]</literal> section of the unit.  See
+        <citerefentry><refentrytitle>systemd.network</refentrytitle>
+        <manvolnum>5</manvolnum></citerefentry> for details.
+      '';
+    };
+
+    dhcpConfig = mkOption {
+      default = {};
+      example = { UseDNS = true; UseRoutes = true; };
+      type = types.addCheck (types.attrsOf unitOption) checkDhcp;
+      description = ''
+        Each attribute in this set specifies an option in the
+        <literal>[DHCP]</literal> section of the unit.  See
+        <citerefentry><refentrytitle>systemd.network</refentrytitle>
+        <manvolnum>5</manvolnum></citerefentry> for details.
+      '';
+    };
+
+    name = mkOption {
+      type = types.nullOr types.str;
+      default = null;
+      description = ''
+        The name of the network interface to match against.
+      '';
+    };
+
+    DHCP = mkOption {
+      type = types.nullOr types.str;
+      default = null;
+      description = ''
+        Whether to enable DHCP on the interfaces matched.
+      '';
+    };
+
+    domains = mkOption {
+      type = types.nullOr (types.listOf types.str);
+      default = null;
+      description = ''
+        A list of domains to pass to the network config.
+      '';
+    };
+
+    address = mkOption {
+      default = [ ];
+      type = types.listOf types.str;
+      description = ''
+        A list of addresses to be added to the network section of the
+        unit.  See <citerefentry><refentrytitle>systemd.network</refentrytitle>
+        <manvolnum>5</manvolnum></citerefentry> for details.
+      '';
+    };
+
+    gateway = mkOption {
+      default = [ ];
+      type = types.listOf types.str;
+      description = ''
+        A list of gateways to be added to the network section of the
+        unit.  See <citerefentry><refentrytitle>systemd.network</refentrytitle>
+        <manvolnum>5</manvolnum></citerefentry> for details.
+      '';
+    };
+
+    dns = mkOption {
+      default = [ ];
+      type = types.listOf types.str;
+      description = ''
+        A list of dns servers to be added to the network section of the
+        unit.  See <citerefentry><refentrytitle>systemd.network</refentrytitle>
+        <manvolnum>5</manvolnum></citerefentry> for details.
+      '';
+    };
+
+    ntp = mkOption {
+      default = [ ];
+      type = types.listOf types.str;
+      description = ''
+        A list of ntp servers to be added to the network section of the
+        unit.  See <citerefentry><refentrytitle>systemd.network</refentrytitle>
+        <manvolnum>5</manvolnum></citerefentry> for details.
+      '';
+    };
+
+    vlan = mkOption {
+      default = [ ];
+      type = types.listOf types.str;
+      description = ''
+        A list of vlan interfaces to be added to the network section of the
+        unit.  See <citerefentry><refentrytitle>systemd.network</refentrytitle>
+        <manvolnum>5</manvolnum></citerefentry> for details.
+      '';
+    };
+
+    macvlan = mkOption {
+      default = [ ];
+      type = types.listOf types.str;
+      description = ''
+        A list of macvlan interfaces to be added to the network section of the
+        unit.  See <citerefentry><refentrytitle>systemd.network</refentrytitle>
+        <manvolnum>5</manvolnum></citerefentry> for details.
+      '';
+    };
+
+    vxlan = mkOption {
+      default = [ ];
+      type = types.listOf types.str;
+      description = ''
+        A list of vxlan interfaces to be added to the network section of the
+        unit.  See <citerefentry><refentrytitle>systemd.network</refentrytitle>
+        <manvolnum>5</manvolnum></citerefentry> for details.
+      '';
+    };
+
+    tunnel = mkOption {
+      default = [ ];
+      type = types.listOf types.str;
+      description = ''
+        A list of tunnel interfaces to be added to the network section of the
+        unit.  See <citerefentry><refentrytitle>systemd.network</refentrytitle>
+        <manvolnum>5</manvolnum></citerefentry> for details.
+      '';
+    };
+
+    addresses = mkOption {
+      default = [ ];
+      type = types.listOf types.optionSet;
+      options = [ addressOptions ];
+      description = ''
+        A list of address sections to be added to the unit.  See
+        <citerefentry><refentrytitle>systemd.network</refentrytitle>
+        <manvolnum>5</manvolnum></citerefentry> for details.
+      '';
+    };
+
+    routes = mkOption {
+      default = [ ];
+      type = types.listOf types.optionSet;
+      options = [ routeOptions ];
+      description = ''
+        A list of route sections to be added to the unit.  See
+        <citerefentry><refentrytitle>systemd.network</refentrytitle>
+        <manvolnum>5</manvolnum></citerefentry> for details.
+      '';
+    };
+
+  };
+
 }
diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix
index 8a86149a9e12..78fe8c49fb05 100644
--- a/nixos/modules/system/boot/systemd.nix
+++ b/nixos/modules/system/boot/systemd.nix
@@ -36,6 +36,7 @@ let
       "graphical.target"
       "multi-user.target"
       "network.target"
+      "network-pre.target"
       "network-online.target"
       "nss-lookup.target"
       "nss-user-lookup.target"
@@ -96,6 +97,12 @@ let
       "systemd-modules-load.service"
       "kmod-static-nodes.service"
 
+      # Networking
+      "systemd-networkd.service"
+      "systemd-networkd-wait-online.service"
+      "systemd-resolved.service"
+      "systemd-timesyncd.service"
+
       # Filesystems.
       "systemd-fsck@.service"
       "systemd-fsck-root.service"
@@ -212,6 +219,8 @@ let
           { PartOf = toString config.partOf; }
         // optionalAttrs (config.conflicts != [])
           { Conflicts = toString config.conflicts; }
+        // optionalAttrs (config.requisite != [])
+          { Requisite = toString config.requisite; }
         // optionalAttrs (config.restartTriggers != [])
           { X-Restart-Triggers = toString config.restartTriggers; }
         // optionalAttrs (config.description != "") {
@@ -292,6 +301,19 @@ let
     };
   };
 
+  networkConfig = { name, config, ... }: {
+    config = {
+      matchConfig = optionalAttrs (config.name != null) {
+        Name = config.name;
+      };
+      networkConfig = optionalAttrs (config.DHCP != null) {
+        DHCP = config.DHCP;
+      } // optionalAttrs (config.domains != null) {
+        Domains = concatStringsSep " " config.domains;
+      };
+    };
+  };
+
   toOption = x:
     if x == true then "true"
     else if x == false then "false"
@@ -384,6 +406,103 @@ let
         '';
     };
 
+  commonMatchText = def: ''
+      [Match]
+      ${attrsToSection def.matchConfig}
+    '';
+
+  linkToUnit = name: def:
+    { inherit (def) enable;
+      text = commonMatchText def +
+        ''
+          [Link]
+          ${attrsToSection def.linkConfig}
+        '';
+    };
+
+  netdevToUnit = name: def:
+    { inherit (def) enable;
+      text = commonMatchText def +
+        ''
+          [NetDev]
+          ${attrsToSection def.netdevConfig}
+
+          ${optionalString (def.vlanConfig != { }) ''
+            [VLAN]
+            ${attrsToSection def.vlanConfig}
+
+          ''}
+          ${optionalString (def.macvlanConfig != { }) ''
+            [MACVLAN]
+            ${attrsToSection def.macvlanConfig}
+
+          ''}
+          ${optionalString (def.vxlanConfig != { }) ''
+            [VXLAN]
+            ${attrsToSection def.vxlanConfig}
+
+          ''}
+          ${optionalString (def.tunnelConfig != { }) ''
+            [Tunnel]
+            ${attrsToSection def.tunnelConfig}
+
+          ''}
+          ${optionalString (def.peerConfig != { }) ''
+            [Peer]
+            ${attrsToSection def.peerConfig}
+
+          ''}
+          ${optionalString (def.tunConfig != { }) ''
+            [Tun]
+            ${attrsToSection def.tunConfig}
+
+          ''}
+          ${optionalString (def.tapConfig != { }) ''
+            [Tap]
+            ${attrsToSection def.tapConfig}
+
+          ''}
+          ${optionalString (def.bondConfig != { }) ''
+            [Bond]
+            ${attrsToSection def.bondConfig}
+
+          ''}
+        '';
+    };
+
+  networkToUnit = name: def:
+    { inherit (def) enable;
+      text = commonMatchText def +
+        ''
+          [Network]
+          ${attrsToSection def.networkConfig}
+          ${concatStringsSep "\n" (map (s: "Address=${s}") def.address)}
+          ${concatStringsSep "\n" (map (s: "Gateway=${s}") def.gateway)}
+          ${concatStringsSep "\n" (map (s: "DNS=${s}") def.dns)}
+          ${concatStringsSep "\n" (map (s: "NTP=${s}") def.ntp)}
+          ${concatStringsSep "\n" (map (s: "VLAN=${s}") def.vlan)}
+          ${concatStringsSep "\n" (map (s: "MACVLAN=${s}") def.macvlan)}
+          ${concatStringsSep "\n" (map (s: "VXLAN=${s}") def.vxlan)}
+          ${concatStringsSep "\n" (map (s: "Tunnel=${s}") def.tunnel)}
+
+          ${optionalString (def.dhcpConfig != { }) ''
+            [DHCP]
+            ${attrsToSection def.dhcpConfig}
+
+          ''}
+          ${flip concatMapStrings def.addresses (x: ''
+            [Address]
+            ${attrsToSection x.addressConfig}
+
+          '')}
+          ${flip concatMapStrings def.routes (x: ''
+            [Route]
+            ${attrsToSection x.routeConfig}
+
+          '')}
+        '';
+    };
+
   generateUnits = type: units: upstreamUnits: upstreamWants:
     pkgs.runCommand "${type}-units" { preferLocalBuild = true; } ''
       mkdir -p $out
@@ -468,8 +587,9 @@ let
         mkdir -p $out/getty.target.wants/
         ln -s ../autovt@tty1.service $out/getty.target.wants/
 
-        ln -s ../local-fs.target ../remote-fs.target ../network.target ../nss-lookup.target \
-              ../nss-user-lookup.target ../swap.target $out/multi-user.target.wants/
+        ln -s ../local-fs.target ../remote-fs.target ../network.target \
+        ../nss-lookup.target ../nss-user-lookup.target ../swap.target \
+        $out/multi-user.target.wants/
       ''}
     ''; # */
 
@@ -562,6 +682,47 @@ in
       '';
     };
 
+    systemd.network.enable = mkOption {
+      default = false;
+      type = types.bool;
+      description = ''
+        Whether to enable networkd or not.
+      '';
+    };
+
+    systemd.network.links = mkOption {
+      default = {};
+      type = types.attrsOf types.optionSet;
+      options = [ linkOptions ];
+      description = "Definiton of systemd network links.";
+    };
+
+    systemd.network.netdevs = mkOption {
+      default = {};
+      type = types.attrsOf types.optionSet;
+      options = [ netdevOptions ];
+      description = "Definiton of systemd network devices.";
+    };
+
+    systemd.network.networks = mkOption {
+      default = {};
+      type = types.attrsOf types.optionSet;
+      options = [ networkOptions networkConfig ];
+      description = "Definiton of systemd networks.";
+    };
+
+    systemd.network.units = mkOption {
+      description = "Definition of networkd units.";
+      default = {};
+      type = types.attrsOf types.optionSet;
+      options = { name, config, ... }:
+        { options = concreteUnitOptions;
+          config = {
+            unit = mkDefault (makeUnit name config);
+          };
+        };
+    };
+
     systemd.defaultUnit = mkOption {
       default = "multi-user.target";
       type = types.str;
@@ -645,6 +806,22 @@ in
       '';
     };
 
+    services.resolved.enable = mkOption {
+      default = false;
+      type = types.bool;
+      description = ''
+        Enables the systemd dns resolver daemon.
+      '';
+    };
+
+    services.timesyncd.enable = mkOption {
+      default = false;
+      type = types.bool;
+      description = ''
+        Enables the systemd ntp client daemon.
+      '';
+    };
+
     systemd.tmpfiles.rules = mkOption {
       type = types.listOf types.str;
       default = [];
@@ -701,7 +878,7 @@ in
 
   ###### implementation
 
-  config = {
+  config = mkMerge [ {
 
     warnings = concatLists (mapAttrsToList (name: service:
       optional (service.serviceConfig.Type or "" == "oneshot" && service.serviceConfig.Restart or "no" != "no")
@@ -714,6 +891,9 @@ in
     environment.etc."systemd/system".source =
       generateUnits "system" cfg.units upstreamSystemUnits upstreamSystemWants;
 
+    environment.etc."systemd/network".source =
+      generateUnits "network" cfg.network.units [] [];
+
     environment.etc."systemd/user".source =
       generateUnits "user" cfg.user.units upstreamUserUnits [];
 
@@ -766,6 +946,18 @@ in
         unitConfig.X-StopOnReconfiguration = true;
       };
 
+    systemd.targets.network-online.after = [ "ip-up.target" ];
+
+    systemd.targets.network-pre = {
+      wantedBy = [ "network.target" ];
+      before = [ "network.target" ];
+    };
+
+    systemd.targets.remote-fs-pre = {
+      wantedBy = [ "remote-fs.target" ];
+      before = [ "remote-fs.target" ];
+    };
+
     systemd.units =
       mapAttrs' (n: v: nameValuePair "${n}.target" (targetToUnit n v)) cfg.targets
       // mapAttrs' (n: v: nameValuePair "${n}.service" (serviceToUnit n v)) cfg.services
@@ -779,6 +971,11 @@ in
                    (v: let n = escapeSystemdPath v.where;
                        in nameValuePair "${n}.automount" (automountToUnit n v)) cfg.automounts);
 
+    systemd.network.units =
+      mapAttrs' (n: v: nameValuePair "${n}.link" (linkToUnit n v)) cfg.network.links
+      // mapAttrs' (n: v: nameValuePair "${n}.netdev" (netdevToUnit n v)) cfg.network.netdevs
+      // mapAttrs' (n: v: nameValuePair "${n}.network" (networkToUnit n v)) cfg.network.networks;
+
     systemd.user.units =
       mapAttrs' (n: v: nameValuePair "${n}.service" (serviceToUnit n v)) cfg.user.services
       // mapAttrs' (n: v: nameValuePair "${n}.socket" (socketToUnit n v)) cfg.user.sockets;
@@ -800,6 +997,15 @@ in
     users.extraUsers.systemd-journal-gateway.uid = config.ids.uids.systemd-journal-gateway;
     users.extraGroups.systemd-journal-gateway.gid = config.ids.gids.systemd-journal-gateway;
 
+    users.extraUsers.systemd-network.uid = config.ids.uids.systemd-network;
+    users.extraGroups.systemd-network.gid = config.ids.gids.systemd-network;
+
+    users.extraUsers.systemd-resolve.uid = config.ids.uids.systemd-resolve;
+    users.extraGroups.systemd-resolve.gid = config.ids.gids.systemd-resolve;
+
+    users.extraUsers.systemd-timesync.uid = config.ids.uids.systemd-timesync;
+    users.extraGroups.systemd-timesync.gid = config.ids.gids.systemd-timesync;
+
     # Generate timer units for all services that have a ‘startAt’ value.
     systemd.timers =
       mapAttrs (name: service:
@@ -833,5 +1039,57 @@ in
     systemd.services.systemd-remount-fs.restartIfChanged = false;
     systemd.services.systemd-journal-flush.restartIfChanged = false;
 
-  };
+  }
+  (mkIf config.systemd.network.enable {
+    systemd.services.systemd-networkd = {
+      wantedBy = [ "multi-user.target" ];
+      before = [ "network-interfaces.target" ];
+      restartTriggers = [ config.environment.etc."systemd/network".source ];
+    };
+
+    systemd.services.systemd-networkd-wait-online = {
+      before = [ "network-online.target" "ip-up.target" ];
+      wantedBy = [ "network-online.target" "ip-up.target" ];
+    };
+
+    systemd.services."systemd-network-wait-online@" = {
+      description = "Wait for Network Interface %I to be Configured";
+      conflicts = [ "shutdown.target" ];
+      requisite = [ "systemd-networkd.service" ];
+      after = [ "systemd-networkd.service" ];
+      serviceConfig = {
+        Type = "oneshot";
+        RemainAfterExit = true;
+        ExecStart = "${config.systemd.package}/lib/systemd/systemd-networkd-wait-online -i %I";
+      };
+    };
+
+    services.resolved.enable = mkDefault true;
+    services.timesyncd.enable = mkDefault config.services.ntp.enable;
+  })
+  (mkIf config.services.resolved.enable {
+    systemd.services.systemd-resolved = {
+      wantedBy = [ "multi-user.target" ];
+      restartTriggers = [ config.environment.etc."systemd/resolved.conf".source ];
+    };
+
+    environment.etc."systemd/resolved.conf".text = ''
+      [Resolve]
+      DNS=${concatStringsSep " " config.networking.nameservers}
+    '';
+  })
+  (mkIf config.services.timesyncd.enable {
+    systemd.services.systemd-timesyncd = {
+      wantedBy = [ "sysinit.target" ];
+      restartTriggers = [ config.environment.etc."systemd/timesyncd.conf".source ];
+    };
+
+    environment.etc."systemd/timesyncd.conf".text = ''
+      [Time]
+      NTP=${concatStringsSep " " config.services.ntp.servers}
+    '';
+
+    systemd.services.ntpd.enable = false;
+  })
+  ];
 }
diff --git a/nixos/modules/tasks/filesystems/nfs.nix b/nixos/modules/tasks/filesystems/nfs.nix
index 16752ce7e1b5..546145e54ac7 100644
--- a/nixos/modules/tasks/filesystems/nfs.nix
+++ b/nixos/modules/tasks/filesystems/nfs.nix
@@ -13,7 +13,7 @@ let
   idmapdConfFile = pkgs.writeText "idmapd.conf" ''
     [General]
     Pipefs-Directory = ${rpcMountpoint}
-    ${optionalString (config.networking.domain != "")
+    ${optionalString (config.networking.domain != null)
       "Domain = ${config.networking.domain}"}
 
     [Mapping]
@@ -73,10 +73,10 @@ in
 
         path = [ pkgs.nfsUtils pkgs.sysvtools pkgs.utillinux ];
 
-        wantedBy = [ "network-online.target" "multi-user.target" ];
-        before = [ "network-online.target" ];
+        wantedBy = [ "remote-fs-pre.target" ];
+        before = [ "remote-fs-pre.target" ];
         requires = [ "basic.target" "rpcbind.service" ];
-        after = [ "basic.target" "rpcbind.service" "network.target" ];
+        after = [ "basic.target" "rpcbind.service" ];
 
         unitConfig.DefaultDependencies = false; # don't stop during shutdown
 
@@ -100,8 +100,8 @@ in
 
         path = [ pkgs.sysvtools pkgs.utillinux ];
 
-        wantedBy = [ "network-online.target" "multi-user.target" ];
-        before = [ "network-online.target" ];
+        wantedBy = [ "remote-fs-pre.target" ];
+        before = [ "remote-fs-pre.target" ];
         requires = [ "rpcbind.service" ];
         after = [ "rpcbind.service" ];
 
diff --git a/nixos/modules/tasks/network-interfaces-scripted.nix b/nixos/modules/tasks/network-interfaces-scripted.nix
new file mode 100644
index 000000000000..316e2e33eec7
--- /dev/null
+++ b/nixos/modules/tasks/network-interfaces-scripted.nix
@@ -0,0 +1,342 @@
+{ config, lib, pkgs, utils, ... }:
+
+with lib;
+with utils;
+
+let
+
+  cfg = config.networking;
+  interfaces = attrValues cfg.interfaces;
+  hasVirtuals = any (i: i.virtual) interfaces;
+
+  # We must escape interfaces due to the systemd interpretation
+  subsystemDevice = interface:
+    "sys-subsystem-net-devices-${escapeSystemdPath interface}.device";
+
+  interfaceIps = i:
+    i.ip4 ++ optionals cfg.enableIPv6 i.ip6
+    ++ optional (i.ipAddress != null) {
+      address = i.ipAddress;
+      prefixLength = i.prefixLength;
+    } ++ optional (cfg.enableIPv6 && i.ipv6Address != null) {
+      address = i.ipv6Address;
+      prefixLength = i.ipv6PrefixLength;
+    };
+
+  destroyBond = i: ''
+    while true; do
+      UPDATED=1
+      SLAVES=$(ip link | grep 'master ${i}' | awk -F: '{print $2}')
+      for I in $SLAVES; do
+        UPDATED=0
+        ip link set "$I" nomaster
+      done
+      [ "$UPDATED" -eq "1" ] && break
+    done
+    ip link set "${i}" down 2>/dev/null || true
+    ip link del "${i}" 2>/dev/null || true
+  '';
+
+in
+
+{
+
+  config = mkIf (!cfg.useNetworkd) {
+
+    systemd.services =
+      let
+
+        networkLocalCommands = {
+          after = [ "network-setup.service" ];
+          bindsTo = [ "network-setup.service" ];
+        };
+
+        networkSetup =
+          { description = "Networking Setup";
+
+            after = [ "network-interfaces.target" "network-pre.target" ];
+            before = [ "network.target" ];
+            wantedBy = [ "network.target" ];
+
+            unitConfig.ConditionCapability = "CAP_NET_ADMIN";
+
+            path = [ pkgs.iproute ];
+
+            serviceConfig.Type = "oneshot";
+            serviceConfig.RemainAfterExit = true;
+
+            script =
+              ''
+                # Set the static DNS configuration, if given.
+                ${pkgs.openresolv}/sbin/resolvconf -m 1 -a static <<EOF
+                ${optionalString (cfg.nameservers != [] && cfg.domain != null) ''
+                  domain ${cfg.domain}
+                ''}
+                ${optionalString (cfg.search != []) ("search " + concatStringsSep " " cfg.search)}
+                ${flip concatMapStrings cfg.nameservers (ns: ''
+                  nameserver ${ns}
+                '')}
+                EOF
+
+                # Set the default gateway.
+                ${optionalString (cfg.defaultGateway != null && cfg.defaultGateway != "") ''
+                  # FIXME: get rid of "|| true" (necessary to make it idempotent).
+                  ip route add default via "${cfg.defaultGateway}" ${
+                    optionalString (cfg.defaultGatewayWindowSize != null)
+                      "window ${cfg.defaultGatewayWindowSize}"} || true
+                ''}
+              '';
+          };
+
+        # For each interface <foo>, create a job ‘network-addresses-<foo>.service"
+        # that performs static address configuration.  It has a "wants"
+        # dependency on ‘<foo>.service’, which is supposed to create
+        # the interface and need not exist (i.e. for hardware
+        # interfaces).  It has a binds-to dependency on the actual
+        # network device, so it only gets started after the interface
+        # has appeared, and it's stopped when the interface
+        # disappears.
+        configureAddrs = i:
+          let
+            ips = interfaceIps i;
+          in
+          nameValuePair "network-addresses-${i.name}"
+          { description = "Addresss configuration of ${i.name}";
+            wantedBy = [ "network-interfaces.target" ];
+            before = [ "network-interfaces.target" ];
+            bindsTo = [ (subsystemDevice i.name) ];
+            after = [ (subsystemDevice i.name) "network-pre.target" ];
+            serviceConfig.Type = "oneshot";
+            serviceConfig.RemainAfterExit = true;
+            path = [ pkgs.iproute ];
+            script =
+              ''
+                echo "bringing up interface..."
+                ip link set "${i.name}" up
+
+                restart_network_interfaces=false
+              '' + flip concatMapStrings (ips) (ip:
+                let
+                  address = "${ip.address}/${toString ip.prefixLength}";
+                in
+                ''
+                  echo "checking ip ${address}..."
+                  if out=$(ip addr add "${address}" dev "${i.name}" 2>&1); then
+                    echo "added ip ${address}..."
+                    restart_network_setup=true
+                  elif ! echo "$out" | grep "File exists" >/dev/null 2>&1; then
+                    echo "failed to add ${address}"
+                    exit 1
+                  fi
+                '')
+              + optionalString (ips != [ ])
+                ''
+                  if [ "$restart_network_setup" = "true" ]; then
+                    # Ensure that the default gateway remains set.
+                    # (Flushing this interface may have removed it.)
+                    ${config.systemd.package}/bin/systemctl try-restart --no-block network-setup.service
+                  fi
+                  ${config.systemd.package}/bin/systemctl start ip-up.target
+                '';
+            preStop =
+              ''
+                echo "releasing configured ip's..."
+              '' + flip concatMapStrings (ips) (ip:
+                let
+                  address = "${ip.address}/${toString ip.prefixLength}";
+                in
+                ''
+                  echo -n "Deleting ${address}..."
+                  ip addr del "${address}" dev "${i.name}" >/dev/null 2>&1 || echo -n " Failed"
+                  echo ""
+                '');
+          };
+
+        createTunDevice = i: nameValuePair "${i.name}-netdev"
+          { description = "Virtual Network Interface ${i.name}";
+            requires = [ "dev-net-tun.device" ];
+            after = [ "dev-net-tun.device" "network-pre.target" ];
+            wantedBy = [ "network.target" (subsystemDevice i.name) ];
+            before = [ "network-interfaces.target" (subsystemDevice i.name) ];
+            path = [ pkgs.iproute ];
+            serviceConfig = {
+              Type = "oneshot";
+              RemainAfterExit = true;
+            };
+            script = ''
+              ip tuntap add dev "${i.name}" \
+              ${optionalString (i.virtualType != null) "mode ${i.virtualType}"} \
+              user "${i.virtualOwner}"
+            '';
+            postStop = ''
+              ip link del ${i.name}
+            '';
+          };
+
+        createBridgeDevice = n: v: nameValuePair "${n}-netdev"
+          (let
+            deps = map subsystemDevice v.interfaces;
+          in
+          { description = "Bridge Interface ${n}";
+            wantedBy = [ "network.target" (subsystemDevice n) ];
+            bindsTo = deps;
+            after = [ "network-pre.target" ] ++ deps
+              ++ concatMap (i: [ "network-addresses-${i}.service" "network-link-${i}.service" ]) v.interfaces;
+            before = [ "network-interfaces.target" (subsystemDevice n) ];
+            serviceConfig.Type = "oneshot";
+            serviceConfig.RemainAfterExit = true;
+            path = [ pkgs.iproute ];
+            script = ''
+              # Remove Dead Interfaces
+              echo "Removing old bridge ${n}..."
+              ip link show "${n}" >/dev/null 2>&1 && ip link del "${n}"
+
+              echo "Adding bridge ${n}..."
+              ip link add name "${n}" type bridge
+
+              # Enslave child interfaces
+              ${flip concatMapStrings v.interfaces (i: ''
+                ip link set "${i}" master "${n}"
+                ip link set "${i}" up
+              '')}
+
+              ip link set "${n}" up
+            '';
+            postStop = ''
+              ip link set "${n}" down || true
+              ip link del "${n}" || true
+            '';
+          });
+
+        createBondDevice = n: v: nameValuePair "${n}-netdev"
+          (let
+            deps = map subsystemDevice v.interfaces;
+          in
+          { description = "Bond Interface ${n}";
+            wantedBy = [ "network.target" (subsystemDevice n) ];
+            bindsTo = deps;
+            after = [ "network-pre.target" ] ++ deps
+              ++ concatMap (i: [ "network-addresses-${i}.service" "network-link-${i}.service" ]) v.interfaces;
+            before = [ "network-interfaces.target" (subsystemDevice n) ];
+            serviceConfig.Type = "oneshot";
+            serviceConfig.RemainAfterExit = true;
+            path = [ pkgs.iproute pkgs.gawk ];
+            script = ''
+              echo "Destroying old bond ${n}..."
+              ${destroyBond n}
+
+              echo "Creating new bond ${n}..."
+              ip link add name "${n}" type bond \
+                ${optionalString (v.mode != null) "mode ${toString v.mode}"} \
+                ${optionalString (v.miimon != null) "miimon ${toString v.miimon}"} \
+                ${optionalString (v.xmit_hash_policy != null) "xmit_hash_policy ${toString v.xmit_hash_policy}"} \
+                ${optionalString (v.lacp_rate != null) "lacp_rate ${toString v.lacp_rate}"}
+
+              # !!! There must be a better way to wait for the interface
+              while [ ! -d "/sys/class/net/${n}" ]; do sleep 0.1; done;
+
+              # Bring up the bond and enslave the specified interfaces
+              ip link set "${n}" up
+              ${flip concatMapStrings v.interfaces (i: ''
+                ip link set "${i}" down
+                ip link set "${i}" master "${n}"
+              '')}
+            '';
+            postStop = destroyBond n;
+          });
+
+        createMacvlanDevice = n: v: nameValuePair "${n}-netdev"
+          (let
+            deps = [ (subsystemDevice v.interface) ];
+          in
+          { description = "Vlan Interface ${n}";
+            wantedBy = [ "network.target" (subsystemDevice n) ];
+            bindsTo = deps;
+            after = [ "network-pre.target" ] ++ deps;
+            before = [ "network-interfaces.target" (subsystemDevice n) ];
+            serviceConfig.Type = "oneshot";
+            serviceConfig.RemainAfterExit = true;
+            path = [ pkgs.iproute ];
+            script = ''
+              # Remove Dead Interfaces
+              ip link show "${n}" >/dev/null 2>&1 && ip link delete "${n}"
+              ip link add link "${v.interface}" name "${n}" type macvlan \
+                ${optionalString (v.mode != null) "mode ${v.mode}"}
+              ip link set "${n}" up
+            '';
+            postStop = ''
+              ip link delete "${n}"
+            '';
+          });
+
+        createSitDevice = n: v: nameValuePair "${n}-netdev"
+          (let
+            deps = optional (v.dev != null) (subsystemDevice v.dev);
+          in
+          { description = "6-to-4 Tunnel Interface ${n}";
+            wantedBy = [ "network.target" (subsystemDevice n) ];
+            bindsTo = deps;
+            after = [ "network-pre.target" ] ++ deps;
+            before = [ "network-interfaces.target" (subsystemDevice n) ];
+            serviceConfig.Type = "oneshot";
+            serviceConfig.RemainAfterExit = true;
+            path = [ pkgs.iproute ];
+            script = ''
+              # Remove Dead Interfaces
+              ip link show "${n}" >/dev/null 2>&1 && ip link delete "${n}"
+              ip link add name "${n}" type sit \
+                ${optionalString (v.remote != null) "remote \"${v.remote}\""} \
+                ${optionalString (v.local != null) "local \"${v.local}\""} \
+                ${optionalString (v.ttl != null) "ttl ${toString v.ttl}"} \
+                ${optionalString (v.dev != null) "dev \"${v.dev}\""}
+              ip link set "${n}" up
+            '';
+            postStop = ''
+              ip link delete "${n}"
+            '';
+          });
+
+        createVlanDevice = n: v: nameValuePair "${n}-netdev"
+          (let
+            deps = [ (subsystemDevice v.interface) ];
+          in
+          { description = "Vlan Interface ${n}";
+            wantedBy = [ "network.target" (subsystemDevice n) ];
+            bindsTo = deps;
+            after = [ "network-pre.target" ] ++ deps;
+            before = [ "network-interfaces.target" (subsystemDevice n) ];
+            serviceConfig.Type = "oneshot";
+            serviceConfig.RemainAfterExit = true;
+            path = [ pkgs.iproute ];
+            script = ''
+              # Remove Dead Interfaces
+              ip link show "${n}" >/dev/null 2>&1 && ip link delete "${n}"
+              ip link add link "${v.interface}" name "${n}" type vlan id "${toString v.id}"
+              ip link set "${n}" up
+            '';
+            postStop = ''
+              ip link delete "${n}"
+            '';
+          });
+
+      in listToAttrs (
+           map configureAddrs interfaces ++
+           map createTunDevice (filter (i: i.virtual) interfaces))
+         // mapAttrs' createBridgeDevice cfg.bridges
+         // mapAttrs' createBondDevice cfg.bonds
+         // mapAttrs' createMacvlanDevice cfg.macvlans
+         // mapAttrs' createSitDevice cfg.sits
+         // mapAttrs' createVlanDevice cfg.vlans
+         // {
+           "network-setup" = networkSetup;
+           "network-local-commands" = networkLocalCommands;
+         };
+
+    services.udev.extraRules =
+      ''
+        KERNEL=="tun", TAG+="systemd"
+      '';
+
+  };
+
+}
diff --git a/nixos/modules/tasks/network-interfaces-systemd.nix b/nixos/modules/tasks/network-interfaces-systemd.nix
new file mode 100644
index 000000000000..ee3efbbc9ffd
--- /dev/null
+++ b/nixos/modules/tasks/network-interfaces-systemd.nix
@@ -0,0 +1,174 @@
+{ config, lib, pkgs, utils, ... }:
+
+with lib;
+with utils;
+
+let
+
+  cfg = config.networking;
+  interfaces = attrValues cfg.interfaces;
+
+  interfaceIps = i:
+    i.ip4 ++ optionals cfg.enableIPv6 i.ip6
+    ++ optional (i.ipAddress != null) {
+      address = i.ipAddress;
+      prefixLength = i.prefixLength;
+    } ++ optional (cfg.enableIPv6 && i.ipv6Address != null) {
+      address = i.ipv6Address;
+      prefixLength = i.ipv6PrefixLength;
+    };
+
+  dhcpStr = useDHCP: if useDHCP == true || useDHCP == null then "both" else "none";
+
+  slaves =
+    concatLists (map (bond: bond.interfaces) (attrValues cfg.bonds))
+    ++ concatLists (map (bridge: bridge.interfaces) (attrValues cfg.bridges))
+    ++ map (sit: sit.dev) (attrValues cfg.sits)
+    ++ map (vlan: vlan.interface) (attrValues cfg.vlans);
+
+in
+
+{
+
+  config = mkIf cfg.useNetworkd {
+
+    assertions = [ {
+      assertion = cfg.defaultGatewayWindowSize == null;
+      message = "networking.defaultGatewayWindowSize is not supported by networkd.";
+    } ];
+
+    systemd.services.dhcpcd.enable = mkDefault false;
+
+    systemd.services.network-local-commands = {
+      after = [ "systemd-networkd.service" ];
+      bindsTo = [ "systemd-networkd.service" ];
+    };
+
+    systemd.network =
+      let
+        domains = cfg.search ++ (optional (cfg.domain != null) cfg.domain);
+        genericNetwork = override: {
+          DHCP = override (dhcpStr cfg.useDHCP);
+        } // optionalAttrs (cfg.defaultGateway != null) {
+          gateway = override [ cfg.defaultGateway ];
+        } // optionalAttrs (domains != [ ]) {
+          domains = override domains;
+        };
+      in mkMerge [ {
+        enable = true;
+        networks."99-main" = genericNetwork mkDefault;
+      }
+      (mkMerge (flip map interfaces (i: {
+        netdevs = mkIf i.virtual (
+          let
+            devType = if i.virtualType != null then i.virtualType
+              else (if hasPrefix "tun" i.name then "tun" else "tap");
+          in {
+            "40-${i.name}" = {
+              netdevConfig = {
+                Name = i.name;
+                Kind = devType;
+              };
+              "${devType}Config" = optionalAttrs (i.virtualOwner != null) {
+                User = i.virtualOwner;
+              };
+            };
+          });
+        networks."40-${i.name}" = mkMerge [ (genericNetwork mkDefault) {
+          name = mkDefault i.name;
+          DHCP = mkForce (dhcpStr
+            (if i.useDHCP != null then i.useDHCP else cfg.useDHCP && interfaceIps i == [ ]));
+          address = flip map (interfaceIps i)
+            (ip: "${ip.address}/${toString ip.prefixLength}");
+        } ];
+      })))
+      (mkMerge (flip mapAttrsToList cfg.bridges (name: bridge: {
+        netdevs."40-${name}" = {
+          netdevConfig = {
+            Name = name;
+            Kind = "bridge";
+          };
+        };
+        networks = listToAttrs (flip map bridge.interfaces (bi:
+          nameValuePair "40-${bi}" (mkMerge [ (genericNetwork (mkOverride 999)) {
+            DHCP = mkOverride 0 (dhcpStr false);
+            networkConfig.Bridge = name;
+          } ])));
+      })))
+      (mkMerge (flip mapAttrsToList cfg.bonds (name: bond: {
+        netdevs."40-${name}" = {
+          netdevConfig = {
+            Name = name;
+            Kind = "bond";
+          };
+          bondConfig =
+            (optionalAttrs (bond.lacp_rate != null) {
+              LACPTransmitRate = bond.lacp_rate;
+            }) // (optionalAttrs (bond.miimon != null) {
+              MIIMonitorSec = bond.miimon;
+            }) // (optionalAttrs (bond.mode != null) {
+              Mode = bond.mode;
+            }) // (optionalAttrs (bond.xmit_hash_policy != null) {
+              TransmitHashPolicy = bond.xmit_hash_policy;
+            });
+        };
+        networks = listToAttrs (flip map bond.interfaces (bi:
+          nameValuePair "40-${bi}" (mkMerge [ (genericNetwork (mkOverride 999)) {
+            DHCP = mkOverride 0 (dhcpStr false);
+            networkConfig.Bond = name;
+          } ])));
+      })))
+      (mkMerge (flip mapAttrsToList cfg.macvlans (name: macvlan: {
+        netdevs."40-${name}" = {
+          netdevConfig = {
+            Name = name;
+            Kind = "macvlan";
+          };
+          macvlanConfig = optionalAttrs (macvlan.mode != null) { Mode = macvlan.mode; };
+        };
+        networks."40-${macvlan.interface}" = (mkMerge [ (genericNetwork (mkOverride 999)) {
+          macvlan = [ name ];
+        } ]);
+      })))
+      (mkMerge (flip mapAttrsToList cfg.sits (name: sit: {
+        netdevs."40-${name}" = {
+          netdevConfig = {
+            Name = name;
+            Kind = "sit";
+          };
+          tunnelConfig =
+            (optionalAttrs (sit.remote != null) {
+              Remote = sit.remote;
+            }) // (optionalAttrs (sit.local != null) {
+              Local = sit.local;
+            }) // (optionalAttrs (sit.ttl != null) {
+              TTL = sit.ttl;
+            });
+        };
+        networks = mkIf (sit.dev != null) {
+          "40-${sit.dev}" = (mkMerge [ (genericNetwork (mkOverride 999)) {
+            tunnel = [ name ];
+          } ]);
+        };
+      })))
+      (mkMerge (flip mapAttrsToList cfg.vlans (name: vlan: {
+        netdevs."40-${name}" = {
+          netdevConfig = {
+            Name = name;
+            Kind = "vlan";
+          };
+          vlanConfig.Id = vlan.id;
+        };
+        networks."40-${vlan.interface}" = (mkMerge [ (genericNetwork (mkOverride 999)) {
+          vlan = [ name ];
+        } ]);
+      })))
+    ];
+
+    # We need to prefill the slaved devices with networking options
+    # This forces the network interface creator to initialize slaves.
+    networking.interfaces = listToAttrs (map (i: nameValuePair i { }) slaves);
+
+  };
+
+}
diff --git a/nixos/modules/tasks/network-interfaces.nix b/nixos/modules/tasks/network-interfaces.nix
index 9579eaa77d06..9c6c71a1dbb0 100644
--- a/nixos/modules/tasks/network-interfaces.nix
+++ b/nixos/modules/tasks/network-interfaces.nix
@@ -11,6 +11,11 @@ let
   hasSits = cfg.sits != { };
   hasBonds = cfg.bonds != { };
 
+  slaves = concatMap (i: i.interfaces) (attrValues cfg.bonds)
+    ++ concatMap (i: i.interfaces) (attrValues cfg.bridges);
+
+  slaveIfs = map (i: cfg.interfaces.${i}) (filter (i: cfg.interfaces ? ${i}) slaves);
+
   # We must escape interfaces due to the systemd interpretation
   subsystemDevice = interface:
     "sys-subsystem-net-devices-${escapeSystemdPath interface}.device";
@@ -45,6 +50,16 @@ let
         description = "Name of the interface.";
       };
 
+      useDHCP = mkOption {
+        type = types.nullOr types.bool;
+        default = null;
+        description = ''
+          Whether this interface should be configured with dhcp.
+          Null implies the old behavior which depends on whether ip addresses
+          are specified or not.
+        '';
+      };
+
       ip4 = mkOption {
         default = [ ];
         example = [
@@ -203,6 +218,7 @@ in
 
     networking.hostName = mkOption {
       default = "nixos";
+      type = types.str;
       description = ''
         The name of the machine.  Leave it empty if you want to obtain
         it from a DHCP server (if using DHCP).
@@ -225,14 +241,16 @@ in
 
     networking.enableIPv6 = mkOption {
       default = true;
+      type = types.bool;
       description = ''
         Whether to enable support for IPv6.
       '';
     };
 
     networking.defaultGateway = mkOption {
-      default = "";
+      default = null;
       example = "131.211.84.1";
+      type = types.nullOr types.str;
       description = ''
         The default gateway.  It can be left empty if it is auto-detected through DHCP.
       '';
@@ -266,8 +284,9 @@ in
     };
 
     networking.domain = mkOption {
-      default = "";
+      default = null;
       example = "home";
+      type = types.nullOr types.str;
       description = ''
         The domain.  It can be left empty if it is auto-detected through DHCP.
       '';
@@ -414,6 +433,37 @@ in
       };
     };
 
+    networking.macvlans = mkOption {
+      type = types.attrsOf types.optionSet;
+      default = { };
+      example = {
+        wan = {
+          interface = "enp2s0";
+          mode = "vepa";
+        };
+      };
+      description = ''
+        This option allows you to define macvlan interfaces which should
+        be automatically created.
+      '';
+      options = {
+
+        interface = mkOption {
+          example = "enp4s0";
+          type = types.string;
+          description = "The interface the macvlan will transmit packets through.";
+        };
+
+        mode = mkOption {
+          default = null;
+          type = types.nullOr types.str;
+          example = "vepa";
+          description = "The mode of the macvlan device.";
+        };
+
+      };
+    };
+
     networking.sits = mkOption {
       type = types.attrsOf types.optionSet;
       default = { };
@@ -523,6 +573,16 @@ in
       '';
     };
 
+    networking.useNetworkd = mkOption {
+      default = false;
+      type = types.bool;
+      description = ''
+        Whether we should use networkd as the network configuration backend or
+        the legacy script based system. Note that this option is experimental,
+        enable at your own risk.
+      '';
+    };
+
   };
 
 
@@ -534,6 +594,9 @@ in
       (flip map interfaces (i: {
         assertion = i.subnetMask == null;
         message = "The networking.interfaces.${i.name}.subnetMask option is defunct. Use prefixLength instead.";
+      })) ++ (flip map slaveIfs (i: {
+        assertion = i.ip4 == [ ] && i.ipAddress == null && i.ip6 == [ ] && i.ipv6Address == null;
+        message = "The networking.interfaces.${i.name} must not have any defined ips when it is a slave.";
       })) ++ [
         {
           assertion = cfg.hostId == null || (stringLength cfg.hostId == 8 && isHexString cfg.hostId);
@@ -552,345 +615,18 @@ in
       # from being created.
       optionalString hasBonds "options bonding max_bonds=0";
 
-    environment.systemPackages =
-      [ pkgs.host
-        pkgs.iproute
-        pkgs.iputils
-        pkgs.nettools
-        pkgs.wirelesstools
-        pkgs.iw
-        pkgs.rfkill
-        pkgs.openresolv
-      ]
-      ++ optional (cfg.bridges != {}) pkgs.bridge_utils
-      ++ optional hasVirtuals pkgs.tunctl
-      ++ optional cfg.enableIPv6 pkgs.ndisc6;
+    boot.kernel.sysctl = {
+      "net.net.ipv4.conf.all.promote_secondaries" = true;
+      "net.ipv6.conf.all.disable_ipv6" = mkDefault (!cfg.enableIPv6);
+      "net.ipv6.conf.default.disable_ipv6" = mkDefault (!cfg.enableIPv6);
+      "net.ipv4.conf.all_forwarding" = mkDefault (any (i: i.proxyARP) interfaces);
+      "net.ipv6.conf.all.forwarding" = mkDefault (any (i: i.proxyARP) interfaces);
+    } // listToAttrs (concatLists (flip map (filter (i: i.proxyARP) interfaces)
+        (i: flip map [ "4" "6" ] (v: nameValuePair "net.ipv${v}.conf.${i.name}.proxy_arp" true))
+      ));
 
     security.setuidPrograms = [ "ping" "ping6" ];
 
-    systemd.targets."network-interfaces" =
-      { description = "All Network Interfaces";
-        wantedBy = [ "network.target" ];
-        unitConfig.X-StopOnReconfiguration = true;
-      };
-
-    systemd.services =
-      let
-
-        networkSetup =
-          { description = "Networking Setup";
-
-            after = [ "network-interfaces.target" ];
-            before = [ "network.target" ];
-            wantedBy = [ "network.target" ];
-
-            unitConfig.ConditionCapability = "CAP_NET_ADMIN";
-
-            path = [ pkgs.iproute ];
-
-            serviceConfig.Type = "oneshot";
-            serviceConfig.RemainAfterExit = true;
-
-            script =
-              ''
-                # Set the static DNS configuration, if given.
-                ${pkgs.openresolv}/sbin/resolvconf -m 1 -a static <<EOF
-                ${optionalString (cfg.nameservers != [] && cfg.domain != "") ''
-                  domain ${cfg.domain}
-                ''}
-                ${optionalString (cfg.search != []) ("search " + concatStringsSep " " cfg.search)}
-                ${flip concatMapStrings cfg.nameservers (ns: ''
-                  nameserver ${ns}
-                '')}
-                EOF
-
-                # Disable or enable IPv6.
-                ${optionalString (!config.boot.isContainer) ''
-                  if [ -e /proc/sys/net/ipv6/conf/all/disable_ipv6 ]; then
-                    echo ${if cfg.enableIPv6 then "0" else "1"} > /proc/sys/net/ipv6/conf/all/disable_ipv6
-                  fi
-                ''}
-
-                # Set the default gateway.
-                ${optionalString (cfg.defaultGateway != "") ''
-                  # FIXME: get rid of "|| true" (necessary to make it idempotent).
-                  ip route add default via "${cfg.defaultGateway}" ${
-                    optionalString (cfg.defaultGatewayWindowSize != null)
-                      "window ${cfg.defaultGatewayWindowSize}"} || true
-                ''}
-
-                # Turn on forwarding if any interface has enabled proxy_arp.
-                ${optionalString (any (i: i.proxyARP) interfaces) ''
-                  echo 1 > /proc/sys/net/ipv4/ip_forward
-                ''}
-
-                # Run any user-specified commands.
-                ${cfg.localCommands}
-              '';
-          };
-
-        # For each interface <foo>, create a job ‘<foo>-cfg.service"
-        # that performs static configuration.  It has a "wants"
-        # dependency on ‘<foo>.service’, which is supposed to create
-        # the interface and need not exist (i.e. for hardware
-        # interfaces).  It has a binds-to dependency on the actual
-        # network device, so it only gets started after the interface
-        # has appeared, and it's stopped when the interface
-        # disappears.
-        configureInterface = i:
-          let
-            ips = i.ip4 ++ optionals cfg.enableIPv6 i.ip6
-              ++ optional (i.ipAddress != null) {
-                address = i.ipAddress;
-                prefixLength = i.prefixLength;
-              } ++ optional (cfg.enableIPv6 && i.ipv6Address != null) {
-                address = i.ipv6Address;
-                prefixLength = i.ipv6PrefixLength;
-              };
-          in
-          nameValuePair "${i.name}-cfg"
-          { description = "Configuration of ${i.name}";
-            wantedBy = [ "network-interfaces.target" ];
-            bindsTo = [ (subsystemDevice i.name) ];
-            after = [ (subsystemDevice i.name) ];
-            serviceConfig.Type = "oneshot";
-            serviceConfig.RemainAfterExit = true;
-            path = [ pkgs.iproute pkgs.gawk ];
-            script =
-              ''
-                echo "bringing up interface..."
-                ip link set "${i.name}" up
-              ''
-              + optionalString (i.macAddress != null)
-                ''
-                  echo "setting MAC address to ${i.macAddress}..."
-                  ip link set "${i.name}" address "${i.macAddress}"
-                ''
-              + optionalString (i.mtu != null)
-                ''
-                  echo "setting MTU to ${toString i.mtu}..."
-                  ip link set "${i.name}" mtu "${toString i.mtu}"
-                ''
-
-              # Ip Setup
-              +
-                ''
-                  curIps=$(ip -o a show dev "${i.name}" | awk '{print $4}')
-                  # Only do an add if it's necessary.  This is
-                  # useful when the Nix store is accessed via this
-                  # interface (e.g. in a QEMU VM test).
-                ''
-              + flip concatMapStrings (ips) (ip:
-                let
-                  address = "${ip.address}/${toString ip.prefixLength}";
-                in
-                ''
-                  echo "checking ip ${address}..."
-                  if ! echo "$curIps" | grep "${address}" >/dev/null 2>&1; then
-                    if out=$(ip addr add "${address}" dev "${i.name}" 2>&1); then
-                      echo "added ip ${address}..."
-                      restart_network_setup=true
-                    elif ! echo "$out" | grep "File exists" >/dev/null 2>&1; then
-                      echo "failed to add ${address}"
-                      exit 1
-                    fi
-                  fi
-                '')
-              + optionalString (ips != [ ])
-                ''
-                  if [ restart_network_setup = true ]; then
-                    # Ensure that the default gateway remains set.
-                    # (Flushing this interface may have removed it.)
-                    ${config.systemd.package}/bin/systemctl try-restart --no-block network-setup.service
-                  fi
-                  ${config.systemd.package}/bin/systemctl start ip-up.target
-                ''
-              + optionalString i.proxyARP
-                ''
-                  echo 1 > /proc/sys/net/ipv4/conf/${i.name}/proxy_arp
-                ''
-              + optionalString (i.proxyARP && cfg.enableIPv6)
-                ''
-                  echo 1 > /proc/sys/net/ipv6/conf/${i.name}/proxy_ndp
-                '';
-            preStop =
-              ''
-                echo "releasing configured ip's..."
-              ''
-              + flip concatMapStrings (ips) (ip:
-                let
-                  address = "${ip.address}/${toString ip.prefixLength}";
-                in
-                ''
-                  echo -n "Deleting ${address}..."
-                  ip addr del "${address}" dev "${i.name}" >/dev/null 2>&1 || echo -n " Failed"
-                  echo ""
-                '');
-          };
-
-        createTunDevice = i: nameValuePair "${i.name}-netdev"
-          { description = "Virtual Network Interface ${i.name}";
-            requires = [ "dev-net-tun.device" ];
-            after = [ "dev-net-tun.device" ];
-            wantedBy = [ "network.target" (subsystemDevice i.name) ];
-            path = [ pkgs.iproute ];
-            serviceConfig = {
-              Type = "oneshot";
-              RemainAfterExit = true;
-            };
-            script = ''
-              ip tuntap add dev "${i.name}" \
-              ${optionalString (i.virtualType != null) "mode ${i.virtualType}"} \
-              user "${i.virtualOwner}"
-            '';
-            postStop = ''
-              ip link del ${i.name}
-            '';
-          };
-
-        createBridgeDevice = n: v: nameValuePair "${n}-netdev"
-          (let
-            deps = map subsystemDevice v.interfaces;
-          in
-          { description = "Bridge Interface ${n}";
-            wantedBy = [ "network.target" (subsystemDevice n) ];
-            bindsTo = deps;
-            after = deps;
-            serviceConfig.Type = "oneshot";
-            serviceConfig.RemainAfterExit = true;
-            path = [ pkgs.bridge_utils pkgs.iproute ];
-            script =
-              ''
-                # Remove Dead Interfaces
-                ip link show "${n}" >/dev/null 2>&1 && ip link delete "${n}"
-
-                brctl addbr "${n}"
-
-                # Set bridge's hello time to 0 to avoid startup delays.
-                brctl setfd "${n}" 0
-
-                ${flip concatMapStrings v.interfaces (i: ''
-                  brctl addif "${n}" "${i}"
-                  ip link set "${i}" up
-                  ip addr flush dev "${i}"
-
-                  echo "bringing up network device ${n}..."
-                  ip link set "${n}" up
-                '')}
-
-                # !!! Should delete (brctl delif) any interfaces that
-                # no longer belong to the bridge.
-              '';
-            postStop =
-              ''
-                ip link set "${n}" down
-                brctl delbr "${n}"
-              '';
-          });
-
-        createBondDevice = n: v: nameValuePair "${n}-netdev"
-          (let
-            deps = map subsystemDevice v.interfaces;
-          in
-          { description = "Bond Interface ${n}";
-            wantedBy = [ "network.target" (subsystemDevice n) ];
-            bindsTo = deps;
-            after = deps;
-            before = [ "${n}-cfg.service" ];
-            serviceConfig.Type = "oneshot";
-            serviceConfig.RemainAfterExit = true;
-            path = [ pkgs.ifenslave pkgs.iproute ];
-            script = ''
-              ip link add name "${n}" type bond
-
-              # !!! There must be a better way to wait for the interface
-              while [ ! -d /sys/class/net/${n} ]; do sleep 0.1; done;
-
-              # Ensure the link is down so that we can set options
-              ip link set "${n}" down
-
-              # Set the miimon and mode options
-              ${optionalString (v.miimon != null)
-                "echo \"${toString v.miimon}\" >/sys/class/net/${n}/bonding/miimon"}
-              ${optionalString (v.mode != null)
-                "echo \"${v.mode}\" >/sys/class/net/${n}/bonding/mode"}
-              ${optionalString (v.lacp_rate != null)
-                "echo \"${v.lacp_rate}\" >/sys/class/net/${n}/bonding/lacp_rate"}
-              ${optionalString (v.xmit_hash_policy != null)
-                "echo \"${v.xmit_hash_policy}\" >/sys/class/net/${n}/bonding/xmit_hash_policy"}
-
-              # Bring up the bond and enslave the specified interfaces
-              ip link set "${n}" up
-              ${flip concatMapStrings v.interfaces (i: ''
-                ifenslave "${n}" "${i}"
-              '')}
-            '';
-            postStop = ''
-              ${flip concatMapStrings v.interfaces (i: ''
-                ifenslave -d "${n}" "${i}" >/dev/null 2>&1 || true
-              '')}
-              ip link set "${n}" down >/dev/null 2>&1 || true
-              ip link del "${n}" >/dev/null 2>&1 || true
-            '';
-          });
-
-        createSitDevice = n: v: nameValuePair "${n}-netdev"
-          (let
-            deps = optional (v.dev != null) (subsystemDevice v.dev);
-          in
-          { description = "6-to-4 Tunnel Interface ${n}";
-            wantedBy = [ "network.target" (subsystemDevice n) ];
-            bindsTo = deps;
-            after = deps;
-            serviceConfig.Type = "oneshot";
-            serviceConfig.RemainAfterExit = true;
-            path = [ pkgs.iproute ];
-            script = ''
-              # Remove Dead Interfaces
-              ip link show "${n}" >/dev/null 2>&1 && ip link delete "${n}"
-              ip link add name "${n}" type sit \
-                ${optionalString (v.remote != null) "remote \"${v.remote}\""} \
-                ${optionalString (v.local != null) "local \"${v.local}\""} \
-                ${optionalString (v.ttl != null) "ttl ${toString v.ttl}"} \
-                ${optionalString (v.dev != null) "dev \"${v.dev}\""}
-              ip link set "${n}" up
-            '';
-            postStop = ''
-              ip link delete "${n}"
-            '';
-          });
-
-        createVlanDevice = n: v: nameValuePair "${n}-netdev"
-          (let
-            deps = [ (subsystemDevice v.interface) ];
-          in
-          { description = "Vlan Interface ${n}";
-            wantedBy = [ "network.target" (subsystemDevice n) ];
-            bindsTo = deps;
-            after = deps;
-            serviceConfig.Type = "oneshot";
-            serviceConfig.RemainAfterExit = true;
-            path = [ pkgs.iproute ];
-            script = ''
-              # Remove Dead Interfaces
-              ip link show "${n}" >/dev/null 2>&1 && ip link delete "${n}"
-              ip link add link "${v.interface}" name "${n}" type vlan id "${toString v.id}"
-              ip link set "${n}" up
-            '';
-            postStop = ''
-              ip link delete "${n}"
-            '';
-          });
-
-      in listToAttrs (
-           map configureInterface interfaces ++
-           map createTunDevice (filter (i: i.virtual) interfaces))
-         // mapAttrs' createBridgeDevice cfg.bridges
-         // mapAttrs' createBondDevice cfg.bonds
-         // mapAttrs' createSitDevice cfg.sits
-         // mapAttrs' createVlanDevice cfg.vlans
-         // { "network-setup" = networkSetup; };
-
     # Set the host and domain names in the activation script.  Don't
     # clear it if it's not configured in the NixOS configuration,
     # since it may have been set by dhcpcd in the meantime.
@@ -899,7 +635,7 @@ in
         hostname "${cfg.hostName}"
       '';
     system.activationScripts.domain =
-      optionalString (cfg.domain != "") ''
+      optionalString (cfg.domain != null) ''
         domainname "${cfg.domain}"
       '';
 
@@ -918,11 +654,63 @@ in
         }
       ];
 
-    services.udev.extraRules =
-      ''
-        KERNEL=="tun", TAG+="systemd"
-      '';
+    environment.systemPackages =
+      [ pkgs.host
+        pkgs.iproute
+        pkgs.iputils
+        pkgs.nettools
+        pkgs.wirelesstools
+        pkgs.iw
+        pkgs.rfkill
+        pkgs.openresolv
+      ];
+
+    systemd.targets."network-interfaces" =
+      { description = "All Network Interfaces";
+        wantedBy = [ "network.target" ];
+        before = [ "network.target" ];
+        after = [ "network-pre.target" ];
+        unitConfig.X-StopOnReconfiguration = true;
+      };
 
+    systemd.services = {
+      network-local-commands = {
+        description = "Extra networking commands.";
+        before = [ "network.target" ];
+        wantedBy = [ "network.target" ];
+        after = [ "network-pre.target" ];
+        unitConfig.ConditionCapability = "CAP_NET_ADMIN";
+        path = [ pkgs.iproute ];
+        serviceConfig.Type = "oneshot";
+        serviceConfig.RemainAfterExit = true;
+        script = ''
+          # Run any user-specified commands.
+          ${cfg.localCommands}
+        '';
+      };
+    } // (listToAttrs (flip map interfaces (i:
+      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" ];
+        path = [ pkgs.iproute ];
+        serviceConfig = {
+          Type = "oneshot";
+          RemainAfterExit = true;
+        };
+        script =
+          ''
+            echo "Configuring link..."
+          '' + optionalString (i.macAddress != null) ''
+            echo "setting MAC address to ${i.macAddress}..."
+            ip link set "${i.name}" address "${i.macAddress}"
+          '' + optionalString (i.mtu != null) ''
+            echo "setting MTU to ${toString i.mtu}..."
+            ip link set "${i.name}" mtu "${toString i.mtu}"
+          '';
+      })));
   };
 
 }
diff --git a/nixos/modules/virtualisation/docker.nix b/nixos/modules/virtualisation/docker.nix
index 11d3f576728f..5be76b2682f5 100644
--- a/nixos/modules/virtualisation/docker.nix
+++ b/nixos/modules/virtualisation/docker.nix
@@ -7,8 +7,8 @@ with lib;
 let
 
   cfg = config.virtualisation.docker;
-  pro = config.nix.proxy;
-  proxy_env = optionalAttrs (pro != "") { Environment = "\"http_proxy=${pro}\""; };
+  pro = config.networking.proxy.default;
+  proxy_env = optionalAttrs (pro != null) { Environment = "\"http_proxy=${pro}\""; };
 
 in
 
@@ -103,6 +103,12 @@ in
           LimitNPROC = 1048576;
         } // proxy_env;
 
+        postStart = ''
+          while ! [ -e /var/run/docker.sock ]; do
+            sleep 0.1
+          done
+        '';
+
         # Presumably some containers are running we don't want to interrupt
         restartIfChanged = false;
       };
diff --git a/nixos/modules/virtualisation/kubernetes.nix b/nixos/modules/virtualisation/kubernetes.nix
new file mode 100644
index 000000000000..50388cf2e121
--- /dev/null
+++ b/nixos/modules/virtualisation/kubernetes.nix
@@ -0,0 +1,461 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.virtualisation.kubernetes;
+
+in {
+
+  ###### interface
+
+  options.virtualisation.kubernetes = {
+    package = mkOption {
+      description = "Kubernetes package to use.";
+      default = pkgs.kubernetes;
+      type = types.package;
+    };
+
+    verbose = mkOption {
+      description = "Kubernetes enable verbose mode for debugging";
+      default = false;
+      type = types.bool;
+    };
+
+    etcdServers = mkOption {
+      description = "Kubernetes list of etcd servers to watch.";
+      default = [ "127.0.0.1:4001" ];
+      type = types.listOf types.str;
+    };
+
+    roles = mkOption {
+      description = ''
+        Kubernetes role that this machine should take.
+
+        Master role will enable etcd, apiserver, scheduler and controller manager
+        services. Node role will enable etcd, docker, kubelet and proxy services.
+      '';
+      default = [];
+      type = types.listOf (types.enum ["master" "node"]);
+    };
+
+    dataDir = mkOption {
+      description = "Kubernetes root directory for managing kubelet files.";
+      default = "/var/lib/kubernetes";
+      type = types.path;
+    };
+
+    apiserver = {
+      enable = mkOption {
+        description = "Whether to enable kubernetes apiserver.";
+        default = false;
+        type = types.bool;
+      };
+
+      address = mkOption {
+        description = "Kubernetes apiserver listening address.";
+        default = "127.0.0.1";
+        type = types.str;
+      };
+
+      publicAddress = mkOption {
+        description = ''
+          Kubernetes apiserver public listening address used for read only and
+          secure port.
+        '';
+        default = cfg.apiserver.address;
+        type = types.str;
+      };
+
+      port = mkOption {
+        description = "Kubernets apiserver listening port.";
+        default = 8080;
+        type = types.int;
+      };
+
+      readOnlyPort = mkOption {
+        description = "Kubernets apiserver read-only port.";
+        default = 7080;
+        type = types.int;
+      };
+
+      securePort = mkOption {
+        description = "Kubernetes apiserver secure port.";
+        default = 6443;
+        type = types.int;
+      };
+
+      tlsCertFile = mkOption {
+        description = "Kubernetes apiserver certificate file.";
+        default = "";
+        type = types.str;
+      };
+
+      tlsPrivateKeyFile = mkOption {
+        description = "Kubernetes apiserver private key file.";
+        default = "";
+        type = types.str;
+      };
+
+      tokenAuth = mkOption {
+        description = ''
+          Kubernetes apiserver token authentication file. See
+          <link xlink:href="https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/authentication.md"/>
+        '';
+        default = {};
+        example = literalExample ''
+          {
+            alice = "abc123";
+            bob = "xyz987";
+          }
+        '';
+        type = types.attrsOf types.str;
+      };
+
+      authorizationMode = mkOption {
+        description = ''
+          Kubernetes apiserver authorization mode (AlwaysAllow/AlwaysDeny/ABAC). See
+          <link xlink:href="https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/authorization.md"/>
+        '';
+        default = "AlwaysAllow";
+        type = types.enum ["AlwaysAllow" "AlwaysDeny" "ABAC"];
+      };
+
+      authorizationPolicy = mkOption {
+        description = ''
+          Kubernetes apiserver authorization policy file. See
+          <link xlink:href="https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/authorization.md"/>
+        '';
+        default = [];
+        example = literalExample ''
+          [
+            {user = "admin";}
+            {user = "scheduler"; readonly = true; kind= "pods";}
+            {user = "scheduler"; kind = "bindings";}
+            {user = "kubelet";  readonly = true; kind = "bindings";}
+            {user = "kubelet"; kind = "events";}
+            {user= "alice"; ns = "projectCaribou";}
+            {user = "bob"; readonly = true; ns = "projectCaribou";}
+          ]
+        '';
+        type = types.listOf types.attrs;
+      };
+
+      allowPrivileged = mkOption {
+        description = "Whether to allow privileged containers on kubernetes.";
+        default = false;
+        type = types.bool;
+      };
+
+      portalNet = mkOption {
+        description = "Kubernetes CIDR notation IP range from which to assign portal IPs";
+        default = "10.10.10.10/16";
+        type = types.str;
+      };
+
+      extraOpts = mkOption {
+        description = "Kubernetes apiserver extra command line options.";
+        default = "";
+        type = types.str;
+      };
+    };
+
+    scheduler = {
+      enable = mkOption {
+        description = "Whether to enable kubernetes scheduler.";
+        default = false;
+        type = types.bool;
+      };
+
+      address = mkOption {
+        description = "Kubernetes scheduler listening address.";
+        default = "127.0.0.1";
+        type = types.str;
+      };
+
+      port = mkOption {
+        description = "Kubernets scheduler listening port.";
+        default = 10251;
+        type = types.int;
+      };
+
+      master = mkOption {
+        description = "Kubernetes apiserver address";
+        default = "${cfg.apiserver.address}:${toString cfg.apiserver.port}";
+        type = types.str;
+      };
+
+      extraOpts = mkOption {
+        description = "Kubernetes scheduler extra command line options.";
+        default = "";
+        type = types.str;
+      };
+    };
+
+    controllerManager = {
+      enable = mkOption {
+        description = "Whether to enable kubernetes controller manager.";
+        default = false;
+        type = types.bool;
+      };
+
+      address = mkOption {
+        description = "Kubernetes controller manager listening address.";
+        default = "127.0.0.1";
+        type = types.str;
+      };
+
+      port = mkOption {
+        description = "Kubernets controller manager listening port.";
+        default = 10252;
+        type = types.int;
+      };
+
+      master = mkOption {
+        description = "Kubernetes apiserver address";
+        default = "${cfg.apiserver.address}:${toString cfg.apiserver.port}";
+        type = types.str;
+      };
+
+      machines = mkOption {
+        description = "Kubernetes apiserver list of machines to schedule to schedule onto";
+        default = [];
+        type = types.listOf types.str;
+      };
+
+      extraOpts = mkOption {
+        description = "Kubernetes scheduler extra command line options.";
+        default = "";
+        type = types.str;
+      };
+    };
+
+    kubelet = {
+      enable = mkOption {
+        description = "Whether to enable kubernetes kubelet.";
+        default = false;
+        type = types.bool;
+      };
+
+      address = mkOption {
+        description = "Kubernetes kubelet info server listening address.";
+        default = "0.0.0.0";
+        type = types.str;
+      };
+
+      port = mkOption {
+        description = "Kubernets kubelet info server listening port.";
+        default = 10250;
+        type = types.int;
+      };
+
+      hostname = mkOption {
+        description = "Kubernetes kubelet hostname override";
+        default = config.networking.hostName;
+        type = types.str;
+      };
+
+      allowPrivileged = mkOption {
+        description = "Whether to allow kubernetes containers to request privileged mode.";
+        default = false;
+        type = types.bool;
+      };
+
+      extraOpts = mkOption {
+        description = "Kubernetes kubelet extra command line options.";
+        default = "";
+        type = types.str;
+      };
+    };
+
+    proxy = {
+      enable = mkOption {
+        description = "Whether to enable kubernetes proxy.";
+        default = false;
+        type = types.bool;
+      };
+
+      address = mkOption {
+        description = "Kubernetes proxy listening address.";
+        default = "0.0.0.0";
+        type = types.str;
+      };
+
+      extraOpts = mkOption {
+        description = "Kubernetes proxy extra command line options.";
+        default = "";
+        type = types.str;
+      };
+    };
+  };
+
+  ###### implementation
+
+  config = mkMerge [
+    (mkIf cfg.apiserver.enable {
+      systemd.services.kubernetes-apiserver = {
+        description = "Kubernetes Api Server";
+        wantedBy = [ "multi-user.target" ];
+        after = [ "network-interfaces.target" "etcd.service" ];
+        serviceConfig = {
+          ExecStart = let
+            authorizationPolicyFile =
+              pkgs.writeText "kubernetes-policy"
+                (builtins.toJSON cfg.apiserver.authorizationPolicy);
+            tokenAuthFile =
+              pkgs.writeText "kubernetes-auth"
+                (concatImapStringsSep "\n" (i: v: v + "," + (toString i))
+                    (mapAttrsToList (name: token: token + "," + name) cfg.apiserver.tokenAuth));
+          in ''${cfg.package}/bin/kube-apiserver \
+            -etcd_servers=${concatMapStringsSep "," (f: "http://${f}") cfg.etcdServers} \
+            -address=${cfg.apiserver.address} \
+            -port=${toString cfg.apiserver.port} \
+            -read_only_port=${toString cfg.apiserver.readOnlyPort} \
+            -public_address_override=${cfg.apiserver.publicAddress} \
+            -allow_privileged=${if cfg.apiserver.allowPrivileged then "true" else "false"} \
+            ${optionalString (cfg.apiserver.tlsCertFile!="")
+              "-tls_cert_file=${cfg.apiserver.tlsCertFile}"} \
+            ${optionalString (cfg.apiserver.tlsPrivateKeyFile!="")
+              "-tls_private_key_file=${cfg.apiserver.tlsPrivateKeyFile}"} \
+            ${optionalString (cfg.apiserver.tokenAuth!=[])
+              "-token_auth_file=${tokenAuthFile}"} \
+            -authorization_mode=${cfg.apiserver.authorizationMode} \
+            ${optionalString (cfg.apiserver.authorizationMode == "ABAC")
+              "-authorization_policy_file=${authorizationPolicyFile}"} \
+            ${optionalString (cfg.apiserver.tlsCertFile!="" && cfg.apiserver.tlsCertFile!="")
+              "-secure_port=${toString cfg.apiserver.securePort}"} \
+            -portal_net=${cfg.apiserver.portalNet} \
+            -logtostderr=true \
+            ${optionalString cfg.verbose "-v=6 -log_flush_frequency=1s"} \
+            ${cfg.apiserver.extraOpts}
+          '';
+          User = "kubernetes";
+        };
+        postStart = ''
+          until ${pkgs.curl}/bin/curl -s -o /dev/null 'http://${cfg.apiserver.address}:${toString cfg.apiserver.port}/'; do
+            sleep 1;
+          done
+        '';
+      };
+    })
+
+    (mkIf cfg.scheduler.enable {
+      systemd.services.kubernetes-scheduler = {
+        description = "Kubernetes Scheduler Service";
+        wantedBy = [ "multi-user.target" ];
+        after = [ "network-interfaces.target" "kubernetes-apiserver.service" ];
+        serviceConfig = {
+          ExecStart = ''${cfg.package}/bin/kube-scheduler \
+            -address=${cfg.scheduler.address} \
+            -port=${toString cfg.scheduler.port} \
+            -master=${cfg.scheduler.master} \
+            -logtostderr=true \
+            ${optionalString cfg.verbose "-v=6 -log_flush_frequency=1s"} \
+            ${cfg.scheduler.extraOpts}
+          '';
+          User = "kubernetes";
+        };
+      };
+    })
+
+    (mkIf cfg.controllerManager.enable {
+      systemd.services.kubernetes-controller-manager = {
+        description = "Kubernetes Controller Manager Service";
+        wantedBy = [ "multi-user.target" ];
+        after = [ "network-interfaces.target" "kubernetes-apiserver.service" ];
+        serviceConfig = {
+          ExecStart = ''${cfg.package}/bin/kube-controller-manager \
+            -address=${cfg.controllerManager.address} \
+            -port=${toString cfg.controllerManager.port} \
+            -master=${cfg.controllerManager.master} \
+            ${optionalString (cfg.controllerManager.machines != [])
+                "-machines=${concatStringsSep "," cfg.controllerManager.machines}"} \
+            -logtostderr=true \
+            ${optionalString cfg.verbose "-v=6 -log_flush_frequency=1s"} \
+            ${cfg.controllerManager.extraOpts}
+          '';
+          User = "kubernetes";
+        };
+      };
+    })
+
+    (mkIf cfg.kubelet.enable {
+      systemd.services.kubernetes-kubelet = {
+        description = "Kubernetes Kubelet Service";
+        wantedBy = [ "multi-user.target" ];
+        after = [ "network-interfaces.target" "etcd.service" "docker.service" ];
+        serviceConfig = {
+          ExecStart = ''${cfg.package}/bin/kubelet \
+            -etcd_servers=${concatMapStringsSep "," (f: "http://${f}") cfg.etcdServers} \
+            -address=${cfg.kubelet.address} \
+            -port=${toString cfg.kubelet.port} \
+            -hostname_override=${cfg.kubelet.hostname} \
+            -allow_privileged=${if cfg.kubelet.allowPrivileged then "true" else "false"} \
+            -root_dir=${cfg.dataDir} \
+            -logtostderr=true \
+            ${optionalString cfg.verbose "-v=6 -log_flush_frequency=1s"} \
+            ${cfg.kubelet.extraOpts}
+          '';
+          User = "kubernetes";
+          PermissionsStartOnly = true;
+          WorkingDirectory = cfg.dataDir;
+        };
+      };
+    })
+
+    (mkIf cfg.proxy.enable {
+      systemd.services.kubernetes-proxy = {
+        description = "Kubernetes Proxy Service";
+        wantedBy = [ "multi-user.target" ];
+        after = [ "network-interfaces.target" "etcd.service" ];
+        serviceConfig = {
+          ExecStart = ''${cfg.package}/bin/kube-proxy \
+            -etcd_servers=${concatMapStringsSep "," (s: "http://${s}") cfg.etcdServers} \
+            -bind_address=${cfg.proxy.address} \
+            -logtostderr=true \
+            ${optionalString cfg.verbose "-v=6 -log_flush_frequency=1s"} \
+            ${cfg.proxy.extraOpts}
+          '';
+        };
+      };
+    })
+
+    (mkIf (any (el: el == "master") cfg.roles) {
+      virtualisation.kubernetes.apiserver.enable = mkDefault true;
+      virtualisation.kubernetes.scheduler.enable = mkDefault true;
+      virtualisation.kubernetes.controllerManager.enable = mkDefault true;
+    })
+
+    (mkIf (any (el: el == "node") cfg.roles) {
+      virtualisation.docker.enable = mkDefault true;
+      virtualisation.kubernetes.kubelet.enable = mkDefault true;
+      virtualisation.kubernetes.proxy.enable = mkDefault true;
+    })
+
+    (mkIf (any (el: el == "node" || el == "master") cfg.roles) {
+      services.etcd.enable = mkDefault true;
+    })
+
+    (mkIf (
+        cfg.apiserver.enable ||
+        cfg.scheduler.enable ||
+        cfg.controllerManager.enable ||
+        cfg.kubelet.enable ||
+        cfg.proxy.enable
+    ) {
+      environment.systemPackages = [ cfg.package ];
+
+      users.extraUsers = singleton {
+        name = "kubernetes";
+        uid = config.ids.uids.kubernetes;
+        description = "Kubernetes user";
+        extraGroups = [ "docker" ];
+        group = "kubernetes";
+        home = cfg.dataDir;
+        createHome = true;
+      };
+      users.extraGroups.kubernetes.gid = config.ids.gids.kubernetes;
+    })
+
+  ];
+}
diff --git a/nixos/modules/virtualisation/virtualbox-guest.nix b/nixos/modules/virtualisation/virtualbox-guest.nix
index a5a4db797877..a0e4bd558e05 100644
--- a/nixos/modules/virtualisation/virtualbox-guest.nix
+++ b/nixos/modules/virtualisation/virtualbox-guest.nix
@@ -6,7 +6,7 @@ with lib;
 
 let
 
-  cfg = config.services.virtualbox;
+  cfg = config.services.virtualboxGuest;
   kernel = config.boot.kernelPackages;
 
 in
@@ -17,7 +17,7 @@ in
 
   options = {
 
-    services.virtualbox = {
+    services.virtualboxGuest = {
 
       enable = mkOption {
         default = false;
diff --git a/nixos/modules/virtualisation/virtualbox-image.nix b/nixos/modules/virtualisation/virtualbox-image.nix
index 106b269d9e1f..8232f6e50dfc 100644
--- a/nixos/modules/virtualisation/virtualbox-image.nix
+++ b/nixos/modules/virtualisation/virtualbox-image.nix
@@ -128,6 +128,6 @@ in {
     boot.loader.grub.version = 2;
     boot.loader.grub.device = "/dev/sda";
   
-    services.virtualbox.enable = true;
+    services.virtualboxGuest.enable = true;
   };
 }
diff --git a/nixos/release-combined.nix b/nixos/release-combined.nix
index 5173c33cab71..e850c1f6cddb 100644
--- a/nixos/release-combined.nix
+++ b/nixos/release-combined.nix
@@ -66,6 +66,14 @@ in rec {
         (all nixos.tests.misc)
         (all nixos.tests.nat.firewall)
         (all nixos.tests.nat.standalone)
+        (all nixos.tests.networking.scripted.static)
+        (all nixos.tests.networking.scripted.dhcpSimple)
+        (all nixos.tests.networking.scripted.dhcpOneIf)
+        (all nixos.tests.networking.scripted.bond)
+        (all nixos.tests.networking.scripted.bridge)
+        (all nixos.tests.networking.scripted.macvlan)
+        (all nixos.tests.networking.scripted.sit)
+        (all nixos.tests.networking.scripted.vlan)
         (all nixos.tests.nfs3)
         (all nixos.tests.openssh)
         (all nixos.tests.printing)
diff --git a/nixos/release.nix b/nixos/release.nix
index 5c08b26c3cf2..e0530276b641 100644
--- a/nixos/release.nix
+++ b/nixos/release.nix
@@ -239,8 +239,9 @@ in rec {
   tests.chromium = callTest tests/chromium.nix {};
   tests.cjdns = callTest tests/cjdns.nix {};
   tests.containers = callTest tests/containers.nix {};
-  tests.dockerRegistry = callTest tests/docker-registry.nix {};
-  tests.etcd = callTest tests/etcd.nix {};
+  tests.docker = scrubDrv (import tests/docker.nix { system = "x86_64-linux"; });
+  tests.dockerRegistry = scrubDrv (import tests/docker-registry.nix { system = "x86_64-linux"; });
+  tests.etcd = scrubDrv (import tests/etcd.nix { system = "x86_64-linux"; });
   tests.firefox = callTest tests/firefox.nix {};
   tests.firewall = callTest tests/firewall.nix {};
   tests.gnome3 = callTest tests/gnome3.nix {};
@@ -258,6 +259,7 @@ in rec {
   tests.ipv6 = callTest tests/ipv6.nix {};
   tests.jenkins = callTest tests/jenkins.nix {};
   tests.kde4 = callTest tests/kde4.nix {};
+  tests.kubernetes = scrubDrv (import tests/kubernetes.nix { system = "x86_64-linux"; });
   tests.latestKernel.login = callTest tests/login.nix { latestKernel = true; };
   tests.login = callTest tests/login.nix {};
   #tests.logstash = callTest tests/logstash.nix {};
@@ -268,9 +270,28 @@ in rec {
   tests.mysqlReplication = callTest tests/mysql-replication.nix {};
   tests.nat.firewall = callTest tests/nat.nix { withFirewall = true; };
   tests.nat.standalone = callTest tests/nat.nix { withFirewall = false; };
+  tests.networking.networkd.static = callTest tests/networking.nix { networkd = true; test = "static"; };
+  tests.networking.networkd.dhcpSimple = callTest tests/networking.nix { networkd = true; test = "dhcpSimple"; };
+  tests.networking.networkd.dhcpOneIf = callTest tests/networking.nix { networkd = true; test = "dhcpOneIf"; };
+  tests.networking.networkd.bond = callTest tests/networking.nix { networkd = true; test = "bond"; };
+  tests.networking.networkd.bridge = callTest tests/networking.nix { networkd = true; test = "bridge"; };
+  tests.networking.networkd.macvlan = callTest tests/networking.nix { networkd = true; test = "macvlan"; };
+  tests.networking.networkd.sit = callTest tests/networking.nix { networkd = true; test = "sit"; };
+  tests.networking.networkd.vlan = callTest tests/networking.nix { networkd = true; test = "vlan"; };
+  tests.networking.scripted.static = callTest tests/networking.nix { networkd = false; test = "static"; };
+  tests.networking.scripted.dhcpSimple = callTest tests/networking.nix { networkd = false; test = "dhcpSimple"; };
+  tests.networking.scripted.dhcpOneIf = callTest tests/networking.nix { networkd = false; test = "dhcpOneIf"; };
+  tests.networking.scripted.bond = callTest tests/networking.nix { networkd = false; test = "bond"; };
+  tests.networking.scripted.bridge = callTest tests/networking.nix { networkd = false; test = "bridge"; };
+  tests.networking.scripted.macvlan = callTest tests/networking.nix { networkd = false; test = "macvlan"; };
+  tests.networking.scripted.sit = callTest tests/networking.nix { networkd = false; test = "sit"; };
+  tests.networking.scripted.vlan = callTest tests/networking.nix { networkd = false; test = "vlan"; };
+  # TODO: put in networking.nix after the test becomes more complete
+  tests.networkingProxy = callTest tests/networking-proxy.nix {};
   tests.nfs3 = callTest tests/nfs.nix { version = 3; };
   tests.nsd = callTest tests/nsd.nix {};
   tests.openssh = callTest tests/openssh.nix {};
+  tests.peerflix = callTest tests/peerflix.nix {};
   tests.printing = callTest tests/printing.nix {};
   tests.proxy = callTest tests/proxy.nix {};
   tests.quake3 = callTest tests/quake3.nix {};
diff --git a/nixos/tests/docker.nix b/nixos/tests/docker.nix
new file mode 100644
index 000000000000..63c909ff294c
--- /dev/null
+++ b/nixos/tests/docker.nix
@@ -0,0 +1,24 @@
+# This test runs docker and checks if simple container starts
+
+import ./make-test.nix {
+  name = "docker";
+
+  nodes = {
+    docker =
+      { config, pkgs, ... }:
+        {
+          virtualisation.docker.enable = true;
+        };
+    };
+
+  testScript = ''
+    startAll;
+
+    $docker->waitForUnit("docker.service");
+    $docker->succeed("tar cv --files-from /dev/null | docker import - scratch");
+    $docker->succeed("docker run -d --name=sleeping -v /nix/store:/nix/store -v /run/current-system/sw/bin:/bin scratch /bin/sleep 10");
+    $docker->succeed("docker ps | grep sleeping");
+    $docker->succeed("docker stop sleeping");
+  '';
+
+}
diff --git a/nixos/tests/kubernetes.nix b/nixos/tests/kubernetes.nix
new file mode 100644
index 000000000000..e5fe8d2b8795
--- /dev/null
+++ b/nixos/tests/kubernetes.nix
@@ -0,0 +1,176 @@
+# This test runs two node kubernetes cluster and checks if simple redis pod works
+
+import ./make-test.nix rec {
+  name = "kubernetes";
+
+  redisMaster = builtins.toFile "redis-master-pod.yaml" ''
+      id: redis-master-pod
+      kind: Pod
+      apiVersion: v1beta1
+      desiredState:
+        manifest:
+          version: v1beta1
+          id: redis-master-pod
+          containers:
+            - name: master
+              image: master:5000/scratch
+              cpu: 100
+              ports:
+                - name: redis-server
+                  containerPort: 6379
+                  hostPort: 6379
+              volumeMounts:
+                - name: nix-store
+                  mountPath: /nix/store
+                  readOnly: true
+              volumeMounts:
+                - name: system-profile
+                  mountPath: /bin
+                  readOnly: true
+              command:
+                - /bin/redis-server
+          volumes:
+            - name: nix-store
+              source:
+                hostDir:
+                  path: /nix/store
+            - name: system-profile
+              source:
+                hostDir:
+                  path: /run/current-system/sw/bin
+      labels:
+        name: redis
+        role: master
+  '';
+
+  nodes = {
+    master =
+      { config, pkgs, nodes, ... }:
+        {
+          virtualisation.memorySize = 512;
+          virtualisation.kubernetes = {
+            roles = ["master" "node"];
+            controllerManager.machines = ["master" "node"];
+            kubelet.extraOpts = "-network_container_image=master:5000/pause";
+            apiserver.address = "0.0.0.0";
+            verbose = true;
+          };
+          virtualisation.docker.extraOptions = "--iptables=false --ip-masq=false -b cbr0 --insecure-registry master:5000";
+
+          services.etcd = {
+            listenPeerUrls = ["http://0.0.0.0:7001"];
+            initialAdvertisePeerUrls = ["http://master:7001"];
+            initialCluster = ["master=http://master:7001" "node=http://node:7001"];
+          };
+          services.dockerRegistry.enable = true;
+          services.dockerRegistry.host = "0.0.0.0";
+          services.dockerRegistry.port = 5000;
+
+          virtualisation.vlans = [ 1 2 ];
+          networking.bridges = {
+            cbr0.interfaces = [ "eth2" ];
+          };
+          networking.interfaces = {
+            cbr0 = {
+              ipAddress = "10.10.0.1";
+              prefixLength = 24;
+            };
+          };
+          networking.localCommands = ''
+            ip route add 10.10.0.0/16 dev cbr0
+            ip route flush cache
+          '';
+          networking.extraHosts = "127.0.0.1 master";
+
+          networking.firewall.enable = false;
+          #networking.firewall.allowedTCPPorts = [ 4001 7001 ];
+
+          environment.systemPackages = [ pkgs.redis ];
+        };
+
+    node =
+      { config, pkgs, nodes, ... }:
+        {
+          virtualisation.kubernetes = {
+            roles = ["node"];
+            kubelet.extraOpts = "-network_container_image=master:5000/pause";
+            verbose = true;
+          };
+          virtualisation.docker.extraOptions = "--iptables=false --ip-masq=false -b cbr0 --insecure-registry master:5000";
+          services.etcd = {
+            listenPeerUrls = ["http://0.0.0.0:7001"];
+            initialAdvertisePeerUrls = ["http://node:7001"];
+            initialCluster = ["master=http://master:7001" "node=http://node:7001"];
+          };
+
+          virtualisation.vlans = [ 1 2 ];
+          networking.bridges = {
+            cbr0.interfaces = [ "eth2" ];
+          };
+          networking.interfaces = {
+            cbr0 = {
+              ipAddress = "10.10.1.1";
+              prefixLength = 24;
+            };
+          };
+          networking.localCommands = ''
+            ip route add 10.10.0.0/16 dev cbr0
+            ip route flush cache
+          '';
+          networking.extraHosts = "127.0.0.1 node";
+
+          networking.firewall.enable = false;
+          #networking.firewall.allowedTCPPorts = [ 4001 7001 ];
+
+          environment.systemPackages = [ pkgs.redis ];
+        };
+
+    client =
+      { config, pkgs, nodes, ... }:
+        {
+          virtualisation.docker.enable = true;
+          virtualisation.docker.extraOptions = "--insecure-registry master:5000";
+          environment.systemPackages = [ pkgs.kubernetes ];
+          environment.etc."test/redis-master-pod.yaml".source = redisMaster;
+          environment.etc."test/pause".source = "${pkgs.kubernetes}/bin/kube-pause";
+          environment.etc."test/Dockerfile".source = pkgs.writeText "Dockerfile" ''
+            FROM scratch
+            ADD pause /
+            ENTRYPOINT ["/pause"]
+          '';
+        };
+  };
+
+  testScript = ''
+    startAll;
+
+    $master->waitForUnit("kubernetes-apiserver.service");
+    $master->waitForUnit("kubernetes-scheduler.service");
+    $master->waitForUnit("kubernetes-controller-manager.service");
+    $master->waitForUnit("kubernetes-kubelet.service");
+    $master->waitForUnit("kubernetes-proxy.service");
+
+    $node->waitForUnit("kubernetes-kubelet.service");
+    $node->waitForUnit("kubernetes-proxy.service");
+
+    $master->waitUntilSucceeds("kubecfg list minions | grep master");
+    $master->waitUntilSucceeds("kubecfg list minions | grep node");
+
+    $client->waitForUnit("docker.service");
+    $client->succeed("tar cv --files-from /dev/null | docker import - scratch");
+    $client->succeed("docker tag scratch master:5000/scratch");
+    $master->waitForUnit("docker-registry.service");
+    $client->succeed("docker push master:5000/scratch");
+    $client->succeed("mkdir -p /root/pause");
+    $client->succeed("cp /etc/test/pause /root/pause/");
+    $client->succeed("cp /etc/test/Dockerfile /root/pause/");
+    $client->succeed("cd /root/pause && docker build -t master:5000/pause .");
+    $client->succeed("docker push master:5000/pause");
+
+    subtest "simple pod", sub {
+      $client->succeed("kubectl create -f ${redisMaster} -s http://master:8080");
+      $client->waitUntilSucceeds("kubectl get pods -s http://master:8080 | grep redis-master | grep -i running");
+    }
+
+  '';
+}
diff --git a/nixos/tests/networking-proxy.nix b/nixos/tests/networking-proxy.nix
new file mode 100644
index 000000000000..30844805ebf8
--- /dev/null
+++ b/nixos/tests/networking-proxy.nix
@@ -0,0 +1,109 @@
+# Test whether `networking.proxy' work as expected.
+
+# TODO: use a real proxy node and put this test into networking.nix
+# TODO: test whether nix tools work as expected behind a proxy
+
+let default-config = {
+        imports = [ ./common/user-account.nix ];
+
+        services.xserver.enable = false;
+
+        virtualisation.memorySize = 128;
+      };
+in import ./make-test.nix {
+  name = "networking-proxy";
+
+  nodes = {
+    # no proxy
+    machine =
+      { config, pkgs, ... }:
+
+      default-config;
+
+    # proxy default
+    machine2 =
+      { config, pkgs, ... }:
+
+      default-config // {
+        networking.proxy.default = "http://user:pass@host:port";
+      };
+
+    # specific proxy options
+    machine3 =
+      { config, pkgs, ... }:
+
+      default-config //
+      {
+        networking.proxy = {
+          # useless because overriden by the next options
+          default = "http://user:pass@host:port";
+          # advanced proxy setup
+          httpProxy = "123-http://user:pass@http-host:port";
+          httpsProxy = "456-http://user:pass@https-host:port";
+          rsyncProxy = "789-http://user:pass@rsync-host:port";
+          ftpProxy = "101112-http://user:pass@ftp-host:port";
+          noProxy = "131415-127.0.0.1,localhost,.localdomain";
+        };
+      };
+
+    # mix default + proxy options
+    machine4 =
+      { config, pkgs, ... }:
+
+      default-config // {
+        networking.proxy = {
+          # open for all *_proxy env var
+          default = "000-http://user:pass@default-host:port";
+          # except for those 2
+          rsyncProxy = "123-http://user:pass@http-host:port";
+          noProxy = "131415-127.0.0.1,localhost,.localdomain";
+        };
+      };
+    };
+
+  testScript =
+    ''
+      startAll;
+
+      # no proxy at all
+      print $machine->execute("env | grep -i proxy");
+      print $machine->execute("su - alice -c 'env | grep -i proxy'");
+      $machine->mustFail("env | grep -i proxy");
+      $machine->mustFail("su - alice -c 'env | grep -i proxy'");
+
+      # Use a default proxy option
+      print $machine2->execute("env | grep -i proxy");
+      print $machine2->execute("su - alice -c 'env | grep -i proxy'");
+      $machine2->mustSucceed("env | grep -i proxy");
+      $machine2->mustSucceed("su - alice -c 'env | grep -i proxy'");
+
+      # explicitly set each proxy option
+      print $machine3->execute("env | grep -i proxy");
+      print $machine3->execute("su - alice -c 'env | grep -i proxy'");
+      $machine3->mustSucceed("env | grep -i http_proxy | grep 123");
+      $machine3->mustSucceed("env | grep -i https_proxy | grep 456");
+      $machine3->mustSucceed("env | grep -i rsync_proxy | grep 789");
+      $machine3->mustSucceed("env | grep -i ftp_proxy | grep 101112");
+      $machine3->mustSucceed("env | grep -i no_proxy | grep 131415");
+      $machine3->mustSucceed("su - alice -c 'env | grep -i http_proxy | grep 123'");
+      $machine3->mustSucceed("su - alice -c 'env | grep -i https_proxy | grep 456'");
+      $machine3->mustSucceed("su - alice -c 'env | grep -i rsync_proxy | grep 789'");
+      $machine3->mustSucceed("su - alice -c 'env | grep -i ftp_proxy | grep 101112'");
+      $machine3->mustSucceed("su - alice -c 'env | grep -i no_proxy | grep 131415'");
+
+      # set default proxy option + some other specifics
+      print $machine4->execute("env | grep -i proxy");
+      print $machine4->execute("su - alice -c 'env | grep -i proxy'");
+      $machine4->mustSucceed("env | grep -i http_proxy | grep 000");
+      $machine4->mustSucceed("env | grep -i https_proxy | grep 000");
+      $machine4->mustSucceed("env | grep -i rsync_proxy | grep 123");
+      $machine4->mustSucceed("env | grep -i ftp_proxy | grep 000");
+      $machine4->mustSucceed("env | grep -i no_proxy | grep 131415");
+      $machine4->mustSucceed("su - alice -c 'env | grep -i http_proxy | grep 000'");
+      $machine4->mustSucceed("su - alice -c 'env | grep -i https_proxy | grep 000'");
+      $machine4->mustSucceed("su - alice -c 'env | grep -i rsync_proxy | grep 123'");
+      $machine4->mustSucceed("su - alice -c 'env | grep -i ftp_proxy | grep 000'");
+      $machine4->mustSucceed("su - alice -c 'env | grep -i no_proxy | grep 131415'");
+    '';
+
+}
diff --git a/nixos/tests/networking.nix b/nixos/tests/networking.nix
new file mode 100644
index 000000000000..46d0422f9c66
--- /dev/null
+++ b/nixos/tests/networking.nix
@@ -0,0 +1,381 @@
+import ./make-test.nix ({ networkd, test, ... }:
+  let
+    router = { config, pkgs, ... }:
+      with pkgs.lib;
+      let
+        vlanIfs = range 1 (length config.virtualisation.vlans);
+      in {
+        virtualisation.vlans = [ 1 2 3 ];
+        networking = {
+          useDHCP = false;
+          useNetworkd = networkd;
+          firewall.allowPing = true;
+          interfaces = mkOverride 0 (listToAttrs (flip map vlanIfs (n:
+            nameValuePair "eth${toString n}" {
+              ipAddress = "192.168.${toString n}.1";
+              prefixLength = 24;
+            })));
+        };
+        services.dhcpd = {
+          enable = true;
+          interfaces = map (n: "eth${toString n}") vlanIfs;
+          extraConfig = ''
+            option subnet-mask 255.255.255.0;
+          '' + flip concatMapStrings vlanIfs (n: ''
+            subnet 192.168.${toString n}.0 netmask 255.255.255.0 {
+              option broadcast-address 192.168.${toString n}.255;
+              option routers 192.168.${toString n}.1;
+              range 192.168.${toString n}.2 192.168.${toString n}.254;
+            }
+          '');
+        };
+      };
+    testCases = {
+      static = {
+        name = "Static";
+        nodes.router = router;
+        nodes.client = { config, pkgs, ... }: with pkgs.lib; {
+          virtualisation.vlans = [ 1 2 ];
+          networking = {
+            useNetworkd = networkd;
+            firewall.allowPing = true;
+            useDHCP = false;
+            defaultGateway = "192.168.1.1";
+            interfaces.eth1.ip4 = mkOverride 0 [
+              { address = "192.168.1.2"; prefixLength = 24; }
+              { address = "192.168.1.3"; prefixLength = 32; }
+              { address = "192.168.1.10"; prefixLength = 32; }
+            ];
+            interfaces.eth2.ip4 = mkOverride 0 [
+              { address = "192.168.2.2"; prefixLength = 24; }
+            ];
+          };
+        };
+        testScript = { nodes, ... }:
+          ''
+            startAll;
+
+            $client->waitForUnit("network-interfaces.target");
+            $client->waitForUnit("network.target");
+            $router->waitForUnit("network-interfaces.target");
+            $router->waitForUnit("network.target");
+
+            # Make sure dhcpcd is not started
+            $client->fail("systemctl status dhcpcd.service");
+
+            # Test vlan 1
+            $client->succeed("ping -c 1 192.168.1.1");
+            $client->succeed("ping -c 1 192.168.1.2");
+            $client->succeed("ping -c 1 192.168.1.3");
+            $client->succeed("ping -c 1 192.168.1.10");
+
+            $router->succeed("ping -c 1 192.168.1.1");
+            $router->succeed("ping -c 1 192.168.1.2");
+            $router->succeed("ping -c 1 192.168.1.3");
+            $router->succeed("ping -c 1 192.168.1.10");
+
+            # Test vlan 2
+            $client->succeed("ping -c 1 192.168.2.1");
+            $client->succeed("ping -c 1 192.168.2.2");
+
+            $router->succeed("ping -c 1 192.168.2.1");
+            $router->succeed("ping -c 1 192.168.2.2");
+
+            # Test default gateway
+            $router->succeed("ping -c 1 192.168.3.1");
+            $client->succeed("ping -c 1 192.168.3.1");
+          '';
+      };
+      dhcpSimple = {
+        name = "SimpleDHCP";
+        nodes.router = router;
+        nodes.client = { config, pkgs, ... }: with pkgs.lib; {
+          virtualisation.vlans = [ 1 2 ];
+          networking = {
+            useNetworkd = networkd;
+            firewall.allowPing = true;
+            useDHCP = true;
+            interfaces.eth1.ip4 = mkOverride 0 [ ];
+            interfaces.eth2.ip4 = mkOverride 0 [ ];
+          };
+        };
+        testScript = { nodes, ... }:
+          ''
+            startAll;
+
+            $client->waitForUnit("network-interfaces.target");
+            $client->waitForUnit("network.target");
+            $router->waitForUnit("network-interfaces.target");
+            $router->waitForUnit("network.target");
+
+            # Wait until we have an ip address on each interface
+            $client->succeed("while ! ip addr show dev eth1 | grep '192.168.1'; do true; done");
+            $client->succeed("while ! ip addr show dev eth2 | grep '192.168.2'; do true; done");
+
+            # Test vlan 1
+            $client->succeed("ping -c 1 192.168.1.1");
+            $client->succeed("ping -c 1 192.168.1.2");
+
+            $router->succeed("ping -c 1 192.168.1.1");
+            $router->succeed("ping -c 1 192.168.1.2");
+
+            # Test vlan 2
+            $client->succeed("ping -c 1 192.168.2.1");
+            $client->succeed("ping -c 1 192.168.2.2");
+
+            $router->succeed("ping -c 1 192.168.2.1");
+            $router->succeed("ping -c 1 192.168.2.2");
+          '';
+      };
+      dhcpOneIf = {
+        name = "OneInterfaceDHCP";
+        nodes.router = router;
+        nodes.client = { config, pkgs, ... }: with pkgs.lib; {
+          virtualisation.vlans = [ 1 2 ];
+          networking = {
+            useNetworkd = networkd;
+            firewall.allowPing = true;
+            useDHCP = false;
+            interfaces.eth1 = {
+              ip4 = mkOverride 0 [ ];
+              useDHCP = true;
+            };
+            interfaces.eth2.ip4 = mkOverride 0 [ ];
+          };
+        };
+        testScript = { nodes, ... }:
+          ''
+            startAll;
+
+            $client->waitForUnit("network-interfaces.target");
+            $client->waitForUnit("network.target");
+            $router->waitForUnit("network-interfaces.target");
+            $router->waitForUnit("network.target");
+
+            # Wait until we have an ip address on each interface
+            $client->succeed("while ! ip addr show dev eth1 | grep '192.168.1'; do true; done");
+
+            # Test vlan 1
+            $client->succeed("ping -c 1 192.168.1.1");
+            $client->succeed("ping -c 1 192.168.1.2");
+
+            $router->succeed("ping -c 1 192.168.1.1");
+            $router->succeed("ping -c 1 192.168.1.2");
+
+            # Test vlan 2
+            $client->succeed("ping -c 1 192.168.2.1");
+            $client->fail("ping -c 1 192.168.2.2");
+
+            $router->succeed("ping -c 1 192.168.2.1");
+            $router->fail("ping -c 1 192.168.2.2");
+          '';
+      };
+      bond = let
+        node = address: { config, pkgs, ... }: with pkgs.lib; {
+          virtualisation.vlans = [ 1 2 ];
+          networking = {
+            useNetworkd = networkd;
+            firewall.allowPing = true;
+            useDHCP = false;
+            bonds.bond = {
+              mode = "balance-rr";
+              interfaces = [ "eth1" "eth2" ];
+            };
+            interfaces.eth1.ip4 = mkOverride 0 [ ];
+            interfaces.eth2.ip4 = mkOverride 0 [ ];
+            interfaces.bond.ip4 = mkOverride 0
+              [ { inherit address; prefixLength = 30; } ];
+          };
+        };
+      in {
+        name = "Bond";
+        nodes.client1 = node "192.168.1.1";
+        nodes.client2 = node "192.168.1.2";
+        testScript = { nodes, ... }:
+          ''
+            startAll;
+
+            $client1->waitForUnit("network-interfaces.target");
+            $client1->waitForUnit("network.target");
+            $client2->waitForUnit("network-interfaces.target");
+            $client2->waitForUnit("network.target");
+
+            # Test bonding
+            $client1->succeed("ping -c 2 192.168.1.1");
+            $client1->succeed("ping -c 2 192.168.1.2");
+
+            $client2->succeed("ping -c 2 192.168.1.1");
+            $client2->succeed("ping -c 2 192.168.1.2");
+          '';
+      };
+      bridge = let
+        node = { address, vlan }: { config, pkgs, ... }: with pkgs.lib; {
+          virtualisation.vlans = [ vlan ];
+          networking = {
+            useNetworkd = networkd;
+            firewall.allowPing = true;
+            useDHCP = false;
+            interfaces.eth1.ip4 = mkOverride 0
+              [ { inherit address; prefixLength = 24; } ];
+          };
+        };
+      in {
+        name = "Bridge";
+        nodes.client1 = node { address = "192.168.1.2"; vlan = 1; };
+        nodes.client2 = node { address = "192.168.1.3"; vlan = 2; };
+        nodes.router = { config, pkgs, ... }: with pkgs.lib; {
+          virtualisation.vlans = [ 1 2 ];
+          networking = {
+            useNetworkd = networkd;
+            firewall.allowPing = true;
+            useDHCP = false;
+            bridges.bridge.interfaces = [ "eth1" "eth2" ];
+            interfaces.eth1.ip4 = mkOverride 0 [ ];
+            interfaces.eth2.ip4 = mkOverride 0 [ ];
+            interfaces.bridge.ip4 = mkOverride 0
+              [ { address = "192.168.1.1"; prefixLength = 24; } ];
+          };
+        };
+        testScript = { nodes, ... }:
+          ''
+            startAll;
+
+            $client1->waitForUnit("network-interfaces.target");
+            $client1->waitForUnit("network.target");
+            $client2->waitForUnit("network-interfaces.target");
+            $client2->waitForUnit("network.target");
+            $router->waitForUnit("network-interfaces.target");
+            $router->waitForUnit("network.target");
+
+            # Test bridging
+            $client1->succeed("ping -c 1 192.168.1.1");
+            $client1->succeed("ping -c 1 192.168.1.2");
+            $client1->succeed("ping -c 1 192.168.1.3");
+
+            $client2->succeed("ping -c 1 192.168.1.1");
+            $client2->succeed("ping -c 1 192.168.1.2");
+            $client2->succeed("ping -c 1 192.168.1.3");
+
+            $router->succeed("ping -c 1 192.168.1.1");
+            $router->succeed("ping -c 1 192.168.1.2");
+            $router->succeed("ping -c 1 192.168.1.3");
+          '';
+      };
+      macvlan = {
+        name = "MACVLAN";
+        nodes.router = router;
+        nodes.client = { config, pkgs, ... }: with pkgs.lib; {
+          virtualisation.vlans = [ 1 ];
+          networking = {
+            useNetworkd = networkd;
+            firewall.allowPing = true;
+            useDHCP = true;
+            macvlans.macvlan.interface = "eth1";
+            interfaces.eth1.ip4 = mkOverride 0 [ ];
+          };
+        };
+        testScript = { nodes, ... }:
+          ''
+            startAll;
+
+            $client->waitForUnit("network-interfaces.target");
+            $client->waitForUnit("network.target");
+            $router->waitForUnit("network-interfaces.target");
+            $router->waitForUnit("network.target");
+
+            # Wait until we have an ip address on each interface
+            $client->succeed("while ! ip addr show dev eth1 | grep '192.168.1'; do true; done");
+            $client->succeed("while ! ip addr show dev macvlan | grep '192.168.1'; do true; done");
+
+            # Test macvlan
+            $client->succeed("ping -c 1 192.168.1.1");
+            $client->succeed("ping -c 1 192.168.1.2");
+            $client->succeed("ping -c 1 192.168.1.3");
+
+            $router->succeed("ping -c 1 192.168.1.1");
+            $router->succeed("ping -c 1 192.168.1.2");
+            $router->succeed("ping -c 1 192.168.1.3");
+          '';
+      };
+      sit = let
+        node = { address4, remote, address6 }: { config, pkgs, ... }: with pkgs.lib; {
+          virtualisation.vlans = [ 1 ];
+          networking = {
+            useNetworkd = networkd;
+            firewall.enable = false;
+            useDHCP = false;
+            sits.sit = {
+              inherit remote;
+              local = address4;
+              dev = "eth1";
+            };
+            interfaces.eth1.ip4 = mkOverride 0
+              [ { address = address4; prefixLength = 24; } ];
+            interfaces.sit.ip6 = mkOverride 0
+              [ { address = address6; prefixLength = 64; } ];
+          };
+        };
+      in {
+        name = "Sit";
+        nodes.client1 = node { address4 = "192.168.1.1"; remote = "192.168.1.2"; address6 = "fc00::1"; };
+        nodes.client2 = node { address4 = "192.168.1.2"; remote = "192.168.1.1"; address6 = "fc00::2"; };
+        testScript = { nodes, ... }:
+          ''
+            startAll;
+
+            $client1->waitForUnit("network-interfaces.target");
+            $client1->waitForUnit("network.target");
+            $client2->waitForUnit("network-interfaces.target");
+            $client2->waitForUnit("network.target");
+
+            $client1->succeed("ip addr >&2");
+            $client2->succeed("ip addr >&2");
+
+            # Test ipv6
+            $client1->succeed("ping6 -c 1 fc00::1");
+            $client1->succeed("ping6 -c 1 fc00::2");
+
+            $client2->succeed("ping6 -c 1 fc00::1");
+            $client2->succeed("ping6 -c 1 fc00::2");
+          '';
+      };
+      vlan = let
+        node = address: { config, pkgs, ... }: with pkgs.lib; {
+          #virtualisation.vlans = [ 1 ];
+          networking = {
+            useNetworkd = networkd;
+            firewall.allowPing = true;
+            useDHCP = false;
+            vlans.vlan = {
+              id = 1;
+              interface = "eth0";
+            };
+            interfaces.eth0.ip4 = mkOverride 0 [ ];
+            interfaces.eth1.ip4 = mkOverride 0 [ ];
+            interfaces.vlan.ip4 = mkOverride 0
+              [ { inherit address; prefixLength = 24; } ];
+          };
+        };
+      in {
+        name = "vlan";
+        nodes.client1 = node "192.168.1.1";
+        nodes.client2 = node "192.168.1.2";
+        testScript = { nodes, ... }:
+          ''
+            startAll;
+
+            $client1->waitForUnit("network-interfaces.target");
+            $client1->waitForUnit("network.target");
+            $client2->waitForUnit("network-interfaces.target");
+            $client2->waitForUnit("network.target");
+
+            # Test vlan is setup
+            $client1->succeed("ip addr show dev vlan >&2");
+            $client2->succeed("ip addr show dev vlan >&2");
+          '';
+      };
+    };
+    case = testCases.${test};
+  in case // {
+    name = "${case.name}-Networking-${if networkd then "Networkd" else "Scripted"}";
+  })
diff --git a/nixos/tests/nfs.nix b/nixos/tests/nfs.nix
index 61b2431c04c7..5ed805a16952 100644
--- a/nixos/tests/nfs.nix
+++ b/nixos/tests/nfs.nix
@@ -38,7 +38,8 @@ in
   testScript =
     ''
       $server->waitForUnit("nfsd");
-      $server->waitForUnit("network.target");
+      $server->succeed("systemctl start network-online.target");
+      $server->waitForUnit("network-online.target");
 
       startAll;
 
diff --git a/nixos/tests/peerflix.nix b/nixos/tests/peerflix.nix
new file mode 100644
index 000000000000..739936a10b23
--- /dev/null
+++ b/nixos/tests/peerflix.nix
@@ -0,0 +1,21 @@
+# This test runs peerflix and checks if peerflix starts
+
+import ./make-test.nix {
+  name = "peerflix";
+
+  nodes = {
+    peerflix =
+      { config, pkgs, ... }:
+        {
+          services.peerflix.enable = true;
+        };
+    };
+
+  testScript = ''
+    startAll;
+
+    $peerflix->waitForUnit("peerflix.service");
+    $peerflix->waitUntilSucceeds("curl localhost:9000");
+  '';
+
+}
diff --git a/nixos/tests/printing.nix b/nixos/tests/printing.nix
index a55e077c2696..79f4db3257aa 100644
--- a/nixos/tests/printing.nix
+++ b/nixos/tests/printing.nix
@@ -9,7 +9,7 @@ import ./make-test.nix ({pkgs, ... }: {
       { config, pkgs, ... }:
       { services.printing.enable = true;
         services.printing.listenAddresses = [ "*:631" ];
-        services.printing.cupsdConf =
+        services.printing.extraConf =
           ''
             <Location />
               Order allow,deny
@@ -40,10 +40,10 @@ import ./make-test.nix ({pkgs, ... }: {
       $server->fail("curl --fail --connect-timeout 2  http://client:631/");
 
       # Add a HP Deskjet printer connected via USB to the server.
-      $server->succeed("lpadmin -p DeskjetLocal -v usb://HP/Deskjet%205400%20series?serial=TH93I152S123XY -m 'drv:///sample.drv/deskjet.ppd' -E");
+      $server->succeed("lpadmin -p DeskjetLocal -E -v usb://foobar/printers/foobar");
 
       # Add it to the client as well via IPP.
-      $client->succeed("lpadmin -p DeskjetRemote -v ipp://server/printers/DeskjetLocal -m 'drv:///sample.drv/deskjet.ppd' -E");
+      $client->succeed("lpadmin -p DeskjetRemote -E -v ipp://server/printers/DeskjetLocal");
       $client->succeed("lpadmin -d DeskjetRemote");
 
       # Do some status checks.
@@ -55,7 +55,7 @@ import ./make-test.nix ({pkgs, ... }: {
       $client->succeed("lpq") =~ /DeskjetRemote is ready.*no entries/s or die;
 
       # Test printing various file types.
-      foreach my $file ("${pkgs.groff}/share/doc/*/examples/mom/typesetting.pdf",
+      foreach my $file ("${pkgs.groff}/share/doc/*/examples/mom/penguin.pdf",
                         "${pkgs.groff}/share/doc/*/meref.ps",
                         "${pkgs.cups}/share/doc/cups/images/cups.png",
                         "${pkgs.xz}/share/doc/xz/faq.txt")
@@ -72,9 +72,8 @@ import ./make-test.nix ({pkgs, ... }: {
               # (showing that the right filters have been applied).  Of
               # course, since there is no actual USB printer attached, the
               # file will stay in the queue forever.
-              $server->waitForFile("/var/spool/cups/d*-*");
-              $server->succeed("lpq -a") =~ /remroot.*$fn/ or die;
-              $server->succeed("hexdump -C -n2 /var/spool/cups/d*-*") =~ /1b 45/ or die; # 1b 45 = printer reset
+              $server->waitForFile("/var/spool/cups/d00001-001");
+              $server->succeed("lpq -a") =~ /$fn/ or die;
 
               # Delete the job on the client.  It should disappear on the
               # server as well.