Skip to content

Commit ad1cdb8

Browse files
magnus-karlssonKernel Patches Daemon
authored andcommitted
selftests: xsk: make stat tests not spin on getsockopt
Convert the stats tests from spinning on the getsockopt to just check getsockopt once when the Rx thread has received all the packets. The actual completion of receiving the last packet forms a natural point in time when the receiver is ready to call the getsockopt to check the stats. In the previous version , we just span on the getsockopt until we received the right answer. This could be forever or just getting the "correct" answer by shear luck. The pacing_on variable can now be dropped since all test can now handle pacing properly. Signed-off-by: Magnus Karlsson <[email protected]>
1 parent dcc2629 commit ad1cdb8

File tree

2 files changed

+99
-77
lines changed

2 files changed

+99
-77
lines changed

tools/testing/selftests/bpf/xdpxceiver.c

Lines changed: 96 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,8 @@ static void __test_spec_init(struct test_spec *test, struct ifobject *ifobj_tx,
424424

425425
ifobj->xsk = &ifobj->xsk_arr[0];
426426
ifobj->use_poll = false;
427-
ifobj->pacing_on = true;
427+
ifobj->use_fill_ring = true;
428+
ifobj->release_rx = true;
428429
ifobj->pkt_stream = test->pkt_stream_default;
429430
ifobj->validation_func = NULL;
430431

@@ -503,9 +504,10 @@ static struct pkt *pkt_stream_get_pkt(struct pkt_stream *pkt_stream, u32 pkt_nb)
503504
return &pkt_stream->pkts[pkt_nb];
504505
}
505506

506-
static struct pkt *pkt_stream_get_next_rx_pkt(struct pkt_stream *pkt_stream)
507+
static struct pkt *pkt_stream_get_next_rx_pkt(struct pkt_stream *pkt_stream, u32 *pkts_sent)
507508
{
508509
while (pkt_stream->rx_pkt_nb < pkt_stream->nb_pkts) {
510+
(*pkts_sent)++;
509511
if (pkt_stream->pkts[pkt_stream->rx_pkt_nb].valid)
510512
return &pkt_stream->pkts[pkt_stream->rx_pkt_nb++];
511513
pkt_stream->rx_pkt_nb++;
@@ -521,10 +523,16 @@ static void pkt_stream_delete(struct pkt_stream *pkt_stream)
521523

522524
static void pkt_stream_restore_default(struct test_spec *test)
523525
{
524-
if (test->ifobj_tx->pkt_stream != test->pkt_stream_default) {
526+
struct pkt_stream *tx_pkt_stream = test->ifobj_tx->pkt_stream;
527+
528+
if (tx_pkt_stream != test->pkt_stream_default) {
525529
pkt_stream_delete(test->ifobj_tx->pkt_stream);
526530
test->ifobj_tx->pkt_stream = test->pkt_stream_default;
527531
}
532+
533+
if (test->ifobj_rx->pkt_stream != test->pkt_stream_default &&
534+
test->ifobj_rx->pkt_stream != tx_pkt_stream)
535+
pkt_stream_delete(test->ifobj_rx->pkt_stream);
528536
test->ifobj_rx->pkt_stream = test->pkt_stream_default;
529537
}
530538

@@ -546,6 +554,16 @@ static struct pkt_stream *__pkt_stream_alloc(u32 nb_pkts)
546554
return pkt_stream;
547555
}
548556

557+
static void pkt_set(struct xsk_umem_info *umem, struct pkt *pkt, u64 addr, u32 len)
558+
{
559+
pkt->addr = addr;
560+
pkt->len = len;
561+
if (len > umem->frame_size - XDP_PACKET_HEADROOM - MIN_PKT_SIZE * 2 - umem->frame_headroom)
562+
pkt->valid = false;
563+
else
564+
pkt->valid = true;
565+
}
566+
549567
static struct pkt_stream *pkt_stream_generate(struct xsk_umem_info *umem, u32 nb_pkts, u32 pkt_len)
550568
{
551569
struct pkt_stream *pkt_stream;
@@ -557,14 +575,9 @@ static struct pkt_stream *pkt_stream_generate(struct xsk_umem_info *umem, u32 nb
557575

558576
pkt_stream->nb_pkts = nb_pkts;
559577
for (i = 0; i < nb_pkts; i++) {
560-
pkt_stream->pkts[i].addr = (i % umem->num_frames) * umem->frame_size;
561-
pkt_stream->pkts[i].len = pkt_len;
578+
pkt_set(umem, &pkt_stream->pkts[i], (i % umem->num_frames) * umem->frame_size,
579+
pkt_len);
562580
pkt_stream->pkts[i].payload = i;
563-
564-
if (pkt_len > umem->frame_size)
565-
pkt_stream->pkts[i].valid = false;
566-
else
567-
pkt_stream->pkts[i].valid = true;
568581
}
569582

570583
return pkt_stream;
@@ -592,15 +605,27 @@ static void pkt_stream_replace_half(struct test_spec *test, u32 pkt_len, int off
592605
u32 i;
593606

594607
pkt_stream = pkt_stream_clone(umem, test->pkt_stream_default);
595-
for (i = 1; i < test->pkt_stream_default->nb_pkts; i += 2) {
596-
pkt_stream->pkts[i].addr = (i % umem->num_frames) * umem->frame_size + offset;
597-
pkt_stream->pkts[i].len = pkt_len;
598-
}
608+
for (i = 1; i < test->pkt_stream_default->nb_pkts; i += 2)
609+
pkt_set(umem, &pkt_stream->pkts[i],
610+
(i % umem->num_frames) * umem->frame_size + offset, pkt_len);
599611

600612
test->ifobj_tx->pkt_stream = pkt_stream;
601613
test->ifobj_rx->pkt_stream = pkt_stream;
602614
}
603615

616+
static void pkt_stream_receive_half(struct test_spec *test)
617+
{
618+
struct xsk_umem_info *umem = test->ifobj_rx->umem;
619+
struct pkt_stream *pkt_stream = test->ifobj_tx->pkt_stream;
620+
u32 i;
621+
622+
test->ifobj_rx->pkt_stream = pkt_stream_generate(umem, pkt_stream->nb_pkts,
623+
pkt_stream->pkts[0].len);
624+
pkt_stream = test->ifobj_rx->pkt_stream;
625+
for (i = 1; i < pkt_stream->nb_pkts; i += 2)
626+
pkt_stream->pkts[i].valid = false;
627+
}
628+
604629
static struct pkt *pkt_generate(struct ifobject *ifobject, u32 pkt_nb)
605630
{
606631
struct pkt *pkt = pkt_stream_get_pkt(ifobject->pkt_stream, pkt_nb);
@@ -795,18 +820,19 @@ static int complete_pkts(struct xsk_socket_info *xsk, int batch_size)
795820
static int receive_pkts(struct ifobject *ifobj, struct pollfd *fds)
796821
{
797822
struct timeval tv_end, tv_now, tv_timeout = {RECV_TMOUT, 0};
823+
u32 idx_rx = 0, idx_fq = 0, rcvd, i, pkts_sent = 0;
798824
struct pkt_stream *pkt_stream = ifobj->pkt_stream;
799-
struct pkt *pkt = pkt_stream_get_next_rx_pkt(pkt_stream);
800825
struct xsk_socket_info *xsk = ifobj->xsk;
801826
struct xsk_umem_info *umem = xsk->umem;
802-
u32 idx_rx = 0, idx_fq = 0, rcvd, i;
827+
struct pkt *pkt;
803828
int ret;
804829

805830
ret = gettimeofday(&tv_now, NULL);
806831
if (ret)
807832
exit_with_error(errno);
808833
timeradd(&tv_now, &tv_timeout, &tv_end);
809834

835+
pkt = pkt_stream_get_next_rx_pkt(pkt_stream, &pkts_sent);
810836
while (pkt) {
811837
ret = gettimeofday(&tv_now, NULL);
812838
if (ret)
@@ -828,49 +854,47 @@ static int receive_pkts(struct ifobject *ifobj, struct pollfd *fds)
828854
continue;
829855
}
830856

831-
ret = xsk_ring_prod__reserve(&umem->fq, rcvd, &idx_fq);
832-
while (ret != rcvd) {
833-
if (ret < 0)
834-
exit_with_error(-ret);
835-
if (xsk_ring_prod__needs_wakeup(&umem->fq)) {
836-
ret = poll(fds, 1, POLL_TMOUT);
857+
if (ifobj->use_fill_ring) {
858+
ret = xsk_ring_prod__reserve(&umem->fq, rcvd, &idx_fq);
859+
while (ret != rcvd) {
837860
if (ret < 0)
838861
exit_with_error(-ret);
862+
if (xsk_ring_prod__needs_wakeup(&umem->fq)) {
863+
ret = poll(fds, 1, POLL_TMOUT);
864+
if (ret < 0)
865+
exit_with_error(-ret);
866+
}
867+
ret = xsk_ring_prod__reserve(&umem->fq, rcvd, &idx_fq);
839868
}
840-
ret = xsk_ring_prod__reserve(&umem->fq, rcvd, &idx_fq);
841869
}
842870

843871
for (i = 0; i < rcvd; i++) {
844872
const struct xdp_desc *desc = xsk_ring_cons__rx_desc(&xsk->rx, idx_rx++);
845873
u64 addr = desc->addr, orig;
846874

847-
if (!pkt) {
848-
ksft_print_msg("[%s] Received too many packets.\n",
849-
__func__);
850-
ksft_print_msg("Last packet has addr: %llx len: %u\n",
851-
addr, desc->len);
852-
return TEST_FAILURE;
853-
}
854-
855875
orig = xsk_umem__extract_addr(addr);
856876
addr = xsk_umem__add_offset_to_addr(addr);
857877

858878
if (!is_pkt_valid(pkt, umem->buffer, addr, desc->len) ||
859879
!is_offset_correct(umem, pkt_stream, addr, pkt->addr))
860880
return TEST_FAILURE;
861881

862-
*xsk_ring_prod__fill_addr(&umem->fq, idx_fq++) = orig;
863-
pkt = pkt_stream_get_next_rx_pkt(pkt_stream);
882+
if (ifobj->use_fill_ring)
883+
*xsk_ring_prod__fill_addr(&umem->fq, idx_fq++) = orig;
884+
pkt = pkt_stream_get_next_rx_pkt(pkt_stream, &pkts_sent);
864885
}
865886

866-
xsk_ring_prod__submit(&umem->fq, rcvd);
867-
xsk_ring_cons__release(&xsk->rx, rcvd);
887+
if (ifobj->use_fill_ring)
888+
xsk_ring_prod__submit(&umem->fq, rcvd);
889+
if (ifobj->release_rx)
890+
xsk_ring_cons__release(&xsk->rx, rcvd);
868891

869892
pthread_mutex_lock(&pacing_mutex);
870-
pkts_in_flight -= rcvd;
893+
pkts_in_flight -= pkts_sent;
871894
if (pkts_in_flight < umem->num_frames)
872895
pthread_cond_signal(&pacing_cond);
873896
pthread_mutex_unlock(&pacing_mutex);
897+
pkts_sent = 0;
874898
}
875899

876900
return TEST_PASS;
@@ -900,7 +924,8 @@ static int __send_pkts(struct ifobject *ifobject, u32 *pkt_nb)
900924

901925
pthread_mutex_lock(&pacing_mutex);
902926
pkts_in_flight += valid_pkts;
903-
if (ifobject->pacing_on && pkts_in_flight >= ifobject->umem->num_frames - BATCH_SIZE) {
927+
/* pkts_in_flight might be negative if many invalid packets are sent */
928+
if (pkts_in_flight >= (int)(ifobject->umem->num_frames - BATCH_SIZE)) {
904929
kick_tx(xsk);
905930
pthread_cond_wait(&pacing_cond, &pacing_mutex);
906931
}
@@ -987,34 +1012,29 @@ static int validate_rx_dropped(struct ifobject *ifobject)
9871012
if (err)
9881013
return TEST_FAILURE;
9891014

990-
if (stats.rx_dropped == ifobject->pkt_stream->nb_pkts)
1015+
if (stats.rx_dropped == ifobject->pkt_stream->nb_pkts / 2)
9911016
return TEST_PASS;
9921017

993-
return TEST_CONTINUE;
1018+
return TEST_FAILURE;
9941019
}
9951020

9961021
static int validate_rx_full(struct ifobject *ifobject)
9971022
{
9981023
struct xsk_socket *xsk = ifobject->xsk->xsk;
9991024
struct xdp_statistics stats;
1000-
u32 expected_stat;
10011025
int err;
10021026

1027+
usleep(1000);
10031028
kick_rx(ifobject->xsk);
10041029

10051030
err = get_xsk_stats(xsk, &stats);
10061031
if (err)
10071032
return TEST_FAILURE;
10081033

1009-
if (ifobject->umem->num_frames < XSK_RING_PROD__DEFAULT_NUM_DESCS)
1010-
expected_stat = ifobject->umem->num_frames - RX_FULL_RXQSIZE;
1011-
else
1012-
expected_stat = XSK_RING_PROD__DEFAULT_NUM_DESCS - RX_FULL_RXQSIZE;
1013-
1014-
if (stats.rx_ring_full == expected_stat)
1034+
if (stats.rx_ring_full)
10151035
return TEST_PASS;
10161036

1017-
return TEST_CONTINUE;
1037+
return TEST_FAILURE;
10181038
}
10191039

10201040
static int validate_fill_empty(struct ifobject *ifobject)
@@ -1023,16 +1043,17 @@ static int validate_fill_empty(struct ifobject *ifobject)
10231043
struct xdp_statistics stats;
10241044
int err;
10251045

1046+
usleep(1000);
10261047
kick_rx(ifobject->xsk);
10271048

10281049
err = get_xsk_stats(xsk, &stats);
10291050
if (err)
10301051
return TEST_FAILURE;
10311052

1032-
if (stats.rx_fill_ring_empty_descs == ifobject->pkt_stream->nb_pkts)
1053+
if (stats.rx_fill_ring_empty_descs)
10331054
return TEST_PASS;
10341055

1035-
return TEST_CONTINUE;
1056+
return TEST_FAILURE;
10361057
}
10371058

10381059
static int validate_tx_invalid_descs(struct ifobject *ifobject)
@@ -1051,7 +1072,7 @@ static int validate_tx_invalid_descs(struct ifobject *ifobject)
10511072
return TEST_FAILURE;
10521073
}
10531074

1054-
if (stats.tx_invalid_descs != ifobject->pkt_stream->nb_pkts) {
1075+
if (stats.tx_invalid_descs != ifobject->pkt_stream->nb_pkts / 2) {
10551076
ksft_print_msg("[%s] tx_invalid_descs incorrect. Got [%u] expected [%u]\n",
10561077
__func__, stats.tx_invalid_descs, ifobject->pkt_stream->nb_pkts);
10571078
return TEST_FAILURE;
@@ -1138,17 +1159,12 @@ static void *worker_testapp_validate_tx(void *arg)
11381159
print_verbose("Sending %d packets on interface %s\n", ifobject->pkt_stream->nb_pkts,
11391160
ifobject->ifname);
11401161
err = send_pkts(test, ifobject);
1141-
if (err) {
1142-
report_failure(test);
1143-
goto out;
1144-
}
11451162

1146-
if (ifobject->validation_func) {
1163+
if (!err && ifobject->validation_func)
11471164
err = ifobject->validation_func(ifobject);
1165+
if (err)
11481166
report_failure(test);
1149-
}
11501167

1151-
out:
11521168
if (test->total_steps == test->current_step || err)
11531169
testapp_cleanup_xsk_res(ifobject);
11541170
pthread_exit(NULL);
@@ -1202,14 +1218,10 @@ static void *worker_testapp_validate_rx(void *arg)
12021218

12031219
pthread_barrier_wait(&barr);
12041220

1205-
if (ifobject->validation_func) {
1206-
do {
1207-
err = ifobject->validation_func(ifobject);
1208-
} while (err == TEST_CONTINUE);
1209-
} else {
1210-
err = receive_pkts(ifobject, &fds);
1211-
}
1221+
err = receive_pkts(ifobject, &fds);
12121222

1223+
if (!err && ifobject->validation_func)
1224+
err = ifobject->validation_func(ifobject);
12131225
if (err) {
12141226
report_failure(test);
12151227
pthread_mutex_lock(&pacing_mutex);
@@ -1327,18 +1339,18 @@ static void testapp_headroom(struct test_spec *test)
13271339
static void testapp_stats_rx_dropped(struct test_spec *test)
13281340
{
13291341
test_spec_set_name(test, "STAT_RX_DROPPED");
1330-
test->ifobj_tx->pacing_on = false;
13311342
test->ifobj_rx->umem->frame_headroom = test->ifobj_rx->umem->frame_size -
1332-
XDP_PACKET_HEADROOM - 1;
1343+
XDP_PACKET_HEADROOM - MIN_PKT_SIZE * 3;
1344+
pkt_stream_replace_half(test, MIN_PKT_SIZE * 4, 0);
1345+
pkt_stream_receive_half(test);
13331346
test->ifobj_rx->validation_func = validate_rx_dropped;
13341347
testapp_validate_traffic(test);
13351348
}
13361349

13371350
static void testapp_stats_tx_invalid_descs(struct test_spec *test)
13381351
{
13391352
test_spec_set_name(test, "STAT_TX_INVALID");
1340-
test->ifobj_tx->pacing_on = false;
1341-
pkt_stream_replace(test, DEFAULT_PKT_CNT, XSK_UMEM__INVALID_FRAME_SIZE);
1353+
pkt_stream_replace_half(test, XSK_UMEM__INVALID_FRAME_SIZE, 0);
13421354
test->ifobj_tx->validation_func = validate_tx_invalid_descs;
13431355
testapp_validate_traffic(test);
13441356

@@ -1348,20 +1360,30 @@ static void testapp_stats_tx_invalid_descs(struct test_spec *test)
13481360
static void testapp_stats_rx_full(struct test_spec *test)
13491361
{
13501362
test_spec_set_name(test, "STAT_RX_FULL");
1351-
test->ifobj_tx->pacing_on = false;
1352-
test->ifobj_rx->xsk->rxqsize = RX_FULL_RXQSIZE;
1363+
pkt_stream_replace(test, DEFAULT_UMEM_BUFFERS + DEFAULT_UMEM_BUFFERS / 2, PKT_SIZE);
1364+
test->ifobj_rx->pkt_stream = pkt_stream_generate(test->ifobj_rx->umem,
1365+
DEFAULT_UMEM_BUFFERS, PKT_SIZE);
1366+
if (!test->ifobj_rx->pkt_stream)
1367+
exit_with_error(ENOMEM);
1368+
1369+
test->ifobj_rx->xsk->rxqsize = DEFAULT_UMEM_BUFFERS;
1370+
test->ifobj_rx->release_rx = false;
13531371
test->ifobj_rx->validation_func = validate_rx_full;
13541372
testapp_validate_traffic(test);
1373+
1374+
pkt_stream_restore_default(test);
13551375
}
13561376

13571377
static void testapp_stats_fill_empty(struct test_spec *test)
13581378
{
13591379
test_spec_set_name(test, "STAT_RX_FILL_EMPTY");
1360-
test->ifobj_tx->pacing_on = false;
1361-
test->ifobj_rx->pkt_stream = pkt_stream_generate(test->ifobj_rx->umem, 0, MIN_PKT_SIZE);
1380+
pkt_stream_replace(test, DEFAULT_UMEM_BUFFERS + DEFAULT_UMEM_BUFFERS / 2, PKT_SIZE);
1381+
test->ifobj_rx->pkt_stream = pkt_stream_generate(test->ifobj_rx->umem,
1382+
DEFAULT_UMEM_BUFFERS, PKT_SIZE);
13621383
if (!test->ifobj_rx->pkt_stream)
13631384
exit_with_error(ENOMEM);
1364-
test->ifobj_rx->pkt_stream->use_addr_for_fill = true;
1385+
1386+
test->ifobj_rx->use_fill_ring = false;
13651387
test->ifobj_rx->validation_func = validate_fill_empty;
13661388
testapp_validate_traffic(test);
13671389

@@ -1504,7 +1526,7 @@ static void run_pkt_test(struct test_spec *test, enum test_mode mode, enum test_
15041526
test_spec_set_name(test, "RUN_TO_COMPLETION_2K_FRAME_SIZE");
15051527
test->ifobj_tx->umem->frame_size = 2048;
15061528
test->ifobj_rx->umem->frame_size = 2048;
1507-
pkt_stream_replace(test, DEFAULT_PKT_CNT, MIN_PKT_SIZE);
1529+
pkt_stream_replace(test, DEFAULT_PKT_CNT, PKT_SIZE);
15081530
testapp_validate_traffic(test);
15091531

15101532
pkt_stream_restore_default(test);

0 commit comments

Comments
 (0)