Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nginx/nginx.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaxim Dounin <mdounin@mdounin.ru>2015-05-20 15:51:56 +0300
committerMaxim Dounin <mdounin@mdounin.ru>2015-05-20 15:51:56 +0300
commitf7f1607bf2b8b7c45834b66cb45f6445bee65587 (patch)
tree8a458d848d86e6b0e7f9108fd1b792d709091965 /src/core/ngx_connection.c
parentd5c34785bc55164afb7cfe7de1badcebdb05fb8d (diff)
The "reuseport" option of the "listen" directive.
When configured, an individual listen socket on a given address is created for each worker process. This allows to reduce in-kernel lock contention on configurations with high accept rates, resulting in better performance. As of now it works on Linux and DragonFly BSD. Note that on Linux incoming connection requests are currently tied up to a specific listen socket, and if some sockets are closed, connection requests will be reset, see https://lwn.net/Articles/542629/. With nginx, this may happen if the number of worker processes is reduced. There is no such problem on DragonFly BSD. Based on previous work by Sepherosa Ziehau and Yingqi Lu.
Diffstat (limited to 'src/core/ngx_connection.c')
-rw-r--r--src/core/ngx_connection.c110
1 files changed, 110 insertions, 0 deletions
diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c
index 52b97ce89..04a365a76 100644
--- a/src/core/ngx_connection.c
+++ b/src/core/ngx_connection.c
@@ -91,6 +91,43 @@ ngx_create_listening(ngx_conf_t *cf, void *sockaddr, socklen_t socklen)
ngx_int_t
+ngx_clone_listening(ngx_conf_t *cf, ngx_listening_t *ls)
+{
+#if (NGX_HAVE_REUSEPORT)
+
+ ngx_int_t n;
+ ngx_core_conf_t *ccf;
+ ngx_listening_t ols;
+
+ if (!ls->reuseport) {
+ return NGX_OK;
+ }
+
+ ols = *ls;
+
+ ccf = (ngx_core_conf_t *) ngx_get_conf(cf->cycle->conf_ctx,
+ ngx_core_module);
+
+ for (n = 1; n < ccf->worker_processes; n++) {
+
+ /* create a socket for each worker process */
+
+ ls = ngx_array_push(&cf->cycle->listening);
+ if (ls == NULL) {
+ return NGX_ERROR;
+ }
+
+ *ls = ols;
+ ls->worker = n;
+ }
+
+#endif
+
+ return NGX_OK;
+}
+
+
+ngx_int_t
ngx_set_inherited_sockets(ngx_cycle_t *cycle)
{
size_t len;
@@ -106,6 +143,9 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle)
#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
int timeout;
#endif
+#if (NGX_HAVE_REUSEPORT)
+ int reuseport;
+#endif
ls = cycle->listening.elts;
for (i = 0; i < cycle->listening.nelts; i++) {
@@ -215,6 +255,25 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle)
#endif
#endif
+#if (NGX_HAVE_REUSEPORT)
+
+ reuseport = 0;
+ olen = sizeof(int);
+
+ if (getsockopt(ls[i].fd, SOL_SOCKET, SO_REUSEPORT,
+ (void *) &reuseport, &olen)
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
+ "getsockopt(SO_REUSEPORT) %V failed, ignored",
+ &ls[i].addr_text);
+
+ } else {
+ ls[i].reuseport = reuseport ? 1 : 0;
+ }
+
+#endif
+
#if (NGX_HAVE_TCP_FASTOPEN)
olen = sizeof(int);
@@ -332,6 +391,31 @@ ngx_open_listening_sockets(ngx_cycle_t *cycle)
continue;
}
+#if (NGX_HAVE_REUSEPORT)
+
+ if (ls[i].add_reuseport) {
+
+ /*
+ * to allow transition from a socket without SO_REUSEPORT
+ * to multiple sockets with SO_REUSEPORT, we have to set
+ * SO_REUSEPORT on the old socket before opening new ones
+ */
+
+ int reuseport = 1;
+
+ if (setsockopt(ls[i].fd, SOL_SOCKET, SO_REUSEPORT,
+ (const void *) &reuseport, sizeof(int))
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
+ "setsockopt(SO_REUSEPORT) %V failed, ignored",
+ &ls[i].addr_text);
+ }
+
+ ls[i].add_reuseport = 0;
+ }
+#endif
+
if (ls[i].fd != (ngx_socket_t) -1) {
continue;
}
@@ -370,6 +454,32 @@ ngx_open_listening_sockets(ngx_cycle_t *cycle)
return NGX_ERROR;
}
+#if (NGX_HAVE_REUSEPORT)
+
+ if (ls[i].reuseport) {
+ int reuseport;
+
+ reuseport = 1;
+
+ if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT,
+ (const void *) &reuseport, sizeof(int))
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+ "setsockopt(SO_REUSEPORT) %V failed, ignored",
+ &ls[i].addr_text);
+
+ if (ngx_close_socket(s) == -1) {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+ ngx_close_socket_n " %V failed",
+ &ls[i].addr_text);
+ }
+
+ return NGX_ERROR;
+ }
+ }
+#endif
+
#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
if (ls[i].sockaddr->sa_family == AF_INET6) {