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
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>
40 #include <sys/msgport.h>
41 #include <sys/socketvar.h>
42 #include <sys/sysctl.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
;
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");
83 ip_dn_queue(struct mbuf
*m
)
85 struct netmsg_packet
*nmp
;
88 KASSERT(m
->m_type
!= MT_TAG
, ("mbuf contains old style tag!\n"));
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,
98 port
= cpu_portfn(ip_dn_cpu
);
99 lwkt_sendmsg(port
, &nmp
->nm_netmsg
.nm_lmsg
);
103 ip_dn_packet_free(struct dn_pkt
*pkt
)
105 struct netmsg_packet
*nmp
;
107 struct mbuf
*m
= pkt
->dn_m
;
109 KASSERT(m
->m_type
!= MT_TAG
, ("mbuf contains old style tag!\n"));
111 KASSERT(m
->m_pkthdr
.fw_flags
& DUMMYNET_MBUF_TAGGED
,
112 ("mbuf is not tagged for dummynet!\n"));
114 if (pkt
->cpuid
== mycpuid
) {
119 nmp
= &m
->m_hdr
.mh_netmsg
;
120 netmsg_init(&nmp
->nm_netmsg
, &netisr_apanic_rport
, 0,
121 ip_dn_freepkt_dispatch
);
124 port
= cpu_portfn(pkt
->cpuid
);
125 lwkt_sendmsg(port
, &nmp
->nm_netmsg
.nm_lmsg
);
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
;
140 netisr_fn_t dispatch
;
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
));
153 KASSERT(m
->m_type
!= MT_TAG
, ("mbuf contains old style tag!\n"));
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
);
162 port
= cpu_portfn(pkt
->cpuid
);
163 lwkt_sendmsg(port
, &nmp
->nm_netmsg
.nm_lmsg
);
167 ip_dn_sockopt(struct sockopt
*sopt
)
171 /* Disallow sets in really-really secure mode. */
172 if (sopt
->sopt_dir
== SOPT_SET
) {
173 if (securelevel
>= 3)
177 switch (sopt
->sopt_name
) {
178 case IP_DUMMYNET_GET
:
179 error
= ip_dn_sockopt_get(sopt
);
182 case IP_DUMMYNET_FLUSH
:
183 error
= ip_dn_sockopt_flush(sopt
);
186 case IP_DUMMYNET_DEL
:
187 case IP_DUMMYNET_CONFIGURE
:
188 error
= ip_dn_sockopt_config(sopt
);
192 kprintf("%s -- unknown option %d\n", __func__
, sopt
->sopt_name
);
200 ip_dn_freepkt(struct dn_pkt
*pkt
)
202 struct rtentry
*rt
= pkt
->ro
.ro_rt
;
204 /* Unreference route entry */
206 if (rt
->rt_refcnt
<= 0) { /* XXX assert? */
207 kprintf("-- warning, refcnt now %ld, decreasing\n",
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 */
222 ip_dn_freepkt_dispatch(struct netmsg
*nmsg
)
224 struct netmsg_packet
*nmp
;
229 nmp
= (struct netmsg_packet
*)nmsg
;
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
));
248 ip_dn_dispatch(struct netmsg
*nmsg
)
250 struct netmsg_packet
*nmp
;
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
;
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)
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
);
282 ip_dn_ip_output(struct netmsg
*nmsg
)
284 struct netmsg_packet
*nmp
;
289 ip_dn_unref_priv_t unref_priv
;
292 nmp
= (struct netmsg_packet
*)nmsg
;
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
));
311 unref_priv
= pkt
->dn_unref_priv
;
314 if (rt
!= NULL
&& !(rt
->rt_flags
& RTF_UP
)) {
316 * Recorded rtentry is gone, when the packet
323 ip_output(pkt
->dn_m
, NULL
, NULL
, 0, NULL
, NULL
);
326 if (rt
->rt_refcnt
<= 0) { /* XXX assert? */
327 kprintf("-- warning, refcnt now %ld, decreasing\n",
337 ip_dn_ip_input(struct netmsg
*nmsg
)
339 struct netmsg_packet
*nmp
;
343 ip_dn_unref_priv_t unref_priv
;
346 nmp
= (struct netmsg_packet
*)nmsg
;
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
));
367 unref_priv
= pkt
->dn_unref_priv
;
376 ip_dn_ether_demux(struct netmsg
*nmsg
)
378 struct netmsg_packet
*nmp
;
382 struct ether_header
*eh
;
383 ip_dn_unref_priv_t unref_priv
;
386 nmp
= (struct netmsg_packet
*)nmsg
;
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
));
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__
);
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
);
427 ip_dn_ether_output(struct netmsg
*nmsg
)
429 struct netmsg_packet
*nmp
;
433 ip_dn_unref_priv_t unref_priv
;
436 nmp
= (struct netmsg_packet
*)nmsg
;
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
));
457 unref_priv
= pkt
->dn_unref_priv
;
459 ether_output_frame(pkt
->ifp
, m
);
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
;
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
));
478 error
= ip_dn_ctl_ptr(dn_sopt
);
481 lwkt_replymsg(msg
, error
);
485 ip_dn_sockopt_flush(struct sockopt
*sopt
)
487 struct dn_sopt dn_sopt
;
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
;
501 ip_dn_sockopt_get(struct sockopt
*sopt
)
503 struct dn_sopt dn_sopt
;
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
;
516 KKASSERT(dn_sopt
.dn_sopt_arg
== NULL
);
517 KKASSERT(dn_sopt
.dn_sopt_arglen
== 0);
521 error
= sooptcopyout(sopt
, dn_sopt
.dn_sopt_arg
, dn_sopt
.dn_sopt_arglen
);
522 kfree(dn_sopt
.dn_sopt_arg
, M_TEMP
);
527 ip_dn_sockopt_config(struct sockopt
*sopt
)
529 struct dn_ioc_pipe tmp_ioc_pipe
;
530 struct dn_sopt dn_sopt
;
534 error
= sooptcopyin(sopt
, &tmp_ioc_pipe
, sizeof(tmp_ioc_pipe
),
535 sizeof(tmp_ioc_pipe
));
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
;