/* 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."
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);
}
/* 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",
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