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>
This commit is contained in:
		
					parent
					
						
							
								6ea2fde13a
							
						
					
				
			
			
				commit
				
					
						ddebc973c5
					
				
			
		
					 11 changed files with 148 additions and 168 deletions
				
			
		| 
						 | 
					@ -1,7 +1,6 @@
 | 
				
			||||||
menuconfig IP_DCCP
 | 
					menuconfig IP_DCCP
 | 
				
			||||||
	tristate "The DCCP Protocol (EXPERIMENTAL)"
 | 
						tristate "The DCCP Protocol (EXPERIMENTAL)"
 | 
				
			||||||
	depends on INET && EXPERIMENTAL
 | 
						depends on INET && EXPERIMENTAL
 | 
				
			||||||
	select IP_DCCP_CCID2
 | 
					 | 
				
			||||||
	---help---
 | 
						---help---
 | 
				
			||||||
	  Datagram Congestion Control Protocol (RFC 4340)
 | 
						  Datagram Congestion Control Protocol (RFC 4340)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,9 +24,6 @@ config INET_DCCP_DIAG
 | 
				
			||||||
	def_tristate y if (IP_DCCP = y && INET_DIAG = y)
 | 
						def_tristate y if (IP_DCCP = y && INET_DIAG = y)
 | 
				
			||||||
	def_tristate m
 | 
						def_tristate m
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config IP_DCCP_ACKVEC
 | 
					 | 
				
			||||||
	bool
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
source "net/dccp/ccids/Kconfig"
 | 
					source "net/dccp/ccids/Kconfig"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
menu "DCCP Kernel Hacking"
 | 
					menu "DCCP Kernel Hacking"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,14 +2,19 @@ obj-$(CONFIG_IP_DCCP) += dccp.o dccp_ipv4.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dccp-y := ccid.o feat.o input.o minisocks.o options.o output.o proto.o timer.o
 | 
					dccp-y := ccid.o feat.o input.o minisocks.o options.o output.o proto.o timer.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# CCID algorithms to be used by dccp.ko
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# CCID-2 is default (RFC 4340, p. 77) and has Ack Vectors as dependency
 | 
				
			||||||
 | 
					dccp-y += ccids/ccid2.o ackvec.o
 | 
				
			||||||
 | 
					dccp-$(CONFIG_IP_DCCP_CCID3)	+= ccids/ccid3.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dccp_ipv4-y := ipv4.o
 | 
					dccp_ipv4-y := ipv4.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# build dccp_ipv6 as module whenever either IPv6 or DCCP is a module
 | 
					# build dccp_ipv6 as module whenever either IPv6 or DCCP is a module
 | 
				
			||||||
obj-$(subst y,$(CONFIG_IP_DCCP),$(CONFIG_IPV6)) += dccp_ipv6.o
 | 
					obj-$(subst y,$(CONFIG_IP_DCCP),$(CONFIG_IPV6)) += dccp_ipv6.o
 | 
				
			||||||
dccp_ipv6-y := ipv6.o
 | 
					dccp_ipv6-y := ipv6.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dccp-$(CONFIG_IP_DCCP_ACKVEC) += ackvec.o
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
obj-$(CONFIG_INET_DCCP_DIAG) += dccp_diag.o
 | 
					obj-$(CONFIG_INET_DCCP_DIAG) += dccp_diag.o
 | 
				
			||||||
obj-$(CONFIG_NET_DCCPPROBE) += dccp_probe.o
 | 
					obj-$(CONFIG_NET_DCCPPROBE) += dccp_probe.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -84,7 +84,7 @@ struct dccp_ackvec_record {
 | 
				
			||||||
struct sock;
 | 
					struct sock;
 | 
				
			||||||
struct sk_buff;
 | 
					struct sk_buff;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_IP_DCCP_ACKVEC
 | 
					#ifndef ___OLD_INTERFACE_TO_BE_REMOVED___
 | 
				
			||||||
extern int dccp_ackvec_init(void);
 | 
					extern int dccp_ackvec_init(void);
 | 
				
			||||||
extern void dccp_ackvec_exit(void);
 | 
					extern void dccp_ackvec_exit(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -106,7 +106,7 @@ static inline int dccp_ackvec_pending(const struct dccp_ackvec *av)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return av->av_vec_len;
 | 
						return av->av_vec_len;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#else /* CONFIG_IP_DCCP_ACKVEC */
 | 
					#else /* ___OLD_INTERFACE_TO_BE_REMOVED___ */
 | 
				
			||||||
static inline int dccp_ackvec_init(void)
 | 
					static inline int dccp_ackvec_init(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										156
									
								
								net/dccp/ccid.c
									
										
									
									
									
								
							
							
						
						
									
										156
									
								
								net/dccp/ccid.c
									
										
									
									
									
								
							| 
						 | 
					@ -13,6 +13,70 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "ccid.h"
 | 
					#include "ccid.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct ccid_operations *ccids[] = {
 | 
				
			||||||
 | 
						&ccid2_ops,
 | 
				
			||||||
 | 
					#ifdef CONFIG_IP_DCCP_CCID3
 | 
				
			||||||
 | 
						&ccid3_ops,
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct ccid_operations *ccid_by_number(const u8 id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < ARRAY_SIZE(ccids); i++)
 | 
				
			||||||
 | 
							if (ccids[i]->ccid_id == id)
 | 
				
			||||||
 | 
								return ccids[i];
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* check that up to @array_len members in @ccid_array are supported */
 | 
				
			||||||
 | 
					bool ccid_support_check(u8 const *ccid_array, u8 array_len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						while (array_len > 0)
 | 
				
			||||||
 | 
							if (ccid_by_number(ccid_array[--array_len]) == NULL)
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * ccid_get_builtin_ccids  -  Populate a list of built-in CCIDs
 | 
				
			||||||
 | 
					 * @ccid_array: pointer to copy into
 | 
				
			||||||
 | 
					 * @array_len: value to return length into
 | 
				
			||||||
 | 
					 * This function allocates memory - caller must see that it is freed after use.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int ccid_get_builtin_ccids(u8 **ccid_array, u8 *array_len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						*ccid_array = kmalloc(ARRAY_SIZE(ccids), gfp_any());
 | 
				
			||||||
 | 
						if (*ccid_array == NULL)
 | 
				
			||||||
 | 
							return -ENOBUFS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (*array_len = 0; *array_len < ARRAY_SIZE(ccids); *array_len += 1)
 | 
				
			||||||
 | 
							(*ccid_array)[*array_len] = ccids[*array_len]->ccid_id;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ccid_getsockopt_builtin_ccids(struct sock *sk, int len,
 | 
				
			||||||
 | 
									  char __user *optval, int __user *optlen)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u8 *ccid_array, array_len;
 | 
				
			||||||
 | 
						int err = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (len < ARRAY_SIZE(ccids))
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ccid_get_builtin_ccids(&ccid_array, &array_len))
 | 
				
			||||||
 | 
							return -ENOBUFS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (put_user(array_len, optlen) ||
 | 
				
			||||||
 | 
						    copy_to_user(optval, ccid_array, array_len))
 | 
				
			||||||
 | 
							err = -EFAULT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						kfree(ccid_array);
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef ___OLD_INTERFACE_TO_BE_REMOVED___
 | 
				
			||||||
static u8 builtin_ccids[] = {
 | 
					static u8 builtin_ccids[] = {
 | 
				
			||||||
	DCCPC_CCID2,		/* CCID2 is supported by default */
 | 
						DCCPC_CCID2,		/* CCID2 is supported by default */
 | 
				
			||||||
#if defined(CONFIG_IP_DCCP_CCID3) || defined(CONFIG_IP_DCCP_CCID3_MODULE)
 | 
					#if defined(CONFIG_IP_DCCP_CCID3) || defined(CONFIG_IP_DCCP_CCID3_MODULE)
 | 
				
			||||||
| 
						 | 
					@ -62,6 +126,7 @@ static inline void ccids_read_unlock(void)
 | 
				
			||||||
#define ccids_read_lock() do { } while(0)
 | 
					#define ccids_read_lock() do { } while(0)
 | 
				
			||||||
#define ccids_read_unlock() do { } while(0)
 | 
					#define ccids_read_unlock() do { } while(0)
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					#endif /* ___OLD_INTERFACE_TO_BE_REMOVED___ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct kmem_cache *ccid_kmem_cache_create(int obj_size, const char *fmt,...)
 | 
					static struct kmem_cache *ccid_kmem_cache_create(int obj_size, const char *fmt,...)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -93,6 +158,7 @@ static void ccid_kmem_cache_destroy(struct kmem_cache *slab)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef ___OLD_INTERFACE_TO_BE_REMOVED___
 | 
				
			||||||
/* check that up to @array_len members in @ccid_array are supported */
 | 
					/* check that up to @array_len members in @ccid_array are supported */
 | 
				
			||||||
bool ccid_support_check(u8 const *ccid_array, u8 array_len)
 | 
					bool ccid_support_check(u8 const *ccid_array, u8 array_len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -133,8 +199,9 @@ int ccid_getsockopt_builtin_ccids(struct sock *sk, int len,
 | 
				
			||||||
		return -EFAULT;
 | 
							return -EFAULT;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					#endif /* ___OLD_INTERFACE_TO_BE_REMOVED___ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int ccid_register(struct ccid_operations *ccid_ops)
 | 
					static int ccid_activate(struct ccid_operations *ccid_ops)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int err = -ENOBUFS;
 | 
						int err = -ENOBUFS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -152,79 +219,40 @@ int ccid_register(struct ccid_operations *ccid_ops)
 | 
				
			||||||
	if (ccid_ops->ccid_hc_tx_slab == NULL)
 | 
						if (ccid_ops->ccid_hc_tx_slab == NULL)
 | 
				
			||||||
		goto out_free_rx_slab;
 | 
							goto out_free_rx_slab;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ccids_write_lock();
 | 
						pr_info("CCID: Activated CCID %d (%s)\n",
 | 
				
			||||||
	err = -EEXIST;
 | 
					 | 
				
			||||||
	if (ccids[ccid_ops->ccid_id] == NULL) {
 | 
					 | 
				
			||||||
		ccids[ccid_ops->ccid_id] = ccid_ops;
 | 
					 | 
				
			||||||
		err = 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	ccids_write_unlock();
 | 
					 | 
				
			||||||
	if (err != 0)
 | 
					 | 
				
			||||||
		goto out_free_tx_slab;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pr_info("CCID: Registered CCID %d (%s)\n",
 | 
					 | 
				
			||||||
		ccid_ops->ccid_id, ccid_ops->ccid_name);
 | 
							ccid_ops->ccid_id, ccid_ops->ccid_name);
 | 
				
			||||||
 | 
						err = 0;
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
out_free_tx_slab:
 | 
					 | 
				
			||||||
	ccid_kmem_cache_destroy(ccid_ops->ccid_hc_tx_slab);
 | 
					 | 
				
			||||||
	ccid_ops->ccid_hc_tx_slab = NULL;
 | 
					 | 
				
			||||||
	goto out;
 | 
					 | 
				
			||||||
out_free_rx_slab:
 | 
					out_free_rx_slab:
 | 
				
			||||||
	ccid_kmem_cache_destroy(ccid_ops->ccid_hc_rx_slab);
 | 
						ccid_kmem_cache_destroy(ccid_ops->ccid_hc_rx_slab);
 | 
				
			||||||
	ccid_ops->ccid_hc_rx_slab = NULL;
 | 
						ccid_ops->ccid_hc_rx_slab = NULL;
 | 
				
			||||||
	goto out;
 | 
						goto out;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
EXPORT_SYMBOL_GPL(ccid_register);
 | 
					static void ccid_deactivate(struct ccid_operations *ccid_ops)
 | 
				
			||||||
 | 
					 | 
				
			||||||
int ccid_unregister(struct ccid_operations *ccid_ops)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	ccids_write_lock();
 | 
					 | 
				
			||||||
	ccids[ccid_ops->ccid_id] = NULL;
 | 
					 | 
				
			||||||
	ccids_write_unlock();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ccid_kmem_cache_destroy(ccid_ops->ccid_hc_tx_slab);
 | 
						ccid_kmem_cache_destroy(ccid_ops->ccid_hc_tx_slab);
 | 
				
			||||||
	ccid_ops->ccid_hc_tx_slab = NULL;
 | 
						ccid_ops->ccid_hc_tx_slab = NULL;
 | 
				
			||||||
	ccid_kmem_cache_destroy(ccid_ops->ccid_hc_rx_slab);
 | 
						ccid_kmem_cache_destroy(ccid_ops->ccid_hc_rx_slab);
 | 
				
			||||||
	ccid_ops->ccid_hc_rx_slab = NULL;
 | 
						ccid_ops->ccid_hc_rx_slab = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pr_info("CCID: Unregistered CCID %d (%s)\n",
 | 
						pr_info("CCID: Deactivated CCID %d (%s)\n",
 | 
				
			||||||
		ccid_ops->ccid_id, ccid_ops->ccid_name);
 | 
							ccid_ops->ccid_id, ccid_ops->ccid_name);
 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
EXPORT_SYMBOL_GPL(ccid_unregister);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx, gfp_t gfp)
 | 
					struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx, gfp_t gfp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct ccid_operations *ccid_ops;
 | 
						struct ccid_operations *ccid_ops = ccid_by_number(id);
 | 
				
			||||||
	struct ccid *ccid = NULL;
 | 
						struct ccid *ccid = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ccids_read_lock();
 | 
					 | 
				
			||||||
#ifdef CONFIG_MODULES
 | 
					 | 
				
			||||||
	if (ccids[id] == NULL) {
 | 
					 | 
				
			||||||
		/* We only try to load if in process context */
 | 
					 | 
				
			||||||
		ccids_read_unlock();
 | 
					 | 
				
			||||||
		if (gfp & GFP_ATOMIC)
 | 
					 | 
				
			||||||
			goto out;
 | 
					 | 
				
			||||||
		request_module("net-dccp-ccid-%d", id);
 | 
					 | 
				
			||||||
		ccids_read_lock();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
	ccid_ops = ccids[id];
 | 
					 | 
				
			||||||
	if (ccid_ops == NULL)
 | 
						if (ccid_ops == NULL)
 | 
				
			||||||
		goto out_unlock;
 | 
							goto out;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!try_module_get(ccid_ops->ccid_owner))
 | 
					 | 
				
			||||||
		goto out_unlock;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ccids_read_unlock();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ccid = kmem_cache_alloc(rx ? ccid_ops->ccid_hc_rx_slab :
 | 
						ccid = kmem_cache_alloc(rx ? ccid_ops->ccid_hc_rx_slab :
 | 
				
			||||||
				     ccid_ops->ccid_hc_tx_slab, gfp);
 | 
									     ccid_ops->ccid_hc_tx_slab, gfp);
 | 
				
			||||||
	if (ccid == NULL)
 | 
						if (ccid == NULL)
 | 
				
			||||||
		goto out_module_put;
 | 
							goto out;
 | 
				
			||||||
	ccid->ccid_ops = ccid_ops;
 | 
						ccid->ccid_ops = ccid_ops;
 | 
				
			||||||
	if (rx) {
 | 
						if (rx) {
 | 
				
			||||||
		memset(ccid + 1, 0, ccid_ops->ccid_hc_rx_obj_size);
 | 
							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)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	return ccid;
 | 
						return ccid;
 | 
				
			||||||
out_unlock:
 | 
					 | 
				
			||||||
	ccids_read_unlock();
 | 
					 | 
				
			||||||
	goto out;
 | 
					 | 
				
			||||||
out_free_ccid:
 | 
					out_free_ccid:
 | 
				
			||||||
	kmem_cache_free(rx ? ccid_ops->ccid_hc_rx_slab :
 | 
						kmem_cache_free(rx ? ccid_ops->ccid_hc_rx_slab :
 | 
				
			||||||
			ccid_ops->ccid_hc_tx_slab, ccid);
 | 
								ccid_ops->ccid_hc_tx_slab, ccid);
 | 
				
			||||||
	ccid = NULL;
 | 
						ccid = NULL;
 | 
				
			||||||
out_module_put:
 | 
					 | 
				
			||||||
	module_put(ccid_ops->ccid_owner);
 | 
					 | 
				
			||||||
	goto out;
 | 
						goto out;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -270,10 +293,6 @@ static void ccid_delete(struct ccid *ccid, struct sock *sk, int rx)
 | 
				
			||||||
			ccid_ops->ccid_hc_tx_exit(sk);
 | 
								ccid_ops->ccid_hc_tx_exit(sk);
 | 
				
			||||||
		kmem_cache_free(ccid_ops->ccid_hc_tx_slab,  ccid);
 | 
							kmem_cache_free(ccid_ops->ccid_hc_tx_slab,  ccid);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ccids_read_lock();
 | 
					 | 
				
			||||||
	if (ccids[ccid_ops->ccid_id] != NULL)
 | 
					 | 
				
			||||||
		module_put(ccid_ops->ccid_owner);
 | 
					 | 
				
			||||||
	ccids_read_unlock();
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ccid_hc_rx_delete(struct ccid *ccid, struct sock *sk)
 | 
					void 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)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
EXPORT_SYMBOL_GPL(ccid_hc_tx_delete);
 | 
					EXPORT_SYMBOL_GPL(ccid_hc_tx_delete);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int __init ccid_initialize_builtins(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i, err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < ARRAY_SIZE(ccids); i++) {
 | 
				
			||||||
 | 
							err = ccid_activate(ccids[i]);
 | 
				
			||||||
 | 
							if (err)
 | 
				
			||||||
 | 
								goto unwind_registrations;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					unwind_registrations:
 | 
				
			||||||
 | 
						while(--i >= 0)
 | 
				
			||||||
 | 
							ccid_deactivate(ccids[i]);
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ccid_cleanup_builtins(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < ARRAY_SIZE(ccids); i++)
 | 
				
			||||||
 | 
							ccid_deactivate(ccids[i]);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,7 +29,6 @@ struct tcp_info;
 | 
				
			||||||
 *  @ccid_id: numerical CCID ID (up to %CCID_MAX, cf. table 5 in RFC 4340, 10.)
 | 
					 *  @ccid_id: numerical CCID ID (up to %CCID_MAX, cf. table 5 in RFC 4340, 10.)
 | 
				
			||||||
 *  @ccid_ccmps: the CCMPS including network/transport headers (0 when disabled)
 | 
					 *  @ccid_ccmps: the CCMPS including network/transport headers (0 when disabled)
 | 
				
			||||||
 *  @ccid_name: alphabetical identifier string for @ccid_id
 | 
					 *  @ccid_name: alphabetical identifier string for @ccid_id
 | 
				
			||||||
 *  @ccid_owner: module which implements/owns this CCID
 | 
					 | 
				
			||||||
 *  @ccid_hc_{r,t}x_slab: memory pool for the receiver/sender half-connection
 | 
					 *  @ccid_hc_{r,t}x_slab: memory pool for the receiver/sender half-connection
 | 
				
			||||||
 *  @ccid_hc_{r,t}x_obj_size: size of the receiver/sender half-connection socket
 | 
					 *  @ccid_hc_{r,t}x_obj_size: size of the receiver/sender half-connection socket
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					@ -48,7 +47,6 @@ struct ccid_operations {
 | 
				
			||||||
	unsigned char		ccid_id;
 | 
						unsigned char		ccid_id;
 | 
				
			||||||
	__u32			ccid_ccmps;
 | 
						__u32			ccid_ccmps;
 | 
				
			||||||
	const char		*ccid_name;
 | 
						const char		*ccid_name;
 | 
				
			||||||
	struct module		*ccid_owner;
 | 
					 | 
				
			||||||
	struct kmem_cache	*ccid_hc_rx_slab,
 | 
						struct kmem_cache	*ccid_hc_rx_slab,
 | 
				
			||||||
				*ccid_hc_tx_slab;
 | 
									*ccid_hc_tx_slab;
 | 
				
			||||||
	__u32			ccid_hc_rx_obj_size,
 | 
						__u32			ccid_hc_rx_obj_size,
 | 
				
			||||||
| 
						 | 
					@ -90,8 +88,13 @@ struct ccid_operations {
 | 
				
			||||||
						 int __user *optlen);
 | 
											 int __user *optlen);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern int ccid_register(struct ccid_operations *ccid_ops);
 | 
					extern struct ccid_operations ccid2_ops;
 | 
				
			||||||
extern int ccid_unregister(struct ccid_operations *ccid_ops);
 | 
					#ifdef CONFIG_IP_DCCP_CCID3
 | 
				
			||||||
 | 
					extern struct ccid_operations ccid3_ops;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int  ccid_initialize_builtins(void);
 | 
				
			||||||
 | 
					extern void ccid_cleanup_builtins(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ccid {
 | 
					struct ccid {
 | 
				
			||||||
	struct ccid_operations *ccid_ops;
 | 
						struct ccid_operations *ccid_ops;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,80 +1,52 @@
 | 
				
			||||||
menu "DCCP CCIDs Configuration (EXPERIMENTAL)"
 | 
					menu "DCCP CCIDs Configuration (EXPERIMENTAL)"
 | 
				
			||||||
	depends on EXPERIMENTAL
 | 
						depends on EXPERIMENTAL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config IP_DCCP_CCID2
 | 
					 | 
				
			||||||
	tristate "CCID2 (TCP-Like) (EXPERIMENTAL)"
 | 
					 | 
				
			||||||
	def_tristate IP_DCCP
 | 
					 | 
				
			||||||
	select IP_DCCP_ACKVEC
 | 
					 | 
				
			||||||
	---help---
 | 
					 | 
				
			||||||
	  CCID 2, TCP-like Congestion Control, denotes Additive Increase,
 | 
					 | 
				
			||||||
	  Multiplicative Decrease (AIMD) congestion control with behavior
 | 
					 | 
				
			||||||
	  modelled directly on TCP, including congestion window, slow start,
 | 
					 | 
				
			||||||
	  timeouts, and so forth [RFC 2581].  CCID 2 achieves maximum
 | 
					 | 
				
			||||||
	  bandwidth over the long term, consistent with the use of end-to-end
 | 
					 | 
				
			||||||
	  congestion control, but halves its congestion window in response to
 | 
					 | 
				
			||||||
	  each congestion event.  This leads to the abrupt rate changes
 | 
					 | 
				
			||||||
	  typical of TCP.  Applications should use CCID 2 if they prefer
 | 
					 | 
				
			||||||
	  maximum bandwidth utilization to steadiness of rate.  This is often
 | 
					 | 
				
			||||||
	  the case for applications that are not playing their data directly
 | 
					 | 
				
			||||||
	  to the user.  For example, a hypothetical application that
 | 
					 | 
				
			||||||
	  transferred files over DCCP, using application-level retransmissions
 | 
					 | 
				
			||||||
	  for lost packets, would prefer CCID 2 to CCID 3.  On-line games may
 | 
					 | 
				
			||||||
	  also prefer CCID 2.  See RFC 4341 for further details.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	  CCID2 is the default CCID used by DCCP.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
config IP_DCCP_CCID2_DEBUG
 | 
					config IP_DCCP_CCID2_DEBUG
 | 
				
			||||||
	  bool "CCID2 debugging messages"
 | 
						bool "CCID-2 debugging messages"
 | 
				
			||||||
	  depends on IP_DCCP_CCID2
 | 
						---help---
 | 
				
			||||||
	  ---help---
 | 
						  Enable CCID-2 specific debugging messages.
 | 
				
			||||||
	    Enable CCID2-specific debugging messages.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	    When compiling CCID2 as a module, this debugging output can
 | 
						  The debugging output can additionally be toggled by setting the
 | 
				
			||||||
	    additionally be toggled by setting the ccid2_debug module
 | 
						  ccid2_debug parameter to 0 or 1.
 | 
				
			||||||
	    parameter to 0 or 1.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	    If in doubt, say N.
 | 
						  If in doubt, say N.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config IP_DCCP_CCID3
 | 
					config IP_DCCP_CCID3
 | 
				
			||||||
	tristate "CCID3 (TCP-Friendly) (EXPERIMENTAL)"
 | 
						bool "CCID-3 (TCP-Friendly) (EXPERIMENTAL)"
 | 
				
			||||||
	def_tristate IP_DCCP
 | 
						def_bool y if (IP_DCCP = y || IP_DCCP = m)
 | 
				
			||||||
	select IP_DCCP_TFRC_LIB
 | 
						select IP_DCCP_TFRC_LIB
 | 
				
			||||||
	---help---
 | 
						---help---
 | 
				
			||||||
	  CCID 3 denotes TCP-Friendly Rate Control (TFRC), an equation-based
 | 
						  CCID-3 denotes TCP-Friendly Rate Control (TFRC), an equation-based
 | 
				
			||||||
	  rate-controlled congestion control mechanism.  TFRC is designed to
 | 
						  rate-controlled congestion control mechanism.  TFRC is designed to
 | 
				
			||||||
	  be reasonably fair when competing for bandwidth with TCP-like flows,
 | 
						  be reasonably fair when competing for bandwidth with TCP-like flows,
 | 
				
			||||||
	  where a flow is "reasonably fair" if its sending rate is generally
 | 
						  where a flow is "reasonably fair" if its sending rate is generally
 | 
				
			||||||
	  within a factor of two of the sending rate of a TCP flow under the
 | 
						  within a factor of two of the sending rate of a TCP flow under the
 | 
				
			||||||
	  same conditions.  However, TFRC has a much lower variation of
 | 
						  same conditions.  However, TFRC has a much lower variation of
 | 
				
			||||||
	  throughput over time compared with TCP, which makes CCID 3 more
 | 
						  throughput over time compared with TCP, which makes CCID-3 more
 | 
				
			||||||
	  suitable than CCID 2 for applications such streaming media where a
 | 
						  suitable than CCID-2 for applications such streaming media where a
 | 
				
			||||||
	  relatively smooth sending rate is of importance.
 | 
						  relatively smooth sending rate is of importance.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	  CCID 3 is further described in RFC 4342,
 | 
						  CCID-3 is further described in RFC 4342,
 | 
				
			||||||
	  http://www.ietf.org/rfc/rfc4342.txt
 | 
						  http://www.ietf.org/rfc/rfc4342.txt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	  The TFRC congestion control algorithms were initially described in
 | 
						  The TFRC congestion control algorithms were initially described in
 | 
				
			||||||
	  RFC 3448.
 | 
						  RFC 5448.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	  This text was extracted from RFC 4340 (sec. 10.2),
 | 
						  This text was extracted from RFC 4340 (sec. 10.2),
 | 
				
			||||||
	  http://www.ietf.org/rfc/rfc4340.txt
 | 
						  http://www.ietf.org/rfc/rfc4340.txt
 | 
				
			||||||
	  
 | 
					 | 
				
			||||||
	  To compile this CCID as a module, choose M here: the module will be
 | 
					 | 
				
			||||||
	  called dccp_ccid3.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	  If in doubt, say M.
 | 
						  If in doubt, say N.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config IP_DCCP_CCID3_DEBUG
 | 
					config IP_DCCP_CCID3_DEBUG
 | 
				
			||||||
	  bool "CCID3 debugging messages"
 | 
						bool "CCID-3 debugging messages"
 | 
				
			||||||
	  depends on IP_DCCP_CCID3
 | 
						depends on IP_DCCP_CCID3
 | 
				
			||||||
	  ---help---
 | 
						---help---
 | 
				
			||||||
	    Enable CCID3-specific debugging messages.
 | 
						  Enable CCID-3 specific debugging messages.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	    When compiling CCID3 as a module, this debugging output can
 | 
						  The debugging output can additionally be toggled by setting the
 | 
				
			||||||
	    additionally be toggled by setting the ccid3_debug module
 | 
						  ccid3_debug parameter to 0 or 1.
 | 
				
			||||||
	    parameter to 0 or 1.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	    If in doubt, say N.
 | 
						  If in doubt, say N.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config IP_DCCP_CCID3_RTO
 | 
					config IP_DCCP_CCID3_RTO
 | 
				
			||||||
	  int "Use higher bound for nofeedback timer"
 | 
						  int "Use higher bound for nofeedback timer"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,9 +1 @@
 | 
				
			||||||
obj-$(CONFIG_IP_DCCP_CCID3) += dccp_ccid3.o
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
dccp_ccid3-y := ccid3.o
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
obj-$(CONFIG_IP_DCCP_CCID2) += dccp_ccid2.o
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
dccp_ccid2-y := ccid2.o
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
obj-y += lib/
 | 
					obj-y += lib/
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -768,10 +768,9 @@ static void ccid2_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct ccid_operations ccid2 = {
 | 
					struct ccid_operations ccid2_ops = {
 | 
				
			||||||
	.ccid_id		= DCCPC_CCID2,
 | 
						.ccid_id		= DCCPC_CCID2,
 | 
				
			||||||
	.ccid_name		= "TCP-like",
 | 
						.ccid_name		= "TCP-like",
 | 
				
			||||||
	.ccid_owner		= THIS_MODULE,
 | 
					 | 
				
			||||||
	.ccid_hc_tx_obj_size	= sizeof(struct ccid2_hc_tx_sock),
 | 
						.ccid_hc_tx_obj_size	= sizeof(struct ccid2_hc_tx_sock),
 | 
				
			||||||
	.ccid_hc_tx_init	= ccid2_hc_tx_init,
 | 
						.ccid_hc_tx_init	= ccid2_hc_tx_init,
 | 
				
			||||||
	.ccid_hc_tx_exit	= ccid2_hc_tx_exit,
 | 
						.ccid_hc_tx_exit	= ccid2_hc_tx_exit,
 | 
				
			||||||
| 
						 | 
					@ -784,22 +783,5 @@ static struct ccid_operations ccid2 = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_IP_DCCP_CCID2_DEBUG
 | 
					#ifdef CONFIG_IP_DCCP_CCID2_DEBUG
 | 
				
			||||||
module_param(ccid2_debug, bool, 0644);
 | 
					module_param(ccid2_debug, bool, 0644);
 | 
				
			||||||
MODULE_PARM_DESC(ccid2_debug, "Enable debug messages");
 | 
					MODULE_PARM_DESC(ccid2_debug, "Enable CCID-2 debug messages");
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					 | 
				
			||||||
static __init int ccid2_module_init(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return ccid_register(&ccid2);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
module_init(ccid2_module_init);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static __exit void ccid2_module_exit(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	ccid_unregister(&ccid2);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
module_exit(ccid2_module_exit);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
MODULE_AUTHOR("Andrea Bittau <a.bittau@cs.ucl.ac.uk>");
 | 
					 | 
				
			||||||
MODULE_DESCRIPTION("DCCP TCP-Like (CCID2) CCID");
 | 
					 | 
				
			||||||
MODULE_LICENSE("GPL");
 | 
					 | 
				
			||||||
MODULE_ALIAS("net-dccp-ccid-2");
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -940,10 +940,9 @@ static int ccid3_hc_rx_getsockopt(struct sock *sk, const int optname, int len,
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct ccid_operations ccid3 = {
 | 
					struct ccid_operations ccid3_ops = {
 | 
				
			||||||
	.ccid_id		   = DCCPC_CCID3,
 | 
						.ccid_id		   = DCCPC_CCID3,
 | 
				
			||||||
	.ccid_name		   = "TCP-Friendly Rate Control",
 | 
						.ccid_name		   = "TCP-Friendly Rate Control",
 | 
				
			||||||
	.ccid_owner		   = THIS_MODULE,
 | 
					 | 
				
			||||||
	.ccid_hc_tx_obj_size	   = sizeof(struct ccid3_hc_tx_sock),
 | 
						.ccid_hc_tx_obj_size	   = sizeof(struct ccid3_hc_tx_sock),
 | 
				
			||||||
	.ccid_hc_tx_init	   = ccid3_hc_tx_init,
 | 
						.ccid_hc_tx_init	   = ccid3_hc_tx_init,
 | 
				
			||||||
	.ccid_hc_tx_exit	   = ccid3_hc_tx_exit,
 | 
						.ccid_hc_tx_exit	   = ccid3_hc_tx_exit,
 | 
				
			||||||
| 
						 | 
					@ -964,23 +963,5 @@ static struct ccid_operations ccid3 = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_IP_DCCP_CCID3_DEBUG
 | 
					#ifdef CONFIG_IP_DCCP_CCID3_DEBUG
 | 
				
			||||||
module_param(ccid3_debug, bool, 0644);
 | 
					module_param(ccid3_debug, bool, 0644);
 | 
				
			||||||
MODULE_PARM_DESC(ccid3_debug, "Enable debug messages");
 | 
					MODULE_PARM_DESC(ccid3_debug, "Enable CCID-3 debug messages");
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					 | 
				
			||||||
static __init int ccid3_module_init(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return ccid_register(&ccid3);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
module_init(ccid3_module_init);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static __exit void ccid3_module_exit(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	ccid_unregister(&ccid3);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
module_exit(ccid3_module_exit);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
MODULE_AUTHOR("Ian McDonald <ian.mcdonald@jandi.co.nz>, "
 | 
					 | 
				
			||||||
	      "Arnaldo Carvalho de Melo <acme@ghostprotocols.net>");
 | 
					 | 
				
			||||||
MODULE_DESCRIPTION("DCCP TFRC CCID3 CCID");
 | 
					 | 
				
			||||||
MODULE_LICENSE("GPL");
 | 
					 | 
				
			||||||
MODULE_ALIAS("net-dccp-ccid-3");
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -432,10 +432,8 @@ static inline int dccp_ack_pending(const struct sock *sk)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const struct dccp_sock *dp = dccp_sk(sk);
 | 
						const struct dccp_sock *dp = dccp_sk(sk);
 | 
				
			||||||
	return dp->dccps_timestamp_echo != 0 ||
 | 
						return dp->dccps_timestamp_echo != 0 ||
 | 
				
			||||||
#ifdef CONFIG_IP_DCCP_ACKVEC
 | 
					 | 
				
			||||||
	       (dp->dccps_hc_rx_ackvec != NULL &&
 | 
						       (dp->dccps_hc_rx_ackvec != NULL &&
 | 
				
			||||||
		dccp_ackvec_pending(dp->dccps_hc_rx_ackvec)) ||
 | 
							dccp_ackvec_pending(dp->dccps_hc_rx_ackvec)) ||
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
	       inet_csk_ack_scheduled(sk);
 | 
						       inet_csk_ack_scheduled(sk);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1118,9 +1118,15 @@ static int __init dccp_init(void)
 | 
				
			||||||
	if (rc)
 | 
						if (rc)
 | 
				
			||||||
		goto out_ackvec_exit;
 | 
							goto out_ackvec_exit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = ccid_initialize_builtins();
 | 
				
			||||||
 | 
						if (rc)
 | 
				
			||||||
 | 
							goto out_sysctl_exit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dccp_timestamping_init();
 | 
						dccp_timestamping_init();
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	return rc;
 | 
						return rc;
 | 
				
			||||||
 | 
					out_sysctl_exit:
 | 
				
			||||||
 | 
						dccp_sysctl_exit();
 | 
				
			||||||
out_ackvec_exit:
 | 
					out_ackvec_exit:
 | 
				
			||||||
	dccp_ackvec_exit();
 | 
						dccp_ackvec_exit();
 | 
				
			||||||
out_free_dccp_mib:
 | 
					out_free_dccp_mib:
 | 
				
			||||||
| 
						 | 
					@ -1143,6 +1149,7 @@ out_free_percpu:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void __exit dccp_fini(void)
 | 
					static void __exit dccp_fini(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						ccid_cleanup_builtins();
 | 
				
			||||||
	dccp_mib_exit();
 | 
						dccp_mib_exit();
 | 
				
			||||||
	free_pages((unsigned long)dccp_hashinfo.bhash,
 | 
						free_pages((unsigned long)dccp_hashinfo.bhash,
 | 
				
			||||||
		   get_order(dccp_hashinfo.bhash_size *
 | 
							   get_order(dccp_hashinfo.bhash_size *
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue