From: Anthony Liguori <aliguori@us.ibm.com>
To: Richa Marwaha <rmarwah@linux.vnet.ibm.com>
Cc: coreyb@linux.vnet.ibm.com, qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] [PATCH 4/4] Add support for bridge
Date: Thu, 06 Oct 2011 12:49:40 -0500 [thread overview]
Message-ID: <4E8DEA34.1050005@us.ibm.com> (raw)
In-Reply-To: <1317915508-15491-5-git-send-email-rmarwah@linux.vnet.ibm.com>
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
>
> Signed-off-by: Richa Marwaha<rmarwah@linux.vnet.ibm.com>
> ---
> 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
next prev parent reply other threads:[~2011-10-06 17:51 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-10-06 15:38 [Qemu-devel] [PATCH 0/4] -net tap: rootless bridge support for qemu Richa Marwaha
2011-10-06 15:38 ` [Qemu-devel] [PATCH 1/4] Add basic version of bridge helper Richa Marwaha
2011-10-06 16:41 ` Daniel P. Berrange
2011-10-06 18:04 ` Anthony Liguori
2011-10-06 18:38 ` Corey Bryant
2011-10-07 9:04 ` Daniel P. Berrange
2011-10-07 14:40 ` Corey Bryant
2011-10-07 14:45 ` Daniel P. Berrange
2011-10-07 14:51 ` Corey Bryant
2011-10-07 14:52 ` Corey Bryant
2011-10-06 17:44 ` Anthony Liguori
2011-10-06 18:10 ` Corey Bryant
2011-10-06 15:38 ` [Qemu-devel] [PATCH 2/4] Add access control support to qemu-bridge-helper Richa Marwaha
2011-10-06 15:38 ` [Qemu-devel] [PATCH 3/4] Add cap reduction support to enable use as SUID Richa Marwaha
2011-10-06 16:34 ` Daniel P. Berrange
2011-10-06 17:42 ` Anthony Liguori
2011-10-06 18:05 ` Corey Bryant
2011-10-06 18:08 ` Corey Bryant
2011-10-06 15:38 ` [Qemu-devel] [PATCH 4/4] Add support for bridge Richa Marwaha
2011-10-06 17:49 ` Anthony Liguori [this message]
2011-10-06 18:15 ` Corey Bryant
2011-10-06 18:19 ` Anthony Liguori
2011-10-06 18:24 ` Corey Bryant
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4E8DEA34.1050005@us.ibm.com \
--to=aliguori@us.ibm.com \
--cc=coreyb@linux.vnet.ibm.com \
--cc=qemu-devel@nongnu.org \
--cc=rmarwah@linux.vnet.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).