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