'networkd-state-file.c',
'networkd-sysctl.c',
'networkd-util.c',
+ 'networkd-varlink-metrics.c',
'networkd-wifi.c',
'networkd-wiphy.c',
'networkd-wwan.c',
#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"
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);
continue;
}
+ if (streq(names[i], "varlink-metrics")) {
+ varlink_metrics_fd = fd;
+ continue;
+ }
+
if (streq(names[i], "resolve-hook")) {
resolve_hook_fd = fd;
continue;
*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;
}
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);
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;
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;
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);
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;
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include "networkd-forward.h"
+
+int manager_varlink_metrics_init(Manager *m, int fd);
'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',
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'):
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'])
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)
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
'-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])
'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',
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
'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',
'StartLimitIntervalSec=0',
]
)
+ create_unit_dropin(
+ 'systemd-networkd-varlink-metrics.socket',
+ [
+ '[Unit]',
+ 'StartLimitIntervalSec=0',
+ ]
+ )
create_unit_dropin(
'systemd-udevd.service',
[
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')
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:
# 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 {}
'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'],
--- /dev/null
+# 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
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
[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