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

Merge branch 'ipv6-more-drop-reason'

Eric Dumazet says:

====================
ipv6: more drop reason

Add more drop reasons to IPv6:

- IPV6_BAD_EXTHDR
- IPV6_NDISC_FRAG
- IPV6_NDISC_HOP_LIMIT
- IPV6_NDISC_BAD_CODE
====================

Link: https://lore.kernel.org/r/20230210184708.2172562-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+55 -21
+15 -4
include/linux/skbuff.h
··· 2631 2631 2632 2632 void *__pskb_pull_tail(struct sk_buff *skb, int delta); 2633 2633 2634 - static inline bool pskb_may_pull(struct sk_buff *skb, unsigned int len) 2634 + static inline enum skb_drop_reason 2635 + pskb_may_pull_reason(struct sk_buff *skb, unsigned int len) 2635 2636 { 2636 2637 if (likely(len <= skb_headlen(skb))) 2637 - return true; 2638 + return SKB_NOT_DROPPED_YET; 2639 + 2638 2640 if (unlikely(len > skb->len)) 2639 - return false; 2640 - return __pskb_pull_tail(skb, len - skb_headlen(skb)) != NULL; 2641 + return SKB_DROP_REASON_PKT_TOO_SMALL; 2642 + 2643 + if (unlikely(!__pskb_pull_tail(skb, len - skb_headlen(skb)))) 2644 + return SKB_DROP_REASON_NOMEM; 2645 + 2646 + return SKB_NOT_DROPPED_YET; 2647 + } 2648 + 2649 + static inline bool pskb_may_pull(struct sk_buff *skb, unsigned int len) 2650 + { 2651 + return pskb_may_pull_reason(skb, len) == SKB_NOT_DROPPED_YET; 2641 2652 } 2642 2653 2643 2654 static inline void *pskb_pull(struct sk_buff *skb, unsigned int len)
+12
include/net/dropreason.h
··· 72 72 FN(FRAG_REASM_TIMEOUT) \ 73 73 FN(FRAG_TOO_FAR) \ 74 74 FN(TCP_MINTTL) \ 75 + FN(IPV6_BAD_EXTHDR) \ 76 + FN(IPV6_NDISC_FRAG) \ 77 + FN(IPV6_NDISC_HOP_LIMIT) \ 78 + FN(IPV6_NDISC_BAD_CODE) \ 75 79 FNe(MAX) 76 80 77 81 /** ··· 322 318 * the threshold (IP_MINTTL or IPV6_MINHOPCOUNT). 323 319 */ 324 320 SKB_DROP_REASON_TCP_MINTTL, 321 + /** @SKB_DROP_REASON_IPV6_BAD_EXTHDR: Bad IPv6 extension header. */ 322 + SKB_DROP_REASON_IPV6_BAD_EXTHDR, 323 + /** @SKB_DROP_REASON_IPV6_NDISC_FRAG: invalid frag (suppress_frag_ndisc). */ 324 + SKB_DROP_REASON_IPV6_NDISC_FRAG, 325 + /** @SKB_DROP_REASON_IPV6_NDISC_HOP_LIMIT: invalid hop limit. */ 326 + SKB_DROP_REASON_IPV6_NDISC_HOP_LIMIT, 327 + /** @SKB_DROP_REASON_IPV6_NDISC_BAD_CODE: invalid NDISC icmp6 code. */ 328 + SKB_DROP_REASON_IPV6_NDISC_BAD_CODE, 325 329 /** 326 330 * @SKB_DROP_REASON_MAX: the maximum of drop reason, which shouldn't be 327 331 * used as a real 'reason'
+2 -1
include/net/ipv6.h
··· 436 436 atomic_dec(&fl->users); 437 437 } 438 438 439 - void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info); 439 + enum skb_drop_reason icmpv6_notify(struct sk_buff *skb, u8 type, 440 + u8 code, __be32 info); 440 441 441 442 void icmpv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6, 442 443 struct icmp6hdr *thdr, int len);
+1 -1
include/net/ndisc.h
··· 445 445 void ndisc_late_cleanup(void); 446 446 void ndisc_cleanup(void); 447 447 448 - int ndisc_rcv(struct sk_buff *skb); 448 + enum skb_drop_reason ndisc_rcv(struct sk_buff *skb); 449 449 450 450 struct sk_buff *ndisc_ns_create(struct net_device *dev, const struct in6_addr *solicit, 451 451 const struct in6_addr *saddr, u64 nonce);
+18 -9
net/ipv6/icmp.c
··· 813 813 local_bh_enable(); 814 814 } 815 815 816 - void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info) 816 + enum skb_drop_reason icmpv6_notify(struct sk_buff *skb, u8 type, 817 + u8 code, __be32 info) 817 818 { 818 819 struct inet6_skb_parm *opt = IP6CB(skb); 820 + struct net *net = dev_net(skb->dev); 819 821 const struct inet6_protocol *ipprot; 822 + enum skb_drop_reason reason; 820 823 int inner_offset; 821 824 __be16 frag_off; 822 825 u8 nexthdr; 823 - struct net *net = dev_net(skb->dev); 824 826 825 - if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) 827 + reason = pskb_may_pull_reason(skb, sizeof(struct ipv6hdr)); 828 + if (reason != SKB_NOT_DROPPED_YET) 826 829 goto out; 827 830 828 831 seg6_icmp_srh(skb, opt); ··· 835 832 /* now skip over extension headers */ 836 833 inner_offset = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), 837 834 &nexthdr, &frag_off); 838 - if (inner_offset < 0) 835 + if (inner_offset < 0) { 836 + SKB_DR_SET(reason, IPV6_BAD_EXTHDR); 839 837 goto out; 838 + } 840 839 } else { 841 840 inner_offset = sizeof(struct ipv6hdr); 842 841 } 843 842 844 843 /* Checkin header including 8 bytes of inner protocol header. */ 845 - if (!pskb_may_pull(skb, inner_offset+8)) 844 + reason = pskb_may_pull_reason(skb, inner_offset + 8); 845 + if (reason != SKB_NOT_DROPPED_YET) 846 846 goto out; 847 847 848 848 /* BUGGG_FUTURE: we should try to parse exthdrs in this packet. ··· 860 854 ipprot->err_handler(skb, opt, type, code, inner_offset, info); 861 855 862 856 raw6_icmp_error(skb, nexthdr, type, code, inner_offset, info); 863 - return; 857 + return SKB_CONSUMED; 864 858 865 859 out: 866 860 __ICMP6_INC_STATS(net, __in6_dev_get(skb->dev), ICMP6_MIB_INERRORS); 861 + return reason; 867 862 } 868 863 869 864 /* ··· 960 953 case ICMPV6_DEST_UNREACH: 961 954 case ICMPV6_TIME_EXCEED: 962 955 case ICMPV6_PARAMPROB: 963 - icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu); 956 + reason = icmpv6_notify(skb, type, hdr->icmp6_code, 957 + hdr->icmp6_mtu); 964 958 break; 965 959 966 960 case NDISC_ROUTER_SOLICITATION: ··· 969 961 case NDISC_NEIGHBOUR_SOLICITATION: 970 962 case NDISC_NEIGHBOUR_ADVERTISEMENT: 971 963 case NDISC_REDIRECT: 972 - ndisc_rcv(skb); 964 + reason = ndisc_rcv(skb); 973 965 break; 974 966 975 967 case ICMPV6_MGM_QUERY: ··· 1003 995 * must pass to upper level 1004 996 */ 1005 997 1006 - icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu); 998 + reason = icmpv6_notify(skb, type, hdr->icmp6_code, 999 + hdr->icmp6_mtu); 1007 1000 } 1008 1001 1009 1002 /* until the v6 path can be better sorted assume failure and
+7 -6
net/ipv6/ndisc.c
··· 1804 1804 return false; 1805 1805 } 1806 1806 1807 - int ndisc_rcv(struct sk_buff *skb) 1807 + enum skb_drop_reason ndisc_rcv(struct sk_buff *skb) 1808 1808 { 1809 1809 struct nd_msg *msg; 1810 + SKB_DR(reason); 1810 1811 1811 1812 if (ndisc_suppress_frag_ndisc(skb)) 1812 - return 0; 1813 + return SKB_DROP_REASON_IPV6_NDISC_FRAG; 1813 1814 1814 1815 if (skb_linearize(skb)) 1815 - return 0; 1816 + return SKB_DROP_REASON_NOMEM; 1816 1817 1817 1818 msg = (struct nd_msg *)skb_transport_header(skb); 1818 1819 ··· 1822 1821 if (ipv6_hdr(skb)->hop_limit != 255) { 1823 1822 ND_PRINTK(2, warn, "NDISC: invalid hop-limit: %d\n", 1824 1823 ipv6_hdr(skb)->hop_limit); 1825 - return 0; 1824 + return SKB_DROP_REASON_IPV6_NDISC_HOP_LIMIT; 1826 1825 } 1827 1826 1828 1827 if (msg->icmph.icmp6_code != 0) { 1829 1828 ND_PRINTK(2, warn, "NDISC: invalid ICMPv6 code: %d\n", 1830 1829 msg->icmph.icmp6_code); 1831 - return 0; 1830 + return SKB_DROP_REASON_IPV6_NDISC_BAD_CODE; 1832 1831 } 1833 1832 1834 1833 switch (msg->icmph.icmp6_type) { ··· 1854 1853 break; 1855 1854 } 1856 1855 1857 - return 0; 1856 + return reason; 1858 1857 } 1859 1858 1860 1859 static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)