aboutsummaryrefslogtreecommitdiffstats
path: root/net/dccp/ccid.c
diff options
context:
space:
mode:
authorGerrit Renker <gerrit@erg.abdn.ac.uk>2009-01-05 00:42:53 -0500
committerDavid S. Miller <davem@davemloft.net>2009-01-05 00:42:53 -0500
commitddebc973c56b51b4e5d84d606f0430d81b895d67 (patch)
treecebe0e4461346072b2063132fc1d9cf8c3e148f1 /net/dccp/ccid.c
parent6ea2fde13abd3444008ab5e9585f9ed249e6047e (diff)
dccp: Lockless integration of CCID congestion-control plugins
Based on Arnaldo's earlier patch, this patch integrates the standardised CCID congestion control plugins (CCID-2 and CCID-3) of DCCP with dccp.ko: * enables a faster connection path by eliminating the need to always go through the CCID registration lock; * updates the implementation to use only a single array whose size equals the number of configured CCIDs instead of the maximum (256); * since the CCIDs are now fixed array elements, synchronization is no longer needed, simplifying use and implementation. CCID-2 is suggested as minimum for a basic DCCP implementation (RFC 4340, 10); CCID-3 is a standards-track CCID supported by RFC 4342 and RFC 5348. Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/dccp/ccid.c')
-rw-r--r--net/dccp/ccid.c156
1 files changed, 100 insertions, 56 deletions
diff --git a/net/dccp/ccid.c b/net/dccp/ccid.c
index bcc643f992ae..538d3b1da623 100644
--- a/net/dccp/ccid.c
+++ b/net/dccp/ccid.c
@@ -13,6 +13,70 @@
13 13
14#include "ccid.h" 14#include "ccid.h"
15 15
16static struct ccid_operations *ccids[] = {
17 &ccid2_ops,
18#ifdef CONFIG_IP_DCCP_CCID3
19 &ccid3_ops,
20#endif
21};
22
23static struct ccid_operations *ccid_by_number(const u8 id)
24{
25 int i;
26
27 for (i = 0; i < ARRAY_SIZE(ccids); i++)
28 if (ccids[i]->ccid_id == id)
29 return ccids[i];
30 return NULL;
31}
32
33/* check that up to @array_len members in @ccid_array are supported */
34bool ccid_support_check(u8 const *ccid_array, u8 array_len)
35{
36 while (array_len > 0)
37 if (ccid_by_number(ccid_array[--array_len]) == NULL)
38 return false;
39 return true;
40}
41
42/**
43 * ccid_get_builtin_ccids - Populate a list of built-in CCIDs
44 * @ccid_array: pointer to copy into
45 * @array_len: value to return length into
46 * This function allocates memory - caller must see that it is freed after use.
47 */
48int ccid_get_builtin_ccids(u8 **ccid_array, u8 *array_len)
49{
50 *ccid_array = kmalloc(ARRAY_SIZE(ccids), gfp_any());
51 if (*ccid_array == NULL)
52 return -ENOBUFS;
53
54 for (*array_len = 0; *array_len < ARRAY_SIZE(ccids); *array_len += 1)
55 (*ccid_array)[*array_len] = ccids[*array_len]->ccid_id;
56 return 0;
57}
58
59int ccid_getsockopt_builtin_ccids(struct sock *sk, int len,
60 char __user *optval, int __user *optlen)
61{
62 u8 *ccid_array, array_len;
63 int err = 0;
64
65 if (len < ARRAY_SIZE(ccids))
66 return -EINVAL;
67
68 if (ccid_get_builtin_ccids(&ccid_array, &array_len))
69 return -ENOBUFS;
70
71 if (put_user(array_len, optlen) ||
72 copy_to_user(optval, ccid_array, array_len))
73 err = -EFAULT;
74
75 kfree(ccid_array);
76 return err;
77}
78
79#ifdef ___OLD_INTERFACE_TO_BE_REMOVED___
16static u8 builtin_ccids[] = { 80static u8 builtin_ccids[] = {
17 DCCPC_CCID2, /* CCID2 is supported by default */ 81 DCCPC_CCID2, /* CCID2 is supported by default */
18#if defined(CONFIG_IP_DCCP_CCID3) || defined(CONFIG_IP_DCCP_CCID3_MODULE) 82#if defined(CONFIG_IP_DCCP_CCID3) || defined(CONFIG_IP_DCCP_CCID3_MODULE)
@@ -62,6 +126,7 @@ static inline void ccids_read_unlock(void)
62#define ccids_read_lock() do { } while(0) 126#define ccids_read_lock() do { } while(0)
63#define ccids_read_unlock() do { } while(0) 127#define ccids_read_unlock() do { } while(0)
64#endif 128#endif
129#endif /* ___OLD_INTERFACE_TO_BE_REMOVED___ */
65 130
66static struct kmem_cache *ccid_kmem_cache_create(int obj_size, const char *fmt,...) 131static struct kmem_cache *ccid_kmem_cache_create(int obj_size, const char *fmt,...)
67{ 132{
@@ -93,6 +158,7 @@ static void ccid_kmem_cache_destroy(struct kmem_cache *slab)
93 } 158 }
94} 159}
95 160
161#ifdef ___OLD_INTERFACE_TO_BE_REMOVED___
96/* check that up to @array_len members in @ccid_array are supported */ 162/* check that up to @array_len members in @ccid_array are supported */
97bool ccid_support_check(u8 const *ccid_array, u8 array_len) 163bool ccid_support_check(u8 const *ccid_array, u8 array_len)
98{ 164{
@@ -133,8 +199,9 @@ int ccid_getsockopt_builtin_ccids(struct sock *sk, int len,
133 return -EFAULT; 199 return -EFAULT;
134 return 0; 200 return 0;
135} 201}
202#endif /* ___OLD_INTERFACE_TO_BE_REMOVED___ */
136 203
137int ccid_register(struct ccid_operations *ccid_ops) 204static int ccid_activate(struct ccid_operations *ccid_ops)
138{ 205{
139 int err = -ENOBUFS; 206 int err = -ENOBUFS;
140 207
@@ -152,79 +219,40 @@ int ccid_register(struct ccid_operations *ccid_ops)
152 if (ccid_ops->ccid_hc_tx_slab == NULL) 219 if (ccid_ops->ccid_hc_tx_slab == NULL)
153 goto out_free_rx_slab; 220 goto out_free_rx_slab;
154 221
155 ccids_write_lock(); 222 pr_info("CCID: Activated CCID %d (%s)\n",
156 err = -EEXIST;
157 if (ccids[ccid_ops->ccid_id] == NULL) {
158 ccids[ccid_ops->ccid_id] = ccid_ops;
159 err = 0;
160 }
161 ccids_write_unlock();
162 if (err != 0)
163 goto out_free_tx_slab;
164
165 pr_info("CCID: Registered CCID %d (%s)\n",
166 ccid_ops->ccid_id, ccid_ops->ccid_name); 223 ccid_ops->ccid_id, ccid_ops->ccid_name);
224 err = 0;
167out: 225out:
168 return err; 226 return err;
169out_free_tx_slab:
170 ccid_kmem_cache_destroy(ccid_ops->ccid_hc_tx_slab);
171 ccid_ops->ccid_hc_tx_slab = NULL;
172 goto out;
173out_free_rx_slab: 227out_free_rx_slab:
174 ccid_kmem_cache_destroy(ccid_ops->ccid_hc_rx_slab); 228 ccid_kmem_cache_destroy(ccid_ops->ccid_hc_rx_slab);
175 ccid_ops->ccid_hc_rx_slab = NULL; 229 ccid_ops->ccid_hc_rx_slab = NULL;
176 goto out; 230 goto out;
177} 231}
178 232
179EXPORT_SYMBOL_GPL(ccid_register); 233static void ccid_deactivate(struct ccid_operations *ccid_ops)
180
181int ccid_unregister(struct ccid_operations *ccid_ops)
182{ 234{
183 ccids_write_lock();
184 ccids[ccid_ops->ccid_id] = NULL;
185 ccids_write_unlock();
186
187 ccid_kmem_cache_destroy(ccid_ops->ccid_hc_tx_slab); 235 ccid_kmem_cache_destroy(ccid_ops->ccid_hc_tx_slab);
188 ccid_ops->ccid_hc_tx_slab = NULL; 236 ccid_ops->ccid_hc_tx_slab = NULL;
189 ccid_kmem_cache_destroy(ccid_ops->ccid_hc_rx_slab); 237 ccid_kmem_cache_destroy(ccid_ops->ccid_hc_rx_slab);
190 ccid_ops->ccid_hc_rx_slab = NULL; 238 ccid_ops->ccid_hc_rx_slab = NULL;
191 239
192 pr_info("CCID: Unregistered CCID %d (%s)\n", 240 pr_info("CCID: Deactivated CCID %d (%s)\n",
193 ccid_ops->ccid_id, ccid_ops->ccid_name); 241 ccid_ops->ccid_id, ccid_ops->ccid_name);
194 return 0;
195} 242}
196 243
197EXPORT_SYMBOL_GPL(ccid_unregister);
198
199struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx, gfp_t gfp) 244struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx, gfp_t gfp)
200{ 245{
201 struct ccid_operations *ccid_ops; 246 struct ccid_operations *ccid_ops = ccid_by_number(id);
202 struct ccid *ccid = NULL; 247 struct ccid *ccid = NULL;
203 248
204 ccids_read_lock();
205#ifdef CONFIG_MODULES
206 if (ccids[id] == NULL) {
207 /* We only try to load if in process context */
208 ccids_read_unlock();
209 if (gfp & GFP_ATOMIC)
210 goto out;
211 request_module("net-dccp-ccid-%d", id);
212 ccids_read_lock();
213 }
214#endif
215 ccid_ops = ccids[id];
216 if (ccid_ops == NULL) 249 if (ccid_ops == NULL)
217 goto out_unlock; 250 goto out;
218
219 if (!try_module_get(ccid_ops->ccid_owner))
220 goto out_unlock;
221
222 ccids_read_unlock();
223 251
224 ccid = kmem_cache_alloc(rx ? ccid_ops->ccid_hc_rx_slab : 252 ccid = kmem_cache_alloc(rx ? ccid_ops->ccid_hc_rx_slab :
225 ccid_ops->ccid_hc_tx_slab, gfp); 253 ccid_ops->ccid_hc_tx_slab, gfp);
226 if (ccid == NULL) 254 if (ccid == NULL)
227 goto out_module_put; 255 goto out;
228 ccid->ccid_ops = ccid_ops; 256 ccid->ccid_ops = ccid_ops;
229 if (rx) { 257 if (rx) {
230 memset(ccid + 1, 0, ccid_ops->ccid_hc_rx_obj_size); 258 memset(ccid + 1, 0, ccid_ops->ccid_hc_rx_obj_size);
@@ -239,15 +267,10 @@ struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx, gfp_t gfp)
239 } 267 }
240out: 268out:
241 return ccid; 269 return ccid;
242out_unlock:
243 ccids_read_unlock();
244 goto out;
245out_free_ccid: 270out_free_ccid:
246 kmem_cache_free(rx ? ccid_ops->ccid_hc_rx_slab : 271 kmem_cache_free(rx ? ccid_ops->ccid_hc_rx_slab :
247 ccid_ops->ccid_hc_tx_slab, ccid); 272 ccid_ops->ccid_hc_tx_slab, ccid);
248 ccid = NULL; 273 ccid = NULL;
249out_module_put:
250 module_put(ccid_ops->ccid_owner);
251 goto out; 274 goto out;
252} 275}
253 276
@@ -270,10 +293,6 @@ static void ccid_delete(struct ccid *ccid, struct sock *sk, int rx)
270 ccid_ops->ccid_hc_tx_exit(sk); 293 ccid_ops->ccid_hc_tx_exit(sk);
271 kmem_cache_free(ccid_ops->ccid_hc_tx_slab, ccid); 294 kmem_cache_free(ccid_ops->ccid_hc_tx_slab, ccid);
272 } 295 }
273 ccids_read_lock();
274 if (ccids[ccid_ops->ccid_id] != NULL)
275 module_put(ccid_ops->ccid_owner);
276 ccids_read_unlock();
277} 296}
278 297
279void ccid_hc_rx_delete(struct ccid *ccid, struct sock *sk) 298void ccid_hc_rx_delete(struct ccid *ccid, struct sock *sk)
@@ -289,3 +308,28 @@ void ccid_hc_tx_delete(struct ccid *ccid, struct sock *sk)
289} 308}
290 309
291EXPORT_SYMBOL_GPL(ccid_hc_tx_delete); 310EXPORT_SYMBOL_GPL(ccid_hc_tx_delete);
311
312int __init ccid_initialize_builtins(void)
313{
314 int i, err;
315
316 for (i = 0; i < ARRAY_SIZE(ccids); i++) {
317 err = ccid_activate(ccids[i]);
318 if (err)
319 goto unwind_registrations;
320 }
321 return 0;
322
323unwind_registrations:
324 while(--i >= 0)
325 ccid_deactivate(ccids[i]);
326 return err;
327}
328
329void ccid_cleanup_builtins(void)
330{
331 int i;
332
333 for (i = 0; i < ARRAY_SIZE(ccids); i++)
334 ccid_deactivate(ccids[i]);
335}