Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/2215692/?format=api
{ "id": 2215692, "url": "http://patchwork.ozlabs.org/api/patches/2215692/?format=api", "web_url": "http://patchwork.ozlabs.org/project/linux-cifs-client/patch/18c72217e52fbdca9971a81ce5aba21096319ec9.1774410440.git.lucien.xin@gmail.com/", "project": { "id": 12, "url": "http://patchwork.ozlabs.org/api/projects/12/?format=api", "name": "Linux CIFS Client", "link_name": "linux-cifs-client", "list_id": "linux-cifs.vger.kernel.org", "list_email": "linux-cifs@vger.kernel.org", "web_url": "", "scm_url": "", "webscm_url": "", "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<18c72217e52fbdca9971a81ce5aba21096319ec9.1774410440.git.lucien.xin@gmail.com>", "list_archive_url": null, "date": "2026-03-25T03:47:12", "name": "[net-next,v11,07/15] quic: add connection id management", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "224bfdd9ac2c6988beb1470b45e3593730332e31", "submitter": { "id": 61073, "url": "http://patchwork.ozlabs.org/api/people/61073/?format=api", "name": "Xin Long", "email": "lucien.xin@gmail.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/linux-cifs-client/patch/18c72217e52fbdca9971a81ce5aba21096319ec9.1774410440.git.lucien.xin@gmail.com/mbox/", "series": [ { "id": 497380, "url": "http://patchwork.ozlabs.org/api/series/497380/?format=api", "web_url": "http://patchwork.ozlabs.org/project/linux-cifs-client/list/?series=497380", "date": "2026-03-25T03:47:06", "name": "net: introduce QUIC infrastructure and core subcomponents", "version": 11, "mbox": "http://patchwork.ozlabs.org/series/497380/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2215692/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2215692/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "\n <linux-cifs+bounces-10509-incoming=patchwork.ozlabs.org@vger.kernel.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "linux-cifs@vger.kernel.org" ], "Delivered-To": "patchwork-incoming@legolas.ozlabs.org", "Authentication-Results": [ "legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20251104 header.b=BoiYRcbg;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=2600:3c15:e001:75::12fc:5321; helo=sin.lore.kernel.org;\n envelope-from=linux-cifs+bounces-10509-incoming=patchwork.ozlabs.org@vger.kernel.org;\n receiver=patchwork.ozlabs.org)", "smtp.subspace.kernel.org;\n\tdkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com\n header.b=\"BoiYRcbg\"", "smtp.subspace.kernel.org;\n arc=none smtp.client-ip=209.85.160.180", "smtp.subspace.kernel.org;\n dmarc=pass (p=none dis=none) header.from=gmail.com", "smtp.subspace.kernel.org;\n spf=pass smtp.mailfrom=gmail.com" ], "Received": [ "from sin.lore.kernel.org (sin.lore.kernel.org\n [IPv6:2600:3c15:e001:75::12fc:5321])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fgY076kY3z1y1G\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 25 Mar 2026 14:52:55 +1100 (AEDT)", "from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby sin.lore.kernel.org (Postfix) with ESMTP id EBF1F303967A\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 25 Mar 2026 03:49:47 +0000 (UTC)", "from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id B7D592DC331;\n\tWed, 25 Mar 2026 03:49:43 +0000 (UTC)", "from mail-qt1-f180.google.com (mail-qt1-f180.google.com\n [209.85.160.180])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id AAA5D2E9ED8\n\tfor <linux-cifs@vger.kernel.org>; Wed, 25 Mar 2026 03:49:41 +0000 (UTC)", "by mail-qt1-f180.google.com with SMTP id\n d75a77b69052e-505a1789a27so10399221cf.3\n for <linux-cifs@vger.kernel.org>;\n Tue, 24 Mar 2026 20:49:41 -0700 (PDT)", "from wsfd-netdev58.anl.eng.rdu2.dc.redhat.com ([66.187.232.140])\n by smtp.gmail.com with ESMTPSA id\n d75a77b69052e-50b36cb2e29sm150093001cf.1.2026.03.24.20.49.37\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Tue, 24 Mar 2026 20:49:39 -0700 (PDT)" ], "ARC-Seal": "i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1774410583; cv=none;\n b=GoI90foT2JJysyQAMg6QJ2JdBiCeEKRdtZvwQBxNfdpj04Vxki6N8LVoHex3uovAcOLglFNnYGcE8TgUsoecwh6C3RVj3C4jWc6axfuRwH2Z9LD8O3S7kCWEL5/leIV0yejGFQafgSnHtTuljtxXJ+rxfAw/UxjrNlhChQnirCg=", "ARC-Message-Signature": "i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1774410583; c=relaxed/simple;\n\tbh=bh1dWZYg4DqIJfjmkuA1UBCjEsgkSfUV0beRr/0ZCf4=;\n\th=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:\n\t MIME-Version;\n b=iQF5ekt6gPeZL+GR+OxPy9DYNca9r7ZUqM9d1WglryphQo5TwQBU57bo7uTbxxyCpub0kF6HxKLoXz4cqF76Bun5O+GQ5a6Qy4SJwF3uA45ksA3nUD4TER9R0t1P2bVqDXMoyBL/YpB7rYP5nCmU/FctwQ1MTZniIahzLjo2ao0=", "ARC-Authentication-Results": "i=1; smtp.subspace.kernel.org;\n dmarc=pass (p=none dis=none) header.from=gmail.com;\n spf=pass smtp.mailfrom=gmail.com;\n dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com\n header.b=BoiYRcbg; arc=none smtp.client-ip=209.85.160.180", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=gmail.com; s=20251104; t=1774410581; x=1775015381;\n darn=vger.kernel.org;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:from:to:cc:subject:date\n :message-id:reply-to;\n bh=YrhnAZpDvKatrTfzkpp/V8O6PISZPhCQXrsEa8n/Yz8=;\n b=BoiYRcbgZ2PloUZdCH5cBTcyaOXe9oOaZjlcwcRh2PNV5ErpHUoXNGt7ELh4PvD2g8\n 1Ari3MLCehmHBLZLPKYV/4l9a/3PJJ0cMn3q+3rQMZfqp8By8z6bUnicHs+/PQ6UMTVp\n lHkmDb9qXzfZwk6tP/iwsOTSxd0BXzwHjqQlaBnQtblnci8KmlcQKhzPJppfgYwcPjIu\n J1gf7AYOHrpm6OcKUdOpIgHdTdlNJ6n2KS9GquESLQJ/3YFiATX+5QlOi+QxMocLf9ep\n gvlJdqlCQMfA024y62Bka5qqnYEX/kOyA8ZJnHKF+BY0w6Vz7+JvC4/nWrENZN4CjvCF\n Qf3Q==", "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1774410581; x=1775015381;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from\n :to:cc:subject:date:message-id:reply-to;\n bh=YrhnAZpDvKatrTfzkpp/V8O6PISZPhCQXrsEa8n/Yz8=;\n b=owQq8gKYXT48OuSTtn3IS4CMH4SvpqJt3q9TdYx2HG+5xXVByyOakxUwq5JsMMsFgF\n FB5CWqkl5bdnq6FRIyuMOchodC71lzL2BVlAuGeloYlLihbjGdg17oEsTR5Kl61NmXNf\n B35YpnUGgX2V4MCcT4bSjxy/1LoFoAoiUBXvR2n5q/U7QWsXRWwyvcG1DxdsEOFO8m1L\n 1BcxMcZtFriV4xqKeJTYBmmIQHOwJXGK/kS9qwXIKz/oUKpxmt8G50S2dxObvbiJkbMc\n ZzEe0nQsMzMRHC4YnswTMTDIEoEcu1Lz+eZnYv3NrtkwOWcxZzlHoxBquML7m+nSrpeh\n 1s6g==", "X-Forwarded-Encrypted": "i=1;\n AJvYcCVqpZYLiVyaKZku8JCuidrF93oO0lQWJ4/Y4pKdjW595z9S5Wwn6CJhnsqO4QnfbEWHQDqhStDq2d0g@vger.kernel.org", "X-Gm-Message-State": "AOJu0Ywi5+iBhkcdn39onXhoxIpilze/TxYao4m9NUozvHRDhS6J4MvJ\n\tdB/G/iwW/3mdlO5jCy/nuSonVjSnhFycg4KmIn01IWuWArLJjd0tc5MZ", "X-Gm-Gg": "ATEYQzzWtZtHhP68pJQTbls/Kr0yiM1sztcAWxK6VNy5TaTGkFD+HRVyt1DIRuwElSN\n\tHupqW/Ej7lJl14J1shzbtWZ6iRBaYIaOJJPoIW0kTauq2eMhCQ+EWyBqmagslZ9y4gKlh3hwCPp\n\tkaoTphgYNwnXUDhgi/j5hxdvhRTx1o5h1WroQLktSSh1AcQA3GwZXWtdcNpPPA6eWYKAhNr7vKX\n\t5r6wm3rf0scM9jiA41bthe7qV/oN48MeeGW56eRyo9/SbJOOeiYNjh7XFNYbZVYjP4pSY/ELKaE\n\tH1kW7fdHGPB0/pyVs4XsMB7IffI4fF779xHbWZ5N7UGCGlK4HXrbfOG3aQRucrcuar3DYangBMw\n\t/lonSEt+PyjvoLMAkvObACqvurymerz9itId0h1LbTExBnajllHgvBZDR6jbJbMReiO43mAP69N\n\t2qU9smJWOhacn3UrUd+Izo+uOJoubP3TPABlXV4F5iZD8rT50NE6INR2AH7Gr2QcDnFOvOwVyFp\n\tOR/O3OhevHHStl9yimbSVzoWohU7CGROeBrXOJ71CVON14wZ2V8UcPfsAdydG0/dA==", "X-Received": "by 2002:a05:622a:4cd:b0:50b:2eef:c900 with SMTP id\n d75a77b69052e-50b80d1b091mr30594421cf.24.1774410580445;\n Tue, 24 Mar 2026 20:49:40 -0700 (PDT)", "From": "Xin Long <lucien.xin@gmail.com>", "To": "network dev <netdev@vger.kernel.org>,\n\tquic@lists.linux.dev", "Cc": "davem@davemloft.net,\n\tkuba@kernel.org,\n\tEric Dumazet <edumazet@google.com>,\n\tPaolo Abeni <pabeni@redhat.com>,\n\tSimon Horman <horms@kernel.org>,\n\tStefan Metzmacher <metze@samba.org>,\n\tMoritz Buhl <mbuhl@openbsd.org>,\n\tTyler Fanelli <tfanelli@redhat.com>,\n\tPengtao He <hepengtao@xiaomi.com>,\n\tThomas Dreibholz <dreibh@simula.no>,\n\tlinux-cifs@vger.kernel.org,\n\tSteve French <smfrench@gmail.com>,\n\tNamjae Jeon <linkinjeon@kernel.org>,\n\tPaulo Alcantara <pc@manguebit.com>,\n\tTom Talpey <tom@talpey.com>,\n\tkernel-tls-handshake@lists.linux.dev,\n\tChuck Lever <chuck.lever@oracle.com>,\n\tJeff Layton <jlayton@kernel.org>,\n\tSteve Dickson <steved@redhat.com>,\n\tHannes Reinecke <hare@suse.de>,\n\tAlexander Aring <aahringo@redhat.com>,\n\tDavid Howells <dhowells@redhat.com>,\n\tMatthieu Baerts <matttbe@kernel.org>,\n\tJohn Ericson <mail@johnericson.me>,\n\tCong Wang <xiyou.wangcong@gmail.com>,\n\t\"D . Wythe\" <alibuda@linux.alibaba.com>,\n\tJason Baron <jbaron@akamai.com>,\n\tilliliti <illiliti@protonmail.com>,\n\tSabrina Dubroca <sd@queasysnail.net>,\n\tMarcelo Ricardo Leitner <marcelo.leitner@gmail.com>,\n\tDaniel Stenberg <daniel@haxx.se>,\n\tAndy Gospodarek <andrew.gospodarek@broadcom.com>,\n\t\"Marc E . Fiuczynski\" <marc@fiuczynski.com>", "Subject": "[PATCH net-next v11 07/15] quic: add connection id management", "Date": "Tue, 24 Mar 2026 23:47:12 -0400", "Message-ID": "\n <18c72217e52fbdca9971a81ce5aba21096319ec9.1774410440.git.lucien.xin@gmail.com>", "X-Mailer": "git-send-email 2.47.1", "In-Reply-To": "<cover.1774410440.git.lucien.xin@gmail.com>", "References": "<cover.1774410440.git.lucien.xin@gmail.com>", "Precedence": "bulk", "X-Mailing-List": "linux-cifs@vger.kernel.org", "List-Id": "<linux-cifs.vger.kernel.org>", "List-Subscribe": "<mailto:linux-cifs+subscribe@vger.kernel.org>", "List-Unsubscribe": "<mailto:linux-cifs+unsubscribe@vger.kernel.org>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit" }, "content": "This patch introduces 'struct quic_conn_id_set' for managing Connection\nIDs (CIDs), which are represented by 'struct quic_source_conn_id'\nand 'struct quic_dest_conn_id'.\n\nIt provides helpers to add and remove CIDs from the set, and handles\ninsertion of source CIDs into the global connection ID hash table\nwhen necessary.\n\n- quic_conn_id_add(): Add a new Connection ID to the set, and inserts\n it to conn_id hash table if it is a source conn_id.\n\n- quic_conn_id_remove(): Remove connection IDs the set with sequence\n numbers less than or equal to a number.\n\nIt also adds utilities to look up CIDs by value or sequence number,\nsearch the global hash table for incoming packets, and check for\nstateless reset tokens among destination CIDs. These functions are\nessential for RX path connection lookup and stateless reset processing.\n\n- quic_conn_id_find(): Find a Connection ID in the set by seq number.\n\n- quic_conn_id_lookup(): Lookup a Connection ID from global hash table\n using the ID value, typically used for socket lookup on the RX path.\n\n- quic_conn_id_token_exists(): Check if a stateless reset token exists\n in any dest Connection ID (used during stateless reset processing).\n\nNote source/dest conn_id set is per socket, the operations on it are\nalways protected by the sock lock.\n\nSigned-off-by: Xin Long <lucien.xin@gmail.com>\nAcked-by: Paolo Abeni <pabeni@redhat.com>\n---\nv3:\n - Clarify in changelog that conn_id set is always protected by sock lock\n (suggested by Paolo).\n - Adjust global source conn_id hashtable operations for the new hashtable\n type.\nv4:\n - Replace struct hlist_node with hlist_nulls_node for the node in\n struct quic_source_conn_id to support lockless lookup.\nv7:\n - Break the loop earlier if common->number > number in\n quic_conn_id_remove/find() (suggested by Paolo).\n - Add a comment in quic_conn_id_first_number().\nv8:\n - Add a comment to quic_conn_id_remove() clarifying that the ID number\n must be smaller than the sequence number of the last ID in the set.\nv11:\n - Note for AI review: each id_set contains at most 8 connection IDs, so\n using an RB-tree for faster lookup is unnecessary.\n - Set maximum line length to 80 characters.\n - Add a check for number in quic_conn_id_remove().\n---\n net/quic/Makefile | 2 +-\n net/quic/connid.c | 249 ++++++++++++++++++++++++++++++++++++++++++++++\n net/quic/connid.h | 182 +++++++++++++++++++++++++++++++++\n net/quic/socket.c | 6 ++\n net/quic/socket.h | 13 +++\n 5 files changed, 451 insertions(+), 1 deletion(-)\n create mode 100644 net/quic/connid.c\n create mode 100644 net/quic/connid.h", "diff": "diff --git a/net/quic/Makefile b/net/quic/Makefile\nindex 094e9da5d739..eee7501588d3 100644\n--- a/net/quic/Makefile\n+++ b/net/quic/Makefile\n@@ -5,4 +5,4 @@\n \n obj-$(CONFIG_IP_QUIC) += quic.o\n \n-quic-y := common.o family.o protocol.o socket.o stream.o\n+quic-y := common.o family.o protocol.o socket.o stream.o connid.o\ndiff --git a/net/quic/connid.c b/net/quic/connid.c\nnew file mode 100644\nindex 000000000000..25913da89eeb\n--- /dev/null\n+++ b/net/quic/connid.c\n@@ -0,0 +1,249 @@\n+// SPDX-License-Identifier: GPL-2.0-or-later\n+/* QUIC kernel implementation\n+ * (C) Copyright Red Hat Corp. 2023\n+ *\n+ * This file is part of the QUIC kernel implementation\n+ *\n+ * Initialization/cleanup for QUIC protocol support.\n+ *\n+ * Written or modified by:\n+ * Xin Long <lucien.xin@gmail.com>\n+ */\n+\n+#include <linux/quic.h>\n+#include <net/sock.h>\n+\n+#include \"common.h\"\n+#include \"connid.h\"\n+\n+/* Lookup a source connection ID (scid) in the global source connection ID hash\n+ * table.\n+ */\n+struct quic_conn_id *quic_conn_id_lookup(struct net *net, u8 *scid, u32 len)\n+{\n+\tstruct quic_shash_head *head = quic_source_conn_id_head(net, scid, len);\n+\tstruct quic_source_conn_id *s_conn_id;\n+\tstruct quic_conn_id *conn_id = NULL;\n+\tstruct hlist_nulls_node *node;\n+\n+\thlist_nulls_for_each_entry_rcu(s_conn_id, node, &head->head, node) {\n+\t\tif (net != sock_net(s_conn_id->sk))\n+\t\t\tcontinue;\n+\t\tif (s_conn_id->common.id.len != len ||\n+\t\t memcmp(scid, &s_conn_id->common.id.data, len))\n+\t\t\tcontinue;\n+\t\tif (likely(refcount_inc_not_zero(&s_conn_id->sk->sk_refcnt)))\n+\t\t\tconn_id = &s_conn_id->common.id;\n+\t\tbreak;\n+\t}\n+\treturn conn_id;\n+}\n+\n+/* Check if a given stateless reset token exists in any connection ID in the\n+ * connection ID set.\n+ */\n+bool quic_conn_id_token_exists(struct quic_conn_id_set *id_set, u8 *token)\n+{\n+\tstruct quic_common_conn_id *common;\n+\tstruct quic_dest_conn_id *dcid;\n+\n+\tdcid = (struct quic_dest_conn_id *)id_set->active;\n+\tif (!memcmp(dcid->token, token, QUIC_CONN_ID_TOKEN_LEN))\n+\t\treturn true; /* Fast path. */\n+\n+\tlist_for_each_entry(common, &id_set->head, list) {\n+\t\tdcid = (struct quic_dest_conn_id *)common;\n+\t\tif (common == id_set->active)\n+\t\t\tcontinue;\n+\t\tif (!memcmp(dcid->token, token, QUIC_CONN_ID_TOKEN_LEN))\n+\t\t\treturn true;\n+\t}\n+\treturn false;\n+}\n+\n+static void quic_source_conn_id_free_rcu(struct rcu_head *head)\n+{\n+\tstruct quic_source_conn_id *s_conn_id;\n+\n+\ts_conn_id = container_of(head, struct quic_source_conn_id, rcu);\n+\tkfree(s_conn_id);\n+}\n+\n+static void quic_source_conn_id_free(struct quic_source_conn_id *s_conn_id)\n+{\n+\tu8 *data = s_conn_id->common.id.data;\n+\tu32 len = s_conn_id->common.id.len;\n+\tstruct quic_shash_head *head;\n+\n+\tif (!hlist_nulls_unhashed(&s_conn_id->node)) {\n+\t\thead = quic_source_conn_id_head(sock_net(s_conn_id->sk), data,\n+\t\t\t\t\t\tlen);\n+\t\tspin_lock_bh(&head->lock);\n+\t\thlist_nulls_del_init_rcu(&s_conn_id->node);\n+\t\tspin_unlock_bh(&head->lock);\n+\t}\n+\n+\t/* Freeing is deferred via RCU to avoid use-after-free during\n+\t * concurrent lookups.\n+\t */\n+\tcall_rcu(&s_conn_id->rcu, quic_source_conn_id_free_rcu);\n+}\n+\n+static void quic_conn_id_del(struct quic_common_conn_id *common)\n+{\n+\tlist_del(&common->list);\n+\tif (!common->hashed) {\n+\t\tkfree(common);\n+\t\treturn;\n+\t}\n+\tquic_source_conn_id_free((struct quic_source_conn_id *)common);\n+}\n+\n+/* Add a connection ID with sequence number and associated private data to the\n+ * connection ID set.\n+ */\n+int quic_conn_id_add(struct quic_conn_id_set *id_set,\n+\t\t struct quic_conn_id *conn_id, u32 number, void *data)\n+{\n+\tstruct quic_source_conn_id *s_conn_id;\n+\tstruct quic_dest_conn_id *d_conn_id;\n+\tstruct quic_common_conn_id *common;\n+\tstruct quic_shash_head *head;\n+\tstruct list_head *list;\n+\n+\t/* Locate insertion point to keep list ordered by number. */\n+\tlist = &id_set->head;\n+\tlist_for_each_entry(common, list, list) {\n+\t\tif (number == common->number)\n+\t\t\treturn 0; /* Ignore if it already exists on the list. */\n+\t\tif (number < common->number) {\n+\t\t\tlist = &common->list;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\tif (conn_id->len > QUIC_CONN_ID_MAX_LEN)\n+\t\treturn -EINVAL;\n+\tcommon = kzalloc(id_set->entry_size, GFP_ATOMIC);\n+\tif (!common)\n+\t\treturn -ENOMEM;\n+\tcommon->id = *conn_id;\n+\tcommon->number = number;\n+\tif (id_set->entry_size == sizeof(struct quic_dest_conn_id)) {\n+\t\t/* For destination connection IDs, copy the stateless reset\n+\t\t * token if available.\n+\t\t */\n+\t\tif (data) {\n+\t\t\td_conn_id = (struct quic_dest_conn_id *)common;\n+\t\t\tmemcpy(d_conn_id->token, data, QUIC_CONN_ID_TOKEN_LEN);\n+\t\t}\n+\t} else {\n+\t\t/* For source connection IDs, mark as hashed and insert into\n+\t\t * the global source connection ID hashtable.\n+\t\t */\n+\t\tcommon->hashed = 1;\n+\t\ts_conn_id = (struct quic_source_conn_id *)common;\n+\t\ts_conn_id->sk = data;\n+\n+\t\thead = quic_source_conn_id_head(sock_net(s_conn_id->sk),\n+\t\t\t\t\t\tcommon->id.data,\n+\t\t\t\t\t\tcommon->id.len);\n+\t\tspin_lock_bh(&head->lock);\n+\t\thlist_nulls_add_head_rcu(&s_conn_id->node, &head->head);\n+\t\tspin_unlock_bh(&head->lock);\n+\t}\n+\tlist_add_tail(&common->list, list);\n+\n+\tif (number == quic_conn_id_last_number(id_set) + 1) {\n+\t\tif (!id_set->active)\n+\t\t\tid_set->active = common;\n+\t\tid_set->count++;\n+\n+\t\t/* Increment count for consecutive following IDs. */\n+\t\tlist_for_each_entry_continue(common, &id_set->head, list) {\n+\t\t\tif (common->number != ++number)\n+\t\t\t\tbreak;\n+\t\t\tid_set->count++;\n+\t\t}\n+\t}\n+\treturn 0;\n+}\n+\n+/* Remove consecutive connection IDs from the set with sequence numbers less\n+ * than or equal to a number.\n+ */\n+void quic_conn_id_remove(struct quic_conn_id_set *id_set, u32 number)\n+{\n+\tstruct quic_common_conn_id *common, *tmp;\n+\tstruct list_head *list;\n+\n+\t/* The number must be less than the sequence number of the last\n+\t * consecutive connection ID in the set.\n+\t */\n+\tif (WARN_ON_ONCE(number >= quic_conn_id_last_number(id_set)))\n+\t\treturn;\n+\tlist = &id_set->head;\n+\tlist_for_each_entry_safe(common, tmp, list, list) {\n+\t\tif (common->number > number)\n+\t\t\tbreak;\n+\t\tif (id_set->active == common)\n+\t\t\tid_set->active = tmp;\n+\t\tquic_conn_id_del(common);\n+\t\tid_set->count--;\n+\t}\n+}\n+\n+struct quic_conn_id *quic_conn_id_find(struct quic_conn_id_set *id_set,\n+\t\t\t\t u32 number)\n+{\n+\tstruct quic_common_conn_id *common;\n+\n+\tlist_for_each_entry(common, &id_set->head, list) {\n+\t\tif (common->number > number)\n+\t\t\tbreak;\n+\t\tif (common->number == number)\n+\t\t\treturn &common->id;\n+\t}\n+\treturn NULL;\n+}\n+\n+void quic_conn_id_update_active(struct quic_conn_id_set *id_set, u32 number)\n+{\n+\tstruct quic_conn_id *conn_id;\n+\n+\tif (number == id_set->active->number)\n+\t\treturn;\n+\tconn_id = quic_conn_id_find(id_set, number);\n+\tif (!conn_id)\n+\t\treturn;\n+\tquic_conn_id_set_active(id_set, conn_id);\n+}\n+\n+void quic_conn_id_set_init(struct quic_conn_id_set *id_set, bool source)\n+{\n+\tid_set->entry_size = source ? sizeof(struct quic_source_conn_id) :\n+\t\t\t\t sizeof(struct quic_dest_conn_id);\n+\tINIT_LIST_HEAD(&id_set->head);\n+}\n+\n+void quic_conn_id_set_free(struct quic_conn_id_set *id_set)\n+{\n+\tstruct quic_common_conn_id *common, *tmp;\n+\n+\tlist_for_each_entry_safe(common, tmp, &id_set->head, list)\n+\t\tquic_conn_id_del(common);\n+\tid_set->count = 0;\n+\tid_set->active = NULL;\n+}\n+\n+void quic_conn_id_get_param(struct quic_conn_id_set *id_set,\n+\t\t\t struct quic_transport_param *p)\n+{\n+\tp->active_connection_id_limit = id_set->max_count;\n+}\n+\n+void quic_conn_id_set_param(struct quic_conn_id_set *id_set,\n+\t\t\t struct quic_transport_param *p)\n+{\n+\tid_set->max_count = p->active_connection_id_limit;\n+}\ndiff --git a/net/quic/connid.h b/net/quic/connid.h\nnew file mode 100644\nindex 000000000000..af5157959b2c\n--- /dev/null\n+++ b/net/quic/connid.h\n@@ -0,0 +1,182 @@\n+/* SPDX-License-Identifier: GPL-2.0-or-later */\n+/* QUIC kernel implementation\n+ * (C) Copyright Red Hat Corp. 2023\n+ *\n+ * This file is part of the QUIC kernel implementation\n+ *\n+ * Written or modified by:\n+ * Xin Long <lucien.xin@gmail.com>\n+ */\n+\n+#define QUIC_CONN_ID_LIMIT\t8\n+#define QUIC_CONN_ID_DEF\t7\n+#define QUIC_CONN_ID_LEAST\t2\n+\n+#define QUIC_CONN_ID_TOKEN_LEN\t16\n+\n+/* Common fields shared by both source and destination Connection IDs */\n+struct quic_common_conn_id {\n+\tstruct quic_conn_id id;\t/* Connection ID value and its length */\n+\tstruct list_head list; /* List node for connection ID management */\n+\tu32 number; /* Sequence number assigned to this Connection ID */\n+\tu8 hashed; /* Non-zero if stored in source_conn_id hash table */\n+};\n+\n+struct quic_source_conn_id {\n+\tstruct quic_common_conn_id common;\n+\tstruct hlist_nulls_node node; /* Hash table node for fast lookup */\n+\tstruct rcu_head rcu; /* RCU header for deferred destruction */\n+\tstruct sock *sk; /* Socket associated with this Connection ID */\n+};\n+\n+struct quic_dest_conn_id {\n+\tstruct quic_common_conn_id common;\n+\t/* Stateless reset token in rfc9000#section-10.3 */\n+\tu8 token[QUIC_CONN_ID_TOKEN_LEN];\n+};\n+\n+struct quic_conn_id_set {\n+\t/* Connection ID in use on the current path */\n+\tstruct quic_common_conn_id *active;\n+\t/* Connection ID to use for a new path (e.g., after migration) */\n+\tstruct quic_common_conn_id *alt;\n+\tstruct list_head head; /* List head of available connection IDs */\n+\tu8 entry_size; /* Size of each connection ID entry in the list */\n+\tu8 max_count; /* active_connection_id_limit in rfc9000#section-18.2 */\n+\tu8 count; /* Current number of connection IDs in the list */\n+};\n+\n+static inline u32 quic_conn_id_first_number(struct quic_conn_id_set *id_set)\n+{\n+\tstruct quic_common_conn_id *common;\n+\n+\t/* The id_set is guaranteed to be non-empty when called (sk is not in\n+\t * CLOSE state).\n+\t */\n+\tcommon = list_first_entry(&id_set->head, struct quic_common_conn_id,\n+\t\t\t\t list);\n+\treturn common->number;\n+}\n+\n+static inline u32 quic_conn_id_last_number(struct quic_conn_id_set *id_set)\n+{\n+\treturn quic_conn_id_first_number(id_set) + id_set->count - 1;\n+}\n+\n+static inline void quic_conn_id_generate(struct quic_conn_id *conn_id)\n+{\n+\tget_random_bytes(conn_id->data, QUIC_CONN_ID_DEF_LEN);\n+\tconn_id->len = QUIC_CONN_ID_DEF_LEN;\n+}\n+\n+/* Select an alternate destination Connection ID for a new path (e.g., after\n+ * migration).\n+ */\n+static inline bool quic_conn_id_select_alt(struct quic_conn_id_set *id_set,\n+\t\t\t\t\t bool active)\n+{\n+\tif (id_set->alt)\n+\t\treturn true;\n+\t/* NAT rebinding: peer keeps using the current source conn_id.\n+\t * In this case, continue using the same dest conn_id for the new path.\n+\t */\n+\tif (active) {\n+\t\tid_set->alt = id_set->active;\n+\t\treturn true;\n+\t}\n+\t/* Treat the prev conn_ids as used.\n+\t * Try selecting the next conn_id in the list, unless at the end.\n+\t */\n+\tif (id_set->active->number != quic_conn_id_last_number(id_set)) {\n+\t\tid_set->alt = list_next_entry(id_set->active, list);\n+\t\treturn true;\n+\t}\n+\t/* If there's only one conn_id in the list, reuse the active one. */\n+\tif (id_set->active->number == quic_conn_id_first_number(id_set)) {\n+\t\tid_set->alt = id_set->active;\n+\t\treturn true;\n+\t}\n+\t/* No alternate conn_id could be selected. Caller should send a\n+\t * QUIC_FRAME_RETIRE_CONNECTION_ID frame to request new connection IDs\n+\t * from the peer.\n+\t */\n+\treturn false;\n+}\n+\n+static inline void quic_conn_id_set_alt(struct quic_conn_id_set *id_set,\n+\t\t\t\t\tstruct quic_conn_id *alt)\n+{\n+\tid_set->alt = (struct quic_common_conn_id *)alt;\n+}\n+\n+/* Swap the active and alternate destination Connection IDs after path\n+ * migration completes, since the path has already been switched accordingly.\n+ */\n+static inline void quic_conn_id_swap_active(struct quic_conn_id_set *id_set)\n+{\n+\tvoid *active = id_set->active;\n+\n+\tid_set->active = id_set->alt;\n+\tid_set->alt = active;\n+}\n+\n+/* Choose which destination Connection ID to use for a new path migration if\n+ * alt is true.\n+ */\n+static inline struct quic_conn_id *\n+quic_conn_id_choose(struct quic_conn_id_set *id_set, u8 alt)\n+{\n+\treturn (alt && id_set->alt) ? &id_set->alt->id : &id_set->active->id;\n+}\n+\n+static inline struct quic_conn_id *\n+quic_conn_id_active(struct quic_conn_id_set *id_set)\n+{\n+\treturn &id_set->active->id;\n+}\n+\n+static inline void quic_conn_id_set_active(struct quic_conn_id_set *id_set,\n+\t\t\t\t\t struct quic_conn_id *active)\n+{\n+\tid_set->active = (struct quic_common_conn_id *)active;\n+}\n+\n+static inline u32 quic_conn_id_number(struct quic_conn_id *conn_id)\n+{\n+\treturn ((struct quic_common_conn_id *)conn_id)->number;\n+}\n+\n+static inline struct sock *quic_conn_id_sk(struct quic_conn_id *conn_id)\n+{\n+\treturn ((struct quic_source_conn_id *)conn_id)->sk;\n+}\n+\n+static inline void quic_conn_id_set_token(struct quic_conn_id *conn_id,\n+\t\t\t\t\t u8 *token)\n+{\n+\tmemcpy(((struct quic_dest_conn_id *)conn_id)->token, token,\n+\t QUIC_CONN_ID_TOKEN_LEN);\n+}\n+\n+static inline int quic_conn_id_cmp(struct quic_conn_id *a,\n+\t\t\t\t struct quic_conn_id *b)\n+{\n+\treturn a->len != b->len || memcmp(a->data, b->data, a->len);\n+}\n+\n+int quic_conn_id_add(struct quic_conn_id_set *id_set,\n+\t\t struct quic_conn_id *conn_id, u32 number, void *data);\n+bool quic_conn_id_token_exists(struct quic_conn_id_set *id_set, u8 *token);\n+void quic_conn_id_remove(struct quic_conn_id_set *id_set, u32 number);\n+\n+struct quic_conn_id *quic_conn_id_find(struct quic_conn_id_set *id_set,\n+\t\t\t\t u32 number);\n+struct quic_conn_id *quic_conn_id_lookup(struct net *net, u8 *scid, u32 len);\n+void quic_conn_id_update_active(struct quic_conn_id_set *id_set, u32 number);\n+\n+void quic_conn_id_get_param(struct quic_conn_id_set *id_set,\n+\t\t\t struct quic_transport_param *p);\n+void quic_conn_id_set_param(struct quic_conn_id_set *id_set,\n+\t\t\t struct quic_transport_param *p);\n+void quic_conn_id_set_init(struct quic_conn_id_set *id_set, bool source);\n+void quic_conn_id_set_free(struct quic_conn_id_set *id_set);\ndiff --git a/net/quic/socket.c b/net/quic/socket.c\nindex 0006668551f4..aa451ea8f516 100644\n--- a/net/quic/socket.c\n+++ b/net/quic/socket.c\n@@ -45,6 +45,9 @@ static int quic_init_sock(struct sock *sk)\n \tsk_sockets_allocated_inc(sk);\n \tsock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);\n \n+\tquic_conn_id_set_init(quic_source(sk), 1);\n+\tquic_conn_id_set_init(quic_dest(sk), 0);\n+\n \tif (quic_stream_init(quic_streams(sk)))\n \t\treturn -ENOMEM;\n \n@@ -53,6 +56,9 @@ static int quic_init_sock(struct sock *sk)\n \n static void quic_destroy_sock(struct sock *sk)\n {\n+\tquic_conn_id_set_free(quic_source(sk));\n+\tquic_conn_id_set_free(quic_dest(sk));\n+\n \tquic_stream_free(quic_streams(sk));\n \n \tquic_data_free(quic_ticket(sk));\ndiff --git a/net/quic/socket.h b/net/quic/socket.h\nindex e76737b9b74b..68a58f0016cc 100644\n--- a/net/quic/socket.h\n+++ b/net/quic/socket.h\n@@ -14,6 +14,7 @@\n #include \"common.h\"\n #include \"family.h\"\n #include \"stream.h\"\n+#include \"connid.h\"\n \n #include \"protocol.h\"\n \n@@ -36,6 +37,8 @@ struct quic_sock {\n \tstruct quic_data\t\talpn;\n \n \tstruct quic_stream_table\tstreams;\n+\tstruct quic_conn_id_set\t\tsource;\n+\tstruct quic_conn_id_set\t\tdest;\n };\n \n struct quic6_sock {\n@@ -73,6 +76,16 @@ static inline struct quic_stream_table *quic_streams(const struct sock *sk)\n \treturn &quic_sk(sk)->streams;\n }\n \n+static inline struct quic_conn_id_set *quic_source(const struct sock *sk)\n+{\n+\treturn &quic_sk(sk)->source;\n+}\n+\n+static inline struct quic_conn_id_set *quic_dest(const struct sock *sk)\n+{\n+\treturn &quic_sk(sk)->dest;\n+}\n+\n static inline bool quic_is_serv(const struct sock *sk)\n {\n \treturn !!sk->sk_max_ack_backlog;\n", "prefixes": [ "net-next", "v11", "07/15" ] }