Major cleanup of the MPR plugin.
authorJonathan Kirchhoff <jonathan.kirchhoff@fkie.fraunhofer.de>
Thu, 19 Jan 2017 14:51:05 +0000 (15:51 +0100)
committerJonathan Kirchhoff <jonathan.kirchhoff@fkie.fraunhofer.de>
Thu, 19 Jan 2017 14:51:05 +0000 (15:51 +0100)
    - Fix several bugs in the MPR calculation
    - Fix several causes of memory leaks (no known leaks left)
    - Remove obsolete code
    - Improve logging
    - Fix and simplify validation functions

Should still be treated as "unstable". More testing is needed.

src-plugins/nhdp/mpr/mpr.c
src-plugins/nhdp/mpr/mpr.h
src-plugins/nhdp/mpr/neighbor-graph-flooding.c
src-plugins/nhdp/mpr/neighbor-graph-routing.c
src-plugins/nhdp/mpr/neighbor-graph.c
src-plugins/nhdp/mpr/neighbor-graph.h
src-plugins/nhdp/mpr/selection-rfc7181.c

index ca82c49..8139f60 100644 (file)
 
 /* FIXME remove unneeded includes */
 
-/* definitions */
-#define LOG_MPR _nhdp_mpr_subsystem.logging
-
 /* prototypes */
+static void _early_cfg_init(void);
 static int _init(void);
 static void _cleanup(void);
 static void _cb_update_mpr(void);
@@ -90,6 +88,7 @@ static struct oonf_subsystem _nhdp_mpr_subsystem = {
   .dependencies_count = ARRAYSIZE(_dependencies),
   .descr = "RFC7181 Appendix B MPR Plugin",
   .author = "Jonathan Kirchhoff",
+  .early_cfg_init = _early_cfg_init,
 
   .init = _init,
   .cleanup = _cleanup,
@@ -101,6 +100,17 @@ static struct nhdp_domain_mpr _mpr_handler = {
   .update_mpr = _cb_update_mpr,
 };
 
+/* logging sources for NHDP subsystem */
+enum oonf_log_source LOG_MPR;
+
+/**
+ * Initialize additional logging sources for NHDP
+ */
+static void
+_early_cfg_init(void) {
+  LOG_MPR = _nhdp_mpr_subsystem.logging;
+}
+
 /**
  * Initialize plugin
  * @return -1 if an error happened, 0 otherwise
@@ -132,7 +142,7 @@ _update_nhdp_routing(struct neighbor_graph *graph) {
   struct netaddr_str buf1;
 #endif
 
-  OONF_DEBUG(LOG_MPR, "Updating ROUTING MPRs");
+//  OONF_DEBUG(LOG_MPR, "Updating ROUTING MPRs");
   
   list_for_each_element(nhdp_db_get_link_list(), lnk, _global_node) {
     lnk->neigh->_domaindata[0].neigh_is_mpr = false;
@@ -140,8 +150,8 @@ _update_nhdp_routing(struct neighbor_graph *graph) {
         &lnk->neigh->originator,
         current_mpr_node, _avl_node);
     if (current_mpr_node != NULL) {
-      OONF_DEBUG(LOG_MPR, "Processing MPR node %s",
-          netaddr_to_string(&buf1, &current_mpr_node->addr));
+//      OONF_DEBUG(LOG_MPR, "Processing MPR node %s",
+//          netaddr_to_string(&buf1, &current_mpr_node->addr));
       lnk->neigh->_domaindata[0].neigh_is_mpr = true;
     }
   }
@@ -159,15 +169,15 @@ _update_nhdp_flooding(struct neighbor_graph *graph) {
   struct netaddr_str buf1;
 #endif
 
-  OONF_DEBUG(LOG_MPR, "Updating FLOODING MPRs");
+//  OONF_DEBUG(LOG_MPR, "Updating FLOODING MPRs");
 
   list_for_each_element(nhdp_db_get_link_list(), current_link, _global_node) {
     current_mpr_node = avl_find_element(&graph->set_mpr,
         &current_link->neigh->originator,
         current_mpr_node, _avl_node);
     if (current_mpr_node != NULL) {
-      OONF_DEBUG(LOG_MPR, "Processing MPR node %s",
-          netaddr_to_string(&buf1, &current_mpr_node->addr));
+//      OONF_DEBUG(LOG_MPR, "Processing MPR node %s",
+//          netaddr_to_string(&buf1, &current_mpr_node->addr));
       current_link->neigh->neigh_is_flooding_mpr = true;
     }
   }
@@ -181,7 +191,7 @@ static void
 _clear_nhdp_flooding(void) {
   struct nhdp_link *current_link;
 
-  OONF_DEBUG(LOG_MPR, "Updating FLOODING MPRs");
+//  OONF_DEBUG(LOG_MPR, "Updating FLOODING MPRs");
 
   list_for_each_element(nhdp_db_get_link_list(), current_link, _global_node) {
     current_link->neigh->neigh_is_flooding_mpr = false;
@@ -199,17 +209,9 @@ _update_flooding_mpr(void) {
     return;
   }
 
-  /* FIXME Currently, the flooding set is calculated incrementally (i.e. 
-   in a coordinated way as suggested by RFC 7181; however, this should
-   be configurable (and other selection algorithms might not be compatible
-   with this approach).
-   */
-  /* FIXME How to support the coordination flooding and routing MPRs 
-   * selection? */
-  /* calculate flooding MPRs */
   _clear_nhdp_flooding();
   avl_for_each_element(nhdp_interface_get_tree(), flooding_data.current_interface, _node) {
-    OONF_DEBUG(LOG_MPR, "Calculating flooding MPRs for interface %s",
+    OONF_DEBUG(LOG_MPR, "*** Calculate flooding MPRs for interface %s ***",
         nhdp_interface_get_name(flooding_data.current_interface));
     
     mpr_calculate_neighbor_graph_flooding(
@@ -217,11 +219,12 @@ _update_flooding_mpr(void) {
     mpr_calculate_mpr_rfc7181(nhdp_domain_get_flooding(),
         &flooding_data.neigh_graph);
     mpr_print_sets(&flooding_data.neigh_graph);
+    _validate_mpr_set(nhdp_domain_get_flooding(), &flooding_data.neigh_graph);
     _update_nhdp_flooding(&flooding_data.neigh_graph);
+    mpr_clear_neighbor_graph(&flooding_data.neigh_graph);
   }
 
-  /* free memory */
-  mpr_clear_neighbor_graph(&flooding_data.neigh_graph);
+  
 }
 
 static void
@@ -234,13 +237,17 @@ _update_routing_mpr(void) {
       /* we are not the routing MPR for this domain */
       continue;
     }
+    OONF_DEBUG(LOG_MPR, "*** Calculate routing MPRs for domain %u ***", domain->index);
+    
     memset(&routing_graph, 0, sizeof(routing_graph));
-
     mpr_calculate_neighbor_graph_routing(domain, &routing_graph);
     mpr_calculate_mpr_rfc7181(domain, &routing_graph);
     mpr_print_sets(&routing_graph);
+    _validate_mpr_set(domain, &routing_graph);
     _update_nhdp_routing(&routing_graph);
-  }
+    mpr_clear_neighbor_graph(&routing_graph);
+  } 
+  
 }
 
 /**
@@ -259,7 +266,7 @@ _cb_update_mpr(void) {
   OONF_DEBUG(LOG_MPR, "Finished recalculating MPRs");
 }
 
-#if 0
+#if 1
 
 /**
  * Validate the MPR set according to section 18.3 (draft 19)
@@ -267,43 +274,44 @@ _cb_update_mpr(void) {
  * @return 
  */
 void
-_validate_mpr_set(struct common_data *mpr_data) {
+_validate_mpr_set(struct nhdp_domain *domain, struct neighbor_graph *graph)
+{
   struct n1_node *node_n1;
   struct addr_node *n2_addr;
-  uint32_t d_y_n1, d_y_mpr;
+  uint32_t d_y_n1;
+  uint32_t d_y_mpr;
 
   OONF_DEBUG(LOG_MPR, "Validating MPR set");
 
   /* 
    * First property: If x in N1 has W(x) = WILL_ALWAYS then x is in M. 
    */
-  avl_for_each_element(&mpr_data->set_n1, node_n1,
-      _avl_node) {
+  avl_for_each_element(&graph->set_n1, node_n1,
+                       _avl_node)
+  {
     if (node_n1->neigh->flooding_willingness
-        == RFC5444_WILLINGNESS_ALWAYS) {
-      assert(_is_mpr(mpr_data, &node_n1->addr));
+            == RFC7181_WILLINGNESS_ALWAYS) {
+      assert(mpr_is_mpr(graph, &node_n1->addr));
     }
   }
 
-  /*
-   * Second property: For any y in N2 that does not have a defined d1(y), 
-   * there is at least one element in M that is also in N1(y). This is 
-   * equivalent to the requirement that d(y, M) is defined.
-   */
-  avl_for_each_element(&mpr_data->set_n2, n2_addr, _avl_node) {
-    assert(_calculate_d_of_y_s(mpr_data, n2_addr, &mpr_data->set_mpr)
-        != RFC5444_METRIC_INFINITE);
-  }
-
-  /*
-   * Third property: For any y in N2, d(y,M) = d(y, N1).
-   */
-  avl_for_each_element(&mpr_data->set_n2, n2_addr, _avl_node) {
-    d_y_n1 = _calculate_d_of_y_s(mpr_data, n2_addr, &mpr_data->set_n1);
-    d_y_mpr = _calculate_d_of_y_s(mpr_data, n2_addr, &mpr_data->set_mpr);
-    assert(d_y_n1 == d_y_mpr);
+  avl_for_each_element(&graph->set_n2, n2_addr, _avl_node)
+  {
+    d_y_n1 = mpr_calculate_d_of_y_s(domain, graph, n2_addr, &graph->set_n1);
+    d_y_mpr = mpr_calculate_d_of_y_s(domain, graph, n2_addr, &graph->set_mpr);
+
+    /*
+     * Second property: For any y in N2 that does not have a defined d1(y), 
+     * there is at least one element in M that is also in N1(y). This is 
+     * equivalent to the requirement that d(y, M) is defined.
+     */
+    assert(d_y_mpr != RFC7181_METRIC_INFINITE);
+
+    /*
+     * Third property: For any y in N2, d(y,M) = d(y, N1).
+     */
+    assert(d_y_mpr == d_y_n1);
   }
 }
 
-
 #endif
index 023535c..6a1302b 100644 (file)
@@ -56,4 +56,6 @@
 /* definitions and constants */
 #define OONF_MPR_SUBSYSTEM "mpr"
 
+void _validate_mpr_set(struct nhdp_domain *domain, struct neighbor_graph *graph);
+
 #endif /* MPR_H_ */
index cc292e9..75c8770 100644 (file)
@@ -170,29 +170,6 @@ _calculate_d_x_y(const struct nhdp_domain *domain,
   return _calculate_d1_x(domain, x) + _calculate_d2_x_y(domain, x, y);
 }
 
-#if 0
-/**
- * Calculate d1(y) according to section 18.2 (draft 19)
- * @param mpr_data
- * @return 
- */
-uint32_t
-_calculate_d1_of_y(struct mpr_flooding_data *data, struct addr_node *y) {
-  struct n1_node *node_n1;
-  struct nhdp_laddr *laddr;
-
-  /* find the N1 neighbor corresponding to this address, if it exists */
-  avl_for_each_element(&data->neigh_graph.set_n1, node_n1, _avl_node) {
-    laddr = avl_find_element(&node_n1->link->_addresses, y,
-        laddr, _link_node);
-    if (laddr != NULL) {
-      return node_n1->link->_domaindata[0].metric.out;
-    }
-  }
-  return RFC5444_METRIC_INFINITE;
-}
-#endif
-
 /**
  * Calculate d1(x) according to section 18.2 (draft 19)
  * @param mpr_data
@@ -229,7 +206,7 @@ static void
 _calculate_n1(const struct nhdp_domain *domain, struct mpr_flooding_data *data) {
   struct nhdp_link *lnk;
 
-  OONF_DEBUG(LOG_MPR, "Calculate N1 for interface %s",
+  OONF_DEBUG(LOG_MPR, "Calculate N1 (flooding) for interface %s",
       nhdp_interface_get_name(data->current_interface));
 
   list_for_each_element(nhdp_db_get_link_list(), lnk, _global_node) {
@@ -261,7 +238,6 @@ _calculate_n2(const struct nhdp_domain *domain, struct mpr_flooding_data *data)
 
   /* iterate over all two-hop neighbor addresses of N1 members */
   avl_for_each_element(&data->neigh_graph.set_n1, n1_neigh, _avl_node) {
-
     avl_for_each_element(&n1_neigh->link->_2hop, twohop, _link_node) {
       if (_is_allowed_2hop_tuple(domain, data->current_interface, twohop)) {
         mpr_add_addr_node_to_set(&data->neigh_graph.set_n2,
@@ -290,79 +266,4 @@ mpr_calculate_neighbor_graph_flooding(const struct nhdp_domain *domain, struct m
   mpr_init_neighbor_graph(&data->neigh_graph, &_api_interface);
   _calculate_n1(domain, data);
   _calculate_n2(domain, data);
-}
-
-#if 0
-
-/**
- * Calculates N1(x) according to Section 18.2
- * @param addr
- * @return 
- */
-struct avl_tree *
-_calculate_n1_of_y(struct common_data *mpr_data, struct addr_node *addr) {
-  struct n1_node *node_n1;
-  struct nhdp_l2hop *two_hop;
-  struct avl_tree *n1_of_y;
-
-  n1_of_y = malloc(sizeof (struct avl_tree));
-  avl_init(n1_of_y, avl_comp_netaddr, false);
-
-  /* find the subset of N1 through which this N2 node is reachable */
-  avl_for_each_element(&mpr_data->set_n1, node_n1, _avl_node) {
-    two_hop = avl_find_element(&node_n1->link->_2hop,
-        addr,
-        two_hop, _link_node);
-    if (two_hop != NULL) {
-      _add_n1_node_to_set_flooding(n1_of_y, node_n1->link);
-    }
-  }
-
-  return n1_of_y;
-}
-
-/**
- * Calculate d(y,S) according to section 18.2 (draft 19)
- * @param mpr_data
- * @return 
- */
-uint32_t
-_calculate_d_of_y_s(struct common_data *mpr_data, struct addr_node *y,
-    struct avl_tree *subset_s) {
-  uint32_t d1_y, d_x_y, min_cost;
-  struct avl_tree *n1_y, union_subset;
-  struct n1_node *node_n1;
-
-  avl_init(&union_subset, avl_comp_netaddr, false);
-
-  n1_y = _calculate_n1_of_y(mpr_data, y);
-  d1_y = _calculate_d1_of_y(mpr_data, y);
-
-  /* calculate union of subset S and N1(y) */
-  avl_for_each_element(subset_s, node_n1, _avl_node) {
-    _add_n1_node_to_set_flooding(&union_subset, node_n1->link);
-  }
-
-  avl_for_each_element(n1_y, node_n1, _avl_node) {
-    _add_n1_node_to_set_flooding(&union_subset, node_n1->link);
-  }
-
-  /* determine the minimum cost to y over all possible intermediate hops */
-  min_cost = d1_y;
-
-  avl_for_each_element(&union_subset, node_n1, _avl_node) {
-    d_x_y = _calculate_d_x_y_routing(mpr_data, node_n1, y);
-    if (d_x_y < min_cost) {
-      min_cost = d_x_y;
-    }
-  }
-
-  /* free temporary data */
-  _clear_n1_set(n1_y);
-  _clear_n1_set(&union_subset);
-  free(n1_y);
-
-  return min_cost;
-}
-
-#endif
+}
\ No newline at end of file
index d7d455d..7c88669 100644 (file)
@@ -128,8 +128,10 @@ _is_allowed_link_tuple(const struct nhdp_domain *domain,
 }
 
 static bool
-_is_allowed_2hop_tuple(struct nhdp_l2hop *two_hop) {
-  if (two_hop->link->_domaindata[0].metric.in != RFC7181_METRIC_INFINITE) {
+_is_allowed_2hop_tuple(const struct nhdp_domain *domain, struct nhdp_l2hop *two_hop) {
+  struct nhdp_neighbor_domaindata *neighdata;
+  neighdata = nhdp_domain_get_l2hopdata(domain, two_hop);
+  if (neighdata->metric.in != RFC7181_METRIC_INFINITE) {
     return true;
   }
   return false;
@@ -161,12 +163,20 @@ _calculate_d2_x_y(const struct nhdp_domain *domain, struct n1_node *x, struct ad
   struct nhdp_link *lnk;
   struct nhdp_l2hop_domaindata *twohopdata;
 
+//  #ifdef OONF_LOG_DEBUG_INFO
+//  struct netaddr_str buf1;
+//#endif
+
+//  OONF_DEBUG(LOG_MPR, "Calculate d2(x,y), look for address %s", netaddr_to_string(&buf1, &y->addr));
   /* find the corresponding 2-hop entry, if it exists */
   list_for_each_element(&x->neigh->_links, lnk, _neigh_node) {
     l2hop = avl_find_element(&lnk->_2hop,
         &y->addr, l2hop, _link_node);
+//    OONF_DEBUG(LOG_MPR, "Addresses of 2hop link");
+//    mpr_print_addr_set(&lnk->_2hop);
     if (l2hop) {
       twohopdata = nhdp_domain_get_l2hopdata(domain, l2hop);
+//      OONF_DEBUG(LOG_MPR, "Got one with metric %i and address %s", l2hop->_domaindata[0].metric.in, netaddr_to_string(&buf1, &l2hop->twohop_addr));
       return twohopdata->metric.in;
     }
   }
@@ -232,8 +242,8 @@ _calculate_n1(const struct nhdp_domain *domain, struct neighbor_graph *graph) {
   struct nhdp_neighbor *neigh;
 
   OONF_DEBUG(LOG_MPR, "Calculate N1 for routing MPRs");
-
-  list_for_each_element(nhdp_db_get_link_list(), neigh, _global_node) {
+  
+  list_for_each_element(nhdp_db_get_neigh_list(), neigh, _global_node) {
     if (_is_allowed_neighbor_tuple(domain, neigh)) {
       mpr_add_n1_node_to_set(&graph->set_n1, neigh, NULL);
     }
@@ -241,11 +251,16 @@ _calculate_n1(const struct nhdp_domain *domain, struct neighbor_graph *graph) {
 }
 
 static void
-_calculate_n2(struct neighbor_graph *graph) {
+_calculate_n2(const struct nhdp_domain *domain, struct neighbor_graph *graph) {
   struct n1_node *n1_neigh;
   struct nhdp_link *lnk;
   struct nhdp_l2hop *twohop;
-
+  struct nhdp_neighbor_domaindata *neighdata;
+  
+#ifdef OONF_LOG_DEBUG_INFO
+  struct netaddr_str buf1;
+#endif
+  
   OONF_DEBUG(LOG_MPR, "Calculate N2 for routing MPRs");
 
 //    list_for_each_element(&nhdp_neigh_list, neigh, _global_node) {
@@ -260,7 +275,11 @@ _calculate_n2(struct neighbor_graph *graph) {
           lnk, _neigh_node) {
         avl_for_each_element(&lnk->_2hop, twohop, _link_node) {
           OONF_DEBUG(LOG_MPR, "Link status %u", lnk->neigh->symmetric);
-          if (_is_allowed_2hop_tuple(twohop)) {
+          if (_is_allowed_2hop_tuple(domain, twohop)) {
+            neighdata = nhdp_domain_get_l2hopdata(domain, twohop);
+            OONF_DEBUG(LOG_MPR, "Add twohop addr %s in: %u out: %u",
+                    netaddr_to_string(&buf1, &twohop->twohop_addr),
+                       neighdata->metric.in, neighdata->metric.out);
             mpr_add_addr_node_to_set(&graph->set_n2, twohop->twohop_addr);
           }
         }
@@ -298,5 +317,5 @@ mpr_calculate_neighbor_graph_routing(const struct nhdp_domain *domain,
 
   mpr_init_neighbor_graph(graph, methods);
   _calculate_n1(domain, graph);
-  _calculate_n2(graph);
+  _calculate_n2(domain, graph);
 }
index 954fdb6..f86271b 100644 (file)
 void
 mpr_add_n1_node_to_set(struct avl_tree *set, struct nhdp_neighbor *neigh, struct nhdp_link *lnk) {
   struct n1_node *tmp_n1_neigh;
+  tmp_n1_neigh = avl_find_element(set, &neigh->originator, tmp_n1_neigh, _avl_node);
+  if (tmp_n1_neigh) {
+    return;
+  }
   tmp_n1_neigh = malloc(sizeof (struct n1_node));
   tmp_n1_neigh->addr = neigh->originator;
   tmp_n1_neigh->_avl_node.key = &tmp_n1_neigh->addr;
@@ -87,7 +91,11 @@ mpr_add_n1_node_to_set(struct avl_tree *set, struct nhdp_neighbor *neigh, struct
 void
 mpr_add_addr_node_to_set(struct avl_tree *set, const struct netaddr addr) {
   struct addr_node *tmp_node;
-
+  
+  tmp_node = avl_find_element(set, &addr, tmp_node, _avl_node);
+  if (tmp_node) {
+    return;
+  }
   tmp_node = malloc(sizeof (struct addr_node));
   tmp_node->addr = addr;
   tmp_node->_avl_node.key = &tmp_node->addr;
@@ -101,7 +109,7 @@ mpr_add_addr_node_to_set(struct avl_tree *set, const struct netaddr addr) {
 void
 mpr_init_neighbor_graph(struct neighbor_graph *graph, struct neighbor_graph_interface *methods) {
   avl_init(&graph->set_n, avl_comp_netaddr, false);
-  avl_init(&graph->set_n1, avl_comp_netaddr, true);
+  avl_init(&graph->set_n1, avl_comp_netaddr, false);
   avl_init(&graph->set_n2, avl_comp_netaddr, false);
   avl_init(&graph->set_mpr, avl_comp_netaddr, false);
   avl_init(&graph->set_mpr_candidates, avl_comp_netaddr, false);
@@ -209,8 +217,10 @@ mpr_print_n1_set(struct avl_tree *set) {
 #endif
 
   avl_for_each_element(set, current_node, _avl_node) {
-    OONF_DEBUG(LOG_MPR, "%s",
-        netaddr_to_string(&buf1, &current_node->addr));
+    OONF_DEBUG(LOG_MPR, "%s in: %u out: %u",
+        netaddr_to_string(&buf1, &current_node->addr),
+               current_node->neigh->_domaindata[0].metric.in,
+               current_node->neigh->_domaindata[0].metric.out);
   }
 }
 
@@ -232,3 +242,27 @@ mpr_print_sets(struct neighbor_graph *graph) {
   OONF_DEBUG(LOG_MPR, "Set MPR");
   mpr_print_n1_set(&graph->set_mpr);
 }
+
+/**
+ * Calculate d(y,S) according to section 18.2 (draft 19)
+ * @param mpr_data
+ * @return 
+ */
+uint32_t
+mpr_calculate_d_of_y_s(struct nhdp_domain *domain, struct neighbor_graph *graph, struct addr_node *y,
+    struct avl_tree *subset_s) {
+  uint32_t d_x_y, min_cost;
+  struct n1_node *node_n1;
+
+  /* determine the minimum cost to y over all possible intermediate hops */
+  min_cost = graph->methods->calculate_d1_x_of_n2_addr(domain, graph, &y->addr);
+  avl_for_each_element(subset_s, node_n1, _avl_node) {
+    d_x_y = graph->methods->calculate_d_x_y(domain, node_n1, y);
+    if (d_x_y < min_cost) {
+      min_cost = d_x_y;
+    }
+  }
+
+  return min_cost;
+}
+
index b7d2831..1304025 100644 (file)
@@ -114,4 +114,6 @@ void mpr_print_n1_set(struct avl_tree *set);
 
 void mpr_print_sets(struct neighbor_graph *graph);
 
+uint32_t mpr_calculate_d_of_y_s(struct nhdp_domain *domain, struct neighbor_graph *graph, struct addr_node *y, struct avl_tree *subset_s);
+
 #endif
index 2811fe6..7d11a59 100644 (file)
@@ -194,6 +194,8 @@ _process_will_always(const struct nhdp_domain *domain, struct neighbor_graph *gr
 #ifdef OONF_LOG_DEBUG_INFO
   struct netaddr_str buf1;
 #endif
+  
+  OONF_DEBUG(LOG_MPR, "Process WILL_ALWAYS");
 
   avl_for_each_element(&graph->set_n1, current_n1_node, _avl_node) {
     if (graph->methods->get_willingness_n1(domain, current_n1_node)
@@ -220,6 +222,8 @@ _process_unique_mprs(const struct nhdp_domain *domain, struct neighbor_graph *gr
 #ifdef OONF_LOG_DEBUG_INFO
   struct netaddr_str buf1;
 #endif
+  
+  OONF_DEBUG(LOG_MPR, "Process unique MPRs");
 
   avl_for_each_element(&graph->set_n, node_n, _avl_node) {
     /* iterate over N1 to determine the number of possible MPRs */
@@ -277,17 +281,15 @@ _select_greatest_by_property(const struct nhdp_domain *domain,
 
   avl_init(&tmp_candidate_subset, avl_comp_netaddr, false);
 
-  if (graph->set_mpr_candidates.count > 0) {
-    /* We already have MPR candidates, so we need to select from these
-     * (these may have resulted from a previous call to this function). */
-    n1_subset = &graph->set_mpr_candidates;
-  }
-  else {
+//  if (graph->set_mpr_candidates.count > 0) {
+//    /* We already have MPR candidates, so we need to select from these
+//     * (these may have resulted from a previous call to this function). */
+//    n1_subset = &graph->set_mpr_candidates;
+//  }
+//  else {
     /* all N1 nodes are potential MPRs */
     n1_subset = &graph->set_n1;
-  }
-
-  OONF_DEBUG(LOG_MPR, "Iterate over nodes");
+//  }
 
   avl_for_each_element(n1_subset, node_n1, _avl_node) {
     current_prop = get_property(domain, graph, node_n1);
@@ -341,17 +343,26 @@ _process_remaining(const struct nhdp_domain *domain, struct neighbor_graph *grap
   struct n1_node *node_n1;
   bool done;
 
+#ifdef OONF_LOG_DEBUG_INFO
+  struct netaddr_str buf1;
+#endif
+  
+  OONF_DEBUG(LOG_MPR, "Process remaining");
+  
   done = false;
   while (!done) {
     /* select node(s) by willingness */
-    _select_greatest_by_property(domain, graph,
-        &_get_willingness_n1);
+//    OONF_DEBUG(LOG_MPR, "Select by greatest willingness");
+//    _select_greatest_by_property(domain, graph,
+//        &_get_willingness_n1);
 
     /* select node(s) by coverage */
-    if (graph->set_mpr_candidates.count > 1) {
+//    if (graph->set_mpr_candidates.count > 1) {
+      OONF_DEBUG(LOG_MPR, "Select by greatest coverage");
+//                 graph->set_mpr_candidates.count);
       _select_greatest_by_property(domain, graph,
           &_calculate_r);
-    }
+//    }
 
     /* TODO More tie-breaking methods might be added here 
      * Ideas from draft 19:
@@ -362,21 +373,30 @@ _process_remaining(const struct nhdp_domain *domain, struct neighbor_graph *grap
 
     if (graph->set_mpr_candidates.count == 0) {
       /* no potential MPRs; we are done */
+      OONF_DEBUG(LOG_MPR, "No more candidates, we are done!");
       done = true;
     }
     else if (graph->set_mpr_candidates.count == 1) {
       /* a unique candidate was found */
       node_n1 = avl_first_element(&graph->set_mpr_candidates,
           node_n1, _avl_node);
+      OONF_DEBUG(LOG_MPR, "Unique candidate %s",
+                 netaddr_to_string(&buf1, &node_n1->addr));
       mpr_add_n1_node_to_set(&graph->set_mpr, node_n1->neigh, node_n1->link);
-      done = true;
+      avl_remove(&graph->set_mpr_candidates, &node_n1->_avl_node);
+      free(node_n1);
+//      done = true;
     }
     else {
       /* Multiple candidates were found; arbitrarily add one of the 
        * candidate nodes (first in list). */
       node_n1 = avl_first_element(&graph->set_mpr_candidates,
           node_n1, _avl_node);
+      OONF_DEBUG(LOG_MPR, "Multiple candidates, select %s",
+                 netaddr_to_string(&buf1, &node_n1->addr));
       mpr_add_n1_node_to_set(&graph->set_mpr, node_n1->neigh, node_n1->link);
+      avl_remove(&graph->set_mpr_candidates, &node_n1->_avl_node);
+      free(node_n1);
     }
   }
 }