summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilippe Guibert <philippe.guibert@6wind.com>2020-01-06 17:39:17 +0100
committerPhilippe Guibert <philippe.guibert@6wind.com>2020-05-18 14:11:03 +0200
commitde0ebb25404fe984f084a0d57b7f873618423876 (patch)
treea64b4dc3e7d1619db9584e27bcf3fe5de20581df
parentbgpd: sanity check when updating nexthop from bgp to zebra (diff)
downloadfrr-de0ebb25404fe984f084a0d57b7f873618423876.tar.xz
frr-de0ebb25404fe984f084a0d57b7f873618423876.zip
zebra: dynamically detect vxlan link interfaces in other netns
this is used when parsing the newly network namespaces. actually, to track the link of some interfaces like vxlan interfaces, both link index and link nsid are necessary. if a vxlan interface is moved to a new netns, the link information is in the default network namespace, then LINK_NSID is the value of the netns by default in the new netns. That value of the default netns in the new netns is not known, because the system does not automatically assign an NSID of default network namespace in the new netns. Now a new NSID of default netns, seen from that new netns, is created. This permits to store at netns creation the default netns relative value for further usage. Because the default netns value is set from the new netns perspective, it is not needed anymore to use the NETNSA_TARGET_NSID attribute only available in recent kernels. Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
-rw-r--r--zebra/zebra_netns_id.c131
-rw-r--r--zebra/zebra_netns_id.h4
-rw-r--r--zebra/zebra_netns_notify.c21
3 files changed, 39 insertions, 117 deletions
diff --git a/zebra/zebra_netns_id.c b/zebra/zebra_netns_id.c
index eca0961b9..0d86421b9 100644
--- a/zebra/zebra_netns_id.c
+++ b/zebra/zebra_netns_id.c
@@ -159,27 +159,34 @@ static ns_id_t extract_nsid(struct nlmsghdr *nlh, char *buf)
return ns_id;
}
-ns_id_t zebra_ns_id_get(const char *netnspath)
+/* fd_param = -1 is ignored.
+ * netnspath set to null is ignored.
+ * one of the 2 params is mandatory. netnspath is looked in priority
+ */
+ns_id_t zebra_ns_id_get(const char *netnspath, int fd_param)
{
int ns_id = -1;
struct sockaddr_nl snl;
- int fd, sock, ret;
+ int fd = -1, sock, ret;
unsigned int seq;
ns_id_t return_nsid = NS_UNKNOWN;
/* netns path check */
- if (!netnspath)
- return NS_UNKNOWN;
- fd = open(netnspath, O_RDONLY);
- if (fd == -1)
+ if (!netnspath && fd_param == -1)
return NS_UNKNOWN;
-
+ if (netnspath) {
+ fd = open(netnspath, O_RDONLY);
+ if (fd == -1)
+ return NS_UNKNOWN;
+ } else if (fd_param != -1)
+ fd = fd_param;
/* 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));
- close(fd);
+ if (fd_param == -1)
+ close(fd);
return NS_UNKNOWN;
}
memset(&snl, 0, sizeof(snl));
@@ -192,7 +199,8 @@ ns_id_t zebra_ns_id_get(const char *netnspath)
"netlink( %u) socket() bind error: %s", sock,
safe_strerror(errno));
close(sock);
- close(fd);
+ if (fd_param == -1)
+ close(fd);
return NS_UNKNOWN;
}
@@ -214,7 +222,8 @@ ns_id_t zebra_ns_id_get(const char *netnspath)
ret = send_receive(sock, nlh, seq, buf);
if (ret < 0) {
close(sock);
- close(fd);
+ if (fd_param == -1)
+ close(fd);
return NS_UNKNOWN;
}
nlh = (struct nlmsghdr *)buf;
@@ -258,7 +267,8 @@ ns_id_t zebra_ns_id_get(const char *netnspath)
"netlink( %u) recvfrom() error 2 when reading: %s",
fd, safe_strerror(errno));
close(sock);
- close(fd);
+ if (fd_param == -1)
+ close(fd);
if (errno == ENOTSUP) {
zlog_debug("NEWNSID locally generated");
return zebra_ns_id_get_fallback(netnspath);
@@ -278,7 +288,8 @@ ns_id_t zebra_ns_id_get(const char *netnspath)
ret = send_receive(sock, nlh, seq, buf);
if (ret < 0) {
close(sock);
- close(fd);
+ if (fd_param == -1)
+ close(fd);
return NS_UNKNOWN;
}
nlh = (struct nlmsghdr *)buf;
@@ -309,106 +320,18 @@ ns_id_t zebra_ns_id_get(const char *netnspath)
} while (len != 0 && ret == 0);
}
- close(fd);
+ if (fd_param == -1)
+ close(fd);
close(sock);
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)
+ns_id_t zebra_ns_id_get(const char *netnspath, int fd __attribute__ ((unused)))
{
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
@@ -444,7 +367,7 @@ ns_id_t zebra_ns_id_get_default(void)
return NS_DEFAULT_INTERNAL;
}
close(fd);
- return zebra_ns_id_get((char *)NS_DEFAULT_NAME);
+ return zebra_ns_id_get((char *)NS_DEFAULT_NAME, -1);
#else /* HAVE_NETNS */
return NS_DEFAULT_INTERNAL;
#endif /* !HAVE_NETNS */
diff --git a/zebra/zebra_netns_id.h b/zebra/zebra_netns_id.h
index 215d627b7..dd9eab18e 100644
--- a/zebra/zebra_netns_id.h
+++ b/zebra/zebra_netns_id.h
@@ -24,10 +24,8 @@
extern "C" {
#endif
-extern ns_id_t zebra_ns_id_get(const char *netnspath);
+extern ns_id_t zebra_ns_id_get(const char *netnspath, int fd);
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 0e2c1684d..72e4fd005 100644
--- a/zebra/zebra_netns_notify.c
+++ b/zebra/zebra_netns_notify.c
@@ -79,19 +79,10 @@ static void zebra_ns_notify_create_context_from_entry_name(const char *name)
return;
frr_with_privs(&zserv_privs) {
- ns_id = zebra_ns_id_get(netnspath);
+ ns_id = zebra_ns_id_get(netnspath, -1);
}
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);
@@ -107,6 +98,16 @@ static void zebra_ns_notify_create_context_from_entry_name(const char *name)
ns_map_nsid_with_external(ns_id, false);
return;
}
+
+ default_ns = ns_get_default();
+
+ /* force kernel ns_id creation in that new vrf */
+ frr_with_privs(&zserv_privs) {
+ ns_switch_to_netns(netnspath);
+ ns_id_relative = zebra_ns_id_get(NULL, default_ns->fd);
+ ns_switchback_to_initial();
+ }
+
frr_with_privs(&zserv_privs) {
ret = vrf_netns_handler_create(NULL, vrf, netnspath,
ns_id_external,