From 1a18b54142be2eef6bed2e599c043a52ca19a813 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Tue, 11 Dec 2018 16:37:42 +0100 Subject: [PATCH] REORG: connection: centralize the conn_set_{tos,mark,quickack} functions There were a number of ugly setsockopt() calls spread all over proto_http.c, proto_htx.c and hlua.c just to manipulate the front connection's TOS, mark or TCP quick-ack. These ones entirely relied on the connection, its existence, its control layer's presence, and its addresses. Worse, inet_set_tos() was placed in proto_http.c, exported and used from the two other ones, surrounded in #ifdefs. This patch moves this code to connection.h and makes the other ones rely on it without ifdefs. --- include/proto/connection.h | 50 +++++++++++++++++++++++++++++++++++ include/proto/proto_http.h | 1 - src/hlua.c | 11 ++------ src/proto_http.c | 54 +++++++------------------------------- src/proto_htx.c | 30 +++++++-------------- 5 files changed, 70 insertions(+), 76 deletions(-) diff --git a/include/proto/connection.h b/include/proto/connection.h index e2fae5f8f5..f84b75a3f2 100644 --- a/include/proto/connection.h +++ b/include/proto/connection.h @@ -738,6 +738,56 @@ static inline void conn_get_to_addr(struct connection *conn) conn->flags |= CO_FL_ADDR_TO_SET; } +/* Sets the TOS header in IPv4 and the traffic class header in IPv6 packets + * (as per RFC3260 #4 and BCP37 #4.2 and #5.2). The connection is tested and if + * it is null, nothing is done. + */ +static inline void conn_set_tos(const struct connection *conn, int tos) +{ + if (!conn || !conn_ctrl_ready(conn)) + return; + +#ifdef IP_TOS + if (conn->addr.from.ss_family == AF_INET) + setsockopt(conn->handle.fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)); +#endif +#ifdef IPV6_TCLASS + if (conn->addr.from.ss_family == AF_INET6) { + if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&conn->addr.from)->sin6_addr)) + /* v4-mapped addresses need IP_TOS */ + setsockopt(conn->handle.fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)); + else + setsockopt(conn->handle.fd, IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof(tos)); + } +#endif +} + +/* Sets the netfilter mark on the connection's socket. The connection is tested + * and if it is null, nothing is done. + */ +static inline void conn_set_mark(const struct connection *conn, int mark) +{ + if (!conn || !conn_ctrl_ready(conn)) + return; + +#ifdef SO_MARK + setsockopt(conn->handle.fd, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)); +#endif +} + +/* Sets adjust the TCP quick-ack feature on the connection's socket. The + * connection is tested and if it is null, nothing is done. + */ +static inline void conn_set_quickack(const struct connection *conn, int value) +{ + if (!conn || !conn_ctrl_ready(conn)) + return; + +#ifdef TCP_QUICKACK + setsockopt(conn->handle.fd, IPPROTO_TCP, TCP_QUICKACK, &value, sizeof(value)); +#endif +} + /* Attaches a conn_stream to a data layer and sets the relevant callbacks */ static inline void cs_attach(struct conn_stream *cs, void *data, const struct data_cb *data_cb) { diff --git a/include/proto/proto_http.h b/include/proto/proto_http.h index 73946198a0..3e7701cf21 100644 --- a/include/proto/proto_http.h +++ b/include/proto/proto_http.h @@ -105,7 +105,6 @@ void http_set_status(unsigned int status, const char *reason, struct stream *s); int http_transform_header_str(struct stream* s, struct http_msg *msg, const char* name, unsigned int name_len, const char *str, struct my_regex *re, int action); -void inet_set_tos(int fd, const struct sockaddr_storage *from, int tos); int http_handle_stats(struct stream *s, struct channel *req); enum rule_result http_req_get_intercept_rule(struct proxy *px, struct list *rules, struct stream *s, int *deny_status); diff --git a/src/hlua.c b/src/hlua.c index 189bf475ad..5dd88f2f19 100644 --- a/src/hlua.c +++ b/src/hlua.c @@ -5373,33 +5373,26 @@ __LJMP static int hlua_txn_set_loglevel(lua_State *L) __LJMP static int hlua_txn_set_tos(lua_State *L) { struct hlua_txn *htxn; - struct connection *cli_conn; int tos; MAY_LJMP(check_args(L, 2, "set_tos")); htxn = MAY_LJMP(hlua_checktxn(L, 1)); tos = MAY_LJMP(luaL_checkinteger(L, 2)); - if ((cli_conn = objt_conn(htxn->s->sess->origin)) && conn_ctrl_ready(cli_conn)) - inet_set_tos(cli_conn->handle.fd, &cli_conn->addr.from, tos); - + conn_set_tos(objt_conn(htxn->s->sess->origin), tos); return 0; } __LJMP static int hlua_txn_set_mark(lua_State *L) { -#ifdef SO_MARK struct hlua_txn *htxn; - struct connection *cli_conn; int mark; MAY_LJMP(check_args(L, 2, "set_mark")); htxn = MAY_LJMP(hlua_checktxn(L, 1)); mark = MAY_LJMP(luaL_checkinteger(L, 2)); - if ((cli_conn = objt_conn(htxn->s->sess->origin)) && conn_ctrl_ready(cli_conn)) - setsockopt(cli_conn->handle.fd, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)); -#endif + conn_set_tos(objt_conn(htxn->s->sess->origin), mark); return 0; } diff --git a/src/proto_http.c b/src/proto_http.c index e2f300950d..6c7cfcbc07 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -23,8 +23,6 @@ #include #include -#include - #include #include #include @@ -1088,16 +1086,14 @@ int http_wait_for_request(struct stream *s, struct channel *req, int an_bit) channel_dont_connect(req); req->flags |= CF_READ_DONTWAIT; /* try to get back here ASAP */ s->res.flags &= ~CF_EXPECT_MORE; /* speed up sending a previous response */ -#ifdef TCP_QUICKACK - if (sess->listener->options & LI_O_NOQUICKACK && ci_data(req) && - objt_conn(sess->origin) && conn_ctrl_ready(__objt_conn(sess->origin))) { + + if (sess->listener->options & LI_O_NOQUICKACK && ci_data(req)) { /* We need more data, we have to re-enable quick-ack in case we * previously disabled it, otherwise we might cause the client * to delay next data. */ - setsockopt(__objt_conn(sess->origin)->handle.fd, IPPROTO_TCP, TCP_QUICKACK, &one, sizeof(one)); + conn_set_quickack(objt_conn(sess->origin), 1); } -#endif if ((msg->msg_state != HTTP_MSG_RQBEFORE) && (txn->flags & TX_WAIT_NEXT_RQ)) { /* If the client starts to talk, let's fall back to @@ -1638,26 +1634,6 @@ int http_handle_stats(struct stream *s, struct channel *req) return 1; } -/* Sets the TOS header in IPv4 and the traffic class header in IPv6 packets - * (as per RFC3260 #4 and BCP37 #4.2 and #5.2). - */ -void inet_set_tos(int fd, const struct sockaddr_storage *from, int tos) -{ -#ifdef IP_TOS - if (from->ss_family == AF_INET) - setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)); -#endif -#ifdef IPV6_TCLASS - if (from->ss_family == AF_INET6) { - if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)from)->sin6_addr)) - /* v4-mapped addresses need IP_TOS */ - setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)); - else - setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof(tos)); - } -#endif -} - int http_transform_header_str(struct stream* s, struct http_msg *msg, const char* name, unsigned int name_len, const char *str, struct my_regex *re, @@ -1802,7 +1778,6 @@ http_req_get_intercept_rule(struct proxy *px, struct list *rules, struct stream { struct session *sess = strm_sess(s); struct http_txn *txn = s->txn; - struct connection *cli_conn; struct act_rule *rule; struct hdr_ctx ctx; const char *auth_realm; @@ -1903,15 +1878,11 @@ resume_execution: break; case ACT_HTTP_SET_TOS: - if ((cli_conn = objt_conn(sess->origin)) && conn_ctrl_ready(cli_conn)) - inet_set_tos(cli_conn->handle.fd, &cli_conn->addr.from, rule->arg.tos); + conn_set_tos(objt_conn(sess->origin), rule->arg.tos); break; case ACT_HTTP_SET_MARK: -#ifdef SO_MARK - if ((cli_conn = objt_conn(sess->origin)) && conn_ctrl_ready(cli_conn)) - setsockopt(cli_conn->handle.fd, SOL_SOCKET, SO_MARK, &rule->arg.mark, sizeof(rule->arg.mark)); -#endif + conn_set_mark(objt_conn(sess->origin), rule->arg.mark); break; case ACT_HTTP_SET_LOGL: @@ -2213,7 +2184,6 @@ http_res_get_intercept_rule(struct proxy *px, struct list *rules, struct stream { struct session *sess = strm_sess(s); struct http_txn *txn = s->txn; - struct connection *cli_conn; struct act_rule *rule; struct hdr_ctx ctx; enum rule_result rule_ret = HTTP_RULE_RES_CONT; @@ -2265,15 +2235,11 @@ resume_execution: break; case ACT_HTTP_SET_TOS: - if ((cli_conn = objt_conn(sess->origin)) && conn_ctrl_ready(cli_conn)) - inet_set_tos(cli_conn->handle.fd, &cli_conn->addr.from, rule->arg.tos); + conn_set_tos(objt_conn(sess->origin), rule->arg.tos); break; case ACT_HTTP_SET_MARK: -#ifdef SO_MARK - if ((cli_conn = objt_conn(sess->origin)) && conn_ctrl_ready(cli_conn)) - setsockopt(cli_conn->handle.fd, SOL_SOCKET, SO_MARK, &rule->arg.mark, sizeof(rule->arg.mark)); -#endif + conn_set_mark(objt_conn(sess->origin), rule->arg.mark); break; case ACT_HTTP_SET_LOGL: @@ -3414,18 +3380,16 @@ int http_process_request(struct stream *s, struct channel *req, int an_bit) req->analysers &= ~AN_REQ_FLT_XFER_DATA; req->analysers |= AN_REQ_HTTP_XFER_BODY; -#ifdef TCP_QUICKACK + /* We expect some data from the client. Unless we know for sure * we already have a full request, we have to re-enable quick-ack * in case we previously disabled it, otherwise we might cause * the client to delay further data. */ if ((sess->listener->options & LI_O_NOQUICKACK) && - cli_conn && conn_ctrl_ready(cli_conn) && ((msg->flags & HTTP_MSGF_TE_CHNK) || (msg->body_len > ci_data(req) - txn->req.eoh - 2))) - setsockopt(cli_conn->handle.fd, IPPROTO_TCP, TCP_QUICKACK, &one, sizeof(one)); -#endif + conn_set_quickack(cli_conn, 1); /************************************************************* * OK, that's finished for the headers. We have done what we * diff --git a/src/proto_htx.c b/src/proto_htx.c index c22908a14a..9088ecb521 100644 --- a/src/proto_htx.c +++ b/src/proto_htx.c @@ -225,16 +225,16 @@ int htx_wait_for_request(struct stream *s, struct channel *req, int an_bit) channel_dont_connect(req); req->flags |= CF_READ_DONTWAIT; /* try to get back here ASAP */ s->res.flags &= ~CF_EXPECT_MORE; /* speed up sending a previous response */ -#ifdef TCP_QUICKACK + if (sess->listener->options & LI_O_NOQUICKACK && htx_is_not_empty(htx) && objt_conn(sess->origin) && conn_ctrl_ready(__objt_conn(sess->origin))) { /* We need more data, we have to re-enable quick-ack in case we * previously disabled it, otherwise we might cause the client * to delay next data. */ - setsockopt(__objt_conn(sess->origin)->handle.fd, IPPROTO_TCP, TCP_QUICKACK, &one, sizeof(one)); + conn_set_quickack(objt_conn(sess->origin), 1); } -#endif + if ((req->flags & CF_READ_PARTIAL) && (txn->flags & TX_WAIT_NEXT_RQ)) { /* If the client starts to talk, let's fall back to * request timeout processing. @@ -951,17 +951,15 @@ int htx_process_request(struct stream *s, struct channel *req, int an_bit) req->analysers &= ~AN_REQ_FLT_XFER_DATA; req->analysers |= AN_REQ_HTTP_XFER_BODY; -#ifdef TCP_QUICKACK + /* We expect some data from the client. Unless we know for sure * we already have a full request, we have to re-enable quick-ack * in case we previously disabled it, otherwise we might cause * the client to delay further data. */ if ((sess->listener->options & LI_O_NOQUICKACK) && - cli_conn && conn_ctrl_ready(cli_conn) && (htx_get_tail_type(htx) != HTX_BLK_EOM)) - setsockopt(cli_conn->handle.fd, IPPROTO_TCP, TCP_QUICKACK, &one, sizeof(one)); -#endif + conn_set_quickack(cli_conn, 1); /************************************************************* * OK, that's finished for the headers. We have done what we * @@ -2754,7 +2752,6 @@ static enum rule_result htx_req_get_intercept_rule(struct proxy *px, struct list struct session *sess = strm_sess(s); struct http_txn *txn = s->txn; struct htx *htx; - struct connection *cli_conn; struct act_rule *rule; struct http_hdr_ctx ctx; const char *auth_realm; @@ -2850,15 +2847,11 @@ static enum rule_result htx_req_get_intercept_rule(struct proxy *px, struct list break; case ACT_HTTP_SET_TOS: - if ((cli_conn = objt_conn(sess->origin)) && conn_ctrl_ready(cli_conn)) - inet_set_tos(cli_conn->handle.fd, &cli_conn->addr.from, rule->arg.tos); + conn_set_tos(objt_conn(sess->origin), rule->arg.tos); break; case ACT_HTTP_SET_MARK: -#ifdef SO_MARK - if ((cli_conn = objt_conn(sess->origin)) && conn_ctrl_ready(cli_conn)) - setsockopt(cli_conn->handle.fd, SOL_SOCKET, SO_MARK, &rule->arg.mark, sizeof(rule->arg.mark)); -#endif + conn_set_mark(objt_conn(sess->origin), rule->arg.mark); break; case ACT_HTTP_SET_LOGL: @@ -3144,7 +3137,6 @@ static enum rule_result htx_res_get_intercept_rule(struct proxy *px, struct list struct session *sess = strm_sess(s); struct http_txn *txn = s->txn; struct htx *htx; - struct connection *cli_conn; struct act_rule *rule; struct http_hdr_ctx ctx; enum rule_result rule_ret = HTTP_RULE_RES_CONT; @@ -3197,15 +3189,11 @@ resume_execution: break; case ACT_HTTP_SET_TOS: - if ((cli_conn = objt_conn(sess->origin)) && conn_ctrl_ready(cli_conn)) - inet_set_tos(cli_conn->handle.fd, &cli_conn->addr.from, rule->arg.tos); + conn_set_tos(objt_conn(sess->origin), rule->arg.tos); break; case ACT_HTTP_SET_MARK: -#ifdef SO_MARK - if ((cli_conn = objt_conn(sess->origin)) && conn_ctrl_ready(cli_conn)) - setsockopt(cli_conn->handle.fd, SOL_SOCKET, SO_MARK, &rule->arg.mark, sizeof(rule->arg.mark)); -#endif + conn_set_mark(objt_conn(sess->origin), rule->arg.mark); break; case ACT_HTTP_SET_LOGL: -- 2.39.5