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"}}
```
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user