mirror of
https://github.com/systemd/systemd
synced 2026-03-25 08:14:54 +01:00
Compare commits
37 Commits
63c00743f4
...
836fb00f21
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
836fb00f21 | ||
|
|
b553abd8ae | ||
|
|
d84f316cce | ||
|
|
9a6549f6f8 | ||
|
|
b2efed520b | ||
|
|
a7a04de0ec | ||
|
|
76b34df91f | ||
|
|
8fd9920273 | ||
|
|
5e739f7eed | ||
|
|
c6f78234d1 | ||
|
|
044ac33c35 | ||
|
|
bd335c961f | ||
|
|
a1fa99d841 | ||
|
|
5f4bca9dcc | ||
|
|
f2a5412bf2 | ||
|
|
92fd70addf | ||
|
|
0744e74c52 | ||
|
|
5393c52897 | ||
|
|
6be97d67c8 | ||
|
|
419ec63135 | ||
|
|
e0d61dac33 | ||
|
|
d9239923c1 | ||
|
|
4c2c2a1256 | ||
|
|
ae48d2d142 | ||
|
|
f784681a3e | ||
|
|
b378b150b7 | ||
|
|
8716018664 | ||
|
|
ccffa166d8 | ||
|
|
6211b7362a | ||
|
|
bc8bd68db8 | ||
|
|
5aebe9c898 | ||
|
|
3bad5487e9 | ||
|
|
cb71e9c606 | ||
|
|
5e3bb5da98 | ||
|
|
6bfa06fc39 | ||
|
|
f85499108f | ||
|
|
d09a179e69 |
9
TODO
9
TODO
@ -83,6 +83,15 @@ Janitorial Clean-ups:
|
|||||||
|
|
||||||
Features:
|
Features:
|
||||||
|
|
||||||
|
* tpm2: figure out if we need to do anything for TPM2 parameter encryption? And
|
||||||
|
if so, what precisely?
|
||||||
|
|
||||||
|
* insert pkcs7 signature for verity gpt
|
||||||
|
|
||||||
|
* when mounting disk images: if IMAGE_ID/IMAGE_VERSION is set in os-release
|
||||||
|
data in the image, make sure the image filename actually matches this, so
|
||||||
|
that images cannot be misused.
|
||||||
|
|
||||||
* use credentials logic/TPM2 logic to store homed signing key
|
* use credentials logic/TPM2 logic to store homed signing key
|
||||||
|
|
||||||
* New udev block device symlink names:
|
* New udev block device symlink names:
|
||||||
|
|||||||
@ -188,6 +188,15 @@ Support: %SUPPORT_URL%
|
|||||||
System shutdown has been initiated. The shutdown has now begun and
|
System shutdown has been initiated. The shutdown has now begun and
|
||||||
all system services are terminated and all file systems unmounted.
|
all system services are terminated and all file systems unmounted.
|
||||||
|
|
||||||
|
-- c14aaf76ec284a5fa1f105f88dfb061c
|
||||||
|
Subject: System factory reset initiated
|
||||||
|
Defined-By: systemd
|
||||||
|
Support: %SUPPORT_URL%
|
||||||
|
|
||||||
|
System factory reset has been initiated. The precise operation this
|
||||||
|
executes is implementation-defined, but typically has the effect of
|
||||||
|
reverting the system's state and configuration to vendor defaults.
|
||||||
|
|
||||||
-- 7d4958e842da4a758f6c1cdc7b36dcc5
|
-- 7d4958e842da4a758f6c1cdc7b36dcc5
|
||||||
Subject: A start job for unit @UNIT@ has begun execution
|
Subject: A start job for unit @UNIT@ has begun execution
|
||||||
Defined-By: systemd
|
Defined-By: systemd
|
||||||
|
|||||||
@ -216,8 +216,9 @@
|
|||||||
<literal>suspend</literal>,
|
<literal>suspend</literal>,
|
||||||
<literal>hibernate</literal>,
|
<literal>hibernate</literal>,
|
||||||
<literal>hybrid-sleep</literal>,
|
<literal>hybrid-sleep</literal>,
|
||||||
<literal>suspend-then-hibernate</literal>, and
|
<literal>suspend-then-hibernate</literal>,
|
||||||
<literal>lock</literal>.
|
<literal>lock</literal>, and
|
||||||
|
<literal>factory-reset</literal>.
|
||||||
If <literal>ignore</literal>, logind will never handle these
|
If <literal>ignore</literal>, logind will never handle these
|
||||||
keys. If <literal>lock</literal>, all running sessions will be
|
keys. If <literal>lock</literal>, all running sessions will be
|
||||||
screen-locked; otherwise, the specified action will be taken
|
screen-locked; otherwise, the specified action will be taken
|
||||||
|
|||||||
@ -33,6 +33,7 @@
|
|||||||
<filename>default.target</filename>,
|
<filename>default.target</filename>,
|
||||||
<filename>emergency.target</filename>,
|
<filename>emergency.target</filename>,
|
||||||
<filename>exit.target</filename>,
|
<filename>exit.target</filename>,
|
||||||
|
<filename>factory-reset.target</filename>,
|
||||||
<filename>final.target</filename>,
|
<filename>final.target</filename>,
|
||||||
<filename>first-boot-complete.target</filename>,
|
<filename>first-boot-complete.target</filename>,
|
||||||
<filename>getty.target</filename>,
|
<filename>getty.target</filename>,
|
||||||
@ -279,6 +280,12 @@
|
|||||||
shutdown when the service manager starts to exit.</para>
|
shutdown when the service manager starts to exit.</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term><filename>factory-reset.target</filename></term>
|
||||||
|
<listitem>
|
||||||
|
<para>A special target to trigger a factory reset.</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><filename>final.target</filename></term>
|
<term><filename>final.target</filename></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
|
|||||||
@ -142,11 +142,8 @@
|
|||||||
#define LIST_FOREACH_SAFE(name,i,n,head) \
|
#define LIST_FOREACH_SAFE(name,i,n,head) \
|
||||||
for ((i) = (head); (i) && (((n) = (i)->name##_next), 1); (i) = (n))
|
for ((i) = (head); (i) && (((n) = (i)->name##_next), 1); (i) = (n))
|
||||||
|
|
||||||
#define LIST_FOREACH_BEFORE(name,i,p) \
|
#define LIST_FOREACH_BACKWARDS(name,i,p) \
|
||||||
for ((i) = (p)->name##_prev; (i); (i) = (i)->name##_prev)
|
for ((i) = (p); (i); (i) = (i)->name##_prev)
|
||||||
|
|
||||||
#define LIST_FOREACH_AFTER(name,i,p) \
|
|
||||||
for ((i) = (p)->name##_next; (i); (i) = (i)->name##_next)
|
|
||||||
|
|
||||||
/* Iterate through all the members of the list p is included in, but skip over p */
|
/* Iterate through all the members of the list p is included in, but skip over p */
|
||||||
#define LIST_FOREACH_OTHERS(name,i,p) \
|
#define LIST_FOREACH_OTHERS(name,i,p) \
|
||||||
|
|||||||
@ -20,6 +20,7 @@
|
|||||||
#define SPECIAL_HIBERNATE_TARGET "hibernate.target"
|
#define SPECIAL_HIBERNATE_TARGET "hibernate.target"
|
||||||
#define SPECIAL_HYBRID_SLEEP_TARGET "hybrid-sleep.target"
|
#define SPECIAL_HYBRID_SLEEP_TARGET "hybrid-sleep.target"
|
||||||
#define SPECIAL_SUSPEND_THEN_HIBERNATE_TARGET "suspend-then-hibernate.target"
|
#define SPECIAL_SUSPEND_THEN_HIBERNATE_TARGET "suspend-then-hibernate.target"
|
||||||
|
#define SPECIAL_FACTORY_RESET_TARGET "factory-reset.target"
|
||||||
|
|
||||||
/* Special boot targets */
|
/* Special boot targets */
|
||||||
#define SPECIAL_RESCUE_TARGET "rescue.target"
|
#define SPECIAL_RESCUE_TARGET "rescue.target"
|
||||||
|
|||||||
@ -771,11 +771,11 @@ static Unit *device_following(Unit *u) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* Make everybody follow the unit that's named after the sysfs path */
|
/* Make everybody follow the unit that's named after the sysfs path */
|
||||||
LIST_FOREACH_AFTER(same_sysfs, other, d)
|
LIST_FOREACH(same_sysfs, other, d->same_sysfs_next)
|
||||||
if (startswith(UNIT(other)->id, "sys-"))
|
if (startswith(UNIT(other)->id, "sys-"))
|
||||||
return UNIT(other);
|
return UNIT(other);
|
||||||
|
|
||||||
LIST_FOREACH_BEFORE(same_sysfs, other, d) {
|
LIST_FOREACH_BACKWARDS(same_sysfs, other, d->same_sysfs_prev) {
|
||||||
if (startswith(UNIT(other)->id, "sys-"))
|
if (startswith(UNIT(other)->id, "sys-"))
|
||||||
return UNIT(other);
|
return UNIT(other);
|
||||||
|
|
||||||
@ -802,13 +802,13 @@ static int device_following_set(Unit *u, Set **_set) {
|
|||||||
if (!set)
|
if (!set)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
LIST_FOREACH_AFTER(same_sysfs, other, d) {
|
LIST_FOREACH(same_sysfs, other, d->same_sysfs_next) {
|
||||||
r = set_put(set, other);
|
r = set_put(set, other);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
LIST_FOREACH_BEFORE(same_sysfs, other, d) {
|
LIST_FOREACH_BACKWARDS(same_sysfs, other, d->same_sysfs_prev) {
|
||||||
r = set_put(set, other);
|
r = set_put(set, other);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|||||||
@ -1323,11 +1323,11 @@ static Unit *swap_following(Unit *u) {
|
|||||||
if (streq_ptr(s->what, s->devnode))
|
if (streq_ptr(s->what, s->devnode))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
LIST_FOREACH_AFTER(same_devnode, other, s)
|
LIST_FOREACH(same_devnode, other, s->same_devnode_next)
|
||||||
if (streq_ptr(other->what, other->devnode))
|
if (streq_ptr(other->what, other->devnode))
|
||||||
return UNIT(other);
|
return UNIT(other);
|
||||||
|
|
||||||
LIST_FOREACH_BEFORE(same_devnode, other, s) {
|
LIST_FOREACH_BACKWARDS(same_devnode, other, s->same_devnode_prev) {
|
||||||
if (streq_ptr(other->what, other->devnode))
|
if (streq_ptr(other->what, other->devnode))
|
||||||
return UNIT(other);
|
return UNIT(other);
|
||||||
|
|
||||||
|
|||||||
@ -451,6 +451,10 @@ static int add_mount(
|
|||||||
"\n"
|
"\n"
|
||||||
"[Mount]\n");
|
"[Mount]\n");
|
||||||
|
|
||||||
|
r = write_what(f, what);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
if (original_where)
|
if (original_where)
|
||||||
fprintf(f, "# Canonicalized from %s\n", original_where);
|
fprintf(f, "# Canonicalized from %s\n", original_where);
|
||||||
|
|
||||||
@ -459,10 +463,6 @@ static int add_mount(
|
|||||||
return log_oom();
|
return log_oom();
|
||||||
fprintf(f, "Where=%s\n", where_escaped);
|
fprintf(f, "Where=%s\n", where_escaped);
|
||||||
|
|
||||||
r = write_what(f, what);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
if (!isempty(fstype) && !streq(fstype, "auto")) {
|
if (!isempty(fstype) && !streq(fstype, "auto")) {
|
||||||
_cleanup_free_ char *t = NULL;
|
_cleanup_free_ char *t = NULL;
|
||||||
|
|
||||||
|
|||||||
@ -27,6 +27,7 @@ const char* manager_target_for_action(HandleAction handle) {
|
|||||||
[HANDLE_HIBERNATE] = SPECIAL_HIBERNATE_TARGET,
|
[HANDLE_HIBERNATE] = SPECIAL_HIBERNATE_TARGET,
|
||||||
[HANDLE_HYBRID_SLEEP] = SPECIAL_HYBRID_SLEEP_TARGET,
|
[HANDLE_HYBRID_SLEEP] = SPECIAL_HYBRID_SLEEP_TARGET,
|
||||||
[HANDLE_SUSPEND_THEN_HIBERNATE] = SPECIAL_SUSPEND_THEN_HIBERNATE_TARGET,
|
[HANDLE_SUSPEND_THEN_HIBERNATE] = SPECIAL_SUSPEND_THEN_HIBERNATE_TARGET,
|
||||||
|
[HANDLE_FACTORY_RESET] = SPECIAL_FACTORY_RESET_TARGET,
|
||||||
};
|
};
|
||||||
|
|
||||||
assert(handle >= 0);
|
assert(handle >= 0);
|
||||||
@ -51,6 +52,7 @@ int manager_handle_action(
|
|||||||
[HANDLE_HIBERNATE] = "Hibernating...",
|
[HANDLE_HIBERNATE] = "Hibernating...",
|
||||||
[HANDLE_HYBRID_SLEEP] = "Hibernating and suspending...",
|
[HANDLE_HYBRID_SLEEP] = "Hibernating and suspending...",
|
||||||
[HANDLE_SUSPEND_THEN_HIBERNATE] = "Suspending, then hibernating...",
|
[HANDLE_SUSPEND_THEN_HIBERNATE] = "Suspending, then hibernating...",
|
||||||
|
[HANDLE_FACTORY_RESET] = "Performing factory reset...",
|
||||||
};
|
};
|
||||||
|
|
||||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||||
@ -179,6 +181,7 @@ static const char* const handle_action_table[_HANDLE_ACTION_MAX] = {
|
|||||||
[HANDLE_HIBERNATE] = "hibernate",
|
[HANDLE_HIBERNATE] = "hibernate",
|
||||||
[HANDLE_HYBRID_SLEEP] = "hybrid-sleep",
|
[HANDLE_HYBRID_SLEEP] = "hybrid-sleep",
|
||||||
[HANDLE_SUSPEND_THEN_HIBERNATE] = "suspend-then-hibernate",
|
[HANDLE_SUSPEND_THEN_HIBERNATE] = "suspend-then-hibernate",
|
||||||
|
[HANDLE_FACTORY_RESET] = "factory-reset",
|
||||||
[HANDLE_LOCK] = "lock",
|
[HANDLE_LOCK] = "lock",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -14,6 +14,7 @@ typedef enum HandleAction {
|
|||||||
HANDLE_HYBRID_SLEEP,
|
HANDLE_HYBRID_SLEEP,
|
||||||
HANDLE_SUSPEND_THEN_HIBERNATE,
|
HANDLE_SUSPEND_THEN_HIBERNATE,
|
||||||
HANDLE_LOCK,
|
HANDLE_LOCK,
|
||||||
|
HANDLE_FACTORY_RESET,
|
||||||
_HANDLE_ACTION_MAX,
|
_HANDLE_ACTION_MAX,
|
||||||
_HANDLE_ACTION_INVALID = -EINVAL,
|
_HANDLE_ACTION_INVALID = -EINVAL,
|
||||||
} HandleAction;
|
} HandleAction;
|
||||||
|
|||||||
@ -1491,41 +1491,59 @@ static int have_multiple_sessions(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bus_manager_log_shutdown(
|
_printf_(2, 0)
|
||||||
Manager *m,
|
static int log_with_wall_message(Manager *m, const char *d, const char *p, const char *q) {
|
||||||
const char *unit_name) {
|
|
||||||
|
|
||||||
const char *p, *q;
|
|
||||||
|
|
||||||
assert(m);
|
assert(m);
|
||||||
assert(unit_name);
|
|
||||||
|
|
||||||
if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
|
|
||||||
p = "MESSAGE=System is powering down";
|
|
||||||
q = "SHUTDOWN=power-off";
|
|
||||||
} else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
|
|
||||||
p = "MESSAGE=System is rebooting";
|
|
||||||
q = "SHUTDOWN=reboot";
|
|
||||||
} else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
|
|
||||||
p = "MESSAGE=System is halting";
|
|
||||||
q = "SHUTDOWN=halt";
|
|
||||||
} else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
|
|
||||||
p = "MESSAGE=System is rebooting with kexec";
|
|
||||||
q = "SHUTDOWN=kexec";
|
|
||||||
} else {
|
|
||||||
p = "MESSAGE=System is shutting down";
|
|
||||||
q = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isempty(m->wall_message))
|
if (isempty(m->wall_message))
|
||||||
p = strjoina(p, ".");
|
p = strjoina(p, ".");
|
||||||
else
|
else
|
||||||
p = strjoina(p, " (", m->wall_message, ").");
|
p = strjoina(p, " (", m->wall_message, ").");
|
||||||
|
|
||||||
return log_struct(LOG_NOTICE,
|
return log_struct(LOG_NOTICE, d, p, q);
|
||||||
"MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_STR,
|
}
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lid_switch_ignore_handler(sd_event_source *e, uint64_t usec, void *userdata) {
|
static int lid_switch_ignore_handler(sd_event_source *e, uint64_t usec, void *userdata) {
|
||||||
|
|||||||
@ -96,113 +96,64 @@ const DUID *link_get_duid(Link *link, int family) {
|
|||||||
return duid;
|
return duid;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int link_configure_and_start_dhcp_delayed(Link *link) {
|
|
||||||
int r;
|
|
||||||
|
|
||||||
assert(link);
|
|
||||||
|
|
||||||
if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!link->dhcp_client) {
|
|
||||||
r = dhcp4_configure(link);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!link->dhcp6_client) {
|
|
||||||
r = dhcp6_configure(link);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (link->set_flags_messages > 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!link_has_carrier(link))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
r = dhcp4_start(link);
|
|
||||||
if (r < 0)
|
|
||||||
return log_link_warning_errno(link, r, "Failed to start DHCPv4 client: %m");
|
|
||||||
|
|
||||||
r = ndisc_start(link);
|
|
||||||
if (r < 0)
|
|
||||||
return log_link_warning_errno(link, r, "Failed to start IPv6 Router Discovery: %m");
|
|
||||||
|
|
||||||
r = dhcp6_start(link);
|
|
||||||
if (r < 0)
|
|
||||||
return log_link_warning_errno(link, r, "Failed to start DHCPv6 client: %m");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int get_product_uuid_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
|
static int get_product_uuid_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
|
||||||
Manager *manager = userdata;
|
Manager *manager = userdata;
|
||||||
const sd_bus_error *e;
|
const sd_bus_error *e;
|
||||||
const void *a;
|
const void *a;
|
||||||
size_t sz;
|
size_t sz;
|
||||||
Link *link;
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(m);
|
assert(m);
|
||||||
assert(manager);
|
assert(manager);
|
||||||
|
|
||||||
|
/* To avoid calling GetProductUUID() bus method so frequently, set the flag below
|
||||||
|
* even if the method fails. */
|
||||||
|
manager->has_product_uuid = true;
|
||||||
|
|
||||||
e = sd_bus_message_get_error(m);
|
e = sd_bus_message_get_error(m);
|
||||||
if (e) {
|
if (e) {
|
||||||
r = sd_bus_error_get_errno(e);
|
r = sd_bus_error_get_errno(e);
|
||||||
log_warning_errno(r, "Could not get product UUID. Falling back to use machine-app-specific ID as DUID-UUID: %s",
|
log_warning_errno(r, "Could not get product UUID. Falling back to use machine-app-specific ID as DUID-UUID: %s",
|
||||||
bus_error_message(e, r));
|
bus_error_message(e, r));
|
||||||
goto configure;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = sd_bus_message_read_array(m, 'y', &a, &sz);
|
r = sd_bus_message_read_array(m, 'y', &a, &sz);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_warning_errno(r, "Failed to get product UUID. Falling back to use machine-app-specific ID as DUID-UUID: %m");
|
log_warning_errno(r, "Failed to get product UUID. Falling back to use machine-app-specific ID as DUID-UUID: %m");
|
||||||
goto configure;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sz != sizeof(sd_id128_t)) {
|
if (sz != sizeof(sd_id128_t)) {
|
||||||
log_warning("Invalid product UUID. Falling back to use machine-app-specific ID as DUID-UUID.");
|
log_warning("Invalid product UUID. Falling back to use machine-app-specific ID as DUID-UUID.");
|
||||||
goto configure;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log_debug("Successfully obtained product UUID");
|
||||||
|
|
||||||
memcpy(&manager->duid_product_uuid.raw_data, a, sz);
|
memcpy(&manager->duid_product_uuid.raw_data, a, sz);
|
||||||
manager->duid_product_uuid.raw_data_len = sz;
|
manager->duid_product_uuid.raw_data_len = sz;
|
||||||
|
|
||||||
configure:
|
return 0;
|
||||||
/* To avoid calling GetProductUUID() bus method so frequently, set the flag below
|
|
||||||
* even if the method fails. */
|
|
||||||
manager->has_product_uuid = true;
|
|
||||||
|
|
||||||
while ((link = set_steal_first(manager->links_requesting_uuid))) {
|
|
||||||
r = link_configure_and_start_dhcp_delayed(link);
|
|
||||||
if (r < 0)
|
|
||||||
link_enter_failed(link);
|
|
||||||
|
|
||||||
link_unref(link);
|
|
||||||
}
|
|
||||||
|
|
||||||
manager->links_requesting_uuid = set_free(manager->links_requesting_uuid);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int manager_request_product_uuid(Manager *m) {
|
int manager_request_product_uuid(Manager *m) {
|
||||||
|
static bool bus_method_is_called = false;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(m);
|
assert(m);
|
||||||
|
|
||||||
if (m->product_uuid_requested)
|
if (bus_method_is_called)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
log_debug("Requesting product UUID");
|
if (sd_bus_is_ready(m->bus) <= 0 && !m->product_uuid_requested) {
|
||||||
|
|
||||||
if (sd_bus_is_ready(m->bus) <= 0) {
|
|
||||||
log_debug("Not connected to system bus, requesting product UUID later.");
|
log_debug("Not connected to system bus, requesting product UUID later.");
|
||||||
|
m->product_uuid_requested = true;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m->product_uuid_requested = false;
|
||||||
|
|
||||||
r = sd_bus_call_method_async(
|
r = sd_bus_call_method_async(
|
||||||
m->bus,
|
m->bus,
|
||||||
NULL,
|
NULL,
|
||||||
@ -217,7 +168,9 @@ int manager_request_product_uuid(Manager *m) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_warning_errno(r, "Failed to get product UUID: %m");
|
return log_warning_errno(r, "Failed to get product UUID: %m");
|
||||||
|
|
||||||
m->product_uuid_requested = true;
|
log_debug("Requesting product UUID.");
|
||||||
|
|
||||||
|
bus_method_is_called = true;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -242,15 +195,11 @@ int dhcp_configure_duid(Link *link, const DUID *duid) {
|
|||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_link_warning_errno(link, r,
|
log_link_warning_errno(link, r,
|
||||||
"Failed to get product UUID. Falling back to use machine-app-specific ID as DUID-UUID: %m");
|
"Failed to get product UUID. Falling back to use machine-app-specific ID as DUID-UUID: %m");
|
||||||
|
|
||||||
|
m->has_product_uuid = true; /* Do not request UUID again on failure. */
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = set_ensure_put(&m->links_requesting_uuid, NULL, link);
|
|
||||||
if (r < 0)
|
|
||||||
return log_oom();
|
|
||||||
if (r > 0)
|
|
||||||
link_ref(link);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -543,8 +492,8 @@ int config_parse_iaid(const char *unit,
|
|||||||
network->dhcp_iaid = iaid;
|
network->dhcp_iaid = iaid;
|
||||||
network->dhcp_iaid_set = true;
|
network->dhcp_iaid_set = true;
|
||||||
if (!network->dhcp6_iaid_set_explicitly) {
|
if (!network->dhcp6_iaid_set_explicitly) {
|
||||||
/* Backward compatibility. Previously, IAID is shared by DHCP4 and DHCP6.
|
/* Backward compatibility. Previously, IAID is shared by DHCPv4 and DHCPv6.
|
||||||
* If DHCP6 IAID is not specified explicitly, then use DHCP4 IAID for DHCP6. */
|
* If DHCPv6 IAID is not specified explicitly, then use DHCPv4 IAID for DHCPv6. */
|
||||||
network->dhcp6_iaid = iaid;
|
network->dhcp6_iaid = iaid;
|
||||||
network->dhcp6_iaid_set = true;
|
network->dhcp6_iaid_set = true;
|
||||||
}
|
}
|
||||||
@ -1036,7 +985,7 @@ int config_parse_manager_duid_type(
|
|||||||
|
|
||||||
assert(manager);
|
assert(manager);
|
||||||
|
|
||||||
/* For backward compatibility. Setting both DHCP4 and DHCP6 DUID if they are not specified explicitly. */
|
/* For backward compatibility. Setting both DHCPv4 and DHCPv6 DUID if they are not specified explicitly. */
|
||||||
|
|
||||||
r = config_parse_duid_type(unit, filename, line, section, section_line, lvalue, false, rvalue, &manager->dhcp_duid, manager);
|
r = config_parse_duid_type(unit, filename, line, section, section_line, lvalue, false, rvalue, &manager->dhcp_duid, manager);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -1066,7 +1015,7 @@ int config_parse_network_duid_type(
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
/* For backward compatibility, also set DHCP6 DUID if not specified explicitly. */
|
/* For backward compatibility, also set DHCPv6 DUID if not specified explicitly. */
|
||||||
return config_parse_duid_type(unit, filename, line, section, section_line, lvalue, false, rvalue, &network->dhcp6_duid, network);
|
return config_parse_duid_type(unit, filename, line, section, section_line, lvalue, false, rvalue, &network->dhcp6_duid, network);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1161,7 +1110,7 @@ int config_parse_manager_duid_rawdata(
|
|||||||
|
|
||||||
assert(manager);
|
assert(manager);
|
||||||
|
|
||||||
/* For backward compatibility. Setting both DHCP4 and DHCP6 DUID if they are not specified explicitly. */
|
/* For backward compatibility. Setting both DHCPv4 and DHCPv6 DUID if they are not specified explicitly. */
|
||||||
|
|
||||||
r = config_parse_duid_rawdata(unit, filename, line, section, section_line, lvalue, false, rvalue, &manager->dhcp_duid, manager);
|
r = config_parse_duid_rawdata(unit, filename, line, section, section_line, lvalue, false, rvalue, &manager->dhcp_duid, manager);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -1191,6 +1140,6 @@ int config_parse_network_duid_rawdata(
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
/* For backward compatibility, also set DHCP6 DUID if not specified explicitly. */
|
/* For backward compatibility, also set DHCPv6 DUID if not specified explicitly. */
|
||||||
return config_parse_duid_rawdata(unit, filename, line, section, section_line, lvalue, false, rvalue, &network->dhcp6_duid, network);
|
return config_parse_duid_rawdata(unit, filename, line, section, section_line, lvalue, false, rvalue, &network->dhcp6_duid, network);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1311,7 +1311,7 @@ static int dhcp4_set_hostname(Link *link) {
|
|||||||
else {
|
else {
|
||||||
r = gethostname_strict(&hostname);
|
r = gethostname_strict(&hostname);
|
||||||
if (r < 0 && r != -ENXIO) /* ENXIO: no hostname set or hostname is "localhost" */
|
if (r < 0 && r != -ENXIO) /* ENXIO: no hostname set or hostname is "localhost" */
|
||||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to get hostname: %m");
|
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to get hostname: %m");
|
||||||
|
|
||||||
hn = hostname;
|
hn = hostname;
|
||||||
}
|
}
|
||||||
@ -1319,9 +1319,9 @@ static int dhcp4_set_hostname(Link *link) {
|
|||||||
r = sd_dhcp_client_set_hostname(link->dhcp_client, hn);
|
r = sd_dhcp_client_set_hostname(link->dhcp_client, hn);
|
||||||
if (r == -EINVAL && hostname)
|
if (r == -EINVAL && hostname)
|
||||||
/* Ignore error when the machine's hostname is not suitable to send in DHCP packet. */
|
/* Ignore error when the machine's hostname is not suitable to send in DHCP packet. */
|
||||||
log_link_debug_errno(link, r, "DHCP4 CLIENT: Failed to set hostname from kernel hostname, ignoring: %m");
|
log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set hostname from kernel hostname, ignoring: %m");
|
||||||
else if (r < 0)
|
else if (r < 0)
|
||||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set hostname: %m");
|
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set hostname: %m");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1351,7 +1351,7 @@ static int dhcp4_set_client_identifier(Link *link) {
|
|||||||
duid->raw_data_len > 0 ? duid->raw_data : NULL,
|
duid->raw_data_len > 0 ? duid->raw_data : NULL,
|
||||||
duid->raw_data_len);
|
duid->raw_data_len);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set IAID+DUID: %m");
|
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set IAID+DUID: %m");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DHCP_CLIENT_ID_DUID_ONLY: {
|
case DHCP_CLIENT_ID_DUID_ONLY: {
|
||||||
@ -1367,7 +1367,7 @@ static int dhcp4_set_client_identifier(Link *link) {
|
|||||||
duid->raw_data_len > 0 ? duid->raw_data : NULL,
|
duid->raw_data_len > 0 ? duid->raw_data : NULL,
|
||||||
duid->raw_data_len);
|
duid->raw_data_len);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set DUID: %m");
|
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set DUID: %m");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DHCP_CLIENT_ID_MAC: {
|
case DHCP_CLIENT_ID_MAC: {
|
||||||
@ -1385,7 +1385,7 @@ static int dhcp4_set_client_identifier(Link *link) {
|
|||||||
hw_addr,
|
hw_addr,
|
||||||
hw_addr_len);
|
hw_addr_len);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set client ID: %m");
|
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set client ID: %m");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -1395,15 +1395,6 @@ static int dhcp4_set_client_identifier(Link *link) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dhcp4_configure_duid(Link *link) {
|
|
||||||
assert(link);
|
|
||||||
|
|
||||||
if (!IN_SET(link->network->dhcp_client_identifier, DHCP_CLIENT_ID_DUID, DHCP_CLIENT_ID_DUID_ONLY))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
return dhcp_configure_duid(link, link_get_dhcp4_duid(link));
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dhcp4_set_request_address(Link *link) {
|
static int dhcp4_set_request_address(Link *link) {
|
||||||
Address *a;
|
Address *a;
|
||||||
|
|
||||||
@ -1424,7 +1415,7 @@ static int dhcp4_set_request_address(Link *link) {
|
|||||||
if (!a)
|
if (!a)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
log_link_debug(link, "DHCP4 CLIENT: requesting " IPV4_ADDRESS_FMT_STR, IPV4_ADDRESS_FMT_VAL(a->in_addr.in));
|
log_link_debug(link, "DHCPv4 CLIENT: requesting " IPV4_ADDRESS_FMT_STR, IPV4_ADDRESS_FMT_VAL(a->in_addr.in));
|
||||||
|
|
||||||
return sd_dhcp_client_set_request_address(link->dhcp_client, &a->in_addr.in);
|
return sd_dhcp_client_set_request_address(link->dhcp_client, &a->in_addr.in);
|
||||||
}
|
}
|
||||||
@ -1445,15 +1436,15 @@ static bool link_needs_dhcp_broadcast(Link *link) {
|
|||||||
if (r < 0 && link->sd_device && sd_device_get_property_value(link->sd_device, "ID_NET_DHCP_BROADCAST", &val) >= 0) {
|
if (r < 0 && link->sd_device && sd_device_get_property_value(link->sd_device, "ID_NET_DHCP_BROADCAST", &val) >= 0) {
|
||||||
r = parse_boolean(val);
|
r = parse_boolean(val);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to parse ID_NET_DHCP_BROADCAST, ignoring: %m");
|
log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to parse ID_NET_DHCP_BROADCAST, ignoring: %m");
|
||||||
else
|
else
|
||||||
log_link_debug(link, "DHCP4 CLIENT: Detected ID_NET_DHCP_BROADCAST='%d'.", r);
|
log_link_debug(link, "DHCPv4 CLIENT: Detected ID_NET_DHCP_BROADCAST='%d'.", r);
|
||||||
|
|
||||||
}
|
}
|
||||||
return r == true;
|
return r == true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dhcp4_configure(Link *link) {
|
static int dhcp4_configure(Link *link) {
|
||||||
sd_dhcp_option *send_option;
|
sd_dhcp_option *send_option;
|
||||||
void *request_options;
|
void *request_options;
|
||||||
int r;
|
int r;
|
||||||
@ -1461,88 +1452,81 @@ int dhcp4_configure(Link *link) {
|
|||||||
assert(link);
|
assert(link);
|
||||||
assert(link->network);
|
assert(link->network);
|
||||||
|
|
||||||
if (!link_dhcp4_enabled(link))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (link->dhcp_client)
|
if (link->dhcp_client)
|
||||||
return -EBUSY; /* Already configured. */
|
return log_link_debug_errno(link, SYNTHETIC_ERRNO(EBUSY), "DHCPv4 client is already configured.");
|
||||||
|
|
||||||
r = dhcp4_configure_duid(link);
|
|
||||||
if (r <= 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
r = sd_dhcp_client_new(&link->dhcp_client, link->network->dhcp_anonymize);
|
r = sd_dhcp_client_new(&link->dhcp_client, link->network->dhcp_anonymize);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to allocate DHCP4 client: %m");
|
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to allocate DHCPv4 client: %m");
|
||||||
|
|
||||||
r = sd_dhcp_client_attach_event(link->dhcp_client, link->manager->event, 0);
|
r = sd_dhcp_client_attach_event(link->dhcp_client, link->manager->event, 0);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to attach event to DHCP4 client: %m");
|
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to attach event to DHCPv4 client: %m");
|
||||||
|
|
||||||
r = sd_dhcp_client_set_mac(link->dhcp_client,
|
r = sd_dhcp_client_set_mac(link->dhcp_client,
|
||||||
link->hw_addr.bytes,
|
link->hw_addr.bytes,
|
||||||
link->bcast_addr.length > 0 ? link->bcast_addr.bytes : NULL,
|
link->bcast_addr.length > 0 ? link->bcast_addr.bytes : NULL,
|
||||||
link->hw_addr.length, link->iftype);
|
link->hw_addr.length, link->iftype);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set MAC address: %m");
|
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set MAC address: %m");
|
||||||
|
|
||||||
r = sd_dhcp_client_set_ifindex(link->dhcp_client, link->ifindex);
|
r = sd_dhcp_client_set_ifindex(link->dhcp_client, link->ifindex);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set ifindex: %m");
|
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set ifindex: %m");
|
||||||
|
|
||||||
r = sd_dhcp_client_set_callback(link->dhcp_client, dhcp4_handler, link);
|
r = sd_dhcp_client_set_callback(link->dhcp_client, dhcp4_handler, link);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set callback: %m");
|
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set callback: %m");
|
||||||
|
|
||||||
r = sd_dhcp_client_set_request_broadcast(link->dhcp_client, link_needs_dhcp_broadcast(link));
|
r = sd_dhcp_client_set_request_broadcast(link->dhcp_client, link_needs_dhcp_broadcast(link));
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for broadcast: %m");
|
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for broadcast: %m");
|
||||||
|
|
||||||
if (link->mtu > 0) {
|
if (link->mtu > 0) {
|
||||||
r = sd_dhcp_client_set_mtu(link->dhcp_client, link->mtu);
|
r = sd_dhcp_client_set_mtu(link->dhcp_client, link->mtu);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set MTU: %m");
|
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set MTU: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!link->network->dhcp_anonymize) {
|
if (!link->network->dhcp_anonymize) {
|
||||||
if (link->network->dhcp_use_mtu) {
|
if (link->network->dhcp_use_mtu) {
|
||||||
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_INTERFACE_MTU);
|
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_INTERFACE_MTU);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for MTU: %m");
|
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for MTU: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (link->network->dhcp_use_routes) {
|
if (link->network->dhcp_use_routes) {
|
||||||
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_STATIC_ROUTE);
|
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_STATIC_ROUTE);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for static route: %m");
|
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for static route: %m");
|
||||||
|
|
||||||
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE);
|
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for classless static route: %m");
|
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for classless static route: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) {
|
if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) {
|
||||||
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_DOMAIN_SEARCH_LIST);
|
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_DOMAIN_SEARCH_LIST);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for domain search list: %m");
|
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for domain search list: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (link->network->dhcp_use_ntp) {
|
if (link->network->dhcp_use_ntp) {
|
||||||
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NTP_SERVER);
|
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NTP_SERVER);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for NTP server: %m");
|
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for NTP server: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (link->network->dhcp_use_sip) {
|
if (link->network->dhcp_use_sip) {
|
||||||
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_SIP_SERVER);
|
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_SIP_SERVER);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for SIP server: %m");
|
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for SIP server: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (link->network->dhcp_use_timezone) {
|
if (link->network->dhcp_use_timezone) {
|
||||||
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NEW_TZDB_TIMEZONE);
|
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NEW_TZDB_TIMEZONE);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for timezone: %m");
|
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for timezone: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
SET_FOREACH(request_options, link->network->dhcp_request_options) {
|
SET_FOREACH(request_options, link->network->dhcp_request_options) {
|
||||||
@ -1550,7 +1534,7 @@ int dhcp4_configure(Link *link) {
|
|||||||
|
|
||||||
r = sd_dhcp_client_set_request_option(link->dhcp_client, option);
|
r = sd_dhcp_client_set_request_option(link->dhcp_client, option);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for '%u': %m", option);
|
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for '%u': %m", option);
|
||||||
}
|
}
|
||||||
|
|
||||||
ORDERED_HASHMAP_FOREACH(send_option, link->network->dhcp_client_send_options) {
|
ORDERED_HASHMAP_FOREACH(send_option, link->network->dhcp_client_send_options) {
|
||||||
@ -1558,7 +1542,7 @@ int dhcp4_configure(Link *link) {
|
|||||||
if (r == -EEXIST)
|
if (r == -EEXIST)
|
||||||
continue;
|
continue;
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set send option: %m");
|
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set send option: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
ORDERED_HASHMAP_FOREACH(send_option, link->network->dhcp_client_send_vendor_options) {
|
ORDERED_HASHMAP_FOREACH(send_option, link->network->dhcp_client_send_vendor_options) {
|
||||||
@ -1566,7 +1550,7 @@ int dhcp4_configure(Link *link) {
|
|||||||
if (r == -EEXIST)
|
if (r == -EEXIST)
|
||||||
continue;
|
continue;
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set send option: %m");
|
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set send option: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
r = dhcp4_set_hostname(link);
|
r = dhcp4_set_hostname(link);
|
||||||
@ -1577,49 +1561,49 @@ int dhcp4_configure(Link *link) {
|
|||||||
r = sd_dhcp_client_set_vendor_class_identifier(link->dhcp_client,
|
r = sd_dhcp_client_set_vendor_class_identifier(link->dhcp_client,
|
||||||
link->network->dhcp_vendor_class_identifier);
|
link->network->dhcp_vendor_class_identifier);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set vendor class identifier: %m");
|
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set vendor class identifier: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (link->network->dhcp_mudurl) {
|
if (link->network->dhcp_mudurl) {
|
||||||
r = sd_dhcp_client_set_mud_url(link->dhcp_client, link->network->dhcp_mudurl);
|
r = sd_dhcp_client_set_mud_url(link->dhcp_client, link->network->dhcp_mudurl);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set MUD URL: %m");
|
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set MUD URL: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (link->network->dhcp_user_class) {
|
if (link->network->dhcp_user_class) {
|
||||||
r = sd_dhcp_client_set_user_class(link->dhcp_client, link->network->dhcp_user_class);
|
r = sd_dhcp_client_set_user_class(link->dhcp_client, link->network->dhcp_user_class);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set user class: %m");
|
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set user class: %m");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (link->network->dhcp_client_port > 0) {
|
if (link->network->dhcp_client_port > 0) {
|
||||||
r = sd_dhcp_client_set_client_port(link->dhcp_client, link->network->dhcp_client_port);
|
r = sd_dhcp_client_set_client_port(link->dhcp_client, link->network->dhcp_client_port);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set listen port: %m");
|
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set listen port: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (link->network->dhcp_max_attempts > 0) {
|
if (link->network->dhcp_max_attempts > 0) {
|
||||||
r = sd_dhcp_client_set_max_attempts(link->dhcp_client, link->network->dhcp_max_attempts);
|
r = sd_dhcp_client_set_max_attempts(link->dhcp_client, link->network->dhcp_max_attempts);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set max attempts: %m");
|
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set max attempts: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (link->network->dhcp_ip_service_type > 0) {
|
if (link->network->dhcp_ip_service_type > 0) {
|
||||||
r = sd_dhcp_client_set_service_type(link->dhcp_client, link->network->dhcp_ip_service_type);
|
r = sd_dhcp_client_set_service_type(link->dhcp_client, link->network->dhcp_ip_service_type);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set IP service type: %m");
|
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set IP service type: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (link->network->dhcp_fallback_lease_lifetime > 0) {
|
if (link->network->dhcp_fallback_lease_lifetime > 0) {
|
||||||
r = sd_dhcp_client_set_fallback_lease_lifetime(link->dhcp_client, link->network->dhcp_fallback_lease_lifetime);
|
r = sd_dhcp_client_set_fallback_lease_lifetime(link->dhcp_client, link->network->dhcp_fallback_lease_lifetime);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed set to lease lifetime: %m");
|
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed set to lease lifetime: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
r = dhcp4_set_request_address(link);
|
r = dhcp4_set_request_address(link);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set initial DHCPv4 address: %m");
|
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set initial DHCPv4 address: %m");
|
||||||
|
|
||||||
return dhcp4_set_client_identifier(link);
|
return dhcp4_set_client_identifier(link);
|
||||||
}
|
}
|
||||||
@ -1642,17 +1626,83 @@ int dhcp4_update_mac(Link *link) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int dhcp4_start(Link *link) {
|
int dhcp4_start(Link *link) {
|
||||||
|
int r;
|
||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
|
|
||||||
if (!link->dhcp_client)
|
if (!link->dhcp_client)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (!link_has_carrier(link))
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (sd_dhcp_client_is_running(link->dhcp_client) > 0)
|
if (sd_dhcp_client_is_running(link->dhcp_client) > 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
log_link_debug(link, "Acquiring DHCPv4 lease");
|
r = sd_dhcp_client_start(link->dhcp_client);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
return sd_dhcp_client_start(link->dhcp_client);
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dhcp4_configure_duid(Link *link) {
|
||||||
|
assert(link);
|
||||||
|
|
||||||
|
if (!IN_SET(link->network->dhcp_client_identifier, DHCP_CLIENT_ID_DUID, DHCP_CLIENT_ID_DUID_ONLY))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return dhcp_configure_duid(link, link_get_dhcp4_duid(link));
|
||||||
|
}
|
||||||
|
|
||||||
|
int request_process_dhcp4_client(Request *req) {
|
||||||
|
Link *link;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(req);
|
||||||
|
assert(req->link);
|
||||||
|
assert(req->type == REQUEST_TYPE_DHCP4_CLIENT);
|
||||||
|
|
||||||
|
link = req->link;
|
||||||
|
|
||||||
|
if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
r = dhcp4_configure_duid(link);
|
||||||
|
if (r <= 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = dhcp4_configure(req->link);
|
||||||
|
if (r < 0)
|
||||||
|
return log_link_warning_errno(link, r, "Failed to configure DHCPv4 client: %m");
|
||||||
|
|
||||||
|
r = dhcp4_start(link);
|
||||||
|
if (r < 0)
|
||||||
|
return log_link_warning_errno(link, r, "Failed to start DHCPv4 client: %m");
|
||||||
|
|
||||||
|
log_link_debug(link, "DHCPv4 client is configured%s.",
|
||||||
|
r > 0 ? ", acquiring DHCPv4 lease" : "");
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int link_request_dhcp4_client(Link *link) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(link);
|
||||||
|
|
||||||
|
if (!link_dhcp4_enabled(link))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (link->dhcp_client)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
r = link_queue_request(link, REQUEST_TYPE_DHCP4_CLIENT, NULL, false, NULL, NULL, NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return log_link_warning_errno(link, r, "Failed to request configuring of the DHCPv4 client: %m");
|
||||||
|
|
||||||
|
log_link_debug(link, "Requested configuring of the DHCPv4 client.");
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int config_parse_dhcp_max_attempts(
|
int config_parse_dhcp_max_attempts(
|
||||||
|
|||||||
@ -4,6 +4,8 @@
|
|||||||
#include "conf-parser.h"
|
#include "conf-parser.h"
|
||||||
|
|
||||||
typedef struct Link Link;
|
typedef struct Link Link;
|
||||||
|
typedef struct Network Network;
|
||||||
|
typedef struct Request Request;
|
||||||
|
|
||||||
typedef enum DHCPClientIdentifier {
|
typedef enum DHCPClientIdentifier {
|
||||||
DHCP_CLIENT_ID_MAC,
|
DHCP_CLIENT_ID_MAC,
|
||||||
@ -18,11 +20,13 @@ typedef enum DHCPClientIdentifier {
|
|||||||
} DHCPClientIdentifier;
|
} DHCPClientIdentifier;
|
||||||
|
|
||||||
void network_adjust_dhcp4(Network *network);
|
void network_adjust_dhcp4(Network *network);
|
||||||
int dhcp4_configure(Link *link);
|
|
||||||
int dhcp4_update_mac(Link *link);
|
int dhcp4_update_mac(Link *link);
|
||||||
int dhcp4_start(Link *link);
|
int dhcp4_start(Link *link);
|
||||||
int dhcp4_lease_lost(Link *link);
|
int dhcp4_lease_lost(Link *link);
|
||||||
|
|
||||||
|
int request_process_dhcp4_client(Request *req);
|
||||||
|
int link_request_dhcp4_client(Link *link);
|
||||||
|
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_client_identifier);
|
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_client_identifier);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_acl_ip_address);
|
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_acl_ip_address);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_max_attempts);
|
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_max_attempts);
|
||||||
|
|||||||
@ -920,7 +920,7 @@ static int dhcp6_pd_prefix_add(Link *link, const struct in6_addr *prefix, uint8_
|
|||||||
log_link_full(link,
|
log_link_full(link,
|
||||||
set_contains(link->dhcp6_pd_prefixes, p) ? LOG_DEBUG :
|
set_contains(link->dhcp6_pd_prefixes, p) ? LOG_DEBUG :
|
||||||
prefixlen > 64 || prefixlen < 48 ? LOG_WARNING : LOG_INFO,
|
prefixlen > 64 || prefixlen < 48 ? LOG_WARNING : LOG_INFO,
|
||||||
"DHCP6: received PD Prefix %s%s",
|
"DHCPv6: received PD Prefix %s%s",
|
||||||
strna(buf),
|
strna(buf),
|
||||||
prefixlen > 64 ? " with prefix length > 64, ignoring." :
|
prefixlen > 64 ? " with prefix length > 64, ignoring." :
|
||||||
prefixlen < 48 ? " with prefix length < 48, looks unusual.": "");
|
prefixlen < 48 ? " with prefix length < 48, looks unusual.": "");
|
||||||
@ -928,7 +928,7 @@ static int dhcp6_pd_prefix_add(Link *link, const struct in6_addr *prefix, uint8_
|
|||||||
/* Store PD prefix even if prefixlen > 64, not to make logged at warning level so frequently. */
|
/* Store PD prefix even if prefixlen > 64, not to make logged at warning level so frequently. */
|
||||||
r = set_ensure_put(&link->dhcp6_pd_prefixes, &in_addr_prefix_hash_ops_free, p);
|
r = set_ensure_put(&link->dhcp6_pd_prefixes, &in_addr_prefix_hash_ops_free, p);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_error_errno(link, r, "Failed to store DHCP6 PD prefix %s: %m", strna(buf));
|
return log_link_error_errno(link, r, "Failed to store DHCPv6 PD prefix %s: %m", strna(buf));
|
||||||
if (r > 0)
|
if (r > 0)
|
||||||
TAKE_PTR(p);
|
TAKE_PTR(p);
|
||||||
|
|
||||||
@ -1393,6 +1393,8 @@ int dhcp6_request_information(Link *link, int ir) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int dhcp6_start(Link *link) {
|
int dhcp6_start(Link *link) {
|
||||||
|
int r;
|
||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
|
|
||||||
if (!link->dhcp6_client)
|
if (!link->dhcp6_client)
|
||||||
@ -1401,6 +1403,9 @@ int dhcp6_start(Link *link) {
|
|||||||
if (!link_dhcp6_enabled(link))
|
if (!link_dhcp6_enabled(link))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (!link_has_carrier(link))
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (link->network->dhcp6_without_ra == DHCP6_CLIENT_START_MODE_NO)
|
if (link->network->dhcp6_without_ra == DHCP6_CLIENT_START_MODE_NO)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -1412,9 +1417,11 @@ int dhcp6_start(Link *link) {
|
|||||||
if (sd_dhcp6_client_is_running(link->dhcp6_client) > 0)
|
if (sd_dhcp6_client_is_running(link->dhcp6_client) > 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
log_link_debug(link, "Acquiring DHCPv6 lease");
|
r = dhcp6_request_information(link, link->network->dhcp6_without_ra == DHCP6_CLIENT_START_MODE_INFORMATION_REQUEST);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
return dhcp6_request_information(link, link->network->dhcp6_without_ra == DHCP6_CLIENT_START_MODE_INFORMATION_REQUEST);
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dhcp6_request_prefix_delegation(Link *link) {
|
int dhcp6_request_prefix_delegation(Link *link) {
|
||||||
@ -1505,7 +1512,7 @@ static int dhcp6_set_hostname(sd_dhcp6_client *client, Link *link) {
|
|||||||
else {
|
else {
|
||||||
r = gethostname_strict(&hostname);
|
r = gethostname_strict(&hostname);
|
||||||
if (r < 0 && r != -ENXIO) /* ENXIO: no hostname set or hostname is "localhost" */
|
if (r < 0 && r != -ENXIO) /* ENXIO: no hostname set or hostname is "localhost" */
|
||||||
return r;
|
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to get hostname: %m");
|
||||||
|
|
||||||
hn = hostname;
|
hn = hostname;
|
||||||
}
|
}
|
||||||
@ -1513,9 +1520,9 @@ static int dhcp6_set_hostname(sd_dhcp6_client *client, Link *link) {
|
|||||||
r = sd_dhcp6_client_set_fqdn(client, hn);
|
r = sd_dhcp6_client_set_fqdn(client, hn);
|
||||||
if (r == -EINVAL && hostname)
|
if (r == -EINVAL && hostname)
|
||||||
/* Ignore error when the machine's hostname is not suitable to send in DHCP packet. */
|
/* Ignore error when the machine's hostname is not suitable to send in DHCP packet. */
|
||||||
log_link_warning_errno(link, r, "DHCP6 CLIENT: Failed to set hostname from kernel hostname, ignoring: %m");
|
log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set hostname from kernel hostname, ignoring: %m");
|
||||||
else if (r < 0)
|
else if (r < 0)
|
||||||
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set hostname: %m");
|
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set hostname: %m");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1571,7 +1578,7 @@ static int dhcp6_set_identifier(Link *link, sd_dhcp6_client *client) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dhcp6_configure(Link *link) {
|
static int dhcp6_configure(Link *link) {
|
||||||
_cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL;
|
_cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL;
|
||||||
sd_dhcp6_option *vendor_option;
|
sd_dhcp6_option *vendor_option;
|
||||||
sd_dhcp6_option *send_option;
|
sd_dhcp6_option *send_option;
|
||||||
@ -1581,36 +1588,29 @@ int dhcp6_configure(Link *link) {
|
|||||||
assert(link);
|
assert(link);
|
||||||
assert(link->network);
|
assert(link->network);
|
||||||
|
|
||||||
if (!link_dhcp6_enabled(link) && !link_ipv6_accept_ra_enabled(link))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (link->dhcp6_client)
|
if (link->dhcp6_client)
|
||||||
return -EBUSY;
|
return log_link_debug_errno(link, SYNTHETIC_ERRNO(EBUSY), "DHCPv6 client is already configured.");
|
||||||
|
|
||||||
r = dhcp_configure_duid(link, link_get_dhcp6_duid(link));
|
|
||||||
if (r <= 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
r = sd_dhcp6_client_new(&client);
|
r = sd_dhcp6_client_new(&client);
|
||||||
if (r == -ENOMEM)
|
if (r == -ENOMEM)
|
||||||
return log_oom();
|
return log_oom_debug();
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to create DHCP6 client: %m");
|
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to create DHCPv6 client: %m");
|
||||||
|
|
||||||
r = sd_dhcp6_client_attach_event(client, link->manager->event, 0);
|
r = sd_dhcp6_client_attach_event(client, link->manager->event, 0);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to attach event: %m");
|
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to attach event: %m");
|
||||||
|
|
||||||
r = dhcp6_set_identifier(link, client);
|
r = dhcp6_set_identifier(link, client);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set identifier: %m");
|
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set identifier: %m");
|
||||||
|
|
||||||
ORDERED_HASHMAP_FOREACH(send_option, link->network->dhcp6_client_send_options) {
|
ORDERED_HASHMAP_FOREACH(send_option, link->network->dhcp6_client_send_options) {
|
||||||
r = sd_dhcp6_client_add_option(client, send_option);
|
r = sd_dhcp6_client_add_option(client, send_option);
|
||||||
if (r == -EEXIST)
|
if (r == -EEXIST)
|
||||||
continue;
|
continue;
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set option: %m");
|
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set option: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
r = dhcp6_set_hostname(client, link);
|
r = dhcp6_set_hostname(client, link);
|
||||||
@ -1619,18 +1619,18 @@ int dhcp6_configure(Link *link) {
|
|||||||
|
|
||||||
r = sd_dhcp6_client_set_ifindex(client, link->ifindex);
|
r = sd_dhcp6_client_set_ifindex(client, link->ifindex);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set ifindex: %m");
|
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set ifindex: %m");
|
||||||
|
|
||||||
if (link->network->dhcp6_rapid_commit) {
|
if (link->network->dhcp6_rapid_commit) {
|
||||||
r = sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_RAPID_COMMIT);
|
r = sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_RAPID_COMMIT);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set request flag for rapid commit: %m");
|
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set request flag for rapid commit: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (link->network->dhcp6_mudurl) {
|
if (link->network->dhcp6_mudurl) {
|
||||||
r = sd_dhcp6_client_set_request_mud_url(client, link->network->dhcp6_mudurl);
|
r = sd_dhcp6_client_set_request_mud_url(client, link->network->dhcp6_mudurl);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set MUD URL: %m");
|
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set MUD URL: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
SET_FOREACH(request_options, link->network->dhcp6_request_options) {
|
SET_FOREACH(request_options, link->network->dhcp6_request_options) {
|
||||||
@ -1638,23 +1638,23 @@ int dhcp6_configure(Link *link) {
|
|||||||
|
|
||||||
r = sd_dhcp6_client_set_request_option(client, option);
|
r = sd_dhcp6_client_set_request_option(client, option);
|
||||||
if (r == -EEXIST) {
|
if (r == -EEXIST) {
|
||||||
log_link_debug(link, "DHCP6 CLIENT: Failed to set request flag for '%u' already exists, ignoring.", option);
|
log_link_debug(link, "DHCPv6 CLIENT: Failed to set request flag for '%u' already exists, ignoring.", option);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set request flag for '%u': %m", option);
|
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set request flag for '%u': %m", option);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (link->network->dhcp6_user_class) {
|
if (link->network->dhcp6_user_class) {
|
||||||
r = sd_dhcp6_client_set_request_user_class(client, link->network->dhcp6_user_class);
|
r = sd_dhcp6_client_set_request_user_class(client, link->network->dhcp6_user_class);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set user class: %m");
|
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set user class: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (link->network->dhcp6_vendor_class) {
|
if (link->network->dhcp6_vendor_class) {
|
||||||
r = sd_dhcp6_client_set_request_vendor_class(client, link->network->dhcp6_vendor_class);
|
r = sd_dhcp6_client_set_request_vendor_class(client, link->network->dhcp6_vendor_class);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set vendor class: %m");
|
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set vendor class: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
ORDERED_HASHMAP_FOREACH(vendor_option, link->network->dhcp6_client_send_vendor_options) {
|
ORDERED_HASHMAP_FOREACH(vendor_option, link->network->dhcp6_client_send_vendor_options) {
|
||||||
@ -1662,23 +1662,23 @@ int dhcp6_configure(Link *link) {
|
|||||||
if (r == -EEXIST)
|
if (r == -EEXIST)
|
||||||
continue;
|
continue;
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set vendor option: %m");
|
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set vendor option: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
r = sd_dhcp6_client_set_callback(client, dhcp6_handler, link);
|
r = sd_dhcp6_client_set_callback(client, dhcp6_handler, link);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set callback: %m");
|
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set callback: %m");
|
||||||
|
|
||||||
if (dhcp6_enable_prefix_delegation(link)) {
|
if (dhcp6_enable_prefix_delegation(link)) {
|
||||||
r = sd_dhcp6_client_set_prefix_delegation(client, true);
|
r = sd_dhcp6_client_set_prefix_delegation(client, true);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set prefix delegation: %m");
|
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set prefix delegation: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (link->network->dhcp6_pd_length > 0) {
|
if (link->network->dhcp6_pd_length > 0) {
|
||||||
r = sd_dhcp6_client_set_prefix_delegation_hint(client, link->network->dhcp6_pd_length, &link->network->dhcp6_pd_address);
|
r = sd_dhcp6_client_set_prefix_delegation_hint(client, link->network->dhcp6_pd_length, &link->network->dhcp6_pd_address);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set prefix hint: %m");
|
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set prefix hint: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
link->dhcp6_client = TAKE_PTR(client);
|
link->dhcp6_client = TAKE_PTR(client);
|
||||||
@ -1716,6 +1716,60 @@ int dhcp6_update_mac(Link *link) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int request_process_dhcp6_client(Request *req) {
|
||||||
|
Link *link;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(req);
|
||||||
|
assert(req->link);
|
||||||
|
assert(req->type == REQUEST_TYPE_DHCP6_CLIENT);
|
||||||
|
|
||||||
|
link = req->link;
|
||||||
|
|
||||||
|
if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
r = dhcp_configure_duid(link, link_get_dhcp6_duid(link));
|
||||||
|
if (r <= 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = dhcp6_configure(link);
|
||||||
|
if (r < 0)
|
||||||
|
return log_link_warning_errno(link, r, "Failed to configure DHCPv6 client: %m");
|
||||||
|
|
||||||
|
r = ndisc_start(link);
|
||||||
|
if (r < 0)
|
||||||
|
return log_link_warning_errno(link, r, "Failed to start IPv6 Router Discovery: %m");
|
||||||
|
|
||||||
|
r = dhcp6_start(link);
|
||||||
|
if (r < 0)
|
||||||
|
return log_link_warning_errno(link, r, "Failed to start DHCPv6 client: %m");
|
||||||
|
|
||||||
|
log_link_debug(link, "DHCPv6 client is configured%s.",
|
||||||
|
r > 0 ? ", acquiring DHCPv6 lease" : "");
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int link_request_dhcp6_client(Link *link) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(link);
|
||||||
|
|
||||||
|
if (!link_dhcp6_enabled(link) && !link_ipv6_accept_ra_enabled(link))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (link->dhcp6_client)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
r = link_queue_request(link, REQUEST_TYPE_DHCP6_CLIENT, NULL, false, NULL, NULL, NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return log_link_warning_errno(link, r, "Failed to request configuring of the DHCPv6 client: %m");
|
||||||
|
|
||||||
|
log_link_debug(link, "Requested configuring of the DHCPv6 client.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int link_serialize_dhcp6_client(Link *link, FILE *f) {
|
int link_serialize_dhcp6_client(Link *link, FILE *f) {
|
||||||
_cleanup_free_ char *duid = NULL;
|
_cleanup_free_ char *duid = NULL;
|
||||||
uint32_t iaid;
|
uint32_t iaid;
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "sd-dhcp6-client.h"
|
|
||||||
|
|
||||||
#include "conf-parser.h"
|
#include "conf-parser.h"
|
||||||
|
#include "in-addr-util.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
|
|
||||||
typedef enum DHCP6ClientStartMode {
|
typedef enum DHCP6ClientStartMode {
|
||||||
@ -15,7 +14,7 @@ typedef enum DHCP6ClientStartMode {
|
|||||||
} DHCP6ClientStartMode;
|
} DHCP6ClientStartMode;
|
||||||
|
|
||||||
typedef struct Link Link;
|
typedef struct Link Link;
|
||||||
typedef struct Manager Manager;
|
typedef struct Request Request;
|
||||||
|
|
||||||
typedef struct DHCP6DelegatedPrefix {
|
typedef struct DHCP6DelegatedPrefix {
|
||||||
struct in6_addr prefix; /* Prefix assigned to the link */
|
struct in6_addr prefix; /* Prefix assigned to the link */
|
||||||
@ -29,12 +28,14 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(DHCP6DelegatedPrefix*, dhcp6_pd_free);
|
|||||||
bool link_dhcp6_with_address_enabled(Link *link);
|
bool link_dhcp6_with_address_enabled(Link *link);
|
||||||
bool link_dhcp6_pd_is_enabled(Link *link);
|
bool link_dhcp6_pd_is_enabled(Link *link);
|
||||||
int dhcp6_pd_remove(Link *link);
|
int dhcp6_pd_remove(Link *link);
|
||||||
int dhcp6_configure(Link *link);
|
|
||||||
int dhcp6_update_mac(Link *link);
|
int dhcp6_update_mac(Link *link);
|
||||||
int dhcp6_start(Link *link);
|
int dhcp6_start(Link *link);
|
||||||
int dhcp6_request_information(Link *link, int ir);
|
int dhcp6_request_information(Link *link, int ir);
|
||||||
int dhcp6_request_prefix_delegation(Link *link);
|
int dhcp6_request_prefix_delegation(Link *link);
|
||||||
|
|
||||||
|
int request_process_dhcp6_client(Request *req);
|
||||||
|
int link_request_dhcp6_client(Link *link);
|
||||||
|
|
||||||
int link_serialize_dhcp6_client(Link *link, FILE *f);
|
int link_serialize_dhcp6_client(Link *link, FILE *f);
|
||||||
|
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_pd_hint);
|
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_pd_hint);
|
||||||
|
|||||||
@ -507,7 +507,7 @@ void link_check_ready(Link *link) {
|
|||||||
!link->dhcp_address && set_isempty(link->dhcp6_addresses) && !has_ndisc_address &&
|
!link->dhcp_address && set_isempty(link->dhcp6_addresses) && !has_ndisc_address &&
|
||||||
!link->ipv4ll_address_configured)
|
!link->ipv4ll_address_configured)
|
||||||
/* When DHCP[46] or IPv4LL is enabled, at least one address is acquired by them. */
|
/* When DHCP[46] or IPv4LL is enabled, at least one address is acquired by them. */
|
||||||
return (void) log_link_debug(link, "%s(): DHCP4, DHCP6 or IPv4LL is enabled but no dynamic address is assigned yet.", __func__);
|
return (void) log_link_debug(link, "%s(): DHCPv4, DHCPv6 or IPv4LL is enabled but no dynamic address is assigned yet.", __func__);
|
||||||
|
|
||||||
/* Ignore NDisc when ConfigureWithoutCarrier= is enabled, as IPv6AcceptRA= is enabled by default. */
|
/* Ignore NDisc when ConfigureWithoutCarrier= is enabled, as IPv6AcceptRA= is enabled by default. */
|
||||||
if (link_dhcp4_enabled(link) || link_dhcp6_enabled(link) || link_dhcp6_pd_is_enabled(link) ||
|
if (link_dhcp4_enabled(link) || link_dhcp6_enabled(link) || link_dhcp6_pd_is_enabled(link) ||
|
||||||
@ -522,8 +522,8 @@ void link_check_ready(Link *link) {
|
|||||||
/* When DHCP[46], NDisc, or IPv4LL is enabled, at least one protocol must be finished. */
|
/* When DHCP[46], NDisc, or IPv4LL is enabled, at least one protocol must be finished. */
|
||||||
return (void) log_link_debug(link, "%s(): dynamic addresses or routes are not configured.", __func__);
|
return (void) log_link_debug(link, "%s(): dynamic addresses or routes are not configured.", __func__);
|
||||||
|
|
||||||
log_link_debug(link, "%s(): dhcp4:%s ipv4ll:%s dhcp6_addresses:%s dhcp6_routes:%s "
|
log_link_debug(link, "%s(): DHCPv4:%s IPv4LL:%s DHCPv6_addresses:%s DHCPv6_routes:%s "
|
||||||
"dhcp6_pd_addresses:%s dhcp6_pd_routes:%s ndisc_addresses:%s ndisc_routes:%s",
|
"DHCPv6PD_addresses:%s DHCPv6PD_routes:%s NDisc_addresses:%s NDisc_routes:%s",
|
||||||
__func__,
|
__func__,
|
||||||
yes_no(link->dhcp4_configured),
|
yes_no(link->dhcp4_configured),
|
||||||
yes_no(link->ipv4ll_address_configured),
|
yes_no(link->ipv4ll_address_configured),
|
||||||
@ -650,12 +650,14 @@ static int link_acquire_dynamic_ipv4_conf(Link *link) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_warning_errno(link, r, "Failed to start DHCPv4 client: %m");
|
return log_link_warning_errno(link, r, "Failed to start DHCPv4 client: %m");
|
||||||
|
|
||||||
} else if (link->ipv4ll) {
|
log_link_debug(link, "Acquiring DHCPv4 lease.");
|
||||||
log_link_debug(link, "Acquiring IPv4 link-local address");
|
|
||||||
|
|
||||||
|
} else if (link->ipv4ll) {
|
||||||
r = sd_ipv4ll_start(link->ipv4ll);
|
r = sd_ipv4ll_start(link->ipv4ll);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m");
|
return log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m");
|
||||||
|
|
||||||
|
log_link_debug(link, "Acquiring IPv4 link-local address.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (link->dhcp_server) {
|
if (link->dhcp_server) {
|
||||||
@ -690,6 +692,12 @@ static int link_acquire_dynamic_conf(Link *link) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_warning_errno(link, r, "Failed to start LLDP transmission: %m");
|
return log_link_warning_errno(link, r, "Failed to start LLDP transmission: %m");
|
||||||
|
|
||||||
|
if (link->lldp) {
|
||||||
|
r = sd_lldp_start(link->lldp);
|
||||||
|
if (r < 0)
|
||||||
|
return log_link_warning_errno(link, r, "Failed to start LLDP client: %m");
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -975,8 +983,6 @@ static Link *link_drop(Link *link) {
|
|||||||
|
|
||||||
link_drop_from_master(link);
|
link_drop_from_master(link);
|
||||||
|
|
||||||
link_unref(set_remove(link->manager->links_requesting_uuid, link));
|
|
||||||
|
|
||||||
(void) unlink(link->state_file);
|
(void) unlink(link->state_file);
|
||||||
link_clean(link);
|
link_clean(link);
|
||||||
|
|
||||||
@ -999,6 +1005,16 @@ static int link_drop_foreign_config(Link *link) {
|
|||||||
assert(link);
|
assert(link);
|
||||||
assert(link->manager);
|
assert(link->manager);
|
||||||
|
|
||||||
|
/* Drop foreign config, but ignore unmanaged, loopback, or critical interfaces. We do not want
|
||||||
|
* to remove loopback address or addresses used for root NFS. */
|
||||||
|
|
||||||
|
if (IN_SET(link->state, LINK_STATE_UNMANAGED, LINK_STATE_PENDING, LINK_STATE_INITIALIZED))
|
||||||
|
return 0;
|
||||||
|
if (FLAGS_SET(link->flags, IFF_LOOPBACK))
|
||||||
|
return 0;
|
||||||
|
if (link->network->keep_configuration == KEEP_CONFIGURATION_YES)
|
||||||
|
return 0;
|
||||||
|
|
||||||
r = link_drop_foreign_routes(link);
|
r = link_drop_foreign_routes(link);
|
||||||
|
|
||||||
k = link_drop_foreign_nexthops(link);
|
k = link_drop_foreign_nexthops(link);
|
||||||
@ -1127,11 +1143,11 @@ static int link_configure(Link *link) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = dhcp4_configure(link);
|
r = link_request_dhcp4_client(link);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = dhcp6_configure(link);
|
r = link_request_dhcp6_client(link);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -1151,14 +1167,9 @@ static int link_configure(Link *link) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
/* Drop foreign config, but ignore loopback or critical devices.
|
r = link_drop_foreign_config(link);
|
||||||
* We do not want to remove loopback address or addresses used for root NFS. */
|
if (r < 0)
|
||||||
if (!(link->flags & IFF_LOOPBACK) &&
|
return r;
|
||||||
link->network->keep_configuration != KEEP_CONFIGURATION_YES) {
|
|
||||||
r = link_drop_foreign_config(link);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = link_request_static_configs(link);
|
r = link_request_static_configs(link);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -1224,23 +1235,22 @@ static int link_get_network(Link *link, Network **ret) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int link_reconfigure_impl(Link *link, bool force) {
|
static int link_reconfigure_impl(Link *link, bool force) {
|
||||||
Network *network;
|
Network *network = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
|
|
||||||
r = link_get_network(link, &network);
|
r = link_get_network(link, &network);
|
||||||
if (r == -ENOENT) {
|
if (r < 0 && r != -ENOENT)
|
||||||
link_set_state(link, LINK_STATE_UNMANAGED);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (link->network == network && !force)
|
if (link->network == network && !force)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
log_link_info(link, "Re-configuring with %s", network->filename);
|
if (network)
|
||||||
|
log_link_info(link, "Reconfiguring with %s.", network->filename);
|
||||||
|
else
|
||||||
|
log_link_info(link, "Unmanaging interface.");
|
||||||
|
|
||||||
/* Dropping old .network file */
|
/* Dropping old .network file */
|
||||||
r = link_stop_engines(link, false);
|
r = link_stop_engines(link, false);
|
||||||
@ -1253,17 +1263,14 @@ static int link_reconfigure_impl(Link *link, bool force) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (!IN_SET(link->state, LINK_STATE_UNMANAGED, LINK_STATE_PENDING, LINK_STATE_INITIALIZED)) {
|
|
||||||
log_link_debug(link, "State is %s, dropping foreign config", link_state_to_string(link->state));
|
|
||||||
r = link_drop_foreign_config(link);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
link_free_carrier_maps(link);
|
link_free_carrier_maps(link);
|
||||||
link_free_engines(link);
|
link_free_engines(link);
|
||||||
link->network = network_unref(link->network);
|
link->network = network_unref(link->network);
|
||||||
link_unref(set_remove(link->manager->links_requesting_uuid, link));
|
|
||||||
|
if (!network) {
|
||||||
|
link_set_state(link, LINK_STATE_UNMANAGED);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Then, apply new .network file */
|
/* Then, apply new .network file */
|
||||||
link->network = network_ref(network);
|
link->network = network_ref(network);
|
||||||
@ -1284,44 +1291,107 @@ static int link_reconfigure_impl(Link *link, bool force) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int link_reconfigure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, bool force) {
|
static int link_reconfigure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, bool force, bool update_wifi) {
|
||||||
|
bool link_was_lower_up;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
assert(link);
|
||||||
|
|
||||||
|
link_was_lower_up = link->flags & IFF_LOWER_UP;
|
||||||
|
|
||||||
r = link_getlink_handler_internal(rtnl, m, link, "Failed to update link state");
|
r = link_getlink_handler_internal(rtnl, m, link, "Failed to update link state");
|
||||||
if (r <= 0)
|
if (r <= 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
if (update_wifi && link_was_lower_up && link->flags & IFF_LOWER_UP) {
|
||||||
|
/* If the interface's L1 was not up, then wifi_get_info() is already called in
|
||||||
|
* link_update_flags(). So, it is not necessary to re-call here. */
|
||||||
|
r = wifi_get_info(link);
|
||||||
|
if (r < 0) {
|
||||||
|
link_enter_failed(link);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
r = link_reconfigure_impl(link, force);
|
r = link_reconfigure_impl(link, force);
|
||||||
if (r < 0)
|
if (r < 0) {
|
||||||
link_enter_failed(link);
|
link_enter_failed(link);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int link_reconfigure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
static int link_reconfigure_internal(Link *link, link_netlink_message_handler_t callback) {
|
||||||
return link_reconfigure_handler_internal(rtnl, m, link, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int link_force_reconfigure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
|
||||||
return link_reconfigure_handler_internal(rtnl, m, link, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
int link_reconfigure(Link *link, bool force) {
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
assert(link);
|
||||||
|
assert(callback);
|
||||||
|
|
||||||
/* When link in pending or initialized state, then link_configure() will be called. To prevent
|
/* When link in pending or initialized state, then link_configure() will be called. To prevent
|
||||||
* the function from being called multiple times simultaneously, refuse to reconfigure the
|
* the function from being called multiple times simultaneously, refuse to reconfigure the
|
||||||
* interface in these cases. */
|
* interface in these cases. */
|
||||||
if (IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_INITIALIZED, LINK_STATE_LINGER))
|
if (IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_INITIALIZED, LINK_STATE_LINGER))
|
||||||
return 0; /* 0 means no-op. */
|
return 0; /* 0 means no-op. */
|
||||||
|
|
||||||
r = link_call_getlink(link, force ? link_force_reconfigure_handler : link_reconfigure_handler);
|
r = link_call_getlink(link, callback);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
return 1; /* 1 means the interface will be reconfigured. */
|
return 1; /* 1 means the interface will be reconfigured. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int link_reconfigure(Link *link, bool force) {
|
||||||
|
return link_reconfigure_internal(link, force ? link_force_reconfigure_handler : link_reconfigure_handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
int link_reconfigure_after_sleep(Link *link) {
|
||||||
|
return link_reconfigure_internal(link, link_reconfigure_after_sleep_handler);
|
||||||
|
}
|
||||||
|
|
||||||
static int link_initialized_and_synced(Link *link) {
|
static int link_initialized_and_synced(Link *link) {
|
||||||
Network *network;
|
Network *network;
|
||||||
int r;
|
int r;
|
||||||
@ -1560,34 +1630,7 @@ static int link_carrier_lost(Link *link) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (!IN_SET(link->state, LINK_STATE_UNMANAGED, LINK_STATE_PENDING, LINK_STATE_INITIALIZED)) {
|
return link_drop_foreign_config(link);
|
||||||
log_link_debug(link, "State is %s, dropping foreign config", link_state_to_string(link->state));
|
|
||||||
r = link_drop_foreign_config(link);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int link_carrier_reset(Link *link) {
|
|
||||||
int r;
|
|
||||||
|
|
||||||
assert(link);
|
|
||||||
|
|
||||||
if (!link_has_carrier(link))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
r = link_carrier_lost(link);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
r = link_carrier_gained(link);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
log_link_info(link, "Reset carrier");
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int link_admin_state_up(Link *link) {
|
static int link_admin_state_up(Link *link) {
|
||||||
@ -1943,10 +1986,6 @@ static int link_update_flags(Link *link, sd_netlink_message *message) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = link_update_lldp(link);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
if (!had_carrier && link_has_carrier(link)) {
|
if (!had_carrier && link_has_carrier(link)) {
|
||||||
log_link_info(link, "Gained carrier");
|
log_link_info(link, "Gained carrier");
|
||||||
|
|
||||||
|
|||||||
@ -232,7 +232,6 @@ void link_check_ready(Link *link);
|
|||||||
|
|
||||||
void link_update_operstate(Link *link, bool also_update_bond_master);
|
void link_update_operstate(Link *link, bool also_update_bond_master);
|
||||||
|
|
||||||
int link_carrier_reset(Link *link);
|
|
||||||
bool link_has_carrier(Link *link);
|
bool link_has_carrier(Link *link);
|
||||||
|
|
||||||
bool link_ipv6_enabled(Link *link);
|
bool link_ipv6_enabled(Link *link);
|
||||||
@ -247,6 +246,7 @@ const char* link_state_to_string(LinkState s) _const_;
|
|||||||
LinkState link_state_from_string(const char *s) _pure_;
|
LinkState link_state_from_string(const char *s) _pure_;
|
||||||
|
|
||||||
int link_reconfigure(Link *link, bool force);
|
int link_reconfigure(Link *link, bool force);
|
||||||
|
int link_reconfigure_after_sleep(Link *link);
|
||||||
|
|
||||||
int manager_udev_process_link(sd_device_monitor *monitor, sd_device *device, void *userdata);
|
int manager_udev_process_link(sd_device_monitor *monitor, sd_device *device, void *userdata);
|
||||||
int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *message, Manager *m);
|
int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *message, Manager *m);
|
||||||
|
|||||||
@ -103,38 +103,9 @@ int link_lldp_rx_configure(Link *link) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = link_update_lldp(link);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int link_update_lldp(Link *link) {
|
|
||||||
int r;
|
|
||||||
|
|
||||||
assert(link);
|
|
||||||
|
|
||||||
if (!link->lldp)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (link->flags & IFF_UP) {
|
|
||||||
r = sd_lldp_start(link->lldp);
|
|
||||||
if (r < 0)
|
|
||||||
return log_link_warning_errno(link, r, "Failed to start LLDP: %m");
|
|
||||||
if (r > 0)
|
|
||||||
log_link_debug(link, "Started LLDP.");
|
|
||||||
} else {
|
|
||||||
r = sd_lldp_stop(link->lldp);
|
|
||||||
if (r < 0)
|
|
||||||
return log_link_warning_errno(link, r, "Failed to stop LLDP: %m");
|
|
||||||
if (r > 0)
|
|
||||||
log_link_debug(link, "Stopped LLDP.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
int link_lldp_save(Link *link) {
|
int link_lldp_save(Link *link) {
|
||||||
_cleanup_(unlink_and_freep) char *temp_path = NULL;
|
_cleanup_(unlink_and_freep) char *temp_path = NULL;
|
||||||
_cleanup_fclose_ FILE *f = NULL;
|
_cleanup_fclose_ FILE *f = NULL;
|
||||||
|
|||||||
@ -14,7 +14,6 @@ typedef enum LLDPMode {
|
|||||||
} LLDPMode;
|
} LLDPMode;
|
||||||
|
|
||||||
int link_lldp_rx_configure(Link *link);
|
int link_lldp_rx_configure(Link *link);
|
||||||
int link_update_lldp(Link *link);
|
|
||||||
int link_lldp_save(Link *link);
|
int link_lldp_save(Link *link);
|
||||||
|
|
||||||
const char* lldp_mode_to_string(LLDPMode m) _const_;
|
const char* lldp_mode_to_string(LLDPMode m) _const_;
|
||||||
|
|||||||
@ -59,9 +59,9 @@ static int manager_reset_all(Manager *m) {
|
|||||||
assert(m);
|
assert(m);
|
||||||
|
|
||||||
HASHMAP_FOREACH(link, m->links_by_index) {
|
HASHMAP_FOREACH(link, m->links_by_index) {
|
||||||
r = link_carrier_reset(link);
|
r = link_reconfigure_after_sleep(link);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_link_warning_errno(link, r, "Could not reset carrier: %m");
|
log_link_warning_errno(link, r, "Failed to reconfigure interface: %m");
|
||||||
link_enter_failed(link);
|
link_enter_failed(link);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -103,7 +103,7 @@ static int on_connected(sd_bus_message *message, void *userdata, sd_bus_error *r
|
|||||||
(void) manager_set_hostname(m, m->dynamic_hostname);
|
(void) manager_set_hostname(m, m->dynamic_hostname);
|
||||||
if (m->dynamic_timezone)
|
if (m->dynamic_timezone)
|
||||||
(void) manager_set_timezone(m, m->dynamic_timezone);
|
(void) manager_set_timezone(m, m->dynamic_timezone);
|
||||||
if (!set_isempty(m->links_requesting_uuid))
|
if (m->product_uuid_requested)
|
||||||
(void) manager_request_product_uuid(m);
|
(void) manager_request_product_uuid(m);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -460,7 +460,6 @@ Manager* manager_free(Manager *m) {
|
|||||||
m->dhcp6_pd_prefixes = set_free_with_destructor(m->dhcp6_pd_prefixes, dhcp6_pd_free);
|
m->dhcp6_pd_prefixes = set_free_with_destructor(m->dhcp6_pd_prefixes, dhcp6_pd_free);
|
||||||
|
|
||||||
m->dirty_links = set_free_with_destructor(m->dirty_links, link_unref);
|
m->dirty_links = set_free_with_destructor(m->dirty_links, link_unref);
|
||||||
m->links_requesting_uuid = set_free_with_destructor(m->links_requesting_uuid, link_unref);
|
|
||||||
m->links_by_name = hashmap_free(m->links_by_name);
|
m->links_by_name = hashmap_free(m->links_by_name);
|
||||||
m->links_by_hw_addr = hashmap_free(m->links_by_hw_addr);
|
m->links_by_hw_addr = hashmap_free(m->links_by_hw_addr);
|
||||||
m->links_by_index = hashmap_free_with_destructor(m->links_by_index, link_unref);
|
m->links_by_index = hashmap_free_with_destructor(m->links_by_index, link_unref);
|
||||||
|
|||||||
@ -60,7 +60,6 @@ struct Manager {
|
|||||||
DUID duid_product_uuid;
|
DUID duid_product_uuid;
|
||||||
bool has_product_uuid;
|
bool has_product_uuid;
|
||||||
bool product_uuid_requested;
|
bool product_uuid_requested;
|
||||||
Set *links_requesting_uuid;
|
|
||||||
|
|
||||||
char* dynamic_hostname;
|
char* dynamic_hostname;
|
||||||
char* dynamic_timezone;
|
char* dynamic_timezone;
|
||||||
|
|||||||
@ -38,6 +38,21 @@
|
|||||||
|
|
||||||
#define NDISC_APP_ID SD_ID128_MAKE(13,ac,81,a7,d5,3f,49,78,92,79,5d,0c,29,3a,bc,7e)
|
#define NDISC_APP_ID SD_ID128_MAKE(13,ac,81,a7,d5,3f,49,78,92,79,5d,0c,29,3a,bc,7e)
|
||||||
|
|
||||||
|
typedef enum IPv6TokenAddressGeneration {
|
||||||
|
IPV6_TOKEN_ADDRESS_GENERATION_NONE,
|
||||||
|
IPV6_TOKEN_ADDRESS_GENERATION_STATIC,
|
||||||
|
IPV6_TOKEN_ADDRESS_GENERATION_PREFIXSTABLE,
|
||||||
|
_IPV6_TOKEN_ADDRESS_GENERATION_MAX,
|
||||||
|
_IPV6_TOKEN_ADDRESS_GENERATION_INVALID = -EINVAL,
|
||||||
|
} IPv6TokenAddressGeneration;
|
||||||
|
|
||||||
|
typedef struct IPv6Token {
|
||||||
|
IPv6TokenAddressGeneration address_generation_type;
|
||||||
|
|
||||||
|
uint8_t dad_counter;
|
||||||
|
struct in6_addr prefix;
|
||||||
|
} IPv6Token;
|
||||||
|
|
||||||
bool link_ipv6_accept_ra_enabled(Link *link) {
|
bool link_ipv6_accept_ra_enabled(Link *link) {
|
||||||
assert(link);
|
assert(link);
|
||||||
|
|
||||||
@ -619,7 +634,7 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool stableprivate_address_is_valid(const struct in6_addr *addr) {
|
static bool stable_private_address_is_valid(const struct in6_addr *addr) {
|
||||||
assert(addr);
|
assert(addr);
|
||||||
|
|
||||||
/* According to rfc4291, generated address should not be in the following ranges. */
|
/* According to rfc4291, generated address should not be in the following ranges. */
|
||||||
@ -636,7 +651,7 @@ static bool stableprivate_address_is_valid(const struct in6_addr *addr) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int make_stableprivate_address(Link *link, const struct in6_addr *prefix, uint8_t prefix_len, uint8_t dad_counter, struct in6_addr **ret) {
|
static int make_stable_private_address(Link *link, const struct in6_addr *prefix, uint8_t prefix_len, uint8_t dad_counter, struct in6_addr **ret) {
|
||||||
_cleanup_free_ struct in6_addr *addr = NULL;
|
_cleanup_free_ struct in6_addr *addr = NULL;
|
||||||
sd_id128_t secret_key;
|
sd_id128_t secret_key;
|
||||||
struct siphash state;
|
struct siphash state;
|
||||||
@ -649,7 +664,7 @@ static int make_stableprivate_address(Link *link, const struct in6_addr *prefix,
|
|||||||
|
|
||||||
r = sd_id128_get_machine_app_specific(NDISC_APP_ID, &secret_key);
|
r = sd_id128_get_machine_app_specific(NDISC_APP_ID, &secret_key);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to generate key: %m");
|
return log_link_warning_errno(link, r, "Failed to generate key for IPv6 stable private address: %m");
|
||||||
|
|
||||||
siphash24_init(&state, secret_key.bytes);
|
siphash24_init(&state, secret_key.bytes);
|
||||||
|
|
||||||
@ -672,7 +687,7 @@ static int make_stableprivate_address(Link *link, const struct in6_addr *prefix,
|
|||||||
memcpy(addr->s6_addr, prefix->s6_addr, l);
|
memcpy(addr->s6_addr, prefix->s6_addr, l);
|
||||||
memcpy(addr->s6_addr + l, &rid, 16 - l);
|
memcpy(addr->s6_addr + l, &rid, 16 - l);
|
||||||
|
|
||||||
if (!stableprivate_address_is_valid(addr)) {
|
if (!stable_private_address_is_valid(addr)) {
|
||||||
*ret = NULL;
|
*ret = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -704,7 +719,7 @@ static int ndisc_router_generate_addresses(Link *link, struct in6_addr *address,
|
|||||||
* only when the address generation algorithm produces an invalid address, and the loop
|
* only when the address generation algorithm produces an invalid address, and the loop
|
||||||
* may exit with an address which ends up being unusable due to duplication on the link. */
|
* may exit with an address which ends up being unusable due to duplication on the link. */
|
||||||
for (; j->dad_counter < DAD_CONFLICTS_IDGEN_RETRIES_RFC7217; j->dad_counter++) {
|
for (; j->dad_counter < DAD_CONFLICTS_IDGEN_RETRIES_RFC7217; j->dad_counter++) {
|
||||||
r = make_stableprivate_address(link, address, prefixlen, j->dad_counter, &new_address);
|
r = make_stable_private_address(link, address, prefixlen, j->dad_counter, &new_address);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
if (r > 0)
|
if (r > 0)
|
||||||
@ -1030,7 +1045,7 @@ static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
|
|||||||
if (rdnss) {
|
if (rdnss) {
|
||||||
rdnss->marked = false;
|
rdnss->marked = false;
|
||||||
rdnss->router = router;
|
rdnss->router = router;
|
||||||
rdnss->valid_until = time_now + lifetime * USEC_PER_SEC;
|
rdnss->valid_until = usec_add(time_now, lifetime * USEC_PER_SEC);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1041,7 +1056,7 @@ static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
|
|||||||
*x = (NDiscRDNSS) {
|
*x = (NDiscRDNSS) {
|
||||||
.address = a[j],
|
.address = a[j],
|
||||||
.router = router,
|
.router = router,
|
||||||
.valid_until = time_now + lifetime * USEC_PER_SEC,
|
.valid_until = usec_add(time_now, lifetime * USEC_PER_SEC),
|
||||||
};
|
};
|
||||||
|
|
||||||
r = set_ensure_consume(&link->ndisc_rdnss, &ndisc_rdnss_hash_ops, TAKE_PTR(x));
|
r = set_ensure_consume(&link->ndisc_rdnss, &ndisc_rdnss_hash_ops, TAKE_PTR(x));
|
||||||
@ -1128,12 +1143,12 @@ static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
|
|||||||
if (dnssl) {
|
if (dnssl) {
|
||||||
dnssl->marked = false;
|
dnssl->marked = false;
|
||||||
dnssl->router = router;
|
dnssl->router = router;
|
||||||
dnssl->valid_until = time_now + lifetime * USEC_PER_SEC;
|
dnssl->valid_until = usec_add(time_now, lifetime * USEC_PER_SEC);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
s->router = router;
|
s->router = router;
|
||||||
s->valid_until = time_now + lifetime * USEC_PER_SEC;
|
s->valid_until = usec_add(time_now, lifetime * USEC_PER_SEC);
|
||||||
|
|
||||||
r = set_ensure_consume(&link->ndisc_dnssl, &ndisc_dnssl_hash_ops, TAKE_PTR(s));
|
r = set_ensure_consume(&link->ndisc_dnssl, &ndisc_dnssl_hash_ops, TAKE_PTR(s));
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -1396,6 +1411,9 @@ int ndisc_start(Link *link) {
|
|||||||
if (!link->ndisc || !link->dhcp6_client)
|
if (!link->ndisc || !link->dhcp6_client)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (!link_has_carrier(link))
|
||||||
|
return 0;
|
||||||
|
|
||||||
log_link_debug(link, "Discovering IPv6 routers");
|
log_link_debug(link, "Discovering IPv6 routers");
|
||||||
|
|
||||||
return sd_ndisc_start(link->ndisc);
|
return sd_ndisc_start(link->ndisc);
|
||||||
@ -1430,7 +1448,7 @@ void ndisc_flush(Link *link) {
|
|||||||
link->ndisc_dnssl = set_free(link->ndisc_dnssl);
|
link->ndisc_dnssl = set_free(link->ndisc_dnssl);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ipv6token_new(IPv6Token **ret) {
|
static int ipv6token_new(IPv6Token **ret) {
|
||||||
IPv6Token *p;
|
IPv6Token *p;
|
||||||
|
|
||||||
p = new(IPv6Token, 1);
|
p = new(IPv6Token, 1);
|
||||||
|
|||||||
@ -7,16 +7,6 @@
|
|||||||
#include "networkd-route.h"
|
#include "networkd-route.h"
|
||||||
#include "time-util.h"
|
#include "time-util.h"
|
||||||
|
|
||||||
typedef struct IPv6Token IPv6Token;
|
|
||||||
|
|
||||||
typedef enum IPv6TokenAddressGeneration {
|
|
||||||
IPV6_TOKEN_ADDRESS_GENERATION_NONE,
|
|
||||||
IPV6_TOKEN_ADDRESS_GENERATION_STATIC,
|
|
||||||
IPV6_TOKEN_ADDRESS_GENERATION_PREFIXSTABLE,
|
|
||||||
_IPV6_TOKEN_ADDRESS_GENERATION_MAX,
|
|
||||||
_IPV6_TOKEN_ADDRESS_GENERATION_INVALID = -EINVAL,
|
|
||||||
} IPv6TokenAddressGeneration;
|
|
||||||
|
|
||||||
typedef enum IPv6AcceptRAStartDHCP6Client {
|
typedef enum IPv6AcceptRAStartDHCP6Client {
|
||||||
IPV6_ACCEPT_RA_START_DHCP6_CLIENT_NO,
|
IPV6_ACCEPT_RA_START_DHCP6_CLIENT_NO,
|
||||||
IPV6_ACCEPT_RA_START_DHCP6_CLIENT_ALWAYS,
|
IPV6_ACCEPT_RA_START_DHCP6_CLIENT_ALWAYS,
|
||||||
@ -55,15 +45,6 @@ typedef struct NDiscDNSSL {
|
|||||||
/* The domain name follows immediately. */
|
/* The domain name follows immediately. */
|
||||||
} NDiscDNSSL;
|
} NDiscDNSSL;
|
||||||
|
|
||||||
struct IPv6Token {
|
|
||||||
IPv6TokenAddressGeneration address_generation_type;
|
|
||||||
|
|
||||||
uint8_t dad_counter;
|
|
||||||
struct in6_addr prefix;
|
|
||||||
};
|
|
||||||
|
|
||||||
int ipv6token_new(IPv6Token **ret);
|
|
||||||
|
|
||||||
static inline char* NDISC_DNSSL_DOMAIN(const NDiscDNSSL *n) {
|
static inline char* NDISC_DNSSL_DOMAIN(const NDiscDNSSL *n) {
|
||||||
return ((char*) n) + ALIGN(sizeof(NDiscDNSSL));
|
return ((char*) n) + ALIGN(sizeof(NDiscDNSSL));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,8 @@
|
|||||||
#include "networkd-bridge-fdb.h"
|
#include "networkd-bridge-fdb.h"
|
||||||
#include "networkd-bridge-mdb.h"
|
#include "networkd-bridge-mdb.h"
|
||||||
#include "networkd-dhcp-server.h"
|
#include "networkd-dhcp-server.h"
|
||||||
|
#include "networkd-dhcp4.h"
|
||||||
|
#include "networkd-dhcp6.h"
|
||||||
#include "networkd-ipv6-proxy-ndp.h"
|
#include "networkd-ipv6-proxy-ndp.h"
|
||||||
#include "networkd-manager.h"
|
#include "networkd-manager.h"
|
||||||
#include "networkd-neighbor.h"
|
#include "networkd-neighbor.h"
|
||||||
@ -33,6 +35,8 @@ static void request_free_object(RequestType type, void *object) {
|
|||||||
case REQUEST_TYPE_CREATE_STACKED_NETDEV:
|
case REQUEST_TYPE_CREATE_STACKED_NETDEV:
|
||||||
break;
|
break;
|
||||||
case REQUEST_TYPE_DHCP_SERVER:
|
case REQUEST_TYPE_DHCP_SERVER:
|
||||||
|
case REQUEST_TYPE_DHCP4_CLIENT:
|
||||||
|
case REQUEST_TYPE_DHCP6_CLIENT:
|
||||||
break;
|
break;
|
||||||
case REQUEST_TYPE_IPV6_PROXY_NDP:
|
case REQUEST_TYPE_IPV6_PROXY_NDP:
|
||||||
free(object);
|
free(object);
|
||||||
@ -112,7 +116,9 @@ static void request_hash_func(const Request *req, struct siphash *state) {
|
|||||||
trivial_hash_func(req->object, state);
|
trivial_hash_func(req->object, state);
|
||||||
break;
|
break;
|
||||||
case REQUEST_TYPE_DHCP_SERVER:
|
case REQUEST_TYPE_DHCP_SERVER:
|
||||||
/* This type does not have an object. */
|
case REQUEST_TYPE_DHCP4_CLIENT:
|
||||||
|
case REQUEST_TYPE_DHCP6_CLIENT:
|
||||||
|
/* These types do not have an object. */
|
||||||
break;
|
break;
|
||||||
case REQUEST_TYPE_IPV6_PROXY_NDP:
|
case REQUEST_TYPE_IPV6_PROXY_NDP:
|
||||||
in6_addr_hash_func(req->ipv6_proxy_ndp, state);
|
in6_addr_hash_func(req->ipv6_proxy_ndp, state);
|
||||||
@ -170,6 +176,8 @@ static int request_compare_func(const struct Request *a, const struct Request *b
|
|||||||
case REQUEST_TYPE_CREATE_STACKED_NETDEV:
|
case REQUEST_TYPE_CREATE_STACKED_NETDEV:
|
||||||
return trivial_compare_func(a->object, b->object);
|
return trivial_compare_func(a->object, b->object);
|
||||||
case REQUEST_TYPE_DHCP_SERVER:
|
case REQUEST_TYPE_DHCP_SERVER:
|
||||||
|
case REQUEST_TYPE_DHCP4_CLIENT:
|
||||||
|
case REQUEST_TYPE_DHCP6_CLIENT:
|
||||||
return 0;
|
return 0;
|
||||||
case REQUEST_TYPE_IPV6_PROXY_NDP:
|
case REQUEST_TYPE_IPV6_PROXY_NDP:
|
||||||
return in6_addr_compare_func(a->ipv6_proxy_ndp, b->ipv6_proxy_ndp);
|
return in6_addr_compare_func(a->ipv6_proxy_ndp, b->ipv6_proxy_ndp);
|
||||||
@ -218,12 +226,16 @@ int link_queue_request(
|
|||||||
assert(IN_SET(type,
|
assert(IN_SET(type,
|
||||||
REQUEST_TYPE_ACTIVATE_LINK,
|
REQUEST_TYPE_ACTIVATE_LINK,
|
||||||
REQUEST_TYPE_DHCP_SERVER,
|
REQUEST_TYPE_DHCP_SERVER,
|
||||||
|
REQUEST_TYPE_DHCP4_CLIENT,
|
||||||
|
REQUEST_TYPE_DHCP6_CLIENT,
|
||||||
REQUEST_TYPE_RADV,
|
REQUEST_TYPE_RADV,
|
||||||
REQUEST_TYPE_SET_LINK,
|
REQUEST_TYPE_SET_LINK,
|
||||||
REQUEST_TYPE_UP_DOWN) ||
|
REQUEST_TYPE_UP_DOWN) ||
|
||||||
object);
|
object);
|
||||||
assert(IN_SET(type,
|
assert(IN_SET(type,
|
||||||
REQUEST_TYPE_DHCP_SERVER,
|
REQUEST_TYPE_DHCP_SERVER,
|
||||||
|
REQUEST_TYPE_DHCP4_CLIENT,
|
||||||
|
REQUEST_TYPE_DHCP6_CLIENT,
|
||||||
REQUEST_TYPE_RADV) ||
|
REQUEST_TYPE_RADV) ||
|
||||||
netlink_handler);
|
netlink_handler);
|
||||||
|
|
||||||
@ -300,6 +312,12 @@ int manager_process_requests(sd_event_source *s, void *userdata) {
|
|||||||
case REQUEST_TYPE_DHCP_SERVER:
|
case REQUEST_TYPE_DHCP_SERVER:
|
||||||
r = request_process_dhcp_server(req);
|
r = request_process_dhcp_server(req);
|
||||||
break;
|
break;
|
||||||
|
case REQUEST_TYPE_DHCP4_CLIENT:
|
||||||
|
r = request_process_dhcp4_client(req);
|
||||||
|
break;
|
||||||
|
case REQUEST_TYPE_DHCP6_CLIENT:
|
||||||
|
r = request_process_dhcp6_client(req);
|
||||||
|
break;
|
||||||
case REQUEST_TYPE_IPV6_PROXY_NDP:
|
case REQUEST_TYPE_IPV6_PROXY_NDP:
|
||||||
r = request_process_ipv6_proxy_ndp_address(req);
|
r = request_process_ipv6_proxy_ndp_address(req);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -28,6 +28,8 @@ typedef enum RequestType {
|
|||||||
REQUEST_TYPE_BRIDGE_MDB,
|
REQUEST_TYPE_BRIDGE_MDB,
|
||||||
REQUEST_TYPE_CREATE_STACKED_NETDEV,
|
REQUEST_TYPE_CREATE_STACKED_NETDEV,
|
||||||
REQUEST_TYPE_DHCP_SERVER,
|
REQUEST_TYPE_DHCP_SERVER,
|
||||||
|
REQUEST_TYPE_DHCP4_CLIENT,
|
||||||
|
REQUEST_TYPE_DHCP6_CLIENT,
|
||||||
REQUEST_TYPE_IPV6_PROXY_NDP,
|
REQUEST_TYPE_IPV6_PROXY_NDP,
|
||||||
REQUEST_TYPE_NEIGHBOR,
|
REQUEST_TYPE_NEIGHBOR,
|
||||||
REQUEST_TYPE_NEXTHOP,
|
REQUEST_TYPE_NEXTHOP,
|
||||||
|
|||||||
@ -869,9 +869,9 @@ int link_request_radv(Link *link) {
|
|||||||
|
|
||||||
r = link_queue_request(link, REQUEST_TYPE_RADV, NULL, false, NULL, NULL, NULL);
|
r = link_queue_request(link, REQUEST_TYPE_RADV, NULL, false, NULL, NULL, NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_warning_errno(link, r, "Failed to request IPv6 Router Advertisement engine: %m");
|
return log_link_warning_errno(link, r, "Failed to request configuring of the IPv6 Router Advertisement engine: %m");
|
||||||
|
|
||||||
log_link_debug(link, "IPv6 Router Advertisement engine is requested.");
|
log_link_debug(link, "Requested configuring of the IPv6 Router Advertisement engine.");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -585,7 +585,7 @@ static int dns_stub_send_reply(
|
|||||||
DNS_PACKET_RD(q->request_packet),
|
DNS_PACKET_RD(q->request_packet),
|
||||||
!!q->request_packet->opt,
|
!!q->request_packet->opt,
|
||||||
edns0_do,
|
edns0_do,
|
||||||
DNS_PACKET_AD(q->request_packet) && dns_query_fully_authenticated(q),
|
(DNS_PACKET_AD(q->request_packet) || DNS_PACKET_DO(q->request_packet)) && dns_query_fully_authenticated(q),
|
||||||
DNS_PACKET_CD(q->request_packet),
|
DNS_PACKET_CD(q->request_packet),
|
||||||
q->stub_listener_extra ? ADVERTISE_EXTRA_DATAGRAM_SIZE_MAX : ADVERTISE_DATAGRAM_SIZE_MAX,
|
q->stub_listener_extra ? ADVERTISE_EXTRA_DATAGRAM_SIZE_MAX : ADVERTISE_DATAGRAM_SIZE_MAX,
|
||||||
dns_packet_has_nsid_request(q->request_packet) > 0 && !q->stub_listener_extra);
|
dns_packet_has_nsid_request(q->request_packet) > 0 && !q->stub_listener_extra);
|
||||||
@ -627,7 +627,7 @@ static int dns_stub_send_failure(
|
|||||||
DNS_PACKET_RD(p),
|
DNS_PACKET_RD(p),
|
||||||
!!p->opt,
|
!!p->opt,
|
||||||
DNS_PACKET_DO(p),
|
DNS_PACKET_DO(p),
|
||||||
DNS_PACKET_AD(p) && authenticated,
|
(DNS_PACKET_AD(p) || DNS_PACKET_DO(p)) && authenticated,
|
||||||
DNS_PACKET_CD(p),
|
DNS_PACKET_CD(p),
|
||||||
l ? ADVERTISE_EXTRA_DATAGRAM_SIZE_MAX : ADVERTISE_DATAGRAM_SIZE_MAX,
|
l ? ADVERTISE_EXTRA_DATAGRAM_SIZE_MAX : ADVERTISE_DATAGRAM_SIZE_MAX,
|
||||||
dns_packet_has_nsid_request(p) > 0 && !l);
|
dns_packet_has_nsid_request(p) > 0 && !l);
|
||||||
|
|||||||
@ -81,6 +81,9 @@ _SD_BEGIN_DECLARATIONS;
|
|||||||
#define SD_MESSAGE_SHUTDOWN SD_ID128_MAKE(98,26,88,66,d1,d5,4a,49,9c,4e,98,92,1d,93,bc,40)
|
#define SD_MESSAGE_SHUTDOWN SD_ID128_MAKE(98,26,88,66,d1,d5,4a,49,9c,4e,98,92,1d,93,bc,40)
|
||||||
#define SD_MESSAGE_SHUTDOWN_STR SD_ID128_MAKE_STR(98,26,88,66,d1,d5,4a,49,9c,4e,98,92,1d,93,bc,40)
|
#define SD_MESSAGE_SHUTDOWN_STR SD_ID128_MAKE_STR(98,26,88,66,d1,d5,4a,49,9c,4e,98,92,1d,93,bc,40)
|
||||||
|
|
||||||
|
#define SD_MESSAGE_FACTORY_RESET SD_ID128_MAKE(c1,4a,af,76,ec,28,4a,5f,a1,f1,05,f8,8d,fb,06,1c)
|
||||||
|
#define SD_MESSAGE_FACTORY_RESET_STR SD_ID128_MAKE_STR(c1,4a,af,76,ec,28,4a,5f,a1,f1,05,f8,8d,fb,06,1c)
|
||||||
|
|
||||||
/* The messages below are actually about jobs, not really about units, the macros are misleadingly named. Moreover
|
/* The messages below are actually about jobs, not really about units, the macros are misleadingly named. Moreover
|
||||||
* SD_MESSAGE_UNIT_FAILED is not actually about a failing unit but about a failed start job. A job either finishes with
|
* SD_MESSAGE_UNIT_FAILED is not actually about a failing unit but about a failed start job. A job either finishes with
|
||||||
* SD_MESSAGE_UNIT_STARTED or with SD_MESSAGE_UNIT_FAILED hence. */
|
* SD_MESSAGE_UNIT_STARTED or with SD_MESSAGE_UNIT_FAILED hence. */
|
||||||
|
|||||||
@ -23,14 +23,14 @@
|
|||||||
/* wire protocol magic must match */
|
/* wire protocol magic must match */
|
||||||
#define UDEV_CTRL_MAGIC 0xdead1dea
|
#define UDEV_CTRL_MAGIC 0xdead1dea
|
||||||
|
|
||||||
struct udev_ctrl_msg_wire {
|
typedef struct UdevCtrlMessageWire {
|
||||||
char version[16];
|
char version[16];
|
||||||
unsigned magic;
|
unsigned magic;
|
||||||
enum udev_ctrl_msg_type type;
|
UdevCtrlMessageType type;
|
||||||
union udev_ctrl_msg_value value;
|
UdevCtrlMessageValue value;
|
||||||
};
|
} UdevCtrlMessageWire;
|
||||||
|
|
||||||
struct udev_ctrl {
|
struct UdevCtrl {
|
||||||
unsigned n_ref;
|
unsigned n_ref;
|
||||||
int sock;
|
int sock;
|
||||||
int sock_connect;
|
int sock_connect;
|
||||||
@ -47,9 +47,9 @@ struct udev_ctrl {
|
|||||||
void *userdata;
|
void *userdata;
|
||||||
};
|
};
|
||||||
|
|
||||||
int udev_ctrl_new_from_fd(struct udev_ctrl **ret, int fd) {
|
int udev_ctrl_new_from_fd(UdevCtrl **ret, int fd) {
|
||||||
_cleanup_close_ int sock = -1;
|
_cleanup_close_ int sock = -1;
|
||||||
struct udev_ctrl *uctrl;
|
UdevCtrl *uctrl;
|
||||||
|
|
||||||
assert(ret);
|
assert(ret);
|
||||||
|
|
||||||
@ -59,11 +59,11 @@ int udev_ctrl_new_from_fd(struct udev_ctrl **ret, int fd) {
|
|||||||
return log_error_errno(errno, "Failed to create socket: %m");
|
return log_error_errno(errno, "Failed to create socket: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
uctrl = new(struct udev_ctrl, 1);
|
uctrl = new(UdevCtrl, 1);
|
||||||
if (!uctrl)
|
if (!uctrl)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
*uctrl = (struct udev_ctrl) {
|
*uctrl = (UdevCtrl) {
|
||||||
.n_ref = 1,
|
.n_ref = 1,
|
||||||
.sock = fd >= 0 ? fd : TAKE_FD(sock),
|
.sock = fd >= 0 ? fd : TAKE_FD(sock),
|
||||||
.sock_connect = -1,
|
.sock_connect = -1,
|
||||||
@ -81,7 +81,7 @@ int udev_ctrl_new_from_fd(struct udev_ctrl **ret, int fd) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl) {
|
int udev_ctrl_enable_receiving(UdevCtrl *uctrl) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(uctrl);
|
assert(uctrl);
|
||||||
@ -107,7 +107,7 @@ int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void udev_ctrl_disconnect(struct udev_ctrl *uctrl) {
|
static void udev_ctrl_disconnect(UdevCtrl *uctrl) {
|
||||||
if (!uctrl)
|
if (!uctrl)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -115,7 +115,7 @@ static void udev_ctrl_disconnect(struct udev_ctrl *uctrl) {
|
|||||||
uctrl->sock_connect = safe_close(uctrl->sock_connect);
|
uctrl->sock_connect = safe_close(uctrl->sock_connect);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct udev_ctrl *udev_ctrl_free(struct udev_ctrl *uctrl) {
|
static UdevCtrl *udev_ctrl_free(UdevCtrl *uctrl) {
|
||||||
assert(uctrl);
|
assert(uctrl);
|
||||||
|
|
||||||
udev_ctrl_disconnect(uctrl);
|
udev_ctrl_disconnect(uctrl);
|
||||||
@ -127,9 +127,9 @@ static struct udev_ctrl *udev_ctrl_free(struct udev_ctrl *uctrl) {
|
|||||||
return mfree(uctrl);
|
return mfree(uctrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_TRIVIAL_REF_UNREF_FUNC(struct udev_ctrl, udev_ctrl, udev_ctrl_free);
|
DEFINE_TRIVIAL_REF_UNREF_FUNC(UdevCtrl, udev_ctrl, udev_ctrl_free);
|
||||||
|
|
||||||
int udev_ctrl_cleanup(struct udev_ctrl *uctrl) {
|
int udev_ctrl_cleanup(UdevCtrl *uctrl) {
|
||||||
if (!uctrl)
|
if (!uctrl)
|
||||||
return 0;
|
return 0;
|
||||||
if (uctrl->cleanup_socket)
|
if (uctrl->cleanup_socket)
|
||||||
@ -137,7 +137,7 @@ int udev_ctrl_cleanup(struct udev_ctrl *uctrl) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int udev_ctrl_attach_event(struct udev_ctrl *uctrl, sd_event *event) {
|
int udev_ctrl_attach_event(UdevCtrl *uctrl, sd_event *event) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert_return(uctrl, -EINVAL);
|
assert_return(uctrl, -EINVAL);
|
||||||
@ -154,25 +154,25 @@ int udev_ctrl_attach_event(struct udev_ctrl *uctrl, sd_event *event) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
sd_event_source *udev_ctrl_get_event_source(struct udev_ctrl *uctrl) {
|
sd_event_source *udev_ctrl_get_event_source(UdevCtrl *uctrl) {
|
||||||
assert(uctrl);
|
assert(uctrl);
|
||||||
|
|
||||||
return uctrl->event_source;
|
return uctrl->event_source;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void udev_ctrl_disconnect_and_listen_again(struct udev_ctrl *uctrl) {
|
static void udev_ctrl_disconnect_and_listen_again(UdevCtrl *uctrl) {
|
||||||
udev_ctrl_disconnect(uctrl);
|
udev_ctrl_disconnect(uctrl);
|
||||||
udev_ctrl_unref(uctrl);
|
udev_ctrl_unref(uctrl);
|
||||||
(void) sd_event_source_set_enabled(uctrl->event_source, SD_EVENT_ON);
|
(void) sd_event_source_set_enabled(uctrl->event_source, SD_EVENT_ON);
|
||||||
/* We don't return NULL here because uctrl is not freed */
|
/* We don't return NULL here because uctrl is not freed */
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct udev_ctrl*, udev_ctrl_disconnect_and_listen_again, NULL);
|
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(UdevCtrl*, udev_ctrl_disconnect_and_listen_again, NULL);
|
||||||
|
|
||||||
static int udev_ctrl_connection_event_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
|
static int udev_ctrl_connection_event_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
|
||||||
_cleanup_(udev_ctrl_disconnect_and_listen_againp) struct udev_ctrl *uctrl = NULL;
|
_cleanup_(udev_ctrl_disconnect_and_listen_againp) UdevCtrl *uctrl = NULL;
|
||||||
struct udev_ctrl_msg_wire msg_wire;
|
UdevCtrlMessageWire msg_wire;
|
||||||
struct iovec iov = IOVEC_MAKE(&msg_wire, sizeof(struct udev_ctrl_msg_wire));
|
struct iovec iov = IOVEC_MAKE(&msg_wire, sizeof(UdevCtrlMessageWire));
|
||||||
CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred))) control;
|
CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred))) control;
|
||||||
struct msghdr smsg = {
|
struct msghdr smsg = {
|
||||||
.msg_iov = &iov,
|
.msg_iov = &iov,
|
||||||
@ -235,7 +235,7 @@ static int udev_ctrl_connection_event_handler(sd_event_source *s, int fd, uint32
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int udev_ctrl_event_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
|
static int udev_ctrl_event_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
|
||||||
struct udev_ctrl *uctrl = userdata;
|
UdevCtrl *uctrl = userdata;
|
||||||
_cleanup_close_ int sock = -1;
|
_cleanup_close_ int sock = -1;
|
||||||
struct ucred ucred;
|
struct ucred ucred;
|
||||||
int r;
|
int r;
|
||||||
@ -282,7 +282,7 @@ static int udev_ctrl_event_handler(sd_event_source *s, int fd, uint32_t revents,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int udev_ctrl_start(struct udev_ctrl *uctrl, udev_ctrl_handler_t callback, void *userdata) {
|
int udev_ctrl_start(UdevCtrl *uctrl, udev_ctrl_handler_t callback, void *userdata) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(uctrl);
|
assert(uctrl);
|
||||||
@ -309,8 +309,8 @@ int udev_ctrl_start(struct udev_ctrl *uctrl, udev_ctrl_handler_t callback, void
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int udev_ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int intval, const char *buf) {
|
int udev_ctrl_send(UdevCtrl *uctrl, UdevCtrlMessageType type, int intval, const char *buf) {
|
||||||
struct udev_ctrl_msg_wire ctrl_msg_wire = {
|
UdevCtrlMessageWire ctrl_msg_wire = {
|
||||||
.version = "udev-" STRINGIFY(PROJECT_VERSION),
|
.version = "udev-" STRINGIFY(PROJECT_VERSION),
|
||||||
.magic = UDEV_CTRL_MAGIC,
|
.magic = UDEV_CTRL_MAGIC,
|
||||||
.type = type,
|
.type = type,
|
||||||
@ -339,7 +339,7 @@ int udev_ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int in
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int udev_ctrl_wait(struct udev_ctrl *uctrl, usec_t timeout) {
|
int udev_ctrl_wait(UdevCtrl *uctrl, usec_t timeout) {
|
||||||
_cleanup_(sd_event_source_unrefp) sd_event_source *source_io = NULL, *source_timeout = NULL;
|
_cleanup_(sd_event_source_unrefp) sd_event_source *source_io = NULL, *source_timeout = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
|||||||
@ -6,9 +6,9 @@
|
|||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
#include "time-util.h"
|
#include "time-util.h"
|
||||||
|
|
||||||
struct udev_ctrl;
|
typedef struct UdevCtrl UdevCtrl;
|
||||||
|
|
||||||
enum udev_ctrl_msg_type {
|
typedef enum UdevCtrlMessageType {
|
||||||
_UDEV_CTRL_END_MESSAGES,
|
_UDEV_CTRL_END_MESSAGES,
|
||||||
UDEV_CTRL_SET_LOG_LEVEL,
|
UDEV_CTRL_SET_LOG_LEVEL,
|
||||||
UDEV_CTRL_STOP_EXEC_QUEUE,
|
UDEV_CTRL_STOP_EXEC_QUEUE,
|
||||||
@ -18,62 +18,62 @@ enum udev_ctrl_msg_type {
|
|||||||
UDEV_CTRL_SET_CHILDREN_MAX,
|
UDEV_CTRL_SET_CHILDREN_MAX,
|
||||||
UDEV_CTRL_PING,
|
UDEV_CTRL_PING,
|
||||||
UDEV_CTRL_EXIT,
|
UDEV_CTRL_EXIT,
|
||||||
};
|
} UdevCtrlMessageType;
|
||||||
|
|
||||||
union udev_ctrl_msg_value {
|
typedef union UdevCtrlMessageValue {
|
||||||
int intval;
|
int intval;
|
||||||
char buf[256];
|
char buf[256];
|
||||||
};
|
} UdevCtrlMessageValue;
|
||||||
|
|
||||||
typedef int (*udev_ctrl_handler_t)(struct udev_ctrl *udev_ctrl, enum udev_ctrl_msg_type type,
|
typedef int (*udev_ctrl_handler_t)(UdevCtrl *udev_ctrl, UdevCtrlMessageType type,
|
||||||
const union udev_ctrl_msg_value *value, void *userdata);
|
const UdevCtrlMessageValue *value, void *userdata);
|
||||||
|
|
||||||
int udev_ctrl_new_from_fd(struct udev_ctrl **ret, int fd);
|
int udev_ctrl_new_from_fd(UdevCtrl **ret, int fd);
|
||||||
static inline int udev_ctrl_new(struct udev_ctrl **ret) {
|
static inline int udev_ctrl_new(UdevCtrl **ret) {
|
||||||
return udev_ctrl_new_from_fd(ret, -1);
|
return udev_ctrl_new_from_fd(ret, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl);
|
int udev_ctrl_enable_receiving(UdevCtrl *uctrl);
|
||||||
struct udev_ctrl *udev_ctrl_ref(struct udev_ctrl *uctrl);
|
UdevCtrl *udev_ctrl_ref(UdevCtrl *uctrl);
|
||||||
struct udev_ctrl *udev_ctrl_unref(struct udev_ctrl *uctrl);
|
UdevCtrl *udev_ctrl_unref(UdevCtrl *uctrl);
|
||||||
int udev_ctrl_cleanup(struct udev_ctrl *uctrl);
|
int udev_ctrl_cleanup(UdevCtrl *uctrl);
|
||||||
int udev_ctrl_attach_event(struct udev_ctrl *uctrl, sd_event *event);
|
int udev_ctrl_attach_event(UdevCtrl *uctrl, sd_event *event);
|
||||||
int udev_ctrl_start(struct udev_ctrl *uctrl, udev_ctrl_handler_t callback, void *userdata);
|
int udev_ctrl_start(UdevCtrl *uctrl, udev_ctrl_handler_t callback, void *userdata);
|
||||||
sd_event_source *udev_ctrl_get_event_source(struct udev_ctrl *uctrl);
|
sd_event_source *udev_ctrl_get_event_source(UdevCtrl *uctrl);
|
||||||
|
|
||||||
int udev_ctrl_wait(struct udev_ctrl *uctrl, usec_t timeout);
|
int udev_ctrl_wait(UdevCtrl *uctrl, usec_t timeout);
|
||||||
|
|
||||||
int udev_ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int intval, const char *buf);
|
int udev_ctrl_send(UdevCtrl *uctrl, UdevCtrlMessageType type, int intval, const char *buf);
|
||||||
static inline int udev_ctrl_send_set_log_level(struct udev_ctrl *uctrl, int priority) {
|
static inline int udev_ctrl_send_set_log_level(UdevCtrl *uctrl, int priority) {
|
||||||
return udev_ctrl_send(uctrl, UDEV_CTRL_SET_LOG_LEVEL, priority, NULL);
|
return udev_ctrl_send(uctrl, UDEV_CTRL_SET_LOG_LEVEL, priority, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl) {
|
static inline int udev_ctrl_send_stop_exec_queue(UdevCtrl *uctrl) {
|
||||||
return udev_ctrl_send(uctrl, UDEV_CTRL_STOP_EXEC_QUEUE, 0, NULL);
|
return udev_ctrl_send(uctrl, UDEV_CTRL_STOP_EXEC_QUEUE, 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl) {
|
static inline int udev_ctrl_send_start_exec_queue(UdevCtrl *uctrl) {
|
||||||
return udev_ctrl_send(uctrl, UDEV_CTRL_START_EXEC_QUEUE, 0, NULL);
|
return udev_ctrl_send(uctrl, UDEV_CTRL_START_EXEC_QUEUE, 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int udev_ctrl_send_reload(struct udev_ctrl *uctrl) {
|
static inline int udev_ctrl_send_reload(UdevCtrl *uctrl) {
|
||||||
return udev_ctrl_send(uctrl, UDEV_CTRL_RELOAD, 0, NULL);
|
return udev_ctrl_send(uctrl, UDEV_CTRL_RELOAD, 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key) {
|
static inline int udev_ctrl_send_set_env(UdevCtrl *uctrl, const char *key) {
|
||||||
return udev_ctrl_send(uctrl, UDEV_CTRL_SET_ENV, 0, key);
|
return udev_ctrl_send(uctrl, UDEV_CTRL_SET_ENV, 0, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int udev_ctrl_send_set_children_max(struct udev_ctrl *uctrl, int count) {
|
static inline int udev_ctrl_send_set_children_max(UdevCtrl *uctrl, int count) {
|
||||||
return udev_ctrl_send(uctrl, UDEV_CTRL_SET_CHILDREN_MAX, count, NULL);
|
return udev_ctrl_send(uctrl, UDEV_CTRL_SET_CHILDREN_MAX, count, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int udev_ctrl_send_ping(struct udev_ctrl *uctrl) {
|
static inline int udev_ctrl_send_ping(UdevCtrl *uctrl) {
|
||||||
return udev_ctrl_send(uctrl, UDEV_CTRL_PING, 0, NULL);
|
return udev_ctrl_send(uctrl, UDEV_CTRL_PING, 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int udev_ctrl_send_exit(struct udev_ctrl *uctrl) {
|
static inline int udev_ctrl_send_exit(UdevCtrl *uctrl) {
|
||||||
return udev_ctrl_send(uctrl, UDEV_CTRL_EXIT, 0, NULL);
|
return udev_ctrl_send(uctrl, UDEV_CTRL_EXIT, 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_ctrl*, udev_ctrl_unref);
|
DEFINE_TRIVIAL_CLEANUP_FUNC(UdevCtrl*, udev_ctrl_unref);
|
||||||
|
|||||||
@ -1154,7 +1154,7 @@ static void rule_resolve_goto(UdevRuleFile *rule_file) {
|
|||||||
if (!FLAGS_SET(line->type, LINE_HAS_GOTO))
|
if (!FLAGS_SET(line->type, LINE_HAS_GOTO))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
LIST_FOREACH_AFTER(rule_lines, i, line)
|
LIST_FOREACH(rule_lines, i, line->rule_lines_next)
|
||||||
if (streq_ptr(i->label, line->goto_label)) {
|
if (streq_ptr(i->label, line->goto_label)) {
|
||||||
line->goto_line = i;
|
line->goto_line = i;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -48,7 +48,7 @@ static int help(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int control_main(int argc, char *argv[], void *userdata) {
|
int control_main(int argc, char *argv[], void *userdata) {
|
||||||
_cleanup_(udev_ctrl_unrefp) struct udev_ctrl *uctrl = NULL;
|
_cleanup_(udev_ctrl_unrefp) UdevCtrl *uctrl = NULL;
|
||||||
usec_t timeout = 60 * USEC_PER_SEC;
|
usec_t timeout = 60 * USEC_PER_SEC;
|
||||||
int c, r;
|
int c, r;
|
||||||
|
|
||||||
|
|||||||
@ -176,7 +176,7 @@ int settle_main(int argc, char *argv[], void *userdata) {
|
|||||||
|
|
||||||
/* guarantee that the udev daemon isn't pre-processing */
|
/* guarantee that the udev daemon isn't pre-processing */
|
||||||
if (getuid() == 0) {
|
if (getuid() == 0) {
|
||||||
_cleanup_(udev_ctrl_unrefp) struct udev_ctrl *uctrl = NULL;
|
_cleanup_(udev_ctrl_unrefp) UdevCtrl *uctrl = NULL;
|
||||||
|
|
||||||
if (udev_ctrl_new(&uctrl) >= 0) {
|
if (udev_ctrl_new(&uctrl) >= 0) {
|
||||||
r = udev_ctrl_send_ping(uctrl);
|
r = udev_ctrl_send_ping(uctrl);
|
||||||
|
|||||||
@ -421,7 +421,7 @@ int trigger_main(int argc, char *argv[], void *userdata) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ping) {
|
if (ping) {
|
||||||
_cleanup_(udev_ctrl_unrefp) struct udev_ctrl *uctrl = NULL;
|
_cleanup_(udev_ctrl_unrefp) UdevCtrl *uctrl = NULL;
|
||||||
|
|
||||||
r = udev_ctrl_new(&uctrl);
|
r = udev_ctrl_new(&uctrl);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
|||||||
657
src/udev/udevd.c
657
src/udev/udevd.c
@ -77,10 +77,13 @@ static usec_t arg_event_timeout_usec = 180 * USEC_PER_SEC;
|
|||||||
static int arg_timeout_signal = SIGKILL;
|
static int arg_timeout_signal = SIGKILL;
|
||||||
static bool arg_blockdev_read_only = false;
|
static bool arg_blockdev_read_only = false;
|
||||||
|
|
||||||
|
typedef struct Event Event;
|
||||||
|
typedef struct Worker Worker;
|
||||||
|
|
||||||
typedef struct Manager {
|
typedef struct Manager {
|
||||||
sd_event *event;
|
sd_event *event;
|
||||||
Hashmap *workers;
|
Hashmap *workers;
|
||||||
LIST_HEAD(struct event, events);
|
LIST_HEAD(Event, events);
|
||||||
const char *cgroup;
|
const char *cgroup;
|
||||||
pid_t pid; /* the process that originally allocated the manager object */
|
pid_t pid; /* the process that originally allocated the manager object */
|
||||||
int log_level;
|
int log_level;
|
||||||
@ -91,7 +94,7 @@ typedef struct Manager {
|
|||||||
sd_netlink *rtnl;
|
sd_netlink *rtnl;
|
||||||
|
|
||||||
sd_device_monitor *monitor;
|
sd_device_monitor *monitor;
|
||||||
struct udev_ctrl *ctrl;
|
UdevCtrl *ctrl;
|
||||||
int worker_watch[2];
|
int worker_watch[2];
|
||||||
|
|
||||||
/* used by udev-watch */
|
/* used by udev-watch */
|
||||||
@ -106,54 +109,52 @@ typedef struct Manager {
|
|||||||
bool exit;
|
bool exit;
|
||||||
} Manager;
|
} Manager;
|
||||||
|
|
||||||
enum event_state {
|
typedef enum EventState {
|
||||||
EVENT_UNDEF,
|
EVENT_UNDEF,
|
||||||
EVENT_QUEUED,
|
EVENT_QUEUED,
|
||||||
EVENT_RUNNING,
|
EVENT_RUNNING,
|
||||||
};
|
} EventState;
|
||||||
|
|
||||||
struct event {
|
typedef struct Event {
|
||||||
Manager *manager;
|
Manager *manager;
|
||||||
struct worker *worker;
|
Worker *worker;
|
||||||
enum event_state state;
|
EventState state;
|
||||||
|
|
||||||
sd_device *dev;
|
sd_device *dev;
|
||||||
sd_device *dev_kernel; /* clone of originally received device */
|
sd_device *dev_kernel; /* clone of originally received device */
|
||||||
|
|
||||||
uint64_t seqnum;
|
uint64_t seqnum;
|
||||||
uint64_t delaying_seqnum;
|
uint64_t blocker_seqnum;
|
||||||
|
|
||||||
sd_event_source *timeout_warning_event;
|
sd_event_source *timeout_warning_event;
|
||||||
sd_event_source *timeout_event;
|
sd_event_source *timeout_event;
|
||||||
|
|
||||||
LIST_FIELDS(struct event, event);
|
LIST_FIELDS(Event, event);
|
||||||
};
|
} Event;
|
||||||
|
|
||||||
static void event_queue_cleanup(Manager *manager, enum event_state type);
|
typedef enum WorkerState {
|
||||||
|
|
||||||
enum worker_state {
|
|
||||||
WORKER_UNDEF,
|
WORKER_UNDEF,
|
||||||
WORKER_RUNNING,
|
WORKER_RUNNING,
|
||||||
WORKER_IDLE,
|
WORKER_IDLE,
|
||||||
WORKER_KILLED,
|
WORKER_KILLED,
|
||||||
WORKER_KILLING,
|
WORKER_KILLING,
|
||||||
};
|
} WorkerState;
|
||||||
|
|
||||||
struct worker {
|
typedef struct Worker {
|
||||||
Manager *manager;
|
Manager *manager;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
sd_device_monitor *monitor;
|
sd_device_monitor *monitor;
|
||||||
enum worker_state state;
|
WorkerState state;
|
||||||
struct event *event;
|
Event *event;
|
||||||
};
|
} Worker;
|
||||||
|
|
||||||
/* passed from worker to main process */
|
/* passed from worker to main process */
|
||||||
struct worker_message {
|
typedef struct WorkerMessage {
|
||||||
};
|
} WorkerMessage;
|
||||||
|
|
||||||
static void event_free(struct event *event) {
|
static Event *event_free(Event *event) {
|
||||||
if (!event)
|
if (!event)
|
||||||
return;
|
return NULL;
|
||||||
|
|
||||||
assert(event->manager);
|
assert(event->manager);
|
||||||
|
|
||||||
@ -170,13 +171,24 @@ static void event_free(struct event *event) {
|
|||||||
/* only clean up the queue from the process that created it */
|
/* only clean up the queue from the process that created it */
|
||||||
if (LIST_IS_EMPTY(event->manager->events) &&
|
if (LIST_IS_EMPTY(event->manager->events) &&
|
||||||
event->manager->pid == getpid_cached())
|
event->manager->pid == getpid_cached())
|
||||||
if (unlink("/run/udev/queue") < 0)
|
if (unlink("/run/udev/queue") < 0 && errno != ENOENT)
|
||||||
log_warning_errno(errno, "Failed to unlink /run/udev/queue: %m");
|
log_warning_errno(errno, "Failed to unlink /run/udev/queue, ignoring: %m");
|
||||||
|
|
||||||
free(event);
|
return mfree(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct worker* worker_free(struct worker *worker) {
|
static void event_queue_cleanup(Manager *manager, EventState match_state) {
|
||||||
|
Event *event, *tmp;
|
||||||
|
|
||||||
|
LIST_FOREACH_SAFE(event, event, tmp, manager->events) {
|
||||||
|
if (match_state != EVENT_UNDEF && match_state != event->state)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
event_free(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Worker *worker_free(Worker *worker) {
|
||||||
if (!worker)
|
if (!worker)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@ -189,89 +201,8 @@ static struct worker* worker_free(struct worker *worker) {
|
|||||||
return mfree(worker);
|
return mfree(worker);
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_TRIVIAL_CLEANUP_FUNC(struct worker *, worker_free);
|
DEFINE_TRIVIAL_CLEANUP_FUNC(Worker*, worker_free);
|
||||||
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(worker_hash_op, void, trivial_hash_func, trivial_compare_func, struct worker, worker_free);
|
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(worker_hash_op, void, trivial_hash_func, trivial_compare_func, Worker, worker_free);
|
||||||
|
|
||||||
static int worker_new(struct worker **ret, Manager *manager, sd_device_monitor *worker_monitor, pid_t pid) {
|
|
||||||
_cleanup_(worker_freep) struct worker *worker = NULL;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
assert(ret);
|
|
||||||
assert(manager);
|
|
||||||
assert(worker_monitor);
|
|
||||||
assert(pid > 1);
|
|
||||||
|
|
||||||
/* close monitor, but keep address around */
|
|
||||||
device_monitor_disconnect(worker_monitor);
|
|
||||||
|
|
||||||
worker = new(struct worker, 1);
|
|
||||||
if (!worker)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
*worker = (struct worker) {
|
|
||||||
.manager = manager,
|
|
||||||
.monitor = sd_device_monitor_ref(worker_monitor),
|
|
||||||
.pid = pid,
|
|
||||||
};
|
|
||||||
|
|
||||||
r = hashmap_ensure_put(&manager->workers, &worker_hash_op, PID_TO_PTR(pid), worker);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
*ret = TAKE_PTR(worker);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int on_event_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
|
|
||||||
struct event *event = userdata;
|
|
||||||
|
|
||||||
assert(event);
|
|
||||||
assert(event->worker);
|
|
||||||
|
|
||||||
kill_and_sigcont(event->worker->pid, arg_timeout_signal);
|
|
||||||
event->worker->state = WORKER_KILLED;
|
|
||||||
|
|
||||||
log_device_error(event->dev, "Worker ["PID_FMT"] processing SEQNUM=%"PRIu64" killed", event->worker->pid, event->seqnum);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int on_event_timeout_warning(sd_event_source *s, uint64_t usec, void *userdata) {
|
|
||||||
struct event *event = userdata;
|
|
||||||
|
|
||||||
assert(event);
|
|
||||||
assert(event->worker);
|
|
||||||
|
|
||||||
log_device_warning(event->dev, "Worker ["PID_FMT"] processing SEQNUM=%"PRIu64" is taking a long time", event->worker->pid, event->seqnum);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void worker_attach_event(struct worker *worker, struct event *event) {
|
|
||||||
sd_event *e;
|
|
||||||
|
|
||||||
assert(worker);
|
|
||||||
assert(worker->manager);
|
|
||||||
assert(event);
|
|
||||||
assert(!event->worker);
|
|
||||||
assert(!worker->event);
|
|
||||||
|
|
||||||
worker->state = WORKER_RUNNING;
|
|
||||||
worker->event = event;
|
|
||||||
event->state = EVENT_RUNNING;
|
|
||||||
event->worker = worker;
|
|
||||||
|
|
||||||
e = worker->manager->event;
|
|
||||||
|
|
||||||
(void) sd_event_add_time_relative(e, &event->timeout_warning_event, CLOCK_MONOTONIC,
|
|
||||||
udev_warn_timeout(arg_event_timeout_usec), USEC_PER_SEC,
|
|
||||||
on_event_timeout_warning, event);
|
|
||||||
|
|
||||||
(void) sd_event_add_time_relative(e, &event->timeout_event, CLOCK_MONOTONIC,
|
|
||||||
arg_event_timeout_usec, USEC_PER_SEC,
|
|
||||||
on_event_timeout, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void manager_clear_for_worker(Manager *manager) {
|
static void manager_clear_for_worker(Manager *manager) {
|
||||||
assert(manager);
|
assert(manager);
|
||||||
@ -314,8 +245,109 @@ static Manager* manager_free(Manager *manager) {
|
|||||||
|
|
||||||
DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
|
DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
|
||||||
|
|
||||||
|
static int worker_new(Worker **ret, Manager *manager, sd_device_monitor *worker_monitor, pid_t pid) {
|
||||||
|
_cleanup_(worker_freep) Worker *worker = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(ret);
|
||||||
|
assert(manager);
|
||||||
|
assert(worker_monitor);
|
||||||
|
assert(pid > 1);
|
||||||
|
|
||||||
|
/* close monitor, but keep address around */
|
||||||
|
device_monitor_disconnect(worker_monitor);
|
||||||
|
|
||||||
|
worker = new(Worker, 1);
|
||||||
|
if (!worker)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
*worker = (Worker) {
|
||||||
|
.manager = manager,
|
||||||
|
.monitor = sd_device_monitor_ref(worker_monitor),
|
||||||
|
.pid = pid,
|
||||||
|
};
|
||||||
|
|
||||||
|
r = hashmap_ensure_put(&manager->workers, &worker_hash_op, PID_TO_PTR(pid), worker);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
*ret = TAKE_PTR(worker);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void manager_kill_workers(Manager *manager, bool force) {
|
||||||
|
Worker *worker;
|
||||||
|
|
||||||
|
assert(manager);
|
||||||
|
|
||||||
|
HASHMAP_FOREACH(worker, manager->workers) {
|
||||||
|
if (worker->state == WORKER_KILLED)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (worker->state == WORKER_RUNNING && !force) {
|
||||||
|
worker->state = WORKER_KILLING;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
worker->state = WORKER_KILLED;
|
||||||
|
(void) kill(worker->pid, SIGTERM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void manager_exit(Manager *manager) {
|
||||||
|
assert(manager);
|
||||||
|
|
||||||
|
manager->exit = true;
|
||||||
|
|
||||||
|
sd_notify(false,
|
||||||
|
"STOPPING=1\n"
|
||||||
|
"STATUS=Starting shutdown...");
|
||||||
|
|
||||||
|
/* close sources of new events and discard buffered events */
|
||||||
|
manager->ctrl = udev_ctrl_unref(manager->ctrl);
|
||||||
|
|
||||||
|
manager->inotify_event = sd_event_source_unref(manager->inotify_event);
|
||||||
|
manager->inotify_fd = safe_close(manager->inotify_fd);
|
||||||
|
|
||||||
|
manager->monitor = sd_device_monitor_unref(manager->monitor);
|
||||||
|
|
||||||
|
/* discard queued events and kill workers */
|
||||||
|
event_queue_cleanup(manager, EVENT_QUEUED);
|
||||||
|
manager_kill_workers(manager, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* reload requested, HUP signal received, rules changed, builtin changed */
|
||||||
|
static void manager_reload(Manager *manager) {
|
||||||
|
|
||||||
|
assert(manager);
|
||||||
|
|
||||||
|
sd_notify(false,
|
||||||
|
"RELOADING=1\n"
|
||||||
|
"STATUS=Flushing configuration...");
|
||||||
|
|
||||||
|
manager_kill_workers(manager, false);
|
||||||
|
manager->rules = udev_rules_free(manager->rules);
|
||||||
|
udev_builtin_exit();
|
||||||
|
|
||||||
|
sd_notifyf(false,
|
||||||
|
"READY=1\n"
|
||||||
|
"STATUS=Processing with %u children at max", arg_children_max);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int on_kill_workers_event(sd_event_source *s, uint64_t usec, void *userdata) {
|
||||||
|
Manager *manager = userdata;
|
||||||
|
|
||||||
|
assert(manager);
|
||||||
|
|
||||||
|
log_debug("Cleanup idle workers");
|
||||||
|
manager_kill_workers(manager, false);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int worker_send_message(int fd) {
|
static int worker_send_message(int fd) {
|
||||||
struct worker_message message = {};
|
WorkerMessage message = {};
|
||||||
|
|
||||||
return loop_write(fd, &message, sizeof(message), false);
|
return loop_write(fd, &message, sizeof(message), false);
|
||||||
}
|
}
|
||||||
@ -591,9 +623,59 @@ static int worker_main(Manager *_manager, sd_device_monitor *monitor, sd_device
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int worker_spawn(Manager *manager, struct event *event) {
|
static int on_event_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
|
||||||
|
Event *event = userdata;
|
||||||
|
|
||||||
|
assert(event);
|
||||||
|
assert(event->worker);
|
||||||
|
|
||||||
|
kill_and_sigcont(event->worker->pid, arg_timeout_signal);
|
||||||
|
event->worker->state = WORKER_KILLED;
|
||||||
|
|
||||||
|
log_device_error(event->dev, "Worker ["PID_FMT"] processing SEQNUM=%"PRIu64" killed", event->worker->pid, event->seqnum);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int on_event_timeout_warning(sd_event_source *s, uint64_t usec, void *userdata) {
|
||||||
|
Event *event = userdata;
|
||||||
|
|
||||||
|
assert(event);
|
||||||
|
assert(event->worker);
|
||||||
|
|
||||||
|
log_device_warning(event->dev, "Worker ["PID_FMT"] processing SEQNUM=%"PRIu64" is taking a long time", event->worker->pid, event->seqnum);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void worker_attach_event(Worker *worker, Event *event) {
|
||||||
|
sd_event *e;
|
||||||
|
|
||||||
|
assert(worker);
|
||||||
|
assert(worker->manager);
|
||||||
|
assert(event);
|
||||||
|
assert(!event->worker);
|
||||||
|
assert(!worker->event);
|
||||||
|
|
||||||
|
worker->state = WORKER_RUNNING;
|
||||||
|
worker->event = event;
|
||||||
|
event->state = EVENT_RUNNING;
|
||||||
|
event->worker = worker;
|
||||||
|
|
||||||
|
e = worker->manager->event;
|
||||||
|
|
||||||
|
(void) sd_event_add_time_relative(e, &event->timeout_warning_event, CLOCK_MONOTONIC,
|
||||||
|
udev_warn_timeout(arg_event_timeout_usec), USEC_PER_SEC,
|
||||||
|
on_event_timeout_warning, event);
|
||||||
|
|
||||||
|
(void) sd_event_add_time_relative(e, &event->timeout_event, CLOCK_MONOTONIC,
|
||||||
|
arg_event_timeout_usec, USEC_PER_SEC,
|
||||||
|
on_event_timeout, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int worker_spawn(Manager *manager, Event *event) {
|
||||||
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *worker_monitor = NULL;
|
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *worker_monitor = NULL;
|
||||||
struct worker *worker;
|
Worker *worker;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -635,16 +717,18 @@ static int worker_spawn(Manager *manager, struct event *event) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void event_run(Manager *manager, struct event *event) {
|
static int event_run(Event *event) {
|
||||||
static bool log_children_max_reached = true;
|
static bool log_children_max_reached = true;
|
||||||
struct worker *worker;
|
Manager *manager;
|
||||||
|
Worker *worker;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(manager);
|
|
||||||
assert(event);
|
assert(event);
|
||||||
|
assert(event->manager);
|
||||||
|
|
||||||
log_device_uevent(event->dev, "Device ready for processing");
|
log_device_uevent(event->dev, "Device ready for processing");
|
||||||
|
|
||||||
|
manager = event->manager;
|
||||||
HASHMAP_FOREACH(worker, manager->workers) {
|
HASHMAP_FOREACH(worker, manager->workers) {
|
||||||
if (worker->state != WORKER_IDLE)
|
if (worker->state != WORKER_IDLE)
|
||||||
continue;
|
continue;
|
||||||
@ -658,110 +742,73 @@ static void event_run(Manager *manager, struct event *event) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
worker_attach_event(worker, event);
|
worker_attach_event(worker, event);
|
||||||
return;
|
return 1; /* event is now processing. */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hashmap_size(manager->workers) >= arg_children_max) {
|
if (hashmap_size(manager->workers) >= arg_children_max) {
|
||||||
|
|
||||||
/* Avoid spamming the debug logs if the limit is already reached and
|
/* Avoid spamming the debug logs if the limit is already reached and
|
||||||
* many events still need to be processed */
|
* many events still need to be processed */
|
||||||
if (log_children_max_reached && arg_children_max > 1) {
|
if (log_children_max_reached && arg_children_max > 1) {
|
||||||
log_debug("Maximum number (%u) of children reached.", hashmap_size(manager->workers));
|
log_debug("Maximum number (%u) of children reached.", hashmap_size(manager->workers));
|
||||||
log_children_max_reached = false;
|
log_children_max_reached = false;
|
||||||
}
|
}
|
||||||
return;
|
return 0; /* no free worker */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Re-enable the debug message for the next batch of events */
|
/* Re-enable the debug message for the next batch of events */
|
||||||
log_children_max_reached = true;
|
log_children_max_reached = true;
|
||||||
|
|
||||||
/* fork with up-to-date SELinux label database, so the child inherits the up-to-date db
|
/* fork with up-to-date SELinux label database, so the child inherits the up-to-date db
|
||||||
and, until the next SELinux policy changes, we safe further reloads in future children */
|
* and, until the next SELinux policy changes, we safe further reloads in future children */
|
||||||
mac_selinux_maybe_reload();
|
mac_selinux_maybe_reload();
|
||||||
|
|
||||||
/* start new worker and pass initial device */
|
/* start new worker and pass initial device */
|
||||||
worker_spawn(manager, event);
|
r = worker_spawn(manager, event);
|
||||||
}
|
|
||||||
|
|
||||||
static int event_queue_insert(Manager *manager, sd_device *dev) {
|
|
||||||
_cleanup_(sd_device_unrefp) sd_device *clone = NULL;
|
|
||||||
struct event *event;
|
|
||||||
uint64_t seqnum;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
assert(manager);
|
|
||||||
assert(dev);
|
|
||||||
|
|
||||||
/* only one process can add events to the queue */
|
|
||||||
assert(manager->pid == getpid_cached());
|
|
||||||
|
|
||||||
/* We only accepts devices received by device monitor. */
|
|
||||||
r = sd_device_get_seqnum(dev, &seqnum);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
/* Save original device to restore the state on failures. */
|
return 1; /* event is now processing. */
|
||||||
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 void manager_kill_workers(Manager *manager, bool force) {
|
static int event_is_blocked(Event *event) {
|
||||||
struct worker *worker;
|
|
||||||
|
|
||||||
assert(manager);
|
|
||||||
|
|
||||||
HASHMAP_FOREACH(worker, manager->workers) {
|
|
||||||
if (worker->state == WORKER_KILLED)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (worker->state == WORKER_RUNNING && !force) {
|
|
||||||
worker->state = WORKER_KILLING;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
worker->state = WORKER_KILLED;
|
|
||||||
(void) kill(worker->pid, SIGTERM);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* lookup event for identical, parent, child device */
|
|
||||||
static int is_device_busy(Manager *manager, struct event *event) {
|
|
||||||
const char *subsystem, *devpath, *devpath_old = NULL;
|
const char *subsystem, *devpath, *devpath_old = NULL;
|
||||||
dev_t devnum = makedev(0, 0);
|
dev_t devnum = makedev(0, 0);
|
||||||
struct event *loop_event;
|
Event *loop_event;
|
||||||
size_t devpath_len;
|
size_t devpath_len;
|
||||||
int r, ifindex = 0;
|
int r, ifindex = 0;
|
||||||
bool is_block;
|
bool is_block;
|
||||||
|
|
||||||
|
/* lookup event for identical, parent, child device */
|
||||||
|
|
||||||
|
assert(event);
|
||||||
|
assert(event->manager);
|
||||||
|
assert(event->blocker_seqnum <= event->seqnum);
|
||||||
|
|
||||||
|
if (event->blocker_seqnum == event->seqnum)
|
||||||
|
/* we have checked previously and no blocker found */
|
||||||
|
return false;
|
||||||
|
|
||||||
|
LIST_FOREACH(event, loop_event, event->manager->events) {
|
||||||
|
/* we already found a later event, earlier cannot block us, no need to check again */
|
||||||
|
if (loop_event->seqnum < event->blocker_seqnum)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* event we checked earlier still exists, no need to check again */
|
||||||
|
if (loop_event->seqnum == event->blocker_seqnum)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/* found ourself, no later event can block us */
|
||||||
|
if (loop_event->seqnum >= event->seqnum)
|
||||||
|
goto no_blocker;
|
||||||
|
|
||||||
|
/* found event we have not checked */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(loop_event);
|
||||||
|
assert(loop_event->seqnum > event->blocker_seqnum &&
|
||||||
|
loop_event->seqnum < event->seqnum);
|
||||||
|
|
||||||
r = sd_device_get_subsystem(event->dev, &subsystem);
|
r = sd_device_get_subsystem(event->dev, &subsystem);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
@ -787,21 +834,13 @@ static int is_device_busy(Manager *manager, struct event *event) {
|
|||||||
return r;
|
return r;
|
||||||
|
|
||||||
/* check if queue contains events we depend on */
|
/* check if queue contains events we depend on */
|
||||||
LIST_FOREACH(event, loop_event, manager->events) {
|
LIST_FOREACH(event, loop_event, loop_event) {
|
||||||
size_t loop_devpath_len, common;
|
size_t loop_devpath_len, common;
|
||||||
const char *loop_devpath;
|
const char *loop_devpath;
|
||||||
|
|
||||||
/* we already found a later event, earlier cannot block us, no need to check again */
|
|
||||||
if (loop_event->seqnum < event->delaying_seqnum)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* event we checked earlier still exists, no need to check again */
|
|
||||||
if (loop_event->seqnum == event->delaying_seqnum)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
/* found ourself, no later event can block us */
|
/* found ourself, no later event can block us */
|
||||||
if (loop_event->seqnum >= event->seqnum)
|
if (loop_event->seqnum >= event->seqnum)
|
||||||
break;
|
goto no_blocker;
|
||||||
|
|
||||||
/* check major/minor */
|
/* check major/minor */
|
||||||
if (major(devnum) != 0) {
|
if (major(devnum) != 0) {
|
||||||
@ -813,7 +852,7 @@ static int is_device_busy(Manager *manager, struct event *event) {
|
|||||||
|
|
||||||
if (sd_device_get_devnum(loop_event->dev, &d) >= 0 &&
|
if (sd_device_get_devnum(loop_event->dev, &d) >= 0 &&
|
||||||
devnum == d && is_block == streq(s, "block"))
|
devnum == d && is_block == streq(s, "block"))
|
||||||
goto set_delaying_seqnum;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check network device ifindex */
|
/* check network device ifindex */
|
||||||
@ -822,7 +861,7 @@ static int is_device_busy(Manager *manager, struct event *event) {
|
|||||||
|
|
||||||
if (sd_device_get_ifindex(loop_event->dev, &i) >= 0 &&
|
if (sd_device_get_ifindex(loop_event->dev, &i) >= 0 &&
|
||||||
ifindex == i)
|
ifindex == i)
|
||||||
goto set_delaying_seqnum;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sd_device_get_devpath(loop_event->dev, &loop_devpath) < 0)
|
if (sd_device_get_devpath(loop_event->dev, &loop_devpath) < 0)
|
||||||
@ -830,7 +869,7 @@ static int is_device_busy(Manager *manager, struct event *event) {
|
|||||||
|
|
||||||
/* check our old name */
|
/* check our old name */
|
||||||
if (devpath_old && streq(devpath_old, loop_devpath))
|
if (devpath_old && streq(devpath_old, loop_devpath))
|
||||||
goto set_delaying_seqnum;
|
break;
|
||||||
|
|
||||||
loop_devpath_len = strlen(loop_devpath);
|
loop_devpath_len = strlen(loop_devpath);
|
||||||
|
|
||||||
@ -843,80 +882,32 @@ static int is_device_busy(Manager *manager, struct event *event) {
|
|||||||
|
|
||||||
/* identical device event found */
|
/* identical device event found */
|
||||||
if (devpath_len == loop_devpath_len)
|
if (devpath_len == loop_devpath_len)
|
||||||
goto set_delaying_seqnum;
|
break;
|
||||||
|
|
||||||
/* parent device event found */
|
/* parent device event found */
|
||||||
if (devpath[common] == '/')
|
if (devpath[common] == '/')
|
||||||
goto set_delaying_seqnum;
|
break;
|
||||||
|
|
||||||
/* child device event found */
|
/* child device event found */
|
||||||
if (loop_devpath[common] == '/')
|
if (loop_devpath[common] == '/')
|
||||||
goto set_delaying_seqnum;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
assert(loop_event);
|
||||||
|
|
||||||
set_delaying_seqnum:
|
|
||||||
log_device_debug(event->dev, "SEQNUM=%" PRIu64 " blocked by SEQNUM=%" PRIu64,
|
log_device_debug(event->dev, "SEQNUM=%" PRIu64 " blocked by SEQNUM=%" PRIu64,
|
||||||
event->seqnum, loop_event->seqnum);
|
event->seqnum, loop_event->seqnum);
|
||||||
|
|
||||||
event->delaying_seqnum = loop_event->seqnum;
|
event->blocker_seqnum = loop_event->seqnum;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
no_blocker:
|
||||||
|
event->blocker_seqnum = event->seqnum;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void manager_exit(Manager *manager) {
|
static int event_queue_start(Manager *manager) {
|
||||||
assert(manager);
|
Event *event, *event_next;
|
||||||
|
|
||||||
manager->exit = true;
|
|
||||||
|
|
||||||
sd_notify(false,
|
|
||||||
"STOPPING=1\n"
|
|
||||||
"STATUS=Starting shutdown...");
|
|
||||||
|
|
||||||
/* close sources of new events and discard buffered events */
|
|
||||||
manager->ctrl = udev_ctrl_unref(manager->ctrl);
|
|
||||||
|
|
||||||
manager->inotify_event = sd_event_source_unref(manager->inotify_event);
|
|
||||||
manager->inotify_fd = safe_close(manager->inotify_fd);
|
|
||||||
|
|
||||||
manager->monitor = sd_device_monitor_unref(manager->monitor);
|
|
||||||
|
|
||||||
/* discard queued events and kill workers */
|
|
||||||
event_queue_cleanup(manager, EVENT_QUEUED);
|
|
||||||
manager_kill_workers(manager, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* reload requested, HUP signal received, rules changed, builtin changed */
|
|
||||||
static void manager_reload(Manager *manager) {
|
|
||||||
|
|
||||||
assert(manager);
|
|
||||||
|
|
||||||
sd_notify(false,
|
|
||||||
"RELOADING=1\n"
|
|
||||||
"STATUS=Flushing configuration...");
|
|
||||||
|
|
||||||
manager_kill_workers(manager, false);
|
|
||||||
manager->rules = udev_rules_free(manager->rules);
|
|
||||||
udev_builtin_exit();
|
|
||||||
|
|
||||||
sd_notifyf(false,
|
|
||||||
"READY=1\n"
|
|
||||||
"STATUS=Processing with %u children at max", arg_children_max);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int on_kill_workers_event(sd_event_source *s, uint64_t usec, void *userdata) {
|
|
||||||
Manager *manager = userdata;
|
|
||||||
|
|
||||||
assert(manager);
|
|
||||||
|
|
||||||
log_debug("Cleanup idle workers");
|
|
||||||
manager_kill_workers(manager, false);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void event_queue_start(Manager *manager) {
|
|
||||||
struct event *event;
|
|
||||||
usec_t usec;
|
usec_t usec;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -924,12 +915,12 @@ static void event_queue_start(Manager *manager) {
|
|||||||
|
|
||||||
if (LIST_IS_EMPTY(manager->events) ||
|
if (LIST_IS_EMPTY(manager->events) ||
|
||||||
manager->exit || manager->stop_exec_queue)
|
manager->exit || manager->stop_exec_queue)
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
assert_se(sd_event_now(manager->event, CLOCK_MONOTONIC, &usec) >= 0);
|
assert_se(sd_event_now(manager->event, CLOCK_MONOTONIC, &usec) >= 0);
|
||||||
/* check for changed config, every 3 seconds at most */
|
/* check for changed config, every 3 seconds at most */
|
||||||
if (manager->last_usec == 0 ||
|
if (manager->last_usec == 0 ||
|
||||||
usec - manager->last_usec > 3 * USEC_PER_SEC) {
|
usec > usec_add(manager->last_usec, 3 * USEC_PER_SEC)) {
|
||||||
if (udev_rules_check_timestamp(manager->rules) ||
|
if (udev_rules_check_timestamp(manager->rules) ||
|
||||||
udev_builtin_validate())
|
udev_builtin_validate())
|
||||||
manager_reload(manager);
|
manager_reload(manager);
|
||||||
@ -945,33 +936,111 @@ static void event_queue_start(Manager *manager) {
|
|||||||
|
|
||||||
if (!manager->rules) {
|
if (!manager->rules) {
|
||||||
r = udev_rules_load(&manager->rules, arg_resolve_name_timing);
|
r = udev_rules_load(&manager->rules, arg_resolve_name_timing);
|
||||||
if (r < 0) {
|
if (r < 0)
|
||||||
log_warning_errno(r, "Failed to read udev rules: %m");
|
return log_warning_errno(r, "Failed to read udev rules: %m");
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LIST_FOREACH(event, event, manager->events) {
|
LIST_FOREACH_SAFE(event, event, event_next, manager->events) {
|
||||||
if (event->state != EVENT_QUEUED)
|
if (event->state != EVENT_QUEUED)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* do not start event if parent or child event is still running */
|
/* do not start event if parent or child event is still running or queued */
|
||||||
if (is_device_busy(manager, event) != 0)
|
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)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
event_run(manager, event);
|
r = event_run(event);
|
||||||
|
if (r <= 0)
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void event_queue_cleanup(Manager *manager, enum event_state match_type) {
|
static int event_queue_insert(Manager *manager, sd_device *dev) {
|
||||||
struct event *event, *tmp;
|
_cleanup_(sd_device_unrefp) sd_device *clone = NULL;
|
||||||
|
Event *event;
|
||||||
|
uint64_t seqnum;
|
||||||
|
int r;
|
||||||
|
|
||||||
LIST_FOREACH_SAFE(event, event, tmp, manager->events) {
|
assert(manager);
|
||||||
if (match_type != EVENT_UNDEF && match_type != event->state)
|
assert(dev);
|
||||||
continue;
|
|
||||||
|
|
||||||
event_free(event);
|
/* only one process can add events to the queue */
|
||||||
|
assert(manager->pid == getpid_cached());
|
||||||
|
|
||||||
|
/* We only accepts devices received by device monitor. */
|
||||||
|
r = sd_device_get_seqnum(dev, &seqnum);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
/* Save original device to restore the state on failures. */
|
||||||
|
r = device_shallow_clone(dev, &clone);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = device_copy_properties(clone, dev);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
event = new(Event, 1);
|
||||||
|
if (!event)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
*event = (Event) {
|
||||||
|
.manager = manager,
|
||||||
|
.dev = sd_device_ref(dev),
|
||||||
|
.dev_kernel = TAKE_PTR(clone),
|
||||||
|
.seqnum = seqnum,
|
||||||
|
.state = EVENT_QUEUED,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (LIST_IS_EMPTY(manager->events)) {
|
||||||
|
r = touch("/run/udev/queue");
|
||||||
|
if (r < 0)
|
||||||
|
log_warning_errno(r, "Failed to touch /run/udev/queue, ignoring: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LIST_APPEND(event, manager->events, event);
|
||||||
|
|
||||||
|
log_device_uevent(dev, "Device is queued");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int on_uevent(sd_device_monitor *monitor, sd_device *dev, void *userdata) {
|
||||||
|
Manager *manager = userdata;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(manager);
|
||||||
|
|
||||||
|
DEVICE_TRACE_POINT(kernel_uevent_received, dev);
|
||||||
|
|
||||||
|
device_ensure_usec_initialized(dev, NULL);
|
||||||
|
|
||||||
|
r = event_queue_insert(manager, dev);
|
||||||
|
if (r < 0) {
|
||||||
|
log_device_error_errno(dev, r, "Failed to insert device into event queue: %m");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we have fresh events, try to schedule them */
|
||||||
|
event_queue_start(manager);
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
|
static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
|
||||||
@ -980,7 +1049,7 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
|
|||||||
assert(manager);
|
assert(manager);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
struct worker_message msg;
|
WorkerMessage msg;
|
||||||
struct iovec iovec = {
|
struct iovec iovec = {
|
||||||
.iov_base = &msg,
|
.iov_base = &msg,
|
||||||
.iov_len = sizeof(msg),
|
.iov_len = sizeof(msg),
|
||||||
@ -994,7 +1063,7 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
|
|||||||
};
|
};
|
||||||
ssize_t size;
|
ssize_t size;
|
||||||
struct ucred *ucred;
|
struct ucred *ucred;
|
||||||
struct worker *worker;
|
Worker *worker;
|
||||||
|
|
||||||
size = recvmsg_safe(fd, &msghdr, MSG_DONTWAIT);
|
size = recvmsg_safe(fd, &msghdr, MSG_DONTWAIT);
|
||||||
if (size == -EINTR)
|
if (size == -EINTR)
|
||||||
@ -1007,7 +1076,7 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
|
|||||||
|
|
||||||
cmsg_close_all(&msghdr);
|
cmsg_close_all(&msghdr);
|
||||||
|
|
||||||
if (size != sizeof(struct worker_message)) {
|
if (size != sizeof(WorkerMessage)) {
|
||||||
log_warning("Ignoring worker message with invalid size %zi bytes", size);
|
log_warning("Ignoring worker message with invalid size %zi bytes", size);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -1041,30 +1110,8 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int on_uevent(sd_device_monitor *monitor, sd_device *dev, void *userdata) {
|
|
||||||
Manager *manager = userdata;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
assert(manager);
|
|
||||||
|
|
||||||
DEVICE_TRACE_POINT(kernel_uevent_received, dev);
|
|
||||||
|
|
||||||
device_ensure_usec_initialized(dev, NULL);
|
|
||||||
|
|
||||||
r = event_queue_insert(manager, dev);
|
|
||||||
if (r < 0) {
|
|
||||||
log_device_error_errno(dev, r, "Failed to insert device into event queue: %m");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* we have fresh events, try to schedule them */
|
|
||||||
event_queue_start(manager);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* receive the udevd message from userspace */
|
/* receive the udevd message from userspace */
|
||||||
static int on_ctrl_msg(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, const union udev_ctrl_msg_value *value, void *userdata) {
|
static int on_ctrl_msg(UdevCtrl *uctrl, UdevCtrlMessageType type, const UdevCtrlMessageValue *value, void *userdata) {
|
||||||
Manager *manager = userdata;
|
Manager *manager = userdata;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -1357,7 +1404,7 @@ static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, voi
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
int status;
|
int status;
|
||||||
struct worker *worker;
|
Worker *worker;
|
||||||
|
|
||||||
pid = waitpid(-1, &status, WNOHANG);
|
pid = waitpid(-1, &status, WNOHANG);
|
||||||
if (pid <= 0)
|
if (pid <= 0)
|
||||||
|
|||||||
@ -674,9 +674,9 @@ class NetworkctlTests(unittest.TestCase, Utilities):
|
|||||||
|
|
||||||
output = check_output('ip -4 address show dev dummy98')
|
output = check_output('ip -4 address show dev dummy98')
|
||||||
print(output)
|
print(output)
|
||||||
self.assertRegex(output, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
|
self.assertIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output)
|
||||||
self.assertRegex(output, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
|
self.assertIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output)
|
||||||
self.assertRegex(output, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
|
self.assertIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output)
|
||||||
|
|
||||||
check_output('ip address del 10.1.2.3/16 dev dummy98')
|
check_output('ip address del 10.1.2.3/16 dev dummy98')
|
||||||
check_output('ip address del 10.1.2.4/16 dev dummy98')
|
check_output('ip address del 10.1.2.4/16 dev dummy98')
|
||||||
@ -687,9 +687,30 @@ class NetworkctlTests(unittest.TestCase, Utilities):
|
|||||||
|
|
||||||
output = check_output('ip -4 address show dev dummy98')
|
output = check_output('ip -4 address show dev dummy98')
|
||||||
print(output)
|
print(output)
|
||||||
self.assertRegex(output, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
|
self.assertIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output)
|
||||||
self.assertRegex(output, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
|
self.assertIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output)
|
||||||
self.assertRegex(output, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
|
self.assertIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output)
|
||||||
|
|
||||||
|
remove_unit_from_networkd_path(['25-address-static.network'])
|
||||||
|
|
||||||
|
check_output(*networkctl_cmd, 'reload', env=env)
|
||||||
|
self.wait_operstate('dummy98', 'degraded', setup_state='unmanaged')
|
||||||
|
|
||||||
|
output = check_output('ip -4 address show dev dummy98')
|
||||||
|
print(output)
|
||||||
|
self.assertNotIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output)
|
||||||
|
self.assertNotIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output)
|
||||||
|
self.assertNotIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output)
|
||||||
|
|
||||||
|
copy_unit_to_networkd_unit_path('25-address-static.network')
|
||||||
|
check_output(*networkctl_cmd, 'reload', env=env)
|
||||||
|
self.wait_online(['dummy98:routable'])
|
||||||
|
|
||||||
|
output = check_output('ip -4 address show dev dummy98')
|
||||||
|
print(output)
|
||||||
|
self.assertIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output)
|
||||||
|
self.assertIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output)
|
||||||
|
self.assertIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output)
|
||||||
|
|
||||||
def test_reload(self):
|
def test_reload(self):
|
||||||
start_networkd(3)
|
start_networkd(3)
|
||||||
|
|||||||
@ -4,4 +4,13 @@ Description=TEST-10-ISSUE-2467
|
|||||||
[Service]
|
[Service]
|
||||||
ExecStartPre=rm -f /failed /testok
|
ExecStartPre=rm -f /failed /testok
|
||||||
Type=oneshot
|
Type=oneshot
|
||||||
ExecStart=sh -e -x -c 'rm -f /tmp/nonexistent; systemctl start test10.socket; printf x >test.file; socat -t20 OPEN:test.file UNIX-CONNECT:/run/test.ctl; >/testok'
|
ExecStart=rm -f /tmp/nonexistent
|
||||||
|
ExecStart=systemctl start test10.socket
|
||||||
|
ExecStart=sh -x -c 'printf x >test.file'
|
||||||
|
ExecStart=-socat -T20 OPEN:test.file UNIX-CONNECT:/run/test.ctl
|
||||||
|
# TriggerLimitIntervalSec= by default is set to 2s. A "sleep 10" should give
|
||||||
|
# systemd enough time even on slower machines, to reach the trigger limit.
|
||||||
|
ExecStart=sleep 10
|
||||||
|
ExecStart=sh -x -c 'test "$(systemctl show test10.socket -P ActiveState)" = failed'
|
||||||
|
ExecStart=sh -x -c 'test "$(systemctl show test10.socket -P Result)" = trigger-limit-hit'
|
||||||
|
ExecStart=sh -x -c 'echo OK >/testok'
|
||||||
|
|||||||
12
units/factory-reset.target
Normal file
12
units/factory-reset.target
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
#
|
||||||
|
# This file is part of systemd.
|
||||||
|
#
|
||||||
|
# systemd is free software; you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU Lesser General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
|
||||||
|
[Unit]
|
||||||
|
Description=Target that triggers factory reset. Does nothing by default.
|
||||||
|
Documentation=man:systemd.special(7)
|
||||||
@ -19,6 +19,7 @@ units = [
|
|||||||
'sysinit.target.wants/'],
|
'sysinit.target.wants/'],
|
||||||
['emergency.target', ''],
|
['emergency.target', ''],
|
||||||
['exit.target', ''],
|
['exit.target', ''],
|
||||||
|
['factory-reset.target', ''],
|
||||||
['final.target', ''],
|
['final.target', ''],
|
||||||
['first-boot-complete.target', ''],
|
['first-boot-complete.target', ''],
|
||||||
['getty.target', '',
|
['getty.target', '',
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user