Merge: zmap: 4.2.0 -> 4.3.1 (#364578)
[NixPkgs.git] / nixos / modules / services / networking / frr.nix
blobe26385802af16548ff152d6d6ec4b4c2a10b48f7
2   config,
3   lib,
4   pkgs,
5   ...
6 }:
8 let
10   cfg = config.services.frr;
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   ];
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   };
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   ];
75   obsoleteServices = renamedServices ++ [
76     "static"
77     "mgmt"
78     "zebra"
79   ];
81   allDaemons = builtins.attrNames daemonDefaultOptions;
83   isEnabled = service: cfg.${service}.enable;
85   daemonLine = d: "${d}=${if isEnabled d then "yes" else "no"}";
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       '';
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     );
130   ###### interface
131   imports =
132     [
133       {
134         options.services.frr = {
135           configFile = lib.mkOption {
136             type = lib.types.nullOr lib.types.path;
137             default = null;
138             example = "/etc/frr/frr.conf";
139             description = ''
140               Configuration file to use for FRR.
141               By default the NixOS generated files are used.
142             '';
143           };
144           config = lib.mkOption {
145             type = lib.types.lines;
146             default = "";
147             example = ''
148               router rip
149                 network 10.0.0.0/8
150               router ospf
151                 network 10.0.0.0/8 area 0
152               router bgp 65001
153                 neighbor 10.0.0.1 remote-as 65001
154             '';
155             description = ''
156               FRR configuration statements.
157             '';
158           };
159           openFilesLimit = lib.mkOption {
160             type = lib.types.ints.unsigned;
161             default = 1024;
162             description = ''
163               This is the maximum number of FD's that will be available.  Use a
164               reasonable value for your setup if you are expecting a large number
165               of peers in say BGP.
166             '';
167           };
168         };
169       }
170       { options.services.frr = (lib.genAttrs allDaemons serviceOptions); }
171       (lib.mkRemovedOptionModule [ "services" "frr" "zebra" "enable" ] "FRR zebra is always enabled")
172     ]
173     ++ (map (
174       d: lib.mkRenamedOptionModule [ "services" "frr" d "enable" ] [ "services" "frr" "${d}d" "enable" ]
175     ) renamedServices)
176     ++ (map
177       (
178         d:
179         lib.mkRenamedOptionModule
180           [ "services" "frr" d "extraOptions" ]
181           [ "services" "frr" "${d}d" "extraOptions" ]
182       )
183       (
184         renamedServices
185         ++ [
186           "static"
187           "mgmt"
188         ]
189       )
190     )
191     ++ (map (d: lib.mkRemovedOptionModule [ "services" "frr" d "enable" ] "FRR ${d}d is always enabled")
192       [
193         "static"
194         "mgmt"
195       ]
196     )
197     ++ (map (
198       d:
199       lib.mkRemovedOptionModule [
200         "services"
201         "frr"
202         d
203         "config"
204       ] "FRR switched to integrated-vtysh-config, please use services.frr.config"
205     ) obsoleteServices)
206     ++ (map (
207       d:
208       lib.mkRemovedOptionModule [ "services" "frr" d "configFile" ]
209         "FRR switched to integrated-vtysh-config, please use services.frr.config or services.frr.configFile"
210     ) obsoleteServices)
211     ++ (map (
212       d:
213       lib.mkRemovedOptionModule [
214         "services"
215         "frr"
216         d
217         "vtyListenAddress"
218       ] "Please change -A option in services.frr.${d}.options instead"
219     ) obsoleteServices)
220     ++ (map (
221       d:
222       lib.mkRemovedOptionModule [ "services" "frr" d "vtyListenPort" ]
223         "Please use `-P «vtyListenPort»` option with services.frr.${d}.extraOptions instead, or change services.frr.${d}.options accordingly"
224     ) obsoleteServices);
226   ###### implementation
228   config =
229     let
230       daemonList = lib.concatStringsSep "\n" (map daemonLine daemons);
231       daemonOptionLine =
232         d: "${d}_options=\"${lib.concatStringsSep " " (cfg.${d}.options ++ cfg.${d}.extraOptions)}\"";
233       daemonOptions = lib.concatStringsSep "\n" (map daemonOptionLine allDaemons);
234     in
235     lib.mkIf (lib.any isEnabled daemons || cfg.configFile != null || cfg.config != "") {
237       environment.systemPackages = [
238         pkgs.frr # for the vtysh tool
239       ];
241       users.users.frr = {
242         description = "FRR daemon user";
243         isSystemUser = true;
244         group = "frr";
245       };
247       users.groups = {
248         frr = { };
249         # Members of the frrvty group can use vtysh to inspect the FRR daemons
250         frrvty = {
251           members = [ "frr" ];
252         };
253       };
255       environment.etc = {
256         "frr/frr.conf".source = configFile;
257         "frr/vtysh.conf".text = ''
258           service integrated-vtysh-config
259         '';
260         "frr/daemons".text = ''
261           # This file tells the frr package which daemons to start.
262           #
263           # The watchfrr, zebra and staticd daemons are always started.
264           #
265           # This part is auto-generated from services.frr.<daemon>.enable config
266           ${daemonList}
268           # If this option is set the /etc/init.d/frr script automatically loads
269           # the config via "vtysh -b" when the servers are started.
270           #
271           vtysh_enable=yes
273           # This part is auto-generated from services.frr.<daemon>.options or
274           # services.frr.<daemon>.extraOptions
275           ${daemonOptions}
276         '';
277       };
279       systemd.tmpfiles.rules = [ "d /run/frr 0755 frr frr -" ];
281       systemd.services.frr = {
282         description = "FRRouting";
283         documentation = [ "https://frrouting.readthedocs.io/en/latest/setup.html" ];
284         wants = [ "network.target" ];
285         after = [
286           "network-pre.target"
287           "systemd-sysctl.service"
288         ];
289         before = [ "network.target" ];
290         wantedBy = [ "multi-user.target" ];
291         startLimitIntervalSec = 180;
292         reloadIfChanged = true;
293         restartTriggers = [
294           configFile
295           daemonList
296         ];
297         serviceConfig = {
298           Nice = -5;
299           Type = "forking";
300           NotifyAccess = "all";
301           StartLimitBurst = "3";
302           TimeoutSec = 120;
303           WatchdogSec = 60;
304           RestartSec = 5;
305           Restart = "always";
306           LimitNOFILE = cfg.openFilesLimit;
307           PIDFile = "/run/frr/watchfrr.pid";
308           ExecStart = "${pkgs.frr}/libexec/frr/frrinit.sh start";
309           ExecStop = "${pkgs.frr}/libexec/frr/frrinit.sh stop";
310           ExecReload = "${pkgs.frr}/libexec/frr/frrinit.sh reload";
311         };
312       };
313     };
315   meta.maintainers = with lib.maintainers; [ woffs ];