1 /* 2 * Copyright (c) 2003 Jeffrey Hsu 3 * All rights reserved. 4 * 5 * $DragonFly: src/sys/netinet/ip_demux.c,v 1.22 2004/04/24 06:55:57 hsu 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 #include <sys/globaldata.h> 18 19 #include <net/if.h> 20 #include <net/netisr.h> 21 22 #include <netinet/in_systm.h> 23 #include <netinet/in.h> 24 #include <netinet/in_var.h> 25 #include <netinet/in_pcb.h> 26 #include <netinet/ip.h> 27 #include <netinet/ip_var.h> 28 #include <netinet/tcp.h> 29 #include <netinet/tcpip.h> 30 #include <netinet/tcp_var.h> 31 #include <netinet/udp.h> 32 #include <netinet/udp_var.h> 33 34 extern struct thread netisr_cpu[]; 35 36 static struct thread tcp_thread[MAXCPU]; 37 static struct thread udp_thread[MAXCPU]; 38 39 static __inline int 40 INP_MPORT_HASH(in_addr_t faddr, in_addr_t laddr, 41 in_port_t fport, in_port_t lport) 42 { 43 /* 44 * Use low order bytes. 45 */ 46 47 #if (BYTE_ORDER == LITTLE_ENDIAN) 48 KASSERT(ncpus2 < 256, ("need different hash function")); /* XXX JH */ 49 return (((faddr >> 24) ^ (fport >> 8) ^ (laddr >> 24) ^ (lport >> 8)) & 50 ncpus2_mask); 51 #else 52 return ((faddr ^ fport ^ laddr ^ lport) & ncpus2_mask); 53 #endif 54 } 55 56 /* 57 * Map a packet to a protocol processing thread. 58 */ 59 lwkt_port_t 60 ip_mport(struct mbuf *m) 61 { 62 struct ip *ip; 63 int iphlen; 64 struct tcphdr *th; 65 struct udphdr *uh; 66 int thoff; /* TCP data offset */ 67 lwkt_port_t port; 68 int cpu; 69 70 if (m->m_pkthdr.len < sizeof(struct ip)) { 71 ipstat.ips_tooshort++; 72 return (NULL); 73 } 74 75 if (m->m_len < sizeof(struct ip) && 76 (m = m_pullup(m, sizeof(struct ip))) == NULL) { 77 ipstat.ips_toosmall++; 78 return (NULL); 79 } 80 81 ip = mtod(m, struct ip *); 82 83 /* 84 * XXX generic packet handling defrag on CPU 0 for now. 85 */ 86 if (ntohs(ip->ip_off) & (IP_MF | IP_OFFMASK)) 87 return (&netisr_cpu[0].td_msgport); 88 89 iphlen = ip->ip_hl << 2; 90 if (iphlen < sizeof(struct ip)) { /* minimum header length */ 91 ipstat.ips_badhlen++; 92 return (NULL); 93 } 94 95 switch (ip->ip_p) { 96 case IPPROTO_TCP: 97 if (m->m_len < iphlen + sizeof(struct tcphdr) && 98 (m = m_pullup(m, iphlen + sizeof(struct tcphdr))) == NULL) { 99 tcpstat.tcps_rcvshort++; 100 return (NULL); 101 } 102 th = (struct tcphdr *)((caddr_t)ip + iphlen); 103 thoff = th->th_off << 2; 104 if (thoff < sizeof(struct tcphdr) || 105 thoff > ntohs(ip->ip_len)) { 106 tcpstat.tcps_rcvbadoff++; 107 return (NULL); 108 } 109 if (m->m_len < iphlen + thoff) { 110 m = m_pullup(m, iphlen + thoff); 111 if (m == NULL) { 112 tcpstat.tcps_rcvshort++; 113 return (NULL); 114 } 115 ip = mtod(m, struct ip *); 116 th = (struct tcphdr *)((caddr_t)ip + iphlen); 117 } 118 119 cpu = INP_MPORT_HASH(ip->ip_src.s_addr, ip->ip_dst.s_addr, 120 th->th_sport, th->th_dport); 121 port = &tcp_thread[cpu].td_msgport; 122 break; 123 case IPPROTO_UDP: 124 if (m->m_len < iphlen + sizeof(struct udphdr)) { 125 m = m_pullup(m, iphlen + sizeof(struct udphdr)); 126 if (m == NULL) { 127 udpstat.udps_hdrops++; 128 return (NULL); 129 } 130 ip = mtod(m, struct ip *); 131 } 132 uh = (struct udphdr *)((caddr_t)ip + iphlen); 133 134 if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) || 135 in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) { 136 cpu = 0; 137 } else { 138 cpu = INP_MPORT_HASH(ip->ip_src.s_addr, 139 ip->ip_dst.s_addr, uh->uh_sport, uh->uh_dport); 140 } 141 port = &udp_thread[cpu].td_msgport; 142 break; 143 default: 144 if (m->m_len < iphlen && (m = m_pullup(m, iphlen)) == NULL) { 145 ipstat.ips_badhlen++; 146 return (NULL); 147 } 148 port = &netisr_cpu[0].td_msgport; 149 break; 150 } 151 KKASSERT(port->mp_putport != NULL); 152 153 return (port); 154 } 155 156 /* 157 * Map a TCP socket to a protocol processing thread. 158 */ 159 lwkt_port_t 160 tcp_soport(struct socket *so, struct sockaddr *nam, int req) 161 { 162 struct inpcb *inp; 163 164 /* The following processing all take place on Protocol Thread 0. */ 165 if (req == PRU_BIND || req == PRU_CONNECT || req == PRU_ATTACH || 166 req == PRU_LISTEN) 167 return (&tcp_thread[0].td_msgport); 168 169 inp = sotoinpcb(so); 170 if (!inp) /* connection reset by peer */ 171 return (&tcp_thread[0].td_msgport); 172 173 /* 174 * Already bound and connected or listening. For TCP connections, 175 * the (faddr, fport, laddr, lport) association cannot change now. 176 * 177 * Note: T/TCP code needs some reorganization to fit into 178 * this model. XXX JH 179 * 180 * Rely on type-stable memory and check in protocol handler 181 * to fix race condition here w/ deallocation of inp. XXX JH 182 */ 183 return (&tcp_thread[INP_MPORT_HASH(inp->inp_faddr.s_addr, 184 inp->inp_laddr.s_addr, inp->inp_fport, inp->inp_lport)].td_msgport); 185 } 186 187 lwkt_port_t 188 tcp_addrport(in_addr_t faddr, in_port_t fport, in_addr_t laddr, in_port_t lport) 189 { 190 return (&tcp_thread[tcp_addrcpu(faddr, fport, 191 laddr, lport)].td_msgport); 192 } 193 194 /* 195 * Map a UDP socket to a protocol processing thread. 196 */ 197 lwkt_port_t 198 udp_soport(struct socket *so, struct sockaddr *nam, int req) 199 { 200 struct inpcb *inp; 201 202 /* 203 * The following processing all take place on Protocol Thread 0: 204 * only bind() and connect() have a non-null nam parameter 205 * attach() has a null socket parameter 206 * Fast and slow timeouts pass in two NULLs 207 */ 208 if (nam != NULL || so == NULL) 209 return (&udp_thread[0].td_msgport); 210 211 inp = sotoinpcb(so); 212 213 if (IN_MULTICAST(ntohl(inp->inp_laddr.s_addr))) 214 return (&udp_thread[0].td_msgport); 215 216 /* 217 * Rely on type-stable memory and check in protocol handler 218 * to fix race condition here w/ deallocation of inp. XXX JH 219 */ 220 221 return (&udp_thread[INP_MPORT_HASH(inp->inp_faddr.s_addr, 222 inp->inp_laddr.s_addr, inp->inp_fport, inp->inp_lport)].td_msgport); 223 } 224 225 /* 226 * Map a network address to a processor. 227 */ 228 int 229 tcp_addrcpu(in_addr_t faddr, in_port_t fport, in_addr_t laddr, in_port_t lport) 230 { 231 return (INP_MPORT_HASH(faddr, laddr, fport, lport)); 232 } 233 234 int 235 udp_addrcpu(in_addr_t faddr, in_port_t fport, in_addr_t laddr, in_port_t lport) 236 { 237 if (IN_MULTICAST(ntohl(laddr))) 238 return (0); 239 else 240 return (INP_MPORT_HASH(faddr, laddr, fport, lport)); 241 } 242 243 /* 244 * Return LWKT port for cpu. 245 */ 246 lwkt_port_t 247 tcp_cport(int cpu) 248 { 249 return (&tcp_thread[cpu].td_msgport); 250 } 251 252 void 253 tcp_thread_init(void) 254 { 255 int cpu; 256 257 for (cpu = 0; cpu < ncpus2; cpu++) { 258 lwkt_create(netmsg_service_loop, NULL, NULL, 259 &tcp_thread[cpu], 0, cpu, "tcp_thread %d", cpu); 260 tcp_thread[cpu].td_msgport.mp_putport = netmsg_put_port; 261 } 262 } 263 264 void 265 udp_thread_init(void) 266 { 267 int cpu; 268 269 for (cpu = 0; cpu < ncpus2; cpu++) { 270 lwkt_create(netmsg_service_loop, NULL, NULL, 271 &udp_thread[cpu], 0, cpu, "udp_thread %d", cpu); 272 udp_thread[cpu].td_msgport.mp_putport = netmsg_put_port; 273 } 274 } 275