1, add new drop reason FRAG_FAILED/FRAG_OUTPUT_FAILED 2, use drop reasons in ip_fragment Signed-off-by: Yonglong Li --- include/net/dropreason-core.h | 6 ++++++ net/ipv4/ip_output.c | 17 ++++++++++++----- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/include/net/dropreason-core.h b/include/net/dropreason-core.h index 58d91cc..4ae042e 100644 --- a/include/net/dropreason-core.h +++ b/include/net/dropreason-core.h @@ -99,6 +99,8 @@ FN(DUP_FRAG) \ FN(FRAG_REASM_TIMEOUT) \ FN(FRAG_TOO_FAR) \ + FN(FRAG_FAILED) \ + FN(FRAG_OUTPUT_FAILED) \ FN(TCP_MINTTL) \ FN(IPV6_BAD_EXTHDR) \ FN(IPV6_NDISC_FRAG) \ @@ -500,6 +502,10 @@ enum skb_drop_reason { * (/proc/sys/net/ipv4/ipfrag_max_dist) */ SKB_DROP_REASON_FRAG_TOO_FAR, + /* do ip/ip6 fragment failed */ + SKB_DROP_REASON_FRAG_FAILED, + /* ip/ip6 fragment output failed */ + SKB_DROP_REASON_FRAG_OUTPUT_FAILED, /** * @SKB_DROP_REASON_TCP_MINTTL: ipv4 ttl or ipv6 hoplimit below * the threshold (IP_MINTTL or IPV6_MINHOPCOUNT). diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index ff11d3a..2eab175 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -588,7 +588,7 @@ static int ip_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, IP_INC_STATS(net, IPSTATS_MIB_FRAGFAILS); icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu)); - kfree_skb(skb); + kfree_skb_reason(skb, SKB_DROP_REASON_PKT_TOO_BIG); return -EMSGSIZE; } @@ -765,6 +765,7 @@ int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, struct sk_buff *skb2; u8 tstamp_type = skb->tstamp_type; struct rtable *rt = skb_rtable(skb); + SKB_DR_INIT(reason, FRAG_FAILED); unsigned int mtu, hlen, ll_rs; struct ip_fraglist_iter iter; ktime_t tstamp = skb->tstamp; @@ -773,8 +774,10 @@ int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, /* for offloaded checksums cleanup checksum before fragmentation */ if (skb->ip_summed == CHECKSUM_PARTIAL && - (err = skb_checksum_help(skb))) + (err = skb_checksum_help(skb))) { + SKB_DR_SET(reason, SKB_CSUM); goto fail; + } /* * Point into the IP datagram header. @@ -860,6 +863,8 @@ int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, if (!err) IP_INC_STATS(net, IPSTATS_MIB_FRAGCREATES); + else + SKB_DR_SET(reason, FRAG_OUTPUT_FAILED); if (err || !iter.frag) break; @@ -871,7 +876,7 @@ int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, return 0; } - kfree_skb_list(iter.frag); + kfree_skb_list_reason(iter.frag, reason); IP_INC_STATS(net, IPSTATS_MIB_FRAGFAILS); return err; @@ -913,8 +918,10 @@ int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, */ skb_set_delivery_time(skb2, tstamp, tstamp_type); err = output(net, sk, skb2); - if (err) + if (err) { + SKB_DR_SET(reason, FRAG_OUTPUT_FAILED); goto fail; + } IP_INC_STATS(net, IPSTATS_MIB_FRAGCREATES); } @@ -923,7 +930,7 @@ int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, return err; fail: - kfree_skb(skb); + kfree_skb_reason(skb, reason); IP_INC_STATS(net, IPSTATS_MIB_FRAGFAILS); return err; } -- 1.8.3.1 use drop reasons in ip6_output like ip_fragment/ip_do_fragment Signed-off-by: Yonglong Li --- net/ipv6/ip6_output.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index f904739e..31dea51 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -879,6 +879,7 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, struct ipv6_pinfo *np = skb->sk && !dev_recursion_level() ? inet6_sk(skb->sk) : NULL; u8 tstamp_type = skb->tstamp_type; + SKB_DR_INIT(reason, FRAG_FAILED); struct ip6_frag_state state; unsigned int mtu, hlen, nexthdr_offset; ktime_t tstamp = skb->tstamp; @@ -925,8 +926,10 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, &ipv6_hdr(skb)->saddr); if (skb->ip_summed == CHECKSUM_PARTIAL && - (err = skb_checksum_help(skb))) + (err = skb_checksum_help(skb))) { + SKB_DR_SET(reason, SKB_CSUM); goto fail; + } prevhdr = skb_network_header(skb) + nexthdr_offset; hroom = LL_RESERVED_SPACE(rt->dst.dev); @@ -979,6 +982,8 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, if (!err) IP6_INC_STATS(net, ip6_dst_idev(&rt->dst), IPSTATS_MIB_FRAGCREATES); + else + SKB_DR_SET(reason, FRAG_OUTPUT_FAILED); if (err || !iter.frag) break; @@ -995,7 +1000,7 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, return 0; } - kfree_skb_list(iter.frag); + kfree_skb_list_reason(iter.frag, reason); IP6_INC_STATS(net, ip6_dst_idev(&rt->dst), IPSTATS_MIB_FRAGFAILS); @@ -1037,8 +1042,10 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, */ skb_set_delivery_time(frag, tstamp, tstamp_type); err = output(net, sk, frag); - if (err) + if (err) { + SKB_DR_SET(reason, FRAG_OUTPUT_FAILED); goto fail; + } IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_FRAGCREATES); @@ -1050,12 +1057,13 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, fail_toobig: icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); + SKB_DR_SET(reason, PKT_TOO_BIG); err = -EMSGSIZE; fail: IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_FRAGFAILS); - kfree_skb(skb); + kfree_skb_reason(skb, reason); return err; } -- 1.8.3.1