]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: server/event_hdl: add support for SERVER_ADD and SERVER_DEL events
authorAurelien DARRAGON <adarragon@haproxy.com>
Thu, 17 Nov 2022 09:37:58 +0000 (10:37 +0100)
committerChristopher Faulet <cfaulet@haproxy.com>
Tue, 6 Dec 2022 09:22:07 +0000 (10:22 +0100)
Basic support for ADD and DEL server events are added through this commit:
SERVER_ADD is published on dynamic server addition through cli.
SERVER_DEL is published on dynamic server deletion through cli.

This work depends on:
"MINOR: event_hdl: add event handler base api"
"MINOR: server: add srv->rid (revision id) value"

include/haproxy/server-t.h
src/server.c

index dd42807d8c8b3a1ddd94b4b1e61e225dd0fa9815..dd1a3afa0d494e32e9e31b829b96c32a4d56a1b8 100644 (file)
@@ -40,6 +40,7 @@
 #include <haproxy/stats-t.h>
 #include <haproxy/task-t.h>
 #include <haproxy/thread-t.h>
+#include <haproxy/event_hdl-t.h>
 
 
 /* server states. Only SRV_ST_STOPPED indicates a down server. */
@@ -403,6 +404,8 @@ struct server {
        } op_st_chg;                            /* operational status change's reason */
        char adm_st_chg_cause[48];              /* administrative status change's cause */
 
+       event_hdl_sub_list e_subs;              /* event_hdl: server's subscribers list (atomically updated) */
+
        /* warning, these structs are huge, keep them at the bottom */
        struct conn_src conn_src;               /* connection source settings */
        struct sockaddr_storage addr;           /* the address to connect to, doesn't include the port */
@@ -411,6 +414,35 @@ struct server {
        EXTRA_COUNTERS(extra_counters);
 };
 
+/* data provided to EVENT_HDL_SUB_SERVER handlers through event_hdl facility */
+struct event_hdl_cb_data_server {
+       /* provided by:
+        *   EVENT_HDL_SUB_SERVER_ADD
+        *   EVENT_HDL_SUB_SERVER_DOWN
+        */
+       struct {
+               /* safe data can be safely used from both
+                * sync and async handlers
+                * data consistency is guaranteed
+                */
+               char name[64];       /* server name/id */
+               char proxy_name[64]; /* id of proxy the server belongs to */
+               int puid;            /* proxy-unique server ID */
+               int rid;             /* server id revision */
+               unsigned int flags;  /* server flags */
+       } safe;
+       struct {
+               /* unsafe data may only be used from sync handlers:
+                * in async mode, data consistency cannot be guaranteed
+                * and unsafe data may already be stale, thus using
+                * it is highly discouraged because it
+                * could lead to undefined behavior (UAF, null dereference...)
+                */
+               struct server *ptr;     /* server live ptr */
+               /* lock hints */
+               uint8_t thread_isolate; /* 1 = thread_isolate is on, no locking required */
+       } unsafe;
+};
 
 /* Storage structure to load server-state lines from a flat file into
  * an ebtree, for faster processing
index bc8d0cba5479f10be18e9b358c1c6495b58cb3f8..eddaf9107bb20db7a97e1ef862c0e46c2476e326 100644 (file)
@@ -47,6 +47,7 @@
 #include <haproxy/time.h>
 #include <haproxy/tools.h>
 #include <haproxy/xxhash.h>
+#include <haproxy/event_hdl.h>
 
 
 static void srv_update_status(struct server *s);
@@ -132,6 +133,33 @@ int srv_getinter(const struct check *check)
        return (check->fastinter)?(check->fastinter):(check->inter);
 }
 
+/*
+ * Use this to publish EVENT_HDL_SUB_SERVER family type event
+ * from srv facility
+ * Event will be published in both global subscription list and
+ * server dedicated subscription list
+ * server ptr must be valid
+ */
+static inline void srv_event_hdl_publish(struct event_hdl_sub_type event, struct server *srv, uint8_t thread_isolate)
+{
+       struct event_hdl_cb_data_server cb_data;
+
+       /* safe data assignments */
+       cb_data.safe.puid = srv->puid;
+       cb_data.safe.rid = srv->rid;
+       cb_data.safe.flags = srv->flags;
+       snprintf(cb_data.safe.name, sizeof(cb_data.safe.name), "%s", srv->id);
+       if (srv->proxy)
+               snprintf(cb_data.safe.proxy_name, sizeof(cb_data.safe.proxy_name), "%s", srv->proxy->id);
+       /* unsafe data assignments */
+       cb_data.unsafe.ptr = srv;
+       cb_data.unsafe.thread_isolate = thread_isolate;
+       /* publish in server dedicated sub list */
+       event_hdl_publish(&srv->e_subs, event, EVENT_HDL_CB_DATA(&cb_data));
+       /* publish in global subscription list */
+       event_hdl_publish(NULL, event, EVENT_HDL_CB_DATA(&cb_data));
+}
+
 /*
  * Check that we did not get a hash collision.
  * Unlikely, but it can happen. The server's proxy must be at least
@@ -2337,6 +2365,7 @@ struct server *new_server(struct proxy *proxy)
        LIST_APPEND(&servers_list, &srv->global_list);
        LIST_INIT(&srv->srv_rec_item);
        LIST_INIT(&srv->ip_rec_item);
+       event_hdl_sub_list_init(&srv->e_subs);
 
        srv->next_state = SRV_ST_RUNNING; /* early server setup */
        srv->last_change = now.tv_sec;
@@ -2419,6 +2448,7 @@ struct server *srv_drop(struct server *srv)
        HA_SPIN_DESTROY(&srv->lock);
 
        LIST_DELETE(&srv->global_list);
+       event_hdl_sub_list_destroy(&srv->e_subs);
 
        EXTRA_COUNTERS_FREE(srv->extra_counters);
 
@@ -4893,6 +4923,11 @@ static int cli_parse_add_server(char **args, char *payload, struct appctx *appct
         */
        srv->rid = (srv_id_reuse_cnt) ? (srv_id_reuse_cnt / 2) : 0;
 
+       /* adding server cannot fail when we reach this:
+        * publishing EVENT_HDL_SUB_SERVER_ADD
+        */
+       srv_event_hdl_publish(EVENT_HDL_SUB_SERVER_ADD, srv, 1);
+
        thread_release();
 
        /* Start the check task. The server must be fully initialized.
@@ -5020,6 +5055,11 @@ static int cli_parse_delete_server(char **args, char *payload, struct appctx *ap
                goto out;
        }
 
+       /* removing cannot fail anymore when we reach this:
+        * publishing EVENT_HDL_SUB_SERVER_DEL
+        */
+       srv_event_hdl_publish(EVENT_HDL_SUB_SERVER_DEL, srv, 1);
+
        /* remove srv from tracking list */
        if (srv->track)
                release_server_track(srv);