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

sfc: Implement ethtool RX NFC rules API instead of n-tuple API

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Ben Hutchings and committed by
David S. Miller
b2bb7b77 1a6281ac

+149 -39
+149 -39
drivers/net/ethernet/sfc/ethtool.c
··· 818 818 return efx_reset(efx, rc); 819 819 } 820 820 821 + static int efx_ethtool_get_class_rule(struct efx_nic *efx, 822 + struct ethtool_rx_flow_spec *rule) 823 + { 824 + struct ethtool_tcpip4_spec *ip_entry = &rule->h_u.tcp_ip4_spec; 825 + struct ethtool_tcpip4_spec *ip_mask = &rule->m_u.tcp_ip4_spec; 826 + struct efx_filter_spec spec; 827 + u16 vid; 828 + u8 proto; 829 + int rc; 830 + 831 + rc = efx_filter_get_filter_safe(efx, EFX_FILTER_PRI_MANUAL, 832 + rule->location, &spec); 833 + if (rc) 834 + return rc; 835 + 836 + if (spec.dmaq_id == 0xfff) 837 + rule->ring_cookie = RX_CLS_FLOW_DISC; 838 + else 839 + rule->ring_cookie = spec.dmaq_id; 840 + 841 + rc = efx_filter_get_eth_local(&spec, &vid, 842 + rule->h_u.ether_spec.h_dest); 843 + if (rc == 0) { 844 + rule->flow_type = ETHER_FLOW; 845 + memset(rule->m_u.ether_spec.h_dest, ~0, ETH_ALEN); 846 + if (vid != EFX_FILTER_VID_UNSPEC) { 847 + rule->flow_type |= FLOW_EXT; 848 + rule->h_ext.vlan_tci = htons(vid); 849 + rule->m_ext.vlan_tci = htons(0xfff); 850 + } 851 + return 0; 852 + } 853 + 854 + rc = efx_filter_get_ipv4_local(&spec, &proto, 855 + &ip_entry->ip4dst, &ip_entry->pdst); 856 + if (rc != 0) { 857 + rc = efx_filter_get_ipv4_full( 858 + &spec, &proto, &ip_entry->ip4src, &ip_entry->psrc, 859 + &ip_entry->ip4dst, &ip_entry->pdst); 860 + EFX_WARN_ON_PARANOID(rc); 861 + ip_mask->ip4src = ~0; 862 + ip_mask->psrc = ~0; 863 + } 864 + rule->flow_type = (proto == IPPROTO_TCP) ? TCP_V4_FLOW : UDP_V4_FLOW; 865 + ip_mask->ip4dst = ~0; 866 + ip_mask->pdst = ~0; 867 + return rc; 868 + } 869 + 821 870 static int 822 871 efx_ethtool_get_rxnfc(struct net_device *net_dev, 823 - struct ethtool_rxnfc *info, u32 *rules __always_unused) 872 + struct ethtool_rxnfc *info, u32 *rule_locs) 824 873 { 825 874 struct efx_nic *efx = netdev_priv(net_dev); 826 875 ··· 911 862 return 0; 912 863 } 913 864 865 + case ETHTOOL_GRXCLSRLCNT: 866 + info->data = efx_filter_get_rx_id_limit(efx); 867 + if (info->data == 0) 868 + return -EOPNOTSUPP; 869 + info->data |= RX_CLS_LOC_SPECIAL; 870 + info->rule_cnt = 871 + efx_filter_count_rx_used(efx, EFX_FILTER_PRI_MANUAL); 872 + return 0; 873 + 874 + case ETHTOOL_GRXCLSRULE: 875 + if (efx_filter_get_rx_id_limit(efx) == 0) 876 + return -EOPNOTSUPP; 877 + return efx_ethtool_get_class_rule(efx, &info->fs); 878 + 879 + case ETHTOOL_GRXCLSRLALL: { 880 + s32 rc; 881 + info->data = efx_filter_get_rx_id_limit(efx); 882 + if (info->data == 0) 883 + return -EOPNOTSUPP; 884 + rc = efx_filter_get_rx_ids(efx, EFX_FILTER_PRI_MANUAL, 885 + rule_locs, info->rule_cnt); 886 + if (rc < 0) 887 + return rc; 888 + info->rule_cnt = rc; 889 + return 0; 890 + } 891 + 914 892 default: 915 893 return -EOPNOTSUPP; 916 894 } 917 895 } 918 896 919 - static int efx_ethtool_set_rx_ntuple(struct net_device *net_dev, 920 - struct ethtool_rx_ntuple *ntuple) 897 + static int efx_ethtool_set_class_rule(struct efx_nic *efx, 898 + struct ethtool_rx_flow_spec *rule) 921 899 { 922 - struct efx_nic *efx = netdev_priv(net_dev); 923 - struct ethtool_tcpip4_spec *ip_entry = &ntuple->fs.h_u.tcp_ip4_spec; 924 - struct ethtool_tcpip4_spec *ip_mask = &ntuple->fs.m_u.tcp_ip4_spec; 925 - struct ethhdr *mac_entry = &ntuple->fs.h_u.ether_spec; 926 - struct ethhdr *mac_mask = &ntuple->fs.m_u.ether_spec; 927 - struct efx_filter_spec filter; 900 + struct ethtool_tcpip4_spec *ip_entry = &rule->h_u.tcp_ip4_spec; 901 + struct ethtool_tcpip4_spec *ip_mask = &rule->m_u.tcp_ip4_spec; 902 + struct ethhdr *mac_entry = &rule->h_u.ether_spec; 903 + struct ethhdr *mac_mask = &rule->m_u.ether_spec; 904 + struct efx_filter_spec spec; 928 905 int rc; 929 906 930 - /* Range-check action */ 931 - if (ntuple->fs.action < ETHTOOL_RXNTUPLE_ACTION_CLEAR || 932 - ntuple->fs.action >= (s32)efx->n_rx_channels) 907 + /* Check that user wants us to choose the location */ 908 + if (rule->location != RX_CLS_LOC_ANY && 909 + rule->location != RX_CLS_LOC_FIRST && 910 + rule->location != RX_CLS_LOC_LAST) 933 911 return -EINVAL; 934 912 935 - if (~ntuple->fs.data_mask) 913 + /* Range-check ring_cookie */ 914 + if (rule->ring_cookie >= efx->n_rx_channels && 915 + rule->ring_cookie != RX_CLS_FLOW_DISC) 936 916 return -EINVAL; 937 917 938 - efx_filter_init_rx(&filter, EFX_FILTER_PRI_MANUAL, 0, 939 - (ntuple->fs.action == ETHTOOL_RXNTUPLE_ACTION_DROP) ? 940 - 0xfff : ntuple->fs.action); 918 + /* Check for unsupported extensions */ 919 + if ((rule->flow_type & FLOW_EXT) && 920 + (rule->m_ext.vlan_etype | rule->m_ext.data[0] | 921 + rule->m_ext.data[1])) 922 + return -EINVAL; 941 923 942 - switch (ntuple->fs.flow_type) { 924 + efx_filter_init_rx(&spec, EFX_FILTER_PRI_MANUAL, 925 + (rule->location == RX_CLS_LOC_FIRST) ? 926 + EFX_FILTER_FLAG_RX_OVERRIDE_IP : 0, 927 + (rule->ring_cookie == RX_CLS_FLOW_DISC) ? 928 + 0xfff : rule->ring_cookie); 929 + 930 + switch (rule->flow_type) { 943 931 case TCP_V4_FLOW: 944 932 case UDP_V4_FLOW: { 945 - u8 proto = (ntuple->fs.flow_type == TCP_V4_FLOW ? 933 + u8 proto = (rule->flow_type == TCP_V4_FLOW ? 946 934 IPPROTO_TCP : IPPROTO_UDP); 947 935 948 936 /* Must match all of destination, */ 949 - if (ip_mask->ip4dst | ip_mask->pdst) 937 + if ((__force u32)~ip_mask->ip4dst | 938 + (__force u16)~ip_mask->pdst) 950 939 return -EINVAL; 951 940 /* all or none of source, */ 952 941 if ((ip_mask->ip4src | ip_mask->psrc) && ··· 992 905 (__force u16)~ip_mask->psrc)) 993 906 return -EINVAL; 994 907 /* and nothing else */ 995 - if ((u8)~ip_mask->tos | (u16)~ntuple->fs.vlan_tag_mask) 908 + if (ip_mask->tos | rule->m_ext.vlan_tci) 996 909 return -EINVAL; 997 910 998 - if (!ip_mask->ip4src) 999 - rc = efx_filter_set_ipv4_full(&filter, proto, 911 + if (ip_mask->ip4src) 912 + rc = efx_filter_set_ipv4_full(&spec, proto, 1000 913 ip_entry->ip4dst, 1001 914 ip_entry->pdst, 1002 915 ip_entry->ip4src, 1003 916 ip_entry->psrc); 1004 917 else 1005 - rc = efx_filter_set_ipv4_local(&filter, proto, 918 + rc = efx_filter_set_ipv4_local(&spec, proto, 1006 919 ip_entry->ip4dst, 1007 920 ip_entry->pdst); 1008 921 if (rc) ··· 1010 923 break; 1011 924 } 1012 925 1013 - case ETHER_FLOW: 1014 - /* Must match all of destination, */ 1015 - if (!is_zero_ether_addr(mac_mask->h_dest)) 926 + case ETHER_FLOW | FLOW_EXT: 927 + /* Must match all or none of VID */ 928 + if (rule->m_ext.vlan_tci != htons(0xfff) && 929 + rule->m_ext.vlan_tci != 0) 1016 930 return -EINVAL; 1017 - /* all or none of VID, */ 1018 - if (ntuple->fs.vlan_tag_mask != 0xf000 && 1019 - ntuple->fs.vlan_tag_mask != 0xffff) 931 + case ETHER_FLOW: 932 + /* Must match all of destination */ 933 + if (!is_broadcast_ether_addr(mac_mask->h_dest)) 1020 934 return -EINVAL; 1021 935 /* and nothing else */ 1022 - if (!is_broadcast_ether_addr(mac_mask->h_source) || 1023 - mac_mask->h_proto != htons(0xffff)) 936 + if (!is_zero_ether_addr(mac_mask->h_source) || 937 + mac_mask->h_proto) 1024 938 return -EINVAL; 1025 939 1026 940 rc = efx_filter_set_eth_local( 1027 - &filter, 1028 - (ntuple->fs.vlan_tag_mask == 0xf000) ? 1029 - ntuple->fs.vlan_tag : EFX_FILTER_VID_UNSPEC, 941 + &spec, 942 + (rule->flow_type & FLOW_EXT && rule->m_ext.vlan_tci) ? 943 + ntohs(rule->h_ext.vlan_tci) : EFX_FILTER_VID_UNSPEC, 1030 944 mac_entry->h_dest); 1031 945 if (rc) 1032 946 return rc; ··· 1037 949 return -EINVAL; 1038 950 } 1039 951 1040 - if (ntuple->fs.action == ETHTOOL_RXNTUPLE_ACTION_CLEAR) 1041 - return efx_filter_remove_filter(efx, &filter); 952 + rc = efx_filter_insert_filter(efx, &spec, true); 953 + if (rc < 0) 954 + return rc; 1042 955 1043 - rc = efx_filter_insert_filter(efx, &filter, true); 1044 - return rc < 0 ? rc : 0; 956 + rule->location = rc; 957 + return 0; 958 + } 959 + 960 + static int efx_ethtool_set_rxnfc(struct net_device *net_dev, 961 + struct ethtool_rxnfc *info) 962 + { 963 + struct efx_nic *efx = netdev_priv(net_dev); 964 + 965 + if (efx_filter_get_rx_id_limit(efx) == 0) 966 + return -EOPNOTSUPP; 967 + 968 + switch (info->cmd) { 969 + case ETHTOOL_SRXCLSRLINS: 970 + return efx_ethtool_set_class_rule(efx, &info->fs); 971 + 972 + case ETHTOOL_SRXCLSRLDEL: 973 + return efx_filter_remove_id_safe(efx, EFX_FILTER_PRI_MANUAL, 974 + info->fs.location); 975 + 976 + default: 977 + return -EOPNOTSUPP; 978 + } 1045 979 } 1046 980 1047 981 static u32 efx_ethtool_get_rxfh_indir_size(struct net_device *net_dev) ··· 1117 1007 .set_wol = efx_ethtool_set_wol, 1118 1008 .reset = efx_ethtool_reset, 1119 1009 .get_rxnfc = efx_ethtool_get_rxnfc, 1120 - .set_rx_ntuple = efx_ethtool_set_rx_ntuple, 1010 + .set_rxnfc = efx_ethtool_set_rxnfc, 1121 1011 .get_rxfh_indir_size = efx_ethtool_get_rxfh_indir_size, 1122 1012 .get_rxfh_indir = efx_ethtool_get_rxfh_indir, 1123 1013 .set_rxfh_indir = efx_ethtool_set_rxfh_indir,