Re: [PATCH v6 2/5] net/handshake: Define handshake_req_keyupdate
"Chuck Lever" <[email protected]>
| Newsgroups | dev.linux.lists.kernel-tls-handshake,org.infradead.lists.linux-nvme,org.kernel.vger.linux-doc,org.kernel.vger.linux-kernel,org.kernel.vger.linux-nfs,org.kernel.vger.netdev |
|---|---|
| Message-ID | <[email protected]> |
On Mon, Dec 1, 2025, at 8:34 PM, [email protected] wrote: > From: Alistair Francis <[email protected]> > > Add a new handshake_req_keyupdate() function which is similar to the > existing handshake_req_submit(). > > The new handshake_req_keyupdate() does not add the request to the hash > table (unlike handshake_req_submit()) but instead uses the existing > request from the initial handshake. > > During the initial handshake handshake_req_submit() will add the request > to the hash table. The request will not be removed from the hash table > unless the socket is closed (reference count hits zero). > > After the initial handshake handshake_req_keyupdate() can be used to re-use > the existing request in the hash table to trigger a KeyUpdate with > userspace. > > Signed-off-by: Alistair Francis <[email protected]> > --- > v6: > - New patch > > net/handshake/handshake.h | 2 + > net/handshake/request.c | 95 +++++++++++++++++++++++++++++++++++++++ > 2 files changed, 97 insertions(+) > > diff --git a/net/handshake/handshake.h b/net/handshake/handshake.h > index a48163765a7a..04feacd1e21d 100644 > --- a/net/handshake/handshake.h > +++ b/net/handshake/handshake.h > @@ -84,6 +84,8 @@ void handshake_req_hash_destroy(void); > void *handshake_req_private(struct handshake_req *req); > struct handshake_req *handshake_req_hash_lookup(struct sock *sk); > struct handshake_req *handshake_req_next(struct handshake_net *hn, int > class); > +int handshake_req_keyupdate(struct socket *sock, struct handshake_req > *req, > + gfp_t flags); > int handshake_req_submit(struct socket *sock, struct handshake_req > *req, > gfp_t flags); > void handshake_complete(struct handshake_req *req, unsigned int status, > diff --git a/net/handshake/request.c b/net/handshake/request.c > index 274d2c89b6b2..916caab88fe0 100644 > --- a/net/handshake/request.c > +++ b/net/handshake/request.c > @@ -196,6 +196,101 @@ struct handshake_req *handshake_req_next(struct > handshake_net *hn, int class) > } > EXPORT_SYMBOL_IF_KUNIT(handshake_req_next); > > +/** > + * handshake_req_keyupdate - Submit a KeyUpdate request > + * @sock: open socket on which to perform the handshake > + * @req: handshake arguments, this must already be allocated and exist > + * in the hash table, which happens as part of handshake_req_submit() > + * @flags: memory allocation flags > + * > + * Return values: > + * %0: Request queued > + * %-EINVAL: Invalid argument > + * %-EBUSY: A handshake is already under way for this socket Or, an initial handshake hasn't been done yet. Perhaps that deserves its own errno value... Thanks for considering this idea! > + * %-ESRCH: No handshake agent is available > + * %-EAGAIN: Too many pending handshake requests > + * %-ENOMEM: Failed to allocate memory > + * %-EMSGSIZE: Failed to construct notification message > + * %-EOPNOTSUPP: Handshake module not initialized > + * > + * A zero return value from handshake_req_submit() means that > + * exactly one subsequent completion callback is guaranteed. > + * > + * A negative return value from handshake_req_submit() means that > + * no completion callback will be done and that @req has been > + * destroyed. > + */ > +int handshake_req_keyupdate(struct socket *sock, struct handshake_req *req, > + gfp_t flags) > +{ > + struct handshake_net *hn; > + struct net *net; > + struct handshake_req *req_lookup; > + int ret; > + > + if (!sock || !req || !sock->file) { > + kfree(req); > + return -EINVAL; > + } > + > + req->hr_sk = sock->sk; > + if (!req->hr_sk) { > + kfree(req); > + return -EINVAL; > + } > + req->hr_odestruct = req->hr_sk->sk_destruct; > + req->hr_sk->sk_destruct = handshake_sk_destruct; > + > + ret = -EOPNOTSUPP; > + net = sock_net(req->hr_sk); > + hn = handshake_pernet(net); > + if (!hn) > + goto out_err; > + > + ret = -EAGAIN; > + if (READ_ONCE(hn->hn_pending) >= hn->hn_pending_max) > + goto out_err; > + > + spin_lock(&hn->hn_lock); > + ret = -EOPNOTSUPP; > + if (test_bit(HANDSHAKE_F_NET_DRAINING, &hn->hn_flags)) > + goto out_unlock; > + ret = -EBUSY; > + > + req_lookup = handshake_req_hash_lookup(sock->sk); > + if (!req_lookup) > + goto out_unlock; > + > + if (req_lookup != req) > + goto out_unlock; > + if (!__add_pending_locked(hn, req)) > + goto out_unlock; > + spin_unlock(&hn->hn_lock); > + > + test_and_clear_bit(HANDSHAKE_F_REQ_COMPLETED, &req->hr_flags); > + > + ret = handshake_genl_notify(net, req->hr_proto, flags); > + if (ret) { > + trace_handshake_notify_err(net, req, req->hr_sk, ret); > + if (remove_pending(hn, req)) > + goto out_err; > + } > + > + /* Prevent socket release while a handshake request is pending */ > + sock_hold(req->hr_sk); > + > + trace_handshake_submit(net, req, req->hr_sk); > + return 0; > + > +out_unlock: > + spin_unlock(&hn->hn_lock); > +out_err: > + trace_handshake_submit_err(net, req, req->hr_sk, ret); > + handshake_req_destroy(req); > + return ret; > +} > +EXPORT_SYMBOL(handshake_req_keyupdate); > + > /** > * handshake_req_submit - Submit a handshake request > * @sock: open socket on which to perform the handshake > -- > 2.51.1 -- Chuck Lever