1
0
mirror of https://github.com/systemd/systemd.git synced 2024-12-23 21:35:11 +03:00

Merge pull request #30908 from poettering/nsid

networkd: expose netns "nsid" together with inode id
This commit is contained in:
Yu Watanabe 2024-01-13 06:54:32 +09:00 committed by GitHub
commit 7a10e25a41
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 186 additions and 9 deletions

View File

@ -87,6 +87,8 @@ node /org/freedesktop/network1 {
readonly s OnlineState = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly t NamespaceId = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly u NamespaceNSID = ...;
};
interface org.freedesktop.DBus.Peer { ... };
interface org.freedesktop.DBus.Introspectable { ... };
@ -148,8 +150,6 @@ node /org/freedesktop/network1 {
<!--property OnlineState is not documented!-->
<!--property NamespaceId is not documented!-->
<!--Autogenerated cross-references for systemd.directives, do not edit-->
<variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.network1.Manager"/>
@ -212,11 +212,24 @@ node /org/freedesktop/network1 {
<variablelist class="dbus-property" generated="True" extra-ref="NamespaceId"/>
<variablelist class="dbus-property" generated="True" extra-ref="NamespaceNSID"/>
<!--End of Autogenerated section-->
<para>
Provides information about the manager.
</para>
<refsect2>
<title>Properties</title>
<para><varname>NamespaceId</varname> contains the inode number of the network namespace that the
network service runs in. A client may compare this with the inode number of its own network namespace
to verify whether the service manages the same network namespace.</para>
<para><varname>NamespaceNSID</varname> contains the "nsid" identifier the kernel maintains for the
network namespace, if there's one assigned.</para>
</refsect2>
</refsect1>
<refsect1>
@ -584,5 +597,9 @@ $ gdbus introspect --system \
<title>DHCPv6 Client Object</title>
<para><varname>State</varname> was added in version 255.</para>
</refsect2>
<refsect2>
<title>Manager Object</title>
<para><varname>NamespaceNSID</varname> was added in version 256.</para>
</refsect2>
</refsect1>
</refentry>

View File

@ -56,6 +56,10 @@ static bool rtnl_message_type_is_mdb(uint16_t type) {
return IN_SET(type, RTM_NEWMDB, RTM_DELMDB, RTM_GETMDB);
}
static bool rtnl_message_type_is_nsid(uint16_t type) {
return IN_SET(type, RTM_NEWNSID, RTM_DELNSID, RTM_GETNSID);
}
int sd_rtnl_message_route_set_dst_prefixlen(sd_netlink_message *m, unsigned char prefixlen) {
struct rtmsg *rtm;
@ -1216,3 +1220,24 @@ int sd_rtnl_message_new_mdb(
return 0;
}
int sd_rtnl_message_new_nsid(
sd_netlink *rtnl,
sd_netlink_message **ret,
uint16_t nlmsg_type) {
struct rtgenmsg *rt;
int r;
assert_return(rtnl_message_type_is_nsid(nlmsg_type), -EINVAL);
assert_return(ret, -EINVAL);
r = message_new(rtnl, ret, nlmsg_type);
if (r < 0)
return r;
rt = NLMSG_DATA((*ret)->hdr);
rt->rtgen_family = AF_UNSPEC;
return 0;
}

View File

@ -17,6 +17,7 @@
#include <linux/if_tunnel.h>
#include <linux/ip.h>
#include <linux/l2tp.h>
#include <linux/net_namespace.h>
#include <linux/netlink.h>
#include <linux/nexthop.h>
#include <linux/nl80211.h>
@ -1185,6 +1186,13 @@ static const NLAPolicy rtnl_mdb_policies[] = {
DEFINE_POLICY_SET(rtnl_mdb);
static const NLAPolicy rtnl_nsid_policies[] = {
[NETNSA_FD] = BUILD_POLICY(S32),
[NETNSA_NSID] = BUILD_POLICY(U32),
};
DEFINE_POLICY_SET(rtnl_nsid);
static const NLAPolicy rtnl_policies[] = {
[RTM_NEWLINK] = BUILD_POLICY_NESTED_WITH_SIZE(rtnl_link, sizeof(struct ifinfomsg)),
[RTM_DELLINK] = BUILD_POLICY_NESTED_WITH_SIZE(rtnl_link, sizeof(struct ifinfomsg)),
@ -1220,6 +1228,9 @@ static const NLAPolicy rtnl_policies[] = {
[RTM_NEWMDB] = BUILD_POLICY_NESTED_WITH_SIZE(rtnl_mdb, sizeof(struct br_port_msg)),
[RTM_DELMDB] = BUILD_POLICY_NESTED_WITH_SIZE(rtnl_mdb, sizeof(struct br_port_msg)),
[RTM_GETMDB] = BUILD_POLICY_NESTED_WITH_SIZE(rtnl_mdb, sizeof(struct br_port_msg)),
[RTM_NEWNSID] = BUILD_POLICY_NESTED_WITH_SIZE(rtnl_nsid, sizeof(struct rtgenmsg)),
[RTM_DELNSID] = BUILD_POLICY_NESTED_WITH_SIZE(rtnl_nsid, sizeof(struct rtgenmsg)),
[RTM_GETNSID] = BUILD_POLICY_NESTED_WITH_SIZE(rtnl_nsid, sizeof(struct rtgenmsg)),
};
DEFINE_POLICY_SET(rtnl);

View File

@ -279,6 +279,31 @@ static int property_get_namespace_id(
return sd_bus_message_append(reply, "t", id);
}
static int property_get_namespace_nsid(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error) {
uint32_t nsid = UINT32_MAX;
int r;
assert(bus);
assert(reply);
/* Returns our own "nsid", which is another ID for the network namespace, different from the inode
* number. */
r = netns_get_nsid(/* netnsfd= */ -EBADF, &nsid);
if (r < 0)
log_warning_errno(r, "Failed to query network nsid, ignoring: %m");
return sd_bus_message_append(reply, "u", nsid);
}
static const sd_bus_vtable manager_vtable[] = {
SD_BUS_VTABLE_START(0),
@ -289,6 +314,7 @@ static const sd_bus_vtable manager_vtable[] = {
SD_BUS_PROPERTY("IPv6AddressState", "s", property_get_address_state, offsetof(Manager, ipv6_address_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("OnlineState", "s", property_get_online_state, offsetof(Manager, online_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("NamespaceId", "t", property_get_namespace_id, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("NamespaceNSID", "u", property_get_namespace_nsid, 0, 0),
SD_BUS_METHOD_WITH_ARGS("ListLinks",
SD_BUS_NO_ARGS,

View File

@ -25,23 +25,35 @@ static int vl_method_get_states(Varlink *link, JsonVariant *parameters, VarlinkM
}
static int vl_method_get_namespace_id(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) {
uint64_t id;
uint64_t inode = 0;
uint32_t nsid = UINT32_MAX;
int r;
assert(link);
if (json_variant_elements(parameters) > 0)
return varlink_error_invalid_parameter(link, parameters);
/* Network namespaces have two identifiers: the inode number (which all namespace types have), and
* the "nsid" (aka the "cookie"), which only network namespaces know as a concept, and which is not
* assigned by default, but once it is, is fixed. Let's return both, to avoid any confusion which one
* this is. */
struct stat st;
if (stat("/proc/self/ns/net", &st) < 0) {
if (stat("/proc/self/ns/net", &st) < 0)
log_warning_errno(errno, "Failed to stat network namespace, ignoring: %m");
id = 0;
} else
id = st.st_ino;
else
inode = st.st_ino;
r = netns_get_nsid(/* netnsfd= */ -EBADF, &nsid);
if (r < 0)
log_warning_errno(r, "Failed to query network nsid, ignoring: %m");
return varlink_replyb(link,
JSON_BUILD_OBJECT(
JSON_BUILD_PAIR_UNSIGNED("NamespaceId", id)));
JSON_BUILD_PAIR_UNSIGNED("NamespaceId", inode),
JSON_BUILD_PAIR_CONDITION(nsid == UINT32_MAX, "NamespaceNSID", JSON_BUILD_NULL),
JSON_BUILD_PAIR_CONDITION(nsid != UINT32_MAX, "NamespaceNSID", JSON_BUILD_UNSIGNED(nsid))));
}
int manager_connect_varlink(Manager *m) {

View File

@ -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;
}

View File

@ -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);

View File

@ -11,7 +11,8 @@ static VARLINK_DEFINE_METHOD(GetStates,
VARLINK_DEFINE_OUTPUT(OperationalState, VARLINK_STRING, 0));
static VARLINK_DEFINE_METHOD(GetNamespaceId,
VARLINK_DEFINE_OUTPUT(NamespaceId, VARLINK_INT, 0));
VARLINK_DEFINE_OUTPUT(NamespaceId, VARLINK_INT, 0),
VARLINK_DEFINE_OUTPUT(NamespaceNSID, VARLINK_INT, VARLINK_NULLABLE));
VARLINK_DEFINE_INTERFACE(
io_systemd_Network,

View File

@ -216,6 +216,8 @@ int sd_rtnl_message_traffic_control_get_parent(sd_netlink_message *m, uint32_t *
int sd_rtnl_message_new_mdb(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t nlmsg_type, int mdb_ifindex);
int sd_rtnl_message_new_nsid(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t nlmsg_type);
/* genl */
int sd_genl_socket_open(sd_netlink **ret);
int sd_genl_message_new(sd_netlink *genl, const char *family_name, uint8_t cmd, sd_netlink_message **ret);

View File

@ -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);