All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH] QEMU multicast socket support v4 (UML mcast compatible)
@ 2005-12-13 22:57 JuanJo Ciarlante
  0 siblings, 0 replies; only message in thread
From: JuanJo Ciarlante @ 2005-12-13 22:57 UTC (permalink / raw)
  To: qemu-devel


[-- Attachment #1.1: Type: text/plain, Size: 2064 bytes --]

Hi!

Attached patch (against qemu CVS 2005-12-10) adds multicast support for 
QEMU socket transport, ie: run several stateless possibly non-local QEMUs 
on same virtual ethernet "BUS". 
User-mode-linux (UML) compatible (tested).

An excerpt from qemu-doc.texi:

  `-net socket[,vlan=n][,fd=h][,mcast=maddr:port]'
        Create a VLAN n shared with another QEMU virtual machines using
        a UDP multicast socket, effectively making a bus for every QEMU
        with same multicast address maddr and port. NOTES:
         1. Several QEMU can be running on different hosts and share same
            bus (assuming correct multicast setup for these hosts).
         2. mcast  support  is  compatible with User Mode Linux (argument
            `ethN=mcast'), see http://user-mode-linux.sf.net.
  Example:
	# launch one QEMU instance
	qemu linux.img -net nic,macaddr=52:54:00:12:34:56 -net socket,mcast=230.0.0.1:1234
	# launch another QEMU instance on same "bus"
	qemu linux.img -net nic,macaddr=52:54:00:12:34:57 -net socket,mcast=230.0.0.1:1234
	# launch yet another QEMU instance on same "bus"
	qemu linux.img -net nic,macaddr=52:54:00:12:34:58 -net socket,mcast=230.0.0.1:1234
  Example (User Mode Linux compat.):
	# launch QEMU instance (note mcast address selected is UML's default)
	qemu linux.img -net nic,macaddr=52:54:00:12:34:56 -net socket,mcast=239.192.168.1:1102
	# launch UML
   	/path/to/linux ubd0=/path/to/root_fs eth0=mcast

Available under GPLv2 from
  http://www.irrigacion.gov.ar/juanjo/qemu/


Changes
-------
v4 (2005-12-12):
	* Tested mcast user-mode-linux compatibility
	* Minor tweaks

v3 (2005-12-07):
	* correctly close fds if any socket syscall fails (ie. close'em don't leak'em ;)

v2 (2005-12-07):
	* 1st public release
	
EnjoY	

-- 
--Juanjo

#  Juan Jose Ciarlante (JuanJo) jjo ;at; mendoza.gov.ar                     #
#  GnuPG Public Key: gpg --keyserver wwwkeys.eu.pgp.net --recv-key 66727177 #
#   Key fingerprint: 0D2F 3E5D 8B5C 729E 0560  F453 A3F7 E249 6672 7177     #

[-- Attachment #1.2: qemu-socket_mcast.jjo.v4.diff --]
[-- Type: text/plain, Size: 9091 bytes --]

diff --git a/README.qemu-mcast b/README.qemu-mcast
new file mode 100644
index 0000000..4021be5
--- /dev/null
+++ b/README.qemu-mcast
@@ -0,0 +1,56 @@
+QEMU multicast support
+======================
+Author:   JuanJo Ciarlante jjo()um.edu.ar, juanjosec()gmail.com
+Date:     Mon Dec 12 12:38:11 ART 2005
+Keywords: qemu, socket, multicast, UDP, mcast, UML
+
+Attached patch (against qemu CVS 2005-12-10) adds multicast support for 
+QEMU socket transport, ie: run several stateless possibly non-local QEMUs 
+on same virtual ethernet "BUS". 
+User-mode-linux (UML) compatible (tested).
+
+An excerpt from qemu-doc.texi:
+
+  `-net socket[,vlan=n][,fd=h][,mcast=maddr:port]'
+        Create a VLAN n shared with another QEMU virtual machines using
+        a UDP multicast socket, effectively making a bus for every QEMU
+        with same multicast address maddr and port. NOTES:
+         1. Several QEMU can be running on different hosts and share same
+            bus (assuming correct multicast setup for these hosts).
+         2. mcast  support  is  compatible with User Mode Linux (argument
+            `ethN=mcast'), see http://user-mode-linux.sf.net.
+  Example:
+	# launch one QEMU instance
+	qemu linux.img -net nic,macaddr=52:54:00:12:34:56 -net socket,mcast=230.0.0.1:1234
+	# launch another QEMU instance on same "bus"
+	qemu linux.img -net nic,macaddr=52:54:00:12:34:57 -net socket,mcast=230.0.0.1:1234
+	# launch yet another QEMU instance on same "bus"
+	qemu linux.img -net nic,macaddr=52:54:00:12:34:58 -net socket,mcast=230.0.0.1:1234
+  Example (User Mode Linux compat.):
+	# launch QEMU instance (note mcast address selected is UML's default)
+	qemu linux.img -net nic,macaddr=52:54:00:12:34:56 -net socket,mcast=239.192.168.1:1102
+	# launch UML
+   	/path/to/linux ubd0=/path/to/root_fs eth0=mcast
+
+Available under GPLv2 from
+  http://www.irrigacion.gov.ar/juanjo/qemu/
+
+
+Changes
+-------
+v4 (2005-12-12):
+	* Tested mcast user-mode-linux compatibility
+	* Minor tweaks
+
+v3 (2005-12-07):
+	* correctly close fds if any socket syscall fails (ie. close'em don't leak'em ;)
+
+v2 (2005-12-07):
+	* 1st public release
+
+
+--Juanjo
+
+#  Juan Jose Ciarlante (JuanJo) jjo ;at; mendoza.gov.ar                     #
+#  GnuPG Public Key: gpg --keyserver wwwkeys.eu.pgp.net --recv-key 66727177 #
+#   Key fingerprint: 0D2F 3E5D 8B5C 729E 0560  F453 A3F7 E249 6672 7177     #
diff --git a/qemu-doc.texi b/qemu-doc.texi
index 7ec41f5..d630adf 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -293,6 +293,41 @@ qemu linux.img -net nic,macaddr=52:54:00
 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=n][,fd=h][,mcast=maddr:port]
+
+Create a VLAN @var{n} shared with another QEMU virtual
+machines using a UDP multicast socket, effectively making a bus for 
+every QEMU with same multicast address @var{maddr} and @var{port}.
+NOTES:
+@enumerate
+@item 
+Several QEMU can be running on different hosts and share same bus (assuming 
+correct multicast setup for these hosts).
+@item
+mcast support is compatible with User Mode Linux (argument @option{eth@var{N}=mcast}), see
+@url{user-mode-linux.sf.net}.
+@end enumerate
+
+
+Example:
+@example
+# launch one QEMU instance
+qemu linux.img -net nic,macaddr=52:54:00:12:34:56 -net socket,mcast=230.0.0.1:1234
+# launch another QEMU instance on same "bus"
+qemu linux.img -net nic,macaddr=52:54:00:12:34:57 -net socket,mcast=230.0.0.1:1234
+# launch yet another QEMU instance on same "bus"
+qemu linux.img -net nic,macaddr=52:54:00:12:34:58 -net socket,mcast=230.0.0.1:1234
+@end example
+
+Example (User Mode Linux compat.):
+@example
+# launch QEMU instance (note mcast address selected is UML's default)
+qemu linux.img -net nic,macaddr=52:54:00:12:34:56 -net socket,mcast=239.192.168.1:1102
+# launch UML
+/path/to/linux ubd0=/path/to/root_fs eth0=mcast
+@end example
+
+
 @item -net none
 Indicate that no network devices should be configured. It is used to
 override the default configuration which is activated if no
diff --git a/vl.c b/vl.c
index 4b1e72e..4492418 100644
--- a/vl.c
+++ b/vl.c
@@ -2131,8 +2131,17 @@ typedef struct NetSocketState {
     int index;
     int packet_len;
     uint8_t buf[4096];
+    struct sockaddr_in dgram_dst; /* contains inet host and port destination iff connectionless (SOCK_DGRAM) */
 } NetSocketState;
 
+static int qemu_socket_is_dgram(const struct NetSocketState *s)
+{
+    /* This could also be: getsockopt(s->fd, SOL_SOCKET, SO_TYPE, &opt, &optlen)
+     * but I would cost an extra syscall per write (DGRAM writes don't require sending pkt length)
+     */
+    return (s->dgram_dst.sin_addr.s_addr!=0);
+}
+
 typedef struct NetSocketListenState {
     VLANState *vlan;
     int fd;
@@ -2145,8 +2154,12 @@ static void net_socket_receive(void *opa
     uint32_t len;
     len = htonl(size);
 
-    unix_write(s->fd, (const uint8_t *)&len, sizeof(len));
-    unix_write(s->fd, buf, size);
+    if (qemu_socket_is_dgram(s)) {
+	sendto(s->fd, buf, size, 0, (struct sockaddr *)&s->dgram_dst, sizeof(s->dgram_dst));
+    } else {
+	unix_write(s->fd, (const uint8_t *)&len, sizeof(len));
+	unix_write(s->fd, buf, size);
+    }
 }
 
 static void net_socket_send(void *opaque)
@@ -2164,6 +2177,11 @@ static void net_socket_send(void *opaque
         qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
         return;
     }
+    if (qemu_socket_is_dgram(s)) {
+	s->index = 0;
+	s->state = 1;
+	s->packet_len = size;
+    }
     buf = buf1;
     while (size > 0) {
         /* reassemble a packet from the network */
@@ -2336,6 +2354,75 @@ static int net_socket_connect_init(VLANS
     return 0;
 }
 
+static int net_socket_mcast_init(VLANState *vlan, const char *host_str)
+{
+    NetSocketState *s;
+    int fd=-1, ret, val;
+    struct sockaddr_in saddr;
+    struct ip_mreq imr;
+
+    if (parse_host_port(&saddr, host_str) < 0)
+        return -1;
+
+    if (!IN_MULTICAST(ntohl(saddr.sin_addr.s_addr))) {
+	fprintf(stderr, "qemu: error: specified mcastaddr \"%s\" (0x%08x) does not contain a multicast address\n",
+		inet_ntoa(saddr.sin_addr), ntohl(saddr.sin_addr.s_addr));
+	return -1;
+
+    }
+    fd = socket(PF_INET, SOCK_DGRAM, 0);
+    if (fd < 0) {
+        perror("socket(PF_INET, SOCK_DGRAM)");
+        return -1;
+    }
+
+    /* Add host to multicast group */
+    imr.imr_multiaddr = saddr.sin_addr;
+    imr.imr_interface.s_addr = htonl(INADDR_ANY);
+
+    ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *) &imr, sizeof(struct ip_mreq));
+    if (ret < 0) {
+	perror("setsockopt(IP_ADD_MEMBERSHIP)");
+	goto fail;
+    }
+
+    /* Force mcast msgs to loopback (eg. several QEMUs in same host */
+    val = 1;
+    ret=setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &val, sizeof(val));
+    if (ret < 0) {
+	perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)");
+	goto fail;
+    }
+    ret=setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
+    if (ret < 0) {
+	perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)");
+	goto fail;
+    }
+    
+    ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr));
+    if (ret < 0) {
+        perror("bind");
+        goto fail;
+    }
+    
+    fcntl(fd, F_SETFL, O_NONBLOCK);
+
+    s = net_socket_fd_init(vlan, fd, 1);
+    if (!s)
+        goto fail;
+    
+    /* Connectionless: save mcast address for sendto() */
+    s->dgram_dst = saddr;
+
+    snprintf(s->vc->info_str, sizeof(s->vc->info_str),
+             "socket: mcast at %s:%d", 
+             inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
+    return 0;
+fail:
+    if (fd>=0) close(fd);
+    return -1;
+}
+
 #endif /* !_WIN32 */
 
 static int get_param_value(char *buf, int buf_size,
@@ -2472,6 +2559,8 @@ int net_client_init(const char *str)
             ret = net_socket_listen_init(vlan, buf);
         } else if (get_param_value(buf, sizeof(buf), "connect", p) > 0) {
             ret = net_socket_connect_init(vlan, buf);
+        } else if (get_param_value(buf, sizeof(buf), "mcast", p) > 0) {
+            ret = net_socket_mcast_init(vlan, buf);
         } else {
             fprintf(stderr, "Unknown socket options: %s\n", p);
             return -1;
@@ -3810,6 +3899,8 @@ void help(void)
            "                use 'fd=h' to connect to an already opened TAP interface\n"
            "-net socket[,vlan=n][,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][,fd=h][,mcast=maddr:port]\n"
+           "                create a vlan 'n' with another QEMUs on multicast maddr and port\n"
 #endif
            "-net none       use it alone to have zero network devices; if no -net option\n"
            "                is provided, the default is '-net nic -net user'\n"

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2005-12-13 22:55 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-12-13 22:57 [Qemu-devel] [PATCH] QEMU multicast socket support v4 (UML mcast compatible) JuanJo Ciarlante

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.