gw: move path_cost into the gateway struct, ensure it's always up-to-date
authorFerry Huberts <ferry.huberts@pelagic.nl>
Thu, 20 Feb 2014 14:21:24 +0000 (15:21 +0100)
committerFerry Huberts <ferry.huberts@pelagic.nl>
Thu, 20 Feb 2014 14:21:37 +0000 (15:21 +0100)
In the process a lot of code surrounding the path costs can be simplified:
upon reception of a HNA we always calculate the costs, and when they have
changed, we re-sort the gateway list.
Therefore no other place in the code needs to do that, and path_cost can
always be used directly from the gateway struct.

Signed-off-by: Ferry Huberts <ferry.huberts@pelagic.nl>
lib/httpinfo/src/olsrd_httpinfo.c
lib/txtinfo/src/olsrd_txtinfo.c
src/gateway.c
src/gateway.h
src/gateway_default_handler.c
src/gateway_list.c
src/gateway_list.h

index 62c2466..ae833cf 100644 (file)
@@ -1612,7 +1612,7 @@ static void sgw_ipvx(struct autobuf *abuf, bool ipv6) {
         if (!gw->gw) {
           abuf_puts(abuf, "      <td></td>\n");
         } else {
-          abuf_appendf(abuf, "      <td>%llu</td>\n", (long long unsigned int)gw->path_cost);
+          abuf_appendf(abuf, "      <td>%llu</td>\n", (long long unsigned int)gw->gw->path_cost);
         }
         abuf_puts(abuf, "    </tr>\n");
       }
index 315e6bd..9885cad 100644 (file)
@@ -570,7 +570,7 @@ static void sgw_ipvx(struct autobuf *abuf, bool ipv6, const char * fmth, const c
           inet_ntop(ipv6 ? AF_INET6 : AF_INET, &gw->tunnel->target, destination, sizeof(destination));
         }
         if (gw->gw) {
-          cost = (long long unsigned int)gw->path_cost;
+          cost = (long long unsigned int)gw->gw->path_cost;
         }
         abuf_appendf(abuf, fmtv, current, originator, prefix, uplink, downlink, pc, sipv4, sipv4nat, sipv6, if_name, destination, cost);
       }
index dc98f8d..2775455 100644 (file)
@@ -468,7 +468,7 @@ static void takeDownExpensiveGateways(struct gw_list * gw_list, bool ipv4, struc
   }
 
   /* get the cost boundary */
-  current_gw_cost_boundary = current_gw->path_cost;
+  current_gw_cost_boundary = current_gw->gw->path_cost;
   if (olsr_cnf->smart_gw_takedown_percentage < 100) {
     if (current_gw_cost_boundary <= (UINT64_MAX / 100)) {
       current_gw_cost_boundary =  ((current_gw_cost_boundary * 100) / olsr_cnf->smart_gw_takedown_percentage);
@@ -492,7 +492,7 @@ static void takeDownExpensiveGateways(struct gw_list * gw_list, bool ipv4, struc
      * exit when it (and further ones; the list is sorted on costs) has lower
      * costs than the boundary costs
      */
-    if (worst_gw->path_cost < current_gw_cost_boundary) {
+    if (worst_gw->gw->path_cost < current_gw_cost_boundary) {
       return;
     }
 
@@ -847,6 +847,7 @@ bool olsr_is_smart_gateway(struct olsr_ip_prefix *prefix, union olsr_ip_addr *ma
 void olsr_update_gateway_entry(union olsr_ip_addr *originator, union olsr_ip_addr *mask, int prefixlen, uint16_t seqno) {
   struct gw_container_entry * new_gw_in_list;
   uint8_t *ptr;
+  uint64_t prev_path_cost = 0;
   struct gateway_entry *gw = node2gateway(avl_find(&gateway_tree, originator));
 
   if (!gw) {
@@ -897,19 +898,23 @@ void olsr_update_gateway_entry(union olsr_ip_addr *originator, union olsr_ip_add
     gw->cleanup_timer = NULL;
   }
 
-  /* update the costs of the gateway when it is an active gateway */
-  new_gw_in_list = olsr_gw_list_find(&gw_list_ipv4, gw);
-  if (new_gw_in_list) {
-    assert(gw_handler);
-    new_gw_in_list = olsr_gw_list_update(&gw_list_ipv4, new_gw_in_list, gw_handler->getcosts(new_gw_in_list->gw));
-    assert(new_gw_in_list);
-  }
+  assert(gw_handler);
+  prev_path_cost = gw->path_cost;
+  gw->path_cost = gw_handler->getcosts(gw);
 
-  new_gw_in_list = olsr_gw_list_find(&gw_list_ipv6, gw);
-  if (new_gw_in_list) {
-    assert(gw_handler);
-    new_gw_in_list = olsr_gw_list_update(&gw_list_ipv6, new_gw_in_list, gw_handler->getcosts(new_gw_in_list->gw));
-    assert(new_gw_in_list);
+  if (prev_path_cost != gw->path_cost) {
+    /* re-sort the gateway list when costs have changed and when it is an active gateway */
+    new_gw_in_list = olsr_gw_list_find(&gw_list_ipv4, gw);
+    if (new_gw_in_list) {
+      new_gw_in_list = olsr_gw_list_update(&gw_list_ipv4, new_gw_in_list);
+      assert(new_gw_in_list);
+    }
+
+    new_gw_in_list = olsr_gw_list_find(&gw_list_ipv6, gw);
+    if (new_gw_in_list) {
+      new_gw_in_list = olsr_gw_list_update(&gw_list_ipv6, new_gw_in_list);
+      assert(new_gw_in_list);
+    }
   }
 
   /* call update handler */
@@ -1075,13 +1080,12 @@ void olsr_trigger_gatewayloss_check(void) {
 /**
  * Sets a new internet gateway.
  *
- * @param originator ip address of the node with the new gateway
- * @param path_cost the path cost
+ * @param the chosen gateway
  * @param ipv4 set ipv4 gateway
  * @param ipv6 set ipv6 gateway
  * @return true if an error happened, false otherwise
  */
-bool olsr_set_inet_gateway(union olsr_ip_addr *originator, uint64_t path_cost, bool ipv4, bool ipv6) {
+bool olsr_set_inet_gateway(struct gateway_entry * chosen_gw, bool ipv4, bool ipv6) {
   struct gateway_entry *new_gw;
 
   ipv4 = ipv4 && (olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit);
@@ -1090,7 +1094,7 @@ bool olsr_set_inet_gateway(union olsr_ip_addr *originator, uint64_t path_cost, b
     return true;
   }
 
-  new_gw = node2gateway(avl_find(&gateway_tree, originator));
+  new_gw = node2gateway(avl_find(&gateway_tree, &chosen_gw->originator));
   if (!new_gw) {
     /* the originator is not in the gateway tree, we can't set it as gateway */
     return true;
@@ -1100,15 +1104,15 @@ bool olsr_set_inet_gateway(union olsr_ip_addr *originator, uint64_t path_cost, b
   if (ipv4 &&
       new_gw->ipv4 &&
       (!new_gw->ipv4nat || olsr_cnf->smart_gw_allow_nat) &&
-      (!current_ipv4_gw || current_ipv4_gw->gw != new_gw || current_ipv4_gw->path_cost != path_cost)) {
-    /* new gw is different than the current gw, or costs have changed */
+      (!current_ipv4_gw || current_ipv4_gw->gw != new_gw)) {
+    /* new gw is different than the current gw */
 
     struct gw_container_entry * new_gw_in_list = olsr_gw_list_find(&gw_list_ipv4, new_gw);
     if (new_gw_in_list) {
       /* new gw is already in the gw list */
       assert(new_gw_in_list->tunnel);
       olsr_os_inetgw_tunnel_route(new_gw_in_list->tunnel->if_index, true, true, olsr_cnf->rt_table_tunnel);
-      current_ipv4_gw = olsr_gw_list_update(&gw_list_ipv4, new_gw_in_list, path_cost);
+      current_ipv4_gw = new_gw_in_list;
     } else {
       /* new gw is not yet in the gw list */
       char name[IFNAMSIZ];
@@ -1134,7 +1138,6 @@ bool olsr_set_inet_gateway(union olsr_ip_addr *originator, uint64_t path_cost, b
         new_gw_in_list = olsr_cookie_malloc(gw_container_entry_mem_cookie);
         new_gw_in_list->gw = new_gw;
         new_gw_in_list->tunnel = new_v4gw_tunnel;
-        new_gw_in_list->path_cost = path_cost;
         current_ipv4_gw = olsr_gw_list_add(&gw_list_ipv4, new_gw_in_list);
       } else {
         /* adding the tunnel failed, we try again in the next cycle */
@@ -1147,15 +1150,15 @@ bool olsr_set_inet_gateway(union olsr_ip_addr *originator, uint64_t path_cost, b
   /* handle IPv6 */
   if (ipv6 &&
       new_gw->ipv6 &&
-      (!current_ipv6_gw || current_ipv6_gw->gw != new_gw || current_ipv6_gw->path_cost != path_cost)) {
-    /* new gw is different than the current gw, or costs have changed */
+      (!current_ipv6_gw || current_ipv6_gw->gw != new_gw)) {
+    /* new gw is different than the current gw */
 
        struct gw_container_entry * new_gw_in_list = olsr_gw_list_find(&gw_list_ipv6, new_gw);
     if (new_gw_in_list) {
       /* new gw is already in the gw list */
       assert(new_gw_in_list->tunnel);
       olsr_os_inetgw_tunnel_route(new_gw_in_list->tunnel->if_index, true, true, olsr_cnf->rt_table_tunnel);
-      current_ipv6_gw = olsr_gw_list_update(&gw_list_ipv6, new_gw_in_list, path_cost);
+      current_ipv6_gw = new_gw_in_list;
     } else {
       /* new gw is not yet in the gw list */
       char name[IFNAMSIZ];
@@ -1181,7 +1184,6 @@ bool olsr_set_inet_gateway(union olsr_ip_addr *originator, uint64_t path_cost, b
         new_gw_in_list = olsr_cookie_malloc(gw_container_entry_mem_cookie);
         new_gw_in_list->gw = new_gw;
         new_gw_in_list->tunnel = new_v6gw_tunnel;
-        new_gw_in_list->path_cost = path_cost;
         current_ipv6_gw = olsr_gw_list_add(&gw_list_ipv6, new_gw_in_list);
       } else {
         /* adding the tunnel failed, we try again in the next cycle */
index 2102ef1..7dd53c7 100644 (file)
@@ -54,6 +54,7 @@ struct gateway_entry {
     struct olsr_ip_prefix external_prefix;
     uint32_t uplink;
     uint32_t downlink;
+    uint64_t path_cost; /**< the gateway path costs */
     bool ipv4;
     bool ipv4nat;
     bool ipv6;
@@ -180,7 +181,7 @@ void olsr_trigger_gatewayloss_check(void);
  * Gateway Plugin Functions
  */
 
-bool olsr_set_inet_gateway(union olsr_ip_addr *originator, uint64_t path_cost, bool ipv4, bool ipv6);
+bool olsr_set_inet_gateway(struct gateway_entry * chosen_gw, bool ipv4, bool ipv6);
 struct gateway_entry *olsr_get_inet_gateway(bool ipv6);
 
 #endif /* GATEWAY_H_ */
index 115d1b5..dd962f9 100644 (file)
@@ -62,7 +62,7 @@ static inline uint64_t gw_default_calc_threshold(uint64_t path_cost) {
 
 /**
  * Look through the gateway list and select the best gateway
- * depending on the distance to this router
+ * depending on the costs
  */
 static void gw_default_choose_gateway(void) {
   uint64_t cost_ipv4_threshold = UINT64_MAX;
@@ -71,29 +71,27 @@ static void gw_default_choose_gateway(void) {
   bool cost_ipv6_threshold_valid = false;
   struct gateway_entry *chosen_gw_ipv4 = NULL;
   struct gateway_entry *chosen_gw_ipv6 = NULL;
-  uint64_t chosen_gw_ipv4_costs = UINT64_MAX;
-  uint64_t chosen_gw_ipv6_costs = UINT64_MAX;
   struct gateway_entry *gw;
   bool dual = false;
 
   if (olsr_cnf->smart_gw_thresh) {
     /* determine the path cost thresholds */
 
-    uint64_t cost = gw_default_getcosts(olsr_get_inet_gateway(false));
-    if (cost != UINT64_MAX) {
-      cost_ipv4_threshold = gw_default_calc_threshold(cost);
+    struct gateway_entry * current_gw = olsr_get_inet_gateway(false);
+    if (current_gw) {
+      cost_ipv4_threshold = gw_default_calc_threshold(current_gw->path_cost);
       cost_ipv4_threshold_valid = true;
     }
 
-    cost = gw_default_getcosts(olsr_get_inet_gateway(true));
-    if (cost != UINT64_MAX) {
-      cost_ipv6_threshold = gw_default_calc_threshold(cost);
+    current_gw = olsr_get_inet_gateway(true);
+    if (current_gw) {
+      cost_ipv6_threshold = gw_default_calc_threshold(current_gw->path_cost);
       cost_ipv6_threshold_valid = true;
     }
   }
 
   OLSR_FOR_ALL_GATEWAY_ENTRIES(gw) {
-    uint64_t gw_cost = gw_default_getcosts(gw);
+    uint64_t gw_cost = gw->path_cost;
 
     if (gw_cost == UINT64_MAX) {
       /* never select a node with infinite costs */
@@ -104,20 +102,18 @@ static void gw_default_choose_gateway(void) {
       bool gw_eligible_v4 = gw->ipv4
           /* && (olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit) *//* contained in gw_def_choose_new_ipv4_gw */
           && (olsr_cnf->smart_gw_allow_nat || !gw->ipv4nat);
-      if (gw_eligible_v4 && gw_cost < chosen_gw_ipv4_costs
+      if (gw_eligible_v4 && gw_cost < chosen_gw_ipv4->path_cost
           && (!cost_ipv4_threshold_valid || (gw_cost < cost_ipv4_threshold))) {
         chosen_gw_ipv4 = gw;
-        chosen_gw_ipv4_costs = gw_cost;
       }
     }
 
     if (gw_def_choose_new_ipv6_gw) {
       bool gw_eligible_v6 = gw->ipv6
           /* && olsr_cnf->ip_version == AF_INET6 *//* contained in gw_def_choose_new_ipv6_gw */;
-      if (gw_eligible_v6 && gw_cost < chosen_gw_ipv6_costs
+      if (gw_eligible_v6 && gw_cost < chosen_gw_ipv6->path_cost
           && (!cost_ipv6_threshold_valid || (gw_cost < cost_ipv6_threshold))) {
         chosen_gw_ipv6 = gw;
-        chosen_gw_ipv6_costs = gw_cost;
       }
     }
   } OLSR_FOR_ALL_GATEWAY_ENTRIES_END(gw)
@@ -131,11 +127,11 @@ static void gw_default_choose_gateway(void) {
 
   if (chosen_gw_ipv4) {
     /* we are dealing with an IPv4 or dual stack gateway */
-    olsr_set_inet_gateway(&chosen_gw_ipv4->originator, chosen_gw_ipv4_costs, true, dual);
+    olsr_set_inet_gateway(chosen_gw_ipv4, true, dual);
   }
   if (chosen_gw_ipv6 && !dual) {
     /* we are dealing with an IPv6-only gateway */
-    olsr_set_inet_gateway(&chosen_gw_ipv6->originator, chosen_gw_ipv6_costs, false, true);
+    olsr_set_inet_gateway(chosen_gw_ipv6, false, true);
   }
 
   if ((olsr_cnf->smart_gw_thresh == 0) && !gw_def_choose_new_ipv4_gw && !gw_def_choose_new_ipv6_gw) {
index c84a789..90d5eda 100644 (file)
@@ -123,7 +123,10 @@ struct gw_container_entry * olsr_gw_list_add(struct gw_list * list, struct gw_co
        list_node_init(&entry->list_node);
 
        OLSR_FOR_ALL_GWS(&list->head, gw) {
-               if (gw && (entry->path_cost <= gw->path_cost)) {
+         assert(gw);
+         assert(gw->gw);
+         assert(entry->gw);
+         if (entry->gw->path_cost <= gw->gw->path_cost) {
                        /* add before the iterated list entry: the gateway to insert has lower
                         * costs or has equal costs but is newer (since we insert it) */
                        list_add_before(&gw->list_node, &entry->list_node);
@@ -140,26 +143,19 @@ struct gw_container_entry * olsr_gw_list_add(struct gw_list * list, struct gw_co
 }
 
 /**
- * Update an entry on the list.
+ * Update an entry on the list (re-sort the list.)
  *
  * @param list a pointer to the list
  * @param entry a pointer to the entry
- * @param path_cost the costs of the entry
  * @return a pointer to the updated entry
  */
-struct gw_container_entry * olsr_gw_list_update(struct gw_list * list, struct gw_container_entry * entry,
-               uint64_t path_cost) {
+struct gw_container_entry * olsr_gw_list_update(struct gw_list * list, struct gw_container_entry * entry) {
        assert(list);
        assert(entry);
        assert(!olsr_gw_list_empty(list));
 
-       if (entry->path_cost == path_cost) {
-               return entry;
-       }
-
        /* don't touch gw */
        /* don't touch tunnel */
-       entry->path_cost = path_cost;
        /* don't touch list_node */
 
        list_remove(&entry->list_node);
index e947b16..ae4d4c9 100644 (file)
@@ -62,7 +62,6 @@ struct gw_list {
 struct gw_container_entry {
                struct gateway_entry * gw; /**< the gateway entry */
                struct olsr_iptunnel_entry * tunnel; /**< the gateway tunnel */
-               uint64_t path_cost; /**< the gateway path costs */
                struct list_node list_node; /**< the list node */
 };
 
@@ -144,8 +143,7 @@ static inline struct gw_container_entry * olsr_gw_list_get_worst_entry(struct gw
 
 struct gw_container_entry * olsr_gw_list_find(struct gw_list * list, struct gateway_entry * entry);
 struct gw_container_entry * olsr_gw_list_add(struct gw_list * list, struct gw_container_entry * entry);
-struct gw_container_entry * olsr_gw_list_update(struct gw_list * list, struct gw_container_entry * entry,
-               uint64_t gw_path_cost);
+struct gw_container_entry * olsr_gw_list_update(struct gw_list * list, struct gw_container_entry * entry);
 struct gw_container_entry * olsr_gw_list_remove(struct gw_list * list, struct gw_container_entry * entry);
 
 #endif /* __linux__ */