udp: Split sending to passt tap interface into separate function
The last part of udp_sock_handler() does the actual sending of frames to the tap interface. For pasta that's just a call to udp_tap_send_pasta() but for passt, it's moderately complex and open coded. For symmetry, move the passt send path into its own function, udp_tap_send_passt(). This will make it easier to abstract the tap interface in future (e.g. when we want to add vhost-user). Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
This commit is contained in:
parent
a6e919a951
commit
09c00f1d2a
1 changed files with 72 additions and 58 deletions
130
udp.c
130
udp.c
|
@ -812,6 +812,73 @@ static void udp_tap_send_pasta(const struct ctx *c, struct mmsghdr *mmh,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* udp_tap_send_passt() - Send datagrams to the passt tap interface
|
||||||
|
* @c: Execution context
|
||||||
|
* @mmh: Array of message headers to send
|
||||||
|
* @n: Number of message headers to send
|
||||||
|
*
|
||||||
|
* #syscalls:passt sendmmsg sendmsg
|
||||||
|
*/
|
||||||
|
static void udp_tap_send_passt(const struct ctx *c, struct mmsghdr *mmh, int n)
|
||||||
|
{
|
||||||
|
struct msghdr *last_mh;
|
||||||
|
ssize_t missing = 0;
|
||||||
|
size_t msg_len = 0;
|
||||||
|
unsigned int i;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = sendmmsg(c->fd_tap, mmh, n, MSG_NOSIGNAL | MSG_DONTWAIT);
|
||||||
|
if (ret <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* If we lose some messages to sendmmsg() here, fine, it's UDP. However,
|
||||||
|
* the last message needs to be delivered completely, otherwise qemu
|
||||||
|
* will fail to reassemble the next message and close the connection. Go
|
||||||
|
* through headers from the last sent message, counting bytes, and, if
|
||||||
|
* and as soon as we see more bytes than sendmmsg() sent, re-send the
|
||||||
|
* rest with a blocking call.
|
||||||
|
*
|
||||||
|
* In pictures, given this example:
|
||||||
|
*
|
||||||
|
* iov #0 iov #1 iov #2 iov #3
|
||||||
|
* tap_mmh[ret - 1].msg_hdr: .... ...... ..... ......
|
||||||
|
* tap_mmh[ret - 1].msg_len: 7 .... ...
|
||||||
|
*
|
||||||
|
* when 'msglen' reaches: 10 ^
|
||||||
|
* and 'missing' below is: 3 ---
|
||||||
|
*
|
||||||
|
* re-send everything from here: ^-- ----- ------
|
||||||
|
*/
|
||||||
|
last_mh = &mmh[ret - 1].msg_hdr;
|
||||||
|
for (i = 0; i < last_mh->msg_iovlen; i++) {
|
||||||
|
if (missing <= 0) {
|
||||||
|
msg_len += last_mh->msg_iov[i].iov_len;
|
||||||
|
missing = msg_len - mmh[ret - 1].msg_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (missing > 0) {
|
||||||
|
uint8_t **iov_base;
|
||||||
|
int first_offset;
|
||||||
|
|
||||||
|
iov_base = (uint8_t **)&last_mh->msg_iov[i].iov_base;
|
||||||
|
first_offset = last_mh->msg_iov[i].iov_len - missing;
|
||||||
|
*iov_base += first_offset;
|
||||||
|
last_mh->msg_iov[i].iov_len = missing;
|
||||||
|
|
||||||
|
last_mh->msg_iov = &last_mh->msg_iov[i];
|
||||||
|
|
||||||
|
if (sendmsg(c->fd_tap, last_mh, MSG_NOSIGNAL) < 0)
|
||||||
|
debug("UDP: %li bytes to tap missing", missing);
|
||||||
|
|
||||||
|
*iov_base -= first_offset;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pcapmm(mmh, ret);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* udp_sock_handler() - Handle new data from socket
|
* udp_sock_handler() - Handle new data from socket
|
||||||
* @c: Execution context
|
* @c: Execution context
|
||||||
|
@ -820,16 +887,14 @@ static void udp_tap_send_pasta(const struct ctx *c, struct mmsghdr *mmh,
|
||||||
* @now: Current timestamp
|
* @now: Current timestamp
|
||||||
*
|
*
|
||||||
* #syscalls recvmmsg
|
* #syscalls recvmmsg
|
||||||
* #syscalls:passt sendmmsg sendmsg
|
|
||||||
*/
|
*/
|
||||||
void udp_sock_handler(const struct ctx *c, union epoll_ref ref, uint32_t events,
|
void udp_sock_handler(const struct ctx *c, union epoll_ref ref, uint32_t events,
|
||||||
const struct timespec *now)
|
const struct timespec *now)
|
||||||
{
|
{
|
||||||
in_port_t dstport = ref.r.p.udp.udp.port;
|
in_port_t dstport = ref.r.p.udp.udp.port;
|
||||||
ssize_t n, msg_len = 0, missing = 0;
|
|
||||||
struct mmsghdr *tap_mmh, *sock_mmh;
|
struct mmsghdr *tap_mmh, *sock_mmh;
|
||||||
int msg_bufs = 0, msg_i = 0, ret;
|
int msg_bufs = 0, msg_i = 0;
|
||||||
struct msghdr *last_mh;
|
ssize_t n, msg_len = 0;
|
||||||
struct iovec *tap_iov;
|
struct iovec *tap_iov;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
|
@ -879,61 +944,10 @@ void udp_sock_handler(const struct ctx *c, union epoll_ref ref, uint32_t events,
|
||||||
}
|
}
|
||||||
tap_mmh[msg_i].msg_hdr.msg_iovlen = msg_bufs;
|
tap_mmh[msg_i].msg_hdr.msg_iovlen = msg_bufs;
|
||||||
|
|
||||||
if (c->mode == MODE_PASTA) {
|
if (c->mode == MODE_PASTA)
|
||||||
udp_tap_send_pasta(c, tap_mmh, msg_i + 1);
|
udp_tap_send_pasta(c, tap_mmh, msg_i + 1);
|
||||||
return;
|
else
|
||||||
}
|
udp_tap_send_passt(c, tap_mmh, msg_i + 1);
|
||||||
|
|
||||||
ret = sendmmsg(c->fd_tap, tap_mmh, msg_i + 1,
|
|
||||||
MSG_NOSIGNAL | MSG_DONTWAIT);
|
|
||||||
if (ret <= 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* If we lose some messages to sendmmsg() here, fine, it's UDP. However,
|
|
||||||
* the last message needs to be delivered completely, otherwise qemu
|
|
||||||
* will fail to reassemble the next message and close the connection. Go
|
|
||||||
* through headers from the last sent message, counting bytes, and, if
|
|
||||||
* and as soon as we see more bytes than sendmmsg() sent, re-send the
|
|
||||||
* rest with a blocking call.
|
|
||||||
*
|
|
||||||
* In pictures, given this example:
|
|
||||||
*
|
|
||||||
* iov #0 iov #1 iov #2 iov #3
|
|
||||||
* tap_mmh[ret - 1].msg_hdr: .... ...... ..... ......
|
|
||||||
* tap_mmh[ret - 1].msg_len: 7 .... ...
|
|
||||||
*
|
|
||||||
* when 'msglen' reaches: 10 ^
|
|
||||||
* and 'missing' below is: 3 ---
|
|
||||||
*
|
|
||||||
* re-send everything from here: ^-- ----- ------
|
|
||||||
*/
|
|
||||||
last_mh = &tap_mmh[ret - 1].msg_hdr;
|
|
||||||
for (i = 0, msg_len = 0; i < last_mh->msg_iovlen; i++) {
|
|
||||||
if (missing <= 0) {
|
|
||||||
msg_len += last_mh->msg_iov[i].iov_len;
|
|
||||||
missing = msg_len - tap_mmh[ret - 1].msg_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (missing > 0) {
|
|
||||||
uint8_t **iov_base;
|
|
||||||
int first_offset;
|
|
||||||
|
|
||||||
iov_base = (uint8_t **)&last_mh->msg_iov[i].iov_base;
|
|
||||||
first_offset = last_mh->msg_iov[i].iov_len - missing;
|
|
||||||
*iov_base += first_offset;
|
|
||||||
last_mh->msg_iov[i].iov_len = missing;
|
|
||||||
|
|
||||||
last_mh->msg_iov = &last_mh->msg_iov[i];
|
|
||||||
|
|
||||||
if (sendmsg(c->fd_tap, last_mh, MSG_NOSIGNAL) < 0)
|
|
||||||
debug("UDP: %li bytes to tap missing", missing);
|
|
||||||
|
|
||||||
*iov_base -= first_offset;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pcapmm(tap_mmh, ret);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue