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