提交 3a75e74c 编写于 作者: M Mike Ryan 提交者: Michael S. Tsirkin

net/sock: option to specify local address

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: NMike Ryan <mikeryan@ISI.EDU>
Signed-off-by: NMichael S. Tsirkin <mst@redhat.com>
上级 138b38b6
...@@ -1050,6 +1050,10 @@ static const struct { ...@@ -1050,6 +1050,10 @@ static const struct {
.name = "mcast", .name = "mcast",
.type = QEMU_OPT_STRING, .type = QEMU_OPT_STRING,
.help = "UDP multicast address and port number", .help = "UDP multicast address and port number",
}, {
.name = "localaddr",
.type = QEMU_OPT_STRING,
.help = "source address for multicast packets",
}, },
{ /* end of list */ } { /* end of list */ }
}, },
......
...@@ -149,7 +149,7 @@ static void net_socket_send_dgram(void *opaque) ...@@ -149,7 +149,7 @@ static void net_socket_send_dgram(void *opaque)
qemu_send_packet(&s->nc, s->buf, size); 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; struct ip_mreq imr;
int fd; int fd;
...@@ -183,7 +183,11 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr) ...@@ -183,7 +183,11 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr)
/* Add host to multicast group */ /* Add host to multicast group */
imr.imr_multiaddr = mcastaddr->sin_addr; 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, ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
(const char *)&imr, sizeof(struct ip_mreq)); (const char *)&imr, sizeof(struct ip_mreq));
...@@ -201,6 +205,15 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr) ...@@ -201,6 +205,15 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr)
goto fail; 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); socket_set_nonblock(fd);
return fd; return fd;
fail: fail:
...@@ -248,7 +261,7 @@ static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, ...@@ -248,7 +261,7 @@ static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan,
return NULL; return NULL;
} }
/* clone dgram socket */ /* clone dgram socket */
newfd = net_socket_mcast_create(&saddr); newfd = net_socket_mcast_create(&saddr, NULL);
if (newfd < 0) { if (newfd < 0) {
/* error already reported by net_socket_mcast_create() */ /* error already reported by net_socket_mcast_create() */
close(fd); close(fd);
...@@ -468,17 +481,26 @@ static int net_socket_connect_init(VLANState *vlan, ...@@ -468,17 +481,26 @@ static int net_socket_connect_init(VLANState *vlan,
static int net_socket_mcast_init(VLANState *vlan, static int net_socket_mcast_init(VLANState *vlan,
const char *model, const char *model,
const char *name, const char *name,
const char *host_str) const char *host_str,
const char *localaddr_str)
{ {
NetSocketState *s; NetSocketState *s;
int fd; int fd;
struct sockaddr_in saddr; struct sockaddr_in saddr;
struct in_addr localaddr, *param_localaddr;
if (parse_host_port(&saddr, host_str) < 0) if (parse_host_port(&saddr, host_str) < 0)
return -1; 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) if (fd < 0)
return -1; return -1;
...@@ -505,8 +527,9 @@ int net_init_socket(QemuOpts *opts, ...@@ -505,8 +527,9 @@ int net_init_socket(QemuOpts *opts,
if (qemu_opt_get(opts, "listen") || if (qemu_opt_get(opts, "listen") ||
qemu_opt_get(opts, "connect") || qemu_opt_get(opts, "connect") ||
qemu_opt_get(opts, "mcast")) { qemu_opt_get(opts, "mcast") ||
error_report("listen=, connect= and mcast= is invalid with fd="); qemu_opt_get(opts, "localaddr")) {
error_report("listen=, connect=, mcast= and localaddr= is invalid with fd=\n");
return -1; return -1;
} }
...@@ -524,8 +547,9 @@ int net_init_socket(QemuOpts *opts, ...@@ -524,8 +547,9 @@ int net_init_socket(QemuOpts *opts,
if (qemu_opt_get(opts, "fd") || if (qemu_opt_get(opts, "fd") ||
qemu_opt_get(opts, "connect") || qemu_opt_get(opts, "connect") ||
qemu_opt_get(opts, "mcast")) { qemu_opt_get(opts, "mcast") ||
error_report("fd=, connect= and mcast= is invalid with listen="); qemu_opt_get(opts, "localaddr")) {
error_report("fd=, connect=, mcast= and localaddr= is invalid with listen=\n");
return -1; return -1;
} }
...@@ -539,8 +563,9 @@ int net_init_socket(QemuOpts *opts, ...@@ -539,8 +563,9 @@ int net_init_socket(QemuOpts *opts,
if (qemu_opt_get(opts, "fd") || if (qemu_opt_get(opts, "fd") ||
qemu_opt_get(opts, "listen") || qemu_opt_get(opts, "listen") ||
qemu_opt_get(opts, "mcast")) { qemu_opt_get(opts, "mcast") ||
error_report("fd=, listen= and mcast= is invalid with connect="); qemu_opt_get(opts, "localaddr")) {
error_report("fd=, listen=, mcast= and localaddr= is invalid with connect=\n");
return -1; return -1;
} }
...@@ -550,7 +575,7 @@ int net_init_socket(QemuOpts *opts, ...@@ -550,7 +575,7 @@ int net_init_socket(QemuOpts *opts,
return -1; return -1;
} }
} else if (qemu_opt_get(opts, "mcast")) { } else if (qemu_opt_get(opts, "mcast")) {
const char *mcast; const char *mcast, *localaddr;
if (qemu_opt_get(opts, "fd") || if (qemu_opt_get(opts, "fd") ||
qemu_opt_get(opts, "connect") || qemu_opt_get(opts, "connect") ||
...@@ -560,8 +585,9 @@ int net_init_socket(QemuOpts *opts, ...@@ -560,8 +585,9 @@ int net_init_socket(QemuOpts *opts,
} }
mcast = qemu_opt_get(opts, "mcast"); 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; return -1;
} }
} else { } else {
......
...@@ -1061,8 +1061,9 @@ DEF("net", HAS_ARG, QEMU_OPTION_net, ...@@ -1061,8 +1061,9 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
#endif #endif
"-net socket[,vlan=n][,name=str][,fd=h][,listen=[host]:port][,connect=host:port]\n" "-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" " 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" " 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 #ifdef CONFIG_VDE
"-net vde[,vlan=n][,name=str][,sock=socketpath][,port=n][,group=groupname][,mode=octalmode]\n" "-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" " 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 \ ...@@ -1256,7 +1257,7 @@ qemu linux.img -net nic,macaddr=52:54:00:12:34:57 \
-net socket,connect=127.0.0.1:1234 -net socket,connect=127.0.0.1:1234
@end example @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 Create a VLAN @var{n} shared with another QEMU virtual
machines using a UDP multicast socket, effectively making a bus for 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 \ ...@@ -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 /path/to/linux ubd0=/path/to/root_fs eth0=mcast
@end example @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}] @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 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} listening for incoming connections on @var{socketpath}. Use GROUP @var{groupname}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册