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. > @@ -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; > + }
Let's let the user pass in the IP address? That would solve the portability issue. Further, we could be doing IPv6, right? So you'd need IPV6_MULTICAST_IF? Also - you might also want to control IP_MULTICAST_LOOP/IPV6_MULTICAST_LOOP? > + } > + > 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 <fcntl.h> > #include <sys/stat.h> > #include <assert.h> > +#include <sys/ioctl.h> > > #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[,vl...@var{n}][,na...@var{name}][,f...@var{h}] > [,mca...@var{maddr}:@var{port}] > +...@item -net > socket[,vl...@var{n}][,na...@var{name}][,f...@var{h}][,mca...@var{maddr}:@var{port}[,interfa...@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[,vl...@var{n}][,na...@var{name}][,so...@var{socketpath}] > [,po...@var{n}][,gro...@var{groupname}][,mo...@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 <arpa/inet.h> > #include <netdb.h> > #include <sys/un.h> > +#include <net/if.h> > > #define socket_error() errno > #define closesocket(s) close(s) > -- > 1.7.0.4 >