Re: [PATCH net-next v7 08/16] quic: add path management
Xin Long <[email protected]> Tue, 20 Jan 2026 16:06:53 -0500
| Newsgroups | dev.linux.lists.quic,dev.linux.lists.kernel-tls-handshake,org.kernel.vger.linux-cifs,org.kernel.vger.netdev |
|---|---|
| Message-ID | <CADvbK_chN0KTnibDW6VL3pR4iPQqrHznDXYCUDneB=vEnVD0MA@mail.gmail.com> |
On Tue, Jan 20, 2026 at 10:34 AM Xin Long <[email protected]> wrote: > > On Tue, Jan 20, 2026 at 9:13 AM Paolo Abeni <[email protected]> wrote: > > > > On 1/15/26 4:11 PM, Xin Long wrote: > > > @@ -0,0 +1,524 @@ > > > +// SPDX-License-Identifier: GPL-2.0-or-later > > > +/* QUIC kernel implementation > > > + * (C) Copyright Red Hat Corp. 2023 > > > + * > > > + * This file is part of the QUIC kernel implementation > > > + * > > > + * Initialization/cleanup for QUIC protocol support. > > > + * > > > + * Written or modified by: > > > + * Xin Long <[email protected]> > > > + */ > > > + > > > +#include <net/udp_tunnel.h> > > > +#include <linux/quic.h> > > > + > > > +#include "common.h" > > > +#include "family.h" > > > +#include "path.h" > > > + > > > +static int (*quic_path_rcv)(struct sock *sk, struct sk_buff *skb, u8 err); > > > > It's unclear why an indirect call is needed here. At least some > > explanation is needed in the commit message, possibly you could call > > directly a static function. > > > This patchset makes the path subcomponent more independent from the core > implementation. Aside from a few shared helper functions, it doesn't > rely on code outside the subcomponent, in particular socket.c and > packet.c. > > Other subcomponents, such as stream, connid, pnspace, cong, > crypto, common, and family follow the same approach. They expose > APIs to the core QUIC logic and don’t see the main process. > > Will leave an explanation here. > To achieve this, instead of introducing an indirect call, we can use an 'extern' declaration of quic_packet_rcv() once it is introduced. Before that point, the code simply falls back to calling kfree_skb(skb). Will update it. Thanks. > > > + > > > +static int quic_udp_rcv(struct sock *sk, struct sk_buff *skb) > > > +{ > > > + memset(skb->cb, 0, sizeof(skb->cb)); > > > + QUIC_SKB_CB(skb)->seqno = -1; > > > + QUIC_SKB_CB(skb)->time = quic_ktime_get_us(); > > > + > > > + skb_pull(skb, sizeof(struct udphdr)); > > > + skb_dst_force(skb); > > > + quic_path_rcv(sk, skb, 0); > > > + return 0; > > > > Why not: > > return quic_path_rcv(sk, skb, 0); > > ? > I checked the udp tunnel users: > > - bareudp: bareudp_udp_encap_recv() > - vxlan: vxlan_rcv() > - geneve: geneve_udp_encap_recv() > - tipc: tipc_udp_recv() > - sctp: sctp_udp_rcv() > > they all are returning 0 in .encap_udp(), I think because they all > take care of the > skb freeing in their err path already. > > is it safe to return error to UDP stack if the skb is already freed? > Do you know? > > > > > > +static struct quic_udp_sock *quic_udp_sock_create(struct sock *sk, union quic_addr *a) > > > +{ > > > + struct udp_tunnel_sock_cfg tuncfg = {}; > > > + struct udp_port_cfg udp_conf = {}; > > > + struct net *net = sock_net(sk); > > > + struct quic_uhash_head *head; > > > + struct quic_udp_sock *us; > > > + struct socket *sock; > > > + > > > + us = kzalloc(sizeof(*us), GFP_KERNEL); > > > + if (!us) > > > + return NULL; > > > + > > > + quic_udp_conf_init(sk, &udp_conf, a); > > > + if (udp_sock_create(net, &udp_conf, &sock)) { > > > + pr_debug("%s: failed to create udp sock\n", __func__); > > > + kfree(us); > > > + return NULL; > > > + } > > > + > > > + tuncfg.encap_type = 1; > > > + tuncfg.encap_rcv = quic_udp_rcv; > > > + tuncfg.encap_err_lookup = quic_udp_err; > > > + setup_udp_tunnel_sock(net, sock, &tuncfg); > > > + > > > + refcount_set(&us->refcnt, 1); > > > + us->sk = sock->sk; > > > + memcpy(&us->addr, a, sizeof(*a)); > > > + us->bind_ifindex = sk->sk_bound_dev_if; > > > + > > > + head = quic_udp_sock_head(net, ntohs(a->v4.sin_port)); > > > + hlist_add_head(&us->node, &head->head); > > > + INIT_WORK(&us->work, quic_udp_sock_put_work); > > > + > > > + return us; > > > +} > > > + > > > +static bool quic_udp_sock_get(struct quic_udp_sock *us) > > > +{ > > > + return refcount_inc_not_zero(&us->refcnt); > > > +} > > > + > > > +static void quic_udp_sock_put(struct quic_udp_sock *us) > > > +{ > > > + if (refcount_dec_and_test(&us->refcnt)) > > > + queue_work(quic_wq, &us->work); > > > > Why using a workqueue here? AFAICS all the caller are in process > > context. Is that to break a possible deadlock due to nested mutex? > > Likely a comment on the refcount/locking scheme would help. > > > quic_udp_sock_put() will also be called in the RX path via > quic_path_unbind() for the connection migration (after changing > to a new path.), which is in the patchset-2. > > I will leave a comment for an explanation here. > > Thanks.