Module Name: src
Committed By: ozaki-r
Date: Mon Feb 13 07:18:20 UTC 2017
Modified Files:
src/sys/netinet: in_proto.c ip_icmp.c
src/sys/netinet6: icmp6.c in6_proto.c
Log Message:
Protect mtudisc and redirect stuffs of icmp/icmp6 with mutex
We have to run pr_init of icmp and icmp6 prior to tcp and tcp6 ones
for mutex initialization.
To generate a diff of this commit:
cvs rdiff -u -r1.120 -r1.121 src/sys/netinet/in_proto.c
cvs rdiff -u -r1.157 -r1.158 src/sys/netinet/ip_icmp.c
cvs rdiff -u -r1.208 -r1.209 src/sys/netinet6/icmp6.c
cvs rdiff -u -r1.114 -r1.115 src/sys/netinet6/in6_proto.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/netinet/in_proto.c
diff -u src/sys/netinet/in_proto.c:1.120 src/sys/netinet/in_proto.c:1.121
--- src/sys/netinet/in_proto.c:1.120 Tue Apr 26 08:44:44 2016
+++ src/sys/netinet/in_proto.c Mon Feb 13 07:18:20 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: in_proto.c,v 1.120 2016/04/26 08:44:44 ozaki-r Exp $ */
+/* $NetBSD: in_proto.c,v 1.121 2017/02/13 07:18:20 ozaki-r Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -61,7 +61,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in_proto.c,v 1.120 2016/04/26 08:44:44 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in_proto.c,v 1.121 2017/02/13 07:18:20 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_mrouting.h"
@@ -201,6 +201,16 @@ const struct protosw inetsw[] = {
.pr_slowtimo = ip_slowtimo,
.pr_drain = ip_drainstub,
},
+{ .pr_type = SOCK_RAW,
+ .pr_domain = &inetdomain,
+ .pr_protocol = IPPROTO_ICMP,
+ .pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR,
+ .pr_input = icmp_input,
+ .pr_ctlinput = rip_ctlinput,
+ .pr_ctloutput = rip_ctloutput,
+ .pr_usrreqs = &rip_usrreqs,
+ .pr_init = icmp_init,
+},
{ .pr_type = SOCK_DGRAM,
.pr_domain = &inetdomain,
.pr_protocol = IPPROTO_UDP,
@@ -277,16 +287,6 @@ const struct protosw inetsw[] = {
.pr_ctloutput = rip_ctloutput,
.pr_usrreqs = &rip_usrreqs,
},
-{ .pr_type = SOCK_RAW,
- .pr_domain = &inetdomain,
- .pr_protocol = IPPROTO_ICMP,
- .pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR,
- .pr_input = icmp_input,
- .pr_ctlinput = rip_ctlinput,
- .pr_ctloutput = rip_ctloutput,
- .pr_usrreqs = &rip_usrreqs,
- .pr_init = icmp_init,
-},
#ifdef GATEWAY
{ .pr_domain = &inetdomain,
.pr_protocol = IPPROTO_IP,
Index: src/sys/netinet/ip_icmp.c
diff -u src/sys/netinet/ip_icmp.c:1.157 src/sys/netinet/ip_icmp.c:1.158
--- src/sys/netinet/ip_icmp.c:1.157 Tue Feb 7 02:38:08 2017
+++ src/sys/netinet/ip_icmp.c Mon Feb 13 07:18:20 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: ip_icmp.c,v 1.157 2017/02/07 02:38:08 ozaki-r Exp $ */
+/* $NetBSD: ip_icmp.c,v 1.158 2017/02/13 07:18:20 ozaki-r Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -94,7 +94,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip_icmp.c,v 1.157 2017/02/07 02:38:08 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip_icmp.c,v 1.158 2017/02/13 07:18:20 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_ipsec.h"
@@ -171,6 +171,9 @@ static int icmp_rediraccept = 1;
static int icmp_redirtimeout = 600;
static struct rttimer_queue *icmp_redirect_timeout_q = NULL;
+/* Protect mtudisc and redirect stuffs */
+static kmutex_t icmp_mtx __cacheline_aligned;
+
static void icmp_mtudisc_timeout(struct rtentry *, struct rttimer *);
static void icmp_redirect_timeout(struct rtentry *, struct rttimer *);
@@ -186,14 +189,17 @@ icmp_init(void)
sysctl_netinet_icmp_setup(NULL);
+ mutex_init(&icmp_mtx, MUTEX_DEFAULT, IPL_NONE);
/*
* This is only useful if the user initializes redirtimeout to
* something other than zero.
*/
+ mutex_enter(&icmp_mtx);
if (icmp_redirtimeout != 0) {
icmp_redirect_timeout_q =
rt_timer_queue_create(icmp_redirtimeout);
}
+ mutex_exit(&icmp_mtx);
icmpstat_percpu = percpu_alloc(sizeof(uint64_t) * ICMP_NSTATS);
icmp_wqinput = wqinput_create("icmp", _icmp_input);
@@ -205,17 +211,23 @@ icmp_init(void)
void
icmp_mtudisc_callback_register(void (*func)(struct in_addr))
{
- struct icmp_mtudisc_callback *mc;
+ struct icmp_mtudisc_callback *mc, *new;
+
+ new = kmem_alloc(sizeof(*mc), KM_SLEEP);
+ mutex_enter(&icmp_mtx);
for (mc = LIST_FIRST(&icmp_mtudisc_callbacks); mc != NULL;
mc = LIST_NEXT(mc, mc_list)) {
- if (mc->mc_func == func)
+ if (mc->mc_func == func) {
+ mutex_exit(&icmp_mtx);
+ kmem_free(new, sizeof(*mc));
return;
+ }
}
- mc = kmem_alloc(sizeof(*mc), KM_SLEEP);
- mc->mc_func = func;
- LIST_INSERT_HEAD(&icmp_mtudisc_callbacks, mc, mc_list);
+ new->mc_func = func;
+ LIST_INSERT_HEAD(&icmp_mtudisc_callbacks, new, mc_list);
+ mutex_exit(&icmp_mtx);
}
/*
@@ -640,6 +652,7 @@ reflect:
rt = NULL;
rtredirect(sintosa(&icmpsrc), sintosa(&icmpdst),
NULL, RTF_GATEWAY | RTF_HOST, sintosa(&icmpgw), &rt);
+ mutex_enter(&icmp_mtx);
if (rt != NULL && icmp_redirtimeout != 0) {
i = rt_timer_add(rt, icmp_redirect_timeout,
icmp_redirect_timeout_q);
@@ -651,6 +664,7 @@ reflect:
IN_PRINT(buf, &icp->icmp_ip.ip_dst), i);
}
}
+ mutex_exit(&icmp_mtx);
if (rt != NULL)
rt_unref(rt);
@@ -1016,19 +1030,20 @@ sysctl_net_inet_icmp_redirtimeout(SYSCTL
int error, tmp;
struct sysctlnode node;
+ mutex_enter(&icmp_mtx);
+
node = *rnode;
node.sysctl_data = &tmp;
tmp = icmp_redirtimeout;
error = sysctl_lookup(SYSCTLFN_CALL(&node));
if (error || newp == NULL)
- return (error);
- if (tmp < 0)
- return (EINVAL);
+ goto out;
+ if (tmp < 0) {
+ error = EINVAL;
+ goto out;
+ }
icmp_redirtimeout = tmp;
- /* XXX NOMPSAFE still need softnet_lock */
- mutex_enter(softnet_lock);
-
/*
* was it a *defined* side-effect that anyone even *reading*
* this value causes these things to happen?
@@ -1045,10 +1060,10 @@ sysctl_net_inet_icmp_redirtimeout(SYSCTL
icmp_redirect_timeout_q =
rt_timer_queue_create(icmp_redirtimeout);
}
-
- mutex_exit(softnet_lock);
-
- return (0);
+ error = 0;
+out:
+ mutex_exit(&icmp_mtx);
+ return error;
}
static int
@@ -1175,9 +1190,11 @@ icmp_mtudisc(struct icmp *icp, struct in
rt = nrt;
}
+ mutex_enter(&icmp_mtx);
if (ip_mtudisc_timeout_q == NULL)
ip_mtudisc_timeout_q = rt_timer_queue_create(ip_mtudisc_timeout);
error = rt_timer_add(rt, icmp_mtudisc_timeout, ip_mtudisc_timeout_q);
+ mutex_exit(&icmp_mtx);
if (error) {
rt_unref(rt);
return;
@@ -1234,9 +1251,11 @@ icmp_mtudisc(struct icmp *icp, struct in
* Notify protocols that the MTU for this destination
* has changed.
*/
+ mutex_enter(&icmp_mtx);
for (mc = LIST_FIRST(&icmp_mtudisc_callbacks); mc != NULL;
mc = LIST_NEXT(mc, mc_list))
(*mc->mc_func)(faddr);
+ mutex_exit(&icmp_mtx);
}
/*
Index: src/sys/netinet6/icmp6.c
diff -u src/sys/netinet6/icmp6.c:1.208 src/sys/netinet6/icmp6.c:1.209
--- src/sys/netinet6/icmp6.c:1.208 Tue Feb 7 02:38:08 2017
+++ src/sys/netinet6/icmp6.c Mon Feb 13 07:18:20 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: icmp6.c,v 1.208 2017/02/07 02:38:08 ozaki-r Exp $ */
+/* $NetBSD: icmp6.c,v 1.209 2017/02/13 07:18:20 ozaki-r Exp $ */
/* $KAME: icmp6.c,v 1.217 2001/06/20 15:03:29 jinmei Exp $ */
/*
@@ -62,7 +62,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: icmp6.c,v 1.208 2017/02/07 02:38:08 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: icmp6.c,v 1.209 2017/02/13 07:18:20 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@@ -152,6 +152,9 @@ static struct rttimer_queue *icmp6_redir
static int icmp6_redirect_hiwat = -1;
static int icmp6_redirect_lowat = -1;
+/* Protect mtudisc and redirect stuffs */
+static kmutex_t icmp6_mtx __cacheline_aligned;
+
static void icmp6_errcount(u_int, int, int);
static int icmp6_rip6_input(struct mbuf **, int);
static int icmp6_ratelimit(const struct in6_addr *, const int, const int);
@@ -180,8 +183,12 @@ icmp6_init(void)
sysctl_net_inet6_icmp6_setup(NULL);
mld_init();
+
+ mutex_init(&icmp6_mtx, MUTEX_DEFAULT, IPL_NONE);
+ mutex_enter(&icmp6_mtx);
icmp6_mtudisc_timeout_q = rt_timer_queue_create(pmtu_expire);
icmp6_redirect_timeout_q = rt_timer_queue_create(icmp6_redirtimeout);
+ mutex_exit(&icmp6_mtx);
icmp6stat_percpu = percpu_alloc(sizeof(uint64_t) * ICMP6_NSTATS);
@@ -253,17 +260,23 @@ icmp6_errcount(u_int base, int type, int
void
icmp6_mtudisc_callback_register(void (*func)(struct in6_addr *))
{
- struct icmp6_mtudisc_callback *mc;
+ struct icmp6_mtudisc_callback *mc, *new;
+
+ new = kmem_alloc(sizeof(*mc), KM_SLEEP);
+ mutex_enter(&icmp6_mtx);
for (mc = LIST_FIRST(&icmp6_mtudisc_callbacks); mc != NULL;
mc = LIST_NEXT(mc, mc_list)) {
- if (mc->mc_func == func)
+ if (mc->mc_func == func) {
+ mutex_exit(&icmp6_mtx);
+ kmem_free(new, sizeof(*mc));
return;
+ }
}
- mc = kmem_alloc(sizeof(*mc), KM_SLEEP);
- mc->mc_func = func;
- LIST_INSERT_HEAD(&icmp6_mtudisc_callbacks, mc, mc_list);
+ new->mc_func = func;
+ LIST_INSERT_HEAD(&icmp6_mtudisc_callbacks, new, mc_list);
+ mutex_exit(&icmp6_mtx);
}
/*
@@ -1146,10 +1159,13 @@ icmp6_mtudisc_update(struct ip6ctlparam
* allow non-validated cases if memory is plenty, to make traffic
* from non-connected pcb happy.
*/
+ mutex_enter(&icmp6_mtx);
rtcount = rt_timer_count(icmp6_mtudisc_timeout_q);
if (validated) {
- if (0 <= icmp6_mtudisc_hiwat && rtcount > icmp6_mtudisc_hiwat)
+ if (0 <= icmp6_mtudisc_hiwat && rtcount > icmp6_mtudisc_hiwat) {
+ mutex_exit(&icmp6_mtx);
return;
+ }
else if (0 <= icmp6_mtudisc_lowat &&
rtcount > icmp6_mtudisc_lowat) {
/*
@@ -1157,9 +1173,12 @@ icmp6_mtudisc_update(struct ip6ctlparam
*/
}
} else {
- if (0 <= icmp6_mtudisc_lowat && rtcount > icmp6_mtudisc_lowat)
+ if (0 <= icmp6_mtudisc_lowat && rtcount > icmp6_mtudisc_lowat) {
+ mutex_exit(&icmp6_mtx);
return;
+ }
}
+ mutex_exit(&icmp6_mtx);
memset(&sin6, 0, sizeof(sin6));
sin6.sin6_family = PF_INET6;
@@ -1192,9 +1211,11 @@ icmp6_mtudisc_update(struct ip6ctlparam
* Notify protocols that the MTU for this destination
* has changed.
*/
+ mutex_enter(&icmp6_mtx);
for (mc = LIST_FIRST(&icmp6_mtudisc_callbacks); mc != NULL;
mc = LIST_NEXT(mc, mc_list))
(*mc->mc_func)(&sin6.sin6_addr);
+ mutex_exit(&icmp6_mtx);
}
/*
@@ -2382,12 +2403,16 @@ icmp6_redirect_input(struct mbuf *m, int
* work just fine even if we do not install redirect route
* (there will be additional hops, though).
*/
+ mutex_enter(&icmp6_mtx);
rtcount = rt_timer_count(icmp6_redirect_timeout_q);
- if (0 <= ip6_maxdynroutes && rtcount >= ip6_maxdynroutes)
+ if (0 <= ip6_maxdynroutes && rtcount >= ip6_maxdynroutes) {
+ mutex_exit(&icmp6_mtx);
goto freeit;
- if (0 <= icmp6_redirect_hiwat && rtcount > icmp6_redirect_hiwat)
+ }
+ if (0 <= icmp6_redirect_hiwat && rtcount > icmp6_redirect_hiwat) {
+ mutex_exit(&icmp6_mtx);
goto freeit;
- else if (0 <= icmp6_redirect_lowat &&
+ } else if (0 <= icmp6_redirect_lowat &&
rtcount > icmp6_redirect_lowat) {
/*
* XXX nuke a victim, install the new one.
@@ -2412,6 +2437,7 @@ icmp6_redirect_input(struct mbuf *m, int
icmp6_redirect_timeout_q);
rt_unref(newrt);
}
+ mutex_exit(&icmp6_mtx);
}
/* finally update cached route in each socket via pfctlinput */
{
@@ -2804,8 +2830,12 @@ icmp6_mtudisc_clone(struct sockaddr *dst
rt_unref(rt);
rt = nrt;
}
+
+ mutex_enter(&icmp6_mtx);
error = rt_timer_add(rt, icmp6_mtudisc_timeout,
icmp6_mtudisc_timeout_q);
+ mutex_exit(&icmp6_mtx);
+
if (error) {
rt_unref(rt);
return NULL;
@@ -2876,14 +2906,18 @@ sysctl_net_inet6_icmp6_redirtimeout(SYSC
int error, tmp;
struct sysctlnode node;
+ mutex_enter(&icmp6_mtx);
+
node = *rnode;
node.sysctl_data = &tmp;
tmp = icmp6_redirtimeout;
error = sysctl_lookup(SYSCTLFN_CALL(&node));
if (error || newp == NULL)
- return error;
- if (tmp < 0)
- return EINVAL;
+ goto out;
+ if (tmp < 0) {
+ error = EINVAL;
+ goto out;
+ }
icmp6_redirtimeout = tmp;
if (icmp6_redirect_timeout_q != NULL) {
@@ -2897,8 +2931,10 @@ sysctl_net_inet6_icmp6_redirtimeout(SYSC
icmp6_redirect_timeout_q =
rt_timer_queue_create(icmp6_redirtimeout);
}
-
- return 0;
+ error = 0;
+out:
+ mutex_exit(&icmp6_mtx);
+ return error;
}
static void
Index: src/sys/netinet6/in6_proto.c
diff -u src/sys/netinet6/in6_proto.c:1.114 src/sys/netinet6/in6_proto.c:1.115
--- src/sys/netinet6/in6_proto.c:1.114 Tue Dec 13 08:29:03 2016
+++ src/sys/netinet6/in6_proto.c Mon Feb 13 07:18:20 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: in6_proto.c,v 1.114 2016/12/13 08:29:03 ozaki-r Exp $ */
+/* $NetBSD: in6_proto.c,v 1.115 2017/02/13 07:18:20 ozaki-r Exp $ */
/* $KAME: in6_proto.c,v 1.66 2000/10/10 15:35:47 itojun Exp $ */
/*
@@ -62,7 +62,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in6_proto.c,v 1.114 2016/12/13 08:29:03 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in6_proto.c,v 1.115 2017/02/13 07:18:20 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_gateway.h"
@@ -213,6 +213,16 @@ const struct ip6protosw inet6sw[] = {
.pr_slowtimo = frag6_slowtimo,
.pr_drain = frag6_drainstub,
},
+{ .pr_type = SOCK_RAW,
+ .pr_domain = &inet6domain,
+ .pr_protocol = IPPROTO_ICMPV6,
+ .pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR,
+ .pr_input = icmp6_input,
+ .pr_ctlinput = rip6_ctlinput,
+ .pr_ctloutput = icmp6_ctloutput,
+ .pr_usrreqs = &rip6_usrreqs,
+ .pr_init = icmp6_init,
+},
{ .pr_type = SOCK_DGRAM,
.pr_domain = &inet6domain,
.pr_protocol = IPPROTO_UDP,
@@ -297,16 +307,6 @@ const struct ip6protosw inet6sw[] = {
#endif /* GATEWAY */
{ .pr_type = SOCK_RAW,
.pr_domain = &inet6domain,
- .pr_protocol = IPPROTO_ICMPV6,
- .pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR,
- .pr_input = icmp6_input,
- .pr_ctlinput = rip6_ctlinput,
- .pr_ctloutput = icmp6_ctloutput,
- .pr_usrreqs = &rip6_usrreqs,
- .pr_init = icmp6_init,
-},
-{ .pr_type = SOCK_RAW,
- .pr_domain = &inet6domain,
.pr_protocol = IPPROTO_DSTOPTS,
.pr_flags = PR_ATOMIC|PR_ADDR,
.pr_input = dest6_input,