Commit 7d92d580 authored by Gal Pressman's avatar Gal Pressman Committed by Saeed Mahameed

net/mlx5e: Add 802.1ad VLAN filter steering rules

When a user chooses to use 802.1ad VLAN the proper steering rules will
be added to the VLAN flow table (matching the specific S-tag VID).
Due to current hardware limitation, when using 802.1ad, we must disable
C-tag VLAN stripping on the RQs.
Signed-off-by: default avatarGal Pressman <galp@mellanox.com>
Reviewed-by: default avatarMaor Gottlieb <maorg@mellanox.com>
Signed-off-by: default avatarSaeed Mahameed <saeedm@mellanox.com>
parent 03eda954
...@@ -656,7 +656,9 @@ struct mlx5e_tc_table { ...@@ -656,7 +656,9 @@ struct mlx5e_tc_table {
struct mlx5e_vlan_table { struct mlx5e_vlan_table {
struct mlx5e_flow_table ft; struct mlx5e_flow_table ft;
DECLARE_BITMAP(active_cvlans, VLAN_N_VID); DECLARE_BITMAP(active_cvlans, VLAN_N_VID);
DECLARE_BITMAP(active_svlans, VLAN_N_VID);
struct mlx5_flow_handle *active_cvlans_rule[VLAN_N_VID]; struct mlx5_flow_handle *active_cvlans_rule[VLAN_N_VID];
struct mlx5_flow_handle *active_svlans_rule[VLAN_N_VID];
struct mlx5_flow_handle *untagged_rule; struct mlx5_flow_handle *untagged_rule;
struct mlx5_flow_handle *any_cvlan_rule; struct mlx5_flow_handle *any_cvlan_rule;
struct mlx5_flow_handle *any_svlan_rule; struct mlx5_flow_handle *any_svlan_rule;
......
...@@ -155,6 +155,7 @@ enum mlx5e_vlan_rule_type { ...@@ -155,6 +155,7 @@ enum mlx5e_vlan_rule_type {
MLX5E_VLAN_RULE_TYPE_ANY_CTAG_VID, MLX5E_VLAN_RULE_TYPE_ANY_CTAG_VID,
MLX5E_VLAN_RULE_TYPE_ANY_STAG_VID, MLX5E_VLAN_RULE_TYPE_ANY_STAG_VID,
MLX5E_VLAN_RULE_TYPE_MATCH_CTAG_VID, MLX5E_VLAN_RULE_TYPE_MATCH_CTAG_VID,
MLX5E_VLAN_RULE_TYPE_MATCH_STAG_VID,
}; };
static int __mlx5e_add_vlan_rule(struct mlx5e_priv *priv, static int __mlx5e_add_vlan_rule(struct mlx5e_priv *priv,
...@@ -174,6 +175,10 @@ static int __mlx5e_add_vlan_rule(struct mlx5e_priv *priv, ...@@ -174,6 +175,10 @@ static int __mlx5e_add_vlan_rule(struct mlx5e_priv *priv,
switch (rule_type) { switch (rule_type) {
case MLX5E_VLAN_RULE_TYPE_UNTAGGED: case MLX5E_VLAN_RULE_TYPE_UNTAGGED:
/* cvlan_tag enabled in match criteria and
* disabled in match value means both S & C tags
* don't exist (untagged of both)
*/
rule_p = &priv->fs.vlan.untagged_rule; rule_p = &priv->fs.vlan.untagged_rule;
MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
outer_headers.cvlan_tag); outer_headers.cvlan_tag);
...@@ -190,6 +195,16 @@ static int __mlx5e_add_vlan_rule(struct mlx5e_priv *priv, ...@@ -190,6 +195,16 @@ static int __mlx5e_add_vlan_rule(struct mlx5e_priv *priv,
outer_headers.svlan_tag); outer_headers.svlan_tag);
MLX5_SET(fte_match_param, spec->match_value, outer_headers.svlan_tag, 1); MLX5_SET(fte_match_param, spec->match_value, outer_headers.svlan_tag, 1);
break; break;
case MLX5E_VLAN_RULE_TYPE_MATCH_STAG_VID:
rule_p = &priv->fs.vlan.active_svlans_rule[vid];
MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
outer_headers.svlan_tag);
MLX5_SET(fte_match_param, spec->match_value, outer_headers.svlan_tag, 1);
MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
outer_headers.first_vid);
MLX5_SET(fte_match_param, spec->match_value, outer_headers.first_vid,
vid);
break;
default: /* MLX5E_VLAN_RULE_TYPE_MATCH_CTAG_VID */ default: /* MLX5E_VLAN_RULE_TYPE_MATCH_CTAG_VID */
rule_p = &priv->fs.vlan.active_cvlans_rule[vid]; rule_p = &priv->fs.vlan.active_cvlans_rule[vid];
MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
...@@ -255,6 +270,12 @@ static void mlx5e_del_vlan_rule(struct mlx5e_priv *priv, ...@@ -255,6 +270,12 @@ static void mlx5e_del_vlan_rule(struct mlx5e_priv *priv,
priv->fs.vlan.any_svlan_rule = NULL; priv->fs.vlan.any_svlan_rule = NULL;
} }
break; break;
case MLX5E_VLAN_RULE_TYPE_MATCH_STAG_VID:
if (priv->fs.vlan.active_svlans_rule[vid]) {
mlx5_del_flow_rules(priv->fs.vlan.active_svlans_rule[vid]);
priv->fs.vlan.active_svlans_rule[vid] = NULL;
}
break;
case MLX5E_VLAN_RULE_TYPE_MATCH_CTAG_VID: case MLX5E_VLAN_RULE_TYPE_MATCH_CTAG_VID:
mlx5e_vport_context_update_vlans(priv); mlx5e_vport_context_update_vlans(priv);
if (priv->fs.vlan.active_cvlans_rule[vid]) { if (priv->fs.vlan.active_cvlans_rule[vid]) {
...@@ -305,10 +326,8 @@ void mlx5e_disable_cvlan_filter(struct mlx5e_priv *priv) ...@@ -305,10 +326,8 @@ void mlx5e_disable_cvlan_filter(struct mlx5e_priv *priv)
mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_CTAG_VID, 0); mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_CTAG_VID, 0);
} }
int mlx5e_vlan_rx_add_vid(struct net_device *dev, __always_unused __be16 proto, static int mlx5e_vlan_rx_add_cvid(struct mlx5e_priv *priv, u16 vid)
u16 vid)
{ {
struct mlx5e_priv *priv = netdev_priv(dev);
int err; int err;
set_bit(vid, priv->fs.vlan.active_cvlans); set_bit(vid, priv->fs.vlan.active_cvlans);
...@@ -320,14 +339,48 @@ int mlx5e_vlan_rx_add_vid(struct net_device *dev, __always_unused __be16 proto, ...@@ -320,14 +339,48 @@ int mlx5e_vlan_rx_add_vid(struct net_device *dev, __always_unused __be16 proto,
return err; return err;
} }
int mlx5e_vlan_rx_kill_vid(struct net_device *dev, __always_unused __be16 proto, static int mlx5e_vlan_rx_add_svid(struct mlx5e_priv *priv, u16 vid)
u16 vid) {
struct net_device *netdev = priv->netdev;
int err;
set_bit(vid, priv->fs.vlan.active_svlans);
err = mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_STAG_VID, vid);
if (err) {
clear_bit(vid, priv->fs.vlan.active_svlans);
return err;
}
/* Need to fix some features.. */
netdev_update_features(netdev);
return err;
}
int mlx5e_vlan_rx_add_vid(struct net_device *dev, __be16 proto, u16 vid)
{ {
struct mlx5e_priv *priv = netdev_priv(dev); struct mlx5e_priv *priv = netdev_priv(dev);
clear_bit(vid, priv->fs.vlan.active_cvlans); if (be16_to_cpu(proto) == ETH_P_8021Q)
return mlx5e_vlan_rx_add_cvid(priv, vid);
else if (be16_to_cpu(proto) == ETH_P_8021AD)
return mlx5e_vlan_rx_add_svid(priv, vid);
mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_CTAG_VID, vid); return -EOPNOTSUPP;
}
int mlx5e_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, u16 vid)
{
struct mlx5e_priv *priv = netdev_priv(dev);
if (be16_to_cpu(proto) == ETH_P_8021Q) {
clear_bit(vid, priv->fs.vlan.active_cvlans);
mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_CTAG_VID, vid);
} else if (be16_to_cpu(proto) == ETH_P_8021AD) {
clear_bit(vid, priv->fs.vlan.active_svlans);
mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_STAG_VID, vid);
netdev_update_features(dev);
}
return 0; return 0;
} }
...@@ -342,6 +395,9 @@ static void mlx5e_add_vlan_rules(struct mlx5e_priv *priv) ...@@ -342,6 +395,9 @@ static void mlx5e_add_vlan_rules(struct mlx5e_priv *priv)
mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_CTAG_VID, i); mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_CTAG_VID, i);
} }
for_each_set_bit(i, priv->fs.vlan.active_svlans, VLAN_N_VID)
mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_STAG_VID, i);
if (priv->fs.vlan.cvlan_filter_disabled && if (priv->fs.vlan.cvlan_filter_disabled &&
!(priv->netdev->flags & IFF_PROMISC)) !(priv->netdev->flags & IFF_PROMISC))
mlx5e_add_any_vid_rules(priv); mlx5e_add_any_vid_rules(priv);
...@@ -357,6 +413,9 @@ static void mlx5e_del_vlan_rules(struct mlx5e_priv *priv) ...@@ -357,6 +413,9 @@ static void mlx5e_del_vlan_rules(struct mlx5e_priv *priv)
mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_CTAG_VID, i); mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_CTAG_VID, i);
} }
for_each_set_bit(i, priv->fs.vlan.active_svlans, VLAN_N_VID)
mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_STAG_VID, i);
if (priv->fs.vlan.cvlan_filter_disabled && if (priv->fs.vlan.cvlan_filter_disabled &&
!(priv->netdev->flags & IFF_PROMISC)) !(priv->netdev->flags & IFF_PROMISC))
mlx5e_del_any_vid_rules(priv); mlx5e_del_any_vid_rules(priv);
...@@ -550,6 +609,9 @@ void mlx5e_set_rx_mode_work(struct work_struct *work) ...@@ -550,6 +609,9 @@ void mlx5e_set_rx_mode_work(struct work_struct *work)
bool disable_broadcast = ea->broadcast_enabled && !broadcast_enabled; bool disable_broadcast = ea->broadcast_enabled && !broadcast_enabled;
if (enable_promisc) { if (enable_promisc) {
if (!priv->channels.params.vlan_strip_disable)
netdev_warn_once(ndev,
"S-tagged traffic will be dropped while C-tag vlan stripping is enabled\n");
mlx5e_add_l2_flow_rule(priv, &ea->promisc, MLX5E_PROMISC); mlx5e_add_l2_flow_rule(priv, &ea->promisc, MLX5E_PROMISC);
if (!priv->fs.vlan.cvlan_filter_disabled) if (!priv->fs.vlan.cvlan_filter_disabled)
mlx5e_add_any_vid_rules(priv); mlx5e_add_any_vid_rules(priv);
...@@ -1270,13 +1332,15 @@ static int mlx5e_create_l2_table(struct mlx5e_priv *priv) ...@@ -1270,13 +1332,15 @@ static int mlx5e_create_l2_table(struct mlx5e_priv *priv)
return err; return err;
} }
#define MLX5E_NUM_VLAN_GROUPS 3 #define MLX5E_NUM_VLAN_GROUPS 4
#define MLX5E_VLAN_GROUP0_SIZE BIT(12) #define MLX5E_VLAN_GROUP0_SIZE BIT(12)
#define MLX5E_VLAN_GROUP1_SIZE BIT(1) #define MLX5E_VLAN_GROUP1_SIZE BIT(12)
#define MLX5E_VLAN_GROUP2_SIZE BIT(0) #define MLX5E_VLAN_GROUP2_SIZE BIT(1)
#define MLX5E_VLAN_GROUP3_SIZE BIT(0)
#define MLX5E_VLAN_TABLE_SIZE (MLX5E_VLAN_GROUP0_SIZE +\ #define MLX5E_VLAN_TABLE_SIZE (MLX5E_VLAN_GROUP0_SIZE +\
MLX5E_VLAN_GROUP1_SIZE +\ MLX5E_VLAN_GROUP1_SIZE +\
MLX5E_VLAN_GROUP2_SIZE) MLX5E_VLAN_GROUP2_SIZE +\
MLX5E_VLAN_GROUP3_SIZE)
static int __mlx5e_create_vlan_table_groups(struct mlx5e_flow_table *ft, u32 *in, static int __mlx5e_create_vlan_table_groups(struct mlx5e_flow_table *ft, u32 *in,
int inlen) int inlen)
...@@ -1299,7 +1363,8 @@ static int __mlx5e_create_vlan_table_groups(struct mlx5e_flow_table *ft, u32 *in ...@@ -1299,7 +1363,8 @@ static int __mlx5e_create_vlan_table_groups(struct mlx5e_flow_table *ft, u32 *in
memset(in, 0, inlen); memset(in, 0, inlen);
MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS); MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS);
MLX5_SET_TO_ONES(fte_match_param, mc, outer_headers.cvlan_tag); MLX5_SET_TO_ONES(fte_match_param, mc, outer_headers.svlan_tag);
MLX5_SET_TO_ONES(fte_match_param, mc, outer_headers.first_vid);
MLX5_SET_CFG(in, start_flow_index, ix); MLX5_SET_CFG(in, start_flow_index, ix);
ix += MLX5E_VLAN_GROUP1_SIZE; ix += MLX5E_VLAN_GROUP1_SIZE;
MLX5_SET_CFG(in, end_flow_index, ix - 1); MLX5_SET_CFG(in, end_flow_index, ix - 1);
...@@ -1310,7 +1375,7 @@ static int __mlx5e_create_vlan_table_groups(struct mlx5e_flow_table *ft, u32 *in ...@@ -1310,7 +1375,7 @@ static int __mlx5e_create_vlan_table_groups(struct mlx5e_flow_table *ft, u32 *in
memset(in, 0, inlen); memset(in, 0, inlen);
MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS); MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS);
MLX5_SET_TO_ONES(fte_match_param, mc, outer_headers.svlan_tag); MLX5_SET_TO_ONES(fte_match_param, mc, outer_headers.cvlan_tag);
MLX5_SET_CFG(in, start_flow_index, ix); MLX5_SET_CFG(in, start_flow_index, ix);
ix += MLX5E_VLAN_GROUP2_SIZE; ix += MLX5E_VLAN_GROUP2_SIZE;
MLX5_SET_CFG(in, end_flow_index, ix - 1); MLX5_SET_CFG(in, end_flow_index, ix - 1);
...@@ -1319,6 +1384,17 @@ static int __mlx5e_create_vlan_table_groups(struct mlx5e_flow_table *ft, u32 *in ...@@ -1319,6 +1384,17 @@ static int __mlx5e_create_vlan_table_groups(struct mlx5e_flow_table *ft, u32 *in
goto err_destroy_groups; goto err_destroy_groups;
ft->num_groups++; ft->num_groups++;
memset(in, 0, inlen);
MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS);
MLX5_SET_TO_ONES(fte_match_param, mc, outer_headers.svlan_tag);
MLX5_SET_CFG(in, start_flow_index, ix);
ix += MLX5E_VLAN_GROUP3_SIZE;
MLX5_SET_CFG(in, end_flow_index, ix - 1);
ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in);
if (IS_ERR(ft->g[ft->num_groups]))
goto err_destroy_groups;
ft->num_groups++;
return 0; return 0;
err_destroy_groups: err_destroy_groups:
......
...@@ -3395,6 +3395,25 @@ static int mlx5e_set_features(struct net_device *netdev, ...@@ -3395,6 +3395,25 @@ static int mlx5e_set_features(struct net_device *netdev,
return err ? -EINVAL : 0; return err ? -EINVAL : 0;
} }
static netdev_features_t mlx5e_fix_features(struct net_device *netdev,
netdev_features_t features)
{
struct mlx5e_priv *priv = netdev_priv(netdev);
mutex_lock(&priv->state_lock);
if (!bitmap_empty(priv->fs.vlan.active_svlans, VLAN_N_VID)) {
/* HW strips the outer C-tag header, this is a problem
* for S-tag traffic.
*/
features &= ~NETIF_F_HW_VLAN_CTAG_RX;
if (!priv->channels.params.vlan_strip_disable)
netdev_warn(netdev, "Dropping C-tag vlan stripping offload due to S-tag vlan\n");
}
mutex_unlock(&priv->state_lock);
return features;
}
static int mlx5e_change_mtu(struct net_device *netdev, int new_mtu) static int mlx5e_change_mtu(struct net_device *netdev, int new_mtu)
{ {
struct mlx5e_priv *priv = netdev_priv(netdev); struct mlx5e_priv *priv = netdev_priv(netdev);
...@@ -3872,6 +3891,7 @@ static const struct net_device_ops mlx5e_netdev_ops = { ...@@ -3872,6 +3891,7 @@ static const struct net_device_ops mlx5e_netdev_ops = {
.ndo_vlan_rx_add_vid = mlx5e_vlan_rx_add_vid, .ndo_vlan_rx_add_vid = mlx5e_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = mlx5e_vlan_rx_kill_vid, .ndo_vlan_rx_kill_vid = mlx5e_vlan_rx_kill_vid,
.ndo_set_features = mlx5e_set_features, .ndo_set_features = mlx5e_set_features,
.ndo_fix_features = mlx5e_fix_features,
.ndo_change_mtu = mlx5e_change_mtu, .ndo_change_mtu = mlx5e_change_mtu,
.ndo_do_ioctl = mlx5e_ioctl, .ndo_do_ioctl = mlx5e_ioctl,
.ndo_set_tx_maxrate = mlx5e_set_tx_maxrate, .ndo_set_tx_maxrate = mlx5e_set_tx_maxrate,
...@@ -4231,6 +4251,7 @@ static void mlx5e_build_nic_netdev(struct net_device *netdev) ...@@ -4231,6 +4251,7 @@ static void mlx5e_build_nic_netdev(struct net_device *netdev)
} }
netdev->features |= NETIF_F_HIGHDMA; netdev->features |= NETIF_F_HIGHDMA;
netdev->features |= NETIF_F_HW_VLAN_STAG_FILTER;
netdev->priv_flags |= IFF_UNICAST_FLT; netdev->priv_flags |= IFF_UNICAST_FLT;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment