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