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