Imported Upstream version 16.07-rc1
[deb_dpdk.git] / examples / ip_pipeline / pipeline / pipeline_passthrough_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_byteorder.h>
39 #include <rte_table_stub.h>
40 #include <rte_table_hash.h>
41 #include <rte_pipeline.h>
42
43 #include "pipeline_passthrough_be.h"
44 #include "pipeline_actions_common.h"
45 #include "parser.h"
46 #include "hash_func.h"
47
48 struct pipeline_passthrough {
49         struct pipeline p;
50         struct pipeline_passthrough_params params;
51         rte_table_hash_op_hash f_hash;
52 } __rte_cache_aligned;
53
54 static pipeline_msg_req_handler handlers[] = {
55         [PIPELINE_MSG_REQ_PING] =
56                 pipeline_msg_req_ping_handler,
57         [PIPELINE_MSG_REQ_STATS_PORT_IN] =
58                 pipeline_msg_req_stats_port_in_handler,
59         [PIPELINE_MSG_REQ_STATS_PORT_OUT] =
60                 pipeline_msg_req_stats_port_out_handler,
61         [PIPELINE_MSG_REQ_STATS_TABLE] =
62                 pipeline_msg_req_stats_table_handler,
63         [PIPELINE_MSG_REQ_PORT_IN_ENABLE] =
64                 pipeline_msg_req_port_in_enable_handler,
65         [PIPELINE_MSG_REQ_PORT_IN_DISABLE] =
66                 pipeline_msg_req_port_in_disable_handler,
67         [PIPELINE_MSG_REQ_CUSTOM] =
68                 pipeline_msg_req_invalid_handler,
69 };
70
71 static inline __attribute__((always_inline)) void
72 pkt_work(
73         struct rte_mbuf *pkt,
74         void *arg,
75         uint32_t dma_size,
76         uint32_t hash_enabled,
77         uint32_t lb_hash,
78         uint32_t port_out_pow2)
79 {
80         struct pipeline_passthrough *p = arg;
81
82         uint64_t *dma_dst = RTE_MBUF_METADATA_UINT64_PTR(pkt,
83                 p->params.dma_dst_offset);
84         uint64_t *dma_src = RTE_MBUF_METADATA_UINT64_PTR(pkt,
85                 p->params.dma_src_offset);
86         uint64_t *dma_mask = (uint64_t *) p->params.dma_src_mask;
87         uint32_t *dma_hash = RTE_MBUF_METADATA_UINT32_PTR(pkt,
88                 p->params.dma_hash_offset);
89         uint32_t i;
90
91         /* Read (dma_src), compute (dma_dst), write (dma_dst) */
92         for (i = 0; i < (dma_size / 8); i++)
93                 dma_dst[i] = dma_src[i] & dma_mask[i];
94
95         /* Read (dma_dst), compute (hash), write (hash) */
96         if (hash_enabled) {
97                 uint32_t hash = p->f_hash(dma_dst, dma_size, 0);
98                 *dma_hash = hash;
99
100                 if (lb_hash) {
101                         uint32_t port_out;
102
103                         if (port_out_pow2)
104                                 port_out
105                                         = hash & (p->p.n_ports_out - 1);
106                         else
107                                 port_out
108                                         = hash % p->p.n_ports_out;
109
110                         rte_pipeline_port_out_packet_insert(p->p.p,
111                                 port_out, pkt);
112                 }
113         }
114 }
115
116 static inline __attribute__((always_inline)) void
117 pkt4_work(
118         struct rte_mbuf **pkts,
119         void *arg,
120         uint32_t dma_size,
121         uint32_t hash_enabled,
122         uint32_t lb_hash,
123         uint32_t port_out_pow2)
124 {
125         struct pipeline_passthrough *p = arg;
126
127         uint64_t *dma_dst0 = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],
128                 p->params.dma_dst_offset);
129         uint64_t *dma_dst1 = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],
130                 p->params.dma_dst_offset);
131         uint64_t *dma_dst2 = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],
132                 p->params.dma_dst_offset);
133         uint64_t *dma_dst3 = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],
134                 p->params.dma_dst_offset);
135
136         uint64_t *dma_src0 = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],
137                 p->params.dma_src_offset);
138         uint64_t *dma_src1 = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],
139                 p->params.dma_src_offset);
140         uint64_t *dma_src2 = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],
141                 p->params.dma_src_offset);
142         uint64_t *dma_src3 = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],
143                 p->params.dma_src_offset);
144
145         uint64_t *dma_mask = (uint64_t *) p->params.dma_src_mask;
146
147         uint32_t *dma_hash0 = RTE_MBUF_METADATA_UINT32_PTR(pkts[0],
148                 p->params.dma_hash_offset);
149         uint32_t *dma_hash1 = RTE_MBUF_METADATA_UINT32_PTR(pkts[1],
150                 p->params.dma_hash_offset);
151         uint32_t *dma_hash2 = RTE_MBUF_METADATA_UINT32_PTR(pkts[2],
152                 p->params.dma_hash_offset);
153         uint32_t *dma_hash3 = RTE_MBUF_METADATA_UINT32_PTR(pkts[3],
154                 p->params.dma_hash_offset);
155
156         uint32_t i;
157
158         /* Read (dma_src), compute (dma_dst), write (dma_dst) */
159         for (i = 0; i < (dma_size / 8); i++) {
160                 dma_dst0[i] = dma_src0[i] & dma_mask[i];
161                 dma_dst1[i] = dma_src1[i] & dma_mask[i];
162                 dma_dst2[i] = dma_src2[i] & dma_mask[i];
163                 dma_dst3[i] = dma_src3[i] & dma_mask[i];
164         }
165
166         /* Read (dma_dst), compute (hash), write (hash) */
167         if (hash_enabled) {
168                 uint32_t hash0 = p->f_hash(dma_dst0, dma_size, 0);
169                 uint32_t hash1 = p->f_hash(dma_dst1, dma_size, 0);
170                 uint32_t hash2 = p->f_hash(dma_dst2, dma_size, 0);
171                 uint32_t hash3 = p->f_hash(dma_dst3, dma_size, 0);
172
173                 *dma_hash0 = hash0;
174                 *dma_hash1 = hash1;
175                 *dma_hash2 = hash2;
176                 *dma_hash3 = hash3;
177
178                 if (lb_hash) {
179                         uint32_t port_out0, port_out1, port_out2, port_out3;
180
181                         if (port_out_pow2) {
182                                 port_out0
183                                         = hash0 & (p->p.n_ports_out - 1);
184                                 port_out1
185                                         = hash1 & (p->p.n_ports_out - 1);
186                                 port_out2
187                                         = hash2 & (p->p.n_ports_out - 1);
188                                 port_out3
189                                         = hash3 & (p->p.n_ports_out - 1);
190                         } else {
191                                 port_out0
192                                         = hash0 % p->p.n_ports_out;
193                                 port_out1
194                                         = hash1 % p->p.n_ports_out;
195                                 port_out2
196                                         = hash2 % p->p.n_ports_out;
197                                 port_out3
198                                         = hash3 % p->p.n_ports_out;
199                         }
200                         rte_pipeline_port_out_packet_insert(p->p.p,
201                                 port_out0, pkts[0]);
202                         rte_pipeline_port_out_packet_insert(p->p.p,
203                                 port_out1, pkts[1]);
204                         rte_pipeline_port_out_packet_insert(p->p.p,
205                                 port_out2, pkts[2]);
206                         rte_pipeline_port_out_packet_insert(p->p.p,
207                                 port_out3, pkts[3]);
208                 }
209         }
210 }
211
212 #define PKT_WORK(dma_size, hash_enabled, lb_hash, port_pow2)    \
213 static inline void                                              \
214 pkt_work_size##dma_size##_hash##hash_enabled            \
215         ##_lb##lb_hash##_pw##port_pow2(                 \
216         struct rte_mbuf *pkt,                                   \
217         void *arg)                                              \
218 {                                                               \
219         pkt_work(pkt, arg, dma_size, hash_enabled, lb_hash, port_pow2); \
220 }
221
222 #define PKT4_WORK(dma_size, hash_enabled, lb_hash, port_pow2)   \
223 static inline void                                              \
224 pkt4_work_size##dma_size##_hash##hash_enabled                   \
225         ##_lb##lb_hash##_pw##port_pow2(                 \
226         struct rte_mbuf **pkts,                                 \
227         void *arg)                                              \
228 {                                                               \
229         pkt4_work(pkts, arg, dma_size, hash_enabled, lb_hash, port_pow2); \
230 }
231
232 #define port_in_ah(dma_size, hash_enabled, lb_hash, port_pow2)  \
233 PKT_WORK(dma_size, hash_enabled, lb_hash, port_pow2)                    \
234 PKT4_WORK(dma_size, hash_enabled, lb_hash, port_pow2)                   \
235 PIPELINE_PORT_IN_AH(port_in_ah_size##dma_size##_hash    \
236         ##hash_enabled##_lb##lb_hash##_pw##port_pow2,           \
237         pkt_work_size##dma_size##_hash##hash_enabled            \
238         ##_lb##lb_hash##_pw##port_pow2,                 \
239         pkt4_work_size##dma_size##_hash##hash_enabled           \
240         ##_lb##lb_hash##_pw##port_pow2)
241
242
243 #define port_in_ah_lb(dma_size, hash_enabled, lb_hash, port_pow2) \
244 PKT_WORK(dma_size, hash_enabled, lb_hash, port_pow2)            \
245 PKT4_WORK(dma_size, hash_enabled, lb_hash, port_pow2)   \
246 PIPELINE_PORT_IN_AH_HIJACK_ALL(                                         \
247         port_in_ah_size##dma_size##_hash##hash_enabled          \
248         ##_lb##lb_hash##_pw##port_pow2,                 \
249         pkt_work_size##dma_size##_hash##hash_enabled            \
250         ##_lb##lb_hash##_pw##port_pow2, \
251         pkt4_work_size##dma_size##_hash##hash_enabled           \
252         ##_lb##lb_hash##_pw##port_pow2)
253
254 /* Port in AH (dma_size, hash_enabled, lb_hash, port_pow2) */
255
256 port_in_ah(8, 0, 0, 0)
257 port_in_ah(8, 1, 0, 0)
258 port_in_ah_lb(8, 1, 1, 0)
259 port_in_ah_lb(8, 1, 1, 1)
260
261 port_in_ah(16, 0, 0, 0)
262 port_in_ah(16, 1, 0, 0)
263 port_in_ah_lb(16, 1, 1, 0)
264 port_in_ah_lb(16, 1, 1, 1)
265
266 port_in_ah(24, 0, 0, 0)
267 port_in_ah(24, 1, 0, 0)
268 port_in_ah_lb(24, 1, 1, 0)
269 port_in_ah_lb(24, 1, 1, 1)
270
271 port_in_ah(32, 0, 0, 0)
272 port_in_ah(32, 1, 0, 0)
273 port_in_ah_lb(32, 1, 1, 0)
274 port_in_ah_lb(32, 1, 1, 1)
275
276 port_in_ah(40, 0, 0, 0)
277 port_in_ah(40, 1, 0, 0)
278 port_in_ah_lb(40, 1, 1, 0)
279 port_in_ah_lb(40, 1, 1, 1)
280
281 port_in_ah(48, 0, 0, 0)
282 port_in_ah(48, 1, 0, 0)
283 port_in_ah_lb(48, 1, 1, 0)
284 port_in_ah_lb(48, 1, 1, 1)
285
286 port_in_ah(56, 0, 0, 0)
287 port_in_ah(56, 1, 0, 0)
288 port_in_ah_lb(56, 1, 1, 0)
289 port_in_ah_lb(56, 1, 1, 1)
290
291 port_in_ah(64, 0, 0, 0)
292 port_in_ah(64, 1, 0, 0)
293 port_in_ah_lb(64, 1, 1, 0)
294 port_in_ah_lb(64, 1, 1, 1)
295
296 static rte_pipeline_port_in_action_handler
297 get_port_in_ah(struct pipeline_passthrough *p)
298 {
299         if (p->params.dma_enabled == 0)
300                 return NULL;
301
302         if (p->params.dma_hash_enabled) {
303                 if (p->params.lb_hash_enabled) {
304                         if (rte_is_power_of_2(p->p.n_ports_out))
305                                 switch (p->params.dma_size) {
306
307                                 case 8: return port_in_ah_size8_hash1_lb1_pw1;
308                                 case 16: return port_in_ah_size16_hash1_lb1_pw1;
309                                 case 24: return port_in_ah_size24_hash1_lb1_pw1;
310                                 case 32: return port_in_ah_size32_hash1_lb1_pw1;
311                                 case 40: return port_in_ah_size40_hash1_lb1_pw1;
312                                 case 48: return port_in_ah_size48_hash1_lb1_pw1;
313                                 case 56: return port_in_ah_size56_hash1_lb1_pw1;
314                                 case 64: return port_in_ah_size64_hash1_lb1_pw1;
315                                 default: return NULL;
316                                 }
317                         else
318                                 switch (p->params.dma_size) {
319
320                                 case 8: return port_in_ah_size8_hash1_lb1_pw0;
321                                 case 16: return port_in_ah_size16_hash1_lb1_pw0;
322                                 case 24: return port_in_ah_size24_hash1_lb1_pw0;
323                                 case 32: return port_in_ah_size32_hash1_lb1_pw0;
324                                 case 40: return port_in_ah_size40_hash1_lb1_pw0;
325                                 case 48: return port_in_ah_size48_hash1_lb1_pw0;
326                                 case 56: return port_in_ah_size56_hash1_lb1_pw0;
327                                 case 64: return port_in_ah_size64_hash1_lb1_pw0;
328                                 default: return NULL;
329                         }
330                 } else
331                         switch (p->params.dma_size) {
332
333                         case 8: return port_in_ah_size8_hash1_lb0_pw0;
334                         case 16: return port_in_ah_size16_hash1_lb0_pw0;
335                         case 24: return port_in_ah_size24_hash1_lb0_pw0;
336                         case 32: return port_in_ah_size32_hash1_lb0_pw0;
337                         case 40: return port_in_ah_size40_hash1_lb0_pw0;
338                         case 48: return port_in_ah_size48_hash1_lb0_pw0;
339                         case 56: return port_in_ah_size56_hash1_lb0_pw0;
340                         case 64: return port_in_ah_size64_hash1_lb0_pw0;
341                         default: return NULL;
342                 }
343         } else
344                 switch (p->params.dma_size) {
345
346                 case 8: return port_in_ah_size8_hash0_lb0_pw0;
347                 case 16: return port_in_ah_size16_hash0_lb0_pw0;
348                 case 24: return port_in_ah_size24_hash0_lb0_pw0;
349                 case 32: return port_in_ah_size32_hash0_lb0_pw0;
350                 case 40: return port_in_ah_size40_hash0_lb0_pw0;
351                 case 48: return port_in_ah_size48_hash0_lb0_pw0;
352                 case 56: return port_in_ah_size56_hash0_lb0_pw0;
353                 case 64: return port_in_ah_size64_hash0_lb0_pw0;
354                 default: return NULL;
355                 }
356 }
357
358 int
359 pipeline_passthrough_parse_args(struct pipeline_passthrough_params *p,
360         struct pipeline_params *params)
361 {
362         uint32_t dma_dst_offset_present = 0;
363         uint32_t dma_src_offset_present = 0;
364         uint32_t dma_src_mask_present = 0;
365         uint32_t dma_size_present = 0;
366         uint32_t dma_hash_offset_present = 0;
367         uint32_t lb_present = 0;
368         uint32_t i;
369         char dma_mask_str[PIPELINE_PASSTHROUGH_DMA_SIZE_MAX * 2];
370
371         /* default values */
372         p->dma_enabled = 0;
373         p->dma_hash_enabled = 0;
374         p->lb_hash_enabled = 0;
375         memset(p->dma_src_mask, 0xFF, sizeof(p->dma_src_mask));
376
377         for (i = 0; i < params->n_args; i++) {
378                 char *arg_name = params->args_name[i];
379                 char *arg_value = params->args_value[i];
380
381                 /* dma_dst_offset */
382                 if (strcmp(arg_name, "dma_dst_offset") == 0) {
383                         int status;
384
385                         PIPELINE_PARSE_ERR_DUPLICATE(
386                                 dma_dst_offset_present == 0, params->name,
387                                 arg_name);
388                         dma_dst_offset_present = 1;
389
390                         status = parser_read_uint32(&p->dma_dst_offset,
391                                 arg_value);
392                         PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
393                                 params->name, arg_name, arg_value);
394                         PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
395                                 params->name, arg_name, arg_value);
396
397                         p->dma_enabled = 1;
398
399                         continue;
400                 }
401
402                 /* dma_src_offset */
403                 if (strcmp(arg_name, "dma_src_offset") == 0) {
404                         int status;
405
406                         PIPELINE_PARSE_ERR_DUPLICATE(
407                                 dma_src_offset_present == 0, params->name,
408                                 arg_name);
409                         dma_src_offset_present = 1;
410
411                         status = parser_read_uint32(&p->dma_src_offset,
412                                 arg_value);
413                         PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
414                                 params->name, arg_name, arg_value);
415                         PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
416                                 params->name, arg_name, arg_value);
417
418                         p->dma_enabled = 1;
419
420                         continue;
421                 }
422
423                 /* dma_size */
424                 if (strcmp(arg_name, "dma_size") == 0) {
425                         int status;
426
427                         PIPELINE_PARSE_ERR_DUPLICATE(
428                                 dma_size_present == 0, params->name,
429                                 arg_name);
430                         dma_size_present = 1;
431
432                         status = parser_read_uint32(&p->dma_size,
433                                 arg_value);
434                         PIPELINE_PARSE_ERR_INV_VAL(((status != -EINVAL) &&
435                                 (p->dma_size != 0) &&
436                                 ((p->dma_size % 8) == 0)),
437                                 params->name, arg_name, arg_value);
438                         PIPELINE_PARSE_ERR_OUT_RNG(((status != -ERANGE) &&
439                                 (p->dma_size <=
440                                 PIPELINE_PASSTHROUGH_DMA_SIZE_MAX)),
441                                 params->name, arg_name, arg_value);
442
443                         p->dma_enabled = 1;
444
445                         continue;
446                 }
447
448                 /* dma_src_mask */
449                 if (strcmp(arg_name, "dma_src_mask") == 0) {
450                         int mask_str_len = strlen(arg_value);
451
452                         PIPELINE_PARSE_ERR_DUPLICATE(
453                                 dma_src_mask_present == 0,
454                                 params->name, arg_name);
455                         dma_src_mask_present = 1;
456
457                         PIPELINE_ARG_CHECK((mask_str_len <
458                                 (PIPELINE_PASSTHROUGH_DMA_SIZE_MAX * 2)),
459                                 "Parse error in section \"%s\": entry "
460                                 "\"%s\" too long", params->name,
461                                 arg_name);
462
463                         snprintf(dma_mask_str, mask_str_len + 1,
464                                 "%s", arg_value);
465
466                         p->dma_enabled = 1;
467
468                         continue;
469                 }
470
471                 /* dma_hash_offset */
472                 if (strcmp(arg_name, "dma_hash_offset") == 0) {
473                         int status;
474
475                         PIPELINE_PARSE_ERR_DUPLICATE(
476                                 dma_hash_offset_present == 0,
477                                 params->name, arg_name);
478                         dma_hash_offset_present = 1;
479
480                         status = parser_read_uint32(&p->dma_hash_offset,
481                                 arg_value);
482                         PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
483                                 params->name, arg_name, arg_value);
484                         PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
485                                 params->name, arg_name, arg_value);
486
487                         p->dma_hash_enabled = 1;
488                         p->dma_enabled = 1;
489
490                         continue;
491                 }
492
493                 /* load_balance mode */
494                 if (strcmp(arg_name, "lb") == 0) {
495                         PIPELINE_PARSE_ERR_DUPLICATE(
496                                 lb_present == 0,
497                                 params->name, arg_name);
498                         lb_present = 1;
499
500                         if ((strcmp(arg_value, "hash") == 0) ||
501                                 (strcmp(arg_value, "HASH") == 0))
502                                 p->lb_hash_enabled = 1;
503                         else
504                                 PIPELINE_PARSE_ERR_INV_VAL(0,
505                                         params->name,
506                                         arg_name,
507                                         arg_value);
508
509                         continue;
510                 }
511
512                 /* any other */
513                 PIPELINE_PARSE_ERR_INV_ENT(0, params->name, arg_name);
514         }
515
516         /* Check correlations between arguments */
517         PIPELINE_ARG_CHECK((dma_dst_offset_present == p->dma_enabled),
518                 "Parse error in section \"%s\": missing entry "
519                 "\"dma_dst_offset\"", params->name);
520         PIPELINE_ARG_CHECK((dma_src_offset_present == p->dma_enabled),
521                 "Parse error in section \"%s\": missing entry "
522                 "\"dma_src_offset\"", params->name);
523         PIPELINE_ARG_CHECK((dma_size_present == p->dma_enabled),
524                 "Parse error in section \"%s\": missing entry "
525                 "\"dma_size\"", params->name);
526         PIPELINE_ARG_CHECK((dma_hash_offset_present == p->dma_enabled),
527                 "Parse error in section \"%s\": missing entry "
528                 "\"dma_hash_offset\"", params->name);
529         PIPELINE_ARG_CHECK((p->lb_hash_enabled <= p->dma_hash_enabled),
530                 "Parse error in section \"%s\": missing entry "
531                 "\"dma_hash_offset\"", params->name);
532
533         if (dma_src_mask_present) {
534                 uint32_t dma_size = p->dma_size;
535                 int status;
536
537                 PIPELINE_ARG_CHECK((strlen(dma_mask_str) ==
538                         (dma_size * 2)), "Parse error in section "
539                         "\"%s\": dma_src_mask should have exactly %u hex "
540                         "digits", params->name, (dma_size * 2));
541
542                 status = parse_hex_string(dma_mask_str, p->dma_src_mask,
543                         &p->dma_size);
544
545                 PIPELINE_PARSE_ERR_INV_VAL(((status == 0) &&
546                         (dma_size == p->dma_size)), params->name,
547                         "dma_src_mask", dma_mask_str);
548         }
549
550         if (p->lb_hash_enabled)
551                 PIPELINE_ARG_CHECK((params->n_ports_out > 1),
552                         "Parse error in section \"%s\": entry \"lb\" not "
553                         "allowed for single output port pipeline",
554                         params->name);
555         else
556                 PIPELINE_ARG_CHECK(((params->n_ports_in >= params->n_ports_out)
557                         && ((params->n_ports_in % params->n_ports_out) == 0)),
558                         "Parse error in section \"%s\": n_ports_in needs to be "
559                         "a multiple of n_ports_out (lb mode disabled)",
560                         params->name);
561
562         return 0;
563 }
564
565
566 static rte_table_hash_op_hash
567 get_hash_function(struct pipeline_passthrough *p)
568 {
569         switch (p->params.dma_size) {
570
571         case 8: return hash_default_key8;
572         case 16: return hash_default_key16;
573         case 24: return hash_default_key24;
574         case 32: return hash_default_key32;
575         case 40: return hash_default_key40;
576         case 48: return hash_default_key48;
577         case 56: return hash_default_key56;
578         case 64: return hash_default_key64;
579         default: return NULL;
580         }
581 }
582
583 static void*
584 pipeline_passthrough_init(struct pipeline_params *params,
585         __rte_unused void *arg)
586 {
587         struct pipeline *p;
588         struct pipeline_passthrough *p_pt;
589         uint32_t size, i;
590
591         /* Check input arguments */
592         if ((params == NULL) ||
593                 (params->n_ports_in == 0) ||
594                 (params->n_ports_out == 0))
595                 return NULL;
596
597         /* Memory allocation */
598         size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct pipeline_passthrough));
599         p = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
600         p_pt = (struct pipeline_passthrough *) p;
601         if (p == NULL)
602                 return NULL;
603
604         strcpy(p->name, params->name);
605         p->log_level = params->log_level;
606
607         PLOG(p, HIGH, "Pass-through");
608
609         /* Parse arguments */
610         if (pipeline_passthrough_parse_args(&p_pt->params, params))
611                 return NULL;
612         p_pt->f_hash = get_hash_function(p_pt);
613
614         /* Pipeline */
615         {
616                 struct rte_pipeline_params pipeline_params = {
617                         .name = "PASS-THROUGH",
618                         .socket_id = params->socket_id,
619                         .offset_port_id = 0,
620                 };
621
622                 p->p = rte_pipeline_create(&pipeline_params);
623                 if (p->p == NULL) {
624                         rte_free(p);
625                         return NULL;
626                 }
627         }
628
629         p->n_ports_in = params->n_ports_in;
630         p->n_ports_out = params->n_ports_out;
631         p->n_tables = p->n_ports_in;
632
633         /*Input ports*/
634         for (i = 0; i < p->n_ports_in; i++) {
635                 struct rte_pipeline_port_in_params port_params = {
636                         .ops = pipeline_port_in_params_get_ops(
637                                 &params->port_in[i]),
638                         .arg_create = pipeline_port_in_params_convert(
639                                 &params->port_in[i]),
640                         .f_action = get_port_in_ah(p_pt),
641                         .arg_ah = p_pt,
642                         .burst_size = params->port_in[i].burst_size,
643                 };
644
645                 int status = rte_pipeline_port_in_create(p->p,
646                         &port_params,
647                         &p->port_in_id[i]);
648
649                 if (status) {
650                         rte_pipeline_free(p->p);
651                         rte_free(p);
652                         return NULL;
653                 }
654         }
655
656         /* Output ports */
657         for (i = 0; i < p->n_ports_out; i++) {
658                 struct rte_pipeline_port_out_params port_params = {
659                         .ops = pipeline_port_out_params_get_ops(
660                                 &params->port_out[i]),
661                         .arg_create = pipeline_port_out_params_convert(
662                                 &params->port_out[i]),
663                         .f_action = NULL,
664                         .arg_ah = NULL,
665                 };
666
667                 int status = rte_pipeline_port_out_create(p->p,
668                         &port_params,
669                         &p->port_out_id[i]);
670
671                 if (status) {
672                         rte_pipeline_free(p->p);
673                         rte_free(p);
674                         return NULL;
675                 }
676         }
677
678         /* Tables */
679         for (i = 0; i < p->n_ports_in; i++) {
680                 struct rte_pipeline_table_params table_params = {
681                         .ops = &rte_table_stub_ops,
682                         .arg_create = NULL,
683                         .f_action_hit = NULL,
684                         .f_action_miss = NULL,
685                         .arg_ah = NULL,
686                         .action_data_size = 0,
687                 };
688
689                 int status = rte_pipeline_table_create(p->p,
690                         &table_params,
691                         &p->table_id[i]);
692
693                 if (status) {
694                         rte_pipeline_free(p->p);
695                         rte_free(p);
696                         return NULL;
697                 }
698         }
699
700         /* Connecting input ports to tables */
701         for (i = 0; i < p->n_ports_in; i++) {
702                 int status = rte_pipeline_port_in_connect_to_table(p->p,
703                         p->port_in_id[i],
704                         p->table_id[i]);
705
706                 if (status) {
707                         rte_pipeline_free(p->p);
708                         rte_free(p);
709                         return NULL;
710                 }
711         }
712
713         /* Add entries to tables */
714         for (i = 0; i < p->n_ports_in; i++) {
715                 uint32_t port_out_id = (p_pt->params.lb_hash_enabled == 0) ?
716                         (i / (p->n_ports_in / p->n_ports_out)) :
717                         0;
718
719                 struct rte_pipeline_table_entry default_entry = {
720                         .action = RTE_PIPELINE_ACTION_PORT,
721                         {.port_id = p->port_out_id[port_out_id]},
722                 };
723
724                 struct rte_pipeline_table_entry *default_entry_ptr;
725
726                 int status = rte_pipeline_table_default_entry_add(p->p,
727                         p->table_id[i],
728                         &default_entry,
729                         &default_entry_ptr);
730
731                 if (status) {
732                         rte_pipeline_free(p->p);
733                         rte_free(p);
734                         return NULL;
735                 }
736         }
737
738         /* Enable input ports */
739         for (i = 0; i < p->n_ports_in; i++) {
740                 int status = rte_pipeline_port_in_enable(p->p,
741                         p->port_in_id[i]);
742
743                 if (status) {
744                         rte_pipeline_free(p->p);
745                         rte_free(p);
746                         return NULL;
747                 }
748         }
749
750         /* Check pipeline consistency */
751         if (rte_pipeline_check(p->p) < 0) {
752                 rte_pipeline_free(p->p);
753                 rte_free(p);
754                 return NULL;
755         }
756
757         /* Message queues */
758         p->n_msgq = params->n_msgq;
759         for (i = 0; i < p->n_msgq; i++)
760                 p->msgq_in[i] = params->msgq_in[i];
761         for (i = 0; i < p->n_msgq; i++)
762                 p->msgq_out[i] = params->msgq_out[i];
763
764         /* Message handlers */
765         memcpy(p->handlers, handlers, sizeof(p->handlers));
766
767         return p;
768 }
769
770 static int
771 pipeline_passthrough_free(void *pipeline)
772 {
773         struct pipeline *p = (struct pipeline *) pipeline;
774
775         /* Check input arguments */
776         if (p == NULL)
777                 return -1;
778
779         /* Free resources */
780         rte_pipeline_free(p->p);
781         rte_free(p);
782         return 0;
783 }
784
785 static int
786 pipeline_passthrough_timer(void *pipeline)
787 {
788         struct pipeline *p = (struct pipeline *) pipeline;
789
790         pipeline_msg_req_handle(p);
791         rte_pipeline_flush(p->p);
792
793         return 0;
794 }
795
796 struct pipeline_be_ops pipeline_passthrough_be_ops = {
797         .f_init = pipeline_passthrough_init,
798         .f_free = pipeline_passthrough_free,
799         .f_run = NULL,
800         .f_timer = pipeline_passthrough_timer,
801 };