- Test m_pkthdr.fw_flags against DUMMYNET_MBUF_TAGGED before trying to locate
[dragonfly/netmp.git] / sys / net / dummynet / ip_dummynet_glue.c
blobc58ace9149e886314f7bfd66a25898f1aa102849
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.8 2008/08/22 09:14:17 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 M_ASSERTPKTHDR(m);
89 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
90 ("mbuf is not tagged for dummynet!\n"));
92 nmp = &m->m_hdr.mh_netmsg;
93 netmsg_init(&nmp->nm_netmsg, &netisr_apanic_rport, 0,
94 ip_dn_dispatch);
95 nmp->nm_packet = m;
97 port = cpu_portfn(ip_dn_cpu);
98 lwkt_sendmsg(port, &nmp->nm_netmsg.nm_lmsg);
101 void
102 ip_dn_packet_free(struct dn_pkt *pkt)
104 struct netmsg_packet *nmp;
105 lwkt_port_t port;
106 struct mbuf *m = pkt->dn_m;
108 M_ASSERTPKTHDR(m);
109 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
110 ("mbuf is not tagged for dummynet!\n"));
112 if (pkt->cpuid == mycpuid) {
113 ip_dn_freepkt(pkt);
114 return;
117 nmp = &m->m_hdr.mh_netmsg;
118 netmsg_init(&nmp->nm_netmsg, &netisr_apanic_rport, 0,
119 ip_dn_freepkt_dispatch);
120 nmp->nm_packet = m;
122 port = cpu_portfn(pkt->cpuid);
123 lwkt_sendmsg(port, &nmp->nm_netmsg.nm_lmsg);
126 void
127 ip_dn_packet_redispatch(struct dn_pkt *pkt)
129 static const netisr_fn_t dispatches[DN_TO_MAX] = {
130 [DN_TO_IP_OUT] = ip_dn_ip_output,
131 [DN_TO_IP_IN] = ip_dn_ip_input,
132 [DN_TO_ETH_DEMUX] = ip_dn_ether_demux,
133 [DN_TO_ETH_OUT] = ip_dn_ether_output
136 struct netmsg_packet *nmp;
137 struct mbuf *m;
138 netisr_fn_t dispatch;
139 lwkt_port_t port;
140 int dir;
142 dir = (pkt->dn_flags & DN_FLAGS_DIR_MASK);
143 KASSERT(dir < DN_TO_MAX,
144 ("unknown dummynet redispatch dir %d\n", dir));
146 dispatch = dispatches[dir];
147 KASSERT(dispatch != NULL,
148 ("unsupported dummynet redispatch dir %d\n", dir));
150 m = pkt->dn_m;
151 M_ASSERTPKTHDR(m);
152 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
153 ("mbuf is not tagged for dummynet!\n"));
155 nmp = &m->m_hdr.mh_netmsg;
156 netmsg_init(&nmp->nm_netmsg, &netisr_apanic_rport, 0, dispatch);
157 nmp->nm_packet = m;
159 port = cpu_portfn(pkt->cpuid);
160 lwkt_sendmsg(port, &nmp->nm_netmsg.nm_lmsg);
164 ip_dn_sockopt(struct sockopt *sopt)
166 int error = 0;
168 /* Disallow sets in really-really secure mode. */
169 if (sopt->sopt_dir == SOPT_SET) {
170 if (securelevel >= 3)
171 return EPERM;
174 switch (sopt->sopt_name) {
175 case IP_DUMMYNET_GET:
176 error = ip_dn_sockopt_get(sopt);
177 break;
179 case IP_DUMMYNET_FLUSH:
180 error = ip_dn_sockopt_flush(sopt);
181 break;
183 case IP_DUMMYNET_DEL:
184 case IP_DUMMYNET_CONFIGURE:
185 error = ip_dn_sockopt_config(sopt);
186 break;
188 default:
189 kprintf("%s -- unknown option %d\n", __func__, sopt->sopt_name);
190 error = EINVAL;
191 break;
193 return error;
196 static void
197 ip_dn_freepkt(struct dn_pkt *pkt)
199 struct rtentry *rt = pkt->ro.ro_rt;
201 /* Unreference route entry */
202 if (rt != NULL) {
203 if (rt->rt_refcnt <= 0) { /* XXX assert? */
204 kprintf("-- warning, refcnt now %ld, decreasing\n",
205 rt->rt_refcnt);
207 RTFREE(rt);
210 /* Unreference packet private data */
211 if (pkt->dn_unref_priv)
212 pkt->dn_unref_priv(pkt->dn_priv);
214 /* Free the parent mbuf, this will free 'pkt' as well */
215 m_freem(pkt->dn_m);
218 static void
219 ip_dn_freepkt_dispatch(struct netmsg *nmsg)
221 struct netmsg_packet *nmp;
222 struct mbuf *m;
223 struct m_tag *mtag;
224 struct dn_pkt *pkt;
226 nmp = (struct netmsg_packet *)nmsg;
227 m = nmp->nm_packet;
228 M_ASSERTPKTHDR(m);
229 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
230 ("mbuf is not tagged for dummynet!\n"));
232 mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
233 KKASSERT(mtag != NULL);
235 pkt = m_tag_data(mtag);
236 KASSERT(pkt->cpuid == mycpuid,
237 ("%s: dummynet packet was delivered to wrong cpu! "
238 "target cpuid %d, mycpuid %d\n", __func__,
239 pkt->cpuid, mycpuid));
241 ip_dn_freepkt(pkt);
244 static void
245 ip_dn_dispatch(struct netmsg *nmsg)
247 struct netmsg_packet *nmp;
248 struct mbuf *m;
249 struct m_tag *mtag;
250 struct dn_pkt *pkt;
252 KASSERT(ip_dn_cpu == mycpuid,
253 ("%s: dummynet packet was delivered to wrong cpu! "
254 "dummynet cpuid %d, mycpuid %d\n", __func__,
255 ip_dn_cpu, mycpuid));
257 nmp = (struct netmsg_packet *)nmsg;
258 m = nmp->nm_packet;
259 M_ASSERTPKTHDR(m);
260 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
261 ("mbuf is not tagged for dummynet!\n"));
263 if (DUMMYNET_LOADED) {
264 if (ip_dn_io_ptr(m) == 0)
265 return;
269 * ip_dn_io_ptr() failed or dummynet(4) is not loaded
271 mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
272 KKASSERT(mtag != NULL);
274 pkt = m_tag_data(mtag);
275 ip_dn_packet_free(pkt);
278 static void
279 ip_dn_ip_output(struct netmsg *nmsg)
281 struct netmsg_packet *nmp;
282 struct mbuf *m;
283 struct m_tag *mtag;
284 struct dn_pkt *pkt;
285 struct rtentry *rt;
286 ip_dn_unref_priv_t unref_priv;
287 void *priv;
289 nmp = (struct netmsg_packet *)nmsg;
290 m = nmp->nm_packet;
291 M_ASSERTPKTHDR(m);
292 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
293 ("mbuf is not tagged for dummynet!\n"));
295 mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
296 KKASSERT(mtag != NULL);
298 pkt = m_tag_data(mtag);
299 KASSERT(pkt->cpuid == mycpuid,
300 ("%s: dummynet packet was delivered to wrong cpu! "
301 "target cpuid %d, mycpuid %d\n", __func__,
302 pkt->cpuid, mycpuid));
303 KASSERT((pkt->dn_flags & DN_FLAGS_DIR_MASK) == DN_TO_IP_OUT,
304 ("wrong direction %d, should be %d\n",
305 (pkt->dn_flags & DN_FLAGS_DIR_MASK), DN_TO_IP_OUT));
307 priv = pkt->dn_priv;
308 unref_priv = pkt->dn_unref_priv;
309 rt = pkt->ro.ro_rt;
311 if (rt != NULL && !(rt->rt_flags & RTF_UP)) {
313 * Recorded rtentry is gone, when the packet
314 * was on delay line.
316 ip_dn_freepkt(pkt);
317 return;
320 ip_output(pkt->dn_m, NULL, NULL, 0, NULL, NULL);
322 if (rt != NULL) {
323 if (rt->rt_refcnt <= 0) { /* XXX assert? */
324 kprintf("-- warning, refcnt now %ld, decreasing\n",
325 rt->rt_refcnt);
327 RTFREE(rt);
329 if (unref_priv)
330 unref_priv(priv);
333 static void
334 ip_dn_ip_input(struct netmsg *nmsg)
336 struct netmsg_packet *nmp;
337 struct mbuf *m;
338 struct m_tag *mtag;
339 struct dn_pkt *pkt;
340 ip_dn_unref_priv_t unref_priv;
341 void *priv;
343 nmp = (struct netmsg_packet *)nmsg;
344 m = nmp->nm_packet;
345 M_ASSERTPKTHDR(m);
346 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
347 ("mbuf is not tagged for dummynet!\n"));
349 mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
350 KKASSERT(mtag != NULL);
352 pkt = m_tag_data(mtag);
353 KASSERT(pkt->cpuid == mycpuid,
354 ("%s: dummynet packet was delivered to wrong cpu! "
355 "target cpuid %d, mycpuid %d\n", __func__,
356 pkt->cpuid, mycpuid));
357 KASSERT(pkt->ro.ro_rt == NULL,
358 ("route entry is not NULL for ip_input\n"));
359 KASSERT((pkt->dn_flags & DN_FLAGS_DIR_MASK) == DN_TO_IP_IN,
360 ("wrong direction %d, should be %d\n",
361 (pkt->dn_flags & DN_FLAGS_DIR_MASK), DN_TO_IP_IN));
363 priv = pkt->dn_priv;
364 unref_priv = pkt->dn_unref_priv;
366 ip_input(m);
368 if (unref_priv)
369 unref_priv(priv);
372 static void
373 ip_dn_ether_demux(struct netmsg *nmsg)
375 struct netmsg_packet *nmp;
376 struct mbuf *m;
377 struct m_tag *mtag;
378 struct dn_pkt *pkt;
379 ip_dn_unref_priv_t unref_priv;
380 void *priv;
382 nmp = (struct netmsg_packet *)nmsg;
383 m = nmp->nm_packet;
384 M_ASSERTPKTHDR(m);
385 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
386 ("mbuf is not tagged for dummynet!\n"));
388 mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
389 KKASSERT(mtag != NULL);
391 pkt = m_tag_data(mtag);
392 KASSERT(pkt->cpuid == mycpuid,
393 ("%s: dummynet packet was delivered to wrong cpu! "
394 "target cpuid %d, mycpuid %d\n", __func__,
395 pkt->cpuid, mycpuid));
396 KASSERT(pkt->ro.ro_rt == NULL,
397 ("route entry is not NULL for ether_demux\n"));
398 KASSERT((pkt->dn_flags & DN_FLAGS_DIR_MASK) == DN_TO_ETH_DEMUX,
399 ("wrong direction %d, should be %d\n",
400 (pkt->dn_flags & DN_FLAGS_DIR_MASK), DN_TO_ETH_DEMUX));
402 priv = pkt->dn_priv;
403 unref_priv = pkt->dn_unref_priv;
406 * Make sure that ether header is contiguous
408 if (m->m_len < ETHER_HDR_LEN &&
409 (m = m_pullup(m, ETHER_HDR_LEN)) == NULL) {
410 kprintf("%s: pullup fail, dropping pkt\n", __func__);
411 goto back;
413 ether_demux_oncpu(NULL, m);
414 back:
415 if (unref_priv)
416 unref_priv(priv);
419 static void
420 ip_dn_ether_output(struct netmsg *nmsg)
422 struct netmsg_packet *nmp;
423 struct mbuf *m;
424 struct m_tag *mtag;
425 struct dn_pkt *pkt;
426 ip_dn_unref_priv_t unref_priv;
427 void *priv;
429 nmp = (struct netmsg_packet *)nmsg;
430 m = nmp->nm_packet;
431 M_ASSERTPKTHDR(m);
432 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
433 ("mbuf is not tagged for dummynet!\n"));
435 mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
436 KKASSERT(mtag != NULL);
438 pkt = m_tag_data(mtag);
439 KASSERT(pkt->cpuid == mycpuid,
440 ("%s: dummynet packet was delivered to wrong cpu! "
441 "target cpuid %d, mycpuid %d\n", __func__,
442 pkt->cpuid, mycpuid));
443 KASSERT(pkt->ro.ro_rt == NULL,
444 ("route entry is not NULL for ether_output_frame\n"));
445 KASSERT((pkt->dn_flags & DN_FLAGS_DIR_MASK) == DN_TO_ETH_OUT,
446 ("wrong direction %d, should be %d\n",
447 (pkt->dn_flags & DN_FLAGS_DIR_MASK), DN_TO_ETH_OUT));
449 priv = pkt->dn_priv;
450 unref_priv = pkt->dn_unref_priv;
452 ether_output_frame(pkt->ifp, m);
454 if (unref_priv)
455 unref_priv(priv);
458 static void
459 ip_dn_sockopt_dispatch(struct netmsg *nmsg)
461 lwkt_msg *msg = &nmsg->nm_lmsg;
462 struct dn_sopt *dn_sopt = msg->u.ms_resultp;
463 int error;
465 KASSERT(ip_dn_cpu == mycpuid,
466 ("%s: dummynet sockopt is done on wrong cpu! "
467 "dummynet cpuid %d, mycpuid %d\n", __func__,
468 ip_dn_cpu, mycpuid));
470 if (DUMMYNET_LOADED)
471 error = ip_dn_ctl_ptr(dn_sopt);
472 else
473 error = ENOPROTOOPT;
474 lwkt_replymsg(msg, error);
477 static int
478 ip_dn_sockopt_flush(struct sockopt *sopt)
480 struct dn_sopt dn_sopt;
481 struct netmsg smsg;
483 bzero(&dn_sopt, sizeof(dn_sopt));
484 dn_sopt.dn_sopt_name = sopt->sopt_name;
486 netmsg_init(&smsg, &curthread->td_msgport, 0, ip_dn_sockopt_dispatch);
487 smsg.nm_lmsg.u.ms_resultp = &dn_sopt;
488 lwkt_domsg(cpu_portfn(ip_dn_cpu), &smsg.nm_lmsg, 0);
490 return smsg.nm_lmsg.ms_error;
493 static int
494 ip_dn_sockopt_get(struct sockopt *sopt)
496 struct dn_sopt dn_sopt;
497 struct netmsg smsg;
498 int error;
500 bzero(&dn_sopt, sizeof(dn_sopt));
501 dn_sopt.dn_sopt_name = sopt->sopt_name;
503 netmsg_init(&smsg, &curthread->td_msgport, 0, ip_dn_sockopt_dispatch);
504 smsg.nm_lmsg.u.ms_resultp = &dn_sopt;
505 lwkt_domsg(cpu_portfn(ip_dn_cpu), &smsg.nm_lmsg, 0);
507 error = smsg.nm_lmsg.ms_error;
508 if (error) {
509 KKASSERT(dn_sopt.dn_sopt_arg == NULL);
510 KKASSERT(dn_sopt.dn_sopt_arglen == 0);
511 return error;
514 soopt_from_kbuf(sopt, dn_sopt.dn_sopt_arg, dn_sopt.dn_sopt_arglen);
515 kfree(dn_sopt.dn_sopt_arg, M_TEMP);
516 return 0;
519 static int
520 ip_dn_sockopt_config(struct sockopt *sopt)
522 struct dn_ioc_pipe tmp_ioc_pipe;
523 struct dn_sopt dn_sopt;
524 struct netmsg smsg;
525 int error;
527 error = soopt_to_kbuf(sopt, &tmp_ioc_pipe, sizeof tmp_ioc_pipe,
528 sizeof tmp_ioc_pipe);
529 if (error)
530 return error;
532 bzero(&dn_sopt, sizeof(dn_sopt));
533 dn_sopt.dn_sopt_name = sopt->sopt_name;
534 dn_sopt.dn_sopt_arg = &tmp_ioc_pipe;
535 dn_sopt.dn_sopt_arglen = sizeof(tmp_ioc_pipe);
537 netmsg_init(&smsg, &curthread->td_msgport, 0, ip_dn_sockopt_dispatch);
538 smsg.nm_lmsg.u.ms_resultp = &dn_sopt;
539 lwkt_domsg(cpu_portfn(ip_dn_cpu), &smsg.nm_lmsg, 0);
541 return smsg.nm_lmsg.ms_error;