2 This file is part of GNUnet.
3 Copyright (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., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, 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_reservations.h"
34 #include "gnunet-service-ats_scheduling.h"
35 #include "gnunet-service-ats_normalization.h"
41 static struct GNUNET_ATS_SolverFunctions *sf;
46 static struct GNUNET_ATS_PluginEnvironment env;
49 * Solver plugin name as string
55 * The preference changed for a peer, update solver.
57 * @param peer the peer
58 * @param kind the ATS kind
59 * @param pref_rel the new relative preference value
62 GAS_plugin_notify_preference_changed (const struct GNUNET_PeerIdentity *peer,
63 enum GNUNET_ATS_PreferenceKind kind,
74 * The relative value for a property changed.
76 * @param address the peer for which a property changed
79 GAS_plugin_notify_property_changed (struct ATS_Address *address)
81 sf->s_address_update_property (sf->cls,
87 * Solver information callback
89 * @param cls the closure
90 * @param op the operation
91 * @param status operation status
92 * @param add additional information
95 solver_info_cb (void *cls,
96 enum GAS_Solver_Operation op,
97 enum GAS_Solver_Status status,
98 enum GAS_Solver_Additional_Information add)
100 const char *add_info;
104 add_info = "GAS_INFO_NONE";
107 add_info = "GAS_INFO_MLP_FULL";
109 case GAS_INFO_UPDATED:
110 add_info = "GAS_INFO_MLP_UPDATED";
112 case GAS_INFO_PROP_ALL:
113 add_info = "GAS_INFO_PROP_ALL";
115 case GAS_INFO_PROP_SINGLE:
116 add_info = "GAS_INFO_PROP_SINGLE";
119 add_info = "INVALID";
124 case GAS_OP_SOLVE_START:
125 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
126 "Solver notifies `%s' with result `%s' `%s'\n",
127 "GAS_OP_SOLVE_START",
128 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL",
131 case GAS_OP_SOLVE_STOP:
132 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
133 "Solver notifies `%s' with result `%s'\n",
135 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL",
138 case GAS_OP_SOLVE_SETUP_START:
139 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
140 "Solver notifies `%s' with result `%s'\n",
141 "GAS_OP_SOLVE_SETUP_START",
142 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
144 case GAS_OP_SOLVE_SETUP_STOP:
145 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
146 "Solver notifies `%s' with result `%s'\n",
147 "GAS_OP_SOLVE_SETUP_STOP",
148 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
150 case GAS_OP_SOLVE_MLP_LP_START:
151 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
152 "Solver notifies `%s' with result `%s'\n",
153 "GAS_OP_SOLVE_LP_START",
154 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
156 case GAS_OP_SOLVE_MLP_LP_STOP:
157 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
158 "Solver notifies `%s' with result `%s'\n",
159 "GAS_OP_SOLVE_LP_STOP",
160 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
162 case GAS_OP_SOLVE_MLP_MLP_START:
163 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
164 "Solver notifies `%s' with result `%s'\n",
165 "GAS_OP_SOLVE_MLP_START",
166 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
168 case GAS_OP_SOLVE_MLP_MLP_STOP:
169 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
170 "Solver notifies `%s' with result `%s'\n",
171 "GAS_OP_SOLVE_MLP_STOP",
172 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
174 case GAS_OP_SOLVE_UPDATE_NOTIFICATION_START:
175 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
176 "Solver notifies `%s' with result `%s'\n",
177 "GAS_OP_SOLVE_UPDATE_NOTIFICATION_START",
178 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
180 case GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP:
181 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
182 "Solver notifies `%s' with result `%s'\n",
183 "GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP",
184 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
194 * Callback for solver to notify about assignment changes
197 * @param address the address with changes
200 bandwidth_changed_cb (void *cls,
201 struct ATS_Address *address)
206 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
207 "Bandwidth assignment changed for peer %s to %u/%u\n",
208 GNUNET_i2s (&address->peer),
209 (unsigned int) address->assigned_bw_in,
210 (unsigned int) address->assigned_bw_out);
211 GAS_reservations_set_bandwidth (&address->peer,
212 GNUNET_BANDWIDTH_value_init (address->assigned_bw_in));
213 /* Notify performance clients about changes to address */
214 GAS_performance_notify_all_clients (&address->peer,
219 &address->properties,
220 address->local_address_info,
221 GNUNET_BANDWIDTH_value_init (address->assigned_bw_out),
222 GNUNET_BANDWIDTH_value_init (address->assigned_bw_in));
224 if ( (0 == address->assigned_bw_in) &&
225 (0 == address->assigned_bw_out) )
227 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
228 "Telling transport to disconnect peer `%s'\n",
229 GNUNET_i2s (&address->peer));
231 /* Notify scheduling clients about suggestion */
232 GAS_scheduling_transmit_address_suggestion (&address->peer,
234 GNUNET_BANDWIDTH_ZERO,
235 GNUNET_BANDWIDTH_ZERO);
239 /* Do bandwidth stability check */
240 diff_out = llabs ((long long) address->assigned_bw_out -
241 (long long) address->last_notified_bw_out);
242 diff_in = llabs ((long long) address->assigned_bw_in -
243 (long long) 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__)) )
247 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
248 "Bandwidth change too small, not notifying client\n");
252 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
253 "Sending bandwidth update for peer `%s': %u/%u\n",
254 GNUNET_i2s (&address->peer),
255 address->assigned_bw_out,
256 address->assigned_bw_out);
258 /* *Notify scheduling clients about suggestion */
259 GAS_scheduling_transmit_address_suggestion (&address->peer,
261 GNUNET_BANDWIDTH_value_init (address->assigned_bw_out),
262 GNUNET_BANDWIDTH_value_init (address->assigned_bw_in));
264 address->last_notified_bw_out = address->assigned_bw_out;
265 address->last_notified_bw_in = address->assigned_bw_in;
270 * Convert quota from text to numeric value.
272 * @param quota_str the value found in the configuration
273 * @param direction direction of the quota
274 * @param network network the quota applies to
275 * @return numeric quota value to use
277 static unsigned long long
278 parse_quota (const char *quota_str,
279 const char *direction,
280 enum GNUNET_ATS_Network_Type network)
283 unsigned long long ret;
286 if (0 == strcmp (quota_str, GNUNET_ATS_MaxBandwidthString))
288 ret = GNUNET_ATS_MaxBandwidth;
291 if ((GNUNET_NO == res) &&
293 GNUNET_STRINGS_fancy_size_to_bytes (quota_str,
296 if ((GNUNET_NO == res) &&
302 if (GNUNET_NO == res)
304 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
305 _("Could not load %s quota for network `%s': `%s', assigning default bandwidth %llu\n"),
307 GNUNET_ATS_print_network_type (network),
309 GNUNET_ATS_DefaultBandwidth);
310 ret = GNUNET_ATS_DefaultBandwidth;
314 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
315 _("%s quota configured for network `%s' is %llu\n"),
317 GNUNET_ATS_print_network_type (network),
325 * Load quota value from the configuration @a cfg for the
326 * given network @a type and @a direction.
328 * @param cfg configuration to parse
329 * @param type network type to parse for
330 * @param direction traffic direction to parse for
331 * @return quota to apply
333 static unsigned long long
334 load_quota (const struct GNUNET_CONFIGURATION_Handle *cfg,
335 enum GNUNET_ATS_Network_Type type,
336 const char *direction)
340 unsigned long long ret;
342 GNUNET_asprintf (&entry,
344 GNUNET_ATS_print_network_type (type),
347 GNUNET_CONFIGURATION_get_value_string (cfg,
352 ret = parse_quota (quota_str,
355 GNUNET_free (quota_str);
359 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
360 _("No %s-quota configured for network `%s', assigning default bandwidth %llu\n"),
362 GNUNET_ATS_print_network_type (type),
363 GNUNET_ATS_DefaultBandwidth);
364 ret = GNUNET_ATS_DefaultBandwidth;
372 * Load quotas for networks from configuration
374 * @param cfg configuration handle
375 * @param out_dest where to write outbound quotas
376 * @param in_dest where to write inbound quotas
377 * @param dest_length length of inbound and outbound arrays
378 * @return number of networks loaded
381 load_quotas (const struct GNUNET_CONFIGURATION_Handle *cfg,
382 unsigned long long *out_dest,
383 unsigned long long *in_dest,
388 for (c = 0; (c < GNUNET_ATS_NetworkTypeCount) && (c < dest_length); c++)
390 in_dest[c] = load_quota (cfg,
393 out_dest[c] = load_quota (cfg,
396 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
397 "Loaded quota for network `%s' (in/out): %llu %llu\n",
398 GNUNET_ATS_print_network_type (c),
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_plugin_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
418 /* Figure out configured solution method */
420 GNUNET_CONFIGURATION_get_value_string (cfg,
425 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
426 "No resource assignment method configured, using proportional approach\n");
427 mode_str = GNUNET_strdup ("proportional");
430 env.info_cb = &solver_info_cb;
431 env.bandwidth_changed_cb = &bandwidth_changed_cb;
432 env.get_preferences = &GAS_preference_get_by_peer;
433 env.get_connectivity = &GAS_connectivity_has_peer;
435 env.stats = GSA_stats;
436 env.addresses = GSA_addresses;
437 env.network_count = GNUNET_ATS_NetworkTypeCount;
441 GNUNET_ATS_NetworkTypeCount);
442 GNUNET_asprintf (&plugin,
443 "libgnunet_plugin_ats_%s",
445 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
446 "Initializing solver `%s'\n",
448 GNUNET_free (mode_str);
449 if (NULL == (sf = GNUNET_PLUGIN_load (plugin, &env)))
451 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
452 _("Failed to initialize solver `%s'!\n"),
454 return GNUNET_SYSERR;
461 * Shutdown address subsystem.
466 GNUNET_PLUGIN_unload (plugin,
469 GNUNET_free (plugin);
475 * Tell the solver that the given address can now be used
476 * for talking to the respective peer.
478 * @param new_address the new address
481 GAS_plugin_new_address (struct ATS_Address *new_address)
485 new_address->properties.scope); /* FIXME: remove 3rd arg here! */
490 * Tell the solver that the given address is no longer valid
491 * can cannot be used any longer.
493 * @param address address that was deleted
496 GAS_plugin_delete_address (struct ATS_Address *address)
504 * Tell the solver that the given client has expressed its
505 * appreciation for the past performance of a given connection.
507 * @param application client providing the feedback
508 * @param peer peer the feedback is about
509 * @param scope timeframe the feedback applies to
510 * @param kind performance property the feedback relates to
511 * @param score_abs degree of the appreciation
514 GAS_plugin_notify_feedback (struct GNUNET_SERVER_Client *application,
515 const struct GNUNET_PeerIdentity *peer,
516 const struct GNUNET_TIME_Relative scope,
517 enum GNUNET_ATS_PreferenceKind kind,
520 sf->s_feedback (sf->cls,
530 * Stop instant solving, there are many state updates
531 * happening in bulk right now.
534 GAS_plugin_solver_lock ()
536 sf->s_bulk_start (sf->cls);
541 * Resume instant solving, we are done with the bulk state updates.
544 GAS_plugin_solver_unlock ()
546 sf->s_bulk_stop (sf->cls);
551 * Notify the plugin that a request to connect to
552 * a particular peer was given to us.
554 * @param pid identity of peer we now care about
557 GAS_plugin_request_connect_start (const struct GNUNET_PeerIdentity *pid)
565 * Notify the plugin that a request to connect to
566 * a particular peer was dropped.
568 * @param pid identity of peer we care now less about
571 GAS_plugin_request_connect_stop (const struct GNUNET_PeerIdentity *pid)
573 sf->s_get_stop (sf->cls,
578 /* end of gnunet-service-ats_plugins.c */