Skip to content

Commit

Permalink
Merge branch 'mlx5-bulk-flow-stats-sriov-tc-offloads'
Browse files Browse the repository at this point in the history
Saeed Mahameed says:

====================
Mellanox 100G mlx5 Bulk flow statistics and SRIOV TC offloads

This series from Amir and Or deals with two enhancements for the mlx5 TC offloads.

The 1st two patches add bulk reading of flow counters. Few bulk counter queries are
used instead of issuing thousands firmware commands per second to get statistics of all
flows set to HW.

The next patches add TC based SRIOV offloading to mlx5, as a follow up for the e-switch
offloads mode and the VF representors. When the e-switch is set to the (new) "offloads"
mode, we can now offload TC/flower drop and forward rules, the forward action we offload
is TC mirred/redirect.

The above is done by the VF representor netdevices exporting the setup_tc ndo where from
there we're re-using and enhancing the existing mlx5 TC offloads sub-module which now
works for both the NIC and the SRIOV cases.

The series is applied on top b38a75d ('mlxsw: core: Trace EMAD messages')
and it has no merge issues with the on-going net submission ('mlx5 tx timeout watchdog fixes')

V2:
    - Fixed compilation warning.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Jul 14, 2016
2 parents 1801772 + d957b4e commit 53d9489
Show file tree
Hide file tree
Showing 13 changed files with 436 additions and 70 deletions.
40 changes: 39 additions & 1 deletion drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,11 @@
#include <generated/utsrelease.h>
#include <linux/mlx5/fs.h>
#include <net/switchdev.h>
#include <net/pkt_cls.h>

#include "eswitch.h"
#include "en.h"
#include "en_tc.h"

static const char mlx5e_rep_driver_name[] = "mlx5e_rep";

Expand Down Expand Up @@ -201,6 +203,10 @@ void mlx5e_nic_rep_unload(struct mlx5_eswitch *esw,

if (test_bit(MLX5E_STATE_OPENED, &priv->state))
mlx5e_remove_sqs_fwd_rules(priv);

/* clean (and re-init) existing uplink offloaded TC rules */
mlx5e_tc_cleanup(priv);
mlx5e_tc_init(priv);
}

static int mlx5e_rep_get_phys_port_name(struct net_device *dev,
Expand All @@ -217,6 +223,29 @@ static int mlx5e_rep_get_phys_port_name(struct net_device *dev,
return 0;
}

static int mlx5e_rep_ndo_setup_tc(struct net_device *dev, u32 handle,
__be16 proto, struct tc_to_netdev *tc)
{
struct mlx5e_priv *priv = netdev_priv(dev);

if (TC_H_MAJ(handle) != TC_H_MAJ(TC_H_INGRESS))
return -EOPNOTSUPP;

switch (tc->type) {
case TC_SETUP_CLSFLOWER:
switch (tc->cls_flower->command) {
case TC_CLSFLOWER_REPLACE:
return mlx5e_configure_flower(priv, proto, tc->cls_flower);
case TC_CLSFLOWER_DESTROY:
return mlx5e_delete_flower(priv, tc->cls_flower);
case TC_CLSFLOWER_STATS:
return mlx5e_stats_flower(priv, tc->cls_flower);
}
default:
return -EOPNOTSUPP;
}
}

static const struct switchdev_ops mlx5e_rep_switchdev_ops = {
.switchdev_port_attr_get = mlx5e_attr_get,
};
Expand All @@ -226,6 +255,7 @@ static const struct net_device_ops mlx5e_netdev_ops_rep = {
.ndo_stop = mlx5e_close,
.ndo_start_xmit = mlx5e_xmit,
.ndo_get_phys_port_name = mlx5e_rep_get_phys_port_name,
.ndo_setup_tc = mlx5e_rep_ndo_setup_tc,
.ndo_get_stats64 = mlx5e_get_stats,
};

Expand Down Expand Up @@ -279,7 +309,8 @@ static void mlx5e_build_rep_netdev(struct net_device *netdev)
netdev->switchdev_ops = &mlx5e_rep_switchdev_ops;
#endif

netdev->features |= NETIF_F_VLAN_CHALLENGED;
netdev->features |= NETIF_F_VLAN_CHALLENGED | NETIF_F_HW_TC;
netdev->hw_features |= NETIF_F_HW_TC;

eth_hw_addr_random(netdev);
}
Expand Down Expand Up @@ -323,8 +354,14 @@ static int mlx5e_init_rep_rx(struct mlx5e_priv *priv)
}
rep->vport_rx_rule = flow_rule;

err = mlx5e_tc_init(priv);
if (err)
goto err_del_flow_rule;

return 0;

err_del_flow_rule:
mlx5_del_flow_rule(rep->vport_rx_rule);
err_destroy_direct_tirs:
mlx5e_destroy_direct_tirs(priv);
err_destroy_direct_rqts:
Expand All @@ -338,6 +375,7 @@ static void mlx5e_cleanup_rep_rx(struct mlx5e_priv *priv)
struct mlx5_eswitch_rep *rep = priv->ppriv;
int i;

mlx5e_tc_cleanup(priv);
mlx5_del_flow_rule(rep->vport_rx_rule);
mlx5e_destroy_direct_tirs(priv);
for (i = 0; i < priv->params.num_channels; i++)
Expand Down
116 changes: 96 additions & 20 deletions drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,11 @@
#include <linux/mlx5/fs.h>
#include <linux/mlx5/device.h>
#include <linux/rhashtable.h>
#include <net/switchdev.h>
#include <net/tc_act/tc_mirred.h>
#include "en.h"
#include "en_tc.h"
#include "eswitch.h"

struct mlx5e_tc_flow {
struct rhash_head node;
Expand All @@ -49,9 +52,9 @@ struct mlx5e_tc_flow {
#define MLX5E_TC_TABLE_NUM_ENTRIES 1024
#define MLX5E_TC_TABLE_NUM_GROUPS 4

static struct mlx5_flow_rule *mlx5e_tc_add_flow(struct mlx5e_priv *priv,
struct mlx5_flow_spec *spec,
u32 action, u32 flow_tag)
static struct mlx5_flow_rule *mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv,
struct mlx5_flow_spec *spec,
u32 action, u32 flow_tag)
{
struct mlx5_core_dev *dev = priv->mdev;
struct mlx5_flow_destination dest = { 0 };
Expand All @@ -62,7 +65,7 @@ static struct mlx5_flow_rule *mlx5e_tc_add_flow(struct mlx5e_priv *priv,
if (action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) {
dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
dest.ft = priv->fs.vlan.ft.t;
} else {
} else if (action & MLX5_FLOW_CONTEXT_ACTION_COUNT) {
counter = mlx5_fc_create(dev, true);
if (IS_ERR(counter))
return ERR_CAST(counter);
Expand Down Expand Up @@ -109,6 +112,22 @@ static struct mlx5_flow_rule *mlx5e_tc_add_flow(struct mlx5e_priv *priv,
return rule;
}

static struct mlx5_flow_rule *mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
struct mlx5_flow_spec *spec,
u32 action, u32 dst_vport)
{
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
struct mlx5_eswitch_rep *rep = priv->ppriv;
u32 src_vport;

if (rep->vport) /* set source vport for the flow */
src_vport = rep->vport;
else
src_vport = FDB_UPLINK_VPORT;

return mlx5_eswitch_add_offloaded_rule(esw, spec, action, src_vport, dst_vport);
}

static void mlx5e_tc_del_flow(struct mlx5e_priv *priv,
struct mlx5_flow_rule *rule)
{
Expand All @@ -120,7 +139,7 @@ static void mlx5e_tc_del_flow(struct mlx5e_priv *priv,

mlx5_fc_destroy(priv->mdev, counter);

if (!mlx5e_tc_num_filters(priv)) {
if (!mlx5e_tc_num_filters(priv) && (priv->fs.tc.t)) {
mlx5_destroy_flow_table(priv->fs.tc.t);
priv->fs.tc.t = NULL;
}
Expand Down Expand Up @@ -295,8 +314,8 @@ static int parse_cls_flower(struct mlx5e_priv *priv, struct mlx5_flow_spec *spec
return 0;
}

static int parse_tc_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
u32 *action, u32 *flow_tag)
static int parse_tc_nic_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
u32 *action, u32 *flow_tag)
{
const struct tc_action *a;

Expand Down Expand Up @@ -339,16 +358,66 @@ static int parse_tc_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
return 0;
}

static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
u32 *action, u32 *dest_vport)
{
const struct tc_action *a;

if (tc_no_actions(exts))
return -EINVAL;

*action = 0;

tc_for_each_action(a, exts) {
/* Only support a single action per rule */
if (*action)
return -EINVAL;

if (is_tcf_gact_shot(a)) {
*action = MLX5_FLOW_CONTEXT_ACTION_DROP |
MLX5_FLOW_CONTEXT_ACTION_COUNT;
continue;
}

if (is_tcf_mirred_redirect(a)) {
int ifindex = tcf_mirred_ifindex(a);
struct net_device *out_dev;
struct mlx5e_priv *out_priv;
struct mlx5_eswitch_rep *out_rep;

out_dev = __dev_get_by_index(dev_net(priv->netdev), ifindex);

if (!switchdev_port_same_parent_id(priv->netdev, out_dev)) {
pr_err("devices %s %s not on same switch HW, can't offload forwarding\n",
priv->netdev->name, out_dev->name);
return -EINVAL;
}

out_priv = netdev_priv(out_dev);
out_rep = out_priv->ppriv;
if (out_rep->vport == 0)
*dest_vport = FDB_UPLINK_VPORT;
else
*dest_vport = out_rep->vport;
*action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
continue;
}

return -EINVAL;
}
return 0;
}

int mlx5e_configure_flower(struct mlx5e_priv *priv, __be16 protocol,
struct tc_cls_flower_offload *f)
{
struct mlx5e_tc_table *tc = &priv->fs.tc;
int err = 0;
u32 flow_tag;
u32 action;
u32 flow_tag, action, dest_vport = 0;
struct mlx5e_tc_flow *flow;
struct mlx5_flow_spec *spec;
struct mlx5_flow_rule *old = NULL;
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;

flow = rhashtable_lookup_fast(&tc->ht, &f->cookie,
tc->ht_params);
Expand All @@ -369,28 +438,35 @@ int mlx5e_configure_flower(struct mlx5e_priv *priv, __be16 protocol,
if (err < 0)
goto err_free;

err = parse_tc_actions(priv, f->exts, &action, &flow_tag);
if (err < 0)
if (esw && esw->mode == SRIOV_OFFLOADS) {
err = parse_tc_fdb_actions(priv, f->exts, &action, &dest_vport);
if (err < 0)
goto err_free;
flow->rule = mlx5e_tc_add_fdb_flow(priv, spec, action, dest_vport);
} else {
err = parse_tc_nic_actions(priv, f->exts, &action, &flow_tag);
if (err < 0)
goto err_free;
flow->rule = mlx5e_tc_add_nic_flow(priv, spec, action, flow_tag);
}

if (IS_ERR(flow->rule)) {
err = PTR_ERR(flow->rule);
goto err_free;
}

err = rhashtable_insert_fast(&tc->ht, &flow->node,
tc->ht_params);
if (err)
goto err_free;

flow->rule = mlx5e_tc_add_flow(priv, spec, action, flow_tag);
if (IS_ERR(flow->rule)) {
err = PTR_ERR(flow->rule);
goto err_hash_del;
}
goto err_del_rule;

if (old)
mlx5e_tc_del_flow(priv, old);

goto out;

err_hash_del:
rhashtable_remove_fast(&tc->ht, &flow->node, tc->ht_params);
err_del_rule:
mlx5_del_flow_rule(flow->rule);

err_free:
if (!old)
Expand Down
7 changes: 7 additions & 0 deletions drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ struct mlx5_eswitch_fdb {
} legacy;

struct offloads_fdb {
struct mlx5_flow_table *fdb;
struct mlx5_flow_group *send_to_vport_grp;
struct mlx5_flow_group *miss_grp;
struct mlx5_flow_rule *miss_rule;
Expand Down Expand Up @@ -221,6 +222,12 @@ int mlx5_eswitch_get_vport_stats(struct mlx5_eswitch *esw,
int vport,
struct ifla_vf_stats *vf_stats);

struct mlx5_flow_spec;

struct mlx5_flow_rule *
mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw,
struct mlx5_flow_spec *spec,
u32 action, u32 src_vport, u32 dst_vport);
struct mlx5_flow_rule *
mlx5_eswitch_create_vport_rx_rule(struct mlx5_eswitch *esw, int vport, u32 tirn);

Expand Down
Loading

0 comments on commit 53d9489

Please sign in to comment.