Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'ip-ingress-skb-reason'

Menglong Dong says:

====================
net: ip: add skb drop reasons to ip ingress

In the series "net: use kfree_skb_reason() for ip/udp packet receive",
skb drop reasons are added to the basic ingress path of IPv4. And in
the series "net: use kfree_skb_reason() for ip/neighbour", the egress
paths of IPv4 and IPv6 are handled. Related links:

https://lore.kernel.org/netdev/20220205074739.543606-1-imagedong@tencent.com/
https://lore.kernel.org/netdev/20220226041831.2058437-1-imagedong@tencent.com/

Seems we still have a lot work to do with IP layer, including IPv6 basic
ingress path, IPv4/IPv6 forwarding, IPv6 exthdrs, fragment and defrag,
etc.

In this series, skb drop reasons are added to the basic ingress path of
IPv6 protocol and IPv4/IPv6 packet forwarding. Following functions, which
are used for IPv6 packet receiving are handled:

ip6_pkt_drop()
ip6_rcv_core()
ip6_protocol_deliver_rcu()

And following functions that used for IPv6 TLV parse are handled:

ip6_parse_tlv()
ipv6_hop_ra()
ipv6_hop_ioam()
ipv6_hop_jumbo()
ipv6_hop_calipso()
ipv6_dest_hao()

Besides, ip_forward() and ip6_forward(), which are used for IPv4/IPv6
forwarding, are also handled. And following new drop reasons are added:

/* host unreachable, corresponding to IPSTATS_MIB_INADDRERRORS */
SKB_DROP_REASON_IP_INADDRERRORS
/* network unreachable, corresponding to IPSTATS_MIB_INADDRERRORS */
SKB_DROP_REASON_IP_INNOROUTES
/* packet size is too big, corresponding to
* IPSTATS_MIB_INTOOBIGERRORS
*/
SKB_DROP_REASON_PKT_TOO_BIG

In order to simply the definition and assignment for
'enum skb_drop_reason', some helper functions are introduced in the 1th
patch. I'm not such if this is necessary, but it makes the code simpler.
For example, we can replace the code:

if (reason == SKB_DROP_REASON_NOT_SPECIFIED)
reason = SKB_DROP_REASON_IP_INHDR;

with:

SKB_DR_OR(reason, IP_INHDR);

In the 6th patch, the statistics for skb in ipv6_hop_jum() is removed,
as I think it is redundant. There are two call chains for
ipv6_hop_jumbo(). The first one is:

ipv6_destopt_rcv() -> ip6_parse_tlv() -> ipv6_hop_jumbo()

On this call chain, the drop statistics will be done in
ipv6_destopt_rcv() with 'IPSTATS_MIB_INHDRERRORS' if ipv6_hop_jumbo()
returns false.

The second call chain is:

ip6_rcv_core() -> ipv6_parse_hopopts() -> ip6_parse_tlv()

And the drop statistics will also be done in ip6_rcv_core() with
'IPSTATS_MIB_INHDRERRORS' if ipv6_hop_jumbo() returns false.

Therefore, the statistics in ipv6_hop_jumbo() is redundant, which
means the drop is counted twice. The statistics in ipv6_hop_jumbo()
is almost the same as the outside, except the
'IPSTATS_MIB_INTRUNCATEDPKTS', which seems that we have to ignore it.

======================================================================

Here is a basic test for IPv6 forwarding packet drop that monitored by
'dropwatch' tool:

drop at: ip6_forward+0x81a/0xb70 (0xffffffff86c73f8a)
origin: software
input port ifindex: 7
timestamp: Wed Apr 13 11:51:06 2022 130010176 nsec
protocol: 0x86dd
length: 94
original length: 94
drop reason: IP_INADDRERRORS

The origin cause of this case is that IPv6 doesn't allow to forward the
packet with LOCAL-LINK saddr, and results the 'IP_INADDRERRORS' drop
reason.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+113 -42
+9 -2
include/linux/icmpv6.h
··· 79 79 extern int icmpv6_err_convert(u8 type, u8 code, 80 80 int *err); 81 81 extern void icmpv6_cleanup(void); 82 - extern void icmpv6_param_prob(struct sk_buff *skb, 83 - u8 code, int pos); 82 + extern void icmpv6_param_prob_reason(struct sk_buff *skb, 83 + u8 code, int pos, 84 + enum skb_drop_reason reason); 84 85 85 86 struct flowi6; 86 87 struct in6_addr; ··· 91 90 const struct in6_addr *saddr, 92 91 const struct in6_addr *daddr, 93 92 int oif); 93 + 94 + static inline void icmpv6_param_prob(struct sk_buff *skb, u8 code, int pos) 95 + { 96 + icmpv6_param_prob_reason(skb, code, pos, 97 + SKB_DROP_REASON_NOT_SPECIFIED); 98 + } 94 99 95 100 static inline bool icmpv6_is_err(int type) 96 101 {
+21
include/linux/skbuff.h
··· 447 447 * 2211, such as a broadcasts 448 448 * ICMP_TIMESTAMP 449 449 */ 450 + SKB_DROP_REASON_IP_INADDRERRORS, /* host unreachable, corresponding 451 + * to IPSTATS_MIB_INADDRERRORS 452 + */ 453 + SKB_DROP_REASON_IP_INNOROUTES, /* network unreachable, corresponding 454 + * to IPSTATS_MIB_INADDRERRORS 455 + */ 456 + SKB_DROP_REASON_PKT_TOO_BIG, /* packet size is too big (maybe exceed 457 + * the MTU) 458 + */ 450 459 SKB_DROP_REASON_MAX, 451 460 }; 461 + 462 + #define SKB_DR_INIT(name, reason) \ 463 + enum skb_drop_reason name = SKB_DROP_REASON_##reason 464 + #define SKB_DR(name) \ 465 + SKB_DR_INIT(name, NOT_SPECIFIED) 466 + #define SKB_DR_SET(name, reason) \ 467 + (name = SKB_DROP_REASON_##reason) 468 + #define SKB_DR_OR(name, reason) \ 469 + do { \ 470 + if (name == SKB_DROP_REASON_NOT_SPECIFIED) \ 471 + SKB_DR_SET(name, reason); \ 472 + } while (0) 452 473 453 474 /* To allow 64K frame to be packed as single skb without frag_list we 454 475 * require 64K/PAGE_SIZE pages plus 1 additional page to allow for
+3
include/trace/events/skb.h
··· 63 63 EM(SKB_DROP_REASON_TAP_TXFILTER, TAP_TXFILTER) \ 64 64 EM(SKB_DROP_REASON_ICMP_CSUM, ICMP_CSUM) \ 65 65 EM(SKB_DROP_REASON_INVALID_PROTO, INVALID_PROTO) \ 66 + EM(SKB_DROP_REASON_IP_INADDRERRORS, IP_INADDRERRORS) \ 67 + EM(SKB_DROP_REASON_IP_INNOROUTES, IP_INNOROUTES) \ 68 + EM(SKB_DROP_REASON_PKT_TOO_BIG, PKT_TOO_BIG) \ 66 69 EMe(SKB_DROP_REASON_MAX, MAX) 67 70 68 71 #undef EM
+10 -3
net/ipv4/ip_forward.c
··· 90 90 struct rtable *rt; /* Route we use */ 91 91 struct ip_options *opt = &(IPCB(skb)->opt); 92 92 struct net *net; 93 + SKB_DR(reason); 93 94 94 95 /* that should never happen */ 95 96 if (skb->pkt_type != PACKET_HOST) ··· 102 101 if (skb_warn_if_lro(skb)) 103 102 goto drop; 104 103 105 - if (!xfrm4_policy_check(NULL, XFRM_POLICY_FWD, skb)) 104 + if (!xfrm4_policy_check(NULL, XFRM_POLICY_FWD, skb)) { 105 + SKB_DR_SET(reason, XFRM_POLICY); 106 106 goto drop; 107 + } 107 108 108 109 if (IPCB(skb)->opt.router_alert && ip_call_ra_chain(skb)) 109 110 return NET_RX_SUCCESS; ··· 121 118 if (ip_hdr(skb)->ttl <= 1) 122 119 goto too_many_hops; 123 120 124 - if (!xfrm4_route_forward(skb)) 121 + if (!xfrm4_route_forward(skb)) { 122 + SKB_DR_SET(reason, XFRM_POLICY); 125 123 goto drop; 124 + } 126 125 127 126 rt = skb_rtable(skb); 128 127 ··· 137 132 IP_INC_STATS(net, IPSTATS_MIB_FRAGFAILS); 138 133 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, 139 134 htonl(mtu)); 135 + SKB_DR_SET(reason, PKT_TOO_BIG); 140 136 goto drop; 141 137 } 142 138 ··· 175 169 /* Tell the sender its packet died... */ 176 170 __IP_INC_STATS(net, IPSTATS_MIB_INHDRERRORS); 177 171 icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, 0); 172 + SKB_DR_SET(reason, IP_INHDR); 178 173 drop: 179 - kfree_skb(skb); 174 + kfree_skb_reason(skb, reason); 180 175 return NET_RX_DROP; 181 176 }
+5 -1
net/ipv4/route.c
··· 945 945 struct inet_peer *peer; 946 946 unsigned long now; 947 947 struct net *net; 948 + SKB_DR(reason); 948 949 bool send; 949 950 int code; 950 951 ··· 965 964 if (!IN_DEV_FORWARD(in_dev)) { 966 965 switch (rt->dst.error) { 967 966 case EHOSTUNREACH: 967 + SKB_DR_SET(reason, IP_INADDRERRORS); 968 968 __IP_INC_STATS(net, IPSTATS_MIB_INADDRERRORS); 969 969 break; 970 970 971 971 case ENETUNREACH: 972 + SKB_DR_SET(reason, IP_INNOROUTES); 972 973 __IP_INC_STATS(net, IPSTATS_MIB_INNOROUTES); 973 974 break; 974 975 } ··· 986 983 break; 987 984 case ENETUNREACH: 988 985 code = ICMP_NET_UNREACH; 986 + SKB_DR_SET(reason, IP_INNOROUTES); 989 987 __IP_INC_STATS(net, IPSTATS_MIB_INNOROUTES); 990 988 break; 991 989 case EACCES: ··· 1013 1009 if (send) 1014 1010 icmp_send(skb, ICMP_DEST_UNREACH, code, 0); 1015 1011 1016 - out: kfree_skb(skb); 1012 + out: kfree_skb_reason(skb, reason); 1017 1013 return 0; 1018 1014 } 1019 1015
+22 -17
net/ipv6/exthdrs.c
··· 90 90 break; 91 91 fallthrough; 92 92 case 2: /* send ICMP PARM PROB regardless and drop packet */ 93 - icmpv6_param_prob(skb, ICMPV6_UNK_OPTION, optoff); 93 + icmpv6_param_prob_reason(skb, ICMPV6_UNK_OPTION, optoff, 94 + SKB_DROP_REASON_UNHANDLED_PROTO); 94 95 return false; 95 96 } 96 97 97 98 drop: 98 - kfree_skb(skb); 99 + kfree_skb_reason(skb, SKB_DROP_REASON_UNHANDLED_PROTO); 99 100 return false; 100 101 } 101 102 ··· 219 218 if (len == 0) 220 219 return true; 221 220 bad: 222 - kfree_skb(skb); 221 + kfree_skb_reason(skb, SKB_DROP_REASON_IP_INHDR); 223 222 return false; 224 223 } 225 224 ··· 233 232 struct ipv6_destopt_hao *hao; 234 233 struct inet6_skb_parm *opt = IP6CB(skb); 235 234 struct ipv6hdr *ipv6h = ipv6_hdr(skb); 235 + SKB_DR(reason); 236 236 int ret; 237 237 238 238 if (opt->dsthao) { ··· 248 246 if (hao->length != 16) { 249 247 net_dbg_ratelimited("hao invalid option length = %d\n", 250 248 hao->length); 249 + SKB_DR_SET(reason, IP_INHDR); 251 250 goto discard; 252 251 } 253 252 254 253 if (!(ipv6_addr_type(&hao->addr) & IPV6_ADDR_UNICAST)) { 255 254 net_dbg_ratelimited("hao is not an unicast addr: %pI6\n", 256 255 &hao->addr); 256 + SKB_DR_SET(reason, INVALID_PROTO); 257 257 goto discard; 258 258 } 259 259 260 260 ret = xfrm6_input_addr(skb, (xfrm_address_t *)&ipv6h->daddr, 261 261 (xfrm_address_t *)&hao->addr, IPPROTO_DSTOPTS); 262 - if (unlikely(ret < 0)) 262 + if (unlikely(ret < 0)) { 263 + SKB_DR_SET(reason, XFRM_POLICY); 263 264 goto discard; 265 + } 264 266 265 267 if (skb_cloned(skb)) { 266 268 if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) ··· 287 281 return true; 288 282 289 283 discard: 290 - kfree_skb(skb); 284 + kfree_skb_reason(skb, reason); 291 285 return false; 292 286 } 293 287 #endif ··· 937 931 } 938 932 net_dbg_ratelimited("ipv6_hop_ra: wrong RA length %d\n", 939 933 nh[optoff + 1]); 940 - kfree_skb(skb); 934 + kfree_skb_reason(skb, SKB_DROP_REASON_IP_INHDR); 941 935 return false; 942 936 } 943 937 ··· 991 985 return true; 992 986 993 987 drop: 994 - kfree_skb(skb); 988 + kfree_skb_reason(skb, SKB_DROP_REASON_IP_INHDR); 995 989 return false; 996 990 } 997 991 ··· 1000 994 static bool ipv6_hop_jumbo(struct sk_buff *skb, int optoff) 1001 995 { 1002 996 const unsigned char *nh = skb_network_header(skb); 1003 - struct inet6_dev *idev = __in6_dev_get_safely(skb->dev); 1004 - struct net *net = ipv6_skb_net(skb); 997 + SKB_DR(reason); 1005 998 u32 pkt_len; 1006 999 1007 1000 if (nh[optoff + 1] != 4 || (optoff & 3) != 2) { 1008 1001 net_dbg_ratelimited("ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n", 1009 1002 nh[optoff+1]); 1010 - __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); 1003 + SKB_DR_SET(reason, IP_INHDR); 1011 1004 goto drop; 1012 1005 } 1013 1006 1014 1007 pkt_len = ntohl(*(__be32 *)(nh + optoff + 2)); 1015 1008 if (pkt_len <= IPV6_MAXPLEN) { 1016 - __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); 1017 - icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff+2); 1009 + icmpv6_param_prob_reason(skb, ICMPV6_HDR_FIELD, optoff + 2, 1010 + SKB_DROP_REASON_IP_INHDR); 1018 1011 return false; 1019 1012 } 1020 1013 if (ipv6_hdr(skb)->payload_len) { 1021 - __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); 1022 - icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff); 1014 + icmpv6_param_prob_reason(skb, ICMPV6_HDR_FIELD, optoff, 1015 + SKB_DROP_REASON_IP_INHDR); 1023 1016 return false; 1024 1017 } 1025 1018 1026 1019 if (pkt_len > skb->len - sizeof(struct ipv6hdr)) { 1027 - __IP6_INC_STATS(net, idev, IPSTATS_MIB_INTRUNCATEDPKTS); 1020 + SKB_DR_SET(reason, PKT_TOO_SMALL); 1028 1021 goto drop; 1029 1022 } 1030 1023 ··· 1034 1029 return true; 1035 1030 1036 1031 drop: 1037 - kfree_skb(skb); 1032 + kfree_skb_reason(skb, reason); 1038 1033 return false; 1039 1034 } 1040 1035 ··· 1056 1051 return true; 1057 1052 1058 1053 drop: 1059 - kfree_skb(skb); 1054 + kfree_skb_reason(skb, SKB_DROP_REASON_IP_INHDR); 1060 1055 return false; 1061 1056 } 1062 1057
+4 -3
net/ipv6/icmp.c
··· 629 629 } 630 630 EXPORT_SYMBOL(icmp6_send); 631 631 632 - /* Slightly more convenient version of icmp6_send. 632 + /* Slightly more convenient version of icmp6_send with drop reasons. 633 633 */ 634 - void icmpv6_param_prob(struct sk_buff *skb, u8 code, int pos) 634 + void icmpv6_param_prob_reason(struct sk_buff *skb, u8 code, int pos, 635 + enum skb_drop_reason reason) 635 636 { 636 637 icmp6_send(skb, ICMPV6_PARAMPROB, code, pos, NULL, IP6CB(skb)); 637 - kfree_skb(skb); 638 + kfree_skb_reason(skb, reason); 638 639 } 639 640 640 641 /* Generate icmpv6 with type/code ICMPV6_DEST_UNREACH/ICMPV6_ADDR_UNREACH
+28 -12
net/ipv6/ip6_input.c
··· 145 145 static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev, 146 146 struct net *net) 147 147 { 148 + enum skb_drop_reason reason; 148 149 const struct ipv6hdr *hdr; 149 150 u32 pkt_len; 150 151 struct inet6_dev *idev; 151 152 152 153 if (skb->pkt_type == PACKET_OTHERHOST) { 153 154 dev_core_stats_rx_otherhost_dropped_inc(skb->dev); 154 - kfree_skb(skb); 155 + kfree_skb_reason(skb, SKB_DROP_REASON_OTHERHOST); 155 156 return NULL; 156 157 } 157 158 ··· 162 161 163 162 __IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_IN, skb->len); 164 163 164 + SKB_DR_SET(reason, NOT_SPECIFIED); 165 165 if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL || 166 166 !idev || unlikely(idev->cnf.disable_ipv6)) { 167 167 __IP6_INC_STATS(net, idev, IPSTATS_MIB_INDISCARDS); 168 + if (unlikely(idev->cnf.disable_ipv6)) 169 + SKB_DR_SET(reason, IPV6DISABLED); 168 170 goto drop; 169 171 } 170 172 ··· 191 187 192 188 hdr = ipv6_hdr(skb); 193 189 194 - if (hdr->version != 6) 190 + if (hdr->version != 6) { 191 + SKB_DR_SET(reason, UNHANDLED_PROTO); 195 192 goto err; 193 + } 196 194 197 195 __IP6_ADD_STATS(net, idev, 198 196 IPSTATS_MIB_NOECTPKTS + ··· 232 226 if (!ipv6_addr_is_multicast(&hdr->daddr) && 233 227 (skb->pkt_type == PACKET_BROADCAST || 234 228 skb->pkt_type == PACKET_MULTICAST) && 235 - idev->cnf.drop_unicast_in_l2_multicast) 229 + idev->cnf.drop_unicast_in_l2_multicast) { 230 + SKB_DR_SET(reason, UNICAST_IN_L2_MULTICAST); 236 231 goto err; 232 + } 237 233 238 234 /* RFC4291 2.7 239 235 * Nodes must not originate a packet to a multicast address whose scope ··· 264 256 if (pkt_len + sizeof(struct ipv6hdr) > skb->len) { 265 257 __IP6_INC_STATS(net, 266 258 idev, IPSTATS_MIB_INTRUNCATEDPKTS); 259 + SKB_DR_SET(reason, PKT_TOO_SMALL); 267 260 goto drop; 268 261 } 269 - if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr))) { 270 - __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); 271 - goto drop; 272 - } 262 + if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr))) 263 + goto err; 273 264 hdr = ipv6_hdr(skb); 274 265 } 275 266 ··· 289 282 return skb; 290 283 err: 291 284 __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); 285 + SKB_DR_OR(reason, IP_INHDR); 292 286 drop: 293 287 rcu_read_unlock(); 294 - kfree_skb(skb); 288 + kfree_skb_reason(skb, reason); 295 289 return NULL; 296 290 } 297 291 ··· 362 354 const struct inet6_protocol *ipprot; 363 355 struct inet6_dev *idev; 364 356 unsigned int nhoff; 357 + SKB_DR(reason); 365 358 bool raw; 366 359 367 360 /* ··· 422 413 if (ipv6_addr_is_multicast(&hdr->daddr) && 423 414 !ipv6_chk_mcast_addr(dev, &hdr->daddr, 424 415 &hdr->saddr) && 425 - !ipv6_is_mld(skb, nexthdr, skb_network_header_len(skb))) 416 + !ipv6_is_mld(skb, nexthdr, skb_network_header_len(skb))) { 417 + SKB_DR_SET(reason, IP_INADDRERRORS); 426 418 goto discard; 419 + } 427 420 } 428 421 if (!(ipprot->flags & INET6_PROTO_NOPOLICY) && 429 - !xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) 422 + !xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) { 423 + SKB_DR_SET(reason, XFRM_POLICY); 430 424 goto discard; 425 + } 431 426 432 427 ret = INDIRECT_CALL_2(ipprot->handler, tcp_v6_rcv, udpv6_rcv, 433 428 skb); ··· 457 444 IPSTATS_MIB_INUNKNOWNPROTOS); 458 445 icmpv6_send(skb, ICMPV6_PARAMPROB, 459 446 ICMPV6_UNK_NEXTHDR, nhoff); 447 + SKB_DR_SET(reason, IP_NOPROTO); 448 + } else { 449 + SKB_DR_SET(reason, XFRM_POLICY); 460 450 } 461 - kfree_skb(skb); 451 + kfree_skb_reason(skb, reason); 462 452 } else { 463 453 __IP6_INC_STATS(net, idev, IPSTATS_MIB_INDELIVERS); 464 454 consume_skb(skb); ··· 471 455 472 456 discard: 473 457 __IP6_INC_STATS(net, idev, IPSTATS_MIB_INDISCARDS); 474 - kfree_skb(skb); 458 + kfree_skb_reason(skb, reason); 475 459 } 476 460 477 461 static int ip6_input_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
+6 -3
net/ipv6/ip6_output.c
··· 469 469 struct inet6_skb_parm *opt = IP6CB(skb); 470 470 struct net *net = dev_net(dst->dev); 471 471 struct inet6_dev *idev; 472 + SKB_DR(reason); 472 473 u32 mtu; 473 474 474 475 idev = __in6_dev_get_safely(dev_get_by_index_rcu(net, IP6CB(skb)->iif)); ··· 519 518 icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, 0); 520 519 __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); 521 520 522 - kfree_skb(skb); 521 + kfree_skb_reason(skb, SKB_DROP_REASON_IP_INHDR); 523 522 return -ETIMEDOUT; 524 523 } 525 524 ··· 538 537 539 538 if (!xfrm6_route_forward(skb)) { 540 539 __IP6_INC_STATS(net, idev, IPSTATS_MIB_INDISCARDS); 540 + SKB_DR_SET(reason, XFRM_POLICY); 541 541 goto drop; 542 542 } 543 543 dst = skb_dst(skb); ··· 598 596 __IP6_INC_STATS(net, idev, IPSTATS_MIB_INTOOBIGERRORS); 599 597 __IP6_INC_STATS(net, ip6_dst_idev(dst), 600 598 IPSTATS_MIB_FRAGFAILS); 601 - kfree_skb(skb); 599 + kfree_skb_reason(skb, SKB_DROP_REASON_PKT_TOO_BIG); 602 600 return -EMSGSIZE; 603 601 } 604 602 ··· 620 618 621 619 error: 622 620 __IP6_INC_STATS(net, idev, IPSTATS_MIB_INADDRERRORS); 621 + SKB_DR_SET(reason, IP_INADDRERRORS); 623 622 drop: 624 - kfree_skb(skb); 623 + kfree_skb_reason(skb, reason); 625 624 return -EINVAL; 626 625 } 627 626
+5 -1
net/ipv6/route.c
··· 4482 4482 struct dst_entry *dst = skb_dst(skb); 4483 4483 struct net *net = dev_net(dst->dev); 4484 4484 struct inet6_dev *idev; 4485 + SKB_DR(reason); 4485 4486 int type; 4486 4487 4487 4488 if (netif_is_l3_master(skb->dev) || ··· 4495 4494 case IPSTATS_MIB_INNOROUTES: 4496 4495 type = ipv6_addr_type(&ipv6_hdr(skb)->daddr); 4497 4496 if (type == IPV6_ADDR_ANY) { 4497 + SKB_DR_SET(reason, IP_INADDRERRORS); 4498 4498 IP6_INC_STATS(net, idev, IPSTATS_MIB_INADDRERRORS); 4499 4499 break; 4500 4500 } 4501 + SKB_DR_SET(reason, IP_INNOROUTES); 4501 4502 fallthrough; 4502 4503 case IPSTATS_MIB_OUTNOROUTES: 4504 + SKB_DR_OR(reason, IP_OUTNOROUTES); 4503 4505 IP6_INC_STATS(net, idev, ipstats_mib_noroutes); 4504 4506 break; 4505 4507 } ··· 4512 4508 skb_dst_drop(skb); 4513 4509 4514 4510 icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0); 4515 - kfree_skb(skb); 4511 + kfree_skb_reason(skb, reason); 4516 4512 return 0; 4517 4513 } 4518 4514