From b1b3fb138f4d5c942b69dd948963f978ee180a8f Mon Sep 17 00:00:00 2001 From: Pravin B Shelar Date: Fri, 19 Dec 2014 16:24:57 -0800 Subject: [PATCH] datapath: compat: introduce ovs_iptunnel_handle_offloads() handle offload code is replicated for different tunneling protocols define compat function to simplify the code. Signed-off-by: Pravin B Shelar Acked-by: Jesse Gross --- datapath/linux/compat/gre.c | 32 +++++----------------- datapath/linux/compat/gso.c | 51 +++++++++++++++++++++++++++++++++++ datapath/linux/compat/gso.h | 8 +++++- datapath/linux/compat/vxlan.c | 19 ++++--------- datapath/vport-geneve.c | 36 +++++++++++++------------ datapath/vport-lisp.c | 36 ++++++++++++------------- 6 files changed, 107 insertions(+), 75 deletions(-) diff --git a/datapath/linux/compat/gre.c b/datapath/linux/compat/gre.c index 1cd885b6f..02551fb3b 100644 --- a/datapath/linux/compat/gre.c +++ b/datapath/linux/compat/gre.c @@ -287,33 +287,15 @@ static void gre_csum_fix(struct sk_buff *skb) struct sk_buff *gre_handle_offloads(struct sk_buff *skb, bool gre_csum) { - int err; - - skb_reset_inner_headers(skb); + gso_fix_segment_t fix_segment; - if (skb_is_gso(skb)) { - if (skb_is_encapsulated(skb)) { - err = -ENOSYS; - goto error; - } + if (gre_csum) + fix_segment = gre_csum_fix; + else + fix_segment = NULL; - if (gre_csum) - OVS_GSO_CB(skb)->fix_segment = gre_csum_fix; - else - OVS_GSO_CB(skb)->fix_segment = NULL; - } else { - if (skb->ip_summed == CHECKSUM_PARTIAL && gre_csum) { - err = skb_checksum_help(skb); - if (err) - goto error; - - } else if (skb->ip_summed != CHECKSUM_PARTIAL) - skb->ip_summed = CHECKSUM_NONE; - } - return skb; -error: - kfree_skb(skb); - return ERR_PTR(err); + skb_reset_inner_headers(skb); + return ovs_iptunnel_handle_offloads(skb, gre_csum, fix_segment); } static bool is_gre_gso(struct sk_buff *skb) diff --git a/datapath/linux/compat/gso.c b/datapath/linux/compat/gso.c index 96b5d3d08..5079f790d 100644 --- a/datapath/linux/compat/gso.c +++ b/datapath/linux/compat/gso.c @@ -294,3 +294,54 @@ int rpl_ip_local_out(struct sk_buff *skb) return ret; } #endif /* 3.16 */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,12,0) +struct sk_buff *ovs_iptunnel_handle_offloads(struct sk_buff *skb, + bool csum_help, + void (*fix_segment)(struct sk_buff *)) +{ + int err; + + /* XXX: synchronize inner header reset for compat and non compat code + * so that we can do it here. + */ + /* + skb_reset_inner_headers(skb); + */ + + /* OVS compat code does not maintain encapsulation bit. + * skb->encapsulation = 1; */ + + if (skb_is_gso(skb)) { + if (skb_is_encapsulated(skb)) { + err = -ENOSYS; + goto error; + } + + OVS_GSO_CB(skb)->fix_segment = fix_segment; + return skb; + } + + /* If packet is not gso and we are resolving any partial checksum, + * clear encapsulation flag. This allows setting CHECKSUM_PARTIAL + * on the outer header without confusing devices that implement + * NETIF_F_IP_CSUM with encapsulation. + */ + /* + if (csum_help) + skb->encapsulation = 0; + */ + + if (skb->ip_summed == CHECKSUM_PARTIAL && csum_help) { + err = skb_checksum_help(skb); + if (unlikely(err)) + goto error; + } else if (skb->ip_summed != CHECKSUM_PARTIAL) + skb->ip_summed = CHECKSUM_NONE; + + return skb; +error: + kfree_skb(skb); + return ERR_PTR(err); +} +#endif /* 3.12 */ diff --git a/datapath/linux/compat/gso.h b/datapath/linux/compat/gso.h index fd1084871..1009892e5 100644 --- a/datapath/linux/compat/gso.h +++ b/datapath/linux/compat/gso.h @@ -9,10 +9,11 @@ #include #include "datapath.h" +typedef void (*gso_fix_segment_t)(struct sk_buff *); struct ovs_gso_cb { struct ovs_skb_cb dp_cb; - void (*fix_segment)(struct sk_buff *); + gso_fix_segment_t fix_segment; sk_buff_data_t inner_mac_header; /* Offset from skb->head */ #if LINUX_VERSION_CODE < KERNEL_VERSION(3,11,0) __be16 inner_protocol; @@ -65,6 +66,11 @@ static inline void skb_reset_inner_headers(struct sk_buff *skb) OVS_GSO_CB(skb)->fix_segment = NULL; } +struct sk_buff *ovs_iptunnel_handle_offloads(struct sk_buff *skb, + bool csum_help, + gso_fix_segment_t fix_segment); + + #endif /* 3.12 */ #if LINUX_VERSION_CODE < KERNEL_VERSION(3,16,0) diff --git a/datapath/linux/compat/vxlan.c b/datapath/linux/compat/vxlan.c index ff040ac2f..b9fd8bad3 100644 --- a/datapath/linux/compat/vxlan.c +++ b/datapath/linux/compat/vxlan.c @@ -166,18 +166,9 @@ static void vxlan_gso(struct sk_buff *skb) skb->ip_summed = CHECKSUM_NONE; } -static int handle_offloads(struct sk_buff *skb) +static struct sk_buff *handle_offloads(struct sk_buff *skb) { - if (skb_is_gso(skb)) { - if (skb_is_encapsulated(skb)) - return -ENOSYS; - - OVS_GSO_CB(skb)->fix_segment = vxlan_gso; - } else { - if (skb->ip_summed != CHECKSUM_PARTIAL) - skb->ip_summed = CHECKSUM_NONE; - } - return 0; + return ovs_iptunnel_handle_offloads(skb, false, vxlan_gso); } int vxlan_xmit_skb(struct vxlan_sock *vs, @@ -226,9 +217,9 @@ int vxlan_xmit_skb(struct vxlan_sock *vs, vxlan_set_owner(vs->sock->sk, skb); - err = handle_offloads(skb); - if (err) - return err; + skb = handle_offloads(skb); + if (IS_ERR(skb)) + return 0; return iptunnel_xmit(vs->sock->sk, rt, skb, src, dst, IPPROTO_UDP, tos, ttl, df, false); diff --git a/datapath/vport-geneve.c b/datapath/vport-geneve.c index 200cc1469..a65dcb6b4 100644 --- a/datapath/vport-geneve.c +++ b/datapath/vport-geneve.c @@ -324,36 +324,36 @@ static void geneve_fix_segment(struct sk_buff *skb) udph->len = htons(skb->len - skb_transport_offset(skb)); } -static int handle_offloads(struct sk_buff *skb) +static struct sk_buff *handle_offloads(struct sk_buff *skb) { - if (skb_is_gso(skb)) { - if (skb_is_encapsulated(skb)) - return -ENOSYS; - OVS_GSO_CB(skb)->fix_segment = geneve_fix_segment; - } else if (skb->ip_summed != CHECKSUM_PARTIAL) { - skb->ip_summed = CHECKSUM_NONE; - } - return 0; + return ovs_iptunnel_handle_offloads(skb, false, geneve_fix_segment); } #else -static int handle_offloads(struct sk_buff *skb) + +static struct sk_buff *handle_offloads(struct sk_buff *skb) { + int err = 0; + if (skb_is_gso(skb)) { - int err; - if (skb_is_encapsulated(skb)) - return -ENOSYS; + if (skb_is_encapsulated(skb)) { + err = -ENOSYS; + goto error; + } err = skb_unclone(skb, GFP_ATOMIC); if (unlikely(err)) - return err; + goto error; skb_shinfo(skb)->gso_type |= SKB_GSO_UDP_TUNNEL; } else if (skb->ip_summed != CHECKSUM_PARTIAL) skb->ip_summed = CHECKSUM_NONE; skb->encapsulation = 1; - return 0; + return skb; +error: + kfree_skb(skb); + return ERR_PTR(err); } #endif @@ -420,9 +420,11 @@ static int geneve_send(struct vport *vport, struct sk_buff *skb) geneve_build_header(vport, skb); /* Offloading */ - err = handle_offloads(skb); - if (err) + skb = handle_offloads(skb); + if (IS_ERR(skb)) { + err = 0; goto err_free_rt; + } df = tun_key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0; diff --git a/datapath/vport-lisp.c b/datapath/vport-lisp.c index a067e050c..04f11ac43 100644 --- a/datapath/vport-lisp.c +++ b/datapath/vport-lisp.c @@ -406,37 +406,35 @@ static void lisp_fix_segment(struct sk_buff *skb) udph->len = htons(skb->len - skb_transport_offset(skb)); } -static int handle_offloads(struct sk_buff *skb) +static struct sk_buff *handle_offloads(struct sk_buff *skb) { - if (skb_is_gso(skb)) { - if (skb_is_encapsulated(skb)) - return -ENOSYS; - - OVS_GSO_CB(skb)->fix_segment = lisp_fix_segment; - } else if (skb->ip_summed != CHECKSUM_PARTIAL) { - skb->ip_summed = CHECKSUM_NONE; - } - return 0; + return ovs_iptunnel_handle_offloads(skb, false, lisp_fix_segment); } #else -static int handle_offloads(struct sk_buff *skb) +static struct sk_buff *handle_offloads(struct sk_buff *skb) { + int err = 0; + if (skb_is_gso(skb)) { - int err; - if (skb_is_encapsulated(skb)) - return -ENOSYS; + if (skb_is_encapsulated(skb)) { + err = -ENOSYS; + goto error; + } err = skb_unclone(skb, GFP_ATOMIC); if (unlikely(err)) - return err; + goto error; skb_shinfo(skb)->gso_type |= SKB_GSO_UDP_TUNNEL; } else if (skb->ip_summed != CHECKSUM_PARTIAL) skb->ip_summed = CHECKSUM_NONE; skb->encapsulation = 1; - return 0; + return skb; +error: + kfree_skb(skb); + return ERR_PTR(err); } #endif @@ -500,9 +498,11 @@ static int lisp_send(struct vport *vport, struct sk_buff *skb) lisp_build_header(vport, skb); /* Offloading */ - err = handle_offloads(skb); - if (err) + skb = handle_offloads(skb); + if (IS_ERR(skb)) { + err = 0; goto err_free_rt; + } skb->ignore_df = 1; -- 2.20.1