Reworking MPR trigger and dijkstra trigger
authorHenning Rogge <henning.rogge@fkie.fraunhofer.de>
Tue, 15 Sep 2015 12:03:05 +0000 (14:03 +0200)
committerHenning Rogge <henning.rogge@fkie.fraunhofer.de>
Tue, 15 Sep 2015 12:03:05 +0000 (14:03 +0200)
15 files changed:
src-plugins/nhdp/constant_metric/constant_metric.c
src-plugins/nhdp/ff_dat_metric/ff_dat_metric.c
src-plugins/nhdp/mpr/mpr.c
src-plugins/nhdp/mpr/mpr_internal.h
src-plugins/nhdp/mpr/neighbor-graph-routing.c
src-plugins/nhdp/nhdp/nhdp_db.c
src-plugins/nhdp/nhdp/nhdp_db.h
src-plugins/nhdp/nhdp/nhdp_domain.c
src-plugins/nhdp/nhdp/nhdp_domain.h
src-plugins/nhdp/nhdp/nhdp_reader.c
src-plugins/olsrv2/olsrv2/olsrv2.c
src-plugins/olsrv2/olsrv2/olsrv2.h
src-plugins/olsrv2/olsrv2/olsrv2_routing.c
src-plugins/olsrv2/olsrv2/olsrv2_routing.h
src-plugins/olsrv2/olsrv2/olsrv2_writer.c

index addd13e..631c67e 100644 (file)
@@ -276,9 +276,6 @@ _cb_set_linkcost(void *ptr __attribute__((unused))) {
       nhdp_domain_set_incoming_metric(&_constant_metric_handler, lnk, RFC7181_METRIC_INFINITE);
     }
   }
-
-  /* update neighbor metrics */
-  nhdp_domain_neighborhood_changed();
 }
 
 static int
index 0b4b9b6..436f04c 100644 (file)
@@ -551,7 +551,6 @@ _cb_dat_sampling(void *ptr __attribute__((unused))) {
   uint32_t metric_value;
   int rx_bitrate;
   int i;
-  bool change_happened;
 
 #ifdef OONF_LOG_DEBUG_INFO
   struct nhdp_laddr *laddr;
@@ -560,8 +559,6 @@ _cb_dat_sampling(void *ptr __attribute__((unused))) {
 
   OONF_DEBUG(LOG_FF_DAT, "Calculate Metric from sampled data");
 
-  change_happened = false;
-
   list_for_each_element(nhdp_db_get_link_list(), lnk, _global_node) {
     ldata = oonf_class_get_extension(&_link_extenstion, lnk);
 
@@ -651,7 +648,7 @@ _cb_dat_sampling(void *ptr __attribute__((unused))) {
     }
 
     /* set metric for incoming link */
-    change_happened |= nhdp_domain_set_incoming_metric(
+    nhdp_domain_set_incoming_metric(
         &_datff_handler, lnk, metric_value);
 
     OONF_DEBUG(LOG_FF_DAT, "New sampling rate for link %s (%s):"
@@ -668,11 +665,6 @@ _cb_dat_sampling(void *ptr __attribute__((unused))) {
     ldata->buckets[ldata->activePtr].received = 0;
     ldata->buckets[ldata->activePtr].total = 0;
   }
-
-  /* update neighbor metrics */
-  if (change_happened) {
-    nhdp_domain_neighborhood_changed();
-  }
 }
 
 void
index 8880ee7..312fcc4 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);
+static void _cb_update_mpr(struct nhdp_domain *);
 
 static const char *_dependencies[] = {
   OONF_CLASS_SUBSYSTEM,
@@ -91,6 +89,7 @@ static struct oonf_subsystem _nhdp_mpr_subsystem = {
   .descr = "RFC7181 Appendix B MPR Plugin",
   .author = "Jonathan Kirchhoff",
 
+  .early_cfg_init = _early_cfg_init,
   .init = _init,
   .cleanup = _cleanup,
 };
@@ -103,6 +102,13 @@ static struct nhdp_domain_mpr _mpr_handler = {
   .mprs_start = false,
 };
 
+enum oonf_log_source LOG_MPR;
+
+static void
+_early_cfg_init(void) {
+  LOG_MPR = _nhdp_mpr_subsystem.logging;
+}
+
 /**
  * Initialize plugin
  * @return -1 if an error happened, 0 otherwise
@@ -183,7 +189,7 @@ static void
 _clear_nhdp_flooding(void) {
   struct nhdp_link *current_link;
 
-  OONF_DEBUG(LOG_MPR, "Updating FLOODING MPRs");
+  OONF_DEBUG(LOG_MPR, "Clear FLOODING MPRs");
 
   list_for_each_element(nhdp_db_get_link_list(), current_link, _global_node) {
     current_link->neigh->neigh_is_flooding_mpr = false;
@@ -191,16 +197,11 @@ _clear_nhdp_flooding(void) {
 }
 
 static void
-_update_flooding_mpr(void) {
+_update_flooding_mpr(struct nhdp_domain *domain) {
   struct mpr_flooding_data flooding_data;
 
   memset(&flooding_data, 0, sizeof(flooding_data));
   
-  if (nhdp_domain_get_flooding()->mpr != &_mpr_handler) {
-    /* we are not the flooding mpr */
-    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
@@ -209,56 +210,61 @@ _update_flooding_mpr(void) {
   /* FIXME How to support the coordination flooding and routing MPRs 
    * selection? */
   /* calculate flooding MPRs */
+
+  OONF_DEBUG(LOG_MPR, "Recalculating flooding MPR");
+
   _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",
         nhdp_interface_get_name(flooding_data.current_interface));
     
-    mpr_calculate_neighbor_graph_flooding(
-        nhdp_domain_get_flooding(), &flooding_data);
-    mpr_calculate_mpr_rfc7181(nhdp_domain_get_flooding(),
-        &flooding_data.neigh_graph);
+    mpr_calculate_neighbor_graph_flooding(domain, &flooding_data);
+    mpr_calculate_mpr_rfc7181(domain, &flooding_data.neigh_graph);
     mpr_print_sets(&flooding_data.neigh_graph);
     _update_nhdp_flooding(&flooding_data.neigh_graph);
   }
 
   /* free memory */
   mpr_clear_neighbor_graph(&flooding_data.neigh_graph);
+
+  OONF_DEBUG(LOG_MPR, "Finished recalculating MPRs");
 }
 
 static void
-_update_routing_mpr(void) {
+_update_routing_mpr(struct nhdp_domain *domain) {
   struct neighbor_graph routing_graph;
-  struct nhdp_domain *domain;
 
-  list_for_each_element(nhdp_domain_get_list(), domain, _node) {
-    if (domain->mpr != &_mpr_handler) {
-      /* we are not the routing MPR for this domain */
-      continue;
-    }
-    memset(&routing_graph, 0, sizeof(routing_graph));
+  OONF_DEBUG(LOG_MPR, "Recalculating MPR for domain %u", domain->ext);
 
-    mpr_calculate_neighbor_graph_routing(domain, &routing_graph);
-    mpr_calculate_mpr_rfc7181(domain, &routing_graph);
-    mpr_print_sets(&routing_graph);
-    _update_nhdp_routing(&routing_graph);
-  }
+  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);
+  _update_nhdp_routing(&routing_graph);
+  mpr_clear_neighbor_graph(&routing_graph);
+
+  OONF_DEBUG(LOG_MPR, "Finished recalculating MPRs");
 }
 
 /**
  * Callback triggered when an MPR update is required
+ * @param domain NHDP domain
  */
 static void
-_cb_update_mpr(void) {
-  OONF_DEBUG(LOG_MPR, "Recalculating MPRs");
-
-  /* calculate flooding MPRs */
-  _update_flooding_mpr();
-  
-  /* calculate routing MPRs */
-  _update_routing_mpr();
+_cb_update_mpr(struct nhdp_domain *domain) {
+  if (domain->mpr != &_mpr_handler) {
+    OONF_WARN(LOG_MPR,
+        "Wrong MPR handler called for domain extension %u", domain->ext);
+    return;
+  }
 
-  OONF_DEBUG(LOG_MPR, "Finished recalculating MPRs");
+  /* calculate MPRs */
+  if (domain == nhdp_domain_get_flooding_domain()) {
+    _update_flooding_mpr(domain);
+  }
+  else {
+    _update_routing_mpr(domain);
+  }
 }
 
 #if 0
index ee1ec3b..f165fa4 100644 (file)
@@ -48,6 +48,6 @@
 #include "core/oonf_logging.h"
 
 /* headers only for use inside the MPR subsystem */
-enum oonf_log_source LOG_MPR;
+extern enum oonf_log_source LOG_MPR;
 
 #endif /* MPR_INTERNAL_H_ */
index 7d6ec49..e39e57c 100644 (file)
@@ -112,9 +112,8 @@ _is_reachable_neighbor_tuple(struct nhdp_neighbor *neigh) {
 static bool
 _is_allowed_neighbor_tuple(const struct nhdp_domain *domain __attribute__((unused)),
     struct nhdp_neighbor *neigh) {
-  if (_is_reachable_neighbor_tuple(neigh)) {
-    // FIXME Willingness handling appears to be broken; routing willingness is always 0
-    //      && neigh->_domaindata[0].willingness > RFC5444_WILLINGNESS_NEVER) {
+  if (_is_reachable_neighbor_tuple(neigh)
+      && neigh->_domaindata[0].willingness > RFC7181_WILLINGNESS_NEVER) {
     return true;
   }
   return false;
@@ -233,7 +232,7 @@ _calculate_n1(const struct nhdp_domain *domain, struct neighbor_graph *graph) {
 
   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);
     }
index 6eb8f9c..61ddacd 100644 (file)
@@ -229,11 +229,14 @@ nhdp_db_neighbor_add(void) {
  */
 void
 nhdp_db_neighbor_remove(struct nhdp_neighbor *neigh) {
+  struct nhdp_neighbor_domaindata *neighdata;
   struct nhdp_naddr *naddr, *na_it;
   struct nhdp_link *lnk, *l_it;
+  struct nhdp_domain *domain;
 #ifdef OONF_LOG_DEBUG_INFO
   struct netaddr_str nbuf;
 #endif
+  bool was_mpr;
 
   OONF_DEBUG(LOG_NHDP, "Remove Neighbor: 0x%0zx (%s)",
       (size_t)neigh, netaddr_to_string(&nbuf, &neigh->originator));
@@ -256,9 +259,23 @@ nhdp_db_neighbor_remove(struct nhdp_neighbor *neigh) {
     avl_remove(&_neigh_originator_tree, &neigh->_originator_node);
   }
 
+  /* check if neighbor was a MPR */
+  was_mpr = false;
+  list_for_each_element(nhdp_domain_get_list(), domain, _node) {
+    neighdata = nhdp_domain_get_neighbordata(domain, neigh);
+    if (neighdata->neigh_is_mpr) {
+      was_mpr = true;
+      break;
+    }
+  }
+
   /* remove from global list and free memory */
   list_remove(&neigh->_global_node);
   oonf_class_free(&_neigh_info, neigh);
+
+  if (was_mpr) {
+    nhdp_domain_recalculate_mpr(true);
+  }
 }
 
 void
@@ -787,6 +804,7 @@ nhdp_db_link_update_status(struct nhdp_link *lnk) {
   was_symmetric = lnk->status == NHDP_LINK_SYMMETRIC;
 
   /* update link status */
+  lnk->last_status = lnk->status;
   lnk->status = _nhdp_db_link_calculate_status(lnk);
 
   /* handle database changes */
@@ -803,7 +821,9 @@ nhdp_db_link_update_status(struct nhdp_link *lnk) {
   }
 
   /* trigger change event */
-  oonf_class_event(&_link_info, lnk, OONF_OBJECT_CHANGED);
+  if (lnk->last_status != lnk->status) {
+    oonf_class_event(&_link_info, lnk, OONF_OBJECT_CHANGED);
+  }
 }
 
 /**
@@ -925,10 +945,6 @@ _cb_link_vtime(void *ptr) {
   /* check if neighbor still has links */
   if (list_is_empty(&neigh->_links)) {
     nhdp_db_neighbor_remove(neigh);
-    nhdp_domain_neighborhood_changed();
-  }
-  else {
-    nhdp_domain_neighbor_changed(neigh);
   }
 }
 
@@ -949,10 +965,19 @@ _cb_link_heard(void *ptr) {
 static void
 _cb_link_symtime(void *ptr) {
   struct nhdp_link *lnk = ptr;
+  struct nhdp_neighbor_domaindata *data;
+  struct nhdp_domain *domain;
 
   OONF_DEBUG(LOG_NHDP, "Link Symtime fired: 0x%0zx", (size_t)ptr);
   nhdp_db_link_update_status(lnk);
-  nhdp_domain_neighbor_changed(lnk->neigh);
+
+  list_for_each_element(nhdp_domain_get_list(), domain, _node) {
+    data = nhdp_domain_get_neighbordata(domain, lnk->neigh);
+    if (data->neigh_is_mpr) {
+      nhdp_domain_recalculate_mpr(false);
+      return;
+    }
+  }
 }
 
 /**
@@ -975,11 +1000,7 @@ _cb_naddr_vtime(void *ptr) {
 static void
 _cb_l2hop_vtime(void *ptr) {
   struct nhdp_l2hop *l2hop = ptr;
-  struct nhdp_neighbor *neigh;
-
-  neigh = l2hop->link->neigh;
 
   OONF_DEBUG(LOG_NHDP, "2Hop vtime fired: 0x%0zx", (size_t)ptr);
   nhdp_db_link_2hop_remove(l2hop);
-  nhdp_domain_neighbor_changed(neigh);
 }
index e7336c5..964575d 100644 (file)
@@ -115,6 +115,9 @@ struct nhdp_neighbor_domaindata {
   /*! true if the neighbor has been selected as a MPR by this router */
   bool neigh_is_mpr;
 
+  /*! true if the neighbor was a MPR of this router before the MPR recalculation */
+  bool _neigh_was_mpr;
+
   /*! Routing willingness of neighbor */
   uint8_t willingness;
 };
@@ -125,6 +128,9 @@ struct nhdp_neighbor_domaindata {
 struct nhdp_l2hop_domaindata {
   /*! incoming and outgoing metric */
   struct nhdp_metric metric;
+
+  /*! metric used for last MPR calculation */
+  uint32_t _last_used_outgoing_metric;
 };
 
 /**
@@ -147,6 +153,9 @@ struct nhdp_link {
   /*! timer that fires when the link has to be removed from the database */
   struct oonf_timer_instance vtime;
 
+  /*! last status of the linked, used to detect status changes */
+  enum nhdp_link_status last_status;
+
   /*! cached status of the linked */
   enum nhdp_link_status status;
 
index b304159..6fe951e 100644 (file)
@@ -67,9 +67,9 @@ static void _apply_mpr(struct nhdp_domain *domain,
     const char *mpr_name, uint8_t willingness);
 static void _remove_mpr(struct nhdp_domain *);
 
-static void _cb_update_everyone_mpr(void);
+static void _cb_update_everyone_mpr(struct nhdp_domain *);
 
-static void _recalculate_neighbor_metric(struct nhdp_domain *domain,
+static bool _recalculate_neighbor_metric(struct nhdp_domain *domain,
         struct nhdp_neighbor *neigh);
 static const char *_link_to_string(struct nhdp_metric_str *, uint32_t);
 static const char *_path_to_string(struct nhdp_metric_str *, uint32_t, uint8_t);
@@ -455,86 +455,90 @@ nhdp_domain_process_metric_2hoptlv(struct nhdp_domain *domain,
   }
 }
 
-/**
- * Neighborhood changed in terms of metrics or connectivity.
- * This will trigger a MPR set recalculation.
- */
-void
-nhdp_domain_neighborhood_changed(void) {
-  struct nhdp_domain_listener *listener;
-  struct nhdp_domain *domain;
+static bool
+_recalculate_neighbor_metrics(struct nhdp_domain *domain) {
   struct nhdp_neighbor *neigh;
-  
-  list_for_each_element(&_domain_list, domain, _node) {
-    list_for_each_element(nhdp_db_get_neigh_list(), neigh, _global_node) {
-      _recalculate_neighbor_metric(domain, neigh);
-    }
+  bool changed;
 
-    if (domain->mpr->update_mpr != NULL) {
-      domain->mpr->update_mpr();
-    }
+  /* recalculate the neighbor metrics and see if they changed */
+  changed = false;
+  list_for_each_element(nhdp_db_get_neigh_list(), neigh, _global_node) {
+    changed |= _recalculate_neighbor_metric(domain, neigh);
   }
 
-  // TODO: flooding mpr ?
-  // (Why do we need to consider flooding MPRs here?)
+  if (changed) {
+    OONF_DEBUG(LOG_NHDP, "Domain ext %u metric changed", domain->ext);
+  }
+  return changed;
+}
 
-  list_for_each_element(&_domain_listener_list, listener, _node) {
-    if (listener->update) {
-      listener->update(NULL);
-    }
+static bool
+_recalculate_mpr_set(struct nhdp_domain *domain) {
+  struct nhdp_neighbor *neigh;
+  struct nhdp_neighbor_domaindata *neighdata;
+
+  if (!domain->mpr->update_mpr) {
+    return false;
   }
 
-  /* check if we still have routing MPR selectors */
-  OONF_DEBUG(LOG_NHDP, "Checking if we still have routing MPR selectors");
-  _node_is_selected_as_mpr = false;
+  /* remember old MPR set */
+  list_for_each_element(nhdp_db_get_neigh_list(), neigh, _global_node) {
+    neighdata = nhdp_domain_get_neighbordata(domain, neigh);
+    neighdata->_neigh_was_mpr = neighdata->neigh_is_mpr;
+  }
 
-  list_for_each_element(&_domain_list, domain, _node) {
-    list_for_each_element(nhdp_db_get_neigh_list(), neigh, _global_node) {
-      if (nhdp_domain_get_neighbordata(domain, neigh)->local_is_mpr) {
-        _node_is_selected_as_mpr = true;
-        return;
-      }
+  /* update MPR set */
+  domain->mpr->update_mpr(domain);
+
+  /* check for changes */
+  list_for_each_element(nhdp_db_get_neigh_list(), neigh, _global_node) {
+    neighdata = nhdp_domain_get_neighbordata(domain, neigh);
+    if (neighdata->_neigh_was_mpr != neighdata->neigh_is_mpr) {
+      OONF_DEBUG(LOG_NHDP, "Domain ext %u MPR set changed", domain->ext);
+      return true;
     }
   }
+  return false;
 }
 
 /**
- * One neighbor changed in terms of metrics or connectivity.
  * This will trigger a MPR set recalculation.
- * @param neigh neighbor where the changed happened
+ * @param force_change force a MPR recalculation and dijkstra trigger
+ *    even if the existing neighbor set didn't change
  */
 void
-nhdp_domain_neighbor_changed(struct nhdp_neighbor *neigh) {
+nhdp_domain_recalculate_mpr(bool force_change) {
   struct nhdp_domain_listener *listener;
   struct nhdp_domain *domain;
-  
 
-  list_for_each_element(&_domain_list, domain, _node) {
-    _recalculate_neighbor_metric(domain, neigh);
+  bool changed_metric[NHDP_MAXIMUM_DOMAINS];
+  bool changed_mpr[NHDP_MAXIMUM_DOMAINS];
 
-    if (domain->mpr->update_mpr != NULL) {
-      domain->mpr->update_mpr();
-    }
-  }
+  memset(changed_metric, 0, sizeof(changed_metric));
+  memset(changed_mpr, 0, sizeof(changed_mpr));
+  
+  OONF_DEBUG(LOG_NHDP, "Recalculating MPR set?");
+  list_for_each_element(&_domain_list, domain, _node) {
+    /* recalculate the neighbor metrics and see if they changed */
+    changed_metric[domain->index] = _recalculate_neighbor_metrics(domain);
 
-  // TODO: flooding mpr ?
-  // (Why do we need to consider flooding MPRs here?)
+    if (changed_metric[domain->index]) {
+      /* recalculate routing MPRs */
+      changed_mpr[domain->index] = _recalculate_mpr_set(domain);
 
-  list_for_each_element(&_domain_listener_list, listener, _node) {
-    if (listener->update) {
-      listener->update(neigh);
+      if (domain->ext == _flooding_domain.ext && domain->mpr->update_mpr) {
+        /* recalculating flooding MPR */
+        domain->mpr->update_mpr(&_flooding_domain);
+      }
     }
-  }
 
-  /* check if we still have routing MPR selectors */
-  OONF_DEBUG(LOG_NHDP, "Checking if we still have routing MPR selectors");
-  _node_is_selected_as_mpr = false;
-
-  list_for_each_element(&_domain_list, domain, _node) {
-    list_for_each_element(nhdp_db_get_neigh_list(), neigh, _global_node) {
-      if (nhdp_domain_get_neighbordata(domain, neigh)->local_is_mpr) {
-        _node_is_selected_as_mpr = true;
-        return;
+    list_for_each_element(&_domain_listener_list, listener, _node) {
+      /* trigger domain listeners */
+      if ((force_change || changed_metric[domain->index]) && listener->metric_update) {
+        listener->metric_update(domain);
+      }
+      if ((force_change || changed_mpr[domain->index]) && listener->mpr_update) {
+        listener->mpr_update(domain);
       }
     }
   }
@@ -583,7 +587,7 @@ nhdp_domain_process_mprtypes_tlv(
 
 /**
  * Process an in MPR tlv for a NHDP link
- * @param mprtypes list of extenstions for MPR
+ * @param mprtypes list of extensions for MPR
  * @param mprtypes_size length of mprtypes array
  * @param neigh NHDP neighbor
  * @param tlv MPR tlv context
@@ -629,6 +633,16 @@ nhdp_domain_process_mpr_tlv(uint8_t *mprtypes, size_t mprtypes_size,
     OONF_DEBUG(LOG_NHDP_R, "Routing MPR for neighbor in domain %u: %s",
         domain->ext, nhdp_domain_get_neighbordata(domain, neigh)->local_is_mpr ? "true" : "false");
   }
+
+  _node_is_selected_as_mpr = false;
+  list_for_each_element(&_domain_list, domain, _node) {
+    list_for_each_element(nhdp_db_get_neigh_list(), neigh, _global_node) {
+      if (nhdp_domain_get_neighbordata(domain, neigh)->local_is_mpr) {
+        _node_is_selected_as_mpr = true;
+        return;
+      }
+    }
+  }
 }
 
 /**
@@ -834,6 +848,13 @@ nhdp_domain_set_flooding_mpr(const char *mpr_name, uint8_t willingness) {
   _apply_mpr(&_flooding_domain, mpr_name, willingness);
 }
 
+/**
+ * @return the virtual flooding domain
+ */
+const struct nhdp_domain *
+nhdp_domain_get_flooding_domain(void) {
+  return &_flooding_domain;
+}
 /**
  * Sets the incoming metric of a link. This is the only function external
  * code should use to commit the calculated metric values to the nhdp db.
@@ -873,22 +894,29 @@ nhdp_domain_get_listener_list(void) {
 
 /**
  * Recalculate the 'best link/metric' values of a neighbor
+ * and check for two-hop outgoing link metric changes
  * @param domain NHDP domain
  * @param neigh NHDP neighbor
+ * @param neighdata NHDP neighbor domaindata
+ * @return true if the MPR set has to be recalculated
  */
-static void
+static bool
 _recalculate_neighbor_metric(
     struct nhdp_domain *domain,
     struct nhdp_neighbor *neigh) {
   struct nhdp_link *lnk;
   struct nhdp_link_domaindata *linkdata;
+  struct nhdp_l2hop *l2hop;
+  struct nhdp_l2hop_domaindata *l2hopdata;
   struct nhdp_neighbor_domaindata *neighdata;
-  struct nhdp_metric oldmetric;
+  uint32_t old_outgoing;
+  bool changed;
 
   neighdata = nhdp_domain_get_neighbordata(domain, neigh);
+  changed = false;
 
-  /* copy old metric value */
-  memcpy(&oldmetric, &neighdata->metric, sizeof(oldmetric));
+    /* copy old metric value */
+  old_outgoing = neighdata->metric.out;
 
   /* reset metric */
   neighdata->metric.in = RFC7181_METRIC_INFINITE;
@@ -896,11 +924,15 @@ _recalculate_neighbor_metric(
 
   /* reset best link */
   neighdata->best_link = NULL;
+  neighdata->best_link_ifindex = 0;
 
   /* get best metric */
   list_for_each_element(&neigh->_links, lnk, _neigh_node) {
-    linkdata = nhdp_domain_get_linkdata(domain, lnk);
+    if (lnk->status != NHDP_LINK_SYMMETRIC) {
+      continue;
+    }
 
+    linkdata = nhdp_domain_get_linkdata(domain, lnk);
     if (linkdata->metric.out < neighdata->metric.out) {
       neighdata->metric.out = linkdata->metric.out;
       neighdata->best_link = lnk;
@@ -908,17 +940,21 @@ _recalculate_neighbor_metric(
     if (linkdata->metric.in < neighdata->metric.in) {
       neighdata->metric.in = linkdata->metric.in;
     }
+
+    /* check for changes in outgoing 2-hop metrics */
+    avl_for_each_element(&lnk->_2hop, l2hop, _link_node) {
+      l2hopdata = nhdp_domain_get_l2hopdata(domain, l2hop);
+
+      changed |= l2hopdata->metric.out != l2hopdata->_last_used_outgoing_metric;
+      l2hopdata->_last_used_outgoing_metric = l2hopdata->metric.out;
+    }
   }
 
   if (neighdata->best_link != NULL) {
     neighdata->best_link_ifindex =
         nhdp_interface_get_coreif(neighdata->best_link->local_if)->data.index;
   }
-
-  if (memcmp(&oldmetric, &neighdata->metric, sizeof(oldmetric)) != 0) {
-    /* mark metric as updated */
-    domain->neighbor_metric_changed = true;
-  }
+  return changed || neighdata->metric.out != old_outgoing;
 }
 
 /**
@@ -1141,23 +1177,19 @@ _remove_mpr(struct nhdp_domain *domain) {
 }
 
 static void
-_cb_update_everyone_mpr(void) {
+_cb_update_everyone_mpr(struct nhdp_domain *domain) {
   struct nhdp_neighbor *neigh;
-  struct nhdp_domain *domain;
   struct nhdp_neighbor_domaindata *domaindata;
 
   list_for_each_element(nhdp_db_get_neigh_list(), neigh, _global_node) {
-    if (_flooding_domain.mpr == &_everyone_mprs) {
+    if (&_flooding_domain == domain) {
       neigh->neigh_is_flooding_mpr =
           neigh->flooding_willingness > RFC7181_WILLINGNESS_NEVER;
     }
-
-    list_for_each_element(nhdp_domain_get_list(), domain, _node) {
-      if (domain->mpr == &_everyone_mprs) {
-        domaindata = nhdp_domain_get_neighbordata(domain, neigh);
-        domaindata->neigh_is_mpr =
-            domaindata->willingness > RFC7181_WILLINGNESS_NEVER;
-      }
+    else if (domain->mpr == &_everyone_mprs) {
+      domaindata = nhdp_domain_get_neighbordata(domain, neigh);
+      domaindata->neigh_is_mpr =
+          domaindata->willingness > RFC7181_WILLINGNESS_NEVER;
     }
   }
 }
index 6fe66ee..8ba7e5f 100644 (file)
@@ -142,6 +142,8 @@ struct nhdp_domain_metric {
   struct avl_node _node;
 };
 
+struct nhdp_domain;
+
 /**
  * MPR handler for a NHDP domain
  */
@@ -151,8 +153,9 @@ struct nhdp_domain_mpr {
 
   /**
    * callback to calculate MPR set
+   * @param domain NHDP domain to update MPR set
    */
-  void (*update_mpr)(void);
+  void (*update_mpr)(struct nhdp_domain *domain);
 
   /**
    * callback to enable mpr
@@ -200,12 +203,6 @@ struct nhdp_domain {
   /*! flooding willingness */
   uint8_t local_willingness;
 
-  /**
-   * true if a neighbor metric of this domain has changed
-   * since the last reset of this variable
-   */
-  bool neighbor_metric_changed;
-
   /*! metric tlv extension */
   uint8_t ext;
 
@@ -226,11 +223,17 @@ struct nhdp_domain {
  * listener for NHDP domain updates
  */
 struct nhdp_domain_listener {
-  /**
-   * Callback to inform about a NHDP neighbor update
-   * @param neigh neighbor that changed, NULL if multiple neighbors changed
-   */
-  void (*update)(struct nhdp_neighbor *neigh);
+    /**
+     * Callback to inform about a NHDP neighbor MPR update
+     * @param domain NHDP domain of which the MPR set changed
+     */
+    void (*mpr_update)(struct nhdp_domain *domain);
+
+    /**
+     * Callback to inform about a NHDP neighbor metric update
+     * @param domain NHDP domain of which the metric changed
+     */
+    void (*metric_update)(struct nhdp_domain *domain);
 
   /*! hook into global domain updater list */
   struct list_entity _node;
@@ -264,8 +267,7 @@ EXPORT void nhdp_domain_process_metric_linktlv(struct nhdp_domain *,
 EXPORT void nhdp_domain_process_metric_2hoptlv(struct nhdp_domain *d,
     struct nhdp_l2hop *l2hop, uint8_t *value);
 
-EXPORT void nhdp_domain_neighborhood_changed(void);
-EXPORT void nhdp_domain_neighbor_changed(struct nhdp_neighbor *neigh);
+EXPORT void nhdp_domain_recalculate_mpr(bool force_update);
 EXPORT bool nhdp_domain_node_is_mpr(void);
 
 EXPORT size_t nhdp_domain_process_mprtypes_tlv(
@@ -289,8 +291,9 @@ EXPORT bool nhdp_domain_set_incoming_metric(
 
 EXPORT struct list_entity *nhdp_domain_get_list(void);
 EXPORT struct list_entity *nhdp_domain_get_listener_list(void);
-EXPORT const struct nhdp_domain *nhdp_domain_get_flooding(void);
+EXPORT const struct nhdp_domain *nhdp_domain_get_flooding_domain(void);
 EXPORT void nhdp_domain_set_flooding_mpr(const char *mpr_name, uint8_t willingness);
+EXPORT const struct nhdp_domain *nhdp_domain_get_flooding_domain(void);
 
 /**
  * @param domain NHDP domain
index 764ff20..53c594c 100644 (file)
@@ -970,14 +970,14 @@ _cb_msg_pass2_end(struct rfc5444_reader_tlvblock_context *context, bool dropped)
   /* copy willingness to permanent storage */
   nhdp_domain_store_willingness(_current.neighbor);
 
-  /* update MPR sets and link metrics */
-  nhdp_domain_neighbor_changed(_current.neighbor);
-
   /* update ip flooding settings */
   nhdp_interface_update_status(_current.localif);
 
   /* update link status */
   nhdp_db_link_update_status(_current.link);
 
+  /* update MPR sets and link metrics */
+  nhdp_domain_recalculate_mpr(false);
+
   return RFC5444_OKAY;
 }
index d03c44c..89751c7 100644 (file)
@@ -53,7 +53,6 @@
 #include "config/cfg_schema.h"
 #include "core/oonf_logging.h"
 #include "core/oonf_subsystem.h"
-#include "core/os_core.h"
 #include "subsystems/oonf_rfc5444.h"
 #include "subsystems/oonf_telnet.h"
 #include "subsystems/oonf_timer.h"
@@ -235,8 +234,6 @@ struct oonf_interface_listener _if_listener = {
 /* global variables */
 static struct oonf_rfc5444_protocol *_protocol;
 
-static uint16_t _ansn;
-
 /* Additional logging sources */
 enum oonf_log_source LOG_OLSRV2;
 enum oonf_log_source LOG_OLSRV2_R;
@@ -260,10 +257,6 @@ _early_cfg_init(void) {
  */
 static int
 _init(void) {
-  if (os_core_get_random(&_ansn, sizeof(_ansn))) {
-    return -1;
-  }
-
   _protocol = oonf_rfc5444_add_protocol(RFC5444_PROTOCOL, true);
   if (_protocol == NULL) {
     return -1;
@@ -274,6 +267,12 @@ _init(void) {
     return -1;
   }
 
+  if (olsrv2_routing_init()) {
+    olsrv2_writer_cleanup();
+    oonf_rfc5444_remove_protocol(_protocol);
+    return -1;
+  }
+
   /* activate interface listener */
   oonf_interface_add_listener(&_if_listener);
 
@@ -282,7 +281,6 @@ _init(void) {
   olsrv2_originator_init();
   olsrv2_reader_init(_protocol);
   olsrv2_tc_init();
-  olsrv2_routing_init();
 
   /* initialize timer */
   oonf_timer_add(&_tc_timer_class);
@@ -489,37 +487,6 @@ olsrv2_mpr_shall_forwarding(struct rfc5444_reader_tlvblock_context *context,
   return forward;
 }
 
-/**
- * @return current answer set number for local topology database
- */
-uint16_t
-olsrv2_get_ansn(void) {
-  return _ansn;
-}
-
-/**
- * Update answer set number if metric of a neighbor changed since last update.
- * @return new answer set number, might be the same if no metric changed.
- */
-uint16_t
-olsrv2_update_ansn(void) {
-  struct nhdp_domain *domain;
-  bool changed;
-
-  changed = false;
-  list_for_each_element(nhdp_domain_get_list(), domain, _node) {
-    if (domain->neighbor_metric_changed) {
-      changed = true;
-      domain->neighbor_metric_changed = false;
-    }
-  }
-
-  if (changed) {
-    _ansn++;
-  }
-  return _ansn;
-}
-
 /**
  * Schema entry validator for an attached network.
  * See CFG_VALIDATE_ACL_*() macros.
index d231678..defc601 100644 (file)
@@ -75,8 +75,6 @@ EXPORT bool olsrv2_mpr_shall_process(
 EXPORT bool olsrv2_mpr_shall_forwarding(
     struct rfc5444_reader_tlvblock_context *context,
     struct netaddr *source_address, uint64_t vtime);
-EXPORT uint16_t olsrv2_get_ansn(void);
-EXPORT uint16_t olsrv2_update_ansn(void);
 EXPORT int olsrv2_validate_lan(const struct cfg_schema_entry *entry,
     const char *section_name, const char *value, struct autobuf *out);
 EXPORT int olsrv2_avl_cmp_sourcspec_prefix(const void *p1, const void *p2);
index 9bd080b..05c38ca 100644 (file)
@@ -51,6 +51,7 @@
 #include "common/list.h"
 #include "common/netaddr.h"
 #include "core/oonf_logging.h"
+#include "core/os_core.h"
 #include "subsystems/oonf_class.h"
 #include "subsystems/oonf_rfc5444.h"
 #include "subsystems/oonf_timer.h"
@@ -87,8 +88,10 @@ static void _handle_nhdp_routes(struct nhdp_domain *);
 static void _add_route_to_kernel_queue(struct olsrv2_routing_entry *rtentry);
 static void _process_dijkstra_result(struct nhdp_domain *);
 static void _process_kernel_queue(void);
+
+static void _cb_mpr_update(struct nhdp_domain *);
+static void _cb_metric_update(struct nhdp_domain *);
 static void _cb_trigger_dijkstra(void *);
-static void _cb_nhdp_update(struct nhdp_neighbor *);
 static void _cb_route_finished(struct os_route *route, int error);
 
 /* Domain parameter of dijkstra algorithm */
@@ -110,12 +113,19 @@ static struct oonf_timer_instance _rate_limit_timer = {
   .class = &_dijkstra_timer_info
 };
 
+static bool _trigger_dijkstra = false;
+
 /* callback for NHDP domain events */
 static struct nhdp_domain_listener _nhdp_listener = {
-  .update = _cb_nhdp_update,
+  .mpr_update = _cb_mpr_update,
+  .metric_update = _cb_metric_update,
 };
 
-static bool _trigger_dijkstra = false;
+/* status variables for domain changes */
+static uint16_t _ansn;
+static bool _domain_changed[NHDP_MAXIMUM_DOMAINS];
+static bool _update_ansn;
+
 
 /* global datastructures for routing */
 static struct avl_tree _routing_tree[NHDP_MAXIMUM_DOMAINS];
@@ -129,10 +139,20 @@ static bool _initiate_shutdown = false;
 /**
  * Initialize olsrv2 dijkstra and routing code
  */
-void
+int
 olsrv2_routing_init(void) {
   int i;
 
+  /* initialize domain change tracker */
+  if (os_core_get_random(&_ansn, sizeof(_ansn))) {
+    return -1;
+  }
+
+  nhdp_domain_listener_add(&_nhdp_listener);
+  memset(_domain_changed, 0, sizeof(_domain_changed));
+  _update_ansn = false;
+
+
   oonf_class_add(&_rtset_entry);
   oonf_timer_add(&_dijkstra_timer_info);
 
@@ -143,7 +163,7 @@ olsrv2_routing_init(void) {
   avl_init(&_dijkstra_working_tree, avl_comp_uint32, true);
   list_init_head(&_kernel_queue);
 
-  nhdp_domain_listener_add(&_nhdp_listener);
+  return 0;
 }
 
 /**
@@ -185,7 +205,6 @@ olsrv2_routing_cleanup(void) {
   int i;
 
   nhdp_domain_listener_remove(&_nhdp_listener);
-
   oonf_timer_stop(&_rate_limit_timer);
 
   for (i=0; i<NHDP_MAXIMUM_DOMAINS; i++) {
@@ -203,6 +222,14 @@ olsrv2_routing_cleanup(void) {
   oonf_class_remove(&_rtset_entry);
 }
 
+/**
+ * @return current answer set number for local topology database
+ */
+uint16_t
+olsrv2_routing_get_ansn(void) {
+  return _ansn;
+}
+
 /**
  * Trigger a new dijkstra as soon as we are back in the mainloop
  * (unless the rate limitation timer is active, then we will wait for it)
@@ -253,9 +280,22 @@ olsrv2_routing_force_update(bool skip_wait) {
     oonf_timer_stop(&_rate_limit_timer);
   }
 
+  if (_update_ansn) {
+    _ansn++;
+    _update_ansn = false;
+    OONF_DEBUG(LOG_OLSRV2_ROUTING, "Update ANSN to %u", _ansn);
+  }
+
   OONF_DEBUG(LOG_OLSRV2_ROUTING, "Run Dijkstra");
 
   list_for_each_element(nhdp_domain_get_list(), domain, _node) {
+    /* check if dijkstra is necessary */
+    if (!_domain_changed[domain->index]) {
+      /* nothing to do for this domain */
+      continue;
+    }
+    _domain_changed[domain->index] = false;
+
     /* initialize dijkstra specific fields */
     _prepare_routes(domain);
     _prepare_nodes();
@@ -359,6 +399,27 @@ olsrv2_routing_get_filter_list(void) {
   return &_routing_filter_list;
 }
 
+/**
+ * Callback triggered when an MPR-set changed
+ * @param domain NHDP domain that changed
+ */
+static void
+_cb_mpr_update(struct nhdp_domain *domain) {
+  _domain_changed[domain->index] = true;
+  olsrv2_routing_trigger_update();
+}
+
+/**
+ * Callback triggered when an outgoing metric changed
+ * @param domain NHDP domain that changed
+ */
+static void
+_cb_metric_update(struct nhdp_domain *domain) {
+  _update_ansn = true;
+  _domain_changed[domain->index] = true;
+  olsrv2_routing_trigger_update();
+}
+
 /**
  * Run Dijkstra for a set domain, address family and
  * (non-)source-specific nodes
@@ -1040,15 +1101,6 @@ _cb_trigger_dijkstra(void *unused __attribute__((unused))) {
   }
 }
 
-/**
- * Callback triggered when neighbor metrics are updates
- * @param neigh
- */
-static void
-_cb_nhdp_update(struct nhdp_neighbor *neigh __attribute__((unused))) {
-  olsrv2_routing_trigger_update();
-}
-
 /**
  * Callback for kernel route processing results
  * @param route pointer to kernel route
index 4077bc1..80bb2a5 100644 (file)
@@ -178,12 +178,13 @@ struct olsrv2_routing_filter {
   struct list_entity _node;
 };
 
-void olsrv2_routing_init(void);
+int olsrv2_routing_init(void);
 void olsrv2_routing_initiate_shutdown(void);
 void olsrv2_routing_cleanup(void);
 
 void olsrv2_routing_dijkstra_node_init(struct olsrv2_dijkstra_node *);
 
+EXPORT uint16_t olsrv2_routing_get_ansn(void);
 EXPORT void olsrv2_routing_set_domain_parameter(struct nhdp_domain *domain,
     struct olsrv2_routing_domain *parameter);
 
index bfe0ad7..19f8b08 100644 (file)
@@ -59,6 +59,7 @@
 #include "olsrv2/olsrv2_internal.h"
 #include "olsrv2/olsrv2_lan.h"
 #include "olsrv2/olsrv2_originator.h"
+#include "olsrv2/olsrv2_routing.h"
 #include "olsrv2/olsrv2_writer.h"
 
 /* constants */
@@ -548,7 +549,7 @@ _cb_finishMessageTLVs(struct rfc5444_writer *writer,
   uint16_t ansn;
 
   /* get ANSN */
-  ansn = htons(olsrv2_update_ansn());
+  ansn = htons(olsrv2_routing_get_ansn());
 
   rfc5444_writer_set_messagetlv(writer, RFC7181_MSGTLV_CONT_SEQ_NUM,
       complete ? RFC7181_CONT_SEQ_NUM_COMPLETE : RFC7181_CONT_SEQ_NUM_INCOMPLETE,