linprocfs - Introduce /proc/mounts
[dragonfly.git] / sys / net / dummynet / ip_dummynet_glue.c
blob214ae095a7a6d8a64d9f8e34feb3102142d43707
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.11 2008/09/20 04:36:51 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, NULL, &netisr_apanic_rport,
94 0, 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 struct mbuf *m = pkt->dn_m;
107 M_ASSERTPKTHDR(m);
108 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
109 ("mbuf is not tagged for dummynet!\n"));
111 nmp = &m->m_hdr.mh_netmsg;
112 netmsg_init(&nmp->nm_netmsg, NULL, &netisr_apanic_rport,
113 0, ip_dn_freepkt_dispatch);
114 nmp->nm_packet = m;
116 lwkt_sendmsg(pkt->msgport, &nmp->nm_netmsg.nm_lmsg);
119 void
120 ip_dn_packet_redispatch(struct dn_pkt *pkt)
122 static const netisr_fn_t dispatches[DN_TO_MAX] = {
123 [DN_TO_IP_OUT] = ip_dn_ip_output,
124 [DN_TO_IP_IN] = ip_dn_ip_input,
125 [DN_TO_ETH_DEMUX] = ip_dn_ether_demux,
126 [DN_TO_ETH_OUT] = ip_dn_ether_output
129 struct netmsg_packet *nmp;
130 struct mbuf *m;
131 netisr_fn_t dispatch;
132 int dir;
134 dir = (pkt->dn_flags & DN_FLAGS_DIR_MASK);
135 KASSERT(dir < DN_TO_MAX,
136 ("unknown dummynet redispatch dir %d\n", dir));
138 dispatch = dispatches[dir];
139 KASSERT(dispatch != NULL,
140 ("unsupported dummynet redispatch dir %d\n", dir));
142 m = pkt->dn_m;
143 M_ASSERTPKTHDR(m);
144 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
145 ("mbuf is not tagged for dummynet!\n"));
147 nmp = &m->m_hdr.mh_netmsg;
148 netmsg_init(&nmp->nm_netmsg, NULL, &netisr_apanic_rport,
149 0, dispatch);
150 nmp->nm_packet = m;
152 lwkt_sendmsg(pkt->msgport, &nmp->nm_netmsg.nm_lmsg);
156 ip_dn_sockopt(struct sockopt *sopt)
158 int error = 0;
160 /* Disallow sets in really-really secure mode. */
161 if (sopt->sopt_dir == SOPT_SET) {
162 if (securelevel >= 3)
163 return EPERM;
166 switch (sopt->sopt_name) {
167 case IP_DUMMYNET_GET:
168 error = ip_dn_sockopt_get(sopt);
169 break;
171 case IP_DUMMYNET_FLUSH:
172 error = ip_dn_sockopt_flush(sopt);
173 break;
175 case IP_DUMMYNET_DEL:
176 case IP_DUMMYNET_CONFIGURE:
177 error = ip_dn_sockopt_config(sopt);
178 break;
180 default:
181 kprintf("%s -- unknown option %d\n", __func__, sopt->sopt_name);
182 error = EINVAL;
183 break;
185 return error;
188 static void
189 ip_dn_freepkt(struct dn_pkt *pkt)
191 struct rtentry *rt = pkt->ro.ro_rt;
193 /* Unreference route entry */
194 if (rt != NULL) {
195 if (rt->rt_refcnt <= 0) { /* XXX assert? */
196 kprintf("-- warning, refcnt now %ld, decreasing\n",
197 rt->rt_refcnt);
199 RTFREE(rt);
202 /* Unreference packet private data */
203 if (pkt->dn_unref_priv)
204 pkt->dn_unref_priv(pkt->dn_priv);
206 /* Free the parent mbuf, this will free 'pkt' as well */
207 m_freem(pkt->dn_m);
210 static void
211 ip_dn_freepkt_dispatch(struct netmsg *nmsg)
213 struct netmsg_packet *nmp;
214 struct mbuf *m;
215 struct m_tag *mtag;
216 struct dn_pkt *pkt;
218 nmp = (struct netmsg_packet *)nmsg;
219 m = nmp->nm_packet;
220 M_ASSERTPKTHDR(m);
221 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
222 ("mbuf is not tagged for dummynet!\n"));
224 mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
225 KKASSERT(mtag != NULL);
227 pkt = m_tag_data(mtag);
228 KASSERT(pkt->cpuid == mycpuid,
229 ("%s: dummynet packet was delivered to wrong cpu! "
230 "target cpuid %d, mycpuid %d\n", __func__,
231 pkt->cpuid, mycpuid));
233 ip_dn_freepkt(pkt);
236 static void
237 ip_dn_dispatch(struct netmsg *nmsg)
239 struct netmsg_packet *nmp;
240 struct mbuf *m;
241 struct m_tag *mtag;
242 struct dn_pkt *pkt;
244 KASSERT(ip_dn_cpu == mycpuid,
245 ("%s: dummynet packet was delivered to wrong cpu! "
246 "dummynet cpuid %d, mycpuid %d\n", __func__,
247 ip_dn_cpu, mycpuid));
249 nmp = (struct netmsg_packet *)nmsg;
250 m = nmp->nm_packet;
251 M_ASSERTPKTHDR(m);
252 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
253 ("mbuf is not tagged for dummynet!\n"));
255 if (DUMMYNET_LOADED) {
256 if (ip_dn_io_ptr(m) == 0)
257 return;
261 * ip_dn_io_ptr() failed or dummynet(4) is not loaded
263 mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
264 KKASSERT(mtag != NULL);
266 pkt = m_tag_data(mtag);
267 ip_dn_packet_free(pkt);
270 static void
271 ip_dn_ip_output(struct netmsg *nmsg)
273 struct netmsg_packet *nmp;
274 struct mbuf *m;
275 struct m_tag *mtag;
276 struct dn_pkt *pkt;
277 struct rtentry *rt;
278 ip_dn_unref_priv_t unref_priv;
279 void *priv;
281 nmp = (struct netmsg_packet *)nmsg;
282 m = nmp->nm_packet;
283 M_ASSERTPKTHDR(m);
284 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
285 ("mbuf is not tagged for dummynet!\n"));
287 mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
288 KKASSERT(mtag != NULL);
290 pkt = m_tag_data(mtag);
291 KASSERT(pkt->cpuid == mycpuid,
292 ("%s: dummynet packet was delivered to wrong cpu! "
293 "target cpuid %d, mycpuid %d\n", __func__,
294 pkt->cpuid, mycpuid));
295 KASSERT((pkt->dn_flags & DN_FLAGS_DIR_MASK) == DN_TO_IP_OUT,
296 ("wrong direction %d, should be %d\n",
297 (pkt->dn_flags & DN_FLAGS_DIR_MASK), DN_TO_IP_OUT));
299 priv = pkt->dn_priv;
300 unref_priv = pkt->dn_unref_priv;
301 rt = pkt->ro.ro_rt;
303 if (rt != NULL && !(rt->rt_flags & RTF_UP)) {
305 * Recorded rtentry is gone, when the packet
306 * was on delay line.
308 ip_dn_freepkt(pkt);
309 return;
312 ip_output(pkt->dn_m, NULL, NULL, pkt->flags, NULL, NULL);
313 /* 'rt' will be freed in ip_output */
315 if (unref_priv)
316 unref_priv(priv);
319 static void
320 ip_dn_ip_input(struct netmsg *nmsg)
322 struct netmsg_packet *nmp;
323 struct mbuf *m;
324 struct m_tag *mtag;
325 struct dn_pkt *pkt;
326 ip_dn_unref_priv_t unref_priv;
327 void *priv;
329 nmp = (struct netmsg_packet *)nmsg;
330 m = nmp->nm_packet;
331 M_ASSERTPKTHDR(m);
332 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
333 ("mbuf is not tagged for dummynet!\n"));
335 mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
336 KKASSERT(mtag != NULL);
338 pkt = m_tag_data(mtag);
339 KASSERT(pkt->cpuid == mycpuid,
340 ("%s: dummynet packet was delivered to wrong cpu! "
341 "target cpuid %d, mycpuid %d\n", __func__,
342 pkt->cpuid, mycpuid));
343 KASSERT(pkt->ro.ro_rt == NULL,
344 ("route entry is not NULL for ip_input\n"));
345 KASSERT((pkt->dn_flags & DN_FLAGS_DIR_MASK) == DN_TO_IP_IN,
346 ("wrong direction %d, should be %d\n",
347 (pkt->dn_flags & DN_FLAGS_DIR_MASK), DN_TO_IP_IN));
349 priv = pkt->dn_priv;
350 unref_priv = pkt->dn_unref_priv;
352 ip_input(m);
354 if (unref_priv)
355 unref_priv(priv);
358 static void
359 ip_dn_ether_demux(struct netmsg *nmsg)
361 struct netmsg_packet *nmp;
362 struct mbuf *m;
363 struct m_tag *mtag;
364 struct dn_pkt *pkt;
365 ip_dn_unref_priv_t unref_priv;
366 void *priv;
368 nmp = (struct netmsg_packet *)nmsg;
369 m = nmp->nm_packet;
370 M_ASSERTPKTHDR(m);
371 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
372 ("mbuf is not tagged for dummynet!\n"));
374 mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
375 KKASSERT(mtag != NULL);
377 pkt = m_tag_data(mtag);
378 KASSERT(pkt->cpuid == mycpuid,
379 ("%s: dummynet packet was delivered to wrong cpu! "
380 "target cpuid %d, mycpuid %d\n", __func__,
381 pkt->cpuid, mycpuid));
382 KASSERT(pkt->ro.ro_rt == NULL,
383 ("route entry is not NULL for ether_demux\n"));
384 KASSERT((pkt->dn_flags & DN_FLAGS_DIR_MASK) == DN_TO_ETH_DEMUX,
385 ("wrong direction %d, should be %d\n",
386 (pkt->dn_flags & DN_FLAGS_DIR_MASK), DN_TO_ETH_DEMUX));
388 priv = pkt->dn_priv;
389 unref_priv = pkt->dn_unref_priv;
392 * Make sure that ether header is contiguous
394 if (m->m_len < ETHER_HDR_LEN &&
395 (m = m_pullup(m, ETHER_HDR_LEN)) == NULL) {
396 kprintf("%s: pullup fail, dropping pkt\n", __func__);
397 goto back;
399 ether_demux_oncpu(m->m_pkthdr.rcvif, m);
400 back:
401 if (unref_priv)
402 unref_priv(priv);
405 static void
406 ip_dn_ether_output(struct netmsg *nmsg)
408 struct netmsg_packet *nmp;
409 struct mbuf *m;
410 struct m_tag *mtag;
411 struct dn_pkt *pkt;
412 ip_dn_unref_priv_t unref_priv;
413 void *priv;
415 nmp = (struct netmsg_packet *)nmsg;
416 m = nmp->nm_packet;
417 M_ASSERTPKTHDR(m);
418 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
419 ("mbuf is not tagged for dummynet!\n"));
421 mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
422 KKASSERT(mtag != NULL);
424 pkt = m_tag_data(mtag);
425 KASSERT(pkt->cpuid == mycpuid,
426 ("%s: dummynet packet was delivered to wrong cpu! "
427 "target cpuid %d, mycpuid %d\n", __func__,
428 pkt->cpuid, mycpuid));
429 KASSERT(pkt->ro.ro_rt == NULL,
430 ("route entry is not NULL for ether_output_frame\n"));
431 KASSERT((pkt->dn_flags & DN_FLAGS_DIR_MASK) == DN_TO_ETH_OUT,
432 ("wrong direction %d, should be %d\n",
433 (pkt->dn_flags & DN_FLAGS_DIR_MASK), DN_TO_ETH_OUT));
435 priv = pkt->dn_priv;
436 unref_priv = pkt->dn_unref_priv;
438 ether_output_frame(pkt->ifp, m);
440 if (unref_priv)
441 unref_priv(priv);
444 static void
445 ip_dn_sockopt_dispatch(struct netmsg *nmsg)
447 lwkt_msg *msg = &nmsg->nm_lmsg;
448 struct dn_sopt *dn_sopt = msg->u.ms_resultp;
449 int error;
451 KASSERT(ip_dn_cpu == mycpuid,
452 ("%s: dummynet sockopt is done on wrong cpu! "
453 "dummynet cpuid %d, mycpuid %d\n", __func__,
454 ip_dn_cpu, mycpuid));
456 if (DUMMYNET_LOADED)
457 error = ip_dn_ctl_ptr(dn_sopt);
458 else
459 error = ENOPROTOOPT;
460 lwkt_replymsg(msg, error);
463 static int
464 ip_dn_sockopt_flush(struct sockopt *sopt)
466 struct dn_sopt dn_sopt;
467 struct netmsg smsg;
469 bzero(&dn_sopt, sizeof(dn_sopt));
470 dn_sopt.dn_sopt_name = sopt->sopt_name;
472 netmsg_init(&smsg, NULL, &curthread->td_msgport,
473 0, ip_dn_sockopt_dispatch);
474 smsg.nm_lmsg.u.ms_resultp = &dn_sopt;
475 lwkt_domsg(cpu_portfn(ip_dn_cpu), &smsg.nm_lmsg, 0);
477 return smsg.nm_lmsg.ms_error;
480 static int
481 ip_dn_sockopt_get(struct sockopt *sopt)
483 struct dn_sopt dn_sopt;
484 struct netmsg smsg;
485 int error;
487 bzero(&dn_sopt, sizeof(dn_sopt));
488 dn_sopt.dn_sopt_name = sopt->sopt_name;
490 netmsg_init(&smsg, NULL, &curthread->td_msgport,
491 0, ip_dn_sockopt_dispatch);
492 smsg.nm_lmsg.u.ms_resultp = &dn_sopt;
493 lwkt_domsg(cpu_portfn(ip_dn_cpu), &smsg.nm_lmsg, 0);
495 error = smsg.nm_lmsg.ms_error;
496 if (error) {
497 KKASSERT(dn_sopt.dn_sopt_arg == NULL);
498 KKASSERT(dn_sopt.dn_sopt_arglen == 0);
499 return error;
502 soopt_from_kbuf(sopt, dn_sopt.dn_sopt_arg, dn_sopt.dn_sopt_arglen);
503 kfree(dn_sopt.dn_sopt_arg, M_TEMP);
504 return 0;
507 static int
508 ip_dn_sockopt_config(struct sockopt *sopt)
510 struct dn_ioc_pipe tmp_ioc_pipe;
511 struct dn_sopt dn_sopt;
512 struct netmsg smsg;
513 int error;
515 error = soopt_to_kbuf(sopt, &tmp_ioc_pipe, sizeof tmp_ioc_pipe,
516 sizeof tmp_ioc_pipe);
517 if (error)
518 return error;
520 bzero(&dn_sopt, sizeof(dn_sopt));
521 dn_sopt.dn_sopt_name = sopt->sopt_name;
522 dn_sopt.dn_sopt_arg = &tmp_ioc_pipe;
523 dn_sopt.dn_sopt_arglen = sizeof(tmp_ioc_pipe);
525 netmsg_init(&smsg, NULL, &curthread->td_msgport,
526 0, ip_dn_sockopt_dispatch);
527 smsg.nm_lmsg.u.ms_resultp = &dn_sopt;
528 lwkt_domsg(cpu_portfn(ip_dn_cpu), &smsg.nm_lmsg, 0);
530 return smsg.nm_lmsg.ms_error;