On Tue, Jun 14, 2022 at 7:51 PM Maciej Fijalkowski <maciej.fijalkowski@xxxxxxxxx> wrote: > > Introduce new mode to xdpxceiver responsible for testing AF_XDP zero > copy support of driver that serves underlying physical device. When > setting up test suite, determine whether driver has ZC support or not by > trying to bind XSK ZC socket to the interface. If it succeeded, > interpret it as ZC support being in place and do softirq and busy poll > tests for zero copy mode. > > Note that Rx dropped tests are skipped since ZC path is not touching > rx_dropped stat at all. And again, thanks for working on this. This feature will be very useful to increase test coverage. Acked-by: Magnus Karlsson <magnus.karlsson@xxxxxxxxx> > Signed-off-by: Maciej Fijalkowski <maciej.fijalkowski@xxxxxxxxx> > --- > tools/testing/selftests/bpf/xdpxceiver.c | 76 ++++++++++++++++++++++-- > tools/testing/selftests/bpf/xdpxceiver.h | 2 + > 2 files changed, 74 insertions(+), 4 deletions(-) > > diff --git a/tools/testing/selftests/bpf/xdpxceiver.c b/tools/testing/selftests/bpf/xdpxceiver.c > index ade9d87e7a7c..66bfb365b656 100644 > --- a/tools/testing/selftests/bpf/xdpxceiver.c > +++ b/tools/testing/selftests/bpf/xdpxceiver.c > @@ -124,9 +124,20 @@ static void __exit_with_error(int error, const char *file, const char *func, int > } > > #define exit_with_error(error) __exit_with_error(error, __FILE__, __func__, __LINE__) > - > -#define mode_string(test) (test)->ifobj_tx->xdp_flags & XDP_FLAGS_SKB_MODE ? "SKB" : "DRV" > #define busy_poll_string(test) (test)->ifobj_tx->busy_poll ? "BUSY-POLL " : "" > +static char *mode_string(struct test_spec *test) > +{ > + switch (test->mode) { > + case TEST_MODE_SKB: > + return "SKB"; > + case TEST_MODE_DRV: > + return "DRV"; > + case TEST_MODE_ZC: > + return "ZC"; > + default: > + return "BOGUS"; > + } > +} > > static void report_failure(struct test_spec *test) > { > @@ -317,6 +328,51 @@ static int __xsk_configure_socket(struct xsk_socket_info *xsk, struct xsk_umem_i > return xsk_socket__create(&xsk->xsk, ifobject->ifname, 0, umem->umem, rxr, txr, &cfg); > } > > +static bool ifobj_zc_avail(struct ifobject *ifobject) > +{ > + size_t umem_sz = DEFAULT_UMEM_BUFFERS * XSK_UMEM__DEFAULT_FRAME_SIZE; > + int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE; > + struct xsk_socket_info *xsk; > + struct xsk_umem_info *umem; > + bool zc_avail = false; > + void *bufs; > + int ret; > + > + bufs = mmap(NULL, umem_sz, PROT_READ | PROT_WRITE, mmap_flags, -1, 0); > + if (bufs == MAP_FAILED) > + exit_with_error(errno); > + > + umem = calloc(1, sizeof(struct xsk_umem_info)); > + if (!umem) { > + munmap(bufs, umem_sz); > + exit_with_error(-ENOMEM); > + } > + umem->frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE; > + ret = xsk_configure_umem(umem, bufs, umem_sz); > + if (ret) > + exit_with_error(-ret); > + > + xsk = calloc(1, sizeof(struct xsk_socket_info)); > + if (!xsk) > + goto out; > + ifobject->xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST; > + ifobject->xdp_flags |= XDP_FLAGS_DRV_MODE; > + ifobject->bind_flags = XDP_USE_NEED_WAKEUP | XDP_ZEROCOPY; > + ifobject->rx_on = true; > + xsk->rxqsize = XSK_RING_CONS__DEFAULT_NUM_DESCS; > + ret = __xsk_configure_socket(xsk, umem, ifobject, false); > + if (!ret) > + zc_avail = true; > + > + xsk_socket__delete(xsk->xsk); > + free(xsk); > +out: > + munmap(umem->buffer, umem_sz); > + xsk_umem__delete(umem->umem); > + free(umem); > + return zc_avail; > +} > + > static struct option long_options[] = { > {"interface", required_argument, 0, 'i'}, > {"busy-poll", no_argument, 0, 'b'}, > @@ -483,9 +539,14 @@ static void test_spec_init(struct test_spec *test, struct ifobject *ifobj_tx, > else > ifobj->xdp_flags |= XDP_FLAGS_DRV_MODE; > > - ifobj->bind_flags = XDP_USE_NEED_WAKEUP | XDP_COPY; > + ifobj->bind_flags = XDP_USE_NEED_WAKEUP; > + if (mode == TEST_MODE_ZC) > + ifobj->bind_flags |= XDP_ZEROCOPY; > + else > + ifobj->bind_flags |= XDP_COPY; > } > > + test->mode = mode; > __test_spec_init(test, ifobj_tx, ifobj_rx); > } > > @@ -1543,6 +1604,10 @@ static void run_pkt_test(struct test_spec *test, enum test_mode mode, enum test_ > { > switch (type) { > case TEST_TYPE_STATS_RX_DROPPED: > + if (mode == TEST_MODE_ZC) { > + ksft_test_result_skip("Can not run RX_DROPPED test for ZC mode\n"); > + return; > + } > testapp_stats_rx_dropped(test); > break; > case TEST_TYPE_STATS_TX_INVALID_DESCS: > @@ -1721,8 +1786,11 @@ int main(int argc, char **argv) > init_iface(ifobj_rx, MAC2, MAC1, IP2, IP1, UDP_PORT2, UDP_PORT1, > worker_testapp_validate_rx); > > - if (is_xdp_supported(ifobj_tx)) > + if (is_xdp_supported(ifobj_tx)) { > modes++; > + if (ifobj_zc_avail(ifobj_tx)) > + modes++; > + } > > test_spec_init(&test, ifobj_tx, ifobj_rx, 0); > tx_pkt_stream_default = pkt_stream_generate(ifobj_tx->umem, DEFAULT_PKT_CNT, PKT_SIZE); > diff --git a/tools/testing/selftests/bpf/xdpxceiver.h b/tools/testing/selftests/bpf/xdpxceiver.h > index 12b792004163..a86331c6b0c5 100644 > --- a/tools/testing/selftests/bpf/xdpxceiver.h > +++ b/tools/testing/selftests/bpf/xdpxceiver.h > @@ -61,6 +61,7 @@ > enum test_mode { > TEST_MODE_SKB, > TEST_MODE_DRV, > + TEST_MODE_ZC, > TEST_MODE_MAX > }; > > @@ -162,6 +163,7 @@ struct test_spec { > u16 current_step; > u16 nb_sockets; > bool fail; > + enum test_mode mode; > char name[MAX_TEST_NAME_SIZE]; > }; > > -- > 2.27.0 >