Patchwork [v3] net: add the support for -netdev socket, listen

login
register
mail settings
Submitter Zhiyong Wu
Date June 4, 2012, 7:29 a.m.
Message ID <1338794993-4543-1-git-send-email-zwu.kernel@gmail.com>
Download mbox | patch
Permalink /patch/162664/
State New
Headers show

Comments

Zhiyong Wu - June 4, 2012, 7:29 a.m.
From: Zhi Yong Wu <wuzhy@linux.vnet.ibm.com>

The -net socket,listen option does not work with the newer -netdev
syntax:
 http://lists.gnu.org/archive/html/qemu-devel/2011-11/msg01508.html

This patch makes it work now.

For the case where one vlan has multiple listenning sockets,
the patch will also provide the support.

Supported syntax:
 1.) -net socket,listen=127.0.0.1:1234,vlan=0
 2.) -net socket,listen=127.0.0.1:1234,vlan=0 -net socket,listen=127.0.0.1:1235,vlan=0
 3.) -netdev socket,listen=127.0.0.1:1234,id=socket0

Suggested-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
Signed-off-by: Zhi Yong Wu <wuzhy@linux.vnet.ibm.com>
---
 net.c        |   24 ++++++++++++
 net.h        |    3 ++
 net/socket.c |  115 +++++++++++++++++++++++++++++++++++++++++++---------------
 3 files changed, 113 insertions(+), 29 deletions(-)

Patch

diff --git a/net.c b/net.c
index 1922d8a..0114537 100644
--- a/net.c
+++ b/net.c
@@ -190,6 +190,30 @@  static ssize_t qemu_deliver_packet_iov(VLANClientState *sender,
                                        int iovcnt,
                                        void *opaque);
 
+VLANClientState *qemu_lookup_net_client(VLANState *vlan,
+                                        const char *name)
+{
+    VLANClientState *vc = NULL;
+
+    if (vlan) {
+        QTAILQ_FOREACH(vc, &vlan->clients, next) {
+            if ((vc->info->type == NET_CLIENT_TYPE_SOCKET)
+                && (!vc->consumed)) {
+                return vc;
+            }
+        }
+    } else {
+        QTAILQ_FOREACH(vc, &non_vlan_clients, next) {
+            if (!strcmp(vc->name, name)
+                && (!vc->consumed)) {
+                return vc;
+            }
+        }
+    }
+
+    return NULL;
+}
+
 VLANClientState *qemu_new_net_client(NetClientInfo *info,
                                      VLANState *vlan,
                                      VLANClientState *peer,
diff --git a/net.h b/net.h
index 64993b4..6033f43 100644
--- a/net.h
+++ b/net.h
@@ -72,6 +72,7 @@  struct VLANClientState {
     char *name;
     char info_str[256];
     unsigned receive_disabled : 1;
+    bool consumed;
 };
 
 typedef struct NICState {
@@ -90,6 +91,8 @@  struct VLANState {
 
 VLANState *qemu_find_vlan(int id, int allocate);
 VLANClientState *qemu_find_netdev(const char *id);
+VLANClientState *qemu_lookup_net_client(VLANState *vlan,
+                                        const char *name);
 VLANClientState *qemu_new_net_client(NetClientInfo *info,
                                      VLANState *vlan,
                                      VLANClientState *peer,
diff --git a/net/socket.c b/net/socket.c
index 0bcf229..459b6a8 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -32,6 +32,10 @@ 
 #include "qemu-option.h"
 #include "qemu_socket.h"
 
+#define NET_SOCKET_CONNECT        0x0001
+#define NET_SOCKET_LISTEN         0x0002
+#define NET_SOCKET_CREATE         0x0004
+
 typedef struct NetSocketState {
     VLANClientState nc;
     int fd;
@@ -47,6 +51,7 @@  typedef struct NetSocketListenState {
     char *model;
     char *name;
     int fd;
+    bool consumed;
 } NetSocketListenState;
 
 /* XXX: we consider we can send the whole packet without blocking */
@@ -247,7 +252,7 @@  static NetClientInfo net_dgram_socket_info = {
 static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan,
                                                 const char *model,
                                                 const char *name,
-                                                int fd, int is_connected)
+                                                int fd, int flag)
 {
     struct sockaddr_in saddr;
     int newfd;
@@ -260,7 +265,7 @@  static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan,
      * by ONLY ONE process: we must "clone" this dgram socket --jjo
      */
 
-    if (is_connected) {
+    if (flag & NET_SOCKET_CONNECT) {
         if (getsockname(fd, (struct sockaddr *) &saddr, &saddr_len) == 0) {
             /* must be bound */
             if (saddr.sin_addr.s_addr == 0) {
@@ -286,21 +291,36 @@  static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan,
         }
     }
 
-    nc = qemu_new_net_client(&net_dgram_socket_info, vlan, NULL, model, name);
+
+    if (flag & NET_SOCKET_CREATE) {
+        nc = qemu_new_net_client(&net_dgram_socket_info,
+                                 vlan, NULL, model, name);
+    } else {
+        nc = qemu_lookup_net_client(vlan, name);
+        if (!nc) {
+            goto err;
+        }
+    }
+
+    s = DO_UPCAST(NetSocketState, nc, nc);
+
+    if (flag & NET_SOCKET_LISTEN) {
+        return s;
+    }
 
     snprintf(nc->info_str, sizeof(nc->info_str),
             "socket: fd=%d (%s mcast=%s:%d)",
-            fd, is_connected ? "cloned" : "",
+            fd, flag & NET_SOCKET_CONNECT ? "cloned" : "",
             inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
 
-    s = DO_UPCAST(NetSocketState, nc, nc);
-
     s->fd = fd;
 
     qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s);
 
     /* mcast: save bound address as dst */
-    if (is_connected) s->dgram_dst=saddr;
+    if (flag & NET_SOCKET_CONNECT) {
+        s->dgram_dst = saddr;
+    }
 
     return s;
 
@@ -325,20 +345,31 @@  static NetClientInfo net_socket_info = {
 static NetSocketState *net_socket_fd_init_stream(VLANState *vlan,
                                                  const char *model,
                                                  const char *name,
-                                                 int fd, int is_connected)
+                                                 int fd, int flag)
 {
     VLANClientState *nc;
     NetSocketState *s;
 
-    nc = qemu_new_net_client(&net_socket_info, vlan, NULL, model, name);
-
-    snprintf(nc->info_str, sizeof(nc->info_str), "socket: fd=%d", fd);
+    if (flag & NET_SOCKET_CREATE) {
+        nc = qemu_new_net_client(&net_socket_info, vlan, NULL, model, name);
+    } else {
+        nc = qemu_lookup_net_client(vlan, name);
+        if (!nc) {
+            return NULL;
+        }
+    }
 
     s = DO_UPCAST(NetSocketState, nc, nc);
 
+    if (flag & NET_SOCKET_LISTEN) {
+        return s;
+    }
+
+    snprintf(nc->info_str, sizeof(nc->info_str), "socket: fd=%d", fd);
+
     s->fd = fd;
 
-    if (is_connected) {
+    if (flag & NET_SOCKET_CONNECT) {
         net_socket_connect(s);
     } else {
         qemu_set_fd_handler(s->fd, NULL, net_socket_connect, s);
@@ -348,7 +379,7 @@  static NetSocketState *net_socket_fd_init_stream(VLANState *vlan,
 
 static NetSocketState *net_socket_fd_init(VLANState *vlan,
                                           const char *model, const char *name,
-                                          int fd, int is_connected)
+                                          int fd, int flag)
 {
     int so_type = -1, optlen=sizeof(so_type);
 
@@ -361,13 +392,13 @@  static NetSocketState *net_socket_fd_init(VLANState *vlan,
     }
     switch(so_type) {
     case SOCK_DGRAM:
-        return net_socket_fd_init_dgram(vlan, model, name, fd, is_connected);
+        return net_socket_fd_init_dgram(vlan, model, name, fd, flag);
     case SOCK_STREAM:
-        return net_socket_fd_init_stream(vlan, model, name, fd, is_connected);
+        return net_socket_fd_init_stream(vlan, model, name, fd, flag);
     default:
         /* who knows ... this could be a eg. a pty, do warn and continue as stream */
         fprintf(stderr, "qemu: warning: socket type=%d for fd=%d is not SOCK_DGRAM or SOCK_STREAM\n", so_type, fd);
-        return net_socket_fd_init_stream(vlan, model, name, fd, is_connected);
+        return net_socket_fd_init_stream(vlan, model, name, fd, flag);
     }
     return NULL;
 }
@@ -378,9 +409,13 @@  static void net_socket_accept(void *opaque)
     NetSocketState *s1;
     struct sockaddr_in saddr;
     socklen_t len;
-    int fd;
+    int fd, flag = 0;
 
     for(;;) {
+        if (s->consumed) {
+            return;
+        }
+
         len = sizeof(saddr);
         fd = qemu_accept(s->fd, (struct sockaddr *)&saddr, &len);
         if (fd < 0 && errno != EINTR) {
@@ -389,11 +424,17 @@  static void net_socket_accept(void *opaque)
             break;
         }
     }
-    s1 = net_socket_fd_init(s->vlan, s->model, s->name, fd, 1);
+
+    flag |= NET_SOCKET_CONNECT;
+    flag &= ~NET_SOCKET_LISTEN & ~NET_SOCKET_CREATE;
+    s1 = net_socket_fd_init(s->vlan, s->model, s->name, fd, flag);
     if (s1) {
+        s->consumed = true;
         snprintf(s1->nc.info_str, sizeof(s1->nc.info_str),
                  "socket: connection from %s:%d",
                  inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
+        s1->nc.link_down = false;
+        s1->nc.consumed = true;
     }
 }
 
@@ -403,8 +444,9 @@  static int net_socket_listen_init(VLANState *vlan,
                                   const char *host_str)
 {
     NetSocketListenState *s;
-    int fd, val, ret;
+    int fd, val, ret, flag = 0;
     struct sockaddr_in saddr;
+    NetSocketState *ns;
 
     if (parse_host_port(&saddr, host_str) < 0)
         return -1;
@@ -441,6 +483,12 @@  static int net_socket_listen_init(VLANState *vlan,
     s->model = g_strdup(model);
     s->name = name ? g_strdup(name) : NULL;
     s->fd = fd;
+
+    flag &= ~NET_SOCKET_CONNECT;
+    flag |= NET_SOCKET_LISTEN | NET_SOCKET_CREATE;
+    ns = net_socket_fd_init(s->vlan, s->model, s->name, fd, flag);
+    ns->nc.link_down = true;
+
     qemu_set_fd_handler(fd, net_socket_accept, NULL, s);
     return 0;
 }
@@ -451,7 +499,7 @@  static int net_socket_connect_init(VLANState *vlan,
                                    const char *host_str)
 {
     NetSocketState *s;
-    int fd, connected, ret, err;
+    int fd, ret, err, flag = 0;
     struct sockaddr_in saddr;
 
     if (parse_host_port(&saddr, host_str) < 0)
@@ -464,7 +512,7 @@  static int net_socket_connect_init(VLANState *vlan,
     }
     socket_set_nonblock(fd);
 
-    connected = 0;
+    flag &= ~NET_SOCKET_CONNECT;
     for(;;) {
         ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));
         if (ret < 0) {
@@ -482,11 +530,14 @@  static int net_socket_connect_init(VLANState *vlan,
                 return -1;
             }
         } else {
-            connected = 1;
+            flag |= NET_SOCKET_CONNECT;
             break;
         }
     }
-    s = net_socket_fd_init(vlan, model, name, fd, connected);
+
+    flag |= NET_SOCKET_CREATE;
+    flag &= ~NET_SOCKET_LISTEN;
+    s = net_socket_fd_init(vlan, model, name, fd, flag);
     if (!s)
         return -1;
     snprintf(s->nc.info_str, sizeof(s->nc.info_str),
@@ -502,7 +553,7 @@  static int net_socket_mcast_init(VLANState *vlan,
                                  const char *localaddr_str)
 {
     NetSocketState *s;
-    int fd;
+    int fd, flag = 0;
     struct sockaddr_in saddr;
     struct in_addr localaddr, *param_localaddr;
 
@@ -521,7 +572,9 @@  static int net_socket_mcast_init(VLANState *vlan,
     if (fd < 0)
         return -1;
 
-    s = net_socket_fd_init(vlan, model, name, fd, 0);
+    flag |= NET_SOCKET_CREATE;
+    flag &= ~NET_SOCKET_CONNECT & ~NET_SOCKET_LISTEN;
+    s = net_socket_fd_init(vlan, model, name, fd, flag);
     if (!s)
         return -1;
 
@@ -541,7 +594,7 @@  static int net_socket_udp_init(VLANState *vlan,
                                  const char *lhost)
 {
     NetSocketState *s;
-    int fd, val, ret;
+    int fd, val, ret, flag = 0;
     struct sockaddr_in laddr, raddr;
 
     if (parse_host_port(&laddr, lhost) < 0) {
@@ -572,7 +625,9 @@  static int net_socket_udp_init(VLANState *vlan,
         return -1;
     }
 
-    s = net_socket_fd_init(vlan, model, name, fd, 0);
+    flag |= NET_SOCKET_CREATE;
+    flag &= ~NET_SOCKET_CONNECT & ~NET_SOCKET_LISTEN;
+    s = net_socket_fd_init(vlan, model, name, fd, flag);
     if (!s) {
         return -1;
     }
@@ -591,7 +646,7 @@  int net_init_socket(QemuOpts *opts,
                     VLANState *vlan)
 {
     if (qemu_opt_get(opts, "fd")) {
-        int fd;
+        int fd, flag = 0;
 
         if (qemu_opt_get(opts, "listen") ||
             qemu_opt_get(opts, "connect") ||
@@ -606,7 +661,9 @@  int net_init_socket(QemuOpts *opts,
             return -1;
         }
 
-        if (!net_socket_fd_init(vlan, "socket", name, fd, 1)) {
+        flag |= NET_SOCKET_CREATE | NET_SOCKET_CONNECT;
+        flag &= ~NET_SOCKET_LISTEN;
+        if (!net_socket_fd_init(vlan, "socket", name, fd, flag)) {
             return -1;
         }
     } else if (qemu_opt_get(opts, "listen")) {