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