handle offload code is replicated for different tunneling protocols define compat function to simplify the code.
Signed-off-by: Pravin B Shelar <pshe...@nicira.com> --- datapath/linux/compat/gre.c | 32 +++----------- datapath/linux/compat/include/net/ip_tunnels.h | 3 + datapath/linux/compat/ip_tunnels_core.c | 52 ++++++++++++++++++++++++ datapath/linux/compat/vxlan.c | 19 ++------ datapath/vport-geneve.c | 25 +++++------- datapath/vport-lisp.c | 26 +++++------- 6 files changed, 87 insertions(+), 70 deletions(-) diff --git a/datapath/linux/compat/gre.c b/datapath/linux/compat/gre.c index 1cd885b..30ee34c 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); + void (*fix_segment)(struct sk_buff *); - 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/include/net/ip_tunnels.h b/datapath/linux/compat/include/net/ip_tunnels.h index 8fb9527..cd5a9e4 100644 --- a/datapath/linux/compat/include/net/ip_tunnels.h +++ b/datapath/linux/compat/include/net/ip_tunnels.h @@ -76,5 +76,8 @@ int iptunnel_pull_header(struct sk_buff *skb, int hdr_len, __be16 inner_proto); #define TUNNEL_OPTIONS_PRESENT __cpu_to_be16(0x0800) bool skb_is_encapsulated(struct sk_buff *skb); +struct sk_buff *ovs_iptunnel_handle_offloads(struct sk_buff *skb, + bool csum_help, + void (*fix_segment)(struct sk_buff *)); #endif /* __NET_IP_TUNNELS_H */ diff --git a/datapath/linux/compat/ip_tunnels_core.c b/datapath/linux/compat/ip_tunnels_core.c index e71ba4e..7606ad6 100644 --- a/datapath/linux/compat/ip_tunnels_core.c +++ b/datapath/linux/compat/ip_tunnels_core.c @@ -126,3 +126,55 @@ bool skb_is_encapsulated(struct sk_buff *skb) /* XXX: set inner protocol for all tunnel in OVS. */ return ovs_skb_get_inner_protocol(skb) || skb_encapsulation(skb); } + +struct sk_buff *ovs_iptunnel_handle_offloads(struct sk_buff *skb, + bool csum_help, + void (*fix_segment)(struct sk_buff *)) +{ + int err; + + if (skb_is_encapsulated(skb)) { + err = -ENOSYS; + goto error; + } + + /* XXX: synchronize inner header 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)) { + err = skb_unclone(skb, GFP_ATOMIC); + if (unlikely(err)) + 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); +} diff --git a/datapath/linux/compat/vxlan.c b/datapath/linux/compat/vxlan.c index ff040ac..76ae552 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 PTR_ERR(skb); 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 200cc14..6fcf1cc 100644 --- a/datapath/vport-geneve.c +++ b/datapath/vport-geneve.c @@ -324,36 +324,29 @@ 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) { if (skb_is_gso(skb)) { int err; if (skb_is_encapsulated(skb)) - return -ENOSYS; + return ERR_PTR(-ENOSYS); err = skb_unclone(skb, GFP_ATOMIC); if (unlikely(err)) - return err; + return ERR_PTR(err); 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; } #endif @@ -420,9 +413,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 = PTR_ERR(skb); 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 a067e05..ce30f69 100644 --- a/datapath/vport-lisp.c +++ b/datapath/vport-lisp.c @@ -406,37 +406,29 @@ 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) { if (skb_is_gso(skb)) { int err; if (skb_is_encapsulated(skb)) - return -ENOSYS; + return ERR_PTR(-ENOSYS); err = skb_unclone(skb, GFP_ATOMIC); if (unlikely(err)) - return err; + return ERR_PTR(err); 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; } #endif @@ -500,9 +492,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 = PTR_ERR(skb); goto err_free_rt; + } skb->ignore_df = 1; -- 1.7.1 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev