Date: Thu, 23 Jan 2014 17:31:04 -0700 From: Alan Somers <asomers@freebsd.org> To: Adrian Chadd <adrian@freebsd.org> Cc: FreeBSD Net <freebsd-net@freebsd.org> Subject: Re: kern/185813: SOCK_SEQPACKET AF_UNIX sockets with asymmetrical buffers drop packets Message-ID: <CAOtMX2hx9AwyuWceiQ0Nt7TjRWqDb2FZ4cAS21tBQb3QTZh39w@mail.gmail.com> In-Reply-To: <CAJ-Vmom6zOMugGUC5y9CPoQN9Z_QzxGjGwshBnyEwRV62f3AYQ@mail.gmail.com> References: <CAOtMX2hkVrT8DmAhPXDO2zkpyzH1VGwXd2SC8VcqqCfycJ3F6w@mail.gmail.com> <CAJ-Vmom6zOMugGUC5y9CPoQN9Z_QzxGjGwshBnyEwRV62f3AYQ@mail.gmail.com>
next in thread | previous in thread | raw e-mail | index | archive | help
On Thu, Jan 23, 2014 at 11:26 AM, Adrian Chadd <adrian@freebsd.org> wrote: > Well, shouldn't we fix the API/code so it doesn't drop packets, > regardless of the sensibility or non-sensibility of different > transmit/receive buffer sizes? That would be nice, but it may be beyond my ability to do so. The relevant code is very complicated, and most of it is in domain-agnostic code where we can't introduce AF_UNIX specific special cases. It may be possible to change the single-buffer optimization to use the receiving sockbuf's size for space calculations in uipc_send() instead of the transmitting sockbuf's size. I could try to do that, though it may cause existing programs to fail if they're depending on setsockopt(s, SOL_SOCKET, SO_SNDBUF, ...) to have an effect. -Alan > > > -a > > > On 23 January 2014 10:02, Alan Somers <asomers@freebsd.org> wrote: >> There is a buffer space calculation bug in the send path for >> SOCK_SEQPACKET AF_UNIX sockets. The result is that, if the sending >> and receiving buffer sizes are different, the kernel will drop >> messages and leak mbufs. A more detailed description is available in >> the PR. >> >> The labyrinthine nature of the networking code makes it difficult to >> directly fix the space calculation. It's especially hard due to the >> optimization that AF_UNIX sockets have only a single socket buffer. >> As implemented, they store data in the receiving sockbuf, but use the >> transmitting sockbuf for space calculations. That's even true of >> SOCK_STREAM sockets. They only work due to an accident; they don't >> end up doing the same space calculation that trips up SOCK_SEQPACKET >> sockets. >> >> Instead, I propose modifying the kernel to force an AF_UNIX socket >> pair's buffers to always have the same size. That is, if you call >> setsockopt(s, SOL_SOCKET, SO_SNDBUF, whatever, whatever), the kernel >> will adjust both s's send buffer and the connected socket's receive >> buffer. This solution also solves another annoying problem: currently >> there is no way for a program to effectively change the size of its >> receiving buffers. If you call setsockopt(s, SOL_SOCKET, SO_RCVBUF, >> whatever, whatever) on an AF_UNIX socket, it will have no effect on >> how packets are actually handled. >> >> The attached patch implements my suggestion for setsockopt. It's >> obviously not perfect; it doesn't handle the case where you call >> setsockopt() before connect() and it introduces an unfortunate >> #include, but it's a working proof of concept. With this patch, the >> recently added ATF test case >> sys/kern/unix_seqpacket_test:pipe_simulator_128k_8k passes. Does this >> look like the correct approach? >> >> >> Index: uipc_socket.c >> =================================================================== >> --- uipc_socket.c (revision 261055) >> +++ uipc_socket.c (working copy) >> @@ -133,6 +133,8 @@ >> #include <sys/sx.h> >> #include <sys/sysctl.h> >> #include <sys/uio.h> >> +#include <sys/un.h> >> +#include <sys/unpcb.h> >> #include <sys/jail.h> >> #include <sys/syslog.h> >> #include <netinet/in.h> >> @@ -2382,6 +2384,8 @@ >> int >> sosetopt(struct socket *so, struct sockopt *sopt) >> { >> + struct socket* so2; >> + struct unpcb *unpcb, *unpcb2; >> int error, optval; >> struct linger l; >> struct timeval tv; >> @@ -2503,6 +2507,32 @@ >> } >> (sopt->sopt_name == SO_SNDBUF ? &so->so_snd : >> &so->so_rcv)->sb_flags &= ~SB_AUTOSIZE; >> + if (so->so_proto->pr_domain->dom_family != >> + PF_LOCAL || >> + so->so_type != SOCK_SEQPACKET) >> + break; >> + /* >> + * For unix domain seqpacket sockets, we set the >> + * bufsize on both ends of the socket. PR >> + * kern/185813 >> + */ >> + unpcb = (struct unpcb*)(so->so_pcb); >> + if (NULL == unpcb) >> + break; /* Shouldn't ever happen */ >> + unpcb2 = unpcb->unp_conn; >> + if (NULL == unpcb2) >> + break; /* For unconnected sockets */ >> + so2 = unpcb2->unp_socket; >> + if (NULL == so2) >> + break; /* Shouldn't ever happen? */ >> + if (sbreserve(sopt->sopt_name == SO_SNDBUF ? >> + &so2->so_rcv : &so2->so_snd, (u_long)optval, >> + so, curthread) == 0) { >> + error = ENOBUFS; >> + goto bad; >> + } >> + (sopt->sopt_name == SO_SNDBUF ? &so2->so_rcv : >> + &so2->so_snd)->sb_flags &= ~SB_AUTOSIZE; >> break; >> >> /* >> >> >> -Alan >> _______________________________________________ >> freebsd-net@freebsd.org mailing list >> http://lists.freebsd.org/mailman/listinfo/freebsd-net >> To unsubscribe, send any mail to "freebsd-net-unsubscribe@freebsd.org"
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CAOtMX2hx9AwyuWceiQ0Nt7TjRWqDb2FZ4cAS21tBQb3QTZh39w>