Tue Aug 10 18:06:10 2010 UTC ()
* improve diagnostic print
* deal with a tap quirk when it returns 0 bytes


(pooka)
diff -r1.18 -r1.19 src/sys/rump/net/lib/libvirtif/if_virt.c

cvs diff -r1.18 -r1.19 src/sys/rump/net/lib/libvirtif/if_virt.c (switch to unified diff)

--- src/sys/rump/net/lib/libvirtif/if_virt.c 2010/04/05 16:35:30 1.18
+++ src/sys/rump/net/lib/libvirtif/if_virt.c 2010/08/10 18:06:10 1.19
@@ -1,323 +1,330 @@ @@ -1,323 +1,330 @@
1/* $NetBSD: if_virt.c,v 1.18 2010/04/05 16:35:30 joerg Exp $ */ 1/* $NetBSD: if_virt.c,v 1.19 2010/08/10 18:06:10 pooka Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2008 Antti Kantee. All Rights Reserved. 4 * Copyright (c) 2008 Antti Kantee. All Rights Reserved.
5 * 5 *
6 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions 7 * modification, are permitted provided that the following conditions
8 * are met: 8 * are met:
9 * 1. Redistributions of source code must retain the above copyright 9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright 11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the 12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution. 13 * documentation and/or other materials provided with the distribution.
14 * 14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE. 25 * SUCH DAMAGE.
26 */ 26 */
27 27
28#include <sys/cdefs.h> 28#include <sys/cdefs.h>
29__KERNEL_RCSID(0, "$NetBSD: if_virt.c,v 1.18 2010/04/05 16:35:30 joerg Exp $"); 29__KERNEL_RCSID(0, "$NetBSD: if_virt.c,v 1.19 2010/08/10 18:06:10 pooka Exp $");
30 30
31#include <sys/param.h> 31#include <sys/param.h>
32#include <sys/condvar.h> 32#include <sys/condvar.h>
33#include <sys/fcntl.h> 33#include <sys/fcntl.h>
34#include <sys/kmem.h> 34#include <sys/kmem.h>
35#include <sys/kthread.h> 35#include <sys/kthread.h>
36#include <sys/mutex.h> 36#include <sys/mutex.h>
37#include <sys/poll.h> 37#include <sys/poll.h>
38#include <sys/sockio.h> 38#include <sys/sockio.h>
39#include <sys/socketvar.h> 39#include <sys/socketvar.h>
40 40
41#include <net/bpf.h> 41#include <net/bpf.h>
42#include <net/if.h> 42#include <net/if.h>
43#include <net/if_ether.h> 43#include <net/if_ether.h>
44#include <net/if_tap.h> 44#include <net/if_tap.h>
45 45
46#include <netinet/in.h> 46#include <netinet/in.h>
47#include <netinet/in_var.h> 47#include <netinet/in_var.h>
48 48
49#include <rump/rump.h> 49#include <rump/rump.h>
50#include <rump/rumpuser.h> 50#include <rump/rumpuser.h>
51 51
52#include "rump_private.h" 52#include "rump_private.h"
53#include "rump_net_private.h" 53#include "rump_net_private.h"
54 54
55/* 55/*
56 * Virtual interface for userspace purposes. Uses tap(4) to 56 * Virtual interface for userspace purposes. Uses tap(4) to
57 * interface with the kernel and just simply shovels data 57 * interface with the kernel and just simply shovels data
58 * to/from /dev/tap. 58 * to/from /dev/tap.
59 */ 59 */
60 60
61#define VIRTIF_BASE "virt" 61#define VIRTIF_BASE "virt"
62 62
63static int virtif_init(struct ifnet *); 63static int virtif_init(struct ifnet *);
64static int virtif_ioctl(struct ifnet *, u_long, void *); 64static int virtif_ioctl(struct ifnet *, u_long, void *);
65static void virtif_start(struct ifnet *); 65static void virtif_start(struct ifnet *);
66static void virtif_stop(struct ifnet *, int); 66static void virtif_stop(struct ifnet *, int);
67 67
68struct virtif_sc { 68struct virtif_sc {
69 struct ethercom sc_ec; 69 struct ethercom sc_ec;
70 int sc_tapfd; 70 int sc_tapfd;
71 kmutex_t sc_sendmtx; 71 kmutex_t sc_sendmtx;
72 kcondvar_t sc_sendcv; 72 kcondvar_t sc_sendcv;
73}; 73};
74 74
75static void virtif_worker(void *); 75static void virtif_worker(void *);
76static void virtif_sender(void *); 76static void virtif_sender(void *);
77 77
78#if 0 78#if 0
79/* 79/*
80 * Create a socket and call ifioctl() to configure the interface. 80 * Create a socket and call ifioctl() to configure the interface.
81 * This trickles down to virtif_ioctl(). 81 * This trickles down to virtif_ioctl().
82 */ 82 */
83static int 83static int
84configaddr(struct ifnet *ifp, struct ifaliasreq *ia) 84configaddr(struct ifnet *ifp, struct ifaliasreq *ia)
85{ 85{
86 struct socket *so; 86 struct socket *so;
87 int error; 87 int error;
88 88
89 strcpy(ia->ifra_name, ifp->if_xname); 89 strcpy(ia->ifra_name, ifp->if_xname);
90 error = socreate(ia->ifra_addr.sa_family, &so, SOCK_DGRAM, 90 error = socreate(ia->ifra_addr.sa_family, &so, SOCK_DGRAM,
91 0, curlwp, NULL); 91 0, curlwp, NULL);
92 if (error) 92 if (error)
93 return error; 93 return error;
94 error = ifioctl(so, SIOCAIFADDR, ia, curlwp); 94 error = ifioctl(so, SIOCAIFADDR, ia, curlwp);
95 soclose(so); 95 soclose(so);
96 96
97 return error; 97 return error;
98} 98}
99#endif 99#endif
100 100
101int 101int
102rump_virtif_create(int num) 102rump_virtif_create(int num)
103{ 103{
104 struct virtif_sc *sc; 104 struct virtif_sc *sc;
105 struct ifnet *ifp; 105 struct ifnet *ifp;
106 uint8_t enaddr[ETHER_ADDR_LEN] = { 0xb2, 0x0a, 0x00, 0x0b, 0x0e, 0x01 }; 106 uint8_t enaddr[ETHER_ADDR_LEN] = { 0xb2, 0x0a, 0x00, 0x0b, 0x0e, 0x01 };
107 char tapdev[16]; 107 char tapdev[16];
108 int fd, error; 108 int fd, error;
109 109
110 snprintf(tapdev, sizeof(tapdev), "/dev/tap%d", num); 110 snprintf(tapdev, sizeof(tapdev), "/dev/tap%d", num);
111 fd = rumpuser_open(tapdev, O_RDWR, &error); 111 fd = rumpuser_open(tapdev, O_RDWR, &error);
112 if (fd == -1) { 112 if (fd == -1) {
113 printf("virtif_create: can't open /dev/tap %d\n", error); 113 printf("virtif_create: can't open /dev/tap%d: %d\n",
 114 num, error);
114 return error; 115 return error;
115 } 116 }
116 KASSERT(num < 0x100); 117 KASSERT(num < 0x100);
117 enaddr[2] = arc4random() & 0xff; 118 enaddr[2] = arc4random() & 0xff;
118 enaddr[5] = num; 119 enaddr[5] = num;
119 120
120 sc = kmem_zalloc(sizeof(*sc), KM_SLEEP); 121 sc = kmem_zalloc(sizeof(*sc), KM_SLEEP);
121 sc->sc_tapfd = fd; 122 sc->sc_tapfd = fd;
122 123
123 ifp = &sc->sc_ec.ec_if; 124 ifp = &sc->sc_ec.ec_if;
124 sprintf(ifp->if_xname, "%s%d", VIRTIF_BASE, num); 125 sprintf(ifp->if_xname, "%s%d", VIRTIF_BASE, num);
125 ifp->if_softc = sc; 126 ifp->if_softc = sc;
126 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 127 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
127 ifp->if_init = virtif_init; 128 ifp->if_init = virtif_init;
128 ifp->if_ioctl = virtif_ioctl; 129 ifp->if_ioctl = virtif_ioctl;
129 ifp->if_start = virtif_start; 130 ifp->if_start = virtif_start;
130 ifp->if_stop = virtif_stop; 131 ifp->if_stop = virtif_stop;
131 132
132 mutex_init(&sc->sc_sendmtx, MUTEX_DEFAULT, IPL_NONE); 133 mutex_init(&sc->sc_sendmtx, MUTEX_DEFAULT, IPL_NONE);
133 cv_init(&sc->sc_sendcv, "virtsnd"); 134 cv_init(&sc->sc_sendcv, "virtsnd");
134 135
135 if_attach(ifp); 136 if_attach(ifp);
136 ether_ifattach(ifp, enaddr); 137 ether_ifattach(ifp, enaddr);
137 138
138 return 0; 139 return 0;
139} 140}
140 141
141static int 142static int
142virtif_init(struct ifnet *ifp) 143virtif_init(struct ifnet *ifp)
143{ 144{
144 int rv; 145 int rv;
145 146
146 if (rump_threads) { 147 if (rump_threads) {
147 rv = kthread_create(PRI_NONE, 0, NULL, virtif_worker, ifp, 148 rv = kthread_create(PRI_NONE, 0, NULL, virtif_worker, ifp,
148 NULL, "virtifi"); 149 NULL, "virtifi");
149 /* XXX: should do proper cleanup */ 150 /* XXX: should do proper cleanup */
150 if (rv) { 151 if (rv) {
151 panic("if_virt: can't create worker"); 152 panic("if_virt: can't create worker");
152 } 153 }
153 rv = kthread_create(PRI_NONE, 0, NULL, virtif_sender, ifp, 154 rv = kthread_create(PRI_NONE, 0, NULL, virtif_sender, ifp,
154 NULL, "virtifs"); 155 NULL, "virtifs");
155 if (rv) { 156 if (rv) {
156 panic("if_virt: can't create sender"); 157 panic("if_virt: can't create sender");
157 } 158 }
158 } else { 159 } else {
159 printf("WARNING: threads not enabled, receive NOT working\n"); 160 printf("WARNING: threads not enabled, receive NOT working\n");
160 } 161 }
161 ifp->if_flags |= IFF_RUNNING; 162 ifp->if_flags |= IFF_RUNNING;
162  163
163 return 0; 164 return 0;
164} 165}
165 166
166static int 167static int
167virtif_ioctl(struct ifnet *ifp, u_long cmd, void *data) 168virtif_ioctl(struct ifnet *ifp, u_long cmd, void *data)
168{ 169{
169 int s, rv; 170 int s, rv;
170 171
171 s = splnet(); 172 s = splnet();
172 rv = ether_ioctl(ifp, cmd, data); 173 rv = ether_ioctl(ifp, cmd, data);
173 if (rv == ENETRESET) 174 if (rv == ENETRESET)
174 rv = 0; 175 rv = 0;
175 splx(s); 176 splx(s);
176 177
177 return rv; 178 return rv;
178} 179}
179 180
180/* just send everything in-context */ 181/* just send everything in-context */
181static void 182static void
182virtif_start(struct ifnet *ifp) 183virtif_start(struct ifnet *ifp)
183{ 184{
184 struct virtif_sc *sc = ifp->if_softc; 185 struct virtif_sc *sc = ifp->if_softc;
185 186
186 mutex_enter(&sc->sc_sendmtx); 187 mutex_enter(&sc->sc_sendmtx);
187 cv_signal(&sc->sc_sendcv); 188 cv_signal(&sc->sc_sendcv);
188 mutex_exit(&sc->sc_sendmtx); 189 mutex_exit(&sc->sc_sendmtx);
189} 190}
190 191
191static void 192static void
192virtif_stop(struct ifnet *ifp, int disable) 193virtif_stop(struct ifnet *ifp, int disable)
193{ 194{
194 195
195 panic("%s: unimpl", __func__); 196 panic("%s: unimpl", __func__);
196} 197}
197 198
198static void 199static void
199virtif_worker(void *arg) 200virtif_worker(void *arg)
200{ 201{
201 struct ifnet *ifp = arg; 202 struct ifnet *ifp = arg;
202 struct virtif_sc *sc = ifp->if_softc; 203 struct virtif_sc *sc = ifp->if_softc;
203 struct mbuf *m; 204 struct mbuf *m;
204 size_t plen = ETHER_MAX_LEN_JUMBO+1; 205 size_t plen = ETHER_MAX_LEN_JUMBO+1;
205 ssize_t n; 206 ssize_t n;
206 int error; 207 int error;
207 208
208 for (;;) { 209 for (;;) {
209 m = m_gethdr(M_WAIT, MT_DATA); 210 m = m_gethdr(M_WAIT, MT_DATA);
210 MEXTMALLOC(m, plen, M_WAIT); 211 MEXTMALLOC(m, plen, M_WAIT);
211 212
212 again: 213 again:
213 n = rumpuser_read(sc->sc_tapfd, mtod(m, void *), plen, &error); 214 n = rumpuser_read(sc->sc_tapfd, mtod(m, void *), plen, &error);
214 KASSERT(n < ETHER_MAX_LEN_JUMBO); 215 KASSERT(n < ETHER_MAX_LEN_JUMBO);
215 if (n <= 0) { 216 if (__predict_false(n < 0)) {
216 /* 217 /*
217 * work around tap bug: /dev/tap is opened in 218 * work around tap bug: /dev/tap is opened in
218 * non-blocking mode if it previously was 219 * non-blocking mode if it previously was
219 * non-blocking. 220 * non-blocking.
220 */ 221 */
221 if (n == -1 && error == EAGAIN) { 222 if (n == -1 && error == EAGAIN) {
222 struct pollfd pfd; 223 struct pollfd pfd;
223 224
224 pfd.fd = sc->sc_tapfd; 225 pfd.fd = sc->sc_tapfd;
225 pfd.events = POLLIN; 226 pfd.events = POLLIN;
226 227
227 rumpuser_poll(&pfd, 1, INFTIM, &error); 228 rumpuser_poll(&pfd, 1, INFTIM, &error);
228 goto again; 229 goto again;
229 } 230 }
 231
230 m_freem(m); 232 m_freem(m);
231 break; 233 break;
232 } 234 }
 235
 236 /* tap sometimes returns EOF. don't sweat it and plow on */
 237 if (__predict_false(n == 0))
 238 goto again;
 239
233 m->m_len = m->m_pkthdr.len = n; 240 m->m_len = m->m_pkthdr.len = n;
234 m->m_pkthdr.rcvif = ifp; 241 m->m_pkthdr.rcvif = ifp;
235 bpf_mtap(ifp, m); 242 bpf_mtap(ifp, m);
236 ether_input(ifp, m); 243 ether_input(ifp, m);
237 } 244 }
238 245
239 panic("virtif_workin is a lazy boy %d\n", error); 246 panic("virtif_workin is a lazy boy %d\n", error);
240} 247}
241 248
242/* lazy bum stetson-harrison magic value */ 249/* lazy bum stetson-harrison magic value */
243#define LB_SH 32 250#define LB_SH 32
244static void 251static void
245virtif_sender(void *arg) 252virtif_sender(void *arg)
246{ 253{
247 struct ifnet *ifp = arg; 254 struct ifnet *ifp = arg;
248 struct virtif_sc *sc = ifp->if_softc; 255 struct virtif_sc *sc = ifp->if_softc;
249 struct mbuf *m, *m0; 256 struct mbuf *m, *m0;
250 struct rumpuser_iovec io[LB_SH]; 257 struct rumpuser_iovec io[LB_SH];
251 int i, error; 258 int i, error;
252 259
253 mutex_enter(&sc->sc_sendmtx); 260 mutex_enter(&sc->sc_sendmtx);
254 for (;;) { 261 for (;;) {
255 IF_DEQUEUE(&ifp->if_snd, m0); 262 IF_DEQUEUE(&ifp->if_snd, m0);
256 if (!m0) { 263 if (!m0) {
257 cv_wait(&sc->sc_sendcv, &sc->sc_sendmtx); 264 cv_wait(&sc->sc_sendcv, &sc->sc_sendmtx);
258 continue; 265 continue;
259 } 266 }
260 mutex_exit(&sc->sc_sendmtx); 267 mutex_exit(&sc->sc_sendmtx);
261 268
262 m = m0; 269 m = m0;
263 for (i = 0; i < LB_SH && m; i++) { 270 for (i = 0; i < LB_SH && m; i++) {
264 io[i].iov_base = mtod(m, void *); 271 io[i].iov_base = mtod(m, void *);
265 io[i].iov_len = m->m_len; 272 io[i].iov_len = m->m_len;
266 m = m->m_next; 273 m = m->m_next;
267 } 274 }
268 if (i == LB_SH) 275 if (i == LB_SH)
269 panic("lazy bum"); 276 panic("lazy bum");
270 bpf_mtap(ifp, m0); 277 bpf_mtap(ifp, m0);
271 rumpuser_writev(sc->sc_tapfd, io, i, &error); 278 rumpuser_writev(sc->sc_tapfd, io, i, &error);
272 m_freem(m0); 279 m_freem(m0);
273 mutex_enter(&sc->sc_sendmtx); 280 mutex_enter(&sc->sc_sendmtx);
274 } 281 }
275 282
276 mutex_exit(softnet_lock); 283 mutex_exit(softnet_lock);
277} 284}
278 285
279/* 286/*
280 * dummyif is a nada-interface. 287 * dummyif is a nada-interface.
281 * As it requires nothing external, it can be used for testing 288 * As it requires nothing external, it can be used for testing
282 * interface configuration. 289 * interface configuration.
283 */ 290 */
284static int dummyif_init(struct ifnet *); 291static int dummyif_init(struct ifnet *);
285static void dummyif_start(struct ifnet *); 292static void dummyif_start(struct ifnet *);
286 293
287void 294void
288rump_dummyif_create() 295rump_dummyif_create()
289{ 296{
290 struct ifnet *ifp; 297 struct ifnet *ifp;
291 struct ethercom *ec; 298 struct ethercom *ec;
292 uint8_t enaddr[ETHER_ADDR_LEN] = { 0xb2, 0x0a, 0x00, 0x0b, 0x0e, 0x01 }; 299 uint8_t enaddr[ETHER_ADDR_LEN] = { 0xb2, 0x0a, 0x00, 0x0b, 0x0e, 0x01 };
293 300
294 enaddr[2] = arc4random() & 0xff; 301 enaddr[2] = arc4random() & 0xff;
295 enaddr[5] = arc4random() & 0xff; 302 enaddr[5] = arc4random() & 0xff;
296 303
297 ec = kmem_zalloc(sizeof(*ec), KM_SLEEP); 304 ec = kmem_zalloc(sizeof(*ec), KM_SLEEP);
298 305
299 ifp = &ec->ec_if; 306 ifp = &ec->ec_if;
300 strlcpy(ifp->if_xname, "dummy0", sizeof(ifp->if_xname)); 307 strlcpy(ifp->if_xname, "dummy0", sizeof(ifp->if_xname));
301 ifp->if_softc = ifp; 308 ifp->if_softc = ifp;
302 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 309 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
303 ifp->if_init = dummyif_init; 310 ifp->if_init = dummyif_init;
304 ifp->if_ioctl = virtif_ioctl; 311 ifp->if_ioctl = virtif_ioctl;
305 ifp->if_start = dummyif_start; 312 ifp->if_start = dummyif_start;
306 313
307 if_attach(ifp); 314 if_attach(ifp);
308 ether_ifattach(ifp, enaddr); 315 ether_ifattach(ifp, enaddr);
309} 316}
310 317
311static int 318static int
312dummyif_init(struct ifnet *ifp) 319dummyif_init(struct ifnet *ifp)
313{ 320{
314 321
315 ifp->if_flags |= IFF_RUNNING; 322 ifp->if_flags |= IFF_RUNNING;
316 return 0; 323 return 0;
317} 324}
318 325
319static void 326static void
320dummyif_start(struct ifnet *ifp) 327dummyif_start(struct ifnet *ifp)
321{ 328{
322 329
323} 330}