]> Pileus Git - ~andy/linux/blobdiff - net/ipv4/ip_fragment.c
net: Add skb_unclone() helper function.
[~andy/linux] / net / ipv4 / ip_fragment.c
index eb9d63a570cd1ce595076096d9b2aea3723a4c38..b6d30acb600c5e306ba825ed394c252e4fe27a8b 100644 (file)
@@ -122,7 +122,7 @@ int ip_frag_nqueues(struct net *net)
 
 int ip_frag_mem(struct net *net)
 {
-       return atomic_read(&net->ipv4.frags.mem);
+       return sum_frag_mem_limit(&net->ipv4.frags);
 }
 
 static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
@@ -161,13 +161,6 @@ static bool ip4_frag_match(struct inet_frag_queue *q, void *a)
                qp->user == arg->user;
 }
 
-/* Memory Tracking Functions. */
-static void frag_kfree_skb(struct netns_frags *nf, struct sk_buff *skb)
-{
-       atomic_sub(skb->truesize, &nf->mem);
-       kfree_skb(skb);
-}
-
 static void ip4_frag_init(struct inet_frag_queue *q, void *a)
 {
        struct ipq *qp = container_of(q, struct ipq, q);
@@ -340,6 +333,7 @@ static inline int ip_frag_too_far(struct ipq *qp)
 static int ip_frag_reinit(struct ipq *qp)
 {
        struct sk_buff *fp;
+       unsigned int sum_truesize = 0;
 
        if (!mod_timer(&qp->q.timer, jiffies + qp->q.net->timeout)) {
                atomic_inc(&qp->q.refcnt);
@@ -349,9 +343,12 @@ static int ip_frag_reinit(struct ipq *qp)
        fp = qp->q.fragments;
        do {
                struct sk_buff *xp = fp->next;
-               frag_kfree_skb(qp->q.net, fp);
+
+               sum_truesize += fp->truesize;
+               kfree_skb(fp);
                fp = xp;
        } while (fp);
+       sub_frag_mem_limit(&qp->q, sum_truesize);
 
        qp->q.last_in = 0;
        qp->q.len = 0;
@@ -496,7 +493,8 @@ found:
                                qp->q.fragments = next;
 
                        qp->q.meat -= free_it->len;
-                       frag_kfree_skb(qp->q.net, free_it);
+                       sub_frag_mem_limit(&qp->q, free_it->truesize);
+                       kfree_skb(free_it);
                }
        }
 
@@ -519,7 +517,7 @@ found:
        qp->q.stamp = skb->tstamp;
        qp->q.meat += skb->len;
        qp->ecn |= ecn;
-       atomic_add(skb->truesize, &qp->q.net->mem);
+       add_frag_mem_limit(&qp->q, skb->truesize);
        if (offset == 0)
                qp->q.last_in |= INET_FRAG_FIRST_IN;
 
@@ -531,9 +529,7 @@ found:
            qp->q.meat == qp->q.len)
                return ip_frag_reasm(qp, prev, dev);
 
-       write_lock(&ip4_frags.lock);
-       list_move_tail(&qp->q.lru_list, &qp->q.net->lru_list);
-       write_unlock(&ip4_frags.lock);
+       inet_frag_lru_move(&qp->q);
        return -EINPROGRESS;
 
 err:
@@ -594,7 +590,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
                goto out_oversize;
 
        /* Head of list must not be cloned. */
-       if (skb_cloned(head) && pskb_expand_head(head, 0, 0, GFP_ATOMIC))
+       if (skb_unclone(head, GFP_ATOMIC))
                goto out_nomem;
 
        /* If the first fragment is fragmented itself, we split
@@ -617,7 +613,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
                head->len -= clone->len;
                clone->csum = 0;
                clone->ip_summed = head->ip_summed;
-               atomic_add(clone->truesize, &qp->q.net->mem);
+               add_frag_mem_limit(&qp->q, clone->truesize);
        }
 
        skb_push(head, head->data - skb_network_header(head));
@@ -645,7 +641,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
                }
                fp = next;
        }
-       atomic_sub(sum_truesize, &qp->q.net->mem);
+       sub_frag_mem_limit(&qp->q, sum_truesize);
 
        head->next = NULL;
        head->dev = dev;
@@ -851,14 +847,22 @@ static inline void ip4_frags_ctl_register(void)
 
 static int __net_init ipv4_frags_init_net(struct net *net)
 {
-       /*
-        * Fragment cache limits. We will commit 256K at one time. Should we
-        * cross that limit we will prune down to 192K. This should cope with
-        * even the most extreme cases without allowing an attacker to
-        * measurably harm machine performance.
+       /* Fragment cache limits.
+        *
+        * The fragment memory accounting code, (tries to) account for
+        * the real memory usage, by measuring both the size of frag
+        * queue struct (inet_frag_queue (ipv4:ipq/ipv6:frag_queue))
+        * and the SKB's truesize.
+        *
+        * A 64K fragment consumes 129736 bytes (44*2944)+200
+        * (1500 truesize == 2944, sizeof(struct ipq) == 200)
+        *
+        * We will commit 4MB at one time. Should we cross that limit
+        * we will prune down to 3MB, making room for approx 8 big 64K
+        * fragments 8x128k.
         */
-       net->ipv4.frags.high_thresh = 256 * 1024;
-       net->ipv4.frags.low_thresh = 192 * 1024;
+       net->ipv4.frags.high_thresh = 4 * 1024 * 1024;
+       net->ipv4.frags.low_thresh  = 3 * 1024 * 1024;
        /*
         * Important NOTE! Fragment queue must be destroyed before MSL expires.
         * RFC791 is wrong proposing to prolongate timer each fragment arrival