From c253dcb5d80aa60112bb31ab95ae9839081064d3 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Thu, 3 Sep 2015 10:47:43 +0200 Subject: [PATCH] vrf: add a runtime check before playing with netns This patch adds a runtime check to determine if netns are available. Some systems like OpenWRT have the system call setns() but don't have the kernel option CONFIG_NET_NS enabled. Reported-by: Christian Franke Signed-off-by: Nicolas Dichtel Tested-by: Christian Franke (cherry picked from commit 04a3aabf58d95d01c4c8168eeff43cf9d9892eee) --- lib/ns.c | 94 +++++++++++++++++++++++++++----------------- vtysh/vtysh_config.c | 2 +- 2 files changed, 58 insertions(+), 38 deletions(-) diff --git a/lib/ns.c b/lib/ns.c index 6fb124181b..4765a18ef2 100644 --- a/lib/ns.c +++ b/lib/ns.c @@ -39,7 +39,6 @@ #include "command.h" #include "vty.h" -#ifdef HAVE_NETNS #ifndef CLONE_NEWNET #define CLONE_NEWNET 0x40000000 /* New network namespace (lo, device, names sockets, etc) */ @@ -57,7 +56,10 @@ static inline int setns(int fd, int nstype) } #endif /* HAVE_SETNS */ +#ifdef HAVE_NETNS + #define NS_DEFAULT_NAME "/proc/self/ns/net" +static int have_netns_enabled = -1; #else /* !HAVE_NETNS */ @@ -65,6 +67,27 @@ static inline int setns(int fd, int nstype) #endif /* HAVE_NETNS */ +static int have_netns(void) +{ +#ifdef HAVE_NETNS + if (have_netns_enabled < 0) + { + int fd = open (NS_DEFAULT_NAME, O_RDONLY); + + if (fd < 0) + have_netns_enabled = 0; + else + { + have_netns_enabled = 1; + close(fd); + } + } + return have_netns_enabled; +#else + return 0; +#endif +} + struct ns { /* Identifier, same as the vector index */ @@ -194,11 +217,10 @@ ns_lookup (ns_id_t ns_id) static int ns_is_enabled (struct ns *ns) { -#ifdef HAVE_NETNS - return ns && ns->fd >= 0; -#else - return ns && ns->fd == -2 && ns->ns_id == NS_DEFAULT; -#endif + if (have_netns()) + return ns && ns->fd >= 0; + else + return ns && ns->fd == -2 && ns->ns_id == NS_DEFAULT; } /* @@ -214,12 +236,12 @@ ns_enable (struct ns *ns) if (!ns_is_enabled (ns)) { -#ifdef HAVE_NETNS - ns->fd = open (ns->name, O_RDONLY); -#else - ns->fd = -2; /* Remember that ns_enable_hook has been called */ - errno = -ENOTSUP; -#endif + if (have_netns()) { + ns->fd = open (ns->name, O_RDONLY); + } else { + ns->fd = -2; /* Remember that ns_enable_hook has been called */ + errno = -ENOTSUP; + } if (!ns_is_enabled (ns)) { @@ -228,10 +250,9 @@ ns_enable (struct ns *ns) return 0; } -#ifdef HAVE_NETNS - zlog_info ("NS %u is associated with NETNS %s.", - ns->ns_id, ns->name); -#endif + if (have_netns()) + zlog_info ("NS %u is associated with NETNS %s.", + ns->ns_id, ns->name); zlog_info ("NS %u is enabled.", ns->ns_id); if (ns_master.ns_enable_hook) @@ -256,9 +277,9 @@ ns_disable (struct ns *ns) if (ns_master.ns_disable_hook) (*ns_master.ns_disable_hook) (ns->ns_id, &ns->info); -#ifdef HAVE_NETNS - close (ns->fd); -#endif + if (have_netns()) + close (ns->fd); + ns->fd = -1; } } @@ -497,7 +518,6 @@ ns_bitmap_check (ns_bitmap_t bmap, ns_id_t ns_id) NS_BITMAP_FLAG (offset)) ? 1 : 0; } -#ifdef HAVE_NETNS /* * NS realization with NETNS */ @@ -633,8 +653,6 @@ ns_config_write (struct vty *vty) return write; } -#endif /* HAVE_NETNS */ - /* Initialize NS module. */ void ns_init (void) @@ -662,12 +680,13 @@ ns_init (void) exit (1); } -#ifdef HAVE_NETNS - /* Install NS commands. */ - install_node (&ns_node, ns_config_write); - install_element (CONFIG_NODE, &ns_netns_cmd); - install_element (CONFIG_NODE, &no_ns_netns_cmd); -#endif + if (have_netns()) + { + /* Install NS commands. */ + install_node (&ns_node, ns_config_write); + install_element (CONFIG_NODE, &ns_netns_cmd); + install_element (CONFIG_NODE, &no_ns_netns_cmd); + } } /* Terminate NS module. */ @@ -698,17 +717,18 @@ ns_socket (int domain, int type, int protocol, ns_id_t ns_id) return -1; } -#ifdef HAVE_NETNS - ret = (ns_id != NS_DEFAULT) ? setns (ns->fd, CLONE_NEWNET) : 0; - if (ret >= 0) + if (have_netns()) { - ret = socket (domain, type, protocol); - if (ns_id != NS_DEFAULT) - setns (ns_lookup (NS_DEFAULT)->fd, CLONE_NEWNET); + ret = (ns_id != NS_DEFAULT) ? setns (ns->fd, CLONE_NEWNET) : 0; + if (ret >= 0) + { + ret = socket (domain, type, protocol); + if (ns_id != NS_DEFAULT) + setns (ns_lookup (NS_DEFAULT)->fd, CLONE_NEWNET); + } } -#else - ret = socket (domain, type, protocol); -#endif + else + ret = socket (domain, type, protocol); return ret; } diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index 4a1b323686..118b7ba035 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -184,7 +184,7 @@ vtysh_config_parse_line (const char *line) default: if (strncmp (line, "interface", strlen ("interface")) == 0) config = config_get (INTERFACE_NODE, line); - else if (strncmp (line, "ns", strlen ("ns")) == 0) + else if (strncmp (line, "logical-router", strlen ("ns")) == 0) config = config_get (NS_NODE, line); else if (strncmp (line, "vrf", strlen ("vrf")) == 0) config = config_get (VRF_NODE, line); -- 2.39.5