forked from acouzens/open5gs
[GTP] Support binding socket to device
This is useful, among other possible applications, to make use of VRFs [1], in this case for GTP-C and GTP-U traffic in the PGW. The bind_dev field is added to the ogs_socknode_t so that it's easy to extend its use into lots of other sockets being set up based on config file information. [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/networking/vrf.rst
This commit is contained in:
parent
ed3444eef5
commit
7bddc92322
|
@ -331,3 +331,22 @@ 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);
|
||||
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);
|
||||
return OGS_ERROR;
|
||||
}
|
||||
return OGS_OK;
|
||||
#else
|
||||
return OGS_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -51,6 +51,8 @@ void ogs_socknode_free(ogs_socknode_t *node)
|
|||
ogs_assert(node);
|
||||
|
||||
ogs_freeaddrinfo(node->addr);
|
||||
if (node->bind_dev)
|
||||
ogs_free(node->bind_dev);
|
||||
if (node->poll)
|
||||
ogs_pollset_remove(node->poll);
|
||||
if (node->sock) {
|
||||
|
@ -101,7 +103,8 @@ void ogs_socknode_remove_all(ogs_list_t *list)
|
|||
}
|
||||
|
||||
int ogs_socknode_probe(
|
||||
ogs_list_t *list, ogs_list_t *list6, const char *dev, uint16_t port)
|
||||
ogs_list_t *list, ogs_list_t *list6, const char *dev, uint16_t port,
|
||||
const char *bind_device)
|
||||
{
|
||||
#if defined(HAVE_GETIFADDRS)
|
||||
ogs_socknode_t *node = NULL;
|
||||
|
@ -164,6 +167,8 @@ int ogs_socknode_probe(
|
|||
|
||||
node = ogs_calloc(1, sizeof(ogs_socknode_t));
|
||||
node->addr = addr;
|
||||
if (bind_device)
|
||||
node->bind_dev = ogs_strdup(bind_device);
|
||||
|
||||
if (addr->ogs_sa_family == AF_INET) {
|
||||
ogs_assert(list);
|
||||
|
|
|
@ -39,6 +39,7 @@ typedef struct ogs_socknode_s {
|
|||
ogs_sock_t *sock;
|
||||
void (*cleanup)(ogs_sock_t *sock);
|
||||
ogs_poll_t *poll;
|
||||
char *bind_dev; /* !NULL: used with SO_BINDTODEVICE */
|
||||
} ogs_socknode_t;
|
||||
|
||||
ogs_socknode_t *ogs_socknode_new(ogs_sockaddr_t *addr);
|
||||
|
@ -50,7 +51,8 @@ void ogs_socknode_remove(ogs_list_t *list, ogs_socknode_t *node);
|
|||
void ogs_socknode_remove_all(ogs_list_t *list);
|
||||
|
||||
int ogs_socknode_probe(
|
||||
ogs_list_t *list, ogs_list_t *list6, const char *dev, uint16_t port);
|
||||
ogs_list_t *list, ogs_list_t *list6, const char *dev, uint16_t port,
|
||||
const char *bind_device);
|
||||
int ogs_socknode_fill_scope_id_in_local(ogs_sockaddr_t *sa_list);
|
||||
|
||||
void ogs_socknode_set_cleanup(
|
||||
|
|
|
@ -45,17 +45,27 @@ 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(node->bind_dev) {
|
||||
if (ogs_bind_to_device(new->fd, node->bind_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->bind_dev);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (addr == NULL) {
|
||||
|
|
|
@ -103,7 +103,9 @@ int ogs_gtp_context_parse_config(const char *local, const char *remote)
|
|||
const char *hostname[OGS_MAX_NUM_OF_HOSTNAME];
|
||||
uint16_t port = self.gtpc_port;
|
||||
const char *dev = NULL;
|
||||
const char *bind_dev = NULL;
|
||||
ogs_sockaddr_t *addr = NULL;
|
||||
ogs_socknode_t *node = NULL, *node6 = NULL;
|
||||
|
||||
if (ogs_yaml_iter_type(>pc_array) ==
|
||||
YAML_MAPPING_NODE) {
|
||||
|
@ -161,6 +163,8 @@ int ogs_gtp_context_parse_config(const char *local, const char *remote)
|
|||
if (v) port = atoi(v);
|
||||
} else if (!strcmp(gtpc_key, "dev")) {
|
||||
dev = ogs_yaml_iter_value(>pc_iter);
|
||||
} else if (!strcmp(gtpc_key, "bind_dev")) {
|
||||
bind_dev = ogs_yaml_iter_value(>pc_iter);
|
||||
} else
|
||||
ogs_warn("unknown key `%s`", gtpc_key);
|
||||
}
|
||||
|
@ -174,11 +178,17 @@ int ogs_gtp_context_parse_config(const char *local, const char *remote)
|
|||
|
||||
if (addr) {
|
||||
if (ogs_app()->parameter.no_ipv4 == 0)
|
||||
ogs_socknode_add(
|
||||
node = ogs_socknode_add(
|
||||
&self.gtpc_list, AF_INET, addr);
|
||||
if (ogs_app()->parameter.no_ipv6 == 0)
|
||||
ogs_socknode_add(
|
||||
node6 = ogs_socknode_add(
|
||||
&self.gtpc_list6, AF_INET6, addr);
|
||||
if (bind_dev) {
|
||||
if (node)
|
||||
node->bind_dev = ogs_strdup(bind_dev);
|
||||
if (node6)
|
||||
node6->bind_dev = ogs_strdup(bind_dev);
|
||||
}
|
||||
ogs_freeaddrinfo(addr);
|
||||
}
|
||||
|
||||
|
@ -188,7 +198,7 @@ int ogs_gtp_context_parse_config(const char *local, const char *remote)
|
|||
NULL : &self.gtpc_list,
|
||||
ogs_app()->parameter.no_ipv6 ?
|
||||
NULL : &self.gtpc_list6,
|
||||
dev, port);
|
||||
dev, port, bind_dev);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
}
|
||||
|
||||
|
@ -202,7 +212,7 @@ int ogs_gtp_context_parse_config(const char *local, const char *remote)
|
|||
NULL : &self.gtpc_list,
|
||||
ogs_app()->parameter.no_ipv6 ?
|
||||
NULL : &self.gtpc_list6,
|
||||
NULL, self.gtpc_port);
|
||||
NULL, self.gtpc_port, NULL);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
}
|
||||
} else if (!strcmp(local_key, "gtpu")) {
|
||||
|
@ -228,6 +238,7 @@ int ogs_gtp_context_parse_config(const char *local, const char *remote)
|
|||
const char *teid_range = NULL;
|
||||
const char *network_instance = NULL;
|
||||
const char *source_interface = NULL;
|
||||
const char *bind_dev = NULL;
|
||||
|
||||
if (ogs_yaml_iter_type(>pu_array) ==
|
||||
YAML_MAPPING_NODE) {
|
||||
|
@ -317,6 +328,8 @@ int ogs_gtp_context_parse_config(const char *local, const char *remote)
|
|||
if (v) port = atoi(v);
|
||||
} else if (!strcmp(gtpu_key, "dev")) {
|
||||
dev = ogs_yaml_iter_value(>pu_iter);
|
||||
} else if (!strcmp(gtpu_key, "bind_dev")) {
|
||||
bind_dev = ogs_yaml_iter_value(>pu_iter);
|
||||
} else if (!strcmp(gtpu_key,
|
||||
"teid_range_indication")) {
|
||||
teid_range_indication =
|
||||
|
@ -348,9 +361,15 @@ int ogs_gtp_context_parse_config(const char *local, const char *remote)
|
|||
|
||||
if (addr) {
|
||||
if (ogs_app()->parameter.no_ipv4 == 0)
|
||||
ogs_socknode_add(&list, AF_INET, addr);
|
||||
node = ogs_socknode_add(&list, AF_INET, addr);
|
||||
if (ogs_app()->parameter.no_ipv6 == 0)
|
||||
ogs_socknode_add(&list6, AF_INET6, addr);
|
||||
node6 = ogs_socknode_add(&list6, AF_INET6, addr);
|
||||
if (bind_dev) {
|
||||
if (node)
|
||||
node->bind_dev = ogs_strdup(bind_dev);
|
||||
if (node6)
|
||||
node6->bind_dev = ogs_strdup(bind_dev);
|
||||
}
|
||||
ogs_freeaddrinfo(addr);
|
||||
}
|
||||
|
||||
|
@ -358,7 +377,7 @@ int ogs_gtp_context_parse_config(const char *local, const char *remote)
|
|||
rv = ogs_socknode_probe(
|
||||
ogs_app()->parameter.no_ipv4 ? NULL : &list,
|
||||
ogs_app()->parameter.no_ipv6 ? NULL : &list6,
|
||||
dev, port);
|
||||
dev, port, bind_dev);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
}
|
||||
|
||||
|
@ -454,7 +473,7 @@ int ogs_gtp_context_parse_config(const char *local, const char *remote)
|
|||
rv = ogs_socknode_probe(
|
||||
ogs_app()->parameter.no_ipv4 ? NULL : &list,
|
||||
ogs_app()->parameter.no_ipv6 ? NULL : &list6,
|
||||
NULL, self.gtpu_port);
|
||||
NULL, self.gtpu_port, NULL);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
|
||||
/*
|
||||
|
|
|
@ -274,7 +274,7 @@ int ogs_pfcp_context_parse_config(const char *local, const char *remote)
|
|||
NULL : &self.pfcp_list,
|
||||
ogs_app()->parameter.no_ipv6 ?
|
||||
NULL : &self.pfcp_list6,
|
||||
dev, self.pfcp_port);
|
||||
dev, self.pfcp_port, NULL);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
}
|
||||
|
||||
|
@ -288,7 +288,7 @@ int ogs_pfcp_context_parse_config(const char *local, const char *remote)
|
|||
NULL : &self.pfcp_list,
|
||||
ogs_app()->parameter.no_ipv6 ?
|
||||
NULL : &self.pfcp_list6,
|
||||
NULL, self.pfcp_port);
|
||||
NULL, self.pfcp_port, NULL);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
}
|
||||
} else if (!strcmp(local_key, "subnet")) {
|
||||
|
|
|
@ -280,7 +280,7 @@ int ogs_sbi_context_parse_config(const char *local, const char *remote)
|
|||
rv = ogs_socknode_probe(
|
||||
ogs_app()->parameter.no_ipv4 ? NULL : &list,
|
||||
ogs_app()->parameter.no_ipv6 ? NULL : &list6,
|
||||
dev, port);
|
||||
dev, port, NULL);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
}
|
||||
|
||||
|
@ -334,7 +334,7 @@ int ogs_sbi_context_parse_config(const char *local, const char *remote)
|
|||
rv = ogs_socknode_probe(
|
||||
ogs_app()->parameter.no_ipv4 ? NULL : &list,
|
||||
ogs_app()->parameter.no_ipv6 ? NULL : &list6,
|
||||
NULL, self.sbi_port);
|
||||
NULL, self.sbi_port, NULL);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
|
||||
node = ogs_list_first(&list);
|
||||
|
|
|
@ -296,7 +296,7 @@ int amf_context_parse_config(void)
|
|||
NULL : &self.ngap_list,
|
||||
ogs_app()->parameter.no_ipv6 ?
|
||||
NULL : &self.ngap_list6,
|
||||
dev, port);
|
||||
dev, port, NULL);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
}
|
||||
|
||||
|
@ -310,7 +310,7 @@ int amf_context_parse_config(void)
|
|||
NULL : &self.ngap_list,
|
||||
ogs_app()->parameter.no_ipv6 ?
|
||||
NULL : &self.ngap_list6,
|
||||
NULL, self.ngap_port);
|
||||
NULL, self.ngap_port, NULL);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
}
|
||||
} else if (!strcmp(amf_key, "guami")) {
|
||||
|
|
|
@ -506,7 +506,7 @@ int mme_context_parse_config()
|
|||
NULL : &self.s1ap_list,
|
||||
ogs_app()->parameter.no_ipv6 ?
|
||||
NULL : &self.s1ap_list6,
|
||||
dev, port);
|
||||
dev, port, NULL);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
}
|
||||
|
||||
|
@ -520,7 +520,7 @@ int mme_context_parse_config()
|
|||
NULL : &self.s1ap_list,
|
||||
ogs_app()->parameter.no_ipv6 ?
|
||||
NULL : &self.s1ap_list6,
|
||||
NULL, self.s1ap_port);
|
||||
NULL, self.s1ap_port, NULL);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
}
|
||||
} else if (!strcmp(mme_key, "gtpc")) {
|
||||
|
|
|
@ -233,7 +233,7 @@ int nssf_context_parse_config(void)
|
|||
rv = ogs_socknode_probe(
|
||||
ogs_app()->parameter.no_ipv4 ? NULL : &list,
|
||||
ogs_app()->parameter.no_ipv6 ? NULL : &list6,
|
||||
dev, port);
|
||||
dev, port, NULL);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
}
|
||||
|
||||
|
|
|
@ -244,7 +244,7 @@ int test_context_parse_config(void)
|
|||
NULL : &self.ngap_list,
|
||||
ogs_app()->parameter.no_ipv6 ?
|
||||
NULL : &self.ngap_list6,
|
||||
dev, port);
|
||||
dev, port, NULL);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
}
|
||||
|
||||
|
@ -258,7 +258,7 @@ int test_context_parse_config(void)
|
|||
NULL : &self.ngap_list,
|
||||
ogs_app()->parameter.no_ipv6 ?
|
||||
NULL : &self.ngap_list6,
|
||||
NULL, self.ngap_port);
|
||||
NULL, self.ngap_port, NULL);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
}
|
||||
} if (!strcmp(amf_key, "tai")) {
|
||||
|
@ -628,7 +628,7 @@ int test_context_parse_config(void)
|
|||
NULL : &self.s1ap_list,
|
||||
ogs_app()->parameter.no_ipv6 ?
|
||||
NULL : &self.s1ap_list6,
|
||||
dev, port);
|
||||
dev, port, NULL);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
}
|
||||
|
||||
|
@ -642,7 +642,7 @@ int test_context_parse_config(void)
|
|||
NULL : &self.s1ap_list,
|
||||
ogs_app()->parameter.no_ipv6 ?
|
||||
NULL : &self.s1ap_list6,
|
||||
NULL, self.s1ap_port);
|
||||
NULL, self.s1ap_port, NULL);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
}
|
||||
} else if (!strcmp(mme_key, "tai")) {
|
||||
|
|
|
@ -396,7 +396,7 @@ static void test7_func(abts_case *tc, void *data)
|
|||
|
||||
ogs_socknode_remove_all(&list);
|
||||
|
||||
rv = ogs_socknode_probe(&list, &list6, NULL, PORT);
|
||||
rv = ogs_socknode_probe(&list, &list6, NULL, PORT, NULL);
|
||||
ABTS_INT_EQUAL(tc, OGS_OK, rv);
|
||||
|
||||
ogs_socknode_remove_all(&list);
|
||||
|
|
Loading…
Reference in New Issue