[PATCH] Proxy: tcp fast open in client mode

Jan Prachař jan.prachar at gmail.com
Thu Oct 5 13:12:42 UTC 2017


What do you think about adding support for tcp fast open in the proxy
module when connecting to upstream?
---
 nginx/conf/nginx/nginx.conf                    |  1 +
 nginx/contrib/vim/syntax/nginx.vim             |  1 +
 nginx/src/core/ngx_connection.h                |  1 +
 nginx/src/event/ngx_event_connect.c            |  9 +++++++++
 nginx/src/event/ngx_event_connect.h            |  1 +
 nginx/src/http/modules/ngx_http_proxy_module.c | 15 +++++++++++++++
 nginx/src/http/ngx_http_upstream.h             |  1 +
 nginx/src/os/unix/ngx_send.c                   | 12 ++++++++++--
 nginx/src/os/unix/ngx_writev_chain.c           | 14 ++++++++++++++
 9 files changed, 53 insertions(+), 2 deletions(-)

diff --git a/nginx/conf/nginx/nginx.conf b/nginx/conf/nginx/nginx.conf
index e1a090132..6d32dfac5 100644
--- a/nginx/conf/nginx/nginx.conf
+++ b/nginx/conf/nginx/nginx.conf
@@ -107,6 +107,7 @@ http
     proxy_max_temp_file_size 0;
     proxy_ignore_client_abort on;
     proxy_temp_path /var/cache/nginx/tmp;
+    proxy_tcp_fastopen on;
 
     proxy_set_header Host $resource_origin;
     proxy_set_header Via $upstream_header_via;
diff --git a/nginx/contrib/vim/syntax/nginx.vim
b/nginx/contrib/vim/syntax/nginx.vim
index e7aadea9c..63e05b3bf 100644
--- a/nginx/contrib/vim/syntax/nginx.vim
+++ b/nginx/contrib/vim/syntax/nginx.vim
@@ -399,6 +399,7 @@ syn keyword ngxDirective contained
proxy_headers_hash_bucket_size
 syn keyword ngxDirective contained proxy_headers_hash_max_size
 syn keyword ngxDirective contained proxy_hide_header
 syn keyword ngxDirective contained proxy_http_version
+syn keyword ngxDirective contained proxy_tcp_fastopen
 syn keyword ngxDirective contained proxy_ignore_client_abort
 syn keyword ngxDirective contained proxy_ignore_headers
 syn keyword ngxDirective contained proxy_intercept_errors
diff --git a/nginx/src/core/ngx_connection.h
b/nginx/src/core/ngx_connection.h
index e4dfe5879..bcfe2f6d8 100644
--- a/nginx/src/core/ngx_connection.h
+++ b/nginx/src/core/ngx_connection.h
@@ -179,6 +179,7 @@ struct ngx_connection_s {
     unsigned            sndlowat:1;
     unsigned            tcp_nodelay:2;   /*
ngx_connection_tcp_nodelay_e */
     unsigned            tcp_nopush:2;    /*
ngx_connection_tcp_nopush_e */
+    unsigned            tcp_fastopen:1;
 
     unsigned            need_last_buf:1;
 
diff --git a/nginx/src/event/ngx_event_connect.c
b/nginx/src/event/ngx_event_connect.c
index c5bb80681..f24804dd9 100644
--- a/nginx/src/event/ngx_event_connect.c
+++ b/nginx/src/event/ngx_event_connect.c
@@ -190,6 +190,15 @@ ngx_event_connect_peer(ngx_peer_connection_t *pc)
     ngx_log_debug3(NGX_LOG_DEBUG_EVENT, pc->log, 0,
                    "connect to %V, fd:%d #%uA", pc->name, s, c-
>number);
 
+#if (NGX_LINUX) && defined(MSG_FASTOPEN)
+    if (pc->tcp_fastopen && type == SOCK_STREAM) {
+        rc = 0; /* Do nothing now */
+
+        c->sockaddr = pc->sockaddr;
+        c->socklen = pc->socklen;
+        c->tcp_fastopen = 1;
+    } else
+#endif
     rc = connect(s, pc->sockaddr, pc->socklen);
 
     if (rc == -1) {
diff --git a/nginx/src/event/ngx_event_connect.h
b/nginx/src/event/ngx_event_connect.h
index 72d21d7f3..ebc6b78a7 100644
--- a/nginx/src/event/ngx_event_connect.h
+++ b/nginx/src/event/ngx_event_connect.h
@@ -62,6 +62,7 @@ struct ngx_peer_connection_s {
 
     unsigned                         cached:1;
     unsigned                         transparent:1;
+    unsigned                         tcp_fastopen:1;
 
                                      /* ngx_connection_log_error_e */
     unsigned                         log_error:2;
diff --git a/nginx/src/http/modules/ngx_http_proxy_module.c
b/nginx/src/http/modules/ngx_http_proxy_module.c
index d8b5541e1..27c25bdfb 100644
--- a/nginx/src/http/modules/ngx_http_proxy_module.c
+++ b/nginx/src/http/modules/ngx_http_proxy_module.c
@@ -653,6 +653,13 @@ static ngx_command_t  ngx_http_proxy_commands[] =
{
       offsetof(ngx_http_proxy_loc_conf_t, http_version),
       &ngx_http_proxy_http_version },
 
+    { ngx_string("proxy_tcp_fastopen"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_
FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_proxy_loc_conf_t, upstream.tcp_fastopen),
+      NULL },
+
 #if (NGX_HTTP_SSL)
 
     { ngx_string("proxy_ssl_session_reuse"),
@@ -956,6 +963,10 @@ ngx_http_proxy_handler(ngx_http_request_t *r)
         r->request_body_no_buffering = 1;
     }
 
+    if (plcf->upstream.tcp_fastopen) {
+        u->peer.tcp_fastopen = 1;
+    }
+
     rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);
 
     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
@@ -3074,6 +3085,8 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
 
     conf->http_version = NGX_CONF_UNSET_UINT;
 
+    conf->upstream.tcp_fastopen = NGX_CONF_UNSET;
+
     conf->headers_hash_max_size = NGX_CONF_UNSET_UINT;
     conf->headers_hash_bucket_size = NGX_CONF_UNSET_UINT;
 
@@ -3473,6 +3486,8 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf,
void *parent, void *child)
     ngx_conf_merge_uint_value(conf->http_version, prev->http_version,
                               NGX_HTTP_VERSION_10);
 
+    ngx_conf_merge_value(conf->upstream.tcp_fastopen, prev-
>upstream.tcp_fastopen, 0);
+
     ngx_conf_merge_uint_value(conf->headers_hash_max_size,
                               prev->headers_hash_max_size, 512);
 
diff --git a/nginx/src/http/ngx_http_upstream.h
b/nginx/src/http/ngx_http_upstream.h
index 089374f65..b2a360f86 100644
--- a/nginx/src/http/ngx_http_upstream.h
+++ b/nginx/src/http/ngx_http_upstream.h
@@ -184,6 +184,7 @@ typedef struct {
     ngx_flag_t                       intercept_errors;
     ngx_flag_t                       cyclic_temp_file;
     ngx_flag_t                       force_ranges;
+    ngx_flag_t                       tcp_fastopen;
 
     ngx_path_t                      *temp_path;
 
diff --git a/nginx/src/os/unix/ngx_send.c
b/nginx/src/os/unix/ngx_send.c
index 61ea20252..0559cb76d 100644
--- a/nginx/src/os/unix/ngx_send.c
+++ b/nginx/src/os/unix/ngx_send.c
@@ -31,6 +31,14 @@ ngx_unix_send(ngx_connection_t *c, u_char *buf,
size_t size)
 #endif
 
     for ( ;; ) {
+#if (NGX_LINUX) && defined(MSG_FASTOPEN)
+        if (c->tcp_fastopen) {
+
+            n = sendto(c->fd, buf, size, MSG_FASTOPEN, c->sockaddr, c-
>socklen);
+            c->tcp_fastopen = 0;
+
+        } else
+#endif
         n = send(c->fd, buf, size, 0);
 
         ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
@@ -54,13 +62,13 @@ ngx_unix_send(ngx_connection_t *c, u_char *buf,
size_t size)
             return n;
         }
 
-        if (err == NGX_EAGAIN || err == NGX_EINTR) {
+        if (err == NGX_EAGAIN || err == NGX_EINTR || err ==
NGX_EINPROGRESS) {
             wev->ready = 0;
 
             ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
                            "send() not ready");
 
-            if (err == NGX_EAGAIN) {
+            if (err == NGX_EAGAIN || err == NGX_EINPROGRESS) {
                 return NGX_AGAIN;
             }
 
diff --git a/nginx/src/os/unix/ngx_writev_chain.c
b/nginx/src/os/unix/ngx_writev_chain.c
index e38a3aae0..349b07900 100644
--- a/nginx/src/os/unix/ngx_writev_chain.c
+++ b/nginx/src/os/unix/ngx_writev_chain.c
@@ -186,6 +186,19 @@ ngx_writev(ngx_connection_t *c, ngx_iovec_t *vec)
 
 eintr:
 
+#if (NGX_LINUX) && defined(MSG_FASTOPEN)
+    if (c->tcp_fastopen) {
+        if (vec->count > 0) {
+
+            n = sendto(c->fd, vec->iovs[0].iov_base, vec-
>iovs[0].iov_len,
+                    MSG_FASTOPEN, c->sockaddr, c->socklen);
+            c->tcp_fastopen = 0;
+
+        } else {
+            n = 0;
+        }
+    } else
+#endif
     n = writev(c->fd, vec->iovs, vec->count);
 
     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
@@ -195,6 +208,7 @@ eintr:
         err = ngx_errno;
 
         switch (err) {
+        case NGX_EINPROGRESS:
         case NGX_EAGAIN:
             ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
                            "writev() not ready");
-- 
2.14.2



More information about the nginx-devel mailing list