aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/sfc
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2012-01-03 07:05:47 -0500
committerDavid S. Miller <davem@davemloft.net>2012-01-04 14:10:18 -0500
commitb2bb7b776a9b16508641a0854642d9737d7621eb (patch)
treefed1d91b3981dbf5dc2977fcb5d6dd1705cb6a59 /drivers/net/ethernet/sfc
parent1a6281ac5cf7285cbc2b1f9725dcf1a2461eac83 (diff)
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>
Diffstat (limited to 'drivers/net/ethernet/sfc')
-rw-r--r--drivers/net/ethernet/sfc/ethtool.c188
1 files changed, 149 insertions, 39 deletions
diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c
index 1be51b2bfa42..29b2ebfef19f 100644
--- a/drivers/net/ethernet/sfc/ethtool.c
+++ b/drivers/net/ethernet/sfc/ethtool.c
@@ -818,9 +818,58 @@ static int efx_ethtool_reset(struct net_device *net_dev, u32 *flags)
818 return efx_reset(efx, rc); 818 return efx_reset(efx, rc);
819} 819}
820 820
821static 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
821static int 870static int
822efx_ethtool_get_rxnfc(struct net_device *net_dev, 871efx_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 struct efx_nic *efx = netdev_priv(net_dev); 874 struct efx_nic *efx = netdev_priv(net_dev);
826 875
@@ -862,42 +911,80 @@ efx_ethtool_get_rxnfc(struct net_device *net_dev,
862 return 0; 911 return 0;
863 } 912 }
864 913
914 case ETHTOOL_GRXCLSRLCNT:
915 info->data = efx_filter_get_rx_id_limit(efx);
916 if (info->data == 0)
917 return -EOPNOTSUPP;
918 info->data |= RX_CLS_LOC_SPECIAL;
919 info->rule_cnt =
920 efx_filter_count_rx_used(efx, EFX_FILTER_PRI_MANUAL);
921 return 0;
922
923 case ETHTOOL_GRXCLSRULE:
924 if (efx_filter_get_rx_id_limit(efx) == 0)
925 return -EOPNOTSUPP;
926 return efx_ethtool_get_class_rule(efx, &info->fs);
927
928 case ETHTOOL_GRXCLSRLALL: {
929 s32 rc;
930 info->data = efx_filter_get_rx_id_limit(efx);
931 if (info->data == 0)
932 return -EOPNOTSUPP;
933 rc = efx_filter_get_rx_ids(efx, EFX_FILTER_PRI_MANUAL,
934 rule_locs, info->rule_cnt);
935 if (rc < 0)
936 return rc;
937 info->rule_cnt = rc;
938 return 0;
939 }
940
865 default: 941 default:
866 return -EOPNOTSUPP; 942 return -EOPNOTSUPP;
867 } 943 }
868} 944}
869 945
870static int efx_ethtool_set_rx_ntuple(struct net_device *net_dev, 946static int efx_ethtool_set_class_rule(struct efx_nic *efx,
871 struct ethtool_rx_ntuple *ntuple) 947 struct ethtool_rx_flow_spec *rule)
872{ 948{
873 struct efx_nic *efx = netdev_priv(net_dev); 949 struct ethtool_tcpip4_spec *ip_entry = &rule->h_u.tcp_ip4_spec;
874 struct ethtool_tcpip4_spec *ip_entry = &ntuple->fs.h_u.tcp_ip4_spec; 950 struct ethtool_tcpip4_spec *ip_mask = &rule->m_u.tcp_ip4_spec;
875 struct ethtool_tcpip4_spec *ip_mask = &ntuple->fs.m_u.tcp_ip4_spec; 951 struct ethhdr *mac_entry = &rule->h_u.ether_spec;
876 struct ethhdr *mac_entry = &ntuple->fs.h_u.ether_spec; 952 struct ethhdr *mac_mask = &rule->m_u.ether_spec;
877 struct ethhdr *mac_mask = &ntuple->fs.m_u.ether_spec; 953 struct efx_filter_spec spec;
878 struct efx_filter_spec filter;
879 int rc; 954 int rc;
880 955
881 /* Range-check action */ 956 /* Check that user wants us to choose the location */
882 if (ntuple->fs.action < ETHTOOL_RXNTUPLE_ACTION_CLEAR || 957 if (rule->location != RX_CLS_LOC_ANY &&
883 ntuple->fs.action >= (s32)efx->n_rx_channels) 958 rule->location != RX_CLS_LOC_FIRST &&
959 rule->location != RX_CLS_LOC_LAST)
884 return -EINVAL; 960 return -EINVAL;
885 961
886 if (~ntuple->fs.data_mask) 962 /* Range-check ring_cookie */
963 if (rule->ring_cookie >= efx->n_rx_channels &&
964 rule->ring_cookie != RX_CLS_FLOW_DISC)
887 return -EINVAL; 965 return -EINVAL;
888 966
889 efx_filter_init_rx(&filter, EFX_FILTER_PRI_MANUAL, 0, 967 /* Check for unsupported extensions */
890 (ntuple->fs.action == ETHTOOL_RXNTUPLE_ACTION_DROP) ? 968 if ((rule->flow_type & FLOW_EXT) &&
891 0xfff : ntuple->fs.action); 969 (rule->m_ext.vlan_etype | rule->m_ext.data[0] |
970 rule->m_ext.data[1]))
971 return -EINVAL;
972
973 efx_filter_init_rx(&spec, EFX_FILTER_PRI_MANUAL,
974 (rule->location == RX_CLS_LOC_FIRST) ?
975 EFX_FILTER_FLAG_RX_OVERRIDE_IP : 0,
976 (rule->ring_cookie == RX_CLS_FLOW_DISC) ?
977 0xfff : rule->ring_cookie);
892 978
893 switch (ntuple->fs.flow_type) { 979 switch (rule->flow_type) {
894 case TCP_V4_FLOW: 980 case TCP_V4_FLOW:
895 case UDP_V4_FLOW: { 981 case UDP_V4_FLOW: {
896 u8 proto = (ntuple->fs.flow_type == TCP_V4_FLOW ? 982 u8 proto = (rule->flow_type == TCP_V4_FLOW ?
897 IPPROTO_TCP : IPPROTO_UDP); 983 IPPROTO_TCP : IPPROTO_UDP);
898 984
899 /* Must match all of destination, */ 985 /* Must match all of destination, */
900 if (ip_mask->ip4dst | ip_mask->pdst) 986 if ((__force u32)~ip_mask->ip4dst |
987 (__force u16)~ip_mask->pdst)
901 return -EINVAL; 988 return -EINVAL;
902 /* all or none of source, */ 989 /* all or none of source, */
903 if ((ip_mask->ip4src | ip_mask->psrc) && 990 if ((ip_mask->ip4src | ip_mask->psrc) &&
@@ -905,17 +992,17 @@ static int efx_ethtool_set_rx_ntuple(struct net_device *net_dev,
905 (__force u16)~ip_mask->psrc)) 992 (__force u16)~ip_mask->psrc))
906 return -EINVAL; 993 return -EINVAL;
907 /* and nothing else */ 994 /* and nothing else */
908 if ((u8)~ip_mask->tos | (u16)~ntuple->fs.vlan_tag_mask) 995 if (ip_mask->tos | rule->m_ext.vlan_tci)
909 return -EINVAL; 996 return -EINVAL;
910 997
911 if (!ip_mask->ip4src) 998 if (ip_mask->ip4src)
912 rc = efx_filter_set_ipv4_full(&filter, proto, 999 rc = efx_filter_set_ipv4_full(&spec, proto,
913 ip_entry->ip4dst, 1000 ip_entry->ip4dst,
914 ip_entry->pdst, 1001 ip_entry->pdst,
915 ip_entry->ip4src, 1002 ip_entry->ip4src,
916 ip_entry->psrc); 1003 ip_entry->psrc);
917 else 1004 else
918 rc = efx_filter_set_ipv4_local(&filter, proto, 1005 rc = efx_filter_set_ipv4_local(&spec, proto,
919 ip_entry->ip4dst, 1006 ip_entry->ip4dst,
920 ip_entry->pdst); 1007 ip_entry->pdst);
921 if (rc) 1008 if (rc)
@@ -923,23 +1010,24 @@ static int efx_ethtool_set_rx_ntuple(struct net_device *net_dev,
923 break; 1010 break;
924 } 1011 }
925 1012
926 case ETHER_FLOW: 1013 case ETHER_FLOW | FLOW_EXT:
927 /* Must match all of destination, */ 1014 /* Must match all or none of VID */
928 if (!is_zero_ether_addr(mac_mask->h_dest)) 1015 if (rule->m_ext.vlan_tci != htons(0xfff) &&
1016 rule->m_ext.vlan_tci != 0)
929 return -EINVAL; 1017 return -EINVAL;
930 /* all or none of VID, */ 1018 case ETHER_FLOW:
931 if (ntuple->fs.vlan_tag_mask != 0xf000 && 1019 /* Must match all of destination */
932 ntuple->fs.vlan_tag_mask != 0xffff) 1020 if (!is_broadcast_ether_addr(mac_mask->h_dest))
933 return -EINVAL; 1021 return -EINVAL;
934 /* and nothing else */ 1022 /* and nothing else */
935 if (!is_broadcast_ether_addr(mac_mask->h_source) || 1023 if (!is_zero_ether_addr(mac_mask->h_source) ||
936 mac_mask->h_proto != htons(0xffff)) 1024 mac_mask->h_proto)
937 return -EINVAL; 1025 return -EINVAL;
938 1026
939 rc = efx_filter_set_eth_local( 1027 rc = efx_filter_set_eth_local(
940 &filter, 1028 &spec,
941 (ntuple->fs.vlan_tag_mask == 0xf000) ? 1029 (rule->flow_type & FLOW_EXT && rule->m_ext.vlan_tci) ?
942 ntuple->fs.vlan_tag : EFX_FILTER_VID_UNSPEC, 1030 ntohs(rule->h_ext.vlan_tci) : EFX_FILTER_VID_UNSPEC,
943 mac_entry->h_dest); 1031 mac_entry->h_dest);
944 if (rc) 1032 if (rc)
945 return rc; 1033 return rc;
@@ -949,11 +1037,33 @@ static int efx_ethtool_set_rx_ntuple(struct net_device *net_dev,
949 return -EINVAL; 1037 return -EINVAL;
950 } 1038 }
951 1039
952 if (ntuple->fs.action == ETHTOOL_RXNTUPLE_ACTION_CLEAR) 1040 rc = efx_filter_insert_filter(efx, &spec, true);
953 return efx_filter_remove_filter(efx, &filter); 1041 if (rc < 0)
1042 return rc;
954 1043
955 rc = efx_filter_insert_filter(efx, &filter, true); 1044 rule->location = rc;
956 return rc < 0 ? rc : 0; 1045 return 0;
1046}
1047
1048static int efx_ethtool_set_rxnfc(struct net_device *net_dev,
1049 struct ethtool_rxnfc *info)
1050{
1051 struct efx_nic *efx = netdev_priv(net_dev);
1052
1053 if (efx_filter_get_rx_id_limit(efx) == 0)
1054 return -EOPNOTSUPP;
1055
1056 switch (info->cmd) {
1057 case ETHTOOL_SRXCLSRLINS:
1058 return efx_ethtool_set_class_rule(efx, &info->fs);
1059
1060 case ETHTOOL_SRXCLSRLDEL:
1061 return efx_filter_remove_id_safe(efx, EFX_FILTER_PRI_MANUAL,
1062 info->fs.location);
1063
1064 default:
1065 return -EOPNOTSUPP;
1066 }
957} 1067}
958 1068
959static u32 efx_ethtool_get_rxfh_indir_size(struct net_device *net_dev) 1069static u32 efx_ethtool_get_rxfh_indir_size(struct net_device *net_dev)
@@ -1007,7 +1117,7 @@ const struct ethtool_ops efx_ethtool_ops = {
1007 .set_wol = efx_ethtool_set_wol, 1117 .set_wol = efx_ethtool_set_wol,
1008 .reset = efx_ethtool_reset, 1118 .reset = efx_ethtool_reset,
1009 .get_rxnfc = efx_ethtool_get_rxnfc, 1119 .get_rxnfc = efx_ethtool_get_rxnfc,
1010 .set_rx_ntuple = efx_ethtool_set_rx_ntuple, 1120 .set_rxnfc = efx_ethtool_set_rxnfc,
1011 .get_rxfh_indir_size = efx_ethtool_get_rxfh_indir_size, 1121 .get_rxfh_indir_size = efx_ethtool_get_rxfh_indir_size,
1012 .get_rxfh_indir = efx_ethtool_get_rxfh_indir, 1122 .get_rxfh_indir = efx_ethtool_get_rxfh_indir,
1013 .set_rxfh_indir = efx_ethtool_set_rxfh_indir, 1123 .set_rxfh_indir = efx_ethtool_set_rxfh_indir,