1# Systemd services for openvswitch
2
3{ config, lib, pkgs, ... }:
4
5with lib;
6
7let
8 cfg = config.virtualisation.vswitch;
9
10in {
11
12 options.virtualisation.vswitch = {
13 enable = mkOption {
14 type = types.bool;
15 default = false;
16 description = ''
17 Whether to enable Open vSwitch. A configuration daemon (ovs-server)
18 will be started.
19 '';
20 };
21
22 resetOnStart = mkOption {
23 type = types.bool;
24 default = false;
25 description = ''
26 Whether to reset the Open vSwitch configuration database to a default
27 configuration on every start of the systemd <literal>ovsdb.service</literal>.
28 '';
29 };
30
31 package = mkOption {
32 type = types.package;
33 default = pkgs.openvswitch;
34 defaultText = "pkgs.openvswitch";
35 description = ''
36 Open vSwitch package to use.
37 '';
38 };
39
40 ipsec = mkOption {
41 type = types.bool;
42 default = false;
43 description = ''
44 Whether to start racoon service for openvswitch.
45 '';
46 };
47 };
48
49 config = mkIf cfg.enable (let
50
51 # Where the communication sockets live
52 runDir = "/var/run/openvswitch";
53
54 # Where the config database live (can't be in nix-store)
55 stateDir = "/var/db/openvswitch";
56
57 # The path to the an initialized version of the database
58 db = pkgs.stdenv.mkDerivation {
59 name = "vswitch.db";
60 unpackPhase = "true";
61 buildPhase = "true";
62 buildInputs = with pkgs; [
63 cfg.package
64 ];
65 installPhase = "mkdir -p $out";
66 };
67
68 in (mkMerge [{
69
70 environment.systemPackages = [ cfg.package pkgs.ipsecTools ];
71
72 boot.kernelModules = [ "tun" "openvswitch" ];
73
74 boot.extraModulePackages = [ cfg.package ];
75
76 systemd.services.ovsdb = {
77 description = "Open_vSwitch Database Server";
78 wantedBy = [ "multi-user.target" ];
79 after = [ "systemd-udev-settle.service" ];
80 path = [ cfg.package ];
81 restartTriggers = [ db cfg.package ];
82 # Create the config database
83 preStart =
84 ''
85 mkdir -p ${runDir}
86 mkdir -p /var/db/openvswitch
87 chmod +w /var/db/openvswitch
88 ${optionalString cfg.resetOnStart "rm -f /var/db/openvswitch/conf.db"}
89 if [[ ! -e /var/db/openvswitch/conf.db ]]; then
90 ${cfg.package}/bin/ovsdb-tool create \
91 "/var/db/openvswitch/conf.db" \
92 "${cfg.package}/share/openvswitch/vswitch.ovsschema"
93 fi
94 chmod -R +w /var/db/openvswitch
95 '';
96 serviceConfig = {
97 ExecStart =
98 ''
99 ${cfg.package}/bin/ovsdb-server \
100 --remote=punix:${runDir}/db.sock \
101 --private-key=db:Open_vSwitch,SSL,private_key \
102 --certificate=db:Open_vSwitch,SSL,certificate \
103 --bootstrap-ca-cert=db:Open_vSwitch,SSL,ca_cert \
104 --unixctl=ovsdb.ctl.sock \
105 --pidfile=/var/run/openvswitch/ovsdb.pid \
106 --detach \
107 /var/db/openvswitch/conf.db
108 '';
109 Restart = "always";
110 RestartSec = 3;
111 PIDFile = "/var/run/openvswitch/ovsdb.pid";
112 # Use service type 'forking' to correctly determine when ovsdb-server is ready.
113 Type = "forking";
114 };
115 postStart = ''
116 ${cfg.package}/bin/ovs-vsctl --timeout 3 --retry --no-wait init
117 '';
118 };
119
120 systemd.services.vswitchd = {
121 description = "Open_vSwitch Daemon";
122 wantedBy = [ "multi-user.target" ];
123 bindsTo = [ "ovsdb.service" ];
124 after = [ "ovsdb.service" ];
125 path = [ cfg.package ];
126 serviceConfig = {
127 ExecStart = ''
128 ${cfg.package}/bin/ovs-vswitchd \
129 --pidfile=/var/run/openvswitch/ovs-vswitchd.pid \
130 --detach
131 '';
132 PIDFile = "/var/run/openvswitch/ovs-vswitchd.pid";
133 # Use service type 'forking' to correctly determine when vswitchd is ready.
134 Type = "forking";
135 };
136 };
137
138 }
139 (mkIf cfg.ipsec {
140 services.racoon.enable = true;
141 services.racoon.configPath = "${runDir}/ipsec/etc/racoon/racoon.conf";
142
143 networking.firewall.extraCommands = ''
144 iptables -I INPUT -t mangle -p esp -j MARK --set-mark 1/1
145 iptables -I INPUT -t mangle -p udp --dport 4500 -j MARK --set-mark 1/1
146 '';
147
148 systemd.services.ovs-monitor-ipsec = {
149 description = "Open_vSwitch Ipsec Daemon";
150 wantedBy = [ "multi-user.target" ];
151 requires = [ "ovsdb.service" ];
152 before = [ "vswitchd.service" "racoon.service" ];
153 environment.UNIXCTLPATH = "/tmp/ovsdb.ctl.sock";
154 serviceConfig = {
155 ExecStart = ''
156 ${cfg.package}/bin/ovs-monitor-ipsec \
157 --root-prefix ${runDir}/ipsec \
158 --pidfile /var/run/openvswitch/ovs-monitor-ipsec.pid \
159 --monitor --detach \
160 unix:/var/run/openvswitch/db.sock
161 '';
162 PIDFile = "/var/run/openvswitch/ovs-monitor-ipsec.pid";
163 # Use service type 'forking' to correctly determine when ovs-monitor-ipsec is ready.
164 Type = "forking";
165 };
166
167 preStart = ''
168 rm -r ${runDir}/ipsec/etc/racoon/certs || true
169 mkdir -p ${runDir}/ipsec/{etc/racoon,etc/init.d/,usr/sbin/}
170 ln -fs ${pkgs.ipsecTools}/bin/setkey ${runDir}/ipsec/usr/sbin/setkey
171 ln -fs ${pkgs.writeScript "racoon-restart" ''
172 #!${pkgs.stdenv.shell}
173 /var/run/current-system/sw/bin/systemctl $1 racoon
174 ''} ${runDir}/ipsec/etc/init.d/racoon
175 '';
176 };
177 })]));
178
179}