2626#include "picoquic_utils.h"
2727
2828#ifdef BBRExperiment
29- #define BBRExpGate (ctx , test , action ) { if (ctx->exp_flags.test) action; }
29+ #define BBRExpGate (ctx , test , action ) { if (! ctx->exp_flags.test) action; }
3030#define BBRExpTest (ctx , test ) ( (ctx)->exp_flags.test )
3131#else
3232#define BBRExpGate (ctx , test , action ) {}
@@ -141,6 +141,22 @@ typedef enum {
141141
142142#define BBRExcessiveEcnCE 0.2
143143
144+ /* Temporary code, do define a set of BBR flags that
145+ * turn on and off individual extensions. We want to use that
146+ * to do "before/after" measurements.
147+ */
148+ #define BBRExperiment on
149+ #ifdef BBRExperiment
150+ /* Control flags for BBR improvements */
151+ typedef struct st_bbr_exp {
152+ unsigned int do_early_exit : 1 ;
153+ unsigned int do_rapid_start : 1 ;
154+ unsigned int do_handle_suspension : 1 ;
155+ unsigned int do_control_lost : 1 ;
156+ unsigned int do_exit_probeBW_up_on_delay : 1 ;
157+ unsigned int do_enter_probeBW_after_limited : 1 ;
158+ } bbr_exp ;
159+ #endif
144160typedef struct st_picoquic_bbr_state_t {
145161 /* Algorithm state: */
146162 picoquic_bbr_alg_state_t state ;
@@ -260,13 +276,13 @@ typedef struct st_picoquic_bbr_state_t {
260276 unsigned int probe_bdp_seed ;
261277
262278 /* Experimental extensions, may or maynot be a good idea. */
279+ char const * option_string ;
263280 uint64_t wifi_shadow_rtt ; /* Shadow RTT used for wifi connections. */
264281 double quantum_ratio ; /* allow application to use a different default than 0.1% of bandwidth (or 1ms of traffic) */
265282#ifdef BBRExperiment
266283 /* Control flags for BBR improvements */
267284 bbr_exp exp_flags ;
268285#endif
269-
270286} picoquic_bbr_state_t ;
271287
272288/* BBR v3 assumes that there is state associated with the acknowledgements.
@@ -422,13 +438,132 @@ static void BBRInitFullPipe(picoquic_bbr_state_t* bbr_state)
422438 bbr_state -> full_bw_count = 0 ;
423439}
424440
441+ /* Initialization of optional variables defined in text string
442+ * Syntax:
443+ * - Single letter options that control the "BBR Experiment"
444+ * E: do_early_exit
445+ * R: do_rapid_start
446+ * H: do_handle_suspension
447+ * L: do_control_lost
448+ * D: do_exit_probeBW_up_on_delay
449+ * A: do_enter_probeBW_after_limited
450+ * - Complex options, ends with ':'
451+ * T999999999: wifi_shadow_rtt, microseconds
452+ * Q99999.999: quantum_ratio, %
453+ *
454+ * The "BBR Experiment" is an attempt to improve behavior of BBR for
455+ * realtime support on some networks, mostly Wi-Fi. The experiment was a
456+ * success, and the corresponding support is on by default, The individual
457+ * option flags can be used to turn off some parts of the experiment,
458+ * for example when doing before/after measurements.
459+ */
460+ static void BBRSetOptions (picoquic_bbr_state_t * bbr_state )
461+ {
462+ const char * x = bbr_state -> option_string ;
463+ #ifdef BBRExperiment
464+ bbr_state -> exp_flags .do_early_exit = 1 ;
465+ bbr_state -> exp_flags .do_rapid_start = 1 ;
466+ bbr_state -> exp_flags .do_handle_suspension = 1 ;
467+ bbr_state -> exp_flags .do_control_lost = 1 ;
468+ bbr_state -> exp_flags .do_exit_probeBW_up_on_delay = 1 ;
469+ bbr_state -> exp_flags .do_enter_probeBW_after_limited = 1 ;
470+ #endif
471+
472+ if (x != NULL ) {
473+ char c ;
474+ while ((c = * x ) != 0 ) {
475+ x ++ ;
476+ switch (c ) {
477+ #ifdef BBRExperiment
478+ case 'E' :
479+ bbr_state -> exp_flags .do_early_exit = 0 ;
480+ break ;
481+ case 'R' :
482+ bbr_state -> exp_flags .do_rapid_start = 0 ;
483+ break ;
484+ case 'H' :
485+ bbr_state -> exp_flags .do_handle_suspension = 0 ;
486+ break ;
487+ case 'L' :
488+ bbr_state -> exp_flags .do_control_lost = 0 ;
489+ break ;
490+ case 'D' :
491+ bbr_state -> exp_flags .do_exit_probeBW_up_on_delay = 0 ;
492+ break ;
493+ case 'A' :
494+ bbr_state -> exp_flags .do_enter_probeBW_after_limited = 0 ;
495+ break ;
496+ #endif
497+ case 'T' : {
498+ /* Reading digits into an uint64_t */
499+ uint64_t u = 0 ;
500+ while ((c = * x ) != 0 ) {
501+ if (c >= '0' && c <= '9' ) {
502+ u *= 10 ;
503+ u += c - '0' ;
504+ x ++ ;
505+ }
506+ else {
507+ break ;
508+ }
509+ }
510+ bbr_state -> wifi_shadow_rtt = u ;
511+ break ;
512+ }
513+ case 'Q' : {
514+ /* Reading digits ad one dot into a double */
515+ while ((c = * x ) != 0 ) {
516+ double d = 0 ;
517+ double div = 1.0 ;
518+ int dotted = 0 ;
519+ while ((c = * x ) != 0 ) {
520+ if (c >= '0' && c <= '9' ) {
521+ if (!dotted ) {
522+ d *= 10 ;
523+ d += c - '0' ;
524+ }
525+ else {
526+ div /= 10.0 ;
527+ d += div * (c - '0' );
528+ }
529+ x ++ ;
530+ }
531+ else if (c == '.' ) {
532+ if (dotted ) {
533+ break ;
534+ }
535+ else {
536+ dotted = 1 ;
537+ x ++ ;
538+ }
539+ }
540+ else {
541+ break ;
542+ }
543+ }
544+ bbr_state -> quantum_ratio = d ;
545+ break ;
546+ }
547+ }
548+ case ':' :
549+ /* Ignore */
550+ break ;
551+ default :
552+ break ;
553+ }
554+ }
555+ }
556+ }
557+
425558/* Initialization of the BBR state */
426- static void BBROnInit (picoquic_bbr_state_t * bbr_state , picoquic_path_t * path_x , uint64_t current_time )
559+ static void BBROnInit (picoquic_bbr_state_t * bbr_state , picoquic_path_t * path_x , uint64_t current_time , char const * option_string )
427560{
428561 /* TODO:
429562 init_windowed_max_filter(filter = BBR.MaxBwFilter, value = 0, time = 0)
430563 */
431564 memset (bbr_state , 0 , sizeof (picoquic_bbr_state_t ));
565+ bbr_state -> option_string = option_string ;
566+
432567 BBRInitRandom (bbr_state , path_x , current_time );
433568 /* If RTT was already sampled, use it, other wise set min RTT to infinity */
434569 if (path_x -> smoothed_rtt == PICOQUIC_INITIAL_RTT
@@ -446,15 +581,8 @@ static void BBROnInit(picoquic_bbr_state_t* bbr_state, picoquic_path_t* path_x,
446581 bbr_state -> min_rtt_stamp = current_time ;
447582 bbr_state -> extra_acked_interval_start = current_time ;
448583 bbr_state -> extra_acked_delivered = 0 ;
449- /* Support for the wifi_shadow_rtt hack */
450- bbr_state -> wifi_shadow_rtt = path_x -> cnx -> quic -> wifi_shadow_rtt ;
451-
452- #ifdef BBRExperiment
453- /* Support for BBR Experiment */
454- bbr_state -> exp_flags = path_x -> cnx -> quic -> bbr_exp_flags ;
455- #endif
456- /* Support for experimenting with the send_quantum ratio */
457- bbr_state -> quantum_ratio = path_x -> cnx -> quic -> bbr_quantum_ratio ;
584+ /* Support for the experimental options */
585+ BBRSetOptions (bbr_state );
458586 if (bbr_state -> quantum_ratio == 0 ) {
459587 bbr_state -> quantum_ratio = 0.001 ;
460588 }
@@ -469,17 +597,17 @@ static void BBROnInit(picoquic_bbr_state_t* bbr_state, picoquic_path_t* path_x,
469597
470598static void picoquic_bbr_reset (picoquic_bbr_state_t * bbr_state , picoquic_path_t * path_x , uint64_t current_time )
471599{
472- BBROnInit (bbr_state , path_x , current_time );
600+ BBROnInit (bbr_state , path_x , current_time , bbr_state -> option_string );
473601}
474602
475- static void picoquic_bbr_init (picoquic_cnx_t * cnx , picoquic_path_t * path_x , uint64_t current_time )
603+ static void picoquic_bbr_init (picoquic_cnx_t * cnx , picoquic_path_t * path_x , char const * option_string , uint64_t current_time )
476604{
477605 /* Initialize the state of the congestion control algorithm */
478606 picoquic_bbr_state_t * bbr_state = (picoquic_bbr_state_t * )malloc (sizeof (picoquic_bbr_state_t ));
479607
480608 path_x -> congestion_alg_state = (void * )bbr_state ;
481609 if (bbr_state != NULL ) {
482- BBROnInit (bbr_state , path_x , current_time );
610+ BBROnInit (bbr_state , path_x , current_time , option_string );
483611 }
484612}
485613
0 commit comments