From nobody Sun Dec 22 08:17:56 2024 Received: from mail-pg1-f201.google.com (mail-pg1-f201.google.com [209.85.215.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 03C5A27453 for ; Sat, 21 Dec 2024 00:51:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734742300; cv=none; b=RSEVff0FmuwMBqeidkVVjijx4Q71eiaop24ocv4aDK9EN0d3UBT6L1F9OSerApoj0ceVReYx0Wtt6LiiqXnbh9nsSnXb0/U+O7SksMqbxcVh5SD9OAFLcLVBgodXh4npKNOf3JDKJtTM3jIbGCLynymDSdyr8JPdOo8L5nMRwmY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734742300; c=relaxed/simple; bh=oM9VPB9o+HoOhFQ2jKZEYqU0zOMOqiBju5kW7kCY7hk=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=TYdyu/8Dh+gGW+ap9vB0V10dAuIQ5Zsl6VsmT5dmL2rWLSiFNUgNGOCpbMNq314BCh7MSQdzDAuLo3XlUvaAENWilKXjHMy6yebBP7o1Aq6zazL4oXKlM6q+/kKucI/tBPaj89Wn3j9EJ05LobBSWD2dDMYb61Qb6yMiUwUWPxg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--almasrymina.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=LZvVG6xt; arc=none smtp.client-ip=209.85.215.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--almasrymina.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="LZvVG6xt" Received: by mail-pg1-f201.google.com with SMTP id 41be03b00d2f7-7fcb7afb4e1so2450283a12.0 for ; Fri, 20 Dec 2024 16:51:37 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1734742297; x=1735347097; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=wvRhxm0PfanRMhR9AWSahUuI027dbnG0NIDTqQqY9zM=; b=LZvVG6xt17QgIKJq9ytXGwuWgp0dYkwSuYljJriPi30A22etdSyik1HzkoV/S26EEC 5FijQR0h1LG04lz7rSLrjPLDnh9eotBwb2vxEZNTX08GymJDa6iiFX1H7kx5tzORUQtQ tdyCNGPddSJw91kA0r1LjVPgIZkZO2B2rfdxeaYKBj8UL/OsLpQZrBxkeG/2/8SW+T6g mz3NQUBpIoR6RY4OXMHfKc2A2g56LSXpFb8mXhF/ue1fqkxLNJBJ4WUHW3kqfNwQRSqB HaSCszZJyW3KL5zqM80YDFgDtobgbRUlzyjo0ArTcwYL2VDZW3zlCaoTYHLNzfI5W3D6 7rTg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1734742297; x=1735347097; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=wvRhxm0PfanRMhR9AWSahUuI027dbnG0NIDTqQqY9zM=; b=UqshcmsIyye/YjKqCP+fOONiOE04/C57oNIza6miGjyp16VUGBxK8nfy0UhPBvCt8C rL2kfD6mnncBBlJEt4k9MjLD3Ju7n4iwsuar+kbdmh6fXNP00o+VmluHv0S/cbueprV2 uJ616crozeLGGUSRfNhepLd35zMagyXpl6IHvjcNmnXNXIVkVxC3NFzxINaKVyqtZlG0 zsXt9lbfS2Ltq3dB/dRMc30wc0I1TbNOSY1gVyFSprWGEtJh+5FqUORz6Frr791mJkSd uENCPW6XxGT7gi+uAFDhxv0jlZOWQNbxYrTUyWNHEZ9YzwyuZeXqnhg1FmFhXzoo+QQ6 bXVQ== X-Forwarded-Encrypted: i=1; AJvYcCUfv0S2yAZDM7gyyUdTjciPUGXBxtFmOlBx1X4NbcOB9uVzMtuGSa/HrjXOKTP8seruLY1WCCJntPRuTdA=@vger.kernel.org X-Gm-Message-State: AOJu0YxTv7kdIkQXMYBxi10irthQ5d9ZhUs2fA2iUosi0dASWSaYLjZZ Krmz6vk2mrU7lOLxm/s4YJ3ZM4j2QgN5N3dDCFUIyQZ7qt/x8abmKJxfZE/dKliT54HFQ3/89SW nFCjq+ZLV2gSNj/G8CGxknQ== X-Google-Smtp-Source: AGHT+IE9+UzLSddcELfZ2mgl0mh/RGerBHIeMvNiWYQCp1XxXSrcI+ut917KM8tfbtPFabOJFM2yXHBxSI1aokLf1g== X-Received: from pgwb8.prod.google.com ([2002:a65:6688:0:b0:801:e378:a64a]) (user=almasrymina job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a21:3115:b0:1e1:aef4:9cd0 with SMTP id adf61e73a8af0-1e5e044e423mr8605246637.3.1734742297348; Fri, 20 Dec 2024 16:51:37 -0800 (PST) Date: Sat, 21 Dec 2024 00:42:33 +0000 In-Reply-To: <20241221004236.2629280-1-almasrymina@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20241221004236.2629280-1-almasrymina@google.com> X-Mailer: git-send-email 2.47.1.613.gc27f4b7a9f-goog Message-ID: <20241221004236.2629280-3-almasrymina@google.com> Subject: [PATCH RFC net-next v1 2/5] selftests: ncdevmem: Implement devmem TCP TX From: Mina Almasry To: netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, virtualization@lists.linux.dev, kvm@vger.kernel.org, linux-kselftest@vger.kernel.org Cc: Mina Almasry , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Donald Hunter , Jonathan Corbet , Andrew Lunn , David Ahern , "Michael S. Tsirkin" , Jason Wang , Xuan Zhuo , "=?UTF-8?q?Eugenio=20P=C3=A9rez?=" , Stefan Hajnoczi , Stefano Garzarella , Shuah Khan , Kaiyuan Zhang , Pavel Begunkov , Willem de Bruijn , Samiullah Khawaja , Stanislav Fomichev , Joe Damato , dw@davidwei.uk Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add support for devmem TX in ncdevmem. This is a combination of the ncdevmem from the devmem TCP series RFCv1 which included the TX path, and work by Stan to include the netlink API and refactored on top of his generic memory_provider support. Signed-off-by: Mina Almasry Signed-off-by: Stanislav Fomichev --- .../selftests/drivers/net/hw/ncdevmem.c | 261 +++++++++++++++++- 1 file changed, 259 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/drivers/net/hw/ncdevmem.c b/tools/test= ing/selftests/drivers/net/hw/ncdevmem.c index 19a6969643f4..c1cbe2e11230 100644 --- a/tools/testing/selftests/drivers/net/hw/ncdevmem.c +++ b/tools/testing/selftests/drivers/net/hw/ncdevmem.c @@ -40,15 +40,18 @@ #include #include #include +#include =20 #include #include #include #include #include +#include =20 #include #include +#include #include #include #include @@ -80,6 +83,8 @@ static int num_queues =3D -1; static char *ifname; static unsigned int ifindex; static unsigned int dmabuf_id; +static uint32_t tx_dmabuf_id; +static int waittime_ms =3D 500; =20 struct memory_buffer { int fd; @@ -93,6 +98,8 @@ struct memory_buffer { struct memory_provider { struct memory_buffer *(*alloc)(size_t size); void (*free)(struct memory_buffer *ctx); + void (*memcpy_to_device)(struct memory_buffer *dst, size_t off, + void *src, int n); void (*memcpy_from_device)(void *dst, struct memory_buffer *src, size_t off, int n); }; @@ -153,6 +160,20 @@ static void udmabuf_free(struct memory_buffer *ctx) free(ctx); } =20 +static void udmabuf_memcpy_to_device(struct memory_buffer *dst, size_t off, + void *src, int n) +{ + struct dma_buf_sync sync =3D {}; + + sync.flags =3D DMA_BUF_SYNC_START | DMA_BUF_SYNC_WRITE; + ioctl(dst->fd, DMA_BUF_IOCTL_SYNC, &sync); + + memcpy(dst->buf_mem + off, src, n); + + sync.flags =3D DMA_BUF_SYNC_END | DMA_BUF_SYNC_WRITE; + ioctl(dst->fd, DMA_BUF_IOCTL_SYNC, &sync); +} + static void udmabuf_memcpy_from_device(void *dst, struct memory_buffer *sr= c, size_t off, int n) { @@ -170,6 +191,7 @@ static void udmabuf_memcpy_from_device(void *dst, struc= t memory_buffer *src, static struct memory_provider udmabuf_memory_provider =3D { .alloc =3D udmabuf_alloc, .free =3D udmabuf_free, + .memcpy_to_device =3D udmabuf_memcpy_to_device, .memcpy_from_device =3D udmabuf_memcpy_from_device, }; =20 @@ -394,6 +416,49 @@ static int bind_rx_queue(unsigned int ifindex, unsigne= d int dmabuf_fd, return -1; } =20 +static int bind_tx_queue(unsigned int ifindex, unsigned int dmabuf_fd, + struct ynl_sock **ys) +{ + struct netdev_bind_tx_req *req =3D NULL; + struct netdev_bind_tx_rsp *rsp =3D NULL; + struct ynl_error yerr; + + *ys =3D ynl_sock_create(&ynl_netdev_family, &yerr); + if (!*ys) { + fprintf(stderr, "YNL: %s\n", yerr.msg); + return -1; + } + + req =3D netdev_bind_tx_req_alloc(); + netdev_bind_tx_req_set_ifindex(req, ifindex); + netdev_bind_tx_req_set_fd(req, dmabuf_fd); + + rsp =3D netdev_bind_tx(*ys, req); + if (!rsp) { + perror("netdev_bind_tx"); + goto err_close; + } + + if (!rsp->_present.id) { + perror("id not present"); + goto err_close; + } + + fprintf(stderr, "got tx dmabuf id=3D%d\n", rsp->id); + tx_dmabuf_id =3D rsp->id; + + netdev_bind_tx_req_free(req); + netdev_bind_tx_rsp_free(rsp); + + return 0; + +err_close: + fprintf(stderr, "YNL failed: %s\n", (*ys)->err.msg); + netdev_bind_tx_req_free(req); + ynl_sock_destroy(*ys); + return -1; +} + static void enable_reuseaddr(int fd) { int opt =3D 1; @@ -432,7 +497,7 @@ static int parse_address(const char *str, int port, str= uct sockaddr_in6 *sin6) return 0; } =20 -int do_server(struct memory_buffer *mem) +static int do_server(struct memory_buffer *mem) { char ctrl_data[sizeof(int) * 20000]; struct netdev_queue_id *queues; @@ -686,6 +751,198 @@ void run_devmem_tests(void) provider->free(mem); } =20 +static unsigned long gettimeofday_ms(void) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + return (tv.tv_sec * 1000) + (tv.tv_usec / 1000); +} + +static int do_poll(int fd) +{ + struct pollfd pfd; + int ret; + + pfd.events =3D POLLERR; + pfd.revents =3D 0; + pfd.fd =3D fd; + + ret =3D poll(&pfd, 1, waittime_ms); + if (ret =3D=3D -1) + error(1, errno, "poll"); + + return ret && (pfd.revents & POLLERR); +} + +static void wait_compl(int fd) +{ + int64_t tstop =3D gettimeofday_ms() + waittime_ms; + char control[CMSG_SPACE(100)] =3D {}; + struct sock_extended_err *serr; + struct msghdr msg =3D {}; + struct cmsghdr *cm; + int retries =3D 10; + __u32 hi, lo; + int ret; + + msg.msg_control =3D control; + msg.msg_controllen =3D sizeof(control); + + while (gettimeofday_ms() < tstop) { + if (!do_poll(fd)) + continue; + + ret =3D recvmsg(fd, &msg, MSG_ERRQUEUE); + if (ret < 0) { + if (errno =3D=3D EAGAIN) + continue; + error(1, ret, "recvmsg(MSG_ERRQUEUE)"); + return; + } + if (msg.msg_flags & MSG_CTRUNC) + error(1, 0, "MSG_CTRUNC\n"); + + for (cm =3D CMSG_FIRSTHDR(&msg); cm; cm =3D CMSG_NXTHDR(&msg, cm)) { + if (cm->cmsg_level !=3D SOL_IP && + cm->cmsg_level !=3D SOL_IPV6) + continue; + if (cm->cmsg_level =3D=3D SOL_IP && + cm->cmsg_type !=3D IP_RECVERR) + continue; + if (cm->cmsg_level =3D=3D SOL_IPV6 && + cm->cmsg_type !=3D IPV6_RECVERR) + continue; + + serr =3D (void *)CMSG_DATA(cm); + if (serr->ee_origin !=3D SO_EE_ORIGIN_ZEROCOPY) + error(1, 0, "wrong origin %u", serr->ee_origin); + if (serr->ee_errno !=3D 0) + error(1, 0, "wrong errno %d", serr->ee_errno); + + hi =3D serr->ee_data; + lo =3D serr->ee_info; + + fprintf(stderr, "tx complete [%d,%d]\n", lo, hi); + return; + } + } + + error(1, 0, "did not receive tx completion"); +} + +static int do_client(struct memory_buffer *mem) +{ + char ctrl_data[CMSG_SPACE(sizeof(struct dmabuf_tx_cmsg))]; + struct sockaddr_in6 server_sin; + struct sockaddr_in6 client_sin; + struct dmabuf_tx_cmsg ddmabuf; + struct ynl_sock *ys =3D NULL; + struct msghdr msg =3D {}; + ssize_t line_size =3D 0; + struct cmsghdr *cmsg; + uint64_t off =3D 100; + char *line =3D NULL; + struct iovec iov; + size_t len =3D 0; + int socket_fd; + int opt =3D 1; + int ret; + + ret =3D parse_address(server_ip, atoi(port), &server_sin); + if (ret < 0) + error(1, 0, "parse server address"); + + socket_fd =3D socket(AF_INET6, SOCK_STREAM, 0); + if (socket_fd < 0) + error(1, socket_fd, "create socket"); + + enable_reuseaddr(socket_fd); + + ret =3D setsockopt(socket_fd, SOL_SOCKET, SO_BINDTODEVICE, ifname, + strlen(ifname) + 1); + if (ret) + error(1, ret, "bindtodevice"); + + if (bind_tx_queue(ifindex, mem->fd, &ys)) + error(1, 0, "Failed to bind\n"); + + ret =3D parse_address(client_ip, atoi(port), &client_sin); + if (ret < 0) + error(1, 0, "parse client address"); + + ret =3D bind(socket_fd, &client_sin, sizeof(client_sin)); + if (ret) + error(1, ret, "bind"); + + ret =3D setsockopt(socket_fd, SOL_SOCKET, SO_ZEROCOPY, &opt, sizeof(opt)); + if (ret) + error(1, ret, "set sock opt"); + + fprintf(stderr, "Connect to %s %d (via %s)\n", server_ip, + ntohs(server_sin.sin6_port), ifname); + + ret =3D connect(socket_fd, &server_sin, sizeof(server_sin)); + if (ret) + error(1, ret, "connect"); + + while (1) { + free(line); + line =3D NULL; + line_size =3D getline(&line, &len, stdin); + + if (line_size < 0) + break; + + provider->memcpy_to_device(mem, off, line, line_size); + + while (line_size) { + fprintf(stderr, "read line_size=3D%ld off=3D%d\n", + line_size, off); + + iov.iov_base =3D NULL; + iov.iov_len =3D line_size; + + msg.msg_iov =3D &iov; + msg.msg_iovlen =3D 1; + + msg.msg_control =3D ctrl_data; + msg.msg_controllen =3D sizeof(ctrl_data); + + cmsg =3D CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level =3D SOL_SOCKET; + cmsg->cmsg_type =3D SCM_DEVMEM_DMABUF; + cmsg->cmsg_len =3D CMSG_LEN(sizeof(struct dmabuf_tx_cmsg)); + + ddmabuf.dmabuf_id =3D tx_dmabuf_id; + ddmabuf.dmabuf_offset =3D off; + + *((struct dmabuf_tx_cmsg *)CMSG_DATA(cmsg)) =3D ddmabuf; + + ret =3D sendmsg(socket_fd, &msg, MSG_ZEROCOPY); + if (ret < 0) + error(1, errno, "Failed sendmsg"); + + fprintf(stderr, "sendmsg_ret=3D%d\n", ret); + + off +=3D ret; + line_size -=3D ret; + + wait_compl(socket_fd); + } + } + + fprintf(stderr, "%s: tx ok\n", TEST_PREFIX); + + free(line); + close(socket_fd); + + if (ys) + ynl_sock_destroy(ys); + + return 0; +} + int main(int argc, char *argv[]) { struct memory_buffer *mem; @@ -779,7 +1036,7 @@ int main(int argc, char *argv[]) error(1, 0, "Missing -p argument\n"); =20 mem =3D provider->alloc(getpagesize() * NUM_PAGES); - ret =3D is_server ? do_server(mem) : 1; + ret =3D is_server ? do_server(mem) : do_client(mem); provider->free(mem); =20 return ret; --=20 2.47.1.613.gc27f4b7a9f-goog