diff --git a/NEWS b/NEWS index a508c73a0cf..5acfd6641fe 100644 --- a/NEWS +++ b/NEWS @@ -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: diff --git a/src/network/meson.build b/src/network/meson.build index 89f3231c290..85b57669e46 100644 --- a/src/network/meson.build +++ b/src/network/meson.build @@ -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', diff --git a/src/network/networkctl-misc.c b/src/network/networkctl-misc.c index 701efee0788..73c79494a07 100644 --- a/src/network/networkctl-misc.c +++ b/src/network/networkctl-misc.c @@ -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))); diff --git a/src/network/networkd-link-varlink.c b/src/network/networkd-link-varlink.c new file mode 100644 index 00000000000..ad7386dabff --- /dev/null +++ b/src/network/networkd-link-varlink.c @@ -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); +} diff --git a/src/network/networkd-link-varlink.h b/src/network/networkd-link-varlink.h new file mode 100644 index 00000000000..60468519ca1 --- /dev/null +++ b/src/network/networkd-link-varlink.h @@ -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); diff --git a/src/network/networkd-manager-varlink.c b/src/network/networkd-manager-varlink.c index 41f1d9b9a58..49bc82678d0 100644 --- a/src/network/networkd-manager-varlink.c +++ b/src/network/networkd-manager-varlink.c @@ -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); diff --git a/src/shared/meson.build b/src/shared/meson.build index 1a07b908caf..bbc03079993 100644 --- a/src/shared/meson.build +++ b/src/shared/meson.build @@ -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', diff --git a/src/shared/varlink-io.systemd.Network.Link.c b/src/shared/varlink-io.systemd.Network.Link.c new file mode 100644 index 00000000000..ccbb046ca00 --- /dev/null +++ b/src/shared/varlink-io.systemd.Network.Link.c @@ -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); diff --git a/src/shared/varlink-io.systemd.Network.Link.h b/src/shared/varlink-io.systemd.Network.Link.h new file mode 100644 index 00000000000..f45723020c0 --- /dev/null +++ b/src/shared/varlink-io.systemd.Network.Link.h @@ -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; diff --git a/src/shared/varlink-io.systemd.Network.c b/src/shared/varlink-io.systemd.Network.c index b80070ee5f5..c67b857f12d 100644 --- a/src/shared/varlink-io.systemd.Network.c +++ b/src/shared/varlink-io.systemd.Network.c @@ -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, diff --git a/src/shared/varlink-io.systemd.service.c b/src/shared/varlink-io.systemd.service.c index 8cbf299e07b..698a3d41eba 100644 --- a/src/shared/varlink-io.systemd.service.c +++ b/src/shared/varlink-io.systemd.service.c @@ -2,6 +2,7 @@ #include +#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, diff --git a/src/test/test-varlink-idl.c b/src/test/test-varlink-idl.c index d4f8eccf28b..a4a50e16e8b 100644 --- a/src/test/test-varlink-idl.c +++ b/src/test/test-varlink-idl.c @@ -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,