From e9f92c88163841d3f1d29fa5b44ae4c6f71bb014 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Sep 20 2021 14:40:14 +0000 Subject: [PATCH 1/4] 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. --- diff --git a/man/systemd.link.xml b/man/systemd.link.xml index 1c18f35..fd744eb 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 f77f694..ed251ec 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 7d28766..aea1319 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; From 78e57b79c8790448412acca41e5d4495366305a6 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sep 20 2021 14:40:48 +0000 Subject: [PATCH 2/4] 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. --- diff --git a/man/systemd.link.xml b/man/systemd.link.xml index fd744eb..dfb0207 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 ed251ec..2d41d86 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 aea1319..8fdbdec 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 e2f07d7..d0190da 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) From a1661a140c97a9e8fd90ee00f2de6baa214c9076 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Sep 20 2021 14:44:23 +0000 Subject: [PATCH 3/4] udev: Add support for configuring nic coalescing settings These are configured via the corresponding ethtool ioctl. --- diff --git a/man/systemd.link.xml b/man/systemd.link.xml index dfb0207..6d8dcb9 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 2d41d86..f7f553d 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 8fdbdec..bb03337 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 d0190da..f800de8 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 8dfe236..9451bd8 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 b505c94..8a29a92 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 112a819..5f232ce 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= From 0e5c20b7a4f47fd3f8edbc2735810ea3513360bb Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Sep 20 2021 14:44:51 +0000 Subject: [PATCH 4/4] link: Add support for rx-gro-hw nic feature --- diff --git a/man/systemd.link.xml b/man/systemd.link.xml index 6d8dcb9..638a152 100644 --- a/man/systemd.link.xml +++ b/man/systemd.link.xml @@ -702,6 +702,13 @@ + 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= Takes a boolean. If set to true, Large Receive Offload (LRO) is enabled. diff --git a/src/shared/ethtool-util.c b/src/shared/ethtool-util.c index f7f553d..a08bb2b 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 bb03337..2181ab6 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 f800de8..44b46cb 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 5f232ce..b5cffb1 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=