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