Here are my updates from the feedback.  It took me quite a while to figure out 
how to send this diff properly formatted with gmail.

If you would like a single patch with all my changes, I can send that as well.

>From 9c71b643e993dcafca36feae71cdfacc24ffaaa2 Mon Sep 17 00:00:00 2001
From: Thayne McCombs <[email protected]>
Date: Sat, 5 Dec 2020 23:09:24 -0700
Subject: [PATCH 1/2] Feedback from initial review

---
 doc/configuration.txt      |  4 ++--
 include/haproxy/dict.h     |  1 +
 include/haproxy/server-t.h |  1 -
 src/cfgparse-listen.c      |  1 +
 src/dict.c                 | 24 +++++++++++++++++++++-
 src/peers.c                |  7 ++++++-
 src/server.c               | 41 ++++++++++++++++++++------------------
 src/stick_table.c          |  8 ++++++++
 src/stream.c               |  2 +-
 src/tools.c                |  3 ++-
 10 files changed, 66 insertions(+), 26 deletions(-)

diff --git a/doc/configuration.txt b/doc/configuration.txt
index 95c9abd8c..d1f7374ea 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -10711,8 +10711,8 @@ stick-table type {ip | integer | string [len <length>] 
| binary [len <length>]}
     <srvkey>   specifies how each server is identified for the purposes of the
                stick table. The valid values are "name" and "addr". If "name" 
is
                given, then <name> argument for the server (may be generated by
-               a template). If "addr" is given, then the server is idntified
-               by it's current network address, including the port. "addr" is
+               a template). If "addr" is given, then the server is identified
+               by its current network address, including the port. "addr" is
                especially useful if you are using service discovery to generate
                the addresses for servers with peered stick-tables and want
                to consistently use the same host across peers for a stickiness
diff --git a/include/haproxy/dict.h b/include/haproxy/dict.h
index 59e81352c..c55834ca5 100644
--- a/include/haproxy/dict.h
+++ b/include/haproxy/dict.h
@@ -31,5 +31,6 @@
 
 struct dict *new_dict(const char *name);
 struct dict_entry *dict_insert(struct dict *d, char *str);
+void dict_entry_unref(struct dict *d, struct dict_entry *de);
 
 #endif  /* _HAPROXY_DICT_H */
diff --git a/include/haproxy/server-t.h b/include/haproxy/server-t.h
index 5a4dadfbd..13f5a5dab 100644
--- a/include/haproxy/server-t.h
+++ b/include/haproxy/server-t.h
@@ -274,7 +274,6 @@ struct server {
        const struct netns_entry *netns;        /* contains network namespace 
name or NULL. Network namespace comes from configuration */
        /* warning, these structs are huge, keep them at the bottom */
        struct sockaddr_storage addr;           /* the address to connect to, 
doesn't include the port */
-       char *addr_desc;                        /* string description of the 
address and port for the server */
        struct xprt_ops *xprt;                  /* transport-layer operations */
        unsigned int svc_port;                  /* the port to connect to (for 
relevant families) */
        unsigned down_time;                     /* total time the server was 
down */
diff --git a/src/cfgparse-listen.c b/src/cfgparse-listen.c
index 97a97e746..a493e741c 100644
--- a/src/cfgparse-listen.c
+++ b/src/cfgparse-listen.c
@@ -457,6 +457,7 @@ int cfg_parse_listen(const char *file, int linenum, char 
**args, int kwm)
                curproxy->grace  = defproxy.grace;
                curproxy->conf.used_listener_id = EB_ROOT;
                curproxy->conf.used_server_id = EB_ROOT;
+               curproxy->used_server_addr = EB_ROOT_UNIQUE;
 
                if (defproxy.check_path)
                        curproxy->check_path = strdup(defproxy.check_path);
diff --git a/src/dict.c b/src/dict.c
index 903f07323..9b3536d96 100644
--- a/src/dict.c
+++ b/src/dict.c
@@ -87,8 +87,10 @@ struct dict_entry *dict_insert(struct dict *d, char *s)
        HA_RWLOCK_RDLOCK(DICT_LOCK, &d->rwlock);
        de = __dict_lookup(d, s);
        HA_RWLOCK_RDUNLOCK(DICT_LOCK, &d->rwlock);
-       if (de)
+       if (de) {
+               HA_ATOMIC_ADD(&de->refcount, 1);
                return de;
+       }
 
        de = new_dict_entry(s);
        if (!de)
@@ -105,3 +107,23 @@ struct dict_entry *dict_insert(struct dict *d, char *s)
        return de;
 }
 
+
+/*
+ * Unreference a dict entry previously acquired with <dict_insert>.
+ * If this is the last live reference to the entry, it is
+ * removed from the dictionary.
+ */
+void dict_entry_unref(struct dict *d, struct dict_entry *de)
+{
+       if (!de)
+               return;
+
+       if (HA_ATOMIC_SUB(&de->refcount, 1) != 0)
+               return;
+
+       HA_RWLOCK_WRLOCK(DICT_LOCK, &d->rwlock);
+       ebpt_delete(&de->value);
+       HA_RWLOCK_WRUNLOCK(DICT_LOCK, &d->rwlock);
+
+       free_dict_entry(de);
+}
diff --git a/src/peers.c b/src/peers.c
index 3f4e2c575..3fa1a28b4 100644
--- a/src/peers.c
+++ b/src/peers.c
@@ -1634,12 +1634,15 @@ static int peer_treat_updatemsg(struct appctx *appctx, 
struct peer *p, int updt,
                                *msg_cur += value_len;
 
                                de = dict_insert(&server_key_dict, chunk->area);
+                               dict_entry_unref(&server_key_dict, dc->rx[id - 
1].de);
                                dc->rx[id - 1].de = de;
                        }
                        if (de) {
                                data_ptr = stktable_data_ptr(st->table, ts, 
data_type);
-                               if (data_ptr)
+                               if (data_ptr) {
+                                       HA_ATOMIC_ADD(&de->refcount, 1);
                                        stktable_data_cast(data_ptr, 
std_t_dict) = de;
+                               }
                        }
                        break;
                }
@@ -3059,6 +3062,8 @@ static inline void flush_dcache(struct peer *peer)
        for (i = 0; i < dc->max_entries; i++) {
                ebpt_delete(&dc->tx->entries[i]);
                dc->tx->entries[i].key = NULL;
+               dict_entry_unref(&server_key_dict, dc->rx[i].de);
+               dc->rx[i].de = NULL;
        }
        dc->tx->prev_lookup = NULL;
        dc->tx->lru_key = 0;
diff --git a/src/server.c b/src/server.c
index dc7a85052..ef536d718 100644
--- a/src/server.c
+++ b/src/server.c
@@ -193,6 +193,9 @@ void srv_set_dyncookie(struct server *s)
        HA_RWLOCK_RDUNLOCK(PROXY_LOCK, &p->lock);
 }
 
+/*
+ * Must be called with the server lock held, and will write-lock the proxy.
+ */
 static void srv_set_addr_desc(struct server *s)
 {
        struct proxy *p = s->proxy;
@@ -200,31 +203,26 @@ static void srv_set_addr_desc(struct server *s)
 
        key = sa2str(&s->addr, s->svc_port, s->flags & SRV_F_MAPPORTS);
 
-       if (strcmp(key, s->addr_desc) == 0) {
-               free(key);
-               return;
-       }
+       if (s->addr_node.key) {
+               if (strcmp(key, s->addr_node.key) == 0) {
+                       free(key);
+                       return;
+               }
 
-       HA_RWLOCK_WRLOCK(PROXY_LOCK, &p->lock);
-       ebpt_delete(&s->addr_node);
-       HA_RWLOCK_WRUNLOCK(PROXY_LOCK, &p->lock);
+               HA_RWLOCK_WRLOCK(PROXY_LOCK, &p->lock);
+               ebpt_delete(&s->addr_node);
+               HA_RWLOCK_WRUNLOCK(PROXY_LOCK, &p->lock);
+
+               free(s->addr_node.key);
+       }
 
-       free(s->addr_desc);
-       s->addr_desc = key;
        s->addr_node.key = key;
 
-       // TODO: should this use a dedicated lock?
        HA_RWLOCK_WRLOCK(PROXY_LOCK, &p->lock);
        ebis_insert(&p->used_server_addr, &s->addr_node);
        HA_RWLOCK_WRUNLOCK(PROXY_LOCK, &p->lock);
 }
 
-static void srv_addr_updated(struct server *srv)
-{
-       srv_set_dyncookie(srv);
-       srv_set_addr_desc(srv);
-}
-
 /*
  * Registers the server keyword list <kwl> as a list of valid keywords for next
  * parsing sessions.
@@ -2084,6 +2082,8 @@ int parse_server(const char *file, int linenum, char 
**args, struct proxy *curpr
 
                        newsrv->addr = *sk;
                        newsrv->svc_port = port;
+                       // we don't need to lock the server here, because
+                       // we are in the process of initializing
                        srv_set_addr_desc(newsrv);
 
                        if (!newsrv->srvrq && !newsrv->hostname && 
!protocol_by_family(newsrv->addr.ss_family)) {
@@ -3551,7 +3551,8 @@ int update_server_addr(struct server *s, void *ip, int 
ip_sin_family, const char
                memcpy(((struct sockaddr_in6 *)&s->addr)->sin6_addr.s6_addr, 
ip, 16);
                break;
        };
-       srv_addr_updated(s);
+       srv_set_dyncookie(s);
+       srv_set_addr_desc(s);
 
        return 0;
 }
@@ -3723,7 +3724,8 @@ out:
        if (changed) {
                /* force connection cleanup on the given server */
                srv_cleanup_connections(s);
-               srv_addr_updated(s);
+               srv_set_dyncookie(s);
+               srv_set_addr_desc(s);
        }
        if (updater)
                chunk_appendf(msg, " by '%s'", updater);
@@ -4203,7 +4205,8 @@ static int srv_iterate_initaddr(struct server *srv)
        return_code |= ERR_ALERT | ERR_FATAL;
        return return_code;
 out:
-       srv_addr_updated(srv);
+       srv_set_dyncookie(srv);
+       srv_set_addr_desc(srv);
        return return_code;
 }
 
diff --git a/src/stick_table.c b/src/stick_table.c
index abdf229fb..825005c2e 100644
--- a/src/stick_table.c
+++ b/src/stick_table.c
@@ -22,6 +22,7 @@
 #include <haproxy/arg.h>
 #include <haproxy/cfgparse.h>
 #include <haproxy/cli.h>
+#include <haproxy/dict.h>
 #include <haproxy/errors.h>
 #include <haproxy/global.h>
 #include <haproxy/http_rules.h>
@@ -94,6 +95,12 @@ void __stksess_free(struct stktable *t, struct stksess *ts)
  */
 void stksess_free(struct stktable *t, struct stksess *ts)
 {
+       void *data;
+       data = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_KEY);
+       if (data) {
+               dict_entry_unref(&server_key_dict, stktable_data_cast(data, 
server_key));
+               stktable_data_cast(data, server_key) = NULL;
+       }
        HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
        __stksess_free(t, ts);
        HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
@@ -894,6 +901,7 @@ int parse_stick_table(const char *file, int linenum, char 
**args,
                                goto out;
 
                        }
+                       idx++;
                }
                else {
                        ha_alert("parsing [%s:%d] : %s: unknown argument 
'%s'.\n",
diff --git a/src/stream.c b/src/stream.c
index f64390652..ed5a6515f 100644
--- a/src/stream.c
+++ b/src/stream.c
@@ -1385,7 +1385,7 @@ static int process_store_rules(struct stream *s, struct 
channel *rep, int an_bit
                if (t->server_key_type == STKTABLE_SRV_NAME)
                        key = __objt_server(s->target)->id;
                else if (t->server_key_type == STKTABLE_SRV_ADDR)
-                       key = __objt_server(s->target)->addr_desc;
+                       key = __objt_server(s->target)->addr_node.key;
                else
                        continue;
 
diff --git a/src/tools.c b/src/tools.c
index 21e3f06ef..27043c186 100644
--- a/src/tools.c
+++ b/src/tools.c
@@ -1228,7 +1228,8 @@ char * sa2str(const struct sockaddr_storage *addr, int 
port, int map_ports)
        case AF_UNIX:
                path = ((struct sockaddr_un *)addr)->sun_path;
                if (path[0] == '\0') {
-                       return memprintf(&out, "abns@%107s", path+1);
+                       const int max_length = sizeof(struct sockaddr_un) - 
offsetof(struct sockaddr_un, sun_path) - 1;
+                       return memprintf(&out, "abns@%.*s", max_length, path+1);
                } else {
                        return strdup(path);
                }
-- 
2.29.2


>From a5cbb749f8a3122f1280163fdaa5d88d530e1537 Mon Sep 17 00:00:00 2001
From: Thayne McCombs <[email protected]>
Date: Wed, 9 Dec 2020 00:36:45 -0700
Subject: [PATCH 2/2] Add test for srvkey addr

---
 reg-tests/peers/srvkey_addr.vtc | 118 ++++++++++++++++++++++++++++++++
 1 file changed, 118 insertions(+)
 create mode 100644 reg-tests/peers/srvkey_addr.vtc

diff --git a/reg-tests/peers/srvkey_addr.vtc b/reg-tests/peers/srvkey_addr.vtc
new file mode 100644
index 000000000..52e43a6cb
--- /dev/null
+++ b/reg-tests/peers/srvkey_addr.vtc
@@ -0,0 +1,118 @@
+vtest "Test for peering by server address"
+feature ignore_unknown_macro
+
+#REQUIRE_VERSION=2.0
+#REGTEST_TYPE=slow
+
+server s1 {
+  rxreq
+  txresp -body "A"
+} -repeat 3 -start
+
+server s2 {
+  rxreq
+  txresp -body "B"
+} -repeat 3 -start
+
+server s3 {
+  rxreq
+  txresp -body "C"
+} -repeat 3 -start
+
+haproxy h1 -arg "-L A" -conf {
+  defaults
+    mode http
+    timeout client  1s
+    timeout connect 1s
+    timeout server  1s
+
+  peers peers
+    bind "fd@${A}"
+    server A
+    server B ${h2_B_addr}:${h2_B_port}
+
+  listen stkt
+    bind "fd@${fe}"
+    balance roundrobin
+    stick-table type string size 10m store gpc0 srvkey addr peers peers
+    stick on path
+    http-request track-sc0 path
+    http-request sc-inc-gpc0(0)
+    server s1_A ${s1_addr}:${s1_port}
+    server s2_A ${s2_addr}:${s2_port}
+    server s3_A ${s3_addr}:${s3_port}
+}
+
+haproxy h2 -arg "-L B" -conf {
+  defaults
+    mode http
+    timeout client  1s
+    timeout connect 1s
+    timeout server  1s
+
+  peers peers
+    bind "fd@${B}"
+    server A ${h1_A_addr}:${h1_A_port}
+    server B
+    server C ${h2_C_addr}:${h2_C_port}
+
+  listen stkt
+    bind "fd@${fe}"
+    balance random
+    stick-table type string size 10m store gpc0 srvkey addr peers peers
+    stick on path
+    http-request track-sc0 path
+    http-request sc-inc-gpc0(0)
+    server s2_B ${s2_addr}:${s2_port}
+    server s3_B ${s3_addr}:${s3_port}
+    server s1_B ${s1_addr}:${s1_port}
+}
+
+haproxy h3 -arg "-L C" -conf {
+  defaults
+    mode http
+    timeout client  1s
+    timeout connect 1s
+    timeout server  1s
+
+  peers peers
+    bind "fd@${C}"
+    server A ${h1_A_addr}:${h1_A_port}
+    server B ${h2_B_addr}:${h2_B_port}
+    server C
+
+  listen stkt
+    bind "fd@${fe}"
+    balance random
+    stick-table type string size 10m store gpc0 srvkey addr peers peers
+    stick on path
+    server s3_C ${s3_addr}:${s3_port}
+    server s1_C ${s1_addr}:${s1_port}
+    server s2_C ${s2_addr}:${s2_port}
+}
+
+haproxy h1 -start
+delay 0.2
+haproxy h2 -start
+delay 0.2
+haproxy h3 -start
+delay 0.2
+
+shell {
+  set -e
+  c1=`curl -sS ${h1_fe_addr}:${h1_fe_port}/c1`
+  c2=`curl -sS ${h1_fe_addr}:${h1_fe_port}/c2`
+  c3=`curl -sS ${h1_fe_addr}:${h1_fe_port}/c3`
+
+  echo $c1 $c2 $c3
+
+  sleep 1
+
+  [ "`curl -sS ${h2_fe_addr}:${h2_fe_port}/c1`" = "$c1" ] || exit 1
+  [ "`curl -sS ${h2_fe_addr}:${h2_fe_port}/c2`" = "$c2" ] || exit 1
+  [ "`curl -sS ${h2_fe_addr}:${h2_fe_port}/c3`" = "$c3" ] || exit 1
+
+  [ "`curl -sS ${h3_fe_addr}:${h3_fe_port}/c1`" = "$c1" ] || exit 1
+  [ "`curl -sS ${h3_fe_addr}:${h3_fe_port}/c2`" = "$c2" ] || exit 1
+  [ "`curl -sS ${h3_fe_addr}:${h3_fe_port}/c3`" = "$c3" ] || exit 1
+}
-- 
2.29.2


Reply via email to