datapath: compat: Configure check GRE DEMUX.
authorPravin B Shelar <pshelar@nicira.com>
Mon, 23 Dec 2013 03:43:58 +0000 (19:43 -0800)
committerPravin B Shelar <pshelar@nicira.com>
Fri, 20 Dec 2013 23:34:43 +0000 (15:34 -0800)
RHEL6-openstack kernel has backported gre DEMUX module,
Therefore add configure check to detect it.

Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
Acked-by: Jesse Gross <jesse@nicira.com>
Bug #21936

acinclude.m4
datapath/linux/compat/gre.c
datapath/linux/compat/include/net/gre.h

index 99b4054..7078654 100644 (file)
@@ -274,6 +274,7 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [
   OVS_GREP_IFELSE([$KSRC/include/net/checksum.h], [csum_unfold])
 
   OVS_GREP_IFELSE([$KSRC/include/net/genetlink.h], [parallel_ops])
+  OVS_GREP_IFELSE([$KSRC/include/net/gre.h], [gre_cisco_register])
   OVS_GREP_IFELSE([$KSRC/include/net/netlink.h], [nla_get_be16])
   OVS_GREP_IFELSE([$KSRC/include/net/netlink.h], [nla_put_be16])
   OVS_GREP_IFELSE([$KSRC/include/net/netlink.h], [nla_put_be32])
index f35f11f..58b1e73 100644 (file)
 
 #include "gso.h"
 
-static void gre_csum_fix(struct sk_buff *skb)
-{
-       struct gre_base_hdr *greh;
-       __be32 *options;
-       int gre_offset = skb_transport_offset(skb);
+#ifndef HAVE_GRE_CISCO_REGISTER
 
-       greh = (struct gre_base_hdr *)skb_transport_header(skb);
-       options = ((__be32 *)greh + 1);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
 
-       *options = 0;
-       *(__sum16 *)options = csum_fold(skb_checksum(skb, gre_offset,
-                                                    skb->len - gre_offset, 0));
-}
+#define GREPROTO_CISCO         0
+#define GREPROTO_MAX           1
 
-struct sk_buff *gre_handle_offloads(struct sk_buff *skb, bool gre_csum)
+struct gre_protocol {
+       int  (*handler)(struct sk_buff *skb);
+};
+static const struct gre_protocol __rcu *gre_proto[GREPROTO_MAX] __read_mostly;
+
+static int gre_rcv(struct sk_buff *skb)
 {
-       int err;
+       const struct gre_protocol *proto;
+       u8 ver;
+       int ret;
 
-       skb_reset_inner_headers(skb);
+       if (!pskb_may_pull(skb, 12))
+               goto drop;
 
-       if (skb_is_gso(skb)) {
-               if (gre_csum)
-                       OVS_GSO_CB(skb)->fix_segment = gre_csum_fix;
-       } else {
-               if (skb->ip_summed == CHECKSUM_PARTIAL && gre_csum) {
-                       err = skb_checksum_help(skb);
-                       if (err)
-                               goto error;
+       ver = skb->data[1] & 0x7f;
+       if (ver >= GREPROTO_MAX)
+               goto drop;
 
-               } else if (skb->ip_summed != CHECKSUM_PARTIAL)
-                       skb->ip_summed = CHECKSUM_NONE;
-       }
-       return skb;
-error:
+       rcu_read_lock();
+       proto = rcu_dereference(gre_proto[ver]);
+       if (!proto || !proto->handler)
+               goto drop_unlock;
+       ret = proto->handler(skb);
+       rcu_read_unlock();
+       return ret;
+
+drop_unlock:
+       rcu_read_unlock();
+drop:
        kfree_skb(skb);
-       return ERR_PTR(err);
+       return NET_RX_DROP;
 }
 
-static bool is_gre_gso(struct sk_buff *skb)
+static const struct net_protocol net_gre_protocol = {
+       .handler     = gre_rcv,
+       .netns_ok    = 1,
+};
+
+static int gre_add_protocol(const struct gre_protocol *proto, u8 version)
 {
-       return skb_is_gso(skb);
+       if (version >= GREPROTO_MAX)
+               return -EINVAL;
+
+       if (inet_add_protocol(&net_gre_protocol, IPPROTO_GRE) < 0) {
+               pr_err("%s: cannot register gre protocol handler\n", __func__);
+               return -EAGAIN;
+       }
+
+       return (cmpxchg((const struct gre_protocol **)&gre_proto[version], NULL, proto) == NULL) ?
+               0 : -EBUSY;
 }
 
-void gre_build_header(struct sk_buff *skb, const struct tnl_ptk_info *tpi,
-                     int hdr_len)
+static int gre_del_protocol(const struct gre_protocol *proto, u8 version)
 {
-       struct gre_base_hdr *greh;
+       int ret;
 
-       __skb_push(skb, hdr_len);
+       if (version >= GREPROTO_MAX)
+               return -EINVAL;
 
-       greh = (struct gre_base_hdr *)skb->data;
-       greh->flags = tnl_flags_to_gre_flags(tpi->flags);
-       greh->protocol = tpi->proto;
+       ret = (cmpxchg((const struct gre_protocol **)&gre_proto[version], proto, NULL) == proto) ?
+               0 : -EBUSY;
 
-       if (tpi->flags & (TUNNEL_KEY | TUNNEL_CSUM | TUNNEL_SEQ)) {
-               __be32 *ptr = (__be32 *)(((u8 *)greh) + hdr_len - 4);
+       if (ret)
+               return ret;
 
-               if (tpi->flags & TUNNEL_SEQ) {
-                       *ptr = tpi->seq;
-                       ptr--;
-               }
-               if (tpi->flags & TUNNEL_KEY) {
-                       *ptr = tpi->key;
-                       ptr--;
-               }
-               if (tpi->flags & TUNNEL_CSUM && !is_gre_gso(skb)) {
-                       *ptr = 0;
-                       *(__sum16 *)ptr = csum_fold(skb_checksum(skb, 0,
-                                               skb->len, 0));
-               }
-       }
+       synchronize_net();
+
+       ret = inet_del_protocol(&net_gre_protocol, IPPROTO_GRE);
+       if (ret)
+               return ret;
+
+       return 0;
 }
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3,11,0)
+#endif
 
 static __sum16 check_checksum(struct sk_buff *skb)
 {
@@ -198,7 +206,6 @@ static int parse_gre_header(struct sk_buff *skb, struct tnl_ptk_info *tpi,
 }
 
 static struct gre_cisco_protocol __rcu *gre_cisco_proto;
-
 static int gre_cisco_rcv(struct sk_buff *skb)
 {
        struct tnl_ptk_info tpi;
@@ -226,136 +233,110 @@ static const struct gre_protocol ipgre_protocol = {
        .handler        =       gre_cisco_rcv,
 };
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
-static const struct gre_protocol __rcu *gre_proto[GREPROTO_MAX] __read_mostly;
-
-int gre_add_protocol(const struct gre_protocol *proto, u8 version)
+int gre_cisco_register(struct gre_cisco_protocol *newp)
 {
-       if (version >= GREPROTO_MAX)
-               return -EINVAL;
+       int err;
 
-       return (cmpxchg((const struct gre_protocol **)&gre_proto[version], NULL, proto) == NULL) ?
+       err = gre_add_protocol(&ipgre_protocol, GREPROTO_CISCO);
+       if (err) {
+               pr_warn("%s: cannot register gre_cisco protocol handler\n", __func__);
+               return err;
+       }
+
+
+       return (cmpxchg((struct gre_cisco_protocol **)&gre_cisco_proto, NULL, newp) == NULL) ?
                0 : -EBUSY;
 }
 
-int gre_del_protocol(const struct gre_protocol *proto, u8 version)
+int gre_cisco_unregister(struct gre_cisco_protocol *proto)
 {
        int ret;
 
-       if (version >= GREPROTO_MAX)
-               return -EINVAL;
-
-       ret = (cmpxchg((const struct gre_protocol **)&gre_proto[version], proto, NULL) == proto) ?
-               0 : -EBUSY;
+       ret = (cmpxchg((struct gre_cisco_protocol **)&gre_cisco_proto, proto, NULL) == proto) ?
+               0 : -EINVAL;
 
        if (ret)
                return ret;
 
        synchronize_net();
-       return 0;
+       ret = gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO);
+       return ret;
 }
 
-static int gre_rcv(struct sk_buff *skb)
-{
-       const struct gre_protocol *proto;
-       u8 ver;
-       int ret;
-
-       if (!pskb_may_pull(skb, 12))
-               goto drop;
+#endif /* !HAVE_GRE_CISCO_REGISTER */
 
-       ver = skb->data[1] & 0x7f;
-       if (ver >= GREPROTO_MAX)
-               goto drop;
+/* GRE TX side. */
+static void gre_csum_fix(struct sk_buff *skb)
+{
+       struct gre_base_hdr *greh;
+       __be32 *options;
+       int gre_offset = skb_transport_offset(skb);
 
-       rcu_read_lock();
-       proto = rcu_dereference(gre_proto[ver]);
-       if (!proto || !proto->handler)
-               goto drop_unlock;
-       ret = proto->handler(skb);
-       rcu_read_unlock();
-       return ret;
+       greh = (struct gre_base_hdr *)skb_transport_header(skb);
+       options = ((__be32 *)greh + 1);
 
-drop_unlock:
-       rcu_read_unlock();
-drop:
-       kfree_skb(skb);
-       return NET_RX_DROP;
+       *options = 0;
+       *(__sum16 *)options = csum_fold(skb_checksum(skb, gre_offset,
+                                                    skb->len - gre_offset, 0));
 }
 
-static const struct net_protocol net_gre_protocol = {
-       .handler     = gre_rcv,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
-       .netns_ok    = 1,
-#endif
-};
-#endif
-
-static int gre_compat_init(void)
+struct sk_buff *gre_handle_offloads(struct sk_buff *skb, bool gre_csum)
 {
        int err;
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
-       if (inet_add_protocol(&net_gre_protocol, IPPROTO_GRE) < 0) {
-               pr_err("%s: cannot register gre protocol handler\n", __func__);
-               return -EAGAIN;
-       }
-#endif
-       err = gre_add_protocol(&ipgre_protocol, GREPROTO_CISCO);
-       if (err) {
-               pr_warn("%s: cannot register gre_cisco protocol handler\n", __func__);
+       skb_reset_inner_headers(skb);
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
-               inet_del_protocol(&net_gre_protocol, IPPROTO_GRE);
-#endif
-       }
+       if (skb_is_gso(skb)) {
+               if (gre_csum)
+                       OVS_GSO_CB(skb)->fix_segment = gre_csum_fix;
+       } else {
+               if (skb->ip_summed == CHECKSUM_PARTIAL && gre_csum) {
+                       err = skb_checksum_help(skb);
+                       if (err)
+                               goto error;
 
-       return err;
+               } else if (skb->ip_summed != CHECKSUM_PARTIAL)
+                       skb->ip_summed = CHECKSUM_NONE;
+       }
+       return skb;
+error:
+       kfree_skb(skb);
+       return ERR_PTR(err);
 }
 
-static int gre_compat_exit(void)
+static bool is_gre_gso(struct sk_buff *skb)
 {
-       int ret;
-
-       ret = gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO);
-       if (ret)
-               return ret;
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
-       ret = inet_del_protocol(&net_gre_protocol, IPPROTO_GRE);
-       if (ret)
-               return ret;
-#endif
-       return 0;
+       return skb_is_gso(skb);
 }
 
-int gre_cisco_register(struct gre_cisco_protocol *newp)
+void gre_build_header(struct sk_buff *skb, const struct tnl_ptk_info *tpi,
+                     int hdr_len)
 {
-       int err;
-
-       err = gre_compat_init();
-       if (err)
-               return err;
-
-       return (cmpxchg((struct gre_cisco_protocol **)&gre_cisco_proto, NULL, newp) == NULL) ?
-               0 : -EBUSY;
-}
+       struct gre_base_hdr *greh;
 
-int gre_cisco_unregister(struct gre_cisco_protocol *proto)
-{
-       int ret;
+       __skb_push(skb, hdr_len);
 
-       ret = (cmpxchg((struct gre_cisco_protocol **)&gre_cisco_proto, proto, NULL) == proto) ?
-               0 : -EINVAL;
+       greh = (struct gre_base_hdr *)skb->data;
+       greh->flags = tnl_flags_to_gre_flags(tpi->flags);
+       greh->protocol = tpi->proto;
 
-       if (ret)
-               return ret;
+       if (tpi->flags & (TUNNEL_KEY | TUNNEL_CSUM | TUNNEL_SEQ)) {
+               __be32 *ptr = (__be32 *)(((u8 *)greh) + hdr_len - 4);
 
-       synchronize_net();
-       ret = gre_compat_exit();
-       return ret;
+               if (tpi->flags & TUNNEL_SEQ) {
+                       *ptr = tpi->seq;
+                       ptr--;
+               }
+               if (tpi->flags & TUNNEL_KEY) {
+                       *ptr = tpi->key;
+                       ptr--;
+               }
+               if (tpi->flags & TUNNEL_CSUM && !is_gre_gso(skb)) {
+                       *ptr = 0;
+                       *(__sum16 *)ptr = csum_fold(skb_checksum(skb, 0,
+                                               skb->len, 0));
+               }
+       }
 }
 
-#endif /* 3.11 */
-
 #endif /* CONFIG_NET_IPGRE_DEMUX */
index 91fb7af..a6f29c4 100644 (file)
@@ -4,22 +4,26 @@
 #include <linux/skbuff.h>
 #include <net/ip_tunnels.h>
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37) || \
+   defined(HAVE_GRE_CISCO_REGISTER)
 #include_next <net/gre.h>
+#endif
 
-#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) */
+#ifndef HAVE_GRE_CISCO_REGISTER
 
-#define GREPROTO_CISCO         0
-#define GREPROTO_MAX           2
+/* GRE demux not available, implement our own demux. */
+#define MAX_GRE_PROTO_PRIORITY 255
 
-struct gre_protocol {
-       int  (*handler)(struct sk_buff *skb);
+struct gre_cisco_protocol {
+       int (*handler)(struct sk_buff *skb, const struct tnl_ptk_info *tpi);
+       u8 priority;
 };
 
-int gre_add_protocol(const struct gre_protocol *proto, u8 version);
-int gre_del_protocol(const struct gre_protocol *proto, u8 version);
+#define gre_cisco_register rpl_gre_cisco_register
+int gre_cisco_register(struct gre_cisco_protocol *proto);
 
-#endif
+#define gre_cisco_unregister rpl_gre_cisco_unregister
+int gre_cisco_unregister(struct gre_cisco_protocol *proto);
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0)
 struct gre_base_hdr {
@@ -72,24 +76,7 @@ static inline __be16 tnl_flags_to_gre_flags(__be16 tflags)
        return flags;
 }
 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) */
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3,11,0)
-/* GRE demux not available, implement our own demux. */
-#define MAX_GRE_PROTO_PRIORITY 255
-#define gre_cisco_protocol rpl_gre_cisco_protocol
-
-struct gre_cisco_protocol {
-       int (*handler)(struct sk_buff *skb, const struct tnl_ptk_info *tpi);
-       u8 priority;
-};
-
-#define gre_cisco_register rpl_gre_cisco_register
-int gre_cisco_register(struct gre_cisco_protocol *proto);
-
-#define gre_cisco_unregister rpl_gre_cisco_unregister
-int gre_cisco_unregister(struct gre_cisco_protocol *proto);
-
-#endif
+#endif /* HAVE_GRE_CISCO_REGISTER */
 
 #define gre_build_header rpl_gre_build_header
 void gre_build_header(struct sk_buff *skb, const struct tnl_ptk_info *tpi,
@@ -112,5 +99,4 @@ static inline int ip_gre_calc_hlen(__be16 o_flags)
        return addend;
 }
 
-
 #endif