2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
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.
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.
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/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
22 * @file testbed/testbed_api_topology.c
23 * @brief topology-generation functions
24 * @author Christian Grothoff
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"
34 * Generic loggins shorthand
36 #define LOG(kind, ...) \
37 GNUNET_log_from(kind, "testbed-api-topology", __VA_ARGS__)
41 * Default number of retires
43 #define DEFAULT_RETRY_CNT 3
47 * Context information for topology operations
49 struct TopologyContext;
53 * Representation of an overlay link
57 * An operation corresponding to this link
59 struct GNUNET_TESTBED_Operation *op;
62 * The topology context this link is a part of
64 struct TopologyContext *tc;
67 * position of peer A's handle in peers array
72 * position of peer B's handle in peers array
79 * Representation of an underlay link
83 * position of peer A's handle in peers array
88 * position of peer B's handle in peers array
93 * Bandwidth of the link in bytes per second
98 * Latency of the link in milliseconds
103 * Loss in the link in percentage of message dropped
109 struct RetryListEntry {
111 * the next pointer for the DLL
113 struct RetryListEntry *next;
116 * the prev pointer for the DLL
118 struct RetryListEntry *prev;
121 * The link to be retired
123 struct OverlayLink *link;
128 * Context information for overlay topologies
130 struct TopologyContextOverlay {
134 struct GNUNET_TESTBED_Peer **peers;
137 * An array of links; this array is of size link_array_size
139 struct OverlayLink *link_array;
142 * The operation closure
147 * topology generation completion callback
149 GNUNET_TESTBED_TopologyCompletionCallback comp_cb;
152 * The closure for the above callback
157 * DLL head for retry list
159 struct RetryListEntry *rl_head;
162 * DLL tail for retry list
164 struct RetryListEntry *rl_tail;
167 * How many retries to do before we give up
169 unsigned int retry_cnt;
172 * Number of links to try
177 * How many links have been completed
179 unsigned int ncompleted;
182 * Total successfully established overlay connections
184 unsigned int nsuccess;
187 * Total failed overlay connections
189 unsigned int nfailures;
194 * Topology context information for underlay topologies
196 struct TopologyContextUnderlay {
200 struct UnderlayLink *link_array;
205 * Context information for topology operations
207 struct TopologyContext {
209 * The type of this context
213 * Type for underlay topology
215 TOPOLOGYCONTEXT_TYPE_UNDERLAY = 0,
218 * Type for overlay topology
220 TOPOLOGYCONTEXT_TYPE_OVERLAY
225 * Topology context information for overlay topology
227 struct TopologyContextOverlay overlay;
230 * Topology context information for underlay topology
232 struct TopologyContextUnderlay underlay;
236 * The number of peers
238 unsigned int num_peers;
241 * The size of the link array
243 unsigned int link_array_size;
248 * A array of names representing topologies. Should be in sync with enum
249 * GNUNET_TESTBED_TopologyOption
251 static const char *topology_strings[] = {
253 * A clique (everyone connected to everyone else). No options. If there are N
254 * peers this topology results in (N * (N -1)) connections.
259 * Small-world network (2d torus plus random links). Followed
260 * by the number of random links to add (unsigned int).
265 * Small-world network (ring plus random links). Followed
266 * by the number of random links to add (unsigned int).
271 * Ring topology. No options.
276 * Star topology. No options.
281 * 2-d torus. No options.
286 * Random graph. Followed by the number of random links to be established
289 "RANDOM", // GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI
292 * Certain percentage of peers are unable to communicate directly
293 * replicating NAT conditions. Followed by the fraction of
294 * NAT'ed peers (float).
299 * Scale free topology. Followed by the maximum number of links a node can
300 * have (unsigned int); and the number of links a new node should have when
301 * it is added to the network (unsigned int)
306 * Straight line topology. No options.
311 * Read a topology from a given file. Followed by the name of the file (const char *).
316 * All peers are disconnected. No options.
328 * Callback to be called when an overlay_link operation complete
330 * @param cls element of the link_op array which points to the corresponding operation
331 * @param op the operation that has been finished
332 * @param emsg error message in case the operation has failed; will be NULL if
333 * operation has executed successfully.
336 overlay_link_completed(void *cls,
337 struct GNUNET_TESTBED_Operation *op,
340 struct OverlayLink *link = cls;
341 struct TopologyContext *tc;
342 struct TopologyContextOverlay *overlay;
343 struct RetryListEntry *retry_entry;
345 GNUNET_assert(op == link->op);
346 GNUNET_TESTBED_operation_done(op);
349 GNUNET_assert(TOPOLOGYCONTEXT_TYPE_OVERLAY == tc->type);
350 overlay = &tc->u.overlay;
353 overlay->nfailures++;
354 if (0 != overlay->retry_cnt)
356 LOG(GNUNET_ERROR_TYPE_WARNING,
357 "Error while establishing a link: %s -- Retrying\n",
359 retry_entry = GNUNET_new(struct RetryListEntry);
360 retry_entry->link = link;
361 GNUNET_CONTAINER_DLL_insert_tail(overlay->rl_head,
368 overlay->ncompleted++;
369 if (overlay->ncompleted < overlay->nlinks)
371 if ((0 != overlay->retry_cnt) && (NULL != overlay->rl_head))
373 overlay->retry_cnt--;
374 overlay->ncompleted = 0;
376 while (NULL != (retry_entry = overlay->rl_head))
378 link = retry_entry->link;
380 GNUNET_TESTBED_overlay_connect(overlay->op_cls,
381 &overlay_link_completed,
383 overlay->peers[link->A],
384 overlay->peers[link->B]);
386 GNUNET_CONTAINER_DLL_remove(overlay->rl_head,
389 GNUNET_free(retry_entry);
393 if (NULL != overlay->comp_cb)
395 overlay->comp_cb(overlay->comp_cb_cls,
404 * Function called when a overlay connect operation is ready
406 * @param cls the Topology context
409 opstart_overlay_configure_topology(void *cls)
411 struct TopologyContext *tc = cls;
412 struct TopologyContextOverlay *overlay;
415 GNUNET_assert(TOPOLOGYCONTEXT_TYPE_OVERLAY == tc->type);
416 overlay = &tc->u.overlay;
417 overlay->nlinks = tc->link_array_size;
418 for (p = 0; p < tc->link_array_size; p++)
420 overlay->link_array[p].op =
421 GNUNET_TESTBED_overlay_connect(overlay->op_cls,
422 &overlay_link_completed,
423 &overlay->link_array[p],
424 overlay->peers[overlay->link_array[p].A],
425 overlay->peers[overlay->link_array[p].B]);
431 * Callback which will be called when overlay connect operation is released
433 * @param cls the Topology context
436 oprelease_overlay_configure_topology(void *cls)
438 struct TopologyContext *tc = cls;
439 struct TopologyContextOverlay *overlay;
440 struct RetryListEntry *retry_entry;
443 GNUNET_assert(TOPOLOGYCONTEXT_TYPE_OVERLAY == tc->type);
444 overlay = &tc->u.overlay;
445 while (NULL != (retry_entry = overlay->rl_head))
447 GNUNET_CONTAINER_DLL_remove(overlay->rl_head, overlay->rl_tail, retry_entry);
448 GNUNET_free(retry_entry);
450 if (NULL != overlay->link_array)
452 for (p = 0; p < tc->link_array_size; p++)
453 if (NULL != overlay->link_array[p].op)
454 GNUNET_TESTBED_operation_done(overlay->link_array[p].op);
455 GNUNET_free(overlay->link_array);
462 * Populates the OverlayLink structure.
464 * @param offset the offset of the link array to use
465 * @param A the peer A. Should be different from B
466 * @param B the peer B. Should be different from A
467 * @param tc the TopologyContext
471 make_link(unsigned int offset,
474 struct TopologyContext *tc)
476 GNUNET_assert(A != B);
479 case TOPOLOGYCONTEXT_TYPE_OVERLAY:
481 struct TopologyContextOverlay *overlay;
482 struct OverlayLink *olink;
484 overlay = &tc->u.overlay;
485 GNUNET_assert(offset < tc->link_array_size);
486 olink = &overlay->link_array[offset];
487 LOG(GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %u to %u\n", B, A);
495 case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
497 struct TopologyContextUnderlay *underlay;
498 struct UnderlayLink *ulink;
500 underlay = &tc->u.underlay;
501 GNUNET_assert(offset < tc->link_array_size);
502 ulink = &underlay->link_array[offset];
512 * Generates line topology
514 * @param tc the topology context
517 gen_topo_line(struct TopologyContext *tc)
521 tc->link_array_size = tc->num_peers - 1;
524 case TOPOLOGYCONTEXT_TYPE_OVERLAY:
526 struct TopologyContextOverlay *overlay;
528 overlay = &tc->u.overlay;
529 overlay->link_array =
530 GNUNET_new_array(tc->link_array_size,
535 case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
537 struct TopologyContextUnderlay *underlay;
539 underlay = &tc->u.underlay;
540 underlay->link_array =
541 GNUNET_new_array(tc->link_array_size,
542 struct UnderlayLink);
546 for (cnt = 0; cnt < (tc->link_array_size); cnt++)
547 make_link(cnt, cnt, cnt + 1, tc);
552 * Generates star topology
554 * @param tc the topology context
557 gen_topo_star(struct TopologyContext *tc)
561 tc->link_array_size = tc->num_peers - 1;
564 case TOPOLOGYCONTEXT_TYPE_OVERLAY:
566 struct TopologyContextOverlay *overlay;
568 overlay = &tc->u.overlay;
569 overlay->link_array =
570 GNUNET_new_array(tc->link_array_size,
575 case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
577 struct TopologyContextUnderlay *underlay;
579 underlay = &tc->u.underlay;
580 underlay->link_array =
581 GNUNET_new_array(tc->link_array_size,
582 struct UnderlayLink);
586 for (cnt = tc->link_array_size; cnt; cnt--)
595 * Generates ring topology
597 * @param tc the topology context
600 gen_topo_ring(struct TopologyContext *tc)
603 tc->link_array_size++;
606 case TOPOLOGYCONTEXT_TYPE_OVERLAY:
608 struct TopologyContextOverlay *overlay;
610 overlay = &tc->u.overlay;
611 overlay->link_array =
612 GNUNET_realloc(overlay->link_array, sizeof(struct OverlayLink) *
613 tc->link_array_size);
617 case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
619 struct TopologyContextUnderlay *underlay;
621 underlay = &tc->u.underlay;
622 underlay->link_array =
623 GNUNET_realloc(underlay->link_array, sizeof(struct UnderlayLink) *
624 tc->link_array_size);
628 make_link(tc->link_array_size - 1, tc->num_peers - 1, 0, tc);
633 * Returns the number of links that are required to generate a 2d torus for the
634 * given number of peers. Also returns the arrangment (number of rows and the
635 * length of each row)
637 * @param num_peers number of peers
638 * @param rows number of rows in the 2d torus. Can be NULL
639 * @param rows_len the length of each row. This array will be allocated
640 * fresh. The caller should free it. Can be NULL
641 * @return the number of links that are required to generate a 2d torus for the
642 * given number of peers
645 GNUNET_TESTBED_2dtorus_calc_links(unsigned int num_peers, unsigned int *rows,
646 unsigned int **rows_len)
649 unsigned int sq_floor;
651 unsigned int *_rows_len;
654 unsigned int _num_peers;
657 sq = sqrt(num_peers);
659 sq_floor = (unsigned int)sq;
660 _rows = (sq_floor + 1);
661 _rows_len = GNUNET_malloc(sizeof(unsigned int) * _rows);
662 for (y = 0; y < _rows - 1; y++)
663 _rows_len[y] = sq_floor;
664 _num_peers = sq_floor * sq_floor;
665 cnt = (_num_peers < 2) ? _num_peers : 2 * _num_peers;
668 while (_num_peers < num_peers)
671 _rows_len[_rows - 1] = ++x;
676 cnt += (x < 2) ? x : 2 * x;
677 cnt += (y < 2) ? y : 2 * y;
678 if (0 == _rows_len[_rows - 1])
682 if (NULL != rows_len)
683 *rows_len = _rows_len;
685 GNUNET_free(_rows_len);
691 * Generates ring topology
693 * @param tc the topology context
696 gen_topo_2dtorus(struct TopologyContext *tc)
699 unsigned int *rows_len;
705 tc->link_array_size =
706 GNUNET_TESTBED_2dtorus_calc_links(tc->num_peers, &rows, &rows_len);
709 case TOPOLOGYCONTEXT_TYPE_OVERLAY:
711 struct TopologyContextOverlay *overlay;
713 overlay = &tc->u.overlay;
714 overlay->link_array =
715 GNUNET_malloc(sizeof(struct OverlayLink) * tc->link_array_size);
719 case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
721 struct TopologyContextUnderlay *underlay;
723 underlay = &tc->u.underlay;
724 underlay->link_array =
725 GNUNET_malloc(sizeof(struct UnderlayLink) * tc->link_array_size);
731 for (y = 0; y < rows; y++)
733 for (x = 0; x < rows_len[y] - 1; x++)
735 make_link(cnt, offset + x, offset + x + 1, tc);
740 make_link(cnt, offset + x, offset, tc);
742 offset += rows_len[y];
744 for (x = 0; x < rows_len[0]; x++)
747 for (y = 0; y < rows - 1; y++)
749 if (x >= rows_len[y + 1])
751 GNUNET_assert(x < rows_len[y + 1]);
752 make_link(cnt, offset + x, offset + rows_len[y] + x, tc);
753 offset += rows_len[y];
758 make_link(cnt, offset + x, x, tc);
761 GNUNET_assert(cnt == tc->link_array_size);
762 GNUNET_free(rows_len);
767 * Generates ring topology
769 * @param tc the topology context
770 * @param links the number of random links to establish
771 * @param append #GNUNET_YES to add links to existing link array; #GNUNET_NO to
772 * create a new link array
775 gen_topo_random(struct TopologyContext *tc,
784 if (1 == tc->num_peers)
786 if (GNUNET_YES == append)
788 index = tc->link_array_size;
789 tc->link_array_size += links;
794 tc->link_array_size = links;
798 case TOPOLOGYCONTEXT_TYPE_OVERLAY:
800 struct TopologyContextOverlay *overlay;
802 overlay = &tc->u.overlay;
803 if (GNUNET_YES != append)
805 GNUNET_assert(NULL == overlay->link_array);
806 overlay->link_array =
807 GNUNET_malloc(sizeof(struct OverlayLink) * tc->link_array_size);
810 GNUNET_assert((0 < tc->link_array_size) && (NULL != overlay->link_array));
811 overlay->link_array =
812 GNUNET_realloc(overlay->link_array,
813 sizeof(struct OverlayLink) * tc->link_array_size);
817 case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
819 struct TopologyContextUnderlay *underlay;
821 underlay = &tc->u.underlay;
822 if (GNUNET_YES != append)
824 GNUNET_assert(NULL == underlay->link_array);
825 underlay->link_array =
826 GNUNET_malloc(sizeof(struct UnderlayLink) * tc->link_array_size);
829 GNUNET_assert((0 < tc->link_array_size) && (NULL != underlay->link_array));
830 underlay->link_array =
831 GNUNET_realloc(underlay->link_array,
832 sizeof(struct UnderlayLink) * tc->link_array_size);
836 for (cnt = 0; cnt < links; cnt++)
841 GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, tc->num_peers);
843 GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, tc->num_peers);
845 while (A_rand == B_rand);
846 make_link(index + cnt, A_rand, B_rand, tc);
852 * Generates scale free network. Its construction is described in:
854 * "Emergence of Scaling in Random Networks." Science 286, 509-512, 1999.
856 * @param tc the topology context
857 * @param cap maximum allowed node degree
858 * @param m number of edges to establish for a new node when it is added to the
862 gen_topo_scale_free(struct TopologyContext *tc,
869 unsigned int etaboff;
873 unsigned int random_peer;
876 unsigned int redo_threshold;
879 tc->link_array_size = tc->num_peers * m;
882 case TOPOLOGYCONTEXT_TYPE_OVERLAY:
884 struct TopologyContextOverlay *overlay;
886 overlay = &tc->u.overlay;
887 overlay->link_array = GNUNET_malloc_large(sizeof(struct OverlayLink) *
888 tc->link_array_size);
892 case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
894 struct TopologyContextUnderlay *underlay;
896 underlay = &tc->u.underlay;
897 underlay->link_array = GNUNET_malloc_large(sizeof(struct UnderlayLink) *
898 tc->link_array_size);
902 etab = GNUNET_malloc_large(sizeof(unsigned int) * 2 * tc->link_array_size);
903 deg = GNUNET_malloc(sizeof(unsigned int) * tc->num_peers);
904 used = GNUNET_malloc(sizeof(unsigned int) * m);
905 /* start by connecting peer 1 to peer 0 */
906 make_link(0, 0, 1, tc);
912 for (peer = 2; peer < tc->num_peers; peer++)
916 for (cnt = 0; cnt < GNUNET_MIN(peer, m); cnt++)
920 off = GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_WEAK, etaboff);
921 random_peer = etab[off];
922 if (cap < deg[random_peer])
924 if (++redo_threshold > GNUNET_MAX(1, cap / 2))
928 for (cnt2 = 0; cnt2 < etaboff; cnt2++)
930 if (random_peer == etab[cnt2])
935 etab[cnt2 - off] = etab[cnt2];
941 for (cnt2 = 0; cnt2 < cnt; cnt2++)
942 if (random_peer == used[cnt2])
944 make_link(links + cnt, random_peer, peer, tc);
947 used[cnt] = random_peer;
949 for (cnt = 0; cnt < GNUNET_MIN(peer, m); cnt++)
951 etab[etaboff++] = used[cnt];
952 etab[etaboff++] = peer;
954 links += GNUNET_MIN(peer, m);
959 GNUNET_assert(links <= tc->link_array_size);
960 tc->link_array_size = links;
963 case TOPOLOGYCONTEXT_TYPE_OVERLAY:
965 struct TopologyContextOverlay *overlay;
967 overlay = &tc->u.overlay;
968 overlay->link_array =
969 GNUNET_realloc(overlay->link_array, sizeof(struct OverlayLink) * tc->link_array_size);
973 case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
975 struct TopologyContextUnderlay *underlay;
977 underlay = &tc->u.underlay;
978 underlay->link_array =
979 GNUNET_realloc(underlay->link_array, sizeof(struct UnderlayLink) * tc->link_array_size);
987 * Generates topology from the given file
989 * @param tc the topology context
990 * @param filename the filename of the file containing topology data
993 gen_topo_from_file(struct TopologyContext *tc,
994 const char *filename)
1001 unsigned long int peer_id;
1002 unsigned long int other_peer_id;
1005 * We read the peer index
1010 * We read the other peer indices
1016 status = GNUNET_SYSERR;
1017 if (GNUNET_YES != GNUNET_DISK_file_test(filename))
1019 LOG(GNUNET_ERROR_TYPE_ERROR,
1020 _("Topology file %s not found\n"),
1025 GNUNET_DISK_file_size(filename, &fs, GNUNET_YES, GNUNET_YES))
1027 LOG(GNUNET_ERROR_TYPE_ERROR,
1028 _("Topology file %s has no data\n"),
1032 data = GNUNET_malloc(fs);
1033 if (fs != GNUNET_DISK_fn_read(filename, data, fs))
1035 LOG(GNUNET_ERROR_TYPE_ERROR,
1036 _("Topology file %s cannot be read\n"),
1046 if (0 != isspace((unsigned char)data[offset]))
1054 buf = strchr(&data[offset], ':');
1057 LOG(GNUNET_ERROR_TYPE_ERROR,
1058 _("Failed to read peer index from toology file: %s"), filename);
1063 peer_id = (unsigned int)strtoul(&data[offset], &end, 10);
1066 LOG(GNUNET_ERROR_TYPE_ERROR,
1067 _("Value in given topology file: %s out of range\n"), filename);
1070 if (&data[offset] == end)
1072 LOG(GNUNET_ERROR_TYPE_ERROR,
1073 _("Failed to read peer index from topology file: %s"), filename);
1076 if (tc->num_peers <= peer_id)
1078 LOG(GNUNET_ERROR_TYPE_ERROR,
1079 _("Topology file needs more peers than given ones\n"), filename);
1082 state = OTHER_PEER_INDEX;
1083 offset += ((unsigned int)(buf - &data[offset])) + 1;
1086 case OTHER_PEER_INDEX:
1088 other_peer_id = (unsigned int)strtoul(&data[offset], &end, 10);
1091 LOG(GNUNET_ERROR_TYPE_ERROR,
1092 _("Value in given topology file: %s out of range\n"), filename);
1095 if (&data[offset] == end)
1097 LOG(GNUNET_ERROR_TYPE_ERROR,
1098 _("Failed to read peer index from topology file: %s"), filename);
1101 if (tc->num_peers <= other_peer_id)
1103 LOG(GNUNET_ERROR_TYPE_ERROR,
1104 _("Topology file needs more peers than given ones\n"), filename);
1107 if (peer_id != other_peer_id)
1109 tc->link_array_size++;
1112 case TOPOLOGYCONTEXT_TYPE_OVERLAY:
1114 struct TopologyContextOverlay *overlay;
1116 overlay = &tc->u.overlay;
1117 overlay->link_array =
1118 GNUNET_realloc(overlay->link_array,
1119 sizeof(struct OverlayLink) * tc->link_array_size);
1123 case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
1125 struct TopologyContextUnderlay *underlay;
1127 underlay = &tc->u.underlay;
1128 underlay->link_array =
1129 GNUNET_realloc(underlay->link_array,
1130 sizeof(struct UnderlayLink) * tc->link_array_size);
1134 offset += end - &data[offset];
1135 make_link(tc->link_array_size - 1, peer_id, other_peer_id, tc);
1138 LOG(GNUNET_ERROR_TYPE_WARNING,
1139 _("Ignoring to connect peer %u to peer %u\n"),
1142 while (('\n' != data[offset]) && ('|' != data[offset]) && (offset < fs))
1144 if ((offset < fs) &&
1145 ('\n' == data[offset]))
1147 else if ((offset < fs) &&
1148 ('|' == data[offset]))
1150 state = OTHER_PEER_INDEX;
1160 if (GNUNET_OK != status)
1162 LOG(GNUNET_ERROR_TYPE_WARNING,
1163 "Removing link data read from the file\n");
1164 tc->link_array_size = 0;
1167 case TOPOLOGYCONTEXT_TYPE_OVERLAY:
1169 struct TopologyContextOverlay *overlay;
1171 overlay = &tc->u.overlay;
1172 GNUNET_free_non_null(overlay->link_array);
1173 overlay->link_array = NULL;
1177 case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
1179 struct TopologyContextUnderlay *underlay;
1181 underlay = &tc->u.underlay;
1182 GNUNET_free_non_null(underlay->link_array);
1183 underlay->link_array = NULL;
1192 * Generates clique topology
1194 * @param tc the topology context
1197 gen_topo_clique(struct TopologyContext *tc)
1200 unsigned int offset;
1201 unsigned int neighbour;
1203 tc->link_array_size = tc->num_peers * (tc->num_peers - 1);
1206 case TOPOLOGYCONTEXT_TYPE_OVERLAY:
1208 struct TopologyContextOverlay *overlay;
1210 overlay = &tc->u.overlay;
1211 overlay->link_array = GNUNET_new_array(tc->link_array_size,
1212 struct OverlayLink);
1216 case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
1218 struct TopologyContextUnderlay *underlay;
1220 underlay = &tc->u.underlay;
1221 underlay->link_array = GNUNET_new_array(tc->link_array_size,
1222 struct UnderlayLink);
1226 for (cnt = 0; cnt < tc->num_peers; cnt++)
1228 for (neighbour = 0; neighbour < tc->num_peers; neighbour++)
1230 if (neighbour == cnt)
1232 make_link(offset, cnt, neighbour, tc);
1240 * Configure overall network topology to have a particular shape.
1242 * @param op_cls closure argument to give with the operation event
1243 * @param num_peers number of peers in @a peers
1244 * @param peers array of @a num_peers with the peers to configure
1245 * @param topo desired underlay topology to use
1246 * @param ap topology-specific options
1247 * @return handle to the operation, NULL if configuring the topology
1248 * is not allowed at this time
1250 struct GNUNET_TESTBED_Operation *
1251 GNUNET_TESTBED_underlay_configure_topology_va(void *op_cls,
1252 unsigned int num_peers,
1253 struct GNUNET_TESTBED_Peer
1256 GNUNET_TESTBED_TopologyOption
1265 * Configure overall network topology to have a particular shape.
1267 * @param op_cls closure argument to give with the operation event
1268 * @param num_peers number of peers in @a peers
1269 * @param peers array of @a num_peers with the peers to configure
1270 * @param topo desired underlay topology to use
1271 * @param ... topology-specific options
1272 * @return handle to the operation, NULL if configuring the topology
1273 * is not allowed at this time
1275 struct GNUNET_TESTBED_Operation *
1276 GNUNET_TESTBED_underlay_configure_topology(void *op_cls,
1277 unsigned int num_peers,
1278 struct GNUNET_TESTBED_Peer **peers,
1279 enum GNUNET_TESTBED_TopologyOption
1288 * All peers must have been started before calling this function.
1289 * This function then connects the given peers in the P2P overlay
1290 * using the given topology.
1292 * @param op_cls closure argument to give with the peer connect operation events
1293 * generated through this function
1294 * @param num_peers number of peers in @a peers
1295 * @param peers array of @a num_peers with the peers to configure
1296 * @param max_connections the maximums number of overlay connections that will
1297 * be made to achieve the given topology
1298 * @param comp_cb the completion callback to call when the topology generation
1300 * @param comp_cb_cls closure for the above completion callback
1301 * @param topo desired underlay topology to use
1302 * @param va topology-specific options
1303 * @return handle to the operation, NULL if connecting these
1304 * peers is fundamentally not possible at this time (peers
1305 * not running or underlay disallows) or if num_peers is less than 2
1307 struct GNUNET_TESTBED_Operation *
1308 GNUNET_TESTBED_overlay_configure_topology_va(void *op_cls,
1309 unsigned int num_peers,
1310 struct GNUNET_TESTBED_Peer **peers,
1311 unsigned int *max_connections,
1312 GNUNET_TESTBED_TopologyCompletionCallback
1315 enum GNUNET_TESTBED_TopologyOption topo,
1318 struct TopologyContext *tc;
1319 struct TopologyContextOverlay *overlay;
1320 struct GNUNET_TESTBED_Operation *op;
1321 struct GNUNET_TESTBED_Controller *c;
1322 enum GNUNET_TESTBED_TopologyOption secondary_option;
1326 c = peers[0]->controller;
1327 tc = GNUNET_new(struct TopologyContext);
1328 tc->type = TOPOLOGYCONTEXT_TYPE_OVERLAY;
1329 overlay = &tc->u.overlay;
1330 overlay->peers = peers;
1331 tc->num_peers = num_peers;
1332 overlay->op_cls = op_cls;
1333 overlay->retry_cnt = DEFAULT_RETRY_CNT;
1334 overlay->comp_cb = comp_cb;
1335 overlay->comp_cb_cls = comp_cb_cls;
1338 case GNUNET_TESTBED_TOPOLOGY_LINE:
1342 case GNUNET_TESTBED_TOPOLOGY_STAR:
1346 case GNUNET_TESTBED_TOPOLOGY_RING:
1350 case GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI:
1351 gen_topo_random(tc, va_arg(va, unsigned int), GNUNET_NO);
1354 case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING:
1356 gen_topo_random(tc, va_arg(va, unsigned int), GNUNET_YES);
1359 case GNUNET_TESTBED_TOPOLOGY_CLIQUE:
1360 gen_topo_clique(tc);
1363 case GNUNET_TESTBED_TOPOLOGY_2D_TORUS:
1364 gen_topo_2dtorus(tc);
1367 case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD:
1368 gen_topo_2dtorus(tc);
1369 gen_topo_random(tc, va_arg(va, unsigned int), GNUNET_YES);
1373 case GNUNET_TESTBED_TOPOLOGY_SCALE_FREE:
1378 cap = (uint16_t)va_arg(va, unsigned int);
1379 m = (uint8_t)va_arg(va, unsigned int);
1380 gen_topo_scale_free(tc, cap, m);
1384 case GNUNET_TESTBED_TOPOLOGY_FROM_FILE:
1386 const char *filename;
1388 filename = va_arg(va, const char *);
1390 GNUNET_assert(NULL != filename);
1391 gen_topo_from_file(tc, filename);
1402 secondary_option = GNUNET_VA_ARG_ENUM(va, GNUNET_TESTBED_TopologyOption);
1404 switch (secondary_option)
1406 case GNUNET_TESTBED_TOPOLOGY_RETRY_CNT:
1407 overlay->retry_cnt = va_arg(va, unsigned int);
1410 case GNUNET_TESTBED_TOPOLOGY_OPTION_END:
1414 GNUNET_break(0); /* Should not use any other option apart from
1415 * the ones handled here */
1416 GNUNET_free_non_null(overlay->link_array);
1421 while (GNUNET_TESTBED_TOPOLOGY_OPTION_END != secondary_option);
1422 op = GNUNET_TESTBED_operation_create_(tc,
1423 &opstart_overlay_configure_topology,
1424 &oprelease_overlay_configure_topology);
1425 GNUNET_TESTBED_operation_queue_insert_
1426 (c->opq_parallel_topology_config_operations, op);
1427 GNUNET_TESTBED_operation_begin_wait_(op);
1428 LOG(GNUNET_ERROR_TYPE_DEBUG,
1429 "Generated %u connections\n",
1430 tc->link_array_size);
1431 if (NULL != max_connections)
1432 *max_connections = tc->link_array_size;
1438 * All peers must have been started before calling this function.
1439 * This function then connects the given peers in the P2P overlay
1440 * using the given topology.
1442 * @param op_cls closure argument to give with the peer connect operation events
1443 * generated through this function
1444 * @param num_peers number of peers in 'peers'
1445 * @param peers array of 'num_peers' with the peers to configure
1446 * @param max_connections the maximums number of overlay connections that will
1447 * be made to achieve the given topology
1448 * @param comp_cb the completion callback to call when the topology generation
1450 * @param comp_cb_cls closure for the above completion callback
1451 * @param topo desired underlay topology to use
1452 * @param ... topology-specific options
1453 * @return handle to the operation, NULL if connecting these
1454 * peers is fundamentally not possible at this time (peers
1455 * not running or underlay disallows) or if num_peers is less than 2
1457 struct GNUNET_TESTBED_Operation *
1458 GNUNET_TESTBED_overlay_configure_topology(void *op_cls,
1459 unsigned int num_peers,
1460 struct GNUNET_TESTBED_Peer **peers,
1461 unsigned int *max_connections,
1462 GNUNET_TESTBED_TopologyCompletionCallback
1465 enum GNUNET_TESTBED_TopologyOption topo,
1468 struct GNUNET_TESTBED_Operation *op;
1471 GNUNET_assert(topo < GNUNET_TESTBED_TOPOLOGY_OPTION_END);
1472 va_start(vargs, topo);
1473 op = GNUNET_TESTBED_overlay_configure_topology_va(op_cls, num_peers, peers,
1475 comp_cb, comp_cb_cls,
1484 * Get a topology from a string input.
1486 * @param topology where to write the retrieved topology
1487 * @param topology_string The string to attempt to
1488 * get a configuration value from
1489 * @return #GNUNET_YES if topology string matched a
1490 * known topology, #GNUNET_NO if not
1493 GNUNET_TESTBED_topology_get_(enum GNUNET_TESTBED_TopologyOption *topology,
1494 const char *topology_string)
1498 for (cnt = 0; NULL != topology_strings[cnt]; cnt++)
1500 if (0 == strcasecmp(topology_string, topology_strings[cnt]))
1502 if (NULL != topology)
1503 *topology = (enum GNUNET_TESTBED_TopologyOption)cnt;
1504 GNUNET_assert(GNUNET_TESTBED_TOPOLOGY_OPTION_END != (enum GNUNET_TESTBED_TopologyOption)cnt);
1513 * Returns the string corresponding to the given topology
1515 * @param topology the topology
1516 * @return the string (freshly allocated) of given topology; NULL if topology cannot be
1517 * expressed as a string
1520 GNUNET_TESTBED_topology_to_str_(enum GNUNET_TESTBED_TopologyOption topology)
1522 if (GNUNET_TESTBED_TOPOLOGY_OPTION_END <= topology)
1524 return GNUNET_strdup(topology_strings[topology]);
1529 * Function to construct an underlay topology
1531 * @param num_peers the number of peers for which the topology should be
1533 * @param proc the underlay link processor callback. Will be called for each
1534 * underlay link generated unless a previous call to this callback
1535 * returned #GNUNET_SYSERR. Cannot be NULL.
1536 * @param cls closure for @a proc
1537 * @param ... variable arguments denoting the topology and its parameters. They
1538 * should start with the type of topology to generate followed by their
1540 * @return #GNUNET_OK if underlay link generation is successful; #GNUNET_SYSERR
1541 * upon error in generating the underlay or if any calls to the
1542 * underlay link processor returned #GNUNET_SYSERR
1545 GNUNET_TESTBED_underlay_construct_(int num_peers,
1546 underlay_link_processor proc,
1550 struct TopologyContext tc;
1551 struct TopologyContextUnderlay *underlay;
1552 struct UnderlayLink *ulink;
1554 enum GNUNET_TESTBED_TopologyOption topology;
1558 GNUNET_assert(NULL != proc);
1560 memset(&tc, 0, sizeof(tc));
1561 tc.num_peers = num_peers;
1562 tc.type = TOPOLOGYCONTEXT_TYPE_UNDERLAY;
1563 underlay = &tc.u.underlay;
1564 va_start(vargs, cls);
1565 topology = GNUNET_VA_ARG_ENUM(vargs, GNUNET_TESTBED_TopologyOption);
1568 case GNUNET_TESTBED_TOPOLOGY_LINE:
1572 case GNUNET_TESTBED_TOPOLOGY_STAR:
1576 case GNUNET_TESTBED_TOPOLOGY_RING:
1580 case GNUNET_TESTBED_TOPOLOGY_CLIQUE:
1581 gen_topo_clique(&tc);
1584 case GNUNET_TESTBED_TOPOLOGY_2D_TORUS:
1585 gen_topo_2dtorus(&tc);
1588 case GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI:
1589 gen_topo_random(&tc, va_arg(vargs, unsigned int), GNUNET_NO);
1592 case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING:
1594 gen_topo_random(&tc, va_arg(vargs, unsigned int), GNUNET_YES);
1597 case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD:
1598 gen_topo_2dtorus(&tc);
1599 gen_topo_random(&tc, va_arg(vargs, unsigned int), GNUNET_YES);
1602 case GNUNET_TESTBED_TOPOLOGY_FROM_FILE:
1604 const char *filename;
1605 filename = va_arg(vargs, char *);
1606 GNUNET_assert(NULL != filename);
1607 gen_topo_from_file(&tc, filename);
1611 case GNUNET_TESTBED_TOPOLOGY_SCALE_FREE:
1615 cap = (uint16_t)va_arg(vargs, unsigned int);
1616 m = (uint8_t)va_arg(vargs, unsigned int);
1617 gen_topo_scale_free(&tc, cap, m);
1625 for (cnt = 0; cnt < tc.link_array_size; cnt++)
1627 ulink = &underlay->link_array[cnt];
1628 if (GNUNET_SYSERR == proc(cls,
1635 ret = GNUNET_SYSERR;
1639 GNUNET_free_non_null(underlay->link_array);
1643 /* end of testbed_api_topology.c */