From 82ff0d0a931ddc610c366551a948ffb33e9c8008 Mon Sep 17 00:00:00 2001 From: Jesse Gross Date: Thu, 18 Feb 2010 11:43:29 -0500 Subject: [PATCH] gre: Add functions to determine address type to compat layer. 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 + .../compat-2.6/addrconf_core-ip_gre.c | 82 +++++++++++++++++++ .../linux-2.6/compat-2.6/include/linux/in.h | 21 +++++ 3 files changed, 104 insertions(+) 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 820d09b6..70931d86 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 00000000..b5a75740 --- /dev/null +++ b/datapath/linux-2.6/compat-2.6/addrconf_core-ip_gre.c @@ -0,0 +1,82 @@ +#include +#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 + +#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 fd5c3c67..f91a832a 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,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 -- 2.30.2