comparison src/core/ngx_connection.c @ 6153:4f6efabcb09b

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.
author Maxim Dounin <mdounin@mdounin.ru>
date Wed, 20 May 2015 15:51:56 +0300
parents adba26ff70b5
children 3096ae76ba47
comparison
equal deleted inserted replaced
6152:3c344ea7d88b 6153:4f6efabcb09b
85 #if (NGX_HAVE_TCP_FASTOPEN) 85 #if (NGX_HAVE_TCP_FASTOPEN)
86 ls->fastopen = -1; 86 ls->fastopen = -1;
87 #endif 87 #endif
88 88
89 return ls; 89 return ls;
90 }
91
92
93 ngx_int_t
94 ngx_clone_listening(ngx_conf_t *cf, ngx_listening_t *ls)
95 {
96 #if (NGX_HAVE_REUSEPORT)
97
98 ngx_int_t n;
99 ngx_core_conf_t *ccf;
100 ngx_listening_t ols;
101
102 if (!ls->reuseport) {
103 return NGX_OK;
104 }
105
106 ols = *ls;
107
108 ccf = (ngx_core_conf_t *) ngx_get_conf(cf->cycle->conf_ctx,
109 ngx_core_module);
110
111 for (n = 1; n < ccf->worker_processes; n++) {
112
113 /* create a socket for each worker process */
114
115 ls = ngx_array_push(&cf->cycle->listening);
116 if (ls == NULL) {
117 return NGX_ERROR;
118 }
119
120 *ls = ols;
121 ls->worker = n;
122 }
123
124 #endif
125
126 return NGX_OK;
90 } 127 }
91 128
92 129
93 ngx_int_t 130 ngx_int_t
94 ngx_set_inherited_sockets(ngx_cycle_t *cycle) 131 ngx_set_inherited_sockets(ngx_cycle_t *cycle)
104 struct accept_filter_arg af; 141 struct accept_filter_arg af;
105 #endif 142 #endif
106 #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) 143 #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
107 int timeout; 144 int timeout;
108 #endif 145 #endif
146 #if (NGX_HAVE_REUSEPORT)
147 int reuseport;
148 #endif
109 149
110 ls = cycle->listening.elts; 150 ls = cycle->listening.elts;
111 for (i = 0; i < cycle->listening.nelts; i++) { 151 for (i = 0; i < cycle->listening.nelts; i++) {
112 152
113 ls[i].sockaddr = ngx_palloc(cycle->pool, NGX_SOCKADDRLEN); 153 ls[i].sockaddr = ngx_palloc(cycle->pool, NGX_SOCKADDRLEN);
211 251
212 ls[i].setfib = -1; 252 ls[i].setfib = -1;
213 } 253 }
214 254
215 #endif 255 #endif
256 #endif
257
258 #if (NGX_HAVE_REUSEPORT)
259
260 reuseport = 0;
261 olen = sizeof(int);
262
263 if (getsockopt(ls[i].fd, SOL_SOCKET, SO_REUSEPORT,
264 (void *) &reuseport, &olen)
265 == -1)
266 {
267 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
268 "getsockopt(SO_REUSEPORT) %V failed, ignored",
269 &ls[i].addr_text);
270
271 } else {
272 ls[i].reuseport = reuseport ? 1 : 0;
273 }
274
216 #endif 275 #endif
217 276
218 #if (NGX_HAVE_TCP_FASTOPEN) 277 #if (NGX_HAVE_TCP_FASTOPEN)
219 278
220 olen = sizeof(int); 279 olen = sizeof(int);
330 389
331 if (ls[i].ignore) { 390 if (ls[i].ignore) {
332 continue; 391 continue;
333 } 392 }
334 393
394 #if (NGX_HAVE_REUSEPORT)
395
396 if (ls[i].add_reuseport) {
397
398 /*
399 * to allow transition from a socket without SO_REUSEPORT
400 * to multiple sockets with SO_REUSEPORT, we have to set
401 * SO_REUSEPORT on the old socket before opening new ones
402 */
403
404 int reuseport = 1;
405
406 if (setsockopt(ls[i].fd, SOL_SOCKET, SO_REUSEPORT,
407 (const void *) &reuseport, sizeof(int))
408 == -1)
409 {
410 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
411 "setsockopt(SO_REUSEPORT) %V failed, ignored",
412 &ls[i].addr_text);
413 }
414
415 ls[i].add_reuseport = 0;
416 }
417 #endif
418
335 if (ls[i].fd != (ngx_socket_t) -1) { 419 if (ls[i].fd != (ngx_socket_t) -1) {
336 continue; 420 continue;
337 } 421 }
338 422
339 if (ls[i].inherited) { 423 if (ls[i].inherited) {
367 &ls[i].addr_text); 451 &ls[i].addr_text);
368 } 452 }
369 453
370 return NGX_ERROR; 454 return NGX_ERROR;
371 } 455 }
456
457 #if (NGX_HAVE_REUSEPORT)
458
459 if (ls[i].reuseport) {
460 int reuseport;
461
462 reuseport = 1;
463
464 if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT,
465 (const void *) &reuseport, sizeof(int))
466 == -1)
467 {
468 ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
469 "setsockopt(SO_REUSEPORT) %V failed, ignored",
470 &ls[i].addr_text);
471
472 if (ngx_close_socket(s) == -1) {
473 ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
474 ngx_close_socket_n " %V failed",
475 &ls[i].addr_text);
476 }
477
478 return NGX_ERROR;
479 }
480 }
481 #endif
372 482
373 #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) 483 #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
374 484
375 if (ls[i].sockaddr->sa_family == AF_INET6) { 485 if (ls[i].sockaddr->sa_family == AF_INET6) {
376 int ipv6only; 486 int ipv6only;