#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);
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)
{ … }
#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;
}
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)
{ … }
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)
{ … }
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)
{ … }
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)
{ … }
void fib6_update_sernum_stub(struct net *net, struct fib6_info *f6i)
{ … }
int fib6_add(struct fib6_node *root, struct fib6_info *rt,
struct nl_info *info, struct netlink_ext_ack *extack)
{ … }
struct lookup_args { … };
static struct fib6_node *fib6_node_lookup_1(struct fib6_node *root,
struct lookup_args *args)
{ … }
struct fib6_node *fib6_node_lookup(struct fib6_node *root,
const struct in6_addr *daddr,
const struct in6_addr *saddr)
{ … }
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)
{ … }
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 void fib6_del_route(struct fib6_table *table, struct fib6_node *fn,
struct fib6_info __rcu **rtp, struct nl_info *info)
{ … }
int fib6_del(struct fib6_info *rt, struct nl_info *info)
{ … }
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)
{ … }
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)
{ … }
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