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.6 2008/06/17 20:50:11 aggelos 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 ip_dn_unref_priv_t unref_priv
;
385 nmp
= (struct netmsg_packet
*)nmsg
;
388 KASSERT(m
->m_pkthdr
.fw_flags
& DUMMYNET_MBUF_TAGGED
,
389 ("mbuf is not tagged for dummynet!\n"));
391 mtag
= m_tag_find(m
, PACKET_TAG_DUMMYNET
, NULL
);
392 KKASSERT(mtag
!= NULL
);
394 pkt
= m_tag_data(mtag
);
395 KASSERT(pkt
->cpuid
== mycpuid
,
396 ("%s: dummynet packet was delivered to wrong cpu! "
397 "target cpuid %d, mycpuid %d\n", __func__
,
398 pkt
->cpuid
, mycpuid
));
399 KASSERT(pkt
->ro
.ro_rt
== NULL
,
400 ("route entry is not NULL for ether_demux\n"));
401 KASSERT((pkt
->dn_flags
& DN_FLAGS_DIR_MASK
) == DN_TO_ETH_DEMUX
,
402 ("wrong direction %d, should be %d\n",
403 (pkt
->dn_flags
& DN_FLAGS_DIR_MASK
), DN_TO_ETH_DEMUX
));
406 unref_priv
= pkt
->dn_unref_priv
;
409 * Make sure that ether header is contiguous
411 if (m
->m_len
< ETHER_HDR_LEN
&&
412 (m
= m_pullup(m
, ETHER_HDR_LEN
)) == NULL
) {
413 kprintf("%s: pullup fail, dropping pkt\n", __func__
);
416 ether_demux(NULL
, m
);
423 ip_dn_ether_output(struct netmsg
*nmsg
)
425 struct netmsg_packet
*nmp
;
429 ip_dn_unref_priv_t unref_priv
;
432 nmp
= (struct netmsg_packet
*)nmsg
;
435 KASSERT(m
->m_pkthdr
.fw_flags
& DUMMYNET_MBUF_TAGGED
,
436 ("mbuf is not tagged for dummynet!\n"));
438 mtag
= m_tag_find(m
, PACKET_TAG_DUMMYNET
, NULL
);
439 KKASSERT(mtag
!= NULL
);
441 pkt
= m_tag_data(mtag
);
442 KASSERT(pkt
->cpuid
== mycpuid
,
443 ("%s: dummynet packet was delivered to wrong cpu! "
444 "target cpuid %d, mycpuid %d\n", __func__
,
445 pkt
->cpuid
, mycpuid
));
446 KASSERT(pkt
->ro
.ro_rt
== NULL
,
447 ("route entry is not NULL for ether_output_frame\n"));
448 KASSERT((pkt
->dn_flags
& DN_FLAGS_DIR_MASK
) == DN_TO_ETH_OUT
,
449 ("wrong direction %d, should be %d\n",
450 (pkt
->dn_flags
& DN_FLAGS_DIR_MASK
), DN_TO_ETH_OUT
));
453 unref_priv
= pkt
->dn_unref_priv
;
455 ether_output_frame(pkt
->ifp
, m
);
462 ip_dn_sockopt_dispatch(struct netmsg
*nmsg
)
464 lwkt_msg
*msg
= &nmsg
->nm_lmsg
;
465 struct dn_sopt
*dn_sopt
= msg
->u
.ms_resultp
;
468 KASSERT(ip_dn_cpu
== mycpuid
,
469 ("%s: dummynet sockopt is done on wrong cpu! "
470 "dummynet cpuid %d, mycpuid %d\n", __func__
,
471 ip_dn_cpu
, mycpuid
));
474 error
= ip_dn_ctl_ptr(dn_sopt
);
477 lwkt_replymsg(msg
, error
);
481 ip_dn_sockopt_flush(struct sockopt
*sopt
)
483 struct dn_sopt dn_sopt
;
486 bzero(&dn_sopt
, sizeof(dn_sopt
));
487 dn_sopt
.dn_sopt_name
= sopt
->sopt_name
;
489 netmsg_init(&smsg
, &curthread
->td_msgport
, 0, ip_dn_sockopt_dispatch
);
490 smsg
.nm_lmsg
.u
.ms_resultp
= &dn_sopt
;
491 lwkt_domsg(cpu_portfn(ip_dn_cpu
), &smsg
.nm_lmsg
, 0);
493 return smsg
.nm_lmsg
.ms_error
;
497 ip_dn_sockopt_get(struct sockopt
*sopt
)
499 struct dn_sopt dn_sopt
;
503 bzero(&dn_sopt
, sizeof(dn_sopt
));
504 dn_sopt
.dn_sopt_name
= sopt
->sopt_name
;
506 netmsg_init(&smsg
, &curthread
->td_msgport
, 0, ip_dn_sockopt_dispatch
);
507 smsg
.nm_lmsg
.u
.ms_resultp
= &dn_sopt
;
508 lwkt_domsg(cpu_portfn(ip_dn_cpu
), &smsg
.nm_lmsg
, 0);
510 error
= smsg
.nm_lmsg
.ms_error
;
512 KKASSERT(dn_sopt
.dn_sopt_arg
== NULL
);
513 KKASSERT(dn_sopt
.dn_sopt_arglen
== 0);
517 soopt_from_kbuf(sopt
, dn_sopt
.dn_sopt_arg
, dn_sopt
.dn_sopt_arglen
);
518 kfree(dn_sopt
.dn_sopt_arg
, M_TEMP
);
523 ip_dn_sockopt_config(struct sockopt
*sopt
)
525 struct dn_ioc_pipe tmp_ioc_pipe
;
526 struct dn_sopt dn_sopt
;
530 error
= soopt_to_kbuf(sopt
, &tmp_ioc_pipe
, sizeof tmp_ioc_pipe
,
531 sizeof tmp_ioc_pipe
);
535 bzero(&dn_sopt
, sizeof(dn_sopt
));
536 dn_sopt
.dn_sopt_name
= sopt
->sopt_name
;
537 dn_sopt
.dn_sopt_arg
= &tmp_ioc_pipe
;
538 dn_sopt
.dn_sopt_arglen
= sizeof(tmp_ioc_pipe
);
540 netmsg_init(&smsg
, &curthread
->td_msgport
, 0, ip_dn_sockopt_dispatch
);
541 smsg
.nm_lmsg
.u
.ms_resultp
= &dn_sopt
;
542 lwkt_domsg(cpu_portfn(ip_dn_cpu
), &smsg
.nm_lmsg
, 0);
544 return smsg
.nm_lmsg
.ms_error
;