From: Michael Vogt Date: Tue, 26 May 2026 13:57:03 +0000 (+0200) Subject: networkd: report per-interface addresses as io.systemd.Network.Address X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F42315%2Fhead;p=thirdparty%2Fsystemd.git networkd: report per-interface addresses as io.systemd.Network.Address The networkd metrics interface already reports a lot of interesting metrics. With this commit it also report the network addresses too. Each ready address is emitted as one record per (interface, address) pair: - object: ifname - value: address in CIDR notation - fields: { family: "ipv4"|"ipv6", scope: "global"|"link"|"host"|... } The loopback addresses are not reported as its just noise. Example output: ``` root@localhost:~# varlinkctl --more --json=short call /run/systemd/report/io.systemd.Network io.systemd.Metrics.List '{}' {"name":"io.systemd.Network.Address","object":"enp0s1","value":"fe80::5054:ff:fe12:3456/64","fields":{"family":"ipv6","scope":"link"}} {"name":"io.systemd.Network.Address","object":"enp0s1","value":"fec0::5054:ff:fe12:3456/64","fields":{"family":"ipv6","scope":"site"}} {"name":"io.systemd.Network.Address","object":"enp0s1","value":"10.0.2.15/24","fields":{"family":"ipv4","scope":"global"}} ``` --- diff --git a/src/network/networkd-varlink-metrics.c b/src/network/networkd-varlink-metrics.c index ee5645314cd..a52b74b0b03 100644 --- a/src/network/networkd-varlink-metrics.c +++ b/src/network/networkd-varlink-metrics.c @@ -1,18 +1,25 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ +#include + #include "sd-json.h" #include "sd-varlink.h" +#include "af-list.h" #include "alloc-util.h" #include "argv-util.h" #include "errno-util.h" #include "fd-util.h" #include "hashmap.h" +#include "in-addr-util.h" #include "metrics.h" #include "network-util.h" +#include "networkd-address.h" #include "networkd-link.h" #include "networkd-manager.h" +#include "networkd-route-util.h" #include "networkd-varlink-metrics.h" +#include "set.h" #define METRIC_IO_SYSTEMD_NETWORK_PREFIX "io.systemd.Network." @@ -65,6 +72,52 @@ static const char* link_get_oper_state(const Link *l) { return link_operstate_to_string(ASSERT_PTR(l)->operstate); } +static int link_addresses_build_json(const MetricFamily *mf, sd_varlink *vl, void *userdata) { + Manager *manager = ASSERT_PTR(userdata); + Link *link; + int r; + + assert(mf && mf->name); + assert(vl); + + HASHMAP_FOREACH(link, manager->links_by_index) { + Address *a; + + SET_FOREACH(a, link->addresses) { + if (!address_is_ready(a)) + continue; + + /* Remove localhost address (127.0.0.1 and ::1) */ + if (link->flags & IFF_LOOPBACK && in_addr_is_localhost_one(a->family, &a->in_addr) > 0) + continue; + + _cleanup_free_ char *scope = NULL; + r = route_scope_to_string_alloc(a->scope, &scope); + if (r < 0) + return r; + + _cleanup_(sd_json_variant_unrefp) sd_json_variant *fields = NULL; + r = sd_json_buildo( + &fields, + SD_JSON_BUILD_PAIR_STRING("family", af_to_ipv4_ipv6(a->family)), + SD_JSON_BUILD_PAIR_STRING("scope", scope)); + if (r < 0) + return r; + + r = metric_build_send_string( + mf, + vl, + link->ifname, + IN_ADDR_PREFIX_TO_STRING(a->family, &a->in_addr, a->prefixlen), + fields); + if (r < 0) + return r; + } + } + + return 0; +} + static int link_address_state_build_json(const MetricFamily *mf, sd_varlink *vl, void *userdata) { return link_metric_build_json(mf, vl, link_get_address_state, userdata); } @@ -159,6 +212,12 @@ static int required_for_online_build_json(const MetricFamily *mf, sd_varlink *vl /* Keep metrics ordered alphabetically */ static const MetricFamily network_metric_family_table[] = { + { + .name = METRIC_IO_SYSTEMD_NETWORK_PREFIX "Address", + .description = "Per interface metric: configured IP address in CIDR notation", + .type = METRIC_FAMILY_TYPE_STRING, + .generate = link_addresses_build_json, + }, { .name = METRIC_IO_SYSTEMD_NETWORK_PREFIX "AddressState", .description = "Per interface metric: address state", diff --git a/test/units/TEST-74-AUX-UTILS.report.sh b/test/units/TEST-74-AUX-UTILS.report.sh index 46f61b3b266..06914fdc503 100755 --- a/test/units/TEST-74-AUX-UTILS.report.sh +++ b/test/units/TEST-74-AUX-UTILS.report.sh @@ -50,6 +50,17 @@ 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 {} +varlinkctl --more --json=short call /run/systemd/report/io.systemd.Network io.systemd.Metrics.Describe {} | grep '"name":"io.systemd.Network.Address"' >/dev/null +# we do not send "lo" +net_metrics="$(varlinkctl call --more --json=short /run/systemd/report/io.systemd.Network io.systemd.Metrics.List {})" +(! echo "$net_metrics" | grep '"name":"io.systemd.Network.Address"' | grep '"object":"lo"' >/dev/null) +# add a scratch address and check that it shows up. +ip address add 192.0.2.1/32 dev lo +timeout 30 bash -c 'until varlinkctl call --more --json=short /run/systemd/report/io.systemd.Network io.systemd.Metrics.List {} | grep -F "192.0.2.1/32" >/dev/null; do sleep .5; done' +net_metrics="$(varlinkctl call --more --json=short /run/systemd/report/io.systemd.Network io.systemd.Metrics.List {})" +echo "$net_metrics" | grep '"name":"io.systemd.Network.Address"' | grep '"object":"lo"' | grep '"value":"192.0.2.1/32"' | grep '"family":"ipv4"' >/dev/null +ip address del 192.0.2.1/32 dev lo + # test io.systemd.Basic Metrics # ensure the socket is running, as some distros don't enable it by default systemctl start systemd-report-basic.socket