]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: connection: use dst addr as parameter for srv conn hash
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 11 Feb 2021 15:46:53 +0000 (16:46 +0100)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Fri, 12 Feb 2021 11:53:56 +0000 (12:53 +0100)
The destination address is used as an input to the server connection hash. The
address and port are used as separated hash inputs. Note that they are not used
when statically specified on the server line. This is only useful for dynamic
destination address.

This is typically used when the server address is dynamically set via the
set-dst action. The address and port are separated hash parameters.

Most notably, it should fixed set-dst use case (cf github issue #947).

include/haproxy/connection-t.h
src/backend.c
src/connection.c

index 9ee00819bfaef0dc18c44a1db04a831b4944ebe7..7acbc2d77e95f23755978749259ffa78e5b18497 100644 (file)
@@ -472,9 +472,11 @@ struct conn_stream {
  * CAUTION! Always update CONN_HASH_PARAMS_TYPE_COUNT when adding a new entry.
  */
 enum conn_hash_params_t {
-       CONN_HASH_PARAMS_TYPE_SNI = 0x1,
+       CONN_HASH_PARAMS_TYPE_SNI      = 0x1,
+       CONN_HASH_PARAMS_TYPE_DST_ADDR = 0x2,
+       CONN_HASH_PARAMS_TYPE_DST_PORT = 0x4,
 };
-#define CONN_HASH_PARAMS_TYPE_COUNT 1
+#define CONN_HASH_PARAMS_TYPE_COUNT 3
 
 #define CONN_HASH_PAYLOAD_LEN \
        (((sizeof(((struct connection *)0)->hash)) * 8) - CONN_HASH_PARAMS_TYPE_COUNT)
@@ -489,6 +491,7 @@ enum conn_hash_params_t {
 struct conn_hash_params {
        struct server *srv;
        XXH64_hash_t *sni_prehash;
+       struct sockaddr_storage *dst_addr;
 };
 
 /* This structure describes a connection with its methods and data.
index d8413fb6ef784197737d1ec775cfefa8eeeeffae..852b0db229cb3fb90bc592d4e804c44026967f29 100644 (file)
@@ -1274,6 +1274,18 @@ int connect_server(struct stream *s)
        }
 #endif /* USE_OPENSSL */
 
+       /* 2. destination address */
+       if (!(s->flags & SF_ADDR_SET)) {
+               err = alloc_dst_address(&s->target_addr, srv, s);
+               if (err != SRV_STATUS_OK)
+                       return SF_ERR_INTERNAL;
+
+               s->flags |= SF_ADDR_SET;
+       }
+
+       if (srv && (!is_addr(&srv->addr) || srv->flags & SRV_F_MAPPORTS))
+               hash_params.dst_addr = s->target_addr;
+
        if (srv)
                hash = conn_calculate_hash(&hash_params);
 
@@ -1460,23 +1472,15 @@ skip_reuse:
                        srv_conn->owner = s->sess;
                        if (reuse_mode == PR_O_REUSE_NEVR)
                                conn_set_private(srv_conn);
-               }
-       }
-
-       if (!srv_conn || !sockaddr_alloc(&srv_conn->dst, 0, 0)) {
-               if (srv_conn)
-                       conn_free(srv_conn);
-               return SF_ERR_RESOURCE;
-       }
 
-       if (!(s->flags & SF_ADDR_SET)) {
-               err = alloc_dst_address(&s->target_addr, srv, s);
-               if (err != SRV_STATUS_OK) {
-                       conn_free(srv_conn);
-                       return SF_ERR_INTERNAL;
+                       if (!sockaddr_alloc(&srv_conn->dst, 0, 0)) {
+                               conn_free(srv_conn);
+                               return SF_ERR_RESOURCE;
+                       }
+               }
+               else {
+                       return SF_ERR_RESOURCE;
                }
-
-               s->flags |= SF_ADDR_SET;
        }
 
        /* copy the target address into the connection */
index 6126dd180348df8ebbeee18d427c66440ecb7dde..5e7a4c5d656e7bdb8cd5b677b2831fbb11b823d5 100644 (file)
@@ -1412,6 +1412,49 @@ static struct cfg_kw_list cfg_kws = {ILH, {
 
 INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
 
+/* private function to handle sockaddr as input for connection hash */
+static void conn_calculate_hash_sockaddr(const struct sockaddr_storage *ss,
+                                         char *buf, size_t *idx,
+                                         enum conn_hash_params_t *hash_flags,
+                                         enum conn_hash_params_t param_type_addr,
+                                         enum conn_hash_params_t param_type_port)
+{
+       struct sockaddr_in *addr;
+       struct sockaddr_in6 *addr6;
+
+       switch (ss->ss_family) {
+       case AF_INET:
+               addr = (struct sockaddr_in *)ss;
+
+               conn_hash_update(buf, idx,
+                                &addr->sin_addr, sizeof(addr->sin_addr),
+                                hash_flags, param_type_addr);
+
+               if (addr->sin_port) {
+                       conn_hash_update(buf, idx,
+                                        &addr->sin_port, sizeof(addr->sin_port),
+                                        hash_flags, param_type_port);
+               }
+
+               break;
+
+       case AF_INET6:
+               addr6 = (struct sockaddr_in6 *)ss;
+
+               conn_hash_update(buf, idx,
+                                &addr6->sin6_addr, sizeof(addr6->sin6_addr),
+                                hash_flags, param_type_addr);
+
+               if (addr6->sin6_port) {
+                       conn_hash_update(buf, idx,
+                                        &addr6->sin6_port, sizeof(addr6->sin6_port),
+                                        hash_flags, param_type_port);
+               }
+
+               break;
+       }
+}
+
 XXH64_hash_t conn_calculate_hash(const struct conn_hash_params *params)
 {
        char *buf;
@@ -1429,6 +1472,14 @@ XXH64_hash_t conn_calculate_hash(const struct conn_hash_params *params)
                                 &hash_flags, CONN_HASH_PARAMS_TYPE_SNI);
        }
 
+       if (params->dst_addr) {
+               conn_calculate_hash_sockaddr(params->dst_addr,
+                                            buf, &idx, &hash_flags,
+                                            CONN_HASH_PARAMS_TYPE_DST_ADDR,
+                                            CONN_HASH_PARAMS_TYPE_DST_PORT);
+       }
+
        hash = conn_hash_digest(buf, idx, hash_flags);
+
        return hash;
 }