xref: /dragonfly/sys/netinet/ip_demux.c (revision 28c7b939)
1 /*
2  * Copyright (c) 2003 Jeffrey Hsu
3  * All rights reserved.
4  *
5  * $DragonFly: src/sys/netinet/ip_demux.c,v 1.3 2003/11/20 06:05:31 dillon Exp $
6  */
7 
8 #include "opt_inet.h"
9 
10 #include <sys/param.h>
11 #include <sys/systm.h>
12 #include <sys/kernel.h>
13 #include <sys/socket.h>
14 #include <sys/socketvar.h>
15 #include <sys/thread.h>
16 #include <sys/sysctl.h>
17 
18 #include <net/if.h>
19 #include <net/netisr.h>
20 
21 #include <netinet/in_systm.h>
22 #include <netinet/in.h>
23 #include <netinet/in_var.h>
24 #include <netinet/in_pcb.h>
25 #include <netinet/ip.h>
26 #include <netinet/ip_var.h>
27 #include <netinet/tcp.h>
28 #include <netinet/tcpip.h>
29 #include <netinet/tcp_var.h>
30 #include <netinet/udp.h>
31 #include <netinet/udp_var.h>
32 
33 extern struct thread netisr_cpu[];
34 
35 static struct thread tcp_thread[MAXCPU];
36 static struct thread udp_thread[MAXCPU];
37 
38 /*
39  * XXX when we remove the MP lock changes to this must be master-synchronized
40  */
41 static int      ip_mthread_enable = 0;
42 SYSCTL_INT(_net_inet_ip, OID_AUTO, mthread_enable, CTLFLAG_RW,
43     &ip_mthread_enable, 0, "");
44 
45 static int
46 INP_MPORT_HASH(in_addr_t src, in_addr_t dst, int sport, int dport)
47 {
48 	int hv;
49 
50 	hv = (int)ntohl(src) ^ (int)ntohl(dst) ^
51 		(int)ntohs(sport) ^ (int)ntohs(dport);
52 	return((hv & 0xFFFF) % ncpus);
53 }
54 
55 lwkt_port_t
56 ip_mport(struct mbuf *m)
57 {
58 	struct ip *ip = mtod(m, struct ip *);
59 	int hlen;
60 	struct tcphdr *th;
61 	struct udphdr *uh;
62 	lwkt_port_t port;
63 
64 	if (ip_mthread_enable == 0)
65 		return (&netisr_cpu[0].td_msgport);
66 
67 	if (m->m_len < sizeof(struct ip) &&
68 	    (m = m_pullup(m, sizeof(struct ip))) == NULL) {
69 		ipstat.ips_toosmall++;
70 		return (NULL);
71 	}
72 
73 	/*
74 	 * XXX generic packet handling defrag on CPU 0 for now.
75 	 */
76 	if (ntohs(ip->ip_off) & (IP_MF | IP_OFFMASK))
77 		return (&netisr_cpu[0].td_msgport);
78 
79 	hlen = ip->ip_hl << 2;
80 
81 	switch (ip->ip_p) {
82 	case IPPROTO_TCP:
83 		if (m->m_len < sizeof(struct tcpiphdr) &&
84 		    (m = m_pullup(m, sizeof(struct tcpiphdr))) == NULL) {
85 			tcpstat.tcps_rcvshort++;
86 			return (NULL);
87 		}
88 
89 		th = (struct tcphdr *)((caddr_t)ip + hlen);
90 		port = &tcp_thread[INP_MPORT_HASH(ip->ip_src.s_addr,
91 		    ip->ip_dst.s_addr, th->th_sport, th->th_dport)].td_msgport;
92 		break;
93 	case IPPROTO_UDP:
94 		if (m->m_len < hlen + sizeof(struct udphdr) &&
95 		    (m = m_pullup(m, hlen + sizeof(struct udphdr))) == NULL) {
96 			udpstat.udps_hdrops++;
97 			return (NULL);
98 		}
99 
100 		uh = (struct udphdr *)((caddr_t)ip + hlen);
101 		port = &udp_thread[INP_MPORT_HASH(ip->ip_src.s_addr,
102 		    ip->ip_dst.s_addr, uh->uh_sport, uh->uh_dport)].td_msgport;
103 		break;
104 	default:
105 		port = &netisr_cpu[0].td_msgport;
106 		break;
107 	}
108 	KKASSERT(port->mp_putport != NULL);
109 
110 	return (port);
111 }
112 
113 lwkt_port_t
114 tcp_soport(struct socket *so)
115 {
116 	struct inpcb *inp = sotoinpcb(so);
117 
118 	return (&tcp_thread[INP_MPORT_HASH(inp->inp_laddr.s_addr,
119 	    inp->inp_faddr.s_addr, inp->inp_lport, inp->inp_fport)].td_msgport);
120 }
121 
122 lwkt_port_t
123 udp_soport(struct socket *so)
124 {
125 	struct inpcb *inp = sotoinpcb(so);
126 
127 	return (&udp_thread[INP_MPORT_HASH(inp->inp_laddr.s_addr,
128 	    inp->inp_faddr.s_addr, inp->inp_lport, inp->inp_fport)].td_msgport);
129 }
130 
131 void
132 tcp_thread_init(void)
133 {
134 	int cpu;
135 
136 	for (cpu = 0; cpu < ncpus; cpu++) {
137 		lwkt_create(netmsg_service_loop, NULL, NULL,
138 			&tcp_thread[cpu], 0, cpu, "tcp_thread %d", cpu);
139 	}
140 }
141 
142 void
143 udp_thread_init(void)
144 {
145 	int cpu;
146 
147 	for (cpu = 0; cpu < ncpus; cpu++) {
148 		lwkt_create(netmsg_service_loop, NULL, NULL,
149 			&udp_thread[cpu], 0, cpu, "udp_thread %d", cpu);
150 	}
151 }
152