table: rework variable size key ext hash tables
[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_nomask 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 + 1];
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, mask_str_len + 1, "%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_params table_hash_params = {
520                         .name = p->name,
521                         .key_size = p_fc->key_size,
522                         .key_offset = p_fc->key_offset,
523                         .key_mask = (p_fc->key_mask_present) ?
524                                 p_fc->key_mask : NULL,
525                         .n_keys = p_fc->n_flows,
526                         .n_buckets = p_fc->n_flows / 4,
527                         .f_hash = (rte_table_hash_op_hash)hash_func[(p_fc->key_size / 8) - 1],
528                         .seed = 0,
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                         table_params.ops = &rte_table_hash_key8_ext_ops;
546                         table_params.arg_create = &table_hash_key8_params;
547                         break;
548
549                 case 16:
550                         table_params.ops = &rte_table_hash_key16_ext_ops;
551                         table_params.arg_create = &table_hash_key16_params;
552                         break;
553
554                 default:
555                         table_params.ops = &rte_table_hash_ext_ops;
556                         table_params.arg_create = &table_hash_params;
557                 }
558
559                 status = rte_pipeline_table_create(p->p,
560                         &table_params,
561                         &p->table_id[0]);
562
563                 if (status) {
564                         rte_pipeline_free(p->p);
565                         rte_free(p);
566                         return NULL;
567                 }
568         }
569
570         /* Connecting input ports to tables */
571         for (i = 0; i < p->n_ports_in; i++) {
572                 int status = rte_pipeline_port_in_connect_to_table(p->p,
573                         p->port_in_id[i],
574                         p->table_id[0]);
575
576                 if (status) {
577                         rte_pipeline_free(p->p);
578                         rte_free(p);
579                         return NULL;
580                 }
581         }
582
583         /* Enable input ports */
584         for (i = 0; i < p->n_ports_in; i++) {
585                 int status = rte_pipeline_port_in_enable(p->p,
586                         p->port_in_id[i]);
587
588                 if (status) {
589                         rte_pipeline_free(p->p);
590                         rte_free(p);
591                         return NULL;
592                 }
593         }
594
595         /* Check pipeline consistency */
596         if (rte_pipeline_check(p->p) < 0) {
597                 rte_pipeline_free(p->p);
598                 rte_free(p);
599                 return NULL;
600         }
601
602         /* Message queues */
603         p->n_msgq = params->n_msgq;
604         for (i = 0; i < p->n_msgq; i++)
605                 p->msgq_in[i] = params->msgq_in[i];
606         for (i = 0; i < p->n_msgq; i++)
607                 p->msgq_out[i] = params->msgq_out[i];
608
609         /* Message handlers */
610         memcpy(p->handlers, handlers, sizeof(p->handlers));
611         memcpy(p_fc->custom_handlers,
612                 custom_handlers,
613                 sizeof(p_fc->custom_handlers));
614
615         return p;
616 }
617
618 static int
619 pipeline_fc_free(void *pipeline)
620 {
621         struct pipeline *p = (struct pipeline *) pipeline;
622
623         /* Check input arguments */
624         if (p == NULL)
625                 return -1;
626
627         /* Free resources */
628         rte_pipeline_free(p->p);
629         rte_free(p);
630         return 0;
631 }
632
633 static int
634 pipeline_fc_timer(void *pipeline)
635 {
636         struct pipeline *p = (struct pipeline *) pipeline;
637
638         pipeline_msg_req_handle(p);
639         rte_pipeline_flush(p->p);
640
641         return 0;
642 }
643
644 static void *
645 pipeline_fc_msg_req_custom_handler(struct pipeline *p, void *msg)
646 {
647         struct pipeline_flow_classification *p_fc =
648                         (struct pipeline_flow_classification *) p;
649         struct pipeline_custom_msg_req *req = msg;
650         pipeline_msg_req_handler f_handle;
651
652         f_handle = (req->subtype < PIPELINE_FC_MSG_REQS) ?
653                 p_fc->custom_handlers[req->subtype] :
654                 pipeline_msg_req_invalid_handler;
655
656         if (f_handle == NULL)
657                 f_handle = pipeline_msg_req_invalid_handler;
658
659         return f_handle(p, req);
660 }
661
662 static void *
663 pipeline_fc_msg_req_add_handler(struct pipeline *p, void *msg)
664 {
665         struct pipeline_fc_add_msg_req *req = msg;
666         struct pipeline_fc_add_msg_rsp *rsp = msg;
667
668         struct flow_table_entry entry = {
669                 .head = {
670                         .action = RTE_PIPELINE_ACTION_PORT,
671                         {.port_id = p->port_out_id[req->port_id]},
672                 },
673                 .flow_id = req->flow_id,
674         };
675
676         rsp->status = rte_pipeline_table_entry_add(p->p,
677                 p->table_id[0],
678                 &req->key,
679                 (struct rte_pipeline_table_entry *) &entry,
680                 &rsp->key_found,
681                 (struct rte_pipeline_table_entry **) &rsp->entry_ptr);
682
683         return rsp;
684 }
685
686 static void *
687 pipeline_fc_msg_req_add_bulk_handler(struct pipeline *p, void *msg)
688 {
689         struct pipeline_fc_add_bulk_msg_req *req = msg;
690         struct pipeline_fc_add_bulk_msg_rsp *rsp = msg;
691         uint32_t i;
692
693         for (i = 0; i < req->n_keys; i++) {
694                 struct pipeline_fc_add_bulk_flow_req *flow_req = &req->req[i];
695                 struct pipeline_fc_add_bulk_flow_rsp *flow_rsp = &req->rsp[i];
696
697                 struct flow_table_entry entry = {
698                         .head = {
699                                 .action = RTE_PIPELINE_ACTION_PORT,
700                                 {.port_id = p->port_out_id[flow_req->port_id]},
701                         },
702                         .flow_id = flow_req->flow_id,
703                 };
704
705                 int status = rte_pipeline_table_entry_add(p->p,
706                         p->table_id[0],
707                         &flow_req->key,
708                         (struct rte_pipeline_table_entry *) &entry,
709                         &flow_rsp->key_found,
710                         (struct rte_pipeline_table_entry **)
711                                 &flow_rsp->entry_ptr);
712
713                 if (status)
714                         break;
715         }
716
717         rsp->n_keys = i;
718
719         return rsp;
720 }
721
722 static void *
723 pipeline_fc_msg_req_del_handler(struct pipeline *p, void *msg)
724 {
725         struct pipeline_fc_del_msg_req *req = msg;
726         struct pipeline_fc_del_msg_rsp *rsp = msg;
727
728         rsp->status = rte_pipeline_table_entry_delete(p->p,
729                 p->table_id[0],
730                 &req->key,
731                 &rsp->key_found,
732                 NULL);
733
734         return rsp;
735 }
736
737 static void *
738 pipeline_fc_msg_req_add_default_handler(struct pipeline *p, void *msg)
739 {
740         struct pipeline_fc_add_default_msg_req *req = msg;
741         struct pipeline_fc_add_default_msg_rsp *rsp = msg;
742
743         struct flow_table_entry default_entry = {
744                 .head = {
745                         .action = RTE_PIPELINE_ACTION_PORT,
746                         {.port_id = p->port_out_id[req->port_id]},
747                 },
748
749                 .flow_id = 0,
750         };
751
752         rsp->status = rte_pipeline_table_default_entry_add(p->p,
753                 p->table_id[0],
754                 (struct rte_pipeline_table_entry *) &default_entry,
755                 (struct rte_pipeline_table_entry **) &rsp->entry_ptr);
756
757         return rsp;
758 }
759
760 static void *
761 pipeline_fc_msg_req_del_default_handler(struct pipeline *p, void *msg)
762 {
763         struct pipeline_fc_del_default_msg_rsp *rsp = msg;
764
765         rsp->status = rte_pipeline_table_default_entry_delete(p->p,
766                 p->table_id[0],
767                 NULL);
768
769         return rsp;
770 }
771
772 struct pipeline_be_ops pipeline_flow_classification_be_ops = {
773         .f_init = pipeline_fc_init,
774         .f_free = pipeline_fc_free,
775         .f_run = NULL,
776         .f_timer = pipeline_fc_timer,
777 };