From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([140.186.70.92]:56409) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RBsUC-0007bc-9O for qemu-devel@nongnu.org; Thu, 06 Oct 2011 14:16:02 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1RBsUA-0001vi-9F for qemu-devel@nongnu.org; Thu, 06 Oct 2011 14:16:00 -0400 Received: from e35.co.us.ibm.com ([32.97.110.153]:54775) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RBsU9-0001ve-W6 for qemu-devel@nongnu.org; Thu, 06 Oct 2011 14:15:58 -0400 Received: from d03relay05.boulder.ibm.com (d03relay05.boulder.ibm.com [9.17.195.107]) by e35.co.us.ibm.com (8.14.4/8.13.1) with ESMTP id p96HsfYh004133 for ; Thu, 6 Oct 2011 11:54:41 -0600 Received: from d03av05.boulder.ibm.com (d03av05.boulder.ibm.com [9.17.195.85]) by d03relay05.boulder.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id p96IFggi120330 for ; Thu, 6 Oct 2011 12:15:45 -0600 Received: from d03av05.boulder.ibm.com (loopback [127.0.0.1]) by d03av05.boulder.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id p96IFblX023860 for ; Thu, 6 Oct 2011 12:15:38 -0600 Message-ID: <4E8DF02E.1060202@linux.vnet.ibm.com> Date: Thu, 06 Oct 2011 14:15:10 -0400 From: Corey Bryant MIME-Version: 1.0 References: <1317915508-15491-1-git-send-email-rmarwah@linux.vnet.ibm.com> <1317915508-15491-5-git-send-email-rmarwah@linux.vnet.ibm.com> <4E8DEA34.1050005@us.ibm.com> In-Reply-To: <4E8DEA34.1050005@us.ibm.com> Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Subject: Re: [Qemu-devel] [PATCH 4/4] Add support for bridge List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Anthony Liguori Cc: Richa Marwaha , qemu-devel@nongnu.org On 10/06/2011 01:49 PM, Anthony Liguori wrote: > On 10/06/2011 10:38 AM, Richa Marwaha wrote: >> The most common use of -net tap is to connect a tap device to a >> bridge. This >> requires the use of a script and running qemu as root in order to >> allocate a >> tap device to pass to the script. >> >> This model is great for portability and flexibility but it's incredibly >> difficult to eliminate the need to run qemu as root. The only really >> viable >> mechanism is to use tunctl to create a tap device, attach it to a >> bridge as >> root, and then hand that tap device to qemu. The problem with this >> mechanism >> is that it requires administrator intervention whenever a user wants >> to create >> a guest. >> >> By essentially writing a helper that implements the most common qemu-ifup >> script that can be safely given cap_net_admin, we can dramatically >> simplify >> things for non-privileged users. We still support existing -net tap >> options >> as a mechanism for advanced users and backwards compatibility. >> >> Currently, this is very Linux centric but there's really no reason why it >> couldn't be extended for other Unixes. >> >> The default bridge that we attach to is qemubr0. The thinking is that >> a distro >> could preconfigure such an interface to allow out-of-the-box bridged >> networking. >> >> Alternatively, if a user wants to use a different bridge, they can say: >> >> qemu-hda linux.img -net >> tap,br=br0,helper=/usr/local/libexec/qemu-bridge-helper >> -net nic,model=virtio > > > Wouldn't it be better to make the syntax: > > -net bridge[,br=BRIDGE][,helper=HELPER] > > And default BRIDGE to br0 and HELPER to > ${prefix}/libexec/qemu-bridge-helper ? > > That gives distros a proper way to configure a default bridge making > -net bridge Just Work for most people. > > Regards, > > Anthony Liguori > Yes I think it would be much more usable under -net bridge. I really wanted this to work under -net tap (where fd and init are) but now we know there's no good way to default to the helper without spelling out the path. We'll move to -net bridge if folks are in agreement and default to bridge br0. >> >> Signed-off-by: Richa Marwaha >> --- >> configure | 2 + >> net.c | 8 +++ >> net.h | 2 + >> net/tap.c | 150 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- >> qemu-options.hx | 48 +++++++++++++----- >> 5 files changed, 190 insertions(+), 20 deletions(-) >> >> diff --git a/configure b/configure >> index f46e9b7..ef05954 100755 >> --- a/configure >> +++ b/configure >> @@ -2775,6 +2775,8 @@ echo "sysconfdir=$sysconfdir">> $config_host_mak >> echo "docdir=$docdir">> $config_host_mak >> echo "libexecdir=\${prefix}/libexec">> $config_host_mak >> echo "confdir=$confdir">> $config_host_mak >> +echo "CONFIG_QEMU_SHAREDIR=\"$prefix$datasuffix\"">> $config_host_mak >> +echo "CONFIG_QEMU_HELPERDIR=\"$prefix/libexec\"">> $config_host_mak >> >> case "$cpu" in >> i386|x86_64|alpha|cris|hppa|ia64|lm32|m68k|microblaze|mips|mips64|ppc|ppc64|s390|s390x|sparc|sparc64|unicore32) >> >> diff --git a/net.c b/net.c >> index d05930c..4c3c551 100644 >> --- a/net.c >> +++ b/net.c >> @@ -956,6 +956,14 @@ static const struct { >> .type = QEMU_OPT_STRING, >> .help = "script to shut down the interface", >> }, { >> + .name = "br", >> + .type = QEMU_OPT_STRING, >> + .help = "bridge name", >> + }, { >> + .name = "helper", >> + .type = QEMU_OPT_STRING, >> + .help = "command to execute to configure bridge", >> + }, { >> .name = "sndbuf", >> .type = QEMU_OPT_SIZE, >> .help = "send buffer limit" >> diff --git a/net.h b/net.h >> index 9f633f8..eeb19a7 100644 >> --- a/net.h >> +++ b/net.h >> @@ -174,6 +174,8 @@ int do_netdev_del(Monitor *mon, const QDict >> *qdict, QObject **ret_data); >> >> #define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup" >> #define DEFAULT_NETWORK_DOWN_SCRIPT "/etc/qemu-ifdown" >> +#define DEFAULT_BRIDGE_HELPER CONFIG_QEMU_HELPERDIR >> "/qemu-bridge-helper" >> +#define DEFAULT_BRIDGE_INTERFACE "qemubr0" >> >> void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd); >> >> diff --git a/net/tap.c b/net/tap.c >> index 1f26dc9..74f103a 100644 >> --- a/net/tap.c >> +++ b/net/tap.c >> @@ -388,6 +388,108 @@ static int launch_script(const char >> *setup_script, const char *ifname, int fd) >> return -1; >> } >> >> +static int recv_fd(int c) >> +{ >> + int fd; >> + uint8_t msgbuf[CMSG_SPACE(sizeof(fd))]; >> + struct msghdr msg = { >> + .msg_control = msgbuf, >> + .msg_controllen = sizeof(msgbuf), >> + }; >> + struct cmsghdr *cmsg; >> + struct iovec iov; >> + uint8_t req[1]; >> + ssize_t len; >> + >> + cmsg = CMSG_FIRSTHDR(&msg); >> + cmsg->cmsg_level = SOL_SOCKET; >> + cmsg->cmsg_type = SCM_RIGHTS; >> + cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); >> + msg.msg_controllen = cmsg->cmsg_len; >> + >> + iov.iov_base = req; >> + iov.iov_len = sizeof(req); >> + >> + msg.msg_iov =&iov; >> + msg.msg_iovlen = 1; >> + >> + len = recvmsg(c,&msg, 0); >> + if (len> 0) { >> + memcpy(&fd, CMSG_DATA(cmsg), sizeof(fd)); >> + return fd; >> + } >> + >> + return len; >> +} >> + >> +static int net_bridge_run_helper(const char *helper, const char *bridge) >> +{ >> + sigset_t oldmask, mask; >> + int pid, status; >> + char *args[5]; >> + char **parg; >> + int sv[2]; >> + >> + sigemptyset(&mask); >> + sigaddset(&mask, SIGCHLD); >> + sigprocmask(SIG_BLOCK,&mask,&oldmask); >> + >> + if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) { >> + return -1; >> + } >> + >> + /* try to launch bridge helper */ >> + pid = fork(); >> + if (pid == 0) { >> + int open_max = sysconf(_SC_OPEN_MAX), i; >> + char buf[32]; >> + >> + snprintf(buf, sizeof(buf), "%d", sv[1]); >> + >> + for (i = 0; i< open_max; i++) { >> + if (i != STDIN_FILENO&& >> + i != STDOUT_FILENO&& >> + i != STDERR_FILENO&& >> + i != sv[1]) { >> + close(i); >> + } >> + } >> + parg = args; >> + *parg++ = (char *)helper; >> + *parg++ = (char *)"--use-vnet"; >> + *parg++ = (char *)bridge; >> + *parg++ = buf; >> + *parg++ = NULL; >> + execv(helper, args); >> + _exit(1); >> + } else if (pid> 0) { >> + int fd; >> + >> + close(sv[1]); >> + >> + do { >> + fd = recv_fd(sv[0]); >> + } while (fd == -1&& errno == EINTR); >> + >> + close(sv[0]); >> + >> + while (waitpid(pid,&status, 0) != pid) { >> + /* loop */ >> + } >> + sigprocmask(SIG_SETMASK,&oldmask, NULL); >> + if (fd< 0) { >> + fprintf(stderr, "failed to recv file descriptor\n"); >> + return -1; >> + } >> + >> + if (WIFEXITED(status)&& WEXITSTATUS(status) == 0) { >> + return fd; >> + } >> + } >> + fprintf(stderr, "failed to launch bridge helper\n"); >> + return -1; >> +} >> + >> static int net_tap_init(QemuOpts *opts, int *vnet_hdr) >> { >> int fd, vnet_hdr_required; >> @@ -433,8 +535,11 @@ int net_init_tap(QemuOpts *opts, Monitor *mon, >> const char *name, VLANState *vlan >> if (qemu_opt_get(opts, "ifname") || >> qemu_opt_get(opts, "script") || >> qemu_opt_get(opts, "downscript") || >> - qemu_opt_get(opts, "vnet_hdr")) { >> - error_report("ifname=, script=, downscript= and vnet_hdr= is invalid >> with fd="); >> + qemu_opt_get(opts, "vnet_hdr") || >> + qemu_opt_get(opts, "br") || >> + qemu_opt_get(opts, "helper")) { >> + error_report("ifname=, script=, downscript=, vnet_hdr=," >> + "br= and helper= are invalid with fd="); >> return -1; >> } >> >> @@ -446,6 +551,37 @@ int net_init_tap(QemuOpts *opts, Monitor *mon, >> const char *name, VLANState *vlan >> fcntl(fd, F_SETFL, O_NONBLOCK); >> >> vnet_hdr = tap_probe_vnet_hdr(fd); >> + } else if (qemu_opt_get(opts, "helper")) { >> + if (qemu_opt_get(opts, "ifname") || >> + qemu_opt_get(opts, "script") || >> + qemu_opt_get(opts, "downscript")) { >> + error_report("ifname=, script= and downscript=" >> + "are invalid with helper="); >> + return -1; >> + } >> + >> + if (!qemu_opt_get(opts, "br")) { >> + qemu_opt_set(opts, "br", DEFAULT_BRIDGE_INTERFACE); >> + } >> + >> + fd = net_bridge_run_helper(qemu_opt_get(opts, "helper"), >> + qemu_opt_get(opts, "br")); >> + >> + fcntl(fd, F_SETFL, O_NONBLOCK); >> + >> + vnet_hdr = tap_probe_vnet_hdr(fd); >> + >> + s = net_tap_fd_init(vlan, "bridge", name, fd, vnet_hdr); >> + >> + if (!s) { >> + close(fd); >> + return -1; >> + } >> + >> + snprintf(s->nc.info_str, sizeof(s->nc.info_str), >> + "br=%s", qemu_opt_get(opts, "br")); >> + >> + return 0; >> } else { >> if (!qemu_opt_get(opts, "script")) { >> qemu_opt_set(opts, "script", DEFAULT_NETWORK_SCRIPT); >> @@ -459,12 +595,12 @@ int net_init_tap(QemuOpts *opts, Monitor *mon, >> const char *name, VLANState *vlan >> if (fd == -1) { >> return -1; >> } >> - } >> >> - s = net_tap_fd_init(vlan, "tap", name, fd, vnet_hdr); >> - if (!s) { >> - close(fd); >> - return -1; >> + s = net_tap_fd_init(vlan, "tap", name, fd, vnet_hdr); >> + if (!s) { >> + close(fd); >> + return -1; >> + } >> } >> >> if (tap_set_sndbuf(s->fd, opts)< 0) { >> diff --git a/qemu-options.hx b/qemu-options.hx >> index dfbabd0..ad4afa9 100644 >> --- a/qemu-options.hx >> +++ b/qemu-options.hx >> @@ -1149,11 +1149,15 @@ DEF("net", HAS_ARG, QEMU_OPTION_net, >> "-net tap[,vlan=n][,name=str],ifname=name\n" >> " connect the host TAP network interface to VLAN 'n'\n" >> #else >> - "-net >> tap[,vlan=n][,name=str][,fd=h][,ifname=name][,script=file][,downscript=dfile][,sndbuf=nbytes][,vnet_hdr=on|off][,vhost=on|off][,vhostfd=h][,vhostforce=on|off]\n" >> >> - " connect the host TAP network interface to VLAN 'n' and use the\n" >> - " network scripts 'file' (default=" DEFAULT_NETWORK_SCRIPT ")\n" >> - " and 'dfile' (default=" DEFAULT_NETWORK_DOWN_SCRIPT ")\n" >> + "-net >> tap[,vlan=n][,name=str][,fd=h][,ifname=name][,script=file][,downscript=dfile][,br=bridge][,helper=helper][,sndbuf=nbytes][,vnet_hdr=on|off][,vhost=on|off][,vhostfd=h][,vhostforce=on|off]\n" >> >> + " connect the host TAP network interface to VLAN 'n' \n" >> + " use network scripts 'file' (default=" DEFAULT_NETWORK_SCRIPT ")\n" >> + " to configure it and 'dfile' (default=" DEFAULT_NETWORK_DOWN_SCRIPT >> ")\n" >> + " to deconfigure it. This requires root privilege.\n" >> " use '[down]script=no' to disable script execution\n" >> + " use network helper 'helper' (default=" DEFAULT_BRIDGE_HELPER ") >> and\n" >> + " use bridge 'br' (default=" DEFAULT_BRIDGE_INTERFACE ") to >> configure it. This\n" >> + " does not require root privilege.\n" >> " use 'fd=h' to connect to an already opened TAP interface\n" >> " use 'sndbuf=nbytes' to limit the size of the send buffer (the\n" >> " default is disabled 'sndbuf=0' to enable flow control set >> 'sndbuf=1048576')\n" >> @@ -1322,26 +1326,44 @@ processed and applied to -net user. Mixing >> them with the new configuration >> syntax gives undefined results. Their use for new applications is >> discouraged >> as they will be removed from future versions. >> >> -@item -net >> tap[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}][,ifname=@var{name}] >> [,script=@var{file}][,downscript=@var{dfile}] >> -Connect the host TAP network interface @var{name} to VLAN @var{n}, use >> -the network script @var{file} to configure it and the network script >> +@item -net >> tap[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}][,ifname=@var{name}] >> [,script=@var{file}][,downscript=@var{dfile}][,br=@var{bridge}][,helper=@var{helper}] >> >> +Connect the host TAP network interface @var{name} to VLAN @var{n}. >> + >> +Use the network script @var{file} to configure it and the network script >> @var{dfile} to deconfigure it. If @var{name} is not provided, the OS >> -automatically provides one. @option{fd}=@var{h} can be used to specify >> -the handle of an already opened host TAP interface. The default network >> -configure script is @file{/etc/qemu-ifup} and the default network >> -deconfigure script is @file{/etc/qemu-ifdown}. Use @option{script=no} >> -or @option{downscript=no} to disable script execution. Example: >> +automatically provides one. The default network configure script is >> +@file{/etc/qemu-ifup} and the default network deconfigure script is >> +@file{/etc/qemu-ifdown}. Use @option{script=no} or >> @option{downscript=no} >> +to disable script execution. >> + >> +If running QEMU as an unprivileged user, use the network helper >> +@var{helper} to configure the TAP interface. The default network >> +bridge helper executable is @file{/usr/local/libexec/qemu-bridge-helper} >> +and bridge name interface is @file{qemubr0}. >> + >> +@option{fd}=@var{h} can be used to specify the handle of an already >> +opened host TAP interface. >> + >> +Examples: >> >> @example >> +#launch a QEMU instance with the default network script >> qemu linux.img -net nic -net tap >> @end example >> >> -More complicated example (two NICs, each one connected to a TAP device) >> @example >> +#launch a QEMU instance with two NICs, each one connected >> +#to a TAP device >> qemu linux.img -net nic,vlan=0 -net tap,vlan=0,ifname=tap0 \ >> -net nic,vlan=1 -net tap,vlan=1,ifname=tap1 >> @end example >> >> +@example >> +#launch a QEMU instance with the default network helper to >> +#connect a TAP device to bridge br0 >> +qemu linux.img -net nic -net >> tap,helper=/usr/local/libexec/qemu-bridge-helper,br=br0 >> +@end example >> + >> @item -net socket[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}] >> [,listen=[@var{host}]:@var{port}][,connect=@var{host}:@var{port}] >> >> Connect the VLAN @var{n} to a remote VLAN in another QEMU virtual > > -- Regards, Corey