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.11 2008/09/20 04:36:51 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
, NULL
, &netisr_apanic_rport
,
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
;
105 struct mbuf
*m
= pkt
->dn_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
);
116 lwkt_sendmsg(pkt
->msgport
, &nmp
->nm_netmsg
.nm_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\n", dir
));
138 dispatch
= dispatches
[dir
];
139 KASSERT(dispatch
!= NULL
,
140 ("unsupported dummynet redispatch dir %d\n", dir
));
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
,
152 lwkt_sendmsg(pkt
->msgport
, &nmp
->nm_netmsg
.nm_lmsg
);
156 ip_dn_sockopt(struct sockopt
*sopt
)
160 /* Disallow sets in really-really secure mode. */
161 if (sopt
->sopt_dir
== SOPT_SET
) {
162 if (securelevel
>= 3)
166 switch (sopt
->sopt_name
) {
167 case IP_DUMMYNET_GET
:
168 error
= ip_dn_sockopt_get(sopt
);
171 case IP_DUMMYNET_FLUSH
:
172 error
= ip_dn_sockopt_flush(sopt
);
175 case IP_DUMMYNET_DEL
:
176 case IP_DUMMYNET_CONFIGURE
:
177 error
= ip_dn_sockopt_config(sopt
);
181 kprintf("%s -- unknown option %d\n", __func__
, sopt
->sopt_name
);
189 ip_dn_freepkt(struct dn_pkt
*pkt
)
191 struct rtentry
*rt
= pkt
->ro
.ro_rt
;
193 /* Unreference route entry */
195 if (rt
->rt_refcnt
<= 0) { /* XXX assert? */
196 kprintf("-- warning, refcnt now %ld, decreasing\n",
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 */
211 ip_dn_freepkt_dispatch(struct netmsg
*nmsg
)
213 struct netmsg_packet
*nmp
;
218 nmp
= (struct netmsg_packet
*)nmsg
;
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
));
237 ip_dn_dispatch(struct netmsg
*nmsg
)
239 struct netmsg_packet
*nmp
;
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
;
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)
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
);
271 ip_dn_ip_output(struct netmsg
*nmsg
)
273 struct netmsg_packet
*nmp
;
278 ip_dn_unref_priv_t unref_priv
;
281 nmp
= (struct netmsg_packet
*)nmsg
;
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
));
300 unref_priv
= pkt
->dn_unref_priv
;
303 if (rt
!= NULL
&& !(rt
->rt_flags
& RTF_UP
)) {
305 * Recorded rtentry is gone, when the packet
312 ip_output(pkt
->dn_m
, NULL
, NULL
, pkt
->flags
, NULL
, NULL
);
313 /* 'rt' will be freed in ip_output */
320 ip_dn_ip_input(struct netmsg
*nmsg
)
322 struct netmsg_packet
*nmp
;
326 ip_dn_unref_priv_t unref_priv
;
329 nmp
= (struct netmsg_packet
*)nmsg
;
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
));
350 unref_priv
= pkt
->dn_unref_priv
;
359 ip_dn_ether_demux(struct netmsg
*nmsg
)
361 struct netmsg_packet
*nmp
;
365 ip_dn_unref_priv_t unref_priv
;
368 nmp
= (struct netmsg_packet
*)nmsg
;
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
));
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__
);
399 ether_demux_oncpu(m
->m_pkthdr
.rcvif
, m
);
406 ip_dn_ether_output(struct netmsg
*nmsg
)
408 struct netmsg_packet
*nmp
;
412 ip_dn_unref_priv_t unref_priv
;
415 nmp
= (struct netmsg_packet
*)nmsg
;
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
));
436 unref_priv
= pkt
->dn_unref_priv
;
438 ether_output_frame(pkt
->ifp
, m
);
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
;
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
));
457 error
= ip_dn_ctl_ptr(dn_sopt
);
460 lwkt_replymsg(msg
, error
);
464 ip_dn_sockopt_flush(struct sockopt
*sopt
)
466 struct dn_sopt dn_sopt
;
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
;
481 ip_dn_sockopt_get(struct sockopt
*sopt
)
483 struct dn_sopt dn_sopt
;
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
;
497 KKASSERT(dn_sopt
.dn_sopt_arg
== NULL
);
498 KKASSERT(dn_sopt
.dn_sopt_arglen
== 0);
502 soopt_from_kbuf(sopt
, dn_sopt
.dn_sopt_arg
, dn_sopt
.dn_sopt_arglen
);
503 kfree(dn_sopt
.dn_sopt_arg
, M_TEMP
);
508 ip_dn_sockopt_config(struct sockopt
*sopt
)
510 struct dn_ioc_pipe tmp_ioc_pipe
;
511 struct dn_sopt dn_sopt
;
515 error
= soopt_to_kbuf(sopt
, &tmp_ioc_pipe
, sizeof tmp_ioc_pipe
,
516 sizeof tmp_ioc_pipe
);
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
;