On Mon, Nov 22, 2010 at 10:48:45AM -0800, Mike Ryan wrote: > Michael, this patch implements the feature with a bind address instead > of a bind interface. It should address the cross-platform issues that > were raised. > > Others: any comments?
Looks ok. This does not handle IPv6 but the rest of the code doesn't, either. > On Wed, Nov 17, 2010 at 05:16:26PM -0800, Mike Ryan wrote: > > Add an option to specify the host IP to send multicast packets from when > > using a multicast socket for networking. The option takes an IP address > > and sets the IP_MULTICAST_IF socket option, which causes the packets to > > use that IP's 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 | 46 ++++++++++++++++++++++++++++++++++------------ > > qemu-options.hx | 11 +++++++++-- > > 3 files changed, 47 insertions(+), 14 deletions(-) > > > > diff --git a/net.c b/net.c > > index c5e6063..9ba5be2 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 = "localaddr", > > + .type = QEMU_OPT_STRING, > > + .help = "source address for multicast packets", > > }, > > { /* end of list */ } > > }, > > diff --git a/net/socket.c b/net/socket.c > > index 1c4e153..d443f4c 100644 > > --- a/net/socket.c > > +++ b/net/socket.c > > @@ -149,7 +149,7 @@ 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, struct > > in_addr *localaddr) > > { > > struct ip_mreq imr; > > int fd; > > @@ -201,6 +201,15 @@ static int net_socket_mcast_create(struct sockaddr_in > > *mcastaddr) > > goto fail; > > } > > > > + /* If a bind address is given, only send packets from that address */ > > + if (localaddr != NULL) { > > + ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, localaddr, > > sizeof(*localaddr)); > > + if (ret < 0) { > > + perror("setsockopt(IP_MULTICAST_IF)"); > > + goto fail; > > + } > > + } > > + > > socket_set_nonblock(fd); > > return fd; > > fail: > > @@ -248,7 +257,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,17 +477,26 @@ 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 *localaddr_str) > > { > > NetSocketState *s; > > int fd; > > struct sockaddr_in saddr; > > + struct in_addr localaddr, *param_localaddr; > > > > if (parse_host_port(&saddr, host_str) < 0) > > return -1; > > > > + if (localaddr_str != NULL) { > > + if (inet_aton(localaddr_str, &localaddr) == 0) > > + return -1; > > + param_localaddr = &localaddr; > > + } else { > > + param_localaddr = NULL; > > + } > > > > - fd = net_socket_mcast_create(&saddr); > > + fd = net_socket_mcast_create(&saddr, param_localaddr); > > if (fd < 0) > > return -1; > > > > @@ -505,8 +523,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, "localaddr")) { > > + error_report("listen=, connect=, mcast= and localaddr= is > > invalid with fd=\n"); > > return -1; > > } > > > > @@ -524,8 +543,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, "localaddr")) { > > + error_report("fd=, connect=, mcast= and localaddr= is invalid > > with listen=\n"); > > return -1; > > } > > > > @@ -539,8 +559,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, "localaddr")) { > > + error_report("fd=, listen=, mcast= and localaddr= is invalid > > with connect=\n"); > > return -1; > > } > > > > @@ -550,7 +571,7 @@ int net_init_socket(QemuOpts *opts, > > return -1; > > } > > } else if (qemu_opt_get(opts, "mcast")) { > > - const char *mcast; > > + const char *mcast, *localaddr; > > > > if (qemu_opt_get(opts, "fd") || > > qemu_opt_get(opts, "connect") || > > @@ -560,8 +581,9 @@ int net_init_socket(QemuOpts *opts, > > } > > > > mcast = qemu_opt_get(opts, "mcast"); > > + localaddr = qemu_opt_get(opts, "localaddr"); > > > > - if (net_socket_mcast_init(vlan, "socket", name, mcast) == -1) { > > + if (net_socket_mcast_init(vlan, "socket", name, mcast, localaddr) > > == -1) { > > return -1; > > } > > } else { > > diff --git a/qemu-options.hx b/qemu-options.hx > > index 4d99a58..accd16a 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[,localaddr=addr]]\n" > > " connect the vlan 'n' to multicast maddr and port\n" > > + " use 'localaddr=addr' to specify the host address to > > send packets from\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}[,localad...@var{addr}]] > > > > 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 from host's 1.2.3.4): > > +...@example > > +qemu linux.img -net nic,macaddr=52:54:00:12:34:56 \ > > + -net socket,mcast=239.192.168.1:1102,localaddr=1.2.3.4 > > +...@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} > > -- > > 1.7.0.4 > >