vkernel - more crit section work to avoid pthread reentrancy.
[dragonfly.git] / sys / dev / virtual / net / if_vke.c
CommitLineData
d869938c
SW
1/*
2 * Copyright (c) 2007 The DragonFly Project. All rights reserved.
23e684fe 3 *
d869938c
SW
4 * This code is derived from software contributed to The DragonFly Project
5 * by Sepherosa Ziehau <sepherosa@gmail.com>
23e684fe 6 *
d869938c
SW
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
23e684fe 10 *
d869938c
SW
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.
23e684fe 20 *
d869938c
SW
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.
23e684fe 33 *
78422960 34 * $DragonFly: src/sys/dev/virtual/net/if_vke.c,v 1.10 2008/05/27 23:44:46 dillon Exp $
d869938c
SW
35 */
36
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>
d53b52ae 45#include <sys/sysctl.h>
d869938c
SW
46
47#include <machine/md_var.h>
23e684fe 48#include <machine/cothread.h>
d869938c
SW
49
50#include <net/ethernet.h>
51#include <net/if.h>
52#include <net/bpf.h>
53#include <net/if_arp.h>
54#include <net/ifq_var.h>
55
d53b52ae
SZ
56#include <netinet/in_var.h>
57
d869938c 58#include <sys/stat.h>
d869938c 59#include <net/tap/if_tap.h>
23e684fe 60#include <err.h>
d869938c
SW
61#include <errno.h>
62#include <stdio.h>
63#include <string.h>
64#include <unistd.h>
78422960 65#include <fcntl.h>
d869938c 66
d53b52ae
SZ
67#define VKE_DEVNAME "vke"
68
23e684fe
JT
69#define VKE_CHUNK 8 /* number of mbufs to queue before interrupting */
70
71#define NETFIFOSIZE 256
72#define NETFIFOMASK (NETFIFOSIZE -1)
73#define NETFIFOINDEX(u) ((u) & NETFIFOMASK)
74
75#define VKE_COTD_RUN 0
76#define VKE_COTD_EXIT 1
77#define VKE_COTD_DEAD 2
78
79struct vke_fifo {
80 struct mbuf *array[NETFIFOSIZE];
81 int rindex;
82 int windex;
83};
84typedef struct vke_fifo *fifo_t;
85
d869938c 86struct vke_softc {
d53b52ae
SZ
87 struct arpcom arpcom;
88 int sc_fd;
89 int sc_unit;
90
23e684fe
JT
91 cothread_t cotd_tx;
92 cothread_t cotd_rx;
93
94 int cotd_tx_exit;
95 int cotd_rx_exit;
d53b52ae
SZ
96
97 void *sc_txbuf;
23e684fe
JT
98 int sc_txbuf_len;
99
100 fifo_t sc_txfifo;
101 fifo_t sc_txfifo_done;
102 fifo_t sc_rxfifo;
d53b52ae
SZ
103
104 struct sysctl_ctx_list sc_sysctl_ctx;
105 struct sysctl_oid *sc_sysctl_tree;
106
107 int sc_tap_unit; /* unit of backend tap(4) */
108 in_addr_t sc_addr; /* address */
109 in_addr_t sc_mask; /* netmask */
d869938c
SW
110};
111
112static void vke_start(struct ifnet *);
113static void vke_init(void *);
d869938c
SW
114static int vke_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *);
115
d53b52ae 116static int vke_attach(const struct vknetif_info *, int);
d869938c 117static int vke_stop(struct vke_softc *);
d53b52ae 118static int vke_init_addr(struct ifnet *, in_addr_t, in_addr_t);
23e684fe
JT
119static void vke_tx_intr(cothread_t cotd);
120static void vke_tx_thread(cothread_t cotd);
121static void vke_rx_intr(cothread_t cotd);
122static void vke_rx_thread(cothread_t cotd);
123
124static int vke_txfifo_enqueue(struct vke_softc *sc, struct mbuf *m);
125static struct mbuf *vke_txfifo_dequeue(struct vke_softc *sc);
126
127static int vke_txfifo_done_enqueue(struct vke_softc *sc, struct mbuf *m);
128static struct mbuf * vke_txfifo_done_dequeue(struct vke_softc *sc, struct mbuf *nm);
129
130static struct mbuf *vke_rxfifo_dequeue(struct vke_softc *sc, struct mbuf *nm);
131static struct mbuf *vke_rxfifo_sniff(struct vke_softc *sc);
d869938c
SW
132
133static void
134vke_sysinit(void *arg __unused)
135{
d53b52ae 136 int i, unit;
d869938c 137
d53b52ae 138 KASSERT(NetifNum <= VKNETIF_MAX, ("too many netifs: %d\n", NetifNum));
d869938c 139
d53b52ae
SZ
140 unit = 0;
141 for (i = 0; i < NetifNum; ++i) {
142 if (vke_attach(&NetifInfo[i], unit) == 0)
143 ++unit;
d869938c 144 }
d869938c
SW
145}
146SYSINIT(vke, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, vke_sysinit, NULL);
147
23e684fe
JT
148/*
149 * vke_txfifo_done_enqueue() - Add an mbuf to the transmit done fifo. Since
150 * the cothread cannot free transmit mbufs after processing we put them on
151 * the done fifo so the kernel can free them.
152 */
153static int
154vke_txfifo_done_enqueue(struct vke_softc *sc, struct mbuf *m)
155{
156 fifo_t fifo = sc->sc_txfifo_done;
157
158 if (NETFIFOINDEX(fifo->windex + 1) == NETFIFOINDEX(fifo->rindex))
159 return (-1);
160
161 fifo->array[NETFIFOINDEX(fifo->windex)] = m;
162 cpu_sfence();
163 ++fifo->windex;
164 return (0);
165}
166
167/*
168 * vke_txfifo_done_dequeue() - Remove an mbuf from the transmit done fifo.
169 */
170static struct mbuf *
171vke_txfifo_done_dequeue(struct vke_softc *sc, struct mbuf *nm)
172{
173 fifo_t fifo = sc->sc_txfifo_done;
174 struct mbuf *m;
175
176 if (NETFIFOINDEX(fifo->rindex) == NETFIFOINDEX(fifo->windex))
177 return (NULL);
178
179 m = fifo->array[NETFIFOINDEX(fifo->rindex)];
180 fifo->array[NETFIFOINDEX(fifo->rindex)] = nm;
181 cpu_lfence();
182 ++fifo->rindex;
183 return (m);
184}
185
186/*
187 * vke_txfifo_enqueue() - Add an mbuf to the transmit fifo. Wake up the
188 * cothread via cothread_signal().
189 */
190static int
191vke_txfifo_enqueue(struct vke_softc *sc, struct mbuf *m)
192{
193 fifo_t fifo = sc->sc_txfifo;
194 cothread_t cotd = sc->cotd_tx;
195
196 if (NETFIFOINDEX(fifo->windex + 1) == NETFIFOINDEX(fifo->rindex))
197 return (-1);
198
199 fifo->array[NETFIFOINDEX(fifo->windex)] = m;
200 cpu_sfence();
201 cothread_signal(cotd);
202 ++fifo->windex;
203
204 return (0);
205}
206
207/*
208 * vke_txfifo_dequeue() - Return next mbuf on the transmit fifo if one
209 * exists.
210 */
211static struct mbuf *
212vke_txfifo_dequeue(struct vke_softc *sc)
213{
214 fifo_t fifo = sc->sc_txfifo;
215 struct mbuf *m;
216
217 if (NETFIFOINDEX(fifo->rindex) == NETFIFOINDEX(fifo->windex))
218 return (NULL);
219
220 m = fifo->array[NETFIFOINDEX(fifo->rindex)];
221 fifo->array[NETFIFOINDEX(fifo->rindex)] = NULL;
222
223 cpu_lfence();
224 ++fifo->rindex;
225 return (m);
226}
227
228/*
229 * vke_rxfifo_dequeue() - Return next mbuf on the receice fifo if one
230 * exists replacing it with newm which should point to a newly allocated
231 * mbuf.
232 */
233static struct mbuf *
234vke_rxfifo_dequeue(struct vke_softc *sc, struct mbuf *newm)
235{
236 fifo_t fifo = sc->sc_rxfifo;
237 struct mbuf *m;
238
239 if (NETFIFOINDEX(fifo->rindex) == NETFIFOINDEX(fifo->windex))
240 return (NULL);
241
242 m = fifo->array[NETFIFOINDEX(fifo->rindex)];
243 fifo->array[NETFIFOINDEX(fifo->rindex)] = newm;
244 cpu_lfence();
245 ++fifo->rindex;
246 return (m);
247}
248
249/*
250 * Return the next mbuf if available but do NOT remove it from the FIFO.
251 */
252static struct mbuf *
253vke_rxfifo_sniff(struct vke_softc *sc)
254{
255 fifo_t fifo = sc->sc_rxfifo;
256 struct mbuf *m;
257
258 if (NETFIFOINDEX(fifo->rindex) == NETFIFOINDEX(fifo->windex))
259 return (NULL);
260
261 m = fifo->array[NETFIFOINDEX(fifo->rindex)];
262 cpu_lfence();
263 return (m);
264}
265
d869938c
SW
266static void
267vke_init(void *xsc)
268{
269 struct vke_softc *sc = xsc;
270 struct ifnet *ifp = &sc->arpcom.ac_if;
23e684fe 271 int i;
d869938c
SW
272
273 ASSERT_SERIALIZED(ifp->if_serializer);
274
d869938c 275
23e684fe 276 vke_stop(sc);
831e0b9d 277
d869938c
SW
278 ifp->if_flags |= IFF_RUNNING;
279 ifp->if_flags &= ~IFF_OACTIVE;
d869938c 280
d53b52ae
SZ
281 if (sc->sc_addr != 0) {
282 in_addr_t addr, mask;
283
284 addr = sc->sc_addr;
285 mask = sc->sc_mask;
286
287 /*
288 * Make sure vkernel assigned
289 * address will not be added
290 * again.
291 */
292 sc->sc_addr = 0;
293 sc->sc_mask = 0;
294
295 vke_init_addr(ifp, addr, mask);
296 }
297
23e684fe
JT
298 sc->sc_txfifo = kmalloc(sizeof(*sc->sc_txfifo), M_DEVBUF, M_WAITOK);
299 sc->sc_txfifo_done = kmalloc(sizeof(*sc->sc_txfifo_done), M_DEVBUF, M_WAITOK);
300
301 sc->sc_rxfifo = kmalloc(sizeof(*sc->sc_rxfifo), M_DEVBUF, M_WAITOK);
302 for (i = 0; i < NETFIFOSIZE; i++) {
303 sc->sc_rxfifo->array[i] = m_getcl(MB_WAIT, MT_DATA, M_PKTHDR);
304 sc->sc_txfifo->array[i] = NULL;
305 sc->sc_txfifo_done->array[i] = NULL;
306 }
307
308 sc->cotd_tx_exit = sc->cotd_rx_exit = VKE_COTD_RUN;
309 sc->cotd_tx = cothread_create(vke_tx_thread, vke_tx_intr, sc, "vke_tx");
310 sc->cotd_rx = cothread_create(vke_rx_thread, vke_rx_intr, sc, "vke_rx");
d869938c
SW
311}
312
313static void
314vke_start(struct ifnet *ifp)
315{
316 struct vke_softc *sc = ifp->if_softc;
317 struct mbuf *m;
23e684fe
JT
318 cothread_t cotd = sc->cotd_tx;
319 int count;
d869938c
SW
320
321 ASSERT_SERIALIZED(ifp->if_serializer);
322
323 if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
324 return;
325
94131955 326 cothread_lock(cotd, 0);
23e684fe
JT
327 count = 0;
328
f991237f 329 while ((m = ifq_dequeue(&ifp->if_snd, NULL)) != NULL) {
23e684fe
JT
330 if (vke_txfifo_enqueue(sc, m) != -1) {
331 if (count++ == VKE_CHUNK) {
332 cothread_signal(cotd);
333 count = 0;
334 }
17d5d1a9 335 } else {
23e684fe 336 m_freem(m);
17d5d1a9 337 }
d869938c 338 }
23e684fe
JT
339
340 if (count) {
341 cothread_signal(cotd);
342 }
343
94131955 344 cothread_unlock(cotd, 0);
d869938c
SW
345}
346
347static int
348vke_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
349{
350 struct vke_softc *sc = ifp->if_softc;
351 int error = 0;
352
353 ASSERT_SERIALIZED(ifp->if_serializer);
354
355 switch (cmd) {
356 case SIOCSIFFLAGS:
357 if (ifp->if_flags & IFF_UP) {
358 if ((ifp->if_flags & IFF_RUNNING) == 0)
359 vke_init(sc);
360 } else {
361 if (ifp->if_flags & IFF_RUNNING)
362 vke_stop(sc);
363 }
364 break;
365 case SIOCGIFMEDIA:
366 case SIOCSIFMEDIA:
367 error = EOPNOTSUPP;
368 /* TODO */
369 break;
d53b52ae
SZ
370 case SIOCGIFSTATUS: {
371 struct ifstat *ifs = (struct ifstat *)data;
372 int len;
373
374 len = strlen(ifs->ascii);
375 if (len < sizeof(ifs->ascii)) {
376 ksnprintf(ifs->ascii + len, sizeof(ifs->ascii) - len,
377 "\tBacked by tap%d\n", sc->sc_tap_unit);
378 }
379 break;
380 }
381 case SIOCSIFADDR:
382 if (((struct ifaddr *)data)->ifa_addr->sa_family == AF_INET) {
383 /*
384 * If we are explicitly requested to change address,
385 * we should invalidate address/netmask passed in
386 * from vkernel command line.
387 */
388 sc->sc_addr = 0;
389 sc->sc_mask = 0;
390 }
391 /* FALL THROUGH */
d869938c
SW
392 default:
393 error = ether_ioctl(ifp, cmd, data);
394 break;
395 }
396 return error;
397}
398
399static int
400vke_stop(struct vke_softc *sc)
401{
402 struct ifnet *ifp = &sc->arpcom.ac_if;
23e684fe 403 int i;
d869938c
SW
404
405 ASSERT_SERIALIZED(ifp->if_serializer);
406
407 ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
d869938c 408
23e684fe
JT
409 if (sc) {
410 if (sc->cotd_tx) {
94131955 411 cothread_lock(sc->cotd_tx, 0);
23e684fe
JT
412 if (sc->cotd_tx_exit == VKE_COTD_RUN)
413 sc->cotd_tx_exit = VKE_COTD_EXIT;
414 cothread_signal(sc->cotd_tx);
94131955 415 cothread_unlock(sc->cotd_tx, 0);
55bf8f02 416 cothread_delete(&sc->cotd_tx);
23e684fe
JT
417 }
418 if (sc->cotd_rx) {
94131955 419 cothread_lock(sc->cotd_rx, 0);
23e684fe
JT
420 if (sc->cotd_rx_exit == VKE_COTD_RUN)
421 sc->cotd_rx_exit = VKE_COTD_EXIT;
422 cothread_signal(sc->cotd_rx);
94131955 423 cothread_unlock(sc->cotd_rx, 0);
55bf8f02 424 cothread_delete(&sc->cotd_rx);
23e684fe
JT
425 }
426
427 for (i = 0; i < NETFIFOSIZE; i++) {
428 if (sc->sc_rxfifo && sc->sc_rxfifo->array[i]) {
429 m_freem(sc->sc_rxfifo->array[i]);
430 sc->sc_rxfifo->array[i] = NULL;
431 }
432 if (sc->sc_txfifo && sc->sc_txfifo->array[i]) {
433 m_freem(sc->sc_txfifo->array[i]);
434 sc->sc_txfifo->array[i] = NULL;
435 }
436 if (sc->sc_txfifo_done && sc->sc_txfifo_done->array[i]) {
437 m_freem(sc->sc_txfifo_done->array[i]);
438 sc->sc_txfifo_done->array[i] = NULL;
439 }
440 }
441
442 if (sc->sc_txfifo) {
443 kfree(sc->sc_txfifo, M_DEVBUF);
444 sc->sc_txfifo = NULL;
445 }
446
447 if (sc->sc_txfifo_done) {
448 kfree(sc->sc_txfifo_done, M_DEVBUF);
449 sc->sc_txfifo_done = NULL;
450 }
451
452 if (sc->sc_rxfifo) {
453 kfree(sc->sc_rxfifo, M_DEVBUF);
454 sc->sc_rxfifo = NULL;
455 }
d53b52ae 456 }
23e684fe
JT
457
458
d869938c
SW
459 return 0;
460}
461
23e684fe
JT
462/*
463 * vke_rx_intr() is the interrupt function for the receive cothread.
464 */
d869938c 465static void
23e684fe 466vke_rx_intr(cothread_t cotd)
d869938c 467{
23e684fe
JT
468 struct mbuf *m;
469 struct mbuf *nm;
470 struct vke_softc *sc = cotd->arg;
d869938c 471 struct ifnet *ifp = &sc->arpcom.ac_if;
23e684fe 472 static int count = 0;
d869938c 473
a3dd34d2 474 ifnet_serialize_all(ifp);
94131955 475 cothread_lock(cotd, 0);
d869938c 476
23e684fe 477 if (sc->cotd_rx_exit != VKE_COTD_RUN) {
94131955 478 cothread_unlock(cotd, 0);
23e684fe
JT
479 ifnet_deserialize_all(ifp);
480 return;
481 }
d869938c 482
23e684fe
JT
483 while ((m = vke_rxfifo_sniff(sc)) != NULL) {
484 nm = m_getcl(MB_DONTWAIT, MT_DATA, M_PKTHDR);
485 if (nm) {
486 vke_rxfifo_dequeue(sc, nm);
487 ifp->if_input(ifp, m);
488 if (count++ == VKE_CHUNK) {
489 cothread_signal(cotd);
490 count = 0;
491 }
492 } else {
493 vke_rxfifo_dequeue(sc, m);
494 }
495 }
d869938c 496
23e684fe
JT
497 if (count)
498 cothread_signal(cotd);
d869938c 499
94131955 500 cothread_unlock(cotd, 0);
a3dd34d2 501 ifnet_deserialize_all(ifp);
d869938c
SW
502}
503
23e684fe
JT
504/*
505 * vke_tx_intr() is the interrupt function for the transmit cothread.
506 * Calls vke_start() to handle processing transmit mbufs.
507 */
17d5d1a9 508static void
23e684fe 509vke_tx_intr(cothread_t cotd)
d869938c 510{
23e684fe 511 struct vke_softc *sc = cotd->arg;
d869938c
SW
512 struct ifnet *ifp = &sc->arpcom.ac_if;
513 struct mbuf *m;
d869938c 514
23e684fe 515 ifnet_serialize_all(ifp);
94131955 516 cothread_lock(cotd, 0);
23e684fe
JT
517
518 if (sc->cotd_tx_exit != VKE_COTD_RUN) {
94131955 519 cothread_unlock(cotd, 0);
23e684fe
JT
520 ifnet_deserialize_all(ifp);
521 return;
522 }
523
524 if ((ifp->if_flags & IFF_RUNNING) == 0)
525 ifp->if_start(ifp);
526
527 /* Free TX mbufs that have been processed */
528 while ((m = vke_txfifo_done_dequeue(sc, NULL)) != NULL) {
529 m_freem(m);
530 }
531
94131955 532 cothread_unlock(cotd, 0);
23e684fe
JT
533
534 ifnet_deserialize_all(ifp);
535}
536
537/*
538 * vke_rx_thread() is the body of the receive cothread.
539 */
540static void
541vke_rx_thread(cothread_t cotd)
542{
543 struct mbuf *m;
544 struct vke_softc *sc = cotd->arg;
545 struct ifnet *ifp = &sc->arpcom.ac_if;
546 int count;
547 fifo_t fifo = sc->sc_rxfifo;
548 fd_set fdset;
549 struct timeval tv;
550
551 /* Select timeout cannot be infinite since we need to check for
552 * the exit flag sc->cotd_rx_exit.
553 */
554 tv.tv_sec = 0;
555 tv.tv_usec = 500000;
556
557 FD_ZERO(&fdset);
558
94131955 559 cothread_lock(cotd, 1);
d869938c 560
f991237f 561 for (;;) {
d869938c 562 int n;
23e684fe
JT
563 count = 0;
564 while (sc->cotd_rx_exit == VKE_COTD_RUN) {
565 /* Wait for the RX FIFO to drain */
566 while (NETFIFOINDEX(fifo->windex + 1) ==
567 NETFIFOINDEX(fifo->rindex)) {
568 usleep(20000);
569 }
570
571 if ((m = fifo->array[NETFIFOINDEX(fifo->windex)]) !=
572 NULL) {
94131955 573 cothread_unlock(cotd, 1);
23e684fe 574 n = read(sc->sc_fd, mtod(m, void *), MCLBYTES);
94131955 575 cothread_lock(cotd, 1);
55bf8f02 576 if (n <= 0)
23e684fe 577 break;
23e684fe
JT
578 ifp->if_ipackets++;
579 m->m_pkthdr.rcvif = ifp;
580 m->m_pkthdr.len = m->m_len = n;
581 ++fifo->windex;
582 cpu_sfence();
583 if (count++ == VKE_CHUNK) {
584 cothread_intr(cotd);
585 count = 0;
586 }
587 }
588 }
d869938c 589
23e684fe
JT
590 if (count) {
591 cothread_intr(cotd);
d869938c 592 }
23e684fe
JT
593
594 if (sc->cotd_rx_exit != VKE_COTD_RUN)
d869938c 595 break;
23e684fe 596
94131955 597 cothread_unlock(cotd, 1);
23e684fe
JT
598
599 /* Set up data for select() call */
600 FD_SET(sc->sc_fd, &fdset);
601
602 if (select(sc->sc_fd + 1, &fdset, NULL, NULL, &tv) == -1)
603 kprintf(VKE_DEVNAME "%d: select failed for TAP device\n", sc->sc_unit);
604
94131955 605 cothread_lock(cotd, 1);
23e684fe
JT
606 }
607
608 sc->cotd_rx_exit = VKE_COTD_DEAD;
94131955 609 cothread_unlock(cotd, 1);
23e684fe
JT
610}
611
612/*
613 * vke_tx_thread() is the body of the transmit cothread.
614 */
615static void
616vke_tx_thread(cothread_t cotd)
617{
618 struct mbuf *m;
619 struct vke_softc *sc = cotd->arg;
620 struct ifnet *ifp = &sc->arpcom.ac_if;
621 int count = 0;
622
94131955 623 cothread_lock(cotd, 1);
23e684fe
JT
624
625 while (sc->cotd_tx_exit == VKE_COTD_RUN) {
626 /* Write outgoing packets to the TAP interface */
627 while ((m = vke_txfifo_dequeue(sc)) != NULL) {
628 if (m->m_pkthdr.len <= MCLBYTES) {
629 m_copydata(m, 0, m->m_pkthdr.len, sc->sc_txbuf);
630 sc->sc_txbuf_len = m->m_pkthdr.len;
94131955 631 cothread_unlock(cotd, 1);
55bf8f02 632
23e684fe 633 if (write(sc->sc_fd, sc->sc_txbuf, sc->sc_txbuf_len) < 0) {
94131955 634 cothread_lock(cotd, 1);
23e684fe
JT
635 ifp->if_oerrors++;
636 } else {
94131955 637 cothread_lock(cotd, 1);
23e684fe
JT
638 vke_txfifo_done_enqueue(sc, m);
639 ifp->if_opackets++;
640 if (count++ == VKE_CHUNK) {
641 cothread_intr(cotd);
642 count = 0;
643 }
644 }
645 }
d869938c 646 }
23e684fe
JT
647
648 if (count) {
649 cothread_intr(cotd);
17d5d1a9 650 }
23e684fe
JT
651
652 cothread_wait(cotd); /* interlocks cothread lock */
d869938c 653 }
23e684fe
JT
654 /* NOT REACHED */
655 sc->cotd_tx_exit = VKE_COTD_DEAD;
94131955 656 cothread_unlock(cotd, 1);
d869938c 657}
d53b52ae
SZ
658
659static int
660vke_attach(const struct vknetif_info *info, int unit)
661{
662 struct vke_softc *sc;
663 struct ifnet *ifp;
664 struct tapinfo tapinfo;
665 uint8_t enaddr[ETHER_ADDR_LEN];
666 int fd;
667
668 KKASSERT(info->tap_fd >= 0);
669 fd = info->tap_fd;
670
91be174d 671 /*
78422960
MD
672 * This is only a TAP device if tap_unit is non-zero. If
673 * connecting to a virtual socket we generate a unique MAC.
91be174d
MD
674 */
675 if (info->tap_unit >= 0) {
676 if (ioctl(fd, TAPGIFINFO, &tapinfo) < 0) {
677 kprintf(VKE_DEVNAME "%d: ioctl(TAPGIFINFO) "
678 "failed: %s\n", unit, strerror(errno));
679 return ENXIO;
680 }
d53b52ae 681
91be174d
MD
682 if (ioctl(fd, SIOCGIFADDR, enaddr) < 0) {
683 kprintf(VKE_DEVNAME "%d: ioctl(SIOCGIFADDR) "
684 "failed: %s\n", unit, strerror(errno));
685 return ENXIO;
686 }
78422960
MD
687 } else {
688 int fd = open("/dev/urandom", O_RDONLY);
689 if (fd >= 0) {
690 read(fd, enaddr + 2, 4);
691 close(fd);
692 }
693 enaddr[4] = (int)getpid() >> 8;
694 enaddr[5] = (int)getpid() & 255;
23e684fe 695
d53b52ae
SZ
696 }
697 enaddr[1] += 1;
698
699 sc = kmalloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO);
700
701 sc->sc_txbuf = kmalloc(MCLBYTES, M_DEVBUF, M_WAITOK);
702 sc->sc_fd = fd;
703 sc->sc_unit = unit;
704 sc->sc_tap_unit = info->tap_unit;
705 sc->sc_addr = info->netif_addr;
706 sc->sc_mask = info->netif_mask;
d53b52ae
SZ
707
708 ifp = &sc->arpcom.ac_if;
709 if_initname(ifp, VKE_DEVNAME, sc->sc_unit);
710
711 /* NB: after if_initname() */
712 sysctl_ctx_init(&sc->sc_sysctl_ctx);
713 sc->sc_sysctl_tree = SYSCTL_ADD_NODE(&sc->sc_sysctl_ctx,
714 SYSCTL_STATIC_CHILDREN(_hw),
715 OID_AUTO, ifp->if_xname,
716 CTLFLAG_RD, 0, "");
717 if (sc->sc_sysctl_tree == NULL) {
718 kprintf(VKE_DEVNAME "%d: can't add sysctl node\n", unit);
719 } else {
d53b52ae
SZ
720 SYSCTL_ADD_INT(&sc->sc_sysctl_ctx,
721 SYSCTL_CHILDREN(sc->sc_sysctl_tree),
722 OID_AUTO, "tap_unit",
85baaaeb 723 CTLFLAG_RD, &sc->sc_tap_unit, 0,
d53b52ae
SZ
724 "Backend tap(4) unit");
725 }
726
727 ifp->if_softc = sc;
728 ifp->if_ioctl = vke_ioctl;
729 ifp->if_start = vke_start;
730 ifp->if_init = vke_init;
731 ifp->if_mtu = tapinfo.mtu;
732 ifp->if_baudrate = tapinfo.baudrate;
733 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
734 ifq_set_maxlen(&ifp->if_snd, IFQ_MAXLEN);
735 ifq_set_ready(&ifp->if_snd);
736
737 /* TODO: if_media */
738
739 ether_ifattach(ifp, enaddr, NULL);
740
741 if (bootverbose && sc->sc_addr != 0) {
742 if_printf(ifp, "pre-configured "
743 "address 0x%08x, netmask 0x%08x\n",
744 ntohl(sc->sc_addr), ntohl(sc->sc_mask));
745 }
746
747 return 0;
748}
749
750static int
751vke_init_addr(struct ifnet *ifp, in_addr_t addr, in_addr_t mask)
752{
753 struct ifaliasreq ifra;
754 struct sockaddr_in *sin;
755 int ret;
756
757 ASSERT_SERIALIZED(ifp->if_serializer);
758
759 if (bootverbose) {
760 if_printf(ifp, "add pre-configured "
761 "address 0x%08x, netmask 0x%08x\n",
762 ntohl(addr), ntohl(mask));
763 }
764
765 bzero(&ifra, sizeof(ifra));
766
767 /* NB: no need to set ifaliasreq.ifra_name */
768
769 sin = (struct sockaddr_in *)&ifra.ifra_addr;
770 sin->sin_family = AF_INET;
771 sin->sin_len = sizeof(*sin);
772 sin->sin_addr.s_addr = addr;
773
774 if (mask != 0) {
775 sin = (struct sockaddr_in *)&ifra.ifra_mask;
776 sin->sin_len = sizeof(*sin);
777 sin->sin_addr.s_addr = mask;
778 }
779
780 /*
781 * Temporarily release serializer, in_control() will hold
782 * it again before calling ifnet.if_ioctl().
783 */
a3dd34d2 784 ifnet_deserialize_all(ifp);
d53b52ae 785 ret = in_control(NULL, SIOCAIFADDR, (caddr_t)&ifra, ifp, NULL);
a3dd34d2 786 ifnet_serialize_all(ifp);
d53b52ae
SZ
787
788 return ret;
789}