|  | @@ -46,11 +46,16 @@
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void accept_connection(h2o_socket_t *listener, const char *err);
 | 
	
		
			
				|  |  |  static void accept_http_connection(h2o_socket_t *listener, const char *err);
 | 
	
		
			
				|  |  | -static int get_listener_socket(const char *bind_address, uint16_t port);
 | 
	
		
			
				|  |  | +static int get_listener_socket(bool is_main_thread,
 | 
	
		
			
				|  |  | +                               int bpf_fd,
 | 
	
		
			
				|  |  | +                               const char *bind_address,
 | 
	
		
			
				|  |  | +                               uint16_t port);
 | 
	
		
			
				|  |  |  static void on_close_connection(void *data);
 | 
	
		
			
				|  |  |  static void process_messages(h2o_multithread_receiver_t *receiver, h2o_linklist_t *messages);
 | 
	
		
			
				|  |  |  static void shutdown_server(h2o_socket_t *listener, const char *err);
 | 
	
		
			
				|  |  | -static void start_accept_polling(const config_t *config,
 | 
	
		
			
				|  |  | +static void start_accept_polling(bool is_main_thread,
 | 
	
		
			
				|  |  | +                                 int bpf_fd,
 | 
	
		
			
				|  |  | +                                 const config_t *config,
 | 
	
		
			
				|  |  |                                   h2o_socket_cb accept_cb,
 | 
	
		
			
				|  |  |                                   bool is_https,
 | 
	
		
			
				|  |  |                                   event_loop_t *loop);
 | 
	
	
		
			
				|  | @@ -98,7 +103,10 @@ static void accept_http_connection(h2o_socket_t *listener, const char *err)
 | 
	
		
			
				|  |  |  	ctx->event_loop.h2o_accept_ctx.ssl_ctx = ssl_ctx;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static int get_listener_socket(const char *bind_address, uint16_t port)
 | 
	
		
			
				|  |  | +static int get_listener_socket(bool is_main_thread,
 | 
	
		
			
				|  |  | +                               int bpf_fd,
 | 
	
		
			
				|  |  | +                               const char *bind_address,
 | 
	
		
			
				|  |  | +                               uint16_t port)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |  	int ret = -1;
 | 
	
		
			
				|  |  |  	char buf[16];
 | 
	
	
		
			
				|  | @@ -148,6 +156,15 @@ static int get_listener_socket(const char *bind_address, uint16_t port)
 | 
	
		
			
				|  |  |  		LOCAL_CHECK_ERRNO(setsockopt, s, IPPROTO_TCP, TCP_FASTOPEN, &option, sizeof(option));
 | 
	
		
			
				|  |  |  		LOCAL_CHECK_ERRNO(bind, s, iter->ai_addr, iter->ai_addrlen);
 | 
	
		
			
				|  |  |  		LOCAL_CHECK_ERRNO(listen, s, INT_MAX);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		if (is_main_thread && bpf_fd >= 0)
 | 
	
		
			
				|  |  | +			LOCAL_CHECK_ERRNO(setsockopt,
 | 
	
		
			
				|  |  | +			                  s,
 | 
	
		
			
				|  |  | +			                  SOL_SOCKET,
 | 
	
		
			
				|  |  | +			                  SO_ATTACH_REUSEPORT_EBPF,
 | 
	
		
			
				|  |  | +			                  &bpf_fd,
 | 
	
		
			
				|  |  | +			                  sizeof(bpf_fd));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  		ret = s;
 | 
	
		
			
				|  |  |  		break;
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -256,16 +273,17 @@ static void shutdown_server(h2o_socket_t *listener, const char *err)
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static void start_accept_polling(const config_t *config,
 | 
	
		
			
				|  |  | +static void start_accept_polling(bool is_main_thread,
 | 
	
		
			
				|  |  | +                                 int bpf_fd,
 | 
	
		
			
				|  |  | +                                 const config_t *config,
 | 
	
		
			
				|  |  |                                   h2o_socket_cb accept_cb,
 | 
	
		
			
				|  |  |                                   bool is_https,
 | 
	
		
			
				|  |  |                                   event_loop_t *loop)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -	const int listener_sd = get_listener_socket(config->bind_address,
 | 
	
		
			
				|  |  | +	const int listener_sd = get_listener_socket(is_main_thread,
 | 
	
		
			
				|  |  | +	                                            bpf_fd,
 | 
	
		
			
				|  |  | +	                                            config->bind_address,
 | 
	
		
			
				|  |  |  	                                            is_https ? config->https_port : config->port);
 | 
	
		
			
				|  |  | -	// Let all the threads race to call accept() on the socket; since the latter is
 | 
	
		
			
				|  |  | -	// non-blocking, that will virtually act as load balancing, and SO_REUSEPORT
 | 
	
		
			
				|  |  | -	// will make it efficient.
 | 
	
		
			
				|  |  |  	h2o_socket_t * const h2o_socket = h2o_evloop_socket_create(loop->h2o_ctx.loop,
 | 
	
		
			
				|  |  |  	                                                           listener_sd,
 | 
	
		
			
				|  |  |  	                                                           H2O_SOCKET_FLAG_DONT_READ);
 | 
	
	
		
			
				|  | @@ -345,13 +363,18 @@ void initialize_event_loop(bool is_main_thread,
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	if (global_data->ssl_ctx) {
 | 
	
		
			
				|  |  |  		loop->h2o_accept_ctx.ssl_ctx = global_data->ssl_ctx;
 | 
	
		
			
				|  |  | -		start_accept_polling(config, accept_connection, true, loop);
 | 
	
		
			
				|  |  | +		start_accept_polling(is_main_thread,
 | 
	
		
			
				|  |  | +		                     global_data->bpf_fd,
 | 
	
		
			
				|  |  | +		                     config,
 | 
	
		
			
				|  |  | +		                     accept_connection,
 | 
	
		
			
				|  |  | +		                     true,
 | 
	
		
			
				|  |  | +		                     loop);
 | 
	
		
			
				|  |  |  		// Assume that the majority of the connections use HTTPS,
 | 
	
		
			
				|  |  |  		// so HTTP can take a few extra operations.
 | 
	
		
			
				|  |  |  		accept_cb = accept_http_connection;
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	start_accept_polling(config, accept_cb, false, loop);
 | 
	
		
			
				|  |  | +	start_accept_polling(is_main_thread, global_data->bpf_fd, config, accept_cb, false, loop);
 | 
	
		
			
				|  |  |  	h2o_multithread_register_receiver(loop->h2o_ctx.queue,
 | 
	
		
			
				|  |  |  	                                  h2o_receiver,
 | 
	
		
			
				|  |  |  	                                  process_messages);
 |