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