at master 8.0 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7 8let 9 10 cfg = config.services.frr; 11 12 daemons = [ 13 "bgpd" 14 "ospfd" 15 "ospf6d" 16 "ripd" 17 "ripngd" 18 "isisd" 19 "pimd" 20 "pim6d" 21 "ldpd" 22 "nhrpd" 23 "eigrpd" 24 "babeld" 25 "sharpd" 26 "pbrd" 27 "bfdd" 28 "fabricd" 29 "vrrpd" 30 "pathd" 31 ]; 32 33 daemonDefaultOptions = { 34 zebra = "-A 127.0.0.1 -s 90000000"; 35 mgmtd = "-A 127.0.0.1"; 36 bgpd = "-A 127.0.0.1"; 37 ospfd = "-A 127.0.0.1"; 38 ospf6d = "-A ::1"; 39 ripd = "-A 127.0.0.1"; 40 ripngd = "-A ::1"; 41 isisd = "-A 127.0.0.1"; 42 pimd = "-A 127.0.0.1"; 43 pim6d = "-A ::1"; 44 ldpd = "-A 127.0.0.1"; 45 nhrpd = "-A 127.0.0.1"; 46 eigrpd = "-A 127.0.0.1"; 47 babeld = "-A 127.0.0.1"; 48 sharpd = "-A 127.0.0.1"; 49 pbrd = "-A 127.0.0.1"; 50 staticd = "-A 127.0.0.1"; 51 bfdd = "-A 127.0.0.1"; 52 fabricd = "-A 127.0.0.1"; 53 vrrpd = "-A 127.0.0.1"; 54 pathd = "-A 127.0.0.1"; 55 }; 56 57 renamedServices = [ 58 "bgp" 59 "ospf" 60 "ospf6" 61 "rip" 62 "ripng" 63 "isis" 64 "pim" 65 "ldp" 66 "nhrp" 67 "eigrp" 68 "babel" 69 "sharp" 70 "pbr" 71 "bfd" 72 "fabric" 73 ]; 74 75 obsoleteServices = renamedServices ++ [ 76 "static" 77 "mgmt" 78 "zebra" 79 ]; 80 81 allDaemons = builtins.attrNames daemonDefaultOptions; 82 83 isEnabled = service: cfg.${service}.enable; 84 85 daemonLine = d: "${d}=${if isEnabled d then "yes" else "no"}"; 86 87 configFile = 88 if cfg.configFile != null then 89 cfg.configFile 90 else 91 pkgs.writeText "frr.conf" '' 92 ! FRR configuration 93 ! 94 hostname ${config.networking.hostName} 95 log syslog 96 service password-encryption 97 service integrated-vtysh-config 98 ! 99 ${cfg.config} 100 ! 101 end 102 ''; 103 104 serviceOptions = 105 service: 106 { 107 options = lib.mkOption { 108 type = lib.types.listOf lib.types.str; 109 default = [ daemonDefaultOptions.${service} ]; 110 description = '' 111 Options for the FRR ${service} daemon. 112 ''; 113 }; 114 extraOptions = lib.mkOption { 115 type = lib.types.listOf lib.types.str; 116 default = [ ]; 117 description = '' 118 Extra options to be appended to the FRR ${service} daemon options. 119 ''; 120 }; 121 } 122 // ( 123 if (builtins.elem service daemons) then { enable = lib.mkEnableOption "FRR ${service}"; } else { } 124 ); 125 126in 127 128{ 129 130 ###### interface 131 imports = [ 132 { 133 options.services.frr = { 134 configFile = lib.mkOption { 135 type = lib.types.nullOr lib.types.path; 136 default = null; 137 example = "/etc/frr/frr.conf"; 138 description = '' 139 Configuration file to use for FRR. 140 By default the NixOS generated files are used. 141 ''; 142 }; 143 config = lib.mkOption { 144 type = lib.types.lines; 145 default = ""; 146 example = '' 147 router rip 148 network 10.0.0.0/8 149 router ospf 150 network 10.0.0.0/8 area 0 151 router bgp 65001 152 neighbor 10.0.0.1 remote-as 65001 153 ''; 154 description = '' 155 FRR configuration statements. 156 ''; 157 }; 158 openFilesLimit = lib.mkOption { 159 type = lib.types.ints.unsigned; 160 default = 1024; 161 description = '' 162 This is the maximum number of FD's that will be available. Use a 163 reasonable value for your setup if you are expecting a large number 164 of peers in say BGP. 165 ''; 166 }; 167 }; 168 } 169 { options.services.frr = (lib.genAttrs allDaemons serviceOptions); } 170 (lib.mkRemovedOptionModule [ "services" "frr" "zebra" "enable" ] "FRR zebra is always enabled") 171 ] 172 ++ (map ( 173 d: lib.mkRenamedOptionModule [ "services" "frr" d "enable" ] [ "services" "frr" "${d}d" "enable" ] 174 ) renamedServices) 175 ++ (map 176 ( 177 d: 178 lib.mkRenamedOptionModule 179 [ "services" "frr" d "extraOptions" ] 180 [ "services" "frr" "${d}d" "extraOptions" ] 181 ) 182 ( 183 renamedServices 184 ++ [ 185 "static" 186 "mgmt" 187 ] 188 ) 189 ) 190 ++ (map (d: lib.mkRemovedOptionModule [ "services" "frr" d "enable" ] "FRR ${d}d is always enabled") 191 [ 192 "static" 193 "mgmt" 194 ] 195 ) 196 ++ (map ( 197 d: 198 lib.mkRemovedOptionModule [ 199 "services" 200 "frr" 201 d 202 "config" 203 ] "FRR switched to integrated-vtysh-config, please use services.frr.config" 204 ) obsoleteServices) 205 ++ (map ( 206 d: 207 lib.mkRemovedOptionModule [ "services" "frr" d "configFile" ] 208 "FRR switched to integrated-vtysh-config, please use services.frr.config or services.frr.configFile" 209 ) obsoleteServices) 210 ++ (map ( 211 d: 212 lib.mkRemovedOptionModule [ 213 "services" 214 "frr" 215 d 216 "vtyListenAddress" 217 ] "Please change -A option in services.frr.${d}.options instead" 218 ) obsoleteServices) 219 ++ (map ( 220 d: 221 lib.mkRemovedOptionModule [ "services" "frr" d "vtyListenPort" ] 222 "Please use `-P «vtyListenPort»` option with services.frr.${d}.extraOptions instead, or change services.frr.${d}.options accordingly" 223 ) obsoleteServices); 224 225 ###### implementation 226 227 config = 228 let 229 daemonList = lib.concatStringsSep "\n" (map daemonLine daemons); 230 daemonOptionLine = 231 d: "${d}_options=\"${lib.concatStringsSep " " (cfg.${d}.options ++ cfg.${d}.extraOptions)}\""; 232 daemonOptions = lib.concatStringsSep "\n" (map daemonOptionLine allDaemons); 233 in 234 lib.mkIf (lib.any isEnabled daemons || cfg.configFile != null || cfg.config != "") { 235 236 environment.systemPackages = [ 237 pkgs.frr # for the vtysh tool 238 ]; 239 240 users.users.frr = { 241 description = "FRR daemon user"; 242 isSystemUser = true; 243 group = "frr"; 244 }; 245 246 users.groups = { 247 frr = { }; 248 # Members of the frrvty group can use vtysh to inspect the FRR daemons 249 frrvty = { 250 members = [ "frr" ]; 251 }; 252 }; 253 254 environment.etc = { 255 "frr/frr.conf".source = configFile; 256 "frr/vtysh.conf".text = '' 257 service integrated-vtysh-config 258 ''; 259 "frr/daemons".text = '' 260 # This file tells the frr package which daemons to start. 261 # 262 # The watchfrr, zebra and staticd daemons are always started. 263 # 264 # This part is auto-generated from services.frr.<daemon>.enable config 265 ${daemonList} 266 267 # If this option is set the /etc/init.d/frr script automatically loads 268 # the config via "vtysh -b" when the servers are started. 269 # 270 vtysh_enable=yes 271 272 # This part is auto-generated from services.frr.<daemon>.options or 273 # services.frr.<daemon>.extraOptions 274 ${daemonOptions} 275 ''; 276 }; 277 278 systemd.tmpfiles.rules = [ "d /run/frr 0755 frr frr -" ]; 279 280 systemd.services.frr = { 281 description = "FRRouting"; 282 documentation = [ "https://frrouting.readthedocs.io/en/latest/setup.html" ]; 283 wants = [ "network.target" ]; 284 after = [ 285 "network-pre.target" 286 "systemd-sysctl.service" 287 ]; 288 before = [ "network.target" ]; 289 wantedBy = [ "multi-user.target" ]; 290 startLimitIntervalSec = 180; 291 reloadIfChanged = true; 292 restartTriggers = [ 293 configFile 294 daemonList 295 ]; 296 serviceConfig = { 297 Nice = -5; 298 Type = "forking"; 299 NotifyAccess = "all"; 300 TimeoutSec = 120; 301 WatchdogSec = 60; 302 RestartSec = 5; 303 Restart = "always"; 304 LimitNOFILE = cfg.openFilesLimit; 305 PIDFile = "/run/frr/watchfrr.pid"; 306 ExecStart = "${pkgs.frr}/libexec/frr/frrinit.sh start"; 307 ExecStop = "${pkgs.frr}/libexec/frr/frrinit.sh stop"; 308 ExecReload = "${pkgs.frr}/libexec/frr/frrinit.sh reload"; 309 }; 310 unitConfig = { 311 StartLimitBurst = "3"; 312 }; 313 }; 314 }; 315 316 meta.maintainers = with lib.maintainers; [ woffs ]; 317}