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_performance.h"
30 #include "gnunet-service-ats_preferences.h"
31 #include "gnunet-service-ats_plugins.h"
32 #include "gnunet-service-ats_scheduling.h"
33 #include "gnunet-service-ats_normalization.h"
37 * Configured ATS solver
44 static struct GNUNET_ATS_SolverFunctions *sf;
49 static struct GNUNET_ATS_PluginEnvironment env;
52 * Solver plugin name as string
58 * The preference changed for a peer, update solver.
60 * @param peer the peer
61 * @param kind the ATS kind
62 * @param pref_rel the new relative preference value
65 GAS_normalized_preference_changed (const struct GNUNET_PeerIdentity *peer,
66 enum GNUNET_ATS_PreferenceKind kind,
69 /* Tell solver about update */
70 sf->s_pref (sf->cls, peer, kind, pref_rel);
75 * The relative value for a property changed
77 * @param address the peer
78 * @param type the ATS type
79 * @param prop_rel the new relative preference value
82 GAS_normalized_property_changed (struct ATS_Address *address,
86 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
87 "Normalized property %s for peer `%s' changed to %.3f \n",
88 GNUNET_ATS_print_property_type (type),
89 GNUNET_i2s (&address->peer),
91 sf->s_address_update_property (sf->cls,
100 * Solver information callback
102 * @param cls the closure
103 * @param op the operation
104 * @param status operation status
105 * @param add additional information
108 solver_info_cb (void *cls,
109 enum GAS_Solver_Operation op,
110 enum GAS_Solver_Status status,
111 enum GAS_Solver_Additional_Information add)
117 add_info = "GAS_INFO_NONE";
120 add_info = "GAS_INFO_MLP_FULL";
122 case GAS_INFO_UPDATED:
123 add_info = "GAS_INFO_MLP_UPDATED";
125 case GAS_INFO_PROP_ALL:
126 add_info = "GAS_INFO_PROP_ALL";
128 case GAS_INFO_PROP_SINGLE:
129 add_info = "GAS_INFO_PROP_SINGLE";
132 add_info = "INVALID";
137 case GAS_OP_SOLVE_START:
138 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
139 "Solver notifies `%s' with result `%s' `%s'\n", "GAS_OP_SOLVE_START",
140 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL", add_info);
142 case GAS_OP_SOLVE_STOP:
143 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
144 "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_STOP",
145 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL", add_info);
148 case GAS_OP_SOLVE_SETUP_START:
149 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
150 "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_SETUP_START",
151 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
154 case GAS_OP_SOLVE_SETUP_STOP:
155 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
156 "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_SETUP_STOP",
157 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
160 case GAS_OP_SOLVE_MLP_LP_START:
161 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
162 "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_LP_START",
163 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
165 case GAS_OP_SOLVE_MLP_LP_STOP:
166 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
167 "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_LP_STOP",
168 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
171 case GAS_OP_SOLVE_MLP_MLP_START:
172 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
173 "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_MLP_START",
174 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
176 case GAS_OP_SOLVE_MLP_MLP_STOP:
177 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
178 "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_MLP_STOP",
179 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
181 case GAS_OP_SOLVE_UPDATE_NOTIFICATION_START:
182 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
183 "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_UPDATE_NOTIFICATION_START",
184 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
186 case GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP:
187 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
188 "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP",
189 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
198 * Callback for solver to notify about assignment changes
201 * @param address the address with changes
204 bandwidth_changed_cb (void *cls,
205 struct ATS_Address *address)
210 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
211 "Bandwidth assignment changed for peer %s \n",
212 GNUNET_i2s (&address->peer));
214 /* Notify performance clients about changes to address */
215 GAS_performance_notify_all_clients (&address->peer,
222 GNUNET_BANDWIDTH_value_init (address->assigned_bw_out),
223 GNUNET_BANDWIDTH_value_init (address->assigned_bw_in));
225 if ( (0 == address->assigned_bw_in) &&
226 (0 == address->assigned_bw_out) )
228 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
229 "Telling transport to disconnect peer `%s'\n",
230 GNUNET_i2s (&address->peer));
232 /* Notify scheduling clients about suggestion */
233 GAS_scheduling_transmit_address_suggestion (&address->peer,
235 GNUNET_BANDWIDTH_ZERO,
236 GNUNET_BANDWIDTH_ZERO);
240 /* Do bandwidth stability check */
241 diff_out = abs (address->assigned_bw_out - address->last_notified_bw_out);
242 diff_in = abs (address->assigned_bw_in - address->last_notified_bw_in);
244 if ( (diff_out < htonl(GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__)) &&
245 (diff_in < htonl(GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__)) )
248 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
249 "Sending bandwidth update for peer `%s': %u %u\n",
250 GNUNET_i2s (&address->peer), address->assigned_bw_out,
251 address->assigned_bw_out);
253 /* *Notify scheduling clients about suggestion */
254 GAS_scheduling_transmit_address_suggestion (&address->peer,
256 GNUNET_BANDWIDTH_value_init (address->assigned_bw_out),
257 GNUNET_BANDWIDTH_value_init (address->assigned_bw_in));
259 address->last_notified_bw_out = address->assigned_bw_out;
260 address->last_notified_bw_in = address->assigned_bw_in;
265 * Load quotas for networks from configuration
267 * @param cfg configuration handle
268 * @param out_dest where to write outbound quotas
269 * @param in_dest where to write inbound quotas
270 * @param dest_length length of inbound and outbound arrays
271 * @return number of networks loaded
274 load_quotas (const struct GNUNET_CONFIGURATION_Handle *cfg,
275 unsigned long long *out_dest, unsigned long long *in_dest, int dest_length)
277 char * entry_in = NULL;
278 char * entry_out = NULL;
279 char * quota_out_str;
284 for (c = 0; (c < GNUNET_ATS_NetworkTypeCount) && (c < dest_length); c++)
288 GNUNET_asprintf (&entry_out,
290 GNUNET_ATS_print_network_type (c));
291 GNUNET_asprintf (&entry_in,
293 GNUNET_ATS_print_network_type (c));
297 == GNUNET_CONFIGURATION_get_value_string (cfg, "ats", entry_out,
301 if (0 == strcmp (quota_out_str, GNUNET_ATS_MaxBandwidthString))
303 out_dest[c] = GNUNET_ATS_MaxBandwidth;
306 if ((GNUNET_NO == res)
308 == GNUNET_STRINGS_fancy_size_to_bytes (quota_out_str,
311 if ((GNUNET_NO == res)
313 == GNUNET_CONFIGURATION_get_value_number (cfg, "ats", entry_out,
317 if (GNUNET_NO == res)
319 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
320 _("Could not load quota for network `%s': `%s', assigning default bandwidth %llu\n"),
321 GNUNET_ATS_print_network_type (c),
323 GNUNET_ATS_DefaultBandwidth);
324 out_dest[c] = GNUNET_ATS_DefaultBandwidth;
328 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
329 _("Outbound quota configure for network `%s' is %llu\n"),
330 GNUNET_ATS_print_network_type (c),
333 GNUNET_free(quota_out_str);
337 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
338 _("No outbound quota configured for network `%s', assigning default bandwidth %llu\n"),
339 GNUNET_ATS_print_network_type (c),
340 GNUNET_ATS_DefaultBandwidth);
341 out_dest[c] = GNUNET_ATS_DefaultBandwidth;
346 == GNUNET_CONFIGURATION_get_value_string (cfg, "ats", entry_in,
350 if (0 == strcmp (quota_in_str, GNUNET_ATS_MaxBandwidthString))
352 in_dest[c] = GNUNET_ATS_MaxBandwidth;
355 if ((GNUNET_NO == res)
357 == GNUNET_STRINGS_fancy_size_to_bytes (quota_in_str, &in_dest[c])))
359 if ((GNUNET_NO == res)
361 == GNUNET_CONFIGURATION_get_value_number (cfg, "ats", entry_in,
365 if (GNUNET_NO == res)
367 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
368 _("Could not load quota for network `%s': `%s', assigning default bandwidth %llu\n"),
369 GNUNET_ATS_print_network_type (c),
371 GNUNET_ATS_DefaultBandwidth);
372 in_dest[c] = GNUNET_ATS_DefaultBandwidth;
376 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
377 _("Inbound quota configured for network `%s' is %llu\n"),
378 GNUNET_ATS_print_network_type (c),
381 GNUNET_free(quota_in_str);
385 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
386 _("No outbound quota configure for network `%s', assigning default bandwidth %llu\n"),
387 GNUNET_ATS_print_network_type (c),
388 GNUNET_ATS_DefaultBandwidth);
389 in_dest[c] = GNUNET_ATS_DefaultBandwidth;
391 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
392 "Loaded quota for network `%s' (in/out): %llu %llu\n",
393 GNUNET_ATS_print_network_type (c),
396 GNUNET_free(entry_out);
397 GNUNET_free(entry_in);
399 return GNUNET_ATS_NetworkTypeCount;
404 * Initialize plugins subsystem.
406 * @param cfg configuration to use
407 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error (failed to load
411 GAS_plugins_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
413 unsigned long long quotas_in[GNUNET_ATS_NetworkTypeCount];
414 unsigned long long quotas_out[GNUNET_ATS_NetworkTypeCount];
419 /* Figure out configured solution method */
421 GNUNET_CONFIGURATION_get_value_string (cfg, "ats", "MODE", &mode_str))
423 GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
424 "No resource assignment method configured, using proportional approach\n");
425 ats_mode = MODE_PROPORTIONAL;
429 for (c = 0; c < strlen (mode_str); c++)
430 mode_str[c] = toupper (mode_str[c]);
431 if (0 == strcmp (mode_str, "PROPORTIONAL"))
432 ats_mode = MODE_PROPORTIONAL;
433 else if (0 == strcmp (mode_str, "MLP"))
437 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
438 "Assignment method `%s' configured, but GLPK is not available, please install \n",
440 ats_mode = MODE_PROPORTIONAL;
443 else if (0 == strcmp (mode_str, "RIL"))
447 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
448 "Invalid resource assignment method `%s' configured, using proportional approach\n",
450 ats_mode = MODE_PROPORTIONAL;
452 GNUNET_free(mode_str);
458 GNUNET_ATS_NetworkTypeCount);
460 env.info_cb = &solver_info_cb;
461 env.bandwidth_changed_cb = &bandwidth_changed_cb;
462 env.get_preferences = &GAS_normalization_get_preferences_by_peer;
463 env.get_property = &GAS_normalization_get_properties;
465 env.stats = GSA_stats;
466 env.addresses = GSA_addresses;
467 env.network_count = GNUNET_ATS_NetworkTypeCount;
468 for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
470 env.out_quota[c] = quotas_out[c];
471 env.in_quota[c] = quotas_in[c];
475 case MODE_PROPORTIONAL:
476 plugin_short = "proportional";
479 plugin_short = "mlp";
482 plugin_short = "ril";
488 GNUNET_asprintf (&plugin,
489 "libgnunet_plugin_ats_%s",
491 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
492 "Initializing solver `%s '`%s'\n",
495 if (NULL == (sf = GNUNET_PLUGIN_load (plugin, &env)))
497 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
498 _("Failed to initialize solver `%s'!\n"),
500 return GNUNET_SYSERR;
507 * Shutdown address subsystem.
512 GNUNET_PLUGIN_unload (plugin,
515 GNUNET_free (plugin);
521 GAS_plugin_new_address (struct ATS_Address *new_address,
522 enum GNUNET_ATS_Network_Type addr_net,
523 const struct GNUNET_ATS_Information *atsi,
526 sf->s_add (sf->cls, new_address, addr_net);
527 sf->s_bulk_start (sf->cls);
528 GAS_normalization_normalize_property (new_address,
531 sf->s_bulk_stop (sf->cls);
536 GAS_plugin_update_address (struct ATS_Address *address,
537 const struct GNUNET_ATS_Information *atsi,
540 sf->s_bulk_start (sf->cls);
541 GAS_normalization_normalize_property (address,
544 sf->s_bulk_stop (sf->cls);
549 GAS_plugin_delete_address (struct ATS_Address *address)
551 sf->s_del (sf->cls, address, GNUNET_NO);
556 GAS_plugin_update_preferences (void *client,
557 const struct GNUNET_PeerIdentity *peer,
558 enum GNUNET_ATS_PreferenceKind kind,
561 sf->s_bulk_start (sf->cls);
562 /* Tell normalization about change, normalization will call callback if preference changed */
563 GAS_normalization_normalize_preference (client, peer, kind, score_abs);
564 sf->s_bulk_stop (sf->cls);
569 GAS_plugin_preference_feedback (void *application,
570 const struct GNUNET_PeerIdentity *peer,
571 const struct GNUNET_TIME_Relative scope,
572 enum GNUNET_ATS_PreferenceKind kind,
575 sf->s_feedback (sf->cls,
585 GAS_plugin_solver_lock ()
587 sf->s_bulk_start (sf->cls);
592 GAS_plugin_solver_unlock ()
594 sf->s_bulk_start (sf->cls);
599 GAS_plugin_request_connect_start (const struct GNUNET_PeerIdentity *pid)
601 const struct ATS_Address *aa;
603 aa = sf->s_get (sf->cls, pid);
606 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
607 "Cannot suggest address for peer `%s'\n",
611 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
612 "Suggesting address %p for peer `%s'\n",
616 GAS_scheduling_transmit_address_suggestion (pid,
618 GNUNET_BANDWIDTH_value_init (aa->assigned_bw_out),
619 GNUNET_BANDWIDTH_value_init (aa->assigned_bw_in));
621 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
622 "Address %p ready for suggestion\n",
628 GAS_plugin_request_connect_stop (const struct GNUNET_PeerIdentity *pid)
630 sf->s_get_stop (sf->cls, pid);
634 /* end of gnunet-service-ats_plugins.c */