diff --git a/src/libsystemd-network/dhcp-client-internal.h b/src/libsystemd-network/dhcp-client-internal.h index a6f37522d1ee9..6f43975977a27 100644 --- a/src/libsystemd-network/dhcp-client-internal.h +++ b/src/libsystemd-network/dhcp-client-internal.h @@ -1,4 +1,12 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +#include "sd-dhcp-client.h" + extern const struct hash_ops dhcp_option_hash_ops; + +int dhcp_client_set_state_callback( + sd_dhcp_client *client, + sd_dhcp_client_callback_t cb, + void *userdata); +int dhcp_client_get_state(sd_dhcp_client *client); diff --git a/src/libsystemd-network/dhcp-internal.h b/src/libsystemd-network/dhcp-internal.h index e020db7bcd0e0..d4e4a026b5275 100644 --- a/src/libsystemd-network/dhcp-internal.h +++ b/src/libsystemd-network/dhcp-internal.h @@ -11,6 +11,7 @@ #include "sd-dhcp-client.h" +#include "dhcp-client-internal.h" #include "dhcp-protocol.h" #include "ether-addr-util.h" #include "network-common.h" @@ -29,8 +30,6 @@ typedef struct DHCPServerData { size_t size; } DHCPServerData; -extern const struct hash_ops dhcp_option_hash_ops; - typedef struct sd_dhcp_client sd_dhcp_client; int dhcp_network_bind_raw_socket( diff --git a/src/libsystemd-network/dhcp-protocol.c b/src/libsystemd-network/dhcp-protocol.c new file mode 100644 index 0000000000000..955d08720dbed --- /dev/null +++ b/src/libsystemd-network/dhcp-protocol.c @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "dhcp-protocol.h" +#include "string-table.h" + +static const char* const dhcp_state_table[_DHCP_STATE_MAX] = { + [DHCP_STATE_STOPPED] = "stopped", + [DHCP_STATE_INIT] = "initialization", + [DHCP_STATE_SELECTING] = "selecting", + [DHCP_STATE_INIT_REBOOT] = "init-reboot", + [DHCP_STATE_REBOOTING] = "rebooting", + [DHCP_STATE_REQUESTING] = "requesting", + [DHCP_STATE_BOUND] = "bound", + [DHCP_STATE_RENEWING] = "renewing", + [DHCP_STATE_REBINDING] = "rebinding", +}; + +DEFINE_STRING_TABLE_LOOKUP_TO_STRING(dhcp_state, DHCPState); diff --git a/src/libsystemd-network/dhcp-protocol.h b/src/libsystemd-network/dhcp-protocol.h index 2dc0660cc7d7b..dd330ae839388 100644 --- a/src/libsystemd-network/dhcp-protocol.h +++ b/src/libsystemd-network/dhcp-protocol.h @@ -55,15 +55,17 @@ enum { }; enum DHCPState { - DHCP_STATE_STOPPED = 0, - DHCP_STATE_INIT = 1, - DHCP_STATE_SELECTING = 2, - DHCP_STATE_INIT_REBOOT = 3, - DHCP_STATE_REBOOTING = 4, - DHCP_STATE_REQUESTING = 5, - DHCP_STATE_BOUND = 6, - DHCP_STATE_RENEWING = 7, - DHCP_STATE_REBINDING = 8, + DHCP_STATE_STOPPED, + DHCP_STATE_INIT, + DHCP_STATE_SELECTING, + DHCP_STATE_INIT_REBOOT, + DHCP_STATE_REBOOTING, + DHCP_STATE_REQUESTING, + DHCP_STATE_BOUND, + DHCP_STATE_RENEWING, + DHCP_STATE_REBINDING, + _DHCP_STATE_MAX, + _DHCP_STATE_INVALID = -EINVAL, }; typedef enum DHCPState DHCPState; @@ -107,3 +109,5 @@ enum { DHCP_FQDN_FLAG_E = (1 << 2), DHCP_FQDN_FLAG_N = (1 << 3), }; + +const char *dhcp_state_to_string(DHCPState s) _const_; diff --git a/src/libsystemd-network/dhcp6-client-internal.h b/src/libsystemd-network/dhcp6-client-internal.h new file mode 100644 index 0000000000000..6c17f5749bc3a --- /dev/null +++ b/src/libsystemd-network/dhcp6-client-internal.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include "sd-dhcp6-client.h" + +int dhcp6_client_set_state_callback( + sd_dhcp6_client *client, + sd_dhcp6_client_callback_t cb, + void *userdata); +int dhcp6_client_get_state(sd_dhcp6_client *client); diff --git a/src/libsystemd-network/dhcp6-internal.h b/src/libsystemd-network/dhcp6-internal.h index fa43f28eb55e0..97bc82d5210cb 100644 --- a/src/libsystemd-network/dhcp6-internal.h +++ b/src/libsystemd-network/dhcp6-internal.h @@ -12,6 +12,7 @@ #include "sd-dhcp6-client.h" #include "dhcp-identifier.h" +#include "dhcp6-client-internal.h" #include "dhcp6-option.h" #include "dhcp6-protocol.h" #include "ether-addr-util.h" @@ -79,6 +80,8 @@ struct sd_dhcp6_client { sd_dhcp6_client_callback_t callback; void *userdata; + sd_dhcp6_client_callback_t state_callback; + void *state_userdata; bool send_release; /* Ignore machine-ID when generating DUID. See dhcp_identifier_set_duid_en(). */ diff --git a/src/libsystemd-network/meson.build b/src/libsystemd-network/meson.build index 043d3bc2548b5..0b35eeec3488a 100644 --- a/src/libsystemd-network/meson.build +++ b/src/libsystemd-network/meson.build @@ -6,6 +6,7 @@ sources = files( 'dhcp-network.c', 'dhcp-option.c', 'dhcp-packet.c', + 'dhcp-protocol.c', 'dhcp6-network.c', 'dhcp6-option.c', 'dhcp6-protocol.c', diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 21b6592037405..82a93af0bcba0 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -118,6 +118,8 @@ struct sd_dhcp_client { sd_event_source *timeout_expire; sd_dhcp_client_callback_t callback; void *userdata; + sd_dhcp_client_callback_t state_callback; + void *state_userdata; sd_dhcp_lease *lease; usec_t start_delay; int ip_service_type; @@ -226,6 +228,19 @@ int sd_dhcp_client_id_to_string(const void *data, size_t len, char **ret) { return 0; } +int dhcp_client_set_state_callback( + sd_dhcp_client *client, + sd_dhcp_client_callback_t cb, + void *userdata) { + + assert_return(client, -EINVAL); + + client->state_callback = cb; + client->state_userdata = userdata; + + return 0; +} + int sd_dhcp_client_set_callback( sd_dhcp_client *client, sd_dhcp_client_callback_t cb, @@ -730,6 +745,27 @@ int sd_dhcp_client_set_fallback_lease_lifetime(sd_dhcp_client *client, uint32_t return 0; } +static void client_set_state(sd_dhcp_client *client, DHCPState state) { + assert(client); + + if (client->state == state) + return; + + log_dhcp_client(client, "State changed: %s -> %s", + dhcp_state_to_string(client->state), dhcp_state_to_string(state)); + + client->state = state; + + if (client->state_callback) + client->state_callback(client, state, client->state_userdata); +} + +int dhcp_client_get_state(sd_dhcp_client *client) { + assert_return(client, -EINVAL); + + return client->state; +} + static int client_notify(sd_dhcp_client *client, int event) { assert(client); @@ -753,7 +789,7 @@ static int client_initialize(sd_dhcp_client *client) { client->attempt = 0; - client->state = DHCP_STATE_STOPPED; + client_set_state(client, DHCP_STATE_STOPPED); client->xid = 0; client->lease = sd_dhcp_lease_unref(client->lease); @@ -1183,6 +1219,7 @@ static int client_send_request(sd_dhcp_client *client) { case DHCP_STATE_REBOOTING: case DHCP_STATE_BOUND: case DHCP_STATE_STOPPED: + default: return -EINVAL; } @@ -1307,7 +1344,7 @@ static int client_timeout_resend( case DHCP_STATE_INIT: r = client_send_discover(client); if (r >= 0) { - client->state = DHCP_STATE_SELECTING; + client_set_state(client, DHCP_STATE_SELECTING); client->attempt = 0; } else if (client->attempt >= client->max_attempts) goto error; @@ -1330,7 +1367,7 @@ static int client_timeout_resend( goto error; if (client->state == DHCP_STATE_INIT_REBOOT) - client->state = DHCP_STATE_REBOOTING; + client_set_state(client, DHCP_STATE_REBOOTING); client->request_sent = time_now; break; @@ -1340,6 +1377,7 @@ static int client_timeout_resend( break; case DHCP_STATE_STOPPED: + default: r = -EINVAL; goto error; } @@ -1479,7 +1517,7 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) client->receive_message = sd_event_source_disable_unref(client->receive_message); client->fd = safe_close(client->fd); - client->state = DHCP_STATE_REBINDING; + client_set_state(client, DHCP_STATE_REBINDING); client->attempt = 0; r = dhcp_network_bind_raw_socket(client->ifindex, &client->link, client->xid, @@ -1500,9 +1538,9 @@ static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata) DHCP_CLIENT_DONT_DESTROY(client); if (client->lease) - client->state = DHCP_STATE_RENEWING; + client_set_state(client, DHCP_STATE_RENEWING); else if (client->state != DHCP_STATE_INIT) - client->state = DHCP_STATE_INIT_REBOOT; + client_set_state(client, DHCP_STATE_INIT_REBOOT); client->attempt = 0; return client_initialize_time_events(client); @@ -1782,7 +1820,7 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, i if (r < 0) goto error; - client->state = DHCP_STATE_REQUESTING; + client_set_state(client, DHCP_STATE_REQUESTING); client->attempt = 0; r = event_reset_time(client->event, &client->timeout_resend, @@ -1831,7 +1869,7 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, i client->receive_message = sd_event_source_disable_unref(client->receive_message); client->fd = safe_close(client->fd); - client->state = DHCP_STATE_BOUND; + client_set_state(client, DHCP_STATE_BOUND); client->attempt = 0; client->last_addr = client->lease->address; @@ -2047,7 +2085,7 @@ int sd_dhcp_client_send_renew(sd_dhcp_client *client) { client->start_delay = 0; client->attempt = 1; - client->state = DHCP_STATE_RENEWING; + client_set_state(client, DHCP_STATE_RENEWING); return client_initialize_time_events(client); } @@ -2083,7 +2121,7 @@ int sd_dhcp_client_start(sd_dhcp_client *client) { the client MAY issue a DHCPREQUEST to try to reclaim the current address. */ if (client->last_addr && !client->anonymize) - client->state = DHCP_STATE_INIT_REBOOT; + client_set_state(client, DHCP_STATE_INIT_REBOOT); r = client_start(client); if (r >= 0) @@ -2176,7 +2214,6 @@ int sd_dhcp_client_stop(sd_dhcp_client *client) { DHCP_CLIENT_DONT_DESTROY(client); client_stop(client, SD_DHCP_CLIENT_EVENT_STOP); - client->state = DHCP_STATE_STOPPED; return 0; } diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index 8957e1cf4bfe5..fb209a0c624cf 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -47,6 +47,19 @@ int sd_dhcp6_client_set_callback( return 0; } +int dhcp6_client_set_state_callback( + sd_dhcp6_client *client, + sd_dhcp6_client_callback_t cb, + void *userdata) { + + assert_return(client, -EINVAL); + + client->state_callback = cb; + client->state_userdata = userdata; + + return 0; +} + int sd_dhcp6_client_set_ifindex(sd_dhcp6_client *client, int ifindex) { assert_return(client, -EINVAL); assert_return(!sd_dhcp6_client_is_running(client), -EBUSY); @@ -553,6 +566,15 @@ static void client_set_state(sd_dhcp6_client *client, DHCP6State state) { dhcp6_state_to_string(client->state), dhcp6_state_to_string(state)); client->state = state; + + if (client->state_callback) + client->state_callback(client, state, client->state_userdata); +} + +int dhcp6_client_get_state(sd_dhcp6_client *client) { + assert_return(client, -EINVAL); + + return client->state; } static void client_notify(sd_dhcp6_client *client, int event) { diff --git a/src/network/meson.build b/src/network/meson.build index 7d0e5d6345741..2ca9eac714b3e 100644 --- a/src/network/meson.build +++ b/src/network/meson.build @@ -43,7 +43,9 @@ sources = files( 'networkd-dhcp-server-bus.c', 'networkd-dhcp-server-static-lease.c', 'networkd-dhcp-server.c', + 'networkd-dhcp4-bus.c', 'networkd-dhcp4.c', + 'networkd-dhcp6-bus.c', 'networkd-dhcp6.c', 'networkd-ipv4acd.c', 'networkd-ipv4ll.c', diff --git a/src/network/networkd-dhcp-common.c b/src/network/networkd-dhcp-common.c index 5b5b251e61ed2..ff0ee717c5ddd 100644 --- a/src/network/networkd-dhcp-common.c +++ b/src/network/networkd-dhcp-common.c @@ -6,7 +6,7 @@ #include "bus-error.h" #include "bus-locator.h" #include "dhcp-identifier.h" -#include "dhcp-internal.h" +#include "dhcp-client-internal.h" #include "dhcp6-internal.h" #include "escape.h" #include "hexdecoct.h" diff --git a/src/network/networkd-dhcp4-bus.c b/src/network/networkd-dhcp4-bus.c new file mode 100644 index 0000000000000..cb88627d200ad --- /dev/null +++ b/src/network/networkd-dhcp4-bus.c @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "sd-dhcp-client.h" + +#include "alloc-util.h" +#include "bus-common-errors.h" +#include "bus-util.h" +#include "dhcp-client-internal.h" +#include "dhcp-protocol.h" +#include "networkd-dhcp4-bus.h" +#include "networkd-link-bus.h" +#include "networkd-manager.h" +#include "string-table.h" +#include "strv.h" + +static int property_get_dhcp_client_state( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Link *l = ASSERT_PTR(userdata); + sd_dhcp_client *c; + + assert(reply); + + c = l->dhcp_client; + if (!c) + return sd_bus_message_append(reply, "s", "disabled"); + + return sd_bus_message_append(reply, "s", dhcp_state_to_string(dhcp_client_get_state(c))); +} + +static int dhcp_client_emit_changed(Link *link, const char *property, ...) { + _cleanup_free_ char *path = NULL; + char **l; + + assert(link); + + if (sd_bus_is_ready(link->manager->bus) <= 0) + return 0; + + path = link_bus_path(link); + if (!path) + return log_oom(); + + l = strv_from_stdarg_alloca(property); + + return sd_bus_emit_properties_changed_strv( + link->manager->bus, + path, + "org.freedesktop.network1.DHCPv4Client", + l); +} + +int dhcp_client_callback_bus(sd_dhcp_client *c, int event, void *userdata) { + Link *l = ASSERT_PTR(userdata); + + return dhcp_client_emit_changed(l, "State", NULL); +} + +static const sd_bus_vtable dhcp_client_vtable[] = { + SD_BUS_VTABLE_START(0), + + SD_BUS_PROPERTY("State", "s", property_get_dhcp_client_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + + SD_BUS_VTABLE_END +}; + +const BusObjectImplementation dhcp_client_object = { + "/org/freedesktop/network1/link", + "org.freedesktop.network1.DHCPv4Client", + .fallback_vtables = BUS_FALLBACK_VTABLES({dhcp_client_vtable, link_object_find}), + .node_enumerator = link_node_enumerator, +}; diff --git a/src/network/networkd-dhcp4-bus.h b/src/network/networkd-dhcp4-bus.h new file mode 100644 index 0000000000000..482e824c0ac1e --- /dev/null +++ b/src/network/networkd-dhcp4-bus.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include "sd-dhcp-client.h" + +#include "networkd-link-bus.h" + +extern const BusObjectImplementation dhcp_client_object; + +int dhcp_client_callback_bus(sd_dhcp_client *client, int event, void *userdata); diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index 9dcd37e11c6ab..f952d6dfbcc2f 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -13,6 +13,7 @@ #include "network-internal.h" #include "networkd-address.h" #include "networkd-dhcp-prefix-delegation.h" +#include "networkd-dhcp4-bus.h" #include "networkd-dhcp4.h" #include "networkd-ipv4acd.h" #include "networkd-link.h" @@ -1482,6 +1483,10 @@ static int dhcp4_configure(Link *link) { if (r < 0) return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for broadcast: %m"); + r = dhcp_client_set_state_callback(link->dhcp_client, dhcp_client_callback_bus, link); + if (r < 0) + return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set state change callback: %m"); + if (link->mtu > 0) { r = sd_dhcp_client_set_mtu(link->dhcp_client, link->mtu); if (r < 0) diff --git a/src/network/networkd-dhcp6-bus.c b/src/network/networkd-dhcp6-bus.c new file mode 100644 index 0000000000000..a225877373eeb --- /dev/null +++ b/src/network/networkd-dhcp6-bus.c @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "alloc-util.h" +#include "bus-common-errors.h" +#include "bus-util.h" +#include "dhcp6-client-internal.h" +#include "dhcp6-protocol.h" +#include "networkd-dhcp6-bus.h" +#include "networkd-link-bus.h" +#include "networkd-manager.h" +#include "string-table.h" +#include "strv.h" + +static int property_get_dhcp6_client_state( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Link *l = ASSERT_PTR(userdata); + sd_dhcp6_client *c; + + assert(reply); + + c = l->dhcp6_client; + if (!c) + return sd_bus_message_append(reply, "s", "disabled"); + + return sd_bus_message_append(reply, "s", dhcp6_state_to_string(dhcp6_client_get_state(c))); +} + +static int dhcp6_client_emit_changed(Link *link, const char *property, ...) { + _cleanup_free_ char *path = NULL; + char **l; + + assert(link); + + if (sd_bus_is_ready(link->manager->bus) <= 0) + return 0; + + path = link_bus_path(link); + if (!path) + return log_oom(); + + l = strv_from_stdarg_alloca(property); + + return sd_bus_emit_properties_changed_strv( + link->manager->bus, + path, + "org.freedesktop.network1.DHCPv6Client", + l); +} + +void dhcp6_client_callback_bus(sd_dhcp6_client *c, int event, void *userdata) { + Link *l = ASSERT_PTR(userdata); + + dhcp6_client_emit_changed(l, "State", NULL); +} + +static const sd_bus_vtable dhcp6_client_vtable[] = { + SD_BUS_VTABLE_START(0), + + SD_BUS_PROPERTY("State", "s", property_get_dhcp6_client_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + + SD_BUS_VTABLE_END +}; + +const BusObjectImplementation dhcp6_client_object = { + "/org/freedesktop/network1/link", + "org.freedesktop.network1.DHCPv6Client", + .fallback_vtables = BUS_FALLBACK_VTABLES({dhcp6_client_vtable, link_object_find}), + .node_enumerator = link_node_enumerator, +}; diff --git a/src/network/networkd-dhcp6-bus.h b/src/network/networkd-dhcp6-bus.h new file mode 100644 index 0000000000000..76a6b727aa802 --- /dev/null +++ b/src/network/networkd-dhcp6-bus.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include "sd-dhcp6-client.h" + +#include "networkd-link-bus.h" + +extern const BusObjectImplementation dhcp6_client_object; + +void dhcp6_client_callback_bus(sd_dhcp6_client *client, int event, void *userdata); diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index 95b13ca93c619..57e108721162c 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -5,11 +5,13 @@ #include "sd-dhcp6-client.h" +#include "dhcp6-client-internal.h" #include "hashmap.h" #include "hostname-setup.h" #include "hostname-util.h" #include "networkd-address.h" #include "networkd-dhcp-prefix-delegation.h" +#include "networkd-dhcp6-bus.h" #include "networkd-dhcp6.h" #include "networkd-link.h" #include "networkd-manager.h" @@ -699,6 +701,10 @@ static int dhcp6_configure(Link *link) { if (r < 0) return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set callback: %m"); + r = dhcp6_client_set_state_callback(client, dhcp6_client_callback_bus, link); + if (r < 0) + return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set state change callback: %m"); + r = sd_dhcp6_client_set_prefix_delegation(client, link->network->dhcp6_use_pd_prefix); if (r < 0) return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to %s requesting prefixes to be delegated: %m", diff --git a/src/network/networkd-link-bus.c b/src/network/networkd-link-bus.c index e9c18f0fd01de..0674930783263 100644 --- a/src/network/networkd-link-bus.c +++ b/src/network/networkd-link-bus.c @@ -862,6 +862,12 @@ int link_object_find(sd_bus *bus, const char *path, const char *interface, void (!link->dhcp_server || sd_dhcp_server_is_in_relay_mode(link->dhcp_server))) return 0; + if (streq(interface, "org.freedesktop.network1.DHCPv4Client") && !link->dhcp_client) + return 0; + + if (streq(interface, "org.freedesktop.network1.DHCPv6Client") && !link->dhcp6_client) + return 0; + *found = link; return 1; diff --git a/src/network/networkd-manager-bus.c b/src/network/networkd-manager-bus.c index 67f951df69d5e..7813a3173a593 100644 --- a/src/network/networkd-manager-bus.c +++ b/src/network/networkd-manager-bus.c @@ -9,6 +9,8 @@ #include "bus-message-util.h" #include "bus-polkit.h" #include "networkd-dhcp-server-bus.h" +#include "networkd-dhcp4-bus.h" +#include "networkd-dhcp6-bus.h" #include "networkd-json.h" #include "networkd-link-bus.h" #include "networkd-link.h" @@ -413,5 +415,6 @@ const BusObjectImplementation manager_object = { "/org/freedesktop/network1", "org.freedesktop.network1.Manager", .vtables = BUS_VTABLES(manager_vtable), - .children = BUS_IMPLEMENTATIONS(&dhcp_server_object, &link_object, &network_object), + .children = BUS_IMPLEMENTATIONS(&dhcp_server_object, &dhcp_client_object, + &dhcp6_client_object, &link_object, &network_object), }; diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index bc60e93850456..58bf23af501c2 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -5071,6 +5071,45 @@ def test_dhcp_client_ipv6_only(self): self.assertIn('DHCPREPLY(veth-peer)', output) self.assertNotIn('rapid-commit', output) + def test_dhcp_client_ipv6_dbus_status(self): + def get_dbus_dhcp6_client_state(IF): + out = subprocess.check_output(['busctl', 'call', 'org.freedesktop.network1', + '/org/freedesktop/network1', 'org.freedesktop.network1.Manager', + 'GetLinkByName', 's', IF]) + + assert out.startswith(b'io ') + out = out.strip() + assert out.endswith(b'"') + out = out.decode() + linkPath = out[:-1].split('"')[1] + + print(f"Found {IF} link path: {linkPath}") + + out = subprocess.check_output(['busctl', 'get-property', 'org.freedesktop.network1', + linkPath, 'org.freedesktop.network1.DHCPv6Client', 'State']) + assert out.startswith(b's "') + out = out.strip() + assert out.endswith(b'"') + return out[3:-1].decode() + + copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client-ipv6-only.network') + + start_networkd() + self.wait_online(['veth-peer:carrier']) + + # Note that at this point the DHCPv6 client has not been started because no RA (with managed + # bit set) has yet been recieved and the configuration does not include WithoutRA=true + state = get_dbus_dhcp6_client_state('veth99') + print(f"State = {state}") + self.assertEqual(state, 'stopped') + + start_dnsmasq() + self.wait_online(['veth99:routable', 'veth-peer:routable']) + + state = get_dbus_dhcp6_client_state('veth99') + print(f"State = {state}") + self.assertEqual(state, 'bound') + def test_dhcp_client_ipv6_only_with_custom_client_identifier(self): copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client-ipv6-only-custom-client-identifier.network') @@ -5224,6 +5263,47 @@ def test_dhcp_client_ipv4_only(self): self.teardown_nftset('addr4', 'network4', 'ifindex') + def test_dhcp_client_ipv4_dbus_status(self): + def get_dbus_dhcp4_client_state(IF): + out = subprocess.check_output(['busctl', 'call', 'org.freedesktop.network1', + '/org/freedesktop/network1', 'org.freedesktop.network1.Manager', + 'GetLinkByName', 's', IF]) + + assert out.startswith(b'io ') + out = out.strip() + assert out.endswith(b'"') + out = out.decode() + linkPath = out[:-1].split('"')[1] + + print(f"Found {IF} link path: {linkPath}") + + out = subprocess.check_output(['busctl', 'get-property', 'org.freedesktop.network1', + linkPath, 'org.freedesktop.network1.DHCPv4Client', 'State']) + assert out.startswith(b's "') + out = out.strip() + assert out.endswith(b'"') + return out[3:-1].decode() + + copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client-ipv4-only.network') + + start_networkd() + self.wait_online(['veth-peer:carrier']) + + state = get_dbus_dhcp4_client_state('veth99') + print(f"State = {state}") + self.assertEqual(state, 'selecting') + + start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7', + '--dhcp-option=option:domain-search,example.com', + '--dhcp-alternate-port=67,5555', + ipv4_range='192.168.5.110,192.168.5.119') + self.wait_online(['veth99:routable', 'veth-peer:routable']) + self.wait_address('veth99', r'inet 192.168.5.11[0-9]*/24', ipv='-4') + + state = get_dbus_dhcp4_client_state('veth99') + print(f"State = {state}") + self.assertEqual(state, 'bound') + def test_dhcp_client_ipv4_use_routes_gateway(self): first = True for (routes, gateway, dns_and_ntp_routes, classless) in itertools.product([True, False], repeat=4):