nixos/networking: add options for configuring a GRE tunnel
Add `networking.greTunnels` option that allows a GRE tunnel to be configured in NixOS.
This commit is contained in:
parent
b56d7a70a7
commit
5ce7061945
@ -532,6 +532,33 @@ let
|
||||
'';
|
||||
});
|
||||
|
||||
createGreDevice = n: v: nameValuePair "${n}-netdev"
|
||||
(let
|
||||
deps = deviceDependency v.dev;
|
||||
in
|
||||
{ description = "GRE Tunnel Interface ${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 = ''
|
||||
# Remove Dead Interfaces
|
||||
ip link show "${n}" >/dev/null 2>&1 && ip link delete "${n}"
|
||||
ip link add name "${n}" type ${v.type} \
|
||||
${optionalString (v.remote != null) "remote \"${v.remote}\""} \
|
||||
${optionalString (v.local != null) "local \"${v.local}\""} \
|
||||
${optionalString (v.dev != null) "dev \"${v.dev}\""}
|
||||
ip link set "${n}" up
|
||||
'';
|
||||
postStop = ''
|
||||
ip link delete "${n}" || true
|
||||
'';
|
||||
});
|
||||
|
||||
createVlanDevice = n: v: nameValuePair "${n}-netdev"
|
||||
(let
|
||||
deps = deviceDependency v.interface;
|
||||
@ -570,6 +597,7 @@ let
|
||||
// mapAttrs' createMacvlanDevice cfg.macvlans
|
||||
// mapAttrs' createFouEncapsulation cfg.fooOverUDP
|
||||
// mapAttrs' createSitDevice cfg.sits
|
||||
// mapAttrs' createGreDevice cfg.greTunnels
|
||||
// mapAttrs' createVlanDevice cfg.vlans
|
||||
// {
|
||||
network-setup = networkSetup;
|
||||
|
@ -18,6 +18,7 @@ let
|
||||
concatLists (map (bond: bond.interfaces) (attrValues cfg.bonds))
|
||||
++ concatLists (map (bridge: bridge.interfaces) (attrValues cfg.bridges))
|
||||
++ map (sit: sit.dev) (attrValues cfg.sits)
|
||||
++ map (gre: gre.dev) (attrValues cfg.greTunnels)
|
||||
++ map (vlan: vlan.interface) (attrValues cfg.vlans)
|
||||
# add dependency to physical or independently created vswitch member interface
|
||||
# TODO: warn the user that any address configured on those interfaces will be useless
|
||||
@ -245,6 +246,25 @@ in
|
||||
} ]);
|
||||
};
|
||||
})))
|
||||
(mkMerge (flip mapAttrsToList cfg.greTunnels (name: gre: {
|
||||
netdevs."40-${name}" = {
|
||||
netdevConfig = {
|
||||
Name = name;
|
||||
Kind = gre.type;
|
||||
};
|
||||
tunnelConfig =
|
||||
(optionalAttrs (gre.remote != null) {
|
||||
Remote = gre.remote;
|
||||
}) // (optionalAttrs (gre.local != null) {
|
||||
Local = gre.local;
|
||||
});
|
||||
};
|
||||
networks = mkIf (gre.dev != null) {
|
||||
"40-${gre.dev}" = (mkMerge [ (genericNetwork (mkOverride 999)) {
|
||||
tunnel = [ name ];
|
||||
} ]);
|
||||
};
|
||||
})))
|
||||
(mkMerge (flip mapAttrsToList cfg.vlans (name: vlan: {
|
||||
netdevs."40-${name}" = {
|
||||
netdevConfig = {
|
||||
|
@ -9,6 +9,7 @@ let
|
||||
interfaces = attrValues cfg.interfaces;
|
||||
hasVirtuals = any (i: i.virtual) interfaces;
|
||||
hasSits = cfg.sits != { };
|
||||
hasGres = cfg.greTunnels != { };
|
||||
hasBonds = cfg.bonds != { };
|
||||
hasFous = cfg.fooOverUDP != { }
|
||||
|| filterAttrs (_: s: s.encapsulation != null) cfg.sits != { };
|
||||
@ -996,6 +997,65 @@ in
|
||||
});
|
||||
};
|
||||
|
||||
networking.greTunnels = mkOption {
|
||||
default = { };
|
||||
example = literalExpression ''
|
||||
{
|
||||
greBridge = {
|
||||
remote = "10.0.0.1";
|
||||
local = "10.0.0.22";
|
||||
dev = "enp4s0f0";
|
||||
type = "tap";
|
||||
};
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
This option allows you to define Generic Routing Encapsulation (GRE) tunnels.
|
||||
'';
|
||||
type = with types; attrsOf (submodule {
|
||||
options = {
|
||||
|
||||
remote = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
example = "10.0.0.1";
|
||||
description = ''
|
||||
The address of the remote endpoint to forward traffic over.
|
||||
'';
|
||||
};
|
||||
|
||||
local = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
example = "10.0.0.22";
|
||||
description = ''
|
||||
The address of the local endpoint which the remote
|
||||
side should send packets to.
|
||||
'';
|
||||
};
|
||||
|
||||
dev = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
example = "enp4s0f0";
|
||||
description = ''
|
||||
The underlying network device on which the tunnel resides.
|
||||
'';
|
||||
};
|
||||
|
||||
type = mkOption {
|
||||
type = with types; enum [ "tun" "tap" ];
|
||||
default = "tap";
|
||||
example = "tap";
|
||||
apply = v: if v == "tun" then "gre" else "gretap";
|
||||
description = ''
|
||||
Whether the tunnel routes layer 2 (tap) or layer 3 (tun) traffic.
|
||||
'';
|
||||
};
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
networking.vlans = mkOption {
|
||||
default = { };
|
||||
example = literalExpression ''
|
||||
@ -1225,6 +1285,7 @@ in
|
||||
boot.kernelModules = [ ]
|
||||
++ optional hasVirtuals "tun"
|
||||
++ optional hasSits "sit"
|
||||
++ optional hasGres "gre"
|
||||
++ optional hasBonds "bonding"
|
||||
++ optional hasFous "fou";
|
||||
|
||||
|
@ -489,6 +489,77 @@ let
|
||||
client2.wait_until_succeeds("ping -c 1 fc00::2")
|
||||
'';
|
||||
};
|
||||
gre = let
|
||||
node = { pkgs, ... }: with pkgs.lib; {
|
||||
networking = {
|
||||
useNetworkd = networkd;
|
||||
useDHCP = false;
|
||||
};
|
||||
};
|
||||
in {
|
||||
name = "GRE";
|
||||
nodes.client1 = args@{ pkgs, ... }:
|
||||
mkMerge [
|
||||
(node args)
|
||||
{
|
||||
virtualisation.vlans = [ 1 2 ];
|
||||
networking = {
|
||||
greTunnels = {
|
||||
greTunnel = {
|
||||
local = "192.168.2.1";
|
||||
remote = "192.168.2.2";
|
||||
dev = "eth2";
|
||||
type = "tap";
|
||||
};
|
||||
};
|
||||
bridges.bridge.interfaces = [ "greTunnel" "eth1" ];
|
||||
interfaces.eth1.ipv4.addresses = mkOverride 0 [];
|
||||
interfaces.bridge.ipv4.addresses = mkOverride 0 [
|
||||
{ address = "192.168.1.1"; prefixLength = 24; }
|
||||
];
|
||||
};
|
||||
}
|
||||
];
|
||||
nodes.client2 = args@{ pkgs, ... }:
|
||||
mkMerge [
|
||||
(node args)
|
||||
{
|
||||
virtualisation.vlans = [ 2 3 ];
|
||||
networking = {
|
||||
greTunnels = {
|
||||
greTunnel = {
|
||||
local = "192.168.2.2";
|
||||
remote = "192.168.2.1";
|
||||
dev = "eth1";
|
||||
type = "tap";
|
||||
};
|
||||
};
|
||||
bridges.bridge.interfaces = [ "greTunnel" "eth2" ];
|
||||
interfaces.eth2.ipv4.addresses = mkOverride 0 [];
|
||||
interfaces.bridge.ipv4.addresses = mkOverride 0 [
|
||||
{ address = "192.168.1.2"; prefixLength = 24; }
|
||||
];
|
||||
};
|
||||
}
|
||||
];
|
||||
testScript = { ... }:
|
||||
''
|
||||
start_all()
|
||||
|
||||
with subtest("Wait for networking to be configured"):
|
||||
client1.wait_for_unit("network.target")
|
||||
client2.wait_for_unit("network.target")
|
||||
|
||||
# Print diagnostic information
|
||||
client1.succeed("ip addr >&2")
|
||||
client2.succeed("ip addr >&2")
|
||||
|
||||
with subtest("Test GRE tunnel bridge over VLAN"):
|
||||
client1.wait_until_succeeds("ping -c 1 192.168.1.2")
|
||||
|
||||
client2.wait_until_succeeds("ping -c 1 192.168.1.1")
|
||||
'';
|
||||
};
|
||||
vlan = let
|
||||
node = address: { pkgs, ... }: with pkgs.lib; {
|
||||
#virtualisation.vlans = [ 1 ];
|
||||
|
Loading…
Reference in New Issue
Block a user