ip_demux: Wrap INP_MPORT_HASH_{TCP,UDP}() around INP_MPORT_HASH()
[dragonfly.git] / sys / netinet / ip_demux.c
1 /*
2  * Copyright (c) 2003, 2004 Jeffrey M. Hsu.  All rights reserved.
3  * Copyright (c) 2003, 2004 The DragonFly Project.  All rights reserved.
4  *
5  * This code is derived from software contributed to The DragonFly Project
6  * by Jeffrey M. Hsu.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of The DragonFly Project nor the names of its
17  *    contributors may be used to endorse or promote products derived
18  *    from this software without specific, prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
24  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
30  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * $DragonFly: src/sys/netinet/ip_demux.c,v 1.45 2008/11/11 10:46:58 sephe Exp $
34  */
35
36 #include "opt_inet.h"
37 #include "opt_rss.h"
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/kernel.h>
42 #include <sys/socket.h>
43 #include <sys/socketvar.h>
44 #include <sys/thread.h>
45 #include <sys/sysctl.h>
46 #include <sys/globaldata.h>
47
48 #include <net/if.h>
49 #include <net/netisr.h>
50
51 #include <netinet/in_systm.h>
52 #include <netinet/in.h>
53 #include <netinet/in_var.h>
54 #include <netinet/in_pcb.h>
55 #include <netinet/ip.h>
56 #include <netinet/ip_var.h>
57 #include <netinet/tcp.h>
58 #include <netinet/tcpip.h>
59 #include <netinet/tcp_var.h>
60 #include <netinet/udp.h>
61 #include <netinet/udp_var.h>
62
63 extern struct thread netisr_cpu[];
64 extern int udp_mpsafe_thread;
65
66 static struct thread tcp_thread[MAXCPU];
67 static struct thread udp_thread[MAXCPU];
68
69 static __inline int
70 INP_MPORT_HASH(in_addr_t faddr, in_addr_t laddr,
71                in_port_t fport, in_port_t lport)
72 {
73         /*
74          * Use low order bytes.
75          */
76
77 #if (BYTE_ORDER == LITTLE_ENDIAN)
78         KASSERT(ncpus2 < 256, ("need different hash function"));  /* XXX JH */
79         return (((faddr >> 24) ^ (fport >> 8) ^ (laddr >> 24) ^ (lport >> 8)) &
80                 ncpus2_mask);
81 #else
82         return ((faddr ^ fport ^ laddr ^ lport) & ncpus2_mask);
83 #endif
84 }
85
86 static __inline int
87 INP_MPORT_HASH_UDP(in_addr_t faddr, in_addr_t laddr,
88                    in_port_t fport, in_port_t lport)
89 {
90         return INP_MPORT_HASH(faddr, laddr, fport, lport);
91 }
92
93 static __inline int
94 INP_MPORT_HASH_TCP(in_addr_t faddr, in_addr_t laddr,
95                    in_port_t fport, in_port_t lport)
96 {
97         return INP_MPORT_HASH(faddr, laddr, fport, lport);
98 }
99
100 /*
101  * If the packet is a valid IP datagram, upon returning of this function
102  * following things are promised:
103  *
104  * o  IP header (including any possible IP options) is in one mbuf (m_len).
105  * o  IP header length is not less than the minimum (sizeof(struct ip)).
106  * o  IP total length is not less than IP header length.
107  * o  IP datagram resides completely in the mbuf chain,
108  *    i.e. pkthdr.len >= IP total length.
109  *
110  * If the packet is a UDP datagram,
111  * o  IP header (including any possible IP options) and UDP header are in
112  *    one mbuf (m_len).
113  * o  IP total length is not less than (IP header length + UDP header length).
114  *
115  * If the packet is a TCP segment,
116  * o  IP header (including any possible IP options) and TCP header (including
117  *    any possible TCP options) are in one mbuf (m_len).
118  * o  TCP header length is not less than the minimum (sizeof(struct tcphdr)).
119  * o  IP total length is not less than (IP header length + TCP header length).
120  */
121 boolean_t
122 ip_lengthcheck(struct mbuf **mp)
123 {
124         struct mbuf *m = *mp;
125         struct ip *ip;
126         int iphlen, iplen;
127         struct tcphdr *th;
128         int thoff;                              /* TCP data offset */
129
130         /* The packet must be at least the size of an IP header. */
131         if (m->m_pkthdr.len < sizeof(struct ip)) {
132                 ipstat.ips_tooshort++;
133                 goto fail;
134         }
135
136         /* The fixed IP header must reside completely in the first mbuf. */
137         if (m->m_len < sizeof(struct ip)) {
138                 m = m_pullup(m, sizeof(struct ip));
139                 if (m == NULL) {
140                         ipstat.ips_toosmall++;
141                         goto fail;
142                 }
143         }
144
145         ip = mtod(m, struct ip *);
146
147         /* Bound check the packet's stated IP header length. */
148         iphlen = ip->ip_hl << 2;
149         if (iphlen < sizeof(struct ip)) {       /* minimum header length */
150                 ipstat.ips_badhlen++;
151                 goto fail;
152         }
153
154         /* The full IP header must reside completely in the one mbuf. */
155         if (m->m_len < iphlen) {
156                 m = m_pullup(m, iphlen);
157                 if (m == NULL) {
158                         ipstat.ips_badhlen++;
159                         goto fail;
160                 }
161                 ip = mtod(m, struct ip *);
162         }
163
164         iplen = ntohs(ip->ip_len);
165
166         /*
167          * Check that the amount of data in the buffers is as
168          * at least much as the IP header would have us expect.
169          */
170         if (m->m_pkthdr.len < iplen) {
171                 ipstat.ips_tooshort++;
172                 goto fail;
173         }
174
175         /*
176          * Fragments other than the first fragment don't have much
177          * length information.
178          */
179         if (ntohs(ip->ip_off) & IP_OFFMASK)
180                 goto ipcheckonly;
181
182         /*
183          * The TCP/IP or UDP/IP header must be entirely contained within
184          * the first fragment of a packet.  Packet filters will break if they
185          * aren't.
186          *
187          * Since the packet will be trimmed to ip_len we must also make sure
188          * the potentially trimmed down length is still sufficient to hold
189          * the header(s).
190          */
191         switch (ip->ip_p) {
192         case IPPROTO_TCP:
193                 if (iplen < iphlen + sizeof(struct tcphdr)) {
194                         ++tcpstat.tcps_rcvshort;
195                         goto fail;
196                 }
197                 if (m->m_len < iphlen + sizeof(struct tcphdr)) {
198                         m = m_pullup(m, iphlen + sizeof(struct tcphdr));
199                         if (m == NULL) {
200                                 tcpstat.tcps_rcvshort++;
201                                 goto fail;
202                         }
203                         ip = mtod(m, struct ip *);
204                 }
205                 th = (struct tcphdr *)((caddr_t)ip + iphlen);
206                 thoff = th->th_off << 2;
207                 if (thoff < sizeof(struct tcphdr) ||
208                     thoff + iphlen > ntohs(ip->ip_len)) {
209                         tcpstat.tcps_rcvbadoff++;
210                         goto fail;
211                 }
212                 if (m->m_len < iphlen + thoff) {
213                         m = m_pullup(m, iphlen + thoff);
214                         if (m == NULL) {
215                                 tcpstat.tcps_rcvshort++;
216                                 goto fail;
217                         }
218                 }
219                 break;
220         case IPPROTO_UDP:
221                 if (iplen < iphlen + sizeof(struct udphdr)) {
222                         ++udpstat.udps_hdrops;
223                         goto fail;
224                 }
225                 if (m->m_len < iphlen + sizeof(struct udphdr)) {
226                         m = m_pullup(m, iphlen + sizeof(struct udphdr));
227                         if (m == NULL) {
228                                 udpstat.udps_hdrops++;
229                                 goto fail;
230                         }
231                 }
232                 break;
233         default:
234 ipcheckonly:
235                 if (iplen < iphlen) {
236                         ++ipstat.ips_badlen;
237                         goto fail;
238                 }
239                 break;
240         }
241
242         *mp = m;
243         return TRUE;
244
245 fail:
246         if (m != NULL)
247                 m_freem(m);
248         *mp = NULL;
249         return FALSE;
250 }
251
252 /*
253  * Map a packet to a protocol processing thread and return the thread's port.
254  * If an error occurs, the passed mbuf will be freed, *mptr will be set
255  * to NULL, and NULL will be returned.  If no error occurs, the passed mbuf
256  * may be modified and a port pointer will be returned.
257  */
258 lwkt_port_t
259 ip_mport(struct mbuf **mptr, int dir)
260 {
261         struct ip *ip;
262         int iphlen;
263         struct tcphdr *th;
264         struct udphdr *uh;
265         struct mbuf *m;
266         int thoff;                              /* TCP data offset */
267         lwkt_port_t port;
268         int cpu;
269
270         if (!ip_lengthcheck(mptr))
271                 return (NULL);
272
273         m = *mptr;
274         ip = mtod(m, struct ip *);
275         iphlen = ip->ip_hl << 2;
276
277         /*
278          * XXX generic packet handling defrag on CPU 0 for now.
279          */
280         if (ntohs(ip->ip_off) & (IP_MF | IP_OFFMASK))
281                 return (&netisr_cpu[0].td_msgport);
282
283         switch (ip->ip_p) {
284         case IPPROTO_TCP:
285                 th = (struct tcphdr *)((caddr_t)ip + iphlen);
286                 thoff = th->th_off << 2;
287                 cpu = INP_MPORT_HASH_TCP(ip->ip_src.s_addr, ip->ip_dst.s_addr,
288                     th->th_sport, th->th_dport);
289                 port = &tcp_thread[cpu].td_msgport;
290                 break;
291
292         case IPPROTO_UDP:
293                 uh = (struct udphdr *)((caddr_t)ip + iphlen);
294
295 #ifndef RSS
296                 if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) ||
297                     (dir == IP_MPORT_IN &&
298                      in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif))) {
299                         cpu = 0;
300                 } else
301 #endif
302                 {
303                         cpu = INP_MPORT_HASH_UDP(ip->ip_src.s_addr,
304                             ip->ip_dst.s_addr, uh->uh_sport, uh->uh_dport);
305                 }
306                 port = &udp_thread[cpu].td_msgport;
307                 break;
308
309         default:
310                 port = &netisr_cpu[0].td_msgport;
311                 break;
312         }
313
314         return (port);
315 }
316
317 lwkt_port_t
318 ip_mport_in(struct mbuf **mptr)
319 {
320         return ip_mport(mptr, IP_MPORT_IN);
321 }
322
323 /*
324  * Map a TCP socket to a protocol processing thread.
325  */
326 lwkt_port_t
327 tcp_soport(struct socket *so, struct sockaddr *nam __unused,
328            struct mbuf **dummy __unused, int req)
329 {
330         struct inpcb *inp;
331
332         /* The following processing all take place on Protocol Thread 0. */
333         if (req == PRU_BIND || req == PRU_CONNECT || req == PRU_ATTACH ||
334             req == PRU_LISTEN)
335                 return (&tcp_thread[0].td_msgport);
336
337         inp = so->so_pcb;
338         if (!inp)               /* connection reset by peer */
339                 return (&tcp_thread[0].td_msgport);
340
341         /*
342          * Already bound and connected or listening.  For TCP connections,
343          * the (faddr, fport, laddr, lport) association cannot change now.
344          *
345          * Note: T/TCP code needs some reorganization to fit into
346          * this model.  XXX JH
347          *
348          * Rely on type-stable memory and check in protocol handler
349          * to fix race condition here w/ deallocation of inp.  XXX JH
350          */
351         return (&tcp_thread[INP_MPORT_HASH_TCP(inp->inp_faddr.s_addr,
352             inp->inp_laddr.s_addr, inp->inp_fport, inp->inp_lport)].td_msgport);
353 }
354
355 /*
356  * Used to route icmp messages to the proper protocol thread for ctlinput
357  * operation.
358  */
359 lwkt_port_t
360 tcp_ctlport(int cmd, struct sockaddr *sa, void *vip)
361 {
362         struct ip *ip = vip;
363         struct tcphdr *th;
364         struct in_addr faddr;
365         int cpu;
366
367         faddr = ((struct sockaddr_in *)sa)->sin_addr;
368         if (sa->sa_family != AF_INET || faddr.s_addr == INADDR_ANY)
369                 return(NULL);
370         if (ip == NULL || PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) {
371                 /*
372                  * Message will be forwarded to all TCP protocol threads
373                  * in following way:
374                  *
375                  * netisr0 (the msgport we return here)
376                  *    |
377                  *    |
378                  *    | domsg <----------------------------+
379                  *    |                                    |
380                  *    |                                    | replymsg
381                  *    |                                    |
382                  *    V   forwardmsg         forwardmsg    |
383                  *  tcp0 ------------> tcp1 ------------> tcpN
384                  */
385                 return cpu0_ctlport(cmd, sa, vip);
386         } else {
387                 th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2));
388                 cpu = tcp_addrcpu(faddr.s_addr, th->th_dport,
389                                   ip->ip_src.s_addr, th->th_sport);
390         }
391         return(&tcp_thread[cpu].td_msgport);
392 }
393
394 lwkt_port_t
395 tcp_addrport(in_addr_t faddr, in_port_t fport, in_addr_t laddr, in_port_t lport)
396 {
397         return (&tcp_thread[tcp_addrcpu(faddr, fport,
398                                         laddr, lport)].td_msgport);
399 }
400
401 /*
402  * Map a UDP socket to a protocol processing thread.
403  */
404 lwkt_port_t
405 udp_soport(struct socket *so, struct sockaddr *nam __unused,
406            struct mbuf **dummy __unused, int req)
407 {
408         struct inpcb *inp;
409
410         /*
411          * The following processing all take place on Protocol Thread 0:
412          *   bind()
413          *   attach() has a null socket parameter
414          *   Fast and slow timeouts pass in null socket parameter
415          */
416         if (req == PRU_BIND || so == NULL)
417                 return (&udp_thread[0].td_msgport);
418
419         inp = so->so_pcb;
420
421 #ifndef RSS
422         if (IN_MULTICAST(ntohl(inp->inp_laddr.s_addr)))
423                 return (&udp_thread[0].td_msgport);
424 #endif
425
426         /*
427          * Rely on type-stable memory and check in protocol handler
428          * to fix race condition here w/ deallocation of inp.  XXX JH
429          */
430
431         return (&udp_thread[INP_MPORT_HASH_UDP(inp->inp_faddr.s_addr,
432             inp->inp_laddr.s_addr, inp->inp_fport, inp->inp_lport)].td_msgport);
433 }
434
435 /*
436  * Used to route icmp messages to the proper protocol thread for ctlinput
437  * operation.
438  */
439 lwkt_port_t
440 udp_ctlport(int cmd, struct sockaddr *sa, void *vip)
441 {
442         struct ip *ip = vip;
443         struct udphdr *uh;
444         struct in_addr faddr;
445         int cpu;
446
447         faddr = ((struct sockaddr_in *)sa)->sin_addr;
448         if (sa->sa_family != AF_INET || faddr.s_addr == INADDR_ANY)
449                 return(NULL);
450         if (PRC_IS_REDIRECT(cmd)) {
451                 /*
452                  * See the comment in tcp_ctlport; the only difference
453                  * is that message is forwarded to UDP protocol theads.
454                  */
455                 return cpu0_ctlport(cmd, sa, vip);
456         } else if (ip == NULL || cmd == PRC_HOSTDEAD) {
457                 /*
458                  * XXX
459                  * Once UDP inpcbs are CPU localized, we should do
460                  * the same forwarding as PRC_IS_REDIRECT(cmd)
461                  */
462                 cpu = 0;
463         } else {
464                 uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
465
466                 cpu = INP_MPORT_HASH_UDP(faddr.s_addr, ip->ip_src.s_addr,
467                                          uh->uh_dport, uh->uh_sport);
468         }
469         return (&udp_thread[cpu].td_msgport);
470 }
471
472 /*
473  * Map a network address to a processor.
474  */
475 int
476 tcp_addrcpu(in_addr_t faddr, in_port_t fport, in_addr_t laddr, in_port_t lport)
477 {
478         return (INP_MPORT_HASH_TCP(faddr, laddr, fport, lport));
479 }
480
481 int
482 udp_addrcpu(in_addr_t faddr, in_port_t fport, in_addr_t laddr, in_port_t lport)
483 {
484 #ifndef RSS
485         if (IN_MULTICAST(ntohl(laddr)))
486                 return (0);
487         else
488 #endif
489                 return (INP_MPORT_HASH_UDP(faddr, laddr, fport, lport));
490 }
491
492 /*
493  * Return LWKT port for cpu.
494  */
495 lwkt_port_t
496 tcp_cport(int cpu)
497 {
498         return (&tcp_thread[cpu].td_msgport);
499 }
500
501 lwkt_port_t
502 udp_cport(int cpu)
503 {
504         return (&udp_thread[cpu].td_msgport);
505 }
506
507 void
508 tcp_thread_init(void)
509 {
510         int cpu;
511
512         for (cpu = 0; cpu < ncpus2; cpu++) {
513                 lwkt_create(tcpmsg_service_loop, NULL, NULL,
514                             &tcp_thread[cpu], TDF_NETWORK | TDF_MPSAFE, cpu,
515                             "tcp_thread %d", cpu);
516                 netmsg_service_port_init(&tcp_thread[cpu].td_msgport);
517         }
518 }
519
520 void
521 udp_thread_init(void)
522 {
523         int cpu;
524
525         for (cpu = 0; cpu < ncpus2; cpu++) {
526                 lwkt_create(netmsg_service_loop, &udp_mpsafe_thread, NULL,
527                             &udp_thread[cpu], TDF_NETWORK | TDF_MPSAFE, cpu,
528                             "udp_thread %d", cpu);
529                 netmsg_service_port_init(&udp_thread[cpu].td_msgport);
530         }
531 }