Imported Upstream version 16.04
[deb_dpdk.git] / examples / ip_pipeline / pipeline / pipeline_flow_classification_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_table_hash.h>
39 #include <rte_byteorder.h>
40 #include <pipeline.h>
41
42 #include "pipeline_flow_classification_be.h"
43 #include "pipeline_actions_common.h"
44 #include "parser.h"
45 #include "hash_func.h"
46
47 struct pipeline_flow_classification {
48         struct pipeline p;
49         pipeline_msg_req_handler custom_handlers[PIPELINE_FC_MSG_REQS];
50
51         uint32_t n_flows;
52         uint32_t key_size;
53         uint32_t flow_id;
54
55         uint32_t key_offset;
56         uint32_t hash_offset;
57         uint8_t key_mask[PIPELINE_FC_FLOW_KEY_MAX_SIZE];
58         uint32_t key_mask_present;
59         uint32_t flow_id_offset;
60
61 } __rte_cache_aligned;
62
63 static void *
64 pipeline_fc_msg_req_custom_handler(struct pipeline *p, void *msg);
65
66 static pipeline_msg_req_handler handlers[] = {
67         [PIPELINE_MSG_REQ_PING] =
68                 pipeline_msg_req_ping_handler,
69         [PIPELINE_MSG_REQ_STATS_PORT_IN] =
70                 pipeline_msg_req_stats_port_in_handler,
71         [PIPELINE_MSG_REQ_STATS_PORT_OUT] =
72                 pipeline_msg_req_stats_port_out_handler,
73         [PIPELINE_MSG_REQ_STATS_TABLE] =
74                 pipeline_msg_req_stats_table_handler,
75         [PIPELINE_MSG_REQ_PORT_IN_ENABLE] =
76                 pipeline_msg_req_port_in_enable_handler,
77         [PIPELINE_MSG_REQ_PORT_IN_DISABLE] =
78                 pipeline_msg_req_port_in_disable_handler,
79         [PIPELINE_MSG_REQ_CUSTOM] =
80                 pipeline_fc_msg_req_custom_handler,
81 };
82
83 static void *
84 pipeline_fc_msg_req_add_handler(struct pipeline *p, void *msg);
85
86 static void *
87 pipeline_fc_msg_req_add_bulk_handler(struct pipeline *p, void *msg);
88
89 static void *
90 pipeline_fc_msg_req_del_handler(struct pipeline *p, void *msg);
91
92 static void *
93 pipeline_fc_msg_req_add_default_handler(struct pipeline *p, void *msg);
94
95 static void *
96 pipeline_fc_msg_req_del_default_handler(struct pipeline *p, void *msg);
97
98 static pipeline_msg_req_handler custom_handlers[] = {
99         [PIPELINE_FC_MSG_REQ_FLOW_ADD] =
100                 pipeline_fc_msg_req_add_handler,
101         [PIPELINE_FC_MSG_REQ_FLOW_ADD_BULK] =
102                 pipeline_fc_msg_req_add_bulk_handler,
103         [PIPELINE_FC_MSG_REQ_FLOW_DEL] =
104                 pipeline_fc_msg_req_del_handler,
105         [PIPELINE_FC_MSG_REQ_FLOW_ADD_DEFAULT] =
106                 pipeline_fc_msg_req_add_default_handler,
107         [PIPELINE_FC_MSG_REQ_FLOW_DEL_DEFAULT] =
108                 pipeline_fc_msg_req_del_default_handler,
109 };
110
111 /*
112  * Flow table
113  */
114 struct flow_table_entry {
115         struct rte_pipeline_table_entry head;
116
117         uint32_t flow_id;
118         uint32_t pad;
119 };
120
121 rte_table_hash_op_hash hash_func[] = {
122         hash_default_key8,
123         hash_default_key16,
124         hash_default_key24,
125         hash_default_key32,
126         hash_default_key40,
127         hash_default_key48,
128         hash_default_key56,
129         hash_default_key64
130 };
131
132 /*
133  * Flow table AH - Write flow_id to packet meta-data
134  */
135 static inline void
136 pkt_work_flow_id(
137         struct rte_mbuf *pkt,
138         struct rte_pipeline_table_entry *table_entry,
139         void *arg)
140 {
141         struct pipeline_flow_classification *p_fc = arg;
142         uint32_t *flow_id_ptr =
143                 RTE_MBUF_METADATA_UINT32_PTR(pkt, p_fc->flow_id_offset);
144         struct flow_table_entry *entry =
145                 (struct flow_table_entry *) table_entry;
146
147         /* Read */
148         uint32_t flow_id = entry->flow_id;
149
150         /* Compute */
151
152         /* Write */
153         *flow_id_ptr = flow_id;
154 }
155
156 static inline void
157 pkt4_work_flow_id(
158         struct rte_mbuf **pkts,
159         struct rte_pipeline_table_entry **table_entries,
160         void *arg)
161 {
162         struct pipeline_flow_classification *p_fc = arg;
163
164         uint32_t *flow_id_ptr0 =
165                 RTE_MBUF_METADATA_UINT32_PTR(pkts[0], p_fc->flow_id_offset);
166         uint32_t *flow_id_ptr1 =
167                 RTE_MBUF_METADATA_UINT32_PTR(pkts[1], p_fc->flow_id_offset);
168         uint32_t *flow_id_ptr2 =
169                 RTE_MBUF_METADATA_UINT32_PTR(pkts[2], p_fc->flow_id_offset);
170         uint32_t *flow_id_ptr3 =
171                 RTE_MBUF_METADATA_UINT32_PTR(pkts[3], p_fc->flow_id_offset);
172
173         struct flow_table_entry *entry0 =
174                 (struct flow_table_entry *) table_entries[0];
175         struct flow_table_entry *entry1 =
176                 (struct flow_table_entry *) table_entries[1];
177         struct flow_table_entry *entry2 =
178                 (struct flow_table_entry *) table_entries[2];
179         struct flow_table_entry *entry3 =
180                 (struct flow_table_entry *) table_entries[3];
181
182         /* Read */
183         uint32_t flow_id0 = entry0->flow_id;
184         uint32_t flow_id1 = entry1->flow_id;
185         uint32_t flow_id2 = entry2->flow_id;
186         uint32_t flow_id3 = entry3->flow_id;
187
188         /* Compute */
189
190         /* Write */
191         *flow_id_ptr0 = flow_id0;
192         *flow_id_ptr1 = flow_id1;
193         *flow_id_ptr2 = flow_id2;
194         *flow_id_ptr3 = flow_id3;
195 }
196
197 PIPELINE_TABLE_AH_HIT(fc_table_ah_hit,
198                 pkt_work_flow_id, pkt4_work_flow_id);
199
200 static rte_pipeline_table_action_handler_hit
201 get_fc_table_ah_hit(struct pipeline_flow_classification *p)
202 {
203         if (p->flow_id)
204                 return fc_table_ah_hit;
205
206         return NULL;
207 }
208
209 /*
210  * Argument parsing
211  */
212 static int
213 pipeline_fc_parse_args(struct pipeline_flow_classification *p,
214         struct pipeline_params *params)
215 {
216         uint32_t n_flows_present = 0;
217         uint32_t key_offset_present = 0;
218         uint32_t key_size_present = 0;
219         uint32_t hash_offset_present = 0;
220         uint32_t key_mask_present = 0;
221         uint32_t flow_id_offset_present = 0;
222
223         uint32_t i;
224         char key_mask_str[PIPELINE_FC_FLOW_KEY_MAX_SIZE * 2];
225
226         p->hash_offset = 0;
227
228         /* default values */
229         p->flow_id = 0;
230
231         for (i = 0; i < params->n_args; i++) {
232                 char *arg_name = params->args_name[i];
233                 char *arg_value = params->args_value[i];
234
235                 /* n_flows */
236                 if (strcmp(arg_name, "n_flows") == 0) {
237                         int status;
238
239                         PIPELINE_PARSE_ERR_DUPLICATE(
240                                 n_flows_present == 0, params->name,
241                                 arg_name);
242                         n_flows_present = 1;
243
244                         status = parser_read_uint32(&p->n_flows,
245                                 arg_value);
246                         PIPELINE_PARSE_ERR_INV_VAL(((status != -EINVAL) &&
247                                 (p->n_flows != 0)), params->name,
248                                 arg_name, arg_value);
249                         PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
250                                 params->name, arg_name, arg_value);
251
252                         continue;
253                 }
254
255                 /* key_offset */
256                 if (strcmp(arg_name, "key_offset") == 0) {
257                         int status;
258
259                         PIPELINE_PARSE_ERR_DUPLICATE(
260                                 key_offset_present == 0, params->name,
261                                 arg_name);
262                         key_offset_present = 1;
263
264                         status = parser_read_uint32(&p->key_offset,
265                                 arg_value);
266                         PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
267                                 params->name, arg_name, arg_value);
268                         PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
269                                 params->name, arg_name, arg_value);
270
271                         continue;
272                 }
273
274                 /* key_size */
275                 if (strcmp(arg_name, "key_size") == 0) {
276                         int status;
277
278                         PIPELINE_PARSE_ERR_DUPLICATE(
279                                 key_size_present == 0, params->name,
280                                 arg_name);
281                         key_size_present = 1;
282
283                         status = parser_read_uint32(&p->key_size,
284                                 arg_value);
285                         PIPELINE_PARSE_ERR_INV_VAL(((status != -EINVAL) &&
286                                 (p->key_size != 0) &&
287                                 (p->key_size % 8 == 0)),
288                                 params->name, arg_name, arg_value);
289                         PIPELINE_PARSE_ERR_OUT_RNG(((status != -ERANGE) &&
290                                 (p->key_size <=
291                                 PIPELINE_FC_FLOW_KEY_MAX_SIZE)),
292                                 params->name, arg_name, arg_value);
293
294                         continue;
295                 }
296
297                 /* key_mask */
298                 if (strcmp(arg_name, "key_mask") == 0) {
299                         int mask_str_len = strlen(arg_value);
300
301                         PIPELINE_PARSE_ERR_DUPLICATE(
302                                 key_mask_present == 0,
303                                 params->name, arg_name);
304                         key_mask_present = 1;
305
306                         PIPELINE_ARG_CHECK((mask_str_len <
307                                 (PIPELINE_FC_FLOW_KEY_MAX_SIZE * 2)),
308                                 "Parse error in section \"%s\": entry "
309                                 "\"%s\" is too long", params->name,
310                                 arg_name);
311
312                         snprintf(key_mask_str, sizeof(key_mask_str), "%s",
313                                 arg_value);
314
315                         continue;
316                 }
317
318                 /* hash_offset */
319                 if (strcmp(arg_name, "hash_offset") == 0) {
320                         int status;
321
322                         PIPELINE_PARSE_ERR_DUPLICATE(
323                                 hash_offset_present == 0, params->name,
324                                 arg_name);
325                         hash_offset_present = 1;
326
327                         status = parser_read_uint32(&p->hash_offset,
328                                 arg_value);
329                         PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
330                                 params->name, arg_name, arg_value);
331                         PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
332                                 params->name, arg_name, arg_value);
333
334                         continue;
335                 }
336
337                 /* flow_id_offset */
338                 if (strcmp(arg_name, "flowid_offset") == 0) {
339                         int status;
340
341                         PIPELINE_PARSE_ERR_DUPLICATE(
342                                 flow_id_offset_present == 0, params->name,
343                                 arg_name);
344                         flow_id_offset_present = 1;
345
346                         status = parser_read_uint32(&p->flow_id_offset,
347                                 arg_value);
348                         PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
349                                 params->name, arg_name, arg_value);
350                         PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
351                                 params->name, arg_name, arg_value);
352
353                         p->flow_id = 1;
354
355                         continue;
356                 }
357
358                 /* Unknown argument */
359                 PIPELINE_PARSE_ERR_INV_ENT(0, params->name, arg_name);
360         }
361
362         /* Check that mandatory arguments are present */
363         PIPELINE_PARSE_ERR_MANDATORY((n_flows_present), params->name,
364                 "n_flows");
365         PIPELINE_PARSE_ERR_MANDATORY((key_offset_present), params->name,
366                 "key_offset");
367         PIPELINE_PARSE_ERR_MANDATORY((key_size_present), params->name,
368                 "key_size");
369
370         if (key_mask_present) {
371                 uint32_t key_size = p->key_size;
372                 int status;
373
374                 PIPELINE_ARG_CHECK(((key_size == 8) || (key_size == 16)),
375                         "Parse error in section \"%s\": entry key_mask "
376                         "only allowed for key_size of 8 or 16 bytes",
377                         params->name);
378
379                 PIPELINE_ARG_CHECK((strlen(key_mask_str) ==
380                         (key_size * 2)), "Parse error in section "
381                         "\"%s\": key_mask should have exactly %u hex "
382                         "digits", params->name, (key_size * 2));
383
384                 PIPELINE_ARG_CHECK((hash_offset_present == 0), "Parse "
385                         "error in section \"%s\": entry hash_offset only "
386                         "allowed when key_mask is not present",
387                         params->name);
388
389                 status = parse_hex_string(key_mask_str, p->key_mask,
390                         &p->key_size);
391
392                 PIPELINE_PARSE_ERR_INV_VAL(((status == 0) &&
393                         (key_size == p->key_size)), params->name,
394                         "key_mask", key_mask_str);
395         }
396
397         p->key_mask_present = key_mask_present;
398
399         return 0;
400 }
401
402 static void *pipeline_fc_init(struct pipeline_params *params,
403         __rte_unused void *arg)
404 {
405         struct pipeline *p;
406         struct pipeline_flow_classification *p_fc;
407         uint32_t size, i;
408
409         /* Check input arguments */
410         if (params == NULL)
411                 return NULL;
412
413         /* Memory allocation */
414         size = RTE_CACHE_LINE_ROUNDUP(
415                 sizeof(struct pipeline_flow_classification));
416         p = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
417         if (p == NULL)
418                 return NULL;
419         p_fc = (struct pipeline_flow_classification *) p;
420
421         strcpy(p->name, params->name);
422         p->log_level = params->log_level;
423
424         PLOG(p, HIGH, "Flow classification");
425
426         /* Parse arguments */
427         if (pipeline_fc_parse_args(p_fc, params))
428                 return NULL;
429
430         /* Pipeline */
431         {
432                 struct rte_pipeline_params pipeline_params = {
433                         .name = params->name,
434                         .socket_id = params->socket_id,
435                         .offset_port_id = 0,
436                 };
437
438                 p->p = rte_pipeline_create(&pipeline_params);
439                 if (p->p == NULL) {
440                         rte_free(p);
441                         return NULL;
442                 }
443         }
444
445         /* Input ports */
446         p->n_ports_in = params->n_ports_in;
447         for (i = 0; i < p->n_ports_in; i++) {
448                 struct rte_pipeline_port_in_params port_params = {
449                         .ops = pipeline_port_in_params_get_ops(
450                                 &params->port_in[i]),
451                         .arg_create = pipeline_port_in_params_convert(
452                                 &params->port_in[i]),
453                         .f_action = NULL,
454                         .arg_ah = NULL,
455                         .burst_size = params->port_in[i].burst_size,
456                 };
457
458                 int status = rte_pipeline_port_in_create(p->p,
459                         &port_params,
460                         &p->port_in_id[i]);
461
462                 if (status) {
463                         rte_pipeline_free(p->p);
464                         rte_free(p);
465                         return NULL;
466                 }
467         }
468
469         /* Output ports */
470         p->n_ports_out = params->n_ports_out;
471         for (i = 0; i < p->n_ports_out; i++) {
472                 struct rte_pipeline_port_out_params port_params = {
473                         .ops = pipeline_port_out_params_get_ops(
474                                 &params->port_out[i]),
475                         .arg_create = pipeline_port_out_params_convert(
476                                 &params->port_out[i]),
477                         .f_action = NULL,
478                         .arg_ah = NULL,
479                 };
480
481                 int status = rte_pipeline_port_out_create(p->p,
482                         &port_params,
483                         &p->port_out_id[i]);
484
485                 if (status) {
486                         rte_pipeline_free(p->p);
487                         rte_free(p);
488                         return NULL;
489                 }
490         }
491
492         /* Tables */
493         p->n_tables = 1;
494         {
495                 struct rte_table_hash_key8_ext_params
496                         table_hash_key8_params = {
497                         .n_entries = p_fc->n_flows,
498                         .n_entries_ext = p_fc->n_flows,
499                         .signature_offset = p_fc->hash_offset,
500                         .key_offset = p_fc->key_offset,
501                         .f_hash = hash_func[(p_fc->key_size / 8) - 1],
502                         .key_mask = (p_fc->key_mask_present) ?
503                                 p_fc->key_mask : NULL,
504                         .seed = 0,
505                 };
506
507                 struct rte_table_hash_key16_ext_params
508                         table_hash_key16_params = {
509                         .n_entries = p_fc->n_flows,
510                         .n_entries_ext = p_fc->n_flows,
511                         .signature_offset = p_fc->hash_offset,
512                         .key_offset = p_fc->key_offset,
513                         .f_hash = hash_func[(p_fc->key_size / 8) - 1],
514                         .key_mask = (p_fc->key_mask_present) ?
515                                 p_fc->key_mask : NULL,
516                         .seed = 0,
517                 };
518
519                 struct rte_table_hash_ext_params
520                         table_hash_params = {
521                         .key_size = p_fc->key_size,
522                         .n_keys = p_fc->n_flows,
523                         .n_buckets = p_fc->n_flows / 4,
524                         .n_buckets_ext = p_fc->n_flows / 4,
525                         .f_hash = hash_func[(p_fc->key_size / 8) - 1],
526                         .seed = 0,
527                         .signature_offset = p_fc->hash_offset,
528                         .key_offset = p_fc->key_offset,
529                 };
530
531                 struct rte_pipeline_table_params table_params = {
532                         .ops = NULL, /* set below */
533                         .arg_create = NULL, /* set below */
534                         .f_action_hit = get_fc_table_ah_hit(p_fc),
535                         .f_action_miss = NULL,
536                         .arg_ah = p_fc,
537                         .action_data_size = sizeof(struct flow_table_entry) -
538                                 sizeof(struct rte_pipeline_table_entry),
539                 };
540
541                 int status;
542
543                 switch (p_fc->key_size) {
544                 case 8:
545                         if (p_fc->hash_offset != 0) {
546                                 table_params.ops =
547                                         &rte_table_hash_key8_ext_ops;
548                         } else {
549                                 table_params.ops =
550                                         &rte_table_hash_key8_ext_dosig_ops;
551                         }
552                         table_params.arg_create = &table_hash_key8_params;
553                         break;
554
555                 case 16:
556                         if (p_fc->hash_offset != 0) {
557                                 table_params.ops =
558                                         &rte_table_hash_key16_ext_ops;
559                         } else {
560                                 table_params.ops =
561                                         &rte_table_hash_key16_ext_dosig_ops;
562                         }
563                         table_params.arg_create = &table_hash_key16_params;
564                         break;
565
566                 default:
567                         table_params.ops = &rte_table_hash_ext_ops;
568                         table_params.arg_create = &table_hash_params;
569                 }
570
571                 status = rte_pipeline_table_create(p->p,
572                         &table_params,
573                         &p->table_id[0]);
574
575                 if (status) {
576                         rte_pipeline_free(p->p);
577                         rte_free(p);
578                         return NULL;
579                 }
580         }
581
582         /* Connecting input ports to tables */
583         for (i = 0; i < p->n_ports_in; i++) {
584                 int status = rte_pipeline_port_in_connect_to_table(p->p,
585                         p->port_in_id[i],
586                         p->table_id[0]);
587
588                 if (status) {
589                         rte_pipeline_free(p->p);
590                         rte_free(p);
591                         return NULL;
592                 }
593         }
594
595         /* Enable input ports */
596         for (i = 0; i < p->n_ports_in; i++) {
597                 int status = rte_pipeline_port_in_enable(p->p,
598                         p->port_in_id[i]);
599
600                 if (status) {
601                         rte_pipeline_free(p->p);
602                         rte_free(p);
603                         return NULL;
604                 }
605         }
606
607         /* Check pipeline consistency */
608         if (rte_pipeline_check(p->p) < 0) {
609                 rte_pipeline_free(p->p);
610                 rte_free(p);
611                 return NULL;
612         }
613
614         /* Message queues */
615         p->n_msgq = params->n_msgq;
616         for (i = 0; i < p->n_msgq; i++)
617                 p->msgq_in[i] = params->msgq_in[i];
618         for (i = 0; i < p->n_msgq; i++)
619                 p->msgq_out[i] = params->msgq_out[i];
620
621         /* Message handlers */
622         memcpy(p->handlers, handlers, sizeof(p->handlers));
623         memcpy(p_fc->custom_handlers,
624                 custom_handlers,
625                 sizeof(p_fc->custom_handlers));
626
627         return p;
628 }
629
630 static int
631 pipeline_fc_free(void *pipeline)
632 {
633         struct pipeline *p = (struct pipeline *) pipeline;
634
635         /* Check input arguments */
636         if (p == NULL)
637                 return -1;
638
639         /* Free resources */
640         rte_pipeline_free(p->p);
641         rte_free(p);
642         return 0;
643 }
644
645 static int
646 pipeline_fc_track(void *pipeline,
647         __rte_unused uint32_t port_in,
648         uint32_t *port_out)
649 {
650         struct pipeline *p = (struct pipeline *) pipeline;
651
652         /* Check input arguments */
653         if ((p == NULL) ||
654                 (port_in >= p->n_ports_in) ||
655                 (port_out == NULL))
656                 return -1;
657
658         if (p->n_ports_in == 1) {
659                 *port_out = 0;
660                 return 0;
661         }
662
663         return -1;
664 }
665
666 static int
667 pipeline_fc_timer(void *pipeline)
668 {
669         struct pipeline *p = (struct pipeline *) pipeline;
670
671         pipeline_msg_req_handle(p);
672         rte_pipeline_flush(p->p);
673
674         return 0;
675 }
676
677 static void *
678 pipeline_fc_msg_req_custom_handler(struct pipeline *p, void *msg)
679 {
680         struct pipeline_flow_classification *p_fc =
681                         (struct pipeline_flow_classification *) p;
682         struct pipeline_custom_msg_req *req = msg;
683         pipeline_msg_req_handler f_handle;
684
685         f_handle = (req->subtype < PIPELINE_FC_MSG_REQS) ?
686                 p_fc->custom_handlers[req->subtype] :
687                 pipeline_msg_req_invalid_handler;
688
689         if (f_handle == NULL)
690                 f_handle = pipeline_msg_req_invalid_handler;
691
692         return f_handle(p, req);
693 }
694
695 static void *
696 pipeline_fc_msg_req_add_handler(struct pipeline *p, void *msg)
697 {
698         struct pipeline_fc_add_msg_req *req = msg;
699         struct pipeline_fc_add_msg_rsp *rsp = msg;
700
701         struct flow_table_entry entry = {
702                 .head = {
703                         .action = RTE_PIPELINE_ACTION_PORT,
704                         {.port_id = p->port_out_id[req->port_id]},
705                 },
706                 .flow_id = req->flow_id,
707         };
708
709         rsp->status = rte_pipeline_table_entry_add(p->p,
710                 p->table_id[0],
711                 &req->key,
712                 (struct rte_pipeline_table_entry *) &entry,
713                 &rsp->key_found,
714                 (struct rte_pipeline_table_entry **) &rsp->entry_ptr);
715
716         return rsp;
717 }
718
719 static void *
720 pipeline_fc_msg_req_add_bulk_handler(struct pipeline *p, void *msg)
721 {
722         struct pipeline_fc_add_bulk_msg_req *req = msg;
723         struct pipeline_fc_add_bulk_msg_rsp *rsp = msg;
724         uint32_t i;
725
726         for (i = 0; i < req->n_keys; i++) {
727                 struct pipeline_fc_add_bulk_flow_req *flow_req = &req->req[i];
728                 struct pipeline_fc_add_bulk_flow_rsp *flow_rsp = &req->rsp[i];
729
730                 struct flow_table_entry entry = {
731                         .head = {
732                                 .action = RTE_PIPELINE_ACTION_PORT,
733                                 {.port_id = p->port_out_id[flow_req->port_id]},
734                         },
735                         .flow_id = flow_req->flow_id,
736                 };
737
738                 int status = rte_pipeline_table_entry_add(p->p,
739                         p->table_id[0],
740                         &flow_req->key,
741                         (struct rte_pipeline_table_entry *) &entry,
742                         &flow_rsp->key_found,
743                         (struct rte_pipeline_table_entry **)
744                                 &flow_rsp->entry_ptr);
745
746                 if (status)
747                         break;
748         }
749
750         rsp->n_keys = i;
751
752         return rsp;
753 }
754
755 static void *
756 pipeline_fc_msg_req_del_handler(struct pipeline *p, void *msg)
757 {
758         struct pipeline_fc_del_msg_req *req = msg;
759         struct pipeline_fc_del_msg_rsp *rsp = msg;
760
761         rsp->status = rte_pipeline_table_entry_delete(p->p,
762                 p->table_id[0],
763                 &req->key,
764                 &rsp->key_found,
765                 NULL);
766
767         return rsp;
768 }
769
770 static void *
771 pipeline_fc_msg_req_add_default_handler(struct pipeline *p, void *msg)
772 {
773         struct pipeline_fc_add_default_msg_req *req = msg;
774         struct pipeline_fc_add_default_msg_rsp *rsp = msg;
775
776         struct flow_table_entry default_entry = {
777                 .head = {
778                         .action = RTE_PIPELINE_ACTION_PORT,
779                         {.port_id = p->port_out_id[req->port_id]},
780                 },
781
782                 .flow_id = 0,
783         };
784
785         rsp->status = rte_pipeline_table_default_entry_add(p->p,
786                 p->table_id[0],
787                 (struct rte_pipeline_table_entry *) &default_entry,
788                 (struct rte_pipeline_table_entry **) &rsp->entry_ptr);
789
790         return rsp;
791 }
792
793 static void *
794 pipeline_fc_msg_req_del_default_handler(struct pipeline *p, void *msg)
795 {
796         struct pipeline_fc_del_default_msg_rsp *rsp = msg;
797
798         rsp->status = rte_pipeline_table_default_entry_delete(p->p,
799                 p->table_id[0],
800                 NULL);
801
802         return rsp;
803 }
804
805 struct pipeline_be_ops pipeline_flow_classification_be_ops = {
806         .f_init = pipeline_fc_init,
807         .f_free = pipeline_fc_free,
808         .f_run = NULL,
809         .f_timer = pipeline_fc_timer,
810         .f_track = pipeline_fc_track,
811 };