Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

net: mctp: Use hashtable for binds

Ensure that a specific EID (remote or local) bind will match in
preference to a MCTP_ADDR_ANY bind.

This adds infrastructure for binding a socket to receive messages from a
specific remote peer address, a future commit will expose an API for
this.

Signed-off-by: Matt Johnston <matt@codeconstruct.com.au>
Link: https://patch.msgid.link/20250710-mctp-bind-v4-5-8ec2f6460c56@codeconstruct.com.au
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

authored by

Matt Johnston and committed by
Paolo Abeni
1aeed732 4ec4b7fc

+87 -25
+16 -4
include/net/netns/mctp.h
··· 6 6 #ifndef __NETNS_MCTP_H__ 7 7 #define __NETNS_MCTP_H__ 8 8 9 + #include <linux/hash.h> 10 + #include <linux/hashtable.h> 9 11 #include <linux/mutex.h> 10 12 #include <linux/types.h> 13 + 14 + #define MCTP_BINDS_BITS 7 11 15 12 16 struct netns_mctp { 13 17 /* Only updated under RTNL, entries freed via RCU */ 14 18 struct list_head routes; 15 19 16 - /* Bound sockets: list of sockets bound by type. 17 - * This list is updated from non-atomic contexts (under bind_lock), 18 - * and read (under rcu) in packet rx 20 + /* Bound sockets: hash table of sockets, keyed by 21 + * (type, src_eid, dest_eid). 22 + * Specific src_eid/dest_eid entries also have an entry for 23 + * MCTP_ADDR_ANY. This list is updated from non-atomic contexts 24 + * (under bind_lock), and read (under rcu) in packet rx. 19 25 */ 20 26 struct mutex bind_lock; 21 - struct hlist_head binds; 27 + DECLARE_HASHTABLE(binds, MCTP_BINDS_BITS); 22 28 23 29 /* tag allocations. This list is read and updated from atomic contexts, 24 30 * but elements are free()ed after a RCU grace-period ··· 39 33 struct mutex neigh_lock; 40 34 struct list_head neighbours; 41 35 }; 36 + 37 + static inline u32 mctp_bind_hash(u8 type, u8 local_addr, u8 peer_addr) 38 + { 39 + return hash_32(type | (u32)local_addr << 8 | (u32)peer_addr << 16, 40 + MCTP_BINDS_BITS); 41 + } 42 42 43 43 #endif /* __NETNS_MCTP_H__ */
+7 -4
net/mctp/af_mctp.c
··· 626 626 struct net *net = sock_net(sk); 627 627 struct sock *existing; 628 628 struct mctp_sock *msk; 629 + u32 hash; 629 630 int rc; 630 631 631 632 msk = container_of(sk, struct mctp_sock, sk); 632 633 633 - /* Bind lookup runs under RCU, remain live during that. */ 634 - sock_set_flag(sk, SOCK_RCU_FREE); 634 + hash = mctp_bind_hash(msk->bind_type, msk->bind_addr, MCTP_ADDR_ANY); 635 635 636 636 mutex_lock(&net->mctp.bind_lock); 637 637 638 638 /* Prevent duplicate binds. */ 639 - sk_for_each(existing, &net->mctp.binds) { 639 + sk_for_each(existing, &net->mctp.binds[hash]) { 640 640 struct mctp_sock *mex = 641 641 container_of(existing, struct mctp_sock, sk); 642 642 ··· 648 648 } 649 649 } 650 650 651 - sk_add_node_rcu(sk, &net->mctp.binds); 651 + /* Bind lookup runs under RCU, remain live during that. */ 652 + sock_set_flag(sk, SOCK_RCU_FREE); 653 + 654 + sk_add_node_rcu(sk, &net->mctp.binds[hash]); 652 655 rc = 0; 653 656 654 657 out:
+64 -17
net/mctp/route.c
··· 40 40 return 0; 41 41 } 42 42 43 - static struct mctp_sock *mctp_lookup_bind(struct net *net, struct sk_buff *skb) 43 + static struct mctp_sock *mctp_lookup_bind_details(struct net *net, 44 + struct sk_buff *skb, 45 + u8 type, u8 dest, 46 + u8 src, bool allow_net_any) 44 47 { 45 48 struct mctp_skb_cb *cb = mctp_cb(skb); 46 - struct mctp_hdr *mh; 47 49 struct sock *sk; 48 - u8 type; 50 + u8 hash; 49 51 50 - WARN_ON(!rcu_read_lock_held()); 52 + WARN_ON_ONCE(!rcu_read_lock_held()); 53 + 54 + hash = mctp_bind_hash(type, dest, src); 55 + 56 + sk_for_each_rcu(sk, &net->mctp.binds[hash]) { 57 + struct mctp_sock *msk = container_of(sk, struct mctp_sock, sk); 58 + 59 + if (!allow_net_any && msk->bind_net == MCTP_NET_ANY) 60 + continue; 61 + 62 + if (msk->bind_net != MCTP_NET_ANY && msk->bind_net != cb->net) 63 + continue; 64 + 65 + if (msk->bind_type != type) 66 + continue; 67 + 68 + if (!mctp_address_matches(msk->bind_addr, dest)) 69 + continue; 70 + 71 + return msk; 72 + } 73 + 74 + return NULL; 75 + } 76 + 77 + static struct mctp_sock *mctp_lookup_bind(struct net *net, struct sk_buff *skb) 78 + { 79 + struct mctp_sock *msk; 80 + struct mctp_hdr *mh; 81 + u8 type; 51 82 52 83 /* TODO: look up in skb->cb? */ 53 84 mh = mctp_hdr(skb); ··· 88 57 89 58 type = (*(u8 *)skb->data) & 0x7f; 90 59 91 - sk_for_each_rcu(sk, &net->mctp.binds) { 92 - struct mctp_sock *msk = container_of(sk, struct mctp_sock, sk); 60 + /* Look for binds in order of widening scope. A given destination or 61 + * source address also implies matching on a particular network. 62 + * 63 + * - Matching destination and source 64 + * - Matching destination 65 + * - Matching source 66 + * - Matching network, any address 67 + * - Any network or address 68 + */ 93 69 94 - if (msk->bind_net != MCTP_NET_ANY && msk->bind_net != cb->net) 95 - continue; 96 - 97 - if (msk->bind_type != type) 98 - continue; 99 - 100 - if (!mctp_address_matches(msk->bind_addr, mh->dest)) 101 - continue; 102 - 70 + msk = mctp_lookup_bind_details(net, skb, type, mh->dest, mh->src, 71 + false); 72 + if (msk) 103 73 return msk; 104 - } 74 + msk = mctp_lookup_bind_details(net, skb, type, MCTP_ADDR_ANY, mh->src, 75 + false); 76 + if (msk) 77 + return msk; 78 + msk = mctp_lookup_bind_details(net, skb, type, mh->dest, MCTP_ADDR_ANY, 79 + false); 80 + if (msk) 81 + return msk; 82 + msk = mctp_lookup_bind_details(net, skb, type, MCTP_ADDR_ANY, 83 + MCTP_ADDR_ANY, false); 84 + if (msk) 85 + return msk; 86 + msk = mctp_lookup_bind_details(net, skb, type, MCTP_ADDR_ANY, 87 + MCTP_ADDR_ANY, true); 88 + if (msk) 89 + return msk; 105 90 106 91 return NULL; 107 92 } ··· 1718 1671 struct netns_mctp *ns = &net->mctp; 1719 1672 1720 1673 INIT_LIST_HEAD(&ns->routes); 1721 - INIT_HLIST_HEAD(&ns->binds); 1674 + hash_init(ns->binds); 1722 1675 mutex_init(&ns->bind_lock); 1723 1676 INIT_HLIST_HEAD(&ns->keys); 1724 1677 spin_lock_init(&ns->keys_lock);