aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/icmpv6.h11
-rw-r--r--include/linux/ipv6_route.h8
-rw-r--r--include/net/ip6_route.h3
-rw-r--r--net/ipv6/Kconfig11
-rw-r--r--net/ipv6/ndisc.c12
-rw-r--r--net/ipv6/route.c11
6 files changed, 49 insertions, 7 deletions
diff --git a/include/linux/icmpv6.h b/include/linux/icmpv6.h
index 0cf6c8b12caf..c771a7db9871 100644
--- a/include/linux/icmpv6.h
+++ b/include/linux/icmpv6.h
@@ -40,14 +40,16 @@ struct icmp6hdr {
40 struct icmpv6_nd_ra { 40 struct icmpv6_nd_ra {
41 __u8 hop_limit; 41 __u8 hop_limit;
42#if defined(__LITTLE_ENDIAN_BITFIELD) 42#if defined(__LITTLE_ENDIAN_BITFIELD)
43 __u8 reserved:6, 43 __u8 reserved:4,
44 router_pref:2,
44 other:1, 45 other:1,
45 managed:1; 46 managed:1;
46 47
47#elif defined(__BIG_ENDIAN_BITFIELD) 48#elif defined(__BIG_ENDIAN_BITFIELD)
48 __u8 managed:1, 49 __u8 managed:1,
49 other:1, 50 other:1,
50 reserved:6; 51 router_pref:2,
52 reserved:4;
51#else 53#else
52#error "Please fix <asm/byteorder.h>" 54#error "Please fix <asm/byteorder.h>"
53#endif 55#endif
@@ -70,8 +72,13 @@ struct icmp6hdr {
70#define icmp6_addrconf_managed icmp6_dataun.u_nd_ra.managed 72#define icmp6_addrconf_managed icmp6_dataun.u_nd_ra.managed
71#define icmp6_addrconf_other icmp6_dataun.u_nd_ra.other 73#define icmp6_addrconf_other icmp6_dataun.u_nd_ra.other
72#define icmp6_rt_lifetime icmp6_dataun.u_nd_ra.rt_lifetime 74#define icmp6_rt_lifetime icmp6_dataun.u_nd_ra.rt_lifetime
75#define icmp6_router_pref icmp6_dataun.u_nd_ra.router_pref
73}; 76};
74 77
78#define ICMPV6_ROUTER_PREF_LOW 0x3
79#define ICMPV6_ROUTER_PREF_MEDIUM 0x0
80#define ICMPV6_ROUTER_PREF_HIGH 0x1
81#define ICMPV6_ROUTER_PREF_INVALID 0x2
75 82
76#define ICMPV6_DEST_UNREACH 1 83#define ICMPV6_DEST_UNREACH 1
77#define ICMPV6_PKT_TOOBIG 2 84#define ICMPV6_PKT_TOOBIG 2
diff --git a/include/linux/ipv6_route.h b/include/linux/ipv6_route.h
index d7c41d1d706a..f4b085c91608 100644
--- a/include/linux/ipv6_route.h
+++ b/include/linux/ipv6_route.h
@@ -27,8 +27,16 @@
27#define RTF_FLOW 0x02000000 /* flow significant route */ 27#define RTF_FLOW 0x02000000 /* flow significant route */
28#define RTF_POLICY 0x04000000 /* policy route */ 28#define RTF_POLICY 0x04000000 /* policy route */
29 29
30#define RTF_PREF(pref) ((pref) << 27)
31#define RTF_PREF_MASK 0x18000000
32
30#define RTF_LOCAL 0x80000000 33#define RTF_LOCAL 0x80000000
31 34
35#ifdef __KERNEL__
36#define IPV6_EXTRACT_PREF(flag) (((flag) & RTF_PREF_MASK) >> 27)
37#define IPV6_DECODE_PREF(pref) ((pref) ^ 2) /* 1:low,2:med,3:high */
38#endif
39
32struct in6_rtmsg { 40struct in6_rtmsg {
33 struct in6_addr rtmsg_dst; 41 struct in6_addr rtmsg_dst;
34 struct in6_addr rtmsg_src; 42 struct in6_addr rtmsg_src;
diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
index 01acca06d6dd..50161322b828 100644
--- a/include/net/ip6_route.h
+++ b/include/net/ip6_route.h
@@ -87,7 +87,8 @@ extern struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
87extern struct rt6_info * rt6_get_dflt_router(struct in6_addr *addr, 87extern struct rt6_info * rt6_get_dflt_router(struct in6_addr *addr,
88 struct net_device *dev); 88 struct net_device *dev);
89extern struct rt6_info * rt6_add_dflt_router(struct in6_addr *gwaddr, 89extern struct rt6_info * rt6_add_dflt_router(struct in6_addr *gwaddr,
90 struct net_device *dev); 90 struct net_device *dev,
91 unsigned int pref);
91 92
92extern void rt6_purge_dflt_routers(void); 93extern void rt6_purge_dflt_routers(void);
93 94
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
38 38
39 See <file:Documentation/networking/ip-sysctl.txt> for details. 39 See <file:Documentation/networking/ip-sysctl.txt> for details.
40 40
41config IPV6_ROUTER_PREF
42 bool "IPv6: Router Preference (RFC 4191) support"
43 depends on IPV6
44 ---help---
45 Router Preference is an optional extension to the Router
46 Advertisement message to improve the ability of hosts
47 to pick more appropriate router, especially when the hosts
48 is placed in a multi-homed network.
49
50 If unsure, say N.
51
41config INET6_AH 52config INET6_AH
42 tristate "IPv6: AH transformation" 53 tristate "IPv6: AH transformation"
43 depends on IPV6 54 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)
1023 int lifetime; 1023 int lifetime;
1024 struct ndisc_options ndopts; 1024 struct ndisc_options ndopts;
1025 int optlen; 1025 int optlen;
1026 unsigned int pref = 0;
1026 1027
1027 __u8 * opt = (__u8 *)(ra_msg + 1); 1028 __u8 * opt = (__u8 *)(ra_msg + 1);
1028 1029
@@ -1086,6 +1087,13 @@ static void ndisc_router_discovery(struct sk_buff *skb)
1086 1087
1087 lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime); 1088 lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime);
1088 1089
1090#ifdef CONFIG_IPV6_ROUTER_PREF
1091 pref = ra_msg->icmph.icmp6_router_pref;
1092 /* 10b is handled as if it were 00b (medium) */
1093 if (pref == ICMPV6_ROUTER_PREF_INVALID)
1094 pref = ICMPV6_ROUTER_PREF_MEDIUM;
1095#endif
1096
1089 rt = rt6_get_dflt_router(&skb->nh.ipv6h->saddr, skb->dev); 1097 rt = rt6_get_dflt_router(&skb->nh.ipv6h->saddr, skb->dev);
1090 1098
1091 if (rt) 1099 if (rt)
@@ -1101,7 +1109,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)
1101 ND_PRINTK3(KERN_DEBUG 1109 ND_PRINTK3(KERN_DEBUG
1102 "ICMPv6 RA: adding default router.\n"); 1110 "ICMPv6 RA: adding default router.\n");
1103 1111
1104 rt = rt6_add_dflt_router(&skb->nh.ipv6h->saddr, skb->dev); 1112 rt = rt6_add_dflt_router(&skb->nh.ipv6h->saddr, skb->dev, pref);
1105 if (rt == NULL) { 1113 if (rt == NULL) {
1106 ND_PRINTK0(KERN_ERR 1114 ND_PRINTK0(KERN_ERR
1107 "ICMPv6 RA: %s() failed to add default route.\n", 1115 "ICMPv6 RA: %s() failed to add default route.\n",
@@ -1120,6 +1128,8 @@ static void ndisc_router_discovery(struct sk_buff *skb)
1120 return; 1128 return;
1121 } 1129 }
1122 neigh->flags |= NTF_ROUTER; 1130 neigh->flags |= NTF_ROUTER;
1131 } else if (rt) {
1132 rt->rt6i_flags |= (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
1123 } 1133 }
1124 1134
1125 if (rt) 1135 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,
251 int m = rt6_check_dev(rt, oif); 251 int m = rt6_check_dev(rt, oif);
252 if (!m && (strict & RT6_SELECT_F_IFACE)) 252 if (!m && (strict & RT6_SELECT_F_IFACE))
253 return -1; 253 return -1;
254#ifdef CONFIG_IPV6_ROUTER_PREF
255 m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->rt6i_flags)) << 2;
256#endif
254 if (rt6_check_neigh(rt)) 257 if (rt6_check_neigh(rt))
255 m |= 4; 258 m |= 16;
256 else if (strict & RT6_SELECT_F_REACHABLE) 259 else if (strict & RT6_SELECT_F_REACHABLE)
257 return -1; 260 return -1;
258 return m; 261 return m;
@@ -1256,7 +1259,8 @@ struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *d
1256} 1259}
1257 1260
1258struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr, 1261struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr,
1259 struct net_device *dev) 1262 struct net_device *dev,
1263 unsigned int pref)
1260{ 1264{
1261 struct in6_rtmsg rtmsg; 1265 struct in6_rtmsg rtmsg;
1262 1266
@@ -1264,7 +1268,8 @@ struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr,
1264 rtmsg.rtmsg_type = RTMSG_NEWROUTE; 1268 rtmsg.rtmsg_type = RTMSG_NEWROUTE;
1265 ipv6_addr_copy(&rtmsg.rtmsg_gateway, gwaddr); 1269 ipv6_addr_copy(&rtmsg.rtmsg_gateway, gwaddr);
1266 rtmsg.rtmsg_metric = 1024; 1270 rtmsg.rtmsg_metric = 1024;
1267 rtmsg.rtmsg_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT | RTF_UP | RTF_EXPIRES; 1271 rtmsg.rtmsg_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT | RTF_UP | RTF_EXPIRES |
1272 RTF_PREF(pref);
1268 1273
1269 rtmsg.rtmsg_ifindex = dev->ifindex; 1274 rtmsg.rtmsg_ifindex = dev->ifindex;
1270 1275