[<prev] [next>] [day] [month] [year] [list]
Message-ID: <50345676.10506@bjencks.net>
Date: Tue, 21 Aug 2012 23:48:06 -0400
From: Ben Jencks <ben@...ncks.net>
To: netdev@...r.kernel.org
Subject: [PATCH RFC] ipv6: Add net.ipv6.conf.*.accept_ra_defrtr_table sysctl.
Allows configuration of the routing table to which default routes from
RAs are added on a per-interface basis.
One use case where this is required is a multi-homed router advertising
multiple prefixes, one for each upstream. The proper routing policy is
something like:
0: from all lookup local
10: from all lookup main
20: from <prefix1> lookup provider1
30: from <prefix2> lookup provider2
with directly connected and internal routes in main, and default routes
from providers 1 and 2 in their respective tables. With static routes
this is straightforward; if the route for either or both providers is
received via RA this configuration option becomes necessary to put the
routes in the appropriate tables.
Signed-off-by: Ben Jencks <ben@...ncks.net>
---
Patch is against v3.5.2, but applies cleanly to master as of today.
Looking for feedback on:
* Is this a worthwhile feature? Did I miss a good way to do this in
userspace?
* Is a sysctl the right place to configure it? I know it's discouraged
to add new ones, but it seems to fit best with the other similar
configuration options.
* Is the rt6_purge_dflt_routers behavior correct? Should
addrconf_fixup_forwarding be modified so that in the single device
case it only purges from that device's table?
Documentation/networking/ip-sysctl.txt | 6 +++++
include/linux/ipv6.h | 2 ++
include/linux/sysctl.h | 1 +
kernel/sysctl_binary.c | 1 +
net/ipv6/addrconf.c | 10 +++++++
net/ipv6/route.c | 45 ++++++++++++++++++++++----------
6 files changed, 51 insertions(+), 14 deletions(-)
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index 6f896b9..0d0947a 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -1085,6 +1085,12 @@ accept_ra_defrtr - BOOLEAN
Functional default: enabled if accept_ra is enabled.
disabled if accept_ra is disabled.
+accept_ra_defrtr_table - INTEGER
+ Routing table into which to put default route learned via Router
+ Advertisement.
+
+ Functional default: "main" routing table (254)
+
accept_ra_pinfo - BOOLEAN
Learn Prefix Information in Router Advertisement.
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index 8260ef7..fa9b4fe 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -153,6 +153,7 @@ struct ipv6_devconf {
#endif
__s32 max_addresses;
__s32 accept_ra_defrtr;
+ __s32 accept_ra_defrtr_table;
__s32 accept_ra_pinfo;
#ifdef CONFIG_IPV6_ROUTER_PREF
__s32 accept_ra_rtr_pref;
@@ -202,6 +203,7 @@ enum {
DEVCONF_MAX_ADDRESSES,
DEVCONF_FORCE_MLD_VERSION,
DEVCONF_ACCEPT_RA_DEFRTR,
+ DEVCONF_ACCEPT_RA_DEFRTR_TABLE,
DEVCONF_ACCEPT_RA_PINFO,
DEVCONF_ACCEPT_RA_RTR_PREF,
DEVCONF_RTR_PROBE_INTERVAL,
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index c34b4c8..80115c8 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -568,6 +568,7 @@ enum {
NET_IPV6_ACCEPT_RA_RT_INFO_MAX_PLEN=22,
NET_IPV6_PROXY_NDP=23,
NET_IPV6_ACCEPT_SOURCE_ROUTE=25,
+ NET_IPV6_ACCEPT_RA_DEFRTR_TABLE=26,
__NET_IPV6_MAX
};
diff --git a/kernel/sysctl_binary.c b/kernel/sysctl_binary.c
index a650694..da964f3 100644
--- a/kernel/sysctl_binary.c
+++ b/kernel/sysctl_binary.c
@@ -517,6 +517,7 @@ static const struct bin_table bin_net_ipv6_conf_var_table[] = {
{ CTL_INT, NET_IPV6_MAX_ADDRESSES, "max_addresses" },
{ CTL_INT, NET_IPV6_FORCE_MLD_VERSION, "force_mld_version" },
{ CTL_INT, NET_IPV6_ACCEPT_RA_DEFRTR, "accept_ra_defrtr" },
+ { CTL_INT, NET_IPV6_ACCEPT_RA_DEFRTR_TABLE, "accept_ra_defrtr_table" },
{ CTL_INT, NET_IPV6_ACCEPT_RA_PINFO, "accept_ra_pinfo" },
{ CTL_INT, NET_IPV6_ACCEPT_RA_RTR_PREF, "accept_ra_rtr_pref" },
{ CTL_INT, NET_IPV6_RTR_PROBE_INTERVAL, "router_probe_interval" },
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 8f6411c..2bdb96c 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -188,6 +188,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
#endif
.max_addresses = IPV6_MAX_ADDRESSES,
.accept_ra_defrtr = 1,
+ .accept_ra_defrtr_table = RT6_TABLE_DFLT,
.accept_ra_pinfo = 1,
#ifdef CONFIG_IPV6_ROUTER_PREF
.accept_ra_rtr_pref = 1,
@@ -222,6 +223,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
#endif
.max_addresses = IPV6_MAX_ADDRESSES,
.accept_ra_defrtr = 1,
+ .accept_ra_defrtr_table = RT6_TABLE_DFLT,
.accept_ra_pinfo = 1,
#ifdef CONFIG_IPV6_ROUTER_PREF
.accept_ra_rtr_pref = 1,
@@ -3894,6 +3896,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
#endif
array[DEVCONF_MAX_ADDRESSES] = cnf->max_addresses;
array[DEVCONF_ACCEPT_RA_DEFRTR] = cnf->accept_ra_defrtr;
+ array[DEVCONF_ACCEPT_RA_DEFRTR_TABLE] = cnf->accept_ra_defrtr_table;
array[DEVCONF_ACCEPT_RA_PINFO] = cnf->accept_ra_pinfo;
#ifdef CONFIG_IPV6_ROUTER_PREF
array[DEVCONF_ACCEPT_RA_RTR_PREF] = cnf->accept_ra_rtr_pref;
@@ -4496,6 +4499,13 @@ static struct addrconf_sysctl_table
.proc_handler = proc_dointvec,
},
{
+ .procname = "accept_ra_defrtr_table",
+ .data = &ipv6_devconf.accept_ra_defrtr_table,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
+ {
.procname = "accept_ra_pinfo",
.data = &ipv6_devconf.accept_ra_pinfo,
.maxlen = sizeof(int),
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index becb048..dafcb61 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -1916,8 +1916,12 @@ struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_dev
{
struct rt6_info *rt;
struct fib6_table *table;
+ struct inet6_dev *idev;
- table = fib6_get_table(dev_net(dev), RT6_TABLE_DFLT);
+ idev = __in6_dev_get(dev);
+ if (!idev)
+ return NULL;
+ table = fib6_get_table(dev_net(dev), idev->cnf.accept_ra_defrtr_table);
if (!table)
return NULL;
@@ -1939,7 +1943,6 @@ struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr,
unsigned int pref)
{
struct fib6_config cfg = {
- .fc_table = RT6_TABLE_DFLT,
.fc_metric = IP6_RT_PRIO_USER,
.fc_ifindex = dev->ifindex,
.fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |
@@ -1948,7 +1951,12 @@ struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr,
.fc_nlinfo.nlh = NULL,
.fc_nlinfo.nl_net = dev_net(dev),
};
+ struct inet6_dev *idev;
+ /* idev should not be null, since we were called from
+ * ndisc_router_discovery which already checked it */
+ idev = __in6_dev_get(dev);
+ cfg.fc_table = idev->cnf.accept_ra_defrtr_table;
cfg.fc_gateway = *gwaddr;
ip6_route_add(&cfg);
@@ -1960,23 +1968,32 @@ void rt6_purge_dflt_routers(struct net *net)
{
struct rt6_info *rt;
struct fib6_table *table;
+ struct net_device *dev;
+ struct inet6_dev *idev;
- /* NOTE: Keep consistent with rt6_get_dflt_router */
- table = fib6_get_table(net, RT6_TABLE_DFLT);
- if (!table)
- return;
+ rcu_read_lock();
+ for_each_netdev_rcu(net, dev) {
+ idev = __in6_dev_get(dev);
+ if (idev == NULL) {
+ continue;
+ }
+ table = fib6_get_table(net, idev->cnf.accept_ra_defrtr_table);
+ if (!table)
+ continue;
restart:
- read_lock_bh(&table->tb6_lock);
- for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
- if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) {
- dst_hold(&rt->dst);
- read_unlock_bh(&table->tb6_lock);
- ip6_del_rt(rt);
- goto restart;
+ read_lock_bh(&table->tb6_lock);
+ for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
+ if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) {
+ dst_hold(&rt->dst);
+ read_unlock_bh(&table->tb6_lock);
+ ip6_del_rt(rt);
+ goto restart;
+ }
}
+ read_unlock_bh(&table->tb6_lock);
}
- read_unlock_bh(&table->tb6_lock);
+ rcu_read_unlock();
}
static void rtmsg_to_fib6_config(struct net *net,
--
1.7.9.5
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists