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