Commit ebacaaa0 authored by YOSHIFUJI Hideaki's avatar YOSHIFUJI Hideaki Committed by David S. Miller

[IPV6]: ROUTE: Add support for Router Preference (RFC4191).

Signed-off-by: default avatarYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 8238dd06
...@@ -40,14 +40,16 @@ struct icmp6hdr { ...@@ -40,14 +40,16 @@ struct icmp6hdr {
struct icmpv6_nd_ra { struct icmpv6_nd_ra {
__u8 hop_limit; __u8 hop_limit;
#if defined(__LITTLE_ENDIAN_BITFIELD) #if defined(__LITTLE_ENDIAN_BITFIELD)
__u8 reserved:6, __u8 reserved:4,
router_pref:2,
other:1, other:1,
managed:1; managed:1;
#elif defined(__BIG_ENDIAN_BITFIELD) #elif defined(__BIG_ENDIAN_BITFIELD)
__u8 managed:1, __u8 managed:1,
other:1, other:1,
reserved:6; router_pref:2,
reserved:4;
#else #else
#error "Please fix <asm/byteorder.h>" #error "Please fix <asm/byteorder.h>"
#endif #endif
...@@ -70,8 +72,13 @@ struct icmp6hdr { ...@@ -70,8 +72,13 @@ struct icmp6hdr {
#define icmp6_addrconf_managed icmp6_dataun.u_nd_ra.managed #define icmp6_addrconf_managed icmp6_dataun.u_nd_ra.managed
#define icmp6_addrconf_other icmp6_dataun.u_nd_ra.other #define icmp6_addrconf_other icmp6_dataun.u_nd_ra.other
#define icmp6_rt_lifetime icmp6_dataun.u_nd_ra.rt_lifetime #define icmp6_rt_lifetime icmp6_dataun.u_nd_ra.rt_lifetime
#define icmp6_router_pref icmp6_dataun.u_nd_ra.router_pref
}; };
#define ICMPV6_ROUTER_PREF_LOW 0x3
#define ICMPV6_ROUTER_PREF_MEDIUM 0x0
#define ICMPV6_ROUTER_PREF_HIGH 0x1
#define ICMPV6_ROUTER_PREF_INVALID 0x2
#define ICMPV6_DEST_UNREACH 1 #define ICMPV6_DEST_UNREACH 1
#define ICMPV6_PKT_TOOBIG 2 #define ICMPV6_PKT_TOOBIG 2
......
...@@ -27,8 +27,16 @@ ...@@ -27,8 +27,16 @@
#define RTF_FLOW 0x02000000 /* flow significant route */ #define RTF_FLOW 0x02000000 /* flow significant route */
#define RTF_POLICY 0x04000000 /* policy route */ #define RTF_POLICY 0x04000000 /* policy route */
#define RTF_PREF(pref) ((pref) << 27)
#define RTF_PREF_MASK 0x18000000
#define RTF_LOCAL 0x80000000 #define RTF_LOCAL 0x80000000
#ifdef __KERNEL__
#define IPV6_EXTRACT_PREF(flag) (((flag) & RTF_PREF_MASK) >> 27)
#define IPV6_DECODE_PREF(pref) ((pref) ^ 2) /* 1:low,2:med,3:high */
#endif
struct in6_rtmsg { struct in6_rtmsg {
struct in6_addr rtmsg_dst; struct in6_addr rtmsg_dst;
struct in6_addr rtmsg_src; struct in6_addr rtmsg_src;
......
...@@ -87,7 +87,8 @@ extern struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, ...@@ -87,7 +87,8 @@ extern struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
extern struct rt6_info * rt6_get_dflt_router(struct in6_addr *addr, extern struct rt6_info * rt6_get_dflt_router(struct in6_addr *addr,
struct net_device *dev); struct net_device *dev);
extern struct rt6_info * rt6_add_dflt_router(struct in6_addr *gwaddr, extern struct rt6_info * rt6_add_dflt_router(struct in6_addr *gwaddr,
struct net_device *dev); struct net_device *dev,
unsigned int pref);
extern void rt6_purge_dflt_routers(void); extern void rt6_purge_dflt_routers(void);
......
...@@ -38,6 +38,17 @@ config IPV6_PRIVACY ...@@ -38,6 +38,17 @@ config IPV6_PRIVACY
See <file:Documentation/networking/ip-sysctl.txt> for details. 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 config INET6_AH
tristate "IPv6: AH transformation" tristate "IPv6: AH transformation"
depends on IPV6 depends on IPV6
......
...@@ -1023,6 +1023,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) ...@@ -1023,6 +1023,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)
int lifetime; int lifetime;
struct ndisc_options ndopts; struct ndisc_options ndopts;
int optlen; int optlen;
unsigned int pref = 0;
__u8 * opt = (__u8 *)(ra_msg + 1); __u8 * opt = (__u8 *)(ra_msg + 1);
...@@ -1086,6 +1087,13 @@ static void ndisc_router_discovery(struct sk_buff *skb) ...@@ -1086,6 +1087,13 @@ static void ndisc_router_discovery(struct sk_buff *skb)
lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime); 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); rt = rt6_get_dflt_router(&skb->nh.ipv6h->saddr, skb->dev);
if (rt) if (rt)
...@@ -1101,7 +1109,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) ...@@ -1101,7 +1109,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)
ND_PRINTK3(KERN_DEBUG ND_PRINTK3(KERN_DEBUG
"ICMPv6 RA: adding default router.\n"); "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) { if (rt == NULL) {
ND_PRINTK0(KERN_ERR ND_PRINTK0(KERN_ERR
"ICMPv6 RA: %s() failed to add default route.\n", "ICMPv6 RA: %s() failed to add default route.\n",
...@@ -1120,6 +1128,8 @@ static void ndisc_router_discovery(struct sk_buff *skb) ...@@ -1120,6 +1128,8 @@ static void ndisc_router_discovery(struct sk_buff *skb)
return; return;
} }
neigh->flags |= NTF_ROUTER; neigh->flags |= NTF_ROUTER;
} else if (rt) {
rt->rt6i_flags |= (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
} }
if (rt) if (rt)
......
...@@ -251,8 +251,11 @@ static int rt6_score_route(struct rt6_info *rt, int oif, ...@@ -251,8 +251,11 @@ static int rt6_score_route(struct rt6_info *rt, int oif,
int m = rt6_check_dev(rt, oif); int m = rt6_check_dev(rt, oif);
if (!m && (strict & RT6_SELECT_F_IFACE)) if (!m && (strict & RT6_SELECT_F_IFACE))
return -1; return -1;
#ifdef CONFIG_IPV6_ROUTER_PREF
m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->rt6i_flags)) << 2;
#endif
if (rt6_check_neigh(rt)) if (rt6_check_neigh(rt))
m |= 4; m |= 16;
else if (strict & RT6_SELECT_F_REACHABLE) else if (strict & RT6_SELECT_F_REACHABLE)
return -1; return -1;
return m; return m;
...@@ -1256,7 +1259,8 @@ struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *d ...@@ -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 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; struct in6_rtmsg rtmsg;
...@@ -1264,7 +1268,8 @@ struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr, ...@@ -1264,7 +1268,8 @@ struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr,
rtmsg.rtmsg_type = RTMSG_NEWROUTE; rtmsg.rtmsg_type = RTMSG_NEWROUTE;
ipv6_addr_copy(&rtmsg.rtmsg_gateway, gwaddr); ipv6_addr_copy(&rtmsg.rtmsg_gateway, gwaddr);
rtmsg.rtmsg_metric = 1024; 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; rtmsg.rtmsg_ifindex = dev->ifindex;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment