From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from [140.186.70.92] (port=60153 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1PI6HR-0005ii-N7 for qemu-devel@nongnu.org; Mon, 15 Nov 2010 16:08:07 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1PI6HL-0004SE-GW for qemu-devel@nongnu.org; Mon, 15 Nov 2010 16:08:01 -0500 Received: from mail-qy0-f173.google.com ([209.85.216.173]:48267) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1PI6HL-0004S8-Ao for qemu-devel@nongnu.org; Mon, 15 Nov 2010 16:07:55 -0500 Received: by qyl33 with SMTP id 33so4321959qyl.4 for ; Mon, 15 Nov 2010 13:07:55 -0800 (PST) Message-ID: <4CE1A127.5080209@codemonkey.ws> Date: Mon, 15 Nov 2010 15:07:51 -0600 From: Anthony Liguori MIME-Version: 1.0 Subject: Re: [Qemu-devel] [PATCH] add a command line option to specify the interface to send multicast packets on References: <20101111014735.GQ2211@zzz.isi.edu> <20101115185452.GE26869@zzz.isi.edu> <4CE18BBC.2050706@codemonkey.ws> <20101115195212.GG26869@zzz.isi.edu> In-Reply-To: <20101115195212.GG26869@zzz.isi.edu> Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Mike Ryan Cc: qemu-devel@nongnu.org On 11/15/2010 01:52 PM, Mike Ryan wrote: > I'll clarify/elaborate a bit: > > When using a multicast socket, the OS chooses a default physical > interface to send packets. The patch I've supplied allows the user to > select the interface. > > Suppose you have a setup like so: > > BoxA --- BoxB --- BoxC > > You wish to run virtual machines on BoxB and BoxC and network them using > a multicast UDP socket. > > BoxB has two network interfaces, and the default multicast interface may > be the link between BoxA and BoxB. In this situation, BoxC will not > receive any multicast packets from BoxB and networking between the boxes > is therefore impossible. > > The utility of a multicast socket is obviously limited in my simplified > example. Generalize BoxC to a LAN of physical machines all running > virtual machines you wish to network and the use case should become a > bit clearer. > Thanks. Second question is how portable is SIOCGIFADDR? I suspect that's very Linux-centric.. Regards, Anthony Liguori > On Mon, Nov 15, 2010 at 01:36:28PM -0600, Anthony Liguori wrote: > >> On 11/15/2010 12:54 PM, Mike Ryan wrote: >> >>> Anyone care to comment? >>> >> I must admit, I don't understand the use-case well enough to really >> give an appropriate amount of review as to whether this is the best >> solution to the problem. >> >> Michael, do you have any thoughts? >> >> Regards, >> >> Anthony Liguori >> >> >>> On Wed, Nov 10, 2010 at 05:47:35PM -0800, Mike Ryan wrote: >>> >>>> Add an option to specify the host interface to send multicast packets on >>>> when using a multicast socket for networking. The option takes the name >>>> of a host interface (e.g., eth0) and sets the IP_MULTICAST_IF socket >>>> option, which causes the packets to use that interface as an egress. >>>> >>>> This is useful if the host machine has several interfaces with several >>>> virtual networks across disparate interfaces. >>>> --- >>>> net.c | 4 ++++ >>>> net/socket.c | 48 ++++++++++++++++++++++++++++++++++++------------ >>>> qemu-common.h | 1 + >>>> qemu-options.hx | 11 +++++++++-- >>>> qemu_socket.h | 1 + >>>> 5 files changed, 51 insertions(+), 14 deletions(-) >>>> >>>> diff --git a/net.c b/net.c >>>> index c5e6063..ff9eb27 100644 >>>> --- a/net.c >>>> +++ b/net.c >>>> @@ -1050,6 +1050,10 @@ static const struct { >>>> .name = "mcast", >>>> .type = QEMU_OPT_STRING, >>>> .help = "UDP multicast address and port number", >>>> + }, { >>>> + .name = "interface", >>>> + .type = QEMU_OPT_STRING, >>>> + .help = "interface to send multicast packets on", >>>> }, >>>> { /* end of list */ } >>>> }, >>>> diff --git a/net/socket.c b/net/socket.c >>>> index 1c4e153..ed7cd12 100644 >>>> --- a/net/socket.c >>>> +++ b/net/socket.c >>>> @@ -149,11 +149,13 @@ static void net_socket_send_dgram(void *opaque) >>>> qemu_send_packet(&s->nc, s->buf, size); >>>> } >>>> >>>> -static int net_socket_mcast_create(struct sockaddr_in *mcastaddr) >>>> +static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, const char *interface) >>>> { >>>> struct ip_mreq imr; >>>> int fd; >>>> int val, ret; >>>> + struct in_addr maddr; >>>> + struct ifreq ifr; >>>> if (!IN_MULTICAST(ntohl(mcastaddr->sin_addr.s_addr))) { >>>> fprintf(stderr, "qemu: error: specified mcastaddr \"%s\" (0x%08x) does not contain a multicast address\n", >>>> inet_ntoa(mcastaddr->sin_addr), >>>> @@ -201,6 +203,23 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr) >>>> goto fail; >>>> } >>>> >>>> + /* If an interface name is given, only send packets out that interface */ >>>> + if (interface != NULL) { >>>> + strncpy(ifr.ifr_name, interface, IFNAMSIZ); >>>> + ret = ioctl(fd, SIOCGIFADDR,&ifr); >>>> + if (ret< 0) { >>>> + fprintf(stderr, "qemu: error: specified interface \"%s\" does not exist\n", interface); >>>> + goto fail; >>>> + } >>>> + >>>> + maddr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr; >>>> + ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,&maddr, sizeof(maddr)); >>>> + if (ret< 0) { >>>> + perror("setsockopt(IP_MULTICAST_IF)"); >>>> + goto fail; >>>> + } >>>> + } >>>> + >>>> socket_set_nonblock(fd); >>>> return fd; >>>> fail: >>>> @@ -248,7 +267,7 @@ static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, >>>> return NULL; >>>> } >>>> /* clone dgram socket */ >>>> - newfd = net_socket_mcast_create(&saddr); >>>> + newfd = net_socket_mcast_create(&saddr, NULL); >>>> if (newfd< 0) { >>>> /* error already reported by net_socket_mcast_create() */ >>>> close(fd); >>>> @@ -468,7 +487,8 @@ static int net_socket_connect_init(VLANState *vlan, >>>> static int net_socket_mcast_init(VLANState *vlan, >>>> const char *model, >>>> const char *name, >>>> - const char *host_str) >>>> + const char *host_str, >>>> + const char *interface) >>>> { >>>> NetSocketState *s; >>>> int fd; >>>> @@ -478,7 +498,7 @@ static int net_socket_mcast_init(VLANState *vlan, >>>> return -1; >>>> >>>> >>>> - fd = net_socket_mcast_create(&saddr); >>>> + fd = net_socket_mcast_create(&saddr, interface); >>>> if (fd< 0) >>>> return -1; >>>> >>>> @@ -505,8 +525,9 @@ int net_init_socket(QemuOpts *opts, >>>> >>>> if (qemu_opt_get(opts, "listen") || >>>> qemu_opt_get(opts, "connect") || >>>> - qemu_opt_get(opts, "mcast")) { >>>> - error_report("listen=, connect= and mcast= is invalid with fd="); >>>> + qemu_opt_get(opts, "mcast") || >>>> + qemu_opt_get(opts, "interface")) { >>>> + error_report("listen=, connect=, mcast= and interface= is invalid with fd=\n"); >>>> return -1; >>>> } >>>> >>>> @@ -524,8 +545,9 @@ int net_init_socket(QemuOpts *opts, >>>> >>>> if (qemu_opt_get(opts, "fd") || >>>> qemu_opt_get(opts, "connect") || >>>> - qemu_opt_get(opts, "mcast")) { >>>> - error_report("fd=, connect= and mcast= is invalid with listen="); >>>> + qemu_opt_get(opts, "mcast") || >>>> + qemu_opt_get(opts, "interface")) { >>>> + error_report("fd=, connect=, mcast= and interface= is invalid with listen=\n"); >>>> return -1; >>>> } >>>> >>>> @@ -539,8 +561,9 @@ int net_init_socket(QemuOpts *opts, >>>> >>>> if (qemu_opt_get(opts, "fd") || >>>> qemu_opt_get(opts, "listen") || >>>> - qemu_opt_get(opts, "mcast")) { >>>> - error_report("fd=, listen= and mcast= is invalid with connect="); >>>> + qemu_opt_get(opts, "mcast") || >>>> + qemu_opt_get(opts, "interface")) { >>>> + error_report("fd=, listen=, mcast= and interface= is invalid with connect=\n"); >>>> return -1; >>>> } >>>> >>>> @@ -550,7 +573,7 @@ int net_init_socket(QemuOpts *opts, >>>> return -1; >>>> } >>>> } else if (qemu_opt_get(opts, "mcast")) { >>>> - const char *mcast; >>>> + const char *mcast, *interface; >>>> >>>> if (qemu_opt_get(opts, "fd") || >>>> qemu_opt_get(opts, "connect") || >>>> @@ -560,8 +583,9 @@ int net_init_socket(QemuOpts *opts, >>>> } >>>> >>>> mcast = qemu_opt_get(opts, "mcast"); >>>> + interface = qemu_opt_get(opts, "interface"); >>>> >>>> - if (net_socket_mcast_init(vlan, "socket", name, mcast) == -1) { >>>> + if (net_socket_mcast_init(vlan, "socket", name, mcast, interface) == -1) { >>>> return -1; >>>> } >>>> } else { >>>> diff --git a/qemu-common.h b/qemu-common.h >>>> index b3957f1..e8bc4af 100644 >>>> --- a/qemu-common.h >>>> +++ b/qemu-common.h >>>> @@ -34,6 +34,7 @@ typedef struct DeviceState DeviceState; >>>> #include >>>> #include >>>> #include >>>> +#include >>>> >>>> #ifndef O_LARGEFILE >>>> #define O_LARGEFILE 0 >>>> diff --git a/qemu-options.hx b/qemu-options.hx >>>> index 4d99a58..e2c4cfa 100644 >>>> --- a/qemu-options.hx >>>> +++ b/qemu-options.hx >>>> @@ -1061,8 +1061,9 @@ DEF("net", HAS_ARG, QEMU_OPTION_net, >>>> #endif >>>> "-net socket[,vlan=n][,name=str][,fd=h][,listen=[host]:port][,connect=host:port]\n" >>>> " connect the vlan 'n' to another VLAN using a socket connection\n" >>>> - "-net socket[,vlan=n][,name=str][,fd=h][,mcast=maddr:port]\n" >>>> + "-net socket[,vlan=n][,name=str][,fd=h][,mcast=maddr:port[,interface=ifname]]\n" >>>> " connect the vlan 'n' to multicast maddr and port\n" >>>> + " use 'interface=ifname' to specify the host interface to send packets on\n" >>>> #ifdef CONFIG_VDE >>>> "-net vde[,vlan=n][,name=str][,sock=socketpath][,port=n][,group=groupname][,mode=octalmode]\n" >>>> " connect the vlan 'n' to port 'n' of a vde switch running\n" >>>> @@ -1256,7 +1257,7 @@ qemu linux.img -net nic,macaddr=52:54:00:12:34:57 \ >>>> -net socket,connect=127.0.0.1:1234 >>>> @end example >>>> >>>> -@item -net socket[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}] [,mcast=@var{maddr}:@var{port}] >>>> +@item -net socket[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}][,mcast=@var{maddr}:@var{port}[,interface=@var{ifname}]] >>>> >>>> Create a VLAN @var{n} shared with another QEMU virtual >>>> machines using a UDP multicast socket, effectively making a bus for >>>> @@ -1296,6 +1297,12 @@ qemu linux.img -net nic,macaddr=52:54:00:12:34:56 \ >>>> /path/to/linux ubd0=/path/to/root_fs eth0=mcast >>>> @end example >>>> >>>> +Example (send packets on host's eth0): >>>> +@example >>>> +qemu linux.img -net nic,macaddr=52:54:00:12:34:56 \ >>>> + -net socket,mcast=239.192.168.1:1102,interface=eth0 >>>> +@end example >>>> + >>>> @item -net vde[,vlan=@var{n}][,name=@var{name}][,sock=@var{socketpath}] [,port=@var{n}][,group=@var{groupname}][,mode=@var{octalmode}] >>>> Connect VLAN @var{n} to PORT @var{n} of a vde switch running on host and >>>> listening for incoming connections on @var{socketpath}. Use GROUP @var{groupname} >>>> diff --git a/qemu_socket.h b/qemu_socket.h >>>> index 897a8ae..5116e4a 100644 >>>> --- a/qemu_socket.h >>>> +++ b/qemu_socket.h >>>> @@ -24,6 +24,7 @@ int inet_aton(const char *cp, struct in_addr *ia); >>>> #include >>>> #include >>>> #include >>>> +#include >>>> >>>> #define socket_error() errno >>>> #define closesocket(s) close(s) >>>> -- >>>> 1.7.0.4 >>>> >>>> >> >