Merge pull request #1432 from wkennington/bond

network-interfaces: Add the ability to create bond devices

+139 -3
+1
nixos/modules/services/networking/dhcpcd.nix
··· 11 11 ignoredInterfaces = 12 12 map (i: i.name) (filter (i: i.ipAddress != null) (attrValues config.networking.interfaces)) 13 13 ++ concatLists (attrValues (mapAttrs (n: v: v.interfaces) config.networking.bridges)) 14 + ++ concatLists (attrValues (mapAttrs (n: v: v.interfaces) config.networking.bonds)) 14 15 ++ config.networking.dhcpcd.denyInterfaces; 15 16 16 17 # Config file adapted from the one that ships with dhcpcd.
+110 -3
nixos/modules/tasks/network-interfaces.nix
··· 7 7 cfg = config.networking; 8 8 interfaces = attrValues cfg.interfaces; 9 9 hasVirtuals = any (i: i.virtual) interfaces; 10 + hasBonds = cfg.bonds != { }; 10 11 11 12 interfaceOpts = { name, ... }: { 12 13 ··· 228 229 229 230 }; 230 231 232 + networking.bonds = mkOption { 233 + default = { }; 234 + example = { 235 + bond0 = { 236 + interfaces = [ "eth0" "wlan0" ]; 237 + miimon = 100; 238 + mode = "active-backup"; 239 + }; 240 + fatpipe.interfaces = [ "enp4s0f0" "enp4s0f1" "enp5s0f0" "enp5s0f1" ]; 241 + }; 242 + description = '' 243 + This option allows you to define bond devices that aggregate multiple, 244 + underlying networking interfaces together. The value of this option is 245 + an attribute set. Each attribute specifies a bond, with the attribute 246 + name specifying the name of the bond's network interface 247 + ''; 248 + 249 + type = types.attrsOf types.optionSet; 250 + 251 + options = { 252 + 253 + interfaces = mkOption { 254 + example = [ "enp4s0f0" "enp4s0f1" "wlan0" ]; 255 + type = types.listOf types.string; 256 + description = "The interfaces to bond together"; 257 + }; 258 + 259 + miimon = mkOption { 260 + default = null; 261 + example = 100; 262 + type = types.nullOr types.int; 263 + description = '' 264 + Miimon is the number of millisecond in between each round of polling 265 + by the device driver for failed links. By default polling is not 266 + enabled and the driver is trusted to properly detect and handle 267 + failure scenarios. 268 + ''; 269 + }; 270 + 271 + mode = mkOption { 272 + default = null; 273 + example = "active-backup"; 274 + type = types.nullOr types.string; 275 + description = '' 276 + The mode which the bond will be running. The default mode for 277 + the bonding driver is balance-rr, optimizing for throughput. 278 + More information about valid modes can be found at 279 + https://www.kernel.org/doc/Documentation/networking/bonding.txt 280 + ''; 281 + }; 282 + 283 + }; 284 + }; 285 + 231 286 networking.vlans = mkOption { 232 287 default = { }; 233 288 example = { ··· 284 339 285 340 config = { 286 341 287 - boot.kernelModules = optional cfg.enableIPv6 "ipv6" ++ optional hasVirtuals "tun"; 342 + boot.kernelModules = [ ] 343 + ++ optional cfg.enableIPv6 "ipv6" 344 + ++ optional hasVirtuals "tun" 345 + ++ optional hasBonds "bonding"; 346 + 347 + boot.extraModprobeConfig = 348 + # This setting is intentional as it prevents default bond devices 349 + # from being created. 350 + optionalString hasBonds "options bonding max_bonds=0"; 288 351 289 352 environment.systemPackages = 290 353 [ pkgs.host ··· 450 513 path = [ pkgs.bridge_utils pkgs.iproute ]; 451 514 script = 452 515 '' 516 + # Remove Dead Interfaces 517 + ip link show "${n}" >/dev/null 2>&1 && ip link delete "${n}" 518 + 453 519 brctl addbr "${n}" 454 520 455 521 # Set bridge's hello time to 0 to avoid startup delays. ··· 474 540 ''; 475 541 }; 476 542 543 + createBondDevice = n: v: 544 + let 545 + deps = map (i: "sys-subsystem-net-devices-${i}.device") v.interfaces; 546 + in 547 + { description = "Bond Interface ${n}"; 548 + wantedBy = [ "network.target" "sys-subsystem-net-devices-${n}.device" ]; 549 + bindsTo = deps; 550 + after = deps; 551 + serviceConfig.Type = "oneshot"; 552 + serviceConfig.RemainAfterExit = true; 553 + path = [ pkgs.ifenslave pkgs.iproute ]; 554 + script = '' 555 + # Remove Dead Interfaces 556 + ip link show "${n}" >/dev/null 2>&1 && ip link delete "${n}" 557 + 558 + ip link add "${n}" type bond 559 + 560 + # !!! There must be a better way to wait for the interface 561 + while [ ! -d /sys/class/net/${n} ]; do sleep 0.1; done; 562 + 563 + # Set the miimon and mode options 564 + ${optionalString (v.miimon != null) 565 + "echo ${toString v.miimon} > /sys/class/net/${n}/bonding/miimon"} 566 + ${optionalString (v.mode != null) 567 + "echo \"${v.mode}\" > /sys/class/net/${n}/bonding/mode"} 568 + 569 + # Bring up the bridge and enslave the specified interfaces 570 + ip link set "${n}" up 571 + ${flip concatMapStrings v.interfaces (i: '' 572 + ifenslave "${n}" "${i}" 573 + '')} 574 + ''; 575 + postStop = '' 576 + ip link set "${n}" down 577 + ifenslave -d "${n}" 578 + ip link delete "${n}" 579 + ''; 580 + }; 581 + 477 582 createVlanDevice = n: v: 478 583 let 479 584 deps = [ "sys-subsystem-net-devices-${v.interface}.device" ]; 480 585 in 481 - { 482 - description = "Vlan Interface ${n}"; 586 + { description = "Vlan Interface ${n}"; 483 587 wantedBy = [ "network.target" "sys-subsystem-net-devices-${n}.device" ]; 484 588 bindsTo = deps; 485 589 after = deps; ··· 487 591 serviceConfig.RemainAfterExit = true; 488 592 path = [ pkgs.iproute ]; 489 593 script = '' 594 + # Remove Dead Interfaces 595 + ip link show "${n}" >/dev/null 2>&1 && ip link delete "${n}" 490 596 ip link add link "${v.interface}" "${n}" type vlan id "${toString v.id}" 491 597 ip link set "${n}" up 492 598 ''; ··· 499 605 map configureInterface interfaces ++ 500 606 map createTunDevice (filter (i: i.virtual) interfaces)) 501 607 // mapAttrs createBridgeDevice cfg.bridges 608 + // mapAttrs createBondDevice cfg.bonds 502 609 // mapAttrs createVlanDevice cfg.vlans 503 610 // { "network-setup" = networkSetup; }; 504 611
+26
pkgs/os-specific/linux/ifenslave/default.nix
··· 1 + { stdenv, fetchurl }: 2 + 3 + stdenv.mkDerivation rec { 4 + name = "ifenslave-${version}"; 5 + version = "1.1.0"; 6 + 7 + src = fetchurl { 8 + url = "mirror://debian/pool/main/i/ifenslave-2.6/ifenslave-2.6_${version}.orig.tar.gz"; 9 + sha256 = "0h9hrmy19zdksl7ys250r158b943ihbgkb95n8p4k8l0vqsby5vr"; 10 + }; 11 + 12 + buildPhase = '' 13 + gcc -o ifenslave ifenslave.c 14 + ''; 15 + 16 + installPhase = '' 17 + mkdir -p $out/bin 18 + cp -a ifenslave $out/bin 19 + ''; 20 + 21 + meta = { 22 + description = "Utility for enslaving networking interfaces under a bond"; 23 + license = stdenv.lib.licenses.gpl2; 24 + platforms = stdenv.lib.platforms.linux; 25 + }; 26 + }
+2
pkgs/top-level/all-packages.nix
··· 8221 8221 8222 8222 id3v2 = callPackage ../applications/audio/id3v2 { }; 8223 8223 8224 + ifenslave = callPackage ../os-specific/linux/ifenslave { }; 8225 + 8224 8226 ii = callPackage ../applications/networking/irc/ii { }; 8225 8227 8226 8228 ike = callPackage ../applications/ike { };