Browse code

Merge 1a29dc28691b5522abe6241a8d840e500ab1e6d7 into bb42ee28fc115e1e3373962c02162c9a8e6d41fc

Julien Chavanton authored on 21/10/2020 16:21:11 • GitHub committed on 21/10/2020 16:21:11
Showing 2 changed files
... ...
@@ -2653,14 +2653,47 @@ static inline void latency_stats_update(ds_latency_stats_t *latency_stats, int l
2653 2653
 	}
2654 2654
 }
2655 2655
 
2656
+typedef struct congestion_control_state {
2657
+	int gw_congested_count;
2658
+	int gw_normal_count;
2659
+	int total_congestion_ms;
2660
+	int enabled;
2661
+	int apply_rweights;
2662
+} congestion_control_state_t;
2663
+
2664
+int ds_update_weighted_congestion_control(congestion_control_state_t *cc, int weight, ds_latency_stats_t *latency_stats)
2665
+{
2666
+	int active_weight = 0;
2667
+	int congestion_ms = latency_stats->estimate - latency_stats->average;
2668
+	if (weight <= 0) return 0;
2669
+	if (congestion_ms < 0) congestion_ms = 0;
2670
+	cc->total_congestion_ms += congestion_ms;
2671
+	active_weight = weight - congestion_ms;
2672
+	if (active_weight < 0) active_weight = 0;
2673
+	if (active_weight == 0) {
2674
+		cc->gw_congested_count++;
2675
+	} else {
2676
+		cc->gw_normal_count++;
2677
+	}
2678
+	return active_weight;
2679
+}
2680
+
2681
+void ds_init_congestion_control_state(congestion_control_state_t *cc)
2682
+{
2683
+	cc->gw_congested_count = 0;
2684
+	cc->gw_normal_count = 0;
2685
+	cc->total_congestion_ms = 0;
2686
+	cc->enabled = 1;
2687
+	cc->apply_rweights = 0;
2688
+}
2689
+
2656 2690
 int ds_update_latency(int group, str *address, int code)
2657 2691
 {
2658 2692
 	int i = 0;
2659 2693
 	int state = 0;
2660 2694
 	ds_set_t *idx = NULL;
2661
-	int apply_rweights = 0;
2662
-	int all_gw_congested = 1;
2663
-	int total_congestion_ms = 0;
2695
+	congestion_control_state_t cc;
2696
+	ds_init_congestion_control_state(&cc);
2664 2697
 
2665 2698
 	if(_ds_list == NULL || _ds_list_nr <= 0) {
2666 2699
 		LM_ERR("the list is null\n");
... ...
@@ -2680,7 +2713,6 @@ int ds_update_latency(int group, str *address, int code)
2680 2713
 				&& strncasecmp(ds_dest->uri.s, address->s, address->len) == 0) {
2681 2714
 			struct timeval now;
2682 2715
 			int latency_ms;
2683
-			int congestion_ms;
2684 2716
 			/* Destination address found, this is the gateway that was pinged. */
2685 2717
 			state = ds_dest->flags;
2686 2718
 			if (code == 408 && latency_stats->timeout < UINT32_MAX)
... ...
@@ -2690,43 +2722,28 @@ int ds_update_latency(int group, str *address, int code)
2690 2722
 		            + (now.tv_usec - latency_stats->start.tv_usec)/1000;
2691 2723
 			latency_stats_update(latency_stats, latency_ms);
2692 2724
 
2693
-			congestion_ms = latency_stats->estimate - latency_stats->average;
2694
-			if (congestion_ms < 0) congestion_ms = 0;
2695
-			total_congestion_ms += congestion_ms;
2696
-
2697 2725
 			/* Adjusting weight using congestion detection based on latency estimator. */
2698
-			if (ds_dest->attrs.congestion_control && ds_dest->attrs.weight) {
2699
-				int active_weight = ds_dest->attrs.weight - congestion_ms;
2700
-				if (active_weight <= 0) {
2701
-					active_weight = 0;
2702
-				} else {
2703
-					all_gw_congested = 0;
2704
-				}
2726
+			if (ds_dest->attrs.congestion_control && ds_dest->attrs.weight > 0) {
2727
+				int active_weight = ds_update_weighted_congestion_control(&cc, ds_dest->attrs.weight, latency_stats);
2705 2728
 				if (ds_dest->attrs.rweight != active_weight) {
2706
-					apply_rweights = 1;
2729
+					cc.apply_rweights = 1;
2707 2730
 					ds_dest->attrs.rweight = active_weight;
2708 2731
 				}
2709 2732
 				LM_DBG("[%d]latency[%d]avg[%.2f][%.*s]code[%d]rweight[%d]cms[%d]\n",
2710 2733
 					latency_stats->count, latency_ms,
2711 2734
 					latency_stats->average, address->len, address->s,
2712
-					code, ds_dest->attrs.rweight, congestion_ms);
2735
+					code, ds_dest->attrs.rweight, ds_dest->attrs.weight - active_weight);
2713 2736
 			}
2714
-		} else {
2715
-			/* Another gateway in the set, we verify if it is congested. */
2716
-			int congestion_ms;
2717
-			int active_weight;
2718
-			congestion_ms = latency_stats->estimate - latency_stats->average;
2719
-			if (congestion_ms < 0) congestion_ms = 0;
2720
-			total_congestion_ms += congestion_ms;
2721
-			active_weight = ds_dest->attrs.weight - congestion_ms;
2722
-			if (active_weight > 0) all_gw_congested = 0;
2737
+		} else if (ds_dest->attrs.congestion_control && ds_dest->attrs.weight > 0) {
2738
+			/* This is another gateway in the set, we verify if it is congested. */
2739
+			ds_update_weighted_congestion_control(&cc, ds_dest->attrs.weight, latency_stats);
2723 2740
 		}
2724
-		if (!ds_dest->attrs.congestion_control) all_gw_congested = 0;
2741
+		if (!ds_dest->attrs.congestion_control) cc.enabled = 0;
2725 2742
 		i++;
2726 2743
 	}
2727 2744
 	/* All the GWs are above their congestion threshold, load distribution will now be based on
2728 2745
 	 * the ratio of congestion_ms each GW is facing. */
2729
-	if (all_gw_congested) {
2746
+	if (cc.enabled && cc.gw_congested_count > 1 && cc.gw_normal_count == 0) {
2730 2747
 		i = 0;
2731 2748
 		while (i < idx->nr) {
2732 2749
 			int congestion_ms;
... ...
@@ -2735,21 +2752,21 @@ int ds_update_latency(int group, str *address, int code)
2735 2752
 			ds_latency_stats_t *latency_stats = &ds_dest->latency_stats;
2736 2753
 			congestion_ms = latency_stats->estimate - latency_stats->average;
2737 2754
 			/* We multiply by 2^4 to keep enough precision */
2738
-			active_weight = (total_congestion_ms << 4) / congestion_ms;
2755
+			active_weight = (cc.total_congestion_ms << 4) / congestion_ms;
2739 2756
 			if (ds_dest->attrs.rweight != active_weight) {
2740
-				apply_rweights = 1;
2757
+				cc.apply_rweights = 1;
2741 2758
 				ds_dest->attrs.rweight = active_weight;
2742 2759
 			}
2743 2760
 			LM_DBG("all gw congested[%d][%d]latency_avg[%.2f][%.*s]code[%d]rweight[%d/%d:%d]cms[%d]\n",
2744
-				        total_congestion_ms, latency_stats->count, latency_stats->average,
2745
-				        address->len, address->s, code, total_congestion_ms, congestion_ms,
2761
+				        cc.total_congestion_ms, latency_stats->count, latency_stats->average,
2762
+				        ds_dest->uri.len, ds_dest->uri.s, code, cc.total_congestion_ms, congestion_ms,
2746 2763
 				        ds_dest->attrs.rweight, congestion_ms);
2747 2764
 		i++;
2748 2765
 		}
2749 2766
 	}
2750 2767
 
2751 2768
 	lock_release(&idx->lock);
2752
-	if (apply_rweights) dp_init_relative_weights(idx);
2769
+	if (cc.enabled && cc.apply_rweights) dp_init_relative_weights(idx);
2753 2770
 	return state;
2754 2771
 }
2755 2772
 
... ...
@@ -1241,7 +1241,7 @@ modparam("dispatcher", "reload_delta", 1)
1241 1241
 				</para>
1242 1242
 				<para>
1243 1243
 				Using this algorithm, you can also enable congestion control by setting the
1244
-				attibute 'cc=1', when 'cc' is enabled the 'rweight' attribute will also be
1244
+				attibute 'cc=1', when 'cc' is enabled the 'weight' attribute will also be
1245 1245
 				used to control congestion tolerance. When facing congestion the weight of
1246 1246
 				a gateway is lowered by 1 for every ms of estimated congestion, a 'rweight'
1247 1247
 				value of 50 is recommended. See the example "configuring load balancing with