Merge pull request #148637 from hexagonal-sun/network/gre-tap-tun

nixos/network: add gre virtual interfaces

authored by Guillaume Girol and committed by GitHub fdc37848 e426ec42

+180
+28
nixos/modules/tasks/network-interfaces-scripted.nix
··· 532 ''; 533 }); 534 535 createVlanDevice = n: v: nameValuePair "${n}-netdev" 536 (let 537 deps = deviceDependency v.interface; ··· 570 // mapAttrs' createMacvlanDevice cfg.macvlans 571 // mapAttrs' createFouEncapsulation cfg.fooOverUDP 572 // mapAttrs' createSitDevice cfg.sits 573 // mapAttrs' createVlanDevice cfg.vlans 574 // { 575 network-setup = networkSetup;
··· 532 ''; 533 }); 534 535 + createGreDevice = n: v: nameValuePair "${n}-netdev" 536 + (let 537 + deps = deviceDependency v.dev; 538 + in 539 + { description = "GRE Tunnel Interface ${n}"; 540 + wantedBy = [ "network-setup.service" (subsystemDevice n) ]; 541 + bindsTo = deps; 542 + partOf = [ "network-setup.service" ]; 543 + after = [ "network-pre.target" ] ++ deps; 544 + before = [ "network-setup.service" ]; 545 + serviceConfig.Type = "oneshot"; 546 + serviceConfig.RemainAfterExit = true; 547 + path = [ pkgs.iproute2 ]; 548 + script = '' 549 + # Remove Dead Interfaces 550 + ip link show "${n}" >/dev/null 2>&1 && ip link delete "${n}" 551 + ip link add name "${n}" type ${v.type} \ 552 + ${optionalString (v.remote != null) "remote \"${v.remote}\""} \ 553 + ${optionalString (v.local != null) "local \"${v.local}\""} \ 554 + ${optionalString (v.dev != null) "dev \"${v.dev}\""} 555 + ip link set "${n}" up 556 + ''; 557 + postStop = '' 558 + ip link delete "${n}" || true 559 + ''; 560 + }); 561 + 562 createVlanDevice = n: v: nameValuePair "${n}-netdev" 563 (let 564 deps = deviceDependency v.interface; ··· 597 // mapAttrs' createMacvlanDevice cfg.macvlans 598 // mapAttrs' createFouEncapsulation cfg.fooOverUDP 599 // mapAttrs' createSitDevice cfg.sits 600 + // mapAttrs' createGreDevice cfg.greTunnels 601 // mapAttrs' createVlanDevice cfg.vlans 602 // { 603 network-setup = networkSetup;
+20
nixos/modules/tasks/network-interfaces-systemd.nix
··· 18 concatLists (map (bond: bond.interfaces) (attrValues cfg.bonds)) 19 ++ concatLists (map (bridge: bridge.interfaces) (attrValues cfg.bridges)) 20 ++ map (sit: sit.dev) (attrValues cfg.sits) 21 ++ map (vlan: vlan.interface) (attrValues cfg.vlans) 22 # add dependency to physical or independently created vswitch member interface 23 # TODO: warn the user that any address configured on those interfaces will be useless ··· 241 }; 242 networks = mkIf (sit.dev != null) { 243 "40-${sit.dev}" = (mkMerge [ (genericNetwork (mkOverride 999)) { 244 tunnel = [ name ]; 245 } ]); 246 };
··· 18 concatLists (map (bond: bond.interfaces) (attrValues cfg.bonds)) 19 ++ concatLists (map (bridge: bridge.interfaces) (attrValues cfg.bridges)) 20 ++ map (sit: sit.dev) (attrValues cfg.sits) 21 + ++ map (gre: gre.dev) (attrValues cfg.greTunnels) 22 ++ map (vlan: vlan.interface) (attrValues cfg.vlans) 23 # add dependency to physical or independently created vswitch member interface 24 # TODO: warn the user that any address configured on those interfaces will be useless ··· 242 }; 243 networks = mkIf (sit.dev != null) { 244 "40-${sit.dev}" = (mkMerge [ (genericNetwork (mkOverride 999)) { 245 + tunnel = [ name ]; 246 + } ]); 247 + }; 248 + }))) 249 + (mkMerge (flip mapAttrsToList cfg.greTunnels (name: gre: { 250 + netdevs."40-${name}" = { 251 + netdevConfig = { 252 + Name = name; 253 + Kind = gre.type; 254 + }; 255 + tunnelConfig = 256 + (optionalAttrs (gre.remote != null) { 257 + Remote = gre.remote; 258 + }) // (optionalAttrs (gre.local != null) { 259 + Local = gre.local; 260 + }); 261 + }; 262 + networks = mkIf (gre.dev != null) { 263 + "40-${gre.dev}" = (mkMerge [ (genericNetwork (mkOverride 999)) { 264 tunnel = [ name ]; 265 } ]); 266 };
+61
nixos/modules/tasks/network-interfaces.nix
··· 10 interfaces = attrValues cfg.interfaces; 11 hasVirtuals = any (i: i.virtual) interfaces; 12 hasSits = cfg.sits != { }; 13 hasBonds = cfg.bonds != { }; 14 hasFous = cfg.fooOverUDP != { } 15 || filterAttrs (_: s: s.encapsulation != null) cfg.sits != { }; ··· 997 }); 998 }; 999 1000 networking.vlans = mkOption { 1001 default = { }; 1002 example = literalExpression '' ··· 1229 boot.kernelModules = [ ] 1230 ++ optional hasVirtuals "tun" 1231 ++ optional hasSits "sit" 1232 ++ optional hasBonds "bonding" 1233 ++ optional hasFous "fou"; 1234
··· 10 interfaces = attrValues cfg.interfaces; 11 hasVirtuals = any (i: i.virtual) interfaces; 12 hasSits = cfg.sits != { }; 13 + hasGres = cfg.greTunnels != { }; 14 hasBonds = cfg.bonds != { }; 15 hasFous = cfg.fooOverUDP != { } 16 || filterAttrs (_: s: s.encapsulation != null) cfg.sits != { }; ··· 998 }); 999 }; 1000 1001 + networking.greTunnels = mkOption { 1002 + default = { }; 1003 + example = literalExpression '' 1004 + { 1005 + greBridge = { 1006 + remote = "10.0.0.1"; 1007 + local = "10.0.0.22"; 1008 + dev = "enp4s0f0"; 1009 + type = "tap"; 1010 + }; 1011 + } 1012 + ''; 1013 + description = '' 1014 + This option allows you to define Generic Routing Encapsulation (GRE) tunnels. 1015 + ''; 1016 + type = with types; attrsOf (submodule { 1017 + options = { 1018 + 1019 + remote = mkOption { 1020 + type = types.nullOr types.str; 1021 + default = null; 1022 + example = "10.0.0.1"; 1023 + description = '' 1024 + The address of the remote endpoint to forward traffic over. 1025 + ''; 1026 + }; 1027 + 1028 + local = mkOption { 1029 + type = types.nullOr types.str; 1030 + default = null; 1031 + example = "10.0.0.22"; 1032 + description = '' 1033 + The address of the local endpoint which the remote 1034 + side should send packets to. 1035 + ''; 1036 + }; 1037 + 1038 + dev = mkOption { 1039 + type = types.nullOr types.str; 1040 + default = null; 1041 + example = "enp4s0f0"; 1042 + description = '' 1043 + The underlying network device on which the tunnel resides. 1044 + ''; 1045 + }; 1046 + 1047 + type = mkOption { 1048 + type = with types; enum [ "tun" "tap" ]; 1049 + default = "tap"; 1050 + example = "tap"; 1051 + apply = v: if v == "tun" then "gre" else "gretap"; 1052 + description = '' 1053 + Whether the tunnel routes layer 2 (tap) or layer 3 (tun) traffic. 1054 + ''; 1055 + }; 1056 + }; 1057 + }); 1058 + }; 1059 + 1060 networking.vlans = mkOption { 1061 default = { }; 1062 example = literalExpression '' ··· 1289 boot.kernelModules = [ ] 1290 ++ optional hasVirtuals "tun" 1291 ++ optional hasSits "sit" 1292 + ++ optional hasGres "gre" 1293 ++ optional hasBonds "bonding" 1294 ++ optional hasFous "fou"; 1295
+71
nixos/tests/networking.nix
··· 489 client2.wait_until_succeeds("ping -c 1 fc00::2") 490 ''; 491 }; 492 vlan = let 493 node = address: { pkgs, ... }: with pkgs.lib; { 494 #virtualisation.vlans = [ 1 ];
··· 489 client2.wait_until_succeeds("ping -c 1 fc00::2") 490 ''; 491 }; 492 + gre = let 493 + node = { pkgs, ... }: with pkgs.lib; { 494 + networking = { 495 + useNetworkd = networkd; 496 + useDHCP = false; 497 + }; 498 + }; 499 + in { 500 + name = "GRE"; 501 + nodes.client1 = args@{ pkgs, ... }: 502 + mkMerge [ 503 + (node args) 504 + { 505 + virtualisation.vlans = [ 1 2 ]; 506 + networking = { 507 + greTunnels = { 508 + greTunnel = { 509 + local = "192.168.2.1"; 510 + remote = "192.168.2.2"; 511 + dev = "eth2"; 512 + type = "tap"; 513 + }; 514 + }; 515 + bridges.bridge.interfaces = [ "greTunnel" "eth1" ]; 516 + interfaces.eth1.ipv4.addresses = mkOverride 0 []; 517 + interfaces.bridge.ipv4.addresses = mkOverride 0 [ 518 + { address = "192.168.1.1"; prefixLength = 24; } 519 + ]; 520 + }; 521 + } 522 + ]; 523 + nodes.client2 = args@{ pkgs, ... }: 524 + mkMerge [ 525 + (node args) 526 + { 527 + virtualisation.vlans = [ 2 3 ]; 528 + networking = { 529 + greTunnels = { 530 + greTunnel = { 531 + local = "192.168.2.2"; 532 + remote = "192.168.2.1"; 533 + dev = "eth1"; 534 + type = "tap"; 535 + }; 536 + }; 537 + bridges.bridge.interfaces = [ "greTunnel" "eth2" ]; 538 + interfaces.eth2.ipv4.addresses = mkOverride 0 []; 539 + interfaces.bridge.ipv4.addresses = mkOverride 0 [ 540 + { address = "192.168.1.2"; prefixLength = 24; } 541 + ]; 542 + }; 543 + } 544 + ]; 545 + testScript = { ... }: 546 + '' 547 + start_all() 548 + 549 + with subtest("Wait for networking to be configured"): 550 + client1.wait_for_unit("network.target") 551 + client2.wait_for_unit("network.target") 552 + 553 + # Print diagnostic information 554 + client1.succeed("ip addr >&2") 555 + client2.succeed("ip addr >&2") 556 + 557 + with subtest("Test GRE tunnel bridge over VLAN"): 558 + client1.wait_until_succeeds("ping -c 1 192.168.1.2") 559 + 560 + client2.wait_until_succeeds("ping -c 1 192.168.1.1") 561 + ''; 562 + }; 563 vlan = let 564 node = address: { pkgs, ... }: with pkgs.lib; { 565 #virtualisation.vlans = [ 1 ];