nixos/networking: add foo-over-udp endpoint support
allows configuration of foo-over-udp decapsulation endpoints. sadly networkd seems to lack the features necessary to support local and peer address configuration, so those are only supported when using scripted configuration.
This commit is contained in:
parent
eebfe7199d
commit
f29ea2d15d
@ -1535,6 +1535,19 @@ Superuser created successfully.
|
||||
release notes</link> for changes and upgrade instructions.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
The <literal>systemd.network</literal> module has gained
|
||||
support for the FooOverUDP link type.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
The <literal>networking</literal> module has a new
|
||||
<literal>networking.fooOverUDP</literal> option to configure
|
||||
Foo-over-UDP encapsulations.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
</section>
|
||||
|
@ -443,3 +443,7 @@ In addition to numerous new and upgraded packages, this release has the followin
|
||||
- Three new options, [xdg.mime.addedAssociations](#opt-xdg.mime.addedAssociations), [xdg.mime.defaultApplications](#opt-xdg.mime.defaultApplications), and [xdg.mime.removedAssociations](#opt-xdg.mime.removedAssociations) have been added to the [xdg.mime](#opt-xdg.mime.enable) module to allow the configuration of `/etc/xdg/mimeapps.list`.
|
||||
|
||||
- Kopia was upgraded from 0.8.x to 0.9.x. Please read the [upstream release notes](https://github.com/kopia/kopia/releases/tag/v0.9.0) for changes and upgrade instructions.
|
||||
|
||||
- The `systemd.network` module has gained support for the FooOverUDP link type.
|
||||
|
||||
- The `networking` module has a new `networking.fooOverUDP` option to configure Foo-over-UDP encapsulations.
|
||||
|
@ -250,6 +250,16 @@ let
|
||||
(assertRange "ERSPANIndex" 1 1048575)
|
||||
];
|
||||
|
||||
sectionFooOverUDP = checkUnitConfig "FooOverUDP" [
|
||||
(assertOnlyFields [
|
||||
"Port"
|
||||
"Encapsulation"
|
||||
"Protocol"
|
||||
])
|
||||
(assertPort "Port")
|
||||
(assertValueOneOf "Encapsulation" ["FooOverUDP" "GenericUDPEncapsulation"])
|
||||
];
|
||||
|
||||
sectionPeer = checkUnitConfig "Peer" [
|
||||
(assertOnlyFields [
|
||||
"Name"
|
||||
@ -919,6 +929,18 @@ let
|
||||
'';
|
||||
};
|
||||
|
||||
fooOverUDPConfig = mkOption {
|
||||
default = { };
|
||||
example = { Port = 9001; };
|
||||
type = types.addCheck (types.attrsOf unitOption) check.netdev.sectionFooOverUDP;
|
||||
description = ''
|
||||
Each attribute in this set specifies an option in the
|
||||
<literal>[FooOverUDP]</literal> section of the unit. See
|
||||
<citerefentry><refentrytitle>systemd.netdev</refentrytitle>
|
||||
<manvolnum>5</manvolnum></citerefentry> for details.
|
||||
'';
|
||||
};
|
||||
|
||||
peerConfig = mkOption {
|
||||
default = {};
|
||||
example = { Name = "veth2"; };
|
||||
@ -1449,6 +1471,10 @@ let
|
||||
[Tunnel]
|
||||
${attrsToSection def.tunnelConfig}
|
||||
''
|
||||
+ optionalString (def.fooOverUDPConfig != { }) ''
|
||||
[FooOverUDP]
|
||||
${attrsToSection def.fooOverUDPConfig}
|
||||
''
|
||||
+ optionalString (def.peerConfig != { }) ''
|
||||
[Peer]
|
||||
${attrsToSection def.peerConfig}
|
||||
|
@ -466,6 +466,39 @@ let
|
||||
'';
|
||||
});
|
||||
|
||||
createFouEncapsulation = n: v: nameValuePair "${n}-fou-encap"
|
||||
(let
|
||||
# if we have a device to bind to we can wait for its addresses to be
|
||||
# configured, otherwise external sequencing is required.
|
||||
deps = optionals (v.local != null && v.local.dev != null)
|
||||
(deviceDependency v.local.dev ++ [ "network-addresses-${v.local.dev}.service" ]);
|
||||
fouSpec = "port ${toString v.port} ${
|
||||
if v.protocol != null then "ipproto ${toString v.protocol}" else "gue"
|
||||
} ${
|
||||
optionalString (v.local != null) "local ${escapeShellArg v.local.address} ${
|
||||
optionalString (v.local.dev != null) "dev ${escapeShellArg v.local.dev}"
|
||||
}"
|
||||
}";
|
||||
in
|
||||
{ description = "FOU endpoint ${n}";
|
||||
wantedBy = [ "network-setup.service" (subsystemDevice n) ];
|
||||
bindsTo = deps;
|
||||
partOf = [ "network-setup.service" ];
|
||||
after = [ "network-pre.target" ] ++ deps;
|
||||
before = [ "network-setup.service" ];
|
||||
serviceConfig.Type = "oneshot";
|
||||
serviceConfig.RemainAfterExit = true;
|
||||
path = [ pkgs.iproute2 ];
|
||||
script = ''
|
||||
# always remove previous incarnation since show can't filter
|
||||
ip fou del ${fouSpec} >/dev/null 2>&1 || true
|
||||
ip fou add ${fouSpec}
|
||||
'';
|
||||
postStop = ''
|
||||
ip fou del ${fouSpec} || true
|
||||
'';
|
||||
});
|
||||
|
||||
createSitDevice = n: v: nameValuePair "${n}-netdev"
|
||||
(let
|
||||
deps = deviceDependency v.dev;
|
||||
@ -530,6 +563,7 @@ let
|
||||
// mapAttrs' createVswitchDevice cfg.vswitches
|
||||
// mapAttrs' createBondDevice cfg.bonds
|
||||
// mapAttrs' createMacvlanDevice cfg.macvlans
|
||||
// mapAttrs' createFouEncapsulation cfg.fooOverUDP
|
||||
// mapAttrs' createSitDevice cfg.sits
|
||||
// mapAttrs' createVlanDevice cfg.vlans
|
||||
// {
|
||||
|
@ -47,6 +47,9 @@ in
|
||||
} ] ++ flip mapAttrsToList cfg.bridges (n: { rstp, ... }: {
|
||||
assertion = !rstp;
|
||||
message = "networking.bridges.${n}.rstp is not supported by networkd.";
|
||||
}) ++ flip mapAttrsToList cfg.fooOverUDP (n: { local, ... }: {
|
||||
assertion = local == null;
|
||||
message = "networking.fooOverUDP.${n}.local is not supported by networkd.";
|
||||
});
|
||||
|
||||
networking.dhcpcd.enable = mkDefault false;
|
||||
@ -194,6 +197,23 @@ in
|
||||
macvlan = [ name ];
|
||||
} ]);
|
||||
})))
|
||||
(mkMerge (flip mapAttrsToList cfg.fooOverUDP (name: fou: {
|
||||
netdevs."40-${name}" = {
|
||||
netdevConfig = {
|
||||
Name = name;
|
||||
Kind = "fou";
|
||||
};
|
||||
# unfortunately networkd cannot encode dependencies of netdevs on addresses/routes,
|
||||
# so we cannot specify Local=, Peer=, PeerPort=. this looks like a missing feature
|
||||
# in networkd.
|
||||
fooOverUDPConfig = {
|
||||
Port = fou.port;
|
||||
Encapsulation = if fou.protocol != null then "FooOverUDP" else "GenericUDPEncapsulation";
|
||||
} // (optionalAttrs (fou.protocol != null) {
|
||||
Protocol = fou.protocol;
|
||||
});
|
||||
};
|
||||
})))
|
||||
(mkMerge (flip mapAttrsToList cfg.sits (name: sit: {
|
||||
netdevs."40-${name}" = {
|
||||
netdevConfig = {
|
||||
|
@ -10,6 +10,7 @@ let
|
||||
hasVirtuals = any (i: i.virtual) interfaces;
|
||||
hasSits = cfg.sits != { };
|
||||
hasBonds = cfg.bonds != { };
|
||||
hasFous = cfg.fooOverUDP != { };
|
||||
|
||||
slaves = concatMap (i: i.interfaces) (attrValues cfg.bonds)
|
||||
++ concatMap (i: i.interfaces) (attrValues cfg.bridges)
|
||||
@ -823,6 +824,71 @@ in
|
||||
});
|
||||
};
|
||||
|
||||
networking.fooOverUDP = mkOption {
|
||||
default = { };
|
||||
example =
|
||||
{
|
||||
primary = { port = 9001; local = { address = "192.0.2.1"; dev = "eth0"; }; };
|
||||
backup = { port = 9002; };
|
||||
};
|
||||
description = ''
|
||||
This option allows you to configure Foo Over UDP and Generic UDP Encapsulation
|
||||
endpoints. See <citerefentry><refentrytitle>ip-fou</refentrytitle>
|
||||
<manvolnum>8</manvolnum></citerefentry> for details.
|
||||
'';
|
||||
type = with types; attrsOf (submodule {
|
||||
options = {
|
||||
port = mkOption {
|
||||
type = port;
|
||||
description = ''
|
||||
Local port of the encapsulation UDP socket.
|
||||
'';
|
||||
};
|
||||
|
||||
protocol = mkOption {
|
||||
type = nullOr (ints.between 1 255);
|
||||
default = null;
|
||||
description = ''
|
||||
Protocol number of the encapsulated packets. Specifying <literal>null</literal>
|
||||
(the default) creates a GUE endpoint, specifying a protocol number will create
|
||||
a FOU endpoint.
|
||||
'';
|
||||
};
|
||||
|
||||
local = mkOption {
|
||||
type = nullOr (submodule {
|
||||
options = {
|
||||
address = mkOption {
|
||||
type = types.str;
|
||||
description = ''
|
||||
Local address to bind to. The address must be available when the FOU
|
||||
endpoint is created, using the scripted network setup this can be achieved
|
||||
either by setting <literal>dev</literal> or adding dependency information to
|
||||
<literal>systemd.services.<name>-fou-encap</literal>; it isn't supported
|
||||
when using networkd.
|
||||
'';
|
||||
};
|
||||
|
||||
dev = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
example = "eth0";
|
||||
description = ''
|
||||
Network device to bind to.
|
||||
'';
|
||||
};
|
||||
};
|
||||
});
|
||||
default = null;
|
||||
example = { address = "203.0.113.22"; };
|
||||
description = ''
|
||||
Local address (and optionally device) to bind to using the given port.
|
||||
'';
|
||||
};
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
networking.sits = mkOption {
|
||||
default = { };
|
||||
example = literalExpression ''
|
||||
@ -1116,7 +1182,8 @@ in
|
||||
boot.kernelModules = [ ]
|
||||
++ optional hasVirtuals "tun"
|
||||
++ optional hasSits "sit"
|
||||
++ optional hasBonds "bonding";
|
||||
++ optional hasBonds "bonding"
|
||||
++ optional hasFous "fou";
|
||||
|
||||
boot.extraModprobeConfig =
|
||||
# This setting is intentional as it prevents default bond devices
|
||||
|
@ -380,6 +380,52 @@ let
|
||||
router.wait_until_succeeds("ping -c 1 192.168.1.3")
|
||||
'';
|
||||
};
|
||||
fou = {
|
||||
name = "foo-over-udp";
|
||||
nodes.machine = { ... }: {
|
||||
virtualisation.vlans = [ 1 ];
|
||||
networking = {
|
||||
useNetworkd = networkd;
|
||||
useDHCP = false;
|
||||
interfaces.eth1.ipv4.addresses = mkOverride 0
|
||||
[ { address = "192.168.1.1"; prefixLength = 24; } ];
|
||||
fooOverUDP = {
|
||||
fou1 = { port = 9001; };
|
||||
fou2 = { port = 9002; protocol = 41; };
|
||||
fou3 = mkIf (!networkd)
|
||||
{ port = 9003; local.address = "192.168.1.1"; };
|
||||
fou4 = mkIf (!networkd)
|
||||
{ port = 9004; local = { address = "192.168.1.1"; dev = "eth1"; }; };
|
||||
};
|
||||
};
|
||||
systemd.services = {
|
||||
fou3-fou-encap.after = optional (!networkd) "network-addresses-eth1.service";
|
||||
};
|
||||
};
|
||||
testScript = { ... }:
|
||||
''
|
||||
import json
|
||||
|
||||
machine.wait_for_unit("network.target")
|
||||
fous = json.loads(machine.succeed("ip -json fou show"))
|
||||
assert {"port": 9001, "gue": None, "family": "inet"} in fous, "fou1 exists"
|
||||
assert {"port": 9002, "ipproto": 41, "family": "inet"} in fous, "fou2 exists"
|
||||
'' + optionalString (!networkd) ''
|
||||
assert {
|
||||
"port": 9003,
|
||||
"gue": None,
|
||||
"family": "inet",
|
||||
"local": "192.168.1.1",
|
||||
} in fous, "fou3 exists"
|
||||
assert {
|
||||
"port": 9004,
|
||||
"gue": None,
|
||||
"family": "inet",
|
||||
"local": "192.168.1.1",
|
||||
"dev": "eth1",
|
||||
} in fous, "fou4 exists"
|
||||
'';
|
||||
};
|
||||
sit = let
|
||||
node = { address4, remote, address6 }: { pkgs, ... }: with pkgs.lib; {
|
||||
virtualisation.vlans = [ 1 ];
|
||||
|
Loading…
Reference in New Issue
Block a user