Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ipv6: optimize ipv6 addresses compares

On 64 bit arches having efficient unaligned accesses (eg x86_64) we can
use long words to reduce number of instructions for free.

Joe Perches suggested to change ipv6_masked_addr_cmp() to return a bool
instead of 'int', to make sure ipv6_masked_addr_cmp() cannot be used
in a sorting function.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Joe Perches <joe@perches.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Eric Dumazet and committed by
David S. Miller
1a203cb3 1aa8b471

+23 -1
+23 -1
include/net/ipv6.h
··· 298 298 return memcmp(a1, a2, sizeof(struct in6_addr)); 299 299 } 300 300 301 - static inline int 301 + static inline bool 302 302 ipv6_masked_addr_cmp(const struct in6_addr *a1, const struct in6_addr *m, 303 303 const struct in6_addr *a2) 304 304 { 305 + #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 306 + const unsigned long *ul1 = (const unsigned long *)a1; 307 + const unsigned long *ulm = (const unsigned long *)m; 308 + const unsigned long *ul2 = (const unsigned long *)a2; 309 + 310 + return !!(((ul1[0] ^ ul2[0]) & ulm[0]) | 311 + ((ul1[1] ^ ul2[1]) & ulm[1])); 312 + #else 305 313 return !!(((a1->s6_addr32[0] ^ a2->s6_addr32[0]) & m->s6_addr32[0]) | 306 314 ((a1->s6_addr32[1] ^ a2->s6_addr32[1]) & m->s6_addr32[1]) | 307 315 ((a1->s6_addr32[2] ^ a2->s6_addr32[2]) & m->s6_addr32[2]) | 308 316 ((a1->s6_addr32[3] ^ a2->s6_addr32[3]) & m->s6_addr32[3])); 317 + #endif 309 318 } 310 319 311 320 static inline void ipv6_addr_prefix(struct in6_addr *pfx, ··· 344 335 static inline bool ipv6_addr_equal(const struct in6_addr *a1, 345 336 const struct in6_addr *a2) 346 337 { 338 + #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 339 + const unsigned long *ul1 = (const unsigned long *)a1; 340 + const unsigned long *ul2 = (const unsigned long *)a2; 341 + 342 + return ((ul1[0] ^ ul2[0]) | (ul1[1] ^ ul2[1])) == 0UL; 343 + #else 347 344 return ((a1->s6_addr32[0] ^ a2->s6_addr32[0]) | 348 345 (a1->s6_addr32[1] ^ a2->s6_addr32[1]) | 349 346 (a1->s6_addr32[2] ^ a2->s6_addr32[2]) | 350 347 (a1->s6_addr32[3] ^ a2->s6_addr32[3])) == 0; 348 + #endif 351 349 } 352 350 353 351 static inline bool __ipv6_prefix_equal(const __be32 *a1, const __be32 *a2, ··· 407 391 408 392 static inline bool ipv6_addr_any(const struct in6_addr *a) 409 393 { 394 + #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 395 + const unsigned long *ul = (const unsigned long *)a; 396 + 397 + return (ul[0] | ul[1]) == 0UL; 398 + #else 410 399 return (a->s6_addr32[0] | a->s6_addr32[1] | 411 400 a->s6_addr32[2] | a->s6_addr32[3]) == 0; 401 + #endif 412 402 } 413 403 414 404 static inline bool ipv6_addr_loopback(const struct in6_addr *a)