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