diff -Nur olsrd-0.4.10.orig/src/duplicate_set.c olsrd-0.4.10/src/duplicate_set.c
--- olsrd-0.4.10.orig/src/duplicate_set.c	2005-02-27 19:39:43.000000000 +0100
+++ olsrd-0.4.10/src/duplicate_set.c	2006-11-12 09:33:49.000000000 +0100
@@ -93,7 +93,7 @@
 
 
   /* Hash the senders address */
-  hash = olsr_hashing(originator);
+  hash = HASHMASK & seqno;
 
   new_dup_entry = olsr_malloc(sizeof(struct dup_entry), "New dup entry");
 
@@ -131,7 +131,7 @@
   struct dup_entry *tmp_dup_table;
 
   /* Hash the senders address */
-  hash = olsr_hashing(originator);
+  hash = HASHMASK & seqno;
 
   /* Check for entry */
   for(tmp_dup_table = dup_set[hash].next;
@@ -163,7 +163,7 @@
   struct dup_entry *tmp_dup_table;
 
   /* Hash the senders address */
-  hash = olsr_hashing(originator);
+  hash = HASHMASK & seqno;
 
   /* Check for entry */
   for(tmp_dup_table = dup_set[hash].next;
@@ -268,7 +268,7 @@
   struct dup_iface *new_iface;
 
   /* Hash the senders address */
-  hash = olsr_hashing(originator);
+  hash = HASHMASK & seqno;
 
 
   /* Check for entry */
@@ -313,7 +313,7 @@
   struct dup_entry *tmp_dup_table;
 
   /* Hash the senders address */
-  hash = olsr_hashing(originator);
+  hash = HASHMASK & seqno;
 
   /* Check for entry */
   for(tmp_dup_table = dup_set[hash].next;
diff -Nur olsrd-0.4.10.orig/src/hashing.c olsrd-0.4.10/src/hashing.c
--- olsrd-0.4.10.orig/src/hashing.c	2005-02-20 19:52:18.000000000 +0100
+++ olsrd-0.4.10/src/hashing.c	2006-11-12 09:33:49.000000000 +0100
@@ -58,7 +58,7 @@
 
   if(olsr_cnf->ip_version == AF_INET)
     /* IPv4 */  
-    hash = (ntohl(address->v4));
+    hash = address->v4x[0] ^ address->v4x[1] ^ address->v4x[2] ^ address->v4x[3];
   else
     {
       /* IPv6 */
diff -Nur olsrd-0.4.10.orig/src/hashing.h olsrd-0.4.10/src/hashing.h
--- olsrd-0.4.10.orig/src/hashing.h	2005-02-20 19:52:18.000000000 +0100
+++ olsrd-0.4.10/src/hashing.h	2006-11-12 09:33:49.000000000 +0100
@@ -43,7 +43,7 @@
 #ifndef _OLSR_HASHING
 #define _OLSR_HASHING
 
-#define	HASHSIZE	32
+#define	HASHSIZE	128
 #define	HASHMASK	(HASHSIZE - 1)
 
 #include "olsr_types.h"
diff -Nur olsrd-0.4.10.orig/src/lq_avl.c olsrd-0.4.10/src/lq_avl.c
--- olsrd-0.4.10.orig/src/lq_avl.c	2005-01-22 15:30:57.000000000 +0100
+++ olsrd-0.4.10/src/lq_avl.c	2006-11-12 09:33:49.000000000 +0100
@@ -40,6 +40,9 @@
  */
 
 #include <stddef.h>
+#ifndef DISABLE_SVEN_OLA
+#include <time.h>
+#endif
 
 #include "lq_avl.h"
 
@@ -52,11 +55,33 @@
   tree->comp = comp;
 }
 
+#ifndef DISABLE_SVEN_OLA
+static struct avl_node *avl_find_rec_ipv4(struct avl_node *node, void *key)
+{
+  if (*(unsigned int *)key < *(unsigned int *)node->key) {
+    if (node->left != NULL) {
+      return avl_find_rec_ipv4(node->left, key);
+    }
+  }
+  else if (*(unsigned int *)key > *(unsigned int *)node->key) {
+    if (node->right != NULL) {
+      return avl_find_rec_ipv4(node->right, key);
+    }
+  }
+  return node;
+}
+#endif
+
 static struct avl_node *avl_find_rec(struct avl_node *node, void *key,
                                      int (*comp)(void *, void *))
 {
   int diff;
 
+#ifndef DISABLE_SVEN_OLA
+  if (0 == comp) {
+    return avl_find_rec_ipv4(node, key);
+  }
+#endif
   diff = (*comp)(key, node->key);
 
   if (diff < 0)
@@ -87,6 +112,13 @@
 
   node = avl_find_rec(tree->root, key, tree->comp);
 
+#ifndef DISABLE_SVEN_OLA
+  if (0 == tree->comp) {
+    if (0 != svenola_avl_comp_ipv4(node->key, key))
+      return NULL;
+  }
+  else
+#endif
   if ((*tree->comp)(node->key, key) != 0)
     return NULL;
 
@@ -228,6 +260,12 @@
 
   node = avl_find_rec(tree->root, new->key, tree->comp);
 
+#ifndef DISABLE_SVEN_OLA
+  if (0 == tree->comp) {
+    diff = svenola_avl_comp_ipv4(new->key, node->key);
+  }
+  else
+#endif
   diff = (*tree->comp)(new->key, node->key);
 
   if (diff == 0)
diff -Nur olsrd-0.4.10.orig/src/lq_avl.h olsrd-0.4.10/src/lq_avl.h
--- olsrd-0.4.10.orig/src/lq_avl.h	2005-02-20 19:52:18.000000000 +0100
+++ olsrd-0.4.10/src/lq_avl.h	2006-11-12 09:33:49.000000000 +0100
@@ -62,4 +62,9 @@
 struct avl_node *avl_find(struct avl_tree *, void *);
 int avl_insert(struct avl_tree *, struct avl_node *);
 
+#ifndef DISABLE_SVEN_OLA
+#define svenola_avl_comp_ipv4(ip1, ip2) \
+  (*(unsigned int *)ip1 == *(unsigned int *)ip2 ? 0 : \
+  *(unsigned int *)ip1 < *(unsigned int *)ip2 ? -1 : +1)
+#endif
 #endif
diff -Nur olsrd-0.4.10.orig/src/lq_list.c olsrd-0.4.10/src/lq_list.c
--- olsrd-0.4.10.orig/src/lq_list.c	2004-12-04 18:06:57.000000000 +0100
+++ olsrd-0.4.10/src/lq_list.c	2006-11-12 09:33:49.000000000 +0100
@@ -48,6 +48,7 @@
   list->tail = NULL;
 }
 
+#ifdef DISABLE_SVEN_OLA
 struct list_node *list_get_head(struct list *list)
 {
   return list->head;
@@ -67,6 +68,7 @@
 {
   return node->prev;
 }
+#endif
 
 void list_add_head(struct list *list, struct list_node *node)
 {
diff -Nur olsrd-0.4.10.orig/src/lq_list.h olsrd-0.4.10/src/lq_list.h
--- olsrd-0.4.10.orig/src/lq_list.h	2005-02-20 19:52:18.000000000 +0100
+++ olsrd-0.4.10/src/lq_list.h	2006-11-12 09:33:49.000000000 +0100
@@ -58,11 +58,18 @@
 
 void list_init(struct list *list);
 
+#ifndef DISABLE_SVEN_OLA
+#define list_get_head(node) (node)->head
+#define list_get_tail(node) (node)->tail
+#define list_get_next(node) (node)->next
+#define list_get_prev(node) (node)->prev
+#else
 struct list_node *list_get_head(struct list *list);
 struct list_node *list_get_tail(struct list *list);
 
 struct list_node *list_get_next(struct list_node *node);
 struct list_node *list_get_prev(struct list_node *node);
+#endif
 
 void list_add_head(struct list *list, struct list_node *node);
 void list_add_tail(struct list *list, struct list_node *node);
diff -Nur olsrd-0.4.10.orig/src/lq_route.c olsrd-0.4.10/src/lq_route.c
--- olsrd-0.4.10.orig/src/lq_route.c	2005-11-29 19:37:58.000000000 +0100
+++ olsrd-0.4.10/src/lq_route.c	2006-11-12 09:34:46.000000000 +0100
@@ -205,6 +205,16 @@
 
   // add the vertex to the list, if it's not us
 
+#ifndef DISABLE_SVEN_OLA
+  if (0 == comp) {
+    if (svenola_avl_comp_ipv4(&main_addr, node->key) != 0)
+    {
+      vert->node.data = vert;
+      list_add_tail(vertex_list, &vert->node);
+    }
+  }
+  else
+#endif
   if ((*comp)(&main_addr, node->key) != 0)
   {
     vert->node.data = vert;
@@ -266,6 +276,154 @@
 }
 
 // XXX - bad complexity
+#define SVEN_OPT
+#undef SVEN_OPT_DBG
+
+/*
+ * The function extract_best() is most expensive (>50% CPU in profiling).
+ * It is called in two modes: while doing Dijkstra route calculation and
+ * while searching for a direct route/hna. The latter can be optimized
+ * because the stored verices do not change from call to call and it is
+ * more sufficient to have them sorted/popped from a list rather than 
+ * searching the complete list by every call. Sven-Ola@gmx.de, 11/2006
+ */
+ 
+#ifdef SVEN_OPT
+static struct dijk_vertex **etx_cache = 0;
+static int etx_cache_count;
+static int etx_cache_get;
+static int etx_cache_saved = 0;
+
+static int etx_cache_compare(const void *a, const void *b)
+{
+  // Oh jeah. I love this macro assembler :)
+  
+  if ((*(struct dijk_vertex **)a)->path_etx > (*(struct dijk_vertex **)b)->path_etx) return 1;
+  if ((*(struct dijk_vertex **)a)->path_etx < (*(struct dijk_vertex **)b)->path_etx) return -1;
+  
+  // This is for debugging only: etx==etx then compare pointers
+  // to make it possible to compare to the original search algo.
+  if (*(struct dijk_vertex **)a > *(struct dijk_vertex **)b) return 1;
+  if (*(struct dijk_vertex **)a < *(struct dijk_vertex **)b) return -1;
+  
+  return 0;
+}
+
+static struct dijk_vertex *extract_best_route(struct list *vertex_list)
+{
+#ifdef SVEN_OPT_DBG
+  float best_etx = INFINITE_ETX + 1.0;
+#endif
+  struct list_node *node;
+  struct dijk_vertex *vert;
+  struct dijk_vertex *res = NULL;
+
+#ifdef SVEN_OPT_DBG
+  node = list_get_head(vertex_list);
+
+  // loop through all vertices
+  
+  while (node != NULL)
+  {
+    vert = node->data;
+
+    // see whether the current vertex is better than what we have
+
+    if (!vert->done && vert->path_etx < best_etx)
+    {
+      best_etx = vert->path_etx;
+      res = vert;
+    }
+    else if (!vert->done && vert->path_etx == best_etx && vert < res)
+    {
+      // Otherwise order is undefined if etx==etx and debug will complain
+      best_etx = vert->path_etx;
+      res = vert;
+    }
+
+    node = list_get_next(node);
+  }
+#endif
+  if (NULL == etx_cache)
+  {
+    int count = 0;
+    node = list_get_head(vertex_list);
+    while (node != NULL)
+    {
+      vert = node->data;
+      if (!vert->done && vert->path_etx < INFINITE_ETX) count++;
+      node = list_get_next(node);
+    }
+    if (0 < count)
+    {
+      etx_cache = olsr_malloc(sizeof(etx_cache[0]) * count, "ETX Cache");
+#ifdef SVEN_OPT_DBG
+      printf("count=%d, Malloc(%d)=%p\n", count, sizeof(etx_cache[0]) * count, etx_cache);
+#endif
+      node = list_get_head(vertex_list);
+      etx_cache_count = 0;
+      etx_cache_get = 0;
+      while (node != NULL)
+      {
+        vert = node->data;
+        if (!vert->done && vert->path_etx < INFINITE_ETX)
+        {
+          etx_cache[etx_cache_count] = vert;
+          etx_cache_count++;
+        }
+        node = list_get_next(node);
+      }
+#ifdef SVEN_OPT_DBG
+      printf("qsort(etx_cache_count=%d)\n", etx_cache_count);
+#endif
+      qsort(etx_cache, etx_cache_count, sizeof(etx_cache[0]), etx_cache_compare);
+#ifdef SVEN_OPT_DBG
+      if (0 < etx_cache_count)
+      {
+        int i = 0; 
+        while(i < etx_cache_count && i < 10)
+        {
+          printf("%d: %p=%f\n", i, etx_cache[i], etx_cache[i]->path_etx);
+          i++;
+        }
+      }
+#endif
+    }
+  }
+
+#ifdef SVEN_OPT_DBG
+  if (NULL != etx_cache)
+  {
+    struct dijk_vertex *rescache = NULL;
+    if (etx_cache_get < etx_cache_count)
+    {
+      rescache = etx_cache[etx_cache_get++];
+    }
+    if (res != rescache)
+    {
+      printf("miss: etx_cache_get=%d, res=%p,%f != rescache=%p,%f\n",
+        etx_cache_get, res, (NULL != res ? res->path_etx : -1), rescache, (NULL != rescache ? rescache->path_etx : -1));
+    }
+    else
+    {
+      etx_cache_saved++;
+    }
+  }
+#else
+  if (NULL != etx_cache && etx_cache_get < etx_cache_count)
+  {
+    res = etx_cache[etx_cache_get++];
+  }
+#endif
+
+  // if we've found a vertex, remove it from the set
+
+  if (res != NULL)
+    res->done = OLSR_TRUE;
+
+  return res;
+}
+#endif // SVEN_OPT
 
 static struct dijk_vertex *extract_best(struct list *vertex_list)
 {
@@ -371,7 +529,11 @@
   struct interface *inter;
 
   if (ipsize == 4)
+#ifndef DISABLE_SVEN_OLA
+    avl_comp = 0;
+#else
     avl_comp = avl_comp_ipv4;
+#endif
 
   else
     avl_comp = avl_comp_ipv6;
@@ -614,13 +776,27 @@
 
   // add HNA routes - the set of unprocessed network nodes contains
   // all reachable network nodes
+#ifdef SVEN_OPT
+#ifdef SVEN_OPT_DBG
+  printf("free etx_cache, saved compares=%d, etx_cache=%p\n", etx_cache_saved, etx_cache);
+  etx_cache_saved = 0;
+#endif
+  if (NULL != etx_cache) {
+    free(etx_cache);
+    etx_cache = NULL;
+  }
+#endif
 
   for (;;)
   {
     // extract the network node with the best ETX and remove it
     // from the set of unprocessed network nodes
 
+#ifdef SVEN_OPT
+    vert = extract_best_route(&vertex_list);
+#else
     vert = extract_best(&vertex_list);
+#endif
 
     // no more nodes left
 
diff -Nur olsrd-0.4.10.orig/src/olsr_types.h olsrd-0.4.10/src/olsr_types.h
--- olsrd-0.4.10.orig/src/olsr_types.h	2005-05-15 14:57:24.000000000 +0200
+++ olsrd-0.4.10/src/olsr_types.h	2006-11-12 09:33:49.000000000 +0100
@@ -93,6 +93,7 @@
 union olsr_ip_addr
 {
   olsr_u32_t v4;
+  olsr_u8_t v4x[4];
   struct in6_addr v6;
 };