mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-18 22:14:16 +00:00
selftests/bpf: Xsk selftests - Bi-directional Sockets - SKB, DRV
Adds following tests:
1. AF_XDP SKB mode
d. Bi-directional Sockets
Configure sockets as bi-directional tx/rx sockets, sets up fill
and completion rings on each socket, tx/rx in both directions.
Only nopoll mode is used
2. AF_XDP DRV/Native mode
d. Bi-directional Sockets
* Only copy mode is supported because veth does not currently support
zero-copy mode
Signed-off-by: Weqaar Janjua <weqaar.a.janjua@intel.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Tested-by: Yonghong Song <yhs@fb.com>
Acked-by: Björn Töpel <bjorn.topel@intel.com>
Link: https://lore.kernel.org/bpf/20201207215333.11586-6-weqaar.a.janjua@intel.com
This commit is contained in:
parent
6674bf6656
commit
7d20441eb0
3 changed files with 104 additions and 24 deletions
|
|
@ -221,6 +221,30 @@ retval=$?
|
||||||
test_status $retval "${TEST_NAME}"
|
test_status $retval "${TEST_NAME}"
|
||||||
statusList+=($retval)
|
statusList+=($retval)
|
||||||
|
|
||||||
|
### TEST 8
|
||||||
|
TEST_NAME="SKB BIDIRECTIONAL SOCKETS"
|
||||||
|
|
||||||
|
vethXDPgeneric ${VETH0} ${VETH1} ${NS1}
|
||||||
|
|
||||||
|
params=("-S" "-B")
|
||||||
|
execxdpxceiver params
|
||||||
|
|
||||||
|
retval=$?
|
||||||
|
test_status $retval "${TEST_NAME}"
|
||||||
|
statusList+=($retval)
|
||||||
|
|
||||||
|
### TEST 9
|
||||||
|
TEST_NAME="DRV BIDIRECTIONAL SOCKETS"
|
||||||
|
|
||||||
|
vethXDPnative ${VETH0} ${VETH1} ${NS1}
|
||||||
|
|
||||||
|
params=("-N" "-B")
|
||||||
|
execxdpxceiver params
|
||||||
|
|
||||||
|
retval=$?
|
||||||
|
test_status $retval "${TEST_NAME}"
|
||||||
|
statusList+=($retval)
|
||||||
|
|
||||||
## END TESTS
|
## END TESTS
|
||||||
|
|
||||||
cleanup_exit ${VETH0} ${VETH1} ${NS1}
|
cleanup_exit ${VETH0} ${VETH1} ${NS1}
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,10 @@
|
||||||
* c. Socket Teardown
|
* c. Socket Teardown
|
||||||
* Create a Tx and a Rx socket, Tx from one socket, Rx on another. Destroy
|
* Create a Tx and a Rx socket, Tx from one socket, Rx on another. Destroy
|
||||||
* both sockets, then repeat multiple times. Only nopoll mode is used
|
* both sockets, then repeat multiple times. Only nopoll mode is used
|
||||||
|
* d. Bi-directional sockets
|
||||||
|
* Configure sockets as bi-directional tx/rx sockets, sets up fill and
|
||||||
|
* completion rings on each socket, tx/rx in both directions. Only nopoll
|
||||||
|
* mode is used
|
||||||
*
|
*
|
||||||
* 2. AF_XDP DRV/Native mode
|
* 2. AF_XDP DRV/Native mode
|
||||||
* Works on any netdevice with XDP_REDIRECT support, driver dependent. Processes
|
* Works on any netdevice with XDP_REDIRECT support, driver dependent. Processes
|
||||||
|
|
@ -37,10 +41,11 @@
|
||||||
* a. nopoll
|
* a. nopoll
|
||||||
* b. poll
|
* b. poll
|
||||||
* c. Socket Teardown
|
* c. Socket Teardown
|
||||||
|
* d. Bi-directional sockets
|
||||||
* - Only copy mode is supported because veth does not currently support
|
* - Only copy mode is supported because veth does not currently support
|
||||||
* zero-copy mode
|
* zero-copy mode
|
||||||
*
|
*
|
||||||
* Total tests: 6
|
* Total tests: 8
|
||||||
*
|
*
|
||||||
* Flow:
|
* Flow:
|
||||||
* -----
|
* -----
|
||||||
|
|
@ -101,8 +106,9 @@ 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 exit_with_error(error) __exit_with_error(error, __FILE__, __func__, __LINE__)
|
||||||
|
|
||||||
#define print_ksft_result(void)\
|
#define print_ksft_result(void)\
|
||||||
(ksft_test_result_pass("PASS: %s %s %s\n", uut ? "DRV" : "SKB", opt_poll ? "POLL" :\
|
(ksft_test_result_pass("PASS: %s %s %s%s\n", uut ? "DRV" : "SKB", opt_poll ? "POLL" :\
|
||||||
"NOPOLL", opt_teardown ? "Socket Teardown" : ""))
|
"NOPOLL", opt_teardown ? "Socket Teardown" : "",\
|
||||||
|
opt_bidi ? "Bi-directional Sockets" : ""))
|
||||||
|
|
||||||
static void pthread_init_mutex(void)
|
static void pthread_init_mutex(void)
|
||||||
{
|
{
|
||||||
|
|
@ -308,8 +314,13 @@ static int xsk_configure_socket(struct ifobject *ifobject)
|
||||||
cfg.xdp_flags = opt_xdp_flags;
|
cfg.xdp_flags = opt_xdp_flags;
|
||||||
cfg.bind_flags = opt_xdp_bind_flags;
|
cfg.bind_flags = opt_xdp_bind_flags;
|
||||||
|
|
||||||
rxr = (ifobject->fv.vector == rx) ? &ifobject->xsk->rx : NULL;
|
if (!opt_bidi) {
|
||||||
txr = (ifobject->fv.vector == tx) ? &ifobject->xsk->tx : NULL;
|
rxr = (ifobject->fv.vector == rx) ? &ifobject->xsk->rx : NULL;
|
||||||
|
txr = (ifobject->fv.vector == tx) ? &ifobject->xsk->tx : NULL;
|
||||||
|
} else {
|
||||||
|
rxr = &ifobject->xsk->rx;
|
||||||
|
txr = &ifobject->xsk->tx;
|
||||||
|
}
|
||||||
|
|
||||||
ret = xsk_socket__create(&ifobject->xsk->xsk, ifobject->ifname,
|
ret = xsk_socket__create(&ifobject->xsk->xsk, ifobject->ifname,
|
||||||
opt_queue, ifobject->umem->umem, rxr, txr, &cfg);
|
opt_queue, ifobject->umem->umem, rxr, txr, &cfg);
|
||||||
|
|
@ -328,6 +339,7 @@ static struct option long_options[] = {
|
||||||
{"xdp-native", no_argument, 0, 'N'},
|
{"xdp-native", no_argument, 0, 'N'},
|
||||||
{"copy", no_argument, 0, 'c'},
|
{"copy", no_argument, 0, 'c'},
|
||||||
{"tear-down", no_argument, 0, 'T'},
|
{"tear-down", no_argument, 0, 'T'},
|
||||||
|
{"bidi", optional_argument, 0, 'B'},
|
||||||
{"debug", optional_argument, 0, 'D'},
|
{"debug", optional_argument, 0, 'D'},
|
||||||
{"tx-pkt-count", optional_argument, 0, 'C'},
|
{"tx-pkt-count", optional_argument, 0, 'C'},
|
||||||
{0, 0, 0, 0}
|
{0, 0, 0, 0}
|
||||||
|
|
@ -345,6 +357,7 @@ static void usage(const char *prog)
|
||||||
" -N, --xdp-native=n Enforce XDP DRV (native) mode\n"
|
" -N, --xdp-native=n Enforce XDP DRV (native) mode\n"
|
||||||
" -c, --copy Force copy mode\n"
|
" -c, --copy Force copy mode\n"
|
||||||
" -T, --tear-down Tear down sockets by repeatedly recreating them\n"
|
" -T, --tear-down Tear down sockets by repeatedly recreating them\n"
|
||||||
|
" -B, --bidi Bi-directional sockets test\n"
|
||||||
" -D, --debug Debug mode - dump packets L2 - L5\n"
|
" -D, --debug Debug mode - dump packets L2 - L5\n"
|
||||||
" -C, --tx-pkt-count=n Number of packets to send\n";
|
" -C, --tx-pkt-count=n Number of packets to send\n";
|
||||||
ksft_print_msg(str, prog);
|
ksft_print_msg(str, prog);
|
||||||
|
|
@ -435,7 +448,7 @@ static void parse_command_line(int argc, char **argv)
|
||||||
opterr = 0;
|
opterr = 0;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
c = getopt_long(argc, argv, "i:q:pSNcTDC:", long_options, &option_index);
|
c = getopt_long(argc, argv, "i:q:pSNcTBDC:", long_options, &option_index);
|
||||||
|
|
||||||
if (c == -1)
|
if (c == -1)
|
||||||
break;
|
break;
|
||||||
|
|
@ -477,6 +490,9 @@ static void parse_command_line(int argc, char **argv)
|
||||||
case 'T':
|
case 'T':
|
||||||
opt_teardown = 1;
|
opt_teardown = 1;
|
||||||
break;
|
break;
|
||||||
|
case 'B':
|
||||||
|
opt_bidi = 1;
|
||||||
|
break;
|
||||||
case 'D':
|
case 'D':
|
||||||
debug_pkt_dump = 1;
|
debug_pkt_dump = 1;
|
||||||
break;
|
break;
|
||||||
|
|
@ -802,22 +818,25 @@ static void *worker_testapp_validate(void *arg)
|
||||||
struct generic_data *data = (struct generic_data *)malloc(sizeof(struct generic_data));
|
struct generic_data *data = (struct generic_data *)malloc(sizeof(struct generic_data));
|
||||||
struct iphdr *ip_hdr = (struct iphdr *)(pkt_data + sizeof(struct ethhdr));
|
struct iphdr *ip_hdr = (struct iphdr *)(pkt_data + sizeof(struct ethhdr));
|
||||||
struct ethhdr *eth_hdr = (struct ethhdr *)pkt_data;
|
struct ethhdr *eth_hdr = (struct ethhdr *)pkt_data;
|
||||||
void *bufs;
|
void *bufs = NULL;
|
||||||
|
|
||||||
pthread_attr_setstacksize(&attr, THREAD_STACK);
|
pthread_attr_setstacksize(&attr, THREAD_STACK);
|
||||||
|
|
||||||
bufs = mmap(NULL, num_frames * XSK_UMEM__DEFAULT_FRAME_SIZE,
|
if (!bidi_pass) {
|
||||||
PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
bufs = mmap(NULL, num_frames * XSK_UMEM__DEFAULT_FRAME_SIZE,
|
||||||
if (bufs == MAP_FAILED)
|
PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||||
exit_with_error(errno);
|
if (bufs == MAP_FAILED)
|
||||||
|
exit_with_error(errno);
|
||||||
|
|
||||||
if (strcmp(((struct ifobject *)arg)->nsname, ""))
|
if (strcmp(((struct ifobject *)arg)->nsname, ""))
|
||||||
switch_namespace(((struct ifobject *)arg)->ifdict_index);
|
switch_namespace(((struct ifobject *)arg)->ifdict_index);
|
||||||
|
}
|
||||||
|
|
||||||
if (((struct ifobject *)arg)->fv.vector == tx) {
|
if (((struct ifobject *)arg)->fv.vector == tx) {
|
||||||
int spinningrxctr = 0;
|
int spinningrxctr = 0;
|
||||||
|
|
||||||
thread_common_ops(arg, bufs, &sync_mutex_tx, &spinning_tx);
|
if (!bidi_pass)
|
||||||
|
thread_common_ops(arg, bufs, &sync_mutex_tx, &spinning_tx);
|
||||||
|
|
||||||
while (atomic_load(&spinning_rx) && spinningrxctr < SOCK_RECONF_CTR) {
|
while (atomic_load(&spinning_rx) && spinningrxctr < SOCK_RECONF_CTR) {
|
||||||
spinningrxctr++;
|
spinningrxctr++;
|
||||||
|
|
@ -847,7 +866,8 @@ static void *worker_testapp_validate(void *arg)
|
||||||
struct pollfd fds[MAX_SOCKS] = { };
|
struct pollfd fds[MAX_SOCKS] = { };
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
thread_common_ops(arg, bufs, &sync_mutex_tx, &spinning_rx);
|
if (!bidi_pass)
|
||||||
|
thread_common_ops(arg, bufs, &sync_mutex_tx, &spinning_rx);
|
||||||
|
|
||||||
ksft_print_msg("Interface [%s] vector [Rx]\n", ((struct ifobject *)arg)->ifname);
|
ksft_print_msg("Interface [%s] vector [Rx]\n", ((struct ifobject *)arg)->ifname);
|
||||||
xsk_populate_fill_ring(((struct ifobject *)arg)->umem);
|
xsk_populate_fill_ring(((struct ifobject *)arg)->umem);
|
||||||
|
|
@ -886,8 +906,10 @@ static void *worker_testapp_validate(void *arg)
|
||||||
ksft_print_msg("Destroying socket\n");
|
ksft_print_msg("Destroying socket\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
xsk_socket__delete(((struct ifobject *)arg)->xsk->xsk);
|
if (!opt_bidi || (opt_bidi && bidi_pass)) {
|
||||||
(void)xsk_umem__delete(((struct ifobject *)arg)->umem->umem);
|
xsk_socket__delete(((struct ifobject *)arg)->xsk->xsk);
|
||||||
|
(void)xsk_umem__delete(((struct ifobject *)arg)->umem->umem);
|
||||||
|
}
|
||||||
pthread_exit(NULL);
|
pthread_exit(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -896,11 +918,26 @@ static void testapp_validate(void)
|
||||||
pthread_attr_init(&attr);
|
pthread_attr_init(&attr);
|
||||||
pthread_attr_setstacksize(&attr, THREAD_STACK);
|
pthread_attr_setstacksize(&attr, THREAD_STACK);
|
||||||
|
|
||||||
|
if (opt_bidi && bidi_pass) {
|
||||||
|
pthread_init_mutex();
|
||||||
|
if (!switching_notify) {
|
||||||
|
ksft_print_msg("Switching Tx/Rx vectors\n");
|
||||||
|
switching_notify++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pthread_mutex_lock(&sync_mutex);
|
pthread_mutex_lock(&sync_mutex);
|
||||||
|
|
||||||
/*Spawn RX thread */
|
/*Spawn RX thread */
|
||||||
if (pthread_create(&t0, &attr, worker_testapp_validate, (void *)ifdict[1]))
|
if (!opt_bidi || (opt_bidi && !bidi_pass)) {
|
||||||
exit_with_error(errno);
|
if (pthread_create(&t0, &attr, worker_testapp_validate, (void *)ifdict[1]))
|
||||||
|
exit_with_error(errno);
|
||||||
|
} else if (opt_bidi && bidi_pass) {
|
||||||
|
/*switch Tx/Rx vectors */
|
||||||
|
ifdict[0]->fv.vector = rx;
|
||||||
|
if (pthread_create(&t0, &attr, worker_testapp_validate, (void *)ifdict[0]))
|
||||||
|
exit_with_error(errno);
|
||||||
|
}
|
||||||
|
|
||||||
struct timespec max_wait = { 0, 0 };
|
struct timespec max_wait = { 0, 0 };
|
||||||
|
|
||||||
|
|
@ -914,8 +951,15 @@ static void testapp_validate(void)
|
||||||
pthread_mutex_unlock(&sync_mutex);
|
pthread_mutex_unlock(&sync_mutex);
|
||||||
|
|
||||||
/*Spawn TX thread */
|
/*Spawn TX thread */
|
||||||
if (pthread_create(&t1, &attr, worker_testapp_validate, (void *)ifdict[0]))
|
if (!opt_bidi || (opt_bidi && !bidi_pass)) {
|
||||||
exit_with_error(errno);
|
if (pthread_create(&t1, &attr, worker_testapp_validate, (void *)ifdict[0]))
|
||||||
|
exit_with_error(errno);
|
||||||
|
} else if (opt_bidi && bidi_pass) {
|
||||||
|
/*switch Tx/Rx vectors */
|
||||||
|
ifdict[1]->fv.vector = tx;
|
||||||
|
if (pthread_create(&t1, &attr, worker_testapp_validate, (void *)ifdict[1]))
|
||||||
|
exit_with_error(errno);
|
||||||
|
}
|
||||||
|
|
||||||
pthread_join(t1, NULL);
|
pthread_join(t1, NULL);
|
||||||
pthread_join(t0, NULL);
|
pthread_join(t0, NULL);
|
||||||
|
|
@ -929,18 +973,19 @@ static void testapp_validate(void)
|
||||||
free(pkt_buf);
|
free(pkt_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!opt_teardown)
|
if (!opt_teardown && !opt_bidi)
|
||||||
print_ksft_result();
|
print_ksft_result();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void testapp_sockets(void)
|
static void testapp_sockets(void)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < MAX_TEARDOWN_ITER; i++) {
|
for (int i = 0; i < (opt_teardown ? MAX_TEARDOWN_ITER : MAX_BIDI_ITER); i++) {
|
||||||
pkt_counter = 0;
|
pkt_counter = 0;
|
||||||
prev_pkt = -1;
|
prev_pkt = -1;
|
||||||
sigvar = 0;
|
sigvar = 0;
|
||||||
ksft_print_msg("Creating socket\n");
|
ksft_print_msg("Creating socket\n");
|
||||||
testapp_validate();
|
testapp_validate();
|
||||||
|
opt_bidi ? bidi_pass++ : bidi_pass;
|
||||||
}
|
}
|
||||||
|
|
||||||
print_ksft_result();
|
print_ksft_result();
|
||||||
|
|
@ -1009,7 +1054,14 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
ksft_set_plan(1);
|
ksft_set_plan(1);
|
||||||
|
|
||||||
opt_teardown ? testapp_sockets() : testapp_validate();
|
if (!opt_teardown && !opt_bidi) {
|
||||||
|
testapp_validate();
|
||||||
|
} else if (opt_teardown && opt_bidi) {
|
||||||
|
ksft_test_result_fail("ERROR: parameters -T and -B cannot be used together\n");
|
||||||
|
ksft_exit_xfail();
|
||||||
|
} else {
|
||||||
|
testapp_sockets();
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < MAX_INTERFACES; i++)
|
for (int i = 0; i < MAX_INTERFACES; i++)
|
||||||
free(ifdict[i]);
|
free(ifdict[i]);
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
#define MAX_INTERFACES_NAMESPACE_CHARS 10
|
#define MAX_INTERFACES_NAMESPACE_CHARS 10
|
||||||
#define MAX_SOCKS 1
|
#define MAX_SOCKS 1
|
||||||
#define MAX_TEARDOWN_ITER 10
|
#define MAX_TEARDOWN_ITER 10
|
||||||
|
#define MAX_BIDI_ITER 2
|
||||||
#define PKT_HDR_SIZE (sizeof(struct ethhdr) + sizeof(struct iphdr) + \
|
#define PKT_HDR_SIZE (sizeof(struct ethhdr) + sizeof(struct iphdr) + \
|
||||||
sizeof(struct udphdr))
|
sizeof(struct udphdr))
|
||||||
#define MIN_PKT_SIZE 64
|
#define MIN_PKT_SIZE 64
|
||||||
|
|
@ -53,12 +54,15 @@ enum TESTS {
|
||||||
u8 uut;
|
u8 uut;
|
||||||
u8 debug_pkt_dump;
|
u8 debug_pkt_dump;
|
||||||
u32 num_frames;
|
u32 num_frames;
|
||||||
|
u8 switching_notify;
|
||||||
|
u8 bidi_pass;
|
||||||
|
|
||||||
static u32 opt_xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
|
static u32 opt_xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
|
||||||
static int opt_queue;
|
static int opt_queue;
|
||||||
static int opt_pkt_count;
|
static int opt_pkt_count;
|
||||||
static int opt_poll;
|
static int opt_poll;
|
||||||
static int opt_teardown;
|
static int opt_teardown;
|
||||||
|
static int opt_bidi;
|
||||||
static u32 opt_xdp_bind_flags = XDP_USE_NEED_WAKEUP;
|
static u32 opt_xdp_bind_flags = XDP_USE_NEED_WAKEUP;
|
||||||
static u8 pkt_data[XSK_UMEM__DEFAULT_FRAME_SIZE];
|
static u8 pkt_data[XSK_UMEM__DEFAULT_FRAME_SIZE];
|
||||||
static u32 pkt_counter;
|
static u32 pkt_counter;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue