]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
networkctl: load information about DHCP client from varlink 42122/head
authorYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 31 Mar 2026 22:56:09 +0000 (07:56 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 15 May 2026 23:05:01 +0000 (08:05 +0900)
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.

src/network/meson.build
src/network/networkctl-dump-util.c
src/network/networkctl-dump-util.h
src/network/networkctl-link-info-json.c [new file with mode: 0644]
src/network/networkctl-link-info-json.h [new file with mode: 0644]
src/network/networkctl-link-info.c
src/network/networkctl-link-info.h
src/network/networkctl-status-link.c
src/network/networkctl-status-system.c

index 134416bcc8dd82234e2223e6cb8091f5b1796448..7370d011d0a22c60af62061bc61e340dd8ef7980 100644 (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',
index 20d5e8f43cc00b6a5881dd867730834d4888c6cd..15fdb103b6d76d3df1e4b42021c8df1d9c248282 100644 (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),
index cfd0dd3de0122c4d3a6732620f83036e8f545022..2aafaae475670ab98c77ca9b901784d6af5b1ad8 100644 (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);
diff --git a/src/network/networkctl-link-info-json.c b/src/network/networkctl-link-info-json.c
new file mode 100644 (file)
index 0000000..b187432
--- /dev/null
@@ -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;
+}
diff --git a/src/network/networkctl-link-info-json.h b/src/network/networkctl-link-info-json.h
new file mode 100644 (file)
index 0000000..2b15e5b
--- /dev/null
@@ -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);
index 0b40b442537ac901d7068dbe4bd30ea0a61f9cae..789f2a00eedd4f937983076355b13374d2ce6d38 100644 (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++;
         }
index ebea57348a30da0ef26c01c23a81b74ce1b2e9f5..ae1bf716875107d8ca98b1b4cb6aeaa68899d9ab 100644 (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;
index 15c9c46336b3a1cb69a3a39706f2a40124413455..9543953df496dc42899d9187e56cd6bb6cc94cd9 100644 (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);
                 }
+        }
+
+        if (sd_dhcp_client_id_is_set(&info->dhcp_client_id)) {
+                _cleanup_free_ char *id = NULL;
 
-                r = sd_dhcp_lease_get_client_id(lease, &client_id);
+                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);
                 }
         }
 
index a03004b882aad40725a60380ee7ea3c7138c4e49..78dd77819dac239e48a8a2082f7fb8a2a452a8fd 100644 (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;