1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 // Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3
4 #include "act.h"
5 #include "en/tc_priv.h"
6
7 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)8 tc_act_can_offload_police(struct mlx5e_tc_act_parse_state *parse_state,
9 const struct flow_action_entry *act,
10 int act_index,
11 struct mlx5_flow_attr *attr)
12 {
13 if (act->police.notexceed.act_id != FLOW_ACTION_PIPE &&
14 act->police.notexceed.act_id != FLOW_ACTION_ACCEPT) {
15 NL_SET_ERR_MSG_MOD(parse_state->extack,
16 "Offload not supported when conform action is not pipe or ok");
17 return false;
18 }
19 if (mlx5e_policer_validate(parse_state->flow_action, act,
20 parse_state->extack))
21 return false;
22
23 return !!mlx5e_get_flow_meters(parse_state->flow->priv->mdev);
24 }
25
26 static int
fill_meter_params_from_act(const struct flow_action_entry * act,struct mlx5e_flow_meter_params * params)27 fill_meter_params_from_act(const struct flow_action_entry *act,
28 struct mlx5e_flow_meter_params *params)
29 {
30 params->index = act->hw_index;
31 if (act->police.rate_bytes_ps) {
32 params->mode = MLX5_RATE_LIMIT_BPS;
33 /* change rate to bits per second */
34 params->rate = act->police.rate_bytes_ps << 3;
35 params->burst = act->police.burst;
36 } else if (act->police.rate_pkt_ps) {
37 params->mode = MLX5_RATE_LIMIT_PPS;
38 params->rate = act->police.rate_pkt_ps;
39 params->burst = act->police.burst_pkt;
40 } else {
41 return -EOPNOTSUPP;
42 }
43
44 return 0;
45 }
46
47 static int
tc_act_parse_police(struct mlx5e_tc_act_parse_state * parse_state,const struct flow_action_entry * act,struct mlx5e_priv * priv,struct mlx5_flow_attr * attr)48 tc_act_parse_police(struct mlx5e_tc_act_parse_state *parse_state,
49 const struct flow_action_entry *act,
50 struct mlx5e_priv *priv,
51 struct mlx5_flow_attr *attr)
52 {
53 int err;
54
55 err = fill_meter_params_from_act(act, &attr->meter_attr.params);
56 if (err)
57 return err;
58
59 attr->action |= MLX5_FLOW_CONTEXT_ACTION_EXECUTE_ASO;
60 attr->exe_aso_type = MLX5_EXE_ASO_FLOW_METER;
61
62 return 0;
63 }
64
65 static bool
tc_act_is_multi_table_act_police(struct mlx5e_priv * priv,const struct flow_action_entry * act,struct mlx5_flow_attr * attr)66 tc_act_is_multi_table_act_police(struct mlx5e_priv *priv,
67 const struct flow_action_entry *act,
68 struct mlx5_flow_attr *attr)
69 {
70 return true;
71 }
72
73 static int
tc_act_police_offload(struct mlx5e_priv * priv,struct flow_offload_action * fl_act,struct flow_action_entry * act)74 tc_act_police_offload(struct mlx5e_priv *priv,
75 struct flow_offload_action *fl_act,
76 struct flow_action_entry *act)
77 {
78 struct mlx5e_flow_meter_params params = {};
79 struct mlx5e_flow_meter_handle *meter;
80 int err = 0;
81
82 err = mlx5e_policer_validate(&fl_act->action, act, fl_act->extack);
83 if (err)
84 return err;
85
86 err = fill_meter_params_from_act(act, ¶ms);
87 if (err)
88 return err;
89
90 meter = mlx5e_tc_meter_get(priv->mdev, ¶ms);
91 if (IS_ERR(meter) && PTR_ERR(meter) == -ENOENT) {
92 meter = mlx5e_tc_meter_replace(priv->mdev, ¶ms);
93 } else if (!IS_ERR(meter)) {
94 err = mlx5e_tc_meter_update(meter, ¶ms);
95 mlx5e_tc_meter_put(meter);
96 }
97
98 if (IS_ERR(meter)) {
99 NL_SET_ERR_MSG_MOD(fl_act->extack, "Failed to get flow meter");
100 mlx5_core_err(priv->mdev, "Failed to get flow meter %d\n", params.index);
101 err = PTR_ERR(meter);
102 }
103
104 return err;
105 }
106
107 static int
tc_act_police_destroy(struct mlx5e_priv * priv,struct flow_offload_action * fl_act)108 tc_act_police_destroy(struct mlx5e_priv *priv,
109 struct flow_offload_action *fl_act)
110 {
111 struct mlx5e_flow_meter_params params = {};
112 struct mlx5e_flow_meter_handle *meter;
113
114 params.index = fl_act->index;
115 meter = mlx5e_tc_meter_get(priv->mdev, ¶ms);
116 if (IS_ERR(meter)) {
117 NL_SET_ERR_MSG_MOD(fl_act->extack, "Failed to get flow meter");
118 mlx5_core_err(priv->mdev, "Failed to get flow meter %d\n", params.index);
119 return PTR_ERR(meter);
120 }
121 /* first put for the get and second for cleanup */
122 mlx5e_tc_meter_put(meter);
123 mlx5e_tc_meter_put(meter);
124 return 0;
125 }
126
127 static int
tc_act_police_stats(struct mlx5e_priv * priv,struct flow_offload_action * fl_act)128 tc_act_police_stats(struct mlx5e_priv *priv,
129 struct flow_offload_action *fl_act)
130 {
131 struct mlx5e_flow_meter_params params = {};
132 struct mlx5e_flow_meter_handle *meter;
133 u64 bytes, packets, drops, lastuse;
134
135 params.index = fl_act->index;
136 meter = mlx5e_tc_meter_get(priv->mdev, ¶ms);
137 if (IS_ERR(meter)) {
138 NL_SET_ERR_MSG_MOD(fl_act->extack, "Failed to get flow meter");
139 mlx5_core_err(priv->mdev, "Failed to get flow meter %d\n", params.index);
140 return PTR_ERR(meter);
141 }
142
143 mlx5e_tc_meter_get_stats(meter, &bytes, &packets, &drops, &lastuse);
144 flow_stats_update(&fl_act->stats, bytes, packets, drops, lastuse,
145 FLOW_ACTION_HW_STATS_DELAYED);
146 mlx5e_tc_meter_put(meter);
147 return 0;
148 }
149
150 struct mlx5e_tc_act mlx5e_tc_act_police = {
151 .can_offload = tc_act_can_offload_police,
152 .parse_action = tc_act_parse_police,
153 .is_multi_table_act = tc_act_is_multi_table_act_police,
154 .offload_action = tc_act_police_offload,
155 .destroy_action = tc_act_police_destroy,
156 .stats_action = tc_act_police_stats,
157 };
158