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