- Move vke_softc.sc_kqueue initialization from vke_start() into vke_init()
[dragonfly/port-amd64.git] / sys / dev / virtual / net / if_vke.c
blob55d8d3c9db788fcc501f888aba99ec6e66770a37
1 /*
2 * Copyright (c) 2007 The DragonFly Project. All rights reserved.
3 *
4 * This code is derived from software contributed to The DragonFly Project
5 * by Sepherosa Ziehau <sepherosa@gmail.com>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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
16 * distribution.
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
32 * SUCH DAMAGE.
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>
41 #include <sys/proc.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>
50 #include <net/if.h>
51 #include <net/bpf.h>
52 #include <net/if_arp.h>
53 #include <net/ifq_var.h>
55 #include <netinet/in_var.h>
57 #include <sys/stat.h>
58 #include <sys/ioccom.h>
59 #include <net/tap/if_tap.h>
60 #include <errno.h>
61 #include <stdio.h>
62 #include <string.h>
63 #include <unistd.h>
65 #define VKE_DEVNAME "vke"
67 struct vke_softc {
68 struct arpcom arpcom;
69 int sc_fd;
70 int sc_unit;
72 struct kqueue_info *sc_kqueue;
74 void *sc_txbuf;
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);
95 static void
96 vke_sysinit(void *arg __unused)
98 int i, unit;
100 KASSERT(NetifNum <= VKNETIF_MAX, ("too many netifs: %d\n", NetifNum));
102 unit = 0;
103 for (i = 0; i < NetifNum; ++i) {
104 if (vke_attach(&NetifInfo[i], unit) == 0)
105 ++unit;
108 SYSINIT(vke, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, vke_sysinit, NULL);
110 static void
111 vke_init(void *xsc)
113 struct vke_softc *sc = xsc;
114 struct ifnet *ifp = &sc->arpcom.ac_if;
116 ASSERT_SERIALIZED(ifp->if_serializer);
118 vke_stop(sc);
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;
130 addr = sc->sc_addr;
131 mask = sc->sc_mask;
134 * Make sure vkernel assigned
135 * address will not be added
136 * again.
138 sc->sc_addr = 0;
139 sc->sc_mask = 0;
141 vke_init_addr(ifp, addr, mask);
144 ifp->if_start(ifp);
147 static void
148 vke_start(struct ifnet *ifp)
150 struct vke_softc *sc = ifp->if_softc;
151 struct mbuf *m;
153 ASSERT_SERIALIZED(ifp->if_serializer);
155 if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
156 return;
158 while ((m = ifq_dequeue(&ifp->if_snd, NULL)) != NULL) {
159 m_copydata(m, 0, m->m_pkthdr.len, sc->sc_txbuf);
160 BPF_MTAP(ifp, m);
161 write(sc->sc_fd, sc->sc_txbuf, m->m_pkthdr.len);
162 m_freem(m);
163 ifp->if_opackets++;
167 static int
168 vke_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
170 struct vke_softc *sc = ifp->if_softc;
171 int error = 0;
173 ASSERT_SERIALIZED(ifp->if_serializer);
175 switch (cmd) {
176 case SIOCSIFFLAGS:
177 if (ifp->if_flags & IFF_UP) {
178 if ((ifp->if_flags & IFF_RUNNING) == 0)
179 vke_init(sc);
180 } else {
181 if (ifp->if_flags & IFF_RUNNING)
182 vke_stop(sc);
184 break;
185 case SIOCGIFMEDIA:
186 case SIOCSIFMEDIA:
187 error = EOPNOTSUPP;
188 /* TODO */
189 break;
190 case SIOCGIFSTATUS: {
191 struct ifstat *ifs = (struct ifstat *)data;
192 int len;
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);
199 break;
201 case SIOCSIFADDR:
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.
208 sc->sc_addr = 0;
209 sc->sc_mask = 0;
211 /* FALL THROUGH */
212 default:
213 error = ether_ioctl(ifp, cmd, data);
214 break;
216 return error;
219 static int
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);
227 if (sc->sc_kqueue) {
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;
236 return 0;
239 static void
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)
248 goto back;
250 vke_rxeof(sc);
252 ifp->if_start(ifp);
254 back:
255 lwkt_serialize_exit(ifp->if_serializer);
258 static int
259 vke_rxeof(struct vke_softc *sc)
261 struct ifnet *ifp = &sc->arpcom.ac_if;
262 struct mbuf *m;
264 ASSERT_SERIALIZED(ifp->if_serializer);
266 for (;;) {
267 int n;
269 if (sc->sc_rx_mbuf != NULL) {
270 m = sc->sc_rx_mbuf;
271 sc->sc_rx_mbuf = NULL;
272 } else {
273 m = m_getcl(MB_DONTWAIT, MT_DATA, M_PKTHDR);
274 if (m == NULL)
275 return ENOBUFS;
278 n = read(sc->sc_fd, mtod(m, void *), MCLBYTES);
279 if (n < 0) {
280 sc->sc_rx_mbuf = m; /* We can use it next time */
282 /* TODO: handle fatal error */
283 break;
285 ifp->if_ipackets++;
286 m->m_pkthdr.rcvif = ifp;
287 m->m_pkthdr.len = m->m_len = n;
288 ifp->if_input(ifp, m);
290 return 0;
293 static int
294 vke_attach(const struct vknetif_info *info, int unit)
296 struct vke_softc *sc;
297 struct ifnet *ifp;
298 struct tapinfo tapinfo;
299 uint8_t enaddr[ETHER_ADDR_LEN];
300 int fd;
302 KKASSERT(info->tap_fd >= 0);
303 fd = info->tap_fd;
305 if (ioctl(fd, TAPGIFINFO, &tapinfo) < 0) {
306 kprintf(VKE_DEVNAME "%d: ioctl(TAPGIFINFO) failed: %s\n",
307 unit, strerror(errno));
308 return ENXIO;
311 if (ioctl(fd, SIOCGIFADDR, enaddr) < 0) {
312 kprintf(VKE_DEVNAME "%d: ioctl(SIOCGIFADDR) failed: %s\n",
313 unit, strerror(errno));
314 return ENXIO;
316 enaddr[1] += 1;
318 sc = kmalloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO);
320 sc->sc_txbuf = kmalloc(MCLBYTES, M_DEVBUF, M_WAITOK);
321 sc->sc_fd = fd;
322 sc->sc_unit = unit;
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,
335 CTLFLAG_RD, 0, "");
336 if (sc->sc_sysctl_tree == NULL) {
337 kprintf(VKE_DEVNAME "%d: can't add sysctl node\n", unit);
338 } else {
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");
346 ifp->if_softc = sc;
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);
356 /* TODO: if_media */
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));
366 return 0;
369 static int
370 vke_init_addr(struct ifnet *ifp, in_addr_t addr, in_addr_t mask)
372 struct ifaliasreq ifra;
373 struct sockaddr_in *sin;
374 int ret;
376 ASSERT_SERIALIZED(ifp->if_serializer);
378 if (bootverbose) {
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;
393 if (mask != 0) {
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);
407 return ret;