On 12/10/20 1:31 AM, Frederic Lecaille wrote: > > It would be preferable to send all your patches, so that others than me > may review your work (no diff between different versions of patches) and > continue to split your work in several patches. >
Ok, here is what I have so far as two patches (I combined feedback into the original commit): >From cf965f47e04776ca20d2ee6ed22028741493824c Mon Sep 17 00:00:00 2001 From: Thayne McCombs <tha...@lucidchart.com> Date: Fri, 20 Nov 2020 01:28:26 -0700 Subject: [PATCH 1/2] Add srvkey option to stick-table This allows using the address of the server rather than the name of the server for keeping track of servers in a backend for stickiness. Fixes #814 --- doc/configuration.txt | 12 ++++++++- include/haproxy/dict.h | 1 + include/haproxy/proxy-t.h | 1 + include/haproxy/server-t.h | 1 + include/haproxy/server.h | 2 +- include/haproxy/stick_table-t.h | 11 ++++++-- include/haproxy/tools.h | 13 +++++++++ src/cfgparse-listen.c | 1 + src/cfgparse.c | 4 +-- src/dict.c | 24 ++++++++++++++++- src/peers.c | 9 +++++-- src/server.c | 40 ++++++++++++++++++++++++++-- src/stick_table.c | 31 +++++++++++++++++++++- src/stream.c | 47 +++++++++++++++++++++++---------- src/tools.c | 45 +++++++++++++++++++++++++++++++ 15 files changed, 216 insertions(+), 26 deletions(-) diff --git a/doc/configuration.txt b/doc/configuration.txt index e60e3428d..e17061518 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -10649,7 +10649,7 @@ stick store-request <pattern> [table <table>] [{if | unless} <condition>] stick-table type {ip | integer | string [len <length>] | binary [len <length>]} - size <size> [expire <expire>] [nopurge] [peers <peersect>] + size <size> [expire <expire>] [nopurge] [peers <peersect>] [srvkey <srvkey>] [store <data_type>]* Configure the stickiness table for the current section May be used in sections : defaults | frontend | listen | backend @@ -10726,6 +10726,16 @@ stick-table type {ip | integer | string [len <length>] | binary [len <length>]} be removed once full. Be sure not to use the "nopurge" parameter if not expiration delay is specified. + <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 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 + token. + <data_type> is used to store additional information in the stick-table. This may be used by ACLs in order to control various criteria related to the activity of the client matching the stick-table. For each 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/proxy-t.h b/include/haproxy/proxy-t.h index 998e210f6..e62b79765 100644 --- a/include/haproxy/proxy-t.h +++ b/include/haproxy/proxy-t.h @@ -424,6 +424,7 @@ struct proxy { char *lfsd_file; /* file name where the structured-data logformat string for RFC5424 appears (strdup) */ int lfsd_line; /* file name where the structured-data logformat string for RFC5424 appears */ } conf; /* config information */ + struct eb_root used_server_addr; /* list of server addresses in use */ void *parent; /* parent of the proxy when applicable */ struct comp *comp; /* http compression */ diff --git a/include/haproxy/server-t.h b/include/haproxy/server-t.h index 0e66be693..13f5a5dab 100644 --- a/include/haproxy/server-t.h +++ b/include/haproxy/server-t.h @@ -337,6 +337,7 @@ struct server { struct ebpt_node name; /* place in the tree of used names */ int line; /* line where the section appears */ } conf; /* config information */ + struct ebpt_node addr_node; /* Node for string representation of address for the server (including port number) */ /* Template information used only for server objects which * serve as template filled at parsing time and used during * server allocations from server templates. diff --git a/include/haproxy/server.h b/include/haproxy/server.h index d63eb01bc..00036b1a1 100644 --- a/include/haproxy/server.h +++ b/include/haproxy/server.h @@ -38,7 +38,7 @@ __decl_thread(extern HA_SPINLOCK_T idle_conn_srv_lock); extern struct eb_root idle_conn_srv; extern struct task *idle_conn_task; -extern struct dict server_name_dict; +extern struct dict server_key_dict; int srv_downtime(const struct server *s); int srv_lastsession(const struct server *s); diff --git a/include/haproxy/stick_table-t.h b/include/haproxy/stick_table-t.h index 59aadea22..2cb4a1b8f 100644 --- a/include/haproxy/stick_table-t.h +++ b/include/haproxy/stick_table-t.h @@ -56,7 +56,7 @@ enum { STKTABLE_DT_BYTES_OUT_RATE,/* bytes rate from servers to client */ STKTABLE_DT_GPC1, /* General Purpose Counter 1 (unsigned 32-bit integer) */ STKTABLE_DT_GPC1_RATE, /* General Purpose Counter 1's event rate */ - STKTABLE_DT_SERVER_NAME, /* The server name */ + STKTABLE_DT_SERVER_KEY, /* The server key */ STKTABLE_STATIC_DATA_TYPES,/* number of types above */ /* up to STKTABLE_EXTRA_DATA_TYPES types may be registered here, always * followed by the number of data types, must always be last. @@ -80,6 +80,12 @@ enum { ARG_T_DELAY, /* a delay which supports time units */ }; +/* They types of keys that servers can be identified by */ +enum { + STKTABLE_SRV_NAME = 0, + STKTABLE_SRV_ADDR, +}; + /* stick table key type flags */ #define STK_F_CUSTOM_KEYSIZE 0x00000001 /* this table's key size is configurable */ @@ -112,7 +118,7 @@ union stktable_data { /* types of each storable data */ int server_id; - struct dict_entry *server_name; + struct dict_entry *server_key; unsigned int gpt0; unsigned int gpc0; struct freq_ctr_period gpc0_rate; @@ -188,6 +194,7 @@ struct stktable { } peers; unsigned long type; /* type of table (determines key format) */ + unsigned int server_key_type; /* What type of key is used to identify servers */ size_t key_size; /* size of a key, maximum size in case of string */ unsigned int size; /* maximum number of sticky sessions in table */ unsigned int current; /* number of sticky sessions currently in table */ diff --git a/include/haproxy/tools.h b/include/haproxy/tools.h index 4080d7a5d..651c0701c 100644 --- a/include/haproxy/tools.h +++ b/include/haproxy/tools.h @@ -245,6 +245,19 @@ struct sockaddr_storage *str2sa_range(const char *str, int *port, int *low, int struct protocol **proto, char **err, const char *pfx, char **fqdn, unsigned int opts); + +/* converts <addr> and <port> into a string representation of the address and port. This is sort + * of an inverse of str2sa_range, with some restrictions. The supported families are AF_INET, + * AF_INET6, AF_UNIX, and AF_CUST_SOCKPAIR. If the family is unsopported NULL is returned. + * If map_ports is true, then the sign of the port is included in the output, to indicate it is + * relative to the incoming port. AF_INET and AF_INET6 will be in the form "<addr>:<port>". + * AF_UNIX will either be just the path (if using a pathname) or "abns@<path>" if it is abstract. + * AF_CUST_SOCKPAIR will be of the form "sockpair@<fd>". + * + * The returned char* is allocated, and it is the responsibility of the caller to free it. + */ +char *sa2str(const struct sockaddr_storage *addr, int port, int map_ports); + /* converts <str> to a struct in_addr containing a network mask. It can be * passed in dotted form (255.255.255.0) or in CIDR form (24). It returns 1 * if the conversion succeeds otherwise zero. 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/cfgparse.c b/src/cfgparse.c index 957ae9e61..51e76c021 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -2666,7 +2666,7 @@ int check_config_validity() free((void *)mrule->table.name); mrule->table.t = target; stktable_alloc_data_type(target, STKTABLE_DT_SERVER_ID, NULL); - stktable_alloc_data_type(target, STKTABLE_DT_SERVER_NAME, NULL); + stktable_alloc_data_type(target, STKTABLE_DT_SERVER_KEY, NULL); if (!in_proxies_list(target->proxies_list, curproxy)) { curproxy->next_stkt_ref = target->proxies_list; target->proxies_list = curproxy; @@ -2704,7 +2704,7 @@ int check_config_validity() free((void *)mrule->table.name); mrule->table.t = target; stktable_alloc_data_type(target, STKTABLE_DT_SERVER_ID, NULL); - stktable_alloc_data_type(target, STKTABLE_DT_SERVER_NAME, NULL); + stktable_alloc_data_type(target, STKTABLE_DT_SERVER_KEY, NULL); if (!in_proxies_list(target->proxies_list, curproxy)) { curproxy->next_stkt_ref = target->proxies_list; target->proxies_list = curproxy; 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 b5c1d429f..3fa1a28b4 100644 --- a/src/peers.c +++ b/src/peers.c @@ -1633,13 +1633,16 @@ static int peer_treat_updatemsg(struct appctx *appctx, struct peer *p, int updt, chunk->area[chunk->data] = '\0'; *msg_cur += value_len; - de = dict_insert(&server_name_dict, chunk->area); + 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 3a3ccc672..ef536d718 100644 --- a/src/server.c +++ b/src/server.c @@ -65,8 +65,8 @@ struct eb_root idle_conn_srv = EB_ROOT; struct task *idle_conn_task = NULL; /* The server names dictionary */ -struct dict server_name_dict = { - .name = "server names", +struct dict server_key_dict = { + .name = "server keys", .values = EB_ROOT_UNIQUE, }; @@ -193,6 +193,36 @@ 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; + char *key; + + key = sa2str(&s->addr, s->svc_port, s->flags & SRV_F_MAPPORTS); + + 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); + + free(s->addr_node.key); + } + + s->addr_node.key = key; + + HA_RWLOCK_WRLOCK(PROXY_LOCK, &p->lock); + ebis_insert(&p->used_server_addr, &s->addr_node); + HA_RWLOCK_WRUNLOCK(PROXY_LOCK, &p->lock); +} + /* * Registers the server keyword list <kwl> as a list of valid keywords for next * parsing sessions. @@ -2052,6 +2082,9 @@ 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)) { ha_alert("parsing [%s:%d] : Unknown protocol family %d '%s'\n", @@ -3519,6 +3552,7 @@ int update_server_addr(struct server *s, void *ip, int ip_sin_family, const char break; }; srv_set_dyncookie(s); + srv_set_addr_desc(s); return 0; } @@ -3691,6 +3725,7 @@ out: /* force connection cleanup on the given server */ srv_cleanup_connections(s); srv_set_dyncookie(s); + srv_set_addr_desc(s); } if (updater) chunk_appendf(msg, " by '%s'", updater); @@ -4171,6 +4206,7 @@ static int srv_iterate_initaddr(struct server *srv) return return_code; out: 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 505916421..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); @@ -877,6 +884,25 @@ int parse_stick_table(const char *file, int linenum, char **args, } idx++; } + else if (strcmp(args[idx], "srvkey") == 0) { + char *keytype; + idx++; + keytype = args[idx]; + if (strcmp(keytype, "name") == 0) { + t->server_key_type = STKTABLE_SRV_NAME; + } + else if (strcmp(keytype, "addr") == 0) { + t->server_key_type = STKTABLE_SRV_ADDR; + } + else { + ha_alert("parsing [%s:%d] : %s : unknown server key type '%s'.\n", + file, linenum, args[0], keytype); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + + } + idx++; + } else { ha_alert("parsing [%s:%d] : %s: unknown argument '%s'.\n", file, linenum, args[0], args[idx]); @@ -1048,7 +1074,7 @@ struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = { [STKTABLE_DT_BYTES_OUT_RATE]= { .name = "bytes_out_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY }, [STKTABLE_DT_GPC1] = { .name = "gpc1", .std_type = STD_T_UINT }, [STKTABLE_DT_GPC1_RATE] = { .name = "gpc1_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY }, - [STKTABLE_DT_SERVER_NAME] = { .name = "server_name", .std_type = STD_T_DICT }, + [STKTABLE_DT_SERVER_KEY] = { .name = "server_key", .std_type = STD_T_DICT }, }; /* Registers stick-table extra data type with index <idx>, name <name>, type @@ -1095,6 +1121,9 @@ int stktable_get_data_type(char *name) if (strcmp(name, stktable_data_types[type].name) == 0) return type; } + /* For backwards compatibility */ + if (strcmp(name, "server_name") == 0) + return STKTABLE_DT_SERVER_KEY; return -1; } diff --git a/src/stream.c b/src/stream.c index 6ca1538e8..e24ea49fc 100644 --- a/src/stream.c +++ b/src/stream.c @@ -1202,17 +1202,27 @@ static inline void sticking_rule_find_target(struct stream *s, /* Look for the server name previously stored in <t> stick-table */ HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock); - ptr = __stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_NAME); - de = stktable_data_cast(ptr, server_name); + ptr = __stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_KEY); + de = stktable_data_cast(ptr, server_key); HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock); if (de) { - struct ebpt_node *name; + struct ebpt_node *node; - name = ebis_lookup(&px->conf.used_server_name, de->value.key); - if (name) { - srv = container_of(name, struct server, conf.name); - goto found; + if (t->server_key_type == STKTABLE_SRV_NAME) { + node = ebis_lookup(&px->conf.used_server_name, de->value.key); + if (node) { + srv = container_of(node, struct server, conf.name); + goto found; + } + } else if (t->server_key_type == STKTABLE_SRV_ADDR) { + HA_RWLOCK_RDLOCK(PROXY_LOCK, &px->lock); + node = ebis_lookup(&px->used_server_addr, de->value.key); + HA_RWLOCK_RDUNLOCK(PROXY_LOCK, &px->lock); + if (node) { + srv = container_of(node, struct server, addr_node); + goto found; + } } } @@ -1378,7 +1388,9 @@ static int process_store_rules(struct stream *s, struct channel *rep, int an_bit for (i = 0; i < s->store_count; i++) { struct stksess *ts; void *ptr; + char *key; struct dict_entry *de; + struct stktable *t = s->store[i].table; if (objt_server(s->target) && objt_server(s->target)->flags & SRV_F_NON_STICK) { stksess_free(s->store[i].table, s->store[i].ts); @@ -1386,27 +1398,34 @@ static int process_store_rules(struct stream *s, struct channel *rep, int an_bit continue; } - ts = stktable_set_entry(s->store[i].table, s->store[i].ts); + ts = stktable_set_entry(t, s->store[i].ts); if (ts != s->store[i].ts) { /* the entry already existed, we can free ours */ - stksess_free(s->store[i].table, s->store[i].ts); + stksess_free(t, s->store[i].ts); } s->store[i].ts = NULL; HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock); - ptr = __stktable_data_ptr(s->store[i].table, ts, STKTABLE_DT_SERVER_ID); + ptr = __stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID); stktable_data_cast(ptr, server_id) = __objt_server(s->target)->puid; HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock); + 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_node.key; + else + continue; + HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock); - de = dict_insert(&server_name_dict, __objt_server(s->target)->id); + de = dict_insert(&server_key_dict, key); if (de) { - ptr = __stktable_data_ptr(s->store[i].table, ts, STKTABLE_DT_SERVER_NAME); - stktable_data_cast(ptr, server_name) = de; + ptr = __stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_KEY); + stktable_data_cast(ptr, server_key) = de; } HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock); - stktable_touch_local(s->store[i].table, ts, 1); + stktable_touch_local(t, ts, 1); } s->store_count = 0; /* everything is stored */ diff --git a/src/tools.c b/src/tools.c index fdc91909a..1cc051148 100644 --- a/src/tools.c +++ b/src/tools.c @@ -1202,6 +1202,51 @@ struct sockaddr_storage *str2sa_range(const char *str, int *port, int *low, int return ret; } +/* converts <addr> and <port> into a string representation of the address and port. This is sort + * of an inverse of str2sa_range, with some restrictions. The supported families are AF_INET, + * AF_INET6, AF_UNIX, and AF_CUST_SOCKPAIR. If the family is unsopported NULL is returned. + * If map_ports is true, then the sign of the port is included in the output, to indicate it is + * relative to the incoming port. AF_INET and AF_INET6 will be in the form "<addr>:<port>". + * AF_UNIX will either be just the path (if using a pathname) or "abns@<path>" if it is abstract. + * AF_CUST_SOCKPAIR will be of the form "sockpair@<fd>". + * + * The returned char* is allocated, and it is the responsibility of the caller to free it. + */ +char * sa2str(const struct sockaddr_storage *addr, int port, int map_ports) +{ + char buffer[INET6_ADDRSTRLEN]; + char *out = NULL; + const void *ptr; + const char *path; + + switch (addr->ss_family) { + case AF_INET: + ptr = &((struct sockaddr_in *)addr)->sin_addr; + break; + case AF_INET6: + ptr = &((struct sockaddr_in6 *)addr)->sin6_addr; + break; + case AF_UNIX: + path = ((struct sockaddr_un *)addr)->sun_path; + if (path[0] == '\0') { + 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); + } + case AF_CUST_SOCKPAIR: + return memprintf(&out, "sockpair@%d", ((struct sockaddr_in *)addr)->sin_addr.s_addr); + default: + return NULL; + } + inet_ntop(addr->ss_family, ptr, buffer, get_addr_len(addr)); + if (map_ports) + return memprintf(&out, "%s:%+d", buffer, port); + else + return memprintf(&out, "%s:%d", buffer, port); +} + + /* converts <str> to a struct in_addr containing a network mask. It can be * passed in dotted form (255.255.255.0) or in CIDR form (24). It returns 1 * if the conversion succeeds otherwise zero. -- 2.29.2 >From 8157a34247104413f7e0c4bb533e3ab342277097 Mon Sep 17 00:00:00 2001 From: Thayne McCombs <tha...@lucidchart.com> 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