mirror of
https://github.com/systemd/systemd
synced 2026-03-25 00:04:53 +01:00
Compare commits
37 Commits
63c00743f4
...
836fb00f21
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
836fb00f21 | ||
|
|
b553abd8ae | ||
|
|
d84f316cce | ||
|
|
9a6549f6f8 | ||
|
|
b2efed520b | ||
|
|
a7a04de0ec | ||
|
|
76b34df91f | ||
|
|
8fd9920273 | ||
|
|
5e739f7eed | ||
|
|
c6f78234d1 | ||
|
|
044ac33c35 | ||
|
|
bd335c961f | ||
|
|
a1fa99d841 | ||
|
|
5f4bca9dcc | ||
|
|
f2a5412bf2 | ||
|
|
92fd70addf | ||
|
|
0744e74c52 | ||
|
|
5393c52897 | ||
|
|
6be97d67c8 | ||
|
|
419ec63135 | ||
|
|
e0d61dac33 | ||
|
|
d9239923c1 | ||
|
|
4c2c2a1256 | ||
|
|
ae48d2d142 | ||
|
|
f784681a3e | ||
|
|
b378b150b7 | ||
|
|
8716018664 | ||
|
|
ccffa166d8 | ||
|
|
6211b7362a | ||
|
|
bc8bd68db8 | ||
|
|
5aebe9c898 | ||
|
|
3bad5487e9 | ||
|
|
cb71e9c606 | ||
|
|
5e3bb5da98 | ||
|
|
6bfa06fc39 | ||
|
|
f85499108f | ||
|
|
d09a179e69 |
9
TODO
9
TODO
@ -83,6 +83,15 @@ Janitorial Clean-ups:
|
||||
|
||||
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
|
||||
|
||||
* New udev block device symlink names:
|
||||
|
||||
@ -188,6 +188,15 @@ Support: %SUPPORT_URL%
|
||||
System shutdown has been initiated. The shutdown has now begun and
|
||||
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
|
||||
Subject: A start job for unit @UNIT@ has begun execution
|
||||
Defined-By: systemd
|
||||
|
||||
@ -216,8 +216,9 @@
|
||||
<literal>suspend</literal>,
|
||||
<literal>hibernate</literal>,
|
||||
<literal>hybrid-sleep</literal>,
|
||||
<literal>suspend-then-hibernate</literal>, and
|
||||
<literal>lock</literal>.
|
||||
<literal>suspend-then-hibernate</literal>,
|
||||
<literal>lock</literal>, and
|
||||
<literal>factory-reset</literal>.
|
||||
If <literal>ignore</literal>, logind will never handle these
|
||||
keys. If <literal>lock</literal>, all running sessions will be
|
||||
screen-locked; otherwise, the specified action will be taken
|
||||
|
||||
@ -33,6 +33,7 @@
|
||||
<filename>default.target</filename>,
|
||||
<filename>emergency.target</filename>,
|
||||
<filename>exit.target</filename>,
|
||||
<filename>factory-reset.target</filename>,
|
||||
<filename>final.target</filename>,
|
||||
<filename>first-boot-complete.target</filename>,
|
||||
<filename>getty.target</filename>,
|
||||
@ -279,6 +280,12 @@
|
||||
shutdown when the service manager starts to exit.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><filename>factory-reset.target</filename></term>
|
||||
<listitem>
|
||||
<para>A special target to trigger a factory reset.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><filename>final.target</filename></term>
|
||||
<listitem>
|
||||
|
||||
@ -142,11 +142,8 @@
|
||||
#define LIST_FOREACH_SAFE(name,i,n,head) \
|
||||
for ((i) = (head); (i) && (((n) = (i)->name##_next), 1); (i) = (n))
|
||||
|
||||
#define LIST_FOREACH_BEFORE(name,i,p) \
|
||||
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)
|
||||
#define LIST_FOREACH_BACKWARDS(name,i,p) \
|
||||
for ((i) = (p); (i); (i) = (i)->name##_prev)
|
||||
|
||||
/* Iterate through all the members of the list p is included in, but skip over p */
|
||||
#define LIST_FOREACH_OTHERS(name,i,p) \
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
#define SPECIAL_HIBERNATE_TARGET "hibernate.target"
|
||||
#define SPECIAL_HYBRID_SLEEP_TARGET "hybrid-sleep.target"
|
||||
#define SPECIAL_SUSPEND_THEN_HIBERNATE_TARGET "suspend-then-hibernate.target"
|
||||
#define SPECIAL_FACTORY_RESET_TARGET "factory-reset.target"
|
||||
|
||||
/* Special boot targets */
|
||||
#define SPECIAL_RESCUE_TARGET "rescue.target"
|
||||
|
||||
@ -771,11 +771,11 @@ static Unit *device_following(Unit *u) {
|
||||
return NULL;
|
||||
|
||||
/* Make everybody follow the unit that's named after the sysfs path */
|
||||
LIST_FOREACH_AFTER(same_sysfs, other, d)
|
||||
LIST_FOREACH(same_sysfs, other, d->same_sysfs_next)
|
||||
if (startswith(UNIT(other)->id, "sys-"))
|
||||
return UNIT(other);
|
||||
|
||||
LIST_FOREACH_BEFORE(same_sysfs, other, d) {
|
||||
LIST_FOREACH_BACKWARDS(same_sysfs, other, d->same_sysfs_prev) {
|
||||
if (startswith(UNIT(other)->id, "sys-"))
|
||||
return UNIT(other);
|
||||
|
||||
@ -802,13 +802,13 @@ static int device_following_set(Unit *u, Set **_set) {
|
||||
if (!set)
|
||||
return -ENOMEM;
|
||||
|
||||
LIST_FOREACH_AFTER(same_sysfs, other, d) {
|
||||
LIST_FOREACH(same_sysfs, other, d->same_sysfs_next) {
|
||||
r = set_put(set, other);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
LIST_FOREACH_BEFORE(same_sysfs, other, d) {
|
||||
LIST_FOREACH_BACKWARDS(same_sysfs, other, d->same_sysfs_prev) {
|
||||
r = set_put(set, other);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -1323,11 +1323,11 @@ static Unit *swap_following(Unit *u) {
|
||||
if (streq_ptr(s->what, s->devnode))
|
||||
return NULL;
|
||||
|
||||
LIST_FOREACH_AFTER(same_devnode, other, s)
|
||||
LIST_FOREACH(same_devnode, other, s->same_devnode_next)
|
||||
if (streq_ptr(other->what, other->devnode))
|
||||
return UNIT(other);
|
||||
|
||||
LIST_FOREACH_BEFORE(same_devnode, other, s) {
|
||||
LIST_FOREACH_BACKWARDS(same_devnode, other, s->same_devnode_prev) {
|
||||
if (streq_ptr(other->what, other->devnode))
|
||||
return UNIT(other);
|
||||
|
||||
|
||||
@ -451,6 +451,10 @@ static int add_mount(
|
||||
"\n"
|
||||
"[Mount]\n");
|
||||
|
||||
r = write_what(f, what);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (original_where)
|
||||
fprintf(f, "# Canonicalized from %s\n", original_where);
|
||||
|
||||
@ -459,10 +463,6 @@ static int add_mount(
|
||||
return log_oom();
|
||||
fprintf(f, "Where=%s\n", where_escaped);
|
||||
|
||||
r = write_what(f, what);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!isempty(fstype) && !streq(fstype, "auto")) {
|
||||
_cleanup_free_ char *t = NULL;
|
||||
|
||||
|
||||
@ -27,6 +27,7 @@ const char* manager_target_for_action(HandleAction handle) {
|
||||
[HANDLE_HIBERNATE] = SPECIAL_HIBERNATE_TARGET,
|
||||
[HANDLE_HYBRID_SLEEP] = SPECIAL_HYBRID_SLEEP_TARGET,
|
||||
[HANDLE_SUSPEND_THEN_HIBERNATE] = SPECIAL_SUSPEND_THEN_HIBERNATE_TARGET,
|
||||
[HANDLE_FACTORY_RESET] = SPECIAL_FACTORY_RESET_TARGET,
|
||||
};
|
||||
|
||||
assert(handle >= 0);
|
||||
@ -51,6 +52,7 @@ int manager_handle_action(
|
||||
[HANDLE_HIBERNATE] = "Hibernating...",
|
||||
[HANDLE_HYBRID_SLEEP] = "Hibernating and suspending...",
|
||||
[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;
|
||||
@ -179,6 +181,7 @@ static const char* const handle_action_table[_HANDLE_ACTION_MAX] = {
|
||||
[HANDLE_HIBERNATE] = "hibernate",
|
||||
[HANDLE_HYBRID_SLEEP] = "hybrid-sleep",
|
||||
[HANDLE_SUSPEND_THEN_HIBERNATE] = "suspend-then-hibernate",
|
||||
[HANDLE_FACTORY_RESET] = "factory-reset",
|
||||
[HANDLE_LOCK] = "lock",
|
||||
};
|
||||
|
||||
|
||||
@ -14,6 +14,7 @@ typedef enum HandleAction {
|
||||
HANDLE_HYBRID_SLEEP,
|
||||
HANDLE_SUSPEND_THEN_HIBERNATE,
|
||||
HANDLE_LOCK,
|
||||
HANDLE_FACTORY_RESET,
|
||||
_HANDLE_ACTION_MAX,
|
||||
_HANDLE_ACTION_INVALID = -EINVAL,
|
||||
} HandleAction;
|
||||
|
||||
@ -1491,41 +1491,59 @@ static int have_multiple_sessions(
|
||||
return false;
|
||||
}
|
||||
|
||||
static int bus_manager_log_shutdown(
|
||||
Manager *m,
|
||||
const char *unit_name) {
|
||||
|
||||
const char *p, *q;
|
||||
|
||||
_printf_(2, 0)
|
||||
static int log_with_wall_message(Manager *m, const char *d, const char *p, const char *q) {
|
||||
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))
|
||||
p = strjoina(p, ".");
|
||||
else
|
||||
p = strjoina(p, " (", m->wall_message, ").");
|
||||
|
||||
return log_struct(LOG_NOTICE,
|
||||
return log_struct(LOG_NOTICE, d, p, q);
|
||||
}
|
||||
|
||||
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,
|
||||
p,
|
||||
q);
|
||||
"MESSAGE=System is powering down",
|
||||
"SHUTDOWN=power-off");
|
||||
|
||||
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) {
|
||||
|
||||
@ -96,113 +96,64 @@ const DUID *link_get_duid(Link *link, int family) {
|
||||
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) {
|
||||
Manager *manager = userdata;
|
||||
const sd_bus_error *e;
|
||||
const void *a;
|
||||
size_t sz;
|
||||
Link *link;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
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);
|
||||
if (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",
|
||||
bus_error_message(e, r));
|
||||
goto configure;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_bus_message_read_array(m, 'y', &a, &sz);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Failed to get product UUID. Falling back to use machine-app-specific ID as DUID-UUID: %m");
|
||||
goto configure;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sz != sizeof(sd_id128_t)) {
|
||||
log_warning("Invalid product UUID. Falling back to use machine-app-specific ID as DUID-UUID.");
|
||||
goto configure;
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_debug("Successfully obtained product UUID");
|
||||
|
||||
memcpy(&manager->duid_product_uuid.raw_data, a, sz);
|
||||
manager->duid_product_uuid.raw_data_len = sz;
|
||||
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int manager_request_product_uuid(Manager *m) {
|
||||
static bool bus_method_is_called = false;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
|
||||
if (m->product_uuid_requested)
|
||||
if (bus_method_is_called)
|
||||
return 0;
|
||||
|
||||
log_debug("Requesting product UUID");
|
||||
|
||||
if (sd_bus_is_ready(m->bus) <= 0) {
|
||||
if (sd_bus_is_ready(m->bus) <= 0 && !m->product_uuid_requested) {
|
||||
log_debug("Not connected to system bus, requesting product UUID later.");
|
||||
m->product_uuid_requested = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
m->product_uuid_requested = false;
|
||||
|
||||
r = sd_bus_call_method_async(
|
||||
m->bus,
|
||||
NULL,
|
||||
@ -217,7 +168,9 @@ int manager_request_product_uuid(Manager *m) {
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "Failed to get product UUID: %m");
|
||||
|
||||
m->product_uuid_requested = true;
|
||||
log_debug("Requesting product UUID.");
|
||||
|
||||
bus_method_is_called = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -242,15 +195,11 @@ int dhcp_configure_duid(Link *link, const DUID *duid) {
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(link, r,
|
||||
"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;
|
||||
}
|
||||
|
||||
r = set_ensure_put(&m->links_requesting_uuid, NULL, link);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
if (r > 0)
|
||||
link_ref(link);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -543,8 +492,8 @@ int config_parse_iaid(const char *unit,
|
||||
network->dhcp_iaid = iaid;
|
||||
network->dhcp_iaid_set = true;
|
||||
if (!network->dhcp6_iaid_set_explicitly) {
|
||||
/* Backward compatibility. Previously, IAID is shared by DHCP4 and DHCP6.
|
||||
* If DHCP6 IAID is not specified explicitly, then use DHCP4 IAID for DHCP6. */
|
||||
/* Backward compatibility. Previously, IAID is shared by DHCPv4 and DHCPv6.
|
||||
* If DHCPv6 IAID is not specified explicitly, then use DHCPv4 IAID for DHCPv6. */
|
||||
network->dhcp6_iaid = iaid;
|
||||
network->dhcp6_iaid_set = true;
|
||||
}
|
||||
@ -1036,7 +985,7 @@ int config_parse_manager_duid_type(
|
||||
|
||||
assert(manager);
|
||||
|
||||
/* For backward compatibility. Setting both DHCP4 and DHCP6 DUID if they are not specified explicitly. */
|
||||
/* For backward compatibility. Setting both DHCPv4 and DHCPv6 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);
|
||||
if (r < 0)
|
||||
@ -1066,7 +1015,7 @@ int config_parse_network_duid_type(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* For backward compatibility, also set DHCP6 DUID if not specified explicitly. */
|
||||
/* For backward compatibility, also set DHCPv6 DUID if not specified explicitly. */
|
||||
return config_parse_duid_type(unit, filename, line, section, section_line, lvalue, false, rvalue, &network->dhcp6_duid, network);
|
||||
}
|
||||
|
||||
@ -1161,7 +1110,7 @@ int config_parse_manager_duid_rawdata(
|
||||
|
||||
assert(manager);
|
||||
|
||||
/* For backward compatibility. Setting both DHCP4 and DHCP6 DUID if they are not specified explicitly. */
|
||||
/* For backward compatibility. Setting both DHCPv4 and DHCPv6 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);
|
||||
if (r < 0)
|
||||
@ -1191,6 +1140,6 @@ int config_parse_network_duid_rawdata(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* For backward compatibility, also set DHCP6 DUID if not specified explicitly. */
|
||||
/* For backward compatibility, also set DHCPv6 DUID if not specified explicitly. */
|
||||
return config_parse_duid_rawdata(unit, filename, line, section, section_line, lvalue, false, rvalue, &network->dhcp6_duid, network);
|
||||
}
|
||||
|
||||
@ -1311,7 +1311,7 @@ static int dhcp4_set_hostname(Link *link) {
|
||||
else {
|
||||
r = gethostname_strict(&hostname);
|
||||
if (r < 0 && r != -ENXIO) /* ENXIO: no hostname set or hostname is "localhost" */
|
||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to get hostname: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to get hostname: %m");
|
||||
|
||||
hn = hostname;
|
||||
}
|
||||
@ -1319,9 +1319,9 @@ static int dhcp4_set_hostname(Link *link) {
|
||||
r = sd_dhcp_client_set_hostname(link->dhcp_client, hn);
|
||||
if (r == -EINVAL && hostname)
|
||||
/* Ignore error when the machine's hostname is not suitable to send in DHCP packet. */
|
||||
log_link_debug_errno(link, r, "DHCP4 CLIENT: Failed to set hostname from kernel hostname, ignoring: %m");
|
||||
log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set hostname from kernel hostname, ignoring: %m");
|
||||
else if (r < 0)
|
||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set hostname: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set hostname: %m");
|
||||
|
||||
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);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set IAID+DUID: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set IAID+DUID: %m");
|
||||
break;
|
||||
}
|
||||
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);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set DUID: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set DUID: %m");
|
||||
break;
|
||||
}
|
||||
case DHCP_CLIENT_ID_MAC: {
|
||||
@ -1385,7 +1385,7 @@ static int dhcp4_set_client_identifier(Link *link) {
|
||||
hw_addr,
|
||||
hw_addr_len);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set client ID: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set client ID: %m");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -1395,15 +1395,6 @@ static int dhcp4_set_client_identifier(Link *link) {
|
||||
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) {
|
||||
Address *a;
|
||||
|
||||
@ -1424,7 +1415,7 @@ static int dhcp4_set_request_address(Link *link) {
|
||||
if (!a)
|
||||
return 0;
|
||||
|
||||
log_link_debug(link, "DHCP4 CLIENT: requesting " IPV4_ADDRESS_FMT_STR, IPV4_ADDRESS_FMT_VAL(a->in_addr.in));
|
||||
log_link_debug(link, "DHCPv4 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);
|
||||
}
|
||||
@ -1445,15 +1436,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) {
|
||||
r = parse_boolean(val);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to parse ID_NET_DHCP_BROADCAST, ignoring: %m");
|
||||
log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to parse ID_NET_DHCP_BROADCAST, ignoring: %m");
|
||||
else
|
||||
log_link_debug(link, "DHCP4 CLIENT: Detected ID_NET_DHCP_BROADCAST='%d'.", r);
|
||||
log_link_debug(link, "DHCPv4 CLIENT: Detected ID_NET_DHCP_BROADCAST='%d'.", r);
|
||||
|
||||
}
|
||||
return r == true;
|
||||
}
|
||||
|
||||
int dhcp4_configure(Link *link) {
|
||||
static int dhcp4_configure(Link *link) {
|
||||
sd_dhcp_option *send_option;
|
||||
void *request_options;
|
||||
int r;
|
||||
@ -1461,88 +1452,81 @@ int dhcp4_configure(Link *link) {
|
||||
assert(link);
|
||||
assert(link->network);
|
||||
|
||||
if (!link_dhcp4_enabled(link))
|
||||
return 0;
|
||||
|
||||
if (link->dhcp_client)
|
||||
return -EBUSY; /* Already configured. */
|
||||
|
||||
r = dhcp4_configure_duid(link);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
return log_link_debug_errno(link, SYNTHETIC_ERRNO(EBUSY), "DHCPv4 client is already configured.");
|
||||
|
||||
r = sd_dhcp_client_new(&link->dhcp_client, link->network->dhcp_anonymize);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to allocate DHCP4 client: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to allocate DHCPv4 client: %m");
|
||||
|
||||
r = sd_dhcp_client_attach_event(link->dhcp_client, link->manager->event, 0);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to attach event to DHCP4 client: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to attach event to DHCPv4 client: %m");
|
||||
|
||||
r = sd_dhcp_client_set_mac(link->dhcp_client,
|
||||
link->hw_addr.bytes,
|
||||
link->bcast_addr.length > 0 ? link->bcast_addr.bytes : NULL,
|
||||
link->hw_addr.length, link->iftype);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set MAC address: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set MAC address: %m");
|
||||
|
||||
r = sd_dhcp_client_set_ifindex(link->dhcp_client, link->ifindex);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set ifindex: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set ifindex: %m");
|
||||
|
||||
r = sd_dhcp_client_set_callback(link->dhcp_client, dhcp4_handler, link);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set callback: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set callback: %m");
|
||||
|
||||
r = sd_dhcp_client_set_request_broadcast(link->dhcp_client, link_needs_dhcp_broadcast(link));
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for broadcast: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for broadcast: %m");
|
||||
|
||||
if (link->mtu > 0) {
|
||||
r = sd_dhcp_client_set_mtu(link->dhcp_client, link->mtu);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set MTU: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set MTU: %m");
|
||||
}
|
||||
|
||||
if (!link->network->dhcp_anonymize) {
|
||||
if (link->network->dhcp_use_mtu) {
|
||||
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_INTERFACE_MTU);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for MTU: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for MTU: %m");
|
||||
}
|
||||
|
||||
if (link->network->dhcp_use_routes) {
|
||||
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_STATIC_ROUTE);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for static route: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv4 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);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for classless static route: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for classless static route: %m");
|
||||
}
|
||||
|
||||
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);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for domain search list: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for domain search list: %m");
|
||||
}
|
||||
|
||||
if (link->network->dhcp_use_ntp) {
|
||||
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NTP_SERVER);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for NTP server: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for NTP server: %m");
|
||||
}
|
||||
|
||||
if (link->network->dhcp_use_sip) {
|
||||
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_SIP_SERVER);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for SIP server: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for SIP server: %m");
|
||||
}
|
||||
|
||||
if (link->network->dhcp_use_timezone) {
|
||||
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NEW_TZDB_TIMEZONE);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for timezone: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for timezone: %m");
|
||||
}
|
||||
|
||||
SET_FOREACH(request_options, link->network->dhcp_request_options) {
|
||||
@ -1550,7 +1534,7 @@ int dhcp4_configure(Link *link) {
|
||||
|
||||
r = sd_dhcp_client_set_request_option(link->dhcp_client, option);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for '%u': %m", option);
|
||||
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for '%u': %m", option);
|
||||
}
|
||||
|
||||
ORDERED_HASHMAP_FOREACH(send_option, link->network->dhcp_client_send_options) {
|
||||
@ -1558,7 +1542,7 @@ int dhcp4_configure(Link *link) {
|
||||
if (r == -EEXIST)
|
||||
continue;
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set send option: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set send option: %m");
|
||||
}
|
||||
|
||||
ORDERED_HASHMAP_FOREACH(send_option, link->network->dhcp_client_send_vendor_options) {
|
||||
@ -1566,7 +1550,7 @@ int dhcp4_configure(Link *link) {
|
||||
if (r == -EEXIST)
|
||||
continue;
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set send option: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set send option: %m");
|
||||
}
|
||||
|
||||
r = dhcp4_set_hostname(link);
|
||||
@ -1577,49 +1561,49 @@ int dhcp4_configure(Link *link) {
|
||||
r = sd_dhcp_client_set_vendor_class_identifier(link->dhcp_client,
|
||||
link->network->dhcp_vendor_class_identifier);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set vendor class identifier: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set vendor class identifier: %m");
|
||||
}
|
||||
|
||||
if (link->network->dhcp_mudurl) {
|
||||
r = sd_dhcp_client_set_mud_url(link->dhcp_client, link->network->dhcp_mudurl);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set MUD URL: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set MUD URL: %m");
|
||||
}
|
||||
|
||||
if (link->network->dhcp_user_class) {
|
||||
r = sd_dhcp_client_set_user_class(link->dhcp_client, link->network->dhcp_user_class);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set user class: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set user class: %m");
|
||||
}
|
||||
}
|
||||
|
||||
if (link->network->dhcp_client_port > 0) {
|
||||
r = sd_dhcp_client_set_client_port(link->dhcp_client, link->network->dhcp_client_port);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set listen port: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set listen port: %m");
|
||||
}
|
||||
|
||||
if (link->network->dhcp_max_attempts > 0) {
|
||||
r = sd_dhcp_client_set_max_attempts(link->dhcp_client, link->network->dhcp_max_attempts);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set max attempts: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set max attempts: %m");
|
||||
}
|
||||
|
||||
if (link->network->dhcp_ip_service_type > 0) {
|
||||
r = sd_dhcp_client_set_service_type(link->dhcp_client, link->network->dhcp_ip_service_type);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set IP service type: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set IP service type: %m");
|
||||
}
|
||||
|
||||
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);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed set to lease lifetime: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed set to lease lifetime: %m");
|
||||
}
|
||||
|
||||
r = dhcp4_set_request_address(link);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set initial DHCPv4 address: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set initial DHCPv4 address: %m");
|
||||
|
||||
return dhcp4_set_client_identifier(link);
|
||||
}
|
||||
@ -1642,17 +1626,83 @@ int dhcp4_update_mac(Link *link) {
|
||||
}
|
||||
|
||||
int dhcp4_start(Link *link) {
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
|
||||
if (!link->dhcp_client)
|
||||
return 0;
|
||||
|
||||
if (!link_has_carrier(link))
|
||||
return 0;
|
||||
|
||||
if (sd_dhcp_client_is_running(link->dhcp_client) > 0)
|
||||
return 0;
|
||||
|
||||
log_link_debug(link, "Acquiring DHCPv4 lease");
|
||||
r = sd_dhcp_client_start(link->dhcp_client);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_dhcp_client_start(link->dhcp_client);
|
||||
return 1;
|
||||
}
|
||||
|
||||
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(
|
||||
|
||||
@ -4,6 +4,8 @@
|
||||
#include "conf-parser.h"
|
||||
|
||||
typedef struct Link Link;
|
||||
typedef struct Network Network;
|
||||
typedef struct Request Request;
|
||||
|
||||
typedef enum DHCPClientIdentifier {
|
||||
DHCP_CLIENT_ID_MAC,
|
||||
@ -18,11 +20,13 @@ typedef enum DHCPClientIdentifier {
|
||||
} DHCPClientIdentifier;
|
||||
|
||||
void network_adjust_dhcp4(Network *network);
|
||||
int dhcp4_configure(Link *link);
|
||||
int dhcp4_update_mac(Link *link);
|
||||
int dhcp4_start(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_acl_ip_address);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_max_attempts);
|
||||
|
||||
@ -920,7 +920,7 @@ static int dhcp6_pd_prefix_add(Link *link, const struct in6_addr *prefix, uint8_
|
||||
log_link_full(link,
|
||||
set_contains(link->dhcp6_pd_prefixes, p) ? LOG_DEBUG :
|
||||
prefixlen > 64 || prefixlen < 48 ? LOG_WARNING : LOG_INFO,
|
||||
"DHCP6: received PD Prefix %s%s",
|
||||
"DHCPv6: received PD Prefix %s%s",
|
||||
strna(buf),
|
||||
prefixlen > 64 ? " with prefix length > 64, ignoring." :
|
||||
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. */
|
||||
r = set_ensure_put(&link->dhcp6_pd_prefixes, &in_addr_prefix_hash_ops_free, p);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Failed to store DHCP6 PD prefix %s: %m", strna(buf));
|
||||
return log_link_error_errno(link, r, "Failed to store DHCPv6 PD prefix %s: %m", strna(buf));
|
||||
if (r > 0)
|
||||
TAKE_PTR(p);
|
||||
|
||||
@ -1393,6 +1393,8 @@ int dhcp6_request_information(Link *link, int ir) {
|
||||
}
|
||||
|
||||
int dhcp6_start(Link *link) {
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
|
||||
if (!link->dhcp6_client)
|
||||
@ -1401,6 +1403,9 @@ int dhcp6_start(Link *link) {
|
||||
if (!link_dhcp6_enabled(link))
|
||||
return 0;
|
||||
|
||||
if (!link_has_carrier(link))
|
||||
return 0;
|
||||
|
||||
if (link->network->dhcp6_without_ra == DHCP6_CLIENT_START_MODE_NO)
|
||||
return 0;
|
||||
|
||||
@ -1412,9 +1417,11 @@ int dhcp6_start(Link *link) {
|
||||
if (sd_dhcp6_client_is_running(link->dhcp6_client) > 0)
|
||||
return 0;
|
||||
|
||||
log_link_debug(link, "Acquiring DHCPv6 lease");
|
||||
r = dhcp6_request_information(link, link->network->dhcp6_without_ra == DHCP6_CLIENT_START_MODE_INFORMATION_REQUEST);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return dhcp6_request_information(link, link->network->dhcp6_without_ra == DHCP6_CLIENT_START_MODE_INFORMATION_REQUEST);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dhcp6_request_prefix_delegation(Link *link) {
|
||||
@ -1505,7 +1512,7 @@ static int dhcp6_set_hostname(sd_dhcp6_client *client, Link *link) {
|
||||
else {
|
||||
r = gethostname_strict(&hostname);
|
||||
if (r < 0 && r != -ENXIO) /* ENXIO: no hostname set or hostname is "localhost" */
|
||||
return r;
|
||||
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to get hostname: %m");
|
||||
|
||||
hn = hostname;
|
||||
}
|
||||
@ -1513,9 +1520,9 @@ static int dhcp6_set_hostname(sd_dhcp6_client *client, Link *link) {
|
||||
r = sd_dhcp6_client_set_fqdn(client, hn);
|
||||
if (r == -EINVAL && hostname)
|
||||
/* Ignore error when the machine's hostname is not suitable to send in DHCP packet. */
|
||||
log_link_warning_errno(link, r, "DHCP6 CLIENT: Failed to set hostname from kernel hostname, ignoring: %m");
|
||||
log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set hostname from kernel hostname, ignoring: %m");
|
||||
else if (r < 0)
|
||||
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set hostname: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set hostname: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1571,7 +1578,7 @@ static int dhcp6_set_identifier(Link *link, sd_dhcp6_client *client) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp6_configure(Link *link) {
|
||||
static int dhcp6_configure(Link *link) {
|
||||
_cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL;
|
||||
sd_dhcp6_option *vendor_option;
|
||||
sd_dhcp6_option *send_option;
|
||||
@ -1581,36 +1588,29 @@ int dhcp6_configure(Link *link) {
|
||||
assert(link);
|
||||
assert(link->network);
|
||||
|
||||
if (!link_dhcp6_enabled(link) && !link_ipv6_accept_ra_enabled(link))
|
||||
return 0;
|
||||
|
||||
if (link->dhcp6_client)
|
||||
return -EBUSY;
|
||||
|
||||
r = dhcp_configure_duid(link, link_get_dhcp6_duid(link));
|
||||
if (r <= 0)
|
||||
return r;
|
||||
return log_link_debug_errno(link, SYNTHETIC_ERRNO(EBUSY), "DHCPv6 client is already configured.");
|
||||
|
||||
r = sd_dhcp6_client_new(&client);
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
return log_oom_debug();
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to create DHCP6 client: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to create DHCPv6 client: %m");
|
||||
|
||||
r = sd_dhcp6_client_attach_event(client, link->manager->event, 0);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to attach event: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to attach event: %m");
|
||||
|
||||
r = dhcp6_set_identifier(link, client);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set identifier: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set identifier: %m");
|
||||
|
||||
ORDERED_HASHMAP_FOREACH(send_option, link->network->dhcp6_client_send_options) {
|
||||
r = sd_dhcp6_client_add_option(client, send_option);
|
||||
if (r == -EEXIST)
|
||||
continue;
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set option: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set option: %m");
|
||||
}
|
||||
|
||||
r = dhcp6_set_hostname(client, link);
|
||||
@ -1619,18 +1619,18 @@ int dhcp6_configure(Link *link) {
|
||||
|
||||
r = sd_dhcp6_client_set_ifindex(client, link->ifindex);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set ifindex: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set ifindex: %m");
|
||||
|
||||
if (link->network->dhcp6_rapid_commit) {
|
||||
r = sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_RAPID_COMMIT);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set request flag for rapid commit: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set request flag for rapid commit: %m");
|
||||
}
|
||||
|
||||
if (link->network->dhcp6_mudurl) {
|
||||
r = sd_dhcp6_client_set_request_mud_url(client, link->network->dhcp6_mudurl);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set MUD URL: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set MUD URL: %m");
|
||||
}
|
||||
|
||||
SET_FOREACH(request_options, link->network->dhcp6_request_options) {
|
||||
@ -1638,23 +1638,23 @@ int dhcp6_configure(Link *link) {
|
||||
|
||||
r = sd_dhcp6_client_set_request_option(client, option);
|
||||
if (r == -EEXIST) {
|
||||
log_link_debug(link, "DHCP6 CLIENT: Failed to set request flag for '%u' already exists, ignoring.", option);
|
||||
log_link_debug(link, "DHCPv6 CLIENT: Failed to set request flag for '%u' already exists, ignoring.", option);
|
||||
continue;
|
||||
}
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set request flag for '%u': %m", option);
|
||||
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set request flag for '%u': %m", option);
|
||||
}
|
||||
|
||||
if (link->network->dhcp6_user_class) {
|
||||
r = sd_dhcp6_client_set_request_user_class(client, link->network->dhcp6_user_class);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set user class: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set user class: %m");
|
||||
}
|
||||
|
||||
if (link->network->dhcp6_vendor_class) {
|
||||
r = sd_dhcp6_client_set_request_vendor_class(client, link->network->dhcp6_vendor_class);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set vendor class: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set vendor class: %m");
|
||||
}
|
||||
|
||||
ORDERED_HASHMAP_FOREACH(vendor_option, link->network->dhcp6_client_send_vendor_options) {
|
||||
@ -1662,23 +1662,23 @@ int dhcp6_configure(Link *link) {
|
||||
if (r == -EEXIST)
|
||||
continue;
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set vendor option: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set vendor option: %m");
|
||||
}
|
||||
|
||||
r = sd_dhcp6_client_set_callback(client, dhcp6_handler, link);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set callback: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set callback: %m");
|
||||
|
||||
if (dhcp6_enable_prefix_delegation(link)) {
|
||||
r = sd_dhcp6_client_set_prefix_delegation(client, true);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set prefix delegation: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set prefix delegation: %m");
|
||||
}
|
||||
|
||||
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);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set prefix hint: %m");
|
||||
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set prefix hint: %m");
|
||||
}
|
||||
|
||||
link->dhcp6_client = TAKE_PTR(client);
|
||||
@ -1716,6 +1716,60 @@ int dhcp6_update_mac(Link *link) {
|
||||
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) {
|
||||
_cleanup_free_ char *duid = NULL;
|
||||
uint32_t iaid;
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "sd-dhcp6-client.h"
|
||||
|
||||
#include "conf-parser.h"
|
||||
#include "in-addr-util.h"
|
||||
#include "macro.h"
|
||||
|
||||
typedef enum DHCP6ClientStartMode {
|
||||
@ -15,7 +14,7 @@ typedef enum DHCP6ClientStartMode {
|
||||
} DHCP6ClientStartMode;
|
||||
|
||||
typedef struct Link Link;
|
||||
typedef struct Manager Manager;
|
||||
typedef struct Request Request;
|
||||
|
||||
typedef struct DHCP6DelegatedPrefix {
|
||||
struct in6_addr prefix; /* Prefix assigned to the link */
|
||||
@ -29,12 +28,14 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(DHCP6DelegatedPrefix*, dhcp6_pd_free);
|
||||
bool link_dhcp6_with_address_enabled(Link *link);
|
||||
bool link_dhcp6_pd_is_enabled(Link *link);
|
||||
int dhcp6_pd_remove(Link *link);
|
||||
int dhcp6_configure(Link *link);
|
||||
int dhcp6_update_mac(Link *link);
|
||||
int dhcp6_start(Link *link);
|
||||
int dhcp6_request_information(Link *link, int ir);
|
||||
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);
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_pd_hint);
|
||||
|
||||
@ -507,7 +507,7 @@ void link_check_ready(Link *link) {
|
||||
!link->dhcp_address && set_isempty(link->dhcp6_addresses) && !has_ndisc_address &&
|
||||
!link->ipv4ll_address_configured)
|
||||
/* When DHCP[46] or IPv4LL is enabled, at least one address is acquired by them. */
|
||||
return (void) log_link_debug(link, "%s(): DHCP4, DHCP6 or IPv4LL is enabled but no dynamic address is assigned yet.", __func__);
|
||||
return (void) log_link_debug(link, "%s(): DHCPv4, DHCPv6 or IPv4LL is enabled but no dynamic address is assigned yet.", __func__);
|
||||
|
||||
/* 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) ||
|
||||
@ -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. */
|
||||
return (void) log_link_debug(link, "%s(): dynamic addresses or routes are not configured.", __func__);
|
||||
|
||||
log_link_debug(link, "%s(): dhcp4:%s ipv4ll:%s dhcp6_addresses:%s dhcp6_routes:%s "
|
||||
"dhcp6_pd_addresses:%s dhcp6_pd_routes:%s ndisc_addresses:%s ndisc_routes:%s",
|
||||
log_link_debug(link, "%s(): DHCPv4:%s IPv4LL:%s DHCPv6_addresses:%s DHCPv6_routes:%s "
|
||||
"DHCPv6PD_addresses:%s DHCPv6PD_routes:%s NDisc_addresses:%s NDisc_routes:%s",
|
||||
__func__,
|
||||
yes_no(link->dhcp4_configured),
|
||||
yes_no(link->ipv4ll_address_configured),
|
||||
@ -650,12 +650,14 @@ static int link_acquire_dynamic_ipv4_conf(Link *link) {
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Failed to start DHCPv4 client: %m");
|
||||
|
||||
} else if (link->ipv4ll) {
|
||||
log_link_debug(link, "Acquiring IPv4 link-local address");
|
||||
log_link_debug(link, "Acquiring DHCPv4 lease.");
|
||||
|
||||
} else if (link->ipv4ll) {
|
||||
r = sd_ipv4ll_start(link->ipv4ll);
|
||||
if (r < 0)
|
||||
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) {
|
||||
@ -690,6 +692,12 @@ static int link_acquire_dynamic_conf(Link *link) {
|
||||
if (r < 0)
|
||||
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;
|
||||
}
|
||||
|
||||
@ -975,8 +983,6 @@ static Link *link_drop(Link *link) {
|
||||
|
||||
link_drop_from_master(link);
|
||||
|
||||
link_unref(set_remove(link->manager->links_requesting_uuid, link));
|
||||
|
||||
(void) unlink(link->state_file);
|
||||
link_clean(link);
|
||||
|
||||
@ -999,6 +1005,16 @@ static int link_drop_foreign_config(Link *link) {
|
||||
assert(link);
|
||||
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);
|
||||
|
||||
k = link_drop_foreign_nexthops(link);
|
||||
@ -1127,11 +1143,11 @@ static int link_configure(Link *link) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dhcp4_configure(link);
|
||||
r = link_request_dhcp4_client(link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dhcp6_configure(link);
|
||||
r = link_request_dhcp6_client(link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -1151,14 +1167,9 @@ static int link_configure(Link *link) {
|
||||
if (r < 0)
|
||||
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);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = link_request_static_configs(link);
|
||||
if (r < 0)
|
||||
@ -1224,23 +1235,22 @@ static int link_get_network(Link *link, Network **ret) {
|
||||
}
|
||||
|
||||
static int link_reconfigure_impl(Link *link, bool force) {
|
||||
Network *network;
|
||||
Network *network = NULL;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
|
||||
r = link_get_network(link, &network);
|
||||
if (r == -ENOENT) {
|
||||
link_set_state(link, LINK_STATE_UNMANAGED);
|
||||
return 0;
|
||||
}
|
||||
if (r < 0)
|
||||
if (r < 0 && r != -ENOENT)
|
||||
return r;
|
||||
|
||||
if (link->network == network && !force)
|
||||
return 0;
|
||||
|
||||
log_link_info(link, "Re-configuring with %s", network->filename);
|
||||
if (network)
|
||||
log_link_info(link, "Reconfiguring with %s.", network->filename);
|
||||
else
|
||||
log_link_info(link, "Unmanaging interface.");
|
||||
|
||||
/* Dropping old .network file */
|
||||
r = link_stop_engines(link, false);
|
||||
@ -1253,17 +1263,14 @@ static int link_reconfigure_impl(Link *link, bool force) {
|
||||
if (r < 0)
|
||||
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_engines(link);
|
||||
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 */
|
||||
link->network = network_ref(network);
|
||||
@ -1284,44 +1291,107 @@ static int link_reconfigure_impl(Link *link, bool force) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int link_reconfigure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, bool force) {
|
||||
static int link_reconfigure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, bool force, bool update_wifi) {
|
||||
bool link_was_lower_up;
|
||||
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");
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
r = link_reconfigure_impl(link, force);
|
||||
if (r < 0)
|
||||
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);
|
||||
if (r < 0) {
|
||||
link_enter_failed(link);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static int link_reconfigure_after_sleep_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||
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_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||
return link_reconfigure_handler_internal(rtnl, m, link, false);
|
||||
}
|
||||
|
||||
static int link_force_reconfigure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||
return link_reconfigure_handler_internal(rtnl, m, link, true);
|
||||
}
|
||||
|
||||
int link_reconfigure(Link *link, bool force) {
|
||||
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
|
||||
* the function from being called multiple times simultaneously, refuse to reconfigure the
|
||||
* interface in these cases. */
|
||||
if (IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_INITIALIZED, LINK_STATE_LINGER))
|
||||
return 0; /* 0 means no-op. */
|
||||
|
||||
r = link_call_getlink(link, force ? link_force_reconfigure_handler : link_reconfigure_handler);
|
||||
r = link_call_getlink(link, callback);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
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) {
|
||||
Network *network;
|
||||
int r;
|
||||
@ -1560,34 +1630,7 @@ static int link_carrier_lost(Link *link) {
|
||||
if (r < 0)
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
return link_drop_foreign_config(link);
|
||||
}
|
||||
|
||||
static int link_admin_state_up(Link *link) {
|
||||
@ -1943,10 +1986,6 @@ static int link_update_flags(Link *link, sd_netlink_message *message) {
|
||||
return r;
|
||||
}
|
||||
|
||||
r = link_update_lldp(link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!had_carrier && link_has_carrier(link)) {
|
||||
log_link_info(link, "Gained carrier");
|
||||
|
||||
|
||||
@ -232,7 +232,6 @@ void link_check_ready(Link *link);
|
||||
|
||||
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_ipv6_enabled(Link *link);
|
||||
@ -247,6 +246,7 @@ const char* link_state_to_string(LinkState s) _const_;
|
||||
LinkState link_state_from_string(const char *s) _pure_;
|
||||
|
||||
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_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *message, Manager *m);
|
||||
|
||||
@ -103,38 +103,9 @@ int link_lldp_rx_configure(Link *link) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = link_update_lldp(link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
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) {
|
||||
_cleanup_(unlink_and_freep) char *temp_path = NULL;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
|
||||
@ -14,7 +14,6 @@ typedef enum LLDPMode {
|
||||
} LLDPMode;
|
||||
|
||||
int link_lldp_rx_configure(Link *link);
|
||||
int link_update_lldp(Link *link);
|
||||
int link_lldp_save(Link *link);
|
||||
|
||||
const char* lldp_mode_to_string(LLDPMode m) _const_;
|
||||
|
||||
@ -59,9 +59,9 @@ static int manager_reset_all(Manager *m) {
|
||||
assert(m);
|
||||
|
||||
HASHMAP_FOREACH(link, m->links_by_index) {
|
||||
r = link_carrier_reset(link);
|
||||
r = link_reconfigure_after_sleep(link);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(link, r, "Could not reset carrier: %m");
|
||||
log_link_warning_errno(link, r, "Failed to reconfigure interface: %m");
|
||||
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);
|
||||
if (m->dynamic_timezone)
|
||||
(void) manager_set_timezone(m, m->dynamic_timezone);
|
||||
if (!set_isempty(m->links_requesting_uuid))
|
||||
if (m->product_uuid_requested)
|
||||
(void) manager_request_product_uuid(m);
|
||||
|
||||
return 0;
|
||||
@ -460,7 +460,6 @@ Manager* manager_free(Manager *m) {
|
||||
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->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_hw_addr = hashmap_free(m->links_by_hw_addr);
|
||||
m->links_by_index = hashmap_free_with_destructor(m->links_by_index, link_unref);
|
||||
|
||||
@ -60,7 +60,6 @@ struct Manager {
|
||||
DUID duid_product_uuid;
|
||||
bool has_product_uuid;
|
||||
bool product_uuid_requested;
|
||||
Set *links_requesting_uuid;
|
||||
|
||||
char* dynamic_hostname;
|
||||
char* dynamic_timezone;
|
||||
|
||||
@ -38,6 +38,21 @@
|
||||
|
||||
#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) {
|
||||
assert(link);
|
||||
|
||||
@ -619,7 +634,7 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool stableprivate_address_is_valid(const struct in6_addr *addr) {
|
||||
static bool stable_private_address_is_valid(const struct in6_addr *addr) {
|
||||
assert(addr);
|
||||
|
||||
/* According to rfc4291, generated address should not be in the following ranges. */
|
||||
@ -636,7 +651,7 @@ static bool stableprivate_address_is_valid(const struct in6_addr *addr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static int make_stableprivate_address(Link *link, const struct in6_addr *prefix, uint8_t prefix_len, uint8_t dad_counter, struct in6_addr **ret) {
|
||||
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) {
|
||||
_cleanup_free_ struct in6_addr *addr = NULL;
|
||||
sd_id128_t secret_key;
|
||||
struct siphash state;
|
||||
@ -649,7 +664,7 @@ static int make_stableprivate_address(Link *link, const struct in6_addr *prefix,
|
||||
|
||||
r = sd_id128_get_machine_app_specific(NDISC_APP_ID, &secret_key);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to generate key: %m");
|
||||
return log_link_warning_errno(link, r, "Failed to generate key for IPv6 stable private address: %m");
|
||||
|
||||
siphash24_init(&state, secret_key.bytes);
|
||||
|
||||
@ -672,7 +687,7 @@ static int make_stableprivate_address(Link *link, const struct in6_addr *prefix,
|
||||
memcpy(addr->s6_addr, prefix->s6_addr, l);
|
||||
memcpy(addr->s6_addr + l, &rid, 16 - l);
|
||||
|
||||
if (!stableprivate_address_is_valid(addr)) {
|
||||
if (!stable_private_address_is_valid(addr)) {
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
@ -704,7 +719,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
|
||||
* 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++) {
|
||||
r = make_stableprivate_address(link, address, prefixlen, j->dad_counter, &new_address);
|
||||
r = make_stable_private_address(link, address, prefixlen, j->dad_counter, &new_address);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0)
|
||||
@ -1030,7 +1045,7 @@ static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
|
||||
if (rdnss) {
|
||||
rdnss->marked = false;
|
||||
rdnss->router = router;
|
||||
rdnss->valid_until = time_now + lifetime * USEC_PER_SEC;
|
||||
rdnss->valid_until = usec_add(time_now, lifetime * USEC_PER_SEC);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1041,7 +1056,7 @@ static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
|
||||
*x = (NDiscRDNSS) {
|
||||
.address = a[j],
|
||||
.router = router,
|
||||
.valid_until = time_now + lifetime * USEC_PER_SEC,
|
||||
.valid_until = usec_add(time_now, lifetime * USEC_PER_SEC),
|
||||
};
|
||||
|
||||
r = set_ensure_consume(&link->ndisc_rdnss, &ndisc_rdnss_hash_ops, TAKE_PTR(x));
|
||||
@ -1128,12 +1143,12 @@ static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
|
||||
if (dnssl) {
|
||||
dnssl->marked = false;
|
||||
dnssl->router = router;
|
||||
dnssl->valid_until = time_now + lifetime * USEC_PER_SEC;
|
||||
dnssl->valid_until = usec_add(time_now, lifetime * USEC_PER_SEC);
|
||||
continue;
|
||||
}
|
||||
|
||||
s->router = router;
|
||||
s->valid_until = time_now + lifetime * USEC_PER_SEC;
|
||||
s->valid_until = usec_add(time_now, lifetime * USEC_PER_SEC);
|
||||
|
||||
r = set_ensure_consume(&link->ndisc_dnssl, &ndisc_dnssl_hash_ops, TAKE_PTR(s));
|
||||
if (r < 0)
|
||||
@ -1396,6 +1411,9 @@ int ndisc_start(Link *link) {
|
||||
if (!link->ndisc || !link->dhcp6_client)
|
||||
return 0;
|
||||
|
||||
if (!link_has_carrier(link))
|
||||
return 0;
|
||||
|
||||
log_link_debug(link, "Discovering IPv6 routers");
|
||||
|
||||
return sd_ndisc_start(link->ndisc);
|
||||
@ -1430,7 +1448,7 @@ void ndisc_flush(Link *link) {
|
||||
link->ndisc_dnssl = set_free(link->ndisc_dnssl);
|
||||
}
|
||||
|
||||
int ipv6token_new(IPv6Token **ret) {
|
||||
static int ipv6token_new(IPv6Token **ret) {
|
||||
IPv6Token *p;
|
||||
|
||||
p = new(IPv6Token, 1);
|
||||
|
||||
@ -7,16 +7,6 @@
|
||||
#include "networkd-route.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 {
|
||||
IPV6_ACCEPT_RA_START_DHCP6_CLIENT_NO,
|
||||
IPV6_ACCEPT_RA_START_DHCP6_CLIENT_ALWAYS,
|
||||
@ -55,15 +45,6 @@ typedef struct NDiscDNSSL {
|
||||
/* The domain name follows immediately. */
|
||||
} 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) {
|
||||
return ((char*) n) + ALIGN(sizeof(NDiscDNSSL));
|
||||
}
|
||||
|
||||
@ -5,6 +5,8 @@
|
||||
#include "networkd-bridge-fdb.h"
|
||||
#include "networkd-bridge-mdb.h"
|
||||
#include "networkd-dhcp-server.h"
|
||||
#include "networkd-dhcp4.h"
|
||||
#include "networkd-dhcp6.h"
|
||||
#include "networkd-ipv6-proxy-ndp.h"
|
||||
#include "networkd-manager.h"
|
||||
#include "networkd-neighbor.h"
|
||||
@ -33,6 +35,8 @@ static void request_free_object(RequestType type, void *object) {
|
||||
case REQUEST_TYPE_CREATE_STACKED_NETDEV:
|
||||
break;
|
||||
case REQUEST_TYPE_DHCP_SERVER:
|
||||
case REQUEST_TYPE_DHCP4_CLIENT:
|
||||
case REQUEST_TYPE_DHCP6_CLIENT:
|
||||
break;
|
||||
case REQUEST_TYPE_IPV6_PROXY_NDP:
|
||||
free(object);
|
||||
@ -112,7 +116,9 @@ static void request_hash_func(const Request *req, struct siphash *state) {
|
||||
trivial_hash_func(req->object, state);
|
||||
break;
|
||||
case REQUEST_TYPE_DHCP_SERVER:
|
||||
/* This type does not have an object. */
|
||||
case REQUEST_TYPE_DHCP4_CLIENT:
|
||||
case REQUEST_TYPE_DHCP6_CLIENT:
|
||||
/* These types do not have an object. */
|
||||
break;
|
||||
case REQUEST_TYPE_IPV6_PROXY_NDP:
|
||||
in6_addr_hash_func(req->ipv6_proxy_ndp, state);
|
||||
@ -170,6 +176,8 @@ static int request_compare_func(const struct Request *a, const struct Request *b
|
||||
case REQUEST_TYPE_CREATE_STACKED_NETDEV:
|
||||
return trivial_compare_func(a->object, b->object);
|
||||
case REQUEST_TYPE_DHCP_SERVER:
|
||||
case REQUEST_TYPE_DHCP4_CLIENT:
|
||||
case REQUEST_TYPE_DHCP6_CLIENT:
|
||||
return 0;
|
||||
case REQUEST_TYPE_IPV6_PROXY_NDP:
|
||||
return in6_addr_compare_func(a->ipv6_proxy_ndp, b->ipv6_proxy_ndp);
|
||||
@ -218,12 +226,16 @@ int link_queue_request(
|
||||
assert(IN_SET(type,
|
||||
REQUEST_TYPE_ACTIVATE_LINK,
|
||||
REQUEST_TYPE_DHCP_SERVER,
|
||||
REQUEST_TYPE_DHCP4_CLIENT,
|
||||
REQUEST_TYPE_DHCP6_CLIENT,
|
||||
REQUEST_TYPE_RADV,
|
||||
REQUEST_TYPE_SET_LINK,
|
||||
REQUEST_TYPE_UP_DOWN) ||
|
||||
object);
|
||||
assert(IN_SET(type,
|
||||
REQUEST_TYPE_DHCP_SERVER,
|
||||
REQUEST_TYPE_DHCP4_CLIENT,
|
||||
REQUEST_TYPE_DHCP6_CLIENT,
|
||||
REQUEST_TYPE_RADV) ||
|
||||
netlink_handler);
|
||||
|
||||
@ -300,6 +312,12 @@ int manager_process_requests(sd_event_source *s, void *userdata) {
|
||||
case REQUEST_TYPE_DHCP_SERVER:
|
||||
r = request_process_dhcp_server(req);
|
||||
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:
|
||||
r = request_process_ipv6_proxy_ndp_address(req);
|
||||
break;
|
||||
|
||||
@ -28,6 +28,8 @@ typedef enum RequestType {
|
||||
REQUEST_TYPE_BRIDGE_MDB,
|
||||
REQUEST_TYPE_CREATE_STACKED_NETDEV,
|
||||
REQUEST_TYPE_DHCP_SERVER,
|
||||
REQUEST_TYPE_DHCP4_CLIENT,
|
||||
REQUEST_TYPE_DHCP6_CLIENT,
|
||||
REQUEST_TYPE_IPV6_PROXY_NDP,
|
||||
REQUEST_TYPE_NEIGHBOR,
|
||||
REQUEST_TYPE_NEXTHOP,
|
||||
|
||||
@ -869,9 +869,9 @@ int link_request_radv(Link *link) {
|
||||
|
||||
r = link_queue_request(link, REQUEST_TYPE_RADV, NULL, false, NULL, NULL, NULL);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Failed to request IPv6 Router Advertisement engine: %m");
|
||||
return log_link_warning_errno(link, r, "Failed to request configuring of the IPv6 Router Advertisement engine: %m");
|
||||
|
||||
log_link_debug(link, "IPv6 Router Advertisement engine is requested.");
|
||||
log_link_debug(link, "Requested configuring of the IPv6 Router Advertisement engine.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -585,7 +585,7 @@ static int dns_stub_send_reply(
|
||||
DNS_PACKET_RD(q->request_packet),
|
||||
!!q->request_packet->opt,
|
||||
edns0_do,
|
||||
DNS_PACKET_AD(q->request_packet) && dns_query_fully_authenticated(q),
|
||||
(DNS_PACKET_AD(q->request_packet) || DNS_PACKET_DO(q->request_packet)) && dns_query_fully_authenticated(q),
|
||||
DNS_PACKET_CD(q->request_packet),
|
||||
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);
|
||||
@ -627,7 +627,7 @@ static int dns_stub_send_failure(
|
||||
DNS_PACKET_RD(p),
|
||||
!!p->opt,
|
||||
DNS_PACKET_DO(p),
|
||||
DNS_PACKET_AD(p) && authenticated,
|
||||
(DNS_PACKET_AD(p) || DNS_PACKET_DO(p)) && authenticated,
|
||||
DNS_PACKET_CD(p),
|
||||
l ? ADVERTISE_EXTRA_DATAGRAM_SIZE_MAX : ADVERTISE_DATAGRAM_SIZE_MAX,
|
||||
dns_packet_has_nsid_request(p) > 0 && !l);
|
||||
|
||||
@ -81,6 +81,9 @@ _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_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
|
||||
* 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. */
|
||||
|
||||
@ -23,14 +23,14 @@
|
||||
/* wire protocol magic must match */
|
||||
#define UDEV_CTRL_MAGIC 0xdead1dea
|
||||
|
||||
struct udev_ctrl_msg_wire {
|
||||
typedef struct UdevCtrlMessageWire {
|
||||
char version[16];
|
||||
unsigned magic;
|
||||
enum udev_ctrl_msg_type type;
|
||||
union udev_ctrl_msg_value value;
|
||||
};
|
||||
UdevCtrlMessageType type;
|
||||
UdevCtrlMessageValue value;
|
||||
} UdevCtrlMessageWire;
|
||||
|
||||
struct udev_ctrl {
|
||||
struct UdevCtrl {
|
||||
unsigned n_ref;
|
||||
int sock;
|
||||
int sock_connect;
|
||||
@ -47,9 +47,9 @@ struct udev_ctrl {
|
||||
void *userdata;
|
||||
};
|
||||
|
||||
int udev_ctrl_new_from_fd(struct udev_ctrl **ret, int fd) {
|
||||
int udev_ctrl_new_from_fd(UdevCtrl **ret, int fd) {
|
||||
_cleanup_close_ int sock = -1;
|
||||
struct udev_ctrl *uctrl;
|
||||
UdevCtrl *uctrl;
|
||||
|
||||
assert(ret);
|
||||
|
||||
@ -59,11 +59,11 @@ int udev_ctrl_new_from_fd(struct udev_ctrl **ret, int fd) {
|
||||
return log_error_errno(errno, "Failed to create socket: %m");
|
||||
}
|
||||
|
||||
uctrl = new(struct udev_ctrl, 1);
|
||||
uctrl = new(UdevCtrl, 1);
|
||||
if (!uctrl)
|
||||
return -ENOMEM;
|
||||
|
||||
*uctrl = (struct udev_ctrl) {
|
||||
*uctrl = (UdevCtrl) {
|
||||
.n_ref = 1,
|
||||
.sock = fd >= 0 ? fd : TAKE_FD(sock),
|
||||
.sock_connect = -1,
|
||||
@ -81,7 +81,7 @@ int udev_ctrl_new_from_fd(struct udev_ctrl **ret, int fd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl) {
|
||||
int udev_ctrl_enable_receiving(UdevCtrl *uctrl) {
|
||||
int r;
|
||||
|
||||
assert(uctrl);
|
||||
@ -107,7 +107,7 @@ int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void udev_ctrl_disconnect(struct udev_ctrl *uctrl) {
|
||||
static void udev_ctrl_disconnect(UdevCtrl *uctrl) {
|
||||
if (!uctrl)
|
||||
return;
|
||||
|
||||
@ -115,7 +115,7 @@ static void udev_ctrl_disconnect(struct udev_ctrl *uctrl) {
|
||||
uctrl->sock_connect = safe_close(uctrl->sock_connect);
|
||||
}
|
||||
|
||||
static struct udev_ctrl *udev_ctrl_free(struct udev_ctrl *uctrl) {
|
||||
static UdevCtrl *udev_ctrl_free(UdevCtrl *uctrl) {
|
||||
assert(uctrl);
|
||||
|
||||
udev_ctrl_disconnect(uctrl);
|
||||
@ -127,9 +127,9 @@ static struct udev_ctrl *udev_ctrl_free(struct udev_ctrl *uctrl) {
|
||||
return mfree(uctrl);
|
||||
}
|
||||
|
||||
DEFINE_TRIVIAL_REF_UNREF_FUNC(struct udev_ctrl, udev_ctrl, udev_ctrl_free);
|
||||
DEFINE_TRIVIAL_REF_UNREF_FUNC(UdevCtrl, udev_ctrl, udev_ctrl_free);
|
||||
|
||||
int udev_ctrl_cleanup(struct udev_ctrl *uctrl) {
|
||||
int udev_ctrl_cleanup(UdevCtrl *uctrl) {
|
||||
if (!uctrl)
|
||||
return 0;
|
||||
if (uctrl->cleanup_socket)
|
||||
@ -137,7 +137,7 @@ int udev_ctrl_cleanup(struct udev_ctrl *uctrl) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int udev_ctrl_attach_event(struct udev_ctrl *uctrl, sd_event *event) {
|
||||
int udev_ctrl_attach_event(UdevCtrl *uctrl, sd_event *event) {
|
||||
int r;
|
||||
|
||||
assert_return(uctrl, -EINVAL);
|
||||
@ -154,25 +154,25 @@ int udev_ctrl_attach_event(struct udev_ctrl *uctrl, sd_event *event) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
sd_event_source *udev_ctrl_get_event_source(struct udev_ctrl *uctrl) {
|
||||
sd_event_source *udev_ctrl_get_event_source(UdevCtrl *uctrl) {
|
||||
assert(uctrl);
|
||||
|
||||
return uctrl->event_source;
|
||||
}
|
||||
|
||||
static void udev_ctrl_disconnect_and_listen_again(struct udev_ctrl *uctrl) {
|
||||
static void udev_ctrl_disconnect_and_listen_again(UdevCtrl *uctrl) {
|
||||
udev_ctrl_disconnect(uctrl);
|
||||
udev_ctrl_unref(uctrl);
|
||||
(void) sd_event_source_set_enabled(uctrl->event_source, SD_EVENT_ON);
|
||||
/* We don't return NULL here because uctrl is not freed */
|
||||
}
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct udev_ctrl*, udev_ctrl_disconnect_and_listen_again, NULL);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(UdevCtrl*, 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) {
|
||||
_cleanup_(udev_ctrl_disconnect_and_listen_againp) struct udev_ctrl *uctrl = NULL;
|
||||
struct udev_ctrl_msg_wire msg_wire;
|
||||
struct iovec iov = IOVEC_MAKE(&msg_wire, sizeof(struct udev_ctrl_msg_wire));
|
||||
_cleanup_(udev_ctrl_disconnect_and_listen_againp) UdevCtrl *uctrl = NULL;
|
||||
UdevCtrlMessageWire msg_wire;
|
||||
struct iovec iov = IOVEC_MAKE(&msg_wire, sizeof(UdevCtrlMessageWire));
|
||||
CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred))) control;
|
||||
struct msghdr smsg = {
|
||||
.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) {
|
||||
struct udev_ctrl *uctrl = userdata;
|
||||
UdevCtrl *uctrl = userdata;
|
||||
_cleanup_close_ int sock = -1;
|
||||
struct ucred ucred;
|
||||
int r;
|
||||
@ -282,7 +282,7 @@ static int udev_ctrl_event_handler(sd_event_source *s, int fd, uint32_t revents,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int udev_ctrl_start(struct udev_ctrl *uctrl, udev_ctrl_handler_t callback, void *userdata) {
|
||||
int udev_ctrl_start(UdevCtrl *uctrl, udev_ctrl_handler_t callback, void *userdata) {
|
||||
int r;
|
||||
|
||||
assert(uctrl);
|
||||
@ -309,8 +309,8 @@ int udev_ctrl_start(struct udev_ctrl *uctrl, udev_ctrl_handler_t callback, void
|
||||
return 0;
|
||||
}
|
||||
|
||||
int udev_ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int intval, const char *buf) {
|
||||
struct udev_ctrl_msg_wire ctrl_msg_wire = {
|
||||
int udev_ctrl_send(UdevCtrl *uctrl, UdevCtrlMessageType type, int intval, const char *buf) {
|
||||
UdevCtrlMessageWire ctrl_msg_wire = {
|
||||
.version = "udev-" STRINGIFY(PROJECT_VERSION),
|
||||
.magic = UDEV_CTRL_MAGIC,
|
||||
.type = type,
|
||||
@ -339,7 +339,7 @@ int udev_ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int in
|
||||
return 0;
|
||||
}
|
||||
|
||||
int udev_ctrl_wait(struct udev_ctrl *uctrl, usec_t timeout) {
|
||||
int udev_ctrl_wait(UdevCtrl *uctrl, usec_t timeout) {
|
||||
_cleanup_(sd_event_source_unrefp) sd_event_source *source_io = NULL, *source_timeout = NULL;
|
||||
int r;
|
||||
|
||||
|
||||
@ -6,9 +6,9 @@
|
||||
#include "macro.h"
|
||||
#include "time-util.h"
|
||||
|
||||
struct udev_ctrl;
|
||||
typedef struct UdevCtrl UdevCtrl;
|
||||
|
||||
enum udev_ctrl_msg_type {
|
||||
typedef enum UdevCtrlMessageType {
|
||||
_UDEV_CTRL_END_MESSAGES,
|
||||
UDEV_CTRL_SET_LOG_LEVEL,
|
||||
UDEV_CTRL_STOP_EXEC_QUEUE,
|
||||
@ -18,62 +18,62 @@ enum udev_ctrl_msg_type {
|
||||
UDEV_CTRL_SET_CHILDREN_MAX,
|
||||
UDEV_CTRL_PING,
|
||||
UDEV_CTRL_EXIT,
|
||||
};
|
||||
} UdevCtrlMessageType;
|
||||
|
||||
union udev_ctrl_msg_value {
|
||||
typedef union UdevCtrlMessageValue {
|
||||
int intval;
|
||||
char buf[256];
|
||||
};
|
||||
} UdevCtrlMessageValue;
|
||||
|
||||
typedef int (*udev_ctrl_handler_t)(struct udev_ctrl *udev_ctrl, enum udev_ctrl_msg_type type,
|
||||
const union udev_ctrl_msg_value *value, void *userdata);
|
||||
typedef int (*udev_ctrl_handler_t)(UdevCtrl *udev_ctrl, UdevCtrlMessageType type,
|
||||
const UdevCtrlMessageValue *value, void *userdata);
|
||||
|
||||
int udev_ctrl_new_from_fd(struct udev_ctrl **ret, int fd);
|
||||
static inline int udev_ctrl_new(struct udev_ctrl **ret) {
|
||||
int udev_ctrl_new_from_fd(UdevCtrl **ret, int fd);
|
||||
static inline int udev_ctrl_new(UdevCtrl **ret) {
|
||||
return udev_ctrl_new_from_fd(ret, -1);
|
||||
}
|
||||
|
||||
int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl);
|
||||
struct udev_ctrl *udev_ctrl_ref(struct udev_ctrl *uctrl);
|
||||
struct udev_ctrl *udev_ctrl_unref(struct udev_ctrl *uctrl);
|
||||
int udev_ctrl_cleanup(struct udev_ctrl *uctrl);
|
||||
int udev_ctrl_attach_event(struct udev_ctrl *uctrl, sd_event *event);
|
||||
int udev_ctrl_start(struct udev_ctrl *uctrl, udev_ctrl_handler_t callback, void *userdata);
|
||||
sd_event_source *udev_ctrl_get_event_source(struct udev_ctrl *uctrl);
|
||||
int udev_ctrl_enable_receiving(UdevCtrl *uctrl);
|
||||
UdevCtrl *udev_ctrl_ref(UdevCtrl *uctrl);
|
||||
UdevCtrl *udev_ctrl_unref(UdevCtrl *uctrl);
|
||||
int udev_ctrl_cleanup(UdevCtrl *uctrl);
|
||||
int udev_ctrl_attach_event(UdevCtrl *uctrl, sd_event *event);
|
||||
int udev_ctrl_start(UdevCtrl *uctrl, udev_ctrl_handler_t callback, void *userdata);
|
||||
sd_event_source *udev_ctrl_get_event_source(UdevCtrl *uctrl);
|
||||
|
||||
int udev_ctrl_wait(struct udev_ctrl *uctrl, usec_t timeout);
|
||||
int udev_ctrl_wait(UdevCtrl *uctrl, usec_t timeout);
|
||||
|
||||
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(struct udev_ctrl *uctrl, int priority) {
|
||||
int udev_ctrl_send(UdevCtrl *uctrl, UdevCtrlMessageType type, int intval, const char *buf);
|
||||
static inline int udev_ctrl_send_set_log_level(UdevCtrl *uctrl, int priority) {
|
||||
return udev_ctrl_send(uctrl, UDEV_CTRL_SET_LOG_LEVEL, priority, NULL);
|
||||
}
|
||||
|
||||
static inline int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl) {
|
||||
static inline int udev_ctrl_send_stop_exec_queue(UdevCtrl *uctrl) {
|
||||
return udev_ctrl_send(uctrl, UDEV_CTRL_STOP_EXEC_QUEUE, 0, NULL);
|
||||
}
|
||||
|
||||
static inline int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl) {
|
||||
static inline int udev_ctrl_send_start_exec_queue(UdevCtrl *uctrl) {
|
||||
return udev_ctrl_send(uctrl, UDEV_CTRL_START_EXEC_QUEUE, 0, NULL);
|
||||
}
|
||||
|
||||
static inline int udev_ctrl_send_reload(struct udev_ctrl *uctrl) {
|
||||
static inline int udev_ctrl_send_reload(UdevCtrl *uctrl) {
|
||||
return udev_ctrl_send(uctrl, UDEV_CTRL_RELOAD, 0, NULL);
|
||||
}
|
||||
|
||||
static inline int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key) {
|
||||
static inline int udev_ctrl_send_set_env(UdevCtrl *uctrl, const char *key) {
|
||||
return udev_ctrl_send(uctrl, UDEV_CTRL_SET_ENV, 0, key);
|
||||
}
|
||||
|
||||
static inline int udev_ctrl_send_set_children_max(struct udev_ctrl *uctrl, int count) {
|
||||
static inline int udev_ctrl_send_set_children_max(UdevCtrl *uctrl, int count) {
|
||||
return udev_ctrl_send(uctrl, UDEV_CTRL_SET_CHILDREN_MAX, count, NULL);
|
||||
}
|
||||
|
||||
static inline int udev_ctrl_send_ping(struct udev_ctrl *uctrl) {
|
||||
static inline int udev_ctrl_send_ping(UdevCtrl *uctrl) {
|
||||
return udev_ctrl_send(uctrl, UDEV_CTRL_PING, 0, NULL);
|
||||
}
|
||||
|
||||
static inline int udev_ctrl_send_exit(struct udev_ctrl *uctrl) {
|
||||
static inline int udev_ctrl_send_exit(UdevCtrl *uctrl) {
|
||||
return udev_ctrl_send(uctrl, UDEV_CTRL_EXIT, 0, NULL);
|
||||
}
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_ctrl*, udev_ctrl_unref);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(UdevCtrl*, udev_ctrl_unref);
|
||||
|
||||
@ -1154,7 +1154,7 @@ static void rule_resolve_goto(UdevRuleFile *rule_file) {
|
||||
if (!FLAGS_SET(line->type, LINE_HAS_GOTO))
|
||||
continue;
|
||||
|
||||
LIST_FOREACH_AFTER(rule_lines, i, line)
|
||||
LIST_FOREACH(rule_lines, i, line->rule_lines_next)
|
||||
if (streq_ptr(i->label, line->goto_label)) {
|
||||
line->goto_line = i;
|
||||
break;
|
||||
|
||||
@ -48,7 +48,7 @@ static int help(void) {
|
||||
}
|
||||
|
||||
int control_main(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(udev_ctrl_unrefp) struct udev_ctrl *uctrl = NULL;
|
||||
_cleanup_(udev_ctrl_unrefp) UdevCtrl *uctrl = NULL;
|
||||
usec_t timeout = 60 * USEC_PER_SEC;
|
||||
int c, r;
|
||||
|
||||
|
||||
@ -176,7 +176,7 @@ int settle_main(int argc, char *argv[], void *userdata) {
|
||||
|
||||
/* guarantee that the udev daemon isn't pre-processing */
|
||||
if (getuid() == 0) {
|
||||
_cleanup_(udev_ctrl_unrefp) struct udev_ctrl *uctrl = NULL;
|
||||
_cleanup_(udev_ctrl_unrefp) UdevCtrl *uctrl = NULL;
|
||||
|
||||
if (udev_ctrl_new(&uctrl) >= 0) {
|
||||
r = udev_ctrl_send_ping(uctrl);
|
||||
|
||||
@ -421,7 +421,7 @@ int trigger_main(int argc, char *argv[], void *userdata) {
|
||||
}
|
||||
|
||||
if (ping) {
|
||||
_cleanup_(udev_ctrl_unrefp) struct udev_ctrl *uctrl = NULL;
|
||||
_cleanup_(udev_ctrl_unrefp) UdevCtrl *uctrl = NULL;
|
||||
|
||||
r = udev_ctrl_new(&uctrl);
|
||||
if (r < 0)
|
||||
|
||||
665
src/udev/udevd.c
665
src/udev/udevd.c
@ -77,10 +77,13 @@ static usec_t arg_event_timeout_usec = 180 * USEC_PER_SEC;
|
||||
static int arg_timeout_signal = SIGKILL;
|
||||
static bool arg_blockdev_read_only = false;
|
||||
|
||||
typedef struct Event Event;
|
||||
typedef struct Worker Worker;
|
||||
|
||||
typedef struct Manager {
|
||||
sd_event *event;
|
||||
Hashmap *workers;
|
||||
LIST_HEAD(struct event, events);
|
||||
LIST_HEAD(Event, events);
|
||||
const char *cgroup;
|
||||
pid_t pid; /* the process that originally allocated the manager object */
|
||||
int log_level;
|
||||
@ -91,7 +94,7 @@ typedef struct Manager {
|
||||
sd_netlink *rtnl;
|
||||
|
||||
sd_device_monitor *monitor;
|
||||
struct udev_ctrl *ctrl;
|
||||
UdevCtrl *ctrl;
|
||||
int worker_watch[2];
|
||||
|
||||
/* used by udev-watch */
|
||||
@ -106,54 +109,52 @@ typedef struct Manager {
|
||||
bool exit;
|
||||
} Manager;
|
||||
|
||||
enum event_state {
|
||||
typedef enum EventState {
|
||||
EVENT_UNDEF,
|
||||
EVENT_QUEUED,
|
||||
EVENT_RUNNING,
|
||||
};
|
||||
} EventState;
|
||||
|
||||
struct event {
|
||||
typedef struct Event {
|
||||
Manager *manager;
|
||||
struct worker *worker;
|
||||
enum event_state state;
|
||||
Worker *worker;
|
||||
EventState state;
|
||||
|
||||
sd_device *dev;
|
||||
sd_device *dev_kernel; /* clone of originally received device */
|
||||
|
||||
uint64_t seqnum;
|
||||
uint64_t delaying_seqnum;
|
||||
uint64_t blocker_seqnum;
|
||||
|
||||
sd_event_source *timeout_warning_event;
|
||||
sd_event_source *timeout_event;
|
||||
|
||||
LIST_FIELDS(struct event, event);
|
||||
};
|
||||
LIST_FIELDS(Event, event);
|
||||
} Event;
|
||||
|
||||
static void event_queue_cleanup(Manager *manager, enum event_state type);
|
||||
|
||||
enum worker_state {
|
||||
typedef enum WorkerState {
|
||||
WORKER_UNDEF,
|
||||
WORKER_RUNNING,
|
||||
WORKER_IDLE,
|
||||
WORKER_KILLED,
|
||||
WORKER_KILLING,
|
||||
};
|
||||
} WorkerState;
|
||||
|
||||
struct worker {
|
||||
typedef struct Worker {
|
||||
Manager *manager;
|
||||
pid_t pid;
|
||||
sd_device_monitor *monitor;
|
||||
enum worker_state state;
|
||||
struct event *event;
|
||||
};
|
||||
WorkerState state;
|
||||
Event *event;
|
||||
} Worker;
|
||||
|
||||
/* passed from worker to main process */
|
||||
struct worker_message {
|
||||
};
|
||||
typedef struct WorkerMessage {
|
||||
} WorkerMessage;
|
||||
|
||||
static void event_free(struct event *event) {
|
||||
static Event *event_free(Event *event) {
|
||||
if (!event)
|
||||
return;
|
||||
return NULL;
|
||||
|
||||
assert(event->manager);
|
||||
|
||||
@ -170,13 +171,24 @@ static void event_free(struct event *event) {
|
||||
/* only clean up the queue from the process that created it */
|
||||
if (LIST_IS_EMPTY(event->manager->events) &&
|
||||
event->manager->pid == getpid_cached())
|
||||
if (unlink("/run/udev/queue") < 0)
|
||||
log_warning_errno(errno, "Failed to unlink /run/udev/queue: %m");
|
||||
if (unlink("/run/udev/queue") < 0 && errno != ENOENT)
|
||||
log_warning_errno(errno, "Failed to unlink /run/udev/queue, ignoring: %m");
|
||||
|
||||
free(event);
|
||||
return mfree(event);
|
||||
}
|
||||
|
||||
static struct worker* worker_free(struct worker *worker) {
|
||||
static void event_queue_cleanup(Manager *manager, EventState match_state) {
|
||||
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)
|
||||
return NULL;
|
||||
|
||||
@ -189,89 +201,8 @@ static struct worker* worker_free(struct worker *worker) {
|
||||
return mfree(worker);
|
||||
}
|
||||
|
||||
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, 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);
|
||||
}
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(Worker*, worker_free);
|
||||
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(worker_hash_op, void, trivial_hash_func, trivial_compare_func, Worker, worker_free);
|
||||
|
||||
static void manager_clear_for_worker(Manager *manager) {
|
||||
assert(manager);
|
||||
@ -314,8 +245,109 @@ static Manager* manager_free(Manager *manager) {
|
||||
|
||||
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) {
|
||||
struct worker_message message = {};
|
||||
WorkerMessage message = {};
|
||||
|
||||
return loop_write(fd, &message, sizeof(message), false);
|
||||
}
|
||||
@ -591,9 +623,59 @@ static int worker_main(Manager *_manager, sd_device_monitor *monitor, sd_device
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int worker_spawn(Manager *manager, struct event *event) {
|
||||
static int on_event_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
|
||||
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;
|
||||
struct worker *worker;
|
||||
Worker *worker;
|
||||
pid_t pid;
|
||||
int r;
|
||||
|
||||
@ -635,16 +717,18 @@ static int worker_spawn(Manager *manager, struct event *event) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void event_run(Manager *manager, struct event *event) {
|
||||
static int event_run(Event *event) {
|
||||
static bool log_children_max_reached = true;
|
||||
struct worker *worker;
|
||||
Manager *manager;
|
||||
Worker *worker;
|
||||
int r;
|
||||
|
||||
assert(manager);
|
||||
assert(event);
|
||||
assert(event->manager);
|
||||
|
||||
log_device_uevent(event->dev, "Device ready for processing");
|
||||
|
||||
manager = event->manager;
|
||||
HASHMAP_FOREACH(worker, manager->workers) {
|
||||
if (worker->state != WORKER_IDLE)
|
||||
continue;
|
||||
@ -658,110 +742,73 @@ static void event_run(Manager *manager, struct event *event) {
|
||||
continue;
|
||||
}
|
||||
worker_attach_event(worker, event);
|
||||
return;
|
||||
return 1; /* event is now processing. */
|
||||
}
|
||||
|
||||
if (hashmap_size(manager->workers) >= arg_children_max) {
|
||||
|
||||
/* Avoid spamming the debug logs if the limit is already reached and
|
||||
* many events still need to be processed */
|
||||
if (log_children_max_reached && arg_children_max > 1) {
|
||||
log_debug("Maximum number (%u) of children reached.", hashmap_size(manager->workers));
|
||||
log_children_max_reached = false;
|
||||
}
|
||||
return;
|
||||
return 0; /* no free worker */
|
||||
}
|
||||
|
||||
/* Re-enable the debug message for the next batch of events */
|
||||
log_children_max_reached = true;
|
||||
|
||||
/* 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();
|
||||
|
||||
/* start new worker and pass initial device */
|
||||
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);
|
||||
r = worker_spawn(manager, event);
|
||||
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(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");
|
||||
return 1; /* event is now processing. */
|
||||
}
|
||||
|
||||
LIST_APPEND(event, manager->events, event);
|
||||
|
||||
log_device_uevent(dev, "Device is queued");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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) {
|
||||
static int event_is_blocked(Event *event) {
|
||||
const char *subsystem, *devpath, *devpath_old = NULL;
|
||||
dev_t devnum = makedev(0, 0);
|
||||
struct event *loop_event;
|
||||
Event *loop_event;
|
||||
size_t devpath_len;
|
||||
int r, ifindex = 0;
|
||||
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);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -787,21 +834,13 @@ static int is_device_busy(Manager *manager, struct event *event) {
|
||||
return r;
|
||||
|
||||
/* check if queue contains events we depend on */
|
||||
LIST_FOREACH(event, loop_event, manager->events) {
|
||||
LIST_FOREACH(event, loop_event, loop_event) {
|
||||
size_t loop_devpath_len, common;
|
||||
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 */
|
||||
if (loop_event->seqnum >= event->seqnum)
|
||||
break;
|
||||
goto no_blocker;
|
||||
|
||||
/* check major/minor */
|
||||
if (major(devnum) != 0) {
|
||||
@ -813,7 +852,7 @@ static int is_device_busy(Manager *manager, struct event *event) {
|
||||
|
||||
if (sd_device_get_devnum(loop_event->dev, &d) >= 0 &&
|
||||
devnum == d && is_block == streq(s, "block"))
|
||||
goto set_delaying_seqnum;
|
||||
break;
|
||||
}
|
||||
|
||||
/* check network device ifindex */
|
||||
@ -822,7 +861,7 @@ static int is_device_busy(Manager *manager, struct event *event) {
|
||||
|
||||
if (sd_device_get_ifindex(loop_event->dev, &i) >= 0 &&
|
||||
ifindex == i)
|
||||
goto set_delaying_seqnum;
|
||||
break;
|
||||
}
|
||||
|
||||
if (sd_device_get_devpath(loop_event->dev, &loop_devpath) < 0)
|
||||
@ -830,7 +869,7 @@ static int is_device_busy(Manager *manager, struct event *event) {
|
||||
|
||||
/* check our old name */
|
||||
if (devpath_old && streq(devpath_old, loop_devpath))
|
||||
goto set_delaying_seqnum;
|
||||
break;
|
||||
|
||||
loop_devpath_len = strlen(loop_devpath);
|
||||
|
||||
@ -843,80 +882,32 @@ static int is_device_busy(Manager *manager, struct event *event) {
|
||||
|
||||
/* identical device event found */
|
||||
if (devpath_len == loop_devpath_len)
|
||||
goto set_delaying_seqnum;
|
||||
break;
|
||||
|
||||
/* parent device event found */
|
||||
if (devpath[common] == '/')
|
||||
goto set_delaying_seqnum;
|
||||
break;
|
||||
|
||||
/* child device event found */
|
||||
if (loop_devpath[common] == '/')
|
||||
goto set_delaying_seqnum;
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
assert(loop_event);
|
||||
|
||||
set_delaying_seqnum:
|
||||
log_device_debug(event->dev, "SEQNUM=%" PRIu64 " blocked by SEQNUM=%" PRIu64,
|
||||
event->seqnum, loop_event->seqnum);
|
||||
|
||||
event->delaying_seqnum = loop_event->seqnum;
|
||||
event->blocker_seqnum = loop_event->seqnum;
|
||||
return true;
|
||||
|
||||
no_blocker:
|
||||
event->blocker_seqnum = event->seqnum;
|
||||
return false;
|
||||
}
|
||||
|
||||
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 void event_queue_start(Manager *manager) {
|
||||
struct event *event;
|
||||
static int event_queue_start(Manager *manager) {
|
||||
Event *event, *event_next;
|
||||
usec_t usec;
|
||||
int r;
|
||||
|
||||
@ -924,12 +915,12 @@ static void event_queue_start(Manager *manager) {
|
||||
|
||||
if (LIST_IS_EMPTY(manager->events) ||
|
||||
manager->exit || manager->stop_exec_queue)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
assert_se(sd_event_now(manager->event, CLOCK_MONOTONIC, &usec) >= 0);
|
||||
/* check for changed config, every 3 seconds at most */
|
||||
if (manager->last_usec == 0 ||
|
||||
usec - manager->last_usec > 3 * USEC_PER_SEC) {
|
||||
usec > usec_add(manager->last_usec, 3 * USEC_PER_SEC)) {
|
||||
if (udev_rules_check_timestamp(manager->rules) ||
|
||||
udev_builtin_validate())
|
||||
manager_reload(manager);
|
||||
@ -945,33 +936,111 @@ static void event_queue_start(Manager *manager) {
|
||||
|
||||
if (!manager->rules) {
|
||||
r = udev_rules_load(&manager->rules, arg_resolve_name_timing);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Failed to read udev rules: %m");
|
||||
return;
|
||||
}
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "Failed to read udev rules: %m");
|
||||
}
|
||||
|
||||
LIST_FOREACH(event, event, manager->events) {
|
||||
LIST_FOREACH_SAFE(event, event, event_next, manager->events) {
|
||||
if (event->state != EVENT_QUEUED)
|
||||
continue;
|
||||
|
||||
/* do not start event if parent or child event is still running */
|
||||
if (is_device_busy(manager, event) != 0)
|
||||
continue;
|
||||
/* do not start event if parent or child event is still running or queued */
|
||||
r = event_is_blocked(event);
|
||||
if (r < 0) {
|
||||
sd_device_action_t a = _SD_DEVICE_ACTION_INVALID;
|
||||
|
||||
event_run(manager, event);
|
||||
}
|
||||
}
|
||||
|
||||
static void event_queue_cleanup(Manager *manager, enum event_state match_type) {
|
||||
struct event *event, *tmp;
|
||||
|
||||
LIST_FOREACH_SAFE(event, event, tmp, manager->events) {
|
||||
if (match_type != EVENT_UNDEF && match_type != event->state)
|
||||
continue;
|
||||
(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;
|
||||
|
||||
r = event_run(event);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int event_queue_insert(Manager *manager, sd_device *dev) {
|
||||
_cleanup_(sd_device_unrefp) sd_device *clone = NULL;
|
||||
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)
|
||||
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) {
|
||||
@ -980,7 +1049,7 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
|
||||
assert(manager);
|
||||
|
||||
for (;;) {
|
||||
struct worker_message msg;
|
||||
WorkerMessage msg;
|
||||
struct iovec iovec = {
|
||||
.iov_base = &msg,
|
||||
.iov_len = sizeof(msg),
|
||||
@ -994,7 +1063,7 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
|
||||
};
|
||||
ssize_t size;
|
||||
struct ucred *ucred;
|
||||
struct worker *worker;
|
||||
Worker *worker;
|
||||
|
||||
size = recvmsg_safe(fd, &msghdr, MSG_DONTWAIT);
|
||||
if (size == -EINTR)
|
||||
@ -1007,7 +1076,7 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
|
||||
|
||||
cmsg_close_all(&msghdr);
|
||||
|
||||
if (size != sizeof(struct worker_message)) {
|
||||
if (size != sizeof(WorkerMessage)) {
|
||||
log_warning("Ignoring worker message with invalid size %zi bytes", size);
|
||||
continue;
|
||||
}
|
||||
@ -1041,30 +1110,8 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
|
||||
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 */
|
||||
static int on_ctrl_msg(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, const union udev_ctrl_msg_value *value, void *userdata) {
|
||||
static int on_ctrl_msg(UdevCtrl *uctrl, UdevCtrlMessageType type, const UdevCtrlMessageValue *value, void *userdata) {
|
||||
Manager *manager = userdata;
|
||||
int r;
|
||||
|
||||
@ -1357,7 +1404,7 @@ static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, voi
|
||||
for (;;) {
|
||||
pid_t pid;
|
||||
int status;
|
||||
struct worker *worker;
|
||||
Worker *worker;
|
||||
|
||||
pid = waitpid(-1, &status, WNOHANG);
|
||||
if (pid <= 0)
|
||||
|
||||
@ -674,9 +674,9 @@ class NetworkctlTests(unittest.TestCase, Utilities):
|
||||
|
||||
output = check_output('ip -4 address show dev dummy98')
|
||||
print(output)
|
||||
self.assertRegex(output, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
|
||||
self.assertRegex(output, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
|
||||
self.assertRegex(output, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
|
||||
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)
|
||||
|
||||
check_output('ip address del 10.1.2.3/16 dev dummy98')
|
||||
check_output('ip address del 10.1.2.4/16 dev dummy98')
|
||||
@ -687,9 +687,30 @@ class NetworkctlTests(unittest.TestCase, Utilities):
|
||||
|
||||
output = check_output('ip -4 address show dev dummy98')
|
||||
print(output)
|
||||
self.assertRegex(output, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
|
||||
self.assertRegex(output, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
|
||||
self.assertRegex(output, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
|
||||
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)
|
||||
|
||||
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):
|
||||
start_networkd(3)
|
||||
|
||||
@ -4,4 +4,13 @@ Description=TEST-10-ISSUE-2467
|
||||
[Service]
|
||||
ExecStartPre=rm -f /failed /testok
|
||||
Type=oneshot
|
||||
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=rm -f /tmp/nonexistent
|
||||
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'
|
||||
|
||||
12
units/factory-reset.target
Normal file
12
units/factory-reset.target
Normal file
@ -0,0 +1,12 @@
|
||||
# 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)
|
||||
@ -19,6 +19,7 @@ units = [
|
||||
'sysinit.target.wants/'],
|
||||
['emergency.target', ''],
|
||||
['exit.target', ''],
|
||||
['factory-reset.target', ''],
|
||||
['final.target', ''],
|
||||
['first-boot-complete.target', ''],
|
||||
['getty.target', '',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user