summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ipcpd/unicast/pol/ca-mb-ecn.c123
1 files changed, 69 insertions, 54 deletions
diff --git a/src/ipcpd/unicast/pol/ca-mb-ecn.c b/src/ipcpd/unicast/pol/ca-mb-ecn.c
index 2de8f8e7..03f7044d 100644
--- a/src/ipcpd/unicast/pol/ca-mb-ecn.c
+++ b/src/ipcpd/unicast/pol/ca-mb-ecn.c
@@ -37,26 +37,32 @@
#include <string.h>
/* congestion avoidance constants */
-#define CA_SHFT 5
-#define CA_WND (1 << CA_SHFT)
-#define CA_UPD (1 << (CA_SHFT - 3))
-#define CA_SLOT 18
-#define CA_AI 20000
+#define CA_SHFT 5 /* Average over 32 pkts */
+#define CA_WND (1 << CA_SHFT) /* 32 pkts receiver wnd */
+#define CA_UPD (1 << (CA_SHFT - 3)) /* Update snd every 8 pkt */
+#define CA_SLOT 24 /* Initial slot = 16 ms */
+#define CA_INC 1 << 16 /* ~4MiB/s^2 additive inc */
+#define CA_IWL 1 << 16 /* Initial limit ~4MiB/s */
+#define CA_MINPS 8 /* Mimimum pkts / slot */
+#define CA_MAXPS 64 /* Maximum pkts / slot */
#define ECN_Q_SHFT 5
#define ts_to_ns(ts) (ts.tv_sec * BILLION + ts.tv_nsec)
struct mb_ecn_ctx {
- uint16_t rx_ece; /* level of congestion (upstream) */
- size_t rx_ctr; /* receiver side packet counter */
-
- uint16_t tx_ece; /* level of congestion (downstream) */
- size_t tx_ctr; /* sender side packet counter */
- size_t tx_aps; /* average packet size */
- time_t tx_wnd; /* tgt time to send packets (ns) */
+ uint16_t rx_ece; /* Level of congestion (upstream) */
+ size_t rx_ctr; /* Receiver side packet counter */
+
+ uint16_t tx_ece; /* Level of congestion (downstream) */
+ size_t tx_ctr; /* Sender side packet counter */
+ size_t tx_wbc; /* Window byte count */
+ size_t tx_wpc; /* Window packet count */
+ size_t tx_wbl; /* Window byte limit */
bool tx_cav; /* Congestion avoidance */
+ size_t tx_mul; /* Slot size multiplier */
+ size_t tx_inc; /* Additive increase */
size_t tx_slot;
- struct timespec t_sent; /* last sent packet */
+ struct timespec t_sent; /* Last sent packet */
};
struct pol_ca_ops mb_ecn_ca_ops = {
@@ -71,15 +77,22 @@ struct pol_ca_ops mb_ecn_ca_ops = {
void * mb_ecn_ctx_create(void)
{
-
+ struct timespec now;
struct mb_ecn_ctx * ctx;
ctx = malloc(sizeof(*ctx));
if (ctx == NULL)
return NULL;
+ clock_gettime(PTHREAD_COND_CLOCK, &now);
+
memset(ctx, 0, sizeof(*ctx));
+ ctx->tx_mul = CA_SLOT;
+ ctx->tx_wbl = CA_IWL;
+ ctx->tx_inc = CA_INC;
+ ctx->tx_slot = ts_to_ns(now) >> ctx->tx_mul;
+
return (void *) ctx;
}
@@ -91,54 +104,59 @@ void mb_ecn_ctx_destroy(void * ctx)
ca_wnd_t mb_ecn_ctx_update_snd(void * _ctx,
size_t len)
{
- struct timespec now;
- size_t slot;
- time_t gap;
- ca_wnd_t wnd;
-
+ struct timespec now;
+ size_t slot;
+ ca_wnd_t wnd;
struct mb_ecn_ctx * ctx = _ctx;
clock_gettime(PTHREAD_COND_CLOCK, &now);
- if (ctx->tx_wnd == 0) { /* 10 ms initial window estimate */
- ctx->tx_wnd = 10 * MILLION;
- gap = ctx->tx_wnd >> CA_SHFT;
- ctx->tx_aps = len >> CA_SHFT;
- ctx->tx_slot = ts_to_ns(now) >> CA_SLOT;
- } else {
- gap = ts_diff_ns(&ctx->t_sent, &now);
- ctx->tx_aps -= ctx->tx_aps >> CA_SHFT;
- ctx->tx_aps += len;
- }
-
ctx->t_sent = now;
- slot = ts_to_ns(now) >> CA_SLOT;
+ slot = ts_to_ns(now) >> ctx->tx_mul;
ctx->tx_ctr++;
+ ctx->tx_wpc++;
- if (slot - ctx->tx_slot > 0) {
- ctx->tx_slot = slot;
+ if (ctx->tx_ctr > CA_WND)
+ ctx->tx_ece = 0;
- if (ctx->tx_ctr > CA_WND)
- ctx->tx_ece = 0;
+ if (slot > ctx->tx_slot) {
+ ctx->tx_slot = slot;
- /* Slow start */
- if (!ctx->tx_cav) {
- ctx->tx_wnd >>= 1;
- /* Multiplicative Decrease */
- } else if (ctx->tx_ece) { /* MD */
- ctx->tx_wnd += (ctx->tx_wnd * ctx->tx_ece)
+ if (!ctx->tx_cav && ctx->tx_wbc > ctx->tx_wbl) /* Slow start */
+ ctx->tx_wbl <<= 1;
+ else if (ctx->tx_ece) /* Multiplicative Decrease */
+ ctx->tx_wbl -= (ctx->tx_wbl * ctx->tx_ece)
>> (CA_SHFT + 8);
- /* Additive Increase */
- } else {
- size_t bw = ctx->tx_aps * BILLION / ctx->tx_wnd;
- bw += CA_AI;
- ctx->tx_wnd = ctx->tx_aps * BILLION / bw;
+ else /* Additive Increase */
+ ctx->tx_wbl = ctx->tx_wbl + ctx->tx_inc;
+
+ /* Window scaling */
+ if (ctx->tx_wpc < CA_MINPS) {
+ ++ctx->tx_mul;
+ ctx->tx_slot >>= 1;
+ ctx->tx_wbl <<= 1;
+ ctx->tx_inc <<= 1;
}
+
+ if (ctx->tx_wpc > CA_MAXPS) {
+ --ctx->tx_mul; /* Underflows at ~CA_MAXPS billion pps */
+ ctx->tx_slot <<= 1;
+ ctx->tx_wbl >>= 1;
+ ctx->tx_inc >>= 1;
+ }
+
+ ctx->tx_wbc = 0;
+ ctx->tx_wpc = 0;
}
- wnd.wait = (ctx->tx_wnd >> CA_SHFT) - gap;
+ ctx->tx_wbc += len;
+
+ if (ctx->tx_wbc > ctx->tx_wbl)
+ wnd.wait = ((ctx->tx_slot + 1) << ctx->tx_mul) - ts_to_ns(now);
+ else
+ wnd.wait = 0;
return wnd;
}
@@ -147,7 +165,7 @@ void mb_ecn_wnd_wait(ca_wnd_t wnd)
{
if (wnd.wait > 0) {
struct timespec s = {0, 0};
- if (wnd.wait > BILLION) /* Don't care throttling < 1pps */
+ if (wnd.wait > BILLION) /* Don't care throttling < 1s */
s.tv_sec = 1;
else
s.tv_nsec = wnd.wait;
@@ -169,18 +187,15 @@ bool mb_ecn_ctx_update_rcv(void * _ctx,
if ((ctx->rx_ece | ecn) == 0)
return false;
- if (ecn == 0) {
- /* end of congestion */
+ if (ecn == 0) { /* End of congestion */
ctx->rx_ece >>= 2;
update = ctx->rx_ece == 0;
} else {
- if (ctx->rx_ece == 0) {
- /* start of congestion */
+ if (ctx->rx_ece == 0) { /* Start of congestion */
ctx->rx_ece = ecn;
ctx->rx_ctr = 0;
update = true;
- } else {
- /* congestion update */
+ } else { /* Congestion update */
ctx->rx_ece -= ctx->rx_ece >> CA_SHFT;
ctx->rx_ece += ecn;
update = (ctx->rx_ctr++ & (CA_UPD - 1)) == true;