]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #9157 from poettering/unit-config-load-error
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Mon, 11 Jun 2018 12:37:10 +0000 (14:37 +0200)
committerGitHub <noreply@github.com>
Mon, 11 Jun 2018 12:37:10 +0000 (14:37 +0200)
introduce a new "bad-setting" unit load state in order to improve "systemctl status" output when bad settings are used

17 files changed:
man/systemd.exec.xml
man/systemd.network.xml
src/basic/parse-util.c
src/basic/parse-util.h
src/core/dbus-socket.c
src/core/socket.c
src/core/socket.h
src/libsystemd/sd-netlink/netlink-types.c
src/libsystemd/sd-netlink/netlink-types.h
src/network/networkd-link.c
src/network/networkd-network-gperf.gperf
src/network/networkd-network.c
src/network/networkd-network.h
src/shared/conf-parser.c
src/shared/conf-parser.h
src/systemctl/systemctl.c
src/test/test-parse-util.c

index a613c390873a87fcf6cd3d65ee58658ce5d09b2e..872d51d4ecc1108593757c7328578516d7a170c8 100644 (file)
@@ -805,13 +805,48 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
 
         <listitem><para>These options take a whitespace-separated list of directory names. The specified directory
         names must be relative, and may not include <literal>..</literal>. If set, one or more
-        directories by the specified names will be created (including their parents) below <filename>/run</filename>
-        (or <varname>$XDG_RUNTIME_DIR</varname> for user services), <filename>/var/lib</filename> (or
-        <varname>$XDG_CONFIG_HOME</varname> for user services), <filename>/var/cache</filename> (or
-        <varname>$XDG_CACHE_HOME</varname> for user services), <filename>/var/log</filename> (or
-        <varname>$XDG_CONFIG_HOME</varname><filename>/log</filename> for user services), or <filename>/etc</filename>
-        (or <varname>$XDG_CONFIG_HOME</varname> for user services), respectively, when the unit is started.</para>
-
+        directories by the specified names will be created (including their parents) below the locations
+        defined in the following table, when the unit is started.</para>          
+        <table>
+          <title>Automatic directory creation</title>
+          <tgroup cols='3'>
+            <thead>
+              <row>
+                <entry>Locations</entry>
+                <entry>for system</entry>
+                <entry>for users</entry>
+              </row>
+            </thead>
+            <tbody>
+              <row>
+                <entry><varname>RuntimeDirectory=</varname></entry>
+                <entry><filename>/run</filename></entry>
+                <entry><varname>$XDG_RUNTIME_DIR</varname></entry>
+              </row>
+              <row>
+                <entry><varname>StateDirectory=</varname></entry>
+                <entry><filename>/var/lib</filename></entry>
+                <entry><varname>$XDG_CONFIG_HOME</varname></entry>
+              </row>
+              <row>
+                <entry><varname>CacheDirectory=</varname></entry>
+                <entry><filename>/var/cache</filename></entry>
+                <entry><varname>$XDG_CACHE_HOME</varname></entry>
+              </row>
+              <row>
+                <entry><varname>LogsDirectory=</varname></entry>
+                <entry><filename>/var/log</filename></entry>
+                <entry><varname>$XDG_CONFIG_HOME</varname><filename>/log</filename></entry>
+              </row>
+              <row>
+                <entry><varname>ConfigurationDirectory=</varname></entry>
+                <entry><filename>/etc</filename></entry>
+                <entry><varname>$XDG_CONFIG_HOME</varname></entry>
+              </row>
+            </tbody>
+          </tgroup>
+        </table>
+          
         <para>In case of <varname>RuntimeDirectory=</varname> the lowest subdirectories are removed when the unit is
         stopped. It is possible to preserve the specified directories in this case if
         <varname>RuntimeDirectoryPreserve=</varname> is configured to <option>restart</option> or <option>yes</option>
index 96ccf5f637d6837878ca6c36fff0b96368e12eb3..d7bcf5a06754fc5aceb6b547e96ee6353506d1e0 100644 (file)
         </varlistentry>
       </variablelist>
   </refsect1>
+
+  <refsect1>
+    <title>[CAN] Section Options</title>
+      <para>The <literal>[CAN]</literal> section manages the Controller Area Network (CAN bus) and accepts the
+      following keys.</para>
+      <variablelist class='network-directives'>
+        <varlistentry>
+          <term><varname>BitRate=</varname></term>
+          <listitem>
+            <para>The bitrate of CAN device in bits per second. The usual SI prefixes (K, M) with the base of 1000 can
+            be used here.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><varname>SamplePoint=</varname></term>
+          <listitem>
+            <para>Optional sample point in percent with one decimal (e.g. <literal>75%</literal>,
+            <literal>87.5%</literal>) or permille (e.g. <literal>875‰</literal>).</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><varname>RestartSec=</varname></term>
+          <listitem>
+            <para>Automatic restart delay time. If set to a non-zero value, a restart of the CAN controller will be
+            triggered automatically in case of a bus-off condition after the specified delay time. Subsecond delays can
+            be specified using decimals (e.g. <literal>0.1s</literal>) or a <literal>ms</literal> or
+            <literal>us</literal> postfix. Using <literal>infinity</literal> or <literal>0</literal> will turn the
+            automatic restart off. By default automatic restart is disabled.</para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+  </refsect1>
+
   <refsect1>
     <title>[BridgeVLAN] Section Options</title>
       <para>The <literal>[BridgeVLAN]</literal> section manages the VLAN ID configuration of a bridge port and accepts
index 07f43b94e5e30db12f2dcd2b6d4cc866db998209..b25bc6e2151614e58c102e680c7c1fffc306fc99 100644 (file)
@@ -632,6 +632,58 @@ int parse_percent(const char *p) {
         return v;
 }
 
+int parse_permille_unbounded(const char *p) {
+        const char *pc, *pm, *dot, *n;
+        int r, q, v;
+
+        pm = endswith(p, "‰");
+        if (pm) {
+                n = strndupa(p, pm - p);
+                r = safe_atoi(n, &v);
+                if (r < 0)
+                        return r;
+        } else {
+                pc = endswith(p, "%");
+                if (!pc)
+                        return -EINVAL;
+
+                dot = memchr(p, '.', pc - p);
+                if (dot) {
+                        if (dot + 2 != pc)
+                                return -EINVAL;
+                        if (dot[1] < '0' || dot[1] > '9')
+                                return -EINVAL;
+                        q = dot[1] - '0';
+                        n = strndupa(p, dot - p);
+                } else {
+                        q = 0;
+                        n = strndupa(p, pc - p);
+                }
+                r = safe_atoi(n, &v);
+                if (r < 0)
+                        return r;
+                if (v > ((INT_MAX - q) / 10))
+                        return -ERANGE;
+
+                v = v * 10 + q;
+        }
+
+        if (v < 0)
+                return -ERANGE;
+
+        return v;
+}
+
+int parse_permille(const char *p) {
+        int v;
+
+        v = parse_permille_unbounded(p);
+        if (v > 1000)
+                return -ERANGE;
+
+        return v;
+}
+
 int parse_nice(const char *p, int *ret) {
         int n, r;
 
index 2b75b938c70e3cd22a500be10411807e6b1f6c5c..b3edfbaecc08ddf10e2446c8e57b5e6ec35044f5 100644 (file)
@@ -115,6 +115,9 @@ int parse_fractional_part_u(const char **s, size_t digits, unsigned *res);
 int parse_percent_unbounded(const char *p);
 int parse_percent(const char *p);
 
+int parse_permille_unbounded(const char *p);
+int parse_permille(const char *p);
+
 int parse_nice(const char *p, int *ret);
 
 int parse_ip_port(const char *s, uint16_t *ret);
index aee81430bb681837c1d5874f4f58d6059c875651..cb0884be13a22bf697d45569edcd6b3cb28b6695 100644 (file)
@@ -125,6 +125,7 @@ const sd_bus_vtable bus_socket_vtable[] = {
         SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Socket, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("NConnections", "u", bus_property_get_unsigned, offsetof(Socket, n_connections), 0),
         SD_BUS_PROPERTY("NAccepted", "u", bus_property_get_unsigned, offsetof(Socket, n_accepted), 0),
+        SD_BUS_PROPERTY("NRefused", "u", bus_property_get_unsigned, offsetof(Socket, n_refused), 0),
         SD_BUS_PROPERTY("FileDescriptorName", "s", property_get_fdname, 0, 0),
         SD_BUS_PROPERTY("SocketProtocol", "i", bus_property_get_int, offsetof(Socket, socket_protocol), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("TriggerLimitIntervalUSec", "t", bus_property_get_usec, offsetof(Socket, trigger_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST),
index 25e99e9e3bca272a0d64b2d18c275c6f4775db67..0a74076f05d32410d7e23ccf7baa6b3e846a9963 100644 (file)
@@ -2243,7 +2243,7 @@ static void socket_enter_running(Socket *s, int cfd) {
                 log_unit_debug(UNIT(s), "Suppressing connection request since unit stop is scheduled.");
 
                 if (cfd >= 0)
-                        cfd = safe_close(cfd);
+                        goto refuse;
                 else
                         flush_ports(s);
 
@@ -2251,10 +2251,9 @@ static void socket_enter_running(Socket *s, int cfd) {
         }
 
         if (!ratelimit_below(&s->trigger_limit)) {
-                safe_close(cfd);
                 log_unit_warning(UNIT(s), "Trigger limit hit, refusing further activation.");
                 socket_enter_stop_pre(s, SOCKET_FAILURE_TRIGGER_LIMIT_HIT);
-                return;
+                goto refuse;
         }
 
         if (cfd < 0) {
@@ -2292,15 +2291,13 @@ static void socket_enter_running(Socket *s, int cfd) {
                 if (s->n_connections >= s->max_connections) {
                         log_unit_warning(UNIT(s), "Too many incoming connections (%u), dropping connection.",
                                          s->n_connections);
-                        safe_close(cfd);
-                        return;
+                        goto refuse;
                 }
 
                 if (s->max_connections_per_source > 0) {
                         r = socket_acquire_peer(s, cfd, &p);
                         if (r < 0) {
-                                safe_close(cfd);
-                                return;
+                                goto refuse;
                         } else if (r > 0 && p->n_ref > s->max_connections_per_source) {
                                 _cleanup_free_ char *t = NULL;
 
@@ -2309,8 +2306,7 @@ static void socket_enter_running(Socket *s, int cfd) {
                                 log_unit_warning(UNIT(s),
                                                  "Too many incoming connections (%u) from source %s, dropping connection.",
                                                  p->n_ref, strnull(t));
-                                safe_close(cfd);
-                                return;
+                                goto refuse;
                         }
                 }
 
@@ -2326,8 +2322,7 @@ static void socket_enter_running(Socket *s, int cfd) {
                         /* ENOTCONN is legitimate if TCP RST was received.
                          * This connection is over, but the socket unit lives on. */
                         log_unit_debug(UNIT(s), "Got ENOTCONN on incoming socket, assuming aborted connection attempt, ignoring.");
-                        safe_close(cfd);
-                        return;
+                        goto refuse;
                 }
 
                 r = unit_name_to_prefix(UNIT(s)->id, &prefix);
@@ -2371,6 +2366,11 @@ static void socket_enter_running(Socket *s, int cfd) {
 
         return;
 
+refuse:
+        s->n_refused++;
+        safe_close(cfd);
+        return;
+
 fail:
         log_unit_warning(UNIT(s), "Failed to queue service startup job (Maybe the service file is missing or not a %s unit?): %s",
                          cfd >= 0 ? "template" : "non-template",
@@ -2514,6 +2514,7 @@ static int socket_serialize(Unit *u, FILE *f, FDSet *fds) {
         unit_serialize_item(u, f, "state", socket_state_to_string(s->state));
         unit_serialize_item(u, f, "result", socket_result_to_string(s->result));
         unit_serialize_item_format(u, f, "n-accepted", "%u", s->n_accepted);
+        unit_serialize_item_format(u, f, "n-refused", "%u", s->n_refused);
 
         if (s->control_pid > 0)
                 unit_serialize_item_format(u, f, "control-pid", PID_FMT, s->control_pid);
@@ -2594,6 +2595,13 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value,
                         log_unit_debug(u, "Failed to parse n-accepted value: %s", value);
                 else
                         s->n_accepted += k;
+        } else if (streq(key, "n-refused")) {
+                unsigned k;
+
+                if (safe_atou(value, &k) < 0)
+                        log_unit_debug(u, "Failed to parse n-refused value: %s", value);
+                else
+                        s->n_refused += k;
         } else if (streq(key, "control-pid")) {
                 pid_t pid;
 
index 8a9559d5c6da0c7f89a92338a134491e96a3c3d3..ffee43cdc5a3900eff84a11cf7a54175b9255b52 100644 (file)
@@ -73,6 +73,7 @@ struct Socket {
 
         unsigned n_accepted;
         unsigned n_connections;
+        unsigned n_refused;
         unsigned max_connections;
         unsigned max_connections_per_source;
 
index ddb4d90eaf2e82b930257e8bb19eff5716503c35..a82b1e1a89018d755aa5f2ff6cdc3431e8baa3e2 100644 (file)
@@ -300,6 +300,11 @@ static const NLType rtnl_link_info_data_geneve_types[] = {
         [IFLA_GENEVE_LABEL]             = { .type = NETLINK_TYPE_U32 },
 };
 
+static const NLType rtnl_link_info_data_can_types[] = {
+        [IFLA_CAN_BITTIMING]            = { .size = sizeof(struct can_bittiming) },
+        [IFLA_CAN_RESTART_MS]           = { .type = NETLINK_TYPE_U32 },
+};
+
 /* these strings must match the .kind entries in the kernel */
 static const char* const nl_union_link_info_data_table[] = {
         [NL_UNION_LINK_INFO_DATA_BOND] = "bond",
@@ -326,6 +331,7 @@ static const char* const nl_union_link_info_data_table[] = {
         [NL_UNION_LINK_INFO_DATA_VXCAN] = "vxcan",
         [NL_UNION_LINK_INFO_DATA_WIREGUARD] = "wireguard",
         [NL_UNION_LINK_INFO_DATA_NETDEVSIM] = "netdevsim",
+        [NL_UNION_LINK_INFO_DATA_CAN] = "can",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(nl_union_link_info_data, NLUnionLinkInfoData);
@@ -371,6 +377,8 @@ static const NLTypeSystem rtnl_link_info_data_type_systems[] = {
                                                        .types = rtnl_link_info_data_geneve_types },
         [NL_UNION_LINK_INFO_DATA_VXCAN] =            { .count = ELEMENTSOF(rtnl_link_info_data_vxcan_types),
                                                        .types = rtnl_link_info_data_vxcan_types },
+        [NL_UNION_LINK_INFO_DATA_CAN] =              { .count = ELEMENTSOF(rtnl_link_info_data_can_types),
+                                                       .types = rtnl_link_info_data_can_types },
 };
 
 static const NLTypeSystemUnion rtnl_link_info_data_type_system_union = {
index a7542eb33d11297c975713bcf972169c9457cfd2..559976c24c28d2cbc3c32f8cdcf2c2aed657aa6f 100644 (file)
@@ -83,6 +83,7 @@ typedef enum NLUnionLinkInfoData {
         NL_UNION_LINK_INFO_DATA_VXCAN,
         NL_UNION_LINK_INFO_DATA_WIREGUARD,
         NL_UNION_LINK_INFO_DATA_NETDEVSIM,
+        NL_UNION_LINK_INFO_DATA_CAN,
         _NL_UNION_LINK_INFO_DATA_MAX,
         _NL_UNION_LINK_INFO_DATA_INVALID = -1
 } NLUnionLinkInfoData;
index c714cd4fc72bee09c1c8f1d977e64038a364e564..c0496407abeb5d5d4f2ff44d4050131050c8c553 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <netinet/ether.h>
 #include <linux/if.h>
+#include <linux/can/netlink.h>
 #include <unistd.h>
 #include <stdio_ext.h>
 
@@ -1847,67 +1848,171 @@ int link_up(Link *link) {
         return 0;
 }
 
-static int link_down_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
-        _cleanup_(link_unrefp) Link *link = userdata;
+static int link_up_can(Link *link) {
+        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
         int r;
 
         assert(link);
 
-        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
-                return 1;
+        log_link_debug(link, "Bringing CAN link up");
 
-        r = sd_netlink_message_get_errno(m);
+        r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
         if (r < 0)
-                log_link_warning_errno(link, r, "Could not bring down interface: %m");
+                return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
 
-        return 1;
+        r = sd_rtnl_message_link_set_flags(req, IFF_UP, IFF_UP);
+        if (r < 0)
+                return log_link_error_errno(link, r, "Could not set link flags: %m");
+
+        r = sd_netlink_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL);
+        if (r < 0)
+                return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
+
+        link_ref(link);
+
+        return 0;
 }
 
-int link_down(Link *link) {
-        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
+static int link_set_can(Link *link) {
+        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
         int r;
 
         assert(link);
+        assert(link->network);
         assert(link->manager);
         assert(link->manager->rtnl);
 
-        log_link_debug(link, "Bringing link down");
+        log_link_debug(link, "link_set_can");
 
-        r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
-                                     RTM_SETLINK, link->ifindex);
+        r = sd_rtnl_message_new_link(link->manager->rtnl, &m, RTM_NEWLINK, link->ifindex);
         if (r < 0)
-                return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
+                return log_link_error_errno(link, r, "Failed to allocate netlink message: %m");
 
-        r = sd_rtnl_message_link_set_flags(req, 0, IFF_UP);
+        r = sd_netlink_message_set_flags(m, NLM_F_REQUEST | NLM_F_ACK);
         if (r < 0)
-                return log_link_error_errno(link, r, "Could not set link flags: %m");
+                return log_link_error_errno(link, r, "Could not set netlink flags: %m");
 
-        r = sd_netlink_call_async(link->manager->rtnl, req, link_down_handler, link,  0, NULL);
+        r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
+        if (r < 0)
+                return log_link_error_errno(link, r, "Failed to open netlink container: %m");
+
+        r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, link->kind);
+        if (r < 0)
+                return log_link_error_errno(link, r, "Could not append IFLA_INFO_DATA attribute: %m");
+
+        if (link->network->can_bitrate > 0 || link->network->can_sample_point > 0) {
+                struct can_bittiming bt = {
+                        .bitrate = link->network->can_bitrate,
+                        .sample_point = link->network->can_sample_point,
+                };
+
+                if (link->network->can_bitrate > UINT32_MAX) {
+                        log_link_error(link, "bitrate (%zu) too big.", link->network->can_bitrate);
+                        return -ERANGE;
+                }
+
+                log_link_debug(link, "Setting bitrate = %d bit/s", bt.bitrate);
+                if (link->network->can_sample_point > 0)
+                        log_link_debug(link, "Setting sample point = %d.%d%%", bt.sample_point / 10, bt.sample_point % 10);
+                else
+                        log_link_debug(link, "Using default sample point");
+
+                r = sd_netlink_message_append_data(m, IFLA_CAN_BITTIMING, &bt, sizeof(bt));
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not append IFLA_CAN_BITTIMING attribute: %m");
+        }
+
+        if (link->network->can_restart_us > 0) {
+                char time_string[FORMAT_TIMESPAN_MAX];
+                uint64_t restart_ms;
+
+                if (link->network->can_restart_us == USEC_INFINITY)
+                        restart_ms = 0;
+                else
+                        restart_ms = DIV_ROUND_UP(link->network->can_restart_us, USEC_PER_MSEC);
+
+                format_timespan(time_string, FORMAT_TIMESPAN_MAX, restart_ms * 1000, MSEC_PER_SEC);
+
+                if (restart_ms > UINT32_MAX) {
+                        log_link_error(link, "restart timeout (%s) too big.", time_string);
+                        return -ERANGE;
+                }
+
+                log_link_debug(link, "Setting restart = %s", time_string);
+
+                r = sd_netlink_message_append_u32(m, IFLA_CAN_RESTART_MS, restart_ms);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not append IFLA_CAN_RESTART_MS attribute: %m");
+        }
+
+        r = sd_netlink_message_close_container(m);
+        if (r < 0)
+                return log_link_error_errno(link, r, "Failed to close netlink container: %m");
+
+        r = sd_netlink_message_close_container(m);
+        if (r < 0)
+                return log_link_error_errno(link, r, "Failed to close netlink container: %m");
+
+        r = sd_netlink_call_async(link->manager->rtnl, m, link_set_handler, link,  0, NULL);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
 
         link_ref(link);
 
-        return 0;
+        if (!(link->flags & IFF_UP)) {
+                r = link_up_can(link);
+                if (r < 0) {
+                        link_enter_failed(link);
+                        return r;
+                }
+        }
+
+        log_link_debug(link, "link_set_can done");
+
+        return r;
 }
 
-static int link_up_can(Link *link) {
+static int link_down_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
+        _cleanup_(link_unrefp) Link *link = userdata;
+        int r;
+
+        assert(link);
+
+        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+                return 1;
+
+        r = sd_netlink_message_get_errno(m);
+        if (r < 0)
+                log_link_warning_errno(link, r, "Could not bring down interface: %m");
+
+        if (streq_ptr(link->kind, "can")) {
+                link_ref(link);
+                link_set_can(link);
+        }
+
+        return 1;
+}
+
+int link_down(Link *link) {
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
         int r;
 
         assert(link);
+        assert(link->manager);
+        assert(link->manager->rtnl);
 
-        log_link_debug(link, "Bringing CAN link up");
+        log_link_debug(link, "Bringing link down");
 
-        r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
+        r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
+                                     RTM_SETLINK, link->ifindex);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
 
-        r = sd_rtnl_message_link_set_flags(req, IFF_UP, IFF_UP);
+        r = sd_rtnl_message_link_set_flags(req, 0, IFF_UP);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not set link flags: %m");
 
-        r = sd_netlink_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL);
+        r = sd_netlink_call_async(link->manager->rtnl, req, link_down_handler, link,  0, NULL);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
 
@@ -2599,26 +2704,45 @@ static int link_update_lldp(Link *link) {
         return r;
 }
 
-static int link_configure(Link *link) {
+static int link_configure_can(Link *link) {
         int r;
 
-        assert(link);
-        assert(link->network);
-        assert(link->state == LINK_STATE_PENDING);
-
-        if (streq_ptr(link->kind, "vcan")) {
-
-                if (!(link->flags & IFF_UP)) {
-                        r = link_up_can(link);
+        if (streq_ptr(link->kind, "can")) {
+                /* The CAN interface must be down to configure bitrate, etc... */
+                if ((link->flags & IFF_UP)) {
+                        r = link_down(link);
                         if (r < 0) {
                                 link_enter_failed(link);
                                 return r;
                         }
+
+                        return 0;
                 }
 
-                return 0;
+                return link_set_can(link);
+        }
+
+        if (!(link->flags & IFF_UP)) {
+                r = link_up_can(link);
+                if (r < 0) {
+                        link_enter_failed(link);
+                        return r;
+                }
         }
 
+        return 0;
+}
+
+static int link_configure(Link *link) {
+        int r;
+
+        assert(link);
+        assert(link->network);
+        assert(link->state == LINK_STATE_PENDING);
+
+        if (STRPTR_IN_SET(link->kind, "can", "vcan"))
+                return link_configure_can(link);
+
         /* Drop foreign config, but ignore loopback or critical devices.
          * We do not want to remove loopback address or addresses used for root NFS. */
         if (!(link->flags & IFF_LOOPBACK) && !(link->network->dhcp_critical)) {
index 7e625e48fa467d4e9b030a5fd4cad5a45384dccb..e6ca6631ed7ab4c9ce176cb95a3629d593baf779 100644 (file)
@@ -178,6 +178,9 @@ IPv6Prefix.OnLink,                      config_parse_prefix_flags,
 IPv6Prefix.AddressAutoconfiguration,    config_parse_prefix_flags,                      0,                             0
 IPv6Prefix.ValidLifetimeSec,            config_parse_prefix_lifetime,                   0,                             0
 IPv6Prefix.PreferredLifetimeSec,        config_parse_prefix_lifetime,                   0,                             0
+CAN.BitRate,                            config_parse_si_size,                           0,                             offsetof(Network, can_bitrate)
+CAN.SamplePoint,                        config_parse_permille,                          0,                             offsetof(Network, can_sample_point)
+CAN.RestartSec,                         config_parse_sec,                               0,                             offsetof(Network, can_restart_us)
 /* backwards compatibility: do not add new entries to this section */
 Network.IPv4LL,                         config_parse_ipv4ll,                            0,                             offsetof(Network, link_local)
 DHCPv4.UseDNS,                          config_parse_bool,                              0,                             offsetof(Network, dhcp_use_dns)
index c3a11ddca07a7ef8ad55a38e3833f1c0a59360c4..b2a75c7e98355ac0d506618f9618cbe345e15c47 100644 (file)
@@ -272,7 +272,8 @@ static int network_load_one(Manager *manager, const char *filename) {
                               "BridgeFDB\0"
                               "BridgeVLAN\0"
                               "IPv6PrefixDelegation\0"
-                              "IPv6Prefix\0",
+                              "IPv6Prefix\0"
+                              "CAN\0",
                               config_item_perf_lookup, network_network_gperf_lookup,
                               CONFIG_PARSE_WARN, network);
         if (r < 0)
index b8e2c523a3c26b96682e2104c028a36b11b22676..5b6b40d5da3b666162c2968788f71552c8276251 100644 (file)
@@ -191,6 +191,11 @@ struct Network {
         uint32_t br_vid_bitmap[BRIDGE_VLAN_BITMAP_LEN];
         uint32_t br_untagged_bitmap[BRIDGE_VLAN_BITMAP_LEN];
 
+        /* CAN support */
+        size_t can_bitrate;
+        unsigned can_sample_point;
+        usec_t can_restart_us;
+
         AddressFamilyBoolean ip_forward;
         bool ip_masquerade;
 
index b5ee07c9bd773336da9deec6e981469ac32b27b0..29dd1ddc887194d8468c918013c7667e985d53c6 100644 (file)
@@ -1203,3 +1203,34 @@ int config_parse_rlimit(
 
         return 0;
 }
+
+int config_parse_permille(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) {
+
+        unsigned *permille = data;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(permille);
+
+        r = parse_permille(rvalue);
+        if (r < 0) {
+                log_syntax(unit, LOG_ERR, filename, line, r,
+                           "Failed to parse permille value, ignoring: %s", rvalue);
+                return 0;
+        }
+
+        *permille = (unsigned) r;
+
+        return 0;
+}
index 70d313d4ebd5d8123d19d118d63cac2daecab96a..8546d5ce6695c846ca9115349c5693e02d7c8306 100644 (file)
@@ -140,6 +140,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_log_facility);
 CONFIG_PARSER_PROTOTYPE(config_parse_log_level);
 CONFIG_PARSER_PROTOTYPE(config_parse_signal);
 CONFIG_PARSER_PROTOTYPE(config_parse_personality);
+CONFIG_PARSER_PROTOTYPE(config_parse_permille);
 CONFIG_PARSER_PROTOTYPE(config_parse_ifname);
 CONFIG_PARSER_PROTOTYPE(config_parse_ip_port);
 CONFIG_PARSER_PROTOTYPE(config_parse_join_controllers);
index edb55d9ffced155aa39f7930b420b3c638111b37..c9d2912e135158a11849d8dea383cb8ba22ff32c 100644 (file)
@@ -3890,6 +3890,7 @@ typedef struct UnitStatusInfo {
         /* Socket */
         unsigned n_accepted;
         unsigned n_connections;
+        unsigned n_refused;
         bool accept;
 
         /* Pairs of type, path */
@@ -4155,8 +4156,13 @@ static void print_status_info(
         STRV_FOREACH_PAIR(t, t2, i->listen)
                 printf(" %*s %s (%s)\n", 9, t == i->listen ? "Listen:" : "", *t2, *t);
 
-        if (i->accept)
-                printf(" Accepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
+        if (i->accept) {
+                printf(" Accepted: %u; Connected: %u;", i->n_accepted, i->n_connections);
+                if (i->n_refused)
+                        printf(" Refused: %u", i->n_refused);
+                printf("\n");
+        }
+
 
         LIST_FOREACH(exec, p, i->exec) {
                 _cleanup_free_ char *argv = NULL;
@@ -4956,6 +4962,7 @@ static int show_one(
                 { "NextElapseUSecMonotonic",        "t",              NULL,           offsetof(UnitStatusInfo, next_elapse_monotonic)             },
                 { "NAccepted",                      "u",              NULL,           offsetof(UnitStatusInfo, n_accepted)                        },
                 { "NConnections",                   "u",              NULL,           offsetof(UnitStatusInfo, n_connections)                     },
+                { "NRefused",                       "u",              NULL,           offsetof(UnitStatusInfo, n_refused)                         },
                 { "Accept",                         "b",              NULL,           offsetof(UnitStatusInfo, accept)                            },
                 { "Listen",                         "a(ss)",          map_listen,     offsetof(UnitStatusInfo, listen)                            },
                 { "SysFSPath",                      "s",              NULL,           offsetof(UnitStatusInfo, sysfs_path)                        },
index a04ab9c9aa494232896d6b65d206fa7c00787774..429eaa479dc01e2f2e4c54d5cf35365741d850b2 100644 (file)
@@ -648,6 +648,54 @@ static void test_parse_percent_unbounded(void) {
         assert_se(parse_percent_unbounded("400%") == 400);
 }
 
+static void test_parse_permille(void) {
+        assert_se(parse_permille("") == -EINVAL);
+        assert_se(parse_permille("foo") == -EINVAL);
+        assert_se(parse_permille("0") == -EINVAL);
+        assert_se(parse_permille("50") == -EINVAL);
+        assert_se(parse_permille("100") == -EINVAL);
+        assert_se(parse_permille("-1") == -EINVAL);
+
+        assert_se(parse_permille("0‰") == 0);
+        assert_se(parse_permille("555‰") == 555);
+        assert_se(parse_permille("1000‰") == 1000);
+        assert_se(parse_permille("-7‰") == -ERANGE);
+        assert_se(parse_permille("1007‰") == -ERANGE);
+        assert_se(parse_permille("‰") == -EINVAL);
+        assert_se(parse_permille("‰‰") == -EINVAL);
+        assert_se(parse_permille("‰1") == -EINVAL);
+        assert_se(parse_permille("1‰‰") == -EINVAL);
+        assert_se(parse_permille("3.2‰") == -EINVAL);
+
+        assert_se(parse_permille("0%") == 0);
+        assert_se(parse_permille("55%") == 550);
+        assert_se(parse_permille("55.5%") == 555);
+        assert_se(parse_permille("100%") == 1000);
+        assert_se(parse_permille("-7%") == -ERANGE);
+        assert_se(parse_permille("107%") == -ERANGE);
+        assert_se(parse_permille("%") == -EINVAL);
+        assert_se(parse_permille("%%") == -EINVAL);
+        assert_se(parse_permille("%1") == -EINVAL);
+        assert_se(parse_permille("1%%") == -EINVAL);
+        assert_se(parse_permille("3.21%") == -EINVAL);
+}
+
+static void test_parse_permille_unbounded(void) {
+        assert_se(parse_permille_unbounded("1001‰") == 1001);
+        assert_se(parse_permille_unbounded("4000‰") == 4000);
+        assert_se(parse_permille_unbounded("2147483647‰") == 2147483647);
+        assert_se(parse_permille_unbounded("2147483648‰") == -ERANGE);
+        assert_se(parse_permille_unbounded("4294967295‰") == -ERANGE);
+        assert_se(parse_permille_unbounded("4294967296‰") == -ERANGE);
+
+        assert_se(parse_permille_unbounded("101%") == 1010);
+        assert_se(parse_permille_unbounded("400%") == 4000);
+        assert_se(parse_permille_unbounded("214748364.7%") == 2147483647);
+        assert_se(parse_permille_unbounded("214748364.8%") == -ERANGE);
+        assert_se(parse_permille_unbounded("429496729.5%") == -ERANGE);
+        assert_se(parse_permille_unbounded("429496729.6%") == -ERANGE);
+}
+
 static void test_parse_nice(void) {
         int n;
 
@@ -797,6 +845,8 @@ int main(int argc, char *argv[]) {
         test_safe_atod();
         test_parse_percent();
         test_parse_percent_unbounded();
+        test_parse_permille();
+        test_parse_permille_unbounded();
         test_parse_nice();
         test_parse_dev();
         test_parse_errno();