]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
networkd: report per-interface addresses as io.systemd.Network.Address 42315/head
authorMichael Vogt <michael@amutable.com>
Tue, 26 May 2026 13:57:03 +0000 (15:57 +0200)
committerMichael Vogt <michael@amutable.com>
Sat, 20 Jun 2026 08:37:47 +0000 (10:37 +0200)
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"}}
```

src/network/networkd-varlink-metrics.c
test/units/TEST-74-AUX-UTILS.report.sh

index ee5645314cdd2a8048b3cb3523e8449ab1089da0..a52b74b0b031056d3fff43bbbaeed8b40acafab3 100644 (file)
@@ -1,18 +1,25 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
+#include <net/if.h>
+
 #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",
index 46f61b3b266f7e03644350c7c05c05cca3a975c7..06914fdc50324f7a7d1b1b662f494f8e8a921f27 100755 (executable)
@@ -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