aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaciej Żenczykowski <maze@google.com>2016-09-28 02:57:58 -0400
committerDavid S. Miller <davem@davemloft.net>2016-09-30 01:54:28 -0400
commitbd11f0741fa5a2c296629898ad07759dd12b35bb (patch)
treee25b67382a3798f6274bc4e85c06a1133deb56a2
parentbcdc6efabda3ba6a67f4cb8915873e7d6759b7e6 (diff)
ipv6 addrconf: implement RFC7559 router solicitation backoff
This implements: https://tools.ietf.org/html/rfc7559 Backoff is performed according to RFC3315 section 14: https://tools.ietf.org/html/rfc3315#section-14 We allow setting /proc/sys/net/ipv6/conf/*/router_solicitations to a negative value meaning an unlimited number of retransmits, and we make this the new default (inline with the RFC). We also add a new setting: /proc/sys/net/ipv6/conf/*/router_solicitation_max_interval defaulting to 1 hour (per RFC recommendation). Signed-off-by: Maciej Żenczykowski <maze@google.com> Acked-by: Erik Kline <ek@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/ipv6.h1
-rw-r--r--include/net/addrconf.h3
-rw-r--r--include/net/if_inet6.h1
-rw-r--r--include/uapi/linux/ipv6.h1
-rw-r--r--net/ipv6/addrconf.c51
5 files changed, 49 insertions, 8 deletions
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index c6dbcd84a2c7..7e9a789be5e0 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -18,6 +18,7 @@ struct ipv6_devconf {
18 __s32 dad_transmits; 18 __s32 dad_transmits;
19 __s32 rtr_solicits; 19 __s32 rtr_solicits;
20 __s32 rtr_solicit_interval; 20 __s32 rtr_solicit_interval;
21 __s32 rtr_solicit_max_interval;
21 __s32 rtr_solicit_delay; 22 __s32 rtr_solicit_delay;
22 __s32 force_mld_version; 23 __s32 force_mld_version;
23 __s32 mldv1_unsolicited_report_interval; 24 __s32 mldv1_unsolicited_report_interval;
diff --git a/include/net/addrconf.h b/include/net/addrconf.h
index 9826d3a9464c..f2d072787947 100644
--- a/include/net/addrconf.h
+++ b/include/net/addrconf.h
@@ -1,8 +1,9 @@
1#ifndef _ADDRCONF_H 1#ifndef _ADDRCONF_H
2#define _ADDRCONF_H 2#define _ADDRCONF_H
3 3
4#define MAX_RTR_SOLICITATIONS 3 4#define MAX_RTR_SOLICITATIONS -1 /* unlimited */
5#define RTR_SOLICITATION_INTERVAL (4*HZ) 5#define RTR_SOLICITATION_INTERVAL (4*HZ)
6#define RTR_SOLICITATION_MAX_INTERVAL (3600*HZ) /* 1 hour */
6 7
7#define MIN_VALID_LIFETIME (2*3600) /* 2 hours */ 8#define MIN_VALID_LIFETIME (2*3600) /* 2 hours */
8 9
diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h
index 1c8b6820b694..515352c6280a 100644
--- a/include/net/if_inet6.h
+++ b/include/net/if_inet6.h
@@ -201,6 +201,7 @@ struct inet6_dev {
201 struct ipv6_devstat stats; 201 struct ipv6_devstat stats;
202 202
203 struct timer_list rs_timer; 203 struct timer_list rs_timer;
204 __s32 rs_interval; /* in jiffies */
204 __u8 rs_probes; 205 __u8 rs_probes;
205 206
206 __u8 addr_gen_mode; 207 __u8 addr_gen_mode;
diff --git a/include/uapi/linux/ipv6.h b/include/uapi/linux/ipv6.h
index 395876060f50..8c2772340c3f 100644
--- a/include/uapi/linux/ipv6.h
+++ b/include/uapi/linux/ipv6.h
@@ -177,6 +177,7 @@ enum {
177 DEVCONF_DROP_UNICAST_IN_L2_MULTICAST, 177 DEVCONF_DROP_UNICAST_IN_L2_MULTICAST,
178 DEVCONF_DROP_UNSOLICITED_NA, 178 DEVCONF_DROP_UNSOLICITED_NA,
179 DEVCONF_KEEP_ADDR_ON_DOWN, 179 DEVCONF_KEEP_ADDR_ON_DOWN,
180 DEVCONF_RTR_SOLICIT_MAX_INTERVAL,
180 DEVCONF_MAX 181 DEVCONF_MAX
181}; 182};
182 183
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 35d4baa55c9d..87183983724d 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -112,6 +112,27 @@ static inline u32 cstamp_delta(unsigned long cstamp)
112 return (cstamp - INITIAL_JIFFIES) * 100UL / HZ; 112 return (cstamp - INITIAL_JIFFIES) * 100UL / HZ;
113} 113}
114 114
115static inline s32 rfc3315_s14_backoff_init(s32 irt)
116{
117 /* multiply 'initial retransmission time' by 0.9 .. 1.1 */
118 u64 tmp = (900000 + prandom_u32() % 200001) * (u64)irt;
119 do_div(tmp, 1000000);
120 return (s32)tmp;
121}
122
123static inline s32 rfc3315_s14_backoff_update(s32 rt, s32 mrt)
124{
125 /* multiply 'retransmission timeout' by 1.9 .. 2.1 */
126 u64 tmp = (1900000 + prandom_u32() % 200001) * (u64)rt;
127 do_div(tmp, 1000000);
128 if ((s32)tmp > mrt) {
129 /* multiply 'maximum retransmission time' by 0.9 .. 1.1 */
130 tmp = (900000 + prandom_u32() % 200001) * (u64)mrt;
131 do_div(tmp, 1000000);
132 }
133 return (s32)tmp;
134}
135
115#ifdef CONFIG_SYSCTL 136#ifdef CONFIG_SYSCTL
116static int addrconf_sysctl_register(struct inet6_dev *idev); 137static int addrconf_sysctl_register(struct inet6_dev *idev);
117static void addrconf_sysctl_unregister(struct inet6_dev *idev); 138static void addrconf_sysctl_unregister(struct inet6_dev *idev);
@@ -187,6 +208,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
187 .dad_transmits = 1, 208 .dad_transmits = 1,
188 .rtr_solicits = MAX_RTR_SOLICITATIONS, 209 .rtr_solicits = MAX_RTR_SOLICITATIONS,
189 .rtr_solicit_interval = RTR_SOLICITATION_INTERVAL, 210 .rtr_solicit_interval = RTR_SOLICITATION_INTERVAL,
211 .rtr_solicit_max_interval = RTR_SOLICITATION_MAX_INTERVAL,
190 .rtr_solicit_delay = MAX_RTR_SOLICITATION_DELAY, 212 .rtr_solicit_delay = MAX_RTR_SOLICITATION_DELAY,
191 .use_tempaddr = 0, 213 .use_tempaddr = 0,
192 .temp_valid_lft = TEMP_VALID_LIFETIME, 214 .temp_valid_lft = TEMP_VALID_LIFETIME,
@@ -232,6 +254,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
232 .dad_transmits = 1, 254 .dad_transmits = 1,
233 .rtr_solicits = MAX_RTR_SOLICITATIONS, 255 .rtr_solicits = MAX_RTR_SOLICITATIONS,
234 .rtr_solicit_interval = RTR_SOLICITATION_INTERVAL, 256 .rtr_solicit_interval = RTR_SOLICITATION_INTERVAL,
257 .rtr_solicit_max_interval = RTR_SOLICITATION_MAX_INTERVAL,
235 .rtr_solicit_delay = MAX_RTR_SOLICITATION_DELAY, 258 .rtr_solicit_delay = MAX_RTR_SOLICITATION_DELAY,
236 .use_tempaddr = 0, 259 .use_tempaddr = 0,
237 .temp_valid_lft = TEMP_VALID_LIFETIME, 260 .temp_valid_lft = TEMP_VALID_LIFETIME,
@@ -3687,7 +3710,7 @@ static void addrconf_rs_timer(unsigned long data)
3687 if (idev->if_flags & IF_RA_RCVD) 3710 if (idev->if_flags & IF_RA_RCVD)
3688 goto out; 3711 goto out;
3689 3712
3690 if (idev->rs_probes++ < idev->cnf.rtr_solicits) { 3713 if (idev->rs_probes++ < idev->cnf.rtr_solicits || idev->cnf.rtr_solicits < 0) {
3691 write_unlock(&idev->lock); 3714 write_unlock(&idev->lock);
3692 if (!ipv6_get_lladdr(dev, &lladdr, IFA_F_TENTATIVE)) 3715 if (!ipv6_get_lladdr(dev, &lladdr, IFA_F_TENTATIVE))
3693 ndisc_send_rs(dev, &lladdr, 3716 ndisc_send_rs(dev, &lladdr,
@@ -3696,11 +3719,13 @@ static void addrconf_rs_timer(unsigned long data)
3696 goto put; 3719 goto put;
3697 3720
3698 write_lock(&idev->lock); 3721 write_lock(&idev->lock);
3722 idev->rs_interval = rfc3315_s14_backoff_update(
3723 idev->rs_interval, idev->cnf.rtr_solicit_max_interval);
3699 /* The wait after the last probe can be shorter */ 3724 /* The wait after the last probe can be shorter */
3700 addrconf_mod_rs_timer(idev, (idev->rs_probes == 3725 addrconf_mod_rs_timer(idev, (idev->rs_probes ==
3701 idev->cnf.rtr_solicits) ? 3726 idev->cnf.rtr_solicits) ?
3702 idev->cnf.rtr_solicit_delay : 3727 idev->cnf.rtr_solicit_delay :
3703 idev->cnf.rtr_solicit_interval); 3728 idev->rs_interval);
3704 } else { 3729 } else {
3705 /* 3730 /*
3706 * Note: we do not support deprecated "all on-link" 3731 * Note: we do not support deprecated "all on-link"
@@ -3949,7 +3974,7 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
3949 send_mld = ifp->scope == IFA_LINK && ipv6_lonely_lladdr(ifp); 3974 send_mld = ifp->scope == IFA_LINK && ipv6_lonely_lladdr(ifp);
3950 send_rs = send_mld && 3975 send_rs = send_mld &&
3951 ipv6_accept_ra(ifp->idev) && 3976 ipv6_accept_ra(ifp->idev) &&
3952 ifp->idev->cnf.rtr_solicits > 0 && 3977 ifp->idev->cnf.rtr_solicits != 0 &&
3953 (dev->flags&IFF_LOOPBACK) == 0; 3978 (dev->flags&IFF_LOOPBACK) == 0;
3954 read_unlock_bh(&ifp->idev->lock); 3979 read_unlock_bh(&ifp->idev->lock);
3955 3980
@@ -3971,10 +3996,11 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
3971 3996
3972 write_lock_bh(&ifp->idev->lock); 3997 write_lock_bh(&ifp->idev->lock);
3973 spin_lock(&ifp->lock); 3998 spin_lock(&ifp->lock);
3999 ifp->idev->rs_interval = rfc3315_s14_backoff_init(
4000 ifp->idev->cnf.rtr_solicit_interval);
3974 ifp->idev->rs_probes = 1; 4001 ifp->idev->rs_probes = 1;
3975 ifp->idev->if_flags |= IF_RS_SENT; 4002 ifp->idev->if_flags |= IF_RS_SENT;
3976 addrconf_mod_rs_timer(ifp->idev, 4003 addrconf_mod_rs_timer(ifp->idev, ifp->idev->rs_interval);
3977 ifp->idev->cnf.rtr_solicit_interval);
3978 spin_unlock(&ifp->lock); 4004 spin_unlock(&ifp->lock);
3979 write_unlock_bh(&ifp->idev->lock); 4005 write_unlock_bh(&ifp->idev->lock);
3980 } 4006 }
@@ -4891,6 +4917,8 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
4891 array[DEVCONF_RTR_SOLICITS] = cnf->rtr_solicits; 4917 array[DEVCONF_RTR_SOLICITS] = cnf->rtr_solicits;
4892 array[DEVCONF_RTR_SOLICIT_INTERVAL] = 4918 array[DEVCONF_RTR_SOLICIT_INTERVAL] =
4893 jiffies_to_msecs(cnf->rtr_solicit_interval); 4919 jiffies_to_msecs(cnf->rtr_solicit_interval);
4920 array[DEVCONF_RTR_SOLICIT_MAX_INTERVAL] =
4921 jiffies_to_msecs(cnf->rtr_solicit_max_interval);
4894 array[DEVCONF_RTR_SOLICIT_DELAY] = 4922 array[DEVCONF_RTR_SOLICIT_DELAY] =
4895 jiffies_to_msecs(cnf->rtr_solicit_delay); 4923 jiffies_to_msecs(cnf->rtr_solicit_delay);
4896 array[DEVCONF_FORCE_MLD_VERSION] = cnf->force_mld_version; 4924 array[DEVCONF_FORCE_MLD_VERSION] = cnf->force_mld_version;
@@ -5099,7 +5127,7 @@ static int inet6_set_iftoken(struct inet6_dev *idev, struct in6_addr *token)
5099 return -EINVAL; 5127 return -EINVAL;
5100 if (!ipv6_accept_ra(idev)) 5128 if (!ipv6_accept_ra(idev))
5101 return -EINVAL; 5129 return -EINVAL;
5102 if (idev->cnf.rtr_solicits <= 0) 5130 if (idev->cnf.rtr_solicits == 0)
5103 return -EINVAL; 5131 return -EINVAL;
5104 5132
5105 write_lock_bh(&idev->lock); 5133 write_lock_bh(&idev->lock);
@@ -5128,8 +5156,10 @@ update_lft:
5128 5156
5129 if (update_rs) { 5157 if (update_rs) {
5130 idev->if_flags |= IF_RS_SENT; 5158 idev->if_flags |= IF_RS_SENT;
5159 idev->rs_interval = rfc3315_s14_backoff_init(
5160 idev->cnf.rtr_solicit_interval);
5131 idev->rs_probes = 1; 5161 idev->rs_probes = 1;
5132 addrconf_mod_rs_timer(idev, idev->cnf.rtr_solicit_interval); 5162 addrconf_mod_rs_timer(idev, idev->rs_interval);
5133 } 5163 }
5134 5164
5135 /* Well, that's kinda nasty ... */ 5165 /* Well, that's kinda nasty ... */
@@ -5778,6 +5808,13 @@ static const struct ctl_table addrconf_sysctl[] = {
5778 .proc_handler = proc_dointvec_jiffies, 5808 .proc_handler = proc_dointvec_jiffies,
5779 }, 5809 },
5780 { 5810 {
5811 .procname = "router_solicitation_max_interval",
5812 .data = &ipv6_devconf.rtr_solicit_max_interval,
5813 .maxlen = sizeof(int),
5814 .mode = 0644,
5815 .proc_handler = proc_dointvec_jiffies,
5816 },
5817 {
5781 .procname = "router_solicitation_delay", 5818 .procname = "router_solicitation_delay",
5782 .data = &ipv6_devconf.rtr_solicit_delay, 5819 .data = &ipv6_devconf.rtr_solicit_delay,
5783 .maxlen = sizeof(int), 5820 .maxlen = sizeof(int),