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