From 6109cf8b61a4b7fbef447cab8fa1a07baf749cfd Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 18 Feb 2026 12:10:50 +0900 Subject: [PATCH 1/3] meson,test: sort unit files --- test/networkd-test.py | 8 +-- test/test-network/systemd-networkd-tests.py | 66 ++++++++++----------- units/meson.build | 4 +- 3 files changed, 39 insertions(+), 39 deletions(-) diff --git a/test/networkd-test.py b/test/networkd-test.py index a082f5456f..62041201ca 100755 --- a/test/networkd-test.py +++ b/test/networkd-test.py @@ -64,11 +64,11 @@ def setUpModule(): # Ensure we don't mess with an existing networkd config for u in [ 'systemd-networkd.socket', - 'systemd-networkd-varlink.socket', 'systemd-networkd-resolve-hook.socket', + 'systemd-networkd-varlink.socket', 'systemd-networkd.service', - 'systemd-resolved-varlink.socket', 'systemd-resolved-monitor.socket', + 'systemd-resolved-varlink.socket', 'systemd-resolved.service', ]: if subprocess.call(['systemctl', 'is-active', '--quiet', u]) == 0: @@ -279,8 +279,8 @@ Gateway=192.168.250.1 def tearDown(self): subprocess.check_call(['systemctl', 'stop', 'systemd-networkd.socket']) - subprocess.check_call(['systemctl', 'stop', 'systemd-networkd-varlink.socket']) subprocess.check_call(['systemctl', 'stop', 'systemd-networkd-resolve-hook.socket']) + subprocess.check_call(['systemctl', 'stop', 'systemd-networkd-varlink.socket']) subprocess.check_call(['systemctl', 'stop', 'systemd-networkd.service']) subprocess.check_call(['ip', 'link', 'del', 'mybridge']) subprocess.check_call(['ip', 'link', 'del', 'port1']) @@ -376,8 +376,8 @@ class ClientTestBase(NetworkdTestingUtilities): def tearDown(self): self.shutdown_iface() subprocess.call(['systemctl', 'stop', 'systemd-networkd.socket']) - subprocess.call(['systemctl', 'stop', 'systemd-networkd-varlink.socket']) subprocess.call(['systemctl', 'stop', 'systemd-networkd-resolve-hook.socket']) + subprocess.call(['systemctl', 'stop', 'systemd-networkd-varlink.socket']) subprocess.call(['systemctl', 'stop', 'systemd-networkd.service']) subprocess.call(['ip', 'link', 'del', 'dummy0'], stderr=subprocess.DEVNULL) diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index 2843be3e2a..93e3ee626f 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -425,8 +425,8 @@ def clear_udev_rules(): def save_active_units(): for u in [ 'systemd-networkd.socket', - 'systemd-networkd-varlink.socket', 'systemd-networkd-resolve-hook.socket', + 'systemd-networkd-varlink.socket', 'systemd-networkd.service', 'systemd-resolved-monitor.socket', 'systemd-resolved-varlink.socket', @@ -447,14 +447,14 @@ def restore_active_units(): call('systemctl stop systemd-networkd.socket') has_network_socket = True - if 'systemd-networkd-varlink.socket' in active_units: - call('systemctl stop systemd-networkd-varlink.socket') - has_network_socket = True - if 'systemd-networkd-resolve-hook.socket' in active_units: call('systemctl stop systemd-networkd-resolve-hook.socket') has_network_socket = True + if 'systemd-networkd-varlink.socket' in active_units: + call('systemctl stop systemd-networkd-varlink.socket') + has_network_socket = True + if 'systemd-resolved-monitor.socket' in active_units: call('systemctl stop systemd-resolved-monitor.socket') has_resolve_socket = True @@ -521,9 +521,9 @@ def setup_system_units(): for unit in [ 'systemd-networkd.service', 'systemd-networkd.socket', - 'systemd-networkd-varlink.socket', - 'systemd-networkd-resolve-hook.socket', 'systemd-networkd-persistent-storage.service', + 'systemd-networkd-resolve-hook.socket', + 'systemd-networkd-varlink.socket', 'systemd-resolved.service', 'systemd-timesyncd.service', 'systemd-udevd.service', @@ -548,14 +548,6 @@ def setup_system_units(): create_service_dropin('systemd-timesyncd', timesyncd_bin) # TODO: also run udevd with sanitizers, valgrind, or coverage - create_unit_dropin( - 'systemd-udevd.service', - [ - '[Service]', - 'ExecStart=', - f'ExecStart=@{udevadm_bin} systemd-udevd', - ] - ) create_unit_dropin( 'systemd-networkd.socket', [ @@ -563,20 +555,6 @@ def setup_system_units(): 'StartLimitIntervalSec=0', ] ) - create_unit_dropin( - 'systemd-networkd-varlink.socket', - [ - '[Unit]', - 'StartLimitIntervalSec=0', - ] - ) - create_unit_dropin( - 'systemd-networkd-resolve-hook.socket', - [ - '[Unit]', - 'StartLimitIntervalSec=0', - ] - ) create_unit_dropin( 'systemd-networkd-persistent-storage.service', [ @@ -590,6 +568,28 @@ def setup_system_units(): 'Environment=SYSTEMD_LOG_LEVEL=debug' if enable_debug else '', ] ) + create_unit_dropin( + 'systemd-networkd-resolve-hook.socket', + [ + '[Unit]', + 'StartLimitIntervalSec=0', + ] + ) + create_unit_dropin( + 'systemd-networkd-varlink.socket', + [ + '[Unit]', + 'StartLimitIntervalSec=0', + ] + ) + create_unit_dropin( + 'systemd-udevd.service', + [ + '[Service]', + 'ExecStart=', + f'ExecStart=@{udevadm_bin} systemd-udevd', + ] + ) check_output('systemctl daemon-reload') print(check_output('systemctl cat systemd-networkd.service')) @@ -608,9 +608,9 @@ def clear_system_units(): rm_unit('systemd-networkd.service') rm_unit('systemd-networkd.socket') - rm_unit('systemd-networkd-varlink.socket') - rm_unit('systemd-networkd-resolve-hook.socket') rm_unit('systemd-networkd-persistent-storage.service') + rm_unit('systemd-networkd-resolve-hook.socket') + rm_unit('systemd-networkd-varlink.socket') rm_unit('systemd-resolved.service') rm_unit('systemd-timesyncd.service') rm_unit('systemd-udevd.service') @@ -995,13 +995,13 @@ def stop_networkd(show_logs=True, check_failed=True): if check_failed: check_output('systemctl stop systemd-networkd.socket') - check_output('systemctl stop systemd-networkd-varlink.socket') check_output('systemctl stop systemd-networkd-resolve-hook.socket') + check_output('systemctl stop systemd-networkd-varlink.socket') check_output('systemctl stop systemd-networkd.service') else: call('systemctl stop systemd-networkd.socket') - call('systemctl stop systemd-networkd-varlink.socket') call('systemctl stop systemd-networkd-resolve-hook.socket') + call('systemctl stop systemd-networkd-varlink.socket') call('systemctl stop systemd-networkd.service') if show_logs: diff --git a/units/meson.build b/units/meson.build index 113a935c90..8030675498 100644 --- a/units/meson.build +++ b/units/meson.build @@ -498,11 +498,11 @@ units = [ 'conditions' : ['ENABLE_NETWORKD'], }, { - 'file' : 'systemd-networkd-varlink.socket', + 'file' : 'systemd-networkd-resolve-hook.socket', 'conditions' : ['ENABLE_NETWORKD'], }, { - 'file' : 'systemd-networkd-resolve-hook.socket', + 'file' : 'systemd-networkd-varlink.socket', 'conditions' : ['ENABLE_NETWORKD'], }, { From 69f75cd896d6da74a5720b93398e6f5008412cc2 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 18 Feb 2026 17:53:35 +0900 Subject: [PATCH 2/3] network: use higher log level when we cannot bind resolve hook varlink socket --- src/network/networkd-resolve-hook.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/networkd-resolve-hook.c b/src/network/networkd-resolve-hook.c index bac5cd5cfe..0f733a3c42 100644 --- a/src/network/networkd-resolve-hook.c +++ b/src/network/networkd-resolve-hook.c @@ -245,7 +245,7 @@ int manager_varlink_init_resolve_hook(Manager *m, int fd) { r = sd_varlink_server_listen_address(s, "/run/systemd/resolve.hook/io.systemd.Network", 0666 | SD_VARLINK_SERVER_MODE_MKDIR_0755); if (ERRNO_IS_NEG_PRIVILEGE(r)) { - log_info_errno(r, "Failed to bind to systemd-resolved hook varlink socket, ignoring: %m"); + log_warning_errno(r, "Failed to bind to systemd-resolved hook varlink socket, ignoring: %m"); return 0; } } else From 23c639be6d4108af8e9be8bf88c8b27983f8a04b Mon Sep 17 00:00:00 2001 From: Yaping Li <202858510+YapingLi04@users.noreply.github.com> Date: Mon, 9 Feb 2026 17:08:01 -0800 Subject: [PATCH 3/3] metrics: add networkd related metrics --- src/network/meson.build | 1 + src/network/networkd-manager.c | 21 +- src/network/networkd-manager.h | 1 + src/network/networkd-varlink-metrics.c | 200 ++++++++++++++++++ src/network/networkd-varlink-metrics.h | 6 + test/networkd-test.py | 9 +- test/test-network/systemd-networkd-tests.py | 16 ++ test/units/TEST-74-AUX-UTILS.varlinkctl.sh | 6 + units/meson.build | 4 + units/systemd-networkd-varlink-metrics.socket | 25 +++ units/systemd-networkd.service.in | 4 +- 11 files changed, 286 insertions(+), 7 deletions(-) create mode 100644 src/network/networkd-varlink-metrics.c create mode 100644 src/network/networkd-varlink-metrics.h create mode 100644 units/systemd-networkd-varlink-metrics.socket diff --git a/src/network/meson.build b/src/network/meson.build index 4457e83644..89f3231c29 100644 --- a/src/network/meson.build +++ b/src/network/meson.build @@ -87,6 +87,7 @@ systemd_networkd_extract_sources = files( 'networkd-state-file.c', 'networkd-sysctl.c', 'networkd-util.c', + 'networkd-varlink-metrics.c', 'networkd-wifi.c', 'networkd-wiphy.c', 'networkd-wwan.c', diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index dbda6311d9..62e5271758 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -44,6 +44,7 @@ #include "networkd-serialize.h" #include "networkd-speed-meter.h" #include "networkd-state-file.h" +#include "networkd-varlink-metrics.h" #include "networkd-wifi.h" #include "networkd-wiphy.h" #include "networkd-wwan-bus.h" @@ -212,13 +213,14 @@ static int manager_connect_udev(Manager *m) { return 0; } -static int manager_listen_fds(Manager *m, int *ret_rtnl_fd, int *ret_varlink_fd, int *ret_resolve_hook_fd) { +static int manager_listen_fds(Manager *m, int *ret_rtnl_fd, int *ret_varlink_fd, int *ret_varlink_metrics_fd, int *ret_resolve_hook_fd) { _cleanup_strv_free_ char **names = NULL; - int n, rtnl_fd = -EBADF, varlink_fd = -EBADF, resolve_hook_fd = -EBADF; + int n, rtnl_fd = -EBADF, varlink_fd = -EBADF, varlink_metrics_fd = -EBADF, resolve_hook_fd = -EBADF; assert(m); assert(ret_rtnl_fd); assert(ret_varlink_fd); + assert(ret_varlink_metrics_fd); assert(ret_resolve_hook_fd); n = sd_listen_fds_with_names(/* unset_environment= */ true, &names); @@ -243,6 +245,11 @@ static int manager_listen_fds(Manager *m, int *ret_rtnl_fd, int *ret_varlink_fd, continue; } + if (streq(names[i], "varlink-metrics")) { + varlink_metrics_fd = fd; + continue; + } + if (streq(names[i], "resolve-hook")) { resolve_hook_fd = fd; continue; @@ -263,6 +270,7 @@ static int manager_listen_fds(Manager *m, int *ret_rtnl_fd, int *ret_varlink_fd, *ret_rtnl_fd = rtnl_fd; *ret_varlink_fd = varlink_fd; + *ret_varlink_metrics_fd = varlink_metrics_fd; *ret_resolve_hook_fd = resolve_hook_fd; return 0; @@ -557,7 +565,7 @@ static int manager_set_keep_configuration(Manager *m) { } int manager_setup(Manager *m) { - _cleanup_close_ int rtnl_fd = -EBADF, varlink_fd = -EBADF, resolve_hook_fd = -EBADF; + _cleanup_close_ int rtnl_fd = -EBADF, varlink_fd = -EBADF, varlink_metrics_fd = -EBADF, resolve_hook_fd = -EBADF; int r; assert(m); @@ -581,7 +589,7 @@ int manager_setup(Manager *m) { if (r < 0) return r; - r = manager_listen_fds(m, &rtnl_fd, &varlink_fd, &resolve_hook_fd); + r = manager_listen_fds(m, &rtnl_fd, &varlink_fd, &varlink_metrics_fd, &resolve_hook_fd); if (r < 0) return r; @@ -604,6 +612,10 @@ int manager_setup(Manager *m) { if (r < 0) return r; + r = manager_varlink_metrics_init(m, TAKE_FD(varlink_metrics_fd)); + if (r < 0) + return r; + r = manager_varlink_init_resolve_hook(m, TAKE_FD(resolve_hook_fd)); if (r < 0) return r; @@ -760,6 +772,7 @@ Manager* manager_free(Manager *m) { m->varlink_server = sd_varlink_server_unref(m->varlink_server); m->varlink_resolve_hook_server = sd_varlink_server_unref(m->varlink_resolve_hook_server); + m->varlink_metrics_server = sd_varlink_server_unref(m->varlink_metrics_server); m->query_filter_subscriptions = set_free(m->query_filter_subscriptions); hashmap_free(m->polkit_registry); sd_bus_flush_close_unref(m->bus); diff --git a/src/network/networkd-manager.h b/src/network/networkd-manager.h index 13467d963e..7b01401720 100644 --- a/src/network/networkd-manager.h +++ b/src/network/networkd-manager.h @@ -23,6 +23,7 @@ typedef struct Manager { sd_bus *bus; sd_varlink_server *varlink_server; sd_varlink_server *varlink_resolve_hook_server; + sd_varlink_server *varlink_metrics_server; Set *query_filter_subscriptions; sd_device_monitor *device_monitor; Hashmap *polkit_registry; diff --git a/src/network/networkd-varlink-metrics.c b/src/network/networkd-varlink-metrics.c new file mode 100644 index 0000000000..1853bfdb83 --- /dev/null +++ b/src/network/networkd-varlink-metrics.c @@ -0,0 +1,200 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "sd-varlink.h" + +#include "argv-util.h" +#include "errno-util.h" +#include "fd-util.h" +#include "hashmap.h" +#include "metrics.h" +#include "network-util.h" +#include "networkd-link.h" +#include "networkd-manager.h" +#include "networkd-varlink-metrics.h" + +#define METRIC_IO_SYSTEMD_NETWORK_PREFIX "io.systemd.Network." + +typedef const char* (*link_metric_extractor_t)(const Link *link); + +static int link_metric_build_json( + MetricFamilyContext *context, + link_metric_extractor_t extractor, + void *userdata) { + + Manager *manager = ASSERT_PTR(userdata); + Link *link; + int r; + + assert(context); + assert(extractor); + + HASHMAP_FOREACH(link, manager->links_by_index) { + r = metric_build_send_string(context, link->ifname, extractor(link), /* fields= */ NULL); + if (r < 0) + return r; + } + + return 0; +} + +static const char* link_get_address_state(const Link *l) { + return link_address_state_to_string(ASSERT_PTR(l)->address_state); +} + +static const char* link_get_admin_state(const Link *l) { + return link_state_to_string(ASSERT_PTR(l)->state); +} + +static const char* link_get_carrier_state(const Link *l) { + return link_carrier_state_to_string(ASSERT_PTR(l)->carrier_state); +} + +static const char* link_get_ipv4_address_state(const Link *l) { + return link_address_state_to_string(ASSERT_PTR(l)->ipv4_address_state); +} + +static const char* link_get_ipv6_address_state(const Link *l) { + return link_address_state_to_string(ASSERT_PTR(l)->ipv6_address_state); +} + +static const char* link_get_oper_state(const Link *l) { + return link_operstate_to_string(ASSERT_PTR(l)->operstate); +} + +static int link_address_state_build_json(MetricFamilyContext *ctx, void *userdata) { + return link_metric_build_json(ctx, link_get_address_state, userdata); +} + +static int link_admin_state_build_json(MetricFamilyContext *ctx, void *userdata) { + return link_metric_build_json(ctx, link_get_admin_state, userdata); +} + +static int link_carrier_state_build_json(MetricFamilyContext *ctx, void *userdata) { + return link_metric_build_json(ctx, link_get_carrier_state, userdata); +} + +static int link_ipv4_address_state_build_json(MetricFamilyContext *ctx, void *userdata) { + return link_metric_build_json(ctx, link_get_ipv4_address_state, userdata); +} + +static int link_ipv6_address_state_build_json(MetricFamilyContext *ctx, void *userdata) { + return link_metric_build_json(ctx, link_get_ipv6_address_state, userdata); +} + +static int link_oper_state_build_json(MetricFamilyContext *ctx, void *userdata) { + return link_metric_build_json(ctx, link_get_oper_state, userdata); +} + +static int managed_interfaces_build_json(MetricFamilyContext *context, void *userdata) { + Manager *manager = ASSERT_PTR(userdata); + Link *link; + uint64_t count = 0; + + assert(context); + + HASHMAP_FOREACH(link, manager->links_by_index) + if (link->network) + count++; + + return metric_build_send_unsigned(context, /* object= */ NULL, count, /* fields= */ NULL); +} + +/* Keep metrics ordered alphabetically */ +static const MetricFamily network_metric_family_table[] = { + { + .name = METRIC_IO_SYSTEMD_NETWORK_PREFIX "addressState", + .description = "Per interface metric: address state", + .type = METRIC_FAMILY_TYPE_STRING, + .generate = link_address_state_build_json, + }, + { + .name = METRIC_IO_SYSTEMD_NETWORK_PREFIX "adminState", + .description = "Per interface metric: admin state", + .type = METRIC_FAMILY_TYPE_STRING, + .generate = link_admin_state_build_json, + }, + { + .name = METRIC_IO_SYSTEMD_NETWORK_PREFIX "carrierState", + .description = "Per interface metric: carrier state", + .type = METRIC_FAMILY_TYPE_STRING, + .generate = link_carrier_state_build_json, + }, + { + .name = METRIC_IO_SYSTEMD_NETWORK_PREFIX "ipv4AddressState", + .description = "Per interface metric: IPv4 address state", + .type = METRIC_FAMILY_TYPE_STRING, + .generate = link_ipv4_address_state_build_json, + }, + { + .name = METRIC_IO_SYSTEMD_NETWORK_PREFIX "ipv6AddressState", + .description = "Per interface metric: IPv6 address state", + .type = METRIC_FAMILY_TYPE_STRING, + .generate = link_ipv6_address_state_build_json, + }, + { + .name = METRIC_IO_SYSTEMD_NETWORK_PREFIX "managedInterfaces", + .description = "Number of network interfaces managed by systemd-networkd", + .type = METRIC_FAMILY_TYPE_GAUGE, + .generate = managed_interfaces_build_json, + }, + { + .name = METRIC_IO_SYSTEMD_NETWORK_PREFIX "operationalState", + .description = "Per interface metric: operational state", + .type = METRIC_FAMILY_TYPE_STRING, + .generate = link_oper_state_build_json, + }, + {} +}; + +static int vl_method_metrics_describe(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) { + return metrics_method_describe(network_metric_family_table, link, parameters, flags, userdata); +} + +static int vl_method_metrics_list(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) { + return metrics_method_list(network_metric_family_table, link, parameters, flags, userdata); +} + +int manager_varlink_metrics_init(Manager *m, int fd) { + _unused_ _cleanup_close_ int fd_close = fd; /* take possession */ + int r; + + assert(m); + + if (m->varlink_metrics_server) + return 0; + + if (fd < 0 && invoked_by_systemd()) { + log_debug("systemd-networkd-varlink-metrics.socket seems to be disabled, not installing metrics varlink server."); + return 0; + } + + _cleanup_(sd_varlink_server_unrefp) sd_varlink_server *s = NULL; + r = metrics_setup_varlink_server( + &s, + SD_VARLINK_SERVER_INHERIT_USERDATA, + m->event, + SD_EVENT_PRIORITY_NORMAL, + vl_method_metrics_list, + vl_method_metrics_describe, + m); + if (r < 0) + return log_error_errno(r, "Failed to set up metrics varlink server: %m"); + + if (fd < 0) { + r = sd_varlink_server_listen_address( + s, + "/run/systemd/report/io.systemd.Network", + 0666 | SD_VARLINK_SERVER_MODE_MKDIR_0755); + if (ERRNO_IS_NEG_PRIVILEGE(r)) { + log_warning_errno(r, "Failed to bind to metrics varlink socket, ignoring: %m"); + return 0; + } + } else + r = sd_varlink_server_listen_fd(s, fd); + if (r < 0) + return log_error_errno(r, "Failed to bind to metrics varlink socket: %m"); + + TAKE_FD(fd_close); + m->varlink_metrics_server = TAKE_PTR(s); + return 0; +} diff --git a/src/network/networkd-varlink-metrics.h b/src/network/networkd-varlink-metrics.h new file mode 100644 index 0000000000..79335042d8 --- /dev/null +++ b/src/network/networkd-varlink-metrics.h @@ -0,0 +1,6 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include "networkd-forward.h" + +int manager_varlink_metrics_init(Manager *m, int fd); diff --git a/test/networkd-test.py b/test/networkd-test.py index 62041201ca..d9f7af3678 100755 --- a/test/networkd-test.py +++ b/test/networkd-test.py @@ -66,6 +66,7 @@ def setUpModule(): 'systemd-networkd.socket', 'systemd-networkd-resolve-hook.socket', 'systemd-networkd-varlink.socket', + 'systemd-networkd-varlink-metrics.socket', 'systemd-networkd.service', 'systemd-resolved-monitor.socket', 'systemd-resolved-varlink.socket', @@ -91,7 +92,8 @@ def setUpModule(): subprocess.call(['useradd', '--system', '--no-create-home', 'systemd-network']) for d in ['/etc/systemd/network', '/run/systemd/network', - '/run/systemd/netif', '/run/systemd/resolve', '/run/systemd/resolve.hook']: + '/run/systemd/netif', '/run/systemd/report', + '/run/systemd/resolve', '/run/systemd/resolve.hook']: subprocess.check_call(["mount", "-m", "-t", "tmpfs", "none", d]) tmpmounts.append(d) if os.path.isdir('/run/systemd/resolve'): @@ -281,6 +283,7 @@ Gateway=192.168.250.1 subprocess.check_call(['systemctl', 'stop', 'systemd-networkd.socket']) subprocess.check_call(['systemctl', 'stop', 'systemd-networkd-resolve-hook.socket']) subprocess.check_call(['systemctl', 'stop', 'systemd-networkd-varlink.socket']) + subprocess.check_call(['systemctl', 'stop', 'systemd-networkd-varlink-metrics.socket']) subprocess.check_call(['systemctl', 'stop', 'systemd-networkd.service']) subprocess.check_call(['ip', 'link', 'del', 'mybridge']) subprocess.check_call(['ip', 'link', 'del', 'port1']) @@ -378,6 +381,7 @@ class ClientTestBase(NetworkdTestingUtilities): subprocess.call(['systemctl', 'stop', 'systemd-networkd.socket']) subprocess.call(['systemctl', 'stop', 'systemd-networkd-resolve-hook.socket']) subprocess.call(['systemctl', 'stop', 'systemd-networkd-varlink.socket']) + subprocess.call(['systemctl', 'stop', 'systemd-networkd-varlink-metrics.socket']) subprocess.call(['systemctl', 'stop', 'systemd-networkd.service']) subprocess.call(['ip', 'link', 'del', 'dummy0'], stderr=subprocess.DEVNULL) @@ -935,10 +939,12 @@ class NetworkdClientTest(ClientTestBase, unittest.TestCase): set -eu mkdir -p /run/systemd/network mkdir -p /run/systemd/netif +mkdir -p /run/systemd/report mkdir -p /run/systemd/resolve.hook mkdir -p /var/lib/systemd/network mount -t tmpfs none /run/systemd/network mount -t tmpfs none /run/systemd/netif +mount -t tmpfs none /run/systemd/report mount -t tmpfs none /run/systemd/resolve.hook mount -t tmpfs none /var/lib/systemd/network [ ! -e /run/dbus ] || mount -t tmpfs none /run/dbus @@ -989,6 +995,7 @@ exec $(systemctl cat systemd-networkd.service | sed -n '/^ExecStart=/ {{ s/^.*=/ '-p', 'InaccessibleDirectories=-/etc/systemd/network', '-p', 'InaccessibleDirectories=-/run/systemd/network', '-p', 'InaccessibleDirectories=-/run/systemd/netif', + '-p', 'InaccessibleDirectories=-/run/systemd/report', '-p', 'InaccessibleDirectories=-/run/systemd/resolve.hook', '-p', 'InaccessibleDirectories=-/var/lib/systemd/network', '--service-type=notify', script]) diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index 93e3ee626f..bbbab8e3fe 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -427,6 +427,7 @@ def save_active_units(): 'systemd-networkd.socket', 'systemd-networkd-resolve-hook.socket', 'systemd-networkd-varlink.socket', + 'systemd-networkd-varlink-metrics.socket', 'systemd-networkd.service', 'systemd-resolved-monitor.socket', 'systemd-resolved-varlink.socket', @@ -455,6 +456,10 @@ def restore_active_units(): call('systemctl stop systemd-networkd-varlink.socket') has_network_socket = True + if 'systemd-networkd-varlink-metrics.socket' in active_units: + call('systemctl stop systemd-networkd-varlink-metrics.socket') + has_network_socket = True + if 'systemd-resolved-monitor.socket' in active_units: call('systemctl stop systemd-resolved-monitor.socket') has_resolve_socket = True @@ -524,6 +529,7 @@ def setup_system_units(): 'systemd-networkd-persistent-storage.service', 'systemd-networkd-resolve-hook.socket', 'systemd-networkd-varlink.socket', + 'systemd-networkd-varlink-metrics.socket', 'systemd-resolved.service', 'systemd-timesyncd.service', 'systemd-udevd.service', @@ -582,6 +588,13 @@ def setup_system_units(): 'StartLimitIntervalSec=0', ] ) + create_unit_dropin( + 'systemd-networkd-varlink-metrics.socket', + [ + '[Unit]', + 'StartLimitIntervalSec=0', + ] + ) create_unit_dropin( 'systemd-udevd.service', [ @@ -611,6 +624,7 @@ def clear_system_units(): rm_unit('systemd-networkd-persistent-storage.service') rm_unit('systemd-networkd-resolve-hook.socket') rm_unit('systemd-networkd-varlink.socket') + rm_unit('systemd-networkd-varlink-metrics.socket') rm_unit('systemd-resolved.service') rm_unit('systemd-timesyncd.service') rm_unit('systemd-udevd.service') @@ -997,11 +1011,13 @@ def stop_networkd(show_logs=True, check_failed=True): check_output('systemctl stop systemd-networkd.socket') check_output('systemctl stop systemd-networkd-resolve-hook.socket') check_output('systemctl stop systemd-networkd-varlink.socket') + check_output('systemctl stop systemd-networkd-varlink-metrics.socket') check_output('systemctl stop systemd-networkd.service') else: call('systemctl stop systemd-networkd.socket') call('systemctl stop systemd-networkd-resolve-hook.socket') call('systemctl stop systemd-networkd-varlink.socket') + call('systemctl stop systemd-networkd-varlink-metrics.socket') call('systemctl stop systemd-networkd.service') if show_logs: diff --git a/test/units/TEST-74-AUX-UTILS.varlinkctl.sh b/test/units/TEST-74-AUX-UTILS.varlinkctl.sh index 9d3e6a0bbc..377c4734e0 100755 --- a/test/units/TEST-74-AUX-UTILS.varlinkctl.sh +++ b/test/units/TEST-74-AUX-UTILS.varlinkctl.sh @@ -245,3 +245,9 @@ systemd-run --wait --pipe --user --machine testuser@ \ # test report systemd-report + +# test io.systemd.Network Metrics +varlinkctl info /run/systemd/report/io.systemd.Network +varlinkctl list-methods /run/systemd/report/io.systemd.Network +varlinkctl --more call /run/systemd/report/io.systemd.Network io.systemd.Metrics.List {} +varlinkctl --more call /run/systemd/report/io.systemd.Network io.systemd.Metrics.Describe {} diff --git a/units/meson.build b/units/meson.build index 8030675498..ebefaf87f0 100644 --- a/units/meson.build +++ b/units/meson.build @@ -505,6 +505,10 @@ units = [ 'file' : 'systemd-networkd-varlink.socket', 'conditions' : ['ENABLE_NETWORKD'], }, + { + 'file' : 'systemd-networkd-varlink-metrics.socket', + 'conditions' : ['ENABLE_NETWORKD'], + }, { 'file' : 'systemd-networkd-wait-online.service.in', 'conditions' : ['ENABLE_NETWORKD'], diff --git a/units/systemd-networkd-varlink-metrics.socket b/units/systemd-networkd-varlink-metrics.socket new file mode 100644 index 0000000000..562cc6b7f2 --- /dev/null +++ b/units/systemd-networkd-varlink-metrics.socket @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +[Unit] +Description=Network Management Metrics Varlink Socket +Documentation=man:systemd-networkd.service(8) +ConditionCapability=CAP_NET_ADMIN +DefaultDependencies=no +Before=sockets.target shutdown.target +Conflicts=shutdown.target + +[Socket] +ListenStream=/run/systemd/report/io.systemd.Network +FileDescriptorName=varlink-metrics +SocketMode=0666 +Service=systemd-networkd.service + +[Install] +WantedBy=sockets.target diff --git a/units/systemd-networkd.service.in b/units/systemd-networkd.service.in index 589782effc..17e7425f28 100644 --- a/units/systemd-networkd.service.in +++ b/units/systemd-networkd.service.in @@ -46,7 +46,7 @@ RestrictRealtime=yes RestrictSUIDSGID=yes RuntimeDirectory=systemd/netif RuntimeDirectoryPreserve=yes -Sockets=systemd-networkd.socket systemd-networkd-varlink.socket systemd-networkd-resolve-hook.socket +Sockets=systemd-networkd.socket systemd-networkd-varlink.socket systemd-networkd-varlink-metrics.socket systemd-networkd-resolve-hook.socket SystemCallArchitectures=native SystemCallErrorNumber=EPERM SystemCallFilter=@system-service bpf @@ -56,7 +56,7 @@ User=systemd-network [Install] WantedBy=multi-user.target -Also=systemd-networkd.socket systemd-networkd-varlink.socket systemd-networkd-resolve-hook.socket +Also=systemd-networkd.socket systemd-networkd-varlink.socket systemd-networkd-varlink-metrics.socket systemd-networkd-resolve-hook.socket Alias=dbus-org.freedesktop.network1.service # The output from this generator is used by udevd and networkd. Enable it by