diff --git a/configs/open5gs/amf.yaml.in b/configs/open5gs/amf.yaml.in index 7b4240143b..0579b12cdc 100644 --- a/configs/open5gs/amf.yaml.in +++ b/configs/open5gs/amf.yaml.in @@ -290,6 +290,7 @@ pool: # # sockopt: # no_delay : true +# so_bindtodevice : true # sockopt: diff --git a/configs/open5gs/mme.yaml.in b/configs/open5gs/mme.yaml.in index ace42a7ef5..f3c78f169c 100644 --- a/configs/open5gs/mme.yaml.in +++ b/configs/open5gs/mme.yaml.in @@ -388,6 +388,7 @@ pool: # # sockopt: # no_delay : true +# so_bindtodevice : true # sockopt: diff --git a/configs/open5gs/sgwc.yaml.in b/configs/open5gs/sgwc.yaml.in index c530223616..96dd7dcd6a 100644 --- a/configs/open5gs/sgwc.yaml.in +++ b/configs/open5gs/sgwc.yaml.in @@ -160,6 +160,12 @@ max: # pool: +# +# sockopt: +# so_bindtodevice : true +# +sockopt: + # # time: # diff --git a/configs/open5gs/sgwu.yaml.in b/configs/open5gs/sgwu.yaml.in index 8824c72884..1e9c6b6fde 100644 --- a/configs/open5gs/sgwu.yaml.in +++ b/configs/open5gs/sgwu.yaml.in @@ -149,6 +149,13 @@ max: # pool: +# +# sockopt: +# no_delay : true +# so_bindtodevice : true +# +sockopt: + # # time: # diff --git a/configs/open5gs/smf.yaml.in b/configs/open5gs/smf.yaml.in index c462b8e512..8670a115b0 100644 --- a/configs/open5gs/smf.yaml.in +++ b/configs/open5gs/smf.yaml.in @@ -498,6 +498,12 @@ max: # pool: +# +# sockopt: +# so_bindtodevice : true +# +sockopt: + # # time: # diff --git a/configs/open5gs/upf.yaml.in b/configs/open5gs/upf.yaml.in index 3dd71f5a67..7f0018a840 100644 --- a/configs/open5gs/upf.yaml.in +++ b/configs/open5gs/upf.yaml.in @@ -220,6 +220,12 @@ max: # pool: +# +# sockopt: +# so_bindtodevice : true +# +sockopt: + # # time: # diff --git a/lib/app/ogs-context.c b/lib/app/ogs-context.c index a76d02f285..69add1078c 100644 --- a/lib/app/ogs-context.c +++ b/lib/app/ogs-context.c @@ -187,6 +187,7 @@ static void app_context_prepare(void) self.sctp.max_initial_timeout = 8000; /* 8 seconds */ self.sockopt.no_delay = true; + self.sockopt.so_bindtodevice = true; #define MAX_NUM_OF_UE 1024 /* Num of UE per AMF/MME */ #define MAX_NUM_OF_GNB 64 /* Num of gNB per AMF/MME */ @@ -376,6 +377,9 @@ int ogs_app_context_parse_config(void) const char *v = ogs_yaml_iter_value(&sockopt_iter); if (v) self.sockopt.l_linger = atoi(v); self.sockopt.l_onoff = true; + } else if (!strcmp(sockopt_key, "so_bindtodevice")) { + self.sockopt.so_bindtodevice = + ogs_yaml_iter_bool(&sockopt_iter); } else ogs_warn("unknown key `%s`", sockopt_key); } diff --git a/lib/app/ogs-context.h b/lib/app/ogs-context.h index 67bc75cf38..ec2eeaeced 100644 --- a/lib/app/ogs-context.h +++ b/lib/app/ogs-context.h @@ -84,6 +84,7 @@ typedef struct ogs_app_context_s { int no_delay; int l_onoff; int l_linger; + int so_bindtodevice; } sockopt; struct { diff --git a/lib/core/ogs-socket.c b/lib/core/ogs-socket.c index 774999f523..7ecd455474 100644 --- a/lib/core/ogs-socket.c +++ b/lib/core/ogs-socket.c @@ -331,3 +331,26 @@ int ogs_listen_reusable(ogs_socket_t fd) return OGS_OK; } + +int ogs_bind_to_device(ogs_socket_t fd, const char *device) +{ +#if defined(SO_BINDTODEVICE) && !defined(_WIN32) + int rc; + + ogs_assert(fd != INVALID_SOCKET); + ogs_assert(device); + rc = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device)+1); + if (rc != OGS_OK) { + ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno, + "setsockopt(SOL_SOCKET, SO_BINDTODEVICE, %s) failed", device); + ogs_error("You need to grant privileges to use SO_BINDTODEVICE."); + ogs_error("OR disable SO_BINDTODEVICE " + "in the configuration file as below."); + ogs_log_print(OGS_LOG_ERROR, "\nsockopt:\n"); + ogs_log_print(OGS_LOG_ERROR, " so_bindtodevice : false\n\n"); + return OGS_ERROR; + } +#endif + + return OGS_OK; +} diff --git a/lib/core/ogs-socket.h b/lib/core/ogs-socket.h index 8294b3c076..bd1e6f2021 100644 --- a/lib/core/ogs-socket.h +++ b/lib/core/ogs-socket.h @@ -74,6 +74,7 @@ int ogs_closesocket(ogs_socket_t fd); int ogs_nonblocking(ogs_socket_t fd); int ogs_closeonexec(ogs_socket_t fd); int ogs_listen_reusable(ogs_socket_t fd); +int ogs_bind_to_device(ogs_socket_t fd, const char *device); #ifdef __cplusplus } diff --git a/lib/core/ogs-socknode.c b/lib/core/ogs-socknode.c index 321a9b6dbf..cb566f77b9 100644 --- a/lib/core/ogs-socknode.c +++ b/lib/core/ogs-socknode.c @@ -51,6 +51,8 @@ void ogs_socknode_free(ogs_socknode_t *node) ogs_assert(node); ogs_freeaddrinfo(node->addr); + if (node->dev) + ogs_free(node->dev); if (node->poll) ogs_pollset_remove(node->poll); if (node->sock) { @@ -164,6 +166,8 @@ int ogs_socknode_probe( node = ogs_calloc(1, sizeof(ogs_socknode_t)); node->addr = addr; + if (dev) + node->dev = ogs_strdup(dev); if (addr->ogs_sa_family == AF_INET) { ogs_assert(list); diff --git a/lib/core/ogs-socknode.h b/lib/core/ogs-socknode.h index 6bb1cc0a35..2158e061be 100644 --- a/lib/core/ogs-socknode.h +++ b/lib/core/ogs-socknode.h @@ -35,6 +35,7 @@ typedef struct ogs_socknode_s { ogs_lnode_t node; ogs_sockaddr_t *addr; + char *dev; /* !NULL: used with SO_BINDTODEVICE */ ogs_sock_t *sock; void (*cleanup)(ogs_sock_t *sock); diff --git a/lib/core/ogs-udp.c b/lib/core/ogs-udp.c index 2e6954379e..6f640d1c62 100644 --- a/lib/core/ogs-udp.c +++ b/lib/core/ogs-udp.c @@ -33,7 +33,7 @@ ogs_sock_t *ogs_udp_socket(int family, ogs_socknode_t *node) return sock; } -ogs_sock_t *ogs_udp_server(ogs_socknode_t *node) +ogs_sock_t *ogs_udp_server(ogs_socknode_t *node, bool so_bindtodevice) { ogs_sock_t *new = NULL; ogs_sockaddr_t *addr; @@ -45,17 +45,26 @@ ogs_sock_t *ogs_udp_server(ogs_socknode_t *node) addr = node->addr; while (addr) { new = ogs_udp_socket(addr->ogs_sa_family, node); - if (new) { - if (ogs_sock_bind(new, addr) == OGS_OK) { - ogs_debug("udp_server() [%s]:%d", - OGS_ADDR(addr, buf), OGS_PORT(addr)); - break; - } - - ogs_sock_destroy(new); + if (!new) { + addr = addr->next; + continue; } - - addr = addr->next; + if (ogs_sock_bind(new, addr) != OGS_OK) { + ogs_sock_destroy(new); + addr = addr->next; + continue; + } + ogs_debug("udp_server() [%s]:%d", OGS_ADDR(addr, buf), OGS_PORT(addr)); + if (so_bindtodevice == true && node->dev) { + if (ogs_bind_to_device(new->fd, node->dev) != OGS_OK) { + ogs_sock_destroy(new); + addr = addr->next; + continue; + } + ogs_debug("udp_server() [%s]:%d bound to device %s", + OGS_ADDR(addr, buf), OGS_PORT(addr), node->dev); + } + break; } if (addr == NULL) { diff --git a/lib/core/ogs-udp.h b/lib/core/ogs-udp.h index c850a8d4ea..239de81134 100644 --- a/lib/core/ogs-udp.h +++ b/lib/core/ogs-udp.h @@ -29,7 +29,7 @@ extern "C" { #endif ogs_sock_t *ogs_udp_socket(int family, ogs_socknode_t *node); -ogs_sock_t *ogs_udp_server(ogs_socknode_t *node); +ogs_sock_t *ogs_udp_server(ogs_socknode_t *node, bool so_bindtodevice); ogs_sock_t *ogs_udp_client(ogs_socknode_t *node); int ogs_udp_connect(ogs_sock_t *sock, ogs_sockaddr_t *sa_list); diff --git a/lib/gtp/path.c b/lib/gtp/path.c index 4e01f4401f..0d7af6adf4 100644 --- a/lib/gtp/path.c +++ b/lib/gtp/path.c @@ -25,7 +25,7 @@ ogs_sock_t *ogs_gtp_server(ogs_socknode_t *node) ogs_sock_t *gtp; ogs_assert(node); - gtp = ogs_udp_server(node); + gtp = ogs_udp_server(node, ogs_app()->sockopt.so_bindtodevice); if (gtp) { ogs_info("gtp_server() [%s]:%d", OGS_ADDR(node->addr, buf), OGS_PORT(node->addr)); diff --git a/lib/pfcp/path.c b/lib/pfcp/path.c index 5822f75fd8..4cdd2dbf8d 100644 --- a/lib/pfcp/path.c +++ b/lib/pfcp/path.c @@ -25,7 +25,7 @@ ogs_sock_t *ogs_pfcp_server(ogs_socknode_t *node) ogs_sock_t *pfcp; ogs_assert(node); - pfcp = ogs_udp_server(node); + pfcp = ogs_udp_server(node, ogs_app()->sockopt.so_bindtodevice); if (pfcp) { ogs_info("pfcp_server() [%s]:%d", OGS_ADDR(node->addr, buf), OGS_PORT(node->addr)); diff --git a/tests/common/gtpu.c b/tests/common/gtpu.c index 5dd1412e73..304a7289b3 100644 --- a/tests/common/gtpu.c +++ b/tests/common/gtpu.c @@ -47,7 +47,7 @@ ogs_socknode_t *test_gtpu_server(int index, int family) node = ogs_socknode_new(addr); ogs_assert(node); - sock = ogs_udp_server(node); + sock = ogs_udp_server(node, false); ogs_assert(sock); return node; diff --git a/tests/core/poll-test.c b/tests/core/poll-test.c index 97be85ab68..e97c0fcb19 100644 --- a/tests/core/poll-test.c +++ b/tests/core/poll-test.c @@ -62,7 +62,7 @@ static void test1_func(abts_case *tc, void *data) ABTS_INT_EQUAL(tc, OGS_OK, rv); server[i] = ogs_socknode_new(addr); ABTS_PTR_NOTNULL(tc, server[i]); - ogs_udp_server(server[i]); + ogs_udp_server(server[i], false, false); ABTS_PTR_NOTNULL(tc, server[i]->sock); rv = ogs_getaddrinfo(&addr, AF_INET, "127.0.0.1", PORT+i, AI_PASSIVE); ABTS_INT_EQUAL(tc, OGS_OK, rv); @@ -293,7 +293,7 @@ static void test4_func(abts_case *tc, void *data) ABTS_INT_EQUAL(tc, OGS_OK, rv); node = ogs_socknode_new(addr); ABTS_PTR_NOTNULL(tc, node); - udp = ogs_udp_server(node); + udp = ogs_udp_server(node, false); ABTS_PTR_NOTNULL(tc, udp); poll = ogs_pollset_add(pollset, OGS_POLLIN, udp->fd, test4_handler, tc); diff --git a/tests/core/socket-test.c b/tests/core/socket-test.c index 60be7234c0..d19739e029 100644 --- a/tests/core/socket-test.c +++ b/tests/core/socket-test.c @@ -40,7 +40,7 @@ static void test1_func(abts_case *tc, void *data) ABTS_INT_EQUAL(tc, OGS_OK, rv); node = ogs_socknode_new(addr); ABTS_PTR_NOTNULL(tc, node); - udp = ogs_udp_server(node); + udp = ogs_udp_server(node, false); ABTS_PTR_NOTNULL(tc, udp); ogs_socknode_free(node); @@ -48,7 +48,7 @@ static void test1_func(abts_case *tc, void *data) ABTS_INT_EQUAL(tc, OGS_OK, rv); node = ogs_socknode_new(addr); ABTS_PTR_NOTNULL(tc, node); - udp = ogs_udp_server(node); + udp = ogs_udp_server(node, false); ABTS_PTR_NOTNULL(tc, udp); ogs_socknode_free(node); @@ -56,7 +56,7 @@ static void test1_func(abts_case *tc, void *data) ABTS_INT_EQUAL(tc, OGS_OK, rv); node = ogs_socknode_new(addr); ABTS_PTR_NOTNULL(tc, node); - udp = ogs_udp_server(node); + udp = ogs_udp_server(node, false); ABTS_PTR_NOTNULL(tc, udp); ogs_socknode_free(node); } @@ -154,7 +154,7 @@ static void test3_func(abts_case *tc, void *data) ABTS_INT_EQUAL(tc, OGS_OK, rv); node = ogs_socknode_new(addr); ABTS_PTR_NOTNULL(tc, node); - udp = ogs_udp_server(node); + udp = ogs_udp_server(node, false); ABTS_PTR_NOTNULL(tc, udp); test3_thread = ogs_thread_create(test3_main, tc); @@ -211,7 +211,7 @@ static void test4_func(abts_case *tc, void *data) ABTS_INT_EQUAL(tc, OGS_OK, rv); node = ogs_socknode_new(addr); ABTS_PTR_NOTNULL(tc, node); - udp = ogs_udp_server(node); + udp = ogs_udp_server(node, false); ABTS_PTR_NOTNULL(tc, udp); test4_thread = ogs_thread_create(test4_main, tc); @@ -244,7 +244,7 @@ static void test5_main(void *data) ABTS_INT_EQUAL(tc, OGS_OK, rv); node = ogs_socknode_new(addr); ABTS_PTR_NOTNULL(tc, node); - udp = ogs_udp_server(node); + udp = ogs_udp_server(node, false); ABTS_PTR_NOTNULL(tc, udp); rv = ogs_getaddrinfo(&addr, AF_INET6, NULL, PORT, 0); @@ -277,7 +277,7 @@ static void test5_func(abts_case *tc, void *data) ABTS_INT_EQUAL(tc, OGS_OK, rv); node = ogs_socknode_new(addr); ABTS_PTR_NOTNULL(tc, node); - udp = ogs_udp_server(node); + udp = ogs_udp_server(node, false); ABTS_PTR_NOTNULL(tc, udp); rv = ogs_getaddrinfo(&addr, AF_INET6, NULL, PORT2, 0); diff --git a/tests/non3gpp/gtp-path.c b/tests/non3gpp/gtp-path.c index d6e8a46931..45f06dc81d 100644 --- a/tests/non3gpp/gtp-path.c +++ b/tests/non3gpp/gtp-path.c @@ -38,7 +38,7 @@ ogs_socknode_t *test_epdg_server(uint16_t port) node = ogs_socknode_new(addr); ogs_assert(node); - sock = ogs_udp_server(node); + sock = ogs_udp_server(node, false); ogs_assert(sock); return node;