lib: Better hashing of string values using Bernstein hash

* hash.{h,c}: (string_hash_make) Hash optimised for strings, current
  implementation using Bernstein hash, which offers a good compromise
  between distribution and performance.
* distribute.c: (distribute_hash_make) use previous instead of additive
  string hash.
* if_rmap.c: (if_rmap_hash_make) ditto
diff --git a/lib/distribute.c b/lib/distribute.c
index 242a225..420849d 100644
--- a/lib/distribute.c
+++ b/lib/distribute.c
@@ -114,16 +114,11 @@
 }
 
 static unsigned int
-distribute_hash_make (struct distribute *dist)
+distribute_hash_make (void *arg)
 {
-  unsigned int i, key;
+  const struct distribute *dist = arg;
 
-  key = 0;
-  if (dist->ifname)
-    for (i = 0; i < strlen (dist->ifname); i++)
-      key += dist->ifname[i];
-
-  return key;
+  return dist->ifname ? string_hash_make (dist->ifname) : 0;
 }
 
 /* If two distribute-list have same value then return 1 else return
@@ -763,7 +758,7 @@
 void
 distribute_list_init (int node)
 {
-  disthash = hash_create ((unsigned int (*) (void *)) distribute_hash_make,
+  disthash = hash_create (distribute_hash_make,
                           (int (*) (const void *, const void *)) distribute_cmp);
 
   if(node==RIP_NODE) {
diff --git a/lib/hash.c b/lib/hash.c
index 672327e..6db79ea 100644
--- a/lib/hash.c
+++ b/lib/hash.c
@@ -101,6 +101,17 @@
   return hash_get (hash, data, NULL);
 }
 
+/* Simple Bernstein hash which is simple and fast for common case */
+unsigned int string_hash_make (const char *str)
+{
+  unsigned int hash = 0;
+
+  while (*str)
+    hash = (hash * 33) ^ (unsigned int) *str++;
+
+  return hash;
+}
+
 /* This function release registered value from specified hash.  When
    release is successfully finished, return the data pointer in the
    hash backet.  */
diff --git a/lib/hash.h b/lib/hash.h
index f4b1c23..4cb772e 100644
--- a/lib/hash.h
+++ b/lib/hash.h
@@ -70,4 +70,6 @@
 extern void hash_clean (struct hash *, void (*) (void *));
 extern void hash_free (struct hash *);
 
+extern unsigned int string_hash_make (const char *);
+
 #endif /* _ZEBRA_HASH_H */
diff --git a/lib/if_rmap.c b/lib/if_rmap.c
index ddc62fd..9774be4 100644
--- a/lib/if_rmap.c
+++ b/lib/if_rmap.c
@@ -109,14 +109,9 @@
 static unsigned int
 if_rmap_hash_make (void *data)
 {
-  struct if_rmap *if_rmap = data;
-  unsigned int i, key;
+  const struct if_rmap *if_rmap = data;
 
-  key = 0;
-  for (i = 0; i < strlen (if_rmap->ifname); i++)
-    key += if_rmap->ifname[i];
-
-  return key;
+  return string_hash_make (if_rmap->ifname);
 }
 
 static int