Ben Hutchings says: ==================== Pull request: Fixes for new ethtool RSS commands This addresses several problems I previously identified with the new ETHTOOL_{G,S}RSSH commands: 1. Missing validation of reserved parameters 2. Vague documentation 3. Use of unnamed magic number 4. No consolidation with existing driver operations I don't currently have access to suitable network hardware, but have tested these changes with a dummy driver that can support various combinations of operations and sizes, together with (a) Debian's ethtool 3.13 (b) ethtool 3.14 with the submitted patch to use ETHTOOL_{G,S}RSSH and minor adjustment for fixes 1 and 3. v2: Update RSS operations in vmxnet3 too ====================
Unified · Split
| @@ -3316,7 +3316,7 @@ static u32 bnx2x_get_rxfh_indir_size(struct net_device *dev) · 3315 unmodified lines | ||
| 3316 | 3316 | return T_ETH_INDIRECTION_TABLE_SIZE; |
| 3317 | 3317 | } |
| 3318 | 3318 | |
| 3319 | −static int bnx2x_get_rxfh_indir(struct net_device *dev, u32 *indir) | |
| 3319 | +static int bnx2x_get_rxfh(struct net_device *dev, u32 *indir, u8 *key) | |
| 3320 | 3320 | { |
| 3321 | 3321 | struct bnx2x *bp = netdev_priv(dev); |
| 3322 | 3322 | u8 ind_table[T_ETH_INDIRECTION_TABLE_SIZE] = {0}; |
| @@ -3340,14 +3340,15 @@ static int bnx2x_get_rxfh_indir(struct net_device *dev, u32 *indir) · 17 unmodified lines | ||
| 3340 | 3340 | return 0; |
| 3341 | 3341 | } |
| 3342 | 3342 | |
| 3343 | −static int bnx2x_set_rxfh_indir(struct net_device *dev, const u32 *indir) | |
| 3343 | +static int bnx2x_set_rxfh(struct net_device *dev, const u32 *indir, | |
| 3344 | + const u8 *key) | |
| 3344 | 3345 | { |
| 3345 | 3346 | struct bnx2x *bp = netdev_priv(dev); |
| 3346 | 3347 | size_t i; |
| 3347 | 3348 | |
| 3348 | 3349 | for (i = 0; i < T_ETH_INDIRECTION_TABLE_SIZE; i++) { |
| 3349 | 3350 | /* |
| 3350 | − * The same as in bnx2x_get_rxfh_indir: we can't use a memcpy() | |
| 3351 | + * The same as in bnx2x_get_rxfh: we can't use a memcpy() | |
| 3351 | 3352 | * as an internal storage of an indirection table is a u8 array |
| 3352 | 3353 | * while indir->ring_index points to an array of u32. |
| 3353 | 3354 | * |
| @@ -3471,8 +3472,8 @@ static const struct ethtool_ops bnx2x_ethtool_ops = { · 117 unmodified lines | ||
| 3471 | 3472 | .get_rxnfc = bnx2x_get_rxnfc, |
| 3472 | 3473 | .set_rxnfc = bnx2x_set_rxnfc, |
| 3473 | 3474 | .get_rxfh_indir_size = bnx2x_get_rxfh_indir_size, |
| 3474 | − .get_rxfh_indir = bnx2x_get_rxfh_indir, | |
| 3475 | − .set_rxfh_indir = bnx2x_set_rxfh_indir, | |
| 3475 | + .get_rxfh = bnx2x_get_rxfh, | |
| 3476 | + .set_rxfh = bnx2x_set_rxfh, | |
| 3476 | 3477 | .get_channels = bnx2x_get_channels, |
| 3477 | 3478 | .set_channels = bnx2x_set_channels, |
| 3478 | 3479 | .get_module_info = bnx2x_get_module_info, |
| @@ -3498,8 +3499,8 @@ static const struct ethtool_ops bnx2x_vf_ethtool_ops = { · 19 unmodified lines | ||
| 3498 | 3499 | .get_rxnfc = bnx2x_get_rxnfc, |
| 3499 | 3500 | .set_rxnfc = bnx2x_set_rxnfc, |
| 3500 | 3501 | .get_rxfh_indir_size = bnx2x_get_rxfh_indir_size, |
| 3501 | − .get_rxfh_indir = bnx2x_get_rxfh_indir, | |
| 3502 | − .set_rxfh_indir = bnx2x_set_rxfh_indir, | |
| 3502 | + .get_rxfh = bnx2x_get_rxfh, | |
| 3503 | + .set_rxfh = bnx2x_set_rxfh, | |
| 3503 | 3504 | .get_channels = bnx2x_get_channels, |
| 3504 | 3505 | .set_channels = bnx2x_set_channels, |
| 3505 | 3506 | }; |
| @@ -12532,7 +12532,7 @@ static u32 tg3_get_rxfh_indir_size(struct net_device *dev) · 12531 unmodified lines | ||
| 12532 | 12532 | return size; |
| 12533 | 12533 | } |
| 12534 | 12534 | |
| 12535 | −static int tg3_get_rxfh_indir(struct net_device *dev, u32 *indir) | |
| 12535 | +static int tg3_get_rxfh(struct net_device *dev, u32 *indir, u8 *key) | |
| 12536 | 12536 | { |
| 12537 | 12537 | struct tg3 *tp = netdev_priv(dev); |
| 12538 | 12538 | int i; |
| @@ -12543,7 +12543,7 @@ static int tg3_get_rxfh_indir(struct net_device *dev, u32 *indir) · 4 unmodified lines | ||
| 12543 | 12543 | return 0; |
| 12544 | 12544 | } |
| 12545 | 12545 | |
| 12546 | −static int tg3_set_rxfh_indir(struct net_device *dev, const u32 *indir) | |
| 12546 | +static int tg3_set_rxfh(struct net_device *dev, const u32 *indir, const u8 *key) | |
| 12547 | 12547 | { |
| 12548 | 12548 | struct tg3 *tp = netdev_priv(dev); |
| 12549 | 12549 | size_t i; |
| @@ -14075,8 +14075,8 @@ static const struct ethtool_ops tg3_ethtool_ops = { · 1525 unmodified lines | ||
| 14075 | 14075 | .get_sset_count = tg3_get_sset_count, |
| 14076 | 14076 | .get_rxnfc = tg3_get_rxnfc, |
| 14077 | 14077 | .get_rxfh_indir_size = tg3_get_rxfh_indir_size, |
| 14078 | − .get_rxfh_indir = tg3_get_rxfh_indir, | |
| 14079 | − .set_rxfh_indir = tg3_set_rxfh_indir, | |
| 14078 | + .get_rxfh = tg3_get_rxfh, | |
| 14079 | + .set_rxfh = tg3_set_rxfh, | |
| 14080 | 14080 | .get_channels = tg3_get_channels, |
| 14081 | 14081 | .set_channels = tg3_set_channels, |
| 14082 | 14082 | .get_ts_info = tg3_get_ts_info, |
| @@ -2739,7 +2739,7 @@ static u32 get_rss_table_size(struct net_device *dev) · 2738 unmodified lines | ||
| 2739 | 2739 | return pi->rss_size; |
| 2740 | 2740 | } |
| 2741 | 2741 | |
| 2742 | −static int get_rss_table(struct net_device *dev, u32 *p) | |
| 2742 | +static int get_rss_table(struct net_device *dev, u32 *p, u8 *key) | |
| 2743 | 2743 | { |
| 2744 | 2744 | const struct port_info *pi = netdev_priv(dev); |
| 2745 | 2745 | unsigned int n = pi->rss_size; |
| @@ -2749,7 +2749,7 @@ static int get_rss_table(struct net_device *dev, u32 *p) · 3 unmodified lines | ||
| 2749 | 2749 | return 0; |
| 2750 | 2750 | } |
| 2751 | 2751 | |
| 2752 | −static int set_rss_table(struct net_device *dev, const u32 *p) | |
| 2752 | +static int set_rss_table(struct net_device *dev, const u32 *p, const u8 *key) | |
| 2753 | 2753 | { |
| 2754 | 2754 | unsigned int i; |
| 2755 | 2755 | struct port_info *pi = netdev_priv(dev); |
| @@ -2851,8 +2851,8 @@ static const struct ethtool_ops cxgb_ethtool_ops = { · 95 unmodified lines | ||
| 2851 | 2851 | .set_wol = set_wol, |
| 2852 | 2852 | .get_rxnfc = get_rxnfc, |
| 2853 | 2853 | .get_rxfh_indir_size = get_rss_table_size, |
| 2854 | − .get_rxfh_indir = get_rss_table, | |
| 2855 | − .set_rxfh_indir = set_rss_table, | |
| 2854 | + .get_rxfh = get_rss_table, | |
| 2855 | + .set_rxfh = set_rss_table, | |
| 2856 | 2856 | .flash_device = set_flash, |
| 2857 | 2857 | }; |
| 2858 | 2858 | |
| @@ -2065,7 +2065,7 @@ int be_cmd_reset_function(struct be_adapter *adapter) · 2064 unmodified lines | ||
| 2065 | 2065 | } |
| 2066 | 2066 | |
| 2067 | 2067 | int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable, |
| 2068 | − u32 rss_hash_opts, u16 table_size, u8 *rss_hkey) | |
| 2068 | + u32 rss_hash_opts, u16 table_size, const u8 *rss_hkey) | |
| 2069 | 2069 | { |
| 2070 | 2070 | struct be_mcc_wrb *wrb; |
| 2071 | 2071 | struct be_cmd_req_rss_config *req; |
| @@ -2082,7 +2082,7 @@ int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num, · 2081 unmodified lines | ||
| 2082 | 2082 | u32 *function_mode, u32 *function_caps, u16 *asic_rev); |
| 2083 | 2083 | int be_cmd_reset_function(struct be_adapter *adapter); |
| 2084 | 2084 | int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable, |
| 2085 | − u32 rss_hash_opts, u16 table_size, u8 *rss_hkey); | |
| 2085 | + u32 rss_hash_opts, u16 table_size, const u8 *rss_hkey); | |
| 2086 | 2086 | int be_process_mcc(struct be_adapter *adapter); |
| 2087 | 2087 | int be_cmd_set_beacon_state(struct be_adapter *adapter, u8 port_num, u8 beacon, |
| 2088 | 2088 | u8 status, u8 state); |
| @@ -1117,7 +1117,8 @@ static int be_get_rxfh(struct net_device *netdev, u32 *indir, u8 *hkey) · 1116 unmodified lines | ||
| 1117 | 1117 | return 0; |
| 1118 | 1118 | } |
| 1119 | 1119 | |
| 1120 | −static int be_set_rxfh(struct net_device *netdev, u32 *indir, u8 *hkey) | |
| 1120 | +static int be_set_rxfh(struct net_device *netdev, const u32 *indir, | |
| 1121 | + const u8 *hkey) | |
| 1121 | 1122 | { |
| 1122 | 1123 | int rc = 0, i, j; |
| 1123 | 1124 | struct be_adapter *adapter = netdev_priv(netdev); |
| @@ -624,13 +624,14 @@ static u32 i40evf_get_rxfh_indir_size(struct net_device *netdev) · 623 unmodified lines | ||
| 624 | 624 | } |
| 625 | 625 | |
| 626 | 626 | /** |
| 627 | − * i40evf_get_rxfh_indir - get the rx flow hash indirection table | |
| 627 | + * i40evf_get_rxfh - get the rx flow hash indirection table | |
| 628 | 628 | * @netdev: network interface device structure |
| 629 | 629 | * @indir: indirection table |
| 630 | + * @key: hash key (will be %NULL until get_rxfh_key_size is implemented) | |
| 630 | 631 | * |
| 631 | 632 | * Reads the indirection table directly from the hardware. Always returns 0. |
| 632 | 633 | **/ |
| 633 | −static int i40evf_get_rxfh_indir(struct net_device *netdev, u32 *indir) | |
| 634 | +static int i40evf_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key) | |
| 634 | 635 | { |
| 635 | 636 | struct i40evf_adapter *adapter = netdev_priv(netdev); |
| 636 | 637 | struct i40e_hw *hw = &adapter->hw; |
| @@ -648,14 +649,16 @@ static int i40evf_get_rxfh_indir(struct net_device *netdev, u32 *indir) · 11 unmodified lines | ||
| 648 | 649 | } |
| 649 | 650 | |
| 650 | 651 | /** |
| 651 | − * i40evf_set_rxfh_indir - set the rx flow hash indirection table | |
| 652 | + * i40evf_set_rxfh - set the rx flow hash indirection table | |
| 652 | 653 | * @netdev: network interface device structure |
| 653 | 654 | * @indir: indirection table |
| 655 | + * @key: hash key (will be %NULL until get_rxfh_key_size is implemented) | |
| 654 | 656 | * |
| 655 | 657 | * Returns -EINVAL if the table specifies an inavlid queue id, otherwise |
| 656 | 658 | * returns 0 after programming the table. |
| 657 | 659 | **/ |
| 658 | −static int i40evf_set_rxfh_indir(struct net_device *netdev, const u32 *indir) | |
| 660 | +static int i40evf_set_rxfh(struct net_device *netdev, const u32 *indir, | |
| 661 | + const u8 *key) | |
| 659 | 662 | { |
| 660 | 663 | struct i40evf_adapter *adapter = netdev_priv(netdev); |
| 661 | 664 | struct i40e_hw *hw = &adapter->hw; |
| @@ -689,8 +692,8 @@ static const struct ethtool_ops i40evf_ethtool_ops = { · 27 unmodified lines | ||
| 689 | 692 | .get_rxnfc = i40evf_get_rxnfc, |
| 690 | 693 | .set_rxnfc = i40evf_set_rxnfc, |
| 691 | 694 | .get_rxfh_indir_size = i40evf_get_rxfh_indir_size, |
| 692 | − .get_rxfh_indir = i40evf_get_rxfh_indir, | |
| 693 | − .set_rxfh_indir = i40evf_set_rxfh_indir, | |
| 695 | + .get_rxfh = i40evf_get_rxfh, | |
| 696 | + .set_rxfh = i40evf_set_rxfh, | |
| 694 | 697 | .get_channels = i40evf_get_channels, |
| 695 | 698 | }; |
| 696 | 699 | |
| @@ -2830,7 +2830,7 @@ static u32 igb_get_rxfh_indir_size(struct net_device *netdev) · 2829 unmodified lines | ||
| 2830 | 2830 | return IGB_RETA_SIZE; |
| 2831 | 2831 | } |
| 2832 | 2832 | |
| 2833 | −static int igb_get_rxfh_indir(struct net_device *netdev, u32 *indir) | |
| 2833 | +static int igb_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key) | |
| 2834 | 2834 | { |
| 2835 | 2835 | struct igb_adapter *adapter = netdev_priv(netdev); |
| 2836 | 2836 | int i; |
| @@ -2876,7 +2876,8 @@ void igb_write_rss_indir_tbl(struct igb_adapter *adapter) · 39 unmodified lines | ||
| 2876 | 2876 | } |
| 2877 | 2877 | } |
| 2878 | 2878 | |
| 2879 | −static int igb_set_rxfh_indir(struct net_device *netdev, const u32 *indir) | |
| 2879 | +static int igb_set_rxfh(struct net_device *netdev, const u32 *indir, | |
| 2880 | + const u8 *key) | |
| 2880 | 2881 | { |
| 2881 | 2882 | struct igb_adapter *adapter = netdev_priv(netdev); |
| 2882 | 2883 | struct e1000_hw *hw = &adapter->hw; |
| @@ -3025,8 +3026,8 @@ static const struct ethtool_ops igb_ethtool_ops = { · 142 unmodified lines | ||
| 3025 | 3026 | .get_module_info = igb_get_module_info, |
| 3026 | 3027 | .get_module_eeprom = igb_get_module_eeprom, |
| 3027 | 3028 | .get_rxfh_indir_size = igb_get_rxfh_indir_size, |
| 3028 | − .get_rxfh_indir = igb_get_rxfh_indir, | |
| 3029 | − .set_rxfh_indir = igb_set_rxfh_indir, | |
| 3029 | + .get_rxfh = igb_get_rxfh, | |
| 3030 | + .set_rxfh = igb_set_rxfh, | |
| 3030 | 3031 | .get_channels = igb_get_channels, |
| 3031 | 3032 | .set_channels = igb_set_channels, |
| 3032 | 3033 | .begin = igb_ethtool_begin, |
| @@ -564,7 +564,7 @@ static u32 mlx4_en_get_rxfh_indir_size(struct net_device *dev) · 563 unmodified lines | ||
| 564 | 564 | return priv->rx_ring_num; |
| 565 | 565 | } |
| 566 | 566 | |
| 567 | −static int mlx4_en_get_rxfh_indir(struct net_device *dev, u32 *ring_index) | |
| 567 | +static int mlx4_en_get_rxfh(struct net_device *dev, u32 *ring_index, u8 *key) | |
| 568 | 568 | { |
| 569 | 569 | struct mlx4_en_priv *priv = netdev_priv(dev); |
| 570 | 570 | struct mlx4_en_rss_map *rss_map = &priv->rss_map; |
| @@ -582,8 +582,8 @@ static int mlx4_en_get_rxfh_indir(struct net_device *dev, u32 *ring_index) · 11 unmodified lines | ||
| 582 | 582 | return err; |
| 583 | 583 | } |
| 584 | 584 | |
| 585 | −static int mlx4_en_set_rxfh_indir(struct net_device *dev, | |
| 586 | − const u32 *ring_index) | |
| 585 | +static int mlx4_en_set_rxfh(struct net_device *dev, const u32 *ring_index, | |
| 586 | + const u8 *key) | |
| 587 | 587 | { |
| 588 | 588 | struct mlx4_en_priv *priv = netdev_priv(dev); |
| 589 | 589 | struct mlx4_en_dev *mdev = priv->mdev; |
| @@ -1224,8 +1224,8 @@ const struct ethtool_ops mlx4_en_ethtool_ops = { · 634 unmodified lines | ||
| 1224 | 1224 | .get_rxnfc = mlx4_en_get_rxnfc, |
| 1225 | 1225 | .set_rxnfc = mlx4_en_set_rxnfc, |
| 1226 | 1226 | .get_rxfh_indir_size = mlx4_en_get_rxfh_indir_size, |
| 1227 | − .get_rxfh_indir = mlx4_en_get_rxfh_indir, | |
| 1228 | − .set_rxfh_indir = mlx4_en_set_rxfh_indir, | |
| 1227 | + .get_rxfh = mlx4_en_get_rxfh, | |
| 1228 | + .set_rxfh = mlx4_en_set_rxfh, | |
| 1229 | 1229 | .get_channels = mlx4_en_get_channels, |
| 1230 | 1230 | .set_channels = mlx4_en_set_channels, |
| 1231 | 1231 | .get_ts_info = mlx4_en_get_ts_info, |
| @@ -1033,7 +1033,7 @@ static u32 efx_ethtool_get_rxfh_indir_size(struct net_device *net_dev) · 1032 unmodified lines | ||
| 1033 | 1033 | 0 : ARRAY_SIZE(efx->rx_indir_table)); |
| 1034 | 1034 | } |
| 1035 | 1035 | |
| 1036 | −static int efx_ethtool_get_rxfh_indir(struct net_device *net_dev, u32 *indir) | |
| 1036 | +static int efx_ethtool_get_rxfh(struct net_device *net_dev, u32 *indir, u8 *key) | |
| 1037 | 1037 | { |
| 1038 | 1038 | struct efx_nic *efx = netdev_priv(net_dev); |
| 1039 | 1039 | |
| @@ -1041,8 +1041,8 @@ static int efx_ethtool_get_rxfh_indir(struct net_device *net_dev, u32 *indir) · 1 unmodified line | ||
| 1041 | 1041 | return 0; |
| 1042 | 1042 | } |
| 1043 | 1043 | |
| 1044 | −static int efx_ethtool_set_rxfh_indir(struct net_device *net_dev, | |
| 1045 | − const u32 *indir) | |
| 1044 | +static int efx_ethtool_set_rxfh(struct net_device *net_dev, | |
| 1045 | + const u32 *indir, const u8 *key) | |
| 1046 | 1046 | { |
| 1047 | 1047 | struct efx_nic *efx = netdev_priv(net_dev); |
| 1048 | 1048 | |
| @@ -1125,8 +1125,8 @@ const struct ethtool_ops efx_ethtool_ops = { · 76 unmodified lines | ||
| 1125 | 1125 | .get_rxnfc = efx_ethtool_get_rxnfc, |
| 1126 | 1126 | .set_rxnfc = efx_ethtool_set_rxnfc, |
| 1127 | 1127 | .get_rxfh_indir_size = efx_ethtool_get_rxfh_indir_size, |
| 1128 | − .get_rxfh_indir = efx_ethtool_get_rxfh_indir, | |
| 1129 | − .set_rxfh_indir = efx_ethtool_set_rxfh_indir, | |
| 1128 | + .get_rxfh = efx_ethtool_get_rxfh, | |
| 1129 | + .set_rxfh = efx_ethtool_set_rxfh, | |
| 1130 | 1130 | .get_ts_info = efx_ethtool_get_ts_info, |
| 1131 | 1131 | .get_module_info = efx_ethtool_get_module_info, |
| 1132 | 1132 | .get_module_eeprom = efx_ethtool_get_module_eeprom, |
| @@ -579,7 +579,7 @@ vmxnet3_get_rss_indir_size(struct net_device *netdev) · 578 unmodified lines | ||
| 579 | 579 | } |
| 580 | 580 | |
| 581 | 581 | static int |
| 582 | −vmxnet3_get_rss_indir(struct net_device *netdev, u32 *p) | |
| 582 | +vmxnet3_get_rss(struct net_device *netdev, u32 *p, u8 *key) | |
| 583 | 583 | { |
| 584 | 584 | struct vmxnet3_adapter *adapter = netdev_priv(netdev); |
| 585 | 585 | struct UPT1_RSSConf *rssConf = adapter->rss_conf; |
| @@ -592,7 +592,7 @@ vmxnet3_get_rss_indir(struct net_device *netdev, u32 *p) · 6 unmodified lines | ||
| 592 | 592 | } |
| 593 | 593 | |
| 594 | 594 | static int |
| 595 | −vmxnet3_set_rss_indir(struct net_device *netdev, const u32 *p) | |
| 595 | +vmxnet3_set_rss(struct net_device *netdev, const u32 *p, const u8 *key) | |
| 596 | 596 | { |
| 597 | 597 | unsigned int i; |
| 598 | 598 | unsigned long flags; |
| @@ -628,8 +628,8 @@ static const struct ethtool_ops vmxnet3_ethtool_ops = { · 29 unmodified lines | ||
| 628 | 628 | .get_rxnfc = vmxnet3_get_rxnfc, |
| 629 | 629 | #ifdef VMXNET3_RSS |
| 630 | 630 | .get_rxfh_indir_size = vmxnet3_get_rss_indir_size, |
| 631 | − .get_rxfh_indir = vmxnet3_get_rss_indir, | |
| 632 | − .set_rxfh_indir = vmxnet3_set_rss_indir, | |
| 631 | + .get_rxfh = vmxnet3_get_rss, | |
| 632 | + .set_rxfh = vmxnet3_set_rss, | |
| 633 | 633 | #endif |
| 634 | 634 | }; |
| 635 | 635 | |
| @@ -158,19 +158,16 @@ static inline u32 ethtool_rxfh_indir_default(u32 index, u32 n_rx_rings) · 157 unmodified lines | ||
| 158 | 158 | * Returns zero if not supported for this specific device. |
| 159 | 159 | * @get_rxfh_indir_size: Get the size of the RX flow hash indirection table. |
| 160 | 160 | * Returns zero if not supported for this specific device. |
| 161 | − * @get_rxfh_indir: Get the contents of the RX flow hash indirection table. | |
| 162 | − * Will not be called if @get_rxfh_indir_size returns zero. | |
| 163 | 161 | * @get_rxfh: Get the contents of the RX flow hash indirection table and hash |
| 164 | 162 | * key. |
| 165 | − * Will not be called if @get_rxfh_indir_size and @get_rxfh_key_size | |
| 166 | − * returns zero. | |
| 163 | + * Will only be called if one or both of @get_rxfh_indir_size and | |
| 164 | + * @get_rxfh_key_size are implemented and return non-zero. | |
| 167 | 165 | * Returns a negative error code or zero. |
| 168 | − * @set_rxfh_indir: Set the contents of the RX flow hash indirection table. | |
| 169 | − * Will not be called if @get_rxfh_indir_size returns zero. | |
| 170 | − * @set_rxfh: Set the contents of the RX flow hash indirection table and | |
| 171 | − * hash key. | |
| 172 | − * Will not be called if @get_rxfh_indir_size and @get_rxfh_key_size | |
| 173 | − * returns zero. | |
| 166 | + * @set_rxfh: Set the contents of the RX flow hash indirection table and/or | |
| 167 | + * hash key. In case only the indirection table or hash key is to be | |
| 168 | + * changed, the other argument will be %NULL. | |
| 169 | + * Will only be called if one or both of @get_rxfh_indir_size and | |
| 170 | + * @get_rxfh_key_size are implemented and return non-zero. | |
| 174 | 171 | * Returns a negative error code or zero. |
| 175 | 172 | * @get_channels: Get number of channels. |
| 176 | 173 | * @set_channels: Set number of channels. Returns a negative error code or |
| @@ -244,10 +241,9 @@ struct ethtool_ops { · 67 unmodified lines | ||
| 244 | 241 | int (*reset)(struct net_device *, u32 *); |
| 245 | 242 | u32 (*get_rxfh_key_size)(struct net_device *); |
| 246 | 243 | u32 (*get_rxfh_indir_size)(struct net_device *); |
| 247 | − int (*get_rxfh)(struct net_device *, u32 *, u8 *); | |
| 248 | − int (*set_rxfh)(struct net_device *, u32 *, u8 *); | |
| 249 | − int (*get_rxfh_indir)(struct net_device *, u32 *); | |
| 250 | − int (*set_rxfh_indir)(struct net_device *, const u32 *); | |
| 244 | + int (*get_rxfh)(struct net_device *, u32 *indir, u8 *key); | |
| 245 | + int (*set_rxfh)(struct net_device *, const u32 *indir, | |
| 246 | + const u8 *key); | |
| 251 | 247 | void (*get_channels)(struct net_device *, struct ethtool_channels *); |
| 252 | 248 | int (*set_channels)(struct net_device *, struct ethtool_channels *); |
| 253 | 249 | int (*get_dump_flag)(struct net_device *, struct ethtool_dump *); |
| @@ -850,21 +850,23 @@ struct ethtool_rxfh_indir { · 849 unmodified lines | ||
| 850 | 850 | * struct ethtool_rxfh - command to get/set RX flow hash indir or/and hash key. |
| 851 | 851 | * @cmd: Specific command number - %ETHTOOL_GRSSH or %ETHTOOL_SRSSH |
| 852 | 852 | * @rss_context: RSS context identifier. |
| 853 | − * @indir_size: On entry, the array size of the user buffer, which may be zero. | |
| 854 | − * On return from %ETHTOOL_GRSSH, the array size of the hardware | |
| 855 | − * indirection table. | |
| 856 | − * @key_size: On entry, the array size of the user buffer in bytes, | |
| 857 | − * which may be zero. | |
| 858 | − * On return from %ETHTOOL_GRSSH, the size of the RSS hash key. | |
| 853 | + * @indir_size: On entry, the array size of the user buffer for the | |
| 854 | + * indirection table, which may be zero, or (for %ETHTOOL_SRSSH), | |
| 855 | + * %ETH_RXFH_INDIR_NO_CHANGE. On return from %ETHTOOL_GRSSH, | |
| 856 | + * the array size of the hardware indirection table. | |
| 857 | + * @key_size: On entry, the array size of the user buffer for the hash key, | |
| 858 | + * which may be zero. On return from %ETHTOOL_GRSSH, the size of the | |
| 859 | + * hardware hash key. | |
| 859 | 860 | * @rsvd: Reserved for future extensions. |
| 860 | 861 | * @rss_config: RX ring/queue index for each hash value i.e., indirection table |
| 861 | − * of size @indir_size followed by hash key of size @key_size. | |
| 862 | + * of @indir_size __u32 elements, followed by hash key of @key_size | |
| 863 | + * bytes. | |
| 862 | 864 | * |
| 863 | 865 | * For %ETHTOOL_GRSSH, a @indir_size and key_size of zero means that only the |
| 864 | − * size should be returned. For %ETHTOOL_SRSSH, a @indir_size of 0xDEADBEEF | |
| 865 | − * means that indir table setting is not requested and a @indir_size of zero | |
| 866 | − * means the indir table should be reset to default values. This last feature | |
| 867 | − * is not supported by the original implementations. | |
| 866 | + * size should be returned. For %ETHTOOL_SRSSH, an @indir_size of | |
| 867 | + * %ETH_RXFH_INDIR_NO_CHANGE means that indir table setting is not requested | |
| 868 | + * and a @indir_size of zero means the indir table should be reset to default | |
| 869 | + * values. | |
| 868 | 870 | */ |
| 869 | 871 | struct ethtool_rxfh { |
| 870 | 872 | __u32 cmd; |
| @@ -874,6 +876,7 @@ struct ethtool_rxfh { · 3 unmodified lines | ||
| 874 | 876 | __u32 rsvd[2]; |
| 875 | 877 | __u32 rss_config[0]; |
| 876 | 878 | }; |
| 879 | +#define ETH_RXFH_INDIR_NO_CHANGE 0xffffffff | |
| 877 | 880 | |
| 878 | 881 | /** |
| 879 | 882 | * struct ethtool_rx_ntuple_flow_spec - specification for RX flow filter |
| @@ -561,19 +561,17 @@ static int ethtool_copy_validate_indir(u32 *indir, void __user *useraddr, · 560 unmodified lines | ||
| 561 | 561 | struct ethtool_rxnfc *rx_rings, |
| 562 | 562 | u32 size) |
| 563 | 563 | { |
| 564 | − int ret = 0, i; | |
| 564 | + int i; | |
| 565 | 565 | |
| 566 | 566 | if (copy_from_user(indir, useraddr, size * sizeof(indir[0]))) |
| 567 | − ret = -EFAULT; | |
| 567 | + return -EFAULT; | |
| 568 | 568 | |
| 569 | 569 | /* Validate ring indices */ |
| 570 | − for (i = 0; i < size; i++) { | |
| 571 | − if (indir[i] >= rx_rings->data) { | |
| 572 | − ret = -EINVAL; | |
| 573 | − break; | |
| 574 | − } | |
| 575 | − } | |
| 576 | − return ret; | |
| 570 | + for (i = 0; i < size; i++) | |
| 571 | + if (indir[i] >= rx_rings->data) | |
| 572 | + return -EINVAL; | |
| 573 | + | |
| 574 | + return 0; | |
| 577 | 575 | } |
| 578 | 576 | |
| 579 | 577 | static noinline_for_stack int ethtool_get_rxfh_indir(struct net_device *dev, |
| @@ -584,7 +582,7 @@ static noinline_for_stack int ethtool_get_rxfh_indir(struct net_device *dev, · 4 unmodified lines | ||
| 584 | 582 | int ret; |
| 585 | 583 | |
| 586 | 584 | if (!dev->ethtool_ops->get_rxfh_indir_size || |
| 587 | − !dev->ethtool_ops->get_rxfh_indir) | |
| 585 | + !dev->ethtool_ops->get_rxfh) | |
| 588 | 586 | return -EOPNOTSUPP; |
| 589 | 587 | dev_size = dev->ethtool_ops->get_rxfh_indir_size(dev); |
| 590 | 588 | if (dev_size == 0) |
| @@ -610,7 +608,7 @@ static noinline_for_stack int ethtool_get_rxfh_indir(struct net_device *dev, · 19 unmodified lines | ||
| 610 | 608 | if (!indir) |
| 611 | 609 | return -ENOMEM; |
| 612 | 610 | |
| 613 | − ret = dev->ethtool_ops->get_rxfh_indir(dev, indir); | |
| 611 | + ret = dev->ethtool_ops->get_rxfh(dev, indir, NULL); | |
| 614 | 612 | if (ret) |
| 615 | 613 | goto out; |
| 616 | 614 | |
| @@ -634,7 +632,7 @@ static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev, · 17 unmodified lines | ||
| 634 | 632 | int ret; |
| 635 | 633 | u32 ringidx_offset = offsetof(struct ethtool_rxfh_indir, ring_index[0]); |
| 636 | 634 | |
| 637 | − if (!ops->get_rxfh_indir_size || !ops->set_rxfh_indir || | |
| 635 | + if (!ops->get_rxfh_indir_size || !ops->set_rxfh || | |
| 638 | 636 | !ops->get_rxnfc) |
| 639 | 637 | return -EOPNOTSUPP; |
| 640 | 638 | |
| @@ -671,7 +669,7 @@ static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev, · 30 unmodified lines | ||
| 671 | 669 | goto out; |
| 672 | 670 | } |
| 673 | 671 | |
| 674 | − ret = ops->set_rxfh_indir(dev, indir); | |
| 672 | + ret = ops->set_rxfh(dev, indir, NULL); | |
| 675 | 673 | |
| 676 | 674 | out: |
| 677 | 675 | kfree(indir); |
| @@ -683,11 +681,11 @@ static noinline_for_stack int ethtool_get_rxfh(struct net_device *dev, · 5 unmodified lines | ||
| 683 | 681 | { |
| 684 | 682 | int ret; |
| 685 | 683 | const struct ethtool_ops *ops = dev->ethtool_ops; |
| 686 | − u32 user_indir_size = 0, user_key_size = 0; | |
| 684 | + u32 user_indir_size, user_key_size; | |
| 687 | 685 | u32 dev_indir_size = 0, dev_key_size = 0; |
| 686 | + struct ethtool_rxfh rxfh; | |
| 688 | 687 | u32 total_size; |
| 689 | − u32 indir_offset, indir_bytes; | |
| 690 | − u32 key_offset; | |
| 688 | + u32 indir_bytes; | |
| 691 | 689 | u32 *indir = NULL; |
| 692 | 690 | u8 *hkey = NULL; |
| 693 | 691 | u8 *rss_config; |
| @@ -699,33 +697,24 @@ static noinline_for_stack int ethtool_get_rxfh(struct net_device *dev, · 5 unmodified lines | ||
| 699 | 697 | |
| 700 | 698 | if (ops->get_rxfh_indir_size) |
| 701 | 699 | dev_indir_size = ops->get_rxfh_indir_size(dev); |
| 702 | − | |
| 703 | − indir_offset = offsetof(struct ethtool_rxfh, indir_size); | |
| 704 | − | |
| 705 | − if (copy_from_user(&user_indir_size, | |
| 706 | − useraddr + indir_offset, | |
| 707 | − sizeof(user_indir_size))) | |
| 708 | − return -EFAULT; | |
| 709 | − | |
| 710 | − if (copy_to_user(useraddr + indir_offset, | |
| 711 | − &dev_indir_size, sizeof(dev_indir_size))) | |
| 712 | − return -EFAULT; | |
| 713 | − | |
| 714 | 700 | if (ops->get_rxfh_key_size) |
| 715 | 701 | dev_key_size = ops->get_rxfh_key_size(dev); |
| 716 | 702 | |
| 717 | 703 | if ((dev_key_size + dev_indir_size) == 0) |
| 718 | 704 | return -EOPNOTSUPP; |
| 719 | 705 | |
| 720 | − key_offset = offsetof(struct ethtool_rxfh, key_size); | |
| 721 | − | |
| 722 | − if (copy_from_user(&user_key_size, | |
| 723 | − useraddr + key_offset, | |
| 724 | − sizeof(user_key_size))) | |
| 706 | + if (copy_from_user(&rxfh, useraddr, sizeof(rxfh))) | |
| 725 | 707 | return -EFAULT; |
| 708 | + user_indir_size = rxfh.indir_size; | |
| 709 | + user_key_size = rxfh.key_size; | |
| 726 | 710 | |
| 727 | − if (copy_to_user(useraddr + key_offset, | |
| 728 | − &dev_key_size, sizeof(dev_key_size))) | |
| 711 | + /* Check that reserved fields are 0 for now */ | |
| 712 | + if (rxfh.rss_context || rxfh.rsvd[0] || rxfh.rsvd[1]) | |
| 713 | + return -EINVAL; | |
| 714 | + | |
| 715 | + rxfh.indir_size = dev_indir_size; | |
| 716 | + rxfh.key_size = dev_key_size; | |
| 717 | + if (copy_to_user(useraddr, &rxfh, sizeof(rxfh))) | |
| 729 | 718 | return -EFAULT; |
| 730 | 719 | |
| 731 | 720 | /* If the user buffer size is 0, this is just a query for the |
| @@ -770,12 +759,11 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev, · 38 unmodified lines | ||
| 770 | 759 | int ret; |
| 771 | 760 | const struct ethtool_ops *ops = dev->ethtool_ops; |
| 772 | 761 | struct ethtool_rxnfc rx_rings; |
| 773 | − u32 user_indir_size = 0, dev_indir_size = 0, i; | |
| 774 | − u32 user_key_size = 0, dev_key_size = 0; | |
| 762 | + struct ethtool_rxfh rxfh; | |
| 763 | + u32 dev_indir_size = 0, dev_key_size = 0, i; | |
| 775 | 764 | u32 *indir = NULL, indir_bytes = 0; |
| 776 | 765 | u8 *hkey = NULL; |
| 777 | 766 | u8 *rss_config; |
| 778 | − u32 indir_offset, key_offset; | |
| 779 | 767 | u32 rss_cfg_offset = offsetof(struct ethtool_rxfh, rss_config[0]); |
| 780 | 768 | |
| 781 | 769 | if (!(ops->get_rxfh_indir_size || ops->get_rxfh_key_size) || |
| @@ -784,36 +772,33 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev, · 2 unmodified lines | ||
| 784 | 772 | |
| 785 | 773 | if (ops->get_rxfh_indir_size) |
| 786 | 774 | dev_indir_size = ops->get_rxfh_indir_size(dev); |
| 787 | − | |
| 788 | − indir_offset = offsetof(struct ethtool_rxfh, indir_size); | |
| 789 | − if (copy_from_user(&user_indir_size, | |
| 790 | − useraddr + indir_offset, | |
| 791 | − sizeof(user_indir_size))) | |
| 792 | − return -EFAULT; | |
| 793 | − | |
| 794 | 775 | if (ops->get_rxfh_key_size) |
| 795 | 776 | dev_key_size = dev->ethtool_ops->get_rxfh_key_size(dev); |
| 796 | − | |
| 797 | 777 | if ((dev_key_size + dev_indir_size) == 0) |
| 798 | 778 | return -EOPNOTSUPP; |
| 799 | 779 | |
| 800 | − key_offset = offsetof(struct ethtool_rxfh, key_size); | |
| 801 | − if (copy_from_user(&user_key_size, | |
| 802 | − useraddr + key_offset, | |
| 803 | − sizeof(user_key_size))) | |
| 780 | + if (copy_from_user(&rxfh, useraddr, sizeof(rxfh))) | |
| 804 | 781 | return -EFAULT; |
| 805 | 782 | |
| 783 | + /* Check that reserved fields are 0 for now */ | |
| 784 | + if (rxfh.rss_context || rxfh.rsvd[0] || rxfh.rsvd[1]) | |
| 785 | + return -EINVAL; | |
| 786 | + | |
| 806 | 787 | /* If either indir or hash key is valid, proceed further. |
| 788 | + * It is not valid to request that both be unchanged. | |
| 807 | 789 | */ |
| 808 | − if ((user_indir_size && ((user_indir_size != 0xDEADBEEF) && | |
| 809 | − user_indir_size != dev_indir_size)) || | |
| 810 | − (user_key_size && (user_key_size != dev_key_size))) | |
| 790 | + if ((rxfh.indir_size && | |
| 791 | + rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE && | |
| 792 | + rxfh.indir_size != dev_indir_size) || | |
| 793 | + (rxfh.key_size && (rxfh.key_size != dev_key_size)) || | |
| 794 | + (rxfh.indir_size == ETH_RXFH_INDIR_NO_CHANGE && | |
| 795 | + rxfh.key_size == 0)) | |
| 811 | 796 | return -EINVAL; |
| 812 | 797 | |
| 813 | − if (user_indir_size != 0xDEADBEEF) | |
| 798 | + if (rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE) | |
| 814 | 799 | indir_bytes = dev_indir_size * sizeof(indir[0]); |
| 815 | 800 | |
| 816 | − rss_config = kzalloc(indir_bytes + user_key_size, GFP_USER); | |
| 801 | + rss_config = kzalloc(indir_bytes + rxfh.key_size, GFP_USER); | |
| 817 | 802 | if (!rss_config) |
| 818 | 803 | return -ENOMEM; |
| 819 | 804 | |
| @@ -822,28 +807,29 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev, · 2 unmodified lines | ||
| 822 | 807 | if (ret) |
| 823 | 808 | goto out; |
| 824 | 809 | |
| 825 | − /* user_indir_size == 0 means reset the indir table to default. | |
| 826 | − * user_indir_size == 0xDEADBEEF means indir setting is not requested. | |
| 810 | + /* rxfh.indir_size == 0 means reset the indir table to default. | |
| 811 | + * rxfh.indir_size == ETH_RXFH_INDIR_NO_CHANGE means leave it unchanged. | |
| 827 | 812 | */ |
| 828 | − if (user_indir_size && user_indir_size != 0xDEADBEEF) { | |
| 813 | + if (rxfh.indir_size && | |
| 814 | + rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE) { | |
| 829 | 815 | indir = (u32 *)rss_config; |
| 830 | 816 | ret = ethtool_copy_validate_indir(indir, |
| 831 | 817 | useraddr + rss_cfg_offset, |
| 832 | 818 | &rx_rings, |
| 833 | − user_indir_size); | |
| 819 | + rxfh.indir_size); | |
| 834 | 820 | if (ret) |
| 835 | 821 | goto out; |
| 836 | − } else if (user_indir_size == 0) { | |
| 822 | + } else if (rxfh.indir_size == 0) { | |
| 837 | 823 | indir = (u32 *)rss_config; |
| 838 | 824 | for (i = 0; i < dev_indir_size; i++) |
| 839 | 825 | indir[i] = ethtool_rxfh_indir_default(i, rx_rings.data); |
| 840 | 826 | } |
| 841 | 827 | |
| 842 | − if (user_key_size) { | |
| 828 | + if (rxfh.key_size) { | |
| 843 | 829 | hkey = rss_config + indir_bytes; |
| 844 | 830 | if (copy_from_user(hkey, |
| 845 | 831 | useraddr + rss_cfg_offset + indir_bytes, |
| 846 | − user_key_size)) { | |
| 832 | + rxfh.key_size)) { | |
| 847 | 833 | ret = -EFAULT; |
| 848 | 834 | goto out; |
| 849 | 835 | } |