Signed-off-by: Jiri Benc <[email protected]>
---
net/openvswitch/vport-vxlan.c | 133 +++++++++++++++++++++++++++++++-----------
1 file changed, 99 insertions(+), 34 deletions(-)
diff --git a/net/openvswitch/vport-vxlan.c b/net/openvswitch/vport-vxlan.c
index 5808a9344b59..5fc9510345ba 100644
--- a/net/openvswitch/vport-vxlan.c
+++ b/net/openvswitch/vport-vxlan.c
@@ -51,6 +51,7 @@ struct vxlan_port {
struct vxlan_sock *vs;
char name[IFNAMSIZ];
u32 exts; /* VXLAN_F_* in <net/vxlan.h> */
+ bool ipv6;
};
static struct vport_ops ovs_vxlan_vport_ops;
@@ -67,7 +68,6 @@ static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff
*skb,
struct ovs_tunnel_info tun_info;
struct vxlan_port *vxlan_port;
struct vport *vport = vs->data;
- struct iphdr *iph;
struct ovs_vxlan_opts opts = {
.gbp = md->gbp,
};
@@ -80,9 +80,9 @@ static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff
*skb,
flags |= TUNNEL_VXLAN_OPT;
/* Save outer tunnel values */
- iph = ip_hdr(skb);
key = cpu_to_be64(ntohl(md->vni) >> 8);
- ovs_flow_tun_info_init(&tun_info, iph, false,
+ ovs_flow_tun_info_init(&tun_info,
+ skb_network_header(skb), vxlan_port->ipv6,
udp_hdr(skb)->source, udp_hdr(skb)->dest,
key, flags, &opts, sizeof(opts));
@@ -157,6 +157,7 @@ static struct vport *vxlan_tnl_create(const struct
vport_parms *parms)
struct vport *vport;
struct nlattr *a;
u16 dst_port;
+ u32 flags;
int err;
if (!options) {
@@ -171,11 +172,6 @@ static struct vport *vxlan_tnl_create(const struct
vport_parms *parms)
err = -EINVAL;
goto error;
}
- a = nla_find_nested(options, OVS_TUNNEL_ATTR_OVER_IPV6);
- if (a) {
- err = -EAFNOSUPPORT;
- goto error;
- }
vport = ovs_vport_alloc(sizeof(struct vxlan_port),
&ovs_vxlan_vport_ops, parms);
@@ -194,8 +190,15 @@ static struct vport *vxlan_tnl_create(const struct
vport_parms *parms)
}
}
+ flags = vxlan_port->exts;
+ a = nla_find_nested(options, OVS_TUNNEL_ATTR_OVER_IPV6);
+ if (a) {
+ vxlan_port->ipv6 = true;
+ flags |= VXLAN_F_IPV6;
+ }
+
vs = vxlan_sock_add(net, htons(dst_port), vxlan_rcv, vport, true,
- vxlan_port->exts);
+ flags);
if (IS_ERR(vs)) {
ovs_vport_free(vport);
return (void *)vs;
@@ -223,54 +226,116 @@ static int vxlan_ext_gbp(struct sk_buff *skb)
return 0;
}
-static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb)
+static int __vxlan_tnl_send(struct net *net, struct sock *sk,
+ const struct ovs_key_ip_tunnel *tun_key,
+ struct vxlan_port *vxlan_port,
+ struct vxlan_metadata *md,
+ __be16 dst_port,
+ __be16 src_port,
+ struct sk_buff *skb)
{
- struct net *net = ovs_dp_get_net(vport->dp);
- struct vxlan_port *vxlan_port = vxlan_vport(vport);
- struct sock *sk = vxlan_port->vs->sock->sk;
- __be16 dst_port = inet_sk(sk)->inet_sport;
- const struct ovs_key_ip_tunnel *tun_key;
- struct vxlan_metadata md = {0};
struct rtable *rt;
struct flowi4 fl;
- __be16 src_port;
__be16 df;
int err;
u32 vxflags;
- if (unlikely(!OVS_CB(skb)->egress_tun_info)) {
- err = -EINVAL;
- goto error;
- }
-
- tun_key = &OVS_CB(skb)->egress_tun_info->tunnel;
+ if (vxlan_port->ipv6)
+ return -EAFNOSUPPORT;
rt = ovs_tunnel_route_lookup(net, tun_key, skb->mark, &fl, IPPROTO_UDP);
if (IS_ERR(rt)) {
- err = PTR_ERR(rt);
- goto error;
+ kfree_skb(skb);
+ return PTR_ERR(rt);
}
df = tun_key->tun_flags & TUNNEL_DONT_FRAGMENT ?
htons(IP_DF) : 0;
- skb->ignore_df = 1;
-
- src_port = udp_flow_src_port(net, skb, 0, 0, true);
- md.vni = htonl(be64_to_cpu(tun_key->tun_id) << 8);
- md.gbp = vxlan_ext_gbp(skb);
vxflags = vxlan_port->exts |
(tun_key->tun_flags & TUNNEL_CSUM ? VXLAN_F_UDP_CSUM : 0);
err = vxlan_xmit_skb(rt, sk, skb, fl.saddr, tun_key->ipv4_dst,
tun_key->tos, tun_key->ttl, df,
src_port, dst_port,
- &md, false, vxflags);
+ md, false, vxflags);
if (err < 0)
ip_rt_put(rt);
return err;
-error:
- kfree_skb(skb);
- return err;
+}
+
+#if IS_ENABLED(CONFIG_IPV6)
+static int __vxlan6_tnl_send(struct sock *sk,
+ const struct ovs_key_ip_tunnel *tun_key,
+ struct vxlan_port *vxlan_port,
+ struct vxlan_metadata *md,
+ __be16 dst_port,
+ __be16 src_port,
+ struct sk_buff *skb)
+{
+ struct dst_entry *dst;
+ struct flowi6 fl6;
+ u32 vxflags;
+
+ if (!vxlan_port->ipv6)
+ return -EAFNOSUPPORT;
+ dst = ovs_tunnel6_route_lookup(sk, tun_key, skb->mark, &fl6,
+ IPPROTO_UDP);
+ if (IS_ERR(dst)) {
+ kfree(skb);
+ return PTR_ERR(dst);
+ }
+
+ vxflags = vxlan_port->exts |
+ (tun_key->tun_flags & TUNNEL_CSUM ?
IFLA_VXLAN_UDP_ZERO_CSUM6_TX : 0);
+
+ return vxlan6_xmit_skb(dst, sk, skb, NULL,
+ &fl6.saddr, &fl6.daddr,
+ tun_key->tos, tun_key->ttl,
+ src_port, dst_port,
+ md, false, vxflags);
+}
+#else
+static int __vxlan6_tnl_send(struct sock *sk,
+ const struct ovs_key_ip_tunnel *tun_key,
+ struct vxlan_port *vxlan_port,
+ struct vxlan_metadata *md,
+ __be16 dst_port,
+ __be16 src_port,
+ struct sk_buff *skb)
+{
+ return -EAFNOSUPPORT;
+}
+#endif
+
+static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb)
+{
+ struct net *net = ovs_dp_get_net(vport->dp);
+ struct vxlan_port *vxlan_port = vxlan_vport(vport);
+ struct sock *sk = vxlan_port->vs->sock->sk;
+ __be16 dst_port = inet_sk(sk)->inet_sport;
+ const struct ovs_key_ip_tunnel *tun_key;
+ struct vxlan_metadata md = {0};
+ __be16 src_port;
+
+ if (unlikely(!OVS_CB(skb)->egress_tun_info)) {
+ kfree_skb(skb);
+ return -EINVAL;
+ }
+
+ tun_key = &OVS_CB(skb)->egress_tun_info->tunnel;
+
+ skb->ignore_df = 1;
+
+ src_port = udp_flow_src_port(net, skb, 0, 0, true);
+ md.vni = htonl(be64_to_cpu(tun_key->tun_id) << 8);
+ md.gbp = vxlan_ext_gbp(skb);
+
+ if (tun_key->ipv4_dst)
+ return __vxlan_tnl_send(net, sk, tun_key, vxlan_port, &md,
+ dst_port, src_port, skb);
+ else
+ return __vxlan6_tnl_send(sk, tun_key, vxlan_port, &md,
+ dst_port, src_port, skb);
}
static int vxlan_get_egress_tun_info(struct vport *vport, struct sk_buff *skb,
--
1.8.3.1
_______________________________________________
dev mailing list
[email protected]
http://openvswitch.org/mailman/listinfo/dev