diff options
Diffstat (limited to 'net/ipv4/ip_fragment.c')
-rw-r--r-- | net/ipv4/ip_fragment.c | 52 |
1 files changed, 28 insertions, 24 deletions
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index eb9d63a570cd..b6d30acb600c 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c | |||
@@ -122,7 +122,7 @@ int ip_frag_nqueues(struct net *net) | |||
122 | 122 | ||
123 | int ip_frag_mem(struct net *net) | 123 | int ip_frag_mem(struct net *net) |
124 | { | 124 | { |
125 | return atomic_read(&net->ipv4.frags.mem); | 125 | return sum_frag_mem_limit(&net->ipv4.frags); |
126 | } | 126 | } |
127 | 127 | ||
128 | static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev, | 128 | 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) | |||
161 | qp->user == arg->user; | 161 | qp->user == arg->user; |
162 | } | 162 | } |
163 | 163 | ||
164 | /* Memory Tracking Functions. */ | ||
165 | static void frag_kfree_skb(struct netns_frags *nf, struct sk_buff *skb) | ||
166 | { | ||
167 | atomic_sub(skb->truesize, &nf->mem); | ||
168 | kfree_skb(skb); | ||
169 | } | ||
170 | |||
171 | static void ip4_frag_init(struct inet_frag_queue *q, void *a) | 164 | static void ip4_frag_init(struct inet_frag_queue *q, void *a) |
172 | { | 165 | { |
173 | struct ipq *qp = container_of(q, struct ipq, q); | 166 | struct ipq *qp = container_of(q, struct ipq, q); |
@@ -340,6 +333,7 @@ static inline int ip_frag_too_far(struct ipq *qp) | |||
340 | static int ip_frag_reinit(struct ipq *qp) | 333 | static int ip_frag_reinit(struct ipq *qp) |
341 | { | 334 | { |
342 | struct sk_buff *fp; | 335 | struct sk_buff *fp; |
336 | unsigned int sum_truesize = 0; | ||
343 | 337 | ||
344 | if (!mod_timer(&qp->q.timer, jiffies + qp->q.net->timeout)) { | 338 | if (!mod_timer(&qp->q.timer, jiffies + qp->q.net->timeout)) { |
345 | atomic_inc(&qp->q.refcnt); | 339 | atomic_inc(&qp->q.refcnt); |
@@ -349,9 +343,12 @@ static int ip_frag_reinit(struct ipq *qp) | |||
349 | fp = qp->q.fragments; | 343 | fp = qp->q.fragments; |
350 | do { | 344 | do { |
351 | struct sk_buff *xp = fp->next; | 345 | struct sk_buff *xp = fp->next; |
352 | frag_kfree_skb(qp->q.net, fp); | 346 | |
347 | sum_truesize += fp->truesize; | ||
348 | kfree_skb(fp); | ||
353 | fp = xp; | 349 | fp = xp; |
354 | } while (fp); | 350 | } while (fp); |
351 | sub_frag_mem_limit(&qp->q, sum_truesize); | ||
355 | 352 | ||
356 | qp->q.last_in = 0; | 353 | qp->q.last_in = 0; |
357 | qp->q.len = 0; | 354 | qp->q.len = 0; |
@@ -496,7 +493,8 @@ found: | |||
496 | qp->q.fragments = next; | 493 | qp->q.fragments = next; |
497 | 494 | ||
498 | qp->q.meat -= free_it->len; | 495 | qp->q.meat -= free_it->len; |
499 | frag_kfree_skb(qp->q.net, free_it); | 496 | sub_frag_mem_limit(&qp->q, free_it->truesize); |
497 | kfree_skb(free_it); | ||
500 | } | 498 | } |
501 | } | 499 | } |
502 | 500 | ||
@@ -519,7 +517,7 @@ found: | |||
519 | qp->q.stamp = skb->tstamp; | 517 | qp->q.stamp = skb->tstamp; |
520 | qp->q.meat += skb->len; | 518 | qp->q.meat += skb->len; |
521 | qp->ecn |= ecn; | 519 | qp->ecn |= ecn; |
522 | atomic_add(skb->truesize, &qp->q.net->mem); | 520 | add_frag_mem_limit(&qp->q, skb->truesize); |
523 | if (offset == 0) | 521 | if (offset == 0) |
524 | qp->q.last_in |= INET_FRAG_FIRST_IN; | 522 | qp->q.last_in |= INET_FRAG_FIRST_IN; |
525 | 523 | ||
@@ -531,9 +529,7 @@ found: | |||
531 | qp->q.meat == qp->q.len) | 529 | qp->q.meat == qp->q.len) |
532 | return ip_frag_reasm(qp, prev, dev); | 530 | return ip_frag_reasm(qp, prev, dev); |
533 | 531 | ||
534 | write_lock(&ip4_frags.lock); | 532 | inet_frag_lru_move(&qp->q); |
535 | list_move_tail(&qp->q.lru_list, &qp->q.net->lru_list); | ||
536 | write_unlock(&ip4_frags.lock); | ||
537 | return -EINPROGRESS; | 533 | return -EINPROGRESS; |
538 | 534 | ||
539 | err: | 535 | err: |
@@ -594,7 +590,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev, | |||
594 | goto out_oversize; | 590 | goto out_oversize; |
595 | 591 | ||
596 | /* Head of list must not be cloned. */ | 592 | /* Head of list must not be cloned. */ |
597 | if (skb_cloned(head) && pskb_expand_head(head, 0, 0, GFP_ATOMIC)) | 593 | if (skb_unclone(head, GFP_ATOMIC)) |
598 | goto out_nomem; | 594 | goto out_nomem; |
599 | 595 | ||
600 | /* If the first fragment is fragmented itself, we split | 596 | /* 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, | |||
617 | head->len -= clone->len; | 613 | head->len -= clone->len; |
618 | clone->csum = 0; | 614 | clone->csum = 0; |
619 | clone->ip_summed = head->ip_summed; | 615 | clone->ip_summed = head->ip_summed; |
620 | atomic_add(clone->truesize, &qp->q.net->mem); | 616 | add_frag_mem_limit(&qp->q, clone->truesize); |
621 | } | 617 | } |
622 | 618 | ||
623 | skb_push(head, head->data - skb_network_header(head)); | 619 | 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, | |||
645 | } | 641 | } |
646 | fp = next; | 642 | fp = next; |
647 | } | 643 | } |
648 | atomic_sub(sum_truesize, &qp->q.net->mem); | 644 | sub_frag_mem_limit(&qp->q, sum_truesize); |
649 | 645 | ||
650 | head->next = NULL; | 646 | head->next = NULL; |
651 | head->dev = dev; | 647 | head->dev = dev; |
@@ -851,14 +847,22 @@ static inline void ip4_frags_ctl_register(void) | |||
851 | 847 | ||
852 | static int __net_init ipv4_frags_init_net(struct net *net) | 848 | static int __net_init ipv4_frags_init_net(struct net *net) |
853 | { | 849 | { |
854 | /* | 850 | /* Fragment cache limits. |
855 | * Fragment cache limits. We will commit 256K at one time. Should we | 851 | * |
856 | * cross that limit we will prune down to 192K. This should cope with | 852 | * The fragment memory accounting code, (tries to) account for |
857 | * even the most extreme cases without allowing an attacker to | 853 | * the real memory usage, by measuring both the size of frag |
858 | * measurably harm machine performance. | 854 | * queue struct (inet_frag_queue (ipv4:ipq/ipv6:frag_queue)) |
855 | * and the SKB's truesize. | ||
856 | * | ||
857 | * A 64K fragment consumes 129736 bytes (44*2944)+200 | ||
858 | * (1500 truesize == 2944, sizeof(struct ipq) == 200) | ||
859 | * | ||
860 | * We will commit 4MB at one time. Should we cross that limit | ||
861 | * we will prune down to 3MB, making room for approx 8 big 64K | ||
862 | * fragments 8x128k. | ||
859 | */ | 863 | */ |
860 | net->ipv4.frags.high_thresh = 256 * 1024; | 864 | net->ipv4.frags.high_thresh = 4 * 1024 * 1024; |
861 | net->ipv4.frags.low_thresh = 192 * 1024; | 865 | net->ipv4.frags.low_thresh = 3 * 1024 * 1024; |
862 | /* | 866 | /* |
863 | * Important NOTE! Fragment queue must be destroyed before MSL expires. | 867 | * Important NOTE! Fragment queue must be destroyed before MSL expires. |
864 | * RFC791 is wrong proposing to prolongate timer each fragment arrival | 868 | * RFC791 is wrong proposing to prolongate timer each fragment arrival |