* [PATCH 0/2] udp_flow: move all udp_flow functions to udp_flow.c
@ 2024-08-02 16:10 Laurent Vivier
2024-08-02 16:10 ` [PATCH 1/2] udp_flow: Remove udp_meta_t from the parameters of udp_flow_from_sock() Laurent Vivier
` (2 more replies)
0 siblings, 3 replies; 8+ messages in thread
From: Laurent Vivier @ 2024-08-02 16:10 UTC (permalink / raw)
To: passt-dev; +Cc: Laurent Vivier
This helps to export them and use them with vhost-user version
of udp.c
There is only one code change: pass s_in rather than udp_meta_t to
udp_flow_from_sock() as udp_meta_t is specific to the socket version
of udp.c
Otherwise, only code move
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
Laurent Vivier (2):
udp_flow: Remove udp_meta_t from the parameters of
udp_flow_from_sock()
udp_flow: move all udp_flow functions to udp_flow.c
Makefile | 2 +-
udp.c | 264 +--------------------------------------------------
udp_flow.c | 274 +++++++++++++++++++++++++++++++++++++++++++++++++++++
udp_flow.h | 9 ++
4 files changed, 286 insertions(+), 263 deletions(-)
create mode 100644 udp_flow.c
--
2.45.2
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 1/2] udp_flow: Remove udp_meta_t from the parameters of udp_flow_from_sock()
2024-08-02 16:10 [PATCH 0/2] udp_flow: move all udp_flow functions to udp_flow.c Laurent Vivier
@ 2024-08-02 16:10 ` Laurent Vivier
2024-08-03 7:47 ` David Gibson
2024-08-02 16:10 ` [PATCH 2/2] udp_flow: move all udp_flow functions to udp_flow.c Laurent Vivier
2024-08-05 19:02 ` [PATCH 0/2] " Stefano Brivio
2 siblings, 1 reply; 8+ messages in thread
From: Laurent Vivier @ 2024-08-02 16:10 UTC (permalink / raw)
To: passt-dev; +Cc: Laurent Vivier
To be used with the vhost-user version of udp.c, we need to export the
udp_flow functions. To avoid to export udp_meta_t too that is specific
to the socket version of udp.c, don't pass udp_meta_t to it,
but the only needed field, s_in.
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
---
udp.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/udp.c b/udp.c
index a92014806a73..f27a00bf5610 100644
--- a/udp.c
+++ b/udp.c
@@ -432,7 +432,7 @@ cancel:
* udp_flow_from_sock() - Find or create UDP flow for "listening" socket
* @c: Execution context
* @ref: epoll reference of the receiving socket
- * @meta: Metadata buffer for the datagram
+ * @s_in: Source socket address, filled in by recvmmsg()
* @now: Timestamp
*
* #syscalls fcntl
@@ -441,7 +441,7 @@ cancel:
* FLOW_SIDX_NONE if we couldn't find or create a flow.
*/
static flow_sidx_t udp_flow_from_sock(const struct ctx *c, union epoll_ref ref,
- struct udp_meta_t *meta,
+ const union sockaddr_inany *s_in,
const struct timespec *now)
{
struct udp_flow *uflow;
@@ -450,7 +450,7 @@ static flow_sidx_t udp_flow_from_sock(const struct ctx *c, union epoll_ref ref,
ASSERT(ref.type == EPOLL_TYPE_UDP_LISTEN);
- sidx = flow_lookup_sa(c, IPPROTO_UDP, ref.udp.pif, &meta->s_in, ref.udp.port);
+ sidx = flow_lookup_sa(c, IPPROTO_UDP, ref.udp.pif, s_in, ref.udp.port);
if ((uflow = udp_at_sidx(sidx))) {
uflow->ts = now->tv_sec;
return flow_sidx_opposite(sidx);
@@ -461,11 +461,11 @@ static flow_sidx_t udp_flow_from_sock(const struct ctx *c, union epoll_ref ref,
debug("Couldn't allocate flow for UDP datagram from %s %s",
pif_name(ref.udp.pif),
- sockaddr_ntop(&meta->s_in, sastr, sizeof(sastr)));
+ sockaddr_ntop(s_in, sastr, sizeof(sastr)));
return FLOW_SIDX_NONE;
}
- flow_initiate_sa(flow, ref.udp.pif, &meta->s_in, ref.udp.port);
+ flow_initiate_sa(flow, ref.udp.pif, s_in, ref.udp.port);
return udp_flow_new(c, flow, ref.fd, now);
}
@@ -712,7 +712,7 @@ void udp_listen_sock_handler(const struct ctx *c, union epoll_ref ref,
* the array, or recalculating tosidx for a single entry, we have to
* populate it one entry *ahead* of the loop counter.
*/
- udp_meta[0].tosidx = udp_flow_from_sock(c, ref, &udp_meta[0], now);
+ udp_meta[0].tosidx = udp_flow_from_sock(c, ref, &udp_meta[0].s_in, now);
for (i = 0; i < n; ) {
flow_sidx_t batchsidx = udp_meta[i].tosidx;
uint8_t batchpif = pif_at_sidx(batchsidx);
@@ -730,7 +730,7 @@ void udp_listen_sock_handler(const struct ctx *c, union epoll_ref ref,
break;
udp_meta[i].tosidx = udp_flow_from_sock(c, ref,
- &udp_meta[i],
+ &udp_meta[i].s_in,
now);
} while (flow_sidx_eq(udp_meta[i].tosidx, batchsidx));
--
@@ -432,7 +432,7 @@ cancel:
* udp_flow_from_sock() - Find or create UDP flow for "listening" socket
* @c: Execution context
* @ref: epoll reference of the receiving socket
- * @meta: Metadata buffer for the datagram
+ * @s_in: Source socket address, filled in by recvmmsg()
* @now: Timestamp
*
* #syscalls fcntl
@@ -441,7 +441,7 @@ cancel:
* FLOW_SIDX_NONE if we couldn't find or create a flow.
*/
static flow_sidx_t udp_flow_from_sock(const struct ctx *c, union epoll_ref ref,
- struct udp_meta_t *meta,
+ const union sockaddr_inany *s_in,
const struct timespec *now)
{
struct udp_flow *uflow;
@@ -450,7 +450,7 @@ static flow_sidx_t udp_flow_from_sock(const struct ctx *c, union epoll_ref ref,
ASSERT(ref.type == EPOLL_TYPE_UDP_LISTEN);
- sidx = flow_lookup_sa(c, IPPROTO_UDP, ref.udp.pif, &meta->s_in, ref.udp.port);
+ sidx = flow_lookup_sa(c, IPPROTO_UDP, ref.udp.pif, s_in, ref.udp.port);
if ((uflow = udp_at_sidx(sidx))) {
uflow->ts = now->tv_sec;
return flow_sidx_opposite(sidx);
@@ -461,11 +461,11 @@ static flow_sidx_t udp_flow_from_sock(const struct ctx *c, union epoll_ref ref,
debug("Couldn't allocate flow for UDP datagram from %s %s",
pif_name(ref.udp.pif),
- sockaddr_ntop(&meta->s_in, sastr, sizeof(sastr)));
+ sockaddr_ntop(s_in, sastr, sizeof(sastr)));
return FLOW_SIDX_NONE;
}
- flow_initiate_sa(flow, ref.udp.pif, &meta->s_in, ref.udp.port);
+ flow_initiate_sa(flow, ref.udp.pif, s_in, ref.udp.port);
return udp_flow_new(c, flow, ref.fd, now);
}
@@ -712,7 +712,7 @@ void udp_listen_sock_handler(const struct ctx *c, union epoll_ref ref,
* the array, or recalculating tosidx for a single entry, we have to
* populate it one entry *ahead* of the loop counter.
*/
- udp_meta[0].tosidx = udp_flow_from_sock(c, ref, &udp_meta[0], now);
+ udp_meta[0].tosidx = udp_flow_from_sock(c, ref, &udp_meta[0].s_in, now);
for (i = 0; i < n; ) {
flow_sidx_t batchsidx = udp_meta[i].tosidx;
uint8_t batchpif = pif_at_sidx(batchsidx);
@@ -730,7 +730,7 @@ void udp_listen_sock_handler(const struct ctx *c, union epoll_ref ref,
break;
udp_meta[i].tosidx = udp_flow_from_sock(c, ref,
- &udp_meta[i],
+ &udp_meta[i].s_in,
now);
} while (flow_sidx_eq(udp_meta[i].tosidx, batchsidx));
--
2.45.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 2/2] udp_flow: move all udp_flow functions to udp_flow.c
2024-08-02 16:10 [PATCH 0/2] udp_flow: move all udp_flow functions to udp_flow.c Laurent Vivier
2024-08-02 16:10 ` [PATCH 1/2] udp_flow: Remove udp_meta_t from the parameters of udp_flow_from_sock() Laurent Vivier
@ 2024-08-02 16:10 ` Laurent Vivier
2024-08-03 7:51 ` David Gibson
2024-08-05 19:02 ` [PATCH 0/2] " Stefano Brivio
2 siblings, 1 reply; 8+ messages in thread
From: Laurent Vivier @ 2024-08-02 16:10 UTC (permalink / raw)
To: passt-dev; +Cc: Laurent Vivier
No code change.
They need to be exported to be available by the vhost-user version of
passt.
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
---
Makefile | 2 +-
udp.c | 260 --------------------------------------------------
udp_flow.c | 274 +++++++++++++++++++++++++++++++++++++++++++++++++++++
udp_flow.h | 9 ++
4 files changed, 284 insertions(+), 261 deletions(-)
create mode 100644 udp_flow.c
diff --git a/Makefile b/Makefile
index bd504d23da3c..b6329e35f884 100644
--- a/Makefile
+++ b/Makefile
@@ -47,7 +47,7 @@ FLAGS += -DDUAL_STACK_SOCKETS=$(DUAL_STACK_SOCKETS)
PASST_SRCS = arch.c arp.c checksum.c conf.c dhcp.c dhcpv6.c flow.c fwd.c \
icmp.c igmp.c inany.c iov.c ip.c isolation.c lineread.c log.c mld.c \
ndp.c netlink.c packet.c passt.c pasta.c pcap.c pif.c tap.c tcp.c \
- tcp_buf.c tcp_splice.c udp.c util.c
+ tcp_buf.c tcp_splice.c udp.c udp_flow.c util.c
QRAP_SRCS = qrap.c
SRCS = $(PASST_SRCS) $(QRAP_SRCS)
diff --git a/udp.c b/udp.c
index f27a00bf5610..7731257292e1 100644
--- a/udp.c
+++ b/udp.c
@@ -95,7 +95,6 @@
#include <sys/socket.h>
#include <sys/uio.h>
#include <time.h>
-#include <fcntl.h>
#include <arpa/inet.h>
#include <linux/errqueue.h>
@@ -111,7 +110,6 @@
#include "log.h"
#include "flow_table.h"
-#define UDP_CONN_TIMEOUT 180 /* s, timeout for ephemeral or local bind */
#define UDP_MAX_FRAMES 32 /* max # of frames to receive at once */
/* "Spliced" sockets indexed by bound port (host order) */
@@ -276,199 +274,6 @@ static void udp_iov_init(const struct ctx *c)
udp_iov_init_one(c, i);
}
-/**
- * udp_at_sidx() - Get UDP specific flow at given sidx
- * @sidx: Flow and side to retrieve
- *
- * Return: UDP specific flow at @sidx, or NULL of @sidx is invalid. Asserts if
- * the flow at @sidx is not FLOW_UDP.
- */
-struct udp_flow *udp_at_sidx(flow_sidx_t sidx)
-{
- union flow *flow = flow_at_sidx(sidx);
-
- if (!flow)
- return NULL;
-
- ASSERT(flow->f.type == FLOW_UDP);
- return &flow->udp;
-}
-
-/*
- * udp_flow_close() - Close and clean up UDP flow
- * @c: Execution context
- * @uflow: UDP flow
- */
-static void udp_flow_close(const struct ctx *c, struct udp_flow *uflow)
-{
- if (uflow->s[INISIDE] >= 0) {
- /* The listening socket needs to stay in epoll */
- close(uflow->s[INISIDE]);
- uflow->s[INISIDE] = -1;
- }
-
- if (uflow->s[TGTSIDE] >= 0) {
- /* But the flow specific one needs to be removed */
- epoll_ctl(c->epollfd, EPOLL_CTL_DEL, uflow->s[TGTSIDE], NULL);
- close(uflow->s[TGTSIDE]);
- uflow->s[TGTSIDE] = -1;
- }
- flow_hash_remove(c, FLOW_SIDX(uflow, INISIDE));
- if (!pif_is_socket(uflow->f.pif[TGTSIDE]))
- flow_hash_remove(c, FLOW_SIDX(uflow, TGTSIDE));
-}
-
-/**
- * udp_flow_new() - Common setup for a new UDP flow
- * @c: Execution context
- * @flow: Initiated flow
- * @s_ini: Initiating socket (or -1)
- * @now: Timestamp
- *
- * Return: UDP specific flow, if successful, NULL on failure
- */
-static flow_sidx_t udp_flow_new(const struct ctx *c, union flow *flow,
- int s_ini, const struct timespec *now)
-{
- const struct flowside *ini = &flow->f.side[INISIDE];
- struct udp_flow *uflow = NULL;
- const struct flowside *tgt;
- uint8_t tgtpif;
-
- if (!inany_is_unicast(&ini->eaddr) || ini->eport == 0) {
- flow_trace(flow, "Invalid endpoint to initiate UDP flow");
- goto cancel;
- }
-
- if (!(tgt = flow_target(c, flow, IPPROTO_UDP)))
- goto cancel;
- tgtpif = flow->f.pif[TGTSIDE];
-
- uflow = FLOW_SET_TYPE(flow, FLOW_UDP, udp);
- uflow->ts = now->tv_sec;
- uflow->s[INISIDE] = uflow->s[TGTSIDE] = -1;
-
- if (s_ini >= 0) {
- /* When using auto port-scanning the listening port could go
- * away, so we need to duplicate the socket
- */
- uflow->s[INISIDE] = fcntl(s_ini, F_DUPFD_CLOEXEC, 0);
- if (uflow->s[INISIDE] < 0) {
- flow_err(uflow,
- "Couldn't duplicate listening socket: %s",
- strerror(errno));
- goto cancel;
- }
- }
-
- if (pif_is_socket(tgtpif)) {
- struct mmsghdr discard[UIO_MAXIOV] = { 0 };
- union {
- flow_sidx_t sidx;
- uint32_t data;
- } fref = {
- .sidx = FLOW_SIDX(flow, TGTSIDE),
- };
- int rc;
-
- uflow->s[TGTSIDE] = flowside_sock_l4(c, EPOLL_TYPE_UDP_REPLY,
- tgtpif, tgt, fref.data);
- if (uflow->s[TGTSIDE] < 0) {
- flow_dbg(uflow,
- "Couldn't open socket for spliced flow: %s",
- strerror(errno));
- goto cancel;
- }
-
- if (flowside_connect(c, uflow->s[TGTSIDE], tgtpif, tgt) < 0) {
- flow_dbg(uflow,
- "Couldn't connect flow socket: %s",
- strerror(errno));
- goto cancel;
- }
-
- /* It's possible, if unlikely, that we could receive some
- * unrelated packets in between the bind() and connect() of this
- * socket. For now we just discard these. We could consider
- * trying to redirect these to an appropriate handler, if we
- * need to.
- */
- rc = recvmmsg(uflow->s[TGTSIDE], discard, ARRAY_SIZE(discard),
- MSG_DONTWAIT, NULL);
- if (rc >= ARRAY_SIZE(discard)) {
- flow_dbg(uflow,
- "Too many (%d) spurious reply datagrams", rc);
- goto cancel;
- } else if (rc > 0) {
- flow_trace(uflow,
- "Discarded %d spurious reply datagrams", rc);
- } else if (errno != EAGAIN) {
- flow_err(uflow,
- "Unexpected error discarding datagrams: %s",
- strerror(errno));
- }
- }
-
- flow_hash_insert(c, FLOW_SIDX(uflow, INISIDE));
-
- /* If the target side is a socket, it will be a reply socket that knows
- * its own flowside. But if it's tap, then we need to look it up by
- * hash.
- */
- if (!pif_is_socket(tgtpif))
- flow_hash_insert(c, FLOW_SIDX(uflow, TGTSIDE));
- FLOW_ACTIVATE(uflow);
-
- return FLOW_SIDX(uflow, TGTSIDE);
-
-cancel:
- if (uflow)
- udp_flow_close(c, uflow);
- flow_alloc_cancel(flow);
- return FLOW_SIDX_NONE;
-}
-
-/**
- * udp_flow_from_sock() - Find or create UDP flow for "listening" socket
- * @c: Execution context
- * @ref: epoll reference of the receiving socket
- * @s_in: Source socket address, filled in by recvmmsg()
- * @now: Timestamp
- *
- * #syscalls fcntl
- *
- * Return: sidx for the destination side of the flow for this packet, or
- * FLOW_SIDX_NONE if we couldn't find or create a flow.
- */
-static flow_sidx_t udp_flow_from_sock(const struct ctx *c, union epoll_ref ref,
- const union sockaddr_inany *s_in,
- const struct timespec *now)
-{
- struct udp_flow *uflow;
- union flow *flow;
- flow_sidx_t sidx;
-
- ASSERT(ref.type == EPOLL_TYPE_UDP_LISTEN);
-
- sidx = flow_lookup_sa(c, IPPROTO_UDP, ref.udp.pif, s_in, ref.udp.port);
- if ((uflow = udp_at_sidx(sidx))) {
- uflow->ts = now->tv_sec;
- return flow_sidx_opposite(sidx);
- }
-
- if (!(flow = flow_alloc())) {
- char sastr[SOCKADDR_STRLEN];
-
- debug("Couldn't allocate flow for UDP datagram from %s %s",
- pif_name(ref.udp.pif),
- sockaddr_ntop(s_in, sastr, sizeof(sastr)));
- return FLOW_SIDX_NONE;
- }
-
- flow_initiate_sa(flow, ref.udp.pif, s_in, ref.udp.port);
- return udp_flow_new(c, flow, ref.fd, now);
-}
-
/**
* udp_splice_prepare() - Prepare one datagram for splicing
* @mmh: Receiving mmsghdr array
@@ -804,53 +609,6 @@ void udp_reply_sock_handler(const struct ctx *c, union epoll_ref ref,
}
}
-/**
- * udp_flow_from_tap() - Find or create UDP flow for tap packets
- * @c: Execution context
- * @pif: pif on which the packet is arriving
- * @af: Address family, AF_INET or AF_INET6
- * @saddr: Source address on guest side
- * @daddr: Destination address guest side
- * @srcport: Source port on guest side
- * @dstport: Destination port on guest side
- *
- * Return: sidx for the destination side of the flow for this packet, or
- * FLOW_SIDX_NONE if we couldn't find or create a flow.
- */
-static flow_sidx_t udp_flow_from_tap(const struct ctx *c,
- uint8_t pif, sa_family_t af,
- const void *saddr, const void *daddr,
- in_port_t srcport, in_port_t dstport,
- const struct timespec *now)
-{
- struct udp_flow *uflow;
- union flow *flow;
- flow_sidx_t sidx;
-
- ASSERT(pif == PIF_TAP);
-
- sidx = flow_lookup_af(c, IPPROTO_UDP, pif, af, saddr, daddr,
- srcport, dstport);
- if ((uflow = udp_at_sidx(sidx))) {
- uflow->ts = now->tv_sec;
- return flow_sidx_opposite(sidx);
- }
-
- if (!(flow = flow_alloc())) {
- char sstr[INET6_ADDRSTRLEN], dstr[INET6_ADDRSTRLEN];
-
- debug("Couldn't allocate flow for UDP datagram from %s %s:%hu -> %s:%hu",
- pif_name(pif),
- inet_ntop(af, saddr, sstr, sizeof(sstr)), srcport,
- inet_ntop(af, daddr, dstr, sizeof(dstr)), dstport);
- return FLOW_SIDX_NONE;
- }
-
- flow_initiate_af(flow, PIF_TAP, af, saddr, srcport, daddr, dstport);
-
- return udp_flow_new(c, flow, -1, now);
-}
-
/**
* udp_tap_handler() - Handle packets from tap
* @c: Execution context
@@ -1098,24 +856,6 @@ static int udp_port_rebind_outbound(void *arg)
return 0;
}
-/**
- * udp_flow_timer() - Handler for timed events related to a given flow
- * @c: Execution context
- * @uflow: UDP flow
- * @now: Current timestamp
- *
- * Return: true if the flow is ready to free, false otherwise
- */
-bool udp_flow_timer(const struct ctx *c, struct udp_flow *uflow,
- const struct timespec *now)
-{
- if (now->tv_sec - uflow->ts <= UDP_CONN_TIMEOUT)
- return false;
-
- udp_flow_close(c, uflow);
- return true;
-}
-
/**
* udp_timer() - Scan activity bitmaps for ports with associated timed events
* @c: Execution context
diff --git a/udp_flow.c b/udp_flow.c
new file mode 100644
index 000000000000..8b25ad162eaa
--- /dev/null
+++ b/udp_flow.c
@@ -0,0 +1,274 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright Red Hat
+ * Author: David Gibson <david@gibson.dropbear.id.au>
+ *
+ * UDP flow tracking functions
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/uio.h>
+
+#include "util.h"
+#include "passt.h"
+#include "flow_table.h"
+
+#define UDP_CONN_TIMEOUT 180 /* s, timeout for ephemeral or local bind */
+
+/**
+ * udp_at_sidx() - Get UDP specific flow at given sidx
+ * @sidx: Flow and side to retrieve
+ *
+ * Return: UDP specific flow at @sidx, or NULL of @sidx is invalid. Asserts if
+ * the flow at @sidx is not FLOW_UDP.
+ */
+struct udp_flow *udp_at_sidx(flow_sidx_t sidx)
+{
+ union flow *flow = flow_at_sidx(sidx);
+
+ if (!flow)
+ return NULL;
+
+ ASSERT(flow->f.type == FLOW_UDP);
+ return &flow->udp;
+}
+
+/*
+ * udp_flow_close() - Close and clean up UDP flow
+ * @c: Execution context
+ * @uflow: UDP flow
+ */
+static void udp_flow_close(const struct ctx *c, struct udp_flow *uflow)
+{
+ if (uflow->s[INISIDE] >= 0) {
+ /* The listening socket needs to stay in epoll */
+ close(uflow->s[INISIDE]);
+ uflow->s[INISIDE] = -1;
+ }
+
+ if (uflow->s[TGTSIDE] >= 0) {
+ /* But the flow specific one needs to be removed */
+ epoll_ctl(c->epollfd, EPOLL_CTL_DEL, uflow->s[TGTSIDE], NULL);
+ close(uflow->s[TGTSIDE]);
+ uflow->s[TGTSIDE] = -1;
+ }
+ flow_hash_remove(c, FLOW_SIDX(uflow, INISIDE));
+ if (!pif_is_socket(uflow->f.pif[TGTSIDE]))
+ flow_hash_remove(c, FLOW_SIDX(uflow, TGTSIDE));
+}
+
+/**
+ * udp_flow_new() - Common setup for a new UDP flow
+ * @c: Execution context
+ * @flow: Initiated flow
+ * @s_ini: Initiating socket (or -1)
+ * @now: Timestamp
+ *
+ * Return: UDP specific flow, if successful, NULL on failure
+ */
+static flow_sidx_t udp_flow_new(const struct ctx *c, union flow *flow,
+ int s_ini, const struct timespec *now)
+{
+ const struct flowside *ini = &flow->f.side[INISIDE];
+ struct udp_flow *uflow = NULL;
+ const struct flowside *tgt;
+ uint8_t tgtpif;
+
+ if (!inany_is_unicast(&ini->eaddr) || ini->eport == 0) {
+ flow_trace(flow, "Invalid endpoint to initiate UDP flow");
+ goto cancel;
+ }
+
+ if (!(tgt = flow_target(c, flow, IPPROTO_UDP)))
+ goto cancel;
+ tgtpif = flow->f.pif[TGTSIDE];
+
+ uflow = FLOW_SET_TYPE(flow, FLOW_UDP, udp);
+ uflow->ts = now->tv_sec;
+ uflow->s[INISIDE] = uflow->s[TGTSIDE] = -1;
+
+ if (s_ini >= 0) {
+ /* When using auto port-scanning the listening port could go
+ * away, so we need to duplicate the socket
+ */
+ uflow->s[INISIDE] = fcntl(s_ini, F_DUPFD_CLOEXEC, 0);
+ if (uflow->s[INISIDE] < 0) {
+ flow_err(uflow,
+ "Couldn't duplicate listening socket: %s",
+ strerror(errno));
+ goto cancel;
+ }
+ }
+
+ if (pif_is_socket(tgtpif)) {
+ struct mmsghdr discard[UIO_MAXIOV] = { 0 };
+ union {
+ flow_sidx_t sidx;
+ uint32_t data;
+ } fref = {
+ .sidx = FLOW_SIDX(flow, TGTSIDE),
+ };
+ int rc;
+
+ uflow->s[TGTSIDE] = flowside_sock_l4(c, EPOLL_TYPE_UDP_REPLY,
+ tgtpif, tgt, fref.data);
+ if (uflow->s[TGTSIDE] < 0) {
+ flow_dbg(uflow,
+ "Couldn't open socket for spliced flow: %s",
+ strerror(errno));
+ goto cancel;
+ }
+
+ if (flowside_connect(c, uflow->s[TGTSIDE], tgtpif, tgt) < 0) {
+ flow_dbg(uflow,
+ "Couldn't connect flow socket: %s",
+ strerror(errno));
+ goto cancel;
+ }
+
+ /* It's possible, if unlikely, that we could receive some
+ * unrelated packets in between the bind() and connect() of this
+ * socket. For now we just discard these. We could consider
+ * trying to redirect these to an appropriate handler, if we
+ * need to.
+ */
+ rc = recvmmsg(uflow->s[TGTSIDE], discard, ARRAY_SIZE(discard),
+ MSG_DONTWAIT, NULL);
+ if (rc >= ARRAY_SIZE(discard)) {
+ flow_dbg(uflow,
+ "Too many (%d) spurious reply datagrams", rc);
+ goto cancel;
+ } else if (rc > 0) {
+ flow_trace(uflow,
+ "Discarded %d spurious reply datagrams", rc);
+ } else if (errno != EAGAIN) {
+ flow_err(uflow,
+ "Unexpected error discarding datagrams: %s",
+ strerror(errno));
+ }
+ }
+
+ flow_hash_insert(c, FLOW_SIDX(uflow, INISIDE));
+
+ /* If the target side is a socket, it will be a reply socket that knows
+ * its own flowside. But if it's tap, then we need to look it up by
+ * hash.
+ */
+ if (!pif_is_socket(tgtpif))
+ flow_hash_insert(c, FLOW_SIDX(uflow, TGTSIDE));
+ FLOW_ACTIVATE(uflow);
+
+ return FLOW_SIDX(uflow, TGTSIDE);
+
+cancel:
+ if (uflow)
+ udp_flow_close(c, uflow);
+ flow_alloc_cancel(flow);
+ return FLOW_SIDX_NONE;
+}
+
+/**
+ * udp_flow_from_sock() - Find or create UDP flow for "listening" socket
+ * @c: Execution context
+ * @ref: epoll reference of the receiving socket
+ * @s_in: Source socket address, filled in by recvmmsg()
+ * @now: Timestamp
+ *
+ * #syscalls fcntl
+ *
+ * Return: sidx for the destination side of the flow for this packet, or
+ * FLOW_SIDX_NONE if we couldn't find or create a flow.
+ */
+flow_sidx_t udp_flow_from_sock(const struct ctx *c, union epoll_ref ref,
+ const union sockaddr_inany *s_in,
+ const struct timespec *now)
+{
+ struct udp_flow *uflow;
+ union flow *flow;
+ flow_sidx_t sidx;
+
+ ASSERT(ref.type == EPOLL_TYPE_UDP_LISTEN);
+
+ sidx = flow_lookup_sa(c, IPPROTO_UDP, ref.udp.pif, s_in, ref.udp.port);
+ if ((uflow = udp_at_sidx(sidx))) {
+ uflow->ts = now->tv_sec;
+ return flow_sidx_opposite(sidx);
+ }
+
+ if (!(flow = flow_alloc())) {
+ char sastr[SOCKADDR_STRLEN];
+
+ debug("Couldn't allocate flow for UDP datagram from %s %s",
+ pif_name(ref.udp.pif),
+ sockaddr_ntop(s_in, sastr, sizeof(sastr)));
+ return FLOW_SIDX_NONE;
+ }
+
+ flow_initiate_sa(flow, ref.udp.pif, s_in, ref.udp.port);
+ return udp_flow_new(c, flow, ref.fd, now);
+}
+
+/**
+ * udp_flow_from_tap() - Find or create UDP flow for tap packets
+ * @c: Execution context
+ * @pif: pif on which the packet is arriving
+ * @af: Address family, AF_INET or AF_INET6
+ * @saddr: Source address on guest side
+ * @daddr: Destination address guest side
+ * @srcport: Source port on guest side
+ * @dstport: Destination port on guest side
+ *
+ * Return: sidx for the destination side of the flow for this packet, or
+ * FLOW_SIDX_NONE if we couldn't find or create a flow.
+ */
+flow_sidx_t udp_flow_from_tap(const struct ctx *c,
+ uint8_t pif, sa_family_t af,
+ const void *saddr, const void *daddr,
+ in_port_t srcport, in_port_t dstport,
+ const struct timespec *now)
+{
+ struct udp_flow *uflow;
+ union flow *flow;
+ flow_sidx_t sidx;
+
+ ASSERT(pif == PIF_TAP);
+
+ sidx = flow_lookup_af(c, IPPROTO_UDP, pif, af, saddr, daddr,
+ srcport, dstport);
+ if ((uflow = udp_at_sidx(sidx))) {
+ uflow->ts = now->tv_sec;
+ return flow_sidx_opposite(sidx);
+ }
+
+ if (!(flow = flow_alloc())) {
+ char sstr[INET6_ADDRSTRLEN], dstr[INET6_ADDRSTRLEN];
+
+ debug("Couldn't allocate flow for UDP datagram from %s %s:%hu -> %s:%hu",
+ pif_name(pif),
+ inet_ntop(af, saddr, sstr, sizeof(sstr)), srcport,
+ inet_ntop(af, daddr, dstr, sizeof(dstr)), dstport);
+ return FLOW_SIDX_NONE;
+ }
+
+ flow_initiate_af(flow, PIF_TAP, af, saddr, srcport, daddr, dstport);
+
+ return udp_flow_new(c, flow, -1, now);
+}
+
+/**
+ * udp_flow_timer() - Handler for timed events related to a given flow
+ * @c: Execution context
+ * @uflow: UDP flow
+ * @now: Current timestamp
+ *
+ * Return: true if the flow is ready to free, false otherwise
+ */
+bool udp_flow_timer(const struct ctx *c, struct udp_flow *uflow,
+ const struct timespec *now)
+{
+ if (now->tv_sec - uflow->ts <= UDP_CONN_TIMEOUT)
+ return false;
+
+ udp_flow_close(c, uflow);
+ return true;
+}
diff --git a/udp_flow.h b/udp_flow.h
index e0736f8f60bc..12ddf0394cce 100644
--- a/udp_flow.h
+++ b/udp_flow.h
@@ -21,6 +21,15 @@ struct udp_flow {
int s[SIDES];
};
+struct udp_flow *udp_at_sidx(flow_sidx_t sidx);
+flow_sidx_t udp_flow_from_sock(const struct ctx *c, union epoll_ref ref,
+ const union sockaddr_inany *s_in,
+ const struct timespec *now);
+flow_sidx_t udp_flow_from_tap(const struct ctx *c,
+ uint8_t pif, sa_family_t af,
+ const void *saddr, const void *daddr,
+ in_port_t srcport, in_port_t dstport,
+ const struct timespec *now);
bool udp_flow_timer(const struct ctx *c, struct udp_flow *uflow,
const struct timespec *now);
--
@@ -21,6 +21,15 @@ struct udp_flow {
int s[SIDES];
};
+struct udp_flow *udp_at_sidx(flow_sidx_t sidx);
+flow_sidx_t udp_flow_from_sock(const struct ctx *c, union epoll_ref ref,
+ const union sockaddr_inany *s_in,
+ const struct timespec *now);
+flow_sidx_t udp_flow_from_tap(const struct ctx *c,
+ uint8_t pif, sa_family_t af,
+ const void *saddr, const void *daddr,
+ in_port_t srcport, in_port_t dstport,
+ const struct timespec *now);
bool udp_flow_timer(const struct ctx *c, struct udp_flow *uflow,
const struct timespec *now);
--
2.45.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 1/2] udp_flow: Remove udp_meta_t from the parameters of udp_flow_from_sock()
2024-08-02 16:10 ` [PATCH 1/2] udp_flow: Remove udp_meta_t from the parameters of udp_flow_from_sock() Laurent Vivier
@ 2024-08-03 7:47 ` David Gibson
0 siblings, 0 replies; 8+ messages in thread
From: David Gibson @ 2024-08-03 7:47 UTC (permalink / raw)
To: Laurent Vivier; +Cc: passt-dev
[-- Attachment #1: Type: text/plain, Size: 3350 bytes --]
On Fri, Aug 02, 2024 at 06:10:35PM +0200, Laurent Vivier wrote:
> To be used with the vhost-user version of udp.c, we need to export the
> udp_flow functions. To avoid to export udp_meta_t too that is specific
> to the socket version of udp.c, don't pass udp_meta_t to it,
> but the only needed field, s_in.
>
> Signed-off-by: Laurent Vivier <lvivier@redhat.com>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
> ---
> udp.c | 14 +++++++-------
> 1 file changed, 7 insertions(+), 7 deletions(-)
>
> diff --git a/udp.c b/udp.c
> index a92014806a73..f27a00bf5610 100644
> --- a/udp.c
> +++ b/udp.c
> @@ -432,7 +432,7 @@ cancel:
> * udp_flow_from_sock() - Find or create UDP flow for "listening" socket
> * @c: Execution context
> * @ref: epoll reference of the receiving socket
> - * @meta: Metadata buffer for the datagram
> + * @s_in: Source socket address, filled in by recvmmsg()
> * @now: Timestamp
> *
> * #syscalls fcntl
> @@ -441,7 +441,7 @@ cancel:
> * FLOW_SIDX_NONE if we couldn't find or create a flow.
> */
> static flow_sidx_t udp_flow_from_sock(const struct ctx *c, union epoll_ref ref,
> - struct udp_meta_t *meta,
> + const union sockaddr_inany *s_in,
> const struct timespec *now)
> {
> struct udp_flow *uflow;
> @@ -450,7 +450,7 @@ static flow_sidx_t udp_flow_from_sock(const struct ctx *c, union epoll_ref ref,
>
> ASSERT(ref.type == EPOLL_TYPE_UDP_LISTEN);
>
> - sidx = flow_lookup_sa(c, IPPROTO_UDP, ref.udp.pif, &meta->s_in, ref.udp.port);
> + sidx = flow_lookup_sa(c, IPPROTO_UDP, ref.udp.pif, s_in, ref.udp.port);
> if ((uflow = udp_at_sidx(sidx))) {
> uflow->ts = now->tv_sec;
> return flow_sidx_opposite(sidx);
> @@ -461,11 +461,11 @@ static flow_sidx_t udp_flow_from_sock(const struct ctx *c, union epoll_ref ref,
>
> debug("Couldn't allocate flow for UDP datagram from %s %s",
> pif_name(ref.udp.pif),
> - sockaddr_ntop(&meta->s_in, sastr, sizeof(sastr)));
> + sockaddr_ntop(s_in, sastr, sizeof(sastr)));
> return FLOW_SIDX_NONE;
> }
>
> - flow_initiate_sa(flow, ref.udp.pif, &meta->s_in, ref.udp.port);
> + flow_initiate_sa(flow, ref.udp.pif, s_in, ref.udp.port);
> return udp_flow_new(c, flow, ref.fd, now);
> }
>
> @@ -712,7 +712,7 @@ void udp_listen_sock_handler(const struct ctx *c, union epoll_ref ref,
> * the array, or recalculating tosidx for a single entry, we have to
> * populate it one entry *ahead* of the loop counter.
> */
> - udp_meta[0].tosidx = udp_flow_from_sock(c, ref, &udp_meta[0], now);
> + udp_meta[0].tosidx = udp_flow_from_sock(c, ref, &udp_meta[0].s_in, now);
> for (i = 0; i < n; ) {
> flow_sidx_t batchsidx = udp_meta[i].tosidx;
> uint8_t batchpif = pif_at_sidx(batchsidx);
> @@ -730,7 +730,7 @@ void udp_listen_sock_handler(const struct ctx *c, union epoll_ref ref,
> break;
>
> udp_meta[i].tosidx = udp_flow_from_sock(c, ref,
> - &udp_meta[i],
> + &udp_meta[i].s_in,
> now);
> } while (flow_sidx_eq(udp_meta[i].tosidx, batchsidx));
>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2] udp_flow: move all udp_flow functions to udp_flow.c
2024-08-02 16:10 ` [PATCH 2/2] udp_flow: move all udp_flow functions to udp_flow.c Laurent Vivier
@ 2024-08-03 7:51 ` David Gibson
2024-08-05 7:11 ` Laurent Vivier
0 siblings, 1 reply; 8+ messages in thread
From: David Gibson @ 2024-08-03 7:51 UTC (permalink / raw)
To: Laurent Vivier; +Cc: passt-dev
[-- Attachment #1: Type: text/plain, Size: 1160 bytes --]
On Fri, Aug 02, 2024 at 06:10:36PM +0200, Laurent Vivier wrote:
> No code change.
>
> They need to be exported to be available by the vhost-user version of
> passt.
>
> Signed-off-by: Laurent Vivier <lvivier@redhat.com>
LGTM, with one nit:
> +/**
> + * udp_at_sidx() - Get UDP specific flow at given sidx
> + * @sidx: Flow and side to retrieve
> + *
> + * Return: UDP specific flow at @sidx, or NULL of @sidx is invalid. Asserts if
> + * the flow at @sidx is not FLOW_UDP.
> + */
> +struct udp_flow *udp_at_sidx(flow_sidx_t sidx)
> +{
> + union flow *flow = flow_at_sidx(sidx);
> +
> + if (!flow)
> + return NULL;
> +
> + ASSERT(flow->f.type == FLOW_UDP);
> + return &flow->udp;
> +}
udp_at_sidx() is so simple it probably makes more sense to have it as
an inline in the header file, rather than a regular function. When it
was a local function, I was pretty much assuming the compiler would
inline it anyways.
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2] udp_flow: move all udp_flow functions to udp_flow.c
2024-08-03 7:51 ` David Gibson
@ 2024-08-05 7:11 ` Laurent Vivier
2024-08-05 12:17 ` David Gibson
0 siblings, 1 reply; 8+ messages in thread
From: Laurent Vivier @ 2024-08-05 7:11 UTC (permalink / raw)
To: David Gibson; +Cc: passt-dev
On 03/08/2024 09:51, David Gibson wrote:
> On Fri, Aug 02, 2024 at 06:10:36PM +0200, Laurent Vivier wrote:
>> No code change.
>>
>> They need to be exported to be available by the vhost-user version of
>> passt.
>>
>> Signed-off-by: Laurent Vivier <lvivier@redhat.com>
>
> LGTM, with one nit:
>
>> +/**
>> + * udp_at_sidx() - Get UDP specific flow at given sidx
>> + * @sidx: Flow and side to retrieve
>> + *
>> + * Return: UDP specific flow at @sidx, or NULL of @sidx is invalid. Asserts if
>> + * the flow at @sidx is not FLOW_UDP.
>> + */
>> +struct udp_flow *udp_at_sidx(flow_sidx_t sidx)
>> +{
>> + union flow *flow = flow_at_sidx(sidx);
>> +
>> + if (!flow)
>> + return NULL;
>> +
>> + ASSERT(flow->f.type == FLOW_UDP);
>> + return &flow->udp;
>> +}
>
> udp_at_sidx() is so simple it probably makes more sense to have it as
> an inline in the header file, rather than a regular function. When it
> was a local function, I was pretty much assuming the compiler would
> inline it anyways.
>
I can't move it to udp_flow.h because udp_at_sidx() uses flow_at_sidx() that is defined in
flow_table.h after udp_flow.h has already been included. flow_table.h includes udp_flow.h
at its top because it needs "struct udp_flow" in union flow.
Thanks,
Laurent
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2] udp_flow: move all udp_flow functions to udp_flow.c
2024-08-05 7:11 ` Laurent Vivier
@ 2024-08-05 12:17 ` David Gibson
0 siblings, 0 replies; 8+ messages in thread
From: David Gibson @ 2024-08-05 12:17 UTC (permalink / raw)
To: Laurent Vivier; +Cc: passt-dev
[-- Attachment #1: Type: text/plain, Size: 1770 bytes --]
On Mon, Aug 05, 2024 at 09:11:36AM +0200, Laurent Vivier wrote:
> On 03/08/2024 09:51, David Gibson wrote:
> > On Fri, Aug 02, 2024 at 06:10:36PM +0200, Laurent Vivier wrote:
> > > No code change.
> > >
> > > They need to be exported to be available by the vhost-user version of
> > > passt.
> > >
> > > Signed-off-by: Laurent Vivier <lvivier@redhat.com>
> >
> > LGTM, with one nit:
> >
> > > +/**
> > > + * udp_at_sidx() - Get UDP specific flow at given sidx
> > > + * @sidx: Flow and side to retrieve
> > > + *
> > > + * Return: UDP specific flow at @sidx, or NULL of @sidx is invalid. Asserts if
> > > + * the flow at @sidx is not FLOW_UDP.
> > > + */
> > > +struct udp_flow *udp_at_sidx(flow_sidx_t sidx)
> > > +{
> > > + union flow *flow = flow_at_sidx(sidx);
> > > +
> > > + if (!flow)
> > > + return NULL;
> > > +
> > > + ASSERT(flow->f.type == FLOW_UDP);
> > > + return &flow->udp;
> > > +}
> >
> > udp_at_sidx() is so simple it probably makes more sense to have it as
> > an inline in the header file, rather than a regular function. When it
> > was a local function, I was pretty much assuming the compiler would
> > inline it anyways.
> >
>
> I can't move it to udp_flow.h because udp_at_sidx() uses flow_at_sidx() that
> is defined in flow_table.h after udp_flow.h has already been included.
> flow_table.h includes udp_flow.h at its top because it needs "struct
> udp_flow" in union flow.
Ah, I didn't think of that. Never mind, then.
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 0/2] udp_flow: move all udp_flow functions to udp_flow.c
2024-08-02 16:10 [PATCH 0/2] udp_flow: move all udp_flow functions to udp_flow.c Laurent Vivier
2024-08-02 16:10 ` [PATCH 1/2] udp_flow: Remove udp_meta_t from the parameters of udp_flow_from_sock() Laurent Vivier
2024-08-02 16:10 ` [PATCH 2/2] udp_flow: move all udp_flow functions to udp_flow.c Laurent Vivier
@ 2024-08-05 19:02 ` Stefano Brivio
2 siblings, 0 replies; 8+ messages in thread
From: Stefano Brivio @ 2024-08-05 19:02 UTC (permalink / raw)
To: Laurent Vivier; +Cc: passt-dev
On Fri, 2 Aug 2024 18:10:34 +0200
Laurent Vivier <lvivier@redhat.com> wrote:
> This helps to export them and use them with vhost-user version
> of udp.c
>
> There is only one code change: pass s_in rather than udp_meta_t to
> udp_flow_from_sock() as udp_meta_t is specific to the socket version
> of udp.c
>
> Otherwise, only code move
>
> Signed-off-by: Laurent Vivier <lvivier@redhat.com>
>
> Laurent Vivier (2):
> udp_flow: Remove udp_meta_t from the parameters of
> udp_flow_from_sock()
> udp_flow: move all udp_flow functions to udp_flow.c
Applied.
--
Stefano
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2024-08-05 19:02 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-08-02 16:10 [PATCH 0/2] udp_flow: move all udp_flow functions to udp_flow.c Laurent Vivier
2024-08-02 16:10 ` [PATCH 1/2] udp_flow: Remove udp_meta_t from the parameters of udp_flow_from_sock() Laurent Vivier
2024-08-03 7:47 ` David Gibson
2024-08-02 16:10 ` [PATCH 2/2] udp_flow: move all udp_flow functions to udp_flow.c Laurent Vivier
2024-08-03 7:51 ` David Gibson
2024-08-05 7:11 ` Laurent Vivier
2024-08-05 12:17 ` David Gibson
2024-08-05 19:02 ` [PATCH 0/2] " Stefano Brivio
Code repositories for project(s) associated with this public inbox
https://passt.top/passt
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for IMAP folder(s).