1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6
7 cfg = config.services.quagga;
8
9 services = [ "babel" "bgp" "isis" "ospf6" "ospf" "pim" "rip" "ripng" ];
10 allServices = services ++ [ "zebra" ];
11
12 isEnabled = service: cfg.${service}.enable;
13
14 daemonName = service: if service == "zebra" then service else "${service}d";
15
16 configFile = service:
17 let
18 scfg = cfg.${service};
19 in
20 if scfg.configFile != null then scfg.configFile
21 else pkgs.writeText "${daemonName service}.conf"
22 ''
23 ! Quagga ${daemonName service} configuration
24 !
25 hostname ${config.networking.hostName}
26 log syslog
27 service password-encryption
28 !
29 ${scfg.config}
30 !
31 end
32 '';
33
34 serviceOptions = service:
35 {
36 enable = mkEnableOption "the Quagga ${toUpper service} routing protocol";
37
38 configFile = mkOption {
39 type = types.nullOr types.path;
40 default = null;
41 example = "/etc/quagga/${daemonName service}.conf";
42 description = ''
43 Configuration file to use for Quagga ${daemonName service}.
44 By default the NixOS generated files are used.
45 '';
46 };
47
48 config = mkOption {
49 type = types.lines;
50 default = "";
51 example =
52 let
53 examples = {
54 rip = ''
55 router rip
56 network 10.0.0.0/8
57 '';
58
59 ospf = ''
60 router ospf
61 network 10.0.0.0/8 area 0
62 '';
63
64 bgp = ''
65 router bgp 65001
66 neighbor 10.0.0.1 remote-as 65001
67 '';
68 };
69 in
70 examples.${service} or "";
71 description = ''
72 ${daemonName service} configuration statements.
73 '';
74 };
75
76 vtyListenAddress = mkOption {
77 type = types.str;
78 default = "127.0.0.1";
79 description = ''
80 Address to bind to for the VTY interface.
81 '';
82 };
83
84 vtyListenPort = mkOption {
85 type = types.nullOr types.int;
86 default = null;
87 description = ''
88 TCP Port to bind to for the VTY interface.
89 '';
90 };
91 };
92
93in
94
95{
96
97 ###### interface
98 imports = [
99 {
100 options.services.quagga = {
101 zebra = (serviceOptions "zebra") // {
102 enable = mkOption {
103 type = types.bool;
104 default = any isEnabled services;
105 description = ''
106 Whether to enable the Zebra routing manager.
107
108 The Zebra routing manager is automatically enabled
109 if any routing protocols are configured.
110 '';
111 };
112 };
113 };
114 }
115 { options.services.quagga = (genAttrs services serviceOptions); }
116 ];
117
118 ###### implementation
119
120 config = mkIf (any isEnabled allServices) {
121
122 environment.systemPackages = [
123 pkgs.quagga # for the vtysh tool
124 ];
125
126 users.users.quagga = {
127 description = "Quagga daemon user";
128 isSystemUser = true;
129 group = "quagga";
130 };
131
132 users.groups = {
133 quagga = {};
134 # Members of the quaggavty group can use vtysh to inspect the Quagga daemons
135 quaggavty = { members = [ "quagga" ]; };
136 };
137
138 systemd.services =
139 let
140 quaggaService = service:
141 let
142 scfg = cfg.${service};
143 daemon = daemonName service;
144 in
145 nameValuePair daemon ({
146 wantedBy = [ "multi-user.target" ];
147 restartTriggers = [ (configFile service) ];
148
149 serviceConfig = {
150 Type = "forking";
151 PIDFile = "/run/quagga/${daemon}.pid";
152 ExecStart = "@${pkgs.quagga}/libexec/quagga/${daemon} ${daemon} -d -f ${configFile service}"
153 + optionalString (scfg.vtyListenAddress != "") " -A ${scfg.vtyListenAddress}"
154 + optionalString (scfg.vtyListenPort != null) " -P ${toString scfg.vtyListenPort}";
155 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
156 Restart = "on-abort";
157 };
158 } // (
159 if service == "zebra" then
160 {
161 description = "Quagga Zebra routing manager";
162 unitConfig.Documentation = "man:zebra(8)";
163 after = [ "network.target" ];
164 preStart = ''
165 install -m 0755 -o quagga -g quagga -d /run/quagga
166
167 ${pkgs.iproute}/bin/ip route flush proto zebra
168 '';
169 }
170 else
171 {
172 description = "Quagga ${toUpper service} routing daemon";
173 unitConfig.Documentation = "man:${daemon}(8) man:zebra(8)";
174 bindsTo = [ "zebra.service" ];
175 after = [ "network.target" "zebra.service" ];
176 }
177 ));
178 in
179 listToAttrs (map quaggaService (filter isEnabled allServices));
180
181 };
182
183 meta.maintainers = with lib.maintainers; [ tavyc ];
184
185}