Next step in consolidating the IP fragment management
Subsystems (4)
cover Next step in consolidating the IP fragment management
This set concerns the xxx_find() routine only. This one is used to obtain the fragment queue depending on some criteria, and this can be consolidated.
The consolidation goes step-by-step, consolidating one sub-routine at a time, so some functions, exports and callbacks that are introduced in patches are temporary and are removed in some subsequent patch.
PATCH 1/7 Omit double hash calculations in xxx_frag_intern
Since the hash value is already calculated in xxx_find, we can simply use it later. This is already done in netfilter code, so make the same in ipv4 and ipv6.
---
Quoted 1 line
From
5bcb464538cf504a9f6cf3be33dbd1a5ff18b693Mon Sep 17 00:00:00 2001
From: Pavel <[email protected]>
Date: Tue, 16 Oct 2007 14:40:30 +0400
Subject: [PATCH 1/7] Pass the hash value as an extra argument
--- net/ipv4/ip_fragment.c | 11 ++++------- net/ipv6/reassembly.c | 11 +++++------ 2 files changed, 9 insertions(+), 13 deletions(-)
net/ipv4/ip_fragment.c +4 -7
@@ -212,17 +212,14 @@ out:/* Creation primitives. */ -static struct ipq *ip_frag_intern (struct ipq *qp_in) +static struct ipq *ip_frag_intern (struct ipq *qp_in,unsigned int hash) {struct ipq *qp;#ifdef CONFIG_SMP struct hlist_node *n;#endif -unsigned int hash;write_lock (&ip4_frags.lock); - hash =ipqhashfn (qp_in->id, qp_in->saddr, qp_in->daddr, - qp_in->protocol);#ifdef CONFIG_SMP /* With SMP race we have to recheck hash table, because * such entry could be created on other cpu, while we
@@ -257,7 +254,7 @@ static struct ipq *ip_frag_intern(struct ipq *qp_in) }/* Add an entry to the 'ipq' queue for a newly received IP datagram. */ -static struct ipq *ip_frag_create (struct iphdr *iph,u32 user) +static struct ipq *ip_frag_create (struct iphdr *iph,u32 user,unsigned int h) {struct ipq *qp;
@@ -278,7 +275,7 @@ static struct ipq *ip_frag_create(struct iphdr *iph, u32 user)spin_lock_init (&qp->q.lock);atomic_set (&qp->q.refcnt,1 ); -return ip_frag_intern (qp); +return ip_frag_intern (qp, h); out_nomem:LIMIT_NETDEBUG (KERN_ERR "ip_frag_create: no memory left !\n" );
@@ -313,7 +310,7 @@ static inline struct ipq *ip_find(struct iphdr *iph, u32 user) }read_unlock (&ip4_frags.lock); -return ip_frag_create (iph, user); +return ip_frag_create (iph, user, hash); }/* Is the fragment too far ahead to be part of ipq? */
net/ipv6/reassembly.c +5 -6
@@ -233,16 +233,15 @@ out:/* Creation primitives. */ -static struct frag_queue *ip6_frag_intern(struct frag_queue *fq_in) +static struct frag_queue *ip6_frag_intern(struct frag_queue *fq_in, + unsigned int hash) { struct frag_queue *fq; - unsigned int hash; #ifdef CONFIG_SMP struct hlist_node *n; #endif write_lock(&ip6_frags.lock); - hash = ip6qhashfn(fq_in->id, &fq_in->saddr, &fq_in->daddr); #ifdef CONFIG_SMP hlist_for_each_entry(fq, n, &ip6_frags.hash[hash], q.list) { if (fq->id == fq_in->id &&
@@ -273,7 +272,7 @@ static struct frag_queue *ip6_frag_intern(struct frag_queue *fq_in)static struct frag_queue *ip6_frag_create (__be32 id,struct in6_addr *src,struct in6_addr *dst, -struct inet6_dev *idev) +struct inet6_dev *idev,unsigned int hash) {struct frag_queue *fq;
@@ -290,7 +289,7 @@ ip6_frag_create(__be32 id, struct in6_addr *src, struct in6_addr *dst,spin_lock_init (&fq->q.lock);atomic_set (&fq->q.refcnt,1 ); -return ip6_frag_intern (fq); +return ip6_frag_intern (fq, hash); oom:IP6_INC_STATS_BH (idev,IPSTATS_MIB_REASMFAILS );
@@ -318,7 +317,7 @@ fq_find(__be32 id, struct in6_addr *src, struct in6_addr *dst, }read_unlock (&ip6_frags.lock); -return ip6_frag_create (id, src, dst, idev); +return ip6_frag_create (id, src, dst, idev, hash); }
Signature · 1 line
1.5.3.4
PATCH 2/7 Consolidate xxx_frag_intern
In reply to Pavel EmelyanovThis routine checks for the existence of a given entry in the hash table and inserts the new one if needed.
The ->equal callback is used to compare two frag_queue-s together, but this one is temporary and will be removed later. The netfilter code and the ipv6 one use the same routine to compare frags.
The inet_frag_intern() always returns non-NULL pointer, so convert the inet_frag_queue into protocol specific one (with the container_of) without any checks.
---
include/net/inet_frag.h +4 -0
@@ -41,6 +41,8 @@ struct inet_frags {unsigned int (*hashfn)(struct inet_frag_queue *);void (*destructor)(struct inet_frag_queue *);void (*skb_free)(struct sk_buff *); +int (*equal)(struct inet_frag_queue *q1, +struct inet_frag_queue *q2); };void inet_frags_init (struct inet_frags *);
@@ -50,6 +52,8 @@ void inet_frag_kill(struct inet_frag_queue *q, struct inet_frags *f);void inet_frag_destroy (struct inet_frag_queue *q,struct inet_frags *f,int *work);int inet_frag_evictor (struct inet_frags *f); +struct inet_frag_queue *inet_frag_intern (struct inet_frag_queue *q, +struct inet_frags *f,unsigned int hash);static inline void inet_frag_put (struct inet_frag_queue *q,struct inet_frags *f) {
include/net/ipv6.h +3 -0
@@ -377,6 +377,9 @@ static inline int ipv6_prefix_equal(const struct in6_addr *a1, prefixlen); } +struct inet_frag_queue ; +int ip6_frag_equal (struct inet_frag_queue *q1,struct inet_frag_queue *q2); +static inline int ipv6_addr_any (const struct in6_addr *a) { return ((a->s6_addr32[0] | a->s6_addr32[1] |
net/ipv4/inet_fragment.c +37 -0
@@ -172,3 +172,40 @@ int inet_frag_evictor(struct inet_frags *f)return evicted; }EXPORT_SYMBOL (inet_frag_evictor); + +struct inet_frag_queue *inet_frag_intern (struct inet_frag_queue *qp_in, +struct inet_frags *f,unsigned int hash) +{ +struct inet_frag_queue *qp; +#ifdef CONFIG_SMP +struct hlist_node *n; +#endif + +write_lock (&f->lock); +#ifdef CONFIG_SMP +/* With SMP race we have to recheck hash table, because +* such entry could be created on other cpu, while we +* promoted read lock to write lock. +*/ +hlist_for_each_entry (qp, n, &f->hash[hash], list) { +if (f->equal (qp, qp_in)) { +atomic_inc (&qp->refcnt); +write_unlock (&f->lock); + qp_in->last_in |=COMPLETE ; +inet_frag_put (qp_in, f); +return qp; + } + } +#endif + qp = qp_in; +if (!mod_timer (&qp->timer, jiffies + f->ctl->timeout)) +atomic_inc (&qp->refcnt); + +atomic_inc (&qp->refcnt); +hlist_add_head (&qp->list, &f->hash[hash]); +list_add_tail (&qp->lru_list, &f->lru_list); + f->nqueues++; +write_unlock (&f->lock); +return qp; +} +EXPORT_SYMBOL (inet_frag_intern);
net/ipv4/ip_fragment.c +18 -36
73 lines not on this page · raw message
net/ipv6/netfilter/nf_conntrack_reasm.c +4 -30
@@ -187,37 +187,10 @@ out:static struct nf_ct_frag6_queue *nf_ct_frag6_intern (unsigned int hash,struct nf_ct_frag6_queue *fq_in) { -struct nf_ct_frag6_queue *fq; -#ifdef CONFIG_SMP -struct hlist_node *n; -#endif - -write_lock (&nf_frags.lock); -#ifdef CONFIG_SMP -hlist_for_each_entry (fq, n, &nf_frags.hash[hash], q.list) { -if (fq->id == fq_in->id && -ipv6_addr_equal (&fq_in->saddr, &fq->saddr) && -ipv6_addr_equal (&fq_in->daddr, &fq->daddr)) { -atomic_inc (&fq->q.refcnt); -write_unlock (&nf_frags.lock); - fq_in->q.last_in |=COMPLETE ; -fq_put (fq_in); -return fq; - } - } -#endif - fq = fq_in; +struct inet_frag_queue *q; -if (!mod_timer (&fq->q.timer, jiffies + nf_frags_ctl.timeout)) -atomic_inc (&fq->q.refcnt); - -atomic_inc (&fq->q.refcnt); -hlist_add_head (&fq->q.list, &nf_frags.hash[hash]); -INIT_LIST_HEAD (&fq->q.lru_list); -list_add_tail (&fq->q.lru_list, &nf_frags.lru_list); - nf_frags.nqueues++; -write_unlock (&nf_frags.lock); -return fq; + q =inet_frag_intern (&fq_in->q, &nf_frags, hash); + return container_of(q, struct nf_ct_frag6_queue, q); }
@@ -752,6 +725,7 @@ int nf_ct_frag6_init(void) nf_frags.destructor = nf_frag_free; nf_frags.skb_free = nf_skb_free; nf_frags.qsize =sizeof (struct nf_ct_frag6_queue ); + nf_frags.equal = ip6_frag_equal;inet_frags_init (&nf_frags);return 0 ;
net/ipv6/reassembly.c +16 -30
64 lines not on this page · raw message
Signature · 1 line
1.5.3.4
PATCH 3/7 Consolidate xxx_frag_alloc()
In reply to Pavel EmelyanovJust perform the kzalloc() allocation and setup common fields in the inet_frag_queue(). Then return the result to the caller to initialize the rest.
The inet_frag_alloc() may return NULL, so check the return value before doing the container_of(). This looks ugly, but the xxx_frag_alloc() will be removed soon.
The xxx_expire() timer callbacks are patches, because the argument is now the inet_frag_queue, not the protocol specific queue.
---
include/net/inet_frag.h +2 -0
@@ -43,6 +43,7 @@ struct inet_frags {void (*skb_free)(struct sk_buff *);int (*equal)(struct inet_frag_queue *q1,struct inet_frag_queue *q2); +void (*frag_expire)(unsigned long data); };void inet_frags_init (struct inet_frags *);
@@ -54,6 +55,7 @@ void inet_frag_destroy(struct inet_frag_queue *q,int inet_frag_evictor (struct inet_frags *f);struct inet_frag_queue *inet_frag_intern (struct inet_frag_queue *q,struct inet_frags *f,unsigned int hash); +struct inet_frag_queue *inet_frag_alloc (struct inet_frags *f);static inline void inet_frag_put (struct inet_frag_queue *q,struct inet_frags *f) {
net/ipv4/inet_fragment.c +17 -0
@@ -209,3 +209,20 @@ struct inet_frag_queue *inet_frag_intern(struct inet_frag_queue *qp_in,return qp; }EXPORT_SYMBOL (inet_frag_intern); + +struct inet_frag_queue *inet_frag_alloc (struct inet_frags *f) +{ +struct inet_frag_queue *q; + + q =kzalloc (f->qsize,GFP_ATOMIC ); +if (q ==NULL ) +return NULL ; + +atomic_add (f->qsize, &f->mem); +setup_timer (&q->timer, f->frag_expire, (unsigned long )q); +spin_lock_init (&q->lock); +atomic_set (&q->refcnt,1 ); + +return q; +} +EXPORT_SYMBOL (inet_frag_alloc);
net/ipv4/ip_fragment.c +7 -13
@@ -158,12 +158,10 @@ static __inline__ void ip4_frag_free(struct inet_frag_queue *q)static __inline__struct ipq *frag_alloc_queue (void ) { -struct ipq *qp =kzalloc (sizeof (struct ipq ),GFP_ATOMIC ); +struct inet_frag_queue *q; -if (!qp) -return NULL ; -atomic_add (sizeof (struct ipq ), &ip4_frags.mem); -return qp; + q =inet_frag_alloc (&ip4_frags); + return q ? container_of(q, struct ipq, q) : NULL; }
@@ -199,7 +197,9 @@ static void ip_evictor(void)*/ static void ip_expire (unsigned long arg) { -struct ipq *qp = (struct ipq *) arg; +struct ipq *qp; + + qp = container_of((struct inet_frag_queue *) arg, struct ipq, q);spin_lock (&qp->q.lock);
@@ -249,13 +249,6 @@ static struct ipq *ip_frag_create(struct iphdr *iph, u32 user, unsigned int h) qp->user = user; qp->peer = sysctl_ipfrag_max_dist ?inet_getpeer (iph->saddr,1 ) :NULL ; -/* Initialize a timer for this entry. */ -init_timer (&qp->q.timer); - qp->q.timer.data = (unsigned long ) qp;/* pointer to queue */ - qp->q.timer.function = ip_expire;/* expire function */ -spin_lock_init (&qp->q.lock); -atomic_set (&qp->q.refcnt,1 ); -return ip_frag_intern (qp, h); out_nomem:
@@ -653,6 +646,7 @@ void __init ipfrag_init(void) ip4_frags.skb_free =NULL ; ip4_frags.qsize =sizeof (struct ipq ); ip4_frags.equal = ip4_frag_equal; + ip4_frags.frag_expire = ip_expire;inet_frags_init (&ip4_frags); }
net/ipv6/netfilter/nf_conntrack_reasm.c +8 -11
@@ -137,13 +137,10 @@ static void nf_frag_free(struct inet_frag_queue *q)static inline struct nf_ct_frag6_queue *frag_alloc_queue (void ) { -struct nf_ct_frag6_queue *fq; +struct inet_frag_queue *q; - fq =kzalloc (sizeof (struct nf_ct_frag6_queue ),GFP_ATOMIC ); -if (fq ==NULL ) -return NULL ; -atomic_add (sizeof (struct nf_ct_frag6_queue ), &nf_frags.mem); -return fq; + q =inet_frag_alloc (&nf_frags); + return q ? container_of(q, struct nf_ct_frag6_queue, q) : NULL; }/* Destruction primitives. */
@@ -168,7 +165,10 @@ static void nf_ct_frag6_evictor(void)static void nf_ct_frag6_expire (unsigned long data) { -struct nf_ct_frag6_queue *fq = (struct nf_ct_frag6_queue *) data; +struct nf_ct_frag6_queue *fq; + + fq =container_of ((struct inet_frag_queue *)data, + struct nf_ct_frag6_queue, q);spin_lock (&fq->q.lock);
@@ -208,10 +208,6 @@ nf_ct_frag6_create(unsigned int hash, __be32 id, struct in6_addr *src, stripv6_addr_copy (&fq->saddr, src);ipv6_addr_copy (&fq->daddr, dst); -setup_timer (&fq->q.timer, nf_ct_frag6_expire, (unsigned long )fq); -spin_lock_init (&fq->q.lock); -atomic_set (&fq->q.refcnt,1 ); -return nf_ct_frag6_intern (hash, fq); oom:
@@ -726,6 +722,7 @@ int nf_ct_frag6_init(void) nf_frags.skb_free = nf_skb_free; nf_frags.qsize =sizeof (struct nf_ct_frag6_queue ); nf_frags.equal = ip6_frag_equal; + nf_frags.frag_expire = nf_ct_frag6_expire;inet_frags_init (&nf_frags);return 0 ;
net/ipv6/reassembly.c +7 -12
@@ -171,12 +171,10 @@ static void ip6_frag_free(struct inet_frag_queue *fq)static inline struct frag_queue *frag_alloc_queue (void ) { -struct frag_queue *fq =kzalloc (sizeof (struct frag_queue ),GFP_ATOMIC ); +struct inet_frag_queue *q; -if (!fq) -return NULL ; -atomic_add (sizeof (struct frag_queue ), &ip6_frags.mem); -return fq; + q =inet_frag_alloc (&ip6_frags); + return q ? container_of(q, struct frag_queue, q) : NULL; }/* Destruction primitives. */
@@ -205,9 +203,11 @@ static void ip6_evictor(struct inet6_dev *idev)static void ip6_frag_expire (unsigned long data) { -struct frag_queue *fq = (struct frag_queue *) data; +struct frag_queue *fq;struct net_device *dev =NULL ; + fq = container_of((struct inet_frag_queue *)data, struct frag_queue, q); +spin_lock (&fq->q.lock);if (fq->q.last_in &COMPLETE )
@@ -268,12 +268,6 @@ ip6_frag_create(__be32 id, struct in6_addr *src, struct in6_addr *dst,ipv6_addr_copy (&fq->saddr, src);ipv6_addr_copy (&fq->daddr, dst); -init_timer (&fq->q.timer); - fq->q.timer.function = ip6_frag_expire; - fq->q.timer.data = (long ) fq; -spin_lock_init (&fq->q.lock); -atomic_set (&fq->q.refcnt,1 ); -return ip6_frag_intern (fq, hash); oom:
@@ -685,5 +679,6 @@ void __init ipv6_frag_init(void) ip6_frags.skb_free =NULL ; ip6_frags.qsize =sizeof (struct frag_queue ); ip6_frags.equal = ip6_frag_equal; + ip6_frags.frag_expire = ip6_frag_expire;inet_frags_init (&ip6_frags); }
Signature · 1 line
1.5.3.4
PATCH 4/7 Consolidate xxx_frag_create()
In reply to Pavel EmelyanovThis one uses the xxx_frag_intern() and xxx_frag_alloc() routines, which are already consolidated, so remove them from protocol code (as promised).
The ->constructor callback is used to init the rest of the frag queue and it is the same for netfilter and ipv6.
---
include/net/inet_frag.h +4 -3
@@ -39,6 +39,8 @@ struct inet_frags {struct inet_frags_ctl *ctl;unsigned int (*hashfn)(struct inet_frag_queue *); +void (*constructor)(struct inet_frag_queue *q, +void *arg);void (*destructor)(struct inet_frag_queue *);void (*skb_free)(struct sk_buff *); int (*equal)(struct inet_frag_queue *q1,
@@ -53,9 +55,8 @@ void inet_frag_kill(struct inet_frag_queue *q, struct inet_frags *f);void inet_frag_destroy (struct inet_frag_queue *q,struct inet_frags *f,int *work);int inet_frag_evictor (struct inet_frags *f); -struct inet_frag_queue *inet_frag_intern (struct inet_frag_queue *q, -struct inet_frags *f,unsigned int hash); -struct inet_frag_queue *inet_frag_alloc (struct inet_frags *f); +struct inet_frag_queue *inet_frag_create (struct inet_frags *f, +void *create_arg,unsigned int hash);static inline void inet_frag_put (struct inet_frag_queue *q,struct inet_frags *f) {
include/net/ipv6.h +8 -0
@@ -380,6 +380,14 @@ static inline int ipv6_prefix_equal(const struct in6_addr *a1,struct inet_frag_queue ;int ip6_frag_equal (struct inet_frag_queue *q1,struct inet_frag_queue *q2); +struct ip6_create_arg { +__be32 id; +struct in6_addr *src; +struct in6_addr *dst; +}; + +void ip6_frag_init (struct inet_frag_queue *q,void *a); +static inline int ipv6_addr_any (const struct in6_addr *a) { return ((a->s6_addr32[0] | a->s6_addr32[1] |
net/ipv4/inet_fragment.c +16 -4
@@ -173,7 +173,7 @@ int inet_frag_evictor(struct inet_frags *f) }EXPORT_SYMBOL (inet_frag_evictor); -struct inet_frag_queue *inet_frag_intern (struct inet_frag_queue *qp_in, +static struct inet_frag_queue *inet_frag_intern (struct inet_frag_queue *qp_in,struct inet_frags *f,unsigned int hash) {struct inet_frag_queue *qp;
@@ -208,9 +208,8 @@ struct inet_frag_queue *inet_frag_intern(struct inet_frag_queue *qp_in,write_unlock (&f->lock);return qp; } -EXPORT_SYMBOL (inet_frag_intern); -struct inet_frag_queue *inet_frag_alloc (struct inet_frags *f) +static struct inet_frag_queue *inet_frag_alloc (struct inet_frags *f,void *arg) {struct inet_frag_queue *q;
@@ -218,6 +217,7 @@ struct inet_frag_queue *inet_frag_alloc(struct inet_frags *f)if (q ==NULL )return NULL ; + f->constructor (q, arg);atomic_add (f->qsize, &f->mem);setup_timer (&q->timer, f->frag_expire, (unsigned long )q);spin_lock_init (&q->lock);
@@ -225,4 +225,16 @@ struct inet_frag_queue *inet_frag_alloc(struct inet_frags *f)return q; } -EXPORT_SYMBOL (inet_frag_alloc); + +struct inet_frag_queue *inet_frag_create (struct inet_frags *f,void *arg, +unsigned int hash) +{ +struct inet_frag_queue *q; + + q =inet_frag_alloc (f, arg); +if (q ==NULL ) +return NULL ; + +return inet_frag_intern (q, f, hash); +} +EXPORT_SYMBOL (inet_frag_create);
net/ipv4/ip_fragment.c +28 -26
90 lines not on this page · raw message
net/ipv6/netfilter/nf_conntrack_reasm.c +12 -27
@@ -135,14 +135,6 @@ static void nf_frag_free(struct inet_frag_queue *q)kfree (container_of(q ,struct nf_ct_frag6_queue ,q )); } -static inline struct nf_ct_frag6_queue *frag_alloc_queue (void ) -{ -struct inet_frag_queue *q; - - q =inet_frag_alloc (&nf_frags); - return q ? container_of(q, struct nf_ct_frag6_queue, q) : NULL; -} -/* Destruction primitives. */ static __inline__void fq_put (struct nf_ct_frag6_queue *fq)
@@ -184,33 +176,25 @@ out:/* Creation primitives. */ -static struct nf_ct_frag6_queue *nf_ct_frag6_intern (unsigned int hash, -struct nf_ct_frag6_queue *fq_in) +static struct nf_ct_frag6_queue * +nf_ct_frag6_create (unsigned int hash,__be32 id,struct in6_addr *src, +struct in6_addr *dst) {struct inet_frag_queue *q; +struct ip6_create_arg arg; - q =inet_frag_intern (&fq_in->q, &nf_frags, hash); - return container_of(q, struct nf_ct_frag6_queue, q); -} - - -static struct nf_ct_frag6_queue * -nf_ct_frag6_create (unsigned int hash,__be32 id,struct in6_addr *src,struct in6_addr *dst) -{ -struct nf_ct_frag6_queue *fq; + arg.id = id; + arg.src = src; + arg.dst = dst; -if ((fq =frag_alloc_queue ()) ==NULL ) { -pr_debug ("Can't alloc new queue\n" ); + q =inet_frag_create (&nf_frags, &arg, hash); +if (q ==NULL ) goto oom; - } - fq->id = id; -ipv6_addr_copy (&fq->saddr, src); -ipv6_addr_copy (&fq->daddr, dst); - -return nf_ct_frag6_intern (hash, fq); + return container_of(q, struct nf_ct_frag6_queue, q); oom: +pr_debug ("Can't alloc new queue\n" );return NULL ; }
@@ -718,6 +702,7 @@ int nf_ct_frag6_init(void) { nf_frags.ctl = &nf_frags_ctl; nf_frags.hashfn = nf_hashfn; + nf_frags.constructor = ip6_frag_init; nf_frags.destructor = nf_frag_free; nf_frags.skb_free = nf_skb_free; nf_frags.qsize =sizeof (struct nf_ct_frag6_queue );
net/ipv6/reassembly.c +20 -25
74 lines not on this page · raw message
Signature · 1 line
1.5.3.4
PATCH 5/7 Consolidate xxx_find() in fragment management
In reply to Pavel EmelyanovHere we need another callback ->match to check whether the entry found in hash matches the key passed. The key used is the same as the creation argument for inet_frag_create.
Yet again, this ->match is the same for netfilter and ipv6. Running a frew steps forward - this callback will later replace the ->equal one.
Since the inet_frag_find() uses the already consolidated inet_frag_create() remove the xxx_frag_create from protocol codes.
---
include/net/inet_frag.h +4 -2
@@ -45,6 +45,8 @@ struct inet_frags {void (*skb_free)(struct sk_buff *);int (*equal)(struct inet_frag_queue *q1,struct inet_frag_queue *q2); +int (*match)(struct inet_frag_queue *q, +void *arg);void (*frag_expire)(unsigned long data); };
@@ -55,8 +57,8 @@ void inet_frag_kill(struct inet_frag_queue *q, struct inet_frags *f);void inet_frag_destroy (struct inet_frag_queue *q,struct inet_frags *f,int *work);int inet_frag_evictor (struct inet_frags *f); -struct inet_frag_queue *inet_frag_create (struct inet_frags *f, -void *create_arg,unsigned int hash); +struct inet_frag_queue *inet_frag_find (struct inet_frags *f,void *key, +unsigned int hash);static inline void inet_frag_put (struct inet_frag_queue *q,struct inet_frags *f) {
include/net/ipv6.h +1 -0
@@ -387,6 +387,7 @@ struct ip6_create_arg { };void ip6_frag_init (struct inet_frag_queue *q,void *a); +int ip6_frag_match (struct inet_frag_queue *q,void *a);static inline int ipv6_addr_any (const struct in6_addr *a) {
net/ipv4/inet_fragment.c +22 -3
@@ -226,8 +226,8 @@ static struct inet_frag_queue *inet_frag_alloc(struct inet_frags *f, void *arg)return q; } -struct inet_frag_queue *inet_frag_create (struct inet_frags *f,void *arg, -unsigned int hash) +static struct inet_frag_queue *inet_frag_create (struct inet_frags *f, +void *arg,unsigned int hash) {struct inet_frag_queue *q;
@@ -237,4 +237,23 @@ struct inet_frag_queue *inet_frag_create(struct inet_frags *f, void *arg,return inet_frag_intern (q, f, hash); } -EXPORT_SYMBOL (inet_frag_create); + +struct inet_frag_queue *inet_frag_find (struct inet_frags *f,void *key, +unsigned int hash) +{ +struct inet_frag_queue *q; +struct hlist_node *n; + +read_lock (&f->lock); +hlist_for_each_entry (q, n, &f->hash[hash], list) { +if (f->match (q, key)) { +atomic_inc (&q->refcnt); +read_unlock (&f->lock); +return q; + } + } +read_unlock (&f->lock); + +return inet_frag_create (f, key, hash); +} +EXPORT_SYMBOL (inet_frag_find);
net/ipv4/ip_fragment.c +21 -36
88 lines not on this page · raw message
net/ipv6/netfilter/nf_conntrack_reasm.c +6 -26
@@ -176,18 +176,19 @@ out:/* Creation primitives. */ -static struct nf_ct_frag6_queue * -nf_ct_frag6_create (unsigned int hash,__be32 id,struct in6_addr *src, -struct in6_addr *dst) +static __inline__struct nf_ct_frag6_queue * +fq_find (__be32 id,struct in6_addr *src,struct in6_addr *dst) {struct inet_frag_queue *q;struct ip6_create_arg arg; +unsigned int hash; arg.id = id; arg.src = src; arg.dst = dst; + hash =ip6qhashfn (id, src, dst); - q =inet_frag_create (&nf_frags, &arg, hash); + q =inet_frag_find (&nf_frags, &arg, hash);if (q ==NULL ) goto oom;
@@ -198,28 +199,6 @@ oom:return NULL ; } -static __inline__struct nf_ct_frag6_queue * -fq_find (__be32 id,struct in6_addr *src,struct in6_addr *dst) -{ -struct nf_ct_frag6_queue *fq; -struct hlist_node *n; -unsigned int hash =ip6qhashfn (id, src, dst); - -read_lock (&nf_frags.lock); -hlist_for_each_entry (fq, n, &nf_frags.hash[hash], q.list) { -if (fq->id == id && -ipv6_addr_equal (src, &fq->saddr) && -ipv6_addr_equal (dst, &fq->daddr)) { -atomic_inc (&fq->q.refcnt); -read_unlock (&nf_frags.lock); -return fq; - } - } -read_unlock (&nf_frags.lock); - -return nf_ct_frag6_create (hash, id, src, dst); -} -static int nf_ct_frag6_queue (struct nf_ct_frag6_queue *fq,struct sk_buff *skb,struct frag_hdr *fhdr,int nhoff)
@@ -706,6 +685,7 @@ int nf_ct_frag6_init(void) nf_frags.destructor = nf_frag_free; nf_frags.skb_free = nf_skb_free; nf_frags.qsize =sizeof (struct nf_ct_frag6_queue ); + nf_frags.match = ip6_frag_match; nf_frags.equal = ip6_frag_equal; nf_frags.frag_expire = nf_ct_frag6_expire;inet_frags_init (&nf_frags);
net/ipv6/reassembly.c +19 -31
82 lines not on this page · raw message
Signature · 1 line
1.5.3.4
PATCH 6/7 Remove no longer needed ->equal callback
In reply to Pavel EmelyanovSince this callback is used to check for conflicts in hashtable when inserting a newly created frag queue, we can do the same by checking for matching the queue with the argument, used to create one.
---
include/net/inet_frag.h +0 -2
@@ -43,8 +43,6 @@ struct inet_frags { void *arg);void (*destructor)(struct inet_frag_queue *);void (*skb_free)(struct sk_buff *); -int (*equal)(struct inet_frag_queue *q1, -struct inet_frag_queue *q2);int (*match)(struct inet_frag_queue *q,void *arg);void (*frag_expire)(unsigned long data);
include/net/ipv6.h +0 -1
@@ -378,7 +378,6 @@ static inline int ipv6_prefix_equal(const struct in6_addr *a1, }struct inet_frag_queue ; -int ip6_frag_equal (struct inet_frag_queue *q1,struct inet_frag_queue *q2);struct ip6_create_arg {__be32 id;
net/ipv4/inet_fragment.c +3 -3
@@ -174,7 +174,7 @@ int inet_frag_evictor(struct inet_frags *f)EXPORT_SYMBOL (inet_frag_evictor);static struct inet_frag_queue *inet_frag_intern (struct inet_frag_queue *qp_in, -struct inet_frags *f,unsigned int hash) +struct inet_frags *f,unsigned int hash,void *arg) {struct inet_frag_queue *qp;#ifdef CONFIG_SMP
@@ -188,7 +188,7 @@ static struct inet_frag_queue *inet_frag_intern(struct inet_frag_queue *qp_in,* promoted read lock to write lock. */ hlist_for_each_entry (qp, n, &f->hash[hash], list) { -if (f->equal (qp, qp_in)) { +if (f->match (qp, arg)) {atomic_inc (&qp->refcnt);write_unlock (&f->lock); qp_in->last_in |=COMPLETE ;
@@ -235,7 +235,7 @@ static struct inet_frag_queue *inet_frag_create(struct inet_frags *f,if (q ==NULL )return NULL ; -return inet_frag_intern (q, f, hash); +return inet_frag_intern (q, f, hash, arg); } struct inet_frag_queue *inet_frag_find(struct inet_frags *f, void *key,
net/ipv4/ip_fragment.c +0 -15
@@ -128,20 +128,6 @@ static unsigned int ip4_hashfn(struct inet_frag_queue *q)return ipqhashfn (ipq->id, ipq->saddr, ipq->daddr, ipq->protocol); } -static int ip4_frag_equal (struct inet_frag_queue *q1, -struct inet_frag_queue *q2) -{ -struct ipq *qp1, *qp2; - - qp1 = container_of(q1, struct ipq, q); - qp2 = container_of(q2, struct ipq, q); -return (qp1->id == qp2->id && - qp1->saddr == qp2->saddr && - qp1->daddr == qp2->daddr && - qp1->protocol == qp2->protocol && - qp1->user == qp2->user); -} -static int ip4_frag_match (struct inet_frag_queue *q,void *a) {struct ipq *qp;
@@ -631,7 +617,6 @@ void __init ipfrag_init(void) ip4_frags.destructor = ip4_frag_free; ip4_frags.skb_free =NULL ; ip4_frags.qsize =sizeof (struct ipq ); - ip4_frags.equal = ip4_frag_equal; ip4_frags.match = ip4_frag_match; ip4_frags.frag_expire = ip_expire;inet_frags_init (&ip4_frags);
net/ipv6/netfilter/nf_conntrack_reasm.c +0 -1
@@ -686,7 +686,6 @@ int nf_ct_frag6_init(void) nf_frags.skb_free = nf_skb_free; nf_frags.qsize =sizeof (struct nf_ct_frag6_queue ); nf_frags.match = ip6_frag_match; - nf_frags.equal = ip6_frag_equal; nf_frags.frag_expire = nf_ct_frag6_expire;inet_frags_init (&nf_frags);
net/ipv6/reassembly.c +0 -13
@@ -143,18 +143,6 @@ static unsigned int ip6_hashfn(struct inet_frag_queue *q)return ip6qhashfn (fq->id, &fq->saddr, &fq->daddr); } -int ip6_frag_equal (struct inet_frag_queue *q1,struct inet_frag_queue *q2) -{ -struct frag_queue *fq1, *fq2; - - fq1 = container_of(q1, struct frag_queue, q); - fq2 = container_of(q2, struct frag_queue, q); -return (fq1->id == fq2->id && -ipv6_addr_equal (&fq2->saddr, &fq1->saddr) && -ipv6_addr_equal (&fq2->daddr, &fq1->daddr)); -} -EXPORT_SYMBOL (ip6_frag_equal); -int ip6_frag_match (struct inet_frag_queue *q,void *a) {struct frag_queue *fq;
@@ -661,7 +649,6 @@ void __init ipv6_frag_init(void) ip6_frags.skb_free =NULL ; ip6_frags.qsize =sizeof (struct frag_queue ); ip6_frags.match = ip6_frag_match; - ip6_frags.equal = ip6_frag_equal; ip6_frags.frag_expire = ip6_frag_expire;inet_frags_init (&ip6_frags); }
Signature · 1 line
1.5.3.4
PATCH 7/7 Consolidate frag queues freeing
In reply to Pavel EmelyanovSince we now allocate the queues in inet_fragment.c, we can safely free it in the same place. The ->destructor callback thus becomes optional for inet_frags.
---
net/ipv4/inet_fragment.c +3 -1
@@ -136,7 +136,9 @@ void inet_frag_destroy(struct inet_frag_queue *q, struct inet_frags *f, *work -= f->qsize;atomic_sub (f->qsize, &f->mem); - f->destructor (q); +if (f->destructor) + f->destructor (q); +kfree (q); }EXPORT_SYMBOL (inet_frag_destroy);
net/ipv4/ip_fragment.c +0 -1
@@ -171,7 +171,6 @@ static __inline__ void ip4_frag_free(struct inet_frag_queue *q) qp = container_of(q, struct ipq, q);if (qp->peer)inet_putpeer (qp->peer); -kfree (qp); }
net/ipv6/netfilter/nf_conntrack_reasm.c +1 -6
@@ -130,11 +130,6 @@ static inline void frag_kfree_skb(struct sk_buff *skb, unsigned int *work)kfree_skb (skb); } -static void nf_frag_free (struct inet_frag_queue *q) -{ -kfree (container_of(q ,struct nf_ct_frag6_queue ,q )); -} -/* Destruction primitives. */ static __inline__void fq_put (struct nf_ct_frag6_queue *fq)
@@ -682,7 +677,7 @@ int nf_ct_frag6_init(void) nf_frags.ctl = &nf_frags_ctl; nf_frags.hashfn = nf_hashfn; nf_frags.constructor = ip6_frag_init; - nf_frags.destructor = nf_frag_free; + nf_frags.destructor =NULL ; nf_frags.skb_free = nf_skb_free; nf_frags.qsize =sizeof (struct nf_ct_frag6_queue ); nf_frags.match = ip6_frag_match;
net/ipv6/reassembly.c +1 -6
@@ -175,11 +175,6 @@ void ip6_frag_init(struct inet_frag_queue *q, void *a) }EXPORT_SYMBOL (ip6_frag_init); -static void ip6_frag_free (struct inet_frag_queue *fq) -{ -kfree (container_of(fq ,struct frag_queue ,q )); -} -/* Destruction primitives. */ static __inline__void fq_put (struct frag_queue *fq)
@@ -645,7 +640,7 @@ void __init ipv6_frag_init(void) ip6_frags.ctl = &ip6_frags_ctl; ip6_frags.hashfn = ip6_hashfn; ip6_frags.constructor = ip6_frag_init; - ip6_frags.destructor = ip6_frag_free; + ip6_frags.destructor =NULL ; ip6_frags.skb_free =NULL ; ip6_frags.qsize =sizeof (struct frag_queue ); ip6_frags.match = ip6_frag_match;
Signature · 1 line
1.5.3.4
Re: [PATCH 1/7] Omit double hash calculations in xxx_frag_intern
In reply to Pavel EmelyanovFrom: Pavel Emelyanov <[email protected]>
Date: Tue, 16 Oct 2007 17:48:46 +0400
Quoted 5 lines
Since the hash value is already calculated in
xxx_find, we can simply use it later. This is already done in netfilter code, so make the same in ipv4 and ipv6.Signed-off-by Pavel Emelyanov <[email protected]>
Applied, but if we ever implement dynamically sized frag queue hash tables, this recomputation of the hash function in the hash insert function would need to be re-added.
Re: [PATCH 2/7] Consolidate xxx_frag_intern
In reply to Pavel EmelyanovFrom: Pavel Emelyanov <[email protected]>
Date: Tue, 16 Oct 2007 17:53:03 +0400
Quoted 8 lines
This routine checks for the existence of a given entry in the hash table and inserts the new one if needed.
The ->equal callback is used to compare two frag_queue-s together, but this one is temporary and will be removed later. The netfilter code and the ipv6 one use the same routine to compare frags.
Quoted 5 lines
The
inet_frag_intern()always returns non-NULL pointer, so convert theinet_frag_queueinto protocol specific one (with thecontainer_of) without any checks.Signed-off-by Pavel Emelyanov <[email protected]>
Applied.
Re: [PATCH 3/7] Consolidate xxx_frag_alloc()
In reply to Pavel EmelyanovFrom: Pavel Emelyanov <[email protected]>
Date: Tue, 16 Oct 2007 17:57:44 +0400
Quoted 8 lines
Just perform the
kzalloc()allocation and setup common fields in theinet_frag_queue(). Then return the result to the caller to initialize the rest.The
inet_frag_alloc()may return NULL, so check the return value before doing thecontainer_of(). This looks ugly, but thexxx_frag_alloc()will be removed soon.
Quoted 5 lines
The
xxx_expire()timer callbacks are patches, because the argument is now theinet_frag_queue, not the protocol specific queue.Signed-off-by Pavel Emelyanov <[email protected]>
Applied, although I had to correct the following white-space problems in your patch:
Adds trailing whitespace.
diff:33:
Adds trailing whitespace.
diff:72:
Adds trailing whitespace.
diff:126:
warning: 3 lines add whitespace errors.
Re: [PATCH 4/7] Consolidate xxx_frag_create()
In reply to Pavel EmelyanovFrom: Pavel Emelyanov <[email protected]>
Date: Tue, 16 Oct 2007 18:00:10 +0400
Quoted 8 lines
This one uses the
xxx_frag_intern()andxxx_frag_alloc()routines, which are already consolidated, so remove them from protocol code (as promised).The ->constructor callback is used to init the rest of the frag queue and it is the same for netfilter and ipv6.
Signed-off-by Pavel Emelyanov <[email protected]>
Applied.
Re: [PATCH 5/7] Consolidate xxx_find() in fragment management
In reply to Pavel EmelyanovFrom: Pavel Emelyanov <[email protected]>
Date: Tue, 16 Oct 2007 18:03:37 +0400
Quoted 8 lines
Here we need another callback ->match to check whether the entry found in hash matches the key passed. The key used is the same as the creation argument for
inet_frag_create.Yet again, this ->match is the same for netfilter and ipv6. Running a frew steps forward - this callback will later replace the ->equal one.
Quoted 5 lines
Since the
inet_frag_find()uses the already consolidatedinet_frag_create()remove thexxx_frag_createfrom protocol codes.Signed-off-by Pavel Emelyanov <[email protected]>
Applied.
Re: [PATCH 6/7] Remove no longer needed ->equal callback
In reply to Pavel EmelyanovFrom: Pavel Emelyanov <[email protected]>
Date: Tue, 16 Oct 2007 18:05:31 +0400
Quoted 6 lines
Since this callback is used to check for conflicts in hashtable when inserting a newly created frag queue, we can do the same by checking for matching the queue with the argument, used to create one.
Signed-off-by Pavel Emelyanov <[email protected]>
Applied.
David Miller
maintainerRe: [PATCH 7/7] Consolidate frag queues freeing
In reply to Pavel EmelyanovFrom: Pavel Emelyanov <[email protected]>
Date: Tue, 16 Oct 2007 18:07:26 +0400
Quoted 5 lines
Since we now allocate the queues in
inet_fragment.c, we can safely free it in the same place. The ->destructor callback thus becomes optional forinet_frags.Signed-off-by Pavel Emelyanov <[email protected]>
Also applied, thanks a lot Pavel!