infrastructure/config/modules/nixos/bird.nix

176 lines
5.7 KiB
Nix

{ config, lib, pkgs, ... }:
with lib;
let
bcfg = config.network.bird;
cfg = config.network.bird.ospf;
in
{
options.network.bird = {
routerId = mkOption {
type = types.nullOr types.str;
default = null;
description = "Router ID to use. Must be an IPv4 address.";
};
kernel4Config = mkOption {
type = types.lines;
default = ''
ipv4 {
import none;
export filter {
if source = RTS_STATIC then reject;
accept;
};
};
scan time 15;
'';
};
kernel6Config = mkOption {
type = types.lines;
default = ''
ipv6 {
import none;
export filter {
if source = RTS_STATIC then reject;
accept;
};
};
scan time 15;
'';
};
staticRoutes4 = mkOption {
type = types.listOf types.str;
default = [ ];
};
extraStatic4 = mkOption {
type = types.lines;
default = "";
};
staticRoutes6 = mkOption {
type = types.listOf types.str;
default = [ ];
};
extraStatic6 = mkOption {
type = types.lines;
default = "";
};
};
options.network.bird.ospf = {
enable = mkEnableOption "OSPF-based network routing";
protocols = mkOption {
default = { };
type = types.attrsOf (types.submodule {
options = {
version = mkOption { type = types.enum [ 2 3 ]; default = 2; };
extra = mkOption { type = types.lines; default = ""; };
areas = mkOption {
description = "areas to configure in bird";
default = { };
type = types.attrsOf (types.submodule {
options = {
extra = mkOption { type = types.lines; default = ""; };
networks = mkOption {
description = "Definition of area IP ranges. This is used in summary LSA origination.";
type = types.listOf types.str;
default = [ ];
};
external = mkOption {
description = "Definition of external area IP ranges for NSSAs. This is used for NSSA-LSA translation.";
type = types.listOf types.str;
default = [ ];
};
interfaces = mkOption {
description = "Interfaces to assign to the area";
type = types.attrsOf (types.submodule {
options = {
cost = mkOption { type = types.int; default = 10; };
poll = mkOption { type = types.int; default = 20; };
retransmit = mkOption { type = types.int; default = 5; };
priority = mkOption { type = types.int; default = 1; };
deadCount = mkOption { type = types.int; default = 4; };
type = mkOption {
type = types.enum [
null
"broadcast"
"bcast"
"pointopoint"
"ptp"
"nonbroadcast"
"nbma"
"pointomultipoint"
"ptmp"
];
default = null;
};
extra = mkOption { type = types.lines; default = ""; };
};
});
};
};
});
};
};
});
};
};
config = mkIf cfg.enable {
services.bird2 = {
enable = true;
config = ''
${optionalString (bcfg.routerId != null) "router id ${bcfg.routerId};"}
protocol device {
scan time 10;
}
protocol kernel kernel4 {
${bcfg.kernel4Config}
}
protocol kernel kernel6 {
${bcfg.kernel6Config}
}
protocol static static4 {
ipv4 { import all; export none; };
${concatMapStringsSep "\n" (x: "route ${x};") bcfg.staticRoutes4}
${bcfg.extraStatic4}
}
protocol static static6 {
ipv6 { import all; export none; };
${concatMapStringsSep "\n" (x: "route ${x};") bcfg.staticRoutes6}
${bcfg.extraStatic6}
}
${concatStringsSep "\n" (mapAttrsToList (protoName: proto: ''
protocol ospf v${toString proto.version} ${protoName} {
${concatStringsSep "\n" (mapAttrsToList (areaName: area: ''
area ${areaName} {
${optionalString
(area.networks != [])
"networks { ${concatStringsSep "\n" (map (x: "${x};") area.networks)} };"}
${optionalString
(area.external != [])
"external { ${concatStringsSep "\n" (map (x: "${x};") area.external)} };"}
${concatStringsSep "\n" (mapAttrsToList (ifacePattern: iface: ''
interface "${ifacePattern}" {
cost ${toString iface.cost};
poll ${toString iface.poll};
retransmit ${toString iface.retransmit};
priority ${toString iface.priority};
dead count ${toString iface.deadCount};
${optionalString (iface.type != null) "type ${iface.type};"}
${iface.extra}
};
'') area.interfaces)}
${area.extra}
};
'') proto.areas)}
${proto.extra}
}
'') cfg.protocols)}
'';
};
};
}