diff options
author | Maciej Żenczykowski <maze@google.com> | 2016-09-28 02:57:58 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-09-30 01:54:28 -0400 |
commit | bd11f0741fa5a2c296629898ad07759dd12b35bb (patch) | |
tree | e25b67382a3798f6274bc4e85c06a1133deb56a2 | |
parent | bcdc6efabda3ba6a67f4cb8915873e7d6759b7e6 (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.h | 1 | ||||
-rw-r--r-- | include/net/addrconf.h | 3 | ||||
-rw-r--r-- | include/net/if_inet6.h | 1 | ||||
-rw-r--r-- | include/uapi/linux/ipv6.h | 1 | ||||
-rw-r--r-- | net/ipv6/addrconf.c | 51 |
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 | ||
115 | static 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 | |||
123 | static 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 |
116 | static int addrconf_sysctl_register(struct inet6_dev *idev); | 137 | static int addrconf_sysctl_register(struct inet6_dev *idev); |
117 | static void addrconf_sysctl_unregister(struct inet6_dev *idev); | 138 | static 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), |