Since UDP has no built in knowledge of connections, the only way we
know when we're done with a UDP flow is a timeout with no activity.
To keep track of this struct udp_flow includes a timestamp to record
the last time we saw traffic on the flow.
For data from listening sockets and from tap, this is done implicitly via
udp_flow_from_{sock,tap}() but for reply sockets it's done explicitly.
However, that logic is duplicated between the vhost-user and "buf" paths.
Make it common in udp_reply_sock_handler() instead.
Technically this is a behavioural change: previously if we got an EPOLLIN
event, but there wasn't actually any data we wouldn't update the timestamp,
now we will. This should be harmless: if there's an EPOLLIN we expect
there to be data, and even if there isn't the worst we can do is mildly
delay the cleanup of a stale flow.
Signed-off-by: David Gibson
---
udp.c | 15 ++++++---------
udp_vu.c | 9 +--------
udp_vu.h | 3 +--
3 files changed, 8 insertions(+), 19 deletions(-)
diff --git a/udp.c b/udp.c
index ac168db9..44b58d1c 100644
--- a/udp.c
+++ b/udp.c
@@ -758,27 +758,21 @@ void udp_listen_sock_handler(const struct ctx *c,
* @c: Execution context
* @s: Socket to read data from
* @tosidx: Flow & side to forward data from @s to
- * @now: Current timestamp
*
* Return: true on success, false if can't forward from socket to flow's pif
*
* #syscalls recvmmsg
*/
static bool udp_buf_reply_sock_data(const struct ctx *c,
- int s, flow_sidx_t tosidx,
- const struct timespec *now)
+ int s, flow_sidx_t tosidx)
{
const struct flowside *toside = flowside_at_sidx(tosidx);
- struct udp_flow *uflow = udp_at_sidx(tosidx);
uint8_t topif = pif_at_sidx(tosidx);
int n, i;
if ((n = udp_sock_recv(c, s, udp_mh_recv)) <= 0)
return true;
- flow_trace(uflow, "Received %d datagrams on reply socket", n);
- uflow->ts = now->tv_sec;
-
for (i = 0; i < n; i++) {
if (pif_is_socket(topif))
udp_splice_prepare(udp_mh_recv, i);
@@ -825,10 +819,13 @@ void udp_reply_sock_handler(const struct ctx *c, union epoll_ref ref,
int s = ref.fd;
bool ret;
+ flow_trace(uflow, "Received data on reply socket");
+ uflow->ts = now->tv_sec;
+
if (c->mode == MODE_VU)
- ret = udp_vu_reply_sock_data(c, s, tosidx, now);
+ ret = udp_vu_reply_sock_data(c, s, tosidx);
else
- ret = udp_buf_reply_sock_data(c, s, tosidx, now);
+ ret = udp_buf_reply_sock_data(c, s, tosidx);
if (!ret) {
flow_err(uflow, "Unable to forward UDP");
diff --git a/udp_vu.c b/udp_vu.c
index 06bdeae6..4153b6c1 100644
--- a/udp_vu.c
+++ b/udp_vu.c
@@ -275,22 +275,17 @@ void udp_vu_listen_sock_data(const struct ctx *c, union epoll_ref ref,
* @c: Execution context
* @s: Socket to read data from
* @tosidx: Flow & side to forward data from @s to
- * @now: Current timestamp
*
* Return: true on success, false if can't forward from socket to flow's pif
*/
-bool udp_vu_reply_sock_data(const struct ctx *c, int s, flow_sidx_t tosidx,
- const struct timespec *now)
+bool udp_vu_reply_sock_data(const struct ctx *c, int s, flow_sidx_t tosidx)
{
const struct flowside *toside = flowside_at_sidx(tosidx);
bool v6 = !(inany_v4(&toside->eaddr) && inany_v4(&toside->oaddr));
- struct udp_flow *uflow = udp_at_sidx(tosidx);
struct vu_dev *vdev = c->vdev;
struct vu_virtq *vq = &vdev->vq[VHOST_USER_RX_QUEUE];
int i;
- ASSERT(uflow);
-
if (pif_at_sidx(tosidx) != PIF_TAP)
return false;
@@ -301,8 +296,6 @@ bool udp_vu_reply_sock_data(const struct ctx *c, int s, flow_sidx_t tosidx,
iov_used = udp_vu_sock_recv(c, s, v6, &dlen);
if (iov_used <= 0)
break;
- flow_trace(uflow, "Received 1 datagram on reply socket");
- uflow->ts = now->tv_sec;
udp_vu_prepare(c, toside, dlen);
if (*c->pcap) {
diff --git a/udp_vu.h b/udp_vu.h
index 2299b51f..6d541a4e 100644
--- a/udp_vu.h
+++ b/udp_vu.h
@@ -8,7 +8,6 @@
void udp_vu_listen_sock_data(const struct ctx *c, union epoll_ref ref,
const struct timespec *now);
-bool udp_vu_reply_sock_data(const struct ctx *c, int s, flow_sidx_t tosidx,
- const struct timespec *now);
+bool udp_vu_reply_sock_data(const struct ctx *c, int s, flow_sidx_t tosidx);
#endif /* UDP_VU_H */
--
2.49.0