91b9f618cef3191553c98b08663db2a32a462804
[dpdk.git] / drivers / net / cnxk / cnxk_ethdev_mtr.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(C) 2021 Marvell.
3  */
4
5 #include "cnxk_ethdev.h"
6 #include <rte_mtr_driver.h>
7
8 #define NIX_MTR_COUNT_MAX      73 /* 64(leaf) + 8(mid) + 1(top) */
9 #define NIX_MTR_COUNT_PER_FLOW 3  /* 1(leaf) + 1(mid) + 1(top) */
10
11 static struct rte_mtr_capabilities mtr_capa = {
12         .n_max = NIX_MTR_COUNT_MAX,
13         .n_shared_max = NIX_MTR_COUNT_PER_FLOW,
14         /* .identical = , */
15         .shared_identical = true,
16         /* .shared_n_flows_per_mtr_max = ,*/
17         .chaining_n_mtrs_per_flow_max = NIX_MTR_COUNT_PER_FLOW,
18         .chaining_use_prev_mtr_color_supported = true,
19         .chaining_use_prev_mtr_color_enforced = true,
20         .meter_srtcm_rfc2697_n_max = NIX_MTR_COUNT_MAX,
21         .meter_trtcm_rfc2698_n_max = NIX_MTR_COUNT_MAX,
22         .meter_trtcm_rfc4115_n_max = NIX_MTR_COUNT_MAX,
23         .meter_rate_max = NIX_BPF_RATE_MAX / 8, /* Bytes per second */
24         .meter_policy_n_max = NIX_MTR_COUNT_MAX,
25         .color_aware_srtcm_rfc2697_supported = true,
26         .color_aware_trtcm_rfc2698_supported = true,
27         .color_aware_trtcm_rfc4115_supported = true,
28         .srtcm_rfc2697_byte_mode_supported = true,
29         .srtcm_rfc2697_packet_mode_supported = true,
30         .trtcm_rfc2698_byte_mode_supported = true,
31         .trtcm_rfc2698_packet_mode_supported = true,
32         .trtcm_rfc4115_byte_mode_supported = true,
33         .trtcm_rfc4115_packet_mode_supported = true,
34         .stats_mask = RTE_MTR_STATS_N_PKTS_GREEN | RTE_MTR_STATS_N_PKTS_YELLOW |
35                       RTE_MTR_STATS_N_PKTS_RED | RTE_MTR_STATS_N_PKTS_DROPPED |
36                       RTE_MTR_STATS_N_BYTES_GREEN |
37                       RTE_MTR_STATS_N_BYTES_YELLOW | RTE_MTR_STATS_N_BYTES_RED |
38                       RTE_MTR_STATS_N_BYTES_DROPPED};
39
40 static struct cnxk_mtr_profile_node *
41 nix_mtr_profile_find(struct cnxk_eth_dev *dev, uint32_t profile_id)
42 {
43         struct cnxk_mtr_profiles *fmps = &dev->mtr_profiles;
44         struct cnxk_mtr_profile_node *fmp;
45
46         TAILQ_FOREACH(fmp, fmps, next)
47                 if (profile_id == fmp->id)
48                         return fmp;
49
50         return NULL;
51 }
52
53 static struct cnxk_mtr_policy_node *
54 nix_mtr_policy_find(struct cnxk_eth_dev *dev, uint32_t meter_policy_id)
55 {
56         struct cnxk_mtr_policy *fmps = &dev->mtr_policy;
57         struct cnxk_mtr_policy_node *fmp;
58
59         TAILQ_FOREACH(fmp, fmps, next)
60                 if (meter_policy_id == fmp->id)
61                         return fmp;
62         return NULL;
63 }
64
65 static int
66 nix_mtr_profile_validate(struct cnxk_eth_dev *dev, uint32_t profile_id,
67                          struct rte_mtr_meter_profile *profile,
68                          struct rte_mtr_error *error)
69 {
70         int rc = 0;
71
72         PLT_SET_USED(dev);
73
74         if (profile == NULL)
75                 return -rte_mtr_error_set(error, EINVAL,
76                                           RTE_MTR_ERROR_TYPE_METER_PROFILE,
77                                           NULL, "Meter profile is null.");
78
79         if (profile_id == UINT32_MAX)
80                 return -rte_mtr_error_set(error, EINVAL,
81                                           RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
82                                           NULL, "Meter profile id not valid.");
83
84         switch (profile->alg) {
85         case RTE_MTR_SRTCM_RFC2697:
86                 if (profile->srtcm_rfc2697.cir > mtr_capa.meter_rate_max)
87                         rc = -rte_mtr_error_set(error, EINVAL,
88                                 RTE_MTR_ERROR_TYPE_METER_PROFILE, NULL,
89                                 "CIR exceeds max meter rate");
90
91                 if (profile->srtcm_rfc2697.cbs > NIX_BPF_BURST_MAX)
92                         rc = -rte_mtr_error_set(error, EINVAL,
93                                 RTE_MTR_ERROR_TYPE_METER_PROFILE, NULL,
94                                 "CBS exceeds max meter burst size");
95
96                 if (profile->srtcm_rfc2697.ebs > NIX_BPF_BURST_MAX)
97                         rc = -rte_mtr_error_set(error, EINVAL,
98                                 RTE_MTR_ERROR_TYPE_METER_PROFILE, NULL,
99                                 "EBS exceeds max meter burst size");
100                 break;
101
102         case RTE_MTR_TRTCM_RFC2698:
103                 if (profile->trtcm_rfc2698.cir > mtr_capa.meter_rate_max)
104                         rc = -rte_mtr_error_set(error, EINVAL,
105                                 RTE_MTR_ERROR_TYPE_METER_PROFILE, NULL,
106                                 "CIR exceeds max meter rate");
107
108                 if (profile->trtcm_rfc2698.pir > mtr_capa.meter_rate_max)
109                         rc = -rte_mtr_error_set(error, EINVAL,
110                                 RTE_MTR_ERROR_TYPE_METER_PROFILE, NULL,
111                                 "PIR exceeds max meter rate");
112
113                 if (profile->trtcm_rfc2698.cbs > NIX_BPF_BURST_MAX)
114                         rc = -rte_mtr_error_set(error, EINVAL,
115                                 RTE_MTR_ERROR_TYPE_METER_PROFILE, NULL,
116                                 "CBS exceeds max meter burst size");
117
118                 if (profile->trtcm_rfc2698.pbs > NIX_BPF_BURST_MAX)
119                         rc = -rte_mtr_error_set(error, EINVAL,
120                                 RTE_MTR_ERROR_TYPE_METER_PROFILE, NULL,
121                                 "PBS exceeds max meter burst size");
122                 break;
123
124         case RTE_MTR_TRTCM_RFC4115:
125                 if ((profile->trtcm_rfc4115.cir + profile->trtcm_rfc4115.eir) >
126                     mtr_capa.meter_rate_max)
127                         rc = -rte_mtr_error_set(error, EINVAL,
128                                 RTE_MTR_ERROR_TYPE_METER_PROFILE, NULL,
129                                 "PIR + EIR exceeds max rate");
130
131                 if (profile->trtcm_rfc4115.cbs > NIX_BPF_BURST_MAX)
132                         rc = -rte_mtr_error_set(error, EINVAL,
133                                 RTE_MTR_ERROR_TYPE_METER_PROFILE, NULL,
134                                 "CBS exceeds max meter burst size");
135
136                 if (profile->trtcm_rfc4115.ebs > NIX_BPF_BURST_MAX)
137                         rc = -rte_mtr_error_set(error, EINVAL,
138                                 RTE_MTR_ERROR_TYPE_METER_PROFILE, NULL,
139                                 "PBS exceeds max meter burst size");
140                 break;
141
142         default:
143                 rc = -rte_mtr_error_set(error, EINVAL,
144                                         RTE_MTR_ERROR_TYPE_METER_PROFILE, NULL,
145                                         "alg is invalid");
146                 break;
147         }
148
149         return rc;
150 }
151
152 static int
153 cnxk_nix_mtr_capabilities_get(struct rte_eth_dev *dev,
154                               struct rte_mtr_capabilities *capa,
155                               struct rte_mtr_error *error)
156 {
157         RTE_SET_USED(dev);
158
159         if (!capa)
160                 return -rte_mtr_error_set(error, EINVAL,
161                                           RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
162                                           "NULL input parameter");
163         *capa = mtr_capa;
164         return 0;
165 }
166
167 static int
168 cnxk_nix_mtr_profile_add(struct rte_eth_dev *eth_dev, uint32_t profile_id,
169                          struct rte_mtr_meter_profile *profile,
170                          struct rte_mtr_error *error)
171 {
172         struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
173         struct cnxk_mtr_profiles *fmps = &dev->mtr_profiles;
174         struct cnxk_mtr_profile_node *fmp;
175         int ret;
176
177         /* Check input params. */
178         ret = nix_mtr_profile_validate(dev, profile_id, profile, error);
179         if (ret)
180                 return ret;
181
182         fmp = nix_mtr_profile_find(dev, profile_id);
183         if (fmp) {
184                 return -rte_mtr_error_set(error, EEXIST,
185                                           RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
186                                           NULL, "Profile already exist");
187         }
188
189         fmp = plt_zmalloc(sizeof(struct cnxk_mtr_profile_node), ROC_ALIGN);
190         if (fmp == NULL)
191                 return -rte_mtr_error_set(error, ENOMEM,
192                                           RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
193                                           "Meter profile memory "
194                                           "alloc failed.");
195
196         fmp->id = profile_id;
197         fmp->profile = *profile;
198
199         TAILQ_INSERT_TAIL(fmps, fmp, next);
200
201         return 0;
202 }
203
204 static int
205 cnxk_nix_mtr_profile_delete(struct rte_eth_dev *eth_dev, uint32_t profile_id,
206                             struct rte_mtr_error *error)
207 {
208         struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
209         struct cnxk_mtr_profile_node *fmp;
210
211         if (profile_id == UINT32_MAX)
212                 return -rte_mtr_error_set(error, EINVAL,
213                                           RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
214                                           NULL, "Meter profile id not valid.");
215
216         fmp = nix_mtr_profile_find(dev, profile_id);
217         if (fmp == NULL)
218                 return -rte_mtr_error_set(error, ENOENT,
219                                           RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
220                                           &profile_id,
221                                           "Meter profile is invalid.");
222
223         if (fmp->ref_cnt)
224                 return -rte_mtr_error_set(error, EBUSY,
225                                           RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
226                                           NULL, "Meter profile is in use.");
227
228         TAILQ_REMOVE(&dev->mtr_profiles, fmp, next);
229         plt_free(fmp);
230         return 0;
231 }
232
233 static int
234 cnxk_nix_mtr_policy_validate(struct rte_eth_dev *dev,
235                              struct rte_mtr_meter_policy_params *policy,
236                              struct rte_mtr_error *error)
237 {
238         static const char *const action_color[] = {"Green", "Yellow", "Red"};
239         bool supported[RTE_COLORS] = {false, false, false};
240         const struct rte_flow_action *action;
241         char message[1024];
242         uint32_t i;
243
244         RTE_SET_USED(dev);
245
246         if (!policy)
247                 return 0; /* Nothing to be validated */
248
249         for (i = 0; i < RTE_COLORS; i++) {
250                 if (policy->actions[i]) {
251                         for (action = policy->actions[i];
252                              action->type != RTE_FLOW_ACTION_TYPE_END;
253                              action++) {
254                                 if (action->type == RTE_FLOW_ACTION_TYPE_METER)
255                                         supported[i] = true;
256
257                                 if (action->type == RTE_FLOW_ACTION_TYPE_DROP)
258                                         supported[i] = true;
259
260                                 if (!supported[i]) {
261                                         sprintf(message,
262                                                 "%s action is not valid",
263                                                 action_color[i]);
264                                         return -rte_mtr_error_set(error,
265                                           ENOTSUP,
266                                           RTE_MTR_ERROR_TYPE_METER_POLICY, NULL,
267                                           message);
268                                 }
269                         }
270                 } else {
271                         sprintf(message, "%s action is null", action_color[i]);
272                         return -rte_mtr_error_set(error, EINVAL,
273                                 RTE_MTR_ERROR_TYPE_METER_POLICY, NULL,
274                                 message);
275                 }
276         }
277
278         return 0;
279 }
280
281 static void
282 cnxk_fill_policy_actions(struct cnxk_mtr_policy_node *fmp,
283                          struct rte_mtr_meter_policy_params *policy)
284
285 {
286         const struct rte_flow_action_meter *mtr;
287         const struct rte_flow_action *action;
288         int i;
289
290         for (i = 0; i < RTE_COLORS; i++) {
291                 if (policy->actions[i]) {
292                         for (action = policy->actions[i];
293                              action->type != RTE_FLOW_ACTION_TYPE_END;
294                              action++) {
295                                 if (action->type ==
296                                     RTE_FLOW_ACTION_TYPE_METER) {
297                                         fmp->actions[i].action_fate =
298                                                 action->type;
299                                         mtr = (const struct
300                                                rte_flow_action_meter *)
301                                                       action->conf;
302                                         fmp->actions[i].mtr_id = mtr->mtr_id;
303                                 }
304
305                                 if (action->type == RTE_FLOW_ACTION_TYPE_DROP) {
306                                         fmp->actions[i].action_fate =
307                                                 action->type;
308                                 }
309                         }
310                 }
311         }
312 }
313
314 static int
315 cnxk_nix_mtr_policy_add(struct rte_eth_dev *eth_dev, uint32_t policy_id,
316                         struct rte_mtr_meter_policy_params *policy,
317                         struct rte_mtr_error *error)
318 {
319         struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
320         struct cnxk_mtr_policy *fmps = &dev->mtr_policy;
321         struct cnxk_mtr_policy_node *fmp;
322         int rc;
323
324         fmp = nix_mtr_policy_find(dev, policy_id);
325         if (fmp) {
326                 return -rte_mtr_error_set(error, EEXIST,
327                                           RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
328                                           NULL, "Policy already exist");
329         }
330
331         fmp = plt_zmalloc(sizeof(struct cnxk_mtr_policy_node), ROC_ALIGN);
332         if (fmp == NULL) {
333                 return -rte_mtr_error_set(error, ENOMEM,
334                                           RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
335                                           "Memory allocation failure");
336         } else {
337                 rc = cnxk_nix_mtr_policy_validate(eth_dev, policy, error);
338                 if (rc)
339                         goto exit;
340         }
341
342         fmp->id = policy_id;
343         cnxk_fill_policy_actions(fmp, policy);
344         TAILQ_INSERT_TAIL(fmps, fmp, next);
345         return 0;
346
347 exit:
348         plt_free(fmp);
349         return rc;
350 }
351
352 const struct rte_mtr_ops nix_mtr_ops = {
353         .capabilities_get = cnxk_nix_mtr_capabilities_get,
354         .meter_profile_add = cnxk_nix_mtr_profile_add,
355         .meter_profile_delete = cnxk_nix_mtr_profile_delete,
356         .meter_policy_validate = cnxk_nix_mtr_policy_validate,
357         .meter_policy_add = cnxk_nix_mtr_policy_add,
358 };
359
360 int
361 cnxk_nix_mtr_ops_get(struct rte_eth_dev *dev, void *ops)
362 {
363         RTE_SET_USED(dev);
364
365         *(const void **)ops = &nix_mtr_ops;
366         return 0;
367 }