From f9ebd7bb0670ee2a8421ecbe2b4cf60dc28901c6 Mon Sep 17 00:00:00 2001 From: noxiouz Date: Sun, 22 Feb 2026 15:09:08 +0000 Subject: [PATCH 01/13] network: extract link_get_bit_rates() into networkd-speed-meter.c Move the bit-rate computation out of property_get_bit_rates() in networkd-link-bus.c into a standalone link_get_bit_rates() helper in networkd-speed-meter.c, which already owns the speed meter state. Co-developed-by: Claude Opus 4.6 --- src/network/networkd-link-bus.c | 23 ++------------------- src/network/networkd-speed-meter.c | 32 ++++++++++++++++++++++++++++++ src/network/networkd-speed-meter.h | 1 + 3 files changed, 35 insertions(+), 21 deletions(-) diff --git a/src/network/networkd-link-bus.c b/src/network/networkd-link-bus.c index 1b96fbdbd3..c411135a33 100644 --- a/src/network/networkd-link-bus.c +++ b/src/network/networkd-link-bus.c @@ -17,6 +17,7 @@ #include "networkd-link.h" #include "networkd-link-bus.h" #include "networkd-manager.h" +#include "networkd-speed-meter.h" #include "networkd-state-file.h" #include "ordered-set.h" #include "parse-util.h" @@ -42,32 +43,12 @@ static int property_get_bit_rates( sd_bus_error *error) { Link *link = ASSERT_PTR(userdata); - Manager *manager; - double interval_sec; uint64_t tx, rx; assert(bus); assert(reply); - manager = link->manager; - - if (!manager->use_speed_meter || - manager->speed_meter_usec_old == 0 || - !link->stats_updated) - return sd_bus_message_append(reply, "(tt)", UINT64_MAX, UINT64_MAX); - - assert(manager->speed_meter_usec_new > manager->speed_meter_usec_old); - interval_sec = (double) (manager->speed_meter_usec_new - manager->speed_meter_usec_old) / USEC_PER_SEC; - - if (link->stats_new.tx_bytes > link->stats_old.tx_bytes) - tx = (uint64_t) ((link->stats_new.tx_bytes - link->stats_old.tx_bytes) / interval_sec); - else - tx = (uint64_t) ((UINT64_MAX - (link->stats_old.tx_bytes - link->stats_new.tx_bytes)) / interval_sec); - - if (link->stats_new.rx_bytes > link->stats_old.rx_bytes) - rx = (uint64_t) ((link->stats_new.rx_bytes - link->stats_old.rx_bytes) / interval_sec); - else - rx = (uint64_t) ((UINT64_MAX - (link->stats_old.rx_bytes - link->stats_new.rx_bytes)) / interval_sec); + link_get_bit_rates(link, &tx, &rx); return sd_bus_message_append(reply, "(tt)", tx, rx); } diff --git a/src/network/networkd-speed-meter.c b/src/network/networkd-speed-meter.c index ade6c74331..f04b11be9c 100644 --- a/src/network/networkd-speed-meter.c +++ b/src/network/networkd-speed-meter.c @@ -86,6 +86,38 @@ static int speed_meter_handler(sd_event_source *s, uint64_t usec, void *userdata return 0; } +void link_get_bit_rates(Link *link, uint64_t *ret_tx, uint64_t *ret_rx) { + Manager *manager; + double interval_sec; + + assert(link); + assert(ret_tx); + assert(ret_rx); + + manager = link->manager; + + if (!manager->use_speed_meter || + manager->speed_meter_usec_old == 0 || + !link->stats_updated) { + *ret_tx = UINT64_MAX; + *ret_rx = UINT64_MAX; + return; + } + + assert(manager->speed_meter_usec_new > manager->speed_meter_usec_old); + interval_sec = (double) (manager->speed_meter_usec_new - manager->speed_meter_usec_old) / USEC_PER_SEC; + + if (link->stats_new.tx_bytes > link->stats_old.tx_bytes) + *ret_tx = (uint64_t) ((link->stats_new.tx_bytes - link->stats_old.tx_bytes) / interval_sec); + else + *ret_tx = (uint64_t) ((UINT64_MAX - (link->stats_old.tx_bytes - link->stats_new.tx_bytes)) / interval_sec); + + if (link->stats_new.rx_bytes > link->stats_old.rx_bytes) + *ret_rx = (uint64_t) ((link->stats_new.rx_bytes - link->stats_old.rx_bytes) / interval_sec); + else + *ret_rx = (uint64_t) ((UINT64_MAX - (link->stats_old.rx_bytes - link->stats_new.rx_bytes)) / interval_sec); +} + int manager_start_speed_meter(Manager *manager) { _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL; int r; diff --git a/src/network/networkd-speed-meter.h b/src/network/networkd-speed-meter.h index f7ef5a4569..8f98005322 100644 --- a/src/network/networkd-speed-meter.h +++ b/src/network/networkd-speed-meter.h @@ -9,4 +9,5 @@ #define SPEED_METER_DEFAULT_TIME_INTERVAL (10 * USEC_PER_SEC) #define SPEED_METER_MINIMUM_TIME_INTERVAL (100 * USEC_PER_MSEC) +void link_get_bit_rates(Link *link, uint64_t *ret_tx, uint64_t *ret_rx); int manager_start_speed_meter(Manager *m); From 872feaa006c9e6e7fa2e036dcbd09d9858470cfa Mon Sep 17 00:00:00 2001 From: noxiouz Date: Sun, 22 Feb 2026 15:09:56 +0000 Subject: [PATCH 02/13] network: add BitRates field to link_build_json() and the Varlink IDL Expose the speed meter transmit/receive rates as a BitRates struct in the per-link JSON output and the io.systemd.Network Varlink IDL. Co-developed-by: Claude Opus 4.6 --- src/network/networkd-json.c | 15 +++++++++++++++ src/shared/varlink-io.systemd.Network.c | 12 +++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/network/networkd-json.c b/src/network/networkd-json.c index de1a8829ee..d109fdc473 100644 --- a/src/network/networkd-json.c +++ b/src/network/networkd-json.c @@ -26,6 +26,7 @@ #include "networkd-route.h" #include "networkd-route-util.h" #include "networkd-routing-policy-rule.h" +#include "networkd-speed-meter.h" #include "networkd-wwan.h" #include "ordered-set.h" #include "set.h" @@ -1639,6 +1640,20 @@ int link_build_json(Link *link, sd_json_variant **ret) { if (r < 0) return r; + /* Append BitRates if speed meter is active */ + uint64_t tx, rx; + link_get_bit_rates(link, &tx, &rx); + if (tx != UINT64_MAX && rx != UINT64_MAX) { + r = sd_json_variant_merge_objectbo( + &v, + SD_JSON_BUILD_PAIR("BitRates", + SD_JSON_BUILD_OBJECT( + SD_JSON_BUILD_PAIR_UNSIGNED("TxBitRate", tx), + SD_JSON_BUILD_PAIR_UNSIGNED("RxBitRate", rx)))); + if (r < 0) + return r; + } + *ret = TAKE_PTR(v); return 0; } diff --git a/src/shared/varlink-io.systemd.Network.c b/src/shared/varlink-io.systemd.Network.c index 9ae737714f..47004fc959 100644 --- a/src/shared/varlink-io.systemd.Network.c +++ b/src/shared/varlink-io.systemd.Network.c @@ -411,6 +411,13 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE( SD_VARLINK_FIELD_COMMENT("Static DHCP leases configured for specific clients"), SD_VARLINK_DEFINE_FIELD_BY_TYPE(StaticLeases, DHCPServerLease, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE)); +static SD_VARLINK_DEFINE_STRUCT_TYPE( + BitRates, + SD_VARLINK_FIELD_COMMENT("Transmit bitrate in bits per second"), + SD_VARLINK_DEFINE_FIELD(TxBitRate, SD_VARLINK_INT, 0), + SD_VARLINK_FIELD_COMMENT("Receive bitrate in bits per second"), + SD_VARLINK_DEFINE_FIELD(RxBitRate, SD_VARLINK_INT, 0)); + static SD_VARLINK_DEFINE_STRUCT_TYPE( Interface, SD_VARLINK_FIELD_COMMENT("Network interface index"), @@ -533,7 +540,9 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE( SD_VARLINK_FIELD_COMMENT("DHCPv6 client configuration and lease information"), SD_VARLINK_DEFINE_FIELD_BY_TYPE(DHCPv6Client, DHCPv6Client, SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("LLDP transmit configuration for this interface"), - SD_VARLINK_DEFINE_FIELD_BY_TYPE(LLDP, LLDPNeighbor, SD_VARLINK_NULLABLE)); + SD_VARLINK_DEFINE_FIELD_BY_TYPE(LLDP, LLDPNeighbor, SD_VARLINK_NULLABLE), + SD_VARLINK_FIELD_COMMENT("Current transmit/receive bitrates from speed meter"), + SD_VARLINK_DEFINE_FIELD_BY_TYPE(BitRates, BitRates, SD_VARLINK_NULLABLE)); static SD_VARLINK_DEFINE_METHOD( Describe, @@ -604,6 +613,7 @@ SD_VARLINK_DEFINE_INTERFACE( &vl_method_GetLLDPNeighbors, &vl_method_SetPersistentStorage, &vl_type_Address, + &vl_type_BitRates, &vl_type_DHCPLease, &vl_type_DHCPServer, &vl_type_DHCPServerLease, From f8722d40335963dace358ef2bc77a5f9a8dc088d Mon Sep 17 00:00:00 2001 From: noxiouz Date: Sun, 22 Feb 2026 15:11:37 +0000 Subject: [PATCH 03/13] network: extend link_reconfigure_full() and manager_reload() for Varlink Add an sd_varlink* parameter to both functions so Varlink callers can receive a deferred reply once all async work completes, symmetrically with the existing sd_bus_message* path. Co-developed-by: Claude Opus 4.6 --- src/network/networkd-link-bus.c | 2 +- src/network/networkd-link.c | 35 ++++++++++++++++++++---------- src/network/networkd-link.h | 4 ++-- src/network/networkd-manager-bus.c | 2 +- src/network/networkd-manager.c | 13 +++++++---- src/network/networkd-manager.h | 2 +- 6 files changed, 37 insertions(+), 21 deletions(-) diff --git a/src/network/networkd-link-bus.c b/src/network/networkd-link-bus.c index c411135a33..a375d0c18b 100644 --- a/src/network/networkd-link-bus.c +++ b/src/network/networkd-link-bus.c @@ -653,7 +653,7 @@ int bus_link_method_reconfigure(sd_bus_message *message, void *userdata, sd_bus_ if (r == 0) return 1; /* Polkit will call us back */ - r = link_reconfigure_full(l, LINK_RECONFIGURE_UNCONDITIONALLY | LINK_RECONFIGURE_CLEANLY, message, /* counter= */ NULL); + r = link_reconfigure_full(l, LINK_RECONFIGURE_UNCONDITIONALLY | LINK_RECONFIGURE_CLEANLY, message, /* varlink= */ NULL, /* counter= */ NULL); if (r != 0) return r; /* Will reply later when r > 0. */ diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index c77b02b8e0..57b074e1be 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -18,6 +18,7 @@ #include "sd-ndisc.h" #include "sd-netlink.h" #include "sd-radv.h" +#include "sd-varlink.h" #include "alloc-util.h" #include "arphrd-util.h" @@ -1509,6 +1510,7 @@ typedef struct LinkReconfigurationData { Link *link; LinkReconfigurationFlag flags; sd_bus_message *message; + sd_varlink *varlink; unsigned *counter; } LinkReconfigurationData; @@ -1518,6 +1520,7 @@ static LinkReconfigurationData* link_reconfiguration_data_free(LinkReconfigurati link_unref(data->link); sd_bus_message_unref(data->message); + sd_varlink_unref(data->varlink); return mfree(data); } @@ -1528,24 +1531,30 @@ static void link_reconfiguration_data_destroy_callback(LinkReconfigurationData * int r; assert(data); + assert(!data->message || !data->varlink); /* D-Bus and Varlink callers are mutually exclusive */ - if (data->message) { - if (data->counter) { - assert(*data->counter > 0); - (*data->counter)--; - } + if (data->counter) { + assert(*data->counter > 0); + (*data->counter)--; + } - if (!data->counter || *data->counter <= 0) { - /* Update the state files before replying the bus method. Otherwise, - * systemd-networkd-wait-online following networkctl reload/reconfigure may read an - * outdated state file and wrongly handle an interface is already in the configured - * state. */ - (void) manager_clean_all(data->manager); + if (!data->counter || *data->counter == 0) { + /* Update the state files before replying. Otherwise, systemd-networkd-wait-online following + * networkctl reload/reconfigure may read an outdated state file and wrongly consider an + * interface already in the configured state. */ + (void) manager_clean_all(data->manager); + if (data->message) { r = sd_bus_reply_method_return(data->message, NULL); if (r < 0) log_warning_errno(r, "Failed to reply for DBus method, ignoring: %m"); } + + if (data->varlink) { + r = sd_varlink_reply(data->varlink, NULL); + if (r < 0) + log_warning_errno(r, "Failed to reply to Varlink request, ignoring: %m"); + } } link_reconfiguration_data_free(data); @@ -1568,7 +1577,7 @@ static int link_reconfigure_handler(sd_netlink *rtnl, sd_netlink_message *m, Lin return r; } -int link_reconfigure_full(Link *link, LinkReconfigurationFlag flags, sd_bus_message *message, unsigned *counter) { +int link_reconfigure_full(Link *link, LinkReconfigurationFlag flags, sd_bus_message *message, sd_varlink *varlink, unsigned *counter) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; _cleanup_(link_reconfiguration_data_freep) LinkReconfigurationData *data = NULL; int r; @@ -1576,6 +1585,7 @@ int link_reconfigure_full(Link *link, LinkReconfigurationFlag flags, sd_bus_mess assert(link); assert(link->manager); assert(link->manager->rtnl); + assert(!message || !varlink); /* D-Bus and Varlink callers are mutually exclusive */ /* When the link is in the pending or initialized state, link_reconfigure_impl() will be called later * by link_initialized() or link_initialized_and_synced(). To prevent the function from being called @@ -1594,6 +1604,7 @@ int link_reconfigure_full(Link *link, LinkReconfigurationFlag flags, sd_bus_mess .link = link_ref(link), .flags = flags, .message = sd_bus_message_ref(message), /* message may be NULL, but _ref() works fine. */ + .varlink = sd_varlink_ref(varlink), /* varlink may be NULL, but _ref() works fine. */ .counter = counter, }; diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 9c641fad39..33c2fd35a5 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -243,9 +243,9 @@ DECLARE_STRING_TABLE_LOOKUP(link_state, LinkState); int link_request_stacked_netdevs(Link *link, NetDevLocalAddressType type); int link_reconfigure_impl(Link *link, LinkReconfigurationFlag flags); -int link_reconfigure_full(Link *link, LinkReconfigurationFlag flags, sd_bus_message *message, unsigned *counter); +int link_reconfigure_full(Link *link, LinkReconfigurationFlag flags, sd_bus_message *message, sd_varlink *varlink, unsigned *counter); static inline int link_reconfigure(Link *link, LinkReconfigurationFlag flags) { - return link_reconfigure_full(link, flags, NULL, NULL); + return link_reconfigure_full(link, flags, NULL, NULL, NULL); } int link_check_initialized(Link *link); diff --git a/src/network/networkd-manager-bus.c b/src/network/networkd-manager-bus.c index a98561b25e..c335d34ff1 100644 --- a/src/network/networkd-manager-bus.c +++ b/src/network/networkd-manager-bus.c @@ -215,7 +215,7 @@ static int bus_method_reload(sd_bus_message *message, void *userdata, sd_bus_err if (r == 0) return 1; /* Polkit will call us back */ - r = manager_reload(manager, message); + r = manager_reload(manager, message, /* varlink= */ NULL); if (r < 0) return r; diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 62e5271758..66366fe60d 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -533,7 +533,7 @@ static int signal_restart_callback(sd_event_source *s, const struct signalfd_sig static int signal_reload_callback(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { Manager *m = ASSERT_PTR(userdata); - (void) manager_reload(m, /* message= */ NULL); + (void) manager_reload(m, /* message= */ NULL, /* varlink= */ NULL); return 0; } @@ -1257,11 +1257,12 @@ int manager_set_timezone(Manager *m, const char *tz) { return 0; } -int manager_reload(Manager *m, sd_bus_message *message) { +int manager_reload(Manager *m, sd_bus_message *message, sd_varlink *varlink) { Link *link; int r; assert(m); + assert(!message || !varlink); /* D-Bus and Varlink callers are mutually exclusive */ log_debug("Reloading..."); (void) notify_reloading(); @@ -1279,8 +1280,12 @@ int manager_reload(Manager *m, sd_bus_message *message) { } HASHMAP_FOREACH(link, m->links_by_index) - (void) link_reconfigure_full(link, /* flags= */ 0, message, - /* counter= */ message ? &m->reloading : NULL); + (void) link_reconfigure_full( + link, + /* flags= */ 0, + message, + varlink, + /* counter= */ (message || varlink) ? &m->reloading : NULL); log_debug("Reloaded."); r = 0; diff --git a/src/network/networkd-manager.h b/src/network/networkd-manager.h index 7b01401720..bacf3df444 100644 --- a/src/network/networkd-manager.h +++ b/src/network/networkd-manager.h @@ -151,7 +151,7 @@ int manager_enumerate(Manager *m); int manager_set_hostname(Manager *m, const char *hostname); int manager_set_timezone(Manager *m, const char *tz); -int manager_reload(Manager *m, sd_bus_message *message); +int manager_reload(Manager *m, sd_bus_message *message, sd_varlink *varlink); static inline Hashmap** manager_get_sysctl_shadow(Manager *manager) { #if ENABLE_SYSCTL_BPF From 5e7287c2b51cb1710652cc8d7226f51f67b17e98 Mon Sep 17 00:00:00 2001 From: noxiouz Date: Sun, 22 Feb 2026 15:24:14 +0000 Subject: [PATCH 04/13] network: add io.systemd.Network.Link.Renew() Varlink method The handler calls dhcp4_renew() and logs a warning on failure. Co-developed-by: Claude Opus 4.6 --- src/network/networkd-link-varlink.c | 28 ++++++++++++++++++++ src/network/networkd-link-varlink.h | 1 + src/network/networkd-manager-varlink.c | 1 + src/shared/varlink-io.systemd.Network.Link.c | 9 ++++++- 4 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/network/networkd-link-varlink.c b/src/network/networkd-link-varlink.c index ad7386dabf..c0abc8ef06 100644 --- a/src/network/networkd-link-varlink.c +++ b/src/network/networkd-link-varlink.c @@ -4,6 +4,7 @@ #include "bus-polkit.h" #include "json-util.h" +#include "networkd-dhcp4.h" #include "networkd-link.h" #include "networkd-link-varlink.h" #include "networkd-manager.h" @@ -100,3 +101,30 @@ int vl_method_link_up(sd_varlink *vlink, sd_json_variant *parameters, sd_varlink int vl_method_link_down(sd_varlink *vlink, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) { return vl_method_link_up_or_down(vlink, parameters, userdata, /* up= */ false); } + +int vl_method_link_renew(sd_varlink *vlink, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) { + Manager *manager = ASSERT_PTR(userdata); + Link *link; + int r; + + assert(vlink); + + r = dispatch_link(vlink, parameters, manager, DISPATCH_LINK_POLKIT | DISPATCH_LINK_MANDATORY, &link); + if (r != 0) + return r; + + r = varlink_verify_polkit_async( + vlink, + manager->bus, + "org.freedesktop.network1.renew", + /* details= */ NULL, + &manager->polkit_registry); + if (r <= 0) + return r; + + r = dhcp4_renew(link); + if (r < 0) + return log_link_warning_errno(link, r, "Failed to renew DHCPv4 lease: %m"); + + return sd_varlink_reply(vlink, NULL); +} diff --git a/src/network/networkd-link-varlink.h b/src/network/networkd-link-varlink.h index 60468519ca..0d0dd3ad25 100644 --- a/src/network/networkd-link-varlink.h +++ b/src/network/networkd-link-varlink.h @@ -12,3 +12,4 @@ int dispatch_link(sd_varlink *vlink, sd_json_variant *parameters, Manager *manag int vl_method_link_up(sd_varlink *vlink, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata); int vl_method_link_down(sd_varlink *vlink, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata); +int vl_method_link_renew(sd_varlink *vlink, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata); diff --git a/src/network/networkd-manager-varlink.c b/src/network/networkd-manager-varlink.c index 49bc82678d..9adfb0c2a5 100644 --- a/src/network/networkd-manager-varlink.c +++ b/src/network/networkd-manager-varlink.c @@ -273,6 +273,7 @@ int manager_varlink_init(Manager *m, int fd) { "io.systemd.Network.SetPersistentStorage", vl_method_set_persistent_storage, "io.systemd.Network.Link.Up", vl_method_link_up, "io.systemd.Network.Link.Down", vl_method_link_down, + "io.systemd.Network.Link.Renew", vl_method_link_renew, "io.systemd.service.Ping", varlink_method_ping, "io.systemd.service.SetLogLevel", varlink_method_set_log_level, "io.systemd.service.GetEnvironment", varlink_method_get_environment); diff --git a/src/shared/varlink-io.systemd.Network.Link.c b/src/shared/varlink-io.systemd.Network.Link.c index ccbb046ca0..338b2be123 100644 --- a/src/shared/varlink-io.systemd.Network.Link.c +++ b/src/shared/varlink-io.systemd.Network.Link.c @@ -19,10 +19,17 @@ static SD_VARLINK_DEFINE_METHOD( VARLINK_NETWORK_INTERFACE_INPUTS, VARLINK_DEFINE_POLKIT_INPUT); +static SD_VARLINK_DEFINE_METHOD( + Renew, + VARLINK_NETWORK_INTERFACE_INPUTS, + VARLINK_DEFINE_POLKIT_INPUT); + SD_VARLINK_DEFINE_INTERFACE( io_systemd_Network_Link, "io.systemd.Network.Link", SD_VARLINK_SYMBOL_COMMENT("Bring the specified link up."), &vl_method_Up, SD_VARLINK_SYMBOL_COMMENT("Bring the specified link down."), - &vl_method_Down); + &vl_method_Down, + SD_VARLINK_SYMBOL_COMMENT("Renew DHCP leases on the specified link."), + &vl_method_Renew); From 982a3fa59f696695651afd9c790029e4db7f7a01 Mon Sep 17 00:00:00 2001 From: noxiouz Date: Sun, 22 Feb 2026 15:25:07 +0000 Subject: [PATCH 05/13] network: add io.systemd.Network.Link.ForceRenew() Varlink method The handler calls sd_dhcp_server_forcerenew() if the server is running and logs a warning on failure. Co-developed-by: Claude Opus 4.6 --- src/network/networkd-link-varlink.c | 30 ++++++++++++++++++++ src/network/networkd-link-varlink.h | 1 + src/network/networkd-manager-varlink.c | 1 + src/shared/varlink-io.systemd.Network.Link.c | 9 +++++- 4 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/network/networkd-link-varlink.c b/src/network/networkd-link-varlink.c index c0abc8ef06..edb7f3aa84 100644 --- a/src/network/networkd-link-varlink.c +++ b/src/network/networkd-link-varlink.c @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ +#include "sd-dhcp-server.h" #include "sd-varlink.h" #include "bus-polkit.h" @@ -128,3 +129,32 @@ int vl_method_link_renew(sd_varlink *vlink, sd_json_variant *parameters, sd_varl return sd_varlink_reply(vlink, NULL); } + +int vl_method_link_force_renew(sd_varlink *vlink, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) { + Manager *manager = ASSERT_PTR(userdata); + Link *link; + int r; + + assert(vlink); + + r = dispatch_link(vlink, parameters, manager, DISPATCH_LINK_POLKIT | DISPATCH_LINK_MANDATORY, &link); + if (r != 0) + return r; + + r = varlink_verify_polkit_async( + vlink, + manager->bus, + "org.freedesktop.network1.forcerenew", + /* details= */ NULL, + &manager->polkit_registry); + if (r <= 0) + return r; + + if (sd_dhcp_server_is_running(link->dhcp_server)) { + r = sd_dhcp_server_forcerenew(link->dhcp_server); + if (r < 0) + return log_link_warning_errno(link, r, "Failed to force-renew DHCP server leases: %m"); + } + + return sd_varlink_reply(vlink, NULL); +} diff --git a/src/network/networkd-link-varlink.h b/src/network/networkd-link-varlink.h index 0d0dd3ad25..b318d5950d 100644 --- a/src/network/networkd-link-varlink.h +++ b/src/network/networkd-link-varlink.h @@ -13,3 +13,4 @@ int dispatch_link(sd_varlink *vlink, sd_json_variant *parameters, Manager *manag int vl_method_link_up(sd_varlink *vlink, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata); int vl_method_link_down(sd_varlink *vlink, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata); int vl_method_link_renew(sd_varlink *vlink, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata); +int vl_method_link_force_renew(sd_varlink *vlink, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata); diff --git a/src/network/networkd-manager-varlink.c b/src/network/networkd-manager-varlink.c index 9adfb0c2a5..4ee7f8e9a2 100644 --- a/src/network/networkd-manager-varlink.c +++ b/src/network/networkd-manager-varlink.c @@ -274,6 +274,7 @@ int manager_varlink_init(Manager *m, int fd) { "io.systemd.Network.Link.Up", vl_method_link_up, "io.systemd.Network.Link.Down", vl_method_link_down, "io.systemd.Network.Link.Renew", vl_method_link_renew, + "io.systemd.Network.Link.ForceRenew", vl_method_link_force_renew, "io.systemd.service.Ping", varlink_method_ping, "io.systemd.service.SetLogLevel", varlink_method_set_log_level, "io.systemd.service.GetEnvironment", varlink_method_get_environment); diff --git a/src/shared/varlink-io.systemd.Network.Link.c b/src/shared/varlink-io.systemd.Network.Link.c index 338b2be123..a42aab413f 100644 --- a/src/shared/varlink-io.systemd.Network.Link.c +++ b/src/shared/varlink-io.systemd.Network.Link.c @@ -24,6 +24,11 @@ static SD_VARLINK_DEFINE_METHOD( VARLINK_NETWORK_INTERFACE_INPUTS, VARLINK_DEFINE_POLKIT_INPUT); +static SD_VARLINK_DEFINE_METHOD( + ForceRenew, + VARLINK_NETWORK_INTERFACE_INPUTS, + VARLINK_DEFINE_POLKIT_INPUT); + SD_VARLINK_DEFINE_INTERFACE( io_systemd_Network_Link, "io.systemd.Network.Link", @@ -32,4 +37,6 @@ SD_VARLINK_DEFINE_INTERFACE( SD_VARLINK_SYMBOL_COMMENT("Bring the specified link down."), &vl_method_Down, SD_VARLINK_SYMBOL_COMMENT("Renew DHCP leases on the specified link."), - &vl_method_Renew); + &vl_method_Renew, + SD_VARLINK_SYMBOL_COMMENT("Force-renew DHCP server leases on the specified link."), + &vl_method_ForceRenew); From 506890fa0d537bf7714d1ad07d18b94d9c0f6f3d Mon Sep 17 00:00:00 2001 From: noxiouz Date: Sun, 22 Feb 2026 15:26:28 +0000 Subject: [PATCH 06/13] network: add io.systemd.Network.Link.Reconfigure() Varlink method The handler calls link_reconfigure_full() with UNCONDITIONALLY|CLEANLY flags and defers the Varlink reply until reconfiguration completes. Co-developed-by: Claude Opus 4.6 --- src/network/networkd-link-varlink.c | 33 ++++++++++++++++++++ src/network/networkd-link-varlink.h | 1 + src/network/networkd-manager-varlink.c | 1 + src/shared/varlink-io.systemd.Network.Link.c | 9 +++++- 4 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/network/networkd-link-varlink.c b/src/network/networkd-link-varlink.c index edb7f3aa84..2010553ead 100644 --- a/src/network/networkd-link-varlink.c +++ b/src/network/networkd-link-varlink.c @@ -158,3 +158,36 @@ int vl_method_link_force_renew(sd_varlink *vlink, sd_json_variant *parameters, s return sd_varlink_reply(vlink, NULL); } + +int vl_method_link_reconfigure(sd_varlink *vlink, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) { + Manager *manager = ASSERT_PTR(userdata); + Link *link; + int r; + + assert(vlink); + + r = dispatch_link(vlink, parameters, manager, DISPATCH_LINK_POLKIT | DISPATCH_LINK_MANDATORY, &link); + if (r != 0) + return r; + + r = varlink_verify_polkit_async( + vlink, + manager->bus, + "org.freedesktop.network1.reconfigure", + /* details= */ NULL, + &manager->polkit_registry); + if (r <= 0) + return r; + + r = link_reconfigure_full(link, + LINK_RECONFIGURE_UNCONDITIONALLY | LINK_RECONFIGURE_CLEANLY, + /* message= */ NULL, + /* varlink= */ vlink, + /* counter= */ NULL); + if (r < 0) + return log_link_warning_errno(link, r, "Failed to reconfigure link: %m"); + if (r > 0) + return 0; /* Reply will be sent asynchronously via vlink */ + + return sd_varlink_reply(vlink, NULL); +} diff --git a/src/network/networkd-link-varlink.h b/src/network/networkd-link-varlink.h index b318d5950d..b23b9717e3 100644 --- a/src/network/networkd-link-varlink.h +++ b/src/network/networkd-link-varlink.h @@ -14,3 +14,4 @@ int vl_method_link_up(sd_varlink *vlink, sd_json_variant *parameters, sd_varlink int vl_method_link_down(sd_varlink *vlink, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata); int vl_method_link_renew(sd_varlink *vlink, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata); int vl_method_link_force_renew(sd_varlink *vlink, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata); +int vl_method_link_reconfigure(sd_varlink *vlink, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata); diff --git a/src/network/networkd-manager-varlink.c b/src/network/networkd-manager-varlink.c index 4ee7f8e9a2..6660f03df1 100644 --- a/src/network/networkd-manager-varlink.c +++ b/src/network/networkd-manager-varlink.c @@ -275,6 +275,7 @@ int manager_varlink_init(Manager *m, int fd) { "io.systemd.Network.Link.Down", vl_method_link_down, "io.systemd.Network.Link.Renew", vl_method_link_renew, "io.systemd.Network.Link.ForceRenew", vl_method_link_force_renew, + "io.systemd.Network.Link.Reconfigure", vl_method_link_reconfigure, "io.systemd.service.Ping", varlink_method_ping, "io.systemd.service.SetLogLevel", varlink_method_set_log_level, "io.systemd.service.GetEnvironment", varlink_method_get_environment); diff --git a/src/shared/varlink-io.systemd.Network.Link.c b/src/shared/varlink-io.systemd.Network.Link.c index a42aab413f..43dd640be8 100644 --- a/src/shared/varlink-io.systemd.Network.Link.c +++ b/src/shared/varlink-io.systemd.Network.Link.c @@ -29,6 +29,11 @@ static SD_VARLINK_DEFINE_METHOD( VARLINK_NETWORK_INTERFACE_INPUTS, VARLINK_DEFINE_POLKIT_INPUT); +static SD_VARLINK_DEFINE_METHOD( + Reconfigure, + VARLINK_NETWORK_INTERFACE_INPUTS, + VARLINK_DEFINE_POLKIT_INPUT); + SD_VARLINK_DEFINE_INTERFACE( io_systemd_Network_Link, "io.systemd.Network.Link", @@ -39,4 +44,6 @@ SD_VARLINK_DEFINE_INTERFACE( SD_VARLINK_SYMBOL_COMMENT("Renew DHCP leases on the specified link."), &vl_method_Renew, SD_VARLINK_SYMBOL_COMMENT("Force-renew DHCP server leases on the specified link."), - &vl_method_ForceRenew); + &vl_method_ForceRenew, + SD_VARLINK_SYMBOL_COMMENT("Unconditionally reconfigure the specified link."), + &vl_method_Reconfigure); From dde311ba1496aedba4c43666c35fcec5620818f1 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 24 Feb 2026 21:46:07 +0900 Subject: [PATCH 07/13] networkctl: use new varlink methods Co-developed-by: Claude Opus 4.6 --- src/network/networkctl-misc.c | 76 ++++++++++------------------------- src/network/networkctl-misc.h | 3 +- src/network/networkctl.c | 32 +++++++-------- 3 files changed, 38 insertions(+), 73 deletions(-) diff --git a/src/network/networkctl-misc.c b/src/network/networkctl-misc.c index e130cdab4c..2596c14409 100644 --- a/src/network/networkctl-misc.c +++ b/src/network/networkctl-misc.c @@ -46,35 +46,6 @@ static int parse_interfaces(sd_netlink **rtnl, char *argv[], OrderedSet **ret) { return 0; } -int verb_link_up_down(int argc, char *argv[], uintptr_t _data, void *userdata) { - int r, ret = 0; - - bool up = streq_ptr(argv[0], "up"); - - _cleanup_ordered_set_free_ OrderedSet *indexes = NULL; - r = parse_interfaces(/* rtnl= */ NULL, argv, &indexes); - if (r < 0) - return r; - - _cleanup_(sd_varlink_flush_close_unrefp) sd_varlink *vl = NULL; - r = varlink_connect_networkd(&vl); - if (r < 0) - return r; - - (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL, arg_ask_password); - - void *p; - ORDERED_SET_FOREACH(p, indexes) - RET_GATHER(ret, varlink_callbo_and_log( - vl, - up ? "io.systemd.Network.Link.Up" : "io.systemd.Network.Link.Down", - /* reply= */ NULL, - SD_JSON_BUILD_PAIR_INTEGER("InterfaceIndex", PTR_TO_INT(p)), - SD_JSON_BUILD_PAIR_BOOLEAN("allowInteractiveAuthentication", arg_ask_password))); - - return ret; -} - int verb_link_delete(int argc, char *argv[], uintptr_t _data, void *userdata) { int r, ret = 0; @@ -104,25 +75,26 @@ int verb_link_delete(int argc, char *argv[], uintptr_t _data, void *userdata) { return ret; } -int verb_link_bus_simple_method(int argc, char *argv[], uintptr_t _data, void *userdata) { +int verb_link_varlink_simple_method(int argc, char *argv[], uintptr_t _data, void *userdata) { int r, ret = 0; - typedef struct LinkBusAction { + typedef struct LinkVarlinkAction { const char *verb; - const char *bus_method; - const char *error_message; - } LinkBusAction; + const char *method; + } LinkVarlinkAction; - static const LinkBusAction link_bus_action_table[] = { - { "renew", "RenewLink", "Failed to renew dynamic configuration of interface" }, - { "forcerenew", "ForceRenewLink", "Failed to forcibly renew dynamic configuration of interface" }, - { "reconfigure", "ReconfigureLink", "Failed to reconfigure network interface" }, + static const LinkVarlinkAction link_varlink_action_table[] = { + { "up", "io.systemd.Network.Link.Up", }, + { "down", "io.systemd.Network.Link.Down", }, + { "renew", "io.systemd.Network.Link.Renew", }, + { "forcerenew", "io.systemd.Network.Link.ForceRenew", }, + { "reconfigure", "io.systemd.Network.Link.Reconfigure", }, }; /* Common implementation for 'simple' method calls that just take an ifindex, and nothing else. */ - const LinkBusAction *a = NULL; - FOREACH_ELEMENT(i, link_bus_action_table) + const LinkVarlinkAction *a = NULL; + FOREACH_ELEMENT(i, link_varlink_action_table) if (streq(argv[0], i->verb)) { a = i; break; @@ -134,27 +106,21 @@ int verb_link_bus_simple_method(int argc, char *argv[], uintptr_t _data, void *u if (r < 0) return r; - _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; - r = acquire_bus(&bus); + _cleanup_(sd_varlink_flush_close_unrefp) sd_varlink *vl = NULL; + r = varlink_connect_networkd(&vl); if (r < 0) return r; (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL, arg_ask_password); void *p; - ORDERED_SET_FOREACH(p, indexes) { - _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - int index = PTR_TO_INT(p); - - r = bus_call_method(bus, bus_network_mgr, a->bus_method, &error, /* ret_reply= */ NULL, "i", index); - if (r < 0) { - RET_GATHER(ret, r); - log_error_errno(r, "%s %s: %s", - a->error_message, - FORMAT_IFNAME_FULL(index, FORMAT_IFNAME_IFINDEX), - bus_error_message(&error, r)); - } - } + ORDERED_SET_FOREACH(p, indexes) + RET_GATHER(ret, varlink_callbo_and_log( + vl, + a->method, + /* reply= */ NULL, + SD_JSON_BUILD_PAIR_INTEGER("InterfaceIndex", PTR_TO_INT(p)), + SD_JSON_BUILD_PAIR_BOOLEAN("allowInteractiveAuthentication", arg_ask_password))); return ret; } diff --git a/src/network/networkctl-misc.h b/src/network/networkctl-misc.h index 092177275d..771761d05f 100644 --- a/src/network/networkctl-misc.h +++ b/src/network/networkctl-misc.h @@ -3,8 +3,7 @@ #include "shared-forward.h" -int verb_link_up_down(int argc, char *argv[], uintptr_t _data, void *userdata); int verb_link_delete(int argc, char *argv[], uintptr_t _data, void *userdata); -int verb_link_bus_simple_method(int argc, char *argv[], uintptr_t _data, void *userdata); +int verb_link_varlink_simple_method(int argc, char *argv[], uintptr_t _data, void *userdata); int verb_reload(int argc, char *argv[], uintptr_t _data, void *userdata); int verb_persistent_storage(int argc, char *argv[], uintptr_t _data, void *userdata); diff --git a/src/network/networkctl.c b/src/network/networkctl.c index 91379cc930..7fe34ac1eb 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -223,22 +223,22 @@ static int parse_argv(int argc, char *argv[]) { static int networkctl_main(int argc, char *argv[]) { static const Verb verbs[] = { - { "list", VERB_ANY, VERB_ANY, VERB_DEFAULT|VERB_ONLINE_ONLY, verb_list_links }, - { "status", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, verb_link_status }, - { "lldp", VERB_ANY, VERB_ANY, 0, verb_link_lldp_status }, - { "label", 1, 1, 0, verb_list_address_labels }, - { "delete", 2, VERB_ANY, 0, verb_link_delete }, - { "up", 2, VERB_ANY, 0, verb_link_up_down }, - { "down", 2, VERB_ANY, 0, verb_link_up_down }, - { "renew", 2, VERB_ANY, VERB_ONLINE_ONLY, verb_link_bus_simple_method }, - { "forcerenew", 2, VERB_ANY, VERB_ONLINE_ONLY, verb_link_bus_simple_method }, - { "reconfigure", 2, VERB_ANY, VERB_ONLINE_ONLY, verb_link_bus_simple_method }, - { "reload", 1, 1, VERB_ONLINE_ONLY, verb_reload }, - { "edit", 2, VERB_ANY, 0, verb_edit }, - { "cat", 1, VERB_ANY, 0, verb_cat }, - { "mask", 2, VERB_ANY, 0, verb_mask }, - { "unmask", 2, VERB_ANY, 0, verb_unmask }, - { "persistent-storage", 2, 2, 0, verb_persistent_storage }, + { "list", VERB_ANY, VERB_ANY, VERB_DEFAULT|VERB_ONLINE_ONLY, verb_list_links }, + { "status", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, verb_link_status }, + { "lldp", VERB_ANY, VERB_ANY, 0, verb_link_lldp_status }, + { "label", 1, 1, 0, verb_list_address_labels }, + { "delete", 2, VERB_ANY, 0, verb_link_delete }, + { "up", 2, VERB_ANY, 0, verb_link_varlink_simple_method }, + { "down", 2, VERB_ANY, 0, verb_link_varlink_simple_method }, + { "renew", 2, VERB_ANY, VERB_ONLINE_ONLY, verb_link_varlink_simple_method }, + { "forcerenew", 2, VERB_ANY, VERB_ONLINE_ONLY, verb_link_varlink_simple_method }, + { "reconfigure", 2, VERB_ANY, VERB_ONLINE_ONLY, verb_link_varlink_simple_method }, + { "reload", 1, 1, VERB_ONLINE_ONLY, verb_reload }, + { "edit", 2, VERB_ANY, 0, verb_edit }, + { "cat", 1, VERB_ANY, 0, verb_cat }, + { "mask", 2, VERB_ANY, 0, verb_mask }, + { "unmask", 2, VERB_ANY, 0, verb_unmask }, + { "persistent-storage", 2, 2, 0, verb_persistent_storage }, {} }; From 6627dfe425e18d38c314c393f12ab43004ecce62 Mon Sep 17 00:00:00 2001 From: noxiouz Date: Sun, 22 Feb 2026 15:29:44 +0000 Subject: [PATCH 08/13] network: implement io.systemd.service.Reload() in networkd Bind networkd's reload handler to the generic io.systemd.service.Reload method. Co-developed-by: Claude Opus 4.6 --- src/network/networkd-manager-varlink.c | 33 +++++++++++++++++++++++++ src/shared/varlink-io.systemd.Network.c | 2 ++ 2 files changed, 35 insertions(+) diff --git a/src/network/networkd-manager-varlink.c b/src/network/networkd-manager-varlink.c index 6660f03df1..033dc87fbb 100644 --- a/src/network/networkd-manager-varlink.c +++ b/src/network/networkd-manager-varlink.c @@ -236,6 +236,38 @@ static int vl_method_set_persistent_storage(sd_varlink *vlink, sd_json_variant * return sd_varlink_reply(vlink, NULL); } +static int vl_method_reload(sd_varlink *vlink, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) { + Manager *m = ASSERT_PTR(userdata); + int r; + + assert(vlink); + + if (m->reloading > 0) + return sd_varlink_error(vlink, "io.systemd.Network.AlreadyReloading", NULL); + + r = sd_varlink_dispatch(vlink, parameters, dispatch_table_polkit_only, /* userdata= */ NULL); + if (r != 0) + return r; + + r = varlink_verify_polkit_async( + vlink, + m->bus, + "org.freedesktop.network1.reload", + /* details= */ NULL, + &m->polkit_registry); + if (r <= 0) + return r; + + r = manager_reload(m, /* message= */ NULL, vlink); + if (r < 0) + return log_error_errno(r, "Failed to reload: %m"); + + if (m->reloading > 0) + return 0; /* Reply will be sent asynchronously. */ + + return sd_varlink_reply(vlink, NULL); +} + int manager_varlink_init(Manager *m, int fd) { _cleanup_(sd_varlink_server_unrefp) sd_varlink_server *s = NULL; _unused_ _cleanup_close_ int fd_close = fd; /* take possession */ @@ -277,6 +309,7 @@ int manager_varlink_init(Manager *m, int fd) { "io.systemd.Network.Link.ForceRenew", vl_method_link_force_renew, "io.systemd.Network.Link.Reconfigure", vl_method_link_reconfigure, "io.systemd.service.Ping", varlink_method_ping, + "io.systemd.service.Reload", vl_method_reload, "io.systemd.service.SetLogLevel", varlink_method_set_log_level, "io.systemd.service.GetEnvironment", varlink_method_get_environment); if (r < 0) diff --git a/src/shared/varlink-io.systemd.Network.c b/src/shared/varlink-io.systemd.Network.c index 47004fc959..27b27c055c 100644 --- a/src/shared/varlink-io.systemd.Network.c +++ b/src/shared/varlink-io.systemd.Network.c @@ -602,6 +602,7 @@ static SD_VARLINK_DEFINE_METHOD( SD_VARLINK_FIELD_COMMENT("Whether persistent storage is ready and writable"), SD_VARLINK_DEFINE_INPUT(Ready, SD_VARLINK_BOOL, 0)); +static SD_VARLINK_DEFINE_ERROR(AlreadyReloading); static SD_VARLINK_DEFINE_ERROR(StorageReadOnly); SD_VARLINK_DEFINE_INTERFACE( @@ -641,4 +642,5 @@ SD_VARLINK_DEFINE_INTERFACE( &vl_type_Route, &vl_type_RoutingPolicyRule, &vl_type_SIP, + &vl_error_AlreadyReloading, &vl_error_StorageReadOnly); From 54e8ea6552fa707dcbe5aca0cf28b422eba0c5ef Mon Sep 17 00:00:00 2001 From: noxiouz Date: Sun, 22 Feb 2026 15:29:44 +0000 Subject: [PATCH 09/13] networkctl: use io.systemd.service.Reload() method Co-authored-by: Yu Watanabe Co-developed-by: Claude Opus 4.6 --- src/network/networkctl-config-file.c | 63 +++------------------------- src/network/networkctl-misc.c | 19 +-------- src/network/networkctl-util.c | 36 ++++++++++++++++ src/network/networkctl-util.h | 2 + 4 files changed, 44 insertions(+), 76 deletions(-) diff --git a/src/network/networkctl-config-file.c b/src/network/networkctl-config-file.c index 5674b630a4..43729c3765 100644 --- a/src/network/networkctl-config-file.c +++ b/src/network/networkctl-config-file.c @@ -2,17 +2,12 @@ #include -#include "sd-bus.h" #include "sd-daemon.h" #include "sd-device.h" #include "sd-netlink.h" #include "sd-network.h" #include "alloc-util.h" -#include "bus-error.h" -#include "bus-locator.h" -#include "bus-util.h" -#include "bus-wait-for-jobs.h" #include "conf-files.h" #include "edit-util.h" #include "errno-util.h" @@ -395,48 +390,8 @@ static int add_config_to_edit( return edit_files_add(context, dropin_path, old_dropin, comment_paths); } -static int udevd_reload(sd_bus *bus) { - _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; - _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL; - const char *job_path; - int r; - - assert(bus); - - r = bus_wait_for_jobs_new(bus, &w); - if (r < 0) - return log_error_errno(r, "Could not watch jobs: %m"); - - r = bus_call_method(bus, - bus_systemd_mgr, - "ReloadUnit", - &error, - &reply, - "ss", - "systemd-udevd.service", - "replace"); - if (r < 0) - return log_error_errno(r, "Failed to reload systemd-udevd: %s", bus_error_message(&error, r)); - - r = sd_bus_message_read(reply, "o", &job_path); - if (r < 0) - return bus_log_parse_error(r); - - r = bus_wait_for_jobs_one(w, job_path, /* flags= */ 0, NULL); - if (r == -ENOEXEC) { - log_debug("systemd-udevd is not running, skipping reload."); - return 0; - } - if (r < 0) - return log_error_errno(r, "Failed to reload systemd-udevd: %m"); - - return 1; -} - static int reload_daemons(ReloadFlags flags) { - _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; - int r, ret = 1; + int ret = 1; if (arg_no_reload) return 0; @@ -449,22 +404,14 @@ static int reload_daemons(ReloadFlags flags) { return 0; } - r = sd_bus_open_system(&bus); - if (r < 0) - return log_error_errno(r, "Failed to connect to system bus: %m"); - if (FLAGS_SET(flags, RELOAD_UDEVD)) - RET_GATHER(ret, udevd_reload(bus)); + RET_GATHER(ret, reload_udevd()); if (FLAGS_SET(flags, RELOAD_NETWORKD)) { - if (networkd_is_running()) { - _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - - r = bus_call_method(bus, bus_network_mgr, "Reload", &error, NULL, NULL); - if (r < 0) - RET_GATHER(ret, log_error_errno(r, "Failed to reload systemd-networkd: %s", bus_error_message(&error, r))); - } else + if (!networkd_is_running()) log_debug("systemd-networkd is not running, skipping reload."); + else + RET_GATHER(ret, reload_networkd()); } return ret; diff --git a/src/network/networkctl-misc.c b/src/network/networkctl-misc.c index 2596c14409..0436346bc8 100644 --- a/src/network/networkctl-misc.c +++ b/src/network/networkctl-misc.c @@ -1,10 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#include "sd-bus.h" #include "sd-netlink.h" -#include "bus-error.h" -#include "bus-locator.h" #include "bus-util.h" #include "errno-util.h" #include "fd-util.h" @@ -126,21 +123,7 @@ int verb_link_varlink_simple_method(int argc, char *argv[], uintptr_t _data, voi } int verb_reload(int argc, char *argv[], uintptr_t _data, void *userdata) { - _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; - _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - int r; - - r = acquire_bus(&bus); - if (r < 0) - return r; - - (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL, arg_ask_password); - - r = bus_call_method(bus, bus_network_mgr, "Reload", &error, NULL, NULL); - if (r < 0) - return log_error_errno(r, "Failed to reload network settings: %s", bus_error_message(&error, r)); - - return 0; + return reload_networkd(); } int verb_persistent_storage(int argc, char *argv[], uintptr_t _data, void *userdata) { diff --git a/src/network/networkctl-util.c b/src/network/networkctl-util.c index 00996e689f..b180dee0b6 100644 --- a/src/network/networkctl-util.c +++ b/src/network/networkctl-util.c @@ -7,9 +7,11 @@ #include "alloc-util.h" #include "ansi-color.h" +#include "bus-util.h" #include "log.h" #include "networkctl.h" #include "networkctl-util.h" +#include "polkit-agent.h" #include "stdio-util.h" #include "string-util.h" #include "strv.h" @@ -62,6 +64,40 @@ int varlink_connect_networkd(sd_varlink **ret_varlink) { return 0; } +int reload_networkd(void) { + _cleanup_(sd_varlink_flush_close_unrefp) sd_varlink *vl = NULL; + int r; + + r = varlink_connect_networkd(&vl); + if (r < 0) + return r; + + (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL, arg_ask_password); + + return varlink_callbo_and_log( + vl, + "io.systemd.service.Reload", + /* reply= */ NULL, + SD_JSON_BUILD_PAIR_BOOLEAN("allowInteractiveAuthentication", arg_ask_password)); +} + +int reload_udevd(void) { + _cleanup_(sd_varlink_flush_close_unrefp) sd_varlink *vl = NULL; + int r; + + r = sd_varlink_connect_address(&vl, "/run/udev/io.systemd.Udev"); + if (r == -ENOENT) { + log_debug("systemd-udevd is not running, skipping reload."); + return 0; + } + if (r < 0) + return log_error_errno(r, "Failed to connect to udev: %m"); + + (void) sd_varlink_set_description(vl, "udev"); + + return varlink_call_and_log(vl, "io.systemd.service.Reload", /* parameters= */ NULL, /* reply= */ NULL); +} + bool networkd_is_running(void) { static int cached = -1; int r; diff --git a/src/network/networkctl-util.h b/src/network/networkctl-util.h index b2721f5ea2..ee05ef6b10 100644 --- a/src/network/networkctl-util.h +++ b/src/network/networkctl-util.h @@ -4,6 +4,8 @@ #include "shared-forward.h" int varlink_connect_networkd(sd_varlink **ret_varlink); +int reload_networkd(void); +int reload_udevd(void); bool networkd_is_running(void); int acquire_bus(sd_bus **ret); int link_get_property( From e90ea94392b3a76595e8c876ef75618d38a049aa Mon Sep 17 00:00:00 2001 From: noxiouz Date: Sun, 22 Feb 2026 15:17:37 +0000 Subject: [PATCH 10/13] network: add io.systemd.Network.Link.Describe() Varlink method The handler returns the JSON produced by link_build_json(). Co-developed-by: Claude Opus 4.6 --- src/network/networkd-link-varlink.c | 22 +++++++++ src/network/networkd-link-varlink.h | 1 + src/network/networkd-manager-varlink.c | 1 + src/shared/varlink-io.systemd.Network.Link.c | 38 +++++++++++++++- src/shared/varlink-io.systemd.Network.c | 48 ++++++++++---------- src/shared/varlink-io.systemd.Network.h | 24 ++++++++++ 6 files changed, 109 insertions(+), 25 deletions(-) diff --git a/src/network/networkd-link-varlink.c b/src/network/networkd-link-varlink.c index 2010553ead..5864132ef8 100644 --- a/src/network/networkd-link-varlink.c +++ b/src/network/networkd-link-varlink.c @@ -6,6 +6,7 @@ #include "bus-polkit.h" #include "json-util.h" #include "networkd-dhcp4.h" +#include "networkd-json.h" #include "networkd-link.h" #include "networkd-link-varlink.h" #include "networkd-manager.h" @@ -67,6 +68,27 @@ int dispatch_link(sd_varlink *vlink, sd_json_variant *parameters, Manager *manag return 0; } +int vl_method_link_describe(sd_varlink *vlink, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) { + _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL; + Manager *manager = ASSERT_PTR(userdata); + Link *link; + int r; + + assert(vlink); + + r = dispatch_link(vlink, parameters, manager, DISPATCH_LINK_MANDATORY, &link); + if (r != 0) + return r; + + r = link_build_json(link, &v); + if (r < 0) + return log_link_error_errno(link, r, "Failed to format JSON data: %m"); + + return sd_varlink_replybo( + vlink, + SD_JSON_BUILD_PAIR_VARIANT("Interface", v)); +} + static int vl_method_link_up_or_down(sd_varlink *vlink, sd_json_variant *parameters, Manager *manager, bool up) { Link *link; int r; diff --git a/src/network/networkd-link-varlink.h b/src/network/networkd-link-varlink.h index b23b9717e3..7be68fee46 100644 --- a/src/network/networkd-link-varlink.h +++ b/src/network/networkd-link-varlink.h @@ -10,6 +10,7 @@ typedef enum DispatchLinkFlag { int dispatch_link(sd_varlink *vlink, sd_json_variant *parameters, Manager *manager, DispatchLinkFlag flags, Link **ret); +int vl_method_link_describe(sd_varlink *vlink, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata); int vl_method_link_up(sd_varlink *vlink, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata); int vl_method_link_down(sd_varlink *vlink, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata); int vl_method_link_renew(sd_varlink *vlink, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata); diff --git a/src/network/networkd-manager-varlink.c b/src/network/networkd-manager-varlink.c index 033dc87fbb..71ec695339 100644 --- a/src/network/networkd-manager-varlink.c +++ b/src/network/networkd-manager-varlink.c @@ -303,6 +303,7 @@ int manager_varlink_init(Manager *m, int fd) { "io.systemd.Network.GetNamespaceId", vl_method_get_namespace_id, "io.systemd.Network.GetLLDPNeighbors", vl_method_get_lldp_neighbors, "io.systemd.Network.SetPersistentStorage", vl_method_set_persistent_storage, + "io.systemd.Network.Link.Describe", vl_method_link_describe, "io.systemd.Network.Link.Up", vl_method_link_up, "io.systemd.Network.Link.Down", vl_method_link_down, "io.systemd.Network.Link.Renew", vl_method_link_renew, diff --git a/src/shared/varlink-io.systemd.Network.Link.c b/src/shared/varlink-io.systemd.Network.Link.c index 43dd640be8..5474e5e475 100644 --- a/src/shared/varlink-io.systemd.Network.Link.c +++ b/src/shared/varlink-io.systemd.Network.Link.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "bus-polkit.h" +#include "varlink-io.systemd.Network.h" #include "varlink-io.systemd.Network.Link.h" #define VARLINK_NETWORK_INTERFACE_INPUTS \ @@ -9,6 +10,12 @@ SD_VARLINK_FIELD_COMMENT("Name of the interface. If specified together with InterfaceIndex, both must reference the same link."), \ SD_VARLINK_DEFINE_INPUT(InterfaceName, SD_VARLINK_STRING, SD_VARLINK_NULLABLE) +static SD_VARLINK_DEFINE_METHOD( + Describe, + VARLINK_NETWORK_INTERFACE_INPUTS, + SD_VARLINK_FIELD_COMMENT("Interface description"), + SD_VARLINK_DEFINE_OUTPUT_BY_TYPE(Interface, Interface, 0)); + static SD_VARLINK_DEFINE_METHOD( Up, VARLINK_NETWORK_INTERFACE_INPUTS, @@ -46,4 +53,33 @@ SD_VARLINK_DEFINE_INTERFACE( SD_VARLINK_SYMBOL_COMMENT("Force-renew DHCP server leases on the specified link."), &vl_method_ForceRenew, SD_VARLINK_SYMBOL_COMMENT("Unconditionally reconfigure the specified link."), - &vl_method_Reconfigure); + &vl_method_Reconfigure, + SD_VARLINK_SYMBOL_COMMENT("Describe the specified link by index or name."), + &vl_method_Describe, + &vl_type_Address, + &vl_type_BitRates, + &vl_type_DHCPLease, + &vl_type_DHCPServer, + &vl_type_DHCPServerLease, + &vl_type_DHCPv6Client, + &vl_type_DHCPv6ClientPD, + &vl_type_DHCPv6ClientVendorOption, + &vl_type_DNS, + &vl_type_DNSSECNegativeTrustAnchor, + &vl_type_DNSSetting, + &vl_type_Domain, + &vl_type_Interface, + &vl_type_LinkState, + &vl_type_LinkAddressState, + &vl_type_LinkOnlineState, + &vl_type_LinkRequiredAddressFamily, + &vl_type_LLDPNeighbor, + &vl_type_NDisc, + &vl_type_Neighbor, + &vl_type_NextHop, + &vl_type_NextHopGroup, + &vl_type_NTP, + &vl_type_Pref64, + &vl_type_PrivateOption, + &vl_type_Route, + &vl_type_SIP); diff --git a/src/shared/varlink-io.systemd.Network.c b/src/shared/varlink-io.systemd.Network.c index 27b27c055c..e98d517cc7 100644 --- a/src/shared/varlink-io.systemd.Network.c +++ b/src/shared/varlink-io.systemd.Network.c @@ -9,7 +9,7 @@ SD_VARLINK_FIELD_COMMENT(comment " (human-readable format)"), \ SD_VARLINK_DEFINE_FIELD(field_name##String, SD_VARLINK_STRING, (flags)) -static SD_VARLINK_DEFINE_ENUM_TYPE( +SD_VARLINK_DEFINE_ENUM_TYPE( LinkState, SD_VARLINK_DEFINE_ENUM_VALUE(pending), SD_VARLINK_DEFINE_ENUM_VALUE(initialized), @@ -93,7 +93,7 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE( SD_VARLINK_FIELD_COMMENT("Configuration state of this rule"), SD_VARLINK_DEFINE_FIELD(ConfigState, SD_VARLINK_STRING, 0)); -static SD_VARLINK_DEFINE_STRUCT_TYPE( +SD_VARLINK_DEFINE_STRUCT_TYPE( Route, SD_VARLINK_FIELD_COMMENT("Address family (AF_INET or AF_INET6)"), SD_VARLINK_DEFINE_FIELD(Family, SD_VARLINK_INT, 0), @@ -149,14 +149,14 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE( SD_VARLINK_FIELD_COMMENT("TCP congestion control algorithm for this route"), SD_VARLINK_DEFINE_FIELD(TCPCongestionControlAlgorithm, SD_VARLINK_STRING, SD_VARLINK_NULLABLE)); -static SD_VARLINK_DEFINE_STRUCT_TYPE( +SD_VARLINK_DEFINE_STRUCT_TYPE( NextHopGroup, SD_VARLINK_FIELD_COMMENT("Next hop identifier in the multipath group"), SD_VARLINK_DEFINE_FIELD(ID, SD_VARLINK_INT, 0), SD_VARLINK_FIELD_COMMENT("Weight for load balancing (higher means more traffic)"), SD_VARLINK_DEFINE_FIELD(Weight, SD_VARLINK_INT, 0)); -static SD_VARLINK_DEFINE_STRUCT_TYPE( +SD_VARLINK_DEFINE_STRUCT_TYPE( NextHop, SD_VARLINK_FIELD_COMMENT("Next hop identifier"), SD_VARLINK_DEFINE_FIELD(ID, SD_VARLINK_INT, 0), @@ -181,7 +181,7 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE( SD_VARLINK_FIELD_COMMENT("Configuration state of this next hop"), SD_VARLINK_DEFINE_FIELD(ConfigState, SD_VARLINK_STRING, SD_VARLINK_NULLABLE)); -static SD_VARLINK_DEFINE_STRUCT_TYPE( +SD_VARLINK_DEFINE_STRUCT_TYPE( LLDPNeighbor, SD_VARLINK_FIELD_COMMENT("Chassis identifier in human-readable format"), SD_VARLINK_DEFINE_FIELD(ChassisID, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), @@ -204,7 +204,7 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE( SD_VARLINK_FIELD_COMMENT("VLAN identifier"), SD_VARLINK_DEFINE_FIELD(VlanID, SD_VARLINK_INT, SD_VARLINK_NULLABLE)); -static SD_VARLINK_DEFINE_STRUCT_TYPE( +SD_VARLINK_DEFINE_STRUCT_TYPE( DNS, SD_VARLINK_FIELD_COMMENT("Address family (AF_INET or AF_INET6)"), SD_VARLINK_DEFINE_FIELD(Family, SD_VARLINK_INT, 0), @@ -219,7 +219,7 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE( SD_VARLINK_DEFINE_FIELD(ConfigSource, SD_VARLINK_STRING, 0), VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(ConfigProvider, "Address of the configuration provider", SD_VARLINK_NULLABLE)); -static SD_VARLINK_DEFINE_STRUCT_TYPE( +SD_VARLINK_DEFINE_STRUCT_TYPE( NTP, SD_VARLINK_FIELD_COMMENT("Address family (AF_INET or AF_INET6) for address-based servers"), SD_VARLINK_DEFINE_FIELD(Family, SD_VARLINK_INT, SD_VARLINK_NULLABLE), @@ -230,7 +230,7 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE( SD_VARLINK_DEFINE_FIELD(ConfigSource, SD_VARLINK_STRING, 0), VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(ConfigProvider, "Address of the configuration provider", SD_VARLINK_NULLABLE)); -static SD_VARLINK_DEFINE_STRUCT_TYPE( +SD_VARLINK_DEFINE_STRUCT_TYPE( SIP, SD_VARLINK_FIELD_COMMENT("Address family (AF_INET or AF_INET6) for address-based servers"), SD_VARLINK_DEFINE_FIELD(Family, SD_VARLINK_INT, SD_VARLINK_NULLABLE), @@ -241,7 +241,7 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE( SD_VARLINK_DEFINE_FIELD(ConfigSource, SD_VARLINK_STRING, 0), VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(ConfigProvider, "Address of the configuration provider", SD_VARLINK_NULLABLE)); -static SD_VARLINK_DEFINE_STRUCT_TYPE( +SD_VARLINK_DEFINE_STRUCT_TYPE( Domain, SD_VARLINK_FIELD_COMMENT("DNS search or route domain name"), SD_VARLINK_DEFINE_FIELD(Domain, SD_VARLINK_STRING, 0), @@ -249,14 +249,14 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE( SD_VARLINK_DEFINE_FIELD(ConfigSource, SD_VARLINK_STRING, 0), VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(ConfigProvider, "Address of the configuration provider", SD_VARLINK_NULLABLE)); -static SD_VARLINK_DEFINE_STRUCT_TYPE( +SD_VARLINK_DEFINE_STRUCT_TYPE( DNSSECNegativeTrustAnchor, SD_VARLINK_FIELD_COMMENT("Domain name for which DNSSEC validation is disabled"), SD_VARLINK_DEFINE_FIELD(DNSSECNegativeTrustAnchor, SD_VARLINK_STRING, 0), SD_VARLINK_FIELD_COMMENT("Configuration source for this negative trust anchor"), SD_VARLINK_DEFINE_FIELD(ConfigSource, SD_VARLINK_STRING, 0)); -static SD_VARLINK_DEFINE_STRUCT_TYPE( +SD_VARLINK_DEFINE_STRUCT_TYPE( DNSSetting, SD_VARLINK_FIELD_COMMENT("Link-Local Multicast Name Resolution setting"), SD_VARLINK_DEFINE_FIELD(LLMNR, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), @@ -269,7 +269,7 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE( SD_VARLINK_FIELD_COMMENT("Configuration source for this DNS setting"), SD_VARLINK_DEFINE_FIELD(ConfigSource, SD_VARLINK_STRING, 0)); -static SD_VARLINK_DEFINE_STRUCT_TYPE( +SD_VARLINK_DEFINE_STRUCT_TYPE( Pref64, SD_VARLINK_FIELD_COMMENT("IPv6 prefix for NAT64/DNS64"), SD_VARLINK_DEFINE_FIELD(Prefix, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE), @@ -281,12 +281,12 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE( SD_VARLINK_DEFINE_FIELD(LifetimeUSec, SD_VARLINK_INT, SD_VARLINK_NULLABLE), VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(ConfigProvider, "Address of router that provided this prefix", SD_VARLINK_NULLABLE)); -static SD_VARLINK_DEFINE_STRUCT_TYPE( +SD_VARLINK_DEFINE_STRUCT_TYPE( NDisc, SD_VARLINK_FIELD_COMMENT("PREF64 (RFC8781) prefixes advertised via IPv6 Router Advertisements"), SD_VARLINK_DEFINE_FIELD_BY_TYPE(PREF64, Pref64, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE)); -static SD_VARLINK_DEFINE_STRUCT_TYPE( +SD_VARLINK_DEFINE_STRUCT_TYPE( Address, SD_VARLINK_FIELD_COMMENT("Address family (AF_INET or AF_INET6)"), SD_VARLINK_DEFINE_FIELD(Family, SD_VARLINK_INT, 0), @@ -319,7 +319,7 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE( SD_VARLINK_FIELD_COMMENT("Configuration state of this address"), SD_VARLINK_DEFINE_FIELD(ConfigState, SD_VARLINK_STRING, SD_VARLINK_NULLABLE)); -static SD_VARLINK_DEFINE_STRUCT_TYPE( +SD_VARLINK_DEFINE_STRUCT_TYPE( Neighbor, SD_VARLINK_FIELD_COMMENT("Address family (AF_INET or AF_INET6)"), SD_VARLINK_DEFINE_FIELD(Family, SD_VARLINK_INT, 0), @@ -331,7 +331,7 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE( SD_VARLINK_FIELD_COMMENT("Configuration state of this neighbor entry"), SD_VARLINK_DEFINE_FIELD(ConfigState, SD_VARLINK_STRING, 0)); -static SD_VARLINK_DEFINE_STRUCT_TYPE( +SD_VARLINK_DEFINE_STRUCT_TYPE( DHCPLease, SD_VARLINK_FIELD_COMMENT("Timestamp when the lease was acquired in microseconds"), SD_VARLINK_DEFINE_FIELD(LeaseTimestampUSec, SD_VARLINK_INT, SD_VARLINK_NULLABLE), @@ -342,14 +342,14 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE( SD_VARLINK_FIELD_COMMENT("Hostname received from DHCP server"), SD_VARLINK_DEFINE_FIELD(Hostname, SD_VARLINK_STRING, SD_VARLINK_NULLABLE)); -static SD_VARLINK_DEFINE_STRUCT_TYPE( +SD_VARLINK_DEFINE_STRUCT_TYPE( PrivateOption, SD_VARLINK_FIELD_COMMENT("DHCP option number"), SD_VARLINK_DEFINE_FIELD(Option, SD_VARLINK_INT, SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("Raw data of the private DHCP option"), SD_VARLINK_DEFINE_FIELD(PrivateOptionData, SD_VARLINK_STRING, SD_VARLINK_NULLABLE)); -static SD_VARLINK_DEFINE_STRUCT_TYPE( +SD_VARLINK_DEFINE_STRUCT_TYPE( DHCPv6ClientPD, SD_VARLINK_FIELD_COMMENT("Delegated IPv6 prefix"), SD_VARLINK_DEFINE_FIELD(Prefix, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE), @@ -362,7 +362,7 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE( SD_VARLINK_FIELD_COMMENT("Valid lifetime of the prefix in microseconds"), SD_VARLINK_DEFINE_FIELD(ValidLifetimeUSec, SD_VARLINK_INT, SD_VARLINK_NULLABLE)); -static SD_VARLINK_DEFINE_STRUCT_TYPE( +SD_VARLINK_DEFINE_STRUCT_TYPE( DHCPv6ClientVendorOption, SD_VARLINK_FIELD_COMMENT("IANA enterprise number identifying the vendor"), SD_VARLINK_DEFINE_FIELD(EnterpriseId, SD_VARLINK_INT, 0), @@ -371,7 +371,7 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE( SD_VARLINK_FIELD_COMMENT("Raw data of the vendor-specific sub-option"), SD_VARLINK_DEFINE_FIELD(SubOptionData, SD_VARLINK_STRING, 0)); -static SD_VARLINK_DEFINE_STRUCT_TYPE( +SD_VARLINK_DEFINE_STRUCT_TYPE( DHCPv6Client, SD_VARLINK_FIELD_COMMENT("DHCPv6 lease information including timestamps and timeouts"), SD_VARLINK_DEFINE_FIELD_BY_TYPE(Lease, DHCPLease, SD_VARLINK_NULLABLE), @@ -382,7 +382,7 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE( SD_VARLINK_FIELD_COMMENT("DHCP Unique Identifier (DUID) of the client"), SD_VARLINK_DEFINE_FIELD(DUID, SD_VARLINK_INT, SD_VARLINK_ARRAY)); -static SD_VARLINK_DEFINE_STRUCT_TYPE( +SD_VARLINK_DEFINE_STRUCT_TYPE( DHCPServerLease, SD_VARLINK_FIELD_COMMENT("DHCP client identifier"), SD_VARLINK_DEFINE_FIELD(ClientId, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE), @@ -400,7 +400,7 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE( SD_VARLINK_FIELD_COMMENT("Lease expiration time in realtime microseconds"), SD_VARLINK_DEFINE_FIELD(ExpirationRealtimeUSec, SD_VARLINK_INT, SD_VARLINK_NULLABLE)); -static SD_VARLINK_DEFINE_STRUCT_TYPE( +SD_VARLINK_DEFINE_STRUCT_TYPE( DHCPServer, SD_VARLINK_FIELD_COMMENT("Offset from the network address for the DHCP address pool"), SD_VARLINK_DEFINE_FIELD(PoolOffset, SD_VARLINK_INT, 0), @@ -411,14 +411,14 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE( SD_VARLINK_FIELD_COMMENT("Static DHCP leases configured for specific clients"), SD_VARLINK_DEFINE_FIELD_BY_TYPE(StaticLeases, DHCPServerLease, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE)); -static SD_VARLINK_DEFINE_STRUCT_TYPE( +SD_VARLINK_DEFINE_STRUCT_TYPE( BitRates, SD_VARLINK_FIELD_COMMENT("Transmit bitrate in bits per second"), SD_VARLINK_DEFINE_FIELD(TxBitRate, SD_VARLINK_INT, 0), SD_VARLINK_FIELD_COMMENT("Receive bitrate in bits per second"), SD_VARLINK_DEFINE_FIELD(RxBitRate, SD_VARLINK_INT, 0)); -static SD_VARLINK_DEFINE_STRUCT_TYPE( +SD_VARLINK_DEFINE_STRUCT_TYPE( Interface, SD_VARLINK_FIELD_COMMENT("Network interface index"), SD_VARLINK_DEFINE_FIELD(Index, SD_VARLINK_INT, 0), diff --git a/src/shared/varlink-io.systemd.Network.h b/src/shared/varlink-io.systemd.Network.h index 6d727cd9ee..25d3bc9600 100644 --- a/src/shared/varlink-io.systemd.Network.h +++ b/src/shared/varlink-io.systemd.Network.h @@ -7,3 +7,27 @@ extern const sd_varlink_interface vl_interface_io_systemd_Network; extern const sd_varlink_symbol vl_type_LinkAddressState; extern const sd_varlink_symbol vl_type_LinkOnlineState; extern const sd_varlink_symbol vl_type_LinkRequiredAddressFamily; +extern const sd_varlink_symbol vl_type_LinkState; +extern const sd_varlink_symbol vl_type_Route; +extern const sd_varlink_symbol vl_type_NextHopGroup; +extern const sd_varlink_symbol vl_type_NextHop; +extern const sd_varlink_symbol vl_type_LLDPNeighbor; +extern const sd_varlink_symbol vl_type_DNS; +extern const sd_varlink_symbol vl_type_NTP; +extern const sd_varlink_symbol vl_type_SIP; +extern const sd_varlink_symbol vl_type_Domain; +extern const sd_varlink_symbol vl_type_DNSSECNegativeTrustAnchor; +extern const sd_varlink_symbol vl_type_DNSSetting; +extern const sd_varlink_symbol vl_type_Pref64; +extern const sd_varlink_symbol vl_type_NDisc; +extern const sd_varlink_symbol vl_type_Address; +extern const sd_varlink_symbol vl_type_Neighbor; +extern const sd_varlink_symbol vl_type_DHCPLease; +extern const sd_varlink_symbol vl_type_PrivateOption; +extern const sd_varlink_symbol vl_type_DHCPv6ClientPD; +extern const sd_varlink_symbol vl_type_DHCPv6ClientVendorOption; +extern const sd_varlink_symbol vl_type_DHCPv6Client; +extern const sd_varlink_symbol vl_type_DHCPServerLease; +extern const sd_varlink_symbol vl_type_DHCPServer; +extern const sd_varlink_symbol vl_type_BitRates; +extern const sd_varlink_symbol vl_type_Interface; From 689e45a6cd71d3b2b260a473e3e627ae4fa0e012 Mon Sep 17 00:00:00 2001 From: noxiouz Date: Sun, 22 Feb 2026 15:17:37 +0000 Subject: [PATCH 11/13] networkctl: use io.systemd.Network.Link.Describe() Varlink method This makes networkctl fetch bit-rate statistics and offered DHCP leases via Link.Describe() method instead of D-Bus. Co-authored-by: Yu Watanabe Co-developed-by: Claude Opus 4.6 --- src/network/networkctl-link-info.c | 52 ++++++------ src/network/networkctl-link-info.h | 3 +- src/network/networkctl-status-link.c | 119 +++++++++------------------ src/network/networkctl-util.c | 37 +++++++++ src/network/networkctl-util.h | 3 + 5 files changed, 107 insertions(+), 107 deletions(-) diff --git a/src/network/networkctl-link-info.c b/src/network/networkctl-link-info.c index 8f072f834a..05990bffbc 100644 --- a/src/network/networkctl-link-info.c +++ b/src/network/networkctl-link-info.c @@ -2,13 +2,10 @@ #include -#include "sd-bus.h" #include "sd-netlink.h" +#include "sd-json.h" #include "alloc-util.h" -#include "bus-common-errors.h" -#include "bus-error.h" -#include "bus-util.h" #include "device-util.h" #include "fd-util.h" #include "glob-util.h" @@ -28,6 +25,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); free(array[i].netdev_kind); free(array[i].ssid); free(array[i].qdisc); @@ -280,33 +278,31 @@ static int decode_link( return 1; } -static int acquire_link_bitrates(sd_bus *bus, LinkInfo *link) { - _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; - _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; +static int acquire_link_bitrates(LinkInfo *link) { int r; - assert(bus); assert(link); - r = link_get_property(bus, link->ifindex, &error, &reply, "org.freedesktop.network1.Link", "BitRates", "(tt)"); - if (r < 0) { - bool quiet = sd_bus_error_has_names(&error, SD_BUS_ERROR_UNKNOWN_PROPERTY, - BUS_ERROR_SPEED_METER_INACTIVE); - - return log_full_errno(quiet ? LOG_DEBUG : LOG_WARNING, - r, "Failed to query link bit rates: %s", bus_error_message(&error, r)); - } - - r = sd_bus_message_read(reply, "(tt)", &link->tx_bitrate, &link->rx_bitrate); + 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 bus_log_parse_error(r); + return r; - r = sd_bus_message_exit_container(reply); + 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 bus_log_parse_error(r); - - link->has_bitrates = link->tx_bitrate != UINT64_MAX && link->rx_bitrate != UINT64_MAX; + return r; + link->has_bitrates = true; return 0; } @@ -356,7 +352,7 @@ static void acquire_wlan_link_info(LinkInfo *link) { link->has_wlan_link_info = r > 0 || k > 0; } -int acquire_link_info(sd_bus *bus, sd_netlink *rtnl, char * const *patterns, LinkInfo **ret) { +int acquire_link_info(sd_varlink *vl, sd_netlink *rtnl, char * const *patterns, LinkInfo **ret) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; _cleanup_(link_info_array_freep) LinkInfo *links = NULL; _cleanup_free_ bool *matched_patterns = NULL; @@ -402,6 +398,10 @@ int acquire_link_info(sd_bus *bus, sd_netlink *rtnl, char * const *patterns, Lin 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]); + c++; } @@ -421,10 +421,6 @@ int acquire_link_info(sd_bus *bus, sd_netlink *rtnl, char * const *patterns, Lin typesafe_qsort(links, c, link_info_compare); - if (bus) - FOREACH_ARRAY(link, links, c) - (void) acquire_link_bitrates(bus, link); - *ret = TAKE_PTR(links); if (patterns && c == 0) diff --git a/src/network/networkctl-link-info.h b/src/network/networkctl-link-info.h index 268798dc7f..ebea57348a 100644 --- a/src/network/networkctl-link-info.h +++ b/src/network/networkctl-link-info.h @@ -35,6 +35,7 @@ typedef struct LinkInfo { char name[IFNAMSIZ+1]; char *netdev_kind; sd_device *sd_device; + sd_json_variant *description; int ifindex; unsigned short iftype; struct hw_addr_data hw_address; @@ -133,4 +134,4 @@ typedef struct LinkInfo { LinkInfo* link_info_array_free(LinkInfo *array); DEFINE_TRIVIAL_CLEANUP_FUNC(LinkInfo*, link_info_array_free); -int acquire_link_info(sd_bus *bus, sd_netlink *rtnl, char * const *patterns, LinkInfo **ret); +int acquire_link_info(sd_varlink *vl, sd_netlink *rtnl, char * const *patterns, LinkInfo **ret); diff --git a/src/network/networkctl-status-link.c b/src/network/networkctl-status-link.c index b73fceb91a..f63ee2d417 100644 --- a/src/network/networkctl-status-link.c +++ b/src/network/networkctl-status-link.c @@ -1,6 +1,5 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#include "sd-bus.h" #include "sd-device.h" #include "sd-dhcp-client-id.h" #include "sd-dhcp-lease.h" @@ -12,8 +11,6 @@ #include "alloc-util.h" #include "bond-util.h" #include "bridge-util.h" -#include "bus-error.h" -#include "bus-util.h" #include "errno-util.h" #include "escape.h" #include "extract-word.h" @@ -21,7 +18,9 @@ #include "format-util.h" #include "geneve-util.h" #include "glyph-util.h" +#include "iovec-util.h" #include "ipvlan-util.h" +#include "json-util.h" #include "macvlan-util.h" #include "netif-util.h" #include "network-internal.h" @@ -40,87 +39,58 @@ #include "time-util.h" #include "udev-util.h" -static int dump_dhcp_leases(Table *table, const char *prefix, sd_bus *bus, const LinkInfo *link) { +typedef struct LeaseInfo { + const char *address; + struct iovec client_id; +} LeaseInfo; + +static void lease_info_done(LeaseInfo *p) { + assert(p); + + iovec_done(&p->client_id); +} + +static int dump_dhcp_leases(Table *table, const char *prefix, const LinkInfo *link) { _cleanup_strv_free_ char **buf = NULL; - _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; - _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; assert(table); assert(prefix); - assert(bus); assert(link); - r = link_get_property(bus, link->ifindex, &error, &reply, "org.freedesktop.network1.DHCPServer", "Leases", "a(uayayayayt)"); - if (r < 0) { - bool quiet = sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_PROPERTY); - - log_full_errno(quiet ? LOG_DEBUG : LOG_WARNING, - r, "Failed to query link DHCP leases: %s", bus_error_message(&error, r)); + sd_json_variant *leases; + r = json_variant_find_object(link->description, STRV_MAKE("Interface", "DHCPServer", "Leases"), &leases); + if (r == -ENODATA) return 0; - } - - r = sd_bus_message_enter_container(reply, 'a', "(uayayayayt)"); if (r < 0) - return bus_log_parse_error(r); + return r; - while ((r = sd_bus_message_enter_container(reply, 'r', "uayayayayt")) > 0) { - _cleanup_free_ char *id = NULL, *ip = NULL; - const void *client_id, *addr, *gtw, *hwaddr; - size_t client_id_sz, sz; - uint64_t expiration; - uint32_t family; + static const sd_json_dispatch_field dispatch_table[] = { + { "AddressString", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(LeaseInfo, address), SD_JSON_MANDATORY }, + { "ClientId", SD_JSON_VARIANT_ARRAY, json_dispatch_byte_array_iovec, offsetof(LeaseInfo, client_id), 0 }, + {} + }; - r = sd_bus_message_read(reply, "u", &family); + sd_json_variant *lease; + JSON_VARIANT_ARRAY_FOREACH(lease, leases) { + _cleanup_(lease_info_done) LeaseInfo info = {}; + _cleanup_free_ char *client_id = NULL; + + r = sd_json_dispatch(lease, dispatch_table, SD_JSON_LOG | SD_JSON_WARNING | SD_JSON_ALLOW_EXTENSIONS, &info); if (r < 0) - return bus_log_parse_error(r); + continue; - r = sd_bus_message_read_array(reply, 'y', &client_id, &client_id_sz); - if (r < 0) - return bus_log_parse_error(r); + if (info.client_id.iov_len > 0) + (void) sd_dhcp_client_id_to_string_from_raw(info.client_id.iov_base, info.client_id.iov_len, &client_id); - r = sd_bus_message_read_array(reply, 'y', &addr, &sz); - if (r < 0 || sz != 4) - return bus_log_parse_error(r); - - r = sd_bus_message_read_array(reply, 'y', >w, &sz); - if (r < 0 || sz != 4) - return bus_log_parse_error(r); - - r = sd_bus_message_read_array(reply, 'y', &hwaddr, &sz); - if (r < 0) - return bus_log_parse_error(r); - - r = sd_bus_message_read_basic(reply, 't', &expiration); - if (r < 0) - return bus_log_parse_error(r); - - r = sd_dhcp_client_id_to_string_from_raw(client_id, client_id_sz, &id); - if (r < 0) - return bus_log_parse_error(r); - - r = in_addr_to_string(family, addr, &ip); - if (r < 0) - return bus_log_parse_error(r); - - r = strv_extendf(&buf, "%s (to %s)", ip, id); + r = strv_extendf(&buf, "%s%s%s%s", + info.address, + client_id ? " (to " : "", + strempty(client_id), + client_id ? ")" : ""); if (r < 0) return log_oom(); - - r = sd_bus_message_exit_container(reply); - if (r < 0) - return bus_log_parse_error(r); } - if (r < 0) - return bus_log_parse_error(r); - - r = sd_bus_message_exit_container(reply); - if (r < 0) - return bus_log_parse_error(r); - - r = sd_bus_message_exit_container(reply); - if (r < 0) - return bus_log_parse_error(r); if (strv_isempty(buf)) { r = strv_extendf(&buf, "none"); @@ -259,7 +229,6 @@ static int format_config_files(char ***files, const char *main_config) { } static int link_status_one( - sd_bus *bus, sd_netlink *rtnl, sd_hwdb *hwdb, sd_varlink *vl, @@ -276,7 +245,6 @@ static int link_status_one( _cleanup_(table_unrefp) Table *table = NULL; int r; - assert(bus); assert(rtnl); assert(vl); assert(info); @@ -919,7 +887,7 @@ static int link_status_one( if (r < 0) return r; - r = dump_dhcp_leases(table, "Offered DHCP leases", bus, info); + r = dump_dhcp_leases(table, "Offered DHCP leases", info); if (r < 0) return r; @@ -940,7 +908,6 @@ static int link_status_one( } int verb_link_status(int argc, char *argv[], uintptr_t _data, void *userdata) { - _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; _cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL; _cleanup_(sd_varlink_flush_close_unrefp) sd_varlink *vl = NULL; @@ -951,10 +918,6 @@ int verb_link_status(int argc, char *argv[], uintptr_t _data, void *userdata) { if (r != 0) return r; - r = acquire_bus(&bus); - if (r < 0) - return r; - pager_open(arg_pager_flags); r = sd_netlink_open(&rtnl); @@ -970,11 +933,11 @@ int verb_link_status(int argc, char *argv[], uintptr_t _data, void *userdata) { return r; if (arg_all) - c = acquire_link_info(bus, rtnl, NULL, &links); + c = acquire_link_info(vl, rtnl, NULL, &links); else if (argc <= 1) return system_status(rtnl, hwdb); else - c = acquire_link_info(bus, rtnl, argv + 1, &links); + c = acquire_link_info(vl, rtnl, argv + 1, &links); if (c < 0) return c; @@ -985,7 +948,7 @@ int verb_link_status(int argc, char *argv[], uintptr_t _data, void *userdata) { if (!first) putchar('\n'); - RET_GATHER(r, link_status_one(bus, rtnl, hwdb, vl, i)); + RET_GATHER(r, link_status_one(rtnl, hwdb, vl, i)); first = false; } diff --git a/src/network/networkctl-util.c b/src/network/networkctl-util.c index b180dee0b6..6c1db351ae 100644 --- a/src/network/networkctl-util.c +++ b/src/network/networkctl-util.c @@ -232,3 +232,40 @@ void online_state_to_color(const char *state, const char **on, const char **off) *off = ""; } } + +int acquire_link_description(sd_varlink *vl, int ifindex, sd_json_variant **ret) { + int r; + + assert(vl); + assert(ifindex > 0); + assert(ret); + + sd_json_variant *v; /* borrowed from vl, do not unref */ + r = varlink_callbo_and_log( + vl, + "io.systemd.Network.Link.Describe", + &v, + SD_JSON_BUILD_PAIR_INTEGER("InterfaceIndex", ifindex)); + if (r < 0) + return r; + + *ret = sd_json_variant_ref(v); + return 0; +} + +int json_variant_find_object(sd_json_variant *v, char * const *object_names, sd_json_variant **ret) { + assert(object_names); + assert(ret); + + if (!v || sd_json_variant_is_null(v)) + return -ENODATA; + + STRV_FOREACH(name, object_names) { + v = sd_json_variant_by_key(v, *name); + if (!v || sd_json_variant_is_null(v)) + return -ENODATA; + } + + *ret = v; + return 0; +} diff --git a/src/network/networkctl-util.h b/src/network/networkctl-util.h index ee05ef6b10..df4ef40347 100644 --- a/src/network/networkctl-util.h +++ b/src/network/networkctl-util.h @@ -20,3 +20,6 @@ int link_get_property( void operational_state_to_color(const char *name, const char *state, const char **on, const char **off); void setup_state_to_color(const char *state, const char **on, const char **off); void online_state_to_color(const char *state, const char **on, const char **off); + +int acquire_link_description(sd_varlink *vl, int ifindex, sd_json_variant **ret); +int json_variant_find_object(sd_json_variant *v, char * const *object_names, sd_json_variant **ret); From 1416d3b69c172d83565c4084eca5b8a1fef4ed3d Mon Sep 17 00:00:00 2001 From: noxiouz Date: Tue, 24 Feb 2026 23:04:09 +0900 Subject: [PATCH 12/13] networkctl: drop unused functions Co-developed-by: Claude Opus 4.6 --- src/network/networkctl-util.c | 57 ----------------------------------- src/network/networkctl-util.h | 9 ------ 2 files changed, 66 deletions(-) diff --git a/src/network/networkctl-util.c b/src/network/networkctl-util.c index 6c1db351ae..590c8a6abc 100644 --- a/src/network/networkctl-util.c +++ b/src/network/networkctl-util.c @@ -3,16 +3,12 @@ #include #include -#include "sd-bus.h" - -#include "alloc-util.h" #include "ansi-color.h" #include "bus-util.h" #include "log.h" #include "networkctl.h" #include "networkctl-util.h" #include "polkit-agent.h" -#include "stdio-util.h" #include "string-util.h" #include "strv.h" #include "varlink-util.h" @@ -117,59 +113,6 @@ bool networkd_is_running(void) { return cached; } -int acquire_bus(sd_bus **ret) { - _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; - int r; - - assert(ret); - - r = sd_bus_open_system(&bus); - if (r < 0) - return log_error_errno(r, "Failed to connect to system bus: %m"); - - (void) sd_bus_set_allow_interactive_authorization(bus, arg_ask_password); - - if (networkd_is_running()) { - r = varlink_connect_networkd(/* ret_varlink= */ NULL); - if (r < 0) - return r; - } else - log_warning("systemd-networkd is not running, output might be incomplete."); - - *ret = TAKE_PTR(bus); - return 0; -} - -int link_get_property( - sd_bus *bus, - int ifindex, - sd_bus_error *error, - sd_bus_message **reply, - const char *iface, - const char *propname, - const char *type) { - - _cleanup_free_ char *path = NULL; - char ifindex_str[DECIMAL_STR_MAX(int)]; - int r; - - assert(bus); - assert(ifindex >= 0); - assert(error); - assert(reply); - assert(iface); - assert(propname); - assert(type); - - xsprintf(ifindex_str, "%i", ifindex); - - r = sd_bus_path_encode("/org/freedesktop/network1/link", ifindex_str, &path); - if (r < 0) - return r; - - return sd_bus_get_property(bus, "org.freedesktop.network1", path, iface, propname, error, reply, type); -} - void operational_state_to_color(const char *name, const char *state, const char **on, const char **off) { if (STRPTR_IN_SET(state, "routable", "enslaved") || (streq_ptr(name, "lo") && streq_ptr(state, "carrier"))) { diff --git a/src/network/networkctl-util.h b/src/network/networkctl-util.h index df4ef40347..6067602d1a 100644 --- a/src/network/networkctl-util.h +++ b/src/network/networkctl-util.h @@ -7,15 +7,6 @@ int varlink_connect_networkd(sd_varlink **ret_varlink); int reload_networkd(void); int reload_udevd(void); bool networkd_is_running(void); -int acquire_bus(sd_bus **ret); -int link_get_property( - sd_bus *bus, - int ifindex, - sd_bus_error *error, - sd_bus_message **reply, - const char *iface, - const char *propname, - const char *type); void operational_state_to_color(const char *name, const char *state, const char **on, const char **off); void setup_state_to_color(const char *state, const char **on, const char **off); From 7d5ec30862b3e9c8c0123520cdb495a0762fe741 Mon Sep 17 00:00:00 2001 From: noxiouz Date: Thu, 19 Mar 2026 11:50:26 +0000 Subject: [PATCH 13/13] network: add unmanaged interface checks to Link.Renew and Link.ForceRenew Varlink methods The D-Bus counterparts (bus_link_method_renew, bus_link_method_force_renew) reject calls on unmanaged interfaces with BUS_ERROR_UNMANAGED_INTERFACE, but the Varlink methods silently succeed. Add the same guard to both Varlink methods, returning io.systemd.Network.Link.InterfaceUnmanaged, and declare the error in the IDL. Co-Authored-By: Claude Opus 4.6 --- src/network/networkctl-link-info.c | 2 +- src/network/networkd-link-varlink.c | 6 ++++++ src/shared/varlink-io.systemd.Network.Link.c | 4 ++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/network/networkctl-link-info.c b/src/network/networkctl-link-info.c index 05990bffbc..0b40b44253 100644 --- a/src/network/networkctl-link-info.c +++ b/src/network/networkctl-link-info.c @@ -2,8 +2,8 @@ #include -#include "sd-netlink.h" #include "sd-json.h" +#include "sd-netlink.h" #include "alloc-util.h" #include "device-util.h" diff --git a/src/network/networkd-link-varlink.c b/src/network/networkd-link-varlink.c index 5864132ef8..c802c7fb43 100644 --- a/src/network/networkd-link-varlink.c +++ b/src/network/networkd-link-varlink.c @@ -136,6 +136,9 @@ int vl_method_link_renew(sd_varlink *vlink, sd_json_variant *parameters, sd_varl if (r != 0) return r; + if (!link->network) + return sd_varlink_error(vlink, "io.systemd.Network.Link.InterfaceUnmanaged", NULL); + r = varlink_verify_polkit_async( vlink, manager->bus, @@ -163,6 +166,9 @@ int vl_method_link_force_renew(sd_varlink *vlink, sd_json_variant *parameters, s if (r != 0) return r; + if (!link->network) + return sd_varlink_error(vlink, "io.systemd.Network.Link.InterfaceUnmanaged", NULL); + r = varlink_verify_polkit_async( vlink, manager->bus, diff --git a/src/shared/varlink-io.systemd.Network.Link.c b/src/shared/varlink-io.systemd.Network.Link.c index 5474e5e475..82807939e3 100644 --- a/src/shared/varlink-io.systemd.Network.Link.c +++ b/src/shared/varlink-io.systemd.Network.Link.c @@ -41,6 +41,8 @@ static SD_VARLINK_DEFINE_METHOD( VARLINK_NETWORK_INTERFACE_INPUTS, VARLINK_DEFINE_POLKIT_INPUT); +static SD_VARLINK_DEFINE_ERROR(InterfaceUnmanaged); + SD_VARLINK_DEFINE_INTERFACE( io_systemd_Network_Link, "io.systemd.Network.Link", @@ -56,6 +58,8 @@ SD_VARLINK_DEFINE_INTERFACE( &vl_method_Reconfigure, SD_VARLINK_SYMBOL_COMMENT("Describe the specified link by index or name."), &vl_method_Describe, + SD_VARLINK_SYMBOL_COMMENT("The specified interface is not managed by systemd-networkd."), + &vl_error_InterfaceUnmanaged, &vl_type_Address, &vl_type_BitRates, &vl_type_DHCPLease,