18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Linux INET6 implementation 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Authors: 68c2ecf20Sopenharmony_ci * Pedro Roque <roque@di.fc.ul.pt> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#ifndef _IP6_FIB_H 108c2ecf20Sopenharmony_ci#define _IP6_FIB_H 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/ipv6_route.h> 138c2ecf20Sopenharmony_ci#include <linux/rtnetlink.h> 148c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 158c2ecf20Sopenharmony_ci#include <linux/notifier.h> 168c2ecf20Sopenharmony_ci#include <net/dst.h> 178c2ecf20Sopenharmony_ci#include <net/flow.h> 188c2ecf20Sopenharmony_ci#include <net/ip_fib.h> 198c2ecf20Sopenharmony_ci#include <net/netlink.h> 208c2ecf20Sopenharmony_ci#include <net/inetpeer.h> 218c2ecf20Sopenharmony_ci#include <net/fib_notifier.h> 228c2ecf20Sopenharmony_ci#include <linux/indirect_call_wrapper.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#ifdef CONFIG_IPV6_MULTIPLE_TABLES 258c2ecf20Sopenharmony_ci#define FIB6_TABLE_HASHSZ 256 268c2ecf20Sopenharmony_ci#else 278c2ecf20Sopenharmony_ci#define FIB6_TABLE_HASHSZ 1 288c2ecf20Sopenharmony_ci#endif 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define RT6_DEBUG 2 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#if RT6_DEBUG >= 3 338c2ecf20Sopenharmony_ci#define RT6_TRACE(x...) pr_debug(x) 348c2ecf20Sopenharmony_ci#else 358c2ecf20Sopenharmony_ci#define RT6_TRACE(x...) do { ; } while (0) 368c2ecf20Sopenharmony_ci#endif 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistruct rt6_info; 398c2ecf20Sopenharmony_cistruct fib6_info; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistruct fib6_config { 428c2ecf20Sopenharmony_ci u32 fc_table; 438c2ecf20Sopenharmony_ci u32 fc_metric; 448c2ecf20Sopenharmony_ci int fc_dst_len; 458c2ecf20Sopenharmony_ci int fc_src_len; 468c2ecf20Sopenharmony_ci int fc_ifindex; 478c2ecf20Sopenharmony_ci u32 fc_flags; 488c2ecf20Sopenharmony_ci u32 fc_protocol; 498c2ecf20Sopenharmony_ci u16 fc_type; /* only 8 bits are used */ 508c2ecf20Sopenharmony_ci u16 fc_delete_all_nh : 1, 518c2ecf20Sopenharmony_ci fc_ignore_dev_down:1, 528c2ecf20Sopenharmony_ci __unused : 14; 538c2ecf20Sopenharmony_ci u32 fc_nh_id; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci struct in6_addr fc_dst; 568c2ecf20Sopenharmony_ci struct in6_addr fc_src; 578c2ecf20Sopenharmony_ci struct in6_addr fc_prefsrc; 588c2ecf20Sopenharmony_ci struct in6_addr fc_gateway; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci unsigned long fc_expires; 618c2ecf20Sopenharmony_ci struct nlattr *fc_mx; 628c2ecf20Sopenharmony_ci int fc_mx_len; 638c2ecf20Sopenharmony_ci int fc_mp_len; 648c2ecf20Sopenharmony_ci struct nlattr *fc_mp; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci struct nl_info fc_nlinfo; 678c2ecf20Sopenharmony_ci struct nlattr *fc_encap; 688c2ecf20Sopenharmony_ci u16 fc_encap_type; 698c2ecf20Sopenharmony_ci bool fc_is_fdb; 708c2ecf20Sopenharmony_ci}; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistruct fib6_node { 738c2ecf20Sopenharmony_ci struct fib6_node __rcu *parent; 748c2ecf20Sopenharmony_ci struct fib6_node __rcu *left; 758c2ecf20Sopenharmony_ci struct fib6_node __rcu *right; 768c2ecf20Sopenharmony_ci#ifdef CONFIG_IPV6_SUBTREES 778c2ecf20Sopenharmony_ci struct fib6_node __rcu *subtree; 788c2ecf20Sopenharmony_ci#endif 798c2ecf20Sopenharmony_ci struct fib6_info __rcu *leaf; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci __u16 fn_bit; /* bit key */ 828c2ecf20Sopenharmony_ci __u16 fn_flags; 838c2ecf20Sopenharmony_ci int fn_sernum; 848c2ecf20Sopenharmony_ci struct fib6_info __rcu *rr_ptr; 858c2ecf20Sopenharmony_ci struct rcu_head rcu; 868c2ecf20Sopenharmony_ci}; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistruct fib6_gc_args { 898c2ecf20Sopenharmony_ci int timeout; 908c2ecf20Sopenharmony_ci int more; 918c2ecf20Sopenharmony_ci}; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci#ifndef CONFIG_IPV6_SUBTREES 948c2ecf20Sopenharmony_ci#define FIB6_SUBTREE(fn) NULL 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic inline bool fib6_routes_require_src(const struct net *net) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci return false; 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic inline void fib6_routes_require_src_inc(struct net *net) {} 1028c2ecf20Sopenharmony_cistatic inline void fib6_routes_require_src_dec(struct net *net) {} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci#else 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic inline bool fib6_routes_require_src(const struct net *net) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci return net->ipv6.fib6_routes_require_src > 0; 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic inline void fib6_routes_require_src_inc(struct net *net) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci net->ipv6.fib6_routes_require_src++; 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic inline void fib6_routes_require_src_dec(struct net *net) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci net->ipv6.fib6_routes_require_src--; 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci#define FIB6_SUBTREE(fn) (rcu_dereference_protected((fn)->subtree, 1)) 1228c2ecf20Sopenharmony_ci#endif 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci/* 1258c2ecf20Sopenharmony_ci * routing information 1268c2ecf20Sopenharmony_ci * 1278c2ecf20Sopenharmony_ci */ 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistruct rt6key { 1308c2ecf20Sopenharmony_ci struct in6_addr addr; 1318c2ecf20Sopenharmony_ci int plen; 1328c2ecf20Sopenharmony_ci}; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistruct fib6_table; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistruct rt6_exception_bucket { 1378c2ecf20Sopenharmony_ci struct hlist_head chain; 1388c2ecf20Sopenharmony_ci int depth; 1398c2ecf20Sopenharmony_ci}; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistruct rt6_exception { 1428c2ecf20Sopenharmony_ci struct hlist_node hlist; 1438c2ecf20Sopenharmony_ci struct rt6_info *rt6i; 1448c2ecf20Sopenharmony_ci unsigned long stamp; 1458c2ecf20Sopenharmony_ci struct rcu_head rcu; 1468c2ecf20Sopenharmony_ci}; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci#define FIB6_EXCEPTION_BUCKET_SIZE_SHIFT 10 1498c2ecf20Sopenharmony_ci#define FIB6_EXCEPTION_BUCKET_SIZE (1 << FIB6_EXCEPTION_BUCKET_SIZE_SHIFT) 1508c2ecf20Sopenharmony_ci#define FIB6_MAX_DEPTH 5 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistruct fib6_nh { 1538c2ecf20Sopenharmony_ci struct fib_nh_common nh_common; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci#ifdef CONFIG_IPV6_ROUTER_PREF 1568c2ecf20Sopenharmony_ci unsigned long last_probe; 1578c2ecf20Sopenharmony_ci#endif 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci struct rt6_info * __percpu *rt6i_pcpu; 1608c2ecf20Sopenharmony_ci struct rt6_exception_bucket __rcu *rt6i_exception_bucket; 1618c2ecf20Sopenharmony_ci}; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistruct fib6_info { 1648c2ecf20Sopenharmony_ci struct fib6_table *fib6_table; 1658c2ecf20Sopenharmony_ci struct fib6_info __rcu *fib6_next; 1668c2ecf20Sopenharmony_ci struct fib6_node __rcu *fib6_node; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci /* Multipath routes: 1698c2ecf20Sopenharmony_ci * siblings is a list of fib6_info that have the same metric/weight, 1708c2ecf20Sopenharmony_ci * destination, but not the same gateway. nsiblings is just a cache 1718c2ecf20Sopenharmony_ci * to speed up lookup. 1728c2ecf20Sopenharmony_ci */ 1738c2ecf20Sopenharmony_ci union { 1748c2ecf20Sopenharmony_ci struct list_head fib6_siblings; 1758c2ecf20Sopenharmony_ci struct list_head nh_list; 1768c2ecf20Sopenharmony_ci }; 1778c2ecf20Sopenharmony_ci unsigned int fib6_nsiblings; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci refcount_t fib6_ref; 1808c2ecf20Sopenharmony_ci unsigned long expires; 1818c2ecf20Sopenharmony_ci struct dst_metrics *fib6_metrics; 1828c2ecf20Sopenharmony_ci#define fib6_pmtu fib6_metrics->metrics[RTAX_MTU-1] 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci struct rt6key fib6_dst; 1858c2ecf20Sopenharmony_ci u32 fib6_flags; 1868c2ecf20Sopenharmony_ci struct rt6key fib6_src; 1878c2ecf20Sopenharmony_ci struct rt6key fib6_prefsrc; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci u32 fib6_metric; 1908c2ecf20Sopenharmony_ci u8 fib6_protocol; 1918c2ecf20Sopenharmony_ci u8 fib6_type; 1928c2ecf20Sopenharmony_ci u8 should_flush:1, 1938c2ecf20Sopenharmony_ci dst_nocount:1, 1948c2ecf20Sopenharmony_ci dst_nopolicy:1, 1958c2ecf20Sopenharmony_ci fib6_destroying:1, 1968c2ecf20Sopenharmony_ci offload:1, 1978c2ecf20Sopenharmony_ci trap:1, 1988c2ecf20Sopenharmony_ci unused:2; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci struct rcu_head rcu; 2018c2ecf20Sopenharmony_ci struct nexthop *nh; 2028c2ecf20Sopenharmony_ci struct fib6_nh fib6_nh[]; 2038c2ecf20Sopenharmony_ci}; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistruct rt6_info { 2068c2ecf20Sopenharmony_ci struct dst_entry dst; 2078c2ecf20Sopenharmony_ci struct fib6_info __rcu *from; 2088c2ecf20Sopenharmony_ci int sernum; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci struct rt6key rt6i_dst; 2118c2ecf20Sopenharmony_ci struct rt6key rt6i_src; 2128c2ecf20Sopenharmony_ci struct in6_addr rt6i_gateway; 2138c2ecf20Sopenharmony_ci struct inet6_dev *rt6i_idev; 2148c2ecf20Sopenharmony_ci u32 rt6i_flags; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci struct list_head rt6i_uncached; 2178c2ecf20Sopenharmony_ci struct uncached_list *rt6i_uncached_list; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci /* more non-fragment space at head required */ 2208c2ecf20Sopenharmony_ci unsigned short rt6i_nfheader_len; 2218c2ecf20Sopenharmony_ci}; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistruct fib6_result { 2248c2ecf20Sopenharmony_ci struct fib6_nh *nh; 2258c2ecf20Sopenharmony_ci struct fib6_info *f6i; 2268c2ecf20Sopenharmony_ci u32 fib6_flags; 2278c2ecf20Sopenharmony_ci u8 fib6_type; 2288c2ecf20Sopenharmony_ci struct rt6_info *rt6; 2298c2ecf20Sopenharmony_ci}; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci#define for_each_fib6_node_rt_rcu(fn) \ 2328c2ecf20Sopenharmony_ci for (rt = rcu_dereference((fn)->leaf); rt; \ 2338c2ecf20Sopenharmony_ci rt = rcu_dereference(rt->fib6_next)) 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci#define for_each_fib6_walker_rt(w) \ 2368c2ecf20Sopenharmony_ci for (rt = (w)->leaf; rt; \ 2378c2ecf20Sopenharmony_ci rt = rcu_dereference_protected(rt->fib6_next, 1)) 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_cistatic inline struct inet6_dev *ip6_dst_idev(struct dst_entry *dst) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci return ((struct rt6_info *)dst)->rt6i_idev; 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cistatic inline bool fib6_requires_src(const struct fib6_info *rt) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci return rt->fib6_src.plen > 0; 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic inline void fib6_clean_expires(struct fib6_info *f6i) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci f6i->fib6_flags &= ~RTF_EXPIRES; 2528c2ecf20Sopenharmony_ci f6i->expires = 0; 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_cistatic inline void fib6_set_expires(struct fib6_info *f6i, 2568c2ecf20Sopenharmony_ci unsigned long expires) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci f6i->expires = expires; 2598c2ecf20Sopenharmony_ci f6i->fib6_flags |= RTF_EXPIRES; 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_cistatic inline bool fib6_check_expired(const struct fib6_info *f6i) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci if (f6i->fib6_flags & RTF_EXPIRES) 2658c2ecf20Sopenharmony_ci return time_after(jiffies, f6i->expires); 2668c2ecf20Sopenharmony_ci return false; 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci/* Function to safely get fn->sernum for passed in rt 2708c2ecf20Sopenharmony_ci * and store result in passed in cookie. 2718c2ecf20Sopenharmony_ci * Return true if we can get cookie safely 2728c2ecf20Sopenharmony_ci * Return false if not 2738c2ecf20Sopenharmony_ci */ 2748c2ecf20Sopenharmony_cistatic inline bool fib6_get_cookie_safe(const struct fib6_info *f6i, 2758c2ecf20Sopenharmony_ci u32 *cookie) 2768c2ecf20Sopenharmony_ci{ 2778c2ecf20Sopenharmony_ci struct fib6_node *fn; 2788c2ecf20Sopenharmony_ci bool status = false; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci fn = rcu_dereference(f6i->fib6_node); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci if (fn) { 2838c2ecf20Sopenharmony_ci *cookie = READ_ONCE(fn->fn_sernum); 2848c2ecf20Sopenharmony_ci /* pairs with smp_wmb() in fib6_update_sernum_upto_root() */ 2858c2ecf20Sopenharmony_ci smp_rmb(); 2868c2ecf20Sopenharmony_ci status = true; 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci return status; 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_cistatic inline u32 rt6_get_cookie(const struct rt6_info *rt) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci struct fib6_info *from; 2958c2ecf20Sopenharmony_ci u32 cookie = 0; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci if (rt->sernum) 2988c2ecf20Sopenharmony_ci return rt->sernum; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci rcu_read_lock(); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci from = rcu_dereference(rt->from); 3038c2ecf20Sopenharmony_ci if (from) 3048c2ecf20Sopenharmony_ci fib6_get_cookie_safe(from, &cookie); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci rcu_read_unlock(); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci return cookie; 3098c2ecf20Sopenharmony_ci} 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_cistatic inline void ip6_rt_put(struct rt6_info *rt) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci /* dst_release() accepts a NULL parameter. 3148c2ecf20Sopenharmony_ci * We rely on dst being first structure in struct rt6_info 3158c2ecf20Sopenharmony_ci */ 3168c2ecf20Sopenharmony_ci BUILD_BUG_ON(offsetof(struct rt6_info, dst) != 0); 3178c2ecf20Sopenharmony_ci dst_release(&rt->dst); 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_cistruct fib6_info *fib6_info_alloc(gfp_t gfp_flags, bool with_fib6_nh); 3218c2ecf20Sopenharmony_civoid fib6_info_destroy_rcu(struct rcu_head *head); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_cistatic inline void fib6_info_hold(struct fib6_info *f6i) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci refcount_inc(&f6i->fib6_ref); 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_cistatic inline bool fib6_info_hold_safe(struct fib6_info *f6i) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci return refcount_inc_not_zero(&f6i->fib6_ref); 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_cistatic inline void fib6_info_release(struct fib6_info *f6i) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci if (f6i && refcount_dec_and_test(&f6i->fib6_ref)) 3368c2ecf20Sopenharmony_ci call_rcu(&f6i->rcu, fib6_info_destroy_rcu); 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_cistatic inline void fib6_info_hw_flags_set(struct fib6_info *f6i, bool offload, 3408c2ecf20Sopenharmony_ci bool trap) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci f6i->offload = offload; 3438c2ecf20Sopenharmony_ci f6i->trap = trap; 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_cienum fib6_walk_state { 3478c2ecf20Sopenharmony_ci#ifdef CONFIG_IPV6_SUBTREES 3488c2ecf20Sopenharmony_ci FWS_S, 3498c2ecf20Sopenharmony_ci#endif 3508c2ecf20Sopenharmony_ci FWS_L, 3518c2ecf20Sopenharmony_ci FWS_R, 3528c2ecf20Sopenharmony_ci FWS_C, 3538c2ecf20Sopenharmony_ci FWS_U 3548c2ecf20Sopenharmony_ci}; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_cistruct fib6_walker { 3578c2ecf20Sopenharmony_ci struct list_head lh; 3588c2ecf20Sopenharmony_ci struct fib6_node *root, *node; 3598c2ecf20Sopenharmony_ci struct fib6_info *leaf; 3608c2ecf20Sopenharmony_ci enum fib6_walk_state state; 3618c2ecf20Sopenharmony_ci unsigned int skip; 3628c2ecf20Sopenharmony_ci unsigned int count; 3638c2ecf20Sopenharmony_ci unsigned int skip_in_node; 3648c2ecf20Sopenharmony_ci int (*func)(struct fib6_walker *); 3658c2ecf20Sopenharmony_ci void *args; 3668c2ecf20Sopenharmony_ci}; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_cistruct rt6_statistics { 3698c2ecf20Sopenharmony_ci __u32 fib_nodes; /* all fib6 nodes */ 3708c2ecf20Sopenharmony_ci __u32 fib_route_nodes; /* intermediate nodes */ 3718c2ecf20Sopenharmony_ci __u32 fib_rt_entries; /* rt entries in fib table */ 3728c2ecf20Sopenharmony_ci __u32 fib_rt_cache; /* cached rt entries in exception table */ 3738c2ecf20Sopenharmony_ci __u32 fib_discarded_routes; /* total number of routes delete */ 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci /* The following stats are not protected by any lock */ 3768c2ecf20Sopenharmony_ci atomic_t fib_rt_alloc; /* total number of routes alloced */ 3778c2ecf20Sopenharmony_ci atomic_t fib_rt_uncache; /* rt entries in uncached list */ 3788c2ecf20Sopenharmony_ci}; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci#define RTN_TL_ROOT 0x0001 3818c2ecf20Sopenharmony_ci#define RTN_ROOT 0x0002 /* tree root node */ 3828c2ecf20Sopenharmony_ci#define RTN_RTINFO 0x0004 /* node with valid routing info */ 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci/* 3858c2ecf20Sopenharmony_ci * priority levels (or metrics) 3868c2ecf20Sopenharmony_ci * 3878c2ecf20Sopenharmony_ci */ 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_cistruct fib6_table { 3918c2ecf20Sopenharmony_ci struct hlist_node tb6_hlist; 3928c2ecf20Sopenharmony_ci u32 tb6_id; 3938c2ecf20Sopenharmony_ci spinlock_t tb6_lock; 3948c2ecf20Sopenharmony_ci struct fib6_node tb6_root; 3958c2ecf20Sopenharmony_ci struct inet_peer_base tb6_peers; 3968c2ecf20Sopenharmony_ci unsigned int flags; 3978c2ecf20Sopenharmony_ci unsigned int fib_seq; 3988c2ecf20Sopenharmony_ci#define RT6_TABLE_HAS_DFLT_ROUTER BIT(0) 3998c2ecf20Sopenharmony_ci}; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci#define RT6_TABLE_UNSPEC RT_TABLE_UNSPEC 4028c2ecf20Sopenharmony_ci#define RT6_TABLE_MAIN RT_TABLE_MAIN 4038c2ecf20Sopenharmony_ci#define RT6_TABLE_DFLT RT6_TABLE_MAIN 4048c2ecf20Sopenharmony_ci#define RT6_TABLE_INFO RT6_TABLE_MAIN 4058c2ecf20Sopenharmony_ci#define RT6_TABLE_PREFIX RT6_TABLE_MAIN 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci#ifdef CONFIG_IPV6_MULTIPLE_TABLES 4088c2ecf20Sopenharmony_ci#define FIB6_TABLE_MIN 1 4098c2ecf20Sopenharmony_ci#define FIB6_TABLE_MAX RT_TABLE_MAX 4108c2ecf20Sopenharmony_ci#define RT6_TABLE_LOCAL RT_TABLE_LOCAL 4118c2ecf20Sopenharmony_ci#else 4128c2ecf20Sopenharmony_ci#define FIB6_TABLE_MIN RT_TABLE_MAIN 4138c2ecf20Sopenharmony_ci#define FIB6_TABLE_MAX FIB6_TABLE_MIN 4148c2ecf20Sopenharmony_ci#define RT6_TABLE_LOCAL RT6_TABLE_MAIN 4158c2ecf20Sopenharmony_ci#endif 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_citypedef struct rt6_info *(*pol_lookup_t)(struct net *, 4188c2ecf20Sopenharmony_ci struct fib6_table *, 4198c2ecf20Sopenharmony_ci struct flowi6 *, 4208c2ecf20Sopenharmony_ci const struct sk_buff *, int); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_cistruct fib6_entry_notifier_info { 4238c2ecf20Sopenharmony_ci struct fib_notifier_info info; /* must be first */ 4248c2ecf20Sopenharmony_ci struct fib6_info *rt; 4258c2ecf20Sopenharmony_ci unsigned int nsiblings; 4268c2ecf20Sopenharmony_ci}; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci/* 4298c2ecf20Sopenharmony_ci * exported functions 4308c2ecf20Sopenharmony_ci */ 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_cistruct fib6_table *fib6_get_table(struct net *net, u32 id); 4338c2ecf20Sopenharmony_cistruct fib6_table *fib6_new_table(struct net *net, u32 id); 4348c2ecf20Sopenharmony_cistruct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6, 4358c2ecf20Sopenharmony_ci const struct sk_buff *skb, 4368c2ecf20Sopenharmony_ci int flags, pol_lookup_t lookup); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci/* called with rcu lock held; can return error pointer 4398c2ecf20Sopenharmony_ci * caller needs to select path 4408c2ecf20Sopenharmony_ci */ 4418c2ecf20Sopenharmony_ciint fib6_lookup(struct net *net, int oif, struct flowi6 *fl6, 4428c2ecf20Sopenharmony_ci struct fib6_result *res, int flags); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci/* called with rcu lock held; caller needs to select path */ 4458c2ecf20Sopenharmony_ciint fib6_table_lookup(struct net *net, struct fib6_table *table, 4468c2ecf20Sopenharmony_ci int oif, struct flowi6 *fl6, struct fib6_result *res, 4478c2ecf20Sopenharmony_ci int strict); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_civoid fib6_select_path(const struct net *net, struct fib6_result *res, 4508c2ecf20Sopenharmony_ci struct flowi6 *fl6, int oif, bool have_oif_match, 4518c2ecf20Sopenharmony_ci const struct sk_buff *skb, int strict); 4528c2ecf20Sopenharmony_cistruct fib6_node *fib6_node_lookup(struct fib6_node *root, 4538c2ecf20Sopenharmony_ci const struct in6_addr *daddr, 4548c2ecf20Sopenharmony_ci const struct in6_addr *saddr); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_cistruct fib6_node *fib6_locate(struct fib6_node *root, 4578c2ecf20Sopenharmony_ci const struct in6_addr *daddr, int dst_len, 4588c2ecf20Sopenharmony_ci const struct in6_addr *saddr, int src_len, 4598c2ecf20Sopenharmony_ci bool exact_match); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_civoid fib6_clean_all(struct net *net, int (*func)(struct fib6_info *, void *arg), 4628c2ecf20Sopenharmony_ci void *arg); 4638c2ecf20Sopenharmony_civoid fib6_clean_all_skip_notify(struct net *net, 4648c2ecf20Sopenharmony_ci int (*func)(struct fib6_info *, void *arg), 4658c2ecf20Sopenharmony_ci void *arg); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ciint fib6_add(struct fib6_node *root, struct fib6_info *rt, 4688c2ecf20Sopenharmony_ci struct nl_info *info, struct netlink_ext_ack *extack); 4698c2ecf20Sopenharmony_ciint fib6_del(struct fib6_info *rt, struct nl_info *info); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_cistatic inline 4728c2ecf20Sopenharmony_civoid rt6_get_prefsrc(const struct rt6_info *rt, struct in6_addr *addr) 4738c2ecf20Sopenharmony_ci{ 4748c2ecf20Sopenharmony_ci const struct fib6_info *from; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci rcu_read_lock(); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci from = rcu_dereference(rt->from); 4798c2ecf20Sopenharmony_ci if (from) { 4808c2ecf20Sopenharmony_ci *addr = from->fib6_prefsrc.addr; 4818c2ecf20Sopenharmony_ci } else { 4828c2ecf20Sopenharmony_ci struct in6_addr in6_zero = {}; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci *addr = in6_zero; 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci rcu_read_unlock(); 4888c2ecf20Sopenharmony_ci} 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ciint fib6_nh_init(struct net *net, struct fib6_nh *fib6_nh, 4918c2ecf20Sopenharmony_ci struct fib6_config *cfg, gfp_t gfp_flags, 4928c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack); 4938c2ecf20Sopenharmony_civoid fib6_nh_release(struct fib6_nh *fib6_nh); 4948c2ecf20Sopenharmony_civoid fib6_nh_release_dsts(struct fib6_nh *fib6_nh); 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ciint call_fib6_entry_notifiers(struct net *net, 4978c2ecf20Sopenharmony_ci enum fib_event_type event_type, 4988c2ecf20Sopenharmony_ci struct fib6_info *rt, 4998c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack); 5008c2ecf20Sopenharmony_ciint call_fib6_multipath_entry_notifiers(struct net *net, 5018c2ecf20Sopenharmony_ci enum fib_event_type event_type, 5028c2ecf20Sopenharmony_ci struct fib6_info *rt, 5038c2ecf20Sopenharmony_ci unsigned int nsiblings, 5048c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack); 5058c2ecf20Sopenharmony_ciint call_fib6_entry_notifiers_replace(struct net *net, struct fib6_info *rt); 5068c2ecf20Sopenharmony_civoid fib6_rt_update(struct net *net, struct fib6_info *rt, 5078c2ecf20Sopenharmony_ci struct nl_info *info); 5088c2ecf20Sopenharmony_civoid inet6_rt_notify(int event, struct fib6_info *rt, struct nl_info *info, 5098c2ecf20Sopenharmony_ci unsigned int flags); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_civoid fib6_run_gc(unsigned long expires, struct net *net, bool force); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_civoid fib6_gc_cleanup(void); 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ciint fib6_init(void); 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_cistruct ipv6_route_iter { 5188c2ecf20Sopenharmony_ci struct seq_net_private p; 5198c2ecf20Sopenharmony_ci struct fib6_walker w; 5208c2ecf20Sopenharmony_ci loff_t skip; 5218c2ecf20Sopenharmony_ci struct fib6_table *tbl; 5228c2ecf20Sopenharmony_ci int sernum; 5238c2ecf20Sopenharmony_ci}; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ciextern const struct seq_operations ipv6_route_seq_ops; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ciint call_fib6_notifier(struct notifier_block *nb, 5288c2ecf20Sopenharmony_ci enum fib_event_type event_type, 5298c2ecf20Sopenharmony_ci struct fib_notifier_info *info); 5308c2ecf20Sopenharmony_ciint call_fib6_notifiers(struct net *net, enum fib_event_type event_type, 5318c2ecf20Sopenharmony_ci struct fib_notifier_info *info); 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ciint __net_init fib6_notifier_init(struct net *net); 5348c2ecf20Sopenharmony_civoid __net_exit fib6_notifier_exit(struct net *net); 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ciunsigned int fib6_tables_seq_read(struct net *net); 5378c2ecf20Sopenharmony_ciint fib6_tables_dump(struct net *net, struct notifier_block *nb, 5388c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack); 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_civoid fib6_update_sernum(struct net *net, struct fib6_info *rt); 5418c2ecf20Sopenharmony_civoid fib6_update_sernum_upto_root(struct net *net, struct fib6_info *rt); 5428c2ecf20Sopenharmony_civoid fib6_update_sernum_stub(struct net *net, struct fib6_info *f6i); 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_civoid fib6_metric_set(struct fib6_info *f6i, int metric, u32 val); 5458c2ecf20Sopenharmony_cistatic inline bool fib6_metric_locked(struct fib6_info *f6i, int metric) 5468c2ecf20Sopenharmony_ci{ 5478c2ecf20Sopenharmony_ci return !!(f6i->fib6_metrics->metrics[RTAX_LOCK - 1] & (1 << metric)); 5488c2ecf20Sopenharmony_ci} 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci#if IS_BUILTIN(CONFIG_IPV6) && defined(CONFIG_BPF_SYSCALL) 5518c2ecf20Sopenharmony_cistruct bpf_iter__ipv6_route { 5528c2ecf20Sopenharmony_ci __bpf_md_ptr(struct bpf_iter_meta *, meta); 5538c2ecf20Sopenharmony_ci __bpf_md_ptr(struct fib6_info *, rt); 5548c2ecf20Sopenharmony_ci}; 5558c2ecf20Sopenharmony_ci#endif 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ciINDIRECT_CALLABLE_DECLARE(struct rt6_info *ip6_pol_route_output(struct net *net, 5588c2ecf20Sopenharmony_ci struct fib6_table *table, 5598c2ecf20Sopenharmony_ci struct flowi6 *fl6, 5608c2ecf20Sopenharmony_ci const struct sk_buff *skb, 5618c2ecf20Sopenharmony_ci int flags)); 5628c2ecf20Sopenharmony_ciINDIRECT_CALLABLE_DECLARE(struct rt6_info *ip6_pol_route_input(struct net *net, 5638c2ecf20Sopenharmony_ci struct fib6_table *table, 5648c2ecf20Sopenharmony_ci struct flowi6 *fl6, 5658c2ecf20Sopenharmony_ci const struct sk_buff *skb, 5668c2ecf20Sopenharmony_ci int flags)); 5678c2ecf20Sopenharmony_ciINDIRECT_CALLABLE_DECLARE(struct rt6_info *__ip6_route_redirect(struct net *net, 5688c2ecf20Sopenharmony_ci struct fib6_table *table, 5698c2ecf20Sopenharmony_ci struct flowi6 *fl6, 5708c2ecf20Sopenharmony_ci const struct sk_buff *skb, 5718c2ecf20Sopenharmony_ci int flags)); 5728c2ecf20Sopenharmony_ciINDIRECT_CALLABLE_DECLARE(struct rt6_info *ip6_pol_route_lookup(struct net *net, 5738c2ecf20Sopenharmony_ci struct fib6_table *table, 5748c2ecf20Sopenharmony_ci struct flowi6 *fl6, 5758c2ecf20Sopenharmony_ci const struct sk_buff *skb, 5768c2ecf20Sopenharmony_ci int flags)); 5778c2ecf20Sopenharmony_cistatic inline struct rt6_info *pol_lookup_func(pol_lookup_t lookup, 5788c2ecf20Sopenharmony_ci struct net *net, 5798c2ecf20Sopenharmony_ci struct fib6_table *table, 5808c2ecf20Sopenharmony_ci struct flowi6 *fl6, 5818c2ecf20Sopenharmony_ci const struct sk_buff *skb, 5828c2ecf20Sopenharmony_ci int flags) 5838c2ecf20Sopenharmony_ci{ 5848c2ecf20Sopenharmony_ci return INDIRECT_CALL_4(lookup, 5858c2ecf20Sopenharmony_ci ip6_pol_route_output, 5868c2ecf20Sopenharmony_ci ip6_pol_route_input, 5878c2ecf20Sopenharmony_ci ip6_pol_route_lookup, 5888c2ecf20Sopenharmony_ci __ip6_route_redirect, 5898c2ecf20Sopenharmony_ci net, table, fl6, skb, flags); 5908c2ecf20Sopenharmony_ci} 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci#ifdef CONFIG_IPV6_MULTIPLE_TABLES 5938c2ecf20Sopenharmony_cistatic inline bool fib6_has_custom_rules(const struct net *net) 5948c2ecf20Sopenharmony_ci{ 5958c2ecf20Sopenharmony_ci return net->ipv6.fib6_has_custom_rules; 5968c2ecf20Sopenharmony_ci} 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ciint fib6_rules_init(void); 5998c2ecf20Sopenharmony_civoid fib6_rules_cleanup(void); 6008c2ecf20Sopenharmony_cibool fib6_rule_default(const struct fib_rule *rule); 6018c2ecf20Sopenharmony_ciint fib6_rules_dump(struct net *net, struct notifier_block *nb, 6028c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack); 6038c2ecf20Sopenharmony_ciunsigned int fib6_rules_seq_read(struct net *net); 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_cistatic inline bool fib6_rules_early_flow_dissect(struct net *net, 6068c2ecf20Sopenharmony_ci struct sk_buff *skb, 6078c2ecf20Sopenharmony_ci struct flowi6 *fl6, 6088c2ecf20Sopenharmony_ci struct flow_keys *flkeys) 6098c2ecf20Sopenharmony_ci{ 6108c2ecf20Sopenharmony_ci unsigned int flag = FLOW_DISSECTOR_F_STOP_AT_ENCAP; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci if (!net->ipv6.fib6_rules_require_fldissect) 6138c2ecf20Sopenharmony_ci return false; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci skb_flow_dissect_flow_keys(skb, flkeys, flag); 6168c2ecf20Sopenharmony_ci fl6->fl6_sport = flkeys->ports.src; 6178c2ecf20Sopenharmony_ci fl6->fl6_dport = flkeys->ports.dst; 6188c2ecf20Sopenharmony_ci fl6->flowi6_proto = flkeys->basic.ip_proto; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci return true; 6218c2ecf20Sopenharmony_ci} 6228c2ecf20Sopenharmony_ci#else 6238c2ecf20Sopenharmony_cistatic inline bool fib6_has_custom_rules(const struct net *net) 6248c2ecf20Sopenharmony_ci{ 6258c2ecf20Sopenharmony_ci return false; 6268c2ecf20Sopenharmony_ci} 6278c2ecf20Sopenharmony_cistatic inline int fib6_rules_init(void) 6288c2ecf20Sopenharmony_ci{ 6298c2ecf20Sopenharmony_ci return 0; 6308c2ecf20Sopenharmony_ci} 6318c2ecf20Sopenharmony_cistatic inline void fib6_rules_cleanup(void) 6328c2ecf20Sopenharmony_ci{ 6338c2ecf20Sopenharmony_ci return ; 6348c2ecf20Sopenharmony_ci} 6358c2ecf20Sopenharmony_cistatic inline bool fib6_rule_default(const struct fib_rule *rule) 6368c2ecf20Sopenharmony_ci{ 6378c2ecf20Sopenharmony_ci return true; 6388c2ecf20Sopenharmony_ci} 6398c2ecf20Sopenharmony_cistatic inline int fib6_rules_dump(struct net *net, struct notifier_block *nb, 6408c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 6418c2ecf20Sopenharmony_ci{ 6428c2ecf20Sopenharmony_ci return 0; 6438c2ecf20Sopenharmony_ci} 6448c2ecf20Sopenharmony_cistatic inline unsigned int fib6_rules_seq_read(struct net *net) 6458c2ecf20Sopenharmony_ci{ 6468c2ecf20Sopenharmony_ci return 0; 6478c2ecf20Sopenharmony_ci} 6488c2ecf20Sopenharmony_cistatic inline bool fib6_rules_early_flow_dissect(struct net *net, 6498c2ecf20Sopenharmony_ci struct sk_buff *skb, 6508c2ecf20Sopenharmony_ci struct flowi6 *fl6, 6518c2ecf20Sopenharmony_ci struct flow_keys *flkeys) 6528c2ecf20Sopenharmony_ci{ 6538c2ecf20Sopenharmony_ci return false; 6548c2ecf20Sopenharmony_ci} 6558c2ecf20Sopenharmony_ci#endif 6568c2ecf20Sopenharmony_ci#endif 657