123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608 |
- /*
- This file is part of GNUnet.
- Copyright (C) 2011-2014 Christian Grothoff (and other contributing authors)
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
- */
- /**
- * @file ats/gnunet-service-ats_plugins.c
- * @brief ats service plugin management
- * @author Matthias Wachs
- * @author Christian Grothoff
- */
- #include "platform.h"
- #include "gnunet_ats_plugin.h"
- #include "gnunet-service-ats_connectivity.h"
- #include "gnunet-service-ats_performance.h"
- #include "gnunet-service-ats_preferences.h"
- #include "gnunet-service-ats_plugins.h"
- #include "gnunet-service-ats_scheduling.h"
- #include "gnunet-service-ats_normalization.h"
- /**
- * Solver handle.
- */
- static struct GNUNET_ATS_SolverFunctions *sf;
- /**
- * Solver environment.
- */
- static struct GNUNET_ATS_PluginEnvironment env;
- /**
- * Solver plugin name as string
- */
- static char *plugin;
- /**
- * The preference changed for a peer, update solver.
- *
- * @param peer the peer
- * @param kind the ATS kind
- * @param pref_rel the new relative preference value
- */
- void
- GAS_normalized_preference_changed (const struct GNUNET_PeerIdentity *peer,
- enum GNUNET_ATS_PreferenceKind kind,
- double pref_rel)
- {
- sf->s_pref (sf->cls,
- peer,
- kind,
- pref_rel);
- }
- /**
- * The relative value for a property changed
- *
- * @param address the peer
- * @param type the ATS type
- * @param prop_rel the new relative preference value
- */
- void
- GAS_normalized_property_changed (struct ATS_Address *address,
- uint32_t type,
- double prop_rel)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Normalized property %s for peer `%s' changed to %.3f \n",
- GNUNET_ATS_print_property_type (type),
- GNUNET_i2s (&address->peer),
- prop_rel);
- sf->s_address_update_property (sf->cls,
- address,
- type,
- 0,
- prop_rel);
- }
- /**
- * Solver information callback
- *
- * @param cls the closure
- * @param op the operation
- * @param status operation status
- * @param add additional information
- */
- static void
- solver_info_cb (void *cls,
- enum GAS_Solver_Operation op,
- enum GAS_Solver_Status status,
- enum GAS_Solver_Additional_Information add)
- {
- const char *add_info;
- switch (add) {
- case GAS_INFO_NONE:
- add_info = "GAS_INFO_NONE";
- break;
- case GAS_INFO_FULL:
- add_info = "GAS_INFO_MLP_FULL";
- break;
- case GAS_INFO_UPDATED:
- add_info = "GAS_INFO_MLP_UPDATED";
- break;
- case GAS_INFO_PROP_ALL:
- add_info = "GAS_INFO_PROP_ALL";
- break;
- case GAS_INFO_PROP_SINGLE:
- add_info = "GAS_INFO_PROP_SINGLE";
- break;
- default:
- add_info = "INVALID";
- break;
- }
- switch (op)
- {
- case GAS_OP_SOLVE_START:
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Solver notifies `%s' with result `%s' `%s'\n",
- "GAS_OP_SOLVE_START",
- (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL",
- add_info);
- return;
- case GAS_OP_SOLVE_STOP:
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Solver notifies `%s' with result `%s'\n",
- "GAS_OP_SOLVE_STOP",
- (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL",
- add_info);
- return;
- case GAS_OP_SOLVE_SETUP_START:
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Solver notifies `%s' with result `%s'\n",
- "GAS_OP_SOLVE_SETUP_START",
- (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
- return;
- case GAS_OP_SOLVE_SETUP_STOP:
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Solver notifies `%s' with result `%s'\n",
- "GAS_OP_SOLVE_SETUP_STOP",
- (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
- return;
- case GAS_OP_SOLVE_MLP_LP_START:
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Solver notifies `%s' with result `%s'\n",
- "GAS_OP_SOLVE_LP_START",
- (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
- return;
- case GAS_OP_SOLVE_MLP_LP_STOP:
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Solver notifies `%s' with result `%s'\n",
- "GAS_OP_SOLVE_LP_STOP",
- (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
- return;
- case GAS_OP_SOLVE_MLP_MLP_START:
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Solver notifies `%s' with result `%s'\n",
- "GAS_OP_SOLVE_MLP_START",
- (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
- return;
- case GAS_OP_SOLVE_MLP_MLP_STOP:
- GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
- "Solver notifies `%s' with result `%s'\n",
- "GAS_OP_SOLVE_MLP_STOP",
- (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
- return;
- case GAS_OP_SOLVE_UPDATE_NOTIFICATION_START:
- GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
- "Solver notifies `%s' with result `%s'\n",
- "GAS_OP_SOLVE_UPDATE_NOTIFICATION_START",
- (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
- return;
- case GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP:
- GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
- "Solver notifies `%s' with result `%s'\n",
- "GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP",
- (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
- return;
- default:
- break;
- }
- }
- /**
- * Callback for solver to notify about assignment changes
- *
- * @param cls NULL
- * @param address the address with changes
- */
- static void
- bandwidth_changed_cb (void *cls,
- struct ATS_Address *address)
- {
- uint32_t diff_out;
- uint32_t diff_in;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Bandwidth assignment changed for peer %s \n",
- GNUNET_i2s (&address->peer));
- /* Notify performance clients about changes to address */
- GAS_performance_notify_all_clients (&address->peer,
- address->plugin,
- address->addr,
- address->addr_len,
- address->active,
- address->atsi,
- address->atsi_count,
- GNUNET_BANDWIDTH_value_init (address->assigned_bw_out),
- GNUNET_BANDWIDTH_value_init (address->assigned_bw_in));
- if ( (0 == address->assigned_bw_in) &&
- (0 == address->assigned_bw_out) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Telling transport to disconnect peer `%s'\n",
- GNUNET_i2s (&address->peer));
- /* Notify scheduling clients about suggestion */
- GAS_scheduling_transmit_address_suggestion (&address->peer,
- address->session_id,
- GNUNET_BANDWIDTH_ZERO,
- GNUNET_BANDWIDTH_ZERO);
- return;
- }
- /* Do bandwidth stability check */
- diff_out = abs (address->assigned_bw_out - address->last_notified_bw_out);
- diff_in = abs (address->assigned_bw_in - address->last_notified_bw_in);
- if ( (diff_out < htonl(GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__)) &&
- (diff_in < htonl(GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__)) )
- return;
- GNUNET_log(GNUNET_ERROR_TYPE_INFO,
- "Sending bandwidth update for peer `%s': %u/%u\n",
- GNUNET_i2s (&address->peer),
- address->assigned_bw_out,
- address->assigned_bw_out);
- /* *Notify scheduling clients about suggestion */
- GAS_scheduling_transmit_address_suggestion (&address->peer,
- address->session_id,
- GNUNET_BANDWIDTH_value_init (address->assigned_bw_out),
- GNUNET_BANDWIDTH_value_init (address->assigned_bw_in));
- address->last_notified_bw_out = address->assigned_bw_out;
- address->last_notified_bw_in = address->assigned_bw_in;
- }
- /**
- * Convert quota from text to numeric value.
- *
- * @param quota_str the value found in the configuration
- * @param direction direction of the quota
- * @param network network the quota applies to
- * @return numeric quota value to use
- */
- static unsigned long long
- parse_quota (const char *quota_str,
- const char *direction,
- enum GNUNET_ATS_Network_Type network)
- {
- int res;
- unsigned long long ret;
- res = GNUNET_NO;
- if (0 == strcmp (quota_str, GNUNET_ATS_MaxBandwidthString))
- {
- ret = GNUNET_ATS_MaxBandwidth;
- res = GNUNET_YES;
- }
- if ((GNUNET_NO == res) &&
- (GNUNET_OK ==
- GNUNET_STRINGS_fancy_size_to_bytes (quota_str,
- &ret)))
- res = GNUNET_YES;
- if ((GNUNET_NO == res) &&
- (1 ==
- sscanf (quota_str,
- "%llu",
- &ret)))
- res = GNUNET_YES;
- if (GNUNET_NO == res)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Could not load %s quota for network `%s': `%s', assigning default bandwidth %llu\n"),
- direction,
- GNUNET_ATS_print_network_type (network),
- quota_str,
- GNUNET_ATS_DefaultBandwidth);
- ret = GNUNET_ATS_DefaultBandwidth;
- }
- else
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- _("%s quota configured for network `%s' is %llu\n"),
- direction,
- GNUNET_ATS_print_network_type (network),
- ret);
- }
- return ret;
- }
- /**
- * Load quota value from the configuration @a cfg for the
- * given network @a type and @a direction.
- *
- * @param cfg configuration to parse
- * @param type network type to parse for
- * @param direction traffic direction to parse for
- * @return quota to apply
- */
- static unsigned long long
- load_quota (const struct GNUNET_CONFIGURATION_Handle *cfg,
- enum GNUNET_ATS_Network_Type type,
- const char *direction)
- {
- char *entry;
- char *quota_str;
- unsigned long long ret;
- GNUNET_asprintf (&entry,
- "%s_QUOTA_%s",
- GNUNET_ATS_print_network_type (type),
- direction);
- if (GNUNET_OK ==
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "ats",
- entry,
- "a_str))
- {
- ret = parse_quota (quota_str,
- direction,
- type);
- GNUNET_free (quota_str);
- }
- else
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("No %s-quota configured for network `%s', assigning default bandwidth %llu\n"),
- direction,
- GNUNET_ATS_print_network_type (type),
- GNUNET_ATS_DefaultBandwidth);
- ret = GNUNET_ATS_DefaultBandwidth;
- }
- GNUNET_free (entry);
- return ret;
- }
- /**
- * Load quotas for networks from configuration
- *
- * @param cfg configuration handle
- * @param out_dest where to write outbound quotas
- * @param in_dest where to write inbound quotas
- * @param dest_length length of inbound and outbound arrays
- * @return number of networks loaded
- */
- static unsigned int
- load_quotas (const struct GNUNET_CONFIGURATION_Handle *cfg,
- unsigned long long *out_dest,
- unsigned long long *in_dest,
- int dest_length)
- {
- unsigned int c;
- for (c = 0; (c < GNUNET_ATS_NetworkTypeCount) && (c < dest_length); c++)
- {
- in_dest[c] = load_quota (cfg,
- c,
- "out");
- out_dest[c] = load_quota (cfg,
- c,
- "in");
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Loaded quota for network `%s' (in/out): %llu %llu\n",
- GNUNET_ATS_print_network_type (c),
- in_dest[c],
- out_dest[c]);
- }
- return c;
- }
- /**
- * Initialize plugins subsystem.
- *
- * @param cfg configuration to use
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on error (failed to load
- * solver plugin)
- */
- int
- GAS_plugins_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
- {
- char *mode_str;
- /* Figure out configured solution method */
- if (GNUNET_SYSERR ==
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "ats",
- "MODE",
- &mode_str))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "No resource assignment method configured, using proportional approach\n");
- mode_str = GNUNET_strdup ("proportional");
- }
- env.cls = NULL;
- env.info_cb = &solver_info_cb;
- env.bandwidth_changed_cb = &bandwidth_changed_cb;
- env.get_preferences = &GAS_normalization_get_preferences_by_peer;
- env.get_property = &GAS_normalization_get_properties;
- env.cfg = cfg;
- env.stats = GSA_stats;
- env.addresses = GSA_addresses;
- env.network_count = GNUNET_ATS_NetworkTypeCount;
- load_quotas (cfg,
- env.out_quota,
- env.in_quota,
- GNUNET_ATS_NetworkTypeCount);
- GNUNET_asprintf (&plugin,
- "libgnunet_plugin_ats_%s",
- mode_str);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Initializing solver `%s'\n",
- mode_str);
- GNUNET_free (mode_str);
- if (NULL == (sf = GNUNET_PLUGIN_load (plugin, &env)))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Failed to initialize solver `%s'!\n"),
- plugin);
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
- }
- /**
- * Shutdown address subsystem.
- */
- void
- GAS_plugins_done ()
- {
- GNUNET_PLUGIN_unload (plugin,
- sf);
- sf = NULL;
- GNUNET_free (plugin);
- plugin = NULL;
- }
- /**
- * Tell the solver that the given address can now be used
- * for talking to the respective peer.
- *
- * @param new_address the new address
- * @param addr_net network scope the address is in
- * @param atsi performance data for the address
- * @param atsi_count size of the @a atsi array
- */
- void
- GAS_plugin_new_address (struct ATS_Address *new_address,
- enum GNUNET_ATS_Network_Type addr_net,
- const struct GNUNET_ATS_Information *atsi,
- uint32_t atsi_count)
- {
- sf->s_add (sf->cls,
- new_address,
- addr_net);
- sf->s_bulk_start (sf->cls);
- GAS_normalization_normalize_property (new_address,
- atsi,
- atsi_count);
- sf->s_bulk_stop (sf->cls);
- }
- /**
- * Tell the solver that the given address is no longer valid
- * can cannot be used any longer.
- *
- * @param address address that was deleted
- */
- void
- GAS_plugin_delete_address (struct ATS_Address *address)
- {
- sf->s_del (sf->cls,
- address,
- GNUNET_NO);
- }
- /**
- * Tell the solver that the given client has expressed its
- * appreciation for the past performance of a given connection.
- *
- * @param application client providing the feedback
- * @param peer peer the feedback is about
- * @param scope timeframe the feedback applies to
- * @param kind performance property the feedback relates to
- * @param score_abs degree of the appreciation
- */
- void
- GAS_plugin_preference_feedback (struct GNUNET_SERVER_Client *application,
- const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_TIME_Relative scope,
- enum GNUNET_ATS_PreferenceKind kind,
- float score_abs)
- {
- sf->s_feedback (sf->cls,
- application,
- peer,
- scope,
- kind,
- score_abs);
- }
- /**
- * Stop instant solving, there are many state updates
- * happening in bulk right now.
- */
- void
- GAS_plugin_solver_lock ()
- {
- sf->s_bulk_start (sf->cls);
- }
- /**
- * Resume instant solving, we are done with the bulk state updates.
- */
- void
- GAS_plugin_solver_unlock ()
- {
- sf->s_bulk_start (sf->cls);
- }
- /**
- * Notify the plugin that a request to connect to
- * a particular peer was given to us.
- *
- * @param pid identity of peer we now care about
- */
- void
- GAS_plugin_request_connect_start (const struct GNUNET_PeerIdentity *pid)
- {
- const struct ATS_Address *aa;
- aa = sf->s_get (sf->cls, pid);
- if (NULL == aa)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Cannot suggest address for peer `%s'\n",
- GNUNET_i2s (pid));
- return;
- }
- GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
- "Suggesting address %p for peer `%s'\n",
- aa,
- GNUNET_i2s (pid));
- GAS_scheduling_transmit_address_suggestion (pid,
- aa->session_id,
- GNUNET_BANDWIDTH_value_init (aa->assigned_bw_out),
- GNUNET_BANDWIDTH_value_init (aa->assigned_bw_in));
- }
- /**
- * Notify the plugin that a request to connect to
- * a particular peer was dropped.
- *
- * @param pid identity of peer we care now less about
- */
- void
- GAS_plugin_request_connect_stop (const struct GNUNET_PeerIdentity *pid)
- {
- sf->s_get_stop (sf->cls,
- pid);
- }
- /* end of gnunet-service-ats_plugins.c */
|