common: Adding common library for sample vnf
[samplevnf.git] / common / VIL / pipeline_loadb / pipeline_loadb_be.c
1 /*
2 // Copyright (c) 2017 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <stdint.h>
20 #include <string.h>
21 #include <unistd.h>
22
23 #include <rte_common.h>
24 #include <rte_malloc.h>
25 #include <rte_ip.h>
26 #include <rte_hash.h>
27 #include <rte_byteorder.h>
28 #include <rte_table_lpm.h>
29 #include <rte_table_hash.h>
30 #include <rte_jhash.h>
31 #include <rte_thash.h>
32 #include <rte_cycles.h>
33 #include <rte_ethdev.h>
34 #include <rte_prefetch.h>
35 #include <rte_table_array.h>
36 #include "pipeline_loadb_be.h"
37 #include "pipeline_actions_common.h"
38 #include "hash_func.h"
39 #include "pipeline_arpicmp_be.h"
40 #include "vnf_common.h"
41 #include "app.h"
42
43 #define BYTES_TO_BITS 8
44 #define ROTATE_15_BITS 15
45
46 #define MAX_VNF_THREADS 16
47
48 int pkt_burst_cnt;
49
50 uint8_t LOADB_DEBUG;
51 uint8_t total_vnf_threads;
52 uint32_t phyport_offset;
53
54 struct pipeline_loadb {
55         struct pipeline p;
56         pipeline_msg_req_handler custom_handlers[PIPELINE_LOADB_MSG_REQS];
57
58         uint8_t n_vnf_threads;
59         uint8_t n_lb_tuples;
60         uint32_t outport_offset;
61         uint64_t receivedLBPktCount;
62         uint64_t droppedLBPktCount;
63         uint8_t links_map[PIPELINE_MAX_PORT_IN];
64         uint8_t outport_id[PIPELINE_MAX_PORT_IN];
65         uint8_t n_prv_Q;
66         uint8_t n_pub_Q;
67         uint8_t pipeline_num;
68 } __rte_cache_aligned;
69
70 uint8_t default_rss_key[] = {
71         0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a,
72         0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a,
73         0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a,
74         0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a,
75         0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a,
76 };
77
78 static void *pipeline_loadb_msg_req_custom_handler(struct pipeline *p,
79                                                          void *msg);
80
81 static pipeline_msg_req_handler handlers[] = {
82         [PIPELINE_MSG_REQ_PING] =
83                 pipeline_msg_req_ping_handler,
84         [PIPELINE_MSG_REQ_STATS_PORT_IN] =
85                 pipeline_msg_req_stats_port_in_handler,
86         [PIPELINE_MSG_REQ_STATS_PORT_OUT] =
87                 pipeline_msg_req_stats_port_out_handler,
88         [PIPELINE_MSG_REQ_STATS_TABLE] =
89                 pipeline_msg_req_stats_table_handler,
90         [PIPELINE_MSG_REQ_PORT_IN_ENABLE] =
91                 pipeline_msg_req_port_in_enable_handler,
92         [PIPELINE_MSG_REQ_PORT_IN_DISABLE] =
93                 pipeline_msg_req_port_in_disable_handler,
94         [PIPELINE_MSG_REQ_CUSTOM] =
95                 pipeline_loadb_msg_req_custom_handler,
96
97 };
98
99 static void *pipeline_loadb_msg_req_entry_dbg_handler(struct pipeline *,
100                                                                         void *msg);
101
102 static pipeline_msg_req_handler custom_handlers[] = {
103         [PIPELINE_LOADB_MSG_REQ_ENTRY_DBG] =
104                         pipeline_loadb_msg_req_entry_dbg_handler,
105 };
106
107 /*
108  * LOADB table
109  */
110 struct loadb_table_entry {
111         struct rte_pipeline_table_entry head;
112 } __rte_cache_aligned;
113
114 void *pipeline_loadb_msg_req_custom_handler(struct pipeline *p, void *msg)
115 {
116         struct pipeline_loadb *p_lb = (struct pipeline_loadb *)p;
117         struct pipeline_custom_msg_req *req = msg;
118         pipeline_msg_req_handler f_handle;
119
120         f_handle = (req->subtype < PIPELINE_LOADB_MSG_REQS) ?
121                         p_lb->custom_handlers[req->subtype] :
122                         pipeline_msg_req_invalid_handler;
123
124         if (f_handle == NULL)
125                 f_handle = pipeline_msg_req_invalid_handler;
126
127         return f_handle(p, req);
128 }
129
130 uint32_t lb_pkt_print_count;
131
132 uint8_t calculate_lb_thread_prv(struct rte_mbuf *pkt, void *arg)
133 {
134         uint32_t hash_key[2], hash_ipv4;
135         uint32_t temp1, temp2, temp3;
136         uint8_t thread;
137         struct pipeline_loadb_in_port_h_arg *ap = arg;
138         struct pipeline_loadb *p_loadb = (struct pipeline_loadb *) ap->p;
139         uint8_t nthreads = p_loadb->n_vnf_threads;
140         union rte_thash_tuple tuple;
141
142         uint32_t *src_addr;
143         uint32_t *dst_addr;
144         uint16_t *src_port;
145         uint16_t *dst_port;
146         uint8_t *protocol;
147         struct lb_pkt *lb_pkt = (struct lb_pkt *)
148                         RTE_MBUF_METADATA_UINT8_PTR(pkt, MBUF_HDR_ROOM);
149
150         if (rte_be_to_cpu_16(lb_pkt->eth.ether_type) == ETHER_TYPE_IPv6) {
151                 src_addr = (uint32_t *)&lb_pkt->ipv6_port.ipv6.src_addr;
152                 dst_addr = (uint32_t *)&lb_pkt->ipv6_port.ipv6.dst_addr;
153                 src_port = &lb_pkt->ipv6_port.src_port;
154                 dst_port = &lb_pkt->ipv6_port.dst_port;
155                 protocol = &lb_pkt->ipv6_port.ipv6.proto;
156         } else {
157                 src_addr = &lb_pkt->ipv4_port.ipv4.src_addr;
158                 dst_addr = &lb_pkt->ipv4_port.ipv4.dst_addr;
159                 src_port = &lb_pkt->ipv4_port.src_port;
160                 dst_port = &lb_pkt->ipv4_port.dst_port;
161                 protocol = &lb_pkt->ipv4_port.ipv4.next_proto_id;
162         }
163
164         switch (p_loadb->n_lb_tuples) {
165
166         case 0:
167                 /* Write */
168                 /* Egress */
169         if (rte_be_to_cpu_16(lb_pkt->eth.ether_type) == ETHER_TYPE_IPv6)
170                 temp1 = rte_bswap32(dst_addr[3]) ^ *dst_port;
171         else
172                 temp1 = *dst_addr ^ *dst_port;
173
174                         temp2 = (temp1 >> 24) ^ (temp1 >> 16) ^
175                                 (temp1 >> 8) ^ temp1;
176
177                         temp3 = (temp2 >> 4) ^ (temp2 & 0xf);
178
179                         /* To select the thread */
180                         thread = temp3 % nthreads;
181                         /* To select the Q */
182                         thread = ap->in_port_id + (p_loadb->p.n_ports_in *
183                                 (thread + 1) - p_loadb->p.n_ports_in);
184                 return thread;
185
186         case 1:
187                 /* Write */
188                 /* Egress */
189                 if (rte_be_to_cpu_16(lb_pkt->eth.ether_type) == ETHER_TYPE_IPv6)
190                         hash_key[0] = rte_bswap32(dst_addr[3]);
191                 else
192                         hash_key[0] = rte_bswap32(*dst_addr);
193
194                 /* Compute */
195                 hash_ipv4 = rte_jhash(&hash_key[0], 4, 0);
196
197                 /* To select the thread */
198                 thread = (hash_ipv4 % nthreads);
199
200                 /* To select the Q */
201                 thread = ap->in_port_id + (p_loadb->p.n_ports_in *
202                                 (thread + 1) - p_loadb->p.n_ports_in);
203
204                 if (LOADB_DEBUG > 3)
205                         printf("thread: %u  hash: %x  hash_key: %x\n",
206                                 thread, hash_ipv4, hash_key[0]);
207                 return thread;
208
209         case 2:
210                 /* Write */
211                 /* Egress */
212                 if (rte_be_to_cpu_16(lb_pkt->eth.ether_type) ==
213                         ETHER_TYPE_IPv6) {
214                         hash_key[0] = rte_bswap32(dst_addr[3]);
215                         hash_key[1] = *dst_port << 16;
216                 } else{
217                         hash_key[0] = rte_bswap32(*dst_addr);
218                         hash_key[1] = *dst_port << 16;
219                 }
220                 /* Compute */
221                 hash_ipv4 = rte_jhash(&hash_key[0], 6, 0);
222
223                 /* To select the thread */
224                 thread = (hash_ipv4 % nthreads);
225
226                 /* To select the Q */
227                 thread = ap->in_port_id + (p_loadb->p.n_ports_in *
228                                 (thread + 1) - p_loadb->p.n_ports_in);
229
230                 if (LOADB_DEBUG > 3) {
231                         printf("public_addr: %x public_port: %x\n",
232                                 hash_key[0], *dst_port);
233                         printf("thread: %u  hash: %x  hash_key0: %x  "
234                                 "hash_key1: %x\n", thread, hash_ipv4,
235                                 hash_key[0], hash_key[1]);
236                 }
237                 return thread;
238
239         case 3:
240                 printf("Invalid n_lb_tuples: %d\n", p_loadb->n_lb_tuples);
241                 return 0;
242
243         case 4:
244                 /* Write */
245                 if (rte_be_to_cpu_16(lb_pkt->eth.ether_type) ==
246                         ETHER_TYPE_IPv6) {
247                         tuple.v4.src_addr = rte_bswap32(src_addr[3]);
248                         tuple.v4.dst_addr = rte_bswap32(dst_addr[3]);
249                         tuple.v4.sport = *src_port;
250                         tuple.v4.dport = *dst_port;
251                 } else{
252                         tuple.v4.src_addr = rte_bswap32(*src_addr);
253                         tuple.v4.dst_addr = rte_bswap32(*dst_addr);
254                         tuple.v4.sport = *src_port;
255                         tuple.v4.dport = *dst_port;
256                 }
257                 /* Compute */
258                 hash_ipv4 = rte_softrss((uint32_t *)&tuple,
259                                 RTE_THASH_V4_L4_LEN,
260                                 default_rss_key);
261                 /* Egress */
262
263                 /* To select the thread */
264                 thread = (hash_ipv4 % nthreads);
265
266                 /* To select the Q */
267                 thread = ap->in_port_id + (p_loadb->p.n_ports_in *
268                                 (thread + 1) - p_loadb->p.n_ports_in);
269
270                 if (LOADB_DEBUG > 3) {
271                         printf("src_addr: %x dst_addr: %x src_port: %x "
272                         "dst_port: %x\n", tuple.v4.src_addr, tuple.v4.dst_addr,
273                         tuple.v4.sport, tuple.v4.dport);
274                         printf("thread: %u  hash: %x\n", thread, hash_ipv4);
275                 }
276
277                 return thread;
278
279         case 5:
280
281                 if (rte_be_to_cpu_16(lb_pkt->eth.ether_type) ==
282                         ETHER_TYPE_IPv6) {
283                         /* point to last 32 bits of IPv6 addresses*/
284                         src_addr += 3;
285                         dst_addr += 3;
286                 }
287
288                 /* Compute */
289                 temp1 = *src_addr ^ *dst_addr ^ *src_port ^
290                         *dst_port ^ *protocol;
291
292                 temp2 = (temp1 >> 24) ^ (temp1 >> 16) ^ (temp1 >> 8) ^ temp1;
293                 temp3 = (temp2 >> 4) ^ (temp2 & 0xf);
294
295                 /* Egress */
296
297                 /* To select the thread */
298                 thread = (temp3 % nthreads);
299
300                 /* To select the Q */
301                 thread = ap->in_port_id + (p_loadb->p.n_ports_in *
302                                 (thread + 1) - p_loadb->p.n_ports_in);
303
304                 if (LOADB_DEBUG > 3) {
305                         printf("thread: %u  temp1: %x  temp2: %x  temp3: %x\n",
306                                 thread, temp1, temp2, temp3);
307                         printf("src_addr: %x dst_addr: %x src_port: %x "
308                         "dst_port: %x protocol: %x\n", *src_addr, *dst_addr,
309                         *src_port, *dst_port, *protocol);
310                 }
311                 return thread;
312
313         default:
314                 printf("Invalid n_lb_tuples: %d\n", p_loadb->n_lb_tuples);
315                 return 0;
316
317         }
318 }
319
320 uint8_t calculate_lb_thread_pub(struct rte_mbuf *pkt, void *arg)
321 {
322         uint32_t hash_key[2], hash_ipv4;
323         uint32_t temp1, temp2, temp3;
324         uint8_t thread;
325         struct pipeline_loadb_in_port_h_arg *ap = arg;
326         struct pipeline_loadb *p_loadb = (struct pipeline_loadb *) ap->p;
327         uint8_t nthreads = p_loadb->n_vnf_threads;
328         union rte_thash_tuple tuple;
329
330         uint32_t *src_addr;
331         uint32_t *dst_addr;
332         uint16_t *src_port;
333         uint16_t *dst_port;
334         uint8_t *protocol;
335         struct lb_pkt *lb_pkt = (struct lb_pkt *)
336                                 RTE_MBUF_METADATA_UINT8_PTR(pkt,
337                                         MBUF_HDR_ROOM);
338
339         if (rte_be_to_cpu_16(lb_pkt->eth.ether_type) == ETHER_TYPE_IPv6) {
340                 src_addr = (uint32_t *)&lb_pkt->ipv6_port.ipv6.src_addr;
341                 dst_addr = (uint32_t *)&lb_pkt->ipv6_port.ipv6.dst_addr;
342                 src_port = &lb_pkt->ipv6_port.src_port;
343                 dst_port = &lb_pkt->ipv6_port.dst_port;
344                 protocol = &lb_pkt->ipv6_port.ipv6.proto;
345         } else {
346                 src_addr = &lb_pkt->ipv4_port.ipv4.src_addr;
347                 dst_addr = &lb_pkt->ipv4_port.ipv4.dst_addr;
348                 src_port = &lb_pkt->ipv4_port.src_port;
349                 dst_port = &lb_pkt->ipv4_port.dst_port;
350                 protocol = &lb_pkt->ipv4_port.ipv4.next_proto_id;
351         }
352
353         switch (p_loadb->n_lb_tuples) {
354
355         case 0:
356                 /* Write */
357                                                  /* Ingress */
358                         temp1 = *src_addr ^ *src_port;
359                         temp2 = (temp1 >> 24) ^ (temp1 >> 16) ^
360                                 (temp1 >> 8) ^ temp1;
361                         temp3 = (temp2 >> 4) ^ (temp2 & 0xf);
362
363                         /* To select the thread */
364                         thread = temp3 % nthreads;
365                         /* To select the Q */
366                         thread = ap->in_port_id + (p_loadb->p.n_ports_in *
367                                 (thread + 1) - p_loadb->p.n_ports_in);
368
369                         return thread;
370
371         case 1:
372                 /* Write */
373                                 /* Ingress */
374                         hash_key[0] = rte_bswap32(*src_addr);
375
376                         /* Compute */
377                         hash_ipv4 = rte_jhash(&hash_key[0], 4, 0);
378
379                         /* To select the thread */
380                         thread = hash_ipv4 % nthreads;
381                         /* To select the Q */
382                         thread = ap->in_port_id + (p_loadb->p.n_ports_in *
383                                 (thread + 1) - p_loadb->p.n_ports_in);
384
385                 if (LOADB_DEBUG > 3)
386                         printf("thread: %u  hash: %x  hash_key: %x\n",
387                                 thread, hash_ipv4, hash_key[0]);
388                 return thread;
389
390         case 2:
391                 /* Write */
392                                 /* Ingress */
393                         hash_key[0] = rte_bswap32(*src_addr);
394                         hash_key[1] = *src_port << 16;
395
396                         /* Compute */
397                         hash_ipv4 = rte_jhash(&hash_key[0], 6, 0);
398
399                         /* To select the thread */
400                         thread = hash_ipv4 % nthreads;
401                         /* To select the Q */
402                         thread = ap->in_port_id + (p_loadb->p.n_ports_in *
403                                 (thread + 1) - p_loadb->p.n_ports_in);
404
405                 if (LOADB_DEBUG > 3) {
406                         printf("thread: %u  hash: %x  hash_key0: %x  "
407                         "hash_key1: %x\n", thread, hash_ipv4,
408                         hash_key[0], hash_key[1]);
409                         printf("public_addr: %x public_port: %x\n",
410                         hash_key[0], *src_port);
411                 }
412                 return thread;
413
414         case 3:
415                 printf("Invalid n_lb_tuples: %d\n", p_loadb->n_lb_tuples);
416                 return 0;
417
418         case 4:
419                 /* Write */
420                 tuple.v4.src_addr = rte_bswap32(*src_addr);
421                 tuple.v4.dst_addr = rte_bswap32(*dst_addr);
422                 tuple.v4.sport = *src_port;
423                 tuple.v4.dport = *dst_port;
424
425                 /* Compute */
426                 hash_ipv4 = rte_softrss((uint32_t *)&tuple,
427                                 RTE_THASH_V4_L4_LEN, default_rss_key);
428
429                         /* Ingress */
430                         /* To select the thread */
431                         thread = hash_ipv4 % nthreads;
432                         /* To select the Q */
433                         thread = ap->in_port_id + (p_loadb->p.n_ports_in *
434                                 (thread + 1) - p_loadb->p.n_ports_in);
435
436                 if (LOADB_DEBUG > 3) {
437                         printf("src_addr: %x dst_addr: %x src_port: %x "
438                                 "dst_port: %x\n", tuple.v4.src_addr,
439                         tuple.v4.dst_addr, tuple.v4.sport, tuple.v4.dport);
440
441                         printf("thread: %u  hash: %x\n", thread, hash_ipv4);
442                 }
443                 return thread;
444
445         case 5:
446
447                 if (rte_be_to_cpu_16(lb_pkt->eth.ether_type) ==
448                         ETHER_TYPE_IPv6) {
449                         /* point to last 32 bits of IPv6 addresses*/
450                         src_addr += 3;
451                         dst_addr += 3;
452                 }
453
454                 /* Compute */
455                 temp1 = *src_addr ^ *dst_addr ^ *src_port ^
456                         *dst_port ^ *protocol;
457                 temp2 = (temp1 >> 24) ^ (temp1 >> 16) ^
458                         (temp1 >> 8) ^ temp1;
459                 temp3 = (temp2 >> 4) ^ (temp2 & 0xf);
460
461                         /* To select the thread */
462                         thread = temp3 % nthreads;
463                         /* To select the Q */
464                         thread = ap->in_port_id + (p_loadb->p.n_ports_in *
465                                 (thread + 1) - p_loadb->p.n_ports_in);
466
467                 if (LOADB_DEBUG > 3) {
468                         printf("src_addr: %x dst_addr: %x src_port: %x "
469                         "dst_port: %x protocol: %x\n", *src_addr, *dst_addr,
470                         *src_port, *dst_port, *protocol);
471
472                         printf("thread: %u  temp1: %x  temp2: %x  temp3: %x\n",
473                                 thread, temp1, temp2, temp3);
474                 }
475
476                 return thread;
477
478         default:
479                 printf("Invalid n_lb_tuples: %d\n", p_loadb->n_lb_tuples);
480                 return 0;
481
482         }
483 }
484
485 static inline void
486 pkt_work_loadb_key_prv(
487         struct rte_mbuf *pkt,
488         __rte_unused uint32_t pkt_num,
489         void *arg)
490 {
491         struct pipeline_loadb_in_port_h_arg *ap = arg;
492         struct pipeline_loadb *p_loadb = (struct pipeline_loadb *)ap->p;
493         uint32_t outport_offset = p_loadb->outport_offset;
494
495         struct lb_pkt *lb_pkt = (struct lb_pkt *)
496                                 RTE_MBUF_METADATA_UINT8_PTR(pkt,
497                                 MBUF_HDR_ROOM);
498         uint32_t *out_port = RTE_MBUF_METADATA_UINT32_PTR(pkt,
499                                 outport_offset);
500
501         #ifdef MY_LOADB_DBG_PRINT
502         if (LOADB_DEBUG == 3)
503                 printf("Start pkt_work_loadb_key\n");
504         #endif
505
506         if ((LOADB_DEBUG > 2) && (lb_pkt_print_count < 10)) {
507                 print_pkt1(pkt);
508                 lb_pkt_print_count++;
509                 printf("\nEth Typ %x, Prot %x, ETH_TYPE_ARP %x, "
510                         "ETH_TYPE_IPV4 %x, IP_PROTOCOL_ICMP %x\n",
511                         rte_be_to_cpu_16(lb_pkt->eth.ether_type),
512                         lb_pkt->ipv4_port.ipv4.next_proto_id, ETH_TYPE_ARP,
513                         ETH_TYPE_IPV4, IP_PROTOCOL_ICMP);
514         }
515
516                 /* Write */
517                 *out_port = calculate_lb_thread_prv(pkt, arg);
518
519         p_loadb->receivedLBPktCount++;
520
521         #ifdef MY_LOADB_DBG_PRINT
522         if (LOADB_DEBUG == 3)
523                 printf("End pkt_work_loadb_key\n");
524         #endif
525 }
526
527 static inline void
528 pkt_work_loadb_key_pub(
529         struct rte_mbuf *pkt,
530         __rte_unused uint32_t pkt_num,
531         void *arg)
532 {
533         struct pipeline_loadb_in_port_h_arg *ap = arg;
534         struct pipeline_loadb *p_loadb = (struct pipeline_loadb *)ap->p;
535         uint32_t outport_offset = p_loadb->outport_offset;
536
537         struct lb_pkt *lb_pkt = (struct lb_pkt *)
538                                 RTE_MBUF_METADATA_UINT8_PTR(pkt,
539                                 MBUF_HDR_ROOM);
540         uint32_t *out_port = RTE_MBUF_METADATA_UINT32_PTR(pkt,
541                                 outport_offset);
542
543         #ifdef MY_LOADB_DBG_PRINT
544         if (LOADB_DEBUG == 3)
545                 printf("Start pkt_work_loadb_key\n");
546         #endif
547
548         if ((LOADB_DEBUG > 2) && (lb_pkt_print_count < 10)) {
549                 print_pkt1(pkt);
550                 lb_pkt_print_count++;
551                 printf("\nEth Typ %x, Prot %x, ETH_TYPE_ARP %x, "
552                         "ETH_TYPE_IPV4 %x, IP_PROTOCOL_ICMP %x\n",
553                         rte_be_to_cpu_16(lb_pkt->eth.ether_type),
554                         lb_pkt->ipv4_port.ipv4.next_proto_id, ETH_TYPE_ARP,
555                         ETH_TYPE_IPV4, IP_PROTOCOL_ICMP);
556         }
557
558                 /* Write */
559                 *out_port = calculate_lb_thread_pub(pkt, arg);
560
561         p_loadb->receivedLBPktCount++;
562 #ifdef MY_LOADB_DBG_PRINT
563         if (LOADB_DEBUG == 3)
564                 printf("End pkt_work_loadb_key\n");
565 #endif
566 }
567
568 static inline void
569 pkt4_work_loadb_key_prv(
570         struct rte_mbuf **pkt,
571         __rte_unused uint32_t pkt_num,
572         void *arg)
573 {
574         struct pipeline_loadb_in_port_h_arg *ap = arg;
575         struct pipeline_loadb *p_loadb = (struct pipeline_loadb *)ap->p;
576         uint32_t outport_offset = p_loadb->outport_offset;
577
578         uint32_t *out_port0 = RTE_MBUF_METADATA_UINT32_PTR(pkt[0],
579                                 outport_offset);
580         uint32_t *out_port1 = RTE_MBUF_METADATA_UINT32_PTR(pkt[1],
581                                 outport_offset);
582         uint32_t *out_port2 = RTE_MBUF_METADATA_UINT32_PTR(pkt[2],
583                                 outport_offset);
584         uint32_t *out_port3 = RTE_MBUF_METADATA_UINT32_PTR(pkt[3],
585                                 outport_offset);
586
587         struct lb_pkt *lb_pkt0 = (struct lb_pkt *)
588                                 RTE_MBUF_METADATA_UINT8_PTR(pkt[0],
589                                         MBUF_HDR_ROOM);
590         struct lb_pkt *lb_pkt1 = (struct lb_pkt *)
591                                 RTE_MBUF_METADATA_UINT8_PTR(pkt[1],
592                                         MBUF_HDR_ROOM);
593         struct lb_pkt *lb_pkt2 = (struct lb_pkt *)
594                                 RTE_MBUF_METADATA_UINT8_PTR(pkt[2],
595                                         MBUF_HDR_ROOM);
596         struct lb_pkt *lb_pkt3 = (struct lb_pkt *)
597                                 RTE_MBUF_METADATA_UINT8_PTR(pkt[3],
598                                         MBUF_HDR_ROOM);
599
600         #ifdef MY_LOADB_DBG_PRINT
601         if (LOADB_DEBUG == 3)
602                 printf("Start pkt4_work_loadb_key\n");
603         #endif
604
605         if ((LOADB_DEBUG > 2) && (lb_pkt_print_count < 10)) {
606                 print_pkt1(pkt[0]);
607                 lb_pkt_print_count++;
608
609                 printf("\nEth Typ %x, Prot %x\n",
610                         rte_be_to_cpu_16(lb_pkt0->eth.ether_type),
611                         lb_pkt0->ipv4_port.ipv4.next_proto_id);
612
613                 print_pkt1(pkt[1]);
614                 lb_pkt_print_count++;
615
616                 printf("\nEth Typ %x, Prot %x\n",
617                         rte_be_to_cpu_16(lb_pkt1->eth.ether_type),
618                         lb_pkt1->ipv4_port.ipv4.next_proto_id);
619
620                 print_pkt1(pkt[2]);
621                 lb_pkt_print_count++;
622
623                 printf("\nEth Typ %x, Prot %x\n",
624                         rte_be_to_cpu_16(lb_pkt2->eth.ether_type),
625                         lb_pkt2->ipv4_port.ipv4.next_proto_id);
626
627                 print_pkt1(pkt[3]);
628                 lb_pkt_print_count++;
629
630                 printf("\nEth Typ %x, Prot %x\n",
631                         rte_be_to_cpu_16(lb_pkt3->eth.ether_type),
632                         lb_pkt3->ipv4_port.ipv4.next_proto_id);
633         }
634                 *out_port0 = calculate_lb_thread_prv(pkt[0], arg);
635                 *out_port1 = calculate_lb_thread_prv(pkt[1], arg);
636                 *out_port2 = calculate_lb_thread_prv(pkt[2], arg);
637                 *out_port3 = calculate_lb_thread_prv(pkt[3], arg);
638
639         p_loadb->receivedLBPktCount += 4;
640
641         #ifdef MY_LOADB_DBG_PRINT
642         if (LOADB_DEBUG == 3)
643                 printf("End pkt4_work_loadb_key\n");
644         #endif
645
646 }
647
648 static inline void
649 pkt4_work_loadb_key_pub(
650         struct rte_mbuf **pkt,
651         __rte_unused uint32_t pkt_num,
652         void *arg)
653 {
654         struct pipeline_loadb_in_port_h_arg *ap = arg;
655         struct pipeline_loadb *p_loadb = (struct pipeline_loadb *)ap->p;
656         uint32_t outport_offset = p_loadb->outport_offset;
657
658         uint32_t *out_port0 = RTE_MBUF_METADATA_UINT32_PTR(pkt[0],
659                                 outport_offset);
660         uint32_t *out_port1 = RTE_MBUF_METADATA_UINT32_PTR(pkt[1],
661                                 outport_offset);
662         uint32_t *out_port2 = RTE_MBUF_METADATA_UINT32_PTR(pkt[2],
663                                 outport_offset);
664         uint32_t *out_port3 = RTE_MBUF_METADATA_UINT32_PTR(pkt[3],
665                                 outport_offset);
666
667         struct lb_pkt *lb_pkt0 = (struct lb_pkt *)
668                                 RTE_MBUF_METADATA_UINT8_PTR(pkt[0],
669                                         MBUF_HDR_ROOM);
670         struct lb_pkt *lb_pkt1 = (struct lb_pkt *)
671                                 RTE_MBUF_METADATA_UINT8_PTR(pkt[1],
672                                         MBUF_HDR_ROOM);
673         struct lb_pkt *lb_pkt2 = (struct lb_pkt *)
674                                 RTE_MBUF_METADATA_UINT8_PTR(pkt[2],
675                                         MBUF_HDR_ROOM);
676         struct lb_pkt *lb_pkt3 = (struct lb_pkt *)
677                                 RTE_MBUF_METADATA_UINT8_PTR(pkt[3],
678                                         MBUF_HDR_ROOM);
679
680         #ifdef MY_LOADB_DBG_PRINT
681         if (LOADB_DEBUG == 3)
682                 printf("Start pkt4_work_loadb_key\n");
683         #endif
684
685         if ((LOADB_DEBUG > 2) && (lb_pkt_print_count < 10)) {
686                 print_pkt1(pkt[0]);
687                 lb_pkt_print_count++;
688
689                 printf("\nEth Typ %x, Prot %x\n",
690                         rte_be_to_cpu_16(lb_pkt0->eth.ether_type),
691                         lb_pkt0->ipv4_port.ipv4.next_proto_id);
692
693                 print_pkt1(pkt[1]);
694                 lb_pkt_print_count++;
695
696                 printf("\nEth Typ %x, Prot %x\n",
697                         rte_be_to_cpu_16(lb_pkt1->eth.ether_type),
698                         lb_pkt1->ipv4_port.ipv4.next_proto_id);
699
700                 print_pkt1(pkt[2]);
701                 lb_pkt_print_count++;
702
703                 printf("\nEth Typ %x, Prot %x\n",
704                         rte_be_to_cpu_16(lb_pkt2->eth.ether_type),
705                         lb_pkt2->ipv4_port.ipv4.next_proto_id);
706
707                 print_pkt1(pkt[3]);
708                 lb_pkt_print_count++;
709
710                 printf("\nEth Typ %x, Prot %x\n",
711                         rte_be_to_cpu_16(lb_pkt3->eth.ether_type),
712                         lb_pkt3->ipv4_port.ipv4.next_proto_id);
713         }
714                 *out_port0 = calculate_lb_thread_prv(pkt[0], arg);
715                 *out_port1 = calculate_lb_thread_pub(pkt[1], arg);
716                 *out_port2 = calculate_lb_thread_pub(pkt[2], arg);
717                 *out_port3 = calculate_lb_thread_pub(pkt[3], arg);
718
719         p_loadb->receivedLBPktCount += 4;
720 #ifdef MY_LOADB_DBG_PRINT
721         if (LOADB_DEBUG == 3)
722                 printf("End pkt4_work_loadb_key\n");
723 #endif
724
725 }
726
727 PIPELINE_LOADB_KEY_PORT_IN_AH(port_in_ah_loadb_key_prv,
728                                 pkt_work_loadb_key_prv,
729                                 pkt4_work_loadb_key_prv);
730
731 PIPELINE_LOADB_KEY_PORT_IN_AH(port_in_ah_loadb_key_pub,
732                                 pkt_work_loadb_key_pub,
733                                 pkt4_work_loadb_key_pub);
734
735 static int
736 pipeline_loadb_parse_args(struct pipeline_loadb *p,
737                                 struct pipeline_params *params)
738 {
739         uint32_t outport_offset_present = 0;
740         uint32_t n_vnf_threads_present = 0;
741         uint32_t pktq_in_prv_present = 0;
742         uint32_t prv_que_handler_present = 0;
743         uint32_t prv_to_pub_map_present = 0;
744         uint8_t n_prv_in_port = 0;
745         uint32_t i;
746
747         /* Default number of tuples */
748         p->n_lb_tuples = 0;
749
750         if (LOADB_DEBUG > 2)
751                 printf("LOADB pipeline_loadb_parse_args params->n_args: %d\n",
752                                          params->n_args);
753
754         for (i = 0; i < params->n_args; i++) {
755                 char *arg_name = params->args_name[i];
756                 char *arg_value = params->args_value[i];
757
758                 if (LOADB_DEBUG > 2)
759                         printf("LOADB args[%d]: %s %d, %s\n", i, arg_name,
760                                                  atoi(arg_value), arg_value);
761
762                 /* outport_offset = 128 + 8 */
763                 if (strcmp(arg_name, "outport_offset") == 0) {
764                         if (outport_offset_present)
765                                 return -1;
766                         outport_offset_present = 1;
767
768                         p->outport_offset = atoi(arg_value);
769                         if (p->outport_offset <= 0) {
770                                 printf("Outport_offset is invalid\n");
771                                 return -1;
772                         }
773                         printf("outport_offset: 0x%x\n", p->outport_offset);
774                         continue;
775                 }
776                 /* n_vnf_threads = 4 */
777                 if (strcmp(arg_name, "n_vnf_threads") == 0) {
778                         if (n_vnf_threads_present)
779                                 return -1;
780                         n_vnf_threads_present = 1;
781
782                         p->n_vnf_threads = atoi(arg_value);
783
784                         total_vnf_threads += p->n_vnf_threads;
785
786                         if ((p->n_vnf_threads <= 0)
787                                         || (total_vnf_threads > MAX_VNF_THREADS)) {
788                                 printf("n_vnf_threads : MIN->0 MAX->16\n");
789                                 return -1;
790                         }
791                         printf("n_vnf_threads    : 0x%x\n", p->n_vnf_threads);
792                         printf("total_vnf_threads: 0x%x\n", total_vnf_threads);
793                         continue;
794                 }
795
796                                 /* pktq_in_prv */
797                 if (strcmp(arg_name, "pktq_in_prv") == 0) {
798                         if (pktq_in_prv_present) {
799                                 printf("Duplicate pktq_in_prv ... "
800                                 "parse failed..\n\n");
801                                 return -1;
802                         }
803                         pktq_in_prv_present = 1;
804
805                         int rxport = 0, j = 0;
806                         char phy_port_num[8];
807                         char *token = strtok(arg_value, "RXQ");
808                         while (token) {
809                                 j = 0;
810                                 while ((j < 7) && (token[j] != '.')) {
811                                         phy_port_num[j] = token[j];
812                                         j++;
813                                 }
814                                 phy_port_num[j] = '\0';
815                                 rxport =  atoi(phy_port_num);
816                                 printf("token: %s, phy_port_str: %s, "
817                                         "phy_port_num %d\n",
818                                 token, phy_port_num, rxport);
819                                 prv_in_port_a[n_prv_in_port++] = rxport;
820                                 // set rxport egress
821                                 if (rxport < 0xff){
822                                        if(rxport < PIPELINE_MAX_PORT_IN)
823                                         in_port_dir_a[rxport] = 1;
824                                 }
825                                 token = strtok(NULL, "RXQ");
826                         }
827
828                         if (n_prv_in_port == 0) {
829                                 printf("VNF common parse error - "
830                                 "no prv RX phy port\n");
831                                 return -1;
832                         }
833                         continue;
834                 }
835
836                                 /* pktq_in_prv_handler */
837
838                 if (strcmp(arg_name, "prv_que_handler") == 0) {
839
840                         if (prv_que_handler_present) {
841                                 printf("Duplicate pktq_in_prv ..\n\n");
842                                 return -1;
843                         }
844                         prv_que_handler_present = 1;
845                         n_prv_in_port = 0;
846
847                         char *token;
848                         int rxport = 0;
849                         /* get the first token */
850                         token = strtok(arg_value, "(");
851                         token = strtok(token, ")");
852                         token = strtok(token, ",");
853                         printf("***** prv_que_handler *****\n");
854                         if (token)
855                                                                                 printf("string is :%s\n", token);
856
857                         if (token)
858                                 //printf("string is null\n");
859                         printf("string is :%s\n", token);
860
861                         /* walk through other tokens */
862                         while (token != NULL) {
863                                 printf(" %s\n", token);
864                                 rxport =  atoi(token);
865                                 prv_que_port_index[n_prv_in_port++] = rxport;
866                                 if (rxport < 0xff){
867                                   if(rxport < PIPELINE_MAX_PORT_IN)
868                                         in_port_egress_prv[rxport] = 1;
869                                 }
870                                 p->n_prv_Q++;
871                                 token = strtok(NULL, ",");
872                         }
873
874                         if (n_prv_in_port == 0) {
875                         printf("VNF common parse err - no prv RX phy port\n");
876                         return -1;
877                         }
878
879                         continue;
880                         }
881                 /* prv_to_pub_map */
882                 if (strcmp(arg_name, "prv_to_pub_map") == 0) {
883                         if (prv_to_pub_map_present) {
884                                 printf("Duplicated prv_to_pub_map ... "
885                                         "parse failed ...\n");
886                                 return -1;
887                         }
888                         prv_to_pub_map_present = 1;
889
890                          int rxport = 0, txport = 0, j = 0, k = 0;
891                          char rx_phy_port_num[5];
892                          char tx_phy_port_num[5];
893                          char *token = strtok(arg_value, "(");
894                         while (token) {
895                                 j = 0;
896                                 while ((j < 4) && (token[j] != ',')) {
897                                         rx_phy_port_num[j] = token[j];
898                                         j++;
899                                 }
900                                 rx_phy_port_num[j] = '\0';
901                                 rxport =  atoi(rx_phy_port_num);
902
903                                 j++;
904                                 k = 0;
905                                 while ((k < 4) && (token[j+k] != ')')) {
906                                         tx_phy_port_num[k] = token[j+k];
907                                         k++;
908                                 }
909                                  tx_phy_port_num[k] = '\0';
910                                  txport =  atoi(tx_phy_port_num);
911
912                         printf("token: %s,rx_phy_port_str: %s, phy_port_num "
913                         "%d, tx_phy_port_str: %s, tx_phy_port_num %d\n",
914                         token, rx_phy_port_num, rxport,
915                         tx_phy_port_num, txport);
916                          if(rxport < PIPELINE_MAX_PORT_IN)
917                         if ((rxport >= PIPELINE_MAX_PORT_IN) ||
918                                 (txport >= PIPELINE_MAX_PORT_IN) ||
919                                 (in_port_dir_a[rxport] != 1)) {
920                                 printf("CG-NAPT parse error - "
921                                 "incorrect prv-pub translation. Rx %d, "
922                                 "Tx %d, Rx Dir %d\n", rxport, txport,
923                                 in_port_dir_a[rxport]);
924
925                                 return -1;
926                         }
927                         if (rxport < 0xff){
928                               if (rxport < PIPELINE_MAX_PORT_IN)
929                                 prv_to_pub_map[rxport] = txport;
930                                                  }
931                        if (txport < 0xff)
932                             if(txport < PIPELINE_MAX_PORT_IN)
933                                 pub_to_prv_map[txport] = rxport;
934                         token = strtok(NULL, "(");
935                 }
936
937                         continue;
938                 }
939                 /* Set number of tuples if available in config file */
940                 if (strcmp(arg_name, "n_lb_tuples") == 0) {
941                         p->n_lb_tuples = atoi(arg_value);
942                         printf("n_lb_tuples: 0x%x\n", p->n_lb_tuples);
943                 }
944
945                 /* loadb_debug */
946                 if (strcmp(arg_name, "loadb_debug") == 0) {
947                         LOADB_DEBUG = atoi(arg_value);
948                         continue;
949                 }
950
951                 /* any other Unknown argument return -1 */
952         }                       /* for */
953
954         /* Check that mandatory arguments are present */
955         if ((n_vnf_threads_present == 0) || (outport_offset_present == 0))
956                 return -1;
957
958         return 0;
959
960 }
961
962 int check_loadb_thread(
963         struct app_params *app,
964         struct pipeline_params *params,
965         int32_t n_vnf_threads)
966 {
967         uint32_t i;
968         int pipeline_num = 0;
969         int count = 0;
970         int dont_care = sscanf(params->name, "PIPELINE%d", &pipeline_num);
971         if (dont_care != 1)
972                 return -1;
973         /* changed from pipeline_num+1 to +2 */
974         for (i = pipeline_num + 2; i < app->n_pipelines; i++) {
975                 struct app_pipeline_params *p = &app->pipeline_params[i];
976                 if (!strncmp(p->type, "LOADB", strlen(p->type)))
977                         break;
978                 count++;
979         }
980         if (n_vnf_threads != count)
981                 return -1;
982         return 0;
983
984 }
985
986 static void *pipeline_loadb_init(
987         struct pipeline_params *params,
988         __rte_unused void *arg)
989         /* arg is app parameter (struct app_params *app) */
990         /*save it for use in port in handler */
991 {
992         struct pipeline *p;
993         struct pipeline_loadb *p_loadb;
994         uint32_t size, i, in_ports_arg_size;
995
996         /* Check input arguments */
997         if ((params == NULL) ||
998                         (params->n_ports_in == 0) || (params->n_ports_out == 0))
999                 return NULL;
1000
1001         /* Memory allocation */
1002         size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct pipeline_loadb));
1003         p = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
1004         p_loadb = (struct pipeline_loadb *)p;
1005         if (p == NULL)
1006                 return NULL;
1007
1008         strcpy(p->name, params->name);
1009         p->log_level = params->log_level;
1010
1011         PLOG(p, HIGH, "LOADB");
1012
1013         p_loadb->n_vnf_threads = 0;
1014         p_loadb->outport_offset = 0;
1015         p_loadb->receivedLBPktCount = 0;
1016         p_loadb->droppedLBPktCount = 0;
1017         for (i = 0; i < PIPELINE_MAX_PORT_IN; i++) {
1018                 p_loadb->links_map[i] = 0xff;
1019         }
1020         p_loadb->pipeline_num = 0xff;
1021         p_loadb->n_prv_Q = 0;
1022         p_loadb->n_pub_Q = 0;
1023
1024         /* Parse arguments */
1025
1026         if (pipeline_loadb_parse_args(p_loadb, params))
1027                 return NULL;
1028
1029         /* Pipeline */
1030         {
1031                 struct rte_pipeline_params pipeline_params = {
1032                         .name = "LOADB",
1033                         .socket_id = params->socket_id,
1034                         .offset_port_id = 0,
1035                 };
1036
1037                 p->p = rte_pipeline_create(&pipeline_params);
1038                 if (p->p == NULL) {
1039                         rte_free(p);
1040                         return NULL;
1041                 }
1042
1043                 printf("Loadb p->p %p, socket %d\n", p->p,
1044                                          pipeline_params.socket_id);
1045         }
1046
1047         /* Memory allocation for in_port_h_arg */
1048         in_ports_arg_size =
1049                         RTE_CACHE_LINE_ROUNDUP((sizeof(struct pipeline_loadb_in_port_h_arg))
1050                                          * (params->n_ports_in));
1051         struct pipeline_loadb_in_port_h_arg *ap =
1052                         (struct pipeline_loadb_in_port_h_arg *)
1053                 rte_zmalloc(NULL,
1054                         in_ports_arg_size,
1055                         RTE_CACHE_LINE_SIZE);
1056         if (ap == NULL)
1057                 return NULL;
1058
1059         printf("ap pointer %p\n", ap);
1060
1061         /* Input ports */
1062         p->n_ports_in = params->n_ports_in;
1063         for (i = 0; i < p->n_ports_in; i++) {
1064                 /* passing our loadb pipeline in call back arg */
1065                 (ap[i]).p = p_loadb;
1066                 (ap[i]).in_port_id = i;
1067
1068                 struct rte_pipeline_port_in_params port_params = {
1069                         .ops =
1070                                         pipeline_port_in_params_get_ops(&params->port_in
1071                                                                         [i]),
1072                         .arg_create =
1073                                         pipeline_port_in_params_convert(&params->port_in
1074                                                                         [i]),
1075                 /* Public in-port handler */
1076                         .f_action = NULL,
1077                         .arg_ah = &(ap[i]),
1078                         .burst_size = params->port_in[i].burst_size,
1079                 };
1080
1081                 /* Private in-port handler */
1082                 if (is_port_index_privte(i)) {/* Multiport changes*/
1083                         printf("LOADB %d port is Prv\n", i);
1084                         port_params.f_action = port_in_ah_loadb_key_prv;
1085                 } else{
1086                         printf("LOADB %d port is Pub\n", i);
1087                         port_params.f_action = port_in_ah_loadb_key_pub;
1088                 }
1089
1090                 int status = rte_pipeline_port_in_create(p->p,
1091                                                          &port_params,
1092                                                          &p->port_in_id[i]);
1093
1094                 if (status) {
1095                         rte_pipeline_free(p->p);
1096                         rte_free(p);
1097                         return NULL;
1098                 }
1099
1100         }
1101
1102                 p_loadb->n_pub_Q = p_loadb->p.n_ports_in - p_loadb->n_prv_Q;
1103                 printf("LOADB : n_prv_Q - %d  n_pub_Q - %d\n",
1104                                 p_loadb->n_prv_Q, p_loadb->n_pub_Q);
1105
1106                 for (i = 0; i <  p->n_ports_in; i++) {
1107                         printf("is_port_index_privte(%d): %d\n", i,
1108                                 is_port_index_privte(i));
1109                         printf("is_phy_port_privte(%d): %d\n", i,
1110                                 is_phy_port_privte(i));
1111                         printf("action handler of %d:%p\n", i,
1112                                 p_loadb->p.p->ports_in[i].f_action);
1113                 }
1114
1115         /* Output ports */
1116         p->n_ports_out = params->n_ports_out;
1117         for (i = 0; i < p->n_ports_out; i++) {
1118                 struct rte_pipeline_port_out_params port_params = {
1119                         .ops =
1120                                         pipeline_port_out_params_get_ops(&params->port_out
1121                                                                          [i]),
1122                         .arg_create =
1123                                         pipeline_port_out_params_convert(&params->port_out
1124                                                                          [i]),
1125                         .f_action = NULL,
1126                         .arg_ah = NULL,
1127                 };
1128
1129                 int status = rte_pipeline_port_out_create(p->p,
1130                                                                 &port_params,
1131                                                                 &p->port_out_id[i]);
1132
1133                 if (status) {
1134                         rte_pipeline_free(p->p);
1135                         rte_free(p);
1136                         return NULL;
1137                 }
1138
1139                 printf("Outport p->port_out_id[%d] %p\n", i,
1140                                          &p->port_out_id[i]);
1141         }
1142
1143         int pipeline_num = 0;
1144         int dont_care = sscanf(params->name, "PIPELINE%d", &pipeline_num);
1145         if (dont_care != 1) {
1146                 printf("Unable to read pipeline number\n");
1147                 return NULL;
1148         }
1149         p_loadb->pipeline_num = pipeline_num;
1150 #if 0
1151         set_outport_id(pipeline_num, p, lb_outport_id);
1152         set_phy_outport_map(pipeline_num, p_loadb->links_map);
1153
1154         set_port_to_loadb_map(pipeline_num);
1155
1156         register_loadb_to_arp(pipeline_num, p, app);
1157 #endif
1158         register_pipeline_Qs(p_loadb->pipeline_num, p);
1159         set_link_map(p_loadb->pipeline_num, p, p_loadb->links_map);
1160         //set_outport_id(p_loadb->pipeline_num, p, p_loadb->outport_id);
1161
1162         /* Tables */
1163         p->n_tables = 1;
1164         {
1165
1166                 struct rte_table_array_params table_array_params = {
1167                         .n_entries = MAX_VNF_THREADS,
1168                         .offset = p_loadb->outport_offset,
1169                 };
1170                 struct rte_pipeline_table_params table_params = {
1171                         .ops = &rte_table_array_ops,
1172                         .arg_create = &table_array_params,
1173                         .f_action_hit = NULL,
1174                         .f_action_miss = NULL,
1175                         .arg_ah = p_loadb,
1176                         .action_data_size = 0,
1177                 };
1178
1179                 int status;
1180
1181                 status = rte_pipeline_table_create(p->p,
1182                                                          &table_params,
1183                                                          &p->table_id[0]);
1184
1185                 if (status) {
1186                         rte_pipeline_free(p->p);
1187                         rte_free(p);
1188                         return NULL;
1189                 }
1190         }                       /* Tables */
1191
1192         /* Connecting input ports to tables */
1193         for (i = 0; i < p->n_ports_in; i++) {
1194                 int status = rte_pipeline_port_in_connect_to_table(
1195                                 p->p,
1196                                 p->port_in_id[i],
1197                                 p->table_id[0]);
1198
1199                 if (status) {
1200                         rte_pipeline_free(p->p);
1201                         rte_free(p);
1202                         return NULL;
1203                 }
1204         }
1205
1206         /* Enable input ports */
1207         for (i = 0; i < p->n_ports_in; i++) {
1208                 int status = rte_pipeline_port_in_enable(p->p,
1209                                                          p->port_in_id[i]);
1210
1211                 if (status) {
1212                         rte_pipeline_free(p->p);
1213                         rte_free(p);
1214                         return NULL;
1215                 }
1216         }
1217
1218         /* Initialize table entries */
1219         {
1220                 for (i = 0; i < MAX_VNF_THREADS; i++) {
1221                         struct rte_table_array_key key = {
1222                                 .pos = i,
1223                         };
1224                         struct loadb_table_entry entry;
1225                         entry.head.action = RTE_PIPELINE_ACTION_PORT;
1226
1227                         if (i < p->n_ports_out) {
1228                                 entry.head.port_id = p->port_out_id[i];
1229                                 printf("\ni %d, p->port_out_id[%d] %d", i, i,
1230                                                 p->port_out_id[i]);
1231                         } else {
1232                                 /* First CGNAPT thread */
1233                                 entry.head.port_id = p->port_out_id[0];
1234                                 entry.head.action = RTE_PIPELINE_ACTION_DROP;
1235                         }
1236
1237                         struct rte_pipeline_table_entry *entry_ptr;
1238                         int key_found, status;
1239                         status = rte_pipeline_table_entry_add(
1240                                         p->p,
1241                                         p->table_id[0],
1242                                         &key,
1243                                         (struct rte_pipeline_table_entry *)
1244                                         &entry,
1245                                         &key_found,
1246                                         &entry_ptr);
1247                         if (status) {
1248                                 rte_pipeline_free(p->p);
1249                                 rte_free(p);
1250                                 return NULL;
1251                         }
1252                 }
1253         }
1254         /* Add default entry to tables */
1255         {
1256                 struct rte_pipeline_table_entry default_entry = {
1257                         .action = RTE_PIPELINE_ACTION_PORT,
1258                         /* LB by default forward to 1st cgnat thread */
1259                         .port_id = p->port_out_id[0],
1260                 };
1261
1262                 struct rte_pipeline_table_entry *default_entry_ptr;
1263
1264                 int status = rte_pipeline_table_default_entry_add(
1265                                 p->p,
1266                                 p->table_id[0],
1267                                 &default_entry,
1268                                 &default_entry_ptr);
1269
1270                 if (status) {
1271                         rte_pipeline_free(p->p);
1272                         rte_free(p);
1273                         return NULL;
1274                 }
1275
1276         }
1277
1278         /* Check pipeline consistency */
1279         if (rte_pipeline_check(p->p) < 0) {
1280                 rte_pipeline_free(p->p);
1281                 rte_free(p);
1282                 return NULL;
1283         }
1284
1285         /* Message queues */
1286         p->n_msgq = params->n_msgq;
1287         for (i = 0; i < p->n_msgq; i++)
1288                 p->msgq_in[i] = params->msgq_in[i];
1289         for (i = 0; i < p->n_msgq; i++)
1290                 p->msgq_out[i] = params->msgq_out[i];
1291
1292         /* Message handlers */
1293         memcpy(p->handlers, handlers, sizeof(p->handlers));
1294         memcpy(p_loadb->custom_handlers,
1295                                  custom_handlers, sizeof(p_loadb->custom_handlers));
1296
1297         return p;
1298 }
1299
1300 static int pipeline_loadb_free(void *pipeline)
1301 {
1302         struct pipeline *p = (struct pipeline *)pipeline;
1303
1304         /* Check input arguments */
1305         if (p == NULL)
1306                 return -1;
1307
1308         /* Free resources */
1309         rte_pipeline_free(p->p);
1310         rte_free(p);
1311         return 0;
1312 }
1313
1314 static int
1315 pipeline_loadb_track(void *pipeline,
1316                                  __rte_unused uint32_t port_in, uint32_t *port_out)
1317 {
1318         struct pipeline *p = (struct pipeline *)pipeline;
1319
1320         /* Check input arguments */
1321         if ((p == NULL) || (port_in >= p->n_ports_in) || (port_out == NULL))
1322                 return -1;
1323
1324         if (p->n_ports_in == 1) {
1325                 *port_out = 0;
1326                 return 0;
1327         }
1328
1329         return -1;
1330 }
1331
1332 static int pipeline_loadb_timer(void *pipeline)
1333 {
1334         struct pipeline *p = (struct pipeline *)pipeline;
1335
1336         pipeline_msg_req_handle(p);
1337         rte_pipeline_flush(p->p);
1338
1339         return 0;
1340 }
1341
1342 void *pipeline_loadb_msg_req_entry_dbg_handler(struct pipeline *p, void *msg)
1343 {
1344         struct pipeline_loadb_entry_dbg_msg_rsp *rsp = msg;
1345         uint8_t *Msg = msg;
1346         struct pipeline_loadb *p_loadb = (struct pipeline_loadb *)p;
1347
1348         rsp->status = 0;
1349
1350         printf("LoadB debug handler called with args %x %x, offset %d\n",
1351                                  Msg[LOADB_DBG_CMD_OFST], Msg[LOADB_DBG_CMD_OFST + 1],
1352                                  LOADB_DBG_CMD_OFST);
1353
1354         if (Msg[LOADB_DBG_CMD_OFST] == LOADB_DBG_CMD_STATS_SHOW) {
1355                 printf("\nLoadB Packet Stats: Received %" PRIu64 "\n",
1356                                          p_loadb->receivedLBPktCount);
1357                 return rsp;
1358         }
1359         if (Msg[LOADB_DBG_CMD_OFST] == LOADB_DBG_CMD_STATS_CLEAR) {
1360                 printf("\nLoadB Packet Stats: Received %" PRIu64 "\n",
1361                                          p_loadb->receivedLBPktCount);
1362                 p_loadb->receivedLBPktCount = 0;
1363                 return rsp;
1364         }
1365
1366         if (Msg[LOADB_DBG_CMD_OFST] == LOADB_DBG_CMD_DBG_LEVEL) {
1367                 LOADB_DEBUG = Msg[LOADB_DBG_CMD_OFST + 1];
1368                 printf("LOADB Debug level set to %d\n", LOADB_DEBUG);
1369                 lb_pkt_print_count = 0;
1370                 return rsp;
1371         }
1372         if (Msg[LOADB_DBG_CMD_OFST] == LOADB_DBG_CMD_DBG_SHOW) {
1373                 printf("\nLoadB DBG Level: %u\n", LOADB_DEBUG);
1374                 return rsp;
1375         }
1376         if (Msg[LOADB_DBG_CMD_OFST] == LOADB_DBG_CMD_IF_STATS) {
1377                 printf("\n");
1378                 uint8_t i, j;
1379
1380                 for (i = 0; i < p->n_ports_in; i++) {
1381                         struct rte_eth_stats stats;
1382                         rte_eth_stats_get(p_loadb->links_map[i], &stats);
1383                         if (is_phy_port_privte(i))
1384                                 printf("Private Port Stats %d\n", i);
1385                         else
1386                                 printf("Public Port Stats  %d\n", i);
1387                         printf("\n\tipackets : %" PRIu64 "\n\topackets : %"
1388                                                  PRIu64 "\n\tierrors  : %" PRIu64
1389                                                  "\n\toerrors  : %" PRIu64 "\n\trx_nombuf: %"
1390                                                  PRIu64 "\n", stats.ipackets, stats.opackets,
1391                                                  stats.ierrors, stats.oerrors, stats.rx_nombuf);
1392                         if (is_phy_port_privte(i))
1393                                 printf("Private Q: ");
1394                         else
1395                                 printf("Public  Q: ");
1396                         for (j = 0; j < RTE_ETHDEV_QUEUE_STAT_CNTRS; j++)
1397                                 printf(" %" PRIu64 ", %" PRIu64 "|",
1398                                                          stats.q_ipackets[j],
1399                                                          stats.q_opackets[j]);
1400
1401                         printf("\n\n");
1402
1403                 }
1404                 return rsp;
1405         }
1406
1407         return rsp;
1408
1409 }
1410
1411 struct pipeline_be_ops pipeline_loadb_be_ops = {
1412         .f_init = pipeline_loadb_init,
1413         .f_free = pipeline_loadb_free,
1414         .f_run = NULL,
1415         .f_timer = pipeline_loadb_timer,
1416         .f_track = pipeline_loadb_track,
1417 };