| .. | .. |
|---|
| 32 | 32 | |
|---|
| 33 | 33 | #include <linux/mlx5/fs.h> |
|---|
| 34 | 34 | #include "en.h" |
|---|
| 35 | +#include "en/params.h" |
|---|
| 36 | +#include "en/xsk/pool.h" |
|---|
| 35 | 37 | |
|---|
| 36 | 38 | struct mlx5e_ethtool_rule { |
|---|
| 37 | 39 | struct list_head list; |
|---|
| .. | .. |
|---|
| 56 | 58 | struct ethtool_rx_flow_spec *fs, |
|---|
| 57 | 59 | int num_tuples) |
|---|
| 58 | 60 | { |
|---|
| 61 | + struct mlx5_flow_table_attr ft_attr = {}; |
|---|
| 59 | 62 | struct mlx5e_ethtool_table *eth_ft; |
|---|
| 60 | 63 | struct mlx5_flow_namespace *ns; |
|---|
| 61 | 64 | struct mlx5_flow_table *ft; |
|---|
| .. | .. |
|---|
| 100 | 103 | table_size = min_t(u32, BIT(MLX5_CAP_FLOWTABLE(priv->mdev, |
|---|
| 101 | 104 | flow_table_properties_nic_receive.log_max_ft_size)), |
|---|
| 102 | 105 | MLX5E_ETHTOOL_NUM_ENTRIES); |
|---|
| 103 | | - ft = mlx5_create_auto_grouped_flow_table(ns, prio, |
|---|
| 104 | | - table_size, |
|---|
| 105 | | - MLX5E_ETHTOOL_NUM_GROUPS, 0, 0); |
|---|
| 106 | + |
|---|
| 107 | + ft_attr.prio = prio; |
|---|
| 108 | + ft_attr.max_fte = table_size; |
|---|
| 109 | + ft_attr.autogroup.max_num_groups = MLX5E_ETHTOOL_NUM_GROUPS; |
|---|
| 110 | + ft = mlx5_create_auto_grouped_flow_table(ns, &ft_attr); |
|---|
| 106 | 111 | if (IS_ERR(ft)) |
|---|
| 107 | 112 | return (void *)ft; |
|---|
| 108 | 113 | |
|---|
| .. | .. |
|---|
| 131 | 136 | if (ip4src_m) { |
|---|
| 132 | 137 | memcpy(MLX5E_FTE_ADDR_OF(headers_v, src_ipv4_src_ipv6.ipv4_layout.ipv4), |
|---|
| 133 | 138 | &ip4src_v, sizeof(ip4src_v)); |
|---|
| 134 | | - memset(MLX5E_FTE_ADDR_OF(headers_c, src_ipv4_src_ipv6.ipv4_layout.ipv4), |
|---|
| 135 | | - 0xff, sizeof(ip4src_m)); |
|---|
| 139 | + memcpy(MLX5E_FTE_ADDR_OF(headers_c, src_ipv4_src_ipv6.ipv4_layout.ipv4), |
|---|
| 140 | + &ip4src_m, sizeof(ip4src_m)); |
|---|
| 136 | 141 | } |
|---|
| 137 | 142 | if (ip4dst_m) { |
|---|
| 138 | 143 | memcpy(MLX5E_FTE_ADDR_OF(headers_v, dst_ipv4_dst_ipv6.ipv4_layout.ipv4), |
|---|
| 139 | 144 | &ip4dst_v, sizeof(ip4dst_v)); |
|---|
| 140 | | - memset(MLX5E_FTE_ADDR_OF(headers_c, dst_ipv4_dst_ipv6.ipv4_layout.ipv4), |
|---|
| 141 | | - 0xff, sizeof(ip4dst_m)); |
|---|
| 145 | + memcpy(MLX5E_FTE_ADDR_OF(headers_c, dst_ipv4_dst_ipv6.ipv4_layout.ipv4), |
|---|
| 146 | + &ip4dst_m, sizeof(ip4dst_m)); |
|---|
| 142 | 147 | } |
|---|
| 143 | 148 | |
|---|
| 144 | 149 | MLX5E_FTE_SET(headers_c, ethertype, 0xffff); |
|---|
| .. | .. |
|---|
| 173 | 178 | __be16 pdst_m, __be16 pdst_v) |
|---|
| 174 | 179 | { |
|---|
| 175 | 180 | if (psrc_m) { |
|---|
| 176 | | - MLX5E_FTE_SET(headers_c, tcp_sport, 0xffff); |
|---|
| 181 | + MLX5E_FTE_SET(headers_c, tcp_sport, ntohs(psrc_m)); |
|---|
| 177 | 182 | MLX5E_FTE_SET(headers_v, tcp_sport, ntohs(psrc_v)); |
|---|
| 178 | 183 | } |
|---|
| 179 | 184 | if (pdst_m) { |
|---|
| 180 | | - MLX5E_FTE_SET(headers_c, tcp_dport, 0xffff); |
|---|
| 185 | + MLX5E_FTE_SET(headers_c, tcp_dport, ntohs(pdst_m)); |
|---|
| 181 | 186 | MLX5E_FTE_SET(headers_v, tcp_dport, ntohs(pdst_v)); |
|---|
| 182 | 187 | } |
|---|
| 183 | 188 | |
|---|
| .. | .. |
|---|
| 190 | 195 | __be16 pdst_m, __be16 pdst_v) |
|---|
| 191 | 196 | { |
|---|
| 192 | 197 | if (psrc_m) { |
|---|
| 193 | | - MLX5E_FTE_SET(headers_c, udp_sport, 0xffff); |
|---|
| 198 | + MLX5E_FTE_SET(headers_c, udp_sport, ntohs(psrc_m)); |
|---|
| 194 | 199 | MLX5E_FTE_SET(headers_v, udp_sport, ntohs(psrc_v)); |
|---|
| 195 | 200 | } |
|---|
| 196 | 201 | |
|---|
| 197 | 202 | if (pdst_m) { |
|---|
| 198 | | - MLX5E_FTE_SET(headers_c, udp_dport, 0xffff); |
|---|
| 203 | + MLX5E_FTE_SET(headers_c, udp_dport, ntohs(pdst_m)); |
|---|
| 199 | 204 | MLX5E_FTE_SET(headers_v, udp_dport, ntohs(pdst_v)); |
|---|
| 200 | 205 | } |
|---|
| 201 | 206 | |
|---|
| .. | .. |
|---|
| 397 | 402 | struct mlx5_flow_table *ft, |
|---|
| 398 | 403 | struct ethtool_rx_flow_spec *fs) |
|---|
| 399 | 404 | { |
|---|
| 405 | + struct mlx5_flow_act flow_act = { .flags = FLOW_ACT_NO_APPEND }; |
|---|
| 400 | 406 | struct mlx5_flow_destination *dst = NULL; |
|---|
| 401 | | - struct mlx5_flow_act flow_act = {0}; |
|---|
| 402 | | - struct mlx5_flow_spec *spec; |
|---|
| 403 | 407 | struct mlx5_flow_handle *rule; |
|---|
| 408 | + struct mlx5_flow_spec *spec; |
|---|
| 404 | 409 | int err = 0; |
|---|
| 405 | 410 | |
|---|
| 406 | 411 | spec = kvzalloc(sizeof(*spec), GFP_KERNEL); |
|---|
| .. | .. |
|---|
| 414 | 419 | if (fs->ring_cookie == RX_CLS_FLOW_DISC) { |
|---|
| 415 | 420 | flow_act.action = MLX5_FLOW_CONTEXT_ACTION_DROP; |
|---|
| 416 | 421 | } else { |
|---|
| 422 | + struct mlx5e_params *params = &priv->channels.params; |
|---|
| 423 | + enum mlx5e_rq_group group; |
|---|
| 424 | + struct mlx5e_tir *tir; |
|---|
| 425 | + u16 ix; |
|---|
| 426 | + |
|---|
| 427 | + mlx5e_qid_get_ch_and_group(params, fs->ring_cookie, &ix, &group); |
|---|
| 428 | + tir = group == MLX5E_RQ_GROUP_XSK ? priv->xsk_tir : priv->direct_tir; |
|---|
| 429 | + |
|---|
| 417 | 430 | dst = kzalloc(sizeof(*dst), GFP_KERNEL); |
|---|
| 418 | 431 | if (!dst) { |
|---|
| 419 | 432 | err = -ENOMEM; |
|---|
| .. | .. |
|---|
| 421 | 434 | } |
|---|
| 422 | 435 | |
|---|
| 423 | 436 | dst->type = MLX5_FLOW_DESTINATION_TYPE_TIR; |
|---|
| 424 | | - dst->tir_num = priv->direct_tir[fs->ring_cookie].tirn; |
|---|
| 437 | + dst->tir_num = tir[ix].tirn; |
|---|
| 425 | 438 | flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; |
|---|
| 426 | 439 | } |
|---|
| 427 | 440 | |
|---|
| 428 | 441 | spec->match_criteria_enable = (!outer_header_zero(spec->match_criteria)); |
|---|
| 429 | | - flow_act.flow_tag = MLX5_FS_DEFAULT_FLOW_TAG; |
|---|
| 442 | + spec->flow_context.flow_tag = MLX5_FS_DEFAULT_FLOW_TAG; |
|---|
| 430 | 443 | rule = mlx5_add_flow_rules(ft, spec, &flow_act, dst, dst ? 1 : 0); |
|---|
| 431 | 444 | if (IS_ERR(rule)) { |
|---|
| 432 | 445 | err = PTR_ERR(rule); |
|---|
| .. | .. |
|---|
| 508 | 521 | if (l4_mask->tos) |
|---|
| 509 | 522 | return -EINVAL; |
|---|
| 510 | 523 | |
|---|
| 511 | | - if (l4_mask->ip4src) { |
|---|
| 512 | | - if (!all_ones(l4_mask->ip4src)) |
|---|
| 513 | | - return -EINVAL; |
|---|
| 524 | + if (l4_mask->ip4src) |
|---|
| 514 | 525 | ntuples++; |
|---|
| 515 | | - } |
|---|
| 516 | | - if (l4_mask->ip4dst) { |
|---|
| 517 | | - if (!all_ones(l4_mask->ip4dst)) |
|---|
| 518 | | - return -EINVAL; |
|---|
| 526 | + if (l4_mask->ip4dst) |
|---|
| 519 | 527 | ntuples++; |
|---|
| 520 | | - } |
|---|
| 521 | | - if (l4_mask->psrc) { |
|---|
| 522 | | - if (!all_ones(l4_mask->psrc)) |
|---|
| 523 | | - return -EINVAL; |
|---|
| 528 | + if (l4_mask->psrc) |
|---|
| 524 | 529 | ntuples++; |
|---|
| 525 | | - } |
|---|
| 526 | | - if (l4_mask->pdst) { |
|---|
| 527 | | - if (!all_ones(l4_mask->pdst)) |
|---|
| 528 | | - return -EINVAL; |
|---|
| 530 | + if (l4_mask->pdst) |
|---|
| 529 | 531 | ntuples++; |
|---|
| 530 | | - } |
|---|
| 531 | 532 | /* Flow is TCP/UDP */ |
|---|
| 532 | 533 | return ++ntuples; |
|---|
| 533 | 534 | } |
|---|
| .. | .. |
|---|
| 540 | 541 | if (l3_mask->l4_4_bytes || l3_mask->tos || |
|---|
| 541 | 542 | fs->h_u.usr_ip4_spec.ip_ver != ETH_RX_NFC_IP4) |
|---|
| 542 | 543 | return -EINVAL; |
|---|
| 543 | | - if (l3_mask->ip4src) { |
|---|
| 544 | | - if (!all_ones(l3_mask->ip4src)) |
|---|
| 545 | | - return -EINVAL; |
|---|
| 544 | + if (l3_mask->ip4src) |
|---|
| 546 | 545 | ntuples++; |
|---|
| 547 | | - } |
|---|
| 548 | | - if (l3_mask->ip4dst) { |
|---|
| 549 | | - if (!all_ones(l3_mask->ip4dst)) |
|---|
| 550 | | - return -EINVAL; |
|---|
| 546 | + if (l3_mask->ip4dst) |
|---|
| 551 | 547 | ntuples++; |
|---|
| 552 | | - } |
|---|
| 553 | 548 | if (l3_mask->proto) |
|---|
| 554 | 549 | ntuples++; |
|---|
| 555 | 550 | /* Flow is IPv4 */ |
|---|
| .. | .. |
|---|
| 588 | 583 | if (!ipv6_addr_any((struct in6_addr *)l4_mask->ip6dst)) |
|---|
| 589 | 584 | ntuples++; |
|---|
| 590 | 585 | |
|---|
| 591 | | - if (l4_mask->psrc) { |
|---|
| 592 | | - if (!all_ones(l4_mask->psrc)) |
|---|
| 593 | | - return -EINVAL; |
|---|
| 586 | + if (l4_mask->psrc) |
|---|
| 594 | 587 | ntuples++; |
|---|
| 595 | | - } |
|---|
| 596 | | - if (l4_mask->pdst) { |
|---|
| 597 | | - if (!all_ones(l4_mask->pdst)) |
|---|
| 598 | | - return -EINVAL; |
|---|
| 588 | + if (l4_mask->pdst) |
|---|
| 599 | 589 | ntuples++; |
|---|
| 600 | | - } |
|---|
| 601 | 590 | /* Flow is TCP/UDP */ |
|---|
| 602 | 591 | return ++ntuples; |
|---|
| 603 | 592 | } |
|---|
| .. | .. |
|---|
| 624 | 613 | if (fs->location >= MAX_NUM_OF_ETHTOOL_RULES) |
|---|
| 625 | 614 | return -ENOSPC; |
|---|
| 626 | 615 | |
|---|
| 627 | | - if (fs->ring_cookie >= priv->channels.params.num_channels && |
|---|
| 628 | | - fs->ring_cookie != RX_CLS_FLOW_DISC) |
|---|
| 629 | | - return -EINVAL; |
|---|
| 616 | + if (fs->ring_cookie != RX_CLS_FLOW_DISC) |
|---|
| 617 | + if (!mlx5e_qid_validate(priv->profile, &priv->channels.params, |
|---|
| 618 | + fs->ring_cookie)) |
|---|
| 619 | + return -EINVAL; |
|---|
| 630 | 620 | |
|---|
| 631 | 621 | switch (fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) { |
|---|
| 632 | 622 | case ETHER_FLOW: |
|---|
| .. | .. |
|---|
| 795 | 785 | INIT_LIST_HEAD(&priv->fs.ethtool.rules); |
|---|
| 796 | 786 | } |
|---|
| 797 | 787 | |
|---|
| 798 | | -int mlx5e_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) |
|---|
| 788 | +static enum mlx5e_traffic_types flow_type_to_traffic_type(u32 flow_type) |
|---|
| 799 | 789 | { |
|---|
| 800 | | - int err = 0; |
|---|
| 790 | + switch (flow_type) { |
|---|
| 791 | + case TCP_V4_FLOW: |
|---|
| 792 | + return MLX5E_TT_IPV4_TCP; |
|---|
| 793 | + case TCP_V6_FLOW: |
|---|
| 794 | + return MLX5E_TT_IPV6_TCP; |
|---|
| 795 | + case UDP_V4_FLOW: |
|---|
| 796 | + return MLX5E_TT_IPV4_UDP; |
|---|
| 797 | + case UDP_V6_FLOW: |
|---|
| 798 | + return MLX5E_TT_IPV6_UDP; |
|---|
| 799 | + case AH_V4_FLOW: |
|---|
| 800 | + return MLX5E_TT_IPV4_IPSEC_AH; |
|---|
| 801 | + case AH_V6_FLOW: |
|---|
| 802 | + return MLX5E_TT_IPV6_IPSEC_AH; |
|---|
| 803 | + case ESP_V4_FLOW: |
|---|
| 804 | + return MLX5E_TT_IPV4_IPSEC_ESP; |
|---|
| 805 | + case ESP_V6_FLOW: |
|---|
| 806 | + return MLX5E_TT_IPV6_IPSEC_ESP; |
|---|
| 807 | + case IPV4_FLOW: |
|---|
| 808 | + return MLX5E_TT_IPV4; |
|---|
| 809 | + case IPV6_FLOW: |
|---|
| 810 | + return MLX5E_TT_IPV6; |
|---|
| 811 | + default: |
|---|
| 812 | + return MLX5E_NUM_INDIR_TIRS; |
|---|
| 813 | + } |
|---|
| 814 | +} |
|---|
| 815 | + |
|---|
| 816 | +static int mlx5e_set_rss_hash_opt(struct mlx5e_priv *priv, |
|---|
| 817 | + struct ethtool_rxnfc *nfc) |
|---|
| 818 | +{ |
|---|
| 819 | + int inlen = MLX5_ST_SZ_BYTES(modify_tir_in); |
|---|
| 820 | + enum mlx5e_traffic_types tt; |
|---|
| 821 | + u8 rx_hash_field = 0; |
|---|
| 822 | + void *in; |
|---|
| 823 | + |
|---|
| 824 | + tt = flow_type_to_traffic_type(nfc->flow_type); |
|---|
| 825 | + if (tt == MLX5E_NUM_INDIR_TIRS) |
|---|
| 826 | + return -EINVAL; |
|---|
| 827 | + |
|---|
| 828 | + /* RSS does not support anything other than hashing to queues |
|---|
| 829 | + * on src IP, dest IP, TCP/UDP src port and TCP/UDP dest |
|---|
| 830 | + * port. |
|---|
| 831 | + */ |
|---|
| 832 | + if (nfc->flow_type != TCP_V4_FLOW && |
|---|
| 833 | + nfc->flow_type != TCP_V6_FLOW && |
|---|
| 834 | + nfc->flow_type != UDP_V4_FLOW && |
|---|
| 835 | + nfc->flow_type != UDP_V6_FLOW) |
|---|
| 836 | + return -EOPNOTSUPP; |
|---|
| 837 | + |
|---|
| 838 | + if (nfc->data & ~(RXH_IP_SRC | RXH_IP_DST | |
|---|
| 839 | + RXH_L4_B_0_1 | RXH_L4_B_2_3)) |
|---|
| 840 | + return -EOPNOTSUPP; |
|---|
| 841 | + |
|---|
| 842 | + if (nfc->data & RXH_IP_SRC) |
|---|
| 843 | + rx_hash_field |= MLX5_HASH_FIELD_SEL_SRC_IP; |
|---|
| 844 | + if (nfc->data & RXH_IP_DST) |
|---|
| 845 | + rx_hash_field |= MLX5_HASH_FIELD_SEL_DST_IP; |
|---|
| 846 | + if (nfc->data & RXH_L4_B_0_1) |
|---|
| 847 | + rx_hash_field |= MLX5_HASH_FIELD_SEL_L4_SPORT; |
|---|
| 848 | + if (nfc->data & RXH_L4_B_2_3) |
|---|
| 849 | + rx_hash_field |= MLX5_HASH_FIELD_SEL_L4_DPORT; |
|---|
| 850 | + |
|---|
| 851 | + in = kvzalloc(inlen, GFP_KERNEL); |
|---|
| 852 | + if (!in) |
|---|
| 853 | + return -ENOMEM; |
|---|
| 854 | + |
|---|
| 855 | + mutex_lock(&priv->state_lock); |
|---|
| 856 | + |
|---|
| 857 | + if (rx_hash_field == priv->rss_params.rx_hash_fields[tt]) |
|---|
| 858 | + goto out; |
|---|
| 859 | + |
|---|
| 860 | + priv->rss_params.rx_hash_fields[tt] = rx_hash_field; |
|---|
| 861 | + mlx5e_modify_tirs_hash(priv, in); |
|---|
| 862 | + |
|---|
| 863 | +out: |
|---|
| 864 | + mutex_unlock(&priv->state_lock); |
|---|
| 865 | + kvfree(in); |
|---|
| 866 | + return 0; |
|---|
| 867 | +} |
|---|
| 868 | + |
|---|
| 869 | +static int mlx5e_get_rss_hash_opt(struct mlx5e_priv *priv, |
|---|
| 870 | + struct ethtool_rxnfc *nfc) |
|---|
| 871 | +{ |
|---|
| 872 | + enum mlx5e_traffic_types tt; |
|---|
| 873 | + u32 hash_field = 0; |
|---|
| 874 | + |
|---|
| 875 | + tt = flow_type_to_traffic_type(nfc->flow_type); |
|---|
| 876 | + if (tt == MLX5E_NUM_INDIR_TIRS) |
|---|
| 877 | + return -EINVAL; |
|---|
| 878 | + |
|---|
| 879 | + hash_field = priv->rss_params.rx_hash_fields[tt]; |
|---|
| 880 | + nfc->data = 0; |
|---|
| 881 | + |
|---|
| 882 | + if (hash_field & MLX5_HASH_FIELD_SEL_SRC_IP) |
|---|
| 883 | + nfc->data |= RXH_IP_SRC; |
|---|
| 884 | + if (hash_field & MLX5_HASH_FIELD_SEL_DST_IP) |
|---|
| 885 | + nfc->data |= RXH_IP_DST; |
|---|
| 886 | + if (hash_field & MLX5_HASH_FIELD_SEL_L4_SPORT) |
|---|
| 887 | + nfc->data |= RXH_L4_B_0_1; |
|---|
| 888 | + if (hash_field & MLX5_HASH_FIELD_SEL_L4_DPORT) |
|---|
| 889 | + nfc->data |= RXH_L4_B_2_3; |
|---|
| 890 | + |
|---|
| 891 | + return 0; |
|---|
| 892 | +} |
|---|
| 893 | + |
|---|
| 894 | +int mlx5e_ethtool_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) |
|---|
| 895 | +{ |
|---|
| 801 | 896 | struct mlx5e_priv *priv = netdev_priv(dev); |
|---|
| 897 | + int err = 0; |
|---|
| 802 | 898 | |
|---|
| 803 | 899 | switch (cmd->cmd) { |
|---|
| 804 | 900 | case ETHTOOL_SRXCLSRLINS: |
|---|
| .. | .. |
|---|
| 806 | 902 | break; |
|---|
| 807 | 903 | case ETHTOOL_SRXCLSRLDEL: |
|---|
| 808 | 904 | err = mlx5e_ethtool_flow_remove(priv, cmd->fs.location); |
|---|
| 905 | + break; |
|---|
| 906 | + case ETHTOOL_SRXFH: |
|---|
| 907 | + err = mlx5e_set_rss_hash_opt(priv, cmd); |
|---|
| 809 | 908 | break; |
|---|
| 810 | 909 | default: |
|---|
| 811 | 910 | err = -EOPNOTSUPP; |
|---|
| .. | .. |
|---|
| 815 | 914 | return err; |
|---|
| 816 | 915 | } |
|---|
| 817 | 916 | |
|---|
| 818 | | -int mlx5e_get_rxnfc(struct net_device *dev, |
|---|
| 819 | | - struct ethtool_rxnfc *info, u32 *rule_locs) |
|---|
| 917 | +int mlx5e_ethtool_get_rxnfc(struct net_device *dev, |
|---|
| 918 | + struct ethtool_rxnfc *info, u32 *rule_locs) |
|---|
| 820 | 919 | { |
|---|
| 821 | 920 | struct mlx5e_priv *priv = netdev_priv(dev); |
|---|
| 822 | 921 | int err = 0; |
|---|
| 823 | 922 | |
|---|
| 824 | 923 | switch (info->cmd) { |
|---|
| 825 | | - case ETHTOOL_GRXRINGS: |
|---|
| 826 | | - info->data = priv->channels.params.num_channels; |
|---|
| 827 | | - break; |
|---|
| 828 | 924 | case ETHTOOL_GRXCLSRLCNT: |
|---|
| 829 | 925 | info->rule_cnt = priv->fs.ethtool.tot_num_rules; |
|---|
| 830 | 926 | break; |
|---|
| .. | .. |
|---|
| 834 | 930 | case ETHTOOL_GRXCLSRLALL: |
|---|
| 835 | 931 | err = mlx5e_ethtool_get_all_flows(priv, info, rule_locs); |
|---|
| 836 | 932 | break; |
|---|
| 933 | + case ETHTOOL_GRXFH: |
|---|
| 934 | + err = mlx5e_get_rss_hash_opt(priv, info); |
|---|
| 935 | + break; |
|---|
| 837 | 936 | default: |
|---|
| 838 | 937 | err = -EOPNOTSUPP; |
|---|
| 839 | 938 | break; |
|---|