1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2018 Intel Corporation
3  */
4 
5 #include <stdint.h>
6 #include <stdlib.h>
7 #include <string.h>
8 
9 #include <rte_mtr.h>
10 #include <rte_mtr_driver.h>
11 
12 #include "rte_eth_softnic_internals.h"
13 
14 int
softnic_mtr_init(struct pmd_internals * p)15 softnic_mtr_init(struct pmd_internals *p)
16 {
17 	/* Initialize meter profiles list */
18 	TAILQ_INIT(&p->mtr.meter_profiles);
19 
20 	/* Initialize meter policies list */
21 	TAILQ_INIT(&p->mtr.meter_policies);
22 
23 	/* Initialize MTR objects list */
24 	TAILQ_INIT(&p->mtr.mtrs);
25 
26 	return 0;
27 }
28 
29 void
softnic_mtr_free(struct pmd_internals * p)30 softnic_mtr_free(struct pmd_internals *p)
31 {
32 	/* Remove MTR objects */
33 	for ( ; ; ) {
34 		struct softnic_mtr *m;
35 
36 		m = TAILQ_FIRST(&p->mtr.mtrs);
37 		if (m == NULL)
38 			break;
39 
40 		TAILQ_REMOVE(&p->mtr.mtrs, m, node);
41 		free(m);
42 	}
43 
44 	/* Remove meter profiles */
45 	for ( ; ; ) {
46 		struct softnic_mtr_meter_profile *mp;
47 
48 		mp = TAILQ_FIRST(&p->mtr.meter_profiles);
49 		if (mp == NULL)
50 			break;
51 
52 		TAILQ_REMOVE(&p->mtr.meter_profiles, mp, node);
53 		free(mp);
54 	}
55 
56 	/* Remove meter policies */
57 	for ( ; ; ) {
58 		struct softnic_mtr_meter_policy *mp;
59 
60 		mp = TAILQ_FIRST(&p->mtr.meter_policies);
61 		if (mp == NULL)
62 			break;
63 
64 		TAILQ_REMOVE(&p->mtr.meter_policies, mp, node);
65 		free(mp);
66 	}
67 }
68 
69 struct softnic_mtr_meter_profile *
softnic_mtr_meter_profile_find(struct pmd_internals * p,uint32_t meter_profile_id)70 softnic_mtr_meter_profile_find(struct pmd_internals *p,
71 	uint32_t meter_profile_id)
72 {
73 	struct softnic_mtr_meter_profile_list *mpl = &p->mtr.meter_profiles;
74 	struct softnic_mtr_meter_profile *mp;
75 
76 	TAILQ_FOREACH(mp, mpl, node)
77 		if (meter_profile_id == mp->meter_profile_id)
78 			return mp;
79 
80 	return NULL;
81 }
82 
83 static int
meter_profile_check(struct rte_eth_dev * dev,uint32_t meter_profile_id,struct rte_mtr_meter_profile * profile,struct rte_mtr_error * error)84 meter_profile_check(struct rte_eth_dev *dev,
85 	uint32_t meter_profile_id,
86 	struct rte_mtr_meter_profile *profile,
87 	struct rte_mtr_error *error)
88 {
89 	struct pmd_internals *p = dev->data->dev_private;
90 	struct softnic_mtr_meter_profile *mp;
91 
92 	/* Meter profile ID must be valid. */
93 	if (meter_profile_id == UINT32_MAX)
94 		return -rte_mtr_error_set(error,
95 			EINVAL,
96 			RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
97 			NULL,
98 			"Meter profile id not valid");
99 
100 	/* Meter profile must not exist. */
101 	mp = softnic_mtr_meter_profile_find(p, meter_profile_id);
102 	if (mp)
103 		return -rte_mtr_error_set(error,
104 			EEXIST,
105 			RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
106 			NULL,
107 			"Meter prfile already exists");
108 
109 	/* Profile must not be NULL. */
110 	if (profile == NULL)
111 		return -rte_mtr_error_set(error,
112 			EINVAL,
113 			RTE_MTR_ERROR_TYPE_METER_PROFILE,
114 			NULL,
115 			"profile null");
116 
117 	/* Traffic metering algorithm : TRTCM_RFC2698 */
118 	if (profile->alg != RTE_MTR_TRTCM_RFC2698)
119 		return -rte_mtr_error_set(error,
120 			EINVAL,
121 			RTE_MTR_ERROR_TYPE_METER_PROFILE,
122 			NULL,
123 			"Metering alg not supported");
124 
125 	/* Not support packet mode, just support byte mode. */
126 	if (profile->packet_mode)
127 		return -rte_mtr_error_set(error,
128 			EINVAL,
129 			RTE_MTR_ERROR_TYPE_METER_PROFILE_PACKET_MODE,
130 			NULL,
131 			"Meter packet mode not supported");
132 
133 	return 0;
134 }
135 
136 /* MTR meter profile add */
137 static int
pmd_mtr_meter_profile_add(struct rte_eth_dev * dev,uint32_t meter_profile_id,struct rte_mtr_meter_profile * profile,struct rte_mtr_error * error)138 pmd_mtr_meter_profile_add(struct rte_eth_dev *dev,
139 	uint32_t meter_profile_id,
140 	struct rte_mtr_meter_profile *profile,
141 	struct rte_mtr_error *error)
142 {
143 	struct pmd_internals *p = dev->data->dev_private;
144 	struct softnic_mtr_meter_profile_list *mpl = &p->mtr.meter_profiles;
145 	struct softnic_mtr_meter_profile *mp;
146 	int status;
147 
148 	/* Check input params */
149 	status = meter_profile_check(dev, meter_profile_id, profile, error);
150 	if (status)
151 		return status;
152 
153 	/* Memory allocation */
154 	mp = calloc(1, sizeof(struct softnic_mtr_meter_profile));
155 	if (mp == NULL)
156 		return -rte_mtr_error_set(error,
157 			ENOMEM,
158 			RTE_MTR_ERROR_TYPE_UNSPECIFIED,
159 			NULL,
160 			"Memory alloc failed");
161 
162 	/* Fill in */
163 	mp->meter_profile_id = meter_profile_id;
164 	memcpy(&mp->params, profile, sizeof(mp->params));
165 
166 	/* Add to list */
167 	TAILQ_INSERT_TAIL(mpl, mp, node);
168 
169 	return 0;
170 }
171 
172 /* MTR meter profile delete */
173 static int
pmd_mtr_meter_profile_delete(struct rte_eth_dev * dev,uint32_t meter_profile_id,struct rte_mtr_error * error)174 pmd_mtr_meter_profile_delete(struct rte_eth_dev *dev,
175 	uint32_t meter_profile_id,
176 	struct rte_mtr_error *error)
177 {
178 	struct pmd_internals *p = dev->data->dev_private;
179 	struct softnic_mtr_meter_profile *mp;
180 
181 	/* Meter profile must exist */
182 	mp = softnic_mtr_meter_profile_find(p, meter_profile_id);
183 	if (mp == NULL)
184 		return -rte_mtr_error_set(error,
185 			EINVAL,
186 			RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
187 			NULL,
188 			"Meter profile id invalid");
189 
190 	/* Check unused */
191 	if (mp->n_users)
192 		return -rte_mtr_error_set(error,
193 			EBUSY,
194 			RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
195 			NULL,
196 			"Meter profile in use");
197 
198 	/* Remove from list */
199 	TAILQ_REMOVE(&p->mtr.meter_profiles, mp, node);
200 	free(mp);
201 
202 	return 0;
203 }
204 
205 struct softnic_mtr_meter_policy *
softnic_mtr_meter_policy_find(struct pmd_internals * p,uint32_t meter_policy_id)206 softnic_mtr_meter_policy_find(struct pmd_internals *p,
207 	uint32_t meter_policy_id)
208 {
209 	struct softnic_mtr_meter_policy_list *mpl = &p->mtr.meter_policies;
210 	struct softnic_mtr_meter_policy *mp;
211 
212 	TAILQ_FOREACH(mp, mpl, node)
213 		if (meter_policy_id == mp->meter_policy_id)
214 			return mp;
215 
216 	return NULL;
217 }
218 
219 /* MTR meter policy add */
220 static int
pmd_mtr_meter_policy_add(struct rte_eth_dev * dev,uint32_t meter_policy_id,struct rte_mtr_meter_policy_params * policy,struct rte_mtr_error * error)221 pmd_mtr_meter_policy_add(struct rte_eth_dev *dev,
222 	uint32_t meter_policy_id,
223 	struct rte_mtr_meter_policy_params *policy,
224 	struct rte_mtr_error *error)
225 {
226 	struct pmd_internals *p = dev->data->dev_private;
227 	struct softnic_mtr_meter_policy_list *mpl = &p->mtr.meter_policies;
228 	struct softnic_mtr_meter_policy *mp;
229 	const struct rte_flow_action *act;
230 	const struct rte_flow_action_meter_color *recolor;
231 	uint32_t i;
232 	bool valid_act_found;
233 
234 	if (policy == NULL)
235 		return -rte_mtr_error_set(error,
236 			EINVAL,
237 			RTE_MTR_ERROR_TYPE_METER_POLICY,
238 			NULL,
239 			"Null meter policy invalid");
240 
241 	/* Meter policy must not exist. */
242 	mp = softnic_mtr_meter_policy_find(p, meter_policy_id);
243 	if (mp != NULL)
244 		return -rte_mtr_error_set(error,
245 			EINVAL,
246 			RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
247 			NULL,
248 			"Meter policy already exists");
249 
250 	for (i = 0; i < RTE_COLORS; i++) {
251 		if (policy->actions[i] == NULL)
252 			return -rte_mtr_error_set(error,
253 				EINVAL,
254 				RTE_MTR_ERROR_TYPE_METER_POLICY,
255 				NULL,
256 				"Null action list");
257 		for (act = policy->actions[i], valid_act_found = false;
258 		     act->type != RTE_FLOW_ACTION_TYPE_END; act++) {
259 			if (act->type == RTE_FLOW_ACTION_TYPE_VOID)
260 				continue;
261 			/*
262 			 * Support one (and one only) of
263 			 * METER_COLOR or DROP action.
264 			 */
265 			if ((act->type != RTE_FLOW_ACTION_TYPE_METER_COLOR &&
266 				act->type != RTE_FLOW_ACTION_TYPE_DROP) ||
267 				valid_act_found)
268 				return -rte_mtr_error_set(error,
269 					EINVAL,
270 					RTE_MTR_ERROR_TYPE_METER_POLICY,
271 					NULL,
272 					"Action invalid");
273 			valid_act_found = true;
274 		}
275 		if (!valid_act_found)
276 			return -rte_mtr_error_set(error,
277 				EINVAL,
278 				RTE_MTR_ERROR_TYPE_METER_POLICY,
279 				NULL,
280 				"No valid action found");
281 	}
282 
283 	/* Memory allocation */
284 	mp = calloc(1, sizeof(struct softnic_mtr_meter_policy));
285 	if (mp == NULL)
286 		return -rte_mtr_error_set(error,
287 			ENOMEM,
288 			RTE_MTR_ERROR_TYPE_UNSPECIFIED,
289 			NULL,
290 			"Memory alloc failed");
291 
292 	/* Fill in */
293 	mp->meter_policy_id = meter_policy_id;
294 	for (i = 0; i < RTE_COLORS; i++) {
295 		mp->policer[i] = RTE_TABLE_ACTION_POLICER_DROP;
296 		act = policy->actions[i];
297 		if (!act)
298 			continue;
299 		if (act->type == RTE_FLOW_ACTION_TYPE_METER_COLOR) {
300 			recolor = act->conf;
301 			switch (recolor->color) {
302 			case RTE_COLOR_GREEN:
303 				mp->policer[i] =
304 				RTE_TABLE_ACTION_POLICER_COLOR_GREEN;
305 				break;
306 			case RTE_COLOR_YELLOW:
307 				mp->policer[i] =
308 				RTE_TABLE_ACTION_POLICER_COLOR_YELLOW;
309 				break;
310 			case RTE_COLOR_RED:
311 				mp->policer[i] =
312 				RTE_TABLE_ACTION_POLICER_COLOR_RED;
313 				break;
314 			default:
315 				break;
316 			}
317 		}
318 	}
319 
320 	/* Add to list */
321 	TAILQ_INSERT_TAIL(mpl, mp, node);
322 
323 	return 0;
324 }
325 
326 /* MTR meter policy delete */
327 static int
pmd_mtr_meter_policy_delete(struct rte_eth_dev * dev,uint32_t meter_policy_id,struct rte_mtr_error * error)328 pmd_mtr_meter_policy_delete(struct rte_eth_dev *dev,
329 	uint32_t meter_policy_id,
330 	struct rte_mtr_error *error)
331 {
332 	struct pmd_internals *p = dev->data->dev_private;
333 	struct softnic_mtr_meter_policy *mp;
334 
335 	/* Meter policy must exist */
336 	mp = softnic_mtr_meter_policy_find(p, meter_policy_id);
337 	if (mp == NULL)
338 		return -rte_mtr_error_set(error,
339 			EINVAL,
340 			RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
341 			NULL,
342 			"Meter policy id invalid");
343 
344 	/* Check unused */
345 	if (mp->n_users)
346 		return -rte_mtr_error_set(error,
347 			EBUSY,
348 			RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
349 			NULL,
350 			"Meter policy in use");
351 
352 	/* Remove from list */
353 	TAILQ_REMOVE(&p->mtr.meter_policies, mp, node);
354 	free(mp);
355 
356 	return 0;
357 }
358 
359 struct softnic_mtr *
softnic_mtr_find(struct pmd_internals * p,uint32_t mtr_id)360 softnic_mtr_find(struct pmd_internals *p, uint32_t mtr_id)
361 {
362 	struct softnic_mtr_list *ml = &p->mtr.mtrs;
363 	struct softnic_mtr *m;
364 
365 	TAILQ_FOREACH(m, ml, node)
366 		if (m->mtr_id == mtr_id)
367 			return m;
368 
369 	return NULL;
370 }
371 
372 
373 static int
mtr_check(struct pmd_internals * p,uint32_t mtr_id,struct rte_mtr_params * params,int shared,struct rte_mtr_error * error)374 mtr_check(struct pmd_internals *p,
375 	uint32_t mtr_id,
376 	struct rte_mtr_params *params,
377 	int shared,
378 	struct rte_mtr_error *error)
379 {
380 	/* MTR id valid  */
381 	if (softnic_mtr_find(p, mtr_id))
382 		return -rte_mtr_error_set(error,
383 			EEXIST,
384 			RTE_MTR_ERROR_TYPE_MTR_ID,
385 			NULL,
386 			"MTR object already exists");
387 
388 	/* MTR params must not be NULL */
389 	if (params == NULL)
390 		return -rte_mtr_error_set(error,
391 			EINVAL,
392 			RTE_MTR_ERROR_TYPE_MTR_PARAMS,
393 			NULL,
394 			"MTR object params null");
395 
396 	/* Previous meter color not supported */
397 	if (params->use_prev_mtr_color)
398 		return -rte_mtr_error_set(error,
399 			EINVAL,
400 			RTE_MTR_ERROR_TYPE_MTR_PARAMS,
401 			NULL,
402 			"Previous meter color not supported");
403 
404 	/* Shared MTR object not supported */
405 	if (shared)
406 		return -rte_mtr_error_set(error,
407 			EINVAL,
408 			RTE_MTR_ERROR_TYPE_SHARED,
409 			NULL,
410 			"Shared MTR object not supported");
411 
412 	return 0;
413 }
414 
415 /* MTR object create */
416 static int
pmd_mtr_create(struct rte_eth_dev * dev,uint32_t mtr_id,struct rte_mtr_params * params,int shared,struct rte_mtr_error * error)417 pmd_mtr_create(struct rte_eth_dev *dev,
418 	uint32_t mtr_id,
419 	struct rte_mtr_params *params,
420 	int shared,
421 	struct rte_mtr_error *error)
422 {
423 	struct pmd_internals *p = dev->data->dev_private;
424 	struct softnic_mtr_list *ml = &p->mtr.mtrs;
425 	struct softnic_mtr_meter_profile *mp;
426 	struct softnic_mtr_meter_policy *policy;
427 	struct softnic_mtr *m;
428 	int status;
429 
430 	/* Check parameters */
431 	status = mtr_check(p, mtr_id, params, shared, error);
432 	if (status)
433 		return status;
434 
435 	/* Meter profile must exist */
436 	mp = softnic_mtr_meter_profile_find(p, params->meter_profile_id);
437 	if (mp == NULL)
438 		return -rte_mtr_error_set(error,
439 			EINVAL,
440 			RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
441 			NULL,
442 			"Meter profile id not valid");
443 
444 	/* Meter policy must exist */
445 	policy = softnic_mtr_meter_policy_find(p, params->meter_policy_id);
446 	if (policy == NULL) {
447 		return -rte_mtr_error_set(error,
448 				EINVAL,
449 				RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
450 				NULL,
451 				"Meter policy id invalid");
452 	}
453 
454 	/* Memory allocation */
455 	m = calloc(1, sizeof(struct softnic_mtr));
456 	if (m == NULL)
457 		return -rte_mtr_error_set(error,
458 			ENOMEM,
459 			RTE_MTR_ERROR_TYPE_UNSPECIFIED,
460 			NULL,
461 			"Memory alloc failed");
462 
463 	/* Fill in */
464 	m->mtr_id = mtr_id;
465 	memcpy(&m->params, params, sizeof(m->params));
466 
467 	/* Add to list */
468 	TAILQ_INSERT_TAIL(ml, m, node);
469 
470 	/* Update dependencies */
471 	mp->n_users++;
472 	policy->n_users++;
473 
474 	return 0;
475 }
476 
477 /* MTR object destroy */
478 static int
pmd_mtr_destroy(struct rte_eth_dev * dev,uint32_t mtr_id,struct rte_mtr_error * error)479 pmd_mtr_destroy(struct rte_eth_dev *dev,
480 	uint32_t mtr_id,
481 	struct rte_mtr_error *error)
482 {
483 	struct pmd_internals *p = dev->data->dev_private;
484 	struct softnic_mtr_list *ml = &p->mtr.mtrs;
485 	struct softnic_mtr_meter_profile *mp;
486 	struct softnic_mtr *m;
487 	struct softnic_mtr_meter_policy *policy;
488 
489 	/* MTR object must exist */
490 	m = softnic_mtr_find(p, mtr_id);
491 	if (m == NULL)
492 		return -rte_mtr_error_set(error,
493 			EEXIST,
494 			RTE_MTR_ERROR_TYPE_MTR_ID,
495 			NULL,
496 			"MTR object id not valid");
497 
498 	/* MTR object must not have any owner */
499 	if (m->flow != NULL)
500 		return -rte_mtr_error_set(error,
501 			EINVAL,
502 			RTE_MTR_ERROR_TYPE_UNSPECIFIED,
503 			NULL,
504 			"MTR object is being used");
505 
506 	/* Get meter profile */
507 	mp = softnic_mtr_meter_profile_find(p, m->params.meter_profile_id);
508 	if (mp == NULL)
509 		return -rte_mtr_error_set(error,
510 			EINVAL,
511 			RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
512 			NULL,
513 			"MTR object meter profile invalid");
514 
515 	/* Meter policy must exist */
516 	policy = softnic_mtr_meter_policy_find(p, m->params.meter_policy_id);
517 	if (policy == NULL)
518 		return -rte_mtr_error_set(error,
519 			EINVAL,
520 			RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
521 			NULL,
522 			"MTR object meter policy invalid");
523 
524 	/* Update dependencies */
525 	mp->n_users--;
526 	policy->n_users--;
527 
528 	/* Remove from list */
529 	TAILQ_REMOVE(ml, m, node);
530 	free(m);
531 
532 	return 0;
533 }
534 
535 /* MTR object meter profile update */
536 static int
pmd_mtr_meter_profile_update(struct rte_eth_dev * dev,uint32_t mtr_id,uint32_t meter_profile_id,struct rte_mtr_error * error)537 pmd_mtr_meter_profile_update(struct rte_eth_dev *dev,
538 	uint32_t mtr_id,
539 	uint32_t meter_profile_id,
540 	struct rte_mtr_error *error)
541 {
542 	struct pmd_internals *p = dev->data->dev_private;
543 	struct softnic_mtr_meter_profile *mp_new, *mp_old;
544 	struct softnic_mtr *m;
545 	int status;
546 
547 	/* MTR object id must be valid */
548 	m = softnic_mtr_find(p, mtr_id);
549 	if (m == NULL)
550 		return -rte_mtr_error_set(error,
551 			EEXIST,
552 			RTE_MTR_ERROR_TYPE_MTR_ID,
553 			NULL,
554 			"MTR object id not valid");
555 
556 	/* Meter profile id must be valid */
557 	mp_new = softnic_mtr_meter_profile_find(p, meter_profile_id);
558 	if (mp_new == NULL)
559 		return -rte_mtr_error_set(error,
560 			EINVAL,
561 			RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
562 			NULL,
563 			"Meter profile not valid");
564 
565 	/* MTR object already set to meter profile id */
566 	if (m->params.meter_profile_id == meter_profile_id)
567 		return 0;
568 
569 	/*  MTR object owner table update */
570 	if (m->flow) {
571 		uint32_t table_id = m->flow->table_id;
572 		struct softnic_table *table = &m->flow->pipeline->table[table_id];
573 		struct softnic_table_rule_action action;
574 
575 		if (!softnic_pipeline_table_meter_profile_find(table,
576 			meter_profile_id)) {
577 			struct rte_table_action_meter_profile profile;
578 
579 			memset(&profile, 0, sizeof(profile));
580 
581 			profile.alg = RTE_TABLE_ACTION_METER_TRTCM;
582 			profile.trtcm.cir = mp_new->params.trtcm_rfc2698.cir;
583 			profile.trtcm.pir = mp_new->params.trtcm_rfc2698.pir;
584 			profile.trtcm.cbs = mp_new->params.trtcm_rfc2698.cbs;
585 			profile.trtcm.pbs = mp_new->params.trtcm_rfc2698.pbs;
586 
587 			/* Add meter profile to pipeline table */
588 			status = softnic_pipeline_table_mtr_profile_add(p,
589 					m->flow->pipeline->name,
590 					table_id,
591 					meter_profile_id,
592 					&profile);
593 			if (status)
594 				return -rte_mtr_error_set(error,
595 					EINVAL,
596 					RTE_MTR_ERROR_TYPE_UNSPECIFIED,
597 					NULL,
598 					"Table meter profile add failed");
599 		}
600 
601 		/* Set meter action */
602 		memcpy(&action, &m->flow->action, sizeof(action));
603 
604 		action.mtr.mtr[0].meter_profile_id = meter_profile_id;
605 
606 		/* Re-add rule */
607 		status = softnic_pipeline_table_rule_add(p,
608 			m->flow->pipeline->name,
609 			table_id,
610 			&m->flow->match,
611 			&action,
612 			&m->flow->data);
613 		if (status)
614 			return -rte_mtr_error_set(error,
615 				EINVAL,
616 				RTE_MTR_ERROR_TYPE_UNSPECIFIED,
617 				NULL,
618 				"Pipeline table rule add failed");
619 
620 		/* Flow: update meter action */
621 		memcpy(&m->flow->action, &action, sizeof(m->flow->action));
622 	}
623 
624 	mp_old = softnic_mtr_meter_profile_find(p, m->params.meter_profile_id);
625 
626 	/* Meter: Set meter profile */
627 	m->params.meter_profile_id = meter_profile_id;
628 
629 	/* Update dependencies*/
630 	mp_old->n_users--;
631 	mp_new->n_users++;
632 
633 	return 0;
634 }
635 
636 /* MTR object meter DSCP table update */
637 static int
pmd_mtr_meter_dscp_table_update(struct rte_eth_dev * dev,uint32_t mtr_id,enum rte_color * dscp_table,struct rte_mtr_error * error)638 pmd_mtr_meter_dscp_table_update(struct rte_eth_dev *dev,
639 	uint32_t mtr_id,
640 	enum rte_color *dscp_table,
641 	struct rte_mtr_error *error)
642 {
643 	struct pmd_internals *p = dev->data->dev_private;
644 	struct rte_table_action_dscp_table dt;
645 	struct pipeline *pipeline;
646 	struct softnic_table *table;
647 	struct softnic_mtr *m;
648 	uint32_t table_id, i;
649 	int status;
650 
651 	/* MTR object id must be valid */
652 	m = softnic_mtr_find(p, mtr_id);
653 	if (m == NULL)
654 		return -rte_mtr_error_set(error,
655 			EEXIST,
656 			RTE_MTR_ERROR_TYPE_MTR_ID,
657 			NULL,
658 			"MTR object id not valid");
659 
660 	/* MTR object owner valid? */
661 	if (m->flow == NULL)
662 		return 0;
663 
664 	pipeline = m->flow->pipeline;
665 	table_id = m->flow->table_id;
666 	table = &pipeline->table[table_id];
667 
668 	memcpy(&dt, &table->dscp_table, sizeof(dt));
669 	for (i = 0; i < RTE_DIM(dt.entry); i++)
670 		dt.entry[i].color = (enum rte_color)dscp_table[i];
671 
672 	/* Update table */
673 	status = softnic_pipeline_table_dscp_table_update(p,
674 			pipeline->name,
675 			table_id,
676 			UINT64_MAX,
677 			&dt);
678 	if (status)
679 		return -rte_mtr_error_set(error,
680 			EINVAL,
681 			RTE_MTR_ERROR_TYPE_UNSPECIFIED,
682 			NULL,
683 			"Table action dscp table update failed");
684 
685 	return 0;
686 }
687 
688 /* MTR object policy update */
689 static int
pmd_mtr_meter_policy_update(struct rte_eth_dev * dev,uint32_t mtr_id,uint32_t meter_policy_id,struct rte_mtr_error * error)690 pmd_mtr_meter_policy_update(struct rte_eth_dev *dev,
691 	uint32_t mtr_id,
692 	uint32_t meter_policy_id,
693 	struct rte_mtr_error *error)
694 {
695 	struct pmd_internals *p = dev->data->dev_private;
696 	struct softnic_mtr *m;
697 	uint32_t i;
698 	int status;
699 	struct softnic_mtr_meter_policy *mp_new, *mp_old;
700 
701 	/* MTR object id must be valid */
702 	m = softnic_mtr_find(p, mtr_id);
703 	if (m == NULL)
704 		return -rte_mtr_error_set(error,
705 			EEXIST,
706 			RTE_MTR_ERROR_TYPE_MTR_ID,
707 			NULL,
708 			"MTR object id not valid");
709 
710 	if (m->params.meter_policy_id == meter_policy_id)
711 		return 0;
712 
713 	/* Meter policy must exist */
714 	mp_new = softnic_mtr_meter_policy_find(p, meter_policy_id);
715 	if (mp_new == NULL)
716 		return -rte_mtr_error_set(error,
717 			EINVAL,
718 			RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
719 			NULL,
720 			"Meter policy id invalid");
721 
722 	/* MTR object owner valid? */
723 	if (m->flow) {
724 		struct pipeline *pipeline = m->flow->pipeline;
725 		struct softnic_table *table = &pipeline->table[m->flow->table_id];
726 		struct softnic_table_rule_action action;
727 
728 		memcpy(&action, &m->flow->action, sizeof(action));
729 
730 		/* Set action */
731 		for (i = 0; i < RTE_COLORS; i++)
732 			action.mtr.mtr[0].policer[i] = mp_new->policer[i];
733 
734 		/* Re-add the rule */
735 		status = softnic_pipeline_table_rule_add(p,
736 			pipeline->name,
737 			m->flow->table_id,
738 			&m->flow->match,
739 			&action,
740 			&m->flow->data);
741 		if (status)
742 			return -rte_mtr_error_set(error,
743 				EINVAL,
744 				RTE_MTR_ERROR_TYPE_UNSPECIFIED,
745 				NULL,
746 				"Pipeline table rule re-add failed");
747 
748 		/* Flow: Update meter action */
749 		memcpy(&m->flow->action, &action, sizeof(m->flow->action));
750 
751 		/* Reset the meter stats */
752 		rte_table_action_meter_read(table->a, m->flow->data,
753 			1, NULL, 1);
754 	}
755 
756 	mp_old = softnic_mtr_meter_policy_find(p, m->params.meter_policy_id);
757 	if (mp_old == NULL)
758 		return -rte_mtr_error_set(error,
759 			EINVAL,
760 			RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
761 			NULL,
762 			"Old meter policy id invalid");
763 
764 	/* Meter: Set meter profile */
765 	m->params.meter_policy_id = meter_policy_id;
766 
767 	/* Update dependencies*/
768 	mp_old->n_users--;
769 	mp_new->n_users++;
770 
771 	return 0;
772 }
773 
774 #define MTR_STATS_PKTS_DEFAULT (RTE_MTR_STATS_N_PKTS_GREEN | \
775 				RTE_MTR_STATS_N_PKTS_YELLOW | \
776 				RTE_MTR_STATS_N_PKTS_RED | \
777 				RTE_MTR_STATS_N_PKTS_DROPPED)
778 
779 #define MTR_STATS_BYTES_DEFAULT (RTE_MTR_STATS_N_BYTES_GREEN | \
780 				RTE_MTR_STATS_N_BYTES_YELLOW | \
781 				RTE_MTR_STATS_N_BYTES_RED | \
782 				RTE_MTR_STATS_N_BYTES_DROPPED)
783 
784 /* MTR object stats read */
785 static void
mtr_stats_convert(struct pmd_internals * p,struct softnic_mtr * m,struct rte_table_action_mtr_counters_tc * in,struct rte_mtr_stats * out,uint64_t * out_mask)786 mtr_stats_convert(struct pmd_internals *p,
787 	struct softnic_mtr *m,
788 	struct rte_table_action_mtr_counters_tc *in,
789 	struct rte_mtr_stats *out,
790 	uint64_t *out_mask)
791 {
792 	struct softnic_mtr_meter_policy *mp;
793 
794 	memset(&out, 0, sizeof(out));
795 	*out_mask = 0;
796 
797 	/* Meter policy must exist */
798 	mp = softnic_mtr_meter_policy_find(p, m->params.meter_policy_id);
799 	if (mp == NULL)
800 		return;
801 
802 	if (in->n_packets_valid) {
803 		uint32_t i;
804 
805 		for (i = 0; i < RTE_COLORS; i++) {
806 			if (mp->policer[i] ==
807 				RTE_TABLE_ACTION_POLICER_COLOR_GREEN)
808 				out->n_pkts[RTE_COLOR_GREEN] += in->n_packets[i];
809 
810 			if (mp->policer[i] ==
811 				RTE_TABLE_ACTION_POLICER_COLOR_YELLOW)
812 				out->n_pkts[RTE_COLOR_YELLOW] += in->n_packets[i];
813 
814 			if (mp->policer[i] ==
815 				RTE_TABLE_ACTION_POLICER_COLOR_RED)
816 				out->n_pkts[RTE_COLOR_RED] += in->n_packets[i];
817 
818 			if (mp->policer[i] ==
819 				RTE_TABLE_ACTION_POLICER_DROP)
820 				out->n_pkts_dropped += in->n_packets[i];
821 		}
822 
823 		*out_mask |= MTR_STATS_PKTS_DEFAULT;
824 	}
825 
826 	if (in->n_bytes_valid) {
827 		uint32_t i;
828 
829 		for (i = 0; i < RTE_COLORS; i++) {
830 			if (mp->policer[i] ==
831 				RTE_TABLE_ACTION_POLICER_COLOR_GREEN)
832 				out->n_bytes[RTE_COLOR_GREEN] += in->n_bytes[i];
833 
834 			if (mp->policer[i] ==
835 				RTE_TABLE_ACTION_POLICER_COLOR_YELLOW)
836 				out->n_bytes[RTE_COLOR_YELLOW] += in->n_bytes[i];
837 
838 			if (mp->policer[i] ==
839 				RTE_TABLE_ACTION_POLICER_COLOR_RED)
840 				out->n_bytes[RTE_COLOR_RED] += in->n_bytes[i];
841 
842 			if (mp->policer[i] ==
843 				RTE_TABLE_ACTION_POLICER_DROP)
844 				out->n_bytes_dropped += in->n_bytes[i];
845 		}
846 
847 		*out_mask |= MTR_STATS_BYTES_DEFAULT;
848 	}
849 }
850 
851 /* MTR object stats read */
852 static int
pmd_mtr_stats_read(struct rte_eth_dev * dev,uint32_t mtr_id,struct rte_mtr_stats * stats,uint64_t * stats_mask,int clear,struct rte_mtr_error * error)853 pmd_mtr_stats_read(struct rte_eth_dev *dev,
854 	uint32_t mtr_id,
855 	struct rte_mtr_stats *stats,
856 	uint64_t *stats_mask,
857 	int clear,
858 	struct rte_mtr_error *error)
859 {
860 	struct pmd_internals *p = dev->data->dev_private;
861 	struct rte_table_action_mtr_counters counters;
862 	struct pipeline *pipeline;
863 	struct softnic_table *table;
864 	struct softnic_mtr *m;
865 	int status;
866 
867 	/* MTR object id must be valid */
868 	m = softnic_mtr_find(p, mtr_id);
869 	if (m == NULL)
870 		return -rte_mtr_error_set(error,
871 			EEXIST,
872 			RTE_MTR_ERROR_TYPE_MTR_ID,
873 			NULL,
874 			"MTR object id not valid");
875 
876 	/* MTR meter object owner valid? */
877 	if (m->flow == NULL) {
878 		if (stats != NULL)
879 			memset(stats, 0, sizeof(*stats));
880 
881 		if (stats_mask)
882 			*stats_mask = MTR_STATS_PKTS_DEFAULT |
883 				MTR_STATS_BYTES_DEFAULT;
884 
885 		return 0;
886 	}
887 
888 	pipeline = m->flow->pipeline;
889 	table = &pipeline->table[m->flow->table_id];
890 
891 	/* Meter stats read. */
892 	status = rte_table_action_meter_read(table->a,
893 		m->flow->data,
894 		1,
895 		&counters,
896 		clear);
897 	if (status)
898 		return -rte_mtr_error_set(error,
899 			EINVAL,
900 			RTE_MTR_ERROR_TYPE_UNSPECIFIED,
901 			NULL,
902 			"Meter stats read failed");
903 
904 	/* Stats format conversion. */
905 	if (stats || stats_mask) {
906 		struct rte_mtr_stats s;
907 		uint64_t s_mask = 0;
908 
909 		mtr_stats_convert(p,
910 			m,
911 			&counters.stats[0],
912 			&s,
913 			&s_mask);
914 
915 		if (stats)
916 			memcpy(stats, &s, sizeof(*stats));
917 
918 		if (stats_mask)
919 			*stats_mask = s_mask;
920 	}
921 
922 	return 0;
923 }
924 
925 const struct rte_mtr_ops pmd_mtr_ops = {
926 	.capabilities_get = NULL,
927 
928 	.meter_profile_add = pmd_mtr_meter_profile_add,
929 	.meter_profile_delete = pmd_mtr_meter_profile_delete,
930 
931 	.meter_policy_add = pmd_mtr_meter_policy_add,
932 	.meter_policy_delete = pmd_mtr_meter_policy_delete,
933 
934 	.create = pmd_mtr_create,
935 	.destroy = pmd_mtr_destroy,
936 	.meter_enable = NULL,
937 	.meter_disable = NULL,
938 
939 	.meter_profile_update = pmd_mtr_meter_profile_update,
940 	.meter_dscp_table_update = pmd_mtr_meter_dscp_table_update,
941 	.meter_policy_update = pmd_mtr_meter_policy_update,
942 	.stats_update = NULL,
943 
944 	.stats_read = pmd_mtr_stats_read,
945 };
946