1*7b93fadfSCorey Bryant /* 2*7b93fadfSCorey Bryant * QEMU Bridge Helper 3*7b93fadfSCorey Bryant * 4*7b93fadfSCorey Bryant * Copyright IBM, Corp. 2011 5*7b93fadfSCorey Bryant * 6*7b93fadfSCorey Bryant * Authors: 7*7b93fadfSCorey Bryant * Anthony Liguori <aliguori@us.ibm.com> 8*7b93fadfSCorey Bryant * Richa Marwaha <rmarwah@linux.vnet.ibm.com> 9*7b93fadfSCorey Bryant * Corey Bryant <coreyb@linux.vnet.ibm.com> 10*7b93fadfSCorey Bryant * 11*7b93fadfSCorey Bryant * This work is licensed under the terms of the GNU GPL, version 2. See 12*7b93fadfSCorey Bryant * the COPYING file in the top-level directory. 13*7b93fadfSCorey Bryant * 14*7b93fadfSCorey Bryant */ 15*7b93fadfSCorey Bryant 16*7b93fadfSCorey Bryant #include "config-host.h" 17*7b93fadfSCorey Bryant 18*7b93fadfSCorey Bryant #include <stdio.h> 19*7b93fadfSCorey Bryant #include <errno.h> 20*7b93fadfSCorey Bryant #include <fcntl.h> 21*7b93fadfSCorey Bryant #include <unistd.h> 22*7b93fadfSCorey Bryant #include <string.h> 23*7b93fadfSCorey Bryant #include <stdlib.h> 24*7b93fadfSCorey Bryant #include <stdbool.h> 25*7b93fadfSCorey Bryant #include <ctype.h> 26*7b93fadfSCorey Bryant 27*7b93fadfSCorey Bryant #include <sys/types.h> 28*7b93fadfSCorey Bryant #include <sys/ioctl.h> 29*7b93fadfSCorey Bryant #include <sys/socket.h> 30*7b93fadfSCorey Bryant #include <sys/un.h> 31*7b93fadfSCorey Bryant #include <sys/prctl.h> 32*7b93fadfSCorey Bryant 33*7b93fadfSCorey Bryant #include <net/if.h> 34*7b93fadfSCorey Bryant 35*7b93fadfSCorey Bryant #include <linux/sockios.h> 36*7b93fadfSCorey Bryant 37*7b93fadfSCorey Bryant #include "net/tap-linux.h" 38*7b93fadfSCorey Bryant 39*7b93fadfSCorey Bryant static void usage(void) 40*7b93fadfSCorey Bryant { 41*7b93fadfSCorey Bryant fprintf(stderr, 42*7b93fadfSCorey Bryant "Usage: qemu-bridge-helper [--use-vnet] --br=bridge --fd=unixfd\n"); 43*7b93fadfSCorey Bryant } 44*7b93fadfSCorey Bryant 45*7b93fadfSCorey Bryant static bool has_vnet_hdr(int fd) 46*7b93fadfSCorey Bryant { 47*7b93fadfSCorey Bryant unsigned int features = 0; 48*7b93fadfSCorey Bryant 49*7b93fadfSCorey Bryant if (ioctl(fd, TUNGETFEATURES, &features) == -1) { 50*7b93fadfSCorey Bryant return false; 51*7b93fadfSCorey Bryant } 52*7b93fadfSCorey Bryant 53*7b93fadfSCorey Bryant if (!(features & IFF_VNET_HDR)) { 54*7b93fadfSCorey Bryant return false; 55*7b93fadfSCorey Bryant } 56*7b93fadfSCorey Bryant 57*7b93fadfSCorey Bryant return true; 58*7b93fadfSCorey Bryant } 59*7b93fadfSCorey Bryant 60*7b93fadfSCorey Bryant static void prep_ifreq(struct ifreq *ifr, const char *ifname) 61*7b93fadfSCorey Bryant { 62*7b93fadfSCorey Bryant memset(ifr, 0, sizeof(*ifr)); 63*7b93fadfSCorey Bryant snprintf(ifr->ifr_name, IFNAMSIZ, "%s", ifname); 64*7b93fadfSCorey Bryant } 65*7b93fadfSCorey Bryant 66*7b93fadfSCorey Bryant static int send_fd(int c, int fd) 67*7b93fadfSCorey Bryant { 68*7b93fadfSCorey Bryant char msgbuf[CMSG_SPACE(sizeof(fd))]; 69*7b93fadfSCorey Bryant struct msghdr msg = { 70*7b93fadfSCorey Bryant .msg_control = msgbuf, 71*7b93fadfSCorey Bryant .msg_controllen = sizeof(msgbuf), 72*7b93fadfSCorey Bryant }; 73*7b93fadfSCorey Bryant struct cmsghdr *cmsg; 74*7b93fadfSCorey Bryant struct iovec iov; 75*7b93fadfSCorey Bryant char req[1] = { 0x00 }; 76*7b93fadfSCorey Bryant 77*7b93fadfSCorey Bryant cmsg = CMSG_FIRSTHDR(&msg); 78*7b93fadfSCorey Bryant cmsg->cmsg_level = SOL_SOCKET; 79*7b93fadfSCorey Bryant cmsg->cmsg_type = SCM_RIGHTS; 80*7b93fadfSCorey Bryant cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); 81*7b93fadfSCorey Bryant msg.msg_controllen = cmsg->cmsg_len; 82*7b93fadfSCorey Bryant 83*7b93fadfSCorey Bryant iov.iov_base = req; 84*7b93fadfSCorey Bryant iov.iov_len = sizeof(req); 85*7b93fadfSCorey Bryant 86*7b93fadfSCorey Bryant msg.msg_iov = &iov; 87*7b93fadfSCorey Bryant msg.msg_iovlen = 1; 88*7b93fadfSCorey Bryant memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd)); 89*7b93fadfSCorey Bryant 90*7b93fadfSCorey Bryant return sendmsg(c, &msg, 0); 91*7b93fadfSCorey Bryant } 92*7b93fadfSCorey Bryant 93*7b93fadfSCorey Bryant int main(int argc, char **argv) 94*7b93fadfSCorey Bryant { 95*7b93fadfSCorey Bryant struct ifreq ifr; 96*7b93fadfSCorey Bryant int fd, ctlfd, unixfd = -1; 97*7b93fadfSCorey Bryant int use_vnet = 0; 98*7b93fadfSCorey Bryant int mtu; 99*7b93fadfSCorey Bryant const char *bridge = NULL; 100*7b93fadfSCorey Bryant char iface[IFNAMSIZ]; 101*7b93fadfSCorey Bryant int index; 102*7b93fadfSCorey Bryant int ret = EXIT_SUCCESS; 103*7b93fadfSCorey Bryant 104*7b93fadfSCorey Bryant /* parse arguments */ 105*7b93fadfSCorey Bryant for (index = 1; index < argc; index++) { 106*7b93fadfSCorey Bryant if (strcmp(argv[index], "--use-vnet") == 0) { 107*7b93fadfSCorey Bryant use_vnet = 1; 108*7b93fadfSCorey Bryant } else if (strncmp(argv[index], "--br=", 5) == 0) { 109*7b93fadfSCorey Bryant bridge = &argv[index][5]; 110*7b93fadfSCorey Bryant } else if (strncmp(argv[index], "--fd=", 5) == 0) { 111*7b93fadfSCorey Bryant unixfd = atoi(&argv[index][5]); 112*7b93fadfSCorey Bryant } else { 113*7b93fadfSCorey Bryant usage(); 114*7b93fadfSCorey Bryant return EXIT_FAILURE; 115*7b93fadfSCorey Bryant } 116*7b93fadfSCorey Bryant } 117*7b93fadfSCorey Bryant 118*7b93fadfSCorey Bryant if (bridge == NULL || unixfd == -1) { 119*7b93fadfSCorey Bryant usage(); 120*7b93fadfSCorey Bryant return EXIT_FAILURE; 121*7b93fadfSCorey Bryant } 122*7b93fadfSCorey Bryant 123*7b93fadfSCorey Bryant /* open a socket to use to control the network interfaces */ 124*7b93fadfSCorey Bryant ctlfd = socket(AF_INET, SOCK_STREAM, 0); 125*7b93fadfSCorey Bryant if (ctlfd == -1) { 126*7b93fadfSCorey Bryant fprintf(stderr, "failed to open control socket: %s\n", strerror(errno)); 127*7b93fadfSCorey Bryant ret = EXIT_FAILURE; 128*7b93fadfSCorey Bryant goto cleanup; 129*7b93fadfSCorey Bryant } 130*7b93fadfSCorey Bryant 131*7b93fadfSCorey Bryant /* open the tap device */ 132*7b93fadfSCorey Bryant fd = open("/dev/net/tun", O_RDWR); 133*7b93fadfSCorey Bryant if (fd == -1) { 134*7b93fadfSCorey Bryant fprintf(stderr, "failed to open /dev/net/tun: %s\n", strerror(errno)); 135*7b93fadfSCorey Bryant ret = EXIT_FAILURE; 136*7b93fadfSCorey Bryant goto cleanup; 137*7b93fadfSCorey Bryant } 138*7b93fadfSCorey Bryant 139*7b93fadfSCorey Bryant /* request a tap device, disable PI, and add vnet header support if 140*7b93fadfSCorey Bryant * requested and it's available. */ 141*7b93fadfSCorey Bryant prep_ifreq(&ifr, "tap%d"); 142*7b93fadfSCorey Bryant ifr.ifr_flags = IFF_TAP|IFF_NO_PI; 143*7b93fadfSCorey Bryant if (use_vnet && has_vnet_hdr(fd)) { 144*7b93fadfSCorey Bryant ifr.ifr_flags |= IFF_VNET_HDR; 145*7b93fadfSCorey Bryant } 146*7b93fadfSCorey Bryant 147*7b93fadfSCorey Bryant if (ioctl(fd, TUNSETIFF, &ifr) == -1) { 148*7b93fadfSCorey Bryant fprintf(stderr, "failed to create tun device: %s\n", strerror(errno)); 149*7b93fadfSCorey Bryant ret = EXIT_FAILURE; 150*7b93fadfSCorey Bryant goto cleanup; 151*7b93fadfSCorey Bryant } 152*7b93fadfSCorey Bryant 153*7b93fadfSCorey Bryant /* save tap device name */ 154*7b93fadfSCorey Bryant snprintf(iface, sizeof(iface), "%s", ifr.ifr_name); 155*7b93fadfSCorey Bryant 156*7b93fadfSCorey Bryant /* get the mtu of the bridge */ 157*7b93fadfSCorey Bryant prep_ifreq(&ifr, bridge); 158*7b93fadfSCorey Bryant if (ioctl(ctlfd, SIOCGIFMTU, &ifr) == -1) { 159*7b93fadfSCorey Bryant fprintf(stderr, "failed to get mtu of bridge `%s': %s\n", 160*7b93fadfSCorey Bryant bridge, strerror(errno)); 161*7b93fadfSCorey Bryant ret = EXIT_FAILURE; 162*7b93fadfSCorey Bryant goto cleanup; 163*7b93fadfSCorey Bryant } 164*7b93fadfSCorey Bryant 165*7b93fadfSCorey Bryant /* save mtu */ 166*7b93fadfSCorey Bryant mtu = ifr.ifr_mtu; 167*7b93fadfSCorey Bryant 168*7b93fadfSCorey Bryant /* set the mtu of the interface based on the bridge */ 169*7b93fadfSCorey Bryant prep_ifreq(&ifr, iface); 170*7b93fadfSCorey Bryant ifr.ifr_mtu = mtu; 171*7b93fadfSCorey Bryant if (ioctl(ctlfd, SIOCSIFMTU, &ifr) == -1) { 172*7b93fadfSCorey Bryant fprintf(stderr, "failed to set mtu of device `%s' to %d: %s\n", 173*7b93fadfSCorey Bryant iface, mtu, strerror(errno)); 174*7b93fadfSCorey Bryant ret = EXIT_FAILURE; 175*7b93fadfSCorey Bryant goto cleanup; 176*7b93fadfSCorey Bryant } 177*7b93fadfSCorey Bryant 178*7b93fadfSCorey Bryant /* add the interface to the bridge */ 179*7b93fadfSCorey Bryant prep_ifreq(&ifr, bridge); 180*7b93fadfSCorey Bryant ifr.ifr_ifindex = if_nametoindex(iface); 181*7b93fadfSCorey Bryant 182*7b93fadfSCorey Bryant if (ioctl(ctlfd, SIOCBRADDIF, &ifr) == -1) { 183*7b93fadfSCorey Bryant fprintf(stderr, "failed to add interface `%s' to bridge `%s': %s\n", 184*7b93fadfSCorey Bryant iface, bridge, strerror(errno)); 185*7b93fadfSCorey Bryant ret = EXIT_FAILURE; 186*7b93fadfSCorey Bryant goto cleanup; 187*7b93fadfSCorey Bryant } 188*7b93fadfSCorey Bryant 189*7b93fadfSCorey Bryant /* bring the interface up */ 190*7b93fadfSCorey Bryant prep_ifreq(&ifr, iface); 191*7b93fadfSCorey Bryant if (ioctl(ctlfd, SIOCGIFFLAGS, &ifr) == -1) { 192*7b93fadfSCorey Bryant fprintf(stderr, "failed to get interface flags for `%s': %s\n", 193*7b93fadfSCorey Bryant iface, strerror(errno)); 194*7b93fadfSCorey Bryant ret = EXIT_FAILURE; 195*7b93fadfSCorey Bryant goto cleanup; 196*7b93fadfSCorey Bryant } 197*7b93fadfSCorey Bryant 198*7b93fadfSCorey Bryant ifr.ifr_flags |= IFF_UP; 199*7b93fadfSCorey Bryant if (ioctl(ctlfd, SIOCSIFFLAGS, &ifr) == -1) { 200*7b93fadfSCorey Bryant fprintf(stderr, "failed to bring up interface `%s': %s\n", 201*7b93fadfSCorey Bryant iface, strerror(errno)); 202*7b93fadfSCorey Bryant ret = EXIT_FAILURE; 203*7b93fadfSCorey Bryant goto cleanup; 204*7b93fadfSCorey Bryant } 205*7b93fadfSCorey Bryant 206*7b93fadfSCorey Bryant /* write fd to the domain socket */ 207*7b93fadfSCorey Bryant if (send_fd(unixfd, fd) == -1) { 208*7b93fadfSCorey Bryant fprintf(stderr, "failed to write fd to unix socket: %s\n", 209*7b93fadfSCorey Bryant strerror(errno)); 210*7b93fadfSCorey Bryant ret = EXIT_FAILURE; 211*7b93fadfSCorey Bryant goto cleanup; 212*7b93fadfSCorey Bryant } 213*7b93fadfSCorey Bryant 214*7b93fadfSCorey Bryant /* ... */ 215*7b93fadfSCorey Bryant 216*7b93fadfSCorey Bryant /* profit! */ 217*7b93fadfSCorey Bryant 218*7b93fadfSCorey Bryant cleanup: 219*7b93fadfSCorey Bryant 220*7b93fadfSCorey Bryant return ret; 221*7b93fadfSCorey Bryant } 222