Skip to content

Commit

Permalink
net/mlx5e: Add support for offloading traffic from uplink to uplink
Browse files Browse the repository at this point in the history
Termination tables change the direction of a packet in hw from RX to SX
pipeline. Use that to offload hairpin flows received from uplink and
sent back to uplink.

Currently termination tables are used for pushing VLAN to packets
received from uplink and targeting a VF. Extend the implementation to
allow forwarding packets to uplink. These packets can either be
encapsulated or not.

In case encapsulation is needed before forwarding, move the reformat
object to the termination table as required.

Extend the hash table key to include tunnel information for the sake of
reusing reformat objects.

Signed-off-by: Eli Cohen <eli@mellanox.com>
Reviewed-by: Oz Shlomo <ozsh@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
  • Loading branch information
Eli Cohen authored and Saeed Mahameed committed Mar 18, 2020
1 parent d8a2034 commit 249ccc3
Showing 1 changed file with 70 additions and 27 deletions.
97 changes: 70 additions & 27 deletions drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads_termtbl.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <linux/mlx5/fs.h>
#include "eswitch.h"
#include "fs_core.h"

struct mlx5_termtbl_handle {
struct hlist_node termtbl_hlist;
Expand All @@ -28,6 +29,10 @@ mlx5_eswitch_termtbl_hash(struct mlx5_flow_act *flow_act,
sizeof(dest->vport.num), hash);
hash = jhash((const void *)&dest->vport.vhca_id,
sizeof(dest->vport.num), hash);
if (dest->vport.pkt_reformat)
hash = jhash(dest->vport.pkt_reformat,
sizeof(*dest->vport.pkt_reformat),
hash);
return hash;
}

Expand All @@ -37,11 +42,19 @@ mlx5_eswitch_termtbl_cmp(struct mlx5_flow_act *flow_act1,
struct mlx5_flow_act *flow_act2,
struct mlx5_flow_destination *dest2)
{
return flow_act1->action != flow_act2->action ||
dest1->vport.num != dest2->vport.num ||
dest1->vport.vhca_id != dest2->vport.vhca_id ||
memcmp(&flow_act1->vlan, &flow_act2->vlan,
sizeof(flow_act1->vlan));
int ret;

ret = flow_act1->action != flow_act2->action ||
dest1->vport.num != dest2->vport.num ||
dest1->vport.vhca_id != dest2->vport.vhca_id ||
memcmp(&flow_act1->vlan, &flow_act2->vlan,
sizeof(flow_act1->vlan));
if (ret)
return ret;

return dest1->vport.pkt_reformat && dest2->vport.pkt_reformat ?
memcmp(dest1->vport.pkt_reformat, dest2->vport.pkt_reformat,
sizeof(*dest1->vport.pkt_reformat)) : 0;
}

static int
Expand All @@ -62,7 +75,8 @@ mlx5_eswitch_termtbl_create(struct mlx5_core_dev *dev,
/* As this is the terminating action then the termination table is the
* same prio as the slow path
*/
ft_attr.flags = MLX5_FLOW_TABLE_TERMINATION;
ft_attr.flags = MLX5_FLOW_TABLE_TERMINATION |
MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT;
ft_attr.prio = FDB_SLOW_PATH;
ft_attr.max_fte = 1;
ft_attr.autogroup.max_num_groups = 1;
Expand All @@ -74,7 +88,6 @@ mlx5_eswitch_termtbl_create(struct mlx5_core_dev *dev,

tt->rule = mlx5_add_flow_rules(tt->termtbl, NULL, flow_act,
&tt->dest, 1);

if (IS_ERR(tt->rule)) {
esw_warn(dev, "Failed to create termination table rule\n");
goto add_flow_err;
Expand All @@ -92,15 +105,15 @@ mlx5_eswitch_termtbl_create(struct mlx5_core_dev *dev,
static struct mlx5_termtbl_handle *
mlx5_eswitch_termtbl_get_create(struct mlx5_eswitch *esw,
struct mlx5_flow_act *flow_act,
struct mlx5_flow_destination *dest)
struct mlx5_flow_destination *dest,
struct mlx5_esw_flow_attr *attr)
{
struct mlx5_termtbl_handle *tt;
bool found = false;
u32 hash_key;
int err;

mutex_lock(&esw->offloads.termtbl_mutex);

hash_key = mlx5_eswitch_termtbl_hash(flow_act, dest);
hash_for_each_possible(esw->offloads.termtbl_tbl, tt,
termtbl_hlist, hash_key) {
Expand All @@ -122,6 +135,7 @@ mlx5_eswitch_termtbl_get_create(struct mlx5_eswitch *esw,
tt->dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
tt->dest.vport.num = dest->vport.num;
tt->dest.vport.vhca_id = dest->vport.vhca_id;
tt->dest.vport.flags = dest->vport.flags;
memcpy(&tt->flow_act, flow_act, sizeof(*flow_act));

err = mlx5_eswitch_termtbl_create(esw->dev, tt, flow_act);
Expand Down Expand Up @@ -156,25 +170,44 @@ mlx5_eswitch_termtbl_put(struct mlx5_eswitch *esw,
}
}

static bool mlx5_eswitch_termtbl_is_encap_reformat(struct mlx5_pkt_reformat *rt)
{
switch (rt->reformat_type) {
case MLX5_REFORMAT_TYPE_L2_TO_VXLAN:
case MLX5_REFORMAT_TYPE_L2_TO_NVGRE:
case MLX5_REFORMAT_TYPE_L2_TO_L2_TUNNEL:
case MLX5_REFORMAT_TYPE_L2_TO_L3_TUNNEL:
return true;
default:
return false;
}
}

static void
mlx5_eswitch_termtbl_actions_move(struct mlx5_flow_act *src,
struct mlx5_flow_act *dst)
{
if (!(src->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH))
return;

src->action &= ~MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH;
dst->action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH;
memcpy(&dst->vlan[0], &src->vlan[0], sizeof(src->vlan[0]));
memset(&src->vlan[0], 0, sizeof(src->vlan[0]));

if (!(src->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH_2))
return;
if (src->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH) {
src->action &= ~MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH;
dst->action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH;
memcpy(&dst->vlan[0], &src->vlan[0], sizeof(src->vlan[0]));
memset(&src->vlan[0], 0, sizeof(src->vlan[0]));

if (src->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH_2) {
src->action &= ~MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH_2;
dst->action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH_2;
memcpy(&dst->vlan[1], &src->vlan[1], sizeof(src->vlan[1]));
memset(&src->vlan[1], 0, sizeof(src->vlan[1]));
}
}

src->action &= ~MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH_2;
dst->action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH_2;
memcpy(&dst->vlan[1], &src->vlan[1], sizeof(src->vlan[1]));
memset(&src->vlan[1], 0, sizeof(src->vlan[1]));
if (src->action & MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT &&
mlx5_eswitch_termtbl_is_encap_reformat(src->pkt_reformat)) {
src->action &= ~MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT;
dst->action |= MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT;
dst->pkt_reformat = src->pkt_reformat;
src->pkt_reformat = NULL;
}
}

static bool mlx5_eswitch_offload_is_uplink_port(const struct mlx5_eswitch *esw,
Expand All @@ -199,13 +232,23 @@ mlx5_eswitch_termtbl_required(struct mlx5_eswitch *esw,
struct mlx5_flow_act *flow_act,
struct mlx5_flow_spec *spec)
{
int i;

if (!MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, termination_table) ||
attr->flags & MLX5_ESW_ATTR_FLAG_SLOW_PATH)
attr->flags & MLX5_ESW_ATTR_FLAG_SLOW_PATH ||
!mlx5_eswitch_offload_is_uplink_port(esw, spec))
return false;

/* push vlan on RX */
return (flow_act->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH) &&
mlx5_eswitch_offload_is_uplink_port(esw, spec);
if (flow_act->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH)
return true;

/* hairpin */
for (i = attr->split_count; i < attr->out_count; i++)
if (attr->dests[i].rep->vport == MLX5_VPORT_UPLINK)
return true;

return false;
}

struct mlx5_flow_handle *
Expand Down Expand Up @@ -235,7 +278,7 @@ mlx5_eswitch_add_termtbl_rule(struct mlx5_eswitch *esw,

/* get the terminating table for the action list */
tt = mlx5_eswitch_termtbl_get_create(esw, &term_tbl_act,
&dest[i]);
&dest[i], attr);
if (IS_ERR(tt)) {
esw_warn(esw->dev, "Failed to create termination table\n");
goto revert_changes;
Expand Down

0 comments on commit 249ccc3

Please sign in to comment.