2 * Copyright (c) 2007 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Sepherosa Ziehau <sepherosa@gmail.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
15 * the documentation and/or other materials provided with the
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 #include <sys/param.h>
36 #include <sys/kernel.h>
38 #include <sys/msgport.h>
39 #include <sys/socketvar.h>
40 #include <sys/sysctl.h>
43 #include <net/if_var.h>
44 #include <net/route.h>
45 #include <net/ethernet.h>
46 #include <net/netisr.h>
47 #include <net/netmsg2.h>
49 #include <netinet/in.h>
50 #include <netinet/in_var.h>
51 #include <netinet/ip.h>
52 #include <netinet/ip_var.h>
54 #include <net/dummynet/ip_dummynet.h>
56 static void ip_dn_ether_output(netmsg_t);
57 static void ip_dn_ether_demux(netmsg_t);
58 static void ip_dn_ip_input(netmsg_t);
59 static void ip_dn_ip_output(netmsg_t);
61 static void ip_dn_sockopt_dispatch(netmsg_t);
62 static void ip_dn_freepkt_dispatch(netmsg_t);
63 static void ip_dn_dispatch(netmsg_t);
65 static void ip_dn_freepkt(struct dn_pkt *);
67 static int ip_dn_sockopt_flush(struct sockopt *);
68 static int ip_dn_sockopt_get(struct sockopt *);
69 static int ip_dn_sockopt_config(struct sockopt *);
71 ip_dn_io_t *ip_dn_io_ptr;
74 TUNABLE_INT("net.inet.ip.dummynet.cpu", &ip_dn_cpu);
76 SYSCTL_NODE(_net_inet_ip, OID_AUTO, dummynet, CTLFLAG_RW, 0, "Dummynet");
77 SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, cpu, CTLFLAG_RD,
78 &ip_dn_cpu, 0, "CPU to run dummynet");
81 ip_dn_queue(struct mbuf *m)
83 struct netmsg_packet *nmp;
87 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
88 ("mbuf is not tagged for dummynet!"));
90 nmp = &m->m_hdr.mh_netmsg;
91 netmsg_init(&nmp->base, NULL, &netisr_apanic_rport,
95 port = netisr_portfn(ip_dn_cpu);
96 lwkt_sendmsg(port, &nmp->base.lmsg);
100 ip_dn_packet_free(struct dn_pkt *pkt)
102 struct netmsg_packet *nmp;
103 struct mbuf *m = pkt->dn_m;
106 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
107 ("mbuf is not tagged for dummynet!"));
109 nmp = &m->m_hdr.mh_netmsg;
110 netmsg_init(&nmp->base, NULL, &netisr_apanic_rport,
111 0, ip_dn_freepkt_dispatch);
114 lwkt_sendmsg(pkt->msgport, &nmp->base.lmsg);
118 ip_dn_packet_redispatch(struct dn_pkt *pkt)
120 static const netisr_fn_t dispatches[DN_TO_MAX] = {
121 [DN_TO_IP_OUT] = ip_dn_ip_output,
122 [DN_TO_IP_IN] = ip_dn_ip_input,
123 [DN_TO_ETH_DEMUX] = ip_dn_ether_demux,
124 [DN_TO_ETH_OUT] = ip_dn_ether_output
127 struct netmsg_packet *nmp;
129 netisr_fn_t dispatch;
132 dir = (pkt->dn_flags & DN_FLAGS_DIR_MASK);
133 KASSERT(dir < DN_TO_MAX,
134 ("unknown dummynet redispatch dir %d", dir));
136 dispatch = dispatches[dir];
137 KASSERT(dispatch != NULL,
138 ("unsupported dummynet redispatch dir %d", dir));
142 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
143 ("mbuf is not tagged for dummynet!"));
145 nmp = &m->m_hdr.mh_netmsg;
146 netmsg_init(&nmp->base, NULL, &netisr_apanic_rport, 0, dispatch);
149 lwkt_sendmsg(pkt->msgport, &nmp->base.lmsg);
153 ip_dn_sockopt(struct sockopt *sopt)
157 /* Disallow sets in really-really secure mode. */
158 if (sopt->sopt_dir == SOPT_SET) {
159 if (securelevel >= 3)
163 switch (sopt->sopt_name) {
164 case IP_DUMMYNET_GET:
165 error = ip_dn_sockopt_get(sopt);
168 case IP_DUMMYNET_FLUSH:
169 error = ip_dn_sockopt_flush(sopt);
172 case IP_DUMMYNET_DEL:
173 case IP_DUMMYNET_CONFIGURE:
174 error = ip_dn_sockopt_config(sopt);
178 kprintf("%s -- unknown option %d\n", __func__, sopt->sopt_name);
186 ip_dn_freepkt(struct dn_pkt *pkt)
188 struct rtentry *rt = pkt->ro.ro_rt;
190 /* Unreference route entry */
192 if (rt->rt_refcnt <= 0) { /* XXX assert? */
193 kprintf("-- warning, refcnt now %ld, decreasing\n",
199 /* Unreference packet private data */
200 if (pkt->dn_unref_priv)
201 pkt->dn_unref_priv(pkt->dn_priv);
203 /* Free the parent mbuf, this will free 'pkt' as well */
208 ip_dn_freepkt_dispatch(netmsg_t nmsg)
210 struct netmsg_packet *nmp;
218 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
219 ("mbuf is not tagged for dummynet!"));
221 mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
222 KKASSERT(mtag != NULL);
224 pkt = m_tag_data(mtag);
225 KASSERT(pkt->cpuid == mycpuid,
226 ("%s: dummynet packet was delivered to wrong cpu! "
227 "target cpuid %d, mycpuid %d", __func__,
228 pkt->cpuid, mycpuid));
234 ip_dn_dispatch(netmsg_t nmsg)
236 struct netmsg_packet *nmp;
241 KASSERT(ip_dn_cpu == mycpuid,
242 ("%s: dummynet packet was delivered to wrong cpu! "
243 "dummynet cpuid %d, mycpuid %d", __func__,
244 ip_dn_cpu, mycpuid));
249 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
250 ("mbuf is not tagged for dummynet!"));
252 if (DUMMYNET_LOADED) {
253 if (ip_dn_io_ptr(m) == 0)
258 * ip_dn_io_ptr() failed or dummynet(4) is not loaded
260 mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
261 KKASSERT(mtag != NULL);
263 pkt = m_tag_data(mtag);
264 ip_dn_packet_free(pkt);
268 ip_dn_ip_output(netmsg_t nmsg)
270 struct netmsg_packet *nmp;
275 ip_dn_unref_priv_t unref_priv;
281 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
282 ("mbuf is not tagged for dummynet!"));
284 mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
285 KKASSERT(mtag != NULL);
287 pkt = m_tag_data(mtag);
288 KASSERT(pkt->cpuid == mycpuid,
289 ("%s: dummynet packet was delivered to wrong cpu! "
290 "target cpuid %d, mycpuid %d", __func__,
291 pkt->cpuid, mycpuid));
292 KASSERT((pkt->dn_flags & DN_FLAGS_DIR_MASK) == DN_TO_IP_OUT,
293 ("wrong direction %d, should be %d",
294 (pkt->dn_flags & DN_FLAGS_DIR_MASK), DN_TO_IP_OUT));
297 unref_priv = pkt->dn_unref_priv;
300 if (rt != NULL && !(rt->rt_flags & RTF_UP)) {
302 * Recorded rtentry is gone, when the packet
309 ip_output(pkt->dn_m, NULL, NULL, pkt->flags, NULL, NULL);
310 /* 'rt' will be freed in ip_output */
317 ip_dn_ip_input(netmsg_t nmsg)
319 struct netmsg_packet *nmp;
323 ip_dn_unref_priv_t unref_priv;
329 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
330 ("mbuf is not tagged for dummynet!"));
332 mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
333 KKASSERT(mtag != NULL);
335 pkt = m_tag_data(mtag);
336 KASSERT(pkt->cpuid == mycpuid,
337 ("%s: dummynet packet was delivered to wrong cpu! "
338 "target cpuid %d, mycpuid %d", __func__,
339 pkt->cpuid, mycpuid));
340 KASSERT(pkt->ro.ro_rt == NULL,
341 ("route entry is not NULL for ip_input"));
342 KASSERT((pkt->dn_flags & DN_FLAGS_DIR_MASK) == DN_TO_IP_IN,
343 ("wrong direction %d, should be %d",
344 (pkt->dn_flags & DN_FLAGS_DIR_MASK), DN_TO_IP_IN));
347 unref_priv = pkt->dn_unref_priv;
356 ip_dn_ether_demux(netmsg_t nmsg)
358 struct netmsg_packet *nmp;
362 ip_dn_unref_priv_t unref_priv;
368 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
369 ("mbuf is not tagged for dummynet!"));
371 mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
372 KKASSERT(mtag != NULL);
374 pkt = m_tag_data(mtag);
375 KASSERT(pkt->cpuid == mycpuid,
376 ("%s: dummynet packet was delivered to wrong cpu! "
377 "target cpuid %d, mycpuid %d", __func__,
378 pkt->cpuid, mycpuid));
379 KASSERT(pkt->ro.ro_rt == NULL,
380 ("route entry is not NULL for ether_demux"));
381 KASSERT((pkt->dn_flags & DN_FLAGS_DIR_MASK) == DN_TO_ETH_DEMUX,
382 ("wrong direction %d, should be %d",
383 (pkt->dn_flags & DN_FLAGS_DIR_MASK), DN_TO_ETH_DEMUX));
386 unref_priv = pkt->dn_unref_priv;
389 * Make sure that ether header is contiguous
391 if (m->m_len < ETHER_HDR_LEN &&
392 (m = m_pullup(m, ETHER_HDR_LEN)) == NULL) {
393 kprintf("%s: pullup fail, dropping pkt\n", __func__);
396 ether_demux_oncpu(m->m_pkthdr.rcvif, m);
403 ip_dn_ether_output(netmsg_t nmsg)
405 struct netmsg_packet *nmp;
409 ip_dn_unref_priv_t unref_priv;
415 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
416 ("mbuf is not tagged for dummynet!"));
418 mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
419 KKASSERT(mtag != NULL);
421 pkt = m_tag_data(mtag);
422 KASSERT(pkt->cpuid == mycpuid,
423 ("%s: dummynet packet was delivered to wrong cpu! "
424 "target cpuid %d, mycpuid %d", __func__,
425 pkt->cpuid, mycpuid));
426 KASSERT(pkt->ro.ro_rt == NULL,
427 ("route entry is not NULL for ether_output_frame"));
428 KASSERT((pkt->dn_flags & DN_FLAGS_DIR_MASK) == DN_TO_ETH_OUT,
429 ("wrong direction %d, should be %d",
430 (pkt->dn_flags & DN_FLAGS_DIR_MASK), DN_TO_ETH_OUT));
433 unref_priv = pkt->dn_unref_priv;
435 ether_output_frame(pkt->ifp, m);
442 ip_dn_sockopt_dispatch(netmsg_t nmsg)
444 lwkt_msg *msg = &nmsg->lmsg;
445 struct dn_sopt *dn_sopt = msg->u.ms_resultp;
448 KASSERT(ip_dn_cpu == mycpuid,
449 ("%s: dummynet sockopt is done on wrong cpu! "
450 "dummynet cpuid %d, mycpuid %d", __func__,
451 ip_dn_cpu, mycpuid));
454 error = ip_dn_ctl_ptr(dn_sopt);
457 lwkt_replymsg(msg, error);
461 ip_dn_sockopt_flush(struct sockopt *sopt)
463 struct dn_sopt dn_sopt;
464 struct netmsg_base smsg;
466 bzero(&dn_sopt, sizeof(dn_sopt));
467 dn_sopt.dn_sopt_name = sopt->sopt_name;
469 netmsg_init(&smsg, NULL, &curthread->td_msgport,
470 0, ip_dn_sockopt_dispatch);
471 smsg.lmsg.u.ms_resultp = &dn_sopt;
472 lwkt_domsg(netisr_portfn(ip_dn_cpu), &smsg.lmsg, 0);
474 return smsg.lmsg.ms_error;
478 ip_dn_sockopt_get(struct sockopt *sopt)
480 struct dn_sopt dn_sopt;
481 struct netmsg_base smsg;
484 bzero(&dn_sopt, sizeof(dn_sopt));
485 dn_sopt.dn_sopt_name = sopt->sopt_name;
487 netmsg_init(&smsg, NULL, &curthread->td_msgport,
488 0, ip_dn_sockopt_dispatch);
489 smsg.lmsg.u.ms_resultp = &dn_sopt;
490 lwkt_domsg(netisr_portfn(ip_dn_cpu), &smsg.lmsg, 0);
492 error = smsg.lmsg.ms_error;
494 KKASSERT(dn_sopt.dn_sopt_arg == NULL);
495 KKASSERT(dn_sopt.dn_sopt_arglen == 0);
499 soopt_from_kbuf(sopt, dn_sopt.dn_sopt_arg, dn_sopt.dn_sopt_arglen);
500 kfree(dn_sopt.dn_sopt_arg, M_TEMP);
505 ip_dn_sockopt_config(struct sockopt *sopt)
507 struct dn_ioc_pipe tmp_ioc_pipe;
508 struct dn_sopt dn_sopt;
509 struct netmsg_base smsg;
512 error = soopt_to_kbuf(sopt, &tmp_ioc_pipe, sizeof tmp_ioc_pipe,
513 sizeof tmp_ioc_pipe);
517 bzero(&dn_sopt, sizeof(dn_sopt));
518 dn_sopt.dn_sopt_name = sopt->sopt_name;
519 dn_sopt.dn_sopt_arg = &tmp_ioc_pipe;
520 dn_sopt.dn_sopt_arglen = sizeof(tmp_ioc_pipe);
522 netmsg_init(&smsg, NULL, &curthread->td_msgport,
523 0, ip_dn_sockopt_dispatch);
524 smsg.lmsg.u.ms_resultp = &dn_sopt;
525 lwkt_domsg(netisr_portfn(ip_dn_cpu), &smsg.lmsg, 0);
527 return smsg.lmsg.ms_error;