summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/net_namespace.h1
-rw-r--r--lib/netns_linux.c6
-rw-r--r--lib/ns.h1
-rw-r--r--zebra/zebra_netns_id.c90
-rw-r--r--zebra/zebra_netns_id.h2
-rw-r--r--zebra/zebra_netns_notify.c12
6 files changed, 111 insertions, 1 deletions
diff --git a/include/linux/net_namespace.h b/include/linux/net_namespace.h
index 0187c74d8..0ed9dd61d 100644
--- a/include/linux/net_namespace.h
+++ b/include/linux/net_namespace.h
@@ -16,6 +16,7 @@ enum {
NETNSA_NSID,
NETNSA_PID,
NETNSA_FD,
+ NETNSA_TARGET_NSID,
__NETNSA_MAX,
};
diff --git a/lib/netns_linux.c b/lib/netns_linux.c
index 09a42b850..bb66e8938 100644
--- a/lib/netns_linux.c
+++ b/lib/netns_linux.c
@@ -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;
+}
+
diff --git a/lib/ns.h b/lib/ns.h
index 1963b8a35..c594cbfac 100644
--- 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
}
diff --git a/zebra/zebra_netns_id.c b/zebra/zebra_netns_id.c
index 8de4daf43..61d2ebe18 100644
--- a/zebra/zebra_netns_id.c
+++ b/zebra/zebra_netns_id.c
@@ -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
diff --git a/zebra/zebra_netns_id.h b/zebra/zebra_netns_id.h
index 7a5f6851f..215d627b7 100644
--- a/zebra/zebra_netns_id.h
+++ b/zebra/zebra_netns_id.h
@@ -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
}
diff --git a/zebra/zebra_netns_notify.c b/zebra/zebra_netns_notify.c
index ec7681bf2..db620cf22 100644
--- a/zebra/zebra_netns_notify.c
+++ b/zebra/zebra_netns_notify.c
@@ -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);