net/mlx5: E-Switch, Vport ingress/egress ACLs rules for spoofchk

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>
This commit is contained in:
Mohamad Haj Yahia 2016-05-03 17:13:59 +03:00 коммит произвёл David S. Miller
Родитель dfcb1ed3c3
Коммит f942380c12
3 изменённых файлов: 118 добавлений и 6 удалений

Просмотреть файл

@ -2438,6 +2438,14 @@ static int mlx5e_set_vf_vlan(struct net_device *dev, int vf, u16 vlan, u8 qos)
vlan, 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) static int mlx5_vport_link2ifla(u8 esw_link)
{ {
switch (esw_link) { switch (esw_link) {
@ -2607,6 +2615,7 @@ static const struct net_device_ops mlx5e_netdev_ops_sriov = {
#endif #endif
.ndo_set_vf_mac = mlx5e_set_vf_mac, .ndo_set_vf_mac = mlx5e_set_vf_mac,
.ndo_set_vf_vlan = mlx5e_set_vf_vlan, .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_get_vf_config = mlx5e_get_vf_config,
.ndo_set_vf_link_state = mlx5e_set_vf_link_state, .ndo_set_vf_link_state = mlx5e_set_vf_link_state,
.ndo_get_vf_stats = mlx5e_get_vf_stats, .ndo_get_vf_stats = mlx5e_get_vf_stats,

Просмотреть файл

@ -951,7 +951,12 @@ static void esw_vport_cleanup_ingress_rules(struct mlx5_eswitch *esw,
{ {
if (!IS_ERR_OR_NULL(vport->ingress.drop_rule)) if (!IS_ERR_OR_NULL(vport->ingress.drop_rule))
mlx5_del_flow_rule(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.drop_rule = NULL;
vport->ingress.allow_rule = NULL;
} }
static void esw_vport_disable_ingress_acl(struct mlx5_eswitch *esw, static void esw_vport_disable_ingress_acl(struct mlx5_eswitch *esw,
@ -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, static int esw_vport_ingress_config(struct mlx5_eswitch *esw,
struct mlx5_vport *vport) struct mlx5_vport *vport)
{ {
u8 smac[ETH_ALEN];
u32 *match_v; u32 *match_v;
u32 *match_c; u32 *match_c;
int err = 0; int err = 0;
u8 *smac_v;
if (IS_ERR_OR_NULL(vport->ingress.acl)) { if (IS_ERR_OR_NULL(vport->ingress.acl)) {
esw_warn(esw->dev, esw_warn(esw->dev,
@ -989,9 +996,26 @@ static int esw_vport_ingress_config(struct mlx5_eswitch *esw,
return -EPERM; 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); esw_vport_cleanup_ingress_rules(esw, vport);
if (!vport->vlan && !vport->qos) if (!vport->vlan && !vport->qos && !vport->spoofchk)
return 0; return 0;
esw_debug(esw->dev, esw_debug(esw->dev,
@ -1006,23 +1030,55 @@ static int esw_vport_ingress_config(struct mlx5_eswitch *esw,
vport->vport, err); vport->vport, err);
goto out; 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_add_flow_rule(vport->ingress.acl,
MLX5_MATCH_OUTER_HEADERS, MLX5_MATCH_OUTER_HEADERS,
match_c, match_c,
match_v, 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, MLX5_FLOW_CONTEXT_ACTION_DROP,
0, NULL); 0, NULL);
if (IS_ERR_OR_NULL(vport->ingress.drop_rule)) { if (IS_ERR_OR_NULL(vport->ingress.drop_rule)) {
err = PTR_ERR(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->vport, err);
vport->ingress.drop_rule = NULL; vport->ingress.drop_rule = NULL;
goto out;
} }
out: out:
if (err)
esw_vport_cleanup_ingress_rules(esw, vport);
kfree(match_v); kfree(match_v);
kfree(match_c); kfree(match_c);
return err; return err;
@ -1367,12 +1423,22 @@ int mlx5_eswitch_set_vport_mac(struct mlx5_eswitch *esw,
int vport, u8 mac[ETH_ALEN]) int vport, u8 mac[ETH_ALEN])
{ {
int err = 0; int err = 0;
struct mlx5_vport *evport;
if (!ESW_ALLOWED(esw)) if (!ESW_ALLOWED(esw))
return -EPERM; return -EPERM;
if (!LEGAL_VPORT(esw, vport)) if (!LEGAL_VPORT(esw, vport))
return -EINVAL; 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); err = mlx5_modify_nic_vport_mac_address(esw->dev, vport, mac);
if (err) { if (err) {
mlx5_core_warn(esw->dev, mlx5_core_warn(esw->dev,
@ -1381,6 +1447,11 @@ int mlx5_eswitch_set_vport_mac(struct mlx5_eswitch *esw,
return err; return err;
} }
mutex_lock(&esw->state_lock);
if (evport->enabled)
err = esw_vport_ingress_config(esw, evport);
mutex_unlock(&esw->state_lock);
return err; return err;
} }
@ -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 mlx5_eswitch_get_vport_config(struct mlx5_eswitch *esw,
int vport, struct ifla_vf_info *ivi) int vport, struct ifla_vf_info *ivi)
{ {
struct mlx5_vport *evport;
u16 vlan; u16 vlan;
u8 qos; u8 qos;
@ -1408,6 +1480,8 @@ int mlx5_eswitch_get_vport_config(struct mlx5_eswitch *esw,
if (!LEGAL_VPORT(esw, vport)) if (!LEGAL_VPORT(esw, vport))
return -EINVAL; return -EINVAL;
evport = &esw->vports[vport];
memset(ivi, 0, sizeof(*ivi)); memset(ivi, 0, sizeof(*ivi));
ivi->vf = vport - 1; ivi->vf = vport - 1;
@ -1418,7 +1492,7 @@ int mlx5_eswitch_get_vport_config(struct mlx5_eswitch *esw,
query_esw_vport_cvlan(esw->dev, vport, &vlan, &qos); query_esw_vport_cvlan(esw->dev, vport, &vlan, &qos);
ivi->vlan = vlan; ivi->vlan = vlan;
ivi->qos = qos; ivi->qos = qos;
ivi->spoofchk = 0; ivi->spoofchk = evport->spoofchk;
return 0; return 0;
} }
@ -1459,6 +1533,32 @@ out:
return err; 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 mlx5_eswitch_get_vport_stats(struct mlx5_eswitch *esw,
int vport, int vport,
struct ifla_vf_stats *vf_stats) struct ifla_vf_stats *vf_stats)

Просмотреть файл

@ -118,6 +118,7 @@ struct mlx5_vport {
u16 vlan; u16 vlan;
u8 qos; u8 qos;
bool spoofchk;
bool enabled; bool enabled;
u16 enabled_events; u16 enabled_events;
}; };
@ -160,6 +161,8 @@ int mlx5_eswitch_set_vport_state(struct mlx5_eswitch *esw,
int vport, int link_state); int vport, int link_state);
int mlx5_eswitch_set_vport_vlan(struct mlx5_eswitch *esw, int mlx5_eswitch_set_vport_vlan(struct mlx5_eswitch *esw,
int vport, u16 vlan, u8 qos); 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 mlx5_eswitch_get_vport_config(struct mlx5_eswitch *esw,
int vport, struct ifla_vf_info *ivi); int vport, struct ifla_vf_info *ivi);
int mlx5_eswitch_get_vport_stats(struct mlx5_eswitch *esw, int mlx5_eswitch_get_vport_stats(struct mlx5_eswitch *esw,