|
@@ -2336,6 +2336,97 @@ static int ixgbe_set_flags(struct net_device *netdev, u32 data)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int ixgbe_get_ethtool_fdir_entry(struct ixgbe_adapter *adapter,
|
|
|
+ struct ethtool_rxnfc *cmd)
|
|
|
+{
|
|
|
+ union ixgbe_atr_input *mask = &adapter->fdir_mask;
|
|
|
+ struct ethtool_rx_flow_spec *fsp =
|
|
|
+ (struct ethtool_rx_flow_spec *)&cmd->fs;
|
|
|
+ struct hlist_node *node, *node2;
|
|
|
+ struct ixgbe_fdir_filter *rule = NULL;
|
|
|
+
|
|
|
+ /* report total rule count */
|
|
|
+ cmd->data = (1024 << adapter->fdir_pballoc) - 2;
|
|
|
+
|
|
|
+ hlist_for_each_entry_safe(rule, node, node2,
|
|
|
+ &adapter->fdir_filter_list, fdir_node) {
|
|
|
+ if (fsp->location <= rule->sw_idx)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!rule || fsp->location != rule->sw_idx)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ /* fill out the flow spec entry */
|
|
|
+
|
|
|
+ /* set flow type field */
|
|
|
+ switch (rule->filter.formatted.flow_type) {
|
|
|
+ case IXGBE_ATR_FLOW_TYPE_TCPV4:
|
|
|
+ fsp->flow_type = TCP_V4_FLOW;
|
|
|
+ break;
|
|
|
+ case IXGBE_ATR_FLOW_TYPE_UDPV4:
|
|
|
+ fsp->flow_type = UDP_V4_FLOW;
|
|
|
+ break;
|
|
|
+ case IXGBE_ATR_FLOW_TYPE_SCTPV4:
|
|
|
+ fsp->flow_type = SCTP_V4_FLOW;
|
|
|
+ break;
|
|
|
+ case IXGBE_ATR_FLOW_TYPE_IPV4:
|
|
|
+ fsp->flow_type = IP_USER_FLOW;
|
|
|
+ fsp->h_u.usr_ip4_spec.ip_ver = ETH_RX_NFC_IP4;
|
|
|
+ fsp->h_u.usr_ip4_spec.proto = 0;
|
|
|
+ fsp->m_u.usr_ip4_spec.proto = 0;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ fsp->h_u.tcp_ip4_spec.psrc = rule->filter.formatted.src_port;
|
|
|
+ fsp->m_u.tcp_ip4_spec.psrc = mask->formatted.src_port;
|
|
|
+ fsp->h_u.tcp_ip4_spec.pdst = rule->filter.formatted.dst_port;
|
|
|
+ fsp->m_u.tcp_ip4_spec.pdst = mask->formatted.dst_port;
|
|
|
+ fsp->h_u.tcp_ip4_spec.ip4src = rule->filter.formatted.src_ip[0];
|
|
|
+ fsp->m_u.tcp_ip4_spec.ip4src = mask->formatted.src_ip[0];
|
|
|
+ fsp->h_u.tcp_ip4_spec.ip4dst = rule->filter.formatted.dst_ip[0];
|
|
|
+ fsp->m_u.tcp_ip4_spec.ip4dst = mask->formatted.dst_ip[0];
|
|
|
+ fsp->h_ext.vlan_tci = rule->filter.formatted.vlan_id;
|
|
|
+ fsp->m_ext.vlan_tci = mask->formatted.vlan_id;
|
|
|
+ fsp->h_ext.vlan_etype = rule->filter.formatted.flex_bytes;
|
|
|
+ fsp->m_ext.vlan_etype = mask->formatted.flex_bytes;
|
|
|
+ fsp->h_ext.data[1] = htonl(rule->filter.formatted.vm_pool);
|
|
|
+ fsp->m_ext.data[1] = htonl(mask->formatted.vm_pool);
|
|
|
+ fsp->flow_type |= FLOW_EXT;
|
|
|
+
|
|
|
+ /* record action */
|
|
|
+ if (rule->action == IXGBE_FDIR_DROP_QUEUE)
|
|
|
+ fsp->ring_cookie = RX_CLS_FLOW_DISC;
|
|
|
+ else
|
|
|
+ fsp->ring_cookie = rule->action;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int ixgbe_get_ethtool_fdir_all(struct ixgbe_adapter *adapter,
|
|
|
+ struct ethtool_rxnfc *cmd,
|
|
|
+ u32 *rule_locs)
|
|
|
+{
|
|
|
+ struct hlist_node *node, *node2;
|
|
|
+ struct ixgbe_fdir_filter *rule;
|
|
|
+ int cnt = 0;
|
|
|
+
|
|
|
+ /* report total rule count */
|
|
|
+ cmd->data = (1024 << adapter->fdir_pballoc) - 2;
|
|
|
+
|
|
|
+ hlist_for_each_entry_safe(rule, node, node2,
|
|
|
+ &adapter->fdir_filter_list, fdir_node) {
|
|
|
+ if (cnt == cmd->rule_cnt)
|
|
|
+ return -EMSGSIZE;
|
|
|
+ rule_locs[cnt] = rule->sw_idx;
|
|
|
+ cnt++;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int ixgbe_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
|
|
|
void *rule_locs)
|
|
|
{
|
|
@@ -2347,6 +2438,17 @@ static int ixgbe_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
|
|
|
cmd->data = adapter->num_rx_queues;
|
|
|
ret = 0;
|
|
|
break;
|
|
|
+ case ETHTOOL_GRXCLSRLCNT:
|
|
|
+ cmd->rule_cnt = adapter->fdir_filter_count;
|
|
|
+ ret = 0;
|
|
|
+ break;
|
|
|
+ case ETHTOOL_GRXCLSRULE:
|
|
|
+ ret = ixgbe_get_ethtool_fdir_entry(adapter, cmd);
|
|
|
+ break;
|
|
|
+ case ETHTOOL_GRXCLSRLALL:
|
|
|
+ ret = ixgbe_get_ethtool_fdir_all(adapter, cmd,
|
|
|
+ (u32 *)rule_locs);
|
|
|
+ break;
|
|
|
default:
|
|
|
break;
|
|
|
}
|