udp: Decide whether to "splice" per datagram rather than per socket
Currently we have special sockets for receiving datagrams from locahost which can use the optimized "splice" path rather than going across the tap interface. We want to loosen this so that sockets can receive sockets that will be forwarded by both the spliced and non-spliced paths. To do this, we alter the meaning of the @splice bit in the reference to mean that packets receieved on this socket *can* be spliced, not that they *will* be spliced. They'll only actually be spliced if they come from 127.0.0.1 or ::1. We can't (for now) remove the splice bit entirely, unlike with TCP. Our gateway mapping means that if the ns initiates communication to the gw address, we'll translate that to target 127.0.0.1 on the host side. Reply packets will therefore have source address 127.0.0.1 when received on the host, but these need to go via the tap path where that will be translated back to the gateway address. We need the @splice bit to distinguish that case from packets going from localhost to a port mapped explicitly with -u which should be spliced. Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
This commit is contained in:
parent
8a10f23720
commit
8d503e825f
2 changed files with 34 additions and 20 deletions
48
udp.c
48
udp.c
|
@ -513,16 +513,25 @@ static int udp_splice_new_ns(void *arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sa_port() - Determine port from a sockaddr_in or sockaddr_in6
|
* udp_mmh_splice_port() - Is source address of message suitable for splicing?
|
||||||
* @v6: Is @sa a sockaddr_in6 (otherwise sockaddr_in)?
|
* @v6: Is @sa a sockaddr_in6 (otherwise sockaddr_in)?
|
||||||
* @sa: Pointer to either sockaddr_in or sockaddr_in6
|
* @mmh: mmsghdr of incoming message
|
||||||
|
*
|
||||||
|
* Return: if @sa refers to localhost (127.0.0.1 or ::1) the port from
|
||||||
|
* @sa in host order, otherwise -1.
|
||||||
*/
|
*/
|
||||||
static in_port_t sa_port(bool v6, const void *sa)
|
static int udp_mmh_splice_port(bool v6, const struct mmsghdr *mmh)
|
||||||
{
|
{
|
||||||
const struct sockaddr_in6 *sa6 = sa;
|
const struct sockaddr_in6 *sa6 = mmh->msg_hdr.msg_name;
|
||||||
const struct sockaddr_in *sa4 = sa;
|
const struct sockaddr_in *sa4 = mmh->msg_hdr.msg_name;
|
||||||
|
|
||||||
return v6 ? ntohs(sa6->sin6_port) : ntohs(sa4->sin_port);
|
if (v6 && IN6_IS_ADDR_LOOPBACK(&sa6->sin6_addr))
|
||||||
|
return ntohs(sa6->sin6_port);
|
||||||
|
|
||||||
|
if (!v6 && IN4_IS_ADDR_LOOPBACK(&sa4->sin_addr))
|
||||||
|
return ntohs(sa4->sin_port);
|
||||||
|
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -926,23 +935,28 @@ void udp_sock_handler(const struct ctx *c, union epoll_ref ref, uint32_t events,
|
||||||
if (n <= 0)
|
if (n <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!ref.r.p.udp.udp.splice) {
|
|
||||||
udp_tap_send(c, 0, n, dstport, v6, now);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < n; i += m) {
|
for (i = 0; i < n; i += m) {
|
||||||
in_port_t src = sa_port(v6, mmh_recv[i].msg_hdr.msg_name);
|
int splicefrom = -1;
|
||||||
|
m = n;
|
||||||
|
|
||||||
|
if (ref.r.p.udp.udp.splice) {
|
||||||
|
splicefrom = udp_mmh_splice_port(v6, mmh_recv + i);
|
||||||
|
|
||||||
for (m = 1; i + m < n; m++) {
|
for (m = 1; i + m < n; m++) {
|
||||||
void *mname = mmh_recv[i + m].msg_hdr.msg_name;
|
int p;
|
||||||
if (sa_port(v6, mname) != src)
|
|
||||||
|
p = udp_mmh_splice_port(v6, mmh_recv + i + m);
|
||||||
|
if (p != splicefrom)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
udp_splice_sendfrom(c, i, m, src, dstport, v6,
|
if (splicefrom >= 0)
|
||||||
ref.r.p.udp.udp.ns, ref.r.p.udp.udp.orig,
|
udp_splice_sendfrom(c, i, m, splicefrom, dstport,
|
||||||
now);
|
v6, ref.r.p.udp.udp.ns,
|
||||||
|
ref.r.p.udp.udp.orig, now);
|
||||||
|
else
|
||||||
|
udp_tap_send(c, i, m, dstport, v6, now);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
2
udp.h
2
udp.h
|
@ -22,7 +22,7 @@ void udp_update_l2_buf(const unsigned char *eth_d, const unsigned char *eth_s,
|
||||||
/**
|
/**
|
||||||
* union udp_epoll_ref - epoll reference portion for TCP connections
|
* union udp_epoll_ref - epoll reference portion for TCP connections
|
||||||
* @bound: Set if this file descriptor is a bound socket
|
* @bound: Set if this file descriptor is a bound socket
|
||||||
* @splice: Set if descriptor is associated to "spliced" connection
|
* @splice: Set if descriptor packets to be "spliced"
|
||||||
* @orig: Set if a spliced socket which can originate "connections"
|
* @orig: Set if a spliced socket which can originate "connections"
|
||||||
* @ns: Set if this is a socket in the pasta network namespace
|
* @ns: Set if this is a socket in the pasta network namespace
|
||||||
* @v6: Set for IPv6 sockets or connections
|
* @v6: Set for IPv6 sockets or connections
|
||||||
|
|
Loading…
Reference in a new issue