]> git.puffer.fish Git - matthieu/frr.git/commitdiff
zebra, lib: add an internal API to get relative default nsid in other ns
authorPhilippe Guibert <philippe.guibert@6wind.com>
Wed, 2 Oct 2019 10:14:13 +0000 (12:14 +0200)
committerPhilippe Guibert <philippe.guibert@6wind.com>
Mon, 21 Sep 2020 07:17:10 +0000 (09:17 +0200)
as remind, the netns identifiers are local to a namespace. that is to
say that for instance, a vrf <vrfx> will have a netns id value in one
netns, and have an other netns id value in one other netns.
There is a need for zebra daemon to collect some cross information, like
the LINK_NETNSID information from interfaces having link layer in an
other network namespace. For that, it is needed to have a global
overview instead of a relative overview per namespace.
The first brick of this change is an API that sticks to netlink API,
that uses NETNSA_TARGET_NSID. from a given vrf vrfX, and a new vrf
created vrfY, the API returns the value of nsID from vrfX, inside the
new vrf vrfY.
The brick also gets the ns id value of default namespace in each other
namespace. An additional value in ns.h is offered, that permits to
retrieve the default namespace context.

Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
include/linux/net_namespace.h
lib/netns_linux.c
lib/ns.h
zebra/zebra_netns_id.c
zebra/zebra_netns_id.h
zebra/zebra_netns_notify.c

index 0187c74d88894ade01c6a6bb9b5baba23675d09b..0ed9dd61d32a1ed7a66ad235566fff8d9a2d63a7 100644 (file)
@@ -16,6 +16,7 @@ enum {
        NETNSA_NSID,
        NETNSA_PID,
        NETNSA_FD,
+       NETNSA_TARGET_NSID,
        __NETNSA_MAX,
 };
 
index 09a42b850bf301ec99f99ea84efe770726fe9d5b..bb66e8938fa0f035d16284f21276bd12d101c8e1 100644 (file)
@@ -590,3 +590,9 @@ ns_id_t ns_get_default_id(void)
                return default_ns->ns_id;
        return NS_DEFAULT_INTERNAL;
 }
+
+struct ns *ns_get_default(void)
+{
+       return default_ns;
+}
+
index 1963b8a35968750efc194319b1614d132fc66ca7..c594cbfac924ddf08d0faf6eb55408120d0b9398 100644 (file)
--- a/lib/ns.h
+++ b/lib/ns.h
@@ -177,6 +177,7 @@ extern struct ns *ns_lookup_name(const char *name);
 extern int ns_enable(struct ns *ns, void (*func)(ns_id_t, void *));
 extern struct ns *ns_get_created(struct ns *ns, char *name, ns_id_t ns_id);
 extern void ns_disable(struct ns *ns);
+extern struct ns *ns_get_default(void);
 
 #ifdef __cplusplus
 }
index 8de4daf439a2cfc073860f7494a7baff32bac8fd..61d2ebe184304065d221710369aab2e5807d2697 100644 (file)
@@ -315,11 +315,101 @@ ns_id_t zebra_ns_id_get(const char *netnspath)
        return return_nsid;
 }
 
+/* if nsid is not default one, get relative default ns for the new ns
+ * for instance, if default ns is 0 and a new ns "vrf1" id is 1,
+ * in  ns "vrf1", the default ns is not known. using GETNSID with
+ * two parameters: NETNS_NSID, and NETNS_TARGET_NSID will help
+ * in identifying that value
+ */
+ns_id_t zebra_ns_id_get_relative_value(ns_id_t ns_read, ns_id_t target_nsid)
+{
+       struct sockaddr_nl snl;
+       int sock, ret;
+       unsigned int seq;
+       ns_id_t return_nsid = NS_UNKNOWN;
+       char buf[NETLINK_SOCKET_BUFFER_SIZE];
+       struct nlmsghdr *nlh;
+       struct rtgenmsg *rt;
+       int len;
+
+       if (ns_read == NS_UNKNOWN || target_nsid == NS_UNKNOWN)
+               return return_nsid;
+
+       /* netlink socket */
+       sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+       if (sock < 0) {
+               flog_err_sys(EC_LIB_SOCKET, "netlink( %u) socket() error: %s",
+                            sock, safe_strerror(errno));
+               return NS_UNKNOWN;
+       }
+       memset(&snl, 0, sizeof(snl));
+       snl.nl_family = AF_NETLINK;
+       snl.nl_groups = RTNLGRP_NSID;
+       snl.nl_pid = 0; /* AUTO PID */
+       ret = bind(sock, (struct sockaddr *)&snl, sizeof(snl));
+       if (ret < 0) {
+               flog_err_sys(EC_LIB_SOCKET,
+                            "netlink( %u) socket() bind error: %s", sock,
+                            safe_strerror(errno));
+               close(sock);
+               return NS_UNKNOWN;
+       }
+
+       /* message to send to netlink : GETNSID */
+       memset(buf, 0, NETLINK_SOCKET_BUFFER_SIZE);
+       nlh = initiate_nlh(buf, &seq, RTM_GETNSID);
+       rt = (struct rtgenmsg *)(buf + nlh->nlmsg_len);
+       nlh->nlmsg_len += NETLINK_ALIGN(sizeof(struct rtgenmsg));
+       rt->rtgen_family = AF_UNSPEC;
+
+       addattr32(nlh, NETLINK_SOCKET_BUFFER_SIZE, NETNSA_NSID, ns_read);
+       addattr32(nlh, NETLINK_SOCKET_BUFFER_SIZE, NETNSA_TARGET_NSID, target_nsid);
+
+       ret = send_receive(sock, nlh, seq, buf);
+       if (ret < 0) {
+               close(sock);
+               return NS_UNKNOWN;
+       }
+       nlh = (struct nlmsghdr *)buf;
+       len = ret;
+       ret = 0;
+       do {
+               if (nlh->nlmsg_type >= NLMSG_MIN_TYPE) {
+                       return_nsid = extract_nsid(nlh, buf);
+                       if (return_nsid != NS_UNKNOWN)
+                               break;
+               } else if (nlh->nlmsg_type == NLMSG_ERROR) {
+                       struct nlmsgerr *err =
+                               (struct nlmsgerr
+                                *)((char *)nlh
+                                   + NETLINK_ALIGN(sizeof(
+                                                          struct
+                                                          nlmsghdr)));
+                       if (err->error < 0)
+                               errno = -err->error;
+                       else
+                               errno = err->error;
+                       break;
+               }
+               len = len - NETLINK_ALIGN(nlh->nlmsg_len);
+               nlh = (struct nlmsghdr *)((char *)nlh
+                                         + NETLINK_ALIGN(
+                                                         nlh->nlmsg_len));
+       } while (len != 0 && ret == 0);
+
+       return return_nsid;
+}
+
 #else
 ns_id_t zebra_ns_id_get(const char *netnspath)
 {
        return zebra_ns_id_get_fallback(netnspath);
 }
+
+ns_id_t zebra_ns_id_get_relative_value(ns_id_t ns_read, ns_id_t target_nsid)
+{
+       return NS_UNKNOWN;
+}
 #endif /* ! defined(HAVE_NETLINK) */
 
 #ifdef HAVE_NETNS
index 7a5f6851f481f94cc11eeaeca0c26a1a781b5215..215d627b7b72bf3f0da08f4599d1be1adcc6f269 100644 (file)
@@ -26,6 +26,8 @@ extern "C" {
 
 extern ns_id_t zebra_ns_id_get(const char *netnspath);
 extern ns_id_t zebra_ns_id_get_default(void);
+extern ns_id_t zebra_ns_id_get_relative_value(ns_id_t ns_read,
+                                             ns_id_t target_nsid);
 
 #ifdef __cplusplus
 }
index ec7681bf2381b09726ea2e5cea4c0b5640c5cbfe..db620cf220e318cb3df2aaf879a712a1886b8588 100644 (file)
@@ -72,7 +72,8 @@ 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, ns_id_external;
+       ns_id_t ns_id, ns_id_external, ns_id_relative = NS_UNKNOWN;
+       struct ns *default_ns;
 
        if (netnspath == NULL)
                return;
@@ -82,6 +83,15 @@ static void zebra_ns_notify_create_context_from_entry_name(const char *name)
        }
        if (ns_id == NS_UNKNOWN)
                return;
+       default_ns = ns_get_default();
+       if (default_ns && default_ns->internal_ns_id != ns_id) {
+               frr_with_privs(&zserv_privs) {
+                       ns_id_relative =
+                               zebra_ns_id_get_relative_value(
+                                                       default_ns->internal_ns_id,
+                                                       ns_id);
+               }
+       }
        ns_id_external = ns_map_nsid_with_external(ns_id, true);
        /* if VRF with NS ID already present */
        vrf = vrf_lookup_by_id((vrf_id_t)ns_id_external);