Commit 7d20441e authored by Weqaar Janjua's avatar Weqaar Janjua Committed by Daniel Borkmann

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: default avatarWeqaar Janjua <weqaar.a.janjua@intel.com>
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Tested-by: default avatarYonghong Song <yhs@fb.com>
Acked-by: default avatarBjörn Töpel <bjorn.topel@intel.com>
Link: https://lore.kernel.org/bpf/20201207215333.11586-6-weqaar.a.janjua@intel.com
parent 6674bf66
...@@ -221,6 +221,30 @@ retval=$? ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 ...@@ -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) ...@@ -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;
if (!opt_bidi) {
rxr = (ifobject->fv.vector == rx) ? &ifobject->xsk->rx : NULL; rxr = (ifobject->fv.vector == rx) ? &ifobject->xsk->rx : NULL;
txr = (ifobject->fv.vector == tx) ? &ifobject->xsk->tx : 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[] = { ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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,10 +818,11 @@ static void *worker_testapp_validate(void *arg) ...@@ -802,10 +818,11 @@ 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);
if (!bidi_pass) {
bufs = mmap(NULL, num_frames * XSK_UMEM__DEFAULT_FRAME_SIZE, bufs = mmap(NULL, num_frames * XSK_UMEM__DEFAULT_FRAME_SIZE,
PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (bufs == MAP_FAILED) if (bufs == MAP_FAILED)
...@@ -813,10 +830,12 @@ static void *worker_testapp_validate(void *arg) ...@@ -813,10 +830,12 @@ static void *worker_testapp_validate(void *arg)
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;
if (!bidi_pass)
thread_common_ops(arg, bufs, &sync_mutex_tx, &spinning_tx); 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) {
...@@ -847,6 +866,7 @@ static void *worker_testapp_validate(void *arg) ...@@ -847,6 +866,7 @@ static void *worker_testapp_validate(void *arg)
struct pollfd fds[MAX_SOCKS] = { }; struct pollfd fds[MAX_SOCKS] = { };
int ret; int ret;
if (!bidi_pass)
thread_common_ops(arg, bufs, &sync_mutex_tx, &spinning_rx); 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);
...@@ -886,8 +906,10 @@ static void *worker_testapp_validate(void *arg) ...@@ -886,8 +906,10 @@ static void *worker_testapp_validate(void *arg)
ksft_print_msg("Destroying socket\n"); ksft_print_msg("Destroying socket\n");
} }
if (!opt_bidi || (opt_bidi && bidi_pass)) {
xsk_socket__delete(((struct ifobject *)arg)->xsk->xsk); xsk_socket__delete(((struct ifobject *)arg)->xsk->xsk);
(void)xsk_umem__delete(((struct ifobject *)arg)->umem->umem); (void)xsk_umem__delete(((struct ifobject *)arg)->umem->umem);
}
pthread_exit(NULL); pthread_exit(NULL);
} }
...@@ -896,11 +918,26 @@ static void testapp_validate(void) ...@@ -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 (!opt_bidi || (opt_bidi && !bidi_pass)) {
if (pthread_create(&t0, &attr, worker_testapp_validate, (void *)ifdict[1])) if (pthread_create(&t0, &attr, worker_testapp_validate, (void *)ifdict[1]))
exit_with_error(errno); 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) ...@@ -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 (!opt_bidi || (opt_bidi && !bidi_pass)) {
if (pthread_create(&t1, &attr, worker_testapp_validate, (void *)ifdict[0])) if (pthread_create(&t1, &attr, worker_testapp_validate, (void *)ifdict[0]))
exit_with_error(errno); 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) ...@@ -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) ...@@ -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 @@ ...@@ -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 { ...@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment