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

net/ipv6: Add helper to return path MTU based on fib result

Determine path MTU from a FIB lookup result. Logic is based on
ip6_dst_mtu_forward plus lookup of nexthop exception.

Add ip6_dst_mtu_forward to ipv6_stubs to handle access by core
bpf code.

Signed-off-by: David Ahern <dsahern@gmail.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>

authored by

David Ahern and committed by
Daniel Borkmann
901731b8 50d889b1

+68
+2
include/net/addrconf.h
··· 236 236 struct flowi6 *fl6, int oif, 237 237 const struct sk_buff *skb, 238 238 int strict); 239 + u32 (*ip6_mtu_from_fib6)(struct fib6_info *f6i, struct in6_addr *daddr, 240 + struct in6_addr *saddr); 239 241 240 242 void (*udpv6_encap_enable)(void); 241 243 void (*ndisc_send_na)(struct net_device *dev, const struct in6_addr *daddr,
+6
include/net/ip6_fib.h
··· 412 412 return f6i->fib6_nh.nh_dev; 413 413 } 414 414 415 + static inline 416 + struct lwtunnel_state *fib6_info_nh_lwt(const struct fib6_info *f6i) 417 + { 418 + return f6i->fib6_nh.nh_lwtstate; 419 + } 420 + 415 421 void inet6_rt_notify(int event, struct fib6_info *rt, struct nl_info *info, 416 422 unsigned int flags); 417 423
+3
include/net/ip6_route.h
··· 300 300 return mtu; 301 301 } 302 302 303 + u32 ip6_mtu_from_fib6(struct fib6_info *f6i, struct in6_addr *daddr, 304 + struct in6_addr *saddr); 305 + 303 306 struct neighbour *ip6_neigh_lookup(const struct in6_addr *gw, 304 307 struct net_device *dev, struct sk_buff *skb, 305 308 const void *daddr);
+8
net/ipv6/addrconf_core.c
··· 161 161 return f6i; 162 162 } 163 163 164 + static u32 165 + eafnosupport_ip6_mtu_from_fib6(struct fib6_info *f6i, struct in6_addr *daddr, 166 + struct in6_addr *saddr) 167 + { 168 + return 0; 169 + } 170 + 164 171 const struct ipv6_stub *ipv6_stub __read_mostly = &(struct ipv6_stub) { 165 172 .ipv6_dst_lookup = eafnosupport_ipv6_dst_lookup, 166 173 .fib6_get_table = eafnosupport_fib6_get_table, 167 174 .fib6_table_lookup = eafnosupport_fib6_table_lookup, 168 175 .fib6_lookup = eafnosupport_fib6_lookup, 169 176 .fib6_multipath_select = eafnosupport_fib6_multipath_select, 177 + .ip6_mtu_from_fib6 = eafnosupport_ip6_mtu_from_fib6, 170 178 }; 171 179 EXPORT_SYMBOL_GPL(ipv6_stub); 172 180
+1
net/ipv6/af_inet6.c
··· 894 894 .fib6_table_lookup = fib6_table_lookup, 895 895 .fib6_lookup = fib6_lookup, 896 896 .fib6_multipath_select = fib6_multipath_select, 897 + .ip6_mtu_from_fib6 = ip6_mtu_from_fib6, 897 898 .udpv6_encap_enable = udpv6_encap_enable, 898 899 .ndisc_send_na = ndisc_send_na, 899 900 .nd_tbl = &nd_tbl,
+48
net/ipv6/route.c
··· 2603 2603 return mtu - lwtunnel_headroom(dst->lwtstate, mtu); 2604 2604 } 2605 2605 2606 + /* MTU selection: 2607 + * 1. mtu on route is locked - use it 2608 + * 2. mtu from nexthop exception 2609 + * 3. mtu from egress device 2610 + * 2611 + * based on ip6_dst_mtu_forward and exception logic of 2612 + * rt6_find_cached_rt; called with rcu_read_lock 2613 + */ 2614 + u32 ip6_mtu_from_fib6(struct fib6_info *f6i, struct in6_addr *daddr, 2615 + struct in6_addr *saddr) 2616 + { 2617 + struct rt6_exception_bucket *bucket; 2618 + struct rt6_exception *rt6_ex; 2619 + struct in6_addr *src_key; 2620 + struct inet6_dev *idev; 2621 + u32 mtu = 0; 2622 + 2623 + if (unlikely(fib6_metric_locked(f6i, RTAX_MTU))) { 2624 + mtu = f6i->fib6_pmtu; 2625 + if (mtu) 2626 + goto out; 2627 + } 2628 + 2629 + src_key = NULL; 2630 + #ifdef CONFIG_IPV6_SUBTREES 2631 + if (f6i->fib6_src.plen) 2632 + src_key = saddr; 2633 + #endif 2634 + 2635 + bucket = rcu_dereference(f6i->rt6i_exception_bucket); 2636 + rt6_ex = __rt6_find_exception_rcu(&bucket, daddr, src_key); 2637 + if (rt6_ex && !rt6_check_expired(rt6_ex->rt6i)) 2638 + mtu = dst_metric_raw(&rt6_ex->rt6i->dst, RTAX_MTU); 2639 + 2640 + if (likely(!mtu)) { 2641 + struct net_device *dev = fib6_info_nh_dev(f6i); 2642 + 2643 + mtu = IPV6_MIN_MTU; 2644 + idev = __in6_dev_get(dev); 2645 + if (idev && idev->cnf.mtu6 > mtu) 2646 + mtu = idev->cnf.mtu6; 2647 + } 2648 + 2649 + mtu = min_t(unsigned int, mtu, IP6_MAX_MTU); 2650 + out: 2651 + return mtu - lwtunnel_headroom(fib6_info_nh_lwt(f6i), mtu); 2652 + } 2653 + 2606 2654 struct dst_entry *icmp6_dst_alloc(struct net_device *dev, 2607 2655 struct flowi6 *fl6) 2608 2656 {