qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Corey Bryant <coreyb@linux.vnet.ibm.com>
To: Anthony Liguori <aliguori@us.ibm.com>
Cc: Richa Marwaha <rmarwah@linux.vnet.ibm.com>, qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] [PATCH 4/4] Add support for bridge
Date: Thu, 06 Oct 2011 14:15:10 -0400	[thread overview]
Message-ID: <4E8DF02E.1060202@linux.vnet.ibm.com> (raw)
In-Reply-To: <4E8DEA34.1050005@us.ibm.com>



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<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
>
>

-- 
Regards,
Corey

  reply	other threads:[~2011-10-06 18:16 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
2011-10-06 18:15     ` Corey Bryant [this message]
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=4E8DF02E.1060202@linux.vnet.ibm.com \
    --to=coreyb@linux.vnet.ibm.com \
    --cc=aliguori@us.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).