162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Linux INET6 implementation 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Authors: 662306a36Sopenharmony_ci * Pedro Roque <roque@di.fc.ul.pt> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#ifndef _IP6_FIB_H 1062306a36Sopenharmony_ci#define _IP6_FIB_H 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/ipv6_route.h> 1362306a36Sopenharmony_ci#include <linux/rtnetlink.h> 1462306a36Sopenharmony_ci#include <linux/spinlock.h> 1562306a36Sopenharmony_ci#include <linux/notifier.h> 1662306a36Sopenharmony_ci#include <net/dst.h> 1762306a36Sopenharmony_ci#include <net/flow.h> 1862306a36Sopenharmony_ci#include <net/ip_fib.h> 1962306a36Sopenharmony_ci#include <net/netlink.h> 2062306a36Sopenharmony_ci#include <net/inetpeer.h> 2162306a36Sopenharmony_ci#include <net/fib_notifier.h> 2262306a36Sopenharmony_ci#include <linux/indirect_call_wrapper.h> 2362306a36Sopenharmony_ci#include <uapi/linux/bpf.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#ifdef CONFIG_IPV6_MULTIPLE_TABLES 2662306a36Sopenharmony_ci#define FIB6_TABLE_HASHSZ 256 2762306a36Sopenharmony_ci#else 2862306a36Sopenharmony_ci#define FIB6_TABLE_HASHSZ 1 2962306a36Sopenharmony_ci#endif 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define RT6_DEBUG 2 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#if RT6_DEBUG >= 3 3462306a36Sopenharmony_ci#define RT6_TRACE(x...) pr_debug(x) 3562306a36Sopenharmony_ci#else 3662306a36Sopenharmony_ci#define RT6_TRACE(x...) do { ; } while (0) 3762306a36Sopenharmony_ci#endif 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistruct rt6_info; 4062306a36Sopenharmony_cistruct fib6_info; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistruct fib6_config { 4362306a36Sopenharmony_ci u32 fc_table; 4462306a36Sopenharmony_ci u32 fc_metric; 4562306a36Sopenharmony_ci int fc_dst_len; 4662306a36Sopenharmony_ci int fc_src_len; 4762306a36Sopenharmony_ci int fc_ifindex; 4862306a36Sopenharmony_ci u32 fc_flags; 4962306a36Sopenharmony_ci u32 fc_protocol; 5062306a36Sopenharmony_ci u16 fc_type; /* only 8 bits are used */ 5162306a36Sopenharmony_ci u16 fc_delete_all_nh : 1, 5262306a36Sopenharmony_ci fc_ignore_dev_down:1, 5362306a36Sopenharmony_ci __unused : 14; 5462306a36Sopenharmony_ci u32 fc_nh_id; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci struct in6_addr fc_dst; 5762306a36Sopenharmony_ci struct in6_addr fc_src; 5862306a36Sopenharmony_ci struct in6_addr fc_prefsrc; 5962306a36Sopenharmony_ci struct in6_addr fc_gateway; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci unsigned long fc_expires; 6262306a36Sopenharmony_ci struct nlattr *fc_mx; 6362306a36Sopenharmony_ci int fc_mx_len; 6462306a36Sopenharmony_ci int fc_mp_len; 6562306a36Sopenharmony_ci struct nlattr *fc_mp; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci struct nl_info fc_nlinfo; 6862306a36Sopenharmony_ci struct nlattr *fc_encap; 6962306a36Sopenharmony_ci u16 fc_encap_type; 7062306a36Sopenharmony_ci bool fc_is_fdb; 7162306a36Sopenharmony_ci}; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistruct fib6_node { 7462306a36Sopenharmony_ci struct fib6_node __rcu *parent; 7562306a36Sopenharmony_ci struct fib6_node __rcu *left; 7662306a36Sopenharmony_ci struct fib6_node __rcu *right; 7762306a36Sopenharmony_ci#ifdef CONFIG_IPV6_SUBTREES 7862306a36Sopenharmony_ci struct fib6_node __rcu *subtree; 7962306a36Sopenharmony_ci#endif 8062306a36Sopenharmony_ci struct fib6_info __rcu *leaf; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci __u16 fn_bit; /* bit key */ 8362306a36Sopenharmony_ci __u16 fn_flags; 8462306a36Sopenharmony_ci int fn_sernum; 8562306a36Sopenharmony_ci struct fib6_info __rcu *rr_ptr; 8662306a36Sopenharmony_ci struct rcu_head rcu; 8762306a36Sopenharmony_ci}; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistruct fib6_gc_args { 9062306a36Sopenharmony_ci int timeout; 9162306a36Sopenharmony_ci int more; 9262306a36Sopenharmony_ci}; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci#ifndef CONFIG_IPV6_SUBTREES 9562306a36Sopenharmony_ci#define FIB6_SUBTREE(fn) NULL 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic inline bool fib6_routes_require_src(const struct net *net) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci return false; 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic inline void fib6_routes_require_src_inc(struct net *net) {} 10362306a36Sopenharmony_cistatic inline void fib6_routes_require_src_dec(struct net *net) {} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci#else 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistatic inline bool fib6_routes_require_src(const struct net *net) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci return net->ipv6.fib6_routes_require_src > 0; 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic inline void fib6_routes_require_src_inc(struct net *net) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci net->ipv6.fib6_routes_require_src++; 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic inline void fib6_routes_require_src_dec(struct net *net) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci net->ipv6.fib6_routes_require_src--; 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci#define FIB6_SUBTREE(fn) (rcu_dereference_protected((fn)->subtree, 1)) 12362306a36Sopenharmony_ci#endif 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci/* 12662306a36Sopenharmony_ci * routing information 12762306a36Sopenharmony_ci * 12862306a36Sopenharmony_ci */ 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistruct rt6key { 13162306a36Sopenharmony_ci struct in6_addr addr; 13262306a36Sopenharmony_ci int plen; 13362306a36Sopenharmony_ci}; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistruct fib6_table; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistruct rt6_exception_bucket { 13862306a36Sopenharmony_ci struct hlist_head chain; 13962306a36Sopenharmony_ci int depth; 14062306a36Sopenharmony_ci}; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistruct rt6_exception { 14362306a36Sopenharmony_ci struct hlist_node hlist; 14462306a36Sopenharmony_ci struct rt6_info *rt6i; 14562306a36Sopenharmony_ci unsigned long stamp; 14662306a36Sopenharmony_ci struct rcu_head rcu; 14762306a36Sopenharmony_ci}; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci#define FIB6_EXCEPTION_BUCKET_SIZE_SHIFT 10 15062306a36Sopenharmony_ci#define FIB6_EXCEPTION_BUCKET_SIZE (1 << FIB6_EXCEPTION_BUCKET_SIZE_SHIFT) 15162306a36Sopenharmony_ci#define FIB6_MAX_DEPTH 5 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cistruct fib6_nh { 15462306a36Sopenharmony_ci struct fib_nh_common nh_common; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci#ifdef CONFIG_IPV6_ROUTER_PREF 15762306a36Sopenharmony_ci unsigned long last_probe; 15862306a36Sopenharmony_ci#endif 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci struct rt6_info * __percpu *rt6i_pcpu; 16162306a36Sopenharmony_ci struct rt6_exception_bucket __rcu *rt6i_exception_bucket; 16262306a36Sopenharmony_ci}; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistruct fib6_info { 16562306a36Sopenharmony_ci struct fib6_table *fib6_table; 16662306a36Sopenharmony_ci struct fib6_info __rcu *fib6_next; 16762306a36Sopenharmony_ci struct fib6_node __rcu *fib6_node; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci /* Multipath routes: 17062306a36Sopenharmony_ci * siblings is a list of fib6_info that have the same metric/weight, 17162306a36Sopenharmony_ci * destination, but not the same gateway. nsiblings is just a cache 17262306a36Sopenharmony_ci * to speed up lookup. 17362306a36Sopenharmony_ci */ 17462306a36Sopenharmony_ci union { 17562306a36Sopenharmony_ci struct list_head fib6_siblings; 17662306a36Sopenharmony_ci struct list_head nh_list; 17762306a36Sopenharmony_ci }; 17862306a36Sopenharmony_ci unsigned int fib6_nsiblings; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci refcount_t fib6_ref; 18162306a36Sopenharmony_ci unsigned long expires; 18262306a36Sopenharmony_ci struct dst_metrics *fib6_metrics; 18362306a36Sopenharmony_ci#define fib6_pmtu fib6_metrics->metrics[RTAX_MTU-1] 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci struct rt6key fib6_dst; 18662306a36Sopenharmony_ci u32 fib6_flags; 18762306a36Sopenharmony_ci struct rt6key fib6_src; 18862306a36Sopenharmony_ci struct rt6key fib6_prefsrc; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci u32 fib6_metric; 19162306a36Sopenharmony_ci u8 fib6_protocol; 19262306a36Sopenharmony_ci u8 fib6_type; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci u8 offload; 19562306a36Sopenharmony_ci u8 trap; 19662306a36Sopenharmony_ci u8 offload_failed; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci u8 should_flush:1, 19962306a36Sopenharmony_ci dst_nocount:1, 20062306a36Sopenharmony_ci dst_nopolicy:1, 20162306a36Sopenharmony_ci fib6_destroying:1, 20262306a36Sopenharmony_ci unused:4; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci struct rcu_head rcu; 20562306a36Sopenharmony_ci struct nexthop *nh; 20662306a36Sopenharmony_ci struct fib6_nh fib6_nh[]; 20762306a36Sopenharmony_ci}; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cistruct rt6_info { 21062306a36Sopenharmony_ci struct dst_entry dst; 21162306a36Sopenharmony_ci struct fib6_info __rcu *from; 21262306a36Sopenharmony_ci int sernum; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci struct rt6key rt6i_dst; 21562306a36Sopenharmony_ci struct rt6key rt6i_src; 21662306a36Sopenharmony_ci struct in6_addr rt6i_gateway; 21762306a36Sopenharmony_ci struct inet6_dev *rt6i_idev; 21862306a36Sopenharmony_ci u32 rt6i_flags; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci /* more non-fragment space at head required */ 22162306a36Sopenharmony_ci unsigned short rt6i_nfheader_len; 22262306a36Sopenharmony_ci}; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cistruct fib6_result { 22562306a36Sopenharmony_ci struct fib6_nh *nh; 22662306a36Sopenharmony_ci struct fib6_info *f6i; 22762306a36Sopenharmony_ci u32 fib6_flags; 22862306a36Sopenharmony_ci u8 fib6_type; 22962306a36Sopenharmony_ci struct rt6_info *rt6; 23062306a36Sopenharmony_ci}; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci#define for_each_fib6_node_rt_rcu(fn) \ 23362306a36Sopenharmony_ci for (rt = rcu_dereference((fn)->leaf); rt; \ 23462306a36Sopenharmony_ci rt = rcu_dereference(rt->fib6_next)) 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci#define for_each_fib6_walker_rt(w) \ 23762306a36Sopenharmony_ci for (rt = (w)->leaf; rt; \ 23862306a36Sopenharmony_ci rt = rcu_dereference_protected(rt->fib6_next, 1)) 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_cistatic inline struct inet6_dev *ip6_dst_idev(struct dst_entry *dst) 24162306a36Sopenharmony_ci{ 24262306a36Sopenharmony_ci return ((struct rt6_info *)dst)->rt6i_idev; 24362306a36Sopenharmony_ci} 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_cistatic inline bool fib6_requires_src(const struct fib6_info *rt) 24662306a36Sopenharmony_ci{ 24762306a36Sopenharmony_ci return rt->fib6_src.plen > 0; 24862306a36Sopenharmony_ci} 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_cistatic inline void fib6_clean_expires(struct fib6_info *f6i) 25162306a36Sopenharmony_ci{ 25262306a36Sopenharmony_ci f6i->fib6_flags &= ~RTF_EXPIRES; 25362306a36Sopenharmony_ci f6i->expires = 0; 25462306a36Sopenharmony_ci} 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_cistatic inline void fib6_set_expires(struct fib6_info *f6i, 25762306a36Sopenharmony_ci unsigned long expires) 25862306a36Sopenharmony_ci{ 25962306a36Sopenharmony_ci f6i->expires = expires; 26062306a36Sopenharmony_ci f6i->fib6_flags |= RTF_EXPIRES; 26162306a36Sopenharmony_ci} 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_cistatic inline bool fib6_check_expired(const struct fib6_info *f6i) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci if (f6i->fib6_flags & RTF_EXPIRES) 26662306a36Sopenharmony_ci return time_after(jiffies, f6i->expires); 26762306a36Sopenharmony_ci return false; 26862306a36Sopenharmony_ci} 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci/* Function to safely get fn->fn_sernum for passed in rt 27162306a36Sopenharmony_ci * and store result in passed in cookie. 27262306a36Sopenharmony_ci * Return true if we can get cookie safely 27362306a36Sopenharmony_ci * Return false if not 27462306a36Sopenharmony_ci */ 27562306a36Sopenharmony_cistatic inline bool fib6_get_cookie_safe(const struct fib6_info *f6i, 27662306a36Sopenharmony_ci u32 *cookie) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci struct fib6_node *fn; 27962306a36Sopenharmony_ci bool status = false; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci fn = rcu_dereference(f6i->fib6_node); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci if (fn) { 28462306a36Sopenharmony_ci *cookie = READ_ONCE(fn->fn_sernum); 28562306a36Sopenharmony_ci /* pairs with smp_wmb() in __fib6_update_sernum_upto_root() */ 28662306a36Sopenharmony_ci smp_rmb(); 28762306a36Sopenharmony_ci status = true; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci return status; 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistatic inline u32 rt6_get_cookie(const struct rt6_info *rt) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci struct fib6_info *from; 29662306a36Sopenharmony_ci u32 cookie = 0; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci if (rt->sernum) 29962306a36Sopenharmony_ci return rt->sernum; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci rcu_read_lock(); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci from = rcu_dereference(rt->from); 30462306a36Sopenharmony_ci if (from) 30562306a36Sopenharmony_ci fib6_get_cookie_safe(from, &cookie); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci rcu_read_unlock(); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci return cookie; 31062306a36Sopenharmony_ci} 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_cistatic inline void ip6_rt_put(struct rt6_info *rt) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci /* dst_release() accepts a NULL parameter. 31562306a36Sopenharmony_ci * We rely on dst being first structure in struct rt6_info 31662306a36Sopenharmony_ci */ 31762306a36Sopenharmony_ci BUILD_BUG_ON(offsetof(struct rt6_info, dst) != 0); 31862306a36Sopenharmony_ci dst_release(&rt->dst); 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistruct fib6_info *fib6_info_alloc(gfp_t gfp_flags, bool with_fib6_nh); 32262306a36Sopenharmony_civoid fib6_info_destroy_rcu(struct rcu_head *head); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_cistatic inline void fib6_info_hold(struct fib6_info *f6i) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci refcount_inc(&f6i->fib6_ref); 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_cistatic inline bool fib6_info_hold_safe(struct fib6_info *f6i) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci return refcount_inc_not_zero(&f6i->fib6_ref); 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cistatic inline void fib6_info_release(struct fib6_info *f6i) 33562306a36Sopenharmony_ci{ 33662306a36Sopenharmony_ci if (f6i && refcount_dec_and_test(&f6i->fib6_ref)) 33762306a36Sopenharmony_ci call_rcu(&f6i->rcu, fib6_info_destroy_rcu); 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_cienum fib6_walk_state { 34162306a36Sopenharmony_ci#ifdef CONFIG_IPV6_SUBTREES 34262306a36Sopenharmony_ci FWS_S, 34362306a36Sopenharmony_ci#endif 34462306a36Sopenharmony_ci FWS_L, 34562306a36Sopenharmony_ci FWS_R, 34662306a36Sopenharmony_ci FWS_C, 34762306a36Sopenharmony_ci FWS_U 34862306a36Sopenharmony_ci}; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_cistruct fib6_walker { 35162306a36Sopenharmony_ci struct list_head lh; 35262306a36Sopenharmony_ci struct fib6_node *root, *node; 35362306a36Sopenharmony_ci struct fib6_info *leaf; 35462306a36Sopenharmony_ci enum fib6_walk_state state; 35562306a36Sopenharmony_ci unsigned int skip; 35662306a36Sopenharmony_ci unsigned int count; 35762306a36Sopenharmony_ci unsigned int skip_in_node; 35862306a36Sopenharmony_ci int (*func)(struct fib6_walker *); 35962306a36Sopenharmony_ci void *args; 36062306a36Sopenharmony_ci}; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_cistruct rt6_statistics { 36362306a36Sopenharmony_ci __u32 fib_nodes; /* all fib6 nodes */ 36462306a36Sopenharmony_ci __u32 fib_route_nodes; /* intermediate nodes */ 36562306a36Sopenharmony_ci __u32 fib_rt_entries; /* rt entries in fib table */ 36662306a36Sopenharmony_ci __u32 fib_rt_cache; /* cached rt entries in exception table */ 36762306a36Sopenharmony_ci __u32 fib_discarded_routes; /* total number of routes delete */ 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci /* The following stat is not protected by any lock */ 37062306a36Sopenharmony_ci atomic_t fib_rt_alloc; /* total number of routes alloced */ 37162306a36Sopenharmony_ci}; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci#define RTN_TL_ROOT 0x0001 37462306a36Sopenharmony_ci#define RTN_ROOT 0x0002 /* tree root node */ 37562306a36Sopenharmony_ci#define RTN_RTINFO 0x0004 /* node with valid routing info */ 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci/* 37862306a36Sopenharmony_ci * priority levels (or metrics) 37962306a36Sopenharmony_ci * 38062306a36Sopenharmony_ci */ 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_cistruct fib6_table { 38462306a36Sopenharmony_ci struct hlist_node tb6_hlist; 38562306a36Sopenharmony_ci u32 tb6_id; 38662306a36Sopenharmony_ci spinlock_t tb6_lock; 38762306a36Sopenharmony_ci struct fib6_node tb6_root; 38862306a36Sopenharmony_ci struct inet_peer_base tb6_peers; 38962306a36Sopenharmony_ci unsigned int flags; 39062306a36Sopenharmony_ci unsigned int fib_seq; 39162306a36Sopenharmony_ci#define RT6_TABLE_HAS_DFLT_ROUTER BIT(0) 39262306a36Sopenharmony_ci}; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci#define RT6_TABLE_UNSPEC RT_TABLE_UNSPEC 39562306a36Sopenharmony_ci#define RT6_TABLE_MAIN RT_TABLE_MAIN 39662306a36Sopenharmony_ci#define RT6_TABLE_DFLT RT6_TABLE_MAIN 39762306a36Sopenharmony_ci#define RT6_TABLE_INFO RT6_TABLE_MAIN 39862306a36Sopenharmony_ci#define RT6_TABLE_PREFIX RT6_TABLE_MAIN 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci#ifdef CONFIG_IPV6_MULTIPLE_TABLES 40162306a36Sopenharmony_ci#define FIB6_TABLE_MIN 1 40262306a36Sopenharmony_ci#define FIB6_TABLE_MAX RT_TABLE_MAX 40362306a36Sopenharmony_ci#define RT6_TABLE_LOCAL RT_TABLE_LOCAL 40462306a36Sopenharmony_ci#else 40562306a36Sopenharmony_ci#define FIB6_TABLE_MIN RT_TABLE_MAIN 40662306a36Sopenharmony_ci#define FIB6_TABLE_MAX FIB6_TABLE_MIN 40762306a36Sopenharmony_ci#define RT6_TABLE_LOCAL RT6_TABLE_MAIN 40862306a36Sopenharmony_ci#endif 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_citypedef struct rt6_info *(*pol_lookup_t)(struct net *, 41162306a36Sopenharmony_ci struct fib6_table *, 41262306a36Sopenharmony_ci struct flowi6 *, 41362306a36Sopenharmony_ci const struct sk_buff *, int); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cistruct fib6_entry_notifier_info { 41662306a36Sopenharmony_ci struct fib_notifier_info info; /* must be first */ 41762306a36Sopenharmony_ci struct fib6_info *rt; 41862306a36Sopenharmony_ci unsigned int nsiblings; 41962306a36Sopenharmony_ci}; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci/* 42262306a36Sopenharmony_ci * exported functions 42362306a36Sopenharmony_ci */ 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_cistruct fib6_table *fib6_get_table(struct net *net, u32 id); 42662306a36Sopenharmony_cistruct fib6_table *fib6_new_table(struct net *net, u32 id); 42762306a36Sopenharmony_cistruct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6, 42862306a36Sopenharmony_ci const struct sk_buff *skb, 42962306a36Sopenharmony_ci int flags, pol_lookup_t lookup); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci/* called with rcu lock held; can return error pointer 43262306a36Sopenharmony_ci * caller needs to select path 43362306a36Sopenharmony_ci */ 43462306a36Sopenharmony_ciint fib6_lookup(struct net *net, int oif, struct flowi6 *fl6, 43562306a36Sopenharmony_ci struct fib6_result *res, int flags); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci/* called with rcu lock held; caller needs to select path */ 43862306a36Sopenharmony_ciint fib6_table_lookup(struct net *net, struct fib6_table *table, 43962306a36Sopenharmony_ci int oif, struct flowi6 *fl6, struct fib6_result *res, 44062306a36Sopenharmony_ci int strict); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_civoid fib6_select_path(const struct net *net, struct fib6_result *res, 44362306a36Sopenharmony_ci struct flowi6 *fl6, int oif, bool have_oif_match, 44462306a36Sopenharmony_ci const struct sk_buff *skb, int strict); 44562306a36Sopenharmony_cistruct fib6_node *fib6_node_lookup(struct fib6_node *root, 44662306a36Sopenharmony_ci const struct in6_addr *daddr, 44762306a36Sopenharmony_ci const struct in6_addr *saddr); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_cistruct fib6_node *fib6_locate(struct fib6_node *root, 45062306a36Sopenharmony_ci const struct in6_addr *daddr, int dst_len, 45162306a36Sopenharmony_ci const struct in6_addr *saddr, int src_len, 45262306a36Sopenharmony_ci bool exact_match); 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_civoid fib6_clean_all(struct net *net, int (*func)(struct fib6_info *, void *arg), 45562306a36Sopenharmony_ci void *arg); 45662306a36Sopenharmony_civoid fib6_clean_all_skip_notify(struct net *net, 45762306a36Sopenharmony_ci int (*func)(struct fib6_info *, void *arg), 45862306a36Sopenharmony_ci void *arg); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ciint fib6_add(struct fib6_node *root, struct fib6_info *rt, 46162306a36Sopenharmony_ci struct nl_info *info, struct netlink_ext_ack *extack); 46262306a36Sopenharmony_ciint fib6_del(struct fib6_info *rt, struct nl_info *info); 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_cistatic inline 46562306a36Sopenharmony_civoid rt6_get_prefsrc(const struct rt6_info *rt, struct in6_addr *addr) 46662306a36Sopenharmony_ci{ 46762306a36Sopenharmony_ci const struct fib6_info *from; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci rcu_read_lock(); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci from = rcu_dereference(rt->from); 47262306a36Sopenharmony_ci if (from) 47362306a36Sopenharmony_ci *addr = from->fib6_prefsrc.addr; 47462306a36Sopenharmony_ci else 47562306a36Sopenharmony_ci *addr = in6addr_any; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci rcu_read_unlock(); 47862306a36Sopenharmony_ci} 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ciint fib6_nh_init(struct net *net, struct fib6_nh *fib6_nh, 48162306a36Sopenharmony_ci struct fib6_config *cfg, gfp_t gfp_flags, 48262306a36Sopenharmony_ci struct netlink_ext_ack *extack); 48362306a36Sopenharmony_civoid fib6_nh_release(struct fib6_nh *fib6_nh); 48462306a36Sopenharmony_civoid fib6_nh_release_dsts(struct fib6_nh *fib6_nh); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ciint call_fib6_entry_notifiers(struct net *net, 48762306a36Sopenharmony_ci enum fib_event_type event_type, 48862306a36Sopenharmony_ci struct fib6_info *rt, 48962306a36Sopenharmony_ci struct netlink_ext_ack *extack); 49062306a36Sopenharmony_ciint call_fib6_multipath_entry_notifiers(struct net *net, 49162306a36Sopenharmony_ci enum fib_event_type event_type, 49262306a36Sopenharmony_ci struct fib6_info *rt, 49362306a36Sopenharmony_ci unsigned int nsiblings, 49462306a36Sopenharmony_ci struct netlink_ext_ack *extack); 49562306a36Sopenharmony_ciint call_fib6_entry_notifiers_replace(struct net *net, struct fib6_info *rt); 49662306a36Sopenharmony_civoid fib6_rt_update(struct net *net, struct fib6_info *rt, 49762306a36Sopenharmony_ci struct nl_info *info); 49862306a36Sopenharmony_civoid inet6_rt_notify(int event, struct fib6_info *rt, struct nl_info *info, 49962306a36Sopenharmony_ci unsigned int flags); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_civoid fib6_run_gc(unsigned long expires, struct net *net, bool force); 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_civoid fib6_gc_cleanup(void); 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ciint fib6_init(void); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_cistruct ipv6_route_iter { 50862306a36Sopenharmony_ci struct seq_net_private p; 50962306a36Sopenharmony_ci struct fib6_walker w; 51062306a36Sopenharmony_ci loff_t skip; 51162306a36Sopenharmony_ci struct fib6_table *tbl; 51262306a36Sopenharmony_ci int sernum; 51362306a36Sopenharmony_ci}; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ciextern const struct seq_operations ipv6_route_seq_ops; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ciint call_fib6_notifier(struct notifier_block *nb, 51862306a36Sopenharmony_ci enum fib_event_type event_type, 51962306a36Sopenharmony_ci struct fib_notifier_info *info); 52062306a36Sopenharmony_ciint call_fib6_notifiers(struct net *net, enum fib_event_type event_type, 52162306a36Sopenharmony_ci struct fib_notifier_info *info); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ciint __net_init fib6_notifier_init(struct net *net); 52462306a36Sopenharmony_civoid __net_exit fib6_notifier_exit(struct net *net); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ciunsigned int fib6_tables_seq_read(struct net *net); 52762306a36Sopenharmony_ciint fib6_tables_dump(struct net *net, struct notifier_block *nb, 52862306a36Sopenharmony_ci struct netlink_ext_ack *extack); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_civoid fib6_update_sernum(struct net *net, struct fib6_info *rt); 53162306a36Sopenharmony_civoid fib6_update_sernum_upto_root(struct net *net, struct fib6_info *rt); 53262306a36Sopenharmony_civoid fib6_update_sernum_stub(struct net *net, struct fib6_info *f6i); 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_civoid fib6_metric_set(struct fib6_info *f6i, int metric, u32 val); 53562306a36Sopenharmony_cistatic inline bool fib6_metric_locked(struct fib6_info *f6i, int metric) 53662306a36Sopenharmony_ci{ 53762306a36Sopenharmony_ci return !!(f6i->fib6_metrics->metrics[RTAX_LOCK - 1] & (1 << metric)); 53862306a36Sopenharmony_ci} 53962306a36Sopenharmony_civoid fib6_info_hw_flags_set(struct net *net, struct fib6_info *f6i, 54062306a36Sopenharmony_ci bool offload, bool trap, bool offload_failed); 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci#if IS_BUILTIN(CONFIG_IPV6) && defined(CONFIG_BPF_SYSCALL) 54362306a36Sopenharmony_cistruct bpf_iter__ipv6_route { 54462306a36Sopenharmony_ci __bpf_md_ptr(struct bpf_iter_meta *, meta); 54562306a36Sopenharmony_ci __bpf_md_ptr(struct fib6_info *, rt); 54662306a36Sopenharmony_ci}; 54762306a36Sopenharmony_ci#endif 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ciINDIRECT_CALLABLE_DECLARE(struct rt6_info *ip6_pol_route_output(struct net *net, 55062306a36Sopenharmony_ci struct fib6_table *table, 55162306a36Sopenharmony_ci struct flowi6 *fl6, 55262306a36Sopenharmony_ci const struct sk_buff *skb, 55362306a36Sopenharmony_ci int flags)); 55462306a36Sopenharmony_ciINDIRECT_CALLABLE_DECLARE(struct rt6_info *ip6_pol_route_input(struct net *net, 55562306a36Sopenharmony_ci struct fib6_table *table, 55662306a36Sopenharmony_ci struct flowi6 *fl6, 55762306a36Sopenharmony_ci const struct sk_buff *skb, 55862306a36Sopenharmony_ci int flags)); 55962306a36Sopenharmony_ciINDIRECT_CALLABLE_DECLARE(struct rt6_info *__ip6_route_redirect(struct net *net, 56062306a36Sopenharmony_ci struct fib6_table *table, 56162306a36Sopenharmony_ci struct flowi6 *fl6, 56262306a36Sopenharmony_ci const struct sk_buff *skb, 56362306a36Sopenharmony_ci int flags)); 56462306a36Sopenharmony_ciINDIRECT_CALLABLE_DECLARE(struct rt6_info *ip6_pol_route_lookup(struct net *net, 56562306a36Sopenharmony_ci struct fib6_table *table, 56662306a36Sopenharmony_ci struct flowi6 *fl6, 56762306a36Sopenharmony_ci const struct sk_buff *skb, 56862306a36Sopenharmony_ci int flags)); 56962306a36Sopenharmony_cistatic inline struct rt6_info *pol_lookup_func(pol_lookup_t lookup, 57062306a36Sopenharmony_ci struct net *net, 57162306a36Sopenharmony_ci struct fib6_table *table, 57262306a36Sopenharmony_ci struct flowi6 *fl6, 57362306a36Sopenharmony_ci const struct sk_buff *skb, 57462306a36Sopenharmony_ci int flags) 57562306a36Sopenharmony_ci{ 57662306a36Sopenharmony_ci return INDIRECT_CALL_4(lookup, 57762306a36Sopenharmony_ci ip6_pol_route_output, 57862306a36Sopenharmony_ci ip6_pol_route_input, 57962306a36Sopenharmony_ci ip6_pol_route_lookup, 58062306a36Sopenharmony_ci __ip6_route_redirect, 58162306a36Sopenharmony_ci net, table, fl6, skb, flags); 58262306a36Sopenharmony_ci} 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci#ifdef CONFIG_IPV6_MULTIPLE_TABLES 58562306a36Sopenharmony_cistatic inline bool fib6_has_custom_rules(const struct net *net) 58662306a36Sopenharmony_ci{ 58762306a36Sopenharmony_ci return net->ipv6.fib6_has_custom_rules; 58862306a36Sopenharmony_ci} 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ciint fib6_rules_init(void); 59162306a36Sopenharmony_civoid fib6_rules_cleanup(void); 59262306a36Sopenharmony_cibool fib6_rule_default(const struct fib_rule *rule); 59362306a36Sopenharmony_ciint fib6_rules_dump(struct net *net, struct notifier_block *nb, 59462306a36Sopenharmony_ci struct netlink_ext_ack *extack); 59562306a36Sopenharmony_ciunsigned int fib6_rules_seq_read(struct net *net); 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_cistatic inline bool fib6_rules_early_flow_dissect(struct net *net, 59862306a36Sopenharmony_ci struct sk_buff *skb, 59962306a36Sopenharmony_ci struct flowi6 *fl6, 60062306a36Sopenharmony_ci struct flow_keys *flkeys) 60162306a36Sopenharmony_ci{ 60262306a36Sopenharmony_ci unsigned int flag = FLOW_DISSECTOR_F_STOP_AT_ENCAP; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci if (!net->ipv6.fib6_rules_require_fldissect) 60562306a36Sopenharmony_ci return false; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci memset(flkeys, 0, sizeof(*flkeys)); 60862306a36Sopenharmony_ci __skb_flow_dissect(net, skb, &flow_keys_dissector, 60962306a36Sopenharmony_ci flkeys, NULL, 0, 0, 0, flag); 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci fl6->fl6_sport = flkeys->ports.src; 61262306a36Sopenharmony_ci fl6->fl6_dport = flkeys->ports.dst; 61362306a36Sopenharmony_ci fl6->flowi6_proto = flkeys->basic.ip_proto; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci return true; 61662306a36Sopenharmony_ci} 61762306a36Sopenharmony_ci#else 61862306a36Sopenharmony_cistatic inline bool fib6_has_custom_rules(const struct net *net) 61962306a36Sopenharmony_ci{ 62062306a36Sopenharmony_ci return false; 62162306a36Sopenharmony_ci} 62262306a36Sopenharmony_cistatic inline int fib6_rules_init(void) 62362306a36Sopenharmony_ci{ 62462306a36Sopenharmony_ci return 0; 62562306a36Sopenharmony_ci} 62662306a36Sopenharmony_cistatic inline void fib6_rules_cleanup(void) 62762306a36Sopenharmony_ci{ 62862306a36Sopenharmony_ci return ; 62962306a36Sopenharmony_ci} 63062306a36Sopenharmony_cistatic inline bool fib6_rule_default(const struct fib_rule *rule) 63162306a36Sopenharmony_ci{ 63262306a36Sopenharmony_ci return true; 63362306a36Sopenharmony_ci} 63462306a36Sopenharmony_cistatic inline int fib6_rules_dump(struct net *net, struct notifier_block *nb, 63562306a36Sopenharmony_ci struct netlink_ext_ack *extack) 63662306a36Sopenharmony_ci{ 63762306a36Sopenharmony_ci return 0; 63862306a36Sopenharmony_ci} 63962306a36Sopenharmony_cistatic inline unsigned int fib6_rules_seq_read(struct net *net) 64062306a36Sopenharmony_ci{ 64162306a36Sopenharmony_ci return 0; 64262306a36Sopenharmony_ci} 64362306a36Sopenharmony_cistatic inline bool fib6_rules_early_flow_dissect(struct net *net, 64462306a36Sopenharmony_ci struct sk_buff *skb, 64562306a36Sopenharmony_ci struct flowi6 *fl6, 64662306a36Sopenharmony_ci struct flow_keys *flkeys) 64762306a36Sopenharmony_ci{ 64862306a36Sopenharmony_ci return false; 64962306a36Sopenharmony_ci} 65062306a36Sopenharmony_ci#endif 65162306a36Sopenharmony_ci#endif 652