Thread (8 messages) 8 messages, 3 authors, 2024-02-10

Re: SOF_TIMESTAMPING_OPT_ID is unreliable when sendmsg fails

From: Andy Lutomirski <luto@amacapital.net>
Date: 2024-02-08 20:40:49

On Thu, Feb 8, 2024 at 12:05 PM Andy Lutomirski [off-list ref] wrote:
On Thu, Feb 8, 2024 at 11:55 AM Vadim Fedorenko
[off-list ref] wrote:
quoted
On 08/02/2024 18:02, Andy Lutomirski wrote:
quoted
I’ve been using OPT_ID-style timestamping for years, but for some
reason this issue only bit me last week: if sendmsg() fails on a UDP
or ping socket, sk_tskey is poorly.  It may or may not get incremented
by the failed sendmsg().
Well, there are several error paths, for sure. For the sockets you
mention the increment of tskey happens at __ip{,6}_append_data. There
are 2 different types of failures which can happen after the increment.
The first is MTU check fail, another one is memory allocation failures.
I believe we can move increment to a later position, after MTU check in
both functions to avoid first type of problem.
For reasons that I still haven't deciphered, I'm sporadically getting
EHOSTUNREACH after the increment.  I can't find anything in the code
that would cause that, and every time I try to instrument it, it stops
happening :(  I sendmsg to the same destination several times in rapid
succession, and at most one of them will get EHOSTUNREACH.
I caught it in strace, finally.  And I also finally grepped the right
part of the kernel tree to (I think) find the offending call chain.

__ip_append_data first increments sk_tskey.  Then it does:

            if (transhdrlen) {
                skb = sock_alloc_send_skb(sk, alloclen,
                        (flags & MSG_DONTWAIT), &err);

(I have no idea why the transhdrlen path is different.)  That does:

static inline struct sk_buff *sock_alloc_send_skb(struct sock *sk,
                          unsigned long size,
                          int noblock, int *errcode)
{
    return sock_alloc_send_pskb(sk, size, 0, noblock, errcode, 0);
}

That does:

struct sk_buff *sock_alloc_send_pskb(struct sock *sk, unsigned long header_len,
                     unsigned long data_len, int noblock,
                     int *errcode, int max_page_order)
{
    struct sk_buff *skb;
    long timeo;
    int err;

    timeo = sock_sndtimeo(sk, noblock);
    for (;;) {
        err = sock_error(sk);

I'm utterly baffled why that check makes any sense whatsoever.  git
blame informs me that it predates 2002.

I'll contemplate a bit more and send a patch.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help