Features:
+* add "throttling" to sd-event event sources: optionally, when we wake up too
+ often for one, let's turn it off entirely for a while. Use that for the
+ /proc/self/mountinfo logic.
+
* move our systemd-user PAM snippet to /usr/, which PAM appears to support
these days
that are linked to these places instead of copied. After all they are
constant vendor data.
-* maybe add kernel cmdline params: 1) to force first-boot mode + 2) to force
- random seed crediting
+* maybe add kernel cmdline params: to force random seed crediting
* nspawn: on cgroupsv1 issue cgroup empty handler process based on host events,
so that we make cgroup agent logic safe
* support projid-based quota in machinectl for containers
-* maybe use SOURCE_DATE_EPOCH (i.e. the env var the reproducible builds folks
- introduced) as the RTC epoch, instead of the mtime of NEWS.
-
* add a way to lock down cgroup migration: a boolean, which when set for a unit
makes sure the processes in it can never migrate out of it
<listitem><para>Takes a boolean argument, defaults to on. If off,
<citerefentry><refentrytitle>systemd-firstboot.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
- will not query the user for basic system settings, even if the system boots up for the first time and the
- relevant settings are not initialized yet.</para></listitem>
+ will not query the user for basic system settings, even if the system boots up for the first time and
+ the relevant settings are not initialized yet. Not to be confused with
+ <varname>systemd.condition-first-boot=</varname> (see below), which overrides the result of the
+ <varname>ConditionFirstBoot=</varname> unit file condition, and thus controls more than just
+ <filename>systemd-firstboot.service</filename> behaviour.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>systemd.condition-needs-update=</varname></term>
+
+ <listitem><para>Takes a boolean argument. If specified, overrides the result of
+ <varname>ConditionNeedsUpdate=</varname> unit condition checks. See
+ <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
+ details.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>systemd.condition-first-boot=</varname></term>
+
+ <listitem><para>Takes a boolean argument. If specified, overrides the result of
+ <varname>ConditionFirstBoot=</varname> unit condition checks. See
+ <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
+ details. Not to be confused with <varname>systemd.firstboot=</varname> which only controls behaviour
+ of the <filename>systemd-firstboot.service</filename> system service but has no effect on the
+ condition check (see above).</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>systemd.clock-usec=</varname></term>
+
+ <listitem><para>Takes a decimal, numeric timestamp in µs since January 1st 1970, 00:00am, to set the
+ system clock to. The system time is set to the specified timestamp early during
+ boot. It is not propagated to the hardware clock (RTC).</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>systemd.hostname=</varname></term>
+
+ <listitem><para>Accepts a hostname to set during early boot. If specified takes precedence over what
+ is set in <filename>/etc/hostname</filename>. Note that this does not bar later runtime changes to
+ the hostname, it simply controls the initial hostname set during early boot.</para></listitem>
</varlistentry>
</variablelist>
This corresponds to the <constant>org.freedesktop.systemd1.Explicit</constant> annotation
in introspection data.</para></listitem>
</varlistentry>
+
+ <varlistentry>
+ <term><constant>SD_BUS_VTABLE_SENSITIVE</constant></term>
+
+ <listitem><para>Mark this vtable method entry as processing sensitive data. When set,
+ incoming method call messages and their outgoing reply messages are marked as sensitive using
+ <citerefentry><refentrytitle>sd_bus_message_sensitive</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ so that they are erased from memory when freed.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>SD_BUS_VTABLE_ABSOLUTE_OFFSET</constant></term>
+
+ <listitem><para>Mark this vtable method or property entry so that the user data pointer passed to
+ its associated handler functions is determined slightly differently: instead of adding the offset
+ parameter of the entry to the user data pointer specified during vtable registration, the offset is
+ passed directly, converted to a pointer, without taking the user data pointer specified during
+ vtable registration into account.</para></listitem>
+ </varlistentry>
</variablelist>
</refsect2>
</refsect1>
<citerefentry project='man-pages'><refentrytitle>touch</refentrytitle><manvolnum>1</manvolnum></citerefentry>
on it.</para>
+ <para>Note that if the <varname>systemd.condition-needs-update=</varname> kernel command line option is
+ used it overrides the <varname>ConditionNeedsUpdate=</varname> unit condition checks. In that case
+ <filename>systemd-update-done.service</filename> will not reset the condition state until a follow-up
+ reboot where the kernel switch is not specified anymore.</para>
</refsect1>
<refsect1>
<varlistentry>
<term><varname>RequestOptions=</varname></term>
<listitem>
- <para>A whitespace-separated list of integers in the range 1–254.</para>
+ <para>When configured, allows to set arbitrary request options in the DHCPv4 request options list and will be
+ sent to the DHCPV4 server. A whitespace-separated list of integers in the range 1..254. Defaults to unset.</para>
</listitem>
</varlistentry>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>RequestOptions=</varname></term>
+ <listitem>
+ <para>When configured, allows to set arbitrary request options in the DHCPv6 request options list and will
+ sent to the DHCPV6 server. A whitespace-separated list of integers in the range 1..254. Defaults to unset.</para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><varname>ForceDHCPv6PDOtherInformation=</varname></term>
<listitem>
<listitem>
<para>Takes an IPv6 address with prefix length as <varname>Address=</varname> in
the "[Network]" section. Specifies the DHCPv6 client for the requesting router to include
- a prefix-hint in the DHCPv6 solicitation. Prefix ranges 1-128. Defaults to unset.</para>
+ a prefix-hint in the DHCPv6 solicitation. Prefix ranges 1..128. Defaults to unset.</para>
</listitem>
</varlistentry>
<citerefentry><refentrytitle>systemd-update-done.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
to make sure they run before the stamp file's modification time gets reset indicating a completed
update.</para>
+
+ <para>If the <varname>systemd.condition-needs-update=</varname> option is specified on the kernel
+ command line (taking a boolean), it will override the result of this condition check, taking
+ precedence over any file modification time checks. If it is used
+ <filename>systemd-update-done.service</filename> will not have immediate effect on any following
+ <varname>ConditionNeedsUpdate=</varname> checks, until the system is rebooted where the kernel
+ command line option is not specified anymore.</para>
</listitem>
</varlistentry>
(specifically: an <filename>/etc</filename> with no <filename>/etc/machine-id</filename>). This may
be used to populate <filename>/etc</filename> on the first boot after factory reset, or when a new
system instance boots up for the first time.</para>
+
+ <para>If the <varname>systemd.condition-first-boot=</varname> option is specified on the kernel
+ command line (taking a boolean), it will override the result of this condition check, taking
+ precedence over <filename>/etc/machine-id</filename> existence checks.</para>
</listitem>
</varlistentry>
time_epoch = get_option('time-epoch')
if time_epoch == -1
- NEWS = files('NEWS')
- time_epoch = run_command(stat, '-c', '%Y', NEWS).stdout().to_int()
+ source_date_epoch = run_command('sh', ['-c', 'echo "$SOURCE_DATE_EPOCH"']).stdout().strip()
+ if source_date_epoch != ''
+ time_epoch = source_date_epoch.to_int()
+ else
+ NEWS = files('NEWS')
+ time_epoch = run_command(stat, '-c', '%Y', NEWS).stdout().to_int()
+ endif
endif
conf.set('TIME_EPOCH', time_epoch)
r = proc_cmdline_get_key(key, PROC_CMDLINE_VALUE_OPTIONAL, &v);
if (r < 0)
return r;
- if (r == 0) {
+ if (r == 0) { /* key not specified at all */
*ret = false;
return 0;
}
- if (v) { /* parameter passed */
+ if (v) { /* key with parameter passed */
r = parse_boolean(v);
if (r < 0)
return r;
*ret = r;
- } else /* no parameter passed */
+ } else /* key without parameter passed */
*ret = true;
return 1;
#include "log.h"
typedef enum ProcCmdlineFlags {
- PROC_CMDLINE_STRIP_RD_PREFIX = 1 << 0,
- PROC_CMDLINE_VALUE_OPTIONAL = 1 << 1,
- PROC_CMDLINE_RD_STRICT = 1 << 2,
+ PROC_CMDLINE_STRIP_RD_PREFIX = 1 << 0, /* automatically strip "rd." prefix if it is set (and we are in the initrd, since otherwise we'd not consider it anyway) */
+ PROC_CMDLINE_VALUE_OPTIONAL = 1 << 1, /* the value is optional (for boolean switches that can omit the value) */
+ PROC_CMDLINE_RD_STRICT = 1 << 2, /* ignore this in the initrd */
} ProcCmdlineFlags;
typedef int (*proc_cmdline_parse_t)(const char *key, const char *value, void *data);
return r;
}
+
+bool stat_inode_unmodified(const struct stat *a, const struct stat *b) {
+
+ /* Returns if the specified stat structures reference the same, unmodified inode. This check tries to
+ * be reasonably careful when detecting changes: we check both inode and mtime, to cater for file
+ * systems where mtimes are fixed to 0 (think: ostree/nixos type installations). We also check file
+ * size, backing device, inode type and if this refers to a device not the major/minor.
+ *
+ * Note that we don't care if file attributes such as ownership or access mode change, this here is
+ * about contents of the file. The purpose here is to detect file contents changes, and nothing
+ * else. */
+
+ return a && b &&
+ (a->st_mode & S_IFMT) != 0 && /* We use the check for .st_mode if the structure was ever initialized */
+ ((a->st_mode ^ b->st_mode) & S_IFMT) == 0 && /* same inode type */
+ a->st_mtime == b->st_mtime &&
+ (!S_ISREG(a->st_mode) || a->st_size == b->st_size) && /* if regular file, compare file size */
+ a->st_dev == b->st_dev &&
+ a->st_ino == b->st_ino &&
+ (!(S_ISCHR(a->st_mode) || S_ISBLK(a->st_mode)) || a->st_rdev == b->st_rdev); /* if device node, also compare major/minor, because we can */
+}
int device_path_parse_major_minor(const char *path, mode_t *ret_mode, dev_t *ret_devno);
int proc_mounted(void);
+
+bool stat_inode_unmodified(const struct stat *a, const struct stat *b);
#include "hostname-util.h"
#include "log.h"
#include "macro.h"
+#include "proc-cmdline.h"
#include "string-util.h"
#include "util.h"
int hostname_setup(void) {
_cleanup_free_ char *b = NULL;
+ const char *hn = NULL;
bool enoent = false;
- const char *hn;
int r;
- r = read_etc_hostname(NULL, &b);
- if (r < 0) {
- if (r == -ENOENT)
- enoent = true;
- else
- log_warning_errno(r, "Failed to read configured hostname: %m");
+ r = proc_cmdline_get_key("systemd.hostname", 0, &b);
+ if (r < 0)
+ log_warning_errno(r, "Failed to retrieve system hostname from kernel command line, ignoring: %m");
+ else if (r > 0) {
+ if (hostname_is_valid(b, true))
+ hn = b;
+ else {
+ log_warning("Hostname specified on kernel command line is invalid, ignoring: %s", b);
+ b = mfree(b);
+ }
+ }
- hn = NULL;
- } else
- hn = b;
+ if (!hn) {
+ r = read_etc_hostname(NULL, &b);
+ if (r < 0) {
+ if (r == -ENOENT)
+ enoent = true;
+ else
+ log_warning_errno(r, "Failed to read configured hostname: %m");
+ } else
+ hn = b;
+ }
if (isempty(hn)) {
- /* Don't override the hostname if it is already set
- * and not explicitly configured */
+ /* Don't override the hostname if it is already set and not explicitly configured */
if (hostname_is_set())
return 0;
static OOMPolicy arg_default_oom_policy;
static CPUSet arg_cpu_affinity;
static NUMAPolicy arg_numa_policy;
+static usec_t arg_clock_usec;
/* A copy of the original environment block */
static char **saved_env = NULL;
(void) parse_path_argument_and_warn(value, false, &arg_watchdog_device);
+ } else if (proc_cmdline_key_streq(key, "systemd.clock_usec")) {
+
+ if (proc_cmdline_value_missing(key, value))
+ return 0;
+
+ r = safe_atou64(value, &arg_clock_usec);
+ if (r < 0)
+ log_warning_errno(r, "Failed to parse systemd.clock_usec= argument, ignoring: %s", value);
+
} else if (streq(key, "quiet") && !value) {
if (arg_show_status == _SHOW_STATUS_INVALID)
static void initialize_clock(void) {
int r;
+ /* This is called very early on, before we parse the kernel command line or otherwise figure out why
+ * we are running, but only once. */
+
if (clock_is_localtime(NULL) > 0) {
int min;
log_info("System time before build time, advancing clock.");
}
+static void apply_clock_update(void) {
+ struct timespec ts;
+
+ /* This is called later than initialize_clock(), i.e. after we parsed configuration files/kernel
+ * command line and such. */
+
+ if (arg_clock_usec == 0)
+ return;
+
+ if (clock_settime(CLOCK_REALTIME, timespec_store(&ts, arg_clock_usec)) < 0)
+ log_error_errno(errno, "Failed to set system clock to time specified on kernel command line: %m");
+ else {
+ char buf[FORMAT_TIMESTAMP_MAX];
+
+ log_info("Set system clock to %s, as specified on the kernel command line.",
+ format_timestamp(buf, sizeof(buf), arg_clock_usec));
+ }
+}
+
static void initialize_coredump(bool skip_setup) {
#if ENABLE_COREDUMP
if (getpid_cached() != 1)
assert_se(chdir("/") == 0);
if (arg_action == ACTION_RUN) {
+ /* Apply the systemd.clock_usec= kernel command line switch */
+ apply_clock_update();
/* A core pattern might have been specified via the cmdline. */
initialize_core_pattern(skip_setup);
#
# See homed.conf(5) for details
-[Resolve]
+[Home]
#DefaultStorage=
#DefaultFileSystemType=ext4
PROP_CHASSIS,
PROP_DEPLOYMENT,
PROP_LOCATION,
- PROP_KERNEL_NAME,
- PROP_KERNEL_RELEASE,
- PROP_KERNEL_VERSION,
PROP_OS_PRETTY_NAME,
PROP_OS_CPE_NAME,
PROP_HOME_URL,
typedef struct Context {
char *data[_PROP_MAX];
Hashmap *polkit_registry;
- sd_id128_t uuid;
- bool has_uuid;
} Context;
static void context_reset(Context *c) {
c->data[p] = mfree(c->data[p]);
}
-static void context_clear(Context *c) {
+static void context_destroy(Context *c) {
assert(c);
context_reset(c);
static int context_read_data(Context *c) {
int r;
- struct utsname u;
assert(c);
context_reset(c);
- assert_se(uname(&u) >= 0);
- c->data[PROP_KERNEL_NAME] = strdup(u.sysname);
- c->data[PROP_KERNEL_RELEASE] = strdup(u.release);
- c->data[PROP_KERNEL_VERSION] = strdup(u.version);
- if (!c->data[PROP_KERNEL_NAME] || !c->data[PROP_KERNEL_RELEASE] ||
- !c->data[PROP_KERNEL_VERSION])
- return -ENOMEM;
-
c->data[PROP_HOSTNAME] = gethostname_malloc();
if (!c->data[PROP_HOSTNAME])
return -ENOMEM;
if (r < 0 && r != -ENOENT)
return r;
- r = id128_read("/sys/class/dmi/id/product_uuid", ID128_UUID, &c->uuid);
- if (r == -ENOENT)
- r = id128_read("/sys/firmware/devicetree/base/vm,uuid", ID128_UUID, &c->uuid);
- if (r < 0)
- log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
- "Failed to read product UUID, ignoring: %m");
- else if (sd_id128_is_null(c->uuid) || sd_id128_is_allf(c->uuid))
- log_debug("DMI product UUID " SD_ID128_FORMAT_STR " is all 0x00 or all 0xFF, ignoring.", SD_ID128_FORMAT_VAL(c->uuid));
- else
- c->has_uuid = true;
-
return 0;
}
return sd_bus_message_append(reply, "s", name);
}
+static int property_get_uname_field(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ struct utsname u;
+
+ assert_se(uname(&u) >= 0);
+
+ return sd_bus_message_append(reply, "s", (char*) &u + PTR_TO_SIZE(userdata));
+}
+
static int method_set_hostname(sd_bus_message *m, void *userdata, sd_bus_error *error) {
Context *c = userdata;
const char *name;
static int method_get_product_uuid(sd_bus_message *m, void *userdata, sd_bus_error *error) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
Context *c = userdata;
+ bool has_uuid = false;
int interactive, r;
+ sd_id128_t uuid;
assert(m);
assert(c);
- if (!c->has_uuid)
- return sd_bus_error_set(error, BUS_ERROR_NO_PRODUCT_UUID, "Failed to read product UUID from /sys/class/dmi/id/product_uuid");
+ r = id128_read("/sys/class/dmi/id/product_uuid", ID128_UUID, &uuid);
+ if (r == -ENOENT)
+ r = id128_read("/sys/firmware/devicetree/base/vm,uuid", ID128_UUID, &uuid);
+ if (r < 0)
+ log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
+ "Failed to read product UUID, ignoring: %m");
+ else if (sd_id128_is_null(uuid) || sd_id128_is_allf(uuid))
+ log_debug("DMI product UUID " SD_ID128_FORMAT_STR " is all 0x00 or all 0xFF, ignoring.", SD_ID128_FORMAT_VAL(uuid));
+ else
+ has_uuid = true;
+
+ if (!has_uuid)
+ return sd_bus_error_set(error, BUS_ERROR_NO_PRODUCT_UUID,
+ "Failed to read product UUID from firmware.");
r = sd_bus_message_read(m, "b", &interactive);
if (r < 0)
if (r < 0)
return r;
- r = sd_bus_message_append_array(reply, 'y', &c->uuid, sizeof(c->uuid));
+ r = sd_bus_message_append_array(reply, 'y', &uuid, sizeof(uuid));
if (r < 0)
return r;
SD_BUS_PROPERTY("Chassis", "s", property_get_chassis, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("Deployment", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_DEPLOYMENT, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("Location", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_LOCATION, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("KernelName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("KernelRelease", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_RELEASE, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("KernelVersion", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_VERSION, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("KernelName", "s", property_get_uname_field, offsetof(struct utsname, sysname), SD_BUS_VTABLE_ABSOLUTE_OFFSET|SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("KernelRelease", "s", property_get_uname_field, offsetof(struct utsname, release), SD_BUS_VTABLE_ABSOLUTE_OFFSET|SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("KernelVersion", "s", property_get_uname_field, offsetof(struct utsname, version), SD_BUS_VTABLE_ABSOLUTE_OFFSET|SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("OperatingSystemPrettyName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_OS_PRETTY_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("OperatingSystemCPEName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_OS_CPE_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("HomeURL", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_HOME_URL, SD_BUS_VTABLE_PROPERTY_CONST),
}
static int run(int argc, char *argv[]) {
- _cleanup_(context_clear) Context context = {};
+ _cleanup_(context_destroy) Context context = {};
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
int r;
cursor);
}
- return process_journal_input(u, 1 + !!after_cursor);
+ return process_journal_input(u, !!after_cursor);
}
r = dhcp_validate_duid_len(duid_type, duid_len, false);
if (r < 0)
return log_dhcp6_client_errno(client, r, "Failed to validate length of DUID: %m");
- log_dhcp6_client(client, "Setting DUID of type %u with unexpected content", duid_type);
+
+ log_dhcp6_client(client, "Using DUID of type %u of incorrect length, proceeding.", duid_type);
}
client->duid.type = htobe16(duid_type);
assert_return(client, -EINVAL);
assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
- switch(option) {
-
- case SD_DHCP6_OPTION_DNS_SERVERS:
- case SD_DHCP6_OPTION_DOMAIN_LIST:
- case SD_DHCP6_OPTION_SNTP_SERVERS:
- case SD_DHCP6_OPTION_NTP_SERVER:
- case SD_DHCP6_OPTION_RAPID_COMMIT:
- break;
-
- default:
+ if (option <= 0 || option >= 255)
return -EINVAL;
- }
for (t = 0; t < client->req_opts_len; t++)
if (client->req_opts[t] == htobe16(option))
assert_se(sd_dhcp6_client_set_fqdn(client, "~host") == -EINVAL);
assert_se(sd_dhcp6_client_set_fqdn(client, "~host.domain") == -EINVAL);
- assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_CLIENTID) == -EINVAL);
+ assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_CLIENTID) == 0);
assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_DNS_SERVERS) == -EEXIST);
assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_NTP_SERVER) == -EEXIST);
assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_SNTP_SERVERS) == -EEXIST);
assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_DOMAIN_LIST) == -EEXIST);
- assert_se(sd_dhcp6_client_set_request_option(client, 10) == -EINVAL);
+ assert_se(sd_dhcp6_client_set_request_option(client, 10) == 0);
assert_se(sd_dhcp6_client_set_information_request(client, 1) >= 0);
v = 0;
static void *vtable_method_convert_userdata(const sd_bus_vtable *p, void *u) {
assert(p);
- if (!u)
+ if (!u || FLAGS_SET(p->flags, SD_BUS_VTABLE_ABSOLUTE_OFFSET))
return SIZE_TO_PTR(p->x.method.offset); /* don't add offset on NULL, to make ubsan happy */
return (uint8_t*) u + p->x.method.offset;
static void *vtable_property_convert_userdata(const sd_bus_vtable *p, void *u) {
assert(p);
- if (!u)
+ if (!u || FLAGS_SET(p->flags, SD_BUS_VTABLE_ABSOLUTE_OFFSET))
return SIZE_TO_PTR(p->x.property.offset); /* as above */
return (uint8_t*) u + p->x.property.offset;
#include "alloc-util.h"
#include "bond.h"
+#include "bond-util.h"
#include "conf-parser.h"
#include "ether-addr-util.h"
#include "extract-word.h"
#include "netlink-util.h"
#include "networkd-manager.h"
#include "string-table.h"
-#include "string-util.h"
/*
* Number of seconds between instances where the bonding
#define GRATUITOUS_ARP_MAX 255
#define GRATUITOUS_ARP_DEFAULT 1
-static const char* const bond_mode_table[_NETDEV_BOND_MODE_MAX] = {
- [NETDEV_BOND_MODE_BALANCE_RR] = "balance-rr",
- [NETDEV_BOND_MODE_ACTIVE_BACKUP] = "active-backup",
- [NETDEV_BOND_MODE_BALANCE_XOR] = "balance-xor",
- [NETDEV_BOND_MODE_BROADCAST] = "broadcast",
- [NETDEV_BOND_MODE_802_3AD] = "802.3ad",
- [NETDEV_BOND_MODE_BALANCE_TLB] = "balance-tlb",
- [NETDEV_BOND_MODE_BALANCE_ALB] = "balance-alb",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(bond_mode, BondMode);
DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_mode, bond_mode, BondMode, "Failed to parse bond mode");
-
-static const char* const bond_xmit_hash_policy_table[_NETDEV_BOND_XMIT_HASH_POLICY_MAX] = {
- [NETDEV_BOND_XMIT_HASH_POLICY_LAYER2] = "layer2",
- [NETDEV_BOND_XMIT_HASH_POLICY_LAYER34] = "layer3+4",
- [NETDEV_BOND_XMIT_HASH_POLICY_LAYER23] = "layer2+3",
- [NETDEV_BOND_XMIT_HASH_POLICY_ENCAP23] = "encap2+3",
- [NETDEV_BOND_XMIT_HASH_POLICY_ENCAP34] = "encap3+4",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(bond_xmit_hash_policy, BondXmitHashPolicy);
DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_xmit_hash_policy,
bond_xmit_hash_policy,
BondXmitHashPolicy,
- "Failed to parse bond transmit hash policy")
-
-static const char* const bond_lacp_rate_table[_NETDEV_BOND_LACP_RATE_MAX] = {
- [NETDEV_BOND_LACP_RATE_SLOW] = "slow",
- [NETDEV_BOND_LACP_RATE_FAST] = "fast",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(bond_lacp_rate, BondLacpRate);
-DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_lacp_rate, bond_lacp_rate, BondLacpRate, "Failed to parse bond lacp rate")
-
-static const char* const bond_ad_select_table[_NETDEV_BOND_AD_SELECT_MAX] = {
- [NETDEV_BOND_AD_SELECT_STABLE] = "stable",
- [NETDEV_BOND_AD_SELECT_BANDWIDTH] = "bandwidth",
- [NETDEV_BOND_AD_SELECT_COUNT] = "count",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(bond_ad_select, BondAdSelect);
+ "Failed to parse bond transmit hash policy");
+DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_lacp_rate, bond_lacp_rate, BondLacpRate, "Failed to parse bond lacp rate");
DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_ad_select, bond_ad_select, BondAdSelect, "Failed to parse bond AD select");
-
-static const char* const bond_fail_over_mac_table[_NETDEV_BOND_FAIL_OVER_MAC_MAX] = {
- [NETDEV_BOND_FAIL_OVER_MAC_NONE] = "none",
- [NETDEV_BOND_FAIL_OVER_MAC_ACTIVE] = "active",
- [NETDEV_BOND_FAIL_OVER_MAC_FOLLOW] = "follow",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(bond_fail_over_mac, BondFailOverMac);
DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_fail_over_mac, bond_fail_over_mac, BondFailOverMac, "Failed to parse bond fail over MAC");
-
-static const char *const bond_arp_validate_table[_NETDEV_BOND_ARP_VALIDATE_MAX] = {
- [NETDEV_BOND_ARP_VALIDATE_NONE] = "none",
- [NETDEV_BOND_ARP_VALIDATE_ACTIVE]= "active",
- [NETDEV_BOND_ARP_VALIDATE_BACKUP]= "backup",
- [NETDEV_BOND_ARP_VALIDATE_ALL]= "all",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(bond_arp_validate, BondArpValidate);
DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_arp_validate, bond_arp_validate, BondArpValidate, "Failed to parse bond arp validate");
-
-static const char *const bond_arp_all_targets_table[_NETDEV_BOND_ARP_ALL_TARGETS_MAX] = {
- [NETDEV_BOND_ARP_ALL_TARGETS_ANY] = "any",
- [NETDEV_BOND_ARP_ALL_TARGETS_ALL] = "all",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(bond_arp_all_targets, BondArpAllTargets);
DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_arp_all_targets, bond_arp_all_targets, BondArpAllTargets, "Failed to parse bond Arp all targets");
-
-static const char *const bond_primary_reselect_table[_NETDEV_BOND_PRIMARY_RESELECT_MAX] = {
- [NETDEV_BOND_PRIMARY_RESELECT_ALWAYS] = "always",
- [NETDEV_BOND_PRIMARY_RESELECT_BETTER]= "better",
- [NETDEV_BOND_PRIMARY_RESELECT_FAILURE]= "failure",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(bond_primary_reselect, BondPrimaryReselect);
DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_primary_reselect, bond_primary_reselect, BondPrimaryReselect, "Failed to parse bond primary reselect");
static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
#include <netinet/in.h>
#include <linux/if_bonding.h>
-#include "in-addr-util.h"
+#include "bond-util.h"
+#include "macro.h"
#include "netdev.h"
#include "ordered-set.h"
-/*
- * Maximum number of targets supported by the kernel for a single
- * bond netdev.
- */
-#define NETDEV_BOND_ARP_TARGETS_MAX 16
-
-typedef enum BondMode {
- NETDEV_BOND_MODE_BALANCE_RR = BOND_MODE_ROUNDROBIN,
- NETDEV_BOND_MODE_ACTIVE_BACKUP = BOND_MODE_ACTIVEBACKUP,
- NETDEV_BOND_MODE_BALANCE_XOR = BOND_MODE_XOR,
- NETDEV_BOND_MODE_BROADCAST = BOND_MODE_BROADCAST,
- NETDEV_BOND_MODE_802_3AD = BOND_MODE_8023AD,
- NETDEV_BOND_MODE_BALANCE_TLB = BOND_MODE_TLB,
- NETDEV_BOND_MODE_BALANCE_ALB = BOND_MODE_ALB,
- _NETDEV_BOND_MODE_MAX,
- _NETDEV_BOND_MODE_INVALID = -1
-} BondMode;
-
-typedef enum BondXmitHashPolicy {
- NETDEV_BOND_XMIT_HASH_POLICY_LAYER2 = BOND_XMIT_POLICY_LAYER2,
- NETDEV_BOND_XMIT_HASH_POLICY_LAYER34 = BOND_XMIT_POLICY_LAYER34,
- NETDEV_BOND_XMIT_HASH_POLICY_LAYER23 = BOND_XMIT_POLICY_LAYER23,
- NETDEV_BOND_XMIT_HASH_POLICY_ENCAP23 = BOND_XMIT_POLICY_ENCAP23,
- NETDEV_BOND_XMIT_HASH_POLICY_ENCAP34 = BOND_XMIT_POLICY_ENCAP34,
- _NETDEV_BOND_XMIT_HASH_POLICY_MAX,
- _NETDEV_BOND_XMIT_HASH_POLICY_INVALID = -1
-} BondXmitHashPolicy;
-
-typedef enum BondLacpRate {
- NETDEV_BOND_LACP_RATE_SLOW,
- NETDEV_BOND_LACP_RATE_FAST,
- _NETDEV_BOND_LACP_RATE_MAX,
- _NETDEV_BOND_LACP_RATE_INVALID = -1,
-} BondLacpRate;
-
-typedef enum BondAdSelect {
- NETDEV_BOND_AD_SELECT_STABLE,
- NETDEV_BOND_AD_SELECT_BANDWIDTH,
- NETDEV_BOND_AD_SELECT_COUNT,
- _NETDEV_BOND_AD_SELECT_MAX,
- _NETDEV_BOND_AD_SELECT_INVALID = -1,
-} BondAdSelect;
-
-typedef enum BondFailOverMac {
- NETDEV_BOND_FAIL_OVER_MAC_NONE,
- NETDEV_BOND_FAIL_OVER_MAC_ACTIVE,
- NETDEV_BOND_FAIL_OVER_MAC_FOLLOW,
- _NETDEV_BOND_FAIL_OVER_MAC_MAX,
- _NETDEV_BOND_FAIL_OVER_MAC_INVALID = -1,
-} BondFailOverMac;
-
-typedef enum BondArpValidate {
- NETDEV_BOND_ARP_VALIDATE_NONE,
- NETDEV_BOND_ARP_VALIDATE_ACTIVE,
- NETDEV_BOND_ARP_VALIDATE_BACKUP,
- NETDEV_BOND_ARP_VALIDATE_ALL,
- _NETDEV_BOND_ARP_VALIDATE_MAX,
- _NETDEV_BOND_ARP_VALIDATE_INVALID = -1,
-} BondArpValidate;
-
-typedef enum BondArpAllTargets {
- NETDEV_BOND_ARP_ALL_TARGETS_ANY,
- NETDEV_BOND_ARP_ALL_TARGETS_ALL,
- _NETDEV_BOND_ARP_ALL_TARGETS_MAX,
- _NETDEV_BOND_ARP_ALL_TARGETS_INVALID = -1,
-} BondArpAllTargets;
-
-typedef enum BondPrimaryReselect {
- NETDEV_BOND_PRIMARY_RESELECT_ALWAYS,
- NETDEV_BOND_PRIMARY_RESELECT_BETTER,
- NETDEV_BOND_PRIMARY_RESELECT_FAILURE,
- _NETDEV_BOND_PRIMARY_RESELECT_MAX,
- _NETDEV_BOND_PRIMARY_RESELECT_INVALID = -1,
-} BondPrimaryReselect;
-
typedef struct Bond {
NetDev meta;
int link_set_bond(Link *link);
-const char *bond_mode_to_string(BondMode d) _const_;
-BondMode bond_mode_from_string(const char *d) _pure_;
-
-const char *bond_xmit_hash_policy_to_string(BondXmitHashPolicy d) _const_;
-BondXmitHashPolicy bond_xmit_hash_policy_from_string(const char *d) _pure_;
-
-const char *bond_lacp_rate_to_string(BondLacpRate d) _const_;
-BondLacpRate bond_lacp_rate_from_string(const char *d) _pure_;
-
-const char *bond_fail_over_mac_to_string(BondFailOverMac d) _const_;
-BondFailOverMac bond_fail_over_mac_from_string(const char *d) _pure_;
-
-const char *bond_ad_select_to_string(BondAdSelect d) _const_;
-BondAdSelect bond_ad_select_from_string(const char *d) _pure_;
-
-const char *bond_arp_validate_to_string(BondArpValidate d) _const_;
-BondArpValidate bond_arp_validate_from_string(const char *d) _pure_;
-
-const char *bond_arp_all_targets_to_string(BondArpAllTargets d) _const_;
-BondArpAllTargets bond_arp_all_targets_from_string(const char *d) _pure_;
-
-const char *bond_primary_reselect_to_string(BondPrimaryReselect d) _const_;
-BondPrimaryReselect bond_primary_reselect_from_string(const char *d) _pure_;
-
CONFIG_PARSER_PROTOTYPE(config_parse_bond_mode);
CONFIG_PARSER_PROTOTYPE(config_parse_bond_xmit_hash_policy);
CONFIG_PARSER_PROTOTYPE(config_parse_bond_lacp_rate);
#include "sd-network.h"
#include "alloc-util.h"
+#include "bond-util.h"
#include "bus-common-errors.h"
#include "bus-error.h"
#include "bus-util.h"
uint16_t dest_port;
+ uint8_t proxy;
+ uint8_t learning;
+ uint8_t inerit;
+ uint8_t rsc;
+ uint8_t l2miss;
+ uint8_t l3miss;
+ uint8_t tos;
+ uint8_t ttl;
} VxLanInfo;
typedef struct LinkInfo {
(void) sd_netlink_message_read_u32(m, IFLA_VXLAN_LINK, &info->vxlan_info.link);
(void) sd_netlink_message_read_u16(m, IFLA_VXLAN_PORT, &info->vxlan_info.dest_port);
+ (void) sd_netlink_message_read_u8(m, IFLA_VXLAN_PROXY, &info->vxlan_info.proxy);
+ (void) sd_netlink_message_read_u8(m, IFLA_VXLAN_LEARNING, &info->vxlan_info.learning);
+ (void) sd_netlink_message_read_u8(m, IFLA_VXLAN_RSC, &info->vxlan_info.rsc);
+ (void) sd_netlink_message_read_u8(m, IFLA_VXLAN_L3MISS, &info->vxlan_info.l3miss);
+ (void) sd_netlink_message_read_u8(m, IFLA_VXLAN_L2MISS, &info->vxlan_info.l2miss);
+ (void) sd_netlink_message_read_u8(m, IFLA_VXLAN_TOS, &info->vxlan_info.tos);
+ (void) sd_netlink_message_read_u8(m, IFLA_VXLAN_TTL, &info->vxlan_info.ttl);
} else if (streq(received_kind, "vlan"))
(void) sd_netlink_message_read_u16(m, IFLA_VLAN_ID, &info->vlan_id);
else if (STR_IN_SET(received_kind, "ipip", "sit")) {
TABLE_STRING, bridge_state_to_string(info->port_state));
}
} else if (streq_ptr(info->netdev_kind, "bond")) {
- static const struct {
- const char *mode;
- } mode_table[] = {
- { "balance-rr" },
- { "active-backup" },
- { "balance-xor" },
- { "broadcast" },
- { "802.3ad" },
- { "balance-tlb" },
- { "balance-alb" },
- };
-
r = table_add_many(table,
TABLE_EMPTY,
TABLE_STRING, "Mode:",
- TABLE_STRING, mode_table[info->mode],
+ TABLE_STRING, bond_mode_to_string(info->mode),
TABLE_EMPTY,
TABLE_STRING, "Miimon:",
TABLE_TIMESPAN_MSEC, jiffies_to_usec(info->miimon),
return table_log_add_error(r);
} else if (streq_ptr(info->netdev_kind, "vxlan")) {
+ char ttl[CONST_MAX(STRLEN("auto") + 1, DECIMAL_STR_MAX(uint8_t))];
+
if (info->vxlan_info.vni > 0) {
r = table_add_many(table,
TABLE_EMPTY,
if (r < 0)
return table_log_add_error(r);
}
+
+ r = table_add_many(table,
+ TABLE_EMPTY,
+ TABLE_STRING, "Learning:",
+ TABLE_BOOLEAN, info->vxlan_info.learning);
+ if (r < 0)
+ return table_log_add_error(r);
+
+ r = table_add_many(table,
+ TABLE_EMPTY,
+ TABLE_STRING, "RSC:",
+ TABLE_BOOLEAN, info->vxlan_info.rsc);
+ if (r < 0)
+ return table_log_add_error(r);
+
+ r = table_add_many(table,
+ TABLE_EMPTY,
+ TABLE_STRING, "L3MISS:",
+ TABLE_BOOLEAN, info->vxlan_info.l3miss);
+ if (r < 0)
+ return table_log_add_error(r);
+
+ r = table_add_many(table,
+ TABLE_EMPTY,
+ TABLE_STRING, "L2MISS:",
+ TABLE_BOOLEAN, info->vxlan_info.l2miss);
+ if (r < 0)
+ return table_log_add_error(r);
+
+ if (info->vxlan_info.tos > 1) {
+ r = table_add_many(table,
+ TABLE_EMPTY,
+ TABLE_STRING, "TOS:",
+ TABLE_UINT8, info->vxlan_info.tos);
+ if (r < 0)
+ return table_log_add_error(r);
+ }
+
+ if (info->vxlan_info.ttl > 0)
+ xsprintf(ttl, "%" PRIu8, info->vxlan_info.ttl);
+ else
+ strcpy(ttl, "auto");
+
+ r = table_add_many(table,
+ TABLE_EMPTY,
+ TABLE_STRING, "TTL:",
+ TABLE_STRING, ttl);
+ if (r < 0)
+ return table_log_add_error(r);
} else if (streq_ptr(info->netdev_kind, "vlan") && info->vlan_id > 0) {
r = table_add_many(table,
TABLE_EMPTY,
return 0;
}
+int config_parse_dhcp_request_options(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ Network *network = data;
+ const char *p;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ if (isempty(rvalue)) {
+ if (ltype == AF_INET)
+ network->dhcp_request_options = set_free(network->dhcp_request_options);
+ else
+ network->dhcp6_request_options = set_free(network->dhcp6_request_options);
+
+ return 0;
+ }
+
+ for (p = rvalue;;) {
+ _cleanup_free_ char *n = NULL;
+ uint32_t i;
+
+ r = extract_first_word(&p, &n, NULL, 0);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Failed to parse DHCP request option, ignoring assignment: %s",
+ rvalue);
+ return 0;
+ }
+ if (r == 0)
+ return 0;
+
+ r = safe_atou32(n, &i);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "DHCP request option is invalid, ignoring assignment: %s", n);
+ continue;
+ }
+
+ if (i < 1 || i >= 255) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "DHCP request option is invalid, valid range is 1-254, ignoring assignment: %s", n);
+ continue;
+ }
+
+ if (ltype == AF_INET)
+ r = set_ensure_allocated(&network->dhcp_request_options, NULL);
+ else
+ r = set_ensure_allocated(&network->dhcp6_request_options, NULL);
+ if (r < 0)
+ return log_oom();
+
+ if (ltype == AF_INET)
+ r = set_put(network->dhcp_request_options, UINT32_TO_PTR(i));
+ else
+ r = set_put(network->dhcp6_request_options, UINT32_TO_PTR(i));
+ if (r < 0)
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Failed to store DHCP request option '%s', ignoring assignment: %m", n);
+ }
+
+ return 0;
+}
+
DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains, dhcp_use_domains, DHCPUseDomains,
"Failed to parse DHCP use domains setting");
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_pd_hint);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_mud_url);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_send_option);
+CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_request_options);
return 0;
}
-int config_parse_dhcp_request_options(
- const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- Network *network = data;
- const char *p;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if (isempty(rvalue)) {
- network->dhcp_request_options = set_free(network->dhcp_request_options);
- return 0;
- }
-
- for (p = rvalue;;) {
- _cleanup_free_ char *n = NULL;
- uint32_t i;
-
- r = extract_first_word(&p, &n, NULL, 0);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r,
- "Failed to parse DHCP request option, ignoring assignment: %s",
- rvalue);
- return 0;
- }
- if (r == 0)
- return 0;
-
- r = safe_atou32(n, &i);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r,
- "DHCP request option is invalid, ignoring assignment: %s", n);
- continue;
- }
-
- if (i < 1 || i >= 255) {
- log_syntax(unit, LOG_ERR, filename, line, r,
- "DHCP request option is invalid, valid range is 1-254, ignoring assignment: %s", n);
- continue;
- }
-
- r = set_ensure_allocated(&network->dhcp_request_options, NULL);
- if (r < 0)
- return log_oom();
-
- r = set_put(network->dhcp_request_options, UINT32_TO_PTR(i));
- if (r < 0)
- log_syntax(unit, LOG_ERR, filename, line, r,
- "Failed to store DHCP request option '%s', ignoring assignment: %m", n);
- }
-
- return 0;
-}
-
int config_parse_dhcp_ip_service_type(
const char *unit,
const char *filename,
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_black_listed_ip_address);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_max_attempts);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_user_class);
-CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_request_options);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_ip_service_type);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_mud_url);
int dhcp6_configure(Link *link) {
_cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL;
sd_dhcp6_option *send_option;
+ void *request_options;
const DUID *duid;
Iterator i;
int r;
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set MUD URL: %m");
}
+ SET_FOREACH(request_options, link->network->dhcp6_request_options, i) {
+ uint32_t option = PTR_TO_UINT32(request_options);
+
+ r = sd_dhcp6_client_set_request_option(client, option);
+ if (r == -EEXIST) {
+ log_link_debug(link, "DHCP6 CLIENT: Failed to set request flag for '%u' already exists, ignoring.", option);
+ continue;
+ }
+
+ if (r < 0)
+ return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set request flag for '%u': %m", option);
+ }
+
r = sd_dhcp6_client_set_callback(client, dhcp6_handler, link);
if (r < 0)
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set callback: %m");
DHCPv4.UseDomains, config_parse_dhcp_use_domains, 0, offsetof(Network, dhcp_use_domains)
DHCPv4.UseRoutes, config_parse_bool, 0, offsetof(Network, dhcp_use_routes)
DHCPv4.UseGateway, config_parse_tristate, 0, offsetof(Network, dhcp_use_gateway)
-DHCPv4.RequestOptions, config_parse_dhcp_request_options, 0, 0
+DHCPv4.RequestOptions, config_parse_dhcp_request_options, AF_INET, 0
DHCPv4.Anonymize, config_parse_bool, 0, offsetof(Network, dhcp_anonymize)
DHCPv4.SendHostname, config_parse_bool, 0, offsetof(Network, dhcp_send_hostname)
DHCPv4.Hostname, config_parse_hostname, 0, offsetof(Network, dhcp_hostname)
DHCPv6.UseNTP, config_parse_bool, 0, offsetof(Network, dhcp6_use_ntp)
DHCPv6.RapidCommit, config_parse_bool, 0, offsetof(Network, rapid_commit)
DHCPv6.MUDURL, config_parse_dhcp6_mud_url, 0, 0
+DHCPv6.RequestOptions, config_parse_dhcp_request_options, AF_INET6, 0
DHCPv6.ForceDHCPv6PDOtherInformation, config_parse_bool, 0, offsetof(Network, dhcp6_force_pd_other_information)
DHCPv6.PrefixDelegationHint, config_parse_dhcp6_pd_hint, 0, 0
DHCPv6.WithoutRA, config_parse_bool, 0, offsetof(Network, dhcp6_without_ra)
free(network->dhcp_hostname);
set_free(network->dhcp_black_listed_ip);
set_free(network->dhcp_request_options);
+ set_free(network->dhcp6_request_options);
free(network->mac);
free(network->dhcp6_mudurl);
char *dhcp6_mudurl;
struct in6_addr dhcp6_pd_address;
OrderedHashmap *dhcp6_client_send_options;
+ Set *dhcp6_request_options;
/* DHCP Server Support */
bool dhcp_server;
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
+#include <sys/stat.h>
+
#include "sd-event.h"
#include "sd-netlink.h"
#include "sd-network.h"
bool need_builtin_fallbacks:1;
bool read_resolv_conf:1;
- usec_t resolv_conf_mtime;
+ struct stat resolv_conf_stat;
DnsTrustAnchor trust_anchor;
#include "resolved-conf.h"
#include "resolved-dns-server.h"
#include "resolved-resolv-conf.h"
+#include "stat-util.h"
#include "string-util.h"
#include "strv.h"
#include "tmpfile-util-label.h"
}
/* Have we already seen the file? */
- if (timespec_load(&st.st_mtim) == m->resolv_conf_mtime)
+ if (stat_inode_unmodified(&st, &m->resolv_conf_stat))
return 0;
if (file_is_our_own(&st))
log_syntax(NULL, LOG_DEBUG, "/etc/resolv.conf", n, 0, "Ignoring resolv.conf line: %s", l);
}
- m->resolv_conf_mtime = timespec_load(&st.st_mtim);
+ m->resolv_conf_stat = st;
/* Flush out all servers and search domains that are still
* marked. Those are then ones that didn't appear in the new
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "bond-util.h"
+#include "string-table.h"
+
+static const char* const bond_mode_table[_NETDEV_BOND_MODE_MAX] = {
+ [NETDEV_BOND_MODE_BALANCE_RR] = "balance-rr",
+ [NETDEV_BOND_MODE_ACTIVE_BACKUP] = "active-backup",
+ [NETDEV_BOND_MODE_BALANCE_XOR] = "balance-xor",
+ [NETDEV_BOND_MODE_BROADCAST] = "broadcast",
+ [NETDEV_BOND_MODE_802_3AD] = "802.3ad",
+ [NETDEV_BOND_MODE_BALANCE_TLB] = "balance-tlb",
+ [NETDEV_BOND_MODE_BALANCE_ALB] = "balance-alb",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(bond_mode, BondMode);
+
+static const char* const bond_xmit_hash_policy_table[_NETDEV_BOND_XMIT_HASH_POLICY_MAX] = {
+ [NETDEV_BOND_XMIT_HASH_POLICY_LAYER2] = "layer2",
+ [NETDEV_BOND_XMIT_HASH_POLICY_LAYER34] = "layer3+4",
+ [NETDEV_BOND_XMIT_HASH_POLICY_LAYER23] = "layer2+3",
+ [NETDEV_BOND_XMIT_HASH_POLICY_ENCAP23] = "encap2+3",
+ [NETDEV_BOND_XMIT_HASH_POLICY_ENCAP34] = "encap3+4",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(bond_xmit_hash_policy, BondXmitHashPolicy);
+
+static const char* const bond_lacp_rate_table[_NETDEV_BOND_LACP_RATE_MAX] = {
+ [NETDEV_BOND_LACP_RATE_SLOW] = "slow",
+ [NETDEV_BOND_LACP_RATE_FAST] = "fast",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(bond_lacp_rate, BondLacpRate);
+
+static const char* const bond_ad_select_table[_NETDEV_BOND_AD_SELECT_MAX] = {
+ [NETDEV_BOND_AD_SELECT_STABLE] = "stable",
+ [NETDEV_BOND_AD_SELECT_BANDWIDTH] = "bandwidth",
+ [NETDEV_BOND_AD_SELECT_COUNT] = "count",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(bond_ad_select, BondAdSelect);
+
+static const char* const bond_fail_over_mac_table[_NETDEV_BOND_FAIL_OVER_MAC_MAX] = {
+ [NETDEV_BOND_FAIL_OVER_MAC_NONE] = "none",
+ [NETDEV_BOND_FAIL_OVER_MAC_ACTIVE] = "active",
+ [NETDEV_BOND_FAIL_OVER_MAC_FOLLOW] = "follow",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(bond_fail_over_mac, BondFailOverMac);
+
+static const char *const bond_arp_validate_table[_NETDEV_BOND_ARP_VALIDATE_MAX] = {
+ [NETDEV_BOND_ARP_VALIDATE_NONE] = "none",
+ [NETDEV_BOND_ARP_VALIDATE_ACTIVE]= "active",
+ [NETDEV_BOND_ARP_VALIDATE_BACKUP]= "backup",
+ [NETDEV_BOND_ARP_VALIDATE_ALL]= "all",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(bond_arp_validate, BondArpValidate);
+
+static const char *const bond_arp_all_targets_table[_NETDEV_BOND_ARP_ALL_TARGETS_MAX] = {
+ [NETDEV_BOND_ARP_ALL_TARGETS_ANY] = "any",
+ [NETDEV_BOND_ARP_ALL_TARGETS_ALL] = "all",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(bond_arp_all_targets, BondArpAllTargets);
+
+static const char *const bond_primary_reselect_table[_NETDEV_BOND_PRIMARY_RESELECT_MAX] = {
+ [NETDEV_BOND_PRIMARY_RESELECT_ALWAYS] = "always",
+ [NETDEV_BOND_PRIMARY_RESELECT_BETTER]= "better",
+ [NETDEV_BOND_PRIMARY_RESELECT_FAILURE]= "failure",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(bond_primary_reselect, BondPrimaryReselect);
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <netinet/in.h>
+#include <linux/if_bonding.h>
+
+#include "macro.h"
+
+/*
+ * Maximum number of targets supported by the kernel for a single
+ * bond netdev.
+ */
+#define NETDEV_BOND_ARP_TARGETS_MAX 16
+
+typedef enum BondMode {
+ NETDEV_BOND_MODE_BALANCE_RR = BOND_MODE_ROUNDROBIN,
+ NETDEV_BOND_MODE_ACTIVE_BACKUP = BOND_MODE_ACTIVEBACKUP,
+ NETDEV_BOND_MODE_BALANCE_XOR = BOND_MODE_XOR,
+ NETDEV_BOND_MODE_BROADCAST = BOND_MODE_BROADCAST,
+ NETDEV_BOND_MODE_802_3AD = BOND_MODE_8023AD,
+ NETDEV_BOND_MODE_BALANCE_TLB = BOND_MODE_TLB,
+ NETDEV_BOND_MODE_BALANCE_ALB = BOND_MODE_ALB,
+ _NETDEV_BOND_MODE_MAX,
+ _NETDEV_BOND_MODE_INVALID = -1
+} BondMode;
+
+typedef enum BondXmitHashPolicy {
+ NETDEV_BOND_XMIT_HASH_POLICY_LAYER2 = BOND_XMIT_POLICY_LAYER2,
+ NETDEV_BOND_XMIT_HASH_POLICY_LAYER34 = BOND_XMIT_POLICY_LAYER34,
+ NETDEV_BOND_XMIT_HASH_POLICY_LAYER23 = BOND_XMIT_POLICY_LAYER23,
+ NETDEV_BOND_XMIT_HASH_POLICY_ENCAP23 = BOND_XMIT_POLICY_ENCAP23,
+ NETDEV_BOND_XMIT_HASH_POLICY_ENCAP34 = BOND_XMIT_POLICY_ENCAP34,
+ _NETDEV_BOND_XMIT_HASH_POLICY_MAX,
+ _NETDEV_BOND_XMIT_HASH_POLICY_INVALID = -1
+} BondXmitHashPolicy;
+
+typedef enum BondLacpRate {
+ NETDEV_BOND_LACP_RATE_SLOW,
+ NETDEV_BOND_LACP_RATE_FAST,
+ _NETDEV_BOND_LACP_RATE_MAX,
+ _NETDEV_BOND_LACP_RATE_INVALID = -1,
+} BondLacpRate;
+
+typedef enum BondAdSelect {
+ NETDEV_BOND_AD_SELECT_STABLE,
+ NETDEV_BOND_AD_SELECT_BANDWIDTH,
+ NETDEV_BOND_AD_SELECT_COUNT,
+ _NETDEV_BOND_AD_SELECT_MAX,
+ _NETDEV_BOND_AD_SELECT_INVALID = -1,
+} BondAdSelect;
+
+typedef enum BondFailOverMac {
+ NETDEV_BOND_FAIL_OVER_MAC_NONE,
+ NETDEV_BOND_FAIL_OVER_MAC_ACTIVE,
+ NETDEV_BOND_FAIL_OVER_MAC_FOLLOW,
+ _NETDEV_BOND_FAIL_OVER_MAC_MAX,
+ _NETDEV_BOND_FAIL_OVER_MAC_INVALID = -1,
+} BondFailOverMac;
+
+typedef enum BondArpValidate {
+ NETDEV_BOND_ARP_VALIDATE_NONE,
+ NETDEV_BOND_ARP_VALIDATE_ACTIVE,
+ NETDEV_BOND_ARP_VALIDATE_BACKUP,
+ NETDEV_BOND_ARP_VALIDATE_ALL,
+ _NETDEV_BOND_ARP_VALIDATE_MAX,
+ _NETDEV_BOND_ARP_VALIDATE_INVALID = -1,
+} BondArpValidate;
+
+typedef enum BondArpAllTargets {
+ NETDEV_BOND_ARP_ALL_TARGETS_ANY,
+ NETDEV_BOND_ARP_ALL_TARGETS_ALL,
+ _NETDEV_BOND_ARP_ALL_TARGETS_MAX,
+ _NETDEV_BOND_ARP_ALL_TARGETS_INVALID = -1,
+} BondArpAllTargets;
+
+typedef enum BondPrimaryReselect {
+ NETDEV_BOND_PRIMARY_RESELECT_ALWAYS,
+ NETDEV_BOND_PRIMARY_RESELECT_BETTER,
+ NETDEV_BOND_PRIMARY_RESELECT_FAILURE,
+ _NETDEV_BOND_PRIMARY_RESELECT_MAX,
+ _NETDEV_BOND_PRIMARY_RESELECT_INVALID = -1,
+} BondPrimaryReselect;
+
+const char *bond_mode_to_string(BondMode d) _const_;
+BondMode bond_mode_from_string(const char *d) _pure_;
+
+const char *bond_xmit_hash_policy_to_string(BondXmitHashPolicy d) _const_;
+BondXmitHashPolicy bond_xmit_hash_policy_from_string(const char *d) _pure_;
+
+const char *bond_lacp_rate_to_string(BondLacpRate d) _const_;
+BondLacpRate bond_lacp_rate_from_string(const char *d) _pure_;
+
+const char *bond_fail_over_mac_to_string(BondFailOverMac d) _const_;
+BondFailOverMac bond_fail_over_mac_from_string(const char *d) _pure_;
+
+const char *bond_ad_select_to_string(BondAdSelect d) _const_;
+BondAdSelect bond_ad_select_from_string(const char *d) _pure_;
+
+const char *bond_arp_validate_to_string(BondArpValidate d) _const_;
+BondArpValidate bond_arp_validate_from_string(const char *d) _pure_;
+
+const char *bond_arp_all_targets_to_string(BondArpAllTargets d) _const_;
+BondArpAllTargets bond_arp_all_targets_from_string(const char *d) _pure_;
+
+const char *bond_primary_reselect_to_string(BondPrimaryReselect d) _const_;
+BondPrimaryReselect bond_primary_reselect_from_string(const char *d) _pure_;
}
static int condition_test_needs_update(Condition *c, char **env) {
- const char *p;
struct stat usr, other;
+ const char *p;
+ bool b;
+ int r;
assert(c);
assert(c->parameter);
assert(c->type == CONDITION_NEEDS_UPDATE);
+ r = proc_cmdline_get_bool("systemd.condition-needs-update", &b);
+ if (r < 0)
+ log_debug_errno(r, "Failed to parse systemd.condition-needs-update= kernel command line argument, ignoring: %m");
+ if (r > 0)
+ return b;
+
+ if (!path_is_absolute(c->parameter)) {
+ log_debug("Specified condition parameter '%s' is not absolute, assuming an update is needed.", c->parameter);
+ return true;
+ }
+
/* If the file system is read-only we shouldn't suggest an update */
- if (path_is_read_only_fs(c->parameter) > 0)
+ r = path_is_read_only_fs(c->parameter);
+ if (r < 0)
+ log_debug_errno(r, "Failed to determine if '%s' is read-only, ignoring: %m", c->parameter);
+ if (r > 0)
return false;
- /* Any other failure means we should allow the condition to be true,
- * so that we rather invoke too many update tools than too
- * few. */
-
- if (!path_is_absolute(c->parameter))
- return true;
+ /* Any other failure means we should allow the condition to be true, so that we rather invoke too
+ * many update tools than too few. */
p = strjoina(c->parameter, "/.updated");
- if (lstat(p, &other) < 0)
+ if (lstat(p, &other) < 0) {
+ if (errno != ENOENT)
+ log_debug_errno(errno, "Failed to stat() '%s', assuming an update is needed: %m", p);
return true;
+ }
- if (lstat("/usr/", &usr) < 0)
+ if (lstat("/usr/", &usr) < 0) {
+ log_debug_errno(errno, "Failed to stat() /usr/, assuming an update is needed: %m");
return true;
+ }
/*
* First, compare seconds as they are always accurate...
* AND the target file's nanoseconds == 0
* (otherwise the filesystem supports nsec timestamps, see stat(2)).
*/
- if (usr.st_mtim.tv_nsec > 0 && other.st_mtim.tv_nsec == 0) {
- _cleanup_free_ char *timestamp_str = NULL;
- uint64_t timestamp;
- int r;
-
- r = parse_env_file(NULL, p, "TIMESTAMP_NSEC", ×tamp_str);
- if (r < 0) {
- log_error_errno(r, "Failed to parse timestamp file '%s', using mtime: %m", p);
- return true;
- } else if (r == 0) {
- log_debug("No data in timestamp file '%s', using mtime", p);
- return true;
- }
+ if (usr.st_mtim.tv_nsec == 0 || other.st_mtim.tv_nsec > 0)
+ return usr.st_mtim.tv_nsec > other.st_mtim.tv_nsec;
- r = safe_atou64(timestamp_str, ×tamp);
- if (r < 0) {
- log_error_errno(r, "Failed to parse timestamp value '%s' in file '%s', using mtime: %m", timestamp_str, p);
- return true;
- }
+ _cleanup_free_ char *timestamp_str = NULL;
+ r = parse_env_file(NULL, p, "TIMESTAMP_NSEC", ×tamp_str);
+ if (r < 0) {
+ log_debug_errno(r, "Failed to parse timestamp file '%s', using mtime: %m", p);
+ return true;
+ } else if (r == 0) {
+ log_debug("No data in timestamp file '%s', using mtime.", p);
+ return true;
+ }
- timespec_store(&other.st_mtim, timestamp);
+ uint64_t timestamp;
+ r = safe_atou64(timestamp_str, ×tamp);
+ if (r < 0) {
+ log_debug_errno(r, "Failed to parse timestamp value '%s' in file '%s', using mtime: %m", timestamp_str, p);
+ return true;
}
- return usr.st_mtim.tv_nsec > other.st_mtim.tv_nsec;
+ return timespec_load_nsec(&usr.st_mtim) > timestamp;
}
static int condition_test_first_boot(Condition *c, char **env) {
- int r;
+ int r, q;
+ bool b;
assert(c);
assert(c->parameter);
assert(c->type == CONDITION_FIRST_BOOT);
+ r = proc_cmdline_get_bool("systemd.condition-first-boot", &b);
+ if (r < 0)
+ log_debug_errno(r, "Failed to parse systemd.condition-first-boot= kernel command line argument, ignoring: %m");
+ if (r > 0)
+ return b == !!r;
+
r = parse_boolean(c->parameter);
if (r < 0)
return r;
- return (access("/run/systemd/first-boot", F_OK) >= 0) == !!r;
+ q = access("/run/systemd/first-boot", F_OK);
+ if (q < 0 && errno != ENOENT)
+ log_debug_errno(errno, "Failed to check if /run/systemd/first-boot exists, ignoring: %m");
+
+ return (q >= 0) == !!r;
}
static int condition_test_environment(Condition *c, char **env) {
bitmap.c
bitmap.h
blkid-util.h
+ bond-util.c
+ bond-util.h
boot-timestamps.c
boot-timestamps.h
bootspec.c
SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION = 1ULL << 6,
SD_BUS_VTABLE_PROPERTY_EXPLICIT = 1ULL << 7,
SD_BUS_VTABLE_SENSITIVE = 1ULL << 8, /* covers both directions: method call + reply */
+ SD_BUS_VTABLE_ABSOLUTE_OFFSET = 1ULL << 9,
_SD_BUS_VTABLE_CAPABILITY_MASK = 0xFFFFULL << 40
};
WithoutRA=
MUDURL=
SendOption=
+RequestOptions=
[Route]
Destination=
Protocol=