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.8 2008/08/22 09:14:17 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
;
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,
97 port
= cpu_portfn(ip_dn_cpu
);
98 lwkt_sendmsg(port
, &nmp
->nm_netmsg
.nm_lmsg
);
102 ip_dn_packet_free(struct dn_pkt
*pkt
)
104 struct netmsg_packet
*nmp
;
106 struct mbuf
*m
= pkt
->dn_m
;
109 KASSERT(m
->m_pkthdr
.fw_flags
& DUMMYNET_MBUF_TAGGED
,
110 ("mbuf is not tagged for dummynet!\n"));
112 if (pkt
->cpuid
== mycpuid
) {
117 nmp
= &m
->m_hdr
.mh_netmsg
;
118 netmsg_init(&nmp
->nm_netmsg
, &netisr_apanic_rport
, 0,
119 ip_dn_freepkt_dispatch
);
122 port
= cpu_portfn(pkt
->cpuid
);
123 lwkt_sendmsg(port
, &nmp
->nm_netmsg
.nm_lmsg
);
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
;
138 netisr_fn_t dispatch
;
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
));
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
);
159 port
= cpu_portfn(pkt
->cpuid
);
160 lwkt_sendmsg(port
, &nmp
->nm_netmsg
.nm_lmsg
);
164 ip_dn_sockopt(struct sockopt
*sopt
)
168 /* Disallow sets in really-really secure mode. */
169 if (sopt
->sopt_dir
== SOPT_SET
) {
170 if (securelevel
>= 3)
174 switch (sopt
->sopt_name
) {
175 case IP_DUMMYNET_GET
:
176 error
= ip_dn_sockopt_get(sopt
);
179 case IP_DUMMYNET_FLUSH
:
180 error
= ip_dn_sockopt_flush(sopt
);
183 case IP_DUMMYNET_DEL
:
184 case IP_DUMMYNET_CONFIGURE
:
185 error
= ip_dn_sockopt_config(sopt
);
189 kprintf("%s -- unknown option %d\n", __func__
, sopt
->sopt_name
);
197 ip_dn_freepkt(struct dn_pkt
*pkt
)
199 struct rtentry
*rt
= pkt
->ro
.ro_rt
;
201 /* Unreference route entry */
203 if (rt
->rt_refcnt
<= 0) { /* XXX assert? */
204 kprintf("-- warning, refcnt now %ld, decreasing\n",
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 */
219 ip_dn_freepkt_dispatch(struct netmsg
*nmsg
)
221 struct netmsg_packet
*nmp
;
226 nmp
= (struct netmsg_packet
*)nmsg
;
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
));
245 ip_dn_dispatch(struct netmsg
*nmsg
)
247 struct netmsg_packet
*nmp
;
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
;
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)
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
);
279 ip_dn_ip_output(struct netmsg
*nmsg
)
281 struct netmsg_packet
*nmp
;
286 ip_dn_unref_priv_t unref_priv
;
289 nmp
= (struct netmsg_packet
*)nmsg
;
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
));
308 unref_priv
= pkt
->dn_unref_priv
;
311 if (rt
!= NULL
&& !(rt
->rt_flags
& RTF_UP
)) {
313 * Recorded rtentry is gone, when the packet
320 ip_output(pkt
->dn_m
, NULL
, NULL
, 0, NULL
, NULL
);
323 if (rt
->rt_refcnt
<= 0) { /* XXX assert? */
324 kprintf("-- warning, refcnt now %ld, decreasing\n",
334 ip_dn_ip_input(struct netmsg
*nmsg
)
336 struct netmsg_packet
*nmp
;
340 ip_dn_unref_priv_t unref_priv
;
343 nmp
= (struct netmsg_packet
*)nmsg
;
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
));
364 unref_priv
= pkt
->dn_unref_priv
;
373 ip_dn_ether_demux(struct netmsg
*nmsg
)
375 struct netmsg_packet
*nmp
;
379 ip_dn_unref_priv_t unref_priv
;
382 nmp
= (struct netmsg_packet
*)nmsg
;
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
));
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__
);
413 ether_demux_oncpu(NULL
, m
);
420 ip_dn_ether_output(struct netmsg
*nmsg
)
422 struct netmsg_packet
*nmp
;
426 ip_dn_unref_priv_t unref_priv
;
429 nmp
= (struct netmsg_packet
*)nmsg
;
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
));
450 unref_priv
= pkt
->dn_unref_priv
;
452 ether_output_frame(pkt
->ifp
, m
);
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
;
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
));
471 error
= ip_dn_ctl_ptr(dn_sopt
);
474 lwkt_replymsg(msg
, error
);
478 ip_dn_sockopt_flush(struct sockopt
*sopt
)
480 struct dn_sopt dn_sopt
;
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
;
494 ip_dn_sockopt_get(struct sockopt
*sopt
)
496 struct dn_sopt dn_sopt
;
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
;
509 KKASSERT(dn_sopt
.dn_sopt_arg
== NULL
);
510 KKASSERT(dn_sopt
.dn_sopt_arglen
== 0);
514 soopt_from_kbuf(sopt
, dn_sopt
.dn_sopt_arg
, dn_sopt
.dn_sopt_arglen
);
515 kfree(dn_sopt
.dn_sopt_arg
, M_TEMP
);
520 ip_dn_sockopt_config(struct sockopt
*sopt
)
522 struct dn_ioc_pipe tmp_ioc_pipe
;
523 struct dn_sopt dn_sopt
;
527 error
= soopt_to_kbuf(sopt
, &tmp_ioc_pipe
, sizeof tmp_ioc_pipe
,
528 sizeof tmp_ioc_pipe
);
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
;