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