From 46f5c07643e6cbf920a44bebe9ac9d3435a5a7b6 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 8 Mar 2016 13:08:21 +0100 Subject: [PATCH] platform: add nmp_netns_bind_to_path() helper function Based-on-patch-by: Stjepan Gros --- src/platform/nmp-netns.c | 80 ++++++++++++++++++++++++++++++++++ src/platform/nmp-netns.h | 3 ++ src/platform/tests/test-link.c | 57 ++++++++++++++++++++++++ 3 files changed, 140 insertions(+) diff --git a/src/platform/nmp-netns.c b/src/platform/nmp-netns.c index 5b1d6ad7e..26295855d 100644 --- a/src/platform/nmp-netns.c +++ b/src/platform/nmp-netns.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include "NetworkManagerUtils.h" @@ -579,6 +581,84 @@ nmp_netns_is_initial (void) /*********************************************************************************************/ +gboolean +nmp_netns_bind_to_path (NMPNetns *self, const char *filename, int *out_fd) +{ + gs_free char *dirname = NULL; + int errsv; + int fd; + nm_auto_pop_netns NMPNetns *netns_pop = NULL; + + g_return_val_if_fail (NMP_IS_NETNS (self), FALSE); + g_return_val_if_fail (filename && filename[0] == '/', FALSE); + + if (!nmp_netns_push_type (self, CLONE_NEWNET)) + return FALSE; + netns_pop = self; + + dirname = g_path_get_dirname (filename); + if (mkdir (dirname, 0) != 0) { + errsv = errno; + if (errsv != EEXIST) { + _LOGE (self, "bind: failed to create directory %s: %s", + dirname, g_strerror (errsv)); + return FALSE; + } + } + + if ((fd = creat (filename, S_IRUSR | S_IRGRP | S_IROTH)) == -1) { + errsv = errno; + _LOGE (self, "bind: failed to create %s: %s", + filename, g_strerror (errsv)); + return FALSE; + } + close (fd); + + if (mount (PROC_SELF_NS_NET, filename, "none", MS_BIND, NULL) != 0) { + errsv = errno; + _LOGE (self, "bind: failed to mount %s to %s: %s", + PROC_SELF_NS_NET, filename, g_strerror (errsv)); + unlink (filename); + return FALSE; + } + + if (out_fd) { + if ((fd = open (filename, O_RDONLY)) == -1) { + errsv = errno; + _LOGE (self, "bind: failed to open %s: %s", filename, g_strerror (errsv)); + umount2 (filename, MNT_DETACH); + unlink (filename); + return FALSE; + } + *out_fd = fd; + } + + return TRUE; +} + +gboolean +nmp_netns_bind_to_path_destroy (NMPNetns *self, const char *filename) +{ + int errsv; + + g_return_val_if_fail (NMP_IS_NETNS (self), FALSE); + g_return_val_if_fail (filename && filename[0] == '/', FALSE); + + if (umount2 (filename, MNT_DETACH) != 0) { + errsv = errno; + _LOGE (self, "bind: failed to unmount2 %s: %s", filename, g_strerror (errsv)); + return FALSE; + } + if (unlink (filename) != 0) { + errsv = errno; + _LOGE (self, "bind: failed to unlink %s: %s", filename, g_strerror (errsv)); + return FALSE; + } + return TRUE; +} + +/******************************************************************************/ + static void set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) diff --git a/src/platform/nmp-netns.h b/src/platform/nmp-netns.h index 1625116f2..4eac07acf 100644 --- a/src/platform/nmp-netns.h +++ b/src/platform/nmp-netns.h @@ -68,4 +68,7 @@ _nm_auto_pop_netns (NMPNetns **p) #define nm_auto_pop_netns __attribute__((cleanup(_nm_auto_pop_netns))) +gboolean nmp_netns_bind_to_path (NMPNetns *self, const char *filename, int *out_fd); +gboolean nmp_netns_bind_to_path_destroy (NMPNetns *self, const char *filename); + #endif /* __NMP_NETNS_UTILS_H__ */ diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c index f7b9f6fb6..69627c405 100644 --- a/src/platform/tests/test-link.c +++ b/src/platform/tests/test-link.c @@ -21,6 +21,9 @@ #include "nm-default.h" #include +#include +#include +#include #include "nmp-object.h" #include "nmp-netns.h" @@ -2236,6 +2239,59 @@ test_netns_push (gpointer fixture, gconstpointer test_data) /*****************************************************************************/ +static void +test_netns_bind_to_path (gpointer fixture, gconstpointer test_data) +{ +#define P_VAR_RUN "/var/run" +#define P_VAR_RUN_NETNS "/var/run/netns" +#define P_VAR_RUN_NETNS_BINDNAME "/var/run/netns/"P_NETNS_BINDNAME +#define P_NETNS_BINDNAME "nmtst-iproute2-netns" + gs_unref_object NMPlatform *platform_0 = NULL; + gs_unref_object NMPlatform *platform_1 = NULL; + gs_unref_object NMPlatform *platform_2 = NULL; + nm_auto_pop_netns NMPNetns *netns_pop = NULL; + NMPlatform *platforms[3]; + NMPNetns *netns; + int i; + + if (_test_netns_check_skip ()) + return; + + g_assert_cmpint (mount ("tmpfs", P_VAR_RUN, "tmpfs", MS_NOATIME | MS_NODEV | MS_NOSUID, "mode=0755,size=32K"), ==, 0); + g_assert_cmpint (mkdir (P_VAR_RUN_NETNS, 755), ==, 0); + + platforms[0] = platform_0 = g_object_new (NM_TYPE_LINUX_PLATFORM, NM_PLATFORM_NETNS_SUPPORT, TRUE, NULL); + platforms[1] = platform_1 = _test_netns_create_platform (); + platforms[2] = platform_2 = _test_netns_create_platform (); + + i = nmtst_get_rand_int () % 4; + if (i != 3) + g_assert (nm_platform_netns_push (platforms[i], &netns_pop)); + + i = (nmtst_get_rand_int () % 2) + 1; + netns = nm_platform_netns_get (platforms[i]); + + _ADD_DUMMY (platforms[i], "dummy2b"); + + g_assert (!g_file_test (P_VAR_RUN_NETNS_BINDNAME, G_FILE_TEST_EXISTS)); + g_assert_cmpint (nmtstp_run_command ("ip netns exec "P_NETNS_BINDNAME" true 2>/dev/null"), !=, 0); + + g_assert (nmp_netns_bind_to_path (netns, P_VAR_RUN_NETNS_BINDNAME, NULL)); + + g_assert (g_file_test (P_VAR_RUN_NETNS_BINDNAME, G_FILE_TEST_EXISTS)); + g_assert_cmpint (nmtstp_run_command ("ip netns exec "P_NETNS_BINDNAME" true"), ==, 0); + g_assert_cmpint (nmtstp_run_command ("ip netns exec "P_NETNS_BINDNAME" ip link show dummy2b 1>/dev/null"), ==, 0); + + g_assert (nmp_netns_bind_to_path_destroy (netns, P_VAR_RUN_NETNS_BINDNAME)); + + g_assert (!g_file_test (P_VAR_RUN_NETNS_BINDNAME, G_FILE_TEST_EXISTS)); + g_assert_cmpint (nmtstp_run_command ("ip netns exec "P_NETNS_BINDNAME" true 2>/dev/null"), !=, 0); + + g_assert_cmpint (umount (P_VAR_RUN), ==, 0); +} + +/*****************************************************************************/ + void init_tests (int *argc, char ***argv) { @@ -2286,5 +2342,6 @@ setup_tests (void) g_test_add_vtable ("/general/netns/general", 0, NULL, _test_netns_setup, test_netns_general, _test_netns_teardown); g_test_add_vtable ("/general/netns/set-netns", 0, NULL, _test_netns_setup, test_netns_set_netns, _test_netns_teardown); g_test_add_vtable ("/general/netns/push", 0, NULL, _test_netns_setup, test_netns_push, _test_netns_teardown); + g_test_add_vtable ("/general/netns/bind-to-path", 0, NULL, _test_netns_setup, test_netns_bind_to_path, _test_netns_teardown); } } -- 2.17.1