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

llc: use a device based hash table to speed up multicast delivery

This patch adds a per SAP device based hash table to solve the
multicast delivery scalability issue when we have large number of
interfaces and a large number of sockets bound to the same SAP.

Signed-off-by: Octavian Purdila <opurdila@ixiacom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Octavian Purdila and committed by
David S. Miller
6d2e3ea2 0f7b67dd

+27 -3
+11
include/net/llc.h
··· 32 32 #define LLC_SAP_STATE_INACTIVE 1 33 33 #define LLC_SAP_STATE_ACTIVE 2 34 34 35 + #define LLC_SK_DEV_HASH_BITS 6 36 + #define LLC_SK_DEV_HASH_ENTRIES (1<<LLC_SK_DEV_HASH_BITS) 37 + 35 38 /** 36 39 * struct llc_sap - Defines the SAP component 37 40 * ··· 59 56 struct list_head node; 60 57 spinlock_t sk_lock; 61 58 struct hlist_nulls_head sk_list; 59 + struct hlist_head sk_dev_hash[LLC_SK_DEV_HASH_ENTRIES]; 62 60 }; 61 + 62 + static inline 63 + struct hlist_head *llc_sk_dev_hash(struct llc_sap *sap, int ifindex) 64 + { 65 + return &sap->sk_dev_hash[ifindex % LLC_SK_DEV_HASH_ENTRIES]; 66 + } 67 + 63 68 64 69 #define LLC_DEST_INVALID 0 /* Invalid LLC PDU type */ 65 70 #define LLC_DEST_SAP 1 /* Type 1 goes here */
+1
include/net/llc_conn.h
··· 77 77 received and caused sending FRMR. 78 78 Used for resending FRMR */ 79 79 u32 cmsg_flags; 80 + struct hlist_node dev_hash_node; 80 81 }; 81 82 82 83 static inline struct llc_sock *llc_sk(const struct sock *sk)
+9 -1
net/llc/llc_conn.c
··· 682 682 */ 683 683 void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk) 684 684 { 685 + struct llc_sock *llc = llc_sk(sk); 686 + struct hlist_head *dev_hb = llc_sk_dev_hash(sap, llc->dev->ifindex); 687 + 685 688 llc_sap_hold(sap); 686 - spin_lock_bh(&sap->sk_lock); 687 689 llc_sk(sk)->sap = sap; 690 + 691 + spin_lock_bh(&sap->sk_lock); 688 692 sk_nulls_add_node_rcu(sk, &sap->sk_list); 693 + hlist_add_head(&llc->dev_hash_node, dev_hb); 689 694 spin_unlock_bh(&sap->sk_lock); 690 695 } 691 696 ··· 704 699 */ 705 700 void llc_sap_remove_socket(struct llc_sap *sap, struct sock *sk) 706 701 { 702 + struct llc_sock *llc = llc_sk(sk); 703 + 707 704 spin_lock_bh(&sap->sk_lock); 708 705 sk_nulls_del_node_init_rcu(sk); 706 + hlist_del(&llc->dev_hash_node); 709 707 spin_unlock_bh(&sap->sk_lock); 710 708 llc_sap_put(sap); 711 709 }
+6 -2
net/llc/llc_sap.c
··· 387 387 { 388 388 int i = 0, count = 256 / sizeof(struct sock *); 389 389 struct sock *sk, *stack[count]; 390 - struct hlist_nulls_node *node; 390 + struct hlist_node *node; 391 + struct llc_sock *llc; 392 + struct hlist_head *dev_hb = llc_sk_dev_hash(sap, skb->dev->ifindex); 391 393 392 394 spin_lock_bh(&sap->sk_lock); 393 - sk_nulls_for_each_rcu(sk, node, &sap->sk_list) { 395 + hlist_for_each_entry(llc, node, dev_hb, dev_hash_node) { 396 + 397 + sk = &llc->sk; 394 398 395 399 if (!llc_mcast_match(sap, laddr, skb, sk)) 396 400 continue;