aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorErik Kline <ek@google.com>2014-10-28 05:11:14 -0400
committerDavid S. Miller <davem@davemloft.net>2014-10-29 15:11:36 -0400
commit7fd2561e4ebdd070ebba6d3326c4c5b13942323f (patch)
tree0705e64d0da12c0194a17f64445f30336159d7b7
parent8b243a61940d2ca3c3a370e551b88d47a09ede0c (diff)
net: ipv6: Add a sysctl to make optimistic addresses useful candidates
Add a sysctl that causes an interface's optimistic addresses to be considered equivalent to other non-deprecated addresses for source address selection purposes. Preferred addresses will still take precedence over optimistic addresses, subject to other ranking in the source address selection algorithm. This is useful where different interfaces are connected to different networks from different ISPs (e.g., a cell network and a home wifi network). The current behaviour complies with RFC 3484/6724, and it makes sense if the host has only one interface, or has multiple interfaces on the same network (same or cooperating administrative domain(s), but not in the multiple distinct networks case. For example, if a mobile device has an IPv6 address on an LTE network and then connects to IPv6-enabled wifi, while the wifi IPv6 address is undergoing DAD, IPv6 connections will try use the wifi default route with the LTE IPv6 address, and will get stuck until they time out. Also, because optimistic nodes can receive frames, issue an RTM_NEWADDR as soon as DAD starts (with the IFA_F_OPTIMSTIC flag appropriately set). A second RTM_NEWADDR is sent if DAD completes (the address flags have changed), otherwise an RTM_DELADDR is sent. Also: add an entry in ip-sysctl.txt for optimistic_dad. Signed-off-by: Erik Kline <ek@google.com> Acked-by: Lorenzo Colitti <lorenzo@google.com> Acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--Documentation/networking/ip-sysctl.txt13
-rw-r--r--include/linux/ipv6.h1
-rw-r--r--include/uapi/linux/ipv6.h1
-rw-r--r--net/ipv6/addrconf.c46
4 files changed, 59 insertions, 2 deletions
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index 9028b879a97b..368e3251c553 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -1460,6 +1460,19 @@ suppress_frag_ndisc - INTEGER
1460 1 - (default) discard fragmented neighbor discovery packets 1460 1 - (default) discard fragmented neighbor discovery packets
1461 0 - allow fragmented neighbor discovery packets 1461 0 - allow fragmented neighbor discovery packets
1462 1462
1463optimistic_dad - BOOLEAN
1464 Whether to perform Optimistic Duplicate Address Detection (RFC 4429).
1465 0: disabled (default)
1466 1: enabled
1467
1468use_optimistic - BOOLEAN
1469 If enabled, do not classify optimistic addresses as deprecated during
1470 source address selection. Preferred addresses will still be chosen
1471 before optimistic addresses, subject to other ranking in the source
1472 address selection algorithm.
1473 0: disabled (default)
1474 1: enabled
1475
1463icmp/*: 1476icmp/*:
1464ratelimit - INTEGER 1477ratelimit - INTEGER
1465 Limit the maximal rates for sending ICMPv6 packets. 1478 Limit the maximal rates for sending ICMPv6 packets.
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index ff560537dd61..7121a2e97ce2 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -42,6 +42,7 @@ struct ipv6_devconf {
42 __s32 accept_ra_from_local; 42 __s32 accept_ra_from_local;
43#ifdef CONFIG_IPV6_OPTIMISTIC_DAD 43#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
44 __s32 optimistic_dad; 44 __s32 optimistic_dad;
45 __s32 use_optimistic;
45#endif 46#endif
46#ifdef CONFIG_IPV6_MROUTE 47#ifdef CONFIG_IPV6_MROUTE
47 __s32 mc_forwarding; 48 __s32 mc_forwarding;
diff --git a/include/uapi/linux/ipv6.h b/include/uapi/linux/ipv6.h
index efa2666f4b8a..e863d088b9a5 100644
--- a/include/uapi/linux/ipv6.h
+++ b/include/uapi/linux/ipv6.h
@@ -164,6 +164,7 @@ enum {
164 DEVCONF_MLDV2_UNSOLICITED_REPORT_INTERVAL, 164 DEVCONF_MLDV2_UNSOLICITED_REPORT_INTERVAL,
165 DEVCONF_SUPPRESS_FRAG_NDISC, 165 DEVCONF_SUPPRESS_FRAG_NDISC,
166 DEVCONF_ACCEPT_RA_FROM_LOCAL, 166 DEVCONF_ACCEPT_RA_FROM_LOCAL,
167 DEVCONF_USE_OPTIMISTIC,
167 DEVCONF_MAX 168 DEVCONF_MAX
168}; 169};
169 170
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 50b95b2db87c..8d12b7c7018f 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -1170,6 +1170,9 @@ enum {
1170 IPV6_SADDR_RULE_PRIVACY, 1170 IPV6_SADDR_RULE_PRIVACY,
1171 IPV6_SADDR_RULE_ORCHID, 1171 IPV6_SADDR_RULE_ORCHID,
1172 IPV6_SADDR_RULE_PREFIX, 1172 IPV6_SADDR_RULE_PREFIX,
1173#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
1174 IPV6_SADDR_RULE_NOT_OPTIMISTIC,
1175#endif
1173 IPV6_SADDR_RULE_MAX 1176 IPV6_SADDR_RULE_MAX
1174}; 1177};
1175 1178
@@ -1197,6 +1200,15 @@ static inline int ipv6_saddr_preferred(int type)
1197 return 0; 1200 return 0;
1198} 1201}
1199 1202
1203static inline bool ipv6_use_optimistic_addr(struct inet6_dev *idev)
1204{
1205#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
1206 return idev && idev->cnf.optimistic_dad && idev->cnf.use_optimistic;
1207#else
1208 return false;
1209#endif
1210}
1211
1200static int ipv6_get_saddr_eval(struct net *net, 1212static int ipv6_get_saddr_eval(struct net *net,
1201 struct ipv6_saddr_score *score, 1213 struct ipv6_saddr_score *score,
1202 struct ipv6_saddr_dst *dst, 1214 struct ipv6_saddr_dst *dst,
@@ -1257,10 +1269,16 @@ static int ipv6_get_saddr_eval(struct net *net,
1257 score->scopedist = ret; 1269 score->scopedist = ret;
1258 break; 1270 break;
1259 case IPV6_SADDR_RULE_PREFERRED: 1271 case IPV6_SADDR_RULE_PREFERRED:
1272 {
1260 /* Rule 3: Avoid deprecated and optimistic addresses */ 1273 /* Rule 3: Avoid deprecated and optimistic addresses */
1274 u8 avoid = IFA_F_DEPRECATED;
1275
1276 if (!ipv6_use_optimistic_addr(score->ifa->idev))
1277 avoid |= IFA_F_OPTIMISTIC;
1261 ret = ipv6_saddr_preferred(score->addr_type) || 1278 ret = ipv6_saddr_preferred(score->addr_type) ||
1262 !(score->ifa->flags & (IFA_F_DEPRECATED|IFA_F_OPTIMISTIC)); 1279 !(score->ifa->flags & avoid);
1263 break; 1280 break;
1281 }
1264#ifdef CONFIG_IPV6_MIP6 1282#ifdef CONFIG_IPV6_MIP6
1265 case IPV6_SADDR_RULE_HOA: 1283 case IPV6_SADDR_RULE_HOA:
1266 { 1284 {
@@ -1306,6 +1324,14 @@ static int ipv6_get_saddr_eval(struct net *net,
1306 ret = score->ifa->prefix_len; 1324 ret = score->ifa->prefix_len;
1307 score->matchlen = ret; 1325 score->matchlen = ret;
1308 break; 1326 break;
1327#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
1328 case IPV6_SADDR_RULE_NOT_OPTIMISTIC:
1329 /* Optimistic addresses still have lower precedence than other
1330 * preferred addresses.
1331 */
1332 ret = !(score->ifa->flags & IFA_F_OPTIMISTIC);
1333 break;
1334#endif
1309 default: 1335 default:
1310 ret = 0; 1336 ret = 0;
1311 } 1337 }
@@ -3222,8 +3248,15 @@ static void addrconf_dad_begin(struct inet6_ifaddr *ifp)
3222 * Optimistic nodes can start receiving 3248 * Optimistic nodes can start receiving
3223 * Frames right away 3249 * Frames right away
3224 */ 3250 */
3225 if (ifp->flags & IFA_F_OPTIMISTIC) 3251 if (ifp->flags & IFA_F_OPTIMISTIC) {
3226 ip6_ins_rt(ifp->rt); 3252 ip6_ins_rt(ifp->rt);
3253 if (ipv6_use_optimistic_addr(idev)) {
3254 /* Because optimistic nodes can use this address,
3255 * notify listeners. If DAD fails, RTM_DELADDR is sent.
3256 */
3257 ipv6_ifa_notify(RTM_NEWADDR, ifp);
3258 }
3259 }
3227 3260
3228 addrconf_dad_kick(ifp); 3261 addrconf_dad_kick(ifp);
3229out: 3262out:
@@ -4330,6 +4363,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
4330 array[DEVCONF_ACCEPT_SOURCE_ROUTE] = cnf->accept_source_route; 4363 array[DEVCONF_ACCEPT_SOURCE_ROUTE] = cnf->accept_source_route;
4331#ifdef CONFIG_IPV6_OPTIMISTIC_DAD 4364#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
4332 array[DEVCONF_OPTIMISTIC_DAD] = cnf->optimistic_dad; 4365 array[DEVCONF_OPTIMISTIC_DAD] = cnf->optimistic_dad;
4366 array[DEVCONF_USE_OPTIMISTIC] = cnf->use_optimistic;
4333#endif 4367#endif
4334#ifdef CONFIG_IPV6_MROUTE 4368#ifdef CONFIG_IPV6_MROUTE
4335 array[DEVCONF_MC_FORWARDING] = cnf->mc_forwarding; 4369 array[DEVCONF_MC_FORWARDING] = cnf->mc_forwarding;
@@ -5155,6 +5189,14 @@ static struct addrconf_sysctl_table
5155 .proc_handler = proc_dointvec, 5189 .proc_handler = proc_dointvec,
5156 5190
5157 }, 5191 },
5192 {
5193 .procname = "use_optimistic",
5194 .data = &ipv6_devconf.use_optimistic,
5195 .maxlen = sizeof(int),
5196 .mode = 0644,
5197 .proc_handler = proc_dointvec,
5198
5199 },
5158#endif 5200#endif
5159#ifdef CONFIG_IPV6_MROUTE 5201#ifdef CONFIG_IPV6_MROUTE
5160 { 5202 {