ipv6: unify fragment thresh handling code
authorAmerigo Wang <amwang@redhat.com>
Tue, 18 Sep 2012 16:50:11 +0000 (16:50 +0000)
committerDavid S. Miller <davem@davemloft.net>
Wed, 19 Sep 2012 21:23:28 +0000 (17:23 -0400)
Cc: Herbert Xu <herbert@gondor.apana.org.au>
Cc: Michal Kubeček <mkubecek@suse.cz>
Cc: David Miller <davem@davemloft.net>
Signed-off-by: Cong Wang <amwang@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/inet_frag.h
net/ipv4/inet_fragment.c
net/ipv4/ip_fragment.c
net/ipv6/netfilter/nf_conntrack_reasm.c
net/ipv6/reassembly.c

index 5098ee7..32786a0 100644 (file)
@@ -61,7 +61,7 @@ void inet_frags_exit_net(struct netns_frags *nf, struct inet_frags *f);
 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 netns_frags *nf, struct inet_frags *f);
+int inet_frag_evictor(struct netns_frags *nf, struct inet_frags *f, bool force);
 struct inet_frag_queue *inet_frag_find(struct netns_frags *nf,
                struct inet_frags *f, void *key, unsigned int hash)
        __releases(&f->lock);
index 85190e6..4750d2b 100644 (file)
@@ -89,7 +89,7 @@ void inet_frags_exit_net(struct netns_frags *nf, struct inet_frags *f)
        nf->low_thresh = 0;
 
        local_bh_disable();
-       inet_frag_evictor(nf, f);
+       inet_frag_evictor(nf, f, true);
        local_bh_enable();
 }
 EXPORT_SYMBOL(inet_frags_exit_net);
@@ -158,11 +158,16 @@ void inet_frag_destroy(struct inet_frag_queue *q, struct inet_frags *f,
 }
 EXPORT_SYMBOL(inet_frag_destroy);
 
-int inet_frag_evictor(struct netns_frags *nf, struct inet_frags *f)
+int inet_frag_evictor(struct netns_frags *nf, struct inet_frags *f, bool force)
 {
        struct inet_frag_queue *q;
        int work, evicted = 0;
 
+       if (!force) {
+               if (atomic_read(&nf->mem) <= nf->high_thresh)
+                       return 0;
+       }
+
        work = atomic_read(&nf->mem) - nf->low_thresh;
        while (work > 0) {
                read_lock(&f->lock);
index fa6a12c..448e685 100644 (file)
@@ -219,7 +219,7 @@ static void ip_evictor(struct net *net)
 {
        int evicted;
 
-       evicted = inet_frag_evictor(&net->ipv4.frags, &ip4_frags);
+       evicted = inet_frag_evictor(&net->ipv4.frags, &ip4_frags, false);
        if (evicted)
                IP_ADD_STATS_BH(net, IPSTATS_MIB_REASMFAILS, evicted);
 }
@@ -684,8 +684,7 @@ int ip_defrag(struct sk_buff *skb, u32 user)
        IP_INC_STATS_BH(net, IPSTATS_MIB_REASMREQDS);
 
        /* Start by cleaning up the memory. */
-       if (atomic_read(&net->ipv4.frags.mem) > net->ipv4.frags.high_thresh)
-               ip_evictor(net);
+       ip_evictor(net);
 
        /* Lookup (or create) queue header */
        if ((qp = ip_find(net, ip_hdr(skb), user)) != NULL) {
index 54274c3..1af12fd 100644 (file)
@@ -566,11 +566,9 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user)
        hdr = ipv6_hdr(clone);
        fhdr = (struct frag_hdr *)skb_transport_header(clone);
 
-       if (atomic_read(&net->nf_frag.frags.mem) > net->nf_frag.frags.high_thresh) {
-               local_bh_disable();
-               inet_frag_evictor(&net->nf_frag.frags, &nf_frags);
-               local_bh_enable();
-       }
+       local_bh_disable();
+       inet_frag_evictor(&net->nf_frag.frags, &nf_frags, false);
+       local_bh_enable();
 
        fq = fq_find(net, fhdr->identification, user, &hdr->saddr, &hdr->daddr);
        if (fq == NULL) {
index cf74f4e..da8a4e3 100644 (file)
@@ -131,15 +131,6 @@ void ip6_frag_init(struct inet_frag_queue *q, void *a)
 }
 EXPORT_SYMBOL(ip6_frag_init);
 
-static void ip6_evictor(struct net *net, struct inet6_dev *idev)
-{
-       int evicted;
-
-       evicted = inet_frag_evictor(&net->ipv6.frags, &ip6_frags);
-       if (evicted)
-               IP6_ADD_STATS_BH(net, idev, IPSTATS_MIB_REASMFAILS, evicted);
-}
-
 void ip6_expire_frag_queue(struct net *net, struct frag_queue *fq,
                           struct inet_frags *frags)
 {
@@ -515,6 +506,7 @@ static int ipv6_frag_rcv(struct sk_buff *skb)
        struct frag_queue *fq;
        const struct ipv6hdr *hdr = ipv6_hdr(skb);
        struct net *net = dev_net(skb_dst(skb)->dev);
+       int evicted;
 
        IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_REASMREQDS);
 
@@ -539,8 +531,10 @@ static int ipv6_frag_rcv(struct sk_buff *skb)
                return 1;
        }
 
-       if (atomic_read(&net->ipv6.frags.mem) > net->ipv6.frags.high_thresh)
-               ip6_evictor(net, ip6_dst_idev(skb_dst(skb)));
+       evicted = inet_frag_evictor(&net->ipv6.frags, &ip6_frags, false);
+       if (evicted)
+               IP6_ADD_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
+                                IPSTATS_MIB_REASMFAILS, evicted);
 
        fq = fq_find(net, fhdr->identification, &hdr->saddr, &hdr->daddr);
        if (fq != NULL) {