From 74a27268699e7cf83f0dd4c9d1a24d0e46038be8 Mon Sep 17 00:00:00 2001 From: Richard Petri Date: Mon, 30 Mar 2020 23:05:56 +0200 Subject: [PATCH 1/2] network: can: introduce a config parser function for bitrates For now, this function is nearly equivalent to the si_uint64 parser, except for an additional range check as Linux only takes 32-bit values as bitrates. In future, this may also be used to introduce fancier bitrate config formats. --- man/systemd.network.xml | 2 +- src/network/networkd-can.c | 46 +++++++++++++++++++++--- src/network/networkd-can.h | 4 +++ src/network/networkd-network-gperf.gperf | 3 +- src/network/networkd-network.h | 2 +- 5 files changed, 49 insertions(+), 8 deletions(-) diff --git a/man/systemd.network.xml b/man/systemd.network.xml index bb6c35f9bab..be0756513ff 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -2350,7 +2350,7 @@ BitRate= The bitrate of CAN device in bits per second. The usual SI prefixes (K, M) with the base of 1000 can - be used here. + be used here. Takes a number in the range 1..4294967295. diff --git a/src/network/networkd-can.c b/src/network/networkd-can.c index 18533843e30..4118fcf859b 100644 --- a/src/network/networkd-can.c +++ b/src/network/networkd-can.c @@ -7,10 +7,51 @@ #include "networkd-can.h" #include "networkd-link.h" #include "networkd-manager.h" +#include "parse-util.h" #include "string-util.h" #define CAN_TERMINATION_OHM_VALUE 120 +int config_parse_can_bitrate( + 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) { + + uint32_t *br = data; + uint64_t sz; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + r = parse_size(rvalue, 1000, &sz); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, + "Failed to parse can bitrate '%s', ignoring: %m", rvalue); + return 0; + } + + /* Linux uses __u32 for bitrates, so the value should not exceed that. */ + if (sz <= 0 || sz > UINT32_MAX) { + log_syntax(unit, LOG_ERR, filename, line, 0, + "Bit rate out of permitted range 1...4294967295"); + return 0; + } + + *br = (uint32_t) sz; + + return 0; +} + static int link_up_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { int r; @@ -103,11 +144,6 @@ static int link_set_can(Link *link) { .sample_point = link->network->can_sample_point, }; - if (link->network->can_bitrate > UINT32_MAX) { - log_link_error(link, "bitrate (%" PRIu64 ") 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); diff --git a/src/network/networkd-can.h b/src/network/networkd-can.h index c744bdfea72..30e99b189d3 100644 --- a/src/network/networkd-can.h +++ b/src/network/networkd-can.h @@ -1,6 +1,10 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once +#include "conf-parser.h" + typedef struct Link Link; int link_configure_can(Link *link); + +CONFIG_PARSER_PROTOTYPE(config_parse_can_bitrate); diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 18ba23bfc8b..ee50da098d6 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -6,6 +6,7 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"") #include "conf-parser.h" #include "netem.h" #include "network-internal.h" +#include "networkd-can.h" #include "networkd-conf.h" #include "networkd-dhcp-common.h" #include "networkd-dhcp-server.h" @@ -257,7 +258,7 @@ IPv6Prefix.PreferredLifetimeSec, config_parse_prefix_lifetime, IPv6Prefix.Assign, config_parse_prefix_assign, 0, 0 IPv6RoutePrefix.Route, config_parse_route_prefix, 0, 0 IPv6RoutePrefix.LifetimeSec, config_parse_route_prefix_lifetime, 0, 0 -CAN.BitRate, config_parse_si_uint64, 0, offsetof(Network, can_bitrate) +CAN.BitRate, config_parse_can_bitrate, 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) CAN.TripleSampling, config_parse_tristate, 0, offsetof(Network, can_triple_sampling) diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 66ee01d7f3f..7acb4a5461d 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -205,7 +205,7 @@ struct Network { uint32_t br_untagged_bitmap[BRIDGE_VLAN_BITMAP_LEN]; /* CAN support */ - uint64_t can_bitrate; + uint32_t can_bitrate; unsigned can_sample_point; usec_t can_restart_us; int can_triple_sampling; From 7e025e9cdba1bce4e7e8259df0a9440f886c3be7 Mon Sep 17 00:00:00 2001 From: Richard Petri Date: Thu, 26 Mar 2020 22:27:41 +0100 Subject: [PATCH 2/2] network: can: add support for CAN-FD related properties --- man/systemd.network.xml | 23 +++++++++++++++ src/network/networkd-can.c | 29 +++++++++++++++++++ src/network/networkd-network-gperf.gperf | 4 +++ src/network/networkd-network.h | 4 +++ .../fuzz-network-parser/directives.network | 4 +++ 5 files changed, 64 insertions(+) diff --git a/man/systemd.network.xml b/man/systemd.network.xml index be0756513ff..9468a548f6c 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -2360,6 +2360,29 @@ 87.5%) or permille (e.g. 875‰). + + DataBitRate= + DataSamplePoint= + + The bitrate and sample point for the data phase, if CAN-FD is used. These settings are + analogous to the BitRate= and SamplePoint= keys. + + + + FDMode= + + Takes a boolean. When yes, CAN-FD mode is enabled for the interface. + Note, that a bitrate and optional sample point should also be set for the CAN-FD data phase using + the DataBitRate= and DataSamplePoint= keys. + + + + FDNonISO= + + Takes a boolean. When yes, non-ISO CAN-FD mode is enabled for the + interface. When unset, the kernel's default will be used. + + RestartSec= diff --git a/src/network/networkd-can.c b/src/network/networkd-can.c index 4118fcf859b..fdd99a3a189 100644 --- a/src/network/networkd-can.c +++ b/src/network/networkd-can.c @@ -155,6 +155,35 @@ static int link_set_can(Link *link) { return log_link_error_errno(link, r, "Could not append IFLA_CAN_BITTIMING attribute: %m"); } + if (link->network->can_data_bitrate > 0 || link->network->can_data_sample_point > 0) { + struct can_bittiming bt = { + .bitrate = link->network->can_data_bitrate, + .sample_point = link->network->can_data_sample_point, + }; + + log_link_debug(link, "Setting data bitrate = %d bit/s", bt.bitrate); + if (link->network->can_data_sample_point > 0) + log_link_debug(link, "Setting data sample point = %d.%d%%", bt.sample_point / 10, bt.sample_point % 10); + else + log_link_debug(link, "Using default data sample point"); + + r = sd_netlink_message_append_data(m, IFLA_CAN_DATA_BITTIMING, &bt, sizeof(bt)); + if (r < 0) + return log_link_error_errno(link, r, "Could not append IFLA_CAN_DATA_BITTIMING attribute: %m"); + } + + if (link->network->can_fd_mode >= 0) { + cm.mask |= CAN_CTRLMODE_FD; + SET_FLAG(cm.flags, CAN_CTRLMODE_FD, link->network->can_fd_mode > 0); + log_link_debug(link, "%sabling FD mode", link->network->can_fd_mode > 0 ? "En" : "Dis"); + } + + if (link->network->can_non_iso >= 0) { + cm.mask |= CAN_CTRLMODE_FD_NON_ISO; + SET_FLAG(cm.flags, CAN_CTRLMODE_FD_NON_ISO, link->network->can_non_iso > 0); + log_link_debug(link, "%sabling FD non-ISO mode", link->network->can_non_iso > 0 ? "En" : "Dis"); + } + if (link->network->can_restart_us > 0) { char time_string[FORMAT_TIMESPAN_MAX]; uint64_t restart_ms; diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index ee50da098d6..7833eec1cf5 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -260,6 +260,10 @@ IPv6RoutePrefix.Route, config_parse_route_prefix, IPv6RoutePrefix.LifetimeSec, config_parse_route_prefix_lifetime, 0, 0 CAN.BitRate, config_parse_can_bitrate, 0, offsetof(Network, can_bitrate) CAN.SamplePoint, config_parse_permille, 0, offsetof(Network, can_sample_point) +CAN.DataBitRate, config_parse_can_bitrate, 0, offsetof(Network, can_data_bitrate) +CAN.DataSamplePoint, config_parse_permille, 0, offsetof(Network, can_data_sample_point) +CAN.FDMode, config_parse_tristate, 0, offsetof(Network, can_fd_mode) +CAN.FDNonISO, config_parse_tristate, 0, offsetof(Network, can_non_iso) CAN.RestartSec, config_parse_sec, 0, offsetof(Network, can_restart_us) CAN.TripleSampling, config_parse_tristate, 0, offsetof(Network, can_triple_sampling) CAN.Termination, config_parse_tristate, 0, offsetof(Network, can_termination) diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 7acb4a5461d..8bd380c6a8e 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -207,10 +207,14 @@ struct Network { /* CAN support */ uint32_t can_bitrate; unsigned can_sample_point; + uint32_t can_data_bitrate; + unsigned can_data_sample_point; usec_t can_restart_us; int can_triple_sampling; int can_termination; int can_listen_only; + int can_fd_mode; + int can_non_iso; AddressFamily ip_forward; bool ip_masquerade; diff --git a/test/fuzz/fuzz-network-parser/directives.network b/test/fuzz/fuzz-network-parser/directives.network index 01b1b50ff6a..fe70429ffe6 100644 --- a/test/fuzz/fuzz-network-parser/directives.network +++ b/test/fuzz/fuzz-network-parser/directives.network @@ -201,6 +201,10 @@ PVID= [CAN] SamplePoint= BitRate= +DataSamplePoint= +DataBitRate= +FDMode= +FDNonISO= RestartSec= TripleSampling= Termination=