diff options
author | YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> | 2006-03-20 20:04:53 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2006-03-20 20:04:53 -0500 |
commit | ebacaaa0fdf4402cdf4c8e569f54af36b6f0aa2d (patch) | |
tree | 5d1cc0c6d94b5226507434bb86e6e2a69fdd4204 | |
parent | 8238dd0698b480e432acd955c45f9f907b8d27de (diff) |
[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>
-rw-r--r-- | include/linux/icmpv6.h | 11 | ||||
-rw-r--r-- | include/linux/ipv6_route.h | 8 | ||||
-rw-r--r-- | include/net/ip6_route.h | 3 | ||||
-rw-r--r-- | net/ipv6/Kconfig | 11 | ||||
-rw-r--r-- | net/ipv6/ndisc.c | 12 | ||||
-rw-r--r-- | net/ipv6/route.c | 11 |
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 | |||
32 | struct in6_rtmsg { | 40 | struct 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, | |||
87 | extern struct rt6_info * rt6_get_dflt_router(struct in6_addr *addr, | 87 | extern struct rt6_info * rt6_get_dflt_router(struct in6_addr *addr, |
88 | struct net_device *dev); | 88 | struct net_device *dev); |
89 | extern struct rt6_info * rt6_add_dflt_router(struct in6_addr *gwaddr, | 89 | extern 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 | ||
92 | extern void rt6_purge_dflt_routers(void); | 93 | extern 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 | ||
41 | config 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 | |||
41 | config INET6_AH | 52 | config 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 | ||
1258 | struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr, | 1261 | struct 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 | ||