Skip to content

Commit 77adfd3

Browse files
edumazetkuba-moo
authored andcommitted
net: dropreason: add SKB_DROP_REASON_FRAG_REASM_TIMEOUT
Used to track skbs freed after a timeout happened in a reassmbly unit. Passing a @Reason argument to inet_frag_rbtree_purge() allows to use correct consumed status for frags that have been successfully re-assembled. Signed-off-by: Eric Dumazet <[email protected]> Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 4ecbb1c commit 77adfd3

File tree

5 files changed

+24
-8
lines changed

5 files changed

+24
-8
lines changed

include/net/dropreason.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
FN(IP_INNOROUTES) \
7070
FN(PKT_TOO_BIG) \
7171
FN(DUP_FRAG) \
72+
FN(FRAG_REASM_TIMEOUT) \
7273
FNe(MAX)
7374

7475
/**
@@ -303,6 +304,8 @@ enum skb_drop_reason {
303304
SKB_DROP_REASON_PKT_TOO_BIG,
304305
/** @SKB_DROP_REASON_DUP_FRAG: duplicate fragment */
305306
SKB_DROP_REASON_DUP_FRAG,
307+
/** @SKB_DROP_REASON_FRAG_REASM_TIMEOUT: fragment reassembly timeout */
308+
SKB_DROP_REASON_FRAG_REASM_TIMEOUT,
306309
/**
307310
* @SKB_DROP_REASON_MAX: the maximum of drop reason, which shouldn't be
308311
* used as a real 'reason'

include/net/inet_frag.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <linux/in6.h>
88
#include <linux/rbtree_types.h>
99
#include <linux/refcount.h>
10+
#include <net/dropreason.h>
1011

1112
/* Per netns frag queues directory */
1213
struct fqdir {
@@ -34,12 +35,14 @@ struct fqdir {
3435
* @INET_FRAG_LAST_IN: final fragment has arrived
3536
* @INET_FRAG_COMPLETE: frag queue has been processed and is due for destruction
3637
* @INET_FRAG_HASH_DEAD: inet_frag_kill() has not removed fq from rhashtable
38+
* @INET_FRAG_DROP: if skbs must be dropped (instead of being consumed)
3739
*/
3840
enum {
3941
INET_FRAG_FIRST_IN = BIT(0),
4042
INET_FRAG_LAST_IN = BIT(1),
4143
INET_FRAG_COMPLETE = BIT(2),
4244
INET_FRAG_HASH_DEAD = BIT(3),
45+
INET_FRAG_DROP = BIT(4),
4346
};
4447

4548
struct frag_v4_compare_key {
@@ -139,7 +142,8 @@ void inet_frag_destroy(struct inet_frag_queue *q);
139142
struct inet_frag_queue *inet_frag_find(struct fqdir *fqdir, void *key);
140143

141144
/* Free all skbs in the queue; return the sum of their truesizes. */
142-
unsigned int inet_frag_rbtree_purge(struct rb_root *root);
145+
unsigned int inet_frag_rbtree_purge(struct rb_root *root,
146+
enum skb_drop_reason reason);
143147

144148
static inline void inet_frag_put(struct inet_frag_queue *q)
145149
{

include/net/ipv6_frag.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ ip6frag_expire_frag_queue(struct net *net, struct frag_queue *fq)
7676
if (fq->q.flags & INET_FRAG_COMPLETE)
7777
goto out;
7878

79+
fq->q.flags |= INET_FRAG_DROP;
7980
inet_frag_kill(&fq->q);
8081

8182
dev = dev_get_by_index_rcu(net, fq->iif);
@@ -101,7 +102,7 @@ ip6frag_expire_frag_queue(struct net *net, struct frag_queue *fq)
101102
spin_unlock(&fq->q.lock);
102103

103104
icmpv6_send(head, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0);
104-
kfree_skb(head);
105+
kfree_skb_reason(head, SKB_DROP_REASON_FRAG_REASM_TIMEOUT);
105106
goto out_rcu_unlock;
106107

107108
out:

net/ipv4/inet_fragment.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ static void inet_frags_free_cb(void *ptr, void *arg)
133133
count = del_timer_sync(&fq->timer) ? 1 : 0;
134134

135135
spin_lock_bh(&fq->lock);
136+
fq->flags |= INET_FRAG_DROP;
136137
if (!(fq->flags & INET_FRAG_COMPLETE)) {
137138
fq->flags |= INET_FRAG_COMPLETE;
138139
count++;
@@ -260,7 +261,8 @@ static void inet_frag_destroy_rcu(struct rcu_head *head)
260261
kmem_cache_free(f->frags_cachep, q);
261262
}
262263

263-
unsigned int inet_frag_rbtree_purge(struct rb_root *root)
264+
unsigned int inet_frag_rbtree_purge(struct rb_root *root,
265+
enum skb_drop_reason reason)
264266
{
265267
struct rb_node *p = rb_first(root);
266268
unsigned int sum = 0;
@@ -274,7 +276,7 @@ unsigned int inet_frag_rbtree_purge(struct rb_root *root)
274276
struct sk_buff *next = FRAG_CB(skb)->next_frag;
275277

276278
sum += skb->truesize;
277-
kfree_skb(skb);
279+
kfree_skb_reason(skb, reason);
278280
skb = next;
279281
}
280282
}
@@ -284,17 +286,21 @@ EXPORT_SYMBOL(inet_frag_rbtree_purge);
284286

285287
void inet_frag_destroy(struct inet_frag_queue *q)
286288
{
287-
struct fqdir *fqdir;
288289
unsigned int sum, sum_truesize = 0;
290+
enum skb_drop_reason reason;
289291
struct inet_frags *f;
292+
struct fqdir *fqdir;
290293

291294
WARN_ON(!(q->flags & INET_FRAG_COMPLETE));
295+
reason = (q->flags & INET_FRAG_DROP) ?
296+
SKB_DROP_REASON_FRAG_REASM_TIMEOUT :
297+
SKB_CONSUMED;
292298
WARN_ON(del_timer(&q->timer) != 0);
293299

294300
/* Release all fragment data. */
295301
fqdir = q->fqdir;
296302
f = fqdir->f;
297-
sum_truesize = inet_frag_rbtree_purge(&q->rb_fragments);
303+
sum_truesize = inet_frag_rbtree_purge(&q->rb_fragments, reason);
298304
sum = sum_truesize + f->qsize;
299305

300306
call_rcu(&q->rcu, inet_frag_destroy_rcu);

net/ipv4/ip_fragment.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ static void ip_expire(struct timer_list *t)
153153
if (qp->q.flags & INET_FRAG_COMPLETE)
154154
goto out;
155155

156+
qp->q.flags |= INET_FRAG_DROP;
156157
ipq_kill(qp);
157158
__IP_INC_STATS(net, IPSTATS_MIB_REASMFAILS);
158159
__IP_INC_STATS(net, IPSTATS_MIB_REASMTIMEOUT);
@@ -194,7 +195,7 @@ static void ip_expire(struct timer_list *t)
194195
spin_unlock(&qp->q.lock);
195196
out_rcu_unlock:
196197
rcu_read_unlock();
197-
kfree_skb(head);
198+
kfree_skb_reason(head, SKB_DROP_REASON_FRAG_REASM_TIMEOUT);
198199
ipq_put(qp);
199200
}
200201

@@ -254,7 +255,8 @@ static int ip_frag_reinit(struct ipq *qp)
254255
return -ETIMEDOUT;
255256
}
256257

257-
sum_truesize = inet_frag_rbtree_purge(&qp->q.rb_fragments);
258+
sum_truesize = inet_frag_rbtree_purge(&qp->q.rb_fragments,
259+
SKB_DROP_REASON_NOT_SPECIFIED);
258260
sub_frag_mem_limit(qp->q.fqdir, sum_truesize);
259261

260262
qp->q.flags = 0;

0 commit comments

Comments
 (0)