vppinfra: add abstract socket & netns fns 77/33177/3
authorNathan Skrzypczak <nathan.skrzypczak@gmail.com>
Mon, 19 Jul 2021 16:21:43 +0000 (18:21 +0200)
committerFlorin Coras <florin.coras@gmail.com>
Thu, 22 Jul 2021 15:22:22 +0000 (15:22 +0000)
* 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>
src/plugins/linux-cp/lcp_interface.c
src/vnet/devices/tap/tap.c
src/vppinfra/CMakeLists.txt
src/vppinfra/linux/netns.c [new file with mode: 0644]
src/vppinfra/linux/netns.h [new file with mode: 0644]
src/vppinfra/socket.c
src/vppinfra/socket.h

index 3fc9117..da40961 100644 (file)
@@ -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 @@ lcp_validate_if_name (u8 *name)
   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 @@ lcp_itf_set_vif_link_state (u32 vif_index, u8 up, u8 *ns)
 
   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 @@ lcp_itf_set_vif_link_state (u32 vif_index, u8 up, u8 *ns)
 
   if (curr_ns_fd != -1)
     {
-      setns (curr_ns_fd, CLONE_NEWNET);
+      clib_setns (curr_ns_fd);
       close (curr_ns_fd);
     }
 }
@@ -706,12 +693,12 @@ lcp_itf_pair_create (u32 phy_sw_if_index, u8 *host_if_name,
 
       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 @@ lcp_itf_pair_create (u32 phy_sw_if_index, u8 *host_if_name,
     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)
index dfd3258..33d6e3b 100644 (file)
@@ -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 @@ virtio_eth_flag_change (vnet_main_t * vnm, vnet_hw_interface_t * hi,
   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 @@ tap_create_if (vlib_main_t * vm, tap_create_if_args_t * args)
        }
       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 @@ tap_create_if (vlib_main_t * vm, tap_create_if_args_t * args)
          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 @@ tap_create_if (vlib_main_t * vm, tap_create_if_args_t * args)
              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 @@ tap_create_if (vlib_main_t * vm, tap_create_if_args_t * args)
   /* 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 @@ tap_set_speed (u32 hw_if_index, u32 speed)
 
   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 @@ tap_set_speed (u32 hw_if_index, u32 speed)
 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");
        }
index 728072c..c682d70 100644 (file)
@@ -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 (file)
index 0000000..2bd62bd
--- /dev/null
@@ -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 (file)
index 0000000..5a09460
--- /dev/null
@@ -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:
+ */
index d842785..26427d9 100644 (file)
@@ -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)
@@ -538,6 +553,38 @@ done:
   return error;
 }
 
+__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)
 {
index 78a56fe..fa5ef1e 100644 (file)
@@ -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);