Turn networking.interfaces into an attribute set

Thus

  networking.interfaces = [ { name = "eth0"; ipAddress = "192.168.15.1"; } ];

can now be written as

  networking.interfaces.eth0.ipAddress = "192.168.15.1";

The old notation still works though.
This commit is contained in:
Eelco Dolstra 2012-11-02 17:08:11 +01:00
parent 93f82dfeef
commit 97f087cd44
7 changed files with 138 additions and 143 deletions

View File

@ -2,7 +2,7 @@
let pkgs = import <nixpkgs> { config = {}; inherit system; }; in let pkgs = import <nixpkgs> { config = {}; inherit system; }; in
with pkgs; with pkgs.lib;
with import ../lib/qemu-flags.nix; with import ../lib/qemu-flags.nix;
rec { rec {
@ -15,7 +15,7 @@ rec {
# hostname and `configX' is a NixOS system configuration. Each # hostname and `configX' is a NixOS system configuration. Each
# machine is given an arbitrary IP address in the virtual network. # machine is given an arbitrary IP address in the virtual network.
buildVirtualNetwork = buildVirtualNetwork =
nodes: let nodesOut = lib.mapAttrs (n: buildVM nodesOut) (assignIPAddresses nodes); in nodesOut; nodes: let nodesOut = mapAttrs (n: buildVM nodesOut) (assignIPAddresses nodes); in nodesOut;
buildVM = buildVM =
@ -27,7 +27,7 @@ rec {
[ ../modules/virtualisation/qemu-vm.nix [ ../modules/virtualisation/qemu-vm.nix
../modules/testing/test-instrumentation.nix # !!! should only get added for automated test runs ../modules/testing/test-instrumentation.nix # !!! should only get added for automated test runs
{ key = "no-manual"; services.nixosManual.enable = false; } { key = "no-manual"; services.nixosManual.enable = false; }
] ++ lib.optional minimal ../modules/testing/minimal-kernel.nix; ] ++ optional minimal ../modules/testing/minimal-kernel.nix;
extraArgs = { inherit nodes; }; extraArgs = { inherit nodes; };
}; };
@ -39,51 +39,49 @@ rec {
let let
machines = lib.attrNames nodes; machines = attrNames nodes;
machinesNumbered = lib.zipTwoLists machines (lib.range 1 254); machinesNumbered = zipTwoLists machines (range 1 254);
nodes_ = lib.flip map machinesNumbered (m: lib.nameValuePair m.first nodes_ = flip map machinesNumbered (m: nameValuePair m.first
[ ( { config, pkgs, nodes, ... }: [ ( { config, pkgs, nodes, ... }:
let let
interfacesNumbered = lib.zipTwoLists config.virtualisation.vlans (lib.range 1 255); interfacesNumbered = zipTwoLists config.virtualisation.vlans (range 1 255);
interfaces = interfaces = flip map interfacesNumbered ({ first, second }:
lib.flip map interfacesNumbered ({ first, second }: nameValuePair "eth${toString second}"
{ name = "eth${toString second}"; { ipAddress = "192.168.${toString first}.${toString m.second}";
ipAddress = "192.168.${toString first}.${toString m.second}";
subnetMask = "255.255.255.0"; subnetMask = "255.255.255.0";
} });
);
in in
{ key = "ip-address"; { key = "ip-address";
config = config =
{ networking.hostName = m.first; { networking.hostName = m.first;
networking.interfaces = interfaces; networking.interfaces = listToAttrs interfaces;
networking.primaryIPAddress = networking.primaryIPAddress =
lib.optionalString (interfaces != []) (lib.head interfaces).ipAddress; optionalString (interfaces != []) (head interfaces).value.ipAddress;
# Put the IP addresses of all VMs in this machine's # Put the IP addresses of all VMs in this machine's
# /etc/hosts file. If a machine has multiple # /etc/hosts file. If a machine has multiple
# interfaces, use the IP address corresponding to # interfaces, use the IP address corresponding to
# the first interface (i.e. the first network in its # the first interface (i.e. the first network in its
# virtualisation.vlans option). # virtualisation.vlans option).
networking.extraHosts = lib.flip lib.concatMapStrings machines networking.extraHosts = flip concatMapStrings machines
(m: let config = (lib.getAttr m nodes).config; in (m: let config = (getAttr m nodes).config; in
lib.optionalString (config.networking.primaryIPAddress != "") optionalString (config.networking.primaryIPAddress != "")
("${config.networking.primaryIPAddress} " + ("${config.networking.primaryIPAddress} " +
"${config.networking.hostName}\n")); "${config.networking.hostName}\n"));
virtualisation.qemu.options = virtualisation.qemu.options =
lib.flip map interfacesNumbered flip map interfacesNumbered
({ first, second }: qemuNICFlags second first m.second); ({ first, second }: qemuNICFlags second first m.second);
}; };
} }
) )
(lib.getAttr m.first nodes) (getAttr m.first nodes)
] ); ] );
in lib.listToAttrs nodes_; in listToAttrs nodes_;
} }

View File

@ -37,5 +37,5 @@ let virtualbox = config.boot.kernelPackages.virtualbox; in
''; '';
}; };
networking.interfaces = [ { name = "vboxnet0"; ipAddress = "192.168.56.1"; prefixLength = 24; } ]; networking.interfaces.vboxnet0 = { ipAddress = "192.168.56.1"; prefixLength = 24; };
} }

View File

@ -9,7 +9,7 @@ let
# Don't start dhclient on explicitly configured interfaces or on # Don't start dhclient on explicitly configured interfaces or on
# interfaces that are part of a bridge. # interfaces that are part of a bridge.
ignoredInterfaces = ignoredInterfaces =
map (i: i.name) (filter (i: i ? ipAddress && i.ipAddress != "" ) config.networking.interfaces) map (i: i.name) (filter (i: i.ipAddress != null) (attrValues config.networking.interfaces))
++ concatLists (attrValues (mapAttrs (n: v: v.interfaces) config.networking.bridges)) ++ concatLists (attrValues (mapAttrs (n: v: v.interfaces) config.networking.bridges))
++ config.networking.dhcpcd.denyInterfaces; ++ config.networking.dhcpcd.denyInterfaces;
@ -104,6 +104,7 @@ in
ExecStart = "@${dhcpcd}/sbin/dhcpcd dhcpcd --config ${dhcpcdConf}"; ExecStart = "@${dhcpcd}/sbin/dhcpcd dhcpcd --config ${dhcpcdConf}";
ExecReload = "${dhcpcd}/sbin/dhcpcd --rebind"; ExecReload = "${dhcpcd}/sbin/dhcpcd --rebind";
StandardError = "null"; StandardError = "null";
Restart = "always";
}; };
}; };

View File

@ -5,7 +5,104 @@ with pkgs.lib;
let let
cfg = config.networking; cfg = config.networking;
hasVirtuals = any (i: i.virtual) cfg.interfaces; interfaces = attrValues cfg.interfaces;
hasVirtuals = any (i: i.virtual) interfaces;
interfaceOpts = { name, ... }: {
options = {
name = mkOption {
example = "eth0";
type = types.string;
description = "Name of the interface.";
};
ipAddress = mkOption {
default = null;
example = "10.0.0.1";
type = types.nullOr types.string;
description = ''
IP address of the interface. Leave empty to configure the
interface using DHCP.
'';
};
prefixLength = mkOption {
default = null;
example = 24;
type = types.nullOr types.int;
description = ''
Subnet mask of the interface, specified as the number of
bits in the prefix (<literal>24</literal>).
'';
};
subnetMask = mkOption {
default = "";
example = "255.255.255.0";
type = types.string;
description = ''
Subnet mask of the interface, specified as a bitmask.
This is deprecated; use <option>prefixLength</option>
instead.
'';
};
macAddress = mkOption {
default = null;
example = "00:11:22:33:44:55";
type = types.nullOr types.string;
description = ''
MAC address of the interface. Leave empty to use the default.
'';
};
virtual = mkOption {
default = false;
type = types.bool;
description = ''
Whether this interface is virtual and should be created by tunctl.
This is mainly useful for creating bridges between a host a virtual
network such as VPN or a virtual machine.
Defaults to tap device, unless interface contains "tun" in its name.
'';
};
virtualOwner = mkOption {
default = "root";
type = types.uniq types.string;
description = ''
In case of a virtual device, the user who owns it.
'';
};
proxyARP = mkOption {
default = false;
type = types.bool;
description = ''
Turn on proxy_arp for this device (and proxy_ndp for ipv6).
This is mainly useful for creating pseudo-bridges between a real
interface and a virtual network such as VPN or a virtual machine for
interfaces that don't support real bridging (most wlan interfaces).
As ARP proxying acts slightly above the link-layer, below-ip traffic
isn't bridged, so things like DHCP won't work. The advantage above
using NAT lies in the fact that no IP addresses are shared, so all
hosts are reachable/routeable.
WARNING: turns on ip-routing, so if you have multiple interfaces, you
should think of the consequence and setup firewall rules to limit this.
'';
};
};
config = {
name = mkDefault name;
};
};
in in
@ -66,121 +163,20 @@ in
}; };
networking.interfaces = mkOption { networking.interfaces = mkOption {
default = []; default = {};
example = [ example =
{ name = "eth0"; { eth0 = {
ipAddress = "131.211.84.78"; ipAddress = "131.211.84.78";
subnetMask = "255.255.255.128"; subnetMask = "255.255.255.128";
} };
]; };
description = '' description = ''
The configuration for each network interface. If The configuration for each network interface. If
<option>networking.useDHCP</option> is true, then every <option>networking.useDHCP</option> is true, then every
interface not listed here will be configured using DHCP. interface not listed here will be configured using DHCP.
''; '';
type = types.loaOf types.optionSet;
type = types.list types.optionSet; options = [ interfaceOpts ];
options = {
name = mkOption {
example = "eth0";
type = types.string;
description = ''
Name of the interface.
'';
};
ipAddress = mkOption {
default = "";
example = "10.0.0.1";
type = types.string;
description = ''
IP address of the interface. Leave empty to configure the
interface using DHCP.
'';
};
prefixLength = mkOption {
default = null;
example = 24;
type = types.nullOr types.int;
description = ''
Subnet mask of the interface, specified as the number of
bits in the prefix (<literal>24</literal>).
'';
};
subnetMask = mkOption {
default = "";
example = "255.255.255.0";
type = types.string;
description = ''
Subnet mask of the interface, specified as a bitmask.
This is deprecated; use <option>prefixLength</option>
instead.
'';
};
macAddress = mkOption {
default = "";
example = "00:11:22:33:44:55";
type = types.string;
description = ''
MAC address of the interface. Leave empty to use the default.
'';
};
virtual = mkOption {
default = false;
type = types.bool;
description = ''
Whether this interface is virtual and should be created by tunctl.
This is mainly useful for creating bridges between a host a virtual
network such as VPN or a virtual machine.
Defaults to tap device, unless interface contains "tun" in its name.
'';
};
virtualOwner = mkOption {
default = "root";
type = types.uniq types.string;
description = ''
In case of a virtual device, the user who owns it.
'';
};
proxyARP = mkOption {
default = false;
type = types.bool;
description = ''
Turn on proxy_arp for this device (and proxy_ndp for ipv6).
This is mainly useful for creating pseudo-bridges between a real
interface and a virtual network such as VPN or a virtual machine for
interfaces that don't support real bridging (most wlan interfaces).
As ARP proxying acts slightly above the link-layer, below-ip traffic
isn't bridged, so things like DHCP won't work. The advantage above
using NAT lies in the fact that no IP addresses are shared, so all
hosts are reachable/routeable.
WARNING: turns on ip-routing, so if you have multiple interfaces, you
should think of the consequence and setup firewall rules to limit this.
'';
};
};
};
networking.ifaces = mkOption {
default = listToAttrs
(map (iface: { name = iface.name; value = iface; }) config.networking.interfaces);
internal = true;
description = ''
The network interfaces in <option>networking.interfaces</option>
as an attribute set keyed on the interface name.
'';
}; };
networking.bridges = mkOption { networking.bridges = mkOption {
@ -288,7 +284,7 @@ in
''} ''}
# 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) '' ${optionalString (any (i: i.proxyARP) interfaces) ''
echo 1 > /proc/sys/net/ipv4/ip_forward echo 1 > /proc/sys/net/ipv4/ip_forward
''} ''}
@ -322,12 +318,12 @@ in
echo "bringing up interface..." echo "bringing up interface..."
ip link set "${i.name}" up ip link set "${i.name}" up
'' ''
+ optionalString (i.macAddress != "") + optionalString (i.macAddress != null)
'' ''
echo "setting MAC address to ${i.macAddress}..." echo "setting MAC address to ${i.macAddress}..."
ip link set "${i.name}" address "${i.macAddress}" ip link set "${i.name}" address "${i.macAddress}"
'' ''
+ optionalString (i.ipAddress != "") + optionalString (i.ipAddress != null)
'' ''
cur=$(ip -4 -o a show dev "${i.name}" | awk '{print $4}') cur=$(ip -4 -o a show dev "${i.name}" | awk '{print $4}')
# Only do a flush/add if it's necessary. This is # Only do a flush/add if it's necessary. This is
@ -400,8 +396,8 @@ in
}; };
in listToAttrs ( in listToAttrs (
map configureInterface cfg.interfaces ++ map configureInterface interfaces ++
map createTunDevice (filter (i: i.virtual) cfg.interfaces)) map createTunDevice (filter (i: i.virtual) interfaces))
// mapAttrs createBridgeDevice cfg.bridges // mapAttrs createBridgeDevice cfg.bridges
// { "network-setup" = networkSetup; }; // { "network-setup" = networkSetup; };

View File

@ -13,7 +13,7 @@ with pkgs.lib;
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
before = [ "sshd.service" ]; before = [ "sshd.service" ];
after = [ "dhcpcd.service" ]; after = [ "network.target" ];
path = [ pkgs.curl pkgs.iproute ]; path = [ pkgs.curl pkgs.iproute ];

View File

@ -16,7 +16,7 @@ let
miniupnpdConf = nodes: pkgs.writeText "miniupnpd.conf" miniupnpdConf = nodes: pkgs.writeText "miniupnpd.conf"
'' ''
ext_ifname=eth1 ext_ifname=eth1
listening_ip=${nodes.router.config.networking.ifaces.eth2.ipAddress}/24 listening_ip=${nodes.router.config.networking.interfaces.eth2.ipAddress}/24
allow 1024-65535 192.168.2.0/24 1024-65535 allow 1024-65535 192.168.2.0/24 1024-65535
''; '';
@ -49,7 +49,7 @@ in
{ environment.systemPackages = [ pkgs.transmission ]; { environment.systemPackages = [ pkgs.transmission ];
virtualisation.vlans = [ 2 ]; virtualisation.vlans = [ 2 ];
networking.defaultGateway = networking.defaultGateway =
nodes.router.config.networking.ifaces.eth2.ipAddress; nodes.router.config.networking.interfaces.eth2.ipAddress;
}; };
client2 = client2 =

View File

@ -13,7 +13,7 @@
{ config, pkgs, nodes, ... }: { config, pkgs, nodes, ... }:
{ virtualisation.vlans = [ 1 ]; { virtualisation.vlans = [ 1 ];
networking.defaultGateway = networking.defaultGateway =
nodes.router.config.networking.ifaces.eth2.ipAddress; nodes.router.config.networking.interfaces.eth2.ipAddress;
}; };
router = router =