]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: server: make server_set_inetaddr() updater serializable
authorAurelien DARRAGON <adarragon@haproxy.com>
Mon, 11 Dec 2023 14:06:43 +0000 (15:06 +0100)
committerChristopher Faulet <cfaulet@haproxy.com>
Thu, 21 Dec 2023 13:22:27 +0000 (14:22 +0100)
server_set_inetaddr() updater argument is a simple char * string
containing infos about the caller responsible for the update.

In this patch, we try to make this argument serializable, that is, make
it so that we can easily export it without having to keep the original
pointer passed by the caller or having to work with strings of variable
lengths.

This was a prerequisite for exposing more updater information through
SERVER_INETADDR event (upcoming patch).

Static strings were simply mapped to a fixed ID that can be converted back
to a string when needed using server_inetaddr_updater_by_to_str(). One
special case one made for the SERVER_INETADDR_UPDATER_DNS_RESOLVER updater
since in this case the updater hint has to be generated from the
corresponding resolver id / nameserver id combination. This was achieved
by saving the nameserver id within the updater struct. Knowing that the
resolver id can be guessed from the server struct directly, it was not
exposed through the updater struct.

This patch depends on:
 - "MINOR: resolvers: add unique numeric id to nameservers"

No functional change should be expected.

include/haproxy/dns-t.h
include/haproxy/server-t.h
include/haproxy/server.h
src/hlua_fcn.c
src/resolvers.c
src/server.c

index 245169bc59da227a56f49072d5e51c9847c91404..255ad33e9195532ca1c8e27874323cb98196a8a9 100644 (file)
@@ -154,8 +154,9 @@ struct dns_nameserver {
 
 /* mixed dns and resolver counters, we will have to split them */
 struct dns_counters {
-       char *id;
-       char *pid;
+       char *id;               /* nameserver id */
+       char *pid;              /* parent resolver id */
+       unsigned int ns_puid;   /* nameserver numerical id (ns->puid) */
        long long sent;         /* - queries sent */
        long long snd_error;    /* - sending errors */
        union {
index 0108372c940a26cfd3ae6e1e943d62943b3e1d58..555eace61b1de16af9828cb660077ff9e2a1313e 100644 (file)
@@ -612,6 +612,49 @@ struct server_inetaddr {
        } port;
 };
 
+/* struct to store informations about server's addr / port updater in
+ * INET context
+ */
+enum server_inetaddr_updater_by {
+       SERVER_INETADDR_UPDATER_BY_NONE = 0,
+       SERVER_INETADDR_UPDATER_BY_CLI,
+       SERVER_INETADDR_UPDATER_BY_LUA,
+       SERVER_INETADDR_UPDATER_BY_DNS_AR,
+       SERVER_INETADDR_UPDATER_BY_DNS_CACHE,
+       SERVER_INETADDR_UPDATER_BY_DNS_RESOLVER,
+       /* changes here must be reflected in SERVER_INETADDR_UPDATER_*
+        * helper macros and in server_inetaddr_updater_by_to_str() func
+        */
+};
+struct server_inetaddr_updater {
+       enum server_inetaddr_updater_by by; // by identifier (unique)
+       union {
+               struct {
+                       unsigned int ns_id; // nameserver id responsible for the update
+               } dns_resolver;             // SERVER_INETADDR_UPDATER_DNS_RESOLVER specific infos
+       };                                  // per updater's additional ctx
+};
+#define SERVER_INETADDR_UPDATER_NONE                                           \
+ (struct server_inetaddr_updater){ .by = SERVER_INETADDR_UPDATER_BY_NONE }
+
+#define SERVER_INETADDR_UPDATER_CLI                                            \
+ (struct server_inetaddr_updater){ .by = SERVER_INETADDR_UPDATER_BY_CLI }
+
+#define SERVER_INETADDR_UPDATER_LUA                                            \
+ (struct server_inetaddr_updater){ .by = SERVER_INETADDR_UPDATER_BY_LUA }
+
+#define SERVER_INETADDR_UPDATER_DNS_AR                                         \
+ (struct server_inetaddr_updater){ .by = SERVER_INETADDR_UPDATER_BY_DNS_AR }
+
+#define SERVER_INETADDR_UPDATER_DNS_CACHE                                      \
+ (struct server_inetaddr_updater){ .by = SERVER_INETADDR_UPDATER_BY_DNS_CACHE }
+
+#define SERVER_INETADDR_UPDATER_DNS_RESOLVER(_ns_id)                           \
+ (struct server_inetaddr_updater){                                             \
+    .by = SERVER_INETADDR_UPDATER_BY_DNS_RESOLVER,                             \
+    .dns_resolver.ns_id = _ns_id,                                              \
+ }
+
 /* data provided to EVENT_HDL_SUB_SERVER_INETADDR handlers through
  * event_hdl facility
  *
index fe78e2b726a91beacf80ba212b38bbd771460661..22989915361596b70d9a3ed4b10dc3e4fac3241c 100644 (file)
@@ -47,12 +47,13 @@ int srv_lastsession(const struct server *s);
 int srv_getinter(const struct check *check);
 void srv_settings_cpy(struct server *srv, const struct server *src, int srv_tmpl);
 int parse_server(const char *file, int linenum, char **args, struct proxy *curproxy, const struct proxy *defproxy, int parse_flags);
-int srv_update_addr(struct server *s, void *ip, int ip_sin_family, const char *updater);
+int srv_update_addr(struct server *s, void *ip, int ip_sin_family, struct server_inetaddr_updater updater);
 int server_parse_sni_expr(struct server *newsrv, struct proxy *px, char **err);
-int server_set_inetaddr(struct server *s, const struct server_inetaddr *inetaddr, const char *updater, struct buffer *msg);
-int server_set_inetaddr_warn(struct server *s, const struct server_inetaddr *inetaddr, const char *updater);
+int server_set_inetaddr(struct server *s, const struct server_inetaddr *inetaddr, struct server_inetaddr_updater updater, struct buffer *msg);
+int server_set_inetaddr_warn(struct server *s, const struct server_inetaddr *inetaddr, struct server_inetaddr_updater updater);
 void server_get_inetaddr(struct server *s, struct server_inetaddr *inetaddr);
-const char *srv_update_addr_port(struct server *s, const char *addr, const char *port, char *updater);
+const char *srv_update_addr_port(struct server *s, const char *addr, const char *port, struct server_inetaddr_updater updater);
+const char *server_inetaddr_updater_by_to_str(enum server_inetaddr_updater_by by);
 const char *srv_update_check_addr_port(struct server *s, const char *addr, const char *port);
 const char *srv_update_agent_addr_port(struct server *s, const char *addr, const char *port);
 struct server *server_find_by_id(struct proxy *bk, int id);
index d8dcdfd1e6ebf3350b3f793ed9988f29be8a2807..a13e0f5f41cf408dcae7b0eb08fe97821047d704 100644 (file)
@@ -1513,7 +1513,7 @@ int hlua_server_set_addr(lua_State *L)
                port = NULL;
 
        HA_SPIN_LOCK(SERVER_LOCK, &srv->lock);
-       err = srv_update_addr_port(srv, addr, port, "Lua script");
+       err = srv_update_addr_port(srv, addr, port, SERVER_INETADDR_UPDATER_LUA);
        HA_SPIN_UNLOCK(SERVER_LOCK, &srv->lock);
        if (!err)
                lua_pushnil(L);
index 762b818a0778d296c4f304777a50fa1eb13f7f5c..8f219f19288df91fd8417646aaa4dd9d98e46164 100644 (file)
@@ -847,10 +847,10 @@ srv_found:
 
                                        switch (item->ar_item->type) {
                                                case DNS_RTYPE_A:
-                                                       srv_update_addr(srv, &item->ar_item->data.in4.sin_addr, AF_INET, "DNS additional record");
+                                                       srv_update_addr(srv, &item->ar_item->data.in4.sin_addr, AF_INET, SERVER_INETADDR_UPDATER_DNS_AR);
                                                break;
                                                case DNS_RTYPE_AAAA:
-                                                       srv_update_addr(srv, &item->ar_item->data.in6.sin6_addr, AF_INET6, "DNS additional record");
+                                                       srv_update_addr(srv, &item->ar_item->data.in6.sin6_addr, AF_INET6, SERVER_INETADDR_UPDATER_DNS_AR);
                                                break;
                                        }
 
@@ -2811,6 +2811,7 @@ int resolv_allocate_counters(struct list *stat_modules)
                                if (strcmp(mod->name, "resolvers") == 0) {
                                        ns->counters = (struct dns_counters *)ns->extra_counters->data + mod->counters_off[COUNTERS_RSLV];
                                        ns->counters->id = ns->id;
+                                       ns->counters->ns_puid = ns->puid;
                                        ns->counters->pid = resolvers->id;
                                }
                        }
index 1c8854af3c1e0d088705ca4f8504b141cf139cea..e9df3f416d7d60145828baa72ce9075b93274ef8 100644 (file)
@@ -3719,6 +3719,66 @@ void server_get_inetaddr(struct server *s, struct server_inetaddr *inetaddr)
        inetaddr->port.map = mapports;
 }
 
+/* get human readable name for server_inetaddr_updater .by struct member
+ */
+const char *server_inetaddr_updater_by_to_str(enum server_inetaddr_updater_by by)
+{
+       switch (by) {
+               case SERVER_INETADDR_UPDATER_BY_CLI:
+                       return "stats socket command";
+               case SERVER_INETADDR_UPDATER_BY_LUA:
+                       return "Lua script";
+               case SERVER_INETADDR_UPDATER_BY_DNS_AR:
+                       return "DNS additional record";
+               case SERVER_INETADDR_UPDATER_BY_DNS_CACHE:
+                       return "DNS cache";
+               case SERVER_INETADDR_UPDATER_BY_DNS_RESOLVER:
+                       return "DNS resolver";
+               default:
+                       /* unknown, don't mention updater */
+                       break;
+       }
+       return NULL;
+}
+
+/* append inetaddr updater info to chunk <out>
+ */
+static void _srv_append_inetaddr_updater_info(struct buffer *out,
+                                              struct server *s,
+                                              struct server_inetaddr_updater updater)
+{
+       switch (updater.by) {
+               case SERVER_INETADDR_UPDATER_BY_DNS_RESOLVER:
+                       /* we need to report the resolver/nameserver id which is
+                        * responsible for the update
+                        */
+                       {
+                               struct resolvers *r = s->resolvers;
+                               struct dns_nameserver *ns;
+
+                               /* we already know that the update comes from the
+                                * resolver section linked to the server, but we
+                                * need to find out which nameserver handled the dns
+                                * query
+                                */
+                               BUG_ON(!r);
+                               ns = find_nameserver_by_resolvers_and_id(r, updater.dns_resolver.ns_id);
+                               BUG_ON(!ns);
+                               chunk_appendf(out, " by '%s/%s'", r->id, ns->id);
+                       }
+                       break;
+               default:
+                       {
+                               const char *by_name;
+
+                               by_name = server_inetaddr_updater_by_to_str(updater.by);
+                               if (by_name)
+                                       chunk_appendf(out, " by '%s'", by_name);
+                       }
+                       break;
+       }
+}
+
 /* server_set_inetaddr() helper */
 static void _addr_to_str(int family, const void *addr, char *addr_str, size_t len)
 {
@@ -3784,7 +3844,7 @@ static int _inetaddr_addr_cmp(const struct server_inetaddr *inetaddr, const stru
  */
 int server_set_inetaddr(struct server *s,
                         const struct server_inetaddr *inetaddr,
-                        const char *updater, struct buffer *msg)
+                        struct server_inetaddr_updater updater, struct buffer *msg)
 {
        union {
                struct event_hdl_cb_data_server_inetaddr addr;
@@ -3893,8 +3953,8 @@ int server_set_inetaddr(struct server *s,
                ret = 1;
        }
 
-       if (ret && msg && updater)
-               chunk_appendf(msg, " by '%s'", updater);
+       if (ret && msg && updater.by != SERVER_INETADDR_UPDATER_BY_NONE)
+               _srv_append_inetaddr_updater_info(msg, s, updater);
        return ret;
 }
 
@@ -3906,7 +3966,7 @@ int server_set_inetaddr(struct server *s,
  */
 int server_set_inetaddr_warn(struct server *s,
                              const struct server_inetaddr *inetaddr,
-                             const char *updater)
+                             struct server_inetaddr_updater updater)
 {
        struct buffer *msg = get_trash_chunk();
        int ret;
@@ -3935,7 +3995,7 @@ int server_set_inetaddr_warn(struct server *s,
  *
  * Must be called with the server lock held.
  */
-int srv_update_addr(struct server *s, void *ip, int ip_sin_family, const char *updater)
+int srv_update_addr(struct server *s, void *ip, int ip_sin_family, struct server_inetaddr_updater updater)
 {
        struct server_inetaddr inetaddr;
 
@@ -4061,8 +4121,8 @@ out:
 /*
  * This function update a server's addr and port only for AF_INET and AF_INET6 families.
  *
- * Caller can pass its name through <updater> to get it integrated in the response message
- * returned by the function.
+ * Caller can pass its info through <updater> to get it integrated in the response
+ * message returned by the function.
  *
  * The function first does the following, in that order:
  * - checks that don't switch from/to a family other than AF_INET and AF_INET6
@@ -4071,7 +4131,8 @@ out:
  *
  * Must be called with the server lock held.
  */
-const char *srv_update_addr_port(struct server *s, const char *addr, const char *port, char *updater)
+const char *srv_update_addr_port(struct server *s, const char *addr, const char *port,
+                                 struct server_inetaddr_updater updater)
 {
        struct sockaddr_storage sa;
        struct server_inetaddr inetaddr;
@@ -4300,7 +4361,6 @@ int snr_resolution_cb(struct resolv_requester *requester, struct dns_counters *c
        void *serverip, *firstip;
        short server_sin_family, firstip_sin_family;
        int ret;
-       struct buffer *chk = get_trash_chunk();
        int has_no_ip = 0;
 
        s = objt_server(requester->owner);
@@ -4375,11 +4435,11 @@ int snr_resolution_cb(struct resolv_requester *requester, struct dns_counters *c
        if (counters) {
                counters->app.resolver.update++;
                /* save the first ip we found */
-               chunk_printf(chk, "%s/%s", counters->pid, counters->id);
+               srv_update_addr(s, firstip, firstip_sin_family,
+                               SERVER_INETADDR_UPDATER_DNS_RESOLVER(counters->ns_puid));
        }
        else
-               chunk_printf(chk, "DNS cache");
-       srv_update_addr(s, firstip, firstip_sin_family, (char *) chk->area);
+               srv_update_addr(s, firstip, firstip_sin_family, SERVER_INETADDR_UPDATER_DNS_CACHE);
 
  update_status:
        if (!snr_update_srv_status(s, has_no_ip) && has_no_ip)
@@ -5005,7 +5065,7 @@ static int cli_parse_set_server(char **args, char *payload, struct appctx *appct
                        port = args[6];
                }
                HA_SPIN_LOCK(SERVER_LOCK, &sv->lock);
-               warning = srv_update_addr_port(sv, addr, port, "stats socket command");
+               warning = srv_update_addr_port(sv, addr, port, SERVER_INETADDR_UPDATER_CLI);
                if (warning)
                        cli_msg(appctx, LOG_WARNING, warning);
                srv_clr_admin_flag(sv, SRV_ADMF_RMAINT);