33f1c411349c9772976e06a23ddcf070b5cec6c6
[dpdk.git] / examples / ip_pipeline / pipeline / pipeline_flow_actions_be.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2016 Intel Corporation
3  */
4
5 #include <string.h>
6
7 #include <rte_common.h>
8 #include <rte_malloc.h>
9 #include <rte_cycles.h>
10 #include <rte_table_array.h>
11 #include <rte_byteorder.h>
12 #include <rte_ip.h>
13
14 #include "pipeline_actions_common.h"
15 #include "pipeline_flow_actions_be.h"
16 #include "parser.h"
17 #include "hash_func.h"
18
19 int
20 pipeline_fa_flow_params_set_default(struct pipeline_fa_flow_params *params)
21 {
22         uint32_t i;
23
24         if (params == NULL)
25                 return -1;
26
27         for (i = 0; i < PIPELINE_FA_N_TC_MAX; i++) {
28                 struct rte_meter_trtcm_params *m = &params->m[i];
29
30                 m->cir = 1;
31                 m->cbs = 1;
32                 m->pir = 1;
33                 m->pbs = 2;
34         }
35
36         for (i = 0; i < PIPELINE_FA_N_TC_MAX; i++) {
37                 struct pipeline_fa_policer_params *p = &params->p[i];
38                 uint32_t j;
39
40                 for (j = 0; j < e_RTE_METER_COLORS; j++) {
41                         struct pipeline_fa_policer_action *a = &p->action[j];
42
43                         a->drop = 0;
44                         a->color = (enum rte_meter_color) j;
45                 }
46         }
47
48         params->port_id = 0;
49
50         return 0;
51 }
52
53 struct dscp_entry {
54         uint32_t traffic_class;
55         enum rte_meter_color color;
56 };
57
58 struct pipeline_flow_actions {
59         struct pipeline p;
60         struct pipeline_fa_params params;
61         pipeline_msg_req_handler custom_handlers[PIPELINE_FA_MSG_REQS];
62
63         struct dscp_entry dscp[PIPELINE_FA_N_DSCP];
64 } __rte_cache_aligned;
65
66 static void *
67 pipeline_fa_msg_req_custom_handler(struct pipeline *p, void *msg);
68
69 static pipeline_msg_req_handler handlers[] = {
70         [PIPELINE_MSG_REQ_PING] =
71                 pipeline_msg_req_ping_handler,
72         [PIPELINE_MSG_REQ_STATS_PORT_IN] =
73                 pipeline_msg_req_stats_port_in_handler,
74         [PIPELINE_MSG_REQ_STATS_PORT_OUT] =
75                 pipeline_msg_req_stats_port_out_handler,
76         [PIPELINE_MSG_REQ_STATS_TABLE] =
77                 pipeline_msg_req_stats_table_handler,
78         [PIPELINE_MSG_REQ_PORT_IN_ENABLE] =
79                 pipeline_msg_req_port_in_enable_handler,
80         [PIPELINE_MSG_REQ_PORT_IN_DISABLE] =
81                 pipeline_msg_req_port_in_disable_handler,
82         [PIPELINE_MSG_REQ_CUSTOM] =
83                 pipeline_fa_msg_req_custom_handler,
84 };
85
86 static void *
87 pipeline_fa_msg_req_flow_config_handler(struct pipeline *p, void *msg);
88
89 static void *
90 pipeline_fa_msg_req_flow_config_bulk_handler(struct pipeline *p, void *msg);
91
92 static void *
93 pipeline_fa_msg_req_dscp_config_handler(struct pipeline *p, void *msg);
94
95 static void *
96 pipeline_fa_msg_req_policer_stats_read_handler(struct pipeline *p, void *msg);
97
98 static pipeline_msg_req_handler custom_handlers[] = {
99         [PIPELINE_FA_MSG_REQ_FLOW_CONFIG] =
100                 pipeline_fa_msg_req_flow_config_handler,
101         [PIPELINE_FA_MSG_REQ_FLOW_CONFIG_BULK] =
102                 pipeline_fa_msg_req_flow_config_bulk_handler,
103         [PIPELINE_FA_MSG_REQ_DSCP_CONFIG] =
104                 pipeline_fa_msg_req_dscp_config_handler,
105         [PIPELINE_FA_MSG_REQ_POLICER_STATS_READ] =
106                 pipeline_fa_msg_req_policer_stats_read_handler,
107 };
108
109 /*
110  * Flow table
111  */
112 struct meter_policer {
113         struct rte_meter_trtcm meter;
114         struct rte_meter_trtcm_profile meter_profile;
115         struct pipeline_fa_policer_params policer;
116         struct pipeline_fa_policer_stats stats;
117 };
118
119 struct flow_table_entry {
120         struct rte_pipeline_table_entry head;
121         struct meter_policer mp[PIPELINE_FA_N_TC_MAX];
122 };
123
124 static int
125 flow_table_entry_set_meter(struct flow_table_entry *entry,
126         uint32_t meter_id,
127         struct pipeline_fa_flow_params *params)
128 {
129         struct rte_meter_trtcm *meter = &entry->mp[meter_id].meter;
130         struct rte_meter_trtcm_params *meter_params = &params->m[meter_id];
131         struct rte_meter_trtcm_profile *meter_profile =
132                                         &entry->mp[meter_id].meter_profile;
133         int status;
134
135         status = rte_meter_trtcm_profile_config(meter_profile, meter_params);
136         if (status)
137                 return status;
138
139         return rte_meter_trtcm_config(meter, meter_profile);
140 }
141
142 static void
143 flow_table_entry_set_policer(struct flow_table_entry *entry,
144         uint32_t policer_id,
145         struct pipeline_fa_flow_params *params)
146 {
147         struct pipeline_fa_policer_params *p0 = &entry->mp[policer_id].policer;
148         struct pipeline_fa_policer_params *p1 = &params->p[policer_id];
149
150         memcpy(p0, p1, sizeof(*p0));
151 }
152
153 static void
154 flow_table_entry_set_port_id(struct pipeline_flow_actions *p,
155         struct flow_table_entry *entry,
156         struct pipeline_fa_flow_params *params)
157 {
158         entry->head.action = RTE_PIPELINE_ACTION_PORT;
159         entry->head.port_id = p->p.port_out_id[params->port_id];
160 }
161
162 static int
163 flow_table_entry_set_default(struct pipeline_flow_actions *p,
164         struct flow_table_entry *entry)
165 {
166         struct pipeline_fa_flow_params params;
167         uint32_t i;
168
169         pipeline_fa_flow_params_set_default(&params);
170
171         memset(entry, 0, sizeof(*entry));
172
173         flow_table_entry_set_port_id(p, entry, &params);
174
175         for (i = 0; i < PIPELINE_FA_N_TC_MAX; i++) {
176                 int status;
177
178                 status = flow_table_entry_set_meter(entry, i, &params);
179                 if (status)
180                         return status;
181         }
182
183         for (i = 0; i < PIPELINE_FA_N_TC_MAX; i++)
184                 flow_table_entry_set_policer(entry, i, &params);
185
186         return 0;
187 }
188
189 static inline uint64_t
190 pkt_work(
191         struct rte_mbuf *pkt,
192         struct rte_pipeline_table_entry *table_entry,
193         void *arg,
194         uint64_t time)
195 {
196         struct pipeline_flow_actions *p = arg;
197         struct flow_table_entry *entry =
198                 (struct flow_table_entry *) table_entry;
199
200         struct ipv4_hdr *pkt_ip = (struct ipv4_hdr *)
201                 RTE_MBUF_METADATA_UINT32_PTR(pkt, p->params.ip_hdr_offset);
202         enum rte_meter_color *pkt_color = (enum rte_meter_color *)
203                 RTE_MBUF_METADATA_UINT32_PTR(pkt, p->params.color_offset);
204
205         /* Read (IP header) */
206         uint32_t total_length = rte_bswap16(pkt_ip->total_length);
207         uint32_t dscp = pkt_ip->type_of_service >> 2;
208
209         uint32_t tc = p->dscp[dscp].traffic_class;
210         enum rte_meter_color color = p->dscp[dscp].color;
211
212         struct rte_meter_trtcm *meter = &entry->mp[tc].meter;
213         struct rte_meter_trtcm_profile *meter_profile =
214                                         &entry->mp[tc].meter_profile;
215         struct pipeline_fa_policer_params *policer = &entry->mp[tc].policer;
216         struct pipeline_fa_policer_stats *stats = &entry->mp[tc].stats;
217
218         /* Read (entry), compute */
219         enum rte_meter_color color2 = rte_meter_trtcm_color_aware_check(meter,
220                 meter_profile,
221                 time,
222                 total_length,
223                 color);
224
225         enum rte_meter_color color3 = policer->action[color2].color;
226         uint64_t drop = policer->action[color2].drop;
227
228         /* Read (entry), write (entry, color) */
229         stats->n_pkts[color3] += drop ^ 1LLU;
230         stats->n_pkts_drop += drop;
231         *pkt_color = color3;
232
233         return drop;
234 }
235
236 static inline uint64_t
237 pkt4_work(
238         struct rte_mbuf **pkts,
239         struct rte_pipeline_table_entry **table_entries,
240         void *arg,
241         uint64_t time)
242 {
243         struct pipeline_flow_actions *p = arg;
244
245         struct flow_table_entry *entry0 =
246                 (struct flow_table_entry *) table_entries[0];
247         struct flow_table_entry *entry1 =
248                 (struct flow_table_entry *) table_entries[1];
249         struct flow_table_entry *entry2 =
250                 (struct flow_table_entry *) table_entries[2];
251         struct flow_table_entry *entry3 =
252                 (struct flow_table_entry *) table_entries[3];
253
254         struct ipv4_hdr *pkt0_ip = (struct ipv4_hdr *)
255                 RTE_MBUF_METADATA_UINT32_PTR(pkts[0], p->params.ip_hdr_offset);
256         struct ipv4_hdr *pkt1_ip = (struct ipv4_hdr *)
257                 RTE_MBUF_METADATA_UINT32_PTR(pkts[1], p->params.ip_hdr_offset);
258         struct ipv4_hdr *pkt2_ip = (struct ipv4_hdr *)
259                 RTE_MBUF_METADATA_UINT32_PTR(pkts[2], p->params.ip_hdr_offset);
260         struct ipv4_hdr *pkt3_ip = (struct ipv4_hdr *)
261                 RTE_MBUF_METADATA_UINT32_PTR(pkts[3], p->params.ip_hdr_offset);
262
263         enum rte_meter_color *pkt0_color = (enum rte_meter_color *)
264                 RTE_MBUF_METADATA_UINT32_PTR(pkts[0], p->params.color_offset);
265         enum rte_meter_color *pkt1_color = (enum rte_meter_color *)
266                 RTE_MBUF_METADATA_UINT32_PTR(pkts[1], p->params.color_offset);
267         enum rte_meter_color *pkt2_color = (enum rte_meter_color *)
268                 RTE_MBUF_METADATA_UINT32_PTR(pkts[2], p->params.color_offset);
269         enum rte_meter_color *pkt3_color = (enum rte_meter_color *)
270                 RTE_MBUF_METADATA_UINT32_PTR(pkts[3], p->params.color_offset);
271
272         /* Read (IP header) */
273         uint32_t total_length0 = rte_bswap16(pkt0_ip->total_length);
274         uint32_t dscp0 = pkt0_ip->type_of_service >> 2;
275
276         uint32_t total_length1 = rte_bswap16(pkt1_ip->total_length);
277         uint32_t dscp1 = pkt1_ip->type_of_service >> 2;
278
279         uint32_t total_length2 = rte_bswap16(pkt2_ip->total_length);
280         uint32_t dscp2 = pkt2_ip->type_of_service >> 2;
281
282         uint32_t total_length3 = rte_bswap16(pkt3_ip->total_length);
283         uint32_t dscp3 = pkt3_ip->type_of_service >> 2;
284
285         uint32_t tc0 = p->dscp[dscp0].traffic_class;
286         enum rte_meter_color color0 = p->dscp[dscp0].color;
287
288         uint32_t tc1 = p->dscp[dscp1].traffic_class;
289         enum rte_meter_color color1 = p->dscp[dscp1].color;
290
291         uint32_t tc2 = p->dscp[dscp2].traffic_class;
292         enum rte_meter_color color2 = p->dscp[dscp2].color;
293
294         uint32_t tc3 = p->dscp[dscp3].traffic_class;
295         enum rte_meter_color color3 = p->dscp[dscp3].color;
296
297         struct rte_meter_trtcm *meter0 = &entry0->mp[tc0].meter;
298         struct rte_meter_trtcm_profile *meter0_profile =
299                                 &entry0->mp[tc0].meter_profile;
300         struct pipeline_fa_policer_params *policer0 = &entry0->mp[tc0].policer;
301         struct pipeline_fa_policer_stats *stats0 = &entry0->mp[tc0].stats;
302
303         struct rte_meter_trtcm *meter1 = &entry1->mp[tc1].meter;
304         struct rte_meter_trtcm_profile *meter1_profile =
305                                 &entry1->mp[tc1].meter_profile;
306         struct pipeline_fa_policer_params *policer1 = &entry1->mp[tc1].policer;
307         struct pipeline_fa_policer_stats *stats1 = &entry1->mp[tc1].stats;
308
309         struct rte_meter_trtcm *meter2 = &entry2->mp[tc2].meter;
310         struct rte_meter_trtcm_profile *meter2_profile =
311                                 &entry2->mp[tc2].meter_profile;
312         struct pipeline_fa_policer_params *policer2 = &entry2->mp[tc2].policer;
313         struct pipeline_fa_policer_stats *stats2 = &entry2->mp[tc2].stats;
314
315         struct rte_meter_trtcm *meter3 = &entry3->mp[tc3].meter;
316         struct rte_meter_trtcm_profile *meter3_profile =
317                                 &entry3->mp[tc3].meter_profile;
318         struct pipeline_fa_policer_params *policer3 = &entry3->mp[tc3].policer;
319         struct pipeline_fa_policer_stats *stats3 = &entry3->mp[tc3].stats;
320
321         /* Read (entry), compute, write (entry) */
322         enum rte_meter_color color2_0 = rte_meter_trtcm_color_aware_check(
323                 meter0,
324                 meter0_profile,
325                 time,
326                 total_length0,
327                 color0);
328
329         enum rte_meter_color color2_1 = rte_meter_trtcm_color_aware_check(
330                 meter1,
331                 meter1_profile,
332                 time,
333                 total_length1,
334                 color1);
335
336         enum rte_meter_color color2_2 = rte_meter_trtcm_color_aware_check(
337                 meter2,
338                 meter2_profile,
339                 time,
340                 total_length2,
341                 color2);
342
343         enum rte_meter_color color2_3 = rte_meter_trtcm_color_aware_check(
344                 meter3,
345                 meter3_profile,
346                 time,
347                 total_length3,
348                 color3);
349
350         enum rte_meter_color color3_0 = policer0->action[color2_0].color;
351         enum rte_meter_color color3_1 = policer1->action[color2_1].color;
352         enum rte_meter_color color3_2 = policer2->action[color2_2].color;
353         enum rte_meter_color color3_3 = policer3->action[color2_3].color;
354
355         uint64_t drop0 = policer0->action[color2_0].drop;
356         uint64_t drop1 = policer1->action[color2_1].drop;
357         uint64_t drop2 = policer2->action[color2_2].drop;
358         uint64_t drop3 = policer3->action[color2_3].drop;
359
360         /* Read (entry), write (entry, color) */
361         stats0->n_pkts[color3_0] += drop0 ^ 1LLU;
362         stats0->n_pkts_drop += drop0;
363
364         stats1->n_pkts[color3_1] += drop1 ^ 1LLU;
365         stats1->n_pkts_drop += drop1;
366
367         stats2->n_pkts[color3_2] += drop2 ^ 1LLU;
368         stats2->n_pkts_drop += drop2;
369
370         stats3->n_pkts[color3_3] += drop3 ^ 1LLU;
371         stats3->n_pkts_drop += drop3;
372
373         *pkt0_color = color3_0;
374         *pkt1_color = color3_1;
375         *pkt2_color = color3_2;
376         *pkt3_color = color3_3;
377
378         return drop0 | (drop1 << 1) | (drop2 << 2) | (drop3 << 3);
379 }
380
381 PIPELINE_TABLE_AH_HIT_DROP_TIME(fa_table_ah_hit, pkt_work, pkt4_work);
382
383 static rte_pipeline_table_action_handler_hit
384 get_fa_table_ah_hit(__rte_unused struct pipeline_flow_actions *p)
385 {
386         return fa_table_ah_hit;
387 }
388
389 /*
390  * Argument parsing
391  */
392 int
393 pipeline_fa_parse_args(struct pipeline_fa_params *p,
394         struct pipeline_params *params)
395 {
396         uint32_t n_flows_present = 0;
397         uint32_t n_meters_per_flow_present = 0;
398         uint32_t flow_id_offset_present = 0;
399         uint32_t ip_hdr_offset_present = 0;
400         uint32_t color_offset_present = 0;
401         uint32_t i;
402
403         /* Default values */
404         p->n_meters_per_flow = 1;
405         p->dscp_enabled = 0;
406
407         for (i = 0; i < params->n_args; i++) {
408                 char *arg_name = params->args_name[i];
409                 char *arg_value = params->args_value[i];
410
411                 /* n_flows */
412                 if (strcmp(arg_name, "n_flows") == 0) {
413                         int status;
414
415                         PIPELINE_PARSE_ERR_DUPLICATE(
416                                 n_flows_present == 0, params->name,
417                                 arg_name);
418                         n_flows_present = 1;
419
420                         status = parser_read_uint32(&p->n_flows,
421                                 arg_value);
422                         PIPELINE_PARSE_ERR_INV_VAL(((status != -EINVAL) &&
423                                 (p->n_flows != 0)), params->name,
424                                 arg_name, arg_value);
425                         PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
426                                 params->name, arg_name, arg_value);
427
428                         continue;
429                 }
430
431                 /* n_meters_per_flow */
432                 if (strcmp(arg_name, "n_meters_per_flow") == 0) {
433                         int status;
434
435                         PIPELINE_PARSE_ERR_DUPLICATE(
436                                 n_meters_per_flow_present == 0,
437                                 params->name, arg_name);
438                         n_meters_per_flow_present = 1;
439
440                         status = parser_read_uint32(&p->n_meters_per_flow,
441                                 arg_value);
442                         PIPELINE_PARSE_ERR_INV_VAL(((status != -EINVAL) &&
443                                 (p->n_meters_per_flow != 0)),
444                                 params->name, arg_name, arg_value);
445                         PIPELINE_PARSE_ERR_OUT_RNG(((status != -ERANGE) &&
446                                 (p->n_meters_per_flow <=
447                                 PIPELINE_FA_N_TC_MAX)), params->name,
448                                 arg_name, arg_value);
449
450                         continue;
451                 }
452
453                 /* flow_id_offset */
454                 if (strcmp(arg_name, "flow_id_offset") == 0) {
455                         int status;
456
457                         PIPELINE_PARSE_ERR_DUPLICATE(
458                                 flow_id_offset_present == 0,
459                                 params->name, arg_name);
460                         flow_id_offset_present = 1;
461
462                         status = parser_read_uint32(&p->flow_id_offset,
463                                 arg_value);
464                         PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
465                                 params->name, arg_name, arg_value);
466                         PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
467                                 params->name, arg_name, arg_value);
468
469                         continue;
470                 }
471
472                 /* ip_hdr_offset */
473                 if (strcmp(arg_name, "ip_hdr_offset") == 0) {
474                         int status;
475
476                         PIPELINE_PARSE_ERR_DUPLICATE(
477                                 ip_hdr_offset_present == 0,
478                                 params->name, arg_name);
479                         ip_hdr_offset_present = 1;
480
481                         status = parser_read_uint32(&p->ip_hdr_offset,
482                                 arg_value);
483                         PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
484                                 params->name, arg_name, arg_value);
485                         PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
486                                 params->name, arg_name, arg_value);
487
488                         continue;
489                 }
490
491                 /* color_offset */
492                 if (strcmp(arg_name, "color_offset") == 0) {
493                         int status;
494
495                         PIPELINE_PARSE_ERR_DUPLICATE(
496                                 color_offset_present == 0, params->name,
497                                 arg_name);
498                         color_offset_present = 1;
499
500                         status = parser_read_uint32(&p->color_offset,
501                                 arg_value);
502                         PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
503                                 params->name, arg_name, arg_value);
504                         PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
505                                 params->name, arg_name, arg_value);
506
507                         p->dscp_enabled = 1;
508
509                         continue;
510                 }
511
512                 /* Unknown argument */
513                 PIPELINE_PARSE_ERR_INV_ENT(0, params->name, arg_name);
514         }
515
516         /* Check that mandatory arguments are present */
517         PIPELINE_PARSE_ERR_MANDATORY((n_flows_present), params->name,
518                 "n_flows");
519         PIPELINE_PARSE_ERR_MANDATORY((flow_id_offset_present),
520                 params->name, "flow_id_offset");
521         PIPELINE_PARSE_ERR_MANDATORY((ip_hdr_offset_present),
522                 params->name, "ip_hdr_offset");
523         PIPELINE_PARSE_ERR_MANDATORY((color_offset_present), params->name,
524                 "color_offset");
525
526         return 0;
527 }
528
529 static void
530 dscp_init(struct pipeline_flow_actions *p)
531 {
532         uint32_t i;
533
534         for (i = 0; i < PIPELINE_FA_N_DSCP; i++) {
535                 p->dscp[i].traffic_class = 0;
536                 p->dscp[i].color = e_RTE_METER_GREEN;
537         }
538 }
539
540 static void *pipeline_fa_init(struct pipeline_params *params,
541         __rte_unused void *arg)
542 {
543         struct pipeline *p;
544         struct pipeline_flow_actions *p_fa;
545         uint32_t size, i;
546
547         /* Check input arguments */
548         if (params == NULL)
549                 return NULL;
550
551         if (params->n_ports_in != params->n_ports_out)
552                 return NULL;
553
554         /* Memory allocation */
555         size = RTE_CACHE_LINE_ROUNDUP(
556                 sizeof(struct pipeline_flow_actions));
557         p = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
558         if (p == NULL)
559                 return NULL;
560         p_fa = (struct pipeline_flow_actions *) p;
561
562         strcpy(p->name, params->name);
563         p->log_level = params->log_level;
564
565         PLOG(p, HIGH, "Flow actions");
566
567         /* Parse arguments */
568         if (pipeline_fa_parse_args(&p_fa->params, params))
569                 return NULL;
570
571         dscp_init(p_fa);
572
573         /* Pipeline */
574         {
575                 struct rte_pipeline_params pipeline_params = {
576                         .name = params->name,
577                         .socket_id = params->socket_id,
578                         .offset_port_id = 0,
579                 };
580
581                 p->p = rte_pipeline_create(&pipeline_params);
582                 if (p->p == NULL) {
583                         rte_free(p);
584                         return NULL;
585                 }
586         }
587
588         /* Input ports */
589         p->n_ports_in = params->n_ports_in;
590         for (i = 0; i < p->n_ports_in; i++) {
591                 struct rte_pipeline_port_in_params port_params = {
592                         .ops = pipeline_port_in_params_get_ops(
593                                 &params->port_in[i]),
594                         .arg_create = pipeline_port_in_params_convert(
595                                 &params->port_in[i]),
596                         .f_action = NULL,
597                         .arg_ah = NULL,
598                         .burst_size = params->port_in[i].burst_size,
599                 };
600
601                 int status = rte_pipeline_port_in_create(p->p,
602                         &port_params,
603                         &p->port_in_id[i]);
604
605                 if (status) {
606                         rte_pipeline_free(p->p);
607                         rte_free(p);
608                         return NULL;
609                 }
610         }
611
612         /* Output ports */
613         p->n_ports_out = params->n_ports_out;
614         for (i = 0; i < p->n_ports_out; i++) {
615                 struct rte_pipeline_port_out_params port_params = {
616                         .ops = pipeline_port_out_params_get_ops(
617                                 &params->port_out[i]),
618                         .arg_create = pipeline_port_out_params_convert(
619                                 &params->port_out[i]),
620                         .f_action = NULL,
621                         .arg_ah = NULL,
622                 };
623
624                 int status = rte_pipeline_port_out_create(p->p,
625                         &port_params,
626                         &p->port_out_id[i]);
627
628                 if (status) {
629                         rte_pipeline_free(p->p);
630                         rte_free(p);
631                         return NULL;
632                 }
633         }
634
635         /* Tables */
636         p->n_tables = 1;
637         {
638                 struct rte_table_array_params table_array_params = {
639                         .n_entries = p_fa->params.n_flows,
640                         .offset = p_fa->params.flow_id_offset,
641                 };
642
643                 struct rte_pipeline_table_params table_params = {
644                         .ops = &rte_table_array_ops,
645                         .arg_create = &table_array_params,
646                         .f_action_hit = get_fa_table_ah_hit(p_fa),
647                         .f_action_miss = NULL,
648                         .arg_ah = p_fa,
649                         .action_data_size =
650                                 sizeof(struct flow_table_entry) -
651                                 sizeof(struct rte_pipeline_table_entry),
652                 };
653
654                 int status;
655
656                 status = rte_pipeline_table_create(p->p,
657                         &table_params,
658                         &p->table_id[0]);
659
660                 if (status) {
661                         rte_pipeline_free(p->p);
662                         rte_free(p);
663                         return NULL;
664                 }
665         }
666
667         /* Connecting input ports to tables */
668         for (i = 0; i < p->n_ports_in; i++) {
669                 int status = rte_pipeline_port_in_connect_to_table(p->p,
670                         p->port_in_id[i],
671                         p->table_id[0]);
672
673                 if (status) {
674                         rte_pipeline_free(p->p);
675                         rte_free(p);
676                         return NULL;
677                 }
678         }
679
680         /* Enable input ports */
681         for (i = 0; i < p->n_ports_in; i++) {
682                 int status = rte_pipeline_port_in_enable(p->p,
683                         p->port_in_id[i]);
684
685                 if (status) {
686                         rte_pipeline_free(p->p);
687                         rte_free(p);
688                         return NULL;
689                 }
690         }
691
692         /* Initialize table entries */
693         for (i = 0; i < p_fa->params.n_flows; i++) {
694                 struct rte_table_array_key key = {
695                         .pos = i,
696                 };
697
698                 struct flow_table_entry entry;
699                 struct rte_pipeline_table_entry *entry_ptr;
700                 int key_found, status;
701
702                 flow_table_entry_set_default(p_fa, &entry);
703
704                 status = rte_pipeline_table_entry_add(p->p,
705                         p->table_id[0],
706                         &key,
707                         (struct rte_pipeline_table_entry *) &entry,
708                         &key_found,
709                         &entry_ptr);
710
711                 if (status) {
712                         rte_pipeline_free(p->p);
713                         rte_free(p);
714                         return NULL;
715                 }
716         }
717
718         /* Check pipeline consistency */
719         if (rte_pipeline_check(p->p) < 0) {
720                 rte_pipeline_free(p->p);
721                 rte_free(p);
722                 return NULL;
723         }
724
725         /* Message queues */
726         p->n_msgq = params->n_msgq;
727         for (i = 0; i < p->n_msgq; i++)
728                 p->msgq_in[i] = params->msgq_in[i];
729         for (i = 0; i < p->n_msgq; i++)
730                 p->msgq_out[i] = params->msgq_out[i];
731
732         /* Message handlers */
733         memcpy(p->handlers, handlers, sizeof(p->handlers));
734         memcpy(p_fa->custom_handlers,
735                 custom_handlers,
736                 sizeof(p_fa->custom_handlers));
737
738         return p;
739 }
740
741 static int
742 pipeline_fa_free(void *pipeline)
743 {
744         struct pipeline *p = (struct pipeline *) pipeline;
745
746         /* Check input arguments */
747         if (p == NULL)
748                 return -1;
749
750         /* Free resources */
751         rte_pipeline_free(p->p);
752         rte_free(p);
753         return 0;
754 }
755
756 static int
757 pipeline_fa_timer(void *pipeline)
758 {
759         struct pipeline *p = (struct pipeline *) pipeline;
760
761         pipeline_msg_req_handle(p);
762         rte_pipeline_flush(p->p);
763
764         return 0;
765 }
766
767 void *
768 pipeline_fa_msg_req_custom_handler(struct pipeline *p, void *msg)
769 {
770         struct pipeline_flow_actions *p_fa =
771                         (struct pipeline_flow_actions *) p;
772         struct pipeline_custom_msg_req *req = msg;
773         pipeline_msg_req_handler f_handle;
774
775         f_handle = (req->subtype < PIPELINE_FA_MSG_REQS) ?
776                 p_fa->custom_handlers[req->subtype] :
777                 pipeline_msg_req_invalid_handler;
778
779         if (f_handle == NULL)
780                 f_handle = pipeline_msg_req_invalid_handler;
781
782         return f_handle(p, req);
783 }
784
785 void *
786 pipeline_fa_msg_req_flow_config_handler(struct pipeline *p, void *msg)
787 {
788         struct pipeline_flow_actions *p_fa = (struct pipeline_flow_actions *) p;
789         struct pipeline_fa_flow_config_msg_req *req = msg;
790         struct pipeline_fa_flow_config_msg_rsp *rsp = msg;
791         struct flow_table_entry *entry;
792         uint32_t mask, i;
793
794         /* Set flow table entry to default if not configured before */
795         if (req->entry_ptr == NULL) {
796                 struct rte_table_array_key key = {
797                         .pos = req->flow_id % p_fa->params.n_flows,
798                 };
799
800                 struct flow_table_entry default_entry;
801
802                 int key_found, status;
803
804                 flow_table_entry_set_default(p_fa, &default_entry);
805
806                 status = rte_pipeline_table_entry_add(p->p,
807                         p->table_id[0],
808                         &key,
809                         (struct rte_pipeline_table_entry *) &default_entry,
810                         &key_found,
811                         (struct rte_pipeline_table_entry **) &entry);
812                 if (status) {
813                         rsp->status = -1;
814                         return rsp;
815                 }
816         } else
817                 entry = (struct flow_table_entry *) req->entry_ptr;
818
819         /* Meter */
820         for (i = 0, mask = 1; i < PIPELINE_FA_N_TC_MAX; i++, mask <<= 1) {
821                 int status;
822
823                 if ((mask & req->meter_update_mask) == 0)
824                         continue;
825
826                 status = flow_table_entry_set_meter(entry, i, &req->params);
827                 if (status) {
828                         rsp->status = -1;
829                         return rsp;
830                 }
831         }
832
833         /* Policer */
834         for (i = 0, mask = 1; i < PIPELINE_FA_N_TC_MAX; i++, mask <<= 1) {
835                 if ((mask & req->policer_update_mask) == 0)
836                         continue;
837
838                 flow_table_entry_set_policer(entry, i, &req->params);
839         }
840
841         /* Port */
842         if (req->port_update)
843                 flow_table_entry_set_port_id(p_fa, entry, &req->params);
844
845         /* Response */
846         rsp->status = 0;
847         rsp->entry_ptr = (void *) entry;
848         return rsp;
849 }
850
851 void *
852 pipeline_fa_msg_req_flow_config_bulk_handler(struct pipeline *p, void *msg)
853 {
854         struct pipeline_flow_actions *p_fa = (struct pipeline_flow_actions *) p;
855         struct pipeline_fa_flow_config_bulk_msg_req *req = msg;
856         struct pipeline_fa_flow_config_bulk_msg_rsp *rsp = msg;
857         uint32_t i;
858
859         for (i = 0; i < req->n_flows; i++) {
860                 struct flow_table_entry *entry;
861                 uint32_t j, mask;
862
863                 /* Set flow table entry to default if not configured before */
864                 if (req->entry_ptr[i] == NULL) {
865                         struct rte_table_array_key key = {
866                                 .pos = req->flow_id[i] % p_fa->params.n_flows,
867                         };
868
869                         struct flow_table_entry entry_to_add;
870
871                         int key_found, status;
872
873                         flow_table_entry_set_default(p_fa, &entry_to_add);
874
875                         status = rte_pipeline_table_entry_add(p->p,
876                          p->table_id[0],
877                          &key,
878                          (struct rte_pipeline_table_entry *) &entry_to_add,
879                          &key_found,
880                          (struct rte_pipeline_table_entry **) &entry);
881                         if (status) {
882                                 rsp->n_flows = i;
883                                 return rsp;
884                         }
885
886                         req->entry_ptr[i] = (void *) entry;
887                 } else
888                         entry = (struct flow_table_entry *) req->entry_ptr[i];
889
890                 /* Meter */
891                 for (j = 0, mask = 1;
892                         j < PIPELINE_FA_N_TC_MAX;
893                         j++, mask <<= 1) {
894                         int status;
895
896                         if ((mask & req->meter_update_mask) == 0)
897                                 continue;
898
899                         status = flow_table_entry_set_meter(entry,
900                                 j, &req->params[i]);
901                         if (status) {
902                                 rsp->n_flows = i;
903                                 return rsp;
904                         }
905                 }
906
907                 /* Policer */
908                 for (j = 0, mask = 1;
909                         j < PIPELINE_FA_N_TC_MAX;
910                         j++, mask <<= 1) {
911                         if ((mask & req->policer_update_mask) == 0)
912                                 continue;
913
914                         flow_table_entry_set_policer(entry,
915                          j, &req->params[i]);
916                 }
917
918                 /* Port */
919                 if (req->port_update)
920                         flow_table_entry_set_port_id(p_fa,
921                          entry, &req->params[i]);
922         }
923
924         /* Response */
925         rsp->n_flows = i;
926         return rsp;
927 }
928
929 void *
930 pipeline_fa_msg_req_dscp_config_handler(struct pipeline *p, void *msg)
931 {
932         struct pipeline_flow_actions *p_fa = (struct pipeline_flow_actions *) p;
933         struct pipeline_fa_dscp_config_msg_req *req = msg;
934         struct pipeline_fa_dscp_config_msg_rsp *rsp = msg;
935
936         /* Check request */
937         if ((req->dscp >= PIPELINE_FA_N_DSCP) ||
938                 (req->traffic_class >= PIPELINE_FA_N_TC_MAX) ||
939                 (req->color >= e_RTE_METER_COLORS)) {
940                 rsp->status = -1;
941                 return rsp;
942         }
943
944         p_fa->dscp[req->dscp].traffic_class = req->traffic_class;
945         p_fa->dscp[req->dscp].color = req->color;
946         rsp->status = 0;
947         return rsp;
948 }
949
950 void *
951 pipeline_fa_msg_req_policer_stats_read_handler(__rte_unused struct pipeline *p,
952         void *msg)
953 {
954         struct pipeline_fa_policer_stats_msg_req *req = msg;
955         struct pipeline_fa_policer_stats_msg_rsp *rsp = msg;
956
957         struct flow_table_entry *entry = req->entry_ptr;
958         uint32_t policer_id = req->policer_id;
959         int clear = req->clear;
960
961         /* Check request */
962         if ((req->entry_ptr == NULL) ||
963                 (req->policer_id >= PIPELINE_FA_N_TC_MAX)) {
964                 rsp->status = -1;
965                 return rsp;
966         }
967
968         memcpy(&rsp->stats,
969                 &entry->mp[policer_id].stats,
970                 sizeof(rsp->stats));
971         if (clear)
972                 memset(&entry->mp[policer_id].stats,
973                         0, sizeof(entry->mp[policer_id].stats));
974         rsp->status = 0;
975         return rsp;
976 }
977
978 struct pipeline_be_ops pipeline_flow_actions_be_ops = {
979         .f_init = pipeline_fa_init,
980         .f_free = pipeline_fa_free,
981         .f_run = NULL,
982         .f_timer = pipeline_fa_timer,
983 };