Bug 176173 - The hash.h hash_long function, when used on a 64 bit machine, ignores many of the middle-order bits.
Summary: The hash.h hash_long function, when used on a 64 bit machine, ignores many o...
Keywords:
Status: CLOSED ERRATA
Alias: None
Product: Red Hat Enterprise Linux 4
Classification: Red Hat
Component: kernel
Version: 4.0
Hardware: ia64
OS: Linux
medium
medium
Target Milestone: ---
: ---
Assignee: Steve Dickson
QA Contact: Brian Brock
URL:
Whiteboard:
Depends On:
Blocks: 181409
TreeView+ depends on / blocked
 
Reported: 2005-12-19 20:12 UTC by John Shakshober
Modified: 2019-10-30 20:37 UTC (History)
1 user (show)

Fixed In Version: RHSA-2006-0575
Doc Type: Bug Fix
Doc Text:
Clone Of:
Environment:
Last Closed: 2006-08-10 21:46:28 UTC
Target Upstream Version:
Embargoed:


Attachments (Terms of Use)


Links
System ID Private Priority Status Summary Last Updated
Red Hat Product Errata RHSA-2006:0575 0 normal SHIPPED_LIVE Important: Updated kernel packages available for Red Hat Enterprise Linux 4 Update 4 2006-08-10 04:00:00 UTC

Description John Shakshober 2005-12-19 20:12:20 UTC
Description of problem:

(Input from Partner HP - Eric Whitney (eric.whitney)
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> for identifying this problem.
Signed-off-by: Neil Brown < neilb>

### 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 18:45:02 UTC
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 21:46:29 UTC
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.