[ovs-dev] [PATCH 5/5] stt: Support simultaneous encrypted and unencrypted to same host
Ben Pfaff
blp at nicira.com
Wed Oct 19 00:02:01 UTC 2011
From: Justin Pettit <jpettit at nicira.com>
In general it is only possible to have a single tunnel between a pair
of end hosts with a given key. This allows one encrypted and one
unencrypted tunnel when using STT. They are distinguished by using
a unique port number on transmit and looking at the security path
on receive.
Signed-off-by: Justin Pettit <jpettit at nicira.com>
Signed-off-by: Jesse Gross <jesse at nicira.com>
[Ben modified this patch for VXLAN, fixed >=2.6.39, updated unit test]
Signed-off-by: Ben Pfaff <blp at nicira.com>
---
datapath/tunnel.c | 9 ++++++-
datapath/tunnel.h | 10 +++++++++
datapath/vport-capwap.c | 2 +
datapath/vport-vxlan.c | 46 ++++++++++++++++++++++++++++++++++++++++++-
debian/ovs-monitor-ipsec | 10 +++-----
tests/ovs-monitor-ipsec.at | 4 +-
vswitchd/vswitch.xml | 6 ++++-
7 files changed, 74 insertions(+), 13 deletions(-)
diff --git a/datapath/tunnel.c b/datapath/tunnel.c
index 8edff06..ca4f337 100644
--- a/datapath/tunnel.c
+++ b/datapath/tunnel.c
@@ -929,7 +929,10 @@ static struct rtable *find_route(struct vport *vport,
{ .daddr = mutable->key.daddr,
.saddr = mutable->key.saddr,
.tos = tos } },
- .proto = tnl_vport->tnl_ops->ipproto };
+ .proto = tnl_vport->tnl_ops->ipproto,
+ .uli_u = { .ports =
+ { .sport = tnl_vport->tnl_ops->sport,
+ .dport = tnl_vport->tnl_ops->dport } } };
if (unlikely(ip_route_output_key(&init_net, &rt, &fl)))
return NULL;
@@ -937,7 +940,9 @@ static struct rtable *find_route(struct vport *vport,
struct flowi4 fl = { .daddr = mutable->key.daddr,
.saddr = mutable->key.saddr,
.flowi4_tos = tos,
- .flowi4_proto = tnl_vport->tnl_ops->ipproto };
+ .flowi4_proto = tnl_vport->tnl_ops->ipproto,
+ .fl4_sport = tnl_vport->tnl_ops->sport,
+ .fl4_dport = tnl_vport->tnl_ops->dport };
rt = ip_route_output_key(&init_net, &fl);
if (IS_ERR(rt))
diff --git a/datapath/tunnel.h b/datapath/tunnel.h
index e1d5489..b09220f 100644
--- a/datapath/tunnel.h
+++ b/datapath/tunnel.h
@@ -34,6 +34,7 @@
/* These flags are only needed when calling tnl_find_port(). */
#define TNL_T_KEY_EXACT (1 << 10)
#define TNL_T_KEY_MATCH (1 << 11)
+#define TNL_T_IPSEC (1 << 12)
/* Private flags not exposed to userspace in this form. */
#define TNL_F_IN_KEY_MATCH (1 << 16) /* Store the key in tun_id to match in flow table. */
@@ -97,6 +98,15 @@ struct tnl_ops {
u8 ipproto; /* The IP protocol for the tunnel. */
/*
+ * Source and destination port for the tunnel. This is necessary
+ * if the tunnel protocol is using TCP or UDP within IPsec. The
+ * IPsec transformation is done as part of the route lookup, so
+ * setting the transport port must be done early.
+ */
+ __be16 sport;
+ __be16 dport;
+
+ /*
* Returns the length of the tunnel header that will be added in
* build_header() (i.e. excludes the IP header). Returns a negative
* error code if the configuration is invalid.
diff --git a/datapath/vport-capwap.c b/datapath/vport-capwap.c
index 3fb4ffb..3668f53 100644
--- a/datapath/vport-capwap.c
+++ b/datapath/vport-capwap.c
@@ -358,6 +358,8 @@ out:
static const struct tnl_ops capwap_tnl_ops = {
.tunnel_type = TNL_T_PROTO_CAPWAP,
.ipproto = IPPROTO_UDP,
+ .sport = htons(CAPWAP_SRC_PORT),
+ .dport = htons(CAPWAP_DST_PORT),
.hdr_len = capwap_hdr_len,
.build_header = capwap_build_header,
.update_header = capwap_update_header,
diff --git a/datapath/vport-vxlan.c b/datapath/vport-vxlan.c
index b839c4c..8e1a091 100644
--- a/datapath/vport-vxlan.c
+++ b/datapath/vport-vxlan.c
@@ -15,9 +15,11 @@
#include <linux/ip.h>
#include <linux/net.h>
#include <linux/udp.h>
+#include <linux/xfrm.h>
#include <net/icmp.h>
#include <net/ip.h>
+#include <net/xfrm.h>
#include "tunnel.h"
#include "vport.h"
@@ -102,6 +104,21 @@ static struct sk_buff *vxlan_update_header(const struct vport *vport,
return skb;
}
+static bool sec_path_esp(struct sk_buff *skb)
+{
+ struct sec_path *sp = skb_sec_path(skb);
+
+ if (sp) {
+ int i;
+
+ for (i = 0; i < sp->len; i++)
+ if (sp->xvec[i]->id.proto == XFRM_PROTO_ESP)
+ return true;
+ }
+
+ return false;
+}
+
/* Called with rcu_read_lock and BH disabled. */
static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
{
@@ -109,6 +126,7 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
struct vxlanhdr *vxh;
const struct tnl_mutable_config *mutable;
struct iphdr *iph;
+ int tunnel_type;
__be64 key;
if (unlikely(!pskb_may_pull(skb, VXLAN_HLEN + ETH_HLEN)))
@@ -123,8 +141,12 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
key = cpu_to_be64(ntohl(vxh->vx_vni) >> 8);
+ tunnel_type = TNL_T_PROTO_VXLAN;
+ if (sec_path_esp(skb))
+ tunnel_type |= TNL_T_IPSEC;
+
iph = ip_hdr(skb);
- vport = tnl_find_port(iph->daddr, iph->saddr, key, TNL_T_PROTO_VXLAN,
+ vport = tnl_find_port(iph->daddr, iph->saddr, key, tunnel_type,
&mutable);
if (unlikely(!vport)) {
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
@@ -150,6 +172,17 @@ out:
static const struct tnl_ops vxlan_tnl_ops = {
.tunnel_type = TNL_T_PROTO_VXLAN,
.ipproto = IPPROTO_UDP,
+ .dport = htons(VXLAN_DST_PORT),
+ .hdr_len = vxlan_hdr_len,
+ .build_header = vxlan_build_header,
+ .update_header = vxlan_update_header,
+};
+
+static const struct tnl_ops ipsec_vxlan_tnl_ops = {
+ .tunnel_type = TNL_T_PROTO_VXLAN | TNL_T_IPSEC,
+ .ipproto = IPPROTO_UDP,
+ .sport = htons(VXLAN_IPSEC_SRC_PORT),
+ .dport = htons(VXLAN_DST_PORT),
.hdr_len = vxlan_hdr_len,
.build_header = vxlan_build_header,
.update_header = vxlan_update_header,
@@ -199,6 +232,7 @@ static void vxlan_uninit(void)
static struct vport *vxlan_create(const struct vport_parms *parms)
{
+ struct nlattr *flags_nlattr;
struct vport *vport;
int error;
@@ -206,7 +240,15 @@ static struct vport *vxlan_create(const struct vport_parms *parms)
if (error)
return ERR_PTR(error);
- vport = tnl_create(parms, &vxlan_vport_ops, &vxlan_tnl_ops);
+ flags_nlattr = nla_find_nested(parms->options, OVS_TUNNEL_ATTR_FLAGS);
+ if (!flags_nlattr || nla_len(flags_nlattr) != sizeof(u32))
+ return ERR_PTR(-EINVAL);
+
+ if (nla_get_u32(flags_nlattr) & TNL_F_IPSEC)
+ vport = tnl_create(parms, &vxlan_vport_ops, &ipsec_vxlan_tnl_ops);
+ else
+ vport = tnl_create(parms, &vxlan_vport_ops, &vxlan_tnl_ops);
+
if (IS_ERR(vport))
vxlan_uninit();
return vport;
diff --git a/debian/ovs-monitor-ipsec b/debian/ovs-monitor-ipsec
index 48741f5..6c3c678 100755
--- a/debian/ovs-monitor-ipsec
+++ b/debian/ovs-monitor-ipsec
@@ -325,12 +325,10 @@ class IPsec:
def spd_add(self, local_ip, remote_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))
+ cmds = ("spdadd %s[%s] %s[%s] udp -P out ipsec esp/transport//require;\n"
+ % (local_ip, VXLAN_SRC_PORT, remote_ip, VXLAN_DST_PORT))
+ cmds += ("spdadd %s[%s] %s[%s] udp -P in ipsec esp/transport//require;\n"
+ % (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))
diff --git a/tests/ovs-monitor-ipsec.at b/tests/ovs-monitor-ipsec.at
index 2b37b85..14a4621 100644
--- a/tests/ovs-monitor-ipsec.at
+++ b/tests/ovs-monitor-ipsec.at
@@ -320,8 +320,8 @@ 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;
+> spdadd 0.0.0.0/0[4564] 4.5.6.7[4563] udp -P out ipsec esp/transport//require;
+> spdadd 4.5.6.7[4563] 0.0.0.0/0[4564] udp -P in ipsec esp/transport//require;
]])
AT_CHECK([trim etc/racoon/psk.txt], [0], [4.5.6.7 mishmash
])
diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml
index 6f2e73a..da223a3 100644
--- a/vswitchd/vswitch.xml
+++ b/vswitchd/vswitch.xml
@@ -954,7 +954,11 @@
<dt><code>ipsec_vxlan</code></dt>
<dd>
- VXLAN over an IPSEC tunnel.
+ VXLAN over an IPSEC tunnel. As an exception to the usual rule that
+ only one tunnel with the same matching criteria is allowed at a
+ time, it is possible to have one <code>vxlan</code> tunnel and one
+ <code>ipsec_vxlan</code> tunnel at the same time that are otherwise
+ equivalent.
</dd>
<dt><code>patch</code></dt>
--
1.7.4.4
More information about the dev
mailing list