Skip to content

Commit 408a6ce

Browse files
committed
tests: net: tcp2: Add tests for TCP recv data queueing
Make sure that received and out-of-order TCP segments are queued until we receive proper segments. Signed-off-by: Jukka Rissanen <[email protected]>
1 parent ef80188 commit 408a6ce

File tree

3 files changed

+209
-16
lines changed

3 files changed

+209
-16
lines changed

tests/net/tcp2/prj.conf

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ CONFIG_NET_IPV4=y
1212
CONFIG_NET_BUF=y
1313

1414
CONFIG_MAIN_STACK_SIZE=2048
15-
CONFIG_NET_PKT_RX_COUNT=20
16-
CONFIG_NET_PKT_TX_COUNT=20
17-
CONFIG_NET_BUF_RX_COUNT=20
18-
CONFIG_NET_BUF_TX_COUNT=20
15+
CONFIG_NET_PKT_RX_COUNT=30
16+
CONFIG_NET_PKT_TX_COUNT=30
17+
CONFIG_NET_BUF_RX_COUNT=30
18+
CONFIG_NET_BUF_TX_COUNT=30
1919

2020
CONFIG_NET_MAX_CONTEXTS=10
2121
CONFIG_NET_LOG=y
@@ -50,3 +50,5 @@ CONFIG_NET_LOG=y
5050
#CONFIG_NET_IPV4_LOG_LEVEL_DBG=y
5151
#CONFIG_NET_IPV6_LOG_LEVEL_DBG=y
5252
#CONFIG_NET_CORE_LOG_LEVEL_DBG=y
53+
54+
CONFIG_NET_TCP_RECV_QUEUE_TIMEOUT=1000

tests/net/tcp2/src/main.c

Lines changed: 197 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,29 @@ LOG_MODULE_REGISTER(net_test, CONFIG_NET_TCP_LOG_LEVEL);
3232
#define MY_PORT 4242
3333
#define PEER_PORT 4242
3434

35+
/* Data (1280 bytes) to be sent */
36+
static const char lorem_ipsum[] =
37+
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris id "
38+
"sodales lacus. Proin vel rhoncus sapien. Morbi semper, enim in "
39+
"ullamcorper luctus, urna mi efficitur ex, laoreet eleifend massa "
40+
"felis ac dui. Duis ut magna convallis, tristique leo eu, ornare "
41+
"eros. Mauris a neque dictum, lobortis quam ut, rutrum erat. Vivamus "
42+
"vulputate neque vel auctor porta. Duis consectetur justo ac molestie "
43+
"tristique. In hac habitasse platea dictumst. Cras augue metus, "
44+
"aliquet sodales elit eget suscipit rutrum tellus. Nulla ante purus, "
45+
"dictum id tellus at, mattis cursus lectus. Mauris fringilla eros "
46+
"lorem, in auctor erat consequat nec. Ut pharetra sollicitudin dolor "
47+
"vel laoreet. Praesent eu lectus a dolor fringilla aliquet varius "
48+
"eget erat. Ut vitae mauris commodo, feugiat arcu non vehicula nunc. "
49+
"Nam ac enim elit. Praesent sit amet erat massa. Suspendisse potenti. "
50+
"Etiam diam justo, tempus vel lobortis tincidunt, scelerisque vitae "
51+
"mauris. Aenean vestibulum venenatis dapibus. Curabitur id ullamcorper"
52+
" diam. Ut eu turpis mauris. Aliquam et ligula est. Proin a velit non "
53+
"velit interdum vulputate. Proin vehicula eleifend suscipit. Cras "
54+
"condimentum non massa egestas tempor. Donec quis scelerisque est, id "
55+
"suscipit neque. Ut lobortis cursus ultrices. Aenean malesuada, nibh "
56+
"ut laoreet.";
57+
3558
static struct in_addr my_addr = { { { 192, 0, 2, 1 } } };
3659
static struct sockaddr_in my_addr_s = {
3760
.sin_family = AF_INET,
@@ -95,12 +118,15 @@ static void handle_server_test(sa_family_t af, struct tcphdr *th);
95118
static void handle_syn_resend(void);
96119
static void handle_client_fin_wait_2_test(sa_family_t af, struct tcphdr *th);
97120
static void handle_client_closing_test(sa_family_t af, struct tcphdr *th);
121+
static void handle_server_recv_out_of_order(struct net_pkt *pkt);
98122

99123
static void verify_flags(struct tcphdr *th, uint8_t flags,
100124
const char *fun, int line)
101125
{
102126
if (!(th && FL(&th->th_flags, ==, flags))) {
103-
zassert_true(false, "%s:%d flags mismatch", fun, line);
127+
zassert_true(false,
128+
"%s:%d flags mismatch (0x%04x vs 0x%04x)",
129+
fun, line, th->th_flags, flags);
104130
}
105131
}
106132

@@ -182,8 +208,10 @@ static uint8_t tcp_options[20] = {
182208
0x03, 0x03, 0x07 /* Win scale*/ };
183209

184210
static struct net_pkt *tester_prepare_tcp_pkt(sa_family_t af,
185-
uint16_t src_port, uint16_t dst_port,
186-
uint8_t flags, uint8_t *data,
211+
uint16_t src_port,
212+
uint16_t dst_port,
213+
uint8_t flags,
214+
const uint8_t *data,
187215
size_t len)
188216
{
189217
NET_PKT_DATA_ACCESS_DEFINE(tcp_access, struct tcphdr);
@@ -302,7 +330,8 @@ static struct net_pkt *prepare_ack_packet(sa_family_t af, uint16_t src_port,
302330
}
303331

304332
static struct net_pkt *prepare_data_packet(sa_family_t af, uint16_t src_port,
305-
uint16_t dst_port, uint8_t *data,
333+
uint16_t dst_port,
334+
const uint8_t *data,
306335
size_t len)
307336
{
308337
return tester_prepare_tcp_pkt(af, src_port, dst_port, PSH | ACK, data,
@@ -382,6 +411,9 @@ static int tester_send(const struct device *dev, struct net_pkt *pkt)
382411
case 8:
383412
handle_client_closing_test(net_pkt_family(pkt), &th);
384413
break;
414+
case 9:
415+
handle_server_recv_out_of_order(pkt);
416+
break;
385417
default:
386418
zassert_true(false, "Undefined test case");
387419
}
@@ -603,8 +635,6 @@ static void handle_server_test(sa_family_t af, struct tcphdr *th)
603635

604636
switch (t_state) {
605637
case T_SYN:
606-
seq = 0U;
607-
ack = 0U;
608638
reply = prepare_syn_packet(af, htons(MY_PORT),
609639
htons(PEER_PORT));
610640
t_state = T_SYN_ACK;
@@ -1172,14 +1202,16 @@ static void test_client_closing_ipv6(void)
11721202
k_sleep(K_MSEC(CONFIG_NET_TCP_TIME_WAIT_DELAY));
11731203
}
11741204

1175-
static struct net_context *create_server_socket(void)
1205+
static struct net_context *create_server_socket(uint32_t my_seq,
1206+
uint32_t my_ack)
11761207
{
11771208
struct net_context *ctx;
11781209
int ret;
11791210

11801211
t_state = T_SYN;
11811212
test_case_no = 5;
1182-
seq = ack = 0;
1213+
seq = my_seq;
1214+
ack = my_ack;
11831215

11841216
ret = net_context_get(AF_INET6, SOCK_STREAM, IPPROTO_TCP, &ctx);
11851217
if (ret < 0) {
@@ -1248,7 +1280,7 @@ static void check_rst_succeed(struct net_context *ctx,
12481280

12491281
/* Make sure that various other corner cases work */
12501282
if (ctx == NULL) {
1251-
ctx = create_server_socket();
1283+
ctx = create_server_socket(0, 0);
12521284
}
12531285

12541286
/* Another valid seq in the RST packet */
@@ -1279,7 +1311,7 @@ static void test_client_invalid_rst(void)
12791311
struct tcp *conn;
12801312
uint16_t wnd;
12811313

1282-
ctx = create_server_socket();
1314+
ctx = create_server_socket(0, 0);
12831315

12841316
conn = ctx->tcp;
12851317
wnd = conn->recv_win;
@@ -1292,6 +1324,158 @@ static void test_client_invalid_rst(void)
12921324
check_rst_succeed(ctx, wnd - 1);
12931325
check_rst_succeed(NULL, 0);
12941326
check_rst_succeed(NULL, 1);
1327+
1328+
net_tcp_put(ctx);
1329+
}
1330+
1331+
#define MAX_DATA 100
1332+
static uint32_t expected_ack = MAX_DATA + 1 - 15;
1333+
static struct net_context *ooo_ctx;
1334+
1335+
static void handle_server_recv_out_of_order(struct net_pkt *pkt)
1336+
{
1337+
struct tcphdr th;
1338+
int ret;
1339+
1340+
ret = read_tcp_header(pkt, &th);
1341+
if (ret < 0) {
1342+
goto fail;
1343+
}
1344+
1345+
/* Verify that we received all the queued data */
1346+
zassert_equal(expected_ack, ntohl(th.th_ack),
1347+
"Not all pending data received. "
1348+
"Expected ACK %u but got %u",
1349+
expected_ack, ntohl(th.th_ack));
1350+
1351+
test_sem_give();
1352+
1353+
return;
1354+
1355+
fail:
1356+
zassert_true(false, "%s failed", __func__);
1357+
net_pkt_unref(pkt);
1358+
}
1359+
1360+
static void test_server_recv_out_of_order_data(void)
1361+
{
1362+
const uint8_t *data = lorem_ipsum + 10;
1363+
struct net_pkt *pkt;
1364+
int ret, i;
1365+
1366+
/* Only run the tests if queueing is enabled */
1367+
if (CONFIG_NET_TCP_RECV_QUEUE_TIMEOUT == 0) {
1368+
return;
1369+
}
1370+
1371+
/* Start the sequence numbering so that we will wrap it (just for
1372+
* testing purposes)
1373+
*/
1374+
ooo_ctx = create_server_socket(-15U, -15U);
1375+
1376+
/* This will force the packet to be routed to our checker func
1377+
* handle_server_recv_out_of_order()
1378+
*/
1379+
test_case_no = 9;
1380+
1381+
/* First packet will be out-of-order */
1382+
seq += MAX_DATA - 20;
1383+
pkt = prepare_data_packet(AF_INET6, htons(MY_PORT), htons(PEER_PORT),
1384+
&data[seq], 10);
1385+
zassert_not_null(pkt, "Cannot create pkt");
1386+
1387+
ret = net_recv_data(iface, pkt);
1388+
zassert_true(ret == 0, "recv data failed (%d)", ret);
1389+
1390+
/* Let the IP stack to process the packet properly */
1391+
k_msleep(1);
1392+
1393+
/* Then we send a packet that is after the previous packet */
1394+
seq += 10;
1395+
1396+
pkt = prepare_data_packet(AF_INET6, htons(MY_PORT), htons(PEER_PORT),
1397+
&data[seq], 10);
1398+
zassert_not_null(pkt, "Cannot create pkt");
1399+
1400+
ret = net_recv_data(iface, pkt);
1401+
zassert_true(ret == 0, "recv data failed (%d)", ret);
1402+
1403+
k_msleep(1);
1404+
1405+
/* Then send packets that are before the first packet. The final packet
1406+
* will flush the receive queue as the seq will be 1
1407+
*/
1408+
for (i = MAX_DATA - 10; i > 0; i -= 10) {
1409+
seq -= 10;
1410+
1411+
pkt = prepare_data_packet(AF_INET6, htons(MY_PORT),
1412+
htons(PEER_PORT),
1413+
&data[i], 10);
1414+
zassert_not_null(pkt, "Cannot create pkt");
1415+
1416+
ret = net_recv_data(iface, pkt);
1417+
zassert_true(ret == 0, "recv data failed (%d)", ret);
1418+
1419+
k_msleep(1);
1420+
}
1421+
1422+
/* Then the final packet that will flush the receive queue */
1423+
pkt = prepare_data_packet(AF_INET6, htons(MY_PORT),
1424+
htons(PEER_PORT),
1425+
&data[i], 10);
1426+
zassert_not_null(pkt, "Cannot create pkt");
1427+
1428+
ret = net_recv_data(iface, pkt);
1429+
zassert_true(ret == 0, "recv data failed (%d)", ret);
1430+
1431+
/* Peer will release the semaphone after it sends proper ACK to the
1432+
* queued data.
1433+
*/
1434+
test_sem_take(K_MSEC(1000), __LINE__);
1435+
}
1436+
1437+
/* This test expects that the system is in correct state after a call to
1438+
* test_server_recv_out_of_order_data(), so this test must be run after that
1439+
* test.
1440+
*/
1441+
static void test_server_timeout_out_of_order_data(void)
1442+
{
1443+
const uint8_t *data = lorem_ipsum + 10;
1444+
struct net_pkt *pkt;
1445+
int ret, i;
1446+
1447+
if (CONFIG_NET_TCP_RECV_QUEUE_TIMEOUT == 0) {
1448+
return;
1449+
}
1450+
1451+
k_sem_reset(&test_sem);
1452+
1453+
/* The +1 will cause the seq to be not sequential thus we should
1454+
* get a timeout.
1455+
*/
1456+
seq = expected_ack + MAX_DATA + 1;
1457+
1458+
/* Then special handling to send out-of-order TCP segments */
1459+
for (i = MAX_DATA; i > 10; i -= 10) {
1460+
seq -= 10;
1461+
1462+
pkt = prepare_data_packet(AF_INET6, htons(MY_PORT),
1463+
htons(PEER_PORT),
1464+
&data[i], 10);
1465+
zassert_not_null(pkt, "Cannot create pkt");
1466+
1467+
ret = net_recv_data(iface, pkt);
1468+
zassert_true(ret == 0, "recv data failed (%d)", ret);
1469+
}
1470+
1471+
/* Because the pending seq values are not sequential,
1472+
* the recv queue in tcp2 should timeout.
1473+
*/
1474+
ret = k_sem_take(&test_sem,
1475+
K_MSEC(CONFIG_NET_TCP_RECV_QUEUE_TIMEOUT + 10));
1476+
zassert_equal(ret, -EAGAIN, "semaphore did not time out (%d)", ret);
1477+
1478+
net_tcp_put(ooo_ctx);
12951479
}
12961480

12971481
/** Test case main entry */
@@ -1307,7 +1491,9 @@ void test_main(void)
13071491
ztest_unit_test(test_client_syn_resend),
13081492
ztest_unit_test(test_client_fin_wait_2_ipv4),
13091493
ztest_unit_test(test_client_closing_ipv6),
1310-
ztest_unit_test(test_client_invalid_rst)
1494+
ztest_unit_test(test_client_invalid_rst),
1495+
ztest_unit_test(test_server_recv_out_of_order_data),
1496+
ztest_unit_test(test_server_timeout_out_of_order_data)
13111497
);
13121498

13131499
ztest_run_test_suite(test_tcp_fn);

tests/net/tcp2/testcase.yaml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
common:
22
depends_on: netif
3+
tags: net tcp2
34
tests:
45
net.tcp2.simple:
5-
tags: net tcp2
6+
extra_configs:
7+
- CONFIG_NET_TCP_RECV_QUEUE_TIMEOUT=1000
8+
net.tcp2.no_recv_queue:
9+
extra_configs:
10+
- CONFIG_NET_TCP_RECV_QUEUE_TIMEOUT=0

0 commit comments

Comments
 (0)