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/dev/virtual/net/if_vke.c,v 1.5 2007/02/10 11:32:39 sephe Exp $
37 #include <sys/param.h>
38 #include <sys/endian.h>
39 #include <sys/kernel.h>
40 #include <sys/malloc.h>
42 #include <sys/serialize.h>
43 #include <sys/socket.h>
44 #include <sys/sockio.h>
45 #include <sys/sysctl.h>
47 #include <machine/md_var.h>
49 #include <net/ethernet.h>
52 #include <net/if_arp.h>
53 #include <net/ifq_var.h>
55 #include <netinet/in_var.h>
58 #include <sys/ioccom.h>
59 #include <net/tap/if_tap.h>
65 #define VKE_DEVNAME "vke"
72 struct kqueue_info
*sc_kqueue
;
75 struct mbuf
*sc_rx_mbuf
;
77 struct sysctl_ctx_list sc_sysctl_ctx
;
78 struct sysctl_oid
*sc_sysctl_tree
;
80 int sc_tap_unit
; /* unit of backend tap(4) */
81 in_addr_t sc_addr
; /* address */
82 in_addr_t sc_mask
; /* netmask */
85 static void vke_start(struct ifnet
*);
86 static void vke_init(void *);
87 static int vke_ioctl(struct ifnet
*, u_long
, caddr_t
, struct ucred
*);
89 static int vke_attach(const struct vknetif_info
*, int);
90 static void vke_intr(void *, struct intrframe
*);
91 static int vke_stop(struct vke_softc
*);
92 static int vke_rxeof(struct vke_softc
*);
93 static int vke_init_addr(struct ifnet
*, in_addr_t
, in_addr_t
);
96 vke_sysinit(void *arg __unused
)
100 KASSERT(NetifNum
<= VKNETIF_MAX
, ("too many netifs: %d\n", NetifNum
));
103 for (i
= 0; i
< NetifNum
; ++i
) {
104 if (vke_attach(&NetifInfo
[i
], unit
) == 0)
108 SYSINIT(vke
, SI_SUB_DRIVERS
, SI_ORDER_MIDDLE
, vke_sysinit
, NULL
);
113 struct vke_softc
*sc
= xsc
;
114 struct ifnet
*ifp
= &sc
->arpcom
.ac_if
;
116 ASSERT_SERIALIZED(ifp
->if_serializer
);
120 KKASSERT(sc
->sc_kqueue
== NULL
);
121 sc
->sc_kqueue
= kqueue_add(sc
->sc_fd
, vke_intr
, sc
);
122 KKASSERT(sc
->sc_kqueue
!= NULL
);
124 ifp
->if_flags
|= IFF_RUNNING
;
125 ifp
->if_flags
&= ~IFF_OACTIVE
;
127 if (sc
->sc_addr
!= 0) {
128 in_addr_t addr
, mask
;
134 * Make sure vkernel assigned
135 * address will not be added
141 vke_init_addr(ifp
, addr
, mask
);
148 vke_start(struct ifnet
*ifp
)
150 struct vke_softc
*sc
= ifp
->if_softc
;
153 ASSERT_SERIALIZED(ifp
->if_serializer
);
155 if ((ifp
->if_flags
& (IFF_RUNNING
| IFF_OACTIVE
)) != IFF_RUNNING
)
158 while ((m
= ifq_dequeue(&ifp
->if_snd
, NULL
)) != NULL
) {
159 m_copydata(m
, 0, m
->m_pkthdr
.len
, sc
->sc_txbuf
);
161 write(sc
->sc_fd
, sc
->sc_txbuf
, m
->m_pkthdr
.len
);
168 vke_ioctl(struct ifnet
*ifp
, u_long cmd
, caddr_t data
, struct ucred
*cr
)
170 struct vke_softc
*sc
= ifp
->if_softc
;
173 ASSERT_SERIALIZED(ifp
->if_serializer
);
177 if (ifp
->if_flags
& IFF_UP
) {
178 if ((ifp
->if_flags
& IFF_RUNNING
) == 0)
181 if (ifp
->if_flags
& IFF_RUNNING
)
190 case SIOCGIFSTATUS
: {
191 struct ifstat
*ifs
= (struct ifstat
*)data
;
194 len
= strlen(ifs
->ascii
);
195 if (len
< sizeof(ifs
->ascii
)) {
196 ksnprintf(ifs
->ascii
+ len
, sizeof(ifs
->ascii
) - len
,
197 "\tBacked by tap%d\n", sc
->sc_tap_unit
);
202 if (((struct ifaddr
*)data
)->ifa_addr
->sa_family
== AF_INET
) {
204 * If we are explicitly requested to change address,
205 * we should invalidate address/netmask passed in
206 * from vkernel command line.
213 error
= ether_ioctl(ifp
, cmd
, data
);
220 vke_stop(struct vke_softc
*sc
)
222 struct ifnet
*ifp
= &sc
->arpcom
.ac_if
;
224 ASSERT_SERIALIZED(ifp
->if_serializer
);
226 ifp
->if_flags
&= ~(IFF_RUNNING
| IFF_OACTIVE
);
228 kqueue_del(sc
->sc_kqueue
);
229 sc
->sc_kqueue
= NULL
;
232 if (sc
->sc_rx_mbuf
!= NULL
) {
233 m_freem(sc
->sc_rx_mbuf
);
234 sc
->sc_rx_mbuf
= NULL
;
240 vke_intr(void *xsc
, struct intrframe
*frame __unused
)
242 struct vke_softc
*sc
= xsc
;
243 struct ifnet
*ifp
= &sc
->arpcom
.ac_if
;
245 lwkt_serialize_enter(ifp
->if_serializer
);
247 if ((ifp
->if_flags
& IFF_RUNNING
) == 0)
255 lwkt_serialize_exit(ifp
->if_serializer
);
259 vke_rxeof(struct vke_softc
*sc
)
261 struct ifnet
*ifp
= &sc
->arpcom
.ac_if
;
264 ASSERT_SERIALIZED(ifp
->if_serializer
);
269 if (sc
->sc_rx_mbuf
!= NULL
) {
271 sc
->sc_rx_mbuf
= NULL
;
273 m
= m_getcl(MB_DONTWAIT
, MT_DATA
, M_PKTHDR
);
278 n
= read(sc
->sc_fd
, mtod(m
, void *), MCLBYTES
);
280 sc
->sc_rx_mbuf
= m
; /* We can use it next time */
282 /* TODO: handle fatal error */
286 m
->m_pkthdr
.rcvif
= ifp
;
287 m
->m_pkthdr
.len
= m
->m_len
= n
;
288 ifp
->if_input(ifp
, m
);
294 vke_attach(const struct vknetif_info
*info
, int unit
)
296 struct vke_softc
*sc
;
298 struct tapinfo tapinfo
;
299 uint8_t enaddr
[ETHER_ADDR_LEN
];
302 KKASSERT(info
->tap_fd
>= 0);
305 if (ioctl(fd
, TAPGIFINFO
, &tapinfo
) < 0) {
306 kprintf(VKE_DEVNAME
"%d: ioctl(TAPGIFINFO) failed: %s\n",
307 unit
, strerror(errno
));
311 if (ioctl(fd
, SIOCGIFADDR
, enaddr
) < 0) {
312 kprintf(VKE_DEVNAME
"%d: ioctl(SIOCGIFADDR) failed: %s\n",
313 unit
, strerror(errno
));
318 sc
= kmalloc(sizeof(*sc
), M_DEVBUF
, M_WAITOK
| M_ZERO
);
320 sc
->sc_txbuf
= kmalloc(MCLBYTES
, M_DEVBUF
, M_WAITOK
);
323 sc
->sc_tap_unit
= info
->tap_unit
;
324 sc
->sc_addr
= info
->netif_addr
;
325 sc
->sc_mask
= info
->netif_mask
;
327 ifp
= &sc
->arpcom
.ac_if
;
328 if_initname(ifp
, VKE_DEVNAME
, sc
->sc_unit
);
330 /* NB: after if_initname() */
331 sysctl_ctx_init(&sc
->sc_sysctl_ctx
);
332 sc
->sc_sysctl_tree
= SYSCTL_ADD_NODE(&sc
->sc_sysctl_ctx
,
333 SYSCTL_STATIC_CHILDREN(_hw
),
334 OID_AUTO
, ifp
->if_xname
,
336 if (sc
->sc_sysctl_tree
== NULL
) {
337 kprintf(VKE_DEVNAME
"%d: can't add sysctl node\n", unit
);
339 SYSCTL_ADD_INT(&sc
->sc_sysctl_ctx
,
340 SYSCTL_CHILDREN(sc
->sc_sysctl_tree
),
341 OID_AUTO
, "tap_unit",
342 CTLFLAG_RW
, &sc
->sc_tap_unit
, 0,
343 "Backend tap(4) unit");
347 ifp
->if_ioctl
= vke_ioctl
;
348 ifp
->if_start
= vke_start
;
349 ifp
->if_init
= vke_init
;
350 ifp
->if_mtu
= tapinfo
.mtu
;
351 ifp
->if_baudrate
= tapinfo
.baudrate
;
352 ifp
->if_flags
= IFF_BROADCAST
| IFF_SIMPLEX
| IFF_MULTICAST
;
353 ifq_set_maxlen(&ifp
->if_snd
, IFQ_MAXLEN
);
354 ifq_set_ready(&ifp
->if_snd
);
358 ether_ifattach(ifp
, enaddr
, NULL
);
360 if (bootverbose
&& sc
->sc_addr
!= 0) {
361 if_printf(ifp
, "pre-configured "
362 "address 0x%08x, netmask 0x%08x\n",
363 ntohl(sc
->sc_addr
), ntohl(sc
->sc_mask
));
370 vke_init_addr(struct ifnet
*ifp
, in_addr_t addr
, in_addr_t mask
)
372 struct ifaliasreq ifra
;
373 struct sockaddr_in
*sin
;
376 ASSERT_SERIALIZED(ifp
->if_serializer
);
379 if_printf(ifp
, "add pre-configured "
380 "address 0x%08x, netmask 0x%08x\n",
381 ntohl(addr
), ntohl(mask
));
384 bzero(&ifra
, sizeof(ifra
));
386 /* NB: no need to set ifaliasreq.ifra_name */
388 sin
= (struct sockaddr_in
*)&ifra
.ifra_addr
;
389 sin
->sin_family
= AF_INET
;
390 sin
->sin_len
= sizeof(*sin
);
391 sin
->sin_addr
.s_addr
= addr
;
394 sin
= (struct sockaddr_in
*)&ifra
.ifra_mask
;
395 sin
->sin_len
= sizeof(*sin
);
396 sin
->sin_addr
.s_addr
= mask
;
400 * Temporarily release serializer, in_control() will hold
401 * it again before calling ifnet.if_ioctl().
403 lwkt_serialize_exit(ifp
->if_serializer
);
404 ret
= in_control(NULL
, SIOCAIFADDR
, (caddr_t
)&ifra
, ifp
, NULL
);
405 lwkt_serialize_enter(ifp
->if_serializer
);