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

Compare commits

..

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

41 changed files with 729 additions and 952 deletions

9
TODO
View File

@ -83,15 +83,6 @@ Janitorial Clean-ups:
Features:
* 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:

View File

@ -188,15 +188,6 @@ 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

View File

@ -216,9 +216,8 @@
<literal>suspend</literal>,
<literal>hibernate</literal>,
<literal>hybrid-sleep</literal>,
<literal>suspend-then-hibernate</literal>,
<literal>lock</literal>, and
<literal>factory-reset</literal>.
<literal>suspend-then-hibernate</literal>, and
<literal>lock</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

View File

@ -33,7 +33,6 @@
<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>,
@ -280,12 +279,6 @@
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>

View File

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

View File

@ -20,7 +20,6 @@
#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"

View File

@ -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(same_sysfs, other, d->same_sysfs_next)
LIST_FOREACH_AFTER(same_sysfs, other, d)
if (startswith(UNIT(other)->id, "sys-"))
return UNIT(other);
LIST_FOREACH_BACKWARDS(same_sysfs, other, d->same_sysfs_prev) {
LIST_FOREACH_BEFORE(same_sysfs, other, d) {
if (startswith(UNIT(other)->id, "sys-"))
return UNIT(other);
@ -802,13 +802,13 @@ static int device_following_set(Unit *u, Set **_set) {
if (!set)
return -ENOMEM;
LIST_FOREACH(same_sysfs, other, d->same_sysfs_next) {
LIST_FOREACH_AFTER(same_sysfs, other, d) {
r = set_put(set, other);
if (r < 0)
return r;
}
LIST_FOREACH_BACKWARDS(same_sysfs, other, d->same_sysfs_prev) {
LIST_FOREACH_BEFORE(same_sysfs, other, d) {
r = set_put(set, other);
if (r < 0)
return r;

View File

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

View File

@ -451,10 +451,6 @@ 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);
@ -463,6 +459,10 @@ 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;

View File

@ -27,7 +27,6 @@ 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);
@ -52,7 +51,6 @@ 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;
@ -181,7 +179,6 @@ 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",
};

View File

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

View File

@ -1491,59 +1491,41 @@ static int have_multiple_sessions(
return false;
}
_printf_(2, 0)
static int log_with_wall_message(Manager *m, const char *d, const char *p, const char *q) {
static int bus_manager_log_shutdown(
Manager *m,
const char *unit_name) {
const char *p, *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, 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,
"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);
return log_struct(LOG_NOTICE,
"MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_STR,
p,
q);
}
static int lid_switch_ignore_handler(sd_event_source *e, uint64_t usec, void *userdata) {

View File

@ -96,64 +96,113 @@ const DUID *link_get_duid(Link *link, int family) {
return duid;
}
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));
return 0;
goto configure;
}
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");
return 0;
goto configure;
}
if (sz != sizeof(sd_id128_t)) {
log_warning("Invalid product UUID. Falling back to use machine-app-specific ID as DUID-UUID.");
return 0;
goto configure;
}
log_debug("Successfully obtained product UUID");
memcpy(&manager->duid_product_uuid.raw_data, a, sz);
manager->duid_product_uuid.raw_data_len = sz;
return 0;
configure:
/* To avoid calling GetProductUUID() bus method so frequently, set the flag below
* even if the method fails. */
manager->has_product_uuid = true;
while ((link = set_steal_first(manager->links_requesting_uuid))) {
r = link_configure_and_start_dhcp_delayed(link);
if (r < 0)
link_enter_failed(link);
link_unref(link);
}
manager->links_requesting_uuid = set_free(manager->links_requesting_uuid);
return 1;
}
int manager_request_product_uuid(Manager *m) {
static bool bus_method_is_called = false;
int r;
assert(m);
if (bus_method_is_called)
if (m->product_uuid_requested)
return 0;
if (sd_bus_is_ready(m->bus) <= 0 && !m->product_uuid_requested) {
log_debug("Requesting product UUID");
if (sd_bus_is_ready(m->bus) <= 0) {
log_debug("Not connected to system bus, requesting product UUID later.");
m->product_uuid_requested = true;
return 0;
}
m->product_uuid_requested = false;
r = sd_bus_call_method_async(
m->bus,
NULL,
@ -168,9 +217,7 @@ int manager_request_product_uuid(Manager *m) {
if (r < 0)
return log_warning_errno(r, "Failed to get product UUID: %m");
log_debug("Requesting product UUID.");
bus_method_is_called = true;
m->product_uuid_requested = true;
return 0;
}
@ -195,11 +242,15 @@ 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;
}
@ -492,8 +543,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 DHCPv4 and DHCPv6.
* If DHCPv6 IAID is not specified explicitly, then use DHCPv4 IAID for DHCPv6. */
/* Backward compatibility. Previously, IAID is shared by DHCP4 and DHCP6.
* If DHCP6 IAID is not specified explicitly, then use DHCP4 IAID for DHCP6. */
network->dhcp6_iaid = iaid;
network->dhcp6_iaid_set = true;
}
@ -985,7 +1036,7 @@ int config_parse_manager_duid_type(
assert(manager);
/* For backward compatibility. Setting both DHCPv4 and DHCPv6 DUID if they are not specified explicitly. */
/* For backward compatibility. Setting both DHCP4 and DHCP6 DUID if they are not specified explicitly. */
r = config_parse_duid_type(unit, filename, line, section, section_line, lvalue, false, rvalue, &manager->dhcp_duid, manager);
if (r < 0)
@ -1015,7 +1066,7 @@ int config_parse_network_duid_type(
if (r < 0)
return r;
/* For backward compatibility, also set DHCPv6 DUID if not specified explicitly. */
/* For backward compatibility, also set DHCP6 DUID if not specified explicitly. */
return config_parse_duid_type(unit, filename, line, section, section_line, lvalue, false, rvalue, &network->dhcp6_duid, network);
}
@ -1110,7 +1161,7 @@ int config_parse_manager_duid_rawdata(
assert(manager);
/* For backward compatibility. Setting both DHCPv4 and DHCPv6 DUID if they are not specified explicitly. */
/* For backward compatibility. Setting both DHCP4 and DHCP6 DUID if they are not specified explicitly. */
r = config_parse_duid_rawdata(unit, filename, line, section, section_line, lvalue, false, rvalue, &manager->dhcp_duid, manager);
if (r < 0)
@ -1140,6 +1191,6 @@ int config_parse_network_duid_rawdata(
if (r < 0)
return r;
/* For backward compatibility, also set DHCPv6 DUID if not specified explicitly. */
/* For backward compatibility, also set DHCP6 DUID if not specified explicitly. */
return config_parse_duid_rawdata(unit, filename, line, section, section_line, lvalue, false, rvalue, &network->dhcp6_duid, network);
}

View File

@ -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_debug_errno(link, r, "DHCPv4 CLIENT: Failed to get hostname: %m");
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to get hostname: %m");
hn = hostname;
}
@ -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, "DHCPv4 CLIENT: Failed to set hostname from kernel hostname, ignoring: %m");
log_link_debug_errno(link, r, "DHCP4 CLIENT: Failed to set hostname from kernel hostname, ignoring: %m");
else if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set hostname: %m");
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set hostname: %m");
return 0;
}
@ -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_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set IAID+DUID: %m");
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set IAID+DUID: %m");
break;
}
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_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set DUID: %m");
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set DUID: %m");
break;
}
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_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set client ID: %m");
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set client ID: %m");
break;
}
default:
@ -1395,6 +1395,15 @@ 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;
@ -1415,7 +1424,7 @@ static int dhcp4_set_request_address(Link *link) {
if (!a)
return 0;
log_link_debug(link, "DHCPv4 CLIENT: requesting " IPV4_ADDRESS_FMT_STR, IPV4_ADDRESS_FMT_VAL(a->in_addr.in));
log_link_debug(link, "DHCP4 CLIENT: requesting " IPV4_ADDRESS_FMT_STR, IPV4_ADDRESS_FMT_VAL(a->in_addr.in));
return sd_dhcp_client_set_request_address(link->dhcp_client, &a->in_addr.in);
}
@ -1436,15 +1445,15 @@ static bool link_needs_dhcp_broadcast(Link *link) {
if (r < 0 && link->sd_device && sd_device_get_property_value(link->sd_device, "ID_NET_DHCP_BROADCAST", &val) >= 0) {
r = parse_boolean(val);
if (r < 0)
log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to parse ID_NET_DHCP_BROADCAST, ignoring: %m");
log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to parse ID_NET_DHCP_BROADCAST, ignoring: %m");
else
log_link_debug(link, "DHCPv4 CLIENT: Detected ID_NET_DHCP_BROADCAST='%d'.", r);
log_link_debug(link, "DHCP4 CLIENT: Detected ID_NET_DHCP_BROADCAST='%d'.", r);
}
return r == true;
}
static int dhcp4_configure(Link *link) {
int dhcp4_configure(Link *link) {
sd_dhcp_option *send_option;
void *request_options;
int r;
@ -1452,81 +1461,88 @@ static int dhcp4_configure(Link *link) {
assert(link);
assert(link->network);
if (!link_dhcp4_enabled(link))
return 0;
if (link->dhcp_client)
return log_link_debug_errno(link, SYNTHETIC_ERRNO(EBUSY), "DHCPv4 client is already configured.");
return -EBUSY; /* Already configured. */
r = dhcp4_configure_duid(link);
if (r <= 0)
return r;
r = sd_dhcp_client_new(&link->dhcp_client, link->network->dhcp_anonymize);
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to allocate DHCPv4 client: %m");
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to allocate DHCP4 client: %m");
r = sd_dhcp_client_attach_event(link->dhcp_client, link->manager->event, 0);
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to attach event to DHCPv4 client: %m");
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to attach event to DHCP4 client: %m");
r = sd_dhcp_client_set_mac(link->dhcp_client,
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_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set MAC address: %m");
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set MAC address: %m");
r = sd_dhcp_client_set_ifindex(link->dhcp_client, link->ifindex);
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set ifindex: %m");
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set ifindex: %m");
r = sd_dhcp_client_set_callback(link->dhcp_client, dhcp4_handler, link);
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set callback: %m");
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set callback: %m");
r = sd_dhcp_client_set_request_broadcast(link->dhcp_client, link_needs_dhcp_broadcast(link));
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for broadcast: %m");
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for broadcast: %m");
if (link->mtu > 0) {
r = sd_dhcp_client_set_mtu(link->dhcp_client, link->mtu);
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set MTU: %m");
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set MTU: %m");
}
if (!link->network->dhcp_anonymize) {
if (link->network->dhcp_use_mtu) {
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_INTERFACE_MTU);
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for MTU: %m");
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for MTU: %m");
}
if (link->network->dhcp_use_routes) {
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_STATIC_ROUTE);
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for static route: %m");
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for static route: %m");
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE);
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for classless static route: %m");
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for classless static route: %m");
}
if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) {
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_DOMAIN_SEARCH_LIST);
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for domain search list: %m");
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for domain search list: %m");
}
if (link->network->dhcp_use_ntp) {
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NTP_SERVER);
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for NTP server: %m");
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for NTP server: %m");
}
if (link->network->dhcp_use_sip) {
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_SIP_SERVER);
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for SIP server: %m");
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for SIP server: %m");
}
if (link->network->dhcp_use_timezone) {
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NEW_TZDB_TIMEZONE);
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for timezone: %m");
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for timezone: %m");
}
SET_FOREACH(request_options, link->network->dhcp_request_options) {
@ -1534,7 +1550,7 @@ static int dhcp4_configure(Link *link) {
r = sd_dhcp_client_set_request_option(link->dhcp_client, option);
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for '%u': %m", option);
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for '%u': %m", option);
}
ORDERED_HASHMAP_FOREACH(send_option, link->network->dhcp_client_send_options) {
@ -1542,7 +1558,7 @@ static int dhcp4_configure(Link *link) {
if (r == -EEXIST)
continue;
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set send option: %m");
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set send option: %m");
}
ORDERED_HASHMAP_FOREACH(send_option, link->network->dhcp_client_send_vendor_options) {
@ -1550,7 +1566,7 @@ static int dhcp4_configure(Link *link) {
if (r == -EEXIST)
continue;
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set send option: %m");
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set send option: %m");
}
r = dhcp4_set_hostname(link);
@ -1561,49 +1577,49 @@ static 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_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set vendor class identifier: %m");
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set vendor class identifier: %m");
}
if (link->network->dhcp_mudurl) {
r = sd_dhcp_client_set_mud_url(link->dhcp_client, link->network->dhcp_mudurl);
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set MUD URL: %m");
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set MUD URL: %m");
}
if (link->network->dhcp_user_class) {
r = sd_dhcp_client_set_user_class(link->dhcp_client, link->network->dhcp_user_class);
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set user class: %m");
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set user class: %m");
}
}
if (link->network->dhcp_client_port > 0) {
r = sd_dhcp_client_set_client_port(link->dhcp_client, link->network->dhcp_client_port);
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set listen port: %m");
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set listen port: %m");
}
if (link->network->dhcp_max_attempts > 0) {
r = sd_dhcp_client_set_max_attempts(link->dhcp_client, link->network->dhcp_max_attempts);
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set max attempts: %m");
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set max attempts: %m");
}
if (link->network->dhcp_ip_service_type > 0) {
r = sd_dhcp_client_set_service_type(link->dhcp_client, link->network->dhcp_ip_service_type);
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set IP service type: %m");
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set IP service type: %m");
}
if (link->network->dhcp_fallback_lease_lifetime > 0) {
r = sd_dhcp_client_set_fallback_lease_lifetime(link->dhcp_client, link->network->dhcp_fallback_lease_lifetime);
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed set to lease lifetime: %m");
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed set to lease lifetime: %m");
}
r = dhcp4_set_request_address(link);
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set initial DHCPv4 address: %m");
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set initial DHCPv4 address: %m");
return dhcp4_set_client_identifier(link);
}
@ -1626,83 +1642,17 @@ 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;
r = sd_dhcp_client_start(link->dhcp_client);
if (r < 0)
return r;
log_link_debug(link, "Acquiring DHCPv4 lease");
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;
return sd_dhcp_client_start(link->dhcp_client);
}
int config_parse_dhcp_max_attempts(

View File

@ -4,8 +4,6 @@
#include "conf-parser.h"
typedef struct Link Link;
typedef struct Network Network;
typedef struct Request Request;
typedef enum DHCPClientIdentifier {
DHCP_CLIENT_ID_MAC,
@ -20,13 +18,11 @@ 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);

View File

@ -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,
"DHCPv6: received PD Prefix %s%s",
"DHCP6: 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 DHCPv6 PD prefix %s: %m", strna(buf));
return log_link_error_errno(link, r, "Failed to store DHCP6 PD prefix %s: %m", strna(buf));
if (r > 0)
TAKE_PTR(p);
@ -1393,8 +1393,6 @@ int dhcp6_request_information(Link *link, int ir) {
}
int dhcp6_start(Link *link) {
int r;
assert(link);
if (!link->dhcp6_client)
@ -1403,9 +1401,6 @@ 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;
@ -1417,11 +1412,9 @@ int dhcp6_start(Link *link) {
if (sd_dhcp6_client_is_running(link->dhcp6_client) > 0)
return 0;
r = dhcp6_request_information(link, link->network->dhcp6_without_ra == DHCP6_CLIENT_START_MODE_INFORMATION_REQUEST);
if (r < 0)
return r;
log_link_debug(link, "Acquiring DHCPv6 lease");
return 1;
return dhcp6_request_information(link, link->network->dhcp6_without_ra == DHCP6_CLIENT_START_MODE_INFORMATION_REQUEST);
}
int dhcp6_request_prefix_delegation(Link *link) {
@ -1512,7 +1505,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 log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to get hostname: %m");
return r;
hn = hostname;
}
@ -1520,9 +1513,9 @@ static int dhcp6_set_hostname(sd_dhcp6_client *client, Link *link) {
r = sd_dhcp6_client_set_fqdn(client, hn);
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, "DHCPv6 CLIENT: Failed to set hostname from kernel hostname, ignoring: %m");
log_link_warning_errno(link, r, "DHCP6 CLIENT: Failed to set hostname from kernel hostname, ignoring: %m");
else if (r < 0)
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set hostname: %m");
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set hostname: %m");
return 0;
}
@ -1578,7 +1571,7 @@ static int dhcp6_set_identifier(Link *link, sd_dhcp6_client *client) {
return 0;
}
static int dhcp6_configure(Link *link) {
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;
@ -1588,29 +1581,36 @@ static 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 log_link_debug_errno(link, SYNTHETIC_ERRNO(EBUSY), "DHCPv6 client is already configured.");
return -EBUSY;
r = dhcp_configure_duid(link, link_get_dhcp6_duid(link));
if (r <= 0)
return r;
r = sd_dhcp6_client_new(&client);
if (r == -ENOMEM)
return log_oom_debug();
return log_oom();
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to create DHCPv6 client: %m");
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to create DHCP6 client: %m");
r = sd_dhcp6_client_attach_event(client, link->manager->event, 0);
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to attach event: %m");
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to attach event: %m");
r = dhcp6_set_identifier(link, client);
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set identifier: %m");
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set identifier: %m");
ORDERED_HASHMAP_FOREACH(send_option, link->network->dhcp6_client_send_options) {
r = sd_dhcp6_client_add_option(client, send_option);
if (r == -EEXIST)
continue;
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set option: %m");
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set option: %m");
}
r = dhcp6_set_hostname(client, link);
@ -1619,18 +1619,18 @@ static int dhcp6_configure(Link *link) {
r = sd_dhcp6_client_set_ifindex(client, link->ifindex);
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set ifindex: %m");
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set ifindex: %m");
if (link->network->dhcp6_rapid_commit) {
r = sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_RAPID_COMMIT);
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set request flag for rapid commit: %m");
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set request flag for rapid commit: %m");
}
if (link->network->dhcp6_mudurl) {
r = sd_dhcp6_client_set_request_mud_url(client, link->network->dhcp6_mudurl);
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set MUD URL: %m");
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set MUD URL: %m");
}
SET_FOREACH(request_options, link->network->dhcp6_request_options) {
@ -1638,23 +1638,23 @@ static int dhcp6_configure(Link *link) {
r = sd_dhcp6_client_set_request_option(client, option);
if (r == -EEXIST) {
log_link_debug(link, "DHCPv6 CLIENT: Failed to set request flag for '%u' already exists, ignoring.", option);
log_link_debug(link, "DHCP6 CLIENT: Failed to set request flag for '%u' already exists, ignoring.", option);
continue;
}
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set request flag for '%u': %m", option);
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set request flag for '%u': %m", option);
}
if (link->network->dhcp6_user_class) {
r = sd_dhcp6_client_set_request_user_class(client, link->network->dhcp6_user_class);
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set user class: %m");
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set user class: %m");
}
if (link->network->dhcp6_vendor_class) {
r = sd_dhcp6_client_set_request_vendor_class(client, link->network->dhcp6_vendor_class);
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set vendor class: %m");
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set vendor class: %m");
}
ORDERED_HASHMAP_FOREACH(vendor_option, link->network->dhcp6_client_send_vendor_options) {
@ -1662,23 +1662,23 @@ static int dhcp6_configure(Link *link) {
if (r == -EEXIST)
continue;
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set vendor option: %m");
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set vendor option: %m");
}
r = sd_dhcp6_client_set_callback(client, dhcp6_handler, link);
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set callback: %m");
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set callback: %m");
if (dhcp6_enable_prefix_delegation(link)) {
r = sd_dhcp6_client_set_prefix_delegation(client, true);
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set prefix delegation: %m");
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set prefix delegation: %m");
}
if (link->network->dhcp6_pd_length > 0) {
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_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set prefix hint: %m");
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set prefix hint: %m");
}
link->dhcp6_client = TAKE_PTR(client);
@ -1716,60 +1716,6 @@ 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;

View File

@ -1,8 +1,9 @@
/* 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 {
@ -14,7 +15,7 @@ typedef enum DHCP6ClientStartMode {
} DHCP6ClientStartMode;
typedef struct Link Link;
typedef struct Request Request;
typedef struct Manager Manager;
typedef struct DHCP6DelegatedPrefix {
struct in6_addr prefix; /* Prefix assigned to the link */
@ -28,14 +29,12 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(DHCP6DelegatedPrefix*, dhcp6_pd_free);
bool link_dhcp6_with_address_enabled(Link *link);
bool link_dhcp6_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);

View File

@ -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(): DHCPv4, DHCPv6 or IPv4LL is enabled but no dynamic address is assigned yet.", __func__);
return (void) log_link_debug(link, "%s(): DHCP4, DHCP6 or IPv4LL is enabled but no dynamic address is assigned yet.", __func__);
/* Ignore NDisc when ConfigureWithoutCarrier= is enabled, as IPv6AcceptRA= is enabled by default. */
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(): DHCPv4:%s IPv4LL:%s DHCPv6_addresses:%s DHCPv6_routes:%s "
"DHCPv6PD_addresses:%s DHCPv6PD_routes:%s NDisc_addresses:%s NDisc_routes:%s",
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",
__func__,
yes_no(link->dhcp4_configured),
yes_no(link->ipv4ll_address_configured),
@ -650,14 +650,12 @@ 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");
log_link_debug(link, "Acquiring DHCPv4 lease.");
} else if (link->ipv4ll) {
log_link_debug(link, "Acquiring IPv4 link-local address");
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) {
@ -692,12 +690,6 @@ 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;
}
@ -983,6 +975,8 @@ 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);
@ -1005,16 +999,6 @@ 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);
@ -1143,11 +1127,11 @@ static int link_configure(Link *link) {
if (r < 0)
return r;
r = link_request_dhcp4_client(link);
r = dhcp4_configure(link);
if (r < 0)
return r;
r = link_request_dhcp6_client(link);
r = dhcp6_configure(link);
if (r < 0)
return r;
@ -1167,9 +1151,14 @@ static int link_configure(Link *link) {
if (r < 0)
return r;
r = link_drop_foreign_config(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)
@ -1235,22 +1224,23 @@ static int link_get_network(Link *link, Network **ret) {
}
static int link_reconfigure_impl(Link *link, bool force) {
Network *network = NULL;
Network *network;
int r;
assert(link);
r = link_get_network(link, &network);
if (r < 0 && r != -ENOENT)
if (r == -ENOENT) {
link_set_state(link, LINK_STATE_UNMANAGED);
return 0;
}
if (r < 0)
return r;
if (link->network == network && !force)
return 0;
if (network)
log_link_info(link, "Reconfiguring with %s.", network->filename);
else
log_link_info(link, "Unmanaging interface.");
log_link_info(link, "Re-configuring with %s", network->filename);
/* Dropping old .network file */
r = link_stop_engines(link, false);
@ -1263,14 +1253,17 @@ 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);
if (!network) {
link_set_state(link, LINK_STATE_UNMANAGED);
return 0;
}
link_unref(set_remove(link->manager->links_requesting_uuid, link));
/* Then, apply new .network file */
link->network = network_ref(network);
@ -1291,85 +1284,30 @@ 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, bool update_wifi) {
bool link_was_lower_up;
static int link_reconfigure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, bool force) {
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;
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) {
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_internal(Link *link, link_netlink_message_handler_t callback) {
int r;
static int link_reconfigure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
return link_reconfigure_handler_internal(rtnl, m, link, false);
}
assert(link);
assert(callback);
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) {
int r;
/* 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
@ -1377,21 +1315,13 @@ static int link_reconfigure_internal(Link *link, link_netlink_message_handler_t
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, callback);
r = link_call_getlink(link, force ? link_force_reconfigure_handler : link_reconfigure_handler);
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;
@ -1630,7 +1560,34 @@ static int link_carrier_lost(Link *link) {
if (r < 0)
return r;
return link_drop_foreign_config(link);
if (!IN_SET(link->state, LINK_STATE_UNMANAGED, LINK_STATE_PENDING, LINK_STATE_INITIALIZED)) {
log_link_debug(link, "State is %s, dropping foreign config", link_state_to_string(link->state));
r = link_drop_foreign_config(link);
if (r < 0)
return r;
}
return 0;
}
int link_carrier_reset(Link *link) {
int r;
assert(link);
if (!link_has_carrier(link))
return 0;
r = link_carrier_lost(link);
if (r < 0)
return r;
r = link_carrier_gained(link);
if (r < 0)
return r;
log_link_info(link, "Reset carrier");
return 0;
}
static int link_admin_state_up(Link *link) {
@ -1986,6 +1943,10 @@ 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");

View File

@ -232,6 +232,7 @@ 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);
@ -246,7 +247,6 @@ 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);

View File

@ -103,9 +103,38 @@ 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;

View File

@ -14,6 +14,7 @@ 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_;

View File

@ -59,9 +59,9 @@ static int manager_reset_all(Manager *m) {
assert(m);
HASHMAP_FOREACH(link, m->links_by_index) {
r = link_reconfigure_after_sleep(link);
r = link_carrier_reset(link);
if (r < 0) {
log_link_warning_errno(link, r, "Failed to reconfigure interface: %m");
log_link_warning_errno(link, r, "Could not reset carrier: %m");
link_enter_failed(link);
}
}
@ -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 (m->product_uuid_requested)
if (!set_isempty(m->links_requesting_uuid))
(void) manager_request_product_uuid(m);
return 0;
@ -460,6 +460,7 @@ Manager* manager_free(Manager *m) {
m->dhcp6_pd_prefixes = set_free_with_destructor(m->dhcp6_pd_prefixes, dhcp6_pd_free);
m->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);

View File

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

View File

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

View File

@ -7,6 +7,16 @@
#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,
@ -45,6 +55,15 @@ 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));
}

View File

@ -5,8 +5,6 @@
#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"
@ -35,8 +33,6 @@ 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);
@ -116,9 +112,7 @@ static void request_hash_func(const Request *req, struct siphash *state) {
trivial_hash_func(req->object, state);
break;
case REQUEST_TYPE_DHCP_SERVER:
case REQUEST_TYPE_DHCP4_CLIENT:
case REQUEST_TYPE_DHCP6_CLIENT:
/* These types do not have an object. */
/* This type does not have an object. */
break;
case REQUEST_TYPE_IPV6_PROXY_NDP:
in6_addr_hash_func(req->ipv6_proxy_ndp, state);
@ -176,8 +170,6 @@ static int request_compare_func(const struct Request *a, const struct Request *b
case REQUEST_TYPE_CREATE_STACKED_NETDEV:
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);
@ -226,16 +218,12 @@ 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);
@ -312,12 +300,6 @@ 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;

View File

@ -28,8 +28,6 @@ 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,

View File

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

View File

@ -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_PACKET_DO(q->request_packet)) && dns_query_fully_authenticated(q),
DNS_PACKET_AD(q->request_packet) && dns_query_fully_authenticated(q),
DNS_PACKET_CD(q->request_packet),
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) || DNS_PACKET_DO(p)) && authenticated,
DNS_PACKET_AD(p) && authenticated,
DNS_PACKET_CD(p),
l ? ADVERTISE_EXTRA_DATAGRAM_SIZE_MAX : ADVERTISE_DATAGRAM_SIZE_MAX,
dns_packet_has_nsid_request(p) > 0 && !l);

View File

@ -81,9 +81,6 @@ _SD_BEGIN_DECLARATIONS;
#define SD_MESSAGE_SHUTDOWN SD_ID128_MAKE(98,26,88,66,d1,d5,4a,49,9c,4e,98,92,1d,93,bc,40)
#define SD_MESSAGE_SHUTDOWN_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. */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -77,13 +77,10 @@ static usec_t arg_event_timeout_usec = 180 * USEC_PER_SEC;
static int arg_timeout_signal = SIGKILL;
static bool arg_blockdev_read_only = false;
typedef struct Event Event;
typedef struct Worker Worker;
typedef struct Manager {
sd_event *event;
Hashmap *workers;
LIST_HEAD(Event, events);
LIST_HEAD(struct event, events);
const char *cgroup;
pid_t pid; /* the process that originally allocated the manager object */
int log_level;
@ -94,7 +91,7 @@ typedef struct Manager {
sd_netlink *rtnl;
sd_device_monitor *monitor;
UdevCtrl *ctrl;
struct udev_ctrl *ctrl;
int worker_watch[2];
/* used by udev-watch */
@ -109,52 +106,54 @@ typedef struct Manager {
bool exit;
} Manager;
typedef enum EventState {
enum event_state {
EVENT_UNDEF,
EVENT_QUEUED,
EVENT_RUNNING,
} EventState;
};
typedef struct Event {
struct event {
Manager *manager;
Worker *worker;
EventState state;
struct worker *worker;
enum event_state state;
sd_device *dev;
sd_device *dev_kernel; /* clone of originally received device */
uint64_t seqnum;
uint64_t blocker_seqnum;
uint64_t delaying_seqnum;
sd_event_source *timeout_warning_event;
sd_event_source *timeout_event;
LIST_FIELDS(Event, event);
} Event;
LIST_FIELDS(struct event, event);
};
typedef enum WorkerState {
static void event_queue_cleanup(Manager *manager, enum event_state type);
enum worker_state {
WORKER_UNDEF,
WORKER_RUNNING,
WORKER_IDLE,
WORKER_KILLED,
WORKER_KILLING,
} WorkerState;
};
typedef struct Worker {
struct worker {
Manager *manager;
pid_t pid;
sd_device_monitor *monitor;
WorkerState state;
Event *event;
} Worker;
enum worker_state state;
struct event *event;
};
/* passed from worker to main process */
typedef struct WorkerMessage {
} WorkerMessage;
struct worker_message {
};
static Event *event_free(Event *event) {
static void event_free(struct event *event) {
if (!event)
return NULL;
return;
assert(event->manager);
@ -171,24 +170,13 @@ static Event *event_free(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 && errno != ENOENT)
log_warning_errno(errno, "Failed to unlink /run/udev/queue, ignoring: %m");
if (unlink("/run/udev/queue") < 0)
log_warning_errno(errno, "Failed to unlink /run/udev/queue: %m");
return mfree(event);
free(event);
}
static void event_queue_cleanup(Manager *manager, EventState match_state) {
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) {
static struct worker* worker_free(struct worker *worker) {
if (!worker)
return NULL;
@ -201,8 +189,89 @@ static Worker *worker_free(Worker *worker) {
return mfree(worker);
}
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);
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);
}
static void manager_clear_for_worker(Manager *manager) {
assert(manager);
@ -245,109 +314,8 @@ 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) {
WorkerMessage message = {};
struct worker_message message = {};
return loop_write(fd, &message, sizeof(message), false);
}
@ -623,59 +591,9 @@ static int worker_main(Manager *_manager, sd_device_monitor *monitor, sd_device
return 0;
}
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) {
static int worker_spawn(Manager *manager, struct event *event) {
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *worker_monitor = NULL;
Worker *worker;
struct worker *worker;
pid_t pid;
int r;
@ -717,18 +635,16 @@ static int worker_spawn(Manager *manager, Event *event) {
return 0;
}
static int event_run(Event *event) {
static void event_run(Manager *manager, struct event *event) {
static bool log_children_max_reached = true;
Manager *manager;
Worker *worker;
struct 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;
@ -742,73 +658,110 @@ static int event_run(Event *event) {
continue;
}
worker_attach_event(worker, event);
return 1; /* event is now processing. */
return;
}
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 0; /* no free worker */
return;
}
/* 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 */
r = worker_spawn(manager, event);
worker_spawn(manager, event);
}
static int event_queue_insert(Manager *manager, sd_device *dev) {
_cleanup_(sd_device_unrefp) sd_device *clone = NULL;
struct event *event;
uint64_t seqnum;
int r;
assert(manager);
assert(dev);
/* only one process can add events to the queue */
assert(manager->pid == getpid_cached());
/* We only accepts devices received by device monitor. */
r = sd_device_get_seqnum(dev, &seqnum);
if (r < 0)
return r;
return 1; /* event is now processing. */
/* Save original device to restore the state on failures. */
r = device_shallow_clone(dev, &clone);
if (r < 0)
return r;
r = device_copy_properties(clone, dev);
if (r < 0)
return r;
event = new(struct event, 1);
if (!event)
return -ENOMEM;
*event = (struct event) {
.manager = manager,
.dev = sd_device_ref(dev),
.dev_kernel = TAKE_PTR(clone),
.seqnum = seqnum,
.state = EVENT_QUEUED,
};
if (LIST_IS_EMPTY(manager->events)) {
r = touch("/run/udev/queue");
if (r < 0)
log_warning_errno(r, "Failed to touch /run/udev/queue: %m");
}
LIST_APPEND(event, manager->events, event);
log_device_uevent(dev, "Device is queued");
return 0;
}
static int event_is_blocked(Event *event) {
static void manager_kill_workers(Manager *manager, bool force) {
struct worker *worker;
assert(manager);
HASHMAP_FOREACH(worker, manager->workers) {
if (worker->state == WORKER_KILLED)
continue;
if (worker->state == WORKER_RUNNING && !force) {
worker->state = WORKER_KILLING;
continue;
}
worker->state = WORKER_KILLED;
(void) kill(worker->pid, SIGTERM);
}
}
/* lookup event for identical, parent, child device */
static int is_device_busy(Manager *manager, struct event *event) {
const char *subsystem, *devpath, *devpath_old = NULL;
dev_t devnum = makedev(0, 0);
Event *loop_event;
struct 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;
@ -834,13 +787,21 @@ static int event_is_blocked(Event *event) {
return r;
/* check if queue contains events we depend on */
LIST_FOREACH(event, loop_event, loop_event) {
LIST_FOREACH(event, loop_event, manager->events) {
size_t loop_devpath_len, common;
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)
goto no_blocker;
break;
/* check major/minor */
if (major(devnum) != 0) {
@ -852,7 +813,7 @@ static int event_is_blocked(Event *event) {
if (sd_device_get_devnum(loop_event->dev, &d) >= 0 &&
devnum == d && is_block == streq(s, "block"))
break;
goto set_delaying_seqnum;
}
/* check network device ifindex */
@ -861,7 +822,7 @@ static int event_is_blocked(Event *event) {
if (sd_device_get_ifindex(loop_event->dev, &i) >= 0 &&
ifindex == i)
break;
goto set_delaying_seqnum;
}
if (sd_device_get_devpath(loop_event->dev, &loop_devpath) < 0)
@ -869,7 +830,7 @@ static int event_is_blocked(Event *event) {
/* check our old name */
if (devpath_old && streq(devpath_old, loop_devpath))
break;
goto set_delaying_seqnum;
loop_devpath_len = strlen(loop_devpath);
@ -882,32 +843,80 @@ static int event_is_blocked(Event *event) {
/* identical device event found */
if (devpath_len == loop_devpath_len)
break;
goto set_delaying_seqnum;
/* parent device event found */
if (devpath[common] == '/')
break;
goto set_delaying_seqnum;
/* child device event found */
if (loop_devpath[common] == '/')
break;
goto set_delaying_seqnum;
}
assert(loop_event);
return false;
set_delaying_seqnum:
log_device_debug(event->dev, "SEQNUM=%" PRIu64 " blocked by SEQNUM=%" PRIu64,
event->seqnum, loop_event->seqnum);
event->blocker_seqnum = loop_event->seqnum;
event->delaying_seqnum = loop_event->seqnum;
return true;
no_blocker:
event->blocker_seqnum = event->seqnum;
return false;
}
static int event_queue_start(Manager *manager) {
Event *event, *event_next;
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;
usec_t usec;
int r;
@ -915,12 +924,12 @@ static int event_queue_start(Manager *manager) {
if (LIST_IS_EMPTY(manager->events) ||
manager->exit || manager->stop_exec_queue)
return 0;
return;
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 > usec_add(manager->last_usec, 3 * USEC_PER_SEC)) {
usec - manager->last_usec > 3 * USEC_PER_SEC) {
if (udev_rules_check_timestamp(manager->rules) ||
udev_builtin_validate())
manager_reload(manager);
@ -936,111 +945,33 @@ static int event_queue_start(Manager *manager) {
if (!manager->rules) {
r = udev_rules_load(&manager->rules, arg_resolve_name_timing);
if (r < 0)
return log_warning_errno(r, "Failed to read udev rules: %m");
if (r < 0) {
log_warning_errno(r, "Failed to read udev rules: %m");
return;
}
}
LIST_FOREACH_SAFE(event, event, event_next, manager->events) {
LIST_FOREACH(event, event, manager->events) {
if (event->state != EVENT_QUEUED)
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;
(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)
/* do not start event if parent or child event is still running */
if (is_device_busy(manager, event) != 0)
continue;
r = event_run(event);
if (r <= 0)
return r;
event_run(manager, event);
}
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;
static void event_queue_cleanup(Manager *manager, enum event_state match_type) {
struct event *event, *tmp;
assert(manager);
assert(dev);
LIST_FOREACH_SAFE(event, event, tmp, manager->events) {
if (match_type != EVENT_UNDEF && match_type != event->state)
continue;
/* 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");
event_free(event);
}
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) {
@ -1049,7 +980,7 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
assert(manager);
for (;;) {
WorkerMessage msg;
struct worker_message msg;
struct iovec iovec = {
.iov_base = &msg,
.iov_len = sizeof(msg),
@ -1063,7 +994,7 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
};
ssize_t size;
struct ucred *ucred;
Worker *worker;
struct worker *worker;
size = recvmsg_safe(fd, &msghdr, MSG_DONTWAIT);
if (size == -EINTR)
@ -1076,7 +1007,7 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
cmsg_close_all(&msghdr);
if (size != sizeof(WorkerMessage)) {
if (size != sizeof(struct worker_message)) {
log_warning("Ignoring worker message with invalid size %zi bytes", size);
continue;
}
@ -1110,8 +1041,30 @@ 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(UdevCtrl *uctrl, UdevCtrlMessageType type, const UdevCtrlMessageValue *value, void *userdata) {
static int on_ctrl_msg(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, const union udev_ctrl_msg_value *value, void *userdata) {
Manager *manager = userdata;
int r;
@ -1404,7 +1357,7 @@ static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, voi
for (;;) {
pid_t pid;
int status;
Worker *worker;
struct worker *worker;
pid = waitpid(-1, &status, WNOHANG);
if (pid <= 0)

View File

@ -674,9 +674,9 @@ class NetworkctlTests(unittest.TestCase, Utilities):
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)
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')
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,30 +687,9 @@ class NetworkctlTests(unittest.TestCase, Utilities):
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)
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)
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')
def test_reload(self):
start_networkd(3)

View File

@ -4,13 +4,4 @@ Description=TEST-10-ISSUE-2467
[Service]
ExecStartPre=rm -f /failed /testok
Type=oneshot
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'
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'

View File

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

View File

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