|
@@ -75,12 +75,14 @@ enum {
|
|
|
MLX5E_TC_FLOW_HAIRPIN_RSS = BIT(MLX5E_TC_FLOW_BASE + 4),
|
|
|
};
|
|
|
|
|
|
+#define MLX5E_TC_MAX_SPLITS 1
|
|
|
+
|
|
|
struct mlx5e_tc_flow {
|
|
|
struct rhash_head node;
|
|
|
struct mlx5e_priv *priv;
|
|
|
u64 cookie;
|
|
|
u8 flags;
|
|
|
- struct mlx5_flow_handle *rule;
|
|
|
+ struct mlx5_flow_handle *rule[MLX5E_TC_MAX_SPLITS + 1];
|
|
|
struct list_head encap; /* flows sharing the same encap ID */
|
|
|
struct list_head mod_hdr; /* flows sharing the same mod hdr ID */
|
|
|
struct list_head hairpin; /* flows sharing the same hairpin */
|
|
@@ -794,8 +796,8 @@ static void mlx5e_tc_del_nic_flow(struct mlx5e_priv *priv,
|
|
|
struct mlx5_nic_flow_attr *attr = flow->nic_attr;
|
|
|
struct mlx5_fc *counter = NULL;
|
|
|
|
|
|
- counter = mlx5_flow_rule_counter(flow->rule);
|
|
|
- mlx5_del_flow_rules(flow->rule);
|
|
|
+ counter = mlx5_flow_rule_counter(flow->rule[0]);
|
|
|
+ mlx5_del_flow_rules(flow->rule[0]);
|
|
|
mlx5_fc_destroy(priv->mdev, counter);
|
|
|
|
|
|
if (!mlx5e_tc_num_filters(priv) && priv->fs.tc.t) {
|
|
@@ -870,9 +872,18 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
|
|
|
rule = mlx5_eswitch_add_offloaded_rule(esw, &parse_attr->spec, attr);
|
|
|
if (IS_ERR(rule))
|
|
|
goto err_add_rule;
|
|
|
+
|
|
|
+ if (attr->mirror_count) {
|
|
|
+ flow->rule[1] = mlx5_eswitch_add_fwd_rule(esw, &parse_attr->spec, attr);
|
|
|
+ if (IS_ERR(flow->rule[1]))
|
|
|
+ goto err_fwd_rule;
|
|
|
+ }
|
|
|
}
|
|
|
return rule;
|
|
|
|
|
|
+err_fwd_rule:
|
|
|
+ mlx5_eswitch_del_offloaded_rule(esw, rule, attr);
|
|
|
+ rule = flow->rule[1];
|
|
|
err_add_rule:
|
|
|
if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
|
|
|
mlx5e_detach_mod_hdr(priv, flow);
|
|
@@ -893,7 +904,9 @@ static void mlx5e_tc_del_fdb_flow(struct mlx5e_priv *priv,
|
|
|
|
|
|
if (flow->flags & MLX5E_TC_FLOW_OFFLOADED) {
|
|
|
flow->flags &= ~MLX5E_TC_FLOW_OFFLOADED;
|
|
|
- mlx5_eswitch_del_offloaded_rule(esw, flow->rule, attr);
|
|
|
+ if (attr->mirror_count)
|
|
|
+ mlx5_eswitch_del_offloaded_rule(esw, flow->rule[1], attr);
|
|
|
+ mlx5_eswitch_del_offloaded_rule(esw, flow->rule[0], attr);
|
|
|
}
|
|
|
|
|
|
mlx5_eswitch_del_vlan_action(esw, attr);
|
|
@@ -929,13 +942,25 @@ void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv,
|
|
|
list_for_each_entry(flow, &e->flows, encap) {
|
|
|
esw_attr = flow->esw_attr;
|
|
|
esw_attr->encap_id = e->encap_id;
|
|
|
- flow->rule = mlx5_eswitch_add_offloaded_rule(esw, &esw_attr->parse_attr->spec, esw_attr);
|
|
|
- if (IS_ERR(flow->rule)) {
|
|
|
- err = PTR_ERR(flow->rule);
|
|
|
+ flow->rule[0] = mlx5_eswitch_add_offloaded_rule(esw, &esw_attr->parse_attr->spec, esw_attr);
|
|
|
+ if (IS_ERR(flow->rule[0])) {
|
|
|
+ err = PTR_ERR(flow->rule[0]);
|
|
|
mlx5_core_warn(priv->mdev, "Failed to update cached encapsulation flow, %d\n",
|
|
|
err);
|
|
|
continue;
|
|
|
}
|
|
|
+
|
|
|
+ if (esw_attr->mirror_count) {
|
|
|
+ flow->rule[1] = mlx5_eswitch_add_fwd_rule(esw, &esw_attr->parse_attr->spec, esw_attr);
|
|
|
+ if (IS_ERR(flow->rule[1])) {
|
|
|
+ mlx5_eswitch_del_offloaded_rule(esw, flow->rule[0], esw_attr);
|
|
|
+ err = PTR_ERR(flow->rule[1]);
|
|
|
+ mlx5_core_warn(priv->mdev, "Failed to update cached mirror flow, %d\n",
|
|
|
+ err);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
flow->flags |= MLX5E_TC_FLOW_OFFLOADED;
|
|
|
}
|
|
|
}
|
|
@@ -948,8 +973,12 @@ void mlx5e_tc_encap_flows_del(struct mlx5e_priv *priv,
|
|
|
|
|
|
list_for_each_entry(flow, &e->flows, encap) {
|
|
|
if (flow->flags & MLX5E_TC_FLOW_OFFLOADED) {
|
|
|
+ struct mlx5_esw_flow_attr *attr = flow->esw_attr;
|
|
|
+
|
|
|
flow->flags &= ~MLX5E_TC_FLOW_OFFLOADED;
|
|
|
- mlx5_eswitch_del_offloaded_rule(esw, flow->rule, flow->esw_attr);
|
|
|
+ if (attr->mirror_count)
|
|
|
+ mlx5_eswitch_del_offloaded_rule(esw, flow->rule[1], attr);
|
|
|
+ mlx5_eswitch_del_offloaded_rule(esw, flow->rule[0], attr);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -984,7 +1013,7 @@ void mlx5e_tc_update_neigh_used_value(struct mlx5e_neigh_hash_entry *nhe)
|
|
|
continue;
|
|
|
list_for_each_entry(flow, &e->flows, encap) {
|
|
|
if (flow->flags & MLX5E_TC_FLOW_OFFLOADED) {
|
|
|
- counter = mlx5_flow_rule_counter(flow->rule);
|
|
|
+ counter = mlx5_flow_rule_counter(flow->rule[0]);
|
|
|
mlx5_fc_query_cached(counter, &bytes, &packets, &lastuse);
|
|
|
if (time_after((unsigned long)lastuse, nhe->reported_lastuse)) {
|
|
|
neigh_used = true;
|
|
@@ -2714,16 +2743,16 @@ int mlx5e_configure_flower(struct mlx5e_priv *priv,
|
|
|
err = parse_tc_fdb_actions(priv, f->exts, parse_attr, flow);
|
|
|
if (err < 0)
|
|
|
goto err_free;
|
|
|
- flow->rule = mlx5e_tc_add_fdb_flow(priv, parse_attr, flow);
|
|
|
+ flow->rule[0] = mlx5e_tc_add_fdb_flow(priv, parse_attr, flow);
|
|
|
} else {
|
|
|
err = parse_tc_nic_actions(priv, f->exts, parse_attr, flow);
|
|
|
if (err < 0)
|
|
|
goto err_free;
|
|
|
- flow->rule = mlx5e_tc_add_nic_flow(priv, parse_attr, flow);
|
|
|
+ flow->rule[0] = mlx5e_tc_add_nic_flow(priv, parse_attr, flow);
|
|
|
}
|
|
|
|
|
|
- if (IS_ERR(flow->rule)) {
|
|
|
- err = PTR_ERR(flow->rule);
|
|
|
+ if (IS_ERR(flow->rule[0])) {
|
|
|
+ err = PTR_ERR(flow->rule[0]);
|
|
|
if (err != -EAGAIN)
|
|
|
goto err_free;
|
|
|
}
|
|
@@ -2796,7 +2825,7 @@ int mlx5e_stats_flower(struct mlx5e_priv *priv,
|
|
|
if (!(flow->flags & MLX5E_TC_FLOW_OFFLOADED))
|
|
|
return 0;
|
|
|
|
|
|
- counter = mlx5_flow_rule_counter(flow->rule);
|
|
|
+ counter = mlx5_flow_rule_counter(flow->rule[0]);
|
|
|
if (!counter)
|
|
|
return 0;
|
|
|
|