Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8c4dc42b authored by Eli Britstein's avatar Eli Britstein Committed by Saeed Mahameed
Browse files

net/mlx5e: Support multiple encapsulations for a TC flow



Currently a flow is associated with a single encap structure. The FW
extended destination features enables the driver to associate a flow
with multiple encap instances.

Change the encap id field from a flow scope to a per destination value
in the flow attributes struct. Use the encaps array to associate a flow
table entry with multiple encap entries.

Update the neigh logic to offload only if all encapsulations used in a
flow are connected, and un-offload upon the first one disconnected.

Note that the driver can now support up to two encap destinations.

Signed-off-by: default avatarEli Britstein <elibr@mellanox.com>
Reviewed-by: default avatarOz Shlomo <ozsh@mellanox.com>
Signed-off-by: default avatarSaeed Mahameed <saeedm@mellanox.com>
parent 79baaec7
Loading
Loading
Loading
Loading
+56 −29
Original line number Diff line number Diff line
@@ -843,14 +843,15 @@ static void mlx5e_tc_del_nic_flow(struct mlx5e_priv *priv,
}

static void mlx5e_detach_encap(struct mlx5e_priv *priv,
			       struct mlx5e_tc_flow *flow);
			       struct mlx5e_tc_flow *flow, int out_index);

static int mlx5e_attach_encap(struct mlx5e_priv *priv,
			      struct ip_tunnel_info *tun_info,
			      struct net_device *mirred_dev,
			      struct net_device **encap_dev,
			      struct mlx5e_tc_flow *flow,
			      struct netlink_ext_ack *extack);
			      struct netlink_ext_ack *extack,
			      int out_index);

static struct mlx5_flow_handle *
mlx5e_tc_offload_fdb_rules(struct mlx5_eswitch *esw,
@@ -955,18 +956,22 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
	}

	for (out_index = 0; out_index < MLX5_MAX_FLOW_FWD_VPORTS; out_index++) {
		int mirred_ifindex;

		if (!(attr->dests[out_index].flags & MLX5_ESW_DEST_ENCAP))
			continue;

		mirred_ifindex = attr->parse_attr->mirred_ifindex[out_index];
		out_dev = __dev_get_by_index(dev_net(priv->netdev),
					     attr->parse_attr->mirred_ifindex[0]);
		encap_err = mlx5e_attach_encap(priv, &parse_attr->tun_info[0],
					     mirred_ifindex);
		err = mlx5e_attach_encap(priv,
					 &parse_attr->tun_info[out_index],
					 out_dev, &encap_dev, flow,
					       extack);
		if (encap_err && encap_err != -EAGAIN) {
			err = encap_err;
					 extack, out_index);
		if (err && err != -EAGAIN)
			goto err_attach_encap;
		}
		if (err == -EAGAIN)
			encap_err = err;
		out_priv = netdev_priv(encap_dev);
		rpriv = out_priv->ppriv;
		attr->dests[out_index].rep = rpriv->rep;
@@ -1022,10 +1027,8 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
	mlx5_eswitch_del_vlan_action(esw, attr);
err_add_vlan:
	for (out_index = 0; out_index < MLX5_MAX_FLOW_FWD_VPORTS; out_index++)
		if (attr->dests[out_index].flags & MLX5_ESW_DEST_ENCAP) {
			mlx5e_detach_encap(priv, flow);
			break;
		}
		if (attr->dests[out_index].flags & MLX5_ESW_DEST_ENCAP)
			mlx5e_detach_encap(priv, flow, out_index);
err_attach_encap:
err_max_prio_chain:
	return err;
@@ -1049,10 +1052,8 @@ static void mlx5e_tc_del_fdb_flow(struct mlx5e_priv *priv,
	mlx5_eswitch_del_vlan_action(esw, attr);

	for (out_index = 0; out_index < MLX5_MAX_FLOW_FWD_VPORTS; out_index++)
		if (attr->dests[out_index].flags & MLX5_ESW_DEST_ENCAP) {
			mlx5e_detach_encap(priv, flow);
			break;
		}
		if (attr->dests[out_index].flags & MLX5_ESW_DEST_ENCAP)
			mlx5e_detach_encap(priv, flow, out_index);
	kvfree(attr->parse_attr);

	if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
@@ -1087,11 +1088,30 @@ void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv,
	mlx5e_rep_queue_neigh_stats_work(priv);

	list_for_each_entry(efi, &e->flows, list) {
		bool all_flow_encaps_valid = true;
		int i;

		flow = container_of(efi, struct mlx5e_tc_flow, encaps[efi->index]);
		esw_attr = flow->esw_attr;
		esw_attr->encap_id = e->encap_id;
		spec = &esw_attr->parse_attr->spec;

		esw_attr->dests[efi->index].encap_id = e->encap_id;
		esw_attr->dests[efi->index].flags |= MLX5_ESW_DEST_ENCAP_VALID;
		/* Flow can be associated with multiple encap entries.
		 * Before offloading the flow verify that all of them have
		 * a valid neighbour.
		 */
		for (i = 0; i < MLX5_MAX_FLOW_FWD_VPORTS; i++) {
			if (!(esw_attr->dests[i].flags & MLX5_ESW_DEST_ENCAP))
				continue;
			if (!(esw_attr->dests[i].flags & MLX5_ESW_DEST_ENCAP_VALID)) {
				all_flow_encaps_valid = false;
				break;
			}
		}
		/* Do not offload flows with unresolved neighbors */
		if (!all_flow_encaps_valid)
			continue;
		/* update from slow path rule to encap rule */
		rule = mlx5e_tc_offload_fdb_rules(esw, flow, spec, esw_attr);
		if (IS_ERR(rule)) {
@@ -1124,6 +1144,8 @@ void mlx5e_tc_encap_flows_del(struct mlx5e_priv *priv,

		/* update from encap rule to slow path rule */
		rule = mlx5e_tc_offload_to_slow_path(esw, flow, spec, &slow_attr);
		/* mark the flow's encap dest as non-valid */
		flow->esw_attr->dests[efi->index].flags &= ~MLX5_ESW_DEST_ENCAP_VALID;

		if (IS_ERR(rule)) {
			err = PTR_ERR(rule);
@@ -1207,11 +1229,11 @@ void mlx5e_tc_update_neigh_used_value(struct mlx5e_neigh_hash_entry *nhe)
}

static void mlx5e_detach_encap(struct mlx5e_priv *priv,
			       struct mlx5e_tc_flow *flow)
			       struct mlx5e_tc_flow *flow, int out_index)
{
	struct list_head *next = flow->encaps[0].list.next;
	struct list_head *next = flow->encaps[out_index].list.next;

	list_del(&flow->encaps[0].list);
	list_del(&flow->encaps[out_index].list);
	if (list_empty(next)) {
		struct mlx5e_encap_entry *e;

@@ -2324,7 +2346,8 @@ static int mlx5e_attach_encap(struct mlx5e_priv *priv,
			      struct net_device *mirred_dev,
			      struct net_device **encap_dev,
			      struct mlx5e_tc_flow *flow,
			      struct netlink_ext_ack *extack)
			      struct netlink_ext_ack *extack,
			      int out_index)
{
	struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
	unsigned short family = ip_tunnel_info_af(tun_info);
@@ -2371,13 +2394,15 @@ static int mlx5e_attach_encap(struct mlx5e_priv *priv,
	hash_add_rcu(esw->offloads.encap_tbl, &e->encap_hlist, hash_key);

attach_flow:
	list_add(&flow->encaps[0].list, &e->flows);
	flow->encaps[0].index = 0;
	list_add(&flow->encaps[out_index].list, &e->flows);
	flow->encaps[out_index].index = out_index;
	*encap_dev = e->out_dev;
	if (e->flags & MLX5_ENCAP_ENTRY_VALID)
		attr->encap_id = e->encap_id;
	else
	if (e->flags & MLX5_ENCAP_ENTRY_VALID) {
		attr->dests[out_index].encap_id = e->encap_id;
		attr->dests[out_index].flags |= MLX5_ESW_DEST_ENCAP_VALID;
	} else {
		err = -EAGAIN;
	}

	return err;

@@ -2516,8 +2541,10 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
				attr->dests[attr->out_count].mdev = out_priv->mdev;
				attr->out_count++;
			} else if (encap) {
				parse_attr->mirred_ifindex[0] = out_dev->ifindex;
				parse_attr->tun_info[0] = *info;
				parse_attr->mirred_ifindex[attr->out_count] =
					out_dev->ifindex;
				parse_attr->tun_info[attr->out_count] = *info;
				encap = false;
				attr->parse_attr = parse_attr;
				attr->dests[attr->out_count].flags |=
					MLX5_ESW_DEST_ENCAP;
+2 −1
Original line number Diff line number Diff line
@@ -283,6 +283,7 @@ enum mlx5_flow_match_level {

enum {
	MLX5_ESW_DEST_ENCAP         = BIT(0),
	MLX5_ESW_DEST_ENCAP_VALID   = BIT(1),
};

struct mlx5_esw_flow_attr {
@@ -298,11 +299,11 @@ struct mlx5_esw_flow_attr {
	u8	vlan_prio[MLX5_FS_VLAN_DEPTH];
	u8	total_vlan;
	bool	vlan_handled;
	u32	encap_id;
	struct {
		u32 flags;
		struct mlx5_eswitch_rep *rep;
		struct mlx5_core_dev *mdev;
		u32 encap_id;
	} dests[MLX5_MAX_FLOW_FWD_VPORTS];
	u32	mod_hdr_id;
	u8	match_level;
+4 −3
Original line number Diff line number Diff line
@@ -130,9 +130,10 @@ mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw,
						MLX5_FLOW_DEST_VPORT_VHCA_ID;
				if (attr->dests[j].flags & MLX5_ESW_DEST_ENCAP) {
					flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT;
					flow_act.reformat_id = attr->encap_id;
					flow_act.reformat_id = attr->dests[j].encap_id;
					dest[i].vport.flags |= MLX5_FLOW_DEST_VPORT_REFORMAT_ID;
					dest[i].vport.reformat_id = attr->encap_id;
					dest[i].vport.reformat_id =
						attr->dests[j].encap_id;
				}
				i++;
			}
@@ -228,7 +229,7 @@ mlx5_eswitch_add_fwd_rule(struct mlx5_eswitch *esw,
			dest[i].vport.flags |= MLX5_FLOW_DEST_VPORT_VHCA_ID;
		if (attr->dests[i].flags & MLX5_ESW_DEST_ENCAP) {
			dest[i].vport.flags |= MLX5_FLOW_DEST_VPORT_REFORMAT_ID;
			dest[i].vport.reformat_id = attr->encap_id;
			dest[i].vport.reformat_id = attr->dests[i].encap_id;
		}
	}
	dest[i].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;