2 This file is part of GNUnet
3 (C) 2008--2012 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 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 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
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 * Context information for topology operations
43 struct TopologyContext;
47 * Representation of an overlay link
53 * An operation corresponding to this link
55 struct GNUNET_TESTBED_Operation *op;
58 * The topology context this link is a part of
60 struct TopologyContext *tc;
63 * position of peer A's handle in peers array
68 * position of peer B's handle in peers array
76 * Context information for topology operations
78 struct TopologyContext
83 struct GNUNET_TESTBED_Peer **peers;
86 * An array of links; this array is of size link_array_size
88 struct OverlayLink *link_array;
91 * The operation closure
98 unsigned int num_peers;
101 * The size of the link array
103 unsigned int link_array_size;
106 * should the automatic retry be disabled
114 * Callback to be called when an overlay_link operation complete
116 * @param cls element of the link_op array which points to the corresponding operation
117 * @param op the operation that has been finished
118 * @param emsg error message in case the operation has failed; will be NULL if
119 * operation has executed successfully.
122 overlay_link_completed (void *cls,
123 struct GNUNET_TESTBED_Operation *op,
126 struct OverlayLink *link = cls;
127 struct TopologyContext *tc;
129 GNUNET_assert (op == link->op);
130 GNUNET_TESTBED_operation_done (op);
133 if ((NULL != emsg) && (GNUNET_NO == tc->disable_retry))
135 LOG (GNUNET_ERROR_TYPE_WARNING,
136 "Error while establishing a link: %s -- Retrying\n", emsg);
138 GNUNET_TESTBED_overlay_connect (tc->op_cls,
139 &overlay_link_completed,
150 * Function called when a overlay connect operation is ready
152 * @param cls the Topology context
155 opstart_overlay_configure_topology (void *cls)
157 struct TopologyContext *tc = cls;
160 for (p = 0; p < tc->link_array_size; p++)
162 tc->link_array[p].op =
163 GNUNET_TESTBED_overlay_connect (tc->op_cls, &overlay_link_completed,
165 tc->peers[tc->link_array[p].A],
166 tc->peers[tc->link_array[p].B]);
172 * Callback which will be called when overlay connect operation is released
174 * @param cls the Topology context
177 oprelease_overlay_configure_topology (void *cls)
179 struct TopologyContext *tc = cls;
182 if (NULL != tc->link_array)
184 for (p = 0; p < tc->link_array_size; p++)
185 if (NULL != tc->link_array[p].op)
186 GNUNET_TESTBED_operation_done (tc->link_array[p].op);
187 GNUNET_free (tc->link_array);
194 * Generates line topology
196 * @param tc the topology context
199 gen_topo_line (struct TopologyContext *tc)
203 tc->link_array_size = tc->num_peers - 1;
204 tc->link_array = GNUNET_malloc (sizeof (struct OverlayLink) *
205 tc->link_array_size);
206 for (cnt=0; cnt < (tc->num_peers - 1); cnt++)
208 tc->link_array[cnt].A = cnt;
209 tc->link_array[cnt].B = cnt + 1;
210 tc->link_array[cnt].tc = tc;
216 * Generates ring topology
218 * @param tc the topology context
221 gen_topo_ring (struct TopologyContext *tc)
224 tc->link_array_size++;
225 tc->link_array = GNUNET_realloc (tc->link_array,
226 sizeof (struct OverlayLink) *
227 tc->link_array_size);
228 tc->link_array[tc->link_array_size - 1].op = NULL;
229 tc->link_array[tc->link_array_size - 1].tc = tc;
230 tc->link_array[tc->link_array_size - 1].A = tc->num_peers - 1;
231 tc->link_array[tc->link_array_size - 1].B = 0;
236 * Returns the number of links that are required to generate a 2d torus for the
237 * given number of peers. Also returns the arrangment (number of rows and the
238 * length of each row)
240 * @param num_peers number of peers
241 * @param rows number of rows in the 2d torus. Can be NULL
242 * @param rows_len the length of each row. This array will be allocated
243 * fresh. The caller should free it. Can be NULL
246 GNUNET_TESTBED_2dtorus_calc_links (unsigned int num_peers,
248 unsigned int **rows_len)
251 unsigned int sq_floor;
253 unsigned int *_rows_len;
256 unsigned int _num_peers;
259 sq = sqrt (num_peers);
261 sq_floor = (unsigned int) sq;
262 _rows = (sq_floor + 1);
263 _rows_len = GNUNET_malloc (sizeof (unsigned int) * _rows);
264 for (y = 0; y < _rows - 1; y++)
265 _rows_len[y] = sq_floor;
266 _num_peers = sq_floor * sq_floor;
267 cnt = 2 * _num_peers;
270 while (_num_peers < num_peers)
273 _rows_len[_rows - 1] = ++x;
278 cnt += (x < 2) ? x : 2 * x;
279 cnt += (y < 2) ? y : 2 * y;
280 if (0 == _rows_len[_rows - 1])
284 if (NULL != rows_len)
285 *rows_len = _rows_len;
287 GNUNET_free (_rows_len);
293 * Generates ring topology
295 * @param tc the topology context
298 gen_topo_2dtorus (struct TopologyContext *tc)
301 unsigned int *rows_len;
307 tc->link_array_size = GNUNET_TESTBED_2dtorus_calc_links (tc->num_peers, &rows,
309 tc->link_array = GNUNET_malloc (sizeof (struct OverlayLink) *
310 tc->link_array_size);
313 for (y = 0; y < rows; y++)
315 for (x = 0; x < rows_len[y] - 1; x++)
317 tc->link_array[cnt].tc = tc;
318 tc->link_array[cnt].A = offset + x;
319 tc->link_array[cnt].B = offset + x + 1;
324 tc->link_array[cnt].tc = tc;
325 tc->link_array[cnt].A = offset + x;
326 tc->link_array[cnt].B = offset;
328 offset += rows_len[y];
330 for (x = 0; x < rows_len[0]; x++)
333 for (y = 0; y < rows - 1; y++)
335 if (x == rows_len[y+1])
337 GNUNET_assert (x < rows_len[y+1]);
338 tc->link_array[cnt].tc= tc;
339 tc->link_array[cnt].A = offset + x;
340 offset += rows_len[y];
341 tc->link_array[cnt].B = offset + x;
346 tc->link_array[cnt].tc = tc;
347 tc->link_array[cnt].A = offset + x;
348 tc->link_array[cnt].B = x;
351 GNUNET_assert (cnt == tc->link_array_size);
352 GNUNET_free (rows_len);
357 * Generates ring topology
359 * @param tc the topology context
360 * @param links the number of random links to establish
361 * @param append GNUNET_YES to add links to existing link array; GNUNET_NO to
362 * create a new link array
365 gen_topo_random (struct TopologyContext *tc, unsigned int links, int append)
372 if (GNUNET_YES == append)
374 GNUNET_assert ((0 < tc->link_array_size) && (NULL != tc->link_array));
375 index = tc->link_array_size;
376 tc->link_array_size += links;
377 tc->link_array = GNUNET_realloc (tc->link_array,
378 sizeof (struct OverlayLink) *
379 tc->link_array_size);
383 GNUNET_assert ((0 == tc->link_array_size) && (NULL == tc->link_array));
385 tc->link_array_size = links;
386 tc->link_array = GNUNET_malloc (sizeof (struct OverlayLink) *
387 tc->link_array_size);
389 for (cnt = 0; cnt < links; cnt++)
392 A_rand = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
394 B_rand = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
396 } while (A_rand == B_rand);
397 tc->link_array[index + cnt].op = NULL;
398 tc->link_array[index + cnt].A = A_rand;
399 tc->link_array[index + cnt].B = B_rand;
400 tc->link_array[index + cnt].tc = tc;
406 * Configure overall network topology to have a particular shape.
408 * @param op_cls closure argument to give with the operation event
409 * @param num_peers number of peers in 'peers'
410 * @param peers array of 'num_peers' with the peers to configure
411 * @param topo desired underlay topology to use
412 * @param ap topology-specific options
413 * @return handle to the operation, NULL if configuring the topology
414 * is not allowed at this time
416 struct GNUNET_TESTBED_Operation *
417 GNUNET_TESTBED_underlay_configure_topology_va (void *op_cls,
418 unsigned int num_peers,
419 struct GNUNET_TESTBED_Peer
422 GNUNET_TESTBED_TopologyOption
431 * Configure overall network topology to have a particular shape.
433 * @param op_cls closure argument to give with the operation event
434 * @param num_peers number of peers in 'peers'
435 * @param peers array of 'num_peers' with the peers to configure
436 * @param topo desired underlay topology to use
437 * @param ... topology-specific options
438 * @return handle to the operation, NULL if configuring the topology
439 * is not allowed at this time
441 struct GNUNET_TESTBED_Operation *
442 GNUNET_TESTBED_underlay_configure_topology (void *op_cls,
443 unsigned int num_peers,
444 struct GNUNET_TESTBED_Peer **peers,
445 enum GNUNET_TESTBED_TopologyOption
454 * All peers must have been started before calling this function.
455 * This function then connects the given peers in the P2P overlay
456 * using the given topology.
458 * @param op_cls closure argument to give with the operation event
459 * @param num_peers number of peers in 'peers'
460 * @param peers array of 'num_peers' with the peers to configure
461 * @param topo desired underlay topology to use
462 * @param va topology-specific options
463 * @return handle to the operation, NULL if connecting these
464 * peers is fundamentally not possible at this time (peers
465 * not running or underlay disallows) or if num_peers is less than 2
467 struct GNUNET_TESTBED_Operation *
468 GNUNET_TESTBED_overlay_configure_topology_va (void *op_cls,
469 unsigned int num_peers,
470 struct GNUNET_TESTBED_Peer **peers,
471 enum GNUNET_TESTBED_TopologyOption
474 struct TopologyContext *tc;
475 struct GNUNET_TESTBED_Operation *op;
476 struct GNUNET_TESTBED_Controller *c;
477 enum GNUNET_TESTBED_TopologyOption secondary_option;
482 c = peers[0]->controller;
483 tc = GNUNET_malloc (sizeof (struct TopologyContext));
485 tc->num_peers = num_peers;
489 case GNUNET_TESTBED_TOPOLOGY_LINE:
492 case GNUNET_TESTBED_TOPOLOGY_RING:
495 case GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI:
497 va_arg (va, unsigned int),
500 case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING:
503 va_arg (va, unsigned int),
506 case GNUNET_TESTBED_TOPOLOGY_CLIQUE:
507 tc->link_array_size = num_peers * (num_peers - 1);
508 tc->link_array = GNUNET_malloc (sizeof (struct OverlayLink) *
509 tc->link_array_size);
514 for (cnt=0; cnt < num_peers; cnt++)
516 unsigned int neighbour;
518 for (neighbour=0; neighbour < num_peers; neighbour++)
520 if (neighbour == cnt)
522 tc->link_array[offset].A = cnt;
523 tc->link_array[offset].B = neighbour;
524 tc->link_array[offset].tc = tc;
530 case GNUNET_TESTBED_TOPOLOGY_2D_TORUS:
531 gen_topo_2dtorus (tc);
540 secondary_option = va_arg (va, enum GNUNET_TESTBED_TopologyOption);
541 switch (secondary_option)
543 case GNUNET_TESTBED_TOPOLOGY_DISABLE_AUTO_RETRY:
544 tc->disable_retry = GNUNET_YES;
546 case GNUNET_TESTBED_TOPOLOGY_OPTION_END:
549 GNUNET_break (0); /* Should not use any other option apart from
550 the ones handled here */
551 GNUNET_free_non_null (tc->link_array);
555 } while (GNUNET_TESTBED_TOPOLOGY_OPTION_END != secondary_option);
556 op = GNUNET_TESTBED_operation_create_ (tc,
557 &opstart_overlay_configure_topology,
558 &oprelease_overlay_configure_topology);
559 GNUNET_TESTBED_operation_queue_insert_
560 (c->opq_parallel_topology_config_operations, op);
561 GNUNET_TESTBED_operation_begin_wait_ (op);
567 * All peers must have been started before calling this function.
568 * This function then connects the given peers in the P2P overlay
569 * using the given topology.
571 * @param op_cls closure argument to give with the operation event
572 * @param num_peers number of peers in 'peers'
573 * @param peers array of 'num_peers' with the peers to configure
574 * @param topo desired underlay topology to use
575 * @param ... topology-specific options
576 * @return handle to the operation, NULL if connecting these
577 * peers is fundamentally not possible at this time (peers
578 * not running or underlay disallows) or if num_peers is less than 2
580 struct GNUNET_TESTBED_Operation *
581 GNUNET_TESTBED_overlay_configure_topology (void *op_cls, unsigned int num_peers,
582 struct GNUNET_TESTBED_Peer **peers,
583 enum GNUNET_TESTBED_TopologyOption
586 struct GNUNET_TESTBED_Operation *op;
589 GNUNET_assert (topo < GNUNET_TESTBED_TOPOLOGY_OPTION_END);
590 va_start (vargs, topo);
591 op = GNUNET_TESTBED_overlay_configure_topology_va (op_cls, num_peers, peers,
597 /* end of testbed_api_topology.c */