Bug 176173 - The hash.h hash_long function, when used on a 64 bit machine, ignores many of the middle-order bits.
The hash.h hash_long function, when used on a 64 bit machine, ignores many o...
Status: CLOSED ERRATA
Product: Red Hat Enterprise Linux 4
Classification: Red Hat
Component: kernel (Show other bugs)
4.0
ia64 Linux
medium Severity medium
: ---
: ---
Assigned To: Steve Dickson
Brian Brock
:
Depends On:
Blocks: 181409
  Show dependency treegraph
 
Reported: 2005-12-19 15:12 EST by John Shakshober
Modified: 2007-11-30 17:07 EST (History)
1 user (show)

See Also:
Fixed In Version: RHSA-2006-0575
Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of:
Environment:
Last Closed: 2006-08-10 17:46:28 EDT
Type: ---
Regression: ---
Mount Type: ---
Documentation: ---
CRM:
Verified Versions:
Category: ---
oVirt Team: ---
RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: ---


Attachments (Terms of Use)

  None (edit)
Description John Shakshober 2005-12-19 15:12:20 EST
Description of problem:

(Input from Partner HP - Eric Whitney (eric.whitney@hp.com)
In the svcauth code there are places that do:

       hash_long((unsigned long)item->m_addr.s_addr, IP_HASHBITS);

That seems reasonable, but then again...maybe not....

I believe that s_addr is an IP address in Network Neutral format (Big Endian)

When one is on a Little Endian system, the hash_long
function gets handed a Big Endian value as a long, and
later, via the magic of being a Little Endian system,
gets byte swapped.

Version-Release number of selected component (if applicable):
 RHEL4 U2 IPF 2.6.9-22.ELsmp

How reproducible:
 Every time

Steps to Reproduce:
1. 192.168.1.2 becomes 2.1.168.192 (byte swap)
2. The 32 bit IP address becomes a 64 bit long when
                 this code is compiled and run on an Opteron, or
                 an IA-64 system.
                 2.1.168.192 -> 0.0.0.0.2.1.168.192
3. Call the hash_long() and get back a hash value
                that is IP_HASHBITS (8) in size.

Actual results:

You'll notice that the hash distribution is not nearly as
    good as one might believe.  If one would have done:

        hash_long( inet_lnaof(item->m_addr.s_addr)),IP_HASHBITS)


The hash_long function would have done a nice job.  Since
one is not converting the network neutral IP address into a
host binary format.  

Expected results:

With the patch below, we the hash can work better in either direction.
Not the only fix, just one suggestion.


Additional info: (one proposed patch is included)

Thanks to "Iozone" < capps@iozone.org> for identifying this problem.
Signed-off-by: Neil Brown < neilb@suse.de>

### Diffstat output
 ./net/sunrpc/svcauth_unix.c |   14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff ./net/sunrpc/svcauth_unix.c~current~ ./net/sunrpc/svcauth_unix.c
--- ./net/sunrpc/svcauth_unix.c~current~ 2005-12-16 15:10:12.000000000 +1100
+++ ./net/sunrpc/svcauth_unix.c 2005-12-16 15:12:00.000000000 +1100
@@ -101,10 +101,22 @@ static void ip_map_put(struct cache_head
  }
 }
 
+#if IP_HASHBITS == 8
+/* hash_long on a 64 bit machine is currently REALLY BAD for
+ * IP addresses in reverse-endian (i.e. on a little-endian machine).
+ * So use a trivial but reliable hash instead
+ */
+static inline int hash_ip(unsigned long ip)
+{
+ int hash = ip ^ (ip>>16);
+ return (hash ^ (hash>>8)) & 0xff;
+}
+#endif
+
 static inline int ip_map_hash(struct ip_map *item)
 {
  return hash_str(item->m_class, IP_HASHBITS) ^ 
- hash_long((unsigned long)item->m_addr.s_addr, IP_HASHBITS);
+ hash_ip((unsigned long)item->m_addr.s_addr);
 }
 static inline int ip_map_match(struct ip_map *item, struct ip_map *tmp)
 {
Comment 3 Jason Baron 2006-03-19 13:45:02 EST
committed in stream u4 build 34.5. A test kernel with this patch is available
from http://people.redhat.com/~jbaron/rhel4/
Comment 7 Red Hat Bugzilla 2006-08-10 17:46:29 EDT
An advisory has been issued which should help the problem
described in this bug report. This report is therefore being
closed with a resolution of ERRATA. For more information
on the solution and/or where to find the updated files,
please follow the link below. You may reopen this bug report
if the solution does not work for you.

http://rhn.redhat.com/errata/RHSA-2006-0575.html

Note You need to log in before you can comment on or make changes to this bug.