Split the monolithic network-interface service into multiple units

For each statically configured interface, we now create a unit
‘<interface>-cfg.service’ which gets started as soon as the network
device comes up.  Similarly, each bridge defined in
‘networking.bridges’ and virtual interface in ‘networking.interfaces’
is created by a service ‘<interface>.service’.

So if we have

  networking.bridges.br0.interfaces = [ "eth0" "eth1" ];
  networking.interfaces =
    [ { name = "br0";
        ipAddress = "192.168.1.1";
      }
    ];

then there will be a unit ‘br0.service’ that depends on
‘sys-subsystem-net-devices-eth0.device’ and
‘sys-subsystem-net-devices-eth1.device’, and a unit ‘br0-cfg.service’
that depends on ‘sys-subsystem-net-devices-br0.device’.
This commit is contained in:
Eelco Dolstra 2012-10-10 17:55:42 -04:00
parent 62b707de07
commit d7458b5fc2
3 changed files with 102 additions and 67 deletions

View File

@ -138,7 +138,7 @@ in
};
services.printing.drivers =
[ pkgs.cups pkgs.cups_pdf_filter pkgs.ghostscript additionalBackends pkgs.perl pkgs.coreutils pkgs.gnused ];
[ pkgs.cups /* pkgs.cups_pdf_filter */ pkgs.ghostscript additionalBackends pkgs.perl pkgs.coreutils pkgs.gnused ];
services.printing.cupsdConf =
''

View File

@ -7,7 +7,7 @@ let
cfg = config.boot.systemd;
systemd = pkgs.systemd;
systemd = pkgs.systemd_tmp;
makeUnit = name: unit:
pkgs.writeTextFile { name = "unit"; inherit (unit) text; destination = "/${name}"; };

View File

@ -248,64 +248,6 @@ in
''
set +e # continue in case of errors
# Create virtual network interfaces
${flip concatMapStrings cfg.interfaces (i:
optionalString i.virtual
''
echo "Creating virtual network interface ${i.name}..."
${pkgs.tunctl}/bin/tunctl -t "${i.name}" -u "${i.virtualOwner}"
'')
}
# Set MAC addresses of interfaces, if desired.
${flip concatMapStrings cfg.interfaces (i:
optionalString (i.macAddress != "")
''
echo "Setting MAC address of ${i.name} to ${i.macAddress}..."
ip link set "${i.name}" address "${i.macAddress}"
'')
}
for i in $(cd /sys/class/net && ls -d *); do
echo "Bringing up network device $i..."
ip link set "$i" up
done
# Create bridge devices.
${concatStrings (attrValues (flip mapAttrs cfg.bridges (n: v: ''
echo "Creating bridge ${n}..."
${pkgs.bridge_utils}/sbin/brctl addbr "${n}"
# Set bridge's hello time to 0 to avoid startup delays.
${pkgs.bridge_utils}/sbin/brctl setfd "${n}" 0
${flip concatMapStrings v.interfaces (i: ''
${pkgs.bridge_utils}/sbin/brctl addif "${n}" "${i}"
ip addr flush dev "${i}"
'')}
# !!! Should delete (brctl delif) any interfaces that
# no longer belong to the bridge.
'')))}
# Configure the manually specified interfaces.
${flip concatMapStrings cfg.interfaces (i:
optionalString (i.ipAddress != "")
''
echo "Configuring interface ${i.name}..."
ip addr add "${i.ipAddress}""${optionalString (i.subnetMask != "") ("/" + i.subnetMask)}" \
dev "${i.name}"
'' +
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
'')
}
# Set the static DNS configuration, if given.
cat | ${pkgs.openresolv}/sbin/resolvconf -a static <<EOF
${optionalString (cfg.nameservers != [] && cfg.domain != "") ''
@ -318,24 +260,117 @@ in
# Set the default gateway.
${optionalString (cfg.defaultGateway != "") ''
ip route add default via "${cfg.defaultGateway}"
ip route add default via "${cfg.defaultGateway}"
''}
# turn on forwarding if any interface has enabled proxy_arp
# Turn on forwarding if any interface has enabled proxy_arp.
${optionalString (any (i: i.proxyARP) cfg.interfaces) ''
echo 1 > /proc/sys/net/ipv4/ip_forward
''}
# Run any user-specified commands.
${pkgs.stdenv.shell} ${pkgs.writeText "local-net-cmds" cfg.localCommands}
${optionalString (cfg.interfaces != [] || cfg.localCommands != "") ''
# Start the ip-up target (e.g. to start ntpd).
${config.system.build.systemd}/bin/systemctl start ip-up.target
''}
'';
};
boot.systemd.services =
let
# 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: nameValuePair "${i.name}-cfg"
{ description = "Configuration of ${i.name}";
wantedBy = [ "network.target" ];
wants = [ "${i.name}.service" ];
bindsTo = [ "sys-subsystem-net-devices-${i.name}.device" ];
after = [ "${i.name}.service" "sys-subsystem-net-devices-${i.name}.device" ];
serviceConfig.Type = "oneshot";
serviceConfig.RemainAfterExit = true;
path = [ pkgs.iproute ];
script =
''
echo "bringing up interface..."
ip link set "${i.name}" up
''
+ optionalString (i.macAddress != "")
''
echo "setting MAC address to ${i.macAddress}..."
ip link set "${i.name}" address "${i.macAddress}"
''
+ optionalString (i.ipAddress != "")
''
echo "configuring interface..."
ip addr flush dev "${i.name}"
ip addr add "${i.ipAddress}""${optionalString (i.subnetMask != "") ("/" + i.subnetMask)}" \
dev "${i.name}"
${config.system.build.systemd}/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
'';
};
createTunDevice = i: nameValuePair "${i.name}"
{ description = "Virtual Network Interface ${i.name}";
wantedBy = [ "network.target" ];
serviceConfig =
{ Type = "oneshot";
RemainAfterExit = true;
ExecStart = "${pkgs.tunctl}/bin/tunctl -t '${i.name}' -u '${i.virtualOwner}'";
ExecStop = "${pkgs.tunctl}/bin/tunctl -d '${i.name}'";
};
};
createBridgeDevice = n: v:
let
deps = map (i: "sys-subsystem-net-devices-${i}.device") v.interfaces;
in
{ description = "Bridge Interface ${n}";
wantedBy = [ "network.target" ];
wants = map (i: "${i}.service") v.interfaces;
bindsTo = deps;
after = deps;
serviceConfig.Type = "oneshot";
serviceConfig.RemainAfterExit = true;
path = [ pkgs.bridge_utils pkgs.iproute ];
script =
''
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 addr flush dev "${i}"
'')}
# !!! Should delete (brctl delif) any interfaces that
# no longer belong to the bridge.
'';
postStop =
''
ip link set "${n}" down
brctl delbr "${n}"
'';
};
in listToAttrs (
map configureInterface cfg.interfaces ++
map createTunDevice (filter (i: i.virtual) cfg.interfaces))
// mapAttrs createBridgeDevice cfg.bridges;
# Set the host name in the activation script. Don't clear it if
# it's not configured in the NixOS configuration, since it may
# have been set by dhclient in the meantime.