- improved configuration and statistics handling
[oweals/gnunet.git] / src / ats / gnunet-service-ats_addresses_mlp.c
index 57033f07b874b36fbc73c3a086cbe269dcbc59c8..175d4f41a79eacf49df43ecdf9d9716191753af1 100644 (file)
@@ -35,6 +35,8 @@
 #define DEBUG_ATS GNUNET_NO
 #define VERBOSE_GLPK GNUNET_NO
 
+#define ENABLE_C8 GNUNET_YES
+#define ENABLE_C9 GNUNET_YES
 /**
  * Translate glpk solver error codes to text
  * @param retcode return code
@@ -350,6 +352,7 @@ create_constraint_it (void *cls, const GNUNET_HashCode * key, void *value)
   /* c 10) obey network specific quotas
    * (1)*b_1 + ... + (1)*b_m <= quota_n
    */
+
   int cur_row = 0;
   int c;
   for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
@@ -389,7 +392,7 @@ static int
 mlp_lookup_ats (struct ATS_Address *addr, int ats_index)
 {
   struct GNUNET_ATS_Information * ats = addr->ats;
-  int c;
+  int c = 0;
   int found = GNUNET_NO;
   for (c = 0; c < addr->ats_count; c++)
   {
@@ -525,8 +528,12 @@ mlp_add_constraints_all_addresses (struct GAS_MLP_Handle *mlp, struct GNUNET_CON
   for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
   {
     mlp->r_quota[c] = glp_add_rows (mlp->prob, 1);
+    char * text;
+    GNUNET_asprintf(&text, "quota_ats_%i", mlp->quota_index[c]);
+    glp_set_row_name (mlp->prob, mlp->r_quota[c], text);
+    GNUNET_free (text);
     /* Set bounds to 0 <= x <= quota_out */
-    glp_set_row_bnds (mlp->prob, mlp->r_quota[c], GLP_DB, 0.0, mlp->quota_out[c]);
+    glp_set_row_bnds (mlp->prob, mlp->r_quota[c], GLP_UP, 0.0, mlp->quota_out[c]);
   }
 
   GNUNET_CONTAINER_multihashmap_iterate (addresses, create_constraint_it, mlp);
@@ -551,6 +558,7 @@ mlp_add_constraints_all_addresses (struct GAS_MLP_Handle *mlp, struct GNUNET_CON
   /* Set row bound == 0 */
   glp_set_row_bnds (mlp->prob, mlp->r_c8, GLP_FX, 0.0, 0.0);
   /* -u */
+
   ia[mlp->ci] = mlp->r_c8;
   ja[mlp->ci] = mlp->c_u;
   ar[mlp->ci] = -1;
@@ -571,6 +579,7 @@ mlp_add_constraints_all_addresses (struct GAS_MLP_Handle *mlp, struct GNUNET_CON
     glp_set_row_bnds (mlp->prob, peer->r_c2, GLP_FX, 1.0, 1.0);
 
     /* Adding rows for c 9) */
+#if ENABLE_C9
     peer->r_c9 = glp_add_rows (mlp->prob, 1);
     GNUNET_asprintf(&name, "c9_%s", GNUNET_i2s(&peer->id));
     glp_set_row_name (mlp->prob, peer->r_c9, name);
@@ -583,12 +592,14 @@ mlp_add_constraints_all_addresses (struct GAS_MLP_Handle *mlp, struct GNUNET_CON
     ja[mlp->ci] = mlp->c_r;
     ar[mlp->ci] = -1;
     mlp->ci++;
+#endif
 
     while (addr != NULL)
     {
       mlpi = (struct MLP_information *) addr->mlp_information;
 
       /* coefficient for c 2) */
+
       ia[mlp->ci] = peer->r_c2;
       ja[mlp->ci] = mlpi->c_n;
       ar[mlp->ci] = 1;
@@ -600,11 +611,13 @@ mlp_add_constraints_all_addresses (struct GAS_MLP_Handle *mlp, struct GNUNET_CON
       ar[mlp->ci] = peer->f;
       mlp->ci++;
 
+#if ENABLE_C9
       /* coefficient for c 9) */
       ia[mlp->ci] = peer->r_c9;
       ja[mlp->ci] = mlpi->c_b;
       ar[mlp->ci] = 1;
       mlp->ci++;
+#endif
 
       addr = addr->next;
     }
@@ -613,58 +626,40 @@ mlp_add_constraints_all_addresses (struct GAS_MLP_Handle *mlp, struct GNUNET_CON
 
   /* c 7) For all quality metrics */
 
+
   for (c = 0; c < mlp->m_q; c++)
   {
-    struct ATS_Peer *p = mlp->peer_head;
-    struct ATS_Address *addr = p->head;
+    struct ATS_Peer *tp;
+    struct ATS_Address *ta;
     struct MLP_information * mlpi;
     double value = 1.0;
 
-    while (p != NULL)
-    {
-      /* Adding rows for c 7) */
-      mlp->r_q[c] = glp_add_rows (mlp->prob, 1);
-      GNUNET_asprintf(&name, "c7_q%i_atsi_%i", c, mlp->q[c]);
-      glp_set_row_name (mlp->prob, mlp->r_q[c], name);
-      GNUNET_free (name);
-      /* Set row bound == 0 */
-      glp_set_row_bnds (mlp->prob, mlp->r_q[c], GLP_LO, 0.0, 0.0);
-
-      ia[mlp->ci] = mlp->r_q[c];
-      ja[mlp->ci] = mlp->c_q[c];
-      ar[mlp->ci] = -1;
-      mlp->ci++;
+    /* Adding rows for c 7) */
+    mlp->r_q[c] = glp_add_rows (mlp->prob, 1);
+    GNUNET_asprintf(&name, "c7_q%i_%s", c, mlp_ats_to_string(mlp->q[c]));
+    glp_set_row_name (mlp->prob, mlp->r_q[c], name);
+    GNUNET_free (name);
+    /* Set row bound == 0 */
+    glp_set_row_bnds (mlp->prob, mlp->r_q[c], GLP_LO, 0.0, 0.0);
 
-      while (addr != NULL)
-      {
-        mlpi = addr->mlp_information;
-        /* lookup ATS information */
-        int index = mlp_lookup_ats(addr, mlp->q[c]);
+    ia[mlp->ci] = mlp->r_q[c];
+    ja[mlp->ci] = mlp->c_q[c];
+    ar[mlp->ci] = -1;
+    mlp->ci++;
 
-        if (index != GNUNET_SYSERR)
+    for (tp = mlp->peer_head; tp != NULL; tp = tp->next)
+      for (ta = tp->head; ta != NULL; ta = ta->next)
         {
-          value = (double) addr->ats[index].value;
-
-          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Quality %i with ATS property `%s' has index %i in addresses ats information has value %f\n", c,  mlp_ats_to_string(mlp->q[c]), index, (double) addr->ats[index].value);
-        }
-        else
-          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Quality %i with ATS property `%s' not existing\n", c,  mlp_ats_to_string(mlp->q[c]), index);
-
-        mlpi = addr->mlp_information;
-
-        mlpi->r_q[c] = mlp->r_q[c];
-        mlpi->c_q[c] = mlpi->c_b;
-        mlpi->q[c] = value;
+          mlpi = ta->mlp_information;
+          value = mlpi->q_averaged[c];
 
-        ia[mlp->ci] = mlp->r_q[c];
-        ja[mlp->ci] = mlpi->c_b;
-        ar[mlp->ci] = p->f * value;
-        mlp->ci++;
+          mlpi->r_q[c] = mlp->r_q[c];
 
-        addr = addr->next;
-      }
-      p = p->next;
-    }
+          ia[mlp->ci] = mlp->r_q[c];
+          ja[mlp->ci] = mlpi->c_b;
+          ar[mlp->ci] = tp->f * value;
+          mlp->ci++;
+        }
   }
 }
 
@@ -695,6 +690,7 @@ create_columns_it (void *cls, const GNUNET_HashCode * key, void *value)
   mlpi->c_b = col;
   mlpi->c_n = col + 1;
 
+
   GNUNET_asprintf (&name, "b_%s_%s", GNUNET_i2s (&address->peer), address->plugin);
   glp_set_col_name (mlp->prob, mlpi->c_b , name);
   GNUNET_free (name);
@@ -772,6 +768,7 @@ mlp_create_problem (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHas
   /* Column lower bound = 0.0 */
   glp_set_col_bnds (mlp->prob, col, GLP_LO, 0.0, 0.0);
 
+#if ENABLE_C9
   /* Relativity r column  */
   col = glp_add_cols (mlp->prob, 1);
   mlp->c_r = col;
@@ -781,6 +778,7 @@ mlp_create_problem (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHas
   glp_set_obj_coef (mlp->prob, col, mlp->co_R);
   /* Column lower bound = 0.0 */
   glp_set_col_bnds (mlp->prob, col, GLP_LO, 0.0, 0.0);
+#endif
 
   /* Quality metric columns */
   col = glp_add_cols(mlp->prob, mlp->m_q);
@@ -1076,7 +1074,6 @@ GAS_mlp_solve_problem (struct GAS_MLP_Handle *mlp)
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "\tAddress %s %f\n",
           (n == 1.0) ? "[x]" : "[ ]", b);
     }
-
   }
 
   if (mlp->mlp_task != GNUNET_SCHEDULER_NO_TASK)
@@ -1112,6 +1109,9 @@ GAS_mlp_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
   unsigned int b_min;
   unsigned int n_min;
   struct GNUNET_TIME_Relative i_exec;
+  int c;
+  char * quota_out_str;
+  char * quota_in_str;
 
   /* Init GLPK environment */
   GNUNET_assert (glp_init_env() == 0);
@@ -1120,6 +1120,8 @@ GAS_mlp_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
   mlp->prob = glp_create_prob();
   GNUNET_assert (mlp->prob != NULL);
 
+  mlp->BIG_M = (double) BIG_M_VALUE;
+
   /* Get diversity coefficient from configuration */
   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
                                                       "COEFFICIENT_D",
@@ -1144,61 +1146,6 @@ GAS_mlp_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
   else
     U = 1.0;
 
-  /* Init network quotas */
-  int quotas[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkType;
-  int c;
-
-  for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
-  {
-    mlp->quota_index[c] = quotas[c];
-    static char * entry_in = NULL;
-    static char * entry_out = NULL;
-    unsigned long long quota_in = 0;
-    unsigned long long quota_out = 0;
-
-    switch (quotas[c]) {
-      case GNUNET_ATS_NET_UNSPECIFIED:
-        entry_out = "UNSPECIFIED_QUOTA_OUT";
-        entry_in = "UNSPECIFIED_QUOTA_IN";
-        break;
-      case GNUNET_ATS_NET_LOOPBACK:
-        entry_out = "LOOPBACK_QUOTA_OUT";
-        entry_in = "LOOPBACK_QUOTA_IN";
-        break;
-      case GNUNET_ATS_NET_LAN:
-        entry_out = "LAN_QUOTA_OUT";
-        entry_in = "LAN_QUOTA_IN";
-        break;
-      case GNUNET_ATS_NET_WAN:
-        entry_out = "WAN_QUOTA_OUT";
-        entry_in = "WAN_QUOTA_IN";
-        break;
-      case GNUNET_ATS_NET_WLAN:
-        entry_out = "WLAN_QUOTA_OUT";
-        entry_in = "WLAN_QUOTA_IN";
-        break;
-      default:
-        break;
-    }
-
-    if ((entry_in == NULL) || (entry_out == NULL))
-      continue;
-
-    if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_size (cfg, "ats", entry_out, &quota_out))
-    {
-      quota_out = UINT32_MAX;
-    }
-    if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_size (cfg, "ats", entry_in, &quota_in))
-    {
-      quota_in = UINT32_MAX;
-    }
-
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found `%s' quota %llu and `%s' quota %llu\n",
-                entry_out, quota_out, entry_in, quota_in);
-    mlp->quota_out[c] = quota_out;
-    mlp->quota_in[c] = quota_in;
-  }
-
   /* Get quality metric coefficients from configuration */
   int i_delay = -1;
   int i_distance = -1;
@@ -1248,6 +1195,99 @@ GAS_mlp_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
   else
     n_min = 4;
 
+  /* Init network quotas */
+  int quotas[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkType;
+  for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
+  {
+    mlp->quota_index[c] = quotas[c];
+    static char * entry_in = NULL;
+    static char * entry_out = NULL;
+    unsigned long long quota_in = 0;
+    unsigned long long quota_out = 0;
+
+    switch (quotas[c]) {
+      case GNUNET_ATS_NET_UNSPECIFIED:
+        entry_out = "UNSPECIFIED_QUOTA_OUT";
+        entry_in = "UNSPECIFIED_QUOTA_IN";
+        break;
+      case GNUNET_ATS_NET_LOOPBACK:
+        entry_out = "LOOPBACK_QUOTA_OUT";
+        entry_in = "LOOPBACK_QUOTA_IN";
+        break;
+      case GNUNET_ATS_NET_LAN:
+        entry_out = "LAN_QUOTA_OUT";
+        entry_in = "LAN_QUOTA_IN";
+        break;
+      case GNUNET_ATS_NET_WAN:
+        entry_out = "WAN_QUOTA_OUT";
+        entry_in = "WAN_QUOTA_IN";
+        break;
+      case GNUNET_ATS_NET_WLAN:
+        entry_out = "WLAN_QUOTA_OUT";
+        entry_in = "WLAN_QUOTA_IN";
+        break;
+      default:
+        break;
+    }
+
+    if ((entry_in == NULL) || (entry_out == NULL))
+      continue;
+
+    if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, "ats", entry_out, &quota_out_str))
+    {
+      if (0 == strcmp(quota_out_str, BIG_M_STRING) ||
+          (GNUNET_SYSERR == GNUNET_STRINGS_fancy_size_to_bytes (quota_out_str, &quota_out)))
+        quota_out = mlp->BIG_M;
+
+      GNUNET_free (quota_out_str);
+      quota_out_str = NULL;
+    }
+    else if (GNUNET_ATS_NET_UNSPECIFIED == quotas[c])
+    {
+      quota_out = 0;
+    }
+    else
+    {
+      quota_out = mlp->BIG_M;
+    }
+
+    if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, "ats", entry_in, &quota_in_str))
+    {
+      if (0 == strcmp(quota_in_str, BIG_M_STRING) ||
+          (GNUNET_SYSERR == GNUNET_STRINGS_fancy_size_to_bytes (quota_in_str, &quota_in)))
+        quota_in = mlp->BIG_M;
+
+      GNUNET_free (quota_in_str);
+      quota_in_str = NULL;
+    }
+    else if (GNUNET_ATS_NET_UNSPECIFIED == quotas[c])
+    {
+      quota_in = 0;
+    }
+    else
+    {
+      quota_in = mlp->BIG_M;
+    }
+
+    /* Check if defined quota could make problem unsolvable */
+    if (((n_min * b_min) > quota_out) && (GNUNET_ATS_NET_UNSPECIFIED != quotas[c]))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Inconsistent quota configuration value `%s': " \
+          "outbound quota (%u Bps) too small for combination of minimum connections and minimum bandwidth per peer (%u * %u Bps = %u)\n", entry_out, quota_out, n_min, b_min, n_min * b_min);
+
+      GAS_mlp_done(mlp);
+      mlp = NULL;
+      return NULL;
+    }
+
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found `%s' quota %llu and `%s' quota %llu\n",
+                entry_out, quota_out, entry_in, quota_in);
+    GNUNET_STATISTICS_update ((struct GNUNET_STATISTICS_Handle *) stats, entry_out, quota_out, GNUNET_NO);
+    GNUNET_STATISTICS_update ((struct GNUNET_STATISTICS_Handle *) stats, entry_in, quota_in, GNUNET_NO);
+    mlp->quota_out[c] = quota_out;
+    mlp->quota_in[c] = quota_in;
+  }
+
   /* Get minimum number of connections from configuration */
   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_time (cfg, "ats",
                                                         "ATS_EXEC_INTERVAL",
@@ -1286,8 +1326,6 @@ GAS_mlp_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
 
   mlp->last_execution = GNUNET_TIME_absolute_get_forever();
 
-
-  mlp->BIG_M = (double) UINT32_MAX;
   mlp->co_D = D;
   mlp->co_R = R;
   mlp->co_U = U;
@@ -1298,6 +1336,159 @@ GAS_mlp_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
   return mlp;
 }
 
+static void
+update_quality (struct GAS_MLP_Handle *mlp, struct ATS_Address * address)
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating quality metrics for peer `%s'\n",
+      GNUNET_i2s (&address->peer));
+
+  struct MLP_information *mlpi = address->mlp_information;
+  struct GNUNET_ATS_Information *ats = address->ats;
+  GNUNET_assert (mlpi != NULL);
+
+  int c;
+
+  for (c = 0; c < GNUNET_ATS_QualityPropertiesCount; c++)
+  {
+    int index = mlp_lookup_ats(address, mlp->q[c]);
+
+    if (index == GNUNET_SYSERR)
+      continue;
+
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating address for peer `%s' value `%s': %f\n",
+        GNUNET_i2s (&address->peer),
+        mlp_ats_to_string(mlp->q[c]),
+        (double) ats[index].value);
+
+    int i = mlpi->q_avg_i[c];
+    double * qp = mlpi->q[c];
+    qp[i] = (double) ats[index].value;
+
+    int t;
+    for (t = 0; t < MLP_AVERAGING_QUEUE_LENGTH; t++)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s': `%s' queue[%u]: %f\n",
+        GNUNET_i2s (&address->peer),
+        mlp_ats_to_string(mlp->q[c]),
+        t,
+        qp[t]);
+    }
+
+    if (mlpi->q_avg_i[c] + 1 < (MLP_AVERAGING_QUEUE_LENGTH))
+      mlpi->q_avg_i[c] ++;
+    else
+      mlpi->q_avg_i[c] = 0;
+
+
+    int c2;
+    int c3;
+    double avg = 0.0;
+    switch (mlp->q[c])
+    {
+      case GNUNET_ATS_QUALITY_NET_DELAY:
+        c3 = 0;
+        for (c2 = 0; c2 < MLP_AVERAGING_QUEUE_LENGTH; c2++)
+        {
+          if (mlpi->q[c][c2] != -1)
+          {
+            double * t2 = mlpi->q[c] ;
+            avg += t2[c2];
+            c3 ++;
+          }
+        }
+        if (c3 > 0)
+          /* avg = 1 / ((q[0] + ... + q[l]) /c3) => c3 / avg*/
+          mlpi->q_averaged[c] = (double) c3 / avg;
+        else
+          mlpi->q_averaged[c] = 0.0;
+
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s': `%s' average sum: %f, average: %f, weight: %f\n",
+          GNUNET_i2s (&address->peer),
+          mlp_ats_to_string(mlp->q[c]),
+          avg,
+          avg / (double) c3,
+          mlpi->q_averaged[c]);
+
+        break;
+      case GNUNET_ATS_QUALITY_NET_DISTANCE:
+        c3 = 0;
+        for (c2 = 0; c2 < MLP_AVERAGING_QUEUE_LENGTH; c2++)
+        {
+          if (mlpi->q[c][c2] != -1)
+          {
+            double * t2 = mlpi->q[c] ;
+            avg += t2[c2];
+            c3 ++;
+          }
+        }
+        if (c3 > 0)
+          /* avg = 1 / ((q[0] + ... + q[l]) /c3) => c3 / avg*/
+          mlpi->q_averaged[c] = (double) c3 / avg;
+        else
+          mlpi->q_averaged[c] = 0.0;
+
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s': `%s' average sum: %f, average: %f, weight: %f\n",
+          GNUNET_i2s (&address->peer),
+          mlp_ats_to_string(mlp->q[c]),
+          avg,
+          avg / (double) c3,
+          mlpi->q_averaged[c]);
+
+        break;
+      default:
+        break;
+    }
+
+    if ((mlpi->c_b != 0) && (mlpi->r_q[c] != 0))
+    {
+
+      /* Get current number of columns */
+      int found = GNUNET_NO;
+      int cols = glp_get_num_cols(mlp->prob);
+      int *ind = GNUNET_malloc (cols * sizeof (int) + 1);
+      double *val = GNUNET_malloc (cols * sizeof (double) + 1);
+
+      /* Get the matrix row of quality */
+      int length = glp_get_mat_row(mlp->prob, mlp->r_q[c], ind, val);
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "cols %i, length %i c_b %i\n", cols, length, mlpi->c_b);
+      int c4;
+      /* Get the index if matrix row of quality */
+      for (c4 = 1; c4 <= length; c4++ )
+      {
+        if (mlpi->c_b == ind[c4])
+        {
+          /* Update the value */
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating quality `%s' column `%s' row `%s' : %f -> %f\n",
+              mlp_ats_to_string(mlp->q[c]),
+              glp_get_col_name (mlp->prob, ind[c4]),
+              glp_get_row_name (mlp->prob, mlp->r_q[c]),
+              val[c4],
+              mlpi->q_averaged[c]);
+          val[c4] = mlpi->q_averaged[c];
+          found = GNUNET_YES;
+          break;
+        }
+      }
+
+      if (found == GNUNET_NO)
+        {
+
+          ind[length+1] = mlpi->c_b;
+          val[length+1] = mlpi->q_averaged[c];
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%i ind[%i] val[%i]:  %i %f\n", length+1,  length+1, length+1, mlpi->c_b, mlpi->q_averaged[c]);
+          glp_set_mat_row (mlp->prob, mlpi->r_q[c], length+1, ind, val);
+        }
+      else
+        {
+        /* Get the index if matrix row of quality */
+        glp_set_mat_row (mlp->prob, mlpi->r_q[c], length, ind, val);
+        }
+
+      GNUNET_free (ind);
+      GNUNET_free (val);
+    }
+  }
+}
 
 /**
  * Updates a single address in the MLP problem
@@ -1335,9 +1526,12 @@ GAS_mlp_address_update (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_Mult
     int c;
     for (c = 0; c < GNUNET_ATS_QualityPropertiesCount; c++)
     {
-      mlpi->c_q[c] = 0;
+      int c2;
       mlpi->r_q[c] = 0;
-      mlpi->q[c] = 0.0;
+      for (c2 = 0; c2 < MLP_AVERAGING_QUEUE_LENGTH; c2++)
+        mlpi->q[c][c2] = -1.0; /* -1.0: invalid value */
+      mlpi->q_avg_i[c] = 0;
+      mlpi->q_averaged[c] = 0.0;
     }
 
     address->mlp_information = mlpi;
@@ -1377,80 +1571,22 @@ GAS_mlp_address_update (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_Mult
 
       GNUNET_CONTAINER_DLL_insert (peer->head, peer->tail, address);
     }
+
+    update_quality (mlp, address);
   }
   else
   {
-
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating existing address to peer `%s'\n",
         GNUNET_i2s (&address->peer));
 
-    mlpi = address->mlp_information;
-    int c;
-    for (c = 0; c < GNUNET_ATS_QualityPropertiesCount; c++)
-    {
-      int index = mlp_lookup_ats(address, mlp->q[c]);
-      if ((index != GNUNET_SYSERR) && (mlpi->c_q[c] != 0) && (mlpi->r_q[c] != 0))
-      {
-        if (mlpi->q[c] == (double) address->ats[index].value)
-          break;
-
-        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating address for peer `%s' value `%s'from %f to %f\n",
-            GNUNET_i2s (&address->peer),
-            mlp_ats_to_string(mlp->q[c]),
-            mlpi->q[c],
-            (double) address->ats[index].value);
-
-        switch (mlp->q[c])
-        {
-          case GNUNET_ATS_QUALITY_NET_DELAY:
-            mlpi->q[c] = (double) address->ats[index].value;
-            break;
-          case GNUNET_ATS_QUALITY_NET_DISTANCE:
-            mlpi->q[c] = (double) address->ats[index].value;
-            break;
-          default:
-            break;
-        }
-
-        /* Get current number of columns */
-        int cols = glp_get_num_cols(mlp->prob);
-        int *ind = GNUNET_malloc (cols * sizeof (int));
-        double *val = GNUNET_malloc (cols * sizeof (double));
-
-        /* Get the matrix row of quality */
-        cols = glp_get_mat_row(mlp->prob, mlp->r_q[c], ind, val);
-
-        int c2;
-        /* Get the index if matrix row of quality */
-        for (c2 = 1; c2 <= cols; c2++ )
-        {
-
-          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Existing element column %i : %f\n",
-            ind[c2], val[c2]);
-
-          if ((mlpi->c_b == ind[c2]) && (val[c2] != mlpi->q[c]))
-          {
-            /* Update the value */
-            val[c2] = mlpi->q[c];
-
-            GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "New element column %i : %f\n",
-                ind[c2], val[c2]);
-
-        }
-      }
-
-      /* Get the index if matrix row of quality */
-      glp_set_mat_row (mlp->prob, mlpi->r_q[c], cols, ind, val);
-
-      GNUNET_free (ind);
-      GNUNET_free (val);
-      }
-    }
+    update_quality (mlp, address);
   }
 
   /* Recalculate */
   if (new == GNUNET_YES)
   {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Recreating problem: new address\n");
+
     mlp_delete_problem (mlp);
     mlp_create_problem (mlp, addresses);
     mlp->presolver_required = GNUNET_YES;
@@ -1502,6 +1638,8 @@ GAS_mlp_address_delete (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_Mult
   }
 
   /* Update problem */
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Recreating problem: new address\n");
+
   mlp_delete_problem (mlp);
   if ((GNUNET_CONTAINER_multihashmap_size (addresses) > 0) && (mlp->c_p > 0))
   {
@@ -1518,12 +1656,19 @@ static int
 mlp_get_preferred_address_it (void *cls, const GNUNET_HashCode * key, void *value)
 {
 
-  struct ATS_Address **aa = (struct ATS_Address **)cls;
+  struct ATS_PreferedAddress *aa = (struct ATS_PreferedAddress *) cls;
   struct ATS_Address *addr = value;
   struct MLP_information *mlpi = addr->mlp_information;
+  if (mlpi == NULL)
+    return GNUNET_YES;
   if (mlpi->n == GNUNET_YES)
   {
-    *aa = addr;
+    aa->address = addr;
+    if (mlpi->b > (double) UINT32_MAX)
+      aa->bandwidth_out = UINT32_MAX;
+    else
+      aa->bandwidth_out = (uint32_t) mlpi->b;
+    aa->bandwidth_in = 0;
     return GNUNET_NO;
   }
   return GNUNET_YES;
@@ -1534,17 +1679,21 @@ mlp_get_preferred_address_it (void *cls, const GNUNET_HashCode * key, void *valu
  * Get the preferred address for a specific peer
  *
  * @param mlp the MLP Handle
+ * @param addresses address hashmap
  * @param peer the peer
  * @return suggested address
  */
-struct ATS_Address *
+struct ATS_PreferedAddress *
 GAS_mlp_get_preferred_address (struct GAS_MLP_Handle *mlp,
                                struct GNUNET_CONTAINER_MultiHashMap * addresses,
                                const struct GNUNET_PeerIdentity *peer)
 {
-  struct ATS_Address * aa = NULL;
+  struct ATS_PreferedAddress * aa = GNUNET_malloc (sizeof (struct ATS_PreferedAddress));
+  aa->address = NULL;
+  aa->bandwidth_in = 0;
+  aa->bandwidth_out = 0;
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting preferred address for `%s'\n", GNUNET_i2s (peer));
-  GNUNET_CONTAINER_multihashmap_get_multiple(addresses, &peer->hashPubKey, mlp_get_preferred_address_it, &aa);
+  GNUNET_CONTAINER_multihashmap_get_multiple (addresses, &peer->hashPubKey, mlp_get_preferred_address_it, aa);
   return aa;
 }