Commit ddda6326 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'mlx5-Support-tc-police-jump-conform-exceed-attribute'

Saeed Mahameed says:

====================
Support tc police jump conform-exceed attribute

The tc police action conform-exceed option defines how to handle
packets which exceed or conform to the configured bandwidth limit.
One of the possible conform-exceed values is jump, which skips over
a specified number of actions.
This series adds support for conform-exceed jump action.

The series adds platform support for branching actions by providing
true/false flow attributes to the branching action.
This is necessary for supporting police jump, as each branch may
execute a different action list.

The first five patches are preparation patches:
- Patches 1 and 2 add support for actions with no destinations (e.g. drop)
- Patch 3 refactor the code for subsequent function reuse
- Patch 4 defines an abstract way for identifying terminating actions
- Patch 5 updates action list validations logic considering branching actions

The following three patches introduce an interface for abstracting branching
actions:
- Patch 6 introduces an abstract api for defining branching actions
- Patch 7 generically instantiates the branching flow attributes using
  the abstract API

Patch 8 adds the platform support for jump actions, by executing the following
sequence:
  a. Store the jumping flow attr
  b. Identify the jump target action while iterating the actions list.
  c. Instantiate a new flow attribute after the jump target action.
     This is the flow attribute that the branching action should jump to.
  d. Set the target post action id on:
    d.1. The jumping attribute, thus realizing the jump functionality.
    d.2. The attribute preceding the target jump attr, if not terminating.

The next patches apply the platform's branching attributes to the police
action:
- Patch 9 is a refactor patch
- Patch 10 initializes the post meter table with the red/green flow attributes,
           as were initialized by the platform
- Patch 11 enables the offload of meter actions using jump conform-exceed
           value.
====================

Link: https://lore.kernel.org/all/20221203221337.29267-1-saeed@kernel.org/Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents bde55dd9 3603f266
......@@ -28,4 +28,5 @@ tc_act_parse_accept(struct mlx5e_tc_act_parse_state *parse_state,
struct mlx5e_tc_act mlx5e_tc_act_accept = {
.can_offload = tc_act_can_offload_accept,
.parse_action = tc_act_parse_accept,
.is_terminating_action = true,
};
......@@ -11,7 +11,7 @@ static struct mlx5e_tc_act *tc_acts_fdb[NUM_FLOW_ACTIONS] = {
[FLOW_ACTION_DROP] = &mlx5e_tc_act_drop,
[FLOW_ACTION_TRAP] = &mlx5e_tc_act_trap,
[FLOW_ACTION_GOTO] = &mlx5e_tc_act_goto,
[FLOW_ACTION_REDIRECT] = &mlx5e_tc_act_mirred,
[FLOW_ACTION_REDIRECT] = &mlx5e_tc_act_redirect,
[FLOW_ACTION_MIRRED] = &mlx5e_tc_act_mirred,
[FLOW_ACTION_REDIRECT_INGRESS] = &mlx5e_tc_act_redirect_ingress,
[FLOW_ACTION_VLAN_PUSH] = &mlx5e_tc_act_vlan,
......
......@@ -32,6 +32,11 @@ struct mlx5e_tc_act_parse_state {
struct mlx5_tc_ct_priv *ct_priv;
};
struct mlx5e_tc_act_branch_ctrl {
enum flow_action_id act_id;
u32 extval;
};
struct mlx5e_tc_act {
bool (*can_offload)(struct mlx5e_tc_act_parse_state *parse_state,
const struct flow_action_entry *act,
......@@ -60,6 +65,12 @@ struct mlx5e_tc_act {
int (*stats_action)(struct mlx5e_priv *priv,
struct flow_offload_action *fl_act);
bool (*get_branch_ctrl)(const struct flow_action_entry *act,
struct mlx5e_tc_act_branch_ctrl *cond_true,
struct mlx5e_tc_act_branch_ctrl *cond_false);
bool is_terminating_action;
};
struct mlx5e_tc_flow_action {
......@@ -81,6 +92,7 @@ extern struct mlx5e_tc_act mlx5e_tc_act_vlan_mangle;
extern struct mlx5e_tc_act mlx5e_tc_act_mpls_push;
extern struct mlx5e_tc_act mlx5e_tc_act_mpls_pop;
extern struct mlx5e_tc_act mlx5e_tc_act_mirred;
extern struct mlx5e_tc_act mlx5e_tc_act_redirect;
extern struct mlx5e_tc_act mlx5e_tc_act_mirred_nic;
extern struct mlx5e_tc_act mlx5e_tc_act_ct;
extern struct mlx5e_tc_act mlx5e_tc_act_sample;
......
......@@ -27,4 +27,5 @@ tc_act_parse_drop(struct mlx5e_tc_act_parse_state *parse_state,
struct mlx5e_tc_act mlx5e_tc_act_drop = {
.can_offload = tc_act_can_offload_drop,
.parse_action = tc_act_parse_drop,
.is_terminating_action = true,
};
......@@ -121,4 +121,5 @@ struct mlx5e_tc_act mlx5e_tc_act_goto = {
.can_offload = tc_act_can_offload_goto,
.parse_action = tc_act_parse_goto,
.post_parse = tc_act_post_parse_goto,
.is_terminating_action = true,
};
......@@ -334,4 +334,11 @@ tc_act_parse_mirred(struct mlx5e_tc_act_parse_state *parse_state,
struct mlx5e_tc_act mlx5e_tc_act_mirred = {
.can_offload = tc_act_can_offload_mirred,
.parse_action = tc_act_parse_mirred,
.is_terminating_action = false,
};
struct mlx5e_tc_act mlx5e_tc_act_redirect = {
.can_offload = tc_act_can_offload_mirred,
.parse_action = tc_act_parse_mirred,
.is_terminating_action = true,
};
......@@ -48,4 +48,5 @@ tc_act_parse_mirred_nic(struct mlx5e_tc_act_parse_state *parse_state,
struct mlx5e_tc_act mlx5e_tc_act_mirred_nic = {
.can_offload = tc_act_can_offload_mirred_nic,
.parse_action = tc_act_parse_mirred_nic,
.is_terminating_action = true,
};
......@@ -4,20 +4,54 @@
#include "act.h"
#include "en/tc_priv.h"
static bool police_act_validate_control(enum flow_action_id act_id,
struct netlink_ext_ack *extack)
{
if (act_id != FLOW_ACTION_PIPE &&
act_id != FLOW_ACTION_ACCEPT &&
act_id != FLOW_ACTION_JUMP &&
act_id != FLOW_ACTION_DROP) {
NL_SET_ERR_MSG_MOD(extack,
"Offload not supported when conform-exceed action is not pipe, ok, jump or drop");
return false;
}
return true;
}
static int police_act_validate(const struct flow_action_entry *act,
struct netlink_ext_ack *extack)
{
if (!police_act_validate_control(act->police.exceed.act_id, extack) ||
!police_act_validate_control(act->police.notexceed.act_id, extack))
return -EOPNOTSUPP;
if (act->police.peakrate_bytes_ps ||
act->police.avrate || act->police.overhead) {
NL_SET_ERR_MSG_MOD(extack,
"Offload not supported when peakrate/avrate/overhead is configured");
return -EOPNOTSUPP;
}
if (act->police.rate_pkt_ps) {
NL_SET_ERR_MSG_MOD(extack,
"QoS offload not support packets per second");
return -EOPNOTSUPP;
}
return 0;
}
static bool
tc_act_can_offload_police(struct mlx5e_tc_act_parse_state *parse_state,
const struct flow_action_entry *act,
int act_index,
struct mlx5_flow_attr *attr)
{
if (act->police.notexceed.act_id != FLOW_ACTION_PIPE &&
act->police.notexceed.act_id != FLOW_ACTION_ACCEPT) {
NL_SET_ERR_MSG_MOD(parse_state->extack,
"Offload not supported when conform action is not pipe or ok");
return false;
}
if (mlx5e_policer_validate(parse_state->flow_action, act,
parse_state->extack))
int err;
err = police_act_validate(act, parse_state->extack);
if (err)
return false;
return !!mlx5e_get_flow_meters(parse_state->flow->priv->mdev);
......@@ -79,7 +113,7 @@ tc_act_police_offload(struct mlx5e_priv *priv,
struct mlx5e_flow_meter_handle *meter;
int err = 0;
err = mlx5e_policer_validate(&fl_act->action, act, fl_act->extack);
err = police_act_validate(act, fl_act->extack);
if (err)
return err;
......@@ -147,6 +181,19 @@ tc_act_police_stats(struct mlx5e_priv *priv,
return 0;
}
static bool
tc_act_police_get_branch_ctrl(const struct flow_action_entry *act,
struct mlx5e_tc_act_branch_ctrl *cond_true,
struct mlx5e_tc_act_branch_ctrl *cond_false)
{
cond_true->act_id = act->police.notexceed.act_id;
cond_true->extval = act->police.notexceed.extval;
cond_false->act_id = act->police.exceed.act_id;
cond_false->extval = act->police.exceed.extval;
return true;
}
struct mlx5e_tc_act mlx5e_tc_act_police = {
.can_offload = tc_act_can_offload_police,
.parse_action = tc_act_parse_police,
......@@ -154,4 +201,5 @@ struct mlx5e_tc_act mlx5e_tc_act_police = {
.offload_action = tc_act_police_offload,
.destroy_action = tc_act_police_destroy,
.stats_action = tc_act_police_stats,
.get_branch_ctrl = tc_act_police_get_branch_ctrl,
};
......@@ -257,16 +257,16 @@ __mlx5e_flow_meter_alloc(struct mlx5e_flow_meters *flow_meters)
counter = mlx5_fc_create(mdev, true);
if (IS_ERR(counter)) {
err = PTR_ERR(counter);
goto err_red_counter;
goto err_drop_counter;
}
meter->red_counter = counter;
meter->drop_counter = counter;
counter = mlx5_fc_create(mdev, true);
if (IS_ERR(counter)) {
err = PTR_ERR(counter);
goto err_green_counter;
goto err_act_counter;
}
meter->green_counter = counter;
meter->act_counter = counter;
meters_obj = list_first_entry_or_null(&flow_meters->partial_list,
struct mlx5e_flow_meter_aso_obj,
......@@ -313,10 +313,10 @@ __mlx5e_flow_meter_alloc(struct mlx5e_flow_meters *flow_meters)
err_mem:
mlx5e_flow_meter_destroy_aso_obj(mdev, id);
err_create:
mlx5_fc_destroy(mdev, meter->green_counter);
err_green_counter:
mlx5_fc_destroy(mdev, meter->red_counter);
err_red_counter:
mlx5_fc_destroy(mdev, meter->act_counter);
err_act_counter:
mlx5_fc_destroy(mdev, meter->drop_counter);
err_drop_counter:
kfree(meter);
return ERR_PTR(err);
}
......@@ -329,8 +329,8 @@ __mlx5e_flow_meter_free(struct mlx5e_flow_meter_handle *meter)
struct mlx5e_flow_meter_aso_obj *meters_obj;
int n, pos;
mlx5_fc_destroy(mdev, meter->green_counter);
mlx5_fc_destroy(mdev, meter->red_counter);
mlx5_fc_destroy(mdev, meter->act_counter);
mlx5_fc_destroy(mdev, meter->drop_counter);
meters_obj = meter->meters_obj;
pos = (meter->obj_id - meters_obj->base_id) * 2 + meter->idx;
......@@ -575,8 +575,8 @@ mlx5e_tc_meter_get_stats(struct mlx5e_flow_meter_handle *meter,
u64 bytes1, packets1, lastuse1;
u64 bytes2, packets2, lastuse2;
mlx5_fc_query_cached(meter->green_counter, &bytes1, &packets1, &lastuse1);
mlx5_fc_query_cached(meter->red_counter, &bytes2, &packets2, &lastuse2);
mlx5_fc_query_cached(meter->act_counter, &bytes1, &packets1, &lastuse1);
mlx5_fc_query_cached(meter->drop_counter, &bytes2, &packets2, &lastuse2);
*bytes = bytes1 + bytes2;
*packets = packets1 + packets2;
......
......@@ -32,8 +32,8 @@ struct mlx5e_flow_meter_handle {
struct hlist_node hlist;
struct mlx5e_flow_meter_params params;
struct mlx5_fc *green_counter;
struct mlx5_fc *red_counter;
struct mlx5_fc *act_counter;
struct mlx5_fc *drop_counter;
};
struct mlx5e_meter_attr {
......
......@@ -11,8 +11,10 @@
struct mlx5e_post_meter_priv {
struct mlx5_flow_table *ft;
struct mlx5_flow_group *fg;
struct mlx5_flow_handle *fwd_green_rule;
struct mlx5_flow_handle *drop_red_rule;
struct mlx5_flow_handle *green_rule;
struct mlx5_flow_attr *green_attr;
struct mlx5_flow_handle *red_rule;
struct mlx5_flow_attr *red_attr;
};
struct mlx5_flow_table *
......@@ -81,15 +83,48 @@ mlx5e_post_meter_fg_create(struct mlx5e_priv *priv,
return err;
}
static struct mlx5_flow_handle *
mlx5e_post_meter_add_rule(struct mlx5e_priv *priv,
struct mlx5e_post_meter_priv *post_meter,
struct mlx5_flow_spec *spec,
struct mlx5_flow_attr *attr,
struct mlx5_fc *act_counter,
struct mlx5_fc *drop_counter)
{
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
struct mlx5_flow_handle *ret;
attr->action |= MLX5_FLOW_CONTEXT_ACTION_COUNT;
if (attr->action & MLX5_FLOW_CONTEXT_ACTION_DROP)
attr->counter = drop_counter;
else
attr->counter = act_counter;
attr->ft = post_meter->ft;
attr->flags |= MLX5_ATTR_FLAG_NO_IN_PORT;
attr->outer_match_level = MLX5_MATCH_NONE;
attr->chain = 0;
attr->prio = 0;
ret = mlx5_eswitch_add_offloaded_rule(esw, spec, attr);
/* We did not create the counter, so we can't delete it.
* Avoid freeing the counter when the attr is deleted in free_branching_attr
*/
attr->action &= ~MLX5_FLOW_CONTEXT_ACTION_COUNT;
return ret;
}
static int
mlx5e_post_meter_rules_create(struct mlx5e_priv *priv,
struct mlx5e_post_meter_priv *post_meter,
struct mlx5e_post_act *post_act,
struct mlx5_fc *green_counter,
struct mlx5_fc *red_counter)
struct mlx5_fc *act_counter,
struct mlx5_fc *drop_counter,
struct mlx5_flow_attr *green_attr,
struct mlx5_flow_attr *red_attr)
{
struct mlx5_flow_destination dest[2] = {};
struct mlx5_flow_act flow_act = {};
struct mlx5_flow_handle *rule;
struct mlx5_flow_spec *spec;
int err;
......@@ -100,52 +135,45 @@ mlx5e_post_meter_rules_create(struct mlx5e_priv *priv,
mlx5e_tc_match_to_reg_match(spec, PACKET_COLOR_TO_REG,
MLX5_FLOW_METER_COLOR_RED, MLX5_PACKET_COLOR_MASK);
flow_act.action = MLX5_FLOW_CONTEXT_ACTION_DROP |
MLX5_FLOW_CONTEXT_ACTION_COUNT;
flow_act.flags |= FLOW_ACT_IGNORE_FLOW_LEVEL;
dest[0].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
dest[0].counter_id = mlx5_fc_id(red_counter);
rule = mlx5_add_flow_rules(post_meter->ft, spec, &flow_act, dest, 1);
rule = mlx5e_post_meter_add_rule(priv, post_meter, spec, red_attr,
act_counter, drop_counter);
if (IS_ERR(rule)) {
mlx5_core_warn(priv->mdev, "Failed to create post_meter flow drop rule\n");
mlx5_core_warn(priv->mdev, "Failed to create post_meter exceed rule\n");
err = PTR_ERR(rule);
goto err_red;
}
post_meter->drop_red_rule = rule;
post_meter->red_rule = rule;
post_meter->red_attr = red_attr;
mlx5e_tc_match_to_reg_match(spec, PACKET_COLOR_TO_REG,
MLX5_FLOW_METER_COLOR_GREEN, MLX5_PACKET_COLOR_MASK);
flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
MLX5_FLOW_CONTEXT_ACTION_COUNT;
dest[0].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
dest[0].ft = mlx5e_tc_post_act_get_ft(post_act);
dest[1].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
dest[1].counter_id = mlx5_fc_id(green_counter);
rule = mlx5_add_flow_rules(post_meter->ft, spec, &flow_act, dest, 2);
rule = mlx5e_post_meter_add_rule(priv, post_meter, spec, green_attr,
act_counter, drop_counter);
if (IS_ERR(rule)) {
mlx5_core_warn(priv->mdev, "Failed to create post_meter flow fwd rule\n");
mlx5_core_warn(priv->mdev, "Failed to create post_meter notexceed rule\n");
err = PTR_ERR(rule);
goto err_green;
}
post_meter->fwd_green_rule = rule;
post_meter->green_rule = rule;
post_meter->green_attr = green_attr;
kvfree(spec);
return 0;
err_green:
mlx5_del_flow_rules(post_meter->drop_red_rule);
mlx5_del_flow_rules(post_meter->red_rule);
err_red:
kvfree(spec);
return err;
}
static void
mlx5e_post_meter_rules_destroy(struct mlx5e_post_meter_priv *post_meter)
mlx5e_post_meter_rules_destroy(struct mlx5_eswitch *esw,
struct mlx5e_post_meter_priv *post_meter)
{
mlx5_del_flow_rules(post_meter->drop_red_rule);
mlx5_del_flow_rules(post_meter->fwd_green_rule);
mlx5_eswitch_del_offloaded_rule(esw, post_meter->red_rule, post_meter->red_attr);
mlx5_eswitch_del_offloaded_rule(esw, post_meter->green_rule, post_meter->green_attr);
}
static void
......@@ -164,8 +192,10 @@ struct mlx5e_post_meter_priv *
mlx5e_post_meter_init(struct mlx5e_priv *priv,
enum mlx5_flow_namespace_type ns_type,
struct mlx5e_post_act *post_act,
struct mlx5_fc *green_counter,
struct mlx5_fc *red_counter)
struct mlx5_fc *act_counter,
struct mlx5_fc *drop_counter,
struct mlx5_flow_attr *branch_true,
struct mlx5_flow_attr *branch_false)
{
struct mlx5e_post_meter_priv *post_meter;
int err;
......@@ -182,8 +212,8 @@ mlx5e_post_meter_init(struct mlx5e_priv *priv,
if (err)
goto err_fg;
err = mlx5e_post_meter_rules_create(priv, post_meter, post_act, green_counter,
red_counter);
err = mlx5e_post_meter_rules_create(priv, post_meter, post_act, act_counter,
drop_counter, branch_true, branch_false);
if (err)
goto err_rules;
......@@ -199,9 +229,9 @@ mlx5e_post_meter_init(struct mlx5e_priv *priv,
}
void
mlx5e_post_meter_cleanup(struct mlx5e_post_meter_priv *post_meter)
mlx5e_post_meter_cleanup(struct mlx5_eswitch *esw, struct mlx5e_post_meter_priv *post_meter)
{
mlx5e_post_meter_rules_destroy(post_meter);
mlx5e_post_meter_rules_destroy(esw, post_meter);
mlx5e_post_meter_fg_destroy(post_meter);
mlx5e_post_meter_table_destroy(post_meter);
kfree(post_meter);
......
......@@ -21,9 +21,11 @@ struct mlx5e_post_meter_priv *
mlx5e_post_meter_init(struct mlx5e_priv *priv,
enum mlx5_flow_namespace_type ns_type,
struct mlx5e_post_act *post_act,
struct mlx5_fc *green_counter,
struct mlx5_fc *red_counter);
struct mlx5_fc *act_counter,
struct mlx5_fc *drop_counter,
struct mlx5_flow_attr *branch_true,
struct mlx5_flow_attr *branch_false);
void
mlx5e_post_meter_cleanup(struct mlx5e_post_meter_priv *post_meter);
mlx5e_post_meter_cleanup(struct mlx5_eswitch *esw, struct mlx5e_post_meter_priv *post_meter);
#endif /* __MLX5_EN_POST_METER_H__ */
......@@ -211,8 +211,4 @@ struct mlx5e_flow_meters *mlx5e_get_flow_meters(struct mlx5_core_dev *dev);
void *mlx5e_get_match_headers_value(u32 flags, struct mlx5_flow_spec *spec);
void *mlx5e_get_match_headers_criteria(u32 flags, struct mlx5_flow_spec *spec);
int mlx5e_policer_validate(const struct flow_action *action,
const struct flow_action_entry *act,
struct netlink_ext_ack *extack);
#endif /* __MLX5_EN_TC_PRIV_H__ */
......@@ -95,6 +95,9 @@ struct mlx5_flow_attr {
*/
bool count;
} lag;
struct mlx5_flow_attr *branch_true;
struct mlx5_flow_attr *branch_false;
struct mlx5_flow_attr *jumping_attr;
/* keep this union last */
union {
DECLARE_FLEX_ARRAY(struct mlx5_esw_flow_attr, esw_attr);
......@@ -110,6 +113,7 @@ enum {
MLX5_ATTR_FLAG_SAMPLE = BIT(4),
MLX5_ATTR_FLAG_ACCEPT = BIT(5),
MLX5_ATTR_FLAG_CT = BIT(6),
MLX5_ATTR_FLAG_TERMINATING = BIT(7),
};
/* Returns true if any of the flags that require skipping further TC/NF processing are set. */
......
......@@ -640,6 +640,11 @@ mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw,
goto err_esw_get;
}
if (!i) {
kfree(dest);
dest = NULL;
}
if (mlx5_eswitch_termtbl_required(esw, attr, &flow_act, spec))
rule = mlx5_eswitch_add_termtbl_rule(esw, fdb, spec, esw_attr,
&flow_act, dest, i);
......
......@@ -1962,6 +1962,9 @@ _mlx5_add_flow_rules(struct mlx5_flow_table *ft,
if (flow_act->fg && ft->autogroup.active)
return ERR_PTR(-EINVAL);
if (dest && dest_num <= 0)
return ERR_PTR(-EINVAL);
for (i = 0; i < dest_num; i++) {
if (!dest_is_valid(&dest[i], flow_act, ft))
return ERR_PTR(-EINVAL);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment