aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--net.c4
-rw-r--r--net/socket.c52
-rw-r--r--qemu-options.hx11
3 files changed, 52 insertions, 15 deletions
diff --git a/net.c b/net.c
index c5e6063fcf..9ba5be22dd 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 1c4e153e3f..916c2a8e10 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,11 @@ 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) {
+ 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 +205,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 +261,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 +481,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 +527,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 +547,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 +563,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 +575,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 +585,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 4d99a58fc5..accd16a55c 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[,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}[,localaddr=@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[,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}