aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2009-11-08 05:17:58 -0500
committerDavid S. Miller <davem@davemloft.net>2009-11-08 23:53:06 -0500
commit512615b6b843ff3ff5ad583f34c39b3f302f5f26 (patch)
tree7420705a314bc691bc478225148935dc67f71904
parentd4cada4ae1c012815f95fa507eb86a0ae9d607d7 (diff)
udp: secondary hash on (local port, local address)
Extends udp_table to contain a secondary hash table. socket anchor for this second hash is free, because UDP doesnt use skc_bind_node : We define an union to hold both skc_bind_node & a new hlist_nulls_node udp_portaddr_node udp_lib_get_port() inserts sockets into second hash chain (additional cost of one atomic op) udp_lib_unhash() deletes socket from second hash chain (additional cost of one atomic op) Note : No spinlock lockdep annotation is needed, because lock for the secondary hash chain is always get after lock for primary hash chain. Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/udp.h1
-rw-r--r--include/net/sock.h8
-rw-r--r--include/net/udp.h22
-rw-r--r--net/ipv4/udp.c31
4 files changed, 53 insertions, 9 deletions
diff --git a/include/linux/udp.h b/include/linux/udp.h
index 5b4b5274e683..59f0ddf2d284 100644
--- a/include/linux/udp.h
+++ b/include/linux/udp.h
@@ -57,6 +57,7 @@ struct udp_sock {
57 struct inet_sock inet; 57 struct inet_sock inet;
58#define udp_port_hash inet.sk.__sk_common.skc_u16hashes[0] 58#define udp_port_hash inet.sk.__sk_common.skc_u16hashes[0]
59#define udp_portaddr_hash inet.sk.__sk_common.skc_u16hashes[1] 59#define udp_portaddr_hash inet.sk.__sk_common.skc_u16hashes[1]
60#define udp_portaddr_node inet.sk.__sk_common.skc_portaddr_node
60 int pending; /* Any pending frames ? */ 61 int pending; /* Any pending frames ? */
61 unsigned int corkflag; /* Cork is required */ 62 unsigned int corkflag; /* Cork is required */
62 __u16 encap_type; /* Is this an Encapsulation socket? */ 63 __u16 encap_type; /* Is this an Encapsulation socket? */
diff --git a/include/net/sock.h b/include/net/sock.h
index 827366b62680..3f1a4804bb3f 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -105,7 +105,7 @@ struct net;
105/** 105/**
106 * struct sock_common - minimal network layer representation of sockets 106 * struct sock_common - minimal network layer representation of sockets
107 * @skc_node: main hash linkage for various protocol lookup tables 107 * @skc_node: main hash linkage for various protocol lookup tables
108 * @skc_nulls_node: main hash linkage for UDP/UDP-Lite protocol 108 * @skc_nulls_node: main hash linkage for TCP/UDP/UDP-Lite protocol
109 * @skc_refcnt: reference count 109 * @skc_refcnt: reference count
110 * @skc_tx_queue_mapping: tx queue number for this connection 110 * @skc_tx_queue_mapping: tx queue number for this connection
111 * @skc_hash: hash value used with various protocol lookup tables 111 * @skc_hash: hash value used with various protocol lookup tables
@@ -115,6 +115,7 @@ struct net;
115 * @skc_reuse: %SO_REUSEADDR setting 115 * @skc_reuse: %SO_REUSEADDR setting
116 * @skc_bound_dev_if: bound device index if != 0 116 * @skc_bound_dev_if: bound device index if != 0
117 * @skc_bind_node: bind hash linkage for various protocol lookup tables 117 * @skc_bind_node: bind hash linkage for various protocol lookup tables
118 * @skc_portaddr_node: second hash linkage for UDP/UDP-Lite protocol
118 * @skc_prot: protocol handlers inside a network family 119 * @skc_prot: protocol handlers inside a network family
119 * @skc_net: reference to the network namespace of this socket 120 * @skc_net: reference to the network namespace of this socket
120 * 121 *
@@ -140,7 +141,10 @@ struct sock_common {
140 volatile unsigned char skc_state; 141 volatile unsigned char skc_state;
141 unsigned char skc_reuse; 142 unsigned char skc_reuse;
142 int skc_bound_dev_if; 143 int skc_bound_dev_if;
143 struct hlist_node skc_bind_node; 144 union {
145 struct hlist_node skc_bind_node;
146 struct hlist_nulls_node skc_portaddr_node;
147 };
144 struct proto *skc_prot; 148 struct proto *skc_prot;
145#ifdef CONFIG_NET_NS 149#ifdef CONFIG_NET_NS
146 struct net *skc_net; 150 struct net *skc_net;
diff --git a/include/net/udp.h b/include/net/udp.h
index 9167281e47dc..af41850f742a 100644
--- a/include/net/udp.h
+++ b/include/net/udp.h
@@ -63,10 +63,19 @@ struct udp_hslot {
63 spinlock_t lock; 63 spinlock_t lock;
64} __attribute__((aligned(2 * sizeof(long)))); 64} __attribute__((aligned(2 * sizeof(long))));
65 65
66/**
67 * struct udp_table - UDP table
68 *
69 * @hash: hash table, sockets are hashed on (local port)
70 * @hash2: hash table, sockets are hashed on (local port, local address)
71 * @mask: number of slots in hash tables, minus 1
72 * @log: log2(number of slots in hash table)
73 */
66struct udp_table { 74struct udp_table {
67 struct udp_hslot *hash; 75 struct udp_hslot *hash;
68 unsigned int mask; 76 struct udp_hslot *hash2;
69 unsigned int log; 77 unsigned int mask;
78 unsigned int log;
70}; 79};
71extern struct udp_table udp_table; 80extern struct udp_table udp_table;
72extern void udp_table_init(struct udp_table *, const char *); 81extern void udp_table_init(struct udp_table *, const char *);
@@ -75,6 +84,15 @@ static inline struct udp_hslot *udp_hashslot(struct udp_table *table,
75{ 84{
76 return &table->hash[udp_hashfn(net, num, table->mask)]; 85 return &table->hash[udp_hashfn(net, num, table->mask)];
77} 86}
87/*
88 * For secondary hash, net_hash_mix() is performed before calling
89 * udp_hashslot2(), this explains difference with udp_hashslot()
90 */
91static inline struct udp_hslot *udp_hashslot2(struct udp_table *table,
92 unsigned int hash)
93{
94 return &table->hash2[hash & table->mask];
95}
78 96
79/* Note: this must match 'valbool' in sock_setsockopt */ 97/* Note: this must match 'valbool' in sock_setsockopt */
80#define UDP_CSUM_NOXMIT 1 98#define UDP_CSUM_NOXMIT 1
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index af72de1c8690..5f04216f35ce 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -163,7 +163,7 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum,
163 int (*saddr_comp)(const struct sock *sk1, 163 int (*saddr_comp)(const struct sock *sk1,
164 const struct sock *sk2)) 164 const struct sock *sk2))
165{ 165{
166 struct udp_hslot *hslot; 166 struct udp_hslot *hslot, *hslot2;
167 struct udp_table *udptable = sk->sk_prot->h.udp_table; 167 struct udp_table *udptable = sk->sk_prot->h.udp_table;
168 int error = 1; 168 int error = 1;
169 struct net *net = sock_net(sk); 169 struct net *net = sock_net(sk);
@@ -222,6 +222,13 @@ found:
222 sk_nulls_add_node_rcu(sk, &hslot->head); 222 sk_nulls_add_node_rcu(sk, &hslot->head);
223 hslot->count++; 223 hslot->count++;
224 sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); 224 sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
225
226 hslot2 = udp_hashslot2(udptable, udp_sk(sk)->udp_portaddr_hash);
227 spin_lock(&hslot2->lock);
228 hlist_nulls_add_head_rcu(&udp_sk(sk)->udp_portaddr_node,
229 &hslot2->head);
230 hslot2->count++;
231 spin_unlock(&hslot2->lock);
225 } 232 }
226 error = 0; 233 error = 0;
227fail_unlock: 234fail_unlock:
@@ -1062,14 +1069,22 @@ void udp_lib_unhash(struct sock *sk)
1062{ 1069{
1063 if (sk_hashed(sk)) { 1070 if (sk_hashed(sk)) {
1064 struct udp_table *udptable = sk->sk_prot->h.udp_table; 1071 struct udp_table *udptable = sk->sk_prot->h.udp_table;
1065 struct udp_hslot *hslot = udp_hashslot(udptable, sock_net(sk), 1072 struct udp_hslot *hslot, *hslot2;
1066 udp_sk(sk)->udp_port_hash); 1073
1074 hslot = udp_hashslot(udptable, sock_net(sk),
1075 udp_sk(sk)->udp_port_hash);
1076 hslot2 = udp_hashslot2(udptable, udp_sk(sk)->udp_portaddr_hash);
1067 1077
1068 spin_lock_bh(&hslot->lock); 1078 spin_lock_bh(&hslot->lock);
1069 if (sk_nulls_del_node_init_rcu(sk)) { 1079 if (sk_nulls_del_node_init_rcu(sk)) {
1070 hslot->count--; 1080 hslot->count--;
1071 inet_sk(sk)->inet_num = 0; 1081 inet_sk(sk)->inet_num = 0;
1072 sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); 1082 sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
1083
1084 spin_lock(&hslot2->lock);
1085 hlist_nulls_del_init_rcu(&udp_sk(sk)->udp_portaddr_node);
1086 hslot2->count--;
1087 spin_unlock(&hslot2->lock);
1073 } 1088 }
1074 spin_unlock_bh(&hslot->lock); 1089 spin_unlock_bh(&hslot->lock);
1075 } 1090 }
@@ -1857,7 +1872,7 @@ void __init udp_table_init(struct udp_table *table, const char *name)
1857 1872
1858 if (!CONFIG_BASE_SMALL) 1873 if (!CONFIG_BASE_SMALL)
1859 table->hash = alloc_large_system_hash(name, 1874 table->hash = alloc_large_system_hash(name,
1860 sizeof(struct udp_hslot), 1875 2 * sizeof(struct udp_hslot),
1861 uhash_entries, 1876 uhash_entries,
1862 21, /* one slot per 2 MB */ 1877 21, /* one slot per 2 MB */
1863 0, 1878 0,
@@ -1869,17 +1884,23 @@ void __init udp_table_init(struct udp_table *table, const char *name)
1869 */ 1884 */
1870 if (CONFIG_BASE_SMALL || table->mask < UDP_HTABLE_SIZE_MIN - 1) { 1885 if (CONFIG_BASE_SMALL || table->mask < UDP_HTABLE_SIZE_MIN - 1) {
1871 table->hash = kmalloc(UDP_HTABLE_SIZE_MIN * 1886 table->hash = kmalloc(UDP_HTABLE_SIZE_MIN *
1872 sizeof(struct udp_hslot), GFP_KERNEL); 1887 2 * sizeof(struct udp_hslot), GFP_KERNEL);
1873 if (!table->hash) 1888 if (!table->hash)
1874 panic(name); 1889 panic(name);
1875 table->log = ilog2(UDP_HTABLE_SIZE_MIN); 1890 table->log = ilog2(UDP_HTABLE_SIZE_MIN);
1876 table->mask = UDP_HTABLE_SIZE_MIN - 1; 1891 table->mask = UDP_HTABLE_SIZE_MIN - 1;
1877 } 1892 }
1893 table->hash2 = table->hash + (table->mask + 1);
1878 for (i = 0; i <= table->mask; i++) { 1894 for (i = 0; i <= table->mask; i++) {
1879 INIT_HLIST_NULLS_HEAD(&table->hash[i].head, i); 1895 INIT_HLIST_NULLS_HEAD(&table->hash[i].head, i);
1880 table->hash[i].count = 0; 1896 table->hash[i].count = 0;
1881 spin_lock_init(&table->hash[i].lock); 1897 spin_lock_init(&table->hash[i].lock);
1882 } 1898 }
1899 for (i = 0; i <= table->mask; i++) {
1900 INIT_HLIST_NULLS_HEAD(&table->hash2[i].head, i);
1901 table->hash2[i].count = 0;
1902 spin_lock_init(&table->hash2[i].lock);
1903 }
1883} 1904}
1884 1905
1885void __init udp_init(void) 1906void __init udp_init(void)