OVS already has compat functions to handle GSO packets.
Following patch get rid of GSO packet handling in lisp
and use ovs iptunnel_xmit() function for same.

CC: Lori Jakab <loja...@cisco.com>
Signed-off-by: Pravin B Shelar <pshe...@nicira.com>
---
 datapath/vport-lisp.c |  209 ++++++++++++-------------------------------------
 1 files changed, 50 insertions(+), 159 deletions(-)

diff --git a/datapath/vport-lisp.c b/datapath/vport-lisp.c
index 847cb39..9ffa74f 100644
--- a/datapath/vport-lisp.c
+++ b/datapath/vport-lisp.c
@@ -35,6 +35,7 @@
 #include <net/xfrm.h>
 
 #include "datapath.h"
+#include "gso.h"
 #include "vport.h"
 
 /*
@@ -177,35 +178,6 @@ static u16 ovs_tnl_get_src_port(struct sk_buff *skb)
        return (((u64) hash * range) >> 32) + low;
 }
 
-static void lisp_build_header(const struct vport *vport,
-                             struct sk_buff *skb,
-                             int tunnel_hlen)
-{
-       struct lisp_port *lisp_port = lisp_vport(vport);
-       struct udphdr *udph = udp_hdr(skb);
-       struct lisphdr *lisph = (struct lisphdr *)(udph + 1);
-       const struct ovs_key_ipv4_tunnel *tun_key = OVS_CB(skb)->tun_key;
-
-       udph->dest = lisp_port->dst_port;
-       udph->source = htons(ovs_tnl_get_src_port(skb));
-       udph->check = 0;
-       udph->len = htons(skb->len - skb_transport_offset(skb));
-
-       lisph->nonce_present = 0;       /* We don't support echo nonce 
algorithm */
-       lisph->locator_status_bits_present = 1; /* Set LSB */
-       lisph->solicit_echo_nonce = 0;  /* No echo noncing */
-       lisph->map_version_present = 0; /* No mapping versioning, nonce instead 
*/
-       lisph->instance_id_present = 1; /* Store the tun_id as Instance ID  */
-       lisph->reserved_flags = 0;      /* Reserved flags, set to 0  */
-
-       lisph->u1.nonce[0] = 0;
-       lisph->u1.nonce[1] = 0;
-       lisph->u1.nonce[2] = 0;
-
-       tunnel_id_to_instance_id(tun_key->tun_id, 
&lisph->u2.word2.instance_id[0]);
-       lisph->u2.word2.locator_status_bits = 1;
-}
-
 /* Called with rcu_read_lock and BH disabled. */
 static int lisp_rcv(struct sock *sk, struct sk_buff *skb)
 {
@@ -376,86 +348,56 @@ error:
        return ERR_PTR(err);
 }
 
-static bool need_linearize(const struct sk_buff *skb)
+static void lisp_build_header(struct sk_buff *skb)
 {
-       int i;
+       struct udphdr *udph = udp_hdr(skb);
+       struct lisphdr *lisph = (struct lisphdr *)(udph + 1);
+       const struct ovs_key_ipv4_tunnel *tun_key = OVS_CB(skb)->tun_key;
 
-       if (unlikely(skb_shinfo(skb)->frag_list))
-               return true;
+       lisph->nonce_present = 0;       /* We don't support echo nonce 
algorithm */
+       lisph->locator_status_bits_present = 1; /* Set LSB */
+       lisph->solicit_echo_nonce = 0;  /* No echo noncing */
+       lisph->map_version_present = 0; /* No mapping versioning, nonce instead 
*/
+       lisph->instance_id_present = 1; /* Store the tun_id as Instance ID  */
+       lisph->reserved_flags = 0;      /* Reserved flags, set to 0  */
 
-       /*
-        * Generally speaking we should linearize if there are paged frags.
-        * However, if all of the refcounts are 1 we know nobody else can
-        * change them from underneath us and we can skip the linearization.
-        */
-       for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
-               if 
(unlikely(page_count(skb_frag_page(&skb_shinfo(skb)->frags[i])) > 1))
-                       return true;
+       lisph->u1.nonce[0] = 0;
+       lisph->u1.nonce[1] = 0;
+       lisph->u1.nonce[2] = 0;
 
-       return false;
+       tunnel_id_to_instance_id(tun_key->tun_id, 
&lisph->u2.word2.instance_id[0]);
+       lisph->u2.word2.locator_status_bits = 1;
 }
 
-static struct sk_buff *handle_offloads(struct sk_buff *skb)
+static void handle_offloads(struct sk_buff *skb)
 {
-       int err;
+       if (skb_is_gso(skb))
+               OVS_GSO_CB(skb)->fix_segment = lisp_build_header;
+       else if (get_ip_summed(skb) != OVS_CSUM_PARTIAL)
+               set_ip_summed(skb, OVS_CSUM_NONE);
 
        forward_ip_summed(skb, true);
-
-       if (skb_is_gso(skb)) {
-               struct sk_buff *nskb;
-
-               nskb = __skb_gso_segment(skb, 0, false);
-               if (IS_ERR(nskb)) {
-                       err = PTR_ERR(nskb);
-                       goto error;
-               }
-
-               consume_skb(skb);
-               skb = nskb;
-       } else if (get_ip_summed(skb) == OVS_CSUM_PARTIAL) {
-               /* Pages aren't locked and could change at any time.
-                * If this happens after we compute the checksum, the
-                * checksum will be wrong.  We linearize now to avoid
-                * this problem.
-                */
-               if (unlikely(need_linearize(skb))) {
-                       err = __skb_linearize(skb);
-                       if (unlikely(err))
-                               goto error;
-               }
-
-               err = skb_checksum_help(skb);
-               if (unlikely(err))
-                       goto error;
-       }
-
-       set_ip_summed(skb, OVS_CSUM_NONE);
-
-       return skb;
-
-error:
-       return ERR_PTR(err);
+       skb_reset_inner_headers(skb);
 }
 
-static int ovs_tnl_send(struct vport *vport, struct sk_buff *skb,
-                       u8 ipproto, int tunnel_hlen,
-                       void (*build_header)(const struct vport *,
-                                            struct sk_buff *,
-                                            int tunnel_hlen))
+static int tnl_send(struct vport *vport, struct sk_buff *skb)
 {
-       int min_headroom;
+       struct net *net = ovs_dp_get_net(vport->dp);
+       struct lisp_port *lisp_port = lisp_vport(vport);
+       struct udphdr *udph;
        struct rtable *rt;
+       int min_headroom;
+       int tunnel_hlen;
        __be32 saddr;
-       int sent_len = 0;
+       __be16 df;
        int err;
-       struct sk_buff *nskb;
 
        /* Route lookup */
        saddr = OVS_CB(skb)->tun_key->ipv4_src;
        rt = find_route(ovs_dp_get_net(vport->dp),
                        &saddr,
                        OVS_CB(skb)->tun_key->ipv4_dst,
-                       ipproto,
+                       IPPROTO_UDP,
                        OVS_CB(skb)->tun_key->ipv4_tos,
                        skb_get_mark(skb));
        if (IS_ERR(rt)) {
@@ -463,7 +405,7 @@ static int ovs_tnl_send(struct vport *vport, struct sk_buff 
*skb,
                goto error;
        }
 
-       tunnel_hlen += sizeof(struct iphdr);
+       tunnel_hlen = sizeof(struct iphdr) + LISP_HLEN;
 
        min_headroom = LL_RESERVED_SPACE(rt_dst(rt).dev) + rt_dst(rt).header_len
                        + tunnel_hlen
@@ -480,77 +422,27 @@ static int ovs_tnl_send(struct vport *vport, struct 
sk_buff *skb,
                        goto err_free_rt;
        }
 
+       __skb_push(skb, LISP_HLEN);
+       skb_reset_transport_header(skb);
+
+       lisp_build_header(skb);
+       udph = udp_hdr(skb);
+       udph->dest = lisp_port->dst_port;
+       udph->source = htons(ovs_tnl_get_src_port(skb));
+       udph->check = 0;
+       udph->len = htons(skb->len - skb_transport_offset(skb));
+
        /* Offloading */
-       nskb = handle_offloads(skb);
-       if (IS_ERR(nskb)) {
-               err = PTR_ERR(nskb);
-               goto err_free_rt;
-       }
-       skb = nskb;
-
-       /* Reset SKB */
-       nf_reset(skb);
-       secpath_reset(skb);
-       skb_dst_drop(skb);
-       skb_clear_rxhash(skb);
-
-       while (skb) {
-               struct sk_buff *next_skb = skb->next;
-               struct iphdr *iph;
-               int frag_len;
-
-               skb->next = NULL;
-
-               if (unlikely(vlan_deaccel_tag(skb)))
-                       goto next;
-
-               frag_len = skb->len;
-               skb_push(skb, tunnel_hlen);
-               skb_reset_network_header(skb);
-               skb_set_transport_header(skb, sizeof(struct iphdr));
-
-               if (next_skb)
-                       skb_dst_set(skb, dst_clone(&rt_dst(rt)));
-               else
-                       skb_dst_set(skb, &rt_dst(rt));
-
-               /* Push Tunnel header. */
-               build_header(vport, skb, tunnel_hlen);
-
-               /* Push IP header. */
-               iph = ip_hdr(skb);
-               iph->version    = 4;
-               iph->ihl        = sizeof(struct iphdr) >> 2;
-               iph->protocol   = ipproto;
-               iph->daddr      = OVS_CB(skb)->tun_key->ipv4_dst;
-               iph->saddr      = saddr;
-               iph->tos        = OVS_CB(skb)->tun_key->ipv4_tos;
-               iph->ttl        = OVS_CB(skb)->tun_key->ipv4_ttl;
-               iph->frag_off   = OVS_CB(skb)->tun_key->tun_flags &
+       handle_offloads(skb);
+       skb->local_df = 1;
+
+       df = OVS_CB(skb)->tun_key->tun_flags &
                                  TUNNEL_DONT_FRAGMENT ?  htons(IP_DF) : 0;
-               /*
-                * Allow our local IP stack to fragment the outer packet even
-                * if the DF bit is set as a last resort.  We also need to
-                * force selection of an IP ID here with __ip_select_ident(),
-                * as ip_select_ident() assumes a proper ID is not needed when
-                * when the DF bit is set.
-                */
-               skb->local_df = 1;
-               __ip_select_ident(iph, skb_dst(skb), 0);
-
-               memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
-
-               err = ip_local_out(skb);
-               if (unlikely(net_xmit_eval(err)))
-                       goto next;
-
-               sent_len += frag_len;
-
-next:
-               skb = next_skb;
-       }
 
-       return sent_len;
+       return iptunnel_xmit(net, rt, skb,
+                            saddr, OVS_CB(skb)->tun_key->ipv4_dst,
+                            IPPROTO_UDP, OVS_CB(skb)->tun_key->ipv4_tos,
+                            OVS_CB(skb)->tun_key->ipv4_ttl, df);
 
 err_free_rt:
        ip_rt_put(rt);
@@ -572,8 +464,7 @@ static int lisp_tnl_send(struct vport *vport, struct 
sk_buff *skb)
        case htons(ETH_P_IPV6):
                /* Pop off "inner" Ethernet header */
                skb_pull(skb, network_offset);
-               tnl_len = ovs_tnl_send(vport, skb, IPPROTO_UDP,
-                               LISP_HLEN, lisp_build_header);
+               tnl_len = tnl_send(vport, skb);
                return tnl_len > 0 ? tnl_len + network_offset : tnl_len;
        default:
                kfree_skb(skb);
-- 
1.7.1

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to