vppinfra: add abstract socket & netns fns
* Add clib_socket_init support for abstract sockets
if name starts with an '@'
* Add clib_socket_init_netns to open socket in netns
* Add clib_netns_open
Type: feature
Change-Id: I89637ad657c702ec38ddecb5c03a1673d0dfb104
Signed-off-by: Nathan Skrzypczak <nathan.skrzypczak@gmail.com>
diff --git a/src/plugins/linux-cp/lcp_interface.c b/src/plugins/linux-cp/lcp_interface.c
index 3fc9117..da40961 100644
--- a/src/plugins/linux-cp/lcp_interface.c
+++ b/src/plugins/linux-cp/lcp_interface.c
@@ -14,7 +14,6 @@
*/
#define _GNU_SOURCE
-#include <sched.h>
#include <fcntl.h>
#include <ctype.h>
#include <sys/socket.h>
@@ -26,6 +25,8 @@
#include <vnet/plugin/plugin.h>
#include <vnet/plugin/plugin.h>
+#include <vppinfra/linux/netns.h>
+
#include <vnet/ip/ip_punt_drop.h>
#include <vnet/fib/fib_table.h>
#include <vnet/adj/adj_mcast.h>
@@ -614,17 +615,6 @@
return 1;
}
-static int
-lcp_itf_get_ns_fd (char *ns_name)
-{
- char ns_path[256] = "/proc/self/ns/net";
-
- if (ns_name)
- snprintf (ns_path, sizeof (ns_path) - 1, "/var/run/netns/%s", ns_name);
-
- return open (ns_path, O_RDONLY);
-}
-
static void
lcp_itf_set_vif_link_state (u32 vif_index, u8 up, u8 *ns)
{
@@ -634,13 +624,10 @@
if (ns)
{
- u8 *ns_path = 0;
-
- curr_ns_fd = open ("/proc/self/ns/net", O_RDONLY);
- ns_path = format (0, "/var/run/netns/%s%c", (char *) ns, 0);
- vif_ns_fd = open ((char *) ns_path, O_RDONLY);
+ curr_ns_fd = clib_netns_open (NULL /* self */);
+ vif_ns_fd = clib_netns_open (ns);
if (vif_ns_fd != -1)
- setns (vif_ns_fd, CLONE_NEWNET);
+ clib_setns (vif_ns_fd);
}
vnet_netlink_set_link_state (vif_index, up);
@@ -650,7 +637,7 @@
if (curr_ns_fd != -1)
{
- setns (curr_ns_fd, CLONE_NEWNET);
+ clib_setns (curr_ns_fd);
close (curr_ns_fd);
}
}
@@ -706,12 +693,12 @@
if (ns && ns[0] != 0)
{
- orig_ns_fd = lcp_itf_get_ns_fd (NULL);
- ns_fd = lcp_itf_get_ns_fd ((char *) ns);
+ orig_ns_fd = clib_netns_open (NULL /* self */);
+ ns_fd = clib_netns_open (ns);
if (orig_ns_fd == -1 || ns_fd == -1)
goto socket_close;
- setns (ns_fd, CLONE_NEWNET);
+ clib_setns (ns_fd);
}
vif_index = if_nametoindex ((const char *) host_if_name);
@@ -745,7 +732,7 @@
socket_close:
if (orig_ns_fd != -1)
{
- setns (orig_ns_fd, CLONE_NEWNET);
+ clib_setns (orig_ns_fd);
close (orig_ns_fd);
}
if (ns_fd != -1)
diff --git a/src/vnet/devices/tap/tap.c b/src/vnet/devices/tap/tap.c
index dfd3258..33d6e3b 100644
--- a/src/vnet/devices/tap/tap.c
+++ b/src/vnet/devices/tap/tap.c
@@ -27,7 +27,6 @@
#include <linux/sockios.h>
#include <sys/eventfd.h>
#include <net/if_arp.h>
-#include <sched.h>
#include <limits.h>
#include <linux/netlink.h>
@@ -36,6 +35,7 @@
#include <vlib/vlib.h>
#include <vlib/physmem.h>
#include <vlib/unix/unix.h>
+#include <vppinfra/linux/netns.h>
#include <vnet/ethernet/ethernet.h>
#include <vnet/ip/ip4_packet.h>
#include <vnet/ip/ip6_packet.h>
@@ -79,24 +79,6 @@
return 0;
}
-static int
-open_netns_fd (char *netns)
-{
- u8 *s = 0;
- int fd;
-
- 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;
-}
-
#define TAP_MAX_INSTANCE 1024
static void
@@ -227,15 +209,15 @@
}
if (args->host_namespace)
{
- old_netns_fd = open ("/proc/self/ns/net", O_RDONLY);
- if ((nfd = open_netns_fd ((char *) args->host_namespace)) == -1)
+ old_netns_fd = clib_netns_open (NULL /* self */);
+ if ((nfd = clib_netns_open (args->host_namespace)) == -1)
{
args->rv = VNET_API_ERROR_SYSCALL_ERROR_2;
- args->error = clib_error_return_unix (0, "open_netns_fd '%s'",
+ args->error = clib_error_return_unix (0, "clib_netns_open '%s'",
args->host_namespace);
goto error;
}
- if (setns (nfd, CLONE_NEWNET) == -1)
+ if (clib_setns (nfd) == -1)
{
args->rv = VNET_API_ERROR_SYSCALL_ERROR_3;
args->error = clib_error_return_unix (0, "setns '%s'",
@@ -423,11 +405,11 @@
after we change our net namespace */
if (args->host_namespace)
{
- old_netns_fd = open ("/proc/self/ns/net", O_RDONLY);
- if ((nfd = open_netns_fd ((char *) args->host_namespace)) == -1)
+ old_netns_fd = clib_netns_open (NULL /* self */);
+ if ((nfd = clib_netns_open (args->host_namespace)) == -1)
{
args->rv = VNET_API_ERROR_SYSCALL_ERROR_2;
- args->error = clib_error_return_unix (0, "open_netns_fd '%s'",
+ args->error = clib_error_return_unix (0, "clib_netns_open '%s'",
args->host_namespace);
goto error;
}
@@ -438,7 +420,7 @@
args->rv = VNET_API_ERROR_NETLINK_ERROR;
goto error;
}
- if (setns (nfd, CLONE_NEWNET) == -1)
+ if (clib_setns (nfd) == -1)
{
args->rv = VNET_API_ERROR_SYSCALL_ERROR_3;
args->error = clib_error_return_unix (0, "setns '%s'",
@@ -567,7 +549,7 @@
/* switch back to old net namespace */
if (args->host_namespace)
{
- if (setns (old_netns_fd, CLONE_NEWNET) == -1)
+ if (clib_setns (old_netns_fd) == -1)
{
args->rv = VNET_API_ERROR_SYSCALL_ERROR_2;
args->error = clib_error_return_unix (0, "setns '%s'",
@@ -1065,13 +1047,13 @@
if (vif->net_ns)
{
- old_netns_fd = open ("/proc/self/ns/net", O_RDONLY);
- if ((nfd = open_netns_fd ((char *) vif->net_ns)) == -1)
+ old_netns_fd = clib_netns_open (NULL /* self */);
+ if ((nfd = clib_netns_open (vif->net_ns)) == -1)
{
clib_warning ("Cannot open netns");
goto done;
}
- if (setns (nfd, CLONE_NEWNET) == -1)
+ if (clib_setns (nfd) == -1)
{
clib_warning ("Cannot set ns");
goto done;
@@ -1109,7 +1091,7 @@
done:
if (old_netns_fd != -1)
{
- if (setns (old_netns_fd, CLONE_NEWNET) == -1)
+ if (clib_setns (old_netns_fd) == -1)
{
clib_warning ("Cannot set old ns");
}
diff --git a/src/vppinfra/CMakeLists.txt b/src/vppinfra/CMakeLists.txt
index 728072c..c682d70 100644
--- a/src/vppinfra/CMakeLists.txt
+++ b/src/vppinfra/CMakeLists.txt
@@ -204,6 +204,7 @@
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 0000000..2bd62bd
--- /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 0000000..5a09460
--- /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 d842785..26427d9 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 @@
*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 @@
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 @@
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 @@
}
__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 78a56fe..fa5ef1e 100644
--- a/src/vppinfra/socket.h
+++ b/src/vppinfra/socket.h
@@ -93,6 +93,8 @@
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);