xref: /qemu/qemu-bridge-helper.c (revision 7b93fadf)
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