linux/net/ipv6/ip6_fib.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 *	Linux INET6 implementation
 *	Forwarding Information Database
 *
 *	Authors:
 *	Pedro Roque		<[email protected]>
 *
 *	Changes:
 *	Yuji SEKIYA @USAGI:	Support default route on router node;
 *				remove ip6_null_entry from the top of
 *				routing table.
 *	Ville Nuorvala:		Fixed routing subtrees.
 */

#define pr_fmt(fmt)

#include <linux/bpf.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/net.h>
#include <linux/route.h>
#include <linux/netdevice.h>
#include <linux/in6.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/slab.h>

#include <net/ip.h>
#include <net/ipv6.h>
#include <net/ndisc.h>
#include <net/addrconf.h>
#include <net/lwtunnel.h>
#include <net/fib_notifier.h>

#include <net/ip_fib.h>
#include <net/ip6_fib.h>
#include <net/ip6_route.h>

static struct kmem_cache *fib6_node_kmem __read_mostly;

struct fib6_cleaner {};

#ifdef CONFIG_IPV6_SUBTREES
#define FWS_INIT
#else
#define FWS_INIT
#endif

static struct fib6_info *fib6_find_prefix(struct net *net,
					 struct fib6_table *table,
					 struct fib6_node *fn);
static struct fib6_node *fib6_repair_tree(struct net *net,
					  struct fib6_table *table,
					  struct fib6_node *fn);
static int fib6_walk(struct net *net, struct fib6_walker *w);
static int fib6_walk_continue(struct fib6_walker *w);

/*
 *	A routing update causes an increase of the serial number on the
 *	affected subtree. This allows for cached routes to be asynchronously
 *	tested when modifications are made to the destination cache as a
 *	result of redirects, path MTU changes, etc.
 */

static void fib6_gc_timer_cb(struct timer_list *t);

#define FOR_WALKERS(net, w)

static void fib6_walker_link(struct net *net, struct fib6_walker *w)
{}

static void fib6_walker_unlink(struct net *net, struct fib6_walker *w)
{}

static int fib6_new_sernum(struct net *net)
{}

enum {};

void fib6_update_sernum(struct net *net, struct fib6_info *f6i)
{}

/*
 *	Auxiliary address test functions for the radix tree.
 *
 *	These assume a 32bit processor (although it will work on
 *	64bit processors)
 */

/*
 *	test bit
 */
#if defined(__LITTLE_ENDIAN)
#define BITOP_BE32_SWIZZLE
#else
#define BITOP_BE32_SWIZZLE
#endif

static __be32 addr_bit_set(const void *token, int fn_bit)
{}

struct fib6_info *fib6_info_alloc(gfp_t gfp_flags, bool with_fib6_nh)
{}

void fib6_info_destroy_rcu(struct rcu_head *head)
{}
EXPORT_SYMBOL_GPL();

static struct fib6_node *node_alloc(struct net *net)
{}

static void node_free_immediate(struct net *net, struct fib6_node *fn)
{}

static void node_free_rcu(struct rcu_head *head)
{}

static void node_free(struct net *net, struct fib6_node *fn)
{}

static void fib6_free_table(struct fib6_table *table)
{}

static void fib6_link_table(struct net *net, struct fib6_table *tb)
{}

#ifdef CONFIG_IPV6_MULTIPLE_TABLES

static struct fib6_table *fib6_alloc_table(struct net *net, u32 id)
{}

struct fib6_table *fib6_new_table(struct net *net, u32 id)
{}
EXPORT_SYMBOL_GPL();

struct fib6_table *fib6_get_table(struct net *net, u32 id)
{}
EXPORT_SYMBOL_GPL();

static void __net_init fib6_tables_init(struct net *net)
{}
#else

struct fib6_table *fib6_new_table(struct net *net, u32 id)
{
	return fib6_get_table(net, id);
}

struct fib6_table *fib6_get_table(struct net *net, u32 id)
{
	  return net->ipv6.fib6_main_tbl;
}

struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6,
				   const struct sk_buff *skb,
				   int flags, pol_lookup_t lookup)
{
	struct rt6_info *rt;

	rt = pol_lookup_func(lookup,
			net, net->ipv6.fib6_main_tbl, fl6, skb, flags);
	if (rt->dst.error == -EAGAIN) {
		ip6_rt_put_flags(rt, flags);
		rt = net->ipv6.ip6_null_entry;
		if (!(flags & RT6_LOOKUP_F_DST_NOREF))
			dst_hold(&rt->dst);
	}

	return &rt->dst;
}

/* called with rcu lock held; no reference taken on fib6_info */
int fib6_lookup(struct net *net, int oif, struct flowi6 *fl6,
		struct fib6_result *res, int flags)
{
	return fib6_table_lookup(net, net->ipv6.fib6_main_tbl, oif, fl6,
				 res, flags);
}

static void __net_init fib6_tables_init(struct net *net)
{
	fib6_link_table(net, net->ipv6.fib6_main_tbl);
}

#endif

unsigned int fib6_tables_seq_read(struct net *net)
{}

static int call_fib6_entry_notifier(struct notifier_block *nb,
				    enum fib_event_type event_type,
				    struct fib6_info *rt,
				    struct netlink_ext_ack *extack)
{}

static int call_fib6_multipath_entry_notifier(struct notifier_block *nb,
					      enum fib_event_type event_type,
					      struct fib6_info *rt,
					      unsigned int nsiblings,
					      struct netlink_ext_ack *extack)
{}

int call_fib6_entry_notifiers(struct net *net,
			      enum fib_event_type event_type,
			      struct fib6_info *rt,
			      struct netlink_ext_ack *extack)
{}

int call_fib6_multipath_entry_notifiers(struct net *net,
					enum fib_event_type event_type,
					struct fib6_info *rt,
					unsigned int nsiblings,
					struct netlink_ext_ack *extack)
{}

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

struct fib6_dump_arg {};

static int fib6_rt_dump(struct fib6_info *rt, struct fib6_dump_arg *arg)
{}

static int fib6_node_dump(struct fib6_walker *w)
{}

static int fib6_table_dump(struct net *net, struct fib6_table *tb,
			   struct fib6_walker *w)
{}

/* Called with rcu_read_lock() */
int fib6_tables_dump(struct net *net, struct notifier_block *nb,
		     struct netlink_ext_ack *extack)
{}

static int fib6_dump_node(struct fib6_walker *w)
{}

static void fib6_dump_end(struct netlink_callback *cb)
{}

static int fib6_dump_done(struct netlink_callback *cb)
{}

static int fib6_dump_table(struct fib6_table *table, struct sk_buff *skb,
			   struct netlink_callback *cb)
{}

static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
{}

void fib6_metric_set(struct fib6_info *f6i, int metric, u32 val)
{}

/*
 *	Routing Table
 *
 *	return the appropriate node for a routing tree "add" operation
 *	by either creating and inserting or by returning an existing
 *	node.
 */

static struct fib6_node *fib6_add_1(struct net *net,
				    struct fib6_table *table,
				    struct fib6_node *root,
				    struct in6_addr *addr, int plen,
				    int offset, int allow_create,
				    int replace_required,
				    struct netlink_ext_ack *extack)
{}

static void __fib6_drop_pcpu_from(struct fib6_nh *fib6_nh,
				  const struct fib6_info *match,
				  const struct fib6_table *table)
{}

struct fib6_nh_pcpu_arg {};

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

static void fib6_drop_pcpu_from(struct fib6_info *f6i,
				const struct fib6_table *table)
{}

static void fib6_purge_rt(struct fib6_info *rt, struct fib6_node *fn,
			  struct net *net)
{}

/*
 *	Insert routing information in a node.
 */

static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt,
			    struct nl_info *info,
			    struct netlink_ext_ack *extack)
{}

static void fib6_start_gc(struct net *net, struct fib6_info *rt)
{}

void fib6_force_start_gc(struct net *net)
{}

static void __fib6_update_sernum_upto_root(struct fib6_info *rt,
					   int sernum)
{}

void fib6_update_sernum_upto_root(struct net *net, struct fib6_info *rt)
{}

/* allow ipv4 to update sernum via ipv6_stub */
void fib6_update_sernum_stub(struct net *net, struct fib6_info *f6i)
{}

/*
 *	Add routing information to the routing tree.
 *	<destination addr>/<source addr>
 *	with source addr info in sub-trees
 *	Need to own table->tb6_lock
 */

int fib6_add(struct fib6_node *root, struct fib6_info *rt,
	     struct nl_info *info, struct netlink_ext_ack *extack)
{}

/*
 *	Routing tree lookup
 *
 */

struct lookup_args {};

static struct fib6_node *fib6_node_lookup_1(struct fib6_node *root,
					    struct lookup_args *args)
{}

/* called with rcu_read_lock() held
 */
struct fib6_node *fib6_node_lookup(struct fib6_node *root,
				   const struct in6_addr *daddr,
				   const struct in6_addr *saddr)
{}

/*
 *	Get node with specified destination prefix (and source prefix,
 *	if subtrees are used)
 *	exact_match == true means we try to find fn with exact match of
 *	the passed in prefix addr
 *	exact_match == false means we try to find fn with longest prefix
 *	match of the passed in prefix addr. This is useful for finding fn
 *	for cached route as it will be stored in the exception table under
 *	the node with longest prefix length.
 */


static struct fib6_node *fib6_locate_1(struct fib6_node *root,
				       const struct in6_addr *addr,
				       int plen, int offset,
				       bool exact_match)
{}

struct fib6_node *fib6_locate(struct fib6_node *root,
			      const struct in6_addr *daddr, int dst_len,
			      const struct in6_addr *saddr, int src_len,
			      bool exact_match)
{}


/*
 *	Deletion
 *
 */

static struct fib6_info *fib6_find_prefix(struct net *net,
					 struct fib6_table *table,
					 struct fib6_node *fn)
{}

/*
 *	Called to trim the tree of intermediate nodes when possible. "fn"
 *	is the node we want to try and remove.
 *	Need to own table->tb6_lock
 */

static struct fib6_node *fib6_repair_tree(struct net *net,
					  struct fib6_table *table,
					  struct fib6_node *fn)
{}

static void fib6_del_route(struct fib6_table *table, struct fib6_node *fn,
			   struct fib6_info __rcu **rtp, struct nl_info *info)
{}

/* Need to own table->tb6_lock */
int fib6_del(struct fib6_info *rt, struct nl_info *info)
{}

/*
 *	Tree traversal function.
 *
 *	Certainly, it is not interrupt safe.
 *	However, it is internally reenterable wrt itself and fib6_add/fib6_del.
 *	It means, that we can modify tree during walking
 *	and use this function for garbage collection, clone pruning,
 *	cleaning tree when a device goes down etc. etc.
 *
 *	It guarantees that every node will be traversed,
 *	and that it will be traversed only once.
 *
 *	Callback function w->func may return:
 *	0 -> continue walking.
 *	positive value -> walking is suspended (used by tree dumps,
 *	and probably by gc, if it will be split to several slices)
 *	negative value -> terminate walking.
 *
 *	The function itself returns:
 *	0   -> walk is complete.
 *	>0  -> walk is incomplete (i.e. suspended)
 *	<0  -> walk is terminated by an error.
 *
 *	This function is called with tb6_lock held.
 */

static int fib6_walk_continue(struct fib6_walker *w)
{}

static int fib6_walk(struct net *net, struct fib6_walker *w)
{}

static int fib6_clean_node(struct fib6_walker *w)
{}

/*
 *	Convenient frontend to tree walker.
 *
 *	func is called on each route.
 *		It may return -2 -> skip multipath route.
 *			      -1 -> delete this route.
 *		              0  -> continue walking
 */

static void fib6_clean_tree(struct net *net, struct fib6_node *root,
			    int (*func)(struct fib6_info *, void *arg),
			    int sernum, void *arg, bool skip_notify)
{}

static void __fib6_clean_all(struct net *net,
			     int (*func)(struct fib6_info *, void *),
			     int sernum, void *arg, bool skip_notify)
{}

void fib6_clean_all(struct net *net, int (*func)(struct fib6_info *, void *),
		    void *arg)
{}

void fib6_clean_all_skip_notify(struct net *net,
				int (*func)(struct fib6_info *, void *),
				void *arg)
{}

static void fib6_flush_trees(struct net *net)
{}

/*
 *	Garbage collection
 */

static int fib6_age(struct fib6_info *rt, struct fib6_gc_args *gc_args)
{}

static void fib6_gc_table(struct net *net,
			  struct fib6_table *tb6,
			  struct fib6_gc_args *gc_args)
{}

static void fib6_gc_all(struct net *net, struct fib6_gc_args *gc_args)
{}

void fib6_run_gc(unsigned long expires, struct net *net, bool force)
{}

static void fib6_gc_timer_cb(struct timer_list *t)
{}

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

static void fib6_net_exit(struct net *net)
{}

static struct pernet_operations fib6_net_ops =;

int __init fib6_init(void)
{}

void fib6_gc_cleanup(void)
{}

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

static int ipv6_route_yield(struct fib6_walker *w)
{}

static void ipv6_route_seq_setup_walk(struct ipv6_route_iter *iter,
				      struct net *net)
{}

static struct fib6_table *ipv6_route_seq_next_table(struct fib6_table *tbl,
						    struct net *net)
{}

static void ipv6_route_check_sernum(struct ipv6_route_iter *iter)
{}

static void *ipv6_route_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{}

static void *ipv6_route_seq_start(struct seq_file *seq, loff_t *pos)
	__acquires(RCU)
{}

static bool ipv6_route_iter_active(struct ipv6_route_iter *iter)
{}

static void ipv6_route_native_seq_stop(struct seq_file *seq, void *v)
	__releases(RCU)
{}

#if IS_BUILTIN(CONFIG_IPV6) && defined(CONFIG_BPF_SYSCALL)
static int ipv6_route_prog_seq_show(struct bpf_prog *prog,
				    struct bpf_iter_meta *meta,
				    void *v)
{}

static int ipv6_route_seq_show(struct seq_file *seq, void *v)
{}

static void ipv6_route_seq_stop(struct seq_file *seq, void *v)
{}
#else
static int ipv6_route_seq_show(struct seq_file *seq, void *v)
{
	return ipv6_route_native_seq_show(seq, v);
}

static void ipv6_route_seq_stop(struct seq_file *seq, void *v)
{
	ipv6_route_native_seq_stop(seq, v);
}
#endif

const struct seq_operations ipv6_route_seq_ops =;
#endif /* CONFIG_PROC_FS */