aboutgitcodebugslistschat
path: root/udp.c
diff options
context:
space:
mode:
Diffstat (limited to 'udp.c')
-rw-r--r--udp.c373
1 files changed, 242 insertions, 131 deletions
diff --git a/udp.c b/udp.c
index 7731257..923cc38 100644
--- a/udp.c
+++ b/udp.c
@@ -109,8 +109,8 @@
#include "pcap.h"
#include "log.h"
#include "flow_table.h"
-
-#define UDP_MAX_FRAMES 32 /* max # of frames to receive at once */
+#include "udp_internal.h"
+#include "udp_vu.h"
/* "Spliced" sockets indexed by bound port (host order) */
static int udp_splice_ns [IP_VERSIONS][NUM_PORTS];
@@ -118,20 +118,8 @@ static int udp_splice_init[IP_VERSIONS][NUM_PORTS];
/* Static buffers */
-/**
- * struct udp_payload_t - UDP header and data for inbound messages
- * @uh: UDP header
- * @data: UDP data
- */
-static struct udp_payload_t {
- struct udphdr uh;
- char data[USHRT_MAX - sizeof(struct udphdr)];
-#ifdef __AVX2__
-} __attribute__ ((packed, aligned(32)))
-#else
-} __attribute__ ((packed, aligned(__alignof__(unsigned int))))
-#endif
-udp_payload[UDP_MAX_FRAMES];
+/* UDP header and data for inbound messages */
+static struct udp_payload_t udp_payload[UDP_MAX_FRAMES];
/* Ethernet header for IPv4 frames */
static struct ethhdr udp4_eth_hdr;
@@ -169,17 +157,16 @@ udp_meta[UDP_MAX_FRAMES];
* @UDP_NUM_IOVS the number of entries in the iovec array
*/
enum udp_iov_idx {
- UDP_IOV_TAP = 0,
- UDP_IOV_ETH = 1,
- UDP_IOV_IP = 2,
- UDP_IOV_PAYLOAD = 3,
- UDP_NUM_IOVS
+ UDP_IOV_TAP,
+ UDP_IOV_ETH,
+ UDP_IOV_IP,
+ UDP_IOV_PAYLOAD,
+ UDP_NUM_IOVS,
};
/* IOVs and msghdr arrays for receiving datagrams from sockets */
static struct iovec udp_iov_recv [UDP_MAX_FRAMES];
-static struct mmsghdr udp4_mh_recv [UDP_MAX_FRAMES];
-static struct mmsghdr udp6_mh_recv [UDP_MAX_FRAMES];
+static struct mmsghdr udp_mh_recv [UDP_MAX_FRAMES];
/* IOVs and msghdr arrays for sending "spliced" datagrams to sockets */
static union sockaddr_inany udp_splice_to;
@@ -222,6 +209,7 @@ void udp_update_l2_buf(const unsigned char *eth_d, const unsigned char *eth_s)
static void udp_iov_init_one(const struct ctx *c, size_t i)
{
struct udp_payload_t *payload = &udp_payload[i];
+ struct msghdr *mh = &udp_mh_recv[i].msg_hdr;
struct udp_meta_t *meta = &udp_meta[i];
struct iovec *siov = &udp_iov_recv[i];
struct iovec *tiov = udp_l2_iov[i];
@@ -236,27 +224,10 @@ static void udp_iov_init_one(const struct ctx *c, size_t i)
tiov[UDP_IOV_TAP] = tap_hdr_iov(c, &meta->taph);
tiov[UDP_IOV_PAYLOAD].iov_base = payload;
- /* It's useful to have separate msghdr arrays for receiving. Otherwise,
- * an IPv4 recv() will alter msg_namelen, so we'd have to reset it every
- * time or risk truncating the address on future IPv6 recv()s.
- */
- if (c->ifi4) {
- struct msghdr *mh = &udp4_mh_recv[i].msg_hdr;
-
- mh->msg_name = &meta->s_in;
- mh->msg_namelen = sizeof(struct sockaddr_in);
- mh->msg_iov = siov;
- mh->msg_iovlen = 1;
- }
-
- if (c->ifi6) {
- struct msghdr *mh = &udp6_mh_recv[i].msg_hdr;
-
- mh->msg_name = &meta->s_in;
- mh->msg_namelen = sizeof(struct sockaddr_in6);
- mh->msg_iov = siov;
- mh->msg_iovlen = 1;
- }
+ mh->msg_name = &meta->s_in;
+ mh->msg_namelen = sizeof(meta->s_in);
+ mh->msg_iov = siov;
+ mh->msg_iovlen = 1;
}
/**
@@ -311,17 +282,19 @@ static void udp_splice_send(const struct ctx *c, size_t start, size_t n,
/**
* udp_update_hdr4() - Update headers for one IPv4 datagram
- * @ip4h: Pre-filled IPv4 header (except for tot_len and saddr)
- * @bp: Pointer to udp_payload_t to update
- * @toside: Flowside for destination side
- * @dlen: Length of UDP payload
+ * @ip4h: Pre-filled IPv4 header (except for tot_len and saddr)
+ * @bp: Pointer to udp_payload_t to update
+ * @toside: Flowside for destination side
+ * @dlen: Length of UDP payload
+ * @no_udp_csum: Do not set UDP checksum
*
* Return: size of IPv4 payload (UDP header + data)
*/
-static size_t udp_update_hdr4(struct iphdr *ip4h, struct udp_payload_t *bp,
- const struct flowside *toside, size_t dlen)
+size_t udp_update_hdr4(struct iphdr *ip4h, struct udp_payload_t *bp,
+ const struct flowside *toside, size_t dlen,
+ bool no_udp_csum)
{
- const struct in_addr *src = inany_v4(&toside->faddr);
+ const struct in_addr *src = inany_v4(&toside->oaddr);
const struct in_addr *dst = inany_v4(&toside->eaddr);
size_t l4len = dlen + sizeof(bp->uh);
size_t l3len = l4len + sizeof(*ip4h);
@@ -333,39 +306,64 @@ static size_t udp_update_hdr4(struct iphdr *ip4h, struct udp_payload_t *bp,
ip4h->saddr = src->s_addr;
ip4h->check = csum_ip4_header(l3len, IPPROTO_UDP, *src, *dst);
- bp->uh.source = htons(toside->fport);
+ bp->uh.source = htons(toside->oport);
bp->uh.dest = htons(toside->eport);
bp->uh.len = htons(l4len);
- csum_udp4(&bp->uh, *src, *dst, bp->data, dlen);
+ if (no_udp_csum) {
+ bp->uh.check = 0;
+ } else {
+ const struct iovec iov = {
+ .iov_base = bp->data,
+ .iov_len = dlen
+ };
+ struct iov_tail data = IOV_TAIL(&iov, 1, 0);
+ csum_udp4(&bp->uh, *src, *dst, &data);
+ }
return l4len;
}
/**
* udp_update_hdr6() - Update headers for one IPv6 datagram
- * @ip6h: Pre-filled IPv6 header (except for payload_len and addresses)
- * @bp: Pointer to udp_payload_t to update
- * @toside: Flowside for destination side
- * @dlen: Length of UDP payload
+ * @ip6h: Pre-filled IPv6 header (except for payload_len and
+ * addresses)
+ * @bp: Pointer to udp_payload_t to update
+ * @toside: Flowside for destination side
+ * @dlen: Length of UDP payload
+ * @no_udp_csum: Do not set UDP checksum
*
* Return: size of IPv6 payload (UDP header + data)
*/
-static size_t udp_update_hdr6(struct ipv6hdr *ip6h, struct udp_payload_t *bp,
- const struct flowside *toside, size_t dlen)
+size_t udp_update_hdr6(struct ipv6hdr *ip6h, struct udp_payload_t *bp,
+ const struct flowside *toside, size_t dlen,
+ bool no_udp_csum)
{
uint16_t l4len = dlen + sizeof(bp->uh);
ip6h->payload_len = htons(l4len);
ip6h->daddr = toside->eaddr.a6;
- ip6h->saddr = toside->faddr.a6;
+ ip6h->saddr = toside->oaddr.a6;
ip6h->version = 6;
ip6h->nexthdr = IPPROTO_UDP;
ip6h->hop_limit = 255;
- bp->uh.source = htons(toside->fport);
+ bp->uh.source = htons(toside->oport);
bp->uh.dest = htons(toside->eport);
bp->uh.len = ip6h->payload_len;
- csum_udp6(&bp->uh, &toside->faddr.a6, &toside->eaddr.a6, bp->data, dlen);
+ if (no_udp_csum) {
+ /* 0 is an invalid checksum for UDP IPv6 and dropped by
+ * the kernel stack, even if the checksum is disabled by virtio
+ * flags. We need to put any non-zero value here.
+ */
+ bp->uh.check = 0xffff;
+ } else {
+ const struct iovec iov = {
+ .iov_base = bp->data,
+ .iov_len = dlen
+ };
+ struct iov_tail data = IOV_TAIL(&iov, 1, 0);
+ csum_udp6(&bp->uh, &toside->oaddr.a6, &toside->eaddr.a6, &data);
+ }
return l4len;
}
@@ -375,23 +373,27 @@ static size_t udp_update_hdr6(struct ipv6hdr *ip6h, struct udp_payload_t *bp,
* @mmh: Receiving mmsghdr array
* @idx: Index of the datagram to prepare
* @toside: Flowside for destination side
+ * @no_udp_csum: Do not set UDP checksum
*/
-static void udp_tap_prepare(const struct mmsghdr *mmh, unsigned idx,
- const struct flowside *toside)
+static void udp_tap_prepare(const struct mmsghdr *mmh,
+ unsigned idx, const struct flowside *toside,
+ bool no_udp_csum)
{
struct iovec (*tap_iov)[UDP_NUM_IOVS] = &udp_l2_iov[idx];
struct udp_payload_t *bp = &udp_payload[idx];
struct udp_meta_t *bm = &udp_meta[idx];
size_t l4len;
- if (!inany_v4(&toside->eaddr) || !inany_v4(&toside->faddr)) {
- l4len = udp_update_hdr6(&bm->ip6h, bp, toside, mmh[idx].msg_len);
+ if (!inany_v4(&toside->eaddr) || !inany_v4(&toside->oaddr)) {
+ l4len = udp_update_hdr6(&bm->ip6h, bp, toside,
+ mmh[idx].msg_len, no_udp_csum);
tap_hdr_update(&bm->taph, l4len + sizeof(bm->ip6h) +
sizeof(udp6_eth_hdr));
(*tap_iov)[UDP_IOV_ETH] = IOV_OF_LVALUE(udp6_eth_hdr);
(*tap_iov)[UDP_IOV_IP] = IOV_OF_LVALUE(bm->ip6h);
} else {
- l4len = udp_update_hdr4(&bm->ip4h, bp, toside, mmh[idx].msg_len);
+ l4len = udp_update_hdr4(&bm->ip4h, bp, toside,
+ mmh[idx].msg_len, no_udp_csum);
tap_hdr_update(&bm->taph, l4len + sizeof(bm->ip4h) +
sizeof(udp4_eth_hdr));
(*tap_iov)[UDP_IOV_ETH] = IOV_OF_LVALUE(udp4_eth_hdr);
@@ -404,11 +406,12 @@ static void udp_tap_prepare(const struct mmsghdr *mmh, unsigned idx,
* udp_sock_recverr() - Receive and clear an error from a socket
* @s: Socket to receive from
*
- * Return: true if errors received and processed, false if no more errors
+ * Return: 1 if error received and processed, 0 if no more errors in queue, < 0
+ * if there was an error reading the queue
*
* #syscalls recvmsg
*/
-static bool udp_sock_recverr(int s)
+static int udp_sock_recverr(int s)
{
const struct sock_extended_err *ee;
const struct cmsghdr *hdr;
@@ -425,14 +428,16 @@ static bool udp_sock_recverr(int s)
rc = recvmsg(s, &mh, MSG_ERRQUEUE);
if (rc < 0) {
- if (errno != EAGAIN && errno != EWOULDBLOCK)
- err_perror("Failed to read error queue");
- return false;
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ return 0;
+
+ err_perror("UDP: Failed to read error queue");
+ return -1;
}
if (!(mh.msg_flags & MSG_ERRQUEUE)) {
err("Missing MSG_ERRQUEUE flag reading error queue");
- return false;
+ return -1;
}
hdr = CMSG_FIRSTHDR(&mh);
@@ -441,16 +446,63 @@ static bool udp_sock_recverr(int s)
(hdr->cmsg_level == IPPROTO_IPV6 &&
hdr->cmsg_type == IPV6_RECVERR))) {
err("Unexpected cmsg reading error queue");
- return false;
+ return -1;
}
ee = (const struct sock_extended_err *)CMSG_DATA(hdr);
/* TODO: When possible propagate and otherwise handle errors */
debug("%s error on UDP socket %i: %s",
- str_ee_origin(ee), s, strerror(ee->ee_errno));
+ str_ee_origin(ee), s, strerror_(ee->ee_errno));
+
+ return 1;
+}
- return true;
+/**
+ * udp_sock_errs() - Process errors on a socket
+ * @c: Execution context
+ * @s: Socket to receive from
+ * @events: epoll events bitmap
+ *
+ * Return: Number of errors handled, or < 0 if we have an unrecoverable error
+ */
+int udp_sock_errs(const struct ctx *c, int s, uint32_t events)
+{
+ unsigned n_err = 0;
+ socklen_t errlen;
+ int rc, err;
+
+ ASSERT(!c->no_udp);
+
+ if (!(events & EPOLLERR))
+ return 0; /* Nothing to do */
+
+ /* Empty the error queue */
+ while ((rc = udp_sock_recverr(s)) > 0)
+ n_err += rc;
+
+ if (rc < 0)
+ return -1; /* error reading error, unrecoverable */
+
+ errlen = sizeof(err);
+ if (getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &errlen) < 0 ||
+ errlen != sizeof(err)) {
+ err_perror("Error reading SO_ERROR");
+ return -1; /* error reading error, unrecoverable */
+ }
+
+ if (err) {
+ debug("Unqueued error on UDP socket %i: %s", s, strerror_(err));
+ n_err++;
+ }
+
+ if (!n_err) {
+ /* EPOLLERR, but no errors to clear !? */
+ err("EPOLLERR event without reported errors on socket %i", s);
+ return -1; /* no way to clear, unrecoverable */
+ }
+
+ return n_err;
}
/**
@@ -460,7 +512,9 @@ static bool udp_sock_recverr(int s)
* @events: epoll events bitmap
* @mmh mmsghdr array to receive into
*
- * #syscalls recvmmsg
+ * Return: Number of datagrams received
+ *
+ * #syscalls recvmmsg arm:recvmmsg_time64 i686:recvmmsg_time64
*/
static int udp_sock_recv(const struct ctx *c, int s, uint32_t events,
struct mmsghdr *mmh)
@@ -476,12 +530,6 @@ static int udp_sock_recv(const struct ctx *c, int s, uint32_t events,
ASSERT(!c->no_udp);
- /* Clear any errors first */
- if (events & EPOLLERR) {
- while (udp_sock_recverr(s))
- ;
- }
-
if (!(events & EPOLLIN))
return 0;
@@ -495,7 +543,7 @@ static int udp_sock_recv(const struct ctx *c, int s, uint32_t events,
}
/**
- * udp_listen_sock_handler() - Handle new data from socket
+ * udp_buf_listen_sock_handler() - Handle new data from socket
* @c: Execution context
* @ref: epoll reference
* @events: epoll events bitmap
@@ -503,13 +551,21 @@ static int udp_sock_recv(const struct ctx *c, int s, uint32_t events,
*
* #syscalls recvmmsg
*/
-void udp_listen_sock_handler(const struct ctx *c, union epoll_ref ref,
- uint32_t events, const struct timespec *now)
+static void udp_buf_listen_sock_handler(const struct ctx *c,
+ union epoll_ref ref, uint32_t events,
+ const struct timespec *now)
{
- struct mmsghdr *mmh_recv = ref.udp.v6 ? udp6_mh_recv : udp4_mh_recv;
+ const socklen_t sasize = sizeof(udp_meta[0].s_in);
int n, i;
- if ((n = udp_sock_recv(c, ref.fd, events, mmh_recv)) <= 0)
+ if (udp_sock_errs(c, ref.fd, events) < 0) {
+ err("UDP: Unrecoverable error on listening socket:"
+ " (%s port %hu)", pif_name(ref.udp.pif), ref.udp.port);
+ /* FIXME: what now? close/re-open socket? */
+ return;
+ }
+
+ if ((n = udp_sock_recv(c, ref.fd, events, udp_mh_recv)) <= 0)
return;
/* We divide datagrams into batches based on how we need to send them,
@@ -518,6 +574,7 @@ void udp_listen_sock_handler(const struct ctx *c, union epoll_ref ref,
* populate it one entry *ahead* of the loop counter.
*/
udp_meta[0].tosidx = udp_flow_from_sock(c, ref, &udp_meta[0].s_in, now);
+ udp_mh_recv[0].msg_hdr.msg_namelen = sasize;
for (i = 0; i < n; ) {
flow_sidx_t batchsidx = udp_meta[i].tosidx;
uint8_t batchpif = pif_at_sidx(batchsidx);
@@ -525,10 +582,11 @@ void udp_listen_sock_handler(const struct ctx *c, union epoll_ref ref,
do {
if (pif_is_socket(batchpif)) {
- udp_splice_prepare(mmh_recv, i);
+ udp_splice_prepare(udp_mh_recv, i);
} else if (batchpif == PIF_TAP) {
- udp_tap_prepare(mmh_recv, i,
- flowside_at_sidx(batchsidx));
+ udp_tap_prepare(udp_mh_recv, i,
+ flowside_at_sidx(batchsidx),
+ false);
}
if (++i >= n)
@@ -537,6 +595,7 @@ void udp_listen_sock_handler(const struct ctx *c, union epoll_ref ref,
udp_meta[i].tosidx = udp_flow_from_sock(c, ref,
&udp_meta[i].s_in,
now);
+ udp_mh_recv[i].msg_hdr.msg_namelen = sasize;
} while (flow_sidx_eq(udp_meta[i].tosidx, batchsidx));
if (pif_is_socket(batchpif)) {
@@ -561,7 +620,26 @@ void udp_listen_sock_handler(const struct ctx *c, union epoll_ref ref,
}
/**
- * udp_reply_sock_handler() - Handle new data from flow specific socket
+ * udp_listen_sock_handler() - Handle new data from socket
+ * @c: Execution context
+ * @ref: epoll reference
+ * @events: epoll events bitmap
+ * @now: Current timestamp
+ */
+void udp_listen_sock_handler(const struct ctx *c,
+ union epoll_ref ref, uint32_t events,
+ const struct timespec *now)
+{
+ if (c->mode == MODE_VU) {
+ udp_vu_listen_sock_handler(c, ref, events, now);
+ return;
+ }
+
+ udp_buf_listen_sock_handler(c, ref, events, now);
+}
+
+/**
+ * udp_buf_reply_sock_handler() - Handle new data from flow specific socket
* @c: Execution context
* @ref: epoll reference
* @events: epoll events bitmap
@@ -569,22 +647,28 @@ void udp_listen_sock_handler(const struct ctx *c, union epoll_ref ref,
*
* #syscalls recvmmsg
*/
-void udp_reply_sock_handler(const struct ctx *c, union epoll_ref ref,
- uint32_t events, const struct timespec *now)
+static void udp_buf_reply_sock_handler(const struct ctx *c, union epoll_ref ref,
+ uint32_t events,
+ const struct timespec *now)
{
- const struct flowside *fromside = flowside_at_sidx(ref.flowside);
flow_sidx_t tosidx = flow_sidx_opposite(ref.flowside);
const struct flowside *toside = flowside_at_sidx(tosidx);
struct udp_flow *uflow = udp_at_sidx(ref.flowside);
- int from_s = uflow->s[ref.flowside.sidei];
- bool v6 = !inany_v4(&fromside->eaddr);
- struct mmsghdr *mmh_recv = v6 ? udp6_mh_recv : udp4_mh_recv;
uint8_t topif = pif_at_sidx(tosidx);
- int n, i;
+ int n, i, from_s;
ASSERT(!c->no_udp && uflow);
- if ((n = udp_sock_recv(c, from_s, events, mmh_recv)) <= 0)
+ from_s = uflow->s[ref.flowside.sidei];
+
+ if (udp_sock_errs(c, from_s, events) < 0) {
+ flow_err(uflow, "Unrecoverable error on reply socket");
+ flow_err_details(uflow);
+ udp_flow_close(c, uflow);
+ return;
+ }
+
+ if ((n = udp_sock_recv(c, from_s, events, udp_mh_recv)) <= 0)
return;
flow_trace(uflow, "Received %d datagrams on reply socket", n);
@@ -592,9 +676,11 @@ void udp_reply_sock_handler(const struct ctx *c, union epoll_ref ref,
for (i = 0; i < n; i++) {
if (pif_is_socket(topif))
- udp_splice_prepare(mmh_recv, i);
+ udp_splice_prepare(udp_mh_recv, i);
else if (topif == PIF_TAP)
- udp_tap_prepare(mmh_recv, i, toside);
+ udp_tap_prepare(udp_mh_recv, i, toside, false);
+ /* Restore sockaddr length clobbered by recvmsg() */
+ udp_mh_recv[i].msg_hdr.msg_namelen = sizeof(udp_meta[i].s_in);
}
if (pif_is_socket(topif)) {
@@ -610,6 +696,24 @@ void udp_reply_sock_handler(const struct ctx *c, union epoll_ref ref,
}
/**
+ * udp_reply_sock_handler() - Handle new data from flow specific socket
+ * @c: Execution context
+ * @ref: epoll reference
+ * @events: epoll events bitmap
+ * @now: Current timestamp
+ */
+void udp_reply_sock_handler(const struct ctx *c, union epoll_ref ref,
+ uint32_t events, const struct timespec *now)
+{
+ if (c->mode == MODE_VU) {
+ udp_vu_reply_sock_handler(c, ref, events, now);
+ return;
+ }
+
+ udp_buf_reply_sock_handler(c, ref, events, now);
+}
+
+/**
* udp_tap_handler() - Handle packets from tap
* @c: Execution context
* @pif: pif on which the packet is arriving
@@ -719,55 +823,62 @@ int udp_tap_handler(const struct ctx *c, uint8_t pif,
* udp_sock_init() - Initialise listening sockets for a given port
* @c: Execution context
* @ns: In pasta mode, if set, bind with loopback address in namespace
- * @af: Address family to select a specific IP version, or AF_UNSPEC
* @addr: Pointer to address for binding, NULL if not configured
* @ifname: Name of interface to bind to, NULL if not configured
* @port: Port, host order
*
* Return: 0 on (partial) success, negative error code on (complete) failure
*/
-int udp_sock_init(const struct ctx *c, int ns, sa_family_t af,
- const void *addr, const char *ifname, in_port_t port)
+int udp_sock_init(const struct ctx *c, int ns, const union inany_addr *addr,
+ const char *ifname, in_port_t port)
{
- union udp_listen_epoll_ref uref = { .port = port };
- int s, r4 = FD_REF_MAX + 1, r6 = FD_REF_MAX + 1;
+ union udp_listen_epoll_ref uref = {
+ .pif = ns ? PIF_SPLICE : PIF_HOST,
+ .port = port,
+ };
+ int r4 = FD_REF_MAX + 1, r6 = FD_REF_MAX + 1;
ASSERT(!c->no_udp);
- if (ns)
- uref.pif = PIF_SPLICE;
- else
- uref.pif = PIF_HOST;
+ if (!addr && c->ifi4 && c->ifi6 && !ns) {
+ int s;
- if ((af == AF_INET || af == AF_UNSPEC) && c->ifi4) {
- uref.v6 = 0;
+ /* Attempt to get a dual stack socket */
+ s = pif_sock_l4(c, EPOLL_TYPE_UDP_LISTEN, PIF_HOST,
+ NULL, ifname, port, uref.u32);
+ udp_splice_init[V4][port] = s < 0 ? -1 : s;
+ udp_splice_init[V6][port] = s < 0 ? -1 : s;
+ if (IN_INTERVAL(0, FD_REF_MAX, s))
+ return 0;
+ }
+ if ((!addr || inany_v4(addr)) && c->ifi4) {
if (!ns) {
- r4 = s = sock_l4(c, AF_INET, EPOLL_TYPE_UDP_LISTEN,
- addr, ifname, port, uref.u32);
+ r4 = pif_sock_l4(c, EPOLL_TYPE_UDP_LISTEN, PIF_HOST,
+ addr ? addr : &inany_any4, ifname,
+ port, uref.u32);
- udp_splice_init[V4][port] = s < 0 ? -1 : s;
+ udp_splice_init[V4][port] = r4 < 0 ? -1 : r4;
} else {
- r4 = s = sock_l4(c, AF_INET, EPOLL_TYPE_UDP_LISTEN,
- &in4addr_loopback,
- ifname, port, uref.u32);
- udp_splice_ns[V4][port] = s < 0 ? -1 : s;
+ r4 = pif_sock_l4(c, EPOLL_TYPE_UDP_LISTEN, PIF_SPLICE,
+ &inany_loopback4, ifname,
+ port, uref.u32);
+ udp_splice_ns[V4][port] = r4 < 0 ? -1 : r4;
}
}
- if ((af == AF_INET6 || af == AF_UNSPEC) && c->ifi6) {
- uref.v6 = 1;
-
+ if ((!addr || !inany_v4(addr)) && c->ifi6) {
if (!ns) {
- r6 = s = sock_l4(c, AF_INET6, EPOLL_TYPE_UDP_LISTEN,
- addr, ifname, port, uref.u32);
+ r6 = pif_sock_l4(c, EPOLL_TYPE_UDP_LISTEN, PIF_HOST,
+ addr ? addr : &inany_any6, ifname,
+ port, uref.u32);
- udp_splice_init[V6][port] = s < 0 ? -1 : s;
+ udp_splice_init[V6][port] = r6 < 0 ? -1 : r6;
} else {
- r6 = s = sock_l4(c, AF_INET6, EPOLL_TYPE_UDP_LISTEN,
- &in6addr_loopback,
- ifname, port, uref.u32);
- udp_splice_ns[V6][port] = s < 0 ? -1 : s;
+ r6 = pif_sock_l4(c, EPOLL_TYPE_UDP_LISTEN, PIF_SPLICE,
+ &inany_loopback6, ifname,
+ port, uref.u32);
+ udp_splice_ns[V6][port] = r6 < 0 ? -1 : r6;
}
}
@@ -834,7 +945,7 @@ static void udp_port_rebind(struct ctx *c, bool outbound)
if ((c->ifi4 && socks[V4][port] == -1) ||
(c->ifi6 && socks[V6][port] == -1))
- udp_sock_init(c, outbound, AF_UNSPEC, NULL, NULL, port);
+ udp_sock_init(c, outbound, NULL, NULL, port);
}
}