]> git.puffer.fish Git - mirror/frr.git/commitdiff
lib: provide an API to switch from one netns to an other
authorPhilippe Guibert <philippe.guibert@6wind.com>
Wed, 20 Dec 2017 11:29:21 +0000 (12:29 +0100)
committerPhilippe Guibert <philippe.guibert@6wind.com>
Tue, 27 Feb 2018 10:11:24 +0000 (11:11 +0100)
Two apis are provided so that the switch from one netns to an other one
is taken care.
Also an other API to know if the VRF has a NETNS backend or a VRF Lite
backend.

Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
lib/ns.c
lib/ns.h
lib/vrf.c
lib/vrf.h

index e2c042d16cb6ca2b7414748b7b35e172146e7071..9aa35099236ebf86785f3814bc794c95ac9cfd39 100644 (file)
--- a/lib/ns.c
+++ b/lib/ns.c
@@ -51,6 +51,9 @@ RB_GENERATE(ns_head, ns, entry, ns_compare)
 
 struct ns_head ns_tree = RB_INITIALIZER(&ns_tree);
 
+static int ns_current_ns_fd;
+static int ns_default_ns_fd;
+
 #ifndef CLONE_NEWNET
 #define CLONE_NEWNET 0x40000000 /* New network namespace (lo, device, names sockets, etc) */
 #endif
@@ -613,13 +616,26 @@ DEFUN (no_ns_netns,
        return CMD_SUCCESS;
 }
 
+void ns_init(void)
+{
+#ifdef HAVE_NETNS
+       if (have_netns_enabled < 0) {
+               ns_default_ns_fd = open(NS_DEFAULT_NAME, O_RDONLY);
+               return;
+       }
+#endif /* HAVE_NETNS */
+       ns_default_ns_fd = -1;
+}
+
 /* Initialize NS module. */
 void ns_init_zebra(void)
 {
        struct ns *default_ns;
 
+       ns_init();
        /* The default NS always exists. */
        default_ns = ns_get(NS_DEFAULT);
+       ns_current_ns_fd = -1;
        if (!default_ns) {
                zlog_err("ns_init: failed to create the default NS!");
                exit(1);
@@ -664,6 +680,40 @@ void ns_terminate(void)
        }
 }
 
+int ns_switch_to_netns(const char *name)
+{
+       int ret;
+       int fd;
+
+       if (name == NULL)
+               return -1;
+       fd = open(name, O_RDONLY);
+       if (fd == -1) {
+               errno = ENOSYS;
+               return -1;
+       }
+       ret = setns(fd, CLONE_NEWNET);
+       ns_current_ns_fd = fd;
+       close(fd);
+       return ret;
+}
+
+/* returns 1 if switch() was not called before
+ * return status of setns() otherwise
+ */
+int ns_switchback_to_initial(void)
+{
+       if (ns_current_ns_fd != -1) {
+               int ret;
+
+               ret = setns(ns_default_ns_fd, CLONE_NEWNET);
+               ns_current_ns_fd = -1;
+               return ret;
+       }
+       /* silently ignore if setns() is not called */
+       return 1;
+}
+
 /* Create a socket for the NS. */
 int ns_socket(int domain, int type, int protocol, ns_id_t ns_id)
 {
@@ -679,8 +729,10 @@ int ns_socket(int domain, int type, int protocol, ns_id_t ns_id)
                ret = (ns_id != NS_DEFAULT) ? setns(ns->fd, CLONE_NEWNET) : 0;
                if (ret >= 0) {
                        ret = socket(domain, type, protocol);
-                       if (ns_id != NS_DEFAULT)
+                       if (ns_id != NS_DEFAULT) {
                                setns(ns_lookup(NS_DEFAULT)->fd, CLONE_NEWNET);
+                               ns_current_ns_fd = ns_id;
+                       }
                }
        } else
                ret = socket(domain, type, protocol);
index fca5becd7a8ab35d306dab4dcafdde4496893289..73482d4d5648a2f799b5ad43fadc083f4c9e33fa 100644 (file)
--- a/lib/ns.h
+++ b/lib/ns.h
@@ -84,6 +84,7 @@ extern void ns_add_hook(int type, int (*)(struct ns *));
 /*
  * NS initializer/destructor
  */
+extern void ns_init(void);
 extern void ns_init_zebra(void);
 extern void ns_terminate(void);
 
@@ -101,4 +102,9 @@ extern void *ns_info_lookup(ns_id_t ns_id);
 extern void ns_walk_func(int (*func)(struct ns *));
 extern const char *ns_get_name(struct ns *ns);
 
+/* API that can be used by all daemons */
+extern int ns_switchback_to_initial(void);
+extern int ns_switch_to_netns(const char *netns_name);
+extern void ns_init(void);
+
 #endif /*_ZEBRA_NS_H*/
index 5b85effabd8ce329d50c059b416aa85a74be6923..787105235225b956c7cf63438f48d13b4c895754 100644 (file)
--- a/lib/vrf.c
+++ b/lib/vrf.c
@@ -86,6 +86,32 @@ static int vrf_name_compare(const struct vrf *a, const struct vrf *b)
        return strcmp(a->name, b->name);
 }
 
+int vrf_switch_to_netns(vrf_id_t vrf_id)
+{
+       char *name;
+       struct vrf *vrf = vrf_lookup_by_id(vrf_id);
+
+       /* VRF has no NETNS backend. silently ignore */
+       if (!vrf || vrf->data.l.netns_name[0] == '\0')
+               return 0;
+       /* VRF is default VRF. silently ignore */
+       if (vrf->vrf_id == VRF_DEFAULT)
+               return 0;
+       name = ns_netns_pathname(NULL, vrf->data.l.netns_name);
+       if (debug_vrf)
+               zlog_debug("VRF_SWITCH: %s(%u)", name, vrf->vrf_id);
+       return ns_switch_to_netns(name);
+}
+
+int vrf_switchback_to_initial(void)
+{
+       int ret = ns_switchback_to_initial();
+
+       if (ret == 0 && debug_vrf)
+               zlog_debug("VRF_SWITCHBACK");
+       return ret;
+}
+
 /* return 1 if vrf can be enabled */
 int vrf_update_vrf_id(vrf_id_t vrf_id, struct vrf *vrf)
 {
@@ -509,6 +535,17 @@ int vrf_handler_create(struct vty *vty, const char *vrfname, struct vrf **vrf)
        return CMD_SUCCESS;
 }
 
+int vrf_is_mapped_on_netns(vrf_id_t vrf_id)
+{
+       struct vrf *vrf = vrf_lookup_by_id(vrf_id);
+
+       if (!vrf || vrf->data.l.netns_name[0] == '\0')
+               return 0;
+       if (vrf->vrf_id == VRF_DEFAULT)
+               return 0;
+       return 1;
+}
+
 /* vrf CLI commands */
 DEFUN_NOSH (vrf,
        vrf_cmd,
index c1da4e8bbcc67e01500204db660ba906b325490b..4bdc183b5ce9c052a208fa3fd7e9b30b1deef81f 100644 (file)
--- a/lib/vrf.h
+++ b/lib/vrf.h
@@ -218,6 +218,13 @@ extern int vrf_handler_create(struct vty *vty,
                              const char *name,
                              struct vrf **vrf);
 
+/* VRF is mapped on netns or not ? */
+int vrf_is_mapped_on_netns(vrf_id_t vrf_id);
+
+/* VRF switch from NETNS */
+extern int vrf_switch_to_netns(vrf_id_t vrf_id);
+extern int vrf_switchback_to_initial(void);
+
 /* used by NS when vrf backend is NS.
  * Notify a change in the VRF ID of the VRF
  */