Resurrect code mistakenly #ifdef'd out before.
[dragonfly.git] / sys / net / dummynet / ip_dummynet_glue.c
blobb34b33f124a84615a5b4ff0292306d09c738f5a9
1 /*
2 * Copyright (c) 2007 The DragonFly Project. All rights reserved.
3 *
4 * This code is derived from software contributed to The DragonFly Project
5 * by Sepherosa Ziehau <sepherosa@gmail.com>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * 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
15 * the documentation and/or other materials provided with the
16 * distribution.
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
32 * SUCH DAMAGE.
34 * $DragonFly: src/sys/net/dummynet/ip_dummynet_glue.c,v 1.4 2007/11/18 13:00:28 sephe Exp $
37 #include <sys/param.h>
38 #include <sys/kernel.h>
39 #include <sys/mbuf.h>
40 #include <sys/msgport.h>
41 #include <sys/socketvar.h>
42 #include <sys/sysctl.h>
44 #include <net/if.h>
45 #include <net/if_var.h>
46 #include <net/route.h>
47 #include <net/ethernet.h>
48 #include <net/netisr.h>
49 #include <net/netmsg2.h>
51 #include <netinet/in.h>
52 #include <netinet/in_var.h>
53 #include <netinet/ip.h>
54 #include <netinet/ip_var.h>
56 #include <net/dummynet/ip_dummynet.h>
58 static void ip_dn_ether_output(struct netmsg *);
59 static void ip_dn_ether_demux(struct netmsg *);
60 static void ip_dn_ip_input(struct netmsg *);
61 static void ip_dn_ip_output(struct netmsg *);
63 static void ip_dn_sockopt_dispatch(struct netmsg *);
64 static void ip_dn_freepkt_dispatch(struct netmsg *);
65 static void ip_dn_dispatch(struct netmsg *);
67 static void ip_dn_freepkt(struct dn_pkt *);
69 static int ip_dn_sockopt_flush(struct sockopt *);
70 static int ip_dn_sockopt_get(struct sockopt *);
71 static int ip_dn_sockopt_config(struct sockopt *);
73 ip_dn_io_t *ip_dn_io_ptr;
74 int ip_dn_cpu = 0;
76 TUNABLE_INT("net.inet.ip.dummynet.cpu", &ip_dn_cpu);
78 SYSCTL_NODE(_net_inet_ip, OID_AUTO, dummynet, CTLFLAG_RW, 0, "Dummynet");
79 SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, cpu, CTLFLAG_RD,
80 &ip_dn_cpu, 0, "CPU to run dummynet");
82 void
83 ip_dn_queue(struct mbuf *m)
85 struct netmsg_packet *nmp;
86 lwkt_port_t port;
88 KASSERT(m->m_type != MT_TAG, ("mbuf contains old style tag!\n"));
89 M_ASSERTPKTHDR(m);
90 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
91 ("mbuf is not tagged for dummynet!\n"));
93 nmp = &m->m_hdr.mh_netmsg;
94 netmsg_init(&nmp->nm_netmsg, &netisr_apanic_rport, 0,
95 ip_dn_dispatch);
96 nmp->nm_packet = m;
98 port = cpu_portfn(ip_dn_cpu);
99 lwkt_sendmsg(port, &nmp->nm_netmsg.nm_lmsg);
102 void
103 ip_dn_packet_free(struct dn_pkt *pkt)
105 struct netmsg_packet *nmp;
106 lwkt_port_t port;
107 struct mbuf *m = pkt->dn_m;
109 KASSERT(m->m_type != MT_TAG, ("mbuf contains old style tag!\n"));
110 M_ASSERTPKTHDR(m);
111 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
112 ("mbuf is not tagged for dummynet!\n"));
114 if (pkt->cpuid == mycpuid) {
115 ip_dn_freepkt(pkt);
116 return;
119 nmp = &m->m_hdr.mh_netmsg;
120 netmsg_init(&nmp->nm_netmsg, &netisr_apanic_rport, 0,
121 ip_dn_freepkt_dispatch);
122 nmp->nm_packet = m;
124 port = cpu_portfn(pkt->cpuid);
125 lwkt_sendmsg(port, &nmp->nm_netmsg.nm_lmsg);
128 void
129 ip_dn_packet_redispatch(struct dn_pkt *pkt)
131 static const netisr_fn_t dispatches[DN_TO_MAX] = {
132 [DN_TO_IP_OUT] = ip_dn_ip_output,
133 [DN_TO_IP_IN] = ip_dn_ip_input,
134 [DN_TO_ETH_DEMUX] = ip_dn_ether_demux,
135 [DN_TO_ETH_OUT] = ip_dn_ether_output
138 struct netmsg_packet *nmp;
139 struct mbuf *m;
140 netisr_fn_t dispatch;
141 lwkt_port_t port;
142 int dir;
144 dir = (pkt->dn_flags & DN_FLAGS_DIR_MASK);
145 KASSERT(dir < DN_TO_MAX,
146 ("unknown dummynet redispatch dir %d\n", dir));
148 dispatch = dispatches[dir];
149 KASSERT(dispatch != NULL,
150 ("unsupported dummynet redispatch dir %d\n", dir));
152 m = pkt->dn_m;
153 KASSERT(m->m_type != MT_TAG, ("mbuf contains old style tag!\n"));
154 M_ASSERTPKTHDR(m);
155 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
156 ("mbuf is not tagged for dummynet!\n"));
158 nmp = &m->m_hdr.mh_netmsg;
159 netmsg_init(&nmp->nm_netmsg, &netisr_apanic_rport, 0, dispatch);
160 nmp->nm_packet = m;
162 port = cpu_portfn(pkt->cpuid);
163 lwkt_sendmsg(port, &nmp->nm_netmsg.nm_lmsg);
167 ip_dn_sockopt(struct sockopt *sopt)
169 int error = 0;
171 /* Disallow sets in really-really secure mode. */
172 if (sopt->sopt_dir == SOPT_SET) {
173 if (securelevel >= 3)
174 return EPERM;
177 switch (sopt->sopt_name) {
178 case IP_DUMMYNET_GET:
179 error = ip_dn_sockopt_get(sopt);
180 break;
182 case IP_DUMMYNET_FLUSH:
183 error = ip_dn_sockopt_flush(sopt);
184 break;
186 case IP_DUMMYNET_DEL:
187 case IP_DUMMYNET_CONFIGURE:
188 error = ip_dn_sockopt_config(sopt);
189 break;
191 default:
192 kprintf("%s -- unknown option %d\n", __func__, sopt->sopt_name);
193 error = EINVAL;
194 break;
196 return error;
199 static void
200 ip_dn_freepkt(struct dn_pkt *pkt)
202 struct rtentry *rt = pkt->ro.ro_rt;
204 /* Unreference route entry */
205 if (rt != NULL) {
206 if (rt->rt_refcnt <= 0) { /* XXX assert? */
207 kprintf("-- warning, refcnt now %ld, decreasing\n",
208 rt->rt_refcnt);
210 RTFREE(rt);
213 /* Unreference packet private data */
214 if (pkt->dn_unref_priv)
215 pkt->dn_unref_priv(pkt->dn_priv);
217 /* Free the parent mbuf, this will free 'pkt' as well */
218 m_freem(pkt->dn_m);
221 static void
222 ip_dn_freepkt_dispatch(struct netmsg *nmsg)
224 struct netmsg_packet *nmp;
225 struct mbuf *m;
226 struct m_tag *mtag;
227 struct dn_pkt *pkt;
229 nmp = (struct netmsg_packet *)nmsg;
230 m = nmp->nm_packet;
231 M_ASSERTPKTHDR(m);
232 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
233 ("mbuf is not tagged for dummynet!\n"));
235 mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
236 KKASSERT(mtag != NULL);
238 pkt = m_tag_data(mtag);
239 KASSERT(pkt->cpuid == mycpuid,
240 ("%s: dummynet packet was delivered to wrong cpu! "
241 "target cpuid %d, mycpuid %d\n", __func__,
242 pkt->cpuid, mycpuid));
244 ip_dn_freepkt(pkt);
247 static void
248 ip_dn_dispatch(struct netmsg *nmsg)
250 struct netmsg_packet *nmp;
251 struct mbuf *m;
252 struct m_tag *mtag;
253 struct dn_pkt *pkt;
255 KASSERT(ip_dn_cpu == mycpuid,
256 ("%s: dummynet packet was delivered to wrong cpu! "
257 "dummynet cpuid %d, mycpuid %d\n", __func__,
258 ip_dn_cpu, mycpuid));
260 nmp = (struct netmsg_packet *)nmsg;
261 m = nmp->nm_packet;
262 M_ASSERTPKTHDR(m);
263 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
264 ("mbuf is not tagged for dummynet!\n"));
266 if (DUMMYNET_LOADED) {
267 if (ip_dn_io_ptr(m) == 0)
268 return;
272 * ip_dn_io_ptr() failed or dummynet(4) is not loaded
274 mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
275 KKASSERT(mtag != NULL);
277 pkt = m_tag_data(mtag);
278 ip_dn_packet_free(pkt);
281 static void
282 ip_dn_ip_output(struct netmsg *nmsg)
284 struct netmsg_packet *nmp;
285 struct mbuf *m;
286 struct m_tag *mtag;
287 struct dn_pkt *pkt;
288 struct rtentry *rt;
289 ip_dn_unref_priv_t unref_priv;
290 void *priv;
292 nmp = (struct netmsg_packet *)nmsg;
293 m = nmp->nm_packet;
294 M_ASSERTPKTHDR(m);
295 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
296 ("mbuf is not tagged for dummynet!\n"));
298 mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
299 KKASSERT(mtag != NULL);
301 pkt = m_tag_data(mtag);
302 KASSERT(pkt->cpuid == mycpuid,
303 ("%s: dummynet packet was delivered to wrong cpu! "
304 "target cpuid %d, mycpuid %d\n", __func__,
305 pkt->cpuid, mycpuid));
306 KASSERT((pkt->dn_flags & DN_FLAGS_DIR_MASK) == DN_TO_IP_OUT,
307 ("wrong direction %d, should be %d\n",
308 (pkt->dn_flags & DN_FLAGS_DIR_MASK), DN_TO_IP_OUT));
310 priv = pkt->dn_priv;
311 unref_priv = pkt->dn_unref_priv;
312 rt = pkt->ro.ro_rt;
314 if (rt != NULL && !(rt->rt_flags & RTF_UP)) {
316 * Recorded rtentry is gone, when the packet
317 * was on delay line.
319 ip_dn_freepkt(pkt);
320 return;
323 ip_output(pkt->dn_m, NULL, NULL, 0, NULL, NULL);
325 if (rt != NULL) {
326 if (rt->rt_refcnt <= 0) { /* XXX assert? */
327 kprintf("-- warning, refcnt now %ld, decreasing\n",
328 rt->rt_refcnt);
330 RTFREE(rt);
332 if (unref_priv)
333 unref_priv(priv);
336 static void
337 ip_dn_ip_input(struct netmsg *nmsg)
339 struct netmsg_packet *nmp;
340 struct mbuf *m;
341 struct m_tag *mtag;
342 struct dn_pkt *pkt;
343 ip_dn_unref_priv_t unref_priv;
344 void *priv;
346 nmp = (struct netmsg_packet *)nmsg;
347 m = nmp->nm_packet;
348 M_ASSERTPKTHDR(m);
349 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
350 ("mbuf is not tagged for dummynet!\n"));
352 mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
353 KKASSERT(mtag != NULL);
355 pkt = m_tag_data(mtag);
356 KASSERT(pkt->cpuid == mycpuid,
357 ("%s: dummynet packet was delivered to wrong cpu! "
358 "target cpuid %d, mycpuid %d\n", __func__,
359 pkt->cpuid, mycpuid));
360 KASSERT(pkt->ro.ro_rt == NULL,
361 ("route entry is not NULL for ip_input\n"));
362 KASSERT((pkt->dn_flags & DN_FLAGS_DIR_MASK) == DN_TO_IP_IN,
363 ("wrong direction %d, should be %d\n",
364 (pkt->dn_flags & DN_FLAGS_DIR_MASK), DN_TO_IP_IN));
366 priv = pkt->dn_priv;
367 unref_priv = pkt->dn_unref_priv;
369 ip_input(m);
371 if (unref_priv)
372 unref_priv(priv);
375 static void
376 ip_dn_ether_demux(struct netmsg *nmsg)
378 struct netmsg_packet *nmp;
379 struct mbuf *m;
380 struct m_tag *mtag;
381 struct dn_pkt *pkt;
382 struct ether_header *eh;
383 ip_dn_unref_priv_t unref_priv;
384 void *priv;
386 nmp = (struct netmsg_packet *)nmsg;
387 m = nmp->nm_packet;
388 M_ASSERTPKTHDR(m);
389 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
390 ("mbuf is not tagged for dummynet!\n"));
392 mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
393 KKASSERT(mtag != NULL);
395 pkt = m_tag_data(mtag);
396 KASSERT(pkt->cpuid == mycpuid,
397 ("%s: dummynet packet was delivered to wrong cpu! "
398 "target cpuid %d, mycpuid %d\n", __func__,
399 pkt->cpuid, mycpuid));
400 KASSERT(pkt->ro.ro_rt == NULL,
401 ("route entry is not NULL for ether_demux\n"));
402 KASSERT((pkt->dn_flags & DN_FLAGS_DIR_MASK) == DN_TO_ETH_DEMUX,
403 ("wrong direction %d, should be %d\n",
404 (pkt->dn_flags & DN_FLAGS_DIR_MASK), DN_TO_ETH_DEMUX));
406 priv = pkt->dn_priv;
407 unref_priv = pkt->dn_unref_priv;
409 if (m->m_len < ETHER_HDR_LEN &&
410 (m = m_pullup(m, ETHER_HDR_LEN)) == NULL) {
411 kprintf("%s: pullup fail, dropping pkt\n", __func__);
412 goto back;
416 * Same as ether_input, make eh be a pointer into the mbuf
418 eh = mtod(m, struct ether_header *);
419 m_adj(m, ETHER_HDR_LEN);
420 ether_demux(NULL, eh, m);
421 back:
422 if (unref_priv)
423 unref_priv(priv);
426 static void
427 ip_dn_ether_output(struct netmsg *nmsg)
429 struct netmsg_packet *nmp;
430 struct mbuf *m;
431 struct m_tag *mtag;
432 struct dn_pkt *pkt;
433 ip_dn_unref_priv_t unref_priv;
434 void *priv;
436 nmp = (struct netmsg_packet *)nmsg;
437 m = nmp->nm_packet;
438 M_ASSERTPKTHDR(m);
439 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
440 ("mbuf is not tagged for dummynet!\n"));
442 mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
443 KKASSERT(mtag != NULL);
445 pkt = m_tag_data(mtag);
446 KASSERT(pkt->cpuid == mycpuid,
447 ("%s: dummynet packet was delivered to wrong cpu! "
448 "target cpuid %d, mycpuid %d\n", __func__,
449 pkt->cpuid, mycpuid));
450 KASSERT(pkt->ro.ro_rt == NULL,
451 ("route entry is not NULL for ether_output_frame\n"));
452 KASSERT((pkt->dn_flags & DN_FLAGS_DIR_MASK) == DN_TO_ETH_OUT,
453 ("wrong direction %d, should be %d\n",
454 (pkt->dn_flags & DN_FLAGS_DIR_MASK), DN_TO_ETH_OUT));
456 priv = pkt->dn_priv;
457 unref_priv = pkt->dn_unref_priv;
459 ether_output_frame(pkt->ifp, m);
461 if (unref_priv)
462 unref_priv(priv);
465 static void
466 ip_dn_sockopt_dispatch(struct netmsg *nmsg)
468 lwkt_msg *msg = &nmsg->nm_lmsg;
469 struct dn_sopt *dn_sopt = msg->u.ms_resultp;
470 int error;
472 KASSERT(ip_dn_cpu == mycpuid,
473 ("%s: dummynet sockopt is done on wrong cpu! "
474 "dummynet cpuid %d, mycpuid %d\n", __func__,
475 ip_dn_cpu, mycpuid));
477 if (DUMMYNET_LOADED)
478 error = ip_dn_ctl_ptr(dn_sopt);
479 else
480 error = ENOPROTOOPT;
481 lwkt_replymsg(msg, error);
484 static int
485 ip_dn_sockopt_flush(struct sockopt *sopt)
487 struct dn_sopt dn_sopt;
488 struct netmsg smsg;
490 bzero(&dn_sopt, sizeof(dn_sopt));
491 dn_sopt.dn_sopt_name = sopt->sopt_name;
493 netmsg_init(&smsg, &curthread->td_msgport, 0, ip_dn_sockopt_dispatch);
494 smsg.nm_lmsg.u.ms_resultp = &dn_sopt;
495 lwkt_domsg(cpu_portfn(ip_dn_cpu), &smsg.nm_lmsg, 0);
497 return smsg.nm_lmsg.ms_error;
500 static int
501 ip_dn_sockopt_get(struct sockopt *sopt)
503 struct dn_sopt dn_sopt;
504 struct netmsg smsg;
505 int error;
507 bzero(&dn_sopt, sizeof(dn_sopt));
508 dn_sopt.dn_sopt_name = sopt->sopt_name;
510 netmsg_init(&smsg, &curthread->td_msgport, 0, ip_dn_sockopt_dispatch);
511 smsg.nm_lmsg.u.ms_resultp = &dn_sopt;
512 lwkt_domsg(cpu_portfn(ip_dn_cpu), &smsg.nm_lmsg, 0);
514 error = smsg.nm_lmsg.ms_error;
515 if (error) {
516 KKASSERT(dn_sopt.dn_sopt_arg == NULL);
517 KKASSERT(dn_sopt.dn_sopt_arglen == 0);
518 return error;
521 error = sooptcopyout(sopt, dn_sopt.dn_sopt_arg, dn_sopt.dn_sopt_arglen);
522 kfree(dn_sopt.dn_sopt_arg, M_TEMP);
523 return error;
526 static int
527 ip_dn_sockopt_config(struct sockopt *sopt)
529 struct dn_ioc_pipe tmp_ioc_pipe;
530 struct dn_sopt dn_sopt;
531 struct netmsg smsg;
532 int error;
534 error = sooptcopyin(sopt, &tmp_ioc_pipe, sizeof(tmp_ioc_pipe),
535 sizeof(tmp_ioc_pipe));
536 if (error)
537 return error;
539 bzero(&dn_sopt, sizeof(dn_sopt));
540 dn_sopt.dn_sopt_name = sopt->sopt_name;
541 dn_sopt.dn_sopt_arg = &tmp_ioc_pipe;
542 dn_sopt.dn_sopt_arglen = sizeof(tmp_ioc_pipe);
544 netmsg_init(&smsg, &curthread->td_msgport, 0, ip_dn_sockopt_dispatch);
545 smsg.nm_lmsg.u.ms_resultp = &dn_sopt;
546 lwkt_domsg(cpu_portfn(ip_dn_cpu), &smsg.nm_lmsg, 0);
548 return smsg.nm_lmsg.ms_error;