network: several follow-ups for new varlink methods (#40808)

This commit is contained in:
Daan De Meyer
2026-02-24 19:59:01 +01:00
committed by GitHub
12 changed files with 169 additions and 119 deletions

7
NEWS
View File

@@ -172,9 +172,10 @@ CHANGES WITH 260 in spe:
RouteMetric=, and UseGateway= settings. This allows systemd-networkd
to establish a cellular modem connection to a broadband network.
* systemd-networkd gained a pair of varlink methods LinkUp()/LinkDown().
networkctl up/down now utilizes the new varlink interfaces in place
of direct RTNL message for better interaction with networkd.
* systemd-networkd gained a pair of varlink methods
io.systemd.Network.Link.Up()/Down(). networkctl up/down now utilizes
the new varlink interfaces in place of direct RTNL message for better
interaction with networkd.
Changes in systemd-boot and the stub:

View File

@@ -59,6 +59,7 @@ systemd_networkd_extract_sources = files(
'networkd-ipv6ll.c',
'networkd-json.c',
'networkd-link-bus.c',
'networkd-link-varlink.c',
'networkd-link.c',
'networkd-lldp-rx.c',
'networkd-lldp-tx.c',

View File

@@ -67,7 +67,7 @@ int link_up_down(int argc, char *argv[], void *userdata) {
ORDERED_SET_FOREACH(p, indexes)
RET_GATHER(ret, varlink_callbo_and_log(
vl,
up ? "io.systemd.Network.LinkUp" : "io.systemd.Network.LinkDown",
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)));

View File

@@ -0,0 +1,102 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "sd-varlink.h"
#include "bus-polkit.h"
#include "json-util.h"
#include "networkd-link.h"
#include "networkd-link-varlink.h"
#include "networkd-manager.h"
#include "networkd-setlink.h"
int dispatch_link(sd_varlink *vlink, sd_json_variant *parameters, Manager *manager, DispatchLinkFlag flags, Link **ret) {
struct {
int ifindex;
const char *ifname;
} info = {};
Link *link = NULL;
int r;
static const sd_json_dispatch_field dispatch_table[] = {
{ "InterfaceIndex", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_ifindex, voffsetof(info, ifindex), SD_JSON_RELAX },
{ "InterfaceName", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, voffsetof(info, ifname), 0 },
{}
}, dispatch_polkit_table[] = {
{ "InterfaceIndex", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_ifindex, voffsetof(info, ifindex), SD_JSON_RELAX },
{ "InterfaceName", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, voffsetof(info, ifname), 0 },
VARLINK_DISPATCH_POLKIT_FIELD,
{}
};
assert(vlink);
assert(manager);
assert(ret);
r = sd_varlink_dispatch(
vlink,
parameters,
FLAGS_SET(flags, DISPATCH_LINK_POLKIT) ? dispatch_polkit_table : dispatch_table,
&info);
if (r != 0)
return r;
if (info.ifindex < 0)
return sd_varlink_error_invalid_parameter(vlink, JSON_VARIANT_STRING_CONST("InterfaceIndex"));
if (info.ifindex > 0 && link_get_by_index(manager, info.ifindex, &link) < 0)
return sd_varlink_error_invalid_parameter(vlink, JSON_VARIANT_STRING_CONST("InterfaceIndex"));
if (info.ifname) {
Link *link_by_name;
if (link_get_by_name(manager, info.ifname, &link_by_name) < 0)
return sd_varlink_error_invalid_parameter(vlink, JSON_VARIANT_STRING_CONST("InterfaceName"));
if (link && link_by_name != link)
/* If both arguments are specified, then these must be consistent. */
return sd_varlink_error_invalid_parameter(vlink, JSON_VARIANT_STRING_CONST("InterfaceName"));
link = link_by_name;
}
if (!link && FLAGS_SET(flags, DISPATCH_LINK_MANDATORY))
return sd_varlink_error_invalid_parameter(vlink, JSON_VARIANT_STRING_CONST("InterfaceIndex"));
/* If the DISPATCH_LINK_MANDATORY flag is not set, this function may return NULL. */
*ret = link;
return 0;
}
static int vl_method_link_up_or_down(sd_varlink *vlink, sd_json_variant *parameters, Manager *manager, bool up) {
Link *link;
int r;
assert(vlink);
assert(manager);
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.manage-links",
/* details= */ NULL,
&manager->polkit_registry);
if (r <= 0)
return r;
if (!up)
/* Stop all network engines while interface is still up to allow proper cleanup,
* e.g. sending IPv6 shutdown RA messages before the interface is brought down. */
(void) link_stop_engines(link, /* may_keep_dynamic = */ false);
return link_up_or_down_now_by_varlink(link, up, vlink);
}
int vl_method_link_up(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= */ true);
}
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);
}

View File

@@ -0,0 +1,14 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "networkd-forward.h"
typedef enum DispatchLinkFlag {
DISPATCH_LINK_POLKIT = 1 << 0,
DISPATCH_LINK_MANDATORY = 1 << 1,
} DispatchLinkFlag;
int dispatch_link(sd_varlink *vlink, sd_json_variant *parameters, Manager *manager, DispatchLinkFlag flags, Link **ret);
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);

View File

@@ -14,11 +14,12 @@
#include "networkd-dhcp-server.h"
#include "networkd-json.h"
#include "networkd-link.h"
#include "networkd-link-varlink.h"
#include "networkd-manager.h"
#include "networkd-manager-varlink.h"
#include "networkd-setlink.h"
#include "stat-util.h"
#include "varlink-io.systemd.Network.h"
#include "varlink-io.systemd.Network.Link.h"
#include "varlink-io.systemd.service.h"
#include "varlink-util.h"
@@ -93,55 +94,6 @@ static int vl_method_get_namespace_id(sd_varlink *link, sd_json_variant *paramet
SD_JSON_BUILD_PAIR_CONDITION(nsid != UINT32_MAX, "NamespaceNSID", SD_JSON_BUILD_UNSIGNED(nsid)));
}
static int dispatch_interface(sd_varlink *vlink, sd_json_variant *parameters, Manager *manager, bool polkit, Link **ret) {
struct {
int ifindex;
const char *ifname;
} info = {};
Link *link = NULL;
int r;
static const sd_json_dispatch_field dispatch_table[] = {
{ "InterfaceIndex", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_ifindex, voffsetof(info, ifindex), SD_JSON_RELAX },
{ "InterfaceName", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, voffsetof(info, ifname), 0 },
{}
}, dispatch_polkit_table[] = {
{ "InterfaceIndex", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_ifindex, voffsetof(info, ifindex), SD_JSON_RELAX },
{ "InterfaceName", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, voffsetof(info, ifname), 0 },
VARLINK_DISPATCH_POLKIT_FIELD,
{}
};
assert(vlink);
assert(manager);
assert(ret);
r = sd_varlink_dispatch(vlink, parameters, polkit ? dispatch_polkit_table : dispatch_table, &info);
if (r != 0)
return r;
if (info.ifindex < 0)
return sd_varlink_error_invalid_parameter(vlink, JSON_VARIANT_STRING_CONST("InterfaceIndex"));
if (info.ifindex > 0 && link_get_by_index(manager, info.ifindex, &link) < 0)
return sd_varlink_error_invalid_parameter(vlink, JSON_VARIANT_STRING_CONST("InterfaceIndex"));
if (info.ifname) {
Link *link_by_name;
if (link_get_by_name(manager, info.ifname, &link_by_name) < 0)
return sd_varlink_error_invalid_parameter(vlink, JSON_VARIANT_STRING_CONST("InterfaceName"));
if (link && link_by_name != link)
/* If both arguments are specified, then these must be consistent. */
return sd_varlink_error_invalid_parameter(vlink, JSON_VARIANT_STRING_CONST("InterfaceName"));
link = link_by_name;
}
/* If neither InterfaceIndex nor InterfaceName specified, this function returns NULL. */
*ret = link;
return 0;
}
static int link_append_lldp_neighbors(Link *link, sd_json_variant *v, sd_json_variant **array) {
assert(link);
assert(array);
@@ -163,7 +115,7 @@ static int vl_method_get_lldp_neighbors(sd_varlink *vlink, sd_json_variant *para
assert(vlink);
assert(manager);
r = dispatch_interface(vlink, parameters, manager, /* polkit= */ false, &link);
r = dispatch_link(vlink, parameters, manager, /* flags= */ 0, &link);
if (r != 0)
return r;
@@ -284,46 +236,6 @@ static int vl_method_set_persistent_storage(sd_varlink *vlink, sd_json_variant *
return sd_varlink_reply(vlink, NULL);
}
static int vl_method_link_up_or_down(sd_varlink *vlink, sd_json_variant *parameters, Manager *manager, bool up) {
Link *link;
int r;
assert(vlink);
assert(manager);
r = dispatch_interface(vlink, parameters, manager, /* polkit= */ true, &link);
if (r != 0)
return r;
/* Require a specific link to be specified. */
if (!link)
return sd_varlink_error_invalid_parameter(vlink, JSON_VARIANT_STRING_CONST("InterfaceIndex"));
r = varlink_verify_polkit_async(
vlink,
manager->bus,
"org.freedesktop.network1.manage-links",
/* details= */ NULL,
&manager->polkit_registry);
if (r <= 0)
return r;
if (!up)
/* Stop all network engines while interface is still up to allow proper cleanup,
* e.g. sending IPv6 shutdown RA messages before the interface is brought down. */
(void) link_stop_engines(link, /* may_keep_dynamic = */ false);
return link_up_or_down_now_by_varlink(link, up, vlink);
}
static int vl_method_link_up(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= */ true);
}
static 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 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 */
@@ -347,6 +259,7 @@ int manager_varlink_init(Manager *m, int fd) {
r = sd_varlink_server_add_interface_many(
s,
&vl_interface_io_systemd_Network,
&vl_interface_io_systemd_Network_Link,
&vl_interface_io_systemd_service);
if (r < 0)
return log_error_errno(r, "Failed to add Network interface to varlink server: %m");
@@ -358,8 +271,8 @@ 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.LinkUp", vl_method_link_up,
"io.systemd.Network.LinkDown", vl_method_link_down,
"io.systemd.Network.Link.Up", vl_method_link_up,
"io.systemd.Network.Link.Down", vl_method_link_down,
"io.systemd.service.Ping", varlink_method_ping,
"io.systemd.service.SetLogLevel", varlink_method_set_log_level,
"io.systemd.service.GetEnvironment", varlink_method_get_environment);

View File

@@ -216,6 +216,7 @@ shared_sources = files(
'varlink-io.systemd.MuteConsole.c',
'varlink-io.systemd.NamespaceResource.c',
'varlink-io.systemd.Network.c',
'varlink-io.systemd.Network.Link.c',
'varlink-io.systemd.PCRExtend.c',
'varlink-io.systemd.PCRLock.c',
'varlink-io.systemd.Repart.c',

View File

@@ -0,0 +1,28 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "bus-polkit.h"
#include "varlink-io.systemd.Network.Link.h"
#define VARLINK_NETWORK_INTERFACE_INPUTS \
SD_VARLINK_FIELD_COMMENT("Index of the interface. If specified together with InterfaceName, both must reference the same link."), \
SD_VARLINK_DEFINE_INPUT(InterfaceIndex, SD_VARLINK_INT, SD_VARLINK_NULLABLE), \
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(
Up,
VARLINK_NETWORK_INTERFACE_INPUTS,
VARLINK_DEFINE_POLKIT_INPUT);
static SD_VARLINK_DEFINE_METHOD(
Down,
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);

View File

@@ -0,0 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "sd-varlink-idl.h"
extern const sd_varlink_interface vl_interface_io_systemd_Network_Link;

View File

@@ -1,6 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "bus-polkit.h"
#include "varlink-io.systemd.Network.h"
/* Helper macro to define address fields with both binary and string representation */
@@ -594,22 +593,6 @@ 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_METHOD(
LinkUp,
SD_VARLINK_FIELD_COMMENT("Index of the interface. If specified together with InterfaceName, both must reference the same link."),
SD_VARLINK_DEFINE_INPUT(InterfaceIndex, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
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),
VARLINK_DEFINE_POLKIT_INPUT);
static SD_VARLINK_DEFINE_METHOD(
LinkDown,
SD_VARLINK_FIELD_COMMENT("Index of the interface. If specified together with InterfaceName, both must reference the same link."),
SD_VARLINK_DEFINE_INPUT(InterfaceIndex, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
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),
VARLINK_DEFINE_POLKIT_INPUT);
static SD_VARLINK_DEFINE_ERROR(StorageReadOnly);
SD_VARLINK_DEFINE_INTERFACE(
@@ -620,10 +603,6 @@ SD_VARLINK_DEFINE_INTERFACE(
&vl_method_GetNamespaceId,
&vl_method_GetLLDPNeighbors,
&vl_method_SetPersistentStorage,
SD_VARLINK_SYMBOL_COMMENT("Bring the specified link up."),
&vl_method_LinkUp,
SD_VARLINK_SYMBOL_COMMENT("Bring the specified link down."),
&vl_method_LinkDown,
&vl_type_Address,
&vl_type_DHCPLease,
&vl_type_DHCPServer,

View File

@@ -2,6 +2,7 @@
#include <unistd.h>
#include "bus-polkit.h"
#include "env-util.h"
#include "json-util.h"
#include "log.h"
@@ -11,7 +12,9 @@
static SD_VARLINK_DEFINE_METHOD(Ping);
static SD_VARLINK_DEFINE_METHOD(Reload);
static SD_VARLINK_DEFINE_METHOD(
Reload,
VARLINK_DEFINE_POLKIT_INPUT);
static SD_VARLINK_DEFINE_METHOD(
SetLogLevel,

View File

@@ -34,6 +34,7 @@
#include "varlink-io.systemd.MuteConsole.h"
#include "varlink-io.systemd.NamespaceResource.h"
#include "varlink-io.systemd.Network.h"
#include "varlink-io.systemd.Network.Link.h"
#include "varlink-io.systemd.PCRExtend.h"
#include "varlink-io.systemd.PCRLock.h"
#include "varlink-io.systemd.Repart.h"
@@ -199,6 +200,7 @@ TEST(parse_format) {
&vl_interface_io_systemd_MuteConsole,
&vl_interface_io_systemd_NamespaceResource,
&vl_interface_io_systemd_Network,
&vl_interface_io_systemd_Network_Link,
&vl_interface_io_systemd_PCRExtend,
&vl_interface_io_systemd_PCRLock,
&vl_interface_io_systemd_Repart,