From: Christopher Faulet Date: Tue, 10 Apr 2018 13:01:45 +0000 (+0200) Subject: MEDIUM: mux: Use the mux protocol specified on bind/server lines X-Git-Tag: v1.9-dev2~175 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7ce0c89;p=thirdparty%2Fhaproxy.git MEDIUM: mux: Use the mux protocol specified on bind/server lines To do so, mux choices are split to handle incoming and outgoing connections in a different way. The protocol specified on the bind/server line is used in priority. Then, for frontend connections, the ALPN is retrieved and used to choose the best mux. For backend connection, there is no ALPN. Finaly, if no protocol is specified and no protocol matches the ALPN, we fall back on a default mux, choosing in priority the first mux with exactly the same mode. --- diff --git a/include/proto/connection.h b/include/proto/connection.h index fe4c0705fe..3b25fc5c69 100644 --- a/include/proto/connection.h +++ b/include/proto/connection.h @@ -1008,56 +1008,78 @@ static inline void list_mux_proto(FILE *out) } } -/* returns the first mux in the list matching the exact same token and - * compatible with the proxy's mode (http or tcp). Mode "health" has to be - * considered as TCP here. Ie passing "px->mode == PR_MODE_HTTP" is fine. Will - * fall back to the first compatible mux with empty ALPN name. May return null - * if the code improperly registered the default mux to use as a fallback. +/* returns the first mux in the list matching the exact same and + * compatible with the (FE or BE) and the (TCP or + * HTTP). can be empty. Will fall back to the first compatible mux + * with exactly the same or with an empty name. May return + * null if the code improperly registered the default mux to use as a fallback. */ -static inline const struct mux_ops *alpn_get_mux(const struct ist token, int http_mode) +static inline const struct mux_ops *conn_get_best_mux(struct connection *conn, + const struct ist mux_proto, + int proto_side, int proto_mode) { struct mux_proto_list *item; - const struct mux_ops *fallback = NULL; - - http_mode = 1 << !!http_mode; + struct mux_proto_list *fallback = NULL; list_for_each_entry(item, &mux_proto_list.list, list) { - if (!(item->mode & http_mode)) + if (!(item->side & proto_side) || !(item->mode & proto_mode)) continue; - if (isteq(token, item->token)) + if (istlen(mux_proto) && isteq(mux_proto, item->token)) return item->mux; - if (!istlen(item->token)) - fallback = item->mux; + else if (!istlen(item->token)) { + if (!fallback || (item->mode == proto_mode && fallback->mode != proto_mode)) + fallback = item; + } } - return fallback; + return (fallback ? fallback->mux : NULL); + } -/* finds the best mux for incoming connection and mode for - * the proxy. Null cannot be returned unless there's a serious bug somewhere - * else (no fallback mux registered). +/* installs the best mux for incoming connection using the upper context + * . If the mux protocol is forced, we use it to find the best + * mux. Otherwise we use the ALPN name, if any. Returns < 0 on error. */ -static inline const struct mux_ops *conn_find_best_mux(struct connection *conn, int http_mode) +static inline int conn_install_mux_fe(struct connection *conn, void *ctx) { - const char *alpn_str; - int alpn_len; - - if (!conn_get_alpn(conn, &alpn_str, &alpn_len)) - alpn_len = 0; + struct bind_conf *bind_conf = objt_listener(conn->target)->bind_conf; + const struct mux_ops *mux_ops; - return alpn_get_mux(ist2(alpn_str, alpn_len), http_mode); + if (bind_conf->mux_proto) + mux_ops = bind_conf->mux_proto->mux; + else { + struct ist mux_proto; + const char *alpn_str = NULL; + int alpn_len = 0; + int mode = (1 << (bind_conf->frontend->mode == PR_MODE_HTTP)); + + conn_get_alpn(conn, &alpn_str, &alpn_len); + mux_proto = ist2(alpn_str, alpn_len); + mux_ops = conn_get_best_mux(conn, mux_proto, PROTO_SIDE_FE, mode); + if (!mux_ops) + return -1; + } + return conn_install_mux(conn, mux_ops, ctx); } -/* finds the best mux for incoming connection , a proxy in and http mode - * , and installs it on the connection for upper context . Returns +/* installs the best mux for outgoing connection using the upper context + * . If the mux protocol is forced, we use it to find the best mux. Returns * < 0 on error. */ -static inline int conn_install_best_mux(struct connection *conn, int mode, void *ctx) +static inline int conn_install_mux_be(struct connection *conn, void *ctx) { + struct server *srv = objt_server(conn->target); const struct mux_ops *mux_ops; - mux_ops = conn_find_best_mux(conn, mode); - if (!mux_ops) - return -1; + if (srv->mux_proto) + mux_ops = srv->mux_proto->mux; + else { + int mode; + + mode = (1 << (srv->proxy->mode == PR_MODE_HTTP)); + mux_ops = conn_get_best_mux(conn, ist(NULL), PROTO_SIDE_BE, mode); + if (!mux_ops) + return -1; + } return conn_install_mux(conn, mux_ops, ctx); } diff --git a/src/backend.c b/src/backend.c index 50ef3b7d24..1aadca5901 100644 --- a/src/backend.c +++ b/src/backend.c @@ -1189,7 +1189,7 @@ int connect_server(struct stream *s) else return SF_ERR_INTERNAL; /* how did we get there ? */ - conn_install_best_mux(srv_conn, s->be->mode == PR_MODE_HTTP, srv_cs); + conn_install_mux_be(srv_conn, srv_cs); /* process the case where the server requires the PROXY protocol to be sent */ srv_conn->send_proxy_ofs = 0; diff --git a/src/session.c b/src/session.c index 635aee5f6e..1d66b739f0 100644 --- a/src/session.c +++ b/src/session.c @@ -423,7 +423,7 @@ static int conn_complete_session(struct connection *conn) goto fail; session_count_new(sess); - if (conn_install_best_mux(conn, sess->fe->mode == PR_MODE_HTTP, NULL) < 0) + if (conn_install_mux_fe(conn, NULL) < 0) goto fail; /* the embryonic session's task is not needed anymore */