Subject: Re: sendto() and ENOBUFS question..
To: None <tech-net@netbsd.org>
From: None <sudog@sudog.com>
List: tech-net
Date: 05/14/2002 19:36:16
> Just a thought: do you know that you are getting ENOBUFS from the
> driver?  Most computers today can generate output way faster than the
> devices can manage, so it's possible that you are getting the failure
> from actually taking up all the mbufs in the system.  What does 'netstat
> -m' show?  Don't forget that there really isn't any backpressure in this
> case, either from UDP or from the driver (AFAIK).
>
> Does the socket layer even check with sowriteable() in the case of UDP?
> Last I looked, data on datagram sockets went straight to the protocol
> layer, bypassing all (socket) buffering completely.
>
> Regards,
>
> Justin

I've got a gut feeling that the ENOBUFS is coming from here:

netinet/udp_usrreq.c:882

        M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT);
        if (m == 0) {
                error = ENOBUFS;
                goto release;
        }

So, the question is, does select() or poll() make a check to ensure
that ENOBUFS won't show up when udp_output() is called? Or should it?

If not, how would I, in userland, cleanly wait until I can do another
udp_output safely without ENOBUFS showing up?

Uh oh.. It seems I am doomed to run a guessing heuristic on when I
think sendto() will succeed or fail.. I just checked in the nfs
drivers to see how they handle it.. when I saw this:

nfs/nfs_socket.c:450:

if (error == ENOBUFS && so->so_type == SOCK_DGRAM) {
/*
   * We're too fast for the network/driver,
   * and UDP isn't flowcontrolled.
   * We need to resend. This is not fatal,
   * just try again.
   *
   * Could be smarter here by doing some sort
   * of a backoff, but this is rare.
   */

Doh!

Any pointers? I'd hate to have to write something unreliable to patch
the kernel with.

Thanks for your patience.

-Marc Tooley