summaryrefslogtreecommitdiff
path: root/net/ipv6
diff options
context:
space:
mode:
authorYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>2006-03-21 04:04:53 +0300
committerDavid S. Miller <davem@davemloft.net>2006-03-21 04:04:53 +0300
commitebacaaa0fdf4402cdf4c8e569f54af36b6f0aa2d (patch)
tree5d1cc0c6d94b5226507434bb86e6e2a69fdd4204 /net/ipv6
parent8238dd0698b480e432acd955c45f9f907b8d27de (diff)
downloadlinux-ebacaaa0fdf4402cdf4c8e569f54af36b6f0aa2d.tar.xz
[IPV6]: ROUTE: Add support for Router Preference (RFC4191).
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/Kconfig11
-rw-r--r--net/ipv6/ndisc.c12
-rw-r--r--net/ipv6/route.c11
3 files changed, 30 insertions, 4 deletions
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
index f925f206d8ff..c456ead8a4a3 100644
--- a/net/ipv6/Kconfig
+++ b/net/ipv6/Kconfig
@@ -38,6 +38,17 @@ config IPV6_PRIVACY
See <file:Documentation/networking/ip-sysctl.txt> for details.
+config IPV6_ROUTER_PREF
+ bool "IPv6: Router Preference (RFC 4191) support"
+ depends on IPV6
+ ---help---
+ Router Preference is an optional extension to the Router
+ Advertisement message to improve the ability of hosts
+ to pick more appropriate router, especially when the hosts
+ is placed in a multi-homed network.
+
+ If unsure, say N.
+
config INET6_AH
tristate "IPv6: AH transformation"
depends on IPV6
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 3b56be85234e..966ab6b3022e 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -1023,6 +1023,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)
int lifetime;
struct ndisc_options ndopts;
int optlen;
+ unsigned int pref = 0;
__u8 * opt = (__u8 *)(ra_msg + 1);
@@ -1086,6 +1087,13 @@ static void ndisc_router_discovery(struct sk_buff *skb)
lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime);
+#ifdef CONFIG_IPV6_ROUTER_PREF
+ pref = ra_msg->icmph.icmp6_router_pref;
+ /* 10b is handled as if it were 00b (medium) */
+ if (pref == ICMPV6_ROUTER_PREF_INVALID)
+ pref = ICMPV6_ROUTER_PREF_MEDIUM;
+#endif
+
rt = rt6_get_dflt_router(&skb->nh.ipv6h->saddr, skb->dev);
if (rt)
@@ -1101,7 +1109,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)
ND_PRINTK3(KERN_DEBUG
"ICMPv6 RA: adding default router.\n");
- rt = rt6_add_dflt_router(&skb->nh.ipv6h->saddr, skb->dev);
+ rt = rt6_add_dflt_router(&skb->nh.ipv6h->saddr, skb->dev, pref);
if (rt == NULL) {
ND_PRINTK0(KERN_ERR
"ICMPv6 RA: %s() failed to add default route.\n",
@@ -1120,6 +1128,8 @@ static void ndisc_router_discovery(struct sk_buff *skb)
return;
}
neigh->flags |= NTF_ROUTER;
+ } else if (rt) {
+ rt->rt6i_flags |= (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
}
if (rt)
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 6a068e7f81f1..a7030fed1a18 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -251,8 +251,11 @@ static int rt6_score_route(struct rt6_info *rt, int oif,
int m = rt6_check_dev(rt, oif);
if (!m && (strict & RT6_SELECT_F_IFACE))
return -1;
+#ifdef CONFIG_IPV6_ROUTER_PREF
+ m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->rt6i_flags)) << 2;
+#endif
if (rt6_check_neigh(rt))
- m |= 4;
+ m |= 16;
else if (strict & RT6_SELECT_F_REACHABLE)
return -1;
return m;
@@ -1256,7 +1259,8 @@ struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *d
}
struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr,
- struct net_device *dev)
+ struct net_device *dev,
+ unsigned int pref)
{
struct in6_rtmsg rtmsg;
@@ -1264,7 +1268,8 @@ struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr,
rtmsg.rtmsg_type = RTMSG_NEWROUTE;
ipv6_addr_copy(&rtmsg.rtmsg_gateway, gwaddr);
rtmsg.rtmsg_metric = 1024;
- rtmsg.rtmsg_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT | RTF_UP | RTF_EXPIRES;
+ rtmsg.rtmsg_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT | RTF_UP | RTF_EXPIRES |
+ RTF_PREF(pref);
rtmsg.rtmsg_ifindex = dev->ifindex;