On 2020-11-05 00:59, Jakub Kicinski wrote:
On Tue, 3 Nov 2020 11:18:25 -0800 Saeed Mahameed wrote:
From: Maxim Mikityanskiy <maxi...@mellanox.com>

On resync, the driver calls inet_lookup_established
(__inet6_lookup_established) that increases sk_refcnt of the socket. To
decrease it, the driver set skb->destructor to sock_edemux. However, it
didn't work well, because the TCP stack also sets this destructor for
early demux, and the refcount gets decreased only once

Why is the stack doing early_demux if there is already a socket
assigned? Or is it not early_demux but something else?
Can you point us at the code?

I thought this was the code that was in conflict with setting skb->destructor in the driver:

void skb_set_owner_w(struct sk_buff *skb, struct sock *sk)
{
        skb_orphan(skb);
        skb->sk = sk;
#ifdef CONFIG_INET
        if (unlikely(!sk_fullsock(sk))) {
                skb->destructor = sock_edemux;
                sock_hold(sk);
                return;
        }
#endif

However, after taking another look, it seems that the root cause is somewhere else. This piece of code actually calls skb_orphan before reassigning the destructor.

I'll debug it further to try to find where the destructor is replaced or just not called.

IPv4:
        if (net->ipv4.sysctl_ip_early_demux &&
            !skb_dst(skb) &&
            !skb->sk &&                              <============
            !ip_is_fragment(iph)) {
                const struct net_protocol *ipprot;
                int protocol = iph->protocol;

                ipprot = rcu_dereference(inet_protos[protocol]);
                if (ipprot && (edemux = READ_ONCE(ipprot->early_demux))) {
                        err = INDIRECT_CALL_2(edemux, tcp_v4_early_demux,
                                              udp_v4_early_demux, skb);
                        if (unlikely(err))
                                goto drop_error;
                        /* must reload iph, skb->head might have changed */
                        iph = ip_hdr(skb);
                }
        }

IPv6:
        if (net->ipv4.sysctl_ip_early_demux && !skb_dst(skb) && skb->sk == 
NULL) {
                                                                 ~~~~~~~~~~~~~~~
                const struct inet6_protocol *ipprot;

                ipprot = rcu_dereference(inet6_protos[ipv6_hdr(skb)->nexthdr]);
                if (ipprot && (edemux = READ_ONCE(ipprot->early_demux)))
                        INDIRECT_CALL_2(edemux, tcp_v6_early_demux,
                                        udp_v6_early_demux, skb);
        }


Reply via email to