[PATCH 02/10] nf_conntrack: Introduces a extension infrastructure

Patrick McHardy kaber at trash.net
Mon Jun 25 12:01:02 CEST 2007


Yasuyuki KOZAKAI wrote:
> +static void *
> +nf_ct_ext_create(struct nf_ct_ext **ext, enum nf_ct_ext_id id, int gfp)
> +{
> +	unsigned int off, len, real_len;
> +	struct nf_ct_ext_type *t;
> +
> +	rcu_read_lock();
> +	t = rcu_dereference(nf_ct_ext_types[id]);
> +	BUG_ON(t == NULL);
> +	off = ALIGN(sizeof(struct nf_ct_ext), t->align);
> +	len = off + t->len;
> +	real_len = t->alloc_size;
> +	rcu_read_unlock();
> +
> +	*ext = kmalloc(real_len, gfp);
> +	if (!*ext)
> +		return NULL;
> +
> +	memset(*ext, 0, len);

Minor improvement: you could use kzalloc above

> +
> +	(*ext)->offset[id] = off;
> +	(*ext)->len = len;
> +	(*ext)->real_len = real_len;
> +
> +	return (void *)(*ext) + off;
> +}
> +
> +void *__nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, int gfp)


Does any caller actually use something besides GFP_ATOMIC for gfp?

> +{
> +	struct nf_ct_ext *new;
> +	int i, newlen, newoff;
> +	struct nf_ct_ext_type *t;
> +
> +	if (!ct->ext)
> +		return nf_ct_ext_create(&ct->ext, id, gfp);
> +
> +	if (nf_ct_ext_exist(ct, id))
> +		return NULL;
> +
> +	rcu_read_lock();
> +	t = rcu_dereference(nf_ct_ext_types[id]);
> +	BUG_ON(t == NULL);
> +
> +	newoff = ALIGN(ct->ext->len, t->align);
> +	newlen = newoff + t->len;
> +	rcu_read_unlock();
> +
> +	if (newlen >= ct->ext->real_len) {
> +		new = kmalloc(newlen, gfp);
> +		if (!new)
> +			return NULL;
> +
> +		memcpy(new, ct->ext, ct->ext->len);

And maybe krealloc here?

> +
> +		for (i = 0; i < NF_CT_EXT_MAX; i++) {
> +			if (!nf_ct_ext_exist(ct, i))
> +				continue;
> +
> +			rcu_read_lock();
> +			t = rcu_dereference(nf_ct_ext_types[i]);
> +			if (t && t->move)
> +				t->move(ct, ct->ext + ct->ext->offset[id]);
> +			rcu_read_unlock();
> +		}
> +		kfree(ct->ext);
> +		new->real_len = newlen;
> +		ct->ext = new;
> +	}
> +
> +	ct->ext->offset[id] = newoff;
> +	ct->ext->len = newlen;
> +	memset((void *)ct->ext + newoff, 0, newlen - newoff);
> +	return (void *)ct->ext + newoff;
> +}
> +EXPORT_SYMBOL(__nf_ct_ext_add);
> +
> +static void update_alloc_size(enum nf_ct_ext_id id)
> +{
> +	int i, j;
> +	struct nf_ct_ext_type *t1, *t2;
> +	enum nf_ct_ext_id min = 0, max = NF_CT_EXT_MAX - 1;
> +
> +	/* unnecessary to update all types */
> +	if ((nf_ct_ext_types[id]->flags & NF_CT_EXT_F_PREALLOC) == 0) {
> +		min = id;
> +		max = id;
> +	}
> +
> +	/* This assumes that extended areas in conntrack for the types
> +  	   whose NF_CT_EXT_F_PREALLOC bit set are allocated in order */
> +	for (i = min; i <= max; i++) {
> +		t1 = nf_ct_ext_types[i];
> +		if (!t1)
> +			continue;
> +
> +		t1->alloc_size = sizeof(struct nf_ct_ext)
> +				 + ALIGN(sizeof(struct nf_ct_ext), t1->align)
> +				 + t1->len;
> +		for (j = 0; j < NF_CT_EXT_MAX; j++) {
> +			t2 = nf_ct_ext_types[j];
> +			if (t2 == NULL || t2 == t1 ||
> +			    (t2->flags & NF_CT_EXT_F_PREALLOC) == 0)
> +				continue;
> +
> +			t1->alloc_size = ALIGN(t1->alloc_size, t2->align)
> +					 + t2->len;
> +		}
> +		if (t1->alloc_size < NF_CT_EXT_MIN_SIZE)
> +			t1->alloc_size = NF_CT_EXT_MIN_SIZE;
> +	}
> +}
> +
> +/* This MUST be called in process context. */
> +int nf_ct_extend_register(struct nf_ct_ext_type *type)
> +{
> +	int ret = 0;
> +
> +	mutex_lock(&nf_ct_ext_type_mutex);
> +	if (nf_ct_ext_types[type->id]) {
> +		ret = -EBUSY;
> +		goto out;
> +	}
> +
> +	/* This ensures that nf_ct_ext_create() can allocate enough area
> +	   before updating alloc_size */
> +	type->alloc_size = ALIGN(sizeof(struct nf_ct_ext), type->align)
> +			   + type->len;
> +	rcu_assign_pointer(nf_ct_ext_types[type->id], type);
> +	update_alloc_size(type->id);
> +out:
> +	mutex_unlock(&nf_ct_ext_type_mutex);
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(nf_ct_extend_register);
> +
> +/* This MUST be called in process context. */
> +void nf_ct_extend_unregister(struct nf_ct_ext_type *type)
> +{
> +	mutex_lock(&nf_ct_ext_type_mutex);
> +	rcu_assign_pointer(nf_ct_ext_types[type->id], NULL);


This seems to need synchronize_rcu().

> +	update_alloc_size(type->id);
> +	mutex_unlock(&nf_ct_ext_type_mutex);
> +}
> +EXPORT_SYMBOL_GPL(nf_ct_extend_unregister);




More information about the netfilter-devel mailing list