1
0
mirror of https://github.com/systemd/systemd synced 2026-03-25 08:14:54 +01:00

Compare commits

..

No commits in common. "836fb00f2190811c2bf804860f5afe1160d10eac" and "63c00743f448300783e1e5b648a57893695ee89f" have entirely different histories.

41 changed files with 729 additions and 952 deletions

9
TODO
View File

@ -83,15 +83,6 @@ Janitorial Clean-ups:
Features: Features:
* tpm2: figure out if we need to do anything for TPM2 parameter encryption? And
if so, what precisely?
* insert pkcs7 signature for verity gpt
* when mounting disk images: if IMAGE_ID/IMAGE_VERSION is set in os-release
data in the image, make sure the image filename actually matches this, so
that images cannot be misused.
* use credentials logic/TPM2 logic to store homed signing key * use credentials logic/TPM2 logic to store homed signing key
* New udev block device symlink names: * New udev block device symlink names:

View File

@ -188,15 +188,6 @@ Support: %SUPPORT_URL%
System shutdown has been initiated. The shutdown has now begun and System shutdown has been initiated. The shutdown has now begun and
all system services are terminated and all file systems unmounted. all system services are terminated and all file systems unmounted.
-- c14aaf76ec284a5fa1f105f88dfb061c
Subject: System factory reset initiated
Defined-By: systemd
Support: %SUPPORT_URL%
System factory reset has been initiated. The precise operation this
executes is implementation-defined, but typically has the effect of
reverting the system's state and configuration to vendor defaults.
-- 7d4958e842da4a758f6c1cdc7b36dcc5 -- 7d4958e842da4a758f6c1cdc7b36dcc5
Subject: A start job for unit @UNIT@ has begun execution Subject: A start job for unit @UNIT@ has begun execution
Defined-By: systemd Defined-By: systemd

View File

@ -216,9 +216,8 @@
<literal>suspend</literal>, <literal>suspend</literal>,
<literal>hibernate</literal>, <literal>hibernate</literal>,
<literal>hybrid-sleep</literal>, <literal>hybrid-sleep</literal>,
<literal>suspend-then-hibernate</literal>, <literal>suspend-then-hibernate</literal>, and
<literal>lock</literal>, and <literal>lock</literal>.
<literal>factory-reset</literal>.
If <literal>ignore</literal>, logind will never handle these If <literal>ignore</literal>, logind will never handle these
keys. If <literal>lock</literal>, all running sessions will be keys. If <literal>lock</literal>, all running sessions will be
screen-locked; otherwise, the specified action will be taken screen-locked; otherwise, the specified action will be taken

View File

@ -33,7 +33,6 @@
<filename>default.target</filename>, <filename>default.target</filename>,
<filename>emergency.target</filename>, <filename>emergency.target</filename>,
<filename>exit.target</filename>, <filename>exit.target</filename>,
<filename>factory-reset.target</filename>,
<filename>final.target</filename>, <filename>final.target</filename>,
<filename>first-boot-complete.target</filename>, <filename>first-boot-complete.target</filename>,
<filename>getty.target</filename>, <filename>getty.target</filename>,
@ -280,12 +279,6 @@
shutdown when the service manager starts to exit.</para> shutdown when the service manager starts to exit.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><filename>factory-reset.target</filename></term>
<listitem>
<para>A special target to trigger a factory reset.</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><filename>final.target</filename></term> <term><filename>final.target</filename></term>
<listitem> <listitem>

View File

@ -142,8 +142,11 @@
#define LIST_FOREACH_SAFE(name,i,n,head) \ #define LIST_FOREACH_SAFE(name,i,n,head) \
for ((i) = (head); (i) && (((n) = (i)->name##_next), 1); (i) = (n)) for ((i) = (head); (i) && (((n) = (i)->name##_next), 1); (i) = (n))
#define LIST_FOREACH_BACKWARDS(name,i,p) \ #define LIST_FOREACH_BEFORE(name,i,p) \
for ((i) = (p); (i); (i) = (i)->name##_prev) for ((i) = (p)->name##_prev; (i); (i) = (i)->name##_prev)
#define LIST_FOREACH_AFTER(name,i,p) \
for ((i) = (p)->name##_next; (i); (i) = (i)->name##_next)
/* Iterate through all the members of the list p is included in, but skip over p */ /* Iterate through all the members of the list p is included in, but skip over p */
#define LIST_FOREACH_OTHERS(name,i,p) \ #define LIST_FOREACH_OTHERS(name,i,p) \

View File

@ -20,7 +20,6 @@
#define SPECIAL_HIBERNATE_TARGET "hibernate.target" #define SPECIAL_HIBERNATE_TARGET "hibernate.target"
#define SPECIAL_HYBRID_SLEEP_TARGET "hybrid-sleep.target" #define SPECIAL_HYBRID_SLEEP_TARGET "hybrid-sleep.target"
#define SPECIAL_SUSPEND_THEN_HIBERNATE_TARGET "suspend-then-hibernate.target" #define SPECIAL_SUSPEND_THEN_HIBERNATE_TARGET "suspend-then-hibernate.target"
#define SPECIAL_FACTORY_RESET_TARGET "factory-reset.target"
/* Special boot targets */ /* Special boot targets */
#define SPECIAL_RESCUE_TARGET "rescue.target" #define SPECIAL_RESCUE_TARGET "rescue.target"

View File

@ -771,11 +771,11 @@ static Unit *device_following(Unit *u) {
return NULL; return NULL;
/* Make everybody follow the unit that's named after the sysfs path */ /* Make everybody follow the unit that's named after the sysfs path */
LIST_FOREACH(same_sysfs, other, d->same_sysfs_next) LIST_FOREACH_AFTER(same_sysfs, other, d)
if (startswith(UNIT(other)->id, "sys-")) if (startswith(UNIT(other)->id, "sys-"))
return UNIT(other); return UNIT(other);
LIST_FOREACH_BACKWARDS(same_sysfs, other, d->same_sysfs_prev) { LIST_FOREACH_BEFORE(same_sysfs, other, d) {
if (startswith(UNIT(other)->id, "sys-")) if (startswith(UNIT(other)->id, "sys-"))
return UNIT(other); return UNIT(other);
@ -802,13 +802,13 @@ static int device_following_set(Unit *u, Set **_set) {
if (!set) if (!set)
return -ENOMEM; return -ENOMEM;
LIST_FOREACH(same_sysfs, other, d->same_sysfs_next) { LIST_FOREACH_AFTER(same_sysfs, other, d) {
r = set_put(set, other); r = set_put(set, other);
if (r < 0) if (r < 0)
return r; return r;
} }
LIST_FOREACH_BACKWARDS(same_sysfs, other, d->same_sysfs_prev) { LIST_FOREACH_BEFORE(same_sysfs, other, d) {
r = set_put(set, other); r = set_put(set, other);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -1323,11 +1323,11 @@ static Unit *swap_following(Unit *u) {
if (streq_ptr(s->what, s->devnode)) if (streq_ptr(s->what, s->devnode))
return NULL; return NULL;
LIST_FOREACH(same_devnode, other, s->same_devnode_next) LIST_FOREACH_AFTER(same_devnode, other, s)
if (streq_ptr(other->what, other->devnode)) if (streq_ptr(other->what, other->devnode))
return UNIT(other); return UNIT(other);
LIST_FOREACH_BACKWARDS(same_devnode, other, s->same_devnode_prev) { LIST_FOREACH_BEFORE(same_devnode, other, s) {
if (streq_ptr(other->what, other->devnode)) if (streq_ptr(other->what, other->devnode))
return UNIT(other); return UNIT(other);

View File

@ -451,10 +451,6 @@ static int add_mount(
"\n" "\n"
"[Mount]\n"); "[Mount]\n");
r = write_what(f, what);
if (r < 0)
return r;
if (original_where) if (original_where)
fprintf(f, "# Canonicalized from %s\n", original_where); fprintf(f, "# Canonicalized from %s\n", original_where);
@ -463,6 +459,10 @@ static int add_mount(
return log_oom(); return log_oom();
fprintf(f, "Where=%s\n", where_escaped); fprintf(f, "Where=%s\n", where_escaped);
r = write_what(f, what);
if (r < 0)
return r;
if (!isempty(fstype) && !streq(fstype, "auto")) { if (!isempty(fstype) && !streq(fstype, "auto")) {
_cleanup_free_ char *t = NULL; _cleanup_free_ char *t = NULL;

View File

@ -27,7 +27,6 @@ const char* manager_target_for_action(HandleAction handle) {
[HANDLE_HIBERNATE] = SPECIAL_HIBERNATE_TARGET, [HANDLE_HIBERNATE] = SPECIAL_HIBERNATE_TARGET,
[HANDLE_HYBRID_SLEEP] = SPECIAL_HYBRID_SLEEP_TARGET, [HANDLE_HYBRID_SLEEP] = SPECIAL_HYBRID_SLEEP_TARGET,
[HANDLE_SUSPEND_THEN_HIBERNATE] = SPECIAL_SUSPEND_THEN_HIBERNATE_TARGET, [HANDLE_SUSPEND_THEN_HIBERNATE] = SPECIAL_SUSPEND_THEN_HIBERNATE_TARGET,
[HANDLE_FACTORY_RESET] = SPECIAL_FACTORY_RESET_TARGET,
}; };
assert(handle >= 0); assert(handle >= 0);
@ -52,7 +51,6 @@ int manager_handle_action(
[HANDLE_HIBERNATE] = "Hibernating...", [HANDLE_HIBERNATE] = "Hibernating...",
[HANDLE_HYBRID_SLEEP] = "Hibernating and suspending...", [HANDLE_HYBRID_SLEEP] = "Hibernating and suspending...",
[HANDLE_SUSPEND_THEN_HIBERNATE] = "Suspending, then hibernating...", [HANDLE_SUSPEND_THEN_HIBERNATE] = "Suspending, then hibernating...",
[HANDLE_FACTORY_RESET] = "Performing factory reset...",
}; };
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
@ -181,7 +179,6 @@ static const char* const handle_action_table[_HANDLE_ACTION_MAX] = {
[HANDLE_HIBERNATE] = "hibernate", [HANDLE_HIBERNATE] = "hibernate",
[HANDLE_HYBRID_SLEEP] = "hybrid-sleep", [HANDLE_HYBRID_SLEEP] = "hybrid-sleep",
[HANDLE_SUSPEND_THEN_HIBERNATE] = "suspend-then-hibernate", [HANDLE_SUSPEND_THEN_HIBERNATE] = "suspend-then-hibernate",
[HANDLE_FACTORY_RESET] = "factory-reset",
[HANDLE_LOCK] = "lock", [HANDLE_LOCK] = "lock",
}; };

View File

@ -14,7 +14,6 @@ typedef enum HandleAction {
HANDLE_HYBRID_SLEEP, HANDLE_HYBRID_SLEEP,
HANDLE_SUSPEND_THEN_HIBERNATE, HANDLE_SUSPEND_THEN_HIBERNATE,
HANDLE_LOCK, HANDLE_LOCK,
HANDLE_FACTORY_RESET,
_HANDLE_ACTION_MAX, _HANDLE_ACTION_MAX,
_HANDLE_ACTION_INVALID = -EINVAL, _HANDLE_ACTION_INVALID = -EINVAL,
} HandleAction; } HandleAction;

View File

@ -1491,59 +1491,41 @@ static int have_multiple_sessions(
return false; return false;
} }
_printf_(2, 0) static int bus_manager_log_shutdown(
static int log_with_wall_message(Manager *m, const char *d, const char *p, const char *q) { Manager *m,
const char *unit_name) {
const char *p, *q;
assert(m); assert(m);
assert(unit_name);
if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
p = "MESSAGE=System is powering down";
q = "SHUTDOWN=power-off";
} else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
p = "MESSAGE=System is rebooting";
q = "SHUTDOWN=reboot";
} else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
p = "MESSAGE=System is halting";
q = "SHUTDOWN=halt";
} else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
p = "MESSAGE=System is rebooting with kexec";
q = "SHUTDOWN=kexec";
} else {
p = "MESSAGE=System is shutting down";
q = NULL;
}
if (isempty(m->wall_message)) if (isempty(m->wall_message))
p = strjoina(p, "."); p = strjoina(p, ".");
else else
p = strjoina(p, " (", m->wall_message, ")."); p = strjoina(p, " (", m->wall_message, ").");
return log_struct(LOG_NOTICE, d, p, q); return log_struct(LOG_NOTICE,
}
static int bus_manager_log_shutdown(
Manager *m,
const char *unit_name) {
assert(m);
assert(unit_name);
if (streq(unit_name, SPECIAL_POWEROFF_TARGET))
return log_with_wall_message(m,
"MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_STR, "MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_STR,
"MESSAGE=System is powering down", p,
"SHUTDOWN=power-off"); q);
if (streq(unit_name, SPECIAL_REBOOT_TARGET))
return log_with_wall_message(m,
"MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_STR,
"MESSAGE=System is rebooting",
"SHUTDOWN=reboot");
if (streq(unit_name, SPECIAL_HALT_TARGET))
return log_with_wall_message(m,
"MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_STR,
"MESSAGE=System is halting",
"SHUTDOWN=halt");
if (streq(unit_name, SPECIAL_KEXEC_TARGET))
return log_with_wall_message(m,
"MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_STR,
"MESSAGE=System is rebooting with kexec",
"SHUTDOWN=kexec");
if (streq(unit_name, SPECIAL_FACTORY_RESET_TARGET))
return log_with_wall_message(m,
"MESSAGE_ID=" SD_MESSAGE_FACTORY_RESET_STR,
"MESSAGE=System is performing factory reset",
NULL);
return log_with_wall_message(m,
"MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_STR,
"MESSAGE=System is shutting down",
NULL);
} }
static int lid_switch_ignore_handler(sd_event_source *e, uint64_t usec, void *userdata) { static int lid_switch_ignore_handler(sd_event_source *e, uint64_t usec, void *userdata) {

View File

@ -96,64 +96,113 @@ const DUID *link_get_duid(Link *link, int family) {
return duid; return duid;
} }
static int link_configure_and_start_dhcp_delayed(Link *link) {
int r;
assert(link);
if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
return 0;
if (!link->dhcp_client) {
r = dhcp4_configure(link);
if (r < 0)
return r;
}
if (!link->dhcp6_client) {
r = dhcp6_configure(link);
if (r < 0)
return r;
}
if (link->set_flags_messages > 0)
return 0;
if (!link_has_carrier(link))
return 0;
r = dhcp4_start(link);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to start DHCPv4 client: %m");
r = ndisc_start(link);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to start IPv6 Router Discovery: %m");
r = dhcp6_start(link);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to start DHCPv6 client: %m");
return 0;
}
static int get_product_uuid_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { static int get_product_uuid_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
Manager *manager = userdata; Manager *manager = userdata;
const sd_bus_error *e; const sd_bus_error *e;
const void *a; const void *a;
size_t sz; size_t sz;
Link *link;
int r; int r;
assert(m); assert(m);
assert(manager); assert(manager);
/* To avoid calling GetProductUUID() bus method so frequently, set the flag below
* even if the method fails. */
manager->has_product_uuid = true;
e = sd_bus_message_get_error(m); e = sd_bus_message_get_error(m);
if (e) { if (e) {
r = sd_bus_error_get_errno(e); r = sd_bus_error_get_errno(e);
log_warning_errno(r, "Could not get product UUID. Falling back to use machine-app-specific ID as DUID-UUID: %s", log_warning_errno(r, "Could not get product UUID. Falling back to use machine-app-specific ID as DUID-UUID: %s",
bus_error_message(e, r)); bus_error_message(e, r));
return 0; goto configure;
} }
r = sd_bus_message_read_array(m, 'y', &a, &sz); r = sd_bus_message_read_array(m, 'y', &a, &sz);
if (r < 0) { if (r < 0) {
log_warning_errno(r, "Failed to get product UUID. Falling back to use machine-app-specific ID as DUID-UUID: %m"); log_warning_errno(r, "Failed to get product UUID. Falling back to use machine-app-specific ID as DUID-UUID: %m");
return 0; goto configure;
} }
if (sz != sizeof(sd_id128_t)) { if (sz != sizeof(sd_id128_t)) {
log_warning("Invalid product UUID. Falling back to use machine-app-specific ID as DUID-UUID."); log_warning("Invalid product UUID. Falling back to use machine-app-specific ID as DUID-UUID.");
return 0; goto configure;
} }
log_debug("Successfully obtained product UUID");
memcpy(&manager->duid_product_uuid.raw_data, a, sz); memcpy(&manager->duid_product_uuid.raw_data, a, sz);
manager->duid_product_uuid.raw_data_len = sz; manager->duid_product_uuid.raw_data_len = sz;
return 0; configure:
/* To avoid calling GetProductUUID() bus method so frequently, set the flag below
* even if the method fails. */
manager->has_product_uuid = true;
while ((link = set_steal_first(manager->links_requesting_uuid))) {
r = link_configure_and_start_dhcp_delayed(link);
if (r < 0)
link_enter_failed(link);
link_unref(link);
}
manager->links_requesting_uuid = set_free(manager->links_requesting_uuid);
return 1;
} }
int manager_request_product_uuid(Manager *m) { int manager_request_product_uuid(Manager *m) {
static bool bus_method_is_called = false;
int r; int r;
assert(m); assert(m);
if (bus_method_is_called) if (m->product_uuid_requested)
return 0; return 0;
if (sd_bus_is_ready(m->bus) <= 0 && !m->product_uuid_requested) { log_debug("Requesting product UUID");
if (sd_bus_is_ready(m->bus) <= 0) {
log_debug("Not connected to system bus, requesting product UUID later."); log_debug("Not connected to system bus, requesting product UUID later.");
m->product_uuid_requested = true;
return 0; return 0;
} }
m->product_uuid_requested = false;
r = sd_bus_call_method_async( r = sd_bus_call_method_async(
m->bus, m->bus,
NULL, NULL,
@ -168,9 +217,7 @@ int manager_request_product_uuid(Manager *m) {
if (r < 0) if (r < 0)
return log_warning_errno(r, "Failed to get product UUID: %m"); return log_warning_errno(r, "Failed to get product UUID: %m");
log_debug("Requesting product UUID."); m->product_uuid_requested = true;
bus_method_is_called = true;
return 0; return 0;
} }
@ -195,11 +242,15 @@ int dhcp_configure_duid(Link *link, const DUID *duid) {
if (r < 0) { if (r < 0) {
log_link_warning_errno(link, r, log_link_warning_errno(link, r,
"Failed to get product UUID. Falling back to use machine-app-specific ID as DUID-UUID: %m"); "Failed to get product UUID. Falling back to use machine-app-specific ID as DUID-UUID: %m");
m->has_product_uuid = true; /* Do not request UUID again on failure. */
return 1; return 1;
} }
r = set_ensure_put(&m->links_requesting_uuid, NULL, link);
if (r < 0)
return log_oom();
if (r > 0)
link_ref(link);
return 0; return 0;
} }
@ -492,8 +543,8 @@ int config_parse_iaid(const char *unit,
network->dhcp_iaid = iaid; network->dhcp_iaid = iaid;
network->dhcp_iaid_set = true; network->dhcp_iaid_set = true;
if (!network->dhcp6_iaid_set_explicitly) { if (!network->dhcp6_iaid_set_explicitly) {
/* Backward compatibility. Previously, IAID is shared by DHCPv4 and DHCPv6. /* Backward compatibility. Previously, IAID is shared by DHCP4 and DHCP6.
* If DHCPv6 IAID is not specified explicitly, then use DHCPv4 IAID for DHCPv6. */ * If DHCP6 IAID is not specified explicitly, then use DHCP4 IAID for DHCP6. */
network->dhcp6_iaid = iaid; network->dhcp6_iaid = iaid;
network->dhcp6_iaid_set = true; network->dhcp6_iaid_set = true;
} }
@ -985,7 +1036,7 @@ int config_parse_manager_duid_type(
assert(manager); assert(manager);
/* For backward compatibility. Setting both DHCPv4 and DHCPv6 DUID if they are not specified explicitly. */ /* For backward compatibility. Setting both DHCP4 and DHCP6 DUID if they are not specified explicitly. */
r = config_parse_duid_type(unit, filename, line, section, section_line, lvalue, false, rvalue, &manager->dhcp_duid, manager); r = config_parse_duid_type(unit, filename, line, section, section_line, lvalue, false, rvalue, &manager->dhcp_duid, manager);
if (r < 0) if (r < 0)
@ -1015,7 +1066,7 @@ int config_parse_network_duid_type(
if (r < 0) if (r < 0)
return r; return r;
/* For backward compatibility, also set DHCPv6 DUID if not specified explicitly. */ /* For backward compatibility, also set DHCP6 DUID if not specified explicitly. */
return config_parse_duid_type(unit, filename, line, section, section_line, lvalue, false, rvalue, &network->dhcp6_duid, network); return config_parse_duid_type(unit, filename, line, section, section_line, lvalue, false, rvalue, &network->dhcp6_duid, network);
} }
@ -1110,7 +1161,7 @@ int config_parse_manager_duid_rawdata(
assert(manager); assert(manager);
/* For backward compatibility. Setting both DHCPv4 and DHCPv6 DUID if they are not specified explicitly. */ /* For backward compatibility. Setting both DHCP4 and DHCP6 DUID if they are not specified explicitly. */
r = config_parse_duid_rawdata(unit, filename, line, section, section_line, lvalue, false, rvalue, &manager->dhcp_duid, manager); r = config_parse_duid_rawdata(unit, filename, line, section, section_line, lvalue, false, rvalue, &manager->dhcp_duid, manager);
if (r < 0) if (r < 0)
@ -1140,6 +1191,6 @@ int config_parse_network_duid_rawdata(
if (r < 0) if (r < 0)
return r; return r;
/* For backward compatibility, also set DHCPv6 DUID if not specified explicitly. */ /* For backward compatibility, also set DHCP6 DUID if not specified explicitly. */
return config_parse_duid_rawdata(unit, filename, line, section, section_line, lvalue, false, rvalue, &network->dhcp6_duid, network); return config_parse_duid_rawdata(unit, filename, line, section, section_line, lvalue, false, rvalue, &network->dhcp6_duid, network);
} }

View File

@ -1311,7 +1311,7 @@ static int dhcp4_set_hostname(Link *link) {
else { else {
r = gethostname_strict(&hostname); r = gethostname_strict(&hostname);
if (r < 0 && r != -ENXIO) /* ENXIO: no hostname set or hostname is "localhost" */ if (r < 0 && r != -ENXIO) /* ENXIO: no hostname set or hostname is "localhost" */
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to get hostname: %m"); return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to get hostname: %m");
hn = hostname; hn = hostname;
} }
@ -1319,9 +1319,9 @@ static int dhcp4_set_hostname(Link *link) {
r = sd_dhcp_client_set_hostname(link->dhcp_client, hn); r = sd_dhcp_client_set_hostname(link->dhcp_client, hn);
if (r == -EINVAL && hostname) if (r == -EINVAL && hostname)
/* Ignore error when the machine's hostname is not suitable to send in DHCP packet. */ /* Ignore error when the machine's hostname is not suitable to send in DHCP packet. */
log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set hostname from kernel hostname, ignoring: %m"); log_link_debug_errno(link, r, "DHCP4 CLIENT: Failed to set hostname from kernel hostname, ignoring: %m");
else if (r < 0) else if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set hostname: %m"); return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set hostname: %m");
return 0; return 0;
} }
@ -1351,7 +1351,7 @@ static int dhcp4_set_client_identifier(Link *link) {
duid->raw_data_len > 0 ? duid->raw_data : NULL, duid->raw_data_len > 0 ? duid->raw_data : NULL,
duid->raw_data_len); duid->raw_data_len);
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set IAID+DUID: %m"); return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set IAID+DUID: %m");
break; break;
} }
case DHCP_CLIENT_ID_DUID_ONLY: { case DHCP_CLIENT_ID_DUID_ONLY: {
@ -1367,7 +1367,7 @@ static int dhcp4_set_client_identifier(Link *link) {
duid->raw_data_len > 0 ? duid->raw_data : NULL, duid->raw_data_len > 0 ? duid->raw_data : NULL,
duid->raw_data_len); duid->raw_data_len);
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set DUID: %m"); return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set DUID: %m");
break; break;
} }
case DHCP_CLIENT_ID_MAC: { case DHCP_CLIENT_ID_MAC: {
@ -1385,7 +1385,7 @@ static int dhcp4_set_client_identifier(Link *link) {
hw_addr, hw_addr,
hw_addr_len); hw_addr_len);
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set client ID: %m"); return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set client ID: %m");
break; break;
} }
default: default:
@ -1395,6 +1395,15 @@ static int dhcp4_set_client_identifier(Link *link) {
return 0; return 0;
} }
static int dhcp4_configure_duid(Link *link) {
assert(link);
if (!IN_SET(link->network->dhcp_client_identifier, DHCP_CLIENT_ID_DUID, DHCP_CLIENT_ID_DUID_ONLY))
return 1;
return dhcp_configure_duid(link, link_get_dhcp4_duid(link));
}
static int dhcp4_set_request_address(Link *link) { static int dhcp4_set_request_address(Link *link) {
Address *a; Address *a;
@ -1415,7 +1424,7 @@ static int dhcp4_set_request_address(Link *link) {
if (!a) if (!a)
return 0; return 0;
log_link_debug(link, "DHCPv4 CLIENT: requesting " IPV4_ADDRESS_FMT_STR, IPV4_ADDRESS_FMT_VAL(a->in_addr.in)); log_link_debug(link, "DHCP4 CLIENT: requesting " IPV4_ADDRESS_FMT_STR, IPV4_ADDRESS_FMT_VAL(a->in_addr.in));
return sd_dhcp_client_set_request_address(link->dhcp_client, &a->in_addr.in); return sd_dhcp_client_set_request_address(link->dhcp_client, &a->in_addr.in);
} }
@ -1436,15 +1445,15 @@ static bool link_needs_dhcp_broadcast(Link *link) {
if (r < 0 && link->sd_device && sd_device_get_property_value(link->sd_device, "ID_NET_DHCP_BROADCAST", &val) >= 0) { if (r < 0 && link->sd_device && sd_device_get_property_value(link->sd_device, "ID_NET_DHCP_BROADCAST", &val) >= 0) {
r = parse_boolean(val); r = parse_boolean(val);
if (r < 0) if (r < 0)
log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to parse ID_NET_DHCP_BROADCAST, ignoring: %m"); log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to parse ID_NET_DHCP_BROADCAST, ignoring: %m");
else else
log_link_debug(link, "DHCPv4 CLIENT: Detected ID_NET_DHCP_BROADCAST='%d'.", r); log_link_debug(link, "DHCP4 CLIENT: Detected ID_NET_DHCP_BROADCAST='%d'.", r);
} }
return r == true; return r == true;
} }
static int dhcp4_configure(Link *link) { int dhcp4_configure(Link *link) {
sd_dhcp_option *send_option; sd_dhcp_option *send_option;
void *request_options; void *request_options;
int r; int r;
@ -1452,81 +1461,88 @@ static int dhcp4_configure(Link *link) {
assert(link); assert(link);
assert(link->network); assert(link->network);
if (!link_dhcp4_enabled(link))
return 0;
if (link->dhcp_client) if (link->dhcp_client)
return log_link_debug_errno(link, SYNTHETIC_ERRNO(EBUSY), "DHCPv4 client is already configured."); return -EBUSY; /* Already configured. */
r = dhcp4_configure_duid(link);
if (r <= 0)
return r;
r = sd_dhcp_client_new(&link->dhcp_client, link->network->dhcp_anonymize); r = sd_dhcp_client_new(&link->dhcp_client, link->network->dhcp_anonymize);
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to allocate DHCPv4 client: %m"); return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to allocate DHCP4 client: %m");
r = sd_dhcp_client_attach_event(link->dhcp_client, link->manager->event, 0); r = sd_dhcp_client_attach_event(link->dhcp_client, link->manager->event, 0);
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to attach event to DHCPv4 client: %m"); return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to attach event to DHCP4 client: %m");
r = sd_dhcp_client_set_mac(link->dhcp_client, r = sd_dhcp_client_set_mac(link->dhcp_client,
link->hw_addr.bytes, link->hw_addr.bytes,
link->bcast_addr.length > 0 ? link->bcast_addr.bytes : NULL, link->bcast_addr.length > 0 ? link->bcast_addr.bytes : NULL,
link->hw_addr.length, link->iftype); link->hw_addr.length, link->iftype);
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set MAC address: %m"); return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set MAC address: %m");
r = sd_dhcp_client_set_ifindex(link->dhcp_client, link->ifindex); r = sd_dhcp_client_set_ifindex(link->dhcp_client, link->ifindex);
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set ifindex: %m"); return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set ifindex: %m");
r = sd_dhcp_client_set_callback(link->dhcp_client, dhcp4_handler, link); r = sd_dhcp_client_set_callback(link->dhcp_client, dhcp4_handler, link);
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set callback: %m"); return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set callback: %m");
r = sd_dhcp_client_set_request_broadcast(link->dhcp_client, link_needs_dhcp_broadcast(link)); r = sd_dhcp_client_set_request_broadcast(link->dhcp_client, link_needs_dhcp_broadcast(link));
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for broadcast: %m"); return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for broadcast: %m");
if (link->mtu > 0) { if (link->mtu > 0) {
r = sd_dhcp_client_set_mtu(link->dhcp_client, link->mtu); r = sd_dhcp_client_set_mtu(link->dhcp_client, link->mtu);
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set MTU: %m"); return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set MTU: %m");
} }
if (!link->network->dhcp_anonymize) { if (!link->network->dhcp_anonymize) {
if (link->network->dhcp_use_mtu) { if (link->network->dhcp_use_mtu) {
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_INTERFACE_MTU); r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_INTERFACE_MTU);
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for MTU: %m"); return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for MTU: %m");
} }
if (link->network->dhcp_use_routes) { if (link->network->dhcp_use_routes) {
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_STATIC_ROUTE); r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_STATIC_ROUTE);
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for static route: %m"); return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for static route: %m");
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE); r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE);
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for classless static route: %m"); return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for classless static route: %m");
} }
if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) { if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) {
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_DOMAIN_SEARCH_LIST); r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_DOMAIN_SEARCH_LIST);
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for domain search list: %m"); return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for domain search list: %m");
} }
if (link->network->dhcp_use_ntp) { if (link->network->dhcp_use_ntp) {
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NTP_SERVER); r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NTP_SERVER);
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for NTP server: %m"); return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for NTP server: %m");
} }
if (link->network->dhcp_use_sip) { if (link->network->dhcp_use_sip) {
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_SIP_SERVER); r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_SIP_SERVER);
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for SIP server: %m"); return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for SIP server: %m");
} }
if (link->network->dhcp_use_timezone) { if (link->network->dhcp_use_timezone) {
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NEW_TZDB_TIMEZONE); r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NEW_TZDB_TIMEZONE);
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for timezone: %m"); return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for timezone: %m");
} }
SET_FOREACH(request_options, link->network->dhcp_request_options) { SET_FOREACH(request_options, link->network->dhcp_request_options) {
@ -1534,7 +1550,7 @@ static int dhcp4_configure(Link *link) {
r = sd_dhcp_client_set_request_option(link->dhcp_client, option); r = sd_dhcp_client_set_request_option(link->dhcp_client, option);
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for '%u': %m", option); return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for '%u': %m", option);
} }
ORDERED_HASHMAP_FOREACH(send_option, link->network->dhcp_client_send_options) { ORDERED_HASHMAP_FOREACH(send_option, link->network->dhcp_client_send_options) {
@ -1542,7 +1558,7 @@ static int dhcp4_configure(Link *link) {
if (r == -EEXIST) if (r == -EEXIST)
continue; continue;
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set send option: %m"); return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set send option: %m");
} }
ORDERED_HASHMAP_FOREACH(send_option, link->network->dhcp_client_send_vendor_options) { ORDERED_HASHMAP_FOREACH(send_option, link->network->dhcp_client_send_vendor_options) {
@ -1550,7 +1566,7 @@ static int dhcp4_configure(Link *link) {
if (r == -EEXIST) if (r == -EEXIST)
continue; continue;
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set send option: %m"); return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set send option: %m");
} }
r = dhcp4_set_hostname(link); r = dhcp4_set_hostname(link);
@ -1561,49 +1577,49 @@ static int dhcp4_configure(Link *link) {
r = sd_dhcp_client_set_vendor_class_identifier(link->dhcp_client, r = sd_dhcp_client_set_vendor_class_identifier(link->dhcp_client,
link->network->dhcp_vendor_class_identifier); link->network->dhcp_vendor_class_identifier);
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set vendor class identifier: %m"); return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set vendor class identifier: %m");
} }
if (link->network->dhcp_mudurl) { if (link->network->dhcp_mudurl) {
r = sd_dhcp_client_set_mud_url(link->dhcp_client, link->network->dhcp_mudurl); r = sd_dhcp_client_set_mud_url(link->dhcp_client, link->network->dhcp_mudurl);
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set MUD URL: %m"); return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set MUD URL: %m");
} }
if (link->network->dhcp_user_class) { if (link->network->dhcp_user_class) {
r = sd_dhcp_client_set_user_class(link->dhcp_client, link->network->dhcp_user_class); r = sd_dhcp_client_set_user_class(link->dhcp_client, link->network->dhcp_user_class);
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set user class: %m"); return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set user class: %m");
} }
} }
if (link->network->dhcp_client_port > 0) { if (link->network->dhcp_client_port > 0) {
r = sd_dhcp_client_set_client_port(link->dhcp_client, link->network->dhcp_client_port); r = sd_dhcp_client_set_client_port(link->dhcp_client, link->network->dhcp_client_port);
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set listen port: %m"); return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set listen port: %m");
} }
if (link->network->dhcp_max_attempts > 0) { if (link->network->dhcp_max_attempts > 0) {
r = sd_dhcp_client_set_max_attempts(link->dhcp_client, link->network->dhcp_max_attempts); r = sd_dhcp_client_set_max_attempts(link->dhcp_client, link->network->dhcp_max_attempts);
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set max attempts: %m"); return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set max attempts: %m");
} }
if (link->network->dhcp_ip_service_type > 0) { if (link->network->dhcp_ip_service_type > 0) {
r = sd_dhcp_client_set_service_type(link->dhcp_client, link->network->dhcp_ip_service_type); r = sd_dhcp_client_set_service_type(link->dhcp_client, link->network->dhcp_ip_service_type);
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set IP service type: %m"); return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set IP service type: %m");
} }
if (link->network->dhcp_fallback_lease_lifetime > 0) { if (link->network->dhcp_fallback_lease_lifetime > 0) {
r = sd_dhcp_client_set_fallback_lease_lifetime(link->dhcp_client, link->network->dhcp_fallback_lease_lifetime); r = sd_dhcp_client_set_fallback_lease_lifetime(link->dhcp_client, link->network->dhcp_fallback_lease_lifetime);
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed set to lease lifetime: %m"); return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed set to lease lifetime: %m");
} }
r = dhcp4_set_request_address(link); r = dhcp4_set_request_address(link);
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set initial DHCPv4 address: %m"); return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set initial DHCPv4 address: %m");
return dhcp4_set_client_identifier(link); return dhcp4_set_client_identifier(link);
} }
@ -1626,83 +1642,17 @@ int dhcp4_update_mac(Link *link) {
} }
int dhcp4_start(Link *link) { int dhcp4_start(Link *link) {
int r;
assert(link); assert(link);
if (!link->dhcp_client) if (!link->dhcp_client)
return 0; return 0;
if (!link_has_carrier(link))
return 0;
if (sd_dhcp_client_is_running(link->dhcp_client) > 0) if (sd_dhcp_client_is_running(link->dhcp_client) > 0)
return 0; return 0;
r = sd_dhcp_client_start(link->dhcp_client); log_link_debug(link, "Acquiring DHCPv4 lease");
if (r < 0)
return r;
return 1; return sd_dhcp_client_start(link->dhcp_client);
}
static int dhcp4_configure_duid(Link *link) {
assert(link);
if (!IN_SET(link->network->dhcp_client_identifier, DHCP_CLIENT_ID_DUID, DHCP_CLIENT_ID_DUID_ONLY))
return 1;
return dhcp_configure_duid(link, link_get_dhcp4_duid(link));
}
int request_process_dhcp4_client(Request *req) {
Link *link;
int r;
assert(req);
assert(req->link);
assert(req->type == REQUEST_TYPE_DHCP4_CLIENT);
link = req->link;
if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
return 0;
r = dhcp4_configure_duid(link);
if (r <= 0)
return r;
r = dhcp4_configure(req->link);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to configure DHCPv4 client: %m");
r = dhcp4_start(link);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to start DHCPv4 client: %m");
log_link_debug(link, "DHCPv4 client is configured%s.",
r > 0 ? ", acquiring DHCPv4 lease" : "");
return 1;
}
int link_request_dhcp4_client(Link *link) {
int r;
assert(link);
if (!link_dhcp4_enabled(link))
return 0;
if (link->dhcp_client)
return 0;
r = link_queue_request(link, REQUEST_TYPE_DHCP4_CLIENT, NULL, false, NULL, NULL, NULL);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to request configuring of the DHCPv4 client: %m");
log_link_debug(link, "Requested configuring of the DHCPv4 client.");
return 0;
} }
int config_parse_dhcp_max_attempts( int config_parse_dhcp_max_attempts(

View File

@ -4,8 +4,6 @@
#include "conf-parser.h" #include "conf-parser.h"
typedef struct Link Link; typedef struct Link Link;
typedef struct Network Network;
typedef struct Request Request;
typedef enum DHCPClientIdentifier { typedef enum DHCPClientIdentifier {
DHCP_CLIENT_ID_MAC, DHCP_CLIENT_ID_MAC,
@ -20,13 +18,11 @@ typedef enum DHCPClientIdentifier {
} DHCPClientIdentifier; } DHCPClientIdentifier;
void network_adjust_dhcp4(Network *network); void network_adjust_dhcp4(Network *network);
int dhcp4_configure(Link *link);
int dhcp4_update_mac(Link *link); int dhcp4_update_mac(Link *link);
int dhcp4_start(Link *link); int dhcp4_start(Link *link);
int dhcp4_lease_lost(Link *link); int dhcp4_lease_lost(Link *link);
int request_process_dhcp4_client(Request *req);
int link_request_dhcp4_client(Link *link);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_client_identifier); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_client_identifier);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_acl_ip_address); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_acl_ip_address);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_max_attempts); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_max_attempts);

View File

@ -920,7 +920,7 @@ static int dhcp6_pd_prefix_add(Link *link, const struct in6_addr *prefix, uint8_
log_link_full(link, log_link_full(link,
set_contains(link->dhcp6_pd_prefixes, p) ? LOG_DEBUG : set_contains(link->dhcp6_pd_prefixes, p) ? LOG_DEBUG :
prefixlen > 64 || prefixlen < 48 ? LOG_WARNING : LOG_INFO, prefixlen > 64 || prefixlen < 48 ? LOG_WARNING : LOG_INFO,
"DHCPv6: received PD Prefix %s%s", "DHCP6: received PD Prefix %s%s",
strna(buf), strna(buf),
prefixlen > 64 ? " with prefix length > 64, ignoring." : prefixlen > 64 ? " with prefix length > 64, ignoring." :
prefixlen < 48 ? " with prefix length < 48, looks unusual.": ""); prefixlen < 48 ? " with prefix length < 48, looks unusual.": "");
@ -928,7 +928,7 @@ static int dhcp6_pd_prefix_add(Link *link, const struct in6_addr *prefix, uint8_
/* Store PD prefix even if prefixlen > 64, not to make logged at warning level so frequently. */ /* Store PD prefix even if prefixlen > 64, not to make logged at warning level so frequently. */
r = set_ensure_put(&link->dhcp6_pd_prefixes, &in_addr_prefix_hash_ops_free, p); r = set_ensure_put(&link->dhcp6_pd_prefixes, &in_addr_prefix_hash_ops_free, p);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Failed to store DHCPv6 PD prefix %s: %m", strna(buf)); return log_link_error_errno(link, r, "Failed to store DHCP6 PD prefix %s: %m", strna(buf));
if (r > 0) if (r > 0)
TAKE_PTR(p); TAKE_PTR(p);
@ -1393,8 +1393,6 @@ int dhcp6_request_information(Link *link, int ir) {
} }
int dhcp6_start(Link *link) { int dhcp6_start(Link *link) {
int r;
assert(link); assert(link);
if (!link->dhcp6_client) if (!link->dhcp6_client)
@ -1403,9 +1401,6 @@ int dhcp6_start(Link *link) {
if (!link_dhcp6_enabled(link)) if (!link_dhcp6_enabled(link))
return 0; return 0;
if (!link_has_carrier(link))
return 0;
if (link->network->dhcp6_without_ra == DHCP6_CLIENT_START_MODE_NO) if (link->network->dhcp6_without_ra == DHCP6_CLIENT_START_MODE_NO)
return 0; return 0;
@ -1417,11 +1412,9 @@ int dhcp6_start(Link *link) {
if (sd_dhcp6_client_is_running(link->dhcp6_client) > 0) if (sd_dhcp6_client_is_running(link->dhcp6_client) > 0)
return 0; return 0;
r = dhcp6_request_information(link, link->network->dhcp6_without_ra == DHCP6_CLIENT_START_MODE_INFORMATION_REQUEST); log_link_debug(link, "Acquiring DHCPv6 lease");
if (r < 0)
return r;
return 1; return dhcp6_request_information(link, link->network->dhcp6_without_ra == DHCP6_CLIENT_START_MODE_INFORMATION_REQUEST);
} }
int dhcp6_request_prefix_delegation(Link *link) { int dhcp6_request_prefix_delegation(Link *link) {
@ -1512,7 +1505,7 @@ static int dhcp6_set_hostname(sd_dhcp6_client *client, Link *link) {
else { else {
r = gethostname_strict(&hostname); r = gethostname_strict(&hostname);
if (r < 0 && r != -ENXIO) /* ENXIO: no hostname set or hostname is "localhost" */ if (r < 0 && r != -ENXIO) /* ENXIO: no hostname set or hostname is "localhost" */
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to get hostname: %m"); return r;
hn = hostname; hn = hostname;
} }
@ -1520,9 +1513,9 @@ static int dhcp6_set_hostname(sd_dhcp6_client *client, Link *link) {
r = sd_dhcp6_client_set_fqdn(client, hn); r = sd_dhcp6_client_set_fqdn(client, hn);
if (r == -EINVAL && hostname) if (r == -EINVAL && hostname)
/* Ignore error when the machine's hostname is not suitable to send in DHCP packet. */ /* Ignore error when the machine's hostname is not suitable to send in DHCP packet. */
log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set hostname from kernel hostname, ignoring: %m"); log_link_warning_errno(link, r, "DHCP6 CLIENT: Failed to set hostname from kernel hostname, ignoring: %m");
else if (r < 0) else if (r < 0)
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set hostname: %m"); return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set hostname: %m");
return 0; return 0;
} }
@ -1578,7 +1571,7 @@ static int dhcp6_set_identifier(Link *link, sd_dhcp6_client *client) {
return 0; return 0;
} }
static int dhcp6_configure(Link *link) { int dhcp6_configure(Link *link) {
_cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL; _cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL;
sd_dhcp6_option *vendor_option; sd_dhcp6_option *vendor_option;
sd_dhcp6_option *send_option; sd_dhcp6_option *send_option;
@ -1588,29 +1581,36 @@ static int dhcp6_configure(Link *link) {
assert(link); assert(link);
assert(link->network); assert(link->network);
if (!link_dhcp6_enabled(link) && !link_ipv6_accept_ra_enabled(link))
return 0;
if (link->dhcp6_client) if (link->dhcp6_client)
return log_link_debug_errno(link, SYNTHETIC_ERRNO(EBUSY), "DHCPv6 client is already configured."); return -EBUSY;
r = dhcp_configure_duid(link, link_get_dhcp6_duid(link));
if (r <= 0)
return r;
r = sd_dhcp6_client_new(&client); r = sd_dhcp6_client_new(&client);
if (r == -ENOMEM) if (r == -ENOMEM)
return log_oom_debug(); return log_oom();
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to create DHCPv6 client: %m"); return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to create DHCP6 client: %m");
r = sd_dhcp6_client_attach_event(client, link->manager->event, 0); r = sd_dhcp6_client_attach_event(client, link->manager->event, 0);
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to attach event: %m"); return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to attach event: %m");
r = dhcp6_set_identifier(link, client); r = dhcp6_set_identifier(link, client);
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set identifier: %m"); return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set identifier: %m");
ORDERED_HASHMAP_FOREACH(send_option, link->network->dhcp6_client_send_options) { ORDERED_HASHMAP_FOREACH(send_option, link->network->dhcp6_client_send_options) {
r = sd_dhcp6_client_add_option(client, send_option); r = sd_dhcp6_client_add_option(client, send_option);
if (r == -EEXIST) if (r == -EEXIST)
continue; continue;
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set option: %m"); return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set option: %m");
} }
r = dhcp6_set_hostname(client, link); r = dhcp6_set_hostname(client, link);
@ -1619,18 +1619,18 @@ static int dhcp6_configure(Link *link) {
r = sd_dhcp6_client_set_ifindex(client, link->ifindex); r = sd_dhcp6_client_set_ifindex(client, link->ifindex);
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set ifindex: %m"); return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set ifindex: %m");
if (link->network->dhcp6_rapid_commit) { if (link->network->dhcp6_rapid_commit) {
r = sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_RAPID_COMMIT); r = sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_RAPID_COMMIT);
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set request flag for rapid commit: %m"); return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set request flag for rapid commit: %m");
} }
if (link->network->dhcp6_mudurl) { if (link->network->dhcp6_mudurl) {
r = sd_dhcp6_client_set_request_mud_url(client, link->network->dhcp6_mudurl); r = sd_dhcp6_client_set_request_mud_url(client, link->network->dhcp6_mudurl);
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set MUD URL: %m"); return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set MUD URL: %m");
} }
SET_FOREACH(request_options, link->network->dhcp6_request_options) { SET_FOREACH(request_options, link->network->dhcp6_request_options) {
@ -1638,23 +1638,23 @@ static int dhcp6_configure(Link *link) {
r = sd_dhcp6_client_set_request_option(client, option); r = sd_dhcp6_client_set_request_option(client, option);
if (r == -EEXIST) { if (r == -EEXIST) {
log_link_debug(link, "DHCPv6 CLIENT: Failed to set request flag for '%u' already exists, ignoring.", option); log_link_debug(link, "DHCP6 CLIENT: Failed to set request flag for '%u' already exists, ignoring.", option);
continue; continue;
} }
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set request flag for '%u': %m", option); return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set request flag for '%u': %m", option);
} }
if (link->network->dhcp6_user_class) { if (link->network->dhcp6_user_class) {
r = sd_dhcp6_client_set_request_user_class(client, link->network->dhcp6_user_class); r = sd_dhcp6_client_set_request_user_class(client, link->network->dhcp6_user_class);
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set user class: %m"); return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set user class: %m");
} }
if (link->network->dhcp6_vendor_class) { if (link->network->dhcp6_vendor_class) {
r = sd_dhcp6_client_set_request_vendor_class(client, link->network->dhcp6_vendor_class); r = sd_dhcp6_client_set_request_vendor_class(client, link->network->dhcp6_vendor_class);
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set vendor class: %m"); return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set vendor class: %m");
} }
ORDERED_HASHMAP_FOREACH(vendor_option, link->network->dhcp6_client_send_vendor_options) { ORDERED_HASHMAP_FOREACH(vendor_option, link->network->dhcp6_client_send_vendor_options) {
@ -1662,23 +1662,23 @@ static int dhcp6_configure(Link *link) {
if (r == -EEXIST) if (r == -EEXIST)
continue; continue;
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set vendor option: %m"); return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set vendor option: %m");
} }
r = sd_dhcp6_client_set_callback(client, dhcp6_handler, link); r = sd_dhcp6_client_set_callback(client, dhcp6_handler, link);
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set callback: %m"); return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set callback: %m");
if (dhcp6_enable_prefix_delegation(link)) { if (dhcp6_enable_prefix_delegation(link)) {
r = sd_dhcp6_client_set_prefix_delegation(client, true); r = sd_dhcp6_client_set_prefix_delegation(client, true);
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set prefix delegation: %m"); return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set prefix delegation: %m");
} }
if (link->network->dhcp6_pd_length > 0) { if (link->network->dhcp6_pd_length > 0) {
r = sd_dhcp6_client_set_prefix_delegation_hint(client, link->network->dhcp6_pd_length, &link->network->dhcp6_pd_address); r = sd_dhcp6_client_set_prefix_delegation_hint(client, link->network->dhcp6_pd_length, &link->network->dhcp6_pd_address);
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set prefix hint: %m"); return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set prefix hint: %m");
} }
link->dhcp6_client = TAKE_PTR(client); link->dhcp6_client = TAKE_PTR(client);
@ -1716,60 +1716,6 @@ int dhcp6_update_mac(Link *link) {
return 0; return 0;
} }
int request_process_dhcp6_client(Request *req) {
Link *link;
int r;
assert(req);
assert(req->link);
assert(req->type == REQUEST_TYPE_DHCP6_CLIENT);
link = req->link;
if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
return 0;
r = dhcp_configure_duid(link, link_get_dhcp6_duid(link));
if (r <= 0)
return r;
r = dhcp6_configure(link);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to configure DHCPv6 client: %m");
r = ndisc_start(link);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to start IPv6 Router Discovery: %m");
r = dhcp6_start(link);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to start DHCPv6 client: %m");
log_link_debug(link, "DHCPv6 client is configured%s.",
r > 0 ? ", acquiring DHCPv6 lease" : "");
return 1;
}
int link_request_dhcp6_client(Link *link) {
int r;
assert(link);
if (!link_dhcp6_enabled(link) && !link_ipv6_accept_ra_enabled(link))
return 0;
if (link->dhcp6_client)
return 0;
r = link_queue_request(link, REQUEST_TYPE_DHCP6_CLIENT, NULL, false, NULL, NULL, NULL);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to request configuring of the DHCPv6 client: %m");
log_link_debug(link, "Requested configuring of the DHCPv6 client.");
return 0;
}
int link_serialize_dhcp6_client(Link *link, FILE *f) { int link_serialize_dhcp6_client(Link *link, FILE *f) {
_cleanup_free_ char *duid = NULL; _cleanup_free_ char *duid = NULL;
uint32_t iaid; uint32_t iaid;

View File

@ -1,8 +1,9 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once #pragma once
#include "sd-dhcp6-client.h"
#include "conf-parser.h" #include "conf-parser.h"
#include "in-addr-util.h"
#include "macro.h" #include "macro.h"
typedef enum DHCP6ClientStartMode { typedef enum DHCP6ClientStartMode {
@ -14,7 +15,7 @@ typedef enum DHCP6ClientStartMode {
} DHCP6ClientStartMode; } DHCP6ClientStartMode;
typedef struct Link Link; typedef struct Link Link;
typedef struct Request Request; typedef struct Manager Manager;
typedef struct DHCP6DelegatedPrefix { typedef struct DHCP6DelegatedPrefix {
struct in6_addr prefix; /* Prefix assigned to the link */ struct in6_addr prefix; /* Prefix assigned to the link */
@ -28,14 +29,12 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(DHCP6DelegatedPrefix*, dhcp6_pd_free);
bool link_dhcp6_with_address_enabled(Link *link); bool link_dhcp6_with_address_enabled(Link *link);
bool link_dhcp6_pd_is_enabled(Link *link); bool link_dhcp6_pd_is_enabled(Link *link);
int dhcp6_pd_remove(Link *link); int dhcp6_pd_remove(Link *link);
int dhcp6_configure(Link *link);
int dhcp6_update_mac(Link *link); int dhcp6_update_mac(Link *link);
int dhcp6_start(Link *link); int dhcp6_start(Link *link);
int dhcp6_request_information(Link *link, int ir); int dhcp6_request_information(Link *link, int ir);
int dhcp6_request_prefix_delegation(Link *link); int dhcp6_request_prefix_delegation(Link *link);
int request_process_dhcp6_client(Request *req);
int link_request_dhcp6_client(Link *link);
int link_serialize_dhcp6_client(Link *link, FILE *f); int link_serialize_dhcp6_client(Link *link, FILE *f);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_pd_hint); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_pd_hint);

View File

@ -507,7 +507,7 @@ void link_check_ready(Link *link) {
!link->dhcp_address && set_isempty(link->dhcp6_addresses) && !has_ndisc_address && !link->dhcp_address && set_isempty(link->dhcp6_addresses) && !has_ndisc_address &&
!link->ipv4ll_address_configured) !link->ipv4ll_address_configured)
/* When DHCP[46] or IPv4LL is enabled, at least one address is acquired by them. */ /* When DHCP[46] or IPv4LL is enabled, at least one address is acquired by them. */
return (void) log_link_debug(link, "%s(): DHCPv4, DHCPv6 or IPv4LL is enabled but no dynamic address is assigned yet.", __func__); return (void) log_link_debug(link, "%s(): DHCP4, DHCP6 or IPv4LL is enabled but no dynamic address is assigned yet.", __func__);
/* Ignore NDisc when ConfigureWithoutCarrier= is enabled, as IPv6AcceptRA= is enabled by default. */ /* Ignore NDisc when ConfigureWithoutCarrier= is enabled, as IPv6AcceptRA= is enabled by default. */
if (link_dhcp4_enabled(link) || link_dhcp6_enabled(link) || link_dhcp6_pd_is_enabled(link) || if (link_dhcp4_enabled(link) || link_dhcp6_enabled(link) || link_dhcp6_pd_is_enabled(link) ||
@ -522,8 +522,8 @@ void link_check_ready(Link *link) {
/* When DHCP[46], NDisc, or IPv4LL is enabled, at least one protocol must be finished. */ /* When DHCP[46], NDisc, or IPv4LL is enabled, at least one protocol must be finished. */
return (void) log_link_debug(link, "%s(): dynamic addresses or routes are not configured.", __func__); return (void) log_link_debug(link, "%s(): dynamic addresses or routes are not configured.", __func__);
log_link_debug(link, "%s(): DHCPv4:%s IPv4LL:%s DHCPv6_addresses:%s DHCPv6_routes:%s " log_link_debug(link, "%s(): dhcp4:%s ipv4ll:%s dhcp6_addresses:%s dhcp6_routes:%s "
"DHCPv6PD_addresses:%s DHCPv6PD_routes:%s NDisc_addresses:%s NDisc_routes:%s", "dhcp6_pd_addresses:%s dhcp6_pd_routes:%s ndisc_addresses:%s ndisc_routes:%s",
__func__, __func__,
yes_no(link->dhcp4_configured), yes_no(link->dhcp4_configured),
yes_no(link->ipv4ll_address_configured), yes_no(link->ipv4ll_address_configured),
@ -650,14 +650,12 @@ static int link_acquire_dynamic_ipv4_conf(Link *link) {
if (r < 0) if (r < 0)
return log_link_warning_errno(link, r, "Failed to start DHCPv4 client: %m"); return log_link_warning_errno(link, r, "Failed to start DHCPv4 client: %m");
log_link_debug(link, "Acquiring DHCPv4 lease.");
} else if (link->ipv4ll) { } else if (link->ipv4ll) {
log_link_debug(link, "Acquiring IPv4 link-local address");
r = sd_ipv4ll_start(link->ipv4ll); r = sd_ipv4ll_start(link->ipv4ll);
if (r < 0) if (r < 0)
return log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m"); return log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m");
log_link_debug(link, "Acquiring IPv4 link-local address.");
} }
if (link->dhcp_server) { if (link->dhcp_server) {
@ -692,12 +690,6 @@ static int link_acquire_dynamic_conf(Link *link) {
if (r < 0) if (r < 0)
return log_link_warning_errno(link, r, "Failed to start LLDP transmission: %m"); return log_link_warning_errno(link, r, "Failed to start LLDP transmission: %m");
if (link->lldp) {
r = sd_lldp_start(link->lldp);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to start LLDP client: %m");
}
return 0; return 0;
} }
@ -983,6 +975,8 @@ static Link *link_drop(Link *link) {
link_drop_from_master(link); link_drop_from_master(link);
link_unref(set_remove(link->manager->links_requesting_uuid, link));
(void) unlink(link->state_file); (void) unlink(link->state_file);
link_clean(link); link_clean(link);
@ -1005,16 +999,6 @@ static int link_drop_foreign_config(Link *link) {
assert(link); assert(link);
assert(link->manager); assert(link->manager);
/* Drop foreign config, but ignore unmanaged, loopback, or critical interfaces. We do not want
* to remove loopback address or addresses used for root NFS. */
if (IN_SET(link->state, LINK_STATE_UNMANAGED, LINK_STATE_PENDING, LINK_STATE_INITIALIZED))
return 0;
if (FLAGS_SET(link->flags, IFF_LOOPBACK))
return 0;
if (link->network->keep_configuration == KEEP_CONFIGURATION_YES)
return 0;
r = link_drop_foreign_routes(link); r = link_drop_foreign_routes(link);
k = link_drop_foreign_nexthops(link); k = link_drop_foreign_nexthops(link);
@ -1143,11 +1127,11 @@ static int link_configure(Link *link) {
if (r < 0) if (r < 0)
return r; return r;
r = link_request_dhcp4_client(link); r = dhcp4_configure(link);
if (r < 0) if (r < 0)
return r; return r;
r = link_request_dhcp6_client(link); r = dhcp6_configure(link);
if (r < 0) if (r < 0)
return r; return r;
@ -1167,9 +1151,14 @@ static int link_configure(Link *link) {
if (r < 0) if (r < 0)
return r; return r;
/* Drop foreign config, but ignore loopback or critical devices.
* We do not want to remove loopback address or addresses used for root NFS. */
if (!(link->flags & IFF_LOOPBACK) &&
link->network->keep_configuration != KEEP_CONFIGURATION_YES) {
r = link_drop_foreign_config(link); r = link_drop_foreign_config(link);
if (r < 0) if (r < 0)
return r; return r;
}
r = link_request_static_configs(link); r = link_request_static_configs(link);
if (r < 0) if (r < 0)
@ -1235,22 +1224,23 @@ static int link_get_network(Link *link, Network **ret) {
} }
static int link_reconfigure_impl(Link *link, bool force) { static int link_reconfigure_impl(Link *link, bool force) {
Network *network = NULL; Network *network;
int r; int r;
assert(link); assert(link);
r = link_get_network(link, &network); r = link_get_network(link, &network);
if (r < 0 && r != -ENOENT) if (r == -ENOENT) {
link_set_state(link, LINK_STATE_UNMANAGED);
return 0;
}
if (r < 0)
return r; return r;
if (link->network == network && !force) if (link->network == network && !force)
return 0; return 0;
if (network) log_link_info(link, "Re-configuring with %s", network->filename);
log_link_info(link, "Reconfiguring with %s.", network->filename);
else
log_link_info(link, "Unmanaging interface.");
/* Dropping old .network file */ /* Dropping old .network file */
r = link_stop_engines(link, false); r = link_stop_engines(link, false);
@ -1263,14 +1253,17 @@ static int link_reconfigure_impl(Link *link, bool force) {
if (r < 0) if (r < 0)
return r; return r;
if (!IN_SET(link->state, LINK_STATE_UNMANAGED, LINK_STATE_PENDING, LINK_STATE_INITIALIZED)) {
log_link_debug(link, "State is %s, dropping foreign config", link_state_to_string(link->state));
r = link_drop_foreign_config(link);
if (r < 0)
return r;
}
link_free_carrier_maps(link); link_free_carrier_maps(link);
link_free_engines(link); link_free_engines(link);
link->network = network_unref(link->network); link->network = network_unref(link->network);
link_unref(set_remove(link->manager->links_requesting_uuid, link));
if (!network) {
link_set_state(link, LINK_STATE_UNMANAGED);
return 0;
}
/* Then, apply new .network file */ /* Then, apply new .network file */
link->network = network_ref(network); link->network = network_ref(network);
@ -1291,107 +1284,44 @@ static int link_reconfigure_impl(Link *link, bool force) {
return 1; return 1;
} }
static int link_reconfigure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, bool force, bool update_wifi) { static int link_reconfigure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, bool force) {
bool link_was_lower_up;
int r; int r;
assert(link);
link_was_lower_up = link->flags & IFF_LOWER_UP;
r = link_getlink_handler_internal(rtnl, m, link, "Failed to update link state"); r = link_getlink_handler_internal(rtnl, m, link, "Failed to update link state");
if (r <= 0) if (r <= 0)
return r; return r;
if (update_wifi && link_was_lower_up && link->flags & IFF_LOWER_UP) {
/* If the interface's L1 was not up, then wifi_get_info() is already called in
* link_update_flags(). So, it is not necessary to re-call here. */
r = wifi_get_info(link);
if (r < 0) {
link_enter_failed(link);
return 0;
}
}
r = link_reconfigure_impl(link, force); r = link_reconfigure_impl(link, force);
if (r < 0) { if (r < 0)
link_enter_failed(link); link_enter_failed(link);
return 0;
}
return r; return 0;
} }
static int link_reconfigure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { static int link_reconfigure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
return link_reconfigure_handler_internal(rtnl, m, link, /* force = */ false, /* update_wifi = */ false); return link_reconfigure_handler_internal(rtnl, m, link, false);
} }
static int link_force_reconfigure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { static int link_force_reconfigure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
return link_reconfigure_handler_internal(rtnl, m, link, /* force = */ true, /* update_wifi = */ false); return link_reconfigure_handler_internal(rtnl, m, link, true);
} }
static int link_reconfigure_after_sleep_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { int link_reconfigure(Link *link, bool force) {
int r; int r;
assert(link);
r = link_reconfigure_handler_internal(rtnl, m, link, /* force = */ false, /* update_wifi = */ true);
if (r != 0)
return r;
/* r == 0 means an error occurs, the link is unmanaged, or the matching network file is unchanged. */
if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
return 0;
/* re-request static configs, and restart engines. */
r = link_stop_engines(link, false);
if (r < 0) {
link_enter_failed(link);
return 0;
}
r = link_acquire_dynamic_conf(link);
if (r < 0) {
link_enter_failed(link);
return 0;
}
r = link_request_static_configs(link);
if (r < 0) {
link_enter_failed(link);
return 0;
}
return 0;
}
static int link_reconfigure_internal(Link *link, link_netlink_message_handler_t callback) {
int r;
assert(link);
assert(callback);
/* When link in pending or initialized state, then link_configure() will be called. To prevent /* When link in pending or initialized state, then link_configure() will be called. To prevent
* the function from being called multiple times simultaneously, refuse to reconfigure the * the function from being called multiple times simultaneously, refuse to reconfigure the
* interface in these cases. */ * interface in these cases. */
if (IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_INITIALIZED, LINK_STATE_LINGER)) if (IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_INITIALIZED, LINK_STATE_LINGER))
return 0; /* 0 means no-op. */ return 0; /* 0 means no-op. */
r = link_call_getlink(link, callback); r = link_call_getlink(link, force ? link_force_reconfigure_handler : link_reconfigure_handler);
if (r < 0) if (r < 0)
return r; return r;
return 1; /* 1 means the interface will be reconfigured. */ return 1; /* 1 means the interface will be reconfigured. */
} }
int link_reconfigure(Link *link, bool force) {
return link_reconfigure_internal(link, force ? link_force_reconfigure_handler : link_reconfigure_handler);
}
int link_reconfigure_after_sleep(Link *link) {
return link_reconfigure_internal(link, link_reconfigure_after_sleep_handler);
}
static int link_initialized_and_synced(Link *link) { static int link_initialized_and_synced(Link *link) {
Network *network; Network *network;
int r; int r;
@ -1630,7 +1560,34 @@ static int link_carrier_lost(Link *link) {
if (r < 0) if (r < 0)
return r; return r;
return link_drop_foreign_config(link); if (!IN_SET(link->state, LINK_STATE_UNMANAGED, LINK_STATE_PENDING, LINK_STATE_INITIALIZED)) {
log_link_debug(link, "State is %s, dropping foreign config", link_state_to_string(link->state));
r = link_drop_foreign_config(link);
if (r < 0)
return r;
}
return 0;
}
int link_carrier_reset(Link *link) {
int r;
assert(link);
if (!link_has_carrier(link))
return 0;
r = link_carrier_lost(link);
if (r < 0)
return r;
r = link_carrier_gained(link);
if (r < 0)
return r;
log_link_info(link, "Reset carrier");
return 0;
} }
static int link_admin_state_up(Link *link) { static int link_admin_state_up(Link *link) {
@ -1986,6 +1943,10 @@ static int link_update_flags(Link *link, sd_netlink_message *message) {
return r; return r;
} }
r = link_update_lldp(link);
if (r < 0)
return r;
if (!had_carrier && link_has_carrier(link)) { if (!had_carrier && link_has_carrier(link)) {
log_link_info(link, "Gained carrier"); log_link_info(link, "Gained carrier");

View File

@ -232,6 +232,7 @@ void link_check_ready(Link *link);
void link_update_operstate(Link *link, bool also_update_bond_master); void link_update_operstate(Link *link, bool also_update_bond_master);
int link_carrier_reset(Link *link);
bool link_has_carrier(Link *link); bool link_has_carrier(Link *link);
bool link_ipv6_enabled(Link *link); bool link_ipv6_enabled(Link *link);
@ -246,7 +247,6 @@ const char* link_state_to_string(LinkState s) _const_;
LinkState link_state_from_string(const char *s) _pure_; LinkState link_state_from_string(const char *s) _pure_;
int link_reconfigure(Link *link, bool force); int link_reconfigure(Link *link, bool force);
int link_reconfigure_after_sleep(Link *link);
int manager_udev_process_link(sd_device_monitor *monitor, sd_device *device, void *userdata); int manager_udev_process_link(sd_device_monitor *monitor, sd_device *device, void *userdata);
int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *message, Manager *m); int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *message, Manager *m);

View File

@ -103,9 +103,38 @@ int link_lldp_rx_configure(Link *link) {
if (r < 0) if (r < 0)
return r; return r;
r = link_update_lldp(link);
if (r < 0)
return r;
return 0; return 0;
} }
int link_update_lldp(Link *link) {
int r;
assert(link);
if (!link->lldp)
return 0;
if (link->flags & IFF_UP) {
r = sd_lldp_start(link->lldp);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to start LLDP: %m");
if (r > 0)
log_link_debug(link, "Started LLDP.");
} else {
r = sd_lldp_stop(link->lldp);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to stop LLDP: %m");
if (r > 0)
log_link_debug(link, "Stopped LLDP.");
}
return r;
}
int link_lldp_save(Link *link) { int link_lldp_save(Link *link) {
_cleanup_(unlink_and_freep) char *temp_path = NULL; _cleanup_(unlink_and_freep) char *temp_path = NULL;
_cleanup_fclose_ FILE *f = NULL; _cleanup_fclose_ FILE *f = NULL;

View File

@ -14,6 +14,7 @@ typedef enum LLDPMode {
} LLDPMode; } LLDPMode;
int link_lldp_rx_configure(Link *link); int link_lldp_rx_configure(Link *link);
int link_update_lldp(Link *link);
int link_lldp_save(Link *link); int link_lldp_save(Link *link);
const char* lldp_mode_to_string(LLDPMode m) _const_; const char* lldp_mode_to_string(LLDPMode m) _const_;

View File

@ -59,9 +59,9 @@ static int manager_reset_all(Manager *m) {
assert(m); assert(m);
HASHMAP_FOREACH(link, m->links_by_index) { HASHMAP_FOREACH(link, m->links_by_index) {
r = link_reconfigure_after_sleep(link); r = link_carrier_reset(link);
if (r < 0) { if (r < 0) {
log_link_warning_errno(link, r, "Failed to reconfigure interface: %m"); log_link_warning_errno(link, r, "Could not reset carrier: %m");
link_enter_failed(link); link_enter_failed(link);
} }
} }
@ -103,7 +103,7 @@ static int on_connected(sd_bus_message *message, void *userdata, sd_bus_error *r
(void) manager_set_hostname(m, m->dynamic_hostname); (void) manager_set_hostname(m, m->dynamic_hostname);
if (m->dynamic_timezone) if (m->dynamic_timezone)
(void) manager_set_timezone(m, m->dynamic_timezone); (void) manager_set_timezone(m, m->dynamic_timezone);
if (m->product_uuid_requested) if (!set_isempty(m->links_requesting_uuid))
(void) manager_request_product_uuid(m); (void) manager_request_product_uuid(m);
return 0; return 0;
@ -460,6 +460,7 @@ Manager* manager_free(Manager *m) {
m->dhcp6_pd_prefixes = set_free_with_destructor(m->dhcp6_pd_prefixes, dhcp6_pd_free); m->dhcp6_pd_prefixes = set_free_with_destructor(m->dhcp6_pd_prefixes, dhcp6_pd_free);
m->dirty_links = set_free_with_destructor(m->dirty_links, link_unref); m->dirty_links = set_free_with_destructor(m->dirty_links, link_unref);
m->links_requesting_uuid = set_free_with_destructor(m->links_requesting_uuid, link_unref);
m->links_by_name = hashmap_free(m->links_by_name); m->links_by_name = hashmap_free(m->links_by_name);
m->links_by_hw_addr = hashmap_free(m->links_by_hw_addr); m->links_by_hw_addr = hashmap_free(m->links_by_hw_addr);
m->links_by_index = hashmap_free_with_destructor(m->links_by_index, link_unref); m->links_by_index = hashmap_free_with_destructor(m->links_by_index, link_unref);

View File

@ -60,6 +60,7 @@ struct Manager {
DUID duid_product_uuid; DUID duid_product_uuid;
bool has_product_uuid; bool has_product_uuid;
bool product_uuid_requested; bool product_uuid_requested;
Set *links_requesting_uuid;
char* dynamic_hostname; char* dynamic_hostname;
char* dynamic_timezone; char* dynamic_timezone;

View File

@ -38,21 +38,6 @@
#define NDISC_APP_ID SD_ID128_MAKE(13,ac,81,a7,d5,3f,49,78,92,79,5d,0c,29,3a,bc,7e) #define NDISC_APP_ID SD_ID128_MAKE(13,ac,81,a7,d5,3f,49,78,92,79,5d,0c,29,3a,bc,7e)
typedef enum IPv6TokenAddressGeneration {
IPV6_TOKEN_ADDRESS_GENERATION_NONE,
IPV6_TOKEN_ADDRESS_GENERATION_STATIC,
IPV6_TOKEN_ADDRESS_GENERATION_PREFIXSTABLE,
_IPV6_TOKEN_ADDRESS_GENERATION_MAX,
_IPV6_TOKEN_ADDRESS_GENERATION_INVALID = -EINVAL,
} IPv6TokenAddressGeneration;
typedef struct IPv6Token {
IPv6TokenAddressGeneration address_generation_type;
uint8_t dad_counter;
struct in6_addr prefix;
} IPv6Token;
bool link_ipv6_accept_ra_enabled(Link *link) { bool link_ipv6_accept_ra_enabled(Link *link) {
assert(link); assert(link);
@ -634,7 +619,7 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
return 0; return 0;
} }
static bool stable_private_address_is_valid(const struct in6_addr *addr) { static bool stableprivate_address_is_valid(const struct in6_addr *addr) {
assert(addr); assert(addr);
/* According to rfc4291, generated address should not be in the following ranges. */ /* According to rfc4291, generated address should not be in the following ranges. */
@ -651,7 +636,7 @@ static bool stable_private_address_is_valid(const struct in6_addr *addr) {
return true; return true;
} }
static int make_stable_private_address(Link *link, const struct in6_addr *prefix, uint8_t prefix_len, uint8_t dad_counter, struct in6_addr **ret) { static int make_stableprivate_address(Link *link, const struct in6_addr *prefix, uint8_t prefix_len, uint8_t dad_counter, struct in6_addr **ret) {
_cleanup_free_ struct in6_addr *addr = NULL; _cleanup_free_ struct in6_addr *addr = NULL;
sd_id128_t secret_key; sd_id128_t secret_key;
struct siphash state; struct siphash state;
@ -664,7 +649,7 @@ static int make_stable_private_address(Link *link, const struct in6_addr *prefix
r = sd_id128_get_machine_app_specific(NDISC_APP_ID, &secret_key); r = sd_id128_get_machine_app_specific(NDISC_APP_ID, &secret_key);
if (r < 0) if (r < 0)
return log_link_warning_errno(link, r, "Failed to generate key for IPv6 stable private address: %m"); return log_error_errno(r, "Failed to generate key: %m");
siphash24_init(&state, secret_key.bytes); siphash24_init(&state, secret_key.bytes);
@ -687,7 +672,7 @@ static int make_stable_private_address(Link *link, const struct in6_addr *prefix
memcpy(addr->s6_addr, prefix->s6_addr, l); memcpy(addr->s6_addr, prefix->s6_addr, l);
memcpy(addr->s6_addr + l, &rid, 16 - l); memcpy(addr->s6_addr + l, &rid, 16 - l);
if (!stable_private_address_is_valid(addr)) { if (!stableprivate_address_is_valid(addr)) {
*ret = NULL; *ret = NULL;
return 0; return 0;
} }
@ -719,7 +704,7 @@ static int ndisc_router_generate_addresses(Link *link, struct in6_addr *address,
* only when the address generation algorithm produces an invalid address, and the loop * only when the address generation algorithm produces an invalid address, and the loop
* may exit with an address which ends up being unusable due to duplication on the link. */ * may exit with an address which ends up being unusable due to duplication on the link. */
for (; j->dad_counter < DAD_CONFLICTS_IDGEN_RETRIES_RFC7217; j->dad_counter++) { for (; j->dad_counter < DAD_CONFLICTS_IDGEN_RETRIES_RFC7217; j->dad_counter++) {
r = make_stable_private_address(link, address, prefixlen, j->dad_counter, &new_address); r = make_stableprivate_address(link, address, prefixlen, j->dad_counter, &new_address);
if (r < 0) if (r < 0)
return r; return r;
if (r > 0) if (r > 0)
@ -1045,7 +1030,7 @@ static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
if (rdnss) { if (rdnss) {
rdnss->marked = false; rdnss->marked = false;
rdnss->router = router; rdnss->router = router;
rdnss->valid_until = usec_add(time_now, lifetime * USEC_PER_SEC); rdnss->valid_until = time_now + lifetime * USEC_PER_SEC;
continue; continue;
} }
@ -1056,7 +1041,7 @@ static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
*x = (NDiscRDNSS) { *x = (NDiscRDNSS) {
.address = a[j], .address = a[j],
.router = router, .router = router,
.valid_until = usec_add(time_now, lifetime * USEC_PER_SEC), .valid_until = time_now + lifetime * USEC_PER_SEC,
}; };
r = set_ensure_consume(&link->ndisc_rdnss, &ndisc_rdnss_hash_ops, TAKE_PTR(x)); r = set_ensure_consume(&link->ndisc_rdnss, &ndisc_rdnss_hash_ops, TAKE_PTR(x));
@ -1143,12 +1128,12 @@ static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
if (dnssl) { if (dnssl) {
dnssl->marked = false; dnssl->marked = false;
dnssl->router = router; dnssl->router = router;
dnssl->valid_until = usec_add(time_now, lifetime * USEC_PER_SEC); dnssl->valid_until = time_now + lifetime * USEC_PER_SEC;
continue; continue;
} }
s->router = router; s->router = router;
s->valid_until = usec_add(time_now, lifetime * USEC_PER_SEC); s->valid_until = time_now + lifetime * USEC_PER_SEC;
r = set_ensure_consume(&link->ndisc_dnssl, &ndisc_dnssl_hash_ops, TAKE_PTR(s)); r = set_ensure_consume(&link->ndisc_dnssl, &ndisc_dnssl_hash_ops, TAKE_PTR(s));
if (r < 0) if (r < 0)
@ -1411,9 +1396,6 @@ int ndisc_start(Link *link) {
if (!link->ndisc || !link->dhcp6_client) if (!link->ndisc || !link->dhcp6_client)
return 0; return 0;
if (!link_has_carrier(link))
return 0;
log_link_debug(link, "Discovering IPv6 routers"); log_link_debug(link, "Discovering IPv6 routers");
return sd_ndisc_start(link->ndisc); return sd_ndisc_start(link->ndisc);
@ -1448,7 +1430,7 @@ void ndisc_flush(Link *link) {
link->ndisc_dnssl = set_free(link->ndisc_dnssl); link->ndisc_dnssl = set_free(link->ndisc_dnssl);
} }
static int ipv6token_new(IPv6Token **ret) { int ipv6token_new(IPv6Token **ret) {
IPv6Token *p; IPv6Token *p;
p = new(IPv6Token, 1); p = new(IPv6Token, 1);

View File

@ -7,6 +7,16 @@
#include "networkd-route.h" #include "networkd-route.h"
#include "time-util.h" #include "time-util.h"
typedef struct IPv6Token IPv6Token;
typedef enum IPv6TokenAddressGeneration {
IPV6_TOKEN_ADDRESS_GENERATION_NONE,
IPV6_TOKEN_ADDRESS_GENERATION_STATIC,
IPV6_TOKEN_ADDRESS_GENERATION_PREFIXSTABLE,
_IPV6_TOKEN_ADDRESS_GENERATION_MAX,
_IPV6_TOKEN_ADDRESS_GENERATION_INVALID = -EINVAL,
} IPv6TokenAddressGeneration;
typedef enum IPv6AcceptRAStartDHCP6Client { typedef enum IPv6AcceptRAStartDHCP6Client {
IPV6_ACCEPT_RA_START_DHCP6_CLIENT_NO, IPV6_ACCEPT_RA_START_DHCP6_CLIENT_NO,
IPV6_ACCEPT_RA_START_DHCP6_CLIENT_ALWAYS, IPV6_ACCEPT_RA_START_DHCP6_CLIENT_ALWAYS,
@ -45,6 +55,15 @@ typedef struct NDiscDNSSL {
/* The domain name follows immediately. */ /* The domain name follows immediately. */
} NDiscDNSSL; } NDiscDNSSL;
struct IPv6Token {
IPv6TokenAddressGeneration address_generation_type;
uint8_t dad_counter;
struct in6_addr prefix;
};
int ipv6token_new(IPv6Token **ret);
static inline char* NDISC_DNSSL_DOMAIN(const NDiscDNSSL *n) { static inline char* NDISC_DNSSL_DOMAIN(const NDiscDNSSL *n) {
return ((char*) n) + ALIGN(sizeof(NDiscDNSSL)); return ((char*) n) + ALIGN(sizeof(NDiscDNSSL));
} }

View File

@ -5,8 +5,6 @@
#include "networkd-bridge-fdb.h" #include "networkd-bridge-fdb.h"
#include "networkd-bridge-mdb.h" #include "networkd-bridge-mdb.h"
#include "networkd-dhcp-server.h" #include "networkd-dhcp-server.h"
#include "networkd-dhcp4.h"
#include "networkd-dhcp6.h"
#include "networkd-ipv6-proxy-ndp.h" #include "networkd-ipv6-proxy-ndp.h"
#include "networkd-manager.h" #include "networkd-manager.h"
#include "networkd-neighbor.h" #include "networkd-neighbor.h"
@ -35,8 +33,6 @@ static void request_free_object(RequestType type, void *object) {
case REQUEST_TYPE_CREATE_STACKED_NETDEV: case REQUEST_TYPE_CREATE_STACKED_NETDEV:
break; break;
case REQUEST_TYPE_DHCP_SERVER: case REQUEST_TYPE_DHCP_SERVER:
case REQUEST_TYPE_DHCP4_CLIENT:
case REQUEST_TYPE_DHCP6_CLIENT:
break; break;
case REQUEST_TYPE_IPV6_PROXY_NDP: case REQUEST_TYPE_IPV6_PROXY_NDP:
free(object); free(object);
@ -116,9 +112,7 @@ static void request_hash_func(const Request *req, struct siphash *state) {
trivial_hash_func(req->object, state); trivial_hash_func(req->object, state);
break; break;
case REQUEST_TYPE_DHCP_SERVER: case REQUEST_TYPE_DHCP_SERVER:
case REQUEST_TYPE_DHCP4_CLIENT: /* This type does not have an object. */
case REQUEST_TYPE_DHCP6_CLIENT:
/* These types do not have an object. */
break; break;
case REQUEST_TYPE_IPV6_PROXY_NDP: case REQUEST_TYPE_IPV6_PROXY_NDP:
in6_addr_hash_func(req->ipv6_proxy_ndp, state); in6_addr_hash_func(req->ipv6_proxy_ndp, state);
@ -176,8 +170,6 @@ static int request_compare_func(const struct Request *a, const struct Request *b
case REQUEST_TYPE_CREATE_STACKED_NETDEV: case REQUEST_TYPE_CREATE_STACKED_NETDEV:
return trivial_compare_func(a->object, b->object); return trivial_compare_func(a->object, b->object);
case REQUEST_TYPE_DHCP_SERVER: case REQUEST_TYPE_DHCP_SERVER:
case REQUEST_TYPE_DHCP4_CLIENT:
case REQUEST_TYPE_DHCP6_CLIENT:
return 0; return 0;
case REQUEST_TYPE_IPV6_PROXY_NDP: case REQUEST_TYPE_IPV6_PROXY_NDP:
return in6_addr_compare_func(a->ipv6_proxy_ndp, b->ipv6_proxy_ndp); return in6_addr_compare_func(a->ipv6_proxy_ndp, b->ipv6_proxy_ndp);
@ -226,16 +218,12 @@ int link_queue_request(
assert(IN_SET(type, assert(IN_SET(type,
REQUEST_TYPE_ACTIVATE_LINK, REQUEST_TYPE_ACTIVATE_LINK,
REQUEST_TYPE_DHCP_SERVER, REQUEST_TYPE_DHCP_SERVER,
REQUEST_TYPE_DHCP4_CLIENT,
REQUEST_TYPE_DHCP6_CLIENT,
REQUEST_TYPE_RADV, REQUEST_TYPE_RADV,
REQUEST_TYPE_SET_LINK, REQUEST_TYPE_SET_LINK,
REQUEST_TYPE_UP_DOWN) || REQUEST_TYPE_UP_DOWN) ||
object); object);
assert(IN_SET(type, assert(IN_SET(type,
REQUEST_TYPE_DHCP_SERVER, REQUEST_TYPE_DHCP_SERVER,
REQUEST_TYPE_DHCP4_CLIENT,
REQUEST_TYPE_DHCP6_CLIENT,
REQUEST_TYPE_RADV) || REQUEST_TYPE_RADV) ||
netlink_handler); netlink_handler);
@ -312,12 +300,6 @@ int manager_process_requests(sd_event_source *s, void *userdata) {
case REQUEST_TYPE_DHCP_SERVER: case REQUEST_TYPE_DHCP_SERVER:
r = request_process_dhcp_server(req); r = request_process_dhcp_server(req);
break; break;
case REQUEST_TYPE_DHCP4_CLIENT:
r = request_process_dhcp4_client(req);
break;
case REQUEST_TYPE_DHCP6_CLIENT:
r = request_process_dhcp6_client(req);
break;
case REQUEST_TYPE_IPV6_PROXY_NDP: case REQUEST_TYPE_IPV6_PROXY_NDP:
r = request_process_ipv6_proxy_ndp_address(req); r = request_process_ipv6_proxy_ndp_address(req);
break; break;

View File

@ -28,8 +28,6 @@ typedef enum RequestType {
REQUEST_TYPE_BRIDGE_MDB, REQUEST_TYPE_BRIDGE_MDB,
REQUEST_TYPE_CREATE_STACKED_NETDEV, REQUEST_TYPE_CREATE_STACKED_NETDEV,
REQUEST_TYPE_DHCP_SERVER, REQUEST_TYPE_DHCP_SERVER,
REQUEST_TYPE_DHCP4_CLIENT,
REQUEST_TYPE_DHCP6_CLIENT,
REQUEST_TYPE_IPV6_PROXY_NDP, REQUEST_TYPE_IPV6_PROXY_NDP,
REQUEST_TYPE_NEIGHBOR, REQUEST_TYPE_NEIGHBOR,
REQUEST_TYPE_NEXTHOP, REQUEST_TYPE_NEXTHOP,

View File

@ -869,9 +869,9 @@ int link_request_radv(Link *link) {
r = link_queue_request(link, REQUEST_TYPE_RADV, NULL, false, NULL, NULL, NULL); r = link_queue_request(link, REQUEST_TYPE_RADV, NULL, false, NULL, NULL, NULL);
if (r < 0) if (r < 0)
return log_link_warning_errno(link, r, "Failed to request configuring of the IPv6 Router Advertisement engine: %m"); return log_link_warning_errno(link, r, "Failed to request IPv6 Router Advertisement engine: %m");
log_link_debug(link, "Requested configuring of the IPv6 Router Advertisement engine."); log_link_debug(link, "IPv6 Router Advertisement engine is requested.");
return 0; return 0;
} }

View File

@ -585,7 +585,7 @@ static int dns_stub_send_reply(
DNS_PACKET_RD(q->request_packet), DNS_PACKET_RD(q->request_packet),
!!q->request_packet->opt, !!q->request_packet->opt,
edns0_do, edns0_do,
(DNS_PACKET_AD(q->request_packet) || DNS_PACKET_DO(q->request_packet)) && dns_query_fully_authenticated(q), DNS_PACKET_AD(q->request_packet) && dns_query_fully_authenticated(q),
DNS_PACKET_CD(q->request_packet), DNS_PACKET_CD(q->request_packet),
q->stub_listener_extra ? ADVERTISE_EXTRA_DATAGRAM_SIZE_MAX : ADVERTISE_DATAGRAM_SIZE_MAX, q->stub_listener_extra ? ADVERTISE_EXTRA_DATAGRAM_SIZE_MAX : ADVERTISE_DATAGRAM_SIZE_MAX,
dns_packet_has_nsid_request(q->request_packet) > 0 && !q->stub_listener_extra); dns_packet_has_nsid_request(q->request_packet) > 0 && !q->stub_listener_extra);
@ -627,7 +627,7 @@ static int dns_stub_send_failure(
DNS_PACKET_RD(p), DNS_PACKET_RD(p),
!!p->opt, !!p->opt,
DNS_PACKET_DO(p), DNS_PACKET_DO(p),
(DNS_PACKET_AD(p) || DNS_PACKET_DO(p)) && authenticated, DNS_PACKET_AD(p) && authenticated,
DNS_PACKET_CD(p), DNS_PACKET_CD(p),
l ? ADVERTISE_EXTRA_DATAGRAM_SIZE_MAX : ADVERTISE_DATAGRAM_SIZE_MAX, l ? ADVERTISE_EXTRA_DATAGRAM_SIZE_MAX : ADVERTISE_DATAGRAM_SIZE_MAX,
dns_packet_has_nsid_request(p) > 0 && !l); dns_packet_has_nsid_request(p) > 0 && !l);

View File

@ -81,9 +81,6 @@ _SD_BEGIN_DECLARATIONS;
#define SD_MESSAGE_SHUTDOWN SD_ID128_MAKE(98,26,88,66,d1,d5,4a,49,9c,4e,98,92,1d,93,bc,40) #define SD_MESSAGE_SHUTDOWN SD_ID128_MAKE(98,26,88,66,d1,d5,4a,49,9c,4e,98,92,1d,93,bc,40)
#define SD_MESSAGE_SHUTDOWN_STR SD_ID128_MAKE_STR(98,26,88,66,d1,d5,4a,49,9c,4e,98,92,1d,93,bc,40) #define SD_MESSAGE_SHUTDOWN_STR SD_ID128_MAKE_STR(98,26,88,66,d1,d5,4a,49,9c,4e,98,92,1d,93,bc,40)
#define SD_MESSAGE_FACTORY_RESET SD_ID128_MAKE(c1,4a,af,76,ec,28,4a,5f,a1,f1,05,f8,8d,fb,06,1c)
#define SD_MESSAGE_FACTORY_RESET_STR SD_ID128_MAKE_STR(c1,4a,af,76,ec,28,4a,5f,a1,f1,05,f8,8d,fb,06,1c)
/* The messages below are actually about jobs, not really about units, the macros are misleadingly named. Moreover /* The messages below are actually about jobs, not really about units, the macros are misleadingly named. Moreover
* SD_MESSAGE_UNIT_FAILED is not actually about a failing unit but about a failed start job. A job either finishes with * SD_MESSAGE_UNIT_FAILED is not actually about a failing unit but about a failed start job. A job either finishes with
* SD_MESSAGE_UNIT_STARTED or with SD_MESSAGE_UNIT_FAILED hence. */ * SD_MESSAGE_UNIT_STARTED or with SD_MESSAGE_UNIT_FAILED hence. */

View File

@ -23,14 +23,14 @@
/* wire protocol magic must match */ /* wire protocol magic must match */
#define UDEV_CTRL_MAGIC 0xdead1dea #define UDEV_CTRL_MAGIC 0xdead1dea
typedef struct UdevCtrlMessageWire { struct udev_ctrl_msg_wire {
char version[16]; char version[16];
unsigned magic; unsigned magic;
UdevCtrlMessageType type; enum udev_ctrl_msg_type type;
UdevCtrlMessageValue value; union udev_ctrl_msg_value value;
} UdevCtrlMessageWire; };
struct UdevCtrl { struct udev_ctrl {
unsigned n_ref; unsigned n_ref;
int sock; int sock;
int sock_connect; int sock_connect;
@ -47,9 +47,9 @@ struct UdevCtrl {
void *userdata; void *userdata;
}; };
int udev_ctrl_new_from_fd(UdevCtrl **ret, int fd) { int udev_ctrl_new_from_fd(struct udev_ctrl **ret, int fd) {
_cleanup_close_ int sock = -1; _cleanup_close_ int sock = -1;
UdevCtrl *uctrl; struct udev_ctrl *uctrl;
assert(ret); assert(ret);
@ -59,11 +59,11 @@ int udev_ctrl_new_from_fd(UdevCtrl **ret, int fd) {
return log_error_errno(errno, "Failed to create socket: %m"); return log_error_errno(errno, "Failed to create socket: %m");
} }
uctrl = new(UdevCtrl, 1); uctrl = new(struct udev_ctrl, 1);
if (!uctrl) if (!uctrl)
return -ENOMEM; return -ENOMEM;
*uctrl = (UdevCtrl) { *uctrl = (struct udev_ctrl) {
.n_ref = 1, .n_ref = 1,
.sock = fd >= 0 ? fd : TAKE_FD(sock), .sock = fd >= 0 ? fd : TAKE_FD(sock),
.sock_connect = -1, .sock_connect = -1,
@ -81,7 +81,7 @@ int udev_ctrl_new_from_fd(UdevCtrl **ret, int fd) {
return 0; return 0;
} }
int udev_ctrl_enable_receiving(UdevCtrl *uctrl) { int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl) {
int r; int r;
assert(uctrl); assert(uctrl);
@ -107,7 +107,7 @@ int udev_ctrl_enable_receiving(UdevCtrl *uctrl) {
return 0; return 0;
} }
static void udev_ctrl_disconnect(UdevCtrl *uctrl) { static void udev_ctrl_disconnect(struct udev_ctrl *uctrl) {
if (!uctrl) if (!uctrl)
return; return;
@ -115,7 +115,7 @@ static void udev_ctrl_disconnect(UdevCtrl *uctrl) {
uctrl->sock_connect = safe_close(uctrl->sock_connect); uctrl->sock_connect = safe_close(uctrl->sock_connect);
} }
static UdevCtrl *udev_ctrl_free(UdevCtrl *uctrl) { static struct udev_ctrl *udev_ctrl_free(struct udev_ctrl *uctrl) {
assert(uctrl); assert(uctrl);
udev_ctrl_disconnect(uctrl); udev_ctrl_disconnect(uctrl);
@ -127,9 +127,9 @@ static UdevCtrl *udev_ctrl_free(UdevCtrl *uctrl) {
return mfree(uctrl); return mfree(uctrl);
} }
DEFINE_TRIVIAL_REF_UNREF_FUNC(UdevCtrl, udev_ctrl, udev_ctrl_free); DEFINE_TRIVIAL_REF_UNREF_FUNC(struct udev_ctrl, udev_ctrl, udev_ctrl_free);
int udev_ctrl_cleanup(UdevCtrl *uctrl) { int udev_ctrl_cleanup(struct udev_ctrl *uctrl) {
if (!uctrl) if (!uctrl)
return 0; return 0;
if (uctrl->cleanup_socket) if (uctrl->cleanup_socket)
@ -137,7 +137,7 @@ int udev_ctrl_cleanup(UdevCtrl *uctrl) {
return 0; return 0;
} }
int udev_ctrl_attach_event(UdevCtrl *uctrl, sd_event *event) { int udev_ctrl_attach_event(struct udev_ctrl *uctrl, sd_event *event) {
int r; int r;
assert_return(uctrl, -EINVAL); assert_return(uctrl, -EINVAL);
@ -154,25 +154,25 @@ int udev_ctrl_attach_event(UdevCtrl *uctrl, sd_event *event) {
return 0; return 0;
} }
sd_event_source *udev_ctrl_get_event_source(UdevCtrl *uctrl) { sd_event_source *udev_ctrl_get_event_source(struct udev_ctrl *uctrl) {
assert(uctrl); assert(uctrl);
return uctrl->event_source; return uctrl->event_source;
} }
static void udev_ctrl_disconnect_and_listen_again(UdevCtrl *uctrl) { static void udev_ctrl_disconnect_and_listen_again(struct udev_ctrl *uctrl) {
udev_ctrl_disconnect(uctrl); udev_ctrl_disconnect(uctrl);
udev_ctrl_unref(uctrl); udev_ctrl_unref(uctrl);
(void) sd_event_source_set_enabled(uctrl->event_source, SD_EVENT_ON); (void) sd_event_source_set_enabled(uctrl->event_source, SD_EVENT_ON);
/* We don't return NULL here because uctrl is not freed */ /* We don't return NULL here because uctrl is not freed */
} }
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(UdevCtrl*, udev_ctrl_disconnect_and_listen_again, NULL); DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct udev_ctrl*, udev_ctrl_disconnect_and_listen_again, NULL);
static int udev_ctrl_connection_event_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) { static int udev_ctrl_connection_event_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
_cleanup_(udev_ctrl_disconnect_and_listen_againp) UdevCtrl *uctrl = NULL; _cleanup_(udev_ctrl_disconnect_and_listen_againp) struct udev_ctrl *uctrl = NULL;
UdevCtrlMessageWire msg_wire; struct udev_ctrl_msg_wire msg_wire;
struct iovec iov = IOVEC_MAKE(&msg_wire, sizeof(UdevCtrlMessageWire)); struct iovec iov = IOVEC_MAKE(&msg_wire, sizeof(struct udev_ctrl_msg_wire));
CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred))) control; CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred))) control;
struct msghdr smsg = { struct msghdr smsg = {
.msg_iov = &iov, .msg_iov = &iov,
@ -235,7 +235,7 @@ static int udev_ctrl_connection_event_handler(sd_event_source *s, int fd, uint32
} }
static int udev_ctrl_event_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) { static int udev_ctrl_event_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
UdevCtrl *uctrl = userdata; struct udev_ctrl *uctrl = userdata;
_cleanup_close_ int sock = -1; _cleanup_close_ int sock = -1;
struct ucred ucred; struct ucred ucred;
int r; int r;
@ -282,7 +282,7 @@ static int udev_ctrl_event_handler(sd_event_source *s, int fd, uint32_t revents,
return 0; return 0;
} }
int udev_ctrl_start(UdevCtrl *uctrl, udev_ctrl_handler_t callback, void *userdata) { int udev_ctrl_start(struct udev_ctrl *uctrl, udev_ctrl_handler_t callback, void *userdata) {
int r; int r;
assert(uctrl); assert(uctrl);
@ -309,8 +309,8 @@ int udev_ctrl_start(UdevCtrl *uctrl, udev_ctrl_handler_t callback, void *userdat
return 0; return 0;
} }
int udev_ctrl_send(UdevCtrl *uctrl, UdevCtrlMessageType type, int intval, const char *buf) { int udev_ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int intval, const char *buf) {
UdevCtrlMessageWire ctrl_msg_wire = { struct udev_ctrl_msg_wire ctrl_msg_wire = {
.version = "udev-" STRINGIFY(PROJECT_VERSION), .version = "udev-" STRINGIFY(PROJECT_VERSION),
.magic = UDEV_CTRL_MAGIC, .magic = UDEV_CTRL_MAGIC,
.type = type, .type = type,
@ -339,7 +339,7 @@ int udev_ctrl_send(UdevCtrl *uctrl, UdevCtrlMessageType type, int intval, const
return 0; return 0;
} }
int udev_ctrl_wait(UdevCtrl *uctrl, usec_t timeout) { int udev_ctrl_wait(struct udev_ctrl *uctrl, usec_t timeout) {
_cleanup_(sd_event_source_unrefp) sd_event_source *source_io = NULL, *source_timeout = NULL; _cleanup_(sd_event_source_unrefp) sd_event_source *source_io = NULL, *source_timeout = NULL;
int r; int r;

View File

@ -6,9 +6,9 @@
#include "macro.h" #include "macro.h"
#include "time-util.h" #include "time-util.h"
typedef struct UdevCtrl UdevCtrl; struct udev_ctrl;
typedef enum UdevCtrlMessageType { enum udev_ctrl_msg_type {
_UDEV_CTRL_END_MESSAGES, _UDEV_CTRL_END_MESSAGES,
UDEV_CTRL_SET_LOG_LEVEL, UDEV_CTRL_SET_LOG_LEVEL,
UDEV_CTRL_STOP_EXEC_QUEUE, UDEV_CTRL_STOP_EXEC_QUEUE,
@ -18,62 +18,62 @@ typedef enum UdevCtrlMessageType {
UDEV_CTRL_SET_CHILDREN_MAX, UDEV_CTRL_SET_CHILDREN_MAX,
UDEV_CTRL_PING, UDEV_CTRL_PING,
UDEV_CTRL_EXIT, UDEV_CTRL_EXIT,
} UdevCtrlMessageType; };
typedef union UdevCtrlMessageValue { union udev_ctrl_msg_value {
int intval; int intval;
char buf[256]; char buf[256];
} UdevCtrlMessageValue; };
typedef int (*udev_ctrl_handler_t)(UdevCtrl *udev_ctrl, UdevCtrlMessageType type, typedef int (*udev_ctrl_handler_t)(struct udev_ctrl *udev_ctrl, enum udev_ctrl_msg_type type,
const UdevCtrlMessageValue *value, void *userdata); const union udev_ctrl_msg_value *value, void *userdata);
int udev_ctrl_new_from_fd(UdevCtrl **ret, int fd); int udev_ctrl_new_from_fd(struct udev_ctrl **ret, int fd);
static inline int udev_ctrl_new(UdevCtrl **ret) { static inline int udev_ctrl_new(struct udev_ctrl **ret) {
return udev_ctrl_new_from_fd(ret, -1); return udev_ctrl_new_from_fd(ret, -1);
} }
int udev_ctrl_enable_receiving(UdevCtrl *uctrl); int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl);
UdevCtrl *udev_ctrl_ref(UdevCtrl *uctrl); struct udev_ctrl *udev_ctrl_ref(struct udev_ctrl *uctrl);
UdevCtrl *udev_ctrl_unref(UdevCtrl *uctrl); struct udev_ctrl *udev_ctrl_unref(struct udev_ctrl *uctrl);
int udev_ctrl_cleanup(UdevCtrl *uctrl); int udev_ctrl_cleanup(struct udev_ctrl *uctrl);
int udev_ctrl_attach_event(UdevCtrl *uctrl, sd_event *event); int udev_ctrl_attach_event(struct udev_ctrl *uctrl, sd_event *event);
int udev_ctrl_start(UdevCtrl *uctrl, udev_ctrl_handler_t callback, void *userdata); int udev_ctrl_start(struct udev_ctrl *uctrl, udev_ctrl_handler_t callback, void *userdata);
sd_event_source *udev_ctrl_get_event_source(UdevCtrl *uctrl); sd_event_source *udev_ctrl_get_event_source(struct udev_ctrl *uctrl);
int udev_ctrl_wait(UdevCtrl *uctrl, usec_t timeout); int udev_ctrl_wait(struct udev_ctrl *uctrl, usec_t timeout);
int udev_ctrl_send(UdevCtrl *uctrl, UdevCtrlMessageType type, int intval, const char *buf); int udev_ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int intval, const char *buf);
static inline int udev_ctrl_send_set_log_level(UdevCtrl *uctrl, int priority) { static inline int udev_ctrl_send_set_log_level(struct udev_ctrl *uctrl, int priority) {
return udev_ctrl_send(uctrl, UDEV_CTRL_SET_LOG_LEVEL, priority, NULL); return udev_ctrl_send(uctrl, UDEV_CTRL_SET_LOG_LEVEL, priority, NULL);
} }
static inline int udev_ctrl_send_stop_exec_queue(UdevCtrl *uctrl) { static inline int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl) {
return udev_ctrl_send(uctrl, UDEV_CTRL_STOP_EXEC_QUEUE, 0, NULL); return udev_ctrl_send(uctrl, UDEV_CTRL_STOP_EXEC_QUEUE, 0, NULL);
} }
static inline int udev_ctrl_send_start_exec_queue(UdevCtrl *uctrl) { static inline int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl) {
return udev_ctrl_send(uctrl, UDEV_CTRL_START_EXEC_QUEUE, 0, NULL); return udev_ctrl_send(uctrl, UDEV_CTRL_START_EXEC_QUEUE, 0, NULL);
} }
static inline int udev_ctrl_send_reload(UdevCtrl *uctrl) { static inline int udev_ctrl_send_reload(struct udev_ctrl *uctrl) {
return udev_ctrl_send(uctrl, UDEV_CTRL_RELOAD, 0, NULL); return udev_ctrl_send(uctrl, UDEV_CTRL_RELOAD, 0, NULL);
} }
static inline int udev_ctrl_send_set_env(UdevCtrl *uctrl, const char *key) { static inline int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key) {
return udev_ctrl_send(uctrl, UDEV_CTRL_SET_ENV, 0, key); return udev_ctrl_send(uctrl, UDEV_CTRL_SET_ENV, 0, key);
} }
static inline int udev_ctrl_send_set_children_max(UdevCtrl *uctrl, int count) { static inline int udev_ctrl_send_set_children_max(struct udev_ctrl *uctrl, int count) {
return udev_ctrl_send(uctrl, UDEV_CTRL_SET_CHILDREN_MAX, count, NULL); return udev_ctrl_send(uctrl, UDEV_CTRL_SET_CHILDREN_MAX, count, NULL);
} }
static inline int udev_ctrl_send_ping(UdevCtrl *uctrl) { static inline int udev_ctrl_send_ping(struct udev_ctrl *uctrl) {
return udev_ctrl_send(uctrl, UDEV_CTRL_PING, 0, NULL); return udev_ctrl_send(uctrl, UDEV_CTRL_PING, 0, NULL);
} }
static inline int udev_ctrl_send_exit(UdevCtrl *uctrl) { static inline int udev_ctrl_send_exit(struct udev_ctrl *uctrl) {
return udev_ctrl_send(uctrl, UDEV_CTRL_EXIT, 0, NULL); return udev_ctrl_send(uctrl, UDEV_CTRL_EXIT, 0, NULL);
} }
DEFINE_TRIVIAL_CLEANUP_FUNC(UdevCtrl*, udev_ctrl_unref); DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_ctrl*, udev_ctrl_unref);

View File

@ -1154,7 +1154,7 @@ static void rule_resolve_goto(UdevRuleFile *rule_file) {
if (!FLAGS_SET(line->type, LINE_HAS_GOTO)) if (!FLAGS_SET(line->type, LINE_HAS_GOTO))
continue; continue;
LIST_FOREACH(rule_lines, i, line->rule_lines_next) LIST_FOREACH_AFTER(rule_lines, i, line)
if (streq_ptr(i->label, line->goto_label)) { if (streq_ptr(i->label, line->goto_label)) {
line->goto_line = i; line->goto_line = i;
break; break;

View File

@ -48,7 +48,7 @@ static int help(void) {
} }
int control_main(int argc, char *argv[], void *userdata) { int control_main(int argc, char *argv[], void *userdata) {
_cleanup_(udev_ctrl_unrefp) UdevCtrl *uctrl = NULL; _cleanup_(udev_ctrl_unrefp) struct udev_ctrl *uctrl = NULL;
usec_t timeout = 60 * USEC_PER_SEC; usec_t timeout = 60 * USEC_PER_SEC;
int c, r; int c, r;

View File

@ -176,7 +176,7 @@ int settle_main(int argc, char *argv[], void *userdata) {
/* guarantee that the udev daemon isn't pre-processing */ /* guarantee that the udev daemon isn't pre-processing */
if (getuid() == 0) { if (getuid() == 0) {
_cleanup_(udev_ctrl_unrefp) UdevCtrl *uctrl = NULL; _cleanup_(udev_ctrl_unrefp) struct udev_ctrl *uctrl = NULL;
if (udev_ctrl_new(&uctrl) >= 0) { if (udev_ctrl_new(&uctrl) >= 0) {
r = udev_ctrl_send_ping(uctrl); r = udev_ctrl_send_ping(uctrl);

View File

@ -421,7 +421,7 @@ int trigger_main(int argc, char *argv[], void *userdata) {
} }
if (ping) { if (ping) {
_cleanup_(udev_ctrl_unrefp) UdevCtrl *uctrl = NULL; _cleanup_(udev_ctrl_unrefp) struct udev_ctrl *uctrl = NULL;
r = udev_ctrl_new(&uctrl); r = udev_ctrl_new(&uctrl);
if (r < 0) if (r < 0)

View File

@ -77,13 +77,10 @@ static usec_t arg_event_timeout_usec = 180 * USEC_PER_SEC;
static int arg_timeout_signal = SIGKILL; static int arg_timeout_signal = SIGKILL;
static bool arg_blockdev_read_only = false; static bool arg_blockdev_read_only = false;
typedef struct Event Event;
typedef struct Worker Worker;
typedef struct Manager { typedef struct Manager {
sd_event *event; sd_event *event;
Hashmap *workers; Hashmap *workers;
LIST_HEAD(Event, events); LIST_HEAD(struct event, events);
const char *cgroup; const char *cgroup;
pid_t pid; /* the process that originally allocated the manager object */ pid_t pid; /* the process that originally allocated the manager object */
int log_level; int log_level;
@ -94,7 +91,7 @@ typedef struct Manager {
sd_netlink *rtnl; sd_netlink *rtnl;
sd_device_monitor *monitor; sd_device_monitor *monitor;
UdevCtrl *ctrl; struct udev_ctrl *ctrl;
int worker_watch[2]; int worker_watch[2];
/* used by udev-watch */ /* used by udev-watch */
@ -109,52 +106,54 @@ typedef struct Manager {
bool exit; bool exit;
} Manager; } Manager;
typedef enum EventState { enum event_state {
EVENT_UNDEF, EVENT_UNDEF,
EVENT_QUEUED, EVENT_QUEUED,
EVENT_RUNNING, EVENT_RUNNING,
} EventState; };
typedef struct Event { struct event {
Manager *manager; Manager *manager;
Worker *worker; struct worker *worker;
EventState state; enum event_state state;
sd_device *dev; sd_device *dev;
sd_device *dev_kernel; /* clone of originally received device */ sd_device *dev_kernel; /* clone of originally received device */
uint64_t seqnum; uint64_t seqnum;
uint64_t blocker_seqnum; uint64_t delaying_seqnum;
sd_event_source *timeout_warning_event; sd_event_source *timeout_warning_event;
sd_event_source *timeout_event; sd_event_source *timeout_event;
LIST_FIELDS(Event, event); LIST_FIELDS(struct event, event);
} Event; };
typedef enum WorkerState { static void event_queue_cleanup(Manager *manager, enum event_state type);
enum worker_state {
WORKER_UNDEF, WORKER_UNDEF,
WORKER_RUNNING, WORKER_RUNNING,
WORKER_IDLE, WORKER_IDLE,
WORKER_KILLED, WORKER_KILLED,
WORKER_KILLING, WORKER_KILLING,
} WorkerState; };
typedef struct Worker { struct worker {
Manager *manager; Manager *manager;
pid_t pid; pid_t pid;
sd_device_monitor *monitor; sd_device_monitor *monitor;
WorkerState state; enum worker_state state;
Event *event; struct event *event;
} Worker; };
/* passed from worker to main process */ /* passed from worker to main process */
typedef struct WorkerMessage { struct worker_message {
} WorkerMessage; };
static Event *event_free(Event *event) { static void event_free(struct event *event) {
if (!event) if (!event)
return NULL; return;
assert(event->manager); assert(event->manager);
@ -171,24 +170,13 @@ static Event *event_free(Event *event) {
/* only clean up the queue from the process that created it */ /* only clean up the queue from the process that created it */
if (LIST_IS_EMPTY(event->manager->events) && if (LIST_IS_EMPTY(event->manager->events) &&
event->manager->pid == getpid_cached()) event->manager->pid == getpid_cached())
if (unlink("/run/udev/queue") < 0 && errno != ENOENT) if (unlink("/run/udev/queue") < 0)
log_warning_errno(errno, "Failed to unlink /run/udev/queue, ignoring: %m"); log_warning_errno(errno, "Failed to unlink /run/udev/queue: %m");
return mfree(event); free(event);
} }
static void event_queue_cleanup(Manager *manager, EventState match_state) { static struct worker* worker_free(struct worker *worker) {
Event *event, *tmp;
LIST_FOREACH_SAFE(event, event, tmp, manager->events) {
if (match_state != EVENT_UNDEF && match_state != event->state)
continue;
event_free(event);
}
}
static Worker *worker_free(Worker *worker) {
if (!worker) if (!worker)
return NULL; return NULL;
@ -201,8 +189,89 @@ static Worker *worker_free(Worker *worker) {
return mfree(worker); return mfree(worker);
} }
DEFINE_TRIVIAL_CLEANUP_FUNC(Worker*, worker_free); DEFINE_TRIVIAL_CLEANUP_FUNC(struct worker *, worker_free);
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(worker_hash_op, void, trivial_hash_func, trivial_compare_func, Worker, worker_free); DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(worker_hash_op, void, trivial_hash_func, trivial_compare_func, struct worker, worker_free);
static int worker_new(struct worker **ret, Manager *manager, sd_device_monitor *worker_monitor, pid_t pid) {
_cleanup_(worker_freep) struct worker *worker = NULL;
int r;
assert(ret);
assert(manager);
assert(worker_monitor);
assert(pid > 1);
/* close monitor, but keep address around */
device_monitor_disconnect(worker_monitor);
worker = new(struct worker, 1);
if (!worker)
return -ENOMEM;
*worker = (struct worker) {
.manager = manager,
.monitor = sd_device_monitor_ref(worker_monitor),
.pid = pid,
};
r = hashmap_ensure_put(&manager->workers, &worker_hash_op, PID_TO_PTR(pid), worker);
if (r < 0)
return r;
*ret = TAKE_PTR(worker);
return 0;
}
static int on_event_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
struct event *event = userdata;
assert(event);
assert(event->worker);
kill_and_sigcont(event->worker->pid, arg_timeout_signal);
event->worker->state = WORKER_KILLED;
log_device_error(event->dev, "Worker ["PID_FMT"] processing SEQNUM=%"PRIu64" killed", event->worker->pid, event->seqnum);
return 1;
}
static int on_event_timeout_warning(sd_event_source *s, uint64_t usec, void *userdata) {
struct event *event = userdata;
assert(event);
assert(event->worker);
log_device_warning(event->dev, "Worker ["PID_FMT"] processing SEQNUM=%"PRIu64" is taking a long time", event->worker->pid, event->seqnum);
return 1;
}
static void worker_attach_event(struct worker *worker, struct event *event) {
sd_event *e;
assert(worker);
assert(worker->manager);
assert(event);
assert(!event->worker);
assert(!worker->event);
worker->state = WORKER_RUNNING;
worker->event = event;
event->state = EVENT_RUNNING;
event->worker = worker;
e = worker->manager->event;
(void) sd_event_add_time_relative(e, &event->timeout_warning_event, CLOCK_MONOTONIC,
udev_warn_timeout(arg_event_timeout_usec), USEC_PER_SEC,
on_event_timeout_warning, event);
(void) sd_event_add_time_relative(e, &event->timeout_event, CLOCK_MONOTONIC,
arg_event_timeout_usec, USEC_PER_SEC,
on_event_timeout, event);
}
static void manager_clear_for_worker(Manager *manager) { static void manager_clear_for_worker(Manager *manager) {
assert(manager); assert(manager);
@ -245,109 +314,8 @@ static Manager* manager_free(Manager *manager) {
DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free); DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
static int worker_new(Worker **ret, Manager *manager, sd_device_monitor *worker_monitor, pid_t pid) {
_cleanup_(worker_freep) Worker *worker = NULL;
int r;
assert(ret);
assert(manager);
assert(worker_monitor);
assert(pid > 1);
/* close monitor, but keep address around */
device_monitor_disconnect(worker_monitor);
worker = new(Worker, 1);
if (!worker)
return -ENOMEM;
*worker = (Worker) {
.manager = manager,
.monitor = sd_device_monitor_ref(worker_monitor),
.pid = pid,
};
r = hashmap_ensure_put(&manager->workers, &worker_hash_op, PID_TO_PTR(pid), worker);
if (r < 0)
return r;
*ret = TAKE_PTR(worker);
return 0;
}
static void manager_kill_workers(Manager *manager, bool force) {
Worker *worker;
assert(manager);
HASHMAP_FOREACH(worker, manager->workers) {
if (worker->state == WORKER_KILLED)
continue;
if (worker->state == WORKER_RUNNING && !force) {
worker->state = WORKER_KILLING;
continue;
}
worker->state = WORKER_KILLED;
(void) kill(worker->pid, SIGTERM);
}
}
static void manager_exit(Manager *manager) {
assert(manager);
manager->exit = true;
sd_notify(false,
"STOPPING=1\n"
"STATUS=Starting shutdown...");
/* close sources of new events and discard buffered events */
manager->ctrl = udev_ctrl_unref(manager->ctrl);
manager->inotify_event = sd_event_source_unref(manager->inotify_event);
manager->inotify_fd = safe_close(manager->inotify_fd);
manager->monitor = sd_device_monitor_unref(manager->monitor);
/* discard queued events and kill workers */
event_queue_cleanup(manager, EVENT_QUEUED);
manager_kill_workers(manager, true);
}
/* reload requested, HUP signal received, rules changed, builtin changed */
static void manager_reload(Manager *manager) {
assert(manager);
sd_notify(false,
"RELOADING=1\n"
"STATUS=Flushing configuration...");
manager_kill_workers(manager, false);
manager->rules = udev_rules_free(manager->rules);
udev_builtin_exit();
sd_notifyf(false,
"READY=1\n"
"STATUS=Processing with %u children at max", arg_children_max);
}
static int on_kill_workers_event(sd_event_source *s, uint64_t usec, void *userdata) {
Manager *manager = userdata;
assert(manager);
log_debug("Cleanup idle workers");
manager_kill_workers(manager, false);
return 1;
}
static int worker_send_message(int fd) { static int worker_send_message(int fd) {
WorkerMessage message = {}; struct worker_message message = {};
return loop_write(fd, &message, sizeof(message), false); return loop_write(fd, &message, sizeof(message), false);
} }
@ -623,59 +591,9 @@ static int worker_main(Manager *_manager, sd_device_monitor *monitor, sd_device
return 0; return 0;
} }
static int on_event_timeout(sd_event_source *s, uint64_t usec, void *userdata) { static int worker_spawn(Manager *manager, struct event *event) {
Event *event = userdata;
assert(event);
assert(event->worker);
kill_and_sigcont(event->worker->pid, arg_timeout_signal);
event->worker->state = WORKER_KILLED;
log_device_error(event->dev, "Worker ["PID_FMT"] processing SEQNUM=%"PRIu64" killed", event->worker->pid, event->seqnum);
return 1;
}
static int on_event_timeout_warning(sd_event_source *s, uint64_t usec, void *userdata) {
Event *event = userdata;
assert(event);
assert(event->worker);
log_device_warning(event->dev, "Worker ["PID_FMT"] processing SEQNUM=%"PRIu64" is taking a long time", event->worker->pid, event->seqnum);
return 1;
}
static void worker_attach_event(Worker *worker, Event *event) {
sd_event *e;
assert(worker);
assert(worker->manager);
assert(event);
assert(!event->worker);
assert(!worker->event);
worker->state = WORKER_RUNNING;
worker->event = event;
event->state = EVENT_RUNNING;
event->worker = worker;
e = worker->manager->event;
(void) sd_event_add_time_relative(e, &event->timeout_warning_event, CLOCK_MONOTONIC,
udev_warn_timeout(arg_event_timeout_usec), USEC_PER_SEC,
on_event_timeout_warning, event);
(void) sd_event_add_time_relative(e, &event->timeout_event, CLOCK_MONOTONIC,
arg_event_timeout_usec, USEC_PER_SEC,
on_event_timeout, event);
}
static int worker_spawn(Manager *manager, Event *event) {
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *worker_monitor = NULL; _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *worker_monitor = NULL;
Worker *worker; struct worker *worker;
pid_t pid; pid_t pid;
int r; int r;
@ -717,18 +635,16 @@ static int worker_spawn(Manager *manager, Event *event) {
return 0; return 0;
} }
static int event_run(Event *event) { static void event_run(Manager *manager, struct event *event) {
static bool log_children_max_reached = true; static bool log_children_max_reached = true;
Manager *manager; struct worker *worker;
Worker *worker;
int r; int r;
assert(manager);
assert(event); assert(event);
assert(event->manager);
log_device_uevent(event->dev, "Device ready for processing"); log_device_uevent(event->dev, "Device ready for processing");
manager = event->manager;
HASHMAP_FOREACH(worker, manager->workers) { HASHMAP_FOREACH(worker, manager->workers) {
if (worker->state != WORKER_IDLE) if (worker->state != WORKER_IDLE)
continue; continue;
@ -742,73 +658,110 @@ static int event_run(Event *event) {
continue; continue;
} }
worker_attach_event(worker, event); worker_attach_event(worker, event);
return 1; /* event is now processing. */ return;
} }
if (hashmap_size(manager->workers) >= arg_children_max) { if (hashmap_size(manager->workers) >= arg_children_max) {
/* Avoid spamming the debug logs if the limit is already reached and /* Avoid spamming the debug logs if the limit is already reached and
* many events still need to be processed */ * many events still need to be processed */
if (log_children_max_reached && arg_children_max > 1) { if (log_children_max_reached && arg_children_max > 1) {
log_debug("Maximum number (%u) of children reached.", hashmap_size(manager->workers)); log_debug("Maximum number (%u) of children reached.", hashmap_size(manager->workers));
log_children_max_reached = false; log_children_max_reached = false;
} }
return 0; /* no free worker */ return;
} }
/* Re-enable the debug message for the next batch of events */ /* Re-enable the debug message for the next batch of events */
log_children_max_reached = true; log_children_max_reached = true;
/* fork with up-to-date SELinux label database, so the child inherits the up-to-date db /* fork with up-to-date SELinux label database, so the child inherits the up-to-date db
* and, until the next SELinux policy changes, we safe further reloads in future children */ and, until the next SELinux policy changes, we safe further reloads in future children */
mac_selinux_maybe_reload(); mac_selinux_maybe_reload();
/* start new worker and pass initial device */ /* start new worker and pass initial device */
r = worker_spawn(manager, event); worker_spawn(manager, event);
}
static int event_queue_insert(Manager *manager, sd_device *dev) {
_cleanup_(sd_device_unrefp) sd_device *clone = NULL;
struct event *event;
uint64_t seqnum;
int r;
assert(manager);
assert(dev);
/* only one process can add events to the queue */
assert(manager->pid == getpid_cached());
/* We only accepts devices received by device monitor. */
r = sd_device_get_seqnum(dev, &seqnum);
if (r < 0) if (r < 0)
return r; return r;
return 1; /* event is now processing. */ /* Save original device to restore the state on failures. */
r = device_shallow_clone(dev, &clone);
if (r < 0)
return r;
r = device_copy_properties(clone, dev);
if (r < 0)
return r;
event = new(struct event, 1);
if (!event)
return -ENOMEM;
*event = (struct event) {
.manager = manager,
.dev = sd_device_ref(dev),
.dev_kernel = TAKE_PTR(clone),
.seqnum = seqnum,
.state = EVENT_QUEUED,
};
if (LIST_IS_EMPTY(manager->events)) {
r = touch("/run/udev/queue");
if (r < 0)
log_warning_errno(r, "Failed to touch /run/udev/queue: %m");
}
LIST_APPEND(event, manager->events, event);
log_device_uevent(dev, "Device is queued");
return 0;
} }
static int event_is_blocked(Event *event) { static void manager_kill_workers(Manager *manager, bool force) {
struct worker *worker;
assert(manager);
HASHMAP_FOREACH(worker, manager->workers) {
if (worker->state == WORKER_KILLED)
continue;
if (worker->state == WORKER_RUNNING && !force) {
worker->state = WORKER_KILLING;
continue;
}
worker->state = WORKER_KILLED;
(void) kill(worker->pid, SIGTERM);
}
}
/* lookup event for identical, parent, child device */
static int is_device_busy(Manager *manager, struct event *event) {
const char *subsystem, *devpath, *devpath_old = NULL; const char *subsystem, *devpath, *devpath_old = NULL;
dev_t devnum = makedev(0, 0); dev_t devnum = makedev(0, 0);
Event *loop_event; struct event *loop_event;
size_t devpath_len; size_t devpath_len;
int r, ifindex = 0; int r, ifindex = 0;
bool is_block; bool is_block;
/* lookup event for identical, parent, child device */
assert(event);
assert(event->manager);
assert(event->blocker_seqnum <= event->seqnum);
if (event->blocker_seqnum == event->seqnum)
/* we have checked previously and no blocker found */
return false;
LIST_FOREACH(event, loop_event, event->manager->events) {
/* we already found a later event, earlier cannot block us, no need to check again */
if (loop_event->seqnum < event->blocker_seqnum)
continue;
/* event we checked earlier still exists, no need to check again */
if (loop_event->seqnum == event->blocker_seqnum)
return true;
/* found ourself, no later event can block us */
if (loop_event->seqnum >= event->seqnum)
goto no_blocker;
/* found event we have not checked */
break;
}
assert(loop_event);
assert(loop_event->seqnum > event->blocker_seqnum &&
loop_event->seqnum < event->seqnum);
r = sd_device_get_subsystem(event->dev, &subsystem); r = sd_device_get_subsystem(event->dev, &subsystem);
if (r < 0) if (r < 0)
return r; return r;
@ -834,13 +787,21 @@ static int event_is_blocked(Event *event) {
return r; return r;
/* check if queue contains events we depend on */ /* check if queue contains events we depend on */
LIST_FOREACH(event, loop_event, loop_event) { LIST_FOREACH(event, loop_event, manager->events) {
size_t loop_devpath_len, common; size_t loop_devpath_len, common;
const char *loop_devpath; const char *loop_devpath;
/* we already found a later event, earlier cannot block us, no need to check again */
if (loop_event->seqnum < event->delaying_seqnum)
continue;
/* event we checked earlier still exists, no need to check again */
if (loop_event->seqnum == event->delaying_seqnum)
return true;
/* found ourself, no later event can block us */ /* found ourself, no later event can block us */
if (loop_event->seqnum >= event->seqnum) if (loop_event->seqnum >= event->seqnum)
goto no_blocker; break;
/* check major/minor */ /* check major/minor */
if (major(devnum) != 0) { if (major(devnum) != 0) {
@ -852,7 +813,7 @@ static int event_is_blocked(Event *event) {
if (sd_device_get_devnum(loop_event->dev, &d) >= 0 && if (sd_device_get_devnum(loop_event->dev, &d) >= 0 &&
devnum == d && is_block == streq(s, "block")) devnum == d && is_block == streq(s, "block"))
break; goto set_delaying_seqnum;
} }
/* check network device ifindex */ /* check network device ifindex */
@ -861,7 +822,7 @@ static int event_is_blocked(Event *event) {
if (sd_device_get_ifindex(loop_event->dev, &i) >= 0 && if (sd_device_get_ifindex(loop_event->dev, &i) >= 0 &&
ifindex == i) ifindex == i)
break; goto set_delaying_seqnum;
} }
if (sd_device_get_devpath(loop_event->dev, &loop_devpath) < 0) if (sd_device_get_devpath(loop_event->dev, &loop_devpath) < 0)
@ -869,7 +830,7 @@ static int event_is_blocked(Event *event) {
/* check our old name */ /* check our old name */
if (devpath_old && streq(devpath_old, loop_devpath)) if (devpath_old && streq(devpath_old, loop_devpath))
break; goto set_delaying_seqnum;
loop_devpath_len = strlen(loop_devpath); loop_devpath_len = strlen(loop_devpath);
@ -882,32 +843,80 @@ static int event_is_blocked(Event *event) {
/* identical device event found */ /* identical device event found */
if (devpath_len == loop_devpath_len) if (devpath_len == loop_devpath_len)
break; goto set_delaying_seqnum;
/* parent device event found */ /* parent device event found */
if (devpath[common] == '/') if (devpath[common] == '/')
break; goto set_delaying_seqnum;
/* child device event found */ /* child device event found */
if (loop_devpath[common] == '/') if (loop_devpath[common] == '/')
break; goto set_delaying_seqnum;
} }
assert(loop_event); return false;
set_delaying_seqnum:
log_device_debug(event->dev, "SEQNUM=%" PRIu64 " blocked by SEQNUM=%" PRIu64, log_device_debug(event->dev, "SEQNUM=%" PRIu64 " blocked by SEQNUM=%" PRIu64,
event->seqnum, loop_event->seqnum); event->seqnum, loop_event->seqnum);
event->blocker_seqnum = loop_event->seqnum; event->delaying_seqnum = loop_event->seqnum;
return true; return true;
no_blocker:
event->blocker_seqnum = event->seqnum;
return false;
} }
static int event_queue_start(Manager *manager) { static void manager_exit(Manager *manager) {
Event *event, *event_next; assert(manager);
manager->exit = true;
sd_notify(false,
"STOPPING=1\n"
"STATUS=Starting shutdown...");
/* close sources of new events and discard buffered events */
manager->ctrl = udev_ctrl_unref(manager->ctrl);
manager->inotify_event = sd_event_source_unref(manager->inotify_event);
manager->inotify_fd = safe_close(manager->inotify_fd);
manager->monitor = sd_device_monitor_unref(manager->monitor);
/* discard queued events and kill workers */
event_queue_cleanup(manager, EVENT_QUEUED);
manager_kill_workers(manager, true);
}
/* reload requested, HUP signal received, rules changed, builtin changed */
static void manager_reload(Manager *manager) {
assert(manager);
sd_notify(false,
"RELOADING=1\n"
"STATUS=Flushing configuration...");
manager_kill_workers(manager, false);
manager->rules = udev_rules_free(manager->rules);
udev_builtin_exit();
sd_notifyf(false,
"READY=1\n"
"STATUS=Processing with %u children at max", arg_children_max);
}
static int on_kill_workers_event(sd_event_source *s, uint64_t usec, void *userdata) {
Manager *manager = userdata;
assert(manager);
log_debug("Cleanup idle workers");
manager_kill_workers(manager, false);
return 1;
}
static void event_queue_start(Manager *manager) {
struct event *event;
usec_t usec; usec_t usec;
int r; int r;
@ -915,12 +924,12 @@ static int event_queue_start(Manager *manager) {
if (LIST_IS_EMPTY(manager->events) || if (LIST_IS_EMPTY(manager->events) ||
manager->exit || manager->stop_exec_queue) manager->exit || manager->stop_exec_queue)
return 0; return;
assert_se(sd_event_now(manager->event, CLOCK_MONOTONIC, &usec) >= 0); assert_se(sd_event_now(manager->event, CLOCK_MONOTONIC, &usec) >= 0);
/* check for changed config, every 3 seconds at most */ /* check for changed config, every 3 seconds at most */
if (manager->last_usec == 0 || if (manager->last_usec == 0 ||
usec > usec_add(manager->last_usec, 3 * USEC_PER_SEC)) { usec - manager->last_usec > 3 * USEC_PER_SEC) {
if (udev_rules_check_timestamp(manager->rules) || if (udev_rules_check_timestamp(manager->rules) ||
udev_builtin_validate()) udev_builtin_validate())
manager_reload(manager); manager_reload(manager);
@ -936,111 +945,33 @@ static int event_queue_start(Manager *manager) {
if (!manager->rules) { if (!manager->rules) {
r = udev_rules_load(&manager->rules, arg_resolve_name_timing); r = udev_rules_load(&manager->rules, arg_resolve_name_timing);
if (r < 0) if (r < 0) {
return log_warning_errno(r, "Failed to read udev rules: %m"); log_warning_errno(r, "Failed to read udev rules: %m");
return;
}
} }
LIST_FOREACH_SAFE(event, event, event_next, manager->events) { LIST_FOREACH(event, event, manager->events) {
if (event->state != EVENT_QUEUED) if (event->state != EVENT_QUEUED)
continue; continue;
/* do not start event if parent or child event is still running or queued */ /* do not start event if parent or child event is still running */
r = event_is_blocked(event); if (is_device_busy(manager, event) != 0)
if (r < 0) {
sd_device_action_t a = _SD_DEVICE_ACTION_INVALID;
(void) sd_device_get_action(event->dev, &a);
log_device_warning_errno(event->dev, r,
"Failed to check event dependency, "
"skipping event (SEQNUM=%"PRIu64", ACTION=%s)",
event->seqnum,
strna(device_action_to_string(a)));
event_free(event);
return r;
}
if (r > 0)
continue; continue;
r = event_run(event); event_run(manager, event);
if (r <= 0)
return r;
} }
return 0;
} }
static int event_queue_insert(Manager *manager, sd_device *dev) { static void event_queue_cleanup(Manager *manager, enum event_state match_type) {
_cleanup_(sd_device_unrefp) sd_device *clone = NULL; struct event *event, *tmp;
Event *event;
uint64_t seqnum;
int r;
assert(manager); LIST_FOREACH_SAFE(event, event, tmp, manager->events) {
assert(dev); if (match_type != EVENT_UNDEF && match_type != event->state)
continue;
/* only one process can add events to the queue */ event_free(event);
assert(manager->pid == getpid_cached());
/* We only accepts devices received by device monitor. */
r = sd_device_get_seqnum(dev, &seqnum);
if (r < 0)
return r;
/* Save original device to restore the state on failures. */
r = device_shallow_clone(dev, &clone);
if (r < 0)
return r;
r = device_copy_properties(clone, dev);
if (r < 0)
return r;
event = new(Event, 1);
if (!event)
return -ENOMEM;
*event = (Event) {
.manager = manager,
.dev = sd_device_ref(dev),
.dev_kernel = TAKE_PTR(clone),
.seqnum = seqnum,
.state = EVENT_QUEUED,
};
if (LIST_IS_EMPTY(manager->events)) {
r = touch("/run/udev/queue");
if (r < 0)
log_warning_errno(r, "Failed to touch /run/udev/queue, ignoring: %m");
} }
LIST_APPEND(event, manager->events, event);
log_device_uevent(dev, "Device is queued");
return 0;
}
static int on_uevent(sd_device_monitor *monitor, sd_device *dev, void *userdata) {
Manager *manager = userdata;
int r;
assert(manager);
DEVICE_TRACE_POINT(kernel_uevent_received, dev);
device_ensure_usec_initialized(dev, NULL);
r = event_queue_insert(manager, dev);
if (r < 0) {
log_device_error_errno(dev, r, "Failed to insert device into event queue: %m");
return 1;
}
/* we have fresh events, try to schedule them */
event_queue_start(manager);
return 1;
} }
static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdata) { static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
@ -1049,7 +980,7 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
assert(manager); assert(manager);
for (;;) { for (;;) {
WorkerMessage msg; struct worker_message msg;
struct iovec iovec = { struct iovec iovec = {
.iov_base = &msg, .iov_base = &msg,
.iov_len = sizeof(msg), .iov_len = sizeof(msg),
@ -1063,7 +994,7 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
}; };
ssize_t size; ssize_t size;
struct ucred *ucred; struct ucred *ucred;
Worker *worker; struct worker *worker;
size = recvmsg_safe(fd, &msghdr, MSG_DONTWAIT); size = recvmsg_safe(fd, &msghdr, MSG_DONTWAIT);
if (size == -EINTR) if (size == -EINTR)
@ -1076,7 +1007,7 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
cmsg_close_all(&msghdr); cmsg_close_all(&msghdr);
if (size != sizeof(WorkerMessage)) { if (size != sizeof(struct worker_message)) {
log_warning("Ignoring worker message with invalid size %zi bytes", size); log_warning("Ignoring worker message with invalid size %zi bytes", size);
continue; continue;
} }
@ -1110,8 +1041,30 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
return 1; return 1;
} }
static int on_uevent(sd_device_monitor *monitor, sd_device *dev, void *userdata) {
Manager *manager = userdata;
int r;
assert(manager);
DEVICE_TRACE_POINT(kernel_uevent_received, dev);
device_ensure_usec_initialized(dev, NULL);
r = event_queue_insert(manager, dev);
if (r < 0) {
log_device_error_errno(dev, r, "Failed to insert device into event queue: %m");
return 1;
}
/* we have fresh events, try to schedule them */
event_queue_start(manager);
return 1;
}
/* receive the udevd message from userspace */ /* receive the udevd message from userspace */
static int on_ctrl_msg(UdevCtrl *uctrl, UdevCtrlMessageType type, const UdevCtrlMessageValue *value, void *userdata) { static int on_ctrl_msg(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, const union udev_ctrl_msg_value *value, void *userdata) {
Manager *manager = userdata; Manager *manager = userdata;
int r; int r;
@ -1404,7 +1357,7 @@ static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, voi
for (;;) { for (;;) {
pid_t pid; pid_t pid;
int status; int status;
Worker *worker; struct worker *worker;
pid = waitpid(-1, &status, WNOHANG); pid = waitpid(-1, &status, WNOHANG);
if (pid <= 0) if (pid <= 0)

View File

@ -674,9 +674,9 @@ class NetworkctlTests(unittest.TestCase, Utilities):
output = check_output('ip -4 address show dev dummy98') output = check_output('ip -4 address show dev dummy98')
print(output) print(output)
self.assertIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output) self.assertRegex(output, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
self.assertIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output) self.assertRegex(output, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
self.assertIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output) self.assertRegex(output, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
check_output('ip address del 10.1.2.3/16 dev dummy98') check_output('ip address del 10.1.2.3/16 dev dummy98')
check_output('ip address del 10.1.2.4/16 dev dummy98') check_output('ip address del 10.1.2.4/16 dev dummy98')
@ -687,30 +687,9 @@ class NetworkctlTests(unittest.TestCase, Utilities):
output = check_output('ip -4 address show dev dummy98') output = check_output('ip -4 address show dev dummy98')
print(output) print(output)
self.assertIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output) self.assertRegex(output, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
self.assertIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output) self.assertRegex(output, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
self.assertIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output) self.assertRegex(output, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
remove_unit_from_networkd_path(['25-address-static.network'])
check_output(*networkctl_cmd, 'reload', env=env)
self.wait_operstate('dummy98', 'degraded', setup_state='unmanaged')
output = check_output('ip -4 address show dev dummy98')
print(output)
self.assertNotIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output)
self.assertNotIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output)
self.assertNotIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output)
copy_unit_to_networkd_unit_path('25-address-static.network')
check_output(*networkctl_cmd, 'reload', env=env)
self.wait_online(['dummy98:routable'])
output = check_output('ip -4 address show dev dummy98')
print(output)
self.assertIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output)
self.assertIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output)
self.assertIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output)
def test_reload(self): def test_reload(self):
start_networkd(3) start_networkd(3)

View File

@ -4,13 +4,4 @@ Description=TEST-10-ISSUE-2467
[Service] [Service]
ExecStartPre=rm -f /failed /testok ExecStartPre=rm -f /failed /testok
Type=oneshot Type=oneshot
ExecStart=rm -f /tmp/nonexistent ExecStart=sh -e -x -c 'rm -f /tmp/nonexistent; systemctl start test10.socket; printf x >test.file; socat -t20 OPEN:test.file UNIX-CONNECT:/run/test.ctl; >/testok'
ExecStart=systemctl start test10.socket
ExecStart=sh -x -c 'printf x >test.file'
ExecStart=-socat -T20 OPEN:test.file UNIX-CONNECT:/run/test.ctl
# TriggerLimitIntervalSec= by default is set to 2s. A "sleep 10" should give
# systemd enough time even on slower machines, to reach the trigger limit.
ExecStart=sleep 10
ExecStart=sh -x -c 'test "$(systemctl show test10.socket -P ActiveState)" = failed'
ExecStart=sh -x -c 'test "$(systemctl show test10.socket -P Result)" = trigger-limit-hit'
ExecStart=sh -x -c 'echo OK >/testok'

View File

@ -1,12 +0,0 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
#
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=Target that triggers factory reset. Does nothing by default.
Documentation=man:systemd.special(7)

View File

@ -19,7 +19,6 @@ units = [
'sysinit.target.wants/'], 'sysinit.target.wants/'],
['emergency.target', ''], ['emergency.target', ''],
['exit.target', ''], ['exit.target', ''],
['factory-reset.target', ''],
['final.target', ''], ['final.target', ''],
['first-boot-complete.target', ''], ['first-boot-complete.target', ''],
['getty.target', '', ['getty.target', '',