lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Tue, 12 Nov 2019 17:13:53 +0000
From:   Saeed Mahameed <saeedm@...lanox.com>
To:     "David S. Miller" <davem@...emloft.net>
CC:     "netdev@...r.kernel.org" <netdev@...r.kernel.org>,
        Ariel Levkovich <lariel@...lanox.com>,
        Jakub Kicinski <jakub.kicinski@...ronome.com>,
        Saeed Mahameed <saeedm@...lanox.com>
Subject: [net-next 8/8] net/mlx5: Add vf ACL access via tc flower

From: Ariel Levkovich <lariel@...lanox.com>

Implementing vf ACL access via tc flower api to allow
admins configure the allowed vlan ids on a vf interface.

To add a vlan id to a vf's ingress/egress ACL table while
in legacy sriov mode, the implementation intercepts tc flows
created on the pf device where the flower matching keys include
the vf's mac address as the src_mac (eswitch ingress) or the
dst_mac (eswitch egress) while the action is accept.

In such cases, the mlx5 driver interpets these flows as adding
a vlan id to the vf's ingress/egress ACL table and updates
the rules in that table using eswitch ACL configuration api
that is introduced in a previous patch.

Signed-off-by: Ariel Levkovich <lariel@...lanox.com>
Cc: Jakub Kicinski <jakub.kicinski@...ronome.com>
Signed-off-by: Saeed Mahameed <saeedm@...lanox.com>
---
 .../net/ethernet/mellanox/mlx5/core/en_tc.c   | 139 +++++++++++++++++-
 .../net/ethernet/mellanox/mlx5/core/eswitch.c |  19 +++
 .../net/ethernet/mellanox/mlx5/core/eswitch.h |   1 +
 3 files changed, 152 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
index bb970b2ebf8a..66b51a3d67c9 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
@@ -68,6 +68,12 @@ struct mlx5_nic_flow_attr {
 	struct mlx5_fc		*counter;
 };
 
+struct mlx5_vf_acl_flow_attr {
+	u16 acl_vlanid;
+	u16 vport;
+	enum mlx5_acl_flow_direction dir;
+};
+
 #define MLX5E_TC_FLOW_BASE (MLX5E_TC_FLAG_LAST_EXPORTED_BIT + 1)
 
 enum {
@@ -82,6 +88,7 @@ enum {
 	MLX5E_TC_FLOW_FLAG_DUP		= MLX5E_TC_FLOW_BASE + 4,
 	MLX5E_TC_FLOW_FLAG_NOT_READY	= MLX5E_TC_FLOW_BASE + 5,
 	MLX5E_TC_FLOW_FLAG_DELETED	= MLX5E_TC_FLOW_BASE + 6,
+	MLX5E_TC_FLOW_FLAG_VF_ACL	= MLX5E_TC_FLOW_BASE + 7,
 };
 
 #define MLX5E_TC_MAX_SPLITS 1
@@ -135,6 +142,7 @@ struct mlx5e_tc_flow {
 	union {
 		struct mlx5_esw_flow_attr esw_attr[0];
 		struct mlx5_nic_flow_attr nic_attr[0];
+		struct mlx5_vf_acl_flow_attr acl_attr[0];
 	};
 };
 
@@ -991,6 +999,15 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv,
 	return PTR_ERR_OR_ZERO(flow->rule[0]);
 }
 
+static void mlx5e_tc_del_vf_acl_flow(struct mlx5e_priv *priv,
+				     struct mlx5e_tc_flow *flow)
+{
+	mlx5_eswitch_del_vport_trunk_vlan(priv->mdev->priv.eswitch,
+					  flow->acl_attr->vport,
+					  flow->acl_attr->acl_vlanid,
+					  flow->acl_attr->dir);
+}
+
 static void mlx5e_tc_del_nic_flow(struct mlx5e_priv *priv,
 				  struct mlx5e_tc_flow *flow)
 {
@@ -1640,6 +1657,8 @@ static void mlx5e_tc_del_flow(struct mlx5e_priv *priv,
 	if (mlx5e_is_eswitch_flow(flow)) {
 		mlx5e_tc_del_fdb_peer_flow(flow);
 		mlx5e_tc_del_fdb_flow(priv, flow);
+	} else if (flow_flag_test(flow, VF_ACL)) {
+		mlx5e_tc_del_vf_acl_flow(priv, flow);
 	} else {
 		mlx5e_tc_del_nic_flow(priv, flow);
 	}
@@ -3718,6 +3737,110 @@ mlx5e_add_fdb_flow(struct mlx5e_priv *priv,
 	return err;
 }
 
+static bool
+parse_vf_acl_flow(struct mlx5_eswitch *esw,
+		  struct flow_cls_offload *f,
+		  struct mlx5_vf_acl_flow_attr *attr)
+{
+	struct flow_rule *rule	 = flow_cls_offload_flow_rule(f);
+	struct flow_dissector *dissector = rule->match.dissector;
+	struct flow_action *flow_action = &rule->action;
+	struct flow_match_eth_addrs match_eth;
+	const struct flow_action_entry *act;
+	struct flow_match_vlan match_vlan;
+	int i;
+
+	if (!esw || esw->mode != MLX5_ESWITCH_LEGACY)
+		return false;
+
+	if (dissector->used_keys ^
+	    (BIT(FLOW_DISSECTOR_KEY_CONTROL) |
+	     BIT(FLOW_DISSECTOR_KEY_BASIC) |
+	     BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
+	     BIT(FLOW_DISSECTOR_KEY_VLAN)))
+		return false;
+
+	/* Allowing only ACCEPT action for acl */
+	if (!flow_action_has_entries(flow_action))
+		return false;
+	flow_action_for_each(i, act, flow_action)
+		if (act->id != FLOW_ACTION_ACCEPT)
+			return false;
+
+	flow_rule_match_vlan(rule, &match_vlan);
+	if (!match_vlan.mask->vlan_id ||
+	    match_vlan.mask->vlan_priority)
+		return false;
+
+	if (match_vlan.key->vlan_tpid != htons(ETH_P_8021Q))
+		return false;
+
+	attr->acl_vlanid = match_vlan.key->vlan_id;
+
+	flow_rule_match_eth_addrs(rule, &match_eth);
+	if (!is_zero_ether_addr(match_eth.mask->dst) &&
+	    !is_zero_ether_addr(match_eth.mask->src))
+		return false;
+
+	if (!is_zero_ether_addr(match_eth.mask->src))
+		attr->dir = MLX5_ACL_INGRESS;
+	else if (!is_zero_ether_addr(match_eth.mask->dst))
+		attr->dir = MLX5_ACL_EGRESS;
+	else
+		return false;
+
+	return true;
+}
+
+static int
+mlx5e_add_vf_acl_flow(struct mlx5e_priv *priv,
+		      struct flow_cls_offload *f,
+		      unsigned long flow_flags,
+		      struct mlx5_vf_acl_flow_attr *acl_attr,
+		      struct mlx5e_tc_flow **__flow)
+{
+	struct flow_rule *rule = flow_cls_offload_flow_rule(f);
+	struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
+	struct mlx5e_tc_flow_parse_attr *parse_attr;
+	struct flow_match_eth_addrs match;
+	struct mlx5e_tc_flow *flow;
+	int attr_size, vport, err;
+
+	flow_rule_match_eth_addrs(rule, &match);
+	vport = mlx5_get_vport_by_mac(esw, (acl_attr->dir == MLX5_ACL_INGRESS) ?
+					   match.key->src :
+					   match.key->dst);
+	if (vport <= 0)
+		return -ENOENT;
+
+	acl_attr->vport = vport;
+	flow_flags |= BIT(MLX5E_TC_FLOW_FLAG_VF_ACL);
+
+	attr_size  = sizeof(struct mlx5_vf_acl_flow_attr);
+	err = mlx5e_alloc_flow(priv, attr_size, f, flow_flags,
+			       &parse_attr, &flow);
+	if (err)
+		return err;
+
+	*flow->acl_attr = *acl_attr;
+	err = mlx5_eswitch_add_vport_trunk_vlan(esw, acl_attr->vport,
+						acl_attr->acl_vlanid, acl_attr->dir);
+	if (err)
+		goto err_free;
+
+	flow_flag_set(flow, OFFLOADED);
+	kvfree(parse_attr);
+	*__flow = flow;
+
+	return 0;
+
+err_free:
+	mlx5e_flow_put(priv, flow);
+	kvfree(parse_attr);
+
+	return err;
+}
+
 static int
 mlx5e_add_nic_flow(struct mlx5e_priv *priv,
 		   struct flow_cls_offload *f,
@@ -3777,8 +3900,8 @@ mlx5e_tc_add_flow(struct mlx5e_priv *priv,
 		  struct mlx5e_tc_flow **flow)
 {
 	struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
+	struct mlx5_vf_acl_flow_attr attr;
 	unsigned long flow_flags;
-	int err;
 
 	get_flags(flags, &flow_flags);
 
@@ -3786,13 +3909,15 @@ mlx5e_tc_add_flow(struct mlx5e_priv *priv,
 		return -EOPNOTSUPP;
 
 	if (esw && esw->mode == MLX5_ESWITCH_OFFLOADS)
-		err = mlx5e_add_fdb_flow(priv, f, flow_flags,
-					 filter_dev, flow);
-	else
-		err = mlx5e_add_nic_flow(priv, f, flow_flags,
-					 filter_dev, flow);
+		return mlx5e_add_fdb_flow(priv, f, flow_flags,
+					  filter_dev, flow);
 
-	return err;
+	if (parse_vf_acl_flow(esw, f, &attr))
+		return mlx5e_add_vf_acl_flow(priv, f, flow_flags,
+					     &attr, flow);
+
+	return mlx5e_add_nic_flow(priv, f, flow_flags,
+				  filter_dev, flow);
 }
 
 int mlx5e_configure_flower(struct net_device *dev, struct mlx5e_priv *priv,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
index 41d67ca6cce3..11436f19b566 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
@@ -66,6 +66,25 @@ struct mlx5_acl_vlan {
 static void esw_destroy_legacy_fdb_table(struct mlx5_eswitch *esw);
 static void esw_cleanup_vepa_rules(struct mlx5_eswitch *esw);
 
+int mlx5_get_vport_by_mac(struct mlx5_eswitch *esw, u8 *mac)
+{
+	struct mlx5_vport *evport;
+	int vport = -ENOENT;
+	int i;
+
+	mutex_lock(&esw->state_lock);
+	mlx5_esw_for_all_vports(esw, i, evport) {
+		if (!ether_addr_equal(mac, evport->info.mac))
+			continue;
+
+		vport = i;
+		break;
+	}
+
+	mutex_unlock(&esw->state_lock);
+	return vport;
+}
+
 struct mlx5_vport *__must_check
 mlx5_eswitch_get_vport(struct mlx5_eswitch *esw, u16 vport_num)
 {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
index 5c84dbdb300f..9cfe34d8877f 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
@@ -630,6 +630,7 @@ bool mlx5_eswitch_is_vf_vport(const struct mlx5_eswitch *esw, u16 vport_num);
 
 void mlx5_eswitch_update_num_of_vfs(struct mlx5_eswitch *esw, const int num_vfs);
 int mlx5_esw_funcs_changed_handler(struct notifier_block *nb, unsigned long type, void *data);
+int mlx5_get_vport_by_mac(struct mlx5_eswitch *esw, u8 *mac);
 
 int
 mlx5_eswitch_enable_pf_vf_vports(struct mlx5_eswitch *esw,
-- 
2.21.0

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ