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
35 #include <sys/param.h>
36 #include <sys/kernel.h>
37 #include <sys/malloc.h>
39 #include <sys/msgport.h>
40 #include <sys/socketvar.h>
41 #include <sys/sysctl.h>
44 #include <net/if_var.h>
45 #include <net/route.h>
46 #include <net/ethernet.h>
47 #include <net/netisr2.h>
48 #include <net/netmsg2.h>
50 #include <netinet/in.h>
51 #include <netinet/in_var.h>
52 #include <netinet/ip.h>
53 #include <netinet/ip_var.h>
55 #include <net/dummynet/ip_dummynet.h>
57 static void ip_dn_ether_output(netmsg_t
);
58 static void ip_dn_ether_demux(netmsg_t
);
59 static void ip_dn_ip_input(netmsg_t
);
60 static void ip_dn_ip_output(netmsg_t
);
62 static void ip_dn_sockopt_dispatch(netmsg_t
);
63 static void ip_dn_freepkt_dispatch(netmsg_t
);
64 static void ip_dn_dispatch(netmsg_t
);
66 static void ip_dn_freepkt(struct dn_pkt
*);
68 static int ip_dn_sockopt_flush(struct sockopt
*);
69 static int ip_dn_sockopt_get(struct sockopt
*);
70 static int ip_dn_sockopt_config(struct sockopt
*);
72 ip_dn_io_t
*ip_dn_io_ptr
;
73 ip_dn_ctl_t
*ip_dn_ctl_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!"));
92 nmp
= &m
->m_hdr
.mh_netmsg
;
93 netmsg_init(&nmp
->base
, NULL
, &netisr_apanic_rport
,
97 port
= netisr_cpuport(ip_dn_cpu
);
98 lwkt_sendmsg(port
, &nmp
->base
.lmsg
);
102 ip_dn_packet_free(struct dn_pkt
*pkt
)
104 struct netmsg_packet
*nmp
;
105 struct mbuf
*m
= pkt
->dn_m
;
108 KASSERT(m
->m_pkthdr
.fw_flags
& DUMMYNET_MBUF_TAGGED
,
109 ("mbuf is not tagged for dummynet!"));
111 nmp
= &m
->m_hdr
.mh_netmsg
;
112 netmsg_init(&nmp
->base
, NULL
, &netisr_apanic_rport
,
113 0, ip_dn_freepkt_dispatch
);
116 lwkt_sendmsg(pkt
->msgport
, &nmp
->base
.lmsg
);
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
;
131 netisr_fn_t dispatch
;
134 dir
= (pkt
->dn_flags
& DN_FLAGS_DIR_MASK
);
135 KASSERT(dir
< DN_TO_MAX
,
136 ("unknown dummynet redispatch dir %d", dir
));
138 dispatch
= dispatches
[dir
];
139 KASSERT(dispatch
!= NULL
,
140 ("unsupported dummynet redispatch dir %d", dir
));
144 KASSERT(m
->m_pkthdr
.fw_flags
& DUMMYNET_MBUF_TAGGED
,
145 ("mbuf is not tagged for dummynet!"));
147 nmp
= &m
->m_hdr
.mh_netmsg
;
148 netmsg_init(&nmp
->base
, NULL
, &netisr_apanic_rport
, 0, dispatch
);
151 lwkt_sendmsg(pkt
->msgport
, &nmp
->base
.lmsg
);
155 ip_dn_sockopt(struct sockopt
*sopt
)
159 /* Disallow sets in really-really secure mode. */
160 if (sopt
->sopt_dir
== SOPT_SET
) {
161 if (securelevel
>= 3)
165 switch (sopt
->sopt_name
) {
166 case IP_DUMMYNET_GET
:
167 error
= ip_dn_sockopt_get(sopt
);
170 case IP_DUMMYNET_FLUSH
:
171 error
= ip_dn_sockopt_flush(sopt
);
174 case IP_DUMMYNET_DEL
:
175 case IP_DUMMYNET_CONFIGURE
:
176 error
= ip_dn_sockopt_config(sopt
);
180 kprintf("%s -- unknown option %d\n", __func__
, sopt
->sopt_name
);
188 ip_dn_freepkt(struct dn_pkt
*pkt
)
190 struct rtentry
*rt
= pkt
->ro
.ro_rt
;
192 /* Unreference route entry */
194 if (rt
->rt_refcnt
<= 0) { /* XXX assert? */
195 kprintf("-- warning, refcnt now %ld, decreasing\n",
201 /* Unreference packet private data */
202 if (pkt
->dn_unref_priv
)
203 pkt
->dn_unref_priv(pkt
->dn_priv
);
205 /* Free the parent mbuf, this will free 'pkt' as well */
210 ip_dn_freepkt_dispatch(netmsg_t nmsg
)
212 struct netmsg_packet
*nmp
;
220 KASSERT(m
->m_pkthdr
.fw_flags
& DUMMYNET_MBUF_TAGGED
,
221 ("mbuf is not tagged for dummynet!"));
223 mtag
= m_tag_find(m
, PACKET_TAG_DUMMYNET
, NULL
);
224 KKASSERT(mtag
!= NULL
);
226 pkt
= m_tag_data(mtag
);
227 KASSERT(pkt
->cpuid
== mycpuid
,
228 ("%s: dummynet packet was delivered to wrong cpu! "
229 "target cpuid %d, mycpuid %d", __func__
,
230 pkt
->cpuid
, mycpuid
));
236 ip_dn_dispatch(netmsg_t nmsg
)
238 struct netmsg_packet
*nmp
;
243 KASSERT(ip_dn_cpu
== mycpuid
,
244 ("%s: dummynet packet was delivered to wrong cpu! "
245 "dummynet cpuid %d, mycpuid %d", __func__
,
246 ip_dn_cpu
, mycpuid
));
251 KASSERT(m
->m_pkthdr
.fw_flags
& DUMMYNET_MBUF_TAGGED
,
252 ("mbuf is not tagged for dummynet!"));
254 if (DUMMYNET_LOADED
) {
255 if (ip_dn_io_ptr(m
) == 0)
260 * ip_dn_io_ptr() failed or dummynet(4) is not loaded
262 mtag
= m_tag_find(m
, PACKET_TAG_DUMMYNET
, NULL
);
263 KKASSERT(mtag
!= NULL
);
265 pkt
= m_tag_data(mtag
);
266 ip_dn_packet_free(pkt
);
270 ip_dn_ip_output(netmsg_t nmsg
)
272 struct netmsg_packet
*nmp
;
277 ip_dn_unref_priv_t unref_priv
;
283 KASSERT(m
->m_pkthdr
.fw_flags
& DUMMYNET_MBUF_TAGGED
,
284 ("mbuf is not tagged for dummynet!"));
286 mtag
= m_tag_find(m
, PACKET_TAG_DUMMYNET
, NULL
);
287 KKASSERT(mtag
!= NULL
);
289 pkt
= m_tag_data(mtag
);
290 KASSERT(pkt
->cpuid
== mycpuid
,
291 ("%s: dummynet packet was delivered to wrong cpu! "
292 "target cpuid %d, mycpuid %d", __func__
,
293 pkt
->cpuid
, mycpuid
));
294 KASSERT((pkt
->dn_flags
& DN_FLAGS_DIR_MASK
) == DN_TO_IP_OUT
,
295 ("wrong direction %d, should be %d",
296 (pkt
->dn_flags
& DN_FLAGS_DIR_MASK
), DN_TO_IP_OUT
));
299 unref_priv
= pkt
->dn_unref_priv
;
302 if (rt
!= NULL
&& !(rt
->rt_flags
& RTF_UP
)) {
304 * Recorded rtentry is gone, when the packet
311 ip_output(pkt
->dn_m
, NULL
, NULL
, pkt
->flags
, NULL
, NULL
);
312 /* 'rt' will be freed in ip_output */
319 ip_dn_ip_input(netmsg_t nmsg
)
321 struct netmsg_packet
*nmp
;
325 ip_dn_unref_priv_t unref_priv
;
332 KASSERT(m
->m_pkthdr
.fw_flags
& DUMMYNET_MBUF_TAGGED
,
333 ("mbuf is not tagged for dummynet!"));
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", __func__
,
342 pkt
->cpuid
, mycpuid
));
343 KASSERT(pkt
->ro
.ro_rt
== NULL
,
344 ("route entry is not NULL for ip_input"));
345 KASSERT((pkt
->dn_flags
& DN_FLAGS_DIR_MASK
) == DN_TO_IP_IN
,
346 ("wrong direction %d, should be %d",
347 (pkt
->dn_flags
& DN_FLAGS_DIR_MASK
), DN_TO_IP_IN
));
350 unref_priv
= pkt
->dn_unref_priv
;
352 KKASSERT(m
->m_len
>= sizeof(*ip
));
361 ip_dn_ether_demux(netmsg_t nmsg
)
363 struct netmsg_packet
*nmp
;
367 ip_dn_unref_priv_t unref_priv
;
373 KASSERT(m
->m_pkthdr
.fw_flags
& DUMMYNET_MBUF_TAGGED
,
374 ("mbuf is not tagged for dummynet!"));
376 mtag
= m_tag_find(m
, PACKET_TAG_DUMMYNET
, NULL
);
377 KKASSERT(mtag
!= NULL
);
379 pkt
= m_tag_data(mtag
);
380 KASSERT(pkt
->cpuid
== mycpuid
,
381 ("%s: dummynet packet was delivered to wrong cpu! "
382 "target cpuid %d, mycpuid %d", __func__
,
383 pkt
->cpuid
, mycpuid
));
384 KASSERT(pkt
->ro
.ro_rt
== NULL
,
385 ("route entry is not NULL for ether_demux"));
386 KASSERT((pkt
->dn_flags
& DN_FLAGS_DIR_MASK
) == DN_TO_ETH_DEMUX
,
387 ("wrong direction %d, should be %d",
388 (pkt
->dn_flags
& DN_FLAGS_DIR_MASK
), DN_TO_ETH_DEMUX
));
391 unref_priv
= pkt
->dn_unref_priv
;
394 * Make sure that ether header is contiguous
396 if (m
->m_len
< ETHER_HDR_LEN
&&
397 (m
= m_pullup(m
, ETHER_HDR_LEN
)) == NULL
) {
398 kprintf("%s: pullup fail, dropping pkt\n", __func__
);
401 ether_demux_oncpu(m
->m_pkthdr
.rcvif
, m
);
408 ip_dn_ether_output(netmsg_t nmsg
)
410 struct netmsg_packet
*nmp
;
414 ip_dn_unref_priv_t unref_priv
;
420 KASSERT(m
->m_pkthdr
.fw_flags
& DUMMYNET_MBUF_TAGGED
,
421 ("mbuf is not tagged for dummynet!"));
423 mtag
= m_tag_find(m
, PACKET_TAG_DUMMYNET
, NULL
);
424 KKASSERT(mtag
!= NULL
);
426 pkt
= m_tag_data(mtag
);
427 KASSERT(pkt
->cpuid
== mycpuid
,
428 ("%s: dummynet packet was delivered to wrong cpu! "
429 "target cpuid %d, mycpuid %d", __func__
,
430 pkt
->cpuid
, mycpuid
));
431 KASSERT(pkt
->ro
.ro_rt
== NULL
,
432 ("route entry is not NULL for ether_output_frame"));
433 KASSERT((pkt
->dn_flags
& DN_FLAGS_DIR_MASK
) == DN_TO_ETH_OUT
,
434 ("wrong direction %d, should be %d",
435 (pkt
->dn_flags
& DN_FLAGS_DIR_MASK
), DN_TO_ETH_OUT
));
438 unref_priv
= pkt
->dn_unref_priv
;
440 ether_output_frame(pkt
->ifp
, m
);
447 ip_dn_sockopt_dispatch(netmsg_t nmsg
)
449 lwkt_msg
*msg
= &nmsg
->lmsg
;
450 struct dn_sopt
*dn_sopt
= msg
->u
.ms_resultp
;
453 KASSERT(ip_dn_cpu
== mycpuid
,
454 ("%s: dummynet sockopt is done on wrong cpu! "
455 "dummynet cpuid %d, mycpuid %d", __func__
,
456 ip_dn_cpu
, mycpuid
));
459 error
= ip_dn_ctl_ptr(dn_sopt
);
462 lwkt_replymsg(msg
, error
);
466 ip_dn_sockopt_flush(struct sockopt
*sopt
)
468 struct dn_sopt dn_sopt
;
469 struct netmsg_base smsg
;
471 bzero(&dn_sopt
, sizeof(dn_sopt
));
472 dn_sopt
.dn_sopt_name
= sopt
->sopt_name
;
474 netmsg_init(&smsg
, NULL
, &curthread
->td_msgport
,
475 0, ip_dn_sockopt_dispatch
);
476 smsg
.lmsg
.u
.ms_resultp
= &dn_sopt
;
477 lwkt_domsg(netisr_cpuport(ip_dn_cpu
), &smsg
.lmsg
, 0);
479 return smsg
.lmsg
.ms_error
;
483 ip_dn_sockopt_get(struct sockopt
*sopt
)
485 struct dn_sopt dn_sopt
;
486 struct netmsg_base smsg
;
489 bzero(&dn_sopt
, sizeof(dn_sopt
));
490 dn_sopt
.dn_sopt_name
= sopt
->sopt_name
;
492 netmsg_init(&smsg
, NULL
, &curthread
->td_msgport
,
493 0, ip_dn_sockopt_dispatch
);
494 smsg
.lmsg
.u
.ms_resultp
= &dn_sopt
;
495 lwkt_domsg(netisr_cpuport(ip_dn_cpu
), &smsg
.lmsg
, 0);
497 error
= smsg
.lmsg
.ms_error
;
499 KKASSERT(dn_sopt
.dn_sopt_arg
== NULL
);
500 KKASSERT(dn_sopt
.dn_sopt_arglen
== 0);
504 soopt_from_kbuf(sopt
, dn_sopt
.dn_sopt_arg
, dn_sopt
.dn_sopt_arglen
);
505 kfree(dn_sopt
.dn_sopt_arg
, M_TEMP
);
510 ip_dn_sockopt_config(struct sockopt
*sopt
)
512 struct dn_ioc_pipe tmp_ioc_pipe
;
513 struct dn_sopt dn_sopt
;
514 struct netmsg_base smsg
;
517 error
= soopt_to_kbuf(sopt
, &tmp_ioc_pipe
, sizeof tmp_ioc_pipe
,
518 sizeof tmp_ioc_pipe
);
522 bzero(&dn_sopt
, sizeof(dn_sopt
));
523 dn_sopt
.dn_sopt_name
= sopt
->sopt_name
;
524 dn_sopt
.dn_sopt_arg
= &tmp_ioc_pipe
;
525 dn_sopt
.dn_sopt_arglen
= sizeof(tmp_ioc_pipe
);
527 netmsg_init(&smsg
, NULL
, &curthread
->td_msgport
,
528 0, ip_dn_sockopt_dispatch
);
529 smsg
.lmsg
.u
.ms_resultp
= &dn_sopt
;
530 lwkt_domsg(netisr_cpuport(ip_dn_cpu
), &smsg
.lmsg
, 0);
532 return smsg
.lmsg
.ms_error
;