Re: [PATCH net-next v10 15/15] quic: add packet parser base
From: Paolo Abeni <pabeni@redhat.com>
Date: 2026-03-03 09:16:51
Also in:
linux-cifs
On 2/25/26 3:34 AM, Xin Long wrote:
+/* Find the listening QUIC socket for an incoming packet.
+ *
+ * This function searches the QUIC socket table for a listening socket that matches the dest
+ * address and port, and the ALPN(s) if presented in the ClientHello. If multiple listening
+ * sockets are bound to the same address, port, and ALPN(s) (e.g., via SO_REUSEPORT), this
+ * function selects a socket from the reuseport group.
+ *
+ * Return: A pointer to the matching listening socket, or NULL if no match is found.
+ */
+struct sock *quic_listen_sock_lookup(struct sk_buff *skb, union quic_addr *sa, union quic_addr *da,
+ struct quic_data *alpns)
+{
+ struct net *net = sock_net(skb->sk);
+ struct hlist_nulls_node *node;
+ struct sock *sk = NULL, *tmp;
+ struct quic_shash_head *head;
+ struct quic_data alpn;
+ union quic_addr *a;
+ u32 hash, len;
+ u64 length;
+ u8 *p;
+
+ hash = quic_listen_sock_hash(net, ntohs(sa->v4.sin_port));
+ head = quic_listen_sock_head(hash);
+
+ rcu_read_lock();
+begin:
+ if (!alpns->len) { /* No ALPN entries present or failed to parse the ALPNs. */
+ sk_nulls_for_each_rcu(tmp, node, &head->head) {
+ /* If alpns->data != NULL, TLS parsing succeeded but no ALPN was found.
+ * In this case, only match sockets that have no ALPN set.
+ */
+ a = quic_path_saddr(quic_paths(tmp), 0);
+ if (net == sock_net(tmp) && quic_cmp_sk_addr(tmp, a, sa) &&
+ quic_path_usock(quic_paths(tmp), 0) == skb->sk &&
+ (!alpns->data || !quic_alpn(tmp)->len)) {
+ sk = tmp;
+ if (!quic_is_any_addr(a)) /* Prefer specific address match. */
+ break;
+ }
+ }
+ goto out;
+ }
+
+ /* ALPN present: loop through each ALPN entry. */
+ for (p = alpns->data, len = alpns->len; len; len -= length, p += length) {
+ quic_get_int(&p, &len, &length, 1);
+ quic_data(&alpn, p, length);
+ sk_nulls_for_each_rcu(tmp, node, &head->head) {
+ a = quic_path_saddr(quic_paths(tmp), 0);
+ if (net == sock_net(tmp) && quic_cmp_sk_addr(tmp, a, sa) &&
+ quic_path_usock(quic_paths(tmp), 0) == skb->sk &&
+ quic_data_has(quic_alpn(tmp), &alpn)) {
+ sk = tmp;
+ if (!quic_is_any_addr(a))
+ break;
+ }
+ }
+ if (sk)
+ break;
+ }
+out:
+ /* If the nulls value we got at the end of the iteration is different from the expected
+ * one, we must restart the lookup as the list was modified concurrently.
+ */
+ if (!sk && get_nulls_value(node) != hash)
+ goto begin;
+
+ if (sk && sk->sk_reuseport)
+ sk = reuseport_select_sock(sk, quic_addr_hash(net, da), skb, 1);
+
+ if (sk && unlikely(!refcount_inc_not_zero(&sk->sk_refcnt)))
+ sk = NULL;Note that you could avoid the refcount if you keep using the sk in an RCU critical section. i.e. plain UDP does that. Same consideration for established lookup. /P