testbed_api_topology.c 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542
  1. /*
  2. This file is part of GNUnet
  3. (C) 2008--2013 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 testbed/testbed_api_topology.c
  19. * @brief topology-generation functions
  20. * @author Christian Grothoff
  21. */
  22. #include "platform.h"
  23. #include "gnunet_testbed_service.h"
  24. #include "testbed_api.h"
  25. #include "testbed_api_peers.h"
  26. #include "testbed_api_operations.h"
  27. #include "testbed_api_topology.h"
  28. /**
  29. * Generic loggins shorthand
  30. */
  31. #define LOG(kind,...) \
  32. GNUNET_log_from (kind, "testbed-api-topology", __VA_ARGS__)
  33. /**
  34. * Default number of retires
  35. */
  36. #define DEFAULT_RETRY_CNT 3
  37. /**
  38. * Context information for topology operations
  39. */
  40. struct TopologyContext;
  41. /**
  42. * Representation of an overlay link
  43. */
  44. struct OverlayLink
  45. {
  46. /**
  47. * An operation corresponding to this link
  48. */
  49. struct GNUNET_TESTBED_Operation *op;
  50. /**
  51. * The topology context this link is a part of
  52. */
  53. struct TopologyContext *tc;
  54. /**
  55. * position of peer A's handle in peers array
  56. */
  57. uint32_t A;
  58. /**
  59. * position of peer B's handle in peers array
  60. */
  61. uint32_t B;
  62. };
  63. /**
  64. * Representation of an underlay link
  65. */
  66. struct UnderlayLink
  67. {
  68. /**
  69. * position of peer A's handle in peers array
  70. */
  71. uint32_t A;
  72. /**
  73. * position of peer B's handle in peers array
  74. */
  75. uint32_t B;
  76. /**
  77. * Bandwidth of the link in bytes per second
  78. */
  79. uint32_t bandwidth;
  80. /**
  81. * Latency of the link in milliseconds
  82. */
  83. uint32_t latency;
  84. /**
  85. * Loss in the link in percentage of message dropped
  86. */
  87. uint32_t loss;
  88. };
  89. struct RetryListEntry
  90. {
  91. /**
  92. * the next pointer for the DLL
  93. */
  94. struct RetryListEntry *next;
  95. /**
  96. * the prev pointer for the DLL
  97. */
  98. struct RetryListEntry *prev;
  99. /**
  100. * The link to be retired
  101. */
  102. struct OverlayLink *link;
  103. };
  104. /**
  105. * Context information for overlay topologies
  106. */
  107. struct TopologyContextOverlay
  108. {
  109. /**
  110. * The array of peers
  111. */
  112. struct GNUNET_TESTBED_Peer **peers;
  113. /**
  114. * An array of links; this array is of size link_array_size
  115. */
  116. struct OverlayLink *link_array;
  117. /**
  118. * The operation closure
  119. */
  120. void *op_cls;
  121. /**
  122. * topology generation completion callback
  123. */
  124. GNUNET_TESTBED_TopologyCompletionCallback comp_cb;
  125. /**
  126. * The closure for the above callback
  127. */
  128. void *comp_cb_cls;
  129. /**
  130. * DLL head for retry list
  131. */
  132. struct RetryListEntry *rl_head;
  133. /**
  134. * DLL tail for retry list
  135. */
  136. struct RetryListEntry *rl_tail;
  137. /**
  138. * How many retries to do before we give up
  139. */
  140. unsigned int retry_cnt;
  141. /**
  142. * Number of links to try
  143. */
  144. unsigned int nlinks;
  145. /**
  146. * How many links have been completed
  147. */
  148. unsigned int ncompleted;
  149. /**
  150. * Total successfully established overlay connections
  151. */
  152. unsigned int nsuccess;
  153. /**
  154. * Total failed overlay connections
  155. */
  156. unsigned int nfailures;
  157. };
  158. /**
  159. * Topology context information for underlay topologies
  160. */
  161. struct TopologyContextUnderlay
  162. {
  163. /**
  164. * The link array
  165. */
  166. struct UnderlayLink *link_array;
  167. };
  168. /**
  169. * Context information for topology operations
  170. */
  171. struct TopologyContext
  172. {
  173. /**
  174. * The type of this context
  175. */
  176. enum {
  177. /**
  178. * Type for underlay topology
  179. */
  180. TOPOLOGYCONTEXT_TYPE_UNDERLAY = 0,
  181. /**
  182. * Type for overlay topology
  183. */
  184. TOPOLOGYCONTEXT_TYPE_OVERLAY
  185. } type;
  186. union {
  187. /**
  188. * Topology context information for overlay topology
  189. */
  190. struct TopologyContextOverlay overlay;
  191. /**
  192. * Topology context information for underlay topology
  193. */
  194. struct TopologyContextUnderlay underlay;
  195. } u;
  196. /**
  197. * The number of peers
  198. */
  199. unsigned int num_peers;
  200. /**
  201. * The size of the link array
  202. */
  203. unsigned int link_array_size;
  204. };
  205. /**
  206. * A array of names representing topologies. Should be in sync with enum
  207. * GNUNET_TESTBED_TopologyOption
  208. */
  209. const char *topology_strings[] = {
  210. /**
  211. * A clique (everyone connected to everyone else). No options. If there are N
  212. * peers this topology results in (N * (N -1)) connections.
  213. */
  214. "CLIQUE",
  215. /**
  216. * Small-world network (2d torus plus random links). Followed
  217. * by the number of random links to add (unsigned int).
  218. */
  219. "SMALL_WORLD",
  220. /**
  221. * Small-world network (ring plus random links). Followed
  222. * by the number of random links to add (unsigned int).
  223. */
  224. "SMALL_WORLD_RING",
  225. /**
  226. * Ring topology. No options.
  227. */
  228. "RING",
  229. /**
  230. * 2-d torus. No options.
  231. */
  232. "2D_TORUS",
  233. /**
  234. * Random graph. Followed by the number of random links to be established
  235. * (unsigned int)
  236. */
  237. "RANDOM", // GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI
  238. /**
  239. * Certain percentage of peers are unable to communicate directly
  240. * replicating NAT conditions. Followed by the fraction of
  241. * NAT'ed peers (float).
  242. */
  243. "INTERNAT",
  244. /**
  245. * Scale free topology. Followed by the maximum number of links a node can
  246. * have (unsigned int); and the number of links a new node should have when
  247. * it is added to the network (unsigned int)
  248. */
  249. "SCALE_FREE",
  250. /**
  251. * Straight line topology. No options.
  252. */
  253. "LINE",
  254. /**
  255. * Read a topology from a given file. Followed by the name of the file (const char *).
  256. */
  257. "FROM_FILE",
  258. /**
  259. * All peers are disconnected. No options.
  260. */
  261. "NONE",
  262. /**
  263. * End of strings
  264. */
  265. NULL
  266. };
  267. /**
  268. * Callback to be called when an overlay_link operation complete
  269. *
  270. * @param cls element of the link_op array which points to the corresponding operation
  271. * @param op the operation that has been finished
  272. * @param emsg error message in case the operation has failed; will be NULL if
  273. * operation has executed successfully.
  274. */
  275. static void
  276. overlay_link_completed (void *cls, struct GNUNET_TESTBED_Operation *op,
  277. const char *emsg)
  278. {
  279. struct OverlayLink *link = cls;
  280. struct TopologyContext *tc;
  281. struct TopologyContextOverlay *overlay;
  282. struct RetryListEntry *retry_entry;
  283. GNUNET_assert (op == link->op);
  284. GNUNET_TESTBED_operation_done (op);
  285. link->op = NULL;
  286. tc = link->tc;
  287. GNUNET_assert (TOPOLOGYCONTEXT_TYPE_OVERLAY == tc->type);
  288. overlay = &tc->u.overlay;
  289. if (NULL != emsg)
  290. {
  291. overlay->nfailures++;
  292. if (0 != overlay->retry_cnt)
  293. {
  294. LOG (GNUNET_ERROR_TYPE_WARNING,
  295. "Error while establishing a link: %s -- Retrying\n", emsg);
  296. retry_entry = GNUNET_new (struct RetryListEntry);
  297. retry_entry->link = link;
  298. GNUNET_CONTAINER_DLL_insert_tail (overlay->rl_head, overlay->rl_tail, retry_entry);
  299. }
  300. }
  301. else
  302. overlay->nsuccess++;
  303. overlay->ncompleted++;
  304. if (overlay->ncompleted < overlay->nlinks)
  305. return;
  306. if ((0 != overlay->retry_cnt) && (NULL != overlay->rl_head))
  307. {
  308. overlay->retry_cnt--;
  309. overlay->ncompleted = 0;
  310. overlay->nlinks = 0;
  311. while (NULL != (retry_entry = overlay->rl_head))
  312. {
  313. link = retry_entry->link;
  314. link->op =
  315. GNUNET_TESTBED_overlay_connect (overlay->op_cls, &overlay_link_completed,
  316. link, overlay->peers[link->A],
  317. overlay->peers[link->B]);
  318. overlay->nlinks++;
  319. GNUNET_CONTAINER_DLL_remove (overlay->rl_head, overlay->rl_tail, retry_entry);
  320. GNUNET_free (retry_entry);
  321. }
  322. return;
  323. }
  324. if (NULL != overlay->comp_cb)
  325. {
  326. overlay->comp_cb (overlay->comp_cb_cls, overlay->nsuccess, overlay->nfailures);
  327. }
  328. }
  329. /**
  330. * Function called when a overlay connect operation is ready
  331. *
  332. * @param cls the Topology context
  333. */
  334. static void
  335. opstart_overlay_configure_topology (void *cls)
  336. {
  337. struct TopologyContext *tc = cls;
  338. struct TopologyContextOverlay *overlay;
  339. unsigned int p;
  340. GNUNET_assert (TOPOLOGYCONTEXT_TYPE_OVERLAY == tc->type);
  341. overlay = &tc->u.overlay;
  342. overlay->nlinks = tc->link_array_size;
  343. for (p = 0; p < tc->link_array_size; p++)
  344. {
  345. overlay->link_array[p].op =
  346. GNUNET_TESTBED_overlay_connect (overlay->op_cls, &overlay_link_completed,
  347. &overlay->link_array[p],
  348. overlay->peers[overlay->link_array[p].A],
  349. overlay->peers[overlay->link_array[p].B]);
  350. }
  351. }
  352. /**
  353. * Callback which will be called when overlay connect operation is released
  354. *
  355. * @param cls the Topology context
  356. */
  357. static void
  358. oprelease_overlay_configure_topology (void *cls)
  359. {
  360. struct TopologyContext *tc = cls;
  361. struct TopologyContextOverlay *overlay;
  362. struct RetryListEntry *retry_entry;
  363. unsigned int p;
  364. GNUNET_assert (TOPOLOGYCONTEXT_TYPE_OVERLAY == tc->type);
  365. overlay = &tc->u.overlay;
  366. while (NULL != (retry_entry = overlay->rl_head))
  367. {
  368. GNUNET_CONTAINER_DLL_remove (overlay->rl_head, overlay->rl_tail, retry_entry);
  369. GNUNET_free (retry_entry);
  370. }
  371. if (NULL != overlay->link_array)
  372. {
  373. for (p = 0; p < tc->link_array_size; p++)
  374. if (NULL != overlay->link_array[p].op)
  375. GNUNET_TESTBED_operation_done (overlay->link_array[p].op);
  376. GNUNET_free (overlay->link_array);
  377. }
  378. GNUNET_free (tc);
  379. }
  380. /**
  381. * Populates the OverlayLink structure.
  382. *
  383. * @param offset the offset of the link array to use
  384. * @param A the peer A. Should be different from B
  385. * @param B the peer B. Should be different from A
  386. * @param tc the TopologyContext
  387. * @return
  388. */
  389. static void
  390. make_link (unsigned int offset, uint32_t A, uint32_t B,
  391. struct TopologyContext *tc)
  392. {
  393. GNUNET_assert (A != B);
  394. switch (tc->type)
  395. {
  396. case TOPOLOGYCONTEXT_TYPE_OVERLAY:
  397. {
  398. struct TopologyContextOverlay *overlay;
  399. struct OverlayLink *olink;
  400. overlay = &tc->u.overlay;
  401. GNUNET_assert (offset < tc->link_array_size);
  402. olink = &overlay->link_array[offset];
  403. LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %u to %u\n", B, A);
  404. olink->A = A;
  405. olink->B = B;
  406. olink->op = NULL;
  407. olink->tc = tc;
  408. }
  409. break;
  410. case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
  411. {
  412. struct TopologyContextUnderlay *underlay;
  413. struct UnderlayLink *ulink;
  414. underlay = &tc->u.underlay;
  415. GNUNET_assert (offset < tc->link_array_size);
  416. ulink = &underlay->link_array[offset];
  417. ulink->A = A;
  418. ulink->B = B;
  419. }
  420. break;
  421. }
  422. }
  423. /**
  424. * Generates line topology
  425. *
  426. * @param tc the topology context
  427. */
  428. static void
  429. gen_topo_line (struct TopologyContext *tc)
  430. {
  431. unsigned int cnt;
  432. tc->link_array_size = tc->num_peers - 1;
  433. switch (tc->type)
  434. {
  435. case TOPOLOGYCONTEXT_TYPE_OVERLAY:
  436. {
  437. struct TopologyContextOverlay *overlay;
  438. overlay = &tc->u.overlay;
  439. overlay->link_array =
  440. GNUNET_malloc (sizeof (struct OverlayLink) * tc->link_array_size);
  441. }
  442. break;
  443. case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
  444. {
  445. struct TopologyContextUnderlay *underlay;
  446. underlay = &tc->u.underlay;
  447. underlay->link_array =
  448. GNUNET_malloc (sizeof (struct UnderlayLink) * tc->link_array_size);
  449. }
  450. break;
  451. }
  452. for (cnt = 0; cnt < (tc->link_array_size); cnt++)
  453. make_link (cnt, cnt, cnt + 1, tc);
  454. }
  455. /**
  456. * Generates ring topology
  457. *
  458. * @param tc the topology context
  459. */
  460. static void
  461. gen_topo_ring (struct TopologyContext *tc)
  462. {
  463. gen_topo_line (tc);
  464. tc->link_array_size++;
  465. switch (tc->type)
  466. {
  467. case TOPOLOGYCONTEXT_TYPE_OVERLAY:
  468. {
  469. struct TopologyContextOverlay *overlay;
  470. overlay = &tc->u.overlay;
  471. overlay->link_array =
  472. GNUNET_realloc (overlay->link_array, sizeof (struct OverlayLink) *
  473. tc->link_array_size);
  474. }
  475. break;
  476. case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
  477. {
  478. struct TopologyContextUnderlay *underlay;
  479. underlay = &tc->u.underlay;
  480. underlay->link_array =
  481. GNUNET_realloc (underlay->link_array, sizeof (struct UnderlayLink) *
  482. tc->link_array_size);
  483. }
  484. break;
  485. }
  486. make_link (tc->link_array_size - 1, tc->num_peers - 1, 0, tc);
  487. }
  488. /**
  489. * Returns the number of links that are required to generate a 2d torus for the
  490. * given number of peers. Also returns the arrangment (number of rows and the
  491. * length of each row)
  492. *
  493. * @param num_peers number of peers
  494. * @param rows number of rows in the 2d torus. Can be NULL
  495. * @param rows_len the length of each row. This array will be allocated
  496. * fresh. The caller should free it. Can be NULL
  497. * @return the number of links that are required to generate a 2d torus for the
  498. * given number of peers
  499. */
  500. unsigned int
  501. GNUNET_TESTBED_2dtorus_calc_links (unsigned int num_peers, unsigned int *rows,
  502. unsigned int **rows_len)
  503. {
  504. double sq;
  505. unsigned int sq_floor;
  506. unsigned int _rows;
  507. unsigned int *_rows_len;
  508. unsigned int x;
  509. unsigned int y;
  510. unsigned int _num_peers;
  511. unsigned int cnt;
  512. sq = sqrt (num_peers);
  513. sq = floor (sq);
  514. sq_floor = (unsigned int) sq;
  515. _rows = (sq_floor + 1);
  516. _rows_len = GNUNET_malloc (sizeof (unsigned int) * _rows);
  517. for (y = 0; y < _rows - 1; y++)
  518. _rows_len[y] = sq_floor;
  519. _num_peers = sq_floor * sq_floor;
  520. cnt = (_num_peers < 2) ? _num_peers : 2 * _num_peers;
  521. x = 0;
  522. y = 0;
  523. while (_num_peers < num_peers)
  524. {
  525. if (x < y)
  526. _rows_len[_rows - 1] = ++x;
  527. else
  528. _rows_len[y++]++;
  529. _num_peers++;
  530. }
  531. cnt += (x < 2) ? x : 2 * x;
  532. cnt += (y < 2) ? y : 2 * y;
  533. if (0 == _rows_len[_rows - 1])
  534. _rows--;
  535. if (NULL != rows)
  536. *rows = _rows;
  537. if (NULL != rows_len)
  538. *rows_len = _rows_len;
  539. else
  540. GNUNET_free (_rows_len);
  541. return cnt;
  542. }
  543. /**
  544. * Generates ring topology
  545. *
  546. * @param tc the topology context
  547. */
  548. static void
  549. gen_topo_2dtorus (struct TopologyContext *tc)
  550. {
  551. unsigned int rows;
  552. unsigned int *rows_len;
  553. unsigned int x;
  554. unsigned int y;
  555. unsigned int cnt;
  556. unsigned int offset;
  557. tc->link_array_size =
  558. GNUNET_TESTBED_2dtorus_calc_links (tc->num_peers, &rows, &rows_len);
  559. switch (tc->type)
  560. {
  561. case TOPOLOGYCONTEXT_TYPE_OVERLAY:
  562. {
  563. struct TopologyContextOverlay *overlay;
  564. overlay = &tc->u.overlay;
  565. overlay->link_array =
  566. GNUNET_malloc (sizeof (struct OverlayLink) * tc->link_array_size);
  567. }
  568. break;
  569. case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
  570. {
  571. struct TopologyContextUnderlay *underlay;
  572. underlay = &tc->u.underlay;
  573. underlay->link_array =
  574. GNUNET_malloc (sizeof (struct UnderlayLink) * tc->link_array_size);
  575. break;
  576. }
  577. }
  578. cnt = 0;
  579. offset = 0;
  580. for (y = 0; y < rows; y++)
  581. {
  582. for (x = 0; x < rows_len[y] - 1; x++)
  583. {
  584. make_link (cnt, offset + x, offset + x + 1, tc);
  585. cnt++;
  586. }
  587. if (0 == x)
  588. break;
  589. make_link (cnt, offset + x, offset, tc);
  590. cnt++;
  591. offset += rows_len[y];
  592. }
  593. for (x = 0; x < rows_len[0]; x++)
  594. {
  595. offset = 0;
  596. for (y = 0; y < rows - 1; y++)
  597. {
  598. if (x >= rows_len[y + 1])
  599. break;
  600. GNUNET_assert (x < rows_len[y + 1]);
  601. make_link (cnt, offset + x, offset + rows_len[y] + x, tc);
  602. offset += rows_len[y];
  603. cnt++;
  604. }
  605. if (0 == offset)
  606. break;
  607. make_link (cnt, offset + x, x, tc);
  608. cnt++;
  609. }
  610. GNUNET_assert (cnt == tc->link_array_size);
  611. GNUNET_free (rows_len);
  612. }
  613. /**
  614. * Generates ring topology
  615. *
  616. * @param tc the topology context
  617. * @param links the number of random links to establish
  618. * @param append GNUNET_YES to add links to existing link array; GNUNET_NO to
  619. * create a new link array
  620. */
  621. static void
  622. gen_topo_random (struct TopologyContext *tc, unsigned int links, int append)
  623. {
  624. unsigned int cnt;
  625. unsigned int index;
  626. uint32_t A_rand;
  627. uint32_t B_rand;
  628. if (1 == tc->num_peers)
  629. return;
  630. if (GNUNET_YES == append)
  631. {
  632. index = tc->link_array_size;
  633. tc->link_array_size += links;
  634. }
  635. else
  636. {
  637. index = 0;
  638. tc->link_array_size = links;
  639. }
  640. switch (tc->type)
  641. {
  642. case TOPOLOGYCONTEXT_TYPE_OVERLAY:
  643. {
  644. struct TopologyContextOverlay *overlay;
  645. overlay = &tc->u.overlay;
  646. if (GNUNET_YES != append)
  647. {
  648. GNUNET_assert (NULL == overlay->link_array);
  649. overlay->link_array =
  650. GNUNET_malloc (sizeof (struct OverlayLink) * tc->link_array_size);
  651. break;
  652. }
  653. GNUNET_assert ((0 < tc->link_array_size) && (NULL != overlay->link_array));
  654. overlay->link_array =
  655. GNUNET_realloc (overlay->link_array,
  656. sizeof (struct OverlayLink) * tc->link_array_size);
  657. break;
  658. }
  659. case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
  660. {
  661. struct TopologyContextUnderlay *underlay;
  662. underlay = &tc->u.underlay;
  663. if (GNUNET_YES != append)
  664. {
  665. GNUNET_assert (NULL == underlay->link_array);
  666. underlay->link_array =
  667. GNUNET_malloc (sizeof (struct UnderlayLink) * tc->link_array_size);
  668. break;
  669. }
  670. GNUNET_assert ((0 < tc->link_array_size) && (NULL != underlay->link_array));
  671. underlay->link_array =
  672. GNUNET_realloc (underlay->link_array,
  673. sizeof (struct UnderlayLink) * tc->link_array_size);
  674. break;
  675. }
  676. }
  677. for (cnt = 0; cnt < links; cnt++)
  678. {
  679. do
  680. {
  681. A_rand =
  682. GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, tc->num_peers);
  683. B_rand =
  684. GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, tc->num_peers);
  685. }
  686. while (A_rand == B_rand);
  687. make_link (index+cnt, A_rand, B_rand, tc);
  688. }
  689. }
  690. /**
  691. * Generates scale free network. Its construction is described in:
  692. *
  693. * "Emergence of Scaling in Random Networks." Science 286, 509-512, 1999.
  694. *
  695. * @param tc the topology context
  696. * @param cap maximum allowed node degree
  697. * @param m number of edges to establish for a new node when it is added to the
  698. * network
  699. */
  700. static void
  701. gen_topo_scale_free (struct TopologyContext *tc, uint16_t cap, uint8_t m)
  702. {
  703. unsigned int *deg;
  704. unsigned int *etab;
  705. unsigned int *used;
  706. unsigned int etaboff;
  707. unsigned int cnt;
  708. unsigned int cnt2;
  709. unsigned int peer;
  710. unsigned int random_peer;
  711. unsigned int links;
  712. unsigned int off;
  713. unsigned int redo_threshold;
  714. etaboff = 0;
  715. tc->link_array_size = tc->num_peers * m;
  716. switch (tc->type)
  717. {
  718. case TOPOLOGYCONTEXT_TYPE_OVERLAY:
  719. {
  720. struct TopologyContextOverlay *overlay;
  721. overlay = &tc->u.overlay;
  722. overlay->link_array = GNUNET_malloc_large (sizeof (struct OverlayLink) *
  723. tc->link_array_size);
  724. }
  725. break;
  726. case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
  727. {
  728. struct TopologyContextUnderlay *underlay;
  729. underlay = &tc->u.underlay;
  730. underlay->link_array = GNUNET_malloc_large (sizeof (struct UnderlayLink) *
  731. tc->link_array_size);
  732. }
  733. break;
  734. }
  735. etab = GNUNET_malloc_large (sizeof (unsigned int) * 2 * tc->link_array_size);
  736. deg = GNUNET_malloc (sizeof (unsigned int) * tc->num_peers);
  737. used = GNUNET_malloc (sizeof (unsigned int) * m);
  738. /* start by connecting peer 1 to peer 0 */
  739. make_link (0, 0, 1, tc);
  740. deg[0]++;
  741. deg[1]++;
  742. etab[etaboff++] = 0;
  743. etab[etaboff++] = 1;
  744. links = 1;
  745. for (peer = 2; peer < tc->num_peers; peer++)
  746. {
  747. if (cap < deg[peer])
  748. continue;
  749. for (cnt = 0; cnt < GNUNET_MIN (peer, m); cnt++)
  750. {
  751. redo_threshold = 0;
  752. redo:
  753. off = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, etaboff);
  754. random_peer = etab[off];
  755. if (cap < deg[random_peer])
  756. {
  757. if (++redo_threshold > GNUNET_MAX (1, cap / 2))
  758. {
  759. redo_threshold = 0;
  760. off = 0;
  761. for (cnt2 = 0; cnt2 < etaboff; cnt2++)
  762. {
  763. if (random_peer == etab[cnt2])
  764. {
  765. off++;
  766. continue;
  767. }
  768. etab[cnt2 - off] = etab[cnt2];
  769. }
  770. etaboff -= off;
  771. }
  772. goto redo;
  773. }
  774. for (cnt2 = 0; cnt2 < cnt; cnt2++)
  775. if (random_peer == used[cnt2])
  776. goto redo;
  777. make_link (links + cnt, random_peer, peer, tc);
  778. deg[random_peer]++;
  779. deg[peer]++;
  780. used[cnt] = random_peer;
  781. }
  782. for (cnt = 0; cnt < GNUNET_MIN (peer, m); cnt++)
  783. {
  784. etab[etaboff++] = used[cnt];
  785. etab[etaboff++] = peer;
  786. }
  787. links += GNUNET_MIN (peer, m);
  788. }
  789. GNUNET_free (etab);
  790. GNUNET_free (used);
  791. GNUNET_free (deg);
  792. GNUNET_assert (links <= tc->link_array_size);
  793. tc->link_array_size = links;
  794. switch (tc->type)
  795. {
  796. case TOPOLOGYCONTEXT_TYPE_OVERLAY:
  797. {
  798. struct TopologyContextOverlay *overlay;
  799. overlay = &tc->u.overlay;
  800. overlay->link_array =
  801. GNUNET_realloc (overlay->link_array, sizeof (struct OverlayLink) * tc->link_array_size);
  802. }
  803. break;
  804. case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
  805. {
  806. struct TopologyContextUnderlay *underlay;
  807. underlay = &tc->u.underlay;
  808. underlay->link_array =
  809. GNUNET_realloc (underlay->link_array, sizeof (struct UnderlayLink) * tc->link_array_size);
  810. }
  811. break;
  812. }
  813. }
  814. /**
  815. * Generates topology from the given file
  816. *
  817. * @param tc the topology context
  818. * @param filename the filename of the file containing topology data
  819. */
  820. static void
  821. gen_topo_from_file (struct TopologyContext *tc, const char *filename)
  822. {
  823. char *data;
  824. char *end;
  825. char *buf;
  826. uint64_t fs;
  827. uint64_t offset;
  828. unsigned long int peer_id;
  829. unsigned long int other_peer_id;
  830. enum ParseState
  831. {
  832. /**
  833. * We read the peer index
  834. */
  835. PEER_INDEX,
  836. /**
  837. * We read the other peer indices
  838. */
  839. OTHER_PEER_INDEX,
  840. } state;
  841. int status;
  842. status = GNUNET_SYSERR;
  843. if (GNUNET_YES != GNUNET_DISK_file_test (filename))
  844. {
  845. LOG (GNUNET_ERROR_TYPE_ERROR, _("Topology file %s not found\n"), filename);
  846. return;
  847. }
  848. if (GNUNET_OK !=
  849. GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
  850. {
  851. LOG (GNUNET_ERROR_TYPE_ERROR, _("Topology file %s has no data\n"),
  852. filename);
  853. return;
  854. }
  855. data = GNUNET_malloc (fs);
  856. if (fs != GNUNET_DISK_fn_read (filename, data, fs))
  857. {
  858. LOG (GNUNET_ERROR_TYPE_ERROR, _("Topology file %s cannot be read\n"),
  859. filename);
  860. goto _exit;
  861. }
  862. offset = 0;
  863. peer_id = 0;
  864. state = PEER_INDEX;
  865. while (offset < fs)
  866. {
  867. if (0 != isspace (data[offset]))
  868. {
  869. offset++;
  870. continue;
  871. }
  872. switch (state)
  873. {
  874. case PEER_INDEX:
  875. buf = strchr (&data[offset], ':');
  876. if (NULL == buf)
  877. {
  878. LOG (GNUNET_ERROR_TYPE_ERROR,
  879. _("Failed to read peer index from toology file: %s"), filename);
  880. goto _exit;
  881. }
  882. *buf = '\0';
  883. errno = 0;
  884. peer_id = (unsigned int) strtoul (&data[offset], &end, 10);
  885. if (0 != errno)
  886. {
  887. LOG (GNUNET_ERROR_TYPE_ERROR,
  888. _("Value in given topology file: %s out of range\n"), filename);
  889. goto _exit;
  890. }
  891. if (&data[offset] == end)
  892. {
  893. LOG (GNUNET_ERROR_TYPE_ERROR,
  894. _("Failed to read peer index from topology file: %s"), filename);
  895. goto _exit;
  896. }
  897. if (tc->num_peers <= peer_id)
  898. {
  899. LOG (GNUNET_ERROR_TYPE_ERROR,
  900. _("Topology file needs more peers than given ones\n"), filename);
  901. goto _exit;
  902. }
  903. state = OTHER_PEER_INDEX;
  904. offset += ((unsigned int) (buf - &data[offset])) + 1;
  905. break;
  906. case OTHER_PEER_INDEX:
  907. errno = 0;
  908. other_peer_id = (unsigned int) strtoul (&data[offset], &end, 10);
  909. if (0 != errno)
  910. {
  911. LOG (GNUNET_ERROR_TYPE_ERROR,
  912. _("Value in given topology file: %s out of range\n"), filename);
  913. goto _exit;
  914. }
  915. if (&data[offset] == end)
  916. {
  917. LOG (GNUNET_ERROR_TYPE_ERROR,
  918. _("Failed to read peer index from topology file: %s"), filename);
  919. goto _exit;
  920. }
  921. if (tc->num_peers <= other_peer_id)
  922. {
  923. LOG (GNUNET_ERROR_TYPE_ERROR,
  924. _("Topology file needs more peers than given ones\n"), filename);
  925. goto _exit;
  926. }
  927. if (peer_id != other_peer_id)
  928. {
  929. tc->link_array_size++;
  930. switch (tc->type)
  931. {
  932. case TOPOLOGYCONTEXT_TYPE_OVERLAY:
  933. {
  934. struct TopologyContextOverlay *overlay;
  935. overlay = &tc->u.overlay;
  936. overlay->link_array =
  937. GNUNET_realloc (overlay->link_array,
  938. sizeof (struct OverlayLink) * tc->link_array_size);
  939. }
  940. break;
  941. case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
  942. {
  943. struct TopologyContextUnderlay *underlay;
  944. underlay = &tc->u.underlay;
  945. underlay->link_array =
  946. GNUNET_realloc (underlay->link_array,
  947. sizeof (struct UnderlayLink) * tc->link_array_size);
  948. }
  949. break;
  950. }
  951. offset += end - &data[offset];
  952. make_link (tc->link_array_size - 1, peer_id, other_peer_id, tc);
  953. }
  954. else
  955. LOG (GNUNET_ERROR_TYPE_WARNING,
  956. _("Ignoring to connect peer %u to peer %u\n"), peer_id,
  957. other_peer_id);
  958. while (('\n' != data[offset]) && ('|' != data[offset]) && (offset < fs))
  959. offset++;
  960. if ('\n' == data[offset])
  961. state = PEER_INDEX;
  962. else if ('|' == data[offset])
  963. {
  964. state = OTHER_PEER_INDEX;
  965. offset++;
  966. }
  967. break;
  968. }
  969. }
  970. status = GNUNET_OK;
  971. _exit:
  972. GNUNET_free (data);
  973. if (GNUNET_OK != status)
  974. {
  975. LOG (GNUNET_ERROR_TYPE_WARNING, "Removing link data read from the file\n");
  976. tc->link_array_size = 0;
  977. switch (tc->type)
  978. {
  979. case TOPOLOGYCONTEXT_TYPE_OVERLAY:
  980. {
  981. struct TopologyContextOverlay *overlay;
  982. overlay = &tc->u.overlay;
  983. GNUNET_free_non_null (overlay->link_array);
  984. overlay->link_array = NULL;
  985. }
  986. break;
  987. case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
  988. {
  989. struct TopologyContextUnderlay *underlay;
  990. underlay = &tc->u.underlay;
  991. GNUNET_free_non_null (underlay->link_array);
  992. underlay->link_array = NULL;
  993. }
  994. break;
  995. }
  996. }
  997. }
  998. /**
  999. * Generates clique topology
  1000. *
  1001. * @param tc the topology context
  1002. */
  1003. static void
  1004. gen_topo_clique (struct TopologyContext *tc)
  1005. {
  1006. unsigned int cnt;
  1007. unsigned int offset;
  1008. unsigned int neighbour;
  1009. tc->link_array_size = tc->num_peers * (tc->num_peers - 1);
  1010. switch (tc->type)
  1011. {
  1012. case TOPOLOGYCONTEXT_TYPE_OVERLAY:
  1013. {
  1014. struct TopologyContextOverlay *overlay;
  1015. overlay = &tc->u.overlay;
  1016. overlay->link_array = GNUNET_malloc (sizeof (struct OverlayLink) *
  1017. tc->link_array_size);
  1018. }
  1019. break;
  1020. case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
  1021. {
  1022. struct TopologyContextUnderlay *underlay;
  1023. underlay = &tc->u.underlay;
  1024. underlay->link_array = GNUNET_malloc (sizeof (struct UnderlayLink) *
  1025. tc->link_array_size);
  1026. }
  1027. }
  1028. offset = 0;
  1029. for (cnt = 0; cnt < tc->num_peers; cnt++)
  1030. {
  1031. for (neighbour = 0; neighbour < tc->num_peers; neighbour++)
  1032. {
  1033. if (neighbour == cnt)
  1034. continue;
  1035. make_link (offset, cnt, neighbour, tc);
  1036. offset++;
  1037. }
  1038. }
  1039. }
  1040. /**
  1041. * Configure overall network topology to have a particular shape.
  1042. *
  1043. * @param op_cls closure argument to give with the operation event
  1044. * @param num_peers number of peers in 'peers'
  1045. * @param peers array of 'num_peers' with the peers to configure
  1046. * @param topo desired underlay topology to use
  1047. * @param ap topology-specific options
  1048. * @return handle to the operation, NULL if configuring the topology
  1049. * is not allowed at this time
  1050. */
  1051. struct GNUNET_TESTBED_Operation *
  1052. GNUNET_TESTBED_underlay_configure_topology_va (void *op_cls,
  1053. unsigned int num_peers,
  1054. struct GNUNET_TESTBED_Peer
  1055. **peers,
  1056. enum
  1057. GNUNET_TESTBED_TopologyOption
  1058. topo, va_list ap)
  1059. {
  1060. GNUNET_break (0);
  1061. return NULL;
  1062. }
  1063. /**
  1064. * Configure overall network topology to have a particular shape.
  1065. *
  1066. * @param op_cls closure argument to give with the operation event
  1067. * @param num_peers number of peers in 'peers'
  1068. * @param peers array of 'num_peers' with the peers to configure
  1069. * @param topo desired underlay topology to use
  1070. * @param ... topology-specific options
  1071. * @return handle to the operation, NULL if configuring the topology
  1072. * is not allowed at this time
  1073. */
  1074. struct GNUNET_TESTBED_Operation *
  1075. GNUNET_TESTBED_underlay_configure_topology (void *op_cls,
  1076. unsigned int num_peers,
  1077. struct GNUNET_TESTBED_Peer **peers,
  1078. enum GNUNET_TESTBED_TopologyOption
  1079. topo, ...)
  1080. {
  1081. GNUNET_break (0);
  1082. return NULL;
  1083. }
  1084. /**
  1085. * All peers must have been started before calling this function.
  1086. * This function then connects the given peers in the P2P overlay
  1087. * using the given topology.
  1088. *
  1089. * @param op_cls closure argument to give with the peer connect operation events
  1090. * generated through this function
  1091. * @param num_peers number of peers in 'peers'
  1092. * @param peers array of 'num_peers' with the peers to configure
  1093. * @param max_connections the maximums number of overlay connections that will
  1094. * be made to achieve the given topology
  1095. * @param comp_cb the completion callback to call when the topology generation
  1096. * is completed
  1097. * @param comp_cb_cls closure for the above completion callback
  1098. * @param topo desired underlay topology to use
  1099. * @param va topology-specific options
  1100. * @return handle to the operation, NULL if connecting these
  1101. * peers is fundamentally not possible at this time (peers
  1102. * not running or underlay disallows) or if num_peers is less than 2
  1103. */
  1104. struct GNUNET_TESTBED_Operation *
  1105. GNUNET_TESTBED_overlay_configure_topology_va (void *op_cls,
  1106. unsigned int num_peers,
  1107. struct GNUNET_TESTBED_Peer **peers,
  1108. unsigned int *max_connections,
  1109. GNUNET_TESTBED_TopologyCompletionCallback
  1110. comp_cb,
  1111. void *comp_cb_cls,
  1112. enum GNUNET_TESTBED_TopologyOption topo,
  1113. va_list va)
  1114. {
  1115. struct TopologyContext *tc;
  1116. struct TopologyContextOverlay *overlay;
  1117. struct GNUNET_TESTBED_Operation *op;
  1118. struct GNUNET_TESTBED_Controller *c;
  1119. enum GNUNET_TESTBED_TopologyOption secondary_option;
  1120. if (num_peers < 2)
  1121. return NULL;
  1122. c = peers[0]->controller;
  1123. tc = GNUNET_new (struct TopologyContext);
  1124. tc->type = TOPOLOGYCONTEXT_TYPE_OVERLAY;
  1125. overlay = &tc->u.overlay;
  1126. overlay->peers = peers;
  1127. tc->num_peers = num_peers;
  1128. overlay->op_cls = op_cls;
  1129. overlay->retry_cnt = DEFAULT_RETRY_CNT;
  1130. overlay->comp_cb = comp_cb;
  1131. overlay->comp_cb_cls = comp_cb_cls;
  1132. switch (topo)
  1133. {
  1134. case GNUNET_TESTBED_TOPOLOGY_LINE:
  1135. gen_topo_line (tc);
  1136. break;
  1137. case GNUNET_TESTBED_TOPOLOGY_RING:
  1138. gen_topo_ring (tc);
  1139. break;
  1140. case GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI:
  1141. gen_topo_random (tc, va_arg (va, unsigned int), GNUNET_NO);
  1142. break;
  1143. case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING:
  1144. gen_topo_ring (tc);
  1145. gen_topo_random (tc, va_arg (va, unsigned int), GNUNET_YES);
  1146. break;
  1147. case GNUNET_TESTBED_TOPOLOGY_CLIQUE:
  1148. gen_topo_clique (tc);
  1149. break;
  1150. case GNUNET_TESTBED_TOPOLOGY_2D_TORUS:
  1151. gen_topo_2dtorus (tc);
  1152. break;
  1153. case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD:
  1154. gen_topo_2dtorus (tc);
  1155. gen_topo_random (tc, va_arg (va, unsigned int), GNUNET_YES);
  1156. break;
  1157. case GNUNET_TESTBED_TOPOLOGY_SCALE_FREE:
  1158. {
  1159. uint16_t cap;
  1160. uint8_t m;
  1161. cap = (uint16_t) va_arg (va, unsigned int);
  1162. m = (uint8_t) va_arg (va, unsigned int);
  1163. gen_topo_scale_free (tc, cap, m);
  1164. }
  1165. break;
  1166. case GNUNET_TESTBED_TOPOLOGY_FROM_FILE:
  1167. {
  1168. const char *filename;
  1169. filename = va_arg (va, const char *);
  1170. GNUNET_assert (NULL != filename);
  1171. gen_topo_from_file (tc, filename);
  1172. }
  1173. break;
  1174. default:
  1175. GNUNET_break (0);
  1176. GNUNET_free (tc);
  1177. return NULL;
  1178. }
  1179. do
  1180. {
  1181. secondary_option = va_arg (va, enum GNUNET_TESTBED_TopologyOption);
  1182. switch (secondary_option)
  1183. {
  1184. case GNUNET_TESTBED_TOPOLOGY_RETRY_CNT:
  1185. overlay->retry_cnt = va_arg (va, unsigned int);
  1186. break;
  1187. case GNUNET_TESTBED_TOPOLOGY_OPTION_END:
  1188. break;
  1189. default:
  1190. GNUNET_break (0); /* Should not use any other option apart from
  1191. * the ones handled here */
  1192. GNUNET_free_non_null (overlay->link_array);
  1193. GNUNET_free (tc);
  1194. return NULL;
  1195. }
  1196. }
  1197. while (GNUNET_TESTBED_TOPOLOGY_OPTION_END != secondary_option);
  1198. op = GNUNET_TESTBED_operation_create_ (tc,
  1199. &opstart_overlay_configure_topology,
  1200. &oprelease_overlay_configure_topology);
  1201. GNUNET_TESTBED_operation_queue_insert_
  1202. (c->opq_parallel_topology_config_operations, op);
  1203. GNUNET_TESTBED_operation_begin_wait_ (op);
  1204. LOG (GNUNET_ERROR_TYPE_DEBUG, "Generated %u connections\n",
  1205. tc->link_array_size);
  1206. if (NULL != max_connections)
  1207. *max_connections = tc->link_array_size;
  1208. return op;
  1209. }
  1210. /**
  1211. * All peers must have been started before calling this function.
  1212. * This function then connects the given peers in the P2P overlay
  1213. * using the given topology.
  1214. *
  1215. * @param op_cls closure argument to give with the peer connect operation events
  1216. * generated through this function
  1217. * @param num_peers number of peers in 'peers'
  1218. * @param peers array of 'num_peers' with the peers to configure
  1219. * @param max_connections the maximums number of overlay connections that will
  1220. * be made to achieve the given topology
  1221. * @param comp_cb the completion callback to call when the topology generation
  1222. * is completed
  1223. * @param comp_cb_cls closure for the above completion callback
  1224. * @param topo desired underlay topology to use
  1225. * @param ... topology-specific options
  1226. * @return handle to the operation, NULL if connecting these
  1227. * peers is fundamentally not possible at this time (peers
  1228. * not running or underlay disallows) or if num_peers is less than 2
  1229. */
  1230. struct GNUNET_TESTBED_Operation *
  1231. GNUNET_TESTBED_overlay_configure_topology (void *op_cls,
  1232. unsigned int num_peers,
  1233. struct GNUNET_TESTBED_Peer **peers,
  1234. unsigned int *max_connections,
  1235. GNUNET_TESTBED_TopologyCompletionCallback
  1236. comp_cb,
  1237. void *comp_cb_cls,
  1238. enum GNUNET_TESTBED_TopologyOption topo,
  1239. ...)
  1240. {
  1241. struct GNUNET_TESTBED_Operation *op;
  1242. va_list vargs;
  1243. GNUNET_assert (topo < GNUNET_TESTBED_TOPOLOGY_OPTION_END);
  1244. va_start (vargs, topo);
  1245. op = GNUNET_TESTBED_overlay_configure_topology_va (op_cls, num_peers, peers,
  1246. max_connections,
  1247. comp_cb, comp_cb_cls,
  1248. topo,
  1249. vargs);
  1250. va_end (vargs);
  1251. return op;
  1252. }
  1253. /**
  1254. * Get a topology from a string input.
  1255. *
  1256. * @param topology where to write the retrieved topology
  1257. * @param topology_string The string to attempt to
  1258. * get a configuration value from
  1259. * @return GNUNET_YES if topology string matched a
  1260. * known topology, GNUNET_NO if not
  1261. */
  1262. int
  1263. GNUNET_TESTBED_topology_get_ (enum GNUNET_TESTBED_TopologyOption *topology,
  1264. const char *topology_string)
  1265. {
  1266. unsigned int cnt;
  1267. for (cnt = 0; NULL != topology_strings[cnt]; cnt++)
  1268. {
  1269. if (0 == strcasecmp (topology_string, topology_strings[cnt]))
  1270. {
  1271. if (NULL != topology)
  1272. *topology = (enum GNUNET_TESTBED_TopologyOption) cnt;
  1273. return GNUNET_YES;
  1274. }
  1275. }
  1276. return GNUNET_NO;
  1277. }
  1278. /**
  1279. * Returns the string corresponding to the given topology
  1280. *
  1281. * @param topology the topology
  1282. * @return the string (freshly allocated) of given topology; NULL if topology cannot be
  1283. * expressed as a string
  1284. */
  1285. char *
  1286. GNUNET_TESTBED_topology_to_str_ (enum GNUNET_TESTBED_TopologyOption topology)
  1287. {
  1288. if (GNUNET_TESTBED_TOPOLOGY_OPTION_END <= topology)
  1289. return NULL;
  1290. return GNUNET_strdup (topology_strings[topology]);
  1291. }
  1292. /**
  1293. * Function to construct an underlay topology
  1294. *
  1295. * @param num_peers the number of peers for which the topology should be
  1296. * generated
  1297. * @param proc the underlay link processor callback. Will be called for each
  1298. * underlay link generated unless a previous call to this callback
  1299. * returned GNUNET_SYSERR. Cannot be NULL.
  1300. * @param cls closure for proc
  1301. * @param ... variable arguments denoting the topology and its parameters. They
  1302. * should start with the type of topology to generate followed by their
  1303. * options.
  1304. * @return GNUNET_OK if underlay link generation is successful; GNUNET_SYSERR
  1305. * upon error in generating the underlay or if any calls to the
  1306. * underlay link processor returned GNUNET_SYSERR
  1307. */
  1308. int
  1309. GNUNET_TESTBED_underlay_construct_ (int num_peers,
  1310. underlay_link_processor proc,
  1311. void *cls,
  1312. ...)
  1313. {
  1314. struct TopologyContext tc;
  1315. struct TopologyContextUnderlay *underlay;
  1316. struct UnderlayLink *ulink;
  1317. va_list vargs;
  1318. enum GNUNET_TESTBED_TopologyOption topology;
  1319. unsigned int cnt;
  1320. int ret;
  1321. GNUNET_assert (NULL != proc);
  1322. ret = GNUNET_OK;
  1323. memset (&tc, 0, sizeof (tc));
  1324. tc.num_peers = num_peers;
  1325. tc.type = TOPOLOGYCONTEXT_TYPE_UNDERLAY;
  1326. underlay = &tc.u.underlay;
  1327. va_start (vargs, cls);
  1328. topology = va_arg (vargs, enum GNUNET_TESTBED_TopologyOption);
  1329. switch (topology)
  1330. {
  1331. case GNUNET_TESTBED_TOPOLOGY_LINE:
  1332. gen_topo_line (&tc);
  1333. break;
  1334. case GNUNET_TESTBED_TOPOLOGY_RING:
  1335. gen_topo_ring (&tc);
  1336. break;
  1337. case GNUNET_TESTBED_TOPOLOGY_CLIQUE:
  1338. gen_topo_clique (&tc);
  1339. break;
  1340. case GNUNET_TESTBED_TOPOLOGY_2D_TORUS:
  1341. gen_topo_2dtorus (&tc);
  1342. break;
  1343. case GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI:
  1344. gen_topo_random (&tc, va_arg (vargs, unsigned int), GNUNET_NO);
  1345. break;
  1346. case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING:
  1347. gen_topo_ring (&tc);
  1348. gen_topo_random (&tc, va_arg (vargs, unsigned int), GNUNET_YES);
  1349. break;
  1350. case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD:
  1351. gen_topo_2dtorus (&tc);
  1352. gen_topo_random (&tc, va_arg (vargs, unsigned int), GNUNET_YES);
  1353. break;
  1354. case GNUNET_TESTBED_TOPOLOGY_FROM_FILE:
  1355. {
  1356. const char *filename;
  1357. filename = va_arg (vargs, char *);
  1358. GNUNET_assert (NULL != filename);
  1359. gen_topo_from_file (&tc, filename);
  1360. }
  1361. break;
  1362. case GNUNET_TESTBED_TOPOLOGY_SCALE_FREE:
  1363. {
  1364. uint16_t cap;
  1365. uint8_t m;
  1366. cap = (uint16_t) va_arg (vargs, unsigned int);
  1367. m = (uint8_t) va_arg (vargs, unsigned int);
  1368. gen_topo_scale_free (&tc, cap, m);
  1369. }
  1370. break;
  1371. default:
  1372. GNUNET_assert (0);
  1373. }
  1374. va_end (vargs);
  1375. for (cnt = 0; cnt < tc.link_array_size; cnt++)
  1376. {
  1377. ulink = &underlay->link_array[cnt];
  1378. if (GNUNET_SYSERR == proc (cls,
  1379. ulink->A,
  1380. ulink->B,
  1381. ulink->bandwidth,
  1382. ulink->latency,
  1383. ulink->loss))
  1384. {
  1385. ret = GNUNET_SYSERR;
  1386. break;
  1387. }
  1388. }
  1389. GNUNET_free_non_null (underlay->link_array);
  1390. return ret;
  1391. }
  1392. /* end of testbed_api_topology.c */