1 1.6 bad /* $NetBSD: virtif_user.c,v 1.6 2019/03/26 08:56:17 bad Exp $ */ 2 1.1 pooka 3 1.1 pooka /* 4 1.1 pooka * Copyright (c) 2013 Antti Kantee. All Rights Reserved. 5 1.1 pooka * 6 1.1 pooka * Redistribution and use in source and binary forms, with or without 7 1.1 pooka * modification, are permitted provided that the following conditions 8 1.1 pooka * are met: 9 1.1 pooka * 1. Redistributions of source code must retain the above copyright 10 1.1 pooka * notice, this list of conditions and the following disclaimer. 11 1.1 pooka * 2. Redistributions in binary form must reproduce the above copyright 12 1.1 pooka * notice, this list of conditions and the following disclaimer in the 13 1.1 pooka * documentation and/or other materials provided with the distribution. 14 1.1 pooka * 15 1.1 pooka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 16 1.1 pooka * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 1.1 pooka * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 1.1 pooka * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 1.1 pooka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 1.1 pooka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 1.1 pooka * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 1.1 pooka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 1.1 pooka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 1.1 pooka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 1.1 pooka * SUCH DAMAGE. 26 1.1 pooka */ 27 1.1 pooka 28 1.4 alnsn #include <sys/cdefs.h> 29 1.6 bad #ifdef __KERNEL_RCSID 30 1.6 bad __KERNEL_RCSID(0, "$NetBSD: virtif_user.c,v 1.6 2019/03/26 08:56:17 bad Exp $"); 31 1.6 bad #endif 32 1.4 alnsn 33 1.1 pooka #ifndef _KERNEL 34 1.1 pooka #include <sys/types.h> 35 1.1 pooka #include <sys/ioctl.h> 36 1.1 pooka #include <sys/uio.h> 37 1.1 pooka 38 1.1 pooka #include <assert.h> 39 1.1 pooka #include <errno.h> 40 1.1 pooka #include <fcntl.h> 41 1.1 pooka #include <inttypes.h> 42 1.1 pooka #include <poll.h> 43 1.1 pooka #include <pthread.h> 44 1.1 pooka #include <stdio.h> 45 1.1 pooka #include <stdlib.h> 46 1.1 pooka #include <string.h> 47 1.1 pooka #include <unistd.h> 48 1.1 pooka 49 1.1 pooka #ifdef __linux__ 50 1.1 pooka #include <net/if.h> 51 1.1 pooka #include <linux/if_tun.h> 52 1.1 pooka #endif 53 1.1 pooka 54 1.1 pooka #include <rump/rumpuser_component.h> 55 1.1 pooka 56 1.1 pooka #include "if_virt.h" 57 1.1 pooka #include "virtif_user.h" 58 1.1 pooka 59 1.3 pooka #if VIFHYPER_REVISION != 20140313 60 1.1 pooka #error VIFHYPER_REVISION mismatch 61 1.1 pooka #endif 62 1.1 pooka 63 1.1 pooka struct virtif_user { 64 1.1 pooka struct virtif_sc *viu_virtifsc; 65 1.1 pooka int viu_devnum; 66 1.1 pooka 67 1.1 pooka int viu_fd; 68 1.1 pooka int viu_pipe[2]; 69 1.1 pooka pthread_t viu_rcvthr; 70 1.1 pooka 71 1.1 pooka int viu_dying; 72 1.1 pooka 73 1.1 pooka char viu_rcvbuf[9018]; /* jumbo frame max len */ 74 1.1 pooka }; 75 1.1 pooka 76 1.1 pooka static int 77 1.1 pooka opentapdev(int devnum) 78 1.1 pooka { 79 1.1 pooka int fd = -1; 80 1.1 pooka 81 1.1 pooka #if defined(__NetBSD__) || defined(__DragonFly__) 82 1.1 pooka char tapdev[64]; 83 1.1 pooka 84 1.1 pooka snprintf(tapdev, sizeof(tapdev), "/dev/tap%d", devnum); 85 1.1 pooka fd = open(tapdev, O_RDWR); 86 1.1 pooka if (fd == -1) { 87 1.1 pooka fprintf(stderr, "rumpcomp_virtif_create: can't open %s: " 88 1.1 pooka "%s\n", tapdev, strerror(errno)); 89 1.1 pooka } 90 1.1 pooka 91 1.1 pooka #elif defined(__linux__) 92 1.1 pooka struct ifreq ifr; 93 1.1 pooka char devname[16]; 94 1.1 pooka 95 1.1 pooka fd = open("/dev/net/tun", O_RDWR); 96 1.1 pooka if (fd == -1) { 97 1.1 pooka fprintf(stderr, "rumpcomp_virtif_create: can't open %s: " 98 1.1 pooka "%s\n", "/dev/net/tun", strerror(errno)); 99 1.1 pooka return -1; 100 1.1 pooka } 101 1.1 pooka 102 1.1 pooka snprintf(devname, sizeof(devname), "tun%d", devnum); 103 1.1 pooka memset(&ifr, 0, sizeof(ifr)); 104 1.1 pooka ifr.ifr_flags = IFF_TAP | IFF_NO_PI; 105 1.1 pooka strncpy(ifr.ifr_name, devname, sizeof(ifr.ifr_name)-1); 106 1.1 pooka 107 1.1 pooka if (ioctl(fd, TUNSETIFF, &ifr) == -1) { 108 1.1 pooka close(fd); 109 1.1 pooka fd = -1; 110 1.1 pooka } 111 1.1 pooka 112 1.1 pooka #else 113 1.1 pooka fprintf(stderr, "virtif not supported on this platform\n"); 114 1.1 pooka #endif 115 1.1 pooka 116 1.1 pooka return fd; 117 1.1 pooka } 118 1.1 pooka 119 1.1 pooka static void 120 1.1 pooka closetapdev(struct virtif_user *viu) 121 1.1 pooka { 122 1.1 pooka 123 1.1 pooka close(viu->viu_fd); 124 1.1 pooka } 125 1.1 pooka 126 1.1 pooka static void * 127 1.1 pooka rcvthread(void *aaargh) 128 1.1 pooka { 129 1.1 pooka struct virtif_user *viu = aaargh; 130 1.1 pooka struct pollfd pfd[2]; 131 1.1 pooka struct iovec iov; 132 1.1 pooka ssize_t nn = 0; 133 1.1 pooka int prv; 134 1.1 pooka 135 1.1 pooka rumpuser_component_kthread(); 136 1.1 pooka 137 1.1 pooka pfd[0].fd = viu->viu_fd; 138 1.1 pooka pfd[0].events = POLLIN; 139 1.1 pooka pfd[1].fd = viu->viu_pipe[0]; 140 1.1 pooka pfd[1].events = POLLIN; 141 1.1 pooka 142 1.1 pooka while (!viu->viu_dying) { 143 1.1 pooka prv = poll(pfd, 2, -1); 144 1.1 pooka if (prv == 0) 145 1.1 pooka continue; 146 1.1 pooka if (prv == -1) { 147 1.1 pooka /* XXX */ 148 1.1 pooka fprintf(stderr, "virt%d: poll error: %d\n", 149 1.1 pooka viu->viu_devnum, errno); 150 1.1 pooka sleep(1); 151 1.1 pooka continue; 152 1.1 pooka } 153 1.1 pooka if (pfd[1].revents & POLLIN) 154 1.1 pooka continue; 155 1.1 pooka 156 1.1 pooka nn = read(viu->viu_fd, 157 1.1 pooka viu->viu_rcvbuf, sizeof(viu->viu_rcvbuf)); 158 1.1 pooka if (nn == -1 && errno == EAGAIN) 159 1.1 pooka continue; 160 1.1 pooka 161 1.1 pooka if (nn < 1) { 162 1.1 pooka /* XXX */ 163 1.1 pooka fprintf(stderr, "virt%d: receive failed\n", 164 1.1 pooka viu->viu_devnum); 165 1.1 pooka sleep(1); 166 1.1 pooka continue; 167 1.1 pooka } 168 1.1 pooka iov.iov_base = viu->viu_rcvbuf; 169 1.1 pooka iov.iov_len = nn; 170 1.1 pooka 171 1.1 pooka rumpuser_component_schedule(NULL); 172 1.1 pooka VIF_DELIVERPKT(viu->viu_virtifsc, &iov, 1); 173 1.1 pooka rumpuser_component_unschedule(); 174 1.1 pooka } 175 1.1 pooka 176 1.1 pooka assert(viu->viu_dying); 177 1.1 pooka 178 1.1 pooka rumpuser_component_kthread_release(); 179 1.1 pooka return NULL; 180 1.1 pooka } 181 1.1 pooka 182 1.1 pooka int 183 1.1 pooka VIFHYPER_CREATE(const char *devstr, struct virtif_sc *vif_sc, uint8_t *enaddr, 184 1.1 pooka struct virtif_user **viup) 185 1.1 pooka { 186 1.1 pooka struct virtif_user *viu = NULL; 187 1.1 pooka void *cookie; 188 1.1 pooka int devnum; 189 1.1 pooka int rv; 190 1.1 pooka 191 1.1 pooka cookie = rumpuser_component_unschedule(); 192 1.1 pooka 193 1.1 pooka /* 194 1.1 pooka * Since this interface doesn't do LINKSTR, we know devstr to be 195 1.1 pooka * well-formatted. 196 1.1 pooka */ 197 1.1 pooka devnum = atoi(devstr); 198 1.1 pooka 199 1.1 pooka viu = calloc(1, sizeof(*viu)); 200 1.1 pooka if (viu == NULL) { 201 1.1 pooka rv = errno; 202 1.1 pooka goto oerr1; 203 1.1 pooka } 204 1.1 pooka viu->viu_virtifsc = vif_sc; 205 1.1 pooka 206 1.1 pooka viu->viu_fd = opentapdev(devnum); 207 1.1 pooka if (viu->viu_fd == -1) { 208 1.1 pooka rv = errno; 209 1.1 pooka goto oerr2; 210 1.1 pooka } 211 1.1 pooka viu->viu_devnum = devnum; 212 1.1 pooka 213 1.1 pooka if (pipe(viu->viu_pipe) == -1) { 214 1.1 pooka rv = errno; 215 1.1 pooka goto oerr3; 216 1.1 pooka } 217 1.1 pooka 218 1.1 pooka if ((rv = pthread_create(&viu->viu_rcvthr, NULL, rcvthread, viu)) != 0) 219 1.1 pooka goto oerr4; 220 1.1 pooka 221 1.1 pooka rumpuser_component_schedule(cookie); 222 1.1 pooka *viup = viu; 223 1.1 pooka return 0; 224 1.1 pooka 225 1.1 pooka oerr4: 226 1.1 pooka close(viu->viu_pipe[0]); 227 1.1 pooka close(viu->viu_pipe[1]); 228 1.1 pooka oerr3: 229 1.1 pooka closetapdev(viu); 230 1.1 pooka oerr2: 231 1.1 pooka free(viu); 232 1.1 pooka oerr1: 233 1.1 pooka rumpuser_component_schedule(cookie); 234 1.1 pooka return rumpuser_component_errtrans(rv); 235 1.1 pooka } 236 1.1 pooka 237 1.1 pooka void 238 1.1 pooka VIFHYPER_SEND(struct virtif_user *viu, 239 1.1 pooka struct iovec *iov, size_t iovlen) 240 1.1 pooka { 241 1.1 pooka void *cookie = rumpuser_component_unschedule(); 242 1.1 pooka ssize_t idontcare __attribute__((__unused__)); 243 1.1 pooka 244 1.1 pooka /* 245 1.1 pooka * no need to check for return value; packets may be dropped 246 1.1 pooka * 247 1.1 pooka * ... sorry, I spoke too soon. We need to check it because 248 1.1 pooka * apparently gcc reinvented const poisoning and it's very 249 1.1 pooka * hard to say "thanks, I know I'm not using the result, 250 1.1 pooka * but please STFU and let's get on with something useful". 251 1.1 pooka * So let's trick gcc into letting us share the compiler 252 1.1 pooka * experience. 253 1.1 pooka */ 254 1.1 pooka idontcare = writev(viu->viu_fd, iov, iovlen); 255 1.1 pooka 256 1.1 pooka rumpuser_component_schedule(cookie); 257 1.1 pooka } 258 1.1 pooka 259 1.2 pooka int 260 1.1 pooka VIFHYPER_DYING(struct virtif_user *viu) 261 1.1 pooka { 262 1.1 pooka void *cookie = rumpuser_component_unschedule(); 263 1.1 pooka 264 1.1 pooka viu->viu_dying = 1; 265 1.1 pooka if (write(viu->viu_pipe[1], 266 1.1 pooka &viu->viu_dying, sizeof(viu->viu_dying)) == -1) { 267 1.2 pooka /* 268 1.2 pooka * this is here mostly to avoid a compiler warning 269 1.2 pooka * about ignoring the return value of write() 270 1.2 pooka */ 271 1.1 pooka fprintf(stderr, "%s: failed to signal thread\n", 272 1.1 pooka VIF_STRING(VIFHYPER_DYING)); 273 1.1 pooka } 274 1.1 pooka 275 1.1 pooka rumpuser_component_schedule(cookie); 276 1.2 pooka 277 1.2 pooka return 0; 278 1.1 pooka } 279 1.1 pooka 280 1.1 pooka void 281 1.1 pooka VIFHYPER_DESTROY(struct virtif_user *viu) 282 1.1 pooka { 283 1.1 pooka void *cookie = rumpuser_component_unschedule(); 284 1.1 pooka 285 1.1 pooka pthread_join(viu->viu_rcvthr, NULL); 286 1.1 pooka closetapdev(viu); 287 1.1 pooka close(viu->viu_pipe[0]); 288 1.1 pooka close(viu->viu_pipe[1]); 289 1.1 pooka free(viu); 290 1.1 pooka 291 1.1 pooka rumpuser_component_schedule(cookie); 292 1.1 pooka } 293 1.1 pooka #endif 294