]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: listeners: implement protocol level ->suspend/resume() calls
authorWilly Tarreau <w@1wt.eu>
Fri, 9 Oct 2020 15:02:21 +0000 (17:02 +0200)
committerWilly Tarreau <w@1wt.eu>
Fri, 9 Oct 2020 16:44:37 +0000 (18:44 +0200)
Now we have ->suspend() and ->resume() for listeners at the protocol
level. This means that it now becomes possible for a protocol to redefine
its own way to suspend and resume. The default functions are provided for
TCP, UDP and unix, and they are pass-through to the receiver equivalent
as it used to be till now. Nothing was defined for sockpair since it does
not need to suspend/resume during reloads, hence it will succeed.

include/haproxy/listener.h
include/haproxy/protocol-t.h
src/listener.c
src/proto_tcp.c
src/proto_udp.c
src/proto_uxst.c

index 399e2669a3f5432f7d5326f4e59ad1a4cd52a322..24a126c2fcbfc90b0f4029f101f259d662a73563 100644 (file)
@@ -130,6 +130,25 @@ void listener_release(struct listener *l);
  * still bound. This must be used under the listener's lock.
  */
 void default_unbind_listener(struct listener *listener);
+
+/* default function called to suspend a listener: it simply passes the call to
+ * the underlying receiver. This is find for most socket-based protocols. This
+ * must be called under the listener's lock. It will return non-zero on success,
+ * 0 on failure. If no receiver-level suspend is provided, the operation is
+ * assumed to succeed.
+ */
+int default_suspend_listener(struct listener *l);
+
+/* Tries to resume a suspended listener, and returns non-zero on success or
+ * zero on failure. On certain errors, an alert or a warning might be displayed.
+ * It must be called with the listener's lock held. Depending on the listener's
+ * state and protocol, a listen() call might be used to resume operations, or a
+ * call to the receiver's resume() function might be used as well. This is
+ * suitable as a default function for TCP and UDP. This must be called with the
+ * listener's lock held.
+ */
+int default_resume_listener(struct listener *l);
+
 /*
  * Registers the bind keyword list <kwl> as a list of valid keywords for next
  * parsing sessions.
index a7d2429899d1ed4747b4af3b803fd039a4b22aec..2dea7326ea7484e648ddcafccc5415589670f30a 100644 (file)
@@ -92,6 +92,8 @@ struct protocol {
        void (*enable)(struct listener *l);             /* enable receipt of new connections */
        void (*disable)(struct listener *l);            /* disable receipt of new connections */
        void (*unbind)(struct listener *l);             /* unbind the listener and possibly its receiver */
+       int (*suspend)(struct listener *l);             /* try to suspend the listener */
+       int (*resume)(struct listener *l);              /* try to resume a suspended listener */
 
        /* functions acting on the receiver */
        void (*rx_enable)(struct receiver *rx);         /* enable receiving on the receiver */
index 3e305c73a95ef0eba5498d0e04781d036730730a..1acf85f60c977d386ff6f53c2cadbcbf9c34da5d 100644 (file)
@@ -358,6 +358,65 @@ void stop_listener(struct listener *l, int lpx, int lpr, int lli)
                HA_SPIN_UNLOCK(PROXY_LOCK, &px->lock);
 }
 
+/* default function called to suspend a listener: it simply passes the call to
+ * the underlying receiver. This is find for most socket-based protocols. This
+ * must be called under the listener's lock. It will return non-zero on success,
+ * 0 on failure. If no receiver-level suspend is provided, the operation is
+ * assumed to succeed.
+ */
+int default_suspend_listener(struct listener *l)
+{
+       int ret = 1;
+
+       if (!l->rx.proto->rx_suspend)
+               return 1;
+
+       ret = l->rx.proto->rx_suspend(&l->rx);
+       return ret > 0 ? ret : 0;
+}
+
+
+/* Tries to resume a suspended listener, and returns non-zero on success or
+ * zero on failure. On certain errors, an alert or a warning might be displayed.
+ * It must be called with the listener's lock held. Depending on the listener's
+ * state and protocol, a listen() call might be used to resume operations, or a
+ * call to the receiver's resume() function might be used as well. This is
+ * suitable as a default function for TCP and UDP. This must be called with the
+ * listener's lock held.
+ */
+int default_resume_listener(struct listener *l)
+{
+       int ret = 1;
+
+       if (l->state == LI_ASSIGNED) {
+               char msg[100];
+               int err;
+
+               err = l->rx.proto->listen(l, msg, sizeof(msg));
+               if (err & ERR_ALERT)
+                       ha_alert("Resuming listener: %s\n", msg);
+               else if (err & ERR_WARN)
+                       ha_warning("Resuming listener: %s\n", msg);
+
+               if (err & (ERR_FATAL | ERR_ABORT)) {
+                       ret = 0;
+                       goto end;
+               }
+       }
+
+       if (l->state < LI_PAUSED) {
+               ret = 0;
+               goto end;
+       }
+
+       if (l->state == LI_PAUSED && l->rx.proto->rx_resume &&
+           l->rx.proto->rx_resume(&l->rx) <= 0)
+               ret = 0;
+ end:
+       return ret;
+}
+
+
 /* This function tries to temporarily disable a listener, depending on the OS
  * capabilities. Linux unbinds the listen socket after a SHUT_RD, and ignores
  * SHUT_WR. Solaris refuses either shutdown(). OpenBSD ignores SHUT_RD but
@@ -379,18 +438,8 @@ int pause_listener(struct listener *l)
        if (l->state <= LI_PAUSED)
                goto end;
 
-       if (l->rx.proto->rx_suspend) {
-               /* Returns < 0 in case of failure, 0 if the listener
-                * was totally stopped, or > 0 if correctly paused.
-                */
-               ret = l->rx.proto->rx_suspend(&l->rx);
-
-               if (ret < 0) {
-                       ret = 0;
-                       goto end;
-               }
-               ret = 1;
-       }
+       if (l->rx.proto->suspend)
+               ret = l->rx.proto->suspend(l);
 
        MT_LIST_DEL(&l->wait_queue);
 
@@ -436,32 +485,8 @@ int resume_listener(struct listener *l)
        if (l->state == LI_READY)
                goto end;
 
-       if (l->state == LI_ASSIGNED) {
-               char msg[100];
-               int err;
-
-               err = l->rx.proto->listen(l, msg, sizeof(msg));
-               if (err & ERR_ALERT)
-                       ha_alert("Resuming listener: %s\n", msg);
-               else if (err & ERR_WARN)
-                       ha_warning("Resuming listener: %s\n", msg);
-
-               if (err & (ERR_FATAL | ERR_ABORT)) {
-                       ret = 0;
-                       goto end;
-               }
-       }
-
-       if (l->state < LI_PAUSED) {
-               ret = 0;
-               goto end;
-       }
-
-       if (l->state == LI_PAUSED && l->rx.proto->rx_resume &&
-           l->rx.proto->rx_resume(&l->rx) <= 0) {
-               ret = 0;
-               goto end;
-       }
+       if (l->rx.proto->resume)
+               ret = l->rx.proto->resume(l);
 
        if (l->maxconn && l->nbconn >= l->maxconn) {
                l->rx.proto->disable(l);
index 71d13c8b772b64b8fc552a9713e4eb4fe697a5dd..9e6a3d7226035306a03e6fba9da6966f32de4107 100644 (file)
@@ -65,6 +65,8 @@ static struct protocol proto_tcpv4 = {
        .enable = tcp_enable_listener,
        .disable = tcp_disable_listener,
        .unbind = default_unbind_listener,
+       .suspend = default_suspend_listener,
+       .resume  = default_resume_listener,
        .rx_enable = sock_enable,
        .rx_disable = sock_disable,
        .rx_unbind = sock_unbind,
@@ -91,6 +93,8 @@ static struct protocol proto_tcpv6 = {
        .enable = tcp_enable_listener,
        .disable = tcp_disable_listener,
        .unbind = default_unbind_listener,
+       .suspend = default_suspend_listener,
+       .resume  = default_resume_listener,
        .rx_enable = sock_enable,
        .rx_disable = sock_disable,
        .rx_unbind = sock_unbind,
index 1c2477e719a7c256eb56e79fb11e3716e054967c..13545ad58ad04b227f4ad84ab0ff201ca054bb72 100644 (file)
@@ -61,6 +61,8 @@ static struct protocol proto_udp4 = {
        .enable = udp_enable_listener,
        .disable = udp_disable_listener,
        .unbind = default_unbind_listener,
+       .suspend = default_suspend_listener,
+       .resume  = default_resume_listener,
        .rx_enable = sock_enable,
        .rx_disable = sock_disable,
        .rx_unbind = sock_unbind,
@@ -85,6 +87,8 @@ static struct protocol proto_udp6 = {
        .enable = udp_enable_listener,
        .disable = udp_disable_listener,
        .unbind = default_unbind_listener,
+       .suspend = default_suspend_listener,
+       .resume  = default_resume_listener,
        .rx_enable = sock_enable,
        .rx_disable = sock_disable,
        .rx_unbind = sock_unbind,
index 04f12faa02299a825fb8c42a47cf0d5d858a1d75..047b75954c09644d1b9c7dce4545c2eceb2db7c3 100644 (file)
@@ -60,6 +60,7 @@ static struct protocol proto_unix = {
        .enable = uxst_enable_listener,
        .disable = uxst_disable_listener,
        .unbind = default_unbind_listener,
+       .suspend = default_suspend_listener,
        .rx_enable = sock_enable,
        .rx_disable = sock_disable,
        .rx_unbind = sock_unbind,