From 5a1d7b406639cb12640c9906ca38c3c08f912a85 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Thu, 6 Dec 2018 18:38:43 +0100 Subject: [PATCH] skeleton for 'simple' ATS2 plugin --- src/ats/Makefile.am | 15 +- src/ats/plugin_ats2_common.c | 96 +++++++ src/ats/plugin_ats2_simple.c | 408 ++++++++++++++++++++++++++++ src/include/gnunet_ats_plugin_new.h | 3 +- src/include/gnunet_mq_lib.h | 5 + 5 files changed, 523 insertions(+), 4 deletions(-) create mode 100644 src/ats/plugin_ats2_common.c create mode 100644 src/ats/plugin_ats2_simple.c diff --git a/src/ats/Makefile.am b/src/ats/Makefile.am index 52a1e7d11..97497c94e 100644 --- a/src/ats/Makefile.am +++ b/src/ats/Makefile.am @@ -24,7 +24,8 @@ lib_LTLIBRARIES = \ libgnunetatstransport.la plugin_LTLIBRARIES = \ - libgnunet_plugin_ats_proportional.la + libgnunet_plugin_ats_proportional.la \ + libgnunet_plugin_ats2_simple.la if HAVE_EXPERIMENTAL plugin_LTLIBRARIES += \ @@ -77,6 +78,15 @@ libgnunet_plugin_ats_proportional_la_LIBADD = \ libgnunet_plugin_ats_proportional_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) +libgnunet_plugin_ats2_simple_la_SOURCES = \ + plugin_ats2_simple.c +libgnunet_plugin_ats2_simple_la_LIBADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(LTLIBINTL) +libgnunet_plugin_ats2_simple_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + libgnunet_plugin_ats_mlp_la_SOURCES = \ plugin_ats_mlp.c @@ -186,7 +196,8 @@ test_ats_api_mlp_LDADD = \ libgnunetats.la EXTRA_DIST = \ - ats.h \ + ats.h ats2.h \ + plugin_ats2_common.c \ test_delay \ test_ats_api_mlp.conf \ test_ats_api_ril.conf \ diff --git a/src/ats/plugin_ats2_common.c b/src/ats/plugin_ats2_common.c new file mode 100644 index 000000000..6911ba44d --- /dev/null +++ b/src/ats/plugin_ats2_common.c @@ -0,0 +1,96 @@ +/* + This file is part of GNUnet. + Copyright (C) 2011-2015, 2018 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + 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 + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ +/** + * @file ats/plugin_ats2_common.c + * @brief ATS solver helper functions to be inlined + * @author Matthias Wachs + * @author Christian Grothoff + */ + +/** + * Default bandwidth assigned to a network: 64 KB/s + */ +#define DEFAULT_BANDWIDTH 65536 + + +/** + * Parse @a cfg for @a quota as specified for @a direction of + * network type @a nts. + * + * @param cfg configuration to parse + * @param nts network type string to get quota for + * @param direction direction to get quota for ("IN" or "OUT") + * @param quota[out] set to quota, #DEFAULT_BANDWIDTH if @a cfg does not say anything useful + */ +static void +get_quota (const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *nts, + const char *direction, + unsigned long long *quota) +{ + char *quota_str; + char *quota_s; + int res; + + GNUNET_asprintf ("a_s, + "%s_QUOTA_%s", + nts, + direction); + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + "ATS", + quota_s, + "a_str)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, + "ATS", + quota_s); + GNUNET_free (quota_s); + return; + } + GNUNET_free (quota_s); + res = GNUNET_NO; + if (0 == strcmp (quota_str, + "unlimited")) + { + *quota = ULONG_MAX; + res = GNUNET_YES; + } + if ( (GNUNET_NO == res) && + (GNUNET_OK == + GNUNET_STRINGS_fancy_size_to_bytes (quota_str, + quota)) ) + res = GNUNET_YES; + if ( (GNUNET_NO == res) && + (1 == + sscanf (quota_str, + "%llu", + quota)) ) + 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, + nts, + quota_str, + (unsigned long long) DEFAULT_BANDWIDTH); + *quota = DEFAULT_BANDWIDTH; + } + GNUNET_free (quota_str); +} diff --git a/src/ats/plugin_ats2_simple.c b/src/ats/plugin_ats2_simple.c new file mode 100644 index 000000000..689524ba4 --- /dev/null +++ b/src/ats/plugin_ats2_simple.c @@ -0,0 +1,408 @@ +/* + This file is part of GNUnet. + Copyright (C) 2011-2015, 2018 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + 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 + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ +/** + * @file ats/plugin_ats2_simple.c + * @brief ATS simple solver + * @author Matthias Wachs + * @author Christian Grothoff + * + * TODO: + * - subscribe to PEERSTORE when short on HELLOs (given application preferences!) + * - keep track of HELLOs and when we tried them last => re-suggest + * - sum up preferences per peer, keep totals! => PeerMap pid -> [preferences + sessions + addrs!] + * - sum up preferences overall, keep global sum => starting point for "proportional" + * - store DLL of available sessions per peer + */ +#include "platform.h" +#include "gnunet_ats_plugin_new.h" +#include "gnunet_peerstore_service.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "ats-simple",__VA_ARGS__) + + +/** + * Entry in list of addresses we could try per peer. + */ +struct Hello +{ + + /** + * Kept in a DLL. + */ + struct Hello *next; + + /** + * Kept in a DLL. + */ + struct Hello *prev; + + /** + * The address we could try. + */ + const char *address; + + /** + * When did we try it last? + */ + struct GNUNET_TIME_Absolute last_attempt; + + /** + * Current exponential backoff value. + */ + struct GNUNET_TIME_Relative backoff; + + /** + * Is a session with this address already up? + * If not, set to NULL. + */ + struct GNUNET_ATS_SessionHandle *sh; + +}; + + +/** + * Internal representation of a session by the plugin. + * (If desired, plugin may just use NULL.) + */ +struct GNUNET_ATS_SessionHandle +{ + + /** + * Kept in DLL per peer. + */ + struct GNUNET_ATS_SessionHandle *next; + + /** + * Kept in DLL per peer. + */ + struct GNUNET_ATS_SessionHandle *prev; + + /** + * The session in the main ATS service. + */ + struct GNUNET_ATS_Session *session; + + /** + * Current performance data for this @e session + */ + const struct GNUNET_ATS_SessionData *data; + + /** + * Hello matching this session, or NULL for none. + */ + struct Hello *hello; + + /** + * Address used by this session (largely for debugging). + */ + const char *address; + + /** + * Last BW-in allocation given to the transport service. + */ + struct GNUNET_BANDWIDTH_Value32NBO bw_in; + + /** + * Last BW-out allocation given to the transport service. + */ + struct GNUNET_BANDWIDTH_Value32NBO bw_out; + +}; + + +/** + * Information about preferences and sessions we track + * per peer. + */ +struct Peer +{ + + /** + * Kept in DLL per peer. + */ + struct GNUNET_ATS_SessionHandle *sh_head; + + /** + * Kept in DLL per peer. + */ + struct GNUNET_ATS_SessionHandle *sh_tail; + + /** + * Which peer is this for? + */ + struct GNUNET_PeerIdentity pid; + + /** + * Array where we sum up the bandwidth requests received indexed + * by preference kind (see `struct GNUNET_MQ_PreferenceKind`) + */ + uint64_t bw_by_pk[GNUNET_MQ_PREFERENCE_COUNT]; + + /** + * Watch context where we are currently looking for HELLOs for + * this peer. + */ + struct GNUNET_PEERSTORE_WatchContext *wc; + + /** + * Task used to try again to suggest an address for this peer. + */ + struct GNUNET_SCHEDULER_TaskHandle *task; + +}; + + +/** + * Representation of a network (to be expanded...) + */ +struct Network +{ + + /** + * Total inbound quota + */ + unsigned long long total_quota_in; + + /** + * Total outbound quota + */ + unsigned long long total_quota_out; + + /** + * ATS network type + */ + enum GNUNET_NetworkType type; + +}; + + +/** + * A handle for the proportional solver + */ +struct SimpleHandle +{ + + /** + * Our execution environment. + */ + struct GNUNET_ATS_PluginEnvironment *env; + + /** + * Information we track for each peer. + */ + struct GNUNET_CONTAINER_MultiPeerMap *peers; + + /** + * Information we track per network type (quotas). + */ + struct Network networks[GNUNET_NT_COUNT]; + + /** + * Handle to the peerstore service. + */ + struct GNUNET_PEERSTORE_Handle *ps; + +}; + + +/** + * The world changed, recalculate our allocations. + */ +static void +update (struct SimpleHandle *h) +{ + // recalculate allocations + // notify transport if it makes sense (delta significant) +} + + +/** + * The plugin should begin to respect a new preference. + * + * @param cls the closure + * @param pref the preference to add + * @return plugin's internal representation, or NULL + */ +static struct GNUNET_ATS_PreferenceHandle * +simple_preference_add (void *cls, + const struct GNUNET_ATS_Preference *pref) +{ + struct SimpleHandle *h = cls; + // Setup peer if necessary (-> including HELLO triggers!) + // add pref to bw_by_pk + // trigger update + return NULL; +} + + +/** + * The plugin should end respecting a preference. + * + * @param cls the closure + * @param ph whatever @e preference_add returned + * @param pref the preference to delete + * @return plugin's internal representation, or NULL + */ +static void +simple_preference_del (void *cls, + struct GNUNET_ATS_PreferenceHandle *ph, + const struct GNUNET_ATS_Preference *pref) +{ + struct SimpleHandle *h = cls; + // find peer + // subtract pref from bw_by_pk + // remove peer if otherwise dead + // trigger update +} + + +/** + * Transport established a new session with performance + * characteristics given in @a data. + * + * @param cls closure + * @param data performance characteristics of @a sh + * @param address address information (for debugging) + * @return handle by which the plugin will identify this session + */ +static struct GNUNET_ATS_SessionHandle * +simple_session_add (void *cls, + const struct GNUNET_ATS_SessionData *data, + const char *address) +{ + struct SimpleHandle *h = cls; + + // find or add peer if necessary + // setup session + // match HELLO + // trigger update + return NULL; +} + + +/** + * @a data changed for a given @a sh, solver should consider + * the updated performance characteristics. + * + * @param cls closure + * @param sh session this is about + * @param data performance characteristics of @a sh + */ +static void +simple_session_update (void *cls, + struct GNUNET_ATS_SessionHandle *sh, + const struct GNUNET_ATS_SessionData *data) +{ + struct SimpleHandle *h = cls; + // trigger update +} + + +/** + * A session went away. Solver should update accordingly. + * + * @param cls closure + * @param sh session this is about + * @param data (last) performance characteristics of @a sh + */ +static void +simple_session_del (void *cls, + struct GNUNET_ATS_SessionHandle *sh, + const struct GNUNET_ATS_SessionData *data) +{ + struct SimpleHandle *h = cls; + // tear down session + // del peer if otherwise dead + // trigger update +} + + +#include "plugin_ats2_common.c" + + +/** + * Function invoked when the plugin is loaded. + * + * @param[in,out] cls the `struct GNUNET_ATS_PluginEnvironment *` to use; + * modified to return the API functions (ugh). + * @return the `struct SimpleHandle` to pass as a closure + */ +void * +libgnunet_plugin_ats2_simple_init (void *cls) +{ + static struct GNUNET_ATS_SolverFunctions sf; + struct GNUNET_ATS_PluginEnvironment *env = cls; + struct SimpleHandle *s; + + s = GNUNET_new (struct SimpleHandle); + s->env = env; + s->peers = GNUNET_CONTAINER_multipeermap_create (128, + GNUNET_YES); + s->ps = GNUNET_PEERSTORE_connect (env->cfg); + sf.cls = s; + sf.preference_add = &simple_preference_add; + sf.preference_del = &simple_preference_del; + sf.session_add = &simple_session_add; + sf.session_update = &simple_session_update; + sf.session_del = &simple_session_del; + for (enum GNUNET_NetworkType nt = 0; + nt < GNUNET_NT_COUNT; + nt++) + { + const char *name = GNUNET_NT_to_string (nt); + + if (NULL == name) + { + GNUNET_break (0); + break; + } + get_quota (env->cfg, + name, + "IN", + &s->networks[nt].total_quota_in); + get_quota (env->cfg, + name, + "OUT", + &s->networks[nt].total_quota_out); + s->networks[nt].type = nt; + } + return &sf; +} + + +/** + * Function used to unload the plugin. + * + * @param cls return value from #libgnunet_plugin_ats_proportional_init() + */ +void * +libgnunet_plugin_ats2_simple_done (void *cls) +{ + struct GNUNET_ATS_SolverFunctions *sf = cls; + struct SimpleHandle *s = sf->cls; + + // FIXME: iterate over peers and clean up! + GNUNET_CONTAINER_multipeermap_destroy (s->peers); + GNUNET_PEERSTORE_disconnect (s->ps, + GNUNET_NO); + GNUNET_free (s); + return NULL; +} + + +/* end of plugin_ats2_simple.c */ diff --git a/src/include/gnunet_ats_plugin_new.h b/src/include/gnunet_ats_plugin_new.h index d2960c9cf..2ae37d7ea 100644 --- a/src/include/gnunet_ats_plugin_new.h +++ b/src/include/gnunet_ats_plugin_new.h @@ -35,8 +35,7 @@ #ifndef PLUGIN_ATS_H #define PLUGIN_ATS_H -#include "gnunet_mq_lib.h" -#include "gnunet_bandwidth_lib.h" +#include "gnunet_util_lib.h" #include "gnunet_ats_application_service.h" #include "gnunet_ats_transport_service.h" #include "gnunet_statistics_service.h" diff --git a/src/include/gnunet_mq_lib.h b/src/include/gnunet_mq_lib.h index 7704a2fca..574c0932d 100644 --- a/src/include/gnunet_mq_lib.h +++ b/src/include/gnunet_mq_lib.h @@ -930,6 +930,11 @@ enum GNUNET_MQ_PreferenceKind */ GNUNET_MQ_PREFERENCE_RELIABILITY = 3 + /** + * Number of preference values allowed. + */ +#define GNUNET_MQ_PREFERENCE_COUNT 4 + }; -- 2.25.1