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