83a16c2f28eccb09688644883ee87822a890456f
[dpdk.git] / examples / ip_pipeline / pipeline / pipeline_passthrough_be.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2015 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 "hash_func.h"
46
47 enum flow_key_type {
48         FLOW_KEY_QINQ,
49         FLOW_KEY_IPV4_5TUPLE,
50         FLOW_KEY_IPV6_5TUPLE,
51 };
52
53 struct pipeline_passthrough {
54         struct pipeline p;
55
56         uint32_t key_type_valid;
57         enum flow_key_type key_type;
58         uint32_t key_offset_rd;
59         uint32_t key_offset_wr;
60         uint32_t hash_offset;
61
62         rte_table_hash_op_hash f_hash;
63         rte_pipeline_port_in_action_handler f_port_in_ah;
64 } __rte_cache_aligned;
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_msg_req_invalid_handler,
81 };
82
83 static inline void
84 pkt_work_key_qinq(
85         struct rte_mbuf *pkt,
86         void *arg)
87 {
88         struct pipeline_passthrough *p_pt = arg;
89         uint32_t key_offset_rd = p_pt->key_offset_rd;
90         uint32_t key_offset_wr = p_pt->key_offset_wr;
91         uint32_t hash_offset = p_pt->hash_offset;
92
93         uint64_t *key_rd = RTE_MBUF_METADATA_UINT64_PTR(pkt, key_offset_rd);
94         uint64_t *key_wr = RTE_MBUF_METADATA_UINT64_PTR(pkt, key_offset_wr);
95         uint32_t *hash = RTE_MBUF_METADATA_UINT32_PTR(pkt, hash_offset);
96
97         /* Read */
98         uint64_t key_qinq = *key_rd & rte_bswap64(0x00000FFF00000FFFLLU);
99
100         /* Compute */
101         uint32_t hash_qinq = p_pt->f_hash(&key_qinq, 8, 0);
102
103         /* Write */
104         *key_wr = key_qinq;
105         *hash = hash_qinq;
106 }
107
108 static inline void
109 pkt4_work_key_qinq(
110         struct rte_mbuf **pkt,
111         void *arg)
112 {
113         struct pipeline_passthrough *p_pt = arg;
114         uint32_t key_offset_rd = p_pt->key_offset_rd;
115         uint32_t key_offset_wr = p_pt->key_offset_wr;
116         uint32_t hash_offset = p_pt->hash_offset;
117
118         uint64_t *key_rd0 = RTE_MBUF_METADATA_UINT64_PTR(pkt[0], key_offset_rd);
119         uint64_t *key_wr0 = RTE_MBUF_METADATA_UINT64_PTR(pkt[0], key_offset_wr);
120         uint32_t *hash0 = RTE_MBUF_METADATA_UINT32_PTR(pkt[0], hash_offset);
121
122         uint64_t *key_rd1 = RTE_MBUF_METADATA_UINT64_PTR(pkt[1], key_offset_rd);
123         uint64_t *key_wr1 = RTE_MBUF_METADATA_UINT64_PTR(pkt[1], key_offset_wr);
124         uint32_t *hash1 = RTE_MBUF_METADATA_UINT32_PTR(pkt[1], hash_offset);
125
126         uint64_t *key_rd2 = RTE_MBUF_METADATA_UINT64_PTR(pkt[2], key_offset_rd);
127         uint64_t *key_wr2 = RTE_MBUF_METADATA_UINT64_PTR(pkt[2], key_offset_wr);
128         uint32_t *hash2 = RTE_MBUF_METADATA_UINT32_PTR(pkt[2], hash_offset);
129
130         uint64_t *key_rd3 = RTE_MBUF_METADATA_UINT64_PTR(pkt[3], key_offset_rd);
131         uint64_t *key_wr3 = RTE_MBUF_METADATA_UINT64_PTR(pkt[3], key_offset_wr);
132         uint32_t *hash3 = RTE_MBUF_METADATA_UINT32_PTR(pkt[3], hash_offset);
133
134         /* Read */
135         uint64_t key_qinq0 = *key_rd0 & rte_bswap64(0x00000FFF00000FFFLLU);
136         uint64_t key_qinq1 = *key_rd1 & rte_bswap64(0x00000FFF00000FFFLLU);
137         uint64_t key_qinq2 = *key_rd2 & rte_bswap64(0x00000FFF00000FFFLLU);
138         uint64_t key_qinq3 = *key_rd3 & rte_bswap64(0x00000FFF00000FFFLLU);
139
140         /* Compute */
141         uint32_t hash_qinq0 = p_pt->f_hash(&key_qinq0, 8, 0);
142         uint32_t hash_qinq1 = p_pt->f_hash(&key_qinq1, 8, 0);
143         uint32_t hash_qinq2 = p_pt->f_hash(&key_qinq2, 8, 0);
144         uint32_t hash_qinq3 = p_pt->f_hash(&key_qinq3, 8, 0);
145
146         /* Write */
147         *key_wr0 = key_qinq0;
148         *key_wr1 = key_qinq1;
149         *key_wr2 = key_qinq2;
150         *key_wr3 = key_qinq3;
151
152         *hash0 = hash_qinq0;
153         *hash1 = hash_qinq1;
154         *hash2 = hash_qinq2;
155         *hash3 = hash_qinq3;
156 }
157
158 PIPELINE_PORT_IN_AH(port_in_ah_key_qinq, pkt_work_key_qinq, pkt4_work_key_qinq);
159
160 static inline void
161 pkt_work_key_ipv4(
162         struct rte_mbuf *pkt,
163         void *arg)
164 {
165         struct pipeline_passthrough *p_pt = arg;
166         uint32_t key_offset_rd = p_pt->key_offset_rd;
167         uint32_t key_offset_wr = p_pt->key_offset_wr;
168         uint32_t hash_offset = p_pt->hash_offset;
169
170         uint64_t *key_rd = RTE_MBUF_METADATA_UINT64_PTR(pkt, key_offset_rd);
171         uint64_t *key_wr = RTE_MBUF_METADATA_UINT64_PTR(pkt, key_offset_wr);
172         uint32_t *hash = RTE_MBUF_METADATA_UINT32_PTR(pkt, hash_offset);
173         uint64_t key_ipv4[2];
174         uint32_t hash_ipv4;
175
176         /* Read */
177         key_ipv4[0] = key_rd[0] & rte_bswap64(0x00FF0000FFFFFFFFLLU);
178         key_ipv4[1] = key_rd[1];
179
180         /* Compute */
181         hash_ipv4 = p_pt->f_hash(key_ipv4, 16, 0);
182
183         /* Write */
184         key_wr[0] = key_ipv4[0];
185         key_wr[1] = key_ipv4[1];
186         *hash = hash_ipv4;
187 }
188
189 static inline void
190 pkt4_work_key_ipv4(
191         struct rte_mbuf **pkt,
192         void *arg)
193 {
194         struct pipeline_passthrough *p_pt = arg;
195         uint32_t key_offset_rd = p_pt->key_offset_rd;
196         uint32_t key_offset_wr = p_pt->key_offset_wr;
197         uint32_t hash_offset = p_pt->hash_offset;
198
199         uint64_t *key_rd0 = RTE_MBUF_METADATA_UINT64_PTR(pkt[0], key_offset_rd);
200         uint64_t *key_wr0 = RTE_MBUF_METADATA_UINT64_PTR(pkt[0], key_offset_wr);
201         uint32_t *hash0 = RTE_MBUF_METADATA_UINT32_PTR(pkt[0], hash_offset);
202
203         uint64_t *key_rd1 = RTE_MBUF_METADATA_UINT64_PTR(pkt[1], key_offset_rd);
204         uint64_t *key_wr1 = RTE_MBUF_METADATA_UINT64_PTR(pkt[1], key_offset_wr);
205         uint32_t *hash1 = RTE_MBUF_METADATA_UINT32_PTR(pkt[1], hash_offset);
206
207         uint64_t *key_rd2 = RTE_MBUF_METADATA_UINT64_PTR(pkt[2], key_offset_rd);
208         uint64_t *key_wr2 = RTE_MBUF_METADATA_UINT64_PTR(pkt[2], key_offset_wr);
209         uint32_t *hash2 = RTE_MBUF_METADATA_UINT32_PTR(pkt[2], hash_offset);
210
211         uint64_t *key_rd3 = RTE_MBUF_METADATA_UINT64_PTR(pkt[3], key_offset_rd);
212         uint64_t *key_wr3 = RTE_MBUF_METADATA_UINT64_PTR(pkt[3], key_offset_wr);
213         uint32_t *hash3 = RTE_MBUF_METADATA_UINT32_PTR(pkt[3], hash_offset);
214
215         uint64_t key_ipv4_0[2];
216         uint64_t key_ipv4_1[2];
217         uint64_t key_ipv4_2[2];
218         uint64_t key_ipv4_3[2];
219
220         uint32_t hash_ipv4_0;
221         uint32_t hash_ipv4_1;
222         uint32_t hash_ipv4_2;
223         uint32_t hash_ipv4_3;
224
225         /* Read */
226         key_ipv4_0[0] = key_rd0[0] & rte_bswap64(0x00FF0000FFFFFFFFLLU);
227         key_ipv4_1[0] = key_rd1[0] & rte_bswap64(0x00FF0000FFFFFFFFLLU);
228         key_ipv4_2[0] = key_rd2[0] & rte_bswap64(0x00FF0000FFFFFFFFLLU);
229         key_ipv4_3[0] = key_rd3[0] & rte_bswap64(0x00FF0000FFFFFFFFLLU);
230
231         key_ipv4_0[1] = key_rd0[1];
232         key_ipv4_1[1] = key_rd1[1];
233         key_ipv4_2[1] = key_rd2[1];
234         key_ipv4_3[1] = key_rd3[1];
235
236         /* Compute */
237         hash_ipv4_0 = p_pt->f_hash(key_ipv4_0, 16, 0);
238         hash_ipv4_1 = p_pt->f_hash(key_ipv4_1, 16, 0);
239         hash_ipv4_2 = p_pt->f_hash(key_ipv4_2, 16, 0);
240         hash_ipv4_3 = p_pt->f_hash(key_ipv4_3, 16, 0);
241
242         /* Write */
243         key_wr0[0] = key_ipv4_0[0];
244         key_wr1[0] = key_ipv4_1[0];
245         key_wr2[0] = key_ipv4_2[0];
246         key_wr3[0] = key_ipv4_3[0];
247
248         key_wr0[1] = key_ipv4_0[1];
249         key_wr1[1] = key_ipv4_1[1];
250         key_wr2[1] = key_ipv4_2[1];
251         key_wr3[1] = key_ipv4_3[1];
252
253         *hash0 = hash_ipv4_0;
254         *hash1 = hash_ipv4_1;
255         *hash2 = hash_ipv4_2;
256         *hash3 = hash_ipv4_3;
257 }
258
259 PIPELINE_PORT_IN_AH(port_in_ah_key_ipv4, pkt_work_key_ipv4, pkt4_work_key_ipv4);
260
261 static inline void
262 pkt_work_key_ipv6(
263         struct rte_mbuf *pkt,
264         void *arg)
265 {
266         struct pipeline_passthrough *p_pt = arg;
267         uint32_t key_offset_rd = p_pt->key_offset_rd;
268         uint32_t key_offset_wr = p_pt->key_offset_wr;
269         uint32_t hash_offset = p_pt->hash_offset;
270
271         uint64_t *key_rd = RTE_MBUF_METADATA_UINT64_PTR(pkt, key_offset_rd);
272         uint64_t *key_wr = RTE_MBUF_METADATA_UINT64_PTR(pkt, key_offset_wr);
273         uint32_t *hash = RTE_MBUF_METADATA_UINT32_PTR(pkt, hash_offset);
274         uint64_t key_ipv6[8];
275         uint32_t hash_ipv6;
276
277         /* Read */
278         key_ipv6[0] = key_rd[0] & rte_bswap64(0x0000FF00FFFFFFFFLLU);
279         key_ipv6[1] = key_rd[1];
280         key_ipv6[2] = key_rd[2];
281         key_ipv6[3] = key_rd[3];
282         key_ipv6[4] = key_rd[4];
283         key_ipv6[5] = 0;
284         key_ipv6[6] = 0;
285         key_ipv6[7] = 0;
286
287         /* Compute */
288         hash_ipv6 = p_pt->f_hash(key_ipv6, 64, 0);
289
290         /* Write */
291         key_wr[0] = key_ipv6[0];
292         key_wr[1] = key_ipv6[1];
293         key_wr[2] = key_ipv6[2];
294         key_wr[3] = key_ipv6[3];
295         key_wr[4] = key_ipv6[4];
296         key_wr[5] = 0;
297         key_wr[6] = 0;
298         key_wr[7] = 0;
299         *hash = hash_ipv6;
300 }
301
302 static inline void
303 pkt4_work_key_ipv6(
304         struct rte_mbuf **pkt,
305         void *arg)
306 {
307         struct pipeline_passthrough *p_pt = arg;
308         uint32_t key_offset_rd = p_pt->key_offset_rd;
309         uint32_t key_offset_wr = p_pt->key_offset_wr;
310         uint32_t hash_offset = p_pt->hash_offset;
311
312         uint64_t *key_rd0 = RTE_MBUF_METADATA_UINT64_PTR(pkt[0], key_offset_rd);
313         uint64_t *key_wr0 = RTE_MBUF_METADATA_UINT64_PTR(pkt[0], key_offset_wr);
314         uint32_t *hash0 = RTE_MBUF_METADATA_UINT32_PTR(pkt[0], hash_offset);
315
316         uint64_t *key_rd1 = RTE_MBUF_METADATA_UINT64_PTR(pkt[1], key_offset_rd);
317         uint64_t *key_wr1 = RTE_MBUF_METADATA_UINT64_PTR(pkt[1], key_offset_wr);
318         uint32_t *hash1 = RTE_MBUF_METADATA_UINT32_PTR(pkt[1], hash_offset);
319
320         uint64_t *key_rd2 = RTE_MBUF_METADATA_UINT64_PTR(pkt[2], key_offset_rd);
321         uint64_t *key_wr2 = RTE_MBUF_METADATA_UINT64_PTR(pkt[2], key_offset_wr);
322         uint32_t *hash2 = RTE_MBUF_METADATA_UINT32_PTR(pkt[2], hash_offset);
323
324         uint64_t *key_rd3 = RTE_MBUF_METADATA_UINT64_PTR(pkt[3], key_offset_rd);
325         uint64_t *key_wr3 = RTE_MBUF_METADATA_UINT64_PTR(pkt[3], key_offset_wr);
326         uint32_t *hash3 = RTE_MBUF_METADATA_UINT32_PTR(pkt[3], hash_offset);
327
328         uint64_t key_ipv6_0[8];
329         uint64_t key_ipv6_1[8];
330         uint64_t key_ipv6_2[8];
331         uint64_t key_ipv6_3[8];
332
333         uint32_t hash_ipv6_0;
334         uint32_t hash_ipv6_1;
335         uint32_t hash_ipv6_2;
336         uint32_t hash_ipv6_3;
337
338         /* Read */
339         key_ipv6_0[0] = key_rd0[0] & rte_bswap64(0x0000FF00FFFFFFFFLLU);
340         key_ipv6_1[0] = key_rd1[0] & rte_bswap64(0x0000FF00FFFFFFFFLLU);
341         key_ipv6_2[0] = key_rd2[0] & rte_bswap64(0x0000FF00FFFFFFFFLLU);
342         key_ipv6_3[0] = key_rd3[0] & rte_bswap64(0x0000FF00FFFFFFFFLLU);
343
344         key_ipv6_0[1] = key_rd0[1];
345         key_ipv6_1[1] = key_rd1[1];
346         key_ipv6_2[1] = key_rd2[1];
347         key_ipv6_3[1] = key_rd3[1];
348
349         key_ipv6_0[2] = key_rd0[2];
350         key_ipv6_1[2] = key_rd1[2];
351         key_ipv6_2[2] = key_rd2[2];
352         key_ipv6_3[2] = key_rd3[2];
353
354         key_ipv6_0[3] = key_rd0[3];
355         key_ipv6_1[3] = key_rd1[3];
356         key_ipv6_2[3] = key_rd2[3];
357         key_ipv6_3[3] = key_rd3[3];
358
359         key_ipv6_0[4] = key_rd0[4];
360         key_ipv6_1[4] = key_rd1[4];
361         key_ipv6_2[4] = key_rd2[4];
362         key_ipv6_3[4] = key_rd3[4];
363
364         key_ipv6_0[5] = 0;
365         key_ipv6_1[5] = 0;
366         key_ipv6_2[5] = 0;
367         key_ipv6_3[5] = 0;
368
369         key_ipv6_0[6] = 0;
370         key_ipv6_1[6] = 0;
371         key_ipv6_2[6] = 0;
372         key_ipv6_3[6] = 0;
373
374         key_ipv6_0[7] = 0;
375         key_ipv6_1[7] = 0;
376         key_ipv6_2[7] = 0;
377         key_ipv6_3[7] = 0;
378
379         /* Compute */
380         hash_ipv6_0 = p_pt->f_hash(key_ipv6_0, 64, 0);
381         hash_ipv6_1 = p_pt->f_hash(key_ipv6_1, 64, 0);
382         hash_ipv6_2 = p_pt->f_hash(key_ipv6_2, 64, 0);
383         hash_ipv6_3 = p_pt->f_hash(key_ipv6_3, 64, 0);
384
385         /* Write */
386         key_wr0[0] = key_ipv6_0[0];
387         key_wr1[0] = key_ipv6_1[0];
388         key_wr2[0] = key_ipv6_2[0];
389         key_wr3[0] = key_ipv6_3[0];
390
391         key_wr0[1] = key_ipv6_0[1];
392         key_wr1[1] = key_ipv6_1[1];
393         key_wr2[1] = key_ipv6_2[1];
394         key_wr3[1] = key_ipv6_3[1];
395
396         key_wr0[2] = key_ipv6_0[2];
397         key_wr1[2] = key_ipv6_1[2];
398         key_wr2[2] = key_ipv6_2[2];
399         key_wr3[2] = key_ipv6_3[2];
400
401         key_wr0[3] = key_ipv6_0[3];
402         key_wr1[3] = key_ipv6_1[3];
403         key_wr2[3] = key_ipv6_2[3];
404         key_wr3[3] = key_ipv6_3[3];
405
406         key_wr0[4] = key_ipv6_0[4];
407         key_wr1[4] = key_ipv6_1[4];
408         key_wr2[4] = key_ipv6_2[4];
409         key_wr3[4] = key_ipv6_3[4];
410
411         key_wr0[5] = 0;
412         key_wr0[5] = 0;
413         key_wr0[5] = 0;
414         key_wr0[5] = 0;
415
416         key_wr0[6] = 0;
417         key_wr0[6] = 0;
418         key_wr0[6] = 0;
419         key_wr0[6] = 0;
420
421         key_wr0[7] = 0;
422         key_wr0[7] = 0;
423         key_wr0[7] = 0;
424         key_wr0[7] = 0;
425
426         *hash0 = hash_ipv6_0;
427         *hash1 = hash_ipv6_1;
428         *hash2 = hash_ipv6_2;
429         *hash3 = hash_ipv6_3;
430 }
431
432 PIPELINE_PORT_IN_AH(port_in_ah_key_ipv6, pkt_work_key_ipv6, pkt4_work_key_ipv6);
433
434 static int
435 pipeline_passthrough_parse_args(struct pipeline_passthrough *p,
436         struct pipeline_params *params)
437 {
438         uint32_t key_type_present = 0;
439         uint32_t key_offset_rd_present = 0;
440         uint32_t key_offset_wr_present = 0;
441         uint32_t hash_offset_present = 0;
442         uint32_t i;
443
444         for (i = 0; i < params->n_args; i++) {
445                 char *arg_name = params->args_name[i];
446                 char *arg_value = params->args_value[i];
447
448                 /* key_type */
449                 if (strcmp(arg_name, "key_type") == 0) {
450                         if (key_type_present)
451                                 return -1;
452                         key_type_present = 1;
453
454                         if ((strcmp(arg_value, "q-in-q") == 0) ||
455                                 (strcmp(arg_value, "qinq") == 0))
456                                 p->key_type = FLOW_KEY_QINQ;
457                         else if (strcmp(arg_value, "ipv4_5tuple") == 0)
458                                 p->key_type = FLOW_KEY_IPV4_5TUPLE;
459                         else if (strcmp(arg_value, "ipv6_5tuple") == 0)
460                                 p->key_type = FLOW_KEY_IPV6_5TUPLE;
461                         else
462                                 return -1;
463
464                         p->key_type_valid = 1;
465
466                         continue;
467                 }
468
469                 /* key_offset_rd */
470                 if (strcmp(arg_name, "key_offset_rd") == 0) {
471                         if (key_offset_rd_present)
472                                 return -1;
473                         key_offset_rd_present = 1;
474
475                         p->key_offset_rd = atoi(arg_value);
476
477                         continue;
478                 }
479
480                 /* key_offset_wr */
481                 if (strcmp(arg_name, "key_offset_wr") == 0) {
482                         if (key_offset_wr_present)
483                                 return -1;
484                         key_offset_wr_present = 1;
485
486                         p->key_offset_wr = atoi(arg_value);
487
488                         continue;
489                 }
490
491                 /* hash_offset */
492                 if (strcmp(arg_name, "hash_offset") == 0) {
493                         if (hash_offset_present)
494                                 return -1;
495                         hash_offset_present = 1;
496
497                         p->hash_offset = atoi(arg_value);
498
499                         continue;
500                 }
501
502                 /* any other */
503                 return -1;
504         }
505
506         /* Check that mandatory arguments are present */
507         if ((key_offset_rd_present != key_type_present) ||
508                 (key_offset_wr_present != key_type_present) ||
509                 (hash_offset_present != key_type_present))
510                 return -1;
511
512         return 0;
513 }
514
515 static void*
516 pipeline_passthrough_init(struct pipeline_params *params,
517         __rte_unused void *arg)
518 {
519         struct pipeline *p;
520         struct pipeline_passthrough *p_pt;
521         uint32_t size, i;
522
523         /* Check input arguments */
524         if ((params == NULL) ||
525                 (params->n_ports_in == 0) ||
526                 (params->n_ports_out == 0) ||
527                 (params->n_ports_in < params->n_ports_out) ||
528                 (params->n_ports_in % params->n_ports_out))
529                 return NULL;
530
531         /* Memory allocation */
532         size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct pipeline_passthrough));
533         p = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
534         p_pt = (struct pipeline_passthrough *) p;
535         if (p == NULL)
536                 return NULL;
537
538         strcpy(p->name, params->name);
539         p->log_level = params->log_level;
540
541         PLOG(p, HIGH, "Pass-through");
542
543         /* Parse arguments */
544         if (pipeline_passthrough_parse_args(p_pt, params))
545                 return NULL;
546
547         if (p_pt->key_type_valid == 0) {
548                 p_pt->f_hash = NULL;
549                 p_pt->f_port_in_ah = NULL;
550         } else
551                 switch (p_pt->key_type) {
552                 case FLOW_KEY_QINQ:
553                         p_pt->f_hash = hash_default_key8;
554                         p_pt->f_port_in_ah = port_in_ah_key_qinq;
555                         break;
556
557                 case FLOW_KEY_IPV4_5TUPLE:
558                         p_pt->f_hash = hash_default_key16;
559                         p_pt->f_port_in_ah = port_in_ah_key_ipv4;
560                         break;
561
562                 case FLOW_KEY_IPV6_5TUPLE:
563                         p_pt->f_hash = hash_default_key64;
564                         p_pt->f_port_in_ah = port_in_ah_key_ipv6;
565                         break;
566
567                 default:
568                         p_pt->f_hash = NULL;
569                         p_pt->f_port_in_ah = NULL;
570                 }
571
572         /* Pipeline */
573         {
574                 struct rte_pipeline_params pipeline_params = {
575                         .name = "PASS-THROUGH",
576                         .socket_id = params->socket_id,
577                         .offset_port_id = 0,
578                 };
579
580                 p->p = rte_pipeline_create(&pipeline_params);
581                 if (p->p == NULL) {
582                         rte_free(p);
583                         return NULL;
584                 }
585         }
586
587         /* Input ports */
588         p->n_ports_in = params->n_ports_in;
589         for (i = 0; i < p->n_ports_in; i++) {
590                 struct rte_pipeline_port_in_params port_params = {
591                         .ops = pipeline_port_in_params_get_ops(
592                                 &params->port_in[i]),
593                         .arg_create = pipeline_port_in_params_convert(
594                                 &params->port_in[i]),
595                         .f_action = p_pt->f_port_in_ah,
596                         .arg_ah = p_pt,
597                         .burst_size = params->port_in[i].burst_size,
598                 };
599
600                 int status = rte_pipeline_port_in_create(p->p,
601                         &port_params,
602                         &p->port_in_id[i]);
603
604                 if (status) {
605                         rte_pipeline_free(p->p);
606                         rte_free(p);
607                         return NULL;
608                 }
609         }
610
611         /* Output ports */
612         p->n_ports_out = params->n_ports_out;
613         for (i = 0; i < p->n_ports_out; i++) {
614                 struct rte_pipeline_port_out_params port_params = {
615                         .ops = pipeline_port_out_params_get_ops(
616                                 &params->port_out[i]),
617                         .arg_create = pipeline_port_out_params_convert(
618                                 &params->port_out[i]),
619                         .f_action = NULL,
620                         .f_action_bulk = NULL,
621                         .arg_ah = NULL,
622                 };
623
624                 int status = rte_pipeline_port_out_create(p->p,
625                         &port_params,
626                         &p->port_out_id[i]);
627
628                 if (status) {
629                         rte_pipeline_free(p->p);
630                         rte_free(p);
631                         return NULL;
632                 }
633         }
634
635         /* Tables */
636         p->n_tables = p->n_ports_in;
637         for (i = 0; i < p->n_ports_in; i++) {
638                 struct rte_pipeline_table_params table_params = {
639                         .ops = &rte_table_stub_ops,
640                         .arg_create = NULL,
641                         .f_action_hit = NULL,
642                         .f_action_miss = NULL,
643                         .arg_ah = NULL,
644                         .action_data_size = 0,
645                 };
646
647                 int status = rte_pipeline_table_create(p->p,
648                         &table_params,
649                         &p->table_id[i]);
650
651                 if (status) {
652                         rte_pipeline_free(p->p);
653                         rte_free(p);
654                         return NULL;
655                 }
656         }
657
658         /* Connecting input ports to tables */
659         for (i = 0; i < p->n_ports_in; i++) {
660                 int status = rte_pipeline_port_in_connect_to_table(p->p,
661                         p->port_in_id[i],
662                         p->table_id[i]);
663
664                 if (status) {
665                         rte_pipeline_free(p->p);
666                         rte_free(p);
667                         return NULL;
668                 }
669         }
670
671         /* Add entries to tables */
672         for (i = 0; i < p->n_ports_in; i++) {
673                 struct rte_pipeline_table_entry default_entry = {
674                         .action = RTE_PIPELINE_ACTION_PORT,
675                         {.port_id = p->port_out_id[
676                                 i / (p->n_ports_in / p->n_ports_out)]},
677                 };
678
679                 struct rte_pipeline_table_entry *default_entry_ptr;
680
681                 int status = rte_pipeline_table_default_entry_add(p->p,
682                         p->table_id[i],
683                         &default_entry,
684                         &default_entry_ptr);
685
686                 if (status) {
687                         rte_pipeline_free(p->p);
688                         rte_free(p);
689                         return NULL;
690                 }
691         }
692
693         /* Enable input ports */
694         for (i = 0; i < p->n_ports_in; i++) {
695                 int status = rte_pipeline_port_in_enable(p->p,
696                         p->port_in_id[i]);
697
698                 if (status) {
699                         rte_pipeline_free(p->p);
700                         rte_free(p);
701                         return NULL;
702                 }
703         }
704
705         /* Check pipeline consistency */
706         if (rte_pipeline_check(p->p) < 0) {
707                 rte_pipeline_free(p->p);
708                 rte_free(p);
709                 return NULL;
710         }
711
712         /* Message queues */
713         p->n_msgq = params->n_msgq;
714         for (i = 0; i < p->n_msgq; i++)
715                 p->msgq_in[i] = params->msgq_in[i];
716         for (i = 0; i < p->n_msgq; i++)
717                 p->msgq_out[i] = params->msgq_out[i];
718
719         /* Message handlers */
720         memcpy(p->handlers, handlers, sizeof(p->handlers));
721
722         return p;
723 }
724
725 static int
726 pipeline_passthrough_free(void *pipeline)
727 {
728         struct pipeline *p = (struct pipeline *) pipeline;
729
730         /* Check input arguments */
731         if (p == NULL)
732                 return -1;
733
734         /* Free resources */
735         rte_pipeline_free(p->p);
736         rte_free(p);
737         return 0;
738 }
739
740 static int
741 pipeline_passthrough_timer(void *pipeline)
742 {
743         struct pipeline *p = (struct pipeline *) pipeline;
744
745         pipeline_msg_req_handle(p);
746         rte_pipeline_flush(p->p);
747
748         return 0;
749 }
750
751 static int
752 pipeline_passthrough_track(void *pipeline, uint32_t port_in, uint32_t *port_out)
753 {
754         struct pipeline *p = (struct pipeline *) pipeline;
755
756         /* Check input arguments */
757         if ((p == NULL) ||
758                 (port_in >= p->n_ports_in) ||
759                 (port_out == NULL))
760                 return -1;
761
762         *port_out = port_in / p->n_ports_in;
763         return 0;
764 }
765
766 struct pipeline_be_ops pipeline_passthrough_be_ops = {
767         .f_init = pipeline_passthrough_init,
768         .f_free = pipeline_passthrough_free,
769         .f_run = NULL,
770         .f_timer = pipeline_passthrough_timer,
771         .f_track = pipeline_passthrough_track,
772 };