diff options
-rw-r--r-- | src/shared/socket-netlink.c | 69 | ||||
-rw-r--r-- | src/shared/socket-netlink.h | 2 | ||||
-rw-r--r-- | src/test/test-socket-netlink.c | 12 |
3 files changed, 83 insertions, 0 deletions
diff --git a/src/shared/socket-netlink.c b/src/shared/socket-netlink.c index 0ba5762761..94b699a5ee 100644 --- a/src/shared/socket-netlink.c +++ b/src/shared/socket-netlink.c @@ -2,14 +2,17 @@ #include <arpa/inet.h> #include <errno.h> +#include <linux/net_namespace.h> #include <net/if.h> #include <string.h> #include "alloc-util.h" #include "errno-util.h" #include "extract-word.h" +#include "fd-util.h" #include "log.h" #include "memory-util.h" +#include "namespace-util.h" #include "netlink-util.h" #include "parse-util.h" #include "socket-netlink.h" @@ -407,3 +410,69 @@ const char *in_addr_full_to_string(struct in_addr_full *a) { return a->cached_server_string; } + +int netns_get_nsid(int netnsfd, uint32_t *ret) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; + _cleanup_close_ int _netns_fd = -EBADF; + int r; + + if (netnsfd < 0) { + r = namespace_open( + 0, + /* pidns_fd= */ NULL, + /* mntns_fd= */ NULL, + &_netns_fd, + /* userns_fd= */ NULL, + /* root_fd= */ NULL); + if (r < 0) + return r; + + netnsfd = _netns_fd; + } + + r = sd_netlink_open(&rtnl); + if (r < 0) + return r; + + r = sd_rtnl_message_new_nsid(rtnl, &req, RTM_GETNSID); + if (r < 0) + return r; + + r = sd_netlink_message_append_s32(req, NETNSA_FD, netnsfd); + if (r < 0) + return r; + + r = sd_netlink_call(rtnl, req, 0, &reply); + if (r < 0) + return r; + + for (sd_netlink_message *m = reply; m; m = sd_netlink_message_next(m)) { + uint16_t type; + + r = sd_netlink_message_get_errno(m); + if (r < 0) + return r; + + r = sd_netlink_message_get_type(m, &type); + if (r < 0) + return r; + if (type != RTM_NEWNSID) + continue; + + uint32_t u; + r = sd_netlink_message_read_u32(m, NETNSA_NSID, &u); + if (r < 0) + return r; + + if (u == UINT32_MAX) /* no NSID assigned yet */ + return -ENODATA; + + if (ret) + *ret = u; + + return 0; + } + + return -ENXIO; +} diff --git a/src/shared/socket-netlink.h b/src/shared/socket-netlink.h index 6256a831ba..2c06fbe3a7 100644 --- a/src/shared/socket-netlink.h +++ b/src/shared/socket-netlink.h @@ -42,3 +42,5 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(struct in_addr_full*, in_addr_full_free); int in_addr_full_new(int family, const union in_addr_union *a, uint16_t port, int ifindex, const char *server_name, struct in_addr_full **ret); int in_addr_full_new_from_string(const char *s, struct in_addr_full **ret); const char *in_addr_full_to_string(struct in_addr_full *a); + +int netns_get_nsid(int netnsfd, uint32_t *ret); diff --git a/src/test/test-socket-netlink.c b/src/test/test-socket-netlink.c index 6dbd50f4a1..ad642ca4b1 100644 --- a/src/test/test-socket-netlink.c +++ b/src/test/test-socket-netlink.c @@ -369,4 +369,16 @@ TEST(in_addr_port_ifindex_name_from_string_auto) { test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%lo#hoge.com", AF_INET6, 53, 1, "hoge.com", "[fe80::18]:53%1#hoge.com"); } +TEST(netns_get_nsid) { + uint32_t u; + int r; + + r = netns_get_nsid(-EBADF, &u); + assert_se(r == -ENODATA || r >= 0); + if (r == -ENODATA) + log_info("Our network namespace has no NSID assigned."); + else + log_info("Our NSID is %" PRIu32, u); +} + DEFINE_TEST_MAIN(LOG_DEBUG); |