public inbox for passt-dev@passt.top
 help / color / mirror / code / Atom feed
888367ef4e16829b916df583722dd11d6479cd06 blob 5396 bytes (raw)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
 
// SPDX-License-Identifier: GPL-2.0-or-later
/* udp_vu.c - UDP L2 vhost-user management functions
 *
 * Copyright Red Hat
 * Author: Laurent Vivier <lvivier@redhat.com>
 */

#include <unistd.h>
#include <assert.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <stdint.h>
#include <stddef.h>
#include <sys/uio.h>
#include <linux/virtio_net.h>

#include "checksum.h"
#include "util.h"
#include "ip.h"
#include "siphash.h"
#include "inany.h"
#include "passt.h"
#include "pcap.h"
#include "log.h"
#include "vhost_user.h"
#include "udp_internal.h"
#include "flow.h"
#include "flow_table.h"
#include "udp_flow.h"
#include "udp_vu.h"
#include "vu_common.h"

/**
 * udp_vu_hdrlen() - Sum size of all headers, from UDP to virtio-net
 * @v6:		Set for IPv6 packet
 *
 * Return: total size of virtio-net, Ethernet, IP, and UDP headers
 */
static size_t udp_vu_hdrlen(bool v6)
{
	size_t hdrlen;

	hdrlen = VNET_HLEN + sizeof(struct ethhdr) + sizeof(struct udphdr);

	if (v6)
		hdrlen += sizeof(struct ipv6hdr);
	else
		hdrlen += sizeof(struct iphdr);

	return hdrlen;
}

/**
 * udp_vu_sock_recv() - Receive datagrams from socket into vhost-user buffers
 * @payload:	UDP payload
 * @cnt:	Number of used entries in @payload to store the datagram (output)
 * 		Unchanged on failure
 * @s:		Socket to receive from
 *
 * Return: size of received data, -1 on error
 */
static ssize_t udp_vu_sock_recv(struct iov_tail *payload, size_t *cnt, int s)
{
	struct iovec msg_iov[VIRTQUEUE_MAX_SIZE];
	struct msghdr msg  = { 0 };
	size_t iov_used;
	ssize_t dlen;

	msg.msg_iov = msg_iov;
	msg.msg_iovlen = iov_tail_clone(msg.msg_iov, ARRAY_SIZE(msg_iov),
					payload);

	/* read data from the socket */
	dlen = recvmsg(s, &msg, 0);
	if (dlen < 0)
		return -1;

	iov_used = iov_skip_bytes(payload->iov, payload->cnt,
				  MAX(dlen + payload->off,
				      VNET_HLEN + ETH_ZLEN), NULL);
	if (iov_used < payload->cnt)
		iov_used++;
	*cnt = iov_used; /* one iovec per element */

	return dlen;
}

/**
 * udp_vu_prepare() - Prepare the packet header
 * @c:		Execution context
 * @data:	IO vector tail for the L2 frame, on return points to the L4 header
 * @payload:	UDP payload
 * @toside:	Address information for one side of the flow
 * @dlen:	Packet data length
 */
static void udp_vu_prepare(const struct ctx *c, struct iov_tail *data,
			   struct iov_tail *payload,
			   const struct flowside *toside, size_t dlen)
{
	bool ipv4 = inany_v4(&toside->eaddr) && inany_v4(&toside->oaddr);
	struct ethhdr eh;
	struct udphdr uh;

	/* ethernet header */
	memcpy(eh.h_dest, c->guest_mac, sizeof(eh.h_dest));
	memcpy(eh.h_source, c->our_tap_mac, sizeof(eh.h_source));

	if (ipv4)
		eh.h_proto = htons(ETH_P_IP);
	else
		eh.h_proto = htons(ETH_P_IPV6);
	IOV_PUSH_HEADER(data, eh);

	/* initialize header */
	if (ipv4) {
		struct iphdr iph = (struct iphdr)L2_BUF_IP4_INIT(IPPROTO_UDP);

		udp_update_hdr4(&iph, &uh, payload, toside, dlen, !*c->pcap);

		IOV_PUSH_HEADER(data, iph);
	} else {
		struct ipv6hdr ip6h = (struct ipv6hdr)L2_BUF_IP6_INIT(IPPROTO_UDP);

		udp_update_hdr6(&ip6h, &uh, payload, toside, dlen, !*c->pcap);

		IOV_PUSH_HEADER(data, ip6h);
	}
	IOV_PUSH_HEADER(data, uh);
}

/**
 * udp_vu_sock_to_tap() - Forward datagrams from socket to tap
 * @c:		Execution context
 * @s:		Socket to read data from
 * @n:		Maximum number of datagrams to forward
 * @tosidx:	Flow & side to forward data from @s to
 */
void udp_vu_sock_to_tap(const struct ctx *c, int s, int n, flow_sidx_t tosidx)
{
	const struct flowside *toside = flowside_at_sidx(tosidx);
	bool v6 = !(inany_v4(&toside->eaddr) && inany_v4(&toside->oaddr));
	static struct vu_virtq_element elem[VIRTQUEUE_MAX_SIZE];
	static struct iovec iov_vu[VIRTQUEUE_MAX_SIZE];
	struct vu_dev *vdev = c->vdev;
	struct vu_virtq *vq = &vdev->vq[VHOST_USER_RX_QUEUE];
	size_t hdrlen = udp_vu_hdrlen(v6);
	int i;

	assert(!c->no_udp);

	if (!vu_queue_enabled(vq) || !vu_queue_started(vq)) {
		struct msghdr msg = { 0 };

		debug("Got UDP packet, but RX virtqueue not usable yet");

		for (i = 0; i < n; i++) {
			if (recvmsg(s, &msg, MSG_DONTWAIT) < 0)
				debug_perror("Failed to discard datagram");
		}

		return;
	}

	for (i = 0; i < n; i++) {
		unsigned elem_cnt, elem_used, j, k;
		struct iov_tail payload;
		size_t iov_cnt;
		ssize_t dlen;

		elem_cnt = vu_collect(vdev, vq, elem, ARRAY_SIZE(elem),
				      iov_vu, ARRAY_SIZE(iov_vu), &iov_cnt,
				      IP_MAX_MTU + ETH_HLEN + VNET_HLEN, NULL);
		if (elem_cnt == 0)
			break;

		payload = IOV_TAIL(iov_vu, iov_cnt, hdrlen);
		dlen = udp_vu_sock_recv(&payload, &iov_cnt, s);
		if (dlen < 0) {
			vu_queue_rewind(vq, elem_cnt);
			break;
		}

		elem_used = 0;
		for (j = 0, k = 0; k < iov_cnt && j < elem_cnt; j++) {
			size_t iov_still_needed = iov_cnt - k;

			if (elem[j].in_num > iov_still_needed)
				elem[j].in_num = iov_still_needed;
			k += elem[j].in_num;
			elem_used++;
		}

		/* release unused buffers */
		vu_queue_rewind(vq, elem_cnt - elem_used);

		if (iov_cnt > 0) {
			struct iov_tail data = IOV_TAIL(iov_vu, iov_cnt, VNET_HLEN);
			udp_vu_prepare(c, &data, &payload, toside, dlen);
			if (*c->pcap) {
				pcap_iov(iov_vu, iov_cnt, VNET_HLEN,
					 hdrlen + dlen - VNET_HLEN);
			}
			vu_pad(iov_vu, iov_cnt, hdrlen + dlen);
			vu_flush(vdev, vq, elem, elem_used, hdrlen + dlen);
			vu_queue_notify(vdev, vq);
		}
	}
}
debug log:

solving 888367ef4e16 ...
found 888367ef4e16 in https://archives.passt.top/passt-dev/20260519155613.3127607-4-lvivier@redhat.com/
found 74bf79d57969 in https://archives.passt.top/passt-dev/20260519155613.3127607-2-lvivier@redhat.com/ ||
	https://archives.passt.top/passt-dev/20260518122625.2290034-2-lvivier@redhat.com/
found dfff7bb1cd53 in https://archives.passt.top/passt-dev/20260513115218.1662850-11-lvivier@redhat.com/
found 3c9fff53324c in https://archives.passt.top/passt-dev/20260513115218.1662850-9-lvivier@redhat.com/
found 3ff643478616 in https://archives.passt.top/passt-dev/20260513115218.1662850-8-lvivier@redhat.com/
found 523447a81fae in https://archives.passt.top/passt-dev/20260513115218.1662850-7-lvivier@redhat.com/
found 96c65803a0ea in https://archives.passt.top/passt-dev/20260513115218.1662850-6-lvivier@redhat.com/
found bd9fd5abb971 in https://archives.passt.top/passt-dev/20260416155721.3807225-5-lvivier@redhat.com/ ||
	https://archives.passt.top/passt-dev/20260513115218.1662850-5-lvivier@redhat.com/
found f8629af58ab5 in https://archives.passt.top/passt-dev/20260401191826.1782394-4-lvivier@redhat.com/ ||
	https://archives.passt.top/passt-dev/20260403163811.3209635-4-lvivier@redhat.com/ ||
	https://archives.passt.top/passt-dev/20260327175834.831995-3-lvivier@redhat.com/ ||
	https://archives.passt.top/passt-dev/20260416155721.3807225-4-lvivier@redhat.com/ ||
	https://archives.passt.top/passt-dev/20260513115218.1662850-4-lvivier@redhat.com/
found cc69654398f0 in https://passt.top/passt
preparing index
index prepared:
100644 cc69654398f02b2b21b3d7f41eb12060e177a709	udp_vu.c

applying [1/15] https://archives.passt.top/passt-dev/20260401191826.1782394-4-lvivier@redhat.com/
diff --git a/udp_vu.c b/udp_vu.c
index cc69654398f0..f8629af58ab5 100644

Checking patch udp_vu.c...
Applied patch udp_vu.c cleanly.

skipping https://archives.passt.top/passt-dev/20260403163811.3209635-4-lvivier@redhat.com/ for f8629af58ab5
skipping https://archives.passt.top/passt-dev/20260327175834.831995-3-lvivier@redhat.com/ for f8629af58ab5
skipping https://archives.passt.top/passt-dev/20260416155721.3807225-4-lvivier@redhat.com/ for f8629af58ab5
skipping https://archives.passt.top/passt-dev/20260513115218.1662850-4-lvivier@redhat.com/ for f8629af58ab5
index at:
100644 f8629af58ab54f9f9728b2364c5b31bb03bb681a	udp_vu.c

applying [2/15] https://archives.passt.top/passt-dev/20260416155721.3807225-5-lvivier@redhat.com/
diff --git a/udp_vu.c b/udp_vu.c
index f8629af58ab5..bd9fd5abb971 100644

Checking patch udp_vu.c...
Applied patch udp_vu.c cleanly.

skipping https://archives.passt.top/passt-dev/20260513115218.1662850-5-lvivier@redhat.com/ for bd9fd5abb971
index at:
100644 bd9fd5abb971b6e3271e320386d243f460a2fb64	udp_vu.c

applying [3/15] https://archives.passt.top/passt-dev/20260513115218.1662850-6-lvivier@redhat.com/
diff --git a/udp_vu.c b/udp_vu.c
index bd9fd5abb971..96c65803a0ea 100644


applying [4/15] https://archives.passt.top/passt-dev/20260513115218.1662850-7-lvivier@redhat.com/
diff --git a/udp_vu.c b/udp_vu.c
index 96c65803a0ea..523447a81fae 100644


applying [5/15] https://archives.passt.top/passt-dev/20260513115218.1662850-8-lvivier@redhat.com/
diff --git a/udp_vu.c b/udp_vu.c
index 523447a81fae..3ff643478616 100644


applying [6/15] https://archives.passt.top/passt-dev/20260513115218.1662850-9-lvivier@redhat.com/
diff --git a/udp_vu.c b/udp_vu.c
index 3ff643478616..3c9fff53324c 100644


applying [7/15] https://archives.passt.top/passt-dev/20260513115218.1662850-11-lvivier@redhat.com/
diff --git a/udp_vu.c b/udp_vu.c
index 3c9fff53324c..dfff7bb1cd53 100644


applying [8/15] https://archives.passt.top/passt-dev/20260519155613.3127607-2-lvivier@redhat.com/
diff --git a/udp_vu.c b/udp_vu.c
index dfff7bb1cd53..74bf79d57969 100644

Checking patch udp_vu.c...
Applied patch udp_vu.c cleanly.
Checking patch udp_vu.c...
Applied patch udp_vu.c cleanly.
Checking patch udp_vu.c...
Applied patch udp_vu.c cleanly.
Checking patch udp_vu.c...
Applied patch udp_vu.c cleanly.
Checking patch udp_vu.c...
Applied patch udp_vu.c cleanly.
Checking patch udp_vu.c...
Applied patch udp_vu.c cleanly.

skipping https://archives.passt.top/passt-dev/20260518122625.2290034-2-lvivier@redhat.com/ for 74bf79d57969
index at:
100644 74bf79d57969cedb357340843e4ba15cd9b7f1bd	udp_vu.c

applying [9/15] https://archives.passt.top/passt-dev/20260519155613.3127607-4-lvivier@redhat.com/
diff --git a/udp_vu.c b/udp_vu.c
index 74bf79d57969..888367ef4e16 100644

Checking patch udp_vu.c...
Applied patch udp_vu.c cleanly.

index at:
100644 888367ef4e16829b916df583722dd11d6479cd06	udp_vu.c

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).