|
@@ -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;
|
|
@@ -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 };
|
|
@@ -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);
|
|
@@ -109,6 +112,22 @@ err_create_ft:
|
|
|
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)
|
|
|
{
|
|
@@ -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;
|
|
|
}
|
|
@@ -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;
|
|
|
|
|
@@ -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);
|
|
@@ -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)
|