Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ethtool: Fail number of channels change when it conflicts with rxnfc

Similar to what we do with the hash indirection table [1], when network
flow classification rules are forwarding traffic to channels greater
than the requested number of channels, fail the operation.
Without this, traffic could be directed to channels which no longer
exist (dropped) after changing number of channels.

[1] commit d4ab4286276f ("ethtool: correctly ensure {GS}CHANNELS doesn't conflict with GS{RXFH}")

Reviewed-by: Tariq Toukan <tariqt@nvidia.com>
Signed-off-by: Gal Pressman <gal@nvidia.com>
Link: https://lore.kernel.org/r/20221106123127.522985-1-gal@nvidia.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

authored by

Gal Pressman and committed by
Paolo Abeni
47f3ecf4 9a0f830f

+92 -11
+14 -5
net/ethtool/channels.c
··· 116 116 struct ethtool_channels channels = {}; 117 117 struct ethnl_req_info req_info = {}; 118 118 struct nlattr **tb = info->attrs; 119 - u32 err_attr, max_rx_in_use = 0; 119 + u32 err_attr, max_rxfh_in_use; 120 120 const struct ethtool_ops *ops; 121 121 struct net_device *dev; 122 + u64 max_rxnfc_in_use; 122 123 int ret; 123 124 124 125 ret = ethnl_parse_header_dev_get(&req_info, ··· 190 189 } 191 190 192 191 /* ensure the new Rx count fits within the configured Rx flow 193 - * indirection table settings 192 + * indirection table/rxnfc settings 194 193 */ 195 - if (netif_is_rxfh_configured(dev) && 196 - !ethtool_get_max_rxfh_channel(dev, &max_rx_in_use) && 197 - (channels.combined_count + channels.rx_count) <= max_rx_in_use) { 194 + if (ethtool_get_max_rxnfc_channel(dev, &max_rxnfc_in_use)) 195 + max_rxnfc_in_use = 0; 196 + if (!netif_is_rxfh_configured(dev) || 197 + ethtool_get_max_rxfh_channel(dev, &max_rxfh_in_use)) 198 + max_rxfh_in_use = 0; 199 + if (channels.combined_count + channels.rx_count <= max_rxfh_in_use) { 198 200 ret = -EINVAL; 199 201 GENL_SET_ERR_MSG(info, "requested channel counts are too low for existing indirection table settings"); 202 + goto out_ops; 203 + } 204 + if (channels.combined_count + channels.rx_count <= max_rxnfc_in_use) { 205 + ret = -EINVAL; 206 + GENL_SET_ERR_MSG(info, "requested channel counts are too low for existing ntuple filter settings"); 200 207 goto out_ops; 201 208 } 202 209
+66
net/ethtool/common.c
··· 512 512 return netif_running(dev) && dev->ethtool_ops->get_link(dev); 513 513 } 514 514 515 + static int ethtool_get_rxnfc_rule_count(struct net_device *dev) 516 + { 517 + const struct ethtool_ops *ops = dev->ethtool_ops; 518 + struct ethtool_rxnfc info = { 519 + .cmd = ETHTOOL_GRXCLSRLCNT, 520 + }; 521 + int err; 522 + 523 + err = ops->get_rxnfc(dev, &info, NULL); 524 + if (err) 525 + return err; 526 + 527 + return info.rule_cnt; 528 + } 529 + 530 + int ethtool_get_max_rxnfc_channel(struct net_device *dev, u64 *max) 531 + { 532 + const struct ethtool_ops *ops = dev->ethtool_ops; 533 + struct ethtool_rxnfc *info; 534 + int err, i, rule_cnt; 535 + u64 max_ring = 0; 536 + 537 + if (!ops->get_rxnfc) 538 + return -EOPNOTSUPP; 539 + 540 + rule_cnt = ethtool_get_rxnfc_rule_count(dev); 541 + if (rule_cnt <= 0) 542 + return -EINVAL; 543 + 544 + info = kvzalloc(struct_size(info, rule_locs, rule_cnt), GFP_KERNEL); 545 + if (!info) 546 + return -ENOMEM; 547 + 548 + info->cmd = ETHTOOL_GRXCLSRLALL; 549 + info->rule_cnt = rule_cnt; 550 + err = ops->get_rxnfc(dev, info, info->rule_locs); 551 + if (err) 552 + goto err_free_info; 553 + 554 + for (i = 0; i < rule_cnt; i++) { 555 + struct ethtool_rxnfc rule_info = { 556 + .cmd = ETHTOOL_GRXCLSRULE, 557 + .fs.location = info->rule_locs[i], 558 + }; 559 + 560 + err = ops->get_rxnfc(dev, &rule_info, NULL); 561 + if (err) 562 + goto err_free_info; 563 + 564 + if (rule_info.fs.ring_cookie != RX_CLS_FLOW_DISC && 565 + rule_info.fs.ring_cookie != RX_CLS_FLOW_WAKE && 566 + !(rule_info.flow_type & FLOW_RSS) && 567 + !ethtool_get_flow_spec_ring_vf(rule_info.fs.ring_cookie)) 568 + max_ring = 569 + max_t(u64, max_ring, rule_info.fs.ring_cookie); 570 + } 571 + 572 + kvfree(info); 573 + *max = max_ring; 574 + return 0; 575 + 576 + err_free_info: 577 + kvfree(info); 578 + return err; 579 + } 580 + 515 581 int ethtool_get_max_rxfh_channel(struct net_device *dev, u32 *max) 516 582 { 517 583 u32 dev_size, current_max = 0;
+1
net/ethtool/common.h
··· 43 43 struct ethtool_link_ksettings *link_ksettings, 44 44 const struct ethtool_cmd *legacy_settings); 45 45 int ethtool_get_max_rxfh_channel(struct net_device *dev, u32 *max); 46 + int ethtool_get_max_rxnfc_channel(struct net_device *dev, u64 *max); 46 47 int __ethtool_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info); 47 48 48 49 extern const struct ethtool_phy_ops *ethtool_phy_ops;
+11 -6
net/ethtool/ioctl.c
··· 1789 1789 { 1790 1790 struct ethtool_channels channels, curr = { .cmd = ETHTOOL_GCHANNELS }; 1791 1791 u16 from_channel, to_channel; 1792 - u32 max_rx_in_use = 0; 1792 + u64 max_rxnfc_in_use; 1793 + u32 max_rxfh_in_use; 1793 1794 unsigned int i; 1794 1795 int ret; 1795 1796 ··· 1821 1820 return -EINVAL; 1822 1821 1823 1822 /* ensure the new Rx count fits within the configured Rx flow 1824 - * indirection table settings */ 1825 - if (netif_is_rxfh_configured(dev) && 1826 - !ethtool_get_max_rxfh_channel(dev, &max_rx_in_use) && 1827 - (channels.combined_count + channels.rx_count) <= max_rx_in_use) 1828 - return -EINVAL; 1823 + * indirection table/rxnfc settings */ 1824 + if (ethtool_get_max_rxnfc_channel(dev, &max_rxnfc_in_use)) 1825 + max_rxnfc_in_use = 0; 1826 + if (!netif_is_rxfh_configured(dev) || 1827 + ethtool_get_max_rxfh_channel(dev, &max_rxfh_in_use)) 1828 + max_rxfh_in_use = 0; 1829 + if (channels.combined_count + channels.rx_count <= 1830 + max_t(u64, max_rxnfc_in_use, max_rxfh_in_use)) 1831 + return -EINVAL; 1829 1832 1830 1833 /* Disabling channels, query zero-copy AF_XDP sockets */ 1831 1834 from_channel = channels.combined_count +