From 1c4d83f9061e38d08c8fcb4c43b5ba3a96d8cd0a Mon Sep 17 00:00:00 2001 From: Anita Zhang Date: Sep 21 2021 21:11:19 +0000 Subject: 249.4-1.1: stable point release; backport some new features - Backport optimization for read_virtual_file() (#20743) - Backport new features for systemd-networkd (#20743, #20472, #20477, #20484) --- diff --git a/.systemd.metadata b/.systemd.metadata index f971042..052ad4c 100644 --- a/.systemd.metadata +++ b/.systemd.metadata @@ -1 +1 @@ -9fdcf03e0c88b3aa98c95626a588311084ef9047 SOURCES/systemd-249.2.tar.gz +5e3b9df64a15cb3b446c0e74556ea9020ce50b8b SOURCES/systemd-249.4.tar.gz diff --git a/SOURCES/20458.patch b/SOURCES/20458.patch new file mode 100644 index 0000000..ad916b4 --- /dev/null +++ b/SOURCES/20458.patch @@ -0,0 +1,143 @@ +From e9f92c88163841d3f1d29fa5b44ae4c6f71bb014 Mon Sep 17 00:00:00 2001 +From: Daan De Meyer +Date: Wed, 18 Aug 2021 07:59:13 +0100 +Subject: [PATCH] udev: Support "max" string for BufferSize options (#20458) + +"max" indicates the hardware advertised maximum queue buffer size +should be used. + +The max sizes can be checked by running `ethtool -g ` (Preset maximums). +Since the buffer sizes can't be set to 0 by users, internally we use 0 to +indicate that the hardware advertised maximum should be used. +--- + man/systemd.link.xml | 20 ++++++++++++-------- + src/shared/ethtool-util.c | 40 +++++++++++++++++++++++++-------------- + src/shared/ethtool-util.h | 2 ++ + 3 files changed, 40 insertions(+), 22 deletions(-) + +diff --git a/man/systemd.link.xml b/man/systemd.link.xml +index 1c18f35fc8..fd744ebaed 100644 +--- a/man/systemd.link.xml ++++ b/man/systemd.link.xml +@@ -735,29 +735,33 @@ + + RxBufferSize= + +- Takes an integer. Specifies the maximum number of pending packets in the NIC receive buffer. +- When unset, the kernel's default will be used. ++ Takes an integer or max. Specifies the maximum number of pending packets ++ in the NIC receive buffer. When unset, the kernel's default will be used. If set to ++ max, the hardware's advertised maximum size will be used. + + + + RxMiniBufferSize= + +- Takes an integer. Specifies the maximum number of pending packets in the NIC mini receive buffer. +- When unset, the kernel's default will be used. ++ Takes an integer or max. Specifies the maximum number of pending packets ++ in the NIC mini receive buffer. When unset, the kernel's default will be used. If set to ++ max, the hardware's advertised maximum size will be used. + + + + RxJumboBufferSize= + +- Takes an integer. Specifies the maximum number of pending packets in the NIC jumbo receive buffer. +- When unset, the kernel's default will be used. ++ Takes an integer or max. Specifies the maximum number of pending packets ++ in the NIC jumbo receive buffer. When unset, the kernel's default will be used. If set to ++ max, the hardware's advertised maximum size will be used. + + + + TxBufferSize= + +- Takes an integer. Specifies the maximum number of pending packets in the NIC transmit buffer. +- When unset, the kernel's default will be used. ++ Takes an integer or max. Specifies the maximum number of pending packets ++ in the NIC transmit buffer. When unset, the kernel's default will be used. If set to ++ max, the hardware's advertised maximum size will be used. + + + +diff --git a/src/shared/ethtool-util.c b/src/shared/ethtool-util.c +index f77f6943ca..ed251ec8dd 100644 +--- a/src/shared/ethtool-util.c ++++ b/src/shared/ethtool-util.c +@@ -399,16 +399,24 @@ int ethtool_set_nic_buffer_size(int *ethtool_fd, const char *ifname, const netde + return -errno; + + if (ring->rx_pending_set) +- UPDATE(ecmd.rx_pending, ring->rx_pending, need_update); ++ UPDATE(ecmd.rx_pending, ++ ring->rx_pending == 0 ? ecmd.rx_max_pending : ring->rx_pending, ++ need_update); + + if (ring->rx_mini_pending_set) +- UPDATE(ecmd.rx_mini_pending, ring->rx_mini_pending, need_update); ++ UPDATE(ecmd.rx_mini_pending, ++ ring->rx_mini_pending == 0 ? ecmd.rx_mini_max_pending : ring->rx_mini_pending, ++ need_update); + + if (ring->rx_jumbo_pending_set) +- UPDATE(ecmd.rx_jumbo_pending, ring->rx_jumbo_pending, need_update); ++ UPDATE(ecmd.rx_jumbo_pending, ++ ring->rx_jumbo_pending == 0 ? ecmd.rx_jumbo_max_pending : ring->rx_jumbo_pending, ++ need_update); + + if (ring->tx_pending_set) +- UPDATE(ecmd.tx_pending, ring->tx_pending, need_update); ++ UPDATE(ecmd.tx_pending, ++ ring->tx_pending == 0 ? ecmd.tx_max_pending : ring->tx_pending, ++ need_update); + + if (!need_update) + return 0; +@@ -1037,16 +1045,20 @@ int config_parse_nic_buffer_size( + assert(rvalue); + assert(data); + +- r = safe_atou32(rvalue, &k); +- if (r < 0) { +- log_syntax(unit, LOG_WARNING, filename, line, r, +- "Failed to parse interface buffer value, ignoring: %s", rvalue); +- return 0; +- } +- if (k < 1) { +- log_syntax(unit, LOG_WARNING, filename, line, 0, +- "Invalid %s= value, ignoring: %s", lvalue, rvalue); +- return 0; ++ if (streq(rvalue, "max")) ++ k = 0; ++ else { ++ r = safe_atou32(rvalue, &k); ++ if (r < 0) { ++ log_syntax(unit, LOG_WARNING, filename, line, r, ++ "Failed to parse interface buffer value, ignoring: %s", rvalue); ++ return 0; ++ } ++ if (k < 1) { ++ log_syntax(unit, LOG_WARNING, filename, line, 0, ++ "Invalid %s= value, ignoring: %s", lvalue, rvalue); ++ return 0; ++ } + } + + if (streq(lvalue, "RxBufferSize")) { +diff --git a/src/shared/ethtool-util.h b/src/shared/ethtool-util.h +index 7d28766624..aea131914e 100644 +--- a/src/shared/ethtool-util.h ++++ b/src/shared/ethtool-util.h +@@ -70,6 +70,8 @@ typedef struct netdev_channels { + } netdev_channels; + + typedef struct netdev_ring_param { ++ /* For any of the 4 following settings, a value of 0 indicates the hardware advertised maximum should ++ * be used. */ + uint32_t rx_pending; + uint32_t rx_mini_pending; + uint32_t rx_jumbo_pending; +-- +2.31.1 + diff --git a/SOURCES/20472.patch b/SOURCES/20472.patch new file mode 100644 index 0000000..e5eb57b --- /dev/null +++ b/SOURCES/20472.patch @@ -0,0 +1,425 @@ +From 78e57b79c8790448412acca41e5d4495366305a6 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Wed, 18 Aug 2021 16:41:11 +0900 +Subject: [PATCH] udev: make RxChannels= or friends also accept "max" + +Follow-up for 406041b7de767316674eb6a2f98ad466577ce8a4. + +Also, this makes +- the settings accept an empty string, +- if the specified value is too large, also use the advertised maximum + value. +- mention the range of the value in the man page. +--- + man/systemd.link.xml | 49 ++------ + src/shared/ethtool-util.c | 170 ++++++++++----------------- + src/shared/ethtool-util.h | 36 +++--- + src/udev/net/link-config-gperf.gperf | 16 +-- + 4 files changed, 90 insertions(+), 181 deletions(-) + +diff --git a/man/systemd.link.xml b/man/systemd.link.xml +index fd744ebaed..dfb02073b2 100644 +--- a/man/systemd.link.xml ++++ b/man/systemd.link.xml +@@ -710,58 +710,27 @@ + + + RxChannels= +- +- Sets the number of receive channels (a number between 1 and 4294967295) . +- +- +- + TxChannels= +- +- Sets the number of transmit channels (a number between 1 and 4294967295). +- +- +- + OtherChannels= +- +- Sets the number of other channels (a number between 1 and 4294967295). +- +- +- + CombinedChannels= + +- Sets the number of combined set channels (a number between 1 and 4294967295). ++ Specifies the number of receive, transmit, other, or combined channels, respectively. ++ Takes an unsigned integer in the range 1…4294967295 or max. If set to ++ max, the advertised maximum value of the hardware will be used. When ++ unset, the number will not be changed. Defaults to unset. + + + + RxBufferSize= +- +- Takes an integer or max. Specifies the maximum number of pending packets +- in the NIC receive buffer. When unset, the kernel's default will be used. If set to +- max, the hardware's advertised maximum size will be used. +- +- +- + RxMiniBufferSize= +- +- Takes an integer or max. Specifies the maximum number of pending packets +- in the NIC mini receive buffer. When unset, the kernel's default will be used. If set to +- max, the hardware's advertised maximum size will be used. +- +- +- + RxJumboBufferSize= +- +- Takes an integer or max. Specifies the maximum number of pending packets +- in the NIC jumbo receive buffer. When unset, the kernel's default will be used. If set to +- max, the hardware's advertised maximum size will be used. +- +- +- + TxBufferSize= + +- Takes an integer or max. Specifies the maximum number of pending packets +- in the NIC transmit buffer. When unset, the kernel's default will be used. If set to +- max, the hardware's advertised maximum size will be used. ++ Specifies the maximum number of pending packets in the NIC receive buffer, mini receive ++ buffer, jumbo receive buffer, or transmit buffer, respectively. Takes an unsigned integer in ++ the range 1…4294967295 or max. If set to max, the ++ advertised maximum value of the hardware will be used. When unset, the number will not be ++ changed. Defaults to unset. + + + +diff --git a/src/shared/ethtool-util.c b/src/shared/ethtool-util.c +index ed251ec8dd..2d41d861ba 100644 +--- a/src/shared/ethtool-util.c ++++ b/src/shared/ethtool-util.c +@@ -329,6 +329,17 @@ int ethtool_get_permanent_macaddr(int *ethtool_fd, const char *ifname, struct et + dest = _v; \ + } while(false) + ++#define UPDATE_WITH_MAX(dest, max, val, updated) \ ++ do { \ ++ typeof(dest) _v = (val); \ ++ typeof(dest) _max = (max); \ ++ if (_v == 0 || _v > _max) \ ++ _v = _max; \ ++ if (dest != _v) \ ++ updated = true; \ ++ dest = _v; \ ++ } while(false) ++ + int ethtool_set_wol(int *ethtool_fd, const char *ifname, uint32_t wolopts) { + struct ethtool_wolinfo ecmd = { + .cmd = ETHTOOL_GWOL, +@@ -382,10 +393,10 @@ int ethtool_set_nic_buffer_size(int *ethtool_fd, const char *ifname, const netde + assert(ifname); + assert(ring); + +- if (!ring->rx_pending_set && +- !ring->rx_mini_pending_set && +- !ring->rx_jumbo_pending_set && +- !ring->tx_pending_set) ++ if (!ring->rx.set && ++ !ring->rx_mini.set && ++ !ring->rx_jumbo.set && ++ !ring->tx.set) + return 0; + + r = ethtool_connect(ethtool_fd); +@@ -398,25 +409,17 @@ int ethtool_set_nic_buffer_size(int *ethtool_fd, const char *ifname, const netde + if (r < 0) + return -errno; + +- if (ring->rx_pending_set) +- UPDATE(ecmd.rx_pending, +- ring->rx_pending == 0 ? ecmd.rx_max_pending : ring->rx_pending, +- need_update); ++ if (ring->rx.set) ++ UPDATE_WITH_MAX(ecmd.rx_pending, ecmd.rx_max_pending, ring->rx.value, need_update); + +- if (ring->rx_mini_pending_set) +- UPDATE(ecmd.rx_mini_pending, +- ring->rx_mini_pending == 0 ? ecmd.rx_mini_max_pending : ring->rx_mini_pending, +- need_update); ++ if (ring->rx_mini.set) ++ UPDATE_WITH_MAX(ecmd.rx_mini_pending, ecmd.rx_mini_max_pending, ring->rx_mini.value, need_update); + +- if (ring->rx_jumbo_pending_set) +- UPDATE(ecmd.rx_jumbo_pending, +- ring->rx_jumbo_pending == 0 ? ecmd.rx_jumbo_max_pending : ring->rx_jumbo_pending, +- need_update); ++ if (ring->rx_jumbo.set) ++ UPDATE_WITH_MAX(ecmd.rx_jumbo_pending, ecmd.rx_jumbo_max_pending, ring->rx_jumbo.value, need_update); + +- if (ring->tx_pending_set) +- UPDATE(ecmd.tx_pending, +- ring->tx_pending == 0 ? ecmd.tx_max_pending : ring->tx_pending, +- need_update); ++ if (ring->tx.set) ++ UPDATE_WITH_MAX(ecmd.tx_pending, ecmd.tx_max_pending, ring->tx.value, need_update); + + if (!need_update) + return 0; +@@ -832,10 +835,10 @@ int ethtool_set_channels(int *fd, const char *ifname, const netdev_channels *cha + assert(ifname); + assert(channels); + +- if (!channels->rx_count_set && +- !channels->tx_count_set && +- !channels->other_count_set && +- !channels->combined_count_set) ++ if (!channels->rx.set && ++ !channels->tx.set && ++ !channels->other.set && ++ !channels->combined.set) + return 0; + + r = ethtool_connect(fd); +@@ -848,17 +851,17 @@ int ethtool_set_channels(int *fd, const char *ifname, const netdev_channels *cha + if (r < 0) + return -errno; + +- if (channels->rx_count_set) +- UPDATE(ecmd.rx_count, channels->rx_count, need_update); ++ if (channels->rx.set) ++ UPDATE_WITH_MAX(ecmd.rx_count, ecmd.max_rx, channels->rx.value, need_update); + +- if (channels->tx_count_set) +- UPDATE(ecmd.tx_count, channels->tx_count, need_update); ++ if (channels->tx.set) ++ UPDATE_WITH_MAX(ecmd.tx_count, ecmd.max_tx, channels->tx.value, need_update); + +- if (channels->other_count_set) +- UPDATE(ecmd.other_count, channels->other_count, need_update); ++ if (channels->other.set) ++ UPDATE_WITH_MAX(ecmd.other_count, ecmd.max_other, channels->other.value, need_update); + +- if (channels->combined_count_set) +- UPDATE(ecmd.combined_count, channels->combined_count, need_update); ++ if (channels->combined.set) ++ UPDATE_WITH_MAX(ecmd.combined_count, ecmd.max_combined, channels->combined.value, need_update); + + if (!need_update) + return 0; +@@ -917,57 +920,6 @@ int ethtool_set_flow_control(int *fd, const char *ifname, int rx, int tx, int au + return 0; + } + +-int config_parse_channel( +- 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) { +- +- netdev_channels *channels = data; +- uint32_t k; +- int r; +- +- assert(filename); +- assert(section); +- assert(lvalue); +- assert(rvalue); +- assert(data); +- +- r = safe_atou32(rvalue, &k); +- if (r < 0) { +- log_syntax(unit, LOG_WARNING, filename, line, r, +- "Failed to parse channel value for %s=, ignoring: %s", lvalue, rvalue); +- return 0; +- } +- if (k < 1) { +- log_syntax(unit, LOG_WARNING, filename, line, 0, +- "Invalid %s= value, ignoring: %s", lvalue, rvalue); +- return 0; +- } +- +- if (streq(lvalue, "RxChannels")) { +- channels->rx_count = k; +- channels->rx_count_set = true; +- } else if (streq(lvalue, "TxChannels")) { +- channels->tx_count = k; +- channels->tx_count_set = true; +- } else if (streq(lvalue, "OtherChannels")) { +- channels->other_count = k; +- channels->other_count_set = true; +- } else if (streq(lvalue, "CombinedChannels")) { +- channels->combined_count = k; +- channels->combined_count_set = true; +- } +- +- return 0; +-} +- + int config_parse_advertise( + const char *unit, + const char *filename, +@@ -1023,7 +975,7 @@ int config_parse_advertise( + } + } + +-int config_parse_nic_buffer_size( ++int config_parse_ring_buffer_or_channel( + const char *unit, + const char *filename, + unsigned line, +@@ -1035,7 +987,7 @@ int config_parse_nic_buffer_size( + void *data, + void *userdata) { + +- netdev_ring_param *ring = data; ++ u32_opt *dst = data; + uint32_t k; + int r; + +@@ -1045,36 +997,32 @@ int config_parse_nic_buffer_size( + assert(rvalue); + assert(data); + +- if (streq(rvalue, "max")) +- k = 0; +- else { +- r = safe_atou32(rvalue, &k); +- if (r < 0) { +- log_syntax(unit, LOG_WARNING, filename, line, r, +- "Failed to parse interface buffer value, ignoring: %s", rvalue); +- return 0; +- } +- if (k < 1) { +- log_syntax(unit, LOG_WARNING, filename, line, 0, +- "Invalid %s= value, ignoring: %s", lvalue, rvalue); +- return 0; +- } ++ if (isempty(rvalue)) { ++ dst->value = 0; ++ dst->set = false; ++ return 0; ++ } ++ ++ if (streq(rvalue, "max")) { ++ dst->value = 0; ++ dst->set = true; ++ return 0; + } + +- if (streq(lvalue, "RxBufferSize")) { +- ring->rx_pending = k; +- ring->rx_pending_set = true; +- } else if (streq(lvalue, "RxMiniBufferSize")) { +- ring->rx_mini_pending = k; +- ring->rx_mini_pending_set = true; +- } else if (streq(lvalue, "RxJumboBufferSize")) { +- ring->rx_jumbo_pending = k; +- ring->rx_jumbo_pending_set = true; +- } else if (streq(lvalue, "TxBufferSize")) { +- ring->tx_pending = k; +- ring->tx_pending_set = true; ++ r = safe_atou32(rvalue, &k); ++ if (r < 0) { ++ log_syntax(unit, LOG_WARNING, filename, line, r, ++ "Failed to parse %s=, ignoring: %s", lvalue, rvalue); ++ return 0; ++ } ++ if (k < 1) { ++ log_syntax(unit, LOG_WARNING, filename, line, 0, ++ "Invalid %s= value, ignoring: %s", lvalue, rvalue); ++ return 0; + } + ++ dst->value = k; ++ dst->set = true; + return 0; + } + +diff --git a/src/shared/ethtool-util.h b/src/shared/ethtool-util.h +index aea131914e..8fdbdec39a 100644 +--- a/src/shared/ethtool-util.h ++++ b/src/shared/ethtool-util.h +@@ -57,30 +57,23 @@ struct ethtool_link_usettings { + } link_modes; + }; + ++typedef struct u32_opt { ++ uint32_t value; /* a value of 0 indicates the hardware advertised maximum should be used.*/ ++ bool set; ++} u32_opt; ++ + typedef struct netdev_channels { +- uint32_t rx_count; +- uint32_t tx_count; +- uint32_t other_count; +- uint32_t combined_count; +- +- bool rx_count_set; +- bool tx_count_set; +- bool other_count_set; +- bool combined_count_set; ++ u32_opt rx; ++ u32_opt tx; ++ u32_opt other; ++ u32_opt combined; + } netdev_channels; + + typedef struct netdev_ring_param { +- /* For any of the 4 following settings, a value of 0 indicates the hardware advertised maximum should +- * be used. */ +- uint32_t rx_pending; +- uint32_t rx_mini_pending; +- uint32_t rx_jumbo_pending; +- uint32_t tx_pending; +- +- bool rx_pending_set; +- bool rx_mini_pending_set; +- bool rx_jumbo_pending_set; +- bool tx_pending_set; ++ u32_opt rx; ++ u32_opt rx_mini; ++ u32_opt rx_jumbo; ++ u32_opt tx; + } netdev_ring_param; + + int ethtool_get_driver(int *ethtool_fd, const char *ifname, char **ret); +@@ -111,6 +104,5 @@ enum ethtool_link_mode_bit_indices ethtool_link_mode_bit_from_string(const char + CONFIG_PARSER_PROTOTYPE(config_parse_duplex); + CONFIG_PARSER_PROTOTYPE(config_parse_wol); + CONFIG_PARSER_PROTOTYPE(config_parse_port); +-CONFIG_PARSER_PROTOTYPE(config_parse_channel); + CONFIG_PARSER_PROTOTYPE(config_parse_advertise); +-CONFIG_PARSER_PROTOTYPE(config_parse_nic_buffer_size); ++CONFIG_PARSER_PROTOTYPE(config_parse_ring_buffer_or_channel); +diff --git a/src/udev/net/link-config-gperf.gperf b/src/udev/net/link-config-gperf.gperf +index e2f07d758b..d0190da5cb 100644 +--- a/src/udev/net/link-config-gperf.gperf ++++ b/src/udev/net/link-config-gperf.gperf +@@ -58,15 +58,15 @@ Link.TCP6SegmentationOffload, config_parse_tristate, 0, + Link.UDPSegmentationOffload, config_parse_warn_compat, DISABLED_LEGACY, 0 + Link.GenericReceiveOffload, config_parse_tristate, 0, offsetof(LinkConfig, features[NET_DEV_FEAT_GRO]) + Link.LargeReceiveOffload, config_parse_tristate, 0, offsetof(LinkConfig, features[NET_DEV_FEAT_LRO]) +-Link.RxChannels, config_parse_channel, 0, offsetof(LinkConfig, channels) +-Link.TxChannels, config_parse_channel, 0, offsetof(LinkConfig, channels) +-Link.OtherChannels, config_parse_channel, 0, offsetof(LinkConfig, channels) +-Link.CombinedChannels, config_parse_channel, 0, offsetof(LinkConfig, channels) ++Link.RxChannels, config_parse_ring_buffer_or_channel, 0, offsetof(LinkConfig, channels.rx) ++Link.TxChannels, config_parse_ring_buffer_or_channel, 0, offsetof(LinkConfig, channels.tx) ++Link.OtherChannels, config_parse_ring_buffer_or_channel, 0, offsetof(LinkConfig, channels.other) ++Link.CombinedChannels, config_parse_ring_buffer_or_channel, 0, offsetof(LinkConfig, channels.combined) + Link.Advertise, config_parse_advertise, 0, offsetof(LinkConfig, advertise) +-Link.RxBufferSize, config_parse_nic_buffer_size, 0, offsetof(LinkConfig, ring) +-Link.RxMiniBufferSize, config_parse_nic_buffer_size, 0, offsetof(LinkConfig, ring) +-Link.RxJumboBufferSize, config_parse_nic_buffer_size, 0, offsetof(LinkConfig, ring) +-Link.TxBufferSize, config_parse_nic_buffer_size, 0, offsetof(LinkConfig, ring) ++Link.RxBufferSize, config_parse_ring_buffer_or_channel, 0, offsetof(LinkConfig, ring.rx) ++Link.RxMiniBufferSize, config_parse_ring_buffer_or_channel, 0, offsetof(LinkConfig, ring.rx_mini) ++Link.RxJumboBufferSize, config_parse_ring_buffer_or_channel, 0, offsetof(LinkConfig, ring.rx_jumbo) ++Link.TxBufferSize, config_parse_ring_buffer_or_channel, 0, offsetof(LinkConfig, ring.tx) + Link.RxFlowControl, config_parse_tristate, 0, offsetof(LinkConfig, rx_flow_control) + Link.TxFlowControl, config_parse_tristate, 0, offsetof(LinkConfig, tx_flow_control) + Link.AutoNegotiationFlowControl, config_parse_tristate, 0, offsetof(LinkConfig, autoneg_flow_control) +-- +2.31.1 + diff --git a/SOURCES/20477.patch b/SOURCES/20477.patch new file mode 100644 index 0000000..6676bff --- /dev/null +++ b/SOURCES/20477.patch @@ -0,0 +1,561 @@ +From a1661a140c97a9e8fd90ee00f2de6baa214c9076 Mon Sep 17 00:00:00 2001 +From: Daan De Meyer +Date: Wed, 18 Aug 2021 13:52:00 +0100 +Subject: [PATCH] udev: Add support for configuring nic coalescing settings + +These are configured via the corresponding ethtool ioctl. +--- + man/systemd.link.xml | 71 +++++++ + src/shared/ethtool-util.c | 205 +++++++++++++++++++++ + src/shared/ethtool-util.h | 29 +++ + src/udev/net/link-config-gperf.gperf | 124 ++++++++----- + src/udev/net/link-config.c | 4 + + src/udev/net/link-config.h | 1 + + test/fuzz/fuzz-link-parser/directives.link | 22 +++ + 7 files changed, 405 insertions(+), 51 deletions(-) + +diff --git a/man/systemd.link.xml b/man/systemd.link.xml +index dfb02073b2..6d8dcb9af7 100644 +--- a/man/systemd.link.xml ++++ b/man/systemd.link.xml +@@ -773,6 +773,77 @@ + accept. An unsigned integer in the range 1…65535. Defaults to unset. + + ++ ++ UseAdaptiveRxCoalesce= ++ UseAdaptiveTxCoalesce= ++ ++ Boolean properties that, when set, enable/disable adaptive Rx/Tx coalescing if the hardware ++ supports it. When unset, the kernel's default will be used. ++ ++ ++ ++ RxCoalesceSec= ++ RxCoalesceIrqSec= ++ RxCoalesceLowSec= ++ RxCoalesceHighSec= ++ TxCoalesceSec= ++ TxCoalesceIrqSec= ++ TxCoalesceLowSec= ++ TxCoalesceHighSec= ++ ++ These properties configure the delay before Rx/Tx interrupts are generated after a packet is ++ sent/received. The Irq properties come into effect when the host is servicing an ++ IRQ. The Low and High properties come into effect when the ++ packet rate drops below the low packet rate threshold or exceeds the high packet rate threshold ++ respectively if adaptive Rx/Tx coalescing is enabled. When unset, the kernel's defaults will be ++ used. ++ ++ ++ ++ RxMaxCoalescedFrames= ++ RxMaxCoalescedIrqFrames= ++ RxMaxCoalescedLowFrames= ++ RxMaxCoalescedHighFrames= ++ TxMaxCoalescedFrames= ++ TxMaxCoalescedIrqFrames= ++ TxMaxCoalescedLowFrames= ++ TxMaxCoalescedHighFrames= ++ ++ These properties configure the maximum number of frames that are sent/received before a Rx/Tx ++ interrupt is generated. The Irq properties come into effect when the host is ++ servicing an IRQ. The Low and High properties come into ++ effect when the packet rate drops below the low packet rate threshold or exceeds the high packet ++ rate threshold respectively if adaptive Rx/Tx coalescing is enabled. When unset, the kernel's ++ defaults will be used. ++ ++ ++ ++ CoalescePacketRateLow= ++ CoalescePacketRateHigh= ++ ++ These properties configure the low and high packet rate (expressed in packets per second) ++ threshold respectively and are used to determine when the corresponding coalescing settings for low ++ and high packet rates come into effect if adaptive Rx/Tx coalescing is enabled. If unset, the ++ kernel's defaults will be used. ++ ++ ++ ++ CoalescePacketRateSampleIntervalSec= ++ ++ Configures how often to sample the packet rate used for adaptive Rx/Tx coalescing. This ++ property cannot be zero. This lowest time granularity supported by this property is seconds. ++ Partial seconds will be rounded up before being passed to the kernel. If unset, the kernel's ++ default will be used. ++ ++ ++ ++ StatisticsBlockCoalesceSec= ++ ++ How long to delay driver in-memory statistics block updates. If the driver does not have an ++ in-memory statistic block, this property is ignored. This property cannot be zero. If unset, the ++ kernel's default will be used. ++ ++ + + + +diff --git a/src/shared/ethtool-util.c b/src/shared/ethtool-util.c +index 2d41d861ba..f7f553dd29 100644 +--- a/src/shared/ethtool-util.c ++++ b/src/shared/ethtool-util.c +@@ -14,6 +14,7 @@ + #include "memory-util.h" + #include "socket-util.h" + #include "string-table.h" ++#include "strv.h" + #include "strxcpyx.h" + + static const char* const duplex_table[_DUP_MAX] = { +@@ -1091,3 +1092,207 @@ int config_parse_wol( + + return 0; + } ++ ++int config_parse_coalesce_u32( ++ 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) { ++ u32_opt *dst = data; ++ uint32_t k; ++ int r; ++ ++ if (isempty(rvalue)) { ++ dst->value = 0; ++ dst->set = false; ++ return 0; ++ } ++ ++ r = safe_atou32(rvalue, &k); ++ if (r < 0) { ++ log_syntax(unit, LOG_WARNING, filename, line, r, ++ "Failed to parse %s=, ignoring: %s", lvalue, rvalue); ++ return 0; ++ } ++ ++ dst->value = k; ++ dst->set = true; ++ return 0; ++} ++ ++int config_parse_coalesce_sec( ++ 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) { ++ u32_opt *dst = data; ++ usec_t usec; ++ int r; ++ ++ if (isempty(rvalue)) { ++ dst->value = 0; ++ dst->set = false; ++ return 0; ++ } ++ ++ r = parse_sec(rvalue, &usec); ++ if (r < 0) { ++ log_syntax(unit, LOG_WARNING, filename, line, r, ++ "Failed to parse coalesce setting value, ignoring: %s", rvalue); ++ return 0; ++ } ++ ++ if (usec > UINT32_MAX) { ++ log_syntax(unit, LOG_WARNING, filename, line, 0, ++ "Too large %s= value, ignoring: %s", lvalue, rvalue); ++ return 0; ++ } ++ ++ if (STR_IN_SET(lvalue, "StatisticsBlockCoalesceSec", "CoalescePacketRateSampleIntervalSec") && usec < 1) { ++ log_syntax(unit, LOG_WARNING, filename, line, 0, ++ "Invalid %s= value, ignoring: %s", lvalue, rvalue); ++ return 0; ++ } ++ ++ dst->value = (uint32_t) usec; ++ dst->set = true; ++ ++ return 0; ++} ++ ++int ethtool_set_nic_coalesce_settings(int *ethtool_fd, const char *ifname, const netdev_coalesce_param *coalesce) { ++ struct ethtool_coalesce ecmd = { ++ .cmd = ETHTOOL_GCOALESCE, ++ }; ++ struct ifreq ifr = { ++ .ifr_data = (void*) &ecmd, ++ }; ++ bool need_update = false; ++ int r; ++ ++ assert(ethtool_fd); ++ assert(ifname); ++ assert(coalesce); ++ ++ if (coalesce->use_adaptive_rx_coalesce < 0 && ++ coalesce->use_adaptive_tx_coalesce < 0 && ++ !coalesce->rx_coalesce_usecs.set && ++ !coalesce->rx_max_coalesced_frames.set && ++ !coalesce->rx_coalesce_usecs_irq.set && ++ !coalesce->rx_max_coalesced_frames_irq.set && ++ !coalesce->tx_coalesce_usecs.set && ++ !coalesce->tx_max_coalesced_frames.set && ++ !coalesce->tx_coalesce_usecs_irq.set && ++ !coalesce->tx_max_coalesced_frames_irq.set && ++ !coalesce->stats_block_coalesce_usecs.set && ++ !coalesce->pkt_rate_low.set && ++ !coalesce->rx_coalesce_usecs_low.set && ++ !coalesce->rx_max_coalesced_frames_low.set && ++ !coalesce->tx_coalesce_usecs_low.set && ++ !coalesce->tx_max_coalesced_frames_low.set && ++ !coalesce->pkt_rate_high.set && ++ !coalesce->rx_coalesce_usecs_high.set && ++ !coalesce->rx_max_coalesced_frames_high.set && ++ !coalesce->tx_coalesce_usecs_high.set && ++ !coalesce->tx_max_coalesced_frames_high.set && ++ !coalesce->rate_sample_interval.set) ++ return 0; ++ ++ r = ethtool_connect(ethtool_fd); ++ if (r < 0) ++ return r; ++ ++ strscpy(ifr.ifr_name, IFNAMSIZ, ifname); ++ ++ r = ioctl(*ethtool_fd, SIOCETHTOOL, &ifr); ++ if (r < 0) ++ return -errno; ++ ++ if (coalesce->use_adaptive_rx_coalesce >= 0) ++ UPDATE(ecmd.use_adaptive_rx_coalesce, (uint32_t) coalesce->use_adaptive_rx_coalesce, need_update); ++ ++ if (coalesce->use_adaptive_tx_coalesce >= 0) ++ UPDATE(ecmd.use_adaptive_tx_coalesce, (uint32_t) coalesce->use_adaptive_tx_coalesce, need_update); ++ ++ if (coalesce->rx_coalesce_usecs.set) ++ UPDATE(ecmd.rx_coalesce_usecs, coalesce->rx_coalesce_usecs.value, need_update); ++ ++ if (coalesce->rx_max_coalesced_frames.set) ++ UPDATE(ecmd.rx_max_coalesced_frames, coalesce->rx_max_coalesced_frames.value, need_update); ++ ++ if (coalesce->rx_coalesce_usecs_irq.set) ++ UPDATE(ecmd.rx_coalesce_usecs_irq, coalesce->rx_coalesce_usecs_irq.value, need_update); ++ ++ if (coalesce->rx_max_coalesced_frames_irq.set) ++ UPDATE(ecmd.rx_max_coalesced_frames_irq, coalesce->rx_max_coalesced_frames_irq.value, need_update); ++ ++ if (coalesce->tx_coalesce_usecs.set) ++ UPDATE(ecmd.tx_coalesce_usecs, coalesce->tx_coalesce_usecs.value, need_update); ++ ++ if (coalesce->tx_max_coalesced_frames.set) ++ UPDATE(ecmd.tx_max_coalesced_frames, coalesce->tx_max_coalesced_frames.value, need_update); ++ ++ if (coalesce->tx_coalesce_usecs_irq.set) ++ UPDATE(ecmd.tx_coalesce_usecs_irq, coalesce->tx_coalesce_usecs_irq.value, need_update); ++ ++ if (coalesce->tx_max_coalesced_frames_irq.set) ++ UPDATE(ecmd.tx_max_coalesced_frames_irq, coalesce->tx_max_coalesced_frames_irq.value, need_update); ++ ++ if (coalesce->stats_block_coalesce_usecs.set) ++ UPDATE(ecmd.stats_block_coalesce_usecs, coalesce->stats_block_coalesce_usecs.value, need_update); ++ ++ if (coalesce->pkt_rate_low.set) ++ UPDATE(ecmd.pkt_rate_low, coalesce->pkt_rate_low.value, need_update); ++ ++ if (coalesce->rx_coalesce_usecs_low.set) ++ UPDATE(ecmd.rx_coalesce_usecs_low, coalesce->rx_coalesce_usecs_low.value, need_update); ++ ++ if (coalesce->rx_max_coalesced_frames_low.set) ++ UPDATE(ecmd.rx_max_coalesced_frames_low, coalesce->rx_max_coalesced_frames_low.value, need_update); ++ ++ if (coalesce->tx_coalesce_usecs_low.set) ++ UPDATE(ecmd.tx_coalesce_usecs_low, coalesce->tx_coalesce_usecs_low.value, need_update); ++ ++ if (coalesce->tx_max_coalesced_frames_low.set) ++ UPDATE(ecmd.tx_max_coalesced_frames_low, coalesce->tx_max_coalesced_frames_low.value, need_update); ++ ++ if (coalesce->pkt_rate_high.set) ++ UPDATE(ecmd.pkt_rate_high, coalesce->pkt_rate_high.value, need_update); ++ ++ if (coalesce->rx_coalesce_usecs_high.set) ++ UPDATE(ecmd.rx_coalesce_usecs_high, coalesce->rx_coalesce_usecs_high.value, need_update); ++ ++ if (coalesce->rx_max_coalesced_frames_high.set) ++ UPDATE(ecmd.rx_max_coalesced_frames_high, coalesce->rx_max_coalesced_frames_high.value, need_update); ++ ++ if (coalesce->tx_coalesce_usecs_high.set) ++ UPDATE(ecmd.tx_coalesce_usecs_high, coalesce->tx_coalesce_usecs_high.value, need_update); ++ ++ if (coalesce->tx_max_coalesced_frames_high.set) ++ UPDATE(ecmd.tx_max_coalesced_frames_high, coalesce->tx_max_coalesced_frames_high.value, need_update); ++ ++ if (coalesce->rate_sample_interval.set) ++ UPDATE(ecmd.rate_sample_interval, DIV_ROUND_UP(coalesce->rate_sample_interval.value, USEC_PER_SEC), need_update); ++ ++ if (!need_update) ++ return 0; ++ ++ ecmd.cmd = ETHTOOL_SCOALESCE; ++ r = ioctl(*ethtool_fd, SIOCETHTOOL, &ifr); ++ if (r < 0) ++ return -errno; ++ ++ return 0; ++} +diff --git a/src/shared/ethtool-util.h b/src/shared/ethtool-util.h +index 8fdbdec39a..bb0333775c 100644 +--- a/src/shared/ethtool-util.h ++++ b/src/shared/ethtool-util.h +@@ -76,6 +76,31 @@ typedef struct netdev_ring_param { + u32_opt tx; + } netdev_ring_param; + ++typedef struct netdev_coalesce_param { ++ u32_opt rx_coalesce_usecs; ++ u32_opt rx_max_coalesced_frames; ++ u32_opt rx_coalesce_usecs_irq; ++ u32_opt rx_max_coalesced_frames_irq; ++ u32_opt tx_coalesce_usecs; ++ u32_opt tx_max_coalesced_frames; ++ u32_opt tx_coalesce_usecs_irq; ++ u32_opt tx_max_coalesced_frames_irq; ++ u32_opt stats_block_coalesce_usecs; ++ int use_adaptive_rx_coalesce; ++ int use_adaptive_tx_coalesce; ++ u32_opt pkt_rate_low; ++ u32_opt rx_coalesce_usecs_low; ++ u32_opt rx_max_coalesced_frames_low; ++ u32_opt tx_coalesce_usecs_low; ++ u32_opt tx_max_coalesced_frames_low; ++ u32_opt pkt_rate_high; ++ u32_opt rx_coalesce_usecs_high; ++ u32_opt rx_max_coalesced_frames_high; ++ u32_opt tx_coalesce_usecs_high; ++ u32_opt tx_max_coalesced_frames_high; ++ u32_opt rate_sample_interval; ++} netdev_coalesce_param; ++ + int ethtool_get_driver(int *ethtool_fd, const char *ifname, char **ret); + int ethtool_get_link_info(int *ethtool_fd, const char *ifname, + int *ret_autonegotiation, uint64_t *ret_speed, +@@ -89,6 +114,7 @@ int ethtool_set_glinksettings(int *ethtool_fd, const char *ifname, + uint64_t speed, Duplex duplex, NetDevPort port); + int ethtool_set_channels(int *ethtool_fd, const char *ifname, const netdev_channels *channels); + int ethtool_set_flow_control(int *fd, const char *ifname, int rx, int tx, int autoneg); ++int ethtool_set_nic_coalesce_settings(int *ethtool_fd, const char *ifname, const netdev_coalesce_param *coalesce); + + const char *duplex_to_string(Duplex d) _const_; + Duplex duplex_from_string(const char *d) _pure_; +@@ -106,3 +132,6 @@ CONFIG_PARSER_PROTOTYPE(config_parse_wol); + CONFIG_PARSER_PROTOTYPE(config_parse_port); + CONFIG_PARSER_PROTOTYPE(config_parse_advertise); + CONFIG_PARSER_PROTOTYPE(config_parse_ring_buffer_or_channel); ++CONFIG_PARSER_PROTOTYPE(config_parse_coalesce_u32); ++CONFIG_PARSER_PROTOTYPE(config_parse_coalesce_sec); ++CONFIG_PARSER_PROTOTYPE(config_parse_nic_coalesce_setting); +diff --git a/src/udev/net/link-config-gperf.gperf b/src/udev/net/link-config-gperf.gperf +index d0190da5cb..f800de8386 100644 +--- a/src/udev/net/link-config-gperf.gperf ++++ b/src/udev/net/link-config-gperf.gperf +@@ -21,54 +21,76 @@ struct ConfigPerfItem; + %struct-type + %includes + %% +-Match.MACAddress, config_parse_hwaddrs, 0, offsetof(LinkConfig, match.mac) +-Match.PermanentMACAddress, config_parse_hwaddrs, 0, offsetof(LinkConfig, match.permanent_mac) +-Match.OriginalName, config_parse_match_ifnames, 0, offsetof(LinkConfig, match.ifname) +-Match.Path, config_parse_match_strv, 0, offsetof(LinkConfig, match.path) +-Match.Driver, config_parse_match_strv, 0, offsetof(LinkConfig, match.driver) +-Match.Type, config_parse_match_strv, 0, offsetof(LinkConfig, match.iftype) +-Match.Property, config_parse_match_property, 0, offsetof(LinkConfig, match.property) +-Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(LinkConfig, conditions) +-Match.Virtualization, config_parse_net_condition, CONDITION_VIRTUALIZATION, offsetof(LinkConfig, conditions) +-Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(LinkConfig, conditions) +-Match.KernelVersion, config_parse_net_condition, CONDITION_KERNEL_VERSION, offsetof(LinkConfig, conditions) +-Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(LinkConfig, conditions) +-Link.Description, config_parse_string, 0, offsetof(LinkConfig, description) +-Link.MACAddressPolicy, config_parse_mac_address_policy, 0, offsetof(LinkConfig, mac_address_policy) +-Link.MACAddress, config_parse_hwaddr, 0, offsetof(LinkConfig, mac) +-Link.NamePolicy, config_parse_name_policy, 0, offsetof(LinkConfig, name_policy) +-Link.Name, config_parse_ifname, 0, offsetof(LinkConfig, name) +-Link.AlternativeName, config_parse_ifnames, IFNAME_VALID_ALTERNATIVE, offsetof(LinkConfig, alternative_names) +-Link.AlternativeNamesPolicy, config_parse_alternative_names_policy, 0, offsetof(LinkConfig, alternative_names_policy) +-Link.Alias, config_parse_ifalias, 0, offsetof(LinkConfig, alias) +-Link.TransmitQueues, config_parse_rx_tx_queues, 0, offsetof(LinkConfig, txqueues) +-Link.ReceiveQueues, config_parse_rx_tx_queues, 0, offsetof(LinkConfig, rxqueues) +-Link.TransmitQueueLength, config_parse_txqueuelen, 0, offsetof(LinkConfig, txqueuelen) +-Link.MTUBytes, config_parse_mtu, AF_UNSPEC, offsetof(LinkConfig, mtu) +-Link.BitsPerSecond, config_parse_si_uint64, 0, offsetof(LinkConfig, speed) +-Link.Duplex, config_parse_duplex, 0, offsetof(LinkConfig, duplex) +-Link.AutoNegotiation, config_parse_tristate, 0, offsetof(LinkConfig, autonegotiation) +-Link.WakeOnLan, config_parse_wol, 0, offsetof(LinkConfig, wol) +-Link.Port, config_parse_port, 0, offsetof(LinkConfig, port) +-Link.ReceiveChecksumOffload, config_parse_tristate, 0, offsetof(LinkConfig, features[NET_DEV_FEAT_RX]) +-Link.TransmitChecksumOffload, config_parse_tristate, 0, offsetof(LinkConfig, features[NET_DEV_FEAT_TX]) +-Link.GenericSegmentationOffload, config_parse_tristate, 0, offsetof(LinkConfig, features[NET_DEV_FEAT_GSO]) +-Link.TCPSegmentationOffload, config_parse_tristate, 0, offsetof(LinkConfig, features[NET_DEV_FEAT_TSO]) +-Link.TCP6SegmentationOffload, config_parse_tristate, 0, offsetof(LinkConfig, features[NET_DEV_FEAT_TSO6]) +-Link.UDPSegmentationOffload, config_parse_warn_compat, DISABLED_LEGACY, 0 +-Link.GenericReceiveOffload, config_parse_tristate, 0, offsetof(LinkConfig, features[NET_DEV_FEAT_GRO]) +-Link.LargeReceiveOffload, config_parse_tristate, 0, offsetof(LinkConfig, features[NET_DEV_FEAT_LRO]) +-Link.RxChannels, config_parse_ring_buffer_or_channel, 0, offsetof(LinkConfig, channels.rx) +-Link.TxChannels, config_parse_ring_buffer_or_channel, 0, offsetof(LinkConfig, channels.tx) +-Link.OtherChannels, config_parse_ring_buffer_or_channel, 0, offsetof(LinkConfig, channels.other) +-Link.CombinedChannels, config_parse_ring_buffer_or_channel, 0, offsetof(LinkConfig, channels.combined) +-Link.Advertise, config_parse_advertise, 0, offsetof(LinkConfig, advertise) +-Link.RxBufferSize, config_parse_ring_buffer_or_channel, 0, offsetof(LinkConfig, ring.rx) +-Link.RxMiniBufferSize, config_parse_ring_buffer_or_channel, 0, offsetof(LinkConfig, ring.rx_mini) +-Link.RxJumboBufferSize, config_parse_ring_buffer_or_channel, 0, offsetof(LinkConfig, ring.rx_jumbo) +-Link.TxBufferSize, config_parse_ring_buffer_or_channel, 0, offsetof(LinkConfig, ring.tx) +-Link.RxFlowControl, config_parse_tristate, 0, offsetof(LinkConfig, rx_flow_control) +-Link.TxFlowControl, config_parse_tristate, 0, offsetof(LinkConfig, tx_flow_control) +-Link.AutoNegotiationFlowControl, config_parse_tristate, 0, offsetof(LinkConfig, autoneg_flow_control) +-Link.GenericSegmentOffloadMaxBytes, config_parse_iec_size, 0, offsetof(LinkConfig, gso_max_size) +-Link.GenericSegmentOffloadMaxSegments, config_parse_uint32, 0, offsetof(LinkConfig, gso_max_segments) ++Match.MACAddress, config_parse_hwaddrs, 0, offsetof(LinkConfig, match.mac) ++Match.PermanentMACAddress, config_parse_hwaddrs, 0, offsetof(LinkConfig, match.permanent_mac) ++Match.OriginalName, config_parse_match_ifnames, 0, offsetof(LinkConfig, match.ifname) ++Match.Path, config_parse_match_strv, 0, offsetof(LinkConfig, match.path) ++Match.Driver, config_parse_match_strv, 0, offsetof(LinkConfig, match.driver) ++Match.Type, config_parse_match_strv, 0, offsetof(LinkConfig, match.iftype) ++Match.Property, config_parse_match_property, 0, offsetof(LinkConfig, match.property) ++Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(LinkConfig, conditions) ++Match.Virtualization, config_parse_net_condition, CONDITION_VIRTUALIZATION, offsetof(LinkConfig, conditions) ++Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(LinkConfig, conditions) ++Match.KernelVersion, config_parse_net_condition, CONDITION_KERNEL_VERSION, offsetof(LinkConfig, conditions) ++Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(LinkConfig, conditions) ++Link.Description, config_parse_string, 0, offsetof(LinkConfig, description) ++Link.MACAddressPolicy, config_parse_mac_address_policy, 0, offsetof(LinkConfig, mac_address_policy) ++Link.MACAddress, config_parse_hwaddr, 0, offsetof(LinkConfig, mac) ++Link.NamePolicy, config_parse_name_policy, 0, offsetof(LinkConfig, name_policy) ++Link.Name, config_parse_ifname, 0, offsetof(LinkConfig, name) ++Link.AlternativeName, config_parse_ifnames, IFNAME_VALID_ALTERNATIVE, offsetof(LinkConfig, alternative_names) ++Link.AlternativeNamesPolicy, config_parse_alternative_names_policy, 0, offsetof(LinkConfig, alternative_names_policy) ++Link.Alias, config_parse_ifalias, 0, offsetof(LinkConfig, alias) ++Link.TransmitQueues, config_parse_rx_tx_queues, 0, offsetof(LinkConfig, txqueues) ++Link.ReceiveQueues, config_parse_rx_tx_queues, 0, offsetof(LinkConfig, rxqueues) ++Link.TransmitQueueLength, config_parse_txqueuelen, 0, offsetof(LinkConfig, txqueuelen) ++Link.MTUBytes, config_parse_mtu, AF_UNSPEC, offsetof(LinkConfig, mtu) ++Link.BitsPerSecond, config_parse_si_uint64, 0, offsetof(LinkConfig, speed) ++Link.Duplex, config_parse_duplex, 0, offsetof(LinkConfig, duplex) ++Link.AutoNegotiation, config_parse_tristate, 0, offsetof(LinkConfig, autonegotiation) ++Link.WakeOnLan, config_parse_wol, 0, offsetof(LinkConfig, wol) ++Link.Port, config_parse_port, 0, offsetof(LinkConfig, port) ++Link.ReceiveChecksumOffload, config_parse_tristate, 0, offsetof(LinkConfig, features[NET_DEV_FEAT_RX]) ++Link.TransmitChecksumOffload, config_parse_tristate, 0, offsetof(LinkConfig, features[NET_DEV_FEAT_TX]) ++Link.GenericSegmentationOffload, config_parse_tristate, 0, offsetof(LinkConfig, features[NET_DEV_FEAT_GSO]) ++Link.TCPSegmentationOffload, config_parse_tristate, 0, offsetof(LinkConfig, features[NET_DEV_FEAT_TSO]) ++Link.TCP6SegmentationOffload, config_parse_tristate, 0, offsetof(LinkConfig, features[NET_DEV_FEAT_TSO6]) ++Link.UDPSegmentationOffload, config_parse_warn_compat, DISABLED_LEGACY, 0 ++Link.GenericReceiveOffload, config_parse_tristate, 0, offsetof(LinkConfig, features[NET_DEV_FEAT_GRO]) ++Link.LargeReceiveOffload, config_parse_tristate, 0, offsetof(LinkConfig, features[NET_DEV_FEAT_LRO]) ++Link.RxChannels, config_parse_ring_buffer_or_channel, 0, offsetof(LinkConfig, channels.rx) ++Link.TxChannels, config_parse_ring_buffer_or_channel, 0, offsetof(LinkConfig, channels.tx) ++Link.OtherChannels, config_parse_ring_buffer_or_channel, 0, offsetof(LinkConfig, channels.other) ++Link.CombinedChannels, config_parse_ring_buffer_or_channel, 0, offsetof(LinkConfig, channels.combined) ++Link.Advertise, config_parse_advertise, 0, offsetof(LinkConfig, advertise) ++Link.RxBufferSize, config_parse_ring_buffer_or_channel, 0, offsetof(LinkConfig, ring.rx) ++Link.RxMiniBufferSize, config_parse_ring_buffer_or_channel, 0, offsetof(LinkConfig, ring.rx_mini) ++Link.RxJumboBufferSize, config_parse_ring_buffer_or_channel, 0, offsetof(LinkConfig, ring.rx_jumbo) ++Link.TxBufferSize, config_parse_ring_buffer_or_channel, 0, offsetof(LinkConfig, ring.tx) ++Link.RxFlowControl, config_parse_tristate, 0, offsetof(LinkConfig, rx_flow_control) ++Link.TxFlowControl, config_parse_tristate, 0, offsetof(LinkConfig, tx_flow_control) ++Link.AutoNegotiationFlowControl, config_parse_tristate, 0, offsetof(LinkConfig, autoneg_flow_control) ++Link.GenericSegmentOffloadMaxBytes, config_parse_iec_size, 0, offsetof(LinkConfig, gso_max_size) ++Link.GenericSegmentOffloadMaxSegments, config_parse_uint32, 0, offsetof(LinkConfig, gso_max_segments) ++Link.RxCoalesceSec, config_parse_coalesce_sec, 0, offsetof(LinkConfig, coalesce.rx_coalesce_usecs) ++Link.RxMaxCoalescedFrames, config_parse_coalesce_u32, 0, offsetof(LinkConfig, coalesce.rx_max_coalesced_frames) ++Link.RxCoalesceIrqSec, config_parse_coalesce_sec, 0, offsetof(LinkConfig, coalesce.rx_coalesce_usecs_irq) ++Link.RxMaxCoalescedIrqFrames, config_parse_coalesce_u32, 0, offsetof(LinkConfig, coalesce.rx_max_coalesced_frames_irq) ++Link.TxCoalesceSec, config_parse_coalesce_sec, 0, offsetof(LinkConfig, coalesce.tx_coalesce_usecs) ++Link.TxMaxCoalescedFrames, config_parse_coalesce_u32, 0, offsetof(LinkConfig, coalesce.tx_max_coalesced_frames) ++Link.TxCoalesceIrqSec, config_parse_coalesce_sec, 0, offsetof(LinkConfig, coalesce.tx_coalesce_usecs_irq) ++Link.TxMaxCoalescedIrqFrames, config_parse_coalesce_u32, 0, offsetof(LinkConfig, coalesce.tx_max_coalesced_frames_irq) ++Link.StatisticsBlockCoalesceSec, config_parse_coalesce_sec, 0, offsetof(LinkConfig, coalesce.stats_block_coalesce_usecs) ++Link.UseAdaptiveRxCoalesce, config_parse_tristate, 0, offsetof(LinkConfig, coalesce.use_adaptive_rx_coalesce) ++Link.UseAdaptiveTxCoalesce, config_parse_tristate, 0, offsetof(LinkConfig, coalesce.use_adaptive_tx_coalesce) ++Link.CoalescePacketRateLow, config_parse_coalesce_u32, 0, offsetof(LinkConfig, coalesce.pkt_rate_low) ++Link.RxCoalesceLowSec, config_parse_coalesce_sec, 0, offsetof(LinkConfig, coalesce.rx_coalesce_usecs_low) ++Link.RxMaxCoalescedLowFrames, config_parse_coalesce_u32, 0, offsetof(LinkConfig, coalesce.rx_max_coalesced_frames_low) ++Link.TxCoalesceLowSec, config_parse_coalesce_sec, 0, offsetof(LinkConfig, coalesce.tx_coalesce_usecs_low) ++Link.TxMaxCoalescedLowFrames, config_parse_coalesce_u32, 0, offsetof(LinkConfig, coalesce.tx_max_coalesced_frames_low) ++Link.CoalescePacketRateHigh, config_parse_coalesce_u32, 0, offsetof(LinkConfig, coalesce.pkt_rate_high) ++Link.RxCoalesceHighSec, config_parse_coalesce_sec, 0, offsetof(LinkConfig, coalesce.rx_coalesce_usecs_high) ++Link.RxMaxCoalescedHighFrames, config_parse_coalesce_u32, 0, offsetof(LinkConfig, coalesce.rx_max_coalesced_frames_high) ++Link.TxCoalesceHighSec, config_parse_coalesce_sec, 0, offsetof(LinkConfig, coalesce.tx_coalesce_usecs_high) ++Link.TxMaxCoalescedHighFrames, config_parse_coalesce_u32, 0, offsetof(LinkConfig, coalesce.tx_max_coalesced_frames_high) ++Link.CoalescePacketRateSampleIntervalSec, config_parse_coalesce_sec, 0, offsetof(LinkConfig, coalesce.rate_sample_interval) +diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c +index 8dfe23691b..9451bd8b66 100644 +--- a/src/udev/net/link-config.c ++++ b/src/udev/net/link-config.c +@@ -353,6 +353,10 @@ static int link_config_apply_ethtool_settings(int *ethtool_fd, const LinkConfig + if (r < 0) + log_device_warning_errno(device, r, "Could not set flow control, ignoring: %m"); + ++ r = ethtool_set_nic_coalesce_settings(ethtool_fd, name, &config->coalesce); ++ if (r < 0) ++ log_device_warning_errno(device, r, "Could not set coalesce settings, ignoring: %m"); ++ + return 0; + } + +diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h +index b505c94f95..8a29a92822 100644 +--- a/src/udev/net/link-config.h ++++ b/src/udev/net/link-config.h +@@ -64,6 +64,7 @@ struct LinkConfig { + int rx_flow_control; + int tx_flow_control; + int autoneg_flow_control; ++ netdev_coalesce_param coalesce; + + LIST_FIELDS(LinkConfig, links); + }; +diff --git a/test/fuzz/fuzz-link-parser/directives.link b/test/fuzz/fuzz-link-parser/directives.link +index 112a81930f..5f232ce698 100644 +--- a/test/fuzz/fuzz-link-parser/directives.link ++++ b/test/fuzz/fuzz-link-parser/directives.link +@@ -51,3 +51,25 @@ TxFlowControl= + AutoNegotiationFlowControl= + GenericSegmentOffloadMaxBytes= + GenericSegmentOffloadMaxSegments= ++RxCoalesceSec= ++RxMaxCoalescedFrames= ++RxCoalesceIrqSec= ++RxMaxCoalescedIrqFrames= ++TxCoalesceSec= ++TxMaxCoalescedFrames= ++TxCoalesceIrqSec= ++TxMaxCoalescedIrqFrames= ++StatisticsBlockCoalesceSec= ++UseAdaptiveRxCoalesce= ++UseAdaptiveTxCoalesce= ++CoalescePacketRateLow= ++RxCoalesceLowSec= ++RxMaxCoalescedLowFrames= ++TxCoalesceLowSec= ++TxMaxCoalescedLowFrames= ++CoalescePacketRateHigh= ++RxCoalesceHighSec= ++RxMaxCoalescedHighFrames= ++TxCoalesceHighSec= ++TxMaxCoalescedHighFrames= ++CoalescePacketRateSampleIntervalSec= +-- +2.31.1 + diff --git a/SOURCES/20484.patch b/SOURCES/20484.patch new file mode 100644 index 0000000..9da073b --- /dev/null +++ b/SOURCES/20484.patch @@ -0,0 +1,96 @@ +From 0e5c20b7a4f47fd3f8edbc2735810ea3513360bb Mon Sep 17 00:00:00 2001 +From: Daan De Meyer +Date: Thu, 19 Aug 2021 13:44:35 +0100 +Subject: [PATCH] link: Add support for rx-gro-hw nic feature + +--- + man/systemd.link.xml | 7 +++++++ + src/shared/ethtool-util.c | 15 ++++++++------- + src/shared/ethtool-util.h | 1 + + src/udev/net/link-config-gperf.gperf | 1 + + test/fuzz/fuzz-link-parser/directives.link | 1 + + 5 files changed, 18 insertions(+), 7 deletions(-) + +diff --git a/man/systemd.link.xml b/man/systemd.link.xml +index 6d8dcb9af7..638a1522cd 100644 +--- a/man/systemd.link.xml ++++ b/man/systemd.link.xml +@@ -701,6 +701,13 @@ + When unset, the kernel's default will be used. + + ++ ++ GenericReceiveOffloadHardware= ++ ++ Takes a boolean. If set to true, hardware accelerated Generic Receive Offload (GRO) is ++ enabled. When unset, the kernel's default will be used. ++ ++ + + LargeReceiveOffload= + +diff --git a/src/shared/ethtool-util.c b/src/shared/ethtool-util.c +index f7f553dd29..a08bb2b7f5 100644 +--- a/src/shared/ethtool-util.c ++++ b/src/shared/ethtool-util.c +@@ -70,13 +70,14 @@ DEFINE_STRING_TABLE_LOOKUP(port, NetDevPort); + DEFINE_CONFIG_PARSE_ENUM(config_parse_port, port, NetDevPort, "Failed to parse Port setting"); + + static const char* const netdev_feature_table[_NET_DEV_FEAT_MAX] = { +- [NET_DEV_FEAT_RX] = "rx-checksum", +- [NET_DEV_FEAT_TX] = "tx-checksum-", /* The suffix "-" means any feature beginning with "tx-checksum-" */ +- [NET_DEV_FEAT_GSO] = "tx-generic-segmentation", +- [NET_DEV_FEAT_GRO] = "rx-gro", +- [NET_DEV_FEAT_LRO] = "rx-lro", +- [NET_DEV_FEAT_TSO] = "tx-tcp-segmentation", +- [NET_DEV_FEAT_TSO6] = "tx-tcp6-segmentation", ++ [NET_DEV_FEAT_RX] = "rx-checksum", ++ [NET_DEV_FEAT_TX] = "tx-checksum-", /* The suffix "-" means any feature beginning with "tx-checksum-" */ ++ [NET_DEV_FEAT_GSO] = "tx-generic-segmentation", ++ [NET_DEV_FEAT_GRO] = "rx-gro", ++ [NET_DEV_FEAT_GRO_HW] = "rx-gro-hw", ++ [NET_DEV_FEAT_LRO] = "rx-lro", ++ [NET_DEV_FEAT_TSO] = "tx-tcp-segmentation", ++ [NET_DEV_FEAT_TSO6] = "tx-tcp6-segmentation", + }; + + static const char* const ethtool_link_mode_bit_table[] = { +diff --git a/src/shared/ethtool-util.h b/src/shared/ethtool-util.h +index bb0333775c..2181ab6fd6 100644 +--- a/src/shared/ethtool-util.h ++++ b/src/shared/ethtool-util.h +@@ -23,6 +23,7 @@ typedef enum NetDevFeature { + NET_DEV_FEAT_TX, + NET_DEV_FEAT_GSO, + NET_DEV_FEAT_GRO, ++ NET_DEV_FEAT_GRO_HW, + NET_DEV_FEAT_LRO, + NET_DEV_FEAT_TSO, + NET_DEV_FEAT_TSO6, +diff --git a/src/udev/net/link-config-gperf.gperf b/src/udev/net/link-config-gperf.gperf +index f800de8386..44b46cb17c 100644 +--- a/src/udev/net/link-config-gperf.gperf ++++ b/src/udev/net/link-config-gperf.gperf +@@ -57,6 +57,7 @@ Link.TCPSegmentationOffload, config_parse_tristate, + Link.TCP6SegmentationOffload, config_parse_tristate, 0, offsetof(LinkConfig, features[NET_DEV_FEAT_TSO6]) + Link.UDPSegmentationOffload, config_parse_warn_compat, DISABLED_LEGACY, 0 + Link.GenericReceiveOffload, config_parse_tristate, 0, offsetof(LinkConfig, features[NET_DEV_FEAT_GRO]) ++Link.GenericReceiveOffloadHardware, config_parse_tristate, 0, offsetof(LinkConfig, features[NET_DEV_FEAT_GRO_HW]) + Link.LargeReceiveOffload, config_parse_tristate, 0, offsetof(LinkConfig, features[NET_DEV_FEAT_LRO]) + Link.RxChannels, config_parse_ring_buffer_or_channel, 0, offsetof(LinkConfig, channels.rx) + Link.TxChannels, config_parse_ring_buffer_or_channel, 0, offsetof(LinkConfig, channels.tx) +diff --git a/test/fuzz/fuzz-link-parser/directives.link b/test/fuzz/fuzz-link-parser/directives.link +index 5f232ce698..b5cffb1a27 100644 +--- a/test/fuzz/fuzz-link-parser/directives.link ++++ b/test/fuzz/fuzz-link-parser/directives.link +@@ -36,6 +36,7 @@ TCPSegmentationOffload= + TCP6SegmentationOffload= + UDPSegmentationOffload= + GenericReceiveOffload= ++GenericReceiveOffloadHardware= + LargeReceiveOffload= + RxChannels= + TxChannels= +-- +2.31.1 + diff --git a/SOURCES/20743.patch b/SOURCES/20743.patch new file mode 100644 index 0000000..0975ce8 --- /dev/null +++ b/SOURCES/20743.patch @@ -0,0 +1,41 @@ +From 0fc51b569570e8bf5aecd5ee03a88eb668b7b385 Mon Sep 17 00:00:00 2001 +From: Anita Zhang +Date: Tue, 14 Sep 2021 16:33:10 -0700 +Subject: [PATCH] fileio: start with 4k buffer for procfs + +There's a very gradual increase of anonymous memory in systemd-journald that +blames to 2ac67221bb6270f0fbe7cbd0076653832cd49de2. + +systemd-journald makes many calls to read /proc/PID/cmdline and +/proc/PID/status, both of which tend to be well under 4K. However the +combination of allocating 4M read buffers, then using `realloc()` to +shrink the buffer in `read_virtual_file()` appears to be creating +fragmentation in the heap (when combined with the other allocations +systemd-journald is doing). + +To help mitigate this, try reading /proc with a 4K buffer as +`read_virtual_file()` did before 2ac67221bb6270f0fbe7cbd0076653832cd49de2. +If it isn't big enough then try again with the larger buffers. +--- + src/basic/fileio.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/src/basic/fileio.c b/src/basic/fileio.c +index 99a44fdea2..466c6321c7 100644 +--- a/src/basic/fileio.c ++++ b/src/basic/fileio.c +@@ -431,6 +431,11 @@ int read_virtual_file(const char *filename, size_t max_size, char **ret_contents + } + + n_retries--; ++ } else if (n_retries > 1) { ++ /* Files in /proc are generally smaller than the page size so let's start with a page size ++ * buffer from malloc and only use the max buffer on the final try. */ ++ size = MIN3(page_size() - 1, READ_VIRTUAL_BYTES_MAX, max_size); ++ n_retries = 1; + } else { + size = MIN(READ_VIRTUAL_BYTES_MAX, max_size); + n_retries = 0; +-- +2.31.1 + diff --git a/SPECS/systemd.spec b/SPECS/systemd.spec index 50d30d2..6190ee9 100644 --- a/SPECS/systemd.spec +++ b/SPECS/systemd.spec @@ -39,8 +39,8 @@ Name: systemd Url: https://www.freedesktop.org/wiki/Software/systemd %if %{without inplace} -Version: 249.2 -Release: 1.2%{?dist} +Version: 249.4 +Release: 1.1%{?dist} %else # determine the build information from local checkout Version: %(tools/meson-vcs-tag.sh . error | sed -r 's/-([0-9])/.^\1/; s/-g/_g/') @@ -108,6 +108,11 @@ Patch0001: 18621-fb.patch # PR 18621: Quiet "proc: Bad value for 'hidepid'" messages Patch0001: https://github.com/systemd/systemd/pull/18621.patch %endif +Patch0002: https://github.com/systemd/systemd/pull/20743.patch +Patch0003: https://github.com/systemd/systemd/pull/20458.patch +Patch0004: https://github.com/systemd/systemd/pull/20472.patch +Patch0005: https://github.com/systemd/systemd/pull/20477.patch +Patch0006: https://github.com/systemd/systemd/pull/20484.patch # Downstream-only patches (0500–9999) @@ -1054,6 +1059,11 @@ fi %endif %changelog +* Mon Sep 20 2021 Anita Zhang - 249.4-1.1 +- New stable point release +- Backport optimization for read_virtual_file() (#20743) +- Backport new features for systemd-networkd (#20743, #20472, #20477, #20484) + * Thu Jul 29 2021 Anita Zhang - 249.2-1.2 - Remove Obsoletes lines on systemd-resolved and systemd-networkd since we don't want to install these by default.