networkctl: load information about DHCP client from varlink

By the previous commit, networkd now exposes the received DHCP message
in the Descibe() DBus/Varlink method. Let's make networkctl deserialize
the DHCP message and use it where necessary.
This commit is contained in:
Yu Watanabe
2026-05-16 08:05:01 +09:00
parent 29e221c9e6
commit c0e40b14ad
9 changed files with 150 additions and 55 deletions
+1
View File
@@ -131,6 +131,7 @@ networkctl_sources = files(
'networkctl-dump-util.c',
'networkctl-journal.c',
'networkctl-link-info.c',
'networkctl-link-info-json.c',
'networkctl-list.c',
'networkctl-lldp.c',
'networkctl-misc.c',
+12 -7
View File
@@ -5,6 +5,7 @@
#include "sd-netlink.h"
#include "alloc-util.h"
#include "dhcp-protocol.h"
#include "ether-addr-util.h"
#include "format-ifname.h"
#include "format-table.h"
@@ -210,13 +211,14 @@ int dump_gateways(sd_netlink *rtnl, sd_hwdb *hwdb, Table *table, int ifindex) {
int dump_addresses(
sd_netlink *rtnl,
sd_dhcp_message *message,
sd_dhcp_lease *lease,
Table *table,
int ifindex) {
_cleanup_free_ struct local_address *local_addrs = NULL;
_cleanup_strv_free_ char **buf = NULL;
struct in_addr dhcp4_address = {};
struct in_addr dhcp4_address = {}, server_address = {};
int r, n;
assert(rtnl);
@@ -226,15 +228,18 @@ int dump_addresses(
if (n <= 0)
return n;
if (lease)
if (message) {
dhcp4_address.s_addr = message->header.yiaddr;
if (dhcp_message_get_option_address(message, SD_DHCP_OPTION_SERVER_IDENTIFIER, &server_address) < 0)
/* The message should be BOOTP, let's fallback to the siaddr field. */
server_address.s_addr = message->header.siaddr;
} else if (lease) {
(void) sd_dhcp_lease_get_address(lease, &dhcp4_address);
(void) sd_dhcp_lease_get_server_identifier(lease, &server_address);
}
FOREACH_ARRAY(local, local_addrs, n) {
struct in_addr server_address;
bool dhcp4 = false;
if (local->family == AF_INET && in4_addr_equal(&local->address.in, &dhcp4_address))
dhcp4 = sd_dhcp_lease_get_server_identifier(lease, &server_address) >= 0;
bool dhcp4 = local->family == AF_INET && in4_addr_equal(&local->address.in, &dhcp4_address);
r = strv_extendf(&buf, "%s%s%s%s%s%s",
IN_ADDR_TO_STRING(local->family, &local->address),
+3 -1
View File
@@ -3,7 +3,9 @@
#include "shared-forward.h"
#include "dhcp-message.h"
int dump_list(Table *table, const char *key, char * const *l);
int ieee_oui(sd_hwdb *hwdb, const struct ether_addr *mac, char **ret);
int dump_gateways(sd_netlink *rtnl, sd_hwdb *hwdb, Table *table, int ifindex);
int dump_addresses(sd_netlink *rtnl, sd_dhcp_lease *lease, Table *table, int ifindex);
int dump_addresses(sd_netlink *rtnl, sd_dhcp_message *message, sd_dhcp_lease *lease, Table *table, int ifindex);
+92
View File
@@ -0,0 +1,92 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "sd-dhcp-client-id.h"
#include "sd-json.h"
#include "iovec-util.h"
#include "json-util.h"
#include "networkctl-link-info.h"
#include "networkctl-link-info-json.h"
#include "networkctl-util.h"
static int acquire_link_bitrates(LinkInfo *link) {
int r;
assert(link);
sd_json_variant *v;
r = json_variant_find_object(link->description, STRV_MAKE("Interface", "BitRates"), &v);
if (r == -ENODATA)
return 0;
if (r < 0)
return r;
static const sd_json_dispatch_field dispatch_table[] = {
{ "TxBitRate", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(LinkInfo, tx_bitrate), SD_JSON_MANDATORY },
{ "RxBitRate", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(LinkInfo, rx_bitrate), SD_JSON_MANDATORY },
{}
};
r = sd_json_dispatch(v, dispatch_table,
SD_JSON_LOG | SD_JSON_WARNING | SD_JSON_ALLOW_EXTENSIONS,
link);
if (r < 0)
return r;
link->has_bitrates = true;
return 0;
}
static int acquire_link_dhcp_client(LinkInfo *link) {
int r;
assert(link);
sd_json_variant *v;
r = json_variant_find_object(link->description, STRV_MAKE("Interface", "DHCPv4Client", "ClientIdentifier"), &v);
if (r == -ENODATA)
return 0;
if (r < 0)
return r;
_cleanup_(iovec_done) struct iovec iov = {};
r = json_dispatch_byte_array_iovec("ClientIdentifier", v, /* flags= */ 0, &iov);
if (r < 0)
return r;
return sd_dhcp_client_id_set_raw(&link->dhcp_client_id, iov.iov_base, iov.iov_len);
}
static int acquire_link_dhcp_message(LinkInfo *link) {
int r;
assert(link);
sd_json_variant *v;
r = json_variant_find_object(link->description, STRV_MAKE("Interface", "DHCPv4Client", "Lease", "Message"), &v);
if (r == -ENODATA)
return 0;
if (r < 0)
return r;
return dhcp_message_parse_json(v, &link->dhcp_message);
}
int link_info_parse_description(LinkInfo *link, sd_varlink *vl) {
int r;
assert(link);
if (!vl)
return 0;
r = acquire_link_description(vl, link->ifindex, &link->description);
if (r < 0)
return r;
(void) acquire_link_bitrates(link);
(void) acquire_link_dhcp_client(link);
(void) acquire_link_dhcp_message(link);
return 0;
}
+8
View File
@@ -0,0 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "shared-forward.h"
typedef struct LinkInfo LinkInfo;
int link_info_parse_description(LinkInfo *link, sd_varlink *vl);
+3 -32
View File
@@ -11,7 +11,7 @@
#include "glob-util.h"
#include "netlink-util.h"
#include "networkctl-link-info.h"
#include "networkctl-util.h"
#include "networkctl-link-info-json.h"
#include "sort-util.h"
#include "stdio-util.h"
#include "string-util.h"
@@ -26,6 +26,7 @@ LinkInfo* link_info_array_free(LinkInfo *array) {
for (unsigned i = 0; array && array[i].needs_freeing; i++) {
sd_device_unref(array[i].sd_device);
sd_json_variant_unref(array[i].description);
sd_dhcp_message_unref(array[i].dhcp_message);
free(array[i].netdev_kind);
free(array[i].ssid);
free(array[i].qdisc);
@@ -278,34 +279,6 @@ static int decode_link(
return 1;
}
static int acquire_link_bitrates(LinkInfo *link) {
int r;
assert(link);
sd_json_variant *v;
r = json_variant_find_object(link->description, STRV_MAKE("Interface", "BitRates"), &v);
if (r == -ENODATA)
return 0;
if (r < 0)
return r;
static const sd_json_dispatch_field dispatch_table[] = {
{ "TxBitRate", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(LinkInfo, tx_bitrate), SD_JSON_MANDATORY },
{ "RxBitRate", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(LinkInfo, rx_bitrate), SD_JSON_MANDATORY },
{}
};
r = sd_json_dispatch(v, dispatch_table,
SD_JSON_LOG | SD_JSON_WARNING | SD_JSON_ALLOW_EXTENSIONS,
link);
if (r < 0)
return r;
link->has_bitrates = true;
return 0;
}
static void acquire_ether_link_info(int *fd, LinkInfo *link) {
assert(fd);
assert(link);
@@ -398,9 +371,7 @@ int acquire_link_info(sd_varlink *vl, sd_netlink *rtnl, char * const *patterns,
acquire_ether_link_info(&fd, &links[c]);
acquire_wlan_link_info(&links[c]);
if (vl)
(void) acquire_link_description(vl, links[c].ifindex, &links[c].description);
(void) acquire_link_bitrates(&links[c]);
(void) link_info_parse_description(&links[c], vl);
c++;
}
+6
View File
@@ -5,6 +5,8 @@
#include <linux/if_link.h>
#include <linux/nl80211.h>
#include "dhcp-client-id-internal.h"
#include "dhcp-message.h"
#include "ether-addr-util.h"
#include "ethtool-util.h"
#include "shared-forward.h"
@@ -58,6 +60,10 @@ typedef struct LinkInfo {
uint64_t tx_bitrate;
uint64_t rx_bitrate;
/* DHCPv4 */
sd_dhcp_message *dhcp_message;
sd_dhcp_client_id dhcp_client_id;
/* bridge info */
uint32_t forward_delay;
uint32_t hello_time;
+24 -14
View File
@@ -3,6 +3,7 @@
#include "sd-device.h"
#include "sd-dhcp-client-id.h"
#include "sd-dhcp-lease.h"
#include "sd-dhcp-protocol.h"
#include "sd-hwdb.h"
#include "sd-netlink.h"
#include "sd-network.h"
@@ -779,7 +780,7 @@ static int link_status_one(
return r;
}
r = dump_addresses(rtnl, lease, table, info->ifindex);
r = dump_addresses(rtnl, info->dhcp_message, lease, table, info->ifindex);
if (r < 0)
return r;
@@ -837,8 +838,18 @@ static int link_status_one(
return table_log_add_error(r);
}
if (lease) {
const sd_dhcp_client_id *client_id;
if (info->dhcp_message) {
_cleanup_free_ char *tz = NULL;
if (dhcp_message_get_option_string(info->dhcp_message, SD_DHCP_OPTION_TZDB_TIMEZONE, &tz) >= 0
&& timezone_is_valid(tz, LOG_DEBUG)) {
r = table_add_many(table,
TABLE_FIELD, "Time Zone",
TABLE_STRING, tz);
if (r < 0)
return table_log_add_error(r);
}
} else if (lease) {
const char *tz;
r = sd_dhcp_lease_get_timezone(lease, &tz);
@@ -849,19 +860,18 @@ static int link_status_one(
if (r < 0)
return table_log_add_error(r);
}
}
r = sd_dhcp_lease_get_client_id(lease, &client_id);
if (sd_dhcp_client_id_is_set(&info->dhcp_client_id)) {
_cleanup_free_ char *id = NULL;
r = sd_dhcp_client_id_to_string(&info->dhcp_client_id, &id);
if (r >= 0) {
_cleanup_free_ char *id = NULL;
r = sd_dhcp_client_id_to_string(client_id, &id);
if (r >= 0) {
r = table_add_many(table,
TABLE_FIELD, "DHCPv4 Client ID",
TABLE_STRING, id);
if (r < 0)
return table_log_add_error(r);
}
r = table_add_many(table,
TABLE_FIELD, "DHCPv4 Client ID",
TABLE_STRING, id);
if (r < 0)
return table_log_add_error(r);
}
}
+1 -1
View File
@@ -94,7 +94,7 @@ int system_status(sd_netlink *rtnl, sd_hwdb *hwdb) {
if (r < 0)
return table_log_add_error(r);
r = dump_addresses(rtnl, NULL, table, 0);
r = dump_addresses(rtnl, /* message= */ NULL, /* lease= */ NULL, table, /* ifindex= */ 0);
if (r < 0)
return r;