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>
This commit is contained in:
Nathan Skrzypczak
2021-07-19 18:21:43 +02:00
committed by Florin Coras
parent 2cf583e3d6
commit 4cef6de591
7 changed files with 164 additions and 58 deletions
+10 -23
View 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)
+14 -32
View 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");
}
+1
View File
@@ -204,6 +204,7 @@ if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
elf_clib.c
linux/mem.c
linux/sysfs.c
linux/netns.c
)
endif()
+55
View File
@@ -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:
*/
+32
View File
@@ -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:
*/
+50 -3
View 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)
{
+2
View 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);