Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c71099ac authored by Thomas Graf's avatar Thomas Graf Committed by David S. Miller
Browse files

[IPV6]: Multiple Routing Tables



Adds the framework to support multiple IPv6 routing tables.
Currently all automatically generated routes are put into the
same table. This could be changed at a later point after
considering the produced locking overhead.

Signed-off-by: default avatarThomas Graf <tgraf@suug.ch>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 5d0bbeeb
Loading
Loading
Loading
Loading
+38 −1
Original line number Diff line number Diff line
@@ -51,6 +51,8 @@ struct rt6key
	int		plen;
};

struct fib6_table;

struct rt6_info
{
	union {
@@ -71,6 +73,7 @@ struct rt6_info
	u32				rt6i_flags;
	u32				rt6i_metric;
	atomic_t			rt6i_ref;
	struct fib6_table		*rt6i_table;

	struct rt6key			rt6i_dst;
	struct rt6key			rt6i_src;
@@ -143,12 +146,43 @@ struct rt6_statistics {

typedef void			(*f_pnode)(struct fib6_node *fn, void *);

extern struct fib6_node		ip6_routing_table;
struct fib6_table {
	struct hlist_node	tb6_hlist;
	u32			tb6_id;
	rwlock_t		tb6_lock;
	struct fib6_node	tb6_root;
};

#define RT6_TABLE_UNSPEC	RT_TABLE_UNSPEC
#define RT6_TABLE_MAIN		RT_TABLE_MAIN
#define RT6_TABLE_LOCAL		RT6_TABLE_MAIN
#define RT6_TABLE_DFLT		RT6_TABLE_MAIN
#define RT6_TABLE_INFO		RT6_TABLE_MAIN
#define RT6_TABLE_PREFIX	RT6_TABLE_MAIN

#ifdef CONFIG_IPV6_MULTIPLE_TABLES
#define FIB6_TABLE_MIN		1
#define FIB6_TABLE_MAX		RT_TABLE_MAX
#else
#define FIB6_TABLE_MIN		RT_TABLE_MAIN
#define FIB6_TABLE_MAX		FIB6_TABLE_MIN
#endif

#define RT6_F_STRICT		1
#define RT6_F_HAS_SADDR		2

typedef struct rt6_info *(*pol_lookup_t)(struct fib6_table *,
					 struct flowi *, int);

/*
 *	exported functions
 */

extern struct fib6_table *	fib6_get_table(u32 id);
extern struct fib6_table *	fib6_new_table(u32 id);
extern struct dst_entry *	fib6_rule_lookup(struct flowi *fl, int flags,
						 pol_lookup_t lookup);

extern struct fib6_node		*fib6_lookup(struct fib6_node *root,
					     struct in6_addr *daddr,
					     struct in6_addr *saddr);
@@ -161,6 +195,9 @@ extern void fib6_clean_tree(struct fib6_node *root,
						int (*func)(struct rt6_info *, void *arg),
						int prune, void *arg);

extern void			fib6_clean_all(int (*func)(struct rt6_info *, void *arg),
					       int prune, void *arg);

extern int			fib6_walk(struct fib6_walker_t *w);
extern int			fib6_walk_continue(struct fib6_walker_t *w);

+2 −1
Original line number Diff line number Diff line
@@ -58,7 +58,8 @@ extern int ipv6_route_ioctl(unsigned int cmd, void __user *arg);
extern int			ip6_route_add(struct in6_rtmsg *rtmsg,
					      struct nlmsghdr *,
					      void *rtattr,
					      struct netlink_skb_parms *req);
					      struct netlink_skb_parms *req,
					      u32 table_id);
extern int			ip6_ins_rt(struct rt6_info *,
					   struct nlmsghdr *,
					   void *rtattr,
+6 −0
Original line number Diff line number Diff line
@@ -136,3 +136,9 @@ config IPV6_TUNNEL

	  If unsure, say N.

config IPV6_MULTIPLE_TABLES
	bool "IPv6: Multiple Routing Tables"
	depends on IPV6 && EXPERIMENTAL
	---help---
	  Support multiple routing tables.
+3 −3
Original line number Diff line number Diff line
@@ -1525,7 +1525,7 @@ addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev,
	if (dev->type == ARPHRD_SIT && (dev->flags&IFF_POINTOPOINT))
		rtmsg.rtmsg_flags |= RTF_NONEXTHOP;

	ip6_route_add(&rtmsg, NULL, NULL, NULL);
	ip6_route_add(&rtmsg, NULL, NULL, NULL, RT6_TABLE_PREFIX);
}

/* Create "default" multicast route to the interface */
@@ -1542,7 +1542,7 @@ static void addrconf_add_mroute(struct net_device *dev)
	rtmsg.rtmsg_ifindex = dev->ifindex;
	rtmsg.rtmsg_flags = RTF_UP;
	rtmsg.rtmsg_type = RTMSG_NEWROUTE;
	ip6_route_add(&rtmsg, NULL, NULL, NULL);
	ip6_route_add(&rtmsg, NULL, NULL, NULL, RT6_TABLE_LOCAL);
}

static void sit_route_add(struct net_device *dev)
@@ -1559,7 +1559,7 @@ static void sit_route_add(struct net_device *dev)
	rtmsg.rtmsg_flags	= RTF_UP|RTF_NONEXTHOP;
	rtmsg.rtmsg_ifindex	= dev->ifindex;

	ip6_route_add(&rtmsg, NULL, NULL, NULL);
	ip6_route_add(&rtmsg, NULL, NULL, NULL, RT6_TABLE_MAIN);
}

static void addrconf_add_lroute(struct net_device *dev)
+140 −4
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#include <linux/netdevice.h>
#include <linux/in6.h>
#include <linux/init.h>
#include <linux/list.h>

#ifdef 	CONFIG_PROC_FS
#include <linux/proc_fs.h>
@@ -147,6 +148,126 @@ static __inline__ void rt6_release(struct rt6_info *rt)
		dst_free(&rt->u.dst);
}

static struct fib6_table fib6_main_tbl = {
	.tb6_id		= RT6_TABLE_MAIN,
	.tb6_lock	= RW_LOCK_UNLOCKED,
	.tb6_root	= {
		.leaf		= &ip6_null_entry,
		.fn_flags	= RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO,
	},
};

#ifdef CONFIG_IPV6_MULTIPLE_TABLES

#define FIB_TABLE_HASHSZ 256
static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ];

static struct fib6_table *fib6_alloc_table(u32 id)
{
	struct fib6_table *table;

	table = kzalloc(sizeof(*table), GFP_ATOMIC);
	if (table != NULL) {
		table->tb6_id = id;
		table->tb6_lock = RW_LOCK_UNLOCKED;
		table->tb6_root.leaf = &ip6_null_entry;
		table->tb6_root.fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
	}

	return table;
}

static void fib6_link_table(struct fib6_table *tb)
{
	unsigned int h;

	h = tb->tb6_id & (FIB_TABLE_HASHSZ - 1);

	/*
	 * No protection necessary, this is the only list mutatation
	 * operation, tables never disappear once they exist.
	 */
	hlist_add_head_rcu(&tb->tb6_hlist, &fib_table_hash[h]);
}

struct fib6_table *fib6_new_table(u32 id)
{
	struct fib6_table *tb;

	if (id == 0)
		id = RT6_TABLE_MAIN;
	tb = fib6_get_table(id);
	if (tb)
		return tb;

	tb = fib6_alloc_table(id);
	if (tb != NULL)
		fib6_link_table(tb);

	return tb;
}

struct fib6_table *fib6_get_table(u32 id)
{
	struct fib6_table *tb;
	struct hlist_node *node;
	unsigned int h;

	if (id == 0)
		id = RT6_TABLE_MAIN;
	h = id & (FIB_TABLE_HASHSZ - 1);
	rcu_read_lock();
	hlist_for_each_entry_rcu(tb, node, &fib_table_hash[h], tb6_hlist) {
		if (tb->tb6_id == id) {
			rcu_read_unlock();
			return tb;
		}
	}
	rcu_read_unlock();

	return NULL;
}

struct dst_entry *fib6_rule_lookup(struct flowi *fl, int flags,
				   pol_lookup_t lookup)
{
	/*
	 * TODO: Add rule lookup
	 */
	struct fib6_table *table = fib6_get_table(RT6_TABLE_MAIN);

	return (struct dst_entry *) lookup(table, fl, flags);
}

static void __init fib6_tables_init(void)
{
	fib6_link_table(&fib6_main_tbl);
}

#else

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

struct fib6_table *fib6_get_table(u32 id)
{
	return &fib6_main_tbl;
}

struct dst_entry *fib6_rule_lookup(struct flowi *fl, int flags,
				   pol_lookup_t lookup)
{
	return (struct dst_entry *) lookup(&fib6_main_tbl, fl, flags);
}

static void __init fib6_tables_init(void)
{
}

#endif


/*
 *	Routing Table
@@ -1064,6 +1185,22 @@ void fib6_clean_tree(struct fib6_node *root,
	fib6_walk(&c.w);
}

void fib6_clean_all(int (*func)(struct rt6_info *, void *arg),
		    int prune, void *arg)
{
	int i;
	struct fib6_table *table;

	for (i = FIB6_TABLE_MIN; i <= FIB6_TABLE_MAX; i++) {
		table = fib6_get_table(i);
		if (table != NULL) {
			write_lock_bh(&table->tb6_lock);
			fib6_clean_tree(&table->tb6_root, func, prune, arg);
			write_unlock_bh(&table->tb6_lock);
		}
	}
}

static int fib6_prune_clone(struct rt6_info *rt, void *arg)
{
	if (rt->rt6i_flags & RTF_CACHE) {
@@ -1142,11 +1279,8 @@ void fib6_run_gc(unsigned long dummy)
	}
	gc_args.more = 0;


	write_lock_bh(&rt6_lock);
	ndisc_dst_gc(&gc_args.more);
	fib6_clean_tree(&ip6_routing_table, fib6_age, 0, NULL);
	write_unlock_bh(&rt6_lock);
	fib6_clean_all(fib6_age, 0, NULL);

	if (gc_args.more)
		mod_timer(&ip6_fib_timer, jiffies + ip6_rt_gc_interval);
@@ -1165,6 +1299,8 @@ void __init fib6_init(void)
					   NULL, NULL);
	if (!fib6_node_kmem)
		panic("cannot create fib6_nodes cache");

	fib6_tables_init();
}

void fib6_gc_cleanup(void)
Loading