gre: Add functions to determine address type to compat layer.
authorJesse Gross <jesse@nicira.com>
Thu, 18 Feb 2010 16:43:29 +0000 (11:43 -0500)
committerJesse Gross <jesse@nicira.com>
Fri, 5 Mar 2010 21:31:27 +0000 (16:31 -0500)
Allows older kernels to classify IPv4/IPv6 addresses as loopback,
broadcast, etc.  The IPv6 functions actually exist in all supported
kernels but add a dependency on the IPv6 code on older kernels (they
are always available on more recent kernels).  This allows us to
process IPv6 packets without dragging in the entire IPv6 subsystem
if it is compiled as a module (such as on Xen).  This is only done
for packets that are passing through the system and does not use
the IPv6 core if it is not configured.

datapath/linux-2.6/Modules.mk
datapath/linux-2.6/compat-2.6/addrconf_core-ip_gre.c [new file with mode: 0644]
datapath/linux-2.6/compat-2.6/include/linux/in.h

index 820d09b65b53e7cd8e55a19e904e86002d5ee0ce..70931d862d0be5e83fb0c6507eeb2edf045defbb 100644 (file)
@@ -53,6 +53,7 @@ veth_headers =
 dist_modules += ip_gre
 build_modules += $(if $(BUILD_GRE),ip_gre)
 ip_gre_sources = \
+       linux-2.6/compat-2.6/addrconf_core-ip_gre.c \
        linux-2.6/compat-2.6/dev-ip_gre.c \
        linux-2.6/compat-2.6/ip_gre.c \
        linux-2.6/compat-2.6/ip_output-ip_gre.c \
diff --git a/datapath/linux-2.6/compat-2.6/addrconf_core-ip_gre.c b/datapath/linux-2.6/compat-2.6/addrconf_core-ip_gre.c
new file mode 100644 (file)
index 0000000..b5a7574
--- /dev/null
@@ -0,0 +1,82 @@
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)
+
+/*
+ * IPv6 library code, needed by static components when full IPv6 support is
+ * not configured or static.
+ */
+
+#include <net/ipv6.h>
+
+#define IPV6_ADDR_SCOPE_TYPE(scope)    ((scope) << 16)
+
+static inline unsigned ipv6_addr_scope2type(unsigned scope)
+{
+       switch(scope) {
+       case IPV6_ADDR_SCOPE_NODELOCAL:
+               return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_NODELOCAL) |
+                       IPV6_ADDR_LOOPBACK);
+       case IPV6_ADDR_SCOPE_LINKLOCAL:
+               return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL) |
+                       IPV6_ADDR_LINKLOCAL);
+       case IPV6_ADDR_SCOPE_SITELOCAL:
+               return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL) |
+                       IPV6_ADDR_SITELOCAL);
+       }
+       return IPV6_ADDR_SCOPE_TYPE(scope);
+}
+
+int __ipv6_addr_type(const struct in6_addr *addr)
+{
+       __be32 st;
+
+       st = addr->s6_addr32[0];
+
+       /* Consider all addresses with the first three bits different of
+          000 and 111 as unicasts.
+        */
+       if ((st & htonl(0xE0000000)) != htonl(0x00000000) &&
+           (st & htonl(0xE0000000)) != htonl(0xE0000000))
+               return (IPV6_ADDR_UNICAST |
+                       IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));
+
+       if ((st & htonl(0xFF000000)) == htonl(0xFF000000)) {
+               /* multicast */
+               /* addr-select 3.1 */
+               return (IPV6_ADDR_MULTICAST |
+                       ipv6_addr_scope2type(IPV6_ADDR_MC_SCOPE(addr)));
+       }
+
+       if ((st & htonl(0xFFC00000)) == htonl(0xFE800000))
+               return (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_UNICAST |
+                       IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL));               /* addr-select 3.1 */
+       if ((st & htonl(0xFFC00000)) == htonl(0xFEC00000))
+               return (IPV6_ADDR_SITELOCAL | IPV6_ADDR_UNICAST |
+                       IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL));               /* addr-select 3.1 */
+       if ((st & htonl(0xFE000000)) == htonl(0xFC000000))
+               return (IPV6_ADDR_UNICAST |
+                       IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));                  /* RFC 4193 */
+
+       if ((addr->s6_addr32[0] | addr->s6_addr32[1]) == 0) {
+               if (addr->s6_addr32[2] == 0) {
+                       if (addr->s6_addr32[3] == 0)
+                               return IPV6_ADDR_ANY;
+
+                       if (addr->s6_addr32[3] == htonl(0x00000001))
+                               return (IPV6_ADDR_LOOPBACK | IPV6_ADDR_UNICAST |
+                                       IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL));       /* addr-select 3.4 */
+
+                       return (IPV6_ADDR_COMPATv4 | IPV6_ADDR_UNICAST |
+                               IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));  /* addr-select 3.3 */
+               }
+
+               if (addr->s6_addr32[2] == htonl(0x0000ffff))
+                       return (IPV6_ADDR_MAPPED |
+                               IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));  /* addr-select 3.3 */
+       }
+
+       return (IPV6_ADDR_RESERVED |
+               IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));  /* addr-select 3.4 */
+}
+
+#endif /* kernel < 2.6.21 */
index fd5c3c67369a14d695903dd4729b1a8544818533..f91a832a7f1742f534f13daaf64cf237114f0474 100644 (file)
@@ -5,11 +5,32 @@
 
 #ifndef HAVE_IPV4_IS_MULTICAST
 
+static inline bool ipv4_is_loopback(__be32 addr)
+{
+       return (addr & htonl(0xff000000)) == htonl(0x7f000000);
+}
+
 static inline bool ipv4_is_multicast(__be32 addr)
 {
        return (addr & htonl(0xf0000000)) == htonl(0xe0000000);
 }
 
+static inline bool ipv4_is_local_multicast(__be32 addr)
+{
+       return (addr & htonl(0xffffff00)) == htonl(0xe0000000);
+}
+
+static inline bool ipv4_is_lbcast(__be32 addr)
+{
+       /* limited broadcast */
+       return addr == htonl(INADDR_BROADCAST);
+}
+
+static inline bool ipv4_is_zeronet(__be32 addr)
+{
+       return (addr & htonl(0xff000000)) == htonl(0x00000000);
+}
+
 #endif /* !HAVE_IPV4_IS_MULTICAST */
 
 #endif