From d5c1acc37da918e3559e17b80e3642155ea46964 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Tue, 8 Feb 2022 18:28:24 +0000 Subject: [PATCH] socket module add SO_ATTACH_REUSEPORT_CPBF for Linux. to be used in conjunction with SO_REUSPORT, giving a greater control over how we bind a socket instead of the round robin workflow, we do instead attach to the processor id as : - we assign the processor_id to A in the BPF filter. - then returns A. in other words, a more modern version of SO_INCOMING_CPU (ie can have a per worker notion we do not use here). --- ext/sockets/config.m4 | 2 +- ext/sockets/sockets.c | 35 ++++++++++++++++++++ ext/sockets/sockets.stub.php | 21 ++++++++++++ ext/sockets/sockets_arginfo.h | 11 +++++- ext/sockets/tests/socket_reuseport_cbpf.phpt | 30 +++++++++++++++++ 5 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 ext/sockets/tests/socket_reuseport_cbpf.phpt diff --git a/ext/sockets/config.m4 b/ext/sockets/config.m4 index aafedcb99ddd3..d7eb86d986fbb 100644 --- a/ext/sockets/config.m4 +++ b/ext/sockets/config.m4 @@ -5,7 +5,7 @@ PHP_ARG_ENABLE([sockets], if test "$PHP_SOCKETS" != "no"; then AC_CHECK_FUNCS([hstrerror if_nametoindex if_indextoname]) - AC_CHECK_HEADERS([netinet/tcp.h sys/un.h sys/sockio.h]) + AC_CHECK_HEADERS([netinet/tcp.h sys/un.h sys/sockio.h linux/filter.h]) AC_DEFINE([HAVE_SOCKETS], 1, [ ]) dnl Check for fied ss_family in sockaddr_storage (missing in AIX until 5.3) diff --git a/ext/sockets/sockets.c b/ext/sockets/sockets.c index 2a55a72432e50..0f008419562e9 100644 --- a/ext/sockets/sockets.c +++ b/ext/sockets/sockets.c @@ -1741,6 +1741,7 @@ PHP_FUNCTION(socket_get_option) return; } #endif + } } @@ -1960,6 +1961,40 @@ PHP_FUNCTION(socket_set_option) } #endif +#ifdef SO_ATTACH_REUSEPORT_CBPF + case SO_ATTACH_REUSEPORT_CBPF: { + convert_to_long(arg4); + + if (!Z_LVAL_P(arg4)) { + ov = 1; + optlen = sizeof(ov); + opt_ptr = &ov; + optname = SO_DETACH_BPF; + } else { + uint32_t k = (uint32_t)Z_LVAL_P(arg4); + static struct sock_filter cbpf[8] = {0}; + static struct sock_fprog bpfprog; + + switch (k) { + case SKF_AD_CPU: + cbpf[0].code = (BPF_LD|BPF_W|BPF_ABS); + cbpf[0].k = (uint32_t)(SKF_AD_OFF + k); + cbpf[1].code = (BPF_RET|BPF_A); + bpfprog.len = 2; + break; + default: + php_error_docref(NULL, E_WARNING, "Unsupported CBPF filter"); + RETURN_FALSE; + } + + bpfprog.filter = cbpf; + optlen = sizeof(bpfprog); + opt_ptr = &bpfprog; + } + break; + } +#endif + default: default_case: convert_to_long(arg4); diff --git a/ext/sockets/sockets.stub.php b/ext/sockets/sockets.stub.php index 9e4664d045139..410d9f0e7e6d0 100644 --- a/ext/sockets/sockets.stub.php +++ b/ext/sockets/sockets.stub.php @@ -1678,6 +1678,27 @@ */ const LOCAL_CREDS = UNKNOWN; #endif +#if defined(SO_ATTACH_REUSEPORT_CBPF) +/** + * @var int + * @cvalue SO_ATTACH_REUSEPORT_CBPF + */ +const SO_ATTACH_REUSEPORT_CBPF = UNKNOWN; +#endif +#if defined(SO_DETACH_FILTER) +/** + * @var int + * @cvalue SO_DETACH_FILTER + */ +const SO_DETACH_FILTER = UNKNOWN; +#endif +#if defined(SO_DETACH_BPF) +/** + * @var int + * @cvalue SO_DETACH_BPF + */ +const SO_DETACH_BPF = UNKNOWN; +#endif /** * @strict-properties diff --git a/ext/sockets/sockets_arginfo.h b/ext/sockets/sockets_arginfo.h index c2e3c18b2cd65..a59373e8babd8 100644 --- a/ext/sockets/sockets_arginfo.h +++ b/ext/sockets/sockets_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: d28c6b566f4739b1eaefb82032e620aeb59728dc */ + * Stub hash: 546bd6fd43a68c8b6a95b4145afa94c04e36364a */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_socket_select, 0, 4, MAY_BE_LONG|MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(1, read, IS_ARRAY, 1) @@ -967,6 +967,15 @@ static void register_sockets_symbols(int module_number) #if (!defined(LOCAL_CREDS_PERSISTENT) && defined(LOCAL_CREDS)) REGISTER_LONG_CONSTANT("LOCAL_CREDS", LOCAL_CREDS, CONST_PERSISTENT); #endif +#if defined(SO_ATTACH_REUSEPORT_CBPF) + REGISTER_LONG_CONSTANT("SO_ATTACH_REUSEPORT_CBPF", SO_ATTACH_REUSEPORT_CBPF, CONST_PERSISTENT); +#endif +#if defined(SO_DETACH_FILTER) + REGISTER_LONG_CONSTANT("SO_DETACH_FILTER", SO_DETACH_FILTER, CONST_PERSISTENT); +#endif +#if defined(SO_DETACH_BPF) + REGISTER_LONG_CONSTANT("SO_DETACH_BPF", SO_DETACH_BPF, CONST_PERSISTENT); +#endif } static zend_class_entry *register_class_Socket(void) diff --git a/ext/sockets/tests/socket_reuseport_cbpf.phpt b/ext/sockets/tests/socket_reuseport_cbpf.phpt new file mode 100644 index 0000000000000..1d4824dca1c81 --- /dev/null +++ b/ext/sockets/tests/socket_reuseport_cbpf.phpt @@ -0,0 +1,30 @@ +--TEST-- +Test if socket_set_option() works, option:SO_ATTACH_REUSEPORT_CBPF +--EXTENSIONS-- +sockets +--SKIPIF-- + +--FILE-- + +--EXPECT-- +bool(true) +bool(true) +bool(true) +bool(true)