gre: Compatibility with older Linux kernel versions.
authorJesse Gross <jesse@nicira.com>
Thu, 3 Dec 2009 02:56:36 +0000 (18:56 -0800)
committerJesse Gross <jesse@nicira.com>
Mon, 7 Dec 2009 20:43:25 +0000 (12:43 -0800)
The upcoming GRE kernel module compiles on a range (2.6.18+) of
Linux kernel versions.  The module expects the kernel headers to
look like newer versions.  Where older and newer versions of the
kernel differ this commit implements shims to paper over the changes.

12 files changed:
datapath/linux-2.6/compat-2.6/include/linux/if.h [new file with mode: 0644]
datapath/linux-2.6/compat-2.6/include/linux/if_ether.h [new file with mode: 0644]
datapath/linux-2.6/compat-2.6/include/linux/in.h [new file with mode: 0644]
datapath/linux-2.6/compat-2.6/include/linux/inetdevice.h [new file with mode: 0644]
datapath/linux-2.6/compat-2.6/include/linux/netdevice.h
datapath/linux-2.6/compat-2.6/include/linux/skbuff.h
datapath/linux-2.6/compat-2.6/include/net/dst.h [new file with mode: 0644]
datapath/linux-2.6/compat-2.6/include/net/ipip.h [new file with mode: 0644]
datapath/linux-2.6/compat-2.6/include/net/net_namespace.h [new file with mode: 0644]
datapath/linux-2.6/compat-2.6/include/net/netns/generic.h [new file with mode: 0644]
datapath/linux-2.6/compat-2.6/include/net/route.h [new file with mode: 0644]
datapath/linux-2.6/compat-2.6/net_namespace-ip_gre.c [new file with mode: 0644]

diff --git a/datapath/linux-2.6/compat-2.6/include/linux/if.h b/datapath/linux-2.6/compat-2.6/include/linux/if.h
new file mode 100644 (file)
index 0000000..0aa9ee3
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __LINUX_IF_WRAPPER_H
+#define __LINUX_IF_WRAPPER_H 1
+
+#include_next <linux/if.h>
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31)
+
+#define IFF_XMIT_DST_RELEASE 0
+
+#endif /* linux kernel < 2.6.31 */
+
+#endif
diff --git a/datapath/linux-2.6/compat-2.6/include/linux/if_ether.h b/datapath/linux-2.6/compat-2.6/include/linux/if_ether.h
new file mode 100644 (file)
index 0000000..b8390e2
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __LINUX_IF_ETHER_WRAPPER_H
+#define __LINUX_IF_ETHER_WRAPPER_H 1
+
+#include_next <linux/if_ether.h>
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
+
+#define ETH_P_TEB      0x6558          /* Trans Ether Bridging         */
+
+#endif /* linux kernel < 2.6.28 */
+
+#endif
diff --git a/datapath/linux-2.6/compat-2.6/include/linux/in.h b/datapath/linux-2.6/compat-2.6/include/linux/in.h
new file mode 100644 (file)
index 0000000..2cfe645
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef __LINUX_IN_WRAPPER_H
+#define __LINUX_IN_WRAPPER_H 1
+
+#include_next <linux/in.h>
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
+
+static inline bool ipv4_is_multicast(__be32 addr)
+{
+       return (addr & htonl(0xf0000000)) == htonl(0xe0000000);
+}
+
+#endif /* linux kernel < 2.6.25 */
+
+#endif
diff --git a/datapath/linux-2.6/compat-2.6/include/linux/inetdevice.h b/datapath/linux-2.6/compat-2.6/include/linux/inetdevice.h
new file mode 100644 (file)
index 0000000..813a70a
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef __LINUX_INETDEVICE_WRAPPER_H
+#define __LINUX_INETDEVICE_WRAPPER_H 1
+
+#include_next <linux/inetdevice.h>
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
+
+#define inetdev_by_index(net, ifindex) \
+               inetdev_by_index((ifindex))
+
+#endif /* linux kernel < 2.6.25 */
+
+#endif
index b7182832999dd9da3a44207d72a2c89327ad2fcb..c25f2bd04ae1ea91766c4c846ecc098f34c01b26 100644 (file)
@@ -5,6 +5,7 @@
 
 struct net;
 
+#include <linux/version.h>
 /* Before 2.6.21, struct net_device has a "struct class_device" member named
  * class_dev.  Beginning with 2.6.21, struct net_device instead has a "struct
  * device" member named dev.  Otherwise the usage of these members is pretty
@@ -23,14 +24,36 @@ struct net;
 static inline
 struct net *dev_net(const struct net_device *dev)
 {
+#ifdef CONFIG_NET_NS
+       return dev->nd_net;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)
+       return &init_net;
+#else
        return NULL;
+#endif
+}
+
+static inline
+void dev_net_set(struct net_device *dev, const struct net *net)
+{
+#ifdef CONFIG_NET_NS
+       dev->nd_dev = net;
+#endif
 }
 #endif /* linux kernel < 2.6.26 */
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+#define NETIF_F_NETNS_LOCAL 0
+#endif
+
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
 #define proc_net init_net.proc_net
 #endif
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
+typedef int netdev_tx_t;
+#endif
+
 #ifndef for_each_netdev
 /* Linux before 2.6.22 didn't have for_each_netdev at all. */
 #define for_each_netdev(net, d) for (d = dev_base; d; d = d->next)
index dd9bfa37272d5e0f1eaef9476c683689776447e5..edeba5ae26b334e650ffed79f392fc0b2a19bdaf 100644 (file)
@@ -76,6 +76,29 @@ static inline int skb_cow_head(struct sk_buff *skb, unsigned int headroom)
 }
 #endif  /* !HAVE_SKB_COW */
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
+static inline int skb_clone_writable(struct sk_buff *skb, int len)
+{
+       return false;
+}
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31)
+static inline struct dst_entry *skb_dst(const struct sk_buff *skb)
+{
+       return (struct dst_entry *)skb->dst;
+}
+
+static inline void skb_dst_set(struct sk_buff *skb, struct dst_entry *dst)
+{
+       skb->dst = dst;
+}
+
+static inline struct rtable *skb_rtable(const struct sk_buff *skb)
+{
+       return (struct rtable *)skb->dst;
+}
+#endif
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
 /* Emulate Linux 2.6.17 and later behavior, in which kfree_skb silently ignores 
@@ -101,6 +124,7 @@ static inline void kfree_skb_maybe_null(struct sk_buff *skb)
 #ifdef HAVE_MAC_RAW
 #define mac_header mac.raw
 #define network_header nh.raw
+#define transport_header h.raw
 #endif
 
 #ifndef HAVE_SKBUFF_HEADER_HELPERS
diff --git a/datapath/linux-2.6/compat-2.6/include/net/dst.h b/datapath/linux-2.6/compat-2.6/include/net/dst.h
new file mode 100644 (file)
index 0000000..edb0f75
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef __NET_DST_WRAPPER_H
+#define __NET_DST_WRAPPER_H 1
+
+#include_next <net/dst.h>
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31)
+
+static inline void skb_dst_drop(struct sk_buff *skb)
+{
+       if (skb->dst)
+               dst_release(skb_dst(skb));
+       skb->dst = 0UL;
+}
+
+#endif /* linux kernel < 2.6.31 */
+
+#endif
diff --git a/datapath/linux-2.6/compat-2.6/include/net/ipip.h b/datapath/linux-2.6/compat-2.6/include/net/ipip.h
new file mode 100644 (file)
index 0000000..2eca5f8
--- /dev/null
@@ -0,0 +1,93 @@
+#ifndef __NET_IPIP_WRAPPER_H
+#define __NET_IPIP_WRAPPER_H 1
+
+#include <linux/version.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
+
+#include <linux/if_tunnel.h>
+#include <net/ip.h>
+
+/* Keep error state on tunnel for 30 sec */
+#define IPTUNNEL_ERR_TIMEO     (30*HZ)
+
+struct ip_tunnel
+{
+       struct ip_tunnel        *next;
+       struct net_device       *dev;
+#ifndef HAVE_NETDEV_STATS
+       struct net_device_stats stat;
+#endif
+
+       int                     err_count;      /* Number of arrived ICMP errors */
+       unsigned long           err_time;       /* Time when the last ICMP error arrived */
+
+       /* These four fields used only by GRE */
+       __u32                   i_seqno;        /* The last seen seqno  */
+       __u32                   o_seqno;        /* The last output seqno */
+       int                     hlen;           /* Precalculated GRE header length */
+       int                     mlink;
+
+       struct ip_tunnel_parm   parms;
+
+       struct ip_tunnel_prl_entry      *prl;           /* potential router list */
+       unsigned int                    prl_count;      /* # of entries in PRL */
+};
+
+/* ISATAP: default interval between RS in secondy */
+#define IPTUNNEL_RS_DEFAULT_DELAY      (900)
+
+struct ip_tunnel_prl_entry
+{
+       struct ip_tunnel_prl_entry      *next;
+       __be32                          addr;
+       u16                             flags;
+       unsigned long                   rs_delay;
+       struct timer_list               rs_timer;
+       struct ip_tunnel                *tunnel;
+       spinlock_t                      lock;
+};
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
+#define IPTUNNEL_XMIT() do {                                           \
+       int err;                                                        \
+       int pkt_len = skb->len - skb_transport_offset(skb);             \
+                                                                       \
+       skb->ip_summed = CHECKSUM_NONE;                                 \
+       iph->tot_len = htons(skb->len);                                 \
+       ip_select_ident(iph, &rt->u.dst, NULL);                         \
+       ip_send_check(iph);                                             \
+                                                                       \
+       err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev, dst_output);\
+       if (err == NET_XMIT_SUCCESS || err == NET_XMIT_CN) {            \
+               stats->tx_bytes += pkt_len;                             \
+               stats->tx_packets++;                                    \
+       } else {                                                        \
+               stats->tx_errors++;                                     \
+               stats->tx_aborted_errors++;                             \
+       }                                                               \
+} while (0)
+#else
+#define IPTUNNEL_XMIT() do {                                           \
+       int err;                                                        \
+       int pkt_len = skb->len;                                         \
+                                                                       \
+       skb->ip_summed = CHECKSUM_NONE;                                 \
+       ip_select_ident(iph, &rt->u.dst, NULL);                         \
+                                                                       \
+       err = ip_local_out(skb);                                        \
+       if (net_xmit_eval(err) == 0) {                                  \
+               stats->tx_bytes += pkt_len;                             \
+               stats->tx_packets++;                                    \
+       } else {                                                        \
+               stats->tx_errors++;                                     \
+               stats->tx_aborted_errors++;                             \
+       }                                                               \
+} while (0)
+#endif
+
+#else
+#include_next <net/ipip.h>
+#endif /* kernel < 2.6.32 */
+
+#endif /* net/ipip.h wrapper */
diff --git a/datapath/linux-2.6/compat-2.6/include/net/net_namespace.h b/datapath/linux-2.6/compat-2.6/include/net/net_namespace.h
new file mode 100644 (file)
index 0000000..9b66c91
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef __NET_NAMESPACE_WRAPPER_H
+#define __NET_NAMESPACE_WRAPPER_H 1
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,24)
+#include_next <net/net_namespace.h>
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+struct net;
+
+struct pernet_operations {
+       struct list_head list;
+       int (*init)(struct net *net);
+       void (*exit)(struct net *net);
+};
+#endif /* linux kernel < 2.6.24 */
+
+extern int register_pernet_gen_device(int *id, struct pernet_operations *);
+extern void unregister_pernet_gen_device(int id, struct pernet_operations *);
+
+#endif /* linux kernel < 2.6.26 */
+
+#endif
diff --git a/datapath/linux-2.6/compat-2.6/include/net/netns/generic.h b/datapath/linux-2.6/compat-2.6/include/net/netns/generic.h
new file mode 100644 (file)
index 0000000..f70bc87
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef __NET_NETNS_GENERIC_WRAPPER_H
+#define __NET_NETNS_GENERIC_WRAPPER_H 1
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
+
+struct net;
+
+extern void *net_generic(struct net *net, int id);
+extern int net_assign_generic(struct net *net, int id, void *data);
+
+#else
+#include_next <net/netns/generic.h>
+#endif /* linux kernel < 2.6.26 */
+
+#endif
diff --git a/datapath/linux-2.6/compat-2.6/include/net/route.h b/datapath/linux-2.6/compat-2.6/include/net/route.h
new file mode 100644 (file)
index 0000000..867f407
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef __NET_ROUTE_WRAPPER_H
+#define __NET_ROUTE_WRAPPER_H 1
+
+#include_next <net/route.h>
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
+
+#define ip_route_output_key(net, rp, flp) \
+               ip_route_output_key((rp), (flp))
+
+#endif /* linux kernel < 2.6.25 */
+
+#endif
diff --git a/datapath/linux-2.6/compat-2.6/net_namespace-ip_gre.c b/datapath/linux-2.6/compat-2.6/net_namespace-ip_gre.c
new file mode 100644 (file)
index 0000000..323b644
--- /dev/null
@@ -0,0 +1,49 @@
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
+
+#include <linux/sched.h>
+#include <net/net_namespace.h>
+#include <net/netns/generic.h>
+
+/* This trivial implementation assumes that there is only a single pernet
+ * generic device registered and that the caller is well behaved.  It only
+ * weakly attempts to check that these conditions are true. */
+
+static bool device_registered;
+static void *ng_data;
+
+int register_pernet_gen_device(int *id, struct pernet_operations *ops)
+{
+       BUG_ON(device_registered);
+
+       *id = 1;
+       device_registered = true;
+
+       if (ops->init == NULL)
+               return 0;
+       return ops->init(NULL);
+}
+
+void unregister_pernet_gen_device(int id, struct pernet_operations *ops)
+{
+       device_registered = false;
+       if (ops->exit)
+               ops->exit(NULL);
+}
+
+int net_assign_generic(struct net *net, int id, void *data)
+{
+       BUG_ON(id != 1);
+
+       ng_data = data;
+       return 0;
+}
+
+void *net_generic(struct net *net, int id)
+{
+       BUG_ON(id != 1);
+
+       return ng_data;
+}
+
+#endif /* kernel < 2.6.26 */