python3Packages.orjson: Disable failing tests on 32 bit
[NixPkgs.git] / nixos / modules / services / networking / frr.nix
blobd350fe3548ae1b4a8dbfd7bda007991dfac2851b
1 { config, lib, pkgs, ... }:
3 with lib;
5 let
7   cfg = config.services.frr;
9   services = [
10     "static"
11     "bgp"
12     "ospf"
13     "ospf6"
14     "rip"
15     "ripng"
16     "isis"
17     "pim"
18     "ldp"
19     "nhrp"
20     "eigrp"
21     "babel"
22     "sharp"
23     "pbr"
24     "bfd"
25     "fabric"
26   ];
28   allServices = services ++ [ "zebra" ];
30   isEnabled = service: cfg.${service}.enable;
32   daemonName = service: if service == "zebra" then service else "${service}d";
34   configFile = service:
35     let
36       scfg = cfg.${service};
37     in
38       if scfg.configFile != null then scfg.configFile
39       else pkgs.writeText "${daemonName service}.conf"
40         ''
41           ! FRR ${daemonName service} configuration
42           !
43           hostname ${config.networking.hostName}
44           log syslog
45           service password-encryption
46           !
47           ${scfg.config}
48           !
49           end
50         '';
52   serviceOptions = service:
53     {
54       enable = mkEnableOption (lib.mdDoc "the FRR ${toUpper service} routing protocol");
56       configFile = mkOption {
57         type = types.nullOr types.path;
58         default = null;
59         example = "/etc/frr/${daemonName service}.conf";
60         description = lib.mdDoc ''
61           Configuration file to use for FRR ${daemonName service}.
62           By default the NixOS generated files are used.
63         '';
64       };
66       config = mkOption {
67         type = types.lines;
68         default = "";
69         example =
70           let
71             examples = {
72               rip = ''
73                 router rip
74                   network 10.0.0.0/8
75               '';
77               ospf = ''
78                 router ospf
79                   network 10.0.0.0/8 area 0
80               '';
82               bgp = ''
83                 router bgp 65001
84                   neighbor 10.0.0.1 remote-as 65001
85               '';
86             };
87           in
88             examples.${service} or "";
89         description = lib.mdDoc ''
90           ${daemonName service} configuration statements.
91         '';
92       };
94       vtyListenAddress = mkOption {
95         type = types.str;
96         default = "localhost";
97         description = lib.mdDoc ''
98           Address to bind to for the VTY interface.
99         '';
100       };
102       vtyListenPort = mkOption {
103         type = types.nullOr types.int;
104         default = null;
105         description = lib.mdDoc ''
106           TCP Port to bind to for the VTY interface.
107         '';
108       };
110       extraOptions = mkOption {
111         type = types.listOf types.str;
112         default = [];
113         description = lib.mdDoc ''
114           Extra options for the daemon.
115         '';
116       };
117     };
123   ###### interface
124   imports = [
125     {
126       options.services.frr = {
127         zebra = (serviceOptions "zebra") // {
128           enable = mkOption {
129             type = types.bool;
130             default = any isEnabled services;
131             description = lib.mdDoc ''
132               Whether to enable the Zebra routing manager.
134               The Zebra routing manager is automatically enabled
135               if any routing protocols are configured.
136             '';
137           };
138         };
139       };
140     }
141     { options.services.frr = (genAttrs services serviceOptions); }
142   ];
144   ###### implementation
146   config = mkIf (any isEnabled allServices) {
148     environment.systemPackages = [
149       pkgs.frr # for the vtysh tool
150     ];
152     users.users.frr = {
153       description = "FRR daemon user";
154       isSystemUser = true;
155       group = "frr";
156     };
158     users.groups = {
159       frr = {};
160       # Members of the frrvty group can use vtysh to inspect the FRR daemons
161       frrvty = { members = [ "frr" ]; };
162     };
164     environment.etc = let
165       mkEtcLink = service: {
166         name = "frr/${service}.conf";
167         value.source = configFile service;
168       };
169     in
170       (builtins.listToAttrs
171       (map mkEtcLink (filter isEnabled allServices))) // {
172         "frr/vtysh.conf".text = "";
173       };
175     systemd.tmpfiles.rules = [
176       "d /run/frr 0750 frr frr -"
177     ];
179     systemd.services =
180       let
181         frrService = service:
182           let
183             scfg = cfg.${service};
184             daemon = daemonName service;
185           in
186             nameValuePair daemon ({
187               wantedBy = [ "multi-user.target" ];
188               after = [ "network-pre.target" "systemd-sysctl.service" ] ++ lib.optionals (service != "zebra") [ "zebra.service" ];
189               bindsTo = lib.optionals (service != "zebra") [ "zebra.service" ];
190               wants = [ "network.target" ];
192               description = if service == "zebra" then "FRR Zebra routing manager"
193                 else "FRR ${toUpper service} routing daemon";
195               unitConfig.Documentation = if service == "zebra" then "man:zebra(8)"
196                 else "man:${daemon}(8) man:zebra(8)";
198               restartTriggers = [
199                 (configFile service)
200               ];
201               reloadIfChanged = true;
203               serviceConfig = {
204                 PIDFile = "frr/${daemon}.pid";
205                 ExecStart = "${pkgs.frr}/libexec/frr/${daemon} -f /etc/frr/${service}.conf"
206                   + optionalString (scfg.vtyListenAddress != "") " -A ${scfg.vtyListenAddress}"
207                   + optionalString (scfg.vtyListenPort != null) " -P ${toString scfg.vtyListenPort}"
208                   + " " + (concatStringsSep " " scfg.extraOptions);
209                 ExecReload = "${pkgs.python3.interpreter} ${pkgs.frr}/libexec/frr/frr-reload.py --reload --daemon ${daemonName service} --bindir ${pkgs.frr}/bin --rundir /run/frr /etc/frr/${service}.conf";
210                 Restart = "on-abnormal";
211               };
212             });
213        in
214          listToAttrs (map frrService (filter isEnabled allServices));
216   };
218   meta.maintainers = with lib.maintainers; [ woffs ];