2 This file is part of GNUnet.
3 (C) 2011-2014 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file ats/gnunet-service-ats_plugins.c
23 * @brief ats service plugin management
24 * @author Matthias Wachs
25 * @author Christian Grothoff
28 #include "gnunet_ats_plugin.h"
29 #include "gnunet-service-ats_connectivity.h"
30 #include "gnunet-service-ats_performance.h"
31 #include "gnunet-service-ats_preferences.h"
32 #include "gnunet-service-ats_plugins.h"
33 #include "gnunet-service-ats_scheduling.h"
34 #include "gnunet-service-ats_normalization.h"
38 * Configured ATS solver
45 static struct GNUNET_ATS_SolverFunctions *sf;
50 static struct GNUNET_ATS_PluginEnvironment env;
53 * Solver plugin name as string
59 * The preference changed for a peer, update solver.
61 * @param peer the peer
62 * @param kind the ATS kind
63 * @param pref_rel the new relative preference value
66 GAS_normalized_preference_changed (const struct GNUNET_PeerIdentity *peer,
67 enum GNUNET_ATS_PreferenceKind kind,
70 /* Tell solver about update */
71 sf->s_pref (sf->cls, peer, kind, pref_rel);
76 * The relative value for a property changed
78 * @param address the peer
79 * @param type the ATS type
80 * @param prop_rel the new relative preference value
83 GAS_normalized_property_changed (struct ATS_Address *address,
87 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
88 "Normalized property %s for peer `%s' changed to %.3f \n",
89 GNUNET_ATS_print_property_type (type),
90 GNUNET_i2s (&address->peer),
92 sf->s_address_update_property (sf->cls,
101 * Solver information callback
103 * @param cls the closure
104 * @param op the operation
105 * @param status operation status
106 * @param add additional information
109 solver_info_cb (void *cls,
110 enum GAS_Solver_Operation op,
111 enum GAS_Solver_Status status,
112 enum GAS_Solver_Additional_Information add)
118 add_info = "GAS_INFO_NONE";
121 add_info = "GAS_INFO_MLP_FULL";
123 case GAS_INFO_UPDATED:
124 add_info = "GAS_INFO_MLP_UPDATED";
126 case GAS_INFO_PROP_ALL:
127 add_info = "GAS_INFO_PROP_ALL";
129 case GAS_INFO_PROP_SINGLE:
130 add_info = "GAS_INFO_PROP_SINGLE";
133 add_info = "INVALID";
138 case GAS_OP_SOLVE_START:
139 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
140 "Solver notifies `%s' with result `%s' `%s'\n", "GAS_OP_SOLVE_START",
141 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL", add_info);
143 case GAS_OP_SOLVE_STOP:
144 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
145 "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_STOP",
146 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL", add_info);
149 case GAS_OP_SOLVE_SETUP_START:
150 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
151 "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_SETUP_START",
152 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
155 case GAS_OP_SOLVE_SETUP_STOP:
156 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
157 "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_SETUP_STOP",
158 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
161 case GAS_OP_SOLVE_MLP_LP_START:
162 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
163 "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_LP_START",
164 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
166 case GAS_OP_SOLVE_MLP_LP_STOP:
167 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
168 "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_LP_STOP",
169 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
172 case GAS_OP_SOLVE_MLP_MLP_START:
173 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
174 "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_MLP_START",
175 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
177 case GAS_OP_SOLVE_MLP_MLP_STOP:
178 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
179 "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_MLP_STOP",
180 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
182 case GAS_OP_SOLVE_UPDATE_NOTIFICATION_START:
183 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
184 "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_UPDATE_NOTIFICATION_START",
185 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
187 case GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP:
188 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
189 "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP",
190 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
199 * Callback for solver to notify about assignment changes
202 * @param address the address with changes
205 bandwidth_changed_cb (void *cls,
206 struct ATS_Address *address)
211 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
212 "Bandwidth assignment changed for peer %s \n",
213 GNUNET_i2s (&address->peer));
215 /* Notify performance clients about changes to address */
216 GAS_performance_notify_all_clients (&address->peer,
223 GNUNET_BANDWIDTH_value_init (address->assigned_bw_out),
224 GNUNET_BANDWIDTH_value_init (address->assigned_bw_in));
226 if ( (0 == address->assigned_bw_in) &&
227 (0 == address->assigned_bw_out) )
229 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
230 "Telling transport to disconnect peer `%s'\n",
231 GNUNET_i2s (&address->peer));
233 /* Notify scheduling clients about suggestion */
234 GAS_scheduling_transmit_address_suggestion (&address->peer,
236 GNUNET_BANDWIDTH_ZERO,
237 GNUNET_BANDWIDTH_ZERO);
241 /* Do bandwidth stability check */
242 diff_out = abs (address->assigned_bw_out - address->last_notified_bw_out);
243 diff_in = abs (address->assigned_bw_in - address->last_notified_bw_in);
245 if ( (diff_out < htonl(GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__)) &&
246 (diff_in < htonl(GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__)) )
249 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
250 "Sending bandwidth update for peer `%s': %u %u\n",
251 GNUNET_i2s (&address->peer), address->assigned_bw_out,
252 address->assigned_bw_out);
254 /* *Notify scheduling clients about suggestion */
255 GAS_scheduling_transmit_address_suggestion (&address->peer,
257 GNUNET_BANDWIDTH_value_init (address->assigned_bw_out),
258 GNUNET_BANDWIDTH_value_init (address->assigned_bw_in));
260 address->last_notified_bw_out = address->assigned_bw_out;
261 address->last_notified_bw_in = address->assigned_bw_in;
266 * Load quotas for networks from configuration
268 * @param cfg configuration handle
269 * @param out_dest where to write outbound quotas
270 * @param in_dest where to write inbound quotas
271 * @param dest_length length of inbound and outbound arrays
272 * @return number of networks loaded
275 load_quotas (const struct GNUNET_CONFIGURATION_Handle *cfg,
276 unsigned long long *out_dest,
277 unsigned long long *in_dest,
280 char *entry_in = NULL;
281 char *entry_out = NULL;
287 for (c = 0; (c < GNUNET_ATS_NetworkTypeCount) && (c < dest_length); c++)
291 GNUNET_asprintf (&entry_out,
293 GNUNET_ATS_print_network_type (c));
294 GNUNET_asprintf (&entry_in,
296 GNUNET_ATS_print_network_type (c));
300 == GNUNET_CONFIGURATION_get_value_string (cfg, "ats", entry_out,
304 if (0 == strcmp (quota_out_str, GNUNET_ATS_MaxBandwidthString))
306 out_dest[c] = GNUNET_ATS_MaxBandwidth;
309 if ((GNUNET_NO == res)
311 == GNUNET_STRINGS_fancy_size_to_bytes (quota_out_str,
314 if ((GNUNET_NO == res)
316 == GNUNET_CONFIGURATION_get_value_number (cfg, "ats", entry_out,
320 if (GNUNET_NO == res)
322 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
323 _("Could not load quota for network `%s': `%s', assigning default bandwidth %llu\n"),
324 GNUNET_ATS_print_network_type (c),
326 GNUNET_ATS_DefaultBandwidth);
327 out_dest[c] = GNUNET_ATS_DefaultBandwidth;
331 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
332 _("Outbound quota configure for network `%s' is %llu\n"),
333 GNUNET_ATS_print_network_type (c),
336 GNUNET_free(quota_out_str);
340 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
341 _("No outbound quota configured for network `%s', assigning default bandwidth %llu\n"),
342 GNUNET_ATS_print_network_type (c),
343 GNUNET_ATS_DefaultBandwidth);
344 out_dest[c] = GNUNET_ATS_DefaultBandwidth;
349 == GNUNET_CONFIGURATION_get_value_string (cfg, "ats", entry_in,
353 if (0 == strcmp (quota_in_str, GNUNET_ATS_MaxBandwidthString))
355 in_dest[c] = GNUNET_ATS_MaxBandwidth;
358 if ((GNUNET_NO == res)
360 == GNUNET_STRINGS_fancy_size_to_bytes (quota_in_str, &in_dest[c])))
362 if ((GNUNET_NO == res)
364 == GNUNET_CONFIGURATION_get_value_number (cfg, "ats", entry_in,
368 if (GNUNET_NO == res)
370 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
371 _("Could not load quota for network `%s': `%s', assigning default bandwidth %llu\n"),
372 GNUNET_ATS_print_network_type (c),
374 GNUNET_ATS_DefaultBandwidth);
375 in_dest[c] = GNUNET_ATS_DefaultBandwidth;
379 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
380 _("Inbound quota configured for network `%s' is %llu\n"),
381 GNUNET_ATS_print_network_type (c),
384 GNUNET_free(quota_in_str);
388 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
389 _("No outbound quota configure for network `%s', assigning default bandwidth %llu\n"),
390 GNUNET_ATS_print_network_type (c),
391 GNUNET_ATS_DefaultBandwidth);
392 in_dest[c] = GNUNET_ATS_DefaultBandwidth;
394 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
395 "Loaded quota for network `%s' (in/out): %llu %llu\n",
396 GNUNET_ATS_print_network_type (c),
399 GNUNET_free(entry_out);
400 GNUNET_free(entry_in);
402 return GNUNET_ATS_NetworkTypeCount;
407 * Initialize plugins subsystem.
409 * @param cfg configuration to use
410 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error (failed to load
414 GAS_plugins_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
416 unsigned long long quotas_in[GNUNET_ATS_NetworkTypeCount];
417 unsigned long long quotas_out[GNUNET_ATS_NetworkTypeCount];
422 /* Figure out configured solution method */
424 GNUNET_CONFIGURATION_get_value_string (cfg, "ats", "MODE", &mode_str))
426 GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
427 "No resource assignment method configured, using proportional approach\n");
428 ats_mode = MODE_PROPORTIONAL;
432 for (c = 0; c < strlen (mode_str); c++)
433 mode_str[c] = toupper (mode_str[c]);
434 if (0 == strcmp (mode_str, "PROPORTIONAL"))
435 ats_mode = MODE_PROPORTIONAL;
436 else if (0 == strcmp (mode_str, "MLP"))
440 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
441 "Assignment method `%s' configured, but GLPK is not available, please install \n",
443 ats_mode = MODE_PROPORTIONAL;
446 else if (0 == strcmp (mode_str, "RIL"))
450 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
451 "Invalid resource assignment method `%s' configured, using proportional approach\n",
453 ats_mode = MODE_PROPORTIONAL;
455 GNUNET_free(mode_str);
461 GNUNET_ATS_NetworkTypeCount);
463 env.info_cb = &solver_info_cb;
464 env.bandwidth_changed_cb = &bandwidth_changed_cb;
465 env.get_preferences = &GAS_normalization_get_preferences_by_peer;
466 env.get_property = &GAS_normalization_get_properties;
468 env.stats = GSA_stats;
469 env.addresses = GSA_addresses;
470 env.network_count = GNUNET_ATS_NetworkTypeCount;
471 for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
473 env.out_quota[c] = quotas_out[c];
474 env.in_quota[c] = quotas_in[c];
478 case MODE_PROPORTIONAL:
479 plugin_short = "proportional";
482 plugin_short = "mlp";
485 plugin_short = "ril";
491 GNUNET_asprintf (&plugin,
492 "libgnunet_plugin_ats_%s",
494 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
495 "Initializing solver `%s '`%s'\n",
498 if (NULL == (sf = GNUNET_PLUGIN_load (plugin, &env)))
500 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
501 _("Failed to initialize solver `%s'!\n"),
503 return GNUNET_SYSERR;
510 * Shutdown address subsystem.
515 GNUNET_PLUGIN_unload (plugin,
518 GNUNET_free (plugin);
524 * Tell the solver that the given address can now be used
525 * for talking to the respective peer.
527 * @param new_address the new address
528 * @param addr_net network scope the address is in
529 * @param atsi performance data for the address
530 * @param atsi_count size of the @a atsi array
533 GAS_plugin_new_address (struct ATS_Address *new_address,
534 enum GNUNET_ATS_Network_Type addr_net,
535 const struct GNUNET_ATS_Information *atsi,
538 sf->s_add (sf->cls, new_address, addr_net);
539 sf->s_bulk_start (sf->cls);
540 GAS_normalization_normalize_property (new_address,
543 sf->s_bulk_stop (sf->cls);
548 * Tell the solver that the given address is no longer valid
549 * can cannot be used any longer.
551 * @param address address that was deleted
554 GAS_plugin_delete_address (struct ATS_Address *address)
556 sf->s_del (sf->cls, address, GNUNET_NO);
561 * Tell the solver that the given client has expressed its
562 * appreciation for the past performance of a given connection.
564 * @param application client providing the feedback
565 * @param peer peer the feedback is about
566 * @param scope timeframe the feedback applies to
567 * @param kind performance property the feedback relates to
568 * @param score_abs degree of the appreciation
571 GAS_plugin_preference_feedback (struct GNUNET_SERVER_Client *application,
572 const struct GNUNET_PeerIdentity *peer,
573 const struct GNUNET_TIME_Relative scope,
574 enum GNUNET_ATS_PreferenceKind kind,
577 sf->s_feedback (sf->cls,
587 * Stop instant solving, there are many state updates
588 * happening in bulk right now.
591 GAS_plugin_solver_lock ()
593 sf->s_bulk_start (sf->cls);
598 * Resume instant solving, we are done with the bulk state updates.
601 GAS_plugin_solver_unlock ()
603 sf->s_bulk_start (sf->cls);
608 * Notify the plugin that a request to connect to
609 * a particular peer was given to us.
611 * @param pid identity of peer we now care about
614 GAS_plugin_request_connect_start (const struct GNUNET_PeerIdentity *pid)
616 const struct ATS_Address *aa;
618 aa = sf->s_get (sf->cls, pid);
621 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
622 "Cannot suggest address for peer `%s'\n",
626 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
627 "Suggesting address %p for peer `%s'\n",
630 GAS_scheduling_transmit_address_suggestion (pid,
632 GNUNET_BANDWIDTH_value_init (aa->assigned_bw_out),
633 GNUNET_BANDWIDTH_value_init (aa->assigned_bw_in));
638 * Notify the plugin that a request to connect to
639 * a particular peer was dropped.
641 * @param pid identity of peer we care now less about
644 GAS_plugin_request_connect_stop (const struct GNUNET_PeerIdentity *pid)
646 sf->s_get_stop (sf->cls, pid);
650 /* end of gnunet-service-ats_plugins.c */