gnunet-service-ats_plugins.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575
  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_plugin_notify_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 for which a property changed
  64. */
  65. void
  66. GAS_plugin_notify_property_changed (struct ATS_Address *address)
  67. {
  68. sf->s_address_update_property (sf->cls,
  69. address);
  70. }
  71. /**
  72. * Solver information callback
  73. *
  74. * @param cls the closure
  75. * @param op the operation
  76. * @param status operation status
  77. * @param add additional information
  78. */
  79. static void
  80. solver_info_cb (void *cls,
  81. enum GAS_Solver_Operation op,
  82. enum GAS_Solver_Status status,
  83. enum GAS_Solver_Additional_Information add)
  84. {
  85. const char *add_info;
  86. switch (add) {
  87. case GAS_INFO_NONE:
  88. add_info = "GAS_INFO_NONE";
  89. break;
  90. case GAS_INFO_FULL:
  91. add_info = "GAS_INFO_MLP_FULL";
  92. break;
  93. case GAS_INFO_UPDATED:
  94. add_info = "GAS_INFO_MLP_UPDATED";
  95. break;
  96. case GAS_INFO_PROP_ALL:
  97. add_info = "GAS_INFO_PROP_ALL";
  98. break;
  99. case GAS_INFO_PROP_SINGLE:
  100. add_info = "GAS_INFO_PROP_SINGLE";
  101. break;
  102. default:
  103. add_info = "INVALID";
  104. break;
  105. }
  106. switch (op)
  107. {
  108. case GAS_OP_SOLVE_START:
  109. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  110. "Solver notifies `%s' with result `%s' `%s'\n",
  111. "GAS_OP_SOLVE_START",
  112. (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL",
  113. add_info);
  114. return;
  115. case GAS_OP_SOLVE_STOP:
  116. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  117. "Solver notifies `%s' with result `%s'\n",
  118. "GAS_OP_SOLVE_STOP",
  119. (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL",
  120. add_info);
  121. return;
  122. case GAS_OP_SOLVE_SETUP_START:
  123. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  124. "Solver notifies `%s' with result `%s'\n",
  125. "GAS_OP_SOLVE_SETUP_START",
  126. (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
  127. return;
  128. case GAS_OP_SOLVE_SETUP_STOP:
  129. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  130. "Solver notifies `%s' with result `%s'\n",
  131. "GAS_OP_SOLVE_SETUP_STOP",
  132. (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
  133. return;
  134. case GAS_OP_SOLVE_MLP_LP_START:
  135. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  136. "Solver notifies `%s' with result `%s'\n",
  137. "GAS_OP_SOLVE_LP_START",
  138. (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
  139. return;
  140. case GAS_OP_SOLVE_MLP_LP_STOP:
  141. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  142. "Solver notifies `%s' with result `%s'\n",
  143. "GAS_OP_SOLVE_LP_STOP",
  144. (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
  145. return;
  146. case GAS_OP_SOLVE_MLP_MLP_START:
  147. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  148. "Solver notifies `%s' with result `%s'\n",
  149. "GAS_OP_SOLVE_MLP_START",
  150. (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
  151. return;
  152. case GAS_OP_SOLVE_MLP_MLP_STOP:
  153. GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
  154. "Solver notifies `%s' with result `%s'\n",
  155. "GAS_OP_SOLVE_MLP_STOP",
  156. (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
  157. return;
  158. case GAS_OP_SOLVE_UPDATE_NOTIFICATION_START:
  159. GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
  160. "Solver notifies `%s' with result `%s'\n",
  161. "GAS_OP_SOLVE_UPDATE_NOTIFICATION_START",
  162. (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
  163. return;
  164. case GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP:
  165. GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
  166. "Solver notifies `%s' with result `%s'\n",
  167. "GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP",
  168. (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
  169. return;
  170. default:
  171. GNUNET_break (0);
  172. break;
  173. }
  174. }
  175. /**
  176. * Callback for solver to notify about assignment changes
  177. *
  178. * @param cls NULL
  179. * @param address the address with changes
  180. */
  181. static void
  182. bandwidth_changed_cb (void *cls,
  183. struct ATS_Address *address)
  184. {
  185. long long diff_out;
  186. long long diff_in;
  187. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  188. "Bandwidth assignment changed for peer %s to %u/%u\n",
  189. GNUNET_i2s (&address->peer),
  190. (unsigned int) address->assigned_bw_in,
  191. (unsigned int) address->assigned_bw_out);
  192. /* Notify performance clients about changes to address */
  193. GAS_performance_notify_all_clients (&address->peer,
  194. address->plugin,
  195. address->addr,
  196. address->addr_len,
  197. address->active,
  198. &address->properties,
  199. GNUNET_BANDWIDTH_value_init (address->assigned_bw_out),
  200. GNUNET_BANDWIDTH_value_init (address->assigned_bw_in));
  201. if ( (0 == address->assigned_bw_in) &&
  202. (0 == address->assigned_bw_out) )
  203. {
  204. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  205. "Telling transport to disconnect peer `%s'\n",
  206. GNUNET_i2s (&address->peer));
  207. /* Notify scheduling clients about suggestion */
  208. GAS_scheduling_transmit_address_suggestion (&address->peer,
  209. address->session_id,
  210. GNUNET_BANDWIDTH_ZERO,
  211. GNUNET_BANDWIDTH_ZERO);
  212. return;
  213. }
  214. /* Do bandwidth stability check */
  215. diff_out = llabs ((long long) address->assigned_bw_out -
  216. (long long) address->last_notified_bw_out);
  217. diff_in = llabs ((long long) address->assigned_bw_in -
  218. (long long) address->last_notified_bw_in);
  219. if ( (diff_out < htonl (GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__)) &&
  220. (diff_in < htonl (GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__)) )
  221. {
  222. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  223. "Bandwidth change too small, not notifying client\n");
  224. return;
  225. }
  226. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  227. "Sending bandwidth update for peer `%s': %u/%u\n",
  228. GNUNET_i2s (&address->peer),
  229. address->assigned_bw_out,
  230. address->assigned_bw_out);
  231. /* *Notify scheduling clients about suggestion */
  232. GAS_scheduling_transmit_address_suggestion (&address->peer,
  233. address->session_id,
  234. GNUNET_BANDWIDTH_value_init (address->assigned_bw_out),
  235. GNUNET_BANDWIDTH_value_init (address->assigned_bw_in));
  236. address->last_notified_bw_out = address->assigned_bw_out;
  237. address->last_notified_bw_in = address->assigned_bw_in;
  238. }
  239. /**
  240. * Convert quota from text to numeric value.
  241. *
  242. * @param quota_str the value found in the configuration
  243. * @param direction direction of the quota
  244. * @param network network the quota applies to
  245. * @return numeric quota value to use
  246. */
  247. static unsigned long long
  248. parse_quota (const char *quota_str,
  249. const char *direction,
  250. enum GNUNET_ATS_Network_Type network)
  251. {
  252. int res;
  253. unsigned long long ret;
  254. res = GNUNET_NO;
  255. if (0 == strcmp (quota_str, GNUNET_ATS_MaxBandwidthString))
  256. {
  257. ret = GNUNET_ATS_MaxBandwidth;
  258. res = GNUNET_YES;
  259. }
  260. if ((GNUNET_NO == res) &&
  261. (GNUNET_OK ==
  262. GNUNET_STRINGS_fancy_size_to_bytes (quota_str,
  263. &ret)))
  264. res = GNUNET_YES;
  265. if ((GNUNET_NO == res) &&
  266. (1 ==
  267. sscanf (quota_str,
  268. "%llu",
  269. &ret)))
  270. res = GNUNET_YES;
  271. if (GNUNET_NO == res)
  272. {
  273. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  274. _("Could not load %s quota for network `%s': `%s', assigning default bandwidth %llu\n"),
  275. direction,
  276. GNUNET_ATS_print_network_type (network),
  277. quota_str,
  278. GNUNET_ATS_DefaultBandwidth);
  279. ret = GNUNET_ATS_DefaultBandwidth;
  280. }
  281. else
  282. {
  283. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  284. _("%s quota configured for network `%s' is %llu\n"),
  285. direction,
  286. GNUNET_ATS_print_network_type (network),
  287. ret);
  288. }
  289. return ret;
  290. }
  291. /**
  292. * Load quota value from the configuration @a cfg for the
  293. * given network @a type and @a direction.
  294. *
  295. * @param cfg configuration to parse
  296. * @param type network type to parse for
  297. * @param direction traffic direction to parse for
  298. * @return quota to apply
  299. */
  300. static unsigned long long
  301. load_quota (const struct GNUNET_CONFIGURATION_Handle *cfg,
  302. enum GNUNET_ATS_Network_Type type,
  303. const char *direction)
  304. {
  305. char *entry;
  306. char *quota_str;
  307. unsigned long long ret;
  308. GNUNET_asprintf (&entry,
  309. "%s_QUOTA_%s",
  310. GNUNET_ATS_print_network_type (type),
  311. direction);
  312. if (GNUNET_OK ==
  313. GNUNET_CONFIGURATION_get_value_string (cfg,
  314. "ats",
  315. entry,
  316. &quota_str))
  317. {
  318. ret = parse_quota (quota_str,
  319. direction,
  320. type);
  321. GNUNET_free (quota_str);
  322. }
  323. else
  324. {
  325. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  326. _("No %s-quota configured for network `%s', assigning default bandwidth %llu\n"),
  327. direction,
  328. GNUNET_ATS_print_network_type (type),
  329. GNUNET_ATS_DefaultBandwidth);
  330. ret = GNUNET_ATS_DefaultBandwidth;
  331. }
  332. GNUNET_free (entry);
  333. return ret;
  334. }
  335. /**
  336. * Load quotas for networks from configuration
  337. *
  338. * @param cfg configuration handle
  339. * @param out_dest where to write outbound quotas
  340. * @param in_dest where to write inbound quotas
  341. * @param dest_length length of inbound and outbound arrays
  342. * @return number of networks loaded
  343. */
  344. static unsigned int
  345. load_quotas (const struct GNUNET_CONFIGURATION_Handle *cfg,
  346. unsigned long long *out_dest,
  347. unsigned long long *in_dest,
  348. int dest_length)
  349. {
  350. unsigned int c;
  351. for (c = 0; (c < GNUNET_ATS_NetworkTypeCount) && (c < dest_length); c++)
  352. {
  353. in_dest[c] = load_quota (cfg,
  354. c,
  355. "out");
  356. out_dest[c] = load_quota (cfg,
  357. c,
  358. "in");
  359. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  360. "Loaded quota for network `%s' (in/out): %llu %llu\n",
  361. GNUNET_ATS_print_network_type (c),
  362. in_dest[c],
  363. out_dest[c]);
  364. }
  365. return c;
  366. }
  367. /**
  368. * Initialize plugins subsystem.
  369. *
  370. * @param cfg configuration to use
  371. * @return #GNUNET_OK on success, #GNUNET_SYSERR on error (failed to load
  372. * solver plugin)
  373. */
  374. int
  375. GAS_plugin_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
  376. {
  377. char *mode_str;
  378. /* Figure out configured solution method */
  379. if (GNUNET_SYSERR ==
  380. GNUNET_CONFIGURATION_get_value_string (cfg,
  381. "ats",
  382. "MODE",
  383. &mode_str))
  384. {
  385. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  386. "No resource assignment method configured, using proportional approach\n");
  387. mode_str = GNUNET_strdup ("proportional");
  388. }
  389. env.cls = NULL;
  390. env.info_cb = &solver_info_cb;
  391. env.bandwidth_changed_cb = &bandwidth_changed_cb;
  392. env.get_preferences = &GAS_preference_get_by_peer;
  393. env.get_connectivity = &GAS_connectivity_has_peer;
  394. env.cfg = cfg;
  395. env.stats = GSA_stats;
  396. env.addresses = GSA_addresses;
  397. env.network_count = GNUNET_ATS_NetworkTypeCount;
  398. load_quotas (cfg,
  399. env.out_quota,
  400. env.in_quota,
  401. GNUNET_ATS_NetworkTypeCount);
  402. GNUNET_asprintf (&plugin,
  403. "libgnunet_plugin_ats_%s",
  404. mode_str);
  405. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  406. "Initializing solver `%s'\n",
  407. mode_str);
  408. GNUNET_free (mode_str);
  409. if (NULL == (sf = GNUNET_PLUGIN_load (plugin, &env)))
  410. {
  411. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  412. _("Failed to initialize solver `%s'!\n"),
  413. plugin);
  414. return GNUNET_SYSERR;
  415. }
  416. return GNUNET_OK;
  417. }
  418. /**
  419. * Shutdown address subsystem.
  420. */
  421. void
  422. GAS_plugin_done ()
  423. {
  424. GNUNET_PLUGIN_unload (plugin,
  425. sf);
  426. sf = NULL;
  427. GNUNET_free (plugin);
  428. plugin = NULL;
  429. }
  430. /**
  431. * Tell the solver that the given address can now be used
  432. * for talking to the respective peer.
  433. *
  434. * @param new_address the new address
  435. */
  436. void
  437. GAS_plugin_new_address (struct ATS_Address *new_address)
  438. {
  439. sf->s_add (sf->cls,
  440. new_address,
  441. new_address->properties.scope); /* FIXME: remove 3rd arg here! */
  442. }
  443. /**
  444. * Tell the solver that the given address is no longer valid
  445. * can cannot be used any longer.
  446. *
  447. * @param address address that was deleted
  448. */
  449. void
  450. GAS_plugin_delete_address (struct ATS_Address *address)
  451. {
  452. sf->s_del (sf->cls,
  453. address);
  454. }
  455. /**
  456. * Tell the solver that the given client has expressed its
  457. * appreciation for the past performance of a given connection.
  458. *
  459. * @param application client providing the feedback
  460. * @param peer peer the feedback is about
  461. * @param scope timeframe the feedback applies to
  462. * @param kind performance property the feedback relates to
  463. * @param score_abs degree of the appreciation
  464. */
  465. void
  466. GAS_plugin_notify_feedback (struct GNUNET_SERVER_Client *application,
  467. const struct GNUNET_PeerIdentity *peer,
  468. const struct GNUNET_TIME_Relative scope,
  469. enum GNUNET_ATS_PreferenceKind kind,
  470. float score_abs)
  471. {
  472. sf->s_feedback (sf->cls,
  473. application,
  474. peer,
  475. scope,
  476. kind,
  477. score_abs);
  478. }
  479. /**
  480. * Stop instant solving, there are many state updates
  481. * happening in bulk right now.
  482. */
  483. void
  484. GAS_plugin_solver_lock ()
  485. {
  486. sf->s_bulk_start (sf->cls);
  487. }
  488. /**
  489. * Resume instant solving, we are done with the bulk state updates.
  490. */
  491. void
  492. GAS_plugin_solver_unlock ()
  493. {
  494. sf->s_bulk_stop (sf->cls);
  495. }
  496. /**
  497. * Notify the plugin that a request to connect to
  498. * a particular peer was given to us.
  499. *
  500. * @param pid identity of peer we now care about
  501. */
  502. void
  503. GAS_plugin_request_connect_start (const struct GNUNET_PeerIdentity *pid)
  504. {
  505. sf->s_get (sf->cls,
  506. pid);
  507. }
  508. /**
  509. * Notify the plugin that a request to connect to
  510. * a particular peer was dropped.
  511. *
  512. * @param pid identity of peer we care now less about
  513. */
  514. void
  515. GAS_plugin_request_connect_stop (const struct GNUNET_PeerIdentity *pid)
  516. {
  517. sf->s_get_stop (sf->cls,
  518. pid);
  519. }
  520. /* end of gnunet-service-ats_plugins.c */