diff options
-rw-r--r-- | include/linux/net_namespace.h | 1 | ||||
-rw-r--r-- | lib/netns_linux.c | 6 | ||||
-rw-r--r-- | lib/ns.h | 1 | ||||
-rw-r--r-- | zebra/zebra_netns_id.c | 90 | ||||
-rw-r--r-- | zebra/zebra_netns_id.h | 2 | ||||
-rw-r--r-- | zebra/zebra_netns_notify.c | 12 |
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; +} + @@ -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); |