Skip to content

Commit

Permalink
net/mlx5e: Ethtool steering flow validation refactoring
Browse files Browse the repository at this point in the history
Have a ethtool rx flow spec validation helper function per flow type.

Signed-off-by: Saeed Mahameed <[email protected]>
  • Loading branch information
Saeed Mahameed committed Aug 13, 2018
1 parent 42c625a commit b29c61d
Showing 1 changed file with 100 additions and 64 deletions.
164 changes: 100 additions & 64 deletions drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -379,90 +379,125 @@ static struct mlx5e_ethtool_rule *get_ethtool_rule(struct mlx5e_priv *priv,
#define all_zeros_or_all_ones(field) \
((field) == 0 || (field) == (__force typeof(field))-1)

static int validate_ethter(struct ethtool_rx_flow_spec *fs)
{
struct ethhdr *eth_mask = &fs->m_u.ether_spec;
int ntuples = 0;

if (!is_zero_ether_addr(eth_mask->h_dest))
ntuples++;
if (!is_zero_ether_addr(eth_mask->h_source))
ntuples++;
if (eth_mask->h_proto)
ntuples++;
return ntuples;
}

static int validate_tcpudp4(struct ethtool_rx_flow_spec *fs)
{
struct ethtool_tcpip4_spec *l4_mask = &fs->m_u.tcp_ip4_spec;
int ntuples = 0;

if (l4_mask->tos)
return -EINVAL;

if (l4_mask->ip4src) {
if (!all_ones(l4_mask->ip4src))
return -EINVAL;
ntuples++;
}
if (l4_mask->ip4dst) {
if (!all_ones(l4_mask->ip4dst))
return -EINVAL;
ntuples++;
}
if (l4_mask->psrc) {
if (!all_ones(l4_mask->psrc))
return -EINVAL;
ntuples++;
}
if (l4_mask->pdst) {
if (!all_ones(l4_mask->pdst))
return -EINVAL;
ntuples++;
}
/* Flow is TCP/UDP */
return ++ntuples;
}

static int validate_ip4(struct ethtool_rx_flow_spec *fs)
{
struct ethtool_usrip4_spec *l3_mask = &fs->m_u.usr_ip4_spec;
int ntuples = 0;

if (l3_mask->l4_4_bytes || l3_mask->tos || l3_mask->proto ||
fs->h_u.usr_ip4_spec.ip_ver != ETH_RX_NFC_IP4)
return -EINVAL;
if (l3_mask->ip4src) {
if (!all_ones(l3_mask->ip4src))
return -EINVAL;
ntuples++;
}
if (l3_mask->ip4dst) {
if (!all_ones(l3_mask->ip4dst))
return -EINVAL;
ntuples++;
}
/* Flow is IPv4 */
return ++ntuples;
}

static int validate_vlan(struct ethtool_rx_flow_spec *fs)
{
if (fs->m_ext.vlan_etype ||
fs->m_ext.vlan_tci != cpu_to_be16(VLAN_VID_MASK))
return -EINVAL;

if (fs->m_ext.vlan_tci &&
(be16_to_cpu(fs->h_ext.vlan_tci) >= VLAN_N_VID))
return -EINVAL;

return 1;
}

static int validate_flow(struct mlx5e_priv *priv,
struct ethtool_rx_flow_spec *fs)
{
struct ethtool_tcpip4_spec *l4_mask;
struct ethtool_usrip4_spec *l3_mask;
struct ethhdr *eth_mask;
int num_tuples = 0;
int ret = 0;

if (fs->location >= MAX_NUM_OF_ETHTOOL_RULES)
return -EINVAL;
return -ENOSPC;

if (fs->ring_cookie >= priv->channels.params.num_channels &&
fs->ring_cookie != RX_CLS_FLOW_DISC)
return -EINVAL;

switch (fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) {
case ETHER_FLOW:
eth_mask = &fs->m_u.ether_spec;
if (!is_zero_ether_addr(eth_mask->h_dest))
num_tuples++;
if (!is_zero_ether_addr(eth_mask->h_source))
num_tuples++;
if (eth_mask->h_proto)
num_tuples++;
num_tuples += validate_ethter(fs);
break;
case TCP_V4_FLOW:
case UDP_V4_FLOW:
if (fs->m_u.tcp_ip4_spec.tos)
return -EINVAL;
l4_mask = &fs->m_u.tcp_ip4_spec;
if (l4_mask->ip4src) {
if (!all_ones(l4_mask->ip4src))
return -EINVAL;
num_tuples++;
}
if (l4_mask->ip4dst) {
if (!all_ones(l4_mask->ip4dst))
return -EINVAL;
num_tuples++;
}
if (l4_mask->psrc) {
if (!all_ones(l4_mask->psrc))
return -EINVAL;
num_tuples++;
}
if (l4_mask->pdst) {
if (!all_ones(l4_mask->pdst))
return -EINVAL;
num_tuples++;
}
/* Flow is TCP/UDP */
num_tuples++;
ret = validate_tcpudp4(fs);
if (ret < 0)
return ret;
num_tuples += ret;
break;
case IP_USER_FLOW:
l3_mask = &fs->m_u.usr_ip4_spec;
if (l3_mask->l4_4_bytes || l3_mask->tos || l3_mask->proto ||
fs->h_u.usr_ip4_spec.ip_ver != ETH_RX_NFC_IP4)
return -EINVAL;
if (l3_mask->ip4src) {
if (!all_ones(l3_mask->ip4src))
return -EINVAL;
num_tuples++;
}
if (l3_mask->ip4dst) {
if (!all_ones(l3_mask->ip4dst))
return -EINVAL;
num_tuples++;
}
/* Flow is IPv4 */
num_tuples++;
ret = validate_ip4(fs);
if (ret < 0)
return ret;
num_tuples += ret;
break;
default:
return -EINVAL;
return -ENOTSUPP;
}
if ((fs->flow_type & FLOW_EXT)) {
if (fs->m_ext.vlan_etype ||
(fs->m_ext.vlan_tci != cpu_to_be16(VLAN_VID_MASK)))
return -EINVAL;

if (fs->m_ext.vlan_tci) {
if (be16_to_cpu(fs->h_ext.vlan_tci) >= VLAN_N_VID)
return -EINVAL;
}
num_tuples++;
ret = validate_vlan(fs);
if (ret < 0)
return ret;
num_tuples += ret;
}

if (fs->flow_type & FLOW_MAC_EXT &&
Expand All @@ -483,8 +518,9 @@ int mlx5e_ethtool_flow_replace(struct mlx5e_priv *priv,

num_tuples = validate_flow(priv, fs);
if (num_tuples <= 0) {
netdev_warn(priv->netdev, "%s: flow is not valid\n", __func__);
return -EINVAL;
netdev_warn(priv->netdev, "%s: flow is not valid %d\n",
__func__, num_tuples);
return num_tuples;
}

eth_ft = get_flow_table(priv, fs, num_tuples);
Expand Down

0 comments on commit b29c61d

Please sign in to comment.