Skip to content

Commit

Permalink
net/mlx5: E-Switch, Vport ingress/egress ACLs rules for spoofchk
Browse files Browse the repository at this point in the history
Configure ingress and egress vport ACL rules according to spoofchk
admin parameters.

Ingress ACL flow table rules:
if (!spoofchk && !vst) allow all traffic.
else :
1) one of the following rules :
* if (spoofchk && vst) allow only untagged traffic with smac=original
mac sent from the VF.
* if (spoofchk && !vst) allow only traffic with smac=original mac sent
from the VF.
* if (!spoofchk && vst) allow only untagged traffic.
2) drop all traffic that didn't hit #1.

Add support for set vf spoofchk ndo.

Add non zero mac validation in case of spoofchk to set mac ndo:
when setting new mac we need to validate that the new mac is
not zero while the spoofchk is on because it is illegal
combination.

Signed-off-by: Mohamad Haj Yahia <mohamad@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Mohamad Haj Yahia authored and David S. Miller committed May 4, 2016
1 parent dfcb1ed commit f942380
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 6 deletions.
9 changes: 9 additions & 0 deletions drivers/net/ethernet/mellanox/mlx5/core/en_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -2438,6 +2438,14 @@ static int mlx5e_set_vf_vlan(struct net_device *dev, int vf, u16 vlan, u8 qos)
vlan, qos);
}

static int mlx5e_set_vf_spoofchk(struct net_device *dev, int vf, bool setting)
{
struct mlx5e_priv *priv = netdev_priv(dev);
struct mlx5_core_dev *mdev = priv->mdev;

return mlx5_eswitch_set_vport_spoofchk(mdev->priv.eswitch, vf + 1, setting);
}

static int mlx5_vport_link2ifla(u8 esw_link)
{
switch (esw_link) {
Expand Down Expand Up @@ -2607,6 +2615,7 @@ static const struct net_device_ops mlx5e_netdev_ops_sriov = {
#endif
.ndo_set_vf_mac = mlx5e_set_vf_mac,
.ndo_set_vf_vlan = mlx5e_set_vf_vlan,
.ndo_set_vf_spoofchk = mlx5e_set_vf_spoofchk,
.ndo_get_vf_config = mlx5e_get_vf_config,
.ndo_set_vf_link_state = mlx5e_set_vf_link_state,
.ndo_get_vf_stats = mlx5e_get_vf_stats,
Expand Down
112 changes: 106 additions & 6 deletions drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
Original file line number Diff line number Diff line change
Expand Up @@ -951,7 +951,12 @@ static void esw_vport_cleanup_ingress_rules(struct mlx5_eswitch *esw,
{
if (!IS_ERR_OR_NULL(vport->ingress.drop_rule))
mlx5_del_flow_rule(vport->ingress.drop_rule);

if (!IS_ERR_OR_NULL(vport->ingress.allow_rule))
mlx5_del_flow_rule(vport->ingress.allow_rule);

vport->ingress.drop_rule = NULL;
vport->ingress.allow_rule = NULL;
}

static void esw_vport_disable_ingress_acl(struct mlx5_eswitch *esw,
Expand All @@ -978,9 +983,11 @@ static void esw_vport_disable_ingress_acl(struct mlx5_eswitch *esw,
static int esw_vport_ingress_config(struct mlx5_eswitch *esw,
struct mlx5_vport *vport)
{
u8 smac[ETH_ALEN];
u32 *match_v;
u32 *match_c;
int err = 0;
u8 *smac_v;

if (IS_ERR_OR_NULL(vport->ingress.acl)) {
esw_warn(esw->dev,
Expand All @@ -989,9 +996,26 @@ static int esw_vport_ingress_config(struct mlx5_eswitch *esw,
return -EPERM;
}

if (vport->spoofchk) {
err = mlx5_query_nic_vport_mac_address(esw->dev, vport->vport, smac);
if (err) {
esw_warn(esw->dev,
"vport[%d] configure ingress rules failed, query smac failed, err(%d)\n",
vport->vport, err);
return err;
}

if (!is_valid_ether_addr(smac)) {
mlx5_core_warn(esw->dev,
"vport[%d] configure ingress rules failed, illegal mac with spoofchk\n",
vport->vport);
return -EPERM;
}
}

esw_vport_cleanup_ingress_rules(esw, vport);

if (!vport->vlan && !vport->qos)
if (!vport->vlan && !vport->qos && !vport->spoofchk)
return 0;

esw_debug(esw->dev,
Expand All @@ -1006,23 +1030,55 @@ static int esw_vport_ingress_config(struct mlx5_eswitch *esw,
vport->vport, err);
goto out;
}
MLX5_SET_TO_ONES(fte_match_param, match_c, outer_headers.vlan_tag);
MLX5_SET_TO_ONES(fte_match_param, match_v, outer_headers.vlan_tag);

vport->ingress.drop_rule =
if (vport->vlan || vport->qos)
MLX5_SET_TO_ONES(fte_match_param, match_c, outer_headers.vlan_tag);

if (vport->spoofchk) {
MLX5_SET_TO_ONES(fte_match_param, match_c, outer_headers.smac_47_16);
MLX5_SET_TO_ONES(fte_match_param, match_c, outer_headers.smac_15_0);
smac_v = MLX5_ADDR_OF(fte_match_param,
match_v,
outer_headers.smac_47_16);
ether_addr_copy(smac_v, smac);
}

vport->ingress.allow_rule =
mlx5_add_flow_rule(vport->ingress.acl,
MLX5_MATCH_OUTER_HEADERS,
match_c,
match_v,
MLX5_FLOW_CONTEXT_ACTION_ALLOW,
0, NULL);
if (IS_ERR_OR_NULL(vport->ingress.allow_rule)) {
err = PTR_ERR(vport->ingress.allow_rule);
pr_warn("vport[%d] configure ingress allow rule, err(%d)\n",
vport->vport, err);
vport->ingress.allow_rule = NULL;
goto out;
}

memset(match_c, 0, MLX5_ST_SZ_BYTES(fte_match_param));
memset(match_v, 0, MLX5_ST_SZ_BYTES(fte_match_param));
vport->ingress.drop_rule =
mlx5_add_flow_rule(vport->ingress.acl,
0,
match_c,
match_v,
MLX5_FLOW_CONTEXT_ACTION_DROP,
0, NULL);
if (IS_ERR_OR_NULL(vport->ingress.drop_rule)) {
err = PTR_ERR(vport->ingress.drop_rule);
pr_warn("vport[%d] configure ingress rules, err(%d)\n",
pr_warn("vport[%d] configure ingress drop rule, err(%d)\n",
vport->vport, err);
vport->ingress.drop_rule = NULL;
goto out;
}

out:
if (err)
esw_vport_cleanup_ingress_rules(esw, vport);

kfree(match_v);
kfree(match_c);
return err;
Expand Down Expand Up @@ -1367,12 +1423,22 @@ int mlx5_eswitch_set_vport_mac(struct mlx5_eswitch *esw,
int vport, u8 mac[ETH_ALEN])
{
int err = 0;
struct mlx5_vport *evport;

if (!ESW_ALLOWED(esw))
return -EPERM;
if (!LEGAL_VPORT(esw, vport))
return -EINVAL;

evport = &esw->vports[vport];

if (evport->spoofchk && !is_valid_ether_addr(mac)) {
mlx5_core_warn(esw->dev,
"MAC invalidation is not allowed when spoofchk is on, vport(%d)\n",
vport);
return -EPERM;
}

err = mlx5_modify_nic_vport_mac_address(esw->dev, vport, mac);
if (err) {
mlx5_core_warn(esw->dev,
Expand All @@ -1381,6 +1447,11 @@ int mlx5_eswitch_set_vport_mac(struct mlx5_eswitch *esw,
return err;
}

mutex_lock(&esw->state_lock);
if (evport->enabled)
err = esw_vport_ingress_config(esw, evport);
mutex_unlock(&esw->state_lock);

return err;
}

Expand All @@ -1400,6 +1471,7 @@ int mlx5_eswitch_set_vport_state(struct mlx5_eswitch *esw,
int mlx5_eswitch_get_vport_config(struct mlx5_eswitch *esw,
int vport, struct ifla_vf_info *ivi)
{
struct mlx5_vport *evport;
u16 vlan;
u8 qos;

Expand All @@ -1408,6 +1480,8 @@ int mlx5_eswitch_get_vport_config(struct mlx5_eswitch *esw,
if (!LEGAL_VPORT(esw, vport))
return -EINVAL;

evport = &esw->vports[vport];

memset(ivi, 0, sizeof(*ivi));
ivi->vf = vport - 1;

Expand All @@ -1418,7 +1492,7 @@ int mlx5_eswitch_get_vport_config(struct mlx5_eswitch *esw,
query_esw_vport_cvlan(esw->dev, vport, &vlan, &qos);
ivi->vlan = vlan;
ivi->qos = qos;
ivi->spoofchk = 0;
ivi->spoofchk = evport->spoofchk;

return 0;
}
Expand Down Expand Up @@ -1459,6 +1533,32 @@ int mlx5_eswitch_set_vport_vlan(struct mlx5_eswitch *esw,
return err;
}

int mlx5_eswitch_set_vport_spoofchk(struct mlx5_eswitch *esw,
int vport, bool spoofchk)
{
struct mlx5_vport *evport;
bool pschk;
int err = 0;

if (!ESW_ALLOWED(esw))
return -EPERM;
if (!LEGAL_VPORT(esw, vport))
return -EINVAL;

evport = &esw->vports[vport];

mutex_lock(&esw->state_lock);
pschk = evport->spoofchk;
evport->spoofchk = spoofchk;
if (evport->enabled)
err = esw_vport_ingress_config(esw, evport);
if (err)
evport->spoofchk = pschk;
mutex_unlock(&esw->state_lock);

return err;
}

int mlx5_eswitch_get_vport_stats(struct mlx5_eswitch *esw,
int vport,
struct ifla_vf_stats *vf_stats)
Expand Down
3 changes: 3 additions & 0 deletions drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ struct mlx5_vport {

u16 vlan;
u8 qos;
bool spoofchk;
bool enabled;
u16 enabled_events;
};
Expand Down Expand Up @@ -160,6 +161,8 @@ int mlx5_eswitch_set_vport_state(struct mlx5_eswitch *esw,
int vport, int link_state);
int mlx5_eswitch_set_vport_vlan(struct mlx5_eswitch *esw,
int vport, u16 vlan, u8 qos);
int mlx5_eswitch_set_vport_spoofchk(struct mlx5_eswitch *esw,
int vport, bool spoofchk);
int mlx5_eswitch_get_vport_config(struct mlx5_eswitch *esw,
int vport, struct ifla_vf_info *ivi);
int mlx5_eswitch_get_vport_stats(struct mlx5_eswitch *esw,
Expand Down

0 comments on commit f942380

Please sign in to comment.