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

Merge branch 'net-ip-add-drop-reasons-to-input-route'

Menglong Dong says:

====================
net: ip: add drop reasons to input route

In this series, we mainly add some skb drop reasons to the input path of
ip routing, and we make the following functions return drop reasons:

fib_validate_source()
ip_route_input_mc()
ip_mc_validate_source()
ip_route_input_slow()
ip_route_input_rcu()
ip_route_input_noref()
ip_route_input()
ip_mkroute_input()
__mkroute_input()
ip_route_use_hint()

And following new skb drop reasons are added:

SKB_DROP_REASON_IP_LOCAL_SOURCE
SKB_DROP_REASON_IP_INVALID_SOURCE
SKB_DROP_REASON_IP_LOCALNET
SKB_DROP_REASON_IP_INVALID_DEST

Changes since v4:
- in the 6th patch: remove the unneeded "else" in ip_expire()
- in the 8th patch: delete the unneeded comment in __mkroute_input()
- in the 9th patch: replace "return 0" with "return SKB_NOT_DROPPED_YET"
in ip_route_use_hint()

Changes since v3:
- don't refactor fib_validate_source/__fib_validate_source, and introduce
a wrapper for fib_validate_source() instead in the 1st patch.
- some small adjustment in the 4-7 patches

Changes since v2:
- refactor fib_validate_source and __fib_validate_source to make
fib_validate_source return drop reasons
- add the 9th and 10th patches to make this series cover the input route
code path

Changes since v1:
- make ip_route_input_noref/ip_route_input_rcu/ip_route_input_slow return
drop reasons, instead of passing a local variable to their function
arguments.
====================

Link: https://patch.msgid.link/20241107125601.1076814-1-dongml2@chinatelecom.cn
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

+224 -140
+26
include/net/dropreason-core.h
··· 76 76 FN(INVALID_PROTO) \ 77 77 FN(IP_INADDRERRORS) \ 78 78 FN(IP_INNOROUTES) \ 79 + FN(IP_LOCAL_SOURCE) \ 80 + FN(IP_INVALID_SOURCE) \ 81 + FN(IP_LOCALNET) \ 82 + FN(IP_INVALID_DEST) \ 79 83 FN(PKT_TOO_BIG) \ 80 84 FN(DUP_FRAG) \ 81 85 FN(FRAG_REASM_TIMEOUT) \ ··· 104 100 FN(IP_TUNNEL_ECN) \ 105 101 FN(TUNNEL_TXINFO) \ 106 102 FN(LOCAL_MAC) \ 103 + FN(ARP_PVLAN_DISABLE) \ 107 104 FNe(MAX) 108 105 109 106 /** ··· 378 373 * IPSTATS_MIB_INADDRERRORS 379 374 */ 380 375 SKB_DROP_REASON_IP_INNOROUTES, 376 + /** @SKB_DROP_REASON_IP_LOCAL_SOURCE: the source ip is local */ 377 + SKB_DROP_REASON_IP_LOCAL_SOURCE, 378 + /** 379 + * @SKB_DROP_REASON_IP_INVALID_SOURCE: the source ip is invalid: 380 + * 1) source ip is multicast or limited broadcast 381 + * 2) source ip is zero and not IGMP 382 + */ 383 + SKB_DROP_REASON_IP_INVALID_SOURCE, 384 + /** @SKB_DROP_REASON_IP_LOCALNET: source or dest ip is local net */ 385 + SKB_DROP_REASON_IP_LOCALNET, 386 + /** 387 + * @SKB_DROP_REASON_IP_INVALID_DEST: the dest ip is invalid: 388 + * 1) dest ip is 0 389 + */ 390 + SKB_DROP_REASON_IP_INVALID_DEST, 381 391 /** 382 392 * @SKB_DROP_REASON_PKT_TOO_BIG: packet size is too big (maybe exceed the 383 393 * MTU) ··· 478 458 * the MAC address of the local netdev. 479 459 */ 480 460 SKB_DROP_REASON_LOCAL_MAC, 461 + /** 462 + * @SKB_DROP_REASON_ARP_PVLAN_DISABLE: packet which is not IP is 463 + * forwarded to the in_dev, and the proxy_arp_pvlan is not 464 + * enabled. 465 + */ 466 + SKB_DROP_REASON_ARP_PVLAN_DISABLE, 481 467 /** 482 468 * @SKB_DROP_REASON_MAX: the maximum of core drop reasons, which 483 469 * shouldn't be used as a real 'reason' - only for tracing code gen
+12
include/net/ip_fib.h
··· 452 452 dscp_t dscp, int oif, struct net_device *dev, 453 453 struct in_device *idev, u32 *itag); 454 454 455 + static inline enum skb_drop_reason 456 + fib_validate_source_reason(struct sk_buff *skb, __be32 src, __be32 dst, 457 + dscp_t dscp, int oif, struct net_device *dev, 458 + struct in_device *idev, u32 *itag) 459 + { 460 + int err = fib_validate_source(skb, src, dst, dscp, oif, dev, idev, 461 + itag); 462 + if (err < 0) 463 + return -err; 464 + return SKB_NOT_DROPPED_YET; 465 + } 466 + 455 467 #ifdef CONFIG_IP_ROUTE_CLASSID 456 468 static inline int fib_num_tclassid_users(struct net *net) 457 469 {
+18 -14
include/net/route.h
··· 199 199 return ip_route_output_key(net, fl4); 200 200 } 201 201 202 - int ip_mc_validate_source(struct sk_buff *skb, __be32 daddr, __be32 saddr, 203 - dscp_t dscp, struct net_device *dev, 204 - struct in_device *in_dev, u32 *itag); 205 - int ip_route_input_noref(struct sk_buff *skb, __be32 daddr, __be32 saddr, 206 - dscp_t dscp, struct net_device *dev); 207 - int ip_route_use_hint(struct sk_buff *skb, __be32 daddr, __be32 saddr, 202 + enum skb_drop_reason 203 + ip_mc_validate_source(struct sk_buff *skb, __be32 daddr, __be32 saddr, 208 204 dscp_t dscp, struct net_device *dev, 209 - const struct sk_buff *hint); 205 + struct in_device *in_dev, u32 *itag); 206 + enum skb_drop_reason 207 + ip_route_input_noref(struct sk_buff *skb, __be32 daddr, __be32 saddr, 208 + dscp_t dscp, struct net_device *dev); 209 + enum skb_drop_reason 210 + ip_route_use_hint(struct sk_buff *skb, __be32 daddr, __be32 saddr, 211 + dscp_t dscp, struct net_device *dev, 212 + const struct sk_buff *hint); 210 213 211 - static inline int ip_route_input(struct sk_buff *skb, __be32 dst, __be32 src, 212 - dscp_t dscp, struct net_device *devin) 214 + static inline enum skb_drop_reason 215 + ip_route_input(struct sk_buff *skb, __be32 dst, __be32 src, dscp_t dscp, 216 + struct net_device *devin) 213 217 { 214 - int err; 218 + enum skb_drop_reason reason; 215 219 216 220 rcu_read_lock(); 217 - err = ip_route_input_noref(skb, dst, src, dscp, devin); 218 - if (!err) { 221 + reason = ip_route_input_noref(skb, dst, src, dscp, devin); 222 + if (!reason) { 219 223 skb_dst_force(skb); 220 224 if (!skb_dst(skb)) 221 - err = -EINVAL; 225 + reason = SKB_DROP_REASON_NOT_SPECIFIED; 222 226 } 223 227 rcu_read_unlock(); 224 228 225 - return err; 229 + return reason; 226 230 } 227 231 228 232 void ipv4_update_pmtu(struct sk_buff *skb, struct net *net, u32 mtu, int oif,
+6 -5
net/bridge/br_netfilter_hooks.c
··· 373 373 struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb); 374 374 struct net_device *dev = skb->dev, *br_indev; 375 375 const struct iphdr *iph = ip_hdr(skb); 376 + enum skb_drop_reason reason; 376 377 struct rtable *rt; 377 - int err; 378 378 379 379 br_indev = nf_bridge_get_physindev(skb, net); 380 380 if (!br_indev) { ··· 390 390 } 391 391 nf_bridge->in_prerouting = 0; 392 392 if (br_nf_ipv4_daddr_was_changed(skb, nf_bridge)) { 393 - err = ip_route_input(skb, iph->daddr, iph->saddr, 394 - ip4h_dscp(iph), dev); 395 - if (err) { 393 + reason = ip_route_input(skb, iph->daddr, iph->saddr, 394 + ip4h_dscp(iph), dev); 395 + if (reason) { 396 396 struct in_device *in_dev = __in_dev_get_rcu(dev); 397 397 398 398 /* If err equals -EHOSTUNREACH the error is due to a ··· 402 402 * martian destinations: loopback destinations and destination 403 403 * 0.0.0.0. In both cases the packet will be dropped because the 404 404 * destination is the loopback device and not the bridge. */ 405 - if (err != -EHOSTUNREACH || !in_dev || IN_DEV_FORWARD(in_dev)) 405 + if (reason != SKB_DROP_REASON_IP_INADDRERRORS || !in_dev || 406 + IN_DEV_FORWARD(in_dev)) 406 407 goto free_skb; 407 408 408 409 rt = ip_route_output(net, iph->daddr, 0,
+4 -2
net/core/lwt_bpf.c
··· 88 88 89 89 static int bpf_lwt_input_reroute(struct sk_buff *skb) 90 90 { 91 + enum skb_drop_reason reason; 91 92 int err = -EINVAL; 92 93 93 94 if (skb->protocol == htons(ETH_P_IP)) { ··· 97 96 98 97 dev_hold(dev); 99 98 skb_dst_drop(skb); 100 - err = ip_route_input_noref(skb, iph->daddr, iph->saddr, 101 - ip4h_dscp(iph), dev); 99 + reason = ip_route_input_noref(skb, iph->daddr, iph->saddr, 100 + ip4h_dscp(iph), dev); 101 + err = reason ? -EINVAL : 0; 102 102 dev_put(dev); 103 103 } else if (skb->protocol == htons(ETH_P_IPV6)) { 104 104 skb_dst_drop(skb);
+12 -5
net/ipv4/fib_frontend.c
··· 346 346 int rpf, struct in_device *idev, u32 *itag) 347 347 { 348 348 struct net *net = dev_net(dev); 349 + enum skb_drop_reason reason; 349 350 struct flow_keys flkeys; 350 351 int ret, no_addr; 351 352 struct fib_result res; ··· 378 377 379 378 if (fib_lookup(net, &fl4, &res, 0)) 380 379 goto last_resort; 381 - if (res.type != RTN_UNICAST && 382 - (res.type != RTN_LOCAL || !IN_DEV_ACCEPT_LOCAL(idev))) 383 - goto e_inval; 380 + if (res.type != RTN_UNICAST) { 381 + if (res.type != RTN_LOCAL) { 382 + reason = SKB_DROP_REASON_IP_INVALID_SOURCE; 383 + goto e_inval; 384 + } else if (!IN_DEV_ACCEPT_LOCAL(idev)) { 385 + reason = SKB_DROP_REASON_IP_LOCAL_SOURCE; 386 + goto e_inval; 387 + } 388 + } 384 389 fib_combine_itag(itag, &res); 385 390 386 391 dev_match = fib_info_nh_uses_dev(res.fi, dev); ··· 419 412 return 0; 420 413 421 414 e_inval: 422 - return -EINVAL; 415 + return -reason; 423 416 e_rpf: 424 - return -EXDEV; 417 + return -SKB_DROP_REASON_IP_RPFILTER; 425 418 } 426 419 427 420 /* Ignore rp_filter for packets protected by IPsec. */
+1 -1
net/ipv4/icmp.c
··· 545 545 orefdst = skb_in->_skb_refdst; /* save old refdst */ 546 546 skb_dst_set(skb_in, NULL); 547 547 err = ip_route_input(skb_in, fl4_dec.daddr, fl4_dec.saddr, 548 - dscp, rt2->dst.dev); 548 + dscp, rt2->dst.dev) ? -EINVAL : 0; 549 549 550 550 dst_release(&rt2->dst); 551 551 rt2 = skb_rtable(skb_in);
+6 -5
net/ipv4/ip_fragment.c
··· 132 132 */ 133 133 static void ip_expire(struct timer_list *t) 134 134 { 135 + enum skb_drop_reason reason = SKB_DROP_REASON_FRAG_REASM_TIMEOUT; 135 136 struct inet_frag_queue *frag = from_timer(frag, t, timer); 136 137 const struct iphdr *iph; 137 138 struct sk_buff *head = NULL; 138 139 struct net *net; 139 140 struct ipq *qp; 140 - int err; 141 141 142 142 qp = container_of(frag, struct ipq, q); 143 143 net = qp->q.fqdir->net; ··· 175 175 176 176 /* skb has no dst, perform route lookup again */ 177 177 iph = ip_hdr(head); 178 - err = ip_route_input_noref(head, iph->daddr, iph->saddr, ip4h_dscp(iph), 179 - head->dev); 180 - if (err) 178 + reason = ip_route_input_noref(head, iph->daddr, iph->saddr, 179 + ip4h_dscp(iph), head->dev); 180 + if (reason) 181 181 goto out; 182 182 183 183 /* Only an end host needs to send an ICMP 184 184 * "Fragment Reassembly Timeout" message, per RFC792. 185 185 */ 186 + reason = SKB_DROP_REASON_FRAG_REASM_TIMEOUT; 186 187 if (frag_expire_skip_icmp(qp->q.key.v4.user) && 187 188 (skb_rtable(head)->rt_type != RTN_LOCAL)) 188 189 goto out; ··· 196 195 spin_unlock(&qp->q.lock); 197 196 out_rcu_unlock: 198 197 rcu_read_unlock(); 199 - kfree_skb_reason(head, SKB_DROP_REASON_FRAG_REASM_TIMEOUT); 198 + kfree_skb_reason(head, reason); 200 199 ipq_put(qp); 201 200 } 202 201
+9 -11
net/ipv4/ip_input.c
··· 322 322 int err, drop_reason; 323 323 struct rtable *rt; 324 324 325 - drop_reason = SKB_DROP_REASON_NOT_SPECIFIED; 326 - 327 325 if (ip_can_use_hint(skb, iph, hint)) { 328 - err = ip_route_use_hint(skb, iph->daddr, iph->saddr, 329 - ip4h_dscp(iph), dev, hint); 330 - if (unlikely(err)) 326 + drop_reason = ip_route_use_hint(skb, iph->daddr, iph->saddr, 327 + ip4h_dscp(iph), dev, hint); 328 + if (unlikely(drop_reason)) 331 329 goto drop_error; 332 330 } 333 331 332 + drop_reason = SKB_DROP_REASON_NOT_SPECIFIED; 334 333 if (READ_ONCE(net->ipv4.sysctl_ip_early_demux) && 335 334 !skb_dst(skb) && 336 335 !skb->sk && ··· 361 362 * how the packet travels inside Linux networking. 362 363 */ 363 364 if (!skb_valid_dst(skb)) { 364 - err = ip_route_input_noref(skb, iph->daddr, iph->saddr, 365 - ip4h_dscp(iph), dev); 366 - if (unlikely(err)) 365 + drop_reason = ip_route_input_noref(skb, iph->daddr, iph->saddr, 366 + ip4h_dscp(iph), dev); 367 + if (unlikely(drop_reason)) 367 368 goto drop_error; 369 + drop_reason = SKB_DROP_REASON_NOT_SPECIFIED; 368 370 } else { 369 371 struct in_device *in_dev = __in_dev_get_rcu(dev); 370 372 ··· 425 425 return NET_RX_DROP; 426 426 427 427 drop_error: 428 - if (err == -EXDEV) { 429 - drop_reason = SKB_DROP_REASON_IP_RPFILTER; 428 + if (drop_reason == SKB_DROP_REASON_IP_RPFILTER) 430 429 __NET_INC_STATS(net, LINUX_MIB_IPRPFILTER); 431 - } 432 430 goto drop; 433 431 } 434 432
+1 -1
net/ipv4/ip_options.c
··· 618 618 orefdst = skb->_skb_refdst; 619 619 skb_dst_set(skb, NULL); 620 620 err = ip_route_input(skb, nexthop, iph->saddr, ip4h_dscp(iph), 621 - dev); 621 + dev) ? -EINVAL : 0; 622 622 rt2 = skb_rtable(skb); 623 623 if (err || (rt2->rt_type != RTN_UNICAST && rt2->rt_type != RTN_LOCAL)) { 624 624 skb_dst_drop(skb);
+122 -89
net/ipv4/route.c
··· 1678 1678 EXPORT_SYMBOL(rt_dst_clone); 1679 1679 1680 1680 /* called in rcu_read_lock() section */ 1681 - int ip_mc_validate_source(struct sk_buff *skb, __be32 daddr, __be32 saddr, 1682 - dscp_t dscp, struct net_device *dev, 1683 - struct in_device *in_dev, u32 *itag) 1681 + enum skb_drop_reason 1682 + ip_mc_validate_source(struct sk_buff *skb, __be32 daddr, __be32 saddr, 1683 + dscp_t dscp, struct net_device *dev, 1684 + struct in_device *in_dev, u32 *itag) 1684 1685 { 1685 - int err; 1686 + enum skb_drop_reason reason; 1686 1687 1687 1688 /* Primary sanity checks. */ 1688 1689 if (!in_dev) 1689 - return -EINVAL; 1690 + return SKB_DROP_REASON_NOT_SPECIFIED; 1690 1691 1691 - if (ipv4_is_multicast(saddr) || ipv4_is_lbcast(saddr) || 1692 - skb->protocol != htons(ETH_P_IP)) 1693 - return -EINVAL; 1692 + if (ipv4_is_multicast(saddr) || ipv4_is_lbcast(saddr)) 1693 + return SKB_DROP_REASON_IP_INVALID_SOURCE; 1694 + 1695 + if (skb->protocol != htons(ETH_P_IP)) 1696 + return SKB_DROP_REASON_INVALID_PROTO; 1694 1697 1695 1698 if (ipv4_is_loopback(saddr) && !IN_DEV_ROUTE_LOCALNET(in_dev)) 1696 - return -EINVAL; 1699 + return SKB_DROP_REASON_IP_LOCALNET; 1697 1700 1698 1701 if (ipv4_is_zeronet(saddr)) { 1699 1702 if (!ipv4_is_local_multicast(daddr) && 1700 1703 ip_hdr(skb)->protocol != IPPROTO_IGMP) 1701 - return -EINVAL; 1704 + return SKB_DROP_REASON_IP_INVALID_SOURCE; 1702 1705 } else { 1703 - err = fib_validate_source(skb, saddr, 0, dscp, 0, dev, in_dev, 1704 - itag); 1705 - if (err < 0) 1706 - return err; 1706 + reason = fib_validate_source_reason(skb, saddr, 0, dscp, 0, 1707 + dev, in_dev, itag); 1708 + if (reason) 1709 + return reason; 1707 1710 } 1708 - return 0; 1711 + return SKB_NOT_DROPPED_YET; 1709 1712 } 1710 1713 1711 1714 /* called in rcu_read_lock() section */ 1712 - static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, 1713 - dscp_t dscp, struct net_device *dev, int our) 1715 + static enum skb_drop_reason 1716 + ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, 1717 + dscp_t dscp, struct net_device *dev, int our) 1714 1718 { 1715 1719 struct in_device *in_dev = __in_dev_get_rcu(dev); 1716 1720 unsigned int flags = RTCF_MULTICAST; 1721 + enum skb_drop_reason reason; 1717 1722 struct rtable *rth; 1718 1723 u32 itag = 0; 1719 - int err; 1720 1724 1721 - err = ip_mc_validate_source(skb, daddr, saddr, dscp, dev, in_dev, 1722 - &itag); 1723 - if (err) 1724 - return err; 1725 + reason = ip_mc_validate_source(skb, daddr, saddr, dscp, dev, in_dev, 1726 + &itag); 1727 + if (reason) 1728 + return reason; 1725 1729 1726 1730 if (our) 1727 1731 flags |= RTCF_LOCAL; ··· 1736 1732 rth = rt_dst_alloc(dev_net(dev)->loopback_dev, flags, RTN_MULTICAST, 1737 1733 false); 1738 1734 if (!rth) 1739 - return -ENOBUFS; 1735 + return SKB_DROP_REASON_NOMEM; 1740 1736 1741 1737 #ifdef CONFIG_IP_ROUTE_CLASSID 1742 1738 rth->dst.tclassid = itag; ··· 1752 1748 1753 1749 skb_dst_drop(skb); 1754 1750 skb_dst_set(skb, &rth->dst); 1755 - return 0; 1751 + return SKB_NOT_DROPPED_YET; 1756 1752 } 1757 1753 1758 1754 ··· 1782 1778 } 1783 1779 1784 1780 /* called in rcu_read_lock() section */ 1785 - static int __mkroute_input(struct sk_buff *skb, const struct fib_result *res, 1786 - struct in_device *in_dev, __be32 daddr, 1787 - __be32 saddr, dscp_t dscp) 1781 + static enum skb_drop_reason 1782 + __mkroute_input(struct sk_buff *skb, const struct fib_result *res, 1783 + struct in_device *in_dev, __be32 daddr, 1784 + __be32 saddr, dscp_t dscp) 1788 1785 { 1786 + enum skb_drop_reason reason = SKB_DROP_REASON_NOT_SPECIFIED; 1789 1787 struct fib_nh_common *nhc = FIB_RES_NHC(*res); 1790 1788 struct net_device *dev = nhc->nhc_dev; 1791 1789 struct fib_nh_exception *fnhe; ··· 1801 1795 out_dev = __in_dev_get_rcu(dev); 1802 1796 if (!out_dev) { 1803 1797 net_crit_ratelimited("Bug in ip_route_input_slow(). Please report.\n"); 1804 - return -EINVAL; 1798 + return reason; 1805 1799 } 1806 1800 1807 1801 err = fib_validate_source(skb, saddr, daddr, dscp, FIB_RES_OIF(*res), 1808 1802 in_dev->dev, in_dev, &itag); 1809 1803 if (err < 0) { 1804 + reason = -err; 1810 1805 ip_handle_martian_source(in_dev->dev, in_dev, skb, daddr, 1811 1806 saddr); 1812 1807 ··· 1835 1828 */ 1836 1829 if (out_dev == in_dev && 1837 1830 IN_DEV_PROXY_ARP_PVLAN(in_dev) == 0) { 1838 - err = -EINVAL; 1831 + reason = SKB_DROP_REASON_ARP_PVLAN_DISABLE; 1839 1832 goto cleanup; 1840 1833 } 1841 1834 } ··· 1858 1851 rth = rt_dst_alloc(out_dev->dev, 0, res->type, 1859 1852 IN_DEV_ORCONF(out_dev, NOXFRM)); 1860 1853 if (!rth) { 1861 - err = -ENOBUFS; 1854 + reason = SKB_DROP_REASON_NOMEM; 1862 1855 goto cleanup; 1863 1856 } 1864 1857 ··· 1872 1865 lwtunnel_set_redirect(&rth->dst); 1873 1866 skb_dst_set(skb, &rth->dst); 1874 1867 out: 1875 - err = 0; 1876 - cleanup: 1877 - return err; 1868 + reason = SKB_NOT_DROPPED_YET; 1869 + cleanup: 1870 + return reason; 1878 1871 } 1879 1872 1880 1873 #ifdef CONFIG_IP_ROUTE_MULTIPATH ··· 2132 2125 } 2133 2126 #endif /* CONFIG_IP_ROUTE_MULTIPATH */ 2134 2127 2135 - static int ip_mkroute_input(struct sk_buff *skb, struct fib_result *res, 2136 - struct in_device *in_dev, __be32 daddr, 2137 - __be32 saddr, dscp_t dscp, struct flow_keys *hkeys) 2128 + static enum skb_drop_reason 2129 + ip_mkroute_input(struct sk_buff *skb, struct fib_result *res, 2130 + struct in_device *in_dev, __be32 daddr, 2131 + __be32 saddr, dscp_t dscp, struct flow_keys *hkeys) 2138 2132 { 2139 2133 #ifdef CONFIG_IP_ROUTE_MULTIPATH 2140 2134 if (res->fi && fib_info_num_path(res->fi) > 1) { ··· 2154 2146 * assuming daddr is valid and the destination is not a local broadcast one. 2155 2147 * Uses the provided hint instead of performing a route lookup. 2156 2148 */ 2157 - int ip_route_use_hint(struct sk_buff *skb, __be32 daddr, __be32 saddr, 2158 - dscp_t dscp, struct net_device *dev, 2159 - const struct sk_buff *hint) 2149 + enum skb_drop_reason 2150 + ip_route_use_hint(struct sk_buff *skb, __be32 daddr, __be32 saddr, 2151 + dscp_t dscp, struct net_device *dev, 2152 + const struct sk_buff *hint) 2160 2153 { 2154 + enum skb_drop_reason reason = SKB_DROP_REASON_NOT_SPECIFIED; 2161 2155 struct in_device *in_dev = __in_dev_get_rcu(dev); 2162 2156 struct rtable *rt = skb_rtable(hint); 2163 2157 struct net *net = dev_net(dev); 2164 - int err = -EINVAL; 2165 2158 u32 tag = 0; 2166 2159 2167 2160 if (!in_dev) 2168 - return -EINVAL; 2161 + return reason; 2169 2162 2170 - if (ipv4_is_multicast(saddr) || ipv4_is_lbcast(saddr)) 2163 + if (ipv4_is_multicast(saddr) || ipv4_is_lbcast(saddr)) { 2164 + reason = SKB_DROP_REASON_IP_INVALID_SOURCE; 2171 2165 goto martian_source; 2166 + } 2172 2167 2173 - if (ipv4_is_zeronet(saddr)) 2168 + if (ipv4_is_zeronet(saddr)) { 2169 + reason = SKB_DROP_REASON_IP_INVALID_SOURCE; 2174 2170 goto martian_source; 2171 + } 2175 2172 2176 - if (ipv4_is_loopback(saddr) && !IN_DEV_NET_ROUTE_LOCALNET(in_dev, net)) 2173 + if (ipv4_is_loopback(saddr) && !IN_DEV_NET_ROUTE_LOCALNET(in_dev, net)) { 2174 + reason = SKB_DROP_REASON_IP_LOCALNET; 2177 2175 goto martian_source; 2176 + } 2178 2177 2179 2178 if (rt->rt_type != RTN_LOCAL) 2180 2179 goto skip_validate_source; 2181 2180 2182 - err = fib_validate_source(skb, saddr, daddr, dscp, 0, dev, in_dev, 2183 - &tag); 2184 - if (err < 0) 2181 + reason = fib_validate_source_reason(skb, saddr, daddr, dscp, 0, dev, 2182 + in_dev, &tag); 2183 + if (reason) 2185 2184 goto martian_source; 2186 2185 2187 2186 skip_validate_source: 2188 2187 skb_dst_copy(skb, hint); 2189 - return 0; 2188 + return SKB_NOT_DROPPED_YET; 2190 2189 2191 2190 martian_source: 2192 2191 ip_handle_martian_source(dev, in_dev, skb, daddr, saddr); 2193 - return err; 2192 + return reason; 2194 2193 } 2195 2194 2196 2195 /* get device for dst_alloc with local routes */ ··· 2226 2211 * called with rcu_read_lock() 2227 2212 */ 2228 2213 2229 - static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr, 2230 - dscp_t dscp, struct net_device *dev, 2231 - struct fib_result *res) 2214 + static enum skb_drop_reason 2215 + ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr, 2216 + dscp_t dscp, struct net_device *dev, 2217 + struct fib_result *res) 2232 2218 { 2219 + enum skb_drop_reason reason = SKB_DROP_REASON_NOT_SPECIFIED; 2233 2220 struct in_device *in_dev = __in_dev_get_rcu(dev); 2234 2221 struct flow_keys *flkeys = NULL, _flkeys; 2235 2222 struct net *net = dev_net(dev); ··· 2259 2242 fl4.flowi4_tun_key.tun_id = 0; 2260 2243 skb_dst_drop(skb); 2261 2244 2262 - if (ipv4_is_multicast(saddr) || ipv4_is_lbcast(saddr)) 2245 + if (ipv4_is_multicast(saddr) || ipv4_is_lbcast(saddr)) { 2246 + reason = SKB_DROP_REASON_IP_INVALID_SOURCE; 2263 2247 goto martian_source; 2248 + } 2264 2249 2265 2250 res->fi = NULL; 2266 2251 res->table = NULL; ··· 2272 2253 /* Accept zero addresses only to limited broadcast; 2273 2254 * I even do not know to fix it or not. Waiting for complains :-) 2274 2255 */ 2275 - if (ipv4_is_zeronet(saddr)) 2256 + if (ipv4_is_zeronet(saddr)) { 2257 + reason = SKB_DROP_REASON_IP_INVALID_SOURCE; 2276 2258 goto martian_source; 2259 + } 2277 2260 2278 - if (ipv4_is_zeronet(daddr)) 2261 + if (ipv4_is_zeronet(daddr)) { 2262 + reason = SKB_DROP_REASON_IP_INVALID_DEST; 2279 2263 goto martian_destination; 2264 + } 2280 2265 2281 2266 /* Following code try to avoid calling IN_DEV_NET_ROUTE_LOCALNET(), 2282 2267 * and call it once if daddr or/and saddr are loopback addresses 2283 2268 */ 2284 2269 if (ipv4_is_loopback(daddr)) { 2285 - if (!IN_DEV_NET_ROUTE_LOCALNET(in_dev, net)) 2270 + if (!IN_DEV_NET_ROUTE_LOCALNET(in_dev, net)) { 2271 + reason = SKB_DROP_REASON_IP_LOCALNET; 2286 2272 goto martian_destination; 2273 + } 2287 2274 } else if (ipv4_is_loopback(saddr)) { 2288 - if (!IN_DEV_NET_ROUTE_LOCALNET(in_dev, net)) 2275 + if (!IN_DEV_NET_ROUTE_LOCALNET(in_dev, net)) { 2276 + reason = SKB_DROP_REASON_IP_LOCALNET; 2289 2277 goto martian_source; 2278 + } 2290 2279 } 2291 2280 2292 2281 /* ··· 2336 2309 goto brd_input; 2337 2310 } 2338 2311 2312 + err = -EINVAL; 2339 2313 if (res->type == RTN_LOCAL) { 2340 - err = fib_validate_source(skb, saddr, daddr, dscp, 0, dev, 2341 - in_dev, &itag); 2342 - if (err < 0) 2314 + reason = fib_validate_source_reason(skb, saddr, daddr, dscp, 2315 + 0, dev, in_dev, &itag); 2316 + if (reason) 2343 2317 goto martian_source; 2344 2318 goto local_input; 2345 2319 } ··· 2349 2321 err = -EHOSTUNREACH; 2350 2322 goto no_route; 2351 2323 } 2352 - if (res->type != RTN_UNICAST) 2324 + if (res->type != RTN_UNICAST) { 2325 + reason = SKB_DROP_REASON_IP_INVALID_DEST; 2353 2326 goto martian_destination; 2327 + } 2354 2328 2355 2329 make_route: 2356 - err = ip_mkroute_input(skb, res, in_dev, daddr, saddr, dscp, flkeys); 2357 - out: return err; 2330 + reason = ip_mkroute_input(skb, res, in_dev, daddr, saddr, dscp, 2331 + flkeys); 2332 + 2333 + out: 2334 + return reason; 2358 2335 2359 2336 brd_input: 2360 - if (skb->protocol != htons(ETH_P_IP)) 2361 - goto e_inval; 2337 + if (skb->protocol != htons(ETH_P_IP)) { 2338 + reason = SKB_DROP_REASON_INVALID_PROTO; 2339 + goto out; 2340 + } 2362 2341 2363 2342 if (!ipv4_is_zeronet(saddr)) { 2364 - err = fib_validate_source(skb, saddr, 0, dscp, 0, dev, in_dev, 2365 - &itag); 2366 - if (err < 0) 2343 + reason = fib_validate_source_reason(skb, saddr, 0, dscp, 0, 2344 + dev, in_dev, &itag); 2345 + if (reason) 2367 2346 goto martian_source; 2368 2347 } 2369 2348 flags |= RTCF_BROADCAST; ··· 2388 2353 rth = rcu_dereference(nhc->nhc_rth_input); 2389 2354 if (rt_cache_valid(rth)) { 2390 2355 skb_dst_set_noref(skb, &rth->dst); 2391 - err = 0; 2356 + reason = SKB_NOT_DROPPED_YET; 2392 2357 goto out; 2393 2358 } 2394 2359 } ··· 2425 2390 rt_add_uncached_list(rth); 2426 2391 } 2427 2392 skb_dst_set(skb, &rth->dst); 2428 - err = 0; 2393 + reason = SKB_NOT_DROPPED_YET; 2429 2394 goto out; 2430 2395 2431 2396 no_route: ··· 2446 2411 &daddr, &saddr, dev->name); 2447 2412 #endif 2448 2413 2449 - e_inval: 2450 - err = -EINVAL; 2451 - goto out; 2452 - 2453 2414 e_nobufs: 2454 - err = -ENOBUFS; 2415 + reason = SKB_DROP_REASON_NOMEM; 2455 2416 goto out; 2456 2417 2457 2418 martian_source: ··· 2456 2425 } 2457 2426 2458 2427 /* called with rcu_read_lock held */ 2459 - static int ip_route_input_rcu(struct sk_buff *skb, __be32 daddr, __be32 saddr, 2460 - dscp_t dscp, struct net_device *dev, 2461 - struct fib_result *res) 2428 + static enum skb_drop_reason 2429 + ip_route_input_rcu(struct sk_buff *skb, __be32 daddr, __be32 saddr, 2430 + dscp_t dscp, struct net_device *dev, 2431 + struct fib_result *res) 2462 2432 { 2463 2433 /* Multicast recognition logic is moved from route cache to here. 2464 2434 * The problem was that too many Ethernet cards have broken/missing ··· 2473 2441 * route cache entry is created eventually. 2474 2442 */ 2475 2443 if (ipv4_is_multicast(daddr)) { 2444 + enum skb_drop_reason reason = SKB_DROP_REASON_NOT_SPECIFIED; 2476 2445 struct in_device *in_dev = __in_dev_get_rcu(dev); 2477 2446 int our = 0; 2478 - int err = -EINVAL; 2479 2447 2480 2448 if (!in_dev) 2481 - return err; 2449 + return -EINVAL; 2482 2450 our = ip_check_mc_rcu(in_dev, daddr, saddr, 2483 2451 ip_hdr(skb)->protocol); 2484 2452 ··· 2499 2467 IN_DEV_MFORWARD(in_dev)) 2500 2468 #endif 2501 2469 ) { 2502 - err = ip_route_input_mc(skb, daddr, saddr, dscp, dev, 2503 - our); 2470 + reason = ip_route_input_mc(skb, daddr, saddr, dscp, 2471 + dev, our); 2504 2472 } 2505 - return err; 2473 + return reason; 2506 2474 } 2507 2475 2508 2476 return ip_route_input_slow(skb, daddr, saddr, dscp, dev, res); 2509 2477 } 2510 2478 2511 - int ip_route_input_noref(struct sk_buff *skb, __be32 daddr, __be32 saddr, 2512 - dscp_t dscp, struct net_device *dev) 2479 + enum skb_drop_reason ip_route_input_noref(struct sk_buff *skb, __be32 daddr, 2480 + __be32 saddr, dscp_t dscp, 2481 + struct net_device *dev) 2513 2482 { 2483 + enum skb_drop_reason reason; 2514 2484 struct fib_result res; 2515 - int err; 2516 2485 2517 2486 rcu_read_lock(); 2518 - err = ip_route_input_rcu(skb, daddr, saddr, dscp, dev, &res); 2487 + reason = ip_route_input_rcu(skb, daddr, saddr, dscp, dev, &res); 2519 2488 rcu_read_unlock(); 2520 2489 2521 - return err; 2490 + return reason; 2522 2491 } 2523 2492 EXPORT_SYMBOL(ip_route_input_noref); 2524 2493 ··· 3331 3298 skb->mark = mark; 3332 3299 err = ip_route_input_rcu(skb, dst, src, 3333 3300 inet_dsfield_to_dscp(rtm->rtm_tos), 3334 - dev, &res); 3301 + dev, &res) ? -EINVAL : 0; 3335 3302 3336 3303 rt = skb_rtable(skb); 3337 3304 if (err == 0 && rt->dst.error)
+7 -7
net/ipv6/seg6_local.c
··· 954 954 struct sk_buff *skb) 955 955 { 956 956 struct dst_entry *orig_dst = skb_dst(skb); 957 + enum skb_drop_reason reason; 957 958 struct seg6_local_lwt *slwt; 958 959 struct iphdr *iph; 959 960 __be32 nhaddr; 960 - int err; 961 961 962 962 slwt = seg6_local_lwtunnel(orig_dst->lwtstate); 963 963 ··· 967 967 968 968 skb_dst_drop(skb); 969 969 970 - err = ip_route_input(skb, nhaddr, iph->saddr, 0, skb->dev); 971 - if (err) { 972 - kfree_skb(skb); 970 + reason = ip_route_input(skb, nhaddr, iph->saddr, 0, skb->dev); 971 + if (reason) { 972 + kfree_skb_reason(skb, reason); 973 973 return -EINVAL; 974 974 } 975 975 ··· 1174 1174 static int input_action_end_dt4(struct sk_buff *skb, 1175 1175 struct seg6_local_lwt *slwt) 1176 1176 { 1177 + enum skb_drop_reason reason; 1177 1178 struct iphdr *iph; 1178 - int err; 1179 1179 1180 1180 if (!decap_and_validate(skb, IPPROTO_IPIP)) 1181 1181 goto drop; ··· 1193 1193 1194 1194 iph = ip_hdr(skb); 1195 1195 1196 - err = ip_route_input(skb, iph->daddr, iph->saddr, 0, skb->dev); 1197 - if (unlikely(err)) 1196 + reason = ip_route_input(skb, iph->daddr, iph->saddr, 0, skb->dev); 1197 + if (unlikely(reason)) 1198 1198 goto drop; 1199 1199 1200 1200 return dst_input(skb);