datapath: Include datapath actions with sampled-packet upcall to userspace.
[cascardo/ovs.git] / datapath / linux / compat / ip_tunnels_core.c
index e71ba4e..8ff7cd7 100644 (file)
 #include "compat.h"
 #include "gso.h"
 
-#ifndef USE_KERNEL_TUNNEL_API
-int iptunnel_xmit(struct sock *sk, struct rtable *rt,
-                 struct sk_buff *skb,
-                 __be32 src, __be32 dst, __u8 proto,
-                 __u8 tos, __u8 ttl, __be16 df, bool xnet)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,18,0)
+int rpl_iptunnel_xmit(struct sock *sk, struct rtable *rt, struct sk_buff *skb,
+                      __be32 src, __be32 dst, __u8 proto, __u8 tos, __u8 ttl,
+                      __be16 df, bool xnet)
 {
        int pkt_len = skb->len;
        struct iphdr *iph;
@@ -81,8 +80,62 @@ int iptunnel_xmit(struct sock *sk, struct rtable *rt,
                pkt_len = 0;
        return pkt_len;
 }
+EXPORT_SYMBOL_GPL(rpl_iptunnel_xmit);
 
-int iptunnel_pull_header(struct sk_buff *skb, int hdr_len, __be16 inner_proto)
+struct sk_buff *ovs_iptunnel_handle_offloads(struct sk_buff *skb,
+                                            bool csum_help, int gso_type_mask,
+                                            void (*fix_segment)(struct sk_buff *))
+{
+       int err;
+
+       if (likely(!skb_is_encapsulated(skb))) {
+               skb_reset_inner_headers(skb);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0)
+               skb->encapsulation = 1;
+#endif
+       } else if (skb_is_gso(skb)) {
+               err = -ENOSYS;
+               goto error;
+       }
+
+       if (gso_type_mask)
+               fix_segment = NULL;
+
+       OVS_GSO_CB(skb)->fix_segment = fix_segment;
+
+       if (skb_is_gso(skb)) {
+               err = skb_unclone(skb, GFP_ATOMIC);
+               if (unlikely(err))
+                       goto error;
+               skb_shinfo(skb)->gso_type |= gso_type_mask;
+               return skb;
+       }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0)
+       /* 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;
+#endif
+
+       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);
+}
+EXPORT_SYMBOL_GPL(ovs_iptunnel_handle_offloads);
+
+int rpl_iptunnel_pull_header(struct sk_buff *skb, int hdr_len, __be16 inner_proto)
 {
        if (unlikely(!pskb_may_pull(skb, hdr_len)))
                return -ENOMEM;
@@ -115,14 +168,15 @@ int iptunnel_pull_header(struct sk_buff *skb, int hdr_len, __be16 inner_proto)
        skb->pkt_type = PACKET_HOST;
        return 0;
 }
+EXPORT_SYMBOL_GPL(rpl_iptunnel_pull_header);
 
 #endif
 
-bool skb_is_encapsulated(struct sk_buff *skb)
+bool ovs_skb_is_encapsulated(struct sk_buff *skb)
 {
        /* checking for inner protocol should be sufficient on newer kernel, but
         * old kernel just set encapsulation bit.
         */
-       /* XXX: set inner protocol for all tunnel in OVS. */
        return ovs_skb_get_inner_protocol(skb) || skb_encapsulation(skb);
 }
+EXPORT_SYMBOL_GPL(ovs_skb_is_encapsulated);