|
62 | 62 | * default callback function for the server context. When a new connection
|
63 | 63 | * arrives, the server uses the "cc_compete" context to find the matching
|
64 | 64 | * client connection, discover the desired congestion algorithm, and
|
65 |
| -* program it in the server side connection context |
| 65 | +* program it in the server side connection context. |
66 | 66 | *
|
67 | 67 | * The main advantages of this simulation are:
|
68 | 68 | * - Running the actual picoquic code.
|
69 | 69 | * - Operating in "virtual time", much faster than "real time".
|
70 | 70 | *
|
| 71 | +* We can simulate a link with a capacity and a latency varies over time. The |
| 72 | +* API provides two ways to do that: |
| 73 | +* |
| 74 | +* - either pick one of the predefines variation scenarios, such as `blackhole` |
| 75 | +* - or provide an array of |
| 76 | +* |
71 | 77 | * There are limits to this setup:
|
72 | 78 | * - we set a maximum number of nodes, links, connections. This is not strictly
|
73 | 79 | * necessary. We could dynamically allocate arrays.
|
@@ -100,24 +106,14 @@ typedef struct st_picoquic_ns_client_t {
|
100 | 106 | picoquic_connection_id_t icid;
|
101 | 107 | } picoquic_ns_client_t;
|
102 | 108 |
|
103 |
| -typedef struct st_picoquic_ns_link_spec_t { |
104 |
| - uint64_t duration; |
105 |
| - double data_rate_in_gbps_up; /* datarate, server to clients, defaults to 10 mbps */ |
106 |
| - double data_rate_in_gbps_down; /* datarate, server to clients, defaults to 10 mbps */ |
107 |
| - uint64_t latency; /* one way latency, microseconds, both directions */ |
108 |
| - uint64_t jitter; /* delay jitter, microseconds, both directions */ |
109 |
| - uint64_t queue_delay_max; /* if specified, specify the max buffer queuing for the link, in microseconds */ |
110 |
| - uint64_t l4s_max; /* if specified, specify the max buffer queuing for the link, in microseconds */ |
111 |
| -} picoquic_ns_link_spec_t; |
112 |
| - |
113 |
| - |
114 | 109 | typedef struct st_picoquic_ns_ctx_t {
|
115 | 110 | picoquic_quic_t* q_ctx[PICOQUIC_NS_NB_NODES];
|
116 | 111 | struct sockaddr_in addr[PICOQUIC_NS_NB_NODES];
|
117 | 112 | picoquictest_sim_link_t* link[PICOQUIC_NS_NB_LINKS];
|
118 | 113 | uint64_t simulated_time;
|
119 | 114 | int nb_connections;
|
120 | 115 | picoquic_ns_link_spec_t* vary_link_spec;
|
| 116 | + int vary_link_is_user_provided; |
121 | 117 | size_t vary_link_nb;
|
122 | 118 | uint64_t next_vary_link_time;
|
123 | 119 | size_t vary_link_index;
|
@@ -267,58 +263,65 @@ int picoquic_ns_create_default_link_spec(picoquic_ns_ctx_t* cc_ctx, picoquic_ns_
|
267 | 263 |
|
268 | 264 | int picoquic_ns_create_link_spec(picoquic_ns_ctx_t* cc_ctx, picoquic_ns_spec_t* spec)
|
269 | 265 | {
|
270 |
| - int ret; |
| 266 | + int ret = 0; |
271 | 267 |
|
272 |
| - switch (spec->link_scenario) { |
273 |
| - case link_scenario_none: |
274 |
| - ret = picoquic_ns_create_default_link_spec(cc_ctx, spec, 1); |
275 |
| - break; |
276 |
| - case link_scenario_black_hole: |
277 |
| - if ((ret = picoquic_ns_create_default_link_spec(cc_ctx, spec, 3)) == 0) { |
278 |
| - cc_ctx->vary_link_spec[0].duration = 2000000; |
279 |
| - cc_ctx->vary_link_spec[1].duration = 2000000; |
280 |
| - cc_ctx->vary_link_spec[2].duration = UINT64_MAX; |
281 |
| - cc_ctx->vary_link_spec[1].data_rate_in_gbps_down = 0; |
282 |
| - cc_ctx->vary_link_spec[1].data_rate_in_gbps_up = 0; |
283 |
| - } |
284 |
| - break; |
285 |
| - case link_scenario_drop_and_back: |
286 |
| - if ((ret = picoquic_ns_create_default_link_spec(cc_ctx, spec, 3)) == 0) { |
287 |
| - cc_ctx->vary_link_spec[0].duration = 1500000; |
288 |
| - cc_ctx->vary_link_spec[1].duration = 2000000; |
289 |
| - cc_ctx->vary_link_spec[2].duration = UINT64_MAX; |
290 |
| - cc_ctx->vary_link_spec[1].data_rate_in_gbps_down *= 0.5; |
291 |
| - cc_ctx->vary_link_spec[1].data_rate_in_gbps_up *= 0.5; |
292 |
| - } |
293 |
| - break; |
294 |
| - case link_scenario_low_and_up: |
295 |
| - if ((ret = picoquic_ns_create_default_link_spec(cc_ctx, spec, 2)) == 0) { |
296 |
| - cc_ctx->vary_link_spec[0].duration = 2500000; |
297 |
| - cc_ctx->vary_link_spec[0].data_rate_in_gbps_down *= 0.5; |
298 |
| - cc_ctx->vary_link_spec[0].data_rate_in_gbps_up *= 0.5; |
299 |
| - cc_ctx->vary_link_spec[1].duration = UINT64_MAX; |
300 |
| - } |
301 |
| - break; |
302 |
| - case link_scenario_wifi_fade: |
303 |
| - if ((ret = picoquic_ns_create_default_link_spec(cc_ctx, spec, 3)) == 0) { |
304 |
| - cc_ctx->vary_link_spec[0].duration = 1000000; |
305 |
| - cc_ctx->vary_link_spec[1].duration = 2000000; |
306 |
| - cc_ctx->vary_link_spec[1].data_rate_in_gbps_down *= 0.1; |
307 |
| - cc_ctx->vary_link_spec[1].data_rate_in_gbps_up *= 0.1; |
308 |
| - cc_ctx->vary_link_spec[2].duration = UINT64_MAX; |
309 |
| - } |
310 |
| - break; |
311 |
| - case link_scenario_wifi_suspension: |
312 |
| - if ((ret = picoquic_ns_create_default_link_spec(cc_ctx, spec, 2)) == 0) { |
313 |
| - cc_ctx->vary_link_spec[0].duration = 1800000; |
314 |
| - cc_ctx->vary_link_spec[1].duration = 200000; |
315 |
| - cc_ctx->vary_link_spec[1].data_rate_in_gbps_down = 0; |
316 |
| - cc_ctx->vary_link_spec[1].data_rate_in_gbps_up = 0; |
| 268 | + if (spec->vary_link_nb > 0) { |
| 269 | + cc_ctx->vary_link_is_user_provided = 1; |
| 270 | + cc_ctx->vary_link_nb = spec->vary_link_nb; |
| 271 | + cc_ctx->vary_link_spec = spec->vary_link_spec; |
| 272 | + } |
| 273 | + else { |
| 274 | + switch (spec->link_scenario) { |
| 275 | + case link_scenario_none: |
| 276 | + ret = picoquic_ns_create_default_link_spec(cc_ctx, spec, 1); |
| 277 | + break; |
| 278 | + case link_scenario_black_hole: |
| 279 | + if ((ret = picoquic_ns_create_default_link_spec(cc_ctx, spec, 3)) == 0) { |
| 280 | + cc_ctx->vary_link_spec[0].duration = 2000000; |
| 281 | + cc_ctx->vary_link_spec[1].duration = 2000000; |
| 282 | + cc_ctx->vary_link_spec[2].duration = UINT64_MAX; |
| 283 | + cc_ctx->vary_link_spec[1].data_rate_in_gbps_down = 0; |
| 284 | + cc_ctx->vary_link_spec[1].data_rate_in_gbps_up = 0; |
| 285 | + } |
| 286 | + break; |
| 287 | + case link_scenario_drop_and_back: |
| 288 | + if ((ret = picoquic_ns_create_default_link_spec(cc_ctx, spec, 3)) == 0) { |
| 289 | + cc_ctx->vary_link_spec[0].duration = 1500000; |
| 290 | + cc_ctx->vary_link_spec[1].duration = 2000000; |
| 291 | + cc_ctx->vary_link_spec[2].duration = UINT64_MAX; |
| 292 | + cc_ctx->vary_link_spec[1].data_rate_in_gbps_down *= 0.5; |
| 293 | + cc_ctx->vary_link_spec[1].data_rate_in_gbps_up *= 0.5; |
| 294 | + } |
| 295 | + break; |
| 296 | + case link_scenario_low_and_up: |
| 297 | + if ((ret = picoquic_ns_create_default_link_spec(cc_ctx, spec, 2)) == 0) { |
| 298 | + cc_ctx->vary_link_spec[0].duration = 2500000; |
| 299 | + cc_ctx->vary_link_spec[0].data_rate_in_gbps_down *= 0.5; |
| 300 | + cc_ctx->vary_link_spec[0].data_rate_in_gbps_up *= 0.5; |
| 301 | + cc_ctx->vary_link_spec[1].duration = UINT64_MAX; |
| 302 | + } |
| 303 | + break; |
| 304 | + case link_scenario_wifi_fade: |
| 305 | + if ((ret = picoquic_ns_create_default_link_spec(cc_ctx, spec, 3)) == 0) { |
| 306 | + cc_ctx->vary_link_spec[0].duration = 1000000; |
| 307 | + cc_ctx->vary_link_spec[1].duration = 2000000; |
| 308 | + cc_ctx->vary_link_spec[1].data_rate_in_gbps_down *= 0.1; |
| 309 | + cc_ctx->vary_link_spec[1].data_rate_in_gbps_up *= 0.1; |
| 310 | + cc_ctx->vary_link_spec[2].duration = UINT64_MAX; |
| 311 | + } |
| 312 | + break; |
| 313 | + case link_scenario_wifi_suspension: |
| 314 | + if ((ret = picoquic_ns_create_default_link_spec(cc_ctx, spec, 2)) == 0) { |
| 315 | + cc_ctx->vary_link_spec[0].duration = 1800000; |
| 316 | + cc_ctx->vary_link_spec[1].duration = 200000; |
| 317 | + cc_ctx->vary_link_spec[1].data_rate_in_gbps_down = 0; |
| 318 | + cc_ctx->vary_link_spec[1].data_rate_in_gbps_up = 0; |
| 319 | + } |
| 320 | + break; |
| 321 | + default: |
| 322 | + ret = -1; |
| 323 | + break; |
317 | 324 | }
|
318 |
| - break; |
319 |
| - default: |
320 |
| - ret = -1; |
321 |
| - break; |
322 | 325 | }
|
323 | 326 | return ret;
|
324 | 327 | }
|
@@ -357,7 +360,8 @@ int picoquic_ns_create_links(picoquic_ns_ctx_t* cc_ctx, picoquic_ns_spec_t* spec
|
357 | 360 | }
|
358 | 361 | }
|
359 | 362 |
|
360 |
| - /* program the first transition if needed -- but this should be automatic */ |
| 363 | + /* The simulation will automatically execute the transition to |
| 364 | + * the first "vary_link_spec" value. */ |
361 | 365 |
|
362 | 366 | return ret;
|
363 | 367 | }
|
@@ -389,8 +393,11 @@ void picoquic_ns_delete_ctx(picoquic_ns_ctx_t* cc_ctx)
|
389 | 393 |
|
390 | 394 | /* delete the link specifications */
|
391 | 395 | if (cc_ctx->vary_link_spec != NULL) {
|
392 |
| - free(cc_ctx->vary_link_spec); |
| 396 | + if (!cc_ctx->vary_link_is_user_provided) { |
| 397 | + free(cc_ctx->vary_link_spec); |
| 398 | + } |
393 | 399 | cc_ctx->vary_link_spec = NULL;
|
| 400 | + cc_ctx->vary_link_nb = 0; |
394 | 401 | }
|
395 | 402 | /* and then free the context itself */
|
396 | 403 | free(cc_ctx);
|
|
0 commit comments