On Wed, Dec 01, 2010 at 11:16:47AM -0800, Mike Ryan wrote: > [one more minor change which is needed on older kernels] > > 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. > > Signed-off-by: Mike Ryan <miker...@isi.edu>
Applied. I tweaked style in one place ({} in if) and the commit message a bit. > --- > net.c | 4 ++++ > net/socket.c | 51 ++++++++++++++++++++++++++++++++++++++------------- > qemu-options.hx | 11 +++++++++-- > 3 files changed, 51 insertions(+), 15 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..df777ff 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; > @@ -183,7 +183,10 @@ static int net_socket_mcast_create(struct sockaddr_in > *mcastaddr) > > /* Add host to multicast group */ > imr.imr_multiaddr = mcastaddr->sin_addr; > - imr.imr_interface.s_addr = htonl(INADDR_ANY); > + if (localaddr != NULL) > + imr.imr_interface = *localaddr; > + else > + imr.imr_interface.s_addr = htonl(INADDR_ANY); > > ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, > (const char *)&imr, sizeof(struct ip_mreq)); > @@ -201,6 +204,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 +260,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 +480,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 +526,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 +546,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 +562,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 +574,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 +584,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