On Sat, Oct 22, 2011 at 08:19:08PM -0700, Jesse Gross wrote:
> On Tue, Oct 18, 2011 at 5:01 PM, Ben Pfaff <[email protected]> wrote:
> > diff --git a/NEWS b/NEWS
> > index 27bb260..540dbff 100644
> > --- a/NEWS
> > +++ b/NEWS
> > @@ -2,7 +2,8 @@ Post-v1.2.0
> > ??------------------------
> >
> > ?? ?? - New support for the experimental VXLAN tunnel protocol (see
> > - ?? ?? ??http://tools.ietf.org/html/draft-mahalingam-dutt-dcops-vxlan-00).
> > + ?? ?? ??http://tools.ietf.org/html/draft-mahalingam-dutt-dcops-vxlan-00)
> > + ?? ?? ??and VXLAN over IPSEC.
>
> I think in most places we use the capitalization IPsec but we use
> IPSEC in a few places here.
OK, I fixed those up and also added a commit before the beginning of
the series that fixes up a few existing instances in the tree.
> > diff --git a/debian/control b/debian/control
> > index 1f3387a..4c23e59 100644
> > --- a/debian/control
> > +++ b/debian/control
> > @@ -60,9 +60,9 @@ Depends:
> > ??openvswitch-common (= ${binary:Version}),
> > ??openvswitch-switch (= ${binary:Version}),
> > ??python-openvswitch (= ${source:Version})
> > -Description: Open vSwitch GRE-over-IPsec support
> > +Description: Open vSwitch support for GRE and VXLAN over ISPEC
>
> IPSEC instead of ISPEC.
Thanks, fixed.
> > diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
> > index 9db93ba..d2c9e14 100644
> > --- a/lib/netdev-vport.c
> > +++ b/lib/netdev-vport.c
> > @@ -135,11 +135,27 @@ netdev_vport_get_vport_type(const struct netdev
> > *netdev)
> > ?? ?? ?? ?? ?? ?? : OVS_VPORT_TYPE_UNSPEC);
> > ??}
> >
> > -const char *
> > -netdev_vport_get_netdev_type(const struct dpif_linux_vport *vport)
> > +static const char *
> > +get_maybe_ipsec_tunnel_type(const struct dpif_linux_vport *vport,
> > + ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??const char *plain_type, const
> > char *ipsec_type)
> > ??{
> > ?? ?? struct nlattr *a[OVS_TUNNEL_ATTR_MAX + 1];
> > + ?? ??uint32_t flags;
> > +
> > + ?? ??if (tnl_port_config_from_nlattr(vport->options, vport->options_len,
> > a)) {
> > + ?? ?? ?? ??VLOG_WARN_RL(&rl, "dp%d: cannot parse options for port `%s'
> > (type %u)",
>
> The first single quote is of a different type.
It's a backquote. I changed them both to \".
Thank you for the review. Here's the revised version:
--8<--------------------------cut here-------------------------->8--
From: Justin Pettit <[email protected]>
Date: Tue, 18 Oct 2011 16:33:14 -0700
Subject: [PATCH] vxlan: Add support for VXLAN-over-IPsec.
This makes it possible to automatically set up IPsec encrypted VXLAN
tunnels through the OVS database.
Signed-off-by: Justin Pettit <[email protected]>
Signed-off-by: Jesse Gross <[email protected]>
[Ben modified this commit for VXLAN, added unit tests, and tweaked it]
Signed-off-by: Ben Pfaff <[email protected]>
---
NEWS | 3 +-
README | 2 +-
datapath/vport-vxlan.c | 4 ++
debian/control | 4 +-
debian/openvswitch-ipsec.init | 3 +-
debian/ovs-monitor-ipsec | 117 ++++++++++++++++++++++++++---------------
lib/netdev-vport.c | 50 +++++++++++------
tests/ovs-monitor-ipsec.at | 67 +++++++++++++++++++++++
vswitchd/vswitch.xml | 20 ++++++-
9 files changed, 201 insertions(+), 69 deletions(-)
diff --git a/NEWS b/NEWS
index 7574957..934b0c4 100644
--- a/NEWS
+++ b/NEWS
@@ -2,7 +2,8 @@ Post-v1.2.0
------------------------
- New support for the experimental VXLAN tunnel protocol (see
- http://tools.ietf.org/html/draft-mahalingam-dutt-dcops-vxlan-00).
+ http://tools.ietf.org/html/draft-mahalingam-dutt-dcops-vxlan-00)
+ and VXLAN over IPsec.
- OpenFlow:
- Added an OpenFlow extension which allows the "output" action to accept
NXM fields.
diff --git a/README b/README
index 760e7ca..ab27ffb 100644
--- a/README
+++ b/README
@@ -24,7 +24,7 @@ vSwitch supports the following features:
* NIC bonding with or without LACP on upstream switch
* NetFlow, sFlow(R), SPAN, RSPAN, and ERSPAN for increased visibility
* QoS (Quality of Service) configuration, plus policing
- * GRE, GRE over IPsec, CAPWAP, and VXLAN tunneling
+ * GRE, GRE over IPsec, CAPWAP, and VXLAN, and VXLAN over IPsec tunneling
* 802.1ag connectivity fault management
* OpenFlow 1.0 plus numerous extensions
* Transactional configuration database with C and Python bindings
diff --git a/datapath/vport-vxlan.c b/datapath/vport-vxlan.c
index 6ff87e8..b839c4c 100644
--- a/datapath/vport-vxlan.c
+++ b/datapath/vport-vxlan.c
@@ -24,6 +24,7 @@
#include "vport-generic.h"
#define VXLAN_DST_PORT 4563
+#define VXLAN_IPSEC_SRC_PORT 4564
#define VXLAN_FLAGS 0x08000000 /* struct vxlanhdr.vx_flags required value. */
@@ -55,6 +56,9 @@ static int vxlan_hdr_len(const struct tnl_mutable_config
*mutable)
static __be16 get_src_port(const struct sk_buff *skb,
const struct tnl_mutable_config *mutable)
{
+ if (mutable->flags & TNL_F_IPSEC)
+ return htons(VXLAN_IPSEC_SRC_PORT);
+
/* Convert hash into a port between 32768 and 65535. */
return (__force __be16)OVS_CB(skb)->flow->hash | htons(32768);
}
diff --git a/debian/control b/debian/control
index 1f3387a..ca47c12 100644
--- a/debian/control
+++ b/debian/control
@@ -60,9 +60,9 @@ Depends:
openvswitch-common (= ${binary:Version}),
openvswitch-switch (= ${binary:Version}),
python-openvswitch (= ${source:Version})
-Description: Open vSwitch GRE-over-IPsec support
+Description: Open vSwitch support for GRE and VXLAN over IPsec
The ovs-monitor-ipsec script provides support for encrypting GRE
- tunnels with IPsec.
+ and VXLAN tunnels with IPsec.
.
Open vSwitch is a full-featured software-based Ethernet switch.
diff --git a/debian/openvswitch-ipsec.init b/debian/openvswitch-ipsec.init
index 17835a5..bb9a5bd 100755
--- a/debian/openvswitch-ipsec.init
+++ b/debian/openvswitch-ipsec.init
@@ -1,5 +1,6 @@
#!/bin/sh
#
+# Copyright (c) 2011 Nicira Networks
# Copyright (c) 2007, 2009 Javier Fernandez-Sanguino <[email protected]>
#
# This is free software; you may redistribute it and/or modify
@@ -23,7 +24,7 @@
# Required-Stop: $remote_fs
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
-# Short-Description: Open vSwitch GRE-over-IPsec daemon
+# Short-Description: Open vSwitch IPsec tunnel daemon
### END INIT INFO
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
diff --git a/debian/ovs-monitor-ipsec b/debian/ovs-monitor-ipsec
index ac2cd7e..48741f5 100755
--- a/debian/ovs-monitor-ipsec
+++ b/debian/ovs-monitor-ipsec
@@ -14,9 +14,10 @@
# limitations under the License.
-# A daemon to monitor attempts to create GRE-over-IPsec tunnels.
-# Uses racoon and setkey to support the configuration. Assumes that
-# OVS has complete control over IPsec configuration for the box.
+# A daemon to monitor attempts to create tunnels over IPsec.
+# Racoon and setkey are used to support the configuration. It is
+# assumed that OVS has complete control over IPsec configuration for
+# the box.
# xxx To-do:
# - Doesn't actually check that Interface is connected to bridge
@@ -41,7 +42,12 @@ import ovs.vlog
vlog = ovs.vlog.Vlog("ovs-monitor-ipsec")
root_prefix = '' # Prefix for absolute file names, for testing.
-setkey = "/usr/sbin/setkey"
+SETKEY = "/usr/sbin/setkey"
+
+# UDP ports used for VXLAN. The source port is only fixed for
+# VXLAN-over-IPsec traffic.
+VXLAN_DST_PORT = 4563
+VXLAN_SRC_PORT = 4564
# Class to configure the racoon daemon, which handles IKE negotiation
@@ -251,17 +257,17 @@ path certificate "%s";
# Class to configure IPsec on a system using racoon for IKE and setkey
# for maintaining the Security Association Database (SAD) and Security
-# Policy Database (SPD). Only policies for GRE are supported.
+# Policy Database (SPD). Only policies for GRE and VXLAN are supported.
class IPsec:
def __init__(self):
self.sad_flush()
self.spd_flush()
self.racoon = Racoon()
- self.entries = []
+ self.entries = {}
def call_setkey(self, cmds):
try:
- p = subprocess.Popen([root_prefix + setkey, "-c"],
+ p = subprocess.Popen([root_prefix + SETKEY, "-c"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE)
except:
@@ -317,26 +323,44 @@ class IPsec:
self.call_setkey("spdflush;\n")
def spd_add(self, local_ip, remote_ip):
- cmds = ("spdadd %s %s gre -P out ipsec esp/transport//require;\n" %
- (local_ip, remote_ip))
- cmds += ("spdadd %s %s gre -P in ipsec esp/transport//require;\n" %
- (remote_ip, local_ip))
+ tunnel_type = self.entries[remote_ip]
+ if tunnel_type == "vxlan":
+ cmds = ("spdadd %s[any] %s[any] udp -P out ipsec
esp/transport/%s[%s]-%s[%s]/require;\n"
+ % (local_ip, remote_ip, local_ip, VXLAN_SRC_PORT,
+ remote_ip, VXLAN_DST_PORT))
+ cmds += ("spdadd %s[any] %s[any] udp -P in ipsec
esp/transport/%s[%s]-%s[%s]/require;\n"
+ % (remote_ip, local_ip, remote_ip, VXLAN_DST_PORT,
+ local_ip, VXLAN_SRC_PORT))
+ else:
+ cmds = ("spdadd %s %s gre -P out ipsec esp/transport//require;\n" %
+ (local_ip, remote_ip))
+ cmds += ("spdadd %s %s gre -P in ipsec esp/transport//require;\n" %
+ (remote_ip, local_ip))
self.call_setkey(cmds)
def spd_del(self, local_ip, remote_ip):
- cmds = "spddelete %s %s gre -P out;\n" % (local_ip, remote_ip)
- cmds += "spddelete %s %s gre -P in;\n" % (remote_ip, local_ip)
+ tunnel_type = self.entries[remote_ip]
+ if tunnel_type == "vxlan":
+ cmds = ("spddelete %s %s udp -P out;\n" % (local_ip, remote_ip))
+ cmds += ("spddelete %s %s udp -P in;\n" % (remote_ip, local_ip))
+ else:
+ cmds = "spddelete %s %s gre -P out;\n" % (local_ip, remote_ip)
+ cmds += "spddelete %s %s gre -P in;\n" % (remote_ip, local_ip)
self.call_setkey(cmds)
def add_entry(self, local_ip, remote_ip, vals):
+ tunnel_type = vals["tunnel_type"]
+ if tunnel_type not in ("gre", "vxlan"):
+ raise error.Error("unknown tunnel type: %s" % tunnel_type)
+
if remote_ip in self.entries:
raise error.Error("host %s already configured for ipsec"
% remote_ip)
self.racoon.add_entry(remote_ip, vals)
- self.spd_add(local_ip, remote_ip)
- self.entries.append(remote_ip)
+ self.entries[remote_ip] = tunnel_type
+ self.spd_add(local_ip, remote_ip)
def del_entry(self, local_ip, remote_ip):
if remote_ip in self.entries:
@@ -344,7 +368,7 @@ class IPsec:
self.spd_del(local_ip, remote_ip)
self.sad_del(local_ip, remote_ip)
- self.entries.remove(remote_ip)
+ del self.entries[remote_ip]
def keep_table_columns(schema, table_name, column_types):
@@ -463,36 +487,43 @@ def main():
new_interfaces = {}
for rec in idl.tables["Interface"].rows.itervalues():
if rec.type == "ipsec_gre":
- name = rec.name
- options = rec.options
- entry = {
- "remote_ip": options.get("remote_ip"),
- "local_ip": options.get("local_ip", "0.0.0.0/0"),
- "certificate": options.get("certificate"),
- "private_key": options.get("private_key"),
- "use_ssl_cert": options.get("use_ssl_cert"),
- "peer_cert": options.get("peer_cert"),
- "psk": options.get("psk")}
-
- if entry["peer_cert"] and entry["psk"]:
- vlog.warn("both 'peer_cert' and 'psk' defined for %s"
- % name)
- continue
- elif not entry["peer_cert"] and not entry["psk"]:
- vlog.warn("no 'peer_cert' or 'psk' defined for %s" % name)
- continue
+ tunnel_type = "gre"
+ elif rec.type == "ipsec_vxlan":
+ tunnel_type = "vxlan"
+ else:
+ continue
+
+ name = rec.name
+ options = rec.options
+ entry = {
+ "remote_ip": options.get("remote_ip"),
+ "local_ip": options.get("local_ip", "0.0.0.0/0"),
+ "certificate": options.get("certificate"),
+ "private_key": options.get("private_key"),
+ "use_ssl_cert": options.get("use_ssl_cert"),
+ "peer_cert": options.get("peer_cert"),
+ "psk": options.get("psk"),
+ "tunnel_type": tunnel_type }
+
+ if entry["peer_cert"] and entry["psk"]:
+ vlog.warn("both 'peer_cert' and 'psk' defined for %s"
+ % name)
+ continue
+ elif not entry["peer_cert"] and not entry["psk"]:
+ vlog.warn("no 'peer_cert' or 'psk' defined for %s" % name)
+ continue
- # The "use_ssl_cert" option is deprecated and will
- # likely go away in the near future.
- if entry["use_ssl_cert"] == "true":
- if not ssl_cert:
- vlog.warn("no valid SSL entry for %s" % name)
- continue
+ # The "use_ssl_cert" option is deprecated and will
+ # likely go away in the near future.
+ if entry["use_ssl_cert"] == "true":
+ if not ssl_cert:
+ vlog.warn("no valid SSL entry for %s" % name)
+ continue
- entry["certificate"] = ssl_cert[0]
- entry["private_key"] = ssl_cert[1]
+ entry["certificate"] = ssl_cert[0]
+ entry["private_key"] = ssl_cert[1]
- new_interfaces[name] = entry
+ new_interfaces[name] = entry
if interfaces != new_interfaces:
update_ipsec(ipsec, interfaces, new_interfaces)
diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
index 7592df3..72c8008 100644
--- a/lib/netdev-vport.c
+++ b/lib/netdev-vport.c
@@ -135,11 +135,27 @@ netdev_vport_get_vport_type(const struct netdev *netdev)
: OVS_VPORT_TYPE_UNSPEC);
}
-const char *
-netdev_vport_get_netdev_type(const struct dpif_linux_vport *vport)
+static const char *
+get_maybe_ipsec_tunnel_type(const struct dpif_linux_vport *vport,
+ const char *plain_type, const char *ipsec_type)
{
struct nlattr *a[OVS_TUNNEL_ATTR_MAX + 1];
+ uint32_t flags;
+
+ if (tnl_port_config_from_nlattr(vport->options, vport->options_len, a)) {
+ VLOG_WARN_RL(&rl, "dp%d: cannot parse options for port \"%s\" "
+ "(type %u)", vport->dp_ifindex, vport->name,
+ (unsigned int) vport->type);
+ return "unknown";
+ }
+
+ flags = nl_attr_get_u32(a[OVS_TUNNEL_ATTR_FLAGS]);
+ return flags & TNL_F_IPSEC ? ipsec_type : plain_type;
+}
+const char *
+netdev_vport_get_netdev_type(const struct dpif_linux_vport *vport)
+{
switch (vport->type) {
case OVS_VPORT_TYPE_UNSPEC:
break;
@@ -154,24 +170,19 @@ netdev_vport_get_netdev_type(const struct
dpif_linux_vport *vport)
return "patch";
case OVS_VPORT_TYPE_GRE:
- if (tnl_port_config_from_nlattr(vport->options, vport->options_len,
- a)) {
- break;
- }
- return (nl_attr_get_u32(a[OVS_TUNNEL_ATTR_FLAGS]) & TNL_F_IPSEC
- ? "ipsec_gre" : "gre");
+ return get_maybe_ipsec_tunnel_type(vport, "gre", "ipsec_gre");
case OVS_VPORT_TYPE_CAPWAP:
return "capwap";
case OVS_VPORT_TYPE_VXLAN:
- return "vxlan";
+ return get_maybe_ipsec_tunnel_type(vport, "vxlan", "ipsec_vxlan");
case __OVS_VPORT_TYPE_MAX:
break;
}
- VLOG_WARN_RL(&rl, "dp%d: port `%s' has unsupported type %u",
+ VLOG_WARN_RL(&rl, "dp%d: port \"%s\" has unsupported type %u",
vport->dp_ifindex, vport->name, (unsigned int) vport->type);
return "unknown";
}
@@ -576,20 +587,19 @@ static int
parse_tunnel_config(const char *name, const char *type,
const struct shash *args, struct ofpbuf *options)
{
- bool is_gre = false;
- bool is_ipsec = false;
+ bool supports_csum;
+ bool is_ipsec;
struct shash_node *node;
bool ipsec_mech_set = false;
ovs_be32 daddr = htonl(0);
ovs_be32 saddr = htonl(0);
uint32_t flags;
+ supports_csum = !strcmp(type, "gre") || !strcmp(type, "ipsec_gre");
+ is_ipsec = !strncmp(type, "ipsec_", 6);
+
flags = TNL_F_DF_DEFAULT | TNL_F_PMTUD | TNL_F_HDR_CACHE;
- if (!strcmp(type, "gre")) {
- is_gre = true;
- } else if (!strcmp(type, "ipsec_gre")) {
- is_gre = true;
- is_ipsec = true;
+ if (is_ipsec) {
flags |= TNL_F_IPSEC;
flags &= ~TNL_F_HDR_CACHE;
}
@@ -621,7 +631,7 @@ parse_tunnel_config(const char *name, const char *type,
} else {
nl_msg_put_u8(options, OVS_TUNNEL_ATTR_TTL, atoi(node->data));
}
- } else if (!strcmp(node->name, "csum") && is_gre) {
+ } else if (!strcmp(node->name, "csum") && supports_csum) {
if (!strcmp(node->data, "true")) {
flags |= TNL_F_CSUM;
}
@@ -970,6 +980,10 @@ netdev_vport_register(void)
{ "vxlan", VPORT_FUNCTIONS(netdev_vport_get_status) },
parse_tunnel_config, unparse_tunnel_config },
+ { OVS_VPORT_TYPE_VXLAN,
+ { "vxlan_ipsec", VPORT_FUNCTIONS(netdev_vport_get_status) },
+ parse_tunnel_config, unparse_tunnel_config },
+
{ OVS_VPORT_TYPE_PATCH,
{ "patch", VPORT_FUNCTIONS(NULL) },
parse_patch_config, unparse_patch_config }
diff --git a/tests/ovs-monitor-ipsec.at b/tests/ovs-monitor-ipsec.at
index f9868e7..2b37b85 100644
--- a/tests/ovs-monitor-ipsec.at
+++ b/tests/ovs-monitor-ipsec.at
@@ -308,4 +308,71 @@ sainfo anonymous {
])
AT_CHECK([test ! -f etc/racoon/certs/ovs-3.4.5.6.pem])
+###
+### Add an ipsec_vxlan psk interface and check what ovs-monitor-ipsec does
+###
+AT_CHECK([ovs_vsctl \
+ -- add-port br0 vxlan0 \
+ -- set interface vxlan0 type=ipsec_vxlan \
+ options:remote_ip=4.5.6.7 \
+ options:psk=mishmash])
+OVS_WAIT_UNTIL([test -f actions && grep 'spdadd 4.5.6.7' actions >/dev/null])
+AT_CHECK([sed '1,41d' actions], [0],
+[[racoon: reload
+setkey:
+> spdadd 0.0.0.0/0[any] 4.5.6.7[any] udp -P out ipsec
esp/transport/0.0.0.0/0[4564]-4.5.6.7[4563]/require;
+> spdadd 4.5.6.7[any] 0.0.0.0/0[any] udp -P in ipsec
esp/transport/4.5.6.7[4563]-0.0.0.0/0[4564]/require;
+]])
+AT_CHECK([trim etc/racoon/psk.txt], [0], [4.5.6.7 mishmash
+])
+AT_CHECK([trim etc/racoon/racoon.conf], [0], [dnl
+path pre_shared_key "/etc/racoon/psk.txt";
+path certificate "/etc/racoon/certs";
+remote 4.5.6.7 {
+ exchange_mode main;
+ nat_traversal on;
+ proposal {
+ encryption_algorithm aes;
+ hash_algorithm sha1;
+ authentication_method pre_shared_key;
+ dh_group 2;
+ }
+}
+sainfo anonymous {
+ pfs_group 2;
+ lifetime time 1 hour;
+ encryption_algorithm aes;
+ authentication_algorithm hmac_sha1, hmac_md5;
+ compression_algorithm deflate;
+}
+])
+
+###
+### Delete the ipsec_vxlan interface and check what ovs-monitor-ipsec does
+###
+AT_CHECK([ovs_vsctl del-port vxlan0])
+OVS_WAIT_UNTIL([test `wc -l < actions` -ge 17])
+AT_CHECK([sed '1,45d' actions], [0], [dnl
+racoon: reload
+setkey:
+> spddelete 0.0.0.0/0 4.5.6.7 udp -P out;
+> spddelete 4.5.6.7 0.0.0.0/0 udp -P in;
+setkey:
+> dump ;
+setkey:
+> dump ;
+])
+AT_CHECK([trim etc/racoon/psk.txt], [0], [])
+AT_CHECK([trim etc/racoon/racoon.conf], [0], [dnl
+path pre_shared_key "/etc/racoon/psk.txt";
+path certificate "/etc/racoon/certs";
+sainfo anonymous {
+ pfs_group 2;
+ lifetime time 1 hour;
+ encryption_algorithm aes;
+ authentication_algorithm hmac_sha1, hmac_md5;
+ compression_algorithm deflate;
+}
+])
+
AT_CLEANUP
diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml
index 5ce457a..ba3f746 100644
--- a/vswitchd/vswitch.xml
+++ b/vswitchd/vswitch.xml
@@ -1104,6 +1104,12 @@
between 32768 and 65535 to allow load balancing.
</p>
</dd>
+
+ <dt><code>ipsec_vxlan</code></dt>
+ <dd>
+ VXLAN over an IPsec tunnel.
+ </dd>
+
<dt><code>patch</code></dt>
<dd>
A pair of virtual devices that act as a patch cable.
@@ -1119,7 +1125,7 @@
<p>
These options apply to interfaces with <ref column="type"/> of
<code>gre</code>, <code>ipsec_gre</code>, <code>capwap</code>,
- and <code>vxlan</code>.
+ <code>vxlan</code>, and <code>vxlan_ipsec</code>.
</p>
<p>
@@ -1294,11 +1300,19 @@
</column>
</group>
- <group title="Tunnel Options: ipsec_gre only">
+ <group title="Tunnel Options: ipsec_gre and ipsec_vxlan only">
<p>
- Only <code>ipsec_gre</code> interfaces support these options.
+ Only <code>ipsec_gre</code> and <code>ipsec_vxlan</code> interfaces
+ support these options.
</p>
+ <p>
+ These options are implemented through a separate daemon named
+ <code>ovs-monitor-ipsec</code> that so far has only been ported to
+ and packaged for Debian (including derivative distributions such as
+ Ubuntu).
+ </p>
+
<column name="options" key="peer_cert">
Required for certificate authentication. A string containing the
peer's certificate in PEM format. Additionally the host's
--
1.7.4.4
_______________________________________________
dev mailing list
[email protected]
http://openvswitch.org/mailman/listinfo/dev