[ovs-dev] [PATCH 6/8] gre: Add functions to determine address type to compat layer.

Jesse Gross jesse at nicira.com
Thu Mar 4 18:22:11 UTC 2010


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                      |    1 +
 .../linux-2.6/compat-2.6/addrconf_core-ip_gre.c    |   82 ++++++++++++++++++++
 datapath/linux-2.6/compat-2.6/include/linux/in.h   |   29 +++++++
 3 files changed, 112 insertions(+), 0 deletions(-)
 create mode 100644 datapath/linux-2.6/compat-2.6/addrconf_core-ip_gre.c

diff --git a/datapath/linux-2.6/Modules.mk b/datapath/linux-2.6/Modules.mk
index 820d09b..70931d8 100644
--- a/datapath/linux-2.6/Modules.mk
+++ b/datapath/linux-2.6/Modules.mk
@@ -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
index 0000000..b5a7574
--- /dev/null
+++ b/datapath/linux-2.6/compat-2.6/addrconf_core-ip_gre.c
@@ -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 */
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
index fd5c3c6..07c26b1 100644
--- a/datapath/linux-2.6/compat-2.6/include/linux/in.h
+++ b/datapath/linux-2.6/compat-2.6/include/linux/in.h
@@ -5,11 +5,40 @@
 
 #ifndef HAVE_IPV4_IS_MULTICAST
 
+#ifndef INADDR_BROADCAST
+#define INADDR_BROADCAST        ((unsigned long int) 0xffffffff)
+#endif
+
+#ifdef __KERNEL__
+
+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 /* __KERNEL__ */
+
 #endif /* !HAVE_IPV4_IS_MULTICAST */
 
 #endif
-- 
1.6.3.3





More information about the dev mailing list