summary refs log tree commit diff
path: root/nixos/modules/virtualisation/openvswitch.nix
blob: ccf32641df626475f4165c5a5abd896bd031c9b7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# Systemd services for openvswitch

{ config, lib, pkgs, ... }:

with lib;

let
  cfg = config.virtualisation.vswitch;

in {

  options.virtualisation.vswitch = {
    enable = mkOption {
      type = types.bool;
      default = false;
      description = ''
        Whether to enable Open vSwitch. A configuration daemon (ovs-server)
        will be started.
        '';
    };

    resetOnStart = mkOption {
      type = types.bool;
      default = false;
      description = ''
        Whether to reset the Open vSwitch configuration database to a default
        configuration on every start of the systemd <literal>ovsdb.service</literal>.
        '';
    };

    package = mkOption {
      type = types.package;
      default = pkgs.openvswitch;
      defaultText = "pkgs.openvswitch";
      description = ''
        Open vSwitch package to use.
      '';
    };

    ipsec = mkOption {
      type = types.bool;
      default = false;
      description = ''
        Whether to start racoon service for openvswitch.
        Supported only if openvswitch version is less than 2.6.0.
        Use <literal>virtualisation.vswitch.package = pkgs.openvswitch-lts</literal>
        for a version that supports ipsec over GRE.
      '';
    };
  };

  config = mkIf cfg.enable (let

    # Where the communication sockets live
    runDir = "/run/openvswitch";

    # The path to the an initialized version of the database
    db = pkgs.stdenv.mkDerivation {
      name = "vswitch.db";
      dontUnpack = true;
      buildPhase = "true";
      buildInputs = with pkgs; [
        cfg.package
      ];
      installPhase = "mkdir -p $out";
    };

  in (mkMerge [{
    environment.systemPackages = [ cfg.package ];
    boot.kernelModules = [ "tun" "openvswitch" ];

    boot.extraModulePackages = [ cfg.package ];

    systemd.services.ovsdb = {
      description = "Open_vSwitch Database Server";
      wantedBy = [ "multi-user.target" ];
      after = [ "systemd-udev-settle.service" ];
      path = [ cfg.package ];
      restartTriggers = [ db cfg.package ];
      # Create the config database
      preStart =
        ''
        mkdir -p ${runDir}
        mkdir -p /var/db/openvswitch
        chmod +w /var/db/openvswitch
        ${optionalString cfg.resetOnStart "rm -f /var/db/openvswitch/conf.db"}
        if [[ ! -e /var/db/openvswitch/conf.db ]]; then
          ${cfg.package}/bin/ovsdb-tool create \
            "/var/db/openvswitch/conf.db" \
            "${cfg.package}/share/openvswitch/vswitch.ovsschema"
        fi
        chmod -R +w /var/db/openvswitch
        if ${cfg.package}/bin/ovsdb-tool needs-conversion /var/db/openvswitch/conf.db | grep -q "yes"
        then
          echo "Performing database upgrade"
          ${cfg.package}/bin/ovsdb-tool convert /var/db/openvswitch/conf.db
        else
          echo "Database already up to date"
        fi
        '';
      serviceConfig = {
        ExecStart =
          ''
          ${cfg.package}/bin/ovsdb-server \
            --remote=punix:${runDir}/db.sock \
            --private-key=db:Open_vSwitch,SSL,private_key \
            --certificate=db:Open_vSwitch,SSL,certificate \
            --bootstrap-ca-cert=db:Open_vSwitch,SSL,ca_cert \
            --unixctl=ovsdb.ctl.sock \
            --pidfile=/run/openvswitch/ovsdb.pid \
            --detach \
            /var/db/openvswitch/conf.db
          '';
        Restart = "always";
        RestartSec = 3;
        PIDFile = "/run/openvswitch/ovsdb.pid";
        # Use service type 'forking' to correctly determine when ovsdb-server is ready.
        Type = "forking";
      };
      postStart = ''
        ${cfg.package}/bin/ovs-vsctl --timeout 3 --retry --no-wait init
      '';
    };

    systemd.services.ovs-vswitchd = {
      description = "Open_vSwitch Daemon";
      wantedBy = [ "multi-user.target" ];
      bindsTo = [ "ovsdb.service" ];
      after = [ "ovsdb.service" ];
      path = [ cfg.package ];
      serviceConfig = {
        ExecStart = ''
          ${cfg.package}/bin/ovs-vswitchd \
          --pidfile=/run/openvswitch/ovs-vswitchd.pid \
          --detach
        '';
        PIDFile = "/run/openvswitch/ovs-vswitchd.pid";
        # Use service type 'forking' to correctly determine when vswitchd is ready.
        Type = "forking";
        Restart = "always";
        RestartSec = 3;
      };
    };

  }
  (mkIf (cfg.ipsec && (versionOlder cfg.package.version "2.6.0")) {
    environment.systemPackages = [ pkgs.ipsecTools ];

    services.racoon.enable = true;
    services.racoon.configPath = "${runDir}/ipsec/etc/racoon/racoon.conf";

    networking.firewall.extraCommands = ''
      iptables -I INPUT -t mangle -p esp -j MARK --set-mark 1/1
      iptables -I INPUT -t mangle -p udp --dport 4500 -j MARK --set-mark 1/1
    '';

    systemd.services.ovs-monitor-ipsec = {
      description = "Open_vSwitch Ipsec Daemon";
      wantedBy = [ "multi-user.target" ];
      requires = [ "ovsdb.service" ];
      before = [ "vswitchd.service" "racoon.service" ];
      environment.UNIXCTLPATH = "/tmp/ovsdb.ctl.sock";
      serviceConfig = {
        ExecStart = ''
          ${cfg.package}/bin/ovs-monitor-ipsec \
            --root-prefix ${runDir}/ipsec \
            --pidfile /run/openvswitch/ovs-monitor-ipsec.pid \
            --monitor --detach \
            unix:/run/openvswitch/db.sock
        '';
        PIDFile = "/run/openvswitch/ovs-monitor-ipsec.pid";
        # Use service type 'forking' to correctly determine when ovs-monitor-ipsec is ready.
        Type = "forking";
      };

      preStart = ''
        rm -r ${runDir}/ipsec/etc/racoon/certs || true
        mkdir -p ${runDir}/ipsec/{etc/racoon,etc/init.d/,usr/sbin/}
        ln -fs ${pkgs.ipsecTools}/bin/setkey ${runDir}/ipsec/usr/sbin/setkey
        ln -fs ${pkgs.writeScript "racoon-restart" ''
        #!${pkgs.runtimeShell}
        /run/current-system/sw/bin/systemctl $1 racoon
        ''} ${runDir}/ipsec/etc/init.d/racoon
      '';
    };
  })]));

  meta.maintainers = with maintainers; [ netixx ];

}