diff options
Diffstat (limited to 'src/vppinfra')
-rw-r--r-- | src/vppinfra/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/vppinfra/linux/netns.c | 55 | ||||
-rw-r--r-- | src/vppinfra/linux/netns.h | 32 | ||||
-rw-r--r-- | src/vppinfra/socket.c | 53 | ||||
-rw-r--r-- | src/vppinfra/socket.h | 2 |
5 files changed, 140 insertions, 3 deletions
diff --git a/src/vppinfra/CMakeLists.txt b/src/vppinfra/CMakeLists.txt index 728072cec3b..c682d70f6f1 100644 --- a/src/vppinfra/CMakeLists.txt +++ b/src/vppinfra/CMakeLists.txt @@ -204,6 +204,7 @@ if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") elf_clib.c linux/mem.c linux/sysfs.c + linux/netns.c ) endif() diff --git a/src/vppinfra/linux/netns.c b/src/vppinfra/linux/netns.c new file mode 100644 index 00000000000..2bd62bd7d92 --- /dev/null +++ b/src/vppinfra/linux/netns.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2021 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _GNU_SOURCE +#include <fcntl.h> +#include <sched.h> + +#include <vppinfra/format.h> + +__clib_export int +clib_netns_open (u8 *netns_u8) +{ + char *netns = (char *) netns_u8; + u8 *s = 0; + int fd; + + if ((NULL) == netns) + s = format (0, "/proc/self/ns/net"); + else if (strncmp (netns, "pid:", 4) == 0) + s = format (0, "/proc/%u/ns/net%c", atoi (netns + 4), 0); + else if (netns[0] == '/') + s = format (0, "%s%c", netns, 0); + else + s = format (0, "/var/run/netns/%s%c", netns, 0); + + fd = open ((char *) s, O_RDONLY); + vec_free (s); + return fd; +} + +__clib_export int +clib_setns (int nfd) +{ + return setns (nfd, CLONE_NEWNET); +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vppinfra/linux/netns.h b/src/vppinfra/linux/netns.h new file mode 100644 index 00000000000..5a094607953 --- /dev/null +++ b/src/vppinfra/linux/netns.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2021 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef included_vppinfra_netns_h +#define included_vppinfra_netns_h + +#include <vppinfra/clib.h> + +int clib_netns_open (u8 *netns); +int clib_setns (int nfd); + +#endif /* included_vppinfra_netns_h */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vppinfra/socket.c b/src/vppinfra/socket.c index d8427852400..26427d98fa1 100644 --- a/src/vppinfra/socket.c +++ b/src/vppinfra/socket.c @@ -52,6 +52,7 @@ #include <vppinfra/mem.h> #include <vppinfra/vec.h> #include <vppinfra/socket.h> +#include <vppinfra/linux/netns.h> #include <vppinfra/format.h> #include <vppinfra/error.h> @@ -113,6 +114,18 @@ socket_config (char *config, *addr_len = sizeof (su[0]); } + /* Treat everything that starts with @ as an abstract socket. */ + else if (config[0] == '@') + { + struct sockaddr_un *su = addr; + su->sun_family = PF_LOCAL; + clib_memcpy (&su->sun_path, config, + clib_min (sizeof (su->sun_path), 1 + strlen (config))); + + *addr_len = sizeof (su->sun_family) + strlen (config); + su->sun_path[0] = '\0'; + } + /* Hostname or hostname:port or port. */ else { @@ -440,7 +453,8 @@ clib_socket_init (clib_socket_t * s) need_bind = 0; } } - if (addr.sa.sa_family == PF_LOCAL) + if (addr.sa.sa_family == PF_LOCAL && + ((struct sockaddr_un *) &addr)->sun_path[0] != 0) unlink (((struct sockaddr_un *) &addr)->sun_path); /* Make address available for multiple users. */ @@ -477,8 +491,9 @@ clib_socket_init (clib_socket_t * s) s->fd, s->config); goto done; } - if (addr.sa.sa_family == PF_LOCAL - && s->flags & CLIB_SOCKET_F_ALLOW_GROUP_WRITE) + if (addr.sa.sa_family == PF_LOCAL && + s->flags & CLIB_SOCKET_F_ALLOW_GROUP_WRITE && + ((struct sockaddr_un *) &addr)->sun_path[0] != 0) { struct stat st = { 0 }; if (stat (((struct sockaddr_un *) &addr)->sun_path, &st) < 0) @@ -539,6 +554,38 @@ done: } __clib_export clib_error_t * +clib_socket_init_netns (clib_socket_t *s, u8 *namespace) +{ + if (namespace == NULL || namespace[0] == 0) + return clib_socket_init (s); + + clib_error_t *error; + int old_netns_fd, nfd; + + old_netns_fd = clib_netns_open (NULL /* self */); + if ((nfd = clib_netns_open (namespace)) == -1) + { + error = clib_error_return_unix (0, "clib_netns_open '%s'", namespace); + goto done; + } + + if (clib_setns (nfd) == -1) + { + error = clib_error_return_unix (0, "setns '%s'", namespace); + goto done; + } + + error = clib_socket_init (s); + +done: + if (clib_setns (old_netns_fd) == -1) + clib_warning ("Cannot set old ns"); + close (old_netns_fd); + + return error; +} + +__clib_export clib_error_t * clib_socket_accept (clib_socket_t * server, clib_socket_t * client) { clib_error_t *err = 0; diff --git a/src/vppinfra/socket.h b/src/vppinfra/socket.h index 78a56fee53e..fa5ef1efced 100644 --- a/src/vppinfra/socket.h +++ b/src/vppinfra/socket.h @@ -93,6 +93,8 @@ typedef struct _socket_t from IPPORT_USERRESERVED (5000). */ clib_error_t *clib_socket_init (clib_socket_t * socket); +clib_error_t *clib_socket_init_netns (clib_socket_t *socket, u8 *namespace); + clib_error_t *clib_socket_accept (clib_socket_t * server, clib_socket_t * client); |