2 This file is part of GNUnet.
3 Copyright (C) 2011-2014 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 * @file ats/gnunet-service-ats_plugins.c
21 * @brief ats service plugin management
22 * @author Matthias Wachs
23 * @author Christian Grothoff
26 #include "gnunet_ats_plugin.h"
27 #include "gnunet-service-ats_connectivity.h"
28 #include "gnunet-service-ats_performance.h"
29 #include "gnunet-service-ats_preferences.h"
30 #include "gnunet-service-ats_plugins.h"
31 #include "gnunet-service-ats_reservations.h"
32 #include "gnunet-service-ats_scheduling.h"
33 #include "gnunet-service-ats_normalization.h"
39 static struct GNUNET_ATS_SolverFunctions *sf;
44 static struct GNUNET_ATS_PluginEnvironment env;
47 * Solver plugin name as string
53 * The preference changed for a peer, update solver.
55 * @param peer the peer
56 * @param kind the ATS kind
57 * @param pref_rel the new relative preference value
60 GAS_plugin_notify_preference_changed (const struct GNUNET_PeerIdentity *peer,
61 enum GNUNET_ATS_PreferenceKind kind,
72 * The relative value for a property changed.
74 * @param address the peer for which a property changed
77 GAS_plugin_notify_property_changed (struct ATS_Address *address)
79 sf->s_address_update_property (sf->cls,
85 * Solver information callback
87 * @param cls the closure
88 * @param op the operation
89 * @param status operation status
90 * @param add additional information
93 solver_info_cb (void *cls,
94 enum GAS_Solver_Operation op,
95 enum GAS_Solver_Status status,
96 enum GAS_Solver_Additional_Information add)
102 add_info = "GAS_INFO_NONE";
105 add_info = "GAS_INFO_MLP_FULL";
107 case GAS_INFO_UPDATED:
108 add_info = "GAS_INFO_MLP_UPDATED";
110 case GAS_INFO_PROP_ALL:
111 add_info = "GAS_INFO_PROP_ALL";
113 case GAS_INFO_PROP_SINGLE:
114 add_info = "GAS_INFO_PROP_SINGLE";
117 add_info = "INVALID";
122 case GAS_OP_SOLVE_START:
123 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
124 "Solver notifies `%s' with result `%s' `%s'\n",
125 "GAS_OP_SOLVE_START",
126 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL",
129 case GAS_OP_SOLVE_STOP:
130 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
131 "Solver notifies `%s' with result `%s'\n",
133 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
135 case GAS_OP_SOLVE_SETUP_START:
136 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
137 "Solver notifies `%s' with result `%s'\n",
138 "GAS_OP_SOLVE_SETUP_START",
139 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
141 case GAS_OP_SOLVE_SETUP_STOP:
142 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
143 "Solver notifies `%s' with result `%s'\n",
144 "GAS_OP_SOLVE_SETUP_STOP",
145 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
147 case GAS_OP_SOLVE_MLP_LP_START:
148 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
149 "Solver notifies `%s' with result `%s'\n",
150 "GAS_OP_SOLVE_LP_START",
151 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
153 case GAS_OP_SOLVE_MLP_LP_STOP:
154 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
155 "Solver notifies `%s' with result `%s'\n",
156 "GAS_OP_SOLVE_LP_STOP",
157 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
159 case GAS_OP_SOLVE_MLP_MLP_START:
160 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
161 "Solver notifies `%s' with result `%s'\n",
162 "GAS_OP_SOLVE_MLP_START",
163 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
165 case GAS_OP_SOLVE_MLP_MLP_STOP:
166 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
167 "Solver notifies `%s' with result `%s'\n",
168 "GAS_OP_SOLVE_MLP_STOP",
169 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
171 case GAS_OP_SOLVE_UPDATE_NOTIFICATION_START:
172 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
173 "Solver notifies `%s' with result `%s'\n",
174 "GAS_OP_SOLVE_UPDATE_NOTIFICATION_START",
175 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
177 case GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP:
178 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
179 "Solver notifies `%s' with result `%s'\n",
180 "GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP",
181 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
191 * Callback for solver to notify about assignment changes
194 * @param address the address with changes
197 bandwidth_changed_cb (void *cls,
198 struct ATS_Address *address)
203 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
204 "Bandwidth assignment changed for peer %s to %u/%u\n",
205 GNUNET_i2s (&address->peer),
206 (unsigned int) address->assigned_bw_in,
207 (unsigned int) address->assigned_bw_out);
208 GAS_reservations_set_bandwidth (&address->peer,
209 GNUNET_BANDWIDTH_value_init (address->assigned_bw_in));
210 /* Notify performance clients about changes to address */
211 GAS_performance_notify_all_clients (&address->peer,
216 &address->properties,
217 address->local_address_info,
218 GNUNET_BANDWIDTH_value_init (address->assigned_bw_out),
219 GNUNET_BANDWIDTH_value_init (address->assigned_bw_in));
221 if ( (0 == address->assigned_bw_in) &&
222 (0 == address->assigned_bw_out) )
224 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
225 "Telling transport to disconnect peer `%s'\n",
226 GNUNET_i2s (&address->peer));
228 /* Notify scheduling clients about suggestion */
229 GAS_scheduling_transmit_address_suggestion (&address->peer,
231 GNUNET_BANDWIDTH_ZERO,
232 GNUNET_BANDWIDTH_ZERO);
236 /* Do bandwidth stability check */
237 diff_out = llabs ((long long) address->assigned_bw_out -
238 (long long) address->last_notified_bw_out);
239 diff_in = llabs ((long long) address->assigned_bw_in -
240 (long long) address->last_notified_bw_in);
241 if ( (diff_out < htonl (GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__)) &&
242 (diff_in < htonl (GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__)) )
244 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
245 "Bandwidth change too small, not notifying client\n");
249 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
250 "Sending bandwidth update for peer `%s': %u/%u\n",
251 GNUNET_i2s (&address->peer),
252 address->assigned_bw_out,
253 address->assigned_bw_out);
255 /* *Notify scheduling clients about suggestion */
256 GAS_scheduling_transmit_address_suggestion (&address->peer,
258 GNUNET_BANDWIDTH_value_init (address->assigned_bw_out),
259 GNUNET_BANDWIDTH_value_init (address->assigned_bw_in));
261 address->last_notified_bw_out = address->assigned_bw_out;
262 address->last_notified_bw_in = address->assigned_bw_in;
267 * Convert quota from text to numeric value.
269 * @param quota_str the value found in the configuration
270 * @param direction direction of the quota
271 * @param network network the quota applies to
272 * @return numeric quota value to use
274 static unsigned long long
275 parse_quota (const char *quota_str,
276 const char *direction,
277 enum GNUNET_ATS_Network_Type network)
280 unsigned long long ret;
283 if (0 == strcmp (quota_str, GNUNET_ATS_MaxBandwidthString))
285 ret = GNUNET_ATS_MaxBandwidth;
288 if ((GNUNET_NO == res) &&
290 GNUNET_STRINGS_fancy_size_to_bytes (quota_str,
293 if ((GNUNET_NO == res) &&
299 if (GNUNET_NO == res)
301 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
302 _("Could not load %s quota for network `%s': `%s', assigning default bandwidth %llu\n"),
304 GNUNET_ATS_print_network_type (network),
306 (unsigned long long) GNUNET_ATS_DefaultBandwidth);
307 ret = GNUNET_ATS_DefaultBandwidth;
311 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
312 _("%s quota configured for network `%s' is %llu\n"),
314 GNUNET_ATS_print_network_type (network),
322 * Load quota value from the configuration @a cfg for the
323 * given network @a type and @a direction.
325 * @param cfg configuration to parse
326 * @param type network type to parse for
327 * @param direction traffic direction to parse for
328 * @return quota to apply
330 static unsigned long long
331 load_quota (const struct GNUNET_CONFIGURATION_Handle *cfg,
332 enum GNUNET_ATS_Network_Type type,
333 const char *direction)
337 unsigned long long ret;
339 GNUNET_asprintf (&entry,
341 GNUNET_ATS_print_network_type (type),
344 GNUNET_CONFIGURATION_get_value_string (cfg,
349 ret = parse_quota (quota_str,
352 GNUNET_free (quota_str);
356 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
357 _("No %s-quota configured for network `%s', assigning default bandwidth %llu\n"),
359 GNUNET_ATS_print_network_type (type),
360 (unsigned long long) GNUNET_ATS_DefaultBandwidth);
361 ret = GNUNET_ATS_DefaultBandwidth;
369 * Load quotas for networks from configuration
371 * @param cfg configuration handle
372 * @param out_dest where to write outbound quotas
373 * @param in_dest where to write inbound quotas
374 * @param dest_length length of inbound and outbound arrays
375 * @return number of networks loaded
378 load_quotas (const struct GNUNET_CONFIGURATION_Handle *cfg,
379 unsigned long long *out_dest,
380 unsigned long long *in_dest,
385 for (c = 0; (c < GNUNET_ATS_NetworkTypeCount) && (c < dest_length); c++)
387 in_dest[c] = load_quota (cfg,
390 out_dest[c] = load_quota (cfg,
393 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
394 "Loaded quota for network `%s' (in/out): %llu %llu\n",
395 GNUNET_ATS_print_network_type (c),
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_plugin_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
415 /* Figure out configured solution method */
417 GNUNET_CONFIGURATION_get_value_string (cfg,
422 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
423 "No resource assignment method configured, using proportional approach\n");
424 mode_str = GNUNET_strdup ("proportional");
427 env.info_cb = &solver_info_cb;
428 env.bandwidth_changed_cb = &bandwidth_changed_cb;
429 env.get_preferences = &GAS_preference_get_by_peer;
430 env.get_connectivity = &GAS_connectivity_has_peer;
432 env.stats = GSA_stats;
433 env.addresses = GSA_addresses;
434 env.network_count = GNUNET_ATS_NetworkTypeCount;
438 GNUNET_ATS_NetworkTypeCount);
439 GNUNET_asprintf (&plugin,
440 "libgnunet_plugin_ats_%s",
442 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
443 "Initializing solver `%s'\n",
445 GNUNET_free (mode_str);
446 if (NULL == (sf = GNUNET_PLUGIN_load (plugin, &env)))
448 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
449 _("Failed to initialize solver `%s'!\n"),
451 return GNUNET_SYSERR;
458 * Shutdown address subsystem.
463 GNUNET_PLUGIN_unload (plugin,
466 GNUNET_free (plugin);
472 * Tell the solver that the given address can now be used
473 * for talking to the respective peer.
475 * @param new_address the new address
478 GAS_plugin_new_address (struct ATS_Address *new_address)
482 new_address->properties.scope); /* FIXME: remove 3rd arg here! */
487 * Tell the solver that the given address is no longer valid
488 * can cannot be used any longer.
490 * @param address address that was deleted
493 GAS_plugin_delete_address (struct ATS_Address *address)
501 * Tell the solver that the given client has expressed its
502 * appreciation for the past performance of a given connection.
504 * @param application client providing the feedback
505 * @param peer peer the feedback is about
506 * @param scope timeframe the feedback applies to
507 * @param kind performance property the feedback relates to
508 * @param score_abs degree of the appreciation
511 GAS_plugin_notify_feedback (struct GNUNET_SERVICE_Client *application,
512 const struct GNUNET_PeerIdentity *peer,
513 const struct GNUNET_TIME_Relative scope,
514 enum GNUNET_ATS_PreferenceKind kind,
517 sf->s_feedback (sf->cls,
527 * Stop instant solving, there are many state updates
528 * happening in bulk right now.
531 GAS_plugin_solver_lock ()
533 sf->s_bulk_start (sf->cls);
538 * Resume instant solving, we are done with the bulk state updates.
541 GAS_plugin_solver_unlock ()
543 sf->s_bulk_stop (sf->cls);
548 * Notify the plugin that a request to connect to
549 * a particular peer was given to us.
551 * @param pid identity of peer we now care about
554 GAS_plugin_request_connect_start (const struct GNUNET_PeerIdentity *pid)
562 * Notify the plugin that a request to connect to
563 * a particular peer was dropped.
565 * @param pid identity of peer we care now less about
568 GAS_plugin_request_connect_stop (const struct GNUNET_PeerIdentity *pid)
570 sf->s_get_stop (sf->cls,
575 /* end of gnunet-service-ats_plugins.c */