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

Reply via email to