Merge from vendor branch LIBARCHIVE:
[dragonfly.git] / sys / dev / virtual / net / if_vke.c
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:
10  * 
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.
20  * 
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.
33  * 
34  * $DragonFly: src/sys/dev/virtual/net/if_vke.c,v 1.10 2008/05/27 23:44:46 dillon Exp $
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>
45 #include <sys/sysctl.h>
46
47 #include <machine/md_var.h>
48
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>
54
55 #include <netinet/in_var.h>
56
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>
64 #include <fcntl.h>
65
66 #define VKE_DEVNAME             "vke"
67
68 struct vke_softc {
69         struct arpcom           arpcom;
70         int                     sc_fd;
71         int                     sc_unit;
72
73         struct kqueue_info      *sc_kqueue;
74
75         void                    *sc_txbuf;
76         struct mbuf             *sc_rx_mbuf;
77
78         struct sysctl_ctx_list  sc_sysctl_ctx;
79         struct sysctl_oid       *sc_sysctl_tree;
80
81         int                     sc_tap_unit;    /* unit of backend tap(4) */
82         in_addr_t               sc_addr;        /* address */
83         in_addr_t               sc_mask;        /* netmask */
84 };
85
86 static void     vke_start(struct ifnet *);
87 static void     vke_init(void *);
88 static int      vke_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *);
89
90 static int      vke_attach(const struct vknetif_info *, int);
91 static void     vke_intr(void *, struct intrframe *);
92 static int      vke_stop(struct vke_softc *);
93 static void     vke_rxeof(struct vke_softc *);
94 static int      vke_init_addr(struct ifnet *, in_addr_t, in_addr_t);
95
96 static void
97 vke_sysinit(void *arg __unused)
98 {
99         int i, unit;
100
101         KASSERT(NetifNum <= VKNETIF_MAX, ("too many netifs: %d\n", NetifNum));
102
103         unit = 0;
104         for (i = 0; i < NetifNum; ++i) {
105                 if (vke_attach(&NetifInfo[i], unit) == 0)
106                         ++unit;
107         }
108 }
109 SYSINIT(vke, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, vke_sysinit, NULL);
110
111 static void
112 vke_init(void *xsc)
113 {
114         struct vke_softc *sc = xsc;
115         struct ifnet *ifp = &sc->arpcom.ac_if;
116
117         ASSERT_SERIALIZED(ifp->if_serializer);
118
119         vke_stop(sc);
120
121         KKASSERT(sc->sc_kqueue == NULL);
122         sc->sc_kqueue = kqueue_add(sc->sc_fd, vke_intr, sc);
123         KKASSERT(sc->sc_kqueue != NULL);
124
125         ifp->if_flags |= IFF_RUNNING;
126         ifp->if_flags &= ~IFF_OACTIVE;
127
128         if (sc->sc_addr != 0) {
129                 in_addr_t addr, mask;
130
131                 addr = sc->sc_addr;
132                 mask = sc->sc_mask;
133
134                 /*
135                  * Make sure vkernel assigned
136                  * address will not be added
137                  * again.
138                  */
139                 sc->sc_addr = 0;
140                 sc->sc_mask = 0;
141
142                 vke_init_addr(ifp, addr, mask);
143         }
144
145         ifp->if_start(ifp);
146 }
147
148 static void
149 vke_start(struct ifnet *ifp)
150 {
151         struct vke_softc *sc = ifp->if_softc;
152         struct mbuf *m;
153
154         ASSERT_SERIALIZED(ifp->if_serializer);
155
156         if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
157                 return;
158
159         while ((m = ifq_dequeue(&ifp->if_snd, NULL)) != NULL) {
160                 /*
161                  * Copy the data into a single mbuf and write it out
162                  * non-blocking.
163                  */
164                 if (m->m_pkthdr.len <= MCLBYTES) {
165                         m_copydata(m, 0, m->m_pkthdr.len, sc->sc_txbuf);
166                         BPF_MTAP(ifp, m);
167                         if (write(sc->sc_fd, sc->sc_txbuf, m->m_pkthdr.len) < 0)
168                                 ifp->if_oerrors++;
169                         else
170                                 ifp->if_opackets++;
171                 } else {
172                         ifp->if_oerrors++;
173                 }
174                 m_freem(m);
175         }
176 }
177
178 static int
179 vke_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
180 {
181         struct vke_softc *sc = ifp->if_softc;
182         int error = 0;
183
184         ASSERT_SERIALIZED(ifp->if_serializer);
185
186         switch (cmd) {
187         case SIOCSIFFLAGS:
188                 if (ifp->if_flags & IFF_UP) {
189                         if ((ifp->if_flags & IFF_RUNNING) == 0)
190                                 vke_init(sc);
191                 } else {
192                         if (ifp->if_flags & IFF_RUNNING)
193                                 vke_stop(sc);
194                 }
195                 break;
196         case SIOCGIFMEDIA:
197         case SIOCSIFMEDIA:
198                 error = EOPNOTSUPP;
199                 /* TODO */
200                 break;
201         case SIOCGIFSTATUS: {
202                 struct ifstat *ifs = (struct ifstat *)data;
203                 int len;
204
205                 len = strlen(ifs->ascii);
206                 if (len < sizeof(ifs->ascii)) {
207                         ksnprintf(ifs->ascii + len, sizeof(ifs->ascii) - len,
208                                   "\tBacked by tap%d\n", sc->sc_tap_unit);
209                 }
210                 break;
211         }
212         case SIOCSIFADDR:
213                 if (((struct ifaddr *)data)->ifa_addr->sa_family == AF_INET) {
214                         /*
215                          * If we are explicitly requested to change address,
216                          * we should invalidate address/netmask passed in
217                          * from vkernel command line.
218                          */
219                         sc->sc_addr = 0;
220                         sc->sc_mask = 0;
221                 }
222                 /* FALL THROUGH */
223         default:
224                 error = ether_ioctl(ifp, cmd, data);
225                 break;
226         }
227         return error;
228 }
229
230 static int
231 vke_stop(struct vke_softc *sc)
232 {
233         struct ifnet *ifp = &sc->arpcom.ac_if;
234
235         ASSERT_SERIALIZED(ifp->if_serializer);
236
237         ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
238         if (sc->sc_kqueue) {
239                 kqueue_del(sc->sc_kqueue);
240                 sc->sc_kqueue = NULL;
241         }
242
243         if (sc->sc_rx_mbuf != NULL) {
244                 m_freem(sc->sc_rx_mbuf);
245                 sc->sc_rx_mbuf = NULL;
246         }
247         return 0;
248 }
249
250 static void
251 vke_intr(void *xsc, struct intrframe *frame __unused)
252 {
253         struct vke_softc *sc = xsc;
254         struct ifnet *ifp = &sc->arpcom.ac_if;
255
256         lwkt_serialize_enter(ifp->if_serializer);
257
258         if ((ifp->if_flags & IFF_RUNNING) == 0)
259                 goto back;
260
261         vke_rxeof(sc);
262
263         ifp->if_start(ifp);
264
265 back:
266         lwkt_serialize_exit(ifp->if_serializer);
267 }
268
269 static void
270 vke_rxeof(struct vke_softc *sc)
271 {
272         struct ifnet *ifp = &sc->arpcom.ac_if;
273         struct mbuf *m;
274
275         ASSERT_SERIALIZED(ifp->if_serializer);
276
277         for (;;) {
278                 int n;
279
280                 /*
281                  * Try to get an mbuf
282                  */
283                 if ((m = sc->sc_rx_mbuf) == NULL)
284                         m = m_getcl(MB_DONTWAIT, MT_DATA, M_PKTHDR);
285                 else
286                         sc->sc_rx_mbuf = NULL;
287
288                 /*
289                  * Drain the interface whether we get an mbuf or not or
290                  * we might stop receiving interrupts.
291                  */
292                 if (m) {
293                         n = read(sc->sc_fd, mtod(m, void *), MCLBYTES);
294                 } else {
295                         n = read(sc->sc_fd, sc->sc_txbuf, MCLBYTES);
296                 }
297                 if (n < 0) {
298                         sc->sc_rx_mbuf = m;     /* We can use it next time */
299                         break;
300                 }
301                 if (m) {
302                         ifp->if_ipackets++;
303                         m->m_pkthdr.rcvif = ifp;
304                         m->m_pkthdr.len = m->m_len = n;
305                         ifp->if_input(ifp, m);
306                 } else {
307                         ifp->if_ierrors++;
308                 }
309         }
310 }
311
312 static int
313 vke_attach(const struct vknetif_info *info, int unit)
314 {
315         struct vke_softc *sc;
316         struct ifnet *ifp;
317         struct tapinfo tapinfo;
318         uint8_t enaddr[ETHER_ADDR_LEN];
319         int fd;
320
321         KKASSERT(info->tap_fd >= 0);
322         fd = info->tap_fd;
323
324         /*
325          * This is only a TAP device if tap_unit is non-zero.  If
326          * connecting to a virtual socket we generate a unique MAC.
327          */
328         if (info->tap_unit >= 0) {
329                 if (ioctl(fd, TAPGIFINFO, &tapinfo) < 0) {
330                         kprintf(VKE_DEVNAME "%d: ioctl(TAPGIFINFO) "
331                                 "failed: %s\n", unit, strerror(errno));
332                         return ENXIO;
333                 }
334
335                 if (ioctl(fd, SIOCGIFADDR, enaddr) < 0) {
336                         kprintf(VKE_DEVNAME "%d: ioctl(SIOCGIFADDR) "
337                                 "failed: %s\n", unit, strerror(errno));
338                         return ENXIO;
339                 }
340         } else {
341                 int fd = open("/dev/urandom", O_RDONLY);
342                 if (fd >= 0) {
343                         read(fd, enaddr + 2, 4);
344                         close(fd);
345                 }
346                 enaddr[4] = (int)getpid() >> 8;
347                 enaddr[5] = (int)getpid() & 255;
348                 
349         }
350         enaddr[1] += 1;
351
352         sc = kmalloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO);
353
354         sc->sc_txbuf = kmalloc(MCLBYTES, M_DEVBUF, M_WAITOK);
355         sc->sc_fd = fd;
356         sc->sc_unit = unit;
357         sc->sc_tap_unit = info->tap_unit;
358         sc->sc_addr = info->netif_addr;
359         sc->sc_mask = info->netif_mask;
360
361         ifp = &sc->arpcom.ac_if;
362         if_initname(ifp, VKE_DEVNAME, sc->sc_unit);
363
364         /* NB: after if_initname() */
365         sysctl_ctx_init(&sc->sc_sysctl_ctx);
366         sc->sc_sysctl_tree = SYSCTL_ADD_NODE(&sc->sc_sysctl_ctx,
367                                              SYSCTL_STATIC_CHILDREN(_hw),
368                                              OID_AUTO, ifp->if_xname,
369                                              CTLFLAG_RD, 0, "");
370         if (sc->sc_sysctl_tree == NULL) {
371                 kprintf(VKE_DEVNAME "%d: can't add sysctl node\n", unit);
372         } else {
373                 SYSCTL_ADD_INT(&sc->sc_sysctl_ctx,
374                                SYSCTL_CHILDREN(sc->sc_sysctl_tree),
375                                OID_AUTO, "tap_unit",
376                                CTLFLAG_RD, &sc->sc_tap_unit, 0,
377                                "Backend tap(4) unit");
378         }
379
380         ifp->if_softc = sc;
381         ifp->if_ioctl = vke_ioctl;
382         ifp->if_start = vke_start;
383         ifp->if_init = vke_init;
384         ifp->if_mtu = tapinfo.mtu;
385         ifp->if_baudrate = tapinfo.baudrate;
386         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
387         ifq_set_maxlen(&ifp->if_snd, IFQ_MAXLEN);
388         ifq_set_ready(&ifp->if_snd);
389
390         /* TODO: if_media */
391
392         ether_ifattach(ifp, enaddr, NULL);
393
394         if (bootverbose && sc->sc_addr != 0) {
395                 if_printf(ifp, "pre-configured "
396                           "address 0x%08x, netmask 0x%08x\n",
397                           ntohl(sc->sc_addr), ntohl(sc->sc_mask));
398         }
399
400         return 0;
401 }
402
403 static int
404 vke_init_addr(struct ifnet *ifp, in_addr_t addr, in_addr_t mask)
405 {
406         struct ifaliasreq ifra;
407         struct sockaddr_in *sin;
408         int ret;
409
410         ASSERT_SERIALIZED(ifp->if_serializer);
411
412         if (bootverbose) {
413                 if_printf(ifp, "add pre-configured "
414                           "address 0x%08x, netmask 0x%08x\n",
415                           ntohl(addr), ntohl(mask));
416         }
417
418         bzero(&ifra, sizeof(ifra));
419
420         /* NB: no need to set ifaliasreq.ifra_name */
421
422         sin = (struct sockaddr_in *)&ifra.ifra_addr;
423         sin->sin_family = AF_INET;
424         sin->sin_len = sizeof(*sin);
425         sin->sin_addr.s_addr = addr;
426
427         if (mask != 0) {
428                 sin = (struct sockaddr_in *)&ifra.ifra_mask;
429                 sin->sin_len = sizeof(*sin);
430                 sin->sin_addr.s_addr = mask;
431         }
432
433         /*
434          * Temporarily release serializer, in_control() will hold
435          * it again before calling ifnet.if_ioctl().
436          */
437         lwkt_serialize_exit(ifp->if_serializer);
438         ret = in_control(NULL, SIOCAIFADDR, (caddr_t)&ifra, ifp, NULL);
439         lwkt_serialize_enter(ifp->if_serializer);
440
441         return ret;
442 }