diff --git a/src/network/meson.build b/src/network/meson.build index 3d692abf44..5f06948752 100644 --- a/src/network/meson.build +++ b/src/network/meson.build @@ -56,8 +56,9 @@ sources = files( 'networkd-link.c', 'networkd-lldp-rx.c', 'networkd-lldp-tx.c', - 'networkd-manager-bus.c', 'networkd-manager.c', + 'networkd-manager-bus.c', + 'networkd-manager-varlink.c', 'networkd-ndisc.c', 'networkd-neighbor.c', 'networkd-netlabel.c', diff --git a/src/network/networkd-manager-varlink.c b/src/network/networkd-manager-varlink.c new file mode 100644 index 0000000000..d9750d9b64 --- /dev/null +++ b/src/network/networkd-manager-varlink.c @@ -0,0 +1,90 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include + +#include "networkd-manager-varlink.h" +#include "varlink.h" +#include "varlink-io.systemd.Network.h" + +static int vl_method_get_states(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) { + Manager *m = ASSERT_PTR(userdata); + + assert(link); + + if (json_variant_elements(parameters) > 0) + return varlink_error_invalid_parameter(link, parameters); + + return varlink_replyb(link, + JSON_BUILD_OBJECT( + JSON_BUILD_PAIR_STRING("AddressState", link_address_state_to_string(m->address_state)), + JSON_BUILD_PAIR_STRING("IPv4AddressState", link_address_state_to_string(m->ipv4_address_state)), + JSON_BUILD_PAIR_STRING("IPv6AddressState", link_address_state_to_string(m->ipv6_address_state)), + JSON_BUILD_PAIR_STRING("CarrierState", link_carrier_state_to_string(m->carrier_state)), + JSON_BUILD_PAIR_CONDITION(m->online_state >= 0, "OnlineState", JSON_BUILD_STRING(link_online_state_to_string(m->online_state))), + JSON_BUILD_PAIR_STRING("OperationalState", link_operstate_to_string(m->operational_state)))); +} + +static int vl_method_get_namespace_id(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) { + uint64_t id; + + assert(link); + + if (json_variant_elements(parameters) > 0) + return varlink_error_invalid_parameter(link, parameters); + + struct stat st; + if (stat("/proc/self/ns/net", &st) < 0) { + log_warning_errno(errno, "Failed to stat network namespace, ignoring: %m"); + id = 0; + } else + id = st.st_ino; + + return varlink_replyb(link, + JSON_BUILD_OBJECT( + JSON_BUILD_PAIR_UNSIGNED("NamespaceId", id))); +} + +int manager_connect_varlink(Manager *m) { + _cleanup_(varlink_server_unrefp) VarlinkServer *s = NULL; + int r; + + assert(m); + + if (m->varlink_server) + return 0; + + r = varlink_server_new(&s, VARLINK_SERVER_ACCOUNT_UID|VARLINK_SERVER_INHERIT_USERDATA); + if (r < 0) + return log_error_errno(r, "Failed to allocate varlink server object: %m"); + + varlink_server_set_userdata(s, m); + + r = varlink_server_add_interface(s, &vl_interface_io_systemd_Network); + if (r < 0) + return log_error_errno(r, "Failed to add Network interface to varlink server: %m"); + + r = varlink_server_bind_method_many( + s, + "io.systemd.Network.GetStates", vl_method_get_states, + "io.systemd.Network.GetNamespaceId", vl_method_get_namespace_id); + if (r < 0) + return log_error_errno(r, "Failed to register varlink methods: %m"); + + r = varlink_server_listen_address(s, "/run/systemd/netif/io.systemd.Network", 0666); + if (r < 0) + return log_error_errno(r, "Failed to bind to varlink socket: %m"); + + r = varlink_server_attach_event(s, m->event, SD_EVENT_PRIORITY_NORMAL); + if (r < 0) + return log_error_errno(r, "Failed to attach varlink connection to event loop: %m"); + + m->varlink_server = TAKE_PTR(s); + return 0; +} + +void manager_varlink_done(Manager *m) { + assert(m); + + m->varlink_server = varlink_server_unref(m->varlink_server); + (void) unlink("/run/systemd/netif/io.systemd.Network"); +} diff --git a/src/network/networkd-manager-varlink.h b/src/network/networkd-manager-varlink.h new file mode 100644 index 0000000000..46078a81d9 --- /dev/null +++ b/src/network/networkd-manager-varlink.h @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include "networkd-manager.h" + +int manager_connect_varlink(Manager *m); +void manager_varlink_done(Manager *m); diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 51f8b0cc74..3319cbe086 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -36,8 +36,9 @@ #include "networkd-dhcp-server-bus.h" #include "networkd-dhcp6.h" #include "networkd-link-bus.h" -#include "networkd-manager-bus.h" #include "networkd-manager.h" +#include "networkd-manager-bus.h" +#include "networkd-manager-varlink.h" #include "networkd-neighbor.h" #include "networkd-network-bus.h" #include "networkd-nexthop.h" @@ -529,6 +530,10 @@ int manager_setup(Manager *m) { if (m->test_mode) return 0; + r = manager_connect_varlink(m); + if (r < 0) + return r; + r = manager_connect_bus(m); if (r < 0) return r; @@ -640,6 +645,8 @@ Manager* manager_free(Manager *m) { sd_device_monitor_unref(m->device_monitor); + manager_varlink_done(m); + bus_verify_polkit_async_registry_free(m->polkit_registry); sd_bus_flush_close_unref(m->bus); diff --git a/src/network/networkd-manager.h b/src/network/networkd-manager.h index a9827d8a4b..fc6d1903fa 100644 --- a/src/network/networkd-manager.h +++ b/src/network/networkd-manager.h @@ -17,6 +17,7 @@ #include "ordered-set.h" #include "set.h" #include "time-util.h" +#include "varlink.h" struct Manager { sd_netlink *rtnl; @@ -25,6 +26,7 @@ struct Manager { sd_event *event; sd_resolve *resolve; sd_bus *bus; + VarlinkServer *varlink_server; sd_device_monitor *device_monitor; Hashmap *polkit_registry; int ethtool_fd; diff --git a/src/shared/meson.build b/src/shared/meson.build index bcd02d4cfb..b2cee6fa2c 100644 --- a/src/shared/meson.build +++ b/src/shared/meson.build @@ -176,9 +176,10 @@ shared_sources = files( 'varlink-io.systemd.Credentials.c', 'varlink-io.systemd.Journal.c', 'varlink-io.systemd.ManagedOOM.c', + 'varlink-io.systemd.Network.c', 'varlink-io.systemd.PCRExtend.c', - 'varlink-io.systemd.Resolve.Monitor.c', 'varlink-io.systemd.Resolve.c', + 'varlink-io.systemd.Resolve.Monitor.c', 'varlink-io.systemd.UserDatabase.c', 'varlink-io.systemd.oom.c', 'varlink-io.systemd.service.c', diff --git a/src/shared/varlink-io.systemd.Network.c b/src/shared/varlink-io.systemd.Network.c new file mode 100644 index 0000000000..ec25e26e29 --- /dev/null +++ b/src/shared/varlink-io.systemd.Network.c @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "varlink-io.systemd.Network.h" + +static VARLINK_DEFINE_METHOD(GetStates, + VARLINK_DEFINE_OUTPUT(AddressState, VARLINK_STRING, 0), + VARLINK_DEFINE_OUTPUT(IPv4AddressState, VARLINK_STRING, 0), + VARLINK_DEFINE_OUTPUT(IPv6AddressState, VARLINK_STRING, 0), + VARLINK_DEFINE_OUTPUT(CarrierState, VARLINK_STRING, 0), + VARLINK_DEFINE_OUTPUT(OnlineState, VARLINK_STRING, 0), + VARLINK_DEFINE_OUTPUT(OperationalState, VARLINK_STRING, 0)); + +static VARLINK_DEFINE_METHOD(GetNamespaceId, + VARLINK_DEFINE_OUTPUT(NamespaceId, VARLINK_INT, 0)); + +VARLINK_DEFINE_INTERFACE( + io_systemd_Network, + "io.systemd.Network", + &vl_method_GetStates, + &vl_method_GetNamespaceId); diff --git a/src/shared/varlink-io.systemd.Network.h b/src/shared/varlink-io.systemd.Network.h new file mode 100644 index 0000000000..12d532ab32 --- /dev/null +++ b/src/shared/varlink-io.systemd.Network.h @@ -0,0 +1,6 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include "varlink-idl.h" + +extern const VarlinkInterface vl_interface_io_systemd_Network; diff --git a/src/test/test-varlink-idl.c b/src/test/test-varlink-idl.c index 6aa1fa6b1d..1770cb3c03 100644 --- a/src/test/test-varlink-idl.c +++ b/src/test/test-varlink-idl.c @@ -11,6 +11,7 @@ #include "varlink-io.systemd.Credentials.h" #include "varlink-io.systemd.Journal.h" #include "varlink-io.systemd.ManagedOOM.h" +#include "varlink-io.systemd.Network.h" #include "varlink-io.systemd.PCRExtend.h" #include "varlink-io.systemd.Resolve.Monitor.h" #include "varlink-io.systemd.Resolve.h" @@ -134,6 +135,8 @@ TEST(parse_format) { print_separator(); test_parse_format_one(&vl_interface_io_systemd_ManagedOOM); print_separator(); + test_parse_format_one(&vl_interface_io_systemd_Network); + print_separator(); test_parse_format_one(&vl_interface_io_systemd_oom); print_separator(); test_parse_format_one(&vl_interface_io_systemd);