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