at 25.11-pre 59 kB view raw
1{ 2 config, 3 options, 4 lib, 5 pkgs, 6 utils, 7 ... 8}: 9 10with lib; 11with utils; 12 13let 14 15 cfg = config.networking; 16 opt = options.networking; 17 interfaces = attrValues cfg.interfaces; 18 hasVirtuals = any (i: i.virtual) interfaces; 19 hasSits = cfg.sits != { }; 20 hasGres = cfg.greTunnels != { }; 21 hasBonds = cfg.bonds != { }; 22 hasFous = cfg.fooOverUDP != { } || filterAttrs (_: s: s.encapsulation != null) cfg.sits != { }; 23 24 slaves = 25 concatMap (i: i.interfaces) (attrValues cfg.bonds) 26 ++ concatMap (i: i.interfaces) (attrValues cfg.bridges) 27 ++ concatMap ( 28 i: 29 attrNames ( 30 filterAttrs (name: config: !(config.type == "internal" || hasAttr name cfg.interfaces)) i.interfaces 31 ) 32 ) (attrValues cfg.vswitches); 33 34 slaveIfs = map (i: cfg.interfaces.${i}) (filter (i: cfg.interfaces ? ${i}) slaves); 35 36 rstpBridges = flip filterAttrs cfg.bridges (_: { rstp, ... }: rstp); 37 38 needsMstpd = rstpBridges != { }; 39 40 bridgeStp = optional needsMstpd ( 41 pkgs.writeTextFile { 42 name = "bridge-stp"; 43 executable = true; 44 destination = "/bin/bridge-stp"; 45 text = '' 46 #!${pkgs.runtimeShell} -e 47 export PATH="${pkgs.mstpd}/bin" 48 49 BRIDGES=(${concatStringsSep " " (attrNames rstpBridges)}) 50 for BRIDGE in $BRIDGES; do 51 if [ "$BRIDGE" = "$1" ]; then 52 if [ "$2" = "start" ]; then 53 mstpctl addbridge "$BRIDGE" 54 exit 0 55 elif [ "$2" = "stop" ]; then 56 mstpctl delbridge "$BRIDGE" 57 exit 0 58 fi 59 exit 1 60 fi 61 done 62 exit 1 63 ''; 64 } 65 ); 66 67 # We must escape interfaces due to the systemd interpretation 68 subsystemDevice = interface: "sys-subsystem-net-devices-${escapeSystemdPath interface}.device"; 69 70 addrOpts = 71 v: 72 assert v == 4 || v == 6; 73 { 74 options = { 75 address = mkOption { 76 type = types.str; 77 description = '' 78 IPv${toString v} address of the interface. Leave empty to configure the 79 interface using DHCP. 80 ''; 81 }; 82 83 prefixLength = mkOption { 84 type = types.addCheck types.int (n: n >= 0 && n <= (if v == 4 then 32 else 128)); 85 description = '' 86 Subnet mask of the interface, specified as the number of 87 bits in the prefix (`${if v == 4 then "24" else "64"}`). 88 ''; 89 }; 90 }; 91 }; 92 93 routeOpts = v: { 94 options = { 95 address = mkOption { 96 type = types.str; 97 description = "IPv${toString v} address of the network."; 98 }; 99 100 prefixLength = mkOption { 101 type = types.addCheck types.int (n: n >= 0 && n <= (if v == 4 then 32 else 128)); 102 description = '' 103 Subnet mask of the network, specified as the number of 104 bits in the prefix (`${if v == 4 then "24" else "64"}`). 105 ''; 106 }; 107 108 type = mkOption { 109 type = types.nullOr ( 110 types.enum [ 111 "unicast" 112 "local" 113 "broadcast" 114 "multicast" 115 ] 116 ); 117 default = null; 118 description = '' 119 Type of the route. See the `Route types` section 120 in the {manpage}`ip-route(8)` manual page for the details. 121 122 Note that `prohibit`, `blackhole`, 123 `unreachable`, and `throw` cannot 124 be configured per device, so they are not available here. Similarly, 125 `nat` hasn't been supported since kernel 2.6. 126 ''; 127 }; 128 129 via = mkOption { 130 type = types.nullOr types.str; 131 default = null; 132 description = "IPv${toString v} address of the next hop."; 133 }; 134 135 options = mkOption { 136 type = types.attrsOf types.str; 137 default = { }; 138 example = { 139 mtu = "1492"; 140 window = "524288"; 141 }; 142 description = '' 143 Other route options. See the symbol `OPTIONS` 144 in the {manpage}`ip-route(8)` manual page for the details. 145 You may also specify `metric`, 146 `src`, `protocol`, 147 `scope`, `from` 148 and `table`, which are technically 149 not route options, in the sense used in the manual. 150 ''; 151 }; 152 153 }; 154 }; 155 156 gatewayCoerce = address: { inherit address; }; 157 158 gatewayOpts = 159 { ... }: 160 { 161 162 options = { 163 164 address = mkOption { 165 type = types.str; 166 description = "The default gateway address."; 167 }; 168 169 interface = mkOption { 170 type = types.nullOr types.str; 171 default = null; 172 example = "enp0s3"; 173 description = "The default gateway interface."; 174 }; 175 176 metric = mkOption { 177 type = types.nullOr types.int; 178 default = null; 179 example = 42; 180 description = "The default gateway metric/preference."; 181 }; 182 183 }; 184 185 }; 186 187 interfaceOpts = 188 { name, ... }: 189 { 190 191 options = { 192 name = mkOption { 193 example = "eth0"; 194 type = types.str; 195 description = "Name of the interface."; 196 }; 197 198 tempAddress = mkOption { 199 type = types.enum (lib.attrNames tempaddrValues); 200 default = cfg.tempAddresses; 201 defaultText = literalExpression ''config.networking.tempAddresses''; 202 description = '' 203 When IPv6 is enabled with SLAAC, this option controls the use of 204 temporary address (aka privacy extensions) on this 205 interface. This is used to reduce tracking. 206 207 See also the global option 208 [](#opt-networking.tempAddresses), which 209 applies to all interfaces where this is not set. 210 211 Possible values are: 212 ${tempaddrDoc} 213 ''; 214 }; 215 216 useDHCP = mkOption { 217 type = types.nullOr types.bool; 218 default = null; 219 description = '' 220 Whether this interface should be configured with DHCP. Overrides the 221 default set by {option}`networking.useDHCP`. If `null` (the default), 222 DHCP is enabled if the interface has no IPv4 addresses configured 223 with {option}`networking.interfaces.<name>.ipv4.addresses`, and 224 disabled otherwise. 225 ''; 226 }; 227 228 ipv4.addresses = mkOption { 229 default = [ ]; 230 example = [ 231 { 232 address = "10.0.0.1"; 233 prefixLength = 16; 234 } 235 { 236 address = "192.168.1.1"; 237 prefixLength = 24; 238 } 239 ]; 240 type = with types; listOf (submodule (addrOpts 4)); 241 description = '' 242 List of IPv4 addresses that will be statically assigned to the interface. 243 ''; 244 }; 245 246 ipv6.addresses = mkOption { 247 default = [ ]; 248 example = [ 249 { 250 address = "fdfd:b3f0:482::1"; 251 prefixLength = 48; 252 } 253 { 254 address = "2001:1470:fffd:2098::e006"; 255 prefixLength = 64; 256 } 257 ]; 258 type = with types; listOf (submodule (addrOpts 6)); 259 description = '' 260 List of IPv6 addresses that will be statically assigned to the interface. 261 ''; 262 }; 263 264 ipv4.routes = mkOption { 265 default = [ ]; 266 example = [ 267 { 268 address = "10.0.0.0"; 269 prefixLength = 16; 270 } 271 { 272 address = "192.168.2.0"; 273 prefixLength = 24; 274 via = "192.168.1.1"; 275 } 276 ]; 277 type = with types; listOf (submodule (routeOpts 4)); 278 description = '' 279 List of extra IPv4 static routes that will be assigned to the interface. 280 281 ::: {.warning} 282 If the route type is the default `unicast`, then the scope 283 is set differently depending on the value of {option}`networking.useNetworkd`: 284 the script-based backend sets it to `link`, while networkd sets 285 it to `global`. 286 ::: 287 288 If you want consistency between the two implementations, 289 set the scope of the route manually with 290 `networking.interfaces.eth0.ipv4.routes = [{ options.scope = "global"; }]` 291 for example. 292 ''; 293 }; 294 295 ipv6.routes = mkOption { 296 default = [ ]; 297 example = [ 298 { 299 address = "fdfd:b3f0::"; 300 prefixLength = 48; 301 } 302 { 303 address = "2001:1470:fffd:2098::"; 304 prefixLength = 64; 305 via = "fdfd:b3f0::1"; 306 } 307 ]; 308 type = with types; listOf (submodule (routeOpts 6)); 309 description = '' 310 List of extra IPv6 static routes that will be assigned to the interface. 311 ''; 312 }; 313 314 macAddress = mkOption { 315 default = null; 316 example = "00:11:22:33:44:55"; 317 type = types.nullOr (types.str); 318 description = '' 319 MAC address of the interface. Leave empty to use the default. 320 ''; 321 }; 322 323 mtu = mkOption { 324 default = null; 325 example = 9000; 326 type = types.nullOr types.int; 327 description = '' 328 MTU size for packets leaving the interface. Leave empty to use the default. 329 ''; 330 }; 331 332 virtual = mkOption { 333 default = false; 334 type = types.bool; 335 description = '' 336 Whether this interface is virtual and should be created by tunctl. 337 This is mainly useful for creating bridges between a host and a virtual 338 network such as VPN or a virtual machine. 339 ''; 340 }; 341 342 virtualOwner = mkOption { 343 default = "root"; 344 type = types.str; 345 description = '' 346 In case of a virtual device, the user who owns it. 347 ''; 348 }; 349 350 virtualType = mkOption { 351 default = if hasPrefix "tun" name then "tun" else "tap"; 352 defaultText = literalExpression ''if hasPrefix "tun" name then "tun" else "tap"''; 353 type = 354 with types; 355 enum [ 356 "tun" 357 "tap" 358 ]; 359 description = '' 360 The type of interface to create. 361 The default is TUN for an interface name starting 362 with "tun", otherwise TAP. 363 ''; 364 }; 365 366 proxyARP = mkOption { 367 default = false; 368 type = types.bool; 369 description = '' 370 Turn on proxy_arp for this device. 371 This is mainly useful for creating pseudo-bridges between a real 372 interface and a virtual network such as VPN or a virtual machine for 373 interfaces that don't support real bridging (most wlan interfaces). 374 As ARP proxying acts slightly above the link-layer, below-ip traffic 375 isn't bridged, so things like DHCP won't work. The advantage above 376 using NAT lies in the fact that no IP addresses are shared, so all 377 hosts are reachable/routeable. 378 379 WARNING: turns on ip-routing, so if you have multiple interfaces, you 380 should think of the consequence and setup firewall rules to limit this. 381 ''; 382 }; 383 384 wakeOnLan = { 385 enable = mkOption { 386 type = types.bool; 387 default = false; 388 description = "Whether to enable wol on this interface."; 389 }; 390 policy = mkOption { 391 type = 392 with types; 393 listOf (enum [ 394 "phy" 395 "unicast" 396 "multicast" 397 "broadcast" 398 "arp" 399 "magic" 400 "secureon" 401 ]); 402 default = [ "magic" ]; 403 description = '' 404 The [Wake-on-LAN policy](https://www.freedesktop.org/software/systemd/man/systemd.link.html#WakeOnLan=) 405 to set for the device. 406 407 The options are 408 - `phy`: Wake on PHY activity 409 - `unicast`: Wake on unicast messages 410 - `multicast`: Wake on multicast messages 411 - `broadcast`: Wake on broadcast messages 412 - `arp`: Wake on ARP 413 - `magic`: Wake on receipt of a magic packet 414 ''; 415 }; 416 }; 417 }; 418 419 config = { 420 name = mkDefault name; 421 }; 422 423 # Renamed or removed options 424 imports = 425 let 426 defined = x: x != "_mkMergedOptionModule"; 427 in 428 [ 429 (mkChangedOptionModule [ "preferTempAddress" ] [ "tempAddress" ] ( 430 config: 431 let 432 bool = getAttrFromPath [ "preferTempAddress" ] config; 433 in 434 if bool then "default" else "enabled" 435 )) 436 (mkRenamedOptionModule [ "ip4" ] [ "ipv4" "addresses" ]) 437 (mkRenamedOptionModule [ "ip6" ] [ "ipv6" "addresses" ]) 438 (mkRemovedOptionModule [ "subnetMask" ] '' 439 Supply a prefix length instead; use option 440 networking.interfaces.<name>.ipv{4,6}.addresses'') 441 (mkMergedOptionModule 442 [ 443 [ "ipAddress" ] 444 [ "prefixLength" ] 445 ] 446 [ "ipv4" "addresses" ] 447 ( 448 cfg: 449 with cfg; 450 optional (defined ipAddress && defined prefixLength) { 451 address = ipAddress; 452 prefixLength = prefixLength; 453 } 454 ) 455 ) 456 (mkMergedOptionModule 457 [ 458 [ "ipv6Address" ] 459 [ "ipv6PrefixLength" ] 460 ] 461 [ "ipv6" "addresses" ] 462 ( 463 cfg: 464 with cfg; 465 optional (defined ipv6Address && defined ipv6PrefixLength) { 466 address = ipv6Address; 467 prefixLength = ipv6PrefixLength; 468 } 469 ) 470 ) 471 472 ({ 473 options.warnings = options.warnings; 474 options.assertions = options.assertions; 475 }) 476 ]; 477 478 }; 479 480 vswitchInterfaceOpts = 481 { name, ... }: 482 { 483 484 options = { 485 486 name = mkOption { 487 description = "Name of the interface"; 488 example = "eth0"; 489 type = types.str; 490 }; 491 492 vlan = mkOption { 493 description = "Vlan tag to apply to interface"; 494 example = 10; 495 type = types.nullOr types.int; 496 default = null; 497 }; 498 499 type = mkOption { 500 description = "Openvswitch type to assign to interface"; 501 example = "internal"; 502 type = types.nullOr types.str; 503 default = null; 504 }; 505 }; 506 }; 507 508 hexChars = stringToCharacters "0123456789abcdef"; 509 510 isHexString = s: all (c: elem c hexChars) (stringToCharacters (toLower s)); 511 512 tempaddrValues = { 513 disabled = { 514 sysctl = "0"; 515 description = "completely disable IPv6 temporary addresses"; 516 }; 517 enabled = { 518 sysctl = "1"; 519 description = "generate IPv6 temporary addresses but still use EUI-64 addresses as source addresses"; 520 }; 521 default = { 522 sysctl = "2"; 523 description = "generate IPv6 temporary addresses and use these as source addresses in routing"; 524 }; 525 }; 526 tempaddrDoc = concatStringsSep "\n" ( 527 mapAttrsToList (name: { description, ... }: ''- `"${name}"` to ${description};'') tempaddrValues 528 ); 529 530 hostidFile = pkgs.runCommand "gen-hostid" { preferLocalBuild = true; } '' 531 hi="${cfg.hostId}" 532 ${ 533 if pkgs.stdenv.hostPlatform.isBigEndian then 534 '' 535 echo -ne "\x''${hi:0:2}\x''${hi:2:2}\x''${hi:4:2}\x''${hi:6:2}" > $out 536 '' 537 else 538 '' 539 echo -ne "\x''${hi:6:2}\x''${hi:4:2}\x''${hi:2:2}\x''${hi:0:2}" > $out 540 '' 541 } 542 ''; 543 544in 545 546{ 547 548 ###### interface 549 550 options = { 551 552 networking.hostName = mkOption { 553 default = config.system.nixos.distroId; 554 defaultText = literalExpression "config.system.nixos.distroId"; 555 # Only allow hostnames without the domain name part (i.e. no FQDNs, see 556 # e.g. "man 5 hostname") and require valid DNS labels (recommended 557 # syntax). Note: We also allow underscores for compatibility/legacy 558 # reasons (as undocumented feature): 559 type = types.strMatching "^$|^[[:alnum:]]([[:alnum:]_-]{0,61}[[:alnum:]])?$"; 560 description = '' 561 The name of the machine. Leave it empty if you want to obtain it from a 562 DHCP server (if using DHCP). The hostname must be a valid DNS label (see 563 RFC 1035 section 2.3.1: "Preferred name syntax", RFC 1123 section 2.1: 564 "Host Names and Numbers") and as such must not contain the domain part. 565 This means that the hostname must start with a letter or digit, 566 end with a letter or digit, and have as interior characters only 567 letters, digits, and hyphen. The maximum length is 63 characters. 568 Additionally it is recommended to only use lower-case characters. 569 If (e.g. for legacy reasons) a FQDN is required as the Linux kernel 570 network node hostname (uname --nodename) the option 571 boot.kernel.sysctl."kernel.hostname" can be used as a workaround (but 572 the 64 character limit still applies). 573 574 WARNING: Do not use underscores (_) or you may run into unexpected issues. 575 ''; 576 # warning until the issues in https://github.com/NixOS/nixpkgs/pull/138978 577 # are resolved 578 }; 579 580 networking.fqdn = mkOption { 581 type = types.str; 582 default = 583 if (cfg.hostName != "" && cfg.domain != null) then 584 "${cfg.hostName}.${cfg.domain}" 585 else 586 throw '' 587 The FQDN is required but cannot be determined from `networking.hostName` 588 and `networking.domain`. Please ensure these options are set properly or 589 set `networking.fqdn` directly. 590 ''; 591 defaultText = literalExpression ''"''${networking.hostName}.''${networking.domain}"''; 592 description = '' 593 The fully qualified domain name (FQDN) of this host. By default, it is 594 the result of combining `networking.hostName` and `networking.domain.` 595 596 Using this option will result in an evaluation error if the hostname is empty or 597 no domain is specified. 598 599 Modules that accept a mere `networking.hostName` but prefer a fully qualified 600 domain name may use `networking.fqdnOrHostName` instead. 601 ''; 602 }; 603 604 networking.fqdnOrHostName = mkOption { 605 readOnly = true; 606 type = types.str; 607 default = 608 if (cfg.domain != null || opt.fqdn.highestPrio < (mkOptionDefault { }).priority) then 609 cfg.fqdn 610 else 611 cfg.hostName; 612 defaultText = literalExpression '' 613 if config.networking.domain != null || config.networking.fqdn is set then config.networking.fqdn else config.networking.hostName 614 ''; 615 description = '' 616 Either the fully qualified domain name (FQDN), or just the host name if 617 it does not exist. 618 619 This is a convenience option for modules to read instead of `fqdn` when 620 a mere `hostName` is also an acceptable value; this option does not 621 throw an error when `domain` or `fqdn` is unset. 622 ''; 623 }; 624 625 networking.hostId = mkOption { 626 default = null; 627 example = "4e98920d"; 628 type = types.nullOr types.str; 629 description = '' 630 The 32-bit host ID of the machine, formatted as 8 hexadecimal characters. 631 632 You should try to make this ID unique among your machines. You can 633 generate a random 32-bit ID using the following commands: 634 635 `head -c 8 /etc/machine-id` 636 637 (this derives it from the machine-id that systemd generates) or 638 639 `head -c4 /dev/urandom | od -A none -t x4` 640 641 The primary use case is to ensure when using ZFS that a pool isn't imported 642 accidentally on a wrong machine. 643 ''; 644 }; 645 646 networking.enableIPv6 = mkOption { 647 default = true; 648 type = types.bool; 649 description = '' 650 Whether to enable support for IPv6. 651 ''; 652 }; 653 654 networking.defaultGateway = mkOption { 655 default = null; 656 example = { 657 address = "131.211.84.1"; 658 interface = "enp3s0"; 659 }; 660 type = types.nullOr (types.coercedTo types.str gatewayCoerce (types.submodule gatewayOpts)); 661 description = '' 662 The default gateway. It can be left empty if it is auto-detected through DHCP. 663 It can be specified as a string or an option set along with a network interface. 664 ''; 665 }; 666 667 networking.defaultGateway6 = mkOption { 668 default = null; 669 example = { 670 address = "2001:4d0:1e04:895::1"; 671 interface = "enp3s0"; 672 }; 673 type = types.nullOr (types.coercedTo types.str gatewayCoerce (types.submodule gatewayOpts)); 674 description = '' 675 The default ipv6 gateway. It can be left empty if it is auto-detected through DHCP. 676 It can be specified as a string or an option set along with a network interface. 677 ''; 678 }; 679 680 networking.defaultGatewayWindowSize = mkOption { 681 default = null; 682 example = 524288; 683 type = types.nullOr types.int; 684 description = '' 685 The window size of the default gateway. It limits maximal data bursts that TCP peers 686 are allowed to send to us. 687 ''; 688 }; 689 690 networking.nameservers = mkOption { 691 type = types.listOf types.str; 692 default = [ ]; 693 example = [ 694 "130.161.158.4" 695 "130.161.33.17" 696 ]; 697 description = '' 698 The list of nameservers. It can be left empty if it is auto-detected through DHCP. 699 ''; 700 }; 701 702 networking.search = mkOption { 703 default = [ ]; 704 example = [ 705 "example.com" 706 "home.arpa" 707 ]; 708 type = types.listOf types.str; 709 description = '' 710 The list of search paths used when resolving domain names. 711 ''; 712 }; 713 714 networking.domain = mkOption { 715 default = null; 716 example = "home.arpa"; 717 type = types.nullOr types.str; 718 description = '' 719 The domain. It can be left empty if it is auto-detected through DHCP. 720 ''; 721 }; 722 723 networking.useHostResolvConf = mkOption { 724 type = types.bool; 725 default = false; 726 description = '' 727 In containers, whether to use the 728 {file}`resolv.conf` supplied by the host. 729 ''; 730 }; 731 732 networking.localCommands = mkOption { 733 type = types.lines; 734 default = ""; 735 example = "text=anything; echo You can put $text here."; 736 description = '' 737 Shell commands to be executed at the end of the 738 `network-setup` systemd service. Note that if 739 you are using DHCP to obtain the network configuration, 740 interfaces may not be fully configured yet. 741 ''; 742 }; 743 744 networking.interfaces = mkOption { 745 default = { }; 746 example = { 747 eth0.ipv4.addresses = [ 748 { 749 address = "131.211.84.78"; 750 prefixLength = 25; 751 } 752 ]; 753 }; 754 description = '' 755 The configuration for each network interface. 756 757 Please note that {option}`systemd.network.netdevs` has more features 758 and is better maintained. When building new things, it is advised to 759 use that instead. 760 ''; 761 type = with types; attrsOf (submodule interfaceOpts); 762 }; 763 764 networking.vswitches = mkOption { 765 default = { }; 766 example = { 767 vs0.interfaces = { 768 eth0 = { }; 769 lo1 = { 770 type = "internal"; 771 }; 772 }; 773 vs1.interfaces = [ 774 { name = "eth2"; } 775 { 776 name = "lo2"; 777 type = "internal"; 778 } 779 ]; 780 }; 781 description = '' 782 This option allows you to define Open vSwitches that connect 783 physical networks together. The value of this option is an 784 attribute set. Each attribute specifies a vswitch, with the 785 attribute name specifying the name of the vswitch's network 786 interface. 787 ''; 788 789 type = 790 with types; 791 attrsOf (submodule { 792 793 options = { 794 795 interfaces = mkOption { 796 description = "The physical network interfaces connected by the vSwitch."; 797 type = with types; attrsOf (submodule vswitchInterfaceOpts); 798 }; 799 800 controllers = mkOption { 801 type = types.listOf types.str; 802 default = [ ]; 803 example = [ "ptcp:6653:[::1]" ]; 804 description = '' 805 Specify the controller targets. For the allowed options see `man 8 ovs-vsctl`. 806 ''; 807 }; 808 809 openFlowRules = mkOption { 810 type = types.lines; 811 default = ""; 812 example = '' 813 actions=normal 814 ''; 815 description = '' 816 OpenFlow rules to insert into the Open vSwitch. All `openFlowRules` are 817 loaded with `ovs-ofctl` within one atomic operation. 818 ''; 819 }; 820 821 # TODO: custom "openflow version" type, with list from existing openflow protocols 822 supportedOpenFlowVersions = mkOption { 823 type = types.listOf types.str; 824 example = [ 825 "OpenFlow10" 826 "OpenFlow13" 827 "OpenFlow14" 828 ]; 829 default = [ "OpenFlow13" ]; 830 description = '' 831 Supported versions to enable on this switch. 832 ''; 833 }; 834 835 # TODO: use same type as elements from supportedOpenFlowVersions 836 openFlowVersion = mkOption { 837 type = types.str; 838 default = "OpenFlow13"; 839 description = '' 840 Version of OpenFlow protocol to use when communicating with the switch internally (e.g. with `openFlowRules`). 841 ''; 842 }; 843 844 extraOvsctlCmds = mkOption { 845 type = types.lines; 846 default = ""; 847 example = '' 848 set-fail-mode <switch_name> secure 849 set Bridge <switch_name> stp_enable=true 850 ''; 851 description = '' 852 Commands to manipulate the Open vSwitch database. Every line executed with `ovs-vsctl`. 853 All commands are bundled together with the operations for adding the interfaces 854 into one atomic operation. 855 ''; 856 }; 857 858 }; 859 860 }); 861 862 }; 863 864 networking.bridges = mkOption { 865 default = { }; 866 example = { 867 br0.interfaces = [ 868 "eth0" 869 "eth1" 870 ]; 871 br1.interfaces = [ 872 "eth2" 873 "wlan0" 874 ]; 875 }; 876 description = '' 877 This option allows you to define Ethernet bridge devices 878 that connect physical networks together. The value of this 879 option is an attribute set. Each attribute specifies a 880 bridge, with the attribute name specifying the name of the 881 bridge's network interface. 882 ''; 883 884 type = 885 with types; 886 attrsOf (submodule { 887 888 options = { 889 890 interfaces = mkOption { 891 example = [ 892 "eth0" 893 "eth1" 894 ]; 895 type = types.listOf types.str; 896 description = "The physical network interfaces connected by the bridge."; 897 }; 898 899 rstp = mkOption { 900 default = false; 901 type = types.bool; 902 description = "Whether the bridge interface should enable rstp."; 903 }; 904 905 }; 906 907 }); 908 909 }; 910 911 networking.bonds = 912 let 913 driverOptionsExample = '' 914 { 915 miimon = "100"; 916 mode = "active-backup"; 917 } 918 ''; 919 in 920 mkOption { 921 default = { }; 922 example = literalExpression '' 923 { 924 bond0 = { 925 interfaces = [ "eth0" "wlan0" ]; 926 driverOptions = ${driverOptionsExample}; 927 }; 928 anotherBond.interfaces = [ "enp4s0f0" "enp4s0f1" "enp5s0f0" "enp5s0f1" ]; 929 } 930 ''; 931 description = '' 932 This option allows you to define bond devices that aggregate multiple, 933 underlying networking interfaces together. The value of this option is 934 an attribute set. Each attribute specifies a bond, with the attribute 935 name specifying the name of the bond's network interface 936 ''; 937 938 type = 939 with types; 940 attrsOf (submodule { 941 942 options = { 943 944 interfaces = mkOption { 945 example = [ 946 "enp4s0f0" 947 "enp4s0f1" 948 "wlan0" 949 ]; 950 type = types.listOf types.str; 951 description = "The interfaces to bond together"; 952 }; 953 954 driverOptions = mkOption { 955 type = types.attrsOf types.str; 956 default = { }; 957 example = literalExpression driverOptionsExample; 958 description = '' 959 Options for the bonding driver. 960 Documentation can be found in 961 <https://www.kernel.org/doc/Documentation/networking/bonding.txt> 962 ''; 963 964 }; 965 966 lacp_rate = mkOption { 967 default = null; 968 example = "fast"; 969 type = types.nullOr types.str; 970 description = '' 971 DEPRECATED, use `driverOptions`. 972 Option specifying the rate in which we'll ask our link partner 973 to transmit LACPDU packets in 802.3ad mode. 974 ''; 975 }; 976 977 miimon = mkOption { 978 default = null; 979 example = 100; 980 type = types.nullOr types.int; 981 description = '' 982 DEPRECATED, use `driverOptions`. 983 Miimon is the number of millisecond in between each round of polling 984 by the device driver for failed links. By default polling is not 985 enabled and the driver is trusted to properly detect and handle 986 failure scenarios. 987 ''; 988 }; 989 990 mode = mkOption { 991 default = null; 992 example = "active-backup"; 993 type = types.nullOr types.str; 994 description = '' 995 DEPRECATED, use `driverOptions`. 996 The mode which the bond will be running. The default mode for 997 the bonding driver is balance-rr, optimizing for throughput. 998 More information about valid modes can be found at 999 https://www.kernel.org/doc/Documentation/networking/bonding.txt 1000 ''; 1001 }; 1002 1003 xmit_hash_policy = mkOption { 1004 default = null; 1005 example = "layer2+3"; 1006 type = types.nullOr types.str; 1007 description = '' 1008 DEPRECATED, use `driverOptions`. 1009 Selects the transmit hash policy to use for slave selection in 1010 balance-xor, 802.3ad, and tlb modes. 1011 ''; 1012 }; 1013 1014 }; 1015 1016 }); 1017 }; 1018 1019 networking.macvlans = mkOption { 1020 default = { }; 1021 example = literalExpression '' 1022 { 1023 wan = { 1024 interface = "enp2s0"; 1025 mode = "vepa"; 1026 }; 1027 } 1028 ''; 1029 description = '' 1030 This option allows you to define macvlan interfaces which should 1031 be automatically created. 1032 ''; 1033 type = 1034 with types; 1035 attrsOf (submodule { 1036 options = { 1037 1038 interface = mkOption { 1039 example = "enp4s0"; 1040 type = types.str; 1041 description = "The interface the macvlan will transmit packets through."; 1042 }; 1043 1044 mode = mkOption { 1045 default = null; 1046 type = types.nullOr types.str; 1047 example = "vepa"; 1048 description = "The mode of the macvlan device."; 1049 }; 1050 1051 }; 1052 1053 }); 1054 }; 1055 1056 networking.fooOverUDP = mkOption { 1057 default = { }; 1058 example = { 1059 primary = { 1060 port = 9001; 1061 local = { 1062 address = "192.0.2.1"; 1063 dev = "eth0"; 1064 }; 1065 }; 1066 backup = { 1067 port = 9002; 1068 }; 1069 }; 1070 description = '' 1071 This option allows you to configure Foo Over UDP and Generic UDP Encapsulation 1072 endpoints. See {manpage}`ip-fou(8)` for details. 1073 ''; 1074 type = 1075 with types; 1076 attrsOf (submodule { 1077 options = { 1078 port = mkOption { 1079 type = port; 1080 description = '' 1081 Local port of the encapsulation UDP socket. 1082 ''; 1083 }; 1084 1085 protocol = mkOption { 1086 type = nullOr (ints.between 1 255); 1087 default = null; 1088 description = '' 1089 Protocol number of the encapsulated packets. Specifying `null` 1090 (the default) creates a GUE endpoint, specifying a protocol number will create 1091 a FOU endpoint. 1092 ''; 1093 }; 1094 1095 local = mkOption { 1096 type = nullOr (submodule { 1097 options = { 1098 address = mkOption { 1099 type = types.str; 1100 description = '' 1101 Local address to bind to. The address must be available when the FOU 1102 endpoint is created, using the scripted network setup this can be achieved 1103 either by setting `dev` or adding dependency information to 1104 `systemd.services.<name>-fou-encap`; it isn't supported 1105 when using networkd. 1106 ''; 1107 }; 1108 1109 dev = mkOption { 1110 type = nullOr str; 1111 default = null; 1112 example = "eth0"; 1113 description = '' 1114 Network device to bind to. 1115 ''; 1116 }; 1117 }; 1118 }); 1119 default = null; 1120 example = { 1121 address = "203.0.113.22"; 1122 }; 1123 description = '' 1124 Local address (and optionally device) to bind to using the given port. 1125 ''; 1126 }; 1127 }; 1128 }); 1129 }; 1130 1131 networking.sits = mkOption { 1132 default = { }; 1133 example = literalExpression '' 1134 { 1135 hurricane = { 1136 remote = "10.0.0.1"; 1137 local = "10.0.0.22"; 1138 ttl = 255; 1139 }; 1140 msipv6 = { 1141 remote = "192.168.0.1"; 1142 dev = "enp3s0"; 1143 ttl = 127; 1144 }; 1145 } 1146 ''; 1147 description = '' 1148 This option allows you to define 6-to-4 interfaces which should be automatically created. 1149 ''; 1150 type = 1151 with types; 1152 attrsOf (submodule { 1153 options = { 1154 1155 remote = mkOption { 1156 type = types.nullOr types.str; 1157 default = null; 1158 example = "10.0.0.1"; 1159 description = '' 1160 The address of the remote endpoint to forward traffic over. 1161 ''; 1162 }; 1163 1164 local = mkOption { 1165 type = types.nullOr types.str; 1166 default = null; 1167 example = "10.0.0.22"; 1168 description = '' 1169 The address of the local endpoint which the remote 1170 side should send packets to. 1171 ''; 1172 }; 1173 1174 ttl = mkOption { 1175 type = types.nullOr types.int; 1176 default = null; 1177 example = 255; 1178 description = '' 1179 The time-to-live of the connection to the remote tunnel endpoint. 1180 ''; 1181 }; 1182 1183 dev = mkOption { 1184 type = types.nullOr types.str; 1185 default = null; 1186 example = "enp4s0f0"; 1187 description = '' 1188 The underlying network device on which the tunnel resides. 1189 ''; 1190 }; 1191 1192 encapsulation = 1193 with types; 1194 mkOption { 1195 type = nullOr (submodule { 1196 options = { 1197 type = mkOption { 1198 type = enum [ 1199 "fou" 1200 "gue" 1201 ]; 1202 description = '' 1203 Selects encapsulation type. See 1204 {manpage}`ip-link(8)` for details. 1205 ''; 1206 }; 1207 1208 port = mkOption { 1209 type = port; 1210 example = 9001; 1211 description = '' 1212 Destination port for encapsulated packets. 1213 ''; 1214 }; 1215 1216 sourcePort = mkOption { 1217 type = nullOr types.port; 1218 default = null; 1219 example = 9002; 1220 description = '' 1221 Source port for encapsulated packets. Will be chosen automatically by 1222 the kernel if unset. 1223 ''; 1224 }; 1225 }; 1226 }); 1227 default = null; 1228 example = { 1229 type = "fou"; 1230 port = 9001; 1231 }; 1232 description = '' 1233 Configures encapsulation in UDP packets. 1234 ''; 1235 }; 1236 1237 }; 1238 1239 }); 1240 }; 1241 1242 networking.greTunnels = mkOption { 1243 default = { }; 1244 example = literalExpression '' 1245 { 1246 greBridge = { 1247 remote = "10.0.0.1"; 1248 local = "10.0.0.22"; 1249 dev = "enp4s0f0"; 1250 type = "tap"; 1251 ttl = 255; 1252 }; 1253 gre6Tunnel = { 1254 remote = "fd7a:5634::1"; 1255 local = "fd7a:5634::2"; 1256 dev = "enp4s0f0"; 1257 type = "tun6"; 1258 ttl = 255; 1259 }; 1260 } 1261 ''; 1262 description = '' 1263 This option allows you to define Generic Routing Encapsulation (GRE) tunnels. 1264 ''; 1265 type = 1266 with types; 1267 attrsOf (submodule { 1268 options = { 1269 1270 remote = mkOption { 1271 type = types.nullOr types.str; 1272 default = null; 1273 example = "10.0.0.1"; 1274 description = '' 1275 The address of the remote endpoint to forward traffic over. 1276 ''; 1277 }; 1278 1279 local = mkOption { 1280 type = types.nullOr types.str; 1281 default = null; 1282 example = "10.0.0.22"; 1283 description = '' 1284 The address of the local endpoint which the remote 1285 side should send packets to. 1286 ''; 1287 }; 1288 1289 dev = mkOption { 1290 type = types.nullOr types.str; 1291 default = null; 1292 example = "enp4s0f0"; 1293 description = '' 1294 The underlying network device on which the tunnel resides. 1295 ''; 1296 }; 1297 1298 ttl = mkOption { 1299 type = types.nullOr types.int; 1300 default = null; 1301 example = 255; 1302 description = '' 1303 The time-to-live/hoplimit of the connection to the remote tunnel endpoint. 1304 ''; 1305 }; 1306 1307 type = mkOption { 1308 type = 1309 with types; 1310 enum [ 1311 "tun" 1312 "tap" 1313 "tun6" 1314 "tap6" 1315 ]; 1316 default = "tap"; 1317 example = "tap"; 1318 apply = 1319 v: 1320 { 1321 tun = "gre"; 1322 tap = "gretap"; 1323 tun6 = "ip6gre"; 1324 tap6 = "ip6gretap"; 1325 } 1326 .${v}; 1327 description = '' 1328 Whether the tunnel routes layer 2 (tap) or layer 3 (tun) traffic. 1329 ''; 1330 }; 1331 }; 1332 }); 1333 }; 1334 1335 networking.vlans = mkOption { 1336 default = { }; 1337 example = literalExpression '' 1338 { 1339 vlan0 = { 1340 id = 3; 1341 interface = "enp3s0"; 1342 }; 1343 vlan1 = { 1344 id = 1; 1345 interface = "wlan0"; 1346 }; 1347 } 1348 ''; 1349 description = '' 1350 This option allows you to define vlan devices that tag packets 1351 on top of a physical interface. The value of this option is an 1352 attribute set. Each attribute specifies a vlan, with the name 1353 specifying the name of the vlan interface. 1354 ''; 1355 1356 type = 1357 with types; 1358 attrsOf (submodule { 1359 1360 options = { 1361 1362 id = mkOption { 1363 example = 1; 1364 type = types.int; 1365 description = "The vlan identifier"; 1366 }; 1367 1368 interface = mkOption { 1369 example = "enp4s0"; 1370 type = types.str; 1371 description = "The interface the vlan will transmit packets through."; 1372 }; 1373 1374 }; 1375 1376 }); 1377 1378 }; 1379 1380 networking.wlanInterfaces = mkOption { 1381 default = { }; 1382 example = literalExpression '' 1383 { 1384 wlan-station0 = { 1385 device = "wlp6s0"; 1386 }; 1387 wlan-adhoc0 = { 1388 type = "ibss"; 1389 device = "wlp6s0"; 1390 mac = "02:00:00:00:00:01"; 1391 }; 1392 wlan-p2p0 = { 1393 device = "wlp6s0"; 1394 mac = "02:00:00:00:00:02"; 1395 }; 1396 wlan-ap0 = { 1397 device = "wlp6s0"; 1398 mac = "02:00:00:00:00:03"; 1399 }; 1400 } 1401 ''; 1402 description = '' 1403 Creating multiple WLAN interfaces on top of one physical WLAN device (NIC). 1404 1405 The name of the WLAN interface corresponds to the name of the attribute. 1406 A NIC is referenced by the persistent device name of the WLAN interface that 1407 `udev` assigns to a NIC by default. 1408 If a NIC supports multiple WLAN interfaces, then the one NIC can be used as 1409 `device` for multiple WLAN interfaces. 1410 If a NIC is used for creating WLAN interfaces, then the default WLAN interface 1411 with a persistent device name form `udev` is not created. 1412 A WLAN interface with the persistent name assigned from `udev` 1413 would have to be created explicitly. 1414 ''; 1415 1416 type = 1417 with types; 1418 attrsOf (submodule { 1419 1420 options = { 1421 1422 device = mkOption { 1423 type = types.str; 1424 example = "wlp6s0"; 1425 description = "The name of the underlying hardware WLAN device as assigned by `udev`."; 1426 }; 1427 1428 type = mkOption { 1429 type = types.enum [ 1430 "managed" 1431 "ibss" 1432 "monitor" 1433 "mesh" 1434 "wds" 1435 ]; 1436 default = "managed"; 1437 example = "ibss"; 1438 description = '' 1439 The type of the WLAN interface. 1440 The type has to be supported by the underlying hardware of the device. 1441 ''; 1442 }; 1443 1444 meshID = mkOption { 1445 type = types.nullOr types.str; 1446 default = null; 1447 description = "MeshID of interface with type `mesh`."; 1448 }; 1449 1450 flags = mkOption { 1451 type = 1452 with types; 1453 nullOr (enum [ 1454 "none" 1455 "fcsfail" 1456 "control" 1457 "otherbss" 1458 "cook" 1459 "active" 1460 ]); 1461 default = null; 1462 example = "control"; 1463 description = '' 1464 Flags for interface of type `monitor`. 1465 ''; 1466 }; 1467 1468 fourAddr = mkOption { 1469 type = types.nullOr types.bool; 1470 default = null; 1471 description = "Whether to enable `4-address mode` with type `managed`."; 1472 }; 1473 1474 mac = mkOption { 1475 type = types.nullOr types.str; 1476 default = null; 1477 example = "02:00:00:00:00:01"; 1478 description = '' 1479 MAC address to use for the device. If `null`, then the MAC of the 1480 underlying hardware WLAN device is used. 1481 1482 INFO: Locally administered MAC addresses are of the form: 1483 - x2:xx:xx:xx:xx:xx 1484 - x6:xx:xx:xx:xx:xx 1485 - xA:xx:xx:xx:xx:xx 1486 - xE:xx:xx:xx:xx:xx 1487 ''; 1488 }; 1489 1490 }; 1491 1492 }); 1493 1494 }; 1495 1496 networking.useDHCP = mkOption { 1497 type = types.bool; 1498 default = true; 1499 description = '' 1500 Whether to use DHCP to obtain an IP address and other 1501 configuration for all network interfaces that do not have any manually 1502 configured IPv4 addresses. 1503 ''; 1504 }; 1505 1506 networking.useNetworkd = mkOption { 1507 default = false; 1508 type = types.bool; 1509 description = '' 1510 Whether we should use networkd as the network configuration backend or 1511 the legacy script based system. Note that this option is experimental, 1512 enable at your own risk. 1513 ''; 1514 }; 1515 1516 networking.tempAddresses = mkOption { 1517 default = if cfg.enableIPv6 then "default" else "disabled"; 1518 defaultText = literalExpression '' 1519 if ''${config.${opt.enableIPv6}} then "default" else "disabled" 1520 ''; 1521 type = types.enum (lib.attrNames tempaddrValues); 1522 description = '' 1523 Whether to enable IPv6 Privacy Extensions for interfaces not 1524 configured explicitly in 1525 [](#opt-networking.interfaces._name_.tempAddress). 1526 1527 This sets the ipv6.conf.*.use_tempaddr sysctl for all 1528 interfaces. Possible values are: 1529 1530 ${tempaddrDoc} 1531 ''; 1532 }; 1533 1534 }; 1535 1536 ###### implementation 1537 1538 config = { 1539 1540 warnings = 1541 (concatMap (i: i.warnings) interfaces) 1542 ++ (lib.optional (config.systemd.network.enable && cfg.useDHCP && !cfg.useNetworkd) '' 1543 The combination of `systemd.network.enable = true`, `networking.useDHCP = true` and `networking.useNetworkd = false` can cause both networkd and dhcpcd to manage the same interfaces. This can lead to loss of networking. It is recommended you choose only one of networkd (by also enabling `networking.useNetworkd`) or scripting (by disabling `systemd.network.enable`) 1544 ''); 1545 1546 assertions = 1547 (forEach interfaces (i: { 1548 # With the linux kernel, interface name length is limited by IFNAMSIZ 1549 # to 16 bytes, including the trailing null byte. 1550 # See include/linux/if.h in the kernel sources 1551 assertion = stringLength i.name < 16; 1552 message = '' 1553 The name of networking.interfaces."${i.name}" is too long, it needs to be less than 16 characters. 1554 ''; 1555 })) 1556 ++ (forEach slaveIfs (i: { 1557 assertion = i.ipv4.addresses == [ ] && i.ipv6.addresses == [ ]; 1558 message = '' 1559 The networking.interfaces."${i.name}" must not have any defined ips when it is a slave. 1560 ''; 1561 })) 1562 ++ (forEach interfaces (i: { 1563 assertion = i.tempAddress != "disabled" -> cfg.enableIPv6; 1564 message = '' 1565 Temporary addresses are only needed when IPv6 is enabled. 1566 ''; 1567 })) 1568 ++ (forEach interfaces (i: { 1569 assertion = (i.virtual && i.virtualType == "tun") -> i.macAddress == null; 1570 message = '' 1571 Setting a MAC Address for tun device ${i.name} isn't supported. 1572 ''; 1573 })) 1574 ++ [ 1575 { 1576 assertion = cfg.hostId == null || (stringLength cfg.hostId == 8 && isHexString cfg.hostId); 1577 message = "Invalid value given to the networking.hostId option."; 1578 } 1579 ]; 1580 1581 boot.kernelModules = 1582 [ ] 1583 ++ optional hasVirtuals "tun" 1584 ++ optional hasSits "sit" 1585 ++ optional hasGres "gre" 1586 ++ optional hasBonds "bonding" 1587 ++ optional hasFous "fou"; 1588 1589 boot.extraModprobeConfig = 1590 # This setting is intentional as it prevents default bond devices 1591 # from being created. 1592 optionalString hasBonds "options bonding max_bonds=0"; 1593 1594 boot.kernel.sysctl = 1595 { 1596 "net.ipv4.conf.all.forwarding" = mkDefault (any (i: i.proxyARP) interfaces); 1597 "net.ipv6.conf.all.disable_ipv6" = mkDefault (!cfg.enableIPv6); 1598 "net.ipv6.conf.default.disable_ipv6" = mkDefault (!cfg.enableIPv6); 1599 # allow all users to do ICMP echo requests (ping) 1600 "net.ipv4.ping_group_range" = mkDefault "0 2147483647"; 1601 # networkmanager falls back to "/proc/sys/net/ipv6/conf/default/use_tempaddr" 1602 "net.ipv6.conf.default.use_tempaddr" = tempaddrValues.${cfg.tempAddresses}.sysctl; 1603 } 1604 // listToAttrs ( 1605 forEach interfaces ( 1606 i: nameValuePair "net.ipv4.conf.${replaceStrings [ "." ] [ "/" ] i.name}.proxy_arp" i.proxyARP 1607 ) 1608 ) 1609 // listToAttrs ( 1610 forEach interfaces ( 1611 i: 1612 let 1613 opt = i.tempAddress; 1614 val = tempaddrValues.${opt}.sysctl; 1615 in 1616 nameValuePair "net.ipv6.conf.${replaceStrings [ "." ] [ "/" ] i.name}.use_tempaddr" val 1617 ) 1618 ); 1619 1620 systemd.services.domainname = lib.mkIf (cfg.domain != null) { 1621 wantedBy = [ "sysinit.target" ]; 1622 before = [ 1623 "sysinit.target" 1624 "shutdown.target" 1625 ]; 1626 conflicts = [ "shutdown.target" ]; 1627 unitConfig.DefaultDependencies = false; 1628 serviceConfig.ExecStart = ''${pkgs.nettools}/bin/domainname "${cfg.domain}"''; 1629 serviceConfig.Type = "oneshot"; 1630 }; 1631 1632 environment.etc.hostid = mkIf (cfg.hostId != null) { source = hostidFile; }; 1633 boot.initrd.systemd.contents."/etc/hostid" = mkIf (cfg.hostId != null) { source = hostidFile; }; 1634 1635 # static hostname configuration needed for hostnamectl and the 1636 # org.freedesktop.hostname1 dbus service (both provided by systemd) 1637 environment.etc.hostname = mkIf (cfg.hostName != "") { 1638 text = cfg.hostName + "\n"; 1639 }; 1640 1641 environment.systemPackages = 1642 [ 1643 pkgs.host 1644 pkgs.iproute2 1645 pkgs.iputils 1646 pkgs.nettools 1647 ] 1648 ++ optionals config.networking.wireless.enable [ 1649 pkgs.wirelesstools # FIXME: obsolete? 1650 pkgs.iw 1651 ] 1652 ++ bridgeStp; 1653 1654 # Wake-on-LAN configuration is shared by the scripted and networkd backends. 1655 systemd.network.links = pipe interfaces [ 1656 (filter (i: i.wakeOnLan.enable)) 1657 (map ( 1658 i: 1659 nameValuePair "40-${i.name}" { 1660 matchConfig.OriginalName = i.name; 1661 linkConfig.WakeOnLan = concatStringsSep " " i.wakeOnLan.policy; 1662 } 1663 )) 1664 listToAttrs 1665 ]; 1666 1667 systemd.services = { 1668 network-local-commands = { 1669 enable = (cfg.localCommands != ""); 1670 description = "Extra networking commands."; 1671 before = [ "network.target" ]; 1672 wantedBy = [ "network.target" ]; 1673 after = [ "network-pre.target" ]; 1674 unitConfig.ConditionCapability = "CAP_NET_ADMIN"; 1675 path = [ pkgs.iproute2 ]; 1676 serviceConfig.Type = "oneshot"; 1677 serviceConfig.RemainAfterExit = true; 1678 script = '' 1679 # Run any user-specified commands. 1680 ${cfg.localCommands} 1681 ''; 1682 }; 1683 }; 1684 services.mstpd = mkIf needsMstpd { enable = true; }; 1685 1686 virtualisation.vswitch = mkIf (cfg.vswitches != { }) { enable = true; }; 1687 1688 services.udev.packages = 1689 [ 1690 (pkgs.writeTextFile rec { 1691 name = "ipv6-privacy-extensions.rules"; 1692 destination = "/etc/udev/rules.d/98-${name}"; 1693 text = 1694 let 1695 sysctl-value = tempaddrValues.${cfg.tempAddresses}.sysctl; 1696 in 1697 '' 1698 # enable and prefer IPv6 privacy addresses by default 1699 ACTION=="add", SUBSYSTEM=="net", RUN+="${pkgs.bash}/bin/sh -c 'echo ${sysctl-value} > /proc/sys/net/ipv6/conf/$name/use_tempaddr'" 1700 ''; 1701 }) 1702 (pkgs.writeTextFile rec { 1703 name = "ipv6-privacy-extensions.rules"; 1704 destination = "/etc/udev/rules.d/99-${name}"; 1705 text = concatMapStrings ( 1706 i: 1707 let 1708 opt = i.tempAddress; 1709 val = tempaddrValues.${opt}.sysctl; 1710 msg = tempaddrValues.${opt}.description; 1711 in 1712 '' 1713 # override to ${msg} for ${i.name} 1714 ACTION=="add", SUBSYSTEM=="net", NAME=="${i.name}", RUN+="${pkgs.procps}/bin/sysctl net.ipv6.conf.${ 1715 replaceStrings [ "." ] [ "/" ] i.name 1716 }.use_tempaddr=${val}" 1717 '' 1718 ) (filter (i: i.tempAddress != cfg.tempAddresses) interfaces); 1719 }) 1720 ] 1721 ++ lib.optional (cfg.wlanInterfaces != { }) ( 1722 pkgs.writeTextFile { 1723 name = "99-zzz-40-wlanInterfaces.rules"; 1724 destination = "/etc/udev/rules.d/99-zzz-40-wlanInterfaces.rules"; 1725 text = 1726 let 1727 # Collect all interfaces that are defined for a device 1728 # as device:interface key:value pairs. 1729 wlanDeviceInterfaces = 1730 let 1731 allDevices = unique (mapAttrsToList (_: v: v.device) cfg.wlanInterfaces); 1732 interfacesOfDevice = d: filterAttrs (_: v: v.device == d) cfg.wlanInterfaces; 1733 in 1734 genAttrs allDevices (d: interfacesOfDevice d); 1735 1736 # Convert device:interface key:value pairs into a list, and if it exists, 1737 # place the interface which is named after the device at the beginning. 1738 wlanListDeviceFirst = 1739 device: interfaces: 1740 if hasAttr device interfaces then 1741 mapAttrsToList (n: v: v // { _iName = n; }) (filterAttrs (n: _: n == device) interfaces) 1742 ++ mapAttrsToList (n: v: v // { _iName = n; }) (filterAttrs (n: _: n != device) interfaces) 1743 else 1744 mapAttrsToList (n: v: v // { _iName = n; }) interfaces; 1745 1746 # Udev script to execute for the default WLAN interface with the persistend udev name. 1747 # The script creates the required, new WLAN interfaces interfaces and configures the 1748 # existing, default interface. 1749 curInterfaceScript = 1750 device: current: new: 1751 pkgs.writeScript "udev-run-script-wlan-interfaces-${device}.sh" '' 1752 #!${pkgs.runtimeShell} 1753 # Change the wireless phy device to a predictable name. 1754 ${pkgs.iw}/bin/iw phy `${pkgs.coreutils}/bin/cat /sys/class/net/$INTERFACE/phy80211/name` set name ${device} 1755 1756 # Add new WLAN interfaces 1757 ${flip concatMapStrings new (i: '' 1758 ${pkgs.iw}/bin/iw phy ${device} interface add ${i._iName} type managed 1759 '')} 1760 1761 # Configure the current interface 1762 ${pkgs.iw}/bin/iw dev ${device} set type ${current.type} 1763 ${optionalString ( 1764 current.type == "mesh" && current.meshID != null 1765 ) "${pkgs.iw}/bin/iw dev ${device} set meshid ${current.meshID}"} 1766 ${optionalString ( 1767 current.type == "monitor" && current.flags != null 1768 ) "${pkgs.iw}/bin/iw dev ${device} set monitor ${current.flags}"} 1769 ${optionalString ( 1770 current.type == "managed" && current.fourAddr != null 1771 ) "${pkgs.iw}/bin/iw dev ${device} set 4addr ${if current.fourAddr then "on" else "off"}"} 1772 ${optionalString ( 1773 current.mac != null 1774 ) "${pkgs.iproute2}/bin/ip link set dev ${device} address ${current.mac}"} 1775 ''; 1776 1777 # Udev script to execute for a new WLAN interface. The script configures the new WLAN interface. 1778 newInterfaceScript = 1779 new: 1780 pkgs.writeScript "udev-run-script-wlan-interfaces-${new._iName}.sh" '' 1781 #!${pkgs.runtimeShell} 1782 # Configure the new interface 1783 ${pkgs.iw}/bin/iw dev ${new._iName} set type ${new.type} 1784 ${optionalString ( 1785 new.type == "mesh" && new.meshID != null 1786 ) "${pkgs.iw}/bin/iw dev ${new._iName} set meshid ${new.meshID}"} 1787 ${optionalString ( 1788 new.type == "monitor" && new.flags != null 1789 ) "${pkgs.iw}/bin/iw dev ${new._iName} set monitor ${new.flags}"} 1790 ${optionalString ( 1791 new.type == "managed" && new.fourAddr != null 1792 ) "${pkgs.iw}/bin/iw dev ${new._iName} set 4addr ${if new.fourAddr then "on" else "off"}"} 1793 ${optionalString ( 1794 new.mac != null 1795 ) "${pkgs.iproute2}/bin/ip link set dev ${new._iName} address ${new.mac}"} 1796 ''; 1797 1798 # Udev attributes for systemd to name the device and to create a .device target. 1799 systemdAttrs = 1800 n: 1801 ''NAME:="${n}", ENV{INTERFACE}="${n}", ENV{SYSTEMD_ALIAS}="/sys/subsystem/net/devices/${n}", TAG+="systemd"''; 1802 in 1803 flip (concatMapStringsSep "\n") (attrNames wlanDeviceInterfaces) ( 1804 device: 1805 let 1806 interfaces = wlanListDeviceFirst device wlanDeviceInterfaces.${device}; 1807 curInterface = elemAt interfaces 0; 1808 newInterfaces = drop 1 interfaces; 1809 in 1810 '' 1811 # It is important to have that rule first as overwriting the NAME attribute also prevents the 1812 # next rules from matching. 1813 ${flip (concatMapStringsSep "\n") (wlanListDeviceFirst device wlanDeviceInterfaces.${device}) ( 1814 interface: 1815 ''ACTION=="add", SUBSYSTEM=="net", ENV{DEVTYPE}=="wlan", ENV{INTERFACE}=="${interface._iName}", ${systemdAttrs interface._iName}, RUN+="${newInterfaceScript interface}"'' 1816 )} 1817 1818 # Add the required, new WLAN interfaces to the default WLAN interface with the 1819 # persistent, default name as assigned by udev. 1820 ACTION=="add", SUBSYSTEM=="net", ENV{DEVTYPE}=="wlan", NAME=="${device}", ${systemdAttrs curInterface._iName}, RUN+="${ 1821 curInterfaceScript device curInterface newInterfaces 1822 }" 1823 # Generate the same systemd events for both 'add' and 'move' udev events. 1824 ACTION=="move", SUBSYSTEM=="net", ENV{DEVTYPE}=="wlan", NAME=="${device}", ${systemdAttrs curInterface._iName} 1825 '' 1826 ); 1827 } 1828 ); 1829 }; 1830 1831}