Imported Upstream version 16.04
[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         return 0;
551 }
552
553
554 static rte_table_hash_op_hash
555 get_hash_function(struct pipeline_passthrough *p)
556 {
557         switch (p->params.dma_size) {
558
559         case 8: return hash_default_key8;
560         case 16: return hash_default_key16;
561         case 24: return hash_default_key24;
562         case 32: return hash_default_key32;
563         case 40: return hash_default_key40;
564         case 48: return hash_default_key48;
565         case 56: return hash_default_key56;
566         case 64: return hash_default_key64;
567         default: return NULL;
568         }
569 }
570
571 static void*
572 pipeline_passthrough_init(struct pipeline_params *params,
573         __rte_unused void *arg)
574 {
575         struct pipeline *p;
576         struct pipeline_passthrough *p_pt;
577         uint32_t size, i;
578
579         /* Check input arguments */
580         if ((params == NULL) ||
581                 (params->n_ports_in == 0) ||
582                 (params->n_ports_out == 0) ||
583                 (params->n_ports_in < params->n_ports_out) ||
584                 (params->n_ports_in % params->n_ports_out))
585                 return NULL;
586
587         /* Memory allocation */
588         size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct pipeline_passthrough));
589         p = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
590         p_pt = (struct pipeline_passthrough *) p;
591         if (p == NULL)
592                 return NULL;
593
594         strcpy(p->name, params->name);
595         p->log_level = params->log_level;
596
597         PLOG(p, HIGH, "Pass-through");
598
599         /* Parse arguments */
600         if (pipeline_passthrough_parse_args(&p_pt->params, params))
601                 return NULL;
602         p_pt->f_hash = get_hash_function(p_pt);
603
604         /* Pipeline */
605         {
606                 struct rte_pipeline_params pipeline_params = {
607                         .name = "PASS-THROUGH",
608                         .socket_id = params->socket_id,
609                         .offset_port_id = 0,
610                 };
611
612                 p->p = rte_pipeline_create(&pipeline_params);
613                 if (p->p == NULL) {
614                         rte_free(p);
615                         return NULL;
616                 }
617         }
618
619         p->n_ports_in = params->n_ports_in;
620         p->n_ports_out = params->n_ports_out;
621         p->n_tables = p->n_ports_in;
622
623         /*Input ports*/
624         for (i = 0; i < p->n_ports_in; i++) {
625                 struct rte_pipeline_port_in_params port_params = {
626                         .ops = pipeline_port_in_params_get_ops(
627                                 &params->port_in[i]),
628                         .arg_create = pipeline_port_in_params_convert(
629                                 &params->port_in[i]),
630                         .f_action = get_port_in_ah(p_pt),
631                         .arg_ah = p_pt,
632                         .burst_size = params->port_in[i].burst_size,
633                 };
634
635                 int status = rte_pipeline_port_in_create(p->p,
636                         &port_params,
637                         &p->port_in_id[i]);
638
639                 if (status) {
640                         rte_pipeline_free(p->p);
641                         rte_free(p);
642                         return NULL;
643                 }
644         }
645
646         /* Output ports */
647         for (i = 0; i < p->n_ports_out; i++) {
648                 struct rte_pipeline_port_out_params port_params = {
649                         .ops = pipeline_port_out_params_get_ops(
650                                 &params->port_out[i]),
651                         .arg_create = pipeline_port_out_params_convert(
652                                 &params->port_out[i]),
653                         .f_action = NULL,
654                         .arg_ah = NULL,
655                 };
656
657                 int status = rte_pipeline_port_out_create(p->p,
658                         &port_params,
659                         &p->port_out_id[i]);
660
661                 if (status) {
662                         rte_pipeline_free(p->p);
663                         rte_free(p);
664                         return NULL;
665                 }
666         }
667
668         /* Tables */
669         for (i = 0; i < p->n_ports_in; i++) {
670                 struct rte_pipeline_table_params table_params = {
671                         .ops = &rte_table_stub_ops,
672                         .arg_create = NULL,
673                         .f_action_hit = NULL,
674                         .f_action_miss = NULL,
675                         .arg_ah = NULL,
676                         .action_data_size = 0,
677                 };
678
679                 int status = rte_pipeline_table_create(p->p,
680                         &table_params,
681                         &p->table_id[i]);
682
683                 if (status) {
684                         rte_pipeline_free(p->p);
685                         rte_free(p);
686                         return NULL;
687                 }
688         }
689
690         /* Connecting input ports to tables */
691         for (i = 0; i < p->n_ports_in; i++) {
692                 int status = rte_pipeline_port_in_connect_to_table(p->p,
693                         p->port_in_id[i],
694                         p->table_id[i]);
695
696                 if (status) {
697                         rte_pipeline_free(p->p);
698                         rte_free(p);
699                         return NULL;
700                 }
701         }
702
703         /* Add entries to tables */
704         for (i = 0; i < p->n_ports_in; i++) {
705                 struct rte_pipeline_table_entry default_entry = {
706                         .action = RTE_PIPELINE_ACTION_PORT,
707                         {.port_id = p->port_out_id[
708                                 i / (p->n_ports_in / p->n_ports_out)]},
709                 };
710
711                 struct rte_pipeline_table_entry *default_entry_ptr;
712
713                 int status = rte_pipeline_table_default_entry_add(p->p,
714                         p->table_id[i],
715                         &default_entry,
716                         &default_entry_ptr);
717
718                 if (status) {
719                         rte_pipeline_free(p->p);
720                         rte_free(p);
721                         return NULL;
722                 }
723         }
724
725         /* Enable input ports */
726         for (i = 0; i < p->n_ports_in; i++) {
727                 int status = rte_pipeline_port_in_enable(p->p,
728                         p->port_in_id[i]);
729
730                 if (status) {
731                         rte_pipeline_free(p->p);
732                         rte_free(p);
733                         return NULL;
734                 }
735         }
736
737         /* Check pipeline consistency */
738         if (rte_pipeline_check(p->p) < 0) {
739                 rte_pipeline_free(p->p);
740                 rte_free(p);
741                 return NULL;
742         }
743
744         /* Message queues */
745         p->n_msgq = params->n_msgq;
746         for (i = 0; i < p->n_msgq; i++)
747                 p->msgq_in[i] = params->msgq_in[i];
748         for (i = 0; i < p->n_msgq; i++)
749                 p->msgq_out[i] = params->msgq_out[i];
750
751         /* Message handlers */
752         memcpy(p->handlers, handlers, sizeof(p->handlers));
753
754         return p;
755 }
756
757 static int
758 pipeline_passthrough_free(void *pipeline)
759 {
760         struct pipeline *p = (struct pipeline *) pipeline;
761
762         /* Check input arguments */
763         if (p == NULL)
764                 return -1;
765
766         /* Free resources */
767         rte_pipeline_free(p->p);
768         rte_free(p);
769         return 0;
770 }
771
772 static int
773 pipeline_passthrough_timer(void *pipeline)
774 {
775         struct pipeline *p = (struct pipeline *) pipeline;
776
777         pipeline_msg_req_handle(p);
778         rte_pipeline_flush(p->p);
779
780         return 0;
781 }
782
783 static int
784 pipeline_passthrough_track(void *pipeline, uint32_t port_in, uint32_t *port_out)
785 {
786         struct pipeline *p = (struct pipeline *) pipeline;
787
788         /* Check input arguments */
789         if ((p == NULL) ||
790                 (port_in >= p->n_ports_in) ||
791                 (port_out == NULL))
792                 return -1;
793
794         *port_out = port_in / p->n_ports_in;
795         return 0;
796 }
797
798 struct pipeline_be_ops pipeline_passthrough_be_ops = {
799         .f_init = pipeline_passthrough_init,
800         .f_free = pipeline_passthrough_free,
801         .f_run = NULL,
802         .f_timer = pipeline_passthrough_timer,
803         .f_track = pipeline_passthrough_track,
804 };