]> git.proxmox.com Git - mirror_frr.git/commitdiff
zebra: collect and get netnamespaces information
authorPhilippe Guibert <philippe.guibert@6wind.com>
Wed, 13 Dec 2017 10:04:31 +0000 (11:04 +0100)
committerPhilippe Guibert <philippe.guibert@6wind.com>
Tue, 27 Feb 2018 10:11:24 +0000 (11:11 +0100)
upon zebra initialisation, and upon further netnamespace creation, the
the netnamespaces are created and a vrf associated to the netnamespace
is created. By convention, the name of the netns will be the same as the
VRF.
Add a stub routine that returns a fake ns identifier, in case netlink (
linux machines) is not available.
Also, upon each newly discovered NETNS, a NSID id being generated,
either by relying on kernel NSID feature, or by generating locally the
NSID ( see previous commit for more information).

Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
zebra/main.c
zebra/subdir.am
zebra/zebra_netns_notify.c [new file with mode: 0644]
zebra/zebra_netns_notify.h [new file with mode: 0644]
zebra/zebra_ns.c

index 73e5f1290d9bfcc49415b778fc4d74e56ee08323..335329081617a52550a463804270d6631dc63cc0 100644 (file)
@@ -47,6 +47,7 @@
 #include "zebra/redistribute.h"
 #include "zebra/zebra_mpls.h"
 #include "zebra/label_manager.h"
+#include "zebra/zebra_netns_notify.h"
 
 #define ZEBRA_PTM_SUPPORT
 
@@ -140,6 +141,7 @@ static void sigint(void)
        vrf_terminate();
 
        ns_walk_func(zebra_ns_disabled);
+       zebra_ns_notify_close();
 
        access_list_reset();
        prefix_list_reset();
index fcfb0cc2036985dfbbc521909004c870ef5b108b..bb7439c0f617625168abc430d8006ef32d23d668 100644 (file)
@@ -66,6 +66,7 @@ zebra_zebra_SOURCES = \
        zebra/zebra_vxlan.c \
        zebra/zserv.c \
        zebra/zebra_netns_id.c \
+       zebra/zebra_netns_notify.c \
        # end
 
 zebra/zebra_vty_clippy.c: $(CLIPPY_DEPS)
@@ -106,6 +107,7 @@ noinst_HEADERS += \
        zebra/zebra_vxlan_private.h \
        zebra/zserv.h \
        zebra/zebra_netns_id.h \
+       zebra/zebra_netns_notify.h \
        # end
 
 zebra_zebra_irdp_la_SOURCES = \
diff --git a/zebra/zebra_netns_notify.c b/zebra/zebra_netns_notify.c
new file mode 100644 (file)
index 0000000..8940546
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * Zebra NS collector and notifier for Network NameSpaces
+ * Copyright (C) 2017 6WIND
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+
+#ifdef HAVE_NETLINK
+#ifdef HAVE_NETNS
+#undef _GNU_SOURCE
+#define _GNU_SOURCE
+
+#include <sched.h>
+#endif
+#include <dirent.h>
+#include <sys/inotify.h>
+#include <sys/stat.h>
+
+#include "thread.h"
+#include "ns.h"
+#include "command.h"
+#include "memory.h"
+
+#include "zserv.h"
+#include "zebra_memory.h"
+#endif /* defined(HAVE_NETLINK) */
+
+#include "zebra_netns_notify.h"
+#include "zebra_netns_id.h"
+
+#ifdef HAVE_NETLINK
+
+/* upon creation of folder under /var/run/netns,
+ * wait that netns context is bound to
+ * that folder 10 seconds
+ */
+#define ZEBRA_NS_POLLING_INTERVAL_MSEC     1000
+#define ZEBRA_NS_POLLING_MAX_RETRIES  200
+
+DEFINE_MTYPE_STATIC(ZEBRA, NETNS_MISC, "ZebraNetNSInfo")
+static struct thread *zebra_netns_notify_current;
+
+struct zebra_netns_info {
+       const char *netnspath;
+       unsigned int retries;
+};
+
+static int zebra_ns_ready_read(struct thread *t);
+static void zebra_ns_notify_create_context_from_entry_name(const char *name);
+static int zebra_ns_continue_read(struct zebra_netns_info *zns_info,
+                                 int stop_retry);
+static int zebra_ns_notify_read(struct thread *t);
+
+static void zebra_ns_notify_create_context_from_entry_name(const char *name)
+{
+       char *netnspath = ns_netns_pathname(NULL, name);
+       struct vrf *vrf;
+       int ret;
+       ns_id_t ns_id;
+
+       if (netnspath == NULL)
+               return;
+
+       if (vrf_handler_create(NULL, name, &vrf) != CMD_SUCCESS) {
+               zlog_warn("NS notify : failed to create VRF %s", name);
+               return;
+       }
+       if (zserv_privs.change(ZPRIVS_RAISE))
+               zlog_err("Can't raise privileges");
+       ns_id = zebra_ns_id_get(netnspath);
+       if (zserv_privs.change(ZPRIVS_LOWER))
+               zlog_err("Can't lower privileges");
+       ret = ns_handler_create(NULL, vrf, netnspath, ns_id);
+       if (ret != CMD_SUCCESS) {
+               zlog_warn("NS notify : failed to create NS %s", netnspath);
+               return;
+       }
+       zlog_info("NS notify : created VRF %s NS %s",
+                  name, netnspath);
+}
+
+static int zebra_ns_continue_read(struct zebra_netns_info *zns_info,
+                                 int stop_retry)
+{
+       void *ns_path_ptr = (void *)zns_info->netnspath;
+
+       if (stop_retry) {
+               XFREE(MTYPE_NETNS_MISC, ns_path_ptr);
+               XFREE(MTYPE_NETNS_MISC, zns_info);
+               return 0;
+       }
+       thread_add_timer_msec(zebrad.master, zebra_ns_ready_read,
+                             (void *)zns_info,
+                             ZEBRA_NS_POLLING_INTERVAL_MSEC, NULL);
+       return 0;
+}
+
+static int zebra_ns_ready_read(struct thread *t)
+{
+       struct zebra_netns_info *zns_info = THREAD_ARG(t);
+       const char *netnspath;
+       int err, stop_retry = 0;
+
+       if (!zns_info)
+               return 0;
+       if (!zns_info->netnspath) {
+               XFREE(MTYPE_NETNS_MISC, zns_info);
+               return 0;
+       }
+       netnspath = zns_info->netnspath;
+       if (--zns_info->retries == 0)
+               stop_retry = 1;
+       if (zserv_privs.change(ZPRIVS_RAISE))
+               zlog_err("Can't raise privileges");
+       err = ns_switch_to_netns(netnspath);
+       if (zserv_privs.change(ZPRIVS_LOWER))
+               zlog_err("Can't lower privileges");
+       if (err < 0)
+               return zebra_ns_continue_read(zns_info, stop_retry);
+
+       /* go back to default ns */
+       if (zserv_privs.change(ZPRIVS_RAISE))
+               zlog_err("Can't raise privileges");
+       err = ns_switchback_to_initial();
+       if (zserv_privs.change(ZPRIVS_LOWER))
+               zlog_err("Can't lower privileges");
+       if (err < 0)
+               return zebra_ns_continue_read(zns_info, stop_retry);
+
+       /* success : close fd and create zns context */
+       zebra_ns_notify_create_context_from_entry_name(basename(netnspath));
+       return zebra_ns_continue_read(zns_info, 1);
+}
+
+static int zebra_ns_notify_read(struct thread *t)
+{
+       int fd_monitor = THREAD_FD(t);
+       struct inotify_event *event;
+       char buf[BUFSIZ];
+       ssize_t len;
+
+       zebra_netns_notify_current = thread_add_read(zebrad.master,
+                                                    zebra_ns_notify_read,
+                                                    NULL, fd_monitor, NULL);
+       len = read(fd_monitor, buf, sizeof(buf));
+       if (len < 0) {
+               zlog_warn("NS notify read: failed to read (%s)",
+                         safe_strerror(errno));
+               return 0;
+       }
+       for (event = (struct inotify_event *)buf;
+            (char *)event < &buf[len];
+            event = (struct inotify_event *)((char *)event +
+                                             sizeof(*event) + event->len)) {
+               char *netnspath;
+               struct zebra_netns_info *netnsinfo;
+
+               if (!(event->mask & IN_CREATE))
+                       continue;
+               netnspath = ns_netns_pathname(NULL, event->name);
+               if (!netnspath)
+                       continue;
+               netnspath = XSTRDUP(MTYPE_NETNS_MISC, netnspath);
+               netnsinfo = XCALLOC(MTYPE_NETNS_MISC,
+                                   sizeof(struct zebra_netns_info));
+               netnsinfo->retries = ZEBRA_NS_POLLING_MAX_RETRIES;
+               netnsinfo->netnspath = netnspath;
+               thread_add_timer_msec(zebrad.master, zebra_ns_ready_read,
+                                      (void *)netnsinfo, 0, NULL);
+       }
+       return 0;
+}
+
+void zebra_ns_notify_parse(void)
+{
+       struct dirent *dent;
+       DIR *srcdir = opendir(NS_RUN_DIR);
+
+       if (srcdir == NULL) {
+               zlog_warn("NS parsing init: failed to parse %s", NS_RUN_DIR);
+               return;
+       }
+       while ((dent = readdir(srcdir)) != NULL) {
+               struct stat st;
+
+               if (strcmp(dent->d_name, ".") == 0
+                  || strcmp(dent->d_name, "..") == 0)
+                       continue;
+               if (fstatat(dirfd(srcdir), dent->d_name, &st, 0) < 0) {
+                       zlog_warn("NS parsing init: failed to parse entry %s",
+                                 dent->d_name);
+                       continue;
+               }
+               if (S_ISDIR(st.st_mode)) {
+                       zlog_warn("NS parsing init: %s is not a NS",
+                                 dent->d_name);
+                       continue;
+               }
+               zebra_ns_notify_create_context_from_entry_name(dent->d_name);
+       }
+       closedir(srcdir);
+}
+
+void zebra_ns_notify_init(void)
+{
+       int fd_monitor;
+
+       zebra_netns_notify_current = NULL;
+       fd_monitor = inotify_init();
+       if (fd_monitor < 0) {
+               zlog_warn("NS notify init: failed to initialize inotify (%s)",
+                         safe_strerror(errno));
+       }
+       if (inotify_add_watch(fd_monitor, NS_RUN_DIR, IN_CREATE) < 0) {
+               zlog_warn("NS notify watch: failed to add watch (%s)",
+                         safe_strerror(errno));
+       }
+       zebra_netns_notify_current = thread_add_read(zebrad.master,
+                                                    zebra_ns_notify_read,
+                                                    NULL, fd_monitor, NULL);
+}
+
+void zebra_ns_notify_close(void)
+{
+       if (zebra_netns_notify_current == NULL)
+               return;
+
+       int fd = 0;
+
+       if (zebra_netns_notify_current->u.fd > 0)
+               fd = zebra_netns_notify_current->u.fd;
+       thread_cancel(zebra_netns_notify_current);
+       /* auto-removal of inotify items */
+       if (fd > 0)
+               close(fd);
+}
+
+#else
+void zebra_ns_notify_parse(void)
+{
+}
+
+void zebra_ns_notify_init(void)
+{
+}
+
+void zebra_ns_notify_close(void)
+{
+}
+#endif /* !HAVE_NETLINK */
diff --git a/zebra/zebra_netns_notify.h b/zebra/zebra_netns_notify.h
new file mode 100644 (file)
index 0000000..0ced749
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Zebra NS collector and notifier for Network NameSpaces
+ * Copyright (C) 2017 6WIND
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _NETNS_NOTIFY_H
+#define _NETNS_NOTIFY_H
+
+extern void zebra_ns_notify_init(void);
+extern void zebra_ns_notify_parse(void);
+extern void zebra_ns_notify_close(void);
+
+extern struct zebra_privs_t zserv_privs;
+
+#endif /* NETNS_NOTIFY_H */
index 02fc2b18443f39b3e4cbe5c9503c650ddf1042c8..50551c9b350d7c2ac23500e18f694343515ad3f3 100644 (file)
@@ -33,6 +33,7 @@
 #include "rt.h"
 #include "zebra_vxlan.h"
 #include "debug.h"
+#include "zebra_netns_notify.h"
 
 DEFINE_MTYPE(ZEBRA, ZEBRA_NS, "Zebra Name Space")
 
@@ -249,6 +250,8 @@ int zebra_ns_init(void)
                ns_add_hook(NS_ENABLE_HOOK, zebra_ns_enabled);
                ns_add_hook(NS_DISABLE_HOOK, zebra_ns_disabled);
                ns_add_hook(NS_DELETE_HOOK, zebra_ns_delete);
+               zebra_ns_notify_parse();
+               zebra_ns_notify_init();
        }
        return 0;
 }