linux/net/ipv6/route.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 *	Linux INET6 implementation
 *	FIB front-end.
 *
 *	Authors:
 *	Pedro Roque		<[email protected]>
 */

/*	Changes:
 *
 *	YOSHIFUJI Hideaki @USAGI
 *		reworked default router selection.
 *		- respect outgoing interface
 *		- select from (probably) reachable routers (i.e.
 *		routers in REACHABLE, STALE, DELAY or PROBE states).
 *		- always select the same router if it is (probably)
 *		reachable.  otherwise, round-robin the list.
 *	Ville Nuorvala
 *		Fixed routing subtrees.
 */

#define pr_fmt(fmt)

#include <linux/capability.h>
#include <linux/errno.h>
#include <linux/export.h>
#include <linux/types.h>
#include <linux/times.h>
#include <linux/socket.h>
#include <linux/sockios.h>
#include <linux/net.h>
#include <linux/route.h>
#include <linux/netdevice.h>
#include <linux/in6.h>
#include <linux/mroute6.h>
#include <linux/init.h>
#include <linux/if_arp.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/nsproxy.h>
#include <linux/slab.h>
#include <linux/jhash.h>
#include <linux/siphash.h>
#include <net/net_namespace.h>
#include <net/snmp.h>
#include <net/ipv6.h>
#include <net/ip6_fib.h>
#include <net/ip6_route.h>
#include <net/ndisc.h>
#include <net/addrconf.h>
#include <net/tcp.h>
#include <linux/rtnetlink.h>
#include <net/dst.h>
#include <net/dst_metadata.h>
#include <net/xfrm.h>
#include <net/netevent.h>
#include <net/netlink.h>
#include <net/rtnh.h>
#include <net/lwtunnel.h>
#include <net/ip_tunnels.h>
#include <net/l3mdev.h>
#include <net/ip.h>
#include <linux/uaccess.h>
#include <linux/btf_ids.h>

#ifdef CONFIG_SYSCTL
#include <linux/sysctl.h>
#endif

static int ip6_rt_type_to_error(u8 fib6_type);

#define CREATE_TRACE_POINTS
#include <trace/events/fib6.h>
EXPORT_TRACEPOINT_SYMBOL_GPL();
#undef CREATE_TRACE_POINTS

enum rt6_nud_state {};

INDIRECT_CALLABLE_SCOPE
struct dst_entry	*ip6_dst_check(struct dst_entry *dst, u32 cookie);
static unsigned int	 ip6_default_advmss(const struct dst_entry *dst);
INDIRECT_CALLABLE_SCOPE
unsigned int		ip6_mtu(const struct dst_entry *dst);
static void		ip6_negative_advice(struct sock *sk,
					    struct dst_entry *dst);
static void		ip6_dst_destroy(struct dst_entry *);
static void		ip6_dst_ifdown(struct dst_entry *,
				       struct net_device *dev);
static void		 ip6_dst_gc(struct dst_ops *ops);

static int		ip6_pkt_discard(struct sk_buff *skb);
static int		ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb);
static int		ip6_pkt_prohibit(struct sk_buff *skb);
static int		ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb);
static void		ip6_link_failure(struct sk_buff *skb);
static void		ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
					   struct sk_buff *skb, u32 mtu,
					   bool confirm_neigh);
static void		rt6_do_redirect(struct dst_entry *dst, struct sock *sk,
					struct sk_buff *skb);
static int rt6_score_route(const struct fib6_nh *nh, u32 fib6_flags, int oif,
			   int strict);
static size_t rt6_nlmsg_size(struct fib6_info *f6i);
static int rt6_fill_node(struct net *net, struct sk_buff *skb,
			 struct fib6_info *rt, struct dst_entry *dst,
			 struct in6_addr *dest, struct in6_addr *src,
			 int iif, int type, u32 portid, u32 seq,
			 unsigned int flags);
static struct rt6_info *rt6_find_cached_rt(const struct fib6_result *res,
					   const struct in6_addr *daddr,
					   const struct in6_addr *saddr);

#ifdef CONFIG_IPV6_ROUTE_INFO
static struct fib6_info *rt6_add_route_info(struct net *net,
					   const struct in6_addr *prefix, int prefixlen,
					   const struct in6_addr *gwaddr,
					   struct net_device *dev,
					   unsigned int pref);
static struct fib6_info *rt6_get_route_info(struct net *net,
					   const struct in6_addr *prefix, int prefixlen,
					   const struct in6_addr *gwaddr,
					   struct net_device *dev);
#endif

struct uncached_list {};

static DEFINE_PER_CPU_ALIGNED(struct uncached_list, rt6_uncached_list);

void rt6_uncached_list_add(struct rt6_info *rt)
{}

void rt6_uncached_list_del(struct rt6_info *rt)
{}

static void rt6_uncached_list_flush_dev(struct net_device *dev)
{}

static inline const void *choose_neigh_daddr(const struct in6_addr *p,
					     struct sk_buff *skb,
					     const void *daddr)
{}

struct neighbour *ip6_neigh_lookup(const struct in6_addr *gw,
				   struct net_device *dev,
				   struct sk_buff *skb,
				   const void *daddr)
{}

static struct neighbour *ip6_dst_neigh_lookup(const struct dst_entry *dst,
					      struct sk_buff *skb,
					      const void *daddr)
{}

static void ip6_confirm_neigh(const struct dst_entry *dst, const void *daddr)
{}

static struct dst_ops ip6_dst_ops_template =;

static struct dst_ops ip6_dst_blackhole_ops =;

static const u32 ip6_template_metrics[RTAX_MAX] =;

static const struct fib6_info fib6_null_entry_template =;

static const struct rt6_info ip6_null_entry_template =;

#ifdef CONFIG_IPV6_MULTIPLE_TABLES

static const struct rt6_info ip6_prohibit_entry_template =;

static const struct rt6_info ip6_blk_hole_entry_template =;

#endif

static void rt6_info_init(struct rt6_info *rt)
{}

/* allocate dst with ip6_dst_ops */
struct rt6_info *ip6_dst_alloc(struct net *net, struct net_device *dev,
			       int flags)
{}
EXPORT_SYMBOL();

static void ip6_dst_destroy(struct dst_entry *dst)
{}

static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev)
{}

static bool __rt6_check_expired(const struct rt6_info *rt)
{}

static bool rt6_check_expired(const struct rt6_info *rt)
{}

void fib6_select_path(const struct net *net, struct fib6_result *res,
		      struct flowi6 *fl6, int oif, bool have_oif_match,
		      const struct sk_buff *skb, int strict)
{}

/*
 *	Route lookup. rcu_read_lock() should be held.
 */

static bool __rt6_device_match(struct net *net, const struct fib6_nh *nh,
			       const struct in6_addr *saddr, int oif, int flags)
{}

struct fib6_nh_dm_arg {};

static int __rt6_nh_dev_match(struct fib6_nh *nh, void *_arg)
{}

/* returns fib6_nh from nexthop or NULL */
static struct fib6_nh *rt6_nh_dev_match(struct net *net, struct nexthop *nh,
					struct fib6_result *res,
					const struct in6_addr *saddr,
					int oif, int flags)
{}

static void rt6_device_match(struct net *net, struct fib6_result *res,
			     const struct in6_addr *saddr, int oif, int flags)
{}

#ifdef CONFIG_IPV6_ROUTER_PREF
struct __rt6_probe_work {};

static void rt6_probe_deferred(struct work_struct *w)
{}

static void rt6_probe(struct fib6_nh *fib6_nh)
{}
#else
static inline void rt6_probe(struct fib6_nh *fib6_nh)
{
}
#endif

/*
 * Default Router Selection (RFC 2461 6.3.6)
 */
static enum rt6_nud_state rt6_check_neigh(const struct fib6_nh *fib6_nh)
{}

static int rt6_score_route(const struct fib6_nh *nh, u32 fib6_flags, int oif,
			   int strict)
{}

static bool find_match(struct fib6_nh *nh, u32 fib6_flags,
		       int oif, int strict, int *mpri, bool *do_rr)
{}

struct fib6_nh_frl_arg {};

static int rt6_nh_find_match(struct fib6_nh *nh, void *_arg)
{}

static void __find_rr_leaf(struct fib6_info *f6i_start,
			   struct fib6_info *nomatch, u32 metric,
			   struct fib6_result *res, struct fib6_info **cont,
			   int oif, int strict, bool *do_rr, int *mpri)
{}

static void find_rr_leaf(struct fib6_node *fn, struct fib6_info *leaf,
			 struct fib6_info *rr_head, int oif, int strict,
			 bool *do_rr, struct fib6_result *res)
{}

static void rt6_select(struct net *net, struct fib6_node *fn, int oif,
		       struct fib6_result *res, int strict)
{}

static bool rt6_is_gw_or_nonexthop(const struct fib6_result *res)
{}

#ifdef CONFIG_IPV6_ROUTE_INFO
int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
		  const struct in6_addr *gwaddr)
{}
#endif

/*
 *	Misc support functions
 */

/* called with rcu_lock held */
static struct net_device *ip6_rt_get_dev_rcu(const struct fib6_result *res)
{}

static const int fib6_prop[RTN_MAX + 1] =;

static int ip6_rt_type_to_error(u8 fib6_type)
{}

static unsigned short fib6_info_dst_flags(struct fib6_info *rt)
{}

static void ip6_rt_init_dst_reject(struct rt6_info *rt, u8 fib6_type)
{}

static void ip6_rt_init_dst(struct rt6_info *rt, const struct fib6_result *res)
{}

/* Caller must already hold reference to @from */
static void rt6_set_from(struct rt6_info *rt, struct fib6_info *from)
{}

/* Caller must already hold reference to f6i in result */
static void ip6_rt_copy_init(struct rt6_info *rt, const struct fib6_result *res)
{}

static struct fib6_node* fib6_backtrack(struct fib6_node *fn,
					struct in6_addr *saddr)
{}

static bool ip6_hold_safe(struct net *net, struct rt6_info **prt)
{}

/* called with rcu_lock held */
static struct rt6_info *ip6_create_rt_rcu(const struct fib6_result *res)
{}

INDIRECT_CALLABLE_SCOPE struct rt6_info *ip6_pol_route_lookup(struct net *net,
					     struct fib6_table *table,
					     struct flowi6 *fl6,
					     const struct sk_buff *skb,
					     int flags)
{}

struct dst_entry *ip6_route_lookup(struct net *net, struct flowi6 *fl6,
				   const struct sk_buff *skb, int flags)
{}
EXPORT_SYMBOL_GPL();

struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr,
			    const struct in6_addr *saddr, int oif,
			    const struct sk_buff *skb, int strict)
{}
EXPORT_SYMBOL();

/* ip6_ins_rt is called with FREE table->tb6_lock.
 * It takes new route entry, the addition fails by any reason the
 * route is released.
 * Caller must hold dst before calling it.
 */

static int __ip6_ins_rt(struct fib6_info *rt, struct nl_info *info,
			struct netlink_ext_ack *extack)
{}

int ip6_ins_rt(struct net *net, struct fib6_info *rt)
{}

static struct rt6_info *ip6_rt_cache_alloc(const struct fib6_result *res,
					   const struct in6_addr *daddr,
					   const struct in6_addr *saddr)
{}

static struct rt6_info *ip6_rt_pcpu_alloc(const struct fib6_result *res)
{}

static bool rt6_is_valid(const struct rt6_info *rt6)
{}

/* It should be called with rcu_read_lock() acquired */
static struct rt6_info *rt6_get_pcpu_route(const struct fib6_result *res)
{}

static struct rt6_info *rt6_make_pcpu_route(struct net *net,
					    const struct fib6_result *res)
{}

/* exception hash table implementation
 */
static DEFINE_SPINLOCK(rt6_exception_lock);

/* Remove rt6_ex from hash table and free the memory
 * Caller must hold rt6_exception_lock
 */
static void rt6_remove_exception(struct rt6_exception_bucket *bucket,
				 struct rt6_exception *rt6_ex)
{}

/* Remove oldest rt6_ex in bucket and free the memory
 * Caller must hold rt6_exception_lock
 */
static void rt6_exception_remove_oldest(struct rt6_exception_bucket *bucket)
{}

static u32 rt6_exception_hash(const struct in6_addr *dst,
			      const struct in6_addr *src)
{}

/* Helper function to find the cached rt in the hash table
 * and update bucket pointer to point to the bucket for this
 * (daddr, saddr) pair
 * Caller must hold rt6_exception_lock
 */
static struct rt6_exception *
__rt6_find_exception_spinlock(struct rt6_exception_bucket **bucket,
			      const struct in6_addr *daddr,
			      const struct in6_addr *saddr)
{}

/* Helper function to find the cached rt in the hash table
 * and update bucket pointer to point to the bucket for this
 * (daddr, saddr) pair
 * Caller must hold rcu_read_lock()
 */
static struct rt6_exception *
__rt6_find_exception_rcu(struct rt6_exception_bucket **bucket,
			 const struct in6_addr *daddr,
			 const struct in6_addr *saddr)
{}

static unsigned int fib6_mtu(const struct fib6_result *res)
{}

#define FIB6_EXCEPTION_BUCKET_FLUSHED

/* used when the flushed bit is not relevant, only access to the bucket
 * (ie., all bucket users except rt6_insert_exception);
 *
 * called under rcu lock; sometimes called with rt6_exception_lock held
 */
static
struct rt6_exception_bucket *fib6_nh_get_excptn_bucket(const struct fib6_nh *nh,
						       spinlock_t *lock)
{}

static bool fib6_nh_excptn_bucket_flushed(struct rt6_exception_bucket *bucket)
{}

/* called with rt6_exception_lock held */
static void fib6_nh_excptn_bucket_set_flushed(struct fib6_nh *nh,
					      spinlock_t *lock)
{}

static int rt6_insert_exception(struct rt6_info *nrt,
				const struct fib6_result *res)
{}

static void fib6_nh_flush_exceptions(struct fib6_nh *nh, struct fib6_info *from)
{}

static int rt6_nh_flush_exceptions(struct fib6_nh *nh, void *arg)
{}

void rt6_flush_exceptions(struct fib6_info *f6i)
{}

/* Find cached rt in the hash table inside passed in rt
 * Caller has to hold rcu_read_lock()
 */
static struct rt6_info *rt6_find_cached_rt(const struct fib6_result *res,
					   const struct in6_addr *daddr,
					   const struct in6_addr *saddr)
{}

/* Remove the passed in cached rt from the hash table that contains it */
static int fib6_nh_remove_exception(const struct fib6_nh *nh, int plen,
				    const struct rt6_info *rt)
{}

struct fib6_nh_excptn_arg {};

static int rt6_nh_remove_exception_rt(struct fib6_nh *nh, void *_arg)
{}

static int rt6_remove_exception_rt(struct rt6_info *rt)
{}

/* Find rt6_ex which contains the passed in rt cache and
 * refresh its stamp
 */
static void fib6_nh_update_exception(const struct fib6_nh *nh, int plen,
				     const struct rt6_info *rt)
{}

struct fib6_nh_match_arg {};

/* determine if fib6_nh has given device and gateway */
static int fib6_nh_find_match(struct fib6_nh *nh, void *_arg)
{}

static void rt6_update_exception_stamp_rt(struct rt6_info *rt)
{}

static bool rt6_mtu_change_route_allowed(struct inet6_dev *idev,
					 struct rt6_info *rt, int mtu)
{}

static void rt6_exceptions_update_pmtu(struct inet6_dev *idev,
				       const struct fib6_nh *nh, int mtu)
{}

#define RTF_CACHE_GATEWAY

static void fib6_nh_exceptions_clean_tohost(const struct fib6_nh *nh,
					    const struct in6_addr *gateway)
{}

static void rt6_age_examine_exception(struct rt6_exception_bucket *bucket,
				      struct rt6_exception *rt6_ex,
				      struct fib6_gc_args *gc_args,
				      unsigned long now)
{}

static void fib6_nh_age_exceptions(const struct fib6_nh *nh,
				   struct fib6_gc_args *gc_args,
				   unsigned long now)
{}

struct fib6_nh_age_excptn_arg {};

static int rt6_nh_age_exceptions(struct fib6_nh *nh, void *_arg)
{}

void rt6_age_exceptions(struct fib6_info *f6i,
			struct fib6_gc_args *gc_args,
			unsigned long now)
{}

/* must be called with rcu lock held */
int fib6_table_lookup(struct net *net, struct fib6_table *table, int oif,
		      struct flowi6 *fl6, struct fib6_result *res, int strict)
{}

struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
			       int oif, struct flowi6 *fl6,
			       const struct sk_buff *skb, int flags)
{}
EXPORT_SYMBOL_GPL();

INDIRECT_CALLABLE_SCOPE struct rt6_info *ip6_pol_route_input(struct net *net,
					    struct fib6_table *table,
					    struct flowi6 *fl6,
					    const struct sk_buff *skb,
					    int flags)
{}

struct dst_entry *ip6_route_input_lookup(struct net *net,
					 struct net_device *dev,
					 struct flowi6 *fl6,
					 const struct sk_buff *skb,
					 int flags)
{}
EXPORT_SYMBOL_GPL();

static void ip6_multipath_l3_keys(const struct sk_buff *skb,
				  struct flow_keys *keys,
				  struct flow_keys *flkeys)
{}

static u32 rt6_multipath_custom_hash_outer(const struct net *net,
					   const struct sk_buff *skb,
					   bool *p_has_inner)
{}

static u32 rt6_multipath_custom_hash_inner(const struct net *net,
					   const struct sk_buff *skb,
					   bool has_inner)
{}

static u32 rt6_multipath_custom_hash_skb(const struct net *net,
					 const struct sk_buff *skb)
{}

static u32 rt6_multipath_custom_hash_fl6(const struct net *net,
					 const struct flowi6 *fl6)
{}

/* if skb is set it will be used and fl6 can be NULL */
u32 rt6_multipath_hash(const struct net *net, const struct flowi6 *fl6,
		       const struct sk_buff *skb, struct flow_keys *flkeys)
{}

/* Called with rcu held */
void ip6_route_input(struct sk_buff *skb)
{}

INDIRECT_CALLABLE_SCOPE struct rt6_info *ip6_pol_route_output(struct net *net,
					     struct fib6_table *table,
					     struct flowi6 *fl6,
					     const struct sk_buff *skb,
					     int flags)
{}

static struct dst_entry *ip6_route_output_flags_noref(struct net *net,
						      const struct sock *sk,
						      struct flowi6 *fl6,
						      int flags)
{}

struct dst_entry *ip6_route_output_flags(struct net *net,
					 const struct sock *sk,
					 struct flowi6 *fl6,
					 int flags)
{}
EXPORT_SYMBOL_GPL();

struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig)
{}

/*
 *	Destination cache support functions
 */

static bool fib6_check(struct fib6_info *f6i, u32 cookie)
{}

static struct dst_entry *rt6_check(struct rt6_info *rt,
				   struct fib6_info *from,
				   u32 cookie)
{}

static struct dst_entry *rt6_dst_from_check(struct rt6_info *rt,
					    struct fib6_info *from,
					    u32 cookie)
{}

INDIRECT_CALLABLE_SCOPE struct dst_entry *ip6_dst_check(struct dst_entry *dst,
							u32 cookie)
{}
EXPORT_INDIRECT_CALLABLE();

static void ip6_negative_advice(struct sock *sk,
				struct dst_entry *dst)
{}

static void ip6_link_failure(struct sk_buff *skb)
{}

static void rt6_update_expires(struct rt6_info *rt0, int timeout)
{}

static void rt6_do_update_pmtu(struct rt6_info *rt, u32 mtu)
{}

static bool rt6_cache_allowed_for_pmtu(const struct rt6_info *rt)
{}

static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
				 const struct ipv6hdr *iph, u32 mtu,
				 bool confirm_neigh)
{}

static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
			       struct sk_buff *skb, u32 mtu,
			       bool confirm_neigh)
{}

void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu,
		     int oif, u32 mark, kuid_t uid)
{}
EXPORT_SYMBOL_GPL();

void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu)
{}
EXPORT_SYMBOL_GPL();

void ip6_sk_dst_store_flow(struct sock *sk, struct dst_entry *dst,
			   const struct flowi6 *fl6)
{}

static bool ip6_redirect_nh_match(const struct fib6_result *res,
				  struct flowi6 *fl6,
				  const struct in6_addr *gw,
				  struct rt6_info **ret)
{}

struct fib6_nh_rd_arg {};

static int fib6_nh_redirect_match(struct fib6_nh *nh, void *_arg)
{}

/* Handle redirects */
struct ip6rd_flowi {};

INDIRECT_CALLABLE_SCOPE struct rt6_info *__ip6_route_redirect(struct net *net,
					     struct fib6_table *table,
					     struct flowi6 *fl6,
					     const struct sk_buff *skb,
					     int flags)
{
	struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl6;
	struct rt6_info *ret = NULL;
	struct fib6_result res = {};
	struct fib6_nh_rd_arg arg = {
		.res = &res,
		.fl6 = fl6,
		.gw  = &rdfl->gateway,
		.ret = &ret
	};
	struct fib6_info *rt;
	struct fib6_node *fn;

	/* Get the "current" route for this destination and
	 * check if the redirect has come from appropriate router.
	 *
	 * RFC 4861 specifies that redirects should only be
	 * accepted if they come from the nexthop to the target.
	 * Due to the way the routes are chosen, this notion
	 * is a bit fuzzy and one might need to check all possible
	 * routes.
	 */

	rcu_read_lock();
	fn = fib6_node_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
restart:
	for_each_fib6_node_rt_rcu(fn) {
		res.f6i = rt;
		if (fib6_check_expired(rt))
			continue;
		if (rt->fib6_flags & RTF_REJECT)
			break;
		if (unlikely(rt->nh)) {
			if (nexthop_is_blackhole(rt->nh))
				continue;
			/* on match, res->nh is filled in and potentially ret */
			if (nexthop_for_each_fib6_nh(rt->nh,
						     fib6_nh_redirect_match,
						     &arg))
				goto out;
		} else {
			res.nh = rt->fib6_nh;
			if (ip6_redirect_nh_match(&res, fl6, &rdfl->gateway,
						  &ret))
				goto out;
		}
	}

	if (!rt)
		rt = net->ipv6.fib6_null_entry;
	else if (rt->fib6_flags & RTF_REJECT) {
		ret = net->ipv6.ip6_null_entry;
		goto out;
	}

	if (rt == net->ipv6.fib6_null_entry) {
		fn = fib6_backtrack(fn, &fl6->saddr);
		if (fn)
			goto restart;
	}

	res.f6i = rt;
	res.nh = rt->fib6_nh;
out:
	if (ret) {
		ip6_hold_safe(net, &ret);
	} else {
		res.fib6_flags = res.f6i->fib6_flags;
		res.fib6_type = res.f6i->fib6_type;
		ret = ip6_create_rt_rcu(&res);
	}

	rcu_read_unlock();

	trace_fib6_table_lookup(net, &res, table, fl6);
	return ret;
};

static struct dst_entry *ip6_route_redirect(struct net *net,
					    const struct flowi6 *fl6,
					    const struct sk_buff *skb,
					    const struct in6_addr *gateway)
{}

void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark,
		  kuid_t uid)
{}
EXPORT_SYMBOL_GPL();

void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif)
{}

void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk)
{}
EXPORT_SYMBOL_GPL();

static unsigned int ip6_default_advmss(const struct dst_entry *dst)
{}

INDIRECT_CALLABLE_SCOPE unsigned int ip6_mtu(const struct dst_entry *dst)
{}
EXPORT_INDIRECT_CALLABLE();

/* MTU selection:
 * 1. mtu on route is locked - use it
 * 2. mtu from nexthop exception
 * 3. mtu from egress device
 *
 * based on ip6_dst_mtu_forward and exception logic of
 * rt6_find_cached_rt; called with rcu_read_lock
 */
u32 ip6_mtu_from_fib6(const struct fib6_result *res,
		      const struct in6_addr *daddr,
		      const struct in6_addr *saddr)
{}

struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
				  struct flowi6 *fl6)
{}

static void ip6_dst_gc(struct dst_ops *ops)
{}

static int ip6_nh_lookup_table(struct net *net, struct fib6_config *cfg,
			       const struct in6_addr *gw_addr, u32 tbid,
			       int flags, struct fib6_result *res)
{}

static int ip6_route_check_nh_onlink(struct net *net,
				     struct fib6_config *cfg,
				     const struct net_device *dev,
				     struct netlink_ext_ack *extack)
{}

static int ip6_route_check_nh(struct net *net,
			      struct fib6_config *cfg,
			      struct net_device **_dev,
			      netdevice_tracker *dev_tracker,
			      struct inet6_dev **idev)
{}

static int ip6_validate_gw(struct net *net, struct fib6_config *cfg,
			   struct net_device **_dev,
			   netdevice_tracker *dev_tracker,
			   struct inet6_dev **idev,
			   struct netlink_ext_ack *extack)
{}

static bool fib6_is_reject(u32 flags, struct net_device *dev, int addr_type)
{}

int fib6_nh_init(struct net *net, struct fib6_nh *fib6_nh,
		 struct fib6_config *cfg, gfp_t gfp_flags,
		 struct netlink_ext_ack *extack)
{}

void fib6_nh_release(struct fib6_nh *fib6_nh)
{}

void fib6_nh_release_dsts(struct fib6_nh *fib6_nh)
{}

static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg,
					      gfp_t gfp_flags,
					      struct netlink_ext_ack *extack)
{}

int ip6_route_add(struct fib6_config *cfg, gfp_t gfp_flags,
		  struct netlink_ext_ack *extack)
{}

static int __ip6_del_rt(struct fib6_info *rt, struct nl_info *info)
{}

int ip6_del_rt(struct net *net, struct fib6_info *rt, bool skip_notify)
{}

static int __ip6_del_rt_siblings(struct fib6_info *rt, struct fib6_config *cfg)
{}

static int __ip6_del_cached_rt(struct rt6_info *rt, struct fib6_config *cfg)
{}

static int ip6_del_cached_rt(struct fib6_config *cfg, struct fib6_info *rt,
			     struct fib6_nh *nh)
{}

struct fib6_nh_del_cached_rt_arg {};

static int fib6_nh_del_cached_rt(struct fib6_nh *nh, void *_arg)
{}

static int ip6_del_cached_rt_nh(struct fib6_config *cfg, struct fib6_info *f6i)
{}

static int ip6_route_del(struct fib6_config *cfg,
			 struct netlink_ext_ack *extack)
{}

static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb)
{}

#ifdef CONFIG_IPV6_ROUTE_INFO
static struct fib6_info *rt6_get_route_info(struct net *net,
					   const struct in6_addr *prefix, int prefixlen,
					   const struct in6_addr *gwaddr,
					   struct net_device *dev)
{}

static struct fib6_info *rt6_add_route_info(struct net *net,
					   const struct in6_addr *prefix, int prefixlen,
					   const struct in6_addr *gwaddr,
					   struct net_device *dev,
					   unsigned int pref)
{}
#endif

struct fib6_info *rt6_get_dflt_router(struct net *net,
				     const struct in6_addr *addr,
				     struct net_device *dev)
{}

struct fib6_info *rt6_add_dflt_router(struct net *net,
				     const struct in6_addr *gwaddr,
				     struct net_device *dev,
				     unsigned int pref,
				     u32 defrtr_usr_metric,
				     int lifetime)
{}

static void __rt6_purge_dflt_routers(struct net *net,
				     struct fib6_table *table)
{}

void rt6_purge_dflt_routers(struct net *net)
{}

static void rtmsg_to_fib6_config(struct net *net,
				 struct in6_rtmsg *rtmsg,
				 struct fib6_config *cfg)
{}

int ipv6_route_ioctl(struct net *net, unsigned int cmd, struct in6_rtmsg *rtmsg)
{}

/*
 *	Drop the packet on the floor
 */

static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes)
{}

static int ip6_pkt_discard(struct sk_buff *skb)
{}

static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb)
{}

static int ip6_pkt_prohibit(struct sk_buff *skb)
{}

static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb)
{}

/*
 *	Allocate a dst for local (unicast / anycast) address.
 */

struct fib6_info *addrconf_f6i_alloc(struct net *net,
				     struct inet6_dev *idev,
				     const struct in6_addr *addr,
				     bool anycast, gfp_t gfp_flags,
				     struct netlink_ext_ack *extack)
{}

/* remove deleted ip from prefsrc entries */
struct arg_dev_net_ip {};

static int fib6_remove_prefsrc(struct fib6_info *rt, void *arg)
{}

void rt6_remove_prefsrc(struct inet6_ifaddr *ifp)
{}

#define RTF_RA_ROUTER

/* Remove routers and update dst entries when gateway turn into host. */
static int fib6_clean_tohost(struct fib6_info *rt, void *arg)
{}

void rt6_clean_tohost(struct net *net, struct in6_addr *gateway)
{}

struct arg_netdev_event {};

static struct fib6_info *rt6_multipath_first_sibling(const struct fib6_info *rt)
{}

/* only called for fib entries with builtin fib6_nh */
static bool rt6_is_dead(const struct fib6_info *rt)
{}

static int rt6_multipath_total_weight(const struct fib6_info *rt)
{}

static void rt6_upper_bound_set(struct fib6_info *rt, int *weight, int total)
{}

static void rt6_multipath_upper_bound_set(struct fib6_info *rt, int total)
{}

void rt6_multipath_rebalance(struct fib6_info *rt)
{}

static int fib6_ifup(struct fib6_info *rt, void *p_arg)
{}

void rt6_sync_up(struct net_device *dev, unsigned char nh_flags)
{}

/* only called for fib entries with inline fib6_nh */
static bool rt6_multipath_uses_dev(const struct fib6_info *rt,
				   const struct net_device *dev)
{}

static void rt6_multipath_flush(struct fib6_info *rt)
{}

static unsigned int rt6_multipath_dead_count(const struct fib6_info *rt,
					     const struct net_device *down_dev)
{}

static void rt6_multipath_nh_flags_set(struct fib6_info *rt,
				       const struct net_device *dev,
				       unsigned char nh_flags)
{}

/* called with write lock held for table with rt */
static int fib6_ifdown(struct fib6_info *rt, void *p_arg)
{}

void rt6_sync_down_dev(struct net_device *dev, unsigned long event)
{}

void rt6_disable_ip(struct net_device *dev, unsigned long event)
{}

struct rt6_mtu_change_arg {};

static int fib6_nh_mtu_change(struct fib6_nh *nh, void *_arg)
{}

static int rt6_mtu_change_route(struct fib6_info *f6i, void *p_arg)
{}

void rt6_mtu_change(struct net_device *dev, unsigned int mtu)
{}

static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] =;

static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
			      struct fib6_config *cfg,
			      struct netlink_ext_ack *extack)
{}

struct rt6_nh {};

static int ip6_route_info_append(struct net *net,
				 struct list_head *rt6_nh_list,
				 struct fib6_info *rt,
				 struct fib6_config *r_cfg)
{}

static void ip6_route_mpath_notify(struct fib6_info *rt,
				   struct fib6_info *rt_last,
				   struct nl_info *info,
				   __u16 nlflags)
{}

static bool ip6_route_mpath_should_notify(const struct fib6_info *rt)
{}

static int fib6_gw_from_attr(struct in6_addr *gw, struct nlattr *nla,
			     struct netlink_ext_ack *extack)
{}

static int ip6_route_multipath_add(struct fib6_config *cfg,
				   struct netlink_ext_ack *extack)
{}

static int ip6_route_multipath_del(struct fib6_config *cfg,
				   struct netlink_ext_ack *extack)
{}

static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh,
			      struct netlink_ext_ack *extack)
{}

static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh,
			      struct netlink_ext_ack *extack)
{}

/* add the overhead of this fib6_nh to nexthop_len */
static int rt6_nh_nlmsg_size(struct fib6_nh *nh, void *arg)
{}

static size_t rt6_nlmsg_size(struct fib6_info *f6i)
{}

static int rt6_fill_node_nexthop(struct sk_buff *skb, struct nexthop *nh,
				 unsigned char *flags)
{}

static int rt6_fill_node(struct net *net, struct sk_buff *skb,
			 struct fib6_info *rt, struct dst_entry *dst,
			 struct in6_addr *dest, struct in6_addr *src,
			 int iif, int type, u32 portid, u32 seq,
			 unsigned int flags)
{}

static int fib6_info_nh_uses_dev(struct fib6_nh *nh, void *arg)
{}

static bool fib6_info_uses_dev(const struct fib6_info *f6i,
			       const struct net_device *dev)
{}

struct fib6_nh_exception_dump_walker {};

static int rt6_nh_dump_exceptions(struct fib6_nh *nh, void *arg)
{}

/* Return -1 if done with node, number of handled routes on partial dump */
int rt6_dump_route(struct fib6_info *rt, void *p_arg, unsigned int skip)
{}

static int inet6_rtm_valid_getroute_req(struct sk_buff *skb,
					const struct nlmsghdr *nlh,
					struct nlattr **tb,
					struct netlink_ext_ack *extack)
{}

static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
			      struct netlink_ext_ack *extack)
{}

void inet6_rt_notify(int event, struct fib6_info *rt, struct nl_info *info,
		     unsigned int nlm_flags)
{}

void fib6_rt_update(struct net *net, struct fib6_info *rt,
		    struct nl_info *info)
{}

void fib6_info_hw_flags_set(struct net *net, struct fib6_info *f6i,
			    bool offload, bool trap, bool offload_failed)
{}
EXPORT_SYMBOL();

static int ip6_route_dev_notify(struct notifier_block *this,
				unsigned long event, void *ptr)
{}

/*
 *	/proc
 */

#ifdef CONFIG_PROC_FS
static int rt6_stats_seq_show(struct seq_file *seq, void *v)
{}
#endif	/* CONFIG_PROC_FS */

#ifdef CONFIG_SYSCTL

static int ipv6_sysctl_rtcache_flush(const struct ctl_table *ctl, int write,
			      void *buffer, size_t *lenp, loff_t *ppos)
{}

static struct ctl_table ipv6_route_table_template[] =;

struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net)
{}

size_t ipv6_route_sysctl_table_size(struct net *net)
{}
#endif

static int __net_init ip6_route_net_init(struct net *net)
{}

static void __net_exit ip6_route_net_exit(struct net *net)
{}

static int __net_init ip6_route_net_init_late(struct net *net)
{}

static void __net_exit ip6_route_net_exit_late(struct net *net)
{}

static struct pernet_operations ip6_route_net_ops =;

static int __net_init ipv6_inetpeer_init(struct net *net)
{}

static void __net_exit ipv6_inetpeer_exit(struct net *net)
{}

static struct pernet_operations ipv6_inetpeer_ops =;

static struct pernet_operations ip6_route_net_late_ops =;

static struct notifier_block ip6_route_dev_notifier =;

void __init ip6_route_init_special_entries(void)
{}

#if IS_BUILTIN(CONFIG_IPV6)
#if defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_PROC_FS)
DEFINE_BPF_ITER_FUNC(ipv6_route, struct bpf_iter_meta *meta, struct fib6_info *rt)

BTF_ID_LIST(btf_fib6_info_id)
BTF_ID()

static const struct bpf_iter_seq_info ipv6_route_seq_info =;

static struct bpf_iter_reg ipv6_route_reg_info =;

static int __init bpf_iter_register(void)
{}

static void bpf_iter_unregister(void)
{}
#endif
#endif

int __init ip6_route_init(void)
{}

void ip6_route_cleanup(void)
{}