qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH 2/5] socket: Add a reconnect option.


From: Anthony Liguori
Subject: Re: [Qemu-devel] [PATCH 2/5] socket: Add a reconnect option.
Date: Mon, 01 Feb 2010 09:25:27 -0600
User-agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.5) Gecko/20091209 Fedora/3.0-4.fc12 Lightning/1.0pre Thunderbird/3.0

On 02/01/2010 07:34 AM, Ian Molton wrote:
        Add a reconnect option that allows sockets to reconnect (after a
specified delay) to the specified server. This makes the virtio-rng driver
useful in production environments where the EGD server may need to be restarted.

Signed-off-by: Ian Molton<address@hidden>

I went back and looked at the last series and found my feedback. I had suggested that instead of automatically reconnecting, a mechanism should be added for a user to initiate a reconnect.

Additionally, we should emit events upon disconnect through QMP (now that we have that functionality).

The main reason I dislike automatic reconnecting is that there is no correct way to handle the period of time while the VM is disconnected.

A user might want to pause the VM, trigger a live migration to a non-broken system, checkpoint the VM, etc.

Auto reconnecting is implementing a policy to handle the failure within QEMU which is not universally the correct choice. This isn't so bad except for the fact that you aren't providing the mechanisms for users to implement other policies which means they're stuck with this particular policy.

Regards,

Anthony Liguori

---
  qemu-char.c   |  159 +++++++++++++++++++++++++++++++++++++++++++--------------
  qemu-char.h   |    2 +
  qemu-config.c |    3 +
  vl.c          |    4 ++
  4 files changed, 129 insertions(+), 39 deletions(-)

diff --git a/qemu-char.c b/qemu-char.c
index 800ee6c..016afd0 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -1870,8 +1870,12 @@ typedef struct {
      int max_size;
      int do_telnetopt;
      int do_nodelay;
+    int reconnect;
      int is_unix;
      int msgfd;
+    QemuOpts *opts;
+    CharDriverState *chr;
+    int (*setup)(QemuOpts *opts);
  } TCPCharDriver;

  static void tcp_chr_accept(void *opaque);
@@ -2011,6 +2015,8 @@ static ssize_t tcp_chr_recv(CharDriverState *chr, char 
*buf, size_t len)
  }
  #endif

+static void qemu_chr_sched_reconnect(TCPCharDriver *s);
+
  static void tcp_chr_read(void *opaque)
  {
      CharDriverState *chr = opaque;
@@ -2030,10 +2036,16 @@ static void tcp_chr_read(void *opaque)
          if (s->listen_fd>= 0) {
              qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
          }
-        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+        if (!s->reconnect) {
+            qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+        }
          closesocket(s->fd);
          s->fd = -1;
-        qemu_chr_event(chr, CHR_EVENT_CLOSED);
+        if (s->reconnect) {
+            qemu_chr_sched_reconnect(s);
+        } else {
+            qemu_chr_event(chr, CHR_EVENT_CLOSED);
+        }
      } else if (size>  0) {
          if (s->do_telnetopt)
              tcp_chr_process_IAC_bytes(chr, s, buf,&size);
@@ -2133,11 +2145,92 @@ static void tcp_chr_close(CharDriverState *chr)
      qemu_chr_event(chr, CHR_EVENT_CLOSED);
  }

+static int qemu_chr_connect_socket(TCPCharDriver *s)
+{
+    QemuOpts *opts = s->opts;
+    int is_listen;
+    int fd;
+    int is_waitconnect;
+    int do_nodelay;
+
+    is_waitconnect = qemu_opt_get_bool(opts, "wait", 1);
+    is_listen      = qemu_opt_get_bool(opts, "server", 0);
+    do_nodelay     = !qemu_opt_get_bool(opts, "delay", 1);
+
+
+    fd = s->setup(s->opts);
+    if (fd<  0)
+        return 0;
+
+    if (!is_waitconnect)
+        socket_set_nonblock(fd);
+
+    if (is_listen) {
+        s->listen_fd = fd;
+        qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, s->chr);
+        if (is_waitconnect) {
+            printf("QEMU waiting for connection on: %s\n",
+                   s->chr->filename);
+            tcp_chr_accept(s->chr);
+            socket_set_nonblock(s->listen_fd);
+        }
+    } else {
+        s->fd = fd;
+        socket_set_nodelay(fd);
+        tcp_chr_connect(s->chr);
+    }
+
+    return 1;
+}
+
+static QLIST_HEAD(reconnect_list_head, reconnect_list_entry) rcl_head;
+
+typedef struct reconnect_list_entry {
+    TCPCharDriver *s;
+    uint64_t when;
+    QLIST_ENTRY(reconnect_list_entry) entries;
+} reconnect_list_entry;
+
+static void qemu_chr_sched_reconnect(TCPCharDriver *s)
+{
+    reconnect_list_entry *new = qemu_malloc(sizeof(*new));
+    struct timeval tv;
+
+    qemu_gettimeofday(&tv);
+    new->s = s;
+    new->when = (s->reconnect + tv.tv_sec) * 1000000 + tv.tv_usec;
+    QLIST_INSERT_HEAD(&rcl_head, new, entries);
+}
+
+void qemu_chr_reconnect(void)
+{
+    struct timeval tv;
+    uint64_t now;
+    reconnect_list_entry *np;
+
+    if (!rcl_head.lh_first)
+        return;
+
+    gettimeofday(&tv, NULL);
+    now = tv.tv_sec * 1000000 + tv.tv_usec;
+
+    for (np = rcl_head.lh_first; np != NULL; np = np->entries.le_next) {
+        if (np->when<= now) {
+            if (qemu_chr_connect_socket(np->s)) {
+                qemu_chr_event(np->s->chr, CHR_EVENT_RECONNECTED);
+                QLIST_REMOVE(np, entries);
+            }
+            else {
+                np->when += np->s->reconnect * 1000000;
+            }
+        }
+    }
+}
+
  static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
  {
      CharDriverState *chr = NULL;
      TCPCharDriver *s = NULL;
-    int fd = -1;
      int is_listen;
      int is_waitconnect;
      int do_nodelay;
@@ -2145,34 +2238,40 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts 
*opts)
      int is_telnet;

      is_listen      = qemu_opt_get_bool(opts, "server", 0);
+    is_unix        = qemu_opt_get(opts, "path") != NULL;
+
      is_waitconnect = qemu_opt_get_bool(opts, "wait", 1);
      is_telnet      = qemu_opt_get_bool(opts, "telnet", 0);
      do_nodelay     = !qemu_opt_get_bool(opts, "delay", 1);
-    is_unix        = qemu_opt_get(opts, "path") != NULL;
-    if (!is_listen)
+
+    if (!is_listen) {
          is_waitconnect = 0;
+    } else {
+        if (is_telnet)
+            s->do_telnetopt = 1;
+    }
+

-    chr = qemu_mallocz(sizeof(CharDriverState));
      s = qemu_mallocz(sizeof(TCPCharDriver));
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    s->opts = opts;
+
+    if (!is_listen&&  !is_telnet)
+        s->reconnect = qemu_opt_get_number(opts, "reconnect", 0);

      if (is_unix) {
          if (is_listen) {
-            fd = unix_listen_opts(opts);
+            s->setup = unix_listen_opts;
          } else {
-            fd = unix_connect_opts(opts);
+            s->setup = unix_connect_opts;
          }
      } else {
          if (is_listen) {
-            fd = inet_listen_opts(opts, 0);
+            s->setup = inet_listen_opts;
          } else {
-            fd = inet_connect_opts(opts);
+            s->setup = inet_connect_opts;
          }
      }
-    if (fd<  0)
-        goto fail;
-
-    if (!is_waitconnect)
-        socket_set_nonblock(fd);

      s->connected = 0;
      s->fd = -1;
@@ -2186,19 +2285,6 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts 
*opts)
      chr->chr_close = tcp_chr_close;
      chr->get_msgfd = tcp_get_msgfd;

-    if (is_listen) {
-        s->listen_fd = fd;
-        qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
-        if (is_telnet)
-            s->do_telnetopt = 1;
-
-    } else {
-        s->connected = 1;
-        s->fd = fd;
-        socket_set_nodelay(fd);
-        tcp_chr_connect(chr);
-    }
-
      /* for "info chardev" monitor command */
      chr->filename = qemu_malloc(256);
      if (is_unix) {
@@ -2215,19 +2301,14 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts 
*opts)
                   qemu_opt_get_bool(opts, "server", 0) ? ",server" : "");
      }

-    if (is_listen&&  is_waitconnect) {
-        printf("QEMU waiting for connection on: %s\n",
-               chr->filename);
-        tcp_chr_accept(chr);
-        socket_set_nonblock(s->listen_fd);
-    }
-    return chr;
+    s->chr = chr;
+
+    if(qemu_chr_connect_socket(s))
+        return chr;

- fail:
-    if (fd>= 0)
-        closesocket(fd);
-    qemu_free(s);
      qemu_free(chr);
+    qemu_free(s);
+
      return NULL;
  }

diff --git a/qemu-char.h b/qemu-char.h
index bcc0766..32bcfd7 100644
--- a/qemu-char.h
+++ b/qemu-char.h
@@ -15,6 +15,7 @@
  #define CHR_EVENT_MUX_IN  3 /* mux-focus was set to this terminal */
  #define CHR_EVENT_MUX_OUT 4 /* mux-focus will move on */
  #define CHR_EVENT_CLOSED  5 /* connection closed */
+#define CHR_EVENT_RECONNECTED  6 /* reconnect event */


  #define CHR_IOCTL_SERIAL_SET_PARAMS   1
@@ -75,6 +76,7 @@ CharDriverState *qemu_chr_open_opts(QemuOpts *opts,
                                      void (*init)(struct CharDriverState *s));
  CharDriverState *qemu_chr_open(const char *label, const char *filename, void 
(*init)(struct CharDriverState *s));
  void qemu_chr_close(CharDriverState *chr);
+void qemu_chr_reconnect(void);
  void qemu_chr_printf(CharDriverState *s, const char *fmt, ...);
  int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len);
  void qemu_chr_send_event(CharDriverState *s, int event);
diff --git a/qemu-config.c b/qemu-config.c
index c3203c8..a229350 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -144,6 +144,9 @@ QemuOptsList qemu_chardev_opts = {
          },{
              .name = "signal",
              .type = QEMU_OPT_BOOL,
+        },{
+            .name = "reconnect",
+            .type = QEMU_OPT_NUMBER,
          },
          { /* end if list */ }
      },
diff --git a/vl.c b/vl.c
index 6f1e1ab..bcd7d44 100644
--- a/vl.c
+++ b/vl.c
@@ -3719,6 +3719,10 @@ void main_loop_wait(int timeout)

      host_main_loop_wait(&timeout);

+    /* Reconnect any disconnected sockets, if necessary */
+
+    qemu_chr_reconnect();
+
      /* poll any events */
      /* XXX: separate device handlers from system ones */
      nfds = -1;





reply via email to

[Prev in Thread] Current Thread [Next in Thread]