gnunet-service-ats_plugins.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2011-2014 Christian Grothoff (and other contributing authors)
  4. GNUnet is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published
  6. by the Free Software Foundation; either version 3, or (at your
  7. option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNUnet; see the file COPYING. If not, write to the
  14. Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  15. Boston, MA 02111-1307, USA.
  16. */
  17. /**
  18. * @file ats/gnunet-service-ats_plugins.c
  19. * @brief ats service plugin management
  20. * @author Matthias Wachs
  21. * @author Christian Grothoff
  22. */
  23. #include "platform.h"
  24. #include "gnunet_ats_plugin.h"
  25. #include "gnunet-service-ats_connectivity.h"
  26. #include "gnunet-service-ats_performance.h"
  27. #include "gnunet-service-ats_preferences.h"
  28. #include "gnunet-service-ats_plugins.h"
  29. #include "gnunet-service-ats_scheduling.h"
  30. #include "gnunet-service-ats_normalization.h"
  31. /**
  32. * Solver handle.
  33. */
  34. static struct GNUNET_ATS_SolverFunctions *sf;
  35. /**
  36. * Solver environment.
  37. */
  38. static struct GNUNET_ATS_PluginEnvironment env;
  39. /**
  40. * Solver plugin name as string
  41. */
  42. static char *plugin;
  43. /**
  44. * The preference changed for a peer, update solver.
  45. *
  46. * @param peer the peer
  47. * @param kind the ATS kind
  48. * @param pref_rel the new relative preference value
  49. */
  50. void
  51. GAS_normalized_preference_changed (const struct GNUNET_PeerIdentity *peer,
  52. enum GNUNET_ATS_PreferenceKind kind,
  53. double pref_rel)
  54. {
  55. sf->s_pref (sf->cls,
  56. peer,
  57. kind,
  58. pref_rel);
  59. }
  60. /**
  61. * The relative value for a property changed
  62. *
  63. * @param address the peer
  64. * @param type the ATS type
  65. * @param prop_rel the new relative preference value
  66. */
  67. void
  68. GAS_normalized_property_changed (struct ATS_Address *address,
  69. uint32_t type,
  70. double prop_rel)
  71. {
  72. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  73. "Normalized property %s for peer `%s' changed to %.3f \n",
  74. GNUNET_ATS_print_property_type (type),
  75. GNUNET_i2s (&address->peer),
  76. prop_rel);
  77. sf->s_address_update_property (sf->cls,
  78. address,
  79. type,
  80. 0,
  81. prop_rel);
  82. }
  83. /**
  84. * Solver information callback
  85. *
  86. * @param cls the closure
  87. * @param op the operation
  88. * @param status operation status
  89. * @param add additional information
  90. */
  91. static void
  92. solver_info_cb (void *cls,
  93. enum GAS_Solver_Operation op,
  94. enum GAS_Solver_Status status,
  95. enum GAS_Solver_Additional_Information add)
  96. {
  97. const char *add_info;
  98. switch (add) {
  99. case GAS_INFO_NONE:
  100. add_info = "GAS_INFO_NONE";
  101. break;
  102. case GAS_INFO_FULL:
  103. add_info = "GAS_INFO_MLP_FULL";
  104. break;
  105. case GAS_INFO_UPDATED:
  106. add_info = "GAS_INFO_MLP_UPDATED";
  107. break;
  108. case GAS_INFO_PROP_ALL:
  109. add_info = "GAS_INFO_PROP_ALL";
  110. break;
  111. case GAS_INFO_PROP_SINGLE:
  112. add_info = "GAS_INFO_PROP_SINGLE";
  113. break;
  114. default:
  115. add_info = "INVALID";
  116. break;
  117. }
  118. switch (op)
  119. {
  120. case GAS_OP_SOLVE_START:
  121. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  122. "Solver notifies `%s' with result `%s' `%s'\n",
  123. "GAS_OP_SOLVE_START",
  124. (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL",
  125. add_info);
  126. return;
  127. case GAS_OP_SOLVE_STOP:
  128. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  129. "Solver notifies `%s' with result `%s'\n",
  130. "GAS_OP_SOLVE_STOP",
  131. (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL",
  132. add_info);
  133. return;
  134. case GAS_OP_SOLVE_SETUP_START:
  135. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  136. "Solver notifies `%s' with result `%s'\n",
  137. "GAS_OP_SOLVE_SETUP_START",
  138. (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
  139. return;
  140. case GAS_OP_SOLVE_SETUP_STOP:
  141. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  142. "Solver notifies `%s' with result `%s'\n",
  143. "GAS_OP_SOLVE_SETUP_STOP",
  144. (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
  145. return;
  146. case GAS_OP_SOLVE_MLP_LP_START:
  147. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  148. "Solver notifies `%s' with result `%s'\n",
  149. "GAS_OP_SOLVE_LP_START",
  150. (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
  151. return;
  152. case GAS_OP_SOLVE_MLP_LP_STOP:
  153. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  154. "Solver notifies `%s' with result `%s'\n",
  155. "GAS_OP_SOLVE_LP_STOP",
  156. (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
  157. return;
  158. case GAS_OP_SOLVE_MLP_MLP_START:
  159. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  160. "Solver notifies `%s' with result `%s'\n",
  161. "GAS_OP_SOLVE_MLP_START",
  162. (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
  163. return;
  164. case GAS_OP_SOLVE_MLP_MLP_STOP:
  165. GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
  166. "Solver notifies `%s' with result `%s'\n",
  167. "GAS_OP_SOLVE_MLP_STOP",
  168. (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
  169. return;
  170. case GAS_OP_SOLVE_UPDATE_NOTIFICATION_START:
  171. GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
  172. "Solver notifies `%s' with result `%s'\n",
  173. "GAS_OP_SOLVE_UPDATE_NOTIFICATION_START",
  174. (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
  175. return;
  176. case GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP:
  177. GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
  178. "Solver notifies `%s' with result `%s'\n",
  179. "GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP",
  180. (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
  181. return;
  182. default:
  183. break;
  184. }
  185. }
  186. /**
  187. * Callback for solver to notify about assignment changes
  188. *
  189. * @param cls NULL
  190. * @param address the address with changes
  191. */
  192. static void
  193. bandwidth_changed_cb (void *cls,
  194. struct ATS_Address *address)
  195. {
  196. uint32_t diff_out;
  197. uint32_t diff_in;
  198. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  199. "Bandwidth assignment changed for peer %s \n",
  200. GNUNET_i2s (&address->peer));
  201. /* Notify performance clients about changes to address */
  202. GAS_performance_notify_all_clients (&address->peer,
  203. address->plugin,
  204. address->addr,
  205. address->addr_len,
  206. address->active,
  207. address->atsi,
  208. address->atsi_count,
  209. GNUNET_BANDWIDTH_value_init (address->assigned_bw_out),
  210. GNUNET_BANDWIDTH_value_init (address->assigned_bw_in));
  211. if ( (0 == address->assigned_bw_in) &&
  212. (0 == address->assigned_bw_out) )
  213. {
  214. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  215. "Telling transport to disconnect peer `%s'\n",
  216. GNUNET_i2s (&address->peer));
  217. /* Notify scheduling clients about suggestion */
  218. GAS_scheduling_transmit_address_suggestion (&address->peer,
  219. address->session_id,
  220. GNUNET_BANDWIDTH_ZERO,
  221. GNUNET_BANDWIDTH_ZERO);
  222. return;
  223. }
  224. /* Do bandwidth stability check */
  225. diff_out = abs (address->assigned_bw_out - address->last_notified_bw_out);
  226. diff_in = abs (address->assigned_bw_in - address->last_notified_bw_in);
  227. if ( (diff_out < htonl(GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__)) &&
  228. (diff_in < htonl(GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__)) )
  229. return;
  230. GNUNET_log(GNUNET_ERROR_TYPE_INFO,
  231. "Sending bandwidth update for peer `%s': %u/%u\n",
  232. GNUNET_i2s (&address->peer),
  233. address->assigned_bw_out,
  234. address->assigned_bw_out);
  235. /* *Notify scheduling clients about suggestion */
  236. GAS_scheduling_transmit_address_suggestion (&address->peer,
  237. address->session_id,
  238. GNUNET_BANDWIDTH_value_init (address->assigned_bw_out),
  239. GNUNET_BANDWIDTH_value_init (address->assigned_bw_in));
  240. address->last_notified_bw_out = address->assigned_bw_out;
  241. address->last_notified_bw_in = address->assigned_bw_in;
  242. }
  243. /**
  244. * Convert quota from text to numeric value.
  245. *
  246. * @param quota_str the value found in the configuration
  247. * @param direction direction of the quota
  248. * @param network network the quota applies to
  249. * @return numeric quota value to use
  250. */
  251. static unsigned long long
  252. parse_quota (const char *quota_str,
  253. const char *direction,
  254. enum GNUNET_ATS_Network_Type network)
  255. {
  256. int res;
  257. unsigned long long ret;
  258. res = GNUNET_NO;
  259. if (0 == strcmp (quota_str, GNUNET_ATS_MaxBandwidthString))
  260. {
  261. ret = GNUNET_ATS_MaxBandwidth;
  262. res = GNUNET_YES;
  263. }
  264. if ((GNUNET_NO == res) &&
  265. (GNUNET_OK ==
  266. GNUNET_STRINGS_fancy_size_to_bytes (quota_str,
  267. &ret)))
  268. res = GNUNET_YES;
  269. if ((GNUNET_NO == res) &&
  270. (1 ==
  271. sscanf (quota_str,
  272. "%llu",
  273. &ret)))
  274. res = GNUNET_YES;
  275. if (GNUNET_NO == res)
  276. {
  277. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  278. _("Could not load %s quota for network `%s': `%s', assigning default bandwidth %llu\n"),
  279. direction,
  280. GNUNET_ATS_print_network_type (network),
  281. quota_str,
  282. GNUNET_ATS_DefaultBandwidth);
  283. ret = GNUNET_ATS_DefaultBandwidth;
  284. }
  285. else
  286. {
  287. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  288. _("%s quota configured for network `%s' is %llu\n"),
  289. direction,
  290. GNUNET_ATS_print_network_type (network),
  291. ret);
  292. }
  293. return ret;
  294. }
  295. /**
  296. * Load quota value from the configuration @a cfg for the
  297. * given network @a type and @a direction.
  298. *
  299. * @param cfg configuration to parse
  300. * @param type network type to parse for
  301. * @param direction traffic direction to parse for
  302. * @return quota to apply
  303. */
  304. static unsigned long long
  305. load_quota (const struct GNUNET_CONFIGURATION_Handle *cfg,
  306. enum GNUNET_ATS_Network_Type type,
  307. const char *direction)
  308. {
  309. char *entry;
  310. char *quota_str;
  311. unsigned long long ret;
  312. GNUNET_asprintf (&entry,
  313. "%s_QUOTA_%s",
  314. GNUNET_ATS_print_network_type (type),
  315. direction);
  316. if (GNUNET_OK ==
  317. GNUNET_CONFIGURATION_get_value_string (cfg,
  318. "ats",
  319. entry,
  320. &quota_str))
  321. {
  322. ret = parse_quota (quota_str,
  323. direction,
  324. type);
  325. GNUNET_free (quota_str);
  326. }
  327. else
  328. {
  329. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  330. _("No %s-quota configured for network `%s', assigning default bandwidth %llu\n"),
  331. direction,
  332. GNUNET_ATS_print_network_type (type),
  333. GNUNET_ATS_DefaultBandwidth);
  334. ret = GNUNET_ATS_DefaultBandwidth;
  335. }
  336. GNUNET_free (entry);
  337. return ret;
  338. }
  339. /**
  340. * Load quotas for networks from configuration
  341. *
  342. * @param cfg configuration handle
  343. * @param out_dest where to write outbound quotas
  344. * @param in_dest where to write inbound quotas
  345. * @param dest_length length of inbound and outbound arrays
  346. * @return number of networks loaded
  347. */
  348. static unsigned int
  349. load_quotas (const struct GNUNET_CONFIGURATION_Handle *cfg,
  350. unsigned long long *out_dest,
  351. unsigned long long *in_dest,
  352. int dest_length)
  353. {
  354. unsigned int c;
  355. for (c = 0; (c < GNUNET_ATS_NetworkTypeCount) && (c < dest_length); c++)
  356. {
  357. in_dest[c] = load_quota (cfg,
  358. c,
  359. "out");
  360. out_dest[c] = load_quota (cfg,
  361. c,
  362. "in");
  363. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  364. "Loaded quota for network `%s' (in/out): %llu %llu\n",
  365. GNUNET_ATS_print_network_type (c),
  366. in_dest[c],
  367. out_dest[c]);
  368. }
  369. return c;
  370. }
  371. /**
  372. * Initialize plugins subsystem.
  373. *
  374. * @param cfg configuration to use
  375. * @return #GNUNET_OK on success, #GNUNET_SYSERR on error (failed to load
  376. * solver plugin)
  377. */
  378. int
  379. GAS_plugins_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
  380. {
  381. char *mode_str;
  382. /* Figure out configured solution method */
  383. if (GNUNET_SYSERR ==
  384. GNUNET_CONFIGURATION_get_value_string (cfg,
  385. "ats",
  386. "MODE",
  387. &mode_str))
  388. {
  389. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  390. "No resource assignment method configured, using proportional approach\n");
  391. mode_str = GNUNET_strdup ("proportional");
  392. }
  393. env.cls = NULL;
  394. env.info_cb = &solver_info_cb;
  395. env.bandwidth_changed_cb = &bandwidth_changed_cb;
  396. env.get_preferences = &GAS_normalization_get_preferences_by_peer;
  397. env.get_property = &GAS_normalization_get_properties;
  398. env.cfg = cfg;
  399. env.stats = GSA_stats;
  400. env.addresses = GSA_addresses;
  401. env.network_count = GNUNET_ATS_NetworkTypeCount;
  402. load_quotas (cfg,
  403. env.out_quota,
  404. env.in_quota,
  405. GNUNET_ATS_NetworkTypeCount);
  406. GNUNET_asprintf (&plugin,
  407. "libgnunet_plugin_ats_%s",
  408. mode_str);
  409. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  410. "Initializing solver `%s'\n",
  411. mode_str);
  412. GNUNET_free (mode_str);
  413. if (NULL == (sf = GNUNET_PLUGIN_load (plugin, &env)))
  414. {
  415. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  416. _("Failed to initialize solver `%s'!\n"),
  417. plugin);
  418. return GNUNET_SYSERR;
  419. }
  420. return GNUNET_OK;
  421. }
  422. /**
  423. * Shutdown address subsystem.
  424. */
  425. void
  426. GAS_plugins_done ()
  427. {
  428. GNUNET_PLUGIN_unload (plugin,
  429. sf);
  430. sf = NULL;
  431. GNUNET_free (plugin);
  432. plugin = NULL;
  433. }
  434. /**
  435. * Tell the solver that the given address can now be used
  436. * for talking to the respective peer.
  437. *
  438. * @param new_address the new address
  439. * @param addr_net network scope the address is in
  440. * @param atsi performance data for the address
  441. * @param atsi_count size of the @a atsi array
  442. */
  443. void
  444. GAS_plugin_new_address (struct ATS_Address *new_address,
  445. enum GNUNET_ATS_Network_Type addr_net,
  446. const struct GNUNET_ATS_Information *atsi,
  447. uint32_t atsi_count)
  448. {
  449. sf->s_add (sf->cls,
  450. new_address,
  451. addr_net);
  452. sf->s_bulk_start (sf->cls);
  453. GAS_normalization_normalize_property (new_address,
  454. atsi,
  455. atsi_count);
  456. sf->s_bulk_stop (sf->cls);
  457. }
  458. /**
  459. * Tell the solver that the given address is no longer valid
  460. * can cannot be used any longer.
  461. *
  462. * @param address address that was deleted
  463. */
  464. void
  465. GAS_plugin_delete_address (struct ATS_Address *address)
  466. {
  467. sf->s_del (sf->cls,
  468. address,
  469. GNUNET_NO);
  470. }
  471. /**
  472. * Tell the solver that the given client has expressed its
  473. * appreciation for the past performance of a given connection.
  474. *
  475. * @param application client providing the feedback
  476. * @param peer peer the feedback is about
  477. * @param scope timeframe the feedback applies to
  478. * @param kind performance property the feedback relates to
  479. * @param score_abs degree of the appreciation
  480. */
  481. void
  482. GAS_plugin_preference_feedback (struct GNUNET_SERVER_Client *application,
  483. const struct GNUNET_PeerIdentity *peer,
  484. const struct GNUNET_TIME_Relative scope,
  485. enum GNUNET_ATS_PreferenceKind kind,
  486. float score_abs)
  487. {
  488. sf->s_feedback (sf->cls,
  489. application,
  490. peer,
  491. scope,
  492. kind,
  493. score_abs);
  494. }
  495. /**
  496. * Stop instant solving, there are many state updates
  497. * happening in bulk right now.
  498. */
  499. void
  500. GAS_plugin_solver_lock ()
  501. {
  502. sf->s_bulk_start (sf->cls);
  503. }
  504. /**
  505. * Resume instant solving, we are done with the bulk state updates.
  506. */
  507. void
  508. GAS_plugin_solver_unlock ()
  509. {
  510. sf->s_bulk_start (sf->cls);
  511. }
  512. /**
  513. * Notify the plugin that a request to connect to
  514. * a particular peer was given to us.
  515. *
  516. * @param pid identity of peer we now care about
  517. */
  518. void
  519. GAS_plugin_request_connect_start (const struct GNUNET_PeerIdentity *pid)
  520. {
  521. const struct ATS_Address *aa;
  522. aa = sf->s_get (sf->cls, pid);
  523. if (NULL == aa)
  524. {
  525. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  526. "Cannot suggest address for peer `%s'\n",
  527. GNUNET_i2s (pid));
  528. return;
  529. }
  530. GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
  531. "Suggesting address %p for peer `%s'\n",
  532. aa,
  533. GNUNET_i2s (pid));
  534. GAS_scheduling_transmit_address_suggestion (pid,
  535. aa->session_id,
  536. GNUNET_BANDWIDTH_value_init (aa->assigned_bw_out),
  537. GNUNET_BANDWIDTH_value_init (aa->assigned_bw_in));
  538. }
  539. /**
  540. * Notify the plugin that a request to connect to
  541. * a particular peer was dropped.
  542. *
  543. * @param pid identity of peer we care now less about
  544. */
  545. void
  546. GAS_plugin_request_connect_stop (const struct GNUNET_PeerIdentity *pid)
  547. {
  548. sf->s_get_stop (sf->cls,
  549. pid);
  550. }
  551. /* end of gnunet-service-ats_plugins.c */