]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #15153 from keszybz/man-bus-address
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Thu, 19 Mar 2020 08:11:14 +0000 (09:11 +0100)
committerGitHub <noreply@github.com>
Thu, 19 Mar 2020 08:11:14 +0000 (09:11 +0100)
Add two man pages for sd-bus

33 files changed:
man/rules/meson.build
man/sd-bus.xml
man/sd_bus_call.xml
man/sd_bus_set_description.xml
man/sd_bus_set_method_call_timeout.xml [new file with mode: 0644]
man/systemd.exec.xml
man/systemd.network.xml
src/core/dbus-execute.c
src/core/execute.c
src/core/execute.h
src/core/load-fragment.c
src/core/selinux-access.c
src/libsystemd-network/dhcp-server-internal.h
src/libsystemd-network/sd-dhcp-client.c
src/libsystemd-network/sd-dhcp-server.c
src/network/networkctl.c
src/network/networkd-dhcp-server.c
src/network/networkd-dhcp4.c
src/network/networkd-network-gperf.gperf
src/network/networkd-network.c
src/network/networkd-network.h
src/shared/bus-unit-util.c
src/shared/cpu-set-util.c
src/shared/cpu-set-util.h
src/shared/meson.build
src/shared/numa-util.c [new file with mode: 0644]
src/shared/numa-util.h [new file with mode: 0644]
src/systemctl/systemctl.c
src/systemd/sd-dhcp-client.h
src/systemd/sd-dhcp-server.h
src/test/test-cpu-set-util.c
test/TEST-36-NUMAPOLICY/testsuite.sh
test/fuzz/fuzz-network-parser/directives.network

index e9d83dd9e16aebd903a5f702dc4147a45f3cb789..0e4c26d074763ee67f50599f7fb3b531d07169ea 100644 (file)
@@ -343,6 +343,10 @@ manpages = [
    'sd_bus_set_anonymous',
    'sd_bus_set_trusted'],
   ''],
+ ['sd_bus_set_method_call_timeout',
+  '3',
+  ['sd_bus_get_method_call_timeout'],
+  ''],
  ['sd_bus_set_sender', '3', ['sd_bus_get_sender'], ''],
  ['sd_bus_set_watch_bind', '3', ['sd_bus_get_watch_bind'], ''],
  ['sd_bus_slot_ref',
index 66b022e6ea5014ac3f1b08c230975af09a1ac86c..fb55a1b526fe10b1df184d22497f0f06ab45796f 100644 (file)
@@ -56,6 +56,7 @@
 <citerefentry><refentrytitle>sd_bus_error_add_map</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_get_address</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_get_fd</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+<citerefentry><refentrytitle>sd_bus_get_method_call_timeout</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_get_n_queued_read</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_message_append</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_message_append_array</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
@@ -89,6 +90,7 @@
 <citerefentry><refentrytitle>sd_bus_set_address</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_set_connected_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_set_description</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+<citerefentry><refentrytitle>sd_bus_set_method_call_timeout</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_set_sender</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_set_watch_bind</refentrytitle><manvolnum>3</manvolnum></citerefentry>
 <citerefentry><refentrytitle>sd_bus_set_close_on_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry>
index 689f950585669778afbf9fc220b4cc016dfcb20b..6555563793e83036ae5737c08010aac5e1a4ab66 100644 (file)
     on the reply object returned by <function>sd_bus_call()</function> or passed to the callback of
     <function>sd_bus_call_async()</function>.</para>
 
-    <para>If <parameter>usec</parameter> is zero, the timeout set using
-    <citerefentry><refentrytitle>sd_bus_set_method_call_timeout</refentrytitle><manvolnum>3</manvolnum></citerefentry>
-    is used. If no method call timeout was set, the timeout is read from the
-    <varname>$SYSTEMD_BUS_TIMEOUT</varname> environment variable. If this environment variable is
-    unset or does not contain a valid timeout, the implementation falls back to a predefined method
-    call timeout of 25 seconds. Note that <varname>$SYSTEMD_BUS_TIMEOUT</varname> is read once and
-    cached so callers should not rely on being able to change the default method call timeout at
-    runtime by changing the value of <varname>$SYSTEMD_BUS_TIMEOUT</varname>. Instead, call
-    <function>sd_bus_set_method_call_timeout()</function> to change the default method call timeout.
+    <para>If <parameter>usec</parameter> is zero, the default D-Bus method call timeout is used. See
+    <citerefentry><refentrytitle>sd_bus_get_method_call_timeout</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
     </para>
 
   </refsect1>
index 84ac76e66c1514d8d903ee5bd32be2d0f89463ef..b855008eb8ecbf16310c74381f308d72bb439549 100644 (file)
   <refsect1>
     <title>Return Value</title>
 
-    <para>On success, these functions return 0 or a positive integer. On failure, they return a negative
-    errno-style error code.</para>
+    <para>On success, these functions return a non-negative integer. On failure, they return a
+    negative errno-style error code.</para>
 
     <refsect2>
       <title>Errors</title>
diff --git a/man/sd_bus_set_method_call_timeout.xml b/man/sd_bus_set_method_call_timeout.xml
new file mode 100644 (file)
index 0000000..01857fd
--- /dev/null
@@ -0,0 +1,104 @@
+<?xml version='1.0'?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
+
+<refentry id="sd_bus_set_method_call_timeout" xmlns:xi="http://www.w3.org/2001/XInclude">
+
+  <refentryinfo>
+    <title>sd_bus_set_method_call_timeout</title>
+    <productname>systemd</productname>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle>sd_bus_set_method_call_timeout</refentrytitle>
+    <manvolnum>3</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>sd_bus_set_method_call_timeout</refname>
+    <refname>sd_bus_get_method_call_timeout</refname>
+
+    <refpurpose>Set or query the default D-Bus method call timeout of a bus object</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcsynopsisinfo>#include &lt;systemd/sd-bus.h&gt;</funcsynopsisinfo>
+
+      <funcprototype>
+        <funcdef>int <function>sd_bus_set_method_call_timeout</function></funcdef>
+        <paramdef>sd_bus *<parameter>bus</parameter></paramdef>
+        <paramdef>uint64_t <parameter>usec</parameter></paramdef>
+      </funcprototype>
+
+      <funcprototype>
+        <funcdef>int <function>sd_bus_get_method_call_timeout</function></funcdef>
+        <paramdef>sd_bus *<parameter>bus</parameter></paramdef>
+        <paramdef>uint64_t *<parameter>ret</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para><function>sd_bus_set_method_call_timeout()</function> sets the default D-Bus method call
+    timeout of <parameter>bus</parameter> to <parameter>usec</parameter> microseconds.</para>
+
+    <para><function>sd_bus_get_method_call_timeout()</function> queries the default D-Bus method
+    call timeout of <parameter>bus</parameter>. If no method call timeout was set using
+    <function>sd_bus_set_method_call_timeout()</function>, the timeout is read from the
+    <varname>$SYSTEMD_BUS_TIMEOUT</varname> environment variable. If this environment variable is
+    unset or does not contain a valid timeout, the implementation falls back to a predefined method
+    call timeout of 25 seconds. Note that <varname>$SYSTEMD_BUS_TIMEOUT</varname> is read once and
+    cached so callers should not rely on being able to change the default method call timeout at
+    runtime by changing the value of <varname>$SYSTEMD_BUS_TIMEOUT</varname>. Instead, call
+    <function>sd_bus_set_method_call_timeout()</function> to change the default method call timeout.
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title>Return Value</title>
+
+    <para>On success, these functions return a non-negative integer. On failure, they return a
+    negative errno-style error code.</para>
+
+    <refsect2>
+      <title>Errors</title>
+
+      <para>Returned errors may indicate the following problems:</para>
+
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
+
+          <listitem><para>The parameters <parameter>bus</parameter> or <parameter>ret</parameter>
+          are <constant>NULL</constant>.</para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><constant>-ENOPKG</constant></term>
+
+          <listitem><para>Bus object <parameter>bus</parameter> could not be resolved.</para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+
+    </refsect2>
+  </refsect1>
+
+  <xi:include href="libsystemd-pkgconfig.xml" />
+
+  <refsect1>
+    <title>See Also</title>
+
+    <para>
+      <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd-bus</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd_bus_call</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd_bus_message_seal</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+    </para>
+  </refsect1>
+
+</refentry>
index 8f1695ad293f6113a4b32f58c18822687c4f8928..79a2c744c64fb15fdb9b05a986d6d89410099c20 100644 (file)
@@ -774,10 +774,11 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
         <term><varname>CPUAffinity=</varname></term>
 
         <listitem><para>Controls the CPU affinity of the executed processes. Takes a list of CPU indices or ranges
-        separated by either whitespace or commas. CPU ranges are specified by the lower and upper CPU indices separated
-        by a dash. This option may be specified more than once, in which case the specified CPU affinity masks are
-        merged. If the empty string is assigned, the mask is reset, all assignments prior to this will have no
-        effect. See
+        separated by either whitespace or commas. Alternatively, takes a special "numa" value in which case systemd
+        automatically derives allowed CPU range based on the value of <varname>NUMAMask=</varname> option. CPU ranges
+        are specified by the lower and upper CPU indices separated by a dash. This option may be specified more than
+        once, in which case the specified CPU affinity masks are merged. If the empty string is assigned, the mask
+        is reset, all assignments prior to this will have no effect. See
         <citerefentry><refentrytitle>sched_setaffinity</refentrytitle><manvolnum>2</manvolnum></citerefentry> for
         details.</para></listitem>
       </varlistentry>
index b13fcd189323b4ad8f371b84785d223db6b5600c..5457e668dd282a7aed9cd974859f10ad395aeb9f 100644 (file)
         <varlistentry>
           <term><varname>SendOption=</varname></term>
           <listitem>
-            <para>Send an arbitrary option in the DHCPv4 request. Takes a DHCP option number, data type
+            <para>Send an arbitrary raw option in the DHCPv4 request. Takes a DHCP option number, data type
+            and data separated with a colon
+            (<literal><replaceable>option</replaceable>:<replaceable>type</replaceable>:<replaceable>value</replaceable></literal>).
+            The option number must be an integer in the range 1..254. The type takes one of <literal>uint8</literal>,
+            <literal>uint16</literal>, <literal>uint32</literal>, <literal>ipv4address</literal>, or
+            <literal>string</literal>. Special characters in the data string may be escaped using
+            <ulink url="https://en.wikipedia.org/wiki/Escape_sequences_in_C#Table_of_escape_sequences">C-style
+            escapes</ulink>. This setting can be specified multiple times. If an empty string is specified,
+            then all options specified earlier are cleared. Defaults to unset.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><varname>SendVendorOption=</varname></term>
+          <listitem>
+            <para>Send an arbitrary vendor option in the DHCPv4 request. Takes a DHCP option number, data type
             and data separated with a colon
             (<literal><replaceable>option</replaceable>:<replaceable>type</replaceable>:<replaceable>value</replaceable></literal>).
             The option number must be an integer in the range 1..254. The type takes one of <literal>uint8</literal>,
         </listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><varname>SendVendorOption=</varname></term>
+        <listitem>
+          <para>Send a vendor option with value via DHCPv4 server. Takes a DHCP option number, data type
+          and data (<literal><replaceable>option</replaceable>:<replaceable>type</replaceable>:<replaceable>value</replaceable></literal>).
+          The option number is an integer in the range 1..254. The type takes one of <literal>uint8</literal>,
+          <literal>uint16</literal>, <literal>uint32</literal>, <literal>ipv4address</literal>, or
+          <literal>string</literal>. Special characters in the data string may be escaped using
+          <ulink url="https://en.wikipedia.org/wiki/Escape_sequences_in_C#Table_of_escape_sequences">C-style
+          escapes</ulink>. This setting can be specified multiple times. If an empty string is specified,
+          then all options specified earlier are cleared. Defaults to unset.</para>
+        </listitem>
+      </varlistentry>
+
     </variablelist>
   </refsect1>
 
index d8ba3e5d9241e763c3d701f218e0080855ab5950..e8be76e315c56c8e90dd4f025607d0211205893f 100644 (file)
@@ -56,6 +56,8 @@ static BUS_DEFINE_PROPERTY_GET2(property_get_ioprio_priority, "i", ExecContext,
 static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_empty_string, "s", NULL);
 static BUS_DEFINE_PROPERTY_GET_REF(property_get_syslog_level, "i", int, LOG_PRI);
 static BUS_DEFINE_PROPERTY_GET_REF(property_get_syslog_facility, "i", int, LOG_FAC);
+static BUS_DEFINE_PROPERTY_GET(property_get_cpu_affinity_from_numa, "b", ExecContext, exec_context_get_cpu_affinity_from_numa);
+
 
 static int property_get_environment_files(
                 sd_bus *bus,
@@ -213,6 +215,7 @@ static int property_get_cpu_affinity(
                 sd_bus_error *error) {
 
         ExecContext *c = userdata;
+        _cleanup_(cpu_set_reset) CPUSet s = {};
         _cleanup_free_ uint8_t *array = NULL;
         size_t allocated;
 
@@ -220,7 +223,16 @@ static int property_get_cpu_affinity(
         assert(reply);
         assert(c);
 
-        (void) cpu_set_to_dbus(&c->cpu_set, &array, &allocated);
+        if (c->cpu_affinity_from_numa) {
+                int r;
+
+                r = numa_to_cpu_set(&c->numa_policy, &s);
+                if (r < 0)
+                        return r;
+        }
+
+        (void) cpu_set_to_dbus(c->cpu_affinity_from_numa ? &s : &c->cpu_set,  &array, &allocated);
+
         return sd_bus_message_append_array(reply, 'y', array, allocated);
 }
 
@@ -741,6 +753,7 @@ const sd_bus_vtable bus_exec_vtable[] = {
         SD_BUS_PROPERTY("CPUSchedulingPolicy", "i", property_get_cpu_sched_policy, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("CPUSchedulingPriority", "i", property_get_cpu_sched_priority, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("CPUAffinity", "ay", property_get_cpu_affinity, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("CPUAffinityFromNUMA", "b", property_get_cpu_affinity_from_numa, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("NUMAPolicy", "i", property_get_numa_policy, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("NUMAMask", "ay", property_get_numa_mask, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("TimerSlackNSec", "t", property_get_timer_slack_nsec, 0, SD_BUS_VTABLE_PROPERTY_CONST),
@@ -1770,6 +1783,20 @@ int bus_exec_context_set_transient_property(
 
                 return 1;
 
+        } else if (streq(name, "CPUAffinityFromNUMA")) {
+                int q;
+
+                r = sd_bus_message_read_basic(message, 'b', &q);
+                if (r < 0)
+                        return r;
+
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+                        c->cpu_affinity_from_numa = q;
+                        unit_write_settingf(u, flags, name, "%s=%s", "CPUAffinity", "numa");
+                }
+
+                return 1;
+
         } else if (streq(name, "NUMAPolicy")) {
                 int32_t type;
 
@@ -1784,6 +1811,7 @@ int bus_exec_context_set_transient_property(
                         c->numa_policy.type = type;
 
                 return 1;
+
         } else if (streq(name, "Nice")) {
                 int32_t q;
 
index 00a2f2e17e477d0610e680946c81d11f8346ddb9..8e1e77b4b2a5442c741943f978def1495ca85898 100644 (file)
@@ -3021,6 +3021,33 @@ static int exec_parameters_get_cgroup_path(const ExecParameters *params, char **
         return using_subcgroup;
 }
 
+static int exec_context_cpu_affinity_from_numa(const ExecContext *c, CPUSet *ret) {
+        _cleanup_(cpu_set_reset) CPUSet s = {};
+        int r;
+
+        assert(c);
+        assert(ret);
+
+        if (!c->numa_policy.nodes.set) {
+                log_debug("Can't derive CPU affinity mask from NUMA mask because NUMA mask is not set, ignoring");
+                return 0;
+        }
+
+        r = numa_to_cpu_set(&c->numa_policy, &s);
+        if (r < 0)
+                return r;
+
+        cpu_set_reset(ret);
+
+        return cpu_set_add_all(ret, &s);
+}
+
+bool exec_context_get_cpu_affinity_from_numa(const ExecContext *c) {
+        assert(c);
+
+        return c->cpu_affinity_from_numa;
+}
+
 static int exec_child(
                 Unit *unit,
                 const ExecCommand *command,
@@ -3318,11 +3345,26 @@ static int exec_child(
                 }
         }
 
-        if (context->cpu_set.set)
-                if (sched_setaffinity(0, context->cpu_set.allocated, context->cpu_set.set) < 0) {
+        if (context->cpu_affinity_from_numa || context->cpu_set.set) {
+                _cleanup_(cpu_set_reset) CPUSet converted_cpu_set = {};
+                const CPUSet *cpu_set;
+
+                if (context->cpu_affinity_from_numa) {
+                        r = exec_context_cpu_affinity_from_numa(context, &converted_cpu_set);
+                        if (r < 0) {
+                                *exit_status = EXIT_CPUAFFINITY;
+                                return log_unit_error_errno(unit, r, "Failed to derive CPU affinity mask from NUMA mask: %m");
+                        }
+
+                        cpu_set = &converted_cpu_set;
+                } else
+                        cpu_set = &context->cpu_set;
+
+                if (sched_setaffinity(0, cpu_set->allocated, cpu_set->set) < 0) {
                         *exit_status = EXIT_CPUAFFINITY;
                         return log_unit_error_errno(unit, errno, "Failed to set up CPU affinity: %m");
                 }
+        }
 
         if (mpol_is_valid(numa_policy_get_type(&context->numa_policy))) {
                 r = apply_numa_policy(&context->numa_policy);
index 09c1510aafd3b9c28680036451251740830ceab1..4baf5b1a405f942d7d00de64ab4a6eedd30b03a5 100644 (file)
@@ -21,6 +21,7 @@ typedef struct Manager Manager;
 #include "missing_resource.h"
 #include "namespace.h"
 #include "nsflags.h"
+#include "numa-util.h"
 #include "time-util.h"
 
 #define EXEC_STDIN_DATA_MAX (64U*1024U*1024U)
@@ -181,6 +182,7 @@ struct ExecContext {
 
         CPUSet cpu_set;
         NUMAPolicy numa_policy;
+        bool cpu_affinity_from_numa;
 
         ExecInput std_input;
         ExecOutput std_output;
@@ -405,6 +407,8 @@ void exec_runtime_vacuum(Manager *m);
 
 void exec_params_clear(ExecParameters *p);
 
+bool exec_context_get_cpu_affinity_from_numa(const ExecContext *c);
+
 const char* exec_output_to_string(ExecOutput i) _const_;
 ExecOutput exec_output_from_string(const char *s) _pure_;
 
index 71a9873da46fbe6404c967b32982c031de02a9cd..646364eb898788b843cc0e72cdbefd662bb12d33 100644 (file)
@@ -1330,13 +1330,25 @@ int config_parse_exec_cpu_affinity(const char *unit,
                                    void *userdata) {
 
         ExecContext *c = data;
+        int r;
 
         assert(filename);
         assert(lvalue);
         assert(rvalue);
         assert(data);
 
-        return parse_cpu_set_extend(rvalue, &c->cpu_set, true, unit, filename, line, lvalue);
+        if (streq(rvalue, "numa")) {
+                c->cpu_affinity_from_numa = true;
+                cpu_set_reset(&c->cpu_set);
+
+                return 0;
+        }
+
+        r = parse_cpu_set_extend(rvalue, &c->cpu_set, true, unit, filename, line, lvalue);
+        if (r >= 0)
+                c->cpu_affinity_from_numa = false;
+
+        return r;
 }
 
 int config_parse_capability_set(
index 008a8ba9b6aa92786a81ba83c8b286efcff9f6b1..e40898d10bc5affa4cdaa62ddb602ff1e64dcaa0 100644 (file)
@@ -185,7 +185,7 @@ int mac_selinux_generic_access_check(
         _cleanup_free_ char *cl = NULL;
         _cleanup_freecon_ char *fcon = NULL;
         char **cmdline = NULL;
-        const bool enforce = mac_selinux_enforcing();
+        bool enforce;
         int r = 0;
 
         assert(message);
@@ -196,6 +196,9 @@ int mac_selinux_generic_access_check(
         if (r <= 0)
                 return r;
 
+        /* delay call until we checked in `access_init()` if SELinux is actually enabled */
+        enforce = mac_selinux_enforcing();
+
         r = sd_bus_query_sender_creds(
                         message,
                         SD_BUS_CREDS_PID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID|
index 42c3ceb8b158ea73d7ba49474ddae17a82ea43f7..41901894f577cc3a172eabd197e1269a809bd170 100644 (file)
@@ -58,7 +58,8 @@ struct sd_dhcp_server {
         struct in_addr *ntp, *dns, *sip;
         unsigned n_ntp, n_dns, n_sip;
 
-        OrderedHashmap *raw_option;
+        OrderedHashmap *extra_options;
+        OrderedHashmap *vendor_options;
 
         bool emit_router;
 
index 4122d08d9658c821cc5d77c2b828d1fe1f27e1f0..82553e79cadfb8a4ccd678a3d7f6b274e201506c 100644 (file)
@@ -89,7 +89,8 @@ struct sd_dhcp_client {
         usec_t start_time;
         uint64_t attempt;
         uint64_t max_attempts;
-        OrderedHashmap *options;
+        OrderedHashmap *extra_options;
+        OrderedHashmap *vendor_options;
         usec_t request_sent;
         sd_event_source *timeout_t1;
         sd_event_source *timeout_t2;
@@ -540,17 +541,17 @@ int sd_dhcp_client_set_max_attempts(sd_dhcp_client *client, uint64_t max_attempt
         return 0;
 }
 
-int sd_dhcp_client_set_dhcp_option(sd_dhcp_client *client, sd_dhcp_option *v) {
+int sd_dhcp_client_add_option(sd_dhcp_client *client, sd_dhcp_option *v) {
         int r;
 
         assert_return(client, -EINVAL);
         assert_return(v, -EINVAL);
 
-        r = ordered_hashmap_ensure_allocated(&client->options, &dhcp_option_hash_ops);
+        r = ordered_hashmap_ensure_allocated(&client->extra_options, &dhcp_option_hash_ops);
         if (r < 0)
                 return r;
 
-        r = ordered_hashmap_put(client->options, UINT_TO_PTR(v->option), v);
+        r = ordered_hashmap_put(client->extra_options, UINT_TO_PTR(v->option), v);
         if (r < 0)
                 return r;
 
@@ -558,6 +559,25 @@ int sd_dhcp_client_set_dhcp_option(sd_dhcp_client *client, sd_dhcp_option *v) {
         return 0;
 }
 
+int sd_dhcp_client_add_vendor_option(sd_dhcp_client *client, sd_dhcp_option *v) {
+        int r;
+
+        assert_return(client, -EINVAL);
+        assert_return(v, -EINVAL);
+
+        r = ordered_hashmap_ensure_allocated(&client->vendor_options, &dhcp_option_hash_ops);
+        if (r < 0)
+                return -ENOMEM;
+
+        r = ordered_hashmap_put(client->vendor_options, v, v);
+        if (r < 0)
+                return r;
+
+        sd_dhcp_option_ref(v);
+
+        return 1;
+}
+
 int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) {
         assert_return(client, -EINVAL);
 
@@ -884,13 +904,22 @@ static int client_send_discover(sd_dhcp_client *client) {
                         return r;
         }
 
-        ORDERED_HASHMAP_FOREACH(j, client->options, i) {
+        ORDERED_HASHMAP_FOREACH(j, client->extra_options, i) {
                 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
                                        j->option, j->length, j->data);
                 if (r < 0)
                         return r;
         }
 
+        if (!ordered_hashmap_isempty(client->vendor_options)) {
+                r = dhcp_option_append(
+                                &discover->dhcp, optlen, &optoffset, 0,
+                                SD_DHCP_OPTION_VENDOR_SPECIFIC,
+                                ordered_hashmap_size(client->vendor_options), client->vendor_options);
+                if (r < 0)
+                        return r;
+        }
+
         r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
                                SD_DHCP_OPTION_END, 0, NULL);
         if (r < 0)
@@ -2073,7 +2102,8 @@ static sd_dhcp_client *dhcp_client_free(sd_dhcp_client *client) {
         free(client->hostname);
         free(client->vendor_class_identifier);
         client->user_class = strv_free(client->user_class);
-        ordered_hashmap_free(client->options);
+        ordered_hashmap_free(client->extra_options);
+        ordered_hashmap_free(client->vendor_options);
         return mfree(client);
 }
 
index 546b5d02c4ceb7853559f68ec248074a8f4c51c9..a0b779bc096a864c96d2886e72742f77a05ee49a 100644 (file)
@@ -143,7 +143,8 @@ static sd_dhcp_server *dhcp_server_free(sd_dhcp_server *server) {
 
         hashmap_free(server->leases_by_client_id);
 
-        ordered_hashmap_free(server->raw_option);
+        ordered_hashmap_free(server->extra_options);
+        ordered_hashmap_free(server->vendor_options);
 
         free(server->bound_leases);
         return mfree(server);
@@ -455,6 +456,8 @@ static int server_send_ack(sd_dhcp_server *server, DHCPRequest *req,
                            be32_t address) {
         _cleanup_free_ DHCPPacket *packet = NULL;
         be32_t lease_time;
+        sd_dhcp_option *j;
+        Iterator i;
         size_t offset;
         int r;
 
@@ -519,11 +522,18 @@ static int server_send_ack(sd_dhcp_server *server, DHCPRequest *req,
                         return r;
         }
 
-        if (!ordered_hashmap_isempty(server->raw_option)) {
+        ORDERED_HASHMAP_FOREACH(j, server->extra_options, i) {
+                r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
+                                       j->option, j->length, j->data);
+                if (r < 0)
+                        return r;
+        }
+
+        if (!ordered_hashmap_isempty(server->vendor_options)) {
                 r = dhcp_option_append(
                                 &packet->dhcp, req->max_optlen, &offset, 0,
                                 SD_DHCP_OPTION_VENDOR_SPECIFIC,
-                                ordered_hashmap_size(server->raw_option), server->raw_option);
+                                ordered_hashmap_size(server->vendor_options), server->vendor_options);
                 if (r < 0)
                         return r;
         }
@@ -1188,11 +1198,29 @@ int sd_dhcp_server_add_option(sd_dhcp_server *server, sd_dhcp_option *v) {
         assert_return(server, -EINVAL);
         assert_return(v, -EINVAL);
 
-        r = ordered_hashmap_ensure_allocated(&server->raw_option, &dhcp_option_hash_ops);
+        r = ordered_hashmap_ensure_allocated(&server->extra_options, &dhcp_option_hash_ops);
+        if (r < 0)
+                return r;
+
+        r = ordered_hashmap_put(server->extra_options, UINT_TO_PTR(v->option), v);
+        if (r < 0)
+                return r;
+
+        sd_dhcp_option_ref(v);
+        return 0;
+}
+
+int sd_dhcp_server_add_vendor_option(sd_dhcp_server *server, sd_dhcp_option *v) {
+        int r;
+
+        assert_return(server, -EINVAL);
+        assert_return(v, -EINVAL);
+
+        r = ordered_hashmap_ensure_allocated(&server->vendor_options, &dhcp_option_hash_ops);
         if (r < 0)
                 return -ENOMEM;
 
-        r = ordered_hashmap_put(server->raw_option, v, v);
+        r = ordered_hashmap_put(server->vendor_options, v, v);
         if (r < 0)
                 return r;
 
index bc67af3c25e92baaa97c6145c005bd1dafbf3eab..772e6a95c22226b39a3f9d736ffd05f06d79bb88 100644 (file)
@@ -127,6 +127,7 @@ typedef struct LinkInfo {
         uint32_t max_mtu;
         uint32_t tx_queues;
         uint32_t rx_queues;
+        uint8_t addr_gen_mode;
         char *qdisc;
         char **alternative_names;
 
@@ -161,6 +162,12 @@ typedef struct LinkInfo {
         union in_addr_union local;
         union in_addr_union remote;
 
+        /* bonding info */
+        uint8_t mode;
+        uint32_t miimon;
+        uint32_t updelay;
+        uint32_t downdelay;
+
         /* ethtool info */
         int autonegotiation;
         uint64_t speed;
@@ -182,6 +189,7 @@ typedef struct LinkInfo {
         bool has_ethtool_link_info:1;
         bool has_wlan_link_info:1;
         bool has_tunnel_ipv4:1;
+        bool has_ipv6_address_generation_mode:1;
 
         bool needs_freeing:1;
 } LinkInfo;
@@ -229,7 +237,11 @@ static int decode_netdev(sd_netlink_message *m, LinkInfo *info) {
                 (void) sd_netlink_message_read_u32(m, IFLA_BR_STP_STATE, &info->stp_state);
                 (void) sd_netlink_message_read_u16(m, IFLA_BR_PRIORITY, &info->priority);
                 (void) sd_netlink_message_read_u8(m, IFLA_BR_MCAST_IGMP_VERSION, &info->mcast_igmp_version);
-
+        } if (streq(received_kind, "bond")) {
+                (void) sd_netlink_message_read_u8(m, IFLA_BOND_MODE, &info->mode);
+                (void) sd_netlink_message_read_u32(m, IFLA_BOND_MIIMON, &info->miimon);
+                (void) sd_netlink_message_read_u32(m, IFLA_BOND_DOWNDELAY, &info->downdelay);
+                (void) sd_netlink_message_read_u32(m, IFLA_BOND_UPDELAY, &info->updelay);
         } else if (streq(received_kind, "vxlan")) {
                 (void) sd_netlink_message_read_u32(m, IFLA_VXLAN_ID, &info->vxlan_info.vni);
 
@@ -387,6 +399,19 @@ static int decode_link(sd_netlink_message *m, LinkInfo *info, char **patterns, b
 
         (void) sd_netlink_message_read_u32(m, IFLA_MASTER, &info->master);
 
+        r = sd_netlink_message_enter_container(m, IFLA_AF_SPEC);
+        if (r >= 0) {
+                r = sd_netlink_message_enter_container(m, AF_INET6);
+                if (r >= 0) {
+                        r = sd_netlink_message_read_u8(m, IFLA_INET6_ADDR_GEN_MODE, &info->addr_gen_mode);
+                        if (r >= 0)
+                                info->has_ipv6_address_generation_mode = true;
+
+                        (void) sd_netlink_message_exit_container(m);
+                }
+                (void) sd_netlink_message_exit_container(m);
+        }
+
         /* fill kind info */
         (void) decode_netdev(m, info);
 
@@ -1408,6 +1433,24 @@ static int link_status_one(
                         return table_log_add_error(r);
         }
 
+        if (info->has_ipv6_address_generation_mode) {
+                static const struct {
+                        const char *mode;
+                } mode_table[] = {
+                        { "eui64" },
+                        { "none" },
+                        { "stable-privacy" },
+                        { "random" },
+                };
+
+                r = table_add_many(table,
+                                   TABLE_EMPTY,
+                                   TABLE_STRING, "IPv6 Address Generation Mode:",
+                                   TABLE_STRING, mode_table[info->addr_gen_mode]);
+                if (r < 0)
+                        return table_log_add_error(r);
+        }
+
         if (streq_ptr(info->netdev_kind, "bridge")) {
                 r = table_add_many(table,
                                    TABLE_EMPTY,
@@ -1434,6 +1477,35 @@ static int link_status_one(
                 if (r < 0)
                         return table_log_add_error(r);
 
+        } 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_EMPTY,
+                                   TABLE_STRING, "Miimon:",
+                                   TABLE_TIMESPAN_MSEC, jiffies_to_usec(info->miimon),
+                                   TABLE_EMPTY,
+                                   TABLE_STRING, "Updelay:",
+                                   TABLE_TIMESPAN_MSEC, jiffies_to_usec(info->updelay),
+                                   TABLE_EMPTY,
+                                   TABLE_STRING, "Downdelay:",
+                                   TABLE_TIMESPAN_MSEC, jiffies_to_usec(info->downdelay));
+                if (r < 0)
+                        return table_log_add_error(r);
+
         } else if (streq_ptr(info->netdev_kind, "vxlan")) {
                 if (info->vxlan_info.vni > 0) {
                         r = table_add_many(table,
index bee75a6930ea690479e9d06b5e4fed00d6ff5928..2ec742b5e3289e7ffcf525b04ea2a46a72fbf6d2 100644 (file)
@@ -312,6 +312,14 @@ int dhcp4_server_configure(Link *link) {
                         return log_link_error_errno(link, r, "Failed to set DHCPv4 option: %m");
         }
 
+        ORDERED_HASHMAP_FOREACH(p, link->network->dhcp_server_send_vendor_options, i) {
+                r = sd_dhcp_server_add_vendor_option(link->dhcp_server, p);
+                if (r == -EEXIST)
+                        continue;
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Failed to set DHCPv4 option: %m");
+        }
+
         if (!sd_dhcp_server_is_running(link->dhcp_server)) {
                 r = sd_dhcp_server_start(link->dhcp_server);
                 if (r < 0)
index 64190375a4183edeeb5770d9c2077c909252b010..83fb25264ab5fdbd07b57bd75ec8c21e43bb905e 100644 (file)
@@ -1430,7 +1430,17 @@ int dhcp4_configure(Link *link) {
         }
 
         ORDERED_HASHMAP_FOREACH(send_option, link->network->dhcp_client_send_options, i) {
-                r = sd_dhcp_client_set_dhcp_option(link->dhcp_client, send_option);
+                r = sd_dhcp_client_add_option(link->dhcp_client, send_option);
+                if (r == -EEXIST)
+                        continue;
+                if (r < 0)
+                        return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set send option: %m");
+        }
+
+        ORDERED_HASHMAP_FOREACH(send_option, link->network->dhcp_client_send_vendor_options, i) {
+                r = sd_dhcp_client_add_vendor_option(link->dhcp_client, send_option);
+                if (r == -EEXIST)
+                        continue;
                 if (r < 0)
                         return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set send option: %m");
         }
index c75a07e4f399e9f62444f157d70f649c7e40f53b..fd996327a55fc5e3e729057de682e493c63b9f69 100644 (file)
@@ -184,6 +184,7 @@ DHCPv4.SendDecline,                          config_parse_bool,
 DHCPv4.BlackList,                            config_parse_dhcp_black_listed_ip_address,                0,                             0
 DHCPv4.IPServiceType,                        config_parse_dhcp_ip_service_type,                        0,                             offsetof(Network, ip_service_type)
 DHCPv4.SendOption,                           config_parse_dhcp_send_option,                            0,                             offsetof(Network, dhcp_client_send_options)
+DHCPv4.SendVendorOption,                     config_parse_dhcp_send_option,                            0,                             offsetof(Network, dhcp_client_send_vendor_options)
 DHCPv4.RouteMTUBytes,                        config_parse_mtu,                                         AF_INET,                       offsetof(Network, dhcp_route_mtu)
 DHCPv6.UseDNS,                               config_parse_bool,                                        0,                             offsetof(Network, dhcp6_use_dns)
 DHCPv6.UseNTP,                               config_parse_bool,                                        0,                             offsetof(Network, dhcp6_use_ntp)
@@ -211,6 +212,7 @@ DHCPServer.EmitTimezone,                     config_parse_bool,
 DHCPServer.Timezone,                         config_parse_timezone,                                    0,                             offsetof(Network, dhcp_server_timezone)
 DHCPServer.PoolOffset,                       config_parse_uint32,                                      0,                             offsetof(Network, dhcp_server_pool_offset)
 DHCPServer.PoolSize,                         config_parse_uint32,                                      0,                             offsetof(Network, dhcp_server_pool_size)
+DHCPServer.SendVendorOption,                 config_parse_dhcp_send_option,                            0,                             offsetof(Network, dhcp_server_send_vendor_options)
 DHCPServer.SendOption,                       config_parse_dhcp_send_option,                            0,                             offsetof(Network, dhcp_server_send_options)
 Bridge.Cost,                                 config_parse_uint32,                                      0,                             offsetof(Network, cost)
 Bridge.UseBPDU,                              config_parse_tristate,                                    0,                             offsetof(Network, use_bpdu)
index 248172f8a204b8ce8059685603cf3ab22ec79950..e7ead446c7640227874263790168a09adfa426f6 100644 (file)
@@ -723,7 +723,9 @@ static Network *network_free(Network *network) {
         set_free_free(network->dnssec_negative_trust_anchors);
 
         ordered_hashmap_free(network->dhcp_client_send_options);
+        ordered_hashmap_free(network->dhcp_client_send_vendor_options);
         ordered_hashmap_free(network->dhcp_server_send_options);
+        ordered_hashmap_free(network->dhcp_server_send_vendor_options);
         ordered_hashmap_free(network->ipv6_tokens);
 
         return mfree(network);
index b6872821240e80465ad47e0c24b625700fd2107b..f747ccaf101812633f0badc35fe88856e2f31e15 100644 (file)
@@ -121,7 +121,9 @@ struct Network {
         Set *dhcp_black_listed_ip;
         Set *dhcp_request_options;
         OrderedHashmap *dhcp_client_send_options;
+        OrderedHashmap *dhcp_client_send_vendor_options;
         OrderedHashmap *dhcp_server_send_options;
+        OrderedHashmap *dhcp_server_send_vendor_options;
 
         /* DHCPv6 Client support*/
         bool dhcp6_use_dns;
index 28d85944a8a73b0b3500d98ed90a7b135de13204..a30876c1a13f672dedc943c7923b11c2c9570e95 100644 (file)
@@ -21,6 +21,7 @@
 #include "missing_fs.h"
 #include "mountpoint-util.h"
 #include "nsflags.h"
+#include "numa-util.h"
 #include "parse-util.h"
 #include "process-util.h"
 #include "rlimit-util.h"
@@ -28,6 +29,7 @@
 #include "signal-util.h"
 #include "socket-util.h"
 #include "sort-util.h"
+#include "stdio-util.h"
 #include "string-util.h"
 #include "syslog-util.h"
 #include "terminal-util.h"
@@ -1102,6 +1104,13 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
                 _cleanup_free_ uint8_t *array = NULL;
                 size_t allocated;
 
+                if (eq && streq(eq, "numa")) {
+                        r = sd_bus_message_append(m, "(sv)", "CPUAffinityFromNUMA", "b", true);
+                        if (r < 0)
+                                return bus_log_create_error(r);
+                        return r;
+                }
+
                 r = parse_cpu_set(eq, &cpuset);
                 if (r < 0)
                         return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
index 219314ef581dc294ff16ea327598e504db2fd1cf..9b9238362f2ff2d27f2fbcf4c4c65ee686c4500f 100644 (file)
 #include "log.h"
 #include "macro.h"
 #include "memory-util.h"
-#include "missing_syscall.h"
 #include "parse-util.h"
 #include "stat-util.h"
 #include "string-util.h"
-#include "string-table.h"
 #include "strv.h"
 #include "util.h"
 
@@ -133,7 +131,7 @@ int cpu_set_add_all(CPUSet *a, const CPUSet *b) {
                                 return r;
                 }
 
-        return 0;
+        return 1;
 }
 
 int parse_cpu_set_full(
@@ -218,7 +216,7 @@ int parse_cpu_set_extend(
         if (!old->set) {
                 *old = cpuset;
                 cpuset = (CPUSet) {};
-                return 0;
+                return 1;
         }
 
         return cpu_set_add_all(old, &cpuset);
@@ -295,88 +293,3 @@ int cpu_set_from_dbus(const uint8_t *bits, size_t size, CPUSet *set) {
         s = (CPUSet) {};
         return 0;
 }
-
-bool numa_policy_is_valid(const NUMAPolicy *policy) {
-        assert(policy);
-
-        if (!mpol_is_valid(numa_policy_get_type(policy)))
-                return false;
-
-        if (!policy->nodes.set &&
-            !IN_SET(numa_policy_get_type(policy), MPOL_DEFAULT, MPOL_LOCAL, MPOL_PREFERRED))
-                return false;
-
-        if (policy->nodes.set &&
-            numa_policy_get_type(policy) == MPOL_PREFERRED &&
-            CPU_COUNT_S(policy->nodes.allocated, policy->nodes.set) != 1)
-                return false;
-
-        return true;
-}
-
-static int numa_policy_to_mempolicy(const NUMAPolicy *policy, unsigned long *ret_maxnode, unsigned long **ret_nodes) {
-        unsigned node, bits = 0, ulong_bits;
-        _cleanup_free_ unsigned long *out = NULL;
-
-        assert(policy);
-        assert(ret_maxnode);
-        assert(ret_nodes);
-
-        if (IN_SET(numa_policy_get_type(policy), MPOL_DEFAULT, MPOL_LOCAL) ||
-            (numa_policy_get_type(policy) == MPOL_PREFERRED && !policy->nodes.set)) {
-                *ret_nodes = NULL;
-                *ret_maxnode = 0;
-                return 0;
-        }
-
-        bits = policy->nodes.allocated * 8;
-        ulong_bits = sizeof(unsigned long) * 8;
-
-        out = new0(unsigned long, DIV_ROUND_UP(policy->nodes.allocated, sizeof(unsigned long)));
-        if (!out)
-                return -ENOMEM;
-
-        /* We don't make any assumptions about internal type libc is using to store NUMA node mask.
-           Hence we need to convert the node mask to the representation expected by set_mempolicy() */
-        for (node = 0; node < bits; node++)
-                if (CPU_ISSET_S(node, policy->nodes.allocated, policy->nodes.set))
-                        out[node / ulong_bits] |= 1ul << (node % ulong_bits);
-
-        *ret_nodes = TAKE_PTR(out);
-        *ret_maxnode = bits + 1;
-        return 0;
-}
-
-int apply_numa_policy(const NUMAPolicy *policy) {
-        int r;
-        _cleanup_free_ unsigned long *nodes = NULL;
-        unsigned long maxnode;
-
-        assert(policy);
-
-        if (get_mempolicy(NULL, NULL, 0, 0, 0) < 0 && errno == ENOSYS)
-                return -EOPNOTSUPP;
-
-        if (!numa_policy_is_valid(policy))
-                return -EINVAL;
-
-        r = numa_policy_to_mempolicy(policy, &maxnode, &nodes);
-        if (r < 0)
-                return r;
-
-        r = set_mempolicy(numa_policy_get_type(policy), nodes, maxnode);
-        if (r < 0)
-                return -errno;
-
-        return 0;
-}
-
-static const char* const mpol_table[] = {
-        [MPOL_DEFAULT]    = "default",
-        [MPOL_PREFERRED]  = "preferred",
-        [MPOL_BIND]       = "bind",
-        [MPOL_INTERLEAVE] = "interleave",
-        [MPOL_LOCAL]      = "local",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(mpol, int);
index 27812dfd5923606675a3b73bb0f295053ae9bce3..a60d4ec41b599e2c04bc5a7a5489bd93f32dfce6 100644 (file)
@@ -49,30 +49,3 @@ int cpu_set_to_dbus(const CPUSet *set, uint8_t **ret, size_t *allocated);
 int cpu_set_from_dbus(const uint8_t *bits, size_t size, CPUSet *set);
 
 int cpus_in_affinity_mask(void);
-
-static inline bool mpol_is_valid(int t) {
-        return t >= MPOL_DEFAULT && t <= MPOL_LOCAL;
-}
-
-typedef struct NUMAPolicy {
-        /* Always use numa_policy_get_type() to read the value */
-        int type;
-        CPUSet nodes;
-} NUMAPolicy;
-
-bool numa_policy_is_valid(const NUMAPolicy *p);
-
-static inline int numa_policy_get_type(const NUMAPolicy *p) {
-        return p->type < 0 ? (p->nodes.set ? MPOL_PREFERRED : -1) : p->type;
-}
-
-static inline void numa_policy_reset(NUMAPolicy *p) {
-        assert(p);
-        cpu_set_reset(&p->nodes);
-        p->type = -1;
-}
-
-int apply_numa_policy(const NUMAPolicy *policy);
-
-const char* mpol_to_string(int i) _const_;
-int mpol_from_string(const char *s) _pure_;
index fa080f8e62d78765b08fe6c34a25ae18d0a0bae3..94174347a15d0d91aed909c79f1ba53af0d18946 100644 (file)
@@ -147,6 +147,8 @@ shared_sources = files('''
         nscd-flush.h
         nsflags.c
         nsflags.h
+        numa-util.c
+        numa-util.h
         openssl-util.h
         os-util.c
         os-util.h
diff --git a/src/shared/numa-util.c b/src/shared/numa-util.c
new file mode 100644 (file)
index 0000000..187992d
--- /dev/null
@@ -0,0 +1,135 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <errno.h>
+#include <sched.h>
+
+#include "alloc-util.h"
+#include "cpu-set-util.h"
+#include "fileio.h"
+#include "macro.h"
+#include "missing_syscall.h"
+#include "numa-util.h"
+#include "stdio-util.h"
+#include "string-table.h"
+
+bool numa_policy_is_valid(const NUMAPolicy *policy) {
+        assert(policy);
+
+        if (!mpol_is_valid(numa_policy_get_type(policy)))
+                return false;
+
+        if (!policy->nodes.set &&
+            !IN_SET(numa_policy_get_type(policy), MPOL_DEFAULT, MPOL_LOCAL, MPOL_PREFERRED))
+                return false;
+
+        if (policy->nodes.set &&
+            numa_policy_get_type(policy) == MPOL_PREFERRED &&
+            CPU_COUNT_S(policy->nodes.allocated, policy->nodes.set) != 1)
+                return false;
+
+        return true;
+}
+
+static int numa_policy_to_mempolicy(const NUMAPolicy *policy, unsigned long *ret_maxnode, unsigned long **ret_nodes) {
+        unsigned node, bits = 0, ulong_bits;
+        _cleanup_free_ unsigned long *out = NULL;
+
+        assert(policy);
+        assert(ret_maxnode);
+        assert(ret_nodes);
+
+        if (IN_SET(numa_policy_get_type(policy), MPOL_DEFAULT, MPOL_LOCAL) ||
+            (numa_policy_get_type(policy) == MPOL_PREFERRED && !policy->nodes.set)) {
+                *ret_nodes = NULL;
+                *ret_maxnode = 0;
+                return 0;
+        }
+
+        bits = policy->nodes.allocated * 8;
+        ulong_bits = sizeof(unsigned long) * 8;
+
+        out = new0(unsigned long, DIV_ROUND_UP(policy->nodes.allocated, sizeof(unsigned long)));
+        if (!out)
+                return -ENOMEM;
+
+        /* We don't make any assumptions about internal type libc is using to store NUMA node mask.
+           Hence we need to convert the node mask to the representation expected by set_mempolicy() */
+        for (node = 0; node < bits; node++)
+                if (CPU_ISSET_S(node, policy->nodes.allocated, policy->nodes.set))
+                        out[node / ulong_bits] |= 1ul << (node % ulong_bits);
+
+        *ret_nodes = TAKE_PTR(out);
+        *ret_maxnode = bits + 1;
+        return 0;
+}
+
+int apply_numa_policy(const NUMAPolicy *policy) {
+        int r;
+        _cleanup_free_ unsigned long *nodes = NULL;
+        unsigned long maxnode;
+
+        assert(policy);
+
+        if (get_mempolicy(NULL, NULL, 0, 0, 0) < 0 && errno == ENOSYS)
+                return -EOPNOTSUPP;
+
+        if (!numa_policy_is_valid(policy))
+                return -EINVAL;
+
+        r = numa_policy_to_mempolicy(policy, &maxnode, &nodes);
+        if (r < 0)
+                return r;
+
+        r = set_mempolicy(numa_policy_get_type(policy), nodes, maxnode);
+        if (r < 0)
+                return -errno;
+
+        return 0;
+}
+
+int numa_to_cpu_set(const NUMAPolicy *policy, CPUSet *ret) {
+        int r;
+        size_t i;
+        _cleanup_(cpu_set_reset) CPUSet s = {};
+
+        assert(policy);
+        assert(ret);
+
+        for (i = 0; i < policy->nodes.allocated * 8; i++) {
+                _cleanup_free_ char *l = NULL;
+                char p[STRLEN("/sys/devices/system/node/node//cpulist") + DECIMAL_STR_MAX(size_t) + 1];
+                _cleanup_(cpu_set_reset) CPUSet part = {};
+
+                if (!CPU_ISSET_S(i, policy->nodes.allocated, policy->nodes.set))
+                        continue;
+
+                xsprintf(p, "/sys/devices/system/node/node%zu/cpulist", i);
+
+                r = read_one_line_file(p, &l);
+                if (r < 0)
+                        return r;
+
+                r = parse_cpu_set(l, &part);
+                if (r < 0)
+                        return r;
+
+                r = cpu_set_add_all(&s, &part);
+                if (r < 0)
+                        return r;
+        }
+
+        *ret = s;
+        s = (CPUSet) {};
+
+        return 0;
+}
+
+static const char* const mpol_table[] = {
+        [MPOL_DEFAULT]    = "default",
+        [MPOL_PREFERRED]  = "preferred",
+        [MPOL_BIND]       = "bind",
+        [MPOL_INTERLEAVE] = "interleave",
+        [MPOL_LOCAL]      = "local",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(mpol, int);
diff --git a/src/shared/numa-util.h b/src/shared/numa-util.h
new file mode 100644 (file)
index 0000000..c991789
--- /dev/null
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include "cpu-set-util.h"
+#include "missing_syscall.h"
+
+static inline bool mpol_is_valid(int t) {
+        return t >= MPOL_DEFAULT && t <= MPOL_LOCAL;
+}
+
+typedef struct NUMAPolicy {
+        /* Always use numa_policy_get_type() to read the value */
+        int type;
+        CPUSet nodes;
+} NUMAPolicy;
+
+bool numa_policy_is_valid(const NUMAPolicy *p);
+
+static inline int numa_policy_get_type(const NUMAPolicy *p) {
+        return p->type < 0 ? (p->nodes.set ? MPOL_PREFERRED : -1) : p->type;
+}
+
+static inline void numa_policy_reset(NUMAPolicy *p) {
+        assert(p);
+        cpu_set_reset(&p->nodes);
+        p->type = -1;
+}
+
+int apply_numa_policy(const NUMAPolicy *policy);
+int numa_to_cpu_set(const NUMAPolicy *policy, CPUSet *set);
+
+const char* mpol_to_string(int i) _const_;
+int mpol_from_string(const char *s) _pure_;
index ba3fe9ec2f7e121b6f4496dd1cf092bfb92c606c..f8b0adc3347b9d798b622da1fbd294af47a9dde7 100644 (file)
@@ -58,6 +58,7 @@
 #include "main-func.h"
 #include "memory-util.h"
 #include "mkdir.h"
+#include "numa-util.h"
 #include "pager.h"
 #include "parse-util.h"
 #include "path-lookup.h"
index 0002ea0e5952d658eae3da8e259f234fcdf61b16..9dd562fa43f646aa0d51631402a96e24e20538e9 100644 (file)
@@ -179,7 +179,8 @@ int sd_dhcp_client_set_service_type(
                 sd_dhcp_client *client,
                 int type);
 
-int sd_dhcp_client_set_dhcp_option(sd_dhcp_client *client, sd_dhcp_option *v);
+int sd_dhcp_client_add_option(sd_dhcp_client *client, sd_dhcp_option *v);
+int sd_dhcp_client_add_vendor_option(sd_dhcp_client *client, sd_dhcp_option *v);
 
 int sd_dhcp_client_stop(sd_dhcp_client *client);
 int sd_dhcp_client_start(sd_dhcp_client *client);
index 5950506c9bc5caad9ae2f9e6d5b312c5f3274915..55272b5164d5bd11d54ff496e7a1d5e5665f6ec5 100644 (file)
@@ -53,6 +53,7 @@ int sd_dhcp_server_set_sip(sd_dhcp_server *server, const struct in_addr sip[], u
 int sd_dhcp_server_set_emit_router(sd_dhcp_server *server, int enabled);
 
 int sd_dhcp_server_add_option(sd_dhcp_server *server, sd_dhcp_option *v);
+int sd_dhcp_server_add_vendor_option(sd_dhcp_server *server, sd_dhcp_option *v);
 
 int sd_dhcp_server_set_max_lease_time(sd_dhcp_server *server, uint32_t t);
 int sd_dhcp_server_set_default_lease_time(sd_dhcp_server *server, uint32_t t);
index e1dd2eb32bae62c1ef3722c2e7b888bbe7eb828d..450e19e06f2d90166cca85cb493a2d69aa1750c8 100644 (file)
@@ -216,12 +216,12 @@ static void test_parse_cpu_set_extend(void) {
 
         log_info("/* %s */", __func__);
 
-        assert_se(parse_cpu_set_extend("1 3", &c, true, NULL, "fake", 1, "CPUAffinity") == 0);
+        assert_se(parse_cpu_set_extend("1 3", &c, true, NULL, "fake", 1, "CPUAffinity") == 1);
         assert_se(CPU_COUNT_S(c.allocated, c.set) == 2);
         assert_se(s1 = cpu_set_to_string(&c));
         log_info("cpu_set_to_string: %s", s1);
 
-        assert_se(parse_cpu_set_extend("4", &c, true, NULL, "fake", 1, "CPUAffinity") == 0);
+        assert_se(parse_cpu_set_extend("4", &c, true, NULL, "fake", 1, "CPUAffinity") == 1);
         assert_se(CPU_COUNT_S(c.allocated, c.set) == 3);
         assert_se(s2 = cpu_set_to_string(&c));
         log_info("cpu_set_to_string: %s", s2);
@@ -238,7 +238,7 @@ static void test_cpu_set_to_from_dbus(void) {
 
         log_info("/* %s */", __func__);
 
-        assert_se(parse_cpu_set_extend("1 3 8 100-200", &c, true, NULL, "fake", 1, "CPUAffinity") == 0);
+        assert_se(parse_cpu_set_extend("1 3 8 100-200", &c, true, NULL, "fake", 1, "CPUAffinity") == 1);
         assert_se(s = cpu_set_to_string(&c));
         log_info("cpu_set_to_string: %s", s);
         assert_se(CPU_COUNT_S(c.allocated, c.set) == 104);
index 4a2bede431a6fe1459b1a74dcfe641065665ae36..bd04bb2efe61bc05601be54d827ba05ad6cda112 100755 (executable)
@@ -279,6 +279,18 @@ else
     # Maks must be ignored
     grep -E "set_mempolicy\((MPOL_LOCAL|0x4 [^,]*), NULL" $straceLog
 
+    echo "Unit file CPUAffinity=NUMA support"
+    writeTestUnitNUMAPolicy "bind" "0"
+    echo "CPUAffinity=numa" >> $testUnitNUMAConf
+    systemctl daemon-reload
+    systemctl start $testUnit
+    systemctlCheckNUMAProperties $testUnit "bind" "0"
+    pid=$(systemctl show --value -p MainPID $testUnit)
+    cpulist=$(cat /sys/devices/system/node/node0/cpulist)
+    affinity_systemd=$(systemctl show --value -p CPUAffinity $testUnit)
+    [ $cpulist = $affinity_systemd ]
+    pid1StopUnit $testUnit
+
     echo "systemd-run NUMAPolicy support"
     runUnit='numa-systemd-run-test.service'
 
@@ -309,6 +321,12 @@ else
     systemd-run -p NUMAPolicy=local -p NUMAMask=0 --unit $runUnit sleep 1000
     systemctlCheckNUMAProperties $runUnit "local" ""
     pid1StopUnit $runUnit
+
+    systemd-run -p NUMAPolicy=local -p NUMAMask=0 -p CPUAffinity=numa --unit $runUnit sleep 1000
+    systemctlCheckNUMAProperties $runUnit "local" ""
+    systemctl cat $runUnit | grep -q 'CPUAffinity=numa'
+    pid1StopUnit $runUnit
+
 fi
 
 # Cleanup
index b3465ceb8c9f11c3a3529de2a55cabde99eb6731..4418fc01495b92e2b16902e4488939f8c0fee072 100644 (file)
@@ -100,6 +100,7 @@ SendRelease=
 MaxAttempts=
 IPServiceType=
 SendOption=
+SendVendorOption=
 SendDecline=
 RouteMTUBytes=
 [DHCPv6]
@@ -273,6 +274,7 @@ DefaultLeaseTimeSec=
 EmitTimezone=
 DNS=
 SendOption=
+SendVendorOption=
 [NextHop]
 Id=
 Gateway=