selftests: ncdevmem: Separate out dmabuf provider
[ Upstream commit 8b9049af8066b4705d83bb7847ee3c960fc58d09 ] So we can plug the other ones in the future if needed. Reviewed-by: Mina Almasry <almasrymina@google.com> Reviewed-by: Joe Damato <jdamato@fastly.com> Signed-off-by: Stanislav Fomichev <sdf@fomichev.me> Link: https://patch.msgid.link/20241107181211.3934153-3-sdf@fomichev.me Signed-off-by: Jakub Kicinski <kuba@kernel.org> Stable-dep-of: 97c4e094a4b2 ("tests/ncdevmem: Fix double-free of queue array") Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
f3380d119f
commit
eb15f4f380
@@ -71,17 +71,101 @@ static char *ifname = "eth1";
|
|||||||
static unsigned int ifindex;
|
static unsigned int ifindex;
|
||||||
static unsigned int dmabuf_id;
|
static unsigned int dmabuf_id;
|
||||||
|
|
||||||
void print_bytes(void *ptr, size_t size)
|
struct memory_buffer {
|
||||||
{
|
int fd;
|
||||||
unsigned char *p = ptr;
|
size_t size;
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < size; i++)
|
int devfd;
|
||||||
printf("%02hhX ", p[i]);
|
int memfd;
|
||||||
printf("\n");
|
char *buf_mem;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct memory_provider {
|
||||||
|
struct memory_buffer *(*alloc)(size_t size);
|
||||||
|
void (*free)(struct memory_buffer *ctx);
|
||||||
|
void (*memcpy_from_device)(void *dst, struct memory_buffer *src,
|
||||||
|
size_t off, int n);
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct memory_buffer *udmabuf_alloc(size_t size)
|
||||||
|
{
|
||||||
|
struct udmabuf_create create;
|
||||||
|
struct memory_buffer *ctx;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ctx = malloc(sizeof(*ctx));
|
||||||
|
if (!ctx)
|
||||||
|
error(1, ENOMEM, "malloc failed");
|
||||||
|
|
||||||
|
ctx->size = size;
|
||||||
|
|
||||||
|
ctx->devfd = open("/dev/udmabuf", O_RDWR);
|
||||||
|
if (ctx->devfd < 0)
|
||||||
|
error(1, errno,
|
||||||
|
"%s: [skip,no-udmabuf: Unable to access DMA buffer device file]\n",
|
||||||
|
TEST_PREFIX);
|
||||||
|
|
||||||
|
ctx->memfd = memfd_create("udmabuf-test", MFD_ALLOW_SEALING);
|
||||||
|
if (ctx->memfd < 0)
|
||||||
|
error(1, errno, "%s: [skip,no-memfd]\n", TEST_PREFIX);
|
||||||
|
|
||||||
|
ret = fcntl(ctx->memfd, F_ADD_SEALS, F_SEAL_SHRINK);
|
||||||
|
if (ret < 0)
|
||||||
|
error(1, errno, "%s: [skip,fcntl-add-seals]\n", TEST_PREFIX);
|
||||||
|
|
||||||
|
ret = ftruncate(ctx->memfd, size);
|
||||||
|
if (ret == -1)
|
||||||
|
error(1, errno, "%s: [FAIL,memfd-truncate]\n", TEST_PREFIX);
|
||||||
|
|
||||||
|
memset(&create, 0, sizeof(create));
|
||||||
|
|
||||||
|
create.memfd = ctx->memfd;
|
||||||
|
create.offset = 0;
|
||||||
|
create.size = size;
|
||||||
|
ctx->fd = ioctl(ctx->devfd, UDMABUF_CREATE, &create);
|
||||||
|
if (ctx->fd < 0)
|
||||||
|
error(1, errno, "%s: [FAIL, create udmabuf]\n", TEST_PREFIX);
|
||||||
|
|
||||||
|
ctx->buf_mem = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED,
|
||||||
|
ctx->fd, 0);
|
||||||
|
if (ctx->buf_mem == MAP_FAILED)
|
||||||
|
error(1, errno, "%s: [FAIL, map udmabuf]\n", TEST_PREFIX);
|
||||||
|
|
||||||
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_nonzero_bytes(void *ptr, size_t size)
|
static void udmabuf_free(struct memory_buffer *ctx)
|
||||||
|
{
|
||||||
|
munmap(ctx->buf_mem, ctx->size);
|
||||||
|
close(ctx->fd);
|
||||||
|
close(ctx->memfd);
|
||||||
|
close(ctx->devfd);
|
||||||
|
free(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void udmabuf_memcpy_from_device(void *dst, struct memory_buffer *src,
|
||||||
|
size_t off, int n)
|
||||||
|
{
|
||||||
|
struct dma_buf_sync sync = {};
|
||||||
|
|
||||||
|
sync.flags = DMA_BUF_SYNC_START;
|
||||||
|
ioctl(src->fd, DMA_BUF_IOCTL_SYNC, &sync);
|
||||||
|
|
||||||
|
memcpy(dst, src->buf_mem + off, n);
|
||||||
|
|
||||||
|
sync.flags = DMA_BUF_SYNC_END;
|
||||||
|
ioctl(src->fd, DMA_BUF_IOCTL_SYNC, &sync);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct memory_provider udmabuf_memory_provider = {
|
||||||
|
.alloc = udmabuf_alloc,
|
||||||
|
.free = udmabuf_free,
|
||||||
|
.memcpy_from_device = udmabuf_memcpy_from_device,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct memory_provider *provider = &udmabuf_memory_provider;
|
||||||
|
|
||||||
|
static void print_nonzero_bytes(void *ptr, size_t size)
|
||||||
{
|
{
|
||||||
unsigned char *p = ptr;
|
unsigned char *p = ptr;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
@@ -201,42 +285,7 @@ err_close:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void create_udmabuf(int *devfd, int *memfd, int *buf, size_t dmabuf_size)
|
int do_server(struct memory_buffer *mem)
|
||||||
{
|
|
||||||
struct udmabuf_create create;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
*devfd = open("/dev/udmabuf", O_RDWR);
|
|
||||||
if (*devfd < 0) {
|
|
||||||
error(70, 0,
|
|
||||||
"%s: [skip,no-udmabuf: Unable to access DMA buffer device file]\n",
|
|
||||||
TEST_PREFIX);
|
|
||||||
}
|
|
||||||
|
|
||||||
*memfd = memfd_create("udmabuf-test", MFD_ALLOW_SEALING);
|
|
||||||
if (*memfd < 0)
|
|
||||||
error(70, 0, "%s: [skip,no-memfd]\n", TEST_PREFIX);
|
|
||||||
|
|
||||||
/* Required for udmabuf */
|
|
||||||
ret = fcntl(*memfd, F_ADD_SEALS, F_SEAL_SHRINK);
|
|
||||||
if (ret < 0)
|
|
||||||
error(73, 0, "%s: [skip,fcntl-add-seals]\n", TEST_PREFIX);
|
|
||||||
|
|
||||||
ret = ftruncate(*memfd, dmabuf_size);
|
|
||||||
if (ret == -1)
|
|
||||||
error(74, 0, "%s: [FAIL,memfd-truncate]\n", TEST_PREFIX);
|
|
||||||
|
|
||||||
memset(&create, 0, sizeof(create));
|
|
||||||
|
|
||||||
create.memfd = *memfd;
|
|
||||||
create.offset = 0;
|
|
||||||
create.size = dmabuf_size;
|
|
||||||
*buf = ioctl(*devfd, UDMABUF_CREATE, &create);
|
|
||||||
if (*buf < 0)
|
|
||||||
error(75, 0, "%s: [FAIL, create udmabuf]\n", TEST_PREFIX);
|
|
||||||
}
|
|
||||||
|
|
||||||
int do_server(void)
|
|
||||||
{
|
{
|
||||||
char ctrl_data[sizeof(int) * 20000];
|
char ctrl_data[sizeof(int) * 20000];
|
||||||
struct netdev_queue_id *queues;
|
struct netdev_queue_id *queues;
|
||||||
@@ -244,23 +293,18 @@ int do_server(void)
|
|||||||
struct sockaddr_in client_addr;
|
struct sockaddr_in client_addr;
|
||||||
struct sockaddr_in server_sin;
|
struct sockaddr_in server_sin;
|
||||||
size_t page_aligned_frags = 0;
|
size_t page_aligned_frags = 0;
|
||||||
int devfd, memfd, buf, ret;
|
|
||||||
size_t total_received = 0;
|
size_t total_received = 0;
|
||||||
socklen_t client_addr_len;
|
socklen_t client_addr_len;
|
||||||
bool is_devmem = false;
|
bool is_devmem = false;
|
||||||
char *buf_mem = NULL;
|
char *tmp_mem = NULL;
|
||||||
struct ynl_sock *ys;
|
struct ynl_sock *ys;
|
||||||
size_t dmabuf_size;
|
|
||||||
char iobuf[819200];
|
char iobuf[819200];
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
int socket_fd;
|
int socket_fd;
|
||||||
int client_fd;
|
int client_fd;
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
int opt = 1;
|
int opt = 1;
|
||||||
|
int ret;
|
||||||
dmabuf_size = getpagesize() * NUM_PAGES;
|
|
||||||
|
|
||||||
create_udmabuf(&devfd, &memfd, &buf, dmabuf_size);
|
|
||||||
|
|
||||||
if (reset_flow_steering())
|
if (reset_flow_steering())
|
||||||
error(1, 0, "Failed to reset flow steering\n");
|
error(1, 0, "Failed to reset flow steering\n");
|
||||||
@@ -284,13 +328,12 @@ int do_server(void)
|
|||||||
queues[i].id = start_queue + i;
|
queues[i].id = start_queue + i;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bind_rx_queue(ifindex, buf, queues, num_queues, &ys))
|
if (bind_rx_queue(ifindex, mem->fd, queues, num_queues, &ys))
|
||||||
error(1, 0, "Failed to bind\n");
|
error(1, 0, "Failed to bind\n");
|
||||||
|
|
||||||
buf_mem = mmap(NULL, dmabuf_size, PROT_READ | PROT_WRITE, MAP_SHARED,
|
tmp_mem = malloc(mem->size);
|
||||||
buf, 0);
|
if (!tmp_mem)
|
||||||
if (buf_mem == MAP_FAILED)
|
error(1, ENOMEM, "malloc failed");
|
||||||
error(1, 0, "mmap()");
|
|
||||||
|
|
||||||
server_sin.sin_family = AF_INET;
|
server_sin.sin_family = AF_INET;
|
||||||
server_sin.sin_port = htons(atoi(port));
|
server_sin.sin_port = htons(atoi(port));
|
||||||
@@ -341,7 +384,6 @@ int do_server(void)
|
|||||||
struct iovec iov = { .iov_base = iobuf,
|
struct iovec iov = { .iov_base = iobuf,
|
||||||
.iov_len = sizeof(iobuf) };
|
.iov_len = sizeof(iobuf) };
|
||||||
struct dmabuf_cmsg *dmabuf_cmsg = NULL;
|
struct dmabuf_cmsg *dmabuf_cmsg = NULL;
|
||||||
struct dma_buf_sync sync = { 0 };
|
|
||||||
struct cmsghdr *cm = NULL;
|
struct cmsghdr *cm = NULL;
|
||||||
struct msghdr msg = { 0 };
|
struct msghdr msg = { 0 };
|
||||||
struct dmabuf_token token;
|
struct dmabuf_token token;
|
||||||
@@ -410,22 +452,16 @@ int do_server(void)
|
|||||||
else
|
else
|
||||||
page_aligned_frags++;
|
page_aligned_frags++;
|
||||||
|
|
||||||
sync.flags = DMA_BUF_SYNC_READ | DMA_BUF_SYNC_START;
|
provider->memcpy_from_device(tmp_mem, mem,
|
||||||
ioctl(buf, DMA_BUF_IOCTL_SYNC, &sync);
|
dmabuf_cmsg->frag_offset,
|
||||||
|
dmabuf_cmsg->frag_size);
|
||||||
|
|
||||||
if (do_validation)
|
if (do_validation)
|
||||||
validate_buffer(
|
validate_buffer(tmp_mem,
|
||||||
((unsigned char *)buf_mem) +
|
dmabuf_cmsg->frag_size);
|
||||||
dmabuf_cmsg->frag_offset,
|
|
||||||
dmabuf_cmsg->frag_size);
|
|
||||||
else
|
else
|
||||||
print_nonzero_bytes(
|
print_nonzero_bytes(tmp_mem,
|
||||||
((unsigned char *)buf_mem) +
|
dmabuf_cmsg->frag_size);
|
||||||
dmabuf_cmsg->frag_offset,
|
|
||||||
dmabuf_cmsg->frag_size);
|
|
||||||
|
|
||||||
sync.flags = DMA_BUF_SYNC_READ | DMA_BUF_SYNC_END;
|
|
||||||
ioctl(buf, DMA_BUF_IOCTL_SYNC, &sync);
|
|
||||||
|
|
||||||
ret = setsockopt(client_fd, SOL_SOCKET,
|
ret = setsockopt(client_fd, SOL_SOCKET,
|
||||||
SO_DEVMEM_DONTNEED, &token,
|
SO_DEVMEM_DONTNEED, &token,
|
||||||
@@ -450,12 +486,9 @@ int do_server(void)
|
|||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
|
|
||||||
munmap(buf_mem, dmabuf_size);
|
free(tmp_mem);
|
||||||
close(client_fd);
|
close(client_fd);
|
||||||
close(socket_fd);
|
close(socket_fd);
|
||||||
close(buf);
|
|
||||||
close(memfd);
|
|
||||||
close(devfd);
|
|
||||||
ynl_sock_destroy(ys);
|
ynl_sock_destroy(ys);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -464,14 +497,11 @@ cleanup:
|
|||||||
void run_devmem_tests(void)
|
void run_devmem_tests(void)
|
||||||
{
|
{
|
||||||
struct netdev_queue_id *queues;
|
struct netdev_queue_id *queues;
|
||||||
int devfd, memfd, buf;
|
struct memory_buffer *mem;
|
||||||
struct ynl_sock *ys;
|
struct ynl_sock *ys;
|
||||||
size_t dmabuf_size;
|
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
|
|
||||||
dmabuf_size = getpagesize() * NUM_PAGES;
|
mem = provider->alloc(getpagesize() * NUM_PAGES);
|
||||||
|
|
||||||
create_udmabuf(&devfd, &memfd, &buf, dmabuf_size);
|
|
||||||
|
|
||||||
/* Configure RSS to divert all traffic from our devmem queues */
|
/* Configure RSS to divert all traffic from our devmem queues */
|
||||||
if (configure_rss())
|
if (configure_rss())
|
||||||
@@ -482,7 +512,7 @@ void run_devmem_tests(void)
|
|||||||
if (configure_headersplit(1))
|
if (configure_headersplit(1))
|
||||||
error(1, 0, "Failed to configure header split\n");
|
error(1, 0, "Failed to configure header split\n");
|
||||||
|
|
||||||
if (!bind_rx_queue(ifindex, buf, queues, num_queues, &ys))
|
if (!bind_rx_queue(ifindex, mem->fd, queues, num_queues, &ys))
|
||||||
error(1, 0, "Binding empty queues array should have failed\n");
|
error(1, 0, "Binding empty queues array should have failed\n");
|
||||||
|
|
||||||
for (i = 0; i < num_queues; i++) {
|
for (i = 0; i < num_queues; i++) {
|
||||||
@@ -495,7 +525,7 @@ void run_devmem_tests(void)
|
|||||||
if (configure_headersplit(0))
|
if (configure_headersplit(0))
|
||||||
error(1, 0, "Failed to configure header split\n");
|
error(1, 0, "Failed to configure header split\n");
|
||||||
|
|
||||||
if (!bind_rx_queue(ifindex, buf, queues, num_queues, &ys))
|
if (!bind_rx_queue(ifindex, mem->fd, queues, num_queues, &ys))
|
||||||
error(1, 0, "Configure dmabuf with header split off should have failed\n");
|
error(1, 0, "Configure dmabuf with header split off should have failed\n");
|
||||||
|
|
||||||
if (configure_headersplit(1))
|
if (configure_headersplit(1))
|
||||||
@@ -508,7 +538,7 @@ void run_devmem_tests(void)
|
|||||||
queues[i].id = start_queue + i;
|
queues[i].id = start_queue + i;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bind_rx_queue(ifindex, buf, queues, num_queues, &ys))
|
if (bind_rx_queue(ifindex, mem->fd, queues, num_queues, &ys))
|
||||||
error(1, 0, "Failed to bind\n");
|
error(1, 0, "Failed to bind\n");
|
||||||
|
|
||||||
/* Deactivating a bound queue should not be legal */
|
/* Deactivating a bound queue should not be legal */
|
||||||
@@ -517,11 +547,15 @@ void run_devmem_tests(void)
|
|||||||
|
|
||||||
/* Closing the netlink socket does an implicit unbind */
|
/* Closing the netlink socket does an implicit unbind */
|
||||||
ynl_sock_destroy(ys);
|
ynl_sock_destroy(ys);
|
||||||
|
|
||||||
|
provider->free(mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
struct memory_buffer *mem;
|
||||||
int is_server = 0, opt;
|
int is_server = 0, opt;
|
||||||
|
int ret;
|
||||||
|
|
||||||
while ((opt = getopt(argc, argv, "ls:c:p:v:q:t:f:")) != -1) {
|
while ((opt = getopt(argc, argv, "ls:c:p:v:q:t:f:")) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
@@ -562,8 +596,9 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
run_devmem_tests();
|
run_devmem_tests();
|
||||||
|
|
||||||
if (is_server)
|
mem = provider->alloc(getpagesize() * NUM_PAGES);
|
||||||
return do_server();
|
ret = is_server ? do_server(mem) : 1;
|
||||||
|
provider->free(mem);
|
||||||
|
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user