Thread (34 messages) 34 messages, 2 authors, 2026-03-05

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
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help