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"
40 static struct GNUNET_ATS_SolverFunctions *sf;
45 static struct GNUNET_ATS_PluginEnvironment env;
48 * Solver plugin name as string
54 * The preference changed for a peer, update solver.
56 * @param peer the peer
57 * @param kind the ATS kind
58 * @param pref_rel the new relative preference value
61 GAS_normalized_preference_changed (const struct GNUNET_PeerIdentity *peer,
62 enum GNUNET_ATS_PreferenceKind kind,
73 * The relative value for a property changed
75 * @param address the peer
76 * @param type the ATS type
77 * @param prop_rel the new relative preference value
80 GAS_normalized_property_changed (struct ATS_Address *address,
84 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
85 "Normalized property %s for peer `%s' changed to %.3f \n",
86 GNUNET_ATS_print_property_type (type),
87 GNUNET_i2s (&address->peer),
89 sf->s_address_update_property (sf->cls,
98 * Solver information callback
100 * @param cls the closure
101 * @param op the operation
102 * @param status operation status
103 * @param add additional information
106 solver_info_cb (void *cls,
107 enum GAS_Solver_Operation op,
108 enum GAS_Solver_Status status,
109 enum GAS_Solver_Additional_Information add)
111 const char *add_info;
115 add_info = "GAS_INFO_NONE";
118 add_info = "GAS_INFO_MLP_FULL";
120 case GAS_INFO_UPDATED:
121 add_info = "GAS_INFO_MLP_UPDATED";
123 case GAS_INFO_PROP_ALL:
124 add_info = "GAS_INFO_PROP_ALL";
126 case GAS_INFO_PROP_SINGLE:
127 add_info = "GAS_INFO_PROP_SINGLE";
130 add_info = "INVALID";
135 case GAS_OP_SOLVE_START:
136 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
137 "Solver notifies `%s' with result `%s' `%s'\n",
138 "GAS_OP_SOLVE_START",
139 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL",
142 case GAS_OP_SOLVE_STOP:
143 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
144 "Solver notifies `%s' with result `%s'\n",
146 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL",
149 case GAS_OP_SOLVE_SETUP_START:
150 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
151 "Solver notifies `%s' with result `%s'\n",
152 "GAS_OP_SOLVE_SETUP_START",
153 (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",
158 "GAS_OP_SOLVE_SETUP_STOP",
159 (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",
164 "GAS_OP_SOLVE_LP_START",
165 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
167 case GAS_OP_SOLVE_MLP_LP_STOP:
168 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
169 "Solver notifies `%s' with result `%s'\n",
170 "GAS_OP_SOLVE_LP_STOP",
171 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
173 case GAS_OP_SOLVE_MLP_MLP_START:
174 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
175 "Solver notifies `%s' with result `%s'\n",
176 "GAS_OP_SOLVE_MLP_START",
177 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
179 case GAS_OP_SOLVE_MLP_MLP_STOP:
180 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
181 "Solver notifies `%s' with result `%s'\n",
182 "GAS_OP_SOLVE_MLP_STOP",
183 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
185 case GAS_OP_SOLVE_UPDATE_NOTIFICATION_START:
186 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
187 "Solver notifies `%s' with result `%s'\n",
188 "GAS_OP_SOLVE_UPDATE_NOTIFICATION_START",
189 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
191 case GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP:
192 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
193 "Solver notifies `%s' with result `%s'\n",
194 "GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP",
195 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
204 * Callback for solver to notify about assignment changes
207 * @param address the address with changes
210 bandwidth_changed_cb (void *cls,
211 struct ATS_Address *address)
216 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
217 "Bandwidth assignment changed for peer %s \n",
218 GNUNET_i2s (&address->peer));
220 /* Notify performance clients about changes to address */
221 GAS_performance_notify_all_clients (&address->peer,
228 GNUNET_BANDWIDTH_value_init (address->assigned_bw_out),
229 GNUNET_BANDWIDTH_value_init (address->assigned_bw_in));
231 if ( (0 == address->assigned_bw_in) &&
232 (0 == address->assigned_bw_out) )
234 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
235 "Telling transport to disconnect peer `%s'\n",
236 GNUNET_i2s (&address->peer));
238 /* Notify scheduling clients about suggestion */
239 GAS_scheduling_transmit_address_suggestion (&address->peer,
241 GNUNET_BANDWIDTH_ZERO,
242 GNUNET_BANDWIDTH_ZERO);
246 /* Do bandwidth stability check */
247 diff_out = abs (address->assigned_bw_out - address->last_notified_bw_out);
248 diff_in = abs (address->assigned_bw_in - address->last_notified_bw_in);
250 if ( (diff_out < htonl(GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__)) &&
251 (diff_in < htonl(GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__)) )
254 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
255 "Sending bandwidth update for peer `%s': %u/%u\n",
256 GNUNET_i2s (&address->peer),
257 address->assigned_bw_out,
258 address->assigned_bw_out);
260 /* *Notify scheduling clients about suggestion */
261 GAS_scheduling_transmit_address_suggestion (&address->peer,
263 GNUNET_BANDWIDTH_value_init (address->assigned_bw_out),
264 GNUNET_BANDWIDTH_value_init (address->assigned_bw_in));
266 address->last_notified_bw_out = address->assigned_bw_out;
267 address->last_notified_bw_in = address->assigned_bw_in;
272 * Convert quota from text to numeric value.
274 * @param quota_str the value found in the configuration
275 * @param direction direction of the quota
276 * @param network network the quota applies to
277 * @return numeric quota value to use
279 static unsigned long long
280 parse_quota (const char *quota_str,
281 const char *direction,
282 enum GNUNET_ATS_Network_Type network)
285 unsigned long long ret;
288 if (0 == strcmp (quota_str, GNUNET_ATS_MaxBandwidthString))
290 ret = GNUNET_ATS_MaxBandwidth;
293 if ((GNUNET_NO == res) &&
295 GNUNET_STRINGS_fancy_size_to_bytes (quota_str,
298 if ((GNUNET_NO == res) &&
304 if (GNUNET_NO == res)
306 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
307 _("Could not load %s quota for network `%s': `%s', assigning default bandwidth %llu\n"),
309 GNUNET_ATS_print_network_type (network),
311 GNUNET_ATS_DefaultBandwidth);
312 ret = GNUNET_ATS_DefaultBandwidth;
316 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
317 _("%s quota configured for network `%s' is %llu\n"),
319 GNUNET_ATS_print_network_type (network),
327 * Load quota value from the configuration @a cfg for the
328 * given network @a type and @a direction.
330 * @param cfg configuration to parse
331 * @param type network type to parse for
332 * @param direction traffic direction to parse for
333 * @return quota to apply
335 static unsigned long long
336 load_quota (const struct GNUNET_CONFIGURATION_Handle *cfg,
337 enum GNUNET_ATS_Network_Type type,
338 const char *direction)
342 unsigned long long ret;
344 GNUNET_asprintf (&entry,
346 GNUNET_ATS_print_network_type (type),
349 GNUNET_CONFIGURATION_get_value_string (cfg,
354 ret = parse_quota (quota_str,
357 GNUNET_free (quota_str);
361 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
362 _("No %s-quota configured for network `%s', assigning default bandwidth %llu\n"),
364 GNUNET_ATS_print_network_type (type),
365 GNUNET_ATS_DefaultBandwidth);
366 ret = GNUNET_ATS_DefaultBandwidth;
374 * Load quotas for networks from configuration
376 * @param cfg configuration handle
377 * @param out_dest where to write outbound quotas
378 * @param in_dest where to write inbound quotas
379 * @param dest_length length of inbound and outbound arrays
380 * @return number of networks loaded
383 load_quotas (const struct GNUNET_CONFIGURATION_Handle *cfg,
384 unsigned long long *out_dest,
385 unsigned long long *in_dest,
390 for (c = 0; (c < GNUNET_ATS_NetworkTypeCount) && (c < dest_length); c++)
392 in_dest[c] = load_quota (cfg,
395 out_dest[c] = load_quota (cfg,
398 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
399 "Loaded quota for network `%s' (in/out): %llu %llu\n",
400 GNUNET_ATS_print_network_type (c),
409 * Initialize plugins subsystem.
411 * @param cfg configuration to use
412 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error (failed to load
416 GAS_plugins_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
418 unsigned long long quotas_in[GNUNET_ATS_NetworkTypeCount];
419 unsigned long long quotas_out[GNUNET_ATS_NetworkTypeCount];
423 /* Figure out configured solution method */
425 GNUNET_CONFIGURATION_get_value_string (cfg,
430 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
431 "No resource assignment method configured, using proportional approach\n");
432 mode_str = GNUNET_strdup ("proportional");
437 GNUNET_ATS_NetworkTypeCount);
439 env.info_cb = &solver_info_cb;
440 env.bandwidth_changed_cb = &bandwidth_changed_cb;
441 env.get_preferences = &GAS_normalization_get_preferences_by_peer;
442 env.get_property = &GAS_normalization_get_properties;
444 env.stats = GSA_stats;
445 env.addresses = GSA_addresses;
446 env.network_count = GNUNET_ATS_NetworkTypeCount;
447 for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
449 env.out_quota[c] = quotas_out[c];
450 env.in_quota[c] = quotas_in[c];
453 GNUNET_asprintf (&plugin,
454 "libgnunet_plugin_ats_%s",
456 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
457 "Initializing solver `%s'\n",
459 GNUNET_free (mode_str);
460 if (NULL == (sf = GNUNET_PLUGIN_load (plugin, &env)))
462 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
463 _("Failed to initialize solver `%s'!\n"),
465 return GNUNET_SYSERR;
472 * Shutdown address subsystem.
477 GNUNET_PLUGIN_unload (plugin,
480 GNUNET_free (plugin);
486 * Tell the solver that the given address can now be used
487 * for talking to the respective peer.
489 * @param new_address the new address
490 * @param addr_net network scope the address is in
491 * @param atsi performance data for the address
492 * @param atsi_count size of the @a atsi array
495 GAS_plugin_new_address (struct ATS_Address *new_address,
496 enum GNUNET_ATS_Network_Type addr_net,
497 const struct GNUNET_ATS_Information *atsi,
503 sf->s_bulk_start (sf->cls);
504 GAS_normalization_normalize_property (new_address,
507 sf->s_bulk_stop (sf->cls);
512 * Tell the solver that the given address is no longer valid
513 * can cannot be used any longer.
515 * @param address address that was deleted
518 GAS_plugin_delete_address (struct ATS_Address *address)
527 * Tell the solver that the given client has expressed its
528 * appreciation for the past performance of a given connection.
530 * @param application client providing the feedback
531 * @param peer peer the feedback is about
532 * @param scope timeframe the feedback applies to
533 * @param kind performance property the feedback relates to
534 * @param score_abs degree of the appreciation
537 GAS_plugin_preference_feedback (struct GNUNET_SERVER_Client *application,
538 const struct GNUNET_PeerIdentity *peer,
539 const struct GNUNET_TIME_Relative scope,
540 enum GNUNET_ATS_PreferenceKind kind,
543 sf->s_feedback (sf->cls,
553 * Stop instant solving, there are many state updates
554 * happening in bulk right now.
557 GAS_plugin_solver_lock ()
559 sf->s_bulk_start (sf->cls);
564 * Resume instant solving, we are done with the bulk state updates.
567 GAS_plugin_solver_unlock ()
569 sf->s_bulk_start (sf->cls);
574 * Notify the plugin that a request to connect to
575 * a particular peer was given to us.
577 * @param pid identity of peer we now care about
580 GAS_plugin_request_connect_start (const struct GNUNET_PeerIdentity *pid)
582 const struct ATS_Address *aa;
584 aa = sf->s_get (sf->cls, pid);
587 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
588 "Cannot suggest address for peer `%s'\n",
592 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
593 "Suggesting address %p for peer `%s'\n",
596 GAS_scheduling_transmit_address_suggestion (pid,
598 GNUNET_BANDWIDTH_value_init (aa->assigned_bw_out),
599 GNUNET_BANDWIDTH_value_init (aa->assigned_bw_in));
604 * Notify the plugin that a request to connect to
605 * a particular peer was dropped.
607 * @param pid identity of peer we care now less about
610 GAS_plugin_request_connect_stop (const struct GNUNET_PeerIdentity *pid)
612 sf->s_get_stop (sf->cls,
617 /* end of gnunet-service-ats_plugins.c */