summaryrefslogtreecommitdiff
path: root/src/ipcpd/unicast/tests
diff options
context:
space:
mode:
authorDimitri Staessens <dimitri@ouroboros.rocks>2026-08-16 19:31:09 +0000
committerSander Vrijders <sander@ouroboros.rocks>2026-08-31 08:31:45 +0200
commit016c3c438e9b066bb45d4934ad039a49bde7014d (patch)
tree968c83282c3a7143f4fe5b1954309db38cfc732f /src/ipcpd/unicast/tests
parent5c239c128c04883dbed6d66f574edf8b48d11e11 (diff)
downloadouroboros-016c3c438e9b066bb45d4934ad039a49bde7014d.tar.gz
ouroboros-016c3c438e9b066bb45d4934ad039a49bde7014d.zip
ipcpd: Use capacity queue estimation for mb-ecn
The mb-ecn algorithm was using rbuff queue depths in packets to mark, but sockets in the poa component report capacity in bytes. The tx rings are now adaptive to block on queuing delay instead of when full to prevent buffer bloat, controllable via fccntl (FLOWSTXQDLY and FLOWGTXQDLY). Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
Diffstat (limited to 'src/ipcpd/unicast/tests')
-rw-r--r--src/ipcpd/unicast/tests/cap_test.c434
1 files changed, 9 insertions, 425 deletions
diff --git a/src/ipcpd/unicast/tests/cap_test.c b/src/ipcpd/unicast/tests/cap_test.c
index 7867b490..e3c3f8b3 100644
--- a/src/ipcpd/unicast/tests/cap_test.c
+++ b/src/ipcpd/unicast/tests/cap_test.c
@@ -1,7 +1,7 @@
/*
* Ouroboros - Copyright (C) 2016 - 2026
*
- * Unit tests for link capacity estimation
+ * Unit tests for link capacity codes
*
* Dimitri Staessens <dimitri@ouroboros.rocks>
* Sander Vrijders <sander@ouroboros.rocks>
@@ -24,41 +24,6 @@
#include <test/test.h>
-#define TICK (50 * 1000ULL) /* 50 us between packets */
-#define LEN 1000ULL /* default packet size (B) */
-#define QLEN 8 /* steady ring backlog */
-#define RATE (LEN * BILLION / TICK) /* LEN per TICK = 20 MB/s */
-
-#define SHP_LEN 1250ULL /* shaped-link packet (B) */
-#define SHP_STEP 20 /* packets per shaped window */
-#define SHP_RATE (SHP_LEN * BILLION / (SHP_STEP * TICK))
-
-static int test_cap_init_fini(void)
-{
- TEST_START();
-
- if (cap_init() < 0) {
- printf("Failed to init cap.\n");
- goto fail;
- }
-
- if (cap_get(0) != 0 || cap_get(PROC_MAX_FLOWS - 1) != 0) {
- printf("Fresh estimator not unknown.\n");
- goto fail_init;
- }
-
- cap_fini();
-
- TEST_SUCCESS();
-
- return TEST_RC_SUCCESS;
- fail_init:
- cap_fini();
- fail:
- TEST_FAIL();
- return TEST_RC_FAIL;
-}
-
/* Exact roundtrip holds for codes >= 32 (rates >= 256 B/s). */
static int test_cap_codec_roundtrip(void)
{
@@ -152,28 +117,36 @@ static int test_cap_stamp(void)
TEST_START();
pci = 42;
+
cap_stamp(&pci, 0);
+
if (pci != 42) {
printf("Unknown own code overwrote the byte.\n");
goto fail;
}
pci = 0;
+
cap_stamp(&pci, 97);
+
if (pci != 97) {
printf("Own code not written into unknown.\n");
goto fail;
}
pci = 97;
+
cap_stamp(&pci, 42);
+
if (pci != 42) {
printf("Lower own code did not lower the byte.\n");
goto fail;
}
pci = 42;
+
cap_stamp(&pci, 97);
+
if (pci != 42) {
printf("Higher own code raised the byte.\n");
goto fail;
@@ -187,384 +160,6 @@ static int test_cap_stamp(void)
return TEST_RC_FAIL;
}
-static int test_cap_est_busy_window(void)
-{
- size_t i;
-
- TEST_START();
-
- if (cap_init() < 0) {
- printf("Failed to init cap.\n");
- goto fail;
- }
-
- /* 1000 B every 50 us, ring steady at 8: drain = 20 MB/s. */
- for (i = 1; i <= 40; i++)
- cap_update_at(0, QLEN, LEN, i * TICK);
-
- if (cap_get(0) != cap_enc(RATE)) {
- printf("Estimated code: exp %u, got %u.\n",
- cap_enc(RATE), cap_get(0));
- goto fail_init;
- }
-
- cap_fini();
-
- TEST_SUCCESS();
-
- return TEST_RC_SUCCESS;
- fail_init:
- cap_fini();
- fail:
- TEST_FAIL();
- return TEST_RC_FAIL;
-}
-
-static int test_cap_est_idle_tolerated(void)
-{
- size_t i;
-
- TEST_START();
-
- if (cap_init() < 0) {
- printf("Failed to init cap.\n");
- goto fail;
- }
-
- for (i = 1; i <= 40; i++)
- cap_update_at(0, i == 21 ? 0 : QLEN, LEN, i * TICK);
-
- if (cap_get(0) != cap_enc(RATE)) {
- printf("Grazed window: exp %u, got %u.\n",
- cap_enc(RATE), cap_get(0));
- goto fail_init;
- }
-
- cap_fini();
-
- TEST_SUCCESS();
-
- return TEST_RC_SUCCESS;
- fail_init:
- cap_fini();
- fail:
- TEST_FAIL();
- return TEST_RC_FAIL;
-}
-
-static int test_cap_est_mostly_idle_rejects(void)
-{
- size_t i;
-
- TEST_START();
-
- if (cap_init() < 0) {
- printf("Failed to init cap.\n");
- goto fail;
- }
-
- for (i = 1; i <= 100; i++)
- cap_update_at(0, 0, LEN, i * TICK);
-
- if (cap_get(0) != 0) {
- printf("Idle ring estimated %u.\n", cap_get(0));
- goto fail_init;
- }
-
- cap_fini();
-
- TEST_SUCCESS();
-
- return TEST_RC_SUCCESS;
- fail_init:
- cap_fini();
- fail:
- TEST_FAIL();
- return TEST_RC_FAIL;
-}
-
-static int test_cap_est_slow_link_extends(void)
-{
- size_t i;
-
- TEST_START();
-
- if (cap_init() < 0) {
- printf("Failed to init cap.\n");
- goto fail;
- }
-
- /* 1000 B every 100 us: 10 slots/ms closes on a 2 ms window. */
- for (i = 1; i <= 30; i++)
- cap_update_at(0, QLEN, LEN, i * 2 * TICK);
-
- if (cap_get(0) != cap_enc(RATE / 2)) {
- printf("Slow link: exp %u, got %u.\n",
- cap_enc(RATE / 2), cap_get(0));
- goto fail_init;
- }
-
- cap_fini();
-
- TEST_SUCCESS();
-
- return TEST_RC_SUCCESS;
- fail_init:
- cap_fini();
- fail:
- TEST_FAIL();
- return TEST_RC_FAIL;
-}
-
-static int test_cap_est_shaped_link(void)
-{
- size_t i;
-
- TEST_START();
-
- if (cap_init() < 0) {
- printf("Failed to init cap.\n");
- goto fail;
- }
-
- /* 1250 B every ms; one empty observation per 20 packets. */
- for (i = 1; i <= 100; i++)
- cap_update_at(0, i % SHP_STEP == 0 ? 0 : 6, SHP_LEN,
- i * SHP_STEP * TICK);
-
- if (cap_get(0) != cap_enc(SHP_RATE)) {
- printf("Shaped link: exp %u, got %u.\n",
- cap_enc(SHP_RATE), cap_get(0));
- goto fail_init;
- }
-
- cap_fini();
-
- TEST_SUCCESS();
-
- return TEST_RC_SUCCESS;
- fail_init:
- cap_fini();
- fail:
- TEST_FAIL();
- return TEST_RC_FAIL;
-}
-
-static int test_cap_est_stale_discard(void)
-{
- uint64_t t;
- size_t i;
-
- TEST_START();
-
- if (cap_init() < 0) {
- printf("Failed to init cap.\n");
- goto fail;
- }
-
- /* Open a window, trickle 4 slots, then ~200 ms of silence. */
- for (i = 1; i <= 5; i++)
- cap_update_at(0, QLEN, LEN, i * CAP_T_MIN);
-
- t = 205 * CAP_T_MIN;
-
- cap_update_at(0, QLEN, LEN, t);
-
- if (cap_get(0) != 0) {
- printf("Gap window estimated %u.\n", cap_get(0));
- goto fail_init;
- }
-
- for (i = 1; i <= 40; i++)
- cap_update_at(0, QLEN, LEN, t + i * TICK);
-
- if (cap_get(0) != cap_enc(RATE)) {
- printf("Post-gap: exp %u, got %u.\n",
- cap_enc(RATE), cap_get(0));
- goto fail_init;
- }
-
- cap_fini();
-
- TEST_SUCCESS();
-
- return TEST_RC_SUCCESS;
- fail_init:
- cap_fini();
- fail:
- TEST_FAIL();
- return TEST_RC_FAIL;
-}
-
-static int test_cap_est_empty_start_no_raise(void)
-{
- size_t i;
-
- TEST_START();
-
- if (cap_init() < 0) {
- printf("Failed to init cap.\n");
- goto fail;
- }
-
- cap_update_at(0, 0, LEN, CAP_T_MIN);
-
- for (i = 1; i <= 40; i++)
- cap_update_at(0, QLEN, LEN, CAP_T_MIN + i * TICK);
-
- if (cap_get(0) != 0) {
- printf("Empty-start window raised to %u.\n",
- cap_get(0));
- goto fail_init;
- }
-
- for (i = 41; i <= 60; i++)
- cap_update_at(0, QLEN, LEN, CAP_T_MIN + i * TICK);
-
- if (cap_get(0) != cap_enc(RATE)) {
- printf("Backlogged window: exp %u, got %u.\n",
- cap_enc(RATE), cap_get(0));
- goto fail_init;
- }
-
- cap_fini();
-
- TEST_SUCCESS();
-
- return TEST_RC_SUCCESS;
- fail_init:
- cap_fini();
- fail:
- TEST_FAIL();
- return TEST_RC_FAIL;
-}
-
-/* Max filter: fast attack on a high sample, slow release on lower. */
-static int test_cap_est_max_filter(void)
-{
- uint8_t high;
- size_t i;
-
- TEST_START();
-
- if (cap_init() < 0) {
- printf("Failed to init cap.\n");
- goto fail;
- }
-
- for (i = 1; i <= 40; i++)
- cap_update_at(0, QLEN, LEN, i * TICK);
-
- high = cap_get(0);
- if (high != cap_enc(RATE)) {
- printf("Attack missed: exp %u, got %u.\n", cap_enc(RATE),
- high);
- goto fail_init;
- }
-
- /* Halved packet size: valid samples at 10 MB/s. */
- for (i = 41; i <= 80; i++)
- cap_update_at(0, QLEN, LEN / 2, i * TICK);
-
- if (cap_get(0) >= high) {
- printf("Release did not decay: %u.\n", cap_get(0));
- goto fail_init;
- }
-
- if (cap_get(0) <= cap_enc(RATE / 2)) {
- printf("Release collapsed to %u.\n", cap_get(0));
- goto fail_init;
- }
-
- cap_fini();
-
- TEST_SUCCESS();
-
- return TEST_RC_SUCCESS;
- fail_init:
- cap_fini();
- fail:
- TEST_FAIL();
- return TEST_RC_FAIL;
-}
-
-/* No fold within CAP_T_MIN of the previous one. */
-static int test_cap_est_gate(void)
-{
- size_t i;
-
- TEST_START();
-
- if (cap_init() < 0) {
- printf("Failed to init cap.\n");
- goto fail;
- }
-
- cap_update_at(0, QLEN, LEN, CAP_T_MIN);
-
- for (i = 0; i < 5; i++)
- cap_update_at(0, QLEN, LEN, CAP_T_MIN + CAP_T_MIN / 2);
-
- if (cap.est[0].t_gate != CAP_T_MIN) {
- printf("Fold ran inside the gate.\n");
- goto fail_init;
- }
-
- if (LOAD_RELAXED(&cap.est[0].c_pkt) != 6) {
- printf("Gated packets not counted.\n");
- goto fail_init;
- }
-
- cap_fini();
-
- TEST_SUCCESS();
-
- return TEST_RC_SUCCESS;
- fail_init:
- cap_fini();
- fail:
- TEST_FAIL();
- return TEST_RC_FAIL;
-}
-
-static int test_cap_reset(void)
-{
- size_t i;
-
- TEST_START();
-
- if (cap_init() < 0) {
- printf("Failed to init cap.\n");
- goto fail;
- }
-
- for (i = 1; i <= 40; i++)
- cap_update_at(0, QLEN, LEN, i * TICK);
-
- if (cap_get(0) == 0) {
- printf("No estimate to reset.\n");
- goto fail_init;
- }
-
- cap_reset(0);
-
- if (cap_get(0) != 0) {
- printf("Reset did not clear the estimate.\n");
- goto fail_init;
- }
-
- cap_fini();
-
- TEST_SUCCESS();
-
- return TEST_RC_SUCCESS;
- fail_init:
- cap_fini();
- fail:
- TEST_FAIL();
- return TEST_RC_FAIL;
-}
-
int cap_test(int argc,
char ** argv)
{
@@ -573,21 +168,10 @@ int cap_test(int argc,
(void) argc;
(void) argv;
- ret |= test_cap_init_fini();
ret |= test_cap_codec_roundtrip();
ret |= test_cap_codec_bounds();
ret |= test_cap_min();
ret |= test_cap_stamp();
- ret |= test_cap_est_busy_window();
- ret |= test_cap_est_idle_tolerated();
- ret |= test_cap_est_mostly_idle_rejects();
- ret |= test_cap_est_slow_link_extends();
- ret |= test_cap_est_shaped_link();
- ret |= test_cap_est_stale_discard();
- ret |= test_cap_est_empty_start_no_raise();
- ret |= test_cap_est_max_filter();
- ret |= test_cap_est_gate();
- ret |= test_cap_reset();
return ret;
}