OSDN Git Service

net: dropreason: add SKB_DROP_REASON_DUP_FRAG
authorEric Dumazet <edumazet@google.com>
Sat, 29 Oct 2022 15:45:18 +0000 (15:45 +0000)
committerJakub Kicinski <kuba@kernel.org>
Tue, 1 Nov 2022 03:14:26 +0000 (20:14 -0700)
This is used to track when a duplicate segment received by various
reassembly units is dropped.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
include/net/dropreason.h
net/ipv4/ip_fragment.c
net/ipv6/netfilter/nf_conntrack_reasm.c
net/ipv6/reassembly.c

index 0bd18c1..602d555 100644 (file)
@@ -68,6 +68,7 @@
        FN(IP_INADDRERRORS)             \
        FN(IP_INNOROUTES)               \
        FN(PKT_TOO_BIG)                 \
+       FN(DUP_FRAG)                    \
        FNe(MAX)
 
 /**
@@ -300,6 +301,8 @@ enum skb_drop_reason {
         * MTU)
         */
        SKB_DROP_REASON_PKT_TOO_BIG,
+       /** @SKB_DROP_REASON_DUP_FRAG: duplicate fragment */
+       SKB_DROP_REASON_DUP_FRAG,
        /**
         * @SKB_DROP_REASON_MAX: the maximum of drop reason, which shouldn't be
         * used as a real 'reason'
index fb15356..676bd8d 100644 (file)
@@ -278,10 +278,14 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
        struct net_device *dev;
        unsigned int fragsize;
        int err = -ENOENT;
+       SKB_DR(reason);
        u8 ecn;
 
-       if (qp->q.flags & INET_FRAG_COMPLETE)
+       /* If reassembly is already done, @skb must be a duplicate frag. */
+       if (qp->q.flags & INET_FRAG_COMPLETE) {
+               SKB_DR_SET(reason, DUP_FRAG);
                goto err;
+       }
 
        if (!(IPCB(skb)->flags & IPSKB_FRAG_COMPLETE) &&
            unlikely(ip_frag_too_far(qp)) &&
@@ -382,8 +386,9 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
 
 insert_error:
        if (err == IPFRAG_DUP) {
-               kfree_skb(skb);
-               return -EINVAL;
+               SKB_DR_SET(reason, DUP_FRAG);
+               err = -EINVAL;
+               goto err;
        }
        err = -EINVAL;
        __IP_INC_STATS(net, IPSTATS_MIB_REASM_OVERLAPS);
@@ -391,7 +396,7 @@ discard_qp:
        inet_frag_kill(&qp->q);
        __IP_INC_STATS(net, IPSTATS_MIB_REASMFAILS);
 err:
-       kfree_skb(skb);
+       kfree_skb_reason(skb, reason);
        return err;
 }
 
index 38db006..d13240f 100644 (file)
@@ -253,7 +253,7 @@ static int nf_ct_frag6_queue(struct frag_queue *fq, struct sk_buff *skb,
        if (err) {
                if (err == IPFRAG_DUP) {
                        /* No error for duplicates, pretend they got queued. */
-                       kfree_skb(skb);
+                       kfree_skb_reason(skb, SKB_DROP_REASON_DUP_FRAG);
                        return -EINPROGRESS;
                }
                goto insert_error;
index ff866f2..5bc8a28 100644 (file)
@@ -112,10 +112,14 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
        struct sk_buff *prev_tail;
        struct net_device *dev;
        int err = -ENOENT;
+       SKB_DR(reason);
        u8 ecn;
 
-       if (fq->q.flags & INET_FRAG_COMPLETE)
+       /* If reassembly is already done, @skb must be a duplicate frag. */
+       if (fq->q.flags & INET_FRAG_COMPLETE) {
+               SKB_DR_SET(reason, DUP_FRAG);
                goto err;
+       }
 
        err = -EINVAL;
        offset = ntohs(fhdr->frag_off) & ~0x7;
@@ -226,8 +230,9 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
 
 insert_error:
        if (err == IPFRAG_DUP) {
-               kfree_skb(skb);
-               return -EINVAL;
+               SKB_DR_SET(reason, DUP_FRAG);
+               err = -EINVAL;
+               goto err;
        }
        err = -EINVAL;
        __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
@@ -237,7 +242,7 @@ discard_fq:
        __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
                        IPSTATS_MIB_REASMFAILS);
 err:
-       kfree_skb(skb);
+       kfree_skb_reason(skb, reason);
        return err;
 }