From: Sepherosa Ziehau Date: Tue, 11 Nov 2008 10:46:58 +0000 (+0000) Subject: - If we receive redirect or host dead ICMP message due to packets sent on X-Git-Url: https://gitweb.dragonflybsd.org/~lentferj/dragonfly.git/commitdiff_plain/14572273ec6f6033125ce481d84fee0bfa70d7e5 - If we receive redirect or host dead ICMP message due to packets sent on TCP sockets, we need to go through all CPUs to check per-cpu TCP inpcbs. - If we receive redirect ICMP message due to packets sent on UDP sockets, we need to go through all CPUs to free UDP inpcbs' cached route entry. Reported-by: pavalos@ Tested-by: pavalos@ --- diff --git a/sys/netinet/ip_demux.c b/sys/netinet/ip_demux.c index cebb1f4959..8fd263b79d 100644 --- a/sys/netinet/ip_demux.c +++ b/sys/netinet/ip_demux.c @@ -30,7 +30,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/netinet/ip_demux.c,v 1.44 2008/10/28 07:09:26 sephe Exp $ + * $DragonFly: src/sys/netinet/ip_demux.c,v 1.45 2008/11/11 10:46:58 sephe Exp $ */ #include "opt_inet.h" @@ -347,8 +347,22 @@ tcp_ctlport(int cmd, struct sockaddr *sa, void *vip) faddr = ((struct sockaddr_in *)sa)->sin_addr; if (sa->sa_family != AF_INET || faddr.s_addr == INADDR_ANY) return(NULL); - if (ip == NULL) { - cpu = 0; + if (ip == NULL || PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) { + /* + * Message will be forwarded to all TCP protocol threads + * in following way: + * + * netisr0 (the msgport we return here) + * | + * | + * | domsg <----------------------------+ + * | | + * | | replymsg + * | | + * V forwardmsg forwardmsg | + * tcp0 ------------> tcp1 ------------> tcpN + */ + return cpu0_ctlport(cmd, sa, vip); } else { th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2)); cpu = tcp_addrcpu(faddr.s_addr, th->th_dport, @@ -411,7 +425,18 @@ udp_ctlport(int cmd, struct sockaddr *sa, void *vip) faddr = ((struct sockaddr_in *)sa)->sin_addr; if (sa->sa_family != AF_INET || faddr.s_addr == INADDR_ANY) return(NULL); - if (ip == NULL) { + if (PRC_IS_REDIRECT(cmd)) { + /* + * See the comment in tcp_ctlport; the only difference + * is that message is forwarded to UDP protocol theads. + */ + return cpu0_ctlport(cmd, sa, vip); + } else if (ip == NULL || cmd == PRC_HOSTDEAD) { + /* + * XXX + * Once UDP inpcbs are CPU localized, we should do + * the same forwarding as PRC_IS_REDIRECT(cmd) + */ cpu = 0; } else { uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2)); @@ -449,6 +474,12 @@ tcp_cport(int cpu) return (&tcp_thread[cpu].td_msgport); } +lwkt_port_t +udp_cport(int cpu) +{ + return (&udp_thread[cpu].td_msgport); +} + void tcp_thread_init(void) { diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index 0c6039b00f..f52320d689 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -65,7 +65,7 @@ * * @(#)tcp_subr.c 8.2 (Berkeley) 5/24/95 * $FreeBSD: src/sys/netinet/tcp_subr.c,v 1.73.2.31 2003/01/24 05:11:34 sam Exp $ - * $DragonFly: src/sys/netinet/tcp_subr.c,v 1.62 2008/10/30 10:50:18 sephe Exp $ + * $DragonFly: src/sys/netinet/tcp_subr.c,v 1.63 2008/11/11 10:46:58 sephe Exp $ */ #include "opt_compat.h" @@ -1312,6 +1312,29 @@ SYSCTL_PROC(_net_inet6_tcp6, OID_AUTO, getcred, (CTLTYPE_OPAQUE | CTLFLAG_RW), tcp6_getcred, "S,ucred", "Get the ucred of a TCP6 connection"); #endif +struct netmsg_tcp_notify { + struct netmsg nm_nmsg; + void (*nm_notify)(struct inpcb *, int); + struct in_addr nm_faddr; + int nm_arg; +}; + +static void +tcp_notifyall_oncpu(struct netmsg *netmsg) +{ + struct netmsg_tcp_notify *nmsg = (struct netmsg_tcp_notify *)netmsg; + int nextcpu; + + in_pcbnotifyall(&tcbinfo[mycpuid].pcblisthead, nmsg->nm_faddr, + nmsg->nm_arg, nmsg->nm_notify); + + nextcpu = mycpuid + 1; + if (nextcpu < ncpus2) + lwkt_forwardmsg(tcp_cport(nextcpu), &netmsg->nm_lmsg); + else + lwkt_replymsg(&netmsg->nm_lmsg, 0); +} + void tcp_ctlinput(int cmd, struct sockaddr *sa, void *vip) { @@ -1382,10 +1405,16 @@ tcp_ctlinput(int cmd, struct sockaddr *sa, void *vip) } crit_exit(); } else { - for (cpu = 0; cpu < ncpus2; cpu++) { - in_pcbnotifyall(&tcbinfo[cpu].pcblisthead, faddr, arg, - notify); - } + struct netmsg_tcp_notify nmsg; + + KKASSERT(&curthread->td_msgport == cpu_portfn(0)); + netmsg_init(&nmsg.nm_nmsg, &curthread->td_msgport, 0, + tcp_notifyall_oncpu); + nmsg.nm_faddr = faddr; + nmsg.nm_arg = arg; + nmsg.nm_notify = notify; + + lwkt_domsg(tcp_cport(0), &nmsg.nm_nmsg.nm_lmsg, 0); } } diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index 907a38521a..160df66e3c 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -65,7 +65,7 @@ * * @(#)udp_usrreq.c 8.6 (Berkeley) 5/23/95 * $FreeBSD: src/sys/netinet/udp_usrreq.c,v 1.64.2.18 2003/01/24 05:11:34 sam Exp $ - * $DragonFly: src/sys/netinet/udp_usrreq.c,v 1.46 2008/09/23 11:28:49 sephe Exp $ + * $DragonFly: src/sys/netinet/udp_usrreq.c,v 1.47 2008/11/11 10:46:58 sephe Exp $ */ #include "opt_ipsec.h" @@ -92,6 +92,7 @@ #include #include +#include #include #include @@ -608,6 +609,47 @@ udp_notify(struct inpcb *inp, int error) sowwakeup(inp->inp_socket); } +struct netmsg_udp_notify { + struct netmsg nm_nmsg; + void (*nm_notify)(struct inpcb *, int); + struct in_addr nm_faddr; + int nm_arg; +}; + +static void +udp_notifyall_oncpu(struct netmsg *netmsg) +{ + struct netmsg_udp_notify *nmsg = (struct netmsg_udp_notify *)netmsg; + int nextcpu; + + in_pcbnotifyall(&udbinfo.pcblisthead, nmsg->nm_faddr, nmsg->nm_arg, + nmsg->nm_notify); + + nextcpu = mycpuid + 1; + if (nextcpu < ncpus2) + lwkt_forwardmsg(udp_cport(nextcpu), &netmsg->nm_lmsg); + else + lwkt_replymsg(&netmsg->nm_lmsg, 0); +} + +static void +udp_rtchange(struct inpcb *inp, int err) +{ +#ifdef SMP + /* XXX Nuke this, once UDP inpcbs are CPU localized */ + if (inp->inp_route.ro_rt && inp->inp_route.ro_rt->rt_cpuid == mycpuid) { + rtfree(inp->inp_route.ro_rt); + inp->inp_route.ro_rt = NULL; + /* + * A new route can be allocated the next time + * output is attempted. + */ + } +#else + in_rtchange(inp, err); +#endif +} + void udp_ctlinput(int cmd, struct sockaddr *sa, void *vip) { @@ -623,7 +665,7 @@ udp_ctlinput(int cmd, struct sockaddr *sa, void *vip) if (PRC_IS_REDIRECT(cmd)) { ip = NULL; - notify = in_rtchange; + notify = udp_rtchange; } else if (cmd == PRC_HOSTDEAD) ip = NULL; else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0) @@ -636,9 +678,26 @@ udp_ctlinput(int cmd, struct sockaddr *sa, void *vip) if (inp != NULL && inp->inp_socket != NULL) (*notify)(inp, inetctlerrmap[cmd]); crit_exit(); - } else + } else if (PRC_IS_REDIRECT(cmd)) { + struct netmsg_udp_notify nmsg; + + KKASSERT(&curthread->td_msgport == cpu_portfn(0)); + netmsg_init(&nmsg.nm_nmsg, &curthread->td_msgport, 0, + udp_notifyall_oncpu); + nmsg.nm_faddr = faddr; + nmsg.nm_arg = inetctlerrmap[cmd]; + nmsg.nm_notify = notify; + + lwkt_domsg(udp_cport(0), &nmsg.nm_nmsg.nm_lmsg, 0); + } else { + /* + * XXX We should forward msg upon PRC_HOSTHEAD and ip == NULL, + * once UDP inpcbs are CPU localized + */ + KKASSERT(&curthread->td_msgport == udp_cport(0)); in_pcbnotifyall(&udbinfo.pcblisthead, faddr, inetctlerrmap[cmd], notify); + } } SYSCTL_PROC(_net_inet_udp, UDPCTL_PCBLIST, pcblist, CTLFLAG_RD, &udbinfo, 0, diff --git a/sys/netinet/udp_var.h b/sys/netinet/udp_var.h index 6941f8f474..8d8b5fad66 100644 --- a/sys/netinet/udp_var.h +++ b/sys/netinet/udp_var.h @@ -65,7 +65,7 @@ * * @(#)udp_var.h 8.1 (Berkeley) 6/10/93 * $FreeBSD: src/sys/netinet/udp_var.h,v 1.22.2.1 2001/02/18 07:12:25 luigi Exp $ - * $DragonFly: src/sys/netinet/udp_var.h,v 1.18 2008/10/27 02:56:30 sephe Exp $ + * $DragonFly: src/sys/netinet/udp_var.h,v 1.19 2008/11/11 10:46:58 sephe Exp $ */ #ifndef _NETINET_UDP_VAR_H_ @@ -156,6 +156,7 @@ int udp_shutdown (struct socket *so); struct lwkt_port *udp_soport (struct socket *, struct sockaddr *, struct mbuf **, int); struct lwkt_port *udp_ctlport (int, struct sockaddr *, void *); +struct lwkt_port *udp_cport (int); #endif