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));
"netlink( %u) socket() bind error: %s", sock,
safe_strerror(errno));
close(sock);
- close(fd);
+ if (fd_param == -1)
+ close(fd);
return NS_UNKNOWN;
}
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;
"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);
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;
} 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
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 */
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);
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,