net/mlx5e: Parse mirroring action for offloaded TC eswitch flows
[sfrench/cifs-2.6.git] / drivers / net / ethernet / mellanox / mlx5 / core / en_tc.c
index a9c96fe8e4fe3c1751def6685c00e30e149c0d5b..302c5500f9addfcb2dec9a2911df3342e6a6f861 100644 (file)
@@ -844,8 +844,8 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
                }
                out_priv = netdev_priv(encap_dev);
                rpriv = out_priv->ppriv;
-               attr->out_rep = rpriv->rep;
-               attr->out_mdev = out_priv->mdev;
+               attr->out_rep[attr->out_count] = rpriv->rep;
+               attr->out_mdev[attr->out_count++] = out_priv->mdev;
        }
 
        err = mlx5_eswitch_add_vlan_action(esw, attr);
@@ -2537,6 +2537,7 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
                                return err;
 
                        action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
+                       attr->mirror_count = attr->out_count;
                        continue;
                }
 
@@ -2548,12 +2549,18 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
                        return -EOPNOTSUPP;
                }
 
-               if (is_tcf_mirred_egress_redirect(a)) {
-                       struct net_device *out_dev;
+               if (is_tcf_mirred_egress_redirect(a) || is_tcf_mirred_egress_mirror(a)) {
                        struct mlx5e_priv *out_priv;
+                       struct net_device *out_dev;
 
                        out_dev = tcf_mirred_dev(a);
 
+                       if (attr->out_count >= MLX5_MAX_FLOW_FWD_VPORTS) {
+                               pr_err("can't support more than %d output ports, can't offload forwarding\n",
+                                      attr->out_count);
+                               return -EOPNOTSUPP;
+                       }
+
                        if (switchdev_port_same_parent_id(priv->netdev,
                                                          out_dev) ||
                            is_merged_eswitch_dev(priv, out_dev)) {
@@ -2561,8 +2568,8 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
                                          MLX5_FLOW_CONTEXT_ACTION_COUNT;
                                out_priv = netdev_priv(out_dev);
                                rpriv = out_priv->ppriv;
-                               attr->out_rep = rpriv->rep;
-                               attr->out_mdev = out_priv->mdev;
+                               attr->out_rep[attr->out_count] = rpriv->rep;
+                               attr->out_mdev[attr->out_count++] = out_priv->mdev;
                        } else if (encap) {
                                parse_attr->mirred_ifindex = out_dev->ifindex;
                                parse_attr->tun_info = *info;
@@ -2585,6 +2592,7 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
                                encap = true;
                        else
                                return -EOPNOTSUPP;
+                       attr->mirror_count = attr->out_count;
                        continue;
                }
 
@@ -2606,6 +2614,7 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
                        } else { /* action is TCA_VLAN_ACT_MODIFY */
                                return -EOPNOTSUPP;
                        }
+                       attr->mirror_count = attr->out_count;
                        continue;
                }
 
@@ -2621,6 +2630,11 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
        if (!actions_match_supported(priv, exts, parse_attr, flow))
                return -EOPNOTSUPP;
 
+       if (attr->out_count > 1 && !mlx5_esw_has_fwd_fdb(priv->mdev)) {
+               netdev_warn_once(priv->netdev, "current firmware doesn't support split rule for port mirroring\n");
+               return -EOPNOTSUPP;
+       }
+
        return 0;
 }