common: Adding common library for sample vnf 91/33491/1
authorVishwesh M Rudramuni <vishweshmr@gmail.com>
Tue, 18 Apr 2017 14:11:40 +0000 (19:41 +0530)
committerDeepak S <deepak.s@linux.intel.com>
Tue, 18 Apr 2017 09:59:07 +0000 (02:59 -0700)
JIRA: SAMPLEVNF-3

This patch adds common libraries required as part of the
sample vnf.

This includes the following libraries

 1. ACL library
 2. SIP
 3. FTP
 4. Connection tracker
 5. L2l3 stack
    - Interface Manager
    - ARP & ICMPv4
    - ND & ICMPv6
and other common libraries needed for ip pipeline framework

Change-Id: I117690b6b63fbcd76974cd7274518484e60980ab
Signed-off-by: Vishwesh M Rudramuni <vishwesh.m.rudramuni@intel.com>
[Push patch to gerrit]
Signed-off-by: Deepak S <deepak.s@linux.intel.com>
78 files changed:
common/VIL/acl/lib_acl.c [new file with mode: 0644]
common/VIL/acl/lib_acl.h [new file with mode: 0644]
common/VIL/alg/lib_ftp_alg.c [new file with mode: 0644]
common/VIL/alg/lib_ftp_alg.h [new file with mode: 0644]
common/VIL/alg/lib_sip_alg.c [new file with mode: 0644]
common/VIL/alg/lib_sip_alg.h [new file with mode: 0644]
common/VIL/conntrack/rte_cnxn_tracking.c [new file with mode: 0644]
common/VIL/conntrack/rte_cnxn_tracking.h [new file with mode: 0644]
common/VIL/conntrack/rte_ct_synproxy.c [new file with mode: 0644]
common/VIL/conntrack/rte_ct_tcp.c [new file with mode: 0644]
common/VIL/conntrack/rte_ct_tcp.h [new file with mode: 0644]
common/VIL/conntrack/rte_ct_udp.c [new file with mode: 0644]
common/VIL/l2l3_stack/Makefile [new file with mode: 0644]
common/VIL/l2l3_stack/bond.c [new file with mode: 0644]
common/VIL/l2l3_stack/build/.interface.o.d [new file with mode: 0644]
common/VIL/l2l3_stack/build/.l2_proto.o.d [new file with mode: 0644]
common/VIL/l2l3_stack/build/.main.o.d [new file with mode: 0644]
common/VIL/l2l3_stack/hle.c [new file with mode: 0644]
common/VIL/l2l3_stack/hle.h [new file with mode: 0644]
common/VIL/l2l3_stack/interface.c [new file with mode: 0644]
common/VIL/l2l3_stack/interface.h [new file with mode: 0644]
common/VIL/l2l3_stack/l2_proto.c [new file with mode: 0644]
common/VIL/l2l3_stack/l2_proto.h [new file with mode: 0644]
common/VIL/l2l3_stack/l3fwd_common.h [new file with mode: 0644]
common/VIL/l2l3_stack/l3fwd_lpm4.c [new file with mode: 0644]
common/VIL/l2l3_stack/l3fwd_lpm4.h [new file with mode: 0644]
common/VIL/l2l3_stack/l3fwd_lpm6.c [new file with mode: 0644]
common/VIL/l2l3_stack/l3fwd_lpm6.h [new file with mode: 0644]
common/VIL/l2l3_stack/l3fwd_main.c [new file with mode: 0644]
common/VIL/l2l3_stack/lib_arp.c [new file with mode: 0644]
common/VIL/l2l3_stack/lib_arp.h [new file with mode: 0644]
common/VIL/l2l3_stack/lib_icmpv6.c [new file with mode: 0644]
common/VIL/l2l3_stack/lib_icmpv6.h [new file with mode: 0644]
common/VIL/l2l3_stack/main_l2l3.c [new file with mode: 0644]
common/VIL/l2l3_stack/tsx.c [new file with mode: 0644]
common/VIL/l2l3_stack/tsx.h [new file with mode: 0644]
common/VIL/pipeline_arpicmp/pipeline_arpicmp.c [new file with mode: 0644]
common/VIL/pipeline_arpicmp/pipeline_arpicmp.h [new file with mode: 0644]
common/VIL/pipeline_arpicmp/pipeline_arpicmp_be.c [new file with mode: 0644]
common/VIL/pipeline_arpicmp/pipeline_arpicmp_be.h [new file with mode: 0644]
common/VIL/pipeline_common/pipeline_common_be.c [new file with mode: 0644]
common/VIL/pipeline_common/pipeline_common_be.h [new file with mode: 0644]
common/VIL/pipeline_common/pipeline_common_fe.c [new file with mode: 0644]
common/VIL/pipeline_common/pipeline_common_fe.h [new file with mode: 0644]
common/VIL/pipeline_loadb/pipeline_loadb.c [new file with mode: 0644]
common/VIL/pipeline_loadb/pipeline_loadb.h [new file with mode: 0644]
common/VIL/pipeline_loadb/pipeline_loadb_be.c [new file with mode: 0644]
common/VIL/pipeline_loadb/pipeline_loadb_be.h [new file with mode: 0644]
common/VIL/pipeline_master/pipeline_master.c [new file with mode: 0644]
common/VIL/pipeline_master/pipeline_master.h [new file with mode: 0644]
common/VIL/pipeline_master/pipeline_master_be.c [new file with mode: 0644]
common/VIL/pipeline_master/pipeline_master_be.h [new file with mode: 0644]
common/VIL/pipeline_passthrough/pipeline_passthrough.c [new file with mode: 0644]
common/VIL/pipeline_passthrough/pipeline_passthrough.h [new file with mode: 0644]
common/VIL/pipeline_passthrough/pipeline_passthrough_be.c [new file with mode: 0644]
common/VIL/pipeline_passthrough/pipeline_passthrough_be.h [new file with mode: 0644]
common/VIL/pipeline_txrx/pipeline_txrx.c [new file with mode: 0644]
common/VIL/pipeline_txrx/pipeline_txrx.h [new file with mode: 0644]
common/VIL/pipeline_txrx/pipeline_txrx_be.c [new file with mode: 0644]
common/VIL/pipeline_txrx/pipeline_txrx_be.h [new file with mode: 0644]
common/vnf_common/app.h [new file with mode: 0644]
common/vnf_common/config_check.c [new file with mode: 0644]
common/vnf_common/config_parse.c [new file with mode: 0644]
common/vnf_common/config_parse_tm.c [new file with mode: 0644]
common/vnf_common/cpu_core_map.c [new file with mode: 0644]
common/vnf_common/cpu_core_map.h [new file with mode: 0644]
common/vnf_common/hash_func.h [new file with mode: 0644]
common/vnf_common/parser.h [new file with mode: 0644]
common/vnf_common/pipeline.h [new file with mode: 0644]
common/vnf_common/pipeline_actions_common.h [new file with mode: 0644]
common/vnf_common/pipeline_be.h [new file with mode: 0644]
common/vnf_common/thread.c [new file with mode: 0644]
common/vnf_common/thread.h [new file with mode: 0644]
common/vnf_common/thread_fe.c [new file with mode: 0644]
common/vnf_common/thread_fe.h [new file with mode: 0644]
common/vnf_common/vnf_common.c [new file with mode: 0644]
common/vnf_common/vnf_common.h [new file with mode: 0644]
common/vnf_common/vnf_define.h [new file with mode: 0644]

diff --git a/common/VIL/acl/lib_acl.c b/common/VIL/acl/lib_acl.c
new file mode 100644 (file)
index 0000000..279727e
--- /dev/null
@@ -0,0 +1,1203 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include "lib_acl.h"
+#include "vnf_common.h"
+#include <rte_port.h>
+#define ACL_LIB_DEBUG 0
+static struct rte_acl_field_def field_format_ipv4[] = {
+       /* Protocol */
+       [0] = {
+                                .type = RTE_ACL_FIELD_TYPE_BITMASK,
+                                .size = sizeof(uint8_t),
+                                .field_index = 0,
+                                .input_index = 0,
+                                .offset = sizeof(struct ether_hdr) +
+                                offsetof(struct ipv4_hdr, next_proto_id),
+                                },
+
+       /* Source IP address (IPv4) */
+       [1] = {
+                                .type = RTE_ACL_FIELD_TYPE_MASK,
+                                .size = sizeof(uint32_t),
+                                .field_index = 1,
+                                .input_index = 1,
+                                .offset = sizeof(struct ether_hdr) +
+                                offsetof(struct ipv4_hdr, src_addr),
+                                },
+
+       /* Destination IP address (IPv4) */
+       [2] = {
+                                .type = RTE_ACL_FIELD_TYPE_MASK,
+                                .size = sizeof(uint32_t),
+                                .field_index = 2,
+                                .input_index = 2,
+                                .offset = sizeof(struct ether_hdr) +
+                                offsetof(struct ipv4_hdr, dst_addr),
+                                },
+
+       /* Source Port */
+       [3] = {
+                                .type = RTE_ACL_FIELD_TYPE_RANGE,
+                                .size = sizeof(uint16_t),
+                                .field_index = 3,
+                                .input_index = 3,
+                                .offset = sizeof(struct ether_hdr) +
+                                sizeof(struct ipv4_hdr) + offsetof(struct tcp_hdr, src_port),
+                                },
+
+       /* Destination Port */
+       [4] = {
+                                .type = RTE_ACL_FIELD_TYPE_RANGE,
+                                .size = sizeof(uint16_t),
+                                .field_index = 4,
+                                .input_index = 3,
+                                .offset = sizeof(struct ether_hdr) +
+                                sizeof(struct ipv4_hdr) + offsetof(struct tcp_hdr, dst_port),
+                                },
+};
+
+#define SIZEOF_VLAN_HDR                          4
+
+static struct rte_acl_field_def field_format_vlan_ipv4[] = {
+       /* Protocol */
+       [0] = {
+                                .type = RTE_ACL_FIELD_TYPE_BITMASK,
+                                .size = sizeof(uint8_t),
+                                .field_index = 0,
+                                .input_index = 0,
+                                .offset = sizeof(struct ether_hdr) +
+                                SIZEOF_VLAN_HDR + offsetof(struct ipv4_hdr, next_proto_id),
+                                },
+
+       /* Source IP address (IPv4) */
+       [1] = {
+                                .type = RTE_ACL_FIELD_TYPE_MASK,
+                                .size = sizeof(uint32_t),
+                                .field_index = 1,
+                                .input_index = 1,
+                                .offset = sizeof(struct ether_hdr) +
+                                SIZEOF_VLAN_HDR + offsetof(struct ipv4_hdr, src_addr),
+                                },
+
+       /* Destination IP address (IPv4) */
+       [2] = {
+                                .type = RTE_ACL_FIELD_TYPE_MASK,
+                                .size = sizeof(uint32_t),
+                                .field_index = 2,
+                                .input_index = 2,
+                                .offset = sizeof(struct ether_hdr) +
+                                SIZEOF_VLAN_HDR + offsetof(struct ipv4_hdr, dst_addr),
+                                },
+
+       /* Source Port */
+       [3] = {
+                                .type = RTE_ACL_FIELD_TYPE_RANGE,
+                                .size = sizeof(uint16_t),
+                                .field_index = 3,
+                                .input_index = 3,
+                                .offset = sizeof(struct ether_hdr) +
+                                SIZEOF_VLAN_HDR +
+                                sizeof(struct ipv4_hdr) + offsetof(struct tcp_hdr, src_port),
+                                },
+
+       /* Destination Port */
+       [4] = {
+                                .type = RTE_ACL_FIELD_TYPE_RANGE,
+                                .size = sizeof(uint16_t),
+                                .field_index = 4,
+                                .input_index = 4,
+                                .offset = sizeof(struct ether_hdr) +
+                                SIZEOF_VLAN_HDR +
+                                sizeof(struct ipv4_hdr) + offsetof(struct tcp_hdr, dst_port),
+                                },
+};
+
+#define SIZEOF_QINQ_HEADER                       8
+
+static struct rte_acl_field_def field_format_qinq_ipv4[] = {
+       /* Protocol */
+       [0] = {
+                                .type = RTE_ACL_FIELD_TYPE_BITMASK,
+                                .size = sizeof(uint8_t),
+                                .field_index = 0,
+                                .input_index = 0,
+                                .offset = sizeof(struct ether_hdr) +
+                                SIZEOF_QINQ_HEADER + offsetof(struct ipv4_hdr, next_proto_id),
+                                },
+
+       /* Source IP address (IPv4) */
+       [1] = {
+                                .type = RTE_ACL_FIELD_TYPE_MASK,
+                                .size = sizeof(uint32_t),
+                                .field_index = 1,
+                                .input_index = 1,
+                                .offset = sizeof(struct ether_hdr) +
+                                SIZEOF_QINQ_HEADER + offsetof(struct ipv4_hdr, src_addr),
+                                },
+
+       /* Destination IP address (IPv4) */
+       [2] = {
+                                .type = RTE_ACL_FIELD_TYPE_MASK,
+                                .size = sizeof(uint32_t),
+                                .field_index = 2,
+                                .input_index = 2,
+                                .offset = sizeof(struct ether_hdr) +
+                                SIZEOF_QINQ_HEADER + offsetof(struct ipv4_hdr, dst_addr),
+                                },
+
+       /* Source Port */
+       [3] = {
+                                .type = RTE_ACL_FIELD_TYPE_RANGE,
+                                .size = sizeof(uint16_t),
+                                .field_index = 3,
+                                .input_index = 3,
+                                .offset = sizeof(struct ether_hdr) +
+                                SIZEOF_QINQ_HEADER +
+                                sizeof(struct ipv4_hdr) + offsetof(struct tcp_hdr, src_port),
+                                },
+
+       /* Destination Port */
+       [4] = {
+                                .type = RTE_ACL_FIELD_TYPE_RANGE,
+                                .size = sizeof(uint16_t),
+                                .field_index = 4,
+                                .input_index = 4,
+                                .offset = sizeof(struct ether_hdr) +
+                                SIZEOF_QINQ_HEADER +
+                                sizeof(struct ipv4_hdr) + offsetof(struct tcp_hdr, dst_port),
+                                },
+};
+
+static struct rte_acl_field_def field_format_ipv6[] = {
+       /* Protocol */
+       [0] = {
+                                .type = RTE_ACL_FIELD_TYPE_BITMASK,
+                                .size = sizeof(uint8_t),
+                                .field_index = 0,
+                                .input_index = 0,
+                                .offset = sizeof(struct ether_hdr) +
+                                offsetof(struct ipv6_hdr, proto),
+                                },
+
+       /* Source IP address (IPv6) */
+       [1] = {
+                                .type = RTE_ACL_FIELD_TYPE_MASK,
+                                .size = sizeof(uint32_t),
+                                .field_index = 1,
+                                .input_index = 1,
+                                .offset = sizeof(struct ether_hdr) +
+                                offsetof(struct ipv6_hdr, src_addr),
+                                },
+
+       [2] = {
+                                .type = RTE_ACL_FIELD_TYPE_MASK,
+                                .size = sizeof(uint32_t),
+                                .field_index = 2,
+                                .input_index = 2,
+                                .offset = sizeof(struct ether_hdr) +
+                                offsetof(struct ipv6_hdr, src_addr) + sizeof(uint32_t),
+                                },
+
+       [3] = {
+                                .type = RTE_ACL_FIELD_TYPE_MASK,
+                                .size = sizeof(uint32_t),
+                                .field_index = 3,
+                                .input_index = 3,
+                                .offset = sizeof(struct ether_hdr) +
+                                offsetof(struct ipv6_hdr, src_addr) + 2 * sizeof(uint32_t),
+                                },
+
+       [4] = {
+                                .type = RTE_ACL_FIELD_TYPE_MASK,
+                                .size = sizeof(uint32_t),
+                                .field_index = 4,
+                                .input_index = 4,
+                                .offset = sizeof(struct ether_hdr) +
+                                offsetof(struct ipv6_hdr, src_addr) + 3 * sizeof(uint32_t),
+                                },
+
+       /* Destination IP address (IPv6) */
+       [5] = {
+                                .type = RTE_ACL_FIELD_TYPE_MASK,
+                                .size = sizeof(uint32_t),
+                                .field_index = 5,
+                                .input_index = 5,
+                                .offset = sizeof(struct ether_hdr) +
+                                offsetof(struct ipv6_hdr, dst_addr),
+                                },
+
+       [6] = {
+                                .type = RTE_ACL_FIELD_TYPE_MASK,
+                                .size = sizeof(uint32_t),
+                                .field_index = 6,
+                                .input_index = 6,
+                                .offset = sizeof(struct ether_hdr) +
+                                offsetof(struct ipv6_hdr, dst_addr) + sizeof(uint32_t),
+                                },
+
+       [7] = {
+                                .type = RTE_ACL_FIELD_TYPE_MASK,
+                                .size = sizeof(uint32_t),
+                                .field_index = 7,
+                                .input_index = 7,
+                                .offset = sizeof(struct ether_hdr) +
+                                offsetof(struct ipv6_hdr, dst_addr) + 2 * sizeof(uint32_t),
+                                },
+
+       [8] = {
+                                .type = RTE_ACL_FIELD_TYPE_MASK,
+                                .size = sizeof(uint32_t),
+                                .field_index = 8,
+                                .input_index = 8,
+                                .offset = sizeof(struct ether_hdr) +
+                                offsetof(struct ipv6_hdr, dst_addr) + 3 * sizeof(uint32_t),
+                                },
+
+       /* Source Port */
+       [9] = {
+                                .type = RTE_ACL_FIELD_TYPE_RANGE,
+                                .size = sizeof(uint16_t),
+                                .field_index = 9,
+                                .input_index = 9,
+                                .offset = sizeof(struct ether_hdr) +
+                                sizeof(struct ipv6_hdr) + offsetof(struct tcp_hdr, src_port),
+                                },
+
+       /* Destination Port */
+       [10] = {
+               .type = RTE_ACL_FIELD_TYPE_RANGE,
+               .size = sizeof(uint16_t),
+               .field_index = 10,
+               .input_index = 9,
+               .offset = sizeof(struct ether_hdr) +
+               sizeof(struct ipv6_hdr) + offsetof(struct tcp_hdr, dst_port),
+               },
+};
+
+void *lib_acl_create_active_standby_table_ipv4(uint8_t table_num,
+               uint32_t *libacl_n_rules)
+{
+       printf("Create LIBACL active IPV4 Tables rte_socket_id(): %i\n",
+                       rte_socket_id());
+
+       /* Create IPV4 LIBACL Rule Tables */
+       struct rte_table_acl_params common_ipv4_table_libacl_params = {
+               .name = "LIBACLIPV4A",
+               .n_rules = *libacl_n_rules,
+               .n_rule_fields = RTE_DIM(field_format_ipv4),
+       };
+
+       memcpy(common_ipv4_table_libacl_params.field_format,
+                       field_format_ipv4, sizeof(field_format_ipv4));
+
+       uint32_t ipv4_entry_size = sizeof(struct lib_acl_table_entry);
+       /* Create second IPV4 Table */
+       if (table_num == 2)
+               common_ipv4_table_libacl_params.name = "LIBACLIPV4B";
+       return  rte_table_acl_ops.f_create(&common_ipv4_table_libacl_params,
+                       rte_socket_id(),
+                       ipv4_entry_size);
+
+
+}
+
+void *lib_acl_create_active_standby_table_ipv6(uint8_t table_num,
+               uint32_t *libacl_n_rules)
+{
+       printf("Create LIBACL active IPV6 Tables rte_socket_id(): %i\n",
+                       rte_socket_id());
+       /* Create IPV6 LIBACL Rule Tables */
+       struct rte_table_acl_params common_ipv6_table_libacl_params = {
+               .name = "LIBACLIPV6A",
+               .n_rules = *libacl_n_rules,
+               .n_rule_fields = RTE_DIM(field_format_ipv6),
+       };
+
+       memcpy(common_ipv6_table_libacl_params.field_format,
+                       field_format_ipv6, sizeof(field_format_ipv6));
+
+       uint32_t ipv6_entry_size = sizeof(struct lib_acl_table_entry);
+       /* Create second IPV6 table */
+       if (table_num == 2)
+               common_ipv6_table_libacl_params.name = "LIBACLIPV6B";
+       return  rte_table_acl_ops.f_create(&common_ipv6_table_libacl_params,
+                       rte_socket_id(),
+                       ipv6_entry_size);
+
+
+}
+int lib_acl_parse_config(struct lib_acl *plib_acl,
+               char *arg_name, char *arg_value,
+               uint32_t *libacl_n_rules)
+{
+       uint32_t n_rules_present = 0;
+       uint32_t pkt_type_present = 0;
+       /* defaults */
+       plib_acl->n_rules = DEFULT_NUM_RULE;
+       *libacl_n_rules = DEFULT_NUM_RULE;
+       plib_acl->n_rule_fields = RTE_DIM(field_format_ipv4);
+       plib_acl->field_format = field_format_ipv4;
+       plib_acl->field_format_size = sizeof(field_format_ipv4);
+       if (strcmp(arg_name, "n_rules") == 0) {
+               if (n_rules_present) {
+                       printf("n_rules_present");
+                       return -1;
+               }
+               n_rules_present = 1;
+
+               plib_acl->n_rules = atoi(arg_value);
+               *libacl_n_rules = atoi(arg_value);
+               return 0;
+       }
+       if (strcmp(arg_name, "pkt_type") == 0) {
+               if (pkt_type_present) {
+                       printf("pkt_type");
+                       return -1;
+               }
+               pkt_type_present = 1;
+
+               /* ipv4 */
+               if (strcmp(arg_value, "ipv4") == 0) {
+                       plib_acl->n_rule_fields =
+                               RTE_DIM(field_format_ipv4);
+                       plib_acl->field_format = field_format_ipv4;
+                       plib_acl->field_format_size =
+                               sizeof(field_format_ipv4);
+                       return 0;
+               }
+
+               /* vlan_ipv4 */
+               if (strcmp(arg_value, "vlan_ipv4") == 0) {
+                       plib_acl->n_rule_fields =
+                               RTE_DIM(field_format_vlan_ipv4);
+                       plib_acl->field_format =
+                               field_format_vlan_ipv4;
+                       plib_acl->field_format_size =
+                               sizeof(field_format_vlan_ipv4);
+                       return 0;
+               }
+
+               /* qinq_ipv4 */
+               if (strcmp(arg_value, "qinq_ipv4") == 0) {
+                       plib_acl->n_rule_fields =
+                               RTE_DIM(field_format_qinq_ipv4);
+                       plib_acl->field_format =
+                               field_format_qinq_ipv4;
+                       plib_acl->field_format_size =
+                               sizeof(field_format_qinq_ipv4);
+                       return 0;
+               }
+
+               /* ipv6 */
+               if (strcmp(arg_value, "ipv6") == 0) {
+                       plib_acl->n_rule_fields =
+                               RTE_DIM(field_format_ipv6);
+                       plib_acl->field_format = field_format_ipv6;
+                       plib_acl->field_format_size =
+                               sizeof(field_format_ipv6);
+                       return 0;
+               }
+               /* other */
+               printf("other");
+               return -1;
+       }
+       /* Parameter not processed in this parse function */
+       return 1;
+}
+/**
+ * Main packet processing function.
+ * 64 packet bit mask are used to identify which packets to forward.
+ * Performs the following:
+ *  - Burst lookup packets in the IPv4 ACL Rule Table.
+ *  - Burst lookup packets in the IPv6 ACL Rule Table.
+ *  - Lookup Action Table, perform actions.
+ *  - Burst lookup Connection Tracking, if enabled.
+ *  - Lookup MAC address.
+ *  - Set bit mask.
+ *  - Packets with bit mask set are forwarded
+ *
+ * @param p
+ *  A pointer to the pipeline.
+ * @param pkts
+ *  A pointer to a burst of packets.
+ * @param n_pkts
+ *  Number of packets to process.
+ * @param arg
+ *  A pointer to pipeline specific data.
+ *
+ * @return
+ *  0 on success, negative on error.
+ */
+       uint64_t
+lib_acl_pkt_work_key(struct lib_acl *plib_acl,
+       struct rte_mbuf **pkts, uint64_t pkts_mask,
+       uint64_t *pkts_drop_without_rule,
+       void *plib_acl_rule_table_ipv4_active,
+       void *plib_acl_rule_table_ipv6_active,
+       struct pipeline_action_key *action_array_active,
+       struct action_counter_block (*p_action_counter_table)[action_array_max],
+       uint64_t *conntrack_mask,
+       uint64_t *connexist_mask,
+       int lib_acl_ipv4_enabled, int lib_acl_ipv6_enabled)
+{
+
+       uint64_t lookup_hit_mask = 0;
+       uint64_t lookup_hit_mask_ipv4 = 0;
+       uint64_t lookup_hit_mask_ipv6 = 0;
+       uint64_t lookup_miss_mask = 0;
+       int status;
+
+
+       if (lib_acl_ipv4_enabled) {
+               if (ACL_LIB_DEBUG)
+                       printf("ACL IPV4 Lookup Mask Before = 0x%"PRIx64"\n",
+                                       pkts_mask);
+               status = rte_table_acl_ops.f_lookup(
+                               plib_acl_rule_table_ipv4_active,
+                               pkts, pkts_mask, &lookup_hit_mask_ipv4,
+                               (void **) plib_acl->plib_acl_entries_ipv4);
+               if (status < 0)
+                       printf("Lookup failed\n");
+               if (ACL_LIB_DEBUG)
+                       printf("ACL IPV4 Lookup Mask After = 0x%"PRIx64"\n",
+                                       lookup_hit_mask_ipv4);
+       }
+
+       if (lib_acl_ipv6_enabled) {
+               if (ACL_LIB_DEBUG)
+                       printf("ACL IPV6 Lookup Mask Before = 0x%"PRIx64"\n",
+                                       pkts_mask);
+               status = rte_table_acl_ops.f_lookup(
+                               plib_acl_rule_table_ipv6_active,
+                               pkts, pkts_mask, &lookup_hit_mask_ipv6,
+                               (void **) plib_acl->plib_acl_entries_ipv6);
+               if (status < 0)
+                       printf("Lookup Failed\n");
+               if (ACL_LIB_DEBUG)
+                       printf("ACL IPV6 Lookup Mask After = 0x%"PRIx64"\n",
+                                       lookup_hit_mask_ipv6);
+       }
+
+       /* Merge lookup results since we process both IPv4 and IPv6 below */
+       lookup_hit_mask = lookup_hit_mask_ipv4 | lookup_hit_mask_ipv6;
+       if (ACL_LIB_DEBUG)
+               printf("ACL Lookup Mask After = 0x%"PRIx64"\n",
+                               lookup_hit_mask);
+
+       lookup_miss_mask = pkts_mask & (~lookup_hit_mask);
+       pkts_mask = lookup_hit_mask;
+       *pkts_drop_without_rule += __builtin_popcountll(lookup_miss_mask);
+       if (ACL_LIB_DEBUG)
+               printf("pkt_work_acl_key pkts_drop: %" PRIu64 " n_pkts: %u\n",
+                               *pkts_drop_without_rule,
+                               __builtin_popcountll(lookup_miss_mask));
+       /* bitmap of packets left to process for ARP */
+       uint64_t pkts_to_process = lookup_hit_mask;
+
+       for (; pkts_to_process;) {
+               uint8_t pos = (uint8_t)__builtin_ctzll(pkts_to_process);
+               /* bitmask representing only this packet */
+               uint64_t pkt_mask = 1LLU << pos;
+               /* remove this packet from remaining list */
+               pkts_to_process &= ~pkt_mask;
+               struct rte_mbuf *pkt = pkts[pos];
+
+               uint8_t hdr_chk = RTE_MBUF_METADATA_UINT8(pkt, IP_START);
+
+               hdr_chk = hdr_chk >> IP_VERSION_CHECK;
+
+               if (hdr_chk == IPv4_HDR_VERSION) {
+
+                       struct lib_acl_table_entry *entry =
+                               (struct lib_acl_table_entry *)
+                               plib_acl->plib_acl_entries_ipv4[pos];
+                       uint16_t phy_port = entry->head.port_id;
+                       uint32_t action_id = entry->action_id;
+
+                       if (ACL_LIB_DEBUG)
+                               printf("action_id = %u\n", action_id);
+
+                       uint32_t dscp_offset = IP_START + IP_HDR_DSCP_OFST;
+
+                       if (action_array_active[action_id].action_bitmap &
+                                       lib_acl_action_count) {
+                               p_action_counter_table
+                                       [plib_acl->action_counter_index]
+                                       [action_id].packetCount++;
+                               p_action_counter_table
+                                       [plib_acl->action_counter_index]
+                                       [action_id].byteCount +=
+                                       rte_pktmbuf_pkt_len(pkt);
+                               if (ACL_LIB_DEBUG)
+                                       printf("Action Count   Packet Count: %"
+                                               PRIu64 "  Byte Count: %"
+                                               PRIu64 "\n"
+                                               , p_action_counter_table
+                                               [plib_acl->action_counter_index]
+                                               [action_id].packetCount,
+                                               p_action_counter_table
+                                               [plib_acl->action_counter_index]
+                                               [action_id].byteCount);
+                       }
+
+                       if (action_array_active[action_id].action_bitmap &
+                                       lib_acl_action_packet_drop) {
+
+                               /* Drop packet by changing the mask */
+                               if (ACL_LIB_DEBUG)
+                                       printf("ACL before drop pkt_mask %"
+                                                       PRIx64", pkt_num %d\n",
+                                                       pkts_mask, pos);
+                               pkts_mask &= ~(1LLU << pos);
+                               (*pkts_drop_without_rule)++;
+                               if (ACL_LIB_DEBUG)
+                                       printf("ACL after drop pkt_mask %"PRIx64
+                                               ", pkt_num %d, packet_drop%"
+                                               PRIu64"\n", pkts_mask, pos,
+                                               *pkts_drop_without_rule);
+                       }
+
+                       if (action_array_active[action_id].action_bitmap &
+                                       lib_acl_action_fwd) {
+                               phy_port = action_array_active[action_id].
+                                       fwd_port;
+                               entry->head.port_id = phy_port;
+                               if (ACL_LIB_DEBUG)
+                                       printf("Action FWD  Port ID: %"
+                                                       PRIu16"\n", phy_port);
+                       }
+
+                       if (action_array_active[action_id].action_bitmap &
+                                       lib_acl_action_nat) {
+                               phy_port = action_array_active[action_id].
+                                       nat_port;
+                               entry->head.port_id = phy_port;
+                               if (ACL_LIB_DEBUG)
+                                       printf("Action NAT  Port ID: %"
+                                                       PRIu16"\n", phy_port);
+                       }
+
+                       if (action_array_active[action_id].action_bitmap &
+                                       lib_acl_action_dscp) {
+
+                               /* Set DSCP priority */
+                               uint8_t *dscp = RTE_MBUF_METADATA_UINT8_PTR(pkt,
+                                               dscp_offset);
+                               *dscp = action_array_active[action_id].
+                                       dscp_priority << 2;
+                               if (ACL_LIB_DEBUG)
+                                       printf("Action DSCP   DSCP Priority: %"
+                                                       PRIu16 "\n", *dscp);
+                       }
+
+                       if (action_array_active[action_id].action_bitmap &
+                                       lib_acl_action_packet_accept) {
+                               if (ACL_LIB_DEBUG)
+                                       printf("Action Accept\n");
+
+                               if (action_array_active[action_id].action_bitmap
+                                               & lib_acl_action_conntrack) {
+
+                                       /* Set conntrack bit for this pkt */
+                                       *conntrack_mask |= pkt_mask;
+                                       if (ACL_LIB_DEBUG)
+                                               printf("ACL CT enabled: 0x%"
+                                                       PRIx64"  pkt_mask: 0x%"
+                                                       PRIx64"\n",
+                                                       *conntrack_mask,
+                                                       pkt_mask);
+                       }
+
+                               if (action_array_active[action_id].action_bitmap
+                                               & lib_acl_action_connexist) {
+
+                                       /* Set conntrack bit for this pkt */
+                                       *conntrack_mask |= pkt_mask;
+
+                                       /* Set connexist bit for this pkt for
+                                        * public -> private */
+                                       /* Private -> public packet will open
+                                        * the connection */
+                                       if (action_array_active[action_id].
+                                                       private_public ==
+                                                       lib_acl_public_private)
+                                               *connexist_mask |= pkt_mask;
+
+                                       if (ACL_LIB_DEBUG)
+                                               printf("Connexist ENB CT:0x%"
+                                                       PRIx64"  connexist: 0x%"
+                                                       PRIx64"  pkt_mask: 0x%"
+                                                       PRIx64"\n",
+                                                       *conntrack_mask,
+                                                       *connexist_mask,
+                                                       pkt_mask);
+                               }
+                       }
+               }
+
+               if (hdr_chk == IPv6_HDR_VERSION) {
+
+                       struct lib_acl_table_entry *entry =
+                               (struct lib_acl_table_entry *)
+                               plib_acl->plib_acl_entries_ipv6[pos];
+                       uint16_t phy_port = entry->head.port_id;
+                       uint32_t action_id = entry->action_id;
+
+                       if (ACL_LIB_DEBUG)
+                               printf("action_id = %u\n", action_id);
+
+                       if (action_array_active[action_id].action_bitmap &
+                                       lib_acl_action_count) {
+                               p_action_counter_table
+                                       [plib_acl->action_counter_index]
+                                       [action_id].packetCount++;
+                               p_action_counter_table
+                                       [plib_acl->action_counter_index]
+                                       [action_id].byteCount +=
+                                       rte_pktmbuf_pkt_len(pkt);
+                               if (ACL_LIB_DEBUG)
+                                       printf("Action Count   Packet Count: %"
+                                               PRIu64 "  Byte Count: %"
+                                               PRIu64 "\n",
+                                               p_action_counter_table
+                                               [plib_acl->action_counter_index]
+                                               [action_id].packetCount,
+                                               p_action_counter_table
+                                               [plib_acl->action_counter_index]
+                                               [action_id].byteCount);
+                       }
+
+                       if (action_array_active[action_id].action_bitmap &
+                                       lib_acl_action_packet_drop) {
+                               /* Drop packet by changing the mask */
+                               if (ACL_LIB_DEBUG)
+                                       printf("ACL before drop pkt_mask %"
+                                                       PRIx64", pkt_num %d\n",
+                                                       pkts_mask, pos);
+                               pkts_mask &= ~(1LLU << pos);
+                               (*pkts_drop_without_rule)++;
+                               if (ACL_LIB_DEBUG)
+                                       printf("ACL after drop pkt_mask %"PRIx64
+                                               ", pkt_num %d, packet_drop %"
+                                               PRIu64 "\n", pkts_mask, pos,
+                                               *pkts_drop_without_rule);
+
+                       }
+
+                       if (action_array_active[action_id].action_bitmap &
+                                       lib_acl_action_fwd) {
+                               phy_port = action_array_active[action_id].
+                                       fwd_port;
+                               entry->head.port_id = phy_port;
+                               if (ACL_LIB_DEBUG)
+                                       printf("Action FWD  Port ID: %"
+                                                       PRIu16"\n", phy_port);
+                       }
+
+                       if (action_array_active[action_id].action_bitmap &
+                                       lib_acl_action_nat) {
+                               phy_port = action_array_active[action_id].
+                                       nat_port;
+                               entry->head.port_id = phy_port;
+                               if (ACL_LIB_DEBUG)
+                                       printf("Action NAT  Port ID: %"
+                                                       PRIu16"\n", phy_port);
+                       }
+
+                       if (action_array_active[action_id].action_bitmap &
+                                       lib_acl_action_dscp) {
+
+                               /* Set DSCP priority */
+                               uint32_t dscp_offset = IP_START +
+                                       IP_HDR_DSCP_OFST_IPV6;
+                               uint16_t *dscp = RTE_MBUF_METADATA_UINT16_PTR(
+                                               pkt, dscp_offset);
+                               uint16_t temp = *dscp;
+                               uint16_t dscp_value = (rte_bswap16(temp) &
+                                               0XF00F);
+                               uint8_t dscp_store =
+                                       action_array_active
+                                       [action_id].dscp_priority << 2;
+                               uint16_t dscp_temp = dscp_store;
+
+                               dscp_temp = dscp_temp << 4;
+                               *dscp = rte_bswap16(dscp_temp | dscp_value);
+                               if (ACL_LIB_DEBUG)
+                                       printf("Action DSCP   DSCP Priority: %"
+                                                       PRIu16"\n", *dscp);
+                       }
+
+                       if (action_array_active[action_id].action_bitmap
+                                       & lib_acl_action_packet_accept) {
+                               if (ACL_LIB_DEBUG)
+                                       printf("Action Accept\n");
+
+                               if (action_array_active[action_id].action_bitmap
+                                               & lib_acl_action_conntrack) {
+
+                                       /* Set conntrack bit for this pkt */
+                                       *conntrack_mask |= pkt_mask;
+                                       if (ACL_LIB_DEBUG)
+                                               printf("ACL CT enabled: 0x%"
+                                                       PRIx64" pkt_mask: 0x%"
+                                                       PRIx64"\n",
+                                                       *conntrack_mask,
+                                                       pkt_mask);
+                               }
+
+                               if (action_array_active[action_id].action_bitmap
+                                               & lib_acl_action_connexist) {
+
+                                       /* Set conntrack bit for this pkt */
+                                       *conntrack_mask |= pkt_mask;
+
+                                       /* Set connexist bit for this pkt for
+                                        * public -> private */
+                                       /* Private -> public packet will open
+                                        * the connection */
+                                       if (action_array_active[action_id].
+                                                       private_public ==
+                                                       lib_acl_public_private)
+                                               *connexist_mask |= pkt_mask;
+
+                                       if (ACL_LIB_DEBUG)
+                                               printf("Connexist ENB CT:0x%"
+                                                       PRIx64"  connexist: 0x%"
+                                                       PRIx64"  pkt_mask: 0x%"
+                                                       PRIx64"\n",
+                                                       *conntrack_mask,
+                                                       *connexist_mask,
+                                                       pkt_mask);
+                               }
+                       }
+               }
+       }
+       return pkts_mask;
+}
+/**
+ * Main packet processing function.
+ * 64 packet bit mask are used to identify which packets to forward.
+ * Performs the following:
+ *  - Burst lookup packets in the IPv4 ACL Rule Table.
+ *  - Lookup Action Table, perform actions.
+ *  - Burst lookup Connection Tracking, if enabled.
+ *  - Lookup MAC address.
+ *  - Set bit mask.
+ *  - Packets with bit mask set are forwarded
+ *
+ * @param p
+ *  A pointer to the pipeline.
+ * @param pkts
+ *  A pointer to a burst of packets.
+ * @param n_pkts
+ *  Number of packets to process.
+ * @param arg
+ *  A pointer to pipeline specific data.
+ *
+ * @return
+ *  0 on success, negative on error.
+ */
+       uint64_t
+lib_acl_ipv4_pkt_work_key(struct lib_acl *plib_acl,
+       struct rte_mbuf **pkts, uint64_t pkts_mask,
+       uint64_t *pkts_drop_without_rule,
+       void *plib_acl_rule_table_ipv4_active,
+       struct pipeline_action_key *action_array_active,
+       struct action_counter_block (*p_action_counter_table)[action_array_max],
+       uint64_t *conntrack_mask,
+       uint64_t *connexist_mask)
+{
+
+       uint64_t lookup_hit_mask_ipv4 = 0;
+       uint64_t lookup_miss_mask_ipv4 = 0;
+       int status;
+
+       if (ACL_LIB_DEBUG)
+               printf("ACL IPV4 Lookup Mask Before = 0x%"PRIx64"\n",
+                               pkts_mask);
+       status = rte_table_acl_ops.f_lookup(
+                       plib_acl_rule_table_ipv4_active,
+                       pkts, pkts_mask, &lookup_hit_mask_ipv4,
+                       (void **) plib_acl->plib_acl_entries_ipv4);
+       if (status < 0)
+               printf("Lookup Failed\n");
+       if (ACL_LIB_DEBUG)
+               printf("ACL IPV4 Lookup Mask After = 0x%"PRIx64"\n",
+                               lookup_hit_mask_ipv4);
+       if (ACL_LIB_DEBUG)
+               printf("ACL Lookup Mask After = 0x%"PRIx64"\n",
+                               lookup_hit_mask_ipv4);
+
+       lookup_miss_mask_ipv4 = pkts_mask & (~lookup_hit_mask_ipv4);
+       pkts_mask = lookup_hit_mask_ipv4;
+       *pkts_drop_without_rule += __builtin_popcountll(lookup_miss_mask_ipv4);
+       if (ACL_LIB_DEBUG)
+               printf("pkt_work_acl_key pkts_drop: %" PRIu64 " n_pkts: %u\n",
+                               *pkts_drop_without_rule,
+                               __builtin_popcountll(lookup_miss_mask_ipv4));
+       /* bitmap of packets left to process for ARP */
+       uint64_t pkts_to_process = lookup_hit_mask_ipv4;
+
+       for (; pkts_to_process;) {
+               uint8_t pos = (uint8_t)__builtin_ctzll(pkts_to_process);
+               /* bitmask representing only this packet */
+               uint64_t pkt_mask = 1LLU << pos;
+               /* remove this packet from remaining list */
+               pkts_to_process &= ~pkt_mask;
+               struct rte_mbuf *pkt = pkts[pos];
+
+
+
+               struct lib_acl_table_entry *entry =
+                       (struct lib_acl_table_entry *)
+                       plib_acl->plib_acl_entries_ipv4[pos];
+               uint16_t phy_port = entry->head.port_id;
+               uint32_t action_id = entry->action_id;
+
+               if (ACL_LIB_DEBUG)
+                       printf("action_id = %u\n", action_id);
+
+               uint32_t dscp_offset = IP_START + IP_HDR_DSCP_OFST;
+
+               if (action_array_active[action_id].action_bitmap &
+                               lib_acl_action_count) {
+                       p_action_counter_table
+                               [plib_acl->action_counter_index]
+                               [action_id].packetCount++;
+                       p_action_counter_table
+                               [plib_acl->action_counter_index]
+                               [action_id].byteCount +=
+                               rte_pktmbuf_pkt_len(pkt);
+                       if (ACL_LIB_DEBUG)
+                               printf("Action Count   Packet Count: %"
+                                               PRIu64 "  Byte Count: %"
+                                               PRIu64 "\n"
+                                               , p_action_counter_table
+                                               [plib_acl->action_counter_index]
+                                               [action_id].packetCount,
+                                               p_action_counter_table
+                                               [plib_acl->action_counter_index]
+                                               [action_id].byteCount);
+               }
+
+               if (action_array_active[action_id].action_bitmap &
+                               lib_acl_action_packet_drop) {
+
+                       /* Drop packet by changing the mask */
+                       if (ACL_LIB_DEBUG)
+                               printf("ACL before drop pkt_mask %"
+                                               PRIx64", pkt_num %d\n",
+                                               pkts_mask, pos);
+                       pkts_mask &= ~(1LLU << pos);
+                       (*pkts_drop_without_rule)++;
+                       if (ACL_LIB_DEBUG)
+                               printf("ACL after drop pkt_mask %" PRIx64
+                                       ", pkt_num %d, action_packet_drop %"
+                                       PRIu64 "\n", pkts_mask, pos,
+                                       *pkts_drop_without_rule);
+               }
+
+               if (action_array_active[action_id].action_bitmap &
+                               lib_acl_action_fwd) {
+                       phy_port = action_array_active[action_id].
+                               fwd_port;
+                       entry->head.port_id = phy_port;
+                       if (ACL_LIB_DEBUG)
+                               printf("Action FWD  Port ID: %"
+                                               PRIu16"\n", phy_port);
+               }
+
+               if (action_array_active[action_id].action_bitmap &
+                               lib_acl_action_nat) {
+                       phy_port = action_array_active[action_id].
+                               nat_port;
+                       entry->head.port_id = phy_port;
+                       if (ACL_LIB_DEBUG)
+                               printf("Action NAT  Port ID: %"
+                                               PRIu16"\n", phy_port);
+               }
+
+               if (action_array_active[action_id].action_bitmap &
+                               lib_acl_action_dscp) {
+
+                       /* Set DSCP priority */
+                       uint8_t *dscp = RTE_MBUF_METADATA_UINT8_PTR(pkt,
+                                       dscp_offset);
+                       *dscp = action_array_active[action_id].
+                               dscp_priority << 2;
+                       if (ACL_LIB_DEBUG)
+                               printf("Action DSCP   DSCP Priority: %"
+                                               PRIu16 "\n", *dscp);
+               }
+
+               if (action_array_active[action_id].action_bitmap &
+                               lib_acl_action_packet_accept) {
+                       if (ACL_LIB_DEBUG)
+                               printf("Action Accept\n");
+
+                       if (action_array_active[action_id].action_bitmap
+                                       & lib_acl_action_conntrack) {
+
+                               /* Set conntrack bit for this pkt */
+                               *conntrack_mask |= pkt_mask;
+                               if (ACL_LIB_DEBUG)
+                                       printf("ACL CT enabled: 0x%"
+                                                       PRIx64"  pkt_mask: 0x%"
+                                                       PRIx64"\n",
+                                                       *conntrack_mask,
+                                                       pkt_mask);
+                       }
+
+                       if (action_array_active[action_id].action_bitmap
+                                       & lib_acl_action_connexist) {
+
+                               /* Set conntrack bit for this pkt */
+                               *conntrack_mask |= pkt_mask;
+
+                               /* Set connexist bit for this pkt for
+                                * public -> private */
+                               /* Private -> public packet will open
+                                * the connection */
+                               if (action_array_active[action_id].
+                                               private_public ==
+                                               lib_acl_public_private)
+                                       *connexist_mask |= pkt_mask;
+
+                               if (ACL_LIB_DEBUG)
+                                       printf("ACL Connexist ENB CT:0x%"
+                                                       PRIx64"  connexist: 0x%"
+                                                       PRIx64"  pkt_mask: 0x%"
+                                                       PRIx64"\n",
+                                                       *conntrack_mask,
+                                                       *connexist_mask,
+                                                       pkt_mask);
+                       }
+               }
+
+       }
+       return pkts_mask;
+}
+/**
+ * Main packet processing function.
+ * 64 packet bit mask are used to identify which packets to forward.
+ * Performs the following:
+ *  - Burst lookup packets in the IPv6 ACL Rule Table.
+ *  - Lookup Action Table, perform actions.
+ *  - Burst lookup Connection Tracking, if enabled.
+ *  - Lookup MAC address.
+ *  - Set bit mask.
+ *  - Packets with bit mask set are forwarded
+ *
+ * @param p
+ *  A pointer to the pipeline.
+ * @param pkts
+ *  A pointer to a burst of packets.
+ * @param n_pkts
+ *  Number of packets to process.
+ * @param arg
+ *  A pointer to pipeline specific data.
+ *
+ * @return
+ *  0 on success, negative on error.
+ */
+       uint64_t
+lib_acl_ipv6_pkt_work_key(struct lib_acl *plib_acl,
+       struct rte_mbuf **pkts, uint64_t pkts_mask,
+       uint64_t *pkts_drop_without_rule,
+       void *plib_acl_rule_table_ipv6_active,
+       struct pipeline_action_key *action_array_active,
+       struct action_counter_block (*p_action_counter_table)[action_array_max],
+       uint64_t *conntrack_mask,
+       uint64_t *connexist_mask)
+{
+
+       uint64_t lookup_hit_mask_ipv6 = 0;
+       uint64_t lookup_miss_mask_ipv6 = 0;
+       int status;
+
+
+       if (ACL_LIB_DEBUG)
+               printf("ACL IPV6 Lookup Mask Before = 0x%"PRIx64"\n",
+                               pkts_mask);
+       status = rte_table_acl_ops.f_lookup(
+                       plib_acl_rule_table_ipv6_active,
+                       pkts, pkts_mask, &lookup_hit_mask_ipv6,
+                       (void **) plib_acl->plib_acl_entries_ipv6);
+       if (status < 0)
+               printf("Lookup Failed\n");
+       if (ACL_LIB_DEBUG)
+               printf("ACL IPV6 Lookup Mask After = 0x%"PRIx64"\n",
+                               lookup_hit_mask_ipv6);
+
+       if (ACL_LIB_DEBUG)
+               printf("ACL Lookup Mask After = 0x%"PRIx64"\n",
+                               lookup_hit_mask_ipv6);
+
+       lookup_miss_mask_ipv6 = pkts_mask & (~lookup_hit_mask_ipv6);
+       pkts_mask = lookup_hit_mask_ipv6;
+       *pkts_drop_without_rule += __builtin_popcountll(lookup_miss_mask_ipv6);
+       if (ACL_LIB_DEBUG)
+               printf("pkt_work_acl_key pkts_drop: %" PRIu64 " n_pkts: %u\n",
+                               *pkts_drop_without_rule,
+                               __builtin_popcountll(lookup_miss_mask_ipv6));
+       /* bitmap of packets left to process for ARP */
+       uint64_t pkts_to_process = lookup_hit_mask_ipv6;
+
+       for (; pkts_to_process;) {
+               uint8_t pos = (uint8_t)__builtin_ctzll(pkts_to_process);
+               /* bitmask representing only this packet */
+               uint64_t pkt_mask = 1LLU << pos;
+               /* remove this packet from remaining list */
+               pkts_to_process &= ~pkt_mask;
+               struct rte_mbuf *pkt = pkts[pos];
+
+
+               struct lib_acl_table_entry *entry =
+                       (struct lib_acl_table_entry *)
+                       plib_acl->plib_acl_entries_ipv6[pos];
+               uint16_t phy_port = entry->head.port_id;
+               uint32_t action_id = entry->action_id;
+
+               if (ACL_LIB_DEBUG)
+                       printf("action_id = %u\n", action_id);
+
+               if (action_array_active[action_id].action_bitmap &
+                               lib_acl_action_count) {
+                       p_action_counter_table
+                               [plib_acl->action_counter_index]
+                               [action_id].packetCount++;
+                       p_action_counter_table
+                               [plib_acl->action_counter_index]
+                               [action_id].byteCount +=
+                               rte_pktmbuf_pkt_len(pkt);
+                       if (ACL_LIB_DEBUG)
+                               printf("Action Count   Packet Count: %"
+                                               PRIu64 "  Byte Count: %"
+                                               PRIu64 "\n",
+                                               p_action_counter_table
+                                               [plib_acl->action_counter_index]
+                                               [action_id].packetCount,
+                                               p_action_counter_table
+                                               [plib_acl->action_counter_index]
+                                               [action_id].byteCount);
+               }
+
+               if (action_array_active[action_id].action_bitmap &
+                               lib_acl_action_packet_drop) {
+                       /* Drop packet by changing the mask */
+                       if (ACL_LIB_DEBUG)
+                               printf("ACL before drop pkt_mask %"
+                                               PRIx64", pkt_num %d\n",
+                                               pkts_mask, pos);
+                       pkts_mask &= ~(1LLU << pos);
+                       (*pkts_drop_without_rule)++;
+                       if (ACL_LIB_DEBUG)
+                               printf("ACL after drop pkt_mask %" PRIx64
+                                       ", pkt_num %d, action_packet_drop %"
+                                       PRIu64 "\n", pkts_mask, pos,
+                                       *pkts_drop_without_rule);
+
+               }
+
+               if (action_array_active[action_id].action_bitmap &
+                               lib_acl_action_fwd) {
+                       phy_port = action_array_active[action_id].
+                               fwd_port;
+                       entry->head.port_id = phy_port;
+                       if (ACL_LIB_DEBUG)
+                               printf("Action FWD  Port ID: %"
+                                               PRIu16"\n", phy_port);
+               }
+
+               if (action_array_active[action_id].action_bitmap &
+                               lib_acl_action_nat) {
+                       phy_port = action_array_active[action_id].
+                               nat_port;
+                       entry->head.port_id = phy_port;
+                       if (ACL_LIB_DEBUG)
+                               printf("Action NAT  Port ID: %"
+                                               PRIu16"\n", phy_port);
+               }
+
+               if (action_array_active[action_id].action_bitmap &
+                               lib_acl_action_dscp) {
+
+                       /* Set DSCP priority */
+                       uint32_t dscp_offset = IP_START +
+                               IP_HDR_DSCP_OFST_IPV6;
+                       uint16_t *dscp = RTE_MBUF_METADATA_UINT16_PTR(
+                                       pkt, dscp_offset);
+                       uint16_t temp = *dscp;
+                       uint16_t dscp_value = (rte_bswap16(temp) &
+                                       0XF00F);
+                       uint8_t dscp_store =
+                               action_array_active
+                               [action_id].dscp_priority << 2;
+                       uint16_t dscp_temp = dscp_store;
+
+                       dscp_temp = dscp_temp << 4;
+                       *dscp = rte_bswap16(dscp_temp | dscp_value);
+                       if (ACL_LIB_DEBUG)
+                               printf("Action DSCP   DSCP Priority: %"
+                                               PRIu16"\n", *dscp);
+               }
+
+               if (action_array_active[action_id].action_bitmap
+                               & lib_acl_action_packet_accept) {
+                       if (ACL_LIB_DEBUG)
+                               printf("Action Accept\n");
+
+                       if (action_array_active[action_id].action_bitmap
+                                       & lib_acl_action_conntrack) {
+
+                               /* Set conntrack bit for this pkt */
+                               *conntrack_mask |= pkt_mask;
+                               if (ACL_LIB_DEBUG)
+                                       printf("ACL CT enabled: 0x%"
+                                                       PRIx64" pkt_mask: 0x%"
+                                                       PRIx64"\n",
+                                                       *conntrack_mask,
+                                                       pkt_mask);
+                       }
+
+                       if (action_array_active[action_id].action_bitmap
+                                       & lib_acl_action_connexist) {
+
+                               /* Set conntrack bit for this pkt */
+                               *conntrack_mask |= pkt_mask;
+
+                               /* Set connexist bit for this pkt for
+                                * public -> private */
+                               /* Private -> public packet will open
+                                * the connection */
+                               if (action_array_active[action_id].
+                                               private_public ==
+                                               lib_acl_public_private)
+                                       *connexist_mask |= pkt_mask;
+
+                               if (ACL_LIB_DEBUG)
+                                       printf("ACL Connexist ENB CT:0x%"
+                                                       PRIx64"  connexist: 0x%"
+                                                       PRIx64"  pkt_mask: 0x%"
+                                                       PRIx64"\n",
+                                                       *conntrack_mask,
+                                                       *connexist_mask,
+                                                       pkt_mask);
+                       }
+               }
+       }
+       return pkts_mask;
+}
diff --git a/common/VIL/acl/lib_acl.h b/common/VIL/acl/lib_acl.h
new file mode 100644 (file)
index 0000000..6eaaf55
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef __INCLUDE_ACL_LIB_H__
+#define __INCLUDE_ACL_LIB_H__
+
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <rte_pipeline.h>
+#include <rte_table_acl.h>
+#include "rte_cnxn_tracking.h"
+#include "rte_ct_tcp.h"
+/* Define VNF actions for bitmap */
+#define lib_acl_action_packet_drop             1
+#define lib_acl_action_packet_accept   2
+#define lib_acl_action_nat                             4
+#define lib_acl_action_fwd                             8
+#define lib_acl_action_count                   16
+#define lib_acl_action_dscp                            32
+#define lib_acl_action_conntrack               64
+#define lib_acl_action_connexist               128
+#define action_array_max            10000
+#define lib_acl_private_public                 0
+#define lib_acl_public_private                 1
+#define IP_HDR_DSCP_OFST 1
+#define IPv4_HDR_VERSION 4
+#define IPv6_HDR_VERSION 6
+#define IP_HDR_DSCP_OFST_IPV6 0
+#define IP_VERSION_CHECK 4
+#define IP_START (MBUF_HDR_ROOM + ETH_HDR_SIZE)
+#define DEFULT_NUM_RULE (4*1024)
+/**
+ * A structure defining the key to store an VNF action.
+ */
+struct pipeline_action_key {
+       uint32_t action_id;
+       uint32_t action_bitmap;
+       uint32_t nat_port;
+       uint32_t fwd_port;
+       uint8_t dscp_priority;
+       uint8_t private_public;
+} __rte_cache_aligned;
+
+/**
+ * A structure defining the Action counters.
+ * One Action Counter Block per VNF thread.
+ */
+struct action_counter_block {
+       uint64_t byteCount;
+       uint64_t packetCount;
+} __rte_cache_aligned;
+
+/**
+ * A structure defining the ACL library table.
+ */
+struct lib_acl_table_entry {
+       struct rte_pipeline_table_entry head;
+       uint32_t action_id;
+};
+
+
+struct lib_acl {
+       uint32_t n_rules;
+       uint32_t n_rule_fields;
+       struct rte_acl_field_def *field_format;
+       uint32_t field_format_size;
+       int action_counter_index;
+       struct lib_acl_table_entry
+       *plib_acl_entries_ipv4[RTE_PORT_IN_BURST_SIZE_MAX];
+       struct lib_acl_table_entry
+       *plib_acl_entries_ipv6[RTE_PORT_IN_BURST_SIZE_MAX];
+} __rte_cache_aligned;
+
+void *lib_acl_create_active_standby_table_ipv4(uint8_t table_num,
+               uint32_t *libacl_n_rules);
+
+void *lib_acl_create_active_standby_table_ipv6(uint8_t table_num,
+               uint32_t *libacl_n_rules);
+int lib_acl_parse_config(struct lib_acl *plib_acl,
+               char *arg_name, char *arg_value,
+               uint32_t *libacl_n_rules);
+uint64_t
+lib_acl_pkt_work_key(struct lib_acl *plib_acl,
+       struct rte_mbuf **pkts, uint64_t pkts_mask,
+       uint64_t *pkts_drop_without_rule,
+       void *plib_acl_rule_table_ipv4_active,
+       void *plib_acl_rule_table_ipv6_active,
+       struct pipeline_action_key *action_array_active,
+       struct action_counter_block (*p_action_counter_table)[action_array_max],
+       uint64_t *conntrack_mask,
+       uint64_t *connexist_mask,
+       int lib_acl_ipv4_enabled, int lib_acl_ipv6_enabled);
+uint64_t
+lib_acl_ipv4_pkt_work_key(struct lib_acl *plib_acl,
+       struct rte_mbuf **pkts, uint64_t pkts_mask,
+       uint64_t *pkts_drop_without_rule,
+       void *plib_acl_rule_table_ipv4_active,
+       struct pipeline_action_key *action_array_active,
+       struct action_counter_block (*p_action_counter_table)[action_array_max],
+       uint64_t *conntrack_mask,
+       uint64_t *connexist_mask);
+uint64_t
+lib_acl_ipv6_pkt_work_key(struct lib_acl *plib_acl,
+       struct rte_mbuf **pkts, uint64_t pkts_mask,
+       uint64_t *pkts_drop_without_rule,
+       void *plib_acl_rule_table_ipv6_active,
+       struct pipeline_action_key *action_array_active,
+       struct action_counter_block (*p_action_counter_table)[action_array_max],
+       uint64_t *conntrack_mask,
+       uint64_t *connexist_mask);
+
+
+#endif
diff --git a/common/VIL/alg/lib_ftp_alg.c b/common/VIL/alg/lib_ftp_alg.c
new file mode 100644 (file)
index 0000000..0a8a0e6
--- /dev/null
@@ -0,0 +1,917 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <app.h>
+#include <rte_common.h>
+#include <rte_malloc.h>
+#include <rte_mbuf.h>
+#include <rte_ip.h>
+#include <rte_byteorder.h>
+#include <rte_table_lpm.h>
+#include <rte_table_hash.h>
+#include <rte_pipeline.h>
+#include <rte_arp.h>
+#include <rte_icmp.h>
+#include <rte_hash.h>
+#include <rte_jhash.h>
+#include <rte_cycles.h>
+#include "pipeline_cgnapt_common.h"
+#include "pipeline_actions_common.h"
+#include "pipeline_cgnapt_be.h"
+#include "hash_func.h"
+#include "lib_ftp_alg.h"
+#include "vnf_common.h"
+#include "pipeline_common_be.h"
+#include "rte_ct_tcp.h"
+#include "rte_cnxn_tracking.h"
+#define ALG_DEBUG 1
+
+#if 1
+extern uint8_t
+rte_ct_create_cnxn_hashkey(
+       uint32_t *src_addr,
+       uint32_t *dst_addr,
+       uint16_t src_port,
+       uint16_t dst_port,
+       uint8_t proto,
+       uint32_t *key,
+       uint8_t type);
+#endif
+
+struct rte_mbuf *lib_alg_pkt;
+enum {PRIVATE, PUBLIC};
+struct rte_hash_parameters ftp_alg_hash_params = {
+       .name = "FTP ALG",
+       .entries = 1024,
+       .reserved = 0,
+       .key_len = sizeof(struct ftp_alg_key),
+       .hash_func = rte_jhash,
+       .hash_func_init_val = 0,
+};
+
+struct rte_hash *ftp_alg_hash_handle;
+
+/**
+ * ftp_alg Init function
+ */
+void lib_ftp_alg_init(void)
+{
+printf("NAT FTP ALG initialization ...\n");
+
+       /* FTP ALG hash table initialization */
+
+       ftp_alg_hash_handle = rte_hash_create(&ftp_alg_hash_params);
+
+       #ifdef ALGDBG
+       if (ftp_alg_hash_handle == NULL)
+               printf("FTP ALG rte_hash_create failed ...\n");
+       else
+               printf("ftp_alg_hash_table %p\n\n",
+                       (void *)ftp_alg_hash_handle);
+
+       #endif
+}
+
+/*
+ * ftp_alg table retreive function
+ * Input - alg key
+ * Output - Entry
+ */
+
+struct ftp_alg_table_entry *retrieve_ftp_alg_entry(struct ftp_alg_key alg_key)
+{
+       struct ftp_alg_table_entry *ret_alg_data = NULL;
+       alg_key.filler1 = 0;
+       alg_key.filler2 = 0;
+
+       int ret = rte_hash_lookup_data(ftp_alg_hash_handle, &alg_key,
+                                                        (void **)&ret_alg_data);
+       if (ret < 0) {
+               #ifdef ALGDBG
+               printf("alg-hash lookup failed ret %d, EINVAL %d, ENOENT %d\n",
+                                        ret, EINVAL, ENOENT);
+               #endif
+       } else {
+               return ret_alg_data;
+       }
+
+       return NULL;
+}
+
+/*
+ * ftp_alg table entry delete
+ * Input - ipaddress, portid
+ * Output - sucess or failure
+ */
+static int remove_ftp_alg_entry(uint32_t ipaddr, uint8_t portid)
+{
+
+       /* need to lock here if multi-threaded... */
+       /* rte_hash_del_key is not thread safe */
+       struct ftp_alg_key alg_key;
+       alg_key.l4port = rte_bswap16(portid);
+       alg_key.ip_address = rte_bswap32(ipaddr);
+       alg_key.filler1 = 0;
+       alg_key.filler2 = 0;
+
+       #ifdef ALGDBG
+               printf("remove_alg_entry ip %x, port %d\n", alg_key.ip_address,
+                                        alg_key.l4port);
+       #endif
+       return rte_hash_del_key(ftp_alg_hash_handle, &alg_key);
+}
+/*
+ * ftp_alg table entry add
+ * Input - ipaddress, portid
+ * Output - sucess or failure
+ */
+void
+populate_ftp_alg_entry(uint32_t ipaddr, uint8_t portid)
+{
+       /* need to lock here if multi-threaded */
+       /* rte_hash_add_key_data is not thread safe */
+       struct ftp_alg_key alg_key;
+       alg_key.l4port = rte_bswap16(portid);
+       //arp_key.ip = rte_bswap32(ipaddr);
+       alg_key.ip_address = rte_bswap32(ipaddr);
+       alg_key.filler1 = 0;
+       alg_key.filler2 = 0;
+
+
+       //lib_arp_populate_called++;
+
+       #ifdef ALGDBG
+       printf("populate_ftp_alg_entry ip %x, port %d\n", alg_key.ip_address,
+                                        alg_key.l4port);
+       #endif
+
+       struct ftp_alg_table_entry *new_alg_data =
+               retrieve_ftp_alg_entry(alg_key);
+       if (new_alg_data) {
+               #ifdef ALGDBG
+               printf("alg_entry exists ip%x, port %d\n", alg_key.ip_address,
+                               alg_key.l4port);
+               #endif
+               //lib_arp_duplicate_found++;
+               return;
+       }
+       new_alg_data = (struct ftp_alg_table_entry *)
+                       malloc(sizeof(new_alg_data));
+       //new_alg_data->status = INCOMPLETE;
+       new_alg_data->l4port = rte_bswap16(portid);
+       new_alg_data->ip_address = rte_bswap32(ipaddr);
+       rte_hash_add_key_data(ftp_alg_hash_handle, &alg_key, new_alg_data);
+
+       #ifdef ALGDBG
+               // print entire hash table
+               printf
+                               ("\tALG: table update - ip=%d.%d.%d.%d  on port=%d\n",
+                                (alg_key.ip_address >> 24),
+                                ((alg_key.ip_address & 0x00ff0000) >> 16),
+                                ((alg_key.ip_address & 0x0000ff00) >> 8),
+                                ((alg_key.ip_address & 0x000000ff)), portid);
+               /* print_arp_table(); */
+               puts("");
+       #endif
+}
+
+/*
+ * ftp_alg payload modification for PORT and PASV command
+ * Input - cgnapt table entry - for taking the public /translated ip/port ,
+ * incoming PORT/PASV string, Session type - PORT or PASV
+ * Output - Translated string
+ */
+int ftp_alg_modify_payload(
+       struct cgnapt_table_entry *egress_entry,
+       char *port_string,
+       char *port_string_translated, int ftp_session_type)
+{
+       uint32_t transport_ip;
+       uint16_t transport_port;
+       uint16_t tmp1, tmp2, tmp3, tmp4, tmp5, tmp6;
+       uint16_t new_port_string_length;
+
+       uint8_t *bptr_public_address;
+
+       transport_ip = egress_entry->data.pub_ip;
+       transport_port = egress_entry->data.pub_port;
+       tmp5 = (uint16_t) (transport_port/0x100);
+       tmp6 = (uint16_t) (transport_port % 0x100);
+
+       transport_ip = rte_bswap32(transport_ip);
+
+       bptr_public_address = (uint8_t *) &transport_ip;
+
+       tmp4 = bptr_public_address[3];
+       tmp3 = bptr_public_address[2];
+       tmp2 = bptr_public_address[1];
+       tmp1 = bptr_public_address[0];
+
+       if (ftp_session_type == 1)
+               sprintf(port_string_translated, FTP_PASV_PARAMETER_STRING,
+                       FTP_PASV_RETURN_CODE, tmp1, tmp2, tmp3, tmp4,
+                       tmp5, tmp6);
+       else
+               sprintf(port_string_translated, FTP_PORT_PARAMETER_STRING,
+                       tmp1, tmp2, tmp3, tmp4, tmp5, tmp6);
+       #ifdef ALGDBG
+       printf("FTP ALG: FTP new string: Len:%d %s\n",
+                       (uint16_t) strlen(port_string_translated)-2,
+                       port_string_translated);
+
+       printf("FTP non translated PASV string: Len:%d, %s\n",
+               (uint16_t)strlen(port_string)-2, port_string);
+               printf("old strlen:%d  new strlen:%d\n",
+               (int)strlen(port_string),
+               (int)strlen(port_string_translated));
+       #endif
+
+       return(new_port_string_length =
+               (uint16_t) strlen(port_string_translated));
+}
+
+/*
+ * ftp_alg modify packet len (due to change in len of FTP payload )
+ * Input - pkt
+ * Output - Length append /Trimmed Pkt
+**/
+static inline void ftp_alg_modify_pkt_len(struct rte_mbuf *pkt)
+{
+       uint16_t pkt_length = 0;
+       int ip_hdr_size_bytes = rte_ct_get_IP_hdr_size(pkt);
+       void *iphdr = RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
+
+       if (ip_hdr_size_bytes == IPv4_HEADER_SIZE) {
+               struct ipv4_hdr *ihdr4 = (struct ipv4_hdr *)iphdr;
+               pkt_length = rte_bswap16(ihdr4->total_length) + ETH_HDR_SIZE;
+       } else if (ip_hdr_size_bytes == IPv6_HEADER_SIZE) {
+               struct ipv6_hdr *ihdr6 = (struct ipv6_hdr *)iphdr;
+               pkt_length = rte_bswap16(ihdr6->payload_len) +
+                       IPv6_HEADER_SIZE + ETH_HDR_SIZE;
+       }
+
+       uint16_t mbuf_pkt_length = rte_pktmbuf_pkt_len(pkt);
+
+       if (pkt_length == mbuf_pkt_length)
+               return;
+
+       if (pkt_length < mbuf_pkt_length) {
+               rte_pktmbuf_trim(pkt, mbuf_pkt_length - pkt_length);
+               return;
+       }
+
+       /* pkt_length > mbuf_pkt_length */
+       rte_pktmbuf_append(pkt, pkt_length - mbuf_pkt_length);
+}
+
+/*
+ * ftp_alg IP HDR size calculation
+ * Input - pkt
+ * Output - Length of IP HDR
+ */
+
+/* same as rte_ct_get_IP_hdr_size()*/
+uint16_t ftp_alg_get_IP_hdr_size(struct rte_mbuf *pkt)
+{
+       /* NOTE: Only supporting IP headers with no options at this time
+       * so header is fixed size
+       */
+
+       uint8_t hdr_chk = RTE_MBUF_METADATA_UINT8(pkt, IP_START);
+       hdr_chk = hdr_chk >> 4;
+
+       if (hdr_chk == IP_VERSION_4)
+               return IPv4_HEADER_SIZE;
+       else if (hdr_chk == IP_VERSION_6)
+               return IPv6_HEADER_SIZE;
+       else            /* Not IPv4 header with no options, return negative. */
+               return -1;
+
+}
+
+/*
+ * ftp_alg checksum re-computing due to change in payload , uses rte function,
+ * if HW Checksum is supported s/w checksum will be disabled
+ * Input - IP HDR and TCP HDR
+ * Output - Length of IP HDR
+ */
+static void ftp_alg_compute_checksums(
+       void *i_hdr,
+       struct tcp_hdr *t_hdr)
+/* same as rte_synproxy_compute_checksums*/
+{
+       /*
+       * calculate IP and TCP checksums.
+       * Note that both checksum routines require
+       * checksum fields to be set to zero, and the the checksum is in the
+       * correct byte order, so no rte_bswap16 is required.
+       */
+
+       int8_t hdr_chk = rte_ct_ipversion(i_hdr);
+       t_hdr->cksum = 0;
+
+       if (hdr_chk == IP_VERSION_4) {
+               struct ipv4_hdr *i4_hdr = (struct ipv4_hdr *)i_hdr;
+               i4_hdr->hdr_checksum = 0;
+               t_hdr->cksum = 0;
+               t_hdr->cksum = rte_ipv4_udptcp_cksum(i4_hdr, t_hdr);
+
+               #ifdef ALGDBG
+               printf("cksum %x\n", rte_bswap32(t_hdr->cksum));
+               #endif
+
+               i4_hdr->hdr_checksum = rte_ipv4_cksum(i4_hdr);
+       } else if (hdr_chk == IP_VERSION_6) {
+               struct ipv6_hdr *i6_hdr = (struct ipv6_hdr *)i_hdr;
+               t_hdr->cksum = 0;
+               t_hdr->cksum = rte_ipv6_udptcp_cksum(i6_hdr, t_hdr);
+       }
+}
+
+/*
+ * ftp_alg adjusting ACK from other end ;
+ * ACK field of return packet to be adjusted
+ * to the same value of length modified in the payload
+ * Input - pkt, ack diff - delta
+ * Output - None(void)
+ */
+static void  ftp_alg_adjust_tcp_ack(struct rte_mbuf *pkt, int16_t ackSeqdiff)
+{
+       /*Since v6 is not supported now*/
+       uint16_t ip_hdr_size_bytes = IPv4_HEADER_SIZE;
+       struct ipv4_hdr *iphdr = (struct ipv4_hdr *)
+               RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
+       struct tcp_hdr *thdr = (struct tcp_hdr *)
+               RTE_MBUF_METADATA_UINT32_PTR(pkt,
+                       IP_START + ip_hdr_size_bytes);
+       /*
+       * recv_ack and total length first to be chnaged to host byte order
+       * and then do the addition and then set back to network byte order
+       */
+       uint32_t temp;
+       temp = rte_bswap32(thdr->recv_ack);
+       //printf("%s: ackSeqdiff :%d %u\n", __FUNCTION__, ackSeqdiff, temp);
+       if (ackSeqdiff < 0)
+               temp += abs(ackSeqdiff);
+       else
+               temp -= abs(ackSeqdiff);
+
+       thdr->recv_ack = rte_bswap32(temp);
+}
+/*
+ * ftp_alg adjusting SEQ from other end ; SEQ field of onward/egress  packet
+ * to be adjusted to the same value of length modified in the payload
+ * Input - pkt, ack diff - delta
+ * Output - None(void)
+ */
+
+static void  ftp_alg_adjust_tcp_seq(struct rte_mbuf *pkt, int16_t ackSeqdiff)
+{
+       /*Since v6 is not supported now*/
+       uint16_t ip_hdr_size_bytes = IPv4_HEADER_SIZE;
+       struct ipv4_hdr *iphdr = (struct ipv4_hdr *)
+               RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
+       struct tcp_hdr *thdr = (struct tcp_hdr *)
+               RTE_MBUF_METADATA_UINT32_PTR(pkt,
+                       IP_START + ip_hdr_size_bytes);
+       uint32_t temp;
+
+       temp = rte_bswap32(thdr->sent_seq);
+       if (ackSeqdiff < 0)
+               temp -= abs(ackSeqdiff);
+       else
+               temp += abs(ackSeqdiff);
+
+       thdr->sent_seq = rte_bswap32(temp);
+}
+/*
+ * ftp_alg adjusting SEQ from other end ; SEQ field of onward/egress  packet
+ * to be adjusted to the same value of length modified in the payload;
+ * This function computes the delta and calls adjust_seq for chaging the packet
+ * Input - pkt,Original incoming String, Translated string and corresponding
+ * lengths of the string
+ * Output - Seq Diff between Original and translated string
+ */
+
+static int ftp_alg_delta_tcp_sequence(
+       struct rte_mbuf *pkt,
+       char *port_string,
+       int16_t existing_tcpSeqdiff,
+       uint16_t old_port_string_length,
+       uint16_t new_port_string_length)
+{
+       int16_t current_sequence_number_delta=0;
+       int16_t final_sequence_number_delta;
+       /*Since v6 is not supported now*/
+       uint16_t ip_hdr_size_bytes = IPv4_HEADER_SIZE;
+       struct ipv4_hdr *iphdr = (struct ipv4_hdr *)
+                               RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
+       struct tcp_hdr *thdr = (struct tcp_hdr *)
+                               RTE_MBUF_METADATA_UINT32_PTR(pkt,
+                                       IP_START + ip_hdr_size_bytes);
+       /*
+       * recv_ack and total length first to be chnaged to host byte order
+       * and then do the addition and then set back to network byte order
+       */
+       current_sequence_number_delta = (int16_t) (new_port_string_length -
+                                       old_port_string_length);
+       iphdr->total_length = rte_bswap16(iphdr->total_length);
+
+       #ifdef ALGDBG
+       printf("total_length :%u\n", iphdr->total_length);
+       #endif
+       if(current_sequence_number_delta < 0)
+               iphdr->total_length -= abs(current_sequence_number_delta);
+       else
+               iphdr->total_length += current_sequence_number_delta;
+
+       iphdr->total_length = rte_bswap16(iphdr->total_length);
+       if (existing_tcpSeqdiff !=0)
+               ftp_alg_adjust_tcp_seq(pkt,existing_tcpSeqdiff);
+       final_sequence_number_delta= current_sequence_number_delta + existing_tcpSeqdiff;
+       return final_sequence_number_delta;
+}
+
+
+/*
+ * ftp_alg dpi - this function parses the packet and does the respective
+ * action based on the type PORT or PASV, based on the direction of packet
+ * (Private or Public) This is called from CGNAPT
+ * Input - cgnapt pipeline struct, cgnapt key, pkt, CT ,
+ * position of packet assigned by CT, direction of packet
+ * Output - None - as it calls respective action functions
+ */
+void ftp_alg_dpi(
+       struct pipeline_cgnapt *p_nat,
+       struct pipeline_cgnapt_entry_key *nat_entry_key,
+       struct rte_mbuf *pkt,
+       struct rte_ct_cnxn_tracker *cgnat_cnxn_tracker,
+       int32_t ct_position,
+       uint8_t direction)
+{
+       /*
+       * recv_ack and total length first to be chnaged to host byte order
+       * and then do the addition and then set back to network byte order
+       */
+
+       /*entry key to be framed in cgnat and pass it over here*/
+       char *port_cmd_string;
+       char *port_cmd_end_string;
+       char *tcp_header_end;
+       char *tcp_start;
+
+
+       uint16_t private_port_number;
+       uint16_t public_port_number;
+       uint16_t ip1, ip2, ip3, ip4, port1, port2;
+       int16_t tcpSeqdiff;
+       int16_t ackSeqdiff, ackAdjust;
+       uint32_t private_address;
+       uint32_t public_address;
+       uint8_t *bptr_private_address;
+       /* also for PASV string */
+       char port_string[FTP_MAXIMUM_PORT_STRING_LENGTH];
+       char port_string_translated[FTP_MAXIMUM_PORT_STRING_LENGTH];
+       int16_t new_port_string_length;
+       int16_t old_port_string_length;
+       int dummy_value;
+       struct cgnapt_table_entry *egress_entry, *ingress_entry;
+       uint32_t ct_key[10];
+       uint8_t key_direction;
+       /*Since v6 is not supported now*/
+       uint16_t ip_hdr_size_bytes = IPv4_HEADER_SIZE;
+
+       struct ipv4_hdr *ip_hdr = rte_pktmbuf_mtod_offset(pkt,
+                       struct ipv4_hdr *, sizeof(struct ether_hdr));
+       /* TCP and UDP ports at same offset,
+       * just use TCP for offset calculation
+       */
+       struct tcp_hdr *thdr = rte_pktmbuf_mtod_offset(pkt, struct tcp_hdr *,
+                       (sizeof(struct ether_hdr)+sizeof(struct ipv4_hdr)));
+       uint16_t src_port = rte_bswap16(thdr->src_port);
+       uint16_t dst_port = rte_bswap16(thdr->dst_port);
+       uint8_t proto = ip_hdr->next_proto_id;
+       uint32_t src_addr = rte_bswap32(ip_hdr->src_addr);
+       uint32_t dst_addr = rte_bswap32(ip_hdr->dst_addr);
+       uint32_t tmp_tcp_paylod_size;
+
+       #if 0
+       - src_port & dst_port checking to be moved from cgnat to dpi
+       - For control channel
+               first validation of tcpSeqdiff to be checked
+               IF <  > 0
+                       ftp_alg_tcp_ack() to be called(this includes PORT
+                       response and PASV response ack as well)
+                       Return
+               ELSE
+                       the port/pasv paramter checkign to be done
+       - For data channel
+       -retreive ALG entry
+               IF found
+                       - remove the ALG entry
+               even if not found(found cases too)
+       - set the bypass flag in the CT session table
+
+       #endif
+
+       #ifdef ALGDBG
+       {
+               printf("ftp port number: %d, %d\n", src_port, dst_port);
+               printf("ftp TCP seq num diff: %d\n",
+                       cgnat_cnxn_tracker->hash_table_entries[
+                                       ct_position].tcpSeqdiff);
+               printf("tcp data offset: %d\n",
+                       ((thdr->data_off & 0xf0) >> 2));
+               printf("ct position in dpi:%d\n", ct_position);
+       }
+       #endif
+
+       if (src_port == 21 || dst_port == 21)/* Control Channel*/{
+       /* Control Channel Start */
+       /*
+       * need to look for the port or pasv command.  Then have to look for
+       * the IP address and the port address. Then must create a TCP control
+       * block and spoof the port number, and change the ip address, and do
+       * the sequence number setting.
+       */
+       /* Handle TCP headers.*/
+       tcp_start = (char *)thdr;
+
+       /* start of TCP payload */
+       port_cmd_string = (char * )(tcp_start+((thdr->data_off & 0xf0) >> 2));
+       tcp_header_end = port_cmd_string;
+
+       if (direction == PRIVATE) {
+
+               #ifdef ALGDBG
+               printf("In PRIVATE  ");
+               #endif
+
+               cgnat_cnxn_tracker->hash_table_entries[ct_position].seq_client
+                               = rte_bswap32(thdr->sent_seq);
+               cgnat_cnxn_tracker->hash_table_entries[ct_position].ack_client
+                               = rte_bswap32(thdr->recv_ack);
+               #ifdef ALGDBG
+               printf("-->Seq_cli:%u, Ack_cli:%u, Len:%4d\n",
+                       rte_bswap32(thdr->sent_seq),
+                       rte_bswap32(thdr->recv_ack),
+                       (rte_bswap16(ip_hdr->total_length) -
+                       (((thdr->data_off & 0xf0) >> 4) * 4)) - 20);
+               #endif
+       } else {
+
+               #ifdef ALGDBG
+               printf("In PUBLIC  ");
+               #endif
+               cgnat_cnxn_tracker->hash_table_entries[ct_position].seq_server
+                               = rte_bswap32(thdr->sent_seq);
+               cgnat_cnxn_tracker->hash_table_entries[ct_position].ack_server
+                               = rte_bswap32(thdr->recv_ack);
+               #ifdef ALGDBG
+               printf("<--Seq_cli:%4d, Ack_cli%4d, Len:%4d\n",
+               rte_bswap32(thdr->sent_seq), rte_bswap32(thdr->recv_ack),
+               (ip_hdr->total_length - (((thdr->data_off & 0xf0) >> 2))
+                       - 20));
+               #endif
+       }
+
+       if (sscanf(port_cmd_string, FTP_PASV_PARAMETER_STRING, &dummy_value,
+               &ip1, &ip2, &ip3, &ip4, &port1, &port2) ==
+               FTP_PASV_PARAMETER_COUNT){
+
+       sprintf (port_string, FTP_PASV_PARAMETER_STRING, FTP_PASV_RETURN_CODE,
+               ip1, ip2, ip3, ip4, port1, port2);
+
+       int i = 0;
+       while (port_cmd_string[i] != '\r' && port_cmd_string[i+1] != '\n')
+               i++;
+
+       i += 2; // now it points to end of port cmd string.
+
+       old_port_string_length = i;
+
+       private_port_number = (uint16_t) (port1 * 0x100 + port2);
+       bptr_private_address = (uint8_t *) &private_address;
+
+       bptr_private_address[3] = (uint8_t) (ip4 & 0x00FF);
+       bptr_private_address[2] = (uint8_t) (ip3 & 0x00FF);
+       bptr_private_address[1] = (uint8_t) (ip2 & 0x00FF);
+       bptr_private_address[0] = (uint8_t) (ip1 & 0x00FF);
+
+       /* Not needed as got the position from CT*/
+
+       if (direction == PUBLIC) {
+       /*Client in Private, Server in Public*/
+       /* Not to convert in the payload for PASV resp from Pub side*/
+       /* Only Table creation and no payload modification*/
+       /* DAta Channel also no need to create as it will be done by NAT
+       * when initiated by Client later
+       */
+       populate_ftp_alg_entry(private_address, private_port_number);
+       /*
+       * Bypass ALG flag to be set ,
+       * seqnumber -delta either to be 0 or not needed ,
+       * direction checking for all scenarios
+       */
+       cgnat_cnxn_tracker->hash_table_entries[ct_position].
+                       server_direction = SERVER_IN_PUBLIC;
+       cgnat_cnxn_tracker->hash_table_entries[ct_position].
+                       ftp_session_type= 1; // Passive session type
+       } else if (direction == PRIVATE) {
+       /*Client in Public , Server in Private*/
+
+       struct pipeline_cgnapt_entry_key data_channel_key;
+       private_address = rte_bswap32(private_address);
+       data_channel_key.ip = private_address;
+       data_channel_key.port = private_port_number;
+       /* to be checked if it can be passed as param from NAT*/
+       data_channel_key.pid = pkt->port;
+
+       /* add_dynamic_cgnat_entry() */ /* for DAta Channel*/
+       /*Will be getting Private IP and port from Server ,
+       * with that NAPT entry egress and ingress can be added ,
+       * for further data channel communication
+       */
+
+       if (add_dynamic_cgnapt_entry_alg((struct pipeline *)p_nat,
+       &data_channel_key, &egress_entry, &ingress_entry) == 0){
+
+               #ifdef ALGDBG
+               printf("Wrong FTP ALG packet\n");
+               #endif
+               //p_nat->invalid_packets |= pkt_mask;
+
+               p_nat->naptDroppedPktCount++;
+
+               #ifdef CGNAPT_DEBUGGING
+               p_nat->naptDroppedPktCount4++;
+               #endif
+               return;
+       }
+
+       tmp_tcp_paylod_size = rte_bswap16(ip_hdr->total_length) -
+                       ((thdr->data_off & 0xf0) >> 2) - ip_hdr_size_bytes;
+       cgnat_cnxn_tracker->hash_table_entries[ct_position].
+                       tcp_payload_size = tmp_tcp_paylod_size;
+
+       /*Adding ALG entry , params to be derived from egress entry*/
+       populate_ftp_alg_entry(egress_entry->data.pub_ip,
+                       egress_entry->data.pub_port);
+       /* payload modification */
+       new_port_string_length = ftp_alg_modify_payload(egress_entry,
+                                       port_string,
+                                       port_string_translated, 1);
+       strncpy(tcp_header_end, port_string_translated,
+               strlen(port_string_translated));
+       tcpSeqdiff = ftp_alg_delta_tcp_sequence( pkt, port_string,
+                       cgnat_cnxn_tracker->hash_table_entries
+                       [ct_position].tcpSeqdiff,
+                       old_port_string_length,
+                       new_port_string_length);
+
+       /* same as rte_synproxy_adjust_pkt_length() in ct */
+       ftp_alg_modify_pkt_len(pkt);
+       /*
+       * Store sequence_number_delta in Session_data structure, also bypass
+       * flag to be set as NO (expecting TCP ack from other end then set the
+       * bypass accordingly , handled earlier in the function
+       */
+
+       cgnat_cnxn_tracker->hash_table_entries[ct_position].
+                       alg_bypass_flag = NO_BYPASS;
+       cgnat_cnxn_tracker->hash_table_entries[ct_position].
+                       tcpSeqdiff = tcpSeqdiff;
+       cgnat_cnxn_tracker->hash_table_entries[ct_position].
+                       server_direction = SERVER_IN_PRIVATE;
+       cgnat_cnxn_tracker->hash_table_entries[ct_position].
+                       ftp_session_type = 1; // Passive session type
+               return;
+
+       } /* PRIVATE dir */
+       } else if (sscanf(port_cmd_string, FTP_PORT_PARAMETER_STRING,
+                       &ip1, &ip2, &ip3, &ip4, &port1, &port2) ==
+                               FTP_PORT_PARAMETER_COUNT){
+
+               int i = 0;
+               static uint8_t port_hit;
+               while (port_cmd_string[i] != '\r' &&
+                       port_cmd_string[i+1] != '\n')
+                       i++;
+
+               i += 2; // now it points to end of port cmd string.
+
+               old_port_string_length = i;
+
+               #ifdef ALGDBG
+               printf( " Existing Seq Diff = %d", cgnat_cnxn_tracker->
+                       hash_table_entries[ct_position].tcpSeqdiff);
+               printf("FTP ALG: FTP PORT command length: %d\n",
+                       old_port_string_length);
+               #endif
+
+               private_port_number = (uint16_t) (port1 * 0x100 + port2);
+
+               #ifdef ALGDBG
+               printf("FTP ALG: private port number before swap: %u\n",
+                               private_port_number);
+               #endif
+
+               bptr_private_address = (uint8_t *) &private_address;
+               bptr_private_address[3] = (uint8_t) (ip4 & 0x00FF);
+               bptr_private_address[2] = (uint8_t) (ip3 & 0x00FF);
+               bptr_private_address[1] = (uint8_t) (ip2 & 0x00FF);
+               bptr_private_address[0] = (uint8_t) (ip1 & 0x00FF);
+
+               sprintf(port_string, FTP_PORT_PARAMETER_STRING, ip1, ip2,
+                               ip3, ip4, port1, port2);
+
+               #ifdef ALGDBG
+               printf("FTP ALG: FTP original PORT string: %d,%s\n",
+                               (int) strlen(port_string)-2, port_string);
+               printf("prv addr: %x\n", private_address);
+               #endif
+
+
+               if (direction == PUBLIC) {
+                       /* Client in Public*/
+                       /* retreive_cgnat_entry()* for Data Channel*/
+                       /* Pub port and ip address to be used for framing key ,
+                       * the private phrase is a misnomer
+                       */
+                       struct pipeline_cgnapt_entry_key data_channel_key;
+                       data_channel_key.ip = private_address;
+                       data_channel_key.port = private_port_number;
+                       data_channel_key.pid = 0xffff;
+
+
+                       cgnat_cnxn_tracker->hash_table_entries[ct_position].
+                               server_direction = SERVER_IN_PRIVATE;
+                       cgnat_cnxn_tracker->hash_table_entries[ct_position].
+                               ftp_session_type= 0; // Active session type
+
+                       /* No payload modificaiton*/
+                       #ifdef ALGDBG
+                       printf("<--Seq_cli:%4d, Ack_cli%4d, Len:%4d\n",
+                       rte_bswap32(thdr->sent_seq),
+                       rte_bswap32(thdr->recv_ack),
+                       (ip_hdr->total_length -
+                               (((thdr->data_off & 0xf0) >> 2)) - 20));
+                       #endif
+                       populate_ftp_alg_entry(private_address, private_port_number);
+               } else if (direction == PRIVATE) {
+
+                       /* Client in Private Server in Public*/
+                       /* Populate_alg_entry*/
+                       /*add_dynamic_cgnapt_entry()*/
+                       /* payload modificaion*/
+                       struct pipeline_cgnapt_entry_key data_channel_key;
+                       private_address = rte_bswap32(private_address);
+                       data_channel_key.ip = private_address;
+                       data_channel_key.port = private_port_number;
+                       /* to be checked if it can be passed as param from NAT*/
+                       data_channel_key.pid = pkt->port;
+
+                       /* add_dynamic_cgnat_entry() */ /* for DAta Channel*/
+                       /*
+                       * Will be getting Private IP and port from Client ,
+                       * with that NAPT entry egress and ingress can be added ,
+                       * for further data channel communication
+                       */
+
+                       if (add_dynamic_cgnapt_entry_alg((struct pipeline *)
+                               p_nat, &data_channel_key, &egress_entry,
+                               &ingress_entry) == 0){
+
+                               #ifdef ALGDBG
+                               printf("Wrong FTP ALG packet\n");
+                               #endif
+                               //p_nat->invalid_packets |= pkt_mask;
+                               p_nat->naptDroppedPktCount++;
+
+                               #ifdef CGNAPT_DEBUGGING
+                               p_nat->naptDroppedPktCount4++;
+                               #endif
+                               return;
+                       }
+
+               tmp_tcp_paylod_size = rte_bswap16(ip_hdr->total_length) -
+                                       ((thdr->data_off & 0xf0) >> 2) -
+                                       ip_hdr_size_bytes;
+               cgnat_cnxn_tracker->hash_table_entries[ct_position].
+                       tcp_payload_size = tmp_tcp_paylod_size;
+               /*ALG entry add, params to be derived from egress entry*/
+
+               populate_ftp_alg_entry(egress_entry->data.pub_ip,
+                       egress_entry->data.pub_port);
+               /* payload modification */
+               new_port_string_length = ftp_alg_modify_payload(egress_entry,
+                                               port_string,
+                                               port_string_translated, 0);
+               strncpy(tcp_header_end, port_string_translated,
+                               strlen(port_string_translated));
+               tcpSeqdiff = ftp_alg_delta_tcp_sequence( pkt, port_string,
+                               cgnat_cnxn_tracker->hash_table_entries
+                               [ct_position].tcpSeqdiff,
+                               old_port_string_length,
+                               new_port_string_length);
+               /* same as rte_synproxy_adjust_pkt_length() in ct */
+               ftp_alg_modify_pkt_len(pkt);
+
+               /*
+               * Store sequence_number_delta in Session_data structure ,
+               * also bypass flag to be set as NO
+               * While response from other end is received ,
+               * modify the ack no using reverse sign of sequen
+               */
+
+               cgnat_cnxn_tracker->hash_table_entries[ct_position].
+                       alg_bypass_flag = NO_BYPASS;
+               cgnat_cnxn_tracker->hash_table_entries[ct_position].
+                       tcpSeqdiff = tcpSeqdiff;
+               cgnat_cnxn_tracker->hash_table_entries[ct_position].
+                       server_direction = SERVER_IN_PUBLIC;
+               cgnat_cnxn_tracker->hash_table_entries[ct_position].
+                       ftp_session_type = 0; // Active session type
+
+               #ifdef ALGDBG
+               printf("<--Seq_cli:%4d, Ack_cli%4d, Len:%4d\n",
+                       rte_bswap32(thdr->sent_seq),
+                       rte_bswap32(thdr->recv_ack),
+                       (ip_hdr->total_length -
+                       (((thdr->data_off & 0xf0) >> 2)) - 20));
+
+               #endif
+               return;
+               } /* PRIVATE dir */
+       } /* PORT cmd message */
+
+       if ((ackAdjust=cgnat_cnxn_tracker->hash_table_entries[
+                       ct_position].tcpSeqdiff) != 0) {
+               if (direction == PRIVATE) {
+                       if (
+                               cgnat_cnxn_tracker->hash_table_entries
+                               [ct_position].seq_client !=
+                               cgnat_cnxn_tracker->hash_table_entries
+                               [ct_position].ack_server) {
+                               static int Seqhits;
+                               ftp_alg_adjust_tcp_seq( pkt,ackAdjust);
+                               tmp_tcp_paylod_size = rte_bswap16(
+                                       ip_hdr->total_length) -
+                                       ((thdr->data_off & 0xf0) >> 2) -
+                                       ip_hdr_size_bytes;
+                               cgnat_cnxn_tracker->hash_table_entries
+                               [ct_position].tcp_payload_size = tmp_tcp_paylod_size;
+               #ifdef ALGDBG
+                printf("<--Seq_cli:%4d, Ack_cli%4d, Len:%4d\n",
+                       rte_bswap32(thdr->sent_seq),
+                       rte_bswap32(thdr->recv_ack),
+                       (ip_hdr->total_length -(((thdr->data_off & 0xf0) >> 2))- 20));
+               #endif
+                       }
+               } else {
+                       if (cgnat_cnxn_tracker->hash_table_entries
+                               [ct_position].ack_server !=
+                               (cgnat_cnxn_tracker->hash_table_entries
+                               [ct_position].seq_client +
+                               cgnat_cnxn_tracker->hash_table_entries
+                               [ct_position].tcp_payload_size)) {
+                               static int Ackhits;
+                               ftp_alg_adjust_tcp_ack( pkt,ackAdjust);
+               #ifdef ALGDBG
+                printf("<--Seq_cli:%4d, Ack_cli%4d, Len:%4d\n",
+                       rte_bswap32(thdr->sent_seq),
+                       rte_bswap32(thdr->recv_ack),
+                       (ip_hdr->total_length -(((thdr->data_off & 0xf0) >> 2))- 20));
+               #endif
+                       }
+               }
+               return;
+                       } /* expected_ack and sequence number updation for PUBLIC dir TCP window */
+       } /* Control Channel End */
+       else {
+               /*remove the ALG entry, retreival is taken care by rte function  */
+               #ifdef ALGDBG
+               printf("In Data Channel \n");
+               #endif
+               remove_ftp_alg_entry (dst_addr,dst_port);/* remove the ALG entry */
+               cgnat_cnxn_tracker->hash_table_entries[ct_position].alg_bypass_flag = BYPASS;
+       } /* Data Channel End */
+}
diff --git a/common/VIL/alg/lib_ftp_alg.h b/common/VIL/alg/lib_ftp_alg.h
new file mode 100644 (file)
index 0000000..875d627
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef __INCLUDE_LIB_FTP_ALG_H__
+#define __INCLUDE_LIB_FTP_ALG_H__
+#include "rte_ether.h"
+#include "rte_ct_tcp.h"
+/*CT & CGNAT integration to be resolved for this definitions*/
+#define META_DATA_OFFSET 128
+#define ETHERNET_START (META_DATA_OFFSET + RTE_PKTMBUF_HEADROOM)
+#define ETH_HDR_SIZE 14
+#define IP_START (ETHERNET_START + ETH_HDR_SIZE)
+#define PROTOCOL_START (IP_START + 9)
+#define TCP_START (IP_START + IP_V4_HEADER_SIZE)
+#define TCP_MIN_HDR_SIZE 20
+
+#define RTE_TCP_PROTO_ID 6
+#define RTE_SP_DEFAULT_TTL 64
+
+#define RTE_SYNPROXY_MAX_SPOOFED_PKTS 64
+
+#define RTE_TCP_SYN 0x02
+#define RTE_TCP_ACK 0x10
+#define RTE_TCP_SYN_ACK (RTE_TCP_SYN | RTE_TCP_ACK)
+#define IP_VERSION_4 4
+#define IP_VERSION_6 6
+#define IPv4_HEADER_SIZE 20
+#define IPv6_HEADER_SIZE 40
+
+//#define IPV4 4
+//#define IPV6 6
+enum ftp_alg_bypass {
+       NO_BYPASS,
+       BYPASS
+};
+
+enum ftp_alg_mode {
+       FTP_ALG_PORT,
+       FTP_ALG_PASV
+};
+enum ftp_alg_direction {
+       SERVER_IN_PRIVATE,
+       SERVER_IN_PUBLIC
+};
+enum phy_port {
+       PRIVATE_PORT,
+       PUBLIC_PORT
+};
+
+struct ftp_alg_key {
+       uint32_t ip_address;
+       uint16_t l4port;
+       uint8_t filler1;
+       uint8_t filler2;
+};
+struct ftp_alg_table_entry {
+       uint32_t ip_address;
+       uint16_t l4port;
+       uint8_t ftp_alg_mode;
+       uint8_t ftp_alg_direction;
+       uint32_t session_id;    /*to be checked */
+       uint8_t alg_bypass_flag;
+       uint8_t dummy;
+       uint8_t dummy1;
+       //uint32_t napt_entry;/* to be checked*/
+} __rte_cache_aligned;
+
+#define FTP_SERVER_PORT                                21
+#define FTP_PORT_STRING                                "PORT"
+#define FTP_PORT_PARAMETER_STRING              "PORT %hu,%hu,%hu,%hu,%hu,%hu\r\n"
+#define FTP_PORT_PARAMETER_COUNT               6
+#define FTP_PORT_RESPONSE_STRING               "200 PORT command successful.\r\n"
+#define FTP_PORT_STRING_END_MARKER             '\n'
+#define FTP_MAXIMUM_PORT_STRING_LENGTH         60
+#define FTP_PASV_STRING                                "PASV"
+#define FTP_PASV_PARAMETER_STRING              "%d Entering Passive Mode (%hu,%hu,%hu,%hu,%hu,%hu)\r\n"
+#define FTP_PASV_PARAMETER_COUNT               7
+#define FTP_PASV_STRING_END_MARKER             '\n'    /* not ')' */
+#define FTP_PASV_RETURN_CODE                   227
+
+void ftp_alg_dpi(
+       struct pipeline_cgnapt *p_nat,
+       struct pipeline_cgnapt_entry_key *nat_entry_key,
+       struct rte_mbuf *pkt,
+       struct rte_ct_cnxn_tracker *cgnat_cnxn_tracker,
+       int32_t ct_position,
+       uint8_t direction);
+void lib_ftp_alg_init(void);
+extern int8_t rte_ct_ipversion(void *i_hdr);
+#endif
diff --git a/common/VIL/alg/lib_sip_alg.c b/common/VIL/alg/lib_sip_alg.c
new file mode 100644 (file)
index 0000000..9940d59
--- /dev/null
@@ -0,0 +1,2257 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+/*Sriramajeyam*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <math.h>
+
+#include <app.h>
+#include <rte_common.h>
+#include <rte_malloc.h>
+#include <rte_ip.h>
+#include <rte_udp.h>
+#include <rte_byteorder.h>
+#include <rte_table_lpm.h>
+#include <rte_table_hash.h>
+#include <rte_pipeline.h>
+#include <rte_arp.h>
+#include <rte_icmp.h>
+#include <rte_hash.h>
+#include <rte_jhash.h>
+#include <rte_cycles.h>
+
+#include "pipeline_actions_common.h"
+#include "hash_func.h"
+#include "lib_sip_alg.h"
+#include "vnf_common.h"
+#include "pipeline_common_be.h"
+
+#define SIP_ALG_SIP "SIP"
+#define SIP_ALG_200_OK "200 OK"
+#define SIP_ALG_INVITE "INVITE"
+#define SIP_ALG_BYE "BYE"
+#define SIP_ALG_TRYING "100 Trying"
+#define SIP_ALG_RINGING "180 Ringing"
+#define SIP_ALG_ACK "ACK"
+#define SIP_ALG_CONTACT "Contact"
+#define SIP_ALG_CONTENT_LEN "Content-Length"
+#define SIP_ALG_VIA "Via"
+#define SIP_ALG_FROM "From"
+#define SIP_ALG_TO "To"
+#define SIP_ALG_CALLID "Call-ID"
+#define SIP_ALG_RTP "RTP"
+#define SIP_ALG_RTCP "a=RTCP"
+#define SIP_ALG_CANCEL "CANCEL"
+#define SIP_ALG_CONTYPE "Content-Type"
+#define SIP_ALG_APPSDP "application/sdp"
+#define SIP_ALG_CSEQ "CSeq"
+#define SIP_ALG_AUDIO "m=audio"
+#define SIP_ALG_DOUBLE_CRLF "\r\n\r\n"
+#define SIP_ALG_CRLF "\r\n"
+#define SIP_ALG_AT "@"
+#define SIP_ALG_GREAT ">"
+#define SIP_ALG_OWNER "o="
+#define SIP_ALG_IPV4 "IP4"
+#define SIP_ALG_CONN "c="
+#define SIP_ALG_REMOTE_PARTY_ID "Remote-Party-ID"
+#define SIP_ALG_SPACE " "
+#define SIP_ALG_SEMICOLON ";"
+
+#define SIP_DEFAULT_L4PORT 5060
+
+#define SIP_ALG_INVITE_MSGTYPE 1
+#define SIP_ALG_BYE_MSGTYPE 2
+#define SIP_ALG_200_OK_INVITE_MSGTYPE 3
+#define SIP_ALG_200_OK_BYE_MSGTYPE 4
+#define SIP_ALG_TRYING_RINGING_MSGTYPE 5
+#define SIP_ALG_ACK_MSGTYPE 6
+
+#define MAX_NUM_SIP_ALG_ENTRIES 16384
+
+#define SIP_ALG_VIA_FIELD_IPADDR   14
+#define SIP_ALG_CTAC_FIELD_IPADDR  7
+
+#define ADDRESS_PORT_STRING   1
+#define PORT_STRING           2
+
+#define MAX_ADDR_PORT_SIZE 30
+#define MAX_ADDR_SIZE 20
+#define MAX_PORT_SIZE 10
+#define MAX_SIP_UDP_MSG_SIZE 2000
+
+#define ALG_DEBUG 0
+
+enum { FALSE, TRUE };
+
+struct rte_mempool *lib_alg_pktmbuf_tx_pool;
+
+struct rte_mbuf *lib_alg_pkt;
+
+static struct rte_hash_parameters sip_alg_hash_params = {
+       .name = NULL,
+       .entries = MAX_NUM_SIP_ALG_ENTRIES,
+       .reserved = 0,
+       .key_len = sizeof(struct sip_alg_key),
+       .hash_func = rte_jhash,
+       .hash_func_init_val = 0,
+       .extra_flag = 1,
+};
+
+struct rte_hash *sip_alg_hash_table;
+
+struct sip_alg_table_entry *sip_alg_table[MAX_NUM_SIP_ALG_ENTRIES];
+
+char *sip_alg_process(struct rte_mbuf *pkt,
+                                       uint16_t pkt_direction, uint16_t call_direction,
+                                       uint16_t msgType, uint32_t modIp,
+                                       uint16_t modL4Port, uint32_t pubIp,
+                                       uint16_t pubL4Port, uint16_t modRtpPort,
+                                       uint16_t modRtcpPort, uint16_t *diffModSipLen);
+char *getSipCallIdStr(char *pMsg);
+char *natSipAlgModifyPayloadAddrPort(char *pSipMsg, char **pSipMsgEnd,
+                                                uint32_t oldStrLen, uint32_t *diffLen,
+                                                uint32_t pub_ip, uint16_t pub_port,
+                                                uint32_t type);
+char *natSipAlgAdjustMsg(char *pSipMsg, char **pSipMsgEnd,
+                        uint32_t newStrLen, uint32_t oldStrLen);
+
+// This method will be called from other VNF to initialize SIP lib
+// Make an API out of it
+void lib_sip_alg_init(void)
+{
+       char *s = rte_zmalloc(NULL, 64, RTE_CACHE_LINE_SIZE);;
+       int socketid = 0;
+       /* create ipv4 hash */
+       if(!s){
+               printf("NAT SIP ALG Init failed\n");
+               return;
+       }
+       snprintf(s, strlen(s), "ipv4_sip_alg_hash_%d", socketid);
+       printf("NAT SIP ALG initialization ...\n");
+
+       /* SIP ALG hash table initialization */
+       sip_alg_hash_params.socket_id = SOCKET_ID_ANY;
+       sip_alg_hash_params.name = s;
+       sip_alg_hash_table = rte_hash_create(&sip_alg_hash_params);
+
+       if (sip_alg_hash_table == NULL) {
+               printf("SIP ALG rte_hash_create failed. socket %d ...\n",
+                                        sip_alg_hash_params.socket_id);
+               rte_exit(0, "SIP ALG rte_hash_create failed");
+       } else {
+               printf("sip_alg_hash_table %p\n\n", (void *)sip_alg_hash_table);
+       }
+
+}
+
+char *itoa(long n);
+char *itoa(long n)
+{
+       int len = n == 0 ? 1 : floor(log10l(labs(n))) + 1;
+
+       if (n < 0)
+               len++;          /* room for negative sign '-' */
+
+       char *buf = calloc(sizeof(char), len + 1);      // +1 for null
+       if(buf != NULL)
+               snprintf(buf, len + 1, "%ld", n);
+       return buf;
+}
+
+struct sip_alg_table_entry *retrieve_sip_alg_entry(
+                       struct sip_alg_key *alg_key);
+
+struct sip_alg_table_entry *retrieve_sip_alg_entry(
+                       struct sip_alg_key *alg_key)
+{
+       struct sip_alg_table_entry *sip_alg_data = NULL;
+
+       int ret = rte_hash_lookup(sip_alg_hash_table, alg_key);
+
+       if (ret < 0) {
+               #ifdef ALGDBG
+                       printf("alg-hash lookup failed ret %d, "
+                                       "EINVAL %d, ENOENT %d\n",
+                                        ret, EINVAL, ENOENT);
+               #endif
+       } else {
+               sip_alg_data = sip_alg_table[ret];
+               return sip_alg_data;
+       }
+
+       return NULL;
+}
+
+//int remove_sip_alg_entry(uint32_t ipaddr, uint16_t portid);
+int remove_sip_alg_entry(uint32_t ipaddr, uint16_t portid)
+{
+       struct sip_alg_key alg_key;
+       void *sip_alg_entry_data;
+       int ret;
+
+       alg_key.l4port = portid;
+       alg_key.ip_address = ipaddr;
+       alg_key.filler1 = 0;
+       alg_key.filler2 = 0;
+
+       if (ALG_DEBUG)
+               printf("remove_sip_entry ip %x, port %d\n", alg_key.ip_address,
+                                        alg_key.l4port);
+
+       ret = rte_hash_lookup(sip_alg_hash_table, &alg_key);
+       if (ret < 0) {
+               if (ALG_DEBUG)
+                       printf("removesipalgentry: "
+                               "rtehashlookup failed with error %d",
+                                        ret);
+               return -1;
+       }
+
+       sip_alg_entry_data = sip_alg_table[ret];
+
+       free(sip_alg_entry_data);
+       rte_hash_del_key(sip_alg_hash_table, &alg_key);
+
+       return 0;
+}
+
+/*
+ * Function for populating SIP ALG entry. return 0 - success &
+ * return -1 - failure
+ */
+int populate_sip_alg_entry(uint32_t ipaddr, uint16_t portid,
+                                char *sip_call_id, uint8_t call_direction,
+                                enum sip_alg_port_type port_type);
+int populate_sip_alg_entry(uint32_t ipaddr, uint16_t portid,
+                                char *sip_call_id, uint8_t call_direction,
+                                enum sip_alg_port_type port_type)
+{
+       struct sip_alg_key alg_key;
+
+       alg_key.l4port = portid;
+       alg_key.ip_address = ipaddr;
+       alg_key.filler1 = 0;
+       alg_key.filler2 = 0;
+       int ret;
+
+       if (ALG_DEBUG)
+               printf("populate_sip_alg_entry port %d, ip %x\n",
+                                        alg_key.l4port, alg_key.ip_address);
+
+       struct sip_alg_table_entry *new_alg_data =
+                       retrieve_sip_alg_entry(&alg_key);
+
+       if (new_alg_data) {
+               if (ALG_DEBUG)
+                       printf("sip_alg_entry exists ip%x, port %d\n",
+                                                alg_key.ip_address, alg_key.l4port);
+               return 0;
+       }
+
+       new_alg_data = NULL;
+       new_alg_data = (struct sip_alg_table_entry *)
+                       malloc(sizeof(struct sip_alg_table_entry));
+       if (new_alg_data == NULL) {
+               printf("populate sip alg entry: allocation failed\n");
+               return -1;
+       }
+
+       new_alg_data->l4port = portid;
+       new_alg_data->ip_address = ipaddr;
+       new_alg_data->l4port_type = port_type;
+       new_alg_data->sip_alg_call_direction = call_direction;
+       strcpy((char *)new_alg_data->sip_alg_call_id, (char *)sip_call_id);
+       new_alg_data->filler1 = 0;
+       new_alg_data->filler2 = 0;
+       new_alg_data->filler3 = 0;
+
+       ret = rte_hash_add_key(sip_alg_hash_table, &alg_key);
+       if (ret < 0) {
+               printf("populate sip - rte_hash_add_key_data ERROR %d\n", ret);
+               free(new_alg_data);
+               return -1;
+       }
+
+       sip_alg_table[ret] = new_alg_data;
+
+       if (ALG_DEBUG) {
+               printf("SIP_ALG: table update - ip=%x on port=%d ret=%d\n",
+                                        alg_key.ip_address, portid, ret);
+       }
+       return 0;
+}
+
+int sip_alg_dpi(struct rte_mbuf *pkt, enum pkt_dir pkt_direction,
+               uint32_t modIp, uint16_t modL4Port,
+               uint32_t pubIp, uint16_t pubL4Port,
+               uint16_t modRtpPort, uint16_t modRtcpPort)
+{
+       uint16_t msgType = 0;
+       enum sip_alg_call_direction call_direction = 0;
+       uint32_t ip_address = 0;
+       uint16_t port = 0;
+       int ret = 0;
+       struct ipv4_hdr *ip_h;
+       struct ether_hdr *eth_h = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+       struct udp_hdr *udp_h;
+       char *pSipMsg = NULL;
+       struct sip_alg_table_entry *sip_alg_entry;
+       char *sip_call_id = NULL;
+       int pos = 0;
+       struct sip_alg_key alg_key;
+       uint16_t diffModSipLen = 0;
+
+       ip_h = (struct ipv4_hdr *)((char *)eth_h + sizeof(struct ether_hdr));
+       udp_h = (struct udp_hdr *)((char *)ip_h + sizeof(struct ipv4_hdr));
+       pSipMsg = ((char *)udp_h + sizeof(struct udp_hdr));
+
+       if (ALG_DEBUG) {
+       printf("%s: packet length(%u), buffer length(%u)\n", __func__,
+               rte_pktmbuf_pkt_len(pkt), pkt->buf_len);
+       printf("%s: last segment addr(%p %p)\n", __func__,
+               rte_pktmbuf_lastseg(pkt), pkt);
+       printf("%s: data len(%u, %u)\n", __func__, rte_pktmbuf_data_len(pkt),
+               rte_pktmbuf_data_len(rte_pktmbuf_lastseg(pkt)));
+       printf("%s: buffer addr(%p), data_off(%u), nb_segs(%u)\n", __func__,
+               pkt->buf_addr, pkt->data_off, pkt->nb_segs);
+       }
+
+       if (IS_STRING_SAME(pSipMsg, SIP_ALG_INVITE)) {
+               /* find the call id position in the message */
+               if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_CALLID, &pos, 0) ==
+                               TRUE)
+                       sip_call_id =
+                                       getSipCallIdStr(pSipMsg + pos +
+                                                       TAG_TO_DATAPOS(SIP_ALG_CALLID));
+
+               if (ALG_DEBUG)
+                       printf("sipalgdpi: %d call id %s\n", __LINE__,
+                                                sip_call_id);
+
+               if (pkt_direction == PRIVATE) {
+                       call_direction = SIP_CALL_OUTGOING;
+                       ip_address = rte_bswap32(ip_h->src_addr);
+                       port = rte_bswap16(udp_h->src_port);
+               } else if (pkt_direction == PUBLIC) {
+                       call_direction = SIP_CALL_INCOMING;
+                       ip_address = pubIp;
+                       port = pubL4Port;
+               }
+
+               if (ALG_DEBUG)
+                       printf("0=>sip_alg_dpi: pkt_dir(%d), call_dir(%d), "
+                                               "ipaddr(%x) port(%x)\n",
+                                        pkt_direction, call_direction, ip_address, port);
+
+               /* add 3 entries in ALG table for SIP, RTP, RTCP */
+               ret = populate_sip_alg_entry(ip_address, port,
+                                                        sip_call_id, call_direction,
+                                                        SIP_UDP);
+               if (ret < 0) {
+                       printf("sipalgdpi:populate SIP alg UDP entry failed\n");
+                       return 0;
+               }
+               if (modRtpPort != 0) {
+                       ret = populate_sip_alg_entry(ip_address, modRtpPort,
+                                                                sip_call_id,
+                                                                call_direction, SIP_RTP);
+                       if (ret < 0) {
+                               printf("sipalgdpi: "
+                                       "populate SIP alg entry RTP failed\n");
+                               return 0;
+                       }
+               }
+               if (modRtcpPort != 0) {
+                       ret = populate_sip_alg_entry(ip_address, modRtcpPort,
+                                                                sip_call_id,
+                                                                call_direction, SIP_RTCP);
+                       if (ret < 0) {
+                               printf("sipalgdpi: "
+                               "populate SIP alg entry RTCP failed\n");
+                               return 0;
+                       }
+               }
+
+/* Call ALG packet process function for checking & payload modification */
+               pSipMsg =
+                               sip_alg_process(pkt, pkt_direction, call_direction,
+                                               SIP_ALG_INVITE_MSGTYPE, modIp, modL4Port, 0,
+                                               0, modRtpPort, modRtcpPort, &diffModSipLen);
+       } else {
+       /*
+        * not SIP INVITE, could be SIP response 200 OK invite, 100 trying,
+        * 180 ringing or BYE or 200 OK BYe
+        */
+               /* retrieve ALG entry from SIP ALG table */
+               if (pkt_direction == PRIVATE) {
+                       alg_key.ip_address = rte_bswap32(ip_h->src_addr);
+                       alg_key.l4port = rte_bswap16(udp_h->src_port);
+               } else {
+                       alg_key.ip_address = pubIp;
+                       alg_key.l4port = pubL4Port;
+               }
+
+               alg_key.filler1 = 0;
+               alg_key.filler2 = 0;
+               sip_alg_entry = retrieve_sip_alg_entry(&alg_key);
+
+               if (ALG_DEBUG) {
+                       printf("%s: sip_alg_entry_ptr(%p)\n", __func__,
+                                                sip_alg_entry);
+                       printf("1=>%s: pkt_dir(%d), modIp(%x),modL4Port(%x), "
+               "modRtpPort(%x), modRtcpPort(%x), pubIp(%x), pubL4Port(%x)\n",
+                                        __func__, pkt_direction, modIp, modL4Port,
+                                        modRtpPort, modRtcpPort, pubIp, pubL4Port);
+               }
+
+               if (sip_alg_entry) {
+                       call_direction = sip_alg_entry->sip_alg_call_direction;
+                       if (IS_STRING_SAME(pSipMsg, SIP_ALG_BYE) ||
+                                       IS_STRING_SAME(pSipMsg, SIP_ALG_CANCEL)) {
+                               msgType = SIP_ALG_BYE_MSGTYPE;
+
+                               goto sipAlgProcess;
+                       } else if (IS_STRING_SAME(pSipMsg, SIP_ALG_ACK)) {
+                               msgType = SIP_ALG_ACK_MSGTYPE;
+
+                               goto sipAlgProcess;
+                       }
+
+                       pSipMsg += 8;
+               /* checking if its OK or Trying or Ringing */
+                       if (IS_STRING_SAME(pSipMsg, SIP_ALG_200_OK)) {
+                       /* check CSEQ. Based on that update the msg type */
+                               if (natSipAlgMsgFieldPos
+                                               (pSipMsg, SIP_ALG_CSEQ, &pos, 0) == TRUE) {
+                                       char *pBye;
+
+                                       pBye =
+                                                       pSipMsg + pos +
+                                                       TAG_TO_DATAPOS(SIP_ALG_CSEQ);
+                                       SKIP_SPACES(pBye);
+                                       /* skip the number field */
+                                       while (*pBye != ' ')
+                                               pBye++;
+                                       SKIP_SPACES(pBye);
+                                       if (IS_STRING_SAME(pBye, SIP_ALG_BYE)
+                                                       ||
+                                                       (IS_STRING_SAME
+                                                        (pBye, SIP_ALG_CANCEL)))
+                                               msgType =
+                                                               SIP_ALG_200_OK_BYE_MSGTYPE;
+
+                                       else
+                                               msgType =
+                                                       SIP_ALG_200_OK_INVITE_MSGTYPE;
+                               }
+                       } else if (IS_STRING_SAME(pSipMsg, SIP_ALG_TRYING) ||
+                                        IS_STRING_SAME(pSipMsg, SIP_ALG_RINGING)) {
+                               msgType = SIP_ALG_TRYING_RINGING_MSGTYPE;
+                       }
+
+ sipAlgProcess:
+                       if (ALG_DEBUG)
+                               printf("2=>%s: pkt_dir(%d), call_dir(%d), "
+                               "msgType(%d), modIp(%x), modL4Port(%x), "
+                               " modRtpPort(%x), modRtcpPort(%x)\n",
+                                                __func__, pkt_direction, call_direction,
+                                                msgType, modIp, modL4Port, modRtpPort,
+                                                modRtcpPort);
+                       /* Call SIP alg processing for further processing. */
+                       pSipMsg =
+                                       sip_alg_process(pkt, pkt_direction, call_direction,
+                                                       msgType, modIp, modL4Port, pubIp,
+                                                       pubL4Port, modRtpPort, modRtcpPort,
+                                                       &diffModSipLen);
+               } else
+                       pSipMsg = NULL;
+       }
+
+       if (ALG_DEBUG)
+               printf("%s: Before IP total length(%u), udp length(%u)\n", __func__,
+               rte_bswap16(ip_h->total_length), rte_bswap16(udp_h->dgram_len));
+       /*
+        * need to modify mbuf & modified length of payload in the IP/UDP
+        * header length fields and return to CGNAT for transmitting
+        */
+       uint16_t len = 0;
+       if (diffModSipLen > 0) {
+               len = rte_bswap16(udp_h->dgram_len);
+               len += diffModSipLen;
+               udp_h->dgram_len = rte_bswap16(len);
+
+               len = rte_bswap16(ip_h->total_length);
+               len += diffModSipLen;
+               ip_h->total_length = rte_bswap16(len);
+
+               if (rte_pktmbuf_append(pkt, diffModSipLen) == NULL)
+                       printf("%s: pktmbuf_append returns NULL", __func__);
+
+       }
+
+       if (ALG_DEBUG)
+               printf("%s: After IP total length(%u), udp length(%u), "
+               "diffModSipLen(%u)\n", __func__,
+               rte_bswap16(ip_h->total_length),
+               rte_bswap16(udp_h->dgram_len),
+               diffModSipLen);
+
+       if (pSipMsg != NULL)
+               return 1;
+       else
+               return 0;
+}
+
+char *sip_alg_process(struct rte_mbuf *pkt, uint16_t pkt_direction,
+                                       uint16_t call_direction, uint16_t msgType, uint32_t modIp,
+                                       uint16_t modL4Port, uint32_t pubIp, uint16_t pubL4Port,
+                                       uint16_t modRtpPort, uint16_t modRtcpPort,
+                                       uint16_t *diffModSipLen)
+{
+       struct ipv4_hdr *ip_h;
+       struct ether_hdr *eth_h = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+       struct udp_hdr *udp_h;
+       char *pSipMsg, *pStr, *pEndPtr;
+       int pos;
+       /* diff between old & new modified field len */
+       uint32_t diffLen, addrPortLen;
+       int sdpMsgLen = 0;
+       int sip_msg_len = 0;
+
+       ip_h = (struct ipv4_hdr *)((char *)eth_h + sizeof(struct ether_hdr));
+       udp_h = (struct udp_hdr *)((char *)ip_h + sizeof(struct ipv4_hdr));
+       pSipMsg = ((char *)udp_h + sizeof(struct udp_hdr));
+       char *pTmpSipMsg = pSipMsg;
+       char *pStartSipMsg = pSipMsg;
+
+       sip_msg_len =
+                       rte_bswap16(ip_h->total_length) - sizeof(struct ipv4_hdr) -
+                       sizeof(struct udp_hdr);
+
+       if (natSipAlgMsgFieldPos(pTmpSipMsg, SIP_ALG_CONTENT_LEN, &pos, 0) ==
+                       TRUE)
+               pTmpSipMsg += (pos + TAG_TO_DATAPOS(SIP_ALG_CONTENT_LEN));
+       else {
+               printf("sip_alg_process: Invalid Content Length\n");
+               return NULL;
+       }
+
+       SKIP_SPACES(pTmpSipMsg);
+       int sdpDataLen = strtol(pTmpSipMsg, &pStr, 10);
+
+       natSipAlgMsgFieldPosFindCrlf(pTmpSipMsg, SIP_ALG_DOUBLE_CRLF, &pos, 0);
+       pTmpSipMsg += (pos + strlen(SIP_ALG_DOUBLE_CRLF));
+
+       if (sdpDataLen != 0)
+               if (natSipAlgMsgFieldPos
+                               (pTmpSipMsg, SIP_ALG_REMOTE_PARTY_ID, &pos, 0) == TRUE) {
+                       pTmpSipMsg += pos + strlen(SIP_ALG_REMOTE_PARTY_ID);
+                       /* move further to CRLF which is the end of SIP msg */
+                       natSipAlgMsgFieldPosFindCrlf(pTmpSipMsg,
+                                                                SIP_ALG_DOUBLE_CRLF, &pos,
+                                                                0);
+                       pTmpSipMsg += (pos + strlen(SIP_ALG_DOUBLE_CRLF));
+               }
+
+       int sipMsgLen = (pTmpSipMsg - pSipMsg);
+
+       char *pSipMsgEnd = pSipMsg + sipMsgLen + sdpDataLen;
+
+       if (ALG_DEBUG)
+               printf("%s: pSipMsg: %p, pSipMsgEnd: %p, sipMsgLen: %d, "
+                               "sdpDataLen: %d totalSipMsgLen: %d\n",
+                                __func__, pSipMsg, pSipMsgEnd, sipMsgLen, sdpDataLen,
+                                sip_msg_len);
+
+       if (call_direction == SIP_CALL_OUTGOING) {
+               if ((msgType == SIP_ALG_INVITE_MSGTYPE)
+                               || (msgType == SIP_ALG_ACK_MSGTYPE)) {
+                       /* Get to Via field IP address/Port to modify */
+                       if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_VIA, &pos, 0)
+                                       == TRUE) {
+                               /* advance to IP/Port string */
+                               pSipMsg +=
+                                               (pos + strlen(SIP_ALG_VIA) +
+                                                SIP_ALG_VIA_FIELD_IPADDR);
+                               pTmpSipMsg = pSipMsg;
+                               /* move pTmp to next field */
+                               natSipAlgMsgFieldPos(pTmpSipMsg,
+                                                                SIP_ALG_SEMICOLON, &pos,
+                                                                0);
+                               pTmpSipMsg += pos;
+                               addrPortLen = pTmpSipMsg - pSipMsg;
+                       } else {
+                               printf("sip_alg_process; No valid VIA field\n");
+                               return NULL;
+                       }
+                       /* Modify VIA field IP addr:port in payload */
+                       pSipMsg =
+                                       natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+                                                                addrPortLen,
+                                                                &diffLen, modIp,
+                                                                modL4Port,
+                                                                ADDRESS_PORT_STRING);
+
+                       *diffModSipLen += diffLen;
+/* increase the overall diff between old & mod sip msg */
+
+                       /* Advance to "From" field IP addr in payload */
+                       if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_FROM, &pos, 0)
+                                       == TRUE) {
+                               pSipMsg += pos; /* Moving to "From" */
+                               /* advance to IP/Port string */
+                               pTmpSipMsg = pSipMsg;
+/* move pTmpSipMsg to str ">" which is end of add:port string */
+                               natSipAlgMsgFieldPos(pTmpSipMsg, SIP_ALG_GREAT,
+                                                                &pos, 0);
+                               pTmpSipMsg += pos;
+                               diffLen = pTmpSipMsg - pSipMsg;
+/* find "@" from "From" string to ">" string which is start of "addr:port" */
+                               natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos,
+                                                                0);
+                               pSipMsg += pos + 1;
+/* now its pointing to start of From field "address:port" */
+                               addrPortLen = pTmpSipMsg - pSipMsg;
+                       } else {
+                               printf
+                                               ("sip_alg_process; No valid From field\n");
+                               return NULL;
+                       }
+                       /* Modify "From" field "addr:port" in payload */
+                       pSipMsg =
+                                       natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+                                                                addrPortLen,
+                                                                &diffLen, modIp,
+                                                                modL4Port,
+                                                                ADDRESS_PORT_STRING);
+
+                       *diffModSipLen += diffLen;
+/* increase the overall diff between old & mod sip msg */
+
+                       /* Advance to Call id field */
+                       if (natSipAlgMsgFieldPos
+                                       (pSipMsg, SIP_ALG_CALLID, &pos, 0) == TRUE) {
+                               pSipMsg += pos;
+/* moving it to start of string "Call-ID" */
+                               pTmpSipMsg = pSipMsg;
+                               /* move tmpSipMsg to next field */
+                               natSipAlgMsgFieldPosFindCrlf(pTmpSipMsg,
+                                                                        SIP_ALG_CRLF, &pos,
+                                                                        0);
+                               pTmpSipMsg += pos;
+                               diffLen = pTmpSipMsg - pSipMsg;
+               /* Move pSipMsg to start of Call id "IP addr" string */
+                               natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos,
+                                                                0);
+                               pSipMsg += pos + 1;
+                               addrPortLen = pTmpSipMsg - pSipMsg;
+                       } else {
+                               printf("sip_alg_process; "
+                                       " No valid Call Id field\n");
+                               return NULL;
+                       }
+                       /* Modify "Call-id" field "addr:port" in payload */
+/* L4 port input is made as 0 as its only addr string modification */
+                       pSipMsg =
+                                       natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+                                                                addrPortLen,
+                                                                &diffLen, modIp, 0,
+                                                                ADDRESS_PORT_STRING);
+
+                       *diffModSipLen += diffLen;
+
+                       /* Advance to "Contact" field */
+                       if (natSipAlgMsgFieldPos
+                                       (pSipMsg, SIP_ALG_CONTACT, &pos, 0) == TRUE) {
+                               pSipMsg += pos;
+                               /* move tmpMsg to CRLF */
+                               pTmpSipMsg = pSipMsg;
+                               natSipAlgMsgFieldPosFindCrlf(pTmpSipMsg,
+                                                                        SIP_ALG_CRLF, &pos,
+                                                                        0);
+                               pTmpSipMsg += pos;
+                               /* move sipMsg to addr:port string */
+                               natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos,
+                                                                0);
+                               pSipMsg += pos + 1;
+                               addrPortLen = pTmpSipMsg - pSipMsg;
+
+                       } else {
+                               printf("sip_alg_process; "
+                                       "No valid Call Id field\n");
+                               return NULL;
+                       }
+                       /* Modify "Contact" field "addr:port" in payload */
+                       pSipMsg =
+                                       natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+                                                                addrPortLen,
+                                                                &diffLen, modIp,
+                                                                modL4Port,
+                                                                ADDRESS_PORT_STRING);
+
+                       *diffModSipLen += diffLen;
+
+                       if (msgType == SIP_ALG_INVITE_MSGTYPE) {
+/* Advance to check content type & get content length (SDP length) */
+                               if (natSipAlgMsgFieldPos
+                                               (pSipMsg, SIP_ALG_CONTYPE, &pos,
+                                                0) == TRUE) {
+                                       pSipMsg +=
+                                                       (pos +
+                                                        TAG_TO_DATAPOS(SIP_ALG_CONTYPE));
+                                       SKIP_SPACES(pSipMsg);
+                       /*check the application/sdp type, if not, exit */
+                                       if (!IS_STRING_SAME
+                                                       (pSipMsg, SIP_ALG_APPSDP)) {
+                                               printf("sip_alg_process "
+                                               "Invalid Content type\n");
+                                               return NULL;
+                                       }
+                               } else {
+                                       printf("sip_alg_process; "
+                                               "No valid Content field\n");
+                                       return NULL;
+                               }
+
+                               /* get the SDP content length */
+                               natSipAlgMsgFieldPos(pSipMsg,
+                                                                SIP_ALG_CONTENT_LEN, &pos,
+                                                                0);
+                               pSipMsg +=
+                                               (pos + TAG_TO_DATAPOS(SIP_ALG_CONTENT_LEN));
+                               SKIP_SPACES(pSipMsg);
+                               sdpMsgLen = strtol(pSipMsg, &pEndPtr, 10);
+                               if (!sdpMsgLen) {
+/* if ACK message, SDP content wont be there.go to ALG process complete */
+                                       if (msgType == SIP_ALG_ACK_MSGTYPE)
+                                               goto sipAlgProcessExit;
+
+                                       printf("sip_alg_process - "
+                                               "sdpMsgLen is 0\n");
+                                       return NULL;
+                               }
+
+                               /* Advance to SDP data message Owner address */
+                               if (natSipAlgMsgFieldPos
+                                               (pSipMsg, SIP_ALG_OWNER, &pos,
+                                                0) == TRUE) {
+                                       pSipMsg += pos;
+                       /* at start of owner string "o=" */
+                                       pTmpSipMsg = pSipMsg;
+                                       /* move tmmsg to CRLF of owner field */
+                                       natSipAlgMsgFieldPosFindCrlf(pSipMsg,
+                                                                        SIP_ALG_CRLF,
+                                                                        &pos,
+                                                                        0);
+                                       pTmpSipMsg += pos;
+/* start of CRLF "/r/n" */
+/* move pSipMsg to IP address string in owner field */
+                                       natSipAlgMsgFieldPos(pSipMsg,
+                                                                        SIP_ALG_IPV4, &pos,
+                                                                        0);
+                                       pSipMsg += (pos + strlen(SIP_ALG_IPV4));
+                                       SKIP_SPACES(pSipMsg);
+/* after skipping spaces, pSip at start of addr */
+                                       addrPortLen = pTmpSipMsg - pSipMsg;
+                               } else {
+                                       printf("sip_alg_processing: "
+                                               "Invalid Owner field\n");
+                                       return NULL;
+                               }
+/* Modify "Owner" field "addr" in payload.  Input L4 port as 0 */
+                               pSipMsg =
+                                               natSipAlgModifyPayloadAddrPort(pSipMsg,
+                                                                        &pSipMsgEnd,
+                                                                        addrPortLen,
+                                                                        &diffLen,
+                                                                        modIp, 0,
+                                                                ADDRESS_PORT_STRING);
+
+                               *diffModSipLen += diffLen;
+                               sdpMsgLen += diffLen;
+/* need to adjust the SDP msg len as modification done. */
+
+/* Advance to Connection information to modify IP address */
+                               if (natSipAlgMsgFieldPos
+                                               (pSipMsg, SIP_ALG_CONN, &pos,
+                                                0) == TRUE) {
+                                       pSipMsg += pos;
+                                       pTmpSipMsg = pSipMsg;
+                                       /* move tmmsg to CRLF of owner field */
+                                       natSipAlgMsgFieldPosFindCrlf(pSipMsg,
+                                                                        SIP_ALG_CRLF,
+                                                                                &pos,
+                                                                                0);
+                                       pTmpSipMsg += pos;
+                       /* start of CRLF "/r/n" */
+                       /* move pSipMsg to IP address string in owner field */
+                                       natSipAlgMsgFieldPos(pSipMsg,
+                                                                        SIP_ALG_IPV4, &pos,
+                                                                        0);
+                                       pSipMsg += (pos + strlen(SIP_ALG_IPV4));
+                                       SKIP_SPACES(pSipMsg);
+/* after skipping spaces, pSip at start of addr */
+                                       addrPortLen = pTmpSipMsg - pSipMsg;
+                               } else {
+                                       printf("sip_alg_processing: "
+                                               "Invalid Owner field\n");
+                                       return NULL;
+                               }
+/* Modify "Connection" field "addr" in payload.  Input L4 port as 0 */
+                               pSipMsg =
+                                               natSipAlgModifyPayloadAddrPort(pSipMsg,
+                                                                        &pSipMsgEnd,
+                                                                        addrPortLen,
+                                                                        &diffLen,
+                                                                        modIp, 0,
+                                                                ADDRESS_PORT_STRING);
+
+                               *diffModSipLen += diffLen;
+                               sdpMsgLen += diffLen;
+/* need to adjust the SDP msg len as modification done. */
+
+                               /* Advance to RTP audio port */
+                               if (natSipAlgMsgFieldPos
+                                               (pSipMsg, SIP_ALG_AUDIO, &pos,
+                                                0) == TRUE) {
+                                       pSipMsg +=
+                                                       (pos +
+                                                        TAG_TO_DATAPOS(SIP_ALG_AUDIO));
+                                       SKIP_SPACES(pSipMsg);
+                                       pTmpSipMsg = pSipMsg;
+                                       natSipAlgMsgFieldPosFindSpace
+                                                       (pTmpSipMsg, SIP_ALG_SPACE, &pos,
+                                                        0);
+                                       pTmpSipMsg += pos;
+                                       addrPortLen = pTmpSipMsg - pSipMsg;
+                               }
+
+/* Modify "RTP Audio" port in payload. pass pub_ip as 0. */
+                               pSipMsg =
+                                               natSipAlgModifyPayloadAddrPort(pSipMsg,
+                                                                        &pSipMsgEnd,
+                                                                        addrPortLen,
+                                                                        &diffLen, 0,
+                                                                        modRtpPort,
+                                                                        PORT_STRING);
+
+                               *diffModSipLen += diffLen;
+                               sdpMsgLen += diffLen;
+/* need to adjust the SDP msg len as modification done. */
+
+                               /* Advance to RTCP control port, if its there */
+                               if (natSipAlgMsgFieldPos
+                                               (pSipMsg, SIP_ALG_RTCP, &pos,
+                                                0) == TRUE) {
+                                       pSipMsg +=
+                                                       (pos +
+                                                        TAG_TO_DATAPOS(SIP_ALG_RTCP));
+                                       SKIP_SPACES(pSipMsg);
+                                       pTmpSipMsg = pSipMsg;
+                                       natSipAlgMsgFieldPosFindSpace
+                                                       (pTmpSipMsg, SIP_ALG_SPACE, &pos,
+                                                        0);
+                                       pTmpSipMsg += pos;
+                                       addrPortLen = pTmpSipMsg - pSipMsg;
+
+/* Modify "RTP Audio" port in payload. pass pub_ip as 0. */
+                                       pSipMsg =
+                                                       natSipAlgModifyPayloadAddrPort
+                                                       (pSipMsg, &pSipMsgEnd, addrPortLen,
+                                                        &diffLen, 0, modRtcpPort,
+                                                        PORT_STRING);
+
+                                       *diffModSipLen += diffLen;
+                                       sdpMsgLen += diffLen;
+/* need to adjust the SDP msg len as modification done. */
+                               }
+                       }
+/* with this SIP payload modification is complete for outbound invite message */
+               } else if ((msgType == SIP_ALG_TRYING_RINGING_MSGTYPE)
+                                || (msgType == SIP_ALG_200_OK_INVITE_MSGTYPE)) {
+                       /* Get to Via field IP address/Port to modify */
+                       if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_VIA, &pos, 0)
+                                       == TRUE) {
+                               /* advance to IP/Port string */
+                               pSipMsg +=
+                                               (pos + strlen(SIP_ALG_VIA) +
+                                                SIP_ALG_VIA_FIELD_IPADDR);
+                               pTmpSipMsg = pSipMsg;
+                               /* move pTmp to next field */
+                               natSipAlgMsgFieldPos(pTmpSipMsg,
+                                                                SIP_ALG_SEMICOLON, &pos,
+                                                                0);
+                               pTmpSipMsg += pos;
+                               addrPortLen = pTmpSipMsg - pSipMsg;
+                       } else {
+                               printf("sip_alg_process; No valid VIA field\n");
+                               return NULL;
+                       }
+                       /* Modify VIA field IP addr:port in payload */
+                       pSipMsg =
+                                       natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+                                                                addrPortLen,
+                                                                &diffLen, modIp,
+                                                                modL4Port,
+                                                                ADDRESS_PORT_STRING);
+                       *diffModSipLen = diffLen;
+
+                       /* Advance to "From" field IP addr in payload */
+                       if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_FROM, &pos, 0)
+                                       == TRUE) {
+                               pSipMsg += pos; /* Moving to "From" */
+                               /* advance to IP/Port string */
+                               pTmpSipMsg = pSipMsg;
+/* move pTmpSipMsg to str ">" which is end of add:port string */
+                               natSipAlgMsgFieldPos(pTmpSipMsg, SIP_ALG_GREAT,
+                                                                &pos, 0);
+                               pTmpSipMsg += pos;
+                               //diffLen = pTmpSipMsg - pSipMsg;
+/* find "@" from "From" string to ">" string which is start of "addr:port" */
+                               natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos,
+                                                                0);
+                               pSipMsg += pos + 1;
+/* now its pointing to start of From field "address:port" */
+                               addrPortLen = pTmpSipMsg - pSipMsg;
+                       } else {
+                               printf
+                                               ("sip_alg_process; No valid From field\n");
+                               return NULL;
+                       }
+                       /* Modify "From" field "addr:port" in payload */
+                       pSipMsg =
+                                       natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+                                                                addrPortLen,
+                                                                &diffLen, modIp,
+                                                                modL4Port,
+                                                                ADDRESS_PORT_STRING);
+
+                       *diffModSipLen += diffLen;
+/* increase the overall diff between old & mod sip msg */
+
+                       /* Advance to Call id field */
+                       if (natSipAlgMsgFieldPos
+                                       (pSipMsg, SIP_ALG_CALLID, &pos, 0) == TRUE) {
+                               pSipMsg += pos;
+/* moving it to start of string "Call-ID" */
+                               pTmpSipMsg = pSipMsg;
+                               /* move tmpSipMsg to next field */
+                               natSipAlgMsgFieldPosFindCrlf(pTmpSipMsg,
+                                                                        SIP_ALG_CRLF, &pos,
+                                                                        0);
+                               pTmpSipMsg += pos;
+                               //diffLen = pTmpSipMsg - pSipMsg;
+               /* Move pSipMsg to start of Call id "IP addr" string */
+                               natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos,
+                                                                0);
+                               pSipMsg += pos + 1;
+                               addrPortLen = pTmpSipMsg - pSipMsg;
+                       } else {
+                               printf("sip_alg_process; "
+                                       "No valid Call Id field\n");
+                               return NULL;
+                       }
+                       /* Modify "Call-id" field "addr" in payload */
+/* L4 port input is made as 0 as its only addr string modification */
+                       pSipMsg =
+                                       natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+                                                                addrPortLen,
+                                                                &diffLen, modIp, 0,
+                                                                ADDRESS_PORT_STRING);
+
+                       *diffModSipLen += diffLen;
+
+               } else if (pkt_direction == PRIVATE
+                                && msgType == SIP_ALG_BYE_MSGTYPE) {
+                       /* change via, from, call-id and contact field */
+
+                       /* Get to Via field IP address to modify */
+                       if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_VIA, &pos, 0)
+                                       == TRUE) {
+                               /* advance to IP/Port string */
+                               pSipMsg +=
+                                               (pos + strlen(SIP_ALG_VIA) +
+                                                SIP_ALG_VIA_FIELD_IPADDR);
+                               pTmpSipMsg = pSipMsg;
+                               /* move pTmp to next field */
+                               natSipAlgMsgFieldPos(pTmpSipMsg,
+                                                                SIP_ALG_SEMICOLON, &pos,
+                                                                0);
+                               pTmpSipMsg += pos;
+                               addrPortLen = pTmpSipMsg - pSipMsg;
+                       } else {
+                               printf("sip_alg_process; No valid VIA field\n");
+                               return NULL;
+                       }
+                       /* Modify VIA field IP addr in payload */
+                       pSipMsg =
+                                       natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+                                                                addrPortLen,
+                                                                &diffLen, modIp, 0,
+                                                                ADDRESS_PORT_STRING);
+                       *diffModSipLen = diffLen;
+
+                       /* Advance to "From" field IP addr in payload */
+                       if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_FROM, &pos, 0)
+                                       == TRUE) {
+                               pSipMsg += pos; /* Moving to "From" */
+                               /* advance to IP/Port string */
+                               pTmpSipMsg = pSipMsg;
+/* move pTmpSipMsg to str ">" which is end of add:port string */
+                               natSipAlgMsgFieldPos(pTmpSipMsg, SIP_ALG_GREAT,
+                                                                &pos, 0);
+                               pTmpSipMsg += pos;
+                               diffLen = pTmpSipMsg - pSipMsg;
+/* find "@" from "From" string to ">" string which is start of "addr:port" */
+                               natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos,
+                                                                0);
+                               pSipMsg += pos + 1;
+/* now its pointing to start of From field "address:port" */
+                               addrPortLen = pTmpSipMsg - pSipMsg;
+                       } else {
+                               printf
+                                               ("sip_alg_process; No valid From field\n");
+                               return NULL;
+                       }
+                       /* Modify "From" field "addr:port" in payload */
+                       pSipMsg =
+                                       natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+                                                                addrPortLen,
+                                                                &diffLen, modIp,
+                                                                modL4Port,
+                                                                ADDRESS_PORT_STRING);
+
+                       *diffModSipLen += diffLen;
+/* increase the overall diff between old & mod sip msg */
+
+                       /* Advance to Call id field */
+                       if (natSipAlgMsgFieldPos
+                                       (pSipMsg, SIP_ALG_CALLID, &pos, 0) == TRUE) {
+                               pSipMsg += pos;
+/* moving it to start of string "Call-ID" */
+                               pTmpSipMsg = pSipMsg;
+                               /* move tmpSipMsg to next field */
+                               natSipAlgMsgFieldPosFindCrlf(pTmpSipMsg,
+                                                                        SIP_ALG_CRLF, &pos,
+                                                                        0);
+                               pTmpSipMsg += pos;
+                               diffLen = pTmpSipMsg - pSipMsg;
+               /* Move pSipMsg to start of Call id "IP addr" string */
+                               natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos,
+                                                                0);
+                               pSipMsg += pos + 1;
+                               addrPortLen = pTmpSipMsg - pSipMsg;
+                       } else {
+                               printf("sip_alg_process; "
+                                       "No valid Call Id field\n");
+                               return NULL;
+                       }
+                       /* Modify "Call-id" field "addr:port" in payload */
+       /* L4 port input is made as 0 as its only addr string modification */
+                       pSipMsg =
+                                       natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+                                                                addrPortLen,
+                                                                &diffLen, modIp, 0,
+                                                                ADDRESS_PORT_STRING);
+
+                       *diffModSipLen += diffLen;
+
+                       /* Advance to "Contact" field */
+                       if (natSipAlgMsgFieldPos
+                                       (pSipMsg, SIP_ALG_CONTACT, &pos, 0) == TRUE) {
+                               pSipMsg += pos;
+                               /* move tmpMsg to semicolon */
+                               pTmpSipMsg = pSipMsg;
+                               natSipAlgMsgFieldPosFindCrlf(pTmpSipMsg,
+                                       SIP_ALG_CRLF, &pos, 0);
+                               pTmpSipMsg += pos;
+                               /* move sipMsg to addr:port string */
+                               int flag = 0;
+                               if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT,
+                                               &pos, 0) == FALSE)
+                                       flag = 1;
+
+                               if (flag)
+                                       goto SipMsgAdvance2;
+                               pSipMsg += pos + 1;
+                               addrPortLen = pTmpSipMsg - pSipMsg;
+
+                       } else {
+                               printf("sip_alg_process; "
+                                       "No valid Call Id field\n");
+                               return NULL;
+                       }
+                       /* Modify "Contact" field "addr:port" in payload */
+                       pSipMsg =
+                                       natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+                                                                addrPortLen,
+                                                                &diffLen, modIp,
+                                                                modL4Port,
+                                                                ADDRESS_PORT_STRING);
+
+                       *diffModSipLen += diffLen;
+               } else if (pkt_direction == PUBLIC
+                                && msgType == SIP_ALG_BYE_MSGTYPE) {
+                       /*
+                        * Modify Bye URL (if its BYE), To field,
+                        * Call-Id if call triggered from private, then modify
+                        */
+
+                       /* need to modify address:Port in Bye message string. */
+                       natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos, 0);
+                       pSipMsg += pos + 1;
+                       pTmpSipMsg = pSipMsg;
+                       natSipAlgMsgFieldPosFindSpace(pTmpSipMsg, SIP_ALG_SPACE,
+                                                                       &pos, 0);
+                       pTmpSipMsg += pos;
+                       addrPortLen = pTmpSipMsg - pSipMsg;
+                       /* modify the "addr:port" in Bye message line */
+                       pSipMsg =
+                                       natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+                                                                addrPortLen,
+                                                                &diffLen, modIp,
+                                                                modL4Port,
+                                                                ADDRESS_PORT_STRING);
+                       *diffModSipLen += diffLen;
+/* increase the overall diff between old & mod sip msg */
+
+                       /* Advance to 'To" field */
+                       if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_TO, &pos, 0)
+                                       == TRUE) {
+                               pSipMsg += pos;
+                               pTmpSipMsg = pSipMsg;
+                               natSipAlgMsgFieldPos(pTmpSipMsg, SIP_ALG_GREAT,
+                                                                &pos, 0);
+                               pTmpSipMsg += pos;
+                               natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos,
+                                                                0);
+                               pSipMsg += pos + 1;
+                               addrPortLen = pTmpSipMsg - pSipMsg;
+                               pSipMsg =
+                                               natSipAlgModifyPayloadAddrPort(pSipMsg,
+                                                                        &pSipMsgEnd,
+                                                                        addrPortLen,
+                                                                        &diffLen,
+                                                                        modIp,
+                                                                        modL4Port,
+                                                                ADDRESS_PORT_STRING);
+                               *diffModSipLen += diffLen;
+/* increase the overall diff between old & mod sip msg */
+                       }
+
+                       /* check for Call-Id. */
+                       if (natSipAlgMsgFieldPos
+                                       (pSipMsg, SIP_ALG_CALLID, &pos, 0) == TRUE) {
+                               pSipMsg += pos;
+/* moving it to start of string "Call-ID" */
+                               pTmpSipMsg = pSipMsg;
+                               /* move tmpSipMsg to next field */
+                               natSipAlgMsgFieldPosFindCrlf(pTmpSipMsg,
+                                                                        SIP_ALG_CRLF, &pos,
+                                                                        0);
+                               pTmpSipMsg += pos;
+                               //diffLen = pTmpSipMsg - pSipMsg;
+               /* Move pSipMsg to start of Call id "IP addr" string */
+                               natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos,
+                                                                0);
+                               pSipMsg += pos + 1;
+                               addrPortLen = pTmpSipMsg - pSipMsg;
+                       } else {
+                               printf("sip_alg_process; "
+                                       "No valid Call Id field\n");
+                               return NULL;
+                       }
+                       /* Modify "Call-id" field "addr" in payload */
+       /* L4 port input is made as 0 as its only addr string modification */
+                       pSipMsg =
+                                       natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+                                                                addrPortLen,
+                                                                &diffLen, modIp, 0,
+                                                                ADDRESS_PORT_STRING);
+
+                       *diffModSipLen += diffLen;
+               } else if (pkt_direction == PRIVATE
+                                && (msgType == SIP_ALG_200_OK_BYE_MSGTYPE)) {
+                       /*
+                        *  Need to modify To field, Call-Id,
+                        * Contact if call triggered from private, then modify
+                        */
+               /* Get to To field IP address to modify */
+                       if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_TO, &pos, 0)
+                                       == TRUE) {
+                               pSipMsg += pos; /* Moving to "From" */
+                               /* advance to IP/Port string */
+                               pTmpSipMsg = pSipMsg;
+/* move pTmpSipMsg to str ">" which is end of add:port string */
+                               natSipAlgMsgFieldPos(pTmpSipMsg, SIP_ALG_GREAT,
+                                                                &pos, 0);
+                               pTmpSipMsg += pos;
+                               diffLen = pTmpSipMsg - pSipMsg;
+/* find "@" from "From" string to ">" string which is start of "addr:port" */
+                               natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos,
+                                                                0);
+                               pSipMsg += pos + 1;
+/* now its pointing to start of From field "address:port" */
+                               addrPortLen = pTmpSipMsg - pSipMsg;
+                       } else {
+                               printf
+                                               ("sip_alg_process; no valid from field\n");
+                               return NULL;
+                       }
+                       /* Modify "From" field "addr:port" in payload */
+                       pSipMsg =
+                                       natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+                                                                addrPortLen,
+                                                                &diffLen, modIp,
+                                                                modL4Port,
+                                                                ADDRESS_PORT_STRING);
+
+                       *diffModSipLen = diffLen;
+/* increase the overall diff between old & mod sip msg */
+
+                       /* Advance to "Contact" field */
+                       if (natSipAlgMsgFieldPos
+                                       (pSipMsg, SIP_ALG_CONTACT, &pos, 0) == TRUE) {
+                               pSipMsg += pos;
+                               /* move tmpMsg to CRLF */
+                               pTmpSipMsg = pSipMsg;
+                               natSipAlgMsgFieldPosFindCrlf(pTmpSipMsg,
+                                                                        SIP_ALG_CRLF, &pos,
+                                                                        0);
+                               pTmpSipMsg += pos;
+                               /* move sipMsg to addr:port string */
+                               int flag = 0;
+                               if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT,
+                                       &pos, 0) == FALSE)
+                                       flag = 1;
+
+                               if (flag)
+                                       goto SipMsgAdvance2;
+                               pSipMsg += pos + 1;
+                               addrPortLen = pTmpSipMsg - pSipMsg;
+                       } else {
+                               printf("sip_alg_process; "
+                                       "No valid Call Id field\n");
+                               return NULL;
+                       }
+                       /* Modify "Contact" field "addr:port" in payload */
+                       pSipMsg =
+                                       natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+                                                                addrPortLen,
+                                                                &diffLen, modIp,
+                                                                modL4Port,
+                                                                ADDRESS_PORT_STRING);
+
+                       *diffModSipLen += diffLen;
+               } else if (pkt_direction == PUBLIC
+                                && (msgType == SIP_ALG_200_OK_BYE_MSGTYPE)) {
+                       /* change via and from field, call-id field */
+
+                       /* Get to Via field IP address to modify */
+                       if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_VIA, &pos, 0)
+                                       == TRUE) {
+                               /* advance to IP/Port string */
+                               pSipMsg +=
+                                               (pos + strlen(SIP_ALG_VIA) +
+                                                SIP_ALG_VIA_FIELD_IPADDR);
+                               pTmpSipMsg = pSipMsg;
+                               /* move pTmp to next field */
+                               natSipAlgMsgFieldPos(pTmpSipMsg,
+                                                                SIP_ALG_SEMICOLON, &pos,
+                                                                0);
+                               pTmpSipMsg += pos;
+                               addrPortLen = pTmpSipMsg - pSipMsg;
+                       } else {
+                               printf("sip_alg_process; No valid VIA field\n");
+                               return NULL;
+                       }
+                       /* Modify VIA field IP addr in payload */
+                       pSipMsg =
+                                       natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+                                                                addrPortLen,
+                                                                &diffLen, modIp, 0,
+                                                                ADDRESS_PORT_STRING);
+                       *diffModSipLen = diffLen;
+
+                       /* Advance to "From" field IP addr in payload */
+                       if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_FROM, &pos, 0)
+                                       == TRUE) {
+                               pSipMsg += pos; /* Moving to "From" */
+                               /* advance to IP/Port string */
+                               pTmpSipMsg = pSipMsg;
+/* move pTmpSipMsg to str ">" which is end of add:port string */
+                               natSipAlgMsgFieldPos(pTmpSipMsg, SIP_ALG_GREAT,
+                                                                &pos, 0);
+                               pTmpSipMsg += pos;
+                               diffLen = pTmpSipMsg - pSipMsg;
+/* find "@" from "From" string to ">" string which is start of "addr:port" */
+                               natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos,
+                                                                0);
+                               pSipMsg += pos + 1;
+/* now its pointing to start of From field "address:port" */
+                               addrPortLen = pTmpSipMsg - pSipMsg;
+                       } else {
+                               printf
+                                               ("sip_alg_process; No valid From field\n");
+                               return NULL;
+                       }
+                       /* Modify "From" field "addr:port" in payload */
+                       pSipMsg =
+                                       natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+                                                                addrPortLen,
+                                                                &diffLen, modIp,
+                                                                modL4Port,
+                                                                ADDRESS_PORT_STRING);
+
+                       *diffModSipLen += diffLen;
+
+                       /* check for Call-Id. */
+                       if (natSipAlgMsgFieldPos
+                                       (pSipMsg, SIP_ALG_CALLID, &pos, 0) == TRUE) {
+                               pSipMsg += pos;
+                               /* Call id 'addr" need to modified. */
+                               pTmpSipMsg = pSipMsg;
+                               natSipAlgMsgFieldPosFindCrlf(pTmpSipMsg,
+                                                                        SIP_ALG_CRLF, &pos,
+                                                                        0);
+                               pTmpSipMsg += pos;
+                               natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos,
+                                                                0);
+                               pSipMsg += pos + 1;
+                               addrPortLen = pTmpSipMsg - pSipMsg;
+                               /* modify call id "addr" */
+                               pSipMsg =
+                                               natSipAlgModifyPayloadAddrPort(pSipMsg,
+                                                                        &pSipMsgEnd,
+                                                                        addrPortLen,
+                                                                        &diffLen,
+                                                                        modIp, 0,
+                                                                ADDRESS_PORT_STRING);
+
+                               *diffModSipLen += diffLen;
+/* increase the overall diff between old & mod sip msg */
+                       } else {
+                               printf("sip_alg_process; "
+                                       "no valid Call-id field\n");
+                               return NULL;
+                       }
+/* increase the overall diff between old & mod sip msg */
+               }
+       } else if (call_direction == SIP_CALL_INCOMING) {
+               if ((msgType == SIP_ALG_INVITE_MSGTYPE)
+                               || (msgType == SIP_ALG_ACK_MSGTYPE)) {
+                       /* need to modify Invite RL, TO field */
+                       /* move to Invite RL IP address string */
+                       if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos, 0)
+                                       == TRUE) {
+                               pSipMsg += pos + 1;
+                               pTmpSipMsg = pSipMsg;
+                               natSipAlgMsgFieldPos(pTmpSipMsg, SIP_ALG_SIP,
+                                                                &pos, 0);
+                               pTmpSipMsg += (pos - 1);
+/* pointing to space before SIP/2.0 */
+                               addrPortLen = pTmpSipMsg - pSipMsg;
+                       } else {
+                               printf
+                                               ("sip_alg_process: %d Invalid Invite RL\n",
+                                                __LINE__);
+                               return NULL;
+                       }
+                       /* modify Invite RL URI in payload */
+                       pSipMsg =
+                                       natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+                                                                addrPortLen,
+                                                                &diffLen, modIp,
+                                                                modL4Port,
+                                                                ADDRESS_PORT_STRING);
+                       *diffModSipLen += diffLen;
+/* increase the overall diff between old & mod sip msg */
+
+                       /* Advance to 'To" field */
+                       if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_TO, &pos, 0)
+                                       == TRUE) {
+                               pSipMsg += pos;
+                               pTmpSipMsg = pSipMsg;
+                               natSipAlgMsgFieldPos(pTmpSipMsg, SIP_ALG_GREAT,
+                                                                &pos, 0);
+                               pTmpSipMsg += pos;
+                               natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos,
+                                                                0);
+                               pSipMsg += pos + 1;
+                               addrPortLen = pTmpSipMsg - pSipMsg;
+                       } else {
+                               printf("sip_alg_processing; "
+                                       "%d Invalid To field\n",
+                                                __LINE__);
+                               return NULL;
+                       }
+                       /* Modify TO field IP addr:port in payload */
+                       pSipMsg =
+                                       natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+                                                                addrPortLen,
+                                                                &diffLen, modIp,
+                                                                modL4Port,
+                                                                ADDRESS_PORT_STRING);
+                       *diffModSipLen += diffLen;
+/* increase the overall diff between old & mod sip msg */
+               } else if ((msgType == SIP_ALG_TRYING_RINGING_MSGTYPE)
+                                || (msgType == SIP_ALG_200_OK_INVITE_MSGTYPE)) {
+                       /* Need to modify TO field */
+                       /* Advance to 'To" field */
+                       if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_TO, &pos, 0)
+                                       == TRUE) {
+                               pSipMsg += pos;
+                               pTmpSipMsg = pSipMsg;
+                               natSipAlgMsgFieldPos(pTmpSipMsg, SIP_ALG_GREAT,
+                                                                &pos, 0);
+                               pTmpSipMsg += pos;
+                               natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos,
+                                                                0);
+                               pSipMsg += pos + 1;
+                               addrPortLen = pTmpSipMsg - pSipMsg;
+                               pSipMsg =
+                                               natSipAlgModifyPayloadAddrPort(pSipMsg,
+                                                                &pSipMsgEnd,
+                                                                addrPortLen,
+                                                                &diffLen,
+                                                                modIp,
+                                                                modL4Port,
+                                                        ADDRESS_PORT_STRING);
+                               *diffModSipLen += diffLen;
+/* increase the overall diff between old & mod sip msg */
+                       }
+                       if (msgType == SIP_ALG_200_OK_INVITE_MSGTYPE) {
+/* need to modify Contact, Remote-Party Id, SDP O=IN, C=IN, Audio Port */
+                               /* Advance to "Contact" field */
+
+                               if (natSipAlgMsgFieldPos
+                                               (pSipMsg, SIP_ALG_CONTACT, &pos,
+                                                0) == TRUE) {
+                                       pSipMsg += pos;
+                                       /* move tmpMsg to CRLF */
+                                       pTmpSipMsg = pSipMsg;
+                                       natSipAlgMsgFieldPos(pTmpSipMsg,
+                                                                        SIP_ALG_SEMICOLON,
+                                                                        &pos, 0);
+                                       pTmpSipMsg += pos;
+                                       /* move sipMsg to addr:port string */
+                                       int flag = 0;
+                                       if (natSipAlgMsgFieldPos(pSipMsg,
+                                                                        SIP_ALG_AT, &pos,
+                                                                        30) == FALSE)
+                                               flag = 1;
+
+                                       if (flag)
+                                               goto SipMsgAdvance;
+
+                                       pSipMsg += pos + 1;
+                                       addrPortLen = pTmpSipMsg - pSipMsg;
+                               } else {
+                                       printf("sip_alg_process; "
+                                       "No valid Call Id field\n");
+                                       return NULL;
+                               }
+                       /* Modify "Contact" field "addr:port" in payload */
+                               pSipMsg =
+                                               natSipAlgModifyPayloadAddrPort(pSipMsg,
+                                                                &pSipMsgEnd,
+                                                                addrPortLen,
+                                                                &diffLen,
+                                                                modIp,
+                                                                modL4Port,
+                                                                ADDRESS_PORT_STRING);
+
+                               *diffModSipLen += diffLen;
+SipMsgAdvance:
+                               /* advance to Remote-Party Id */
+                               pTmpSipMsg = pSipMsg;
+                               if (natSipAlgMsgFieldPos
+                                               (pSipMsg, SIP_ALG_REMOTE_PARTY_ID, &pos,
+                                                0) == TRUE) {
+                                       pSipMsg += pos +
+                                                       strlen(SIP_ALG_REMOTE_PARTY_ID);
+                                       pTmpSipMsg = pSipMsg;
+                                       natSipAlgMsgFieldPos(pTmpSipMsg,
+                                                                        SIP_ALG_GREAT,
+                                                                        &pos, 0);
+                                       pTmpSipMsg += pos;
+                                       natSipAlgMsgFieldPos(pSipMsg,
+                                                                        SIP_ALG_AT, &pos,
+                                                                        0);
+                                       pSipMsg += pos + 1;
+                                       addrPortLen = pTmpSipMsg - pSipMsg;
+                                       /* modify the field */
+                                       pSipMsg =
+                                                       natSipAlgModifyPayloadAddrPort
+                                                       (pSipMsg, &pSipMsgEnd, addrPortLen,
+                                                        &diffLen, modIp, modL4Port,
+                                                        ADDRESS_PORT_STRING);
+                                       diffModSipLen += diffLen;
+                               } else {
+                                       printf("sip_alg_process: "
+                                       "Remote-party-id is not in the msg\n");
+                                       pSipMsg = pTmpSipMsg;
+                               }
+
+                               /* Advance to SDP data message Owner address */
+                               if (natSipAlgMsgFieldPos
+                                               (pSipMsg, SIP_ALG_OWNER, &pos,
+                                                0) == TRUE) {
+                                       pSipMsg += pos;
+                               /* at start of owner string "o=" */
+                                       pTmpSipMsg = pSipMsg;
+                                       /* move tmmsg to CRLF of owner field */
+                                       natSipAlgMsgFieldPosFindCrlf(pSipMsg,
+                                                                        SIP_ALG_CRLF,
+                                                                        &pos,
+                                                                        0);
+                                       pTmpSipMsg += pos;
+                                       /* start of CRLF "/r/n" */
+/* move pSipMsg to IP address string in owner field */
+                                       natSipAlgMsgFieldPos(pSipMsg,
+                                                                        SIP_ALG_IPV4, &pos,
+                                                                        0);
+                                       pSipMsg += (pos + strlen(SIP_ALG_IPV4));
+                                       SKIP_SPACES(pSipMsg);
+/* after skipping spaces, pSip at start of addr */
+                                       addrPortLen = pTmpSipMsg - pSipMsg;
+                               } else {
+                                       printf("sip_alg_processing: "
+                                               "Invalid Owner field\n");
+                                       return NULL;
+                               }
+/* Modify "Owner" field "addr" in payload.  Input L4 port as 0 */
+                               pSipMsg =
+                                               natSipAlgModifyPayloadAddrPort(pSipMsg,
+                                                        &pSipMsgEnd,
+                                                        addrPortLen,
+                                                        &diffLen,
+                                                        modIp, 0,
+                                                        ADDRESS_PORT_STRING);
+
+                               *diffModSipLen += diffLen;
+                               sdpMsgLen += diffLen;
+               /* update the sdpMsgLen after modification */
+
+               /* Advance to Connection information to modify IP address */
+                               if (natSipAlgMsgFieldPos
+                                               (pSipMsg, SIP_ALG_CONN, &pos,
+                                                0) == TRUE) {
+                                       pSipMsg += pos;
+                                       pTmpSipMsg = pSipMsg;
+                                       /* move tmmsg to CRLF of owner field */
+                                       natSipAlgMsgFieldPosFindCrlf(pSipMsg,
+                                                                       SIP_ALG_CRLF,
+                                                                       &pos,
+                                                                        0);
+                                       pTmpSipMsg += pos;
+                       /* start of CRLF "/r/n" */
+                       /* move pSipMsg to IP address string in owner field */
+                                       natSipAlgMsgFieldPos(pSipMsg,
+                                                                        SIP_ALG_IPV4, &pos,
+                                                                        0);
+                                       pSipMsg += (pos + strlen(SIP_ALG_IPV4));
+                                       SKIP_SPACES(pSipMsg);
+/* after skipping spaces, pSip at start of addr */
+                                       addrPortLen = pTmpSipMsg - pSipMsg;
+                               } else {
+                                       printf("sip_alg_processing: "
+                                               "Invalid Connection field\n");
+                                       return NULL;
+                               }
+/* Modify "Connection" field "addr" in payload.  Input L4 port as 0 */
+                               pSipMsg =
+                                               natSipAlgModifyPayloadAddrPort(pSipMsg,
+                                                                        &pSipMsgEnd,
+                                                                        addrPortLen,
+                                                                        &diffLen,
+                                                                        modIp, 0,
+                                                                ADDRESS_PORT_STRING);
+
+                               *diffModSipLen += diffLen;
+                               sdpMsgLen += diffLen;
+/* update the sdpMsgLen after modification */
+
+                               /* Advance to RTP audio port */
+                               if (natSipAlgMsgFieldPos
+                                               (pSipMsg, SIP_ALG_AUDIO, &pos,
+                                                0) == TRUE) {
+                                       pSipMsg +=
+                                                       (pos + strlen(SIP_ALG_AUDIO));
+                                       SKIP_SPACES(pSipMsg);
+                                       pTmpSipMsg = pSipMsg;
+                                       natSipAlgMsgFieldPosFindSpace
+                                                       (pTmpSipMsg, SIP_ALG_SPACE, &pos,
+                                                        0);
+                                       pTmpSipMsg += pos;
+                                       addrPortLen = pTmpSipMsg - pSipMsg;
+                               }
+
+/* Modify "RTP Audio" port in payload. pass pub_ip as 0. */
+                               pSipMsg =
+                                               natSipAlgModifyPayloadAddrPort(pSipMsg,
+                                                                        &pSipMsgEnd,
+                                                                        addrPortLen,
+                                                                        &diffLen, 0,
+                                                                        modRtpPort,
+                                                                        PORT_STRING);
+
+                               *diffModSipLen += diffLen;
+                               sdpMsgLen += diffLen;
+/* update the sdpMsgLen after modification */
+                       }
+               } else if (pkt_direction == PUBLIC
+                                && msgType == SIP_ALG_BYE_MSGTYPE) {
+                       /* Modify Bye URL (if its BYE), To field */
+
+                       /* need to modify address:Port in Bye message string. */
+                       natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos, 0);
+                       pSipMsg += pos + 1;
+                       pTmpSipMsg = pSipMsg;
+                       natSipAlgMsgFieldPosFindSpace(pTmpSipMsg, SIP_ALG_SPACE,
+                                                                       &pos, 0);
+                       pTmpSipMsg += pos;
+                       addrPortLen = pTmpSipMsg - pSipMsg;
+                       /* modify the "addr:port" in Bye message line */
+                       pSipMsg =
+                                       natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+                                                                addrPortLen,
+                                                                &diffLen, modIp,
+                                                                modL4Port,
+                                                                ADDRESS_PORT_STRING);
+                       *diffModSipLen += diffLen;
+/* increase the overall diff between old & mod sip msg */
+
+                       /* Advance to 'To" field */
+                       if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_TO, &pos, 0)
+                                       == TRUE) {
+                               pSipMsg += pos;
+                               pTmpSipMsg = pSipMsg;
+                               natSipAlgMsgFieldPos(pTmpSipMsg, SIP_ALG_GREAT,
+                                                                &pos, 0);
+                               pTmpSipMsg += pos;
+                               natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos,
+                                                                0);
+                               pSipMsg += pos + 1;
+                               addrPortLen = pTmpSipMsg - pSipMsg;
+                               pSipMsg =
+                                               natSipAlgModifyPayloadAddrPort(pSipMsg,
+                                                                &pSipMsgEnd,
+                                                                addrPortLen,
+                                                                &diffLen,
+                                                                modIp,
+                                                                modL4Port,
+                                                                ADDRESS_PORT_STRING);
+                               *diffModSipLen += diffLen;
+/* increase the overall diff between old & mod sip msg */
+                       } else {
+                               printf
+                                               ("sip_alg_processing: Invalid TO field\n");
+                               return NULL;
+                       }
+               } else if (pkt_direction == PRIVATE
+                                && msgType == SIP_ALG_BYE_MSGTYPE) {
+                       /* change via and from field */
+
+                       /* Get to Via field IP address to modify */
+                       if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_VIA, &pos, 0)
+                                       == TRUE) {
+                               /* advance to IP/Port string */
+                               pSipMsg +=
+                                               (pos + strlen(SIP_ALG_VIA) +
+                                                SIP_ALG_VIA_FIELD_IPADDR);
+                               pTmpSipMsg = pSipMsg;
+                               /* move pTmp to next field */
+                               natSipAlgMsgFieldPos(pTmpSipMsg,
+                                                                SIP_ALG_SEMICOLON, &pos,
+                                                                0);
+                               pTmpSipMsg += pos;
+                               addrPortLen = pTmpSipMsg - pSipMsg;
+                       } else {
+                               printf("sip_alg_process; No valid VIA field\n");
+                               return NULL;
+                       }
+                       /* Modify VIA field IP addr in payload */
+                       pSipMsg =
+                                       natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+                                                                addrPortLen,
+                                                                &diffLen, modIp, 0,
+                                                                ADDRESS_PORT_STRING);
+                       *diffModSipLen = diffLen;
+
+                       /* Advance to "From" field IP addr in payload */
+                       if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_FROM, &pos, 0)
+                                       == TRUE) {
+                               pSipMsg += pos; /* Moving to "From" */
+                               /* advance to IP/Port string */
+                               pTmpSipMsg = pSipMsg;
+/* move pTmpSipMsg to str ">" which is end of add:port string */
+                               natSipAlgMsgFieldPos(pTmpSipMsg, SIP_ALG_GREAT,
+                                                                &pos, 0);
+                               pTmpSipMsg += pos;
+                               diffLen = pTmpSipMsg - pSipMsg;
+/* find "@" from "From" string to ">" string which is start of "addr:port" */
+                               natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos,
+                                                                0);
+                               pSipMsg += pos + 1;
+/* now its pointing to start of From field "address:port" */
+                               addrPortLen = pTmpSipMsg - pSipMsg;
+                       } else {
+                               printf
+                                               ("sip_alg_process; No valid From field\n");
+                               return NULL;
+                       }
+                       /* Modify "From" field "addr:port" in payload */
+                       pSipMsg =
+                                       natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+                                                                addrPortLen,
+                                                                &diffLen, modIp,
+                                                                modL4Port,
+                                                                ADDRESS_PORT_STRING);
+
+                       *diffModSipLen += diffLen;
+/* increase the overall diff between old & mod sip msg */
+               } else if (pkt_direction == PRIVATE
+                                && msgType == SIP_ALG_200_OK_BYE_MSGTYPE) {
+                       /* change via and from field */
+
+                       /* Get to Via field IP address to modify */
+                       if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_VIA, &pos, 0)
+                                       == TRUE) {
+                               /* advance to IP/Port string */
+                               pSipMsg +=
+                                               (pos + strlen(SIP_ALG_VIA) +
+                                                SIP_ALG_VIA_FIELD_IPADDR);
+                               pTmpSipMsg = pSipMsg;
+                               /* move pTmp to next field */
+                               natSipAlgMsgFieldPos(pTmpSipMsg,
+                                                                SIP_ALG_SEMICOLON, &pos,
+                                                                0);
+                               pTmpSipMsg += pos;
+                               addrPortLen = pTmpSipMsg - pSipMsg;
+                       } else {
+                               printf("sip_alg_process; No valid VIA field\n");
+                               return NULL;
+                       }
+                       /* Modify VIA field IP addr in payload */
+                       pSipMsg =
+                                       natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+                                                                addrPortLen,
+                                                                &diffLen, modIp, 0,
+                                                                ADDRESS_PORT_STRING);
+                       *diffModSipLen = diffLen;
+
+                       /* Advance to "From" field IP addr in payload */
+                       if (natSipAlgMsgFieldPos(pSipMsg,
+                               SIP_ALG_FROM, &pos, 0) == TRUE) {
+                               pSipMsg += pos; /* Moving to "From" */
+                               /* advance to IP/Port string */
+                               pTmpSipMsg = pSipMsg;
+/* move pTmpSipMsg to str ">" which is end of add:port string */
+                               natSipAlgMsgFieldPos(pTmpSipMsg, SIP_ALG_GREAT,
+                                                                &pos, 0);
+                               pTmpSipMsg += pos;
+                               diffLen = pTmpSipMsg - pSipMsg;
+/* find "@" from "From" string to ">" string which is start of "addr:port" */
+                               natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos,
+                                                                0);
+                               pSipMsg += pos + 1;
+/* now its pointing to start of From field "address:port" */
+                               addrPortLen = pTmpSipMsg - pSipMsg;
+                       } else {
+                               printf
+                                               ("sip_alg_process; No valid From field\n");
+                               return NULL;
+                       }
+                       /* Modify "From" field "addr:port" in payload */
+                       pSipMsg =
+                                       natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+                                                                addrPortLen,
+                                                                &diffLen, modIp,
+                                                                modL4Port,
+                                                                ADDRESS_PORT_STRING);
+
+                       *diffModSipLen += diffLen;
+/* increase the overall diff between old & mod sip msg */
+               } else if (pkt_direction == PUBLIC
+                                && msgType == SIP_ALG_200_OK_BYE_MSGTYPE) {
+                       /* Get to To field IP address to modify */
+                       if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_TO, &pos, 0)
+                                       == TRUE) {
+                               pSipMsg += pos; /* Moving to "From" */
+                               /* advance to IP/Port string */
+                               pTmpSipMsg = pSipMsg;
+/* move pTmpSipMsg to str ">" which is end of add:port string */
+                               natSipAlgMsgFieldPos(pTmpSipMsg, SIP_ALG_GREAT,
+                                                                &pos, 0);
+                               pTmpSipMsg += pos;
+                               diffLen = pTmpSipMsg - pSipMsg;
+/* find "@" from "From" string to ">" string which is start of "addr:port" */
+                               natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos,
+                                                                0);
+                               pSipMsg += pos + 1;
+/* now its pointing to start of From field "address:port" */
+                               addrPortLen = pTmpSipMsg - pSipMsg;
+                       } else {
+                               printf
+                                               ("sip_alg_process; no valid from field\n");
+                               return NULL;
+                       }
+                       /* Modify "From" field "addr:port" in payload */
+                       pSipMsg = natSipAlgModifyPayloadAddrPort(pSipMsg,
+                                                        &pSipMsgEnd,
+                                                        addrPortLen,
+                                                        &diffLen, modIp,
+                                                        modL4Port,
+                                                        ADDRESS_PORT_STRING);
+
+                       *diffModSipLen = diffLen;
+/* increase the overall diff between old & mod sip msg */
+
+                       /* Advance to "Contact" field */
+                       if (natSipAlgMsgFieldPos
+                                       (pSipMsg, SIP_ALG_CONTACT, &pos, 0) == TRUE) {
+                               pSipMsg += pos;
+                               /* move tmpMsg to CRLF */
+                               pTmpSipMsg = pSipMsg;
+                               natSipAlgMsgFieldPosFindCrlf(pTmpSipMsg,
+                                                                SIP_ALG_CRLF, &pos,
+                                                                        0);
+                               pTmpSipMsg += pos;
+                               /* move sipMsg to addr:port string */
+                               natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos,
+                                                                0);
+                               pSipMsg += pos + 1;
+                               addrPortLen = pTmpSipMsg - pSipMsg;
+                       } else {
+                               printf("sip_alg_process; "
+                                       "No valid Call Id field\n");
+                               return NULL;
+                       }
+                       /* Modify "Contact" field "addr:port" in payload */
+                       pSipMsg =
+                                       natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+                                                                addrPortLen,
+                                                                &diffLen, modIp,
+                                                                modL4Port,
+                                                                ADDRESS_PORT_STRING);
+
+                       *diffModSipLen += diffLen;
+               }
+       }
+
+SipMsgAdvance2:
+/* need to remove the SIP ALG entry if msg is 200 OK BYE response */
+       if (call_direction == SIP_CALL_OUTGOING) {
+               /* call remove sip alg entry here */
+               if (pkt_direction == PRIVATE) {
+                       if (msgType == SIP_ALG_200_OK_BYE_MSGTYPE) {
+                               if (remove_sip_alg_entry
+                                               (rte_bswap32(ip_h->src_addr),
+                                                rte_bswap16(udp_h->src_port)) < 0)
+                                       printf("removesipalgentry failed: "
+                                               "ipaddr %d, portid %d\n",
+                                                        ip_h->src_addr, udp_h->src_port);
+                       }
+               }
+       } else {
+               if (pkt_direction == PUBLIC) {
+                       if (msgType == SIP_ALG_200_OK_BYE_MSGTYPE) {
+                               if (remove_sip_alg_entry(pubIp, pubL4Port) < 0)
+                                       printf("removesipalgentry failed: "
+                                               " ipaddr %d, portid %d\n",
+                                                        pubIp, pubL4Port);
+                       }
+               }
+       }
+
+/* adjust SDP msg len (sdpMsgLen) in the content length field of SIP msg */
+       if ((sdpMsgLen > 0) && (sdpDataLen > 0)) {
+               pSipMsg = pStartSipMsg;
+               char *tmpSdpLen = NULL;
+
+               sdpMsgLen += sdpDataLen;
+               tmpSdpLen = itoa(sdpMsgLen);
+               int tmpStrLen = strlen(tmpSdpLen);
+
+       /* move to Content length field & change the length to sipMsgLen */
+               if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_CONTENT_LEN, &pos, 0)
+                               == TRUE) {
+                       pSipMsg += (pos + TAG_TO_DATAPOS(SIP_ALG_CONTENT_LEN));
+                       SKIP_SPACES(pSipMsg);
+                       pTmpSipMsg = pSipMsg;
+                       natSipAlgMsgFieldPosFindCrlf(pTmpSipMsg,
+                                                                SIP_ALG_DOUBLE_CRLF, &pos,
+                                                                0);
+                       pTmpSipMsg += pos;
+                       SKIP_SPACES(pSipMsg);
+                       diffLen = pTmpSipMsg - pSipMsg;
+                       natSipAlgAdjustMsg(pSipMsg, &pSipMsgEnd, tmpStrLen,
+                                                diffLen);
+                       strncpy(pSipMsg, tmpSdpLen, tmpStrLen);
+               } else {
+                       printf("sip_alg_process: Invalid Content Length\n");
+                       return NULL;
+               }
+       }
+
+ sipAlgProcessExit:
+       /* need to return toe start of the SIP msg */
+       return pStartSipMsg;
+}
+
+/*
+ * Function to Fetch RTP & RTCP port & return. Invoked by CGNAT
+ * while adding NAPT entry for RTP & RTCP
+ */
+int natSipAlgGetAudioPorts(struct rte_mbuf *pkt, uint16_t *rtpPort,
+                                uint16_t *rtcpPort)
+{
+       struct ipv4_hdr *ip_h;
+       struct ether_hdr *eth_h = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+       struct udp_hdr *udp_h;
+       char *pSipMsg, *pEndPtr;
+       int pos, sdpMsgLen;
+
+       ip_h = (struct ipv4_hdr *)((char *)eth_h + sizeof(struct ether_hdr));
+       udp_h = (struct udp_hdr *)((char *)ip_h + sizeof(struct ipv4_hdr));
+       pSipMsg = ((char *)udp_h + sizeof(struct udp_hdr));
+
+       /* Advance to check content type & get content length (SDP length) */
+       if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_CONTYPE, &pos, 0) == FALSE)
+               return -1;
+
+       pSipMsg += (pos + TAG_TO_DATAPOS(SIP_ALG_CONTYPE));
+       SKIP_SPACES(pSipMsg);
+
+       /*check the application/sdp type, if not, exit */
+       if (!IS_STRING_SAME(pSipMsg, SIP_ALG_APPSDP)) {
+               printf("sip_alg_getAudioPort Invalid Content type\n");
+               return -1;
+       }
+
+       /* get the SDP content length */
+       natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_CONTENT_LEN, &pos, 0);
+       pSipMsg += (pos + TAG_TO_DATAPOS(SIP_ALG_CONTENT_LEN));
+       SKIP_SPACES(pSipMsg);
+       sdpMsgLen = strtol(pSipMsg, &pEndPtr, 10);
+       if (!sdpMsgLen) {
+               printf("sipAlggetAudioport - sdpMsgLen is 0\n");
+               return -1;
+       }
+
+       /* advance to RTP audio port */
+       if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AUDIO, &pos, 0) ==
+                       TRUE) {
+               pSipMsg += (pos + TAG_TO_DATAPOS(SIP_ALG_AUDIO));
+               SKIP_SPACES(pSipMsg);
+               *rtpPort = strtol(pSipMsg, &pEndPtr, 10);
+       } else
+               *rtpPort = 0;
+
+       /* advance to RTCP audio control port */
+       if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_RTCP, &pos, 0) ==
+                       TRUE) {
+               pSipMsg += (pos + TAG_TO_DATAPOS(SIP_ALG_RTCP));
+               SKIP_SPACES(pSipMsg);
+               *rtcpPort = strtol(pSipMsg, &pEndPtr, 10);
+       } else
+               *rtcpPort = 0;
+
+       if (ALG_DEBUG)
+               printf(" sipAlgGetAudioPort; rtpPort %d, rtcpPort %d\n",
+                                        *rtpPort, *rtcpPort);
+       return 0;
+}
+
+/* function to find SPACES in ALG message */
+int
+natSipAlgMsgFieldPosFindSpace(char *pData, const char *pIdStr, int *pPos,
+                                               int searchLen)
+{
+       char *pStart = pData;
+       int i = 0;
+
+       if (!pIdStr)
+               return FALSE;
+
+       if (!searchLen)
+               searchLen = 1500;       /* max default search length */
+
+       while (TRUE) {
+               while (*pData != ' ') {
+                       pData++;
+                       i++;
+               }
+
+               if (i > searchLen) {
+                       printf("SIP ALG Find Field Pos: "
+                               "Single message exceeds max len: %d\n",
+                               searchLen);
+                       *pPos = searchLen;      /* reaches the end */
+                       return FALSE;
+               }
+
+               if (bcmp(pData, pIdStr, strlen(pIdStr)) == 0)
+                       break;
+       }
+
+       *pPos = pData - pStart;
+       return TRUE;
+}
+
+/* function to find CRLF in ALG message */
+int natSipAlgMsgFieldPosFindCrlf(
+       char *pData,
+       const char *pIdStr,
+       int *pPos,
+       int searchLen)
+{
+       char *pStart = pData;
+       int i = 0;
+
+       if (!pIdStr)
+               return FALSE;
+
+       if (!searchLen)
+               searchLen = 1500;       /* max default search length */
+
+       while (TRUE) {
+               while (*pData != '\r' && *(pData + 1) != '\n') {
+                       pData++;
+                       i++;
+               }
+               if (i >= searchLen) {
+                       printf("SIP ALG Find Field Pos: "
+                               " Single message exceeds max len: %d\n",
+                                        searchLen);
+                       *pPos = searchLen;      /* reaches the end */
+                       return FALSE;
+               }
+
+               if (bcmp(pData, pIdStr, strlen(pIdStr)) == 0)
+                       break;
+       }
+
+       *pPos = pData - pStart;
+       return TRUE;
+}
+
+/* function to find field position in ALG message */
+int natSipAlgMsgFieldPos(char *pData,
+       const char *pIdStr,
+       int *pPos,
+       int searchLen)
+{
+       char *pStart = pData;
+       int i = 0, j = 0;
+
+       if (!pIdStr)
+               return FALSE;
+
+       if (!searchLen)
+               searchLen = 1500;       /* max default search length */
+
+       while (TRUE) {
+               while (*pData != '\r' && *(pData + 1) != '\n') {
+                       /* skip all space */
+
+                       while (*pData == ' ') {
+                               pData++;
+                               j++;
+                       }
+
+                       if (*pData == '\r' && *(pData + 1) == '\n')
+                               break;
+
+                       if (bcmp(pData, pIdStr, strlen(pIdStr)) == 0) {
+                               *pPos = pData - pStart;
+                               return TRUE;
+                       }
+
+                       pData++;
+                       j++;
+
+                       if (j >= searchLen) {
+                               *pPos = pData - pStart;
+                               return FALSE;
+                       }
+
+               }
+
+               /* advance to next line */
+
+               for (i = 0; i < (searchLen - 1); i++) {
+                       if (pData[i] == '\r')
+                               if (pData[i + 1] == '\n')
+                                       break;
+               }
+
+               if (i > searchLen) {
+                       printf("SIP ALG Find Field Pos: "
+                               "Single message exceeds max len: %d\n",
+                                        searchLen);
+                       *pPos = searchLen;      /* reaches the end */
+                       return FALSE;
+               }
+
+               pData += i + 2;
+               searchLen -= (i + 2);
+
+               if ((pData[0] == '\r' && pData[1] == '\n') ||
+                                       (searchLen <= 0)) {
+                       /* reach the end mark \r\n\r\n */
+
+                       if (searchLen > 0) {
+                               pData += 2;
+                               continue;
+                       }
+
+                       *pPos = pData - pStart;
+
+                       return FALSE;
+               }
+       }
+
+       *pPos = pData - pStart;
+       return TRUE;
+}
+
+/* get SIP Call id string */
+char *getSipCallIdStr(char *pMsg)
+{
+       char *pStart;
+       char *pCallId = NULL;
+       int i;
+
+       pStart = pMsg;
+       for (i = 0; i < 200; i++) {
+               if (*pMsg != '\r')
+                       pMsg++;
+               else
+                       break;
+       }
+       if (i >= 200) {
+               printf("SIP_ALG: getCallid wrong string format\n");
+               return NULL;
+       }
+
+       size_t size = RTE_CACHE_LINE_ROUNDUP(pMsg - pStart + 1);
+
+       pCallId = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
+       if (!pCallId)
+               return NULL;
+
+       bcopy(pStart, pCallId, pMsg - pStart);
+       *(pCallId + (pMsg - pStart)) = 0;
+
+       if (ALG_DEBUG)
+               printf("%s: %s\n", __func__, pCallId);
+
+       return pCallId;
+}
+
+char *natSipAlgModifyPayloadAddrPort(
+       char *pSipMsg, char **pSipMsgEnd,
+       uint32_t oldStrLen, uint32_t *diffLen,
+       uint32_t modIp, uint16_t modPort, uint32_t type)
+{
+       char addrport[MAX_ADDR_PORT_SIZE];
+       struct in_addr ipAddr;
+       uint32_t newStrLen = 0;
+       char *tmpPort = NULL;
+
+       if (modPort != 0)
+               tmpPort = itoa(modPort);
+
+       *diffLen = 0;
+       if (type == ADDRESS_PORT_STRING) {
+               ipAddr.s_addr = htonl(modIp);
+               char *tmpAddr = inet_ntoa(ipAddr);
+
+               if (modPort != 0)       /* for addr:port combo modification */
+                       sprintf(addrport, "%s:%s", tmpAddr, tmpPort);
+               else            /* if only address modification */
+                       sprintf(addrport, "%s", tmpAddr);
+
+               newStrLen = strlen(addrport);
+
+               if (abs(newStrLen - oldStrLen) > 0) {
+               /*
+                * Call the function moving the SIP Msg pointer
+                * to modify the field
+                */
+                       natSipAlgAdjustMsg(pSipMsg, pSipMsgEnd,
+                                                       newStrLen, oldStrLen);
+               }
+
+               /* replace the old addr:port with new addr:port */
+               strncpy(pSipMsg, addrport, strlen(addrport));
+       } else if (type == PORT_STRING) {       /* only port modification */
+               if(tmpPort)
+               newStrLen = strlen(tmpPort);
+
+               if (abs(newStrLen - oldStrLen) > 0) {
+               /*
+                * Call the function moving the SIP msg pointer
+                * to modify the field
+                */
+                       natSipAlgAdjustMsg(pSipMsg, pSipMsgEnd,
+                                                       newStrLen, oldStrLen);
+               }
+
+               /* replace the old port with new port */
+               if(tmpPort)
+               strncpy(pSipMsg, tmpPort, strlen(tmpPort));
+       }
+       /* output difflen between old str len & modified new str length */
+       if (newStrLen > oldStrLen)
+               *diffLen = newStrLen - oldStrLen;
+
+       return pSipMsg;         /* modified SIP Msg */
+}
+
+char *natSipAlgAdjustMsg(char *pSipMsg, char **pSipMsgEnd,
+                        uint32_t newStrLen, uint32_t oldStrLen)
+{
+       char MsgBuffer[MAX_SIP_UDP_MSG_SIZE];
+
+       if (newStrLen > oldStrLen) {
+               pSipMsg += oldStrLen;
+               int msgLen = *pSipMsgEnd - pSipMsg;
+
+               strncpy(MsgBuffer, pSipMsg, msgLen);
+               pSipMsg += (newStrLen - oldStrLen);
+               strncpy(pSipMsg, MsgBuffer, msgLen);
+
+               if (ALG_DEBUG)
+                       printf("natSipAlgAdjustMsg: %u\n", msgLen);
+
+               /* moving output end of SIP MSG by difflen like pSipMsg */
+               *pSipMsgEnd += (newStrLen - oldStrLen);
+       } else {
+               /* Setting space on the oldStr position */
+               memset(pSipMsg, ' ', oldStrLen);
+       }
+
+       return pSipMsg;
+}
+
+/* end of file */
diff --git a/common/VIL/alg/lib_sip_alg.h b/common/VIL/alg/lib_sip_alg.h
new file mode 100644 (file)
index 0000000..b320a4f
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef __INCLUDE_LIB_ALG_H__
+#define __INCLUDE_LIB_ALG_H__
+
+#include "rte_ether.h"
+
+uint16_t sip_session_number;/* SIP session count */
+#define IS_STRING_SAME(pStr, strId) (bcmp((pStr), strId, strlen(strId)) == 0)
+#define TAG_TO_DATAPOS(str) (strlen(str) + 1)
+#define SKIP_SPACES(pStr)              \
+{                                      \
+       while (*(char *)(pStr) == ' ')  \
+       (char *)(pStr)++;               \
+}
+
+enum pkt_dir {PRIVATE, PUBLIC};
+
+/* enum for  SIP Call direction - NAT ALG */
+enum sip_alg_call_direction {
+       SIP_CALL_INCOMING, /* Incoming call public to private */
+       SIP_CALL_OUTGOING /* Outgoing call private to public */
+};
+
+/* enum of  SIP port type - NAT ALG */
+enum sip_alg_port_type {
+       SIP_UDP, /* SIP SDP port 5460 */
+       SIP_RTP, /* RTP port number */
+       SIP_RTCP /* RTCP port number */
+};
+
+/*
+ * Data structure for NAT SIP ALG table key
+ * Key - IP address & L4 port number.
+ */
+struct sip_alg_key {
+       /*
+        *  IP address based on direction.
+        *  outgoing - public IP, incoming - destinatio IP of pkt
+        */
+       uint32_t ip_address;
+       uint16_t l4port; /* SIP SDP, RTP, RTCP port number */
+       uint8_t filler1;
+       uint8_t filler2;
+};
+
+/*
+ * Data structure for NAT SIP ALG table entry.
+ * Placeholder for storing SIP ALG entries.
+ */
+struct sip_alg_table_entry {
+       uint32_t ip_address;
+       /*
+        * IP address based on direction.
+        * outgoing - public IP, incoming - destinatio IP of pkt
+        */
+       uint16_t l4port; /* SIP UDP (5061), RTP, RTCP port number */
+       uint8_t sip_alg_call_direction;
+       /* Call incoming (pub to prv) or outgoing (prv to pub) */
+       uint8_t sip_alg_call_id[100];/* unique identfier for a SIP call */
+       uint8_t l4port_type;/* SIP_UDP or RTP or RTCP */
+       uint8_t filler1;
+       uint16_t filler2;
+       uint32_t filler3;
+} __rte_cache_aligned;
+
+
+/* Function declarations */
+
+/**
+ * To initalize SIP ALG library and should be called-
+ * - before other SIP ALG library funcitons
+ * @param params
+ * pipeline parameter structure pointer
+ * @param app
+ * pipeline application conext structure pointer
+ * @return
+ * void return
+ */
+void lib_sip_alg_init(void);
+
+/**
+ * Main SIP ALG DPI function for processing SIP ALG functionlity
+ * @param pkt
+ * mbuf packet pointer
+ * @param pkt_direction
+ * Indicates whether pkt is from PRIVATE or PUBLIC direction
+ * @param modIp
+ * NAPT tranlated IP address based on direction
+ * @param modL4Port
+ * NAPT translated L4 port based on direction
+ * @param pubIP
+ * Original IP address before translation
+ * @param pubL4Port
+ * Original L4 port before translation
+ * @param modRtpPort
+ * RTP port
+ * @param modRtcpPort
+ * RTCP port
+ * @return
+ * 0 means success, -1 means failure
+ */
+int sip_alg_dpi(struct rte_mbuf *pkt, enum pkt_dir pkt_direction,
+               uint32_t modIp, uint16_t modL4Port,
+               uint32_t pubIp, uint16_t pubL4Port,
+               uint16_t modRtpPort, uint16_t modRtcpPort);
+
+/**
+ * To get audio ports from SIP Packet
+ * @param pkt
+ * mbuf packet pointer
+ * @param rtpPort
+ * rtp port in parameter
+ * @param rtcpPort
+ * rtcp port in parameter
+ * @return
+ * 0 means success, -1 means failre
+ */
+int natSipAlgGetAudioPorts(
+       struct rte_mbuf *pkt,
+       uint16_t *rtpPort,
+       uint16_t *rtcp_port);
+int natSipAlgMsgFieldPos(
+       char *pData,
+       const char *pIdStr,
+       int *pos,
+       int searchLen);
+int natSipAlgMsgFieldPosFindCrlf(
+       char *pData,
+       const char *pIdStr,
+       int *pPos,
+       int searchLen);
+int natSipAlgMsgFieldPosFindSpace(
+       char *pData,
+       const char *pIdStr,
+       int *pPos,
+       int searchLen);
+int remove_sip_alg_entry(
+       uint32_t ipaddr,
+       uint16_t portid);
+
+#endif
diff --git a/common/VIL/conntrack/rte_cnxn_tracking.c b/common/VIL/conntrack/rte_cnxn_tracking.c
new file mode 100644 (file)
index 0000000..461ed42
--- /dev/null
@@ -0,0 +1,1804 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <rte_ether.h>
+#include <rte_prefetch.h>
+#include <rte_cycles.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_timer.h>
+#include <rte_spinlock.h>
+#include "rte_cnxn_tracking.h"
+#include "rte_ct_tcp.h"
+
+#define CNXN_TRX_DEBUG 0
+#define TESTING_TIMERS 0
+#define RTE_CT_TIMER_EXPIRED_DUMP 0
+
+#define META_DATA_OFFSET 128
+#define ETHERNET_START (META_DATA_OFFSET + RTE_PKTMBUF_HEADROOM)
+#define ETH_HDR_SIZE 14
+#define IP_START (ETHERNET_START + ETH_HDR_SIZE)
+#define PROTOCOL_START (IP_START + 9)
+#define SRC_ADDR_START (IP_START + 12)
+#define TCP_START (IP_START + 20)
+
+/* IPV6 changes */
+#define PROTOCOL_START_IPV6 (IP_START + 6)
+#define SRC_ADDR_START_IPV6 (IP_START + 8)
+#define TCP_START_IPV6 (IP_START + 40)
+
+#define TCP_PROTOCOL 6
+#define UDP_PROTOCOL 17
+#define TCP_FW_IPV4_KEY_SIZE 16
+
+#define TCP_FW_IPV6_KEY_SIZE 40
+
+#define IPv4_HEADER_SIZE 20
+#define IPv6_HEADER_SIZE 40
+
+#define IP_VERSION_4 4
+#define IP_VERSION_6 6
+
+static void
+rte_ct_cnxn_tracker_batch_lookup_basic_type(
+       struct rte_ct_cnxn_tracker *ct,
+       struct rte_mbuf **pkts,
+       uint64_t *pkts_mask,
+       uint64_t no_new_cnxn_mask,
+       uint64_t *reply_pkt_mask,
+       uint64_t *hijack_mask,
+       uint8_t ip_hdr_size_bytes);
+
+/*
+ * Check if the packet is valid for the given connection. "original_direction"
+ * is false if the address order need to be "flipped".See create_cnxn_hashkey().
+ * True otherwise. Return 0 if the packet is valid, or a negative otherwise.
+ */
+
+/* IP/TCP header print for debugging */
+static void
+rte_ct_cnxn_print_pkt(struct rte_mbuf *pkt, uint8_t type)
+{
+       int i;
+       uint8_t *rd = RTE_MBUF_METADATA_UINT8_PTR(pkt, IP_START);
+
+       printf("\n");
+       printf("IP and TCP/UDP headers:\n");
+
+       if (type == IP_VERSION_4) {
+               for (i = 0; i < 40; i++) {
+                       printf("%02x ", rd[i]);
+                       if ((i & 3) == 3)
+                               printf("\n");
+               }
+               printf("\n");
+       }
+
+       if (type == IP_VERSION_6) {
+               for (i = 0; i < 60; i++) {
+                       printf("%02x ", rd[i]);
+                       if ((i & 3) == 3)
+                               printf("\n");
+               }
+               printf("\n");
+       }
+
+}
+
+static void
+rte_cnxn_ip_type(uint8_t *type, struct rte_mbuf *pkt)
+{
+
+       int ip_hdr_size_bytes = rte_ct_get_IP_hdr_size(pkt);
+
+       if (ip_hdr_size_bytes == IPv4_HEADER_SIZE)
+               *type = IP_VERSION_4;
+
+       if (ip_hdr_size_bytes == IPv6_HEADER_SIZE)
+               *type = IP_VERSION_6;
+}
+
+static void
+rte_ct_print_hashkey(uint32_t *key)
+{
+       printf("Key: %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x \\\n",
+                                key[0], key[1], key[2], key[3],
+                                key[4], key[5], key[6], key[7], key[8], key[9]);
+}
+
+/*
+ * Create a hash key consisting of the source address/port, the destination
+ * address/ports, and the tcp protocol number. The address/port combos are
+ * treated as two 48 bit numbers and sorted. Thus the key is always the
+ * same regardless of the direction of the packet. Remembering if the numbers
+ * were "flipped" from the order in the packet, and comparing that to whether
+ * the original hash key was flipped, tells if this packet is from the same
+ * direction as the original sender or the response direction. Returns 1 (true)
+ * if the key was left in the original direction.
+ */
+uint8_t
+rte_ct_create_cnxn_hashkey(
+       uint32_t *src_addr,
+       uint32_t *dst_addr,
+       uint16_t src_port,
+       uint16_t dst_port,
+       uint8_t proto,
+       uint32_t *key,
+       uint8_t type)
+{
+       uint8_t hash_order_original_direction = 1;
+
+       key[9] = proto;
+
+       if (type == IP_VERSION_4) {
+               uint32_t source = *src_addr;
+               uint32_t dest = *dst_addr;
+
+               key[3] = key[4] = key[5] = key[6] = key[7] = key[8] = 0;
+
+               if ((source < dest)
+                               || ((source == dest) && (src_port < dst_port))) {
+                       key[0] = source;
+                       key[1] = dest;
+                       key[2] = (src_port << 16) | dst_port;
+               } else {
+                       key[0] = dest;
+                       key[1] = source;
+                       key[2] = (dst_port << 16) | src_port;
+                       hash_order_original_direction = 0;
+               }
+       }
+
+       if (type == IP_VERSION_6) {
+               int ip_cmp = memcmp(src_addr, dst_addr, 16);
+               uint32_t *lo_addr;
+               uint32_t *hi_addr;
+
+               if ((ip_cmp < 0) || ((ip_cmp == 0) && (src_port < dst_port))) {
+                       lo_addr = src_addr;
+                       hi_addr = dst_addr;
+                       key[8] = (src_port << 16) | dst_port;
+               } else {
+                       lo_addr = dst_addr;
+                       hi_addr = src_addr;
+                       key[8] = (dst_port << 16) | src_port;
+                       hash_order_original_direction = 0;
+               }
+               key[0] = lo_addr[0];
+               key[1] = lo_addr[1];
+               key[2] = lo_addr[2];
+               key[3] = lo_addr[3];
+               key[4] = hi_addr[0];
+               key[5] = hi_addr[1];
+               key[6] = hi_addr[2];
+               key[7] = hi_addr[3];
+
+       }
+#ifdef ALGDBG
+        rte_ct_print_hashkey(key);
+#endif
+       return hash_order_original_direction;
+}
+
+
+int
+rte_ct_get_IP_hdr_size(struct rte_mbuf *pkt)
+{
+       /* NOTE: Only supporting IP headers with no options at this time, so
+        * header is fixed size
+        */
+       /* TODO: Need to find defined contstants for start of Ether and
+        * IP headers.
+        */
+       uint8_t hdr_chk = RTE_MBUF_METADATA_UINT8(pkt, IP_START);
+
+       hdr_chk = hdr_chk >> 4;
+
+       if (hdr_chk == IP_VERSION_4)
+               return IPv4_HEADER_SIZE;
+
+       else if (hdr_chk == IP_VERSION_6)
+               return IPv6_HEADER_SIZE;
+
+       else    /* Not IPv4 header with no options, return negative. */
+               return -1;
+       /*
+        * int ip_hdr_size_bytes = (ihdr->version_ihl & IPV4_HDR_IHL_MASK) *
+        * IPV4_IHL_MULTIPLIER;
+        * return ip_hdr_size_bytes;
+        */
+}
+
+static void
+rte_ct_set_timer_for_new_cnxn(
+               struct rte_ct_cnxn_tracker *ct,
+               struct rte_ct_cnxn_data *cd)
+{
+       cd->state_used_for_timer = RTE_CT_TCP_NONE;
+       rte_ct_set_cnxn_timer_for_tcp(ct, cd, RTE_CT_TCP_SYN_SENT);
+}
+
+/*
+ * The connection data is stored in a hash table which makes use of the bulk
+ * lookup optimization provided in DPDK. All of the packets seen in one call
+ * to rte_ct_cnxn_tracker_batch_lookup are done in one hash table lookup. The
+ * number of packets is the number being processed by the pipeline (default
+ * max 32, absolute max 64). For any TCP or UDP packet that does not have
+ * an existing (pseudo-)connection in the table (i.e. was a miss on the hash
+ * lookup), a new connection must be added.
+ *
+ * It is possible, for UDP, that the first packet for a (pseudo-)connection and
+ * a subsequent packet are in the same batch. This means that when looking for
+ * new connections in a batch the first one must add the connection, the
+ * second and subsequent (in that batch) that are part of the same connection
+ * must use that newly created one, not create another table entry.
+ *
+ * Any newly created entries are "remembered" in linear table, which is search
+ * when processing hash tables misses. All the entries in that table are
+ * "forgotten" at the start of a new batch.
+ *
+ * A linear table may seem slow, but consider:
+ * - out of millions of packets/second, this involves at most 64.
+ * - this affects only UDP. TCP connections are set up using an acknowledgement
+ *   protocl, so would not have multiple packets for new connection in
+ *   same batch (TODO)
+ * - the number of new connections in a batch would usually be zero, or a low
+ *   number like 1
+ * - all the data to search through should still be in cache
+ */
+
+static inline void
+rte_ct_remember_new_connection(
+       struct rte_ct_cnxn_tracker *ct,
+       struct rte_ct_cnxn_data *entry)
+{
+       ct->latest_connection++;
+       ct->new_connections[ct->latest_connection] = entry;
+}
+
+static struct rte_ct_cnxn_data *
+rte_ct_search_new_connections(struct rte_ct_cnxn_tracker *ct, uint32_t *key)
+{
+       int i;
+
+       for (i = 0; i <= ct->latest_connection; i++) {
+               uint32_t *cnxn_key = ct->new_connections[i]->key;
+               int key_cmp = memcmp(cnxn_key, key,
+                               sizeof(ct->new_connections[i]->key));
+
+               if (key_cmp == 0)
+                       return ct->new_connections[i];
+       }
+       return NULL;
+}
+
+static inline void rte_ct_forget_new_connections(struct rte_ct_cnxn_tracker *ct)
+{
+       ct->latest_connection = -1;
+}
+
+
+
+
+static enum rte_ct_packet_action
+rte_ct_handle_tcp_lookup(
+       struct  rte_ct_cnxn_tracker *ct,
+       struct  rte_mbuf *packet,
+       uint8_t pkt_num,
+       uint8_t key_is_client_order,
+       uint32_t *key,
+       int     hash_table_entry,
+       int     no_new_cnxn,
+       uint8_t ip_hdr_size_bytes)
+{
+       struct rte_ct_cnxn_data new_cnxn_data;
+
+       memset(&new_cnxn_data, 0, sizeof(struct rte_ct_cnxn_data));
+       enum rte_ct_packet_action packet_action;
+
+       #ifdef CT_CGNAT
+       int32_t position = hash_table_entry;
+       ct->positions[pkt_num] = position;
+       #endif
+
+       /* rte_ct_cnxn_print_pkt(packet); */
+       if (hash_table_entry >= 0) {
+               /*
+                * connection found for this packet.
+                * Check that this is a valid packet for connection
+                */
+
+               struct rte_ct_cnxn_data *entry =
+                               &ct->hash_table_entries[hash_table_entry];
+
+               packet_action = rte_ct_verify_tcp_packet(ct, entry, packet,
+                               key_is_client_order, ip_hdr_size_bytes);
+
+               switch (packet_action) {
+
+               case RTE_CT_FORWARD_PACKET:
+                       entry->counters.packets_forwarded++;
+                       break;
+
+               case RTE_CT_DROP_PACKET:
+                       entry->counters.packets_dropped++;
+                       return RTE_CT_DROP_PACKET;
+
+               case RTE_CT_REOPEN_CNXN_AND_FORWARD_PACKET:
+                       /* Entry already in hash table, just re-initialize */
+
+                       /* Don't use syproxy on re-init, since it
+                        * is a valid connection
+                        */
+
+                       if (rte_ct_tcp_new_connection(ct, &new_cnxn_data,
+                                               packet, 0, ip_hdr_size_bytes) !=
+                                       RTE_CT_DROP_PACKET) {
+                               rte_memcpy(&entry->ct_protocol.tcp_ct_data,
+                               &new_cnxn_data.ct_protocol.tcp_ct_data,
+                               sizeof(new_cnxn_data.ct_protocol.tcp_ct_data));
+                               rte_ct_set_timer_for_new_cnxn(ct, entry);
+                               if (ct->counters->sessions_reactivated > 0)
+                                       ct->counters->sessions_reactivated--;
+                       }
+
+                       break;
+
+               case RTE_CT_SEND_SERVER_SYN:
+                       ct->counters->pkts_forwarded++;
+                       /* packet modified, send back to original source */
+                       return RTE_CT_SEND_SERVER_SYN;
+
+               case RTE_CT_SEND_SERVER_ACK:
+                       ct->counters->pkts_forwarded++;
+                       /* packet modified, send back to original source */
+                       return RTE_CT_SEND_SERVER_ACK;
+
+               case RTE_CT_HIJACK:
+                       ct->counters->pkts_forwarded++;
+                       /* packet saved with connection, notify VNF
+                        * to hijack it
+                        */
+                       return RTE_CT_HIJACK;
+
+               case RTE_CT_DESTROY_CNXN_AND_FORWARD_PACKET:
+
+                       /*
+                        * Forward the packet because it is "legal", but destroy
+                        * the connection by removing it from the hash table and
+                        * cancelling any timer. There is a remote possibility
+                        * (perhaps impossible?) that a later packet in the same
+                        * batch is for this connection. Due to the batch
+                        * lookup, which has already happened, the later packet
+                        * thinks that the connection is valid. This might cause
+                        * a timer to be set. Eventually, it would time out so
+                        * the only bug case occurs if the hash table also, in
+                        * the same batch, allocates this entry for a new
+                        * connection before the above packet is received. The
+                        * chances of this happening seem impossibly small but
+                        * this case should perhaps be investigated further.
+                        */
+
+                       if (rte_hash_del_key(ct->rhash, entry->key) >= 0) {
+                               /*
+                                * if rte_hash_del_key >= 0, then the connection
+                                * was found in the hash table and removed.
+                                * Counters must be updated, and the timer
+                                * cancelled. If the result was < 0, then the
+                                * connection must have already been deleted,
+                                * and it must have been deleted in this batch
+                                * of packets processed. Do nothing.
+                                */
+
+                               ct->counters->sessions_closed++;
+                               if (ct->counters->current_active_sessions > 0)
+                                       ct->counters->current_active_sessions--;
+                               rte_ct_cancel_cnxn_timer(entry);
+                       }
+                       entry->counters.packets_forwarded++;
+                       break;
+
+               default:
+                       break;
+               }
+       } else {
+               /* try to add new connection */
+               struct rte_ct_cnxn_data *new_hash_entry;
+
+               if (no_new_cnxn) {
+                       ct->counters->pkts_drop_invalid_conn++;
+                       return RTE_CT_DROP_PACKET;
+               }
+
+               packet_action = rte_ct_tcp_new_connection(ct, &new_cnxn_data,
+                               packet, ct->misc_options.synproxy_enabled,
+                               ip_hdr_size_bytes);
+
+               if (unlikely(packet_action == RTE_CT_DROP_PACKET)) {
+                       ct->counters->pkts_drop_invalid_conn++;
+                       return RTE_CT_DROP_PACKET;
+               }
+
+               /* This packet creates a connection . */
+               int32_t position = rte_hash_add_key(ct->rhash, key);
+               if (position < 0) {
+                       printf
+                                       ("Failed to add new connection to hash table %d, pkt_num:%d\n",
+                                        position, pkt_num);
+                       return RTE_CT_DROP_PACKET;
+               }
+       #ifdef CT_CGNAT
+       ct->positions[pkt_num] = position;
+       #endif
+               new_hash_entry = &ct->hash_table_entries[position];
+
+               /* update fields in new_cnxn_data not set by new_connection */
+
+               memcpy(new_cnxn_data.key, key, sizeof(new_cnxn_data.key));
+               new_cnxn_data.key_is_client_order = key_is_client_order;
+               new_cnxn_data.protocol = TCP_PROTOCOL;
+               rte_cnxn_ip_type(&new_cnxn_data.type, packet);
+               rte_memcpy(new_hash_entry, &new_cnxn_data,
+                               sizeof(struct rte_ct_cnxn_data));
+               new_hash_entry->counters.packets_forwarded = 1;
+               new_hash_entry->counters.packets_dropped = 0;
+               ct->counters->current_active_sessions++;
+               ct->counters->sessions_activated++;
+
+               if (packet_action == RTE_CT_SEND_CLIENT_SYNACK) {
+                       /* this is a synproxied connecton */
+                       /* must remember mss, window scaling etc. from client */
+
+                       rte_sp_parse_options(packet, new_hash_entry);
+
+                       /*
+                        * update packet to a SYN/ACK directed to the client,
+                        * including default header options
+                        */
+
+                       rte_sp_cvt_to_spoofed_client_synack(new_hash_entry,
+                                       packet);
+
+                       /*
+                        * run updated packet through connection tracking so
+                        * cnxn data updated appropriately and timer set for syn
+                        * received state, not syn sent.
+                        */
+                       packet_action = rte_ct_verify_tcp_packet(ct,
+                                       new_hash_entry, packet,
+                                       !key_is_client_order,
+                                       ip_hdr_size_bytes);
+
+                       if (unlikely(packet_action != RTE_CT_FORWARD_PACKET)) {
+                               /* should never get here */
+                               printf("Serious error in synproxy generating ");
+                               printf("SYN/ACK\n");
+                               return RTE_CT_DROP_PACKET;
+                       }
+                       ct->counters->pkts_forwarded++;
+                       /* spoofed packet good to go */
+                       return RTE_CT_SEND_CLIENT_SYNACK;
+               }
+               rte_ct_set_timer_for_new_cnxn(ct, new_hash_entry);
+
+       }
+
+       /* TODO: is it possible that earlier packet in this batch caused new
+        * entry to be added for the connection? Seems unlikely, since it
+        * would require multiple packets from the same side of the connection
+        * one after another immediately, and the TCP connection OPEN requires
+        * acknowledgement before further packets. What about simultaneous
+        * OPEN? Only if both sides are on same input port. Is that possible?
+        */
+       /* if made it here, packet will be forwarded */
+       ct->counters->pkts_forwarded++;
+       return RTE_CT_FORWARD_PACKET;
+}
+
+static uint64_t
+rte_ct_cnxn_tracker_batch_lookup_basic(
+       struct rte_ct_cnxn_tracker *ct,
+       struct rte_mbuf **pkts,
+       uint64_t pkts_mask,
+       uint64_t no_new_cnxn_mask,
+       uint64_t *reply_pkt_mask,
+       uint64_t *hijack_mask)
+{
+       /* bitmap of packets left to process */
+       uint64_t pkts_to_process = pkts_mask;
+       /* bitmap of valid packets to return */
+       uint64_t valid_packets = pkts_mask;
+       uint8_t compacting_map[RTE_HASH_LOOKUP_BULK_MAX];
+       /* for pkt, key in originators direction? */
+       uint8_t key_orig_dir[RTE_HASH_LOOKUP_BULK_MAX];
+       uint32_t packets_for_lookup = 0;
+       int32_t positions[RTE_HASH_LOOKUP_BULK_MAX];
+       uint32_t i;
+       struct rte_ct_cnxn_data new_cnxn_data;
+
+       if (CNXN_TRX_DEBUG > 1) {
+               printf("Enter cnxn tracker %p", ct);
+               printf(" synproxy batch lookup with packet mask %p\n",
+                               (void *)pkts_mask);
+       }
+
+       rte_ct_forget_new_connections(ct);
+       *reply_pkt_mask = 0;
+       *hijack_mask = 0;
+
+       /*
+        * Use bulk lookup into hash table for performance reasons. Cannot have
+        * "empty slots" in the bulk lookup,so need to create a compacted table.
+        */
+
+       for (; pkts_to_process;) {
+               uint8_t pos = (uint8_t) __builtin_ctzll(pkts_to_process);
+               /* bitmask representing only this packet */
+               uint64_t pkt_mask = 1LLU << pos;
+               /* remove this packet from remaining list */
+               pkts_to_process &= ~pkt_mask;
+
+               struct rte_mbuf *pkt = pkts[pos];
+
+               int ip_hdr_size_bytes = rte_ct_get_IP_hdr_size(pkt);
+
+               if (unlikely(ip_hdr_size_bytes < 0)) {
+                       /* Not IPv4, ignore. */
+                       continue;
+               }
+
+               void *ip_hdr = RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
+
+               /* TCP and UDP ports at same offset, just use TCP for
+                * offset calculation
+                */
+               struct tcp_hdr *thdr =
+                       (struct tcp_hdr *)RTE_MBUF_METADATA_UINT32_PTR(pkt,
+                                       (IP_START + ip_hdr_size_bytes));
+               uint16_t src_port = rte_bswap16(thdr->src_port);
+               uint16_t dst_port = rte_bswap16(thdr->dst_port);
+
+               if (ip_hdr_size_bytes == IPv4_HEADER_SIZE) {
+                       struct ipv4_hdr *ihdr = (struct ipv4_hdr *)ip_hdr;
+                       uint8_t proto = ihdr->next_proto_id;
+
+                       if (!(proto == TCP_PROTOCOL || proto == UDP_PROTOCOL)) {
+                               /* only tracking TCP and UDP at this time */
+                               continue;
+                       }
+
+                       /*
+                        * Load the addresses and ports, and convert from Intel
+                        * to network byte order. Strictly speaking, it is not
+                        * necessary to do this conversion, as this data is only
+                        * used to create a hash key.
+                        */
+                       uint32_t src_addr = rte_bswap32(ihdr->src_addr);
+                       uint32_t dst_addr = rte_bswap32(ihdr->dst_addr);
+
+                       if (CNXN_TRX_DEBUG > 2) {
+                               if (CNXN_TRX_DEBUG > 4)
+                                       rte_ct_cnxn_print_pkt(pkt,
+                                                       IP_VERSION_4);
+                       }
+                       /* need to create compacted table of pointers to pass
+                        * to bulk lookup
+                        */
+
+                       compacting_map[packets_for_lookup] = pos;
+                       key_orig_dir[packets_for_lookup] =
+                               rte_ct_create_cnxn_hashkey(&src_addr, &dst_addr,
+                                               src_port, dst_port,
+                                               proto,
+                                               &ct->hash_keys
+                                               [packets_for_lookup][0],
+                                               IP_VERSION_4);
+                       packets_for_lookup++;
+               }
+
+               if (ip_hdr_size_bytes == IPv6_HEADER_SIZE) {
+                       struct ipv6_hdr *ihdr = (struct ipv6_hdr *)ip_hdr;
+                       uint8_t proto = ihdr->proto;
+
+                       if (!(proto == TCP_PROTOCOL || proto == UDP_PROTOCOL)) {
+                               /* only tracking TCP and UDP at this time */
+                               continue;
+                       }
+
+                       if (CNXN_TRX_DEBUG > 2) {
+                               if (CNXN_TRX_DEBUG > 4)
+                                       rte_ct_cnxn_print_pkt(pkt,
+                                                       IP_VERSION_6);
+                       }
+
+                       /* need to create compacted table of pointers to pass
+                        * to bulk lookup
+                        */
+
+                       compacting_map[packets_for_lookup] = pos;
+                       key_orig_dir[packets_for_lookup] =
+                               rte_ct_create_cnxn_hashkey(
+                                               (uint32_t *) ihdr->src_addr,
+                                               (uint32_t *) ihdr->dst_addr,
+                                               src_port, dst_port,
+                                               proto,
+                                               &ct->hash_keys
+                                               [packets_for_lookup][0],
+                                               IP_VERSION_6);
+                       packets_for_lookup++;
+               }
+
+       }
+
+       if (unlikely(packets_for_lookup == 0))
+               return valid_packets;   /* no suitable packet for lookup */
+
+       /* Clear all the data to make sure no stack garbage is in it */
+       memset(&new_cnxn_data, 0, sizeof(struct rte_ct_cnxn_data));
+
+       /* lookup all tcp & udp packets in the connection table */
+
+       int lookup_result =
+                       rte_hash_lookup_bulk(ct->rhash, (const void **)&ct->hash_key_ptrs,
+                                packets_for_lookup, &positions[0]);
+
+       if (unlikely(lookup_result < 0)) {
+               /* TODO: change a log */
+               printf("Unexpected hash table problem, discarding all packets");
+               return 0;       /* unknown error, just discard all packets */
+       }
+#ifdef ALGDBG
+       for (i = 0; i < packets_for_lookup; i++) {
+               if (positions[i] >= 0)
+               printf("@CT positions[i]= %d, compacting_map[i]= %d\n",
+                       positions[i], compacting_map[i]);
+       }
+#endif
+       for (i = 0; i < packets_for_lookup; i++) {
+               /* index into hash table entries */
+               int hash_table_entry = positions[i];
+               /* index into packet table of this packet */
+               uint8_t pkt_index = compacting_map[i];
+               /* bitmask representing only this packet */
+               uint64_t pkt_mask = 1LLU << pkt_index;
+               uint8_t key_is_client_order = key_orig_dir[i];
+               uint32_t *key = ct->hash_key_ptrs[pkt_index];
+               uint8_t protocol = *(key + 9);
+               struct rte_mbuf *packet = pkts[pkt_index];
+               int no_new_cnxn = (pkt_mask & no_new_cnxn_mask) != 0;
+
+                /* rte_ct_print_hashkey(key); */
+
+               if (protocol == TCP_PROTOCOL) {
+                       enum rte_ct_packet_action tcp_pkt_action;
+
+                       int ip_hdr_size_bytes = rte_ct_get_IP_hdr_size(packet);
+                       tcp_pkt_action = rte_ct_handle_tcp_lookup(ct, packet,
+                                       pkt_index, key_is_client_order,
+                                       key, hash_table_entry, no_new_cnxn,
+                                       ip_hdr_size_bytes);
+
+                       switch (tcp_pkt_action) {
+
+                       case RTE_CT_SEND_CLIENT_SYNACK:
+                       case RTE_CT_SEND_SERVER_ACK:
+                               /* altered packet or copy must be returned
+                                * to originator
+                                */
+                               *reply_pkt_mask |= pkt_mask;
+                               /* FALL-THROUGH */
+
+                       case RTE_CT_SEND_SERVER_SYN:
+                       case RTE_CT_FORWARD_PACKET:
+                               break;
+
+                       case RTE_CT_HIJACK:
+                               *hijack_mask |= pkt_mask;
+                               break;
+
+                       default:
+                               /* bad packet, clear mask to drop */
+                               valid_packets ^= pkt_mask;
+                               ct->counters->pkts_drop++;
+                               break;
+                       }
+
+                       /* rte_ct_cnxn_print_pkt(pkts[pkt_index]); */
+               } else {        /* UDP entry */
+
+                       if (hash_table_entry >= 0) {
+                               /*
+                                * connection found for this packet. Check that
+                                * this is a valid packet for connection
+                                */
+
+                               struct rte_ct_cnxn_data *entry =
+                                               &ct->hash_table_entries[hash_table_entry];
+
+                               if (rte_ct_udp_packet
+                                               (ct, entry, pkts[pkt_index],
+                                                key_is_client_order)) {
+                                       entry->counters.packets_forwarded++;
+                                       ct->counters->pkts_forwarded++;
+                               }
+                       } else {
+                               /*
+                                * connection not found in bulk hash lookup,
+                                * but might have been added in this batch
+                                */
+
+                               struct rte_ct_cnxn_data *recent_entry =
+                                               rte_ct_search_new_connections(ct, key);
+
+                               if (recent_entry != NULL) {
+                                       if (rte_ct_udp_packet(ct, recent_entry,
+                                                       pkts[pkt_index],
+                                                       key_is_client_order)) {
+                                               recent_entry->counters.
+                                                       packets_forwarded++;
+                                               ct->counters->pkts_forwarded++;
+                                       }
+                               } else {
+                                       /* no existing connection, try to add
+                                        * new one
+                                        */
+
+                                       if (no_new_cnxn) {
+                                               /* new cnxn not allowed, clear
+                                                * mask to drop
+                                                */
+                                               valid_packets ^= pkt_mask;
+                                               ct->counters->pkts_drop++;
+                                               ct->counters->
+                                               pkts_drop_invalid_conn++;
+                                               continue;
+                                       }
+
+                                       if (rte_ct_udp_new_connection(ct,
+                                                       &new_cnxn_data,
+                                                       pkts[pkt_index])) {
+                                               /* This packet creates a
+                                                * connection .
+                                                */
+                                               int32_t position =
+                                                       rte_hash_add_key(
+                                                               ct->rhash, key);
+
+                                       if (position < 0)
+                                               continue;
+
+                                               struct rte_ct_cnxn_data
+                                                       *new_hash_entry = &ct->
+                                               hash_table_entries[position];
+
+                                               /*
+                                                *update fields in new_cnxn_data
+                                                * not set by "new_connection"
+                                                */
+
+                                               memcpy(new_cnxn_data.key, key,
+                                               sizeof(new_cnxn_data.key));
+
+                                               new_cnxn_data.
+                                                       key_is_client_order
+                                                       = key_is_client_order;
+                                               new_cnxn_data.protocol =
+                                                       UDP_PROTOCOL;
+                                               rte_cnxn_ip_type(
+                                                       &new_cnxn_data.type,
+                                                       packet);
+                                               rte_memcpy(new_hash_entry,
+                                                       &new_cnxn_data,
+                                                       sizeof(struct
+                                                       rte_ct_cnxn_data));
+
+                                               new_hash_entry->counters.
+                                                       packets_forwarded = 1;
+                                               ct->counters->pkts_forwarded++;
+                                               new_hash_entry->counters.
+                                                       packets_dropped = 0;
+                                               ct->counters->pkts_drop = 0;
+                                               ct->counters->
+                                               current_active_sessions++;
+                                               ct->counters->
+                                                       sessions_activated++;
+
+                                               new_hash_entry->
+                                                       state_used_for_timer
+                                                       = RTE_CT_UDP_NONE;
+                                               rte_ct_set_cnxn_timer_for_udp(
+                                                       ct,
+                                                       new_hash_entry,
+                                                       RTE_CT_UDP_UNREPLIED);
+
+                                               rte_ct_remember_new_connection(
+                                                               ct,
+                                                               new_hash_entry);
+                                       }
+                               }
+
+                       }
+
+               }               /* UDP */
+       }                       /* packets_for_lookup */
+
+       if (CNXN_TRX_DEBUG > 1) {
+               printf("Exit cnxn tracker synproxy batch lookup with");
+               printf(" packet mask %p\n", (void *)valid_packets);
+       }
+
+       return valid_packets;
+}
+
+uint64_t
+rte_ct_cnxn_tracker_batch_lookup_with_synproxy(
+       struct rte_ct_cnxn_tracker *ct,
+       struct rte_mbuf **pkts,
+       uint64_t pkts_mask,
+       struct rte_synproxy_helper *sp_helper)
+{
+       return rte_ct_cnxn_tracker_batch_lookup_basic(ct, pkts, pkts_mask, 0,
+                       &sp_helper->reply_pkt_mask, &sp_helper->hijack_mask);
+}
+#ifdef CT_CGNAT
+uint64_t cgnapt_ct_process(
+       struct rte_ct_cnxn_tracker *ct,
+       struct rte_mbuf **pkts,
+       uint64_t pkts_mask,
+       struct rte_CT_helper *ct_helper)
+{
+/* to disable SynProxy for CGNAT */
+       rte_ct_disable_synproxy(ct);
+       return rte_ct_cnxn_tracker_batch_lookup_basic(ct, pkts, pkts_mask,
+                                       ct_helper->no_new_cnxn_mask,
+                                       &ct_helper->reply_pkt_mask,
+                                       &ct_helper->hijack_mask);
+}
+#endif/*CT-CGNAT*/
+uint64_t
+rte_ct_cnxn_tracker_batch_lookup(
+       struct rte_ct_cnxn_tracker *ct,
+       struct rte_mbuf **pkts,
+       uint64_t pkts_mask,
+       struct rte_CT_helper *ct_helper)
+{
+
+       return rte_ct_cnxn_tracker_batch_lookup_basic(ct, pkts, pkts_mask,
+                       ct_helper->no_new_cnxn_mask,
+                       &ct_helper->reply_pkt_mask, &ct_helper->hijack_mask);
+}
+
+
+void rte_ct_cnxn_tracker_batch_lookup_type(
+       struct rte_ct_cnxn_tracker *ct,
+       struct rte_mbuf **pkts,
+       uint64_t *pkts_mask,
+       struct rte_CT_helper *ct_helper,
+       uint8_t ip_hdr_size_bytes)
+{
+
+       rte_ct_cnxn_tracker_batch_lookup_basic_type(ct, pkts, pkts_mask,
+                       ct_helper->no_new_cnxn_mask,
+                       &ct_helper->reply_pkt_mask, &ct_helper->hijack_mask,
+                       ip_hdr_size_bytes);
+}
+
+
+
+uint64_t
+rte_ct_cnxn_tracker_batch_lookup_with_new_cnxn_control(
+       struct rte_ct_cnxn_tracker *ct,
+       struct rte_mbuf **pkts,
+       uint64_t pkts_mask,
+       uint64_t no_new_cnxn_mask)
+{
+       uint64_t dont_care;
+
+       return rte_ct_cnxn_tracker_batch_lookup_basic(ct, pkts, pkts_mask,
+                       no_new_cnxn_mask,
+                       &dont_care, &dont_care);
+}
+
+
+int
+rte_ct_initialize_default_timeouts(struct rte_ct_cnxn_tracker *new_cnxn_tracker)
+{
+
+       /* timer system init */
+
+       uint64_t hertz = rte_get_tsc_hz();
+
+       new_cnxn_tracker->hertz = hertz;
+       new_cnxn_tracker->timing_cycles_per_timing_step = hertz / 10;
+       new_cnxn_tracker->timing_100ms_steps_previous = 0;
+       new_cnxn_tracker->timing_100ms_steps = 0;
+       new_cnxn_tracker->timing_last_time = rte_get_tsc_cycles();
+
+       /* timeouts in seconds */
+       new_cnxn_tracker->ct_timeout.tcptimeout.tcp_timeouts
+               [RTE_CT_TCP_SYN_SENT] = 120 * hertz;
+       new_cnxn_tracker->ct_timeout.tcptimeout.tcp_timeouts
+               [RTE_CT_TCP_SYN_RECV] = 60 * hertz;
+       /* 5 * DAYS */
+       new_cnxn_tracker->ct_timeout.tcptimeout.tcp_timeouts
+               [RTE_CT_TCP_ESTABLISHED] = 60 * 60 * 24 * 5 * hertz;
+
+       new_cnxn_tracker->ct_timeout.tcptimeout.tcp_timeouts
+               [RTE_CT_TCP_FIN_WAIT] = 120 * hertz;
+       new_cnxn_tracker->ct_timeout.tcptimeout.tcp_timeouts
+               [RTE_CT_TCP_CLOSE_WAIT] = 60 * hertz;
+       new_cnxn_tracker->ct_timeout.tcptimeout.tcp_timeouts
+               [RTE_CT_TCP_LAST_ACK] = 30 * hertz;
+       new_cnxn_tracker->ct_timeout.tcptimeout.tcp_timeouts
+               [RTE_CT_TCP_TIME_WAIT] = 120 * hertz;
+       new_cnxn_tracker->ct_timeout.tcptimeout.tcp_timeouts
+               [RTE_CT_TCP_CLOSE] = 10 * hertz;
+       new_cnxn_tracker->ct_timeout.tcptimeout.tcp_timeouts
+               [RTE_CT_TCP_SYN_SENT_2] = 120 * hertz;
+       new_cnxn_tracker->ct_timeout.tcptimeout.tcp_timeouts
+               [RTE_CT_TCP_RETRANS] = 300 * hertz;
+       new_cnxn_tracker->ct_timeout.tcptimeout.tcp_timeouts
+               [RTE_CT_TCP_UNACK] = 300 * hertz;
+
+       new_cnxn_tracker->ct_timeout.udptimeout.udp_timeouts
+               [RTE_CT_UDP_UNREPLIED] = 30 * hertz;
+       new_cnxn_tracker->ct_timeout.udptimeout.udp_timeouts
+               [RTE_CT_UDP_REPLIED] = 180 * hertz;
+       /* miscellaneous init */
+       new_cnxn_tracker->misc_options.tcp_max_retrans =
+               RTE_CT_TCP_MAX_RETRANS;
+       new_cnxn_tracker->misc_options.tcp_loose = 0;
+       new_cnxn_tracker->misc_options.tcp_be_liberal = 0;
+#ifdef CT_CGNAT
+       int i;
+       for (i=0; i < RTE_HASH_LOOKUP_BULK_MAX ;i ++ )
+                       new_cnxn_tracker->positions[i] = -1;
+#endif
+
+       return 0;
+}
+
+struct rte_CT_counter_block rte_CT_counter_table[MAX_CT_INSTANCES]
+__rte_cache_aligned;
+int rte_CT_hi_counter_block_in_use = -1;
+
+int
+rte_ct_initialize_cnxn_tracker_with_synproxy(
+       struct rte_ct_cnxn_tracker *new_cnxn_tracker,
+       uint32_t max_connection_count,
+       char *name,
+       uint16_t pointer_offset)
+{
+       uint32_t i;
+       uint32_t size;
+       struct rte_CT_counter_block *counter_ptr;
+       /*
+        * TODO: Should number of entries be something like
+        * max_connection_count * 1.1 to allow for unused space
+        * and thus increased performance of hash table, at a cost of memory???
+        */
+
+       new_cnxn_tracker->pointer_offset = pointer_offset;
+
+       memset(new_cnxn_tracker->name, '\0', sizeof(new_cnxn_tracker->name));
+       strncpy(new_cnxn_tracker->name, name, strlen(new_cnxn_tracker->name));
+       //strcpy(new_cnxn_tracker->name, name);
+       /* + (max_connection_count >> 3); */
+       uint32_t number_of_entries = max_connection_count;
+
+       size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct rte_ct_cnxn_data) *
+                       number_of_entries);
+       new_cnxn_tracker->hash_table_entries =
+               rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
+       if (new_cnxn_tracker->hash_table_entries == NULL) {
+               printf(" Not enough memory, or invalid arguments\n");
+               return -1;
+       }
+       new_cnxn_tracker->num_cnxn_entries = number_of_entries;
+
+       /* initialize all timers */
+
+       for (i = 0; i < number_of_entries; i++)
+               rte_timer_init(&new_cnxn_tracker->hash_table_entries[i].timer);
+
+       /* pointers for temp storage used during bulk hash */
+       for (i = 0; i < RTE_HASH_LOOKUP_BULK_MAX; i++)
+               new_cnxn_tracker->hash_key_ptrs[i] =
+                               &new_cnxn_tracker->hash_keys[i][0];
+
+       /*
+        * Now allocate a counter block entry.It appears that the initialization
+        * of these threads is serialized on core 0 so no lock is necessary
+        */
+
+       if (rte_CT_hi_counter_block_in_use == MAX_CT_INSTANCES)
+               return -1;
+
+       rte_CT_hi_counter_block_in_use++;
+       counter_ptr = &rte_CT_counter_table[rte_CT_hi_counter_block_in_use];
+
+       new_cnxn_tracker->counters = counter_ptr;
+
+       /* set up hash table parameters, then create hash table */
+       struct rte_hash_parameters rhash_parms = {
+               .name = name,
+               .entries = number_of_entries,
+               .hash_func = NULL,      /* use default hash */
+               .key_len = 40,
+               .hash_func_init_val = 0,
+               .socket_id = rte_socket_id(),
+               .extra_flag = 1 /*This is needed for TSX memory*/
+       };
+
+       new_cnxn_tracker->rhash = rte_hash_create(&rhash_parms);
+
+       return 0;
+}
+
+int
+rte_ct_initialize_cnxn_tracker(
+       struct rte_ct_cnxn_tracker *new_cnxn_tracker,
+       uint32_t max_connection_count,
+       char *name)
+{
+       return rte_ct_initialize_cnxn_tracker_with_synproxy(new_cnxn_tracker,
+                               max_connection_count, name, 0);
+}
+
+int
+rte_ct_free_cnxn_tracker_resources(struct rte_ct_cnxn_tracker *old_cnxn_tracker)
+{
+       rte_free(old_cnxn_tracker->hash_table_entries);
+       rte_hash_free(old_cnxn_tracker->rhash);
+       return 0;
+}
+
+int
+rte_ct_get_cnxn_tracker_size(void)
+{
+       return sizeof(struct rte_ct_cnxn_tracker);
+}
+
+void
+rte_ct_cnxn_timer_expired(struct rte_timer *rt, void *arg);
+
+static void
+rte_ct_set_cnxn_timer(
+       struct rte_ct_cnxn_tracker *ct,
+       struct rte_ct_cnxn_data *cd,
+       uint64_t ticks_until_timeout)
+{
+       /*
+        * pointer to cnxn_data will be stored in timer system as pointer to
+        * rte_timer for later cast back to cnxn_data during timeout handling
+        */
+
+       struct rte_timer *rt = (struct rte_timer *)cd;
+       #ifdef CT_CGNAT
+       /* execute timeout on timer core */
+       uint32_t core_id = get_timer_core_id();
+       #else
+       /* execute timeout on current core */
+       uint32_t core_id = rte_lcore_id();
+       #endif
+       /* safe to reset since timeouts handled synchronously
+        * by rte_timer_manage
+        */
+       int success = rte_timer_reset(rt, ticks_until_timeout, SINGLE, core_id,
+                       rte_ct_cnxn_timer_expired, ct);
+
+       if (success < 0) {
+               /* TODO: Change to log, perhaps something else?
+                * This should not happen
+                */
+               printf("CNXN_TRACKER: Failed to set connection timer.\n");
+       }
+}
+
+/*
+ * For the given connection, set a timeout based on the given state. If the
+* timer is already set, this call will reset the timer with a new value.
+ */
+
+void
+rte_ct_set_cnxn_timer_for_tcp(
+       struct rte_ct_cnxn_tracker *ct,
+       struct rte_ct_cnxn_data *cd,
+       uint8_t tcp_state)
+{
+
+       cd->expected_timeout =
+                       (ct->timing_100ms_steps * ct->timing_cycles_per_timing_step) +
+                       ct->ct_timeout.tcptimeout.tcp_timeouts[tcp_state];
+
+       if (tcp_state == cd->state_used_for_timer) {
+               /*
+                * Don't reset timer, too expensive. Instead, determine time
+                * elapsed since start of timer. When this timer expires, the
+                * timer will be reset to the elapsed timer. So if in a state
+                * with a 5 minute timer last sees a packet 4 minutes into the
+                * timer, the timer when expires will be reset to 4 minutes.
+                * This means the timer will then expire 5 minutes after
+                * the last packet.
+                */
+               return;
+       }
+
+       if (TESTING_TIMERS)
+               printf("Set Timer for connection %p and state %s\n", cd,
+                                        rte_ct_tcp_names[tcp_state]);
+
+       rte_ct_set_cnxn_timer(ct, cd,
+                                               ct->ct_timeout.
+                                               tcptimeout.tcp_timeouts[tcp_state]);
+       cd->state_used_for_timer = tcp_state;
+}
+
+/*
+ * For the given connection, set a timeout based on the given state.
+ * If the timer is already set,
+ * this call will reset the timer with a new value.
+ */
+
+void
+rte_ct_set_cnxn_timer_for_udp(
+       struct rte_ct_cnxn_tracker *ct,
+       struct rte_ct_cnxn_data *cd,
+       uint8_t udp_state)
+{
+
+       cd->expected_timeout = (ct->timing_cycles_per_timing_step) +
+                       ct->ct_timeout.udptimeout.udp_timeouts[udp_state];
+
+       if (udp_state == cd->state_used_for_timer) {
+               /*
+                * Don't reset timer, too expensive. Instead, determine time
+                * elapsed since start of timer. When this timer expires, the
+                * timer will be reset to the elapsed timer. So if in a state
+                * with a 5 minute timer last sees a packet 4 minutes into the
+                * timer, the timer when expires will be reset to 4 minutes.
+                * This means the timer will then
+                * expire 5 minutes after the last packet.
+                */
+               return;
+       }
+
+       if (TESTING_TIMERS)
+               printf("Set Timer for connection %p and state %s\n", cd,
+                                        rte_ct_udp_names[udp_state]);
+       rte_ct_set_cnxn_timer(ct, cd,
+                                               ct->ct_timeout.
+                                               udptimeout.udp_timeouts[udp_state]);
+       cd->state_used_for_timer = udp_state;
+}
+
+/* Cancel the timer associated with the connection.
+ * Safe to call if no timer set.
+ */
+       void
+rte_ct_cancel_cnxn_timer(struct rte_ct_cnxn_data *cd)
+{
+       if (TESTING_TIMERS)
+               printf("Cancel Timer\n");
+
+       rte_timer_stop(&cd->timer);
+}
+
+void
+rte_ct_handle_expired_timers(struct rte_ct_cnxn_tracker *ct)
+{
+       /*
+        * If current time (in 100 ms increments) is different from the
+        * time it was last viewed, then check for and process expired timers.
+        */
+
+       uint64_t new_time = rte_get_tsc_cycles();
+       uint64_t time_diff = new_time - ct->timing_last_time;
+
+       if (time_diff >= ct->timing_cycles_per_timing_step) {
+               ct->timing_last_time = new_time;
+               ct->timing_100ms_steps++;
+       }
+
+       if (ct->timing_100ms_steps != ct->timing_100ms_steps_previous) {
+               rte_timer_manage();
+               ct->timing_100ms_steps_previous = ct->timing_100ms_steps;
+       }
+}
+
+/* timer has expired. Need to delete connection entry */
+
+void
+rte_ct_cnxn_timer_expired(struct rte_timer *rt, void *arg)
+{
+       /* the pointer to the rte_timer was actually a pointer
+        * to the cnxn data
+        */
+       struct rte_ct_cnxn_data *cd = (struct rte_ct_cnxn_data *)rt;
+       struct rte_ct_cnxn_tracker *ct = (struct rte_ct_cnxn_tracker *)arg;
+       int success = 0;
+
+       /*
+        * Check to see if the timer has "really" expired. If traffic occured
+        * since the timer was set, the timer needs be extended, so that timer
+        * expires the appropriate amount after that last packet.
+        */
+
+       uint64_t current_time = ct->timing_100ms_steps *
+               ct->timing_cycles_per_timing_step;
+
+       if (cd->expected_timeout >= current_time) {
+               uint64_t time_diff = cd->expected_timeout - current_time;
+
+               rte_ct_set_cnxn_timer(ct, cd, time_diff);
+               return;
+       }
+
+       if (cd->protocol == TCP_PROTOCOL) {
+               if (cd->state_used_for_timer == RTE_CT_TCP_TIME_WAIT ||
+                               cd->state_used_for_timer == RTE_CT_TCP_CLOSE)
+                       ct->counters->sessions_closed++;
+               else
+                       ct->counters->sessions_timedout++;
+               /* if synproxied connection, free list of buffered
+                * packets if any
+                */
+
+               if (cd->ct_protocol.synproxy_data.synproxied)
+                       rte_ct_release_buffered_packets(ct, cd);
+
+       } else if (cd->protocol == UDP_PROTOCOL)
+               ct->counters->sessions_closed++;
+       if (ct->counters->current_active_sessions > 0)
+               ct->counters->current_active_sessions--;
+
+       if (RTE_CT_TIMER_EXPIRED_DUMP) {
+               uint64_t percent = (cd->counters.packets_dropped * 10000) /
+                               (cd->counters.packets_forwarded +
+                                cd->counters.packets_dropped);
+
+               if (cd->protocol == TCP_PROTOCOL) {
+                       printf("CnxnTrkr %s, timed-out TCP Connection: %p,",
+                                       ct->name, cd);
+                       printf(" %s, pkts forwarded %"
+                               PRIu64 ", pkts dropped %" PRIu64
+                               ", drop%% %u.%u\n",
+                               rte_ct_tcp_names[cd->state_used_for_timer],
+                               cd->counters.packets_forwarded,
+                               cd->counters.packets_dropped,
+                               (uint32_t) (percent / 100),
+                               (uint32_t) (percent % 100));
+               } else if (cd->protocol == UDP_PROTOCOL) {
+                       printf("CnxnTrkr %s, Timed-out UDP Connection: %p,",
+                                       ct->name, cd);
+                       printf(" %s, pkts forwarded %" PRIu64
+                               ", pkts dropped %" PRIu64 ", drop%% %u.%u\n",
+                               rte_ct_udp_names[cd->state_used_for_timer],
+                               cd->counters.packets_forwarded,
+                               cd->counters.packets_dropped,
+                               (uint32_t) (percent / 100),
+                               (uint32_t) (percent % 100));
+               }
+       }
+
+       success = rte_hash_del_key(ct->rhash, &cd->key);
+
+       if (success < 0) {
+               /* TODO: change to a log */
+               rte_ct_print_hashkey(cd->key);
+       }
+
+}
+
+struct rte_CT_counter_block *
+rte_ct_get_counter_address(struct rte_ct_cnxn_tracker *ct)
+{
+       return ct->counters;
+}
+
+int
+rte_ct_set_configuration_options(struct rte_ct_cnxn_tracker *ct,
+               char *name, char *value)
+{
+       /* check non-time values first */
+       int ival = atoi(value);
+
+       /* tcp_loose */
+       if (strcmp(name, "tcp_loose") == 0) {
+               ct->misc_options.tcp_loose = ival;
+               return 0;
+       }
+
+       /* tcp_be_liberal */
+       if (strcmp(name, "tcp_be_liberal") == 0) {
+               ct->misc_options.tcp_be_liberal = ival;
+               return 0;
+       }
+
+       /* tcp_max_retrans */
+       if (strcmp(name, "tcp_max_retrans") == 0) {
+               ct->misc_options.tcp_max_retrans = ival;
+               return 0;
+       }
+
+       uint64_t time_value = ival * ct->hertz;
+
+
+       /* configuration of timer values */
+
+       /* tcp_syn_sent */
+       if (strcmp(name, "tcp_syn_sent") == 0) {
+               if (time_value == 0)
+                       return -1;
+               ct->ct_timeout.tcptimeout.tcp_timeouts[RTE_CT_TCP_SYN_SENT] =
+                       time_value;
+               return 0;
+       }
+
+       /* tcp_syn_recv */
+       if (strcmp(name, "tcp_syn_recv") == 0) {
+               if (time_value == 0)
+                       return -1;
+               ct->ct_timeout.tcptimeout.tcp_timeouts[RTE_CT_TCP_SYN_RECV] =
+                       time_value;
+               return 0;
+       }
+
+       /* tcp_established */
+       if (strcmp(name, "tcp_established") == 0) {
+               if (time_value == 0)
+                       return -1;
+               ct->ct_timeout.tcptimeout.tcp_timeouts[RTE_CT_TCP_ESTABLISHED] =
+                       time_value;
+               return 0;
+       }
+
+       /* tcp_fin_wait */
+       if (strcmp(name, "tcp_fin_wait") == 0) {
+               if (time_value == 0)
+                       return -1;
+               ct->ct_timeout.tcptimeout.tcp_timeouts[RTE_CT_TCP_FIN_WAIT] =
+                       time_value;
+               return 0;
+       }
+
+       /* tcp_close_wait */
+       if (strcmp(name, "tcp_close_wait") == 0) {
+               if (time_value == 0)
+                       return -1;
+               ct->ct_timeout.tcptimeout.tcp_timeouts[RTE_CT_TCP_CLOSE_WAIT] =
+                       time_value;
+               return 0;
+       }
+
+       /* tcp_last_ack */
+       if (strcmp(name, "tcp_last_ack") == 0) {
+               if (time_value == 0)
+                       return -1;
+               ct->ct_timeout.tcptimeout.tcp_timeouts[RTE_CT_TCP_LAST_ACK] =
+                       time_value;
+               return 0;
+       }
+
+       /* tcp_time_wait */
+       if (strcmp(name, "tcp_time_wait") == 0) {
+               if (time_value == 0)
+                       return -1;
+               ct->ct_timeout.tcptimeout.tcp_timeouts[RTE_CT_TCP_TIME_WAIT] =
+                       time_value;
+               return 0;
+       }
+
+       /* tcp_close */
+       if (strcmp(name, "tcp_close") == 0) {
+               if (time_value == 0)
+                       return -1;
+               ct->ct_timeout.tcptimeout.tcp_timeouts[RTE_CT_TCP_CLOSE] =
+                       time_value;
+               return 0;
+       }
+
+       /* tcp_syn_sent_2 */
+       if (strcmp(name, "tcp_syn_sent_2") == 0) {
+               if (time_value == 0)
+                       return -1;
+               ct->ct_timeout.tcptimeout.tcp_timeouts[RTE_CT_TCP_SYN_SENT_2] =
+                       time_value;
+               return 0;
+       }
+
+       /* tcp_retrans */
+       if (strcmp(name, "tcp_retrans") == 0) {
+               if (time_value == 0)
+                       return -1;
+               ct->ct_timeout.tcptimeout.tcp_timeouts[RTE_CT_TCP_RETRANS] =
+                       time_value;
+               return 0;
+       }
+
+       /* tcp_unack */
+       if (strcmp(name, "tcp_unack") == 0) {
+               if (time_value == 0)
+                       return -1;
+               ct->ct_timeout.tcptimeout.tcp_timeouts[RTE_CT_TCP_UNACK] =
+                       time_value;
+               return 0;
+       }
+
+       /* udp_unreplied */
+       if (strcmp(name, "udp_unreplied") == 0) {
+               if (time_value == 0)
+                       return -1;
+               ct->ct_timeout.udptimeout.udp_timeouts[RTE_CT_UDP_UNREPLIED] =
+                       time_value;
+               return 0;
+       }
+
+       /* udp_replied */
+       if (strcmp(name, "udp_replied") == 0) {
+               if (time_value == 0)
+                       return -1;
+               ct->ct_timeout.udptimeout.udp_timeouts[RTE_CT_UDP_REPLIED] =
+                       time_value;
+               return 0;
+       }
+       return 1;
+}
+
+static void
+rte_ct_cnxn_tracker_batch_lookup_basic_type(
+               struct rte_ct_cnxn_tracker *ct,
+               struct rte_mbuf **pkts,
+               uint64_t *pkts_mask,
+               uint64_t no_new_cnxn_mask,
+               uint64_t *reply_pkt_mask,
+               uint64_t *hijack_mask,
+               uint8_t ip_hdr_size_bytes)
+{
+       /* bitmap of packets left to process */
+       uint64_t pkts_to_process = *pkts_mask;
+       /* bitmap of valid packets to return */
+       uint8_t compacting_map[RTE_HASH_LOOKUP_BULK_MAX];
+       /* for pkt, key in originators direction? */
+       uint8_t key_orig_dir[RTE_HASH_LOOKUP_BULK_MAX];
+       uint32_t packets_for_lookup = 0;
+       int32_t positions[RTE_HASH_LOOKUP_BULK_MAX];
+       uint32_t i;
+       struct rte_ct_cnxn_data new_cnxn_data;
+
+       if (CNXN_TRX_DEBUG > 1) {
+               printf("Enter cnxn tracker %p", ct);
+               printf(" synproxy batch lookup with packet mask %p\n",
+                               (void *)*pkts_mask);
+       }
+
+       rte_ct_forget_new_connections(ct);
+       *reply_pkt_mask = 0;
+       *hijack_mask = 0;
+
+       /*
+        * Use bulk lookup into hash table for performance reasons. Cannot have
+        * "empty slots" in the bulk lookup,so need to create a compacted table.
+        */
+
+       switch (ip_hdr_size_bytes) {
+       case IPv4_HEADER_SIZE:
+               for (; pkts_to_process;) {
+                       uint8_t pos = (uint8_t) __builtin_ctzll(
+                                       pkts_to_process);
+                       /* bitmask representing only this packet */
+                       uint64_t pkt_mask = 1LLU << pos;
+                       /* remove this packet from remaining list */
+                       pkts_to_process &= ~pkt_mask;
+
+                       struct rte_mbuf *pkt = pkts[pos];
+
+
+                       /* TCP and UDP ports at same offset, just use TCP for
+                        * offset calculation
+                        */
+                       struct tcp_hdr *thdr = (struct tcp_hdr *)
+                               RTE_MBUF_METADATA_UINT32_PTR(pkt,
+                                               (IP_START + ip_hdr_size_bytes));
+                       uint16_t src_port = rte_bswap16(thdr->src_port);
+                       uint16_t dst_port = rte_bswap16(thdr->dst_port);
+
+                       struct ipv4_hdr *ihdr = (struct ipv4_hdr *)
+                               RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
+                       uint8_t proto = ihdr->next_proto_id;
+
+                       if (!(proto == TCP_PROTOCOL || proto == UDP_PROTOCOL)) {
+                               /* only tracking TCP and UDP at this time */
+                               continue;
+                       }
+
+                       /*
+                        * Load the addresses and ports, and convert from Intel
+                        * to network byte order. Strictly speaking, it is not
+                        * necessary to do this conversion, as this data is only
+                        * used to create a hash key.
+                        */
+                       uint32_t src_addr = rte_bswap32(ihdr->src_addr);
+                       uint32_t dst_addr = rte_bswap32(ihdr->dst_addr);
+
+                       if (CNXN_TRX_DEBUG > 2) {
+                               if (CNXN_TRX_DEBUG > 4)
+                                       rte_ct_cnxn_print_pkt(pkt,
+                                                       IP_VERSION_4);
+                       }
+                       /* need to create compacted table of pointers to pass
+                        * to bulk lookup
+                        */
+
+                       compacting_map[packets_for_lookup] = pos;
+                       key_orig_dir[packets_for_lookup] =
+                               rte_ct_create_cnxn_hashkey(&src_addr, &dst_addr,
+                                               src_port, dst_port,
+                                               proto,
+                                               &ct->hash_keys
+                                               [packets_for_lookup][0],
+                                               IP_VERSION_4);
+                       packets_for_lookup++;
+               }
+               break;
+       case IPv6_HEADER_SIZE:
+               for (; pkts_to_process;) {
+                       uint8_t pos = (uint8_t) __builtin_ctzll(
+                                       pkts_to_process);
+                       /* bitmask representing only this packet */
+                       uint64_t pkt_mask = 1LLU << pos;
+                       /* remove this packet from remaining list */
+                       pkts_to_process &= ~pkt_mask;
+
+                       struct rte_mbuf *pkt = pkts[pos];
+
+
+                       void *ip_hdr = RTE_MBUF_METADATA_UINT32_PTR(pkt,
+                                       IP_START);
+
+                       /* TCP and UDP ports at same offset, just use TCP for
+                        * offset calculation
+                        */
+                       struct tcp_hdr *thdr = (struct tcp_hdr *)
+                               RTE_MBUF_METADATA_UINT32_PTR(pkt,
+                                               (IP_START + ip_hdr_size_bytes));
+                       uint16_t src_port = rte_bswap16(thdr->src_port);
+                       uint16_t dst_port = rte_bswap16(thdr->dst_port);
+
+                       struct ipv6_hdr *ihdr = (struct ipv6_hdr *)ip_hdr;
+                       uint8_t proto = ihdr->proto;
+
+                       if (!(proto == TCP_PROTOCOL || proto == UDP_PROTOCOL)) {
+                               /* only tracking TCP and UDP at this time */
+                               continue;
+                       }
+
+                       if (CNXN_TRX_DEBUG > 2) {
+                               if (CNXN_TRX_DEBUG > 4)
+                                       rte_ct_cnxn_print_pkt(pkt,
+                                                       IP_VERSION_6);
+                       }
+
+                       /* need to create compacted table of pointers to pass
+                        * to bulk lookup
+                        */
+
+                       compacting_map[packets_for_lookup] = pos;
+                       key_orig_dir[packets_for_lookup] =
+                               rte_ct_create_cnxn_hashkey(
+                                               (uint32_t *) ihdr->src_addr,
+                                               (uint32_t *) ihdr->dst_addr,
+                                               src_port, dst_port,
+                                               proto,
+                                               &ct->hash_keys
+                                               [packets_for_lookup][0],
+                                               IP_VERSION_6);
+                       packets_for_lookup++;
+               }
+               break;
+       default:
+               break;
+       }
+       if (unlikely(packets_for_lookup == 0))
+               return; /* no suitable packet for lookup */
+
+       /* Clear all the data to make sure no stack garbage is in it */
+       memset(&new_cnxn_data, 0, sizeof(struct rte_ct_cnxn_data));
+
+       /* lookup all tcp & udp packets in the connection table */
+
+       int lookup_result = rte_hash_lookup_bulk(ct->rhash,
+                       (const void **)&ct->hash_key_ptrs,
+                       packets_for_lookup, &positions[0]);
+
+       if (unlikely(lookup_result < 0)) {
+               /* TODO: change a log */
+               printf("Unexpected hash table problem, discarding all packets");
+               *pkts_mask = 0;
+               return; /* unknown error, just discard all packets */
+       }
+       for (i = 0; i < packets_for_lookup; i++) {
+               /* index into hash table entries */
+               int hash_table_entry = positions[i];
+               /* index into packet table of this packet */
+               uint8_t pkt_index = compacting_map[i];
+               /* bitmask representing only this packet */
+               uint64_t pkt_mask = 1LLU << pkt_index;
+               uint8_t key_is_client_order = key_orig_dir[i];
+               uint32_t *key = ct->hash_key_ptrs[pkt_index];
+               uint8_t protocol = *(key + 9);
+               struct rte_mbuf *packet = pkts[pkt_index];
+               int no_new_cnxn = (pkt_mask & no_new_cnxn_mask) != 0;
+
+               /* rte_ct_print_hashkey(key); */
+
+               if (protocol == TCP_PROTOCOL) {
+                       enum rte_ct_packet_action tcp_pkt_action;
+
+                       tcp_pkt_action = rte_ct_handle_tcp_lookup(ct, packet,
+                                       pkt_index, key_is_client_order,
+                                       key, hash_table_entry, no_new_cnxn,
+                                       ip_hdr_size_bytes);
+
+                       switch (tcp_pkt_action) {
+
+                       case RTE_CT_SEND_CLIENT_SYNACK:
+                       case RTE_CT_SEND_SERVER_ACK:
+                               /* altered packet or copy must be returned
+                                * to originator
+                                */
+                               *reply_pkt_mask |= pkt_mask;
+                               /* FALL-THROUGH */
+
+                       case RTE_CT_SEND_SERVER_SYN:
+                       case RTE_CT_FORWARD_PACKET:
+                               break;
+
+                       case RTE_CT_HIJACK:
+                               *hijack_mask |= pkt_mask;
+                               break;
+
+                       default:
+                               /* bad packet, clear mask to drop */
+                               *pkts_mask ^= pkt_mask;
+                               ct->counters->pkts_drop++;
+                               break;
+               }
+                       /* rte_ct_cnxn_print_pkt(pkts[pkt_index]); */
+
+               } else {        /* UDP entry */
+
+                       if (hash_table_entry >= 0) {
+                               /*
+                                * connection found for this packet. Check that
+                                * this is a valid packet for connection
+                                */
+
+                               struct rte_ct_cnxn_data *entry =
+                               &ct->hash_table_entries[hash_table_entry];
+
+                               if (rte_ct_udp_packet
+                                               (ct, entry, pkts[pkt_index],
+                                                key_is_client_order)) {
+                                       entry->counters.packets_forwarded++;
+                                       ct->counters->pkts_forwarded++;
+                               }
+                       } else {
+                               /*
+                                * connection not found in bulk hash lookup,
+                                * but might have been added in this batch
+                                */
+
+                               struct rte_ct_cnxn_data *recent_entry =
+                                       rte_ct_search_new_connections(ct, key);
+
+                               if (recent_entry != NULL) {
+                                       if (rte_ct_udp_packet(ct, recent_entry,
+                                                       pkts[pkt_index],
+                                                       key_is_client_order)) {
+                                               recent_entry->counters.
+                                                       packets_forwarded++;
+                                               ct->counters->pkts_forwarded++;
+                                       }
+                               } else {
+                                       /* no existing connection, try to add
+                                        * new one
+                                        */
+
+                                       if (no_new_cnxn) {
+                                               /* new cnxn not allowed, clear
+                                                * mask to drop
+                                                */
+                                               *pkts_mask ^= pkt_mask;
+                                               ct->counters->pkts_drop++;
+                                               ct->counters->
+                                               pkts_drop_invalid_conn++;
+                                               continue;
+                                       }
+
+                                       if (rte_ct_udp_new_connection(ct,
+                                       &new_cnxn_data, pkts[pkt_index])) {
+                                               /* This packet creates a
+                                                * connection
+                                                */
+                                               int32_t position =
+                                                       rte_hash_add_key(ct->
+                                                               rhash, key);
+
+                                       if (position < 0)
+                                               continue;
+
+                                               struct rte_ct_cnxn_data
+                                                       *new_hash_entry = &ct->
+                                               hash_table_entries[position];
+
+                                               /*
+                                                *update fields in new_cnxn_data
+                                                * not set by "new_connection"
+                                                */
+
+                                               memcpy(new_cnxn_data.key, key,
+                                               sizeof(new_cnxn_data.key));
+
+                                               new_cnxn_data.
+                                                       key_is_client_order
+                                                       = key_is_client_order;
+                                               new_cnxn_data.protocol =
+                                                       UDP_PROTOCOL;
+                                               rte_cnxn_ip_type(
+                                                       &new_cnxn_data.type,
+                                                       packet);
+                                               rte_memcpy(new_hash_entry,
+                                                       &new_cnxn_data,
+                                                       sizeof(struct
+                                                       rte_ct_cnxn_data));
+
+                                               new_hash_entry->counters.
+                                                       packets_forwarded = 1;
+                                               ct->counters->pkts_forwarded++;
+                                               new_hash_entry->counters.
+                                                       packets_dropped = 0;
+                                               ct->counters->pkts_drop = 0;
+                                               ct->counters->
+                                               current_active_sessions++;
+                                               ct->counters->
+                                                       sessions_activated++;
+
+                                               new_hash_entry->
+                                                       state_used_for_timer
+                                                       = RTE_CT_UDP_NONE;
+                                               rte_ct_set_cnxn_timer_for_udp(
+                                                       ct,
+                                                       new_hash_entry,
+                                                       RTE_CT_UDP_UNREPLIED);
+
+                                               rte_ct_remember_new_connection(
+                                                               ct,
+                                                               new_hash_entry);
+                                       }
+                               }
+
+                       }
+
+               }               /* UDP */
+       }                       /* packets_for_lookup */
+
+       if (CNXN_TRX_DEBUG > 1) {
+               printf("Exit cnxn tracker synproxy batch lookup with");
+               printf(" packet mask %p\n", (void *)*pkts_mask);
+       }
+}
diff --git a/common/VIL/conntrack/rte_cnxn_tracking.h b/common/VIL/conntrack/rte_cnxn_tracking.h
new file mode 100644 (file)
index 0000000..1efb60e
--- /dev/null
@@ -0,0 +1,413 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef _CNXN_TRACKING_H
+#define _CNXN_TRACKING_H
+
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <stdbool.h>
+
+
+#include <rte_hash.h>
+#include <rte_ether.h>
+
+#include "rte_ct_tcp.h"
+
+
+/**
+ *  @file
+ *  Connection Tracker
+ *
+ *  A Connection Tracker tracks the status of TCP connections. By remembering
+ *  keys pieces of data, such as connection state, sequence numbers seen, and
+ *  transmission window size, it can determine if a give packet is valid, or
+ *  invalid and should be discarded.
+ *
+ *  The current interface is designed for use with ip_pipeline code.
+ */
+
+/*
+ * Opaque type definition for an instance of the connection tracker. It is
+ * possible to have multiple instances of connection tracking running, on one
+ * or more cores. All traffic for a TCP connection must be run through the same
+ * rte_ct_cnxn_tracker.
+ */
+
+/*
+ * The rte_ct_cnxn_tracker is an instance of a connection tracker.
+ */
+struct rte_ct_cnxn_tracker  __rte_cache_aligned;
+
+extern int rte_CT_hi_counter_block_in_use;
+
+struct rte_CT_counter_block {
+ /* as long as a counter doesn't cross cache line, writes are atomic */
+       uint64_t current_active_sessions;
+       uint64_t sessions_activated;    /* a SYN packet seen, or UDP */
+       /* a SYN packet re-opening a connection */
+       uint64_t sessions_reactivated;
+       /* SYN, SYN/ACK, ACK established a connection */
+       uint64_t sessions_established;
+       uint64_t sessions_closed;
+       uint64_t sessions_timedout;
+       uint64_t pkts_forwarded;
+       uint64_t pkts_drop;
+       uint64_t pkts_drop_invalid_conn;
+       uint64_t pkts_drop_invalid_state;
+       uint64_t pkts_drop_invalid_rst;
+       uint64_t pkts_drop_outof_window;
+} __rte_cache_aligned;
+
+struct rte_synproxy_helper {
+       uint64_t reply_pkt_mask;
+       uint64_t hijack_mask;
+       struct rte_mbuf **buffered_pkts_to_forward;
+       uint8_t num_buffered_pkts_to_forward;
+};
+
+struct rte_CT_helper {
+       uint64_t no_new_cnxn_mask;
+       uint64_t reply_pkt_mask;
+       uint64_t hijack_mask;
+       struct rte_mbuf **buffered_pkts_to_forward;
+       uint8_t num_buffered_pkts_to_forward;
+};
+
+#define MAX_CT_INSTANCES 24 /* max number fw threads, actual usually less*/
+
+extern struct rte_CT_counter_block rte_CT_counter_table[MAX_CT_INSTANCES]
+__rte_cache_aligned;
+
+/**
+ * Run the connection tracking for 1 to 64 packets.
+ *
+ * @param ct
+ *   Instance of cnxn tracker to use.
+ * @param pkts
+ *   Table of pointers to mbufs containing packets for connection tracking.
+ *   Any packets which are not TCP/IP will be ignnored. A maximum of 64
+ *   packets may be processed in a call.
+ * @param pkts_mask
+ *   Bit map representing which table elements of "pkts" are valid mbuf
+ *   pointers, where the least-significant bit of the map represents table
+ *   element 0. There must be at least as many elements in the table as the
+ *   highest order bit in the map. Valid table entries with a corresponding
+ *   0 in the bitmap will be ignored.
+ * @param ct_helper
+ *   Pointer to rte_CT_helper structure which hold the connection tracker
+ *   tracking information.
+ *
+ * @return
+ *   Returns an updated bitmap that reflects which packets are valid and should
+ *   be forwarded.
+ *   Any bits representing invalid TCP packets are cleared.
+ *   Any packets which are not TCP/IP are considered valid for this purpose.
+ */
+
+uint64_t
+rte_ct_cnxn_tracker_batch_lookup(
+       struct rte_ct_cnxn_tracker *ct,
+       struct rte_mbuf **pkts,
+       uint64_t pkts_mask,
+       struct rte_CT_helper *ct_helper);
+
+void
+rte_ct_cnxn_tracker_batch_lookup_type(
+       struct rte_ct_cnxn_tracker *ct,
+       struct rte_mbuf **pkts,
+       uint64_t *pkts_mask,
+       struct rte_CT_helper *ct_helper,
+       uint8_t ip_hdr_size_bytes);
+
+
+/**
+ * Run the connection tracking for 1 to 64 packets.
+ *
+ * @param ct
+ *   Instance of cnxn tracker to use.
+ * @param pkts
+ *   Table of pointers to mbufs containing packets for connection tracking.
+ *   Any packets which are not TCP/IP will be ignnored. A maximum of 64
+ *   packets may be processed in a call.
+ * @param pkts_mask
+ *   Bit map representing which table elements of "pkts" are valid mbuf
+ *   pointers, where the least-significant bit of the map represents table
+ *   element 0. There must be at least as many elements in the table as the
+ *   highest order bit in the map. Valid table entries with a corresponding
+ *   0 in the bitmap will be ignored.
+ * @param no_new_cnxn_mask
+ *   Bit map representing which table elements of "pkts" are should be
+ *   considered valid packets only if there is already an existing connection
+ *   for this packet (i.e. same ip addresses, tcp/udp ports, and protocol).
+ *   This mask must be a subset of "pkts_mask" (including all or none), and
+ *   follows the same format. A 1 means must be existing connection, a 0 means
+ *   a new connection setup (e.g. TCP SYN packet) is allowed, or this entry
+ *   corresponds to a 0 in pkts_mask.
+ *
+ * @return
+ *   Returns an updated bitmap that reflects which packets are valid and should
+ *   be forwarded.
+ *   Any bits representing invalid TCP packets are cleared.
+ *   Any packets which are not TCP/IP are considered valid for this purpose.
+ */
+
+uint64_t
+rte_ct_cnxn_tracker_batch_lookup_with_new_cnxn_control(
+       struct rte_ct_cnxn_tracker *ct,
+       struct rte_mbuf **pkts,
+       uint64_t pkts_mask,
+       uint64_t no_new_cnxn_mask);
+
+
+/**
+* Run the connection tracking for 1 to 64 packets, with support for
+* synproxy.
+*
+* @param ct
+*   Instance of cnxn tracker to use.
+* @param pkts
+*   Table of pointers to mbufs containing packets for connection tracking.
+*   Any packets which are not TCP/IP will be ignnored. A maximum of 64
+*   packets may be processed in a call.
+* @param pkts_mask
+*   Bit map representing which table elements of "pkts" are valid mbuf pointers,
+*   where the least-significant bit of the map represents table element 0. There
+*   must be at least as many elements in the table as the highest order bit in
+*   the map. Valid table entries with a corresponding 0 in the bitmap will be
+*   ignored.
+* @param reply_pkt_mask
+*   Bit map representing which table elements of "pkts" have been altered to
+*   reply messages for synproxy. These packets, or copies of them must be sent
+*   back to the originator. IP and TCP headers have been altered, ethernet
+*   header has not
+* @return
+*   Returns an updated bitmap that reflects which packets are valid and should
+*   be forwarded.Any bits representing invalid TCP packets are cleared.
+*   Any packets which are not TCP/IP are considered valid for this purpose.
+*/
+
+
+uint64_t
+rte_ct_cnxn_tracker_batch_lookup_with_synproxy(
+       struct rte_ct_cnxn_tracker *ct,
+       struct rte_mbuf **pkts,
+       uint64_t pkts_mask,
+       struct rte_synproxy_helper *sp_helper);
+
+
+
+
+
+/**
+ * Synproxy might need to buffer client-side packets while the
+ * server-side of the proxy is still being set up. The packets
+ * are released when the server-side connection is complete.
+ * This routine is used to retrieve those packets. Packets are
+ * also released in a similar manner if there is a timeout
+ * during a synproxy setup. This routine should be called before
+ * immediately before any timeout handling, to get the list of
+ * packets (if any) to forward, and again immediately after timeout
+ * handling  to get the list of  packets (if any) to delete.
+ * Calling this routine removes the packets from synproxy.
+ *
+ * @param new_cnxn_tracker
+ *   The connection tracker from which to retrieve the packets
+ *
+ * @return
+ *   a linked list of packets to process, in order. The list is
+ *   connected via a pointer stored in the mbuf in the offset
+ *   given in the "pointer_offset" parameter to the routine:
+ *   "rte_ct_initialize_cnxn_tracker_with_synproxy".
+ *   If not packets currently available, returns NULL.
+ */
+
+struct rte_mbuf *
+rte_ct_get_buffered_synproxy_packets(struct rte_ct_cnxn_tracker *ct);
+
+
+/**
+ * Initialize a connection tracker instance before use.
+ *
+ * @param new_cnxn_tracker
+ *   The connection tracker to initialize, allocated by the user.
+ * @param max_connection_count
+ *   Maximum number of simultaneous connections supported.
+ * @param name
+ *  A name to give to this connection tracker, for debug purposes
+ *
+ * @return
+ *   - 0 if successful
+ *   - negative if unsuccesful
+ */
+
+int
+rte_ct_initialize_cnxn_tracker_with_synproxy(
+       struct rte_ct_cnxn_tracker *new_cnxn_tracker,
+       uint32_t max_connection_count,
+       char *name,
+       uint16_t pointer_offset);
+
+/**
+ * Initialize a connection tracker instance before use with synproxy support.
+ *
+ * @param new_cnxn_tracker
+ *   The connection tracker to initialize, allocated by the user.
+ * @param max_connection_count
+ *   Maximum number of simultaneous connections supported.
+ * @param name
+ *  A name to give to this connection tracker, for debug purposes
+ * @param pointer_offset
+ *  An offset into the mbuf where the connection tracker can store two pointers.
+ *
+ * @return
+ *   - 0 if successful
+ *   - negative if unsuccesful
+ */
+
+int
+rte_ct_initialize_cnxn_tracker(
+       struct rte_ct_cnxn_tracker *new_cnxn_tracker,
+       uint32_t max_connection_count,
+       char *name);
+
+
+/**
+ * Free resources allocated by earlier call to rte_ct_initialize_cnxn_tracker()
+ *
+ * @param old_cnxn_tracker
+ *   The connection tracker previously initialized.
+ *
+ * @return
+ *   - 0 if successful
+ *   - < 0 if unsuccesful
+ */
+
+int
+rte_ct_free_cnxn_tracker_resources(
+               struct rte_ct_cnxn_tracker *old_cnxn_tracker);
+
+
+/**
+ * Get size of opaque type rte_ct_cnxn_tracker in order to allocate an instance.
+ *
+ * @return
+ *   Size in bytes of rte_ct_cnxn_tracker type
+ */
+
+int
+rte_ct_get_cnxn_tracker_size(void);
+
+/**
+ * Get address of counters kept by this instance.
+ *
+ * @param ct
+ *   Instance of cnxn tracker.
+ *
+ */
+
+struct rte_CT_counter_block*
+rte_ct_get_counter_address(struct rte_ct_cnxn_tracker *ct);
+
+
+/**
+ * Process a configuration option supported in the config file.
+ * If a valid name/value pair, update the cnxn tracker.
+ *
+ * @param ct
+ *   Instance of cnxn tracker.
+ *
+ * @param name
+ *   Name of configuration option.
+ *
+ * @param value
+ *   Value of configuration option.
+ *
+ * @return
+ *   - 0 if successful
+ *   - < 0 if unsuccesful
+ */
+
+int
+rte_ct_set_configuration_options(
+       struct rte_ct_cnxn_tracker *ct,
+       char *name,
+       char *value);
+
+/**
+ * Check for expired connection tracking timers, and delete any expired
+ * connections. This routine must be called in the loop that processes packets,
+ * to ensure that timeouts are handled synchronously with packet processing.
+ * More frequent calls means more accurate timing but more overhead.
+ *
+ * @param ct
+ *   Instance of cnxn tracker to check timers.
+ *
+ */
+
+void
+rte_ct_handle_expired_timers(struct rte_ct_cnxn_tracker *ct);
+
+
+int
+rte_ct_get_IP_hdr_size(struct rte_mbuf *pkt);
+
+/**
+* Enable synproxy for this connection tracker.
+*
+* @param ct
+*   Instance of cnxn tracker to enable.
+*
+*/
+
+void
+rte_ct_enable_synproxy(struct rte_ct_cnxn_tracker *ct);
+
+/**
+* Disable synproxy for this connection tracker.
+*
+* @param ct
+*   Instance of cnxn tracker to disable.
+*
+*/
+
+void
+rte_ct_disable_synproxy(struct rte_ct_cnxn_tracker *ct);
+int
+rte_ct_initialize_default_timeouts(
+               struct rte_ct_cnxn_tracker *new_cnxn_tracker);
+
+uint8_t
+rte_ct_create_cnxn_hashkey(
+       uint32_t *src_addr,
+       uint32_t *dst_addr,
+       uint16_t src_port,
+       uint16_t dst_port,
+       uint8_t proto,
+       uint32_t *key,
+       uint8_t type);
+
+/* To get timer core id from CGNAPT timer thread*/
+#ifdef CT_CGNAT
+extern uint32_t get_timer_core_id(void);
+uint64_t cgnapt_ct_process(
+       struct rte_ct_cnxn_tracker *ct,
+       struct rte_mbuf **pkts,
+       uint64_t pkts_mask,
+       struct rte_CT_helper *ct_helper);
+#endif
+#endif
diff --git a/common/VIL/conntrack/rte_ct_synproxy.c b/common/VIL/conntrack/rte_ct_synproxy.c
new file mode 100644 (file)
index 0000000..967596d
--- /dev/null
@@ -0,0 +1,873 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <rte_common.h>
+#include <rte_malloc.h>
+#include <rte_ether.h>
+#include <rte_ip.h>
+#include <rte_udp.h>
+#include <rte_icmp.h>
+#include <rte_byteorder.h>
+#include <rte_cycles.h>
+
+#include "rte_ct_tcp.h"
+
+
+/*
+ * OVERVIEW:
+ * This module will behave as a proxy between an initiator (external client)
+ * and listener (internal server).
+ * (1) Proxy receives SYN from initiator, replies with spoofed SYN-ACK message
+ *     No packet is sent to the lister at this time.
+ * (2) Proxy receives ACK from the initiator, so the connection request is
+ *     considred valid. Proxy sends a spoofed SYN message to the listener.
+ * (3) Proxy receives SYN-ACK message from listener. Proxy replies to listener
+ *     with a spoofed ACK message. The connection is considered established.
+ * (4) Traffic is exchanged between initiator and listener. Sequence and
+ *     ack numbers translated appropriately by proxy.
+ */
+
+/*
+ * DETAILS, when SynProxy on:
+ * (1) receive initial SYN from client
+ *    call CT, all new connections assigned spoofed (random) SEQ number
+ *    packet re-purposed as SYN-ACK back to client with spoofed SEQ
+ *    -> change ethernet, IP, and TCP headers, put on appropriate output ring
+ * (2) receive ACK packet from client
+ *    connection request now considered valid
+ *    packet re-purposed as SYN to server, using SEQ from original SYN
+ *    -> change TCP header, put on output ring originally targetted
+ * (3) receive SYN-ACK packet from server
+ *    connection now ESTABLISHED
+ *    compute SEQ difference between spoofed SEQ and real server SEQ
+ *    packet re-purposed as ACK to server
+ *    -> change ethernet, IP, and TCP headers, put on appropriate output ring
+ * (4) all further packets flow normally, except SEQ and ACK numbers must be
+ *    modified by SEQ diff (SEQ in server->client direction, ACK and SACK in
+ *    client->server direction)
+ *
+ */
+
+#define META_DATA_OFFSET 128
+#define ETHERNET_START (META_DATA_OFFSET + RTE_PKTMBUF_HEADROOM)
+#define ETH_HDR_SIZE 14
+#define IP_START (ETHERNET_START + ETH_HDR_SIZE)
+#define PROTOCOL_START (IP_START + 9)
+#define IP_V4_HEADER_SIZE 20
+#define IP_V6_HEADER_SIZE 40
+#define TCP_START (IP_START + IP_V4_HEADER_SIZE)
+#define TCP_MIN_HDR_SIZE 20
+
+#define RTE_TCP_PROTO_ID 6
+#define RTE_SP_DEFAULT_TTL 64
+
+#define RTE_SYNPROXY_MAX_SPOOFED_PKTS 64
+
+#define RTE_TCP_SYN 0x02
+#define RTE_TCP_ACK 0x10
+#define RTE_TCP_SYN_ACK (RTE_TCP_SYN | RTE_TCP_ACK)
+
+#define RTE_SP_DEFAULT_WINDOW 29200
+#define RTE_CT_DEBUG_SPOOFED_SEQ 0
+#define RTE_DPDK_IS_16_4 0
+
+#define IP_VERSION_4 4
+#define IP_VERSION_6 6
+
+
+/* default TCP options */
+/* TODO: need to set in config file */
+
+struct rte_synproxy_options default_ipv4_synproxy_options = {
+       .options = RTE_SP_OPTIONS_MSS |
+                       RTE_SP_OPTIONS_SACK_PERM |
+                       RTE_SP_OPTIONS_WINDOW_SCALE,
+       .mss = 1460,
+       .window_scale = 7,
+       .initial_window = RTE_SP_DEFAULT_WINDOW
+};
+
+
+struct rte_synproxy_options default_ipv6_synproxy_options = {
+       .options = RTE_SP_OPTIONS_MSS |
+                       RTE_SP_OPTIONS_SACK_PERM |
+                       RTE_SP_OPTIONS_WINDOW_SCALE,
+       .mss = 1440,
+       .window_scale = 7,
+       .initial_window = RTE_SP_DEFAULT_WINDOW
+};
+
+/* IP/TCP header print for debugging */
+static __rte_unused void
+rte_ct_synproxy_print_pkt_info(struct rte_mbuf *pkt)
+{
+       struct ipv4_hdr *ihdr4 = (struct ipv4_hdr *)
+               RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
+       __rte_unused struct tcp_hdr *thdr = (struct tcp_hdr *)
+               RTE_MBUF_METADATA_UINT32_PTR(pkt, TCP_START);
+       uint32_t packet_length = rte_pktmbuf_pkt_len(pkt);
+
+       printf("\npacket length %u, ip length %u\n", packet_length,
+               rte_bswap16(ihdr4->total_length));
+       rte_pktmbuf_dump(stdout, pkt, 80);
+}
+
+static inline void
+rte_sp_incremental_tcp_chksum_update_32(
+       uint32_t num_before,    /* in Intel order, not network order */
+       uint32_t num_after,     /* in Intel order, not network order */
+
+       uint16_t *chksum)       /* network order, e.g. pointer into header */
+{
+       uint32_t sum;
+
+       sum = ~rte_bswap16(*chksum) & 0xffff;
+       num_before = ~num_before;
+       sum += (num_before >> 16) + (num_before & 0xffff);
+       sum += (num_after >> 16) + (num_after & 0xffff);
+       sum = (sum >> 16) + (sum & 0xffff);
+       sum += (sum >> 16);
+       *chksum = rte_bswap16(~sum & 0xffff);
+}
+
+
+
+static inline uint32_t
+rte_sp_get_random_seq_number(void)
+{
+       return rte_get_tsc_cycles(); /* low 32 bits of timestamp*/
+}
+
+
+static int8_t rte_ct_ipversion(void *i_hdr)
+{
+       uint8_t *ihdr = (uint8_t *)i_hdr;
+       int8_t hdr_chk = *ihdr;
+
+       hdr_chk = hdr_chk >> 4;
+       if (hdr_chk == IP_VERSION_4 || hdr_chk == IP_VERSION_6)
+               return hdr_chk;
+       else
+               return -1;
+}
+
+static inline void
+rte_synproxy_adjust_pkt_length(struct rte_mbuf *pkt)
+{
+       uint16_t pkt_length = 0;
+       int ip_hdr_size_bytes = rte_ct_get_IP_hdr_size(pkt);
+       void *iphdr = RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
+
+       if (ip_hdr_size_bytes == IP_V4_HEADER_SIZE) {
+               struct ipv4_hdr *ihdr4 = (struct ipv4_hdr *)iphdr;
+
+               pkt_length = rte_bswap16(ihdr4->total_length) + ETH_HDR_SIZE;
+       } else if (ip_hdr_size_bytes == IP_V6_HEADER_SIZE) {
+               struct ipv6_hdr *ihdr6 = (struct ipv6_hdr *)iphdr;
+
+               pkt_length = rte_bswap16(ihdr6->payload_len) +
+                       IP_V6_HEADER_SIZE + ETH_HDR_SIZE;
+       }
+       uint16_t mbuf_pkt_length = rte_pktmbuf_pkt_len(pkt);
+
+       if (pkt_length == mbuf_pkt_length)
+               return;
+
+       if (pkt_length < mbuf_pkt_length) {
+               rte_pktmbuf_trim(pkt, mbuf_pkt_length - pkt_length);
+               return;
+       }
+
+       /* pkt_length > mbuf_pkt_length */
+       rte_pktmbuf_append(pkt, pkt_length - mbuf_pkt_length);
+}
+
+static void
+rte_synproxy_build_ipv4_header(
+       struct ipv4_hdr *hdr4,
+       uint32_t src_addr,
+       uint32_t dst_addr,
+       uint16_t tcp_length)
+{
+       /* TODO: consider interface re-work, too many rte_bswapxx */
+       /* options are not supported, so header size is fixed */
+       hdr4->version_ihl = 0x45;
+       hdr4->type_of_service = 0;
+       hdr4->total_length = rte_bswap16(tcp_length + IP_V4_HEADER_SIZE);
+       hdr4->packet_id = 0;
+       /* set Don't fragment bit, Intel order */
+       hdr4->fragment_offset = 0x0040;
+       hdr4->time_to_live = RTE_SP_DEFAULT_TTL;
+       hdr4->next_proto_id = RTE_TCP_PROTO_ID;
+       /* checksum calculated later */
+       hdr4->src_addr = rte_bswap32(src_addr);
+       hdr4->dst_addr = rte_bswap32(dst_addr);
+}
+
+
+static void
+rte_synproxy_build_ipv6_header(
+       struct ipv6_hdr *hdr6,
+       uint8_t *src_addr,
+       uint8_t *dst_addr,
+       uint16_t tcp_length)
+{
+       /* TODO: consider interface re-work, too many rte_bswapxx */
+       /* options are not supported, so header size is fixed */
+       uint8_t temp_src[16];
+       uint8_t temp_dst[16];
+
+       hdr6->vtc_flow = 0x60;  /* Intel Order */
+       hdr6->payload_len = rte_bswap16(tcp_length);
+       hdr6->proto = RTE_TCP_PROTO_ID;
+       hdr6->hop_limits = RTE_SP_DEFAULT_TTL;
+       /* checksum calculated later */
+
+       /* must copy to temps to avoid overwriting */
+       rte_mov16(temp_src, src_addr);
+       rte_mov16(temp_dst, dst_addr);
+       rte_mov16(hdr6->src_addr, temp_src);
+       rte_mov16(hdr6->dst_addr, temp_dst);
+}
+
+/* add options specified in t_opts to TCP header in packet. */
+
+static uint16_t
+rte_sp_add_tcp_options(struct tcp_hdr *thdr,
+               const struct rte_synproxy_options *t_opts)
+{
+       uint32_t *options_ptr = (uint32_t *)(thdr + 1);
+       uint32_t *saved_ptr = options_ptr;
+       uint8_t options = t_opts->options;
+       uint32_t option_bytes;  /* options built in groups of 4 bytes */
+
+       if (options & RTE_SP_OPTIONS_MSS) {
+               option_bytes = (RTE_CT_TCPOPT_MSS << 24) |
+                       (RTE_CT_TCPOLEN_MSS << 16) | t_opts->mss;
+               *options_ptr++ = rte_bswap32(option_bytes);
+       }
+
+       if (options & RTE_SP_OPTIONS_TIMESTAMP) {
+               /* if both timestamp and sack permitted options,
+                * pack together
+                */
+               if (options & RTE_SP_OPTIONS_SACK_PERM)
+                       option_bytes = (RTE_CT_TCPOPT_SACK_PERM << 24) |
+                                       (RTE_CT_TCPOLEN_SACK_PERM << 16);
+               else
+                       option_bytes = (RTE_CT_TCPOPT_NOP << 24) |
+                               (RTE_CT_TCPOPT_NOP << 16);
+
+               option_bytes |= (RTE_CT_TCPOPT_TIMESTAMP << 8) |
+                       RTE_CT_TCPOLEN_TIMESTAMP;
+               *options_ptr++ = rte_bswap32(option_bytes);
+               *options_ptr++ = rte_bswap32(t_opts->ts_val);
+               *options_ptr++ = rte_bswap32(t_opts->ts_echo_reply);
+       } else if (options & RTE_SP_OPTIONS_SACK_PERM) {
+               option_bytes = (RTE_CT_TCPOPT_NOP << 24) |
+                       (RTE_CT_TCPOPT_NOP << 16) |
+                       (RTE_CT_TCPOPT_SACK_PERM << 8) |
+                       RTE_CT_TCPOLEN_SACK_PERM;
+               *options_ptr++ = rte_bswap32(option_bytes);
+       }
+
+       if (options & RTE_SP_OPTIONS_WINDOW_SCALE) {
+               option_bytes = (RTE_CT_TCPOPT_NOP << 24) |
+                       (RTE_CT_TCPOPT_WINDOW << 16) |
+                       (RTE_CT_TCPOLEN_WINDOW << 8) |
+                       t_opts->window_scale;
+               *options_ptr++ = rte_bswap32(option_bytes);
+       }
+
+       /* compute the data offset field, which is size of total
+        * TCP header in 32 bit words
+        */
+       /* TODO: diff from options ptr to thdr */
+       uint16_t data_offset_bytes = (uint16_t)RTE_PTR_DIFF(options_ptr,
+                       saved_ptr) + sizeof(struct tcp_hdr);
+       thdr->data_off = (data_offset_bytes >> 2) << 4;
+
+       return data_offset_bytes;
+}
+
+/* Build a TCP header.
+ * Note that the the tcp_hdr must be in the appropriate location
+ * in an mbuf
+ * TODO: consider interface re-work, too many rte_bswapxx
+ */
+static inline uint16_t
+rte_synproxy_build_tcp_header(
+       __rte_unused struct rte_mbuf *old_pkt,
+       struct tcp_hdr *t_hdr,
+       uint16_t src_port,
+       uint16_t dst_port,
+       uint32_t seq,
+       uint32_t ack,
+       uint8_t flags,
+       const struct rte_synproxy_options *t_opts,
+       uint8_t add_options)
+{
+       t_hdr->src_port = rte_bswap16(src_port);
+       t_hdr->dst_port = rte_bswap16(dst_port);
+       t_hdr->sent_seq = rte_bswap32(seq);
+       t_hdr->recv_ack = rte_bswap32(ack);
+
+       t_hdr->tcp_flags = flags;
+       t_hdr->rx_win = t_opts->initial_window;
+       /* checksum calculated later */
+       t_hdr->tcp_urp = 0;
+
+       /* add tcp header options, if applicable */
+
+       uint16_t new_tcp_hdr_size = TCP_MIN_HDR_SIZE;
+
+       if (add_options)
+               new_tcp_hdr_size = rte_sp_add_tcp_options(t_hdr, t_opts);
+       else
+               t_hdr->data_off = (TCP_MIN_HDR_SIZE >> 2) << 4;
+
+       return new_tcp_hdr_size;
+}
+
+static void
+rte_synproxy_compute_checksums(void *i_hdr, struct tcp_hdr *t_hdr)
+{
+       /*
+        * calculate IP and TCP checksums. Note that both checksum
+        * routines requirehecksum fields to be set to zero,
+        * and the the checksum is in the correct
+        * byte order, so no rte_bswap16 is required.
+        */
+
+       /* TODO: look into h/w computation of checksums */
+
+       int8_t hdr_chk = rte_ct_ipversion(i_hdr);
+
+       t_hdr->cksum = 0;
+
+       if (hdr_chk == IP_VERSION_4) {
+               struct ipv4_hdr *i4_hdr = (struct ipv4_hdr *)i_hdr;
+
+               i4_hdr->hdr_checksum = 0;
+               t_hdr->cksum = rte_ipv4_udptcp_cksum(i4_hdr, t_hdr);
+               i4_hdr->hdr_checksum = rte_ipv4_cksum(i4_hdr);
+       } else if (hdr_chk == IP_VERSION_6) {
+               struct ipv6_hdr *i6_hdr = (struct ipv6_hdr *)i_hdr;
+
+               t_hdr->cksum = rte_ipv6_udptcp_cksum(i6_hdr, t_hdr);
+       }
+}
+
+
+
+/*
+ * Building new packet headers:
+ * For IPv4 and IPv6 headers, no options and no fragmentation are supported.
+ * Header size is fixed.
+ * TCP header will (likely) have options, so header size is not fixed.
+ * TCP header will be built first, and size used in IP packet size calculation.
+ */
+void
+rte_sp_cvt_to_spoofed_client_synack(struct rte_ct_cnxn_data *cd,
+               struct rte_mbuf *old_pkt)
+{
+       /* old packet is syn from client. Change to a (spoofed)
+        * SYN-ACK to send back
+        */
+
+       int ip_hdr_size_bytes = rte_ct_get_IP_hdr_size(old_pkt);
+       void *iphdr = RTE_MBUF_METADATA_UINT32_PTR(old_pkt, IP_START);
+       struct tcp_hdr *thdr = (struct tcp_hdr *)
+               RTE_MBUF_METADATA_UINT32_PTR(old_pkt, IP_START +
+                               ip_hdr_size_bytes);
+       uint16_t tcp_header_size;
+
+       /* get a spoofed sequence number and save in the connection data */
+       uint32_t new_seq = rte_sp_get_random_seq_number();
+
+       if (RTE_CT_DEBUG_SPOOFED_SEQ)
+               new_seq = 10; /* something simple to aid debugging */
+
+       cd->ct_protocol.synproxy_data.original_spoofed_seq = new_seq;
+
+       /* build the TCP header, including reversing the port numbers. */
+       tcp_header_size = rte_synproxy_build_tcp_header(old_pkt, thdr,
+                       rte_bswap16(thdr->dst_port),
+                       rte_bswap16(thdr->src_port),
+                       new_seq, rte_bswap32(thdr->sent_seq) + 1,
+                       RTE_TCP_SYN_ACK,
+                       ip_hdr_size_bytes == IP_V4_HEADER_SIZE ?
+                       &default_ipv4_synproxy_options :
+                       &default_ipv6_synproxy_options, 1);
+
+       /* reverse the source and destination addresses in the IP hdr */
+       if (ip_hdr_size_bytes == IP_V4_HEADER_SIZE) {
+               struct ipv4_hdr *ihdr4 = (struct ipv4_hdr *)iphdr;
+
+               rte_synproxy_build_ipv4_header(ihdr4,
+                               rte_bswap32(ihdr4->dst_addr),
+                               rte_bswap32(ihdr4->src_addr), tcp_header_size);
+
+       } else if (ip_hdr_size_bytes == IP_V6_HEADER_SIZE) {
+               struct ipv6_hdr *ihdr6 = (struct ipv6_hdr *)iphdr;
+
+               rte_synproxy_build_ipv6_header(ihdr6,
+                               (uint8_t *)ihdr6->dst_addr,
+                               (uint8_t *)ihdr6->src_addr, tcp_header_size);
+       }
+       rte_synproxy_adjust_pkt_length(old_pkt);
+       /* compute checksums */
+       rte_synproxy_compute_checksums(iphdr, thdr);
+
+}
+
+
+void
+rte_sp_cvt_to_spoofed_server_syn(struct rte_ct_cnxn_data *cd,
+               struct rte_mbuf *old_pkt)
+{
+       /* old packet is ACK from client. Change to (spoofed)
+        * SYN to send to server
+        */
+
+       int ip_hdr_size_bytes = rte_ct_get_IP_hdr_size(old_pkt);
+       void *iphdr = RTE_MBUF_METADATA_UINT32_PTR(old_pkt, IP_START);
+       struct tcp_hdr *thdr = (struct tcp_hdr *)
+               RTE_MBUF_METADATA_UINT32_PTR(old_pkt, IP_START
+                               + ip_hdr_size_bytes);
+       uint16_t tcp_header_size;
+
+       tcp_header_size = rte_synproxy_build_tcp_header(old_pkt, thdr,
+                       rte_bswap16(thdr->src_port),
+                       rte_bswap16(thdr->dst_port),
+                       rte_bswap32(thdr->sent_seq) - 1, 0,
+                       RTE_TCP_SYN,
+                       &cd->ct_protocol.synproxy_data.cnxn_options, 1);
+
+       if (ip_hdr_size_bytes == IP_V4_HEADER_SIZE) {
+               struct ipv4_hdr *ihdr4 = (struct ipv4_hdr *)iphdr;
+
+               rte_synproxy_build_ipv4_header(ihdr4,
+                               rte_bswap32(ihdr4->src_addr),
+                               rte_bswap32(ihdr4->dst_addr), tcp_header_size);
+       } else if (ip_hdr_size_bytes == IP_V6_HEADER_SIZE) {
+               struct ipv6_hdr *ihdr6 = (struct ipv6_hdr *)iphdr;
+
+               rte_synproxy_build_ipv6_header(ihdr6,
+                               (uint8_t *)ihdr6->src_addr,
+                               (uint8_t *)ihdr6->dst_addr, tcp_header_size);
+       }
+
+       rte_synproxy_adjust_pkt_length(old_pkt);
+       /* compute checksums */
+       rte_synproxy_compute_checksums(iphdr, thdr);
+
+}
+
+void
+rte_sp_cvt_to_spoofed_server_ack(struct rte_ct_cnxn_data *cd,
+               struct rte_mbuf *old_pkt)
+{
+       /* old packet is SYN-ACK from server. Change to spoofed ACK and
+        * send back to server
+        */
+
+       int ip_hdr_size_bytes = rte_ct_get_IP_hdr_size(old_pkt);
+       void *iphdr = RTE_MBUF_METADATA_UINT32_PTR(old_pkt, IP_START);
+       struct tcp_hdr *thdr = (struct tcp_hdr *)
+               RTE_MBUF_METADATA_UINT32_PTR(old_pkt, IP_START +
+                               ip_hdr_size_bytes);
+
+       /* read real seq out of SYN-ACK from server, and save the delta from
+        * the spoofed one
+        */
+       uint32_t real_seq = rte_bswap32(thdr->sent_seq);
+       uint16_t tcp_header_size;
+
+       cd->ct_protocol.synproxy_data.seq_diff =
+               real_seq - cd->ct_protocol.synproxy_data.original_spoofed_seq;
+
+       /* reverse the source and destination addresses */
+       tcp_header_size = rte_synproxy_build_tcp_header(old_pkt, thdr,
+                       rte_bswap16(thdr->dst_port),
+                       rte_bswap16(thdr->src_port),
+                       rte_bswap32(thdr->recv_ack),
+                       rte_bswap32(thdr->sent_seq) + 1, RTE_TCP_ACK,
+                       &cd->ct_protocol.synproxy_data.cnxn_options, 0);
+
+       /* reverse the source and destination addresses in the IP hdr */
+       if (ip_hdr_size_bytes == IP_V4_HEADER_SIZE) {
+               struct ipv4_hdr *ihdr4 = (struct ipv4_hdr *)iphdr;
+
+               rte_synproxy_build_ipv4_header(ihdr4,
+                               rte_bswap32(ihdr4->dst_addr),
+                               rte_bswap32(ihdr4->src_addr), tcp_header_size);
+
+       } else if (ip_hdr_size_bytes == IP_V6_HEADER_SIZE) {
+               struct ipv6_hdr *ihdr6 = (struct ipv6_hdr *)iphdr;
+
+               rte_synproxy_build_ipv6_header(ihdr6,
+                               (uint8_t *)ihdr6->dst_addr,
+                               (uint8_t *)ihdr6->src_addr, tcp_header_size);
+       }
+       rte_synproxy_adjust_pkt_length(old_pkt);
+       /* compute checksums */
+       rte_synproxy_compute_checksums(iphdr, thdr);
+}
+
+/*
+ * if running synproxy and both halves of the proxied connection has been
+ * established, need adjust the seq or ack value of the packet.
+ * The value is adjusted by the difference between the spoofed server
+ * initial sequence number and the real server sequence number.
+ * In the client -> server direction, the ack must be increased by the
+ * difference before the window check.
+ * In the server -> client direction, the seq must be decreased by the
+ * difference after the window check.
+ */
+
+
+void
+rte_sp_adjust_server_seq_after_window_check(
+       struct rte_ct_cnxn_data *cd,
+       __rte_unused void *i_hdr,
+       struct tcp_hdr *thdr,
+       enum rte_ct_pkt_direction dir)
+{
+       uint32_t num_before, num_after;
+
+       if (!cd->ct_protocol.synproxy_data.cnxn_established)
+               return;
+
+       if (dir == RTE_CT_DIR_ORIGINAL)
+               return; /*wrong direction */
+
+
+       /* update appropriate number (seq or ack) in header */
+       num_before = rte_bswap32(thdr->sent_seq);
+       num_after = num_before - cd->ct_protocol.synproxy_data.seq_diff;
+       thdr->sent_seq = rte_bswap32(num_after);
+
+       rte_sp_incremental_tcp_chksum_update_32(num_before, num_after,
+                       &thdr->cksum);
+}
+
+
+static void
+rte_sp_adjust_client_sack_entries(
+       struct tcp_hdr *thdr,
+       uint32_t diff)
+{
+       uint32_t num_before, num_after;
+       uint32_t *sack_ptr;
+       uint8_t  sack_blk_size;
+       uint16_t dataoff_in_bytes = (thdr->data_off & 0xf0) >> 2;
+       uint16_t length = dataoff_in_bytes - sizeof(struct tcp_hdr);
+
+       if (!length)
+               return;
+
+       uint8_t *options_ptr = (uint8_t *)(thdr + 1);
+
+       while (length > 0) {
+               uint8_t opcode = *options_ptr;
+               uint8_t opsize = options_ptr[1];
+               int i;
+
+               switch (opcode) {
+
+               case RTE_CT_TCPOPT_EOL:
+                       return; /* end of options */
+
+               case RTE_CT_TCPOPT_NOP: /* Ref: RFC 793 section 3.1 */
+                       length--;
+                       options_ptr++;
+                       continue;
+
+               case RTE_CT_TCPOPT_SACK:
+                       /*
+                        * SACK (selective ACK) contains a block of 1 to 4
+                        * entries of 8 bytes each. Each entry is a pair of
+                        * 32 bit numbers. This block follows the usual 2
+                        * bytes for opcode and opsize. Thus, the entire SACK
+                        * option must be 10, 18, 26 or 34 bytes long.
+                        */
+
+                       sack_blk_size = opsize - 2;
+                       /* start of entries */
+                       sack_ptr = (uint32_t *)(options_ptr + 2);
+                       /* count of 32 bit elements */
+                       int num_acks = sack_blk_size >> 2;
+
+                       if (unlikely(sack_blk_size > 32 ||
+                                               ((sack_blk_size & 0x3) != 0))) {
+                               printf("Sack block parsing failure\n");
+                               return;
+                       }
+
+                       for (i = 0; i < num_acks; i++) {
+                               num_before = rte_bswap32(*sack_ptr);
+                               num_after = num_before + diff;
+                               *sack_ptr = rte_bswap32(num_after);
+                               sack_ptr++;
+                               rte_sp_incremental_tcp_chksum_update_32(
+                                               num_before,
+                                               num_after,
+                                               &thdr->cksum);
+                       }
+
+                       return;
+               default:
+                       break;
+               }
+               if ((opsize < 2) || (opsize > length)) {
+                       printf("ERROR!, opsize %i, length %i\n",
+                               opsize, length);
+                       return;
+               }
+
+               options_ptr += opsize;
+               length -= opsize;
+       }
+}
+
+void
+rte_sp_adjust_client_ack_before_window_check(
+       struct rte_ct_cnxn_data *cd,
+        __rte_unused void *i_hdr,
+       struct tcp_hdr *thdr,
+       enum rte_ct_pkt_direction dir)
+{
+       uint32_t num_before, num_after;
+
+       if (!cd->ct_protocol.synproxy_data.cnxn_established)
+               return;
+
+       if (dir != RTE_CT_DIR_ORIGINAL)
+               return; /*wrong direction */
+
+
+       /* first update appropriate number (seq or ack) in header */
+       num_before = rte_bswap32(thdr->recv_ack);
+       num_after = num_before + cd->ct_protocol.synproxy_data.seq_diff;
+       thdr->recv_ack = rte_bswap32(num_after);
+       rte_sp_incremental_tcp_chksum_update_32(num_before,
+                       num_after, &thdr->cksum);
+
+       /* update SACK entries in header if any */
+
+       if (1) { /* TODO: check if sack permitted before calling */
+               rte_sp_adjust_client_sack_entries(thdr,
+                               cd->ct_protocol.synproxy_data.seq_diff);
+               /* note that tcp hdr checksum adjusted in above sack
+                * entries routine call
+                */
+       }
+}
+
+
+
+
+/* parse the tcp header options, if any, and save interesting ones */
+static void
+rte_sp_parse_tcp_options(
+       uint8_t *options_ptr,
+       uint16_t length,
+       struct rte_synproxy_options *t_opts)
+{
+       int opsize;
+
+       t_opts->options = 0;
+
+       while (length > 0) {
+               uint8_t opcode = *options_ptr++;
+
+               if (opcode == RTE_CT_TCPOPT_EOL)
+                       return;
+
+               if (opcode == RTE_CT_TCPOPT_NOP) {
+                       length--;
+                       continue; /* skip adjustments at loop bottom */
+               }
+
+               opsize = *options_ptr++;
+
+               if (unlikely(opsize < 2 || opsize > length)) {
+                       /* TODO: Change printf to log */
+                       printf("parsing error, opsize: %i, length: %i\n",
+                               opsize, length);
+                       return;
+               }
+
+               switch (opcode) {
+
+               case RTE_CT_TCPOPT_MSS:
+                       if (opsize == RTE_CT_TCPOLEN_MSS) {
+                               uint16_t *mss_ptr = (uint16_t *)options_ptr;
+
+                               t_opts->mss = rte_bswap16(*mss_ptr);
+                               t_opts->options |= RTE_SP_OPTIONS_MSS;
+                       }
+                       break;
+
+               case RTE_CT_TCPOPT_WINDOW:
+                       if (opsize == RTE_CT_TCPOLEN_WINDOW) {
+                               t_opts->window_scale = RTE_MIN(*options_ptr,
+                                               RTE_CT_MAX_TCP_WINDOW_SCALE);
+                               t_opts->options |= RTE_SP_OPTIONS_WINDOW_SCALE;
+                       }
+                       break;
+
+               case RTE_CT_TCPOPT_TIMESTAMP:
+                       if (opsize == RTE_CT_TCPOLEN_TIMESTAMP) {
+                               uint32_t *ts_val_ptr = (uint32_t *)options_ptr;
+                               uint32_t *ts_ecr_ptr =
+                                       (uint32_t *)(options_ptr + 4);
+                               t_opts->ts_val = rte_bswap32(*ts_val_ptr);
+                               t_opts->ts_echo_reply =
+                                       rte_bswap32(*ts_ecr_ptr);
+                               t_opts->options |= RTE_SP_OPTIONS_TIMESTAMP;
+                       }
+                       break;
+
+               case RTE_CT_TCPOPT_SACK_PERM:
+                       if (opsize == RTE_CT_TCPOLEN_SACK_PERM)
+                               t_opts->options |= RTE_SP_OPTIONS_SACK_PERM;
+                       break;
+
+               default:
+                       break;
+               }
+
+               options_ptr += opsize - 2;
+               length -= opsize;
+
+       }
+}
+
+/* parse the tcp header options, if any, and save interesting ones in t_opts */
+void
+rte_sp_parse_options(struct rte_mbuf *pkt, struct rte_ct_cnxn_data *cd)
+{
+       /*uint16_t ip_hdr_length = rte_sp_get_ip_header_size(pkt);
+        * skip over IPv4 or IPv6 header
+        */
+       int ip_hdr_length = rte_ct_get_IP_hdr_size(pkt);
+       struct tcp_hdr *thdr = (struct tcp_hdr *)
+               RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START + ip_hdr_length);
+       uint8_t *opt_ptr = RTE_MBUF_METADATA_UINT8_PTR(pkt,
+                       (IP_START + ip_hdr_length + sizeof(struct tcp_hdr)));
+
+       struct rte_synproxy_options *t_opts =
+               &cd->ct_protocol.synproxy_data.cnxn_options;
+       int length_in_bytes =
+               ((thdr->data_off & 0xf0) >> 2) - sizeof(struct tcp_hdr);
+
+       rte_sp_parse_tcp_options(opt_ptr, length_in_bytes, t_opts);
+       t_opts->initial_window = thdr->rx_win;
+}
+
+
+
+
+struct rte_mbuf *
+rte_ct_get_buffered_synproxy_packets(
+       struct rte_ct_cnxn_tracker *ct)
+{
+       struct rte_mbuf *trkr_list = ct->buffered_pkt_list;
+
+       ct->buffered_pkt_list = NULL;
+       return trkr_list;
+}
+
+
+
+void rte_ct_enable_synproxy(struct rte_ct_cnxn_tracker *ct)
+{
+       ct->misc_options.synproxy_enabled = 1;
+       printf("rte_ct_enable_synproxy = %d\n",
+                       ct->misc_options.synproxy_enabled);
+}
+
+void rte_ct_disable_synproxy(struct rte_ct_cnxn_tracker *ct)
+{
+       ct->misc_options.synproxy_enabled = 0;
+       //printf("rte_ct_disable_synproxy = %d\n",
+       //              ct->misc_options.synproxy_enabled);
+}
+
+void
+rte_ct_buffer_packet(
+       struct rte_ct_cnxn_tracker *ct,
+       struct rte_ct_cnxn_data *cd,
+       struct rte_mbuf *pkt)
+{
+       /*
+        * Add packet to list of buffered packets for the connection.
+        * List is built in reverse of order received by adding to front.
+        * List will later be reversed to maintain order of arrival.
+        */
+
+       struct rte_mbuf **next = (struct rte_mbuf **)
+               RTE_MBUF_METADATA_UINT64_PTR(pkt,
+                               ct->pointer_offset);
+       *next = cd->ct_protocol.synproxy_data.buffered_pkt_list;
+       cd->ct_protocol.synproxy_data.buffered_pkt_list = pkt;
+}
+
+void
+rte_ct_release_buffered_packets(
+       struct rte_ct_cnxn_tracker *ct,
+       struct rte_ct_cnxn_data *cd)
+{
+       struct rte_mbuf *cnxn_list =
+               cd->ct_protocol.synproxy_data.buffered_pkt_list;
+
+       if (cnxn_list == NULL)
+               return;
+
+       cd->ct_protocol.synproxy_data.buffered_pkt_list = NULL;
+
+       struct rte_mbuf *trkr_list = ct->buffered_pkt_list;
+
+       if (trkr_list == NULL)
+               return;
+       /*
+        * walk the cnxn_list, and add to front of trkr_list, reversing order
+        * and thus restoring orginal order. Order between different
+        * connections is irrelevant.
+        */
+       while (cnxn_list != NULL) {
+               struct rte_mbuf *old_next;
+
+               struct rte_mbuf **next = (struct rte_mbuf **)
+                       RTE_MBUF_METADATA_UINT64_PTR(cnxn_list,
+                                       ct->pointer_offset);
+
+               old_next = *next;       /* save next cd packet */
+               *next = trkr_list;/* make this cd packet point to ct list */
+               trkr_list = cnxn_list;/* make the cd packet head of ct list */
+               cnxn_list = old_next;   /* advance along cd list */
+       }
+       ct->buffered_pkt_list = trkr_list;
+}
diff --git a/common/VIL/conntrack/rte_ct_tcp.c b/common/VIL/conntrack/rte_ct_tcp.c
new file mode 100644 (file)
index 0000000..073c63e
--- /dev/null
@@ -0,0 +1,1116 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <immintrin.h>
+#include <inttypes.h>
+#include "rte_ct_tcp.h"
+#include "rte_cnxn_tracking.h"
+
+/* uint32_t CT_DEBUG = 1; */ /* Can be used to conditionally turn of debug */
+#define CT_DEBUG 0
+#define STATE_TRACKING 0
+#define RTE_CT_ASSERT 0
+
+/* constants for mbuff manipulation */
+#define META_DATA_OFFSET 128
+#define RTE_PKTMBUF_HEADROOM 128       /* where is this defined ? */
+#define ETHERNET_START (META_DATA_OFFSET + RTE_PKTMBUF_HEADROOM)
+#define ETH_HDR_SIZE 14
+#define IP_START (ETHERNET_START + ETH_HDR_SIZE)
+
+#define IPv4_HEADER_SIZE 20
+#define IPv6_HEADER_SIZE 40
+
+#define IP_VERSION_4 4
+#define IP_VERSION_6 6
+
+#define rte_after(seq2, seq1) rte_before(seq1, seq2)
+static inline uint8_t rte_before(uint32_t seq1, uint32_t seq2)
+{
+       return (int32_t) (seq1 - seq2) < 0;
+}
+
+/* short state names for defining state table */
+
+#define ctNO RTE_CT_TCP_NONE
+#define ctSS RTE_CT_TCP_SYN_SENT
+#define ctSR RTE_CT_TCP_SYN_RECV
+#define ctES RTE_CT_TCP_ESTABLISHED
+#define ctFW RTE_CT_TCP_FIN_WAIT
+#define ctCW RTE_CT_TCP_CLOSE_WAIT
+#define ctLA RTE_CT_TCP_LAST_ACK
+#define ctTW RTE_CT_TCP_TIME_WAIT
+#define ctCL RTE_CT_TCP_CLOSE
+#define ctS2 RTE_CT_TCP_SYN_SENT_2
+#define ctIV RTE_CT_TCP_MAX
+#define ctIG RTE_CT_TCP_IGNORE
+
+static const uint8_t rte_ct_tcp_state_table[2][6][RTE_CT_TCP_MAX] = {
+       {                       /* "client" direction, i.e. first SYN sent */
+        /* ctNO, ctSS, ctSR, ctES, ctFW, ctCW, ctLA, ctTW, ctCL, ctS2 */
+        /* syn */ {ctSS, ctSS, ctIG, ctIG, ctIG, ctIG, ctIG, ctSS, ctSS,
+                               ctS2},
+
+        /* ctNO, ctSS, ctSR, ctES, ctFW, ctCW, ctLA, ctTW, ctCL, ctS2 */
+        /* synack */ {ctIV, ctIV, ctSR, ctIV, ctIV, ctIV, ctIV, ctIV, ctIV,
+                                        ctSR},
+
+        /* ctNO, ctSS, ctSR, ctES, ctFW, ctCW, ctLA, ctTW, ctCL, ctS2 */
+        /* fin */ {ctIV, ctIV, ctFW, ctFW, ctLA, ctLA, ctLA, ctTW, ctCL,
+                               ctIV},
+        /* ctNO, ctSS, ctSR, ctES, ctFW, ctCW, ctLA, ctTW, ctCL, ctS2 */
+        /* ack */ {ctES, ctIV, ctES, ctES, ctCW, ctCW, ctTW, ctTW, ctCL,
+                               ctIV},
+
+        /* ctNO, ctSS, ctSR, ctES, ctFW, ctCW, ctLA, ctTW, ctCL, ctS2 */
+        /* rst */ {ctIV, ctCL, ctCL, ctCL, ctCL, ctCL, ctCL, ctCL, ctCL,
+                               ctCL},
+        /* ill */ {ctIV, ctIV, ctIV, ctIV, ctIV, ctIV, ctIV, ctIV, ctIV, ctIV}
+        },
+
+       {                       /* "server" direction */
+        /* ctNO, ctSS, ctSR, ctES, ctFW, ctCW, ctLA, ctTW, ctCL, ctS2 */
+        /* syn */ {ctIV, ctS2, ctIV, ctIV, ctIV, ctIV, ctIV, ctSS, ctIV,
+                               ctS2},
+
+        /* ctNO, ctSS, ctSR, ctES, ctFW, ctCW, ctLA, ctTW, ctCL, ctS2 */
+        /* synack */ {ctIV, ctSR, ctIG, ctIG, ctIG, ctIG, ctIG, ctIG, ctIG,
+                                        ctSR},
+
+        /* ctNO, ctSS, ctSR, ctES, ctFW, ctCW, ctLA, ctTW, ctCL, ctS2 */
+        /* fin */ {ctIV, ctIV, ctFW, ctFW, ctLA, ctLA, ctLA, ctTW, ctCL,
+                               ctIV},
+
+        /* ctNO, ctSS, ctSR, ctES, ctFW, ctCW, ctLA, ctTW, ctCL, ctS2 */
+        /* ack */ {ctIV, ctIG, ctSR, ctES, ctCW, ctCW, ctTW, ctTW, ctCL,
+                               ctIG},
+
+        /* ctNO, ctSS, ctSR, ctES, ctFW, ctCW, ctLA, ctTW, ctCL, ctS2 */
+        /* rst */ {ctIV, ctCL, ctCL, ctCL, ctCL, ctCL, ctCL, ctCL, ctCL,
+                               ctCL},
+        /* ill */ {ctIV, ctIV, ctIV, ctIV, ctIV, ctIV, ctIV, ctIV, ctIV, ctIV}
+        }
+};
+
+/* What TCP flags are set from RST/SYN/FIN/ACK. */
+enum rte_tcp_flag {
+       RTE_CT_TCP_SYN_FLAG,
+       RTE_CT_TCP_SAK_FLAG,    /* SYN ACK */
+       RTE_CT_TCP_FIN_FLAG,
+       RTE_CT_TCP_ACK_FLAG,
+       RTE_CT_TCP_RST_FLAG,
+       RTE_CT_TCP_ILL_FLAG,
+};
+
+static uint8_t rte_ct_tcp_flags_to_state_table_index[16] = {
+       /* A R S F */
+       RTE_CT_TCP_ILL_FLAG,    /* 0 0 0 0 */
+       RTE_CT_TCP_FIN_FLAG,    /* 0 0 0 1 */
+       RTE_CT_TCP_SYN_FLAG,    /* 0 0 1 0 */
+       RTE_CT_TCP_ILL_FLAG,    /* 0 0 1 1 */
+       RTE_CT_TCP_RST_FLAG,    /* 0 1 0 0 */
+       RTE_CT_TCP_RST_FLAG,    /* 0 1 0 1 */
+       RTE_CT_TCP_RST_FLAG,    /* 0 1 1 0 */
+       RTE_CT_TCP_ILL_FLAG,    /* 0 1 1 1 */
+
+       RTE_CT_TCP_ACK_FLAG,    /* 1 0 0 0 */
+       RTE_CT_TCP_FIN_FLAG,    /* 1 0 0 1 */
+       RTE_CT_TCP_SAK_FLAG,    /* 1 0 1 0 */
+       RTE_CT_TCP_ILL_FLAG,    /* 1 0 1 1 */
+       RTE_CT_TCP_RST_FLAG,    /* 1 1 0 0 */
+       RTE_CT_TCP_ILL_FLAG,    /* 1 1 0 1 */
+       RTE_CT_TCP_RST_FLAG,    /* 1 1 1 0 */
+       RTE_CT_TCP_ILL_FLAG,    /* 1 1 1 1 */
+};
+
+static inline uint8_t
+rte_ct_get_index(uint8_t tcp_flags)
+{
+       uint8_t important_flags;
+
+       tcp_flags &= 0x3f;      /* clear off optional flags */
+       important_flags = ((tcp_flags & 0x10) >> 1) | (tcp_flags & 7);
+       /* should be _pext_u32(tcp_flags, 0x17) */
+
+       if (unlikely((tcp_flags == 0) || (tcp_flags == 0x3f)))
+               /* these known as null and christmas tree respectively */
+               return RTE_CT_TCP_ILL_FLAG;
+
+       return rte_ct_tcp_flags_to_state_table_index[important_flags];
+
+}
+
+static inline int
+rte_ct_either_direction_has_flags(struct rte_ct_cnxn_data *cd, uint8_t flags)
+{
+       return ((cd->ct_protocol.tcp_ct_data.seen[0].flags | cd->
+                ct_protocol.tcp_ct_data.seen[1].flags) & flags) != 0;
+}
+
+static inline uint32_t rte_ct_seq_plus_length(struct rte_mbuf *pkt,
+               uint8_t ip_hdr_size)
+{
+       uint16_t pkt_length = 0;
+       struct tcp_hdr *tcpheader =
+                       (struct tcp_hdr *)RTE_MBUF_METADATA_UINT32_PTR(pkt,
+                                                                (IP_START +
+                                                                       ip_hdr_size));
+       uint32_t tcp_hdr_size = (tcpheader->data_off & 0xf0) >> 2;
+
+       void *ip_hdr = RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
+
+       if (ip_hdr_size == IPv4_HEADER_SIZE) {
+               struct ipv4_hdr *ihdr = (struct ipv4_hdr *)ip_hdr;
+
+               pkt_length = rte_bswap16(ihdr->total_length);
+       }
+       if (ip_hdr_size == IPv6_HEADER_SIZE) {
+               struct ipv6_hdr *ihdr = (struct ipv6_hdr *)ip_hdr;
+
+               pkt_length = rte_bswap16(ihdr->payload_len) + IPv6_HEADER_SIZE;
+       }
+
+       /*
+        * Return sequence number plus the length of TCP segment (payload).
+        * SYN & FIN are each considered one byte, but it is illegal
+        * to have them together in one header (checked elsewhere)
+       */
+
+
+       return rte_bswap32(tcpheader->sent_seq) +
+                       pkt_length - ip_hdr_size - tcp_hdr_size +
+                       ((tcpheader->tcp_flags & (RTE_CT_TCPHDR_SYN | RTE_CT_TCPHDR_FIN)) !=
+                        0 ? 1 : 0);
+
+}
+
+static void
+rte_ct_check_for_scaling_and_sack_perm(
+       struct rte_mbuf *pkt,
+       struct rte_ct_tcp_state *state,
+       uint8_t ip_hdr_size)
+{
+
+       struct tcp_hdr *tcpheader =
+                       (struct tcp_hdr *)RTE_MBUF_METADATA_UINT32_PTR(pkt,
+                                                                (IP_START +
+                                                                       ip_hdr_size));
+       uint32_t dataoff_in_bytes = (tcpheader->data_off & 0xf0) >> 2;
+       uint32_t length = dataoff_in_bytes - sizeof(struct tcp_hdr);
+
+       state->scale = 0;
+       state->flags = 0;
+
+       if (length == 0)
+               /* no header options */
+               return;
+       uint8_t *options_ptr =
+                       RTE_MBUF_METADATA_UINT8_PTR(pkt,
+                                       (IP_START + ip_hdr_size +
+                                        sizeof(struct tcp_hdr)));
+
+       while (length > 0) {
+               uint8_t option = *options_ptr;
+               uint8_t opsize = options_ptr[1];
+               /* opsize reset for NOPs below */
+
+               switch (option) {
+
+               case RTE_CT_TCPOPT_EOL:
+                       /* end of options */
+                       return;
+
+               case RTE_CT_TCPOPT_NOP:
+                       options_ptr++;
+                       length--;
+                       continue;
+
+               case RTE_CT_TCPOPT_SACK_PERM:
+                       if (opsize == RTE_CT_TCPOLEN_SACK_PERM)
+                               state->flags |= RTE_CT_TCP_FLAG_SACK_PERM;
+                       break;
+
+               case RTE_CT_TCPOPT_WINDOW:
+                       if (opsize == RTE_CT_TCPOLEN_WINDOW) {
+                               state->scale =
+                                               RTE_MIN(options_ptr[2],
+                                                       RTE_CT_MAX_TCP_WINDOW_SCALE);
+                               state->flags |= RTE_CT_TCP_FLAG_WINDOW_SCALE;
+                       }
+                       break;
+
+               default:
+                       break;
+
+               }
+
+               if ((opsize < 2) || (opsize > length)) {
+                       /* something wrong */
+                       printf("scaling_and_sack_perm:something wrong\n");
+                       return;
+               }
+               options_ptr += opsize;
+               length -= opsize;
+
+       }
+}
+
+static void
+rte_ct_tcpdisplay_hdr(struct tcp_hdr *tcpheader)
+{
+       printf("Tcp header: src_port=%d", rte_bswap16(tcpheader->src_port));
+       printf(", dst_port=%d", rte_bswap16(tcpheader->dst_port));
+       printf(", sent_seq=%u", rte_bswap32(tcpheader->sent_seq));
+       printf(", recv_ack=%u", rte_bswap32(tcpheader->recv_ack));
+       printf(",data_off=%d", tcpheader->data_off / 16);
+       printf(",tcp_flags=%02x", tcpheader->tcp_flags);
+       printf(", rx_win=%d\n", rte_bswap16(tcpheader->rx_win));
+
+}
+
+static inline void
+rte_ct_clear_cnxn_data(__rte_unused struct rte_ct_cnxn_tracker *ct,
+               struct rte_ct_cnxn_data *cd,
+               __rte_unused struct rte_mbuf *pkt)
+{
+       /* clear all tcp connection data, then set up individual fields */
+
+       memset(&cd->ct_protocol.tcp_ct_data, 0,
+                                sizeof(cd->ct_protocol.tcp_ct_data));
+       cd->ct_protocol.tcp_ct_data.last_index = RTE_CT_TCP_ILL_FLAG;
+
+}
+
+enum rte_ct_packet_action
+rte_ct_tcp_new_connection(
+       struct rte_ct_cnxn_tracker *ct,
+       struct rte_ct_cnxn_data *cd,
+       struct rte_mbuf *pkt,
+       int     use_synproxy,
+       uint8_t ip_hdr_size)
+{
+       struct tcp_hdr *tcpheader =
+               (struct tcp_hdr *)RTE_MBUF_METADATA_UINT32_PTR(pkt,
+                               (IP_START + ip_hdr_size));
+
+       enum rte_ct_tcp_states new_state;
+       uint8_t index;
+       struct rte_ct_tcp_state *sender =
+               &cd->ct_protocol.tcp_ct_data.seen[RTE_CT_DIR_ORIGINAL];
+       struct rte_ct_tcp_state *receiver =
+               &cd->ct_protocol.tcp_ct_data.seen[RTE_CT_DIR_REPLY];
+       uint16_t win;
+
+        if (CT_DEBUG)
+               rte_ct_tcpdisplay_hdr(tcpheader);
+
+       index = rte_ct_get_index(tcpheader->tcp_flags);
+       new_state = rte_ct_tcp_state_table[0][index][RTE_CT_TCP_NONE];
+
+       if (unlikely(new_state >= RTE_CT_TCP_MAX)) {
+               if (CT_DEBUG)
+                       printf("invalid new state with flags %02x\n",
+                                       tcpheader->tcp_flags);
+               return RTE_CT_DROP_PACKET;
+       }
+       /*
+        * A normal connection starts with a SYN packet. However, it is possible
+        * that an onginging connection has been routed here somehow. Support
+        * for these connections is optional.
+        */
+
+       if (unlikely((new_state != RTE_CT_TCP_SYN_SENT
+                                       && ct->misc_options.tcp_loose == 0))) {
+               /* Not a standard connection start and not supporting
+                * onging connections. */
+               return RTE_CT_DROP_PACKET;
+       }
+
+       if (CT_DEBUG)
+               printf(" new connection with state %s\n",
+                                        rte_ct_tcp_names[new_state]);
+
+       /* clear all tcp connection data, then set up individual fields */
+       rte_ct_clear_cnxn_data(ct, cd, pkt);
+       cd->ct_protocol.tcp_ct_data.state = new_state;
+
+       sender->end = sender->maxend = rte_ct_seq_plus_length(pkt, ip_hdr_size);
+       win = rte_bswap16(tcpheader->rx_win);
+       sender->maxwin = RTE_MAX(win, (uint32_t)1);
+
+       if (likely(new_state == RTE_CT_TCP_SYN_SENT)) {
+               /* check for window scaling and selective ACK */
+               rte_ct_check_for_scaling_and_sack_perm(pkt, sender,
+                               ip_hdr_size);
+
+               cd->ct_protocol.synproxy_data.synproxied = use_synproxy;
+
+               if (use_synproxy) {
+                       /*
+                        * new connection from client using synproxy. The proxy
+                        * must send back a SYN-ACK
+                        */
+
+
+                       if (CT_DEBUG > 2)
+                               printf("synproxy sending SYN-ACK to client\n");
+
+                       return RTE_CT_SEND_CLIENT_SYNACK;
+               }
+       } else {
+               /*
+                * An ongoing connection. Make a very liberal connection since
+                * all the original set up data is lost. Assume SACK and
+                * liberal window checking to handle unknown window scaling.
+                */
+
+               sender->maxend += sender->maxwin;
+               sender->flags = receiver->flags =
+                               (RTE_CT_TCP_FLAG_SACK_PERM | RTE_CT_TCP_FLAG_BE_LIBERAL);
+       }
+
+       if (CT_DEBUG > 0) {
+               printf("tcp_new: sender end=%u maxend=%u maxwin=%u scale=%i",
+                               sender->end, sender->maxend, sender->maxwin,
+                               sender->scale);
+               printf(" receiver end=%u maxend=%u maxwin=%u scale=%i\n",
+                               receiver->end, receiver->maxend,
+                               receiver->maxwin,
+                               receiver->scale);
+       }
+
+       return RTE_CT_OPEN_CONNECTION;
+}
+
+static uint32_t
+rte_ct_tcp_sack(struct rte_mbuf *pkt, uint8_t ip_hdr_size)
+{
+       struct tcp_hdr *tcpheader =
+               (struct tcp_hdr *)RTE_MBUF_METADATA_UINT32_PTR(pkt,
+                               (IP_START +
+                                ip_hdr_size));
+       uint16_t dataoff_in_bytes = (tcpheader->data_off & 0xf0) >> 2;
+       uint16_t length = dataoff_in_bytes - sizeof(struct tcp_hdr);
+       uint32_t sack = rte_bswap32(tcpheader->recv_ack);
+
+       if (unlikely(!length))
+               return sack;
+
+       uint8_t *options_ptr = RTE_MBUF_METADATA_UINT8_PTR(pkt,
+                       (IP_START + ip_hdr_size + sizeof(struct tcp_hdr)));
+
+       while (length > 0) {
+               uint8_t opcode = *options_ptr;
+               uint8_t opsize = options_ptr[1];
+               int i;
+               uint32_t *sack_ptr;
+
+               switch (opcode) {
+               case RTE_CT_TCPOPT_TIMESTAMP:
+                       /* common "solo" option, check first */
+                       break;
+
+               case RTE_CT_TCPOPT_EOL:
+                       return sack;    /* end of options */
+
+               case RTE_CT_TCPOPT_NOP: /* Ref: RFC 793 section 3.1 */
+                       length--;
+                       options_ptr++;
+                       continue;
+
+               case RTE_CT_TCPOPT_SACK:
+                       /*
+                        * SACK (selective ACK) contains a block of
+                        * 1 to 4 entries of 8 bytes each.
+                        *  Each entry is a pair of 32 bit numbers.
+                        * This block follows the usual 2
+                        * bytes for opcode and opsize. Thus,
+                        * the entire SACK option must be 10, 18,
+                        * 26 or 34 bytes long.
+                        */
+                       if ((opsize >= (RTE_CT_TCPOLEN_PER_SACK_ENTRY + 2)) &&
+                                       ((opsize - 2) %
+                                        RTE_CT_TCPOLEN_PER_SACK_ENTRY) == 0) {
+                               /* skip over opcode and size, and point to
+                                * 2nd 32 bits in entry */
+                               options_ptr += 6;
+                               for (i = 0; i < (opsize - 2); i +=
+                                               RTE_CT_TCPOLEN_PER_SACK_ENTRY) {
+                                       sack_ptr =
+                                               (uint32_t *) &options_ptr[i];
+                                       uint32_t ack = rte_bswap32(*sack_ptr);
+
+                                       if (rte_after(ack, sack))
+                                               sack = ack;
+                               }
+                               return sack;
+                       }
+                       break;
+               default:
+                       break;
+               }
+               if ((opsize < 2) || (opsize > length)) {
+                       printf("rte_ct_tcp_sack: something wrong, opsize %i,",
+                                       opsize);
+                       printf(" length %i\n", length);
+                       return sack;
+               }
+               options_ptr += opsize;
+               length -= opsize;
+       }
+       return sack;
+}
+
+/*
+ * if this is a retransmission of last packet, increment retransmission count,
+ * otherwise record this as last packet.
+ */
+static inline void
+rte_ct_check_for_retransmissions(
+       struct rte_ct_tcp *state,
+       uint8_t dir,
+       uint32_t seq,
+       uint32_t ack,
+       uint32_t end,
+       uint16_t win)
+{
+       if (state->last_dir == dir
+                       && state->last_seq == seq
+                       && state->last_ack == ack
+                       && state->last_end == end && state->last_win == win)
+               state->retrans++;
+       else {
+               state->last_dir = dir;
+               state->last_seq = seq;
+               state->last_ack = ack;
+               state->last_end = end;
+               state->last_win = win;
+               state->retrans = 0;
+       }
+}
+
+/*
+ * Verify that the sequence number in the given packet is within the valid
+ * range at this point in the connection
+ */
+static uint8_t
+rte_ct_tcp_in_window(
+       struct rte_ct_cnxn_data *cd,
+       struct rte_ct_cnxn_tracker *ct,
+       struct rte_ct_tcp *state,
+       enum rte_ct_pkt_direction dir,
+       uint8_t index,
+       struct rte_mbuf *pkt,
+       uint8_t ip_hdr_size)
+{
+       struct rte_ct_tcp_state *sender = &state->seen[dir];
+       struct rte_ct_tcp_state *receiver = &state->seen[!dir];
+       uint32_t seq, ack, sack, end, win, swin;
+       uint8_t in_recv_win, tcp_flags;
+       enum rte_ct_packet_action res;
+
+       void *iphdr = RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
+       struct tcp_hdr *tcpheader =
+               (struct tcp_hdr *)RTE_MBUF_METADATA_UINT32_PTR(pkt,
+                               (IP_START + ip_hdr_size));
+
+       if (cd->ct_protocol.synproxy_data.synproxied)
+               rte_sp_adjust_client_ack_before_window_check(cd, iphdr,
+                               tcpheader, dir);
+
+
+       seq = rte_bswap32(tcpheader->sent_seq);
+       ack = sack = rte_bswap32(tcpheader->recv_ack);
+       win = rte_bswap16(tcpheader->rx_win);
+       end = rte_ct_seq_plus_length(pkt, ip_hdr_size);
+       tcp_flags = tcpheader->tcp_flags;
+
+       if (receiver->flags & RTE_CT_TCP_FLAG_SACK_PERM)
+               sack = rte_ct_tcp_sack(pkt, ip_hdr_size);
+
+       if (unlikely(sender->maxwin == 0)) {
+               /* First packet for sender, initialize data.  */
+               if (tcp_flags & RTE_CT_TCPHDR_SYN) {
+                       /*
+                        * SYN-ACK in reply to a SYN
+                        * or SYN from reply direction in simultaneous open.
+                        */
+                       sender->end = sender->maxend = end;
+                       sender->maxwin = RTE_MAX(win, (uint32_t)1);
+
+                       rte_ct_check_for_scaling_and_sack_perm(pkt, sender,
+                                       ip_hdr_size);
+
+                       /*
+                        * RFC 1323: Both sides must send Window Scale option
+                        * to enable scaling in either direction.
+                        */
+                       if ((sender->
+                                        flags & receiver->flags &
+                                        RTE_CT_TCP_FLAG_WINDOW_SCALE) == 0)
+                               sender->scale = receiver->scale = 0;
+
+                       if (!(tcp_flags & RTE_CT_TCPHDR_ACK))
+                               /* Simultaneous open */
+                               return 1;
+               } else {
+                       /*
+                        * In the middle of a connection with no setup data.
+                        * Use available data from the packet.
+                        */
+                       sender->end = end;
+                       swin = win << sender->scale;
+                       sender->maxwin = (swin == 0 ? 1 : swin);
+                       sender->maxend = end + sender->maxwin;
+                       /*
+                        * We haven't seen traffic in the other direction yet
+                        * but we have to tweak window tracking to pass III
+                        * and IV until that happens.
+                        */
+                       if (receiver->maxwin == 0)
+                               receiver->end = receiver->maxend = sack;
+               }
+       }
+       /* if sender unititialized */
+       else if (((cd->ct_protocol.tcp_ct_data.state == RTE_CT_TCP_SYN_SENT &&
+                        dir == RTE_CT_DIR_ORIGINAL) ||
+                       (cd->ct_protocol.tcp_ct_data.state == RTE_CT_TCP_SYN_RECV &&
+                        dir == RTE_CT_DIR_REPLY)) && rte_after(end, sender->end)) {
+               /*
+                * RFC 793: "if a TCP is reinitialized ... then it need
+                * not wait at all; it must only be sure to use sequence
+                * numbers larger than those recently used."
+                */
+               sender->end = sender->maxend = end;
+               sender->maxwin = RTE_MAX(win, (uint32_t)1);
+
+               rte_ct_check_for_scaling_and_sack_perm(pkt, sender,
+                               ip_hdr_size);
+       }
+       /* If no ACK, just pretend there was.  */
+       if (!(tcp_flags & RTE_CT_TCPHDR_ACK) ||
+                       (((tcp_flags & RTE_CT_TCPHDR_RST_ACK) ==
+                               RTE_CT_TCPHDR_RST_ACK) && (ack == 0))) {
+               /* Bad TCP Stacks */
+               ack = sack = receiver->end;
+       }
+
+       if ((tcp_flags & RTE_CT_TCPHDR_RST) && seq == 0 &&
+                       cd->ct_protocol.tcp_ct_data.state == RTE_CT_TCP_SYN_SENT)
+               /* RST sent answering SYN. */
+               seq = end = sender->end;
+
+       /* Is the ending sequence in the receive window (if available)? */
+       in_recv_win = !receiver->maxwin ||
+                       rte_after(end, sender->end - receiver->maxwin - 1);
+
+       if (rte_before(seq, sender->maxend + 1) && in_recv_win &&
+                       rte_before(sack, receiver->end + 1) &&
+                       rte_after(sack,
+                               receiver->end - RTE_MAX(sender->maxwin,
+                                       (uint32_t)RTE_MAX_ACKWIN_CONST) - 1)) {
+               /*
+                * Apply window scaling (RFC 1323). Only valid if both
+                * directions sent this option in a SYN packet,
+                * so ignore until not a SYN packet. Scale will be
+                * set to zero if connection set up but no valid scale is there.
+                */
+               if (!(tcp_flags & RTE_CT_TCPHDR_SYN))
+                       win <<= sender->scale;
+
+               /* Update sender data. */
+               swin = win + (sack - ack);
+               sender->maxwin = RTE_MAX(sender->maxwin, swin);
+
+               if (rte_after(end, sender->end)) {
+                       sender->end = end;
+                       sender->flags |= RTE_CT_TCP_FLAG_DATA_UNACKNOWLEDGED;
+               }
+
+               if (tcp_flags & RTE_CT_TCPHDR_ACK) {
+                       if (!(sender->flags & RTE_CT_TCP_FLAG_MAXACK_SET)) {
+                               sender->maxack = ack;
+                               sender->flags |= RTE_CT_TCP_FLAG_MAXACK_SET;
+                       } else if (rte_after(ack, sender->maxack))
+                               sender->maxack = ack;
+               }
+
+               /* Update receiver data. */
+               if (receiver->maxwin != 0 && rte_after(end, sender->maxend))
+                       receiver->maxwin += end - sender->maxend;
+
+               if (rte_after(sack + win, receiver->maxend - 1))
+                       receiver->maxend = sack + RTE_MAX(win, (uint32_t)1);
+
+               if (ack == receiver->end)
+                       receiver->flags &= ~RTE_CT_TCP_FLAG_DATA_UNACKNOWLEDGED;
+
+               /* If this packet has an ACK, it may be a retransmission.  */
+               if (index == RTE_CT_TCP_ACK_FLAG)
+                       rte_ct_check_for_retransmissions(state, dir, seq, ack,
+                                                        end, win);
+               res = 1;
+       } else {
+               res = (sender->flags & RTE_CT_TCP_FLAG_BE_LIBERAL ||
+                                        ct->misc_options.tcp_be_liberal);
+       }
+
+       if (CT_DEBUG) {
+               if (!res) {
+                       /* CT_DEBUG = 0; */
+                       printf("tcp_in_window FAILED for %p\n", cd);
+                       printf("rte_before(%u, %u + 1) is %d\n",
+                                                seq, sender->maxend + 1,
+                                                rte_before(seq, sender->maxend + 1));
+                       printf("!%u ||  rte_after(%u, %u - %u - 1) is %d\n",
+                                                receiver->maxwin, end, sender->end,
+                                                receiver->maxwin, in_recv_win);
+                       printf("rte_before(%u, %u + 1) is %d\n", sack,
+                                                receiver->end, rte_before(sack,
+                                                        receiver->end + 1));
+                       printf
+                                       ("rte_after(%u,(%u - RTE_MAX(%u, %u) - 1))) is%d\n",
+                                        sack, receiver->end, sender->maxwin,
+                                        RTE_MAX_ACKWIN_CONST, rte_after(sack,
+                                                receiver->end - RTE_MAX(sender->maxwin,
+                                                        (uint32_t)RTE_MAX_ACKWIN_CONST)
+                                                - 1));
+
+               }
+       }
+       if (cd->ct_protocol.synproxy_data.synproxied)
+               rte_sp_adjust_server_seq_after_window_check(cd, iphdr,
+                               tcpheader, dir);
+       return res;
+}
+
+/*for the given two FSM states,return the one with the smallest timeout value*/
+static inline uint8_t
+rte_ct_choose_min_timeout_state(
+       struct rte_ct_cnxn_tracker *ct,
+       uint8_t state1,
+       uint8_t state2)
+{
+       if (ct->ct_timeout.tcptimeout.tcp_timeouts[state1] <
+                       ct->ct_timeout.tcptimeout.tcp_timeouts[state2])
+               return state1;
+       else
+               return state2;
+}
+
+
+/* Returns verdict for packet */
+enum rte_ct_packet_action
+rte_ct_verify_tcp_packet(
+       struct rte_ct_cnxn_tracker *ct,
+       struct rte_ct_cnxn_data *cd,
+       struct rte_mbuf *pkt,
+       uint8_t key_was_flipped,
+       uint8_t ip_hdr_size)
+{
+       struct tcp_hdr *tcpheader = (struct tcp_hdr *)
+                       RTE_MBUF_METADATA_UINT32_PTR(pkt, (IP_START + ip_hdr_size));
+
+       enum rte_ct_tcp_states new_state, old_state;
+       enum rte_ct_pkt_direction dir;
+       uint8_t index;
+
+       /* state whose timeout value will be used. In odd cases,
+        * not always current state */
+       uint8_t timeout_state;
+
+       dir = (cd->key_is_client_order == !key_was_flipped);
+
+       if (cd->ct_protocol.synproxy_data.synproxied &&
+               cd->ct_protocol.synproxy_data.half_established &&
+               !cd->ct_protocol.synproxy_data.cnxn_established &&
+               dir == RTE_CT_DIR_ORIGINAL) {
+               /*
+                * Packet from client, but only client side of this connection
+                * has been set up. Buffer packet until server side of
+                * connection complete.
+                */
+               rte_ct_buffer_packet(ct, cd, pkt);
+               return RTE_CT_HIJACK;
+       }
+
+       uint32_t recv_ack = rte_bswap32(tcpheader->recv_ack);
+       uint32_t sent_seq = rte_bswap32(tcpheader->sent_seq);
+
+       int check_window = 1;
+       enum rte_ct_packet_action return_action = RTE_CT_FORWARD_PACKET;
+
+       /*  rte_ct_tcpdisplay_hdr(tcpheader); */
+
+       old_state = cd->ct_protocol.tcp_ct_data.state;
+       index = rte_ct_get_index(tcpheader->tcp_flags);
+       new_state = rte_ct_tcp_state_table[dir][index][old_state];
+
+       if (new_state == RTE_CT_TCP_MAX) {
+               if (CT_DEBUG) {
+                       printf("!!!!invalid state transition from %s ",
+                                       rte_ct_tcp_names[old_state]);
+                       printf("with flags 0x%02x\n",
+                                       tcpheader->tcp_flags);
+               }
+
+               ct->counters->pkts_drop_invalid_state++;
+               return RTE_CT_DROP_PACKET;
+       }
+
+       if (STATE_TRACKING && new_state != old_state)
+               printf(" new state %s\n", rte_ct_tcp_names[new_state]);
+
+       switch (new_state) {
+
+       case RTE_CT_TCP_ESTABLISHED:
+
+               if (cd->ct_protocol.synproxy_data.synproxied &&
+                               !cd->ct_protocol.synproxy_data.half_established &&
+                               (old_state == RTE_CT_TCP_SYN_RECV)) {
+                       /*
+                        * During synproxy setup, ESTABLISHED state entered by
+                        * ACK arriving from client. The proxy must now send a
+                        * spoofed SYN to the server.
+                        * Reset the state to RTE_CT_TCP_SYN_SENT.
+                        */
+
+                       if (STATE_TRACKING) {
+                               printf(" synproxy first half-cnxn complete,");
+                               printf(" new state %s\n",
+                                       rte_ct_tcp_names[RTE_CT_TCP_SYN_SENT]);
+                       }
+                       cd->ct_protocol.synproxy_data.half_established = true;
+
+                       rte_sp_cvt_to_spoofed_server_syn(cd, pkt);
+                       rte_ct_clear_cnxn_data(ct, cd, pkt);
+                       cd->ct_protocol.tcp_ct_data.state = RTE_CT_TCP_SYN_SENT;
+
+                       struct rte_ct_tcp_state *sender =
+                               &cd->ct_protocol.tcp_ct_data.
+                               seen[RTE_CT_DIR_ORIGINAL];
+                       uint16_t win = rte_bswap16(tcpheader->rx_win);
+
+                       sender->end = sender->maxend =
+                               rte_ct_seq_plus_length(pkt, ip_hdr_size);
+                       sender->maxwin = RTE_MAX(win, (uint32_t)1);
+                       rte_ct_check_for_scaling_and_sack_perm(pkt, sender,
+                                       ip_hdr_size);
+                       /* TODO seq number code */
+                       rte_ct_set_cnxn_timer_for_tcp(ct, cd,
+                                       RTE_CT_TCP_SYN_SENT);
+                       return RTE_CT_SEND_SERVER_SYN;
+               }
+
+
+       case RTE_CT_TCP_SYN_RECV:
+
+               if (cd->ct_protocol.synproxy_data.synproxied &&
+                               cd->ct_protocol.synproxy_data.half_established &&
+                               !cd->ct_protocol.synproxy_data.cnxn_established) {
+                       /*
+                        * The reply SYN/ACK has been received from the server.
+                        * The connection can now be considered established,
+                        * even though an ACK stills needs to be sent to
+                        * the server.
+                        */
+
+                       if (!rte_ct_tcp_in_window(cd, ct,
+                                               &cd->ct_protocol.tcp_ct_data,
+                                               dir, index, pkt, ip_hdr_size)) {
+                               ct->counters->pkts_drop_outof_window++;
+                               return RTE_CT_DROP_PACKET;
+                       }
+
+                       if (STATE_TRACKING) {
+                               printf("synproxy full cnxn complete,");
+                               printf(" new state %s\n", rte_ct_tcp_names
+                                               [RTE_CT_TCP_ESTABLISHED]);
+                       }
+
+                       /*
+                        * Convert the packet to an ack to return to the server.
+                        * This routine also saves the real sequence number
+                        * from the server.
+                        */
+
+                       rte_sp_cvt_to_spoofed_server_ack(cd, pkt);
+
+                       index = rte_ct_get_index(tcpheader->tcp_flags);
+
+                       if (!rte_ct_tcp_in_window(cd, ct,
+                                       &cd->ct_protocol.tcp_ct_data,
+                                       !dir, index, pkt, ip_hdr_size)) {
+                               ct->counters->pkts_drop_outof_window++;
+                               return RTE_CT_DROP_PACKET;
+                       }
+
+                       /* good packets, OK to update state */
+
+                       cd->ct_protocol.tcp_ct_data.state =
+                               RTE_CT_TCP_ESTABLISHED;
+                       ct->counters->sessions_established++;
+                       cd->ct_protocol.synproxy_data.cnxn_established = true;
+                       cd->ct_protocol.tcp_ct_data.last_index = index;
+                       cd->ct_protocol.tcp_ct_data.last_dir = !dir;
+
+                       rte_ct_set_cnxn_timer_for_tcp(ct, cd,
+                                       RTE_CT_TCP_ESTABLISHED);
+                       rte_ct_release_buffered_packets(ct, cd);
+
+                       return RTE_CT_SEND_SERVER_ACK;
+               }
+
+       case RTE_CT_TCP_SYN_SENT:
+
+               /*
+                * A connection that is actively closed goes to TIME-WAIT state.
+                * It can be re-opened (before it times out) by a SYN packet.
+                */
+
+               if (old_state < RTE_CT_TCP_TIME_WAIT)
+                       break;
+               /*
+                * Due to previous check and state machine transitions,
+                * old state must be RTE_CT_TCP_TIME_WAIT or RTE_CT_TCP_CLOSE .
+                * Need to re-open connection.
+                */
+
+               return RTE_CT_REOPEN_CNXN_AND_FORWARD_PACKET;
+
+       case RTE_CT_TCP_IGNORE:
+
+               /*
+                * Ignored packets usually mean the connection data is
+                * out of sync with client/server. Ignore, but forward
+                * these packets since they may be valid for the connection.
+                * If the ignored packet is invalid, the receiver will send
+                * an RST which should get the connection entry back in sync.
+                */
+
+               /*
+                * However, if connection is running synproxy and the full
+                * connection is not yet established, there is no where
+                * for test packets to go so drop these packets.
+                */
+
+               if (cd->ct_protocol.synproxy_data.synproxied &&
+                               !cd->ct_protocol.synproxy_data.cnxn_established)
+                       return RTE_CT_DROP_PACKET;
+
+               if (index == RTE_CT_TCP_SAK_FLAG &&
+                               cd->ct_protocol.tcp_ct_data.last_index ==
+                               RTE_CT_TCP_SYN_FLAG
+                               && cd->ct_protocol.tcp_ct_data.last_dir != dir
+                               && recv_ack == cd->ct_protocol.tcp_ct_data.last_end) {
+                       /*
+                        * SYN/ACK in reply direction acknowledging a SYN
+                        * earlier ignored as invalid.Client and server in sync,
+                        * but connection tracker is not. Use previous values
+                        * to get back in sync.
+                        */
+
+                       struct rte_ct_tcp_state *last_seen =
+                                       &cd->ct_protocol.tcp_ct_data.seen[cd->ct_protocol.
+                                                                               tcp_ct_data.
+                                                                               last_dir];
+
+                       /* reset new and old states to what they should
+                        * have been */
+                       old_state = RTE_CT_TCP_SYN_SENT;
+                       new_state = RTE_CT_TCP_SYN_RECV;
+
+                       last_seen->end = cd->ct_protocol.tcp_ct_data.last_end;
+                       last_seen->maxend =
+                                       cd->ct_protocol.tcp_ct_data.last_end;
+                       last_seen->maxwin =
+                               RTE_MAX(cd->ct_protocol.tcp_ct_data.last_win,
+                                               (uint32_t)1);
+                       last_seen->scale =
+                                       cd->ct_protocol.tcp_ct_data.last_wscale;
+                       cd->ct_protocol.tcp_ct_data.last_flags &=
+                                       ~RTE_CT_EXP_CHALLENGE_ACK;
+                       last_seen->flags =
+                                       cd->ct_protocol.tcp_ct_data.last_flags;
+                       memset(&cd->ct_protocol.tcp_ct_data.seen[dir], 0,
+                                                sizeof(struct rte_ct_tcp_state));
+                       break;
+               }
+
+               cd->ct_protocol.tcp_ct_data.last_index = index;
+               cd->ct_protocol.tcp_ct_data.last_dir = dir;
+               cd->ct_protocol.tcp_ct_data.last_seq = sent_seq;
+               cd->ct_protocol.tcp_ct_data.last_end =
+                       rte_ct_seq_plus_length(pkt, ip_hdr_size);
+               cd->ct_protocol.tcp_ct_data.last_win =
+                       rte_bswap16(tcpheader->rx_win);
+
+               /*
+                * An orinal SYN. Client and the server may be in sync, but
+                * the tracker is not . Annotate
+                * the TCP options and let the packet go through. If it is a
+                * valid SYN packet, the server will reply with a SYN/ACK, and
+                * then we'll get in sync. Otherwise, the server potentially
+                * responds with a challenge ACK if implementing RFC5961.
+                */
+               if (index == RTE_CT_TCP_SYN_FLAG &&
+                               dir == RTE_CT_DIR_ORIGINAL) {
+                       struct rte_ct_tcp_state seen;
+
+                       /* call following to set "flag" and "scale" fields */
+                       rte_ct_check_for_scaling_and_sack_perm(pkt, &seen,
+                                       ip_hdr_size);
+
+                       /* only possible flags set for scling and sack */
+                       cd->ct_protocol.tcp_ct_data.last_flags = seen.flags;
+                       cd->ct_protocol.tcp_ct_data.last_wscale =
+                       (seen.flags & RTE_CT_TCP_FLAG_WINDOW_SCALE) == 0 ?
+                                       0 : seen.scale;
+
+                       /*
+                        * Mark the potential for RFC5961 challenge ACK,
+                        * this pose a special problem for LAST_ACK state
+                        * as ACK is intrepretated as ACKing last FIN.
+                        */
+                       if (old_state == RTE_CT_TCP_LAST_ACK)
+                               cd->ct_protocol.tcp_ct_data.last_flags |=
+                                       RTE_CT_EXP_CHALLENGE_ACK;
+               }
+               return RTE_CT_FORWARD_PACKET;
+
+       case RTE_CT_TCP_TIME_WAIT:
+               /*
+                * RFC5961 compliance cause stack to send "challenge-ACK" in
+                * response to unneeded SYNs. Do not treat this as acking
+                * last FIN.
+                */
+               if (old_state == RTE_CT_TCP_LAST_ACK &&
+                               index == RTE_CT_TCP_ACK_FLAG &&
+                               cd->ct_protocol.tcp_ct_data.last_dir != dir &&
+                               cd->ct_protocol.tcp_ct_data.last_index ==
+                               RTE_CT_TCP_SYN_FLAG
+                               && (cd->ct_protocol.tcp_ct_data.
+                       last_flags & RTE_CT_EXP_CHALLENGE_ACK)) {
+                       /* Detected RFC5961 challenge ACK */
+                       cd->ct_protocol.tcp_ct_data.last_flags &=
+                               ~RTE_CT_EXP_CHALLENGE_ACK;
+                       return RTE_CT_FORWARD_PACKET;   /* Don't change state */
+               }
+               break;
+
+       case RTE_CT_TCP_CLOSE:
+
+               if (index == RTE_CT_TCP_RST_FLAG) {
+                       /*
+                        * Can only transition to CLOSE state with an RST,
+                        * but can remain in
+                        * CLOSE state with ACK, FIN, or RST. Do special checks.
+                        */
+
+                       if ((cd->ct_protocol.tcp_ct_data.seen[!dir].flags &
+                                               RTE_CT_TCP_FLAG_MAXACK_SET) &&
+                                       rte_before(sent_seq, cd->ct_protocol.
+                                       tcp_ct_data.seen[!dir].maxack)) {
+
+                               ct->counters->pkts_drop_invalid_rst++;
+                               /* Invalid RST  */
+                               return RTE_CT_DROP_PACKET;
+                       }
+
+                       if (((cd->connstatus == RTE_SEEN_REPLY_CONN &&
+                                               cd->ct_protocol.tcp_ct_data.last_index ==
+                                                       RTE_CT_TCP_SYN_FLAG) ||
+                               (cd->connstatus != RTE_ASSURED_CONN &&
+                               cd->ct_protocol.tcp_ct_data.last_index ==
+                                                       RTE_CT_TCP_ACK_FLAG)) &&
+                               recv_ack ==
+                                       cd->ct_protocol.tcp_ct_data.last_end) {
+                               /* RST sent to invalid SYN or ACK previously
+                                * let through */
+                               check_window = 0;
+                       }
+               }
+               break;
+
+       default:
+               break;
+       }
+
+       if (likely(check_window)) {
+               if (unlikely(!rte_ct_tcp_in_window(cd, ct,
+                                               &cd->ct_protocol.tcp_ct_data,
+                                               dir, index,
+                                               pkt, ip_hdr_size))) {
+                       ct->counters->pkts_drop_outof_window++;
+                       return RTE_CT_DROP_PACKET;
+               }
+       }
+
+       if (new_state == RTE_CT_TCP_ESTABLISHED &&
+                       old_state != RTE_CT_TCP_ESTABLISHED)
+               /* only increment for first state transition to established */
+               /* synproxy established count handled elswhere */
+               ct->counters->sessions_established++;
+       /* From this point on, all packets are in-window */
+       cd->ct_protocol.tcp_ct_data.last_index = index;
+       cd->ct_protocol.tcp_ct_data.last_dir = dir;
+
+       if (index == RTE_CT_TCP_SAK_FLAG)
+               cd->connstatus = RTE_SEEN_REPLY_CONN;
+
+       timeout_state = new_state;
+
+       if (cd->ct_protocol.tcp_ct_data.retrans >=
+                       ct->misc_options.tcp_max_retrans)
+               timeout_state =
+                       rte_ct_choose_min_timeout_state(ct, timeout_state,
+                                       RTE_CT_TCP_RETRANS);
+       else if (rte_ct_either_direction_has_flags(cd,
+                               RTE_CT_TCP_FLAG_DATA_UNACKNOWLEDGED))
+               timeout_state =
+                       rte_ct_choose_min_timeout_state(ct, timeout_state,
+                                       RTE_CT_TCP_UNACK);
+
+       if (cd->connstatus != RTE_SEEN_REPLY_CONN) {
+               if (tcpheader->tcp_flags & RTE_CT_TCPHDR_RST) {
+                       /*
+                        * if only reply seen is RST, there is not an
+                        * established connection, so just destroy
+                        * connection now.
+                        */
+
+                       return RTE_CT_DESTROY_CNXN_AND_FORWARD_PACKET;
+               }
+               /* ESTABLISHED without SEEN_REPLY, i.e. mid-connection
+                        pickup with loose=1. Avoid large ESTABLISHED timeout. */
+               if (new_state == RTE_CT_TCP_ESTABLISHED)
+                       timeout_state = rte_ct_choose_min_timeout_state(ct,
+                                       timeout_state,
+                                       RTE_CT_TCP_UNACK);
+
+       } else if (cd->connstatus != RTE_ASSURED_CONN &&
+                        (old_state == RTE_CT_TCP_SYN_RECV
+                               || old_state == RTE_CT_TCP_ESTABLISHED)
+                        && new_state == RTE_CT_TCP_ESTABLISHED)
+               cd->connstatus = RTE_ASSURED_CONN;
+
+       cd->ct_protocol.tcp_ct_data.state = new_state;
+       rte_ct_set_cnxn_timer_for_tcp(ct, cd, timeout_state);
+
+       return return_action;
+}
diff --git a/common/VIL/conntrack/rte_ct_tcp.h b/common/VIL/conntrack/rte_ct_tcp.h
new file mode 100644 (file)
index 0000000..391200c
--- /dev/null
@@ -0,0 +1,484 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef __INCLUDE_RTE_CT_TCP_H__
+#define __INCLUDE_RTE_CT_TCP_H__
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include <rte_tcp.h>
+#include <rte_port.h>
+#include <rte_timer.h>
+#include <rte_ip.h>
+#include <rte_tcp.h>
+#include <rte_udp.h>
+#include <rte_port.h>
+#include <rte_byteorder.h>
+#include "rte_cnxn_tracking.h"
+
+/* AN INNER, PRIVATE INTERFACE FOR RTE_CNXN_TRACKING */
+
+/* constants for TCP options */
+
+#define RTE_CT_TCPOPT_EOL                              0       /* End of options */
+#define RTE_CT_TCPOPT_NOP                              1       /* Padding */
+#define RTE_CT_TCPOPT_MSS                              2       /* Segment size negotiating */
+#define RTE_CT_TCPOPT_WINDOW            3       /* Window scaling */
+#define RTE_CT_TCPOPT_SACK_PERM        4       /* SACK Permitted */
+#define RTE_CT_TCPOPT_SACK                      5       /* SACK Block */
+#define RTE_CT_TCPOPT_TIMESTAMP        8       /* RTT estimations */
+
+#define RTE_CT_TCPOLEN_MSS                     4
+#define RTE_CT_TCPOLEN_WINDOW   3
+#define RTE_CT_TCPOLEN_SACK_PERM      2
+#define RTE_CT_TCPOLEN_TIMESTAMP      10
+#define RTE_CT_TCPOLEN_PER_SACK_ENTRY 8
+
+#define RTE_CT_TCPOLEN_MSS_ALIGNED                     4
+#define RTE_CT_TCPOLEN_WINDOW_ALIGNED   4
+#define RTE_CT_TCPOLEN_SACK_PERM_ALIGNED      4
+#define RTE_CT_TCPOLEN_TIMESTAMP_ALIGNED      12
+
+#define RTE_CT_MAX_TCP_WINDOW_SCALE  14
+
+#define RTE_SP_OPTIONS_MSS 1
+#define RTE_SP_OPTIONS_WINDOW_SCALE 2
+#define RTE_SP_OPTIONS_TIMESTAMP 4
+#define RTE_SP_OPTIONS_SACK_PERM 8
+
+
+enum rte_ct_packet_action {
+       RTE_CT_OPEN_CONNECTION,
+       RTE_CT_DROP_PACKET,
+       RTE_CT_FORWARD_PACKET,
+       RTE_CT_DESTROY_CNXN_AND_FORWARD_PACKET,
+       RTE_CT_REOPEN_CNXN_AND_FORWARD_PACKET,
+       RTE_CT_SEND_CLIENT_SYNACK,
+       RTE_CT_SEND_SERVER_SYN,
+       RTE_CT_SEND_SERVER_ACK,
+       RTE_CT_HIJACK
+};
+
+enum rte_ct_connstatus {
+       RTE_INIT_CONN,
+       RTE_SEEN_REPLY_CONN,
+       RTE_ASSURED_CONN
+};
+
+/* TCP tracking. */
+
+static const char *const rte_ct_tcp_names[] = {
+       "NONE",
+       "SYN_SENT",
+       "SYN_RECV",
+       "ESTABLISHED",
+       "FIN_WAIT",
+       "CLOSE_WAIT",
+       "LAST_ACK",
+       "TIME_WAIT",
+       "CLOSE",
+       "SYN_SENT2",
+       "RETRANS",
+       "UNACK",
+       "IGNORE"
+};
+
+static const char *const rte_ct_udp_names[] = {
+       "NONE_UDP",
+       "UNREPLIED",
+       "REPLIED"
+};
+
+/* Fixme: what about big packets? */
+#define RTE_MAX_ACKWIN_CONST                   66000
+
+/* Window scaling is advertised by the sender */
+#define RTE_CT_TCP_FLAG_WINDOW_SCALE                    0x01
+
+/* SACK is permitted by the sender */
+#define RTE_CT_TCP_FLAG_SACK_PERM              0x02
+
+/* This sender sent FIN first */
+#define RTE_CT_TCP_FLAG_CLOSE_INIT                              0x04
+
+/* Be liberal in window checking */
+#define RTE_CT_TCP_FLAG_BE_LIBERAL                              0x08
+
+/* Has unacknowledged data */
+#define RTE_CT_TCP_FLAG_DATA_UNACKNOWLEDGED      0x10
+
+/* The field td_maxack has been set */
+#define RTE_CT_TCP_FLAG_MAXACK_SET                              0x20
+/* Marks possibility for expected RFC5961 challenge ACK */
+#define RTE_CT_EXP_CHALLENGE_ACK                0x40
+
+
+
+/* TCP header flags of interest */
+#define RTE_CT_TCPHDR_FIN 0x01
+#define RTE_CT_TCPHDR_SYN 0x02
+#define RTE_CT_TCPHDR_RST 0x04
+#define RTE_CT_TCPHDR_ACK 0x10
+
+#define RTE_CT_TCPHDR_RST_ACK (RTE_CT_TCPHDR_RST | RTE_CT_TCPHDR_ACK)
+
+
+
+/* state machine values. Note that order is important as relative checks made */
+enum rte_ct_tcp_states {
+       RTE_CT_TCP_NONE,
+       RTE_CT_TCP_SYN_SENT,
+       RTE_CT_TCP_SYN_RECV,
+       RTE_CT_TCP_ESTABLISHED,
+       RTE_CT_TCP_FIN_WAIT,
+       RTE_CT_TCP_CLOSE_WAIT,
+       RTE_CT_TCP_LAST_ACK,
+       RTE_CT_TCP_TIME_WAIT,
+       RTE_CT_TCP_CLOSE,
+       RTE_CT_TCP_SYN_SENT_2,
+       RTE_CT_TCP_RETRANS,
+       RTE_CT_TCP_UNACK,
+       RTE_CT_TCP_IGNORE
+};
+
+enum rte_ct_udp_states {
+       RTE_CT_UDP_NONE,
+       RTE_CT_UDP_UNREPLIED,
+       RTE_CT_UDP_REPLIED,
+       RTE_CT_UDP_MAX
+};
+
+
+
+#define RTE_CT_TCP_MAX RTE_CT_TCP_UNACK
+
+enum rte_ct_pkt_direction {
+       RTE_CT_DIR_ORIGINAL,
+       RTE_CT_DIR_REPLY
+};
+
+struct rte_ct_tcp_state {
+       uint32_t       end;      /* max of seq + len */
+       uint32_t       maxend;      /* max of ack + max(win, 1) */
+       uint32_t       maxwin;      /* max(win) */
+       uint32_t       maxack;      /* max of ack */
+       uint8_t scale;       /* window scale factor */
+       uint8_t flags;          /* per direction options */
+};
+
+struct rte_synproxy_options {
+       uint8_t         options;
+       uint8_t         window_scale;
+       uint16_t        mss;
+       uint32_t        ts_val;
+       uint32_t        ts_echo_reply;
+       uint16_t        initial_window;
+};
+
+struct ct_sp_cnxn_data {
+       /* buffer client pkt while waiting on server setup,
+        * store in reverse order
+        */
+       struct rte_mbuf *buffered_pkt_list;
+       uint32_t original_spoofed_seq;
+       /* difference between spoofed and real seq from server */
+       uint32_t seq_diff;
+       struct rte_synproxy_options cnxn_options;
+       /* non-zero if this connection created using synproxy */
+       uint8_t  synproxied;
+       bool     half_established;
+       /* non-zero after both half-connections established */
+       bool     cnxn_established;
+};
+
+struct rte_ct_tcp {
+       struct rte_ct_tcp_state seen[2]; /* connection parms per direction */
+       uint8_t state;
+       uint8_t last_dir;       /* Direction of the last packet
+                                       * (TODO: enum ip_conntrack_dir)
+                                       */
+       uint8_t retrans;        /* Number of retransmitted packets */
+       uint8_t last_index;     /* Index of the last packet */
+       uint32_t       last_seq;       /* Last seq number seen in dir */
+       uint32_t       last_ack;       /* Last seq number seen opposite dir */
+       uint32_t       last_end;       /* Last seq + len */
+       uint16_t       last_win;       /* Last window seen in dir */
+       /* For SYN packets while we may be out-of-sync */
+       uint8_t last_wscale;    /* Last window scaling factor seen */
+       uint8_t last_flags;     /* Last flags set */
+};
+
+/*
+ * rte_ct_cnxn_counters holds all the connection-specicif counters.
+ * TODO: Make available in public interface
+ */
+
+struct rte_ct_cnxn_counters {
+       uint64_t packets_received;//Added for CT-NAT
+       uint64_t packets_forwarded;
+       uint64_t packets_dropped;
+};
+
+struct rte_ct_proto {
+       struct rte_ct_tcp tcp_ct_data; /* TCP specific data fields*/
+       struct ct_sp_cnxn_data synproxy_data;
+};
+
+
+/*
+ * rte_ct_cnxn_data contains all the data for a TCP connection. This include
+ * state data as necessary for verifying the validity of TCP packets. In
+ * addition, it holds data necessary for implementing the TCP timers.
+ */
+
+struct rte_ct_cnxn_data {
+       /* The timer will be kept as part of the cnxn_data. When it fires, the
+        * pointer to the timer can be cast as the pointer to the cnxn_data
+        */
+       struct rte_timer timer; /* !!!!! IMPORTANT: Keep as first field !!!!! */
+
+       struct rte_ct_cnxn_counters counters;
+
+       /* full key stored here to allow the timer to remove the connection */
+       /* TODO: Consider storing key signature as well to speed up deletions.*/
+       uint32_t key[10];
+
+       struct rte_ct_proto ct_protocol;
+
+       /* the 100 ms timing step that a packet was seen for connection */
+       uint64_t expected_timeout;
+
+       /* Abstract states also used for timer values, e.g. RTE_CT_TCP_UNACK*/
+       uint8_t state_used_for_timer;
+
+       /* used to compute the "direction" of the packet */
+       uint8_t key_is_client_order;
+       uint8_t connstatus;
+       uint8_t protocol;
+       /* used to store the type of packet ipv4 or ipv6 */
+       uint8_t type;
+       //#ifdef FTP_ALG
+       // Bypass flag to indicate that ALG checking is no more needed;
+       uint8_t alg_bypass_flag;
+       // Can we use key_is_client_order for direction checking
+       uint8_t server_direction;
+       int16_t tcpSeqdiff;
+       // PORT = 0, PASV = 1
+       uint8_t ftp_session_type;
+       uint32_t tcp_payload_size;
+       int16_t  seq_client;
+       int16_t  ack_client;
+       int16_t  seq_server;
+       int16_t  ack_server;
+       //#endif
+} __rte_cache_aligned;
+
+
+#define RTE_CT_TCP_MAX_RETRANS 3
+
+struct rte_ct_tcptimeout {
+       /* a table of timeouts for each state of TCP */
+       uint64_t tcp_timeouts[RTE_CT_TCP_MAX + 1];
+};
+
+
+struct rte_ct_misc_options {
+       uint8_t  synproxy_enabled;
+       uint32_t tcp_loose;
+       uint32_t tcp_be_liberal;
+       uint32_t tcp_max_retrans;
+};
+
+struct rte_ct_udptimeout {
+       uint64_t udp_timeouts[RTE_CT_UDP_MAX + 1];
+};
+
+struct rte_ct_timeout {
+       struct rte_ct_tcptimeout tcptimeout;
+       struct rte_ct_udptimeout udptimeout;
+};
+
+struct rte_ct_cnxn_tracker {
+       struct rte_hash *rhash;
+
+       /*
+        * Data for bulk hash lookup. Use this memory as temporary space.
+        * Too big for stack (64*16 bytes)
+        */
+       uint32_t hash_keys[RTE_HASH_LOOKUP_BULK_MAX][10];
+
+       /* table of pointers to above, for bulk hash lookup */
+       void *hash_key_ptrs[RTE_HASH_LOOKUP_BULK_MAX];
+       #ifdef CT_CGNAT
+       uint32_t positions[RTE_HASH_LOOKUP_BULK_MAX];/*added for ALG*/
+       #endif
+       /* hash table and timer storage */
+       uint32_t num_cnxn_entries;
+
+       /*
+        * pointer to data space used for hash table, "num_cnxn_entries" long.
+        * Memory allocated during initialization.
+        */
+       struct rte_ct_cnxn_data *hash_table_entries;
+       struct rte_CT_counter_block *counters;
+
+       uint64_t hertz;
+       uint64_t timing_cycles_per_timing_step;
+       uint64_t timing_100ms_steps;
+       uint64_t timing_100ms_steps_previous;
+       uint64_t timing_last_time;
+       struct rte_ct_timeout ct_timeout;
+       struct rte_ct_misc_options misc_options;
+
+       char name[16];
+       struct rte_ct_cnxn_data *new_connections[64];
+       struct rte_mbuf *buffered_pkt_list;
+       int latest_connection;
+       /* offset into mbuf where synnproxy can store a pointer */
+       uint16_t pointer_offset;
+} __rte_cache_aligned;
+
+/*
+ * Returns a value stating if this is a valid TCP open connection attempt.
+ * If valid, updates cnxn with any data fields it need to save.
+ */
+
+enum rte_ct_packet_action
+rte_ct_tcp_new_connection(
+       struct  rte_ct_cnxn_tracker *inst,
+       struct  rte_ct_cnxn_data *cnxn,
+       struct  rte_mbuf *pkt,
+       int     use_synproxy,
+       uint8_t ip_hdr_size);
+
+/*
+* Returns a value stating if this is a valid TCP packet for the give connection.
+* If valid, updates cnxn with any data fields it need to save.
+*/
+
+enum rte_ct_packet_action
+rte_ct_verify_tcp_packet(
+       struct rte_ct_cnxn_tracker *inst,
+       struct rte_ct_cnxn_data *cnxn,
+       struct rte_mbuf *pkt,
+       uint8_t  key_was_flipped,
+       uint8_t ip_hdr_size);
+
+/*
+* Returns a value stating if this is a valid UDP open connection attempt.
+* If valid, updates cnxn with any data fields it need to save.
+*/
+
+uint8_t
+rte_ct_udp_new_connection(
+       struct rte_ct_cnxn_tracker *ct,
+       struct rte_ct_cnxn_data *cd,
+       struct rte_mbuf *pkt);
+
+/*
+* Returns a value stating if this is a valid UDP packet for the give connection.
+* If valid, updates cnxn with any data fields it need to save.
+*/
+
+enum rte_ct_packet_action
+rte_ct_udp_packet(
+       struct rte_ct_cnxn_tracker *ct,
+       struct rte_ct_cnxn_data *cd,
+       struct rte_mbuf *pkt,
+       uint8_t  key_was_flipped);
+
+
+/*
+ * For the given connection, set a timeout based on the given state. If the
+ * timer is already set, this call will reset the timer with a new value.
+ */
+
+void
+rte_ct_set_cnxn_timer_for_tcp(
+       struct rte_ct_cnxn_tracker *ct,
+       struct rte_ct_cnxn_data *cd,
+       uint8_t tcp_state);
+
+void
+rte_ct_set_cnxn_timer_for_udp(
+       struct rte_ct_cnxn_tracker *ct,
+       struct rte_ct_cnxn_data *cd,
+       uint8_t tcp_state);
+
+/* Cancel timer associated with the connection. Safe to call if no timer set.*/
+void rte_ct_cancel_cnxn_timer(struct rte_ct_cnxn_data *cd);
+
+
+/*
+ * SYNPROXY related routines. Detailed comments are available in
+ * rte_ct_synproxy.c where they are implemented.
+ */
+
+
+/* these 3 routines convert a received packet to a different one */
+
+void
+rte_sp_cvt_to_spoofed_client_synack(struct rte_ct_cnxn_data *cd,
+               struct rte_mbuf *old_pkt);
+
+void
+rte_sp_cvt_to_spoofed_server_syn(struct rte_ct_cnxn_data *cd,
+               struct rte_mbuf *old_pkt);
+
+void
+rte_sp_cvt_to_spoofed_server_ack(struct rte_ct_cnxn_data *cd,
+               struct rte_mbuf *old_pkt);
+
+/* These two routines adjust seq or ack numbers,
+ * as part of the proxy mechanism
+ */
+
+void
+rte_sp_adjust_client_ack_before_window_check(
+       struct rte_ct_cnxn_data *cd,
+       void *i_hdr,
+       struct tcp_hdr *thdr,
+       enum rte_ct_pkt_direction dir);
+
+void
+rte_sp_adjust_server_seq_after_window_check(
+       struct rte_ct_cnxn_data *cd,
+       void *i_hdr,
+       struct tcp_hdr *thdr,
+       enum rte_ct_pkt_direction dir);
+
+
+
+/* parse tcp options and save in t_opts */
+void
+rte_sp_parse_options(struct rte_mbuf *pkt, struct rte_ct_cnxn_data *cd);
+
+
+/* these two routines deal with packet buffering */
+
+void
+rte_ct_buffer_packet(
+       struct rte_ct_cnxn_tracker *ct,
+       struct rte_ct_cnxn_data *cd,
+       struct rte_mbuf *pkt);
+
+void
+       rte_ct_release_buffered_packets(
+       struct rte_ct_cnxn_tracker *ct,
+       struct rte_ct_cnxn_data *cd);
+
+#endif /* TCPCONNTRACK_H */
diff --git a/common/VIL/conntrack/rte_ct_udp.c b/common/VIL/conntrack/rte_ct_udp.c
new file mode 100644 (file)
index 0000000..88f3a9a
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include "rte_ct_tcp.h"
+#include "rte_cnxn_tracking.h"
+
+uint8_t rte_ct_udp_new_connection(__rte_unused struct rte_ct_cnxn_tracker *ct,
+               struct rte_ct_cnxn_data *cd,
+               __rte_unused struct rte_mbuf *pkt)
+{
+       /* printf("New connection UDP packet received\n"); */
+       cd->connstatus = RTE_INIT_CONN;
+       return 1;
+}
+enum rte_ct_packet_action rte_ct_udp_packet(struct rte_ct_cnxn_tracker *ct,
+               struct rte_ct_cnxn_data *cd,
+               __rte_unused struct rte_mbuf *pkt,
+               uint8_t  key_was_flipped)
+{
+       enum rte_ct_pkt_direction dir;
+
+       dir = (cd->key_is_client_order == !key_was_flipped);
+       /* printf("packet received verify"); */
+       if (dir == RTE_CT_DIR_REPLY &&
+                       cd->connstatus == RTE_INIT_CONN) {
+               rte_ct_set_cnxn_timer_for_udp(ct, cd, RTE_CT_UDP_REPLIED);
+               cd->connstatus = RTE_ASSURED_CONN;
+       } else if (dir == RTE_CT_DIR_REPLY &&
+                       cd->connstatus == RTE_ASSURED_CONN)
+               rte_ct_set_cnxn_timer_for_udp(ct, cd, RTE_CT_UDP_REPLIED);
+       else
+               rte_ct_set_cnxn_timer_for_udp(ct, cd, RTE_CT_UDP_UNREPLIED);
+       return RTE_CT_FORWARD_PACKET;
+}
diff --git a/common/VIL/l2l3_stack/Makefile b/common/VIL/l2l3_stack/Makefile
new file mode 100644 (file)
index 0000000..b85bf1d
--- /dev/null
@@ -0,0 +1,35 @@
+# Copyright (c) 2017 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http:#www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overriden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+# binary name
+APP = Protocol
+
+# all source are stored in SRCS-y
+SRCS-y := main.c l2_proto.c interface.c lib_arp.c lib_icmpv6.c l3fwd_main.c l3fwd_lpm4.c l3fwd_lpm6.c bond.c tsx.c hle.c
+
+CFLAGS += -I$(SRCDIR)
+CFLAGS += -O3 $(USER_FLAGS)
+CFLAGS += $(WERROR_FLAGS)
+CFLAGS += -O0 -g
+CFLAGS += -mrtm -mhle
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/common/VIL/l2l3_stack/bond.c b/common/VIL/l2l3_stack/bond.c
new file mode 100644 (file)
index 0000000..8fd1171
--- /dev/null
@@ -0,0 +1,1595 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <interface.h>
+#include "tsx.h"
+extern interface_main_t ifm;
+extern uint8_t ifm_debug;
+extern int USE_RTM_LOCKS;
+extern rte_rwlock_t rwlock;
+
+int ifm_bond_port_create(const char *name, int mode, port_config_t * portconf)
+{
+       int port_id;
+       l2_phy_interface_t *bond_port;
+       if (ifm_debug && IFM_DEBUG_CONFIG)
+               RTE_LOG(INFO, IFM, "%s: i/p name %p, mode %d\n\r", __FUNCTION__,
+                       name, mode);
+       if (name == NULL) {
+               RTE_LOG(ERR, IFM, "%s: Param name cannot be NULL\n\r",
+                       __FUNCTION__);
+               return IFM_FAILURE;
+       }
+       if (mode < 0 || mode > 6) {
+               RTE_LOG(ERR, IFM, "%s: Param mode should be withing 0 to 6\n\r",
+                       __FUNCTION__);
+               return IFM_FAILURE;
+       }
+       if (portconf == NULL) {
+               RTE_LOG(ERR, IFM, "%s: Param portconf cannot be NULL\n\r",
+                       __FUNCTION__);
+               return IFM_FAILURE;
+       }
+       bond_port = ifm_get_port_by_name(name);
+       if (bond_port == NULL) {
+               if (ifm_debug && IFM_DEBUG_CONFIG)
+                       RTE_LOG(INFO, IFM, "Call ifm_port_setup %s\n\r", name);
+               port_id = rte_eth_bond_create(name, mode, 0);
+               if (port_id < 0) {
+                       RTE_LOG(ERR, IFM,
+                               "%s: Failed to create bond port %s with mode %u\n\r",
+                               __FUNCTION__, name, mode);
+                       return IFM_FAILURE;
+               }
+               RTE_LOG(INFO, IFM,
+                       "%s: Created bond port %s(%u) on socket %u with "
+                       "mode %u.\n\r", __FUNCTION__, name, port_id,
+                       rte_eth_dev_socket_id(port_id), mode);
+
+               bond_port = (l2_phy_interface_t *) rte_zmalloc(NULL,
+                                                                                sizeof
+                                                                                (l2_phy_interface_t),
+                                                                                RTE_CACHE_LINE_SIZE);
+               bond_port->pmdid = port_id;
+               strncpy(bond_port->ifname, name, IFM_IFNAME_LEN);
+               memcpy(&bond_port->port_config, portconf,
+                                        sizeof(port_config_t));
+               bond_port->flags |= IFM_MASTER;
+               struct bond_port *bond_info;
+               bond_info = (struct bond_port *)rte_zmalloc(NULL,
+                                                                       sizeof(struct
+                                                                        bond_port),
+                                                                       RTE_CACHE_LINE_SIZE);
+               bond_info->socket_id = rte_eth_dev_socket_id(port_id);
+               bond_info->mode = mode;
+               bond_info->bond_portid = port_id;
+               bond_port->bond_config = bond_info;
+               if (mode == IFM_BONDING_MODE_8023AD)
+                       bond_port->tx_buf_len =
+                                       (2 * RTE_ETH_TX_BUFFER_SIZE(IFM_BURST_SIZE)) *
+                                       RTE_MAX_ETHPORTS;
+               //ifm_add_port_to_port_list(bond_port);
+               ifm.port_list[port_id] = bond_port;
+               if (ifm_debug && IFM_DEBUG_CONFIG)
+                       RTE_LOG(INFO, IFM,
+                               "%s: Added bond port %s(%u) to port list\n\r",
+                               __FUNCTION__, name, port_id);
+       } else {
+               RTE_LOG(INFO, IFM, "%s: Port %s already exists in the"
+                       " port list\n\r", __FUNCTION__, name);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Acquiring lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS)
+                       rtm_lock();
+               else
+                       rte_rwlock_write_lock(&rwlock);
+
+               if (!(bond_port->flags & IFM_MASTER)) {
+                       RTE_LOG(ERR, IFM, "%s: Previously port %s was not "
+                               "configured as Bond port\n\r", __FUNCTION__,
+                               name);
+                       if (ifm_debug & IFM_DEBUG_LOCKS)
+                               RTE_LOG(INFO, IFM,
+                                       "%s: Releasing lock @ %d\n\r",
+                                       __FUNCTION__, __LINE__);
+                       if (USE_RTM_LOCKS)
+                               rtm_unlock();
+                       else
+                               rte_rwlock_write_unlock(&rwlock);
+                       return IFM_FAILURE;
+               }
+               if (bond_port->bond_config->mode != mode) {
+                       if (rte_eth_bond_mode_set(bond_port->pmdid, mode) < 0) {
+                               RTE_LOG(ERR, IFM, "%s: rte_eth_bond_mode_set "
+                                       "failed\n\r", __FUNCTION__);
+                               if (ifm_debug & IFM_DEBUG_LOCKS)
+                                       RTE_LOG(INFO, IFM,
+                                               "%s: Releasing lock @ %d\n\r",
+                                               __FUNCTION__, __LINE__);
+                               if (USE_RTM_LOCKS)
+                                       rtm_unlock();
+                               else
+                                       rte_rwlock_write_unlock(&rwlock);
+                               return IFM_FAILURE;
+                       }
+
+                       bond_port->bond_config->mode =
+                                       rte_eth_bond_mode_get(bond_port->pmdid);
+                       /* xmit policy may change for based on mode */
+                       bond_port->bond_config->xmit_policy =
+                                       rte_eth_bond_xmit_policy_get(bond_port->pmdid);
+                       if (ifm_debug && IFM_DEBUG_CONFIG)
+                               RTE_LOG(INFO, IFM,
+                                       "%s: Bond port %u mode is updated. Mode %u xmit_policy %u."
+                                       "\n\r", __FUNCTION__, bond_port->pmdid,
+                                       bond_port->bond_config->mode,
+                                       bond_port->bond_config->xmit_policy);
+               }
+               port_id = bond_port->pmdid;
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Acquiring lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS)
+                       rtm_unlock();
+               else
+                       rte_rwlock_write_unlock(&rwlock);
+       }
+       return port_id;
+}
+
+int ifm_bond_port_delete(const char *name)
+{
+       l2_phy_interface_t *bond_port;
+       if (name == NULL) {
+               RTE_LOG(ERR, IFM, "%s: Param name cannot be NULL\n\r",
+                       __FUNCTION__);
+               return IFM_FAILURE;
+       }
+       bond_port = ifm_get_port_by_name(name);
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Acquiring WR lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS)
+               rtm_lock();
+       else
+               rte_rwlock_write_lock(&rwlock);
+       if (bond_port == NULL) {
+               RTE_LOG(ERR, IFM, "%s: Given bond port with name %s not"
+                       " found in the list\n\r", __FUNCTION__, name);
+               return IFM_FAILURE;
+       }
+       if (!(bond_port->flags & IFM_MASTER)) {
+               RTE_LOG(ERR, IFM, "%s: Given bond port %s is not "
+                       "configured is not bond port\n\r", __FUNCTION__, name);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS) {
+                       rtm_unlock();
+               } else {
+                       rte_rwlock_write_unlock(&rwlock);
+               }
+               return IFM_FAILURE;
+       }
+       if (bond_port->bond_config && bond_port->bond_config->slave_count > 0) {
+               RTE_LOG(ERR, IFM, "%s: First unbind all slave "
+                       "ports from the bond port %s\n\r", __FUNCTION__, name);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS) {
+                       rtm_unlock();
+               } else {
+                       rte_rwlock_write_unlock(&rwlock);
+               }
+               return IFM_FAILURE;
+       }
+       int ret;
+       ret = rte_eth_bond_free(name);
+       if (ret < 0) {
+               RTE_LOG(ERR, IFM, "%s: Failed to delete "
+                       "bond port %s\n\r", __FUNCTION__, name);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS) {
+                       rtm_unlock();
+               } else {
+                       rte_rwlock_write_unlock(&rwlock);
+               }
+               return IFM_FAILURE;
+       }
+       if (ifm_debug & IFM_DEBUG_CONFIG)
+               RTE_LOG(INFO, IFM, "%s: Bond port %s deleted successfully\n\r",
+                       __FUNCTION__, name);
+
+       if (bond_port && bond_port->bond_config != NULL) {
+               rte_free(bond_port->bond_config);
+               bond_port->bond_config = NULL;
+       }
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS)
+               rtm_unlock();
+       else
+               rte_rwlock_write_unlock(&rwlock);
+       ifm_remove_port_details(bond_port->pmdid);
+       //ifm.port_list[bond_port->pmdid] = NULL;
+       return IFM_SUCCESS;
+}
+
+int ifm_add_slave_port(uint8_t bonded_port_id, uint8_t slave_port_id)
+{
+       l2_phy_interface_t *bond_port, *slave_port;
+       bond_port = ifm_get_port(bonded_port_id);
+       //   bond_port = ifm.port_list[bonded_port_id];
+       slave_port = ifm_get_port(slave_port_id);
+       // slave_port = ifm.port_list[slave_port_id];
+       if (ifm_debug & IFM_DEBUG)
+               RTE_LOG(INFO, IFM, "%s: i/p bond id %u, slave id %u\n\r",
+                       __FUNCTION__, bonded_port_id, slave_port_id);
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Acquiring WR lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS) {
+               rtm_lock();
+       } else {
+               rte_rwlock_write_lock(&rwlock);
+       }
+       if (bond_port == NULL) {
+               RTE_LOG(ERR, IFM, "%s: Given bond port %u is not available in"
+                       " port list.\n\r", __FUNCTION__, bonded_port_id);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS) {
+                       rtm_unlock();
+               } else {
+                       rte_rwlock_write_unlock(&rwlock);
+               }
+               return IFM_FAILURE;
+       }
+       if (slave_port == NULL) {
+               RTE_LOG(ERR, IFM, "%s: Given slave port %u is not available in "
+                       "port list.\n\r", __FUNCTION__, slave_port_id);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS) {
+                       rtm_unlock();
+               } else {
+                       rte_rwlock_write_unlock(&rwlock);
+               }
+               return IFM_FAILURE;
+       }
+       if (bond_port && !(bond_port->flags & IFM_MASTER)) {
+               RTE_LOG(ERR, IFM, "%s: Given bond port %u is not configured "
+                       "as Master port. %u\n\r", __FUNCTION__, bonded_port_id,
+                       bond_port->flags & IFM_MASTER);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS) {
+                       rtm_unlock();
+               } else {
+                       rte_rwlock_write_unlock(&rwlock);
+               }
+               return IFM_FAILURE;
+       }
+       if (bond_port && bond_port->bond_config
+                       && bond_port->bond_config->slave_count == RTE_MAX_ETHPORTS) {
+               RTE_LOG(ERR, IFM,
+                       "%s: Failed to bind.Already %u ports are bonded to master port...\n\r ",
+                       __FUNCTION__, RTE_MAX_ETHPORTS);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS) {
+                       rtm_unlock();
+               } else {
+                       rte_rwlock_write_unlock(&rwlock);
+               }
+               return IFM_FAILURE;
+       }
+       if (slave_port && slave_port->flags & IFM_SLAVE) {
+               /* Have to check whether the port is already part of someother bond port */
+               if (slave_port->bond_config != NULL) {
+                       if (bonded_port_id !=
+                                       slave_port->bond_config->bond_portid) {
+                               RTE_LOG(ERR, IFM,
+                                       "%s: Slave port %u is already part"
+                                       " of other bond port %u.\n\r",
+                                       __FUNCTION__, slave_port_id,
+                                       slave_port->bond_config->bond_portid);
+                               if (ifm_debug & IFM_DEBUG_LOCKS)
+                                       RTE_LOG(INFO, IFM,
+                                               "%s: Releasing WR lock @ %d\n\r",
+                                               __FUNCTION__, __LINE__);
+                               if (USE_RTM_LOCKS) {
+                                       rtm_unlock();
+                               } else {
+                                       rte_rwlock_write_unlock(&rwlock);
+                               }
+                               return IFM_FAILURE;
+                       } else {
+                               if (ifm_debug & IFM_DEBUG)
+                                       RTE_LOG(INFO, IFM,
+                                               "%s: Slave port %u is already bounded to %u\n\r",
+                                               __FUNCTION__, slave_port_id,
+                                               bonded_port_id);
+                               if (ifm_debug & IFM_DEBUG_LOCKS)
+                                       RTE_LOG(INFO, IFM,
+                                               "%s: Releasing WR lock @ %d\n\r",
+                                               __FUNCTION__, __LINE__);
+                               if (USE_RTM_LOCKS) {
+                                       rtm_unlock();
+                               } else {
+                                       rte_rwlock_write_unlock(&rwlock);
+                               }
+                               return IFM_SUCCESS;
+                       }
+               }
+       }
+       if (bond_port->bond_config && bond_port->bond_config->slave_count &&
+                       bond_port->link_speed != slave_port->link_speed
+                       && bond_port->link_duplex != slave_port->link_duplex) {
+               RTE_LOG(ERR, IFM,
+                       "%s: Error in adding slave port to bond port. Reason speed mismatch\n\r",
+                       __FUNCTION__);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS) {
+                       rtm_unlock();
+               } else {
+                       rte_rwlock_write_unlock(&rwlock);
+               }
+               return IFM_FAILURE;
+       }
+       if (ifm_debug & IFM_DEBUG)
+               RTE_LOG(INFO, IFM, "%s: Slave port %u Master port %u\n\r",
+                       __FUNCTION__, slave_port_id, bonded_port_id);
+       int ret;
+       ret = rte_eth_bond_slave_add(bond_port->pmdid, slave_port->pmdid);
+       if (ret < 0) {
+               RTE_LOG(ERR, IFM, "%s: Failed to add slave port %u to bond "
+                       "port %u.\n\r", __FUNCTION__, slave_port->pmdid,
+                       bond_port->pmdid);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS) {
+                       rtm_unlock();
+               } else {
+                       rte_rwlock_write_unlock(&rwlock);
+               }
+               return IFM_FAILURE;
+       }
+       slave_port->flags |= IFM_SLAVE;
+       /* Populate bond config information */
+       if (bond_port->bond_config) {
+               bond_port->bond_config->xmit_policy =
+                               rte_eth_bond_xmit_policy_get(bond_port->pmdid);
+               bond_port->bond_config->internal_ms =
+                               rte_eth_bond_link_monitoring_get(bond_port->pmdid);
+               bond_port->bond_config->link_up_delay_ms =
+                               rte_eth_bond_link_up_prop_delay_get(bond_port->pmdid);
+               bond_port->bond_config->link_down_delay_ms =
+                               rte_eth_bond_link_down_prop_delay_get(bond_port->pmdid);
+               bond_port->bond_config->primary =
+                               rte_eth_bond_primary_get(bond_port->pmdid);
+               bond_port->bond_config->slave_count =
+                               rte_eth_bond_slaves_get(bond_port->pmdid,
+                                                       bond_port->bond_config->slaves,
+                                                       RTE_MAX_ETHPORTS);
+               bond_port->bond_config->active_slave_count =
+                               rte_eth_bond_active_slaves_get(bond_port->pmdid,
+                                                        bond_port->bond_config->
+                                                        active_slaves,
+                                                        RTE_MAX_ETHPORTS);
+               slave_port->bond_config = bond_port->bond_config;
+               if (ifm_debug & IFM_DEBUG)
+                       RTE_LOG(INFO, IFM, "%s: Slave count is %u\n\r",
+                               __FUNCTION__,
+                               bond_port->bond_config->slave_count);
+               if (bond_port->bond_config->slave_count == 1) {
+                       ret =
+                                       ifm_port_setup(bond_port->pmdid,
+                                                &(bond_port->port_config));
+                       if (ret < 0) {
+                               RTE_LOG(ERR, IFM,
+                                       "%s: Failed to start bond port %u.\n\r",
+                                       __FUNCTION__, bond_port->pmdid);
+                               if (ifm_debug & IFM_DEBUG_LOCKS)
+                                       RTE_LOG(INFO, IFM,
+                                               "%s: Releasing WR lock @ %d\n\r",
+                                               __FUNCTION__, __LINE__);
+                               if (USE_RTM_LOCKS) {
+                                       rtm_unlock();
+                               } else {
+                                       rte_rwlock_write_unlock(&rwlock);
+                               }
+                               return IFM_FAILURE;
+                       }
+               } else {
+                       if (ifm_debug & IFM_DEBUG)
+                               RTE_LOG(INFO, IFM, "%s: Skipping"
+                                       " port setup\n\r", __FUNCTION__);
+               }
+       }
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS) {
+               rtm_unlock();
+       } else {
+               rte_rwlock_write_unlock(&rwlock);
+       }
+       return IFM_SUCCESS;
+}
+
+int ifm_remove_slave_port(uint8_t bonded_port_id, uint8_t slave_port_id)
+{
+       l2_phy_interface_t *bond_port, *slave_port;
+
+       bond_port = ifm_get_port(bonded_port_id);
+       //bond_port = ifm.port_list[bonded_port_id];
+       slave_port = ifm_get_port(slave_port_id);
+       //slave_port = ifm.port_list[slave_port_id];
+
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Acquiring WR lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS) {
+               rtm_lock();
+       } else {
+               rte_rwlock_write_lock(&rwlock);
+       }
+       if (bond_port == NULL) {
+               RTE_LOG(ERR, IFM, "%s: Given bond port %u is not available "
+                       "in port list.\n\r", __FUNCTION__, bonded_port_id);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS)
+                       rtm_unlock();
+               else
+                       rte_rwlock_write_unlock(&rwlock);
+               return IFM_FAILURE;
+       }
+       if (slave_port == NULL) {
+               RTE_LOG(ERR, IFM, "%s: Given slave port %u is not available "
+                       "in port list.\n\r", __FUNCTION__, slave_port_id);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS)
+                       rtm_unlock();
+               else
+                       rte_rwlock_write_unlock(&rwlock);
+               return IFM_FAILURE;
+       }
+       if (bond_port && !(bond_port->flags & IFM_MASTER)) {
+               RTE_LOG(ERR, IFM, "%s: Given bond port %u is not configured "
+                       "as Master port.\n\r", __FUNCTION__, bonded_port_id);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS)
+                       rtm_unlock();
+               else
+                       rte_rwlock_write_unlock(&rwlock);
+               return IFM_FAILURE;
+       }
+       if (slave_port && !(slave_port->flags & IFM_SLAVE)) {
+               RTE_LOG(ERR, IFM, "%s: Given slave port %u is not configured"
+                       " as slave port.\n\r", __FUNCTION__, slave_port_id);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS)
+                       rtm_unlock();
+               else
+                       rte_rwlock_write_unlock(&rwlock);
+               return IFM_FAILURE;
+       }
+       int i;
+       int found = 0;
+       for (i = 0; i < bond_port->bond_config->slave_count; i++) {
+               if (slave_port_id == bond_port->bond_config->slaves[i]) {
+                       found = 1;
+                       break;
+               }
+       }
+       if (!found) {
+               RTE_LOG(ERR, IFM, "%s: Given slave port %u is not binded "
+                       "with bond port %u\n\r", __FUNCTION__, slave_port_id,
+                       bonded_port_id);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS)
+                       rtm_unlock();
+               else
+                       rte_rwlock_write_unlock(&rwlock);
+               return IFM_FAILURE;
+       }
+       if (rte_eth_bond_slave_remove(bonded_port_id, slave_port_id) < 0) {
+               RTE_LOG(ERR, IFM, "%s: Failed to unbind slave port %u"
+                       " from bond port %u\n\r", __FUNCTION__, slave_port_id,
+                       bonded_port_id);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS)
+                       rtm_unlock();
+               else
+                       rte_rwlock_write_unlock(&rwlock);
+               return IFM_FAILURE;
+       }
+       slave_port->flags &= ~IFM_SLAVE;
+       slave_port->bond_config = NULL;
+       bond_port->bond_config->primary =
+                       rte_eth_bond_primary_get(bond_port->pmdid);
+       bond_port->bond_config->slave_count =
+                       rte_eth_bond_slaves_get(bond_port->pmdid,
+                                               bond_port->bond_config->slaves,
+                                               RTE_MAX_ETHPORTS);
+       bond_port->bond_config->active_slave_count =
+                       rte_eth_bond_active_slaves_get(bond_port->pmdid,
+                                                bond_port->bond_config->
+                                                active_slaves, RTE_MAX_ETHPORTS);
+
+       if (ifm_debug & IFM_DEBUG)
+               RTE_LOG(ERR, IFM, "%s: Unbinded slave port %u from the bond "
+                       "port %u %d\n\r", __FUNCTION__, slave_port_id,
+                       bonded_port_id,
+                       rte_eth_bond_primary_get(bond_port->pmdid));
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS)
+               rtm_unlock();
+       else
+               rte_rwlock_write_unlock(&rwlock);
+       return IFM_SUCCESS;
+}
+
+int set_bond_mode(uint8_t bonded_port_id, uint8_t mode)
+{
+       l2_phy_interface_t *bond_port;
+       bond_port = ifm_get_port(bonded_port_id);
+       //bond_port = ifm.port_list[bonded_port_id];
+
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Acquiring WR lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS)
+               rtm_lock();
+       else
+               rte_rwlock_write_lock(&rwlock);
+       if(bond_port)
+       ifm_remove_port_details(bond_port->pmdid);
+       if (bond_port == NULL) {
+               RTE_LOG(ERR, IFM, "%s: Given bond port %u is not available in"
+                       " port list.\n\r", __FUNCTION__, bonded_port_id);
+               return IFM_FAILURE;
+       }
+       if (bond_port && bond_port->bond_config->mode == mode) {
+               if (ifm_debug & IFM_DEBUG)
+                       RTE_LOG(INFO, IFM,
+                               "%s: Already bond port is set with the given"
+                               " mode %u\n\r.", __FUNCTION__, mode);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS)
+                       rtm_unlock();
+               else
+                       rte_rwlock_write_unlock(&rwlock);
+               ifm_remove_port_details(bond_port->pmdid);
+               return IFM_SUCCESS;
+
+       }
+       if (rte_eth_bond_mode_set(bond_port->pmdid, mode) < 0) {
+               RTE_LOG(ERR, IFM,
+                       "%s: Failed to set bond mode %u for port id %u\n\r.",
+                       __FUNCTION__, mode, bond_port->pmdid);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS)
+                       rtm_unlock();
+               else
+                       rte_rwlock_write_unlock(&rwlock);
+               ifm_remove_port_details(bond_port->pmdid);
+               return IFM_FAILURE;
+       }
+
+       bond_port->bond_config->mode = rte_eth_bond_mode_get(bond_port->pmdid);
+       /* xmit policy may change for based on mode */
+       bond_port->bond_config->xmit_policy =
+                       rte_eth_bond_xmit_policy_get(bond_port->pmdid);
+       if (ifm_debug & IFM_DEBUG)
+               RTE_LOG(INFO, IFM,
+                       "%s: Bond port %u mode is updated. Mode %u xmit_policy %u."
+                       "\n\r.", __FUNCTION__, bond_port->pmdid,
+                       bond_port->bond_config->mode,
+                       bond_port->bond_config->xmit_policy);
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS)
+               rtm_unlock();
+       else
+               rte_rwlock_write_unlock(&rwlock);
+       ifm_remove_port_details(bond_port->pmdid);
+       return IFM_SUCCESS;
+}
+
+int get_bond_mode(uint8_t bonded_port_id)
+{
+       l2_phy_interface_t *bond_port;
+       bond_port = ifm_get_port(bonded_port_id);
+       //bond_port = ifm.port_list[bonded_port_id];
+
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Acquiring RD lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS) {
+               rtm_lock();
+       } else {
+               rte_rwlock_read_lock(&rwlock);
+       }
+       if (bond_port == NULL) {
+               RTE_LOG(ERR, IFM, "%s: Given bond port %u is not available in"
+                       " port list.\n\r", __FUNCTION__, bonded_port_id);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing RD lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS) {
+                       rtm_unlock();
+               } else {
+                       rte_rwlock_read_unlock(&rwlock);
+               }
+               return IFM_FAILURE;
+       }
+       uint8_t mode = bond_port->bond_config->mode;
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Releasing RD lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS) {
+               rtm_unlock();
+       } else {
+               rte_rwlock_read_unlock(&rwlock);
+       }
+       return mode;
+}
+
+int set_bond_primary(uint8_t bonded_port_id, uint8_t slave_port_id)
+{
+       l2_phy_interface_t *bond_port;
+       l2_phy_interface_t *slave_port;
+       bond_port = ifm_get_port(bonded_port_id);
+       //  bond_port = ifm.port_list[bonded_port_id];
+       slave_port = ifm_get_port(slave_port_id);
+       //  slave_port = ifm.port_list[slave_port_id];
+
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Acquiring WR lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS)
+               rtm_lock();
+       else
+               rte_rwlock_write_lock(&rwlock);
+       if (bond_port == NULL) {
+               RTE_LOG(ERR, IFM, "%s: Given bond port %u is not available in"
+                       " port list.\n\r", __FUNCTION__, bonded_port_id);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS)
+                       rtm_unlock();
+               else
+                       rte_rwlock_write_unlock(&rwlock);
+               return IFM_FAILURE;
+       }
+       if (slave_port == NULL) {
+               RTE_LOG(ERR, IFM, "%s: Given slave port %u is not available in"
+                       " port list.\n\r", __FUNCTION__, bonded_port_id);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS)
+                       rtm_unlock();
+               else
+                       rte_rwlock_write_unlock(&rwlock);
+               return IFM_FAILURE;
+       }
+       int i;
+       int found = 0;
+       for (i = 0; i < bond_port->bond_config->slave_count; i++) {
+               if (slave_port_id == bond_port->bond_config->slaves[i]) {
+                       found = 1;
+                       break;
+               }
+       }
+       if (!found) {
+               RTE_LOG(ERR, IFM, "%s: Slave port %u is not binded "
+                       "with bond port %u. Slave port should be binded first\n\r",
+                       __FUNCTION__, slave_port_id, bonded_port_id);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS)
+                       rtm_unlock();
+               else
+                       rte_rwlock_write_unlock(&rwlock);
+               return IFM_FAILURE;
+       }
+
+       if (bond_port->bond_config->primary == slave_port_id) {
+               if (ifm_debug & IFM_DEBUG)
+                       RTE_LOG(INFO, IFM,
+                               "%s: Already slave port %u is primary for bond port"
+                               "%u\n\r.", __FUNCTION__, bonded_port_id,
+                               slave_port_id);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS)
+                       rtm_unlock();
+               else
+                       rte_rwlock_write_unlock(&rwlock);
+               return IFM_SUCCESS;
+
+       }
+       if (rte_eth_bond_primary_set(bond_port->pmdid, slave_port->pmdid) < 0) {
+               RTE_LOG(ERR, IFM,
+                       "%s:Failed to set slave %u as primary for bond port %u\n\r.",
+                       __FUNCTION__, slave_port->pmdid, bond_port->pmdid);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS)
+                       rtm_unlock();
+               else
+                       rte_rwlock_write_unlock(&rwlock);
+               return IFM_FAILURE;
+       }
+
+       bond_port->bond_config->primary =
+                       rte_eth_bond_primary_get(bond_port->pmdid);
+       if (ifm_debug & IFM_DEBUG)
+               RTE_LOG(INFO, IFM,
+                       "%s: Primary port is updated as %u for bond port %u",
+                       __FUNCTION__, bond_port->bond_config->primary,
+                       bond_port->pmdid);
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS)
+               rtm_unlock();
+       else
+               rte_rwlock_write_unlock(&rwlock);
+       return IFM_SUCCESS;
+}
+
+int get_bond_primary_port(uint8_t bonded_port_id)
+{
+       l2_phy_interface_t *bond_port;
+       bond_port = ifm_get_port(bonded_port_id);
+       //bond_port = ifm.port_list[bonded_port_id];
+
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Acquiring RD lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS) {
+               rtm_lock();
+       } else {
+               rte_rwlock_read_lock(&rwlock);
+       }
+       if (bond_port == NULL) {
+               RTE_LOG(ERR, IFM, "%s: Given bond port %u is not available in"
+                       " port list.\n\r", __FUNCTION__, bonded_port_id);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing RD lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS) {
+                       rtm_unlock();
+               } else {
+                       rte_rwlock_read_unlock(&rwlock);
+               }
+               return IFM_FAILURE;
+       }
+       uint8_t primary = bond_port->bond_config->primary;
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Releasing RD lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS) {
+               rtm_unlock();
+       } else {
+               rte_rwlock_read_unlock(&rwlock);
+       }
+       return primary;
+}
+
+int get_bond_slave_count(uint8_t bonded_port_id)
+{
+       l2_phy_interface_t *bond_port;
+       bond_port = ifm_get_port(bonded_port_id);
+       // bond_port = ifm.port_list[bonded_port_id];
+
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Acquiring RD lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS) {
+               rtm_lock();
+       } else {
+               rte_rwlock_read_lock(&rwlock);
+       }
+       if (bond_port == NULL) {
+               RTE_LOG(ERR, IFM, "%s: Given bond port %u is not available in"
+                       " port list.\n\r", __FUNCTION__, bonded_port_id);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing RD lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS) {
+                       rtm_unlock();
+               } else {
+                       rte_rwlock_read_unlock(&rwlock);
+               }
+               return IFM_FAILURE;
+       }
+       uint32_t slave_count = bond_port->bond_config->slave_count;
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Releasing RD lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS) {
+               rtm_unlock();
+       } else {
+               rte_rwlock_read_unlock(&rwlock);
+       }
+       return slave_count;
+}
+
+int get_bond_active_slave_count(uint8_t bonded_port_id)
+{
+       l2_phy_interface_t *bond_port;
+       bond_port = ifm_get_port(bonded_port_id);
+       //bond_port = ifm.port_list[bonded_port_id];
+
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Acquiring RD lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS) {
+               rtm_lock();
+       } else {
+               rte_rwlock_read_lock(&rwlock);
+       }
+       if (bond_port == NULL) {
+               RTE_LOG(ERR, IFM, "%s: Given bond port %u is not available in"
+                       " port list.\n\r", __FUNCTION__, bonded_port_id);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing RD lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS) {
+                       rtm_unlock();
+               } else {
+                       rte_rwlock_read_unlock(&rwlock);
+               }
+               return IFM_FAILURE;
+       }
+       uint32_t slave_count = bond_port->bond_config->active_slave_count;
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Releasing RD lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS) {
+               rtm_unlock();
+       } else {
+               rte_rwlock_read_unlock(&rwlock);
+       }
+       return slave_count;
+}
+
+int get_bond_slaves(uint8_t bonded_port_id, uint8_t slaves[RTE_MAX_ETHPORTS])
+{
+       l2_phy_interface_t *bond_port;
+       bond_port = ifm_get_port(bonded_port_id);
+       //bond_port = ifm.port_list[bonded_port_id];
+
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Acquiring RD lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS) {
+               rtm_lock();
+       } else {
+               rte_rwlock_read_lock(&rwlock);
+       }
+       if (bond_port == NULL) {
+               RTE_LOG(ERR, IFM, "%s: Given bond port %u is not available in"
+                       " port list.\n\r", __FUNCTION__, bonded_port_id);
+               return IFM_FAILURE;
+       }
+       memcpy(slaves, bond_port->bond_config->slaves,
+                                bond_port->bond_config->slave_count);
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Releasing RD lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS) {
+               rtm_unlock();
+       } else {
+               rte_rwlock_read_unlock(&rwlock);
+       }
+       return IFM_SUCCESS;
+}
+
+int get_bond_active_slaves(uint8_t bonded_port_id,
+                                uint8_t active_slaves[RTE_MAX_ETHPORTS])
+{
+       l2_phy_interface_t *bond_port;
+       bond_port = ifm_get_port(bonded_port_id);
+       //bond_port = ifm.port_list[bonded_port_id];
+
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Acquiring RD lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS) {
+               rtm_lock();
+       } else {
+               rte_rwlock_read_lock(&rwlock);
+       }
+       if (bond_port == NULL) {
+               RTE_LOG(ERR, IFM, "%s: Given bond port %u is not available in"
+                       " port list.\n\r", __FUNCTION__, bonded_port_id);
+               return IFM_FAILURE;
+       }
+       memcpy(active_slaves, bond_port->bond_config->active_slaves,
+                                bond_port->bond_config->active_slave_count);
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Releasing RD lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS) {
+               rtm_unlock();
+       } else {
+               rte_rwlock_read_unlock(&rwlock);
+       }
+       return IFM_SUCCESS;
+}
+
+int set_bond_mac_address(uint8_t bonded_port_id, struct ether_addr *mac_addr)
+{
+       l2_phy_interface_t *bond_port;
+       bond_port = ifm_get_port(bonded_port_id);
+       //bond_port = ifm.port_list[bonded_port_id];
+
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Acquiring WR lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS) {
+               rtm_lock();
+       } else {
+               rte_rwlock_write_lock(&rwlock);
+       }
+       if (mac_addr == NULL) {
+               RTE_LOG(ERR, IFM, "%s: MAC address cannot be NULL.\n\r",
+                       __FUNCTION__);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS) {
+                       rtm_unlock();
+               } else {
+                       rte_rwlock_write_unlock(&rwlock);
+               }
+               return IFM_FAILURE;
+       }
+
+       if (bond_port == NULL) {
+               RTE_LOG(ERR, IFM, "%s: Given bond port %u is not available in"
+                       " port list.\n\r", __FUNCTION__, bonded_port_id);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS) {
+                       rtm_unlock();
+               } else {
+                       rte_rwlock_write_unlock(&rwlock);
+               }
+               return IFM_FAILURE;
+       }
+       if (rte_eth_bond_mac_address_set(bond_port->pmdid, mac_addr) < 0) {
+               RTE_LOG(ERR, IFM, "%s: Failed to set MAC addr for port %u\n\r",
+                       __FUNCTION__, bond_port->pmdid);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS) {
+                       rtm_unlock();
+               } else {
+                       rte_rwlock_write_unlock(&rwlock);
+               }
+               return IFM_FAILURE;
+       }
+       rte_eth_macaddr_get(bond_port->pmdid,
+                                       (struct ether_addr *)bond_port->macaddr);
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS) {
+               rtm_unlock();
+       } else {
+               rte_rwlock_write_unlock(&rwlock);
+       }
+       return IFM_SUCCESS;
+}
+
+int reset_bond_mac_addr(uint8_t bonded_port_id)
+{
+       l2_phy_interface_t *bond_port;
+       bond_port = ifm_get_port(bonded_port_id);
+       //   bond_port = ifm.port_list[bonded_port_id];
+
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Acquiring WR lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS) {
+               rtm_lock();
+       } else {
+               rte_rwlock_write_lock(&rwlock);
+       }
+       if (bond_port == NULL) {
+               RTE_LOG(ERR, IFM, "%s: Given bond port %u is not available in"
+                       " port list.\n\r", __FUNCTION__, bonded_port_id);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS) {
+                       rtm_unlock();
+               } else {
+                       rte_rwlock_write_unlock(&rwlock);
+               }
+               return IFM_FAILURE;
+       }
+       if (rte_eth_bond_mac_address_reset(bond_port->pmdid) < 0) {
+               RTE_LOG(ERR, IFM,
+                       "%s: Failed to reset MAC addr for port %u\n\r",
+                       __FUNCTION__, bond_port->pmdid);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS) {
+                       rtm_unlock();
+               } else {
+                       rte_rwlock_write_unlock(&rwlock);
+               }
+               return IFM_FAILURE;
+       }
+       rte_eth_macaddr_get(bond_port->pmdid,
+                                       (struct ether_addr *)bond_port->macaddr);
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS) {
+               rtm_unlock();
+       } else {
+               rte_rwlock_write_unlock(&rwlock);
+       }
+       return IFM_FAILURE;
+}
+
+int set_bond_xmitpolicy(uint8_t bonded_port_id, uint8_t policy)
+{
+
+       l2_phy_interface_t *bond_port;
+       bond_port = ifm_get_port(bonded_port_id);
+       //bond_port = ifm.port_list[bonded_port_id];
+       int ret = 0;
+
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Acquiring WR lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS) {
+               rtm_lock();
+       } else {
+               rte_rwlock_write_lock(&rwlock);
+       }
+       if (bond_port == NULL) {
+               RTE_LOG(ERR, IFM, "%s: Given bond port %u is not available in"
+                       " port list.\n\r", __FUNCTION__, bonded_port_id);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS) {
+                       rtm_unlock();
+               } else {
+                       rte_rwlock_write_unlock(&rwlock);
+               }
+               return IFM_FAILURE;
+       }
+       if (bond_port->bond_config->xmit_policy == policy) {
+               if (ifm_debug & IFM_DEBUG)
+                       RTE_LOG(INFO, IFM,
+                               "%s: For port %u, old policy value and new value are same\n\r",
+                               __FUNCTION__, bonded_port_id);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS) {
+                       rtm_unlock();
+               } else {
+                       rte_rwlock_write_unlock(&rwlock);
+               }
+               return IFM_SUCCESS;
+       }
+       if (rte_eth_bond_xmit_policy_set(bond_port->pmdid, policy) < 0) {
+               RTE_LOG(ERR, IFM, "%s: Failed to set policy for port %u\n\r",
+                       __FUNCTION__, bond_port->pmdid);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS) {
+                       rtm_unlock();
+               } else {
+                       rte_rwlock_write_unlock(&rwlock);
+               }
+               return IFM_FAILURE;
+       }
+       ret = rte_eth_bond_xmit_policy_get(bond_port->pmdid);
+       if (ret < 0) {
+               if (ifm_debug & IFM_DEBUG)
+                       RTE_LOG(INFO, IFM,
+                               "%s: rte_eth_bond_xmit_policy_set failed\n\r",
+                               __FUNCTION__);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS) {
+                       rtm_unlock();
+               } else {
+                       rte_rwlock_write_unlock(&rwlock);
+               }
+               return IFM_FAILURE;
+       }
+       bond_port->bond_config->xmit_policy = policy;
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS) {
+               rtm_unlock();
+       } else {
+               rte_rwlock_write_unlock(&rwlock);
+       }
+       return IFM_SUCCESS;
+}
+
+int get_bond_xmitpolicy(uint8_t bonded_port_id)
+{
+       l2_phy_interface_t *bond_port;
+
+       bond_port = ifm_get_port(bonded_port_id);
+
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: RD Acquiring lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS) {
+               rtm_lock();
+       } else {
+               rte_rwlock_read_lock(&rwlock);
+       }
+       if (bond_port == NULL) {
+               RTE_LOG(ERR, IFM, "%s: Given bond port %u is not available in"
+                       " port list.\n\r", __FUNCTION__, bonded_port_id);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s:Releasing RD lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS) {
+                       rtm_unlock();
+               } else {
+                       rte_rwlock_read_unlock(&rwlock);
+               }
+               return IFM_FAILURE;
+       }
+       uint8_t policy = bond_port->bond_config->xmit_policy;
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s:Releasing RD lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS) {
+               rtm_unlock();
+       } else {
+               rte_rwlock_read_unlock(&rwlock);
+       }
+       return policy;
+}
+
+int set_bond_link_montitor_frequency(uint8_t bonded_port_id,
+                                                uint32_t internal_ms)
+{
+       l2_phy_interface_t *bond_port;
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Acquiring WR lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS) {
+               rtm_lock();
+       } else {
+               rte_rwlock_write_lock(&rwlock);
+       }
+//      bond_port = ifm.port_list[bonded_port_id];
+       bond_port = ifm_get_port(bonded_port_id);
+       int ret = 0;
+
+       if (bond_port == NULL) {
+               RTE_LOG(ERR, IFM, "%s: Given bond port %u is not available in"
+                       " port list.\n\r", __FUNCTION__, bonded_port_id);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS) {
+                       rtm_unlock();
+               } else {
+                       rte_rwlock_write_unlock(&rwlock);
+               }
+               return IFM_FAILURE;
+       }
+       if (bond_port->bond_config->internal_ms == internal_ms) {
+               if (ifm_debug & IFM_DEBUG)
+                       RTE_LOG(INFO, IFM,
+                               "%s: For port %u, old frequency value and new value are same\n\r",
+                               __FUNCTION__, bonded_port_id);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS) {
+                       rtm_unlock();
+               } else {
+                       rte_rwlock_write_unlock(&rwlock);
+               }
+               return IFM_SUCCESS;
+       }
+       if (rte_eth_bond_link_monitoring_set(bond_port->pmdid, internal_ms) < 0) {
+               RTE_LOG(ERR, IFM,
+                       "%s: Failed to set link monitor frequency for port %u\n\r",
+                       __FUNCTION__, bond_port->pmdid);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS) {
+                       rtm_unlock();
+               } else {
+                       rte_rwlock_write_unlock(&rwlock);
+               }
+               return IFM_FAILURE;
+       }
+       ret = rte_eth_bond_link_monitoring_get(bond_port->pmdid);
+       if (ret < 0) {
+               if (ifm_debug & IFM_DEBUG)
+                       RTE_LOG(INFO, IFM,
+                               "%s: rte_eth_bond_link_monitoring_get failed\n\r",
+                               __FUNCTION__);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS) {
+                       rtm_unlock();
+               } else {
+                       rte_rwlock_write_unlock(&rwlock);
+               }
+               return IFM_FAILURE;
+       }
+       bond_port->bond_config->internal_ms = internal_ms;
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS) {
+               rtm_unlock();
+       } else {
+               rte_rwlock_write_unlock(&rwlock);
+       }
+       return IFM_SUCCESS;
+}
+
+int get_bond_link_monitor_frequency(uint8_t bonded_port_id)
+{
+       l2_phy_interface_t *bond_port;
+//      bond_port = ifm.port_list[bonded_port_id];
+       bond_port = ifm_get_port(bonded_port_id);
+
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s:  Acquiring RD lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS) {
+               rtm_lock();
+       } else {
+               rte_rwlock_read_lock(&rwlock);
+       }
+       if (bond_port == NULL) {
+               RTE_LOG(ERR, IFM, "%s: Given bond port %u is not available in"
+                       " port list.\n\r", __FUNCTION__, bonded_port_id);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing RD lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS) {
+                       rtm_unlock();
+               } else {
+                       rte_rwlock_read_unlock(&rwlock);
+               }
+               return IFM_FAILURE;
+       }
+       uint32_t internal_ms = bond_port->bond_config->internal_ms;
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Releasing RD lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS) {
+               rtm_unlock();
+       } else {
+               rte_rwlock_read_unlock(&rwlock);
+       }
+       return internal_ms;
+}
+
+int set_bond_linkdown_delay(uint8_t bonded_port_id, uint32_t delay_ms)
+{
+       l2_phy_interface_t *bond_port;
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Acquiring WR lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+
+       if (USE_RTM_LOCKS) {
+               rtm_lock();
+       } else {
+               rte_rwlock_write_lock(&rwlock);
+       }
+//      bond_port = ifm.port_list[bonded_port_id];
+       bond_port = ifm_get_port(bonded_port_id);
+       int delay = 0;
+
+       if (bond_port == NULL) {
+               RTE_LOG(ERR, IFM, "%s: Given bond port %u is not available in"
+                       " port list.\n\r", __FUNCTION__, bonded_port_id);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+
+               if (USE_RTM_LOCKS) {
+                       rtm_unlock();
+               } else {
+                       rte_rwlock_write_unlock(&rwlock);
+               }
+               return IFM_FAILURE;
+       }
+       if (bond_port->bond_config->link_down_delay_ms == delay_ms) {
+               if (ifm_debug & IFM_DEBUG)
+                       RTE_LOG(INFO, IFM,
+                               "%s: For port %u, old delay value and new value are same\n\r",
+                               __FUNCTION__, bonded_port_id);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+
+               if (USE_RTM_LOCKS) {
+                       rtm_unlock();
+               } else {
+                       rte_rwlock_write_unlock(&rwlock);
+               }
+               return IFM_SUCCESS;
+       }
+       if (rte_eth_bond_link_down_prop_delay_set(bond_port->pmdid, delay_ms) <
+                       0) {
+               RTE_LOG(ERR, IFM, "%s: Failed to set delay for port %u\n\r",
+                       __FUNCTION__, bond_port->pmdid);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+
+               if (USE_RTM_LOCKS) {
+                       rtm_unlock();
+               } else {
+                       rte_rwlock_write_unlock(&rwlock);
+               }
+               return IFM_FAILURE;
+       }
+       delay = rte_eth_bond_link_down_prop_delay_get(bond_port->pmdid);
+       if (delay < 0) {
+               if (ifm_debug & IFM_DEBUG)
+                       RTE_LOG(INFO, IFM,
+                               "%s: rte_eth_bond_link_down_prop_delay_get failed\n\r",
+                               __FUNCTION__);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+
+               if (USE_RTM_LOCKS) {
+                       rtm_unlock();
+               } else {
+                       rte_rwlock_write_unlock(&rwlock);
+               }
+               return IFM_FAILURE;
+       }
+       bond_port->bond_config->link_down_delay_ms = delay;
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+
+       if (USE_RTM_LOCKS) {
+               rtm_unlock();
+       } else {
+               rte_rwlock_write_unlock(&rwlock);
+       }
+       return IFM_SUCCESS;
+}
+
+int get_bond_link_down_delay(uint8_t bonded_port_id)
+{
+       l2_phy_interface_t *bond_port;
+       //bond_port = ifm.port_list[bonded_port_id];
+       bond_port = ifm_get_port(bonded_port_id);
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Acquiring RD lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS)
+               rtm_lock();
+       else
+               rte_rwlock_read_lock(&rwlock);
+
+       if (bond_port == NULL) {
+               RTE_LOG(ERR, IFM, "%s: Given bond port %u is not available in"
+                       " port list.\n\r", __FUNCTION__, bonded_port_id);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing RD lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS) {
+                       rtm_unlock();
+               } else {
+                       rte_rwlock_read_unlock(&rwlock);
+               }
+               return IFM_FAILURE;
+       }
+       uint32_t delay_ms = bond_port->bond_config->link_down_delay_ms;
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Releasing RD lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS) {
+               rtm_unlock();
+       } else {
+               rte_rwlock_read_unlock(&rwlock);
+       }
+       return delay_ms;
+
+}
+
+int set_bond_linkup_delay(uint8_t bonded_port_id, uint32_t delay_ms)
+{
+       l2_phy_interface_t *bond_port;
+       int delay = 0;
+       bond_port = ifm_get_port(bonded_port_id);
+
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Acquiring WR lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS)
+               rtm_unlock();
+       else
+               rte_rwlock_write_unlock(&rwlock);
+
+       if (bond_port == NULL) {
+               RTE_LOG(ERR, IFM, "%s: Given bond port %u is not available in"
+                       " port list.\n\r", __FUNCTION__, bonded_port_id);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS)
+                       rtm_unlock();
+               else
+                       rte_rwlock_write_unlock(&rwlock);
+               return IFM_FAILURE;
+       }
+       if (bond_port->bond_config->link_up_delay_ms == delay_ms) {
+               if (ifm_debug & IFM_DEBUG)
+                       RTE_LOG(INFO, IFM,
+                               "%s: For port %u, old delay value and new value are same\n\r",
+                               __FUNCTION__, bonded_port_id);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS)
+                       rtm_unlock();
+               else
+                       rte_rwlock_write_unlock(&rwlock);
+               return IFM_SUCCESS;
+       }
+       if (rte_eth_bond_link_up_prop_delay_set(bond_port->pmdid, delay_ms) < 0) {
+               RTE_LOG(ERR, IFM, "%s: Failed to set delay for port %u\n\r",
+                       __FUNCTION__, bond_port->pmdid);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+
+               if (USE_RTM_LOCKS)
+                       rtm_unlock();
+               else
+                       rte_rwlock_write_unlock(&rwlock);
+               return IFM_FAILURE;
+       }
+       delay = rte_eth_bond_link_up_prop_delay_get(bond_port->pmdid);
+       if (delay < 0) {
+               RTE_LOG(INFO, IFM,
+                       "%s: rte_eth_bond_link_up_prop_delay_get failed\n\r",
+                       __FUNCTION__);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+
+               if (USE_RTM_LOCKS)
+                       rtm_unlock();
+               else
+                       rte_rwlock_write_unlock(&rwlock);
+               return IFM_FAILURE;
+       }
+       bond_port->bond_config->link_up_delay_ms = delay;
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+
+       if (USE_RTM_LOCKS)
+               rtm_unlock();
+       else
+               rte_rwlock_write_unlock(&rwlock);
+       return IFM_SUCCESS;
+}
+
+int get_bond_link_up_delay(uint8_t bonded_port_id)
+{
+       l2_phy_interface_t *bond_port;
+       uint32_t delay_ms;
+
+       bond_port = ifm_get_port(bonded_port_id);
+
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Acquiring RD lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS)
+               rtm_lock();
+       else
+               rte_rwlock_read_lock(&rwlock);
+       if (bond_port == NULL) {
+               if (ifm_debug & IFM_DEBUG) {
+                       RTE_LOG(ERR, IFM,
+                               "%s: Given bond port %u is not available in"
+                               " port list.\n\r", __FUNCTION__,
+                               bonded_port_id);
+               }
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing RD lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS)
+                       rtm_unlock();
+               else
+                       rte_rwlock_read_unlock(&rwlock);
+               return IFM_FAILURE;
+       }
+       delay_ms = bond_port->bond_config->link_up_delay_ms;
+
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Releasing RD lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS)
+               rtm_unlock();
+       else
+               rte_rwlock_read_unlock(&rwlock);
+       return delay_ms;
+}
diff --git a/common/VIL/l2l3_stack/build/.interface.o.d b/common/VIL/l2l3_stack/build/.interface.o.d
new file mode 100644 (file)
index 0000000..582958f
--- /dev/null
@@ -0,0 +1,180 @@
+dep_interface.o = \
+ /home/ubuntu/feb_cgnat/csig_sdnd_benchmarking-industrial_standard_benchmarking/common/VIL/l2l3_stack/interface.c \
+ /usr/include/stdc-predef.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_config.h \
+ /home/ubuntu/feb_cgnat/csig_sdnd_benchmarking-industrial_standard_benchmarking/common/VIL/l2l3_stack/interface.h \
+ /usr/include/stdio.h /usr/include/features.h \
+ /usr/include/x86_64-linux-gnu/sys/cdefs.h \
+ /usr/include/x86_64-linux-gnu/bits/wordsize.h \
+ /usr/include/x86_64-linux-gnu/gnu/stubs.h \
+ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h \
+ /usr/include/x86_64-linux-gnu/bits/types.h \
+ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/libio.h \
+ /usr/include/_G_config.h /usr/include/wchar.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \
+ /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \
+ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/stdlib.h \
+ /usr/include/x86_64-linux-gnu/bits/waitflags.h \
+ /usr/include/x86_64-linux-gnu/bits/waitstatus.h /usr/include/endian.h \
+ /usr/include/x86_64-linux-gnu/bits/endian.h \
+ /usr/include/x86_64-linux-gnu/bits/byteswap.h \
+ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \
+ /usr/include/x86_64-linux-gnu/sys/types.h /usr/include/time.h \
+ /usr/include/x86_64-linux-gnu/sys/select.h \
+ /usr/include/x86_64-linux-gnu/bits/select.h \
+ /usr/include/x86_64-linux-gnu/bits/sigset.h \
+ /usr/include/x86_64-linux-gnu/bits/time.h \
+ /usr/include/x86_64-linux-gnu/sys/sysmacros.h \
+ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h /usr/include/alloca.h \
+ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/string.h \
+ /usr/include/xlocale.h /usr/lib/gcc/x86_64-linux-gnu/5/include/stdint.h \
+ /usr/include/stdint.h /usr/include/x86_64-linux-gnu/bits/wchar.h \
+ /usr/include/inttypes.h /usr/include/x86_64-linux-gnu/sys/queue.h \
+ /usr/include/netinet/in.h /usr/include/x86_64-linux-gnu/sys/socket.h \
+ /usr/include/x86_64-linux-gnu/sys/uio.h \
+ /usr/include/x86_64-linux-gnu/bits/uio.h \
+ /usr/include/x86_64-linux-gnu/bits/socket.h \
+ /usr/include/x86_64-linux-gnu/bits/socket_type.h \
+ /usr/include/x86_64-linux-gnu/bits/sockaddr.h \
+ /usr/include/x86_64-linux-gnu/asm/socket.h \
+ /usr/include/asm-generic/socket.h \
+ /usr/include/x86_64-linux-gnu/asm/sockios.h \
+ /usr/include/asm-generic/sockios.h \
+ /usr/include/x86_64-linux-gnu/bits/in.h /usr/include/setjmp.h \
+ /usr/include/x86_64-linux-gnu/bits/setjmp.h /usr/include/ctype.h \
+ /usr/include/errno.h /usr/include/x86_64-linux-gnu/bits/errno.h \
+ /usr/include/linux/errno.h /usr/include/x86_64-linux-gnu/asm/errno.h \
+ /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h \
+ /usr/include/getopt.h /usr/include/signal.h \
+ /usr/include/x86_64-linux-gnu/bits/signum.h \
+ /usr/include/x86_64-linux-gnu/bits/siginfo.h \
+ /usr/include/x86_64-linux-gnu/bits/sigaction.h \
+ /usr/include/x86_64-linux-gnu/bits/sigcontext.h \
+ /usr/include/x86_64-linux-gnu/bits/sigstack.h \
+ /usr/include/x86_64-linux-gnu/sys/ucontext.h \
+ /usr/include/x86_64-linux-gnu/bits/sigthread.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdbool.h \
+ /usr/include/arpa/inet.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_common.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include-fixed/limits.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include-fixed/syslimits.h \
+ /usr/include/limits.h /usr/include/x86_64-linux-gnu/bits/posix1_lim.h \
+ /usr/include/x86_64-linux-gnu/bits/local_lim.h \
+ /usr/include/linux/limits.h \
+ /usr/include/x86_64-linux-gnu/bits/posix2_lim.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/emmintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/xmmintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/mmintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/mm_malloc.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_log.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_common.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_malloc.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_memory.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/exec-env/rte_dom0_common.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_memcpy.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_vect.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/x86intrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/ia32intrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/pmmintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/tmmintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/ammintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/smmintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/popcntintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/wmmintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/immintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avxintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx2intrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx512fintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx512erintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx512pfintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx512cdintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx512vlintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx512bwintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx512dqintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx512vlbwintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx512vldqintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx512ifmaintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx512ifmavlintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx512vbmiintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx512vbmivlintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/shaintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/lzcntintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/bmiintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/bmi2intrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/fmaintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/f16cintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/rtmintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/xtestintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/mm3dnow.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/prfchwintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/fma4intrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/xopintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/lwpintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/tbmintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/rdseedintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/fxsrintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/xsaveintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/xsaveoptintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/adxintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/clwbintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/pcommitintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/clflushoptintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/xsavesintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/xsavecintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/mwaitxintrin.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_memzone.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_eal.h \
+ /usr/include/sched.h /usr/include/x86_64-linux-gnu/bits/sched.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_per_lcore.h \
+ /usr/include/pthread.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_launch.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_atomic.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/generic/rte_atomic.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_atomic_64.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_cycles.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/generic/rte_cycles.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_debug.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_log.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_branch_prediction.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_branch_prediction.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_prefetch.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/generic/rte_prefetch.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_lcore.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_interrupts.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/exec-env/rte_interrupts.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_pci.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_random.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_ether.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_mbuf.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_mempool.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_spinlock.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/generic/rte_spinlock.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_rtm.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_cpuflags.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/generic/rte_cpuflags.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_ring.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_byteorder.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/generic/rte_byteorder.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_byteorder_64.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_ethdev.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_dev.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_devargs.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_ether.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_eth_ctrl.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_dev_info.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_eth_ctrl.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_errno.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_port_ethdev.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_port.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_eth_bond.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_rwlock.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/generic/rte_rwlock.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_spinlock.h \
+ /home/ubuntu/feb_cgnat/csig_sdnd_benchmarking-industrial_standard_benchmarking/common/VIL/l2l3_stack/lib_arp.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_pipeline.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_port.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_table.h \
+ /home/ubuntu/feb_cgnat/csig_sdnd_benchmarking-industrial_standard_benchmarking/common/VIL/l2l3_stack/l2_proto.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_ip.h \
+ /home/ubuntu/feb_cgnat/csig_sdnd_benchmarking-industrial_standard_benchmarking/common/VIL/l2l3_stack/tsx.h
diff --git a/common/VIL/l2l3_stack/build/.l2_proto.o.d b/common/VIL/l2l3_stack/build/.l2_proto.o.d
new file mode 100644 (file)
index 0000000..13bcf50
--- /dev/null
@@ -0,0 +1,175 @@
+dep_l2_proto.o = \
+ /home/ubuntu/feb_cgnat/csig_sdnd_benchmarking-industrial_standard_benchmarking/common/VIL/l2l3_stack/l2_proto.c \
+ /usr/include/stdc-predef.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_config.h \
+ /home/ubuntu/feb_cgnat/csig_sdnd_benchmarking-industrial_standard_benchmarking/common/VIL/l2l3_stack/l2_proto.h \
+ /usr/include/stdio.h /usr/include/features.h \
+ /usr/include/x86_64-linux-gnu/sys/cdefs.h \
+ /usr/include/x86_64-linux-gnu/bits/wordsize.h \
+ /usr/include/x86_64-linux-gnu/gnu/stubs.h \
+ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h \
+ /usr/include/x86_64-linux-gnu/bits/types.h \
+ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/libio.h \
+ /usr/include/_G_config.h /usr/include/wchar.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \
+ /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \
+ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/stdlib.h \
+ /usr/include/x86_64-linux-gnu/bits/waitflags.h \
+ /usr/include/x86_64-linux-gnu/bits/waitstatus.h /usr/include/endian.h \
+ /usr/include/x86_64-linux-gnu/bits/endian.h \
+ /usr/include/x86_64-linux-gnu/bits/byteswap.h \
+ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \
+ /usr/include/x86_64-linux-gnu/sys/types.h /usr/include/time.h \
+ /usr/include/x86_64-linux-gnu/sys/select.h \
+ /usr/include/x86_64-linux-gnu/bits/select.h \
+ /usr/include/x86_64-linux-gnu/bits/sigset.h \
+ /usr/include/x86_64-linux-gnu/bits/time.h \
+ /usr/include/x86_64-linux-gnu/sys/sysmacros.h \
+ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h /usr/include/alloca.h \
+ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/string.h \
+ /usr/include/xlocale.h /usr/lib/gcc/x86_64-linux-gnu/5/include/stdint.h \
+ /usr/include/stdint.h /usr/include/x86_64-linux-gnu/bits/wchar.h \
+ /usr/include/inttypes.h /usr/include/x86_64-linux-gnu/sys/queue.h \
+ /usr/include/netinet/in.h /usr/include/x86_64-linux-gnu/sys/socket.h \
+ /usr/include/x86_64-linux-gnu/sys/uio.h \
+ /usr/include/x86_64-linux-gnu/bits/uio.h \
+ /usr/include/x86_64-linux-gnu/bits/socket.h \
+ /usr/include/x86_64-linux-gnu/bits/socket_type.h \
+ /usr/include/x86_64-linux-gnu/bits/sockaddr.h \
+ /usr/include/x86_64-linux-gnu/asm/socket.h \
+ /usr/include/asm-generic/socket.h \
+ /usr/include/x86_64-linux-gnu/asm/sockios.h \
+ /usr/include/asm-generic/sockios.h \
+ /usr/include/x86_64-linux-gnu/bits/in.h /usr/include/setjmp.h \
+ /usr/include/x86_64-linux-gnu/bits/setjmp.h /usr/include/ctype.h \
+ /usr/include/errno.h /usr/include/x86_64-linux-gnu/bits/errno.h \
+ /usr/include/linux/errno.h /usr/include/x86_64-linux-gnu/asm/errno.h \
+ /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h \
+ /usr/include/getopt.h /usr/include/signal.h \
+ /usr/include/x86_64-linux-gnu/bits/signum.h \
+ /usr/include/x86_64-linux-gnu/bits/siginfo.h \
+ /usr/include/x86_64-linux-gnu/bits/sigaction.h \
+ /usr/include/x86_64-linux-gnu/bits/sigcontext.h \
+ /usr/include/x86_64-linux-gnu/bits/sigstack.h \
+ /usr/include/x86_64-linux-gnu/sys/ucontext.h \
+ /usr/include/x86_64-linux-gnu/bits/sigthread.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdbool.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_common.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include-fixed/limits.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include-fixed/syslimits.h \
+ /usr/include/limits.h /usr/include/x86_64-linux-gnu/bits/posix1_lim.h \
+ /usr/include/x86_64-linux-gnu/bits/local_lim.h \
+ /usr/include/linux/limits.h \
+ /usr/include/x86_64-linux-gnu/bits/posix2_lim.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/emmintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/xmmintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/mmintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/mm_malloc.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_log.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_common.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_malloc.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_memory.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/exec-env/rte_dom0_common.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_memcpy.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_vect.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/x86intrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/ia32intrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/pmmintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/tmmintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/ammintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/smmintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/popcntintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/wmmintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/immintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avxintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx2intrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx512fintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx512erintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx512pfintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx512cdintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx512vlintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx512bwintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx512dqintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx512vlbwintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx512vldqintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx512ifmaintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx512ifmavlintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx512vbmiintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx512vbmivlintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/shaintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/lzcntintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/bmiintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/bmi2intrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/fmaintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/f16cintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/rtmintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/xtestintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/mm3dnow.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/prfchwintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/fma4intrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/xopintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/lwpintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/tbmintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/rdseedintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/fxsrintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/xsaveintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/xsaveoptintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/adxintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/clwbintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/pcommitintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/clflushoptintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/xsavesintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/xsavecintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/mwaitxintrin.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_memzone.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_eal.h \
+ /usr/include/sched.h /usr/include/x86_64-linux-gnu/bits/sched.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_per_lcore.h \
+ /usr/include/pthread.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_launch.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_atomic.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/generic/rte_atomic.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_atomic_64.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_cycles.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/generic/rte_cycles.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_debug.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_log.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_branch_prediction.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_branch_prediction.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_prefetch.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/generic/rte_prefetch.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_lcore.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_interrupts.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/exec-env/rte_interrupts.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_pci.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_random.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_ether.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_mbuf.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_mempool.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_spinlock.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/generic/rte_spinlock.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_rtm.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_cpuflags.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/generic/rte_cpuflags.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_ring.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_byteorder.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/generic/rte_byteorder.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_byteorder_64.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_ethdev.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_dev.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_devargs.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_ether.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_eth_ctrl.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_dev_info.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_ip.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_eth_ctrl.h \
+ /home/ubuntu/feb_cgnat/csig_sdnd_benchmarking-industrial_standard_benchmarking/common/VIL/l2l3_stack/interface.h \
+ /usr/include/arpa/inet.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_errno.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_port_ethdev.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_port.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_eth_bond.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_rwlock.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/generic/rte_rwlock.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_spinlock.h
diff --git a/common/VIL/l2l3_stack/build/.main.o.d b/common/VIL/l2l3_stack/build/.main.o.d
new file mode 100644 (file)
index 0000000..9d27acc
--- /dev/null
@@ -0,0 +1,209 @@
+dep_main.o = \
+ /home/ubuntu/feb_cgnat/csig_sdnd_benchmarking-industrial_standard_benchmarking/common/VIL/l2l3_stack/main.c \
+ /usr/include/stdc-predef.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_config.h \
+ /usr/include/stdio.h /usr/include/features.h \
+ /usr/include/x86_64-linux-gnu/sys/cdefs.h \
+ /usr/include/x86_64-linux-gnu/bits/wordsize.h \
+ /usr/include/x86_64-linux-gnu/gnu/stubs.h \
+ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h \
+ /usr/include/x86_64-linux-gnu/bits/types.h \
+ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/libio.h \
+ /usr/include/_G_config.h /usr/include/wchar.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \
+ /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \
+ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/stdlib.h \
+ /usr/include/x86_64-linux-gnu/bits/waitflags.h \
+ /usr/include/x86_64-linux-gnu/bits/waitstatus.h /usr/include/endian.h \
+ /usr/include/x86_64-linux-gnu/bits/endian.h \
+ /usr/include/x86_64-linux-gnu/bits/byteswap.h \
+ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \
+ /usr/include/x86_64-linux-gnu/sys/types.h /usr/include/time.h \
+ /usr/include/x86_64-linux-gnu/sys/select.h \
+ /usr/include/x86_64-linux-gnu/bits/select.h \
+ /usr/include/x86_64-linux-gnu/bits/sigset.h \
+ /usr/include/x86_64-linux-gnu/bits/time.h \
+ /usr/include/x86_64-linux-gnu/sys/sysmacros.h \
+ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h /usr/include/alloca.h \
+ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdint.h /usr/include/stdint.h \
+ /usr/include/x86_64-linux-gnu/bits/wchar.h /usr/include/inttypes.h \
+ /usr/include/string.h /usr/include/xlocale.h \
+ /usr/include/x86_64-linux-gnu/sys/queue.h /usr/include/errno.h \
+ /usr/include/x86_64-linux-gnu/bits/errno.h /usr/include/linux/errno.h \
+ /usr/include/x86_64-linux-gnu/asm/errno.h \
+ /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h \
+ /usr/include/getopt.h /usr/include/signal.h \
+ /usr/include/x86_64-linux-gnu/bits/signum.h \
+ /usr/include/x86_64-linux-gnu/bits/siginfo.h \
+ /usr/include/x86_64-linux-gnu/bits/sigaction.h \
+ /usr/include/x86_64-linux-gnu/bits/sigcontext.h \
+ /usr/include/x86_64-linux-gnu/bits/sigstack.h \
+ /usr/include/x86_64-linux-gnu/sys/ucontext.h \
+ /usr/include/x86_64-linux-gnu/bits/sigthread.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdbool.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_common.h \
+ /usr/include/ctype.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include-fixed/limits.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include-fixed/syslimits.h \
+ /usr/include/limits.h /usr/include/x86_64-linux-gnu/bits/posix1_lim.h \
+ /usr/include/x86_64-linux-gnu/bits/local_lim.h \
+ /usr/include/linux/limits.h \
+ /usr/include/x86_64-linux-gnu/bits/posix2_lim.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/emmintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/xmmintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/mmintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/mm_malloc.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_vect.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/x86intrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/ia32intrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/pmmintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/tmmintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/ammintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/smmintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/popcntintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/wmmintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/immintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avxintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx2intrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx512fintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx512erintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx512pfintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx512cdintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx512vlintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx512bwintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx512dqintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx512vlbwintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx512vldqintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx512ifmaintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx512ifmavlintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx512vbmiintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/avx512vbmivlintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/shaintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/lzcntintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/bmiintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/bmi2intrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/fmaintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/f16cintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/rtmintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/xtestintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/mm3dnow.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/prfchwintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/fma4intrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/xopintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/lwpintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/tbmintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/rdseedintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/fxsrintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/xsaveintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/xsaveoptintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/adxintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/clwbintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/pcommitintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/clflushoptintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/xsavesintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/xsavecintrin.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/mwaitxintrin.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_byteorder.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/generic/rte_byteorder.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_byteorder_64.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_log.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_common.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_memory.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/exec-env/rte_dom0_common.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_memcpy.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_memzone.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_eal.h \
+ /usr/include/sched.h /usr/include/x86_64-linux-gnu/bits/sched.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_per_lcore.h \
+ /usr/include/pthread.h /usr/include/x86_64-linux-gnu/bits/setjmp.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_launch.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_atomic.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/generic/rte_atomic.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_atomic_64.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_cycles.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/generic/rte_cycles.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_debug.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_log.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_branch_prediction.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_branch_prediction.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_prefetch.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/generic/rte_prefetch.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_lcore.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_interrupts.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/exec-env/rte_interrupts.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_pci.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_random.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_ether.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_mbuf.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_mempool.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_spinlock.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/generic/rte_spinlock.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_rtm.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_cpuflags.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/generic/rte_cpuflags.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_ring.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_ethdev.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_dev.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_devargs.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_ether.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_eth_ctrl.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_dev_info.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_ip.h \
+ /usr/include/netinet/in.h /usr/include/x86_64-linux-gnu/sys/socket.h \
+ /usr/include/x86_64-linux-gnu/sys/uio.h \
+ /usr/include/x86_64-linux-gnu/bits/uio.h \
+ /usr/include/x86_64-linux-gnu/bits/socket.h \
+ /usr/include/x86_64-linux-gnu/bits/socket_type.h \
+ /usr/include/x86_64-linux-gnu/bits/sockaddr.h \
+ /usr/include/x86_64-linux-gnu/asm/socket.h \
+ /usr/include/asm-generic/socket.h \
+ /usr/include/x86_64-linux-gnu/asm/sockios.h \
+ /usr/include/asm-generic/sockios.h \
+ /usr/include/x86_64-linux-gnu/bits/in.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_tcp.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_udp.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_string_fns.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_cpuflags.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_timer.h \
+ /home/ubuntu/feb_cgnat/csig_sdnd_benchmarking-industrial_standard_benchmarking/common/VIL/l2l3_stack/lib_arp.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_pipeline.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_port.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_table.h \
+ /home/ubuntu/feb_cgnat/csig_sdnd_benchmarking-industrial_standard_benchmarking/common/VIL/l2l3_stack/l2_proto.h \
+ /usr/include/setjmp.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_malloc.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_eth_ctrl.h \
+ /home/ubuntu/feb_cgnat/csig_sdnd_benchmarking-industrial_standard_benchmarking/common/VIL/l2l3_stack/interface.h \
+ /usr/include/arpa/inet.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_errno.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_port_ethdev.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_port.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_eth_bond.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_rwlock.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/generic/rte_rwlock.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_spinlock.h \
+ /home/ubuntu/feb_cgnat/csig_sdnd_benchmarking-industrial_standard_benchmarking/common/VIL/l2l3_stack/interface.h \
+ /home/ubuntu/feb_cgnat/csig_sdnd_benchmarking-industrial_standard_benchmarking/common/VIL/l2l3_stack/l3fwd_common.h \
+ /usr/include/x86_64-linux-gnu/sys/param.h \
+ /usr/include/x86_64-linux-gnu/bits/param.h /usr/include/linux/param.h \
+ /usr/include/x86_64-linux-gnu/asm/param.h \
+ /usr/include/asm-generic/param.h /usr/include/unistd.h \
+ /usr/include/x86_64-linux-gnu/bits/posix_opt.h \
+ /usr/include/x86_64-linux-gnu/bits/environments.h \
+ /usr/include/x86_64-linux-gnu/bits/confname.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_hash.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_jhash.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_table_hash.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_table.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_table_lpm.h \
+ /home/ubuntu/feb_cgnat/csig_sdnd_benchmarking-industrial_standard_benchmarking/common/VIL/l2l3_stack/l3fwd_lpm4.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_lpm.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_compat.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_lpm_sse.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_lpm6.h \
+ /home/ubuntu/feb_cgnat/csig_sdnd_benchmarking-industrial_standard_benchmarking/common/VIL/l2l3_stack/l3fwd_lpm6.h \
+ /home/ubuntu/dpdk-16.07/x86_64-native-linuxapp-gcc/include/rte_table_lpm_ipv6.h \
+ /home/ubuntu/feb_cgnat/csig_sdnd_benchmarking-industrial_standard_benchmarking/common/VIL/l2l3_stack/l3fwd_lpm4.h \
+ /home/ubuntu/feb_cgnat/csig_sdnd_benchmarking-industrial_standard_benchmarking/common/VIL/l2l3_stack/l3fwd_lpm6.h
diff --git a/common/VIL/l2l3_stack/hle.c b/common/VIL/l2l3_stack/hle.c
new file mode 100644 (file)
index 0000000..a0661b3
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include "tsx.h"
+//#include "hle.h"
+#include <xmmintrin.h>
+
+void hle_init(void)
+{
+       mutex_val = 0;
+}
+
+int hle_lock(void)
+{
+       while (__atomic_exchange_n
+                                (&mutex_val, 1, __ATOMIC_ACQUIRE | __ATOMIC_HLE_ACQUIRE))
+               _mm_pause();
+       return TRUE;
+}
+
+int hle_release(void)
+{
+       __atomic_store_n(&mutex_val, 0,
+                        __ATOMIC_RELEASE | __ATOMIC_HLE_RELEASE);
+       return TRUE;
+}
+
+int is_hle_locked(void)
+{
+       return (mutex_val == 0) ? FALSE : TRUE;
+}
diff --git a/common/VIL/l2l3_stack/hle.h b/common/VIL/l2l3_stack/hle.h
new file mode 100644 (file)
index 0000000..21da710
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#define HLE_TRUE 1
+#define HLE_FALSE 0
+
+volatile int mutex_val;
+/*
+ * hle mutex
+ * @param void
+ */
+void hle_mutex(void);
+/*
+ * To lock instrution
+ * @param void
+ */
+int hle_lock(void);
+/*
+ * To release held lock
+ * @param void
+ */
+int hle_release(void);
+/*
+ * To check whether lock is held
+ * @param void
+ */
+int is_locked(void);
diff --git a/common/VIL/l2l3_stack/interface.c b/common/VIL/l2l3_stack/interface.c
new file mode 100644 (file)
index 0000000..84c390d
--- /dev/null
@@ -0,0 +1,1478 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <interface.h>
+#include <rte_byteorder.h>
+#include <lib_arp.h>
+#include <tsx.h>
+
+interface_main_t ifm;
+int USE_RTM_LOCKS = 0;
+rte_rwlock_t rwlock;
+uint8_t ifm_debug;
+static int prev_state;
+
+void config_ifm_debug(int dbg, int flag)
+{
+       switch (dbg) {
+       case IFM_DEBUG_CONFIG:
+               if (flag) {
+                       ifm_debug |= IFM_DEBUG_CONFIG;
+               } else {
+                       ifm_debug &= ~IFM_DEBUG_CONFIG;
+               }
+               break;
+       case IFM_DEBUG_RXTX:
+               if (flag) {
+                       ifm_debug |= IFM_DEBUG_RXTX;
+               } else {
+                       ifm_debug &= ~IFM_DEBUG_RXTX;
+               }
+               break;
+       case IFM_DEBUG_LOCKS:
+               if (flag) {
+                       ifm_debug |= IFM_DEBUG_LOCKS;
+               } else {
+                       ifm_debug &= ~IFM_DEBUG_LOCKS;
+               }
+               break;
+       case IFM_DEBUG:
+               if (flag) {
+                       ifm_debug |= IFM_DEBUG;
+               } else {
+                       ifm_debug &= ~IFM_DEBUG;
+               }
+               break;
+       }
+}
+
+void ifm_init(void)
+{
+       int i = 0;
+       config_ifm_debug(IFM_DEBUG_CONFIG, 1);
+       if (can_use_intel_core_4th_gen_features()) {
+               if (ifm_debug & IFM_DEBUG_CONFIG)
+                       RTE_LOG(INFO, IFM, "TSX not currently supported...\n\r");
+               USE_RTM_LOCKS = 0;
+       } else {
+               if (ifm_debug & IFM_DEBUG_CONFIG)
+                       RTE_LOG(INFO, IFM, "TSX not supported\n\r");
+               USE_RTM_LOCKS = 0;
+       }
+       if (USE_RTM_LOCKS)
+               rtm_init();
+       else
+               rte_rwlock_init(&rwlock);
+
+       for (i = 0; i < IFM_MAX_PORTARR_SZ; i++) {
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Acquiring WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS)
+                       rtm_lock();
+               else
+                       rte_rwlock_write_lock(&rwlock);
+
+               ifm.port_list[i] = NULL;
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS)
+                       rtm_unlock();
+               else
+                       rte_rwlock_write_unlock(&rwlock);
+       }
+       ifm.nport_intialized = rte_eth_dev_count();
+       ifm.nport_configured = 0;
+       RTE_LOG(INFO, IFM, "IFM_INIT: Number of ports initialized during "
+               "PCI probing %u.\n\r", ifm.nport_intialized);
+}
+
+void ifm_remove_port_details(uint8_t portid)
+{
+       if (ifm.port_list[portid] != NULL) {
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Acquiring lock %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS)
+                       rtm_lock();
+               else
+                       rte_rwlock_write_lock(&rwlock);
+               l2_phy_interface_t *port = ifm.port_list[portid];
+               ifm.port_list[portid] = NULL;
+               if (ifm_debug & IFM_DEBUG_CONFIG)
+                       RTE_LOG(INFO, IFM, "%s: NULL set for port %u\n\r",
+                               __FUNCTION__, portid);
+               rte_free(port);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+
+               if (USE_RTM_LOCKS)
+                       rtm_unlock();
+               else
+                       rte_rwlock_write_unlock(&rwlock);
+       } else {
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM,
+                               "%s: Failed to remove port details.Port %u info"
+                               " is already Null.\n\r", __FUNCTION__, portid);
+       }
+}
+
+l2_phy_interface_t *ifm_get_port(uint8_t port_id)
+{
+       l2_phy_interface_t *port = NULL;
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Acquiring lock @ %d\n\r", __FUNCTION__,
+                       __LINE__);
+
+       if (USE_RTM_LOCKS)
+               rtm_lock();
+       else
+               rte_rwlock_read_lock(&rwlock);
+
+       port = ifm.port_list[port_id];
+
+       if (port == NULL) {
+               /*RTE_LOG(ERR, IFM, "%s: Port %u info not found... configure it first.\n\r",
+                        __FUNCTION__, port_id);
+                */
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing RD lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS)
+                       rtm_unlock();
+               else
+                       rte_rwlock_read_unlock(&rwlock);
+               return NULL;
+       }
+       if (port->pmdid == port_id) {
+               /*RTE_LOG(INFO, IFM, "%s: Port %u found....\n\r",
+                        __FUNCTION__, port_id); */
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+
+               if (USE_RTM_LOCKS)
+                       rtm_unlock();
+               else
+                       rte_rwlock_read_unlock(&rwlock);
+               return port;
+       } else {
+
+/*             RTE_LOG(INFO, IFM,"%s: Mismatch given port %u port in loc %u\n\r",__FUNCTION__,port_id,
+                               ifm.port_list[port_id]->pmdid);
+*/
+       }
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Releasing lock @ %d\n\r", __FUNCTION__,
+                       __LINE__);
+       if (USE_RTM_LOCKS)
+               rtm_unlock();
+       else
+               rte_rwlock_read_unlock(&rwlock);
+       return NULL;
+}
+
+l2_phy_interface_t *ifm_get_first_port(void)
+{
+       l2_phy_interface_t *port = NULL;
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Acquiring lock @ %d\n\r", __FUNCTION__,
+                       __LINE__);
+
+       if (USE_RTM_LOCKS)
+               rtm_lock();
+       else
+               rte_rwlock_read_lock(&rwlock);
+       port = ifm.port_list[0];
+       if (port == NULL) {
+               /*RTE_LOG(ERR, IFM, "%s: Port info not found... configure it first.\n\r",
+                        __FUNCTION__); */
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS)
+                       rtm_unlock();
+               else
+                       rte_rwlock_read_unlock(&rwlock);
+               return NULL;
+       }
+       /*RTE_LOG(ERR, IFM, "%s: Port  %u info is found...%p\n\r",
+                __FUNCTION__, port->pmdid, port); */
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Releasing lock @ %d\n\r", __FUNCTION__,
+                       __LINE__);
+       if (USE_RTM_LOCKS)
+               rtm_unlock();
+       else
+               rte_rwlock_read_unlock(&rwlock);
+       return port;
+}
+
+l2_phy_interface_t *ifm_get_next_port(uint8_t port_id)
+{
+       l2_phy_interface_t *port = NULL;
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Acquiring lock @ %d\n\r", __FUNCTION__,
+                       __LINE__);
+       if (USE_RTM_LOCKS)
+               rtm_lock();
+       else
+               rte_rwlock_read_lock(&rwlock);
+       port = ifm.port_list[port_id + 1];
+       if (port == NULL) {
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS)
+                       rtm_unlock();
+               else
+                       rte_rwlock_read_unlock(&rwlock);
+               return NULL;
+       }
+       /*RTE_LOG(ERR, IFM, "%s: Port  %u info is found...\n\r",
+                __FUNCTION__, port_id); */
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Releasing lock @ %d\n\r", __FUNCTION__,
+                       __LINE__);
+
+       if (USE_RTM_LOCKS)
+               rtm_unlock();
+       else
+               rte_rwlock_read_unlock(&rwlock);
+       return port;
+}
+
+l2_phy_interface_t *ifm_get_port_by_name(const char *name)
+{
+       l2_phy_interface_t *port = NULL;
+       int i;
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Acquiring lock @ %d\n\r", __FUNCTION__,
+                       __LINE__);
+
+       if (USE_RTM_LOCKS)
+               rtm_lock();
+       else
+               rte_rwlock_read_lock(&rwlock);
+       for (i = 0; i < RTE_MAX_ETHPORTS && ifm.port_list[i]; i++) {
+               port = ifm.port_list[i];
+               if (strcmp(name, port->ifname) == 0) {
+                       if (ifm_debug & IFM_DEBUG_CONFIG)
+                               RTE_LOG(INFO, IFM, "FOUND! port %u %s\n\r",
+                                       port->pmdid, port->ifname);
+                       if (ifm_debug & IFM_DEBUG_LOCKS)
+                               RTE_LOG(INFO, IFM,
+                                       "%s: Releasing lock @ %d\n\r",
+                                       __FUNCTION__, __LINE__);
+                       if (USE_RTM_LOCKS)
+                               rtm_unlock();
+                       else
+                               rte_rwlock_read_unlock(&rwlock);
+                       return port;
+               }
+       }
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Releasing lock @ %d\n\r", __FUNCTION__,
+                       __LINE__);
+       if (USE_RTM_LOCKS)
+               rtm_unlock();
+       else
+               rte_rwlock_read_unlock(&rwlock);
+       return NULL;
+}
+
+void lsi_event_callback(uint8_t port_id, enum rte_eth_event_type type,
+                       void *param)
+{
+       struct rte_eth_link link;
+       l2_phy_interface_t *port;
+       int nclients = ifm.nclient;
+       int i;
+
+       RTE_SET_USED(param);
+       RTE_SET_USED(type);
+
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Acquiring WR lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS) {
+               rtm_lock();
+       } else {
+               rte_rwlock_write_lock(&rwlock);
+       }
+       rte_eth_link_get(port_id, &link);
+       for (i = 0; i < nclients; i++)
+               ifm.if_client[i].cb_linkupdate(port_id, link.link_status);
+       port = ifm.port_list[port_id];
+       if (port == NULL) {
+               RTE_LOG(ERR, IFM,
+                       "%s: Port %u info not found... configure it first.\n\r",
+                       __FUNCTION__, port_id);
+       }
+       if (port != NULL && port->pmdid == port_id) {
+               if (link.link_status) {
+                       port->link_status = IFM_ETH_LINK_UP;
+                       port->link_speed = link.link_speed;
+                       port->link_duplex = link.link_duplex;
+                       RTE_LOG(INFO, IFM,
+                               "EVENT-- PORT %u Link UP - Speed %u Mbps - %s.\n",
+                               port_id, (unsigned)link.link_speed,
+                               (link.link_duplex ==
+                                ETH_LINK_FULL_DUPLEX) ? ("full-duplex")
+                               : ("half-duplex"));
+                       if (port->flags & IFM_MASTER) {
+                               port->flags |= IFM_BONDED;
+                               port->bond_config->active_slave_count =
+                                               rte_eth_bond_active_slaves_get(port->pmdid,
+                                                                        port->
+                                                                        bond_config->
+                                                                        active_slaves,
+                                                                        RTE_MAX_ETHPORTS);
+                               struct ether_addr new_mac;
+                               rte_eth_macaddr_get(port->pmdid,
+                                                               (struct ether_addr *)
+                                                               &new_mac);
+                               if (memcmp
+                                               (&new_mac, port->macaddr,
+                                                sizeof(struct ether_addr))) {
+                                       RTE_LOG(INFO, IFM,
+                                               "Bond port %u MAC has changed.\n\r",
+                                               port->pmdid);
+                               } else {
+                                       RTE_LOG(INFO, IFM,
+                                               "Bond port %u MAC remains same\n\r",
+                                               port->pmdid);
+                               }
+                       }
+                       if (port->flags & IFM_SLAVE) {
+                               uint8_t master_portid =
+                                               port->bond_config->bond_portid;
+                               struct rte_eth_link linkstatus;
+                               rte_eth_link_get(master_portid, &linkstatus);
+                               RTE_LOG(INFO, IFM, "Port %u 's Master(%u) status is %u\n\r", port_id,
+                                               master_portid, linkstatus.link_status);
+                       }
+                       if (ifm_debug & IFM_DEBUG_LOCKS)
+                               RTE_LOG(INFO, IFM,
+                                       "%s: Releasing WR lock @ %d\n\r",
+                                       __FUNCTION__, __LINE__);
+
+                       if (USE_RTM_LOCKS) {
+                               rtm_unlock();
+                       } else {
+                               rte_rwlock_write_unlock(&rwlock);
+                       }
+                       if (port->ipv4_list != NULL) {
+                               if (ifm_debug & IFM_DEBUG_CONFIG)
+                                       RTE_LOG(INFO, IFM,
+                                               "Sending garp on port %u\n\r",
+                                               port->pmdid);
+                               if (!prev_state) {
+                                       send_gratuitous_arp(port);
+                                       prev_state = 1;
+                               }
+                       }
+#if 0
+                       else {
+                               if (ifm_debug & IFM_DEBUG_CONFIG)
+                                       RTE_LOG(INFO, IFM,
+                                               "IP is not enabled on port %u, not sending GARP\n\r",
+                                               port->pmdid);
+                       }
+#endif
+               } else {
+                       if (port->flags & IFM_MASTER) {
+                               port->flags &= ~IFM_BONDED;
+                               //RTE_LOG(INFO, IFM, "IFM_MASTER port, resetting IFM_BONDED. %u\n\r", port->flags);
+                       }
+                       port->link_status = IFM_ETH_LINK_DOWN;
+                       RTE_LOG(INFO, IFM, "EVENT-- PORT %u is Link DOWN.\n",
+                               port_id);
+                       if (port->flags & IFM_SLAVE) {
+                               struct rte_eth_link linkstatus;
+                               uint8_t master_portid =
+                                               port->bond_config->bond_portid;
+                               rte_eth_link_get_nowait(master_portid,
+                                                       &linkstatus);
+                               RTE_LOG(INFO, IFM,
+                                       "Port %u 's Master(%u) status is %u\n\r",
+                                       port_id, master_portid,
+                                       linkstatus.link_status);
+                       }
+                       if (ifm_debug & IFM_DEBUG_LOCKS)
+                               RTE_LOG(INFO, IFM,
+                                       "%s: Releasing WR lock @ %d\n\r",
+                                       __FUNCTION__, __LINE__);
+                       if (USE_RTM_LOCKS) {
+                               rtm_unlock();
+                       } else {
+                               rte_rwlock_write_unlock(&rwlock);
+                       }
+                       prev_state = 0;
+               }
+       }
+       //print_interface_details();
+}
+
+void ifm_update_linkstatus(uint8_t port_id, uint16_t linkstatus)
+{
+       struct rte_eth_link link;
+       l2_phy_interface_t *port;
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Acquiring lock @ %d\n\r", __FUNCTION__,
+                       __LINE__);
+
+       if (USE_RTM_LOCKS) {
+               rtm_lock();
+       } else {
+               rte_rwlock_write_lock(&rwlock);
+       }
+       port = ifm.port_list[port_id];
+
+       if (port == NULL) {
+               RTE_LOG(ERR, IFM,
+                       "%s: Port %u info not found... configure it first.\n\r",
+                       __FUNCTION__, port_id);
+       }
+       if (port != NULL && port->pmdid == port_id) {
+               rte_eth_link_get(port_id, &link);
+               if (linkstatus == IFM_ETH_LINK_UP) {
+                       port->admin_status = IFM_ETH_LINK_UP;
+                       if(!link.link_status) {
+                               if (rte_eth_dev_set_link_up(port_id) < 0) {
+                                       RTE_LOG(INFO, IFM,
+                                                       "%s:Port %u admin up is unsuccessful\n\r",
+                                                       __FUNCTION__, port->pmdid);
+                               } else {
+                                       if (ifm_debug & IFM_DEBUG_LOCKS)
+                                               RTE_LOG(INFO, IFM,
+                                                               "%s: Releasing lock @ %d\n\r",
+                                                               __FUNCTION__, __LINE__);
+
+                                       if (USE_RTM_LOCKS) {
+                                               rtm_unlock();
+                                       } else {
+                                               rte_rwlock_write_unlock(&rwlock);
+                                       }
+                                       if (ifm_debug & IFM_DEBUG_CONFIG)
+                                               RTE_LOG(INFO, IFM,
+                                                               "%s:Port %u admin up...\n\r",
+                                                               __FUNCTION__, port->pmdid);
+                                       send_gratuitous_arp(port);
+                                       return;
+                               }
+                       }
+               } else if (linkstatus == IFM_ETH_LINK_DOWN)
+               {
+                       int status;
+                       port->admin_status = IFM_ETH_LINK_DOWN;
+                       /* need to check the following if */
+                       if(link.link_status) {
+                               status = rte_eth_dev_set_link_down(port_id);
+                               if (status < 0)
+                               {
+                                       rte_panic("(%" PRIu32 "): PMD set link down error %"
+                                                       PRId32 "\n", port_id, status);
+                               }
+                       }
+               }
+       }
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Releasing lock @ %d\n\r", __FUNCTION__,
+                       __LINE__);
+
+       if (USE_RTM_LOCKS) {
+               rtm_unlock();
+       } else {
+               rte_rwlock_write_unlock(&rwlock);
+       }
+}
+
+void ifm_set_l2_interface_mtu(uint8_t port_id, uint16_t mtu)
+{
+       int ret;
+       l2_phy_interface_t *port;
+       port = ifm.port_list[port_id];
+       if (port == NULL) {
+               RTE_LOG(ERR, IFM,
+                       "%s: Port %u info not found... configure it first.\n\r",
+                       __FUNCTION__, port_id);
+       }
+
+       if (port != NULL && port->pmdid == port_id) {
+               ret = rte_eth_dev_set_mtu(port_id, mtu);
+               if (ret != 0)
+                       RTE_LOG(INFO, IFM,
+                               "set_l2_interface_mtu: Set MTU failed. ret=%d\n",
+                               ret);
+               else {
+                       if (ifm_debug & IFM_DEBUG_LOCKS)
+                               RTE_LOG(INFO, IFM,
+                                       "%s: Acquiring lock @ %d\n\r",
+                                       __FUNCTION__, __LINE__);
+
+                       if (USE_RTM_LOCKS) {
+                               rtm_lock();
+                       } else {
+                               rte_rwlock_write_lock(&rwlock);
+                       }
+                       port->mtu = mtu;
+                       if (ifm_debug & IFM_DEBUG_LOCKS)
+                               RTE_LOG(INFO, IFM,
+                                       "%s: Releasing lock @ %d\n\r",
+                                       __FUNCTION__, __LINE__);
+
+                       if (USE_RTM_LOCKS) {
+                               rtm_unlock();
+                       } else {
+                               rte_rwlock_write_unlock(&rwlock);
+                       }
+                       return;
+               }
+       }
+}
+
+void ifm_set_port_promisc(uint8_t port_id, uint8_t enable)
+{
+       l2_phy_interface_t *port;
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Acquiring WR lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS) {
+               rtm_lock();
+       } else {
+               rte_rwlock_write_lock(&rwlock);
+       }
+       port = ifm.port_list[port_id];
+       if (port == NULL) {
+               RTE_LOG(ERR, IFM,
+                       "%s: Port %u info not found... configure it first.\n\r",
+                       __FUNCTION__, port_id);
+       }
+       if (port != NULL && port->pmdid == port_id) {
+               if (enable == 1) {
+                       rte_eth_promiscuous_enable(port_id);
+                       port->promisc = 1;
+               } else {
+                       rte_eth_promiscuous_disable(port_id);
+                       port->promisc = 0;
+               }
+       }
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS) {
+               rtm_unlock();
+       } else {
+               rte_rwlock_write_unlock(&rwlock);
+       }
+}
+
+int32_t ifm_get_nactive_ports(void)
+{
+       return ifm.nport_configured;
+}
+
+int32_t ifm_get_nports_initialized(void)
+{
+       return ifm.nport_intialized;
+}
+
+uint16_t ifm_receive_bulk_pkts(uint8_t port_id, uint16_t qid,
+                                                struct rte_mbuf **rx_pkts)
+{
+       uint64_t no_of_rcvd_pkt;
+       no_of_rcvd_pkt =
+                       rte_eth_rx_burst(port_id, qid, rx_pkts, IFM_BURST_SIZE);
+       if (ifm_debug & IFM_DEBUG_RXTX)
+               RTE_LOG(INFO, IFM,
+                       "ifm_receive_bulk_pkts: port_id %u no_of_rcvd_pkt %lu\n\r",
+                       port_id, no_of_rcvd_pkt);
+       return no_of_rcvd_pkt;
+}
+
+uint16_t ifm_transmit_bulk_pkts(l2_phy_interface_t *port,
+                               struct rte_mbuf **tx_pkts, uint64_t npkts)
+{
+       uint32_t burst_tx_delay_time = IFM_BURST_TX_WAIT_US;
+       uint32_t burst_tx_retry_num = IFM_BURST_TX_RETRIES;
+       uint32_t retry;
+       uint32_t no_of_tx_pkt;
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Acquiring RD lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS) {
+               rtm_lock();
+       } else {
+               rte_rwlock_read_lock(&rwlock);
+       }
+       no_of_tx_pkt = rte_eth_tx_burst(port->pmdid, IFM_TX_DEFAULT_Q, tx_pkts,
+                                       npkts);
+       if (unlikely(no_of_tx_pkt < npkts)) {
+               retry = 0;
+               while (no_of_tx_pkt < IFM_BURST_SIZE
+                                        && retry++ < burst_tx_retry_num) {
+                       rte_delay_us(burst_tx_delay_time);
+                       no_of_tx_pkt =
+                                       rte_eth_tx_burst(port->pmdid, IFM_TX_DEFAULT_Q,
+                                                        &tx_pkts[no_of_tx_pkt],
+                                                        IFM_BURST_SIZE - no_of_tx_pkt);
+               }
+       }
+       if (ifm_debug & IFM_DEBUG_RXTX)
+               RTE_LOG(INFO, IFM,
+                       "ifm_transmit_bulk_pkts: no_of_tx_pkt %u\n\r",
+                       no_of_tx_pkt);
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Releasing RD lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS) {
+               rtm_unlock();
+       } else {
+               rte_rwlock_read_unlock(&rwlock);
+       }
+       return no_of_tx_pkt;
+}
+
+int ifm_transmit_single_pkt(l2_phy_interface_t *port, struct rte_mbuf *tx_pkts)
+{
+       uint64_t tx_npkts = 0;
+       if (tx_pkts == NULL || port == NULL) {
+               RTE_LOG(INFO, IFM,
+                       "ifm_transmit_single_pkt: tx_pkts and port are NULL ");
+               return IFM_FAILURE;
+       }
+       if (ifm_debug & IFM_DEBUG_RXTX)
+               RTE_LOG(INFO, IFM,
+                       "ifm_transmit_single_pkt: port->pmdid %u\n\r",
+                       port->pmdid);
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Acquiring RD lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+
+       if (USE_RTM_LOCKS) {
+               rtm_lock();
+       } else {
+               rte_rwlock_read_lock(&rwlock);
+       }
+       tx_npkts =
+                       rte_eth_tx_buffer(port->pmdid, IFM_TX_DEFAULT_Q, port->tx_buffer,
+                                               tx_pkts);
+       if (ifm_debug & IFM_DEBUG_RXTX)
+               RTE_LOG(INFO, IFM,
+                       "ifm_transmit_single_pkt: port->pmdid %u No of packets buffered %lu\n\r",
+                       port->pmdid, tx_npkts);
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Releasing RW lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+
+       if (USE_RTM_LOCKS) {
+               rtm_unlock();
+       } else {
+               rte_rwlock_read_unlock(&rwlock);
+       }
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Acquiring WR lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+
+       if (USE_RTM_LOCKS) {
+               rtm_lock();
+       } else {
+               rte_rwlock_write_lock(&rwlock);
+       }
+       port->n_txpkts +=
+                       rte_eth_tx_buffer_flush(port->pmdid, IFM_TX_DEFAULT_Q,
+                                               port->tx_buffer);
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+
+       if (USE_RTM_LOCKS) {
+               rtm_unlock();
+       } else {
+               rte_rwlock_write_unlock(&rwlock);
+       }
+       if (ifm_debug & IFM_DEBUG_RXTX)
+               RTE_LOG(INFO, IFM,
+                       "ifm_transmit_single_pkt: no of pkts flushed %lu\n\r",
+                       port->n_txpkts);
+       return tx_npkts;
+}
+
+int16_t ifm_add_ipv4_port(uint8_t port_id, uint32_t ipaddr, uint32_t addrlen)
+{
+       l2_phy_interface_t *port;
+       ipv4list_t *ipconf;
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Acquiring lock @ %d\n\r", __FUNCTION__,
+                       __LINE__);
+
+       if (USE_RTM_LOCKS) {
+               rtm_lock();
+       } else {
+               rte_rwlock_write_lock(&rwlock);
+       }
+       port = ifm.port_list[port_id];
+       if (port == NULL) {
+               RTE_LOG(ERR, IFM,
+                       "%s: Port %u info not found... configure it first.\n\r",
+                       __FUNCTION__, port_id);
+       }
+       if (port != NULL && port->pmdid == port_id) {
+               ipconf = (ipv4list_t *) rte_zmalloc(NULL, sizeof(ipv4list_t),
+                                                               RTE_CACHE_LINE_SIZE);
+               if (ipconf != NULL) {
+                       ipconf->next = NULL;
+                       //ipconf->ipaddr = rte_bswap32(ipaddr);
+                       ipconf->ipaddr = ipaddr;
+                       ipconf->port = port;
+                       ipconf->addrlen = addrlen;
+                       if (port->ipv4_list == NULL)
+                               port->flags |= IFM_IPV4_ENABLED;
+                       ipconf->next = (ipv4list_t *) port->ipv4_list;
+                       port->ipv4_list = (ipv4list_t *) ipconf;
+                       if (ifm_debug & IFM_DEBUG_LOCKS)
+                               RTE_LOG(INFO, IFM,
+                                       "%s: Releasing lock @ %d\n\r",
+                                       __FUNCTION__, __LINE__);
+
+                       if (USE_RTM_LOCKS) {
+                               rtm_unlock();
+                       } else {
+                               rte_rwlock_write_unlock(&rwlock);
+                       }
+                       return 0;
+               }
+       }
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Releasing lock @ %d\n\r", __FUNCTION__,
+                       __LINE__);
+
+       if (USE_RTM_LOCKS) {
+               rtm_unlock();
+       } else {
+               rte_rwlock_write_unlock(&rwlock);
+       }
+       return -1;
+}
+
+int16_t ifm_remove_ipv4_port(uint8_t port_id, uint32_t ipaddr,
+                                               uint32_t addrlen)
+{
+       l2_phy_interface_t *port;
+       ipv4list_t *iplist, *previplist = NULL;
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Acquiring lock @ %d\n\r", __FUNCTION__,
+                       __LINE__);
+
+       if (USE_RTM_LOCKS) {
+               rtm_lock();
+       } else {
+               rte_rwlock_write_lock(&rwlock);
+       }
+       port = ifm.port_list[port_id];
+       if (port == NULL) {
+               RTE_LOG(ERR, IFM,
+                       "%s: Port %u info not found... configure it first.\n\r",
+                       __FUNCTION__, port_id);
+       }
+       if (port != NULL && port->pmdid == port_id) {
+               if (port->ipv4_list == NULL) {
+                       if (ifm_debug & IFM_DEBUG_LOCKS)
+                               RTE_LOG(INFO, IFM,
+                                       "%s: Releasing lock @ %d\n\r",
+                                       __FUNCTION__, __LINE__);
+
+                       if (USE_RTM_LOCKS) {
+                               rtm_unlock();
+                       } else {
+                               rte_rwlock_write_unlock(&rwlock);
+                       }
+                       return -1;
+               }
+               iplist = (ipv4list_t *) port->ipv4_list;
+               while (iplist != NULL) {
+                       if (addrlen == iplist->addrlen &&
+                                       memcpy(&iplist->ipaddr, &ipaddr, addrlen)) {
+                               if (iplist == port->ipv4_list) {
+                                       port->ipv4_list = iplist->next;
+                               } else {
+                                       if (previplist != NULL)
+                                               previplist->next = iplist->next;
+                               }
+                               port->flags &= ~IFM_IPV4_ENABLED;
+                               rte_free(iplist);
+                               if (ifm_debug & IFM_DEBUG_LOCKS)
+                                       RTE_LOG(INFO, IFM,
+                                               "%s: Releasing lock @ %d\n\r",
+                                               __FUNCTION__, __LINE__);
+
+                               if (USE_RTM_LOCKS) {
+                                       rtm_unlock();
+                               } else {
+                                       rte_rwlock_write_unlock(&rwlock);
+                               }
+                               return 0;
+                       } else {
+                               previplist = iplist;
+                               iplist = iplist->next;
+                       }
+               }
+       }
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Releasing lock @ %d\n\r", __FUNCTION__,
+                       __LINE__);
+
+       if (USE_RTM_LOCKS) {
+               rtm_unlock();
+       } else {
+               rte_rwlock_write_unlock(&rwlock);
+       }
+       return -1;
+}
+
+int8_t ifm_add_ipv6_port(uint8_t port_id, uint8_t ip6addr[], uint32_t addrlen)
+{
+       l2_phy_interface_t *port;
+       ipv6list_t *ip6conf;
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Acquiring lock @ %d\n\r", __FUNCTION__,
+                       __LINE__);
+
+       if (USE_RTM_LOCKS) {
+               rtm_lock();
+       } else {
+               rte_rwlock_write_lock(&rwlock);
+       }
+       port = ifm.port_list[port_id];
+       if (port == NULL) {
+               RTE_LOG(ERR, IFM,
+                       "%s: Port %u info not found... configure it first.\n\r",
+                       __FUNCTION__, port_id);
+       }
+       if (port != NULL && port->pmdid == port_id) {
+               ip6conf = (ipv6list_t *) rte_zmalloc(NULL, sizeof(ipv6list_t),
+                                                                RTE_CACHE_LINE_SIZE);
+               if (ip6conf != NULL) {
+                       ip6conf->next = NULL;
+                       memcpy(ip6conf->ipaddr, ip6addr, IFM_IPV6_ADDR_SIZE);
+                       ip6conf->port = port;
+                       ip6conf->addrlen = addrlen;
+
+                       if (port->ipv6_list == NULL) {
+                               port->flags |= IFM_IPV6_ENABLED;
+                       }
+                       ip6conf->next = (ipv6list_t *) port->ipv6_list;
+                       port->ipv6_list = (ipv6list_t *) ip6conf;
+                       if (ifm_debug & IFM_DEBUG_LOCKS)
+                               RTE_LOG(INFO, IFM,
+                                       "%s: Releasing lock @ %d\n\r",
+                                       __FUNCTION__, __LINE__);
+
+                       if (USE_RTM_LOCKS) {
+                               rtm_unlock();
+                       } else {
+                               rte_rwlock_write_unlock(&rwlock);
+                       }
+                       return 0;
+               }
+       }
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Releasing lock @ %d\n\r", __FUNCTION__,
+                       __LINE__);
+
+       if (USE_RTM_LOCKS) {
+               rtm_unlock();
+       } else {
+               rte_rwlock_write_unlock(&rwlock);
+       }
+       return -1;
+}
+
+int16_t ifm_remove_ipv6_port(uint8_t port_id, uint32_t ip6addr,
+                                               uint32_t addrlen)
+{
+       l2_phy_interface_t *port;
+       ipv6list_t *ip6list, *previp6list = NULL;
+
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Acquiring lock @ %d\n\r", __FUNCTION__,
+                       __LINE__);
+       if (USE_RTM_LOCKS)
+               rtm_lock();
+       else
+               rte_rwlock_write_lock(&rwlock);
+       port = ifm.port_list[port_id];
+       if (port == NULL) {
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS) {
+                       rtm_unlock();
+               } else {
+                       rte_rwlock_write_unlock(&rwlock);
+               }
+               RTE_LOG(ERR, IFM,
+                       "%s: Port %u info not found... configure it first.\n\r",
+                       __FUNCTION__, port_id);
+       }
+       if (port != NULL && port->pmdid == port_id) {
+               if (port->ipv6_list == NULL) {
+                       if (ifm_debug & IFM_DEBUG_LOCKS)
+                               RTE_LOG(INFO, IFM,
+                                       "%s: Releasing lock @ %d\n\r",
+                                       __FUNCTION__, __LINE__);
+
+                       if (USE_RTM_LOCKS) {
+                               rtm_unlock();
+                       } else {
+                               rte_rwlock_write_unlock(&rwlock);
+                       }
+                       return -1;
+               }
+               ip6list = (ipv6list_t *) port->ipv6_list;
+               while (ip6list != NULL) {
+                       if (addrlen == ip6list->addrlen &&
+                                       memcpy(&ip6list->ipaddr, &ip6addr, addrlen)) {
+                               if (ip6list == port->ipv6_list) {
+                                       port->ipv6_list = ip6list->next;
+                               } else {
+                                       if (previp6list != NULL)
+                                               previp6list->next =
+                                                               ip6list->next;
+                               }
+                               port->flags &= ~IFM_IPV6_ENABLED;
+                               rte_free(ip6list);
+                               if (ifm_debug & IFM_DEBUG_LOCKS)
+                                       RTE_LOG(INFO, IFM,
+                                               "%s: Releasing lock @ %d\n\r",
+                                               __FUNCTION__, __LINE__);
+
+                               if (USE_RTM_LOCKS) {
+                                       rtm_unlock();
+                               } else {
+                                       rte_rwlock_write_unlock(&rwlock);
+                               }
+                               return 0;
+                       } else {
+                               previp6list = ip6list;
+                               ip6list = ip6list->next;
+                       }
+               }
+       }
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Releasing lock @ %d\n\r", __FUNCTION__,
+                       __LINE__);
+       if (USE_RTM_LOCKS)
+               rtm_unlock();
+       else
+               rte_rwlock_write_unlock(&rwlock);
+       return -1;
+}
+
+int32_t ifm_chk_port_ipv4_enabled(uint8_t port_id)
+{
+       l2_phy_interface_t *port;
+
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Acquiring RD lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS)
+               rtm_lock();
+       else
+               rte_rwlock_read_lock(&rwlock);
+       port = ifm.port_list[port_id];
+       if (port == NULL) {
+               RTE_LOG(ERR, IFM,
+                       "%s: Port %u info not found... configure it first.\n\r",
+                       __FUNCTION__, port_id);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS)
+                       rtm_unlock();
+               else
+                       rte_rwlock_read_unlock(&rwlock);
+               return IFM_FAILURE;
+       }
+       if ((port->flags & IFM_IPV4_ENABLED) == 0) {
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS)
+                       rtm_unlock();
+               else
+                       rte_rwlock_read_unlock(&rwlock);
+               return 0;
+       } else {
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS)
+                       rtm_unlock();
+               else
+                       rte_rwlock_read_unlock(&rwlock);
+               return 1;
+       }
+}
+
+int32_t ifm_chk_port_ipv6_enabled(uint8_t port_id)
+{
+       l2_phy_interface_t *port;
+
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Acquiring RD lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS)
+               rtm_lock();
+       else
+               rte_rwlock_read_lock(&rwlock);
+
+       port = ifm.port_list[port_id];
+       if (port == NULL) {
+               if (ifm_debug & IFM_DEBUG)
+                       RTE_LOG(ERR, IFM, "%s: Port %u info not found..."
+                               " configure it first.\n\r",
+                               __FUNCTION__, port_id);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing RD lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS)
+                       rtm_unlock();
+               else
+                       rte_rwlock_read_unlock(&rwlock);
+               return IFM_FAILURE;
+       }
+       if ((port->flags & IFM_IPV6_ENABLED) == 0) {
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing RD lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS)
+                       rtm_unlock();
+               else
+                       rte_rwlock_read_unlock(&rwlock);
+               return 0;
+       } else {
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing RD lock @ %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS)
+                       rtm_unlock();
+               else
+                       rte_rwlock_read_unlock(&rwlock);
+               return 1;
+       }
+}
+
+void ifm_register_for_linkupdate(uint32_t clientid,
+                                void (*cb_linkupdate) (uint8_t, unsigned int))
+{
+       ifm.if_client[ifm.nclient].cb_linkupdate = cb_linkupdate;
+       ifm.if_client[ifm.nclient].clientid = clientid;
+       ifm.nclient++;
+}
+
+int ifm_port_setup(uint8_t port_id, port_config_t *pconfig)
+{
+       int status, sock;
+       char buf[12];
+       struct rte_eth_dev_info dev_info;
+       struct rte_eth_link linkstatus;
+       l2_phy_interface_t *port = NULL;
+
+       if (!ifm.nport_intialized) {
+               RTE_LOG(ERR, IFM, "%s: Failed to configure port %u. 0 ports"
+                       "were intialized during PCI probe...\n\r",
+                       __FUNCTION__, port_id);
+               return IFM_FAILURE;
+       }
+       if (ifm_debug & IFM_DEBUG_CONFIG)
+               RTE_LOG(INFO, IFM, "%s: Configuring port %u with "
+                       "nrxq: %u, ntxq: %u\n\r", __FUNCTION__,
+                       port_id, pconfig->nrx_queue, pconfig->ntx_queue);
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Acquiring WR lock1 @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS)
+               rtm_lock();
+       else
+               rte_rwlock_write_lock(&rwlock);
+
+       if (ifm.port_list[port_id] == NULL) {
+               ifm.port_list[port_id] =
+                               (l2_phy_interface_t *) rte_zmalloc(NULL,
+                                                                        sizeof
+                                                                        (l2_phy_interface_t),
+                                                                        RTE_CACHE_LINE_SIZE);
+               ifm.port_list[port_id]->pmdid = port_id;
+       }
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Releasing WR lock1 @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS)
+               rtm_unlock();
+       else
+               rte_rwlock_write_unlock(&rwlock);
+
+       rte_eth_link_get(port_id, &linkstatus);
+       if (linkstatus.link_status) {
+               if (ifm_debug & IFM_DEBUG_CONFIG) {
+                       RTE_LOG(INFO, IFM, "%s: %u is up.Stop it before"
+                               " reconfiguring.\n\r", __FUNCTION__, port_id);
+               }
+               rte_eth_dev_stop(port_id);
+       }
+       /*Configure an Ethernet device. rets 0 on success queue */
+       status = rte_eth_dev_configure(port_id, pconfig->nrx_queue,
+                                                        pconfig->ntx_queue, &pconfig->port_conf);
+       if (status < 0) {
+               ifm_remove_port_details(port_id);
+               RTE_LOG(ERR, IFM, "%s: rte_eth_dev_configure is failed"
+                       "for port %u.\n\r", __FUNCTION__, port_id);
+               return IFM_FAILURE;
+       }
+       status = rte_eth_dev_callback_register(port_id,
+                                                                RTE_ETH_EVENT_INTR_LSC,
+                                                                lsi_event_callback, NULL);
+       if (status < 0) {
+               ifm_remove_port_details(port_id);
+               RTE_LOG(ERR, IFM, "%s: rte_eth_dev_callback_register()"
+                       " failed for port %u.\n\r", __FUNCTION__, port_id);
+               return IFM_FAILURE;
+       }
+       /*promiscuous mode is enabled set it */
+       if (pconfig->promisc)
+               rte_eth_promiscuous_enable(port_id);
+
+       sock = rte_eth_dev_socket_id(port_id);
+       if (sock == -1)
+               RTE_LOG(ERR, IFM, "%s: Warning: rte_eth_dev_socket_id,"
+                       " port_id value is"
+                       "out of range %u\n\r", __FUNCTION__, port_id);
+       /*Port initialization */
+       int ntxqs;
+       for (ntxqs = 0; ntxqs < pconfig->ntx_queue; ntxqs++) {
+               status = rte_eth_tx_queue_setup(port_id, ntxqs,
+                                               IFM_TX_DESC_DEFAULT, sock,
+                                               &(pconfig->tx_conf));
+               if (status < 0) {
+                       ifm_remove_port_details(port_id);
+                       RTE_LOG(ERR, IFM, "%s: rte_eth_tx_queue_setup failed"
+                               " for port %u\n\r", __FUNCTION__, port_id);
+                       return IFM_FAILURE;
+               }
+       }
+       port = ifm_get_port(port_id);
+       if (port == NULL) {
+               RTE_LOG(INFO, IFM, "%s: Port is NULL @ %d\n\r", __FUNCTION__,
+                       __LINE__);
+               return IFM_FAILURE;
+       }
+
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Acquiring WR lock 2 @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS)
+               rtm_lock();
+       else
+               rte_rwlock_write_lock(&rwlock);
+
+       if (port->tx_buf_len == 0) {
+               port->tx_buf_len = RTE_ETH_TX_BUFFER_SIZE(IFM_BURST_SIZE);
+       }
+       port->tx_buffer = rte_zmalloc_socket("tx_buffer", port->tx_buf_len, 0,
+                                                        rte_eth_dev_socket_id(port_id));
+
+       if (port->tx_buffer == NULL) {
+               ifm_remove_port_details(port_id);
+               RTE_LOG(ERR, IFM, "%s: Failed to allocate tx buffers for"
+                       " port %u\n\r", __FUNCTION__, port_id);
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock2 %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS)
+                       rtm_unlock();
+               else
+                       rte_rwlock_write_unlock(&rwlock);
+               return IFM_FAILURE;
+       }
+       rte_eth_tx_buffer_init(port->tx_buffer, IFM_BURST_SIZE);
+
+       sprintf(buf, "MEMPOOL%d", port_id);
+       port->mempool = rte_mempool_create(buf,
+                                                pconfig->mempool.pool_size,
+                                                pconfig->mempool.buffer_size,
+                                                pconfig->mempool.cache_size,
+                                                sizeof(struct
+                                                       rte_pktmbuf_pool_private),
+                                                rte_pktmbuf_pool_init, NULL,
+                                                rte_pktmbuf_init, NULL, sock, 0);
+       if (port->mempool == NULL) {
+               ifm_remove_port_details(port_id);
+               RTE_LOG(ERR, IFM, "%s: rte_mempool_create is failed for port"
+                       " %u. Error: %s\n\r",
+                       __FUNCTION__, port_id, rte_strerror(rte_errno));
+               if (ifm_debug & IFM_DEBUG_LOCKS)
+                       RTE_LOG(INFO, IFM, "%s: Releasing WR lock2 %d\n\r",
+                               __FUNCTION__, __LINE__);
+               if (USE_RTM_LOCKS)
+                       rtm_unlock();
+               else
+                       rte_rwlock_write_unlock(&rwlock);
+               return IFM_FAILURE;
+       }
+       int nrxqs;
+       for (nrxqs = 0; nrxqs < pconfig->nrx_queue; nrxqs++) {
+               status = rte_eth_rx_queue_setup(port_id, nrxqs,
+                                               IFM_RX_DESC_DEFAULT, sock,
+                                               &(pconfig->rx_conf),
+                                               port->mempool);
+               if (status < 0) {
+                       ifm_remove_port_details(port_id);
+                       RTE_LOG(ERR, IFM,
+                               "%s: rte_eth_rx_queue_setup is failed "
+                               "for port %u queue %u. Error: %s\n\r",
+                               __FUNCTION__, port_id, nrxqs,
+                               rte_strerror(rte_errno));
+                       if (ifm_debug & IFM_DEBUG_LOCKS)
+                               RTE_LOG(INFO, IFM,
+                                       "%s: Releasing WR lock2 %d\n\r",
+                                       __FUNCTION__, __LINE__);
+                       if (USE_RTM_LOCKS)
+                               rtm_unlock();
+                       else
+                               rte_rwlock_write_unlock(&rwlock);
+                       return IFM_FAILURE;
+               }
+       }
+       /*Start link */
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Releasing WR lock2  @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS)
+               rtm_unlock();
+       else
+               rte_rwlock_write_unlock(&rwlock);
+       status = rte_eth_dev_start(port_id);
+       if (status < 0) {
+               ifm_remove_port_details(port_id);
+               RTE_LOG(ERR, IFM, "%s: rte_eth_dev_start is failed for"
+                       " port %u.\n\r", __FUNCTION__, port_id);
+               return IFM_FAILURE;
+       }
+       rte_delay_ms(5000);
+       /*Get device info and populate interface structure */
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Acquiring WR lock3 @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS)
+               rtm_lock();
+       else
+               rte_rwlock_write_lock(&rwlock);
+       rte_eth_macaddr_get(port_id, (struct ether_addr *)port->macaddr);
+       if (pconfig->promisc)
+               port->promisc = 1;
+       rte_eth_link_get(port_id, &linkstatus);
+       /*Link status */
+       port->link_duplex = linkstatus.link_duplex;
+       port->link_autoneg = linkstatus.link_autoneg;
+       port->link_speed = linkstatus.link_speed;
+       port->admin_status = pconfig->state;
+
+       /*Get dev_info */
+       memset(&dev_info, 0, sizeof(dev_info));
+       rte_eth_dev_info_get(port_id, &dev_info);
+       port->min_rx_bufsize = dev_info.min_rx_bufsize;
+       port->max_rx_pktlen = dev_info.max_rx_pktlen;
+       port->max_rx_queues = dev_info.max_rx_queues;
+       port->max_tx_queues = dev_info.max_tx_queues;
+       rte_eth_dev_get_mtu(port_id, &(port->mtu));
+
+       /*Add rx and tx packet function ptrs */
+       port->retrieve_bulk_pkts = &ifm_receive_bulk_pkts;
+       port->transmit_bulk_pkts = &ifm_transmit_bulk_pkts;
+       port->transmit_single_pkt = &ifm_transmit_single_pkt;
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Releasing WR3 lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS)
+               rtm_unlock();
+       else
+               rte_rwlock_write_unlock(&rwlock);
+       RTE_LOG(INFO, IFM, "%s: Port %u is successfully configured.\n\r",
+               __FUNCTION__, port_id);
+       return IFM_SUCCESS;
+}
+
+int ifm_configure_ports(port_config_t *pconfig)
+{
+       uint8_t port_id;
+       int status = 0;
+       if (!ifm.nport_intialized) {
+               RTE_LOG(ERR, IFM, "%s, Configuring ports failed. Zero ports "
+                       "are intialized during PCI probe", __FUNCTION__);
+               return IFM_FAILURE;
+       }
+       if (pconfig == NULL) {
+               RTE_LOG(ERR, IFM, "%s, Configuring ports failed. "
+                       "Param pconfig is NULL\n\r", __FUNCTION__);
+               return IFM_FAILURE;
+       }
+
+       /*Initialize all ports */
+       for (port_id = 0; port_id < ifm.nport_intialized; port_id++) {
+               if (ifm_debug & IFM_DEBUG_CONFIG)
+                       RTE_LOG(INFO, IFM, "Call ifm_port_setup %u\n\r",
+                               port_id);
+               status =
+                               ifm_port_setup(pconfig[port_id].port_id, &pconfig[port_id]);
+               if (status == IFM_SUCCESS)
+                       ifm.nport_configured++;
+       }
+       if (!ifm.nport_configured) {
+               RTE_LOG(ERR, IFM, "%s: Zero ports are configured\n\r",
+                       __FUNCTION__);
+               return IFM_FAILURE;
+       }
+       RTE_LOG(INFO, IFM, "%s: Number of ports sucessfully configured:"
+               " %d\n\r", __FUNCTION__, ifm.nport_configured);
+       return IFM_SUCCESS;
+}
+
+void print_interface_details(void)
+{
+       l2_phy_interface_t *port;
+       int i = 0;
+       struct sockaddr_in ip;
+       printf("\n\r");
+
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Acquiring RW lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS)
+               rtm_lock();
+       else
+               rte_rwlock_read_lock(&rwlock);
+
+       for (i = 0; i < RTE_MAX_ETHPORTS && ifm.port_list[i]; i++) {
+               port = ifm.port_list[i];
+               printf(" %u", port->pmdid);
+               if (port->ifname && strlen(port->ifname)) {
+                       printf(" (%s)\t", port->ifname);
+               } else
+                       printf("\t\t");
+               printf("MAC:%02x:%02x:%02x:%02x:%02x:%02x Adminstate:%s"
+                                        " Operstate:%s \n\r",
+                                        port->macaddr[0], port->macaddr[1],
+                                        port->macaddr[2], port->macaddr[3],
+                                        port->macaddr[4], port->macaddr[5],
+                                        port->admin_status ? "UP" : "DOWN",
+                                        port->link_status ? "UP" : "DOWN");
+               printf("\t\t");
+               printf("Speed: %u, %s-duplex\n\r", port->link_speed,
+                                        port->link_duplex ? "full" : "half");
+               printf("\t\t");
+
+               if (port->ipv4_list != NULL) {
+                       ip.sin_addr.s_addr =
+                                       (unsigned long)((ipv4list_t *) (port->ipv4_list))->
+                                       ipaddr;
+                       printf("IP: %s/%d", inet_ntoa(ip.sin_addr),
+                                                ((ipv4list_t *) (port->ipv4_list))->addrlen);
+               } else {
+                       printf("IP: NA");
+               }
+
+               printf("\r\n");
+               printf("\t\t");
+               if (port->ipv6_list != NULL) {
+                       uint8_t *addr =
+                                       ((ipv6list_t *) (port->ipv6_list))->ipaddr;
+                       printf
+                                       ("IPv6: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
+                                        addr[0], addr[1], addr[2], addr[3], addr[4],
+                                        addr[5], addr[6], addr[7], addr[8], addr[9],
+                                        addr[10], addr[11], addr[12], addr[13], addr[14],
+                                        addr[15]);
+               } else {
+                       printf("IPv6: NA");
+               }
+
+               if (port->flags & IFM_SLAVE) {
+                       printf("  IFM_SLAVE ");
+                       printf(" MasterPort: %u",
+                                                port->bond_config->bond_portid);
+               }
+               if (port->flags & IFM_MASTER) {
+                       printf("  IFM_MASTER ");
+                       printf("  Mode: %u", port->bond_config->mode);
+                       printf("  PrimaryPort: %u", port->bond_config->primary);
+                       printf("\n\r");
+                       printf("\t\tSlavePortCount: %u",
+                                                port->bond_config->slave_count);
+                       printf(" SlavePorts:");
+                       int i;
+                       for (i = 0; i < port->bond_config->slave_count; i++) {
+                               printf(" %u ", port->bond_config->slaves[i]);
+                       }
+                       printf(" ActivePortCount: %u",
+                                                port->bond_config->active_slave_count);
+                       printf(" ActivePorts:");
+                       for (i = 0; i < port->bond_config->active_slave_count;
+                                        i++) {
+                               printf(" %u ",
+                                                        port->bond_config->active_slaves[i]);
+                       }
+                       printf("\n\r");
+                       printf("\t\t");
+                       printf("Link_monitor_freq: %u ms ",
+                                                port->bond_config->internal_ms);
+                       printf(" Link_up_prop_delay: %u ms ",
+                                                port->bond_config->link_up_delay_ms);
+                       printf(" Link_down_prop_delay: %u ms ",
+                                                port->bond_config->link_down_delay_ms);
+                       printf("\n\r");
+                       printf("\t\t");
+                       printf("Xmit_policy: %u",
+                                                port->bond_config->xmit_policy);
+               }
+               printf("\n\r");
+               printf("\t\t");
+               printf("n_rxpkts: %" PRIu64 " ,n_txpkts: %" PRIu64 " ,",
+                                        port->n_rxpkts, port->n_txpkts);
+               struct rte_eth_stats eth_stats;
+               rte_eth_stats_get(port->pmdid, &eth_stats);
+               printf("pkts_in: %" PRIu64 " ,", eth_stats.ipackets);
+               printf("pkts_out: %" PRIu64 " ", eth_stats.opackets);
+               printf("\n\r");
+               printf("\t\t");
+               printf("in_errs: %" PRIu64 " ,", eth_stats.ierrors);
+               printf("in_missed: %" PRIu64 " ,", eth_stats.imissed);
+               printf("out_errs: %" PRIu64 " ,", eth_stats.oerrors);
+               printf("mbuf_errs: %" PRIu64 " ", eth_stats.rx_nombuf);
+               printf("\n\r");
+               printf("\n\r");
+       }
+       if (ifm_debug & IFM_DEBUG_LOCKS)
+               RTE_LOG(INFO, IFM, "%s: Releasing RW lock @ %d\n\r",
+                       __FUNCTION__, __LINE__);
+       if (USE_RTM_LOCKS)
+               rtm_unlock();
+       else
+               rte_rwlock_read_unlock(&rwlock);
+}
diff --git a/common/VIL/l2l3_stack/interface.h b/common/VIL/l2l3_stack/interface.h
new file mode 100644 (file)
index 0000000..0f654fa
--- /dev/null
@@ -0,0 +1,873 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef INTERFACE_H
+#define INTERFACE_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <netinet/in.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <rte_common.h>
+#include <rte_log.h>
+#include <rte_malloc.h>
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+#include <rte_memzone.h>
+#include <rte_eal.h>
+#include <rte_per_lcore.h>
+#include <rte_launch.h>
+#include <rte_atomic.h>
+#include <rte_cycles.h>
+#include <rte_prefetch.h>
+#include <rte_lcore.h>
+#include <rte_per_lcore.h>
+#include <rte_branch_prediction.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_random.h>
+#include <rte_debug.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_ring.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include <rte_eth_ctrl.h>
+#include <rte_errno.h>
+#include <rte_port_ethdev.h>
+#include <rte_eth_bond.h>
+#include <rte_rwlock.h>
+
+#define RTE_LOGTYPE_IFM RTE_LOGTYPE_USER1
+#define IFM_SUCCESS  0
+#define IFM_FAILURE -1
+/*
+ * IFM Ether link related macros
+ */
+#define IFM_ETH_LINK_HALF_DUPLEX    0
+#define IFM_ETH_LINK_FULL_DUPLEX    1
+#define IFM_ETH_LINK_DOWN           0
+#define IFM_ETH_LINK_UP             1
+#define IFM_ETH_LINK_FIXED          0
+
+/*
+ *  Bonding
+ */
+#define IFM_SLAVE                   (1<<0)
+#define IFM_MASTER                  (1<<1)
+#define IFM_BONDED                  (1<<2)
+#define IFM_IPV4_ENABLED                       (1<<3)
+#define IFM_IPV6_ENABLED                       (1<<4)
+
+#define IFM_BONDING_MODE_ROUND_ROBIN   0
+#define IFM_BONDING_MODE_ACTIVE_BACKUP 1
+#define IFM_BONDING_MODE_BALANCE       2
+#define IFM_BONDING_MODE_BROADCAST     3
+#define IFM_BONDING_MODE_8023AD        4
+#define IFM_BONDING_MODE_TLB           5
+#define IFM_BONDING_MODE_ALB           6
+
+#define IFM_BALANCE_XMIT_POLICY_LAYER2   0
+#define IFM_BALANCE_XMIT_POLICY_LAYER23  1
+#define IFM_BALANCE_XMIT_POLICY_LAYER34  2
+/*
+ * Queue related macros
+ */
+#define IFM_QUEUE_STAT_CNTRS   16
+#define IFM_TX_DEFAULT_Q       0
+#define IFM_RX_DEFAULT_Q       0
+#define IFM_RX_DESC_DEFAULT    128
+#define IFM_TX_DESC_DEFAULT    512
+#define IFM_BURST_SIZE         32
+#define IFM_BURST_TX_WAIT_US   1
+#define IFM_BURST_TX_RETRIES   64
+#define BURST_TX_DRAIN_US      100
+
+/*
+ * Misc
+ */
+#define IFM_IFNAME_LEN                 16
+#define IFM_CLIENT_NAME                20
+#define IFM_MAX_CLIENT                 10
+
+#define IFM_ETHER_ADDR_SIZE    6
+#define IFM_IPV6_ADDR_SIZE     16
+
+#define IFM_DEBUG_CONFIG        (1<<0)
+#define IFM_DEBUG_RXTX          (1<<1)
+#define IFM_DEBUG_LOCKS         (1<<2)
+#define IFM_DEBUG              (1<<4)
+#define IFM_MAX_PORTARR_SZ 64
+#define IFM_MAX_PORTARR_SZ 64
+/**
+ * Mempool configuration details:
+ * Stores the mempool configuration information for the port.
+ */
+struct mempool_config {
+       uint32_t pool_size;/**< The number of elements in the mempool.*/
+       uint32_t buffer_size;
+                                /**< The size of an element*/
+       uint32_t cache_size;
+                                /**< Cache size */
+       uint32_t cpu_socket_id;
+                                /**< The socket identifier in the case of NUMA.*/
+} __rte_cache_aligned;
+
+/**
+ * Port configuration:
+ * Stores the configuration information for the port.
+ * This structure is used during port and tx/rx queue setup.
+ */
+typedef struct _port_config_ {
+       uint8_t port_id;                        /**< port id or pmd id to be configured */
+       int nrx_queue;                          /**< no of rx queues */
+       int ntx_queue;                          /**< no of tx queues */
+       uint32_t tx_buf_size;
+       uint32_t state;                         /**< noshut/shut the admin state of the port*/
+       uint32_t promisc;                       /**< enable/diable promisc mode*/
+       struct mempool_config mempool;
+                                               /**< Mempool configurations */
+       struct rte_eth_conf port_conf;
+                                               /**< port configuration */
+       struct rte_eth_rxconf rx_conf;
+                                               /**< rx queue configurations */
+       struct rte_eth_txconf tx_conf;
+                                               /**< tx queue configurations */
+} port_config_t;
+
+/**
+ * Port statistics:
+ * if_stats structure is a member variable of structure l2_phy_interface_t.
+ * Used to maintain stats retreived from rte_eth_stats structure.
+ */
+typedef struct _if_stats_ {
+       uint64_t rx_npkts;/**< Total number of successfully received packets.*/
+       uint64_t tx_npkts;/**< Total number of successfully transmitted bytes. */
+       uint64_t rx_bytes;/**< Total number of successfully received bytes.*/
+       uint64_t tx_bytes;/**< Total number of successfully transmitted bytes.*/
+       uint64_t rx_missed_pkts;
+                                                /**< no of packets dropped by hw due because rx queues are full*/
+       uint64_t rx_err_pkts;/**< Total number of erroneous received packets. */
+       uint64_t rx_nobuf_fail;/**< Total number of RX mbuf allocation failures. */
+       uint64_t tx_failed_pkts;/**< Total number of failed transmitted packets.*/
+       uint64_t q_rxpkts[IFM_QUEUE_STAT_CNTRS];/**< Total number of queue RX packets.*/
+       uint64_t q_txpkts[IFM_QUEUE_STAT_CNTRS];/**< Total number of queue TX packets.*/
+       uint64_t q_rx_bytes[IFM_QUEUE_STAT_CNTRS];
+                                                /**< Total number of successfully received queue bytes.*/
+       uint64_t q_tx_bytes[IFM_QUEUE_STAT_CNTRS];
+                                                /**< Total number of successfully transmitted queue bytes.*/
+       uint64_t q_rx_pkt_drop[IFM_QUEUE_STAT_CNTRS];
+                                                               /**<Total number of queue packets received that are dropped.*/
+} __rte_cache_aligned if_stats;
+/**
+ * structure to store bond port information
+ */
+struct bond_port {
+       uint8_t bond_portid;
+                                       /**<portid of the bond port.*/
+       uint8_t socket_id;
+                               /**<socketid of the port.*/
+       uint8_t mode;
+                                /**<mode config.*/
+       uint8_t xmit_policy;
+                                       /**<xmit policy for this port.*/
+       uint32_t internal_ms;
+                                        /**<in frequency.*/
+       uint32_t link_up_delay_ms;
+                                /**<frequency of informing linkup delay.*/
+       uint32_t link_down_delay_ms;
+                                               /**<frequency of informing linkdown delay.*/
+       uint8_t primary;
+                       /**<primary port of this bond.*/
+       uint8_t slaves[RTE_MAX_ETHPORTS];
+                                        /**<list of slaves*/
+       int slave_count;
+                /**<slave count.*/
+       uint8_t active_slaves[RTE_MAX_ETHPORTS];
+                                        /**<list of active slaves.*/
+       int active_slave_count;
+                       /**<cnt of active slave.*/
+} __rte_cache_aligned;
+
+/**
+ * Physical port details:
+ * Used to store information about configured port.
+ * Most of the member variables in this structure are populated
+ * from struct rte_eth_dev_info
+ */
+typedef struct _l2_phy_interface_ {
+       struct _l2_phy_interface_ *next;                                 /**< pointer to physical interface list */
+       uint8_t pmdid;                                                   /**< populated from rth_eth_dev_info */
+       unsigned int if_index;                                           /**< populated from rth_eth_dev_info */
+       char ifname[IFM_IFNAME_LEN];                                     /**< populated from rth_eth_dev_info */
+       uint16_t mtu;                                                    /**< mtu value - configurable */
+       uint8_t macaddr[IFM_ETHER_ADDR_SIZE];                           /**< Ether addr*/
+       uint32_t promisc;                                                /**< promisc mode - configurable*/
+       uint32_t flags;                                                  /**< Used for link bonding */
+       /* Link status */
+       uint32_t link_speed;                                             /**< line speed */
+       uint16_t link_duplex:1;                                          /**< duplex mode */
+       uint16_t link_autoneg:1;                                         /**< auto negotiation*/
+       uint16_t link_status:1;                                          /**< operational status */
+       uint16_t admin_status:1;                                         /**< Admin status of a port*/
+       /* queue details */
+       struct rte_mempool *mempool;                                     /**< HW Q*/
+       uint32_t min_rx_bufsize;                                         /**< rx buffer size supported */
+       uint32_t max_rx_pktlen;                                          /**< max size of packet*/
+       uint16_t max_rx_queues;                                          /**< max number of rx queues supported */
+       uint16_t max_tx_queues;                                          /**< max number queues supported*/
+       uint64_t n_rxpkts;                                               /**< number of packets received */
+       uint64_t n_txpkts;                                               /**< number of packets transmitted */
+       if_stats stats;                                                  /**< port stats - populated from rte_eth_ifstats */
+        uint16_t(*retrieve_bulk_pkts) (uint8_t, uint16_t, struct rte_mbuf **);
+                                                                               /**< pointer to read packets*/
+        uint16_t(*transmit_bulk_pkts) (struct _l2_phy_interface_ *, struct rte_mbuf **, uint64_t);
+                                                               /**< pointer to transmit the bulk of packets */
+       int (*transmit_single_pkt) (struct _l2_phy_interface_ *, struct rte_mbuf *);
+                                                               /**< pointer to transmit the a single packet*/
+       struct rte_eth_dev_tx_buffer *tx_buffer;
+       uint64_t tx_buf_len;                                             /**< number of packets in tx_buf */
+       void *ipv4_list;                                                 /**< pointer to ip list */
+       void *ipv6_list;                        /**< pointer to ipv6 list */
+       struct bond_port *bond_config;                  /**< pointer to bond info*/
+       port_config_t port_config;
+} __rte_cache_aligned l2_phy_interface_t;
+
+/**
+ * Port IPv4 address details:
+ * Used to maintain IPv4 information of a port.
+ */
+typedef struct _ipv4list_ {
+       struct _ipv4list_ *next;/**< pointer to IPv4 list */
+       uint32_t ipaddr;        /**< Configured ipv4 address */
+       unsigned int addrlen;   /**< subnet mask or addrlen */
+       unsigned int mtu;       /**< IPv6 mtu*/
+       l2_phy_interface_t *port;
+                               /**< pointer to a port on which this ipaddr is configured*/
+} ipv4list_t;
+
+/**
+ * Port IPv6 address details:
+ * Used to maintain IPv6 information of a port.
+ */
+typedef struct _ipv6list_ {
+       struct _ipv6list_ *next;                         /**< Ptr IPv6 list */
+       uint8_t ipaddr[IFM_IPV6_ADDR_SIZE];              /**< Configured ipv6 address */
+       unsigned int addrlen;                            /**< subnet mask or addrlen*/
+       unsigned int mtu;                               /**< IPv6 mtu*/
+       l2_phy_interface_t *port;                        /**< ptr to a port on whicch ipv6 addr is configured*/
+} ipv6list_t;
+
+/**
+ * Interface Manager client details:
+ * Maintains information about clients who registered for link status update.
+ * Stores callback function to be called in case of link state change.
+ */
+typedef struct _ifm_client_ {
+       uint32_t clientid;                                       /**< unique client id identifies the client used for indexing*/
+       void (*cb_linkupdate) (uint8_t, unsigned int);
+                                                                /**< callback function to be triggered during an event*/
+} __rte_cache_aligned ifm_client;
+
+/**
+ * Interface manager global structure:
+ * IFM main structure has pointer configured port list.
+ */
+typedef struct _interface_main_ {
+       l2_phy_interface_t *port_list[IFM_MAX_PORTARR_SZ];
+       uint32_t nport_configured;                       /**< no of ports sucessfully configured during PCI probe*/
+       uint32_t nport_intialized;                       /**< no of ports sucessfully initialized through ifm_init*/
+       uint8_t nclient;                                 /**< no of clients registered for Interface manager events*/
+       ifm_client if_client[IFM_MAX_CLIENT];            /**< Array of interface manager client details*/
+} __rte_cache_aligned interface_main_t;
+
+/**
+ * Init function of Interface manager. Calls port_setup function for every port.
+ *
+ * @param *pconfig
+ *   A pointer to port_config_t contains port configuration.
+ *
+ * @returns
+ *    IFM_SUCCESS - On success.
+ *    IFM_FAILURE - On Failure.
+ */
+int ifm_configure_ports(port_config_t *pconfig);
+
+/**
+ * Returns first port from port list.
+ *
+ * @param
+ *     None
+ *
+ * @returns
+ *    On success - Returns a pointer to first port in the list of
+ *                 type l2_phy_interface_t.
+ *    NULL - On Failure.
+ */
+l2_phy_interface_t *ifm_get_first_port(void);
+
+/**
+ * Get a port from the physical port list which is next node to
+ * the given portid in the list.
+ *
+ * @param portid
+ *   A pmdid of port.
+ *
+ * @returns
+ *    On success - Returns a pointer to next port in the list of
+ *                 type l2_phy_interface_t.
+ *    NULL - On Failure.
+ */
+l2_phy_interface_t *ifm_get_next_port(uint8_t port_id);
+
+/**
+ * Get a pointer to port for the given portid from the physical port list.
+ *
+ * @param portid
+ *   A pmd id of the port.
+ *
+ * @returns
+ *    On success - returns pointer to l2_phy_interface_t.
+ *    NULL - On Failure.
+ */
+l2_phy_interface_t *ifm_get_port(uint8_t);
+
+/**
+ * Get a pointer to port for the given port name from the physical port list.
+ *
+ * @param name
+ *   Name of the port
+ *
+ * @returns
+ *    On success - returns pointer to l2_phy_interface_t.
+ *    NULL - On Failure.
+ */
+l2_phy_interface_t *ifm_get_port_by_name(const char *name);
+/**
+ * Removes given port from the physical interface list.
+ *
+ * @params
+ *   portid - pmd_id of port.
+ * @returns
+ *   none
+ */
+void ifm_remove_port_details(uint8_t portid);
+
+/**
+ * Adds give port to the begining of physical interface list.
+ *
+ * @param l2_phy_interface_t *
+ *  pointer to l2_phy_interface_t.
+ * @returns
+ *   none
+ */
+void ifm_add_port_to_port_list(l2_phy_interface_t *);
+
+/**
+ * Checks whether the global physical port list is NULL.
+ *
+ * @returns
+ *     0 - On success.
+ *     1 - On Failure.
+ */
+int is_port_list_null(void);
+
+/**
+ * Configures the device port. Also sets tx and rx queue.
+ * Populates port structure and adds it physical interface list.
+ *
+ * @param portconfig
+ *   Contains configuration about rx queue, tx queue.
+ *
+ * @returns
+ *    IFM_SUCCESS - On success.
+ *    IFM_FAILURE - On Failure.
+ */
+int ifm_port_setup(uint8_t port_id, port_config_t *);
+
+/**
+ * Initializes interface manager main structure
+ * @params
+ *   none
+ * @returns
+ *   none
+ */
+void ifm_init(void);
+
+/**
+ * Returns number of ports initialized during pci probe.
+ *
+ * @params
+ *   void
+ *
+ * @returns
+ *    number of ports initialized - On success.
+ *    IFM_FAILURE - On Failure.
+ */
+int32_t ifm_get_nports_initialized(void);
+
+/**
+ * Returns number of ports initialized ifm_init.
+ *
+ * @params
+ *   void
+ *
+ * @returns
+ *    number of ports initialized - On success.
+ *    IFM_FAILURE - On Failure.
+ */
+int32_t ifm_get_nactive_ports(void);
+
+/**
+ * Checks whether port is ipv4 enabled.
+ *
+ * @param portid
+ *   A pmd id of the port.
+ *
+ * @returns
+ *    IFM_SUCCESS - On success.
+ *    IFM_FAILURE - On Failure.
+ */
+int32_t ifm_chk_port_ipv4_enabled(uint8_t port_id);
+
+/**
+ * Checks whether port is ipv6 enabled.
+ *
+ * @param portid
+ *   A pmd id of the port.
+ *
+ * @returns
+ *    IFM_SUCCESS - On success.
+ *    IFM_FAILURE - On Failure.
+ */
+int32_t ifm_chk_port_ipv6_enabled(uint8_t port_id);
+
+/**
+ * Remove ipv4 address from the given port.
+ *
+ * @param portid
+ *   A pmd id of the port.
+ * @param ipaddr
+ *   ipv4 address to be removed
+ * @param addrlen
+ *   ipv4 address length
+ *
+ * @returns
+ *     IFM_SUCCESS - On success.
+ *    IFM_FAILURE - On Failure.
+ */
+int16_t ifm_remove_ipv4_port(uint8_t port_id, uint32_t ipaddr,
+                                               uint32_t addrlen);
+
+/**
+ * Remove ipv6 address from the given port.
+ *
+ * @param portid
+ *   A pmd id of the port.
+ * @param ip6addr
+ *   ipv4 address to be removed
+ * @param addrlen
+ *   ipv4 address length
+ *
+ * @returns
+ *     IFM_SUCCESS - On success.
+ *    IFM_FAILURE - On Failure.
+ */
+int16_t ifm_remove_ipv6_port(uint8_t port_id, uint32_t ip6addr,
+                                               uint32_t addrlen);
+
+/**
+ * Add ipv4 address to the given port.
+ *
+ * @param portid
+ *   A pmd id of the port.
+ * @param ipaddr
+ *   ipv4 address to be configured
+ * @param addrlen
+ *   ipv4 address length
+ *
+ * @returns
+ *     IFM_SUCCESS - On success.
+ *    IFM_FAILURE - On Failure.
+ */
+int16_t ifm_add_ipv4_port(uint8_t port_id, uint32_t ipaddr, uint32_t addrlen);
+
+/**
+ * Add ipv6 address to the given port.
+ *
+ * @param portid
+ *   A pmd id of the port.
+ * @param ip6addr
+ *   ipv6 address to be configured
+ * @param addrlen
+ *   ipv4 address length
+ *
+ * @returns
+ *     IFM_SUCCESS - On success.
+ *    IFM_FAILURE - On Failure.
+ */
+int8_t ifm_add_ipv6_port(uint8_t port_id, uint8_t ip6addr[], uint32_t addrlen);
+
+/**
+ * Buffers the packet in the tx quueue.
+ *
+ * @param *port
+ *   pointer to the port.
+ * @param *tx_pkts
+ *   packet to be transmitted
+ *
+ * @returns
+ *     number of packets transmitted
+ */
+int ifm_transmit_single_pkt(l2_phy_interface_t *port,
+                                       struct rte_mbuf *tx_pkts);
+
+/**
+ * Transmit the packet
+ *
+ * @param *port
+ *   pointer to the port.
+ * @param *tx_pkts
+ *   packets to be transmitted
+ * @param npkts
+ *   number of packets to be transmitted
+ *
+ * @returns
+ *     number of packets transmitted
+ */
+uint16_t ifm_transmit_bulk_pkts(l2_phy_interface_t *, struct rte_mbuf **tx_pkts,
+                               uint64_t npkts);
+
+/**
+ * Receive burst of 32 packets
+ *
+ * @param portid
+ *   From which port we need to read packets
+ * @param qid
+ *   From which port we need to read packets
+ * @param npkts
+ *   mbuf in which read packets will be placed
+ *
+ * @returns
+ *     number of packets read
+ */
+uint16_t ifm_receive_bulk_pkts(uint8_t port_id, uint16_t qid,
+                                                struct rte_mbuf **rx_pkts);
+
+/**
+ * Enable or disable promiscmous mode
+ *
+ * @param portid
+ *   pmd id of the port
+ * @param enable
+ *   1 - enable, IFM_SUCCESS - disable
+ *
+ * @returns
+ *   none
+ */
+void ifm_set_port_promisc(uint8_t port_id, uint8_t enable);
+
+/**
+ * Enable or disable promiscmous mode
+ *
+ * @param portid
+ *   pmd id of the port
+ * @param enable
+ *   1 - enable, 0 - disable
+ *
+ * @returns
+ *   none
+ */
+void ifm_set_l2_interface_mtu(uint8_t port_id, uint16_t mtu);
+
+/**
+ * Set MTU value for the port
+ *
+ * @param portid
+ *   pmd id of the port
+ * @param mtu
+ *   MTU value
+ *
+ * @returns
+ *   none
+ */
+void ifm_update_linkstatus(uint8_t port_id, uint16_t linkstatus);
+
+/**
+ * Register for link state event
+ *
+ * @param clientid
+ *   Unique number identifies client.
+ * @param cb_linkupdate
+ *   Callback function which has to be called at time of event
+ *
+ * @returns
+ *   none
+ */
+void ifm_register_for_linkupdate(uint32_t clientid,
+                                void (*cb_linkupdate) (uint8_t, unsigned int));
+
+/**
+ * Callback which is triggered at the time of link state change which in turn triggers registered
+ * clients callback
+ *
+ * @param portid
+ *   pmd id of the port
+ * @param type
+ *   lsi event type
+ * @param
+ *   Currently not used
+ *
+ * @returns
+ *   none
+ */
+void lsi_event_callback(uint8_t port_id, enum rte_eth_event_type type,
+                       void *param);
+/*
+ * Prints list of interfaces
+ * @param vois
+ */
+void print_interface_details(void);
+/*
+ * Creates bond interface
+ * @Param name
+ *     name of bond port
+ * @Param mode
+ *     mode
+ * @Param portconf
+ *     port configuration to be applied
+ * @returns 0 on success and 1 on failure
+ */
+int ifm_bond_port_create(const char *name, int mode, port_config_t *portconf);
+/*
+ * Deletes bond interface
+ * @Param name
+ *     name of bond port
+ * @returns 0 on success and 1 on failure
+ */
+int ifm_bond_port_delete(const char *name);
+/*
+ * Addes a port as slave to bond
+ * @Param bonded_port_id
+ *     bond port id
+ * @Param slave_port_id
+ *     slave port s port id
+ * @returns 0 on success and 1 on failure
+ */
+int ifm_add_slave_port(uint8_t bonded_port_id, uint8_t slave_port_id);
+/*
+ * Removes a port as slave to bond
+ * @Param bonded_port_id
+ *     bond port id
+ * @Param slave_port_id
+ *     slave port s port id
+ * @returns 0 on success and 1 on failure
+ */
+int ifm_remove_slave_port(uint8_t bonded_port_id, uint8_t slave_port_id);
+/*
+ * Sets bond port 's mode
+ * @Param bonded_port_id
+ *      bond port id
+ * @Param mode
+ *      mode 0 ... 5
+ * @returns 0 on success and 1 on failure
+ */
+int set_bond_mode(uint8_t bonded_port_id, uint8_t mode);
+/*
+ * Get bond port 's mode
+ * @Param bonded_port_id
+ *      bond port id
+ * @returns mode value or -1 on failure
+ */
+int get_bond_mode(uint8_t bonded_port_id);
+/*
+ * Set a slave port to bond
+ * @Param bonded_port_id
+ *     bond port id
+ * @Param slave_port_id
+ *     slave port s port id
+ * @returns 0 on success and 1 on failure
+ */
+int set_bond_primary(uint8_t bonded_port_id, uint8_t slave_port_id);
+/*
+ * Get primary port of the bond
+ * @Param bonded_port_id
+ *     bond port id
+ * @returns port id of primary on success and 1 on failure
+ */
+int get_bond_primary_port(uint8_t bonded_port_id);
+/*
+ * Get slave count for the bond
+ * @Param bonded_port_id
+ *     bond port id
+ * @returns slave count on success and 1 on failure
+ */
+int get_bond_slave_count(uint8_t bonded_port_id);
+/*
+ * Get active slave count for the bond
+ * @Param bonded_port_id
+ *     bond port id
+ * @returns active slaves count on success and 1 on failure
+ */
+int get_bond_active_slave_count(uint8_t bonded_port_id);
+/*
+ * Get slaves in the bond
+ * @Param bonded_port_id
+ *     bond port id
+ * @Param slaves
+ *     array to save slave port
+ * @returns 0 on success and 1 on failure
+ */
+int get_bond_slaves(uint8_t bonded_port_id, uint8_t slaves[RTE_MAX_ETHPORTS]);
+/*
+ * Get active slaves in the bond
+ * @Param bonded_port_id
+ *     bond port id
+ * @Param slaves
+ *     array to save slave port
+ * @returns 0 on success and 1 on failure
+ */
+int get_bond_active_slaves(uint8_t bonded_port_id,
+                                uint8_t slaves[RTE_MAX_ETHPORTS]);
+/*
+ * Sets bond port 's mac address
+ * @Param bonded_port_id
+ *      bond port id
+ * @Param mode
+ *      mac_addr - mac addr
+ * @returns 0 on success and 1 on failure
+ */
+int set_bond_mac_address(uint8_t bonded_port_id, struct ether_addr *mac_addr);
+/*
+ * Sets bond port 's MAC
+ * @Param bonded_port_id
+ *      bond port id
+ * @returns 0 on success and 1 on failure
+ */
+int reset_bond_mac_addr(uint8_t bonded_port_id);
+int get_bond_mac(uint8_t bonded_port_id, struct ether_addr *macaddr);
+/*
+ * Sets bond port 's policy
+ * @Param bonded_port_id
+ *      bond port id
+ * @Param policy
+ *      xmit policy
+ * @returns 0 on success and 1 on failure
+ */
+int set_bond_xmitpolicy(uint8_t bonded_port_id, uint8_t policy);
+/*
+ * Get bond port 's xmit policy
+ * @Param bonded_port_id
+ *      bond port id
+ * @returns xmit policy value or -1 on failure
+ */
+int get_bond_xmitpolicy(uint8_t bonded_port_id);
+/*
+ * Sets bond port 's monitor frequency
+ * @Param bonded_port_id
+ *      bond port id
+ * @Param internal_ms
+ *      frequency in ms
+ * @returns 0 on success and 1 on failure
+ */
+int set_bond_link_montitor_frequency(uint8_t bonded_port_id,
+                                                uint32_t internal_ms);
+/*
+ * Get bond port 's monitor frequency
+ * @Param bonded_port_id
+ *      bond port id
+ * @returns frequency value or -1 on failure
+ */
+int get_bond_link_monitor_frequency(uint8_t bonded_port_id);
+/*
+ * Sets bond port 's link down delay
+ * @Param bonded_port_id
+ *      bond port id
+ * @Param delay_ms
+ *      delay time in ms
+ * @returns 0 on success and 1 on failure
+ */
+int set_bond_linkdown_delay(uint8_t bonded_port_id, uint32_t delay_ms);
+/*
+ * Get bond port 's link down delay
+ * @Param bonded_port_id
+ *      bond port id
+ * @returns delay ms value or -1 on failure
+ */
+int get_bond_link_down_delay(uint8_t bonded_port_id);
+/*
+ * Sets bond port 's link up delay
+ * @Param bonded_port_id
+ *      bond port id
+ * @Param delay_ms
+ *      delay time in ms
+ * @returns 0 on success and 1 on failure
+ */
+int set_bond_linkup_delay(uint8_t bonded_port_id, uint32_t delay_ms);
+/*
+ * Get bond port 's link up delay
+ * @Param bonded_port_id
+ *      bond port id
+ * @returns delay ms value or -1 on failure
+ */
+int get_bond_link_up_delay(uint8_t bonded_port_id);
+/*
+ * Print port s statistics
+ * @Param void
+ * @returns void
+ */
+void print_stats(void);
+/*
+ * Gets information about port
+ * @Param port_id
+ *     portid of the port
+ * @param port_info
+ *      port to address to copy port info
+ * @returns 0 on success otherwise -1
+ */
+int ifm_get_port_info(uint8_t port_id, l2_phy_interface_t *port_info);
+/*
+ * Gets information about next port of given portid
+ * @Param port_id
+ *     portid of the port
+ * @param port_info
+ *      port to address to copy port info
+ * @returns 0 on success otherwise -1
+ */
+int ifm_get_next_port_info(uint8_t port_id, l2_phy_interface_t *port_info);
+/*
+ * Enable ifm debug
+ * @Param dbg value
+ *     Debug- 1(port config),2(port RXTX),3(hle LOCKS),4(GENERALDEBUG)
+ * @param flag
+ *      Enable 1, disable 0
+ * @returns 0 on success otherwise -1
+ */
+void config_ifm_debug(int dbg, int flag);
+#endif
diff --git a/common/VIL/l2l3_stack/l2_proto.c b/common/VIL/l2l3_stack/l2_proto.c
new file mode 100644 (file)
index 0000000..44c50b0
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+/*
+ *     Filename - l2_proto.c
+ *     L2 Protocol Handler
+ */
+
+#include "l2_proto.h"
+
+static struct proto_packet_type *proto_list[3];
+/*
+ *     Function to register the rx functions for different ethertypes. This is maintained in a list.
+ */
+void
+list_add_type(uint16_t type,
+                               void (*func) (struct rte_mbuf **, uint16_t, uint64_t,
+                                       l2_phy_interface_t *))
+{
+       if (type == ETHER_TYPE_IPv4) {
+               proto_list[IPv4_VAL] =
+                               rte_malloc(NULL, sizeof(struct proto_packet_type),
+                                                RTE_CACHE_LINE_SIZE);
+               proto_list[IPv4_VAL]->type = type;
+               proto_list[IPv4_VAL]->func = func;
+       }
+
+       else if (type == ETHER_TYPE_ARP) {
+               proto_list[ARP_VAL] =
+                               rte_malloc(NULL, sizeof(struct proto_packet_type),
+                                                RTE_CACHE_LINE_SIZE);
+               proto_list[ARP_VAL]->type = type;
+               proto_list[ARP_VAL]->func = func;
+       } else if (type == ETHER_TYPE_IPv6) {
+               proto_list[IPv6_VAL] =
+                               rte_malloc(NULL, sizeof(struct proto_packet_type),
+                                                RTE_CACHE_LINE_SIZE);
+               proto_list[IPv6_VAL]->type = type;
+               proto_list[IPv6_VAL]->func = func;
+       }
+
+}
+
+/*
+ *     Check the mac address to see whether it is destined to this host or not.
+ *     Call relevant functions registered by other modules when the ethertype matches,
+ *     if it is destined to this host. Drop the packet otherwise.
+ */
+
+void
+l2_check_mac(struct rte_mbuf *m[IFM_BURST_SIZE], l2_phy_interface_t *port,
+                        uint8_t i, uint64_t *pkts_mask, uint64_t *arp_pkts_mask,
+                        uint64_t *ipv4_pkts_mask, uint64_t *ipv6_pkts_mask)
+{
+       struct ether_hdr *eth=NULL;
+       uint16_t same_mac=0;
+       uint16_t ethtype = 0;
+
+       if (m[i] != NULL) {
+               eth = rte_pktmbuf_mtod(m[i], struct ether_hdr *);
+               if(eth)
+               ethtype = rte_be_to_cpu_16(eth->ether_type);
+               if (eth == NULL) {
+                       /*Destination MAC address inside the packet */
+                       printf("l2_check_mac: Ethernet Dest Addr NULL !!!\n");
+                       return;
+               }
+               ethtype = rte_be_to_cpu_16(eth->ether_type);
+#if L2_PROTO_DBG
+               printf("%s => mbuf pkt dest mac addr: %x:%x:%x:%x:%x:%x\n",
+                                        __FUNCTION__, eth->d_addr.addr_bytes[0],
+                                        eth->d_addr.addr_bytes[1], eth->d_addr.addr_bytes[2],
+                                        eth->d_addr.addr_bytes[3], eth->d_addr.addr_bytes[4],
+                                        eth->d_addr.addr_bytes[5]);
+               printf("%s => port mac addr: %x:%x:%x:%x:%x:%x\n", __FUNCTION__,
+                                        port->macaddr[0], port->macaddr[1], port->macaddr[2],
+                                        port->macaddr[3], port->macaddr[4], port->macaddr[5]);
+
+#endif
+               /*     Compare the mac addresses       */
+               same_mac =
+                               (is_same_ether_addr
+                                (&eth->d_addr, (struct ether_addr *)port->macaddr)
+                                ||
+                                ((is_broadcast_ether_addr
+                                        ((struct ether_addr *)&eth->d_addr)
+                                        && (ethtype == ETHER_TYPE_ARP)))
+                                || (ethtype == ETHER_TYPE_IPv6
+                        && eth->d_addr.addr_bytes[0] == 0x33
+                        && eth->d_addr.addr_bytes[1] == 0x33));
+
+               if (!same_mac) {
+                       uint64_t temp_mask = 1LLU << i;
+                       *pkts_mask ^= temp_mask;
+                       rte_pktmbuf_free(m[i]);
+                       m[i] = NULL;
+               } else if ((ethtype == ETHER_TYPE_IPv4) && same_mac) {
+                       uint64_t temp_mask = 1LLU << i;
+                       *ipv4_pkts_mask ^= temp_mask;
+               } else if ((ethtype == ETHER_TYPE_ARP) && same_mac) {
+                       uint64_t temp_mask = 1LLU << i;
+                       *arp_pkts_mask ^= temp_mask;
+               } else if ((ethtype == ETHER_TYPE_IPv6) && same_mac) {
+                       uint64_t temp_mask = 1LLU << i;
+                       *ipv6_pkts_mask ^= temp_mask;
+               }
+       }
+       printf("\n%s: arp_pkts_mask = %" PRIu64 ", ipv4_pkts_mask = %" PRIu64
+                                ", ipv6_pkts_mask =%" PRIu64 ", pkt-type = %x, sam_mac = %d\n",
+                                __FUNCTION__, *arp_pkts_mask, *ipv4_pkts_mask, *ipv6_pkts_mask,
+                                ethtype, same_mac);
+}
+
+void
+protocol_handler_recv(struct rte_mbuf **pkts_burst, uint16_t nb_rx,
+                                       l2_phy_interface_t *port)
+{
+       uint8_t i;
+       uint64_t pkts_mask = 0; //RTE_LEN2MASK(nb_rx, uint64_t);
+       uint64_t arp_pkts_mask = 0;     //RTE_LEN2MASK(nb_rx, uint64_t);
+       uint64_t ipv4_pkts_mask = 0;    //RTE_LEN2MASK(nb_rx, uint64_t);
+       uint64_t ipv6_pkts_mask = 0;    //RTE_LEN2MASK(nb_rx, uint64_t);
+
+       /*Check the mac address of every single packet and unset the bits in the packet mask
+        *for those packets which are not destined to this host
+        */
+       for (i = 0; i < nb_rx; i++) {
+               l2_check_mac(pkts_burst, port, i, &pkts_mask, &arp_pkts_mask,
+                                        &ipv4_pkts_mask, &ipv6_pkts_mask);
+       }
+       if (nb_rx) {
+               if (arp_pkts_mask) {
+                       proto_list[ARP_VAL]->func(pkts_burst, nb_rx,
+                                                       arp_pkts_mask, port);
+                       printf
+                                       ("=================After ARP ==================\n");
+               }
+               if (ipv4_pkts_mask) {
+                       printf
+                                       ("=================Calling IPV4 L3 RX ==================\n");
+                       printf("====nb_rx:%u, ipv4_pkts_mask: %lu\n\n", nb_rx,
+                                                ipv4_pkts_mask);
+                       proto_list[IPv4_VAL]->func(pkts_burst, nb_rx,
+                                                        ipv4_pkts_mask, port);
+               }
+               if (ipv6_pkts_mask) {
+                       printf
+                                       ("=================Calling IPV6 L3 RX ==================\n");
+                       printf("====nb_rx:%u, ipv6_pkts_mask: %lu\n\n", nb_rx,
+                                                ipv6_pkts_mask);
+                       proto_list[IPv6_VAL]->func(pkts_burst, nb_rx,
+                                                        ipv6_pkts_mask, port);
+               }
+       }
+}
+
+#if 0
+switch (qid) {
+case 1:
+       {
+#if 0
+               printf
+                               ("=====================ENTERED ARP CASE================\n");
+               while (cur->type != ETHER_TYPE_ARP && cur != NULL) {
+                       cur = cur->next;
+               }
+               if (cur != NULL) {
+                       //printf("L2 PROTO TEST-14=================================\n");
+                       printf
+                                       ("==============\nARPARPARPARP  \n=======================\n");
+                       cur->func(pkts_burst, nb_rx, pkts_mask, portid);
+               }
+#endif
+               proto_list[ARP_VAL]->func(pkts_burst, nb_rx, arp_pkts_mask,
+                                               portid);
+               break;
+       }
+case 0:
+       {
+#if 0
+               while (cur->type != ETHER_TYPE_IPv4 && cur != NULL) {
+                       cur = cur->next;
+               }
+               if (cur != NULL) {
+                       //printf("L2 PROTO TEST-15=================================\n");
+                       //printf("==============\nPkts mask in while calling IPv4 %d \n=======================\n",ipv4_pkts_mask);
+                       cur->func(pkts_burst, nb_rx, ipv4_pkts_mask, portid);
+               }
+               break;
+#endif
+               //      printf("=========Inside switch==============\n");
+               proto_list[IPv4_VAL]->func(pkts_burst, nb_rx, ipv4_pkts_mask,
+                                                portid);
+               break;
+       }
+       /*     case 2:
+                {
+                while(cur->type != ETHER_TYPE_IPv6  && cur != NULL)
+                {
+                cur = cur->next;
+                }
+                if(cur != NULL)
+                {
+                cur->func(pkts_burst, nb_rx, ipv6_pkts_mask, portid);
+                }
+                break;
+                } */
+default:
+       {
+               rte_exit(EXIT_FAILURE, "Ethertype not found \n");
+               break;
+       }
+}
+#endif
+
+/*
+ *     L2 Stack Init for future
+
+
+       void
+l2_stack_init(void)
+{
+
+}
+
+*/
diff --git a/common/VIL/l2l3_stack/l2_proto.h b/common/VIL/l2l3_stack/l2_proto.h
new file mode 100644 (file)
index 0000000..0546607
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+/**
+ *     @file
+ *     L2 Protocol Handler
+ *     Reads the packet from the interface and sets the
+ *     masks for a burst of packets based on ethertype and
+ *     calls the relevant function registered for that ethertype
+ *
+ */
+
+#ifndef L2_PROTO_H
+#define L2_PROTO_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <netinet/in.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+#include <signal.h>
+#include <stdbool.h>
+
+#include <rte_common.h>
+#include <rte_log.h>
+#include <rte_malloc.h>
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+#include <rte_memzone.h>
+#include <rte_eal.h>
+#include <rte_per_lcore.h>
+#include <rte_launch.h>
+#include <rte_atomic.h>
+#include <rte_cycles.h>
+#include <rte_prefetch.h>
+#include <rte_lcore.h>
+#include <rte_per_lcore.h>
+#include <rte_branch_prediction.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_random.h>
+#include <rte_debug.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_ip.h>
+#include <rte_ring.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include <rte_eth_ctrl.h>
+#include <interface.h>
+
+/* Array indexes of proto_packet_type structure */
+#define IPv4_VAL 0 /**< Array index for IPv4 */
+#define ARP_VAL 1 /**< Array index for ARP */
+#define IPv6_VAL 2 /**< Array index for IPv6 */
+
+/* Enable to print L2_Proto debugs */
+#define L2_PROTO_DBG 1 /**< Enable to print L2 Proto debugs */
+
+/**
+ * A structure used to call the function handlers for a certain ethertype
+ */
+struct proto_packet_type {
+       uint16_t type;          /**< Ethertype  */
+       void (*func) (struct rte_mbuf **m, uint16_t nb_pkts, uint64_t pkt_mask, l2_phy_interface_t *port);  /**< Function pointer to the registered callback function */
+} __rte_cache_aligned;/**< RTE Cache alignment */
+
+/**
+ * Function called from other modules to add the certain rx functions for particular ethertypes
+ *
+ * @param type
+ * Ethertype
+ * @param (*func)()
+ * Function pointer to the function being registered by different modules
+ */
+void
+list_add_type(uint16_t type,
+                               void (*func) (struct rte_mbuf **, uint16_t, uint64_t,
+                                       l2_phy_interface_t *));
+
+/**
+ * Function to check whether the destination mac address of the packet is the mac address of the received port.
+ * Drop the packet if it is not destined to the host.
+ * If it is destined to this host, then set the packet masks for IPv4, IPv6 and ARP packet types for a burst of packets.
+ *
+ * @param m
+ * rte_mbuf packet
+ *
+ * @param portid
+ * Portid from which the packet was received
+ *
+ * @param pos
+ * Index of the packet in the burst
+ *
+ * @param pkts_mask
+ * Packet mask where bits are set at positions for the packets in the burst which were destined to the host
+ *
+ * @param arp_pkts_mask
+ * Packet mask for ARP where bits are set for valid ARP packets
+ *
+ * @param ipv4_pkts_mask
+ * Packet mask for IPv4 where bits are set for valid IPv4 packets
+ *
+ * @param ipv6_pkts_mask
+ * Packet mask for IPv6 where bits are set for valid IPv6 packets
+ *
+ */
+void
+l2_check_mac(struct rte_mbuf *m[IFM_BURST_SIZE], l2_phy_interface_t *port,
+                        uint8_t pos, uint64_t *pkts_mask, uint64_t *arp_pkts_mask,
+                        uint64_t *ipv4_pkts_mask, uint64_t *ipv6_pkts_mask);
+
+/**
+ * Entry function to L2 Protocol Handler where appropriate functions are called for particular ethertypes
+ *
+ * @param m
+ * rte_mbuf packet
+ *
+ * @param nb_rx
+ * Number of packets read
+ *
+ * @param portid
+ * Port-id of the port in which packet was received
+ */
+void
+protocol_handler_recv(struct rte_mbuf *m[IFM_BURST_SIZE], uint16_t nb_rx,
+                                       l2_phy_interface_t *port);
+
+#endif
diff --git a/common/VIL/l2l3_stack/l3fwd_common.h b/common/VIL/l2l3_stack/l3fwd_common.h
new file mode 100644 (file)
index 0000000..cece57c
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+/**
+* @file
+* L3fwd common header file for LPM IPv4 and IPv6 stack initialization
+*/
+
+#ifndef L3FWD_COMMON_H
+#define L3FWD_COMMON_H
+
+/* Standard Libraries */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/param.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <getopt.h>
+#include <unistd.h>
+
+/* DPDK RTE Libraries */
+#include <rte_common.h>
+#include <rte_hash.h>
+#include <rte_jhash.h>
+#include <rte_port.h>
+#include <rte_vect.h>
+#include <rte_byteorder.h>
+#include <rte_log.h>
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+#include <rte_memzone.h>
+#include <rte_eal.h>
+#include <rte_per_lcore.h>
+#include <rte_launch.h>
+#include <rte_atomic.h>
+#include <rte_cycles.h>
+#include <rte_prefetch.h>
+#include <rte_lcore.h>
+#include <rte_per_lcore.h>
+#include <rte_branch_prediction.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_random.h>
+#include <rte_debug.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_ring.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include <rte_ip.h>
+#include <rte_tcp.h>
+#include <rte_udp.h>
+#include <rte_table_hash.h>
+#include <rte_table.h>
+#include <rte_table_lpm.h>
+#include <rte_string_fns.h>
+#include <rte_cpuflags.h>
+#include <l3fwd_lpm4.h>
+#include <l3fwd_lpm6.h>
+#include <rte_table_lpm_ipv6.h>
+
+/**
+* Define the Macros
+*/
+#define MAX_ROUTES 4            /**< MAX route that can be added*/
+#define L3FWD_DEBUG 1           /**< if set, enables the fast path logs */
+#define MULTIPATH_FEAT 1   /**< if set, enables the ECMP Multicast feature */
+
+//#define IPPROTO_ICMPV6 58 /**< Protocol ID for ICMPv6 */
+
+/**
+* L3fwd initilazation for creating IPv4 and IPv6 LPM table.
+*/
+void l3fwd_init(void);
+
+/**
+* L3fwd IPv4 LPM table population, it calls IPv4 route add function which stores all the route in LPM table
+*/
+void populate_lpm4_table_routes(void);
+
+/**
+* L3fwd IPv6 LPM table population, it calls IPv6 route add function which stores all the route in LPM6 table
+*/
+void populate_lpm6_table_routes(void);
+
+/**
+* L3fwd LPM table population for both IPv4 and IPv6.
+*/
+void populate_lpm_routes(void);
+
+#endif
diff --git a/common/VIL/l2l3_stack/l3fwd_lpm4.c b/common/VIL/l2l3_stack/l3fwd_lpm4.c
new file mode 100644 (file)
index 0000000..081038b
--- /dev/null
@@ -0,0 +1,1119 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include "l3fwd_common.h"
+#include "interface.h"
+#include "l2_proto.h"
+#include "l3fwd_lpm4.h"
+#include "l3fwd_lpm6.h"
+#include "lib_arp.h"
+#include "lib_icmpv6.h"
+#include <inttypes.h>
+
+/* Declare Global variables */
+
+/* Global for IPV6 */
+void *lpm4_table; /**< lpm4_table handler */
+
+/*Hash table for L2 adjacency */
+struct rte_hash *l2_adj_hash_handle;  /**< l2 adjacency hash table handler */
+struct rte_hash *fib_path_hash_handle;  /**< fib path hash table handler */
+
+l3_stats_t stats; /**< L3 statistics */
+
+/* Global load balancing hash table for ECMP*/
+uint8_t nh_links[MAX_SUPPORTED_FIB_PATHS][HASH_BUCKET_SIZE] = /**< Round Robin Hash entries for ECMP only*/
+{
+       /* 1 path, No Load balancing is required */
+       {0},
+
+       /* 2 path */
+       {0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
+        0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
+        0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
+        0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1},
+
+       /* 3 path */
+       {0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0,
+        1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1,
+        2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2,
+        0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0},
+
+       /* 4 path */
+       {0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3,
+        0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3,
+        0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3,
+        0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3},
+
+       /* 5 path */
+       {0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0,
+        1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1,
+        2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2,
+        3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3},
+
+       /* 6 path */
+       {0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3,
+        4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1,
+        2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5,
+        0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3},
+
+       /* 7 path */
+       {0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1,
+        2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3,
+        4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5,
+        6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0},
+
+       /* 8 path */
+       {0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7,
+        0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7,
+        0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7,
+        0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7}
+};
+
+#if 0
+#define META_DATA_OFFSET 128
+
+#define RTE_PKTMBUF_HEADROOM 128       /* where is this defined ? */
+#define ETHERNET_START (META_DATA_OFFSET + RTE_PKTMBUF_HEADROOM)
+#define ETH_HDR_SIZE 14
+#define IP_START (ETHERNET_START + ETH_HDR_SIZE)
+#define TCP_START (IP_START + 20)
+
+static void print_pkt(struct rte_mbuf *pkt)
+{
+       int i;
+       int size = 14;
+       uint8_t *rd = RTE_MBUF_METADATA_UINT8_PTR(pkt, ETHERNET_START);
+
+       printf("Meta-data:\n");
+       for (i = 0; i < size; i++) {
+               printf("%02x ", rd[i]);
+               if ((i & 3) == 3)
+                       printf("\n");
+       }
+       printf("\n");
+       printf("IP and TCP/UDP headers:\n");
+       rd = RTE_MBUF_METADATA_UINT8_PTR(pkt, IP_START);
+       for (i = 0; i < 40; i++) {
+               printf("%02x ", rd[i]);
+               if ((i & 3) == 3)
+                       printf("\n");
+       }
+
+}
+#endif
+static struct ip_protocol_type *proto_type[2];
+int lpm_init(void)
+{
+
+       /* Initiliaze LPMv4 params */
+       struct rte_table_lpm_params lpm_params = {
+               .name = "LPMv4",
+               .n_rules = IPV4_L3FWD_LPM_MAX_RULES,
+               .number_tbl8s = IPV4_L3FWD_LPM_NUMBER_TBL8S,
+               .flags = 0,
+               .entry_unique_size = sizeof(struct fib_info),
+               .offset = 128,
+       };
+
+       /* Create LPMv4 tables */
+       lpm4_table =
+                       rte_table_lpm_ops.f_create(&lpm_params, rte_socket_id(),
+                                                        sizeof(struct fib_info));
+       if (lpm4_table == NULL) {
+               printf("Failed to create LPM IPV4 table\n");
+               return 0;
+       }
+
+       /*Initialize L2 ADJ hash params  */
+       struct rte_hash_parameters l2_adj_ipv4_params = {
+               .name = "l2_ADJ_HASH",
+               .entries = 64,
+               .key_len = sizeof(struct l2_adj_key_ipv4),
+               .hash_func = rte_jhash,
+               .hash_func_init_val = 0,
+       };
+
+       /* Create IPv4 L2 Adj Hash tables */
+       l2_adj_hash_handle = rte_hash_create(&l2_adj_ipv4_params);
+
+       if (l2_adj_hash_handle == NULL) {
+               printf("L2 ADJ rte_hash_create failed\n");
+               return 0;
+       } else {
+               printf("l2_adj_hash_handle %p\n\n", (void *)l2_adj_hash_handle);
+       }
+
+       /*Initialize Fib PAth hassh params  */
+       struct rte_hash_parameters fib_path_ipv4_params = {
+               .name = "FIB_PATH_HASH",
+               .entries = 64,
+               .key_len = sizeof(struct fib_path_key_ipv4),
+               .hash_func = rte_jhash,
+               .hash_func_init_val = 0,
+       };
+
+       /* Create FIB PATH Hash tables */
+       fib_path_hash_handle = rte_hash_create(&fib_path_ipv4_params);
+
+       if (fib_path_hash_handle == NULL) {
+               printf("FIB path rte_hash_create failed\n");
+               return 0;
+       }
+       return 1;
+}
+
+int lpm4_table_route_add(struct routing_info *data)
+{
+
+       struct routing_info *fib = data;
+       struct rte_table_lpm_key lpm_key = {
+               .ip = fib->dst_ip_addr,
+               .depth = fib->depth,
+       };
+       uint8_t i;
+       static int Total_route_count;
+       struct fib_info entry;
+       entry.dst_ip_addr = rte_bswap32(fib->dst_ip_addr);
+       entry.depth = fib->depth;
+       entry.fib_nh_size = fib->fib_nh_size;                   /**< For Single Path, greater then 1 for Multipath(ECMP)*/
+
+#if MULTIPATH_FEAT
+       if (entry.fib_nh_size == 0 || entry.fib_nh_size > MAX_FIB_PATHS)
+#else
+       if (entry.fib_nh_size != 1)     /**< For Single FIB_PATH */
+#endif
+       {
+               printf("Route can't be configured!!, entry.fib_nh_size = %d\n",
+                                        entry.fib_nh_size);
+               return 0;
+       }
+       /* Populate L2 adj and precomputes l2 encap string */
+#if MULTIPATH_FEAT
+       for (i = 0; i < entry.fib_nh_size; i++)
+#else
+       for (i = 0; i < 1; i++)
+#endif
+       {
+               struct fib_path *fib_path_addr = NULL;
+
+               fib_path_addr =
+                               populate_fib_path(fib->nh_ip_addr[i], fib->out_port[i]);
+               if (fib_path_addr) {
+
+                       entry.path[i] = fib_path_addr;
+                       printf("Fib info for the Dest IP");
+                       printf(" : %" PRIu32 ".%" PRIu32 ".%" PRIu32 ".%" PRIu32
+                                                "/%" PRIu8
+                                                " => fib_path Addr: %p, l2_adj Addr: %p\n",
+                                                (fib->dst_ip_addr & 0xFF000000) >> 24,
+                                                (fib->dst_ip_addr & 0x00FF0000) >> 16,
+                                                (fib->dst_ip_addr & 0x0000FF00) >> 8,
+                                                (fib->dst_ip_addr & 0x000000FF), fib->depth,
+                                                fib_path_addr,
+                                                (void *)entry.path[i]->l2_adj_ptr);
+               } else {
+                       printf("Fib info for the Dest IP :\
+                                       %" PRIu32 ".%" PRIu32 ".%" PRIu32 ".%" PRIu32 "/%" PRIu8 " => fib_path Addr: NULL \n", (fib->dst_ip_addr & 0xFF000000) >> 24, (fib->dst_ip_addr & 0x00FF0000) >> 16, (fib->dst_ip_addr & 0x0000FF00) >> 8, (fib->dst_ip_addr & 0x000000FF), fib->depth);
+                       entry.path[i] = NULL;                            /**< setting all other fib_paths to NULL */
+               }
+       }
+
+       int key_found, ret;
+       void *entry_ptr;
+       ret =
+                       rte_table_lpm_ops.f_add(lpm4_table, (void *)&lpm_key, &entry,
+                                               &key_found, &entry_ptr);
+
+       if (ret != 0) {
+               printf("Failed to Add IP route\n");
+               return 0;
+       }
+       Total_route_count++;
+       printf("Total Routed Added : %u, Key_found: %d\n", Total_route_count,
+                                key_found);
+       printf("Adding Route to LPM table...\n");
+
+       printf("Iterate with Cuckoo Hash table\n");
+       iterate_cuckoo_hash_table();
+       return 1;
+}
+
+int lpm4_table_route_delete(uint32_t dst_ip, uint8_t depth)
+{
+
+       struct rte_table_lpm_key lpm_key = {
+               .ip = dst_ip,
+               .depth = depth,
+       };
+
+       int key_found, ret;
+       void *entry = NULL;
+
+       entry = rte_zmalloc(NULL, 512, RTE_CACHE_LINE_SIZE);
+
+       /* Deleting a IP route from LPMv4 table */
+       ret =
+                       rte_table_lpm_ops.f_delete(lpm4_table, &lpm_key, &key_found, entry);
+
+       if (ret) {
+               printf("Failed to Delete IP route from LPMv4 table\n");
+               return 0;
+       }
+
+       printf("Deleted route from LPM table (IPv4 Address = %"
+                                PRIu32 ".%" PRIu32 ".%" PRIu32 ".%" PRIu32
+                                "/%u , key_found = %d\n", (lpm_key.ip & 0xFF000000) >> 24,
+                                (lpm_key.ip & 0x00FF0000) >> 16, (lpm_key.ip & 0x0000FF00) >> 8,
+                                (lpm_key.ip & 0x000000FF), lpm_key.depth, key_found);
+
+       /* Deleting a L2 Adj entry if refcount is 1, Else decrement Refcount */
+       remove_fib_l2_adj_entry(entry);
+       rte_free(entry);
+       printf("Iterate with Cuckoo Hash table\n");
+       iterate_cuckoo_hash_table();
+       return 1;
+}
+
+int
+lpm4_table_lookup(struct rte_mbuf **pkts_burst, uint16_t nb_pkts,
+                       uint64_t pkts_mask,
+                       l2_phy_interface_t *port_ptr[RTE_PORT_IN_BURST_SIZE_MAX],
+                       uint64_t *hit_mask)
+{
+
+       struct routing_table_entry *ipv4_entries[RTE_PORT_IN_BURST_SIZE_MAX];
+       uint64_t lookup_hit_mask_ipv4 = 0;
+       int status;
+       uint64_t pkts_key_mask = pkts_mask;
+       uint64_t lookup_miss_mask_ipv4 = pkts_mask;
+
+       static uint64_t sent_count;
+       static uint64_t rcvd_count;
+       rcvd_count += nb_pkts;
+       if (L3FWD_DEBUG) {
+               printf
+                               (" Received IPv4 nb_pkts: %u, Rcvd_count: %lu\n, pkts_mask: %p\n",
+                                nb_pkts, rcvd_count, (void *)pkts_mask);
+       }
+       uint32_t dst_addr_offset =
+                       MBUF_HDR_ROOM + ETH_HDR_SIZE + IP_HDR_DST_ADR_OFST;
+
+       for (; pkts_key_mask;) {
+/**< Populate key offset in META DATA for all valid pkts */
+               uint8_t pos = (uint8_t) __builtin_ctzll(pkts_key_mask);
+               uint64_t pkt_mask = 1LLU << pos;
+               pkts_key_mask &= ~pkt_mask;
+               struct rte_mbuf *mbuf = pkts_burst[pos];
+               uint32_t *lpm_key = NULL;
+               uint32_t *dst_addr = NULL;
+               lpm_key = (uint32_t *) RTE_MBUF_METADATA_UINT8_PTR(mbuf, 128);
+               dst_addr =
+                               (uint32_t *) RTE_MBUF_METADATA_UINT8_PTR(mbuf,
+                                                                        dst_addr_offset);
+               *lpm_key = *dst_addr;
+               if (L3FWD_DEBUG) {
+
+                       printf("Rcvd Pakt (IPv4 Address = %"
+                                                PRIu32 ".%" PRIu32 ".%" PRIu32 ".%" PRIu32 ")\n",
+                                                (rte_cpu_to_be_32(*lpm_key) & 0xFF000000) >> 24,
+                                                (rte_cpu_to_be_32(*lpm_key) & 0x00FF0000) >> 16,
+                                                (rte_cpu_to_be_32(*lpm_key) & 0x0000FF00) >> 8,
+                                                (rte_cpu_to_be_32(*lpm_key) & 0x000000FF));
+               }
+       }
+
+       /* Lookup for IP route in LPM table */
+       if (L3FWD_DEBUG)
+               printf("\nIPV4 Lookup Mask Before = %p\n",
+                                        (void *)lookup_hit_mask_ipv4);
+       status =
+                       rte_table_lpm_ops.f_lookup(lpm4_table, pkts_burst, pkts_mask,
+                                                        &lookup_hit_mask_ipv4,
+                                                        (void **)ipv4_entries);
+
+       if (status) {
+               printf("LPM Lookup failed for IP route\n");
+               return 0;
+       }
+
+       lookup_miss_mask_ipv4 = lookup_miss_mask_ipv4 & (~lookup_hit_mask_ipv4);
+       if (L3FWD_DEBUG) {
+               printf
+                               ("AFTER lookup_hit_mask_ipv4 = %p, lookup_miss_mask_ipv4 =%p\n",
+                                (void *)lookup_hit_mask_ipv4,
+                                (void *)lookup_miss_mask_ipv4);
+       }
+
+       for (; lookup_miss_mask_ipv4;) {
+/**< Drop packets for lookup_miss_mask */
+               uint8_t pos = (uint8_t) __builtin_ctzll(lookup_miss_mask_ipv4);
+               uint64_t pkt_mask = 1LLU << pos;
+               lookup_miss_mask_ipv4 &= ~pkt_mask;
+               rte_pktmbuf_free(pkts_burst[pos]);
+               pkts_burst[pos] = NULL;
+               stats.nb_l3_drop_pkt++;  /**< Peg the L3 Drop counter */
+               if (L3FWD_DEBUG)
+                       printf("\n DROP PKT IPV4 Lookup_miss_Mask  = %p\n",
+                                                (void *)lookup_miss_mask_ipv4);
+       }
+
+       *hit_mask = lookup_hit_mask_ipv4;
+       for (; lookup_hit_mask_ipv4;) {
+/**< Process the packets for lookup_hit_mask*/
+               uint8_t pos = (uint8_t) __builtin_ctzll(lookup_hit_mask_ipv4);
+               uint64_t pkt_mask = 1LLU << pos;
+               lookup_hit_mask_ipv4 &= ~pkt_mask;
+               struct rte_mbuf *pkt = pkts_burst[pos];
+
+               struct fib_info *entry = (struct fib_info *)ipv4_entries[pos];
+
+#if MULTIPATH_FEAT
+
+               uint8_t ecmp_path = 0;
+               ecmp_path = ip_hash_load_balance(pkts_burst[pos]);
+               uint8_t selected_path = 0;
+               struct fib_path *fib_path = NULL;
+               if (((entry->fib_nh_size != 0)
+                                && (entry->fib_nh_size - 1) < MAX_SUPPORTED_FIB_PATHS)
+                               && ((ecmp_path != 0) && (ecmp_path - 1) < HASH_BUCKET_SIZE))
+                       selected_path =
+                                       nh_links[entry->fib_nh_size - 1][ecmp_path - 1];
+               if (selected_path < MAX_FIB_PATHS)
+                       fib_path = entry->path[selected_path];
+               if (L3FWD_DEBUG) {
+                       printf
+                                       ("Total supported Path :%u, Hashed ECMP Key : %u, selected Fib_path: %u\n",
+                                        entry->fib_nh_size, ecmp_path, selected_path);
+               }
+#else
+               struct fib_path *fib_path = entry->path[0];
+#endif
+
+               if (fib_path == NULL) {
+                       rte_pktmbuf_free(pkt);
+                       pkts_burst[pos] = NULL;
+                       stats.nb_l3_drop_pkt++;  /**< Peg the L3 Drop counter */
+                       *hit_mask &= ~pkt_mask; /**< Remove this pkt from port Mask */
+                       if (L3FWD_DEBUG)
+                               printf
+                                               ("Fib_path is NULL, ARP has not resolved, DROPPED UNKNOWN PKT\n");
+                       continue;
+               }
+
+               if (fib_path->l2_adj_ptr->flags == L2_ADJ_UNRESOLVED) {
+                       if (fib_path->l2_adj_ptr->phy_port->ipv4_list != NULL)
+                               request_arp(fib_path->l2_adj_ptr->phy_port->
+                                                       pmdid, fib_path->nh_ip);
+
+                       rte_pktmbuf_free(pkts_burst[pos]);
+                       pkts_burst[pos] = NULL;
+                       *hit_mask &= ~pkt_mask; /**< Remove this pkt from port Mask */
+                       if (L3FWD_DEBUG)
+                               printf
+                                               ("L2_ADJ_UNRESOLVED, DROPPED UNKNOWN PKT\n");
+                       continue;
+               }
+
+               /* extract ip headers and MAC */
+               uint8_t *eth_dest =
+                               RTE_MBUF_METADATA_UINT8_PTR(pkt, MBUF_HDR_ROOM);
+               uint8_t *eth_src =
+                               RTE_MBUF_METADATA_UINT8_PTR(pkt, MBUF_HDR_ROOM + 6);
+               if (L3FWD_DEBUG) {
+                       printf
+                                       ("MAC BEFORE- DST MAC %02x:%02x:%02x:%02x:%02x:%02x, \
+                                       SRC MAC %02x:%02x:%02x:%02x:%02x:%02x \n",
+                                        eth_dest[0], eth_dest[1], eth_dest[2], eth_dest[3], eth_dest[4], eth_dest[5], eth_src[0], eth_src[1],
+                                        eth_src[2], eth_src[3], eth_src[4], eth_src[5]);
+               }
+               /* Rewrite the packet with L2 string  */
+               memcpy(eth_dest, fib_path->l2_adj_ptr->l2_string, sizeof(struct ether_addr) * 2);       // For MAC
+               if (L3FWD_DEBUG) {
+                       int k = 0;
+                       for (k = 0; k < 14; k++) {
+                               printf("%02x ",
+                                                        fib_path->l2_adj_ptr->l2_string[k]);
+                               printf("\n");
+                       }
+                       printf
+                                       ("MAC AFTER DST MAC %02x:%02x:%02x:%02x:%02x:%02x, \
+                                       SRC MAC %02x:%02x:%02x:%02x:%02x:%02x\n", eth_dest[0], eth_dest[1], eth_dest[2], eth_dest[3], eth_dest[4], eth_dest[5], eth_src[0], eth_src[1], eth_src[2], eth_src[3], eth_src[4], eth_src[5]);
+               }
+               port_ptr[pos] = fib_path->l2_adj_ptr->phy_port;
+               if (L3FWD_DEBUG) {
+                       printf("l3fwd_lookup API!!!!\n");
+                       //print_pkt(pkt);
+               }
+
+               sent_count++;
+               stats.nb_tx_l3_pkt++;
+               if (L3FWD_DEBUG)
+                       printf
+                                       ("Successfully sent to port %u, sent_count : %lu\n\r",
+                                        fib_path->out_port, sent_count);
+       }
+       return 1;
+}
+
+int is_valid_ipv4_pkt(struct ipv4_hdr *pkt, uint32_t link_len)
+{
+       if (link_len < sizeof(struct ipv4_hdr))
+               return -1;
+       if (((pkt->version_ihl) >> 4) != 4)
+               return -1;
+       if ((pkt->version_ihl & 0xf) < 5)
+               return -1;
+       if (rte_cpu_to_be_16(pkt->total_length) < sizeof(struct ipv4_hdr))
+               return -1;
+       return 0;
+}
+
+int
+get_dest_mac_for_nexthop(uint32_t next_hop_ip,
+                        uint8_t out_phy_port, struct ether_addr *hw_addr)
+{
+       struct arp_entry_data *arp_data = NULL;
+       struct arp_key_ipv4 arp_key;
+       arp_key.port_id = out_phy_port;
+       arp_key.ip = next_hop_ip;
+
+       arp_data = retrieve_arp_entry(arp_key);
+       if (arp_data == NULL) {
+               printf("ARP entry is not found for ip %x, port %d\n",
+                                        next_hop_ip, out_phy_port);
+               return 0;
+       }
+       ether_addr_copy(&arp_data->eth_addr, hw_addr);
+       return 1;
+}
+
+struct l2_adj_entry *retrieve_l2_adj_entry(struct l2_adj_key_ipv4 l2_adj_key)
+{
+       struct l2_adj_entry *ret_l2_adj_data = NULL;
+       l2_adj_key.filler1 = 0;
+       l2_adj_key.filler2 = 0;
+       l2_adj_key.filler3 = 0;
+
+       int ret =
+                       rte_hash_lookup_data(l2_adj_hash_handle, &l2_adj_key,
+                                (void **)&ret_l2_adj_data);
+       if (ret < 0) {
+               #ifdef L2L3_DEBUG
+               printf
+                               ("L2 Adj hash lookup failed ret %d, EINVAL %d, ENOENT %d\n",
+                                ret, EINVAL, ENOENT);
+               #endif
+               return NULL;
+       } else {
+               #ifdef L2L3_DEBUG
+               printf
+                               ("L2 Adj hash lookup Success, Entry Already Exist ret %d, EINVAL %d, ENOENT %d\n",
+                                ret, EINVAL, ENOENT);
+               #endif
+               return ret_l2_adj_data;
+       }
+}
+
+void remove_fib_l2_adj_entry(void *entry)
+{
+       struct fib_info entry1;
+       memcpy(&entry1, entry, sizeof(struct fib_info));
+
+       struct fib_path *fib_path_addr = entry1.path[0];  /**< For Single path */
+       if (fib_path_addr->refcount > 1) {
+               printf
+                               (" BEFORE fib_path entry, nh_ip %x, port %d, refcount %d\n",
+                                fib_path_addr->nh_ip, fib_path_addr->out_port,
+                                fib_path_addr->refcount);
+               fib_path_addr->refcount--;               /**< Just decrement the refcount this entry is still referred*/
+               printf("AFTER fib_path entry, nh_ip %x, port %d, refcount %d\n",
+                                        fib_path_addr->nh_ip, fib_path_addr->out_port,
+                                        fib_path_addr->refcount);
+       } else {
+/**< Refcount is 1 so delete both fib_path and l2_adj_entry */
+
+               struct l2_adj_entry *adj_addr = NULL;
+               adj_addr = fib_path_addr->l2_adj_ptr;
+
+               if (adj_addr != NULL) {
+/** < l2_adj_entry is has some entry in hash table*/
+                       struct l2_adj_key_ipv4 l2_adj_key = {
+                               .Next_hop_ip = fib_path_addr->nh_ip,
+                               .out_port_id = fib_path_addr->out_port,
+                       };
+                       #ifdef L3FWD_DEBUG
+                       printf
+                                       (" l2_adj_entry is removed for ip %x, port %d, refcount %d\n",
+                                        l2_adj_key.Next_hop_ip, l2_adj_key.out_port_id,
+                                        adj_addr->refcount);
+                       #endif
+
+                       rte_hash_del_key(l2_adj_hash_handle, &l2_adj_key);
+                       rte_free(adj_addr); /**< free the memory which was allocated for Hash entry */
+                       adj_addr = NULL;
+               }
+
+               struct fib_path_key_ipv4 path_key = {
+                       .nh_ip = fib_path_addr->nh_ip,
+                       .out_port = fib_path_addr->out_port,
+               };
+
+               printf
+                               ("fib_path entry is removed for ip %x, port %d, refcount %d\n",
+                                fib_path_addr->nh_ip, fib_path_addr->out_port,
+                                fib_path_addr->refcount);
+               rte_hash_del_key(fib_path_hash_handle, &path_key);
+               rte_free(fib_path_addr); /**< Free the memory which was allocated for Hash entry*/
+               fib_path_addr = NULL;
+       }
+}
+
+struct l2_adj_entry *populate_l2_adj(uint32_t ipaddr, uint8_t portid)
+{
+
+       struct l2_adj_key_ipv4 l2_adj_key;
+       l2_adj_key.out_port_id = portid;
+       l2_adj_key.Next_hop_ip = ipaddr;
+       l2_adj_key.filler1 = 0;
+       l2_adj_key.filler2 = 0;
+       l2_adj_key.filler3 = 0;
+
+       struct ether_addr eth_dst;
+       struct l2_adj_entry *adj_data = NULL;
+
+       /* Populate L2 adj if the MAC Address is already present in L2 Adj HAsh Table */
+       adj_data = retrieve_l2_adj_entry(l2_adj_key);
+
+       if (adj_data) {  /**< L2 Adj Entry Exists*/
+
+               printf
+                               ("l2_adj_entry exists ip%x, port %d, Refcnt :%u Address :%p\n",
+                                l2_adj_key.Next_hop_ip, l2_adj_key.out_port_id,
+                                adj_data->refcount, adj_data);
+               ether_addr_copy(&adj_data->eth_addr, &eth_dst);
+               adj_data->refcount++;
+               printf
+                               ("l2_adj_entry UPDATED Refcount for NH ip%x, port %d, Refcnt :%u Address :%p\n",
+                                l2_adj_key.Next_hop_ip, l2_adj_key.out_port_id,
+                                adj_data->refcount, adj_data);
+               return adj_data;
+       }
+
+       struct ether_addr eth_src;
+       l2_phy_interface_t *port;
+       //uint16_t ether_type = 0x0800;
+       port = ifm_get_port(portid);
+
+       if (port != NULL) {
+               memcpy(&eth_src, &port->macaddr, sizeof(struct ether_addr));
+               unsigned char *p = (unsigned char *)eth_src.addr_bytes;
+               printf("S-MAC %x:%x:%x:%x:%x:%x\n\r", p[0], p[1], p[2], p[3],
+                                        p[4], p[5]);
+
+               uint32_t size =
+                               RTE_CACHE_LINE_ROUNDUP(sizeof(struct l2_adj_entry));
+               adj_data = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
+               if (adj_data == NULL) {
+                       printf("L2 Adjacency memory allocation failed !\n");
+                       return NULL;
+               }
+
+               adj_data->out_port_id = portid;
+               adj_data->Next_hop_ip = ipaddr;
+               adj_data->refcount++;
+
+               adj_data->phy_port = port;
+               memset(&adj_data->eth_addr, 0, sizeof(struct ether_addr));
+               memset(&adj_data->l2_string, 0, 256);
+
+               /**< Store the received MAC Address in L2 Adj HAsh Table */
+               rte_hash_add_key_data(l2_adj_hash_handle, &l2_adj_key,
+                                                       adj_data);
+               #ifdef L2L3_DEBUG
+               printf
+                               ("L2 adj data stored in l2_adj_entry hash table,Addr:%p\n",
+                                adj_data);
+               #endif
+       } else {
+               #ifdef L2L3_DEBUG
+               printf("\n PORT %u IS DOWN...\n", portid);
+               #endif
+               return NULL;
+       }
+       /* Query ARP to get L2 Adj */
+       if (get_dest_mac_for_nexthop(ipaddr, portid, &eth_dst)) {
+               unsigned char *p = (unsigned char *)eth_dst.addr_bytes;
+               printf
+                               ("ARP resolution success and stored in l2_adj_entry hash table:D-MAC %x:%x:%x:%x:%x:%x\n\r",
+                                p[0], p[1], p[2], p[3], p[4], p[5]);
+
+               memcpy(adj_data->l2_string, &eth_dst, sizeof(struct ether_addr));       //** < Precompute the L2 String encap*/
+               memcpy(&adj_data->l2_string[6], &eth_src,
+                                        sizeof(struct ether_addr));
+               //memcpy(&adj_data->l2_string[12], &ether_type, 2);
+
+               ether_addr_copy(&eth_dst, &adj_data->eth_addr);
+               adj_data->flags = L2_ADJ_RESOLVED;
+       } else {
+               adj_data->flags = L2_ADJ_UNRESOLVED;
+               printf
+                               (" ARP resolution Failed !! , unable to write in l2_adj_entry\n");
+       }
+       return adj_data;
+}
+
+struct fib_path *populate_fib_path(uint32_t nh_ip, uint8_t portid)
+{
+
+       struct fib_path_key_ipv4 path_key;
+       path_key.out_port = portid;
+       path_key.nh_ip = nh_ip;
+       path_key.filler1 = 0;
+       path_key.filler2 = 0;
+       path_key.filler3 = 0;
+
+       struct fib_path *fib_data = NULL;
+
+       /* Populate fib_path */
+       fib_data = retrieve_fib_path_entry(path_key);
+
+       if (fib_data) {/**< fib_path entry already exists */
+
+               /* Already present in FIB_PATH cuckoo HAsh Table */
+               printf
+                               ("fib_path_entry already exists for NextHop ip: %x, port %d\n, Refcount %u Addr:%p\n",
+                                fib_data->nh_ip, fib_data->out_port, fib_data->refcount,
+                                fib_data);
+               fib_data->refcount++;
+               fib_data->l2_adj_ptr->refcount++;
+               printf
+                               ("fib_path Refcount Updated NextHop :%x , port %u, Refcount %u\n\r",
+                                fib_data->nh_ip, fib_data->out_port, fib_data->refcount);
+               return fib_data;
+       } else {
+               printf("fib_path entry Doesn't Exists.......\n");
+       }
+
+       fib_data = NULL;
+       struct l2_adj_entry *l2_adj_ptr = NULL;
+       l2_adj_ptr = populate_l2_adj(nh_ip, portid);
+
+       if (l2_adj_ptr) {
+
+               uint32_t size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct fib_path));
+               fib_data = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
+
+               fib_data->out_port = portid;
+               fib_data->nh_ip = nh_ip;
+               fib_data->refcount++;
+               fib_data->l2_adj_ptr = l2_adj_ptr;
+
+               printf("%s: get port details %u %d\n\r", __FUNCTION__, portid,
+                                        __LINE__);
+               /* Store the received MAC Address in L2 Adj HAsh Table */
+               int status;
+               status =
+                               rte_hash_add_key_data(fib_path_hash_handle, &path_key,
+                                               fib_data);
+               if (status) {
+                       printf
+                                       ("fib_path entry addition to hash table FAILED!! NextHop :%x , port %u, Refcount %u\n\r",
+                                        fib_data->nh_ip, fib_data->out_port,
+                                        fib_data->refcount);
+
+                       rte_free(fib_data);
+               } else {
+                       printf
+                                       ("fib_path entry Added into hash table for the NextHop :%x , port %u, Refcount %u\n\r",
+                                        fib_data->nh_ip, fib_data->out_port,
+                                        fib_data->refcount);
+                       printf
+                                       (" l2_adj_entry Addr: %p, Fib_path Addr: %p, FibPath->l2ADJ Addr:%p \n",
+                                        l2_adj_ptr, fib_data, fib_data->l2_adj_ptr);
+                       printf
+                                       (" ARP resolution success l2_adj_entry Addr: %p, Fib_path Addr: %p \n",
+                                        l2_adj_ptr, fib_data);
+                       return fib_data;
+               }
+       } else {
+               printf
+                               (" ARP resolution failed and unable to write fib path in fib_path cuckoo hash\n");
+       }
+       return NULL;
+}
+
+struct fib_path *retrieve_fib_path_entry(struct fib_path_key_ipv4 path_key)
+{
+       printf("FIB PATH for NExtHOP IP : %x, port :%u\n", path_key.nh_ip,
+                                path_key.out_port);
+
+       struct fib_path *ret_fib_path_data = NULL;
+       int ret =
+                       rte_hash_lookup_data(fib_path_hash_handle, &path_key,
+                                (void **)&ret_fib_path_data);
+       if (ret < 0) {
+               printf
+                               ("FIB PATH hash lookup Failed!! ret %d, EINVAL %d, ENOENT %d\n",
+                                ret, EINVAL, ENOENT);
+               return NULL;
+       } else {
+               printf("FIB PATH ALREADY Exists for NExtHOP IP: %x, port: %u\n",
+                                        path_key.nh_ip, path_key.out_port);
+               return ret_fib_path_data;
+       }
+}
+
+void iterate_cuckoo_hash_table(void)
+{
+       const void *next_key;
+       void *next_data;
+       uint32_t iter = 0;
+
+       printf("\n\t\t\t FIB_path Cache table....");
+       printf
+                       ("\n----------------------------------------------------------------");
+       printf("\n\tNextHop IP    Port   Refcount   l2_adj_ptr_addrress\n");
+       printf
+                       ("\n----------------------------------------------------------------\n");
+
+       while (rte_hash_iterate
+                                (fib_path_hash_handle, &next_key, &next_data, &iter) >= 0) {
+               struct fib_path *tmp_data = (struct fib_path *)next_data;
+               struct fib_path_key_ipv4 tmp_key;
+               memcpy(&tmp_key, next_key, sizeof(tmp_key));
+               printf("\t %" PRIu32 ".%" PRIu32 ".%" PRIu32 ".%" PRIu32
+                                        " \t %u \t %u \t %p\n",
+                                        (tmp_data->nh_ip & 0xFF000000) >> 24,
+                                        (tmp_data->nh_ip & 0x00FF0000) >> 16,
+                                        (tmp_data->nh_ip & 0x0000FF00) >> 8,
+                                        (tmp_data->nh_ip & 0x000000FF), tmp_data->out_port,
+                                        tmp_data->refcount, tmp_data->l2_adj_ptr);
+
+       }
+       iter = 0;
+
+       printf("\n\t\t\t L2 ADJ Cache table.....");
+       printf
+                       ("\n------------------------------------------------------------------------------------");
+       printf
+                       ("\n\tNextHop IP    Port  \t l2 Encap string \t l2_Phy_interface\n");
+       printf
+                       ("\n------------------------------------------------------------------------------------\n");
+
+       while (rte_hash_iterate
+                                (l2_adj_hash_handle, &next_key, &next_data, &iter) >= 0) {
+               struct l2_adj_entry *l2_data = (struct l2_adj_entry *)next_data;
+               struct l2_adj_key_ipv4 l2_key;
+               memcpy(&l2_key, next_key, sizeof(l2_key));
+               printf("\t %" PRIu32 ".%" PRIu32 ".%" PRIu32 ".%" PRIu32
+                                        "\t %u \t%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x\t%p\n",
+                                        (l2_data->Next_hop_ip & 0xFF000000) >> 24,
+                                        (l2_data->Next_hop_ip & 0x00FF0000) >> 16,
+                                        (l2_data->Next_hop_ip & 0x0000FF00) >> 8,
+                                        (l2_data->Next_hop_ip & 0x000000FF),
+                                        l2_data->out_port_id, l2_data->l2_string[0],
+                                        l2_data->l2_string[1], l2_data->l2_string[2],
+                                        l2_data->l2_string[3], l2_data->l2_string[4],
+                                        l2_data->l2_string[5], l2_data->l2_string[6],
+                                        l2_data->l2_string[7], l2_data->l2_string[8],
+                                        l2_data->l2_string[9], l2_data->l2_string[10],
+                                        l2_data->l2_string[11], l2_data->phy_port);
+       }
+}
+
+void print_l3_stats(void)
+{
+       printf("==============================================\n");
+       printf("\t\t L3 STATISTICS \t\n");
+       printf("==============================================\n");
+       printf(" Num of Received L3 Pkts     : %lu\n", stats.nb_rx_l3_pkt);
+       printf(" Num of Dropped L3 Pkts      : %lu\n", stats.nb_l3_drop_pkt);
+       printf(" Num of Transmitted L3 Pkts  : %lu\n", stats.nb_tx_l3_pkt);
+       printf(" Num of ICMP Pkts Rcvd at L3 : %lu\n", stats.nb_rx_l3_icmp_pkt);
+       printf(" Num of ICMP Pkts Tx to ICMP : %lu\n", stats.nb_tx_l3_icmp_pkt);
+       stats.total_nb_rx_l3_pkt = stats.nb_rx_l3_icmp_pkt + stats.nb_rx_l3_pkt;
+       stats.total_nb_tx_l3_pkt = stats.nb_tx_l3_icmp_pkt + stats.nb_tx_l3_pkt;
+       printf(" Total Num of Rcvd pkts at L3: %lu\n",
+                                stats.total_nb_rx_l3_pkt);
+       printf(" Total Num of Sent pkts at L3: %lu\n",
+                                stats.total_nb_tx_l3_pkt);
+}
+
+void
+ip_local_packets_process(struct rte_mbuf **pkt_burst, uint16_t nb_rx,
+                        uint64_t icmp_pkt_mask, l2_phy_interface_t *port)
+{
+       process_arpicmp_pkt_parse(pkt_burst, nb_rx, icmp_pkt_mask, port);
+}
+
+void
+ip_forward_deliver(struct rte_mbuf **pkt_burst, uint16_t nb_pkts,
+                        uint64_t ipv4_forward_pkts_mask, l2_phy_interface_t *port)
+{
+       if (L3FWD_DEBUG) {
+               printf
+                               ("ip_forward_deliver BEFORE DROP: nb_pkts: %u\n from in_port %u",
+                                nb_pkts, port->pmdid);
+       }
+       uint64_t pkts_for_process = ipv4_forward_pkts_mask;
+
+       struct ipv4_hdr *ipv4_hdr;
+       l2_phy_interface_t *port_ptr[RTE_PORT_IN_BURST_SIZE_MAX];
+       uint64_t hit_mask = 0;
+
+       for (; pkts_for_process;) {
+/**< process only valid packets.*/
+               uint8_t pos = (uint8_t) __builtin_ctzll(pkts_for_process);
+               uint64_t pkt_mask = 1LLU << pos;   /**< bitmask representing only this packet */
+               pkts_for_process &= ~pkt_mask;           /**< remove this packet from the mask */
+               ipv4_hdr =
+                               rte_pktmbuf_mtod_offset(pkt_burst[pos], struct ipv4_hdr *,
+                                                       sizeof(struct ether_hdr));
+               /* Make sure the IPv4 packet is valid  */
+               if (is_valid_ipv4_pkt(ipv4_hdr, pkt_burst[pos]->pkt_len) < 0) {
+                       rte_pktmbuf_free(pkt_burst[pos]);   /**< Drop the Unknown IPv4 Packet */
+                       pkt_burst[pos] = NULL;
+                       ipv4_forward_pkts_mask &= ~(1LLU << pos);  /**< That will clear bit of that position*/
+                       nb_pkts--;
+                       stats.nb_l3_drop_pkt++;
+               }
+       }
+
+       if (L3FWD_DEBUG) {
+               printf
+                               ("\nl3fwd_rx_ipv4_packets_received AFTER DROP: nb_pkts: %u, valid_Pkts_mask :%lu\n",
+                                nb_pkts, ipv4_forward_pkts_mask);
+       }
+
+       /* Lookup for IP destination in LPMv4 table */
+       lpm4_table_lookup(pkt_burst, nb_pkts, ipv4_forward_pkts_mask, port_ptr,
+                               &hit_mask);
+
+       for (; hit_mask;) {
+/**< process only valid packets.*/
+               uint8_t pos = (uint8_t) __builtin_ctzll(hit_mask);
+               uint64_t pkt_mask = 1LLU << pos;   /**< bitmask representing only this packet */
+               hit_mask &= ~pkt_mask;           /**< remove this packet from the mask */
+
+               port_ptr[pos]->transmit_single_pkt(port_ptr[pos],
+                                                        pkt_burst[pos]);
+       }
+
+}
+
+void
+l3_protocol_type_add(uint8_t protocol_type,
+                                void (*func) (struct rte_mbuf **, uint16_t, uint64_t,
+                                        l2_phy_interface_t *port))
+{
+       switch (protocol_type) {
+       case IPPROTO_ICMP:
+               proto_type[IP_LOCAL] =
+                               rte_malloc(NULL, sizeof(struct ip_protocol_type),
+                                                RTE_CACHE_LINE_SIZE);
+               proto_type[IP_LOCAL]->protocol_type = protocol_type;
+               proto_type[IP_LOCAL]->func = func;
+               break;
+
+       case IPPROTO_TCP:       // Time being treared as Remote forwarding
+       case IPPROTO_UDP:
+               proto_type[IP_REMOTE] =
+                               rte_malloc(NULL, sizeof(struct ip_protocol_type),
+                                                RTE_CACHE_LINE_SIZE);
+               proto_type[IP_REMOTE]->protocol_type = protocol_type;
+               proto_type[IP_REMOTE]->func = func;
+               break;
+
+       }
+
+}
+
+void l3fwd_rx_ipv4_packets(struct rte_mbuf **m, uint16_t nb_pkts,
+                                uint64_t valid_pkts_mask, l2_phy_interface_t *port)
+{
+       if (L3FWD_DEBUG) {
+               printf
+                               ("l3fwd_rx_ipv4_packets_received BEFORE DROP: nb_pkts: %u\n from in_port %u",
+                                nb_pkts, port->pmdid);
+       }
+       uint64_t pkts_for_process = valid_pkts_mask;
+
+       struct ipv4_hdr *ipv4_hdr;
+       uint32_t configure_port_ip = 0;
+       uint64_t icmp_pkts_mask = RTE_LEN2MASK(nb_pkts, uint64_t);
+       uint64_t ipv4_forward_pkts_mask = RTE_LEN2MASK(nb_pkts, uint64_t);
+       uint16_t nb_icmp_pkt = 0;
+       uint16_t nb_l3_pkt = 0;
+
+       if (port->ipv4_list != NULL)
+               configure_port_ip =
+                               (uint32_t) (((ipv4list_t *) (port->ipv4_list))->ipaddr);
+
+       for (; pkts_for_process;) {
+/**< process only valid packets.*/
+               uint8_t pos = (uint8_t) __builtin_ctzll(pkts_for_process);
+               uint64_t pkt_mask = 1LLU << pos;   /**< bitmask representing only this packet */
+               pkts_for_process &= ~pkt_mask;           /**< remove this packet from the mask */
+               ipv4_hdr =
+                               rte_pktmbuf_mtod_offset(m[pos], struct ipv4_hdr *,
+                                                       sizeof(struct ether_hdr));
+
+               if ((ipv4_hdr->next_proto_id == IPPROTO_ICMP)
+                               && (ipv4_hdr->dst_addr == configure_port_ip)) {
+                       ipv4_forward_pkts_mask &= ~pkt_mask; /**< Its  ICMP, remove this packet from the ipv4_forward_pkts_mask*/
+                       stats.nb_rx_l3_icmp_pkt++;  /**< Increment stats for ICMP PKT */
+                       nb_icmp_pkt++;
+               } else{         // Forward the packet
+                       icmp_pkts_mask &= ~pkt_mask;  /**< Not ICMP, remove this packet from the icmp_pkts_mask*/
+                       stats.nb_rx_l3_pkt++;
+                       nb_l3_pkt++;    /**< Increment stats for L3 PKT */
+               }
+       }
+
+       if (icmp_pkts_mask) {
+               if (L3FWD_DEBUG)
+                       printf
+                                       ("\n RECEiVED LOCAL ICMP PKT at L3...\n PROCESSING ICMP LOCAL PKT...\n");
+               proto_type[IP_LOCAL]->func(m, nb_icmp_pkt, icmp_pkts_mask,
+                                                port);
+       }
+
+       if (ipv4_forward_pkts_mask) {
+               if (L3FWD_DEBUG)
+                       printf
+                                       ("\n RECEIVED L3 PKT, \n\n FORWARDING L3 PKT....\n");
+               proto_type[IP_REMOTE]->func(m, nb_l3_pkt,
+                                                       ipv4_forward_pkts_mask, port);
+       }
+}
+
+void
+resolve_l2_adj(uint32_t nexthop_ip, uint8_t out_port_id,
+                                const struct ether_addr *hw_addr)
+{
+       struct l2_adj_key_ipv4 l2_adj_key = {
+               .Next_hop_ip = nexthop_ip,
+               .out_port_id = out_port_id,
+       };
+       //uint16_t ether_type = 0x0800;
+
+       struct l2_adj_entry *adj_data = retrieve_l2_adj_entry(l2_adj_key);
+
+       if (adj_data) {  /**< L2 Adj Entry Exists*/
+
+               printf
+                               ("l2_adj_entry exists ip%x, port %d, Refcnt :%u Address :%p\n",
+                                l2_adj_key.Next_hop_ip, l2_adj_key.out_port_id,
+                                adj_data->refcount, adj_data);
+
+               if (adj_data->flags == L2_ADJ_UNRESOLVED
+                               || memcmp(hw_addr, &adj_data->eth_addr,
+                                               sizeof(struct ether_addr))) {
+                       memcpy(adj_data->l2_string, hw_addr, sizeof(struct ether_addr));        //** < Precompute the L2 String encap*/
+                       memcpy(&adj_data->l2_string[6],
+                                                &adj_data->phy_port->macaddr,
+                                                sizeof(struct ether_addr));
+                       //memcpy(&adj_data->l2_string[12], &ether_type, 2);
+
+                       ether_addr_copy(hw_addr, &adj_data->eth_addr);
+                       adj_data->flags = L2_ADJ_RESOLVED;
+               }
+
+               return;
+       }
+
+       l2_phy_interface_t *port;
+       port = ifm_get_port(out_port_id);
+       if (port != NULL) {
+
+               uint32_t size =
+                               RTE_CACHE_LINE_ROUNDUP(sizeof(struct l2_adj_entry));
+               adj_data = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
+               if (adj_data == NULL) {
+                       printf("L2 Adjacency memory allocation failed !\n");
+                       return;
+               }
+
+               adj_data->out_port_id = out_port_id;
+               adj_data->Next_hop_ip = nexthop_ip;
+               adj_data->phy_port = port;
+
+               memcpy(adj_data->l2_string, hw_addr, sizeof(struct ether_addr));        //** < Precompute the L2 String encap*/
+               memcpy(&adj_data->l2_string[6], &adj_data->phy_port->macaddr,
+                                        sizeof(struct ether_addr));
+               //memcpy(&adj_data->l2_string[12], &ether_type, 2);
+
+               ether_addr_copy(hw_addr, &adj_data->eth_addr);
+               adj_data->flags = L2_ADJ_RESOLVED;
+
+               rte_hash_add_key_data(l2_adj_hash_handle, &l2_adj_key,
+                                                       adj_data);
+               printf
+                               ("L2 adj data stored in l2_adj_entry hash table,Addr:%p\n",
+                                adj_data);
+       } else
+               printf("PORT:%u IS DOWN...\n", out_port_id);
+
+       return;
+}
+
+uint8_t ip_hash_load_balance(struct rte_mbuf *mbuf)
+{
+       uint32_t src_addr_offset =
+                       MBUF_HDR_ROOM + ETH_HDR_SIZE + IP_HDR_SRC_ADR_OFST;
+       uint32_t dst_addr_offset =
+                       MBUF_HDR_ROOM + ETH_HDR_SIZE + IP_HDR_DST_ADR_OFST;
+       uint32_t *dst_addr = NULL;
+       uint32_t *src_addr = NULL;
+       src_addr =
+                       (uint32_t *) RTE_MBUF_METADATA_UINT8_PTR(mbuf, src_addr_offset);
+       dst_addr =
+                       (uint32_t *) RTE_MBUF_METADATA_UINT8_PTR(mbuf, dst_addr_offset);
+
+       uint32_t hash_key1 = *src_addr; /* STORE SRC IP in key1 variable */
+       uint32_t hash_key2 = *dst_addr; /* STORE DST IP in key variable */
+
+       hash_key1 = hash_key1 ^ hash_key2;      /* XOR With SRC and DST IP, Result is hask_key1 */
+       hash_key2 = hash_key1;  /* MOVE The result to hask_key2 */
+
+       hash_key1 = rotr32(hash_key1, 16);      /* Circular Rotate to 16 bit */
+       hash_key1 = hash_key1 ^ hash_key2;      /* XOR With Key1 with Key2 */
+
+       hash_key2 = hash_key1;  /* MOVE The result to hask_key2 */
+
+       hash_key1 = rotr32(hash_key1, 8);       /* Circular Rotate to 8 bit */
+       hash_key1 = hash_key1 ^ hash_key2;      /* XOR With Key1 with Key2 */
+
+       hash_key1 = hash_key1 & (HASH_BUCKET_SIZE - 1); /* MASK the KEY with BUCKET SIZE */
+       if (L3FWD_DEBUG)
+               printf("Hash Result_key: %d, \n", hash_key1);
+       return hash_key1;
+}
+
+uint32_t rotr32(uint32_t value, unsigned int count)
+{
+       const unsigned int mask = (CHAR_BIT * sizeof(value) - 1);
+       count &= mask;
+       return (value >> count) | (value << ((-count) & mask));
+}
+
+void
+ip_local_out_deliver(struct rte_mbuf **pkt_burst, uint16_t nb_rx,
+                                uint64_t ipv4_pkts_mask, l2_phy_interface_t *port)
+{
+       ip_forward_deliver(pkt_burst, nb_rx, ipv4_pkts_mask, port);
+}
diff --git a/common/VIL/l2l3_stack/l3fwd_lpm4.h b/common/VIL/l2l3_stack/l3fwd_lpm4.h
new file mode 100644 (file)
index 0000000..69e6236
--- /dev/null
@@ -0,0 +1,374 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+/**
+* @file
+* L3fwd lpm4 header file is for IPv4 specific declarations
+*/
+#ifndef L3FWD_LPM_H
+#define L3FWD_LPM_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <string.h>
+#include <sys/queue.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <getopt.h>
+#include <stdbool.h>
+
+#include <rte_debug.h>
+#include <rte_memory.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_ring.h>
+#include <rte_mempool.h>
+#include <rte_cycles.h>
+#include <rte_mbuf.h>
+#include <rte_ip.h>
+#include <rte_tcp.h>
+#include <rte_udp.h>
+#include <rte_lpm.h>
+#include <rte_lpm6.h>
+#include "l3fwd_common.h"
+#include "l3fwd_lpm6.h"
+#include "interface.h"
+
+/**
+* Define all RTE MBUF offset size
+*/
+
+#define MBUF_HDR_ROOM 256 /**< MBUF HEADER ROOM OFFSET */
+
+/* IPv4 */
+#define ETH_HDR_SIZE  14 /**< ETHER HEADER OFFSET */
+#define IP_HDR_SIZE  20        /**< IP HEADER OFFSET */
+#define IP_HDR_DST_ADR_OFST 16 /**< IP HEADER DST IP ADDRESS OFFSET */
+#define IP_HDR_SRC_ADR_OFST 12 /**< IP HEADER SRC IP ADDRESS OFFSET */
+
+/* Rules and Tables8s */
+#define IPV4_L3FWD_LPM_MAX_RULES      256  /**< Number of LPM RULES */
+#define IPV4_L3FWD_LPM_NUMBER_TBL8S (1 <<  8) /**< Number of TABLE 8s for LPM */
+#define MAX_FIB_PATHS 8        /**< MAX FIB PATH, If ECMP feature is enabled */
+#define IP_LOCAL 0 /**< for ICMP Packet destined to Local */
+#define IP_REMOTE 1 /**< for ICMP Packet destined to Local */
+
+/* ECMP MACROS */
+#define MAX_SUPPORTED_FIB_PATHS 8 /**< for ECMP max supported FIB Paths */
+#define HASH_BUCKET_SIZE 64  /**< size of HASH bucket for ECMP */
+
+/* L2 Adjacency Macro */
+#define L2_ADJ_RESOLVED   0x00 /** <MACRO to define a flag as Resolved*/
+#define L2_ADJ_UNRESOLVED 0x01 /** <MacrO to define a flag as Unresolved */
+/**
+* A structure used to define the routing information for IPv4
+* This structure is used as input parameters for route ADD
+*/
+struct routing_info {
+       uint32_t dst_ip_addr;  /**< DST IP Address */
+       uint8_t depth;                           /**< Depth */
+       uint32_t metric;       /**< Metrics */
+       uint32_t fib_nh_size; /**< num of fib paths, greater than if Multipath(ECMP) feature is supported*/
+       uint32_t nh_ip_addr[MAX_FIB_PATHS];   /**< NextHop IP Address */
+       uint8_t out_port[MAX_FIB_PATHS];      /**< OUTGOING PORT */
+} __rte_cache_aligned;
+
+/**
+* A structure used to define the fib path for Destination IP Address
+* This fib path is shared accross different fib_info.
+*/
+struct fib_path {
+       uint32_t nh_ip;         /**< Next hop IP address (only valid for remote routes) */
+       uint8_t out_port;       /**< Output port */
+       uint32_t refcount;      /**< Refcount, greater then 1 if multiple fib_info has same fib_path*/
+       struct l2_adj_entry *l2_adj_ptr; /**< Address of the L2 ADJ table entry */
+} __rte_cache_aligned;                          /**< RTE CACHE ALIGNED */
+
+/**
+* A structure used to define the fib info (Route info)
+* This fib info structure can have multiple fib paths.
+*/
+struct fib_info {
+       uint32_t dst_ip_addr; /**< DST IP Address */
+       uint32_t metric;      /**< Metrics */
+       uint32_t fib_nh_size; /**< num of fib paths, greater than if Multipath(ECMP) feature is supported*/
+       uint8_t depth;                          /**< Depth */
+       struct fib_path *path[MAX_FIB_PATHS]; /**< Array of pointers to the fib_path */
+} __rte_cache_aligned;                         /**< RTE CACHE ALIGNED */
+
+/**
+* A structure used to define the L2 Adjacency table
+*/
+struct l2_adj_entry {
+       struct ether_addr eth_addr;    /**< Ether address */
+       uint32_t Next_hop_ip;                            /**< Next hop IP address (only valid for remote routes) */
+       uint8_t out_port_id;                             /**< Output port */
+       uint32_t refcount;                               /**< Refcount, greater then 1 if multiple fib_path has same L2_adj_entry*/
+       uint8_t l2_string[256];                          /**< L2 string, to rewrite the packet before transmission */
+       l2_phy_interface_t *phy_port;  /**<  Address of the L2 physical interface structure */
+       uint8_t flags;                                   /**< Set to unresolved, when ARP entry not available. Set to resolved, when ARP is available */
+} __rte_cache_aligned;                                  /**< RTE CACHE ALIGNED */
+
+/**
+* A structure used to define the fib path key for hash table
+*/
+struct fib_path_key_ipv4 {
+       uint32_t nh_ip;                 /**< Next hop IP address */
+       uint8_t out_port;   /**< Output port */
+       uint8_t filler1;    /**< Filler 1, for better hash key */
+       uint8_t filler2;    /**< Filler2, for better hash key*/
+       uint8_t filler3;    /**< Filler3, for better hash Key */
+};
+
+/**
+* A structure used to define the fib path key for hash table
+*/
+struct l2_adj_key_ipv4 {
+       uint32_t Next_hop_ip;   /**< Next hop IP address */
+       uint8_t out_port_id;    /**< Output port */
+       uint8_t filler1;        /**< Filler 1, for better hash key */
+       uint8_t filler2;        /**< Filler2, for better hash key*/
+       uint8_t filler3;        /**< Filler3, for better hash Key */
+};
+
+/**
+* A structure used to hold the fib info after LPM Lookup
+*/
+struct routing_table_entry {
+       uint32_t ip;                     /**< Next hop IP address (only valid for remote routes) */
+       uint8_t port_id;                 /**< Output port ID */
+       struct l2_adj_entry *l2_adj_ptr; /**< Address of L2 Adjacency table entry */
+} __rte_cache_aligned;                  /**< RTE CACHE ALIGNED */
+
+/**
+* A structure used to define the L3 counter statistics
+*/
+typedef struct l3fwd_stats {
+       uint64_t nb_rx_l3_pkt;          /**< Num of L3 pkts Received */
+       uint64_t nb_tx_l3_pkt;          /**< Num of L3 pkts Transmitted */
+       uint64_t nb_rx_l3_icmp_pkt;
+                                       /**< Num of ICMP pkts Received at L3*/
+       uint64_t nb_tx_l3_icmp_pkt;
+                                       /**< Num of ICMP pkts Transmitted at L3*/
+       uint64_t nb_l3_drop_pkt;  /**< Num of L3 Packets Dropped*/
+       uint64_t total_nb_rx_l3_pkt;
+                                       /**< Total Num of L3 Packets received, includes ICMP Pkt*/
+       uint64_t total_nb_tx_l3_pkt;
+                                       /**< Total Num of L3 Packets Transmitted, includes ICMP Pkt*/
+} l3_stats_t;
+
+struct ip_protocol_type {
+       uint8_t protocol_type;          /**< Protocol Type */
+       void (*func) (struct rte_mbuf **, uint16_t, uint64_t,
+                                       l2_phy_interface_t *);
+} __rte_cache_aligned;
+
+/* Function Declarations */
+
+/**
+ * To creare LPM table, Cuckoo hash table for fib_path and l2_adj_entry tables
+ * @return
+ * 0 for failure, 1 for success
+ */
+int lpm_init(void);
+
+/**
+ * To add a route in LPM table by populating fib_path and L2 Adjacency.
+ * @param input_array
+ * To add the route based on routing_info stucture.
+ * @return
+ * 0 for failure, 1 for success
+ */
+int lpm4_table_route_add(struct routing_info *input_array);
+
+/**
+ * To Delete the IP route and corresponding fib_path and L2 Adjacency entries.
+ * @param ip
+ * Destionation IP for which the route need to deleted
+ * @param depth
+ * netmask for the Destination IP
+ * @return
+ * 0 for failure, 1 for success
+ */
+int lpm4_table_route_delete(uint32_t ip, uint8_t depth);
+
+/**
+ * To perform a LPM table lookup
+ * @param pkts_burst
+ * Burst of packets that needs to be lookup in LPM table
+ * @param nb_pkts
+ * number of packets that needs to be lookup in LPM table
+ * @param valid_pkts_mask
+ * lookup of the valid IPv4 Pkt mask
+ * @return
+ * 0 for failure, 1 for success
+ */
+int lpm4_table_lookup(struct rte_mbuf **pkts_burst, uint16_t nb_pkts,
+                                       uint64_t valid_pkts_mask,
+                                       l2_phy_interface_t *port[RTE_PORT_IN_BURST_SIZE_MAX],
+                                       uint64_t *hit_mask);
+
+/**
+ * To Verify whether the received IPv4 Packet is valid or not
+ * @param pkt
+ * packet pointing to IPv4 header that needs to be verifed
+ * @param link_len
+ * length of the IPv4 Pkt
+ * @return
+ * 0 for failure, 1 for success
+*/
+int is_valid_ipv4_pkt(struct ipv4_hdr *pkt, uint32_t link_len);
+
+/**
+ * To forward the valid L3 packets for LMP table lookup and forward ICMP Pkts to ICMP module
+ * @param m
+ * packet burst of type rte_mbuf
+ * @param nb_pkts
+ * Number of valid L3 packets
+ * @param pkt_mask
+ * Valid IPv4 packets mask that needs to be processed
+ * @param port
+ * IPv4 Pkt received form the input port structure.
+ * @return
+ * 0 for failure, 1 for success
+*/
+void l3fwd_rx_ipv4_packets(struct rte_mbuf **m, uint16_t nb_pkts,
+                                uint64_t pkt_mask, l2_phy_interface_t *port);
+
+/**
+ * To get the destination MAC Address for the nexthop IP and outgoing port
+ * @param next_hop_ip
+ * Next HOP IP Address for which MAC address is needed
+ * @param out_phy_port
+ * Outgoing physical port
+ * @param hw_addr
+ * pointer to the ether_add, This gets update with valid MAC address based on nh_ip and out port
+ * @return
+ * 0 if failure, 1 if success
+ */
+int get_dest_mac_for_nexthop(uint32_t next_hop_ip,
+                                        uint8_t out_phy_port, struct ether_addr *hw_addr);
+/**
+ * To retrieve the l2_adj_entry for the nexthop IP and outgoing port
+ * This queries with cuckoo hash table based on the l2_adj_key_ipv4
+ * @param l2_adj_key
+ * Key which is required for Cuckook hash table lookup
+ * @return
+ * NULL if lookup fails, Address of the L2_adj_entry if lookup success
+*/
+
+struct l2_adj_entry *retrieve_l2_adj_entry(struct l2_adj_key_ipv4 l2_adj_key);
+
+/**
+ * To populate the l2_adj_entry for the nexthop IP and outgoing port
+ * @param ipaddr
+ * NextHop Ip Address for which L2_adj_entry needs to be populated
+ * @param portid
+ * outgong port ID
+ * @return
+ * NULL if lookup fails, Address of the L2_adj_entry if lookup success
+*/
+
+struct l2_adj_entry *populate_l2_adj(uint32_t ipaddr, uint8_t portid);
+
+/**
+ * To populate the fib_path for the nexthop IP and outgoing port
+ * @param nh_ip
+ * NextHop Ip Address for which L2_adj_entry needs to be populated
+ * @param portid
+ * outgong port ID
+ * @return
+ * NULL if lookup fails, Address of the type fib_path if lookup success
+*/
+struct fib_path *populate_fib_path(uint32_t nh_ip, uint8_t portid);
+
+/**
+ * To retrieve the fib_path entry for the nexthop IP and outgoing port
+ * This queries with cuckoo hash table based on the fib_path_key_ipv4
+ * @param path_key
+ * Key which is required for Cuckook hash table lookup
+ * @return
+ * NULL if lookup fails, Address of type fib_path if lookup success
+*/
+
+struct fib_path *retrieve_fib_path_entry(struct fib_path_key_ipv4 path_key);
+
+/**
+ * To delete the fib path and l2 adjacency entry from the cuckoo hash table
+ * @return
+ * None
+*/
+void remove_fib_l2_adj_entry(void *);
+
+/**
+ * To iterate the cuckoo hash table for fib_path and l2_adj_entry and print the table contents
+ * @return
+ * None
+*/
+void iterate_cuckoo_hash_table(void);
+
+/**
+ * To print the l3 counter statitics
+ * @return
+ * None
+*/
+void print_l3_stats(void);
+
+/**
+ * To get the hash resultant value based on SRC IP and DST IP
+ * @param mbuf
+ * packet of type rte_mbuf
+ * @return
+ * It returns a result of type uint8_t
+ */
+
+uint8_t ip_hash_load_balance(struct rte_mbuf *mbuf);
+
+/**
+ * Rotates the count number of bits from the value
+ * @param value
+ * an integer value
+ * @param count
+ * rotates a count number of bits from integer value
+ * @return
+ * It returns a result.
+ */
+
+uint32_t rotr32(uint32_t value, unsigned int count);
+
+void
+resolve_l2_adj(uint32_t nexthop_ip, uint8_t out_port_id,
+                                const struct ether_addr *hw_addr);
+
+void
+l3_protocol_type_add(uint8_t protocol_type,
+                                void (*func) (struct rte_mbuf **, uint16_t, uint64_t,
+                                        l2_phy_interface_t *));
+
+void
+ip_local_packets_process(struct rte_mbuf **, uint16_t, uint64_t,
+                        l2_phy_interface_t *);
+void ip_local_out_deliver(struct rte_mbuf **, uint16_t, uint64_t,
+                               l2_phy_interface_t *);
+
+void
+ip_forward_deliver(struct rte_mbuf **, uint16_t, uint64_t,
+                        l2_phy_interface_t *);
+
+#endif                         /* L3FWD_LPM_H */
diff --git a/common/VIL/l2l3_stack/l3fwd_lpm6.c b/common/VIL/l2l3_stack/l3fwd_lpm6.c
new file mode 100644 (file)
index 0000000..7aa7fb6
--- /dev/null
@@ -0,0 +1,1058 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include "l3fwd_common.h"
+#include "l3fwd_lpm4.h"
+#include "l3fwd_lpm6.h"
+#include "l3fwd_common.h"
+#include "interface.h"
+#include "l2_proto.h"
+#include "lib_arp.h"
+#include "lib_icmpv6.h"
+
+/* Declare Global variables */
+
+/* Global for IPV6 */
+void *lpm6_table; /**< lpm6 table handler */
+struct rte_hash *l2_adj_ipv6_hash_handle;  /**< IPv6 l2 adjacency table handler */
+struct rte_hash *fib_path_ipv6_hash_handle;  /**< IPv6 fib path hash table handler */
+extern uint8_t nh_links[MAX_SUPPORTED_FIB_PATHS][HASH_BUCKET_SIZE];
+extern l3_stats_t stats; /**< L3 statistics */
+
+static struct ipv6_protocol_type *proto_type[2];
+
+int lpm6_init(void)
+{
+
+       /* Initiliaze LPMv6 params */
+
+       struct rte_table_lpm_ipv6_params lpm6_params = {
+               .name = "LPMv6",
+               .n_rules = IPV6_L3FWD_LPM_MAX_RULES,
+               .number_tbl8s = IPV6_L3FWD_LPM_NUMBER_TBL8S,
+               .entry_unique_size = sizeof(struct ipv6_fib_info),
+               .offset = 128,
+       };
+
+       /* Create LPMv6 tables */
+       lpm6_table =
+                       rte_table_lpm_ipv6_ops.f_create(&lpm6_params, rte_socket_id(),
+                                                       sizeof(struct ipv6_fib_info));
+       if (lpm6_table == NULL) {
+               printf("Failed to create LPM IPV6 table\n");
+               return 0;
+       }
+
+       /*Initialize IPv6 params for l2 Adj  */
+       struct rte_hash_parameters l2_adj_ipv6_params = {
+               .name = "l2_ADJ_IPV6_HASH",
+               .entries = 64,
+               .key_len = sizeof(struct l2_adj_key_ipv6),
+               .hash_func = rte_jhash,
+               .hash_func_init_val = 0,
+       };
+
+       l2_adj_ipv6_hash_handle = rte_hash_create(&l2_adj_ipv6_params);
+       if (l2_adj_ipv6_hash_handle == NULL) {
+               printf("ND for IPV6 rte_hash_create failed.\n");
+               return 0;
+       } else {
+               printf("ND IPV6_hash_handle %p\n\n",
+                                        (void *)l2_adj_ipv6_hash_handle);
+       }
+
+       /*Initialize Fib PAth hassh params  */
+       struct rte_hash_parameters fib_path_ipv6_params = {
+               .name = "FIB_PATH_IPV6_HASH",
+               .entries = 64,
+               .key_len = sizeof(struct fib_path_key_ipv6),
+               .hash_func = rte_jhash,
+               .hash_func_init_val = 0,
+               .extra_flag = 1,
+       };
+
+       /* Create FIB PATH Hash tables */
+       fib_path_ipv6_hash_handle = rte_hash_create(&fib_path_ipv6_params);
+
+       if (fib_path_ipv6_hash_handle == NULL) {
+               printf("FIB path rte_hash_create failed\n");
+               return 0;
+       }
+       return 1;
+}
+
+int lpm6_table_route_add(struct ipv6_routing_info *data)
+{
+
+       struct ipv6_routing_info *fib = data;
+       /* Populate the Key */
+       struct rte_table_lpm_ipv6_key lpm6_key;
+       uint8_t i;
+       for (i = 0; i < 16; i++) {
+               lpm6_key.ip[i] = fib->dst_ipv6[i];
+       }
+       lpm6_key.depth = fib->depth;
+
+       static int Total_route_count;
+       struct ipv6_fib_info entry;
+       for (i = 0; i < 16; i++) {
+               entry.dst_ipv6[i] = fib->dst_ipv6[i];
+       }
+       entry.depth = fib->depth;
+       entry.fib_nh_size = fib->fib_nh_size;
+
+#if MULTIPATH_FEAT
+       if (entry.fib_nh_size == 0 || entry.fib_nh_size > MAX_FIB_PATHS)
+#else
+       if (entry.fib_nh_size != 1)     /**< For Single FIB_PATH */
+#endif
+       {
+               printf
+                               ("Route's can't be configured!!, entry.fib_nh_size = %d\n",
+                                entry.fib_nh_size);
+               return 0;
+       }
+
+       /* Populate L2 adj and precomputes l2 encap string */
+#if MULTIPATH_FEAT
+       for (i = 0; i < entry.fib_nh_size; i++)
+#else
+       for (i = 0; i < 1; i++)
+#endif
+       {
+               struct ipv6_fib_path *ipv6_fib_path_addr = NULL;
+               ipv6_fib_path_addr =
+                               populate_ipv6_fib_path(fib->nh_ipv6[i], fib->out_port[i]);
+
+               if (ipv6_fib_path_addr) {
+                       entry.path[i] = ipv6_fib_path_addr;
+                       printf("Fib path for IPv6 destination = "
+                                                "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:"
+                                                "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x/%u) ==> fib_path Addr :%p, L2_adj Addr ;%p\n",
+                                                lpm6_key.ip[0], lpm6_key.ip[1], lpm6_key.ip[2],
+                                                lpm6_key.ip[3], lpm6_key.ip[4], lpm6_key.ip[5],
+                                                lpm6_key.ip[6], lpm6_key.ip[7], lpm6_key.ip[8],
+                                                lpm6_key.ip[9], lpm6_key.ip[10], lpm6_key.ip[11],
+                                                lpm6_key.ip[12], lpm6_key.ip[13],
+                                                lpm6_key.ip[14], lpm6_key.ip[15], fib->depth,
+                                                ipv6_fib_path_addr,
+                                                (void *)entry.path[i]->l2_adj_ipv6_ptr);
+               } else {
+                       printf("Fib path for IPv6 destination = "
+                                                "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:"
+                                                "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x/%u) ==> fib_path Addr : NULL\n",
+                                                lpm6_key.ip[0], lpm6_key.ip[1], lpm6_key.ip[2],
+                                                lpm6_key.ip[3], lpm6_key.ip[4], lpm6_key.ip[5],
+                                                lpm6_key.ip[6], lpm6_key.ip[7], lpm6_key.ip[8],
+                                                lpm6_key.ip[9], lpm6_key.ip[10], lpm6_key.ip[11],
+                                                lpm6_key.ip[12], lpm6_key.ip[13],
+                                                lpm6_key.ip[14], lpm6_key.ip[15], fib->depth);
+                       entry.path[i] = NULL;   /**< setting all other fib_paths to NULL */
+               }
+       }
+
+       int key_found, ret;
+       void *entry_ptr;
+
+       /* Adding a IP route in LPMv6 table */
+       printf("%s, Line %u \n", __FUNCTION__, __LINE__);
+
+       ret =
+                       rte_table_lpm_ipv6_ops.f_add(lpm6_table, (void *)&lpm6_key, &entry,
+                                        &key_found, &entry_ptr);
+       printf("%s, Line %u \n", __FUNCTION__, __LINE__);
+
+       if (ret) {
+               printf("Failed to Add IP route in LPMv6\n");
+               return 0;
+       }
+       printf("Added route to IPv6 LPM table (IPv6 destination = "
+                                "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:"
+                                "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x/%u)\n",
+                                lpm6_key.ip[0], lpm6_key.ip[1], lpm6_key.ip[2], lpm6_key.ip[3],
+                                lpm6_key.ip[4], lpm6_key.ip[5], lpm6_key.ip[6], lpm6_key.ip[7],
+                                lpm6_key.ip[8], lpm6_key.ip[9], lpm6_key.ip[10], lpm6_key.ip[11],
+                                lpm6_key.ip[12], lpm6_key.ip[13], lpm6_key.ip[14],
+                                lpm6_key.ip[15], fib->depth);
+
+       Total_route_count++;
+       printf("Total Routed Added : %u, Key_found: %d\n", Total_route_count,
+                                key_found);
+
+       if (Total_route_count == 2)
+               ipv6_iterate__hash_table();
+
+       return 1;
+}
+
+int
+lpm6_table_route_delete(uint8_t dst_ipv6[RTE_LPM_IPV6_ADDR_SIZE], uint8_t depth)
+{
+
+       /* Populate the Key */
+       struct rte_table_lpm_ipv6_key lpm6_key;
+       memcpy(&lpm6_key.ip, &dst_ipv6, sizeof(RTE_LPM_IPV6_ADDR_SIZE));
+       lpm6_key.depth = depth;
+       int key_found, ret;
+       char *entry = NULL;
+       entry = rte_zmalloc(NULL, 512, RTE_CACHE_LINE_SIZE);
+       /* Delete a IP route in LPMv6 table */
+       ret =
+                       rte_table_lpm_ipv6_ops.f_delete(lpm6_table, &lpm6_key, &key_found,
+                                                       entry);
+
+       if (ret) {
+               printf("Failed to Delete IP route from LPMv6 table\n");
+               return 0;
+       }
+
+       printf("Deleted route from IPv6 LPM table (IPv6 destination = "
+                                "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:"
+                                "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x/%u, key_found = %d\n",
+                                lpm6_key.ip[0], lpm6_key.ip[1], lpm6_key.ip[2], lpm6_key.ip[3],
+                                lpm6_key.ip[4], lpm6_key.ip[5], lpm6_key.ip[6], lpm6_key.ip[7],
+                                lpm6_key.ip[8], lpm6_key.ip[9], lpm6_key.ip[10], lpm6_key.ip[11],
+                                lpm6_key.ip[12], lpm6_key.ip[13], lpm6_key.ip[14],
+                                lpm6_key.ip[15], lpm6_key.depth, key_found);
+
+       /* Deleting a L2 Adj entry if refcount is 1, Else decrement Refcount */
+       remove_ipv6_fib_l2_adj_entry(entry);
+       rte_free(entry);        // free memory
+       return 1;
+}
+
+int
+lpm6_table_lookup(struct rte_mbuf **pkts_burst,
+                       uint16_t nb_pkts,
+                       uint64_t pkts_mask,
+                       l2_phy_interface_t *port_ptr[RTE_PORT_IN_BURST_SIZE_MAX],
+                       uint64_t *hit_mask)
+{
+       struct ipv6_routing_table_entry
+                       *ipv6_entries[RTE_PORT_IN_BURST_SIZE_MAX];
+       uint64_t lookup_hit_mask_ipv6 = 0;
+       int status;
+       uint64_t lookup_miss_mask = pkts_mask;
+       /*Populate the key offset in META DATA */
+       uint32_t dst_addr_offset =
+                       MBUF_HDR_ROOM + ETH_HDR_SIZE + IP_HDR_DST_ADR_OFST_IPV6;
+       uint64_t pkts_key_mask = pkts_mask;
+
+       //for(i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++)
+       for (; pkts_key_mask;) {
+/**< Populate key offset in META DATA for all valid pkts */
+               uint8_t pos = (uint8_t) __builtin_ctzll(pkts_key_mask);
+               uint64_t pkt_mask = 1LLU << pos;
+               pkts_key_mask &= ~pkt_mask;
+
+               uint8_t *lpm6_key;
+               uint8_t dst_addr[RTE_LPM_IPV6_ADDR_SIZE];
+               memcpy(dst_addr,
+                                        (uint8_t *) RTE_MBUF_METADATA_UINT32_PTR(pkts_burst[pos],
+                                                               dst_addr_offset),
+                                        RTE_LPM_IPV6_ADDR_SIZE);
+               lpm6_key =
+                               (uint8_t *) RTE_MBUF_METADATA_UINT8_PTR(pkts_burst[pos],
+                                                                       128);
+               memcpy(lpm6_key, dst_addr, RTE_LPM_IPV6_ADDR_SIZE);
+       }
+       /* Lookup for IP route in LPM6 table */
+       printf(" IPV6 Lookup Mask Before = %p, nb_pkts :%u\n",
+                                (void *)pkts_mask, nb_pkts);
+       status =
+                       rte_table_lpm_ops.f_lookup(lpm6_table, pkts_burst, pkts_mask,
+                                                        &lookup_hit_mask_ipv6,
+                                                        (void **)ipv6_entries);
+       if (status) {
+               printf("LPM Lookup failed for IP route\n");
+               return 0;
+       }
+       printf(" IPV6 Lookup Mask After = %p\n", (void *)lookup_hit_mask_ipv6);
+       lookup_miss_mask = lookup_miss_mask & (~lookup_hit_mask_ipv6);
+       if (L3FWD_DEBUG) {
+               printf("AFTER lookup_hit_mask = %p, lookup_miss_mask =%p\n",
+                                        (void *)lookup_hit_mask_ipv6, (void *)lookup_miss_mask);
+       }
+
+       for (; lookup_miss_mask;) {
+/**< Drop packets for lookup_miss_mask */
+               uint8_t pos = (uint8_t) __builtin_ctzll(lookup_miss_mask);
+               uint64_t pkt_mask = 1LLU << pos;
+               lookup_miss_mask &= ~pkt_mask;
+               rte_pktmbuf_free(pkts_burst[pos]);
+               pkts_burst[pos] = NULL;
+               if (L3FWD_DEBUG)
+                       printf("\n DROP PKT IPV4 Lookup_miss_Mask  = %p\n",
+                                                (void *)lookup_miss_mask);
+
+       }
+       *hit_mask = lookup_hit_mask_ipv6;
+       for (; lookup_hit_mask_ipv6;) {
+               uint8_t pos = (uint8_t) __builtin_ctzll(lookup_hit_mask_ipv6);
+               uint64_t pkt_mask = 1LLU << pos;
+               lookup_hit_mask_ipv6 &= ~pkt_mask;
+               struct rte_mbuf *pkt = pkts_burst[pos];
+
+               struct ipv6_fib_info *entry =
+                               (struct ipv6_fib_info *)ipv6_entries[pos];
+
+#if MULTIPATH_FEAT
+
+               uint8_t ecmp_path = ipv6_hash_load_balance(pkts_burst[pos]);
+               uint8_t selected_path = 0;
+               struct ipv6_fib_path *fib_path = NULL;
+               if (((entry->fib_nh_size != 0)
+                                && (entry->fib_nh_size - 1) < MAX_SUPPORTED_FIB_PATHS)
+                               && ((ecmp_path != 0) && (ecmp_path - 1) < HASH_BUCKET_SIZE))
+                       selected_path =
+                                       nh_links[entry->fib_nh_size - 1][ecmp_path - 1];
+               if (selected_path < MAX_FIB_PATHS)
+                       fib_path = entry->path[selected_path];
+               printf
+                               ("Total supported Path :%u, Hashed ECMP Key : %u, selected Fib_path: %u\n",
+                                entry->fib_nh_size, ecmp_path, selected_path);
+#else
+               struct ipv6_fib_path *fib_path = entry->path[0];
+#endif
+               if (fib_path == NULL) {
+                       printf("Fib_path is NULL, ND has not resolved\n");
+                       rte_pktmbuf_free(pkt);
+                       pkts_burst[pos] = NULL;
+                       stats.nb_l3_drop_pkt++;  /**< Peg the L3 Drop counter */
+                       *hit_mask &= ~pkt_mask; /**< Remove this pkt from port Mask */
+                       printf
+                                       ("Fib_path is NULL, ND has not resolved, DROPPED UNKNOWN PKT\n");
+                       continue;
+               }
+
+               if (fib_path->l2_adj_ipv6_ptr->flags == L2_ADJ_UNRESOLVED) {
+                       rte_pktmbuf_free(pkts_burst[pos]);
+                       pkts_burst[pos] = NULL;
+                       *hit_mask &= ~pkt_mask; /**< Remove this pkt from port Mask */
+                       if (L3FWD_DEBUG)
+                               printf
+                                               ("L2_ADJ_UNRESOLVED, DROPPED UNKNOWN PKT\n");
+                       continue;
+               }
+
+               uint8_t *eth_dest =
+                               RTE_MBUF_METADATA_UINT8_PTR(pkt, MBUF_HDR_ROOM);
+               uint8_t *eth_src =
+                               RTE_MBUF_METADATA_UINT8_PTR(pkt, MBUF_HDR_ROOM + 6);
+               if (L3FWD_DEBUG) {
+                       printf
+                               ("MAC BEFORE- DST MAC %02x:%02x:%02x:%02x"
+                                ":%02x:%02x, "
+                                "SRC MAC %02x:%02x:%02x:%02x:"
+                                "%02x:%02x \n",
+                                eth_dest[0], eth_dest[1], eth_dest[2],
+                                eth_dest[3],
+                                eth_dest[4], eth_dest[5], eth_src[0],
+                                eth_src[1],
+                                eth_src[2], eth_src[3],
+                                eth_src[4], eth_src[5]);
+               }
+
+               /* Rewrite the packet with L2 string  */
+               memcpy(eth_dest, fib_path->l2_adj_ipv6_ptr->l2_string,
+                                        sizeof(struct ether_addr) * 2 + 2);
+
+               if (L3FWD_DEBUG) {
+                       printf
+                               ("MAC AFTER DST MAC %02x:%02x:%02x:%02x:%02x:%02x,"
+                                "SRC MAC %02x:%02x:%02x:%02x:"
+                                "%02x:%02x\n", eth_dest[0],
+                                eth_dest[1], eth_dest[2], eth_dest[3],
+                                eth_dest[4],
+                                eth_dest[5], eth_src[0], eth_src[1],
+                                eth_src[2],
+                                eth_src[3], eth_src[4], eth_src[5]);
+               }
+               port_ptr[pos] = fib_path->l2_adj_ipv6_ptr->phy_port;
+
+               //fib_path->l2_adj_ipv6_ptr->phy_port->transmit_single_pkt(fib_path->l2_adj_ipv6_ptr->phy_port, pkt);
+               if (L3FWD_DEBUG)
+                       printf("Successfully sent to port %u \n\r",
+                                                fib_path->out_port);
+       }
+       return 1;
+}
+
+void l3fwd_rx_ipv6_packets(struct rte_mbuf **m, uint16_t nb_pkts,
+                                uint64_t valid_pkts_mask, l2_phy_interface_t *port)
+{
+       if (!port)
+               return;
+       if (L3FWD_DEBUG) {
+               printf
+                               ("l3fwd_rx_ipv6_packets_received BEFORE DROP: nb_pkts: %u, from in_port %u, valid_pkts_mask:%"
+                                PRIu64 "\n", nb_pkts, port->pmdid, valid_pkts_mask);
+       }
+       uint64_t pkts_for_process = valid_pkts_mask;
+
+       struct ipv6_hdr *ipv6_hdr;
+       //struct ether_hdr *eth_h;
+       uint64_t icmp_pkts_mask = valid_pkts_mask;
+       uint64_t ipv6_forward_pkts_mask = valid_pkts_mask;
+       uint16_t nb_icmpv6_pkt = 0;
+       uint16_t nb_l3_pkt = 0;
+
+       uint8_t configured_port_ipv6[RTE_LPM_IPV6_ADDR_SIZE] = { 0 };
+       int8_t solicited_node_multicast_addr[RTE_LPM_IPV6_ADDR_SIZE] = {
+               0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x01, 0xff, 0x00, 0x00, 0x00 };
+       uint8_t dest_ipv6_addr[RTE_LPM_IPV6_ADDR_SIZE];
+
+       memset(dest_ipv6_addr, 0, RTE_LPM_IPV6_ADDR_SIZE);
+
+       printf("\n%s : LINE # %u\n", __FUNCTION__, __LINE__);
+       int ii;
+       if (port->ipv6_list != NULL) {
+               for (ii = 0; ii < 16; ii += 1) {
+                       configured_port_ipv6[ii] =
+                                       ((ipv6list_t *) (port->ipv6_list))->ipaddr[ii];
+               }
+       }
+       //      memcpy(&configured_port_ipv6, &(((ipv6list_t*)(port->ipv6_list))->ipaddr), RTE_LPM_IPV6_ADDR_SIZE);
+
+       for (ii = 0; ii < 16; ii += 2) {
+               if (port && port->ipv6_list)
+                       printf("%02X%02X ",
+                                                ((ipv6list_t *) (port->ipv6_list))->ipaddr[ii],
+                                                ((ipv6list_t *) (port->ipv6_list))->ipaddr[ii +
+                                                                               1]);
+       }
+
+       printf("\n%s : LINE # %u\n", __FUNCTION__, __LINE__);
+       for (ii = 0; ii < 16; ii += 2) {
+               printf("%02X%02X ", configured_port_ipv6[ii],
+                                        configured_port_ipv6[ii + 1]);
+       }
+
+       for (; pkts_for_process;) {
+/**< process only valid packets.*/
+               printf("\n%s : LINE # %u\n", __FUNCTION__, __LINE__);
+               uint8_t pos = (uint8_t) __builtin_ctzll(pkts_for_process);
+               uint64_t pkt_mask = 1LLU << pos;    /**< bitmask representing only this packet */
+               pkts_for_process &= ~pkt_mask;                  /**< remove this packet from the mask */
+               //printf("\n%s : LINE # %u\n", __FUNCTION__, __LINE__);
+               //eth_h = rte_pktmbuf_mtod(m[pos], struct ether_hdr *);
+               printf("\n%s : LINE #%u,  POS%u\n", __FUNCTION__, __LINE__,
+                                        pos);
+               //ipv6_hdr = (struct ipv6_hdr *)((char *)eth_h + sizeof(struct ether_hdr));
+               if (m[pos] == NULL) {
+                       printf("\n%s : M_POS IS NULLLLLLL, LINE: %u\n",
+                                                __FUNCTION__, __LINE__);
+                       return;
+               }
+               ipv6_hdr =
+                               rte_pktmbuf_mtod_offset(m[pos], struct ipv6_hdr *,
+                                                       sizeof(struct ether_hdr));
+               printf("\n%s : LINE # %u\n", __FUNCTION__, __LINE__);
+               for (ii = 0; ii < 13; ii += 1) {
+                       dest_ipv6_addr[ii] = ipv6_hdr->dst_addr[ii];
+               }
+
+               printf("\n");
+               printf("\n%s : LINE # %u\n", __FUNCTION__, __LINE__);
+               for (ii = 0; ii < 16; ii += 2) {
+                       printf("%02X%02X ", ipv6_hdr->dst_addr[ii],
+                                                ipv6_hdr->dst_addr[ii + 1]);
+               }
+               printf("\n");
+               printf("\n%s : LINE # %u\n", __FUNCTION__, __LINE__);
+               for (ii = 0; ii < 16; ii += 2) {
+                       printf("%02X%02X ", dest_ipv6_addr[ii],
+                                                dest_ipv6_addr[ii + 1]);
+               }
+
+               printf("\n%s : LINE # %u", __FUNCTION__, __LINE__);
+               if ((ipv6_hdr->proto == IPPROTO_ICMPV6) &&
+                               (!memcmp
+                                (&ipv6_hdr->dst_addr, &configured_port_ipv6[0],
+                                       RTE_LPM_IPV6_ADDR_SIZE)
+                                || !memcmp(&dest_ipv6_addr[0],
+                               &solicited_node_multicast_addr[0],
+                               RTE_LPM_IPV6_ADDR_SIZE))) {
+                       ipv6_forward_pkts_mask &= ~pkt_mask;  /**< Its  ICMP, remove this packet from the ipv6_forward_pkts_mask*/
+                       stats.nb_rx_l3_icmp_pkt++;   /**< Increment stats for ICMP PKT */
+                       nb_icmpv6_pkt++;
+               } else{         // Forward the packet
+                       icmp_pkts_mask &= ~pkt_mask;   /**< Not ICMP, remove this packet from the icmp_pkts_mask*/
+                       stats.nb_rx_l3_pkt++;
+                       nb_l3_pkt++;     /**< Increment stats for L3 PKT */
+               }
+       }
+
+       if (icmp_pkts_mask) {
+               if (L3FWD_DEBUG)
+                       printf
+                                       ("\n RECEiVED LOCAL ICMP PKT at L3...\n PROCESSING ICMP LOCAL PKT...\n");
+               proto_type[IP_LOCAL]->func(m, nb_icmpv6_pkt, icmp_pkts_mask,
+                                                port);
+       }
+
+       if (ipv6_forward_pkts_mask) {
+               if (L3FWD_DEBUG)
+                       printf
+                                       ("\n RECEIVED L3 PKT, \n\n FORWARDING L3 PKT....\n");
+               proto_type[IP_REMOTE]->func(m, nb_l3_pkt,
+                                                       ipv6_forward_pkts_mask, port);
+       }
+}
+
+struct ipv6_fib_path *populate_ipv6_fib_path(uint8_t
+                                                        nh_ipv6[RTE_LPM_IPV6_ADDR_SIZE],
+                                                        uint8_t portid)
+{
+
+       struct fib_path_key_ipv6 path_key;
+       uint8_t i;
+       for (i = 0; i < 16; i++) {
+               path_key.nh_ipv6[i] = nh_ipv6[i];
+       }
+       path_key.out_port = portid;
+       path_key.filler1 = 0;
+       path_key.filler2 = 0;
+       path_key.filler3 = 0;
+
+       struct ipv6_fib_path *fib_data = NULL;
+       /* Populate fib_path if it is present in FIB_PATH cuckoo HAsh Table */
+       fib_data = retrieve_ipv6_fib_path_entry(path_key);
+
+       if (fib_data) {
+
+               printf(" Fib path entry exists for IPv6 destination = "
+                                        "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:"
+                                        "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x and out port :%u\n",
+                                        nh_ipv6[0], nh_ipv6[1], nh_ipv6[2], nh_ipv6[3],
+                                        nh_ipv6[4], nh_ipv6[5], nh_ipv6[6], nh_ipv6[7],
+                                        nh_ipv6[8], nh_ipv6[9], nh_ipv6[10], nh_ipv6[11],
+                                        nh_ipv6[12], nh_ipv6[13], nh_ipv6[14], nh_ipv6[15],
+                                        portid);
+
+               fib_data->refcount++;
+               return fib_data;        // Entry Exists. Return True (1)
+       } else {
+               printf("IPv6 fib_path entry Doesn't Exists.......\n");
+       }
+
+       /* populate L2 Adj */
+       fib_data = NULL;
+       struct l2_adj_ipv6_entry *l2_adj_ptr = NULL;
+       l2_adj_ptr = populate_ipv6_l2_adj(nh_ipv6, portid);
+
+       if (l2_adj_ptr) {
+
+               uint32_t size =
+                               RTE_CACHE_LINE_ROUNDUP(sizeof(struct ipv6_fib_path));
+               fib_data = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
+
+               for (i = 0; i < 16; i++) {
+                       fib_data->nh_ipv6[i] = nh_ipv6[i];
+               }
+               fib_data->out_port = portid;
+               //memcpy(fib_data->nh_ipv6, &nh_ipv6, RTE_LPM_IPV6_ADDR_SIZE);
+
+               fib_data->refcount++;
+               fib_data->l2_adj_ipv6_ptr = l2_adj_ptr;
+
+               /* Store the received MAC Address in L2 Adj HAsh Table */
+               rte_hash_add_key_data(fib_path_ipv6_hash_handle, &path_key,
+                                                       fib_data);
+               printf
+                               (" ND resolution success l2_adj_entry %p\n, ipv6_fib_path_addr %p",
+                                l2_adj_ptr, fib_data);
+               return fib_data;
+       } else {
+               printf
+                               ("ND resolution failed and unable to write fib path in fib_path cuckoo hash\n");
+       }
+       return NULL;
+
+}
+
+struct l2_adj_ipv6_entry *populate_ipv6_l2_adj(uint8_t
+                                                                nh_ipv6[RTE_LPM_IPV6_ADDR_SIZE],
+                                                                uint8_t portid)
+{
+
+       struct l2_adj_key_ipv6 l2_adj_key;
+       uint8_t i;
+       for (i = 0; i < 16; i++) {
+               l2_adj_key.nh_ipv6[i] = nh_ipv6[i];
+       }
+       l2_adj_key.out_port_id = portid;
+       l2_adj_key.filler1 = 0;
+       l2_adj_key.filler2 = 0;
+       l2_adj_key.filler3 = 0;
+
+       struct l2_adj_ipv6_entry *adj_data = NULL;
+       struct ether_addr eth_dst;
+       /* Populate L2 adj if the MAC Address is present in L2 Adj HAsh Table */
+       adj_data = retrieve_ipv6_l2_adj_entry(l2_adj_key);
+
+       if (adj_data) {
+
+               printf("ipv6_l2_adj_entry exists for Next Hop IPv6 = "
+                                        "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:"
+                                        "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x and out port :%u\n",
+                                        nh_ipv6[0], nh_ipv6[1], nh_ipv6[2], nh_ipv6[3],
+                                        nh_ipv6[4], nh_ipv6[5], nh_ipv6[6], nh_ipv6[7],
+                                        nh_ipv6[8], nh_ipv6[9], nh_ipv6[10], nh_ipv6[11],
+                                        nh_ipv6[12], nh_ipv6[13], nh_ipv6[14], nh_ipv6[15],
+                                        portid);
+
+               ether_addr_copy(&adj_data->eth_addr, &eth_dst);
+               adj_data->refcount++;
+               return adj_data;        // Entry Exists. Return True (1)
+       }
+
+       struct ether_addr eth_src;
+       uint16_t ether_type = 0x086DD;
+       l2_phy_interface_t *port;
+       port = ifm_get_port(portid);
+       if (port == NULL) {
+               printf("PORT %u IS DOWN.. Unable to process !\n", portid);
+               return NULL;
+       }
+
+       memcpy(&eth_src, &port->macaddr, sizeof(struct ether_addr));
+       uint32_t size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct l2_adj_entry));
+       adj_data = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
+       if (adj_data == NULL) {
+               printf("L2 Adjacency memory allocation failed !\n");
+               return NULL;
+       }
+
+       adj_data->out_port_id = portid;
+       //memcpy(adj_data->nh_ipv6, &nh_ipv6, RTE_LPM_IPV6_ADDR_SIZE);
+       for (i = 0; i < 16; i++) {
+               adj_data->nh_ipv6[i] = nh_ipv6[i];
+       }
+       adj_data->refcount++;
+       adj_data->phy_port = port;
+
+       rte_hash_add_key_data(l2_adj_ipv6_hash_handle, &l2_adj_key, adj_data);
+
+       /* Query ND to get L2 Adj */
+       if (get_dest_mac_for_nexthop_ipv6(nh_ipv6, portid, &eth_dst)) {
+               /* Store the received MAC Address in L2 Adj HAsh Table */
+               ether_addr_copy(&eth_dst, &adj_data->eth_addr);
+
+               /* Precompute the L2 string encapsulation */
+               memcpy(&adj_data->l2_string, &eth_dst,
+                                        sizeof(struct ether_addr));
+               memcpy(&adj_data->l2_string[6], &eth_src,
+                                        sizeof(struct ether_addr));
+               memcpy(&adj_data->l2_string[12], &ether_type, 2);
+
+               adj_data->flags = L2_ADJ_RESOLVED;
+               printf
+                               (" ND resolution successful and stored in ipv6_l2_adj_entry %p\n",
+                                adj_data);
+
+               return adj_data;
+       } else {
+               adj_data->flags = L2_ADJ_UNRESOLVED;
+               printf
+                               ("ND resolution failed and unable to write in ipv6_l2_adj_entry\n");
+       }
+       return NULL;
+}
+
+struct l2_adj_ipv6_entry *retrieve_ipv6_l2_adj_entry(struct l2_adj_key_ipv6
+                                                                l2_adj_key)
+{
+       struct l2_adj_ipv6_entry *ret_l2_adj_data = NULL;
+
+       int ret =
+                       rte_hash_lookup_data(l2_adj_ipv6_hash_handle, &l2_adj_key,
+                                (void **)&ret_l2_adj_data);
+       if (ret < 0) {
+               printf
+                               ("L2 Adj hash lookup failed ret %d, EINVAL %d, ENOENT %d\n",
+                                ret, EINVAL, ENOENT);
+       } else {
+               printf("L2 Adj hash lookup Successful..!!!\n");
+               return ret_l2_adj_data;
+       }
+       return NULL;
+}
+
+int get_dest_mac_for_nexthop_ipv6(uint8_t nh_ipv6[RTE_LPM_IPV6_ADDR_SIZE],
+                                       uint32_t out_phy_port,
+                                       struct ether_addr *hw_addr)
+{
+       struct nd_entry_data *nd_data = NULL;
+       struct nd_key_ipv6 tmp_nd_key;
+       uint8_t i;
+       for (i = 0; i < 16; i++) {
+               tmp_nd_key.ipv6[i] = nh_ipv6[i];
+       }
+       tmp_nd_key.port_id = out_phy_port;
+
+       nd_data = retrieve_nd_entry(tmp_nd_key);
+       if (nd_data == NULL) {
+               printf("ND entry is not found\n");
+               return 0;
+       }
+       ether_addr_copy(&nd_data->eth_addr, hw_addr);
+
+       return 1;
+}
+
+struct ipv6_fib_path *retrieve_ipv6_fib_path_entry(struct fib_path_key_ipv6
+                                                        path_key)
+{
+
+       struct ipv6_fib_path *ret_fib_path_data = NULL;
+       int ret =
+                       rte_hash_lookup_data(fib_path_ipv6_hash_handle, &path_key,
+                                (void **)&ret_fib_path_data);
+       if (ret < 0) {
+               printf
+                               ("FIB Path Adj hash lookup failed ret %d, EINVAL %d, ENOENT %d\n",
+                                ret, EINVAL, ENOENT);
+               return NULL;
+       } else {
+               return ret_fib_path_data;
+       }
+}
+
+void remove_ipv6_fib_l2_adj_entry(void *entry)
+{
+       struct ipv6_fib_info entry1;
+       memcpy(&entry1, entry, sizeof(struct ipv6_fib_info));
+
+       struct ipv6_fib_path *fib_path_addr = entry1.path[0];   //fib_info->path[0];
+       if (fib_path_addr->refcount > 1) {
+               printf("BEFORE fib_path entry is not Removed! nh_iPv6 = "
+                                        "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:"
+                                        "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x and out port :%u, refcount :%d\n",
+                                        fib_path_addr->nh_ipv6[0], fib_path_addr->nh_ipv6[1],
+                                        fib_path_addr->nh_ipv6[2], fib_path_addr->nh_ipv6[3],
+                                        fib_path_addr->nh_ipv6[4], fib_path_addr->nh_ipv6[5],
+                                        fib_path_addr->nh_ipv6[6], fib_path_addr->nh_ipv6[7],
+                                        fib_path_addr->nh_ipv6[8], fib_path_addr->nh_ipv6[9],
+                                        fib_path_addr->nh_ipv6[10], fib_path_addr->nh_ipv6[11],
+                                        fib_path_addr->nh_ipv6[12], fib_path_addr->nh_ipv6[13],
+                                        fib_path_addr->nh_ipv6[14], fib_path_addr->nh_ipv6[15],
+                                        fib_path_addr->out_port, fib_path_addr->refcount);
+               fib_path_addr->refcount--;      // Just decrement the refcount this entry is still referred
+               printf("AFTER fib_path entry is not Removed! nh_iPv6 = "
+                                        "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:"
+                                        "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x and out port :%u, refcount :%d\n",
+                                        fib_path_addr->nh_ipv6[0], fib_path_addr->nh_ipv6[1],
+                                        fib_path_addr->nh_ipv6[2], fib_path_addr->nh_ipv6[3],
+                                        fib_path_addr->nh_ipv6[4], fib_path_addr->nh_ipv6[5],
+                                        fib_path_addr->nh_ipv6[6], fib_path_addr->nh_ipv6[7],
+                                        fib_path_addr->nh_ipv6[8], fib_path_addr->nh_ipv6[9],
+                                        fib_path_addr->nh_ipv6[10], fib_path_addr->nh_ipv6[11],
+                                        fib_path_addr->nh_ipv6[12], fib_path_addr->nh_ipv6[13],
+                                        fib_path_addr->nh_ipv6[14], fib_path_addr->nh_ipv6[15],
+                                        fib_path_addr->out_port, fib_path_addr->refcount);
+       } else {                        // Refcount is 1 so delete both fib_path and l2_adj_entry
+
+               struct l2_adj_ipv6_entry *adj_addr = NULL;
+               adj_addr = fib_path_addr->l2_adj_ipv6_ptr;
+
+               if (adj_addr != NULL) { //l2_adj_entry is has some entry in hash table
+                       printf("%s: CHECK   %d\n\r", __FUNCTION__, __LINE__);
+                       struct l2_adj_key_ipv6 l2_adj_key;
+                       memcpy(&l2_adj_key.nh_ipv6, fib_path_addr->nh_ipv6,
+                                                RTE_LPM_IPV6_ADDR_SIZE);
+                       l2_adj_key.out_port_id =
+                                       fib_path_addr->out_port,
+                                       rte_hash_del_key(l2_adj_ipv6_hash_handle,
+                                                        &l2_adj_key);
+                       rte_free(adj_addr);     // free memory
+                       adj_addr = NULL;
+               }
+
+               struct fib_path_key_ipv6 path_key;
+               memcpy(&path_key.nh_ipv6, fib_path_addr->nh_ipv6,
+                                        RTE_LPM_IPV6_ADDR_SIZE);
+               path_key.out_port = fib_path_addr->out_port;
+               rte_hash_del_key(fib_path_ipv6_hash_handle, &path_key);
+               rte_free(fib_path_addr);        //Free the memory
+               fib_path_addr = NULL;
+       }
+}
+
+int is_valid_ipv6_pkt(struct ipv6_hdr *pkt, uint32_t link_len)
+{
+       if (link_len < sizeof(struct ipv4_hdr))
+               return -1;
+       if (rte_cpu_to_be_16(pkt->payload_len) < sizeof(struct ipv6_hdr))
+               return -1;
+
+       return 0;
+}
+
+void
+ipv6_l3_protocol_type_add(uint8_t protocol_type,
+                               void (*func) (struct rte_mbuf **, uint16_t, uint64_t,
+                                       l2_phy_interface_t *))
+{
+       switch (protocol_type) {
+       case IPPROTO_ICMPV6:
+               proto_type[IP_LOCAL] =
+                               rte_malloc(NULL, sizeof(struct ip_protocol_type),
+                                                RTE_CACHE_LINE_SIZE);
+               proto_type[IP_LOCAL]->protocol_type = protocol_type;
+               proto_type[IP_LOCAL]->func = func;
+               break;
+
+       case IPPROTO_TCP:       // Time being treared as Remote forwarding
+       case IPPROTO_UDP:
+               proto_type[IP_REMOTE] =
+                               rte_malloc(NULL, sizeof(struct ip_protocol_type),
+                                                RTE_CACHE_LINE_SIZE);
+               proto_type[IP_REMOTE]->protocol_type = protocol_type;
+               proto_type[IP_REMOTE]->func = func;
+               break;
+       }
+}
+
+void
+ipv6_local_deliver(struct rte_mbuf **pkt_burst, __rte_unused uint16_t nb_rx,
+                        uint64_t icmp_pkt_mask, l2_phy_interface_t *port)
+{
+       for (; icmp_pkt_mask;) {
+/**< process only valid packets.*/
+               uint8_t pos = (uint8_t) __builtin_ctzll(icmp_pkt_mask);
+               uint64_t pkt_mask = 1LLU << pos;   /**< bitmask representing only this packet */
+               icmp_pkt_mask &= ~pkt_mask;     /**< remove this packet from the mask */
+
+               process_icmpv6_pkt(pkt_burst[pos], port);
+       }
+}
+
+void
+ipv6_forward_deliver(struct rte_mbuf **pkt_burst, uint16_t nb_pkts,
+                                uint64_t ipv6_forward_pkts_mask, l2_phy_interface_t *port)
+{
+       if (L3FWD_DEBUG) {
+               printf
+                               ("ip_forward_deliver BEFORE DROP: nb_pkts: %u\n from in_port %u",
+                                nb_pkts, port->pmdid);
+       }
+       uint64_t pkts_for_process = ipv6_forward_pkts_mask;
+
+       struct ipv6_hdr *ipv6_hdr;
+       l2_phy_interface_t *port_ptr[RTE_PORT_IN_BURST_SIZE_MAX];
+       uint64_t hit_mask = 0;
+
+       for (; pkts_for_process;) {
+/**< process only valid packets.*/
+               uint8_t pos = (uint8_t) __builtin_ctzll(pkts_for_process);
+               uint64_t pkt_mask = 1LLU << pos;   /**< bitmask representing only this packet */
+               pkts_for_process &= ~pkt_mask;           /**< remove this packet from the mask */
+               ipv6_hdr =
+                               rte_pktmbuf_mtod_offset(pkt_burst[pos], struct ipv6_hdr *,
+                                                       sizeof(struct ether_hdr));
+               /* Make sure the IPv4 packet is valid  */
+
+               if (is_valid_ipv6_pkt(ipv6_hdr, pkt_burst[pos]->pkt_len) < 0) {
+                       rte_pktmbuf_free(pkt_burst[pos]);   /**< Drop the Unknown IPv4 Packet */
+                       pkt_burst[pos] = NULL;
+                       ipv6_forward_pkts_mask &= ~(1LLU << pos);  /**< That will clear bit of that position*/
+                       nb_pkts--;
+                       stats.nb_l3_drop_pkt++;
+               }
+       }
+
+       if (L3FWD_DEBUG) {
+               printf
+                               ("\nl3fwd_rx_ipv4_packets_received AFTER DROP: nb_pkts: %u, valid_Pkts_mask :%lu\n",
+                                nb_pkts, ipv6_forward_pkts_mask);
+       }
+
+       /* Lookup for IP destination in LPMv4 table */
+       lpm6_table_lookup(pkt_burst, nb_pkts, ipv6_forward_pkts_mask, port_ptr,
+                               &hit_mask);
+}
+
+uint8_t ipv6_hash_load_balance(struct rte_mbuf *mbuf)
+{
+       uint32_t src_addr_offset =
+                       MBUF_HDR_ROOM + ETH_HDR_SIZE + IP_HDR_SRC_ADR_OFST_IPV6;
+       uint32_t dst_addr_offset =
+                       MBUF_HDR_ROOM + ETH_HDR_SIZE + IP_HDR_DST_ADR_OFST_IPV6;
+       uint8_t src_addr[RTE_LPM_IPV6_ADDR_SIZE];
+       uint8_t dst_addr[RTE_LPM_IPV6_ADDR_SIZE];
+
+       memcpy(&src_addr,
+                                (uint8_t *) RTE_MBUF_METADATA_UINT32_PTR(mbuf, src_addr_offset),
+                                RTE_LPM_IPV6_ADDR_SIZE);
+       memcpy(&dst_addr,
+                                (uint8_t *) RTE_MBUF_METADATA_UINT32_PTR(mbuf, dst_addr_offset),
+                                RTE_LPM_IPV6_ADDR_SIZE);
+       uint32_t hash_key1 = 0; /* STORE Accumulated value of SRC IP in key1 variable */
+       uint32_t hash_key2 = 0; /* STORE Accumulated value of DST IP in key2 variable */
+       uint8_t i;
+       for (i = 0; i < RTE_LPM_IPV6_ADDR_SIZE; i++) {
+               hash_key1 += src_addr[i];       /* Accumulate */
+               hash_key2 += dst_addr[i];       /* Accumulate */
+       }
+       hash_key1 = hash_key1 ^ hash_key2;      /* XOR With SRC and DST IP, Result is hask_key1 */
+       hash_key2 = hash_key1;  /* MOVE The result to hask_key2 */
+       hash_key1 = rotr32(hash_key1, RTE_LPM_IPV6_ADDR_SIZE);  /* Circular Rotate to 16 bit */
+       hash_key1 = hash_key1 ^ hash_key2;      /* XOR With Key1 with Key2 */
+
+       hash_key2 = hash_key1;  /* MOVE The result to hask_key2 */
+
+       hash_key1 = rotr32(hash_key1, 8);       /* Circular Rotate to 8 bit */
+       hash_key1 = hash_key1 ^ hash_key2;      /* XOR With Key1 with Key2 */
+
+       hash_key1 = hash_key1 & (HASH_BUCKET_SIZE - 1); /* MASK the KEY with BUCKET SIZE */
+       if (L3FWD_DEBUG)
+               printf("Hash Result_key: %d, \n", hash_key1);
+       return hash_key1;
+}
+
+void
+resolve_ipv6_l2_adj(uint8_t nh_ipv6[RTE_LPM_IPV6_ADDR_SIZE], uint8_t portid,
+                               struct ether_addr *hw_addr)
+{
+       struct l2_adj_ipv6_entry *adj_data = NULL;
+       struct ether_addr eth_dst;
+       uint16_t ether_type = 0x086DD;
+
+       struct l2_adj_key_ipv6 l2_adj_key;
+       memcpy(&l2_adj_key.nh_ipv6, &nh_ipv6, RTE_LPM_IPV6_ADDR_SIZE);
+       l2_adj_key.out_port_id = portid;
+
+       adj_data = retrieve_ipv6_l2_adj_entry(l2_adj_key);
+       if (adj_data) {
+               if (adj_data->flags == L2_ADJ_UNRESOLVED
+                               || memcmp(&adj_data->eth_addr, hw_addr, 6)) {
+                       ether_addr_copy(hw_addr, &adj_data->eth_addr);
+
+                       /* Precompute the L2 string encapsulation */
+                       memcpy(&adj_data->l2_string, hw_addr,
+                                                sizeof(struct ether_addr));
+                       memcpy(&adj_data->l2_string[6],
+                                                &adj_data->phy_port->macaddr,
+                                                sizeof(struct ether_addr));
+                       memcpy(&adj_data->l2_string[12], &ether_type, 2);
+
+                       adj_data->flags = L2_ADJ_RESOLVED;
+               }
+
+               return;
+       }
+
+       l2_phy_interface_t *port;
+       port = ifm_get_port(portid);
+       if (port == NULL) {
+               printf("PORT %u IS DOWN..! Unable to Process\n", portid);
+               return;
+       }
+       uint32_t size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct l2_adj_entry));
+       adj_data = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
+       if (adj_data == NULL) {
+               printf("L2 Adjacency memory allocation failed !\n");
+               return;
+       }
+
+       adj_data->out_port_id = portid;
+       memcpy(adj_data->nh_ipv6, &nh_ipv6, RTE_LPM_IPV6_ADDR_SIZE);
+
+       adj_data->phy_port = port;
+
+       ether_addr_copy(&eth_dst, &adj_data->eth_addr);
+
+       /* Precompute the L2 string encapsulation */
+       memcpy(&adj_data->l2_string, hw_addr, sizeof(struct ether_addr));
+       memcpy(&adj_data->l2_string[6], &port->macaddr,
+                                sizeof(struct ether_addr));
+       memcpy(&adj_data->l2_string[12], &ether_type, 2);
+
+       adj_data->flags = L2_ADJ_RESOLVED;
+
+       /* Store the received MAC Address in L2 Adj HAsh Table */
+       rte_hash_add_key_data(l2_adj_ipv6_hash_handle, &l2_adj_key, adj_data);
+
+       printf(" ND resolution successful and stored in ipv6_l2_adj_entry %p\n",
+                                adj_data);
+}
+
+void ipv6_iterate__hash_table(void)
+{
+       const void *next_key;
+       void *next_data;
+       uint32_t iter = 0;
+       uint8_t ii;
+       printf("\n\t\t\t IPv6 FIB_path Cache table....");
+       printf
+                       ("\n------------------------------------------------------------------------------");
+       printf
+                       ("\n\tNextHop IP \t\t\t\t Port   Refcount   l2_adj_ptr_addrress\n\n");
+       printf
+                       ("--------------------------------------------------------------------------------\n");
+
+       while (rte_hash_iterate
+                                (fib_path_ipv6_hash_handle, &next_key, &next_data, &iter) >= 0) {
+               struct ipv6_fib_path *tmp_data =
+                               (struct ipv6_fib_path *)next_data;
+               struct fib_path_key_ipv6 tmp_key;
+               memcpy(&tmp_key, next_key, sizeof(tmp_key));
+               for (ii = 0; ii < 16; ii += 2) {
+                       printf("%02X%02X ", tmp_data->nh_ipv6[ii],
+                                                tmp_data->nh_ipv6[ii + 1]);
+               }
+               printf(" \t %u \t %u \t %p\n", tmp_data->out_port,
+                                        tmp_data->refcount, tmp_data->l2_adj_ipv6_ptr);
+
+       }
+
+       iter = 0;
+
+       printf("\n\t\t\t L2 ADJ Cache table.....");
+       printf
+                       ("\n----------------------------------------------------------------------------------\n");
+       printf
+                       ("\tNextHop IP  \t\t\t\t Port \t  l2 Encap string \t l2_Phy_interface\n");
+       printf
+                       ("\n------------------------------------------------------------------------------------\n");
+       while (rte_hash_iterate
+                                (l2_adj_ipv6_hash_handle, &next_key, &next_data, &iter) >= 0) {
+               struct l2_adj_ipv6_entry *l2_data =
+                               (struct l2_adj_ipv6_entry *)next_data;
+               struct l2_adj_key_ipv6 l2_key;
+               memcpy(&l2_key, next_key, sizeof(l2_key));
+               for (ii = 0; ii < 16; ii += 2) {
+                       printf("%02X%02X ", l2_data->nh_ipv6[ii],
+                                                l2_data->nh_ipv6[ii + 1]);
+               }
+               printf(" \t%u\t%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x\t%p\n",
+                                        l2_data->out_port_id,
+                                        l2_data->l2_string[0],
+                                        l2_data->l2_string[1],
+                                        l2_data->l2_string[2],
+                                        l2_data->l2_string[3],
+                                        l2_data->l2_string[4],
+                                        l2_data->l2_string[5],
+                                        l2_data->l2_string[6],
+                                        l2_data->l2_string[7],
+                                        l2_data->l2_string[8],
+                                        l2_data->l2_string[9],
+                                        l2_data->l2_string[10],
+                                        l2_data->l2_string[11], l2_data->phy_port);
+       }
+}
diff --git a/common/VIL/l2l3_stack/l3fwd_lpm6.h b/common/VIL/l2l3_stack/l3fwd_lpm6.h
new file mode 100644 (file)
index 0000000..fdd8287
--- /dev/null
@@ -0,0 +1,315 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+/**
+* @file
+* L3fwd lpm6 header file is for IPv6 specific declarations
+*/
+
+#ifndef L3FWD_LPM6_H
+#define L3FWD_LPM6_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <string.h>
+#include <sys/queue.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <getopt.h>
+#include <stdbool.h>
+
+#include <rte_debug.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_ring.h>
+#include <rte_mempool.h>
+#include <rte_cycles.h>
+#include <rte_mbuf.h>
+#include <rte_ip.h>
+#include <rte_tcp.h>
+#include <rte_udp.h>
+#include <rte_lpm.h>
+#include <rte_lpm6.h>
+#include <rte_table_lpm_ipv6.h>
+#include "l3fwd_common.h"
+#include "l3fwd_lpm4.h"
+#include "interface.h"
+
+/**
+* Define all RTE MBUF offset size
+*/
+
+#define MBUF_HDR_ROOM 256                      /**< MBUF HEADER ROOM OFFSET */
+/* IPv6 */
+#define IP_HDR_SIZE_IPV6  40                   /**< IPv6 HEADER OFFSET */
+#define IP_HDR_SRC_ADR_OFST_IPV6 8  /**< IPv6 HEADER SRC IP ADDRESS OFFSET */
+#define IP_HDR_DST_ADR_OFST_IPV6 24 /**< IPv6 HEADER DST IP ADDRESS OFFSET */
+
+/* IPV6 Rules and Tables8s */
+#define IPV6_L3FWD_LPM_MAX_RULES         1024  /**< Number of LPM6 Rules*/
+#define IPV6_L3FWD_LPM_NUMBER_TBL8S (1 << 16)  /**< Number of Table 8 for LPM6 */
+
+#define MAX_FIB_PATHS 8        /**< MAX FIB PATH, If ECMP feature is enabled */
+
+/**
+* A structure used to define the routing information for IPv6
+* This structure is used as input parameters for route ADD
+*/
+struct ipv6_routing_info {
+       uint8_t dst_ipv6[RTE_LPM_IPV6_ADDR_SIZE];  /**< DST IPv6 Address */
+       uint8_t depth;                                   /**< Depth */
+       uint32_t metric;                                 /**< Metrics */
+       uint32_t fib_nh_size; /**< num of fib paths, greater than if Multipath(ECMP) feature is supported*/
+       uint8_t nh_ipv6[MAX_FIB_PATHS][RTE_LPM_IPV6_ADDR_SIZE];         /**< NextHop IP Address */
+       uint8_t out_port[MAX_FIB_PATHS];                                /**< OUTGOING PORT */
+} __rte_cache_aligned;                                  /**< RTE CACHE ALIGNED */
+
+/**
+* A structure used to define the fib path for Destination IPv6 Address
+* This fib path is shared accross different fib_info.
+*/
+struct ipv6_fib_path {
+       uint8_t nh_ipv6[RTE_LPM_IPV6_ADDR_SIZE];  /**< Next hop IP address (only valid for remote routes) */
+       uint32_t refcount;                              /**< Refcount, greater then 1 if multiple fib_info has same fib_path*/
+       uint8_t out_port;                               /**< Output port */
+       struct l2_adj_ipv6_entry *l2_adj_ipv6_ptr;/**< Address of the L2 ADJ table entry */
+} __rte_cache_aligned;                                 /**< RTE CACHE ALIGNED */
+
+/**
+* A structure used to define the fib info (Route info)
+* This fib info structure can have multiple fib paths.
+*/
+struct ipv6_fib_info {
+       uint8_t dst_ipv6[RTE_LPM_IPV6_ADDR_SIZE]; /**< DST IPv6 Address */
+       uint8_t depth;                                  /**< Depth */
+       uint32_t metric;                                /**< Metric */
+       uint32_t fib_nh_size;                   /**< num of fib paths, greater than if Multipath(ECMP) feature is supported*/
+       struct ipv6_fib_path *path[MAX_FIB_PATHS]; /**< Array of pointers to the fib_path */
+} __rte_cache_aligned;                                 /**< RTE CACHE ALIGNED */
+
+/**
+* A structure used to define the L2 Adjacency table
+*/
+struct l2_adj_ipv6_entry {
+       struct ether_addr eth_addr;              /**< Ether address */
+       uint8_t out_port_id;                     /**< Outgoing port */
+       uint8_t nh_ipv6[RTE_LPM_IPV6_ADDR_SIZE]; /**< Next hop IP address (only valid for remote routes) */
+       uint32_t refcount;                      /**< Refcount, greater then 1 if multiple fib_path has same L2_adj_entry*/
+       uint8_t l2_string[256];                  /**< L2 string, to rewrite the packet before transmission */
+       l2_phy_interface_t *phy_port;  /**<  Address of the L2 physical interface structure */
+       uint8_t flags;                  /**< flags for marking this entry as resolved or unresolved. */
+} __rte_cache_aligned;                                         /**< RTE CACHE ALIGNED */
+
+/**
+* A structure used to define the L2 Adjacency table
+*/
+struct l2_adj_key_ipv6 {
+       /*128 Bit of IPv6 Address */
+       /*<48bit Network> <16bit Subnet> <64bit Interface> */
+       uint8_t nh_ipv6[RTE_LPM_IPV6_ADDR_SIZE]; /**< Next hop IPv6 address */
+       uint8_t out_port_id;                     /**< Outgoing port */
+       uint8_t filler1;    /**< Filler 1, for better hash key */
+       uint8_t filler2;    /**< Filler2, for better hash key*/
+       uint8_t filler3;    /**< Filler3, for better hash Key */
+};
+
+/**
+* A structure used to define the fib path key for hash table
+*/
+struct fib_path_key_ipv6 {
+       /*128 Bit of IPv6 Address */
+       /*<48bit Network> <16bit Subnet> <64bit Interface> */
+       uint8_t nh_ipv6[RTE_LPM_IPV6_ADDR_SIZE];  /**< Next hop IPv6 address */
+       uint8_t out_port;                               /**< Outgoing port */
+       uint8_t filler1;    /**< Filler 1, for better hash key */
+       uint8_t filler2;    /**< Filler2, for better hash key*/
+       uint8_t filler3;    /**< Filler3, for better hash Key */
+};
+
+struct ipv6_protocol_type {
+       uint8_t protocol_type;          /**< Protocol Type */
+       void (*func) (struct rte_mbuf **, uint16_t, uint64_t,
+                                       l2_phy_interface_t *);
+} __rte_cache_aligned;
+
+/* Function Declarations */
+/**
+ * To creare LPM6 table, Cuckoo hash table for fib_path and l2_adj_entry tables
+ * @return
+ * 0 for failure, 1 for success
+ */
+int lpm6_init(void);
+
+/**
+ * To add a route in LPM6 table by populating fib_path and L2 Adjacency.
+ * @param data
+ * To add the route based on ipv6_routing_info stucture.
+ * @return
+ * 0 for failure, 1 for success
+ */
+int lpm6_table_route_add(struct ipv6_routing_info *data);
+
+/**
+ * To Delete the IP route and corresponding fib_path and L2 Adjacency entries.
+ * @param dst_ipv6
+ * Destionation IPv6 for which the route need to deleted
+ * @param depth
+ * netmask for the Destination IP
+ * @return
+ * 0 for failure, 1 for success
+ */
+int lpm6_table_route_delete(uint8_t dst_ipv6[RTE_LPM_IPV6_ADDR_SIZE],
+                                       uint8_t depth);
+
+/**
+ * To perform a LPM6 table lookup
+ * @param pkts_burst
+ * Burst of packets that needs to be lookup in LPM6 table
+ * @param nb_pkts
+ * Number of valid L3 packets
+ * @param pkts_mask
+ * number of valid pkts mask that needs to be lookup in LPM6 table
+ * @return
+ * 0 for failure, 1 for success
+ */
+int lpm6_table_lookup(struct rte_mbuf **pkts_burst, uint16_t nb_pkts,
+                                       uint64_t pkts_mask,
+                                       l2_phy_interface_t *port_ptr[RTE_PORT_IN_BURST_SIZE_MAX],
+                                       uint64_t *hit_mask);
+
+/**
+ * To forward the valid L3 packets for LMP6 table lookup and forward ICMP Pkts to ICMP module
+ * @param m
+ * packet burst of type rte_mbuf
+ * @param nb_pkts
+ * Number of valid L3 packets
+ * @param valid_pkts_mask
+ * Valid IPv6 packets mask that needs to be processed
+ * @param in_port
+ * IPv6 Pkt received form the input port.
+ * @return
+ * None
+ */
+void l3fwd_rx_ipv6_packets(struct rte_mbuf **m, uint16_t nb_pkts,
+                                uint64_t valid_pkts_mask,
+                                l2_phy_interface_t *in_port);
+
+/**
+ * To populate the fib_path for the nexthop IPv6 and outgoing port
+ * @param nh_ipv6
+ * NextHop Ip Address for which L2_adj_entry needs to be populated
+ * @param out_port
+ * outgong port ID
+ * @return
+ * NULL if lookup fails, Address of the type ipv6_fib_path if lookup success
+*/
+struct ipv6_fib_path *populate_ipv6_fib_path(uint8_t
+                                                        nh_ipv6[RTE_LPM_IPV6_ADDR_SIZE],
+                                                        uint8_t out_port);
+
+/**
+ * To retrieve the fib_path entry for the nexthop IP and outgoing port
+ * This queries with cuckoo hash table based on the fib_path_key_ipv4
+ * @param path_key
+ * Key which is required for Cuckook hash table lookup
+ * @return
+ * NULL if lookup fails, Address of type ipv6_fib_path if lookup success
+*/
+struct ipv6_fib_path *retrieve_ipv6_fib_path_entry(struct fib_path_key_ipv6
+                                                        path_key);
+
+/**
+ * To retrieve the l2_adj_entry for the nexthop IP and outgoing port
+ * This queries with cuckoo hash table based on the l2_adj_key_ipv6
+ * @param l2_adj_key
+ * Key which is required for Cuckook hash table lookup
+ * @return
+ * NULL if lookup fails, Address of type l2_adj_ipv6_entry if lookup success
+*/
+struct l2_adj_ipv6_entry *retrieve_ipv6_l2_adj_entry(struct l2_adj_key_ipv6
+                                                                l2_adj_key);
+
+/**
+ * To populate the l2_adj_entry for the nexthop IP and outgoing port
+ * @param nh_ip
+ * NextHop Ip Address for which L2_adj_entry needs to be populated
+ * @param portid
+ * outgong port ID
+ * @return
+ * NULL if lookup fails, Address of the L2_adj_ipv6_entry if lookup success
+*/
+struct l2_adj_ipv6_entry *populate_ipv6_l2_adj(uint8_t
+                                                                nh_ip[RTE_LPM_IPV6_ADDR_SIZE],
+                                                                uint8_t portid);
+
+/**
+ * To get the destination MAC Address for the nexthop IP and outgoing port
+ * @param nh_ipv6
+ * Next HOP IP Address for which MAC address is needed
+ * @param out_phy_port
+ * Outgoing physical port
+ * @param hw_addr
+ * pointet to the ether_add, This gets update with valid MAC address based on nh_ip and out port
+ * @return
+ * 0 if failure, 1 if success
+ */
+int get_dest_mac_for_nexthop_ipv6(uint8_t nh_ipv6[RTE_LPM_IPV6_ADDR_SIZE],
+                                       uint32_t out_phy_port,
+                                       struct ether_addr *hw_addr);
+
+/**
+ * To delete the ipv6 fib path and l2 adjacency entry from the cuckoo hash table
+ * @return
+ * None
+*/
+void remove_ipv6_fib_l2_adj_entry(void *entry);
+
+void
+ipv6_l3_protocol_type_add(uint8_t protocol_type,
+                               void (*func) (struct rte_mbuf **, uint16_t, uint64_t,
+                                       l2_phy_interface_t *));
+
+void
+ipv6_local_deliver(struct rte_mbuf **, uint16_t, uint64_t,
+                        l2_phy_interface_t *);
+
+void
+ipv6_forward_deliver(struct rte_mbuf **, uint16_t, uint64_t,
+                                l2_phy_interface_t *);
+
+int is_valid_ipv6_pkt(struct ipv6_hdr *pkt, uint32_t link_len);
+uint8_t ipv6_hash_load_balance(struct rte_mbuf *mbuf);
+
+/**
+ * To resolve l2_adj_entry based on nexthop IP, outgoing port and ether hw address.
+ * @param nh_ip
+ * NextHop Ip Address for which L2_adj_entry needs to be resolved
+ * @param portid
+ * outgong port ID
+ * @hw_addr
+ * Ethernet hardware address for the above nexthop IP and out port ID.
+ * @return
+ * Return is void.
+*/
+
+void resolve_ipv6_l2_adj(uint8_t nh_ip[RTE_LPM_IPV6_ADDR_SIZE], uint8_t portid,
+                        struct ether_addr *hw_addr);
+
+void ipv6_iterate__hash_table(void);
+#endif                         /* L3FWD_LPM_H */
diff --git a/common/VIL/l2l3_stack/l3fwd_main.c b/common/VIL/l2l3_stack/l3fwd_main.c
new file mode 100644 (file)
index 0000000..247d887
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+/****************************************************************************
+*
+* filename : :l3fwd_main.c
+*
+*
+******************************************************************************/
+
+#include "l3fwd_common.h"
+#include "l2_proto.h"
+#include "l3fwd_lpm4.h"
+#include "l3fwd_lpm6.h"
+#include "interface.h"
+#include "lib_arp.h"
+#include "lib_icmpv6.h"
+
+struct routing_info input_array[] = {
+#if MULTIPATH_FEAT
+       {IPv4(30, 12, 0, 1), 24, 0, 4,
+        {IPv4(192, 168, 0, 2), IPv4(1, 1, 1, 7), IPv4(120, 0, 0, 2),
+               IPv4(30, 40, 50, 60)}, {1, 1, 1, 1} },
+
+       {IPv4(40, 12, 0, 1), 24, 0, 4,
+        {IPv4(192, 168, 0, 2), IPv4(1, 1, 1, 7), IPv4(120, 0, 0, 2),
+               IPv4(30, 40, 50, 60)}, {1, 1, 1, 1} },
+
+       {IPv4(50, 12, 0, 1), 24, 0, 4,
+        {IPv4(192, 168, 0, 2), IPv4(1, 1, 1, 7), IPv4(120, 0, 0, 2),
+               IPv4(30, 40, 50, 60)}, {1, 1, 1, 1} },
+
+       {IPv4(60, 12, 0, 1), 24, 0, 4,
+        {IPv4(192, 168, 0, 2), IPv4(1, 1, 1, 7), IPv4(120, 0, 0, 2),
+               IPv4(30, 40, 50, 60)}, {1, 1, 1, 1} },
+
+       {IPv4(100, 100, 100, 100), 24, 0, 2,
+        {IPv4(120, 0, 0, 2), IPv4(120, 0, 0, 2)}, {1, 1} },    // FIb Path Available
+
+       {IPv4(200, 100, 100, 100), 24, 0, 2,
+        {IPv4(80, 0, 0, 2), IPv4(80, 40, 50, 60)}, {1, 1} },   // Fib path Not Available
+#else
+       {IPv4(30, 12, 0, 1), 24, 0, 1,
+        {IPv4(192, 168, 0, 2)}, {1} },
+
+       {IPv4(20, 12, 0, 1), 24, 0, 1,
+        {IPv4(120, 0, 0, 2)}, {1} },
+#endif
+};
+
+struct ipv6_routing_info ipv6_input_array[] = {
+
+       {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 48, 0, 2,
+        {{10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10},
+               {20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20}
+               },
+        {1, 1}
+        },
+
+       {{2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}, 48, 0, 2,
+        {{10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10},
+               {20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20}
+               },
+        {1, 1}
+        },
+};
+
+void l3fwd_init(void)
+{
+       printf(" *********** L3  Initialization START ************\n");
+       if (lpm_init() == 0) {
+               rte_exit(EXIT_FAILURE, "L3 Initialization IPv4 Failed\n");
+       }
+       if (lpm6_init() == 0) {
+               rte_exit(EXIT_FAILURE, "L3 Initialization for IPV6 Failed\n");
+       }
+
+       list_add_type(ETHER_TYPE_IPv4, l3fwd_rx_ipv4_packets);
+       list_add_type(ETHER_TYPE_IPv6, l3fwd_rx_ipv6_packets);
+
+       l3_protocol_type_add(IPPROTO_ICMP, ip_local_packets_process);
+       l3_protocol_type_add(IPPROTO_TCP, ip_forward_deliver);
+       l3_protocol_type_add(IPPROTO_UDP, ip_forward_deliver);
+
+       ipv6_l3_protocol_type_add(IPPROTO_ICMPV6, ipv6_local_deliver);
+       ipv6_l3_protocol_type_add(IPPROTO_TCP, ipv6_forward_deliver);
+       ipv6_l3_protocol_type_add(IPPROTO_UDP, ipv6_forward_deliver);
+
+}
+
+void populate_lpm_routes(void)
+{
+       populate_lpm4_table_routes();
+       //populate_lpm6_table_routes();
+}
+
+void populate_lpm4_table_routes(void)
+{
+       uint8_t i;
+       printf
+                       (" *********** L3 IPV4 Route Initialization START ************\n");
+       for (i = 0; i < MAX_ROUTES; i++) {
+               if (lpm4_table_route_add(&input_array[i])) {
+
+                       printf("Total routes Added# %d\n", i + 1);
+               } else {
+                       rte_exit(EXIT_FAILURE,
+                                "L3 route addition failed for the route# %d\n",
+                                i);
+               }
+       }
+       printf
+                       (" *********** L3 IPV4 Route Initialization END ************\n\n");
+}
+
+void populate_lpm6_table_routes(void)
+{
+       uint8_t i;
+       printf
+                       (" *********** L3 IPV6 Route Initialization START ************\n");
+       for (i = 0; i < 2; i++) {
+               if (lpm6_table_route_add(&ipv6_input_array[i])) {
+
+                       printf("Added route # %d\n", i);
+               } else {
+                       rte_exit(EXIT_FAILURE,
+                                "L3 route addition failed for the route# %d\n",
+                                i);
+               }
+       }
+       printf(" *********** L3 IPV6 Route Initialization END ************\n");
+}
diff --git a/common/VIL/l2l3_stack/lib_arp.c b/common/VIL/l2l3_stack/lib_arp.c
new file mode 100644 (file)
index 0000000..042dd39
--- /dev/null
@@ -0,0 +1,2655 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <execinfo.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <rte_common.h>
+#include <rte_malloc.h>
+#include <rte_ip.h>
+#include <rte_byteorder.h>
+#include <rte_log.h>
+#include <rte_table_lpm.h>
+#include <rte_table_hash.h>
+#include <rte_pipeline.h>
+#include <rte_arp.h>
+#include <rte_icmp.h>
+#include <rte_hash.h>
+#include <rte_jhash.h>
+#include <rte_cycles.h>
+#include <rte_timer.h>
+#include "interface.h"
+#include "l2_proto.h"
+#include "lib_arp.h"
+#include "l3fwd_lpm4.h"
+#include "vnf_common.h"
+
+#if (RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN)
+#define CHECK_ENDIAN_16(x) rte_be_to_cpu_16(x)
+#define CHECK_ENDIAN_32(x) rte_be_to_cpu_32(x)
+#else
+#define CHECK_ENDIAN_16(x) (x)
+#define CHECK_ENDIAN_32(x) (x)
+#endif
+
+#define NB_ARPICMP_MBUF  64
+#define NB_NDICMP_MBUF  64
+#define IP_VERSION_4 0x40
+#define IP_HDRLEN  0x05                /**< default IP header length == five 32-bits words. */
+#define IP_VHL_DEF (IP_VERSION_4 | IP_HDRLEN)
+
+#define is_multicast_ipv4_addr(ipv4_addr) \
+       (((rte_be_to_cpu_32((ipv4_addr)) >> 24) & 0x000000FF) == 0xE0)
+
+extern uint8_t prv_in_port_a[16];
+extern uint32_t timer_lcore;
+uint32_t arp_timeout = ARP_TIMER_EXPIRY;
+
+/*ND IPV6 */
+#define INADDRSZ 4
+#define IN6ADDRSZ 16
+static int my_inet_pton_ipv6(int af, const char *src, void *dst);
+static int inet_pton_ipv6(const char *src, unsigned char *dst);
+static int inet_pton_ipv4(const char *src, unsigned char *dst);
+extern void convert_prefixlen_to_netmask_ipv6(uint32_t depth,
+                                                               uint8_t netmask_ipv6[]);
+
+uint8_t vnf_common_arp_lib_init;
+uint8_t vnf_common_nd_lib_init;
+uint8_t loadb_pipeline_count;
+
+uint32_t ARPICMP_DEBUG;
+uint32_t NDIPV6_DEBUG;
+
+uint32_t arp_route_tbl_index;
+uint32_t nd_route_tbl_index;
+uint32_t link_hw_addr_array_idx;
+
+uint32_t lib_arp_get_mac_req;
+uint32_t lib_arp_nh_found;
+uint32_t lib_arp_no_nh_found;
+uint32_t lib_arp_arp_entry_found;
+uint32_t lib_arp_no_arp_entry_found;
+uint32_t lib_arp_populate_called;
+uint32_t lib_arp_delete_called;
+uint32_t lib_arp_duplicate_found;
+
+uint32_t lib_nd_get_mac_req;
+uint32_t lib_nd_nh_found;
+uint32_t lib_nd_no_nh_found;
+uint32_t lib_nd_nd_entry_found;
+uint32_t lib_nd_no_arp_entry_found;
+uint32_t lib_nd_populate_called;
+uint32_t lib_nd_delete_called;
+uint32_t lib_nd_duplicate_found;
+struct rte_mempool *lib_arp_pktmbuf_tx_pool;
+struct rte_mempool *lib_nd_pktmbuf_tx_pool;
+
+struct rte_mbuf *lib_arp_pkt;
+struct rte_mbuf *lib_nd_pkt;
+
+uint8_t default_ether_addr[6] = { 0, 0, 0, 0, 1, 1 };
+uint8_t default_ip[4] = { 0, 0, 1, 1 };
+
+static struct rte_hash_parameters arp_hash_params = {
+       .name = "ARP",
+       .entries = 64,
+       .reserved = 0,
+       .key_len = sizeof(struct arp_key_ipv4),
+       .hash_func = rte_jhash,
+       .hash_func_init_val = 0,
+};
+
+static struct rte_hash_parameters nd_hash_params = {
+       .name = "ND",
+       .entries = 64,
+       .reserved = 0,
+       .key_len = sizeof(struct nd_key_ipv6),
+       .hash_func = rte_jhash,
+       .hash_func_init_val = 0,
+};
+
+struct rte_hash *arp_hash_handle;
+struct rte_hash *nd_hash_handle;
+
+void print_pkt1(struct rte_mbuf *pkt);
+
+struct app_params *myApp;
+struct rte_pipeline *myP;
+uint8_t num_vnf_threads;
+
+/**
+* A structure for Arp port address
+*/
+struct arp_port_address {
+       uint32_t ip;                     /**< Ip address */
+       uint8_t mac_addr[6]; /**< Mac address */
+};
+
+struct arp_port_address arp_port_addresses[RTE_MAX_ETHPORTS];
+struct rte_mempool *timer_mempool_arp;
+
+int timer_objs_mempool_count = 70000;
+
+#define MAX_NUM_ARP_ENTRIES 64
+#define MAX_NUM_ND_ENTRIES 64
+
+uint32_t get_nh(uint32_t, uint32_t *);
+void get_nh_ipv6(uint8_t ipv6[], uint32_t *port, uint8_t nhipv6[]);
+
+#define MAX_ARP_DATA_ENTRY_TABLE 7
+
+struct table_arp_entry_data arp_entry_data_table[MAX_ARP_DATA_ENTRY_TABLE] = {
+       {{0, 0, 0, 0, 0, 1}, 1, INCOMPLETE, IPv4(192, 168, 0, 2)},
+       {{0, 0, 0, 0, 0, 2}, 0, INCOMPLETE, IPv4(192, 168, 0, 3)},
+       {{0, 0, 0, 0, 0, 1}, 1, INCOMPLETE, IPv4(30, 40, 50, 60)},
+       {{0, 0, 0, 0, 0, 1}, 1, INCOMPLETE, IPv4(120, 0, 0, 2)},
+       {{0, 0, 0, 0, 0, 4}, 3, INCOMPLETE, IPv4(1, 1, 1, 4)},
+       {{0, 0, 0, 0, 0, 5}, 4, INCOMPLETE, IPv4(1, 1, 1, 5)},
+       {{0, 0, 0, 0, 0, 6}, 1, INCOMPLETE, IPv4(1, 1, 1, 7)},
+};
+
+#define MAX_ND_DATA_ENTRY_TABLE 7
+struct table_nd_entry_data nd_entry_data_table[MAX_ND_DATA_ENTRY_TABLE] = {
+       {{0, 0, 0, 0, 0, 8}, 1, INCOMPLETE,
+        {10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, 0},
+
+       {{0, 0, 0, 0, 0, 9}, 1, INCOMPLETE,
+        {20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20}, 0},
+       {{0, 0, 0, 0, 0, 10}, 2, INCOMPLETE,
+        {3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1}, 0},
+       {{0, 0, 0, 0, 0, 11}, 3, INCOMPLETE,
+        {4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1}, 0},
+       {{0, 0, 0, 0, 0, 12}, 4, INCOMPLETE,
+        {5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1}, 0},
+       {{0, 0, 0, 0, 0, 13}, 5, INCOMPLETE,
+        {6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1}, 0},
+       {{0, 0, 0, 0, 0, 14}, 6, INCOMPLETE,
+        {7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1}, 0},
+};
+
+struct lib_nd_route_table_entry lib_nd_route_table[MAX_ND_RT_ENTRY] = {
+       {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, 0,
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+       {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, 0,
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+       {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, 0,
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+       {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, 0,
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+       {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, 0,
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+       {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, 0,
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+       {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, 0,
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+       {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, 0,
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+       {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, 0,
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+       {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, 0,
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+       {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, 0,
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+       {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, 0,
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+       {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, 0,
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+       {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, 0,
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+       {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, 0,
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+       {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, 0,
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }
+};
+
+struct lib_arp_route_table_entry lib_arp_route_table[MAX_ARP_RT_ENTRY] = {
+       {0, 0, 0, 0},
+       {0, 0, 0, 0},
+       {0, 0, 0, 0},
+       {0, 0, 0, 0},
+       {0, 0, 0, 0},
+       {0, 0, 0, 0},
+       {0, 0, 0, 0},
+       {0, 0, 0, 0},
+       {0, 0, 0, 0},
+       {0, 0, 0, 0},
+       {0, 0, 0, 0},
+       {0, 0, 0, 0},
+       {0, 0, 0, 0},
+       {0, 0, 0, 0},
+       {0, 0, 0, 0},
+       {0, 0, 0, 0}
+};
+
+void print_trace(void);
+
+/* Obtain a backtrace and print it to stdout. */
+void print_trace(void)
+{
+       void *array[10];
+       size_t size;
+       char **strings;
+       size_t i;
+
+       size = backtrace(array, 10);
+       strings = backtrace_symbols(array, size);
+
+       RTE_LOG(INFO, LIBARP, "Obtained %zd stack frames.\n", size);
+
+       for (i = 0; i < size; i++)
+               RTE_LOG(INFO, LIBARP, "%s\n", strings[i]);
+
+       free(strings);
+}
+
+uint32_t get_nh(uint32_t ip, uint32_t *port)
+{
+       int i = 0;
+       for (i = 0; i < MAX_ARP_RT_ENTRY; i++) {
+               if (((lib_arp_route_table[i].
+                                       ip & lib_arp_route_table[i].mask) ==
+                                (ip & lib_arp_route_table[i].mask))) {
+
+                       *port = lib_arp_route_table[i].port;
+                       lib_arp_nh_found++;
+                       return lib_arp_route_table[i].nh;
+               }
+               if (ARPICMP_DEBUG)
+                       printf("No nh match ip 0x%x, port %u, t_ip "
+                                                "0x%x, t_port %u, mask 0x%x, r1 %x, r2 %x\n",
+                                                ip, *port, lib_arp_route_table[i].ip,
+                                                lib_arp_route_table[i].port,
+                                                lib_arp_route_table[i].mask,
+                                                (lib_arp_route_table[i].ip &
+                               lib_arp_route_table[i].mask),
+                                                (ip & lib_arp_route_table[i].mask));
+       }
+       if (ARPICMP_DEBUG)
+               printf("No NH - ip 0x%x, port %u\n", ip, *port);
+       lib_arp_no_nh_found++;
+       return 0;
+}
+
+/*ND IPv6 */
+void get_nh_ipv6(uint8_t ipv6[], uint32_t *port, uint8_t nhipv6[])
+{
+       int i = 0;
+       uint8_t netmask_ipv6[16], netip_nd[16], netip_in[16];
+       uint8_t k = 0, l = 0, depthflags = 0, depthflags1 = 0;
+       memset(netmask_ipv6, 0, sizeof(netmask_ipv6));
+       memset(netip_nd, 0, sizeof(netip_nd));
+       memset(netip_in, 0, sizeof(netip_in));
+       if (!ipv6)
+               return;
+       for (i = 0; i < MAX_ARP_RT_ENTRY; i++) {
+
+               convert_prefixlen_to_netmask_ipv6(lib_nd_route_table[i].depth,
+                                                       netmask_ipv6);
+
+               for (k = 0; k < 16; k++) {
+                       if (lib_nd_route_table[i].ipv6[k] & netmask_ipv6[k]) {
+                               depthflags++;
+                               netip_nd[k] = lib_nd_route_table[i].ipv6[k];
+                       }
+               }
+
+               for (l = 0; l < 16; l++) {
+                       if (ipv6[l] & netmask_ipv6[l]) {
+                               depthflags1++;
+                               netip_in[l] = ipv6[l];
+                       }
+               }
+               int j = 0;
+               if ((depthflags == depthflags1)
+                               && (memcmp(netip_nd, netip_in, sizeof(netip_nd)) == 0)) {
+                       //&& (lib_nd_route_table[i].port == port))
+                       *port = lib_nd_route_table[i].port;
+                       lib_nd_nh_found++;
+
+                       for (j = 0; j < 16; j++)
+                               nhipv6[j] = lib_nd_route_table[i].nhipv6[j];
+
+                       return;
+               }
+
+               if (NDIPV6_DEBUG)
+                       printf("No nh match\n");
+               depthflags = 0;
+               depthflags1 = 0;
+       }
+       if (NDIPV6_DEBUG)
+               printf("No NH - ip 0x%x, port %u\n", ipv6[0], *port);
+       lib_nd_no_nh_found++;
+}
+
+/* Added for Multiport changes*/
+int get_dest_mac_addr_port(const uint32_t ipaddr,
+                                uint32_t *phy_port, struct ether_addr *hw_addr)
+{
+       lib_arp_get_mac_req++;
+       uint32_t nhip = 0;
+
+       nhip = get_nh(ipaddr, phy_port);
+       if (nhip == 0) {
+               if (ARPICMP_DEBUG)
+                       printf("ARPICMP no nh found for ip %x, port %d\n",
+                                                ipaddr, *phy_port);
+               //return 0;
+               return NH_NOT_FOUND;
+       }
+
+       struct arp_entry_data *ret_arp_data = NULL;
+       struct arp_key_ipv4 tmp_arp_key;
+       tmp_arp_key.port_id = *phy_port;        /* Changed for Multi Port */
+       tmp_arp_key.ip = nhip;
+
+       if (ARPICMP_DEBUG)
+               printf("%s: nhip: %x, phyport: %d\n", __FUNCTION__, nhip,
+                                        *phy_port);
+
+       ret_arp_data = retrieve_arp_entry(tmp_arp_key);
+       if (ret_arp_data == NULL) {
+               if (ARPICMP_DEBUG) {
+                       printf
+                                       ("ARPICMP no arp entry found for ip %x, port %d\n",
+                                        ipaddr, *phy_port);
+                       print_arp_table();
+               }
+               if (nhip != 0) {
+                       if (ARPICMP_DEBUG)
+                               printf("CG-NAPT requesting ARP for ip %x, "
+                                                        "port %d\n", nhip, *phy_port);
+                       request_arp(*phy_port, nhip);   //Changed for Multiport
+
+               }
+               lib_arp_no_arp_entry_found++;
+               return ARP_NOT_FOUND;
+       }
+       ether_addr_copy(&ret_arp_data->eth_addr, hw_addr);
+       lib_arp_arp_entry_found++;
+       if (ARPICMP_DEBUG)
+               printf("%s: ARPICMP hwaddr found\n", __FUNCTION__);
+       return ARP_FOUND;
+}
+
+int get_dest_mac_address(const uint32_t ipaddr, uint32_t *phy_port,
+                        struct ether_addr *hw_addr, uint32_t *nhip)
+{
+       lib_arp_get_mac_req++;
+
+       *nhip = get_nh(ipaddr, phy_port);
+       if (*nhip == 0) {
+               if (ARPICMP_DEBUG && ipaddr)
+                       RTE_LOG(INFO, LIBARP,
+                               "ARPICMP no nh found for ip %x, port %d\n",
+                               ipaddr, *phy_port);
+               return 0;
+       }
+
+       struct arp_entry_data *ret_arp_data = NULL;
+       struct arp_key_ipv4 tmp_arp_key;
+       tmp_arp_key.port_id = *phy_port;
+       tmp_arp_key.ip = *nhip;
+
+       ret_arp_data = retrieve_arp_entry(tmp_arp_key);
+       if (ret_arp_data == NULL) {
+               if (ARPICMP_DEBUG && ipaddr) {
+                       RTE_LOG(INFO, LIBARP,
+                               "ARPICMP no arp entry found for ip %x, port %d\n",
+                               ipaddr, *phy_port);
+                       print_arp_table();
+               }
+               lib_arp_no_arp_entry_found++;
+               return 0;
+       }
+       ether_addr_copy(&ret_arp_data->eth_addr, hw_addr);
+       lib_arp_arp_entry_found++;
+       return 1;
+
+}
+
+int get_dest_mac_addr(const uint32_t ipaddr,
+                                       uint32_t *phy_port, struct ether_addr *hw_addr)
+{
+       lib_arp_get_mac_req++;
+       uint32_t nhip = 0;
+
+       nhip = get_nh(ipaddr, phy_port);
+       if (nhip == 0) {
+               if (ARPICMP_DEBUG && ipaddr)
+                       RTE_LOG(INFO, LIBARP,
+                               "ARPICMP no nh found for ip %x, port %d\n",
+                               ipaddr, *phy_port);
+               return 0;
+       }
+
+       struct arp_entry_data *ret_arp_data = NULL;
+       struct arp_key_ipv4 tmp_arp_key;
+       tmp_arp_key.port_id = *phy_port;
+       tmp_arp_key.ip = nhip;
+
+       ret_arp_data = retrieve_arp_entry(tmp_arp_key);
+       if (ret_arp_data == NULL) {
+               if (ARPICMP_DEBUG && ipaddr) {
+                       printf
+                                       ("ARPICMP no arp entry found for ip %x, port %d\n",
+                                        ipaddr, *phy_port);
+                       print_arp_table();
+               }
+
+               if (nhip != 0) {
+                       if (ARPICMP_DEBUG > 4)
+                               printf
+                                               ("CG-NAPT requesting ARP for ip %x, port %d\n",
+                                                nhip, *phy_port);
+                       if (ifm_chk_port_ipv4_enabled(*phy_port)) {
+                               request_arp(*phy_port, nhip);
+                       } else {
+                               if (ARPICMP_DEBUG)
+                                       RTE_LOG(INFO, LIBARP,
+                                               "%s: IP is not enabled on port %u, not sending ARP REQ\n\r",
+                                               __FUNCTION__, *phy_port);
+                       }
+
+               }
+               lib_arp_no_arp_entry_found++;
+               return 0;
+       }
+       ether_addr_copy(&ret_arp_data->eth_addr, hw_addr);
+       lib_arp_arp_entry_found++;
+       return 1;
+}
+
+int get_dest_mac_address_ipv6_port(uint8_t ipv6addr[], uint32_t *phy_port,
+                                        struct ether_addr *hw_addr, uint8_t nhipv6[])
+{
+       int i = 0, j = 0, flag = 0;
+       lib_nd_get_mac_req++;
+
+       get_nh_ipv6(ipv6addr, phy_port, nhipv6);
+       for (j = 0; j < 16; j++) {
+               if (nhipv6[j])
+                       flag++;
+       }
+       if (flag == 0) {
+               if (NDIPV6_DEBUG)
+                       printf("NDIPV6 no nh found for ipv6 "
+                                                "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
+                                                "%02x%02x%02x%02x%02x%02x, port %d\n",
+                                                ipv6addr[0], ipv6addr[1], ipv6addr[2],
+                                                ipv6addr[3], ipv6addr[4], ipv6addr[5],
+                                                ipv6addr[6], ipv6addr[7], ipv6addr[8],
+                                                ipv6addr[9], ipv6addr[10], ipv6addr[11],
+                                                ipv6addr[12], ipv6addr[13], ipv6addr[14],
+                                                ipv6addr[15], *phy_port);
+               return 0;
+       }
+
+       struct nd_entry_data *ret_nd_data = NULL;
+       struct nd_key_ipv6 tmp_nd_key;
+       tmp_nd_key.port_id = *phy_port;
+
+       for (i = 0; i < 16; i++)
+               tmp_nd_key.ipv6[i] = nhipv6[i];
+
+       ret_nd_data = retrieve_nd_entry(tmp_nd_key);
+       if (ret_nd_data == NULL) {
+               if (NDIPV6_DEBUG) {
+                       printf("NDIPV6 no nd entry found for ip %x, port %d\n",
+                                                ipv6addr[0], *phy_port);
+               }
+               lib_nd_no_arp_entry_found++;
+               return 0;
+       }
+       ether_addr_copy(&ret_nd_data->eth_addr, hw_addr);
+       lib_nd_nd_entry_found++;
+       return 1;
+}
+
+int get_dest_mac_address_ipv6(uint8_t ipv6addr[], uint32_t *phy_port,
+                                               struct ether_addr *hw_addr, uint8_t nhipv6[])
+{
+       int i = 0, j = 0, flag = 0;
+       lib_nd_get_mac_req++;
+
+       get_nh_ipv6(ipv6addr, phy_port, nhipv6);
+       for (j = 0; j < 16; j++) {
+               if (nhipv6[j]) {
+                       flag++;
+               }
+       }
+       if (flag == 0) {
+               if (NDIPV6_DEBUG && ipv6addr)
+                       RTE_LOG(INFO, LIBARP,
+                               "NDIPV6 no nh found for ipv6 %x, port %d\n",
+                               ipv6addr[0], *phy_port);
+               return 0;
+       }
+
+       struct nd_entry_data *ret_nd_data = NULL;
+       struct nd_key_ipv6 tmp_nd_key;
+       tmp_nd_key.port_id = *phy_port;
+
+       for (i = 0; i < 16; i++) {
+               tmp_nd_key.ipv6[i] = nhipv6[i];
+       }
+
+       ret_nd_data = retrieve_nd_entry(tmp_nd_key);
+       if (ret_nd_data == NULL) {
+               if (NDIPV6_DEBUG && ipv6addr) {
+                       RTE_LOG(INFO, LIBARP,
+                               "NDIPV6 no nd entry found for ip %x, port %d\n",
+                               ipv6addr[0], *phy_port);
+               }
+               if (flag != 0) {
+                       if (ARPICMP_DEBUG > 4)
+                               printf
+                                               ("Requesting ARP for ipv6 addr and port %d\n",
+                                                *phy_port);
+                       request_nd(&nhipv6[0], ifm_get_port(*phy_port));
+
+               }
+
+               lib_nd_no_arp_entry_found++;
+               return 0;
+       }
+       ether_addr_copy(&ret_nd_data->eth_addr, hw_addr);
+       lib_nd_nd_entry_found++;
+       return 1;
+}
+
+/**
+* A structure for arp entries in Arp table
+*
+*/
+struct lib_arp_arp_table_entry {
+       struct rte_pipeline_table_entry head;
+       uint64_t macaddr;  /**< Mac address */
+};
+
+static const char *arp_op_name(uint16_t arp_op)
+{
+       switch (CHECK_ENDIAN_16(arp_op)) {
+       case (ARP_OP_REQUEST):
+               return "ARP Request";
+       case (ARP_OP_REPLY):
+               return "ARP Reply";
+       case (ARP_OP_REVREQUEST):
+               return "Reverse ARP Request";
+       case (ARP_OP_REVREPLY):
+               return "Reverse ARP Reply";
+       case (ARP_OP_INVREQUEST):
+               return "Peer Identify Request";
+       case (ARP_OP_INVREPLY):
+               return "Peer Identify Reply";
+       default:
+               break;
+       }
+       return "Unkwown ARP op";
+}
+
+static void print_icmp_packet(struct icmp_hdr *icmp_h)
+{
+       RTE_LOG(INFO, LIBARP, "  ICMP: type=%d (%s) code=%d id=%d seqnum=%d\n",
+               icmp_h->icmp_type,
+               (icmp_h->icmp_type == IP_ICMP_ECHO_REPLY ? "Reply" :
+                (icmp_h->icmp_type ==
+                       IP_ICMP_ECHO_REQUEST ? "Reqest" : "Undef")),
+               icmp_h->icmp_code, CHECK_ENDIAN_16(icmp_h->icmp_ident),
+               CHECK_ENDIAN_16(icmp_h->icmp_seq_nb));
+}
+
+static void print_ipv4_h(struct ipv4_hdr *ip_h)
+{
+       struct icmp_hdr *icmp_h =
+                       (struct icmp_hdr *)((char *)ip_h + sizeof(struct ipv4_hdr));
+       RTE_LOG(INFO, LIBARP, "  IPv4: Version=%d HLEN=%d Type=%d Length=%d\n",
+               (ip_h->version_ihl & 0xf0) >> 4, (ip_h->version_ihl & 0x0f),
+               ip_h->type_of_service, rte_cpu_to_be_16(ip_h->total_length));
+       if (ip_h->next_proto_id == IPPROTO_ICMP) {
+               print_icmp_packet(icmp_h);
+       }
+}
+
+static void print_arp_packet(struct arp_hdr *arp_h)
+{
+       RTE_LOG(INFO, LIBARP, "  ARP:  hrd=%d proto=0x%04x hln=%d "
+               "pln=%d op=%u (%s)\n",
+               CHECK_ENDIAN_16(arp_h->arp_hrd),
+               CHECK_ENDIAN_16(arp_h->arp_pro), arp_h->arp_hln,
+               arp_h->arp_pln, CHECK_ENDIAN_16(arp_h->arp_op),
+               arp_op_name(arp_h->arp_op));
+
+       if (CHECK_ENDIAN_16(arp_h->arp_hrd) != ARP_HRD_ETHER) {
+               RTE_LOG(INFO, LIBARP,
+                       "incorrect arp_hrd format for IPv4 ARP (%d)\n",
+                       (arp_h->arp_hrd));
+       } else if (CHECK_ENDIAN_16(arp_h->arp_pro) != ETHER_TYPE_IPv4) {
+               RTE_LOG(INFO, LIBARP,
+                       "incorrect arp_pro format for IPv4 ARP (%d)\n",
+                       (arp_h->arp_pro));
+       } else if (arp_h->arp_hln != 6) {
+               RTE_LOG(INFO, LIBARP,
+                       "incorrect arp_hln format for IPv4 ARP (%d)\n",
+                       arp_h->arp_hln);
+       } else if (arp_h->arp_pln != 4) {
+               RTE_LOG(INFO, LIBARP,
+                       "incorrect arp_pln format for IPv4 ARP (%d)\n",
+                       arp_h->arp_pln);
+       } else {
+               RTE_LOG(INFO, LIBARP,
+                       "        sha=%02X:%02X:%02X:%02X:%02X:%02X",
+                       arp_h->arp_data.arp_sha.addr_bytes[0],
+                       arp_h->arp_data.arp_sha.addr_bytes[1],
+                       arp_h->arp_data.arp_sha.addr_bytes[2],
+                       arp_h->arp_data.arp_sha.addr_bytes[3],
+                       arp_h->arp_data.arp_sha.addr_bytes[4],
+                       arp_h->arp_data.arp_sha.addr_bytes[5]);
+               RTE_LOG(INFO, LIBARP, " sip=%d.%d.%d.%d\n",
+                       (CHECK_ENDIAN_32(arp_h->arp_data.arp_sip) >> 24) & 0xFF,
+                       (CHECK_ENDIAN_32(arp_h->arp_data.arp_sip) >> 16) & 0xFF,
+                       (CHECK_ENDIAN_32(arp_h->arp_data.arp_sip) >> 8) & 0xFF,
+                       CHECK_ENDIAN_32(arp_h->arp_data.arp_sip) & 0xFF);
+               RTE_LOG(INFO, LIBARP,
+                       "        tha=%02X:%02X:%02X:%02X:%02X:%02X",
+                       arp_h->arp_data.arp_tha.addr_bytes[0],
+                       arp_h->arp_data.arp_tha.addr_bytes[1],
+                       arp_h->arp_data.arp_tha.addr_bytes[2],
+                       arp_h->arp_data.arp_tha.addr_bytes[3],
+                       arp_h->arp_data.arp_tha.addr_bytes[4],
+                       arp_h->arp_data.arp_tha.addr_bytes[5]);
+               RTE_LOG(INFO, LIBARP, " tip=%d.%d.%d.%d\n",
+                       (CHECK_ENDIAN_32(arp_h->arp_data.arp_tip) >> 24) & 0xFF,
+                       (CHECK_ENDIAN_32(arp_h->arp_data.arp_tip) >> 16) & 0xFF,
+                       (CHECK_ENDIAN_32(arp_h->arp_data.arp_tip) >> 8) & 0xFF,
+                       CHECK_ENDIAN_32(arp_h->arp_data.arp_tip) & 0xFF);
+       }
+}
+
+static void print_eth(struct ether_hdr *eth_h)
+{
+       RTE_LOG(INFO, LIBARP, "  ETH:  src=%02X:%02X:%02X:%02X:%02X:%02X",
+               eth_h->s_addr.addr_bytes[0],
+               eth_h->s_addr.addr_bytes[1],
+               eth_h->s_addr.addr_bytes[2],
+               eth_h->s_addr.addr_bytes[3],
+               eth_h->s_addr.addr_bytes[4], eth_h->s_addr.addr_bytes[5]);
+       RTE_LOG(INFO, LIBARP, " dst=%02X:%02X:%02X:%02X:%02X:%02X\n",
+               eth_h->d_addr.addr_bytes[0],
+               eth_h->d_addr.addr_bytes[1],
+               eth_h->d_addr.addr_bytes[2],
+               eth_h->d_addr.addr_bytes[3],
+               eth_h->d_addr.addr_bytes[4], eth_h->d_addr.addr_bytes[5]);
+
+}
+
+static void
+print_mbuf(const char *rx_tx, uint8_t portid, struct rte_mbuf *mbuf,
+                unsigned line)
+{
+       struct ether_hdr *eth_h = rte_pktmbuf_mtod(mbuf, struct ether_hdr *);
+       struct arp_hdr *arp_h =
+                       (struct arp_hdr *)((char *)eth_h + sizeof(struct ether_hdr));
+       struct ipv4_hdr *ipv4_h =
+                       (struct ipv4_hdr *)((char *)eth_h + sizeof(struct ether_hdr));
+
+       RTE_LOG(INFO, LIBARP, "%s(%d): on port %d pkt-len=%u nb-segs=%u\n",
+               rx_tx, line, portid, mbuf->pkt_len, mbuf->nb_segs);
+       print_eth(eth_h);
+       switch (rte_cpu_to_be_16(eth_h->ether_type)) {
+       case ETHER_TYPE_IPv4:
+               print_ipv4_h(ipv4_h);
+               break;
+       case ETHER_TYPE_ARP:
+               print_arp_packet(arp_h);
+               break;
+       default:
+               RTE_LOG(INFO, LIBARP, "  unknown packet type\n");
+               break;
+       }
+       fflush(stdout);
+}
+
+struct arp_entry_data *retrieve_arp_entry(struct arp_key_ipv4 arp_key)
+{
+       struct arp_entry_data *ret_arp_data = NULL;
+       arp_key.filler1 = 0;
+       arp_key.filler2 = 0;
+       arp_key.filler3 = 0;
+
+       int ret = rte_hash_lookup_data(arp_hash_handle, &arp_key,
+                                                        (void **)&ret_arp_data);
+       if (ret < 0) {
+               //      RTE_LOG(INFO, LIBARP,"arp-hash lookup failed ret %d, EINVAL %d, ENOENT %d\n", ret, EINVAL, ENOENT);
+       } else {
+
+               if (ret_arp_data->mode == DYNAMIC_ARP) {
+                       struct arp_timer_key callback_key;
+                       callback_key.port_id = ret_arp_data->port;
+                       callback_key.ip = ret_arp_data->ip;
+                       /*lcore need to check which parameter need to be put */
+                       if (rte_timer_reset(ret_arp_data->timer,
+                                                       (arp_timeout * rte_get_tsc_hz()),
+                                                       SINGLE, timer_lcore,
+                                                       arp_timer_callback,
+                                                       &callback_key) < 0)
+                               if (ARPICMP_DEBUG)
+                                       RTE_LOG(INFO, LIBARP,
+                                               "Err : Timer already running\n");
+               }
+
+               return ret_arp_data;
+       }
+
+       return NULL;
+}
+
+struct nd_entry_data *retrieve_nd_entry(struct nd_key_ipv6 nd_key)
+{
+       struct nd_entry_data *ret_nd_data = NULL;
+       nd_key.filler1 = 0;
+       nd_key.filler2 = 0;
+       nd_key.filler3 = 0;
+       int i = 0;
+
+       /*Find a nd IPv6 key-data pair in the hash table for ND IPv6 */
+       int ret = rte_hash_lookup_data(nd_hash_handle, &nd_key,
+                                                        (void **)&ret_nd_data);
+       if (ret < 0) {
+/*             RTE_LOG(INFO, LIBARP,"nd-hash: no lookup Entry Found - ret %d, EINVAL %d, ENOENT %d\n",
+                               ret, EINVAL, ENOENT);*/
+       } else {
+               if (ret_nd_data->mode == DYNAMIC_ND) {
+                       struct nd_timer_key callback_key;
+                       callback_key.port_id = ret_nd_data->port;
+
+                       for (i = 0; i < ND_IPV6_ADDR_SIZE; i++) {
+                               callback_key.ipv6[i] = ret_nd_data->ipv6[i];
+
+                       }
+
+                       if (rte_timer_reset
+                                       (ret_nd_data->timer,
+                                        (arp_timeout * rte_get_tsc_hz()), SINGLE,
+                                        timer_lcore, nd_timer_callback, &callback_key) < 0)
+                               if (ARPICMP_DEBUG)
+                                       RTE_LOG(INFO, LIBARP,
+                                               "Err : Timer already running\n");
+               }
+               return ret_nd_data;
+       }
+
+       return NULL;
+}
+
+void print_arp_table(void)
+{
+       const void *next_key;
+       void *next_data;
+       uint32_t iter = 0;
+
+       printf
+                       ("------------------------ ARP CACHE -----------------------------------------\n");
+       printf
+                       ("----------------------------------------------------------------------------\n");
+       printf("\tport  hw addr            status     ip addr\n");
+       printf
+                       ("----------------------------------------------------------------------------\n");
+
+       while (rte_hash_iterate(arp_hash_handle, &next_key, &next_data, &iter)
+                                >= 0) {
+
+               struct arp_entry_data *tmp_arp_data =
+                               (struct arp_entry_data *)next_data;
+               struct arp_key_ipv4 tmp_arp_key;
+               memcpy(&tmp_arp_key, next_key, sizeof(struct arp_key_ipv4));
+               printf
+                               ("\t%4d  %02X:%02X:%02X:%02X:%02X:%02X  %10s %d.%d.%d.%d\n",
+                                tmp_arp_data->port, tmp_arp_data->eth_addr.addr_bytes[0],
+                                tmp_arp_data->eth_addr.addr_bytes[1],
+                                tmp_arp_data->eth_addr.addr_bytes[2],
+                                tmp_arp_data->eth_addr.addr_bytes[3],
+                                tmp_arp_data->eth_addr.addr_bytes[4],
+                                tmp_arp_data->eth_addr.addr_bytes[5],
+                                tmp_arp_data->status ==
+                                COMPLETE ? "COMPLETE" : "INCOMPLETE",
+                                (tmp_arp_data->ip >> 24),
+                                ((tmp_arp_data->ip & 0x00ff0000) >> 16),
+                                ((tmp_arp_data->ip & 0x0000ff00) >> 8),
+                                ((tmp_arp_data->ip & 0x000000ff)));
+       }
+
+       uint32_t i = 0;
+       printf("\nARP routing table has %d entries\n", arp_route_tbl_index);
+       printf("\nIP_Address    Mask          Port    NH_IP_Address\n");
+       for (i = 0; i < arp_route_tbl_index; i++) {
+               printf("0x%x    0x%x    %d       0x%x\n",
+                                        lib_arp_route_table[i].ip,
+                                        lib_arp_route_table[i].mask,
+                                        lib_arp_route_table[i].port, lib_arp_route_table[i].nh);
+       }
+
+       printf
+                       ("\nARP Stats: Total Queries %u, ok_NH %u, no_NH %u, ok_Entry %u, no_Entry %u, PopulateCall %u, Del %u, Dup %u\n",
+                        lib_arp_get_mac_req, lib_arp_nh_found, lib_arp_no_nh_found,
+                        lib_arp_arp_entry_found, lib_arp_no_arp_entry_found,
+                        lib_arp_populate_called, lib_arp_delete_called,
+                        lib_arp_duplicate_found);
+
+       printf("ARP table key len is %lu\n", sizeof(struct arp_key_ipv4));
+}
+
+/* ND IPv6 */
+void print_nd_table(void)
+{
+       const void *next_key;
+       void *next_data;
+       uint32_t iter = 0;
+       uint8_t ii = 0, j = 0, k = 0;
+       printf
+                       ("------------------------------------------------------------------------------------------------------\n");
+       printf("\tport  hw addr            status         ip addr\n");
+
+       printf
+                       ("------------------------------------------------------------------------------------------------------\n");
+       while (rte_hash_iterate(nd_hash_handle, &next_key, &next_data, &iter) >=
+                                0) {
+
+               struct nd_entry_data *tmp_nd_data =
+                               (struct nd_entry_data *)next_data;
+               struct nd_key_ipv6 tmp_nd_key;
+               memcpy(&tmp_nd_key, next_key, sizeof(struct nd_key_ipv6));
+               printf("\t%4d  %02X:%02X:%02X:%02X:%02X:%02X  %10s\n",
+                                        tmp_nd_data->port,
+                                        tmp_nd_data->eth_addr.addr_bytes[0],
+                                        tmp_nd_data->eth_addr.addr_bytes[1],
+                                        tmp_nd_data->eth_addr.addr_bytes[2],
+                                        tmp_nd_data->eth_addr.addr_bytes[3],
+                                        tmp_nd_data->eth_addr.addr_bytes[4],
+                                        tmp_nd_data->eth_addr.addr_bytes[5],
+                                        tmp_nd_data->status ==
+                                        COMPLETE ? "COMPLETE" : "INCOMPLETE");
+               printf("\t\t\t\t\t\t");
+               for (ii = 0; ii < ND_IPV6_ADDR_SIZE; ii += 2) {
+                       printf("%02X%02X ", tmp_nd_data->ipv6[ii],
+                                                tmp_nd_data->ipv6[ii + 1]);
+               }
+               printf("\n");
+       }
+
+       uint32_t i = 0;
+       printf("\n\nND IPV6 routing table has %d entries\n",
+                                nd_route_tbl_index);
+       printf
+                       ("\nIP_Address                                          Depth          Port                             NH_IP_Address\n");
+       for (i = 0; i < nd_route_tbl_index; i++) {
+               printf("\n");
+
+               for (j = 0; j < ND_IPV6_ADDR_SIZE; j += 2) {
+                       RTE_LOG(INFO, LIBARP, "%02X%02X ",
+                               lib_nd_route_table[i].ipv6[j],
+                               lib_nd_route_table[i].ipv6[j + 1]);
+               }
+
+               printf
+                               ("\n\t\t\t                      %d                                       %d                                     \n",
+                                lib_nd_route_table[i].depth, lib_nd_route_table[i].port);
+               printf("\t\t\t\t\t\t\t\t\t");
+               for (k = 0; k < ND_IPV6_ADDR_SIZE; k += 2) {
+                       printf("%02X%02X ", lib_nd_route_table[i].nhipv6[k],
+                                                lib_nd_route_table[i].ipv6[k + 1]);
+               }
+       }
+       printf
+                       ("\nND IPV6 Stats: \nTotal Queries %u, ok_NH %u, no_NH %u, ok_Entry %u, no_Entry %u, PopulateCall %u, Del %u, Dup %u\n",
+                        lib_nd_get_mac_req, lib_nd_nh_found, lib_nd_no_nh_found,
+                        lib_nd_nd_entry_found, lib_nd_no_arp_entry_found,
+                        lib_nd_populate_called, lib_nd_delete_called,
+                        lib_nd_duplicate_found);
+       printf("ND table key len is %lu\n\n", sizeof(struct nd_key_ipv6));
+}
+
+void remove_arp_entry(uint32_t ipaddr, uint8_t portid, void *arg)
+{
+
+       struct arp_key_ipv4 arp_key;
+       arp_key.port_id = portid;
+       arp_key.ip = ipaddr;
+       arp_key.filler1 = 0;
+       arp_key.filler2 = 0;
+       arp_key.filler3 = 0;
+
+       lib_arp_delete_called++;
+
+       struct arp_entry_data *ret_arp_data = NULL;
+
+       int ret = rte_hash_lookup_data(arp_hash_handle, &arp_key,
+                                                        (void **)&ret_arp_data);
+       if (ret < 0) {
+//              RTE_LOG(INFO, LIBARP,"arp-hash lookup failed ret %d, EINVAL %d, ENOENT %d\n", ret, EINVAL, ENOENT);
+               return;
+       } else {
+               if (ret_arp_data->mode == DYNAMIC_ARP) {
+                       if (ret_arp_data->retry_count == 3) {
+                               rte_timer_stop(ret_arp_data->timer);
+                               rte_free(ret_arp_data->timer_key);
+                               if (ARPICMP_DEBUG) {
+                                       RTE_LOG(INFO, LIBARP,
+                                               "ARP Entry Deleted for IP :%d.%d.%d.%d , port %d\n",
+                                               (arp_key.ip >> 24),
+                                               ((arp_key.ip & 0x00ff0000) >>
+                                                16),
+                                               ((arp_key.ip & 0x0000ff00) >>
+                                                8),
+                                               ((arp_key.ip & 0x000000ff)),
+                                               arp_key.port_id);
+                               }
+                               rte_hash_del_key(arp_hash_handle, &arp_key);
+                               //print_arp_table();
+                       } else {
+                               ret_arp_data->retry_count++;
+                               if (ARPICMP_DEBUG)
+                                       RTE_LOG(INFO, LIBARP,
+                                               "RETRY ARP..retry count : %u\n",
+                                               ret_arp_data->retry_count);
+                               //print_arp_table();
+                               if (ARPICMP_DEBUG)
+                                       RTE_LOG(INFO, LIBARP,
+                                               "TIMER STARTED FOR %u seconds\n",
+                                               ARP_TIMER_EXPIRY);
+                               if (ifm_chk_port_ipv4_enabled
+                                               (ret_arp_data->port)) {
+                                       request_arp(ret_arp_data->port,
+                                                               ret_arp_data->ip);
+                               } else {
+                                       if (ARPICMP_DEBUG)
+                                               RTE_LOG(INFO, LIBARP,
+                                                       "%s: IP is not enabled on port %u, not sending GARP\n\r",
+                                                       __FUNCTION__,
+                                                       ret_arp_data->port);
+                               }
+                               if (rte_timer_reset(ret_arp_data->timer,
+                                                               (arp_timeout *
+                                                                rte_get_tsc_hz()), SINGLE,
+                                                               timer_lcore,
+                                                               arp_timer_callback,
+                                                               arg) < 0)
+                                       if (ARPICMP_DEBUG)
+                                               RTE_LOG(INFO, LIBARP,
+                                                       "Err : Timer already running\n");
+
+                       }
+               } else {
+                       rte_hash_del_key(arp_hash_handle, &arp_key);
+               }
+       }
+}
+
+/* ND IPv6 */
+void remove_nd_entry_ipv6(uint8_t ipv6addr[], uint8_t portid)
+{
+       int i = 0;
+       struct nd_entry_data *ret_nd_data = NULL;
+       struct nd_key_ipv6 nd_key;
+       nd_key.port_id = portid;
+
+       for (i = 0; i < ND_IPV6_ADDR_SIZE; i++) {
+               nd_key.ipv6[i] = ipv6addr[i];
+       }
+
+       nd_key.filler1 = 0;
+       nd_key.filler2 = 0;
+       nd_key.filler3 = 0;
+
+       lib_nd_delete_called++;
+
+       if (NDIPV6_DEBUG) {
+               RTE_LOG(INFO, LIBARP,
+                       "Deletes rte hash table nd entry for port %d ipv6=",
+                       nd_key.port_id);
+               for (i = 0; i < ND_IPV6_ADDR_SIZE; i += 2) {
+                       RTE_LOG(INFO, LIBARP, "%02X%02X ", nd_key.ipv6[i],
+                               nd_key.ipv6[i + 1]);
+               }
+       }
+       struct nd_timer_key callback_key;
+       callback_key.port_id = portid;
+
+       for (i = 0; i < ND_IPV6_ADDR_SIZE; i++) {
+               callback_key.ipv6[i] = ipv6addr[i];
+
+       }
+       int ret = rte_hash_lookup_data(arp_hash_handle, &callback_key,
+                                                        (void **)&ret_nd_data);
+       if (ret < 0) {
+//              RTE_LOG(INFO, LIBARP,"arp-hash lookup failed ret %d, EINVAL %d, ENOENT %d\n", ret, EINVAL, ENOENT);
+       } else {
+               if (ret_nd_data->mode == DYNAMIC_ND) {
+                       rte_timer_stop(ret_nd_data->timer);
+                       rte_free(ret_nd_data->timer);
+               }
+       }
+       rte_hash_del_key(nd_hash_handle, &nd_key);
+}
+
+void
+populate_arp_entry(const struct ether_addr *hw_addr, uint32_t ipaddr,
+                        uint8_t portid, uint8_t mode)
+{
+       struct arp_key_ipv4 arp_key;
+       arp_key.port_id = portid;
+       arp_key.ip = ipaddr;
+       arp_key.filler1 = 0;
+       arp_key.filler2 = 0;
+       arp_key.filler3 = 0;
+
+       lib_arp_populate_called++;
+
+       if (ARPICMP_DEBUG)
+               RTE_LOG(INFO, LIBARP, "populate_arp_entry ip %x, port %d\n",
+                       arp_key.ip, arp_key.port_id);
+
+       struct arp_entry_data *new_arp_data = retrieve_arp_entry(arp_key);
+       if (new_arp_data && ((new_arp_data->mode == STATIC_ARP
+                && mode == DYNAMIC_ARP) || (new_arp_data->mode == DYNAMIC_ARP
+                && mode == STATIC_ARP))) {
+                if (ARPICMP_DEBUG)
+                        RTE_LOG(INFO, LIBARP,"populate_arp_entry: ARP entry already exists(%d %d)\n",
+                               new_arp_data->mode, mode);
+
+                return;
+        }
+
+       if (mode == DYNAMIC_ARP) {
+               if (new_arp_data
+                               && is_same_ether_addr(&new_arp_data->eth_addr, hw_addr)) {
+                       if (ARPICMP_DEBUG) {
+                               RTE_LOG(INFO, LIBARP,
+                                       "arp_entry exists ip :%d.%d.%d.%d , port %d\n",
+                                       (arp_key.ip >> 24),
+                                       ((arp_key.ip & 0x00ff0000) >> 16),
+                                       ((arp_key.ip & 0x0000ff00) >> 8),
+                                       ((arp_key.ip & 0x000000ff)),
+                                       arp_key.port_id);
+                       }
+                       lib_arp_duplicate_found++;
+                       new_arp_data->retry_count = 0;  // Reset
+                       if (rte_timer_reset(new_arp_data->timer,
+                                                       (arp_timeout * rte_get_tsc_hz()),
+                                                       SINGLE, timer_lcore,
+                                                       arp_timer_callback,
+                                                       new_arp_data->timer_key) < 0)
+                               if (ARPICMP_DEBUG)
+                                       RTE_LOG(INFO, LIBARP,
+                                               "Err : Timer already running\n");
+                       return;
+               }
+
+               uint32_t size =
+                               RTE_CACHE_LINE_ROUNDUP(sizeof(struct arp_entry_data));
+               new_arp_data = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
+               new_arp_data->eth_addr = *hw_addr;
+               new_arp_data->status = COMPLETE;
+               new_arp_data->port = portid;
+               new_arp_data->ip = ipaddr;
+               new_arp_data->mode = mode;
+               if (rte_mempool_get
+                               (timer_mempool_arp, (void **)&(new_arp_data->timer)) < 0) {
+                       RTE_LOG(INFO, LIBARP,
+                               "TIMER - Error in getting timer alloc buffer\n");
+                       return;
+               }
+
+               rte_hash_add_key_data(arp_hash_handle, &arp_key, new_arp_data);
+               if (ARPICMP_DEBUG) {
+                       RTE_LOG(INFO, LIBARP,
+                               "arp_entry exists ip :%d.%d.%d.%d , port %d\n",
+                               (arp_key.ip >> 24),
+                               ((arp_key.ip & 0x00ff0000) >> 16),
+                               ((arp_key.ip & 0x0000ff00) >> 8),
+                               ((arp_key.ip & 0x000000ff)), arp_key.port_id);
+               }
+               // Call l3fwd module for resolving 2_adj structure.
+               resolve_l2_adj(ipaddr, portid, hw_addr);
+
+               rte_timer_init(new_arp_data->timer);
+               struct arp_timer_key *callback_key =
+                               (struct arp_timer_key *)rte_malloc(NULL,
+                                                                        sizeof(struct
+                                                                               arp_timer_key *),
+                                                                        RTE_CACHE_LINE_SIZE);
+               callback_key->port_id = portid;
+               callback_key->ip = ipaddr;
+
+               if (ARPICMP_DEBUG)
+                       RTE_LOG(INFO, LIBARP, "TIMER STARTED FOR %u seconds\n",
+                               ARP_TIMER_EXPIRY);
+               if (rte_timer_reset
+                               (new_arp_data->timer, (arp_timeout * rte_get_tsc_hz()),
+                                SINGLE, timer_lcore, arp_timer_callback, callback_key) < 0)
+                       if (ARPICMP_DEBUG)
+                               RTE_LOG(INFO, LIBARP,
+                                       "Err : Timer already running\n");
+
+               new_arp_data->timer_key = callback_key;
+       } else {
+               if (new_arp_data
+                               && is_same_ether_addr(&new_arp_data->eth_addr, hw_addr)) {
+                       if (ARPICMP_DEBUG) {
+                               RTE_LOG(INFO, LIBARP,
+                                       "arp_entry exists ip :%d.%d.%d.%d , port %d\n",
+                                       (arp_key.ip >> 24),
+                                       ((arp_key.ip & 0x00ff0000) >> 16),
+                                       ((arp_key.ip & 0x0000ff00) >> 8),
+                                       ((arp_key.ip & 0x000000ff)),
+                                       arp_key.port_id);
+                       }
+                       lib_arp_duplicate_found++;
+               } else {
+                       uint32_t size =
+                                       RTE_CACHE_LINE_ROUNDUP(sizeof
+                                                        (struct arp_entry_data));
+                       new_arp_data =
+                                       rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
+                       new_arp_data->eth_addr = *hw_addr;
+                       new_arp_data->status = COMPLETE;
+                       new_arp_data->port = portid;
+                       new_arp_data->ip = ipaddr;
+                       new_arp_data->mode = mode;
+
+                       rte_hash_add_key_data(arp_hash_handle, &arp_key,
+                                                               new_arp_data);
+                       if (ARPICMP_DEBUG) {
+                               RTE_LOG(INFO, LIBARP,
+                                       "arp_entry exists ip :%d.%d.%d.%d , port %d\n",
+                                       (arp_key.ip >> 24),
+                                       ((arp_key.ip & 0x00ff0000) >> 16),
+                                       ((arp_key.ip & 0x0000ff00) >> 8),
+                                       ((arp_key.ip & 0x000000ff)),
+                                       arp_key.port_id);
+                       }
+                       // Call l3fwd module for resolving 2_adj structure.
+                       resolve_l2_adj(ipaddr, portid, hw_addr);
+               }
+       }
+       if (ARPICMP_DEBUG) {
+               /* print entire hash table */
+               RTE_LOG(INFO, LIBARP,
+                       "\tARP: table update - hwaddr=%02x:%02x:%02x:%02x:%02x:%02x  ip=%d.%d.%d.%d  on port=%d\n",
+                       new_arp_data->eth_addr.addr_bytes[0],
+                       new_arp_data->eth_addr.addr_bytes[1],
+                       new_arp_data->eth_addr.addr_bytes[2],
+                       new_arp_data->eth_addr.addr_bytes[3],
+                       new_arp_data->eth_addr.addr_bytes[4],
+                       new_arp_data->eth_addr.addr_bytes[5],
+                       (arp_key.ip >> 24), ((arp_key.ip & 0x00ff0000) >> 16),
+                       ((arp_key.ip & 0x0000ff00) >> 8),
+                       ((arp_key.ip & 0x000000ff)), portid);
+               puts("");
+       }
+}
+
+/*
+ * ND IPv6
+ *
+ * Install key - data pair in Hash table - From Pipeline Configuration
+ *
+ */
+
+void populate_nd_entry(const struct ether_addr *hw_addr, uint8_t ipv6[],
+                                        uint8_t portid, uint8_t mode)
+{
+
+       /* need to lock here if multi-threaded */
+       /* rte_hash_add_key_data is not thread safe */
+       uint8_t i;
+       struct nd_key_ipv6 nd_key;
+       nd_key.port_id = portid;
+
+       for (i = 0; i < ND_IPV6_ADDR_SIZE; i++)
+               nd_key.ipv6[i] = ipv6[i];
+
+//      RTE_LOG(INFO, LIBARP,"\n");
+       nd_key.filler1 = 0;
+       nd_key.filler2 = 0;
+       nd_key.filler3 = 0;
+
+       lib_nd_populate_called++;
+
+       /* Validate if key-value pair already exists in the hash table for ND IPv6 */
+       struct nd_entry_data *new_nd_data = retrieve_nd_entry(nd_key);
+
+       if (mode == DYNAMIC_ND) {
+               if (new_nd_data
+                               && is_same_ether_addr(&new_nd_data->eth_addr, hw_addr)) {
+
+                       if (NDIPV6_DEBUG) {
+                               RTE_LOG(INFO, LIBARP,
+                                       "nd_entry exists port %d ipv6 = ",
+                                       nd_key.port_id);
+                               for (i = 0; i < ND_IPV6_ADDR_SIZE; i += 2) {
+
+                                       RTE_LOG(INFO, LIBARP, "%02X%02X ",
+                                               nd_key.ipv6[i],
+                                               nd_key.ipv6[i + 1]);
+                               }
+                       }
+
+                       lib_nd_duplicate_found++;
+                       RTE_LOG(INFO, LIBARP, "nd_entry exists\n");
+                       return;
+               }
+               uint32_t size =
+                               RTE_CACHE_LINE_ROUNDUP(sizeof(struct nd_entry_data));
+               new_nd_data = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
+
+               //new_nd_data = (struct nd_entry_data *)rte_malloc(NULL, sizeof(struct nd_entry_data *),RTE_CACHE_LINE_SIZE);
+               new_nd_data->eth_addr = *hw_addr;
+               new_nd_data->status = COMPLETE;
+               new_nd_data->port = portid;
+               new_nd_data->mode = mode;
+               if (rte_mempool_get
+                               (timer_mempool_arp, (void **)&(new_nd_data->timer)) < 0) {
+                       RTE_LOG(INFO, LIBARP,
+                               "TIMER - Error in getting timer alloc buffer\n");
+                       return;
+               }
+
+               if (NDIPV6_DEBUG)
+                       RTE_LOG(INFO, LIBARP, "populate_nd_entry ipv6=");
+
+               for (i = 0; i < ND_IPV6_ADDR_SIZE; i++) {
+                       new_nd_data->ipv6[i] = ipv6[i];
+               }
+
+               if (NDIPV6_DEBUG) {
+                       for (i = 0; i < ND_IPV6_ADDR_SIZE; i += 2) {
+
+                               RTE_LOG(INFO, LIBARP, "%02X%02X ",
+                                       new_nd_data->ipv6[i],
+                                       new_nd_data->ipv6[i + 1]);
+                       }
+               }
+
+               /*Add a key-data pair at hash table for ND IPv6 static routing */
+               rte_hash_add_key_data(nd_hash_handle, &nd_key, new_nd_data);
+               /* need to check the return value of the hash add */
+
+               /* after the hash is created then time is started */
+               rte_timer_init(new_nd_data->timer);
+               struct nd_timer_key *callback_key =
+                               (struct nd_timer_key *)rte_malloc(NULL,
+                                                                       sizeof(struct nd_timer_key
+                                                                        *),
+                                                                       RTE_CACHE_LINE_SIZE);
+               callback_key->port_id = portid;
+
+               for (i = 0; i < ND_IPV6_ADDR_SIZE; i++) {
+                       callback_key->ipv6[i] = ipv6[i];
+               }
+               if (rte_timer_reset
+                               (new_nd_data->timer, (arp_timeout * rte_get_tsc_hz()),
+                                SINGLE, timer_lcore, nd_timer_callback, callback_key) < 0)
+                       RTE_LOG(INFO, LIBARP, "Err : Timer already running\n");
+       } else {
+               if (new_nd_data
+                               && is_same_ether_addr(&new_nd_data->eth_addr, hw_addr)) {
+                       if (NDIPV6_DEBUG) {
+                               RTE_LOG(INFO, LIBARP,
+                                       "nd_entry exists port %d ipv6 = ",
+                                       nd_key.port_id);
+                               for (i = 0; i < ND_IPV6_ADDR_SIZE; i += 2) {
+
+                                       RTE_LOG(INFO, LIBARP, "%02X%02X ",
+                                               nd_key.ipv6[i],
+                                               nd_key.ipv6[i + 1]);
+                               }
+                       }
+
+                       lib_nd_duplicate_found++;
+               } else {
+                       uint32_t size =
+                                       RTE_CACHE_LINE_ROUNDUP(sizeof
+                                                        (struct nd_entry_data));
+                       new_nd_data =
+                                       rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
+
+                       //new_nd_data = (struct nd_entry_data *)rte_malloc(NULL, sizeof(struct nd_entry_data *),RTE_CACHE_LINE_SIZE);
+                       new_nd_data->eth_addr = *hw_addr;
+                       new_nd_data->status = COMPLETE;
+                       new_nd_data->port = portid;
+                       new_nd_data->mode = mode;
+                       for (i = 0; i < ND_IPV6_ADDR_SIZE; i++) {
+                               new_nd_data->ipv6[i] = ipv6[i];
+                       }
+
+                       /*Add a key-data pair at hash table for ND IPv6 static routing */
+                       rte_hash_add_key_data(nd_hash_handle, &nd_key,
+                                                               new_nd_data);
+                       /* need to check the return value of the hash add */
+               }
+       }
+       if (NDIPV6_DEBUG)
+               printf
+                               ("\n....Added a key-data pair at rte hash table for ND IPv6 static routing\n");
+
+       if (1) {
+               /* print entire hash table */
+               printf
+                               ("\tND: table update - hwaddr=%02x:%02x:%02x:%02x:%02x:%02x on port=%d\n",
+                                new_nd_data->eth_addr.addr_bytes[0],
+                                new_nd_data->eth_addr.addr_bytes[1],
+                                new_nd_data->eth_addr.addr_bytes[2],
+                                new_nd_data->eth_addr.addr_bytes[3],
+                                new_nd_data->eth_addr.addr_bytes[4],
+                                new_nd_data->eth_addr.addr_bytes[5], portid);
+               RTE_LOG(INFO, LIBARP, "\tipv6=");
+               for (i = 0; i < ND_IPV6_ADDR_SIZE; i += 2) {
+                       new_nd_data->ipv6[i] = ipv6[i];
+                       RTE_LOG(INFO, LIBARP, "%02X%02X ", new_nd_data->ipv6[i],
+                               new_nd_data->ipv6[i + 1]);
+               }
+
+               RTE_LOG(INFO, LIBARP, "\n");
+
+               puts("");
+       }
+}
+
+void print_pkt1(struct rte_mbuf *pkt)
+{
+       uint8_t *rd = RTE_MBUF_METADATA_UINT8_PTR(pkt, 0);
+       int i = 0, j = 0;
+       RTE_LOG(INFO, LIBARP, "\nPacket Contents...\n");
+       for (i = 0; i < 20; i++) {
+               for (j = 0; j < 20; j++)
+                       RTE_LOG(INFO, LIBARP, "%02x ", rd[(20 * i) + j]);
+               RTE_LOG(INFO, LIBARP, "\n");
+       }
+}
+
+struct ether_addr broadcast_ether_addr = {
+       .addr_bytes[0] = 0xFF,
+       .addr_bytes[1] = 0xFF,
+       .addr_bytes[2] = 0xFF,
+       .addr_bytes[3] = 0xFF,
+       .addr_bytes[4] = 0xFF,
+       .addr_bytes[5] = 0xFF,
+};
+
+static const struct ether_addr null_ether_addr = {
+       .addr_bytes[0] = 0x00,
+       .addr_bytes[1] = 0x00,
+       .addr_bytes[2] = 0x00,
+       .addr_bytes[3] = 0x00,
+       .addr_bytes[4] = 0x00,
+       .addr_bytes[5] = 0x00,
+};
+
+#define MAX_NUM_MAC_ADDRESS 16
+struct ether_addr link_hw_addr[MAX_NUM_MAC_ADDRESS] = {
+{.addr_bytes = {0x90, 0xe2, 0xba, 0x54, 0x67, 0xc8} },
+{.addr_bytes = {0x90, 0xe2, 0xba, 0x54, 0x67, 0xc9} },
+{.addr_bytes = {0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11} },
+{.addr_bytes = {0x12, 0x13, 0x14, 0x15, 0x16, 0x17} },
+{.addr_bytes = {0x22, 0x33, 0x44, 0x55, 0x66, 0x77} },
+{.addr_bytes = {0x12, 0x13, 0x14, 0x15, 0x16, 0x17} },
+{.addr_bytes = {0x22, 0x33, 0x44, 0x55, 0x66, 0x77} },
+{.addr_bytes = {0x90, 0xe2, 0xba, 0x54, 0x67, 0xc9} },
+{.addr_bytes = {0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11} },
+{.addr_bytes = {0x12, 0x13, 0x14, 0x15, 0x16, 0x17} },
+{.addr_bytes = {0x22, 0x33, 0x44, 0x55, 0x66, 0x77} },
+{.addr_bytes = {0x12, 0x13, 0x14, 0x15, 0x16, 0x17} },
+{.addr_bytes = {0x22, 0x33, 0x44, 0x55, 0x66, 0x77} },
+{.addr_bytes = {0x12, 0x13, 0x14, 0x15, 0x16, 0x17} },
+{.addr_bytes = {0x22, 0x33, 0x44, 0x55, 0x66, 0x77} },
+{.addr_bytes = {0x18, 0x19, 0x1a, 0x1b, 0xcd, 0xef} }
+};
+
+struct ether_addr *get_link_hw_addr(uint8_t out_port)
+{
+       return &link_hw_addr[out_port];
+}
+
+void request_arp(uint8_t port_id, uint32_t ip)
+{
+
+       struct ether_hdr *eth_h;
+       struct arp_hdr *arp_h;
+
+       l2_phy_interface_t *link;
+       link = ifm_get_port(port_id);
+       struct rte_mbuf *arp_pkt = lib_arp_pkt;
+
+       if (arp_pkt == NULL) {
+               if (ARPICMP_DEBUG)
+                       RTE_LOG(INFO, LIBARP,
+                               "Error allocating arp_pkt rte_mbuf\n");
+               return;
+       }
+
+       eth_h = rte_pktmbuf_mtod(arp_pkt, struct ether_hdr *);
+
+       ether_addr_copy(&broadcast_ether_addr, &eth_h->d_addr);
+       ether_addr_copy((struct ether_addr *)
+                       &link->macaddr[0], &eth_h->s_addr);
+       eth_h->ether_type = CHECK_ENDIAN_16(ETHER_TYPE_ARP);
+
+       arp_h = (struct arp_hdr *)((char *)eth_h + sizeof(struct ether_hdr));
+       arp_h->arp_hrd = CHECK_ENDIAN_16(ARP_HRD_ETHER);
+       arp_h->arp_pro = CHECK_ENDIAN_16(ETHER_TYPE_IPv4);
+       arp_h->arp_hln = ETHER_ADDR_LEN;
+       arp_h->arp_pln = sizeof(uint32_t);
+       arp_h->arp_op = CHECK_ENDIAN_16(ARP_OP_REQUEST);
+
+       ether_addr_copy((struct ether_addr *)
+                       &link->macaddr[0], &arp_h->arp_data.arp_sha);
+       if (link && link->ipv4_list) {
+               arp_h->arp_data.arp_sip =
+                               (((ipv4list_t *) (link->ipv4_list))->ipaddr);
+       }
+       ether_addr_copy(&null_ether_addr, &arp_h->arp_data.arp_tha);
+       arp_h->arp_data.arp_tip = rte_cpu_to_be_32(ip);
+       if (ARPICMP_DEBUG)
+               RTE_LOG(INFO, LIBARP, "arp tip:%x arp sip :%x\n",
+                       arp_h->arp_data.arp_tip, arp_h->arp_data.arp_sip);
+       // mmcd changed length from 60 to 42 - real length of arp request, no padding on ethernet needed - looks now like linux arp
+       arp_pkt->pkt_len = 42;
+       arp_pkt->data_len = 42;
+
+       if (ARPICMP_DEBUG) {
+               RTE_LOG(INFO, LIBARP, "Sending arp request\n");
+               print_mbuf("TX", port_id, arp_pkt, __LINE__);
+       }
+       if (link)
+               link->transmit_single_pkt(link, arp_pkt);
+}
+
+struct rte_mbuf *request_echo(uint32_t port_id, uint32_t ip)
+{
+       struct ether_hdr *eth_h;
+       struct ipv4_hdr *ip_h;
+       struct icmp_hdr *icmp_h;
+       l2_phy_interface_t *port = ifm_get_port(port_id);
+
+       struct rte_mbuf *icmp_pkt = lib_arp_pkt;
+       if (icmp_pkt == NULL) {
+               if (ARPICMP_DEBUG)
+                       RTE_LOG(INFO, LIBARP,
+                               "Error allocating icmp_pkt rte_mbuf\n");
+               return NULL;
+       }
+
+       eth_h = rte_pktmbuf_mtod(icmp_pkt, struct ether_hdr *);
+
+       ip_h = (struct ipv4_hdr *)((char *)eth_h + sizeof(struct ether_hdr));
+       icmp_h = (struct icmp_hdr *)((char *)ip_h + sizeof(struct ipv4_hdr));
+
+       ip_h->version_ihl = IP_VHL_DEF;
+       ip_h->type_of_service = 0;
+       ip_h->total_length =
+                       rte_cpu_to_be_16(sizeof(struct ipv4_hdr) + sizeof(struct icmp_hdr));
+       ip_h->packet_id = 0xaabb;
+       ip_h->fragment_offset = 0x0000;
+       ip_h->time_to_live = 64;
+       ip_h->next_proto_id = IPPROTO_ICMP;
+       if (port && port->ipv4_list)
+               ip_h->src_addr =
+                               rte_cpu_to_be_32(((ipv4list_t *) port->ipv4_list)->ipaddr);
+       ip_h->dst_addr = rte_cpu_to_be_32(ip);
+
+       ip_h->hdr_checksum = 0;
+       ip_h->hdr_checksum = rte_ipv4_cksum(ip_h);
+
+       icmp_h->icmp_type = IP_ICMP_ECHO_REQUEST;
+       icmp_h->icmp_code = 0;
+       icmp_h->icmp_ident = 0xdead;
+       icmp_h->icmp_seq_nb = 0xbeef;
+
+       icmp_h->icmp_cksum = ~rte_raw_cksum(icmp_h, sizeof(struct icmp_hdr));
+
+       icmp_pkt->pkt_len =
+                       sizeof(struct ether_hdr) + sizeof(struct ipv4_hdr) +
+                       sizeof(struct icmp_hdr);
+       icmp_pkt->data_len = icmp_pkt->pkt_len;
+
+       print_mbuf("TX", 0, icmp_pkt, __LINE__);
+
+       return icmp_pkt;
+}
+
+#if 0
+/**
+ * Function to send ICMP dest unreachable msg
+ *
+ */
+struct rte_mbuf *send_icmp_dest_unreachable_msg(uint32_t src_ip,
+                                               uint32_t dest_ip)
+{
+       struct ether_hdr *eth_h;
+       struct ipv4_hdr *ip_h;
+       struct icmp_hdr *icmp_h;
+       struct rte_mbuf *icmp_pkt = lib_arp_pkt;
+
+       if (icmp_pkt == NULL) {
+               if (ARPICMP_DEBUG)
+                       RTE_LOG(INFO, LIBARP,
+                               "Error allocating icmp_pkt rte_mbuf\n");
+               return NULL;
+       }
+
+       eth_h = rte_pktmbuf_mtod(icmp_pkt, struct ether_hdr *);
+       ip_h = (struct ipv4_hdr *)((char *)eth_h + sizeof(struct ether_hdr));
+       icmp_h = (struct icmp_hdr *)((char *)ip_h + sizeof(struct ipv4_hdr));
+
+       ip_h->version_ihl = IP_VHL_DEF;
+       ip_h->type_of_service = 0;
+       ip_h->total_length =
+                       rte_cpu_to_be_16(sizeof(struct ipv4_hdr) + sizeof(struct icmp_hdr));
+       ip_h->packet_id = 0xaabb;
+       ip_h->fragment_offset = 0x0000;
+       ip_h->time_to_live = 64;
+       ip_h->next_proto_id = 1;
+
+       ip_h->dst_addr = rte_bswap32(dest_ip);
+       ip_h->src_addr = rte_bswap32(src_ip);
+
+       ip_h->hdr_checksum = 0;
+       ip_h->hdr_checksum = rte_ipv4_cksum(ip_h);
+
+       icmp_h->icmp_type = 3;  /* Destination Unreachable */
+       icmp_h->icmp_code = 13; /* Communication administratively prohibited */
+
+       icmp_h->icmp_cksum = ~rte_raw_cksum(icmp_h, sizeof(struct icmp_hdr));
+
+       icmp_pkt->pkt_len = sizeof(struct ether_hdr) + sizeof(struct ipv4_hdr) +
+                       sizeof(struct icmp_hdr);
+       icmp_pkt->data_len = icmp_pkt->pkt_len;
+
+       return icmp_pkt;
+}
+#endif
+void
+process_arpicmp_pkt_parse(struct rte_mbuf **pkt, uint16_t pkt_num,
+                               uint64_t pkt_mask, l2_phy_interface_t *port)
+{
+       RTE_SET_USED(pkt_num);
+       if (ARPICMP_DEBUG)
+               RTE_LOG(INFO, LIBARP,
+                       "============ARP ENTRY================\n");
+       if (pkt_mask) {
+               if (ARPICMP_DEBUG)
+                       RTE_LOG(INFO, LIBARP,
+                               "============ARP PROCESS================\n");
+       }
+
+       uint64_t pkts_for_process = pkt_mask;
+       for (; pkts_for_process;) {
+/**< process only valid packets. */
+               uint8_t pos = (uint8_t) __builtin_ctzll(pkts_for_process);
+               uint64_t pkts_mask = 1LLU << pos;    /** <bitmask representing only this packet. */
+               pkts_for_process &= ~pkts_mask;                         /** <remove this packet from the mask. */
+               process_arpicmp_pkt(pkt[pos], port);
+       }
+
+}
+
+void process_arpicmp_pkt(struct rte_mbuf *pkt, l2_phy_interface_t *port)
+{
+       uint8_t in_port_id = pkt->port;
+       struct ether_hdr *eth_h;
+       struct arp_hdr *arp_h;
+       struct ipv4_hdr *ip_h;
+       struct icmp_hdr *icmp_h;
+
+       uint32_t cksum;
+       uint32_t ip_addr;
+
+       uint32_t req_tip;
+
+       eth_h = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+
+       if (eth_h->ether_type == rte_cpu_to_be_16(ETHER_TYPE_ARP)) {
+               if (ARPICMP_DEBUG)
+                       RTE_LOG(INFO, LIBARP, "%s, portid %u. Line %d\n\r",
+                               __FUNCTION__, port->pmdid, __LINE__);
+               arp_h =
+                               (struct arp_hdr *)((char *)eth_h +
+                                                        sizeof(struct ether_hdr));
+               if (CHECK_ENDIAN_16(arp_h->arp_hrd) != ARP_HRD_ETHER)
+                       RTE_LOG(INFO, LIBARP,
+                               "Invalid hardware format of hardware address - not processing ARP req\n");
+               else if (CHECK_ENDIAN_16(arp_h->arp_pro) != ETHER_TYPE_IPv4)
+                       RTE_LOG(INFO, LIBARP,
+                               "Invalid protocol address format - not processing ARP req\n");
+               else if (arp_h->arp_hln != 6)
+                       RTE_LOG(INFO, LIBARP,
+                               "Invalid hardware address length - not processing ARP req\n");
+               else if (arp_h->arp_pln != 4)
+                       RTE_LOG(INFO, LIBARP,
+                               "Invalid protocol address length - not processing ARP req\n");
+               else {
+                       if (port->ipv4_list == NULL) {
+                               RTE_LOG(INFO, LIBARP,
+                                       "Ports IPV4 List is NULL.. Unable to Process\n");
+                               return;
+                       }
+
+                       if (arp_h->arp_data.arp_tip !=
+                                       ((ipv4list_t *) (port->ipv4_list))->ipaddr) {
+                               if (arp_h->arp_data.arp_tip == arp_h->arp_data.arp_sip) {
+                                       populate_arp_entry(
+                                                       (struct ether_addr *)&arp_h->arp_data.arp_sha,
+                                                       rte_cpu_to_be_32(arp_h->arp_data.arp_sip),
+                                                       in_port_id,
+                                                       DYNAMIC_ARP);
+
+                               } else {
+                                       RTE_LOG(INFO, LIBARP,"ARP requested IP address mismatches interface IP - discarding\n");
+                               }
+                       }
+                       /// revise conditionals to allow processing of requests with target ip = this ip and
+                       //                               processing of replies to destination ip = this ip
+                       else if (arp_h->arp_op ==
+                                rte_cpu_to_be_16(ARP_OP_REQUEST)) {
+                               if (ARPICMP_DEBUG) {
+                                       RTE_LOG(INFO, LIBARP,
+                                               "%s, portid %u. Line %d\n\r",
+                                               __FUNCTION__, port->pmdid,
+                                               __LINE__);
+
+                                       RTE_LOG(INFO, LIBARP,
+                                               "arp_op %d, ARP_OP_REQUEST %d\n",
+                                               arp_h->arp_op,
+                                               rte_cpu_to_be_16
+                                               (ARP_OP_REQUEST));
+                                       print_mbuf("RX", in_port_id, pkt,
+                                                        __LINE__);
+                               }
+
+                               populate_arp_entry((struct ether_addr *)
+                                                        &arp_h->arp_data.arp_sha,
+                                                        rte_cpu_to_be_32
+                                                        (arp_h->arp_data.arp_sip),
+                                                        in_port_id, DYNAMIC_ARP);
+
+                               /*build reply */
+                               req_tip = arp_h->arp_data.arp_tip;
+                               ether_addr_copy(&eth_h->s_addr, &eth_h->d_addr);
+                               ether_addr_copy((struct ether_addr *)&port->macaddr[0], &eth_h->s_addr);  /**< set sender mac address*/
+                               arp_h->arp_op = rte_cpu_to_be_16(ARP_OP_REPLY);
+                               ether_addr_copy(&eth_h->s_addr,
+                                               &arp_h->arp_data.arp_sha);
+                               arp_h->arp_data.arp_tip =
+                                               arp_h->arp_data.arp_sip;
+                               arp_h->arp_data.arp_sip = req_tip;
+                               ether_addr_copy(&eth_h->d_addr,
+                                               &arp_h->arp_data.arp_tha);
+
+                               if (ARPICMP_DEBUG)
+                                       print_mbuf("TX ARP REPLY PKT",
+                                                        port->pmdid, pkt, __LINE__);
+                               port->transmit_bulk_pkts(port, &pkt, 1);
+                               if (ARPICMP_DEBUG)
+                                       print_mbuf("TX", port->pmdid, pkt,
+                                                        __LINE__);
+
+                               return;
+                       } else if (arp_h->arp_op ==
+                                        rte_cpu_to_be_16(ARP_OP_REPLY)) {
+                               if (ARPICMP_DEBUG) {
+                                       RTE_LOG(INFO, LIBARP,
+                                               "ARP_OP_REPLY received");
+                                       print_mbuf("RX", port->pmdid, pkt,
+                                                        __LINE__);
+                               }
+                               populate_arp_entry((struct ether_addr *)
+                                                        &arp_h->arp_data.arp_sha,
+                                                        rte_bswap32(arp_h->
+                                                                                arp_data.arp_sip),
+                                                        in_port_id, DYNAMIC_ARP);
+
+                               return;
+                       } else {
+                               if (ARPICMP_DEBUG)
+                                       RTE_LOG(INFO, LIBARP,
+                                               "Invalid ARP opcode - not processing ARP req %x\n",
+                                               arp_h->arp_op);
+                       }
+               }
+
+               rte_pktmbuf_free(pkt);
+       } else {
+               ip_h =
+                               (struct ipv4_hdr *)((char *)eth_h +
+                                       sizeof(struct ether_hdr));
+               icmp_h =
+                               (struct icmp_hdr *)((char *)ip_h + sizeof(struct ipv4_hdr));
+
+               if (eth_h->ether_type == rte_cpu_to_be_16(ETHER_TYPE_IPv4)) {
+
+                       if (ip_h->next_proto_id != IPPROTO_ICMP) {
+                               if (ARPICMP_DEBUG) {
+                                       RTE_LOG(INFO, LIBARP,
+                                               "IP protocol ID is not set to ICMP - discarding\n");
+                               }
+                       } else if ((ip_h->version_ihl & 0xf0) != IP_VERSION_4) {
+                               if (ARPICMP_DEBUG) {
+                                       RTE_LOG(INFO, LIBARP,
+                                               "IP version other than 4 - discarding\n");
+                               }
+                       } else if ((ip_h->version_ihl & 0x0f) != IP_HDRLEN) {
+                               if (ARPICMP_DEBUG) {
+                                       RTE_LOG(INFO, LIBARP,
+                                               "Unknown IHL - discarding\n");
+                               }
+                       } else {
+                               if (icmp_h->icmp_type == IP_ICMP_ECHO_REQUEST
+                                               && icmp_h->icmp_code == 0) {
+                                       if (ARPICMP_DEBUG)
+                                               print_mbuf("RX", in_port_id,
+                                                                pkt, __LINE__);
+
+                                       ip_addr = ip_h->src_addr;
+                                       ether_addr_copy(&eth_h->s_addr,
+                                                       &eth_h->d_addr);
+                                       ether_addr_copy((struct ether_addr *)
+                                                       &port->macaddr[0],
+                                                       &eth_h->s_addr);
+                                       if (ARPICMP_DEBUG)
+                                               RTE_LOG(INFO, LIBARP,
+                                                       "%s, portid %u. Line %d\n\r",
+                                                       __FUNCTION__,
+                                                       port->pmdid, __LINE__);
+
+                                       if (is_multicast_ipv4_addr
+                                                       (ip_h->dst_addr)) {
+                                               uint32_t ip_src;
+
+                                               ip_src =
+                                                               rte_be_to_cpu_32(ip_addr);
+                                               if ((ip_src & 0x00000003) == 1)
+                                                       ip_src =
+                                                                       (ip_src &
+                                                                        0xFFFFFFFC) |
+                                                                       0x00000002;
+                                               else
+                                                       ip_src =
+                                                                       (ip_src &
+                                                                        0xFFFFFFFC) |
+                                                                       0x00000001;
+                                               ip_h->src_addr =
+                                                               rte_cpu_to_be_32(ip_src);
+                                               ip_h->dst_addr = ip_addr;
+
+                                               ip_h->hdr_checksum = 0;
+                                               ip_h->hdr_checksum =
+                                                               ~rte_raw_cksum(ip_h,
+                                                                        sizeof(struct
+                                                                               ipv4_hdr));
+                                       } else {
+                                               if (ARPICMP_DEBUG)
+                                                       RTE_LOG(INFO, LIBARP,
+                                                               "%s, portid %u. Line %d\n\r",
+                                                               __FUNCTION__,
+                                                               port->pmdid,
+                                                               __LINE__);
+                                               ip_h->src_addr = ip_h->dst_addr;
+                                               ip_h->dst_addr = ip_addr;
+                                       }
+
+                                       icmp_h->icmp_type = IP_ICMP_ECHO_REPLY;
+                                       cksum = ~icmp_h->icmp_cksum & 0xffff;
+                                       cksum +=
+                                                       ~htons(IP_ICMP_ECHO_REQUEST << 8) &
+                                                       0xffff;
+                                       cksum += htons(IP_ICMP_ECHO_REPLY << 8);
+                                       cksum =
+                                                       (cksum & 0xffff) + (cksum >> 16);
+                                       cksum =
+                                                       (cksum & 0xffff) + (cksum >> 16);
+                                       icmp_h->icmp_cksum = ~cksum;
+
+                                       if (ARPICMP_DEBUG)
+                                               print_mbuf
+                                                               ("TX ICMP ECHO REPLY PKT",
+                                                                in_port_id, pkt, __LINE__);
+                                       port->transmit_bulk_pkts(port, &pkt, 1);
+                                       if (ARPICMP_DEBUG)
+                                               print_mbuf("TX", port->pmdid,
+                                                                pkt, __LINE__);
+
+                                       return;
+                               } else if (icmp_h->icmp_type ==
+                                                IP_ICMP_ECHO_REPLY
+                                                && icmp_h->icmp_code == 0) {
+                                       if (ARPICMP_DEBUG)
+                                               print_mbuf("RX", in_port_id,
+                                                                pkt, __LINE__);
+
+                                       struct arp_key_ipv4 arp_key;
+                                       arp_key.port_id = in_port_id;
+                                       arp_key.ip =
+                                                       rte_bswap32(ip_h->src_addr);
+                                       arp_key.filler1 = 0;
+                                       arp_key.filler2 = 0;
+                                       arp_key.filler3 = 0;
+
+                                       struct arp_entry_data *arp_entry =
+                                                       retrieve_arp_entry(arp_key);
+                                       if (arp_entry == NULL) {
+                                               if (ARPICMP_DEBUG)
+                                                       RTE_LOG(INFO, LIBARP,
+                                                               "Received unsolicited ICMP echo reply from ip%x, port %d\n",
+                                                               arp_key.ip,
+                                                               arp_key.port_id);
+                                               return;
+                                       }
+                                       arp_entry->status = COMPLETE;
+                               }
+                       }
+               }
+
+               rte_pktmbuf_free(pkt);
+       }
+}
+
+/* int
+ * inet_pton(af, src, dst)
+ *      convert from presentation format (which usually means ASCII printable)
+ *      to network format (which is usually some kind of binary format).
+ * return:
+ *      1 if the address was valid for the specified address family
+ *      0 if the address wasn't valid (`dst' is untouched in this case)
+ *      -1 if some other error occurred (`dst' is untouched in this case, too)
+ * author:
+ *      Paul Vixie, 1996.
+ */
+static int my_inet_pton_ipv6(int af, const char *src, void *dst)
+{
+       switch (af) {
+       case AF_INET:
+               return inet_pton_ipv4(src, dst);
+       case AF_INET6:
+               return inet_pton_ipv6(src, dst);
+       default:
+               errno = EAFNOSUPPORT;
+               return -1;
+       }
+       /* NOTREACHED */
+}
+
+/* int
+ * inet_pton_ipv4(src, dst)
+ *      like inet_aton() but without all the hexadecimal and shorthand.
+ * return:
+ *      1 if `src' is a valid dotted quad, else 0.
+ * notice:
+ *      does not touch `dst' unless it's returning 1.
+ * author:
+ *      Paul Vixie, 1996.
+ */
+static int inet_pton_ipv4(const char *src, unsigned char *dst)
+{
+       static const char digits[] = "0123456789";
+       int saw_digit, octets, ch;
+       unsigned char tmp[INADDRSZ], *tp;
+
+       saw_digit = 0;
+       octets = 0;
+       *(tp = tmp) = 0;
+       while ((ch = *src++) != '\0') {
+               const char *pch;
+
+               pch = strchr(digits, ch);
+               if (pch != NULL) {
+                       unsigned int new = *tp * 10 + (pch - digits);
+
+                       if (new > 255)
+                               return 0;
+                       if (!saw_digit) {
+                               if (++octets > 4)
+                                       return 0;
+                               saw_digit = 1;
+                       }
+                       *tp = (unsigned char)new;
+               } else if (ch == '.' && saw_digit) {
+                       if (octets == 4)
+                               return 0;
+                       *++tp = 0;
+                       saw_digit = 0;
+               } else
+                       return 0;
+       }
+       if (octets < 4)
+               return 0;
+
+       memcpy(dst, tmp, INADDRSZ);
+       return 1;
+}
+
+/* int
+ * inet_pton_ipv6(src, dst)
+ *      convert presentation level address to network order binary form.
+ * return:
+ *      1 if `src' is a valid [RFC1884 2.2] address, else 0.
+ * notice:
+ *      (1) does not touch `dst' unless it's returning 1.
+ *      (2) :: in a full address is silently ignored.
+ * credit:
+ *      inspired by Mark Andrews.
+ * author:
+ *      Paul Vixie, 1996.
+ */
+static int inet_pton_ipv6(const char *src, unsigned char *dst)
+{
+       static const char xdigits_l[] = "0123456789abcdef",
+                       xdigits_u[] = "0123456789ABCDEF";
+       unsigned char tmp[IN6ADDRSZ], *tp = 0, *endp = 0, *colonp = 0;
+       const char *xdigits = 0, *curtok = 0;
+       int ch = 0, saw_xdigit = 0, count_xdigit = 0;
+       unsigned int val = 0;
+       unsigned int dbloct_count = 0;
+
+       memset((tp = tmp), '\0', IN6ADDRSZ);
+       endp = tp + IN6ADDRSZ;
+       colonp = NULL;
+       /* Leading :: requires some special handling. */
+       if (*src == ':')
+               if (*++src != ':')
+                       return 0;
+       curtok = src;
+       saw_xdigit = count_xdigit = 0;
+       val = 0;
+
+       while ((ch = *src++) != '\0') {
+               const char *pch;
+
+               pch = strchr((xdigits = xdigits_l), ch);
+               if (pch == NULL)
+                       pch = strchr((xdigits = xdigits_u), ch);
+               if (pch != NULL) {
+                       if (count_xdigit >= 4)
+                               return 0;
+                       val <<= 4;
+                       val |= (pch - xdigits);
+                       if (val > 0xffff)
+                               return 0;
+                       saw_xdigit = 1;
+                       count_xdigit++;
+                       continue;
+               }
+               if (ch == ':') {
+                       curtok = src;
+                       if (!saw_xdigit) {
+                               if (colonp)
+                                       return 0;
+                               colonp = tp;
+                               continue;
+                       } else if (*src == '\0') {
+                               return 0;
+                       }
+                       if (tp + sizeof(int16_t) > endp)
+                               return 0;
+                       *tp++ = (unsigned char)((val >> 8) & 0xff);
+                       *tp++ = (unsigned char)(val & 0xff);
+                       saw_xdigit = 0;
+                       count_xdigit = 0;
+                       val = 0;
+                       dbloct_count++;
+                       continue;
+               }
+               if (ch == '.' && ((tp + INADDRSZ) <= endp) &&
+                               inet_pton_ipv4(curtok, tp) > 0) {
+                       tp += INADDRSZ;
+                       saw_xdigit = 0;
+                       dbloct_count += 2;
+                       break;  /* '\0' was seen by inet_pton4(). */
+               }
+               return 0;
+       }
+       if (saw_xdigit) {
+               if (tp + sizeof(int16_t) > endp)
+                       return 0;
+               *tp++ = (unsigned char)((val >> 8) & 0xff);
+               *tp++ = (unsigned char)(val & 0xff);
+               dbloct_count++;
+       }
+       if (colonp != NULL) {
+               /* if we already have 8 double octets, having a colon means error */
+               if (dbloct_count == 8)
+                       return 0;
+
+               /*
+                * Since some memmove()'s erroneously fail to handle
+                * overlapping regions, we'll do the shift by hand.
+                */
+               const int n = tp - colonp;
+               int i;
+
+               for (i = 1; i <= n; i++) {
+                       endp[-i] = colonp[n - i];
+                       colonp[n - i] = 0;
+               }
+               tp = endp;
+       }
+       if (tp != endp)
+               return 0;
+       memcpy(dst, tmp, IN6ADDRSZ);
+       return 1;
+}
+
+static int arp_parse_args(struct pipeline_params *params)
+{
+       uint32_t arp_route_tbl_present = 0;
+       uint32_t nd_route_tbl_present = 0;
+       uint32_t ports_mac_list_present = 0;
+       uint32_t numArg;
+       uint32_t n_vnf_threads_present = 0;
+
+       uint32_t pktq_in_prv_present = 0;
+       uint32_t prv_to_pub_map_present = 0;
+
+       uint8_t n_prv_in_port = 0;
+       int i;
+       for (i = 0; i < PIPELINE_MAX_PORT_IN; i++) {
+               in_port_dir_a[i] = 0;   //make all RX ports ingress initially
+               prv_to_pub_map[i] = 0xff;
+               pub_to_prv_map[i] = 0xff;
+       }
+
+       RTE_SET_USED(ports_mac_list_present);
+       RTE_SET_USED(nd_route_tbl_present);
+       RTE_SET_USED(arp_route_tbl_present);
+       for (numArg = 0; numArg < params->n_args; numArg++) {
+               char *arg_name = params->args_name[numArg];
+               char *arg_value = params->args_value[numArg];
+
+               /* arp timer expiry */
+               if (strcmp(arg_name, "arp_timer_expiry") == 0) {
+                       arp_timeout = atoi(arg_value);
+               }
+
+               /* pktq_in_prv */
+               if (strcmp(arg_name, "pktq_in_prv") == 0) {
+                       if (pktq_in_prv_present) {
+                               printf
+                                               ("Duplicate pktq_in_prv ... parse failed..\n\n");
+                               return -1;
+                       }
+                       pktq_in_prv_present = 1;
+
+                       int rxport = 0, j = 0;
+                       char phy_port_num[5];
+                       char *token = strtok(arg_value, "RXQ");
+                       while (token) {
+                               j = 0;
+                               while ((j < 4) && (token[j] != '.')) {
+                                       phy_port_num[j] = token[j];
+                                       j++;
+                               }
+                               phy_port_num[j] = '\0';
+                               rxport = atoi(phy_port_num);
+                               prv_in_port_a[n_prv_in_port++] = rxport;
+                               if (rxport < 0)
+                                       rxport = 0;
+                               printf
+                                               ("token: %s, phy_port_str: %s, phy_port_num %d\n",
+                                                token, phy_port_num, rxport);
+                               prv_in_port_a[n_prv_in_port++] = rxport;
+                               if(rxport < PIPELINE_MAX_PORT_IN)
+                               in_port_dir_a[rxport] = 1;      // set rxport egress
+                               token = strtok(NULL, "RXQ");
+                       }
+
+                       if (n_prv_in_port == 0) {
+                               printf
+                                               ("VNF common parse error - no prv RX phy port\n");
+                               return -1;
+                       }
+                       continue;
+               }
+
+               /* prv_to_pub_map */
+               if (strcmp(arg_name, "prv_to_pub_map") == 0) {
+                       if (prv_to_pub_map_present) {
+                               printf
+                                               ("Duplicated prv_to_pub_map ... parse failed ...\n");
+                               return -1;
+                       }
+                       prv_to_pub_map_present = 1;
+
+                       int rxport = 0, txport = 0, j = 0, k = 0;
+                       char rx_phy_port_num[5];
+                       char tx_phy_port_num[5];
+                       char *token = strtok(arg_value, "(");
+                       while (token) {
+                               j = 0;
+                               while ((j < 4) && (token[j] != ',')) {
+                                       rx_phy_port_num[j] = token[j];
+                                       j++;
+                               }
+                               rx_phy_port_num[j] = '\0';
+                               rxport = atoi(rx_phy_port_num);
+                               if (rxport < 0)
+                                       rxport = 0;
+
+                               j++;
+                               k = 0;
+                               while ((k < 4) && (token[j + k] != ')')) {
+                                       tx_phy_port_num[k] = token[j + k];
+                                       k++;
+                               }
+                               tx_phy_port_num[k] = '\0';
+                               txport = atoi(tx_phy_port_num);
+                               if (txport < 0)
+                                       txport = 0;
+
+                               RTE_LOG(INFO, LIBARP, "token: %s,"
+                                       "rx_phy_port_str: %s, phy_port_num %d,"
+                                       "tx_phy_port_str: %s, tx_phy_port_num %d\n",
+                                       token, rx_phy_port_num, rxport,
+                                       tx_phy_port_num, txport);
+
+                               if ((rxport >= PIPELINE_MAX_PORT_IN) ||
+                                               (txport >= PIPELINE_MAX_PORT_IN) ||
+                                               (in_port_dir_a[rxport] != 1)) {
+                                       printf
+                                                       ("CG-NAPT parse error - incorrect prv-pub translation. Rx %d, Tx %d, Rx Dir %d\n",
+                                                        rxport, txport,
+                                                        in_port_dir_a[rxport]);
+                                       return -1;
+                               }
+
+                               prv_to_pub_map[rxport] = txport;
+                               pub_to_prv_map[txport] = rxport;
+                               token = strtok(NULL, "(");
+                       }
+
+                       continue;
+               }
+               //n_vnf_threads = 3
+               if (strcmp(arg_name, "n_vnf_threads") == 0) {
+                       if (n_vnf_threads_present)
+                               return -1;
+                       n_vnf_threads_present = 1;
+                       trim(arg_value);
+                       num_vnf_threads = atoi(arg_value);
+                       if (num_vnf_threads <= 0) {
+                               RTE_LOG(INFO, LIBARP,
+                                       "n_vnf_threads is invalid\n");
+                               return -1;
+                       }
+                       RTE_LOG(INFO, LIBARP, "n_vnf_threads: 0x%x\n",
+                               num_vnf_threads);
+               }
+
+               /* lib_arp_debug */
+               if (strcmp(arg_name, "lib_arp_debug") == 0) {
+                       ARPICMP_DEBUG = atoi(arg_value);
+
+                       continue;
+               }
+
+               /* ports_mac_list */
+               if (strcmp(arg_name, "ports_mac_list") == 0) {
+                       ports_mac_list_present = 1;
+
+                       uint32_t i = 0, j = 0, k = 0, MAC_NUM_BYTES = 6;
+
+                       char byteStr[MAC_NUM_BYTES][3];
+                       uint32_t byte[MAC_NUM_BYTES];
+
+                       char *token = strtok(arg_value, " ");
+                       while (token) {
+                               k = 0;
+                               for (i = 0; i < MAC_NUM_BYTES; i++) {
+                                       for (j = 0; j < 2; j++) {
+                                               byteStr[i][j] = token[k++];
+                                       }
+                                       byteStr[i][j] = '\0';
+                                       k++;
+                               }
+
+                               for (i = 0; i < MAC_NUM_BYTES; i++) {
+                                       byte[i] = strtoul(byteStr[i], NULL, 16);
+                               }
+
+                               if (ARPICMP_DEBUG) {
+                                       RTE_LOG(INFO, LIBARP, "token: %s",
+                                               token);
+                                       for (i = 0; i < MAC_NUM_BYTES; i++)
+                                               RTE_LOG(INFO, LIBARP,
+                                                       ", byte[%u] %u", i,
+                                                       byte[i]);
+                                       RTE_LOG(INFO, LIBARP, "\n");
+                               }
+                               //Populate the static arp_route_table
+                               for (i = 0; i < MAC_NUM_BYTES; i++)
+                                       link_hw_addr
+                                                       [link_hw_addr_array_idx].addr_bytes
+                                                       [i] = byte[i];
+
+                               link_hw_addr_array_idx++;
+                               token = strtok(NULL, " ");
+                       }
+
+                       continue;
+               }
+
+               /* arp_route_tbl */
+               if (strcmp(arg_name, "arp_route_tbl") == 0) {
+                       arp_route_tbl_present = 1;
+
+                       uint32_t dest_ip = 0, mask = 0, tx_port = 0, nh_ip =
+                                       0, i = 0, j = 0, k = 0, l = 0;
+                       uint32_t arp_route_tbl_str_max_len = 10;
+                       char dest_ip_str[arp_route_tbl_str_max_len];
+                       char mask_str[arp_route_tbl_str_max_len];
+                       char tx_port_str[arp_route_tbl_str_max_len];
+                       char nh_ip_str[arp_route_tbl_str_max_len];
+                       char *token = strtok(arg_value, "(");
+                       while (token) {
+                               i = 0;
+                               while ((i < (arp_route_tbl_str_max_len - 1))
+                                                        && (token[i] != ',')) {
+                                       dest_ip_str[i] = token[i];
+                                       i++;
+                               }
+                               dest_ip_str[i] = '\0';
+                               dest_ip = strtoul(dest_ip_str, NULL, 16);
+
+                               i++;
+                               j = 0;
+                               while ((j < (arp_route_tbl_str_max_len - 1))
+                                                        && (token[i + j] != ',')) {
+                                       mask_str[j] = token[i + j];
+                                       j++;
+                               }
+                               mask_str[j] = '\0';
+                               mask = strtoul(mask_str, NULL, 16);
+
+                               j++;
+                               k = 0;
+                               while ((k < (arp_route_tbl_str_max_len - 1))
+                                                        && (token[i + j + k] != ',')) {
+                                       tx_port_str[k] = token[i + j + k];
+                                       k++;
+                               }
+                               tx_port_str[k] = '\0';
+                               tx_port = strtoul(tx_port_str, NULL, 16);       //atoi(tx_port_str);
+
+                               k++;
+                               l = 0;
+                               while ((l < (arp_route_tbl_str_max_len - 1))
+                                                        && (token[i + j + k + l] != ')')) {
+                                       nh_ip_str[l] = token[i + j + k + l];
+                                       l++;
+                               }
+                               nh_ip_str[l] = '\0';
+                               nh_ip = strtoul(nh_ip_str, NULL, 16);   //atoi(nh_ip_str);
+
+                               if (1) {
+                                       RTE_LOG(INFO, LIBARP, "token: %s, "
+                                               "dest_ip_str: %s, dest_ip %u, "
+                                               "mask_str: %s, mask %u, "
+                                               "tx_port_str: %s, tx_port %u, "
+                                               "nh_ip_str: %s, nh_ip %u\n",
+                                               token, dest_ip_str, dest_ip,
+                                               mask_str, mask, tx_port_str,
+                                               tx_port, nh_ip_str, nh_ip);
+                               }
+
+                               /*  if (tx_port >= params->n_ports_out)
+                                        {
+                                        RTE_LOG(INFO, LIBARP,"ARP-ICMP parse error - incorrect tx_port %d, max %d\n",
+                                        tx_port, params->n_ports_out);
+                                        return -1;
+                                        }
+                                */
+                               //Populate the static arp_route_table
+                               lib_arp_route_table[arp_route_tbl_index].ip =
+                                               dest_ip;
+                               lib_arp_route_table[arp_route_tbl_index].mask =
+                                               mask;
+                               lib_arp_route_table[arp_route_tbl_index].port =
+                                               tx_port;
+                               lib_arp_route_table[arp_route_tbl_index].nh =
+                                               nh_ip;
+                               arp_route_tbl_index++;
+                               token = strtok(NULL, "(");
+                       }
+
+                       continue;
+               }
+               /*ND IPv6 */
+               /* nd_route_tbl */
+               if (strcmp(arg_name, "nd_route_tbl") == 0) {
+                       nd_route_tbl_present = 1;
+
+                       uint8_t dest_ipv6[16], depth = 0, tx_port =
+                                       0, nh_ipv6[16], i = 0, j = 0, k = 0, l = 0;
+                       uint8_t nd_route_tbl_str_max_len = 128; //64;
+                       char dest_ipv6_str[nd_route_tbl_str_max_len];
+                       char depth_str[nd_route_tbl_str_max_len];
+                       char tx_port_str[nd_route_tbl_str_max_len];
+                       char nh_ipv6_str[nd_route_tbl_str_max_len];
+                       char *token = strtok(arg_value, "(");
+                       while (token) {
+                               i = 0;
+                               while ((i < (nd_route_tbl_str_max_len - 1))
+                                                        && (token[i] != ',')) {
+                                       dest_ipv6_str[i] = token[i];
+                                       i++;
+                               }
+                               dest_ipv6_str[i] = '\0';
+                               my_inet_pton_ipv6(AF_INET6, dest_ipv6_str,
+                                                       &dest_ipv6);
+
+                               i++;
+                               j = 0;
+                               while ((j < (nd_route_tbl_str_max_len - 1))
+                                                        && (token[i + j] != ',')) {
+                                       depth_str[j] = token[i + j];
+                                       j++;
+                               }
+                               depth_str[j] = '\0';
+                               //converting string char to integer
+                               int s;
+                               for (s = 0; depth_str[s] != '\0'; ++s)
+                                       depth = depth * 10 + depth_str[s] - '0';
+
+                               j++;
+                               k = 0;
+                               while ((k < (nd_route_tbl_str_max_len - 1))
+                                                        && (token[i + j + k] != ',')) {
+                                       tx_port_str[k] = token[i + j + k];
+                                       k++;
+                               }
+                               tx_port_str[k] = '\0';
+                               tx_port = strtoul(tx_port_str, NULL, 16);       //atoi(tx_port_str);
+
+                               k++;
+                               l = 0;
+                               while ((l < (nd_route_tbl_str_max_len - 1))
+                                                        && (token[i + j + k + l] != ')')) {
+                                       nh_ipv6_str[l] = token[i + j + k + l];
+                                       l++;
+                               }
+                               nh_ipv6_str[l] = '\0';
+                               my_inet_pton_ipv6(AF_INET6, nh_ipv6_str,
+                                                       &nh_ipv6);
+
+                               //Populate the static arp_route_table
+                               for (i = 0; i < 16; i++) {
+                                       lib_nd_route_table
+                                                       [nd_route_tbl_index].ipv6[i] =
+                                                       dest_ipv6[i];
+                                       lib_nd_route_table
+                                                       [nd_route_tbl_index].nhipv6[i] =
+                                                       nh_ipv6[i];
+                               }
+                               lib_nd_route_table[nd_route_tbl_index].depth =
+                                               depth;
+                               lib_nd_route_table[nd_route_tbl_index].port =
+                                               tx_port;
+
+                               nd_route_tbl_index++;
+                               token = strtok(NULL, "(");
+                       }
+
+                       continue;
+               }
+               /* any other */
+               //return -1;
+       }
+       /* Check that mandatory arguments are present */
+       /*
+                if ((arp_route_tbl_present == 0) || (ports_mac_list_present == 0)) {
+                RTE_LOG(INFO, LIBARP,"VNF common not all mandatory arguments are present\n");
+                RTE_LOG(INFO, LIBARP,"%d, %d \n",
+                arp_route_tbl_present, ports_mac_list_present);
+                return -1;
+                }
+        */
+
+       return 0;
+}
+
+void lib_arp_init(struct pipeline_params *params,
+                       __rte_unused struct app_params *app)
+{
+
+       RTE_LOG(INFO, LIBARP, "ARP initialization ...\n");
+
+       /* Parse arguments */
+       if (arp_parse_args(params)) {
+               RTE_LOG(INFO, LIBARP, "arp_parse_args failed ...\n");
+               return;
+       }
+
+       /* create the arp_icmp mbuf rx pool */
+       lib_arp_pktmbuf_tx_pool =
+                       rte_pktmbuf_pool_create("lib_arp_mbuf_tx_pool", NB_ARPICMP_MBUF, 32,
+                                               0, RTE_MBUF_DEFAULT_BUF_SIZE,
+                                               rte_socket_id());
+
+       if (lib_arp_pktmbuf_tx_pool == NULL) {
+               RTE_LOG(INFO, LIBARP, "ARP mbuf pool create failed.\n");
+               return;
+       }
+
+       lib_arp_pkt = rte_pktmbuf_alloc(lib_arp_pktmbuf_tx_pool);
+       if (lib_arp_pkt == NULL) {
+               RTE_LOG(INFO, LIBARP, "ARP lib_arp_pkt alloc failed.\n");
+               return;
+       }
+
+       arp_hash_params.socket_id = rte_socket_id();
+       arp_hash_params.entries = MAX_NUM_ARP_ENTRIES;
+       arp_hash_params.key_len = sizeof(struct arp_key_ipv4);
+       arp_hash_handle = rte_hash_create(&arp_hash_params);
+
+       if (arp_hash_handle == NULL) {
+               RTE_LOG(INFO, LIBARP,
+                       "ARP rte_hash_create failed. socket %d ... \n",
+                       arp_hash_params.socket_id);
+       } else {
+               RTE_LOG(INFO, LIBARP, "arp_hash_handle %p\n\n",
+                       (void *)arp_hash_handle);
+       }
+
+       /* Create port alloc buffer */
+
+       timer_mempool_arp = rte_mempool_create("timer_mempool_arp",
+                                                                timer_objs_mempool_count,
+                                                                sizeof(struct rte_timer),
+                                                                0, 0,
+                                                                NULL, NULL,
+                                                                NULL, NULL, rte_socket_id(), 0);
+       if (timer_mempool_arp == NULL) {
+               rte_panic("timer_mempool create error\n");
+       }
+       rte_timer_subsystem_init();
+       list_add_type(ETHER_TYPE_ARP, process_arpicmp_pkt_parse);
+
+       /* ND IPv6 */
+       nd_hash_params.socket_id = rte_socket_id();
+       nd_hash_params.entries = MAX_NUM_ND_ENTRIES;
+       nd_hash_params.key_len = sizeof(struct nd_key_ipv6);
+       nd_hash_handle = rte_hash_create(&nd_hash_params);
+       if (nd_hash_handle == NULL) {
+               RTE_LOG(INFO, LIBARP,
+                       "ND rte_hash_create failed. socket %d ... \n",
+                       nd_hash_params.socket_id);
+       } else {
+               RTE_LOG(INFO, LIBARP, "nd_hash_handle %p\n\n",
+                       (void *)nd_hash_handle);
+       }
+
+       return;
+}
+
+void arp_timer_callback(struct rte_timer *timer, void *arg)
+{
+       struct arp_timer_key *remove_key = (struct arp_timer_key *)arg;
+       if (ARPICMP_DEBUG)
+               RTE_LOG(INFO, LIBARP, "ARP TIMER callback : expire :%d\n",
+                       (int)timer->expire);
+       if (ARPICMP_DEBUG)
+               RTE_LOG(INFO, LIBARP,
+                       "Remove ARP Entry for IP :%d.%d.%d.%d , port %d\n",
+                       (remove_key->ip >> 24),
+                       ((remove_key->ip & 0x00ff0000) >> 16),
+                       ((remove_key->ip & 0x0000ff00) >> 8),
+                       ((remove_key->ip & 0x000000ff)), remove_key->port_id);
+       remove_arp_entry((uint32_t) remove_key->ip,
+                        (uint8_t) remove_key->port_id, arg);
+       return;
+}
+
+void nd_timer_callback(struct rte_timer *timer, void *arg)
+{
+       struct nd_timer_key *remove_key = (struct nd_timer_key *)arg;
+       if (ARPICMP_DEBUG)
+               RTE_LOG(INFO, LIBARP, "nd  time callback : expire :%d\n",
+                       (int)timer->expire);
+       remove_nd_entry_ipv6(remove_key->ipv6, remove_key->port_id);
+       return;
+}
+
+void create_arp_table(void)
+{
+
+       int i;
+       for (i = 0; i < MAX_ARP_DATA_ENTRY_TABLE; i++) {
+               populate_arp_entry((const struct ether_addr *)
+                                        &arp_entry_data_table[i].eth_addr,
+                                        arp_entry_data_table[i].ip,
+                                        (uint8_t) arp_entry_data_table[i].port,
+                                        STATIC_ARP);
+       }
+       print_arp_table();
+       return;
+}
+
+void create_nd_table(void)
+{
+
+       int i;
+       for (i = 0; i < MAX_ND_DATA_ENTRY_TABLE; i++) {
+               populate_nd_entry((const struct ether_addr *)
+                                       nd_entry_data_table[i].eth_addr,
+                                       nd_entry_data_table[i].ipv6,
+                                       (uint8_t) nd_entry_data_table[i].port,
+                                       STATIC_ND);
+       }
+       print_nd_table();
+       return;
+}
+
+void send_gratuitous_arp(l2_phy_interface_t *port)
+{
+       struct ether_hdr *eth_h;
+       struct arp_hdr *arp_h;
+
+       struct rte_mbuf *arp_pkt = lib_arp_pkt;
+
+       if (port == NULL) {
+               RTE_LOG(INFO, LIBARP, "PORT ID DOWN.. %s\n", __FUNCTION__);
+               return;
+
+       }
+
+       if (arp_pkt == NULL) {
+               if (ARPICMP_DEBUG)
+                       RTE_LOG(INFO, LIBARP,
+                               "Error allocating arp_pkt rte_mbuf\n");
+               return;
+       }
+
+       eth_h = rte_pktmbuf_mtod(arp_pkt, struct ether_hdr *);
+
+       ether_addr_copy(&broadcast_ether_addr, &eth_h->d_addr);
+       ether_addr_copy((struct ether_addr *)
+                       &port->macaddr[0], &eth_h->s_addr);
+       eth_h->ether_type = CHECK_ENDIAN_16(ETHER_TYPE_ARP);
+
+       arp_h = (struct arp_hdr *)((char *)eth_h + sizeof(struct ether_hdr));
+       arp_h->arp_hrd = CHECK_ENDIAN_16(ARP_HRD_ETHER);
+       arp_h->arp_pro = CHECK_ENDIAN_16(ETHER_TYPE_IPv4);
+       arp_h->arp_hln = ETHER_ADDR_LEN;
+       arp_h->arp_pln = sizeof(uint32_t);
+       arp_h->arp_op = CHECK_ENDIAN_16(ARP_OP_REQUEST);
+
+       ether_addr_copy((struct ether_addr *)
+                       &port->macaddr[0], &arp_h->arp_data.arp_sha);
+       if (port->ipv4_list == NULL) {
+               if (ARPICMP_DEBUG)
+                       RTE_LOG(INFO, LIBARP, "port->ipv4_list is NULL.. %s\n",
+                               __FUNCTION__);
+               return;
+       }
+       arp_h->arp_data.arp_sip = (((ipv4list_t *) (port->ipv4_list))->ipaddr);
+       ether_addr_copy(&null_ether_addr, &arp_h->arp_data.arp_tha);
+       //arp_h->arp_data.arp_tip = rte_cpu_to_be_32(ip);
+       arp_h->arp_data.arp_tip = 0;    //(((ipv4list_t *) (port->ipv4_list))->ipaddr);
+       //  RTE_LOG(INFO, LIBARP,"arp tip:%x arp sip :%x\n", arp_h->arp_data.arp_tip,
+       //arp_h->arp_data.arp_sip);
+       // mmcd changed length from 60 to 42 - real length of arp request, no padding on ethernet needed - looks now like linux arp
+       arp_pkt->pkt_len = 42;
+       arp_pkt->data_len = 42;
+
+       if (ARPICMP_DEBUG) {
+               RTE_LOG(INFO, LIBARP, "SENDING GRATUITOUS ARP REQUEST\n");
+               print_mbuf("TX", port->pmdid, arp_pkt, __LINE__);
+       }
+       port->transmit_single_pkt(port, arp_pkt);
+}
+
+void set_arpdebug(int flag)
+{
+       if (flag) {
+               RTE_LOG(INFO, LIBARP, "Debugs turned on\n\r");
+               ARPICMP_DEBUG = 1;
+               NDIPV6_DEBUG = 1;
+
+       } else {
+               RTE_LOG(INFO, LIBARP, "Debugs turned off\n\r");
+               ARPICMP_DEBUG = 0;
+               NDIPV6_DEBUG = 0;
+       }
+}
+
+void set_arptimeout(uint32_t timeout_val)
+{
+       if (timeout_val == 0) {
+               RTE_LOG(INFO, LIBARP, "Cannot be zero...\n\r");
+               return;
+       }
+       if (ARPICMP_DEBUG)
+               RTE_LOG(INFO, LIBARP,
+                       "set_arptimeout: arp_timeout %u, timeout_val %u\n\r",
+                       arp_timeout, timeout_val);
+       arp_timeout = timeout_val;
+       if (ARPICMP_DEBUG)
+               RTE_LOG(INFO, LIBARP, "set_arptimeout: arp_timeout %u\n\r",
+                       arp_timeout);
+}
diff --git a/common/VIL/l2l3_stack/lib_arp.h b/common/VIL/l2l3_stack/lib_arp.h
new file mode 100644 (file)
index 0000000..3387567
--- /dev/null
@@ -0,0 +1,506 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef __INCLUDE_LIB_ARP_H__
+#define __INCLUDE_LIB_ARP_H__
+
+#include <rte_pipeline.h>
+#include "rte_ether.h"
+#include "l2_proto.h"
+#include "app.h"
+
+#define ND_IPV6_ADDR_SIZE 16   /**< 16 Byte of IPv6 Address. */
+#define ND_IPV6_TIMER_EXPIRY 300  /**< in Seconds, Timer for ND IPv6 Expiry */
+#define ARP_TIMER_EXPIRY 1800   /**< in Seconds, TIMER for ARP Expiry */
+#define TIMER_MILLISECOND 1
+#define RTE_LOGTYPE_LIBARP RTE_LOGTYPE_USER1
+#define MAX_ND_RT_ENTRY 16
+#define MAX_ARP_RT_ENTRY 16
+
+/**
+* A structure for Route table entries of IPv4
+*/
+
+struct lib_arp_route_table_entry {
+       uint32_t ip;    /**< Ipv4 address*/
+       uint32_t mask;  /**< mask */
+       uint32_t port;  /**< Physical port */
+       uint32_t nh;    /**< next hop */
+};
+
+/**
+* A structure for Route table entires of IPv6
+*
+*/
+struct lib_nd_route_table_entry {
+       uint8_t ipv6[16];       /**< Ipv6 address */
+       uint8_t depth;          /**< Depth */
+       uint32_t port;          /**< Port */
+       uint8_t nhipv6[16];     /**< next hop Ipv6 */
+};
+
+extern struct lib_nd_route_table_entry lib_nd_route_table[MAX_ND_RT_ENTRY];
+extern struct lib_arp_route_table_entry lib_arp_route_table[MAX_ARP_RT_ENTRY];
+
+enum {
+       ARP_FOUND,
+       ARP_NOT_FOUND,
+       NH_NOT_FOUND,
+};
+
+enum arp_key_type {
+       ARP_IPV4,
+       ND_IPV6,
+};
+
+struct arp_key_ipv4 {
+       uint32_t ip;     /**< IP address */
+       uint8_t port_id; /**< Port id */
+       uint8_t filler1; /**< filler 1, for better hash key */
+       uint8_t filler2; /**< filler 2, for better hash key */
+       uint8_t filler3; /**< filler 3, for better hash key */
+};
+
+/**
+* IPv6
+*/
+struct nd_key_ipv6 {
+       uint8_t ipv6[ND_IPV6_ADDR_SIZE]; /**< 128 Bit of IPv6 Address*/
+       uint8_t port_id;                 /**< Port id */
+       uint8_t filler1;
+       uint8_t filler2;
+       uint8_t filler3;
+};
+
+/**
+* Arp Key
+*/
+struct arp_key {
+       enum arp_key_type type;
+       union {
+               struct arp_key_ipv4 ipv4;
+       } key;  /**< Key of type arp key Ipv4 */
+};
+
+/**
+* call back function parameter pair remove nd entry
+*
+*/
+
+struct nd_timer_key {
+       uint8_t ipv6[ND_IPV6_ADDR_SIZE];   /**< IPv6 address */
+       uint8_t port_id;                 /**< Port id */
+} __rte_cache_aligned;
+
+/**
+* call back function parameter remove arp entry
+*
+*/
+struct arp_timer_key {
+       uint32_t ip;     /**< Ip address */
+       uint8_t port_id; /**< Port id */
+} __rte_cache_aligned;
+
+extern uint32_t ARPICMP_DEBUG;
+
+#define COMPLETE   1 /**< ARP entry populated and echo reply recieved. */
+#define INCOMPLETE 0 /**< ARP entry populated and either awaiting echo reply or stale entry. */
+
+extern uint32_t NDIPV6_DEBUG;  /**< ND IPv6 */
+
+#define ICMPv6_COMPLETE   1 /**< ICMPv6 entry populated and echo reply recieved. */
+#define ICMPv6_INCOMPLETE 0 /**< ICMPv6 entry populated and either awaiting echo reply or stale entry. */
+#define STATIC_ARP 1                   /**< Static ARP Entry. */
+#define DYNAMIC_ARP 0                  /**< Dynamic ARP Entry. */
+#define STATIC_ND 1                    /**< Static ND Entry. */
+#define DYNAMIC_ND 0                   /**< Dynamic ND Entry. */
+
+/**
+* A structure is used to defined the ARP entry data
+* This structure is used as a input parameters for entry of ARP data
+*/
+
+struct arp_entry_data {
+       struct ether_addr eth_addr; /**< ethernet address */
+       uint32_t ip;                            /**< IP address */
+       uint8_t port;                           /**< Port */
+       uint8_t status;                         /**< Status of entry */
+       uint8_t mode;                           /**< Mode */
+       uint8_t retry_count;                    /**< retry count for ARP*/
+       struct rte_timer *timer;    /**< Timer Associated with ARP*/
+       struct arp_timer_key *timer_key;
+} __attribute__ ((packed));
+
+/**
+* A structure is used to defined the table for arp entry data
+* This structure is used to maintain the arp entry data
+*/
+
+struct table_arp_entry_data {
+       uint8_t eth_addr[6];     /**< Ethernet address */
+       uint8_t port;            /**< port */
+       uint8_t status;          /**< status of entry */
+       uint32_t ip;             /**< Ip address */
+} __attribute__ ((packed));
+
+/**
+* A structure is used to define the ND entry data for IPV6
+* This structure is used as a input parameters  for ND entry data
+*/
+
+struct nd_entry_data {
+       struct ether_addr eth_addr;             /**< Ethernet address */
+       uint8_t port;                           /**< port */
+       uint8_t status;                         /**< statusof the entry */
+       uint8_t mode;                           /**< Mode */
+       uint8_t ipv6[ND_IPV6_ADDR_SIZE];  /**< Ipv6 address */
+       struct rte_timer *timer;                /**< Timer */
+} __attribute__ ((packed));
+
+/**
+* A structure is used to define the table for ND entry data
+* This structure is used to maintain ND entry data
+*
+*/
+
+struct table_nd_entry_data {
+       uint8_t eth_addr[6];             /**< Ethernet address */
+       uint8_t port;                    /**< Port */
+       uint8_t status;                  /**< status of Entry */
+       uint8_t ipv6[ND_IPV6_ADDR_SIZE]; /**< IPv6 address */
+       struct rte_timer *timer;         /**< Timer */
+} __attribute__ ((packed));
+
+/**
+* To get the destination MAC address andnext hop for the ip address  and outgoing port
+* @param1 ip addr
+* IP address for which MAC address is needed.
+* @param2 phy_port
+*  Physical Port
+* @param3 ether_addr
+* pointer to the ether_addr, This gets update with valid MAC addresss
+* @Param4 next nhip
+* Gets the next hop IP by Ip address and physical port
+* @return
+* 0 if failure, and 1 if success
+*/
+
+int get_dest_mac_address(const uint32_t ipaddr, uint32_t *phy_port,
+                        struct ether_addr *hw_addr, uint32_t *nhip);
+/**
+* To get the destination MAC address andnext hop for the ip address  and outgoing port
+* @param1 ip addr
+* IP address for which MAC address is needed.
+* @param2 phy_port
+*  Physical Port
+* @param3 ether_addr
+* pointer to the ether_addr, This gets update with valid MAC addresss
+* @Param4 next nhip
+* Gets the next hop IP by Ip address and physical port
+* @return
+* 0 if failure, and 1 if success
+*/
+int get_dest_mac_addr_port(const uint32_t ipaddr,
+                                uint32_t *phy_port, struct ether_addr *hw_addr);
+
+/**
+* To get the destination mac address for  IPv4  address
+* @param  Ipaddr
+* IP address which need the destination mac address
+* @param Phy_port
+* physical port
+* @param ether_addr
+* pointer to the ether_addr, This gets update with valid mac address
+* @return
+* 0 if failure, 1 if success
+*/
+int get_dest_mac_addr(const uint32_t ipaddr, uint32_t *phy_port,
+                                       struct ether_addr *hw_addr);
+
+/**
+* To get the destination mac address for IPV6 address
+* @param ipv6addr
+* IPv6 address which need the destination mac adress
+* @param Phy_Port
+* physical prt
+* @param ether_addr
+* pointer to the ether_address, This gets update with valid mac address
+* @param Nhipv6[]
+* Gets the next hop ipv6 address by ipv6 address and physical port
+* @return
+* 0 if failure, 1 ifsuccess
+*/
+int get_dest_mac_address_ipv6(uint8_t ipv6addr[], uint32_t *phy_port,
+                                               struct ether_addr *hw_addr, uint8_t nhipv6[]);
+/**
+* To get the destination mac address for IPV6 address
+* @param ipv6addr
+* IPv6 address which need the destination mac adress
+* @param Phy_Port
+* physical prt
+* @param ether_addr
+* pointer to the ether_address, This gets update with valid mac address
+* @param Nhipv6[]
+* Gets the next hop ipv6 address by ipv6 address and physical port
+* @return
+* 0 if failure, 1 ifsuccess
+*/
+
+int get_dest_mac_address_ipv6_port(uint8_t ipv6addr[], uint32_t *phy_port,
+                                        struct ether_addr *hw_addr,
+                                        uint8_t nhipv6[]);
+
+/**
+* To get hardware link address
+* @param out_port
+* out going  port
+*/
+
+struct ether_addr *get_link_hw_addr(uint8_t out_port);
+
+/**
+* This prints the Arp Table
+* @param void
+*
+*/
+void print_arp_table(void);
+
+/**
+* This prints the ND table
+* @param void
+*
+*/
+void print_nd_table(void);
+
+/**
+* This removes arp entry from Table
+* @param ipaddr
+* Ipv4 address
+* @param portid
+* Port id
+*/
+void remove_arp_entry(uint32_t ipaddr, uint8_t portid, void *arg);
+
+/**
+* Removes ND entry from Nd Table
+* @Param ipv6addr[]
+* Ipv6 address
+* @Param portid
+* Port id
+*/
+
+void remove_nd_entry_ipv6(uint8_t ipv6addr[], uint8_t portid);
+
+/**
+* Populate arp entry in arp Table
+* @param ether_addr
+* Ethernet address
+* @param ipaddr
+* Ipv4 adress
+* @Param portid
+* port id
+* @Param mode
+* Mode
+*/
+void populate_arp_entry(const struct ether_addr *hw_addr, uint32_t ipaddr,
+                       uint8_t portid, uint8_t mode);
+
+/**
+* Populate ND entry in ND Table
+* @param ether_addr
+* Ethernet address
+* @param ip[]
+* Ipv6 adress
+* @Param portid
+* port id
+* @Param mode
+* Mode
+*/
+
+void populate_nd_entry(const struct ether_addr *hw_addr, uint8_t ip[],
+                                        uint8_t portid, uint8_t mode);
+
+/**
+* To send ARp request
+* @Param port_id
+* port id
+@ Param IP
+* Ip address
+*/
+
+void request_arp(uint8_t port_id, uint32_t ip);
+
+/**
+* TO send echo request
+* @param port_id
+* Port id
+* @Param ip
+* Ip address
+*/
+struct rte_mbuf *request_echo(uint32_t port_id, uint32_t ip);
+
+/**
+* To send icmpv6 echo request
+* @Param port_id
+* Port id
+* @Param ipv6
+* ipv6 address
+*/
+struct rte_mbuf *request_icmpv6_echo(uint8_t ipv6[], l2_phy_interface_t *port);
+
+/**
+* To request ND
+* @Param ipv6
+* ipv6 address
+* @Param port
+* pointer to port
+*/
+struct rte_mbuf *request_nd(uint8_t ipv6[], l2_phy_interface_t *port);
+
+/**
+* To process te ARP and ICMP packets
+* @Param Pkt
+* Packets to be processed
+* @Param pkt_num
+* packet number
+* @Param portid
+* port id
+*/
+void process_arpicmp_pkt(struct rte_mbuf *pkt, l2_phy_interface_t *port);
+
+/**
+* IPv4
+* Validate if key-value pair already exists in the hash table for given key - IPv4
+* @Param arp_key
+* Arp key to validate entry
+*/
+struct arp_entry_data *retrieve_arp_entry(const struct arp_key_ipv4 arp_key);
+
+/**
+* ND IPv6
+* Validate if key-value pair already exists in the hash table for given key - ND IPv6
+* @Param nd_key
+* Nd key to validate Nd entry
+*/
+
+struct nd_entry_data *retrieve_nd_entry(struct nd_key_ipv6 nd_key);
+
+/**
+* Setsup Arp Initilization
+*/
+//void lib_arp_init(void);
+void lib_arp_init(struct pipeline_params *params, struct app_params *app);
+#if 0
+void set_port_to_loadb_map(uint8_t pipeline_num);
+
+/**
+* Acts on port_to_loadb_map
+*/
+uint8_t get_port_to_loadb_map(uint8_t phy_port_id);
+
+void set_phy_inport_map(uint8_t pipeline_num, uint8_t *map);
+void set_phy_outport_map(uint8_t pipeline_num, uint8_t *map);
+
+/**
+* Acts on lb_outport_id
+*/
+
+uint8_t get_loadb_outport_id(uint8_t actual_phy_port);
+uint8_t get_vnf_set_num(uint8_t pipeline_num);
+
+void pipelines_port_info(void);
+void pipelines_map_info(void);
+#endif
+/**
+* A callback for arp Timer
+* @Param rte_timer
+* timer pointer
+* @Param arg
+* arguments to timer
+*/
+void arp_timer_callback(struct rte_timer *, void *arg);
+
+/**
+* A callback for ND timer
+* @Param rte_timer
+* timer pointer
+* @Param arg
+* arguments to timer
+*/
+void nd_timer_callback(struct rte_timer *timer, void *arg);
+
+/**
+* To create Arp Table
+* @param void
+*/
+void create_arp_table(void);
+/**
+* To create ND Table
+* @param void
+*/
+void create_nd_table(void);
+
+/**
+* To parse and process the Arp and icmp packets
+* @Param pkt
+* pkt to process
+* @Param pkt_num
+* pkt number
+* @Param pkt_mask
+* packet mask
+* @Param port
+* pointer to port
+*/
+void process_arpicmp_pkt_parse(struct rte_mbuf **pkt, uint16_t pkt_num,
+                                                uint64_t pkt_mask, l2_phy_interface_t *port);
+
+/**
+* Sends garp packet
+* @Param port
+* pointer to port
+*/
+void send_gratuitous_arp(l2_phy_interface_t *port);
+/**
+* To set arp debug
+* @Param flag
+* set 1 unset 0
+*/
+void set_arpdebug(int flag);
+/**
+* To set timer for arp entry
+* @Param timeout_val
+* timer val for arp entry
+*/
+void set_arptimeout(uint32_t timeout_val);
+/**
+* To get nexthop for ipv4
+* @Param ipv4
+* ipv4 address
+* @Param
+* timeout_val to set
+*/
+uint32_t get_nh(uint32_t, uint32_t *);
+/**
+* To get nexthop for ipv6
+* @Param ipv6
+* ipv6 address
+* @Param port
+* pointer to port
+* @Param nhipv6
+* next hop ipv6
+*/
+void get_nh_ipv6(uint8_t ipv6[], uint32_t *port, uint8_t nhipv6[]);
+#endif
diff --git a/common/VIL/l2l3_stack/lib_icmpv6.c b/common/VIL/l2l3_stack/lib_icmpv6.c
new file mode 100644 (file)
index 0000000..44f30cb
--- /dev/null
@@ -0,0 +1,410 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+/*     Santosh Sethupathi*/
+
+#include "lib_icmpv6.h"
+
+static void print_pkt(uint8_t *rd)
+{
+       int i = 0, j = 0;
+
+       printf("Packet Contents:\n");
+
+       for (i = 0; i < 20; i++) {
+               for (j = 0; j < 20; j++)
+                       printf("%02x ", rd[(20 * i) + j]);
+
+               printf("\n");
+       }
+}
+
+static uint16_t icmpv6_ipv6_nd_checksum(struct rte_mbuf *pkt)
+{
+       struct ether_hdr *eth_h;
+       struct ipv6_hdr *ipv6_h;
+       struct icmpv6_hdr *icmpv6_h;
+
+       size_t tmplen, offset;
+       uint8_t *tmppacket, *tpacket;
+
+       eth_h = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+       ipv6_h = (struct ipv6_hdr *)((char *)eth_h + sizeof(struct ether_hdr));
+       icmpv6_h =
+                       (struct icmpv6_hdr *)((char *)ipv6_h + sizeof(struct ipv6_hdr));
+
+       uint32_t payloadlen = 0x20;
+       payloadlen = rte_bswap32(payloadlen);
+
+       tmplen = 40 + sizeof(struct icmpv6_hdr) + sizeof(struct icmpv6_nd_hdr);
+       tmplen = RTE_CACHE_LINE_ROUNDUP(tmplen);
+       tmppacket = rte_zmalloc(NULL, tmplen, RTE_CACHE_LINE_SIZE);
+       tpacket = tmppacket;
+
+       offset = 16;
+       memcpy(tpacket, &ipv6_h->src_addr[0], offset);
+       tpacket += offset;
+       memcpy(tpacket, &ipv6_h->dst_addr[0], offset);
+       tpacket += offset;
+       *tpacket = 0;
+       tpacket++;
+       *tpacket = 0;
+       tpacket++;
+       *tpacket = 0;
+       tpacket++;
+       memcpy(tpacket, &ipv6_h->proto, 1);
+       tpacket++;
+       memcpy(tpacket, &payloadlen, 4);
+       tpacket += 4;
+       memcpy(tpacket, icmpv6_h,
+                                sizeof(struct icmpv6_hdr) + sizeof(struct icmpv6_nd_hdr));
+
+       if (ARPICMP_DEBUG)
+               print_pkt(tmppacket);
+
+       return rte_raw_cksum(tmppacket, tmplen);
+}
+
+static uint16_t icmpv6_ipv6_echo_checksum(struct rte_mbuf *pkt)
+{
+       struct ether_hdr *eth_h;
+       struct ipv6_hdr *ipv6_h;
+       struct icmpv6_hdr *icmpv6_h;
+
+       size_t tmplen, offset;
+       uint8_t *tmppacket, *tpacket;
+
+       eth_h = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+       ipv6_h = (struct ipv6_hdr *)((char *)eth_h + sizeof(struct ether_hdr));
+       icmpv6_h =
+                       (struct icmpv6_hdr *)((char *)ipv6_h + sizeof(struct ipv6_hdr));
+
+       uint32_t payloadlen = rte_bswap16(ipv6_h->payload_len);
+       uint32_t payloadlen_swap = rte_bswap32(payloadlen);
+
+       if (ARPICMP_DEBUG)
+               printf("%s: payloadlen: %u\n", __FUNCTION__, payloadlen);
+
+       tmplen = 40 + payloadlen;
+       tmplen = RTE_CACHE_LINE_ROUNDUP(tmplen);
+       tmppacket = rte_zmalloc(NULL, tmplen, RTE_CACHE_LINE_SIZE);
+       tpacket = tmppacket;
+
+       offset = 16;
+       memcpy(tpacket, &ipv6_h->src_addr[0], offset);
+       tpacket += offset;
+       memcpy(tpacket, &ipv6_h->dst_addr[0], offset);
+       tpacket += offset;
+       *tpacket = 0;
+       tpacket++;
+       *tpacket = 0;
+       tpacket++;
+       *tpacket = 0;
+       tpacket++;
+       memcpy(tpacket, &ipv6_h->proto, 1);
+       tpacket++;
+       memcpy(tpacket, &payloadlen_swap, 4);
+       tpacket += 4;
+       memcpy(tpacket, icmpv6_h, payloadlen);
+
+       if (ARPICMP_DEBUG)
+               print_pkt(tmppacket);
+
+       return rte_raw_cksum(tmppacket, tmplen);
+}
+
+void process_icmpv6_pkt(struct rte_mbuf *pkt, l2_phy_interface_t *port)
+{
+
+       struct ether_hdr *eth_h;
+       struct ipv6_hdr *ipv6_h;
+       struct icmpv6_hdr *icmpv6_h;
+       struct icmpv6_nd_hdr *icmpv6_nd_h;
+       uint8_t ipv6_addr[16];
+       uint8_t i = 0;
+       uint8_t req_tipv6[16];
+       /* To drop the packet */
+
+       if (port == NULL) {
+               printf("port is NULL");
+               return;
+       } else if (port->ipv6_list == NULL) {
+               printf("IPV6 address not configured on link\n");
+               return;
+       }
+
+       eth_h = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+       ipv6_h = (struct ipv6_hdr *)((char *)eth_h + sizeof(struct ether_hdr));
+       icmpv6_h =
+                       (struct icmpv6_hdr *)((char *)ipv6_h + sizeof(struct ipv6_hdr));
+
+       if ((icmpv6_h->icmpv6_type == ICMPV6_ECHO_REQUEST)
+                       && (icmpv6_h->icmpv6_code == 0)) {
+               for (i = 0; i < 16; i++) {
+                       ipv6_addr[i] = ipv6_h->src_addr[i];
+               }
+
+               ether_addr_copy(&eth_h->s_addr, &eth_h->d_addr);
+               ether_addr_copy((struct ether_addr *)&port->macaddr[0],
+                               &eth_h->s_addr);
+
+               for (i = 0; i < 16; i++)
+                       ipv6_h->src_addr[i] = ipv6_h->dst_addr[i];
+               for (i = 0; i < 16; i++)
+                       ipv6_h->dst_addr[i] = ipv6_addr[i];
+
+               icmpv6_h->icmpv6_type = ICMPV6_ECHO_REPLY;
+               icmpv6_h->icmpv6_cksum = 0;
+               icmpv6_h->icmpv6_cksum = ~icmpv6_ipv6_echo_checksum(pkt);
+               port->transmit_bulk_pkts(port, &pkt, 1);
+
+               return;
+       } else if ((icmpv6_h->icmpv6_type == ICMPV6_ECHO_REPLY)
+                        && (icmpv6_h->icmpv6_code == 0)) {
+               struct nd_key_ipv6 nd_key;
+               nd_key.port_id = port->pmdid;
+               for (i = 0; i < ND_IPV6_ADDR_SIZE; i++) {
+                       nd_key.ipv6[i] = ipv6_h->src_addr[i];
+
+               }
+               nd_key.filler1 = 0;
+               nd_key.filler2 = 0;
+               nd_key.filler3 = 0;
+
+               /*Validate if key-value pair already exists in the hash table for ND IPv6 */
+               struct nd_entry_data *new_nd_data = retrieve_nd_entry(nd_key);
+               if (new_nd_data == NULL) {
+                       printf
+                                       ("Received unsolicited ICMPv6 echo reply on port %d\n",
+                                        nd_key.port_id);
+                       for (i = 0; i < ND_IPV6_ADDR_SIZE; i += 2) {
+                               printf("%02X%02X ", nd_key.ipv6[i],
+                                                        nd_key.ipv6[i + 1]);
+                       }
+                       return;
+               }
+
+               new_nd_data->status = COMPLETE;
+       } else if ((icmpv6_h->icmpv6_type == ICMPV6_NEIGHBOR_SOLICITATION)
+                        && (icmpv6_h->icmpv6_code == 0)) {
+
+               icmpv6_nd_h =
+                               (struct icmpv6_nd_hdr *)((char *)icmpv6_h +
+                                                        sizeof(struct icmpv6_hdr));
+               struct ether_addr *src_hw_addr = &eth_h->s_addr;
+               uint8_t src_ipv6[16], dst_ipv6[16];
+               uint16_t multi_addr;
+
+               for (i = 0; i < ND_IPV6_ADDR_SIZE; i++)
+                       src_ipv6[i] = ipv6_h->src_addr[i];
+               for (i = 0; i < ND_IPV6_ADDR_SIZE; i++)
+                       dst_ipv6[i] = ipv6_h->dst_addr[i];
+
+               multi_addr = dst_ipv6[0];
+
+               /*  Check for Multicast Address */
+               if ((IPV6_MULTICAST & ((multi_addr << 8) | dst_ipv6[1]))
+                               || !memcmp(&port->macaddr[0], &eth_h->d_addr, 6)) {
+                       populate_nd_entry(src_hw_addr, src_ipv6, port->pmdid,
+                                               DYNAMIC_ND);
+
+                       /* build a Neighbor Advertisement message */
+                       for (i = 0; i < ND_IPV6_ADDR_SIZE; i++)
+                               req_tipv6[i] = icmpv6_nd_h->target_ipv6[i];
+
+                       if (!memcmp
+                                       (&req_tipv6[0],
+                                        &((ipv6list_t *) port->ipv6_list)->ipaddr[0],
+                                        16)) {
+
+                               ether_addr_copy(&eth_h->s_addr, &eth_h->d_addr);
+                               ether_addr_copy((struct ether_addr *)&port->
+                                               macaddr[0], &eth_h->s_addr);
+
+                               /* set sender mac address */
+                               for (i = 0; i < ND_IPV6_ADDR_SIZE; i++)
+                                       ipv6_h->dst_addr[i] =
+                                                       ipv6_h->src_addr[i];
+                               for (i = 0; i < ND_IPV6_ADDR_SIZE; i++)
+                                       ipv6_h->src_addr[i] = req_tipv6[i];
+                               icmpv6_h->icmpv6_type =
+                                               ICMPV6_NEIGHBOR_ADVERTISEMENT;
+                               icmpv6_nd_h->type = e_Target_Link_Layer_Address;
+                               icmpv6_nd_h->length = 1;
+                               memcpy(&icmpv6_nd_h->link_layer_addr[0],
+                                                        &port->macaddr[0], 6);
+                               icmpv6_nd_h->icmpv6_reserved = 0;
+                               icmpv6_nd_h->icmpv6_reserved |=
+                                               rte_cpu_to_be_32
+                                               (NEIGHBOR_ROUTER_OVERRIDE_SET);
+
+                               icmpv6_h->icmpv6_cksum = 0;
+                               icmpv6_h->icmpv6_cksum =
+                                               ~icmpv6_ipv6_nd_checksum(pkt);
+
+                               port->transmit_bulk_pkts(port, &pkt, 1);
+
+                       } else if (ARPICMP_DEBUG) {
+                               printf
+                                               ("............Some one else is the target host here !!!\n");
+                       }
+
+                       return;
+               } else {
+                       if (ARPICMP_DEBUG) {
+                               printf
+                                               ("...............Malformed ND Solicitation message!!!\n");
+                       }
+               }
+
+       } else if ((icmpv6_h->icmpv6_type == ICMPV6_NEIGHBOR_ADVERTISEMENT)
+                        && (icmpv6_h->icmpv6_code == 0)) {
+               struct ether_addr *src_hw_addr = &eth_h->s_addr;
+               uint8_t ipv6[16];
+               for (i = 0; i < ND_IPV6_ADDR_SIZE; i++) {
+                       ipv6[i] = ipv6_h->src_addr[i];
+
+               }
+               populate_nd_entry(src_hw_addr, ipv6, port->pmdid, DYNAMIC_ND);
+       } else {
+               if (ARPICMP_DEBUG) {
+                       printf("ICMPv6 Type %d Not Supported yet !!!\n",
+                                                icmpv6_h->icmpv6_type);
+               }
+       }
+
+       rte_pktmbuf_free(pkt);
+}
+
+struct rte_mbuf *request_icmpv6_echo(uint8_t ipv6[], l2_phy_interface_t *port)
+{
+       struct ether_hdr *eth_h;
+       struct ipv6_hdr *ipv6_h;
+       struct icmpv6_hdr *icmpv6_h;
+       struct icmpv6_info_hdr *icmpv6_info_h;
+       int i;
+       uint8_t *icmp_data;
+
+       struct rte_mbuf *icmpv6_pkt = lib_icmpv6_pkt;
+       if (icmpv6_pkt == NULL) {
+               if (ARPICMP_DEBUG)
+                       printf("Error allocating icmpv6_pkt rte_mbuf\n");
+               return NULL;
+       }
+
+       eth_h = rte_pktmbuf_mtod(icmpv6_pkt, struct ether_hdr *);
+
+       ipv6_h = (struct ipv6_hdr *)((char *)eth_h + sizeof(struct ether_hdr));
+       icmpv6_h =
+                       (struct icmpv6_hdr *)((char *)ipv6_h + sizeof(struct ipv6_hdr));
+       icmpv6_info_h =
+                       (struct icmpv6_info_hdr *)((char *)icmpv6_h +
+                                                        sizeof(struct icmpv6_hdr));
+
+       ether_addr_copy((struct ether_addr *)&port->macaddr[0], &eth_h->s_addr);
+       eth_h->ether_type = rte_bswap16(0x86dd);
+       for (i = 0; i < 6; i++) {
+               eth_h->d_addr.addr_bytes[i] = 0;
+       }
+
+       ipv6_h->vtc_flow = rte_bswap32(0x60000000);
+       ipv6_h->payload_len = rte_bswap16(64);
+       ipv6_h->proto = 58;
+       ipv6_h->hop_limits = 64;
+
+       for (i = 0; i < 16; i++) {
+               ipv6_h->src_addr[i] = 0x0;
+               ipv6_h->dst_addr[i] = ipv6[i];
+       }
+
+       icmpv6_h->icmpv6_type = ICMPV6_ECHO_REQUEST;
+       icmpv6_h->icmpv6_code = 0;
+       icmpv6_info_h->icmpv6_ident = rte_bswap16(0x5151);
+       icmpv6_info_h->icmpv6_seq_nb = rte_bswap16(0x1);
+
+       icmp_data = (uint8_t *) icmpv6_h + 8;
+       for (i = 0; i < 56; i++) {
+               *icmp_data = i + 1;
+               icmp_data++;
+       }
+       icmpv6_h->icmpv6_cksum = 0;
+       icmpv6_h->icmpv6_cksum = ~icmpv6_ipv6_echo_checksum(icmpv6_pkt);
+
+       icmpv6_pkt->pkt_len =
+                       sizeof(struct ether_hdr) + sizeof(struct ipv6_hdr) + 64;
+       icmpv6_pkt->data_len = icmpv6_pkt->pkt_len;
+
+       return icmpv6_pkt;
+}
+
+struct rte_mbuf *request_nd(uint8_t ipv6[], l2_phy_interface_t *port)
+{
+       struct ether_hdr *eth_h;
+       struct ipv6_hdr *ipv6_h;
+       struct icmpv6_hdr *icmpv6_h;
+       struct icmpv6_nd_hdr *icmpv6_nd_h;
+       int i;
+
+       struct rte_mbuf *icmpv6_pkt = lib_icmpv6_pkt;
+       if (icmpv6_pkt == NULL) {
+               if (ARPICMP_DEBUG)
+                       printf("Error allocating icmpv6_pkt rte_mbuf\n");
+               return NULL;
+       }
+
+       eth_h = rte_pktmbuf_mtod(icmpv6_pkt, struct ether_hdr *);
+
+       ipv6_h = (struct ipv6_hdr *)((char *)eth_h + sizeof(struct ether_hdr));
+       icmpv6_h =
+                       (struct icmpv6_hdr *)((char *)ipv6_h + sizeof(struct ipv6_hdr));
+       icmpv6_nd_h =
+                       (struct icmpv6_nd_hdr *)((char *)icmpv6_h +
+                                                sizeof(struct icmpv6_hdr));
+
+       ether_addr_copy((struct ether_addr *)&port->macaddr[0], &eth_h->s_addr);
+       eth_h->ether_type = rte_bswap16(0x86dd);
+       for (i = 0; i < 6; i++) {
+               eth_h->d_addr.addr_bytes[i] = 0;
+       }
+
+       ipv6_h->vtc_flow = 0x60000000;
+       ipv6_h->payload_len = rte_bswap16(32);
+       ipv6_h->proto = 58;
+       ipv6_h->hop_limits = 64;
+
+       for (i = 0; i < 16; i++) {
+               ipv6_h->src_addr[i] = 0x0;
+               ipv6_h->dst_addr[i] = ipv6[i];
+       }
+
+       icmpv6_h->icmpv6_type = ICMPV6_NEIGHBOR_SOLICITATION;
+       icmpv6_h->icmpv6_code = 0;
+
+       icmpv6_nd_h->icmpv6_reserved = 0x0;
+       for (i = 0; i < ND_IPV6_ADDR_SIZE; i++)
+               icmpv6_nd_h->target_ipv6[i] = ipv6[i];
+       icmpv6_nd_h->type = e_Source_Link_Layer_Address;
+       icmpv6_nd_h->length = 1;
+       memcpy(&icmpv6_nd_h->link_layer_addr[0], &port->macaddr[0], 6);
+
+       icmpv6_h->icmpv6_cksum = 0;
+       icmpv6_h->icmpv6_cksum = ~icmpv6_ipv6_nd_checksum(icmpv6_pkt);
+
+       icmpv6_pkt->pkt_len =
+                       sizeof(struct ether_hdr) + sizeof(struct ipv6_hdr) + 32;
+       icmpv6_pkt->data_len = icmpv6_pkt->pkt_len;
+
+       return icmpv6_pkt;
+}
diff --git a/common/VIL/l2l3_stack/lib_icmpv6.h b/common/VIL/l2l3_stack/lib_icmpv6.h
new file mode 100644 (file)
index 0000000..e9ccca1
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+/*     Author - Santosh Sethupathi     */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <rte_common.h>
+#include <rte_malloc.h>
+#include <rte_ip.h>
+#include <rte_byteorder.h>
+#include <rte_table_lpm.h>
+#include <rte_table_hash.h>
+#include <rte_pipeline.h>
+#include <rte_arp.h>
+#include <rte_icmp.h>
+#include <rte_hash.h>
+#include <rte_jhash.h>
+#include <rte_cycles.h>
+#include "lib_arp.h"
+#include <rte_pipeline.h>
+#include "rte_ether.h"
+
+/**
+* ICMPv6 Header
+*/
+
+struct icmpv6_hdr {
+       uint8_t icmpv6_type;    /**< ICMPV6 packet type. */
+       uint8_t icmpv6_code;    /**<  ICMPV6 packet code. */
+       uint16_t icmpv6_cksum;  /**< ICMPV6 packet checksum. */
+} __attribute__ ((__packed__));
+
+/**
+* ICMPV6 Info Header
+*/
+struct icmpv6_info_hdr {
+       uint16_t icmpv6_ident;  /**< ICMPV6 packet identifier. */
+       uint16_t icmpv6_seq_nb; /**< ICMPV6 packet sequence number. */
+} __attribute__ ((__packed__));
+
+/**
+ * ICMPV6 ND Header
+ */
+struct icmpv6_nd_hdr {
+       /*ND Advertisement flags */
+       uint32_t icmpv6_reserved; /**< bit31-Router, bit30-Solicited, bit29-Override, bit28-bit0 unused */
+
+       uint8_t target_ipv6[16];  /**< target IPv6 address */
+       uint8_t type;                   /**< ICMPv6 Option*/
+       uint8_t length;          /**< Length */
+       uint8_t link_layer_addr[6]; /**< Link layer address */
+} __attribute__ ((__packed__));
+
+/* Icmpv6 types */
+#define ICMPV6_PROTOCOL_ID 58
+#define ICMPV6_ECHO_REQUEST 0x0080
+#define ICMPV6_ECHO_REPLY 0x0081
+#define ICMPV6_NEIGHBOR_SOLICITATION 0x0087
+#define ICMPV6_NEIGHBOR_ADVERTISEMENT 0x0088
+#define IPV6_MULTICAST 0xFF02
+
+#define NEIGHBOR_SOLICITATION_SET 0x40000000
+#define NEIGHBOR_ROUTER_OVERRIDE_SET 0xa0000000
+enum icmpv6_link_layer_Address_type {
+       e_Source_Link_Layer_Address = 1,
+       e_Target_Link_Layer_Address,
+       e_Link_Layer_Address
+};
+
+/* Checks whether ipv6 is multicast
+ * @param ipv6
+ */
+uint8_t is_multicast_ipv6_addr(uint8_t ipv6[]);
+
+/**
+*Icmpv6 Port address
+*/
+struct icmpv6_port_address {
+       uint32_t ipv6[16];   /**< Ipv6 address */
+       uint64_t mac_addr;   /**< Mac address */
+};
+
+/**
+* To store Icmpv6 Port address
+*/
+struct icmpv6_port_address icmpv6_port_addresses[RTE_MAX_ETHPORTS];
+
+#define MAX_NUM_ICMPv6_ENTRIES 64
+struct rte_mbuf *lib_icmpv6_pkt;
+
+/**
+ * Processes icmpv6 packets
+ * @param pkt
+ *  pkt mbuf packets
+ * @param port
+ *  port - port structure
+ */
+void process_icmpv6_pkt(struct rte_mbuf *pkt, l2_phy_interface_t *port);
diff --git a/common/VIL/l2l3_stack/main_l2l3.c b/common/VIL/l2l3_stack/main_l2l3.c
new file mode 100644 (file)
index 0000000..08c9764
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef __INCLUDE_MAIN__
+#define __INCLUDE_MAIN_H__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <string.h>
+#include <sys/queue.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <getopt.h>
+#include <signal.h>
+#include <stdbool.h>
+
+#include <rte_common.h>
+#include <rte_vect.h>
+#include <rte_byteorder.h>
+#include <rte_log.h>
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+#include <rte_memzone.h>
+#include <rte_eal.h>
+#include <rte_per_lcore.h>
+#include <rte_launch.h>
+#include <rte_atomic.h>
+#include <rte_cycles.h>
+#include <rte_prefetch.h>
+#include <rte_lcore.h>
+#include <rte_per_lcore.h>
+#include <rte_branch_prediction.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_random.h>
+#include <rte_debug.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_ring.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include <rte_ip.h>
+#include <rte_tcp.h>
+#include <rte_udp.h>
+#include <rte_string_fns.h>
+#include <rte_cpuflags.h>
+#include <rte_timer.h>
+#include "lib_arp.h"
+#include "l2_proto.h"
+#include "interface.h"
+#include "l3fwd_common.h"
+#include "l3fwd_lpm4.h"
+#include "l3fwd_lpm6.h"
+#define TIMER_RESOLUTION_CYCLES 20000000ULL    /* around 10ms at 2 Ghz */
+unsigned lcore_id = 1;
+void convert_ipstr_to_numeric(void);
+struct sockaddr_in ipaddr1, ipaddr2, ipaddr3, ipaddr4;
+uint8_t ipv6_addr0[16] = {
+       0, 0x64, 0xff, 0x9b, 0, 0, 0, 0, 0, 0, 0, 0, 0xc0, 0x10, 0x28, 0x15
+};
+
+uint8_t ipv6_addr1[16] = {
+       0x12, 0x64, 0xff, 0x9b, 0, 0, 0, 0, 0, 0, 0, 0, 0xc0, 0x10, 0x28, 0x15
+};
+
+/*{port_id, nrx_queue, ntx_queue, adminstate, promisc}*/
+port_config_t portconf[5] = {
+       {
+               .port_id = 0,
+               .nrx_queue = 1,
+               .ntx_queue = 1,
+               .state = 1,
+               .promisc = 1,
+               .mempool = {
+                       .buffer_size = 2048 + sizeof(struct rte_mbuf) +
+                               RTE_PKTMBUF_HEADROOM,
+                       .pool_size = 32 * 1024,
+                       .cache_size = 256,
+                       .cpu_socket_id = 0,
+               },
+               .port_conf = {
+                       .link_speeds = 0,
+                       .rxmode = {
+                               .mq_mode = ETH_MQ_RX_NONE,
+                               .header_split = 0,      /* Header split */
+                               .hw_ip_checksum = 0,    /* IP checksum offload */
+                               .hw_vlan_filter = 0,    /* VLAN filtering */
+                               .hw_vlan_strip = 0,     /* VLAN strip */
+                               .hw_vlan_extend = 0,    /* Extended VLAN */
+                               .jumbo_frame = 0,       /* Jumbo frame support */
+                               .hw_strip_crc = 0,      /* CRC strip by HW */
+                               .enable_scatter = 0,    /* Scattered packets RX handler */
+                               .max_rx_pkt_len = 9000, /* Jumbo frame max packet len */
+                               .split_hdr_size = 0,    /* Header split buffer size */
+                       },
+                       _adv_conf = {
+                               .rss_conf = {
+                                       .rss_key = NULL,
+                                       .rss_key_len = 40,
+                                       .rss_hf = 0,
+                               },
+                       },
+                       .txmode = {
+                               .mq_mode = ETH_MQ_TX_NONE,},
+                       .lpbk_mode = 0,
+                       .intr_conf = {
+                               .lsc = 1,
+                               /**< lsc interrupt feature enabled */
+                       }
+               },
+               .rx_conf = {
+                       .rx_thresh = {
+                               .pthresh = 8,
+                               .hthresh = 8,
+                               .wthresh = 4,
+                       },
+                       .rx_free_thresh = 64,
+                       .rx_drop_en = 0,
+                       .rx_deferred_start = 0,
+               },
+               .tx_conf = {
+                       .tx_thresh = {
+                               .pthresh = 36,
+                               .hthresh = 0,
+                               .wthresh = 0,                                   =
+                       },
+                       .tx_rs_thresh = 0,
+                       .tx_free_thresh = 0,
+                       .txq_flags = ETH_TXQ_FLAGS_NOMULTSEGS | ETH_TXQ_FLAGS_NOOFFLOADS,
+                       .tx_deferred_start = 0,
+               }
+       },
+       {
+               .port_id = 1,
+               .nrx_queue = 1,
+               .ntx_queue = 1,
+               .state = 1,
+               .promisc = 1,
+               .mempool = {
+                       .buffer_size = 2048 + sizeof(struct rte_mbuf) +
+                               RTE_PKTMBUF_HEADROOM,
+                       .pool_size = 32 * 1024,
+                       .cache_size = 256,
+                       .cpu_socket_id = 0,
+               },
+               .port_conf = {
+                       .link_speeds = 0,
+                       .rxmode = {
+                               .mq_mode = ETH_MQ_RX_NONE,
+                               .header_split = 0,      /* Header split */
+                               .hw_ip_checksum = 0,    /* IP checksum offload */
+                               .hw_vlan_filter = 0,    /* VLAN filtering */
+                               .hw_vlan_strip = 0,     /* VLAN strip */
+                               .hw_vlan_extend = 0,    /* Extended VLAN */
+                               .jumbo_frame = 0,       /* Jumbo frame support */
+                               .hw_strip_crc = 0,      /* CRC strip by HW */
+                               .enable_scatter = 0,    /* Scattered packets RX handler */
+                               .max_rx_pkt_len = 9000, /* Jumbo frame max packet len */
+                               .split_hdr_size = 0,    /* Header split buffer size */
+                       },
+                       _adv_conf = {
+                               .rss_conf = {
+                                       .rss_key = NULL,
+                                       .rss_key_len = 40,
+                                       .rss_hf = 0,
+                               },
+                       },
+                       .txmode = {
+                               .mq_mode = ETH_MQ_TX_NONE,},
+                       .lpbk_mode = 0,
+                       .intr_conf = {
+                               .lsc = 1,
+                               /**< lsc interrupt feature enabled */
+                       }
+               },
+               .rx_conf = {
+                       .rx_thresh = {
+                               .pthresh = 8,
+                               .hthresh = 8,
+                               .wthresh = 4,
+                       },
+                       .rx_free_thresh = 64,
+                       .rx_drop_en = 0,
+                       .rx_deferred_start = 0,
+               },
+               .tx_conf = {
+                       .tx_thresh = {
+                               .pthresh = 36,
+                               .hthresh = 0,
+                               .wthresh = 0,                                   =
+                       },
+                       .tx_rs_thresh = 0,
+                       .tx_free_thresh = 0,
+                       .txq_flags = ETH_TXQ_FLAGS_NOMULTSEGS | ETH_TXQ_FLAGS_NOOFFLOADS,
+                       .tx_deferred_start = 0,
+               }
+       },
+};
+
+static __attribute__ ((noreturn))
+int lcore_mainloop (__attribute__ ((unused))
+                        void *arg)
+{
+       l2_phy_interface_t *port;
+       int8_t portid;
+       struct rte_mbuf *pkts_burst[IFM_BURST_SIZE];
+       uint32_t nb_tx, nb_rx;
+       const uint64_t drain_tsc =
+                       (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S * BURST_TX_DRAIN_US;
+       uint64_t prev_tsc = 0, cur_tsc, diff_tsc;
+       while (1) {
+               port = ifm_get_first_port();
+               while (port != NULL) {
+                       rte_timer_manage();
+                       portid = port->pmdid;
+                       cur_tsc = rte_rdtsc();
+                       diff_tsc = cur_tsc - prev_tsc;
+
+                       /* call rx function ptr from port, with port.arpq, */
+                       if (unlikely(diff_tsc > drain_tsc)) {
+                               if (port->tx_buf_len > 0) {
+                                       RTE_SET_USED(nb_tx);
+
+                                       //nb_tx = port->transmit_bulk_pkts(port, port->tx_buf, port->tx_buf_len);
+                                       port->tx_buf_len = 0;
+                               }
+                               prev_tsc = cur_tsc;
+                       }
+                       nb_rx = port->retrieve_bulk_pkts(portid, 0, pkts_burst);
+                       port->n_rxpkts += nb_rx;
+                       protocol_handler_recv(pkts_burst, nb_rx, port);
+                       port = ifm_get_next_port(portid);
+                       if (port != NULL)
+                               prev_tsc = cur_tsc;
+               }
+       }
+}
+
+void convert_ipstr_to_numeric(void)
+{
+       memset(&ipaddr1, '\0', sizeof(struct sockaddr_in));
+       ipaddr1.sin_addr.s_addr = inet_addr("30.0.0.10");
+       memset(&ipaddr2, '\0', sizeof(struct sockaddr_in));
+       ipaddr2.sin_addr.s_addr = inet_addr("120.0.0.10");
+}
+
+int main(int argc, char **argv)
+{
+       int ret = 0;
+       /* init EAL */
+       ret = rte_eal_init(argc, argv);
+       if (ret < 0)
+               rte_exit(EXIT_FAILURE, "Invalid EAL parameters\n");
+       /* Port init */
+       //lib_arp_init();
+       ifm_init();
+       ifm_configure_ports(portconf);
+
+       //convert_ipstr_to_numeric();
+       //ifm_add_ipv4_port(0, ipaddr1.sin_addr.s_addr, 24);
+       //ifm_add_ipv4_port(1, ipaddr2.sin_addr.s_addr, 24);
+       ifm_add_ipv6_port(0, ipv6_addr0, 96);
+       ifm_add_ipv6_port(1, ipv6_addr1, 96);
+       print_interface_details();
+
+       //filter_init();
+       l3fwd_init();
+       create_arp_table();
+       create_nd_table();
+       populate_lpm_routes();
+       /*call the main loop */
+       /* launch per-lcore init on every lcore */
+       int ii;
+       for (ii = 0; ii < 16; ii += 2) {
+               printf("%02X%02X ", ipv6_addr0[ii], ipv6_addr0[ii + 1]);
+       }
+       printf("\n");
+       for (ii = 0; ii < 16; ii += 2) {
+               printf("%02X%02X ", ipv6_addr1[ii], ipv6_addr1[ii + 1]);
+       }
+       printf("REMOTE LAUNCH STARTED........\n");
+       rte_eal_remote_launch(lcore_mainloop, NULL, lcore_id);
+       printf("REMOTE LAUNCH DONE.......\n");
+       if (rte_eal_wait_lcore(lcore_id) < 0) {
+       }
+       return 0;
+}
+#endif
diff --git a/common/VIL/l2l3_stack/tsx.c b/common/VIL/l2l3_stack/tsx.c
new file mode 100644 (file)
index 0000000..a361c94
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <immintrin.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <stdint.h>
+#include "rte_atomic.h"
+#include "tsx.h"
+int max_retries = 3;
+
+static void
+run_cpuid (uint32_t eax, uint32_t ecx, uint32_t *abcd)
+{
+  uint32_t ebx = 0, edx = 0;
+
+#if defined(__i386__) && defined (__PIC__)
+  /* in case of PIC under 32-bit EBX cannot be clobbered */
+__asm__ ("movl %%ebx, %%edi \n\t cpuid \n\t xchgl %%ebx, %%edi":"=D" (ebx),
+#else
+__asm__ ("cpuid":"+b" (ebx),
+#endif
+                "+a" (eax), "+c" (ecx), "=d" (edx));
+  abcd[0] = eax;
+  abcd[1] = ebx;
+  abcd[2] = ecx;
+  abcd[3] = edx;
+}
+
+static int
+check_xcr0_ymm (void)
+{
+uint32_t xcr0;
+__asm__ ("xgetbv" : "=a" (xcr0) : "c" (0) : "%edx");
+return ((xcr0 & 6) == 6);/* checking if xmm and ymm state are enabled in XCR0 */
+}
+
+static int
+check_4th_gen_intel_core_features (void)
+{
+  uint32_t abcd[4];
+  uint32_t fma_movbe_osxsave_mask = ((1 << 12) | (1 << 22) | (1 << 27));
+  uint32_t avx2_bmi12_mask = (1 << 5) | (1 << 3) | (1 << 8);
+
+  /* CPUID.(EAX=01H, ECX=0H):ECX.FMA[bit 12]==1   &&
+     CPUID.(EAX=01H, ECX=0H):ECX.MOVBE[bit 22]==1 &&
+     CPUID.(EAX=01H, ECX=0H):ECX.OSXSAVE[bit 27]==1 */
+  run_cpuid (1, 0, abcd);
+  if ((abcd[2] & fma_movbe_osxsave_mask) != fma_movbe_osxsave_mask) {
+               printf ("Failing in if cond-1\n");
+               return 0;
+  }
+  if (!check_xcr0_ymm ()) {
+               printf ("Failing in if cond-2\n");
+               return 0;
+  }
+
+  /*  CPUID.(EAX=07H, ECX=0H):EBX.AVX2[bit 5]==1  &&
+     CPUID.(EAX=07H, ECX=0H):EBX.BMI1[bit 3]==1  &&
+     CPUID.(EAX=07H, ECX=0H):EBX.BMI2[bit 8]==1  */
+  run_cpuid (7, 0, abcd);
+  if ((abcd[1] & avx2_bmi12_mask) != avx2_bmi12_mask) {
+      printf ("Failing in if cond-3\n");
+      return 0;
+    }
+  /* CPUID.(EAX=80000001H):ECX.LZCNT[bit 5]==1 */
+  run_cpuid (0x80000001, 0, abcd);
+  if ((abcd[2] & (1 << 5)) == 0) {
+      printf ("Failing in if cond-4\n");
+      return 0;
+    }
+  /* CPUID.(EAX=07H, ECX=0H).EBX.RTM[bit 11]==1 */
+  run_cpuid (7, 0, abcd);
+  if ((abcd[1] & (1 << 11)) == 0) {
+      printf ("Failing in if cond-5\n");
+      return 0;
+    }
+  /* CPUID.(EAX=07H, ECX=0H).EBX.HLE[bit 4]==1 */
+  run_cpuid (7, 0, abcd);
+  if ((abcd[1] & (1 << 4)) == 0) {
+      printf ("Failing in if cond-6\n");
+      return 0;
+    }
+  return 1;
+}
+
+int
+can_use_intel_core_4th_gen_features (void)
+{
+  static int the_4th_gen_features_available = -1;
+  /* test is performed once */
+  if (the_4th_gen_features_available < 0)
+    the_4th_gen_features_available = check_4th_gen_intel_core_features ();
+  return the_4th_gen_features_available;
+}
+
+void
+rtm_init (void)
+{
+  naborted = (rte_atomic64_t) RTE_ATOMIC64_INIT (0);
+
+  //RTE_ATOMIC64_INIT(naborted);
+} int
+
+rtm_lock (void)
+{
+  int nretries = 0;
+  while (1) {
+      ++nretries;
+      unsigned int status = _xbegin ();
+      if (status == _XBEGIN_STARTED) {
+               if (!is_hle_locked ())
+                       return 1;               // successfully started transaction
+               // started transaction but someone executes the transaction section
+               // non-speculatively (acquired the fall-back lock)
+               _xabort (0xff); // abort with code 0xff
+       }
+      // abort handler
+      rte_atomic64_inc (&naborted);    // do abort statistics
+      printf
+       ("DEBUG: Transaction aborted: %d time(s) with the status: %u\n",
+        nretries, status);
+      // handle _xabort(0xff) from above
+      if ((status & _XABORT_EXPLICIT)
+               && _XABORT_CODE (status) == 0xff && !(status & _XABORT_NESTED)) {
+               while (is_hle_locked ())
+                       _mm_pause ();   // wait until lock is free
+       }
+      else if (!(status & _XABORT_RETRY))
+       break;                  // take the fall-back lock if the retry abort flag is not set
+      if (nretries >= max_retries)
+       break;                  // too many retries, take the fall-back lock
+    }
+  hle_lock ();
+  return 1;
+}
+
+int
+rtm_unlock (void)
+{
+  if (is_hle_locked ())
+    hle_release ();
+
+  else
+    _xend ();
+  return 1;
+}
+
+int
+is_rtm_locked (void)
+{
+  return ((int) _xtest ());
+}
diff --git a/common/VIL/l2l3_stack/tsx.h b/common/VIL/l2l3_stack/tsx.h
new file mode 100644 (file)
index 0000000..8b74816
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef _TSX_H_
+#define _RSX_H_
+#include <rte_atomic.h>
+#define TRUE 1
+#define FALSE 0
+
+volatile int mutex_val;
+
+rte_atomic64_t naborted;
+
+void hle_init(void);
+int hle_lock(void);
+int hle_release(void);
+int is_hle_locked(void);
+
+void rtm_init(void);
+int rtm_lock(void);
+int rtm_unlock(void);
+int is_rtm_locked(void);
+
+int can_use_intel_core_4th_gen_features(void);
+
+#endif
diff --git a/common/VIL/pipeline_arpicmp/pipeline_arpicmp.c b/common/VIL/pipeline_arpicmp/pipeline_arpicmp.c
new file mode 100644 (file)
index 0000000..1ea9e74
--- /dev/null
@@ -0,0 +1,2118 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <cmdline_parse.h>
+#include <cmdline_parse_num.h>
+#include <cmdline_parse_string.h>
+#include <cmdline_parse_ipaddr.h>
+#include <cmdline_parse_etheraddr.h>
+
+#include "app.h"
+#include "pipeline_common_fe.h"
+#include "pipeline_arpicmp_be.h"
+#include "pipeline_arpicmp.h"
+#include "vnf_common.h"
+
+#include "app.h"
+#include "vnf_common.h"
+#ifndef VNF_ACL
+#include "lib_arp.h"
+#endif
+
+#include <rte_ip.h>
+#include <rte_udp.h>
+#include <rte_string_fns.h>
+
+uint16_t verbose_level = 1; /**< should be Silent by default. */
+uint16_t nb_pkt_per_burst = DEF_PKT_BURST; /**< Number of packets per burst. */
+
+/*
+ * Work-around of a compilation error with ICC on invocations of the
+ * rte_be_to_cpu_16() function.
+ */
+#ifdef __GCC__
+#define RTE_BE_TO_CPU_16(be_16_v)  rte_be_to_cpu_16((be_16_v))
+#define RTE_CPU_TO_BE_16(cpu_16_v) rte_cpu_to_be_16((cpu_16_v))
+#else
+#if RTE_BYTE_ORDER == RTE_BIG_ENDIAN
+#define RTE_BE_TO_CPU_16(be_16_v)  (be_16_v)
+#define RTE_CPU_TO_BE_16(cpu_16_v) (cpu_16_v)
+#else
+#define RTE_BE_TO_CPU_16(be_16_v) \
+       ((uint16_t) ((((be_16_v) & 0xFF) << 8) | ((be_16_v) >> 8)))
+#define RTE_CPU_TO_BE_16(cpu_16_v) \
+       ((uint16_t) ((((cpu_16_v) & 0xFF) << 8) | ((cpu_16_v) >> 8)))
+#endif
+#endif
+
+/*
+ * arp add
+ */
+
+struct cmd_arp_add_result {
+       cmdline_fixed_string_t p_string;
+       uint32_t p;
+       cmdline_fixed_string_t arpadd_string;
+       uint32_t port_id;
+       cmdline_ipaddr_t ip;
+       struct ether_addr macaddr;
+
+};
+
+static void
+cmd_arp_add_parsed(void *parsed_result,
+                        __rte_unused struct cmdline *cl, __rte_unused void *data)
+{
+       struct cmd_arp_add_result *params = parsed_result;
+       uint8_t ipv6[16];
+
+       #if 0
+       struct pipeline_arp_icmp_arp_key key;
+       key.type = PIPELINE_ARP_ICMP_ARP_IPV4;
+       key.key.ipv4.port_id = params->port_id;
+       key.key.ipv4.ip = rte_cpu_to_be_32(params->ip.addr.ipv4.s_addr);
+       populate_arp_entry(&req->macaddr, rte_bswap32(req->key.key.ipv4.ip),
+               req->key.key.ipv4.port_id);
+       #endif
+       if (params->ip.family == AF_INET) {
+               populate_arp_entry(&params->macaddr,
+                                        rte_cpu_to_be_32(params->ip.addr.
+                                                               ipv4.s_addr),
+                                        params->port_id
+                               #ifndef VNF_ACL
+                                        , STATIC_ARP
+                               #endif
+                               );
+       } else {
+               memcpy(ipv6, params->ip.addr.ipv6.s6_addr, 16);
+               populate_nd_entry(&params->macaddr, ipv6, params->port_id
+                               #ifndef VNF_ACL
+                               , STATIC_ND
+                               #endif
+                               );
+       }
+}
+
+static cmdline_parse_token_string_t cmd_arp_add_p_string =
+TOKEN_STRING_INITIALIZER(struct cmd_arp_add_result, p_string,
+                        "p");
+
+static cmdline_parse_token_num_t cmd_arp_add_p =
+TOKEN_NUM_INITIALIZER(struct cmd_arp_add_result, p, UINT32);
+
+static cmdline_parse_token_string_t cmd_arp_add_arp_string =
+TOKEN_STRING_INITIALIZER(struct cmd_arp_add_result, arpadd_string, "arpadd");
+
+static cmdline_parse_token_num_t cmd_arp_add_port_id =
+TOKEN_NUM_INITIALIZER(struct cmd_arp_add_result, port_id, UINT32);
+
+static cmdline_parse_token_ipaddr_t cmd_arp_add_ip =
+TOKEN_IPADDR_INITIALIZER(struct cmd_arp_add_result, ip);
+
+static cmdline_parse_token_etheraddr_t cmd_arp_add_macaddr =
+TOKEN_ETHERADDR_INITIALIZER(struct cmd_arp_add_result, macaddr);
+
+static cmdline_parse_inst_t cmd_arp_add = {
+       .f = cmd_arp_add_parsed,
+       .data = NULL,
+       .help_str = "ARP add",
+       .tokens = {
+                        (void *)&cmd_arp_add_p_string,
+                        (void *)&cmd_arp_add_p,
+                        (void *)&cmd_arp_add_arp_string,
+                        (void *)&cmd_arp_add_port_id,
+                        (void *)&cmd_arp_add_ip,
+                        (void *)&cmd_arp_add_macaddr,
+                        NULL,
+                        },
+};
+
+/*
+ * arp del
+ */
+
+struct cmd_arp_del_result {
+       cmdline_fixed_string_t p_string;
+       uint32_t p;
+       cmdline_fixed_string_t arp_string;
+       uint32_t port_id;
+       cmdline_ipaddr_t ip;
+};
+
+static void
+cmd_arp_del_parsed(void *parsed_result,
+                        __rte_unused struct cmdline *cl, __rte_unused void *data)
+{
+       struct cmd_arp_del_result *params = parsed_result;
+       uint8_t ipv6[16];
+
+       #if 0
+       struct pipeline_arp_icmp_arp_key key;
+       key.type = PIPELINE_ARP_ICMP_ARP_IPV4;
+       key.key.ipv4.ip = rte_cpu_to_be_32(params->ip.addr.ipv4.s_addr);
+       key.key.ipv4.port_id = params->port_id;
+       remove_arp_entry(rte_bswap32(req->key.key.ipv4.ip),
+               req->key.key.ipv4.port_id);
+       #endif
+       if (params->ip.family == AF_INET) {
+               remove_arp_entry(rte_cpu_to_be_32(params->ip.addr.ipv4.s_addr),
+                                params->port_id
+                               #ifndef VNF_ACL
+                                , NULL
+                               #endif
+                                );
+       } else {
+               memcpy(ipv6, params->ip.addr.ipv6.s6_addr, 16);
+               remove_nd_entry_ipv6(ipv6, params->port_id);
+       }
+}
+
+static cmdline_parse_token_string_t cmd_arp_del_p_string =
+TOKEN_STRING_INITIALIZER(struct cmd_arp_del_result, p_string,
+                        "p");
+
+static cmdline_parse_token_num_t cmd_arp_del_p =
+TOKEN_NUM_INITIALIZER(struct cmd_arp_del_result, p, UINT32);
+
+static cmdline_parse_token_string_t cmd_arp_del_arp_string =
+TOKEN_STRING_INITIALIZER(struct cmd_arp_del_result, arp_string, "arpdel");
+
+static cmdline_parse_token_num_t cmd_arp_del_port_id =
+TOKEN_NUM_INITIALIZER(struct cmd_arp_del_result, port_id, UINT32);
+
+static cmdline_parse_token_ipaddr_t cmd_arp_del_ip =
+TOKEN_IPADDR_INITIALIZER(struct cmd_arp_del_result, ip);
+
+static cmdline_parse_inst_t cmd_arp_del = {
+       .f = cmd_arp_del_parsed,
+       .data = NULL,
+       .help_str = "ARP delete",
+       .tokens = {
+                        (void *)&cmd_arp_del_p_string,
+                        (void *)&cmd_arp_del_p,
+                        (void *)&cmd_arp_del_arp_string,
+                        (void *)&cmd_arp_del_port_id,
+                        (void *)&cmd_arp_del_ip,
+                        NULL,
+                        },
+};
+
+/*
+ * arp req
+ */
+
+/*Re-uses delete structures*/
+
+static void
+cmd_arp_req_parsed(void *parsed_result,
+                        __rte_unused struct cmdline *cl, __rte_unused void *data)
+{
+       struct cmd_arp_del_result *params = parsed_result;
+       /*struct app_params *app = data;*/
+
+       struct arp_key_ipv4 key;
+/*     int status;*/
+
+/*     key.type = ARP_IPV4;*/
+/*     key.key.ipv4.ip = rte_cpu_to_be_32(params->ip.addr.ipv4.s_addr);*/
+/*     key.key.ipv4.port_id = params->port_id;*/
+       key.ip = rte_cpu_to_be_32(params->ip.addr.ipv4.s_addr);
+       key.port_id = params->port_id;
+       key.filler1 = 0;
+       key.filler2 = 0;
+       key.filler3 = 0;
+
+       struct arp_entry_data *arp_data = retrieve_arp_entry(key);
+
+       if (arp_data) {
+               if (ARPICMP_DEBUG)
+                       printf("ARP entry exists for ip 0x%x, port %d\n",
+                                                params->ip.addr.ipv4.s_addr, params->port_id);
+               return;
+       }
+       /* else request an arp*/
+       if (ARPICMP_DEBUG)
+               printf("ARP - requesting arp for ip 0x%x, port %d\n",
+                                        params->ip.addr.ipv4.s_addr, params->port_id);
+
+       #ifdef VNF_ACL
+       request_arp_wrap(params->port_id, params->ip.addr.ipv4.s_addr);
+       #else
+       request_arp(params->port_id, params->ip.addr.ipv4.s_addr);
+       #endif
+       /*give pipeline number too*/
+}
+
+static cmdline_parse_token_string_t cmd_arp_req_string =
+TOKEN_STRING_INITIALIZER(struct cmd_arp_del_result, arp_string, "arpreq");
+
+static cmdline_parse_inst_t cmd_arp_req = {
+       .f = cmd_arp_req_parsed,
+       .data = NULL,
+       .help_str = "ARP request",
+       .tokens = {
+                        (void *)&cmd_arp_del_p_string,
+                        (void *)&cmd_arp_del_p,
+                        (void *)&cmd_arp_req_string,
+                        (void *)&cmd_arp_del_port_id,
+                        (void *)&cmd_arp_del_ip,
+                        NULL,
+                        },
+};
+
+/*
+ * arpicmp echo req
+ */
+
+/*Re-uses delete structures*/
+
+static void
+cmd_icmp_echo_req_parsed(void *parsed_result,
+                        __rte_unused struct cmdline *cl,
+                        __rte_unused void *data)
+{
+       struct cmd_arp_del_result *params = parsed_result;
+
+       if (ARPICMP_DEBUG)
+               printf("Echo Req Handler ip %x, port %d\n",
+                                        params->ip.addr.ipv4.s_addr, params->port_id);
+
+       request_echo(params->port_id, params->ip.addr.ipv4.s_addr);
+}
+
+static cmdline_parse_token_string_t cmd_icmp_echo_req_string =
+TOKEN_STRING_INITIALIZER(struct cmd_arp_del_result, arp_string, "icmpecho");
+
+static cmdline_parse_inst_t cmd_icmp_echo_req = {
+       .f = cmd_icmp_echo_req_parsed,
+       .data = NULL,
+       .help_str = "ICMP echo request",
+       .tokens = {
+                        (void *)&cmd_arp_del_p_string,
+                        (void *)&cmd_arp_del_p,
+                        (void *)&cmd_icmp_echo_req_string,
+                        (void *)&cmd_arp_del_port_id,
+                        (void *)&cmd_arp_del_ip,
+                        NULL,
+                        },
+};
+
+/*
+ * arp ls
+ */
+
+struct cmd_arp_ls_result {
+       cmdline_fixed_string_t p_string;
+       uint32_t p;
+       cmdline_fixed_string_t arp_string;
+};
+
+static void
+cmd_arp_ls_parsed(__rte_unused void *parsed_result,
+                       __rte_unused struct cmdline *cl, __rte_unused void *data)
+{
+       printf("\nARP table ...\n");
+       printf("-------------\n");
+       print_arp_table();
+
+       printf
+                       ("............................................................\n");
+
+       printf("\nND IPv6 table:\n");
+       printf("--------------\n");
+       print_nd_table();
+}
+
+static cmdline_parse_token_string_t cmd_arp_ls_p_string =
+TOKEN_STRING_INITIALIZER(struct cmd_arp_ls_result, p_string,
+                        "p");
+
+static cmdline_parse_token_num_t cmd_arp_ls_p =
+TOKEN_NUM_INITIALIZER(struct cmd_arp_ls_result, p, UINT32);
+
+static cmdline_parse_token_string_t cmd_arp_ls_arp_string =
+TOKEN_STRING_INITIALIZER(struct cmd_arp_ls_result, arp_string,
+                        "arpls");
+
+static cmdline_parse_inst_t cmd_arp_ls = {
+       .f = cmd_arp_ls_parsed,
+       .data = NULL,
+       .help_str = "ARP list",
+       .tokens = {
+                        (void *)&cmd_arp_ls_p_string,
+                        (void *)&cmd_arp_ls_p,
+                        (void *)&cmd_arp_ls_arp_string,
+                        NULL,
+                        },
+};
+
+/*
+ * show ports info
+ */
+
+struct cmd_show_ports_info_result {
+       cmdline_fixed_string_t p_string;
+       uint32_t p;
+       cmdline_fixed_string_t arp_string;
+};
+
+static void
+cmd_show_ports_info_parsed(__rte_unused void *parsed_result,
+                                __rte_unused struct cmdline *cl,
+                                __rte_unused void *data)
+{
+       show_ports_info();
+}
+
+static cmdline_parse_token_string_t cmd_show_ports_info_string =
+TOKEN_STRING_INITIALIZER(struct cmd_arp_ls_result, arp_string,
+                        "showPortsInfo");
+
+static cmdline_parse_inst_t cmd_show_ports_info = {
+       .f = cmd_show_ports_info_parsed,
+       .data = NULL,
+       .help_str = "show ports info",
+       .tokens = {
+                        (void *)&cmd_arp_ls_p_string,
+                        (void *)&cmd_arp_ls_p,
+                        (void *)&cmd_show_ports_info_string,
+                        NULL,
+                        },
+};
+
+#ifndef VNF_ACL
+struct cmd_arp_dbg_result {
+       cmdline_fixed_string_t arpdbg_str;
+       uint32_t flag;
+};
+
+cmdline_parse_token_string_t cmd_arp_dbg_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_arp_dbg_result, arpdbg_str,
+               "arpdbg");
+cmdline_parse_token_num_t cmd_arp_dbg_flag =
+       TOKEN_NUM_INITIALIZER(struct cmd_arp_dbg_result, flag, UINT32);
+
+static void
+cmd_arp_dbg_parse(
+               void *parsed_result,
+               __attribute__((unused)) struct cmdline *cl,
+               __rte_unused void *data)
+{
+       struct cmd_arp_dbg_result *params = parsed_result;
+       if(params)
+       {
+               set_arpdebug(params->flag);
+       }
+       else
+       {
+               printf("%s: Params is NULL",__FUNCTION__);
+       }
+}
+
+cmdline_parse_inst_t cmd_arp_dbg = {
+       .f = cmd_arp_dbg_parse,
+       .data = NULL,
+       .help_str = "Turn on/off(1/0) arp debug",
+       .tokens = {
+               (void *)&cmd_arp_dbg_string,
+               (void *)&cmd_arp_dbg_flag,
+               NULL,
+       },
+};
+
+struct cmd_arp_timer_result {
+       cmdline_fixed_string_t arptimer_str;
+       uint32_t arptimer_val;
+};
+
+cmdline_parse_token_string_t cmd_arp_timer_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_arp_timer_result, arptimer_str,
+               "arptimerexpiry");
+cmdline_parse_token_num_t cmd_arp_timer_val =
+       TOKEN_NUM_INITIALIZER(struct cmd_arp_timer_result, arptimer_val, UINT32);
+
+static void
+cmd_arp_timer_parse(
+               void *parsed_result,
+               __attribute__((unused)) struct cmdline *cl,
+               __rte_unused void *data)
+{
+       struct cmd_arp_timer_result *params = parsed_result;
+       if(params)
+       {
+               set_arptimeout(params->arptimer_val);
+       }
+       else
+       {
+               printf("%s: Params is NULL",__FUNCTION__);
+       }
+}
+
+cmdline_parse_inst_t cmd_arp_timer = {
+       .f = cmd_arp_timer_parse,
+       .data = NULL,
+       .help_str = "Timer expiry val by def 10 sec",
+       .tokens = {
+               (void *)&cmd_arp_timer_string,
+               (void *)&cmd_arp_timer_val,
+               NULL,
+       },
+};
+#endif
+
+/*
+ * Forwarding of packets in I/O mode.
+ * Forward packets "as-is".
+ * This is the fastest possible forwarding operation, as it does not access
+ * to packets data.
+ */
+       static void
+pkt_burst_io_forward(struct fwd_stream *fs)
+{
+       struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+       uint16_t nb_rx;
+       uint16_t nb_tx;
+
+       #ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+       uint64_t start_tsc;
+       uint64_t end_tsc;
+       uint64_t core_cycles;
+       #endif
+
+       #ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+       start_tsc = rte_rdtsc();
+       #endif
+
+       /*
+        * Receive a burst of packets and forward them.
+        */
+       nb_rx = rte_eth_rx_burst(fs->rx_port, fs->rx_queue, pkts_burst,
+                       nb_pkt_per_burst);
+       if (unlikely(nb_rx == 0))
+               return;
+
+       #ifdef RTE_TEST_PMD_RECORD_BURST_STATS
+       fs->rx_burst_stats.pkt_burst_spread[nb_rx]++;
+       #endif
+
+       fs->rx_packets += nb_rx;
+       nb_tx = rte_eth_tx_burst(fs->tx_port, fs->tx_queue, pkts_burst, nb_rx);
+       fs->tx_packets += nb_tx;
+
+       #ifdef RTE_TEST_PMD_RECORD_BURST_STATS
+       fs->tx_burst_stats.pkt_burst_spread[nb_tx]++;
+       #endif
+
+       if (unlikely(nb_tx < nb_rx)) {
+               fs->fwd_dropped += (nb_rx - nb_tx);
+               do {
+                       rte_pktmbuf_free(pkts_burst[nb_tx]);
+               } while (++nb_tx < nb_rx);
+       }
+
+       #ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+       end_tsc = rte_rdtsc();
+       core_cycles = (end_tsc - start_tsc);
+       fs->core_cycles = (uint64_t) (fs->core_cycles + core_cycles);
+       #endif
+}
+
+
+struct fwd_engine io_fwd_engine = {
+       .fwd_mode_name  = "io",
+       .port_fwd_begin = NULL,
+       .port_fwd_end   = NULL,
+       .packet_fwd     = pkt_burst_io_forward,
+};
+
+static inline void print_ether_addr(
+       const char *what,
+       struct ether_addr *eth_addr)
+{
+       char buf[ETHER_ADDR_FMT_SIZE];
+       ether_format_addr(buf, ETHER_ADDR_FMT_SIZE, eth_addr);
+       printf("%s%s", what, buf);
+}
+
+/*
+ * Received a burst of packets.
+ */
+       static void
+pkt_burst_receive(struct fwd_stream *fs)
+{
+       struct rte_mbuf  *pkts_burst[MAX_PKT_BURST];
+       struct rte_mbuf  *mb;
+       struct ether_hdr *eth_hdr;
+       uint16_t eth_type;
+       uint64_t ol_flags;
+       uint16_t nb_rx;
+       uint16_t i, packet_type;
+       uint16_t is_encapsulation;
+
+       #ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+       uint64_t start_tsc;
+       uint64_t end_tsc;
+       uint64_t core_cycles;
+       #endif
+
+       #ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+       start_tsc = rte_rdtsc();
+       #endif
+
+       /*
+        * Receive a burst of packets.
+        */
+       nb_rx = rte_eth_rx_burst(fs->rx_port, fs->rx_queue, pkts_burst,
+                       nb_pkt_per_burst);
+       if (unlikely(nb_rx == 0))
+               return;
+
+       #ifdef RTE_TEST_PMD_RECORD_BURST_STATS
+       fs->rx_burst_stats.pkt_burst_spread[nb_rx]++;
+       #endif
+
+       fs->rx_packets += nb_rx;
+
+       /*
+        * Dump each received packet if verbose_level > 0.
+        */
+       if (verbose_level > 0)
+               printf("port %u/queue %u: received %u packets\n",
+                               (unsigned int) fs->rx_port,
+                               (unsigned int) fs->rx_queue,
+                               (unsigned int) nb_rx);
+       for (i = 0; i < nb_rx; i++) {
+               mb = pkts_burst[i];
+               if (verbose_level == 0) {
+                       rte_pktmbuf_free(mb);
+                       continue;
+               }
+               eth_hdr = rte_pktmbuf_mtod(mb, struct ether_hdr *);
+               eth_type = RTE_BE_TO_CPU_16(eth_hdr->ether_type);
+               ol_flags = mb->ol_flags;
+               packet_type = mb->packet_type;
+               is_encapsulation = RTE_ETH_IS_TUNNEL_PKT(packet_type);
+
+               print_ether_addr("  src=", &eth_hdr->s_addr);
+               print_ether_addr(" - dst=", &eth_hdr->d_addr);
+               printf(" - type=0x%04x - length=%u - nb_segs=%d",
+                               eth_type, (unsigned int) mb->pkt_len,
+                               (int)mb->nb_segs);
+               if (ol_flags & PKT_RX_RSS_HASH) {
+                       printf(" - RSS hash=0x%x", (unsigned int)
+                               mb->hash.rss);
+                       printf(" - RSS queue=0x%x", (unsigned int)
+                               fs->rx_queue);
+               } else if (ol_flags & PKT_RX_FDIR) {
+                       printf(" - FDIR matched ");
+                       if (ol_flags & PKT_RX_FDIR_ID)
+                               printf("ID=0x%x",
+                                               mb->hash.fdir.hi);
+                       else if (ol_flags & PKT_RX_FDIR_FLX)
+                               printf("flex bytes=0x%08x %08x",
+                                       mb->hash.fdir.hi, mb->hash.fdir.lo);
+                       else
+                               printf("hash=0x%x ID=0x%x ",
+                                       mb->hash.fdir.hash, mb->hash.fdir.id);
+               }
+               if (ol_flags & PKT_RX_VLAN_PKT)
+                       printf(" - VLAN tci=0x%x", mb->vlan_tci);
+               if (ol_flags & PKT_RX_QINQ_PKT)
+                       printf(" - QinQ VLAN tci=0x%x, VLAN tci outer=0x%x",
+                                       mb->vlan_tci, mb->vlan_tci_outer);
+               if (mb->packet_type) {
+                       uint32_t ptype;
+
+                       /* (outer) L2 packet type */
+                       ptype = mb->packet_type & RTE_PTYPE_L2_MASK;
+                       switch (ptype) {
+                       case RTE_PTYPE_L2_ETHER:
+                               printf(" - (outer) L2 type: ETHER");
+                               break;
+                       case RTE_PTYPE_L2_ETHER_TIMESYNC:
+                               printf(" - (outer) L2 type: ETHER_Timesync");
+                               break;
+                       case RTE_PTYPE_L2_ETHER_ARP:
+                               printf(" - (outer) L2 type: ETHER_ARP");
+                               break;
+                       case RTE_PTYPE_L2_ETHER_LLDP:
+                               printf(" - (outer) L2 type: ETHER_LLDP");
+                               break;
+                       default:
+                               printf(" - (outer) L2 type: Unknown");
+                               break;
+                       }
+
+                       /* (outer) L3 packet type */
+                       ptype = mb->packet_type & RTE_PTYPE_L3_MASK;
+                       switch (ptype) {
+                       case RTE_PTYPE_L3_IPV4:
+                               printf(" - (outer) L3 type: IPV4");
+                               break;
+                       case RTE_PTYPE_L3_IPV4_EXT:
+                               printf(" - (outer) L3 type: IPV4_EXT");
+                               break;
+                       case RTE_PTYPE_L3_IPV6:
+                               printf(" - (outer) L3 type: IPV6");
+                               break;
+                       case RTE_PTYPE_L3_IPV4_EXT_UNKNOWN:
+                               printf(" - (outer) L3 type: IPV4_EXT_UNKNOWN");
+                               break;
+                       case RTE_PTYPE_L3_IPV6_EXT:
+                               printf(" - (outer) L3 type: IPV6_EXT");
+                               break;
+                       case RTE_PTYPE_L3_IPV6_EXT_UNKNOWN:
+                               printf(" - (outer) L3 type: IPV6_EXT_UNKNOWN");
+                               break;
+                       default:
+                               printf(" - (outer) L3 type: Unknown");
+                               break;
+                       }
+
+                       /* (outer) L4 packet type */
+                       ptype = mb->packet_type & RTE_PTYPE_L4_MASK;
+                       switch (ptype) {
+                       case RTE_PTYPE_L4_TCP:
+                               printf(" - (outer) L4 type: TCP");
+                               break;
+                       case RTE_PTYPE_L4_UDP:
+                               printf(" - (outer) L4 type: UDP");
+                               break;
+                       case RTE_PTYPE_L4_FRAG:
+                               printf(" - (outer) L4 type: L4_FRAG");
+                               break;
+                       case RTE_PTYPE_L4_SCTP:
+                               printf(" - (outer) L4 type: SCTP");
+                               break;
+                       case RTE_PTYPE_L4_ICMP:
+                               printf(" - (outer) L4 type: ICMP");
+                               break;
+                       case RTE_PTYPE_L4_NONFRAG:
+                               printf(" - (outer) L4 type: L4_NONFRAG");
+                               break;
+                       default:
+                               printf(" - (outer) L4 type: Unknown");
+                               break;
+                       }
+
+                       /* packet tunnel type */
+                       ptype = mb->packet_type & RTE_PTYPE_TUNNEL_MASK;
+                       switch (ptype) {
+                       case RTE_PTYPE_TUNNEL_IP:
+                               printf(" - Tunnel type: IP");
+                               break;
+                       case RTE_PTYPE_TUNNEL_GRE:
+                               printf(" - Tunnel type: GRE");
+                               break;
+                       case RTE_PTYPE_TUNNEL_VXLAN:
+                               printf(" - Tunnel type: VXLAN");
+                               break;
+                       case RTE_PTYPE_TUNNEL_NVGRE:
+                               printf(" - Tunnel type: NVGRE");
+                               break;
+                       case RTE_PTYPE_TUNNEL_GENEVE:
+                               printf(" - Tunnel type: GENEVE");
+                               break;
+                       case RTE_PTYPE_TUNNEL_GRENAT:
+                               printf(" - Tunnel type: GRENAT");
+                               break;
+                       default:
+                               printf(" - Tunnel type: Unknown");
+                               break;
+                       }
+
+                       /* inner L2 packet type */
+                       ptype = mb->packet_type & RTE_PTYPE_INNER_L2_MASK;
+                       switch (ptype) {
+                       case RTE_PTYPE_INNER_L2_ETHER:
+                               printf(" - Inner L2 type: ETHER");
+                               break;
+                       case RTE_PTYPE_INNER_L2_ETHER_VLAN:
+                               printf(" - Inner L2 type: ETHER_VLAN");
+                               break;
+                       default:
+                               printf(" - Inner L2 type: Unknown");
+                               break;
+                       }
+                       /* inner L3 packet type */
+                       ptype = mb->packet_type & RTE_PTYPE_INNER_L3_MASK;
+                       switch (ptype) {
+                       case RTE_PTYPE_INNER_L3_IPV4:
+                               printf(" - Inner L3 type: IPV4");
+                               break;
+                       case RTE_PTYPE_INNER_L3_IPV4_EXT:
+                               printf(" - Inner L3 type: IPV4_EXT");
+                               break;
+                       case RTE_PTYPE_INNER_L3_IPV6:
+                               printf(" - Inner L3 type: IPV6");
+                               break;
+                       case RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN:
+                               printf(" - Inner L3 type: "
+                                       "IPV4_EXT_UNKNOWN");
+                               break;
+                       case RTE_PTYPE_INNER_L3_IPV6_EXT:
+                                       printf(" - Inner L3 type: IPV6_EXT");
+                               break;
+                       case RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN:
+                               printf(" - Inner L3 type: "
+                                       "IPV6_EXT_UNKNOWN");
+                               break;
+                       default:
+                               printf(" - Inner L3 type: Unknown");
+                               break;
+                       }
+
+                       /* inner L4 packet type */
+                       ptype = mb->packet_type & RTE_PTYPE_INNER_L4_MASK;
+                       switch (ptype) {
+                       case RTE_PTYPE_INNER_L4_TCP:
+                               printf(" - Inner L4 type: TCP");
+                               break;
+                       case RTE_PTYPE_INNER_L4_UDP:
+                               printf(" - Inner L4 type: UDP");
+                               break;
+                       case RTE_PTYPE_INNER_L4_FRAG:
+                               printf(" - Inner L4 type: L4_FRAG");
+                               break;
+                       case RTE_PTYPE_INNER_L4_SCTP:
+                               printf(" - Inner L4 type: SCTP");
+                               break;
+                       case RTE_PTYPE_INNER_L4_ICMP:
+                               printf(" - Inner L4 type: ICMP");
+                               break;
+                       case RTE_PTYPE_INNER_L4_NONFRAG:
+                               printf(" - Inner L4 type: L4_NONFRAG");
+                               break;
+                       default:
+                               printf(" - Inner L4 type: Unknown");
+                               break;
+                       }
+                       printf("\n");
+               } else
+                       printf("Unknown packet type\n");
+               if (is_encapsulation) {
+                       struct ipv4_hdr *ipv4_hdr;
+                       struct ipv6_hdr *ipv6_hdr;
+                       struct udp_hdr *udp_hdr;
+                       uint8_t l2_len;
+                       uint8_t l3_len;
+                       uint8_t l4_len;
+                       uint8_t l4_proto;
+                       struct  vxlan_hdr *vxlan_hdr;
+
+                       l2_len  = sizeof(struct ether_hdr);
+
+                       /* Do not support ipv4 option field */
+                       if (RTE_ETH_IS_IPV4_HDR(packet_type)) {
+                               l3_len = sizeof(struct ipv4_hdr);
+                               ipv4_hdr = rte_pktmbuf_mtod_offset(mb,
+                                               struct ipv4_hdr *,
+                                               l2_len);
+                               l4_proto = ipv4_hdr->next_proto_id;
+                       } else {
+                               l3_len = sizeof(struct ipv6_hdr);
+                               ipv6_hdr = rte_pktmbuf_mtod_offset(mb,
+                                               struct ipv6_hdr *,
+                                               l2_len);
+                               l4_proto = ipv6_hdr->proto;
+                       }
+                       if (l4_proto == IPPROTO_UDP) {
+                               udp_hdr = rte_pktmbuf_mtod_offset(mb,
+                                               struct udp_hdr *,
+                                               l2_len + l3_len);
+                               l4_len = sizeof(struct udp_hdr);
+                               vxlan_hdr = rte_pktmbuf_mtod_offset(mb,
+                                               struct vxlan_hdr *,
+                                               l2_len + l3_len + l4_len);
+
+                               printf(" - VXLAN packet: packet type =%d, "
+                                       "Destination UDP port =%d, VNI = %d",
+                                       packet_type,
+                                       RTE_BE_TO_CPU_16(udp_hdr->dst_port),
+                                       rte_be_to_cpu_32(
+                                               vxlan_hdr->vx_vni) >> 8);
+                       }
+               }
+               printf(" - Receive queue=0x%x", (unsigned int) fs->rx_queue);
+               printf("\n");
+               if (ol_flags != 0) {
+                       unsigned int rxf;
+                       const char *name;
+
+                       for (rxf = 0; rxf < sizeof(mb->ol_flags) * 8; rxf++) {
+                               if ((ol_flags & (1ULL << rxf)) == 0)
+                                       continue;
+                               name = rte_get_rx_ol_flag_name(1ULL << rxf);
+                               if (name == NULL)
+                                       continue;
+                               printf("  %s\n", name);
+                       }
+               }
+               rte_pktmbuf_free(mb);
+       }
+
+       #ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+       end_tsc = rte_rdtsc();
+       core_cycles = (end_tsc - start_tsc);
+       fs->core_cycles = (uint64_t) (fs->core_cycles + core_cycles);
+       #endif
+}
+
+struct fwd_engine rx_only_engine = {
+       .fwd_mode_name  = "rxonly",
+       .port_fwd_begin = NULL,
+       .port_fwd_end   = NULL,
+       .packet_fwd     = pkt_burst_receive,
+};
+
+/* *** SET FORWARDING MODE *** */
+struct cmd_set_fwd_mode_result {
+       cmdline_fixed_string_t set;
+       cmdline_fixed_string_t fwd;
+       cmdline_fixed_string_t mode;
+};
+
+/*
+ * Forwarding engines.
+ */
+struct fwd_engine *fwd_engines[] = {
+       &io_fwd_engine,
+       #if 0
+       &mac_fwd_engine,
+       &mac_retry_fwd_engine,
+       &mac_swap_engine,
+       &flow_gen_engine,
+       #endif
+       &rx_only_engine,
+       #if 0
+       &tx_only_engine,
+       &csum_fwd_engine,
+       &icmp_echo_engine,
+       #ifdef RTE_LIBRTE_IEEE1588
+       &ieee1588_fwd_engine,
+       #endif
+       #endif
+       NULL,
+};
+
+struct fwd_engine *cur_fwd_eng = &io_fwd_engine; /**< IO mode by default. */
+
+void set_pkt_forwarding_mode(const char *fwd_mode_name)
+{
+       struct fwd_engine *fwd_eng;
+       unsigned int i;
+
+       i = 0;
+       while ((fwd_eng = fwd_engines[i]) != NULL) {
+               if (!strcmp(fwd_eng->fwd_mode_name, fwd_mode_name)) {
+                       printf("Set %s packet forwarding mode\n",
+                                       fwd_mode_name);
+                       cur_fwd_eng = fwd_eng;
+                       return;
+               }
+               i++;
+       }
+       printf("Invalid %s packet forwarding mode\n", fwd_mode_name);
+}
+
+static void cmd_set_fwd_mode_parsed(void *parsed_result,
+               __attribute__((unused)) struct cmdline *cl,
+               __attribute__((unused)) void *data)
+{
+       struct cmd_set_fwd_mode_result *res = parsed_result;
+
+       set_pkt_forwarding_mode(res->mode);
+}
+
+cmdline_parse_token_string_t cmd_setfwd_set =
+TOKEN_STRING_INITIALIZER(struct cmd_set_fwd_mode_result, set, "set");
+cmdline_parse_token_string_t cmd_setfwd_fwd =
+TOKEN_STRING_INITIALIZER(struct cmd_set_fwd_mode_result, fwd, "fwd");
+cmdline_parse_token_string_t cmd_setfwd_mode =
+TOKEN_STRING_INITIALIZER(struct cmd_set_fwd_mode_result, mode,
+               "rxonly" /* defined at init */);
+
+cmdline_parse_inst_t cmd_set_fwd_mode = {
+       .f = cmd_set_fwd_mode_parsed,
+       .data = NULL,
+       .help_str = NULL, /* defined at init */
+       .tokens = {
+               (void *)&cmd_setfwd_set,
+               (void *)&cmd_setfwd_fwd,
+               (void *)&cmd_setfwd_mode,
+               NULL,
+       },
+};
+
+#if 1
+
+static uint16_t
+str2flowtype(char *string)
+{
+       uint8_t i = 0;
+       static const struct {
+       char str[32];
+       uint16_t type;
+       } flowtype_str[] = {
+               {"raw", RTE_ETH_FLOW_RAW},
+               {"ipv4", RTE_ETH_FLOW_IPV4},
+               {"ipv4-frag", RTE_ETH_FLOW_FRAG_IPV4},
+               {"ipv4-tcp", RTE_ETH_FLOW_NONFRAG_IPV4_TCP},
+               {"ipv4-udp", RTE_ETH_FLOW_NONFRAG_IPV4_UDP},
+               {"ipv4-sctp", RTE_ETH_FLOW_NONFRAG_IPV4_SCTP},
+               {"ipv4-other", RTE_ETH_FLOW_NONFRAG_IPV4_OTHER},
+               {"ipv6", RTE_ETH_FLOW_IPV6},
+               {"ipv6-frag", RTE_ETH_FLOW_FRAG_IPV6},
+               {"ipv6-tcp", RTE_ETH_FLOW_NONFRAG_IPV6_TCP},
+               {"ipv6-udp", RTE_ETH_FLOW_NONFRAG_IPV6_UDP},
+               {"ipv6-sctp", RTE_ETH_FLOW_NONFRAG_IPV6_SCTP},
+               {"ipv6-other", RTE_ETH_FLOW_NONFRAG_IPV6_OTHER},
+               {"l2_payload", RTE_ETH_FLOW_L2_PAYLOAD},
+       };
+
+       for (i = 0; i < RTE_DIM(flowtype_str); i++) {
+               if (!strcmp(flowtype_str[i].str, string))
+                       return flowtype_str[i].type;
+       }
+       return RTE_ETH_FLOW_UNKNOWN;
+}
+
+static inline int
+parse_flexbytes(const char *q_arg, uint8_t *flexbytes, uint16_t max_num)
+{
+       char s[256];
+       const char *p, *p0 = q_arg;
+       char *end;
+       unsigned long int_fld;
+       char *str_fld[max_num];
+       int i;
+       unsigned int size;
+       int ret = -1;
+
+       p = strchr(p0, '(');
+       if (p == NULL)
+               return -1;
+       ++p;
+       p0 = strchr(p, ')');
+       if (p0 == NULL)
+               return -1;
+
+       size = p0 - p;
+       if (size >= sizeof(s))
+               return -1;
+
+       snprintf(s, sizeof(s), "%.*s", size, p);
+       ret = rte_strsplit(s, sizeof(s), str_fld, max_num, ',');
+       if (ret < 0 || ret > max_num)
+               return -1;
+       for (i = 0; i < ret; i++) {
+               errno = 0;
+               int_fld = strtoul(str_fld[i], &end, 0);
+               if (errno != 0 || *end != '\0' || int_fld > UINT8_MAX)
+                       return -1;
+               flexbytes[i] = (uint8_t)int_fld;
+       }
+       return ret;
+}
+
+/* *** deal with flow director filter *** */
+struct cmd_flow_director_result {
+       cmdline_fixed_string_t flow_director_filter;
+       uint8_t port_id;
+       cmdline_fixed_string_t mode;
+       cmdline_fixed_string_t mode_value;
+       cmdline_fixed_string_t ops;
+       cmdline_fixed_string_t flow;
+       cmdline_fixed_string_t flow_type;
+       cmdline_fixed_string_t ether;
+       uint16_t ether_type;
+       cmdline_fixed_string_t src;
+       cmdline_ipaddr_t ip_src;
+       uint16_t port_src;
+       cmdline_fixed_string_t dst;
+       cmdline_ipaddr_t ip_dst;
+       uint16_t port_dst;
+       cmdline_fixed_string_t verify_tag;
+       uint32_t verify_tag_value;
+       cmdline_ipaddr_t tos;
+       uint8_t tos_value;
+       cmdline_ipaddr_t proto;
+       uint8_t proto_value;
+       cmdline_ipaddr_t ttl;
+       uint8_t ttl_value;
+       cmdline_fixed_string_t vlan;
+       uint16_t vlan_value;
+       cmdline_fixed_string_t flexbytes;
+       cmdline_fixed_string_t flexbytes_value;
+       cmdline_fixed_string_t pf_vf;
+       cmdline_fixed_string_t drop;
+       cmdline_fixed_string_t queue;
+       uint16_t  queue_id;
+       cmdline_fixed_string_t fd_id;
+       uint32_t  fd_id_value;
+       cmdline_fixed_string_t mac;
+       struct ether_addr mac_addr;
+       cmdline_fixed_string_t tunnel;
+       cmdline_fixed_string_t tunnel_type;
+       cmdline_fixed_string_t tunnel_id;
+       uint32_t tunnel_id_value;
+};
+
+static void
+cmd_flow_director_filter_parsed(void *parsed_result,
+               __attribute__((unused)) struct cmdline *cl,
+               __attribute__((unused)) void *data)
+{
+       struct cmd_flow_director_result *res = parsed_result;
+       struct rte_eth_fdir_filter entry;
+       uint8_t flexbytes[RTE_ETH_FDIR_MAX_FLEXLEN];
+       char *end;
+       unsigned long vf_id;
+       int ret = 0;
+
+       if (enable_hwlb) {
+               printf("Hash Filter is already Defined !\n");
+               printf("Please undefine HWLD flag and define "
+                       "FDIR_FILTER flag\n");
+       return;
+       }
+
+       ret = rte_eth_dev_filter_supported(res->port_id, RTE_ETH_FILTER_FDIR);
+       if (ret < 0) {
+               printf("flow director is not supported on port %u.\n",
+                               res->port_id);
+               return;
+       }
+       memset(flexbytes, 0, sizeof(flexbytes));
+       memset(&entry, 0, sizeof(struct rte_eth_fdir_filter));
+#if 0
+       if (fdir_conf.mode ==  RTE_FDIR_MODE_PERFECT_MAC_VLAN) {
+               if (strcmp(res->mode_value, "MAC-VLAN")) {
+                       printf("Please set mode to MAC-VLAN.\n");
+                       return;
+               }
+       } else if (fdir_conf.mode ==  RTE_FDIR_MODE_PERFECT_TUNNEL) {
+               if (strcmp(res->mode_value, "Tunnel")) {
+                       printf("Please set mode to Tunnel.\n");
+                       return;
+               }
+       } else {
+               if (strcmp(res->mode_value, "IP")) {
+                       printf("Please set mode to IP.\n");
+                       return;
+               }
+#endif
+       {
+               entry.input.flow_type = str2flowtype(res->flow_type);
+       }
+
+       ret = parse_flexbytes(res->flexbytes_value,
+                       flexbytes,
+                       RTE_ETH_FDIR_MAX_FLEXLEN);
+       if (ret < 0) {
+               printf("error: Cannot parse flexbytes input.\n");
+               return;
+       }
+
+       switch (entry.input.flow_type) {
+       case RTE_ETH_FLOW_FRAG_IPV4:
+       case RTE_ETH_FLOW_NONFRAG_IPV4_OTHER:
+               entry.input.flow.ip4_flow.proto = res->proto_value;
+       case RTE_ETH_FLOW_NONFRAG_IPV4_UDP:
+       case RTE_ETH_FLOW_NONFRAG_IPV4_TCP:
+               IPV4_ADDR_TO_UINT(res->ip_dst,
+                               entry.input.flow.ip4_flow.dst_ip);
+               IPV4_ADDR_TO_UINT(res->ip_src,
+                       entry.input.flow.ip4_flow.src_ip);
+                       entry.input.flow.ip4_flow.tos = res->tos_value;
+                       entry.input.flow.ip4_flow.ttl = res->ttl_value;
+                       /* need convert to big endian. */
+                       entry.input.flow.udp4_flow.dst_port =
+                               rte_cpu_to_be_16(res->port_dst);
+                       entry.input.flow.udp4_flow.src_port =
+                               rte_cpu_to_be_16(res->port_src);
+       break;
+
+       case RTE_ETH_FLOW_NONFRAG_IPV4_SCTP:
+               IPV4_ADDR_TO_UINT(res->ip_dst,
+                               entry.input.flow.sctp4_flow.ip.dst_ip);
+               IPV4_ADDR_TO_UINT(res->ip_src,
+                               entry.input.flow.sctp4_flow.ip.src_ip);
+               entry.input.flow.ip4_flow.tos = res->tos_value;
+               entry.input.flow.ip4_flow.ttl = res->ttl_value;
+               /* need convert to big endian. */
+               entry.input.flow.sctp4_flow.dst_port =
+                       rte_cpu_to_be_16(res->port_dst);
+               entry.input.flow.sctp4_flow.src_port =
+                       rte_cpu_to_be_16(res->port_src);
+               entry.input.flow.sctp4_flow.verify_tag =
+                       rte_cpu_to_be_32(res->verify_tag_value);
+       break;
+
+       case RTE_ETH_FLOW_FRAG_IPV6:
+       case RTE_ETH_FLOW_NONFRAG_IPV6_OTHER:
+               entry.input.flow.ipv6_flow.proto = res->proto_value;
+       case RTE_ETH_FLOW_NONFRAG_IPV6_UDP:
+       case RTE_ETH_FLOW_NONFRAG_IPV6_TCP:
+               IPV6_ADDR_TO_ARRAY(res->ip_dst,
+                       entry.input.flow.ipv6_flow.dst_ip);
+               IPV6_ADDR_TO_ARRAY(res->ip_src,
+                       entry.input.flow.ipv6_flow.src_ip);
+               entry.input.flow.ipv6_flow.tc = res->tos_value;
+               entry.input.flow.ipv6_flow.hop_limits = res->ttl_value;
+               /* need convert to big endian. */
+               entry.input.flow.udp6_flow.dst_port =
+                       rte_cpu_to_be_16(res->port_dst);
+               entry.input.flow.udp6_flow.src_port =
+                       rte_cpu_to_be_16(res->port_src);
+       break;
+
+       case RTE_ETH_FLOW_NONFRAG_IPV6_SCTP:
+               IPV6_ADDR_TO_ARRAY(res->ip_dst,
+                       entry.input.flow.sctp6_flow.ip.dst_ip);
+               IPV6_ADDR_TO_ARRAY(res->ip_src,
+                       entry.input.flow.sctp6_flow.ip.src_ip);
+               entry.input.flow.ipv6_flow.tc = res->tos_value;
+               entry.input.flow.ipv6_flow.hop_limits = res->ttl_value;
+               /* need convert to big endian. */
+               entry.input.flow.sctp6_flow.dst_port =
+                       rte_cpu_to_be_16(res->port_dst);
+               entry.input.flow.sctp6_flow.src_port =
+                       rte_cpu_to_be_16(res->port_src);
+               entry.input.flow.sctp6_flow.verify_tag =
+                       rte_cpu_to_be_32(res->verify_tag_value);
+       break;
+       case RTE_ETH_FLOW_L2_PAYLOAD:
+               entry.input.flow.l2_flow.ether_type =
+                       rte_cpu_to_be_16(res->ether_type);
+       break;
+       default:
+               break;
+       }
+#if 0
+       if (fdir_conf.mode ==  RTE_FDIR_MODE_PERFECT_MAC_VLAN)
+               (void)rte_memcpy(&entry.input.flow.mac_vlan_flow.mac_addr,
+                               &res->mac_addr,
+                               sizeof(struct ether_addr));
+
+       if (fdir_conf.mode ==  RTE_FDIR_MODE_PERFECT_TUNNEL) {
+               (void)rte_memcpy(&entry.input.flow.tunnel_flow.mac_addr,
+                               &res->mac_addr,
+                               sizeof(struct ether_addr));
+               entry.input.flow.tunnel_flow.tunnel_type =
+                       str2fdir_tunneltype(res->tunnel_type);
+               entry.input.flow.tunnel_flow.tunnel_id =
+                       rte_cpu_to_be_32(res->tunnel_id_value);
+       }
+#endif
+
+       (void)rte_memcpy(entry.input.flow_ext.flexbytes,
+                       flexbytes,
+                       RTE_ETH_FDIR_MAX_FLEXLEN);
+
+       entry.input.flow_ext.vlan_tci = rte_cpu_to_be_16(res->vlan_value);
+
+       entry.action.flex_off = 0;  /*use 0 by default */
+       if (!strcmp(res->drop, "drop"))
+               entry.action.behavior = RTE_ETH_FDIR_REJECT;
+       else
+               entry.action.behavior = RTE_ETH_FDIR_ACCEPT;
+
+       if (!strcmp(res->pf_vf, "pf"))
+               entry.input.flow_ext.is_vf = 0;
+       else if (!strncmp(res->pf_vf, "vf", 2)) {
+               struct rte_eth_dev_info dev_info;
+
+               memset(&dev_info, 0, sizeof(dev_info));
+               rte_eth_dev_info_get(res->port_id, &dev_info);
+               errno = 0;
+               vf_id = strtoul(res->pf_vf + 2, &end, 10);
+               if (errno != 0 || *end != '\0' || vf_id >= dev_info.max_vfs) {
+                       printf("invalid parameter %s.\n", res->pf_vf);
+                       return;
+               }
+               entry.input.flow_ext.is_vf = 1;
+               entry.input.flow_ext.dst_id = (uint16_t)vf_id;
+       } else {
+               printf("invalid parameter %s.\n", res->pf_vf);
+               return;
+       }
+       /* set to report FD ID by default */
+       entry.action.report_status = RTE_ETH_FDIR_REPORT_ID;
+       entry.action.rx_queue = res->queue_id;
+       entry.soft_id = res->fd_id_value;
+       if (!strcmp(res->ops, "add"))
+               ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_FDIR,
+                               RTE_ETH_FILTER_ADD, &entry);
+       else if (!strcmp(res->ops, "del"))
+               ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_FDIR,
+                               RTE_ETH_FILTER_DELETE, &entry);
+       else
+               ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_FDIR,
+                               RTE_ETH_FILTER_UPDATE, &entry);
+       if (ret < 0)
+               printf("flow director programming error: (%s)\n",
+                               strerror(-ret));
+//     fdir_filter_enabled = 1;
+}
+
+
+
+cmdline_parse_token_string_t cmd_flow_director_filter =
+TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+               flow_director_filter, "flow_director_filter");
+
+cmdline_parse_token_num_t cmd_flow_director_port_id =
+TOKEN_NUM_INITIALIZER(struct cmd_flow_director_result,
+               port_id, UINT8);
+
+
+cmdline_parse_token_string_t cmd_flow_director_mode =
+TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+               mode, "mode");
+
+cmdline_parse_token_string_t cmd_flow_director_mode_ip =
+TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+               mode_value, "IP");
+
+cmdline_parse_token_string_t cmd_flow_director_ops =
+TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+               ops, "add#del#update");
+
+cmdline_parse_token_string_t cmd_flow_director_flow =
+TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+               flow, "flow");
+
+cmdline_parse_token_string_t cmd_flow_director_flow_type =
+TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+               flow_type, "ipv4-other#ipv4-frag#ipv4-tcp#ipv4-udp#ipv4-sctp#"
+               "ipv6-other#ipv6-frag#ipv6-tcp#ipv6-udp#ipv6-sctp#l2_payload");
+
+cmdline_parse_token_string_t cmd_flow_director_src =
+TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+               src, "src");
+cmdline_parse_token_ipaddr_t cmd_flow_director_ip_src =
+TOKEN_IPADDR_INITIALIZER(struct cmd_flow_director_result,
+               ip_src);
+cmdline_parse_token_num_t cmd_flow_director_port_src =
+TOKEN_NUM_INITIALIZER(struct cmd_flow_director_result,
+               port_src, UINT16);
+cmdline_parse_token_string_t cmd_flow_director_dst =
+TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+               dst, "dst");
+cmdline_parse_token_ipaddr_t cmd_flow_director_ip_dst =
+TOKEN_IPADDR_INITIALIZER(struct cmd_flow_director_result,
+               ip_dst);
+cmdline_parse_token_num_t cmd_flow_director_port_dst =
+TOKEN_NUM_INITIALIZER(struct cmd_flow_director_result,
+               port_dst, UINT16);
+
+cmdline_parse_token_string_t cmd_flow_director_tos =
+TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+               tos, "tos");
+cmdline_parse_token_num_t cmd_flow_director_tos_value =
+TOKEN_NUM_INITIALIZER(struct cmd_flow_director_result,
+               tos_value, UINT8);
+
+cmdline_parse_token_string_t cmd_flow_director_ttl =
+TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+               ttl, "ttl");
+cmdline_parse_token_num_t cmd_flow_director_ttl_value =
+TOKEN_NUM_INITIALIZER(struct cmd_flow_director_result,
+               ttl_value, UINT8);
+
+cmdline_parse_token_string_t cmd_flow_director_vlan =
+TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+               vlan, "vlan");
+cmdline_parse_token_num_t cmd_flow_director_vlan_value =
+TOKEN_NUM_INITIALIZER(struct cmd_flow_director_result,
+               vlan_value, UINT16);
+cmdline_parse_token_string_t cmd_flow_director_flexbytes =
+TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+               flexbytes, "flexbytes");
+cmdline_parse_token_string_t cmd_flow_director_flexbytes_value =
+TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+               flexbytes_value, NULL);
+cmdline_parse_token_string_t cmd_flow_director_drop =
+TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+               drop, "drop#fwd");
+cmdline_parse_token_string_t cmd_flow_director_pf_vf =
+TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+               pf_vf, NULL);
+cmdline_parse_token_string_t cmd_flow_director_queue =
+TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+               queue, "queue");
+cmdline_parse_token_num_t cmd_flow_director_queue_id =
+TOKEN_NUM_INITIALIZER(struct cmd_flow_director_result,
+               queue_id, UINT16);
+cmdline_parse_token_string_t cmd_flow_director_fd_id =
+TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+               fd_id, "fd_id");
+cmdline_parse_token_num_t cmd_flow_director_fd_id_value =
+TOKEN_NUM_INITIALIZER(struct cmd_flow_director_result,
+               fd_id_value, UINT32);
+
+
+cmdline_parse_inst_t cmd_add_del_udp_flow_director = {
+       .f = cmd_flow_director_filter_parsed,
+       .data = NULL,
+       .help_str = "add or delete an udp/tcp flow director entry on NIC",
+       .tokens = {
+               (void *)&cmd_flow_director_filter,
+               (void *)&cmd_flow_director_port_id,
+               (void *)&cmd_flow_director_mode,
+               (void *)&cmd_flow_director_mode_ip,
+               (void *)&cmd_flow_director_ops,
+               (void *)&cmd_flow_director_flow,
+               (void *)&cmd_flow_director_flow_type,
+               (void *)&cmd_flow_director_src,
+               (void *)&cmd_flow_director_ip_src,
+               (void *)&cmd_flow_director_port_src,
+               (void *)&cmd_flow_director_dst,
+               (void *)&cmd_flow_director_ip_dst,
+               (void *)&cmd_flow_director_port_dst,
+               (void *)&cmd_flow_director_tos,
+               (void *)&cmd_flow_director_tos_value,
+               (void *)&cmd_flow_director_ttl,
+               (void *)&cmd_flow_director_ttl_value,
+               (void *)&cmd_flow_director_vlan,
+               (void *)&cmd_flow_director_vlan_value,
+               (void *)&cmd_flow_director_flexbytes,
+               (void *)&cmd_flow_director_flexbytes_value,
+               (void *)&cmd_flow_director_drop,
+               (void *)&cmd_flow_director_pf_vf,
+               (void *)&cmd_flow_director_queue,
+               (void *)&cmd_flow_director_queue_id,
+               (void *)&cmd_flow_director_fd_id,
+               (void *)&cmd_flow_director_fd_id_value,
+               NULL,
+       },
+};
+/* L2 payload*/
+cmdline_parse_token_string_t cmd_flow_director_ether =
+       TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+               ether, "ether");
+cmdline_parse_token_num_t cmd_flow_director_ether_type =
+       TOKEN_NUM_INITIALIZER(struct cmd_flow_director_result,
+               ether_type, UINT16);
+
+cmdline_parse_inst_t cmd_add_del_l2_flow_director = {
+       .f = cmd_flow_director_filter_parsed,
+       .data = NULL,
+       .help_str = "add or delete a L2 flow director entry on NIC",
+       .tokens = {
+       (void *)&cmd_flow_director_filter,
+       (void *)&cmd_flow_director_port_id,
+       (void *)&cmd_flow_director_mode,
+       (void *)&cmd_flow_director_mode_ip,
+       (void *)&cmd_flow_director_ops,
+       (void *)&cmd_flow_director_flow,
+       (void *)&cmd_flow_director_flow_type,
+       (void *)&cmd_flow_director_ether,
+       (void *)&cmd_flow_director_ether_type,
+       (void *)&cmd_flow_director_flexbytes,
+       (void *)&cmd_flow_director_flexbytes_value,
+       (void *)&cmd_flow_director_drop,
+       (void *)&cmd_flow_director_pf_vf,
+       (void *)&cmd_flow_director_queue,
+       (void *)&cmd_flow_director_queue_id,
+       (void *)&cmd_flow_director_fd_id,
+       (void *)&cmd_flow_director_fd_id_value,
+       NULL,
+       },
+};
+
+#if 1
+/* Set hash input set */
+struct cmd_set_hash_input_set_result {
+       cmdline_fixed_string_t set_hash_input_set;
+       uint8_t port_id;
+       cmdline_fixed_string_t flow_type;
+       cmdline_fixed_string_t inset_field0;
+       cmdline_fixed_string_t inset_field1;
+       cmdline_fixed_string_t inset_field2;
+       cmdline_fixed_string_t inset_field3;
+       cmdline_fixed_string_t inset_field4;
+       cmdline_fixed_string_t select;
+};
+
+static enum rte_eth_input_set_field
+str2inset(char *string)
+{
+       uint16_t i;
+
+       static const struct {
+               char str[32];
+               enum rte_eth_input_set_field inset;
+       } inset_table[] = {
+               {"ethertype", RTE_ETH_INPUT_SET_L2_ETHERTYPE},
+               {"ovlan", RTE_ETH_INPUT_SET_L2_OUTER_VLAN},
+               {"ivlan", RTE_ETH_INPUT_SET_L2_INNER_VLAN},
+               {"src-ipv4", RTE_ETH_INPUT_SET_L3_SRC_IP4},
+               {"dst-ipv4", RTE_ETH_INPUT_SET_L3_DST_IP4},
+               {"ipv4-tos", RTE_ETH_INPUT_SET_L3_IP4_TOS},
+               {"ipv4-proto", RTE_ETH_INPUT_SET_L3_IP4_PROTO},
+               {"ipv4-ttl", RTE_ETH_INPUT_SET_L3_IP4_TTL},
+               {"src-ipv6", RTE_ETH_INPUT_SET_L3_SRC_IP6},
+               {"dst-ipv6", RTE_ETH_INPUT_SET_L3_DST_IP6},
+               {"ipv6-tc", RTE_ETH_INPUT_SET_L3_IP6_TC},
+               {"ipv6-next-header", RTE_ETH_INPUT_SET_L3_IP6_NEXT_HEADER},
+               {"ipv6-hop-limits", RTE_ETH_INPUT_SET_L3_IP6_HOP_LIMITS},
+               {"udp-src-port", RTE_ETH_INPUT_SET_L4_UDP_SRC_PORT},
+               {"udp-dst-port", RTE_ETH_INPUT_SET_L4_UDP_DST_PORT},
+               {"tcp-src-port", RTE_ETH_INPUT_SET_L4_TCP_SRC_PORT},
+               {"tcp-dst-port", RTE_ETH_INPUT_SET_L4_TCP_DST_PORT},
+               {"sctp-src-port", RTE_ETH_INPUT_SET_L4_SCTP_SRC_PORT},
+               {"sctp-dst-port", RTE_ETH_INPUT_SET_L4_SCTP_DST_PORT},
+               {"sctp-veri-tag", RTE_ETH_INPUT_SET_L4_SCTP_VERIFICATION_TAG},
+               {"udp-key", RTE_ETH_INPUT_SET_TUNNEL_L4_UDP_KEY},
+               {"gre-key", RTE_ETH_INPUT_SET_TUNNEL_GRE_KEY},
+               {"fld-1st", RTE_ETH_INPUT_SET_FLEX_PAYLOAD_1ST_WORD},
+               {"fld-2nd", RTE_ETH_INPUT_SET_FLEX_PAYLOAD_2ND_WORD},
+               {"fld-3rd", RTE_ETH_INPUT_SET_FLEX_PAYLOAD_3RD_WORD},
+               {"fld-4th", RTE_ETH_INPUT_SET_FLEX_PAYLOAD_4TH_WORD},
+               {"fld-5th", RTE_ETH_INPUT_SET_FLEX_PAYLOAD_5TH_WORD},
+               {"fld-6th", RTE_ETH_INPUT_SET_FLEX_PAYLOAD_6TH_WORD},
+               {"fld-7th", RTE_ETH_INPUT_SET_FLEX_PAYLOAD_7TH_WORD},
+               {"fld-8th", RTE_ETH_INPUT_SET_FLEX_PAYLOAD_8TH_WORD},
+               {"none", RTE_ETH_INPUT_SET_NONE},
+       };
+       for (i = 0; i < RTE_DIM(inset_table); i++) {
+               if (!strcmp(string, inset_table[i].str))
+                       return inset_table[i].inset;
+       }
+
+       return RTE_ETH_INPUT_SET_UNKNOWN;
+}
+
+static void
+cmd_set_hash_input_set_1_parsed(void *parsed_result,
+               __rte_unused struct cmdline *cl,
+               __rte_unused void *data)
+{
+       struct cmd_set_hash_input_set_result *res = parsed_result;
+       struct rte_eth_hash_filter_info info;
+
+       if (enable_flow_dir) {
+               printf("FDIR Filter is Defined!\n");
+               printf("Please undefine FDIR_FILTER flag and define "
+                       "HWLD flag\n");
+               return;
+       }
+
+       memset(&info, 0, sizeof(info));
+       info.info_type = RTE_ETH_HASH_FILTER_INPUT_SET_SELECT;
+       info.info.input_set_conf.flow_type = str2flowtype(res->flow_type);
+
+       info.info.input_set_conf.field[0] = str2inset(res->inset_field0);
+       info.info.input_set_conf.inset_size = 1;
+
+       if (!strcmp(res->select, "select"))
+               info.info.input_set_conf.op = RTE_ETH_INPUT_SET_SELECT;
+       else if (!strcmp(res->select, "add"))
+               info.info.input_set_conf.op = RTE_ETH_INPUT_SET_ADD;
+
+       rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+               RTE_ETH_FILTER_SET, &info);
+
+       //hash_filter_enabled = 1;
+}
+
+static void
+cmd_set_hash_input_set_2_parsed(void *parsed_result,
+                       __rte_unused struct cmdline *cl,
+                       __rte_unused void *data)
+{
+       struct cmd_set_hash_input_set_result *res = parsed_result;
+       struct rte_eth_hash_filter_info info;
+
+       if (enable_flow_dir) {
+               printf("FDIR Filter is Defined!\n");
+               printf("Please undefine FDIR_FILTER flag and define "
+                       "HWLD flag\n");
+               return;
+       }
+
+       memset(&info, 0, sizeof(info));
+       info.info_type = RTE_ETH_HASH_FILTER_INPUT_SET_SELECT;
+       info.info.input_set_conf.flow_type = str2flowtype(res->flow_type);
+
+       info.info.input_set_conf.field[0] = str2inset(res->inset_field0);
+       info.info.input_set_conf.field[1] = str2inset(res->inset_field1);
+
+       info.info.input_set_conf.inset_size = 2;
+
+       if (!strcmp(res->select, "select"))
+               info.info.input_set_conf.op = RTE_ETH_INPUT_SET_SELECT;
+       else if (!strcmp(res->select, "add"))
+               info.info.input_set_conf.op = RTE_ETH_INPUT_SET_ADD;
+
+       rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+               RTE_ETH_FILTER_SET, &info);
+
+       //hash_filter_enabled = 1;
+}
+
+#if 0
+static void
+cmd_set_hash_input_set_3_parsed(void *parsed_result,
+               __rte_unused struct cmdline *cl,
+                __rte_unused void *data)
+{
+       struct cmd_set_hash_input_set_result *res = parsed_result;
+       struct rte_eth_hash_filter_info info;
+
+       memset(&info, 0, sizeof(info));
+       info.info_type = RTE_ETH_HASH_FILTER_INPUT_SET_SELECT;
+       info.info.input_set_conf.flow_type = str2flowtype(res->flow_type);
+
+       info.info.input_set_conf.field[0] = str2inset(res->inset_field0);
+       info.info.input_set_conf.field[1] = str2inset(res->inset_field1);
+       info.info.input_set_conf.field[2] = str2inset(res->inset_field2);
+       info.info.input_set_conf.inset_size = 3;
+
+       if (!strcmp(res->select, "select"))
+               info.info.input_set_conf.op = RTE_ETH_INPUT_SET_SELECT;
+       else if (!strcmp(res->select, "add"))
+               info.info.input_set_conf.op = RTE_ETH_INPUT_SET_ADD;
+
+       rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+               RTE_ETH_FILTER_SET, &info);
+}
+#endif
+static void
+cmd_set_hash_input_set_4_parsed(void *parsed_result,
+                        __rte_unused struct cmdline *cl,
+                        __rte_unused void *data)
+{
+       struct cmd_set_hash_input_set_result *res = parsed_result;
+       struct rte_eth_hash_filter_info info;
+
+       if (enable_flow_dir) {
+               printf("FDIR Filter is Defined!\n");
+               printf("Please undefine FDIR_FILTER flag and define "
+                       "HWLD flag\n");
+               return;
+       }
+
+       memset(&info, 0, sizeof(info));
+       info.info_type = RTE_ETH_HASH_FILTER_INPUT_SET_SELECT;
+       info.info.input_set_conf.flow_type = str2flowtype(res->flow_type);
+
+       info.info.input_set_conf.field[0] = str2inset(res->inset_field0);
+       info.info.input_set_conf.field[1] = str2inset(res->inset_field1);
+       info.info.input_set_conf.field[2] = str2inset(res->inset_field2);
+       info.info.input_set_conf.field[3] = str2inset(res->inset_field3);
+
+       info.info.input_set_conf.inset_size = 4;
+       if (!strcmp(res->select, "select"))
+               info.info.input_set_conf.op = RTE_ETH_INPUT_SET_SELECT;
+       else if (!strcmp(res->select, "add"))
+               info.info.input_set_conf.op = RTE_ETH_INPUT_SET_ADD;
+
+       rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+               RTE_ETH_FILTER_SET, &info);
+       //hash_filter_enabled = 1;
+}
+
+#if 0
+static void
+cmd_set_hash_input_set_5_parsed(void *parsed_result,
+       __rte_unused struct cmdline *cl,
+       __rte_unused void *data)
+{
+       struct cmd_set_hash_input_set_result *res = parsed_result;
+       struct rte_eth_hash_filter_info info;
+
+       memset(&info, 0, sizeof(info));
+       info.info_type = RTE_ETH_HASH_FILTER_INPUT_SET_SELECT;
+       info.info.input_set_conf.flow_type = str2flowtype(res->flow_type);
+
+       info.info.input_set_conf.field[0] = str2inset(res->inset_field0);
+       info.info.input_set_conf.field[1] = str2inset(res->inset_field1);
+       info.info.input_set_conf.field[2] = str2inset(res->inset_field2);
+       info.info.input_set_conf.field[3] = str2inset(res->inset_field3);
+       info.info.input_set_conf.field[4] = str2inset(res->inset_field4);
+
+       info.info.input_set_conf.inset_size = 5;
+       if (!strcmp(res->select, "select"))
+               info.info.input_set_conf.op = RTE_ETH_INPUT_SET_SELECT;
+       else if (!strcmp(res->select, "add"))
+               info.info.input_set_conf.op = RTE_ETH_INPUT_SET_ADD;
+       rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+       RTE_ETH_FILTER_SET, &info);
+}
+#endif
+
+cmdline_parse_token_string_t cmd_set_hash_input_set_cmd =
+       TOKEN_STRING_INITIALIZER(struct cmd_set_hash_input_set_result,
+       set_hash_input_set, "set_hash_input_set");
+cmdline_parse_token_num_t cmd_set_hash_input_set_port_id =
+       TOKEN_NUM_INITIALIZER(struct cmd_set_hash_input_set_result,
+       port_id, UINT8);
+cmdline_parse_token_string_t cmd_set_hash_input_set_flow_type =
+       TOKEN_STRING_INITIALIZER(struct cmd_set_hash_input_set_result,
+       flow_type,
+       "ipv4-frag#ipv4-tcp#ipv4-udp#ipv4-sctp#ipv4-other#"
+       "ipv6-frag#ipv6-tcp#ipv6-udp#ipv6-sctp#ipv6-other#l2_payload");
+
+cmdline_parse_token_string_t cmd_set_hash_input_set_field0 =
+       TOKEN_STRING_INITIALIZER(struct cmd_set_hash_input_set_result,
+       inset_field0,
+       "src-ipv4#src-ipv6#dst-ipv4#dst-ipv6#"
+       "udp-src-port#udp-dst-port#tcp-src-port#tcp-dst-port#none");
+
+cmdline_parse_token_string_t cmd_set_hash_input_set_field1 =
+       TOKEN_STRING_INITIALIZER(struct cmd_set_hash_input_set_result,
+       inset_field1,
+       "dst-ipv4#dst-ipv6#"
+       "udp-src-port#tcp-src-port#udp-dst-port#tcp-dst-port#none");
+
+cmdline_parse_token_string_t cmd_set_hash_input_set_field2 =
+       TOKEN_STRING_INITIALIZER(struct cmd_set_hash_input_set_result,
+       inset_field2,
+       "udp-src-port#tcp-src-port#none");
+
+cmdline_parse_token_string_t cmd_set_hash_input_set_field3 =
+       TOKEN_STRING_INITIALIZER(struct cmd_set_hash_input_set_result,
+       inset_field3,
+       "udp-dst-port#tcp-dst-port#none");
+#if 0
+cmdline_parse_token_string_t cmd_set_hash_input_set_field4 =
+       TOKEN_STRING_INITIALIZER(struct cmd_set_hash_input_set_result,
+       inset_field4, "ipv4-proto#ipv6-next-header#none");
+#endif
+
+cmdline_parse_token_string_t cmd_set_hash_input_set_select =
+       TOKEN_STRING_INITIALIZER(struct cmd_set_hash_input_set_result,
+       select, "select#add");
+
+cmdline_parse_inst_t cmd_set_hash_input_set_1 = {
+       .f = cmd_set_hash_input_set_1_parsed,
+       .data = NULL,
+       .help_str = "set_hash_input_set_1 <port_id> "
+       "ipv4|ipv4-frag|ipv4-tcp|ipv4-udp|ipv4-sctp|ipv4-other|"
+       "ipv6|ipv6-frag|ipv6-tcp|ipv6-udp|ipv6-sctp|ipv6-other|l2_payload    "
+       "src-ipv4|src-ipv6|dst-ipv4|dst-ipv6|"
+       "udp-src-port|udp-dst-port|tcp-src-port|tcp-dst-port|none    "
+       "select|add",
+       .tokens = {
+               (void *)&cmd_set_hash_input_set_cmd,
+               (void *)&cmd_set_hash_input_set_port_id,
+               (void *)&cmd_set_hash_input_set_flow_type,
+               (void *)&cmd_set_hash_input_set_field0,
+               (void *)&cmd_set_hash_input_set_select,
+               NULL,
+       },
+};
+
+cmdline_parse_inst_t cmd_set_hash_input_set_2 = {
+       .f = cmd_set_hash_input_set_2_parsed,
+       .data = NULL,
+       .help_str = "set_hash_input_set_2 <port_id> "
+       "ipv4|ipv4-frag|ipv4-tcp|ipv4-udp|ipv4-sctp|ipv4-other| "
+       "ipv6|ipv6-frag|ipv6-tcp|ipv6-udp|ipv6-sctp|ipv6-other|l2_payload "
+       "src-ipv4|src-ipv6|dst-ipv4|dst-ipv6| "
+       "udp-src-port|udp-dst-port|tcp-src-port|tcp-dst-port|none "
+       "udp-src-port|tcp-src-port|udp-dst-port|tcp-dst-port|none "
+       "select|add",
+       .tokens = {
+               (void *)&cmd_set_hash_input_set_cmd,
+               (void *)&cmd_set_hash_input_set_port_id,
+               (void *)&cmd_set_hash_input_set_flow_type,
+               (void *)&cmd_set_hash_input_set_field0,
+               (void *)&cmd_set_hash_input_set_field1,
+               (void *)&cmd_set_hash_input_set_select,
+               NULL,
+       },
+};
+
+#if 0
+cmdline_parse_inst_t cmd_set_hash_input_set_3 = {
+       .f = cmd_set_hash_input_set_3_parsed,
+       .data = NULL,
+       .help_str = "set_hash_input_set_3 <port_id> "
+       "ipv4-frag|ipv4-tcp|ipv4-udp|ipv4-sctp|ipv4-other|"
+       "ipv6-frag|ipv6-tcp|ipv6-udp|ipv6-sctp|ipv6-other|l2_payload        "
+       "ovlan|ivlan|src-ipv4|dst-ipv4|src-ipv6|dst-ipv6|ipv4-tos|ipv4-proto|"
+       "ipv6-tc|ipv6-next-header|udp-src-port|udp-dst-port|tcp-src-port|"
+       "tcp-dst-port|sctp-src-port|sctp-dst-port|sctp-veri-tag|udp-key|"
+       "gre-key|fld-1st|fld-2nd|fld-3rd|fld-4th|fld-5th|fld-6th|"
+       "fld-7th|fld-8th|none       "
+       "udp-src-port|udp-dst-port|tcp-src-port|tcp-dst-port|none       "
+       "select|add",
+       .tokens = {
+               (void *)&cmd_set_hash_input_set_cmd,
+               (void *)&cmd_set_hash_input_set_port_id,
+               (void *)&cmd_set_hash_input_set_flow_type,
+               (void *)&cmd_set_hash_input_set_field0,
+               (void *)&cmd_set_hash_input_set_field1,
+               (void *)&cmd_set_hash_input_set_field2,
+               (void *)&cmd_set_hash_input_set_select,
+               NULL,
+       },
+};
+#endif
+
+cmdline_parse_inst_t cmd_set_hash_input_set_4 = {
+       .f = cmd_set_hash_input_set_4_parsed,
+       .data = NULL,
+       .help_str = "set_hash_input_set_4 <port_id> "
+       "ipv4|ipv4-frag|ipv4-tcp|ipv4-udp|ipv4-sctp|ipv4-other|"
+       "ipv6|ipv6-frag|ipv6-tcp|ipv6-udp|ipv6-sctp|ipv6-other|l2_payload "
+       "src-ipv4|src-ipv6|dst-ipv4|dst-ipv6|"
+       "udp-src-port|udp-dst-port|tcp-src-port|tcp-dst-port|none "
+       "udp-src-port|tcp-src-port|udp-dst-port|tcp-dst-port|none "
+       "udp-src-port|tcp-src-port|dst-ipv4|none    "
+       "udp-dst-port|tcp-dst-port|none    "
+       "select|add",
+       .tokens = {
+               (void *)&cmd_set_hash_input_set_cmd,
+               (void *)&cmd_set_hash_input_set_port_id,
+               (void *)&cmd_set_hash_input_set_flow_type,
+               (void *)&cmd_set_hash_input_set_field0,
+               (void *)&cmd_set_hash_input_set_field1,
+               (void *)&cmd_set_hash_input_set_field2,
+               (void *)&cmd_set_hash_input_set_field3,
+               (void *)&cmd_set_hash_input_set_select,
+               NULL,
+       },
+};
+#if 0
+cmdline_parse_inst_t cmd_set_hash_input_set_5 = {
+       .f = cmd_set_hash_input_set_5_parsed,
+       .data = NULL,
+       .help_str = "set_hash_input_set_5 <port_id> "
+       "ipv4|ipv4-frag|ipv4-tcp|ipv4-udp|ipv4-sctp|ipv4-other|"
+       "ipv6|ipv6-frag|ipv6-tcp|ipv6-udp|ipv6-sctp|ipv6-other|l2_payload    "
+       "src-ipv4|src-ipv6|none    "
+       "dst-ipv4|dst-ipv6|none    "
+       "udp-src-port|tcp-src-port|none    "
+       "udp-dst-port|tcp-dst-port|none    "
+       "ipv4-proto|ipv6-next-header|none    "
+       "select|add",
+
+       .tokens = {
+               (void *)&cmd_set_hash_input_set_cmd,
+               (void *)&cmd_set_hash_input_set_port_id,
+               (void *)&cmd_set_hash_input_set_flow_type,
+               (void *)&cmd_set_hash_input_set_field0,
+               (void *)&cmd_set_hash_input_set_field1,
+               (void *)&cmd_set_hash_input_set_field2,
+               (void *)&cmd_set_hash_input_set_field3,
+               (void *)&cmd_set_hash_input_set_field4,
+               (void *)&cmd_set_hash_input_set_select,
+               NULL,
+       },
+};
+#endif
+#endif
+/* set hash global config */
+struct cmd_set_hash_global_config_result {
+       cmdline_fixed_string_t set_hash_global_config;
+       uint8_t port_id;
+       cmdline_fixed_string_t hash_func;
+       cmdline_fixed_string_t flow_type;
+       cmdline_fixed_string_t enable;
+};
+
+static void
+cmd_set_hash_global_config_parsed(void *parsed_result,
+               __rte_unused struct cmdline *cl,
+               __rte_unused void *data)
+{
+       struct cmd_set_hash_global_config_result *res = parsed_result;
+       struct rte_eth_hash_filter_info info;
+       uint32_t ftype, idx, offset;
+       int ret;
+
+       if (rte_eth_dev_filter_supported(res->port_id,
+                               RTE_ETH_FILTER_HASH) < 0) {
+               printf("RTE_ETH_FILTER_HASH not supported on port %d\n",
+                               res->port_id);
+               return;
+       }
+       memset(&info, 0, sizeof(info));
+       info.info_type = RTE_ETH_HASH_FILTER_GLOBAL_CONFIG;
+       if (!strcmp(res->hash_func, "toeplitz"))
+               info.info.global_conf.hash_func =
+                       RTE_ETH_HASH_FUNCTION_TOEPLITZ;
+       else if (!strcmp(res->hash_func, "simple_xor"))
+               info.info.global_conf.hash_func =
+                       RTE_ETH_HASH_FUNCTION_SIMPLE_XOR;
+       else if (!strcmp(res->hash_func, "default"))
+               info.info.global_conf.hash_func =
+                       RTE_ETH_HASH_FUNCTION_DEFAULT;
+
+       ftype = str2flowtype(res->flow_type);
+       idx = ftype / (CHAR_BIT * sizeof(uint32_t));
+       offset = ftype % (CHAR_BIT * sizeof(uint32_t));
+       info.info.global_conf.valid_bit_mask[idx] |= (1UL << offset);
+       if (!strcmp(res->enable, "enable"))
+               if(idx < RTE_SYM_HASH_MASK_ARRAY_SIZE)
+               info.info.global_conf.sym_hash_enable_mask[idx] |=
+                       (1UL << offset);
+       ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+                       RTE_ETH_FILTER_SET, &info);
+       if (ret < 0)
+               printf("Cannot set global hash configurations by port %d\n",
+                               res->port_id);
+       else
+               printf("Global hash configurations have been set "
+                               "succcessfully by port %d\n", res->port_id);
+}
+cmdline_parse_token_string_t cmd_set_hash_global_config_all =
+TOKEN_STRING_INITIALIZER(struct cmd_set_hash_global_config_result,
+               set_hash_global_config, "set_hash_global_config");
+cmdline_parse_token_num_t cmd_set_hash_global_config_port_id =
+TOKEN_NUM_INITIALIZER(struct cmd_set_hash_global_config_result,
+               port_id, UINT8);
+cmdline_parse_token_string_t cmd_set_hash_global_config_hash_func =
+TOKEN_STRING_INITIALIZER(struct cmd_set_hash_global_config_result,
+               hash_func, "toeplitz#simple_xor#default");
+cmdline_parse_token_string_t cmd_set_hash_global_config_flow_type =
+TOKEN_STRING_INITIALIZER(struct cmd_set_hash_global_config_result,
+               flow_type,
+               "ipv4#ipv4-frag#ipv4-tcp#ipv4-udp#ipv4-sctp#ipv4-other#ipv6#"
+               "ipv6-frag#ipv6-tcp#ipv6-udp#ipv6-sctp#ipv6-other#l2_payload");
+cmdline_parse_token_string_t cmd_set_hash_global_config_enable =
+TOKEN_STRING_INITIALIZER(struct cmd_set_hash_global_config_result,
+               enable, "enable#disable");
+
+cmdline_parse_inst_t cmd_set_hash_global_config = {
+       .f = cmd_set_hash_global_config_parsed,
+       .data = NULL,
+       .help_str = "set_hash_global_config port_id "
+               "toeplitz|simple_xor|default "
+               "ipv4|ipv4-frag|ipv4-tcp|ipv4-udp|ipv4-sctp|ipv4-other|ipv6|"
+               "ipv6-frag|ipv6-tcp|ipv6-udp|ipv6-sctp|ipv6-other|l2_payload "
+               "enable|disable",
+       .tokens = {
+               (void *)&cmd_set_hash_global_config_all,
+               (void *)&cmd_set_hash_global_config_port_id,
+               (void *)&cmd_set_hash_global_config_hash_func,
+               (void *)&cmd_set_hash_global_config_flow_type,
+               (void *)&cmd_set_hash_global_config_enable,
+               NULL,
+       },
+};
+
+/* *** Set symmetric hash enable per port *** */
+struct cmd_set_sym_hash_ena_per_port_result {
+       cmdline_fixed_string_t set_sym_hash_ena_per_port;
+       cmdline_fixed_string_t enable;
+       uint8_t port_id;
+};
+
+static void
+cmd_set_sym_hash_per_port_parsed(void *parsed_result,
+                __rte_unused struct cmdline *cl,
+                __rte_unused void *data)
+{
+       struct cmd_set_sym_hash_ena_per_port_result *res = parsed_result;
+       struct rte_eth_hash_filter_info info;
+       int ret;
+
+       if (rte_eth_dev_filter_supported(res->port_id,
+                RTE_ETH_FILTER_HASH) < 0) {
+               printf("RTE_ETH_FILTER_HASH not supported on port: %d\n",
+                       res->port_id);
+               return;
+       }
+
+       memset(&info, 0, sizeof(info));
+       info.info_type = RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT;
+
+       if (!strcmp(res->enable, "enable"))
+               info.info.enable = 1;
+
+       ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+                                RTE_ETH_FILTER_SET, &info);
+       if (ret < 0) {
+               printf("Cannot set symmetric hash enable per port on "
+                       "port %u\n", res->port_id);
+               return;
+       }
+       printf("Symmetric hash has been set to %s on port %u\n",
+                                res->enable, res->port_id);
+}
+
+cmdline_parse_token_string_t cmd_set_sym_hash_ena_per_port_all =
+       TOKEN_STRING_INITIALIZER(struct cmd_set_sym_hash_ena_per_port_result,
+       set_sym_hash_ena_per_port, "set_sym_hash_ena_per_port");
+cmdline_parse_token_num_t cmd_set_sym_hash_ena_per_port_port_id =
+       TOKEN_NUM_INITIALIZER(struct cmd_set_sym_hash_ena_per_port_result,
+       port_id, UINT8);
+cmdline_parse_token_string_t cmd_set_sym_hash_ena_per_port_enable =
+       TOKEN_STRING_INITIALIZER(struct cmd_set_sym_hash_ena_per_port_result,
+       enable, "enable#disable");
+
+cmdline_parse_inst_t cmd_set_sym_hash_ena_per_port = {
+       .f = cmd_set_sym_hash_per_port_parsed,
+       .data = NULL,
+       .help_str = "set_sym_hash_ena_per_port port_id enable|disable",
+       .tokens = {
+               (void *)&cmd_set_sym_hash_ena_per_port_all,
+               (void *)&cmd_set_sym_hash_ena_per_port_port_id,
+               (void *)&cmd_set_sym_hash_ena_per_port_enable,
+               NULL,
+       },
+};
+#endif
+
+static int
+app_pipeline_arpicmp_entry_dbg(struct app_params *app,
+                                       uint32_t pipeline_id, uint8_t *msg)
+{
+       struct pipeline_arpicmp_entry_dbg_msg_req *req;
+       struct pipeline_arpicmp_entry_dbg_msg_rsp *rsp;
+
+       /* Check input arguments */
+       if (app == NULL)
+               return -1;
+
+       /* Allocate and write request */
+       req = app_msg_alloc(app);
+       if (req == NULL)
+               return -1;
+
+       req->type = PIPELINE_MSG_REQ_CUSTOM;
+       req->subtype = PIPELINE_ARPICMP_MSG_REQ_ENTRY_DBG;
+       req->data[0] = msg[0];
+       req->data[1] = msg[1];
+
+       rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
+       if (rsp == NULL)
+               return -1;
+
+       /* Read response */
+       if (rsp->status) {
+               app_msg_free(app, rsp);
+               printf("Error rsp->status %d\n", rsp->status);
+               return -1;
+       }
+
+       /* Free response */
+       app_msg_free(app, rsp);
+
+       return 0;
+}
+
+/*
+ * entry dbg
+ */
+
+
+struct cmd_entry_dbg_result {
+       cmdline_fixed_string_t p_string;
+       uint32_t p;
+       cmdline_fixed_string_t entry_string;
+       cmdline_fixed_string_t dbg_string;
+       uint8_t cmd;
+       uint8_t d1;
+};
+
+static void
+cmd_entry_dbg_parsed(void *parsed_result,
+                                __rte_unused struct cmdline *cl, void *data)
+{
+       struct cmd_entry_dbg_result *params = parsed_result;
+       struct app_params *app = data;
+       uint8_t msg[2];
+       int status;
+
+       msg[0] = params->cmd;
+       msg[1] = params->d1;
+       status = app_pipeline_arpicmp_entry_dbg(app, params->p, msg);
+
+       if (status != 0) {
+               printf("Dbg Command failed\n");
+               return;
+       }
+}
+
+static cmdline_parse_token_string_t lb_cmd_entry_dbg_p_string =
+TOKEN_STRING_INITIALIZER(struct cmd_entry_dbg_result, p_string, "p");
+
+static cmdline_parse_token_num_t lb_cmd_entry_dbg_p =
+TOKEN_NUM_INITIALIZER(struct cmd_entry_dbg_result, p, UINT32);
+
+static cmdline_parse_token_string_t lb_cmd_entry_dbg_entry_string =
+TOKEN_STRING_INITIALIZER(struct cmd_entry_dbg_result,
+                        entry_string, "txrx");
+
+static cmdline_parse_token_string_t lb_cmd_entry_dbg_dbg_string =
+TOKEN_STRING_INITIALIZER(struct cmd_entry_dbg_result, dbg_string,
+                        "dbg");
+
+static cmdline_parse_token_num_t lb_cmd_entry_dbg_cmd =
+TOKEN_NUM_INITIALIZER(struct cmd_entry_dbg_result, cmd, UINT8);
+
+static cmdline_parse_token_num_t lb_cmd_entry_dbg_d1 =
+TOKEN_NUM_INITIALIZER(struct cmd_entry_dbg_result, d1, UINT8);
+
+static cmdline_parse_inst_t lb_cmd_entry_dbg = {
+       .f = cmd_entry_dbg_parsed,
+       .data = NULL,
+       .help_str = "ARPICMP dbg cmd",
+       .tokens = {
+                        (void *)&lb_cmd_entry_dbg_p_string,
+                        (void *)&lb_cmd_entry_dbg_p,
+                        (void *)&lb_cmd_entry_dbg_entry_string,
+                        (void *)&lb_cmd_entry_dbg_dbg_string,
+                        (void *)&lb_cmd_entry_dbg_cmd,
+                        (void *)&lb_cmd_entry_dbg_d1,
+                        NULL,
+       },
+};
+
+static cmdline_parse_ctx_t pipeline_cmds[] = {
+       (cmdline_parse_inst_t *) &lb_cmd_entry_dbg,
+       (cmdline_parse_inst_t *) &cmd_arp_add,
+       (cmdline_parse_inst_t *) &cmd_arp_del,
+       (cmdline_parse_inst_t *) &cmd_arp_req,
+       (cmdline_parse_inst_t *) &cmd_icmp_echo_req,
+       (cmdline_parse_inst_t *) &cmd_arp_ls,
+       (cmdline_parse_inst_t *) &cmd_show_ports_info,
+       /*HWLB cmds*/
+       (cmdline_parse_inst_t *) &cmd_set_fwd_mode,
+       (cmdline_parse_inst_t *) &cmd_add_del_udp_flow_director,
+       (cmdline_parse_inst_t *) &cmd_add_del_l2_flow_director,
+       (cmdline_parse_inst_t *) &cmd_set_hash_input_set_1,
+       (cmdline_parse_inst_t *) &cmd_set_hash_input_set_2,
+/*      (cmdline_parse_inst_t *) & cmd_set_hash_input_set_3,*/
+       (cmdline_parse_inst_t *) &cmd_set_hash_input_set_4,
+/*      (cmdline_parse_inst_t *) & cmd_set_hash_input_set_5,*/
+       (cmdline_parse_inst_t *) &cmd_set_hash_global_config,
+       (cmdline_parse_inst_t *) &cmd_set_sym_hash_ena_per_port,
+       #ifndef VNF_ACL
+       (cmdline_parse_inst_t *) &cmd_arp_dbg,
+       (cmdline_parse_inst_t *) &cmd_arp_timer,
+       #endif
+       NULL,
+};
+
+static struct pipeline_fe_ops pipeline_arpicmp_fe_ops = {
+       .f_init = NULL,
+       .f_free = NULL,
+       .cmds = pipeline_cmds,
+};
+
+struct pipeline_type pipeline_arpicmp = {
+       .name = "ARPICMP",
+       .be_ops = &pipeline_arpicmp_be_ops,
+       .fe_ops = &pipeline_arpicmp_fe_ops,
+};
diff --git a/common/VIL/pipeline_arpicmp/pipeline_arpicmp.h b/common/VIL/pipeline_arpicmp/pipeline_arpicmp.h
new file mode 100644 (file)
index 0000000..1efb14e
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef __INCLUDE_PIPELINE_ARPICMP_H__
+#define __INCLUDE_PIPELINE_ARPICMP_H__
+
+#include "pipeline.h"
+#include "pipeline_arpicmp_be.h"
+
+/*
+ * Pipeline type
+ */
+extern struct pipeline_type pipeline_arpicmp;
+//uint16_t verbose_level = 1; /**< should be Silent by default. */
+#define MAX_PKT_BURST 512
+#define DEF_PKT_BURST 32
+/**< Number of packets per burst. */
+//uint16_t nb_pkt_per_burst = DEF_PKT_BURST;
+typedef uint8_t  portid_t;
+typedef uint16_t queueid_t;
+typedef uint16_t streamid_t;
+/**
+ * The data structure associated with a forwarding stream between a receive
+ * port/queue and a transmit port/queue.
+ */
+struct fwd_stream {
+       /* "read-only" data */
+       /**< port to poll for received packets */
+       portid_t   rx_port;
+       /**< RX queue to poll on "rx_port" */
+       queueid_t  rx_queue;
+       /**< forwarding port of received packets */
+       portid_t   tx_port;
+       /**< TX queue to send forwarded packets */
+       queueid_t  tx_queue;
+       /**< index of peer ethernet address of packets */
+       streamid_t peer_addr;
+
+       /* "read-write" results */
+       /**< received packets */
+       unsigned int rx_packets;
+       /**< received packets transmitted */
+       unsigned int tx_packets;
+       /**< received packets not forwarded */
+       unsigned int fwd_dropped;
+       /**< received packets has bad ip checksum */
+       unsigned int rx_bad_ip_csum;
+       /**< received packets has bad l4 checksum */
+       unsigned int rx_bad_l4_csum;
+       #ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+       uint64_t     core_cycles; /**< used for RX and TX processing */
+       #endif
+       #ifdef RTE_TEST_PMD_RECORD_BURST_STATS
+       struct pkt_burst_stats rx_burst_stats;
+       struct pkt_burst_stats tx_burst_stats;
+       #endif
+};
+/*
+ * Forwarding mode operations:
+ *   - IO forwarding mode (default mode)
+ *     Forwards packets unchanged.
+ *
+ *   - MAC forwarding mode
+ *     Set the source and the destination Ethernet addresses of packets
+ *     before forwarding them.
+ *
+ *   - IEEE1588 forwarding mode
+ *     Check that received IEEE1588 Precise Time Protocol (PTP) packets are
+ *     filtered and timestamped by the hardware.
+ *     Forwards packets unchanged on the same port.
+ *     Check that sent IEEE1588 PTP packets are timestamped by the hardware.
+ */
+typedef void (*port_fwd_begin_t)(portid_t pi);
+typedef void (*port_fwd_end_t)(portid_t pi);
+typedef void (*packet_fwd_t)(struct fwd_stream *fs);
+struct fwd_engine {
+       /**< Forwarding mode name. */
+       const char       *fwd_mode_name;
+       /**< NULL if nothing special to do. */
+       port_fwd_begin_t port_fwd_begin;
+       /**< NULL if nothing special to do. */
+       port_fwd_end_t   port_fwd_end;
+       /**< Mandatory. */
+       packet_fwd_t     packet_fwd;
+};
+#define IPV4_ADDR_TO_UINT(ip_addr, ip)                 \
+do {                                                   \
+       if ((ip_addr).family == AF_INET)                \
+               (ip) = (ip_addr).addr.ipv4.s_addr;      \
+       else {                                          \
+               printf("invalid parameter.\n");         \
+               return;                                 \
+       }                                               \
+} while (0)
+
+#define IPV6_ADDR_TO_ARRAY(ip_addr, ip)                        \
+do {                                                   \
+       if ((ip_addr).family == AF_INET6)               \
+       (void)rte_memcpy(&(ip),                         \
+               &((ip_addr).addr.ipv6),                 \
+               sizeof(struct in6_addr));               \
+       else {                                          \
+               printf("invalid parameter.\n");         \
+               return;                                 \
+       }                                               \
+} while (0)
+
+void set_pkt_forwarding_mode(const char *fwd_mode_name);
+#endif
diff --git a/common/VIL/pipeline_arpicmp/pipeline_arpicmp_be.c b/common/VIL/pipeline_arpicmp/pipeline_arpicmp_be.c
new file mode 100644 (file)
index 0000000..7238bd1
--- /dev/null
@@ -0,0 +1,3484 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <string.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <app.h>
+#include <rte_common.h>
+#include <rte_malloc.h>
+#include <rte_ip.h>
+#include <rte_byteorder.h>
+#include <rte_table_stub.h>
+#include <rte_table_hash.h>
+#include <rte_pipeline.h>
+#include <rte_arp.h>
+#include <rte_icmp.h>
+#include <rte_hash.h>
+#include <rte_jhash.h>
+#include <rte_cycles.h>
+#include <rte_hexdump.h>
+#include "pipeline_actions_common.h"
+#include "hash_func.h"
+#include "vnf_common.h"
+#include "pipeline_common_be.h"
+#include "pipeline_arpicmp_be.h"
+#include "parser.h"
+#include "hash_func.h"
+#include "vnf_common.h"
+#include "app.h"
+
+#include"pipeline_common_fe.h"
+#ifndef VNF_ACL
+#include "lib_arp.h"
+#include "lib_icmpv6.h"
+#include "interface.h"
+#endif
+
+#ifdef VNF_ACL
+
+#define NB_ARPICMP_MBUF  64
+#define NB_NDICMP_MBUF  64
+#define IP_VERSION_4 0x40
+/* default IP header length == five 32-bits words. */
+#define IP_HDRLEN  0x05
+#define IP_VHL_DEF (IP_VERSION_4 | IP_HDRLEN)
+
+#define is_multicast_ipv4_addr(ipv4_addr) \
+       (((rte_be_to_cpu_32((ipv4_addr)) >> 24) & 0x000000FF) == 0xE0)
+
+
+/*ND IPV6 */
+#define INADDRSZ 4
+#define IN6ADDRSZ 16
+static int my_inet_pton_ipv6(int af, const char *src, void *dst);
+static int inet_pton_ipv6(const char *src, unsigned char *dst);
+static int inet_pton_ipv4(const char *src, unsigned char *dst);
+
+uint8_t vnf_common_arp_lib_init;
+uint8_t vnf_common_nd_lib_init;
+uint8_t loadb_pipeline_count;
+
+uint32_t ARPICMP_DEBUG;
+uint32_t NDIPV6_DEBUG;
+
+uint32_t arp_route_tbl_index;
+uint32_t nd_route_tbl_index;
+uint32_t link_hw_addr_array_idx;
+
+uint32_t lib_arp_get_mac_req;
+uint32_t lib_arp_nh_found;
+uint32_t lib_arp_no_nh_found;
+uint32_t lib_arp_arp_entry_found;
+uint32_t lib_arp_no_arp_entry_found;
+uint32_t lib_arp_populate_called;
+uint32_t lib_arp_delete_called;
+uint32_t lib_arp_duplicate_found;
+
+uint32_t lib_nd_get_mac_req;
+uint32_t lib_nd_nh_found;
+uint32_t lib_nd_no_nh_found;
+uint32_t lib_nd_nd_entry_found;
+uint32_t lib_nd_no_arp_entry_found;
+uint32_t lib_nd_populate_called;
+uint32_t lib_nd_delete_called;
+uint32_t lib_nd_duplicate_found;
+
+struct rte_mempool *lib_arp_pktmbuf_tx_pool;
+struct rte_mempool *lib_nd_pktmbuf_tx_pool;
+
+struct rte_mbuf *lib_arp_pkt;
+struct rte_mbuf *lib_nd_pkt;
+
+static struct rte_hash_parameters arp_hash_params = {
+       .name = "ARP",
+       .entries = 64,
+       .reserved = 0,
+       .key_len = sizeof(struct arp_key_ipv4),
+       .hash_func = rte_jhash,
+       .hash_func_init_val = 0,
+};
+
+static struct rte_hash_parameters nd_hash_params = {
+       .name = "ND",
+       .entries = 64,
+       .reserved = 0,
+       .key_len = sizeof(struct nd_key_ipv6),
+       .hash_func = rte_jhash,
+       .hash_func_init_val = 0,
+};
+
+struct rte_hash *arp_hash_handle;
+struct rte_hash *nd_hash_handle;
+
+#endif
+/* Shared among all VNFs including LB */
+struct app_params *myApp;
+struct rte_pipeline *myP;
+struct pipeline_arpicmp *gp_arp;
+uint8_t num_vnf_threads;
+
+#ifdef VNF_ACL
+
+struct arp_port_address {
+       uint32_t ip;
+       uint64_t mac_addr;
+};
+
+struct arp_port_address arp_port_addresses[RTE_MAX_ETHPORTS];
+
+uint16_t arp_meta_offset;
+#endif
+
+struct pipeline_arpicmp {
+       struct pipeline p;
+       pipeline_msg_req_handler
+               custom_handlers[PIPELINE_ARPICMP_MSG_REQS];
+       uint64_t receivedPktCount;
+       uint64_t droppedPktCount;
+       uint64_t sentPktCount;
+       uint8_t links_map[PIPELINE_MAX_PORT_IN];
+       uint8_t outport_id[PIPELINE_MAX_PORT_IN];
+       uint8_t pipeline_num;
+} __rte_cache_aligned;
+
+#ifdef VNF_ACL
+
+#define MAX_NUM_ARP_ENTRIES 64
+#define MAX_NUM_ND_ENTRIES 64
+
+
+struct lib_nd_route_table_entry lib_nd_route_table[MAX_ND_RT_ENTRY] = {
+       {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, 0,
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+       {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, 0,
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+       {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, 0,
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+       {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, 0,
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+       {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, 0,
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+       {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, 0,
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+       {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, 0,
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+       {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, 0,
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+       {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, 0,
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+       {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, 0,
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+       {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, 0,
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+       {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, 0,
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+       {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, 0,
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+       {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, 0,
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+       {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, 0,
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+       {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, 0,
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }
+};
+
+struct lib_arp_route_table_entry lib_arp_route_table[MAX_ARP_RT_ENTRY] = {
+//   {0xac102814, 1, 0xac102814},
+//   {0xac106414, 0, 0xac106414},
+       {0, 0, 0, 0},
+       {0, 0, 0, 0},
+       {0, 0, 0, 0},
+       {0, 0, 0, 0},
+       {0, 0, 0, 0},
+       {0, 0, 0, 0},
+       {0, 0, 0, 0},
+       {0, 0, 0, 0},
+       {0, 0, 0, 0},
+       {0, 0, 0, 0},
+       {0, 0, 0, 0},
+       {0, 0, 0, 0},
+       {0, 0, 0, 0},
+       {0, 0, 0, 0},
+       {0, 0, 0, 0},
+       {0, 0, 0, 0}
+};
+
+#endif
+
+void pipelines_port_info(void)
+{
+       struct app_params *app = myApp;
+       uint8_t i, pipeline;
+       for (pipeline = 0; pipeline < app->n_pipelines; pipeline++) {
+               printf("*** PIPELINE %d ***\n\n", pipeline);
+
+               printf("*** OUTPORTs ***\n");
+               for (i = 1; i < app->pipeline_params[pipeline].n_pktq_out;
+                       i++) {
+                       switch (app->pipeline_params[pipeline].pktq_out[i].
+                       type) {
+                       case APP_PKTQ_OUT_SWQ:
+                               printf("pktq_out[%d]:%s\n", i,
+                                                        app->swq_params[app->pipeline_params
+                                                                        [pipeline].
+                                                                        pktq_out[i].id].name);
+                               break;
+                       case APP_PKTQ_OUT_HWQ:
+                               printf("pktq_out[%d]:%s\n", i,
+                                                        app->hwq_out_params[app->pipeline_params
+                                                                [pipeline].pktq_out
+                                                                [i].id].name);
+                               break;
+                       default:
+                               printf("Not OUT SWQ or HWQ\n");
+                       }
+               }
+               printf("*** INPORTs ***\n");
+               for (i = 0; i < app->pipeline_params[pipeline].n_pktq_in; i++) {
+                       switch (app->pipeline_params[pipeline].pktq_in[i]
+                       .type) {
+                       case APP_PKTQ_IN_SWQ:
+                               printf("pktq_in[%d]:%s\n", i,
+                                                        app->swq_params[app->pipeline_params
+                                                                        [pipeline].
+                                                                        pktq_in[i].id].name);
+                               break;
+                       case APP_PKTQ_IN_HWQ:
+                               printf("pktq_in[%d]:%s\n", i,
+                                                        app->hwq_in_params[app->pipeline_params
+                                                               [pipeline].
+                                                               pktq_in[i].id].name);
+                               break;
+                       default:
+                               printf("Not IN SWQ or HWQ\n");
+                       }
+               }
+       }                       //for
+}
+
+void pipelines_map_info(void)
+{
+        int i = 0;
+
+       printf("PIPELINE_MAX_PORT_IN %d\n", PIPELINE_MAX_PORT_IN);
+       printf("lb_outport_id[%d", lb_outport_id[0]);
+       for (i = 1; i < PIPELINE_MAX_PORT_IN; i++)
+               printf(",%d", lb_outport_id[i]);
+       printf("]\n");
+
+       printf("vnf_to_loadb_map[%d", vnf_to_loadb_map[0]);
+       for (i = 1; i < PIPELINE_MAX_PORT_IN; i++)
+               printf(",%d", vnf_to_loadb_map[i]);
+       printf("]\n");
+
+       printf("port_to_loadb_map[%d", port_to_loadb_map[0]);
+       for (i = 1; i < PIPELINE_MAX_PORT_IN; i++)
+               printf(",%d", port_to_loadb_map[i]);
+       printf("]\n");
+
+       printf("loadb_pipeline_nums[%d", loadb_pipeline_nums[0]);
+       for (i = 1; i < PIPELINE_MAX_PORT_IN; i++)
+               printf(",%d", loadb_pipeline_nums[i]);
+       printf("]\n");
+
+       printf("loadb_pipeline[%p", loadb_pipeline[0]);
+       for (i = 1; i < PIPELINE_MAX_PORT_IN; i++)
+               printf(",%p", loadb_pipeline[i]);
+       printf("]\n");
+}
+
+void register_pipeline_Qs(uint8_t pipeline_num, struct pipeline *p)
+{
+       struct rte_port_ethdev_reader *hwq;
+       struct rte_port_ring_writer *out_swq;
+       struct rte_port_ring_reader *in_swq;
+       struct rte_pipeline *rte = p->p;
+       uint8_t port_count = 0;
+       int queue_out = 0xff, queue_in = 0xff;
+
+       printf("Calling register_pipeline_Qs in PIPELINE%d\n", pipeline_num);
+       for (port_count = 0; port_count < rte->num_ports_out; port_count++) {
+
+       switch (myApp->pipeline_params[pipeline_num].
+                               pktq_out[port_count].type){
+
+       case APP_PKTQ_OUT_SWQ:
+
+               if (port_count >= rte->num_ports_in) {
+
+                       /* Dont register ARP output Q */
+                       if (rte->num_ports_out % rte->num_ports_in)
+                               if (port_count == rte->num_ports_out - 1)
+                                       return;
+                       int temp;
+                       temp = ((port_count) % rte->num_ports_in);
+
+                       in_swq = rte->ports_in[temp].h_port;
+                       out_swq = rte->ports_out[port_count].h_port;
+                       printf("in_swq : %s\n",
+                               in_swq->ring->name);
+                       int status =
+                       sscanf(in_swq->ring->name, "SWQ%d",
+                                       &queue_in);
+                       if (status < 0) {
+                               printf("Unable to read SWQ number\n");
+                               return;
+                       }
+                       printf("out_swq: %s\n",
+                                       out_swq->ring->name);
+                       status =
+                       sscanf(out_swq->ring->name, "SWQ%d",
+                                       &queue_out);
+                       if (status < 0) {
+                               printf("Unable to read SWQ number\n");
+                               return;
+                       }
+                       if (queue_in < 128 && queue_out < 128) {
+                               SWQ_to_Port_map[queue_out] =
+                                       SWQ_to_Port_map[queue_in];
+                        printf("SWQ_to_Port_map[%d]%d\n", queue_out,
+                                SWQ_to_Port_map[queue_out]);
+                        }
+                       continue;
+               }
+
+               switch (myApp->pipeline_params[pipeline_num].
+                        pktq_in[port_count].type){
+
+               case APP_PKTQ_OUT_HWQ:
+                        hwq = rte->ports_in[port_count].h_port;
+                        out_swq = rte->ports_out[port_count].h_port;
+                        printf("out_swq: %s\n",
+                                out_swq->ring->name);
+                       int status =
+                       sscanf(out_swq->ring->name, "SWQ%d",
+                                &queue_out);
+
+                       if (status < 0) {
+                               printf("Unable to read SWQ number\n");
+                               return;
+                       }
+                       if (queue_out < 128) {
+                               SWQ_to_Port_map[queue_out] = hwq->port_id;
+                               printf("SWQ_to_Port_map[%d]%d\n", queue_out,
+                                       SWQ_to_Port_map[queue_out]);
+                       }
+               break;
+
+               case APP_PKTQ_OUT_SWQ:
+                        in_swq = rte->ports_in[port_count].h_port;
+                        out_swq = rte->ports_out[port_count].h_port;
+                        printf("in_swq : %s\n",
+                                in_swq->ring->name);
+                       status =
+                       sscanf(in_swq->ring->name, "SWQ%d",
+                                        &queue_in);
+                       if (status < 0) {
+                               printf("Unable to read SWQ number\n");
+                               return;
+                       }
+                       printf("out_swq: %s\n",
+                                        out_swq->ring->name);
+                       status =
+                       sscanf(out_swq->ring->name, "SWQ%d",
+                                        &queue_out);
+                       if (status < 0) {
+                               printf("Unable to read SWQ number\n");
+                               return;
+                       }
+                       if (queue_in < 128 && queue_out < 128){
+                               SWQ_to_Port_map[queue_out] =
+                                       SWQ_to_Port_map[queue_in];
+                        printf("SWQ_to_Port_map[%d]%d\n", queue_out,
+                                SWQ_to_Port_map[queue_out]);
+                          }
+               break;
+
+               default:
+                        printf("This never hits\n");
+               }
+
+       break;
+
+       case APP_PKTQ_OUT_HWQ:
+                printf("This is HWQ\n");
+       break;
+
+       default:
+                printf("set_phy_outport_map: This never hits\n");
+       }
+       }
+}
+
+void set_link_map(uint8_t pipeline_num, struct pipeline *p, uint8_t *map)
+{
+               struct rte_port_ethdev_writer *hwq;
+               struct rte_port_ring_writer *out_swq;
+               struct rte_pipeline *rte = p->p;
+
+               uint8_t port_count = 0;
+               int index = 0, queue_out = 0xff;
+
+       printf("Calling set_link_map in PIPELINE%d\n", pipeline_num);
+       for (port_count = 0; port_count < rte->num_ports_out; port_count++) {
+
+               switch (myApp->pipeline_params[pipeline_num].
+                               pktq_out[port_count].type){
+
+               case APP_PKTQ_OUT_HWQ:
+                       hwq = rte->ports_out[port_count].h_port;
+                       map[index++] = hwq->port_id;
+                       printf("links_map[%d]:%d\n", index - 1, map[index - 1]);
+               break;
+
+               case APP_PKTQ_OUT_SWQ:
+                       out_swq = rte->ports_out[port_count].h_port;
+                       printf("set_link_map out_swq: %s\n",
+                               out_swq->ring->name);
+                       int status = sscanf(out_swq->ring->name, "SWQ%d",
+                                       &queue_out);
+                       if (status < 0) {
+                               printf("Unable to read SWQ number\n");
+                               return;
+                       }
+
+                       if (queue_out < 128) {
+                       map[index++] = SWQ_to_Port_map[queue_out];
+                       printf("links_map[%s]:%d\n", out_swq->ring->name,
+                                       map[index - 1]);
+                       }
+               break;
+
+               default:
+                       printf("set_phy_outport_map: This never hits\n");
+               }
+               }
+}
+
+void set_outport_id(uint8_t pipeline_num, struct pipeline *p, uint8_t *map)
+{
+       uint8_t port_count = 0;
+       int queue_out = 0xff, index = 0;
+
+       struct rte_port_ethdev_writer *hwq;
+       struct rte_port_ring_writer *out_swq;
+       struct rte_pipeline *rte = p->p;
+
+       printf("\n**** set_outport_id() with pipeline_num:%d ****\n\n",
+               pipeline_num);
+       for (port_count = 0;
+               port_count < rte->num_ports_out;
+               port_count++) {
+
+       switch (myApp->pipeline_params[pipeline_num].
+                       pktq_out[port_count].type) {
+
+       case APP_PKTQ_OUT_HWQ:
+               hwq = rte->ports_out[port_count].h_port;
+               //if (index >= 0)
+               {
+                       map[hwq->port_id] = index;
+                       printf("hwq port_id:%d index:%d\n",
+                               hwq->port_id, index);
+                       map[hwq->port_id] = index++;
+                       printf("hwq port_id:%d index:%d\n",
+                               hwq->port_id, index-1);
+                       printf("outport_id[%d]:%d\n", index - 1,
+                               map[index - 1]);
+               }
+               break;
+
+       case APP_PKTQ_OUT_SWQ:
+
+               /* Dont register ARP output Q */
+               if (port_count >= rte->num_ports_in)
+                       if (rte->num_ports_out % rte->num_ports_in)
+                               if (port_count == rte->num_ports_out - 1)
+                                       return;
+                out_swq = rte->ports_out[port_count].h_port;
+                printf("set_outport_id out_swq: %s\n",
+                        out_swq->ring->name);
+               int temp = sscanf(out_swq->ring->name, "SWQ%d",
+                                &queue_out);
+               if (temp < 0) {
+                       printf("Unable to read SWQ number\n");
+                       return;
+               }
+
+               if (queue_out < 128 && index >= 0) {
+                       map[SWQ_to_Port_map[queue_out]] = index++;
+                       printf("outport_id[%s]:%d\n", out_swq->ring->name,
+                                        map[SWQ_to_Port_map[queue_out]]);
+               }
+               break;
+
+               default:
+                        printf(" ");
+
+               }
+       }
+}
+
+void set_phy_outport_id(uint8_t pipeline_num, struct pipeline *p, uint8_t *map)
+{
+       uint8_t port_count = 0;
+       int index = 0;
+
+       struct rte_port_ethdev_writer *hwq;
+       struct rte_pipeline *rte = p->p;
+
+       printf("\n**** set_phy_outport_id() with pipeline_num:%d ****\n\n",
+               pipeline_num);
+       for (port_count = 0;
+               port_count < myApp->pipeline_params[pipeline_num].n_pktq_out;
+               port_count++) {
+
+       switch (myApp->pipeline_params[pipeline_num].
+                       pktq_out[port_count].type) {
+
+       case APP_PKTQ_OUT_HWQ:
+               hwq = rte->ports_out[port_count].h_port;
+               map[hwq->port_id] = index++;
+               printf("outport_id[%d]:%d\n", index - 1,
+                       map[index - 1]);
+       break;
+
+       default:
+                printf(" ");
+
+               }
+       }
+}
+
+void set_phy_inport_id(uint8_t pipeline_num, struct pipeline *p, uint8_t *map)
+{
+       uint8_t port_count = 0;
+       int index = 0;
+
+       struct rte_port_ethdev_reader *hwq;
+       struct rte_pipeline *rte = p->p;
+
+       printf("\n**** set_phy_inport_id() with pipeline_num:%d ****\n\n",
+                                pipeline_num);
+       for (port_count = 0;
+               port_count < myApp->pipeline_params[pipeline_num].n_pktq_in;
+               port_count++) {
+
+               switch (myApp->pipeline_params[pipeline_num].
+                       pktq_in[port_count].type) {
+
+               case APP_PKTQ_OUT_HWQ:
+                       hwq = rte->ports_in[port_count].h_port;
+                       map[hwq->port_id] = index++;
+                       printf("outport_id[%d]:%d\n", index - 1,
+                               map[index - 1]);
+               break;
+
+               default:
+                       printf(" ");
+
+               }
+       }
+}
+
+#ifdef VNF_ACL
+
+uint32_t get_nh(uint32_t ip, uint32_t *port)
+{
+       int i = 0;
+       for (i = 0; i < MAX_ARP_RT_ENTRY; i++) {
+               if (((lib_arp_route_table[i].
+                       ip & lib_arp_route_table[i].mask) ==
+                       (ip & lib_arp_route_table[i].mask))) {
+
+                       *port = lib_arp_route_table[i].port;
+                       lib_arp_nh_found++;
+                       return lib_arp_route_table[i].nh;
+               }
+       if (ARPICMP_DEBUG > 1)
+               printf("No nh match ip 0x%x, port %u, t_ip "
+               "0x%x, t_port %u, mask 0x%x, r1 %x, r2 %x\n",
+               ip, *port, lib_arp_route_table[i].ip,
+               lib_arp_route_table[i].port,
+               lib_arp_route_table[i].mask,
+               (lib_arp_route_table[i].ip &
+               lib_arp_route_table[i].mask),
+               (ip & lib_arp_route_table[i].mask));
+       }
+       if (ARPICMP_DEBUG && ip)
+               printf("No NH - ip 0x%x, port %u\n", ip, *port);
+       lib_arp_no_nh_found++;
+       return 0;
+}
+
+/*ND IPv6 */
+void get_nh_ipv6(uint8_t ipv6[], uint32_t *port, uint8_t nhipv6[])
+{
+       int i = 0;
+       uint8_t netmask_ipv6[16], netip_nd[16], netip_in[16];
+       uint8_t k = 0, l = 0, depthflags = 0, depthflags1 = 0;
+       memset(netmask_ipv6, 0, sizeof(netmask_ipv6));
+       memset(netip_nd, 0, sizeof(netip_nd));
+       memset(netip_in, 0, sizeof(netip_in));
+       if (!ipv6)
+               return;
+       for (i = 0; i < MAX_ARP_RT_ENTRY; i++) {
+
+               convert_prefixlen_to_netmask_ipv6(
+                                       lib_nd_route_table[i].depth,
+                                       netmask_ipv6);
+
+               for (k = 0; k < 16; k++) {
+                       if (lib_nd_route_table[i].ipv6[k] & netmask_ipv6[k]) {
+                               depthflags++;
+                               netip_nd[k] = lib_nd_route_table[i].ipv6[k];
+                       }
+               }
+
+               for (l = 0; l < 16; l++) {
+                       if (ipv6[l] & netmask_ipv6[l]) {
+                               depthflags1++;
+                               netip_in[l] = ipv6[l];
+                       }
+               }
+               int j = 0;
+               if ((depthflags == depthflags1)
+                       && (memcmp(netip_nd, netip_in,
+                               sizeof(netip_nd)) == 0)) {
+                       //&& (lib_nd_route_table[i].port == port))
+                       *port = lib_nd_route_table[i].port;
+                       lib_nd_nh_found++;
+
+                       for (j = 0; j < 16; j++)
+                               nhipv6[j] = lib_nd_route_table[i].nhipv6[j];
+
+                       return;
+               }
+
+               if (NDIPV6_DEBUG > 1)
+                       printf("No nh match\n");
+               depthflags = 0;
+               depthflags1 = 0;
+       }
+       if (NDIPV6_DEBUG && ipv6)
+               printf("No NH - ip 0x%x, port %u\n", ipv6[0], *port);
+       lib_nd_no_nh_found++;
+}
+
+/* Added for Multiport changes*/
+int get_dest_mac_addr_port(const uint32_t ipaddr,
+                                       uint32_t *phy_port, struct ether_addr *hw_addr)
+{
+       lib_arp_get_mac_req++;
+       uint32_t nhip = 0;
+
+       nhip = get_nh(ipaddr, phy_port);
+       if (nhip == 0) {
+               if (ARPICMP_DEBUG && ipaddr)
+                       printf("ARPICMP no nh found for ip %x, port %d\n",
+                                                ipaddr, *phy_port);
+               //return 0;
+               return NH_NOT_FOUND;
+       }
+
+       struct arp_entry_data *ret_arp_data = NULL;
+       struct arp_key_ipv4 tmp_arp_key;
+       tmp_arp_key.port_id = *phy_port;/* Changed for Multi Port*/
+       tmp_arp_key.ip = nhip;
+
+       ret_arp_data = retrieve_arp_entry(tmp_arp_key);
+       if (ret_arp_data == NULL) {
+               if (ARPICMP_DEBUG && ipaddr) {
+                       printf
+                                       ("ARPICMP no arp entry found for ip %x, port %d\n",
+                                        ipaddr, *phy_port);
+                       print_arp_table();
+               }
+               lib_arp_no_arp_entry_found++;
+               return ARP_NOT_FOUND;
+       }
+       ether_addr_copy(&ret_arp_data->eth_addr, hw_addr);
+       lib_arp_arp_entry_found++;
+       return ARP_FOUND;
+}
+
+/*ND IPv6 */
+int get_dest_mac_address_ipv6(uint8_t ipv6addr[], uint32_t phy_port,
+                                                struct ether_addr *hw_addr, uint8_t nhipv6[])
+{
+       int i = 0, j = 0, flag = 0;
+       lib_nd_get_mac_req++;
+
+       if (ipv6addr)
+       get_nh_ipv6(ipv6addr, &phy_port, nhipv6);
+       for (j = 0; j < 16; j++) {
+               if (nhipv6[j])
+                       flag++;
+       }
+       if (flag == 0) {
+               if (ipv6addr) {
+               if (NDIPV6_DEBUG && ipv6addr)
+                       printf("NDIPV6 no nh found for ipv6 "
+                       "%02x%02x%02x%02x%02x%02x%02x%02x%02x"
+                       "%02x%02x%02x%02x%02x%02x%02x, port %d\n",
+                       ipv6addr[0], ipv6addr[1], ipv6addr[2], ipv6addr[3],
+                       ipv6addr[4], ipv6addr[5], ipv6addr[6], ipv6addr[7],
+                       ipv6addr[8], ipv6addr[9], ipv6addr[10],
+                       ipv6addr[11], ipv6addr[12], ipv6addr[13],
+                       ipv6addr[14], ipv6addr[15], phy_port);
+                       return 0;
+       }
+       }
+
+        struct nd_entry_data *ret_nd_data = NULL;
+        struct nd_key_ipv6 tmp_nd_key;
+        tmp_nd_key.port_id = phy_port;
+
+       for (i = 0; i < 16; i++)
+               tmp_nd_key.ipv6[i] = nhipv6[i];
+
+        ret_nd_data = retrieve_nd_entry(tmp_nd_key);
+       if (ret_nd_data == NULL) {
+               if (NDIPV6_DEBUG && ipv6addr) {
+                       printf("NDIPV6 no nd entry found for ip %x, port %d\n",
+                               ipv6addr[0], phy_port);
+               }
+                lib_nd_no_arp_entry_found++;
+               return 0;
+       }
+        ether_addr_copy(&ret_nd_data->eth_addr, hw_addr);
+        lib_nd_nd_entry_found++;
+       return 1;
+
+}
+
+/*ND IPv6 */
+int get_dest_mac_address_ipv6_port(uint8_t ipv6addr[], uint32_t *phy_port,
+                                                struct ether_addr *hw_addr, uint8_t nhipv6[])
+{
+       int i = 0, j = 0, flag = 0;
+       lib_nd_get_mac_req++;
+
+       get_nh_ipv6(ipv6addr, phy_port, nhipv6);
+       for (j = 0; j < 16; j++) {
+               if (nhipv6[j])
+                       flag++;
+       }
+       if (flag == 0) {
+               if (NDIPV6_DEBUG && ipv6addr)
+                       printf("NDIPV6 no nh found for ipv6 "
+                       "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
+                       "%02x%02x%02x%02x%02x%02x, port %d\n",
+                       ipv6addr[0], ipv6addr[1], ipv6addr[2], ipv6addr[3],
+                       ipv6addr[4], ipv6addr[5], ipv6addr[6], ipv6addr[7],
+                       ipv6addr[8], ipv6addr[9], ipv6addr[10],
+                       ipv6addr[11], ipv6addr[12], ipv6addr[13],
+                       ipv6addr[14], ipv6addr[15], *phy_port);
+                       return 0;
+       }
+
+        struct nd_entry_data *ret_nd_data = NULL;
+        struct nd_key_ipv6 tmp_nd_key;
+        tmp_nd_key.port_id = *phy_port;
+
+       for (i = 0; i < 16; i++)
+               tmp_nd_key.ipv6[i] = nhipv6[i];
+
+        ret_nd_data = retrieve_nd_entry(tmp_nd_key);
+       if (ret_nd_data == NULL) {
+               if (NDIPV6_DEBUG && ipv6addr) {
+                       printf("NDIPV6 no nd entry found for ip %x, port %d\n",
+                               ipv6addr[0], *phy_port);
+               }
+                lib_nd_no_arp_entry_found++;
+               return 0;
+       }
+        ether_addr_copy(&ret_nd_data->eth_addr, hw_addr);
+        lib_nd_nd_entry_found++;
+       return 1;
+
+}
+
+/*
+ * ARP table
+ */
+struct lib_arp_arp_table_entry {
+       struct rte_pipeline_table_entry head;
+       uint64_t macaddr;
+};
+
+static const char *arp_op_name(uint16_t arp_op)
+{
+       switch (CHECK_ENDIAN_16(arp_op)) {
+       case (ARP_OP_REQUEST):
+               return "ARP Request";
+       case (ARP_OP_REPLY):
+               return "ARP Reply";
+       case (ARP_OP_REVREQUEST):
+               return "Reverse ARP Request";
+       case (ARP_OP_REVREPLY):
+               return "Reverse ARP Reply";
+       case (ARP_OP_INVREQUEST):
+               return "Peer Identify Request";
+       case (ARP_OP_INVREPLY):
+               return "Peer Identify Reply";
+       default:
+               break;
+       }
+       return "Unkwown ARP op";
+}
+
+static void print_icmp_packet(struct icmp_hdr *icmp_h)
+{
+       printf("  ICMP: type=%d (%s) code=%d id=%d seqnum=%d\n",
+                                icmp_h->icmp_type,
+                                (icmp_h->icmp_type == IP_ICMP_ECHO_REPLY ? "Reply" :
+               (icmp_h->icmp_type ==
+                IP_ICMP_ECHO_REQUEST ? "Reqest" : "Undef")), icmp_h->icmp_code,
+                                CHECK_ENDIAN_16(icmp_h->icmp_ident),
+                                CHECK_ENDIAN_16(icmp_h->icmp_seq_nb));
+}
+
+static void print_ipv4_h(struct ipv4_hdr *ip_h)
+{
+       struct icmp_hdr *icmp_h =
+                       (struct icmp_hdr *)((char *)ip_h + sizeof(struct ipv4_hdr));
+       printf("  IPv4: Version=%d HLEN=%d Type=%d Length=%d\n",
+                                (ip_h->version_ihl & 0xf0) >> 4, (ip_h->version_ihl & 0x0f),
+                                ip_h->type_of_service, rte_cpu_to_be_16(ip_h->total_length));
+       if (ip_h->next_proto_id == IPPROTO_ICMP)
+               print_icmp_packet(icmp_h);
+}
+
+static void print_arp_packet(struct arp_hdr *arp_h)
+{
+       printf("  ARP:  hrd=%d proto=0x%04x hln=%d "
+                                "pln=%d op=%u (%s)\n",
+                                CHECK_ENDIAN_16(arp_h->arp_hrd),
+                                CHECK_ENDIAN_16(arp_h->arp_pro), arp_h->arp_hln,
+                                arp_h->arp_pln, CHECK_ENDIAN_16(arp_h->arp_op),
+                                arp_op_name(arp_h->arp_op));
+
+       if (CHECK_ENDIAN_16(arp_h->arp_hrd) != ARP_HRD_ETHER) {
+               printf("incorrect arp_hrd format for IPv4 ARP (%d)\n",
+                                        (arp_h->arp_hrd));
+       } else if (CHECK_ENDIAN_16(arp_h->arp_pro) != ETHER_TYPE_IPv4) {
+               printf("incorrect arp_pro format for IPv4 ARP (%d)\n",
+                                        (arp_h->arp_pro));
+       } else if (arp_h->arp_hln != 6) {
+               printf("incorrect arp_hln format for IPv4 ARP (%d)\n",
+                                        arp_h->arp_hln);
+       } else if (arp_h->arp_pln != 4) {
+               printf("incorrect arp_pln format for IPv4 ARP (%d)\n",
+                                        arp_h->arp_pln);
+       } else {
+               // print remainder of ARP request
+               printf("        sha=%02X:%02X:%02X:%02X:%02X:%02X",
+                                        arp_h->arp_data.arp_sha.addr_bytes[0],
+                                        arp_h->arp_data.arp_sha.addr_bytes[1],
+                                        arp_h->arp_data.arp_sha.addr_bytes[2],
+                                        arp_h->arp_data.arp_sha.addr_bytes[3],
+                                        arp_h->arp_data.arp_sha.addr_bytes[4],
+                                        arp_h->arp_data.arp_sha.addr_bytes[5]);
+               printf(" sip=%d.%d.%d.%d\n",
+                                        (CHECK_ENDIAN_32(arp_h->arp_data.arp_sip) >> 24) & 0xFF,
+                                        (CHECK_ENDIAN_32(arp_h->arp_data.arp_sip) >> 16) & 0xFF,
+                                        (CHECK_ENDIAN_32(arp_h->arp_data.arp_sip) >> 8) & 0xFF,
+                                        CHECK_ENDIAN_32(arp_h->arp_data.arp_sip) & 0xFF);
+               printf("        tha=%02X:%02X:%02X:%02X:%02X:%02X",
+                                        arp_h->arp_data.arp_tha.addr_bytes[0],
+                                        arp_h->arp_data.arp_tha.addr_bytes[1],
+                                        arp_h->arp_data.arp_tha.addr_bytes[2],
+                                        arp_h->arp_data.arp_tha.addr_bytes[3],
+                                        arp_h->arp_data.arp_tha.addr_bytes[4],
+                                        arp_h->arp_data.arp_tha.addr_bytes[5]);
+               printf(" tip=%d.%d.%d.%d\n",
+                                        (CHECK_ENDIAN_32(arp_h->arp_data.arp_tip) >> 24) & 0xFF,
+                                        (CHECK_ENDIAN_32(arp_h->arp_data.arp_tip) >> 16) & 0xFF,
+                                        (CHECK_ENDIAN_32(arp_h->arp_data.arp_tip) >> 8) & 0xFF,
+                                        CHECK_ENDIAN_32(arp_h->arp_data.arp_tip) & 0xFF);
+       }
+}
+
+static void print_eth(struct ether_hdr *eth_h)
+{
+       printf("  ETH:  src=%02X:%02X:%02X:%02X:%02X:%02X",
+                                eth_h->s_addr.addr_bytes[0],
+                                eth_h->s_addr.addr_bytes[1],
+                                eth_h->s_addr.addr_bytes[2],
+                                eth_h->s_addr.addr_bytes[3],
+                                eth_h->s_addr.addr_bytes[4], eth_h->s_addr.addr_bytes[5]);
+       printf(" dst=%02X:%02X:%02X:%02X:%02X:%02X\n",
+                                eth_h->d_addr.addr_bytes[0],
+                                eth_h->d_addr.addr_bytes[1],
+                                eth_h->d_addr.addr_bytes[2],
+                                eth_h->d_addr.addr_bytes[3],
+                                eth_h->d_addr.addr_bytes[4], eth_h->d_addr.addr_bytes[5]);
+
+}
+
+static void
+print_mbuf(const char *rx_tx, unsigned int portid, struct rte_mbuf *mbuf,
+                unsigned int line)
+{
+       struct ether_hdr *eth_h = rte_pktmbuf_mtod(mbuf, struct ether_hdr *);
+       struct arp_hdr *arp_h =
+                       (struct arp_hdr *)((char *)eth_h + sizeof(struct ether_hdr));
+       struct ipv4_hdr *ipv4_h =
+                       (struct ipv4_hdr *)((char *)eth_h + sizeof(struct ether_hdr));
+
+       printf("%s(%d): on port %d pkt-len=%u nb-segs=%u\n",
+                                rx_tx, line, portid, mbuf->pkt_len, mbuf->nb_segs);
+       print_eth(eth_h);
+       switch (rte_cpu_to_be_16(eth_h->ether_type)) {
+       case ETHER_TYPE_IPv4:
+               print_ipv4_h(ipv4_h);
+               break;
+       case ETHER_TYPE_ARP:
+               print_arp_packet(arp_h);
+               break;
+       default:
+               printf("  unknown packet type\n");
+               break;
+       }
+       fflush(stdout);
+}
+
+struct arp_entry_data *retrieve_arp_entry(struct arp_key_ipv4 arp_key)
+{
+       struct arp_entry_data *ret_arp_data = NULL;
+       arp_key.filler1 = 0;
+       arp_key.filler2 = 0;
+       arp_key.filler3 = 0;
+
+       int ret = rte_hash_lookup_data(arp_hash_handle, &arp_key,
+                                                        (void **)&ret_arp_data);
+       if (ret < 0) {
+               if (ARPICMP_DEBUG)
+                       printf("arp-hash lookup failed ret %d, "
+                       "EINVAL %d, ENOENT %d\n",
+                       ret, EINVAL, ENOENT);
+       } else {
+               return ret_arp_data;
+       }
+
+       return NULL;
+}
+
+/*
+* ND IPv6
+* Validate if key-value pair already exists in the hash table
+* for given key - ND IPv6
+*
+*/
+struct nd_entry_data *retrieve_nd_entry(struct nd_key_ipv6 nd_key)
+{
+       struct nd_entry_data *ret_nd_data = NULL;
+       nd_key.filler1 = 0;
+       nd_key.filler2 = 0;
+       nd_key.filler3 = 0;
+
+       /*Find a nd IPv6 key-data pair in the hash table for ND IPv6 */
+       int ret = rte_hash_lookup_data(nd_hash_handle, &nd_key,
+                                                        (void **)&ret_nd_data);
+       if (ret < 0) {
+               if (NDIPV6_DEBUG)
+                       printf("nd-hash: no lookup Entry Found - "
+                       "ret %d, EINVAL %d, ENOENT %d\n",
+                       ret, EINVAL, ENOENT);
+       } else {
+               return ret_nd_data;
+       }
+
+       return NULL;
+}
+
+void print_arp_table(void)
+{
+       const void *next_key;
+       void *next_data;
+       uint32_t iter = 0;
+
+       printf("\tport  hw addr            status     ip addr\n");
+
+       while (rte_hash_iterate(arp_hash_handle, &next_key, &next_data, &iter)
+                                >= 0) {
+
+               struct arp_entry_data *tmp_arp_data =
+                               (struct arp_entry_data *)next_data;
+               struct arp_key_ipv4 tmp_arp_key;
+               memcpy(&tmp_arp_key, next_key, sizeof(struct arp_key_ipv4));
+               printf
+                               ("\t%4d  %02X:%02X:%02X:%02X:%02X:%02X  %10s %d.%d.%d.%d\n",
+                                tmp_arp_data->port, tmp_arp_data->eth_addr.addr_bytes[0],
+                                tmp_arp_data->eth_addr.addr_bytes[1],
+                                tmp_arp_data->eth_addr.addr_bytes[2],
+                                tmp_arp_data->eth_addr.addr_bytes[3],
+                                tmp_arp_data->eth_addr.addr_bytes[4],
+                                tmp_arp_data->eth_addr.addr_bytes[5],
+                                tmp_arp_data->status ==
+                                COMPLETE ? "COMPLETE" : "INCOMPLETE",
+                                (tmp_arp_data->ip >> 24),
+                                ((tmp_arp_data->ip & 0x00ff0000) >> 16),
+                                ((tmp_arp_data->ip & 0x0000ff00) >> 8),
+                                ((tmp_arp_data->ip & 0x000000ff)));
+       }
+
+       uint32_t i = 0;
+       printf("\nARP routing table has %d entries\n", arp_route_tbl_index);
+       printf("\nIP_Address    Mask          Port    NH_IP_Address\n");
+       for (i = 0; i < arp_route_tbl_index; i++) {
+               printf("0x%x    0x%x    %d       0x%x\n",
+                                        lib_arp_route_table[i].ip,
+                                        lib_arp_route_table[i].mask,
+                                        lib_arp_route_table[i].port, lib_arp_route_table[i].nh);
+       }
+
+       printf("\nARP Stats: Total Queries %u, ok_NH %u, no_NH %u, "
+       "ok_Entry %u, no_Entry %u, PopulateCall %u, Del %u, Dup %u\n",
+                        lib_arp_get_mac_req, lib_arp_nh_found, lib_arp_no_nh_found,
+                        lib_arp_arp_entry_found, lib_arp_no_arp_entry_found,
+                        lib_arp_populate_called, lib_arp_delete_called,
+                        lib_arp_duplicate_found);
+
+       printf("ARP table key len is %lu\n", sizeof(struct arp_key_ipv4));
+}
+
+/* ND IPv6 */
+void print_nd_table(void)
+{
+       const void *next_key;
+       void *next_data;
+       uint32_t iter = 0;
+       uint8_t ii = 0, j = 0, k = 0;
+
+       printf("\tport  hw addr            status         ip addr\n");
+
+       while (rte_hash_iterate(nd_hash_handle, &next_key, &next_data, &iter) >=
+                                0) {
+
+               struct nd_entry_data *tmp_nd_data =
+                               (struct nd_entry_data *)next_data;
+               struct nd_key_ipv6 tmp_nd_key;
+               memcpy(&tmp_nd_key, next_key, sizeof(struct nd_key_ipv6));
+               printf("\t%4d  %02X:%02X:%02X:%02X:%02X:%02X  %10s\n",
+                                        tmp_nd_data->port,
+                                        tmp_nd_data->eth_addr.addr_bytes[0],
+                                        tmp_nd_data->eth_addr.addr_bytes[1],
+                                        tmp_nd_data->eth_addr.addr_bytes[2],
+                                        tmp_nd_data->eth_addr.addr_bytes[3],
+                                        tmp_nd_data->eth_addr.addr_bytes[4],
+                                        tmp_nd_data->eth_addr.addr_bytes[5],
+                                        tmp_nd_data->status ==
+                                        COMPLETE ? "COMPLETE" : "INCOMPLETE");
+               printf("\t\t\t\t\t\t");
+               for (ii = 0; ii < ND_IPV6_ADDR_SIZE; ii += 2) {
+                       printf("%02X%02X ", tmp_nd_data->ipv6[ii],
+                                                tmp_nd_data->ipv6[ii + 1]);
+               }
+               printf("\n");
+       }
+
+       uint32_t i = 0;
+       printf("\n\nND IPV6 routing table has %d entries\n",
+                                nd_route_tbl_index);
+       printf("\nIP_Address    Depth           Port    NH_IP_Address\n");
+       for (i = 0; i < nd_route_tbl_index; i++) {
+               printf("\n");
+
+               for (j = 0; j < ND_IPV6_ADDR_SIZE; j += 2) {
+                       printf("%02X%02X ", lib_nd_route_table[i].ipv6[j],
+                                                lib_nd_route_table[i].ipv6[j + 1]);
+               }
+
+               printf
+                               ("\n\t\t\t                      %d                                       %d\n",
+                                lib_nd_route_table[i].depth, lib_nd_route_table[i].port);
+               printf("\t\t\t\t\t\t\t\t\t");
+               for (k = 0; k < ND_IPV6_ADDR_SIZE; k += 2) {
+                       printf("%02X%02X ", lib_nd_route_table[i].nhipv6[k],
+                                                lib_nd_route_table[i].ipv6[k + 1]);
+               }
+       }
+       printf("\nND IPV6 Stats:\nTotal Queries %u, ok_NH %u, no_NH %u,"
+               "ok_Entry %u, no_Entry %u, PopulateCall %u, Del %u, Dup %u\n",
+                        lib_nd_get_mac_req, lib_nd_nh_found, lib_nd_no_nh_found,
+                        lib_nd_nd_entry_found, lib_nd_no_arp_entry_found,
+                        lib_nd_populate_called, lib_nd_delete_called,
+                        lib_nd_duplicate_found);
+       printf("ND table key len is %lu\n\n", sizeof(struct nd_key_ipv6));
+}
+
+void remove_arp_entry(uint32_t ipaddr, uint8_t portid)
+{
+
+       /* need to lock here if multi-threaded... */
+       /* rte_hash_del_key is not thread safe */
+       struct arp_key_ipv4 arp_key;
+       arp_key.port_id = portid;
+       arp_key.ip = ipaddr;
+       arp_key.filler1 = 0;
+       arp_key.filler2 = 0;
+       arp_key.filler3 = 0;
+
+       lib_arp_delete_called++;
+
+       if (ARPICMP_DEBUG)
+               printf("remove_arp_entry ip %x, port %d\n", arp_key.ip,
+                                        arp_key.port_id);
+       rte_hash_del_key(arp_hash_handle, &arp_key);
+}
+
+/* ND IPv6 */
+void remove_nd_entry_ipv6(uint8_t ipv6addr[], uint8_t portid)
+{
+       /* need to lock here if multi-threaded */
+       /* rte_hash_del_key is not thread safe */
+       int i = 0;
+       struct nd_key_ipv6 nd_key;
+       nd_key.port_id = portid;
+       /* arp_key.ip = rte_bswap32(ipaddr); */
+
+       for (i = 0; i < ND_IPV6_ADDR_SIZE; i++)
+               nd_key.ipv6[i] = ipv6addr[i];
+
+       nd_key.filler1 = 0;
+       nd_key.filler2 = 0;
+       nd_key.filler3 = 0;
+
+       lib_nd_delete_called++;
+
+       if (NDIPV6_DEBUG) {
+               printf("Deletes rte hash table nd entry for port %d ipv6=",
+                                        nd_key.port_id);
+               for (i = 0; i < ND_IPV6_ADDR_SIZE; i += 2)
+                       printf("%02X%02X ", nd_key.ipv6[i], nd_key.ipv6[i + 1]);
+       }
+       rte_hash_del_key(nd_hash_handle, &nd_key);
+}
+
+void
+populate_arp_entry(const struct ether_addr *hw_addr, uint32_t ipaddr,
+                        uint8_t portid)
+{
+       /* need to lock here if multi-threaded */
+       /* rte_hash_add_key_data is not thread safe */
+       struct arp_key_ipv4 arp_key;
+       arp_key.port_id = portid;
+       arp_key.ip = ipaddr;
+       arp_key.filler1 = 0;
+       arp_key.filler2 = 0;
+       arp_key.filler3 = 0;
+
+       lib_arp_populate_called++;
+
+       if (ARPICMP_DEBUG)
+               printf("populate_arp_entry ip %x, port %d\n", arp_key.ip,
+                                        arp_key.port_id);
+       struct arp_entry_data *new_arp_data = retrieve_arp_entry(arp_key);
+       if (new_arp_data
+                       && is_same_ether_addr(&new_arp_data->eth_addr, hw_addr)) {
+               if (ARPICMP_DEBUG)
+                       printf("arp_entry exists ip%x, port %d\n", arp_key.ip,
+                                                arp_key.port_id);
+               lib_arp_duplicate_found++;
+               return;
+       }
+       new_arp_data = (struct arp_entry_data *)
+                       malloc(sizeof(struct arp_entry_data));
+       if (new_arp_data == NULL) {
+       printf("populate_arp_entry:new_arp_data is NULL\n");
+               return;
+       }
+       new_arp_data->eth_addr = *hw_addr;
+       new_arp_data->status = INCOMPLETE;
+       new_arp_data->port = portid;
+       new_arp_data->ip = ipaddr;
+       rte_hash_add_key_data(arp_hash_handle, &arp_key, new_arp_data);
+
+       if (ARPICMP_DEBUG) {
+               // print entire hash table
+               printf("\tARP: table update - hwaddr= "
+               "%02x:%02x:%02x:%02x:%02x:%02x  ip=%d.%d.%d.%d  "
+               "on port=%d\n",
+               new_arp_data->eth_addr.addr_bytes[0],
+               new_arp_data->eth_addr.addr_bytes[1],
+               new_arp_data->eth_addr.addr_bytes[2],
+               new_arp_data->eth_addr.addr_bytes[3],
+               new_arp_data->eth_addr.addr_bytes[4],
+               new_arp_data->eth_addr.addr_bytes[5],
+               (arp_key.ip >> 24),
+               ((arp_key.ip & 0x00ff0000) >> 16),
+               ((arp_key.ip & 0x0000ff00) >> 8),
+               ((arp_key.ip & 0x000000ff)), portid);
+               /* print_arp_table(); */
+               puts("");
+       }
+}
+
+/*
+* ND IPv6
+*
+* Install key - data pair in Hash table - From Pipeline Configuration
+*
+*/
+int
+populate_nd_entry(const struct ether_addr *hw_addr, uint8_t ipv6[],
+                       uint8_t portid)
+{
+
+       /* need to lock here if multi-threaded */
+       /* rte_hash_add_key_data is not thread safe */
+       uint8_t i;
+       struct nd_key_ipv6 nd_key;
+       nd_key.port_id = portid;
+
+       for (i = 0; i < ND_IPV6_ADDR_SIZE; i++ /*i+=2 */)
+               nd_key.ipv6[i] = ipv6[i];
+
+       printf("\n");
+       nd_key.filler1 = 0;
+       nd_key.filler2 = 0;
+       nd_key.filler3 = 0;
+
+       lib_nd_populate_called++;
+
+       /*Validate if key-value pair already
+       * exists in the hash table for ND IPv6
+       */
+       struct nd_entry_data *new_nd_data = retrieve_nd_entry(nd_key);
+
+       if (new_nd_data && is_same_ether_addr(&new_nd_data->eth_addr,
+               hw_addr)) {
+
+               if (NDIPV6_DEBUG) {
+                       printf("nd_entry exists port %d ipv6 = ",
+                                                nd_key.port_id);
+                       for (i = 0; i < ND_IPV6_ADDR_SIZE; i += 2) {
+
+                               printf("%02X%02X ", nd_key.ipv6[i],
+                                                        nd_key.ipv6[i + 1]);
+                       }
+               }
+
+               lib_nd_duplicate_found++;
+               if (NDIPV6_DEBUG)
+                       printf("nd_entry exists\n");
+               return 0;
+       }
+
+       new_nd_data = (struct nd_entry_data *)
+                       malloc(sizeof(struct nd_entry_data));
+       if (new_nd_data == NULL) {
+               printf("populate_nd_entry: new_nd_data is NULL\n");
+               return 0;
+       }
+       new_nd_data->eth_addr = *hw_addr;
+       new_nd_data->status = COMPLETE;
+       new_nd_data->port = portid;
+
+       if (NDIPV6_DEBUG)
+               printf("populate_nd_entry ipv6=");
+
+       for (i = 0; i < ND_IPV6_ADDR_SIZE; i++ /*i+=2 */)
+               new_nd_data->ipv6[i] = ipv6[i];
+
+       if (NDIPV6_DEBUG) {
+               for (i = 0; i < ND_IPV6_ADDR_SIZE; i += 2) {
+
+                       printf("%02X%02X ", new_nd_data->ipv6[i],
+                                                new_nd_data->ipv6[i + 1]);
+               }
+       }
+
+       /*Add a key-data pair at hash table for ND IPv6 static routing */
+       rte_hash_add_key_data(nd_hash_handle, &nd_key, new_nd_data);
+
+       if (NDIPV6_DEBUG)
+               printf("\n....Added a key-data pair at rte hash table "
+               "for ND IPv6 static routing\n");
+
+       if (NDIPV6_DEBUG) {
+               /* print entire hash table */
+               printf("\tND: table update - hwaddr= "
+               "%02x:%02x:%02x:%02x:%02x:%02x on port=%d\n",
+               new_nd_data->eth_addr.addr_bytes[0],
+               new_nd_data->eth_addr.addr_bytes[1],
+               new_nd_data->eth_addr.addr_bytes[2],
+               new_nd_data->eth_addr.addr_bytes[3],
+               new_nd_data->eth_addr.addr_bytes[4],
+               new_nd_data->eth_addr.addr_bytes[5], portid);
+               printf("\tipv6=");
+               for (i = 0; i < ND_IPV6_ADDR_SIZE; i += 2) {
+                       new_nd_data->ipv6[i] = ipv6[i];
+                       printf("%02X%02X ", new_nd_data->ipv6[i],
+                                                new_nd_data->ipv6[i + 1]);
+               }
+
+               printf("\n");
+
+               puts("");
+       }
+       return 1;
+}
+
+void print_pkt1(struct rte_mbuf *pkt)
+{
+       uint8_t *rd = RTE_MBUF_METADATA_UINT8_PTR(pkt, 0);
+       int i = 0, j = 0;
+       printf("\nPacket Contents...\n");
+       for (i = 0; i < 20; i++) {
+               for (j = 0; j < 20; j++)
+                       printf("%02x ", rd[(20 * i) + j]);
+               printf("\n");
+       }
+}
+
+struct ether_addr broadcast_ether_addr = {
+       .addr_bytes[0] = 0xFF,
+       .addr_bytes[1] = 0xFF,
+       .addr_bytes[2] = 0xFF,
+       .addr_bytes[3] = 0xFF,
+       .addr_bytes[4] = 0xFF,
+       .addr_bytes[5] = 0xFF,
+};
+
+static const struct ether_addr null_ether_addr = {
+       .addr_bytes[0] = 0x00,
+       .addr_bytes[1] = 0x00,
+       .addr_bytes[2] = 0x00,
+       .addr_bytes[3] = 0x00,
+       .addr_bytes[4] = 0x00,
+       .addr_bytes[5] = 0x00,
+};
+
+#define MAX_NUM_MAC_ADDRESS 16
+struct ether_addr link_hw_addr[MAX_NUM_MAC_ADDRESS] = {
+{.addr_bytes = {0x90, 0xe2, 0xba, 0x54, 0x67, 0xc8} },
+{.addr_bytes = {0x90, 0xe2, 0xba, 0x54, 0x67, 0xc9} },
+{.addr_bytes = {0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11} },
+{.addr_bytes = {0x12, 0x13, 0x14, 0x15, 0x16, 0x17} },
+{.addr_bytes = {0x22, 0x33, 0x44, 0x55, 0x66, 0x77} },
+{.addr_bytes = {0x12, 0x13, 0x14, 0x15, 0x16, 0x17} },
+{.addr_bytes = {0x22, 0x33, 0x44, 0x55, 0x66, 0x77} },
+{.addr_bytes = {0x90, 0xe2, 0xba, 0x54, 0x67, 0xc9} },
+{.addr_bytes = {0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11} },
+{.addr_bytes = {0x12, 0x13, 0x14, 0x15, 0x16, 0x17} },
+{.addr_bytes = {0x22, 0x33, 0x44, 0x55, 0x66, 0x77} },
+{.addr_bytes = {0x12, 0x13, 0x14, 0x15, 0x16, 0x17} },
+{.addr_bytes = {0x22, 0x33, 0x44, 0x55, 0x66, 0x77} },
+{.addr_bytes = {0x12, 0x13, 0x14, 0x15, 0x16, 0x17} },
+{.addr_bytes = {0x22, 0x33, 0x44, 0x55, 0x66, 0x77} },
+{.addr_bytes = {0x18, 0x19, 0x1a, 0x1b, 0xcd, 0xef} }
+};
+
+struct ether_addr *get_link_hw_addr(uint8_t out_port)
+{
+       return &link_hw_addr[out_port];
+}
+
+static void
+request_icmp_echo(unsigned int port_id, uint32_t ip, struct ether_addr *gw_addr)
+{
+       struct ether_hdr *eth_h;
+       struct ipv4_hdr *ip_h;
+       struct icmp_hdr *icmp_h;
+
+       struct app_link_params *link;
+       link = &myApp->link_params[port_id];
+       arp_port_addresses[port_id].ip = link->ip;
+       arp_port_addresses[port_id].mac_addr = link->mac_addr;
+
+       struct rte_mbuf *icmp_pkt = lib_arp_pkt;
+       if (icmp_pkt == NULL) {
+               if (ARPICMP_DEBUG)
+                       printf("Error allocating icmp_pkt rte_mbuf\n");
+               return;
+       }
+
+       eth_h = rte_pktmbuf_mtod(icmp_pkt, struct ether_hdr *);
+       ether_addr_copy(gw_addr, &eth_h->d_addr);
+       ether_addr_copy((struct ether_addr *)
+                       &arp_port_addresses[port_id].mac_addr, &eth_h->s_addr);
+       eth_h->ether_type = CHECK_ENDIAN_16(ETHER_TYPE_IPv4);
+
+       ip_h = (struct ipv4_hdr *)((char *)eth_h + sizeof(struct ether_hdr));
+       icmp_h = (struct icmp_hdr *)((char *)ip_h + sizeof(struct ipv4_hdr));
+
+       ip_h->version_ihl = IP_VHL_DEF;
+       ip_h->type_of_service = 0;
+       ip_h->total_length =
+                       rte_cpu_to_be_16(sizeof(struct ipv4_hdr) + sizeof(struct icmp_hdr));
+       ip_h->packet_id = 0xaabb;
+       ip_h->fragment_offset = 0x0000;
+       ip_h->time_to_live = 64;
+       ip_h->next_proto_id = IPPROTO_ICMP;
+       ip_h->src_addr = rte_bswap32(arp_port_addresses[port_id].ip);
+       ip_h->dst_addr = ip;
+
+       ip_h->hdr_checksum = 0;
+       ip_h->hdr_checksum = rte_ipv4_cksum(ip_h);
+
+       icmp_h->icmp_type = IP_ICMP_ECHO_REQUEST;
+       icmp_h->icmp_code = 0;
+       icmp_h->icmp_ident = 0xdead;
+       icmp_h->icmp_seq_nb = 0xbeef;
+
+       icmp_h->icmp_cksum = ~rte_raw_cksum(icmp_h, sizeof(struct icmp_hdr));
+
+       icmp_pkt->pkt_len =
+                       sizeof(struct ether_hdr) + sizeof(struct ipv4_hdr) +
+                       sizeof(struct icmp_hdr);
+       icmp_pkt->data_len = icmp_pkt->pkt_len;
+
+       if (ARPICMP_DEBUG) {
+               printf("Sending echo request\n");
+               print_mbuf("TX", port_id, icmp_pkt, __LINE__);
+       }
+
+       rte_pipeline_port_out_packet_insert(gp_arp->p.p,
+               gp_arp->outport_id[port_id], icmp_pkt);
+       gp_arp->sentPktCount++;
+}
+
+void request_echo(unsigned int port_id, uint32_t ip)
+{
+       (void)port_id;
+       (void)ip;
+
+       struct ether_addr gw_addr;
+       uint32_t dest_ip = rte_bswap32(ip);
+       uint32_t phy_port;
+
+       if (get_dest_mac_addr_port(dest_ip, &phy_port, &gw_addr) == ARP_FOUND) {
+               request_icmp_echo(phy_port, ip, &gw_addr);
+               return;
+       }
+
+       if (ARPICMP_DEBUG)
+               printf("Sending echo request ... get mac failed.\n");
+}
+
+void request_arp(uint8_t port_id, uint32_t ip, struct rte_pipeline *rte_p)
+{
+       (void)port_id;
+       (void)ip;
+
+       struct ether_hdr *eth_h;
+       struct arp_hdr *arp_h;
+
+       struct app_link_params *link;
+       link = &myApp->link_params[port_id];
+       arp_port_addresses[port_id].ip = link->ip;
+       arp_port_addresses[port_id].mac_addr = link->mac_addr;
+
+       struct rte_mbuf *arp_pkt = lib_arp_pkt;
+
+       if (arp_pkt == NULL) {
+               if (ARPICMP_DEBUG)
+                       printf("Error allocating arp_pkt rte_mbuf\n");
+               return;
+       }
+
+       eth_h = rte_pktmbuf_mtod(arp_pkt, struct ether_hdr *);
+
+       ether_addr_copy(&broadcast_ether_addr, &eth_h->d_addr);
+       ether_addr_copy((struct ether_addr *)
+                       &arp_port_addresses[port_id].mac_addr, &eth_h->s_addr);
+       eth_h->ether_type = CHECK_ENDIAN_16(ETHER_TYPE_ARP);
+
+       arp_h = (struct arp_hdr *)((char *)eth_h + sizeof(struct ether_hdr));
+       arp_h->arp_hrd = CHECK_ENDIAN_16(ARP_HRD_ETHER);
+       arp_h->arp_pro = CHECK_ENDIAN_16(ETHER_TYPE_IPv4);
+       arp_h->arp_hln = ETHER_ADDR_LEN;
+       arp_h->arp_pln = sizeof(uint32_t);
+       arp_h->arp_op = CHECK_ENDIAN_16(ARP_OP_REQUEST);
+
+       ether_addr_copy((struct ether_addr *)
+                       &arp_port_addresses[port_id].mac_addr,
+                       &arp_h->arp_data.arp_sha);
+       arp_h->arp_data.arp_sip =
+                       rte_cpu_to_be_32(arp_port_addresses[port_id].ip);
+       ether_addr_copy(&null_ether_addr, &arp_h->arp_data.arp_tha);
+       arp_h->arp_data.arp_tip = rte_cpu_to_be_32(ip);
+       printf("arp tip:%x arp sip :%x\n", arp_h->arp_data.arp_tip,
+                                arp_h->arp_data.arp_sip);
+       /* mmcd changed length from 60 to 42 -
+       * real length of arp request, no padding on ethernet needed -
+       * looks now like linux arp
+       */
+
+       arp_pkt->pkt_len = 42;
+       arp_pkt->data_len = 42;
+
+       if (ARPICMP_DEBUG) {
+               printf("Sending arp request\n");
+               print_mbuf("TX", port_id, arp_pkt, __LINE__);
+       }
+
+       rte_pipeline_port_out_packet_insert(rte_p, port_id, arp_pkt);
+       gp_arp->sentPktCount++;
+
+}
+
+void request_arp_wrap(uint8_t port_id, uint32_t ip)
+{
+       request_arp(port_id, ip, gp_arp->p.p);
+}
+
+void process_arpicmp_pkt(
+       struct rte_mbuf *pkt,
+       uint32_t out_port,
+       uint32_t pkt_mask)
+{
+       uint8_t in_port_id = pkt->port;
+       struct app_link_params *link;
+       struct ether_hdr *eth_h;
+       struct arp_hdr *arp_h;
+       struct ipv4_hdr *ip_h;
+       struct icmp_hdr *icmp_h;
+       uint32_t cksum;
+       uint32_t ip_addr;
+       uint32_t req_tip;
+
+
+       eth_h = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+
+       if (eth_h->ether_type == rte_cpu_to_be_16(ETHER_TYPE_ARP)) {
+               arp_h =
+                               (struct arp_hdr *)((char *)eth_h +
+                                                        sizeof(struct ether_hdr));
+               if (CHECK_ENDIAN_16(arp_h->arp_hrd) != ARP_HRD_ETHER)
+                       printf
+                                       ("Invalid hardware format of hardware address - "
+                               "not processing ARP req\n");
+               else if (CHECK_ENDIAN_16(arp_h->arp_pro) != ETHER_TYPE_IPv4)
+                       printf
+                                       ("Invalid protocol address format - "
+                               "not processing ARP req\n");
+               else if (arp_h->arp_hln != 6)
+                       printf
+                                       ("Invalid hardware address length - "
+                               "not processing ARP req\n");
+               else if (arp_h->arp_pln != 4)
+                       printf
+                                       ("Invalid protocol address length - "
+                               "not processing ARP req\n");
+               else {
+                       link = &myApp->link_params[in_port_id];
+                       arp_port_addresses[in_port_id].ip = link->ip;
+                       arp_port_addresses[in_port_id].mac_addr =
+                                       link->mac_addr;
+
+                       if (arp_h->arp_data.arp_tip !=
+                                       rte_bswap32(arp_port_addresses[in_port_id].ip)) {
+                               printf
+                                               ("ARP requested IP address mismatches "
+                                       "interface IP - discarding\n");
+                               printf("arp_tip = %x\n",
+                                                        arp_h->arp_data.arp_tip);
+                               printf("arp_port_addresses = %x\n",
+                                                        arp_port_addresses[in_port_id].ip);
+                               printf("in_port_id = %x\n", in_port_id);
+                               printf("arp_port_addresses[0] = %x\n",
+                                                        arp_port_addresses[0].ip);
+
+                               rte_pipeline_ah_packet_drop(gp_arp->p.p,
+                                               pkt_mask);
+                               gp_arp->droppedPktCount++;
+
+                       }
+                       /* revise conditionals to allow processing of
+                       * requests with target ip = this ip and
+                       * processing of replies to destination ip = this ip
+                       */
+                       else if (arp_h->arp_op ==
+                                rte_cpu_to_be_16(ARP_OP_REQUEST)) {
+
+                               if (ARPICMP_DEBUG) {
+                               printf("arp_op %d, ARP_OP_REQUEST %d\n",
+                                                        arp_h->arp_op,
+                                                        rte_cpu_to_be_16(ARP_OP_REQUEST));
+                               print_mbuf("RX", in_port_id, pkt, __LINE__);
+                               }
+
+                               populate_arp_entry((struct ether_addr *)
+                                                        &arp_h->arp_data.arp_sha,
+                                                        rte_cpu_to_be_32
+                                                        (arp_h->arp_data.arp_sip),
+                                                        in_port_id);
+
+                               /* build reply */
+                               req_tip = arp_h->arp_data.arp_tip;
+                               ether_addr_copy(&eth_h->s_addr, &eth_h->d_addr);
+
+                               // set sender mac address -
+                               ether_addr_copy((struct ether_addr *)&
+                               arp_port_addresses[in_port_id].mac_addr,
+                               &eth_h->s_addr);
+
+                               arp_h->arp_op = rte_cpu_to_be_16(ARP_OP_REPLY);
+                               ether_addr_copy(&eth_h->s_addr,
+                                               &arp_h->arp_data.arp_sha);
+                               arp_h->arp_data.arp_tip =
+                                               arp_h->arp_data.arp_sip;
+                               arp_h->arp_data.arp_sip = req_tip;
+                               ether_addr_copy(&eth_h->d_addr,
+                                               &arp_h->arp_data.arp_tha);
+
+                               rte_pipeline_port_out_packet_insert(gp_arp->p.p,
+                                               out_port, pkt);
+                               gp_arp->sentPktCount++;
+
+                       } else if (arp_h->arp_op ==
+                                        rte_cpu_to_be_16(ARP_OP_REPLY)) {
+                               // TODO: be sure that ARP request
+                               //was actually sent!!!
+                               if (ARPICMP_DEBUG) {
+                                       printf("ARP_OP_REPLY received");
+                                       print_mbuf("RX", in_port_id, pkt,
+                                                        __LINE__);
+                               }
+                               populate_arp_entry((struct ether_addr *)
+                                                        &arp_h->arp_data.arp_sha,
+                                                        rte_bswap32(arp_h->
+                                                       arp_data.arp_sip),
+                                                        in_port_id);
+
+                               /* To drop the packet from LB */
+                               rte_pipeline_ah_packet_drop(gp_arp->p.p,
+                                               pkt_mask);
+                               gp_arp->droppedPktCount++;
+
+                       } else {
+                               if (ARPICMP_DEBUG)
+                                       printf("Invalid ARP opcode - not "
+                                       "processing ARP req %x\n",
+                                       arp_h->arp_op);
+                       }
+               }
+       } else {
+               ip_h =
+                               (struct ipv4_hdr *)((char *)eth_h +
+                                       sizeof(struct ether_hdr));
+               icmp_h =
+                               (struct icmp_hdr *)((char *)ip_h + sizeof(struct ipv4_hdr));
+
+               if (eth_h->ether_type == rte_cpu_to_be_16(ETHER_TYPE_IPv4)) {
+
+                       link = &myApp->link_params[in_port_id];
+                       arp_port_addresses[in_port_id].ip = link->ip;
+                       arp_port_addresses[in_port_id].mac_addr =
+                                       link->mac_addr;
+
+                       if (!is_same_ether_addr((struct ether_addr *)
+                                               &arp_port_addresses[in_port_id].
+                                               mac_addr, &eth_h->d_addr)) {
+
+                               if (ARPICMP_DEBUG)
+                                       printf("Ethernet frame not destined "
+                                       "for MAC address of received network "
+                                       "interface - discarding\n");
+
+                       } else if (ip_h->next_proto_id != IPPROTO_ICMP) {
+                               if (ARPICMP_DEBUG)
+                                       printf("IP protocol ID is not set to "
+                                       "ICMP - discarding\n");
+
+                       } else if ((ip_h->version_ihl & 0xf0) != IP_VERSION_4) {
+                               if (ARPICMP_DEBUG)
+                                       printf("IP version other than 4 - "
+                                       "discarding\n");
+
+                       } else if ((ip_h->version_ihl & 0x0f) != IP_HDRLEN) {
+                               if (ARPICMP_DEBUG)
+                                       printf("Unknown IHL - discarding\n");
+
+                       } else {
+                               if (icmp_h->icmp_type == IP_ICMP_ECHO_REQUEST
+                                               && icmp_h->icmp_code == 0) {
+                               if (ARPICMP_DEBUG)
+                                       print_mbuf("RX", in_port_id,
+                                                                pkt, __LINE__);
+
+                               ip_addr = ip_h->src_addr;
+                               ether_addr_copy(&eth_h->s_addr,
+                                               &eth_h->d_addr);
+                               ether_addr_copy((struct ether_addr *)
+                                               &arp_port_addresses
+                                               [in_port_id].mac_addr,
+                                               &eth_h->s_addr);
+
+                               if (ip_h->dst_addr !=
+                                       rte_bswap32(arp_port_addresses
+                                       [in_port_id].ip)) {
+                                       if (ARPICMP_DEBUG) {
+                                       printf("IPv4 packet not destined for "
+                                       "configured IP on RX port - "
+                                       "discarding\n");
+                                       printf("ip_h->dst_addr = %u, "
+                                       "in_port_id = %u, "
+                                       "arp_port_addresses.ip = %u\n",
+                                       ip_h->dst_addr, in_port_id,
+                                       arp_port_addresses[in_port_id].ip);
+                                       }
+                               } else {
+
+                                       if (is_multicast_ipv4_addr
+                                               (ip_h->dst_addr)) {
+                                               uint32_t ip_src;
+
+                                       ip_src = rte_be_to_cpu_32
+                                                                       (ip_addr);
+                                       if ((ip_src & 0x00000003) == 1)
+                                               ip_src = (ip_src &
+                                                               0xFFFFFFFC)
+                                                       | 0x00000002;
+                                       else
+                                               ip_src = (ip_src &
+                                                               0xFFFFFFFC)
+                                                       | 0x00000001;
+
+                                       ip_h->src_addr =
+                                                               rte_cpu_to_be_32(ip_src);
+                                       ip_h->dst_addr = ip_addr;
+
+                                       ip_h->hdr_checksum = 0;
+                                       ip_h->hdr_checksum = ~rte_raw_cksum(
+                                                       ip_h, sizeof(struct
+                                                       ipv4_hdr));
+                       } else {
+                               ip_h->src_addr = ip_h->dst_addr;
+                               ip_h->dst_addr = ip_addr;
+                               }
+
+                       icmp_h->icmp_type =
+                                               IP_ICMP_ECHO_REPLY;
+                       cksum = ~icmp_h->icmp_cksum & 0xffff;
+                       cksum += ~htons(IP_ICMP_ECHO_REQUEST << 8) & 0xffff;
+                       cksum += htons(IP_ICMP_ECHO_REPLY << 8);
+                       cksum = (cksum & 0xffff) + (cksum >> 16);
+                       cksum = (cksum & 0xffff) + (cksum >> 16);
+                       icmp_h->icmp_cksum = ~cksum;
+
+                       if (ARPICMP_DEBUG)
+                               print_mbuf("TX", in_port_id, pkt, __LINE__);
+
+                               rte_pipeline_port_out_packet_insert(gp_arp->p.p,
+                                               out_port, pkt);
+                               gp_arp->sentPktCount++;
+
+                       }
+                       }
+                       else if (icmp_h->icmp_type == IP_ICMP_ECHO_REPLY
+                               && icmp_h->icmp_code == 0) {
+                       if (ARPICMP_DEBUG)
+                               print_mbuf("RX", in_port_id,
+                                                        pkt, __LINE__);
+
+                       struct arp_key_ipv4 arp_key;
+                       arp_key.port_id = in_port_id;
+                       arp_key.ip =
+                       rte_bswap32(ip_h->src_addr);
+                       arp_key.filler1 = 0;
+                       arp_key.filler2 = 0;
+                       arp_key.filler3 = 0;
+
+                       struct arp_entry_data *arp_entry =
+                                               retrieve_arp_entry(arp_key);
+                       if (arp_entry == NULL) {
+                               printf("Received unsolicited "
+                               "ICMP echo reply from ip%x, "
+                                       "port %d\n",
+                                                arp_key.ip,
+                                                arp_key.port_id);
+                                       return;
+                       }
+
+                               arp_entry->status = COMPLETE;
+                               /* To drop the packet from LB */
+                               rte_pipeline_ah_packet_drop(gp_arp->p.p,
+                                               pkt_mask);
+                               gp_arp->droppedPktCount++;
+                       }
+                       }
+               }
+       }
+}
+
+
+
+/* int
+ * inet_pton(af, src, dst)
+ *      convert from presentation format (which usually means ASCII printable)
+ *      to network format (which is usually some kind of binary format).
+ * return:
+ *      1 if the address was valid for the specified address family
+ *      0 if the address wasn't valid (`dst' is untouched in this case)
+ *      -1 if some other error occurred (`dst' is untouched in this case, too)
+ * author:
+ *      Paul Vixie, 1996.
+ */
+static int my_inet_pton_ipv6(int af, const char *src, void *dst)
+{
+       switch (af) {
+       case AF_INET:
+               return inet_pton_ipv4(src, dst);
+       case AF_INET6:
+               return inet_pton_ipv6(src, dst);
+       default:
+               errno = EAFNOSUPPORT;
+               return -1;
+       }
+       /* NOTREACHED */
+}
+
+/* int
+ * inet_pton_ipv4(src, dst)
+ *      like inet_aton() but without all the hexadecimal and shorthand.
+ * return:
+ *      1 if `src' is a valid dotted quad, else 0.
+ * notice:
+ *      does not touch `dst' unless it's returning 1.
+ * author:
+ *      Paul Vixie, 1996.
+ */
+static int inet_pton_ipv4(const char *src, unsigned char *dst)
+{
+       static const char digits[] = "0123456789";
+       int saw_digit, octets, ch;
+       unsigned char tmp[INADDRSZ], *tp;
+
+       saw_digit = 0;
+       octets = 0;
+       *(tp = tmp) = 0;
+       while ((ch = *src++) != '\0') {
+               const char *pch;
+
+               pch = strchr(digits, ch);
+               if (pch != NULL) {
+                       unsigned int new = *tp * 10 + (pch - digits);
+
+                       if (new > 255)
+                               return 0;
+                       if (!saw_digit) {
+                               if (++octets > 4)
+                                       return 0;
+                               saw_digit = 1;
+                       }
+                       *tp = (unsigned char)new;
+               } else if (ch == '.' && saw_digit) {
+                       if (octets == 4)
+                               return 0;
+                       *++tp = 0;
+                       saw_digit = 0;
+               } else
+                       return 0;
+       }
+       if (octets < 4)
+               return 0;
+
+       memcpy(dst, tmp, INADDRSZ);
+       return 1;
+}
+
+/* int
+ * inet_pton_ipv6(src, dst)
+ *      convert presentation level address to network order binary form.
+ * return:
+ *      1 if `src' is a valid [RFC1884 2.2] address, else 0.
+ * notice:
+ *      (1) does not touch `dst' unless it's returning 1.
+ *      (2) :: in a full address is silently ignored.
+ * credit:
+ *      inspired by Mark Andrews.
+ * author:
+ *      Paul Vixie, 1996.
+ */
+static int inet_pton_ipv6(const char *src, unsigned char *dst)
+{
+       static const char xdigits_l[] = "0123456789abcdef",
+                       xdigits_u[] = "0123456789ABCDEF";
+       unsigned char tmp[IN6ADDRSZ], *tp = 0, *endp = 0, *colonp = 0;
+       const char *xdigits = 0, *curtok = 0;
+       int ch = 0, saw_xdigit = 0, count_xdigit = 0;
+       unsigned int val = 0;
+       unsigned int dbloct_count = 0;
+
+       memset((tp = tmp), '\0', IN6ADDRSZ);
+       endp = tp + IN6ADDRSZ;
+       colonp = NULL;
+       /* Leading :: requires some special handling. */
+       if (*src == ':')
+               if (*++src != ':')
+                       return 0;
+       curtok = src;
+       saw_xdigit = count_xdigit = 0;
+       val = 0;
+
+       while ((ch = *src++) != '\0') {
+               const char *pch;
+
+               pch = strchr((xdigits = xdigits_l), ch);
+               if (pch  == NULL)
+                       pch = strchr((xdigits = xdigits_u), ch);
+               if (pch != NULL) {
+                       if (count_xdigit >= 4)
+                               return 0;
+                       val <<= 4;
+                       val |= (pch - xdigits);
+                       if (val > 0xffff)
+                               return 0;
+                       saw_xdigit = 1;
+                       count_xdigit++;
+                       continue;
+               }
+               if (ch == ':') {
+                       curtok = src;
+                       if (!saw_xdigit) {
+                               if (colonp)
+                                       return 0;
+                               colonp = tp;
+                               continue;
+                       } else if (*src == '\0') {
+                               return 0;
+                       }
+                       if (tp + sizeof(int16_t) > endp)
+                               return 0;
+                       *tp++ = (unsigned char)((val >> 8) & 0xff);
+                       *tp++ = (unsigned char)(val & 0xff);
+                       saw_xdigit = 0;
+                       count_xdigit = 0;
+                       val = 0;
+                       dbloct_count++;
+                       continue;
+               }
+               if (ch == '.' && ((tp + INADDRSZ) <= endp) &&
+                               inet_pton_ipv4(curtok, tp) > 0) {
+                       tp += INADDRSZ;
+                       saw_xdigit = 0;
+                       dbloct_count += 2;
+                       break;  /* '\0' was seen by inet_pton4(). */
+               }
+               return 0;
+       }
+       if (saw_xdigit) {
+               if (tp + sizeof(int16_t) > endp)
+                       return 0;
+               *tp++ = (unsigned char)((val >> 8) & 0xff);
+               *tp++ = (unsigned char)(val & 0xff);
+               dbloct_count++;
+       }
+       if (colonp != NULL) {
+               /* if we already have 8 double octets,
+               * having a colon means error
+               */
+               if (dbloct_count == 8)
+                       return 0;
+
+               /*
+                * Since some memmove()'s erroneously fail to handle
+                * overlapping regions, we'll do the shift by hand.
+                */
+               const int n = tp - colonp;
+               int i;
+
+               for (i = 1; i <= n; i++) {
+                       endp[-i] = colonp[n - i];
+                       colonp[n - i] = 0;
+               }
+               tp = endp;
+       }
+       if (tp != endp)
+               return 0;
+       memcpy(dst, tmp, IN6ADDRSZ);
+       return 1;
+}
+
+/**
+ * Function to classify ICMPv6 Packets based on NextHeader field in IPv6 Header.
+ * Updates ND Cache table with link layer addresses as received from Neighbor.
+ * Processes ICMPv6 Echo destined to local port and replys.
+ *
+ * @param pkt
+ *   A pointer to the packet received from Loadbalancer pipeline
+ * @param out_port
+ *  A pointer to the output port action
+ * @param pkt_num
+ *  A packet number
+ *
+ * @return
+ *  NULL
+ */
+
+void
+process_icmpv6_pkt(
+       struct rte_mbuf *pkt,
+       uint32_t out_port,
+       __rte_unused uint32_t pkt_num)
+{
+
+       uint8_t in_port_id = pkt->port;
+       struct app_link_params *link;
+       struct ether_hdr *eth_h;
+       struct ipv6_hdr *ipv6_h;
+       struct icmpv6_hdr *icmpv6_h;
+       struct icmpv6_nd_hdr *icmpv6_nd_h;
+       uint8_t ipv6_addr[16];
+       uint8_t i = 0, flag = 1;
+       uint8_t req_tipv6[16];
+
+       eth_h = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+       ipv6_h = (struct ipv6_hdr *)((char *)eth_h + sizeof(struct ether_hdr));
+       icmpv6_h =
+                       (struct icmpv6_hdr *)((char *)ipv6_h + sizeof(struct ipv6_hdr));
+       struct rte_mbuf *icmpv6_pkt = pkt;
+
+       link = &myApp->link_params[in_port_id];
+       icmpv6_port_addresses[in_port_id].mac_addr = link->mac_addr;
+
+       if (!is_same_ether_addr
+                       ((struct ether_addr *)&icmpv6_port_addresses[in_port_id].mac_addr,
+                        &eth_h->d_addr)) {
+               if (ARPICMP_DEBUG) {
+                       printf("Ethernet frame not destined for MAC address "
+                       "of received network interface - discarding\n");
+               }
+       } else {
+               if ((icmpv6_h->icmpv6_type == ICMPV6_ECHO_REQUEST)
+                               && (icmpv6_h->icmpv6_code == 0)) {
+                       for (i = 0; i < 16; i++)
+                               ipv6_addr[i] = ipv6_h->src_addr[i];
+
+                       for (i = 0; i < 16; i++) {
+                               if (ipv6_h->dst_addr[i] !=
+                                               icmpv6_port_addresses[in_port_id].ipv6[i]) {
+                                       flag++;
+                               }
+                       }
+                       if (!flag) {
+                               printf("IPv6 packet not destined for "
+                               "configured IP on RX port - discarding\n");
+                       } else {
+                               {
+
+                                       ether_addr_copy(&eth_h->s_addr,
+                                                       &eth_h->d_addr);
+                                       ether_addr_copy((struct ether_addr *)
+                                                       &icmpv6_port_addresses
+                                                       [in_port_id].mac_addr,
+                                                       &eth_h->s_addr);
+
+                                       for (i = 0; i < 16; i++)
+                                               ipv6_h->src_addr[i] =
+                                                               ipv6_h->dst_addr[i];
+                                       for (i = 0; i < 16; i++)
+                                               ipv6_h->dst_addr[i] =
+                                                               ipv6_addr[i];
+
+                                       icmpv6_h->icmpv6_type =
+                                                       ICMPV6_ECHO_REPLY;
+
+                                       rte_pipeline_port_out_packet_insert
+                                                       (gp_arp->p.p, out_port, icmpv6_pkt);
+                                       gp_arp->sentPktCount++;
+                               }
+                       }
+
+               } else if ((icmpv6_h->icmpv6_type == ICMPV6_ECHO_REPLY)
+                                && (icmpv6_h->icmpv6_code == 0)) {
+                       struct nd_key_ipv6 nd_key;
+                       nd_key.port_id = in_port_id;
+
+                       for (i = 0; i < ND_IPV6_ADDR_SIZE; i++)
+                               nd_key.ipv6[i] = ipv6_h->src_addr[i];
+
+                       nd_key.filler1 = 0;
+                       nd_key.filler2 = 0;
+                       nd_key.filler3 = 0;
+
+                       /* Validate if key-value pair already
+                       * exists in the hash table for ND IPv6
+                       */
+                       struct nd_entry_data *new_nd_data =
+                                       retrieve_nd_entry(nd_key);
+
+                       if (new_nd_data == NULL) {
+                               printf("Received unsolicited ICMPv6 echo "
+                               "reply on port %d\n",
+                                                nd_key.port_id);
+                               for (i = 0; i < ND_IPV6_ADDR_SIZE; i += 2) {
+                                       printf("%02X%02X ", nd_key.ipv6[i],
+                                                                nd_key.ipv6[i + 1]);
+                               }
+                               return;
+                       }
+
+                       new_nd_data->status = COMPLETE;
+
+               } else
+               if ((icmpv6_h->icmpv6_type == ICMPV6_NEIGHBOR_SOLICITATION)
+                       && (icmpv6_h->icmpv6_code == 0)) {
+
+                       icmpv6_nd_h =
+                                       (struct icmpv6_nd_hdr *)((char *)icmpv6_h +
+                                                                sizeof(struct icmpv6_hdr));
+                       struct ether_addr *src_hw_addr = &eth_h->s_addr;
+                       uint8_t src_ipv6[16], dst_ipv6[16];
+
+                       for (i = 0; i < ND_IPV6_ADDR_SIZE; i++)
+                               src_ipv6[i] = ipv6_h->src_addr[i];
+                       for (i = 0; i < ND_IPV6_ADDR_SIZE; i++)
+                               dst_ipv6[i] = ipv6_h->dst_addr[i];
+
+                       // Check for Multicast Address
+                       if ((IPV6_MULTICAST
+                                        && ((dst_ipv6[0] << 8) | dst_ipv6[1]))) {
+                               if (populate_nd_entry
+                                               (src_hw_addr, src_ipv6, in_port_id)) {
+
+                                       //build a Neighbor Advertisement message
+                                       for (i = 0; i < ND_IPV6_ADDR_SIZE; i++)
+                                               req_tipv6[i] =
+                                                               icmpv6_nd_h->target_ipv6[i];
+
+                                       ether_addr_copy(&eth_h->s_addr,
+                                                       &eth_h->d_addr);
+                                       ether_addr_copy((struct ether_addr *)
+                                                       &icmpv6_port_addresses
+                                                       [in_port_id].mac_addr,
+                                                       &eth_h->s_addr);
+
+                                       // set sender mac address
+                                       ether_addr_copy(&eth_h->s_addr,
+                                                       &icmpv6_nd_h->
+                                                       link_layer_address);
+                                       for (i = 0; i < ND_IPV6_ADDR_SIZE; i++)
+                                               ipv6_h->dst_addr[i] =
+                                                               ipv6_h->src_addr[i];
+                                       for (i = 0; i < ND_IPV6_ADDR_SIZE; i++)
+                                               ipv6_h->src_addr[i] =
+                                                               req_tipv6[i];
+                                       icmpv6_h->icmpv6_type =
+                                                       ICMPV6_NEIGHBOR_ADVERTISEMENT;
+                                       icmpv6_nd_h->type =
+                                                       e_Target_Link_Layer_Address;
+                                       icmpv6_nd_h->icmpv6_reserved |=
+                                                       rte_cpu_to_be_32
+                                                       (NEIGHBOR_SOLICITATION_SET);
+
+                                       rte_pipeline_port_out_packet_insert
+                                                       (gp_arp->p.p, out_port, icmpv6_pkt);
+                                       gp_arp->sentPktCount++;
+                               }
+                       } else {
+                               if (ARPICMP_DEBUG) {
+                                       printf("Non-Multicasted Neighbor "
+                                       "Solicitation Message Received, "
+                                       "can't do Address Resolution\n");
+                                       printf("............Some one else "
+                                       "is the target host here !!!\n");
+                               }
+                       }
+
+               } else
+               if ((icmpv6_h->icmpv6_type == ICMPV6_NEIGHBOR_ADVERTISEMENT)
+                       && (icmpv6_h->icmpv6_code == 0)) {
+                       struct ether_addr *src_hw_addr = &eth_h->s_addr;
+                       uint8_t ipv6[16];
+                       for (i = 0; i < ND_IPV6_ADDR_SIZE; i++)
+                               ipv6[i] = ipv6_h->src_addr[i];
+
+                       if (populate_nd_entry(src_hw_addr, ipv6, in_port_id))
+                               if (ARPICMP_DEBUG)
+                                       printf("Now on, unicast IPv6 traffic "
+                                       "is possible\n");
+                       // Now on, unicast IPv6 traffic is possible
+               } else {
+                       if (ARPICMP_DEBUG) {
+                               printf("ICMPv6 Type %d Not Supported yet !!!\n",
+                                                        icmpv6_h->icmpv6_type);
+                       }
+               }
+
+       }
+
+}
+
+void request_icmpv6_echo(uint32_t port_id, uint8_t ipv6[])
+{
+       (void)port_id;
+       (void)ipv6;
+       int i;
+
+       struct ether_addr gw_addr;
+       uint8_t nhipv6[16];
+       uint8_t dest_ipv6[16];
+       uint32_t phy_port;
+
+       for (i = 0; i < ND_IPV6_ADDR_SIZE; i++)
+               dest_ipv6[i] = ipv6[i];
+
+       if (get_dest_mac_address_ipv6_port(dest_ipv6, &phy_port,
+                       &gw_addr, nhipv6)) {
+               request_icmpv6_echo_message(phy_port, ipv6, &gw_addr);
+               return;
+       }
+
+       if (ARPICMP_DEBUG)
+               printf("Sending icmpv6 echo request ... get mac failed.\n");
+}
+
+void
+request_icmpv6_echo_message(uint16_t port_id, uint8_t ipv6[],
+                                       struct ether_addr *gw_addr)
+{
+       struct ether_hdr *eth_h;
+       struct ipv6_hdr *ipv6_h;
+       struct icmpv6_hdr *icmpv6_h;
+       struct icmpv6_info_hdr *icmpv6_info_h;
+       int i;
+       struct app_link_params *link;
+       link = &mylink[port_id];
+
+       for (i = 0; i < 16; i++)
+               icmpv6_port_addresses[port_id].ipv6[i] = link->ipv6[i];
+
+       icmpv6_port_addresses[port_id].mac_addr = link->mac_addr;
+
+       struct rte_mbuf *icmpv6_pkt = lib_icmpv6_pkt;
+       if (icmpv6_pkt == NULL) {
+               if (ARPICMP_DEBUG)
+                       printf("Error allocating icmpv6_pkt rte_mbuf\n");
+               return;
+       }
+
+       eth_h = rte_pktmbuf_mtod(icmpv6_pkt, struct ether_hdr *);
+       ether_addr_copy(gw_addr, &eth_h->d_addr);
+       ether_addr_copy((struct ether_addr *)&icmpv6_port_addresses[port_id].
+                       mac_addr, &eth_h->s_addr);
+       eth_h->ether_type = CHECK_ENDIAN_16(ETHER_TYPE_IPv6);
+
+       ipv6_h = (struct ipv6_hdr *)((char *)eth_h + sizeof(struct ether_hdr));
+       icmpv6_h =
+                       (struct icmpv6_hdr *)((char *)ipv6_h + sizeof(struct ipv6_hdr));
+       icmpv6_info_h =
+                       (struct icmpv6_info_hdr *)((char *)icmpv6_h +
+                                                        sizeof(struct icmpv6_hdr));
+
+       ipv6_h->vtc_flow = 0x60000000;
+       ipv6_h->payload_len = 64;
+       ipv6_h->proto = 58;
+       ipv6_h->hop_limits = 64;
+
+       for (i = 0; i < 16; i++) {
+               ipv6_h->src_addr[i] = icmpv6_port_addresses[port_id].ipv6[i];
+               ipv6_h->dst_addr[i] = ipv6[i];
+       }
+
+       icmpv6_h->icmpv6_type = ICMPV6_ECHO_REQUEST;
+       icmpv6_h->icmpv6_code = 0;
+       icmpv6_info_h->icmpv6_ident = 0x5151;
+       icmpv6_info_h->icmpv6_seq_nb = 0x1;
+
+       icmpv6_h->icmpv6_cksum =
+                       ~rte_raw_cksum(icmpv6_h, sizeof(struct icmpv6_hdr));
+
+       icmpv6_pkt->pkt_len =
+                       sizeof(struct ether_hdr) + sizeof(struct ipv6_hdr) +
+                       sizeof(struct icmpv6_hdr);
+       icmpv6_pkt->data_len = icmpv6_pkt->pkt_len;
+
+       if (ARPICMP_DEBUG)
+               printf("Sending icmpv6 echo request\n");
+
+       rte_pipeline_port_out_packet_insert(gp_arp->p.p,
+               gp_arp->outport_id[port_id],
+               icmpv6_pkt);
+
+       gp_arp->sentPktCount++;
+}
+
+
+#endif
+
+static void *pipeline_arpicmp_msg_req_custom_handler(struct pipeline *p,
+                                                       void *msg);
+
+static pipeline_msg_req_handler handlers[] = {
+       [PIPELINE_MSG_REQ_PING] =
+               pipeline_msg_req_ping_handler,
+       [PIPELINE_MSG_REQ_STATS_PORT_IN] =
+               pipeline_msg_req_stats_port_in_handler,
+       [PIPELINE_MSG_REQ_STATS_PORT_OUT] =
+               pipeline_msg_req_stats_port_out_handler,
+       [PIPELINE_MSG_REQ_STATS_TABLE] =
+               pipeline_msg_req_stats_table_handler,
+       [PIPELINE_MSG_REQ_PORT_IN_ENABLE] =
+               pipeline_msg_req_port_in_enable_handler,
+       [PIPELINE_MSG_REQ_PORT_IN_DISABLE] =
+               pipeline_msg_req_port_in_disable_handler,
+       [PIPELINE_MSG_REQ_CUSTOM] =
+               pipeline_arpicmp_msg_req_custom_handler,
+
+};
+
+static void *pipeline_arpicmp_msg_req_entry_dbg_handler(struct pipeline *p,
+                                                                void *msg);
+static void *pipeline_arpicmp_msg_req_entry_dbg_handler(
+       __rte_unused struct pipeline *p,
+       __rte_unused void *msg)
+{
+       /*have to handle dbg commands*/
+       return NULL;
+}
+
+static __rte_unused pipeline_msg_req_handler custom_handlers[] = {
+       [PIPELINE_ARPICMP_MSG_REQ_ENTRY_DBG] =
+                       pipeline_arpicmp_msg_req_entry_dbg_handler,
+};
+
+/**
+ * Function for pipeline custom handlers
+ *
+ * @param pipeline
+ *  A void pointer to pipeline
+ * @param msg
+ *  void pointer for incoming data
+ *
+ * @return
+ *  void pointer of response
+ */
+void *pipeline_arpicmp_msg_req_custom_handler(struct pipeline *p, void *msg)
+{
+       struct pipeline_arpicmp *p_arp = (struct pipeline_arpicmp *)p;
+       struct pipeline_custom_msg_req *req = msg;
+       pipeline_msg_req_handler f_handle;
+
+       f_handle = (req->subtype < PIPELINE_ARPICMP_MSG_REQS) ?
+                       p_arp->custom_handlers[req->subtype] :
+                       pipeline_msg_req_invalid_handler;
+
+       if (f_handle == NULL)
+               f_handle = pipeline_msg_req_invalid_handler;
+
+       return f_handle(p, req);
+}
+
+#ifdef VNF_ACL
+
+/* Not needed as no arguments are needed for TxRX
+ * ARP arguments are handled in ARP module
+ */
+int
+pipeline_arpicmp_parse_args(struct pipeline_arpicmp *p,
+                        struct pipeline_params *params);
+int
+pipeline_arpicmp_parse_args(
+       __rte_unused struct pipeline_arpicmp *p,
+       struct pipeline_params *params)
+{
+
+       uint32_t i;
+       uint32_t arp_meta_offset_present = 0;
+
+       uint32_t arp_route_tbl_present = 0;
+       uint32_t nd_route_tbl_present = 0;
+       uint32_t ports_mac_list_present = 0;
+       uint32_t pktq_in_prv_present = 0;
+       uint32_t prv_to_pub_map_present = 0;
+
+       uint8_t n_prv_in_port = 0;
+       for (i = 0; i < PIPELINE_MAX_PORT_IN; i++) {
+               in_port_dir_a[i] = 0;   //make all RX ports ingress initially
+               prv_to_pub_map[i] = 0xff;
+               pub_to_prv_map[i] = 0xff;
+       }
+
+       for (i = 0; i < params->n_args; i++) {
+               char *arg_name = params->args_name[i];
+               char *arg_value = params->args_value[i];
+
+               if (ARPICMP_DEBUG > 2) {
+                       printf("ARP args[%d]: %s %d, %s\n", i, arg_name,
+                                       atoi(arg_value), arg_value);
+               }
+               if (strcmp(arg_name, "arp_meta_offset") == 0) {
+                       if (arp_meta_offset_present) {
+                               printf("arp_meta_offset "
+                               "initialized already\n");
+                               return -1;
+                       }
+                       arp_meta_offset_present = 1;
+                       arp_meta_offset = atoi(arg_value);
+                       continue;
+               }
+               /* pktq_in_prv */
+               if (strcmp(arg_name, "pktq_in_prv") == 0) {
+                       if (pktq_in_prv_present) {
+                               printf("Duplicate pktq_in_prv ... "
+                               "parse failed..\n\n");
+                               return -1;
+                       }
+                       pktq_in_prv_present = 1;
+
+                       int rxport = 0, j = 0;
+                       char phy_port_num[5];
+                       char *token = strtok(arg_value, "RXQ");
+                       while (token) {
+                               j = 0;
+                               while ((j < 4) && (token[j] != '.')) {
+                                       phy_port_num[j] = token[j];
+                                       j++;
+                               }
+                               phy_port_num[j] = '\0';
+                               rxport = atoi(phy_port_num);
+                               printf("token: %s, phy_port_str: %s, "
+                               "phy_port_num %d\n",
+                                                token, phy_port_num, rxport);
+
+                               prv_in_port_a[n_prv_in_port++] = rxport;
+                               // set rxport egress
+                                if(rxport < PIPELINE_MAX_PORT_IN)
+                               in_port_dir_a[rxport] = 1;
+                               token = strtok(NULL, "RXQ");
+                       }
+
+                       if (n_prv_in_port == 0) {
+                               printf
+                                               ("VNF common parse error - "
+                                       "no prv RX phy port\n");
+                               return -1;
+                       }
+                       continue;
+               }
+
+               /* prv_to_pub_map */
+               if (strcmp(arg_name, "prv_to_pub_map") == 0) {
+                       if (prv_to_pub_map_present) {
+                               printf
+                                               ("Duplicated prv_to_pub_map ... "
+                                       "parse failed ...\n");
+                               return -1;
+                       }
+                       prv_to_pub_map_present = 1;
+
+                       int rxport = 0, txport = 0, j = 0, k = 0;
+                       char rx_phy_port_num[5];
+                       char tx_phy_port_num[5];
+                       char *token = strtok(arg_value, "(");
+                       while (token) {
+                               j = 0;
+                               while ((j < 4) && (token[j] != ',')) {
+                                       rx_phy_port_num[j] = token[j];
+                                       j++;
+                               }
+                               rx_phy_port_num[j] = '\0';
+                               rxport = atoi(rx_phy_port_num);
+
+                               j++;
+                               k = 0;
+                               while ((k < 4) && (token[j + k] != ')')) {
+                                       tx_phy_port_num[k] = token[j + k];
+                                       k++;
+                               }
+                               tx_phy_port_num[k] = '\0';
+                               txport = atoi(tx_phy_port_num);
+                               if (rxport < PIPELINE_MAX_PORT_IN && txport < PIPELINE_MAX_PORT_IN){
+                               printf("token: %s,"
+                                                        "rx_phy_port_str: %s, phy_port_num %d,"
+                                                        "tx_phy_port_str: %s, tx_phy_port_num %d\n",
+                                                        token, rx_phy_port_num, rxport,
+                                                        tx_phy_port_num, txport);
+                               }
+                               else
+                                       return -1;
+                               if ((rxport >= PIPELINE_MAX_PORT_IN) ||
+                                               (txport >= PIPELINE_MAX_PORT_IN) ||
+                                               (in_port_dir_a[rxport] != 1)) {
+                                       printf("CG-NAPT parse error - "
+                                       "incorrect prv-pub translation. "
+                                       "Rx %d, Tx %d, Rx Dir %d\n",
+                                       rxport, txport, in_port_dir_a[rxport]);
+                                       return -1;
+                               }
+
+                               prv_to_pub_map[rxport] = txport;
+                               pub_to_prv_map[txport] = rxport;
+                               token = strtok(NULL, "(");
+                       }
+
+                       continue;
+               }
+
+               /* lib_arp_debug */
+               if (strcmp(arg_name, "lib_arp_debug") == 0) {
+                       ARPICMP_DEBUG = atoi(arg_value);
+
+                       continue;
+               }
+
+               /* ports_mac_list */
+               if (strcmp(arg_name, "ports_mac_list") == 0) {
+                       ports_mac_list_present = 1;
+
+                       uint32_t i = 0, j = 0, k = 0, MAC_NUM_BYTES = 6;
+
+                       char byteStr[MAC_NUM_BYTES][3];
+                       uint32_t byte[MAC_NUM_BYTES];
+
+                       char *token = strtok(arg_value, " ");
+                       while (token) {
+                               k = 0;
+                               for (i = 0; i < MAC_NUM_BYTES; i++) {
+                                       for (j = 0; j < 2; j++)
+                                               byteStr[i][j] = token[k++];
+                                       byteStr[i][j] = '\0';
+                                       k++;
+                               }
+
+                               for (i = 0; i < MAC_NUM_BYTES; i++)
+                                       byte[i] = strtoul(byteStr[i], NULL, 16);
+
+                               if (ARPICMP_DEBUG) {
+                                       printf("token: %s", token);
+                                       for (i = 0; i < MAC_NUM_BYTES; i++)
+                                               printf(", byte[%u] %u", i,
+                                                                        byte[i]);
+                                       printf("\n");
+                               }
+                               //Populate the static arp_route_table
+                               for (i = 0; i < MAC_NUM_BYTES; i++)
+                                       link_hw_addr
+                                                       [link_hw_addr_array_idx].addr_bytes
+                                                       [i] = byte[i];
+
+                               link_hw_addr_array_idx++;
+                               token = strtok(NULL, " ");
+                       }
+
+                       continue;
+               }
+
+               /* arp_route_tbl */
+               if (strcmp(arg_name, "arp_route_tbl") == 0) {
+                       arp_route_tbl_present = 1;
+
+                       uint32_t dest_ip = 0, mask = 0, tx_port = 0, nh_ip =
+                                       0, i = 0, j = 0, k = 0, l = 0;
+                       uint32_t arp_route_tbl_str_max_len = 10;
+                       char dest_ip_str[arp_route_tbl_str_max_len];
+                       char mask_str[arp_route_tbl_str_max_len];
+                       char tx_port_str[arp_route_tbl_str_max_len];
+                       char nh_ip_str[arp_route_tbl_str_max_len];
+                       char *token = strtok(arg_value, "(");
+                       while (token) {
+                               i = 0;
+                               while ((i < (arp_route_tbl_str_max_len - 1))
+                                                        && (token[i] != ',')) {
+                                       dest_ip_str[i] = token[i];
+                                       i++;
+                               }
+                               dest_ip_str[i] = '\0';
+                               dest_ip = strtoul(dest_ip_str, NULL, 16);
+
+                               i++;
+                               j = 0;
+                               while ((j < (arp_route_tbl_str_max_len - 1))
+                                                        && (token[i + j] != ',')) {
+                                       mask_str[j] = token[i + j];
+                                       j++;
+                               }
+                               mask_str[j] = '\0';
+                               mask = strtoul(mask_str, NULL, 16);
+
+                               j++;
+                               k = 0;
+                               while ((k < (arp_route_tbl_str_max_len - 1))
+                                                        && (token[i + j + k] != ',')) {
+                                       tx_port_str[k] = token[i + j + k];
+                                       k++;
+                               }
+                               tx_port_str[k] = '\0';
+                               //atoi(tx_port_str);
+                               tx_port = strtoul(tx_port_str, NULL, 16);
+
+                               k++;
+                               l = 0;
+                               while ((l < (arp_route_tbl_str_max_len - 1))
+                                                        && (token[i + j + k + l] != ')')) {
+                                       nh_ip_str[l] = token[i + j + k + l];
+                                       l++;
+                               }
+                               nh_ip_str[l] = '\0';
+                               //atoi(nh_ip_str);
+                               nh_ip = strtoul(nh_ip_str, NULL, 16);
+
+                               if (ARPICMP_DEBUG) {
+                                       printf("token: %s, "
+                                                                "dest_ip_str: %s, dest_ip %u, "
+                                                                "mask_str: %s, mask %u, "
+                                                                "tx_port_str: %s, tx_port %u, "
+                                                                "nh_ip_str: %s, nh_ip %u\n",
+                                                                token, dest_ip_str, dest_ip,
+                                                                mask_str, mask, tx_port_str,
+                                                                tx_port, nh_ip_str, nh_ip);
+                               }
+                               #if 0
+                               if (tx_port >= params->n_ports_out) {
+                                       printf("ARP-ICMP parse error - "
+                                       "incorrect tx_port %d, max %d\n",
+                                       tx_port, params->n_ports_out);
+                                       return -1;
+                               }
+                               #endif
+
+                               //Populate the static arp_route_table
+                               lib_arp_route_table[arp_route_tbl_index].ip =
+                                               dest_ip;
+                               lib_arp_route_table[arp_route_tbl_index].mask =
+                                               mask;
+                               lib_arp_route_table[arp_route_tbl_index].port =
+                                               tx_port;
+                               lib_arp_route_table[arp_route_tbl_index].nh =
+                                               nh_ip;
+                               arp_route_tbl_index++;
+                               token = strtok(NULL, "(");
+                       }
+
+                       continue;
+               }
+               /*ND IPv6 */
+               /* nd_route_tbl */
+               if (strcmp(arg_name, "nd_route_tbl") == 0) {
+                       nd_route_tbl_present = 1;
+
+                       uint8_t dest_ipv6[16], depth = 0, tx_port =
+                                       0, nh_ipv6[16], i = 0, j = 0, k = 0, l = 0;
+                       uint8_t nd_route_tbl_str_max_len = 128; //64;
+                       char dest_ipv6_str[nd_route_tbl_str_max_len];
+                       char depth_str[nd_route_tbl_str_max_len];
+                       char tx_port_str[nd_route_tbl_str_max_len];
+                       char nh_ipv6_str[nd_route_tbl_str_max_len];
+                       char *token = strtok(arg_value, "(");
+                       while (token) {
+                               i = 0;
+                               while ((i < (nd_route_tbl_str_max_len - 1))
+                                                        && (token[i] != ',')) {
+                                       dest_ipv6_str[i] = token[i];
+                                       i++;
+                               }
+                               dest_ipv6_str[i] = '\0';
+                               my_inet_pton_ipv6(AF_INET6, dest_ipv6_str,
+                                                       &dest_ipv6);
+
+                               i++;
+                               j = 0;
+                               while ((j < (nd_route_tbl_str_max_len - 1))
+                                                        && (token[i + j] != ',')) {
+                                       depth_str[j] = token[i + j];
+                                       j++;
+                               }
+                               depth_str[j] = '\0';
+                               //converting string char to integer
+                               int s;
+                               for (s = 0; depth_str[s] != '\0'; ++s)
+                                       depth = depth * 10 + depth_str[s] - '0';
+
+                               j++;
+                               k = 0;
+                               while ((k < (nd_route_tbl_str_max_len - 1))
+                                                        && (token[i + j + k] != ',')) {
+                                       tx_port_str[k] = token[i + j + k];
+                                       k++;
+                               }
+                               tx_port_str[k] = '\0';
+                               //atoi(tx_port_str);
+                               tx_port = strtoul(tx_port_str, NULL, 16);
+
+                               k++;
+                               l = 0;
+                               while ((l < (nd_route_tbl_str_max_len - 1))
+                                                        && (token[i + j + k + l] != ')')) {
+                                       nh_ipv6_str[l] = token[i + j + k + l];
+                                       l++;
+                               }
+                               nh_ipv6_str[l] = '\0';
+                               my_inet_pton_ipv6(AF_INET6, nh_ipv6_str,
+                                                       &nh_ipv6);
+
+                               //Populate the static arp_route_table
+                               for (i = 0; i < 16; i++) {
+                                       lib_nd_route_table
+                                                       [nd_route_tbl_index].ipv6[i] =
+                                                       dest_ipv6[i];
+                                       lib_nd_route_table
+                                                       [nd_route_tbl_index].nhipv6[i] =
+                                                       nh_ipv6[i];
+                               }
+                               lib_nd_route_table[nd_route_tbl_index].depth =
+                                               depth;
+                               lib_nd_route_table[nd_route_tbl_index].port =
+                                               tx_port;
+
+                               nd_route_tbl_index++;
+                               token = strtok(NULL, "(");
+                       } //while
+
+                       continue;
+               }
+               /* any other */
+
+       }
+
+       #if 0
+       if (!arp_meta_offset_present) {
+               printf("ARPICMP: arp_meta_offset not initialized\n");
+               return -1;
+       }
+       #endif
+
+       if (!arp_route_tbl_present && !nd_route_tbl_present) {
+               printf("Neither arp_route_tbl_present nor "
+                       "nd_route_tbl_present declared\n");
+               return -1;
+       }
+
+       if (!pktq_in_prv_present) {
+               printf("pktq_in_prv not declared\n");
+               return -1;
+       }
+
+       if (!ports_mac_list_present) {
+               printf("ports_mac_list not declared\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+#endif
+
+uint32_t arpicmp_pkt_print_count;
+static inline void
+pkt_key_arpicmp(struct rte_mbuf *pkt, uint32_t pkt_num, void *arg)
+{
+
+       struct pipeline_arpicmp_in_port_h_arg *ap = arg;
+       struct pipeline_arpicmp *p_arp = (struct pipeline_arpicmp *)ap->p;
+
+       p_arp->receivedPktCount++;
+
+       uint8_t in_port_id = pkt->port;
+       #ifdef VNF_ACL
+       struct app_link_params *link;
+       #endif
+       uint8_t *protocol;
+       uint32_t pkt_mask = 1 << pkt_num;
+       uint32_t eth_proto_offset = MBUF_HDR_ROOM + 12;
+
+       uint32_t prot_offset =
+                       MBUF_HDR_ROOM + ETH_HDR_SIZE + IP_HDR_PROTOCOL_OFST;
+
+       #ifdef VNF_ACL
+       uint32_t out_port;
+       #endif
+
+       uint16_t *eth_proto =
+               RTE_MBUF_METADATA_UINT16_PTR(pkt, eth_proto_offset);
+
+       /* header room + eth hdr size + src_aadr offset in ip header */
+       #ifdef VNF_ACL
+       uint32_t dst_addr_offset =
+               MBUF_HDR_ROOM + ETH_HDR_SIZE + IP_HDR_DST_ADR_OFST;
+       uint32_t *dst_addr = RTE_MBUF_METADATA_UINT32_PTR(pkt, dst_addr_offset);
+       #endif
+
+       #ifdef IPV6
+        uint32_t prot_offset_ipv6 =
+                        MBUF_HDR_ROOM + ETH_HDR_SIZE + IPV6_HDR_PROTOCOL_OFST;
+
+       if (rte_be_to_cpu_16(*eth_proto) == ETHER_TYPE_IPv6)
+               protocol = RTE_MBUF_METADATA_UINT8_PTR(pkt, prot_offset_ipv6);
+       else
+               protocol = RTE_MBUF_METADATA_UINT8_PTR(pkt, prot_offset);
+       #else
+       protocol = RTE_MBUF_METADATA_UINT8_PTR(pkt, prot_offset);
+       #endif
+
+
+       if ((ARPICMP_DEBUG > 2) && (arpicmp_pkt_print_count < 10)) {
+               print_pkt1(pkt);
+               arpicmp_pkt_print_count++;
+               printf("\nEth Typ %x, Prot %x, ETH_TYPE_ARP %x, "
+                       "ETH_TYPE_IPV4 %x, IP_PROTOCOL_ICMP %x\n",
+                                rte_be_to_cpu_16(*eth_proto), *protocol, ETH_TYPE_ARP,
+                                ETH_TYPE_IPV4, IP_PROTOCOL_ICMP);
+       }
+
+       #ifdef VNF_ACL
+       link = &myApp->link_params[in_port_id];
+       #endif
+
+       /* Classifier for ICMP pass-through*/
+       if ((rte_be_to_cpu_16(*eth_proto) == ETH_TYPE_ARP) ||
+                       ((rte_be_to_cpu_16(*eth_proto) == ETH_TYPE_IPV4)
+                        && (*protocol == IP_PROTOCOL_ICMP)
+               #ifdef VNF_ACL
+               && (link->ip == rte_be_to_cpu_32(*dst_addr))
+               #endif
+               )) {
+
+               #ifdef VNF_ACL
+               out_port = p_arp->outport_id[in_port_id];
+               process_arpicmp_pkt(pkt, out_port, pkt_mask);
+               #else
+               process_arpicmp_pkt(pkt, ifm_get_port(in_port_id));
+               #endif
+               return;
+       }
+       #ifdef IPV6
+       else if ((rte_be_to_cpu_16(*eth_proto) == ETH_TYPE_IPV6)
+               && (*protocol == ICMPV6_PROTOCOL_ID)) {
+               #ifdef VNF_ACL
+               out_port = p_arp->outport_id[in_port_id];
+               process_icmpv6_pkt(pkt, out_port, pkt_mask);
+               #else
+               process_icmpv6_pkt(pkt, ifm_get_port(in_port_id));
+               #endif
+
+               return;
+       }
+       #endif
+
+       /* Drop the pkt if not ARP/ICMP */
+       rte_pipeline_ah_packet_drop(p_arp->p.p, pkt_mask);
+       p_arp->droppedPktCount++;
+
+}
+
+static inline void
+pkt4_key_arpicmp(struct rte_mbuf **pkt, uint32_t pkt_num, void *arg)
+{
+
+       struct pipeline_arpicmp_in_port_h_arg *ap = arg;
+       struct pipeline_arpicmp *p_arp = (struct pipeline_arpicmp *)ap->p;
+
+       p_arp->receivedPktCount += 4;
+
+       uint32_t eth_proto_offset = MBUF_HDR_ROOM + 12;
+       uint8_t in_port_id = pkt[0]->port;
+
+       uint32_t prot_offset =
+                       MBUF_HDR_ROOM + ETH_HDR_SIZE + IP_HDR_PROTOCOL_OFST;
+
+       /* header room + eth hdr size + src_aadr offset in ip header */
+       #ifdef VNF_ACL
+       uint32_t dst_addr_offset =
+               MBUF_HDR_ROOM + ETH_HDR_SIZE + IP_HDR_DST_ADR_OFST;
+       #endif
+
+       uint32_t pkt_mask0 = 1 << pkt_num;
+       uint32_t pkt_mask1 = 1 << (pkt_num + 1);
+       uint32_t pkt_mask2 = 1 << (pkt_num + 2);
+       uint32_t pkt_mask3 = 1 << (pkt_num + 3);
+
+       #ifdef VNF_ACL
+       uint32_t out_port0;
+       uint32_t out_port1;
+       uint32_t out_port2;
+       uint32_t out_port3;
+       #endif
+
+       uint16_t *eth_proto0 =
+               RTE_MBUF_METADATA_UINT16_PTR(pkt[0], eth_proto_offset);
+       uint16_t *eth_proto1 =
+               RTE_MBUF_METADATA_UINT16_PTR(pkt[1], eth_proto_offset);
+       uint16_t *eth_proto2 =
+               RTE_MBUF_METADATA_UINT16_PTR(pkt[2], eth_proto_offset);
+       uint16_t *eth_proto3 =
+               RTE_MBUF_METADATA_UINT16_PTR(pkt[3], eth_proto_offset);
+
+       uint8_t *protocol0;
+       uint8_t *protocol1;
+       uint8_t *protocol2;
+       uint8_t *protocol3;
+
+       #ifdef VNF_ACL
+       uint32_t *dst_addr0 =
+                       RTE_MBUF_METADATA_UINT32_PTR(pkt[0], dst_addr_offset);
+       uint32_t *dst_addr1 =
+                       RTE_MBUF_METADATA_UINT32_PTR(pkt[1], dst_addr_offset);
+       uint32_t *dst_addr2 =
+                       RTE_MBUF_METADATA_UINT32_PTR(pkt[2], dst_addr_offset);
+       uint32_t *dst_addr3 =
+                       RTE_MBUF_METADATA_UINT32_PTR(pkt[3], dst_addr_offset);
+
+       struct app_link_params *link0;
+       struct app_link_params *link1;
+       struct app_link_params *link2;
+       struct app_link_params *link3;
+
+       link0 = &myApp->link_params[pkt[0]->port];
+       link1 = &myApp->link_params[pkt[1]->port];
+       link2 = &myApp->link_params[pkt[2]->port];
+       link3 = &myApp->link_params[pkt[3]->port];
+       #endif
+
+       #ifdef IPV6
+       uint32_t prot_offset_ipv6 =
+                       MBUF_HDR_ROOM + ETH_HDR_SIZE + IPV6_HDR_PROTOCOL_OFST;
+
+       #endif
+
+       #ifdef IPV6
+/* --0-- */
+       if (rte_be_to_cpu_16(*eth_proto0) == ETHER_TYPE_IPv6)
+               protocol0 =
+                               RTE_MBUF_METADATA_UINT8_PTR(pkt[0], prot_offset_ipv6);
+       else
+               protocol0 = RTE_MBUF_METADATA_UINT8_PTR(pkt[0], prot_offset);
+
+/* --1-- */
+       if (rte_be_to_cpu_16(*eth_proto1) == ETHER_TYPE_IPv6)
+               protocol1 =
+                               RTE_MBUF_METADATA_UINT8_PTR(pkt[1], prot_offset_ipv6);
+       else
+               protocol1 = RTE_MBUF_METADATA_UINT8_PTR(pkt[1], prot_offset);
+
+/* --2-- */
+       if (rte_be_to_cpu_16(*eth_proto2) == ETHER_TYPE_IPv6)
+               protocol2 =
+                               RTE_MBUF_METADATA_UINT8_PTR(pkt[2], prot_offset_ipv6);
+       else
+               protocol2 = RTE_MBUF_METADATA_UINT8_PTR(pkt[2], prot_offset);
+
+/* --3-- */
+       if (rte_be_to_cpu_16(*eth_proto3) == ETHER_TYPE_IPv6)
+               protocol3 =
+                               RTE_MBUF_METADATA_UINT8_PTR(pkt[3], prot_offset_ipv6);
+       else
+               protocol3 = RTE_MBUF_METADATA_UINT8_PTR(pkt[3], prot_offset);
+       #else
+       protocol0 = RTE_MBUF_METADATA_UINT8_PTR(pkt[0], prot_offset);
+       protocol1 = RTE_MBUF_METADATA_UINT8_PTR(pkt[1], prot_offset);
+       protocol2 = RTE_MBUF_METADATA_UINT8_PTR(pkt[2], prot_offset);
+       protocol3 = RTE_MBUF_METADATA_UINT8_PTR(pkt[3], prot_offset);
+       #endif
+
+       if ((ARPICMP_DEBUG > 2) && (arpicmp_pkt_print_count < 10)) {
+               print_pkt1(pkt[0]);
+               arpicmp_pkt_print_count++;
+               printf("\nEth Typ %x, Prot %x, ETH_TYPE_ARP %x, "
+                       "ETH_TYPE_IPV4 %x, IP_PROTOCOL_ICMP %x\n",
+                                rte_be_to_cpu_16(*eth_proto0), *protocol0, ETH_TYPE_ARP,
+                                ETH_TYPE_IPV4, IP_PROTOCOL_ICMP);
+       }
+
+
+       if ((rte_be_to_cpu_16(*eth_proto0) == ETH_TYPE_ARP) ||
+                       ((rte_be_to_cpu_16(*eth_proto0) == ETH_TYPE_IPV4)
+                        && (*protocol0 == IP_PROTOCOL_ICMP)
+               #ifdef VNF_ACL
+                               && (link0->ip == rte_be_to_cpu_32(*dst_addr0))
+               #endif
+               )) {
+
+               #ifdef VNF_ACL
+               out_port0 = p_arp->outport_id[pkt[0]->port];
+               process_arpicmp_pkt(pkt[0], out_port0, pkt_mask0);
+               #else
+               process_arpicmp_pkt(pkt[0], ifm_get_port(in_port_id));
+               #endif
+
+               goto PKT1;
+       }
+       #ifdef IPV6
+       else if ((rte_be_to_cpu_16(*eth_proto0) == ETH_TYPE_IPV6)
+                        && (*protocol0 == ICMPV6_PROTOCOL_ID)) {
+
+               #ifdef VNF_ACL
+               out_port0 = p_arp->outport_id[pkt[0]->port];
+               process_icmpv6_pkt(pkt[0], out_port0, pkt_mask0);
+               #else
+               process_icmpv6_pkt(pkt[0], ifm_get_port(in_port_id));
+               #endif
+
+               goto PKT1;
+       }
+       #endif
+
+       /* Drop the pkt if not ARP/ICMP */
+       rte_pipeline_ah_packet_drop(p_arp->p.p, pkt_mask0);
+       p_arp->droppedPktCount++;
+
+PKT1:
+       if ((ARPICMP_DEBUG > 2) && (arpicmp_pkt_print_count < 10)) {
+               print_pkt1(pkt[1]);
+               arpicmp_pkt_print_count++;
+               printf("\nEth Typ %x, Prot %x, ETH_TYPE_ARP %x, "
+                       "ETH_TYPE_IPV4 %x, IP_PROTOCOL_ICMP %x\n",
+                                rte_be_to_cpu_16(*eth_proto1), *protocol1, ETH_TYPE_ARP,
+                                ETH_TYPE_IPV4, IP_PROTOCOL_ICMP);
+       }
+
+       if ((rte_be_to_cpu_16(*eth_proto1) == ETH_TYPE_ARP) ||
+                       ((rte_be_to_cpu_16(*eth_proto1) == ETH_TYPE_IPV4)
+                        && (*protocol1 == IP_PROTOCOL_ICMP)
+               #ifdef VNF_ACL
+                               && (link1->ip == rte_be_to_cpu_32(*dst_addr1))
+               #endif
+               )) {
+
+               #ifdef VNF_ACL
+               out_port1 = p_arp->outport_id[pkt[1]->port];
+               process_arpicmp_pkt(pkt[1], out_port1, pkt_mask1);
+               #else
+               process_arpicmp_pkt(pkt[1], ifm_get_port(in_port_id));
+               #endif
+               goto PKT2;
+       }
+       #ifdef IPV6
+       else if ((rte_be_to_cpu_16(*eth_proto1) == ETH_TYPE_IPV6)
+               && (*protocol1 == ICMPV6_PROTOCOL_ID)) {
+
+               #ifdef VNF_ACL
+               out_port1 = p_arp->outport_id[pkt[1]->port];
+               process_icmpv6_pkt(pkt[1], out_port1, pkt_mask1);
+               #else
+               process_icmpv6_pkt(pkt[1], ifm_get_port(in_port_id));
+               #endif
+
+               goto PKT2;
+       }
+       #endif
+
+       /* Drop the pkt if not ARP/ICMP */
+       rte_pipeline_ah_packet_drop(p_arp->p.p, pkt_mask1);
+       p_arp->droppedPktCount++;
+
+PKT2:
+       if ((ARPICMP_DEBUG > 2) && (arpicmp_pkt_print_count < 10)) {
+               print_pkt1(pkt[2]);
+               arpicmp_pkt_print_count++;
+               printf("\nEth Typ %x, Prot %x, ETH_TYPE_ARP %x, "
+                       "ETH_TYPE_IPV4 %x, IP_PROTOCOL_ICMP %x\n",
+                                rte_be_to_cpu_16(*eth_proto2), *protocol2, ETH_TYPE_ARP,
+                                ETH_TYPE_IPV4, IP_PROTOCOL_ICMP);
+       }
+
+       if ((rte_be_to_cpu_16(*eth_proto2) == ETH_TYPE_ARP) ||
+                       ((rte_be_to_cpu_16(*eth_proto2) == ETH_TYPE_IPV4)
+                        && (*protocol2 == IP_PROTOCOL_ICMP)
+               #ifdef VNF_ACL
+                               && (link2->ip == rte_be_to_cpu_32(*dst_addr2))
+               #endif
+               )) {
+
+               #ifdef VNF_ACL
+               out_port2 = p_arp->outport_id[pkt[2]->port];
+               process_arpicmp_pkt(pkt[2], out_port2, pkt_mask2);
+               #else
+               process_arpicmp_pkt(pkt[2], ifm_get_port(in_port_id));
+               #endif
+
+               goto PKT3;
+       }
+       #ifdef IPV6
+       else if ((rte_be_to_cpu_16(*eth_proto2) == ETH_TYPE_IPV6)
+               && (*protocol2 == ICMPV6_PROTOCOL_ID)) {
+
+               #ifdef VNF_ACL
+               out_port2 = p_arp->outport_id[pkt[2]->port];
+               process_icmpv6_pkt(pkt[2], out_port2, pkt_mask2);
+               #else
+               process_icmpv6_pkt(pkt[2], ifm_get_port(in_port_id));
+               #endif
+
+               goto PKT3;
+       }
+       #endif
+
+       /* Drop the pkt if not ARP/ICMP */
+       rte_pipeline_ah_packet_drop(p_arp->p.p, pkt_mask2);
+       p_arp->droppedPktCount++;
+
+PKT3:
+       if ((ARPICMP_DEBUG > 2) && (arpicmp_pkt_print_count < 10)) {
+               print_pkt1(pkt[3]);
+               arpicmp_pkt_print_count++;
+               printf("\nEth Typ %x, Prot %x, ETH_TYPE_ARP %x, "
+                       "ETH_TYPE_IPV4 %x, IP_PROTOCOL_ICMP %x\n",
+                                rte_be_to_cpu_16(*eth_proto3), *protocol3, ETH_TYPE_ARP,
+                                ETH_TYPE_IPV4, IP_PROTOCOL_ICMP);
+       }
+
+       if ((rte_be_to_cpu_16(*eth_proto3) == ETH_TYPE_ARP) ||
+                       ((rte_be_to_cpu_16(*eth_proto3) == ETH_TYPE_IPV4)
+                        && (*protocol3 == IP_PROTOCOL_ICMP)
+
+               #ifdef VNF_ACL
+               && (link3->ip == rte_be_to_cpu_32(*dst_addr3))
+               #endif
+               )) {
+
+               #ifdef VNF_ACL
+               out_port3 = p_arp->outport_id[pkt[3]->port];
+               process_arpicmp_pkt(pkt[3], out_port3, pkt_mask3);
+               #else
+               process_arpicmp_pkt(pkt[3], ifm_get_port(in_port_id));
+               #endif
+
+               return;
+       }
+       #ifdef IPV6
+       else if ((rte_be_to_cpu_16(*eth_proto3) == ETH_TYPE_IPV6)
+               && (*protocol3 == ICMPV6_PROTOCOL_ID)) {
+
+               #ifdef VNF_ACL
+               out_port3 = p_arp->outport_id[pkt[3]->port];
+               process_icmpv6_pkt(pkt[3], out_port3, pkt_mask3);
+               #else
+               process_icmpv6_pkt(pkt[3], ifm_get_port(in_port_id));
+               #endif
+               return;
+       }
+       #endif
+
+       /* Drop the pkt if not ARP/ICMP */
+       rte_pipeline_ah_packet_drop(p_arp->p.p, pkt_mask3);
+       p_arp->droppedPktCount++;
+
+
+}
+
+PIPELINE_ARPICMP_KEY_PORT_IN_AH(
+       port_in_ah_arpicmp,
+       pkt_key_arpicmp,
+       pkt4_key_arpicmp);
+
+static void *pipeline_arpicmp_init(struct pipeline_params *params,
+                               __rte_unused void *arg)
+{
+       struct pipeline *p;
+       struct pipeline_arpicmp *p_arp;
+       uint32_t size, i, in_ports_arg_size;
+
+       printf("Start pipeline_arpicmp_init\n");
+
+       /* Check input arguments */
+       if ((params == NULL) ||
+                       (params->n_ports_in == 0) ||
+                       (params->n_ports_out == 0))
+               return NULL;
+
+       /* Memory allocation */
+       size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct pipeline_arpicmp));
+       p = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
+       p_arp = (struct pipeline_arpicmp *)p;
+       if (p == NULL)
+               return NULL;
+
+       //gp_arp = p_arp;
+       struct app_params *app = (struct app_params *)arg;
+       myApp = arg;
+
+       PLOG(p, HIGH, "ARPICMP");
+       strcpy(p->name, params->name);
+       p->log_level = params->log_level;
+
+       p_arp->receivedPktCount = 0;
+       p_arp->droppedPktCount = 0;
+
+#ifdef VNF_ACL
+       for (i = 0; i < PIPELINE_MAX_PORT_IN; i++)
+               p_arp->links_map[i] = 0xff;
+
+       p_arp->pipeline_num = 0;
+
+       /* Parse arguments */
+       if (pipeline_arpicmp_parse_args(p_arp, params))
+               return NULL;
+#endif
+       #ifndef VNF_ACL
+       lib_arp_init(params, app);
+       #endif
+
+       /* Pipeline */
+       {
+               struct rte_pipeline_params pipeline_params = {
+                       .name = "ARPICMP",
+                       .socket_id = params->socket_id,
+                       .offset_port_id = 0,
+                       //.offset_port_id = arp_meta_offset,
+               };
+
+               p->p = rte_pipeline_create(&pipeline_params);
+               if (p->p == NULL) {
+                       rte_free(p);
+                       return NULL;
+               }
+       }
+
+       p->n_ports_in = params->n_ports_in;
+       p->n_ports_out = params->n_ports_out;
+       p->n_tables = 1;
+
+       /* Memory allocation for in_port_h_arg */
+       in_ports_arg_size = RTE_CACHE_LINE_ROUNDUP(
+               (sizeof(struct pipeline_arpicmp_in_port_h_arg)) *
+                               (params->n_ports_in));
+       struct pipeline_arpicmp_in_port_h_arg *ap =
+               (struct pipeline_arpicmp_in_port_h_arg *)rte_zmalloc(NULL,
+                               in_ports_arg_size,
+                               RTE_CACHE_LINE_SIZE);
+       if (ap == NULL)
+               return NULL;
+
+       /*Input ports */
+       for (i = 0; i < p->n_ports_in; i++) {
+               /* passing our txrx pipeline in call back arg */
+               (ap[i]).p = p_arp;
+               (ap[i]).in_port_id = i;
+               struct rte_pipeline_port_in_params port_params = {
+                       .ops =
+                                       pipeline_port_in_params_get_ops(&params->
+                                                                       port_in[i]),
+                       .arg_create =
+                                       pipeline_port_in_params_convert(&params->
+                                                                       port_in[i]),
+                       .f_action = NULL,
+                       .arg_ah = &(ap[i]),
+                       .burst_size = params->port_in[i].burst_size,
+               };
+
+                       port_params.f_action = port_in_ah_arpicmp;
+
+               int status = rte_pipeline_port_in_create(p->p,
+                                                        &port_params,
+                                                        &p->port_in_id[i]);
+
+               if (status) {
+                       rte_pipeline_free(p->p);
+                       rte_free(p);
+                       return NULL;
+               }
+       }
+
+       /* Output ports */
+       for (i = 0; i < p->n_ports_out; i++) {
+               struct rte_pipeline_port_out_params port_params = {
+                       .ops =
+                                       pipeline_port_out_params_get_ops(&params->
+                                                                        port_out[i]),
+                       .arg_create =
+                                       pipeline_port_out_params_convert(&params->
+                                                                        port_out[i]),
+                       .f_action = NULL,
+                       .arg_ah = NULL,
+               };
+
+               int status = rte_pipeline_port_out_create(p->p,
+                                                               &port_params,
+                                                               &p->port_out_id[i]);
+
+               if (status) {
+                       rte_pipeline_free(p->p);
+                       rte_free(p);
+                       return NULL;
+               }
+       }
+       int pipeline_num = 0;
+
+       int status = sscanf(params->name, "PIPELINE%d", &pipeline_num);
+
+       if (status < 0) {
+               return NULL;
+               printf("Unable to read pipeline number\n");
+       }
+
+       p_arp->pipeline_num = (uint8_t) pipeline_num;
+
+       register_pipeline_Qs(p_arp->pipeline_num, p);
+       set_phy_outport_id(p_arp->pipeline_num, p, p_arp->outport_id);
+
+       /* Tables */
+       {
+               struct rte_pipeline_table_params table_params = {
+                       .ops = &rte_table_stub_ops,
+                       .arg_create = NULL,
+                       .f_action_hit = NULL,
+                       .f_action_miss = NULL,
+                       .arg_ah = NULL,
+                       .action_data_size = 0,
+               };
+
+               int status = rte_pipeline_table_create(p->p,
+                                                                        &table_params,
+                                                                        &p->table_id[0]);
+
+               if (status) {
+                       rte_pipeline_free(p->p);
+                       rte_free(p);
+                       return NULL;
+               }
+       }
+
+       /* Connecting input ports to tables */
+       for (i = 0; i < p->n_ports_in; i++) {
+
+               int status = rte_pipeline_port_in_connect_to_table(p->p,
+                                                                        p->
+                                                                        port_in_id
+                                                                        [i],
+                                                                        p->
+                                                                        table_id[0]);
+
+               if (status) {
+                       rte_pipeline_free(p->p);
+                       rte_free(p);
+                       return NULL;
+               }
+
+       }
+
+       /* Enable input ports */
+       for (i = 0; i < p->n_ports_in; i++) {
+               int status = rte_pipeline_port_in_enable(p->p,
+                                                        p->port_in_id[i]);
+
+               if (status) {
+                       rte_pipeline_free(p->p);
+                       rte_free(p);
+                       return NULL;
+               }
+       }
+
+       /* Check pipeline consistency */
+       if (rte_pipeline_check(p->p) < 0) {
+               rte_pipeline_free(p->p);
+               rte_free(p);
+               return NULL;
+       }
+
+       /* Message queues */
+       p->n_msgq = params->n_msgq;
+       for (i = 0; i < p->n_msgq; i++)
+               p->msgq_in[i] = params->msgq_in[i];
+       for (i = 0; i < p->n_msgq; i++)
+               p->msgq_out[i] = params->msgq_out[i];
+
+       /* Message handlers */
+       memcpy(p->handlers, handlers, sizeof(p->handlers));
+
+#ifdef VNF_ACL
+
+       /* create the arpicmp mbuf rx pool */
+       lib_arp_pktmbuf_tx_pool = rte_pktmbuf_pool_create(
+                               "lib_arp_mbuf_tx_pool",
+                               NB_ARPICMP_MBUF, 32,
+                               0, RTE_MBUF_DEFAULT_BUF_SIZE,
+                               rte_socket_id());
+
+       if (lib_arp_pktmbuf_tx_pool == NULL) {
+               printf("ARP mbuf pool create failed.\n");
+               return NULL;
+       }
+
+       lib_arp_pkt = rte_pktmbuf_alloc(lib_arp_pktmbuf_tx_pool);
+       if (lib_arp_pkt == NULL) {
+               printf("ARP lib_arp_pkt alloc failed.\n");
+               return NULL;
+       }
+
+       /* ARP Table */
+       arp_hash_params.socket_id = rte_socket_id();
+       arp_hash_params.entries = MAX_NUM_ARP_ENTRIES;
+       arp_hash_handle = rte_hash_create(&arp_hash_params);
+
+       if (arp_hash_handle == NULL) {
+               printf("ARP rte_hash_create failed. socket %d ...\n",
+                                        arp_hash_params.socket_id);
+               return NULL;
+       }
+       printf("arp_hash_handle %p\n\n", (void *)arp_hash_handle);
+
+       /* ND IPv6 */
+       nd_hash_params.socket_id = rte_socket_id();
+       nd_hash_params.entries = MAX_NUM_ND_ENTRIES;
+       nd_hash_handle = rte_hash_create(&nd_hash_params);
+
+       if (nd_hash_handle == NULL) {
+               printf("ND rte_hash_create failed. socket %d ...\n",
+                                        nd_hash_params.socket_id);
+               return NULL;
+       }
+
+       printf("nd_hash_handle %p\n\n", (void *)nd_hash_handle);
+#endif
+       return p;
+}
+
+static int pipeline_arpicmp_free(void *pipeline)
+{
+       struct pipeline *p = (struct pipeline *)pipeline;
+
+       /* Check input arguments */
+       if (p == NULL)
+               return -1;
+
+       /* Free resources */
+       rte_pipeline_free(p->p);
+       rte_free(p);
+       return 0;
+}
+
+static int pipeline_arpicmp_timer(void *pipeline)
+{
+       struct pipeline *p = (struct pipeline *)pipeline;
+
+       pipeline_msg_req_handle(p);
+       rte_pipeline_flush(p->p);
+
+       return 0;
+}
+
+static int
+pipeline_arpicmp_track(void *pipeline, uint32_t port_in, uint32_t *port_out)
+{
+       struct pipeline *p = (struct pipeline *)pipeline;
+
+       /* Check input arguments */
+       if ((p == NULL) || (port_in >= p->n_ports_in) || (port_out == NULL))
+               return -1;
+
+       *port_out = port_in / p->n_ports_in;
+       return 0;
+}
+
+struct pipeline_be_ops pipeline_arpicmp_be_ops = {
+       .f_init = pipeline_arpicmp_init,
+       .f_free = pipeline_arpicmp_free,
+       .f_run = NULL,
+       .f_timer = pipeline_arpicmp_timer,
+       .f_track = pipeline_arpicmp_track,
+};
diff --git a/common/VIL/pipeline_arpicmp/pipeline_arpicmp_be.h b/common/VIL/pipeline_arpicmp/pipeline_arpicmp_be.h
new file mode 100644 (file)
index 0000000..2c7fce2
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef __INCLUDE_PIPELINE_ARPICMP_BE_H__
+#define __INCLUDE_PIPELINE_ARPICMP_BE_H__
+
+#include "pipeline_common_be.h"
+#define PIPELINE_ARPICMP_KEY_PORT_IN_AH(f_ah, f_pkt_work, f_pkt4_work)  \
+static int                                                              \
+f_ah(                                                                   \
+       __rte_unused struct rte_pipeline *rte_p,                        \
+       struct rte_mbuf **pkts,                                         \
+       uint32_t n_pkts,                                                \
+       void *arg)                                                      \
+{                                                                       \
+       uint32_t i, j;                                                  \
+                                                                       \
+       for (j = 0; j < n_pkts; j++)                                    \
+               rte_prefetch0(pkts[j]);                                 \
+                                                                       \
+       for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4)                   \
+               f_pkt4_work(&pkts[i], i, arg);                          \
+                                                                       \
+       for ( ; i < n_pkts; i++)                                        \
+               f_pkt_work(pkts[i], i, arg);                            \
+                                                                       \
+                                                                       \
+       return 0;                                                       \
+}
+
+extern struct app_params *myApp;
+void print_pkt1(struct rte_mbuf *pkt);
+struct ether_addr *get_link_hw_addr(uint8_t out_port);
+#ifdef VNF_ACL
+
+#include <rte_pipeline.h>
+#include "rte_ether.h"
+#include "app.h"
+
+#if (RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN)
+// x86 == little endian
+// network  == big endian
+#define CHECK_ENDIAN_16(x) rte_be_to_cpu_16(x)
+#define CHECK_ENDIAN_32(x) rte_be_to_cpu_32(x)
+#else
+#define CHECK_ENDIAN_16(x) (x)
+#define CHECK_ENDIAN_32(x) (x)
+#endif
+
+
+#define MAX_ARP_RT_ENTRY 16
+#define MAX_ND_RT_ENTRY 16
+
+#define ND_IPV6_ADDR_SIZE 16   /* 16 Byte of IPv6 Address */
+
+enum {
+ARP_FOUND,
+ARP_NOT_FOUND,
+NH_NOT_FOUND,
+};
+
+enum arp_key_type {
+       ARP_IPV4,
+       /* ND IPv6 */
+       ND_IPV6,
+};
+
+struct arp_key_ipv4 {
+       uint32_t ip;
+       uint8_t port_id;
+       uint8_t filler1;
+       uint8_t filler2;
+       uint8_t filler3;
+};
+
+/* ND IPv6 */
+struct nd_key_ipv6 {
+       /*128 Bit of IPv6 Address */
+       /*<48bit Network> <16bit Subnet> <64bit Interface> */
+       uint8_t ipv6[ND_IPV6_ADDR_SIZE];
+       uint8_t port_id;
+       uint8_t filler1;
+       uint8_t filler2;
+       uint8_t filler3;
+};
+
+struct arp_key {
+       enum arp_key_type type;
+       union {
+               struct arp_key_ipv4 ipv4;
+       } key;
+};
+
+struct lib_arp_route_table_entry {
+       uint32_t ip;
+       uint32_t mask;
+       uint32_t port;
+       uint32_t nh;
+};
+
+struct lib_nd_route_table_entry {
+       uint8_t ipv6[16];
+       uint8_t depth;
+       uint32_t port;
+       uint8_t nhipv6[16];
+};
+extern struct lib_arp_route_table_entry lib_arp_route_table[MAX_ARP_RT_ENTRY];
+extern struct lib_nd_route_table_entry  lib_nd_route_table[MAX_ND_RT_ENTRY];
+
+extern uint8_t prv_in_port_a[PIPELINE_MAX_PORT_IN];
+extern void convert_prefixlen_to_netmask_ipv6(uint32_t depth,
+                                                               uint8_t netmask_ipv6[]);
+uint32_t get_nh(uint32_t, uint32_t*);
+void get_nh_ipv6(uint8_t ipv6[], uint32_t *port, uint8_t nhipv6[]);
+
+extern uint32_t ARPICMP_DEBUG;
+
+
+/* ARP entry populated and echo reply recieved */
+#define COMPLETE   1
+/* ARP entry populated and either awaiting echo reply or stale entry */
+#define INCOMPLETE 0
+
+/* ND IPv6 */
+extern uint32_t NDIPV6_DEBUG;
+
+/* ICMPv6 entry populated and echo reply recieved */
+#define ICMPv6_COMPLETE   1
+/* ICMPv6 entry populated and either awaiting echo reply or stale entry */
+#define ICMPv6_INCOMPLETE 0
+
+struct arp_entry_data {
+       struct ether_addr eth_addr;
+       uint8_t port;
+       uint8_t status;
+       uint32_t ip;
+} __attribute__ ((__packed__));
+
+/*ND IPv6*/
+struct nd_entry_data {
+       struct ether_addr eth_addr;
+       uint8_t port;
+       uint8_t status;
+       uint8_t ipv6[ND_IPV6_ADDR_SIZE];
+} __attribute__ ((__packed__));
+
+int get_dest_mac_address(const uint32_t ipaddr, const uint32_t phy_port,
+                        struct ether_addr *hw_addr, uint32_t *nhip);
+int get_dest_mac_addr(const uint32_t ipaddr, const uint32_t phy_port,
+                                       struct ether_addr *hw_addr);
+
+int get_dest_mac_address_ipv6(uint8_t ipv6addr[], uint32_t phy_port,
+                                               struct ether_addr *hw_addr, uint8_t nhipv6[]);
+
+void lib_arp_request_arp(
+       const uint32_t ipaddr,
+       const uint32_t phy_port,
+       struct rte_pipeline *rte_p);
+
+void print_arp_table(void);
+void print_nd_table(void);
+void remove_arp_entry(uint32_t ipaddr, uint8_t portid);
+void remove_nd_entry_ipv6(uint8_t ipv6addr[], uint8_t portid);
+void populate_arp_entry(const struct ether_addr *hw_addr, uint32_t ipaddr,
+                       uint8_t portid);
+/*ND IPv6*/
+int populate_nd_entry(const struct ether_addr *hw_addr, uint8_t ip[],
+                                       uint8_t portid);
+void request_arp(uint8_t port_id, uint32_t ip, struct rte_pipeline *rte_p);
+void request_arp_wrap(uint8_t port_id, uint32_t ip);
+void request_echo(unsigned int port_id, uint32_t ip);
+
+void process_arpicmp_pkt(struct rte_mbuf *pkt, uint32_t out_port,
+                        uint32_t pkt_num);
+
+struct arp_entry_data *retrieve_arp_entry(const struct arp_key_ipv4 arp_key);
+struct nd_entry_data *retrieve_nd_entry(struct nd_key_ipv6 nd_key);
+
+struct nd_entry_data *retrieve_nd_entry(struct nd_key_ipv6 nd_key);
+
+void lib_nd_init(/*struct pipeline_params *params, */ struct app_params *app);
+void print_pkt1(struct rte_mbuf *pkt);
+
+#endif
+
+uint8_t lb_outport_id[PIPELINE_MAX_PORT_IN];
+struct pipeline *loadb_pipeline[PIPELINE_MAX_PORT_IN];
+struct pipeline *all_pipeline[PIPELINE_MAX_PORT_IN];
+uint8_t vnf_to_loadb_map[PIPELINE_MAX_PORT_IN];
+uint8_t port_to_loadb_map[PIPELINE_MAX_PORT_IN];
+uint8_t loadb_pipeline_nums[PIPELINE_MAX_PORT_IN];
+
+#if 0
+uint8_t lb_outport_id[PIPELINE_MAX_PORT_IN];
+struct pipeline *arp_pipeline[PIPELINE_MAX_PORT_IN];
+uint8_t vnf_to_arp_map[PIPELINE_MAX_PORT_IN];
+uint8_t port_to_arp_map[PIPELINE_MAX_PORT_IN];
+uint8_t arp_pipeline_nums[PIPELINE_MAX_PORT_IN];
+#endif
+
+void set_port_to_loadb_map(uint8_t pipeline_num);
+uint8_t get_port_to_loadb_map(uint8_t phy_port_id);
+/* acts on port_to_loadb_map */
+
+void set_phy_inport_map(uint8_t pipeline_num, uint8_t *map);
+void set_phy_outport_map(uint8_t pipeline_num, uint8_t *map);
+
+void set_outport_id(uint8_t pipeline_num, struct pipeline *p, uint8_t *map);
+/* acts on lb_outport_id */
+uint8_t get_loadb_outport_id(uint8_t actual_phy_port);
+/* acts on lb_outport_id */
+uint8_t get_vnf_set_num(uint8_t pipeline_num);
+
+void pipelines_port_info(void);
+void pipelines_map_info(void);
+void register_loadb_to_arp(uint8_t pipeline_num, struct pipeline *p,
+                                __rte_unused struct app_params *app);
+/* vnf_to_loadb_map[]  and loadb_pipelines[] */
+uint8_t SWQ_to_Port_map[128];
+
+extern struct pipeline_be_ops pipeline_arpicmp_be_ops;
+void register_pipeline_Qs(uint8_t pipeline_num, struct pipeline *p);
+void set_link_map(uint8_t pipeline_num, struct pipeline *p, uint8_t *map);
+void set_outport_id(uint8_t pipeline_num, struct pipeline *p, uint8_t *map);
+void set_phy_outport_id(uint8_t pipeline_num, struct pipeline *p, uint8_t *map);
+void set_phy_inport_id(uint8_t pipeline_num, struct pipeline *p, uint8_t *map);
+
+/*
+ * Messages
+ */
+enum pipeline_arpicmp_msg_req_type {
+       PIPELINE_ARPICMP_MSG_REQ_ENTRY_DBG,
+       PIPELINE_ARPICMP_MSG_REQS
+};
+
+/*
+ * MSG ENTRY DBG
+ */
+struct pipeline_arpicmp_entry_dbg_msg_req {
+       enum pipeline_msg_req_type type;
+       enum pipeline_arpicmp_msg_req_type subtype;
+
+       /* data */
+       uint8_t data[2];
+};
+
+/*
+ * ARPICMP Entry
+ */
+
+struct pipeline_arpicmp_in_port_h_arg {
+       struct pipeline_arpicmp *p;
+       uint8_t in_port_id;
+};
+
+struct pipeline_arpicmp_entry_dbg_msg_rsp {
+       int status;
+};
+
+#ifdef VNF_ACL
+
+ /* ICMPv6 Header */
+struct icmpv6_hdr {
+        uint8_t icmpv6_type;    /* ICMPV6 packet type. */
+        uint8_t icmpv6_code;    /* ICMPV6 packet code. */
+        uint16_t icmpv6_cksum;  /* ICMPV6 packet checksum. */
+} __attribute__ ((__packed__));
+
+ /**
+  * ICMPV6 Info Header
+  */
+struct icmpv6_info_hdr {
+        uint16_t icmpv6_ident;  /* ICMPV6 packet identifier. */
+        uint16_t icmpv6_seq_nb; /* ICMPV6 packet sequence number. */
+} __attribute__ ((__packed__));
+
+ /**
+  * ICMPV6 ND Header
+  */
+struct icmpv6_nd_hdr {
+        /*ND Advertisement flags */
+        uint32_t icmpv6_reserved;
+        /* bit31-Router, bit30-Solicited, bit29-Override, bit28-bit0 unused */
+
+        uint8_t target_ipv6[16];  /**< target IPv6 address */
+ /*ICMPv6 Option*/
+        uint8_t type;
+        uint8_t length;
+        struct ether_addr link_layer_address;
+} __attribute__ ((__packed__));
+
+ /* Icmpv6 types */
+ #define ICMPV6_PROTOCOL_ID 58
+ #define ICMPV6_ECHO_REQUEST 0x0080
+ #define ICMPV6_ECHO_REPLY 0x0081
+ #define ICMPV6_NEIGHBOR_SOLICITATION 0x0087
+  #define ICMPV6_NEIGHBOR_ADVERTISEMENT 0x0088
+ #define IPV6_MULTICAST 0xFF02
+
+ #define NEIGHBOR_SOLICITATION_SET 0x40000000
+enum icmpv6_link_layer_Address_type {
+        e_Source_Link_Layer_Address = 1,
+        e_Target_Link_Layer_Address,
+        e_Link_Layer_Address
+};
+
+uint8_t is_multicast_ipv6_addr(uint8_t ipv6[]);
+struct icmpv6_port_address {
+        uint32_t ipv6[16];
+        uint64_t mac_addr;
+};
+
+struct icmpv6_port_address icmpv6_port_addresses[RTE_MAX_ETHPORTS];
+
+ #define MAX_NUM_ICMPv6_ENTRIES 64
+ //struct rte_pipeline *myicmpP;
+struct rte_mbuf *lib_icmpv6_pkt;
+void request_icmpv6_echo(uint32_t port_id, uint8_t ipv6[]);
+void request_icmpv6_echo_message(uint16_t port_id, uint8_t ipv6[],
+                                        struct ether_addr *gw_addr);
+void
+process_icmpv6_pkt(struct rte_mbuf *pkt, uint32_t out_port, uint32_t pkt_num);
+
+int get_dest_mac_addr_port(const uint32_t ipaddr,
+       uint32_t *phy_port, struct ether_addr *hw_addr);
+
+int get_dest_mac_address_ipv6_port(uint8_t ipv6addr[], uint32_t *phy_port,
+       struct ether_addr *hw_addr, uint8_t nhipv6[]);
+#endif
+#endif
diff --git a/common/VIL/pipeline_common/pipeline_common_be.c b/common/VIL/pipeline_common/pipeline_common_be.c
new file mode 100644 (file)
index 0000000..66e2c5b
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <rte_common.h>
+#include <rte_ring.h>
+#include <rte_malloc.h>
+
+#include "pipeline_common_be.h"
+
+void *
+pipeline_msg_req_ping_handler(__rte_unused struct pipeline *p,
+       void *msg)
+{
+       struct pipeline_msg_rsp *rsp = msg;
+
+       rsp->status = 0; /* OK */
+
+       return rsp;
+}
+
+void *
+pipeline_msg_req_stats_port_in_handler(struct pipeline *p,
+       void *msg)
+{
+       struct pipeline_stats_msg_req *req = msg;
+       struct pipeline_stats_port_in_msg_rsp *rsp = msg;
+       uint32_t port_id;
+
+       /* Check request */
+       if (req->id >= p->n_ports_in) {
+               rsp->status = -1;
+               return rsp;
+       }
+       port_id = p->port_in_id[req->id];
+
+       /* Process request */
+       rsp->status = rte_pipeline_port_in_stats_read(p->p,
+               port_id,
+               &rsp->stats,
+               1);
+
+       return rsp;
+}
+
+void *
+pipeline_msg_req_stats_port_out_handler(struct pipeline *p,
+       void *msg)
+{
+       struct pipeline_stats_msg_req *req = msg;
+       struct pipeline_stats_port_out_msg_rsp *rsp = msg;
+       uint32_t port_id;
+
+       /* Check request */
+       if (req->id >= p->n_ports_out) {
+               rsp->status = -1;
+               return rsp;
+       }
+       port_id = p->port_out_id[req->id];
+
+       /* Process request */
+       rsp->status = rte_pipeline_port_out_stats_read(p->p,
+               port_id,
+               &rsp->stats,
+               1);
+
+       return rsp;
+}
+
+void *
+pipeline_msg_req_stats_table_handler(struct pipeline *p,
+       void *msg)
+{
+       struct pipeline_stats_msg_req *req = msg;
+       struct pipeline_stats_table_msg_rsp *rsp = msg;
+       uint32_t table_id;
+
+       /* Check request */
+       if (req->id >= p->n_tables) {
+               rsp->status = -1;
+               return rsp;
+       }
+       table_id = p->table_id[req->id];
+
+       /* Process request */
+       rsp->status = rte_pipeline_table_stats_read(p->p,
+               table_id,
+               &rsp->stats,
+               1);
+
+       return rsp;
+}
+
+void *
+pipeline_msg_req_port_in_enable_handler(struct pipeline *p,
+       void *msg)
+{
+       struct pipeline_port_in_msg_req *req = msg;
+       struct pipeline_msg_rsp *rsp = msg;
+       uint32_t port_id;
+
+       /* Check request */
+       if (req->port_id >= p->n_ports_in) {
+               rsp->status = -1;
+               return rsp;
+       }
+       port_id = p->port_in_id[req->port_id];
+
+       /* Process request */
+       rsp->status = rte_pipeline_port_in_enable(p->p,
+               port_id);
+
+       return rsp;
+}
+
+void *
+pipeline_msg_req_port_in_disable_handler(struct pipeline *p,
+       void *msg)
+{
+       struct pipeline_port_in_msg_req *req = msg;
+       struct pipeline_msg_rsp *rsp = msg;
+       uint32_t port_id;
+
+       /* Check request */
+       if (req->port_id >= p->n_ports_in) {
+               rsp->status = -1;
+               return rsp;
+       }
+       port_id = p->port_in_id[req->port_id];
+
+       /* Process request */
+       rsp->status = rte_pipeline_port_in_disable(p->p,
+               port_id);
+
+       return rsp;
+}
+
+void *
+pipeline_msg_req_invalid_handler(__rte_unused struct pipeline *p,
+       void *msg)
+{
+       struct pipeline_msg_rsp *rsp = msg;
+
+       rsp->status = -1; /* Error */
+
+       return rsp;
+}
+
+int
+pipeline_msg_req_handle(struct pipeline *p)
+{
+       uint32_t msgq_id;
+
+       for (msgq_id = 0; msgq_id < p->n_msgq; msgq_id++) {
+               for ( ; ; ) {
+                       struct pipeline_msg_req *req;
+                       pipeline_msg_req_handler f_handle;
+
+                       req = pipeline_msg_recv(p, msgq_id);
+                       if (req == NULL)
+                               break;
+
+                       f_handle = (req->type < PIPELINE_MSG_REQS) ?
+                               p->handlers[req->type] :
+                               pipeline_msg_req_invalid_handler;
+
+                       if (f_handle == NULL)
+                               f_handle = pipeline_msg_req_invalid_handler;
+
+                       pipeline_msg_send(p,
+                               msgq_id,
+                               f_handle(p, (void *) req));
+               }
+       }
+
+       return 0;
+}
diff --git a/common/VIL/pipeline_common/pipeline_common_be.h b/common/VIL/pipeline_common/pipeline_common_be.h
new file mode 100644 (file)
index 0000000..f3e937e
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef __INCLUDE_PIPELINE_COMMON_BE_H__
+#define __INCLUDE_PIPELINE_COMMON_BE_H__
+
+#include <rte_common.h>
+#include <rte_ring.h>
+#include <rte_pipeline.h>
+
+#include "pipeline_be.h"
+
+struct pipeline;
+
+enum pipeline_msg_req_type {
+       PIPELINE_MSG_REQ_PING = 0,
+       PIPELINE_MSG_REQ_STATS_PORT_IN,
+       PIPELINE_MSG_REQ_STATS_PORT_OUT,
+       PIPELINE_MSG_REQ_STATS_TABLE,
+       PIPELINE_MSG_REQ_PORT_IN_ENABLE,
+       PIPELINE_MSG_REQ_PORT_IN_DISABLE,
+       PIPELINE_MSG_REQ_CUSTOM,
+       PIPELINE_MSG_REQS
+};
+
+typedef void *(*pipeline_msg_req_handler)(struct pipeline *p, void *msg);
+
+struct pipeline {
+       struct rte_pipeline *p;
+       uint32_t port_in_id[PIPELINE_MAX_PORT_IN];
+       uint32_t port_out_id[PIPELINE_MAX_PORT_OUT];
+       uint32_t table_id[PIPELINE_MAX_TABLES];
+       struct rte_ring *msgq_in[PIPELINE_MAX_MSGQ_IN];
+       struct rte_ring *msgq_out[PIPELINE_MAX_MSGQ_OUT];
+
+       uint32_t n_ports_in;
+       uint32_t n_ports_out;
+       uint32_t n_tables;
+       uint32_t n_msgq;
+
+       pipeline_msg_req_handler handlers[PIPELINE_MSG_REQS];
+       char name[PIPELINE_NAME_SIZE];
+       uint32_t log_level;
+};
+
+enum pipeline_log_level {
+       PIPELINE_LOG_LEVEL_HIGH = 1,
+       PIPELINE_LOG_LEVEL_LOW,
+       PIPELINE_LOG_LEVELS
+};
+
+#define PLOG(p, level, fmt, ...)                                       \
+do {                                                                   \
+       if (p->log_level >= PIPELINE_LOG_LEVEL_ ## level)               \
+               fprintf(stdout, "[%s] " fmt "\n", p->name, ## __VA_ARGS__);\
+} while (0)
+
+static inline void *
+pipeline_msg_recv(struct pipeline *p,
+       uint32_t msgq_id)
+{
+       struct rte_ring *r = p->msgq_in[msgq_id];
+       void *msg;
+       int status = rte_ring_sc_dequeue(r, &msg);
+
+       if (status != 0)
+               return NULL;
+
+       return msg;
+}
+
+static inline void
+pipeline_msg_send(struct pipeline *p,
+       uint32_t msgq_id,
+       void *msg)
+{
+       struct rte_ring *r = p->msgq_out[msgq_id];
+       int status;
+
+       do {
+               status = rte_ring_sp_enqueue(r, msg);
+       } while (status == -ENOBUFS);
+}
+
+struct pipeline_msg_req {
+       enum pipeline_msg_req_type type;
+};
+
+struct pipeline_stats_msg_req {
+       enum pipeline_msg_req_type type;
+       uint32_t id;
+};
+
+struct pipeline_port_in_msg_req {
+       enum pipeline_msg_req_type type;
+       uint32_t port_id;
+};
+
+struct pipeline_custom_msg_req {
+       enum pipeline_msg_req_type type;
+       uint32_t subtype;
+};
+
+struct pipeline_msg_rsp {
+       int status;
+};
+
+struct pipeline_stats_port_in_msg_rsp {
+       int status;
+       struct rte_pipeline_port_in_stats stats;
+};
+
+struct pipeline_stats_port_out_msg_rsp {
+       int status;
+       struct rte_pipeline_port_out_stats stats;
+};
+
+struct pipeline_stats_table_msg_rsp {
+       int status;
+       struct rte_pipeline_table_stats stats;
+};
+
+void *pipeline_msg_req_ping_handler(struct pipeline *p, void *msg);
+void *pipeline_msg_req_stats_port_in_handler(struct pipeline *p, void *msg);
+void *pipeline_msg_req_stats_port_out_handler(struct pipeline *p, void *msg);
+void *pipeline_msg_req_stats_table_handler(struct pipeline *p, void *msg);
+void *pipeline_msg_req_port_in_enable_handler(struct pipeline *p, void *msg);
+void *pipeline_msg_req_port_in_disable_handler(struct pipeline *p, void *msg);
+void *pipeline_msg_req_invalid_handler(struct pipeline *p, void *msg);
+
+int pipeline_msg_req_handle(struct pipeline *p);
+
+#endif
diff --git a/common/VIL/pipeline_common/pipeline_common_fe.c b/common/VIL/pipeline_common/pipeline_common_fe.c
new file mode 100644 (file)
index 0000000..5df2977
--- /dev/null
@@ -0,0 +1,1429 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <rte_common.h>
+#include <rte_ring.h>
+#include <rte_malloc.h>
+#include <cmdline_rdline.h>
+#include <cmdline_parse.h>
+#include <cmdline_parse_num.h>
+#include <cmdline_parse_string.h>
+#include <cmdline_parse_ipaddr.h>
+#include <cmdline_parse_etheraddr.h>
+#include <cmdline_socket.h>
+#include <cmdline.h>
+
+#include "pipeline_common_fe.h"
+#ifndef VNF_ACL
+#include "interface.h"
+#endif
+
+int
+app_pipeline_ping(struct app_params *app,
+       uint32_t pipeline_id)
+{
+       struct app_pipeline_params *p;
+       struct pipeline_msg_req *req;
+       struct pipeline_msg_rsp *rsp;
+       int status = 0;
+
+       /* Check input arguments */
+       if (app == NULL)
+               return -1;
+
+       APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, p);
+       if (p == NULL)
+               return -1;
+
+       /* Message buffer allocation */
+       req = app_msg_alloc(app);
+       if (req == NULL)
+               return -1;
+
+       /* Fill in request */
+       req->type = PIPELINE_MSG_REQ_PING;
+
+       /* Send request and wait for response */
+       rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
+       if (rsp == NULL)
+               return -1;
+
+       /* Check response */
+       status = rsp->status;
+
+       /* Message buffer free */
+       app_msg_free(app, rsp);
+
+       return status;
+}
+#if 1
+int
+app_pipeline_stats_port_in(struct app_params *app,
+       uint32_t pipeline_id,
+       uint32_t port_id,
+       struct rte_pipeline_port_in_stats *stats)
+{
+       struct app_pipeline_params *p;
+       struct pipeline_stats_msg_req *req;
+       struct pipeline_stats_port_in_msg_rsp *rsp;
+       int status = 0;
+
+       /* Check input arguments */
+       if ((app == NULL) ||
+               (stats == NULL))
+               return -1;
+
+       APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, p);
+       if ((p == NULL) ||
+               (port_id >= p->n_pktq_in))
+               return -1;
+
+       /* Message buffer allocation */
+       req = app_msg_alloc(app);
+       if (req == NULL)
+               return -1;
+
+       /* Fill in request */
+       req->type = PIPELINE_MSG_REQ_STATS_PORT_IN;
+       req->id = port_id;
+
+       /* Send request and wait for response */
+       rsp = (struct pipeline_stats_port_in_msg_rsp *)
+               app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
+       if (rsp == NULL)
+               return -1;
+
+       /* Check response */
+       status = rsp->status;
+       if (status == 0)
+               memcpy(stats, &rsp->stats, sizeof(rsp->stats));
+
+       /* Message buffer free */
+       app_msg_free(app, rsp);
+
+       return status;
+}
+
+int
+app_pipeline_stats_port_out(struct app_params *app,
+       uint32_t pipeline_id,
+       uint32_t port_id,
+       struct rte_pipeline_port_out_stats *stats)
+{
+       struct app_pipeline_params *p;
+       struct pipeline_stats_msg_req *req;
+       struct pipeline_stats_port_out_msg_rsp *rsp;
+       int status = 0;
+
+       /* Check input arguments */
+       if ((app == NULL) ||
+               (pipeline_id >= app->n_pipelines) ||
+               (stats == NULL))
+               return -1;
+
+       APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, p);
+       if ((p == NULL) ||
+               (port_id >= p->n_pktq_out))
+               return -1;
+
+       /* Message buffer allocation */
+       req = app_msg_alloc(app);
+       if (req == NULL)
+               return -1;
+
+       /* Fill in request */
+       req->type = PIPELINE_MSG_REQ_STATS_PORT_OUT;
+       req->id = port_id;
+
+       /* Send request and wait for response */
+       rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
+       if (rsp == NULL)
+               return -1;
+
+       /* Check response */
+       status = rsp->status;
+       if (status == 0)
+               memcpy(stats, &rsp->stats, sizeof(rsp->stats));
+
+       /* Message buffer free */
+       app_msg_free(app, rsp);
+
+       return status;
+}
+
+int
+app_pipeline_stats_table(struct app_params *app,
+       uint32_t pipeline_id,
+       uint32_t table_id,
+       struct rte_pipeline_table_stats *stats)
+{
+       struct app_pipeline_params *p;
+       struct pipeline_stats_msg_req *req;
+       struct pipeline_stats_table_msg_rsp *rsp;
+       int status = 0;
+
+       /* Check input arguments */
+       if ((app == NULL) ||
+               (stats == NULL))
+               return -1;
+
+       APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, p);
+       if (p == NULL)
+               return -1;
+
+       /* Message buffer allocation */
+       req = app_msg_alloc(app);
+       if (req == NULL)
+               return -1;
+
+       /* Fill in request */
+       req->type = PIPELINE_MSG_REQ_STATS_TABLE;
+       req->id = table_id;
+
+       /* Send request and wait for response */
+       rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
+       if (rsp == NULL)
+               return -1;
+
+       /* Check response */
+       status = rsp->status;
+       if (status == 0)
+               memcpy(stats, &rsp->stats, sizeof(rsp->stats));
+
+       /* Message buffer free */
+       app_msg_free(app, rsp);
+
+       return status;
+}
+
+int
+app_pipeline_port_in_enable(struct app_params *app,
+       uint32_t pipeline_id,
+       uint32_t port_id)
+{
+       struct app_pipeline_params *p;
+       struct pipeline_port_in_msg_req *req;
+       struct pipeline_msg_rsp *rsp;
+       int status = 0;
+
+       /* Check input arguments */
+       if (app == NULL)
+               return -1;
+
+       APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, p);
+       if ((p == NULL) ||
+               (port_id >= p->n_pktq_in))
+               return -1;
+
+       /* Message buffer allocation */
+       req = app_msg_alloc(app);
+       if (req == NULL)
+               return -1;
+
+       /* Fill in request */
+       req->type = PIPELINE_MSG_REQ_PORT_IN_ENABLE;
+       req->port_id = port_id;
+
+       /* Send request and wait for response */
+       rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
+       if (rsp == NULL)
+               return -1;
+
+       /* Check response */
+       status = rsp->status;
+
+       /* Message buffer free */
+       app_msg_free(app, rsp);
+
+       return status;
+}
+
+int
+app_pipeline_port_in_disable(struct app_params *app,
+       uint32_t pipeline_id,
+       uint32_t port_id)
+{
+       struct app_pipeline_params *p;
+       struct pipeline_port_in_msg_req *req;
+       struct pipeline_msg_rsp *rsp;
+       int status = 0;
+
+       /* Check input arguments */
+       if (app == NULL)
+               return -1;
+
+       APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, p);
+       if ((p == NULL) ||
+               (port_id >= p->n_pktq_in))
+               return -1;
+
+       /* Message buffer allocation */
+       req = app_msg_alloc(app);
+       if (req == NULL)
+               return -1;
+
+       /* Fill in request */
+       req->type = PIPELINE_MSG_REQ_PORT_IN_DISABLE;
+       req->port_id = port_id;
+
+       /* Send request and wait for response */
+       rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
+       if (rsp == NULL)
+               return -1;
+
+       /* Check response */
+       status = rsp->status;
+
+       /* Message buffer free */
+       app_msg_free(app, rsp);
+
+       return status;
+}
+
+int
+app_link_config(struct app_params *app,
+       uint32_t link_id,
+       uint32_t ip,
+       uint32_t depth)
+{
+       struct app_link_params *p;
+       uint32_t i, netmask, host, bcast;
+
+       /* Check input arguments */
+       if (app == NULL)
+               return -1;
+
+       APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, p);
+       if (p == NULL) {
+               APP_LOG(app, HIGH, "LINK%" PRIu32 " is not a valid link",
+                       link_id);
+               return -1;
+       }
+
+       if (p->state) {
+               APP_LOG(app, HIGH, "%s is UP, please bring it DOWN first",
+                       p->name);
+               return -1;
+       }
+
+       netmask = (~0U) << (32 - depth);
+       host = ip & netmask;
+       bcast = host | (~netmask);
+
+       if ((ip == 0) ||
+               (ip == UINT32_MAX) ||
+               (ip == host) ||
+               (ip == bcast)) {
+               APP_LOG(app, HIGH, "Illegal IP address");
+               return -1;
+       }
+
+       for (i = 0; i < app->n_links; i++) {
+               struct app_link_params *link = &app->link_params[i];
+               mylink[i] = *link;
+               if (strcmp(p->name, link->name) == 0)
+                       continue;
+
+               if (link->ip == ip) {
+                       APP_LOG(app, HIGH,
+                               "%s is already assigned this IP address",
+                               link->name);
+                       return -1;
+               }
+       }
+
+       if ((depth == 0) || (depth > 32)) {
+               APP_LOG(app, HIGH, "Illegal value for depth parameter "
+                       "(%" PRIu32 ")",
+                       depth);
+               return -1;
+       }
+
+       /* Save link parameters */
+       p->ip = ip;
+       p->depth = depth;
+        #ifndef VNF_ACL
+        if (ifm_add_ipv4_port(link_id, rte_bswap32(ip), depth) == IFM_FAILURE)
+            return -1;
+        #endif
+
+       return 0;
+}
+
+
+void convert_prefixlen_to_netmask_ipv6(uint32_t depth, uint8_t netmask_ipv6[])
+{
+       int mod, div, i;
+
+       memset(netmask_ipv6, 0, 16);
+
+       mod = depth % 8;
+       div = depth / 8;
+
+       for (i = 0; i < div; i++)
+               netmask_ipv6[i] = 0xff;
+
+       netmask_ipv6[i] = (~0 << (8 - mod));
+
+       return;
+}
+
+void
+get_host_portion_ipv6(uint8_t ipv6[], uint8_t netmask[], uint8_t host_ipv6[])
+{
+       int i;
+
+       for (i = 0; i < 16; i++) {
+               host_ipv6[i] = ipv6[i] & netmask[i];
+       }
+
+       return;
+}
+
+void
+get_bcast_portion_ipv6(uint8_t host[], uint8_t netmask[], uint8_t bcast_ipv6[])
+{
+       int i;
+
+       for (i = 0; i < 16; i++) {
+               bcast_ipv6[i] = host[i] | ~netmask[i];
+       }
+
+       return;
+}
+
+int
+app_link_config_ipv6(struct app_params *app,
+                                uint32_t link_id, uint8_t ipv6[], uint32_t depth)
+{
+       struct app_link_params *p;
+       uint32_t i;
+       uint8_t netmask_ipv6[16], host[16], bcast[16];
+
+       /* Check input arguments */
+       if (app == NULL)
+               return -1;
+
+       APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, p);
+       if (p == NULL) {
+               APP_LOG(app, HIGH, "LINK%" PRIu32 " is not a valid link",
+                       link_id);
+               return -1;
+       }
+
+       if (p->state) {
+               APP_LOG(app, HIGH, "%s is UP, please bring it DOWN first",
+                       p->name);
+               return -1;
+       }
+
+       convert_prefixlen_to_netmask_ipv6(depth, netmask_ipv6);
+       get_host_portion_ipv6(ipv6, netmask_ipv6, host);
+       get_bcast_portion_ipv6(host, netmask_ipv6, bcast);
+
+       for (i = 0; i < app->n_links; i++) {
+               struct app_link_params *link = &app->link_params[i];
+
+               if (strcmp(p->name, link->name) == 0)
+                       continue;
+
+               if (!memcmp(link->ipv6, ipv6, 16)) {
+                       APP_LOG(app, HIGH,
+                               "%s is already assigned this IPv6 address",
+                               link->name);
+                       return -1;
+               }
+       }
+
+       if ((depth == 0) || (depth > 128)) {
+               APP_LOG(app, HIGH, "Illegal value for depth parameter "
+                       "(%" PRIu32 ")", depth);
+               return -1;
+       }
+
+       /* Save link parameters */
+       memcpy(p->ipv6, ipv6, 16);
+
+       p->depth_ipv6 = depth;
+/*
+        printf("IPv6: %x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x",
+                                       ipv6[0], ipv6[1], ipv6[2], ipv6[3], ipv6[4], ipv6[5],
+               ipv6[6], ipv6[7], ipv6[8], ipv6[9], ipv6[10], ipv6[11],
+               ipv6[12], ipv6[13], ipv6[14], ipv6[15]);
+*/
+        #ifndef VNF_ACL
+       if (ifm_add_ipv6_port(link_id, ipv6, depth) == IFM_FAILURE)
+               return -1;
+        #endif
+       return 0;
+}
+
+int
+app_link_up(struct app_params *app,
+       uint32_t link_id)
+{
+       struct app_link_params *p;
+
+       /* Check input arguments */
+       if (app == NULL)
+               return -1;
+
+       APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, p);
+       if (p == NULL) {
+               APP_LOG(app, HIGH, "LINK%" PRIu32 " is not a valid link",
+                       link_id);
+               return -1;
+       }
+
+       /* Check link state */
+       if (p->state) {
+               APP_LOG(app, HIGH, "%s is already UP", p->name);
+               return 0;
+       }
+
+       /* Check that IP address is valid */
+       uint8_t temp[16];
+
+       memset(temp, 0, 16);
+
+       if ((p->ip || memcmp(p->ipv6, temp, 16)) == 0) {
+               APP_LOG(app, HIGH, "%s IP address is not set", p->name);
+               return 0;
+       }
+
+       app_link_up_internal(app, p);
+
+       return 0;
+}
+
+int
+app_link_down(struct app_params *app,
+       uint32_t link_id)
+{
+       struct app_link_params *p;
+
+       /* Check input arguments */
+       if (app == NULL)
+               return -1;
+
+       APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, p);
+       if (p == NULL) {
+               APP_LOG(app, HIGH, "LINK%" PRIu32 " is not a valid link",
+                       link_id);
+               return -1;
+       }
+
+       /* Check link state */
+       if (p->state == 0) {
+               APP_LOG(app, HIGH, "%s is already DOWN", p->name);
+               return 0;
+       }
+
+       app_link_down_internal(app, p);
+
+       return 0;
+}
+
+/*
+ * ping
+ */
+
+struct cmd_ping_result {
+       cmdline_fixed_string_t p_string;
+       uint32_t pipeline_id;
+       cmdline_fixed_string_t ping_string;
+};
+
+static void
+cmd_ping_parsed(
+       void *parsed_result,
+       __rte_unused struct cmdline *cl,
+       void *data)
+{
+       struct cmd_ping_result *params = parsed_result;
+       struct app_params *app = data;
+       int status;
+
+       status = app_pipeline_ping(app, params->pipeline_id);
+       if (status != 0)
+               printf("Command failed\n");
+}
+
+cmdline_parse_token_string_t cmd_ping_p_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_ping_result, p_string, "p");
+
+cmdline_parse_token_num_t cmd_ping_pipeline_id =
+       TOKEN_NUM_INITIALIZER(struct cmd_ping_result, pipeline_id, UINT32);
+
+cmdline_parse_token_string_t cmd_ping_ping_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_ping_result, ping_string, "ping");
+
+cmdline_parse_inst_t cmd_ping = {
+       .f = cmd_ping_parsed,
+       .data = NULL,
+       .help_str = "Pipeline ping",
+       .tokens = {
+               (void *) &cmd_ping_p_string,
+               (void *) &cmd_ping_pipeline_id,
+               (void *) &cmd_ping_ping_string,
+               NULL,
+       },
+};
+
+/*
+ * stats port in
+ */
+
+struct cmd_stats_port_in_result {
+       cmdline_fixed_string_t p_string;
+       uint32_t pipeline_id;
+       cmdline_fixed_string_t stats_string;
+       cmdline_fixed_string_t port_string;
+       cmdline_fixed_string_t in_string;
+       uint32_t port_in_id;
+
+};
+static void
+cmd_stats_port_in_parsed(
+       void *parsed_result,
+       __rte_unused struct cmdline *cl,
+       void *data)
+{
+       struct cmd_stats_port_in_result *params = parsed_result;
+       struct app_params *app = data;
+       struct rte_pipeline_port_in_stats stats;
+       int status;
+
+       status = app_pipeline_stats_port_in(app,
+                       params->pipeline_id,
+                       params->port_in_id,
+                       &stats);
+
+       if (status != 0) {
+               printf("Command failed\n");
+               return;
+       }
+
+       /* Display stats */
+       printf("Pipeline %" PRIu32 " - stats for input port %" PRIu32 ":\n"
+               "\tPkts in: %" PRIu64 "\n"
+               "\tPkts dropped by AH: %" PRIu64 "\n"
+               "\tPkts dropped by other: %" PRIu64 "\n",
+               params->pipeline_id,
+               params->port_in_id,
+               stats.stats.n_pkts_in,
+               stats.n_pkts_dropped_by_ah,
+               stats.stats.n_pkts_drop);
+}
+
+cmdline_parse_token_string_t cmd_stats_port_in_p_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_stats_port_in_result, p_string,
+               "p");
+
+cmdline_parse_token_num_t cmd_stats_port_in_pipeline_id =
+       TOKEN_NUM_INITIALIZER(struct cmd_stats_port_in_result, pipeline_id,
+               UINT32);
+
+cmdline_parse_token_string_t cmd_stats_port_in_stats_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_stats_port_in_result, stats_string,
+               "stats");
+
+cmdline_parse_token_string_t cmd_stats_port_in_port_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_stats_port_in_result, port_string,
+               "port");
+
+cmdline_parse_token_string_t cmd_stats_port_in_in_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_stats_port_in_result, in_string,
+               "in");
+
+       cmdline_parse_token_num_t cmd_stats_port_in_port_in_id =
+       TOKEN_NUM_INITIALIZER(struct cmd_stats_port_in_result, port_in_id,
+               UINT32);
+
+cmdline_parse_inst_t cmd_stats_port_in = {
+       .f = cmd_stats_port_in_parsed,
+       .data = NULL,
+       .help_str = "Pipeline input port stats",
+       .tokens = {
+               (void *) &cmd_stats_port_in_p_string,
+               (void *) &cmd_stats_port_in_pipeline_id,
+               (void *) &cmd_stats_port_in_stats_string,
+               (void *) &cmd_stats_port_in_port_string,
+               (void *) &cmd_stats_port_in_in_string,
+               (void *) &cmd_stats_port_in_port_in_id,
+               NULL,
+       },
+};
+
+/*
+ * stats port out
+ */
+
+struct cmd_stats_port_out_result {
+       cmdline_fixed_string_t p_string;
+       uint32_t pipeline_id;
+       cmdline_fixed_string_t stats_string;
+       cmdline_fixed_string_t port_string;
+       cmdline_fixed_string_t out_string;
+       uint32_t port_out_id;
+};
+
+static void
+cmd_stats_port_out_parsed(
+       void *parsed_result,
+       __rte_unused struct cmdline *cl,
+       void *data)
+{
+
+       struct cmd_stats_port_out_result *params = parsed_result;
+       struct app_params *app = data;
+       struct rte_pipeline_port_out_stats stats;
+       int status;
+
+       status = app_pipeline_stats_port_out(app,
+                       params->pipeline_id,
+                       params->port_out_id,
+                       &stats);
+
+       if (status != 0) {
+               printf("Command failed\n");
+               return;
+       }
+
+       /* Display stats */
+       printf("Pipeline %" PRIu32 " - stats for output port %" PRIu32 ":\n"
+               "\tPkts in: %" PRIu64 "\n"
+               "\tPkts dropped by AH: %" PRIu64 "\n"
+               "\tPkts dropped by other: %" PRIu64 "\n",
+               params->pipeline_id,
+               params->port_out_id,
+               stats.stats.n_pkts_in,
+               stats.n_pkts_dropped_by_ah,
+               stats.stats.n_pkts_drop);
+}
+
+cmdline_parse_token_string_t cmd_stats_port_out_p_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_stats_port_out_result, p_string,
+       "p");
+
+cmdline_parse_token_num_t cmd_stats_port_out_pipeline_id =
+       TOKEN_NUM_INITIALIZER(struct cmd_stats_port_out_result, pipeline_id,
+               UINT32);
+
+cmdline_parse_token_string_t cmd_stats_port_out_stats_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_stats_port_out_result, stats_string,
+               "stats");
+
+cmdline_parse_token_string_t cmd_stats_port_out_port_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_stats_port_out_result, port_string,
+               "port");
+
+cmdline_parse_token_string_t cmd_stats_port_out_out_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_stats_port_out_result, out_string,
+               "out");
+
+cmdline_parse_token_num_t cmd_stats_port_out_port_out_id =
+       TOKEN_NUM_INITIALIZER(struct cmd_stats_port_out_result, port_out_id,
+               UINT32);
+
+cmdline_parse_inst_t cmd_stats_port_out = {
+       .f = cmd_stats_port_out_parsed,
+       .data = NULL,
+       .help_str = "Pipeline output port stats",
+       .tokens = {
+               (void *) &cmd_stats_port_out_p_string,
+               (void *) &cmd_stats_port_out_pipeline_id,
+               (void *) &cmd_stats_port_out_stats_string,
+               (void *) &cmd_stats_port_out_port_string,
+               (void *) &cmd_stats_port_out_out_string,
+               (void *) &cmd_stats_port_out_port_out_id,
+               NULL,
+       },
+};
+
+/*
+ * stats table
+ */
+
+struct cmd_stats_table_result {
+       cmdline_fixed_string_t p_string;
+       uint32_t pipeline_id;
+       cmdline_fixed_string_t stats_string;
+       cmdline_fixed_string_t table_string;
+       uint32_t table_id;
+};
+
+static void
+cmd_stats_table_parsed(
+       void *parsed_result,
+       __rte_unused struct cmdline *cl,
+       void *data)
+{
+       struct cmd_stats_table_result *params = parsed_result;
+       struct app_params *app = data;
+       struct rte_pipeline_table_stats stats;
+       int status;
+
+       status = app_pipeline_stats_table(app,
+                       params->pipeline_id,
+                       params->table_id,
+                       &stats);
+
+       if (status != 0) {
+               printf("Command failed\n");
+               return;
+       }
+
+       /* Display stats */
+       printf("Pipeline %" PRIu32 " - stats for table %" PRIu32 ":\n"
+               "\tPkts in: %" PRIu64 "\n"
+               "\tPkts in with lookup miss: %" PRIu64 "\n"
+               "\tPkts in with lookup hit dropped by AH: %" PRIu64 "\n"
+               "\tPkts in with lookup hit dropped by others: %" PRIu64 "\n"
+               "\tPkts in with lookup miss dropped by AH: %" PRIu64 "\n"
+               "\tPkts in with lookup miss dropped by others: %" PRIu64 "\n",
+               params->pipeline_id,
+               params->table_id,
+               stats.stats.n_pkts_in,
+               stats.stats.n_pkts_lookup_miss,
+               stats.n_pkts_dropped_by_lkp_hit_ah,
+               stats.n_pkts_dropped_lkp_hit,
+               stats.n_pkts_dropped_by_lkp_miss_ah,
+               stats.n_pkts_dropped_lkp_miss);
+}
+
+cmdline_parse_token_string_t cmd_stats_table_p_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_stats_table_result, p_string,
+               "p");
+
+cmdline_parse_token_num_t cmd_stats_table_pipeline_id =
+       TOKEN_NUM_INITIALIZER(struct cmd_stats_table_result, pipeline_id,
+               UINT32);
+
+cmdline_parse_token_string_t cmd_stats_table_stats_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_stats_table_result, stats_string,
+               "stats");
+
+cmdline_parse_token_string_t cmd_stats_table_table_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_stats_table_result, table_string,
+               "table");
+
+cmdline_parse_token_num_t cmd_stats_table_table_id =
+       TOKEN_NUM_INITIALIZER(struct cmd_stats_table_result, table_id, UINT32);
+
+cmdline_parse_inst_t cmd_stats_table = {
+       .f = cmd_stats_table_parsed,
+       .data = NULL,
+       .help_str = "Pipeline table stats",
+       .tokens = {
+               (void *) &cmd_stats_table_p_string,
+               (void *) &cmd_stats_table_pipeline_id,
+               (void *) &cmd_stats_table_stats_string,
+               (void *) &cmd_stats_table_table_string,
+               (void *) &cmd_stats_table_table_id,
+               NULL,
+       },
+};
+
+/*
+ * port in enable
+ */
+
+struct cmd_port_in_enable_result {
+       cmdline_fixed_string_t p_string;
+       uint32_t pipeline_id;
+       cmdline_fixed_string_t port_string;
+       cmdline_fixed_string_t in_string;
+       uint32_t port_in_id;
+       cmdline_fixed_string_t enable_string;
+};
+
+static void
+cmd_port_in_enable_parsed(
+       void *parsed_result,
+       __rte_unused struct cmdline *cl,
+       void *data)
+{
+       struct cmd_port_in_enable_result *params = parsed_result;
+       struct app_params *app = data;
+       int status;
+
+       status = app_pipeline_port_in_enable(app,
+                       params->pipeline_id,
+                       params->port_in_id);
+
+       if (status != 0)
+               printf("Command failed\n");
+}
+
+cmdline_parse_token_string_t cmd_port_in_enable_p_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_port_in_enable_result, p_string,
+               "p");
+
+cmdline_parse_token_num_t cmd_port_in_enable_pipeline_id =
+       TOKEN_NUM_INITIALIZER(struct cmd_port_in_enable_result, pipeline_id,
+               UINT32);
+
+cmdline_parse_token_string_t cmd_port_in_enable_port_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_port_in_enable_result, port_string,
+       "port");
+
+cmdline_parse_token_string_t cmd_port_in_enable_in_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_port_in_enable_result, in_string,
+               "in");
+
+cmdline_parse_token_num_t cmd_port_in_enable_port_in_id =
+       TOKEN_NUM_INITIALIZER(struct cmd_port_in_enable_result, port_in_id,
+               UINT32);
+
+cmdline_parse_token_string_t cmd_port_in_enable_enable_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_port_in_enable_result,
+               enable_string, "enable");
+
+cmdline_parse_inst_t cmd_port_in_enable = {
+       .f = cmd_port_in_enable_parsed,
+       .data = NULL,
+       .help_str = "Pipeline input port enable",
+       .tokens = {
+               (void *) &cmd_port_in_enable_p_string,
+               (void *) &cmd_port_in_enable_pipeline_id,
+               (void *) &cmd_port_in_enable_port_string,
+               (void *) &cmd_port_in_enable_in_string,
+               (void *) &cmd_port_in_enable_port_in_id,
+               (void *) &cmd_port_in_enable_enable_string,
+               NULL,
+       },
+};
+
+/*
+ * port in disable
+ */
+
+struct cmd_port_in_disable_result {
+       cmdline_fixed_string_t p_string;
+       uint32_t pipeline_id;
+       cmdline_fixed_string_t port_string;
+       cmdline_fixed_string_t in_string;
+       uint32_t port_in_id;
+       cmdline_fixed_string_t disable_string;
+};
+
+static void
+cmd_port_in_disable_parsed(
+       void *parsed_result,
+       __rte_unused struct cmdline *cl,
+       void *data)
+{
+       struct cmd_port_in_disable_result *params = parsed_result;
+       struct app_params *app = data;
+       int status;
+
+       status = app_pipeline_port_in_disable(app,
+                       params->pipeline_id,
+                       params->port_in_id);
+
+       if (status != 0)
+               printf("Command failed\n");
+}
+
+cmdline_parse_token_string_t cmd_port_in_disable_p_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_port_in_disable_result, p_string,
+               "p");
+
+cmdline_parse_token_num_t cmd_port_in_disable_pipeline_id =
+       TOKEN_NUM_INITIALIZER(struct cmd_port_in_disable_result, pipeline_id,
+               UINT32);
+
+cmdline_parse_token_string_t cmd_port_in_disable_port_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_port_in_disable_result, port_string,
+               "port");
+
+cmdline_parse_token_string_t cmd_port_in_disable_in_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_port_in_disable_result, in_string,
+               "in");
+
+cmdline_parse_token_num_t cmd_port_in_disable_port_in_id =
+       TOKEN_NUM_INITIALIZER(struct cmd_port_in_disable_result, port_in_id,
+               UINT32);
+
+cmdline_parse_token_string_t cmd_port_in_disable_disable_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_port_in_disable_result,
+               disable_string, "disable");
+
+cmdline_parse_inst_t cmd_port_in_disable = {
+       .f = cmd_port_in_disable_parsed,
+       .data = NULL,
+       .help_str = "Pipeline input port disable",
+       .tokens = {
+               (void *) &cmd_port_in_disable_p_string,
+               (void *) &cmd_port_in_disable_pipeline_id,
+               (void *) &cmd_port_in_disable_port_string,
+               (void *) &cmd_port_in_disable_in_string,
+               (void *) &cmd_port_in_disable_port_in_id,
+               (void *) &cmd_port_in_disable_disable_string,
+               NULL,
+       },
+};
+
+/*
+ * link config
+ */
+
+static void
+print_link_info(struct app_link_params *p)
+{
+       struct rte_eth_stats stats;
+       struct ether_addr *mac_addr;
+       uint32_t netmask = (~0U) << (32 - p->depth);
+       uint32_t host = p->ip & netmask;
+       uint32_t bcast = host | (~netmask);
+
+       memset(&stats, 0, sizeof(stats));
+       rte_eth_stats_get(p->pmd_id, &stats);
+
+       mac_addr = (struct ether_addr *) &p->mac_addr;
+
+       if (strlen(p->pci_bdf))
+               printf("%s(%s): flags=<%s>\n",
+                       p->name,
+                       p->pci_bdf,
+                       (p->state) ? "UP" : "DOWN");
+       else
+               printf("%s: flags=<%s>\n",
+                       p->name,
+                       (p->state) ? "UP" : "DOWN");
+
+       if (p->ip)
+               printf("\tinet %" PRIu32 ".%" PRIu32
+                       ".%" PRIu32 ".%" PRIu32
+                       " netmask %" PRIu32 ".%" PRIu32
+                       ".%" PRIu32 ".%" PRIu32 " "
+                       "broadcast %" PRIu32 ".%" PRIu32
+                       ".%" PRIu32 ".%" PRIu32 "\n",
+                       (p->ip >> 24) & 0xFF,
+                       (p->ip >> 16) & 0xFF,
+                       (p->ip >> 8) & 0xFF,
+                       p->ip & 0xFF,
+                       (netmask >> 24) & 0xFF,
+                       (netmask >> 16) & 0xFF,
+                       (netmask >> 8) & 0xFF,
+                       netmask & 0xFF,
+                       (bcast >> 24) & 0xFF,
+                       (bcast >> 16) & 0xFF,
+                       (bcast >> 8) & 0xFF,
+                       bcast & 0xFF);
+
+       printf("\tether %02" PRIx32 ":%02" PRIx32 ":%02" PRIx32
+               ":%02" PRIx32 ":%02" PRIx32 ":%02" PRIx32 "\n",
+               mac_addr->addr_bytes[0],
+               mac_addr->addr_bytes[1],
+               mac_addr->addr_bytes[2],
+               mac_addr->addr_bytes[3],
+               mac_addr->addr_bytes[4],
+               mac_addr->addr_bytes[5]);
+
+       printf("\tRX packets %" PRIu64
+               "  bytes %" PRIu64
+               "\n",
+               stats.ipackets,
+               stats.ibytes);
+
+       printf("\tRX errors %" PRIu64
+               "  missed %" PRIu64
+               "  no-mbuf %" PRIu64
+               "\n",
+               stats.ierrors,
+               stats.imissed,
+               stats.rx_nombuf);
+
+       printf("\tTX packets %" PRIu64
+               "  bytes %" PRIu64 "\n",
+               stats.opackets,
+               stats.obytes);
+
+       printf("\tTX errors %" PRIu64
+               "\n",
+               stats.oerrors);
+
+       printf("\n");
+}
+#endif
+struct cmd_link_config_result {
+       cmdline_fixed_string_t link_string;
+       uint32_t link_id;
+       cmdline_fixed_string_t config_string;
+       cmdline_ipaddr_t ip;
+       uint32_t depth;
+};
+
+static void
+cmd_link_config_parsed(
+       void *parsed_result,
+       __attribute__((unused)) struct cmdline *cl,
+        void *data)
+{
+       struct cmd_link_config_result *params = parsed_result;
+       struct app_params *app = data;
+       int status;
+
+       uint32_t link_id = params->link_id;
+       uint32_t ip;
+       uint8_t ipv6[16];
+       if (params->ip.family == AF_INET)
+               ip = rte_bswap32((uint32_t) params->ip.addr.ipv4.s_addr);
+       else
+               memcpy(ipv6, params->ip.addr.ipv6.s6_addr, 16);
+
+       uint32_t depth = params->depth;
+
+       if (params->ip.family == AF_INET)
+               status = app_link_config(app, link_id, ip, depth);
+       else
+               status = app_link_config_ipv6(app, link_id, ipv6, depth);
+
+       if (status)
+               printf("Command failed\n");
+       else {
+               struct app_link_params *p;
+
+               APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, p);
+               if (p)
+               print_link_info(p);
+       }
+}
+
+cmdline_parse_token_string_t cmd_link_config_link_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_link_config_result, link_string,
+               "link");
+
+cmdline_parse_token_num_t cmd_link_config_link_id =
+       TOKEN_NUM_INITIALIZER(struct cmd_link_config_result, link_id, UINT32);
+
+cmdline_parse_token_string_t cmd_link_config_config_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_link_config_result, config_string,
+               "config");
+
+cmdline_parse_token_ipaddr_t cmd_link_config_ip =
+       TOKEN_IPADDR_INITIALIZER(struct cmd_link_config_result, ip);
+
+cmdline_parse_token_num_t cmd_link_config_depth =
+       TOKEN_NUM_INITIALIZER(struct cmd_link_config_result, depth, UINT32);
+
+cmdline_parse_inst_t cmd_link_config = {
+       .f = cmd_link_config_parsed,
+       .data = NULL,
+       .help_str = "Link configuration",
+       .tokens = {
+               (void *)&cmd_link_config_link_string,
+               (void *)&cmd_link_config_link_id,
+               (void *)&cmd_link_config_config_string,
+               (void *)&cmd_link_config_ip,
+               (void *)&cmd_link_config_depth,
+               NULL,
+       },
+};
+
+/*
+ * link up
+ */
+
+struct cmd_link_up_result {
+       cmdline_fixed_string_t link_string;
+       uint32_t link_id;
+       cmdline_fixed_string_t up_string;
+};
+
+static void
+cmd_link_up_parsed(
+       void *parsed_result,
+       __attribute__((unused)) struct cmdline *cl,
+       void *data)
+{
+       struct cmd_link_up_result *params = parsed_result;
+       struct app_params *app = data;
+       int status;
+
+       status = app_link_up(app, params->link_id);
+       if (status != 0)
+               printf("Command failed\n");
+       else {
+               struct app_link_params *p;
+
+               APP_PARAM_FIND_BY_ID(app->link_params, "LINK", params->link_id,
+                       p);
+               if (p)
+               print_link_info(p);
+       }
+}
+
+cmdline_parse_token_string_t cmd_link_up_link_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_link_up_result, link_string,
+               "link");
+
+cmdline_parse_token_num_t cmd_link_up_link_id =
+       TOKEN_NUM_INITIALIZER(struct cmd_link_up_result, link_id, UINT32);
+
+cmdline_parse_token_string_t cmd_link_up_up_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_link_up_result, up_string, "up");
+
+cmdline_parse_inst_t cmd_link_up = {
+       .f = cmd_link_up_parsed,
+       .data = NULL,
+       .help_str = "Link UP",
+       .tokens = {
+               (void *)&cmd_link_up_link_string,
+               (void *)&cmd_link_up_link_id,
+               (void *)&cmd_link_up_up_string,
+               NULL,
+       },
+};
+
+/*
+ * link down
+ */
+
+struct cmd_link_down_result {
+       cmdline_fixed_string_t link_string;
+       uint32_t link_id;
+       cmdline_fixed_string_t down_string;
+};
+
+static void
+cmd_link_down_parsed(
+       void *parsed_result,
+       __attribute__((unused)) struct cmdline *cl,
+       void *data)
+{
+       struct cmd_link_down_result *params = parsed_result;
+       struct app_params *app = data;
+       int status;
+
+       status = app_link_down(app, params->link_id);
+       if (status != 0)
+               printf("Command failed\n");
+       else {
+               struct app_link_params *p;
+
+               APP_PARAM_FIND_BY_ID(app->link_params, "LINK", params->link_id,
+                       p);
+                 if (p)
+                       print_link_info(p);
+       }
+}
+
+cmdline_parse_token_string_t cmd_link_down_link_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_link_down_result, link_string,
+               "link");
+
+cmdline_parse_token_num_t cmd_link_down_link_id =
+       TOKEN_NUM_INITIALIZER(struct cmd_link_down_result, link_id, UINT32);
+
+cmdline_parse_token_string_t cmd_link_down_down_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_link_down_result, down_string,
+               "down");
+
+cmdline_parse_inst_t cmd_link_down = {
+       .f = cmd_link_down_parsed,
+       .data = NULL,
+       .help_str = "Link DOWN",
+       .tokens = {
+               (void *) &cmd_link_down_link_string,
+               (void *) &cmd_link_down_link_id,
+               (void *) &cmd_link_down_down_string,
+               NULL,
+       },
+};
+
+/*
+ * link ls
+ */
+
+struct cmd_link_ls_result {
+       cmdline_fixed_string_t link_string;
+       cmdline_fixed_string_t ls_string;
+};
+
+static void
+cmd_link_ls_parsed(
+       __attribute__((unused)) void *parsed_result,
+       __attribute__((unused)) struct cmdline *cl,
+        void *data)
+{
+       struct app_params *app = data;
+       uint32_t link_id;
+
+       for (link_id = 0; link_id < app->n_links; link_id++) {
+               struct app_link_params *p;
+
+               APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, p);
+                if (p)
+               print_link_info(p);
+       }
+       #ifndef VNF_ACL
+        print_interface_details();
+       #endif
+}
+
+cmdline_parse_token_string_t cmd_link_ls_link_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_link_ls_result, link_string,
+               "link");
+
+cmdline_parse_token_string_t cmd_link_ls_ls_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_link_ls_result, ls_string, "ls");
+
+cmdline_parse_inst_t cmd_link_ls = {
+       .f = cmd_link_ls_parsed,
+       .data = NULL,
+       .help_str = "Link list",
+       .tokens = {
+               (void *)&cmd_link_ls_link_string,
+               (void *)&cmd_link_ls_ls_string,
+               NULL,
+       },
+};
+
+/*
+ * quit
+ */
+
+struct cmd_quit_result {
+       cmdline_fixed_string_t quit;
+};
+
+static void
+cmd_quit_parsed(
+       __rte_unused void *parsed_result,
+       struct cmdline *cl,
+       __rte_unused void *data)
+{
+       cmdline_quit(cl);
+}
+
+static cmdline_parse_token_string_t cmd_quit_quit =
+       TOKEN_STRING_INITIALIZER(struct cmd_quit_result, quit, "quit");
+
+static cmdline_parse_inst_t cmd_quit = {
+       .f = cmd_quit_parsed,
+       .data = NULL,
+       .help_str = "Quit",
+       .tokens = {
+               (void *) &cmd_quit_quit,
+               NULL,
+       },
+};
+
+/*
+ * run
+ */
+
+static void
+app_run_file(
+       cmdline_parse_ctx_t *ctx,
+       const char *file_name)
+{
+       struct cmdline *file_cl;
+       int fd;
+
+       fd = open(file_name, O_RDONLY);
+       if (fd < 0) {
+               printf("Cannot open file \"%s\"\n", file_name);
+               return;
+       }
+
+       file_cl = cmdline_new(ctx, "", fd, 1);
+       cmdline_interact(file_cl);
+       close(fd);
+}
+
+struct cmd_run_file_result {
+       cmdline_fixed_string_t run_string;
+       char file_name[APP_FILE_NAME_SIZE];
+};
+
+static void
+cmd_run_parsed(
+       void *parsed_result,
+       struct cmdline *cl,
+       __attribute__((unused)) void *data)
+{
+       struct cmd_run_file_result *params = parsed_result;
+
+       app_run_file(cl->ctx, params->file_name);
+}
+
+cmdline_parse_token_string_t cmd_run_run_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_run_file_result, run_string,
+               "run");
+
+cmdline_parse_token_string_t cmd_run_file_name =
+       TOKEN_STRING_INITIALIZER(struct cmd_run_file_result, file_name, NULL);
+
+cmdline_parse_inst_t cmd_run = {
+       .f = cmd_run_parsed,
+       .data = NULL,
+       .help_str = "Run CLI script file",
+       .tokens = {
+               (void *) &cmd_run_run_string,
+               (void *) &cmd_run_file_name,
+               NULL,
+       },
+};
+
+static cmdline_parse_ctx_t pipeline_common_cmds[] = {
+       (cmdline_parse_inst_t *) &cmd_quit,
+       (cmdline_parse_inst_t *) &cmd_run,
+
+       (cmdline_parse_inst_t *) &cmd_link_config,
+       (cmdline_parse_inst_t *) &cmd_link_up,
+       (cmdline_parse_inst_t *) &cmd_link_down,
+       (cmdline_parse_inst_t *) &cmd_link_ls,
+
+       (cmdline_parse_inst_t *) &cmd_ping,
+       (cmdline_parse_inst_t *) &cmd_stats_port_in,
+       (cmdline_parse_inst_t *) &cmd_stats_port_out,
+       (cmdline_parse_inst_t *) &cmd_stats_table,
+       (cmdline_parse_inst_t *) &cmd_port_in_enable,
+       (cmdline_parse_inst_t *) &cmd_port_in_disable,
+       NULL,
+};
+
+int
+app_pipeline_common_cmd_push(struct app_params *app)
+{
+       uint32_t n_cmds, i;
+
+       /* Check for available slots in the application commands array */
+       n_cmds = RTE_DIM(pipeline_common_cmds) - 1;
+       if (n_cmds > APP_MAX_CMDS - app->n_cmds)
+               return -ENOMEM;
+
+       /* Push pipeline commands into the application */
+       memcpy(&app->cmds[app->n_cmds],
+               pipeline_common_cmds,
+               n_cmds * sizeof(cmdline_parse_ctx_t));
+
+       for (i = 0; i < n_cmds; i++)
+               app->cmds[app->n_cmds + i]->data = app;
+
+       app->n_cmds += n_cmds;
+       app->cmds[app->n_cmds] = NULL;
+
+       return 0;
+}
diff --git a/common/VIL/pipeline_common/pipeline_common_fe.h b/common/VIL/pipeline_common/pipeline_common_fe.h
new file mode 100644 (file)
index 0000000..fd53cc1
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef __INCLUDE_PIPELINE_COMMON_FE_H__
+#define __INCLUDE_PIPELINE_COMMON_FE_H__
+
+#include <rte_common.h>
+#include <rte_cycles.h>
+#include <rte_malloc.h>
+#include <cmdline_parse.h>
+
+#include "pipeline_common_be.h"
+#include "pipeline.h"
+#include "app.h"
+
+#ifndef MSG_TIMEOUT_DEFAULT
+#define MSG_TIMEOUT_DEFAULT                      1000
+#endif
+struct app_link_params mylink[APP_MAX_LINKS];
+static inline struct app_pipeline_data *
+app_pipeline_data(struct app_params *app, uint32_t id)
+{
+       struct app_pipeline_params *params;
+
+       APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", id, params);
+       if (params == NULL)
+               return NULL;
+
+       return &app->pipeline_data[params - app->pipeline_params];
+}
+
+static inline void *
+app_pipeline_data_fe(struct app_params *app, uint32_t id, struct pipeline_type *ptype)
+{
+       struct app_pipeline_data *pipeline_data;
+
+       pipeline_data = app_pipeline_data(app, id);
+       if (pipeline_data == NULL)
+               return NULL;
+
+       if (strcmp(pipeline_data->ptype->name, ptype->name) != 0)
+               return NULL;
+
+       if (pipeline_data->enabled == 0)
+               return NULL;
+
+       return pipeline_data->fe;
+}
+
+static inline struct rte_ring *
+app_pipeline_msgq_in_get(struct app_params *app,
+       uint32_t pipeline_id)
+{
+       struct app_msgq_params *p;
+
+       APP_PARAM_FIND_BY_ID(app->msgq_params,
+               "MSGQ-REQ-PIPELINE",
+               pipeline_id,
+               p);
+       if (p == NULL)
+               return NULL;
+
+       return app->msgq[p - app->msgq_params];
+}
+
+static inline struct rte_ring *
+app_pipeline_msgq_out_get(struct app_params *app,
+       uint32_t pipeline_id)
+{
+       struct app_msgq_params *p;
+
+       APP_PARAM_FIND_BY_ID(app->msgq_params,
+               "MSGQ-RSP-PIPELINE",
+               pipeline_id,
+               p);
+       if (p == NULL)
+               return NULL;
+
+       return app->msgq[p - app->msgq_params];
+}
+
+static inline void *
+app_msg_alloc(__rte_unused struct app_params *app)
+{
+       return rte_malloc(NULL, 2048, RTE_CACHE_LINE_SIZE);
+}
+
+static inline void
+app_msg_free(__rte_unused struct app_params *app,
+       void *msg)
+{
+       rte_free(msg);
+}
+
+static inline void
+app_msg_send(struct app_params *app,
+       uint32_t pipeline_id,
+       void *msg)
+{
+       struct rte_ring *r = app_pipeline_msgq_in_get(app, pipeline_id);
+       int status;
+
+       do {
+               status = rte_ring_sp_enqueue(r, msg);
+       } while (status == -ENOBUFS);
+}
+
+static inline void *
+app_msg_recv(struct app_params *app,
+       uint32_t pipeline_id)
+{
+       struct rte_ring *r = app_pipeline_msgq_out_get(app, pipeline_id);
+       void *msg;
+       int status = rte_ring_sc_dequeue(r, &msg);
+
+       if (status != 0)
+               return NULL;
+
+       return msg;
+}
+
+static inline void *
+app_msg_send_recv(struct app_params *app,
+       uint32_t pipeline_id,
+       void *msg,
+       uint32_t timeout_ms)
+{
+       struct rte_ring *r_req = app_pipeline_msgq_in_get(app, pipeline_id);
+       struct rte_ring *r_rsp = app_pipeline_msgq_out_get(app, pipeline_id);
+       uint64_t hz = rte_get_tsc_hz();
+       void *msg_recv = NULL;
+       uint64_t deadline;
+       int status = 0;
+
+       /* send */
+       do {
+                if(r_req)
+               status = rte_ring_sp_enqueue(r_req, (void *) msg);
+       } while (status == -ENOBUFS);
+
+       /* recv */
+       deadline = (timeout_ms) ?
+               (rte_rdtsc() + ((hz * timeout_ms) / 1000)) :
+               UINT64_MAX;
+
+       do {
+               if (rte_rdtsc() > deadline)
+                       return NULL;
+                 if (r_rsp)
+               status = rte_ring_sc_dequeue(r_rsp, &msg_recv);
+       } while (status != 0);
+
+       return msg_recv;
+}
+
+int
+app_pipeline_ping(struct app_params *app,
+       uint32_t pipeline_id);
+
+int
+app_pipeline_stats_port_in(struct app_params *app,
+       uint32_t pipeline_id,
+       uint32_t port_id,
+       struct rte_pipeline_port_in_stats *stats);
+
+int
+app_pipeline_stats_port_out(struct app_params *app,
+       uint32_t pipeline_id,
+       uint32_t port_id,
+       struct rte_pipeline_port_out_stats *stats);
+
+int
+app_pipeline_stats_table(struct app_params *app,
+       uint32_t pipeline_id,
+       uint32_t table_id,
+       struct rte_pipeline_table_stats *stats);
+
+int
+app_pipeline_port_in_enable(struct app_params *app,
+       uint32_t pipeline_id,
+       uint32_t port_id);
+
+int
+app_pipeline_port_in_disable(struct app_params *app,
+       uint32_t pipeline_id,
+       uint32_t port_id);
+
+int
+app_link_config(struct app_params *app,
+       uint32_t link_id,
+       uint32_t ip,
+       uint32_t depth);
+
+int
+app_link_up(struct app_params *app,
+       uint32_t link_id);
+
+int
+app_link_down(struct app_params *app,
+       uint32_t link_id);
+
+int
+app_pipeline_common_cmd_push(struct app_params *app);
+
+
+void convert_prefixlen_to_netmask_ipv6(uint32_t depth, uint8_t netmask_ipv6[]);
+
+void
+get_host_portion_ipv6(uint8_t ipv6[], uint8_t netmask[], uint8_t host_ipv6[]);
+
+void
+get_bcast_portion_ipv6(uint8_t host[], uint8_t netmask[], uint8_t bcast_ipv6[]);
+
+int
+app_link_config_ipv6(struct app_params *app,
+                                uint32_t link_id, uint8_t ipv6[], uint32_t depth);
+
+#endif
diff --git a/common/VIL/pipeline_loadb/pipeline_loadb.c b/common/VIL/pipeline_loadb/pipeline_loadb.c
new file mode 100644 (file)
index 0000000..fdcc17a
--- /dev/null
@@ -0,0 +1,493 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <cmdline_parse.h>
+#include <cmdline_parse_num.h>
+#include <cmdline_parse_string.h>
+#include <cmdline_parse_ipaddr.h>
+#include <cmdline_parse_etheraddr.h>
+
+#include "app.h"
+#include "pipeline_common_fe.h"
+#include "pipeline_loadb.h"
+#include "vnf_common.h"
+//#include "lib_arp.h"
+#include "pipeline_arpicmp_be.h"
+//#include "lib_arp.h"
+//#include "interface.h"
+static int
+app_pipeline_loadb_entry_dbg(struct app_params *app,
+                                        uint32_t pipeline_id, uint8_t *msg)
+{
+       struct pipeline_loadb_entry_dbg_msg_req *req;
+       struct pipeline_loadb_entry_dbg_msg_rsp *rsp;
+
+       /* Check input arguments */
+       if (app == NULL)
+               return -1;
+
+       /* Allocate and write request */
+       req = app_msg_alloc(app);
+       if (req == NULL)
+               return -1;
+
+       req->type = PIPELINE_MSG_REQ_CUSTOM;
+       req->subtype = PIPELINE_LOADB_MSG_REQ_ENTRY_DBG;
+       req->data[0] = msg[0];
+       req->data[1] = msg[1];
+
+       rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
+       if (rsp == NULL)
+               return -1;
+
+       /* Read response */
+       if (rsp->status) {
+               app_msg_free(app, rsp);
+               printf("Error rsp->status %d\n", rsp->status);
+               return -1;
+       }
+
+       /* Free response */
+       app_msg_free(app, rsp);
+
+       return 0;
+}
+
+/*
+ * entry dbg
+ */
+
+struct cmd_entry_dbg_result {
+       cmdline_fixed_string_t p_string;
+       uint32_t p;
+       cmdline_fixed_string_t entry_string;
+       cmdline_fixed_string_t dbg_string;
+       uint8_t cmd;
+       uint8_t d1;
+};
+
+static void
+cmd_entry_dbg_parsed(void *parsed_result,
+                                __rte_unused struct cmdline *cl, void *data)
+{
+       struct cmd_entry_dbg_result *params = parsed_result;
+       struct app_params *app = data;
+       uint8_t msg[2];
+       int status;
+
+       msg[0] = params->cmd;
+       msg[1] = params->d1;
+       status = app_pipeline_loadb_entry_dbg(app, params->p, msg);
+
+       if (status != 0) {
+               printf("Dbg Command failed\n");
+               return;
+       }
+}
+
+static cmdline_parse_token_string_t lb_cmd_entry_dbg_p_string =
+TOKEN_STRING_INITIALIZER(struct cmd_entry_dbg_result, p_string, "p");
+
+static cmdline_parse_token_num_t lb_cmd_entry_dbg_p =
+TOKEN_NUM_INITIALIZER(struct cmd_entry_dbg_result, p, UINT32);
+
+static cmdline_parse_token_string_t lb_cmd_entry_dbg_entry_string =
+TOKEN_STRING_INITIALIZER(struct cmd_entry_dbg_result,
+                        entry_string, "lbentry");
+
+static cmdline_parse_token_string_t lb_cmd_entry_dbg_dbg_string =
+TOKEN_STRING_INITIALIZER(struct cmd_entry_dbg_result, dbg_string,
+                        "dbg");
+
+static cmdline_parse_token_num_t lb_cmd_entry_dbg_cmd =
+TOKEN_NUM_INITIALIZER(struct cmd_entry_dbg_result, cmd, UINT8);
+
+static cmdline_parse_token_num_t lb_cmd_entry_dbg_d1 =
+TOKEN_NUM_INITIALIZER(struct cmd_entry_dbg_result, d1, UINT8);
+
+static cmdline_parse_inst_t lb_cmd_entry_dbg = {
+       .f = cmd_entry_dbg_parsed,
+       .data = NULL,
+       .help_str = "LOADB dbg cmd",
+       .tokens = {
+                        (void *)&lb_cmd_entry_dbg_p_string,
+                        (void *)&lb_cmd_entry_dbg_p,
+                        (void *)&lb_cmd_entry_dbg_entry_string,
+                        (void *)&lb_cmd_entry_dbg_dbg_string,
+                        (void *)&lb_cmd_entry_dbg_cmd,
+                        (void *)&lb_cmd_entry_dbg_d1,
+                        NULL,
+                        },
+};
+
+/*static void*/
+/*print_arp_entry(const struct app_pipeline_arp_icmp_arp_entry *entry)*/
+/*{*/
+/*     printf("(Port = %" PRIu32 ", IP = %" PRIu32 ".%" PRIu32*/
+/*             ".%" PRIu32 ".%" PRIu32 ") => "*/
+/*             "HWaddress = %02" PRIx32 ":%02" PRIx32 ":%02" PRIx32*/
+/*             ":%02" PRIx32 ":%02" PRIx32 ":%02" PRIx32 "\n",*/
+/*             entry->key.key.ipv4.port_id,*/
+/*             (entry->key.key.ipv4.ip >> 24) & 0xFF,*/
+/*             (entry->key.key.ipv4.ip >> 16) & 0xFF,*/
+/*             (entry->key.key.ipv4.ip >> 8) & 0xFF,*/
+/*             entry->key.key.ipv4.ip & 0xFF,*/
+
+/*             entry->macaddr.addr_bytes[0],*/
+/*             entry->macaddr.addr_bytes[1],*/
+/*             entry->macaddr.addr_bytes[2],*/
+/*             entry->macaddr.addr_bytes[3],*/
+/*             entry->macaddr.addr_bytes[4],*/
+/*             entry->macaddr.addr_bytes[5]);*/
+/*}*/
+
+#if 0
+/*
+ * arp add
+ */
+
+struct cmd_arp_add_result {
+       cmdline_fixed_string_t p_string;
+       uint32_t p;
+       cmdline_fixed_string_t arpadd_string;
+       uint32_t port_id;
+       cmdline_ipaddr_t ip;
+       struct ether_addr macaddr;
+
+};
+
+static void
+cmd_arp_add_parsed(void *parsed_result,
+                        __rte_unused struct cmdline *cl, __rte_unused void *data)
+{
+       struct cmd_arp_add_result *params = parsed_result;
+       uint8_t ipv6[16];
+
+/*     struct pipeline_arp_icmp_arp_key key;*/
+/*     key.type = PIPELINE_ARP_ICMP_ARP_IPV4;*/
+/*     key.key.ipv4.port_id = params->port_id;*/
+/*     key.key.ipv4.ip = rte_cpu_to_be_32(params->ip.addr.ipv4.s_addr);*/
+/*     populate_arp_entry(&req->macaddr, rte_bswap32(req->key.key.ipv4.ip),
+ * req->key.key.ipv4.port_id);
+ */
+       if (params->ip.family == AF_INET) {
+               populate_arp_entry(&params->macaddr,
+                                        rte_cpu_to_be_32(params->ip.addr.
+                                                               ipv4.s_addr),
+                                        params->port_id, STATIC_ARP);
+       } else {
+               memcpy(ipv6, params->ip.addr.ipv6.s6_addr, 16);
+               populate_nd_entry(&params->macaddr, ipv6, params->port_id, STATIC_ND);
+       }
+}
+
+static cmdline_parse_token_string_t cmd_arp_add_p_string =
+TOKEN_STRING_INITIALIZER(struct cmd_arp_add_result, p_string,
+                        "p");
+
+static cmdline_parse_token_num_t cmd_arp_add_p =
+TOKEN_NUM_INITIALIZER(struct cmd_arp_add_result, p, UINT32);
+
+static cmdline_parse_token_string_t cmd_arp_add_arp_string =
+TOKEN_STRING_INITIALIZER(struct cmd_arp_add_result, arpadd_string, "arpadd");
+
+static cmdline_parse_token_num_t cmd_arp_add_port_id =
+TOKEN_NUM_INITIALIZER(struct cmd_arp_add_result, port_id, UINT32);
+
+static cmdline_parse_token_ipaddr_t cmd_arp_add_ip =
+TOKEN_IPADDR_INITIALIZER(struct cmd_arp_add_result, ip);
+
+static cmdline_parse_token_etheraddr_t cmd_arp_add_macaddr =
+TOKEN_ETHERADDR_INITIALIZER(struct cmd_arp_add_result, macaddr);
+
+static cmdline_parse_inst_t cmd_arp_add = {
+       .f = cmd_arp_add_parsed,
+       .data = NULL,
+       .help_str = "ARP add",
+       .tokens = {
+                        (void *)&cmd_arp_add_p_string,
+                        (void *)&cmd_arp_add_p,
+                        (void *)&cmd_arp_add_arp_string,
+                        (void *)&cmd_arp_add_port_id,
+                        (void *)&cmd_arp_add_ip,
+                        (void *)&cmd_arp_add_macaddr,
+                        NULL,
+                        },
+};
+
+/*
+ * arp del
+ */
+
+struct cmd_arp_del_result {
+       cmdline_fixed_string_t p_string;
+       uint32_t p;
+       cmdline_fixed_string_t arp_string;
+       uint32_t port_id;
+       cmdline_ipaddr_t ip;
+};
+
+static void
+cmd_arp_del_parsed(void *parsed_result,
+                        __rte_unused struct cmdline *cl, __rte_unused void *data)
+{
+       struct cmd_arp_del_result *params = parsed_result;
+       uint8_t ipv6[16];
+
+/*     struct pipeline_arp_icmp_arp_key key;*/
+/*     key.type = PIPELINE_ARP_ICMP_ARP_IPV4;*/
+/*     key.key.ipv4.ip = rte_cpu_to_be_32(params->ip.addr.ipv4.s_addr);*/
+/*     key.key.ipv4.port_id = params->port_id;*/
+/*     remove_arp_entry(rte_bswap32(req->key.key.ipv4.ip),
+ * req->key.key.ipv4.port_id);
+ */
+       if (params->ip.family == AF_INET) {
+               remove_arp_entry(rte_cpu_to_be_32(params->ip.addr.ipv4.s_addr),
+                                params->port_id, NULL);
+       } else {
+               memcpy(ipv6, params->ip.addr.ipv6.s6_addr, 16);
+               remove_nd_entry_ipv6(ipv6, params->port_id);
+       }
+}
+
+static cmdline_parse_token_string_t cmd_arp_del_p_string =
+TOKEN_STRING_INITIALIZER(struct cmd_arp_del_result, p_string,
+                        "p");
+
+static cmdline_parse_token_num_t cmd_arp_del_p =
+TOKEN_NUM_INITIALIZER(struct cmd_arp_del_result, p, UINT32);
+
+static cmdline_parse_token_string_t cmd_arp_del_arp_string =
+TOKEN_STRING_INITIALIZER(struct cmd_arp_del_result, arp_string, "arpdel");
+
+static cmdline_parse_token_num_t cmd_arp_del_port_id =
+TOKEN_NUM_INITIALIZER(struct cmd_arp_del_result, port_id, UINT32);
+
+static cmdline_parse_token_ipaddr_t cmd_arp_del_ip =
+TOKEN_IPADDR_INITIALIZER(struct cmd_arp_del_result, ip);
+
+static cmdline_parse_inst_t cmd_arp_del = {
+       .f = cmd_arp_del_parsed,
+       .data = NULL,
+       .help_str = "ARP delete",
+       .tokens = {
+                        (void *)&cmd_arp_del_p_string,
+                        (void *)&cmd_arp_del_p,
+                        (void *)&cmd_arp_del_arp_string,
+                        (void *)&cmd_arp_del_port_id,
+                        (void *)&cmd_arp_del_ip,
+                        NULL,
+                        },
+};
+
+/*
+ * arp req
+ */
+
+/*Re-uses delete structures*/
+
+static void
+cmd_arp_req_parsed(void *parsed_result,
+                        __rte_unused struct cmdline *cl, __rte_unused void *data)
+{
+       struct cmd_arp_del_result *params = parsed_result;
+       /*struct app_params *app = data;*/
+
+       struct arp_key_ipv4 key;
+/*     int status;*/
+
+/*     key.type = ARP_IPV4;*/
+/*     key.key.ipv4.ip = rte_cpu_to_be_32(params->ip.addr.ipv4.s_addr);*/
+/*     key.key.ipv4.port_id = params->port_id;*/
+       key.ip = rte_cpu_to_be_32(params->ip.addr.ipv4.s_addr);
+       key.port_id = params->port_id;
+       key.filler1 = 0;
+       key.filler2 = 0;
+       key.filler3 = 0;
+
+       struct arp_entry_data *arp_data = retrieve_arp_entry(key);
+
+       if (arp_data) {
+               if (ARPICMP_DEBUG)
+                       printf("ARP entry exists for ip 0x%x, port %d\n",
+                                                params->ip.addr.ipv4.s_addr, params->port_id);
+               return;
+       }
+       /* else request an arp*/
+       if (ARPICMP_DEBUG)
+               printf("ARP - requesting arp for ip 0x%x, port %d\n",
+                                        params->ip.addr.ipv4.s_addr, params->port_id);
+       request_arp(params->port_id, params->ip.addr.ipv4.s_addr);
+       /*give pipeline number too*/
+}
+
+static cmdline_parse_token_string_t cmd_arp_req_string =
+TOKEN_STRING_INITIALIZER(struct cmd_arp_del_result, arp_string, "arpreq");
+
+static cmdline_parse_inst_t cmd_arp_req = {
+       .f = cmd_arp_req_parsed,
+       .data = NULL,
+       .help_str = "ARP request",
+       .tokens = {
+                        (void *)&cmd_arp_del_p_string,
+                        (void *)&cmd_arp_del_p,
+                        (void *)&cmd_arp_req_string,
+                        (void *)&cmd_arp_del_port_id,
+                        (void *)&cmd_arp_del_ip,
+                        NULL,
+                        },
+};
+
+/*
+ * arpicmp echo req
+ */
+
+/*Re-uses delete structures*/
+
+static void
+cmd_icmp_echo_req_parsed(void *parsed_result,
+                        __rte_unused struct cmdline *cl,
+                        __rte_unused void *data)
+{
+       struct cmd_arp_del_result *params = parsed_result;
+       struct rte_mbuf *pkt;
+       l2_phy_interface_t *port = (l2_phy_interface_t *) ifm_get_port((uint8_t)params->port_id);
+
+       if (ARPICMP_DEBUG)
+               printf("Echo Req Handler ip %x, port %d\n",
+                                        params->ip.addr.ipv4.s_addr, params->port_id);
+
+       pkt = request_echo(params->port_id, params->ip.addr.ipv4.s_addr);
+       port->transmit_single_pkt(port, pkt);
+}
+
+static cmdline_parse_token_string_t cmd_icmp_echo_req_string =
+TOKEN_STRING_INITIALIZER(struct cmd_arp_del_result, arp_string, "icmpecho");
+
+static cmdline_parse_inst_t cmd_icmp_echo_req = {
+       .f = cmd_icmp_echo_req_parsed,
+       .data = NULL,
+       .help_str = "ICMP echo request",
+       .tokens = {
+                        (void *)&cmd_arp_del_p_string,
+                        (void *)&cmd_arp_del_p,
+                        (void *)&cmd_icmp_echo_req_string,
+                        (void *)&cmd_arp_del_port_id,
+                        (void *)&cmd_arp_del_ip,
+                        NULL,
+                        },
+};
+
+/*
+ * arp ls
+ */
+
+struct cmd_arp_ls_result {
+       cmdline_fixed_string_t p_string;
+       uint32_t p;
+       cmdline_fixed_string_t arp_string;
+};
+
+static void
+cmd_arp_ls_parsed(__rte_unused void *parsed_result,
+                       __rte_unused struct cmdline *cl, __rte_unused void *data)
+{
+       printf("\nARP table ...\n");
+       printf("-------------\n");
+       print_arp_table();
+
+       printf
+                       ("............................................................\n");
+
+       printf("\nND IPv6 table:\n");
+       printf("--------------\n");
+       print_nd_table();
+}
+
+static cmdline_parse_token_string_t cmd_arp_ls_p_string =
+TOKEN_STRING_INITIALIZER(struct cmd_arp_ls_result, p_string,
+                        "p");
+
+static cmdline_parse_token_num_t cmd_arp_ls_p =
+TOKEN_NUM_INITIALIZER(struct cmd_arp_ls_result, p, UINT32);
+
+static cmdline_parse_token_string_t cmd_arp_ls_arp_string =
+TOKEN_STRING_INITIALIZER(struct cmd_arp_ls_result, arp_string,
+                        "arpls");
+
+static cmdline_parse_inst_t cmd_arp_ls = {
+       .f = cmd_arp_ls_parsed,
+       .data = NULL,
+       .help_str = "ARP list",
+       .tokens = {
+                        (void *)&cmd_arp_ls_p_string,
+                        (void *)&cmd_arp_ls_p,
+                        (void *)&cmd_arp_ls_arp_string,
+                        NULL,
+                        },
+};
+
+/*
+ * show ports info
+ */
+
+struct cmd_show_ports_info_result {
+       cmdline_fixed_string_t p_string;
+       uint32_t p;
+       cmdline_fixed_string_t arp_string;
+};
+
+static void
+cmd_show_ports_info_parsed(__rte_unused void *parsed_result,
+                                __rte_unused struct cmdline *cl,
+                                __rte_unused void *data)
+{
+       show_ports_info();
+}
+
+static cmdline_parse_token_string_t cmd_show_ports_info_string =
+TOKEN_STRING_INITIALIZER(struct cmd_arp_ls_result, arp_string,
+                        "showPortsInfo");
+
+static cmdline_parse_inst_t cmd_show_ports_info = {
+       .f = cmd_show_ports_info_parsed,
+       .data = NULL,
+       .help_str = "show ports info",
+       .tokens = {
+                        (void *)&cmd_arp_ls_p_string,
+                        (void *)&cmd_arp_ls_p,
+                        (void *)&cmd_show_ports_info_string,
+                        NULL,
+                        },
+};
+#endif
+
+static cmdline_parse_ctx_t pipeline_cmds[] = {
+       (cmdline_parse_inst_t *) &lb_cmd_entry_dbg,
+       NULL,
+};
+
+static struct pipeline_fe_ops pipeline_loadb_fe_ops = {
+       .f_init = NULL,
+       .f_free = NULL,
+       .cmds = pipeline_cmds,
+};
+
+struct pipeline_type pipeline_loadb = {
+       .name = "LOADB",
+       .be_ops = &pipeline_loadb_be_ops,
+       .fe_ops = &pipeline_loadb_fe_ops,
+};
diff --git a/common/VIL/pipeline_loadb/pipeline_loadb.h b/common/VIL/pipeline_loadb/pipeline_loadb.h
new file mode 100644 (file)
index 0000000..866a6ea
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef __INCLUDE_PIPELINE_LOADB_H__
+#define __INCLUDE_PIPELINE_LOADB_H__
+
+#include "pipeline.h"
+#include "pipeline_loadb_be.h"
+
+/*
+ * Pipeline type
+ */
+
+extern struct pipeline_type pipeline_loadb;
+
+#endif
diff --git a/common/VIL/pipeline_loadb/pipeline_loadb_be.c b/common/VIL/pipeline_loadb/pipeline_loadb_be.c
new file mode 100644 (file)
index 0000000..c791012
--- /dev/null
@@ -0,0 +1,1417 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <rte_common.h>
+#include <rte_malloc.h>
+#include <rte_ip.h>
+#include <rte_hash.h>
+#include <rte_byteorder.h>
+#include <rte_table_lpm.h>
+#include <rte_table_hash.h>
+#include <rte_jhash.h>
+#include <rte_thash.h>
+#include <rte_cycles.h>
+#include <rte_ethdev.h>
+#include <rte_prefetch.h>
+#include <rte_table_array.h>
+#include "pipeline_loadb_be.h"
+#include "pipeline_actions_common.h"
+#include "hash_func.h"
+#include "pipeline_arpicmp_be.h"
+#include "vnf_common.h"
+#include "app.h"
+
+#define BYTES_TO_BITS 8
+#define ROTATE_15_BITS 15
+
+#define MAX_VNF_THREADS 16
+
+int pkt_burst_cnt;
+
+uint8_t LOADB_DEBUG;
+uint8_t total_vnf_threads;
+uint32_t phyport_offset;
+
+struct pipeline_loadb {
+       struct pipeline p;
+       pipeline_msg_req_handler custom_handlers[PIPELINE_LOADB_MSG_REQS];
+
+       uint8_t n_vnf_threads;
+       uint8_t n_lb_tuples;
+       uint32_t outport_offset;
+       uint64_t receivedLBPktCount;
+       uint64_t droppedLBPktCount;
+       uint8_t links_map[PIPELINE_MAX_PORT_IN];
+       uint8_t outport_id[PIPELINE_MAX_PORT_IN];
+       uint8_t n_prv_Q;
+       uint8_t n_pub_Q;
+       uint8_t pipeline_num;
+} __rte_cache_aligned;
+
+uint8_t default_rss_key[] = {
+       0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a,
+       0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a,
+       0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a,
+       0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a,
+       0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a,
+};
+
+static void *pipeline_loadb_msg_req_custom_handler(struct pipeline *p,
+                                                        void *msg);
+
+static pipeline_msg_req_handler handlers[] = {
+       [PIPELINE_MSG_REQ_PING] =
+               pipeline_msg_req_ping_handler,
+       [PIPELINE_MSG_REQ_STATS_PORT_IN] =
+               pipeline_msg_req_stats_port_in_handler,
+       [PIPELINE_MSG_REQ_STATS_PORT_OUT] =
+               pipeline_msg_req_stats_port_out_handler,
+       [PIPELINE_MSG_REQ_STATS_TABLE] =
+               pipeline_msg_req_stats_table_handler,
+       [PIPELINE_MSG_REQ_PORT_IN_ENABLE] =
+               pipeline_msg_req_port_in_enable_handler,
+       [PIPELINE_MSG_REQ_PORT_IN_DISABLE] =
+               pipeline_msg_req_port_in_disable_handler,
+       [PIPELINE_MSG_REQ_CUSTOM] =
+               pipeline_loadb_msg_req_custom_handler,
+
+};
+
+static void *pipeline_loadb_msg_req_entry_dbg_handler(struct pipeline *,
+                                                                       void *msg);
+
+static pipeline_msg_req_handler custom_handlers[] = {
+       [PIPELINE_LOADB_MSG_REQ_ENTRY_DBG] =
+                       pipeline_loadb_msg_req_entry_dbg_handler,
+};
+
+/*
+ * LOADB table
+ */
+struct loadb_table_entry {
+       struct rte_pipeline_table_entry head;
+} __rte_cache_aligned;
+
+void *pipeline_loadb_msg_req_custom_handler(struct pipeline *p, void *msg)
+{
+       struct pipeline_loadb *p_lb = (struct pipeline_loadb *)p;
+       struct pipeline_custom_msg_req *req = msg;
+       pipeline_msg_req_handler f_handle;
+
+       f_handle = (req->subtype < PIPELINE_LOADB_MSG_REQS) ?
+                       p_lb->custom_handlers[req->subtype] :
+                       pipeline_msg_req_invalid_handler;
+
+       if (f_handle == NULL)
+               f_handle = pipeline_msg_req_invalid_handler;
+
+       return f_handle(p, req);
+}
+
+uint32_t lb_pkt_print_count;
+
+uint8_t calculate_lb_thread_prv(struct rte_mbuf *pkt, void *arg)
+{
+       uint32_t hash_key[2], hash_ipv4;
+       uint32_t temp1, temp2, temp3;
+       uint8_t thread;
+       struct pipeline_loadb_in_port_h_arg *ap = arg;
+       struct pipeline_loadb *p_loadb = (struct pipeline_loadb *) ap->p;
+       uint8_t nthreads = p_loadb->n_vnf_threads;
+       union rte_thash_tuple tuple;
+
+       uint32_t *src_addr;
+       uint32_t *dst_addr;
+       uint16_t *src_port;
+       uint16_t *dst_port;
+       uint8_t *protocol;
+       struct lb_pkt *lb_pkt = (struct lb_pkt *)
+                       RTE_MBUF_METADATA_UINT8_PTR(pkt, MBUF_HDR_ROOM);
+
+       if (rte_be_to_cpu_16(lb_pkt->eth.ether_type) == ETHER_TYPE_IPv6) {
+               src_addr = (uint32_t *)&lb_pkt->ipv6_port.ipv6.src_addr;
+               dst_addr = (uint32_t *)&lb_pkt->ipv6_port.ipv6.dst_addr;
+               src_port = &lb_pkt->ipv6_port.src_port;
+               dst_port = &lb_pkt->ipv6_port.dst_port;
+               protocol = &lb_pkt->ipv6_port.ipv6.proto;
+       } else {
+               src_addr = &lb_pkt->ipv4_port.ipv4.src_addr;
+               dst_addr = &lb_pkt->ipv4_port.ipv4.dst_addr;
+               src_port = &lb_pkt->ipv4_port.src_port;
+               dst_port = &lb_pkt->ipv4_port.dst_port;
+               protocol = &lb_pkt->ipv4_port.ipv4.next_proto_id;
+       }
+
+       switch (p_loadb->n_lb_tuples) {
+
+       case 0:
+               /* Write */
+               /* Egress */
+       if (rte_be_to_cpu_16(lb_pkt->eth.ether_type) == ETHER_TYPE_IPv6)
+               temp1 = rte_bswap32(dst_addr[3]) ^ *dst_port;
+       else
+               temp1 = *dst_addr ^ *dst_port;
+
+                       temp2 = (temp1 >> 24) ^ (temp1 >> 16) ^
+                               (temp1 >> 8) ^ temp1;
+
+                       temp3 = (temp2 >> 4) ^ (temp2 & 0xf);
+
+                       /* To select the thread */
+                       thread = temp3 % nthreads;
+                       /* To select the Q */
+                       thread = ap->in_port_id + (p_loadb->p.n_ports_in *
+                               (thread + 1) - p_loadb->p.n_ports_in);
+               return thread;
+
+       case 1:
+               /* Write */
+               /* Egress */
+               if (rte_be_to_cpu_16(lb_pkt->eth.ether_type) == ETHER_TYPE_IPv6)
+                       hash_key[0] = rte_bswap32(dst_addr[3]);
+               else
+                       hash_key[0] = rte_bswap32(*dst_addr);
+
+               /* Compute */
+               hash_ipv4 = rte_jhash(&hash_key[0], 4, 0);
+
+               /* To select the thread */
+               thread = (hash_ipv4 % nthreads);
+
+               /* To select the Q */
+               thread = ap->in_port_id + (p_loadb->p.n_ports_in *
+                               (thread + 1) - p_loadb->p.n_ports_in);
+
+               if (LOADB_DEBUG > 3)
+                       printf("thread: %u  hash: %x  hash_key: %x\n",
+                               thread, hash_ipv4, hash_key[0]);
+               return thread;
+
+       case 2:
+               /* Write */
+               /* Egress */
+               if (rte_be_to_cpu_16(lb_pkt->eth.ether_type) ==
+                       ETHER_TYPE_IPv6) {
+                       hash_key[0] = rte_bswap32(dst_addr[3]);
+                       hash_key[1] = *dst_port << 16;
+               } else{
+                       hash_key[0] = rte_bswap32(*dst_addr);
+                       hash_key[1] = *dst_port << 16;
+               }
+               /* Compute */
+               hash_ipv4 = rte_jhash(&hash_key[0], 6, 0);
+
+               /* To select the thread */
+               thread = (hash_ipv4 % nthreads);
+
+               /* To select the Q */
+               thread = ap->in_port_id + (p_loadb->p.n_ports_in *
+                               (thread + 1) - p_loadb->p.n_ports_in);
+
+               if (LOADB_DEBUG > 3) {
+                       printf("public_addr: %x public_port: %x\n",
+                               hash_key[0], *dst_port);
+                       printf("thread: %u  hash: %x  hash_key0: %x  "
+                               "hash_key1: %x\n", thread, hash_ipv4,
+                               hash_key[0], hash_key[1]);
+               }
+               return thread;
+
+       case 3:
+               printf("Invalid n_lb_tuples: %d\n", p_loadb->n_lb_tuples);
+               return 0;
+
+       case 4:
+               /* Write */
+               if (rte_be_to_cpu_16(lb_pkt->eth.ether_type) ==
+                       ETHER_TYPE_IPv6) {
+                       tuple.v4.src_addr = rte_bswap32(src_addr[3]);
+                       tuple.v4.dst_addr = rte_bswap32(dst_addr[3]);
+                       tuple.v4.sport = *src_port;
+                       tuple.v4.dport = *dst_port;
+               } else{
+                       tuple.v4.src_addr = rte_bswap32(*src_addr);
+                       tuple.v4.dst_addr = rte_bswap32(*dst_addr);
+                       tuple.v4.sport = *src_port;
+                       tuple.v4.dport = *dst_port;
+               }
+               /* Compute */
+               hash_ipv4 = rte_softrss((uint32_t *)&tuple,
+                               RTE_THASH_V4_L4_LEN,
+                               default_rss_key);
+               /* Egress */
+
+               /* To select the thread */
+               thread = (hash_ipv4 % nthreads);
+
+               /* To select the Q */
+               thread = ap->in_port_id + (p_loadb->p.n_ports_in *
+                               (thread + 1) - p_loadb->p.n_ports_in);
+
+               if (LOADB_DEBUG > 3) {
+                       printf("src_addr: %x dst_addr: %x src_port: %x "
+                       "dst_port: %x\n", tuple.v4.src_addr, tuple.v4.dst_addr,
+                       tuple.v4.sport, tuple.v4.dport);
+                       printf("thread: %u  hash: %x\n", thread, hash_ipv4);
+               }
+
+               return thread;
+
+       case 5:
+
+               if (rte_be_to_cpu_16(lb_pkt->eth.ether_type) ==
+                       ETHER_TYPE_IPv6) {
+                       /* point to last 32 bits of IPv6 addresses*/
+                       src_addr += 3;
+                       dst_addr += 3;
+               }
+
+               /* Compute */
+               temp1 = *src_addr ^ *dst_addr ^ *src_port ^
+                       *dst_port ^ *protocol;
+
+               temp2 = (temp1 >> 24) ^ (temp1 >> 16) ^ (temp1 >> 8) ^ temp1;
+               temp3 = (temp2 >> 4) ^ (temp2 & 0xf);
+
+               /* Egress */
+
+               /* To select the thread */
+               thread = (temp3 % nthreads);
+
+               /* To select the Q */
+               thread = ap->in_port_id + (p_loadb->p.n_ports_in *
+                               (thread + 1) - p_loadb->p.n_ports_in);
+
+               if (LOADB_DEBUG > 3) {
+                       printf("thread: %u  temp1: %x  temp2: %x  temp3: %x\n",
+                               thread, temp1, temp2, temp3);
+                       printf("src_addr: %x dst_addr: %x src_port: %x "
+                       "dst_port: %x protocol: %x\n", *src_addr, *dst_addr,
+                       *src_port, *dst_port, *protocol);
+               }
+               return thread;
+
+       default:
+               printf("Invalid n_lb_tuples: %d\n", p_loadb->n_lb_tuples);
+               return 0;
+
+       }
+}
+
+uint8_t calculate_lb_thread_pub(struct rte_mbuf *pkt, void *arg)
+{
+       uint32_t hash_key[2], hash_ipv4;
+       uint32_t temp1, temp2, temp3;
+       uint8_t thread;
+       struct pipeline_loadb_in_port_h_arg *ap = arg;
+       struct pipeline_loadb *p_loadb = (struct pipeline_loadb *) ap->p;
+       uint8_t nthreads = p_loadb->n_vnf_threads;
+       union rte_thash_tuple tuple;
+
+       uint32_t *src_addr;
+       uint32_t *dst_addr;
+       uint16_t *src_port;
+       uint16_t *dst_port;
+       uint8_t *protocol;
+       struct lb_pkt *lb_pkt = (struct lb_pkt *)
+                               RTE_MBUF_METADATA_UINT8_PTR(pkt,
+                                       MBUF_HDR_ROOM);
+
+       if (rte_be_to_cpu_16(lb_pkt->eth.ether_type) == ETHER_TYPE_IPv6) {
+               src_addr = (uint32_t *)&lb_pkt->ipv6_port.ipv6.src_addr;
+               dst_addr = (uint32_t *)&lb_pkt->ipv6_port.ipv6.dst_addr;
+               src_port = &lb_pkt->ipv6_port.src_port;
+               dst_port = &lb_pkt->ipv6_port.dst_port;
+               protocol = &lb_pkt->ipv6_port.ipv6.proto;
+       } else {
+               src_addr = &lb_pkt->ipv4_port.ipv4.src_addr;
+               dst_addr = &lb_pkt->ipv4_port.ipv4.dst_addr;
+               src_port = &lb_pkt->ipv4_port.src_port;
+               dst_port = &lb_pkt->ipv4_port.dst_port;
+               protocol = &lb_pkt->ipv4_port.ipv4.next_proto_id;
+       }
+
+       switch (p_loadb->n_lb_tuples) {
+
+       case 0:
+               /* Write */
+                                                /* Ingress */
+                       temp1 = *src_addr ^ *src_port;
+                       temp2 = (temp1 >> 24) ^ (temp1 >> 16) ^
+                               (temp1 >> 8) ^ temp1;
+                       temp3 = (temp2 >> 4) ^ (temp2 & 0xf);
+
+                       /* To select the thread */
+                       thread = temp3 % nthreads;
+                       /* To select the Q */
+                       thread = ap->in_port_id + (p_loadb->p.n_ports_in *
+                               (thread + 1) - p_loadb->p.n_ports_in);
+
+                       return thread;
+
+       case 1:
+               /* Write */
+                               /* Ingress */
+                       hash_key[0] = rte_bswap32(*src_addr);
+
+                       /* Compute */
+                       hash_ipv4 = rte_jhash(&hash_key[0], 4, 0);
+
+                       /* To select the thread */
+                       thread = hash_ipv4 % nthreads;
+                       /* To select the Q */
+                       thread = ap->in_port_id + (p_loadb->p.n_ports_in *
+                               (thread + 1) - p_loadb->p.n_ports_in);
+
+               if (LOADB_DEBUG > 3)
+                       printf("thread: %u  hash: %x  hash_key: %x\n",
+                               thread, hash_ipv4, hash_key[0]);
+               return thread;
+
+       case 2:
+               /* Write */
+                               /* Ingress */
+                       hash_key[0] = rte_bswap32(*src_addr);
+                       hash_key[1] = *src_port << 16;
+
+                       /* Compute */
+                       hash_ipv4 = rte_jhash(&hash_key[0], 6, 0);
+
+                       /* To select the thread */
+                       thread = hash_ipv4 % nthreads;
+                       /* To select the Q */
+                       thread = ap->in_port_id + (p_loadb->p.n_ports_in *
+                               (thread + 1) - p_loadb->p.n_ports_in);
+
+               if (LOADB_DEBUG > 3) {
+                       printf("thread: %u  hash: %x  hash_key0: %x  "
+                       "hash_key1: %x\n", thread, hash_ipv4,
+                       hash_key[0], hash_key[1]);
+                       printf("public_addr: %x public_port: %x\n",
+                       hash_key[0], *src_port);
+               }
+               return thread;
+
+       case 3:
+               printf("Invalid n_lb_tuples: %d\n", p_loadb->n_lb_tuples);
+               return 0;
+
+       case 4:
+               /* Write */
+               tuple.v4.src_addr = rte_bswap32(*src_addr);
+               tuple.v4.dst_addr = rte_bswap32(*dst_addr);
+               tuple.v4.sport = *src_port;
+               tuple.v4.dport = *dst_port;
+
+               /* Compute */
+               hash_ipv4 = rte_softrss((uint32_t *)&tuple,
+                               RTE_THASH_V4_L4_LEN, default_rss_key);
+
+                       /* Ingress */
+                       /* To select the thread */
+                       thread = hash_ipv4 % nthreads;
+                       /* To select the Q */
+                       thread = ap->in_port_id + (p_loadb->p.n_ports_in *
+                               (thread + 1) - p_loadb->p.n_ports_in);
+
+               if (LOADB_DEBUG > 3) {
+                       printf("src_addr: %x dst_addr: %x src_port: %x "
+                               "dst_port: %x\n", tuple.v4.src_addr,
+                       tuple.v4.dst_addr, tuple.v4.sport, tuple.v4.dport);
+
+                       printf("thread: %u  hash: %x\n", thread, hash_ipv4);
+               }
+               return thread;
+
+       case 5:
+
+               if (rte_be_to_cpu_16(lb_pkt->eth.ether_type) ==
+                       ETHER_TYPE_IPv6) {
+                       /* point to last 32 bits of IPv6 addresses*/
+                       src_addr += 3;
+                       dst_addr += 3;
+               }
+
+               /* Compute */
+               temp1 = *src_addr ^ *dst_addr ^ *src_port ^
+                       *dst_port ^ *protocol;
+               temp2 = (temp1 >> 24) ^ (temp1 >> 16) ^
+                       (temp1 >> 8) ^ temp1;
+               temp3 = (temp2 >> 4) ^ (temp2 & 0xf);
+
+                       /* To select the thread */
+                       thread = temp3 % nthreads;
+                       /* To select the Q */
+                       thread = ap->in_port_id + (p_loadb->p.n_ports_in *
+                               (thread + 1) - p_loadb->p.n_ports_in);
+
+               if (LOADB_DEBUG > 3) {
+                       printf("src_addr: %x dst_addr: %x src_port: %x "
+                       "dst_port: %x protocol: %x\n", *src_addr, *dst_addr,
+                       *src_port, *dst_port, *protocol);
+
+                       printf("thread: %u  temp1: %x  temp2: %x  temp3: %x\n",
+                               thread, temp1, temp2, temp3);
+               }
+
+               return thread;
+
+       default:
+               printf("Invalid n_lb_tuples: %d\n", p_loadb->n_lb_tuples);
+               return 0;
+
+       }
+}
+
+static inline void
+pkt_work_loadb_key_prv(
+       struct rte_mbuf *pkt,
+       __rte_unused uint32_t pkt_num,
+       void *arg)
+{
+       struct pipeline_loadb_in_port_h_arg *ap = arg;
+       struct pipeline_loadb *p_loadb = (struct pipeline_loadb *)ap->p;
+       uint32_t outport_offset = p_loadb->outport_offset;
+
+       struct lb_pkt *lb_pkt = (struct lb_pkt *)
+                               RTE_MBUF_METADATA_UINT8_PTR(pkt,
+                               MBUF_HDR_ROOM);
+       uint32_t *out_port = RTE_MBUF_METADATA_UINT32_PTR(pkt,
+                               outport_offset);
+
+       #ifdef MY_LOADB_DBG_PRINT
+       if (LOADB_DEBUG == 3)
+               printf("Start pkt_work_loadb_key\n");
+       #endif
+
+       if ((LOADB_DEBUG > 2) && (lb_pkt_print_count < 10)) {
+               print_pkt1(pkt);
+               lb_pkt_print_count++;
+               printf("\nEth Typ %x, Prot %x, ETH_TYPE_ARP %x, "
+                       "ETH_TYPE_IPV4 %x, IP_PROTOCOL_ICMP %x\n",
+                       rte_be_to_cpu_16(lb_pkt->eth.ether_type),
+                       lb_pkt->ipv4_port.ipv4.next_proto_id, ETH_TYPE_ARP,
+                       ETH_TYPE_IPV4, IP_PROTOCOL_ICMP);
+       }
+
+               /* Write */
+               *out_port = calculate_lb_thread_prv(pkt, arg);
+
+       p_loadb->receivedLBPktCount++;
+
+       #ifdef MY_LOADB_DBG_PRINT
+       if (LOADB_DEBUG == 3)
+               printf("End pkt_work_loadb_key\n");
+       #endif
+}
+
+static inline void
+pkt_work_loadb_key_pub(
+       struct rte_mbuf *pkt,
+       __rte_unused uint32_t pkt_num,
+       void *arg)
+{
+       struct pipeline_loadb_in_port_h_arg *ap = arg;
+       struct pipeline_loadb *p_loadb = (struct pipeline_loadb *)ap->p;
+       uint32_t outport_offset = p_loadb->outport_offset;
+
+       struct lb_pkt *lb_pkt = (struct lb_pkt *)
+                               RTE_MBUF_METADATA_UINT8_PTR(pkt,
+                               MBUF_HDR_ROOM);
+       uint32_t *out_port = RTE_MBUF_METADATA_UINT32_PTR(pkt,
+                               outport_offset);
+
+       #ifdef MY_LOADB_DBG_PRINT
+       if (LOADB_DEBUG == 3)
+               printf("Start pkt_work_loadb_key\n");
+       #endif
+
+       if ((LOADB_DEBUG > 2) && (lb_pkt_print_count < 10)) {
+               print_pkt1(pkt);
+               lb_pkt_print_count++;
+               printf("\nEth Typ %x, Prot %x, ETH_TYPE_ARP %x, "
+                       "ETH_TYPE_IPV4 %x, IP_PROTOCOL_ICMP %x\n",
+                       rte_be_to_cpu_16(lb_pkt->eth.ether_type),
+                       lb_pkt->ipv4_port.ipv4.next_proto_id, ETH_TYPE_ARP,
+                       ETH_TYPE_IPV4, IP_PROTOCOL_ICMP);
+       }
+
+               /* Write */
+               *out_port = calculate_lb_thread_pub(pkt, arg);
+
+       p_loadb->receivedLBPktCount++;
+#ifdef MY_LOADB_DBG_PRINT
+       if (LOADB_DEBUG == 3)
+               printf("End pkt_work_loadb_key\n");
+#endif
+}
+
+static inline void
+pkt4_work_loadb_key_prv(
+       struct rte_mbuf **pkt,
+       __rte_unused uint32_t pkt_num,
+       void *arg)
+{
+       struct pipeline_loadb_in_port_h_arg *ap = arg;
+       struct pipeline_loadb *p_loadb = (struct pipeline_loadb *)ap->p;
+       uint32_t outport_offset = p_loadb->outport_offset;
+
+       uint32_t *out_port0 = RTE_MBUF_METADATA_UINT32_PTR(pkt[0],
+                               outport_offset);
+       uint32_t *out_port1 = RTE_MBUF_METADATA_UINT32_PTR(pkt[1],
+                               outport_offset);
+       uint32_t *out_port2 = RTE_MBUF_METADATA_UINT32_PTR(pkt[2],
+                               outport_offset);
+       uint32_t *out_port3 = RTE_MBUF_METADATA_UINT32_PTR(pkt[3],
+                               outport_offset);
+
+       struct lb_pkt *lb_pkt0 = (struct lb_pkt *)
+                               RTE_MBUF_METADATA_UINT8_PTR(pkt[0],
+                                       MBUF_HDR_ROOM);
+       struct lb_pkt *lb_pkt1 = (struct lb_pkt *)
+                               RTE_MBUF_METADATA_UINT8_PTR(pkt[1],
+                                       MBUF_HDR_ROOM);
+       struct lb_pkt *lb_pkt2 = (struct lb_pkt *)
+                               RTE_MBUF_METADATA_UINT8_PTR(pkt[2],
+                                       MBUF_HDR_ROOM);
+       struct lb_pkt *lb_pkt3 = (struct lb_pkt *)
+                               RTE_MBUF_METADATA_UINT8_PTR(pkt[3],
+                                       MBUF_HDR_ROOM);
+
+       #ifdef MY_LOADB_DBG_PRINT
+       if (LOADB_DEBUG == 3)
+               printf("Start pkt4_work_loadb_key\n");
+       #endif
+
+       if ((LOADB_DEBUG > 2) && (lb_pkt_print_count < 10)) {
+               print_pkt1(pkt[0]);
+               lb_pkt_print_count++;
+
+               printf("\nEth Typ %x, Prot %x\n",
+                       rte_be_to_cpu_16(lb_pkt0->eth.ether_type),
+                       lb_pkt0->ipv4_port.ipv4.next_proto_id);
+
+               print_pkt1(pkt[1]);
+               lb_pkt_print_count++;
+
+               printf("\nEth Typ %x, Prot %x\n",
+                       rte_be_to_cpu_16(lb_pkt1->eth.ether_type),
+                       lb_pkt1->ipv4_port.ipv4.next_proto_id);
+
+               print_pkt1(pkt[2]);
+               lb_pkt_print_count++;
+
+               printf("\nEth Typ %x, Prot %x\n",
+                       rte_be_to_cpu_16(lb_pkt2->eth.ether_type),
+                       lb_pkt2->ipv4_port.ipv4.next_proto_id);
+
+               print_pkt1(pkt[3]);
+               lb_pkt_print_count++;
+
+               printf("\nEth Typ %x, Prot %x\n",
+                       rte_be_to_cpu_16(lb_pkt3->eth.ether_type),
+                       lb_pkt3->ipv4_port.ipv4.next_proto_id);
+       }
+               *out_port0 = calculate_lb_thread_prv(pkt[0], arg);
+               *out_port1 = calculate_lb_thread_prv(pkt[1], arg);
+               *out_port2 = calculate_lb_thread_prv(pkt[2], arg);
+               *out_port3 = calculate_lb_thread_prv(pkt[3], arg);
+
+       p_loadb->receivedLBPktCount += 4;
+
+       #ifdef MY_LOADB_DBG_PRINT
+       if (LOADB_DEBUG == 3)
+               printf("End pkt4_work_loadb_key\n");
+       #endif
+
+}
+
+static inline void
+pkt4_work_loadb_key_pub(
+       struct rte_mbuf **pkt,
+       __rte_unused uint32_t pkt_num,
+       void *arg)
+{
+       struct pipeline_loadb_in_port_h_arg *ap = arg;
+       struct pipeline_loadb *p_loadb = (struct pipeline_loadb *)ap->p;
+       uint32_t outport_offset = p_loadb->outport_offset;
+
+       uint32_t *out_port0 = RTE_MBUF_METADATA_UINT32_PTR(pkt[0],
+                               outport_offset);
+       uint32_t *out_port1 = RTE_MBUF_METADATA_UINT32_PTR(pkt[1],
+                               outport_offset);
+       uint32_t *out_port2 = RTE_MBUF_METADATA_UINT32_PTR(pkt[2],
+                               outport_offset);
+       uint32_t *out_port3 = RTE_MBUF_METADATA_UINT32_PTR(pkt[3],
+                               outport_offset);
+
+       struct lb_pkt *lb_pkt0 = (struct lb_pkt *)
+                               RTE_MBUF_METADATA_UINT8_PTR(pkt[0],
+                                       MBUF_HDR_ROOM);
+       struct lb_pkt *lb_pkt1 = (struct lb_pkt *)
+                               RTE_MBUF_METADATA_UINT8_PTR(pkt[1],
+                                       MBUF_HDR_ROOM);
+       struct lb_pkt *lb_pkt2 = (struct lb_pkt *)
+                               RTE_MBUF_METADATA_UINT8_PTR(pkt[2],
+                                       MBUF_HDR_ROOM);
+       struct lb_pkt *lb_pkt3 = (struct lb_pkt *)
+                               RTE_MBUF_METADATA_UINT8_PTR(pkt[3],
+                                       MBUF_HDR_ROOM);
+
+       #ifdef MY_LOADB_DBG_PRINT
+       if (LOADB_DEBUG == 3)
+               printf("Start pkt4_work_loadb_key\n");
+       #endif
+
+       if ((LOADB_DEBUG > 2) && (lb_pkt_print_count < 10)) {
+               print_pkt1(pkt[0]);
+               lb_pkt_print_count++;
+
+               printf("\nEth Typ %x, Prot %x\n",
+                       rte_be_to_cpu_16(lb_pkt0->eth.ether_type),
+                       lb_pkt0->ipv4_port.ipv4.next_proto_id);
+
+               print_pkt1(pkt[1]);
+               lb_pkt_print_count++;
+
+               printf("\nEth Typ %x, Prot %x\n",
+                       rte_be_to_cpu_16(lb_pkt1->eth.ether_type),
+                       lb_pkt1->ipv4_port.ipv4.next_proto_id);
+
+               print_pkt1(pkt[2]);
+               lb_pkt_print_count++;
+
+               printf("\nEth Typ %x, Prot %x\n",
+                       rte_be_to_cpu_16(lb_pkt2->eth.ether_type),
+                       lb_pkt2->ipv4_port.ipv4.next_proto_id);
+
+               print_pkt1(pkt[3]);
+               lb_pkt_print_count++;
+
+               printf("\nEth Typ %x, Prot %x\n",
+                       rte_be_to_cpu_16(lb_pkt3->eth.ether_type),
+                       lb_pkt3->ipv4_port.ipv4.next_proto_id);
+       }
+               *out_port0 = calculate_lb_thread_prv(pkt[0], arg);
+               *out_port1 = calculate_lb_thread_pub(pkt[1], arg);
+               *out_port2 = calculate_lb_thread_pub(pkt[2], arg);
+               *out_port3 = calculate_lb_thread_pub(pkt[3], arg);
+
+       p_loadb->receivedLBPktCount += 4;
+#ifdef MY_LOADB_DBG_PRINT
+       if (LOADB_DEBUG == 3)
+               printf("End pkt4_work_loadb_key\n");
+#endif
+
+}
+
+PIPELINE_LOADB_KEY_PORT_IN_AH(port_in_ah_loadb_key_prv,
+                               pkt_work_loadb_key_prv,
+                               pkt4_work_loadb_key_prv);
+
+PIPELINE_LOADB_KEY_PORT_IN_AH(port_in_ah_loadb_key_pub,
+                               pkt_work_loadb_key_pub,
+                               pkt4_work_loadb_key_pub);
+
+static int
+pipeline_loadb_parse_args(struct pipeline_loadb *p,
+                               struct pipeline_params *params)
+{
+       uint32_t outport_offset_present = 0;
+       uint32_t n_vnf_threads_present = 0;
+       uint32_t pktq_in_prv_present = 0;
+       uint32_t prv_que_handler_present = 0;
+       uint32_t prv_to_pub_map_present = 0;
+       uint8_t n_prv_in_port = 0;
+       uint32_t i;
+
+       /* Default number of tuples */
+       p->n_lb_tuples = 0;
+
+       if (LOADB_DEBUG > 2)
+               printf("LOADB pipeline_loadb_parse_args params->n_args: %d\n",
+                                        params->n_args);
+
+       for (i = 0; i < params->n_args; i++) {
+               char *arg_name = params->args_name[i];
+               char *arg_value = params->args_value[i];
+
+               if (LOADB_DEBUG > 2)
+                       printf("LOADB args[%d]: %s %d, %s\n", i, arg_name,
+                                                atoi(arg_value), arg_value);
+
+               /* outport_offset = 128 + 8 */
+               if (strcmp(arg_name, "outport_offset") == 0) {
+                       if (outport_offset_present)
+                               return -1;
+                       outport_offset_present = 1;
+
+                       p->outport_offset = atoi(arg_value);
+                       if (p->outport_offset <= 0) {
+                               printf("Outport_offset is invalid\n");
+                               return -1;
+                       }
+                       printf("outport_offset: 0x%x\n", p->outport_offset);
+                       continue;
+               }
+               /* n_vnf_threads = 4 */
+               if (strcmp(arg_name, "n_vnf_threads") == 0) {
+                       if (n_vnf_threads_present)
+                               return -1;
+                       n_vnf_threads_present = 1;
+
+                       p->n_vnf_threads = atoi(arg_value);
+
+                       total_vnf_threads += p->n_vnf_threads;
+
+                       if ((p->n_vnf_threads <= 0)
+                                       || (total_vnf_threads > MAX_VNF_THREADS)) {
+                               printf("n_vnf_threads : MIN->0 MAX->16\n");
+                               return -1;
+                       }
+                       printf("n_vnf_threads    : 0x%x\n", p->n_vnf_threads);
+                       printf("total_vnf_threads: 0x%x\n", total_vnf_threads);
+                       continue;
+               }
+
+                               /* pktq_in_prv */
+               if (strcmp(arg_name, "pktq_in_prv") == 0) {
+                       if (pktq_in_prv_present) {
+                               printf("Duplicate pktq_in_prv ... "
+                               "parse failed..\n\n");
+                               return -1;
+                       }
+                       pktq_in_prv_present = 1;
+
+                       int rxport = 0, j = 0;
+                       char phy_port_num[8];
+                       char *token = strtok(arg_value, "RXQ");
+                       while (token) {
+                               j = 0;
+                               while ((j < 7) && (token[j] != '.')) {
+                                       phy_port_num[j] = token[j];
+                                       j++;
+                               }
+                               phy_port_num[j] = '\0';
+                               rxport =  atoi(phy_port_num);
+                               printf("token: %s, phy_port_str: %s, "
+                                       "phy_port_num %d\n",
+                               token, phy_port_num, rxport);
+                               prv_in_port_a[n_prv_in_port++] = rxport;
+                               // set rxport egress
+                               if (rxport < 0xff){
+                                       if(rxport < PIPELINE_MAX_PORT_IN)
+                                       in_port_dir_a[rxport] = 1;
+                                }
+                               token = strtok(NULL, "RXQ");
+                       }
+
+                       if (n_prv_in_port == 0) {
+                               printf("VNF common parse error - "
+                               "no prv RX phy port\n");
+                               return -1;
+                       }
+                       continue;
+               }
+
+                               /* pktq_in_prv_handler */
+
+               if (strcmp(arg_name, "prv_que_handler") == 0) {
+
+                       if (prv_que_handler_present) {
+                               printf("Duplicate pktq_in_prv ..\n\n");
+                               return -1;
+                       }
+                       prv_que_handler_present = 1;
+                       n_prv_in_port = 0;
+
+                       char *token;
+                       int rxport = 0;
+                       /* get the first token */
+                       token = strtok(arg_value, "(");
+                       token = strtok(token, ")");
+                       token = strtok(token, ",");
+                       printf("***** prv_que_handler *****\n");
+                        if (token)
+                                                                               printf("string is :%s\n", token);
+
+                       if (token)
+                               //printf("string is null\n");
+                       printf("string is :%s\n", token);
+
+                       /* walk through other tokens */
+                       while (token != NULL) {
+                               printf(" %s\n", token);
+                               rxport =  atoi(token);
+                               prv_que_port_index[n_prv_in_port++] = rxport;
+                               if (rxport < 0xff){
+                                  if(rxport < PIPELINE_MAX_PORT_IN)
+                                       in_port_egress_prv[rxport] = 1;
+                                }
+                               p->n_prv_Q++;
+                               token = strtok(NULL, ",");
+                       }
+
+                       if (n_prv_in_port == 0) {
+                       printf("VNF common parse err - no prv RX phy port\n");
+                       return -1;
+                       }
+
+                       continue;
+                       }
+               /* prv_to_pub_map */
+               if (strcmp(arg_name, "prv_to_pub_map") == 0) {
+                       if (prv_to_pub_map_present) {
+                               printf("Duplicated prv_to_pub_map ... "
+                                       "parse failed ...\n");
+                               return -1;
+                       }
+                       prv_to_pub_map_present = 1;
+
+                        int rxport = 0, txport = 0, j = 0, k = 0;
+                        char rx_phy_port_num[5];
+                        char tx_phy_port_num[5];
+                        char *token = strtok(arg_value, "(");
+                       while (token) {
+                               j = 0;
+                               while ((j < 4) && (token[j] != ',')) {
+                                       rx_phy_port_num[j] = token[j];
+                                       j++;
+                               }
+                               rx_phy_port_num[j] = '\0';
+                               rxport =  atoi(rx_phy_port_num);
+
+                               j++;
+                               k = 0;
+                               while ((k < 4) && (token[j+k] != ')')) {
+                                       tx_phy_port_num[k] = token[j+k];
+                                       k++;
+                               }
+                                tx_phy_port_num[k] = '\0';
+                                txport =  atoi(tx_phy_port_num);
+
+                       printf("token: %s,rx_phy_port_str: %s, phy_port_num "
+                       "%d, tx_phy_port_str: %s, tx_phy_port_num %d\n",
+                       token, rx_phy_port_num, rxport,
+                       tx_phy_port_num, txport);
+                         if(rxport < PIPELINE_MAX_PORT_IN)
+                       if ((rxport >= PIPELINE_MAX_PORT_IN) ||
+                               (txport >= PIPELINE_MAX_PORT_IN) ||
+                               (in_port_dir_a[rxport] != 1)) {
+                               printf("CG-NAPT parse error - "
+                               "incorrect prv-pub translation. Rx %d, "
+                               "Tx %d, Rx Dir %d\n", rxport, txport,
+                               in_port_dir_a[rxport]);
+
+                               return -1;
+                       }
+                       if (rxport < 0xff){
+                              if (rxport < PIPELINE_MAX_PORT_IN)
+                               prv_to_pub_map[rxport] = txport;
+                                                }
+                       if (txport < 0xff)
+                            if(txport < PIPELINE_MAX_PORT_IN)
+                               pub_to_prv_map[txport] = rxport;
+                       token = strtok(NULL, "(");
+               }
+
+                       continue;
+               }
+               /* Set number of tuples if available in config file */
+               if (strcmp(arg_name, "n_lb_tuples") == 0) {
+                       p->n_lb_tuples = atoi(arg_value);
+                       printf("n_lb_tuples: 0x%x\n", p->n_lb_tuples);
+               }
+
+               /* loadb_debug */
+               if (strcmp(arg_name, "loadb_debug") == 0) {
+                       LOADB_DEBUG = atoi(arg_value);
+                       continue;
+               }
+
+               /* any other Unknown argument return -1 */
+       }                       /* for */
+
+       /* Check that mandatory arguments are present */
+       if ((n_vnf_threads_present == 0) || (outport_offset_present == 0))
+               return -1;
+
+       return 0;
+
+}
+
+int check_loadb_thread(
+       struct app_params *app,
+       struct pipeline_params *params,
+       int32_t n_vnf_threads)
+{
+       uint32_t i;
+       int pipeline_num = 0;
+       int count = 0;
+       int dont_care = sscanf(params->name, "PIPELINE%d", &pipeline_num);
+       if (dont_care != 1)
+               return -1;
+       /* changed from pipeline_num+1 to +2 */
+       for (i = pipeline_num + 2; i < app->n_pipelines; i++) {
+               struct app_pipeline_params *p = &app->pipeline_params[i];
+               if (!strncmp(p->type, "LOADB", strlen(p->type)))
+                       break;
+               count++;
+       }
+       if (n_vnf_threads != count)
+               return -1;
+       return 0;
+
+}
+
+static void *pipeline_loadb_init(
+       struct pipeline_params *params,
+       __rte_unused void *arg)
+       /* arg is app parameter (struct app_params *app) */
+       /*save it for use in port in handler */
+{
+       struct pipeline *p;
+       struct pipeline_loadb *p_loadb;
+       uint32_t size, i, in_ports_arg_size;
+
+       /* Check input arguments */
+       if ((params == NULL) ||
+                       (params->n_ports_in == 0) || (params->n_ports_out == 0))
+               return NULL;
+
+       /* Memory allocation */
+       size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct pipeline_loadb));
+       p = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
+       p_loadb = (struct pipeline_loadb *)p;
+       if (p == NULL)
+               return NULL;
+
+       strcpy(p->name, params->name);
+       p->log_level = params->log_level;
+
+       PLOG(p, HIGH, "LOADB");
+
+       p_loadb->n_vnf_threads = 0;
+       p_loadb->outport_offset = 0;
+       p_loadb->receivedLBPktCount = 0;
+       p_loadb->droppedLBPktCount = 0;
+       for (i = 0; i < PIPELINE_MAX_PORT_IN; i++) {
+               p_loadb->links_map[i] = 0xff;
+       }
+       p_loadb->pipeline_num = 0xff;
+       p_loadb->n_prv_Q = 0;
+       p_loadb->n_pub_Q = 0;
+
+       /* Parse arguments */
+
+       if (pipeline_loadb_parse_args(p_loadb, params))
+               return NULL;
+
+       /* Pipeline */
+       {
+               struct rte_pipeline_params pipeline_params = {
+                       .name = "LOADB",
+                       .socket_id = params->socket_id,
+                       .offset_port_id = 0,
+               };
+
+               p->p = rte_pipeline_create(&pipeline_params);
+               if (p->p == NULL) {
+                       rte_free(p);
+                       return NULL;
+               }
+
+               printf("Loadb p->p %p, socket %d\n", p->p,
+                                        pipeline_params.socket_id);
+       }
+
+       /* Memory allocation for in_port_h_arg */
+       in_ports_arg_size =
+                       RTE_CACHE_LINE_ROUNDUP((sizeof(struct pipeline_loadb_in_port_h_arg))
+                                        * (params->n_ports_in));
+       struct pipeline_loadb_in_port_h_arg *ap =
+                       (struct pipeline_loadb_in_port_h_arg *)
+               rte_zmalloc(NULL,
+                       in_ports_arg_size,
+                       RTE_CACHE_LINE_SIZE);
+       if (ap == NULL)
+               return NULL;
+
+       printf("ap pointer %p\n", ap);
+
+       /* Input ports */
+       p->n_ports_in = params->n_ports_in;
+       for (i = 0; i < p->n_ports_in; i++) {
+               /* passing our loadb pipeline in call back arg */
+               (ap[i]).p = p_loadb;
+               (ap[i]).in_port_id = i;
+
+               struct rte_pipeline_port_in_params port_params = {
+                       .ops =
+                                       pipeline_port_in_params_get_ops(&params->port_in
+                                                                       [i]),
+                       .arg_create =
+                                       pipeline_port_in_params_convert(&params->port_in
+                                                                       [i]),
+               /* Public in-port handler */
+                       .f_action = NULL,
+                       .arg_ah = &(ap[i]),
+                       .burst_size = params->port_in[i].burst_size,
+               };
+
+               /* Private in-port handler */
+               if (is_port_index_privte(i)) {/* Multiport changes*/
+                       printf("LOADB %d port is Prv\n", i);
+                       port_params.f_action = port_in_ah_loadb_key_prv;
+               } else{
+                       printf("LOADB %d port is Pub\n", i);
+                       port_params.f_action = port_in_ah_loadb_key_pub;
+               }
+
+               int status = rte_pipeline_port_in_create(p->p,
+                                                        &port_params,
+                                                        &p->port_in_id[i]);
+
+               if (status) {
+                       rte_pipeline_free(p->p);
+                       rte_free(p);
+                       return NULL;
+               }
+
+       }
+
+               p_loadb->n_pub_Q = p_loadb->p.n_ports_in - p_loadb->n_prv_Q;
+               printf("LOADB : n_prv_Q - %d  n_pub_Q - %d\n",
+                               p_loadb->n_prv_Q, p_loadb->n_pub_Q);
+
+               for (i = 0; i <  p->n_ports_in; i++) {
+                       printf("is_port_index_privte(%d): %d\n", i,
+                               is_port_index_privte(i));
+                       printf("is_phy_port_privte(%d): %d\n", i,
+                               is_phy_port_privte(i));
+                       printf("action handler of %d:%p\n", i,
+                               p_loadb->p.p->ports_in[i].f_action);
+               }
+
+       /* Output ports */
+       p->n_ports_out = params->n_ports_out;
+       for (i = 0; i < p->n_ports_out; i++) {
+               struct rte_pipeline_port_out_params port_params = {
+                       .ops =
+                                       pipeline_port_out_params_get_ops(&params->port_out
+                                                                        [i]),
+                       .arg_create =
+                                       pipeline_port_out_params_convert(&params->port_out
+                                                                        [i]),
+                       .f_action = NULL,
+                       .arg_ah = NULL,
+               };
+
+               int status = rte_pipeline_port_out_create(p->p,
+                                                               &port_params,
+                                                               &p->port_out_id[i]);
+
+               if (status) {
+                       rte_pipeline_free(p->p);
+                       rte_free(p);
+                       return NULL;
+               }
+
+               printf("Outport p->port_out_id[%d] %p\n", i,
+                                        &p->port_out_id[i]);
+       }
+
+       int pipeline_num = 0;
+       int dont_care = sscanf(params->name, "PIPELINE%d", &pipeline_num);
+       if (dont_care != 1) {
+               printf("Unable to read pipeline number\n");
+               return NULL;
+       }
+       p_loadb->pipeline_num = pipeline_num;
+#if 0
+       set_outport_id(pipeline_num, p, lb_outport_id);
+       set_phy_outport_map(pipeline_num, p_loadb->links_map);
+
+       set_port_to_loadb_map(pipeline_num);
+
+       register_loadb_to_arp(pipeline_num, p, app);
+#endif
+       register_pipeline_Qs(p_loadb->pipeline_num, p);
+       set_link_map(p_loadb->pipeline_num, p, p_loadb->links_map);
+       //set_outport_id(p_loadb->pipeline_num, p, p_loadb->outport_id);
+
+       /* Tables */
+       p->n_tables = 1;
+       {
+
+               struct rte_table_array_params table_array_params = {
+                       .n_entries = MAX_VNF_THREADS,
+                       .offset = p_loadb->outport_offset,
+               };
+               struct rte_pipeline_table_params table_params = {
+                       .ops = &rte_table_array_ops,
+                       .arg_create = &table_array_params,
+                       .f_action_hit = NULL,
+                       .f_action_miss = NULL,
+                       .arg_ah = p_loadb,
+                       .action_data_size = 0,
+               };
+
+               int status;
+
+               status = rte_pipeline_table_create(p->p,
+                                                        &table_params,
+                                                        &p->table_id[0]);
+
+               if (status) {
+                       rte_pipeline_free(p->p);
+                       rte_free(p);
+                       return NULL;
+               }
+       }                       /* Tables */
+
+       /* Connecting input ports to tables */
+       for (i = 0; i < p->n_ports_in; i++) {
+               int status = rte_pipeline_port_in_connect_to_table(
+                               p->p,
+                               p->port_in_id[i],
+                               p->table_id[0]);
+
+               if (status) {
+                       rte_pipeline_free(p->p);
+                       rte_free(p);
+                       return NULL;
+               }
+       }
+
+       /* Enable input ports */
+       for (i = 0; i < p->n_ports_in; i++) {
+               int status = rte_pipeline_port_in_enable(p->p,
+                                                        p->port_in_id[i]);
+
+               if (status) {
+                       rte_pipeline_free(p->p);
+                       rte_free(p);
+                       return NULL;
+               }
+       }
+
+       /* Initialize table entries */
+       {
+               for (i = 0; i < MAX_VNF_THREADS; i++) {
+                       struct rte_table_array_key key = {
+                               .pos = i,
+                       };
+                       struct loadb_table_entry entry;
+                       entry.head.action = RTE_PIPELINE_ACTION_PORT;
+
+                       if (i < p->n_ports_out) {
+                               entry.head.port_id = p->port_out_id[i];
+                               printf("\ni %d, p->port_out_id[%d] %d", i, i,
+                                               p->port_out_id[i]);
+                       } else {
+                               /* First CGNAPT thread */
+                               entry.head.port_id = p->port_out_id[0];
+                               entry.head.action = RTE_PIPELINE_ACTION_DROP;
+                       }
+
+                       struct rte_pipeline_table_entry *entry_ptr;
+                       int key_found, status;
+                       status = rte_pipeline_table_entry_add(
+                                       p->p,
+                                       p->table_id[0],
+                                       &key,
+                                       (struct rte_pipeline_table_entry *)
+                                       &entry,
+                                       &key_found,
+                                       &entry_ptr);
+                       if (status) {
+                               rte_pipeline_free(p->p);
+                               rte_free(p);
+                               return NULL;
+                       }
+               }
+       }
+       /* Add default entry to tables */
+       {
+               struct rte_pipeline_table_entry default_entry = {
+                       .action = RTE_PIPELINE_ACTION_PORT,
+                       /* LB by default forward to 1st cgnat thread */
+                       .port_id = p->port_out_id[0],
+               };
+
+               struct rte_pipeline_table_entry *default_entry_ptr;
+
+               int status = rte_pipeline_table_default_entry_add(
+                               p->p,
+                               p->table_id[0],
+                               &default_entry,
+                               &default_entry_ptr);
+
+               if (status) {
+                       rte_pipeline_free(p->p);
+                       rte_free(p);
+                       return NULL;
+               }
+
+       }
+
+       /* Check pipeline consistency */
+       if (rte_pipeline_check(p->p) < 0) {
+               rte_pipeline_free(p->p);
+               rte_free(p);
+               return NULL;
+       }
+
+       /* Message queues */
+       p->n_msgq = params->n_msgq;
+       for (i = 0; i < p->n_msgq; i++)
+               p->msgq_in[i] = params->msgq_in[i];
+       for (i = 0; i < p->n_msgq; i++)
+               p->msgq_out[i] = params->msgq_out[i];
+
+       /* Message handlers */
+       memcpy(p->handlers, handlers, sizeof(p->handlers));
+       memcpy(p_loadb->custom_handlers,
+                                custom_handlers, sizeof(p_loadb->custom_handlers));
+
+       return p;
+}
+
+static int pipeline_loadb_free(void *pipeline)
+{
+       struct pipeline *p = (struct pipeline *)pipeline;
+
+       /* Check input arguments */
+       if (p == NULL)
+               return -1;
+
+       /* Free resources */
+       rte_pipeline_free(p->p);
+       rte_free(p);
+       return 0;
+}
+
+static int
+pipeline_loadb_track(void *pipeline,
+                                __rte_unused uint32_t port_in, uint32_t *port_out)
+{
+       struct pipeline *p = (struct pipeline *)pipeline;
+
+       /* Check input arguments */
+       if ((p == NULL) || (port_in >= p->n_ports_in) || (port_out == NULL))
+               return -1;
+
+       if (p->n_ports_in == 1) {
+               *port_out = 0;
+               return 0;
+       }
+
+       return -1;
+}
+
+static int pipeline_loadb_timer(void *pipeline)
+{
+       struct pipeline *p = (struct pipeline *)pipeline;
+
+       pipeline_msg_req_handle(p);
+       rte_pipeline_flush(p->p);
+
+       return 0;
+}
+
+void *pipeline_loadb_msg_req_entry_dbg_handler(struct pipeline *p, void *msg)
+{
+       struct pipeline_loadb_entry_dbg_msg_rsp *rsp = msg;
+       uint8_t *Msg = msg;
+       struct pipeline_loadb *p_loadb = (struct pipeline_loadb *)p;
+
+       rsp->status = 0;
+
+       printf("LoadB debug handler called with args %x %x, offset %d\n",
+                                Msg[LOADB_DBG_CMD_OFST], Msg[LOADB_DBG_CMD_OFST + 1],
+                                LOADB_DBG_CMD_OFST);
+
+       if (Msg[LOADB_DBG_CMD_OFST] == LOADB_DBG_CMD_STATS_SHOW) {
+               printf("\nLoadB Packet Stats: Received %" PRIu64 "\n",
+                                        p_loadb->receivedLBPktCount);
+               return rsp;
+       }
+       if (Msg[LOADB_DBG_CMD_OFST] == LOADB_DBG_CMD_STATS_CLEAR) {
+               printf("\nLoadB Packet Stats: Received %" PRIu64 "\n",
+                                        p_loadb->receivedLBPktCount);
+               p_loadb->receivedLBPktCount = 0;
+               return rsp;
+       }
+
+       if (Msg[LOADB_DBG_CMD_OFST] == LOADB_DBG_CMD_DBG_LEVEL) {
+               LOADB_DEBUG = Msg[LOADB_DBG_CMD_OFST + 1];
+               printf("LOADB Debug level set to %d\n", LOADB_DEBUG);
+               lb_pkt_print_count = 0;
+               return rsp;
+       }
+       if (Msg[LOADB_DBG_CMD_OFST] == LOADB_DBG_CMD_DBG_SHOW) {
+               printf("\nLoadB DBG Level: %u\n", LOADB_DEBUG);
+               return rsp;
+       }
+       if (Msg[LOADB_DBG_CMD_OFST] == LOADB_DBG_CMD_IF_STATS) {
+               printf("\n");
+               uint8_t i, j;
+
+               for (i = 0; i < p->n_ports_in; i++) {
+                       struct rte_eth_stats stats;
+                       rte_eth_stats_get(p_loadb->links_map[i], &stats);
+                       if (is_phy_port_privte(i))
+                               printf("Private Port Stats %d\n", i);
+                       else
+                               printf("Public Port Stats  %d\n", i);
+                       printf("\n\tipackets : %" PRIu64 "\n\topackets : %"
+                                                PRIu64 "\n\tierrors  : %" PRIu64
+                                                "\n\toerrors  : %" PRIu64 "\n\trx_nombuf: %"
+                                                PRIu64 "\n", stats.ipackets, stats.opackets,
+                                                stats.ierrors, stats.oerrors, stats.rx_nombuf);
+                       if (is_phy_port_privte(i))
+                               printf("Private Q: ");
+                       else
+                               printf("Public  Q: ");
+                       for (j = 0; j < RTE_ETHDEV_QUEUE_STAT_CNTRS; j++)
+                               printf(" %" PRIu64 ", %" PRIu64 "|",
+                                                        stats.q_ipackets[j],
+                                                        stats.q_opackets[j]);
+
+                       printf("\n\n");
+
+               }
+               return rsp;
+       }
+
+       return rsp;
+
+}
+
+struct pipeline_be_ops pipeline_loadb_be_ops = {
+       .f_init = pipeline_loadb_init,
+       .f_free = pipeline_loadb_free,
+       .f_run = NULL,
+       .f_timer = pipeline_loadb_timer,
+       .f_track = pipeline_loadb_track,
+};
diff --git a/common/VIL/pipeline_loadb/pipeline_loadb_be.h b/common/VIL/pipeline_loadb/pipeline_loadb_be.h
new file mode 100644 (file)
index 0000000..a948f4c
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef __INCLUDE_PIPELINE_LOADB_BE_H__
+#define __INCLUDE_PIPELINE_LOADB_BE_H__
+
+#include <rte_ip.h>
+#include "pipeline_common_be.h"
+#include <app.h>
+
+#define MBUF_HDR_ROOM 256
+#define ETH_HDR_SIZE  14
+#define IP_HDR_SRC_ADR_OFST 12
+#define IP_HDR_DST_ADR_OFST 16
+#define IP_HDR_PROTOCOL_OFST 9
+#define IP_HDR_SIZE  20
+#define IPV6_HDR_SRC_ADR_OFST 8
+#define IPV6_HDR_DST_ADR_OFST 24
+#define IPV6_HDR_PROTOCOL_OFST 6
+#define IPV6_HDR_SIZE  40
+#define IP_PROTOCOL_TCP 6
+#define IP_PROTOCOL_UDP 17
+#define PIPELINE_LOADB_KEY_MAX_SIZE  64
+
+#define LOADB_ING_DIR 0
+#define LOADB_EGR_DIR 1
+
+#define LOADB_DBG_CMD_OFST 8
+#define LOADB_DBG_CMD_STATS_SHOW 0
+#define LOADB_DBG_CMD_STATS_CLEAR 1
+#define LOADB_DBG_CMD_DBG_LEVEL 2
+#define LOADB_DBG_CMD_DBG_SHOW 3
+#define LOADB_DBG_CMD_IF_STATS 4
+#define LOADB_DBG_CMD_OFST1 10
+
+#define PIPELINE_LOADB_KEY_PORT_IN_AH(f_ah, f_pkt_work, f_pkt4_work)    \
+static int                                                              \
+f_ah(                                                                   \
+       __rte_unused struct rte_pipeline *rte_p,                        \
+       struct rte_mbuf **pkts,                                         \
+       uint32_t n_pkts,                                                \
+       void *arg)                                                      \
+{                                                                       \
+       uint32_t i, j;                                                  \
+                                                                       \
+       for (j = 0; j < n_pkts; j++)                                    \
+               rte_prefetch0(pkts[j]);                                 \
+       pkt_burst_cnt = 0;                                              \
+       for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4)                   \
+               f_pkt4_work(&pkts[i], i, arg);                          \
+                                                                       \
+       for ( ; i < n_pkts; i++)                                        \
+               f_pkt_work(pkts[i], i, arg);                            \
+                                                                       \
+                                                                       \
+       return 0;                                                       \
+}
+
+extern uint8_t LOADB_DEBUG;
+extern uint8_t in_port_egress_prv[PIPELINE_MAX_PORT_IN];
+extern uint8_t prv_que_port_index[PIPELINE_MAX_PORT_IN];
+extern uint8_t in_port_dir_a[PIPELINE_MAX_PORT_IN];
+
+extern uint8_t get_in_port_dir(uint8_t);
+extern uint8_t is_port_index_privte(uint16_t);
+extern uint8_t is_phy_port_privte(uint16_t);
+extern uint32_t get_prv_to_pub_port(uint32_t *ip_addr, uint8_t type);
+extern uint32_t get_pub_to_prv_port(uint32_t *ip_addr, uint8_t type);
+extern uint8_t prv_to_pub_map[PIPELINE_MAX_PORT_IN];
+//extern struct app_params *myApp;
+//extern struct pipeline_arpicmp *p_arp;
+
+/*
+ * LOADB Entry
+ */
+
+struct pipeline_loadb_in_port_h_arg {
+       struct pipeline_loadb *p;
+       uint8_t in_port_id;
+};
+
+/*
+ * Messages
+ */
+enum pipeline_loadb_msg_req_type {
+       /* to be used for debug purposes */
+       PIPELINE_LOADB_MSG_REQ_ENTRY_DBG,
+       PIPELINE_LOADB_MSG_REQS
+};
+
+/*
+ * MSG ENTRY DBG
+ */
+struct pipeline_loadb_entry_dbg_msg_req {
+       enum pipeline_msg_req_type type;
+       enum pipeline_loadb_msg_req_type subtype;
+
+       /* data */
+       uint8_t data[5];
+};
+
+struct pipeline_loadb_entry_dbg_msg_rsp {
+       int status;
+       void *entry_ptr;
+};
+
+extern struct pipeline_be_ops pipeline_loadb_be_ops;
+struct ipv4_hdr_port {
+       struct ipv4_hdr ipv4;
+       uint16_t src_port;
+       uint16_t dst_port;
+
+} __attribute__((__packed__));
+struct ipv6_hdr_port {
+       struct ipv6_hdr ipv6;
+       uint16_t src_port;
+       uint16_t dst_port;
+
+} __attribute__((__packed__));
+
+struct lb_pkt {
+       struct ether_hdr eth;
+       union{
+               struct ipv4_hdr_port ipv4_port;
+               struct ipv6_hdr_port ipv6_port;
+       };
+} __attribute__((__packed__));
+
+uint8_t calculate_lb_thread_prv(struct rte_mbuf *pkt, void *arg);
+uint8_t calculate_lb_thread_pub(struct rte_mbuf *pkt, void *arg);
+int check_loadb_thread(
+       struct app_params *app,
+       struct pipeline_params *params,
+       int32_t n_vnf_threads);
+
+#endif
diff --git a/common/VIL/pipeline_master/pipeline_master.c b/common/VIL/pipeline_master/pipeline_master.c
new file mode 100644 (file)
index 0000000..bfab32a
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include "pipeline_master.h"
+#include "pipeline_master_be.h"
+
+static struct pipeline_fe_ops pipeline_master_fe_ops = {
+       .f_init = NULL,
+       .f_free = NULL,
+       .cmds = NULL,
+};
+
+struct pipeline_type pipeline_master = {
+       .name = "MASTER",
+       .be_ops = &pipeline_master_be_ops,
+       .fe_ops = &pipeline_master_fe_ops,
+};
diff --git a/common/VIL/pipeline_master/pipeline_master.h b/common/VIL/pipeline_master/pipeline_master.h
new file mode 100644 (file)
index 0000000..d39afb5
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef __INCLUDE_PIPELINE_MASTER_H__
+#define __INCLUDE_PIPELINE_MASTER_H__
+
+#include "pipeline.h"
+
+extern struct pipeline_type pipeline_master;
+
+#endif
diff --git a/common/VIL/pipeline_master/pipeline_master_be.c b/common/VIL/pipeline_master/pipeline_master_be.c
new file mode 100644 (file)
index 0000000..425e233
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <rte_common.h>
+#include <rte_malloc.h>
+
+#include <cmdline_parse.h>
+#include <cmdline_parse_string.h>
+#include <cmdline_socket.h>
+#include <cmdline.h>
+
+#include "app.h"
+#include "pipeline_master_be.h"
+
+struct pipeline_master {
+       struct app_params *app;
+       struct cmdline *cl;
+       int script_file_done;
+} __rte_cache_aligned;
+
+static void*
+pipeline_init(__rte_unused struct pipeline_params *params, void *arg)
+{
+       struct app_params *app = (struct app_params *) arg;
+       struct pipeline_master *p;
+       uint32_t size;
+
+       /* Check input arguments */
+       if (app == NULL)
+               return NULL;
+
+       /* Memory allocation */
+       size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct pipeline_master));
+       p = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
+       if (p == NULL)
+               return NULL;
+
+       /* Initialization */
+       p->app = app;
+
+       p->cl = cmdline_stdin_new(app->cmds, "pipeline> ");
+       if (p->cl == NULL) {
+               rte_free(p);
+               return NULL;
+       }
+
+       p->script_file_done = 0;
+       if (app->script_file == NULL)
+               p->script_file_done = 1;
+
+       return (void *) p;
+}
+
+static int
+pipeline_free(void *pipeline)
+{
+       struct pipeline_master *p = (struct pipeline_master *) pipeline;
+
+       if (p == NULL)
+               return -EINVAL;
+
+       cmdline_stdin_exit(p->cl);
+       rte_free(p);
+
+       return 0;
+}
+
+static int
+pipeline_run(void *pipeline)
+{
+       struct pipeline_master *p = (struct pipeline_master *) pipeline;
+       int status;
+
+       if (p->script_file_done == 0) {
+               struct app_params *app = p->app;
+               int fd = open(app->script_file, O_RDONLY);
+
+               if (fd < 0)
+                       printf("Cannot open CLI script file \"%s\"\n",
+                               app->script_file);
+               else {
+                       struct cmdline *file_cl;
+
+                       printf("Running CLI script file \"%s\" ...\n",
+                               app->script_file);
+                       file_cl = cmdline_new(p->cl->ctx, "", fd, 1);
+                       cmdline_interact(file_cl);
+                       close(fd);
+               }
+
+               p->script_file_done = 1;
+       }
+
+       status = cmdline_poll(p->cl);
+       if (status < 0)
+               rte_panic("CLI poll error (%" PRId32 ")\n", status);
+       else if (status == RDLINE_EXITED) {
+               cmdline_stdin_exit(p->cl);
+               rte_exit(0, "Bye!\n");
+       }
+
+       return 0;
+}
+
+static int
+pipeline_timer(__rte_unused void *pipeline)
+{
+       rte_timer_manage();
+       return 0;
+}
+
+struct pipeline_be_ops pipeline_master_be_ops = {
+               .f_init = pipeline_init,
+               .f_free = pipeline_free,
+               .f_run = pipeline_run,
+               .f_timer = pipeline_timer,
+               .f_track = NULL,
+};
diff --git a/common/VIL/pipeline_master/pipeline_master_be.h b/common/VIL/pipeline_master/pipeline_master_be.h
new file mode 100644 (file)
index 0000000..fceb684
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef __INCLUDE_PIPELINE_MASTER_BE_H__
+#define __INCLUDE_PIPELINE_MASTER_BE_H__
+
+#include "pipeline_common_be.h"
+
+extern struct pipeline_be_ops pipeline_master_be_ops;
+
+#endif
diff --git a/common/VIL/pipeline_passthrough/pipeline_passthrough.c b/common/VIL/pipeline_passthrough/pipeline_passthrough.c
new file mode 100644 (file)
index 0000000..0463f8e
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include "pipeline_passthrough.h"
+#include "pipeline_passthrough_be.h"
+
+static struct pipeline_fe_ops pipeline_passthrough_fe_ops = {
+       .f_init = NULL,
+       .f_free = NULL,
+       .cmds = NULL,
+};
+
+struct pipeline_type pipeline_passthrough = {
+       .name = "PASS-THROUGH",
+       .be_ops = &pipeline_passthrough_be_ops,
+       .fe_ops = &pipeline_passthrough_fe_ops,
+};
diff --git a/common/VIL/pipeline_passthrough/pipeline_passthrough.h b/common/VIL/pipeline_passthrough/pipeline_passthrough.h
new file mode 100644 (file)
index 0000000..9b650eb
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef __INCLUDE_PIPELINE_PASSTHROUGH_H__
+#define __INCLUDE_PIPELINE_PASSTHROUGH_H__
+
+#include "pipeline.h"
+
+extern struct pipeline_type pipeline_passthrough;
+
+#endif
diff --git a/common/VIL/pipeline_passthrough/pipeline_passthrough_be.c b/common/VIL/pipeline_passthrough/pipeline_passthrough_be.c
new file mode 100644 (file)
index 0000000..5b74d75
--- /dev/null
@@ -0,0 +1,787 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <string.h>
+
+#include <rte_common.h>
+#include <rte_malloc.h>
+#include <rte_byteorder.h>
+#include <rte_table_stub.h>
+#include <rte_table_hash.h>
+#include <rte_pipeline.h>
+
+#include "pipeline_passthrough_be.h"
+#include "pipeline_actions_common.h"
+#include "parser.h"
+#include "hash_func.h"
+
+struct pipeline_passthrough {
+       struct pipeline p;
+       struct pipeline_passthrough_params params;
+       rte_table_hash_op_hash f_hash;
+} __rte_cache_aligned;
+
+static pipeline_msg_req_handler handlers[] = {
+       [PIPELINE_MSG_REQ_PING] =
+               pipeline_msg_req_ping_handler,
+       [PIPELINE_MSG_REQ_STATS_PORT_IN] =
+               pipeline_msg_req_stats_port_in_handler,
+       [PIPELINE_MSG_REQ_STATS_PORT_OUT] =
+               pipeline_msg_req_stats_port_out_handler,
+       [PIPELINE_MSG_REQ_STATS_TABLE] =
+               pipeline_msg_req_stats_table_handler,
+       [PIPELINE_MSG_REQ_PORT_IN_ENABLE] =
+               pipeline_msg_req_port_in_enable_handler,
+       [PIPELINE_MSG_REQ_PORT_IN_DISABLE] =
+               pipeline_msg_req_port_in_disable_handler,
+       [PIPELINE_MSG_REQ_CUSTOM] =
+               pipeline_msg_req_invalid_handler,
+};
+
+static inline __attribute__((always_inline)) void
+pkt_work(
+       struct rte_mbuf *pkt,
+       void *arg,
+       uint32_t dma_size,
+       uint32_t hash_enabled,
+       uint32_t lb_hash,
+       uint32_t port_out_pow2)
+{
+       struct pipeline_passthrough *p = arg;
+
+       uint64_t *dma_dst = RTE_MBUF_METADATA_UINT64_PTR(pkt,
+               p->params.dma_dst_offset);
+       uint64_t *dma_src = RTE_MBUF_METADATA_UINT64_PTR(pkt,
+               p->params.dma_src_offset);
+       uint64_t *dma_mask = (uint64_t *) p->params.dma_src_mask;
+       uint32_t *dma_hash = RTE_MBUF_METADATA_UINT32_PTR(pkt,
+               p->params.dma_hash_offset);
+       uint32_t i;
+
+       /* Read (dma_src), compute (dma_dst), write (dma_dst) */
+       for (i = 0; i < (dma_size / 8); i++)
+               dma_dst[i] = dma_src[i] & dma_mask[i];
+
+       /* Read (dma_dst), compute (hash), write (hash) */
+       if (hash_enabled) {
+               uint32_t hash = p->f_hash(dma_dst, dma_size, 0);
+               *dma_hash = hash;
+
+               if (lb_hash) {
+                       uint32_t port_out;
+
+                       if (port_out_pow2)
+                               port_out
+                                       = hash & (p->p.n_ports_out - 1);
+                       else
+                               port_out
+                                       = hash % p->p.n_ports_out;
+
+                       rte_pipeline_port_out_packet_insert(p->p.p,
+                               port_out, pkt);
+               }
+       }
+}
+
+static inline __attribute__((always_inline)) void
+pkt4_work(
+       struct rte_mbuf **pkts,
+       void *arg,
+       uint32_t dma_size,
+       uint32_t hash_enabled,
+       uint32_t lb_hash,
+       uint32_t port_out_pow2)
+{
+       struct pipeline_passthrough *p = arg;
+
+       uint64_t *dma_dst0 = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],
+               p->params.dma_dst_offset);
+       uint64_t *dma_dst1 = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],
+               p->params.dma_dst_offset);
+       uint64_t *dma_dst2 = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],
+               p->params.dma_dst_offset);
+       uint64_t *dma_dst3 = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],
+               p->params.dma_dst_offset);
+
+       uint64_t *dma_src0 = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],
+               p->params.dma_src_offset);
+       uint64_t *dma_src1 = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],
+               p->params.dma_src_offset);
+       uint64_t *dma_src2 = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],
+               p->params.dma_src_offset);
+       uint64_t *dma_src3 = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],
+               p->params.dma_src_offset);
+
+       uint64_t *dma_mask = (uint64_t *) p->params.dma_src_mask;
+
+       uint32_t *dma_hash0 = RTE_MBUF_METADATA_UINT32_PTR(pkts[0],
+               p->params.dma_hash_offset);
+       uint32_t *dma_hash1 = RTE_MBUF_METADATA_UINT32_PTR(pkts[1],
+               p->params.dma_hash_offset);
+       uint32_t *dma_hash2 = RTE_MBUF_METADATA_UINT32_PTR(pkts[2],
+               p->params.dma_hash_offset);
+       uint32_t *dma_hash3 = RTE_MBUF_METADATA_UINT32_PTR(pkts[3],
+               p->params.dma_hash_offset);
+
+       uint32_t i;
+
+       /* Read (dma_src), compute (dma_dst), write (dma_dst) */
+       for (i = 0; i < (dma_size / 8); i++) {
+               dma_dst0[i] = dma_src0[i] & dma_mask[i];
+               dma_dst1[i] = dma_src1[i] & dma_mask[i];
+               dma_dst2[i] = dma_src2[i] & dma_mask[i];
+               dma_dst3[i] = dma_src3[i] & dma_mask[i];
+       }
+
+       /* Read (dma_dst), compute (hash), write (hash) */
+       if (hash_enabled) {
+               uint32_t hash0 = p->f_hash(dma_dst0, dma_size, 0);
+               uint32_t hash1 = p->f_hash(dma_dst1, dma_size, 0);
+               uint32_t hash2 = p->f_hash(dma_dst2, dma_size, 0);
+               uint32_t hash3 = p->f_hash(dma_dst3, dma_size, 0);
+
+               *dma_hash0 = hash0;
+               *dma_hash1 = hash1;
+               *dma_hash2 = hash2;
+               *dma_hash3 = hash3;
+
+               if (lb_hash) {
+                       uint32_t port_out0, port_out1, port_out2, port_out3;
+
+                       if (port_out_pow2) {
+                               port_out0
+                                       = hash0 & (p->p.n_ports_out - 1);
+                               port_out1
+                                       = hash1 & (p->p.n_ports_out - 1);
+                               port_out2
+                                       = hash2 & (p->p.n_ports_out - 1);
+                               port_out3
+                                       = hash3 & (p->p.n_ports_out - 1);
+                       } else {
+                               port_out0
+                                       = hash0 % p->p.n_ports_out;
+                               port_out1
+                                       = hash1 % p->p.n_ports_out;
+                               port_out2
+                                       = hash2 % p->p.n_ports_out;
+                               port_out3
+                                       = hash3 % p->p.n_ports_out;
+                       }
+                       rte_pipeline_port_out_packet_insert(p->p.p,
+                               port_out0, pkts[0]);
+                       rte_pipeline_port_out_packet_insert(p->p.p,
+                               port_out1, pkts[1]);
+                       rte_pipeline_port_out_packet_insert(p->p.p,
+                               port_out2, pkts[2]);
+                       rte_pipeline_port_out_packet_insert(p->p.p,
+                               port_out3, pkts[3]);
+               }
+       }
+}
+
+#define PKT_WORK(dma_size, hash_enabled, lb_hash, port_pow2)   \
+static inline void                                             \
+pkt_work_size##dma_size##_hash##hash_enabled           \
+       ##_lb##lb_hash##_pw##port_pow2(                 \
+       struct rte_mbuf *pkt,                                   \
+       void *arg)                                              \
+{                                                              \
+       pkt_work(pkt, arg, dma_size, hash_enabled, lb_hash, port_pow2); \
+}
+
+#define PKT4_WORK(dma_size, hash_enabled, lb_hash, port_pow2)  \
+static inline void                                             \
+pkt4_work_size##dma_size##_hash##hash_enabled                  \
+       ##_lb##lb_hash##_pw##port_pow2(                 \
+       struct rte_mbuf **pkts,                                 \
+       void *arg)                                              \
+{                                                              \
+       pkt4_work(pkts, arg, dma_size, hash_enabled, lb_hash, port_pow2); \
+}
+
+#define port_in_ah(dma_size, hash_enabled, lb_hash, port_pow2) \
+PKT_WORK(dma_size, hash_enabled, lb_hash, port_pow2)                   \
+PKT4_WORK(dma_size, hash_enabled, lb_hash, port_pow2)                  \
+PIPELINE_PORT_IN_AH(port_in_ah_size##dma_size##_hash   \
+       ##hash_enabled##_lb##lb_hash##_pw##port_pow2,           \
+       pkt_work_size##dma_size##_hash##hash_enabled            \
+       ##_lb##lb_hash##_pw##port_pow2,                 \
+       pkt4_work_size##dma_size##_hash##hash_enabled           \
+       ##_lb##lb_hash##_pw##port_pow2)
+
+
+#define port_in_ah_lb(dma_size, hash_enabled, lb_hash, port_pow2) \
+PKT_WORK(dma_size, hash_enabled, lb_hash, port_pow2)           \
+PKT4_WORK(dma_size, hash_enabled, lb_hash, port_pow2)  \
+PIPELINE_PORT_IN_AH_HIJACK_ALL(                                                \
+       port_in_ah_size##dma_size##_hash##hash_enabled          \
+       ##_lb##lb_hash##_pw##port_pow2,                 \
+       pkt_work_size##dma_size##_hash##hash_enabled            \
+       ##_lb##lb_hash##_pw##port_pow2, \
+       pkt4_work_size##dma_size##_hash##hash_enabled           \
+       ##_lb##lb_hash##_pw##port_pow2)
+
+/* Port in AH (dma_size, hash_enabled, lb_hash, port_pow2) */
+
+port_in_ah(8, 0, 0, 0)
+port_in_ah(8, 1, 0, 0)
+port_in_ah_lb(8, 1, 1, 0)
+port_in_ah_lb(8, 1, 1, 1)
+
+port_in_ah(16, 0, 0, 0)
+port_in_ah(16, 1, 0, 0)
+port_in_ah_lb(16, 1, 1, 0)
+port_in_ah_lb(16, 1, 1, 1)
+
+port_in_ah(24, 0, 0, 0)
+port_in_ah(24, 1, 0, 0)
+port_in_ah_lb(24, 1, 1, 0)
+port_in_ah_lb(24, 1, 1, 1)
+
+port_in_ah(32, 0, 0, 0)
+port_in_ah(32, 1, 0, 0)
+port_in_ah_lb(32, 1, 1, 0)
+port_in_ah_lb(32, 1, 1, 1)
+
+port_in_ah(40, 0, 0, 0)
+port_in_ah(40, 1, 0, 0)
+port_in_ah_lb(40, 1, 1, 0)
+port_in_ah_lb(40, 1, 1, 1)
+
+port_in_ah(48, 0, 0, 0)
+port_in_ah(48, 1, 0, 0)
+port_in_ah_lb(48, 1, 1, 0)
+port_in_ah_lb(48, 1, 1, 1)
+
+port_in_ah(56, 0, 0, 0)
+port_in_ah(56, 1, 0, 0)
+port_in_ah_lb(56, 1, 1, 0)
+port_in_ah_lb(56, 1, 1, 1)
+
+port_in_ah(64, 0, 0, 0)
+port_in_ah(64, 1, 0, 0)
+port_in_ah_lb(64, 1, 1, 0)
+port_in_ah_lb(64, 1, 1, 1)
+
+static rte_pipeline_port_in_action_handler
+get_port_in_ah(struct pipeline_passthrough *p)
+{
+       if (p->params.dma_enabled == 0)
+               return NULL;
+
+       if (p->params.dma_hash_enabled) {
+               if (p->params.lb_hash_enabled) {
+                       if (rte_is_power_of_2(p->p.n_ports_out))
+                               switch (p->params.dma_size) {
+
+                               case 8: return port_in_ah_size8_hash1_lb1_pw1;
+                               case 16: return port_in_ah_size16_hash1_lb1_pw1;
+                               case 24: return port_in_ah_size24_hash1_lb1_pw1;
+                               case 32: return port_in_ah_size32_hash1_lb1_pw1;
+                               case 40: return port_in_ah_size40_hash1_lb1_pw1;
+                               case 48: return port_in_ah_size48_hash1_lb1_pw1;
+                               case 56: return port_in_ah_size56_hash1_lb1_pw1;
+                               case 64: return port_in_ah_size64_hash1_lb1_pw1;
+                               default: return NULL;
+                               }
+                       else
+                               switch (p->params.dma_size) {
+
+                               case 8: return port_in_ah_size8_hash1_lb1_pw0;
+                               case 16: return port_in_ah_size16_hash1_lb1_pw0;
+                               case 24: return port_in_ah_size24_hash1_lb1_pw0;
+                               case 32: return port_in_ah_size32_hash1_lb1_pw0;
+                               case 40: return port_in_ah_size40_hash1_lb1_pw0;
+                               case 48: return port_in_ah_size48_hash1_lb1_pw0;
+                               case 56: return port_in_ah_size56_hash1_lb1_pw0;
+                               case 64: return port_in_ah_size64_hash1_lb1_pw0;
+                               default: return NULL;
+                       }
+               } else
+                       switch (p->params.dma_size) {
+
+                       case 8: return port_in_ah_size8_hash1_lb0_pw0;
+                       case 16: return port_in_ah_size16_hash1_lb0_pw0;
+                       case 24: return port_in_ah_size24_hash1_lb0_pw0;
+                       case 32: return port_in_ah_size32_hash1_lb0_pw0;
+                       case 40: return port_in_ah_size40_hash1_lb0_pw0;
+                       case 48: return port_in_ah_size48_hash1_lb0_pw0;
+                       case 56: return port_in_ah_size56_hash1_lb0_pw0;
+                       case 64: return port_in_ah_size64_hash1_lb0_pw0;
+                       default: return NULL;
+               }
+       } else
+               switch (p->params.dma_size) {
+
+               case 8: return port_in_ah_size8_hash0_lb0_pw0;
+               case 16: return port_in_ah_size16_hash0_lb0_pw0;
+               case 24: return port_in_ah_size24_hash0_lb0_pw0;
+               case 32: return port_in_ah_size32_hash0_lb0_pw0;
+               case 40: return port_in_ah_size40_hash0_lb0_pw0;
+               case 48: return port_in_ah_size48_hash0_lb0_pw0;
+               case 56: return port_in_ah_size56_hash0_lb0_pw0;
+               case 64: return port_in_ah_size64_hash0_lb0_pw0;
+               default: return NULL;
+               }
+}
+
+int
+pipeline_passthrough_parse_args(struct pipeline_passthrough_params *p,
+       struct pipeline_params *params)
+{
+       uint32_t dma_dst_offset_present = 0;
+       uint32_t dma_src_offset_present = 0;
+       uint32_t dma_src_mask_present = 0;
+       uint32_t dma_size_present = 0;
+       uint32_t dma_hash_offset_present = 0;
+       uint32_t lb_present = 0;
+       uint32_t i;
+       char dma_mask_str[PIPELINE_PASSTHROUGH_DMA_SIZE_MAX * 2];
+
+       /* default values */
+       p->dma_enabled = 0;
+       p->dma_hash_enabled = 0;
+       p->lb_hash_enabled = 0;
+       memset(p->dma_src_mask, 0xFF, sizeof(p->dma_src_mask));
+
+       for (i = 0; i < params->n_args; i++) {
+               char *arg_name = params->args_name[i];
+               char *arg_value = params->args_value[i];
+
+               /* dma_dst_offset */
+               if (strcmp(arg_name, "dma_dst_offset") == 0) {
+                       int status;
+
+                       PIPELINE_PARSE_ERR_DUPLICATE(
+                               dma_dst_offset_present == 0, params->name,
+                               arg_name);
+                       dma_dst_offset_present = 1;
+
+                       status = parser_read_uint32(&p->dma_dst_offset,
+                               arg_value);
+                       PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
+                               params->name, arg_name, arg_value);
+                       PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
+                               params->name, arg_name, arg_value);
+
+                       p->dma_enabled = 1;
+
+                       continue;
+               }
+
+               /* dma_src_offset */
+               if (strcmp(arg_name, "dma_src_offset") == 0) {
+                       int status;
+
+                       PIPELINE_PARSE_ERR_DUPLICATE(
+                               dma_src_offset_present == 0, params->name,
+                               arg_name);
+                       dma_src_offset_present = 1;
+
+                       status = parser_read_uint32(&p->dma_src_offset,
+                               arg_value);
+                       PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
+                               params->name, arg_name, arg_value);
+                       PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
+                               params->name, arg_name, arg_value);
+
+                       p->dma_enabled = 1;
+
+                       continue;
+               }
+
+               /* dma_size */
+               if (strcmp(arg_name, "dma_size") == 0) {
+                       int status;
+
+                       PIPELINE_PARSE_ERR_DUPLICATE(
+                               dma_size_present == 0, params->name,
+                               arg_name);
+                       dma_size_present = 1;
+
+                       status = parser_read_uint32(&p->dma_size,
+                               arg_value);
+                       PIPELINE_PARSE_ERR_INV_VAL(((status != -EINVAL) &&
+                               (p->dma_size != 0) &&
+                               ((p->dma_size % 8) == 0)),
+                               params->name, arg_name, arg_value);
+                       PIPELINE_PARSE_ERR_OUT_RNG(((status != -ERANGE) &&
+                               (p->dma_size <=
+                               PIPELINE_PASSTHROUGH_DMA_SIZE_MAX)),
+                               params->name, arg_name, arg_value);
+
+                       p->dma_enabled = 1;
+
+                       continue;
+               }
+
+               /* dma_src_mask */
+               if (strcmp(arg_name, "dma_src_mask") == 0) {
+                       int mask_str_len = strlen(arg_value);
+
+                       PIPELINE_PARSE_ERR_DUPLICATE(
+                               dma_src_mask_present == 0,
+                               params->name, arg_name);
+                       dma_src_mask_present = 1;
+
+                       PIPELINE_ARG_CHECK((mask_str_len <
+                               (PIPELINE_PASSTHROUGH_DMA_SIZE_MAX * 2)),
+                               "Parse error in section \"%s\": entry "
+                               "\"%s\" too long", params->name,
+                               arg_name);
+
+                       snprintf(dma_mask_str, mask_str_len + 1,
+                               "%s", arg_value);
+
+                       p->dma_enabled = 1;
+
+                       continue;
+               }
+
+               /* dma_hash_offset */
+               if (strcmp(arg_name, "dma_hash_offset") == 0) {
+                       int status;
+
+                       PIPELINE_PARSE_ERR_DUPLICATE(
+                               dma_hash_offset_present == 0,
+                               params->name, arg_name);
+                       dma_hash_offset_present = 1;
+
+                       status = parser_read_uint32(&p->dma_hash_offset,
+                               arg_value);
+                       PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
+                               params->name, arg_name, arg_value);
+                       PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
+                               params->name, arg_name, arg_value);
+
+                       p->dma_hash_enabled = 1;
+                       p->dma_enabled = 1;
+
+                       continue;
+               }
+
+               /* load_balance mode */
+               if (strcmp(arg_name, "lb") == 0) {
+                       PIPELINE_PARSE_ERR_DUPLICATE(
+                               lb_present == 0,
+                               params->name, arg_name);
+                       lb_present = 1;
+
+                       if ((strcmp(arg_value, "hash") == 0) ||
+                               (strcmp(arg_value, "HASH") == 0))
+                               p->lb_hash_enabled = 1;
+                       else
+                               PIPELINE_PARSE_ERR_INV_VAL(0,
+                                       params->name,
+                                       arg_name,
+                                       arg_value);
+
+                       continue;
+               }
+
+               /* any other */
+               PIPELINE_PARSE_ERR_INV_ENT(0, params->name, arg_name);
+       }
+
+       /* Check correlations between arguments */
+       PIPELINE_ARG_CHECK((dma_dst_offset_present == p->dma_enabled),
+               "Parse error in section \"%s\": missing entry "
+               "\"dma_dst_offset\"", params->name);
+       PIPELINE_ARG_CHECK((dma_src_offset_present == p->dma_enabled),
+               "Parse error in section \"%s\": missing entry "
+               "\"dma_src_offset\"", params->name);
+       PIPELINE_ARG_CHECK((dma_size_present == p->dma_enabled),
+               "Parse error in section \"%s\": missing entry "
+               "\"dma_size\"", params->name);
+       PIPELINE_ARG_CHECK((dma_hash_offset_present == p->dma_enabled),
+               "Parse error in section \"%s\": missing entry "
+               "\"dma_hash_offset\"", params->name);
+       PIPELINE_ARG_CHECK((p->lb_hash_enabled <= p->dma_hash_enabled),
+               "Parse error in section \"%s\": missing entry "
+               "\"dma_hash_offset\"", params->name);
+
+       if (dma_src_mask_present) {
+               uint32_t dma_size = p->dma_size;
+               int status;
+
+               PIPELINE_ARG_CHECK((strlen(dma_mask_str) ==
+                       (dma_size * 2)), "Parse error in section "
+                       "\"%s\": dma_src_mask should have exactly %u hex "
+                       "digits", params->name, (dma_size * 2));
+
+               status = parse_hex_string(dma_mask_str, p->dma_src_mask,
+                       &p->dma_size);
+
+               PIPELINE_PARSE_ERR_INV_VAL(((status == 0) &&
+                       (dma_size == p->dma_size)), params->name,
+                       "dma_src_mask", dma_mask_str);
+       }
+
+       return 0;
+}
+
+
+static rte_table_hash_op_hash
+get_hash_function(struct pipeline_passthrough *p)
+{
+       switch (p->params.dma_size) {
+
+       case 8: return hash_default_key8;
+       case 16: return hash_default_key16;
+       case 24: return hash_default_key24;
+       case 32: return hash_default_key32;
+       case 40: return hash_default_key40;
+       case 48: return hash_default_key48;
+       case 56: return hash_default_key56;
+       case 64: return hash_default_key64;
+       default: return NULL;
+       }
+}
+
+static void*
+pipeline_passthrough_init(struct pipeline_params *params,
+       __rte_unused void *arg)
+{
+       struct pipeline *p;
+       struct pipeline_passthrough *p_pt;
+       uint32_t size, i;
+
+       /* Check input arguments */
+       if ((params == NULL) ||
+               (params->n_ports_in == 0) ||
+               (params->n_ports_out == 0) ||
+               (params->n_ports_in < params->n_ports_out) ||
+               (params->n_ports_in % params->n_ports_out))
+               return NULL;
+
+       /* Memory allocation */
+       size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct pipeline_passthrough));
+       p = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
+       p_pt = (struct pipeline_passthrough *) p;
+       if (p == NULL)
+               return NULL;
+
+       strcpy(p->name, params->name);
+       p->log_level = params->log_level;
+
+       PLOG(p, HIGH, "Pass-through");
+
+       /* Parse arguments */
+       if (pipeline_passthrough_parse_args(&p_pt->params, params))
+               return NULL;
+       p_pt->f_hash = get_hash_function(p_pt);
+
+       /* Pipeline */
+       {
+               struct rte_pipeline_params pipeline_params = {
+                       .name = "PASS-THROUGH",
+                       .socket_id = params->socket_id,
+                       .offset_port_id = 0,
+               };
+
+               p->p = rte_pipeline_create(&pipeline_params);
+               if (p->p == NULL) {
+                       rte_free(p);
+                       return NULL;
+               }
+       }
+
+       p->n_ports_in = params->n_ports_in;
+       p->n_ports_out = params->n_ports_out;
+       p->n_tables = p->n_ports_in;
+
+       /*Input ports*/
+       for (i = 0; i < p->n_ports_in; i++) {
+               struct rte_pipeline_port_in_params port_params = {
+                       .ops = pipeline_port_in_params_get_ops(
+                               &params->port_in[i]),
+                       .arg_create = pipeline_port_in_params_convert(
+                               &params->port_in[i]),
+                       .f_action = get_port_in_ah(p_pt),
+                       .arg_ah = p_pt,
+                       .burst_size = params->port_in[i].burst_size,
+               };
+
+               int status = rte_pipeline_port_in_create(p->p,
+                       &port_params,
+                       &p->port_in_id[i]);
+
+               if (status) {
+                       rte_pipeline_free(p->p);
+                       rte_free(p);
+                       return NULL;
+               }
+       }
+
+       /* Output ports */
+       for (i = 0; i < p->n_ports_out; i++) {
+               struct rte_pipeline_port_out_params port_params = {
+                       .ops = pipeline_port_out_params_get_ops(
+                               &params->port_out[i]),
+                       .arg_create = pipeline_port_out_params_convert(
+                               &params->port_out[i]),
+                       .f_action = NULL,
+                       .arg_ah = NULL,
+               };
+
+               int status = rte_pipeline_port_out_create(p->p,
+                       &port_params,
+                       &p->port_out_id[i]);
+
+               if (status) {
+                       rte_pipeline_free(p->p);
+                       rte_free(p);
+                       return NULL;
+               }
+       }
+
+       /* Tables */
+       for (i = 0; i < p->n_ports_in; i++) {
+               struct rte_pipeline_table_params table_params = {
+                       .ops = &rte_table_stub_ops,
+                       .arg_create = NULL,
+                       .f_action_hit = NULL,
+                       .f_action_miss = NULL,
+                       .arg_ah = NULL,
+                       .action_data_size = 0,
+               };
+
+               int status = rte_pipeline_table_create(p->p,
+                       &table_params,
+                       &p->table_id[i]);
+
+               if (status) {
+                       rte_pipeline_free(p->p);
+                       rte_free(p);
+                       return NULL;
+               }
+       }
+
+       /* Connecting input ports to tables */
+       for (i = 0; i < p->n_ports_in; i++) {
+               int status = rte_pipeline_port_in_connect_to_table(p->p,
+                       p->port_in_id[i],
+                       p->table_id[i]);
+
+               if (status) {
+                       rte_pipeline_free(p->p);
+                       rte_free(p);
+                       return NULL;
+               }
+       }
+
+       /* Add entries to tables */
+       for (i = 0; i < p->n_ports_in; i++) {
+               struct rte_pipeline_table_entry default_entry = {
+                       .action = RTE_PIPELINE_ACTION_PORT,
+                       {.port_id = p->port_out_id[
+                               i / (p->n_ports_in / p->n_ports_out)]},
+               };
+
+               struct rte_pipeline_table_entry *default_entry_ptr;
+
+               int status = rte_pipeline_table_default_entry_add(p->p,
+                       p->table_id[i],
+                       &default_entry,
+                       &default_entry_ptr);
+
+               if (status) {
+                       rte_pipeline_free(p->p);
+                       rte_free(p);
+                       return NULL;
+               }
+       }
+
+       /* Enable input ports */
+       for (i = 0; i < p->n_ports_in; i++) {
+               int status = rte_pipeline_port_in_enable(p->p,
+                       p->port_in_id[i]);
+
+               if (status) {
+                       rte_pipeline_free(p->p);
+                       rte_free(p);
+                       return NULL;
+               }
+       }
+
+       /* Check pipeline consistency */
+       if (rte_pipeline_check(p->p) < 0) {
+               rte_pipeline_free(p->p);
+               rte_free(p);
+               return NULL;
+       }
+
+       /* Message queues */
+       p->n_msgq = params->n_msgq;
+       for (i = 0; i < p->n_msgq; i++)
+               p->msgq_in[i] = params->msgq_in[i];
+       for (i = 0; i < p->n_msgq; i++)
+               p->msgq_out[i] = params->msgq_out[i];
+
+       /* Message handlers */
+       memcpy(p->handlers, handlers, sizeof(p->handlers));
+
+       return p;
+}
+
+static int
+pipeline_passthrough_free(void *pipeline)
+{
+       struct pipeline *p = (struct pipeline *) pipeline;
+
+       /* Check input arguments */
+       if (p == NULL)
+               return -1;
+
+       /* Free resources */
+       rte_pipeline_free(p->p);
+       rte_free(p);
+       return 0;
+}
+
+static int
+pipeline_passthrough_timer(void *pipeline)
+{
+       struct pipeline *p = (struct pipeline *) pipeline;
+
+       pipeline_msg_req_handle(p);
+       rte_pipeline_flush(p->p);
+
+       return 0;
+}
+
+static int
+pipeline_passthrough_track(void *pipeline, uint32_t port_in, uint32_t *port_out)
+{
+       struct pipeline *p = (struct pipeline *) pipeline;
+
+       /* Check input arguments */
+       if ((p == NULL) ||
+               (port_in >= p->n_ports_in) ||
+               (port_out == NULL))
+               return -1;
+
+       *port_out = port_in / p->n_ports_in;
+       return 0;
+}
+
+struct pipeline_be_ops pipeline_passthrough_be_ops = {
+       .f_init = pipeline_passthrough_init,
+       .f_free = pipeline_passthrough_free,
+       .f_run = NULL,
+       .f_timer = pipeline_passthrough_timer,
+       .f_track = pipeline_passthrough_track,
+};
diff --git a/common/VIL/pipeline_passthrough/pipeline_passthrough_be.h b/common/VIL/pipeline_passthrough/pipeline_passthrough_be.h
new file mode 100644 (file)
index 0000000..442734f
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef __INCLUDE_PIPELINE_PASSTHROUGH_BE_H__
+#define __INCLUDE_PIPELINE_PASSTHROUGH_BE_H__
+
+#include "pipeline_common_be.h"
+
+#define PIPELINE_PASSTHROUGH_DMA_SIZE_MAX                             64
+
+struct pipeline_passthrough_params {
+       uint32_t dma_enabled;
+       uint32_t dma_dst_offset;
+       uint32_t dma_src_offset;
+       uint8_t dma_src_mask[PIPELINE_PASSTHROUGH_DMA_SIZE_MAX];
+       uint32_t dma_size;
+
+       uint32_t dma_hash_enabled;
+       uint32_t dma_hash_offset;
+       uint32_t lb_hash_enabled;
+};
+
+int
+pipeline_passthrough_parse_args(struct pipeline_passthrough_params *p,
+       struct pipeline_params *params);
+
+extern struct pipeline_be_ops pipeline_passthrough_be_ops;
+
+#endif
diff --git a/common/VIL/pipeline_txrx/pipeline_txrx.c b/common/VIL/pipeline_txrx/pipeline_txrx.c
new file mode 100644 (file)
index 0000000..c1fc075
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <cmdline_parse.h>
+#include <cmdline_parse_num.h>
+#include <cmdline_parse_string.h>
+#include <cmdline_parse_ipaddr.h>
+#include <cmdline_parse_etheraddr.h>
+
+#include "app.h"
+#include "pipeline_common_fe.h"
+#include "pipeline_txrx.h"
+#include "vnf_common.h"
+//#include "lib_arp.h"
+#include "pipeline_arpicmp_be.h"
+
+static int
+app_pipeline_txrx_entry_dbg(struct app_params *app,
+                                       uint32_t pipeline_id, uint8_t *msg)
+{
+       struct pipeline_txrx_entry_dbg_msg_req *req;
+       struct pipeline_txrx_entry_dbg_msg_rsp *rsp;
+
+       /* Check input arguments */
+       if (app == NULL)
+               return -1;
+
+       /* Allocate and write request */
+       req = app_msg_alloc(app);
+       if (req == NULL)
+               return -1;
+
+       req->type = PIPELINE_MSG_REQ_CUSTOM;
+       req->subtype = PIPELINE_TXRX_MSG_REQ_ENTRY_DBG;
+       req->data[0] = msg[0];
+       req->data[1] = msg[1];
+
+       rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
+       if (rsp == NULL)
+               return -1;
+
+       /* Read response */
+       if (rsp->status) {
+               app_msg_free(app, rsp);
+               printf("Error rsp->status %d\n", rsp->status);
+               return -1;
+       }
+
+       /* Free response */
+       app_msg_free(app, rsp);
+
+       return 0;
+}
+
+/*
+ * entry dbg
+ */
+
+
+struct cmd_entry_dbg_result {
+       cmdline_fixed_string_t p_string;
+       uint32_t p;
+       cmdline_fixed_string_t entry_string;
+       cmdline_fixed_string_t dbg_string;
+       uint8_t cmd;
+       uint8_t d1;
+};
+
+static void
+cmd_entry_dbg_parsed(void *parsed_result,
+                                __rte_unused struct cmdline *cl, void *data)
+{
+       struct cmd_entry_dbg_result *params = parsed_result;
+       struct app_params *app = data;
+       uint8_t msg[2];
+       int status;
+
+       msg[0] = params->cmd;
+       msg[1] = params->d1;
+       status = app_pipeline_txrx_entry_dbg(app, params->p, msg);
+
+       if (status != 0) {
+               printf("Dbg Command failed\n");
+               return;
+       }
+}
+
+static cmdline_parse_token_string_t lb_cmd_entry_dbg_p_string =
+TOKEN_STRING_INITIALIZER(struct cmd_entry_dbg_result, p_string, "p");
+
+static cmdline_parse_token_num_t lb_cmd_entry_dbg_p =
+TOKEN_NUM_INITIALIZER(struct cmd_entry_dbg_result, p, UINT32);
+
+static cmdline_parse_token_string_t lb_cmd_entry_dbg_entry_string =
+TOKEN_STRING_INITIALIZER(struct cmd_entry_dbg_result,
+                        entry_string, "txrx");
+
+static cmdline_parse_token_string_t lb_cmd_entry_dbg_dbg_string =
+TOKEN_STRING_INITIALIZER(struct cmd_entry_dbg_result, dbg_string,
+                        "dbg");
+
+static cmdline_parse_token_num_t lb_cmd_entry_dbg_cmd =
+TOKEN_NUM_INITIALIZER(struct cmd_entry_dbg_result, cmd, UINT8);
+
+static cmdline_parse_token_num_t lb_cmd_entry_dbg_d1 =
+TOKEN_NUM_INITIALIZER(struct cmd_entry_dbg_result, d1, UINT8);
+
+static cmdline_parse_inst_t lb_cmd_entry_dbg = {
+       .f = cmd_entry_dbg_parsed,
+       .data = NULL,
+       .help_str = "TXRX dbg cmd",
+       .tokens = {
+                        (void *)&lb_cmd_entry_dbg_p_string,
+                        (void *)&lb_cmd_entry_dbg_p,
+                        (void *)&lb_cmd_entry_dbg_entry_string,
+                        (void *)&lb_cmd_entry_dbg_dbg_string,
+                        (void *)&lb_cmd_entry_dbg_cmd,
+                        (void *)&lb_cmd_entry_dbg_d1,
+                        NULL,
+                        },
+};
+
+static cmdline_parse_ctx_t pipeline_cmds[] = {
+       (cmdline_parse_inst_t *) &lb_cmd_entry_dbg,
+       NULL,
+};
+
+static struct pipeline_fe_ops pipeline_txrx_fe_ops = {
+       .f_init = NULL,
+       .f_free = NULL,
+       .cmds = pipeline_cmds,
+};
+
+struct pipeline_type pipeline_txrx = {
+       .name = "TXRX",
+       .be_ops = &pipeline_txrx_be_ops,
+       .fe_ops = &pipeline_txrx_fe_ops,
+};
diff --git a/common/VIL/pipeline_txrx/pipeline_txrx.h b/common/VIL/pipeline_txrx/pipeline_txrx.h
new file mode 100644 (file)
index 0000000..9906924
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef __INCLUDE_PIPELINE_TXRX_H__
+#define __INCLUDE_PIPELINE_TXRX_H__
+
+#include "pipeline.h"
+#include "pipeline_txrx_be.h"
+
+/*
+ * Pipeline type
+ */
+extern struct pipeline_type pipeline_txrx;
+
+#endif
diff --git a/common/VIL/pipeline_txrx/pipeline_txrx_be.c b/common/VIL/pipeline_txrx/pipeline_txrx_be.c
new file mode 100644 (file)
index 0000000..9e7645d
--- /dev/null
@@ -0,0 +1,915 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <string.h>
+
+#include <rte_common.h>
+#include <rte_malloc.h>
+#include <rte_byteorder.h>
+#include <rte_table_stub.h>
+#include <rte_table_hash.h>
+#include <rte_pipeline.h>
+
+#include "pipeline_txrx_be.h"
+#include "pipeline_actions_common.h"
+#include "parser.h"
+#include "hash_func.h"
+#include "pipeline_arpicmp_be.h"
+#include "vnf_common.h"
+#include "app.h"
+#ifndef VNF_ACL
+#include "lib_icmpv6.h"
+#endif
+
+uint8_t TXRX_DEBUG;
+int pkt_burst_cnt;
+
+struct pipeline_txrx {
+       struct pipeline p;
+       pipeline_msg_req_handler
+               custom_handlers[PIPELINE_TXRX_MSG_REQS];
+       uint64_t receivedPktCount;
+       uint64_t droppedPktCount;
+       uint8_t links_map[PIPELINE_MAX_PORT_IN];
+       uint8_t outport_id[PIPELINE_MAX_PORT_IN];
+       uint8_t pipeline_num;
+       uint8_t txrx_type;
+} __rte_cache_aligned;
+
+enum{
+TYPE_TXTX,
+TYPE_RXRX,
+};
+static void *pipeline_txrx_msg_req_custom_handler(struct pipeline *p,
+                                                       void *msg);
+
+static pipeline_msg_req_handler handlers[] = {
+       [PIPELINE_MSG_REQ_PING] =
+               pipeline_msg_req_ping_handler,
+       [PIPELINE_MSG_REQ_STATS_PORT_IN] =
+               pipeline_msg_req_stats_port_in_handler,
+       [PIPELINE_MSG_REQ_STATS_PORT_OUT] =
+               pipeline_msg_req_stats_port_out_handler,
+       [PIPELINE_MSG_REQ_STATS_TABLE] =
+               pipeline_msg_req_stats_table_handler,
+       [PIPELINE_MSG_REQ_PORT_IN_ENABLE] =
+               pipeline_msg_req_port_in_enable_handler,
+       [PIPELINE_MSG_REQ_PORT_IN_DISABLE] =
+               pipeline_msg_req_port_in_disable_handler,
+       [PIPELINE_MSG_REQ_CUSTOM] =
+               pipeline_txrx_msg_req_custom_handler,
+
+};
+
+static void *pipeline_txrx_msg_req_entry_dbg_handler(struct pipeline *p,
+                                                                void *msg);
+static void *pipeline_txrx_msg_req_entry_dbg_handler(
+       __rte_unused struct pipeline *p,
+       __rte_unused void *msg)
+{
+       /*have to handle dbg commands*/
+       return NULL;
+}
+
+static __rte_unused pipeline_msg_req_handler custom_handlers[] = {
+       [PIPELINE_TXRX_MSG_REQ_ENTRY_DBG] =
+                       pipeline_txrx_msg_req_entry_dbg_handler,
+};
+
+/**
+ * Function for pipeline custom handlers
+ *
+ * @param pipeline
+ *  A void pointer to pipeline
+ * @param msg
+ *  void pointer for incoming data
+ *
+ * @return
+ *  void pointer of response
+ */
+void *pipeline_txrx_msg_req_custom_handler(struct pipeline *p, void *msg)
+{
+       struct pipeline_txrx *p_txrx = (struct pipeline_txrx *)p;
+       struct pipeline_custom_msg_req *req = msg;
+       pipeline_msg_req_handler f_handle;
+
+       f_handle = (req->subtype < PIPELINE_TXRX_MSG_REQS) ?
+                       p_txrx->custom_handlers[req->subtype] :
+                       pipeline_msg_req_invalid_handler;
+
+       if (f_handle == NULL)
+               f_handle = pipeline_msg_req_invalid_handler;
+
+       return f_handle(p, req);
+}
+
+/* Not needed as no arguments are needed for TxRX
+ * ARP arguments are handled in ARP module
+ */
+int
+pipeline_txrx_parse_args(struct pipeline_txrx *p,
+                        struct pipeline_params *params);
+int
+pipeline_txrx_parse_args(struct pipeline_txrx *p,
+                        struct pipeline_params *params)
+{
+       uint32_t i;
+       uint8_t txrx_type_present = 0;
+
+       if (TXRX_DEBUG > 2)
+               printf("TXRX pipeline_txrx_parse_args params->n_args: %d\n",
+                       params->n_args);
+
+       for (i = 0; i < params->n_args; i++) {
+               char *arg_name = params->args_name[i];
+               char *arg_value = params->args_value[i];
+
+               if (TXRX_DEBUG > 2)
+                       printf("TXRX args[%d]: %s %d, %s\n", i, arg_name,
+                               atoi(arg_value), arg_value);
+
+                /* txrx_type = val */
+               if (strcmp(arg_name, "pipeline_txrx_type") == 0) {
+                       if (txrx_type_present)
+                               return -1;
+                        txrx_type_present = 1;
+
+
+                       if (strcmp(arg_value, "TXTX") == 0) {
+                               p->txrx_type = TYPE_TXTX;
+                               printf("pipeline_txrx_type is TXTX\n");
+                       }
+                       if (strcmp(arg_value, "RXRX") == 0) {
+                               p->txrx_type = TYPE_RXRX;
+                               printf("pipeline_txrx_type is RXRX\n");
+                       }
+                       continue;
+               }
+       }
+
+       if (!txrx_type_present) {
+               printf("TXRX type not specified\n");
+               return -1;
+       }
+
+       return 0;
+
+}
+
+uint32_t txrx_pkt_print_count;
+static inline void
+pkt_work_txrx(struct rte_mbuf *pkt, uint32_t pkt_num, void *arg)
+{
+
+       struct pipeline_txrx_in_port_h_arg *ap = arg;
+       struct pipeline_txrx *p_txrx = (struct pipeline_txrx *)ap->p;
+       uint8_t solicited_node_multicast_addr[16] =
+                                       {0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x00, 0x00, 0x00};
+
+       p_txrx->receivedPktCount++;
+
+       if (p_txrx->txrx_type == TYPE_TXTX)
+               return;
+
+       uint8_t in_port_id = pkt->port;
+       uint32_t eth_proto_offset = MBUF_HDR_ROOM + 12;
+
+       uint32_t pkt_mask = 1 << pkt_num;
+       /* ARP outport number */
+       uint32_t out_port = p_txrx->p.n_ports_out - 1;
+
+       uint16_t *eth_proto =
+                       RTE_MBUF_METADATA_UINT16_PTR(pkt, eth_proto_offset);
+
+       uint8_t *protocol;
+       uint32_t prot_offset =
+                       MBUF_HDR_ROOM + ETH_HDR_SIZE + IP_HDR_PROTOCOL_OFST;
+
+       #ifdef IPV6
+       struct ipv6_hdr *ipv6_h;
+       ipv6_h = rte_pktmbuf_mtod_offset (pkt, struct ipv6_hdr *, sizeof(struct ether_hdr));
+       uint32_t prot_offset_ipv6 =
+                        MBUF_HDR_ROOM + ETH_HDR_SIZE + IPV6_HDR_PROTOCOL_OFST;
+
+       if (rte_be_to_cpu_16(*eth_proto) == ETHER_TYPE_IPv6)
+               protocol = RTE_MBUF_METADATA_UINT8_PTR(pkt, prot_offset_ipv6);
+       else
+               protocol = RTE_MBUF_METADATA_UINT8_PTR(pkt, prot_offset);
+       #else
+       protocol = RTE_MBUF_METADATA_UINT8_PTR(pkt, prot_offset);
+       #endif
+
+
+       if ((TXRX_DEBUG > 2) && (txrx_pkt_print_count < 10)) {
+               print_pkt1(pkt);
+               txrx_pkt_print_count++;
+               printf("\nEth Typ %x, Prot %x, ETH_TYPE_ARP %x, "
+                       "ETH_TYPE_IPV4 %x, IP_PROTOCOL_ICMP %x\n",
+                                rte_be_to_cpu_16(*eth_proto), *protocol, ETH_TYPE_ARP,
+                                ETH_TYPE_IPV4, IP_PROTOCOL_ICMP);
+       }
+       /* Classifier for ICMP pass-through*/
+       struct app_link_params *link;
+
+       link = &myApp->link_params[in_port_id];
+
+       /* header room + eth hdr size + src_aadr offset in ip header */
+       uint32_t dst_addr_offset =
+                       MBUF_HDR_ROOM + ETH_HDR_SIZE + IP_HDR_DST_ADR_OFST;
+       uint32_t *dst_addr = RTE_MBUF_METADATA_UINT32_PTR(pkt, dst_addr_offset);
+
+       if (TXRX_DEBUG > 2)
+               if (rte_be_to_cpu_16(*eth_proto) == ETH_TYPE_IPV4)
+                       printf ("%s: linkIp: %x, dst_addr: %x\n", __FUNCTION__, link->ip, *dst_addr);
+
+       #if 1
+       switch (rte_be_to_cpu_16(*eth_proto)) {
+       case ETH_TYPE_ARP:
+               rte_pipeline_port_out_packet_insert(p_txrx->p.p,
+                       out_port, pkt);
+               rte_pipeline_ah_packet_drop(p_txrx->p.p, pkt_mask);
+       break;
+
+       case ETH_TYPE_IPV4:
+               if ((*protocol == IP_PROTOCOL_ICMP)  &&
+                       (link->ip == rte_be_to_cpu_32(*dst_addr))) {
+                       if (is_phy_port_privte(pkt->port)) {
+                               rte_pipeline_port_out_packet_insert(
+                                       p_txrx->p.p,
+                                       out_port, pkt);
+                               rte_pipeline_ah_packet_drop(
+                                       p_txrx->p.p,
+                                       pkt_mask);
+                       }
+               }
+
+       break;
+
+       #ifdef IPV6
+       case ETH_TYPE_IPV6:
+               if (*protocol == ICMPV6_PROTOCOL_ID) {
+                       #ifndef VNF_ACL
+                       if (!memcmp(ipv6_h->dst_addr, link->ipv6, 16)
+                       || !memcmp(ipv6_h->dst_addr, solicited_node_multicast_addr, 13)) {
+                       #endif
+                               rte_pipeline_port_out_packet_insert(p_txrx->p.p,
+                                       out_port, pkt);
+                               rte_pipeline_ah_packet_drop(p_txrx->p.p, pkt_mask);
+                       #ifndef VNF_ACL
+                       } else {
+                               printf("Dropping the IPv6 pkt\n");
+                               rte_pipeline_ah_packet_drop(p_txrx->p.p, pkt_mask);
+                       }
+                       #endif
+               }
+       break;
+       #endif
+
+       default: /* Not valid pkt */
+               printf("Dropping the pkt\n");
+               rte_pipeline_ah_packet_drop(p_txrx->p.p, pkt_mask);
+
+       }
+       #endif
+
+}
+
+static inline void
+pkt4_work_txrx(struct rte_mbuf **pkt, uint32_t pkt_num, void *arg)
+{
+       struct pipeline_txrx_in_port_h_arg *ap = arg;
+       struct pipeline_txrx *p_txrx = (struct pipeline_txrx *)ap->p;
+       uint8_t solicited_node_multicast_addr[16] =
+                                       {0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x01, 0xff, 0x00, 0x00, 0x00};
+
+       if (p_txrx->txrx_type == TYPE_TXTX)
+               return;
+
+       uint16_t in_port_id = (*pkt)->port;
+       uint32_t eth_proto_offset = MBUF_HDR_ROOM + 12;
+
+
+       uint32_t pkt_mask0 = 1 << pkt_num;
+       uint32_t pkt_mask1 = 1 << (pkt_num + 1);
+       uint32_t pkt_mask2 = 1 << (pkt_num + 2);
+       uint32_t pkt_mask3 = 1 << (pkt_num + 3);
+
+       /* ARP outport number */
+       uint32_t out_port = p_txrx->p.n_ports_out - 1;
+
+       uint16_t *eth_proto0 =
+                       RTE_MBUF_METADATA_UINT16_PTR(pkt[0], eth_proto_offset);
+       uint16_t *eth_proto1 =
+                       RTE_MBUF_METADATA_UINT16_PTR(pkt[1], eth_proto_offset);
+       uint16_t *eth_proto2 =
+                       RTE_MBUF_METADATA_UINT16_PTR(pkt[2], eth_proto_offset);
+       uint16_t *eth_proto3 =
+                       RTE_MBUF_METADATA_UINT16_PTR(pkt[3], eth_proto_offset);
+
+       uint8_t *protocol0, *protocol1, *protocol2, *protocol3;
+       uint32_t prot_offset =
+                       MBUF_HDR_ROOM + ETH_HDR_SIZE + IP_HDR_PROTOCOL_OFST;
+
+       #ifdef IPV6
+       struct ipv6_hdr *ipv6_h0, *ipv6_h1, *ipv6_h2, *ipv6_h3;
+       ipv6_h0 = rte_pktmbuf_mtod_offset (pkt[0], struct ipv6_hdr *, sizeof(struct ether_hdr));
+       uint32_t prot_offset_ipv6 =
+                       MBUF_HDR_ROOM + ETH_HDR_SIZE + IPV6_HDR_PROTOCOL_OFST;
+
+/* --0-- */
+       if (rte_be_to_cpu_16(*eth_proto0) == ETHER_TYPE_IPv6)
+               protocol0 =
+                               RTE_MBUF_METADATA_UINT8_PTR(pkt[0], prot_offset_ipv6);
+       else
+               protocol0 = RTE_MBUF_METADATA_UINT8_PTR(pkt[0], prot_offset);
+
+/* --1-- */
+       ipv6_h1 = rte_pktmbuf_mtod_offset (pkt[1], struct ipv6_hdr *, sizeof(struct ether_hdr));
+       if (rte_be_to_cpu_16(*eth_proto1) == ETHER_TYPE_IPv6)
+               protocol1 =
+                               RTE_MBUF_METADATA_UINT8_PTR(pkt[1], prot_offset_ipv6);
+       else
+               protocol1 = RTE_MBUF_METADATA_UINT8_PTR(pkt[1], prot_offset);
+
+/* --2-- */
+       ipv6_h2 = rte_pktmbuf_mtod_offset (pkt[2], struct ipv6_hdr *, sizeof(struct ether_hdr));
+       if (rte_be_to_cpu_16(*eth_proto2) == ETHER_TYPE_IPv6)
+               protocol2 =
+                               RTE_MBUF_METADATA_UINT8_PTR(pkt[2], prot_offset_ipv6);
+       else
+               protocol2 = RTE_MBUF_METADATA_UINT8_PTR(pkt[2], prot_offset);
+
+/* --3-- */
+       ipv6_h3 = rte_pktmbuf_mtod_offset (pkt[3], struct ipv6_hdr *, sizeof(struct ether_hdr));
+       if (rte_be_to_cpu_16(*eth_proto3) == ETHER_TYPE_IPv6)
+               protocol3 =
+                               RTE_MBUF_METADATA_UINT8_PTR(pkt[3], prot_offset_ipv6);
+       else
+               protocol3 = RTE_MBUF_METADATA_UINT8_PTR(pkt[3], prot_offset);
+       #else
+       protocol0 = RTE_MBUF_METADATA_UINT8_PTR(pkt[0], prot_offset);
+       protocol1 = RTE_MBUF_METADATA_UINT8_PTR(pkt[1], prot_offset);
+       protocol2 = RTE_MBUF_METADATA_UINT8_PTR(pkt[2], prot_offset);
+       protocol3 = RTE_MBUF_METADATA_UINT8_PTR(pkt[3], prot_offset);
+       #endif
+
+       if ((TXRX_DEBUG > 2) && (txrx_pkt_print_count < 10)) {
+               print_pkt1(pkt[0]);
+               txrx_pkt_print_count++;
+               printf("\nEth Typ %x, Prot %x, ETH_TYPE_ARP %x, "
+                       "ETH_TYPE_IPV4 %x, IP_PROTOCOL_ICMP %x\n",
+                                rte_be_to_cpu_16(*eth_proto0), *protocol0, ETH_TYPE_ARP,
+                                ETH_TYPE_IPV4, IP_PROTOCOL_ICMP);
+       }
+
+       struct app_link_params *link;
+
+       link = &myApp->link_params[in_port_id];
+
+       /* header room + eth hdr size + src_aadr offset in ip header */
+       uint32_t dst_addr_offset0 =
+                       MBUF_HDR_ROOM + ETH_HDR_SIZE + IP_HDR_DST_ADR_OFST;
+       uint32_t *dst_addr0 =
+                       RTE_MBUF_METADATA_UINT32_PTR(pkt[0], dst_addr_offset0);
+
+       if (TXRX_DEBUG > 2)
+               if (rte_be_to_cpu_16(*eth_proto0) == ETH_TYPE_IPV4)
+                       printf ("%s: linkIp: %x, dst_addr0: %x\n", __FUNCTION__, link->ip, *dst_addr0);
+
+       #if 1
+       switch (rte_be_to_cpu_16(*eth_proto0)) {
+       case ETH_TYPE_ARP:
+               rte_pipeline_port_out_packet_insert(p_txrx->p.p,
+                       out_port, pkt[0]);
+               rte_pipeline_ah_packet_drop(p_txrx->p.p, pkt_mask0);
+       break;
+
+       case ETH_TYPE_IPV4:
+               if ((*protocol0 == IP_PROTOCOL_ICMP)  &&
+                       (link->ip == rte_be_to_cpu_32(*dst_addr0))) {
+                       if (is_phy_port_privte(pkt[0]->port)) {
+                               rte_pipeline_port_out_packet_insert(
+                                       p_txrx->p.p, out_port, pkt[0]);
+                               rte_pipeline_ah_packet_drop(
+                                       p_txrx->p.p, pkt_mask0);
+                       }
+               }
+
+       break;
+
+       #ifdef IPV6
+       case ETH_TYPE_IPV6:
+               if (*protocol0 == ICMPV6_PROTOCOL_ID) {
+                       #ifndef VNF_ACL
+                       if (!memcmp(ipv6_h0->dst_addr, link->ipv6, 16)
+                               || !memcmp(ipv6_h0->dst_addr, solicited_node_multicast_addr, 13)) {
+                       #endif
+                               rte_pipeline_port_out_packet_insert(p_txrx->p.p,
+                                       out_port, pkt[0]);
+                               rte_pipeline_ah_packet_drop(p_txrx->p.p, pkt_mask0);
+
+                       #ifndef VNF_ACL
+                       } else {
+                               printf("Dropping the IPv6 pkt\n");
+                               rte_pipeline_ah_packet_drop(p_txrx->p.p, pkt_mask0);
+                       }
+                       #endif
+               }
+       break;
+       #endif
+
+       default: /* Not valid pkt */
+               rte_pipeline_ah_packet_drop(p_txrx->p.p, pkt_mask0);
+
+       }
+       #endif
+
+       if ((TXRX_DEBUG > 2) && (txrx_pkt_print_count < 10)) {
+               print_pkt1(pkt[1]);
+               txrx_pkt_print_count++;
+               printf("\nEth Typ %x, Prot %x, ETH_TYPE_ARP %x, "
+                       "ETH_TYPE_IPV4 %x, IP_PROTOCOL_ICMP %x\n",
+                                rte_be_to_cpu_16(*eth_proto1), *protocol1, ETH_TYPE_ARP,
+                                ETH_TYPE_IPV4, IP_PROTOCOL_ICMP);
+       }
+
+       /* header room + eth hdr size + src_aadr offset in ip header */
+       uint32_t dst_addr_offset1 =
+                       MBUF_HDR_ROOM + ETH_HDR_SIZE + IP_HDR_DST_ADR_OFST;
+       uint32_t *dst_addr1 =
+                       RTE_MBUF_METADATA_UINT32_PTR(pkt[1], dst_addr_offset1);
+
+       if (TXRX_DEBUG > 2)
+               if (rte_be_to_cpu_16(*eth_proto1) == ETH_TYPE_IPV4)
+                       printf ("%s: linkIp: %x, dst_addr1: %x\n", __FUNCTION__, link->ip, *dst_addr1);
+
+       switch (rte_be_to_cpu_16(*eth_proto1)) {
+       case ETH_TYPE_ARP:
+               rte_pipeline_port_out_packet_insert(p_txrx->p.p,
+                       out_port, pkt[1]);
+               rte_pipeline_ah_packet_drop(p_txrx->p.p, pkt_mask1);
+       break;
+
+       case ETH_TYPE_IPV4:
+               if ((*protocol1 == IP_PROTOCOL_ICMP)  &&
+                       (link->ip == rte_be_to_cpu_32(*dst_addr1))) {
+                       if (is_phy_port_privte(pkt[1]->port)) {
+                               rte_pipeline_port_out_packet_insert(
+                                       p_txrx->p.p,
+                                       out_port, pkt[1]);
+                               rte_pipeline_ah_packet_drop(
+                                       p_txrx->p.p,
+                                       pkt_mask1);
+                       }
+               }
+
+       break;
+
+       #ifdef IPV6
+       case ETH_TYPE_IPV6:
+               if (*protocol1 == ICMPV6_PROTOCOL_ID) {
+                       #ifndef VNF_ACL
+                       if (!memcmp(ipv6_h1->dst_addr, link->ipv6, 16)
+                               || !memcmp(ipv6_h1->dst_addr, solicited_node_multicast_addr, 13)) {
+                       #endif
+                               rte_pipeline_port_out_packet_insert(p_txrx->p.p,
+                                       out_port, pkt[1]);
+                               rte_pipeline_ah_packet_drop(p_txrx->p.p, pkt_mask1);
+                       #ifndef VNF_ACL
+                       } else {
+                               printf("Dropping the IPv6 pkt\n");
+                               rte_pipeline_ah_packet_drop(p_txrx->p.p, pkt_mask1);
+                       }
+                       #endif
+               }
+       break;
+       #endif
+
+       default: /* Not valid pkt */
+               rte_pipeline_ah_packet_drop(p_txrx->p.p, pkt_mask1);
+
+       }
+
+       if ((TXRX_DEBUG > 2) && (txrx_pkt_print_count < 10)) {
+               print_pkt1(pkt[2]);
+               txrx_pkt_print_count++;
+               printf("\nEth Typ %x, Prot %x, ETH_TYPE_ARP %x, "
+                       "ETH_TYPE_IPV4 %x, IP_PROTOCOL_ICMP %x\n",
+                                rte_be_to_cpu_16(*eth_proto2), *protocol2, ETH_TYPE_ARP,
+                                ETH_TYPE_IPV4, IP_PROTOCOL_ICMP);
+       }
+
+       /* header room + eth hdr size + src_aadr offset in ip header */
+       uint32_t dst_addr_offset2 =
+                       MBUF_HDR_ROOM + ETH_HDR_SIZE + IP_HDR_DST_ADR_OFST;
+       uint32_t *dst_addr2 =
+                       RTE_MBUF_METADATA_UINT32_PTR(pkt[2], dst_addr_offset2);
+
+       if (TXRX_DEBUG > 2)
+               if (rte_be_to_cpu_16(*eth_proto2) == ETH_TYPE_IPV4)
+                       printf ("%s: linkIp: %x, dst_addr2: %x\n", __FUNCTION__, link->ip, *dst_addr2);
+
+       switch (rte_be_to_cpu_16(*eth_proto2)) {
+       case ETH_TYPE_ARP:
+               rte_pipeline_port_out_packet_insert(p_txrx->p.p,
+                       out_port, pkt[2]);
+               rte_pipeline_ah_packet_drop(p_txrx->p.p, pkt_mask2);
+       break;
+
+       case ETH_TYPE_IPV4:
+               if ((*protocol2 == IP_PROTOCOL_ICMP)  &&
+                       (link->ip == rte_be_to_cpu_32(*dst_addr2))) {
+                       if (is_phy_port_privte(pkt[2]->port)) {
+                               rte_pipeline_port_out_packet_insert(
+                                       p_txrx->p.p,
+                                       out_port, pkt[2]);
+                               rte_pipeline_ah_packet_drop(
+                                       p_txrx->p.p,
+                                       pkt_mask2);
+                       }
+               }
+
+       break;
+
+       #ifdef IPV6
+       case ETH_TYPE_IPV6:
+               if (*protocol2 == ICMPV6_PROTOCOL_ID) {
+                       #ifndef VNF_ACL
+                       if (!memcmp(ipv6_h2->dst_addr, link->ipv6, 16)
+                               || !memcmp(ipv6_h2->dst_addr, solicited_node_multicast_addr, 13)) {
+                       #endif
+                               rte_pipeline_port_out_packet_insert(p_txrx->p.p,
+                                       out_port, pkt[2]);
+                               rte_pipeline_ah_packet_drop(p_txrx->p.p, pkt_mask2);
+                       #ifndef VNF_ACL
+                       } else {
+                               printf("Dropping the IPv6 pkt\n");
+                               rte_pipeline_ah_packet_drop(p_txrx->p.p, pkt_mask2);
+                       }
+                       #endif
+               }
+       break;
+       #endif
+
+       default: /* Not valid pkt */
+               rte_pipeline_ah_packet_drop(p_txrx->p.p, pkt_mask2);
+
+       }
+
+       if ((TXRX_DEBUG > 2) && (txrx_pkt_print_count < 10)) {
+               print_pkt1(pkt[3]);
+               txrx_pkt_print_count++;
+               printf("\nEth Typ %x, Prot %x, ETH_TYPE_ARP %x, "
+                       "ETH_TYPE_IPV4 %x, IP_PROTOCOL_ICMP %x\n",
+                                rte_be_to_cpu_16(*eth_proto3), *protocol3, ETH_TYPE_ARP,
+                                ETH_TYPE_IPV4, IP_PROTOCOL_ICMP);
+       }
+
+       /* header room + eth hdr size + src_aadr offset in ip header */
+       uint32_t dst_addr_offset3 =
+                       MBUF_HDR_ROOM + ETH_HDR_SIZE + IP_HDR_DST_ADR_OFST;
+       uint32_t *dst_addr3 =
+                       RTE_MBUF_METADATA_UINT32_PTR(pkt, dst_addr_offset3);
+
+       if (TXRX_DEBUG > 2)
+               if (rte_be_to_cpu_16(*eth_proto3) == ETH_TYPE_IPV4)
+                       printf ("%s: linkIp: %x, dst_addr3: %x\n", __FUNCTION__, link->ip, *dst_addr3);
+
+       switch (rte_be_to_cpu_16(*eth_proto3)) {
+       case ETH_TYPE_ARP:
+               rte_pipeline_port_out_packet_insert(p_txrx->p.p,
+                       out_port, pkt[3]);
+               rte_pipeline_ah_packet_drop(p_txrx->p.p, pkt_mask3);
+       break;
+
+       case ETH_TYPE_IPV4:
+               if ((*protocol3 == IP_PROTOCOL_ICMP)  &&
+                       (link->ip == rte_be_to_cpu_32(*dst_addr3))) {
+                       if (is_phy_port_privte(pkt[3]->port)) {
+                               rte_pipeline_port_out_packet_insert(
+                                       p_txrx->p.p,
+                                       out_port, pkt[3]);
+                               rte_pipeline_ah_packet_drop(
+                                       p_txrx->p.p,
+                                       pkt_mask3);
+                       }
+               }
+
+       break;
+
+       #ifdef IPV6
+       case ETH_TYPE_IPV6:
+               if (*protocol3 == ICMPV6_PROTOCOL_ID) {
+                       #ifndef VNF_ACL
+                       if (!memcmp(ipv6_h3->dst_addr, link->ipv6, 16)
+                               || !memcmp(ipv6_h3->dst_addr, solicited_node_multicast_addr, 13)) {
+                       #endif
+                               rte_pipeline_port_out_packet_insert(p_txrx->p.p,
+                                       out_port, pkt[3]);
+                               rte_pipeline_ah_packet_drop(p_txrx->p.p, pkt_mask3);
+                       #ifndef VNF_ACL
+                       } else {
+                               printf("Dropping the IPv6 pkt\n");
+                               rte_pipeline_ah_packet_drop(p_txrx->p.p, pkt_mask3);
+                       }
+                       #endif
+               }
+       break;
+       #endif
+
+       default: /* Not valid pkt */
+               rte_pipeline_ah_packet_drop(p_txrx->p.p, pkt_mask3);
+
+       }
+
+       p_txrx->receivedPktCount += 4;
+
+}
+
+PIPELINE_TXRX_KEY_PORT_IN_AH(port_in_ah_txrx, pkt_work_txrx, pkt4_work_txrx);
+
+static void *pipeline_txrx_init(struct pipeline_params *params,
+                               __rte_unused void *arg)
+{
+       struct pipeline *p;
+       struct pipeline_txrx *p_pt;
+       uint32_t size, i, in_ports_arg_size;
+
+       printf("Start pipeline_txrx_init\n");
+
+       /* Check input arguments */
+       if ((params == NULL) ||
+                       (params->n_ports_in == 0) ||
+                       (params->n_ports_out == 0))
+               return NULL;
+
+       /* Memory allocation */
+       size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct pipeline_txrx));
+       p = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
+       p_pt = (struct pipeline_txrx *)p;
+       if (p == NULL)
+               return NULL;
+
+       PLOG(p, HIGH, "TXRX");
+       strcpy(p->name, params->name);
+       p->log_level = params->log_level;
+
+       p_pt->receivedPktCount = 0;
+       p_pt->droppedPktCount = 0;
+       for (i = 0; i < PIPELINE_MAX_PORT_IN; i++)
+               p_pt->links_map[i] = 0xff;
+
+       p_pt->pipeline_num = 0;
+       printf("txrx initialization of variables done\n");
+
+       /* Parse arguments */
+       if (pipeline_txrx_parse_args(p_pt, params))
+               return NULL;
+
+       /* Pipeline */
+       {
+               struct rte_pipeline_params pipeline_params = {
+                       .name = "TXRX",
+                       .socket_id = params->socket_id,
+                       .offset_port_id = 0,
+               };
+
+               p->p = rte_pipeline_create(&pipeline_params);
+               if (p->p == NULL) {
+                       rte_free(p);
+                       return NULL;
+               }
+       }
+
+       p->n_ports_in = params->n_ports_in;
+       p->n_ports_out = params->n_ports_out;
+       p->n_tables = p->n_ports_in;
+
+       /* Memory allocation for in_port_h_arg */
+       in_ports_arg_size =
+               RTE_CACHE_LINE_ROUNDUP((sizeof
+                                       (struct pipeline_txrx_in_port_h_arg)) *
+                               (params->n_ports_in));
+       struct pipeline_txrx_in_port_h_arg *ap =
+               (struct pipeline_txrx_in_port_h_arg *)rte_zmalloc(NULL,
+                               in_ports_arg_size,
+                               RTE_CACHE_LINE_SIZE);
+       if (ap == NULL)
+               return NULL;
+       /*Input ports */
+       for (i = 0; i < p->n_ports_in; i++) {
+               /* passing our txrx pipeline in call back arg */
+               (ap[i]).p = p_pt;
+               (ap[i]).in_port_id = i;
+               struct rte_pipeline_port_in_params port_params = {
+                       .ops =
+                                       pipeline_port_in_params_get_ops(&params->
+                                                                       port_in[i]),
+                       .arg_create =
+                                       pipeline_port_in_params_convert(&params->
+                                                                       port_in[i]),
+                       .f_action = NULL,
+                       .arg_ah = &(ap[i]),
+                       .burst_size = params->port_in[i].burst_size,
+               };
+
+                       port_params.f_action = port_in_ah_txrx;
+
+               int status = rte_pipeline_port_in_create(p->p,
+                                                        &port_params,
+                                                        &p->port_in_id[i]);
+
+               if (status) {
+                       rte_pipeline_free(p->p);
+                       rte_free(p);
+                       return NULL;
+               }
+       }
+
+       /* Output ports */
+       for (i = 0; i < p->n_ports_out; i++) {
+               struct rte_pipeline_port_out_params port_params = {
+                       .ops =
+                                       pipeline_port_out_params_get_ops(&params->
+                                                                        port_out[i]),
+                       .arg_create =
+                                       pipeline_port_out_params_convert(&params->
+                                                                        port_out[i]),
+                       .f_action = NULL,
+                       .arg_ah = NULL,
+               };
+
+               int status = rte_pipeline_port_out_create(p->p,
+                                                               &port_params,
+                                                               &p->port_out_id[i]);
+
+               if (status) {
+                       rte_pipeline_free(p->p);
+                       rte_free(p);
+                       return NULL;
+               }
+       }
+
+       int pipeline_num = 0;
+       int status = sscanf(params->name, "PIPELINE%d", &pipeline_num);
+       if (status < 0) {
+               printf("Unable to read pipeline number\n");
+               return NULL;
+       }
+       p_pt->pipeline_num = (uint8_t) pipeline_num;
+
+       register_pipeline_Qs(p_pt->pipeline_num, p);
+       set_link_map(p_pt->pipeline_num, p, p_pt->links_map);
+       set_outport_id(p_pt->pipeline_num, p, p_pt->outport_id);
+
+       /* Tables */
+       for (i = 0; i < p->n_ports_in; i++) {
+               struct rte_pipeline_table_params table_params = {
+                       .ops = &rte_table_stub_ops,
+                       .arg_create = NULL,
+                       .f_action_hit = NULL,
+                       .f_action_miss = NULL,
+                       .arg_ah = NULL,
+                       .action_data_size = 0,
+               };
+
+               int status = rte_pipeline_table_create(p->p,
+                                                                        &table_params,
+                                                                        &p->table_id[i]);
+
+               if (status) {
+                       rte_pipeline_free(p->p);
+                       rte_free(p);
+                       return NULL;
+               }
+       }
+
+       /* Connecting input ports to tables */
+       for (i = 0; i < p->n_ports_in; i++) {
+               int status = rte_pipeline_port_in_connect_to_table(p->p,
+                                                                        p->
+                                                                        port_in_id
+                                                                        [i],
+                                                                        p->
+                                                                        table_id[i]);
+
+               if (status) {
+                       rte_pipeline_free(p->p);
+                       rte_free(p);
+                       return NULL;
+               }
+       }
+
+       /* Add entries to tables */
+       for (i = 0; i < p->n_ports_in; i++) {
+               struct rte_pipeline_table_entry default_entry = {
+                       .action = RTE_PIPELINE_ACTION_PORT,
+                       .port_id = p->port_out_id[i],
+               };
+
+               struct rte_pipeline_table_entry *default_entry_ptr;
+
+               int status = rte_pipeline_table_default_entry_add(
+                               p->p,
+                               p->
+                               table_id[i],
+                               &default_entry,
+                               &default_entry_ptr);
+
+               if (status) {
+                       rte_pipeline_free(p->p);
+                       rte_free(p);
+                       return NULL;
+               }
+       }
+
+       /* Enable input ports */
+       for (i = 0; i < p->n_ports_in; i++) {
+               int status = rte_pipeline_port_in_enable(p->p,
+                                                        p->port_in_id[i]);
+
+               if (status) {
+                       rte_pipeline_free(p->p);
+                       rte_free(p);
+                       return NULL;
+               }
+       }
+
+       /* Check pipeline consistency */
+       if (rte_pipeline_check(p->p) < 0) {
+               rte_pipeline_free(p->p);
+               rte_free(p);
+               return NULL;
+       }
+
+       /* Message queues */
+       p->n_msgq = params->n_msgq;
+       for (i = 0; i < p->n_msgq; i++)
+               p->msgq_in[i] = params->msgq_in[i];
+       for (i = 0; i < p->n_msgq; i++)
+               p->msgq_out[i] = params->msgq_out[i];
+
+       /* Message handlers */
+       memcpy(p->handlers, handlers, sizeof(p->handlers));
+
+       return p;
+}
+
+static int pipeline_txrx_free(void *pipeline)
+{
+       struct pipeline *p = (struct pipeline *)pipeline;
+
+       /* Check input arguments */
+       if (p == NULL)
+               return -1;
+
+       /* Free resources */
+       rte_pipeline_free(p->p);
+       rte_free(p);
+       return 0;
+}
+
+static int pipeline_txrx_timer(void *pipeline)
+{
+       struct pipeline *p = (struct pipeline *)pipeline;
+
+       pipeline_msg_req_handle(p);
+       rte_pipeline_flush(p->p);
+
+       return 0;
+}
+
+static int
+pipeline_txrx_track(void *pipeline, uint32_t port_in, uint32_t *port_out)
+{
+       struct pipeline *p = (struct pipeline *)pipeline;
+
+       /* Check input arguments */
+       if ((p == NULL) || (port_in >= p->n_ports_in) || (port_out == NULL))
+               return -1;
+
+       *port_out = port_in / p->n_ports_in;
+       return 0;
+}
+
+struct pipeline_be_ops pipeline_txrx_be_ops = {
+       .f_init = pipeline_txrx_init,
+       .f_free = pipeline_txrx_free,
+       .f_run = NULL,
+       .f_timer = pipeline_txrx_timer,
+       .f_track = pipeline_txrx_track,
+};
diff --git a/common/VIL/pipeline_txrx/pipeline_txrx_be.h b/common/VIL/pipeline_txrx/pipeline_txrx_be.h
new file mode 100644 (file)
index 0000000..f794729
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef __INCLUDE_PIPELINE_TXRX_BE_H__
+#define __INCLUDE_PIPELINE_TXRX_BE_H__
+
+#include "pipeline_common_be.h"
+#define PIPELINE_TXRX_KEY_PORT_IN_AH(f_ah, f_pkt_work, f_pkt4_work)     \
+static int                                                              \
+f_ah(                                                                   \
+       __rte_unused struct rte_pipeline *rte_p,                        \
+       struct rte_mbuf **pkts,                                         \
+       uint32_t n_pkts,                                                \
+       void *arg)                                                      \
+{                                                                       \
+       uint32_t i, j;                                                  \
+                                                                       \
+       for (j = 0; j < n_pkts; j++)                                    \
+               rte_prefetch0(pkts[j]);                                 \
+                                                                       \
+       pkt_burst_cnt = 0;                                              \
+       for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4)                   \
+               f_pkt4_work(&pkts[i], i, arg);                          \
+                                                                       \
+       for ( ; i < n_pkts; i++)                                        \
+               f_pkt_work(pkts[i], i, arg);                            \
+                                                                       \
+                                                                       \
+       return 0;                                                       \
+}
+
+extern struct pipeline_be_ops pipeline_txrx_be_ops;
+/*
+ * Messages
+ */
+enum pipeline_txrx_msg_req_type {
+       PIPELINE_TXRX_MSG_REQ_ENTRY_DBG,
+       PIPELINE_TXRX_MSG_REQS
+};
+/*
+ * MSG ENTRY DBG
+ */
+struct pipeline_txrx_entry_dbg_msg_req {
+       enum pipeline_msg_req_type type;
+       enum pipeline_txrx_msg_req_type subtype;
+
+       /* data */
+       uint8_t data[5];
+};
+/*
+ * TXRX Entry
+ */
+
+struct pipeline_txrx_in_port_h_arg {
+       struct pipeline_txrx *p;
+       uint8_t in_port_id;
+};
+
+struct pipeline_txrx_entry_dbg_msg_rsp {
+       int status;
+};
+
+#endif
diff --git a/common/vnf_common/app.h b/common/vnf_common/app.h
new file mode 100644 (file)
index 0000000..2af62f1
--- /dev/null
@@ -0,0 +1,972 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef __INCLUDE_APP_H__
+#define __INCLUDE_APP_H__
+
+#include <stdint.h>
+#include <string.h>
+
+#include <rte_common.h>
+#include <rte_mempool.h>
+#include <rte_ring.h>
+#include <rte_sched.h>
+#include <rte_timer.h>
+#include <cmdline_parse.h>
+
+#include <rte_ethdev.h>
+
+#include "cpu_core_map.h"
+#include "pipeline.h"
+
+#define APP_PARAM_NAME_SIZE                      PIPELINE_NAME_SIZE
+#define APP_LINK_PCI_BDF_SIZE                    16
+struct app_link_params *fdir_p_link;
+struct app_mempool_params {
+       char *name;
+       uint32_t parsed;
+       uint32_t buffer_size;
+       uint32_t pool_size;
+       uint32_t cache_size;
+       uint32_t cpu_socket_id;
+};
+
+struct app_link_params {
+       char *name;
+       uint32_t parsed;
+       uint32_t pmd_id; /* Generated based on port mask */
+       uint32_t arp_q; /* 0 = Disabled (packets go to default queue 0) */
+       uint32_t tcp_syn_q; /* 0 = Disabled (pkts go to default queue) */
+       uint32_t ip_local_q; /* 0 = Disabled (pkts go to default queue 0) */
+       uint32_t tcp_local_q; /* 0 = Disabled (pkts go to default queue 0) */
+       uint32_t udp_local_q; /* 0 = Disabled (pkts go to default queue 0) */
+       uint32_t sctp_local_q; /* 0 = Disabled (pkts go to default queue 0) */
+       uint32_t state; /* DOWN = 0, UP = 1 */
+       uint32_t ip; /* 0 = Invalid */
+        uint8_t ipv6[16];
+        uint32_t depth;         /* Valid only when IP is valid */
+        uint32_t depth_ipv6;
+       uint64_t mac_addr; /* Read from HW */
+       char pci_bdf[APP_LINK_PCI_BDF_SIZE];
+
+       struct rte_eth_conf conf;
+       uint8_t promisc;
+};
+
+struct app_pktq_hwq_in_params {
+       char *name;
+       uint32_t parsed;
+       uint32_t mempool_id; /* Position in the app->mempool_params */
+       uint32_t size;
+       uint32_t burst;
+
+       struct rte_eth_rxconf conf;
+};
+
+struct app_pktq_hwq_out_params {
+       char *name;
+       uint32_t parsed;
+       uint32_t size;
+       uint32_t burst;
+       uint32_t dropless;
+       uint64_t n_retries;
+       struct rte_eth_txconf conf;
+};
+
+struct app_pktq_swq_params {
+       char *name;
+       uint32_t parsed;
+       uint32_t size;
+       uint32_t burst_read;
+       uint32_t burst_write;
+       uint32_t dropless;
+       uint64_t n_retries;
+       uint32_t cpu_socket_id;
+       uint32_t ipv4_frag;
+       uint32_t ipv6_frag;
+       uint32_t ipv4_ras;
+       uint32_t ipv6_ras;
+       uint32_t mtu;
+       uint32_t metadata_size;
+       uint32_t mempool_direct_id;
+       uint32_t mempool_indirect_id;
+};
+
+#ifndef APP_FILE_NAME_SIZE
+#define APP_FILE_NAME_SIZE                       256
+#endif
+
+#ifndef APP_MAX_SCHED_SUBPORTS
+#define APP_MAX_SCHED_SUBPORTS                   8
+#endif
+
+#ifndef APP_MAX_SCHED_PIPES
+#define APP_MAX_SCHED_PIPES                      4096
+#endif
+
+struct app_pktq_tm_params {
+       char *name;
+       uint32_t parsed;
+       const char *file_name;
+       struct rte_sched_port_params sched_port_params;
+       struct rte_sched_subport_params
+               sched_subport_params[APP_MAX_SCHED_SUBPORTS];
+       struct rte_sched_pipe_params
+               sched_pipe_profiles[RTE_SCHED_PIPE_PROFILES_PER_PORT];
+       int sched_pipe_to_profile[APP_MAX_SCHED_SUBPORTS * APP_MAX_SCHED_PIPES];
+       uint32_t burst_read;
+       uint32_t burst_write;
+};
+
+struct app_pktq_source_params {
+       char *name;
+       uint32_t parsed;
+       uint32_t mempool_id; /* Position in the app->mempool_params array */
+       uint32_t burst;
+       char *file_name; /* Full path of PCAP file to be copied to mbufs */
+       uint32_t n_bytes_per_pkt;
+};
+
+struct app_pktq_sink_params {
+       char *name;
+       uint8_t parsed;
+       char *file_name; /* Full path of PCAP file to be copied to mbufs */
+       uint32_t n_pkts_to_dump;
+};
+
+struct app_msgq_params {
+       char *name;
+       uint32_t parsed;
+       uint32_t size;
+       uint32_t cpu_socket_id;
+};
+
+enum app_pktq_in_type {
+       APP_PKTQ_IN_HWQ,
+       APP_PKTQ_IN_SWQ,
+       APP_PKTQ_IN_TM,
+       APP_PKTQ_IN_SOURCE,
+};
+
+struct app_pktq_in_params {
+       enum app_pktq_in_type type;
+       uint32_t id; /* Position in the appropriate app array */
+};
+
+enum app_pktq_out_type {
+       APP_PKTQ_OUT_HWQ,
+       APP_PKTQ_OUT_SWQ,
+       APP_PKTQ_OUT_TM,
+       APP_PKTQ_OUT_SINK,
+};
+
+struct app_pktq_out_params {
+       enum app_pktq_out_type type;
+       uint32_t id; /* Position in the appropriate app array */
+};
+
+#ifndef APP_PIPELINE_TYPE_SIZE
+#define APP_PIPELINE_TYPE_SIZE                   64
+#endif
+
+#define APP_MAX_PIPELINE_PKTQ_IN                 PIPELINE_MAX_PORT_IN
+#define APP_MAX_PIPELINE_PKTQ_OUT                PIPELINE_MAX_PORT_OUT
+#define APP_MAX_PIPELINE_MSGQ_IN                 PIPELINE_MAX_MSGQ_IN
+#define APP_MAX_PIPELINE_MSGQ_OUT                PIPELINE_MAX_MSGQ_OUT
+
+#define APP_MAX_PIPELINE_ARGS                    PIPELINE_MAX_ARGS
+
+struct app_pipeline_params {
+       char *name;
+       uint8_t parsed;
+
+       char type[APP_PIPELINE_TYPE_SIZE];
+
+       uint32_t socket_id;
+       uint32_t core_id;
+       uint32_t hyper_th_id;
+
+       struct app_pktq_in_params pktq_in[APP_MAX_PIPELINE_PKTQ_IN];
+       struct app_pktq_out_params pktq_out[APP_MAX_PIPELINE_PKTQ_OUT];
+       uint32_t msgq_in[APP_MAX_PIPELINE_MSGQ_IN];
+       uint32_t msgq_out[APP_MAX_PIPELINE_MSGQ_OUT];
+
+       uint32_t n_pktq_in;
+       uint32_t n_pktq_out;
+       uint32_t n_msgq_in;
+       uint32_t n_msgq_out;
+
+       uint32_t timer_period;
+
+       char *args_name[APP_MAX_PIPELINE_ARGS];
+       char *args_value[APP_MAX_PIPELINE_ARGS];
+       uint32_t n_args;
+};
+
+struct app_pipeline_data {
+       void *be;
+       void *fe;
+       struct pipeline_type *ptype;
+       uint64_t timer_period;
+       uint32_t enabled;
+};
+
+struct app_thread_pipeline_data {
+       uint32_t pipeline_id;
+       void *be;
+       pipeline_be_op_run f_run;
+       pipeline_be_op_timer f_timer;
+       uint64_t timer_period;
+       uint64_t deadline;
+};
+
+#ifndef APP_MAX_THREAD_PIPELINES
+#define APP_MAX_THREAD_PIPELINES                 16
+#endif
+
+#ifndef APP_THREAD_TIMER_PERIOD
+#define APP_THREAD_TIMER_PERIOD                  1
+#endif
+
+struct app_thread_data {
+       struct app_thread_pipeline_data regular[APP_MAX_THREAD_PIPELINES];
+       struct app_thread_pipeline_data custom[APP_MAX_THREAD_PIPELINES];
+
+       uint32_t n_regular;
+       uint32_t n_custom;
+
+       uint64_t timer_period;
+       uint64_t thread_req_deadline;
+
+       uint64_t deadline;
+
+       struct rte_ring *msgq_in;
+       struct rte_ring *msgq_out;
+
+       uint64_t headroom_time;
+       uint64_t headroom_cycles;
+       double headroom_ratio;
+};
+
+#ifndef APP_MAX_LINKS
+#define APP_MAX_LINKS                            16
+#endif
+
+struct app_eal_params {
+       /* Map lcore set to physical cpu set */
+       char *coremap;
+
+       /* Core ID that is used as master */
+       uint32_t master_lcore_present;
+       uint32_t master_lcore;
+
+       /* Number of memory channels */
+       uint32_t channels_present;
+       uint32_t channels;
+
+       /* Memory to allocate (see also --socket-mem) */
+       uint32_t memory_present;
+       uint32_t memory;
+
+       /* Force number of memory ranks (don't detect) */
+       uint32_t ranks_present;
+       uint32_t ranks;
+
+       /* Add a PCI device in black list. */
+       char *pci_blacklist[APP_MAX_LINKS];
+
+       /* Add a PCI device in white list. */
+       char *pci_whitelist[APP_MAX_LINKS];
+
+       /* Add a virtual device. */
+       char *vdev[APP_MAX_LINKS];
+
+        /* Use VMware TSC map instead of native RDTSC */
+       uint32_t vmware_tsc_map_present;
+       int vmware_tsc_map;
+
+        /* Type of this process (primary|secondary|auto) */
+       char *proc_type;
+
+        /* Set syslog facility */
+       char *syslog;
+
+       /* Set default log level */
+       uint32_t log_level_present;
+       uint32_t log_level;
+
+       /* Display version information on startup */
+       uint32_t version_present;
+       int version;
+
+       /* This help */
+       uint32_t help_present;
+       int help;
+
+        /* Use malloc instead of hugetlbfs */
+       uint32_t no_huge_present;
+       int no_huge;
+
+       /* Disable PCI */
+       uint32_t no_pci_present;
+       int no_pci;
+
+       /* Disable HPET */
+       uint32_t no_hpet_present;
+       int no_hpet;
+
+       /* No shared config (mmap'd files) */
+       uint32_t no_shconf_present;
+       int no_shconf;
+
+       /* Add driver */
+       char *add_driver;
+
+       /*  Memory to allocate on sockets (comma separated values)*/
+       char *socket_mem;
+
+       /* Directory where hugetlbfs is mounted */
+       char *huge_dir;
+
+       /* Prefix for hugepage filenames */
+       char *file_prefix;
+
+       /* Base virtual address */
+       char *base_virtaddr;
+
+       /* Create /dev/uioX (usually done by hotplug) */
+       uint32_t create_uio_dev_present;
+       int create_uio_dev;
+
+       /* Interrupt mode for VFIO (legacy|msi|msix) */
+       char *vfio_intr;
+
+       /* Support running on Xen dom0 without hugetlbfs */
+       uint32_t xen_dom0_present;
+       int xen_dom0;
+};
+
+#ifndef APP_APPNAME_SIZE
+#define APP_APPNAME_SIZE                         256
+#endif
+
+#ifndef APP_MAX_MEMPOOLS
+#define APP_MAX_MEMPOOLS                         8
+#endif
+
+#ifndef APP_LINK_MAX_HWQ_IN
+#define APP_LINK_MAX_HWQ_IN                      64
+#endif
+
+#ifndef APP_LINK_MAX_HWQ_OUT
+#define APP_LINK_MAX_HWQ_OUT                     64
+#endif
+
+#define APP_MAX_HWQ_IN                     (APP_MAX_LINKS * APP_LINK_MAX_HWQ_IN)
+
+#define APP_MAX_HWQ_OUT                   (APP_MAX_LINKS * APP_LINK_MAX_HWQ_OUT)
+
+#ifndef APP_MAX_PKTQ_SWQ
+#define APP_MAX_PKTQ_SWQ                         256
+#endif
+
+#define APP_MAX_PKTQ_TM                          APP_MAX_LINKS
+
+#ifndef APP_MAX_PKTQ_SOURCE
+#define APP_MAX_PKTQ_SOURCE                      16
+#endif
+
+#ifndef APP_MAX_PKTQ_SINK
+#define APP_MAX_PKTQ_SINK                        16
+#endif
+
+#ifndef APP_MAX_MSGQ
+#define APP_MAX_MSGQ                             128
+#endif
+
+#ifndef APP_MAX_PIPELINES
+#define APP_MAX_PIPELINES                        64
+#endif
+
+#ifndef APP_EAL_ARGC
+#define APP_EAL_ARGC                             32
+#endif
+
+#ifndef APP_MAX_PIPELINE_TYPES
+#define APP_MAX_PIPELINE_TYPES                   64
+#endif
+
+#ifndef APP_MAX_THREADS
+#define APP_MAX_THREADS                          RTE_MAX_LCORE
+#endif
+
+#ifndef APP_MAX_CMDS
+#define APP_MAX_CMDS                             128
+#endif
+
+#ifndef APP_THREAD_HEADROOM_STATS_COLLECT
+#define APP_THREAD_HEADROOM_STATS_COLLECT        1
+#endif
+
+uint8_t enable_hwlb;
+uint8_t enable_flow_dir;
+
+#define APP_CORE_MASK_SIZE                                     \
+       (RTE_MAX_LCORE / 64 + ((RTE_MAX_LCORE % 64) ? 1 : 0))
+
+struct app_params {
+       /* Config */
+       char app_name[APP_APPNAME_SIZE];
+       const char *config_file;
+       const char *script_file;
+       const char *parser_file;
+       const char *output_file;
+       const char *preproc;
+       const char *preproc_args;
+       uint64_t port_mask;
+       uint32_t log_level;
+
+       struct app_eal_params eal_params;
+       struct app_mempool_params mempool_params[APP_MAX_MEMPOOLS];
+       struct app_link_params link_params[APP_MAX_LINKS];
+       struct app_pktq_hwq_in_params hwq_in_params[APP_MAX_HWQ_IN];
+       struct app_pktq_hwq_out_params hwq_out_params[APP_MAX_HWQ_OUT];
+       struct app_pktq_swq_params swq_params[APP_MAX_PKTQ_SWQ];
+       struct app_pktq_tm_params tm_params[APP_MAX_PKTQ_TM];
+       struct app_pktq_source_params source_params[APP_MAX_PKTQ_SOURCE];
+       struct app_pktq_sink_params sink_params[APP_MAX_PKTQ_SINK];
+       struct app_msgq_params msgq_params[APP_MAX_MSGQ];
+       struct app_pipeline_params pipeline_params[APP_MAX_PIPELINES];
+
+       uint32_t n_mempools;
+       uint32_t n_links;
+       uint32_t n_pktq_hwq_in;
+       uint32_t n_pktq_hwq_out;
+       uint32_t n_pktq_swq;
+       uint32_t n_pktq_tm;
+       uint32_t n_pktq_source;
+       uint32_t n_pktq_sink;
+       uint32_t n_msgq;
+       uint32_t n_pipelines;
+
+       uint32_t header_csum_req;
+       uint32_t n_hwlb_q;
+       /* Init */
+       char *eal_argv[1 + APP_EAL_ARGC];
+       struct cpu_core_map *core_map;
+        uint64_t core_mask[APP_CORE_MASK_SIZE];
+       struct rte_mempool *mempool[APP_MAX_MEMPOOLS];
+       struct rte_ring *swq[APP_MAX_PKTQ_SWQ];
+       struct rte_sched_port *tm[APP_MAX_PKTQ_TM];
+       struct rte_ring *msgq[APP_MAX_MSGQ];
+       struct pipeline_type pipeline_type[APP_MAX_PIPELINE_TYPES];
+       struct app_pipeline_data pipeline_data[APP_MAX_PIPELINES];
+       struct app_thread_data thread_data[APP_MAX_THREADS];
+       cmdline_parse_ctx_t cmds[APP_MAX_CMDS + 1];
+
+       int eal_argc;
+       uint32_t n_pipeline_types;
+       uint32_t n_cmds;
+};
+
+#define APP_PARAM_VALID(obj) ((obj)->name != NULL)
+
+#define APP_PARAM_COUNT(obj_array, n_objs)                             \
+{                                                                      \
+       size_t i;                                                       \
+                                                                       \
+       n_objs = 0;                                                     \
+       for (i = 0; i < RTE_DIM(obj_array); i++)                        \
+               if (APP_PARAM_VALID(&((obj_array)[i])))                 \
+                       n_objs++;                                       \
+}
+
+#define APP_PARAM_FIND(obj_array, key)                                 \
+({                                                                     \
+       ssize_t obj_idx;                                                \
+       const ssize_t obj_count = RTE_DIM(obj_array);                   \
+                                                                       \
+       for (obj_idx = 0; obj_idx < obj_count; obj_idx++) {             \
+               if (!APP_PARAM_VALID(&((obj_array)[obj_idx])))          \
+                       continue;                                       \
+                                                                       \
+               if (strcmp(key, (obj_array)[obj_idx].name) == 0)        \
+                       break;                                          \
+       }                                                               \
+       obj_idx < obj_count ? obj_idx : -ENOENT;                        \
+})
+
+#define APP_PARAM_FIND_BY_ID(obj_array, prefix, id, obj)               \
+do {                                                                   \
+       char name[APP_PARAM_NAME_SIZE];                                 \
+       ssize_t pos;                                                    \
+                                                                       \
+       sprintf(name, prefix "%" PRIu32, id);                           \
+       pos = APP_PARAM_FIND(obj_array, name);                          \
+       obj = (pos < 0) ? NULL : &((obj_array)[pos]);                   \
+} while (0)
+
+#define APP_PARAM_GET_ID(obj, prefix, id)                              \
+do                                                                     \
+       sscanf(obj->name, prefix "%" SCNu32, &id);                              \
+while (0)                                                              \
+
+#define APP_PARAM_ADD(obj_array, obj_name)                             \
+({                                                                     \
+       ssize_t obj_idx;                                                \
+       const ssize_t obj_count = RTE_DIM(obj_array);                   \
+                                                                       \
+       obj_idx = APP_PARAM_FIND(obj_array, obj_name);                  \
+       if (obj_idx < 0) {                                              \
+               for (obj_idx = 0; obj_idx < obj_count; obj_idx++) {     \
+                       if (!APP_PARAM_VALID(&((obj_array)[obj_idx])))  \
+                               break;                                  \
+               }                                                       \
+                                                                       \
+               if (obj_idx < obj_count) {                              \
+                       (obj_array)[obj_idx].name = strdup(obj_name);   \
+                       if ((obj_array)[obj_idx].name == NULL)          \
+                               obj_idx = -EINVAL;                      \
+               } else                                                  \
+                       obj_idx = -ENOMEM;                              \
+       }                                                               \
+       obj_idx;                                                        \
+})
+
+#define        APP_CHECK(exp, fmt, ...)                                        \
+do {                                                                   \
+       if (!(exp)) {                                                   \
+               fprintf(stderr, fmt "\n", ## __VA_ARGS__);              \
+               abort();                                                \
+       }                                                               \
+} while (0)
+
+enum app_log_level {
+       APP_LOG_LEVEL_HIGH = 1,
+       APP_LOG_LEVEL_LOW,
+       APP_LOG_LEVELS
+};
+
+#define APP_LOG(app, level, fmt, ...)                                  \
+do {                                                                   \
+       if (app->log_level >= APP_LOG_LEVEL_ ## level)                  \
+               fprintf(stdout, "[APP] " fmt "\n", ## __VA_ARGS__);     \
+} while (0)
+
+static inline uint32_t
+app_link_get_n_rxq(struct app_params *app, struct app_link_params *link)
+{
+       uint32_t n_rxq = 0, link_id, i;
+       uint32_t n_pktq_hwq_in = RTE_MIN(app->n_pktq_hwq_in,
+               RTE_DIM(app->hwq_in_params));
+
+       APP_PARAM_GET_ID(link, "LINK", link_id);
+
+       for (i = 0; i < n_pktq_hwq_in; i++) {
+               struct app_pktq_hwq_in_params *p = &app->hwq_in_params[i];
+               uint32_t rxq_link_id, rxq_queue_id;
+
+               sscanf(p->name, "RXQ%" SCNu32 ".%" SCNu32,
+                       &rxq_link_id, &rxq_queue_id);
+               if (rxq_link_id == link_id)
+                       n_rxq++;
+       }
+
+       return n_rxq;
+}
+
+static inline uint32_t
+app_link_get_n_txq(struct app_params *app, struct app_link_params *link)
+{
+       uint32_t n_txq = 0, link_id, i;
+       uint32_t n_pktq_hwq_out = RTE_MIN(app->n_pktq_hwq_out,
+               RTE_DIM(app->hwq_out_params));
+
+       APP_PARAM_GET_ID(link, "LINK", link_id);
+
+       for (i = 0; i < n_pktq_hwq_out; i++) {
+               struct app_pktq_hwq_out_params *p = &app->hwq_out_params[i];
+               uint32_t txq_link_id, txq_queue_id;
+
+               sscanf(p->name, "TXQ%" SCNu32 ".%" SCNu32,
+                       &txq_link_id, &txq_queue_id);
+               if (txq_link_id == link_id)
+                       n_txq++;
+       }
+
+       return n_txq;
+}
+
+static inline uint32_t
+app_rxq_get_readers(struct app_params *app, struct app_pktq_hwq_in_params *rxq)
+{
+       uint32_t pos = rxq - app->hwq_in_params;
+       uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
+               RTE_DIM(app->pipeline_params));
+       uint32_t n_readers = 0, i;
+
+       for (i = 0; i < n_pipelines; i++) {
+               struct app_pipeline_params *p = &app->pipeline_params[i];
+               uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
+               uint32_t j;
+
+               for (j = 0; j < n_pktq_in; j++) {
+                       struct app_pktq_in_params *pktq = &p->pktq_in[j];
+
+                       if ((pktq->type == APP_PKTQ_IN_HWQ) &&
+                               (pktq->id == pos))
+                               n_readers++;
+               }
+       }
+
+       return n_readers;
+}
+
+static inline uint32_t
+app_swq_get_readers(struct app_params *app, struct app_pktq_swq_params *swq)
+{
+       uint32_t pos = swq - app->swq_params;
+       uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
+               RTE_DIM(app->pipeline_params));
+       uint32_t n_readers = 0, i;
+
+       for (i = 0; i < n_pipelines; i++) {
+               struct app_pipeline_params *p = &app->pipeline_params[i];
+               uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
+               uint32_t j;
+
+               for (j = 0; j < n_pktq_in; j++) {
+                       struct app_pktq_in_params *pktq = &p->pktq_in[j];
+
+                       if ((pktq->type == APP_PKTQ_IN_SWQ) &&
+                               (pktq->id == pos))
+                               n_readers++;
+               }
+       }
+
+       return n_readers;
+}
+
+static inline uint32_t
+app_tm_get_readers(struct app_params *app, struct app_pktq_tm_params *tm)
+{
+       uint32_t pos = tm - app->tm_params;
+       uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
+               RTE_DIM(app->pipeline_params));
+       uint32_t n_readers = 0, i;
+
+       for (i = 0; i < n_pipelines; i++) {
+               struct app_pipeline_params *p = &app->pipeline_params[i];
+               uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
+               uint32_t j;
+
+               for (j = 0; j < n_pktq_in; j++) {
+                       struct app_pktq_in_params *pktq = &p->pktq_in[j];
+
+                       if ((pktq->type == APP_PKTQ_IN_TM) &&
+                               (pktq->id == pos))
+                               n_readers++;
+               }
+       }
+
+       return n_readers;
+}
+
+static inline uint32_t
+app_source_get_readers(struct app_params *app,
+struct app_pktq_source_params *source)
+{
+       uint32_t pos = source - app->source_params;
+       uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
+               RTE_DIM(app->pipeline_params));
+       uint32_t n_readers = 0, i;
+
+       for (i = 0; i < n_pipelines; i++) {
+               struct app_pipeline_params *p = &app->pipeline_params[i];
+               uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
+               uint32_t j;
+
+               for (j = 0; j < n_pktq_in; j++) {
+                       struct app_pktq_in_params *pktq = &p->pktq_in[j];
+
+                       if ((pktq->type == APP_PKTQ_IN_SOURCE) &&
+                               (pktq->id == pos))
+                               n_readers++;
+               }
+       }
+
+       return n_readers;
+}
+
+static inline uint32_t
+app_msgq_get_readers(struct app_params *app, struct app_msgq_params *msgq)
+{
+       uint32_t pos = msgq - app->msgq_params;
+       uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
+               RTE_DIM(app->pipeline_params));
+       uint32_t n_readers = 0, i;
+
+       for (i = 0; i < n_pipelines; i++) {
+               struct app_pipeline_params *p = &app->pipeline_params[i];
+               uint32_t n_msgq_in = RTE_MIN(p->n_msgq_in, RTE_DIM(p->msgq_in));
+               uint32_t j;
+
+               for (j = 0; j < n_msgq_in; j++)
+                       if (p->msgq_in[j] == pos)
+                               n_readers++;
+       }
+
+       return n_readers;
+}
+
+static inline uint32_t
+app_txq_get_writers(struct app_params *app, struct app_pktq_hwq_out_params *txq)
+{
+       uint32_t pos = txq - app->hwq_out_params;
+       uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
+               RTE_DIM(app->pipeline_params));
+       uint32_t n_writers = 0, i;
+
+       for (i = 0; i < n_pipelines; i++) {
+               struct app_pipeline_params *p = &app->pipeline_params[i];
+               uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
+                       RTE_DIM(p->pktq_out));
+               uint32_t j;
+
+               for (j = 0; j < n_pktq_out; j++) {
+                       struct app_pktq_out_params *pktq = &p->pktq_out[j];
+
+                       if ((pktq->type == APP_PKTQ_OUT_HWQ) &&
+                               (pktq->id == pos))
+                               n_writers++;
+               }
+       }
+
+       return n_writers;
+}
+
+static inline uint32_t
+app_swq_get_writers(struct app_params *app, struct app_pktq_swq_params *swq)
+{
+       uint32_t pos = swq - app->swq_params;
+       uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
+               RTE_DIM(app->pipeline_params));
+       uint32_t n_writers = 0, i;
+
+       for (i = 0; i < n_pipelines; i++) {
+               struct app_pipeline_params *p = &app->pipeline_params[i];
+               uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
+                       RTE_DIM(p->pktq_out));
+               uint32_t j;
+
+               for (j = 0; j < n_pktq_out; j++) {
+                       struct app_pktq_out_params *pktq = &p->pktq_out[j];
+
+                       if ((pktq->type == APP_PKTQ_OUT_SWQ) &&
+                               (pktq->id == pos))
+                               n_writers++;
+               }
+       }
+
+       return n_writers;
+}
+
+static inline uint32_t
+app_tm_get_writers(struct app_params *app, struct app_pktq_tm_params *tm)
+{
+       uint32_t pos = tm - app->tm_params;
+       uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
+               RTE_DIM(app->pipeline_params));
+       uint32_t n_writers = 0, i;
+
+       for (i = 0; i < n_pipelines; i++) {
+               struct app_pipeline_params *p = &app->pipeline_params[i];
+               uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
+                       RTE_DIM(p->pktq_out));
+               uint32_t j;
+
+               for (j = 0; j < n_pktq_out; j++) {
+                       struct app_pktq_out_params *pktq = &p->pktq_out[j];
+
+                       if ((pktq->type == APP_PKTQ_OUT_TM) &&
+                               (pktq->id == pos))
+                               n_writers++;
+               }
+       }
+
+       return n_writers;
+}
+
+static inline uint32_t
+app_sink_get_writers(struct app_params *app, struct app_pktq_sink_params *sink)
+{
+       uint32_t pos = sink - app->sink_params;
+       uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
+               RTE_DIM(app->pipeline_params));
+       uint32_t n_writers = 0, i;
+
+       for (i = 0; i < n_pipelines; i++) {
+               struct app_pipeline_params *p = &app->pipeline_params[i];
+               uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
+                       RTE_DIM(p->pktq_out));
+               uint32_t j;
+
+               for (j = 0; j < n_pktq_out; j++) {
+                       struct app_pktq_out_params *pktq = &p->pktq_out[j];
+
+                       if ((pktq->type == APP_PKTQ_OUT_SINK) &&
+                               (pktq->id == pos))
+                               n_writers++;
+               }
+       }
+
+       return n_writers;
+}
+
+static inline uint32_t
+app_core_is_enabled(struct app_params *app, uint32_t lcore_id) {
+       return(app->core_mask[lcore_id / 64] &
+               (1LLU << (lcore_id % 64)));
+}
+
+static inline void
+app_core_enable_in_core_mask(struct app_params *app, int lcore_id) {
+       app->core_mask[lcore_id / 64] |= 1LLU << (lcore_id % 64);
+
+}
+
+static inline void
+app_core_build_core_mask_string(struct app_params *app, char
+*mask_buffer) {
+       int i;
+
+       mask_buffer[0] = '\0';
+       for (i = (int)RTE_DIM(app->core_mask); i > 0; i--) {
+               /* For Hex representation of bits in uint64_t */
+               char buffer[(64 / 8) * 2 + 1];
+               memset(buffer, 0, sizeof(buffer));
+               snprintf(buffer, sizeof(buffer), "%016" PRIx64,
+                        app->core_mask[i-1]);
+               strcat(mask_buffer, buffer);
+       }
+}
+
+static inline uint32_t
+app_msgq_get_writers(struct app_params *app, struct app_msgq_params *msgq)
+{
+       uint32_t pos = msgq - app->msgq_params;
+       uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
+               RTE_DIM(app->pipeline_params));
+       uint32_t n_writers = 0, i;
+
+       for (i = 0; i < n_pipelines; i++) {
+               struct app_pipeline_params *p = &app->pipeline_params[i];
+               uint32_t n_msgq_out = RTE_MIN(p->n_msgq_out,
+                       RTE_DIM(p->msgq_out));
+               uint32_t j;
+
+               for (j = 0; j < n_msgq_out; j++)
+                       if (p->msgq_out[j] == pos)
+                               n_writers++;
+       }
+
+       return n_writers;
+}
+
+static inline struct app_link_params *
+app_get_link_for_rxq(struct app_params *app, struct app_pktq_hwq_in_params *p)
+{
+       char link_name[APP_PARAM_NAME_SIZE];
+       ssize_t link_param_idx;
+       uint32_t rxq_link_id, rxq_queue_id;
+
+       sscanf(p->name, "RXQ%" SCNu32 ".%" SCNu32,
+               &rxq_link_id, &rxq_queue_id);
+       sprintf(link_name, "LINK%" PRIu32, rxq_link_id);
+       link_param_idx = APP_PARAM_FIND(app->link_params, link_name);
+       APP_CHECK((link_param_idx >= 0),
+               "Cannot find %s for %s", link_name, p->name);
+
+       return &app->link_params[link_param_idx];
+}
+
+static inline struct app_link_params *
+app_get_link_for_txq(struct app_params *app, struct app_pktq_hwq_out_params *p)
+{
+       char link_name[APP_PARAM_NAME_SIZE];
+       ssize_t link_param_idx;
+       uint32_t txq_link_id, txq_queue_id;
+
+       sscanf(p->name, "TXQ%" SCNu32 ".%" SCNu32,
+               &txq_link_id, &txq_queue_id);
+       sprintf(link_name, "LINK%" PRIu32, txq_link_id);
+       link_param_idx = APP_PARAM_FIND(app->link_params, link_name);
+       APP_CHECK((link_param_idx >= 0),
+               "Cannot find %s for %s", link_name, p->name);
+
+       return &app->link_params[link_param_idx];
+}
+
+static inline struct app_link_params *
+app_get_link_for_tm(struct app_params *app, struct app_pktq_tm_params *p_tm)
+{
+       char link_name[APP_PARAM_NAME_SIZE];
+       uint32_t link_id;
+       ssize_t link_param_idx;
+
+       sscanf(p_tm->name, "TM%" PRIu32, &link_id);
+       sprintf(link_name, "LINK%" PRIu32, link_id);
+       link_param_idx = APP_PARAM_FIND(app->link_params, link_name);
+       APP_CHECK((link_param_idx >= 0),
+               "Cannot find %s for %s", link_name, p_tm->name);
+
+       return &app->link_params[link_param_idx];
+}
+
+int app_config_init(struct app_params *app);
+
+int app_config_args(struct app_params *app,
+       int argc, char **argv);
+
+int app_config_preproc(struct app_params *app);
+
+int app_config_parse(struct app_params *app,
+       const char *file_name);
+
+int app_config_parse_tm(struct app_params *app);
+
+void app_config_save(struct app_params *app,
+       const char *file_name);
+
+int app_config_check(struct app_params *app);
+
+int app_init(struct app_params *app);
+
+int app_thread(void *arg);
+
+int app_pipeline_type_register(struct app_params *app,
+       struct pipeline_type *ptype);
+
+struct pipeline_type *app_pipeline_type_find(struct app_params *app,
+       char *name);
+
+void app_link_up_internal(struct app_params *app,
+       struct app_link_params *cp);
+
+void app_link_down_internal(struct app_params *app,
+       struct app_link_params *cp);
+
+#endif
diff --git a/common/vnf_common/config_check.c b/common/vnf_common/config_check.c
new file mode 100644 (file)
index 0000000..09638c6
--- /dev/null
@@ -0,0 +1,443 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <stdio.h>
+
+#include <rte_ip.h>
+
+#include "app.h"
+//uint8_t g_n_hwq_in = N_RXQ;
+uint8_t g_n_hwq_in;
+static void
+check_mempools(struct app_params *app)
+{
+       uint32_t i;
+
+       for (i = 0; i < app->n_mempools; i++) {
+               struct app_mempool_params *p = &app->mempool_params[i];
+
+               APP_CHECK((p->pool_size > 0),
+                       "Mempool %s size is 0\n", p->name);
+
+               APP_CHECK((p->cache_size > 0),
+                       "Mempool %s cache size is 0\n", p->name);
+
+               APP_CHECK(rte_is_power_of_2(p->cache_size),
+                       "Mempool %s cache size not a power of 2\n", p->name);
+       }
+}
+
+static void
+check_links(struct app_params *app)
+{
+       uint32_t i;
+
+       /* Check that number of links matches the port mask */
+       if (app->port_mask) {
+               uint32_t n_links_port_mask =
+                       __builtin_popcountll(app->port_mask);
+
+               APP_CHECK((app->n_links == n_links_port_mask),
+                       "Not enough links provided in the PORT_MASK\n");
+       }
+
+       for (i = 0; i < app->n_links; i++) {
+               struct app_link_params *link = &app->link_params[i];
+               uint32_t rxq_max, n_rxq, n_txq, link_id, i;
+
+               APP_PARAM_GET_ID(link, "LINK", link_id);
+
+               /* Check that link RXQs are contiguous */
+               rxq_max = 0;
+               if (link->arp_q > rxq_max)
+                       rxq_max = link->arp_q;
+               if (link->tcp_syn_q > rxq_max)
+                       rxq_max = link->tcp_syn_q;
+               if (link->ip_local_q > rxq_max)
+                       rxq_max = link->ip_local_q;
+               if (link->tcp_local_q > rxq_max)
+                       rxq_max = link->tcp_local_q;
+               if (link->udp_local_q > rxq_max)
+                       rxq_max = link->udp_local_q;
+               if (link->sctp_local_q > rxq_max)
+                       rxq_max = link->sctp_local_q;
+
+if(enable_hwlb || enable_flow_dir){
+       g_n_hwq_in = app->n_hwlb_q;
+       rxq_max = (g_n_hwq_in - 1);
+       for (i = g_n_hwq_in; i <= rxq_max; i++)
+                       APP_CHECK(((link->arp_q == i) ||
+                               (link->tcp_syn_q == i) ||
+                               (link->ip_local_q == i) ||
+                               (link->tcp_local_q == i) ||
+                               (link->udp_local_q == i) ||
+                               (link->sctp_local_q == i)),
+                               "%s RXQs are not contiguous (A)\n", link->name);
+
+}
+else{
+               for (i = 1; i <= rxq_max; i++)
+                       APP_CHECK(((link->arp_q == i) ||
+                               (link->tcp_syn_q == i) ||
+                               (link->ip_local_q == i) ||
+                               (link->tcp_local_q == i) ||
+                               (link->udp_local_q == i) ||
+                               (link->sctp_local_q == i)),
+                               "%s RXQs are not contiguous (A)\n", link->name);
+}
+               n_rxq = app_link_get_n_rxq(app, link);
+
+               APP_CHECK((n_rxq), "%s does not have any RXQ\n", link->name);
+               printf("n_rxq = %d\n",n_rxq);
+               printf("rxq_max = %d\n",rxq_max);
+               //APP_CHECK((n_rxq == rxq_max + 1),
+               //      "%s RXQs are not contiguous (B)\n", link->name);
+
+               for (i = 0; i < n_rxq; i++) {
+                       char name[APP_PARAM_NAME_SIZE];
+                       int pos;
+
+                       sprintf(name, "RXQ%" PRIu32 ".%" PRIu32,
+                               link_id, i);
+                       pos = APP_PARAM_FIND(app->hwq_in_params, name);
+                       APP_CHECK((pos >= 0),
+                               "%s RXQs are not contiguous (C)\n", link->name);
+               }
+
+               /* Check that link RXQs are contiguous */
+               n_txq = app_link_get_n_txq(app, link);
+
+               APP_CHECK((n_txq),  "%s does not have any TXQ\n", link->name);
+
+               for (i = 0; i < n_txq; i++) {
+                       char name[APP_PARAM_NAME_SIZE];
+                       int pos;
+
+                       sprintf(name, "TXQ%" PRIu32 ".%" PRIu32,
+                               link_id, i);
+                       pos = APP_PARAM_FIND(app->hwq_out_params, name);
+                       APP_CHECK((pos >= 0),
+                               "%s TXQs are not contiguous\n", link->name);
+               }
+       }
+}
+
+static void
+check_rxqs(struct app_params *app)
+{
+       uint32_t i;
+
+       for (i = 0; i < app->n_pktq_hwq_in; i++) {
+               struct app_pktq_hwq_in_params *p = &app->hwq_in_params[i];
+               uint32_t n_readers = app_rxq_get_readers(app, p);
+
+               APP_CHECK((p->size > 0),
+                       "%s size is 0\n", p->name);
+
+               APP_CHECK((rte_is_power_of_2(p->size)),
+                       "%s size is not a power of 2\n", p->name);
+
+               APP_CHECK((p->burst > 0),
+                       "%s burst size is 0\n", p->name);
+
+               APP_CHECK((p->burst <= p->size),
+                       "%s burst size is bigger than its size\n", p->name);
+
+               APP_CHECK((n_readers != 0),
+                       "%s has no reader\n", p->name);
+
+               APP_CHECK((n_readers == 1),
+                       "%s has more than one reader\n", p->name);
+       }
+}
+
+static void
+check_txqs(struct app_params *app)
+{
+       uint32_t i;
+
+       for (i = 0; i < app->n_pktq_hwq_out; i++) {
+               struct app_pktq_hwq_out_params *p = &app->hwq_out_params[i];
+               uint32_t n_writers = app_txq_get_writers(app, p);
+
+               APP_CHECK((p->size > 0),
+                       "%s size is 0\n", p->name);
+
+               APP_CHECK((rte_is_power_of_2(p->size)),
+                       "%s size is not a power of 2\n", p->name);
+
+               APP_CHECK((p->burst > 0),
+                       "%s burst size is 0\n", p->name);
+
+               APP_CHECK((p->burst <= p->size),
+                       "%s burst size is bigger than its size\n", p->name);
+
+               APP_CHECK((n_writers != 0),
+                       "%s has no writer\n", p->name);
+
+               APP_CHECK((n_writers == 1),
+                       "%s has more than one writer\n", p->name);
+       }
+}
+
+static void
+check_swqs(struct app_params *app)
+{
+       uint32_t i;
+
+       for (i = 0; i < app->n_pktq_swq; i++) {
+               struct app_pktq_swq_params *p = &app->swq_params[i];
+               uint32_t n_readers = app_swq_get_readers(app, p);
+               uint32_t n_writers = app_swq_get_writers(app, p);
+               uint32_t n_flags;
+
+               APP_CHECK((p->size > 0),
+                       "%s size is 0\n", p->name);
+
+               APP_CHECK((rte_is_power_of_2(p->size)),
+                       "%s size is not a power of 2\n", p->name);
+
+               APP_CHECK((p->burst_read > 0),
+                       "%s read burst size is 0\n", p->name);
+
+               APP_CHECK((p->burst_read <= p->size),
+                       "%s read burst size is bigger than its size\n",
+                       p->name);
+
+               APP_CHECK((p->burst_write > 0),
+                       "%s write burst size is 0\n", p->name);
+
+               APP_CHECK((p->burst_write <= p->size),
+                       "%s write burst size is bigger than its size\n",
+                       p->name);
+
+               APP_CHECK((n_readers != 0),
+                       "%s has no reader\n", p->name);
+
+               if (n_readers > 1)
+                       APP_LOG(app, LOW, "%s has more than one reader", p->name);
+
+               APP_CHECK((n_writers != 0),
+                       "%s has no writer\n", p->name);
+
+               if (n_writers > 1)
+                       APP_LOG(app, LOW, "%s has more than one writer", p->name);
+
+               n_flags = p->ipv4_frag + p->ipv6_frag + p->ipv4_ras + p->ipv6_ras;
+
+               APP_CHECK((n_flags < 2),
+                       "%s has more than one fragmentation or reassembly mode enabled\n",
+                       p->name);
+
+               APP_CHECK((!((n_readers > 1) && (n_flags == 1))),
+                       "%s has more than one reader when fragmentation or reassembly"
+                       " mode enabled\n",
+                       p->name);
+
+               APP_CHECK((!((n_writers > 1) && (n_flags == 1))),
+                       "%s has more than one writer when fragmentation or reassembly"
+                       " mode enabled\n",
+                       p->name);
+
+               n_flags = p->ipv4_ras + p->ipv6_ras;
+
+               APP_CHECK((!((p->dropless == 1) && (n_flags == 1))),
+                       "%s has dropless when reassembly mode enabled\n", p->name);
+
+               n_flags = p->ipv4_frag + p->ipv6_frag;
+
+               if (n_flags == 1) {
+                       uint16_t ip_hdr_size = (p->ipv4_frag) ? sizeof(struct ipv4_hdr) :
+                               sizeof(struct ipv6_hdr);
+
+                       APP_CHECK((p->mtu > ip_hdr_size),
+                               "%s mtu size is smaller than ip header\n", p->name);
+
+                       APP_CHECK((!((p->mtu - ip_hdr_size) % 8)),
+                               "%s mtu size is incorrect\n", p->name);
+               }
+       }
+}
+
+static void
+check_tms(struct app_params *app)
+{
+       uint32_t i;
+
+       for (i = 0; i < app->n_pktq_tm; i++) {
+               struct app_pktq_tm_params *p = &app->tm_params[i];
+               uint32_t n_readers = app_tm_get_readers(app, p);
+               uint32_t n_writers = app_tm_get_writers(app, p);
+
+               APP_CHECK((n_readers != 0),
+                       "%s has no reader\n", p->name);
+
+               APP_CHECK((n_readers == 1),
+                       "%s has more than one reader\n", p->name);
+
+               APP_CHECK((n_writers != 0),
+                       "%s has no writer\n", p->name);
+
+               APP_CHECK((n_writers == 1),
+                       "%s has more than one writer\n", p->name);
+       }
+}
+
+static void
+check_sources(struct app_params *app)
+{
+       uint32_t i;
+
+       for (i = 0; i < app->n_pktq_source; i++) {
+               struct app_pktq_source_params *p = &app->source_params[i];
+               uint32_t n_readers = app_source_get_readers(app, p);
+
+               APP_CHECK((n_readers != 0),
+                       "%s has no reader\n", p->name);
+
+               APP_CHECK((n_readers == 1),
+                       "%s has more than one reader\n", p->name);
+       }
+}
+
+static void
+check_sinks(struct app_params *app)
+{
+       uint32_t i;
+
+       for (i = 0; i < app->n_pktq_sink; i++) {
+               struct app_pktq_sink_params *p = &app->sink_params[i];
+               uint32_t n_writers = app_sink_get_writers(app, p);
+
+               APP_CHECK((n_writers != 0),
+                       "%s has no writer\n", p->name);
+
+               APP_CHECK((n_writers == 1),
+                       "%s has more than one writer\n", p->name);
+       }
+}
+
+static void
+check_msgqs(struct app_params *app)
+{
+       uint32_t i;
+
+       for (i = 0; i < app->n_msgq; i++) {
+               struct app_msgq_params *p = &app->msgq_params[i];
+               uint32_t n_readers = app_msgq_get_readers(app, p);
+               uint32_t n_writers = app_msgq_get_writers(app, p);
+               uint32_t msgq_req_pipeline, msgq_rsp_pipeline;
+               uint32_t msgq_req_core, msgq_rsp_core;
+
+               APP_CHECK((p->size > 0),
+                       "%s size is 0\n", p->name);
+
+               APP_CHECK((rte_is_power_of_2(p->size)),
+                       "%s size is not a power of 2\n", p->name);
+
+               msgq_req_pipeline = (strncmp(p->name, "MSGQ-REQ-PIPELINE",
+                       strlen("MSGQ-REQ-PIPELINE")) == 0);
+
+               msgq_rsp_pipeline = (strncmp(p->name, "MSGQ-RSP-PIPELINE",
+                       strlen("MSGQ-RSP-PIPELINE")) == 0);
+
+               msgq_req_core = (strncmp(p->name, "MSGQ-REQ-CORE",
+                       strlen("MSGQ-REQ-CORE")) == 0);
+
+               msgq_rsp_core = (strncmp(p->name, "MSGQ-RSP-CORE",
+                       strlen("MSGQ-RSP-CORE")) == 0);
+
+               if ((msgq_req_pipeline == 0) &&
+                       (msgq_rsp_pipeline == 0) &&
+                       (msgq_req_core == 0) &&
+                       (msgq_rsp_core == 0)) {
+                       APP_CHECK((n_readers != 0),
+                               "%s has no reader\n", p->name);
+
+                       APP_CHECK((n_readers == 1),
+                               "%s has more than one reader\n", p->name);
+
+                       APP_CHECK((n_writers != 0),
+                               "%s has no writer\n", p->name);
+
+                       APP_CHECK((n_writers == 1),
+                               "%s has more than one writer\n", p->name);
+               }
+
+               if (msgq_req_pipeline) {
+                       struct app_pipeline_params *pipeline;
+                       uint32_t pipeline_id;
+
+                       APP_PARAM_GET_ID(p, "MSGQ-REQ-PIPELINE", pipeline_id);
+
+                       APP_PARAM_FIND_BY_ID(app->pipeline_params,
+                               "PIPELINE",
+                               pipeline_id,
+                               pipeline);
+
+                       APP_CHECK((pipeline != NULL),
+                               "%s is not associated with a valid pipeline\n",
+                               p->name);
+               }
+
+               if (msgq_rsp_pipeline) {
+                       struct app_pipeline_params *pipeline;
+                       uint32_t pipeline_id;
+
+                       APP_PARAM_GET_ID(p, "MSGQ-RSP-PIPELINE", pipeline_id);
+
+                       APP_PARAM_FIND_BY_ID(app->pipeline_params,
+                               "PIPELINE",
+                               pipeline_id,
+                               pipeline);
+
+                       APP_CHECK((pipeline != NULL),
+                               "%s is not associated with a valid pipeline\n",
+                               p->name);
+               }
+       }
+}
+
+static void
+check_pipelines(struct app_params *app)
+{
+       uint32_t i;
+
+       for (i = 0; i < app->n_pipelines; i++) {
+               struct app_pipeline_params *p = &app->pipeline_params[i];
+
+               APP_CHECK((p->n_msgq_in == p->n_msgq_out),
+                       "%s number of input MSGQs does not match "
+                       "the number of output MSGQs\n", p->name);
+       }
+}
+
+int
+app_config_check(struct app_params *app)
+{
+       check_mempools(app);
+       check_links(app);
+       check_rxqs(app);
+       check_txqs(app);
+       check_swqs(app);
+       check_tms(app);
+       check_sources(app);
+       check_sinks(app);
+       check_msgqs(app);
+       check_pipelines(app);
+
+       return 0;
+}
diff --git a/common/vnf_common/config_parse.c b/common/vnf_common/config_parse.c
new file mode 100644 (file)
index 0000000..b4b99d1
--- /dev/null
@@ -0,0 +1,3434 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <string.h>
+#include <libgen.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+#include <rte_errno.h>
+#include <rte_cfgfile.h>
+#include <rte_string_fns.h>
+
+#include "app.h"
+#include "parser.h"
+
+/**
+ * Default config values
+ **/
+
+static struct app_params app_params_default = {
+       .config_file = "./config/ip_pipeline.cfg",
+       .log_level = APP_LOG_LEVEL_HIGH,
+       .port_mask = 0,
+
+       .eal_params = {
+               .channels = 4,
+       },
+};
+
+static const struct app_mempool_params mempool_params_default = {
+       .parsed = 0,
+       .buffer_size = 2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM,
+       .pool_size = 32 * 1024,
+       .cache_size = 256,
+       .cpu_socket_id = 0,
+};
+
+static const struct app_link_params link_params_default = {
+       .parsed = 0,
+       .pmd_id = 0,
+       .arp_q = 0,
+       .tcp_syn_q = 0,
+       .ip_local_q = 0,
+       .tcp_local_q = 0,
+       .udp_local_q = 0,
+       .sctp_local_q = 0,
+       .state = 0,
+       .ip = 0,
+       .ipv6 = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+       .depth = 0,
+       .depth_ipv6 = 0,
+       .mac_addr = 0,
+       .pci_bdf = {0},
+
+       .conf = {
+               .link_speeds = 0,
+               .rxmode = {
+                       .mq_mode = ETH_MQ_RX_NONE,
+
+                       .header_split   = 0, /* Header split */
+                       .hw_ip_checksum = 0, /* IP checksum offload */
+                       .hw_vlan_filter = 0, /* VLAN filtering */
+                       .hw_vlan_strip  = 0, /* VLAN strip */
+                       .hw_vlan_extend = 0, /* Extended VLAN */
+                       .jumbo_frame    = 0, /* Jumbo frame support */
+                       .hw_strip_crc   = 0, /* CRC strip by HW */
+                       .enable_scatter = 0, /* Scattered packets RX handler */
+
+                       .max_rx_pkt_len = 9000, /* Jumbo frame max packet len */
+                       .split_hdr_size = 0, /* Header split buffer size */
+               },
+               .txmode = {
+                       .mq_mode = ETH_MQ_TX_NONE,
+               },
+               .lpbk_mode = 0,
+               #ifndef VNF_ACL
+               #ifdef LSC_GRARP
+                .intr_conf = {
+                     .lsc = 1, /**< lsc interrupt feature enabled */
+                }
+               #endif
+               #endif
+       },
+
+       .promisc = 1,
+};
+
+static const struct app_pktq_hwq_in_params default_hwq_in_params = {
+       .parsed = 0,
+       .mempool_id = 0,
+       .size = 128,
+       .burst = 32,
+
+       .conf = {
+               .rx_thresh = {
+                               .pthresh = 8,
+                               .hthresh = 8,
+                               .wthresh = 4,
+               },
+               .rx_free_thresh = 64,
+               .rx_drop_en = 0,
+               .rx_deferred_start = 0,
+       }
+};
+
+static const struct app_pktq_hwq_out_params default_hwq_out_params = {
+       .parsed = 0,
+       .size = 512,
+       .burst = 32,
+       .dropless = 0,
+       .n_retries = 0,
+
+       .conf = {
+               .tx_thresh = {
+                       .pthresh = 36,
+                       .hthresh = 0,
+                       .wthresh = 0,
+               },
+               .tx_rs_thresh = 0,
+               .tx_free_thresh = 0,
+               .txq_flags = ETH_TXQ_FLAGS_NOMULTSEGS |
+                       ETH_TXQ_FLAGS_NOOFFLOADS,
+               .tx_deferred_start = 0,
+       }
+};
+
+static const struct app_pktq_swq_params default_swq_params = {
+       .parsed = 0,
+       .size = 256,
+       .burst_read = 32,
+       .burst_write = 32,
+       .dropless = 0,
+       .n_retries = 0,
+       .cpu_socket_id = 0,
+       .ipv4_frag = 0,
+       .ipv6_frag = 0,
+       .ipv4_ras = 0,
+       .ipv6_ras = 0,
+       .mtu = 0,
+       .metadata_size = 0,
+       .mempool_direct_id = 0,
+       .mempool_indirect_id = 0,
+};
+
+struct app_pktq_tm_params default_tm_params = {
+       .parsed = 0,
+       .file_name = "./config/tm_profile.cfg",
+       .burst_read = 64,
+       .burst_write = 32,
+};
+
+struct app_pktq_source_params default_source_params = {
+       .parsed = 0,
+       .mempool_id = 0,
+       .burst = 32,
+       .file_name = NULL,
+       .n_bytes_per_pkt = 0,
+};
+
+struct app_pktq_sink_params default_sink_params = {
+       .parsed = 0,
+       .file_name = NULL,
+       .n_pkts_to_dump = 0,
+};
+
+struct app_msgq_params default_msgq_params = {
+       .parsed = 0,
+       .size = 64,
+       .cpu_socket_id = 0,
+};
+
+struct app_pipeline_params default_pipeline_params = {
+       .parsed = 0,
+       .socket_id = 0,
+       .core_id = 0,
+       .hyper_th_id = 0,
+       .n_pktq_in = 0,
+       .n_pktq_out = 0,
+       .n_msgq_in = 0,
+       .n_msgq_out = 0,
+       .timer_period = 1,
+       .n_args = 0,
+};
+
+static const char app_usage[] =
+       "Usage: %s [-f CONFIG_FILE] [-s SCRIPT_FILE] [-p PORT_MASK] "
+       "[-l LOG_LEVEL] [--preproc PREPROCESSOR] [--preproc-args ARGS]\n"
+       "\n"
+       "Arguments:\n"
+       "\t-f CONFIG_FILE: Default config file is %s\n"
+       "\t-p PORT_MASK: Mask of NIC port IDs in hex format (generated from "
+               "config file when not provided)\n"
+       "\t-s SCRIPT_FILE: No CLI script file is run when not specified\n"
+       "\t-l LOG_LEVEL: 0 = NONE, 1 = HIGH PRIO (default), 2 = LOW PRIO\n"
+       "\t--disable-hw-csum Disable TCP/UDP HW checksum\n"
+       "\t--preproc PREPROCESSOR: Configuration file pre-processor\n"
+       "\t--preproc-args ARGS: Arguments to be passed to pre-processor\n"
+       "\n";
+
+static void
+app_print_usage(char *prgname)
+{
+       rte_exit(0, app_usage, prgname, app_params_default.config_file);
+}
+
+#define skip_white_spaces(pos)                 \
+({                                             \
+       __typeof__(pos) _p = (pos);             \
+       for ( ; isspace(*_p); _p++);            \
+       _p;                                     \
+})
+
+#define PARSER_PARAM_ADD_CHECK(result, params_array, section_name)     \
+do {                                                                   \
+       APP_CHECK((result != -EINVAL),                                  \
+               "Parse error: no free memory");                         \
+       APP_CHECK((result != -ENOMEM),                                  \
+               "Parse error: too many \"%s\" sections", section_name); \
+       APP_CHECK(((result >= 0) && (params_array)[result].parsed == 0),\
+               "Parse error: duplicate \"%s\" section", section_name); \
+       APP_CHECK((result >= 0),                                        \
+               "Parse error in section \"%s\"", section_name);         \
+} while (0)
+
+int
+parser_read_arg_bool(const char *p)
+{
+       p = skip_white_spaces(p);
+       int result = -EINVAL;
+
+       if (((p[0] == 'y') && (p[1] == 'e') && (p[2] == 's')) ||
+               ((p[0] == 'Y') && (p[1] == 'E') && (p[2] == 'S'))) {
+               p += 3;
+               result = 1;
+       }
+
+       if (((p[0] == 'o') && (p[1] == 'n')) ||
+               ((p[0] == 'O') && (p[1] == 'N'))) {
+               p += 2;
+               result = 1;
+       }
+
+       if (((p[0] == 'n') && (p[1] == 'o')) ||
+               ((p[0] == 'N') && (p[1] == 'O'))) {
+               p += 2;
+               result = 0;
+       }
+
+       if (((p[0] == 'o') && (p[1] == 'f') && (p[2] == 'f')) ||
+               ((p[0] == 'O') && (p[1] == 'F') && (p[2] == 'F'))) {
+               p += 3;
+               result = 0;
+       }
+
+       p = skip_white_spaces(p);
+
+       if (p[0] != '\0')
+               return -EINVAL;
+
+       return result;
+}
+
+#define PARSE_ERROR(exp, section, entry)                               \
+APP_CHECK(exp, "Parse error in section \"%s\": entry \"%s\"\n", section, entry)
+
+#define PARSE_ERROR_MESSAGE(exp, section, entry, message)              \
+APP_CHECK(exp, "Parse error in section \"%s\", entry \"%s\": %s\n",    \
+       section, entry, message)
+
+
+#define PARSE_ERROR_MALLOC(exp)                                                \
+APP_CHECK(exp, "Parse error: no free memory\n")
+
+#define PARSE_ERROR_SECTION(exp, section)                              \
+APP_CHECK(exp, "Parse error in section \"%s\"", section)
+
+#define PARSE_ERROR_SECTION_NO_ENTRIES(exp, section)                   \
+APP_CHECK(exp, "Parse error in section \"%s\": no entries\n", section)
+
+#define PARSE_WARNING_IGNORED(exp, section, entry)                     \
+do                                                                     \
+if (!(exp))                                                            \
+       fprintf(stderr, "Parse warning in section \"%s\": "             \
+               "entry \"%s\" is ignored\n", section, entry);           \
+while (0)
+
+#define PARSE_ERROR_INVALID(exp, section, entry)                       \
+APP_CHECK(exp, "Parse error in section \"%s\": unrecognized entry \"%s\"\n",\
+       section, entry)
+
+#define PARSE_ERROR_DUPLICATE(exp, section, entry)                     \
+APP_CHECK(exp, "Parse error in section \"%s\": duplicate entry \"%s\"\n",\
+       section, entry)
+
+int
+parser_read_uint64(uint64_t *value, const char *p)
+{
+       char *next;
+       uint64_t val;
+
+       p = skip_white_spaces(p);
+       if (!isdigit(*p))
+               return -EINVAL;
+
+       val = strtoul(p, &next, 10);
+       if (p == next)
+               return -EINVAL;
+
+       p = next;
+       switch (*p) {
+       case 'T':
+               val *= 1024ULL;
+               /* fall through */
+       case 'G':
+               val *= 1024ULL;
+               /* fall through */
+       case 'M':
+               val *= 1024ULL;
+               /* fall through */
+       case 'k':
+       case 'K':
+               val *= 1024ULL;
+               p++;
+               break;
+       }
+
+       p = skip_white_spaces(p);
+       if (*p != '\0')
+               return -EINVAL;
+
+       *value = val;
+       return 0;
+}
+
+int
+parser_read_uint32(uint32_t *value, const char *p)
+{
+       uint64_t val = 0;
+       int ret = parser_read_uint64(&val, p);
+
+       if (ret < 0)
+               return ret;
+
+       if (val > UINT32_MAX)
+               return -ERANGE;
+
+       *value = val;
+       return 0;
+}
+
+int
+parse_pipeline_core(uint32_t *socket,
+       uint32_t *core,
+       uint32_t *ht,
+       const char *entry)
+{
+       size_t num_len;
+       char num[8];
+
+       uint32_t s = 0, c = 0, h = 0, val;
+       uint8_t s_parsed = 0, c_parsed = 0, h_parsed = 0;
+       const char *next = skip_white_spaces(entry);
+       char type;
+
+       /* Expect <CORE> or [sX][cY][h]. At least one parameter is required. */
+       while (*next != '\0') {
+               /* If everything parsed nothing should left */
+               if (s_parsed && c_parsed && h_parsed)
+                       return -EINVAL;
+
+               type = *next;
+               switch (type) {
+               case 's':
+               case 'S':
+                       if (s_parsed || c_parsed || h_parsed)
+                               return -EINVAL;
+                       s_parsed = 1;
+                       next++;
+                       break;
+               case 'c':
+               case 'C':
+                       if (c_parsed || h_parsed)
+                               return -EINVAL;
+                       c_parsed = 1;
+                       next++;
+                       break;
+               case 'h':
+               case 'H':
+                       if (h_parsed)
+                               return -EINVAL;
+                       h_parsed = 1;
+                       next++;
+                       break;
+               default:
+                       /* If it start from digit it must be only core id. */
+                       if (!isdigit(*next) || s_parsed || c_parsed || h_parsed)
+                               return -EINVAL;
+
+                       type = 'C';
+               }
+
+               for (num_len = 0; *next != '\0'; next++, num_len++) {
+                       if (num_len == RTE_DIM(num))
+                               return -EINVAL;
+
+                       if (!isdigit(*next))
+                               break;
+
+                       num[num_len] = *next;
+               }
+
+               if (num_len == 0 && type != 'h' && type != 'H')
+                       return -EINVAL;
+
+               if (num_len != 0 && (type == 'h' || type == 'H'))
+                       return -EINVAL;
+               if(num_len < sizeof(num))
+                       num[num_len] = '\0';
+               val = strtol(num, NULL, 10);
+
+               h = 0;
+               switch (type) {
+               case 's':
+               case 'S':
+                       s = val;
+                       break;
+               case 'c':
+               case 'C':
+                       c = val;
+                       break;
+               case 'h':
+               case 'H':
+                       h = 1;
+                       break;
+               }
+       }
+
+       *socket = s;
+       *core = c;
+       *ht = h;
+       return 0;
+}
+
+static uint32_t
+get_hex_val(char c)
+{
+       switch (c) {
+       case '0': case '1': case '2': case '3': case '4': case '5':
+       case '6': case '7': case '8': case '9':
+               return c - '0';
+       case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+               return c - 'A' + 10;
+       case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+               return c - 'a' + 10;
+       default:
+               return 0;
+       }
+}
+
+int
+parse_hex_string(char *src, uint8_t *dst, uint32_t *size)
+{
+       char *c;
+       uint32_t len, i;
+
+       /* Check input parameters */
+       if ((src == NULL) ||
+               (dst == NULL) ||
+               (size == NULL) ||
+               (*size == 0))
+               return -1;
+
+       len = strlen(src);
+       if (((len & 3) != 0) ||
+               (len > (*size) * 2))
+               return -1;
+       *size = len / 2;
+
+       for (c = src; *c != 0; c++) {
+               if ((((*c) >= '0') && ((*c) <= '9')) ||
+                       (((*c) >= 'A') && ((*c) <= 'F')) ||
+                       (((*c) >= 'a') && ((*c) <= 'f')))
+                       continue;
+
+               return -1;
+       }
+
+       /* Convert chars to bytes */
+       for (i = 0; i < *size; i++)
+               dst[i] = get_hex_val(src[2 * i]) * 16 +
+                       get_hex_val(src[2 * i + 1]);
+
+       return 0;
+}
+
+static size_t
+skip_digits(const char *src)
+{
+       size_t i;
+
+       for (i = 0; isdigit(src[i]); i++);
+
+       return i;
+}
+
+static int
+validate_name(const char *name, const char *prefix, int num)
+{
+       size_t i, j;
+
+       for (i = 0; (name[i] != '\0') && (prefix[i] != '\0'); i++) {
+               if (name[i] != prefix[i])
+                       return -1;
+       }
+
+       if (prefix[i] != '\0')
+               return -1;
+
+       if (!num) {
+               if (name[i] != '\0')
+                       return -1;
+               else
+                       return 0;
+       }
+
+       if (num == 2) {
+               j = skip_digits(&name[i]);
+               i += j;
+               if ((j == 0) || (name[i] != '.'))
+                       return -1;
+               i++;
+       }
+
+       if (num == 1) {
+               j = skip_digits(&name[i]);
+               i += j;
+               if ((j == 0) || (name[i] != '\0'))
+                       return -1;
+       }
+
+       return 0;
+}
+
+static void
+parse_eal(struct app_params *app,
+       const char *section_name,
+       struct rte_cfgfile *cfg)
+{
+       struct app_eal_params *p = &app->eal_params;
+       struct rte_cfgfile_entry *entries;
+       int n_entries, i;
+
+       n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
+       PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
+
+       entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
+       PARSE_ERROR_MALLOC(entries != NULL);
+
+       rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
+
+       for (i = 0; i < n_entries; i++) {
+               struct rte_cfgfile_entry *entry = &entries[i];
+
+               /* coremask */
+               if (strcmp(entry->name, "c") == 0) {
+                       PARSE_WARNING_IGNORED(0, section_name, entry->name);
+                       continue;
+               }
+
+               /* corelist */
+               if (strcmp(entry->name, "l") == 0) {
+                       PARSE_WARNING_IGNORED(0, section_name, entry->name);
+                       continue;
+               }
+
+               /* coremap */
+               if (strcmp(entry->name, "lcores") == 0) {
+                       PARSE_ERROR_DUPLICATE((p->coremap == NULL),
+                               section_name,
+                               entry->name);
+                       p->coremap = strdup(entry->value);
+                       continue;
+               }
+
+               /* master_lcore */
+               if (strcmp(entry->name, "master_lcore") == 0) {
+                       int status;
+
+                       PARSE_ERROR_DUPLICATE((p->master_lcore_present == 0),
+                               section_name,
+                               entry->name);
+                       p->master_lcore_present = 1;
+
+                       status = parser_read_uint32(&p->master_lcore,
+                               entry->value);
+                       PARSE_ERROR((status == 0), section_name, entry->name);
+                       continue;
+               }
+
+               /* channels */
+               if (strcmp(entry->name, "n") == 0) {
+                       int status;
+
+                       PARSE_ERROR_DUPLICATE((p->channels_present == 0),
+                               section_name,
+                               entry->name);
+                       p->channels_present = 1;
+
+                       status = parser_read_uint32(&p->channels, entry->value);
+                       PARSE_ERROR((status == 0), section_name, entry->name);
+                       continue;
+               }
+
+               /* memory */
+               if (strcmp(entry->name, "m") == 0) {
+                       int status;
+
+                       PARSE_ERROR_DUPLICATE((p->memory_present == 0),
+                               section_name,
+                               entry->name);
+                       p->memory_present = 1;
+
+                       status = parser_read_uint32(&p->memory, entry->value);
+                       PARSE_ERROR((status == 0), section_name, entry->name);
+                       continue;
+               }
+
+               /* ranks */
+               if (strcmp(entry->name, "r") == 0) {
+                       int status;
+
+                       PARSE_ERROR_DUPLICATE((p->ranks_present == 0),
+                               section_name,
+                               entry->name);
+                       p->ranks_present = 1;
+
+                       status = parser_read_uint32(&p->ranks, entry->value);
+                       PARSE_ERROR((status == 0), section_name, entry->name);
+                       continue;
+               }
+
+               /* pci_blacklist */
+               if ((strcmp(entry->name, "pci_blacklist") == 0) ||
+                       (strcmp(entry->name, "b") == 0)) {
+                       uint32_t i;
+
+                       for (i = 0; i < APP_MAX_LINKS; i++) {
+                               if (p->pci_blacklist[i])
+                                       continue;
+
+                               p->pci_blacklist[i] =
+                                       strdup(entry->value);
+                               PARSE_ERROR_MALLOC(p->pci_blacklist[i]);
+
+                               break;
+                       }
+
+                       PARSE_ERROR_MESSAGE((i < APP_MAX_LINKS),
+                               section_name, entry->name,
+                               "too many elements");
+                       continue;
+               }
+
+               /* pci_whitelist */
+               if ((strcmp(entry->name, "pci_whitelist") == 0) ||
+                       (strcmp(entry->name, "w") == 0)) {
+                       uint32_t i;
+
+                       PARSE_ERROR_MESSAGE((app->port_mask != 0),
+                               section_name, entry->name, "entry to be "
+                               "generated by the application (port_mask "
+                               "not provided)");
+
+                       for (i = 0; i < APP_MAX_LINKS; i++) {
+                               if (p->pci_whitelist[i])
+                                       continue;
+
+                               p->pci_whitelist[i] = strdup(entry->value);
+                               PARSE_ERROR_MALLOC(p->pci_whitelist[i]);
+
+                               break;
+                       }
+
+                       PARSE_ERROR_MESSAGE((i < APP_MAX_LINKS),
+                               section_name, entry->name,
+                               "too many elements");
+                       continue;
+               }
+
+               /* vdev */
+               if (strcmp(entry->name, "vdev") == 0) {
+                       uint32_t i;
+
+                       for (i = 0; i < APP_MAX_LINKS; i++) {
+                               if (p->vdev[i])
+                                       continue;
+
+                               p->vdev[i] = strdup(entry->value);
+                               PARSE_ERROR_MALLOC(p->vdev[i]);
+
+                               break;
+                       }
+
+                       PARSE_ERROR_MESSAGE((i < APP_MAX_LINKS),
+                               section_name, entry->name,
+                               "too many elements");
+                       continue;
+               }
+
+               /* vmware_tsc_map */
+               if (strcmp(entry->name, "vmware_tsc_map") == 0) {
+                       int val;
+
+                       PARSE_ERROR_DUPLICATE((p->vmware_tsc_map_present == 0),
+                               section_name,
+                               entry->name);
+                       p->vmware_tsc_map_present = 1;
+
+                       val = parser_read_arg_bool(entry->value);
+                       PARSE_ERROR((val >= 0), section_name, entry->name);
+                       p->vmware_tsc_map = val;
+                       continue;
+               }
+
+               /* proc_type */
+               if (strcmp(entry->name, "proc_type") == 0) {
+                       PARSE_ERROR_DUPLICATE((p->proc_type == NULL),
+                               section_name,
+                               entry->name);
+                       p->proc_type = strdup(entry->value);
+                       continue;
+               }
+
+               /* syslog */
+               if (strcmp(entry->name, "syslog") == 0) {
+                       PARSE_ERROR_DUPLICATE((p->syslog == NULL),
+                               section_name,
+                               entry->name);
+                       p->syslog = strdup(entry->value);
+                       continue;
+               }
+
+               /* log_level */
+               if (strcmp(entry->name, "log_level") == 0) {
+                       int status;
+
+                       PARSE_ERROR_DUPLICATE((p->log_level_present == 0),
+                               section_name,
+                               entry->name);
+                       p->log_level_present = 1;
+
+                       status = parser_read_uint32(&p->log_level,
+                               entry->value);
+                       PARSE_ERROR((status == 0), section_name, entry->name);
+                       continue;
+               }
+
+               /* version */
+               if (strcmp(entry->name, "v") == 0) {
+                       int val;
+
+                       PARSE_ERROR_DUPLICATE((p->version_present == 0),
+                               section_name,
+                               entry->name);
+                       p->version_present = 1;
+
+                       val = parser_read_arg_bool(entry->value);
+                       PARSE_ERROR((val >= 0), section_name, entry->name);
+                       p->version = val;
+                       continue;
+               }
+
+               /* help */
+               if ((strcmp(entry->name, "help") == 0) ||
+                       (strcmp(entry->name, "h") == 0)) {
+                       int val;
+
+                       PARSE_ERROR_DUPLICATE((p->help_present == 0),
+                               section_name,
+                               entry->name);
+                       p->help_present = 1;
+
+                       val = parser_read_arg_bool(entry->value);
+                       PARSE_ERROR((val >= 0), section_name, entry->name);
+                       p->help = val;
+                       continue;
+               }
+
+               /* no_huge */
+               if (strcmp(entry->name, "no_huge") == 0) {
+                       int val;
+
+                       PARSE_ERROR_DUPLICATE((p->no_huge_present == 0),
+                               section_name,
+                               entry->name);
+                       p->no_huge_present = 1;
+
+                       val = parser_read_arg_bool(entry->value);
+                       PARSE_ERROR((val >= 0), section_name, entry->name);
+                       p->no_huge = val;
+                       continue;
+               }
+
+               /* no_pci */
+               if (strcmp(entry->name, "no_pci") == 0) {
+                       int val;
+
+                       PARSE_ERROR_DUPLICATE((p->no_pci_present == 0),
+                               section_name,
+                               entry->name);
+                       p->no_pci_present = 1;
+
+                       val = parser_read_arg_bool(entry->value);
+                       PARSE_ERROR((val >= 0), section_name, entry->name);
+                       p->no_pci = val;
+                       continue;
+               }
+
+               /* no_hpet */
+               if (strcmp(entry->name, "no_hpet") == 0) {
+                       int val;
+
+                       PARSE_ERROR_DUPLICATE((p->no_hpet_present == 0),
+                               section_name,
+                               entry->name);
+                       p->no_hpet_present = 1;
+
+                       val = parser_read_arg_bool(entry->value);
+                       PARSE_ERROR((val >= 0), section_name, entry->name);
+                       p->no_hpet = val;
+                       continue;
+               }
+
+               /* no_shconf */
+               if (strcmp(entry->name, "no_shconf") == 0) {
+                       int val;
+
+                       PARSE_ERROR_DUPLICATE((p->no_shconf_present == 0),
+                               section_name,
+                               entry->name);
+                       p->no_shconf_present = 1;
+
+                       val = parser_read_arg_bool(entry->value);
+                       PARSE_ERROR((val >= 0), section_name, entry->name);
+                       p->no_shconf = val;
+                       continue;
+               }
+
+               /* add_driver */
+               if (strcmp(entry->name, "d") == 0) {
+                       PARSE_ERROR_DUPLICATE((p->add_driver == NULL),
+                               section_name,
+                               entry->name);
+                       p->add_driver = strdup(entry->value);
+                       continue;
+               }
+
+               /* socket_mem */
+               if (strcmp(entry->name, "socket_mem") == 0) {
+                       PARSE_ERROR_DUPLICATE((p->socket_mem == NULL),
+                               section_name,
+                               entry->name);
+                       p->socket_mem = strdup(entry->value);
+                       continue;
+               }
+
+               /* huge_dir */
+               if (strcmp(entry->name, "huge_dir") == 0) {
+                       PARSE_ERROR_DUPLICATE((p->huge_dir == NULL),
+                               section_name,
+                               entry->name);
+                       p->huge_dir = strdup(entry->value);
+                       continue;
+               }
+
+               /* file_prefix */
+               if (strcmp(entry->name, "file_prefix") == 0) {
+                       PARSE_ERROR_DUPLICATE((p->file_prefix == NULL),
+                               section_name,
+                               entry->name);
+                       p->file_prefix = strdup(entry->value);
+                       continue;
+               }
+
+               /* base_virtaddr */
+               if (strcmp(entry->name, "base_virtaddr") == 0) {
+                       PARSE_ERROR_DUPLICATE((p->base_virtaddr == NULL),
+                               section_name,
+                               entry->name);
+                       p->base_virtaddr = strdup(entry->value);
+                       continue;
+               }
+
+               /* create_uio_dev */
+               if (strcmp(entry->name, "create_uio_dev") == 0) {
+                       int val;
+
+                       PARSE_ERROR_DUPLICATE((p->create_uio_dev_present == 0),
+                               section_name,
+                               entry->name);
+                       p->create_uio_dev_present = 1;
+
+                       val = parser_read_arg_bool(entry->value);
+                       PARSE_ERROR((val >= 0), section_name, entry->name);
+                       p->create_uio_dev = val;
+                       continue;
+               }
+
+               /* vfio_intr */
+               if (strcmp(entry->name, "vfio_intr") == 0) {
+                       PARSE_ERROR_DUPLICATE((p->vfio_intr == NULL),
+                               section_name,
+                               entry->name);
+                       p->vfio_intr = strdup(entry->value);
+                       continue;
+               }
+
+               /* xen_dom0 */
+               if (strcmp(entry->name, "xen_dom0") == 0) {
+                       int val;
+
+                       PARSE_ERROR_DUPLICATE((p->xen_dom0_present == 0),
+                               section_name,
+                               entry->name);
+                       p->xen_dom0_present = 1;
+
+                       val = parser_read_arg_bool(entry->value);
+                       PARSE_ERROR((val >= 0), section_name, entry->name);
+                       p->xen_dom0 = val;
+                       continue;
+               }
+
+               /* unrecognized */
+               PARSE_ERROR_INVALID(0, section_name, entry->name);
+       }
+
+       free(entries);
+}
+
+static int
+parse_pipeline_pcap_source(struct app_params *app,
+       struct app_pipeline_params *p,
+       const char *file_name, const char *cp_size)
+{
+       const char *next = NULL;
+       char *end;
+       uint32_t i;
+       int parse_file = 0;
+
+       if (file_name && !cp_size) {
+               next = file_name;
+               parse_file = 1; /* parse file path */
+       } else if (cp_size && !file_name) {
+               next = cp_size;
+               parse_file = 0; /* parse copy size */
+       } else
+               return -EINVAL;
+
+       char name[APP_PARAM_NAME_SIZE];
+       size_t name_len;
+
+       if (p->n_pktq_in == 0)
+               return -EINVAL;
+
+       i = 0;
+       while (*next != '\0') {
+               uint32_t id;
+
+               if (i >= p->n_pktq_in)
+                       return -EINVAL;
+
+               id = p->pktq_in[i].id;
+
+               end = strchr(next, ' ');
+               if (!end)
+                       name_len = strlen(next);
+               else
+                       name_len = end - next;
+
+               if (name_len == 0 || name_len == sizeof(name))
+                       return -EINVAL;
+
+               strncpy(name, next, name_len);
+               name[name_len] = '\0';
+               next += name_len;
+               if (*next != '\0')
+                       next++;
+
+               if (parse_file) {
+                       app->source_params[id].file_name = strdup(name);
+                       if (app->source_params[id].file_name == NULL)
+                               return -ENOMEM;
+               } else {
+                       if (parser_read_uint32(
+                               &app->source_params[id].n_bytes_per_pkt,
+                               name) != 0) {
+                               if (app->source_params[id].
+                                       file_name != NULL)
+                                       free(app->source_params[id].
+                                               file_name);
+                               return -EINVAL;
+                       }
+               }
+
+               i++;
+
+               if (i == p->n_pktq_in)
+                       return 0;
+       }
+
+       return -EINVAL;
+}
+
+static int
+parse_pipeline_pcap_sink(struct app_params *app,
+       struct app_pipeline_params *p,
+       const char *file_name, const char *n_pkts_to_dump)
+{
+       const char *next = NULL;
+       char *end;
+       uint32_t i;
+       int parse_file = 0;
+
+       if (file_name && !n_pkts_to_dump) {
+               next = file_name;
+               parse_file = 1; /* parse file path */
+       } else if (n_pkts_to_dump && !file_name) {
+               next = n_pkts_to_dump;
+               parse_file = 0; /* parse copy size */
+       } else
+               return -EINVAL;
+
+       char name[APP_PARAM_NAME_SIZE];
+       size_t name_len;
+
+       if (p->n_pktq_out == 0)
+               return -EINVAL;
+
+       i = 0;
+       while (*next != '\0') {
+               uint32_t id;
+
+               if (i >= p->n_pktq_out)
+                       return -EINVAL;
+
+               id = p->pktq_out[i].id;
+
+               end = strchr(next, ' ');
+               if (!end)
+                       name_len = strlen(next);
+               else
+                       name_len = end - next;
+
+               if (name_len == 0 || name_len == sizeof(name))
+                       return -EINVAL;
+
+               strncpy(name, next, name_len);
+               name[name_len] = '\0';
+               next += name_len;
+               if (*next != '\0')
+                       next++;
+
+               if (parse_file) {
+                       app->sink_params[id].file_name = strdup(name);
+                       if (app->sink_params[id].file_name == NULL)
+                               return -ENOMEM;
+               } else {
+                       if (parser_read_uint32(
+                               &app->sink_params[id].n_pkts_to_dump,
+                               name) != 0) {
+                               if (app->sink_params[id].file_name !=
+                                       NULL)
+                                       free(app->sink_params[id].
+                                               file_name);
+                               return -EINVAL;
+                       }
+               }
+
+               i++;
+
+               if (i == p->n_pktq_out)
+                       return 0;
+       }
+
+       return -EINVAL;
+}
+
+static int
+parse_pipeline_pktq_in(struct app_params *app,
+       struct app_pipeline_params *p,
+       const char *value)
+{
+       const char *next = value;
+       if(next == NULL)
+               return -EINVAL;
+       char *end;
+       char name[APP_PARAM_NAME_SIZE];
+       size_t name_len;
+
+       while (*next != '\0') {
+               enum app_pktq_in_type type;
+               int id;
+               char *end_space;
+               char *end_tab;
+                if(next != NULL)
+               next = skip_white_spaces(next);
+               if (!next)
+                       break;
+
+               end_space = strchr(next, ' ');
+               end_tab = strchr(next, '        ');
+
+               if (end_space && (!end_tab))
+                       end = end_space;
+               else if ((!end_space) && end_tab)
+                       end = end_tab;
+               else if (end_space && end_tab)
+                       end = RTE_MIN(end_space, end_tab);
+               else
+                       end = NULL;
+
+               if (!end)
+                       name_len = strlen(next);
+               else
+                       name_len = end - next;
+
+               if (name_len == 0 || name_len == sizeof(name))
+                       return -EINVAL;
+
+               strncpy(name, next, name_len);
+               name[name_len] = '\0';
+               next += name_len;
+               if (*next != '\0')
+                       next++;
+
+               if (validate_name(name, "RXQ", 2) == 0) {
+                       type = APP_PKTQ_IN_HWQ;
+                       id = APP_PARAM_ADD(app->hwq_in_params, name);
+               } else if (validate_name(name, "SWQ", 1) == 0) {
+                       type = APP_PKTQ_IN_SWQ;
+                       id = APP_PARAM_ADD(app->swq_params, name);
+               } else if (validate_name(name, "TM", 1) == 0) {
+                       type = APP_PKTQ_IN_TM;
+                       id = APP_PARAM_ADD(app->tm_params, name);
+               } else if (validate_name(name, "SOURCE", 1) == 0) {
+                       type = APP_PKTQ_IN_SOURCE;
+                       id = APP_PARAM_ADD(app->source_params, name);
+               } else
+                       return -EINVAL;
+
+               if (id < 0)
+                       return id;
+
+               p->pktq_in[p->n_pktq_in].type = type;
+               p->pktq_in[p->n_pktq_in].id = (uint32_t) id;
+               p->n_pktq_in++;
+       }
+
+       return 0;
+}
+
+static int
+parse_pipeline_pktq_out(struct app_params *app,
+       struct app_pipeline_params *p,
+       const char *value)
+{
+       const char *next = value;
+       if(next == NULL)
+               return -EINVAL;
+       char *end;
+       char name[APP_PARAM_NAME_SIZE];
+       size_t name_len;
+
+       while (*next != '\0') {
+               enum app_pktq_out_type type;
+               int id;
+               char *end_space;
+               char *end_tab;
+                if(next != NULL)
+               next = skip_white_spaces(next);
+               if (!next)
+                       break;
+
+               end_space = strchr(next, ' ');
+               end_tab = strchr(next, '        ');
+
+               if (end_space && (!end_tab))
+                       end = end_space;
+               else if ((!end_space) && end_tab)
+                       end = end_tab;
+               else if (end_space && end_tab)
+                       end = RTE_MIN(end_space, end_tab);
+               else
+                       end = NULL;
+
+               if (!end)
+                       name_len = strlen(next);
+               else
+                       name_len = end - next;
+
+               if (name_len == 0 || name_len == sizeof(name))
+                       return -EINVAL;
+
+               strncpy(name, next, name_len);
+               name[name_len] = '\0';
+               next += name_len;
+               if (*next != '\0')
+                       next++;
+               if (validate_name(name, "TXQ", 2) == 0) {
+                       type = APP_PKTQ_OUT_HWQ;
+                       id = APP_PARAM_ADD(app->hwq_out_params, name);
+               } else if (validate_name(name, "SWQ", 1) == 0) {
+                       type = APP_PKTQ_OUT_SWQ;
+                       id = APP_PARAM_ADD(app->swq_params, name);
+               } else if (validate_name(name, "TM", 1) == 0) {
+                       type = APP_PKTQ_OUT_TM;
+                       id = APP_PARAM_ADD(app->tm_params, name);
+               } else if (validate_name(name, "SINK", 1) == 0) {
+                       type = APP_PKTQ_OUT_SINK;
+                       id = APP_PARAM_ADD(app->sink_params, name);
+               } else
+                       return -EINVAL;
+
+               if (id < 0)
+                       return id;
+
+               p->pktq_out[p->n_pktq_out].type = type;
+               p->pktq_out[p->n_pktq_out].id = id;
+               p->n_pktq_out++;
+       }
+
+       return 0;
+}
+
+static int
+parse_pipeline_msgq_in(struct app_params *app,
+       struct app_pipeline_params *p,
+       const char *value)
+{
+       const char *next = value;
+       if(next == NULL)
+               return -EINVAL;
+       char *end;
+       char name[APP_PARAM_NAME_SIZE];
+       size_t name_len;
+       ssize_t idx;
+
+       while (*next != '\0') {
+               char *end_space;
+               char *end_tab;
+               if(next != NULL)
+               next = skip_white_spaces(next);
+               if (!next)
+                       break;
+
+               end_space = strchr(next, ' ');
+               end_tab = strchr(next, '        ');
+
+               if (end_space && (!end_tab))
+                       end = end_space;
+               else if ((!end_space) && end_tab)
+                       end = end_tab;
+               else if (end_space && end_tab)
+                       end = RTE_MIN(end_space, end_tab);
+               else
+                       end = NULL;
+
+               if (!end)
+                       name_len = strlen(next);
+               else
+                       name_len = end - next;
+
+               if (name_len == 0 || name_len == sizeof(name))
+                       return -EINVAL;
+
+               strncpy(name, next, name_len);
+               name[name_len] = '\0';
+               next += name_len;
+               if (*next != '\0')
+                       next++;
+
+               if (validate_name(name, "MSGQ", 1) != 0)
+                       return -EINVAL;
+
+               idx = APP_PARAM_ADD(app->msgq_params, name);
+               if (idx < 0)
+                       return idx;
+
+               p->msgq_in[p->n_msgq_in] = idx;
+               p->n_msgq_in++;
+       }
+
+       return 0;
+}
+
+static int
+parse_pipeline_msgq_out(struct app_params *app,
+       struct app_pipeline_params *p,
+       const char *value)
+{
+       const char *next = value;
+       if(next == NULL)
+               return -EINVAL;
+       char *end;
+       char name[APP_PARAM_NAME_SIZE];
+       size_t name_len;
+       ssize_t idx;
+
+       while (*next != '\0') {
+               char *end_space;
+               char *end_tab;
+               if(next != NULL)
+               next = skip_white_spaces(next);
+               if (!next)
+                       break;
+
+               end_space = strchr(next, ' ');
+               end_tab = strchr(next, '        ');
+
+               if (end_space && (!end_tab))
+                       end = end_space;
+               else if ((!end_space) && end_tab)
+                       end = end_tab;
+               else if (end_space && end_tab)
+                       end = RTE_MIN(end_space, end_tab);
+               else
+                       end = NULL;
+
+               if (!end)
+                       name_len = strlen(next);
+               else
+                       name_len = end - next;
+
+               if (name_len == 0 || name_len == sizeof(name))
+                       return -EINVAL;
+
+               strncpy(name, next, name_len);
+               name[name_len] = '\0';
+               next += name_len;
+               if (*next != '\0')
+                       next++;
+
+               if (validate_name(name, "MSGQ", 1) != 0)
+                       return -EINVAL;
+
+               idx = APP_PARAM_ADD(app->msgq_params, name);
+               if (idx < 0)
+                       return idx;
+
+               p->msgq_out[p->n_msgq_out] = idx;
+               p->n_msgq_out++;
+       }
+
+       return 0;
+}
+
+static void
+parse_pipeline(struct app_params *app,
+       const char *section_name,
+       struct rte_cfgfile *cfg)
+{
+       char name[CFG_NAME_LEN];
+       struct app_pipeline_params *param;
+       struct rte_cfgfile_entry *entries;
+       ssize_t param_idx;
+       int n_entries, i;
+
+       n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
+       PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
+
+       entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
+       PARSE_ERROR_MALLOC(entries != NULL);
+
+       rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
+
+       param_idx = APP_PARAM_ADD(app->pipeline_params, section_name);
+       PARSER_PARAM_ADD_CHECK(param_idx, app->pipeline_params, section_name);
+
+       param = &app->pipeline_params[param_idx];
+
+       for (i = 0; i < n_entries; i++) {
+               struct rte_cfgfile_entry *ent = &entries[i];
+
+               if (strcmp(ent->name, "type") == 0) {
+                       int w_size = snprintf(param->type, RTE_DIM(param->type),
+                                       "%s", ent->value);
+
+                       PARSE_ERROR(((w_size > 0) &&
+                               (w_size < (int)RTE_DIM(param->type))),
+                               section_name,
+                               ent->name);
+                       continue;
+               }
+
+               if (strcmp(ent->name, "core") == 0) {
+                       int status = parse_pipeline_core(
+                               &param->socket_id, &param->core_id,
+                               &param->hyper_th_id, ent->value);
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+                       continue;
+               }
+
+               if (strcmp(ent->name, "pktq_in") == 0) {
+                       int status = parse_pipeline_pktq_in(app, param,
+                               ent->value);
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+                       continue;
+               }
+
+               if (strcmp(ent->name, "pktq_out") == 0) {
+                       int status = parse_pipeline_pktq_out(app, param,
+                               ent->value);
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+                       continue;
+               }
+
+               if (strcmp(ent->name, "msgq_in") == 0) {
+                       int status = parse_pipeline_msgq_in(app, param,
+                               ent->value);
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+                       continue;
+               }
+
+               if (strcmp(ent->name, "msgq_out") == 0) {
+                       int status = parse_pipeline_msgq_out(app, param,
+                               ent->value);
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+                       continue;
+               }
+
+               if (strcmp(ent->name, "timer_period") == 0) {
+                       int status = parser_read_uint32(
+                               &param->timer_period,
+                               ent->value);
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+                       continue;
+               }
+
+               if (strcmp(ent->name, "pcap_file_rd") == 0) {
+                       int status;
+
+#ifndef RTE_PORT_PCAP
+                       PARSE_ERROR_INVALID(0, section_name, ent->name);
+#endif
+
+                       status = parse_pipeline_pcap_source(app,
+                               param, ent->value, NULL);
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+                       continue;
+               }
+
+               if (strcmp(ent->name, "pcap_bytes_rd_per_pkt") == 0) {
+                       int status;
+
+#ifndef RTE_PORT_PCAP
+                       PARSE_ERROR_INVALID(0, section_name, ent->name);
+#endif
+
+                       status = parse_pipeline_pcap_source(app,
+                               param, NULL, ent->value);
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+                       continue;
+               }
+
+               if (strcmp(ent->name, "pcap_file_wr") == 0) {
+                       int status;
+
+#ifndef RTE_PORT_PCAP
+                       PARSE_ERROR_INVALID(0, section_name, ent->name);
+#endif
+
+                       status = parse_pipeline_pcap_sink(app, param,
+                               ent->value, NULL);
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+                       continue;
+               }
+
+               if (strcmp(ent->name, "pcap_n_pkt_wr") == 0) {
+                       int status;
+
+#ifndef RTE_PORT_PCAP
+                       PARSE_ERROR_INVALID(0, section_name, ent->name);
+#endif
+
+                       status = parse_pipeline_pcap_sink(app, param,
+                               NULL, ent->value);
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+                       continue;
+               }
+
+               /* pipeline type specific items */
+               APP_CHECK((param->n_args < APP_MAX_PIPELINE_ARGS),
+                       "Parse error in section \"%s\": too many "
+                       "pipeline specified parameters", section_name);
+
+               param->args_name[param->n_args] = strdup(ent->name);
+               param->args_value[param->n_args] = strdup(ent->value);
+
+               APP_CHECK((param->args_name[param->n_args] != NULL) &&
+                       (param->args_value[param->n_args] != NULL),
+                       "Parse error: no free memory");
+
+               param->n_args++;
+       }
+
+       param->parsed = 1;
+
+       snprintf(name, sizeof(name), "MSGQ-REQ-%s", section_name);
+       param_idx = APP_PARAM_ADD(app->msgq_params, name);
+       PARSER_PARAM_ADD_CHECK(param_idx, app->msgq_params, name);
+       app->msgq_params[param_idx].cpu_socket_id = param->socket_id;
+       param->msgq_in[param->n_msgq_in++] = param_idx;
+
+       snprintf(name, sizeof(name), "MSGQ-RSP-%s", section_name);
+       param_idx = APP_PARAM_ADD(app->msgq_params, name);
+       PARSER_PARAM_ADD_CHECK(param_idx, app->msgq_params, name);
+       app->msgq_params[param_idx].cpu_socket_id = param->socket_id;
+       param->msgq_out[param->n_msgq_out++] = param_idx;
+
+       snprintf(name, sizeof(name), "MSGQ-REQ-CORE-s%" PRIu32 "c%" PRIu32 "%s",
+               param->socket_id,
+               param->core_id,
+               (param->hyper_th_id) ? "h" : "");
+       param_idx = APP_PARAM_ADD(app->msgq_params, name);
+       PARSER_PARAM_ADD_CHECK(param_idx, app->msgq_params, name);
+       app->msgq_params[param_idx].cpu_socket_id = param->socket_id;
+
+       snprintf(name, sizeof(name), "MSGQ-RSP-CORE-s%" PRIu32 "c%" PRIu32 "%s",
+               param->socket_id,
+               param->core_id,
+               (param->hyper_th_id) ? "h" : "");
+       param_idx = APP_PARAM_ADD(app->msgq_params, name);
+       PARSER_PARAM_ADD_CHECK(param_idx, app->msgq_params, name);
+       app->msgq_params[param_idx].cpu_socket_id = param->socket_id;
+
+       free(entries);
+}
+
+static void
+parse_mempool(struct app_params *app,
+       const char *section_name,
+       struct rte_cfgfile *cfg)
+{
+       struct app_mempool_params *param;
+       struct rte_cfgfile_entry *entries;
+       ssize_t param_idx;
+       int n_entries, i;
+
+       n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
+       PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
+
+       entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
+       PARSE_ERROR_MALLOC(entries != NULL);
+
+       rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
+
+       param_idx = APP_PARAM_ADD(app->mempool_params, section_name);
+       PARSER_PARAM_ADD_CHECK(param_idx, app->mempool_params, section_name);
+
+       param = &app->mempool_params[param_idx];
+
+       for (i = 0; i < n_entries; i++) {
+               struct rte_cfgfile_entry *ent = &entries[i];
+
+               if (strcmp(ent->name, "buffer_size") == 0) {
+                       int status = parser_read_uint32(
+                               &param->buffer_size, ent->value);
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+                       continue;
+               }
+
+               if (strcmp(ent->name, "pool_size") == 0) {
+                       int status = parser_read_uint32(
+                               &param->pool_size, ent->value);
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+                       continue;
+               }
+
+               if (strcmp(ent->name, "cache_size") == 0) {
+                       int status = parser_read_uint32(
+                               &param->cache_size, ent->value);
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+                       continue;
+               }
+
+               if (strcmp(ent->name, "cpu") == 0) {
+                       int status = parser_read_uint32(
+                               &param->cpu_socket_id, ent->value);
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+                       continue;
+               }
+
+               /* unrecognized */
+               PARSE_ERROR_INVALID(0, section_name, ent->name);
+       }
+
+       param->parsed = 1;
+
+       free(entries);
+}
+
+static void
+parse_link(struct app_params *app,
+       const char *section_name,
+       struct rte_cfgfile *cfg)
+{
+       struct app_link_params *param;
+       struct rte_cfgfile_entry *entries;
+       int n_entries, i;
+       int pci_bdf_present = 0;
+       ssize_t param_idx;
+
+       n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
+       PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
+
+       entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
+       PARSE_ERROR_MALLOC(entries != NULL);
+
+       rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
+
+       param_idx = APP_PARAM_ADD(app->link_params, section_name);
+       PARSER_PARAM_ADD_CHECK(param_idx, app->link_params, section_name);
+
+       param = &app->link_params[param_idx];
+
+       for (i = 0; i < n_entries; i++) {
+               struct rte_cfgfile_entry *ent = &entries[i];
+
+               if (strcmp(ent->name, "promisc") == 0) {
+                       int status = parser_read_arg_bool(ent->value);
+
+                       PARSE_ERROR((status != -EINVAL), section_name,
+                               ent->name);
+                       param->promisc = status;
+                       continue;
+               }
+
+               if (strcmp(ent->name, "arp_q") == 0) {
+                       int status = parser_read_uint32(&param->arp_q,
+                               ent->value);
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+                       continue;
+               }
+
+               if (strcmp(ent->name, "tcp_syn_q") == 0) {
+                       int status = parser_read_uint32(
+                               &param->tcp_syn_q, ent->value);
+
+                       PARSE_ERROR((status == 0), section_name, ent->name);
+                       continue;
+               }
+
+               if (strcmp(ent->name, "ip_local_q") == 0) {
+                       int status = parser_read_uint32(
+                               &param->ip_local_q, ent->value);
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+                       continue;
+               }
+
+
+               if (strcmp(ent->name, "tcp_local_q") == 0) {
+                       int status = parser_read_uint32(
+                               &param->tcp_local_q, ent->value);
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+                       continue;
+               }
+
+               if (strcmp(ent->name, "udp_local_q") == 0) {
+                       int status = parser_read_uint32(
+                               &param->udp_local_q, ent->value);
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+                       continue;
+               }
+
+               if (strcmp(ent->name, "sctp_local_q") == 0) {
+                       int status = parser_read_uint32(
+                               &param->sctp_local_q, ent->value);
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+                       continue;
+               }
+
+               if (strcmp(ent->name, "pci_bdf") == 0) {
+                       PARSE_ERROR_DUPLICATE((pci_bdf_present == 0),
+                               section_name, ent->name);
+
+                       snprintf(param->pci_bdf, APP_LINK_PCI_BDF_SIZE,
+                               "%s", ent->value);
+                       pci_bdf_present = 1;
+                       continue;
+               }
+
+               /* unrecognized */
+               PARSE_ERROR_INVALID(0, section_name, ent->name);
+       }
+
+       /* Check for mandatory fields */
+       if (app->port_mask)
+               PARSE_ERROR_MESSAGE((pci_bdf_present == 0),
+                       section_name, "pci_bdf",
+                       "entry not allowed (port_mask is provided)");
+       else
+               PARSE_ERROR_MESSAGE((pci_bdf_present),
+                       section_name, "pci_bdf",
+                       "this entry is mandatory (port_mask is not "
+                       "provided)");
+
+       param->parsed = 1;
+
+       free(entries);
+}
+
+static void
+parse_rxq(struct app_params *app,
+       const char *section_name,
+       struct rte_cfgfile *cfg)
+{
+       struct app_pktq_hwq_in_params *param;
+       struct rte_cfgfile_entry *entries;
+       int n_entries, i;
+       ssize_t param_idx;
+
+       n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
+       PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
+
+       entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
+       PARSE_ERROR_MALLOC(entries != NULL);
+
+       rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
+
+       param_idx = APP_PARAM_ADD(app->hwq_in_params, section_name);
+       PARSER_PARAM_ADD_CHECK(param_idx, app->hwq_in_params, section_name);
+
+       param = &app->hwq_in_params[param_idx];
+
+       for (i = 0; i < n_entries; i++) {
+               struct rte_cfgfile_entry *ent = &entries[i];
+
+               if (strcmp(ent->name, "mempool") == 0) {
+                       int status = validate_name(ent->value,
+                               "MEMPOOL", 1);
+                       ssize_t idx;
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+                       idx = APP_PARAM_ADD(app->mempool_params,
+                               ent->value);
+                       PARSER_PARAM_ADD_CHECK(idx, app->mempool_params,
+                               section_name);
+                       param->mempool_id = idx;
+                       continue;
+               }
+
+               if (strcmp(ent->name, "size") == 0) {
+                       int status = parser_read_uint32(&param->size,
+                               ent->value);
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+                       continue;
+               }
+
+               if (strcmp(ent->name, "burst") == 0) {
+                       int status = parser_read_uint32(&param->burst,
+                               ent->value);
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+                       continue;
+               }
+
+               /* unrecognized */
+               PARSE_ERROR_INVALID(0, section_name, ent->name);
+       }
+
+       param->parsed = 1;
+
+       free(entries);
+}
+
+static void
+parse_txq(struct app_params *app,
+       const char *section_name,
+       struct rte_cfgfile *cfg)
+{
+       struct app_pktq_hwq_out_params *param;
+       struct rte_cfgfile_entry *entries;
+       int n_entries, i;
+       ssize_t param_idx;
+
+       n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
+       PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
+
+       entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
+       PARSE_ERROR_MALLOC(entries != NULL);
+
+       rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
+
+       param_idx = APP_PARAM_ADD(app->hwq_out_params, section_name);
+       PARSER_PARAM_ADD_CHECK(param_idx, app->hwq_out_params, section_name);
+
+       param = &app->hwq_out_params[param_idx];
+
+       for (i = 0; i < n_entries; i++) {
+               struct rte_cfgfile_entry *ent = &entries[i];
+
+               if (strcmp(ent->name, "size") == 0) {
+                       int status = parser_read_uint32(&param->size,
+                               ent->value);
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+                       continue;
+               }
+
+               if (strcmp(ent->name, "burst") == 0) {
+                       int status = parser_read_uint32(&param->burst,
+                               ent->value);
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+                       continue;
+               }
+
+               if (strcmp(ent->name, "dropless") == 0) {
+                       int status = parser_read_arg_bool(ent->value);
+
+
+                       PARSE_ERROR((status != -EINVAL), section_name,
+                               ent->name);
+                       param->dropless = status;
+                       continue;
+               }
+
+               /* unrecognized */
+               PARSE_ERROR_INVALID(0, section_name, ent->name);
+       }
+
+       param->parsed = 1;
+
+       free(entries);
+}
+
+static void
+parse_swq(struct app_params *app,
+       const char *section_name,
+       struct rte_cfgfile *cfg)
+{
+       struct app_pktq_swq_params *param;
+       struct rte_cfgfile_entry *entries;
+       int n_entries, i;
+       uint32_t mtu_present = 0;
+       uint32_t metadata_size_present = 0;
+       uint32_t mempool_direct_present = 0;
+       uint32_t mempool_indirect_present = 0;
+
+       ssize_t param_idx;
+
+       n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
+       PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
+
+       entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
+       PARSE_ERROR_MALLOC(entries != NULL);
+
+       rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
+
+       param_idx = APP_PARAM_ADD(app->swq_params, section_name);
+       PARSER_PARAM_ADD_CHECK(param_idx, app->swq_params, section_name);
+
+       param = &app->swq_params[param_idx];
+
+       for (i = 0; i < n_entries; i++) {
+               struct rte_cfgfile_entry *ent = &entries[i];
+
+               if (strcmp(ent->name, "size") == 0) {
+                       int status = parser_read_uint32(&param->size,
+                               ent->value);
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+                       continue;
+               }
+
+               if (strcmp(ent->name, "burst_read") == 0) {
+                       int status = parser_read_uint32(&
+                               param->burst_read, ent->value);
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+                       continue;
+               }
+
+               if (strcmp(ent->name, "burst_write") == 0) {
+                       int status = parser_read_uint32(
+                               &param->burst_write, ent->value);
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+                       continue;
+               }
+
+               if (strcmp(ent->name, "dropless") == 0) {
+                       int status = parser_read_arg_bool(ent->value);
+
+                       PARSE_ERROR((status != -EINVAL), section_name,
+                               ent->name);
+                       param->dropless = status;
+                       continue;
+               }
+
+               if (strcmp(ent->name, "n_retries") == 0) {
+                       int status = parser_read_uint64(&param->n_retries,
+                               ent->value);
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+                       continue;
+               }
+
+               if (strcmp(ent->name, "cpu") == 0) {
+                       int status = parser_read_uint32(
+                               &param->cpu_socket_id, ent->value);
+
+                       PARSE_ERROR((status == 0), section_name, ent->name);
+                       continue;
+               }
+
+               if (strcmp(ent->name, "ipv4_frag") == 0) {
+                       int status = parser_read_arg_bool(ent->value);
+
+                       PARSE_ERROR((status != -EINVAL), section_name,
+                               ent->name);
+
+                       param->ipv4_frag = status;
+                       if (param->mtu == 0)
+                               param->mtu = 1500;
+
+                       continue;
+               }
+
+               if (strcmp(ent->name, "ipv6_frag") == 0) {
+                       int status = parser_read_arg_bool(ent->value);
+
+                       PARSE_ERROR((status != -EINVAL), section_name,
+                               ent->name);
+                       param->ipv6_frag = status;
+                       if (param->mtu == 0)
+                               param->mtu = 1320;
+                       continue;
+               }
+
+               if (strcmp(ent->name, "ipv4_ras") == 0) {
+                       int status = parser_read_arg_bool(ent->value);
+
+                       PARSE_ERROR((status != -EINVAL), section_name,
+                               ent->name);
+                       param->ipv4_ras = status;
+                       continue;
+               }
+
+               if (strcmp(ent->name, "ipv6_ras") == 0) {
+                       int status = parser_read_arg_bool(ent->value);
+
+                       PARSE_ERROR((status != -EINVAL), section_name,
+                               ent->name);
+                       param->ipv6_ras = status;
+                       continue;
+               }
+
+               if (strcmp(ent->name, "mtu") == 0) {
+                       int status = parser_read_uint32(&param->mtu,
+                                       ent->value);
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+                       mtu_present = 1;
+                       continue;
+               }
+
+               if (strcmp(ent->name, "metadata_size") == 0) {
+                       int status = parser_read_uint32(
+                               &param->metadata_size, ent->value);
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+                       metadata_size_present = 1;
+                       continue;
+               }
+
+               if (strcmp(ent->name, "mempool_direct") == 0) {
+                       int status = validate_name(ent->value,
+                               "MEMPOOL", 1);
+                       ssize_t idx;
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+
+                       idx = APP_PARAM_ADD(app->mempool_params,
+                               ent->value);
+                       PARSER_PARAM_ADD_CHECK(idx, app->mempool_params,
+                               section_name);
+                       param->mempool_direct_id = idx;
+                       mempool_direct_present = 1;
+                       continue;
+               }
+
+               if (strcmp(ent->name, "mempool_indirect") == 0) {
+                       int status = validate_name(ent->value,
+                               "MEMPOOL", 1);
+                       ssize_t idx;
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+                       idx = APP_PARAM_ADD(app->mempool_params,
+                               ent->value);
+                       PARSER_PARAM_ADD_CHECK(idx, app->mempool_params,
+                               section_name);
+                       param->mempool_indirect_id = idx;
+                       mempool_indirect_present = 1;
+                       continue;
+               }
+
+               /* unrecognized */
+               PARSE_ERROR_INVALID(0, section_name, ent->name);
+       }
+
+       APP_CHECK(((mtu_present) &&
+               ((param->ipv4_frag == 1) || (param->ipv6_frag == 1))),
+               "Parse error in section \"%s\": IPv4/IPv6 fragmentation "
+               "is off, therefore entry \"mtu\" is not allowed",
+               section_name);
+
+       APP_CHECK(((metadata_size_present) &&
+               ((param->ipv4_frag == 1) || (param->ipv6_frag == 1))),
+               "Parse error in section \"%s\": IPv4/IPv6 fragmentation "
+               "is off, therefore entry \"metadata_size\" is "
+               "not allowed", section_name);
+
+       APP_CHECK(((mempool_direct_present) &&
+               ((param->ipv4_frag == 1) || (param->ipv6_frag == 1))),
+               "Parse error in section \"%s\": IPv4/IPv6 fragmentation "
+               "is off, therefore entry \"mempool_direct\" is "
+               "not allowed", section_name);
+
+       APP_CHECK(((mempool_indirect_present) &&
+               ((param->ipv4_frag == 1) || (param->ipv6_frag == 1))),
+               "Parse error in section \"%s\": IPv4/IPv6 fragmentation "
+               "is off, therefore entry \"mempool_indirect\" is "
+               "not allowed", section_name);
+
+       param->parsed = 1;
+
+       free(entries);
+}
+
+static void
+parse_tm(struct app_params *app,
+       const char *section_name,
+       struct rte_cfgfile *cfg)
+{
+       struct app_pktq_tm_params *param;
+       struct rte_cfgfile_entry *entries;
+       int n_entries, i;
+       ssize_t param_idx;
+
+       n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
+       PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
+
+       entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
+       PARSE_ERROR_MALLOC(entries != NULL);
+
+       rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
+
+       param_idx = APP_PARAM_ADD(app->tm_params, section_name);
+       PARSER_PARAM_ADD_CHECK(param_idx, app->tm_params, section_name);
+
+       param = &app->tm_params[param_idx];
+
+       for (i = 0; i < n_entries; i++) {
+               struct rte_cfgfile_entry *ent = &entries[i];
+
+               if (strcmp(ent->name, "cfg") == 0) {
+                       param->file_name = strdup(ent->value);
+                       PARSE_ERROR_MALLOC(param->file_name != NULL);
+                       continue;
+               }
+
+               if (strcmp(ent->name, "burst_read") == 0) {
+                       int status = parser_read_uint32(
+                               &param->burst_read, ent->value);
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+                       continue;
+               }
+
+               if (strcmp(ent->name, "burst_write") == 0) {
+                       int status = parser_read_uint32(
+                               &param->burst_write, ent->value);
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+                       continue;
+               }
+
+               /* unrecognized */
+               PARSE_ERROR_INVALID(0, section_name, ent->name);
+       }
+
+       param->parsed = 1;
+
+       free(entries);
+}
+
+static void
+parse_source(struct app_params *app,
+       const char *section_name,
+       struct rte_cfgfile *cfg)
+{
+       struct app_pktq_source_params *param;
+       struct rte_cfgfile_entry *entries;
+       int n_entries, i;
+       ssize_t param_idx;
+       uint32_t pcap_file_present = 0;
+       uint32_t pcap_size_present = 0;
+
+       n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
+       PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
+
+       entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
+       PARSE_ERROR_MALLOC(entries != NULL);
+
+       rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
+
+       param_idx = APP_PARAM_ADD(app->source_params, section_name);
+       PARSER_PARAM_ADD_CHECK(param_idx, app->source_params, section_name);
+
+       param = &app->source_params[param_idx];
+
+       for (i = 0; i < n_entries; i++) {
+               struct rte_cfgfile_entry *ent = &entries[i];
+
+               if (strcmp(ent->name, "mempool") == 0) {
+                       int status = validate_name(ent->value,
+                               "MEMPOOL", 1);
+                       ssize_t idx;
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+                       idx = APP_PARAM_ADD(app->mempool_params,
+                               ent->value);
+                       PARSER_PARAM_ADD_CHECK(idx, app->mempool_params,
+                               section_name);
+                       param->mempool_id = idx;
+                       continue;
+               }
+
+               if (strcmp(ent->name, "burst") == 0) {
+                       int status = parser_read_uint32(&param->burst,
+                               ent->value);
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+                       continue;
+               }
+
+               if (strcmp(ent->name, "pcap_file_rd")) {
+                       PARSE_ERROR_DUPLICATE((pcap_file_present == 0),
+                               section_name, ent->name);
+
+                       param->file_name = strdup(ent->value);
+
+                       PARSE_ERROR_MALLOC(param->file_name != NULL);
+                       pcap_file_present = 1;
+
+                       continue;
+               }
+
+               if (strcmp(ent->name, "pcap_bytes_rd_per_pkt") == 0) {
+                       int status;
+
+                       PARSE_ERROR_DUPLICATE((pcap_size_present == 0),
+                               section_name, ent->name);
+
+                       status = parser_read_uint32(
+                               &param->n_bytes_per_pkt, ent->value);
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+                       pcap_size_present = 1;
+
+                       continue;
+               }
+
+               /* unrecognized */
+               PARSE_ERROR_INVALID(0, section_name, ent->name);
+       }
+
+       param->parsed = 1;
+
+       free(entries);
+}
+
+static void
+parse_sink(struct app_params *app,
+       const char *section_name,
+       struct rte_cfgfile *cfg)
+{
+       struct app_pktq_sink_params *param;
+       struct rte_cfgfile_entry *entries;
+       int n_entries, i;
+       ssize_t param_idx;
+       uint32_t pcap_file_present = 0;
+       uint32_t pcap_n_pkt_present = 0;
+
+       n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
+       PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
+
+       entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
+       PARSE_ERROR_MALLOC(entries != NULL);
+
+       rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
+
+       param_idx = APP_PARAM_ADD(app->sink_params, section_name);
+       PARSER_PARAM_ADD_CHECK(param_idx, app->sink_params, section_name);
+
+       param = &app->sink_params[param_idx];
+
+       for (i = 0; i < n_entries; i++) {
+               struct rte_cfgfile_entry *ent = &entries[i];
+
+               if (strcmp(ent->name, "pcap_file_wr")) {
+                       PARSE_ERROR_DUPLICATE((pcap_file_present == 0),
+                               section_name, ent->name);
+
+                       param->file_name = strdup(ent->value);
+
+                       PARSE_ERROR_MALLOC((param->file_name != NULL));
+
+                       continue;
+               }
+
+               if (strcmp(ent->name, "pcap_n_pkt_wr")) {
+                       int status;
+
+                       PARSE_ERROR_DUPLICATE((pcap_n_pkt_present == 0),
+                               section_name, ent->name);
+
+                       status = parser_read_uint32(
+                               &param->n_pkts_to_dump, ent->value);
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+
+                       continue;
+               }
+
+               /* unrecognized */
+               PARSE_ERROR_INVALID(0, section_name, ent->name);
+       }
+
+       param->parsed = 1;
+
+       free(entries);
+}
+
+static void
+parse_msgq_req_pipeline(struct app_params *app,
+       const char *section_name,
+       struct rte_cfgfile *cfg)
+{
+       struct app_msgq_params *param;
+       struct rte_cfgfile_entry *entries;
+       int n_entries, i;
+       ssize_t param_idx;
+
+       n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
+       PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
+
+       entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
+       PARSE_ERROR_MALLOC(entries != NULL);
+
+       rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
+
+       param_idx = APP_PARAM_ADD(app->msgq_params, section_name);
+       PARSER_PARAM_ADD_CHECK(param_idx, app->msgq_params, section_name);
+
+       param = &app->msgq_params[param_idx];
+
+       for (i = 0; i < n_entries; i++) {
+               struct rte_cfgfile_entry *ent = &entries[i];
+
+               if (strcmp(ent->name, "size") == 0) {
+                       int status = parser_read_uint32(&param->size,
+                               ent->value);
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+                       continue;
+               }
+
+               /* unrecognized */
+               PARSE_ERROR_INVALID(0, section_name, ent->name);
+       }
+
+       param->parsed = 1;
+       free(entries);
+}
+
+static void
+parse_msgq_rsp_pipeline(struct app_params *app,
+       const char *section_name,
+       struct rte_cfgfile *cfg)
+{
+       struct app_msgq_params *param;
+       struct rte_cfgfile_entry *entries;
+       int n_entries, i;
+       ssize_t param_idx;
+
+       n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
+       PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
+
+       entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
+       PARSE_ERROR_MALLOC(entries != NULL);
+
+       rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
+
+       param_idx = APP_PARAM_ADD(app->msgq_params, section_name);
+       PARSER_PARAM_ADD_CHECK(param_idx, app->msgq_params, section_name);
+
+       param = &app->msgq_params[param_idx];
+
+       for (i = 0; i < n_entries; i++) {
+               struct rte_cfgfile_entry *ent = &entries[i];
+
+               if (strcmp(ent->name, "size") == 0) {
+                       int status = parser_read_uint32(&param->size,
+                               ent->value);
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+                       continue;
+               }
+
+               /* unrecognized */
+               PARSE_ERROR_INVALID(0, section_name, ent->name);
+       }
+
+       param->parsed = 1;
+
+       free(entries);
+}
+
+static void
+parse_msgq(struct app_params *app,
+       const char *section_name,
+       struct rte_cfgfile *cfg)
+{
+       struct app_msgq_params *param;
+       struct rte_cfgfile_entry *entries;
+       int n_entries, i;
+       ssize_t param_idx;
+
+       n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
+       PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
+
+       entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
+       PARSE_ERROR_MALLOC(entries != NULL);
+
+       rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
+
+       param_idx = APP_PARAM_ADD(app->msgq_params, section_name);
+       PARSER_PARAM_ADD_CHECK(param_idx, app->msgq_params, section_name);
+
+       param = &app->msgq_params[param_idx];
+
+       for (i = 0; i < n_entries; i++) {
+               struct rte_cfgfile_entry *ent = &entries[i];
+
+               if (strcmp(ent->name, "size") == 0) {
+                       int status = parser_read_uint32(&param->size,
+                               ent->value);
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+                       continue;
+               }
+
+               if (strcmp(ent->name, "cpu") == 0) {
+                       int status = parser_read_uint32(
+                               &param->cpu_socket_id, ent->value);
+
+                       PARSE_ERROR((status == 0), section_name,
+                               ent->name);
+                       continue;
+               }
+
+               /* unrecognized */
+               PARSE_ERROR_INVALID(0, section_name, ent->name);
+       }
+
+       param->parsed = 1;
+
+       free(entries);
+}
+
+typedef void (*config_section_load)(struct app_params *p,
+       const char *section_name,
+       struct rte_cfgfile *cfg);
+
+struct config_section {
+       const char prefix[CFG_NAME_LEN];
+       int numbers;
+       config_section_load load;
+};
+
+static const struct config_section cfg_file_scheme[] = {
+       {"EAL", 0, parse_eal},
+       {"PIPELINE", 1, parse_pipeline},
+       {"MEMPOOL", 1, parse_mempool},
+       {"LINK", 1, parse_link},
+       {"RXQ", 2, parse_rxq},
+       {"TXQ", 2, parse_txq},
+       {"SWQ", 1, parse_swq},
+       {"TM", 1, parse_tm},
+       {"SOURCE", 1, parse_source},
+       {"SINK", 1, parse_sink},
+       {"MSGQ-REQ-PIPELINE", 1, parse_msgq_req_pipeline},
+       {"MSGQ-RSP-PIPELINE", 1, parse_msgq_rsp_pipeline},
+       {"MSGQ", 1, parse_msgq},
+};
+
+static void
+create_implicit_mempools(struct app_params *app)
+{
+       ssize_t idx;
+
+       idx = APP_PARAM_ADD(app->mempool_params, "MEMPOOL0");
+       PARSER_PARAM_ADD_CHECK(idx, app->mempool_params, "start-up");
+}
+
+static void
+create_implicit_links_from_port_mask(struct app_params *app,
+       uint64_t port_mask)
+{
+       uint32_t pmd_id, link_id;
+
+       link_id = 0;
+       for (pmd_id = 0; pmd_id < RTE_MAX_ETHPORTS; pmd_id++) {
+               char name[APP_PARAM_NAME_SIZE];
+               ssize_t idx;
+
+               if ((port_mask & (1LLU << pmd_id)) == 0)
+                       continue;
+
+               snprintf(name, sizeof(name), "LINK%" PRIu32, link_id);
+               idx = APP_PARAM_ADD(app->link_params, name);
+               PARSER_PARAM_ADD_CHECK(idx, app->link_params, name);
+
+               app->link_params[idx].pmd_id = pmd_id;
+               link_id++;
+       }
+}
+
+static void
+assign_link_pmd_id_from_pci_bdf(struct app_params *app)
+{
+       uint32_t i;
+
+       for (i = 0; i < app->n_links; i++) {
+               struct app_link_params *link = &app->link_params[i];
+
+               link->pmd_id = i;
+       }
+}
+
+int
+app_config_parse(struct app_params *app, const char *file_name)
+{
+       struct rte_cfgfile *cfg;
+       char **section_names;
+       int i, j, sect_count;
+
+       /* Implicit mempools */
+       create_implicit_mempools(app);
+
+       /* Port mask */
+       if (app->port_mask)
+               create_implicit_links_from_port_mask(app, app->port_mask);
+
+       /* Load application configuration file */
+       cfg = rte_cfgfile_load(file_name, 0);
+       APP_CHECK((cfg != NULL), "Parse error: Unable to load config "
+               "file %s", file_name);
+
+       sect_count = rte_cfgfile_num_sections(cfg, NULL, 0);
+       APP_CHECK((sect_count > 0), "Parse error: number of sections "
+               "in file \"%s\" return %d", file_name,
+               sect_count);
+
+       section_names = malloc(sect_count * sizeof(char *));
+       PARSE_ERROR_MALLOC(section_names != NULL);
+
+       for (i = 0; i < sect_count; i++)
+               section_names[i] = malloc(CFG_NAME_LEN);
+
+       rte_cfgfile_sections(cfg, section_names, sect_count);
+
+       for (i = 0; i < sect_count; i++) {
+               const struct config_section *sch_s;
+               int len, cfg_name_len;
+
+               cfg_name_len = strlen(section_names[i]);
+
+               /* Find section type */
+               for (j = 0; j < (int)RTE_DIM(cfg_file_scheme); j++) {
+                       sch_s = &cfg_file_scheme[j];
+                       len = strlen(sch_s->prefix);
+
+                       if (cfg_name_len < len)
+                               continue;
+
+                       /* After section name we expect only '\0' or digit or
+                        * digit dot digit, so protect against false matching,
+                        * for example: "ABC" should match section name
+                        * "ABC0.0", but it should not match section_name
+                        * "ABCDEF".
+                        */
+                       if ((section_names[i][len] != '\0') &&
+                               !isdigit(section_names[i][len]))
+                               continue;
+
+                       if (strncmp(sch_s->prefix, section_names[i], len) == 0)
+                               break;
+               }
+
+               APP_CHECK(j < (int)RTE_DIM(cfg_file_scheme),
+                       "Parse error: unknown section %s",
+                       section_names[i]);
+
+               APP_CHECK(validate_name(section_names[i],
+                       sch_s->prefix,
+                       sch_s->numbers) == 0,
+                       "Parse error: invalid section name \"%s\"",
+                       section_names[i]);
+
+               sch_s->load(app, section_names[i], cfg);
+       }
+
+       for (i = 0; i < sect_count; i++)
+               free(section_names[i]);
+
+       free(section_names);
+
+       rte_cfgfile_close(cfg);
+
+       APP_PARAM_COUNT(app->mempool_params, app->n_mempools);
+       APP_PARAM_COUNT(app->link_params, app->n_links);
+       APP_PARAM_COUNT(app->hwq_in_params, app->n_pktq_hwq_in);
+       APP_PARAM_COUNT(app->hwq_out_params, app->n_pktq_hwq_out);
+       APP_PARAM_COUNT(app->swq_params, app->n_pktq_swq);
+       APP_PARAM_COUNT(app->tm_params, app->n_pktq_tm);
+       APP_PARAM_COUNT(app->source_params, app->n_pktq_source);
+       APP_PARAM_COUNT(app->sink_params, app->n_pktq_sink);
+       APP_PARAM_COUNT(app->msgq_params, app->n_msgq);
+       APP_PARAM_COUNT(app->pipeline_params, app->n_pipelines);
+
+#ifdef RTE_PORT_PCAP
+       for (i = 0; i < (int)app->n_pktq_source; i++) {
+               struct app_pktq_source_params *p = &app->source_params[i];
+
+               APP_CHECK((p->file_name), "Parse error: missing "
+                       "mandatory field \"pcap_file_rd\" for \"%s\"",
+                       p->name);
+       }
+#else
+       for (i = 0; i < (int)app->n_pktq_source; i++) {
+               struct app_pktq_source_params *p = &app->source_params[i];
+
+               APP_CHECK((!p->file_name), "Parse error: invalid field "
+                       "\"pcap_file_rd\" for \"%s\"", p->name);
+       }
+#endif
+
+       if (app->port_mask == 0)
+               assign_link_pmd_id_from_pci_bdf(app);
+
+       /* Save configuration to output file */
+       app_config_save(app, app->output_file);
+
+       /* Load TM configuration files */
+       app_config_parse_tm(app);
+
+       return 0;
+}
+
+static void
+save_eal_params(struct app_params *app, FILE *f)
+{
+       struct app_eal_params *p = &app->eal_params;
+       uint32_t i;
+
+       fprintf(f, "[EAL]\n");
+
+       if (p->coremap)
+               fprintf(f, "%s = %s\n", "lcores", p->coremap);
+
+       if (p->master_lcore_present)
+               fprintf(f, "%s = %" PRIu32 "\n",
+                       "master_lcore", p->master_lcore);
+
+       fprintf(f, "%s = %" PRIu32 "\n", "n", p->channels);
+
+       if (p->memory_present)
+               fprintf(f, "%s = %" PRIu32 "\n", "m", p->memory);
+
+       if (p->ranks_present)
+               fprintf(f, "%s = %" PRIu32 "\n", "r", p->ranks);
+
+       for (i = 0; i < APP_MAX_LINKS; i++) {
+               if (p->pci_blacklist[i] == NULL)
+                       break;
+
+               fprintf(f, "%s = %s\n", "pci_blacklist",
+                       p->pci_blacklist[i]);
+       }
+
+       for (i = 0; i < APP_MAX_LINKS; i++) {
+               if (p->pci_whitelist[i] == NULL)
+                       break;
+
+               fprintf(f, "%s = %s\n", "pci_whitelist",
+                       p->pci_whitelist[i]);
+       }
+
+       for (i = 0; i < APP_MAX_LINKS; i++) {
+               if (p->vdev[i] == NULL)
+                       break;
+
+               fprintf(f, "%s = %s\n", "vdev",
+                       p->vdev[i]);
+       }
+
+       if (p->vmware_tsc_map_present)
+               fprintf(f, "%s = %s\n", "vmware_tsc_map",
+                       (p->vmware_tsc_map) ? "yes" : "no");
+
+       if (p->proc_type)
+               fprintf(f, "%s = %s\n", "proc_type", p->proc_type);
+
+       if (p->syslog)
+               fprintf(f, "%s = %s\n", "syslog", p->syslog);
+
+       if (p->log_level_present)
+               fprintf(f, "%s = %" PRIu32 "\n", "log_level", p->log_level);
+
+       if (p->version_present)
+               fprintf(f, "%s = %s\n", "v", (p->version) ? "yes" : "no");
+
+       if (p->help_present)
+               fprintf(f, "%s = %s\n", "help", (p->help) ? "yes" : "no");
+
+       if (p->no_huge_present)
+               fprintf(f, "%s = %s\n", "no_huge", (p->no_huge) ? "yes" : "no");
+
+       if (p->no_pci_present)
+               fprintf(f, "%s = %s\n", "no_pci", (p->no_pci) ? "yes" : "no");
+
+       if (p->no_hpet_present)
+               fprintf(f, "%s = %s\n", "no_hpet", (p->no_hpet) ? "yes" : "no");
+
+       if (p->no_shconf_present)
+               fprintf(f, "%s = %s\n", "no_shconf",
+                       (p->no_shconf) ? "yes" : "no");
+
+       if (p->add_driver)
+               fprintf(f, "%s = %s\n", "d", p->add_driver);
+
+       if (p->socket_mem)
+               fprintf(f, "%s = %s\n", "socket_mem", p->socket_mem);
+
+       if (p->huge_dir)
+               fprintf(f, "%s = %s\n", "huge_dir", p->huge_dir);
+
+       if (p->file_prefix)
+               fprintf(f, "%s = %s\n", "file_prefix", p->file_prefix);
+
+       if (p->base_virtaddr)
+               fprintf(f, "%s = %s\n", "base_virtaddr", p->base_virtaddr);
+
+       if (p->create_uio_dev_present)
+               fprintf(f, "%s = %s\n", "create_uio_dev",
+                       (p->create_uio_dev) ? "yes" : "no");
+
+       if (p->vfio_intr)
+               fprintf(f, "%s = %s\n", "vfio_intr", p->vfio_intr);
+
+       if (p->xen_dom0_present)
+               fprintf(f, "%s = %s\n", "xen_dom0",
+                       (p->xen_dom0) ? "yes" : "no");
+
+       fputc('\n', f);
+}
+
+static void
+save_mempool_params(struct app_params *app, FILE *f)
+{
+       struct app_mempool_params *p;
+       size_t i, count;
+
+       count = RTE_DIM(app->mempool_params);
+       for (i = 0; i < count; i++) {
+               p = &app->mempool_params[i];
+               if (!APP_PARAM_VALID(p))
+                       continue;
+
+               fprintf(f, "[%s]\n", p->name);
+               fprintf(f, "%s = %" PRIu32 "\n", "buffer_size", p->buffer_size);
+               fprintf(f, "%s = %" PRIu32 "\n", "pool_size", p->pool_size);
+               fprintf(f, "%s = %" PRIu32 "\n", "cache_size", p->cache_size);
+               fprintf(f, "%s = %" PRIu32 "\n", "cpu", p->cpu_socket_id);
+
+               fputc('\n', f);
+       }
+}
+
+static void
+save_links_params(struct app_params *app, FILE *f)
+{
+       struct app_link_params *p;
+       size_t i, count;
+
+       count = RTE_DIM(app->link_params);
+       for (i = 0; i < count; i++) {
+               p = &app->link_params[i];
+               if (!APP_PARAM_VALID(p))
+                       continue;
+
+               fprintf(f, "[%s]\n", p->name);
+               fprintf(f, "; %s = %" PRIu32 "\n", "pmd_id", p->pmd_id);
+               fprintf(f, "%s = %s\n", "promisc", p->promisc ? "yes" : "no");
+               fprintf(f, "%s = %" PRIu32 "\n", "arp_q", p->arp_q);
+               fprintf(f, "%s = %" PRIu32 "\n", "tcp_syn_q",
+                       p->tcp_syn_q);
+               fprintf(f, "%s = %" PRIu32 "\n", "ip_local_q", p->ip_local_q);
+               fprintf(f, "%s = %" PRIu32 "\n", "tcp_local_q", p->tcp_local_q);
+               fprintf(f, "%s = %" PRIu32 "\n", "udp_local_q", p->udp_local_q);
+               fprintf(f, "%s = %" PRIu32 "\n", "sctp_local_q",
+                       p->sctp_local_q);
+
+               if (strlen(p->pci_bdf))
+                       fprintf(f, "%s = %s\n", "pci_bdf", p->pci_bdf);
+
+               fputc('\n', f);
+       }
+}
+
+static void
+save_rxq_params(struct app_params *app, FILE *f)
+{
+       struct app_pktq_hwq_in_params *p;
+       size_t i, count;
+
+       count = RTE_DIM(app->hwq_in_params);
+       for (i = 0; i < count; i++) {
+               p = &app->hwq_in_params[i];
+               if (!APP_PARAM_VALID(p))
+                       continue;
+
+               fprintf(f, "[%s]\n", p->name);
+               fprintf(f, "%s = %s\n",
+                       "mempool",
+                       app->mempool_params[p->mempool_id].name);
+               fprintf(f, "%s = %" PRIu32 "\n", "size", p->size);
+               fprintf(f, "%s = %" PRIu32 "\n", "burst", p->burst);
+
+               fputc('\n', f);
+       }
+}
+
+static void
+save_txq_params(struct app_params *app, FILE *f)
+{
+       struct app_pktq_hwq_out_params *p;
+       size_t i, count;
+
+       count = RTE_DIM(app->hwq_out_params);
+       for (i = 0; i < count; i++) {
+               p = &app->hwq_out_params[i];
+               if (!APP_PARAM_VALID(p))
+                       continue;
+
+               fprintf(f, "[%s]\n", p->name);
+               fprintf(f, "%s = %" PRIu32 "\n", "size", p->size);
+               fprintf(f, "%s = %" PRIu32 "\n", "burst", p->burst);
+               fprintf(f, "%s = %s\n",
+                       "dropless",
+                       p->dropless ? "yes" : "no");
+
+               fputc('\n', f);
+       }
+}
+
+static void
+save_swq_params(struct app_params *app, FILE *f)
+{
+       struct app_pktq_swq_params *p;
+       size_t i, count;
+
+       count = RTE_DIM(app->swq_params);
+       for (i = 0; i < count; i++) {
+               p = &app->swq_params[i];
+               if (!APP_PARAM_VALID(p))
+                       continue;
+
+               fprintf(f, "[%s]\n", p->name);
+               fprintf(f, "%s = %" PRIu32 "\n", "size", p->size);
+               fprintf(f, "%s = %" PRIu32 "\n", "burst_read", p->burst_read);
+               fprintf(f, "%s = %" PRIu32 "\n", "burst_write", p->burst_write);
+               fprintf(f, "%s = %s\n", "dropless", p->dropless ? "yes" : "no");
+               fprintf(f, "%s = %" PRIu64 "\n", "n_retries", p->n_retries);
+               fprintf(f, "%s = %" PRIu32 "\n", "cpu", p->cpu_socket_id);
+               fprintf(f, "%s = %s\n", "ipv4_frag", p->ipv4_frag ? "yes" : "no");
+               fprintf(f, "%s = %s\n", "ipv6_frag", p->ipv6_frag ? "yes" : "no");
+               fprintf(f, "%s = %s\n", "ipv4_ras", p->ipv4_ras ? "yes" : "no");
+               fprintf(f, "%s = %s\n", "ipv6_ras", p->ipv6_ras ? "yes" : "no");
+               if ((p->ipv4_frag == 1) || (p->ipv6_frag == 1)) {
+                       fprintf(f, "%s = %" PRIu32 "\n", "mtu", p->mtu);
+                       fprintf(f, "%s = %" PRIu32 "\n", "metadata_size", p->metadata_size);
+                       fprintf(f, "%s = %s\n",
+                               "mempool_direct",
+                               app->mempool_params[p->mempool_direct_id].name);
+                       fprintf(f, "%s = %s\n",
+                               "mempool_indirect",
+                               app->mempool_params[p->mempool_indirect_id].name);
+               }
+
+               fputc('\n', f);
+       }
+}
+
+static void
+save_tm_params(struct app_params *app, FILE *f)
+{
+       struct app_pktq_tm_params *p;
+       size_t i, count;
+
+       count = RTE_DIM(app->tm_params);
+       for (i = 0; i < count; i++) {
+               p = &app->tm_params[i];
+               if (!APP_PARAM_VALID(p))
+                       continue;
+
+               fprintf(f, "[%s]\n", p->name);
+               fprintf(f, "%s = %s\n", "cfg", p->file_name);
+               fprintf(f, "%s = %" PRIu32 "\n", "burst_read", p->burst_read);
+               fprintf(f, "%s = %" PRIu32 "\n", "burst_write", p->burst_write);
+
+               fputc('\n', f);
+       }
+}
+
+static void
+save_source_params(struct app_params *app, FILE *f)
+{
+       struct app_pktq_source_params *p;
+       size_t i, count;
+
+       count = RTE_DIM(app->source_params);
+       for (i = 0; i < count; i++) {
+               p = &app->source_params[i];
+               if (!APP_PARAM_VALID(p))
+                       continue;
+
+               fprintf(f, "[%s]\n", p->name);
+               fprintf(f, "%s = %s\n",
+                       "mempool",
+                       app->mempool_params[p->mempool_id].name);
+               fprintf(f, "%s = %" PRIu32 "\n", "burst", p->burst);
+               fprintf(f, "%s = %s\n", "pcap_file_rd", p->file_name);
+               fprintf(f, "%s = %" PRIu32 "\n", "pcap_bytes_rd_per_pkt",
+                       p->n_bytes_per_pkt);
+               fputc('\n', f);
+       }
+}
+
+static void
+save_sink_params(struct app_params *app, FILE *f)
+{
+       struct app_pktq_sink_params *p;
+       size_t i, count;
+
+       count = RTE_DIM(app->sink_params);
+       for (i = 0; i < count; i++) {
+               p = &app->sink_params[i];
+               if (!APP_PARAM_VALID(p))
+                       continue;
+
+               fprintf(f, "[%s]\n", p->name);
+               fprintf(f, "%s = %s\n", "pcap_file_wr", p->file_name);
+               fprintf(f, "%s = %" PRIu32 "\n",
+                               "pcap_n_pkt_wr", p->n_pkts_to_dump);
+               fputc('\n', f);
+       }
+}
+
+static void
+save_msgq_params(struct app_params *app, FILE *f)
+{
+       struct app_msgq_params *p;
+       size_t i, count;
+
+       count = RTE_DIM(app->msgq_params);
+       for (i = 0; i < count; i++) {
+               p = &app->msgq_params[i];
+               if (!APP_PARAM_VALID(p))
+                       continue;
+
+               fprintf(f, "[%s]\n", p->name);
+               fprintf(f, "%s = %" PRIu32 "\n", "size", p->size);
+               fprintf(f, "%s = %" PRIu32 "\n", "cpu", p->cpu_socket_id);
+
+               fputc('\n', f);
+       }
+}
+
+static void
+save_pipeline_params(struct app_params *app, FILE *f)
+{
+       size_t i, count;
+
+       count = RTE_DIM(app->pipeline_params);
+       for (i = 0; i < count; i++) {
+               struct app_pipeline_params *p = &app->pipeline_params[i];
+
+               if (!APP_PARAM_VALID(p))
+                       continue;
+
+               /* section name */
+               fprintf(f, "[%s]\n", p->name);
+
+               /* type */
+               fprintf(f, "type = %s\n", p->type);
+
+               /* core */
+               fprintf(f, "core = s%" PRIu32 "c%" PRIu32 "%s\n",
+                       p->socket_id,
+                       p->core_id,
+                       (p->hyper_th_id) ? "h" : "");
+
+               /* pktq_in */
+               if (p->n_pktq_in) {
+                       uint32_t j;
+
+                       fprintf(f, "pktq_in =");
+                       for (j = 0; j < p->n_pktq_in; j++) {
+                               struct app_pktq_in_params *pp = &p->pktq_in[j];
+                               char *name;
+
+                               switch (pp->type) {
+                               case APP_PKTQ_IN_HWQ:
+                                       name = app->hwq_in_params[pp->id].name;
+                                       break;
+                               case APP_PKTQ_IN_SWQ:
+                                       name = app->swq_params[pp->id].name;
+                                       break;
+                               case APP_PKTQ_IN_TM:
+                                       name = app->tm_params[pp->id].name;
+                                       break;
+                               case APP_PKTQ_IN_SOURCE:
+                                       name = app->source_params[pp->id].name;
+                                       break;
+                               default:
+                                       APP_CHECK(0, "System error "
+                                               "occurred while saving "
+                                               "parameter to file");
+                               }
+
+                               fprintf(f, " %s", name);
+                       }
+                       fprintf(f, "\n");
+               }
+
+               /* pktq_in */
+               if (p->n_pktq_out) {
+                       uint32_t j;
+
+                       fprintf(f, "pktq_out =");
+                       for (j = 0; j < p->n_pktq_out; j++) {
+                               struct app_pktq_out_params *pp =
+                                       &p->pktq_out[j];
+                               char *name;
+
+                               switch (pp->type) {
+                               case APP_PKTQ_OUT_HWQ:
+                                       name = app->hwq_out_params[pp->id].name;
+                                       break;
+                               case APP_PKTQ_OUT_SWQ:
+                                       name = app->swq_params[pp->id].name;
+                                       break;
+                               case APP_PKTQ_OUT_TM:
+                                       name = app->tm_params[pp->id].name;
+                                       break;
+                               case APP_PKTQ_OUT_SINK:
+                                       name = app->sink_params[pp->id].name;
+                                       break;
+                               default:
+                                       APP_CHECK(0, "System error "
+                                               "occurred while saving "
+                                               "parameter to file");
+                               }
+
+                               fprintf(f, " %s", name);
+                       }
+                       fprintf(f, "\n");
+               }
+
+               /* msgq_in */
+               if (p->n_msgq_in) {
+                       uint32_t j;
+
+                       fprintf(f, "msgq_in =");
+                       for (j = 0; j < p->n_msgq_in; j++) {
+                               uint32_t id = p->msgq_in[j];
+                               char *name = app->msgq_params[id].name;
+
+                               fprintf(f, " %s", name);
+                       }
+                       fprintf(f, "\n");
+               }
+
+               /* msgq_out */
+               if (p->n_msgq_out) {
+                       uint32_t j;
+
+                       fprintf(f, "msgq_out =");
+                       for (j = 0; j < p->n_msgq_out; j++) {
+                               uint32_t id = p->msgq_out[j];
+                               char *name = app->msgq_params[id].name;
+
+                               fprintf(f, " %s", name);
+                       }
+                       fprintf(f, "\n");
+               }
+
+               /* timer_period */
+               fprintf(f, "timer_period = %" PRIu32 "\n", p->timer_period);
+
+               /* args */
+               if (p->n_args) {
+                       uint32_t j;
+
+                       for (j = 0; j < p->n_args; j++)
+                               fprintf(f, "%s = %s\n", p->args_name[j],
+                                       p->args_value[j]);
+               }
+
+               fprintf(f, "\n");
+       }
+}
+
+void
+app_config_save(struct app_params *app, const char *file_name)
+{
+       FILE *file;
+       char *name, *dir_name;
+       int status;
+
+       name = strdup(file_name);
+       dir_name = dirname(name);
+       status = access(dir_name, W_OK);
+       APP_CHECK((status == 0),
+               "Error: need write access privilege to directory "
+               "\"%s\" to save configuration\n", dir_name);
+
+       file = fopen(file_name, "w");
+       APP_CHECK((file != NULL),
+               "Error: failed to save configuration to file \"%s\"",
+               file_name);
+
+       save_eal_params(app, file);
+       save_pipeline_params(app, file);
+       save_mempool_params(app, file);
+       save_links_params(app, file);
+       save_rxq_params(app, file);
+       save_txq_params(app, file);
+       save_swq_params(app, file);
+       save_tm_params(app, file);
+       save_source_params(app, file);
+       save_sink_params(app, file);
+       save_msgq_params(app, file);
+
+       fclose(file);
+       free(name);
+}
+
+int
+app_config_init(struct app_params *app)
+{
+       size_t i;
+
+       memcpy(app, &app_params_default, sizeof(struct app_params));
+
+       for (i = 0; i < RTE_DIM(app->mempool_params); i++)
+               memcpy(&app->mempool_params[i],
+                       &mempool_params_default,
+                       sizeof(struct app_mempool_params));
+
+       for (i = 0; i < RTE_DIM(app->link_params); i++)
+               memcpy(&app->link_params[i],
+                       &link_params_default,
+                       sizeof(struct app_link_params));
+
+       for (i = 0; i < RTE_DIM(app->hwq_in_params); i++)
+               memcpy(&app->hwq_in_params[i],
+                       &default_hwq_in_params,
+                       sizeof(default_hwq_in_params));
+
+       for (i = 0; i < RTE_DIM(app->hwq_out_params); i++)
+               memcpy(&app->hwq_out_params[i],
+                       &default_hwq_out_params,
+                       sizeof(default_hwq_out_params));
+
+       for (i = 0; i < RTE_DIM(app->swq_params); i++)
+               memcpy(&app->swq_params[i],
+                       &default_swq_params,
+                       sizeof(default_swq_params));
+
+       for (i = 0; i < RTE_DIM(app->tm_params); i++)
+               memcpy(&app->tm_params[i],
+                       &default_tm_params,
+                       sizeof(default_tm_params));
+
+       for (i = 0; i < RTE_DIM(app->source_params); i++)
+               memcpy(&app->source_params[i],
+                       &default_source_params,
+                       sizeof(default_source_params));
+
+       for (i = 0; i < RTE_DIM(app->sink_params); i++)
+               memcpy(&app->sink_params[i],
+                       &default_sink_params,
+                       sizeof(default_sink_params));
+
+       for (i = 0; i < RTE_DIM(app->msgq_params); i++)
+               memcpy(&app->msgq_params[i],
+                       &default_msgq_params,
+                       sizeof(default_msgq_params));
+
+       for (i = 0; i < RTE_DIM(app->pipeline_params); i++)
+               memcpy(&app->pipeline_params[i],
+                       &default_pipeline_params,
+                       sizeof(default_pipeline_params));
+
+       return 0;
+}
+
+static char *
+filenamedup(const char *filename, const char *suffix)
+{
+       char *s = malloc(strlen(filename) + strlen(suffix) + 1);
+
+       if (!s)
+               return NULL;
+
+       sprintf(s, "%s%s", filename, suffix);
+       return s;
+}
+
+int
+app_config_args(struct app_params *app, int argc, char **argv)
+{
+       const char *optname;
+       int opt, option_index;
+       int f_present, s_present, p_present, l_present;
+       int preproc_present, preproc_params_present, disable_csum_present;
+       int hwlb_present;
+       int flow_dir_present;
+       int scaned = 0;
+
+       static struct option lgopts[] = {
+               { "disable-hw-csum", 0, 0, 0 },
+               { "preproc", 1, 0, 0 },
+               { "preproc-args", 1, 0, 0 },
+               { "hwlb", 1, 0, 0 },
+               { "flow_dir", 0, 0, 0 },
+               { NULL,  0, 0, 0 }
+       };
+
+       /* Copy application name */
+       strncpy(app->app_name, argv[0], APP_APPNAME_SIZE - 1);
+
+       f_present = 0;
+       s_present = 0;
+       p_present = 0;
+       l_present = 0;
+       disable_csum_present = 0;
+       preproc_present = 0;
+       preproc_params_present = 0;
+       app->header_csum_req =1; //Default enable haeader checksum
+       hwlb_present = 0;
+       flow_dir_present = 0;
+
+
+       while ((opt = getopt_long(argc, argv, "f:s:p:l:", lgopts,
+                       &option_index)) != EOF)
+               switch (opt) {
+               case 'f':
+                       if (f_present)
+                               rte_panic("Error: Config file is provided "
+                                       "more than once\n");
+                       f_present = 1;
+
+                       if (!strlen(optarg))
+                               rte_panic("Error: Config file name is null\n");
+
+                       app->config_file = strdup(optarg);
+                       if (app->config_file == NULL)
+                               rte_panic("Error: Memory allocation failure\n");
+
+                       break;
+
+               case 's':
+                       if (s_present)
+                               rte_panic("Error: Script file is provided "
+                                       "more than once\n");
+                       s_present = 1;
+
+                       if (!strlen(optarg))
+                               rte_panic("Error: Script file name is null\n");
+
+                       app->script_file = strdup(optarg);
+                       if (app->script_file == NULL)
+                               rte_panic("Error: Memory allocation failure\n");
+
+                       break;
+
+               case 'p':
+                       if (p_present)
+                               rte_panic("Error: PORT_MASK is provided "
+                                       "more than once\n");
+                       p_present = 1;
+
+                       if ((sscanf(optarg, "%" SCNx64 "%n", &app->port_mask,
+                               &scaned) != 1) ||
+                               ((size_t) scaned != strlen(optarg)))
+                               rte_panic("Error: PORT_MASK is not "
+                                       "a hexadecimal integer\n");
+
+                       if (app->port_mask == 0)
+                               rte_panic("Error: PORT_MASK is null\n");
+
+                       break;
+
+               case 'l':
+                       if (l_present)
+                               rte_panic("Error: LOG_LEVEL is provided "
+                                       "more than once\n");
+                       l_present = 1;
+
+                       if ((sscanf(optarg, "%" SCNu32 "%n", &app->log_level,
+                               &scaned) != 1) ||
+                               ((size_t) scaned != strlen(optarg)) ||
+                               (app->log_level >= APP_LOG_LEVELS))
+                               rte_panic("Error: LOG_LEVEL invalid value\n");
+
+                       break;
+
+               case 0:
+                       optname = lgopts[option_index].name;
+
+                       if (strcmp(optname, "hwlb") == 0) {
+                               if (hwlb_present)
+                                       rte_panic("Error: hwlb argument "
+                                               "is provided more than once\n");
+                       hwlb_present = 1;
+                       printf(" HWLB is configured\n");
+
+                       app->n_hwlb_q = atoi(optarg);
+
+                       if(!app->n_hwlb_q)
+                               rte_panic("HWQs for HWLB must be atleast 1\n");
+
+                       printf("No of HWQs for HWLB are %d\n",app->n_hwlb_q);
+                       enable_hwlb = 1;
+                       break;
+                       }
+
+                       if (strcmp(optname, "flow_dir") == 0) {
+                                if (flow_dir_present)
+                                        rte_panic("Error: flow_dir argument "
+                                                "is provided more than once\n");
+                        flow_dir_present = 1;
+                        printf(" FLOW DIR is configured\n");
+
+                       enable_flow_dir = 1;
+
+                        break;
+                        }
+
+                       if (strcmp(optname, "disable-hw-csum") == 0) {
+                               if (disable_csum_present)
+                                       rte_panic("Error: disable-hw-csum argument "
+                                               "is provided more than once\n");
+
+                               printf("Disable TCP/UDP HW checksumi\n");
+                               app->header_csum_req = 0;
+                               disable_csum_present = 1;
+                               break;
+                       }
+
+                       if (strcmp(optname, "preproc") == 0) {
+                               if (preproc_present)
+                                       rte_panic("Error: Preprocessor argument "
+                                               "is provided more than once\n");
+                               preproc_present = 1;
+
+                               app->preproc = strdup(optarg);
+                               break;
+                       }
+
+                       if (strcmp(optname, "preproc-args") == 0) {
+                               if (preproc_params_present)
+                                       rte_panic("Error: Preprocessor args "
+                                               "are provided more than once\n");
+                               preproc_params_present = 1;
+
+                               app->preproc_args = strdup(optarg);
+                               break;
+                       }
+
+                       app_print_usage(argv[0]);
+                       break;
+
+               default:
+                       app_print_usage(argv[0]);
+               }
+
+       optind = 0; /* reset getopt lib */
+
+       /* Check dependencies between args */
+       if (preproc_params_present && (preproc_present == 0))
+               rte_panic("Error: Preprocessor args specified while "
+                       "preprocessor is not defined\n");
+
+       app->parser_file = preproc_present ?
+               filenamedup(app->config_file, ".preproc") :
+               strdup(app->config_file);
+       app->output_file = filenamedup(app->config_file, ".out");
+
+       return 0;
+}
+
+int
+app_config_preproc(struct app_params *app)
+{
+       char buffer[256];
+       int status;
+
+       if (app->preproc == NULL)
+               return 0;
+
+       status = access(app->config_file, F_OK | R_OK);
+       APP_CHECK((status == 0), "Error: Unable to open file %s",
+               app->config_file);
+
+       snprintf(buffer, sizeof(buffer), "%s %s %s > %s",
+               app->preproc,
+               app->preproc_args ? app->preproc_args : "",
+               app->config_file,
+               app->parser_file);
+
+       status = system(buffer);
+       APP_CHECK((WIFEXITED(status) && (WEXITSTATUS(status) == 0)),
+               "Error occurred while pre-processing file \"%s\"\n",
+               app->config_file);
+
+       return status;
+}
diff --git a/common/vnf_common/config_parse_tm.c b/common/vnf_common/config_parse_tm.c
new file mode 100644 (file)
index 0000000..fe7eb64
--- /dev/null
@@ -0,0 +1,431 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <string.h>
+#include <libgen.h>
+#include <unistd.h>
+
+#include <rte_errno.h>
+#include <rte_cfgfile.h>
+#include <rte_string_fns.h>
+
+#include "app.h"
+
+static int
+tm_cfgfile_load_sched_port(
+       struct rte_cfgfile *file,
+       struct rte_sched_port_params *port_params)
+{
+       const char *entry;
+       int j;
+
+       entry = rte_cfgfile_get_entry(file, "port", "frame overhead");
+       if (entry)
+               port_params->frame_overhead = (uint32_t)atoi(entry);
+
+       entry = rte_cfgfile_get_entry(file, "port", "mtu");
+       if (entry)
+               port_params->mtu = (uint32_t)atoi(entry);
+
+       entry = rte_cfgfile_get_entry(file,
+               "port",
+               "number of subports per port");
+       if (entry)
+               port_params->n_subports_per_port = (uint32_t) atoi(entry);
+
+       entry = rte_cfgfile_get_entry(file,
+               "port",
+               "number of pipes per subport");
+       if (entry)
+               port_params->n_pipes_per_subport = (uint32_t) atoi(entry);
+
+       entry = rte_cfgfile_get_entry(file, "port", "queue sizes");
+       if (entry) {
+               char *next;
+
+               for (j = 0; j < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; j++) {
+                       port_params->qsize[j] = (uint16_t)
+                               strtol(entry, &next, 10);
+                       if (next == NULL)
+                               break;
+                       entry = next;
+               }
+       }
+
+#ifdef RTE_SCHED_RED
+       for (j = 0; j < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; j++) {
+               char str[32];
+
+               /* Parse WRED min thresholds */
+               snprintf(str, sizeof(str), "tc %" PRId32 " wred min", j);
+               entry = rte_cfgfile_get_entry(file, "red", str);
+               if (entry) {
+                       char *next;
+                       int k;
+
+                       /* for each packet colour (green, yellow, red) */
+                       for (k = 0; k < e_RTE_METER_COLORS; k++) {
+                               port_params->red_params[j][k].min_th
+                                       = (uint16_t)strtol(entry, &next, 10);
+                               if (next == NULL)
+                                       break;
+                               entry = next;
+                       }
+               }
+
+               /* Parse WRED max thresholds */
+               snprintf(str, sizeof(str), "tc %" PRId32 " wred max", j);
+               entry = rte_cfgfile_get_entry(file, "red", str);
+               if (entry) {
+                       char *next;
+                       int k;
+
+                       /* for each packet colour (green, yellow, red) */
+                       for (k = 0; k < e_RTE_METER_COLORS; k++) {
+                               port_params->red_params[j][k].max_th
+                                       = (uint16_t)strtol(entry, &next, 10);
+                               if (next == NULL)
+                                       break;
+                               entry = next;
+                       }
+               }
+
+               /* Parse WRED inverse mark probabilities */
+               snprintf(str, sizeof(str), "tc %" PRId32 " wred inv prob", j);
+               entry = rte_cfgfile_get_entry(file, "red", str);
+               if (entry) {
+                       char *next;
+                       int k;
+
+                       /* for each packet colour (green, yellow, red) */
+                       for (k = 0; k < e_RTE_METER_COLORS; k++) {
+                               port_params->red_params[j][k].maxp_inv
+                                       = (uint8_t)strtol(entry, &next, 10);
+
+                               if (next == NULL)
+                                       break;
+                               entry = next;
+                       }
+               }
+
+               /* Parse WRED EWMA filter weights */
+               snprintf(str, sizeof(str), "tc %" PRId32 " wred weight", j);
+               entry = rte_cfgfile_get_entry(file, "red", str);
+               if (entry) {
+                       char *next;
+                       int k;
+
+                       /* for each packet colour (green, yellow, red) */
+                       for (k = 0; k < e_RTE_METER_COLORS; k++) {
+                               port_params->red_params[j][k].wq_log2
+                                       = (uint8_t)strtol(entry, &next, 10);
+                               if (next == NULL)
+                                       break;
+                               entry = next;
+                       }
+               }
+       }
+#endif /* RTE_SCHED_RED */
+
+       return 0;
+}
+
+static int
+tm_cfgfile_load_sched_pipe(
+       struct rte_cfgfile *file,
+       struct rte_sched_port_params *port_params,
+       struct rte_sched_pipe_params *pipe_params)
+{
+       int i, j;
+       char *next;
+       const char *entry;
+       int profiles;
+
+       profiles = rte_cfgfile_num_sections(file,
+               "pipe profile", sizeof("pipe profile") - 1);
+       port_params->n_pipe_profiles = profiles;
+
+       for (j = 0; j < profiles; j++) {
+               char pipe_name[32];
+
+               snprintf(pipe_name, sizeof(pipe_name),
+                       "pipe profile %" PRId32, j);
+
+               entry = rte_cfgfile_get_entry(file, pipe_name, "tb rate");
+               if (entry)
+                       pipe_params[j].tb_rate = (uint32_t) atoi(entry);
+
+               entry = rte_cfgfile_get_entry(file, pipe_name, "tb size");
+               if (entry)
+                       pipe_params[j].tb_size = (uint32_t) atoi(entry);
+
+               entry = rte_cfgfile_get_entry(file, pipe_name, "tc period");
+               if (entry)
+                       pipe_params[j].tc_period = (uint32_t) atoi(entry);
+
+               entry = rte_cfgfile_get_entry(file, pipe_name, "tc 0 rate");
+               if (entry)
+                       pipe_params[j].tc_rate[0] = (uint32_t) atoi(entry);
+
+               entry = rte_cfgfile_get_entry(file, pipe_name, "tc 1 rate");
+               if (entry)
+                       pipe_params[j].tc_rate[1] = (uint32_t) atoi(entry);
+
+               entry = rte_cfgfile_get_entry(file, pipe_name, "tc 2 rate");
+               if (entry)
+                       pipe_params[j].tc_rate[2] = (uint32_t) atoi(entry);
+
+               entry = rte_cfgfile_get_entry(file, pipe_name, "tc 3 rate");
+               if (entry)
+                       pipe_params[j].tc_rate[3] = (uint32_t) atoi(entry);
+
+#ifdef RTE_SCHED_SUBPORT_TC_OV
+               entry = rte_cfgfile_get_entry(file, pipe_name,
+                       "tc 3 oversubscription weight");
+               if (entry)
+                       pipe_params[j].tc_ov_weight = (uint8_t)atoi(entry);
+#endif
+
+               entry = rte_cfgfile_get_entry(file,
+                       pipe_name,
+                       "tc 0 wrr weights");
+               if (entry)
+                       for (i = 0; i < RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS; i++) {
+                               pipe_params[j].wrr_weights[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE*0 + i] =
+                                       (uint8_t) strtol(entry, &next, 10);
+                               if (next == NULL)
+                                       break;
+                               entry = next;
+                       }
+
+               entry = rte_cfgfile_get_entry(file, pipe_name, "tc 1 wrr weights");
+               if (entry)
+                       for (i = 0; i < RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS; i++) {
+                               pipe_params[j].wrr_weights[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE*1 + i] =
+                                       (uint8_t) strtol(entry, &next, 10);
+                               if (next == NULL)
+                                       break;
+                               entry = next;
+                       }
+
+               entry = rte_cfgfile_get_entry(file, pipe_name, "tc 2 wrr weights");
+               if (entry)
+                       for (i = 0; i < RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS; i++) {
+                               pipe_params[j].wrr_weights[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE*2 + i] =
+                                       (uint8_t) strtol(entry, &next, 10);
+                               if (next == NULL)
+                                       break;
+                               entry = next;
+                       }
+
+               entry = rte_cfgfile_get_entry(file, pipe_name, "tc 3 wrr weights");
+               if (entry)
+                       for (i = 0; i < RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS; i++) {
+                               pipe_params[j].wrr_weights[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE*3 + i] =
+                                       (uint8_t) strtol(entry, &next, 10);
+                               if (next == NULL)
+                                       break;
+                               entry = next;
+                       }
+       }
+       return 0;
+}
+
+static int
+tm_cfgfile_load_sched_subport(
+       struct rte_cfgfile *file,
+       struct rte_sched_subport_params *subport_params,
+       int *pipe_to_profile)
+{
+       const char *entry;
+       int i, j, k;
+
+       for (i = 0; i < APP_MAX_SCHED_SUBPORTS; i++) {
+               char sec_name[CFG_NAME_LEN];
+
+               snprintf(sec_name, sizeof(sec_name),
+                       "subport %" PRId32, i);
+
+               if (rte_cfgfile_has_section(file, sec_name)) {
+                       entry = rte_cfgfile_get_entry(file,
+                               sec_name,
+                               "tb rate");
+                       if (entry)
+                               subport_params[i].tb_rate =
+                                       (uint32_t) atoi(entry);
+
+                       entry = rte_cfgfile_get_entry(file,
+                               sec_name,
+                               "tb size");
+                       if (entry)
+                               subport_params[i].tb_size =
+                                       (uint32_t) atoi(entry);
+
+                       entry = rte_cfgfile_get_entry(file,
+                               sec_name,
+                               "tc period");
+                       if (entry)
+                               subport_params[i].tc_period =
+                                       (uint32_t) atoi(entry);
+
+                       entry = rte_cfgfile_get_entry(file,
+                               sec_name,
+                               "tc 0 rate");
+                       if (entry)
+                               subport_params[i].tc_rate[0] =
+                                       (uint32_t) atoi(entry);
+
+                       entry = rte_cfgfile_get_entry(file,
+                               sec_name,
+                               "tc 1 rate");
+                       if (entry)
+                               subport_params[i].tc_rate[1] =
+                                       (uint32_t) atoi(entry);
+
+                       entry = rte_cfgfile_get_entry(file,
+                               sec_name,
+                               "tc 2 rate");
+                       if (entry)
+                               subport_params[i].tc_rate[2] =
+                                       (uint32_t) atoi(entry);
+
+                       entry = rte_cfgfile_get_entry(file,
+                               sec_name,
+                               "tc 3 rate");
+                       if (entry)
+                               subport_params[i].tc_rate[3] =
+                                       (uint32_t) atoi(entry);
+
+                       int n_entries = rte_cfgfile_section_num_entries(file,
+                               sec_name);
+                       struct rte_cfgfile_entry entries[n_entries];
+
+                       rte_cfgfile_section_entries(file,
+                               sec_name,
+                               entries,
+                               n_entries);
+
+                       for (j = 0; j < n_entries; j++)
+                               if (strncmp("pipe",
+                                       entries[j].name,
+                                       sizeof("pipe") - 1) == 0) {
+                                       int profile;
+                                       char *tokens[2] = {NULL, NULL};
+                                       int n_tokens;
+                                       int begin, end;
+                                       char name[CFG_NAME_LEN + 1];
+
+                                       profile = atoi(entries[j].value);
+                                       strncpy(name,
+                                               entries[j].name,
+                                               sizeof(name));
+                                       n_tokens = rte_strsplit(
+                                               &name[sizeof("pipe")],
+                                               strnlen(name, CFG_NAME_LEN),
+                                                       tokens, 2, '-');
+
+                                       begin =  atoi(tokens[0]);
+                                       if (n_tokens == 2)
+                                               end = atoi(tokens[1]);
+                                       else
+                                               end = begin;
+
+                                       if ((end >= APP_MAX_SCHED_PIPES) ||
+                                               (begin > end))
+                                               return -1;
+
+                                       for (k = begin; k <= end; k++) {
+                                               char profile_name[CFG_NAME_LEN];
+
+                                               snprintf(profile_name,
+                                                       sizeof(profile_name),
+                                                       "pipe profile %" PRId32,
+                                                       profile);
+                                               if (rte_cfgfile_has_section(file, profile_name))
+                                                       pipe_to_profile[i * APP_MAX_SCHED_PIPES + k] = profile;
+                                               else
+                                                       rte_exit(EXIT_FAILURE,
+                                                               "Wrong pipe profile %s\n",
+                                                               entries[j].value);
+                                       }
+                               }
+               }
+       }
+
+       return 0;
+}
+
+static int
+tm_cfgfile_load(struct app_pktq_tm_params *tm)
+{
+       struct rte_cfgfile *file;
+       uint32_t i;
+
+       memset(tm->sched_subport_params, 0, sizeof(tm->sched_subport_params));
+       memset(tm->sched_pipe_profiles, 0, sizeof(tm->sched_pipe_profiles));
+       memset(&tm->sched_port_params, 0, sizeof(tm->sched_port_params));
+       for (i = 0; i < APP_MAX_SCHED_SUBPORTS * APP_MAX_SCHED_PIPES; i++)
+               tm->sched_pipe_to_profile[i] = -1;
+
+       tm->sched_port_params.pipe_profiles = &tm->sched_pipe_profiles[0];
+
+       if (tm->file_name[0] == '\0')
+               return -1;
+
+       file = rte_cfgfile_load(tm->file_name, 0);
+       if (file == NULL)
+               return -1;
+
+       tm_cfgfile_load_sched_port(file,
+               &tm->sched_port_params);
+       tm_cfgfile_load_sched_subport(file,
+               tm->sched_subport_params,
+               tm->sched_pipe_to_profile);
+       tm_cfgfile_load_sched_pipe(file,
+               &tm->sched_port_params,
+               tm->sched_pipe_profiles);
+
+       rte_cfgfile_close(file);
+       return 0;
+}
+
+int
+app_config_parse_tm(struct app_params *app)
+{
+       uint32_t i;
+
+       for (i = 0; i < RTE_DIM(app->tm_params); i++) {
+               struct app_pktq_tm_params *p = &app->tm_params[i];
+               int status;
+
+               if (!APP_PARAM_VALID(p))
+                       break;
+
+               status = tm_cfgfile_load(p);
+               APP_CHECK(status == 0,
+                       "Parse error for %s configuration file \"%s\"\n",
+                       p->name,
+                       p->file_name);
+       }
+
+       return 0;
+}
diff --git a/common/vnf_common/cpu_core_map.c b/common/vnf_common/cpu_core_map.c
new file mode 100644 (file)
index 0000000..f0a08f4
--- /dev/null
@@ -0,0 +1,475 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <rte_lcore.h>
+
+#include "cpu_core_map.h"
+
+struct cpu_core_map {
+       uint32_t n_max_sockets;
+       uint32_t n_max_cores_per_socket;
+       uint32_t n_max_ht_per_core;
+       uint32_t n_sockets;
+       uint32_t n_cores_per_socket;
+       uint32_t n_ht_per_core;
+       int map[0];
+};
+
+static inline uint32_t
+cpu_core_map_pos(struct cpu_core_map *map,
+       uint32_t socket_id,
+       uint32_t core_id,
+       uint32_t ht_id)
+{
+       return (socket_id * map->n_max_cores_per_socket + core_id) *
+               map->n_max_ht_per_core + ht_id;
+}
+
+static int
+cpu_core_map_compute_eal(struct cpu_core_map *map);
+
+static int
+cpu_core_map_compute_linux(struct cpu_core_map *map);
+
+static int
+cpu_core_map_compute_and_check(struct cpu_core_map *map);
+
+struct cpu_core_map *
+cpu_core_map_init(uint32_t n_max_sockets,
+       uint32_t n_max_cores_per_socket,
+       uint32_t n_max_ht_per_core,
+       uint32_t eal_initialized)
+{
+       uint32_t map_size, map_mem_size, i;
+       struct cpu_core_map *map;
+       int status;
+
+       /* Check input arguments */
+       if ((n_max_sockets == 0) ||
+               (n_max_cores_per_socket == 0) ||
+               (n_max_ht_per_core == 0))
+               return NULL;
+
+       /* Memory allocation */
+       map_size = n_max_sockets * n_max_cores_per_socket * n_max_ht_per_core;
+       map_mem_size = sizeof(struct cpu_core_map) + map_size * sizeof(int);
+       map = (struct cpu_core_map *) malloc(map_mem_size);
+       if (map == NULL)
+               return NULL;
+
+       /* Initialization */
+       map->n_max_sockets = n_max_sockets;
+       map->n_max_cores_per_socket = n_max_cores_per_socket;
+       map->n_max_ht_per_core = n_max_ht_per_core;
+       map->n_sockets = 0;
+       map->n_cores_per_socket = 0;
+       map->n_ht_per_core = 0;
+
+       for (i = 0; i < map_size; i++)
+               map->map[i] = -1;
+
+       status = (eal_initialized) ?
+               cpu_core_map_compute_eal(map) :
+               cpu_core_map_compute_linux(map);
+
+       if (status) {
+               free(map);
+               return NULL;
+       }
+
+       status = cpu_core_map_compute_and_check(map);
+       if (status) {
+               free(map);
+               return NULL;
+       }
+
+       return map;
+}
+
+int
+cpu_core_map_compute_eal(struct cpu_core_map *map)
+{
+       uint32_t socket_id, core_id, ht_id;
+
+       /* Compute map */
+       for (socket_id = 0; socket_id < map->n_max_sockets; socket_id++) {
+               uint32_t n_detected, core_id_contig;
+               int lcore_id;
+
+               n_detected = 0;
+               for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
+                       struct lcore_config *p = &lcore_config[lcore_id];
+
+                       if ((p->detected) && (p->socket_id == socket_id))
+                               n_detected++;
+               }
+
+               core_id_contig = 0;
+
+               for (core_id = 0; n_detected ; core_id++) {
+                       ht_id = 0;
+
+                       for (lcore_id = 0;
+                               lcore_id < RTE_MAX_LCORE;
+                               lcore_id++) {
+                               struct lcore_config *p =
+                                       &lcore_config[lcore_id];
+
+                               if ((p->detected) &&
+                                       (p->socket_id == socket_id) &&
+                                       (p->core_id == core_id)) {
+                                       uint32_t pos = cpu_core_map_pos(map,
+                                               socket_id,
+                                               core_id_contig,
+                                               ht_id);
+
+                                       map->map[pos] = lcore_id;
+                                       ht_id++;
+                                       n_detected--;
+                               }
+                       }
+
+                       if (ht_id) {
+                               core_id_contig++;
+                               if (core_id_contig ==
+                                       map->n_max_cores_per_socket)
+                                       return -1;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+int
+cpu_core_map_compute_and_check(struct cpu_core_map *map)
+{
+       uint32_t socket_id, core_id, ht_id;
+
+       /* Compute n_ht_per_core, n_cores_per_socket, n_sockets */
+       for (ht_id = 0; ht_id < map->n_max_ht_per_core; ht_id++) {
+               if (map->map[ht_id] == -1)
+                       break;
+
+               map->n_ht_per_core++;
+       }
+
+       if (map->n_ht_per_core == 0)
+               return -1;
+
+       for (core_id = 0; core_id < map->n_max_cores_per_socket; core_id++) {
+               uint32_t pos = core_id * map->n_max_ht_per_core;
+
+               if (map->map[pos] == -1)
+                       break;
+
+               map->n_cores_per_socket++;
+       }
+
+       if (map->n_cores_per_socket == 0)
+               return -1;
+
+       for (socket_id = 0; socket_id < map->n_max_sockets; socket_id++) {
+               uint32_t pos = socket_id * map->n_max_cores_per_socket *
+                       map->n_max_ht_per_core;
+
+               if (map->map[pos] == -1)
+                       break;
+
+               map->n_sockets++;
+       }
+
+       if (map->n_sockets == 0)
+               return -1;
+
+       /* Check that each socket has exactly the same number of cores
+       and that each core has exactly the same number of hyper-threads */
+       for (socket_id = 0; socket_id < map->n_sockets; socket_id++) {
+               for (core_id = 0; core_id < map->n_cores_per_socket; core_id++)
+                       for (ht_id = 0;
+                               ht_id < map->n_max_ht_per_core;
+                               ht_id++) {
+                               uint32_t pos = (socket_id *
+                                       map->n_max_cores_per_socket + core_id) *
+                                       map->n_max_ht_per_core + ht_id;
+
+                               if (((ht_id < map->n_ht_per_core) &&
+                                       (map->map[pos] == -1)) ||
+                                       ((ht_id >= map->n_ht_per_core) &&
+                                       (map->map[pos] != -1)))
+                                       return -1;
+                       }
+
+               for ( ; core_id < map->n_max_cores_per_socket; core_id++)
+                       for (ht_id = 0;
+                               ht_id < map->n_max_ht_per_core;
+                               ht_id++) {
+                               uint32_t pos = cpu_core_map_pos(map,
+                                       socket_id,
+                                       core_id,
+                                       ht_id);
+
+                               if (map->map[pos] != -1)
+                                       return -1;
+                       }
+       }
+
+       return 0;
+}
+
+#define FILE_LINUX_CPU_N_LCORES \
+       "/sys/devices/system/cpu/present"
+
+static int
+cpu_core_map_get_n_lcores_linux(void)
+{
+       char buffer[64], *string;
+       FILE *fd;
+
+       fd = fopen(FILE_LINUX_CPU_N_LCORES, "r");
+       if (fd == NULL)
+               return -1;
+
+       if (fgets(buffer, sizeof(buffer), fd) == NULL) {
+               fclose(fd);
+               return -1;
+       }
+
+       fclose(fd);
+
+       string = index(buffer, '-');
+       if (string == NULL)
+               return -1;
+
+       return atoi(++string) + 1;
+}
+
+#define FILE_LINUX_CPU_CORE_ID \
+       "/sys/devices/system/cpu/cpu%" PRIu32 "/topology/core_id"
+
+static int
+cpu_core_map_get_core_id_linux(int lcore_id)
+{
+       char buffer[64];
+       FILE *fd;
+       int core_id;
+
+       snprintf(buffer, sizeof(buffer), FILE_LINUX_CPU_CORE_ID, lcore_id);
+       fd = fopen(buffer, "r");
+       if (fd == NULL)
+               return -1;
+
+       if (fgets(buffer, sizeof(buffer), fd) == NULL) {
+               fclose(fd);
+               return -1;
+       }
+
+       fclose(fd);
+
+       core_id = atoi(buffer);
+       return core_id;
+}
+
+#define FILE_LINUX_CPU_SOCKET_ID \
+       "/sys/devices/system/cpu/cpu%" PRIu32 "/topology/physical_package_id"
+
+static int
+cpu_core_map_get_socket_id_linux(int lcore_id)
+{
+       char buffer[64];
+       FILE *fd;
+       int socket_id;
+
+       snprintf(buffer, sizeof(buffer), FILE_LINUX_CPU_SOCKET_ID, lcore_id);
+       fd = fopen(buffer, "r");
+       if (fd == NULL)
+               return -1;
+
+       if (fgets(buffer, sizeof(buffer), fd) == NULL) {
+               fclose(fd);
+               return -1;
+       }
+
+       fclose(fd);
+
+       socket_id = atoi(buffer);
+       return socket_id;
+}
+
+int
+cpu_core_map_compute_linux(struct cpu_core_map *map)
+{
+       uint32_t socket_id, core_id, ht_id;
+       int n_lcores;
+
+       n_lcores = cpu_core_map_get_n_lcores_linux();
+       if (n_lcores <= 0)
+               return -1;
+
+       /* Compute map */
+       for (socket_id = 0; socket_id < map->n_max_sockets; socket_id++) {
+               uint32_t n_detected, core_id_contig;
+               int lcore_id;
+
+               n_detected = 0;
+               for (lcore_id = 0; lcore_id < n_lcores; lcore_id++) {
+                       int lcore_socket_id =
+                               cpu_core_map_get_socket_id_linux(lcore_id);
+
+                       if (lcore_socket_id < 0)
+                               return -1;
+
+                       if (((uint32_t) lcore_socket_id) == socket_id)
+                               n_detected++;
+               }
+
+               core_id_contig = 0;
+
+               for (core_id = 0; n_detected ; core_id++) {
+                       ht_id = 0;
+
+                       for (lcore_id = 0; lcore_id < n_lcores; lcore_id++) {
+                               int lcore_socket_id =
+                                       cpu_core_map_get_socket_id_linux(
+                                       lcore_id);
+
+                               if (lcore_socket_id < 0)
+                                       return -1;
+
+                               int lcore_core_id =
+                                       cpu_core_map_get_core_id_linux(
+                                               lcore_id);
+
+                               if (lcore_core_id < 0)
+                                       return -1;
+
+                               if (((uint32_t) lcore_socket_id == socket_id) &&
+                                       ((uint32_t) lcore_core_id == core_id)) {
+                                       uint32_t pos = cpu_core_map_pos(map,
+                                               socket_id,
+                                               core_id_contig,
+                                               ht_id);
+
+                                       map->map[pos] = lcore_id;
+                                       ht_id++;
+                                       n_detected--;
+                               }
+                       }
+
+                       if (ht_id) {
+                               core_id_contig++;
+                               if (core_id_contig ==
+                                       map->n_max_cores_per_socket)
+                                       return -1;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+void
+cpu_core_map_print(struct cpu_core_map *map)
+{
+       uint32_t socket_id, core_id, ht_id;
+
+       if (map == NULL)
+               return;
+
+       for (socket_id = 0; socket_id < map->n_sockets; socket_id++) {
+               printf("Socket %" PRIu32 ":\n", socket_id);
+
+               for (core_id = 0;
+                       core_id < map->n_cores_per_socket;
+                       core_id++) {
+                       printf("[%" PRIu32 "] = [", core_id);
+
+                       for (ht_id = 0; ht_id < map->n_ht_per_core; ht_id++) {
+                               int lcore_id = cpu_core_map_get_lcore_id(map,
+                                       socket_id,
+                                       core_id,
+                                       ht_id);
+
+                               uint32_t core_id_noncontig =
+                                       cpu_core_map_get_core_id_linux(
+                                               lcore_id);
+
+                               printf(" %" PRId32 " (%" PRIu32 ") ",
+                                       lcore_id,
+                                       core_id_noncontig);
+                       }
+
+                       printf("]\n");
+               }
+       }
+}
+
+uint32_t
+cpu_core_map_get_n_sockets(struct cpu_core_map *map)
+{
+       if (map == NULL)
+               return 0;
+
+       return map->n_sockets;
+}
+
+uint32_t
+cpu_core_map_get_n_cores_per_socket(struct cpu_core_map *map)
+{
+       if (map == NULL)
+               return 0;
+
+       return map->n_cores_per_socket;
+}
+
+uint32_t
+cpu_core_map_get_n_ht_per_core(struct cpu_core_map *map)
+{
+       if (map == NULL)
+               return 0;
+
+       return map->n_ht_per_core;
+}
+
+int
+cpu_core_map_get_lcore_id(struct cpu_core_map *map,
+       uint32_t socket_id,
+       uint32_t core_id,
+       uint32_t ht_id)
+{
+       uint32_t pos;
+
+       if ((map == NULL) ||
+               (socket_id >= map->n_sockets) ||
+               (core_id >= map->n_cores_per_socket) ||
+               (ht_id >= map->n_ht_per_core))
+               return -1;
+
+       pos = cpu_core_map_pos(map, socket_id, core_id, ht_id);
+
+       return map->map[pos];
+}
+
+void
+cpu_core_map_free(struct cpu_core_map *map)
+{
+       free(map);
+}
diff --git a/common/vnf_common/cpu_core_map.h b/common/vnf_common/cpu_core_map.h
new file mode 100644 (file)
index 0000000..03c00c7
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef __INCLUDE_CPU_CORE_MAP_H__
+#define __INCLUDE_CPU_CORE_MAP_H__
+
+#include <stdio.h>
+
+#include <rte_lcore.h>
+
+struct cpu_core_map;
+
+struct cpu_core_map *
+cpu_core_map_init(uint32_t n_max_sockets,
+       uint32_t n_max_cores_per_socket,
+       uint32_t n_max_ht_per_core,
+       uint32_t eal_initialized);
+
+uint32_t
+cpu_core_map_get_n_sockets(struct cpu_core_map *map);
+
+uint32_t
+cpu_core_map_get_n_cores_per_socket(struct cpu_core_map *map);
+
+uint32_t
+cpu_core_map_get_n_ht_per_core(struct cpu_core_map *map);
+
+int
+cpu_core_map_get_lcore_id(struct cpu_core_map *map,
+       uint32_t socket_id,
+       uint32_t core_id,
+       uint32_t ht_id);
+
+void cpu_core_map_print(struct cpu_core_map *map);
+
+void
+cpu_core_map_free(struct cpu_core_map *map);
+
+#endif
diff --git a/common/vnf_common/hash_func.h b/common/vnf_common/hash_func.h
new file mode 100644 (file)
index 0000000..c256491
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef __INCLUDE_HASH_FUNC_H__
+#define __INCLUDE_HASH_FUNC_H__
+
+static inline uint64_t
+hash_xor_key8(void *key, __rte_unused uint32_t key_size, uint64_t seed)
+{
+       uint64_t *k = key;
+       uint64_t xor0;
+
+       xor0 = seed ^ k[0];
+
+       return (xor0 >> 32) ^ xor0;
+}
+
+static inline uint64_t
+hash_xor_key16(void *key, __rte_unused uint32_t key_size, uint64_t seed)
+{
+       uint64_t *k = key;
+       uint64_t xor0;
+
+       xor0 = (k[0] ^ seed) ^ k[1];
+
+       return (xor0 >> 32) ^ xor0;
+}
+
+static inline uint64_t
+hash_xor_key24(void *key, __rte_unused uint32_t key_size, uint64_t seed)
+{
+       uint64_t *k = key;
+       uint64_t xor0;
+
+       xor0 = (k[0] ^ seed) ^ k[1];
+
+       xor0 ^= k[2];
+
+       return (xor0 >> 32) ^ xor0;
+}
+
+static inline uint64_t
+hash_xor_key32(void *key, __rte_unused uint32_t key_size, uint64_t seed)
+{
+       uint64_t *k = key;
+       uint64_t xor0, xor1;
+
+       xor0 = (k[0] ^ seed) ^ k[1];
+       xor1 = k[2] ^ k[3];
+
+       xor0 ^= xor1;
+
+       return (xor0 >> 32) ^ xor0;
+}
+
+static inline uint64_t
+hash_xor_key40(void *key, __rte_unused uint32_t key_size, uint64_t seed)
+{
+       uint64_t *k = key;
+       uint64_t xor0, xor1;
+
+       xor0 = (k[0] ^ seed) ^ k[1];
+       xor1 = k[2] ^ k[3];
+
+       xor0 ^= xor1;
+
+       xor0 ^= k[4];
+
+       return (xor0 >> 32) ^ xor0;
+}
+
+static inline uint64_t
+hash_xor_key48(void *key, __rte_unused uint32_t key_size, uint64_t seed)
+{
+       uint64_t *k = key;
+       uint64_t xor0, xor1, xor2;
+
+       xor0 = (k[0] ^ seed) ^ k[1];
+       xor1 = k[2] ^ k[3];
+       xor2 = k[4] ^ k[5];
+
+       xor0 ^= xor1;
+
+       xor0 ^= xor2;
+
+       return (xor0 >> 32) ^ xor0;
+}
+
+static inline uint64_t
+hash_xor_key56(void *key, __rte_unused uint32_t key_size, uint64_t seed)
+{
+       uint64_t *k = key;
+       uint64_t xor0, xor1, xor2;
+
+       xor0 = (k[0] ^ seed) ^ k[1];
+       xor1 = k[2] ^ k[3];
+       xor2 = k[4] ^ k[5];
+
+       xor0 ^= xor1;
+       xor2 ^= k[6];
+
+       xor0 ^= xor2;
+
+       return (xor0 >> 32) ^ xor0;
+}
+
+static inline uint64_t
+hash_xor_key64(void *key, __rte_unused uint32_t key_size, uint64_t seed)
+{
+       uint64_t *k = key;
+       uint64_t xor0, xor1, xor2, xor3;
+
+       xor0 = (k[0] ^ seed) ^ k[1];
+       xor1 = k[2] ^ k[3];
+       xor2 = k[4] ^ k[5];
+       xor3 = k[6] ^ k[7];
+
+       xor0 ^= xor1;
+       xor2 ^= xor3;
+
+       xor0 ^= xor2;
+
+       return (xor0 >> 32) ^ xor0;
+}
+
+#if defined(RTE_ARCH_X86_64) && defined(RTE_MACHINE_CPUFLAG_SSE4_2)
+
+#include <x86intrin.h>
+
+static inline uint64_t
+hash_crc_key8(void *key, __rte_unused uint32_t key_size, uint64_t seed)
+{
+       uint64_t *k = key;
+       uint64_t crc0;
+
+       crc0 = _mm_crc32_u64(seed, k[0]);
+
+       return crc0;
+}
+
+static inline uint64_t
+hash_crc_key16(void *key, __rte_unused uint32_t key_size, uint64_t seed)
+{
+       uint64_t *k = key;
+       uint64_t k0, crc0, crc1;
+
+       k0 = k[0];
+
+       crc0 = _mm_crc32_u64(k0, seed);
+       crc1 = _mm_crc32_u64(k0 >> 32, k[1]);
+
+       crc0 ^= crc1;
+
+       return crc0;
+}
+
+static inline uint64_t
+hash_crc_key24(void *key, __rte_unused uint32_t key_size, uint64_t seed)
+{
+       uint64_t *k = key;
+       uint64_t k0, k2, crc0, crc1;
+
+       k0 = k[0];
+       k2 = k[2];
+
+       crc0 = _mm_crc32_u64(k0, seed);
+       crc1 = _mm_crc32_u64(k0 >> 32, k[1]);
+
+       crc0 = _mm_crc32_u64(crc0, k2);
+
+       crc0 ^= crc1;
+
+       return crc0;
+}
+
+static inline uint64_t
+hash_crc_key32(void *key, __rte_unused uint32_t key_size, uint64_t seed)
+{
+       uint64_t *k = key;
+       uint64_t k0, k2, crc0, crc1, crc2, crc3;
+
+       k0 = k[0];
+       k2 = k[2];
+
+       crc0 = _mm_crc32_u64(k0, seed);
+       crc1 = _mm_crc32_u64(k0 >> 32, k[1]);
+
+       crc2 = _mm_crc32_u64(k2, k[3]);
+       crc3 = k2 >> 32;
+
+       crc0 = _mm_crc32_u64(crc0, crc1);
+       crc1 = _mm_crc32_u64(crc2, crc3);
+
+       crc0 ^= crc1;
+
+       return crc0;
+}
+
+static inline uint64_t
+hash_crc_key40(void *key, __rte_unused uint32_t key_size, uint64_t seed)
+{
+       uint64_t *k = key;
+       uint64_t k0, k2, crc0, crc1, crc2, crc3;
+
+       k0 = k[0];
+       k2 = k[2];
+
+       crc0 = _mm_crc32_u64(k0, seed);
+       crc1 = _mm_crc32_u64(k0 >> 32, k[1]);
+
+       crc2 = _mm_crc32_u64(k2, k[3]);
+       crc3 = _mm_crc32_u64(k2 >> 32, k[4]);
+
+       crc0 = _mm_crc32_u64(crc0, crc1);
+       crc1 = _mm_crc32_u64(crc2, crc3);
+
+       crc0 ^= crc1;
+
+       return crc0;
+}
+
+static inline uint64_t
+hash_crc_key48(void *key, __rte_unused uint32_t key_size, uint64_t seed)
+{
+       uint64_t *k = key;
+       uint64_t k0, k2, k5, crc0, crc1, crc2, crc3;
+
+       k0 = k[0];
+       k2 = k[2];
+       k5 = k[5];
+
+       crc0 = _mm_crc32_u64(k0, seed);
+       crc1 = _mm_crc32_u64(k0 >> 32, k[1]);
+
+       crc2 = _mm_crc32_u64(k2, k[3]);
+       crc3 = _mm_crc32_u64(k2 >> 32, k[4]);
+
+       crc0 = _mm_crc32_u64(crc0, (crc1 << 32) ^ crc2);
+       crc1 = _mm_crc32_u64(crc3, k5);
+
+       crc0 ^= crc1;
+
+       return crc0;
+}
+
+static inline uint64_t
+hash_crc_key56(void *key, __rte_unused uint32_t key_size, uint64_t seed)
+{
+       uint64_t *k = key;
+       uint64_t k0, k2, k5, crc0, crc1, crc2, crc3, crc4, crc5;
+
+       k0 = k[0];
+       k2 = k[2];
+       k5 = k[5];
+
+       crc0 = _mm_crc32_u64(k0, seed);
+       crc1 = _mm_crc32_u64(k0 >> 32, k[1]);
+
+       crc2 = _mm_crc32_u64(k2, k[3]);
+       crc3 = _mm_crc32_u64(k2 >> 32, k[4]);
+
+       crc4 = _mm_crc32_u64(k5, k[6]);
+       crc5 = k5 >> 32;
+
+       crc0 = _mm_crc32_u64(crc0, (crc1 << 32) ^ crc2);
+       crc1 = _mm_crc32_u64(crc3, (crc4 << 32) ^ crc5);
+
+       crc0 ^= crc1;
+
+       return crc0;
+}
+
+static inline uint64_t
+hash_crc_key64(void *key, __rte_unused uint32_t key_size, uint64_t seed)
+{
+       uint64_t *k = key;
+       uint64_t k0, k2, k5, crc0, crc1, crc2, crc3, crc4, crc5;
+
+       k0 = k[0];
+       k2 = k[2];
+       k5 = k[5];
+
+       crc0 = _mm_crc32_u64(k0, seed);
+       crc1 = _mm_crc32_u64(k0 >> 32, k[1]);
+
+       crc2 = _mm_crc32_u64(k2, k[3]);
+       crc3 = _mm_crc32_u64(k2 >> 32, k[4]);
+
+       crc4 = _mm_crc32_u64(k5, k[6]);
+       crc5 = _mm_crc32_u64(k5 >> 32, k[7]);
+
+       crc0 = _mm_crc32_u64(crc0, (crc1 << 32) ^ crc2);
+       crc1 = _mm_crc32_u64(crc3, (crc4 << 32) ^ crc5);
+
+       crc0 ^= crc1;
+
+       return crc0;
+}
+
+#define hash_default_key8                      hash_crc_key8
+#define hash_default_key16                     hash_crc_key16
+#define hash_default_key24                     hash_crc_key24
+#define hash_default_key32                     hash_crc_key32
+#define hash_default_key40                     hash_crc_key40
+#define hash_default_key48                     hash_crc_key48
+#define hash_default_key56                     hash_crc_key56
+#define hash_default_key64                     hash_crc_key64
+
+#else
+
+#define hash_default_key8                      hash_xor_key8
+#define hash_default_key16                     hash_xor_key16
+#define hash_default_key24                     hash_xor_key24
+#define hash_default_key32                     hash_xor_key32
+#define hash_default_key40                     hash_xor_key40
+#define hash_default_key48                     hash_xor_key48
+#define hash_default_key56                     hash_xor_key56
+#define hash_default_key64                     hash_xor_key64
+
+#endif
+
+#endif
diff --git a/common/vnf_common/parser.h b/common/vnf_common/parser.h
new file mode 100644 (file)
index 0000000..b104c16
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef __INCLUDE_PARSER_H__
+#define __INCLUDE_PARSER_H__
+
+int
+parser_read_arg_bool(const char *p);
+
+int
+parser_read_uint64(uint64_t *value, const char *p);
+
+int
+parser_read_uint32(uint32_t *value, const char *p);
+
+int
+parse_hex_string(char *src, uint8_t *dst, uint32_t *size);
+
+#endif
diff --git a/common/vnf_common/pipeline.h b/common/vnf_common/pipeline.h
new file mode 100644 (file)
index 0000000..7bbc0ae
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef __INCLUDE_PIPELINE_H__
+#define __INCLUDE_PIPELINE_H__
+
+#include <cmdline_parse.h>
+
+#include "pipeline_be.h"
+
+/*
+ * Pipeline type front-end operations
+ */
+
+typedef void* (*pipeline_fe_op_init)(struct pipeline_params *params, void *arg);
+
+typedef int (*pipeline_fe_op_free)(void *pipeline);
+
+struct pipeline_fe_ops {
+       pipeline_fe_op_init f_init;
+       pipeline_fe_op_free f_free;
+       cmdline_parse_ctx_t *cmds;
+};
+
+/*
+ * Pipeline type
+ */
+
+struct pipeline_type {
+       const char *name;
+
+       /* pipeline back-end */
+       struct pipeline_be_ops *be_ops;
+
+       /* pipeline front-end */
+       struct pipeline_fe_ops *fe_ops;
+};
+
+static inline uint32_t
+pipeline_type_cmds_count(struct pipeline_type *ptype)
+{
+       cmdline_parse_ctx_t *cmds;
+       uint32_t n_cmds;
+
+       if (ptype->fe_ops == NULL)
+               return 0;
+
+       cmds = ptype->fe_ops->cmds;
+       if (cmds == NULL)
+               return 0;
+
+       for (n_cmds = 0; cmds[n_cmds]; n_cmds++);
+
+       return n_cmds;
+}
+
+int
+parse_pipeline_core(uint32_t *socket,
+       uint32_t *core,
+       uint32_t *ht,
+       const char *entry);
+
+#endif
diff --git a/common/vnf_common/pipeline_actions_common.h b/common/vnf_common/pipeline_actions_common.h
new file mode 100644 (file)
index 0000000..c8c2991
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#ifndef __INCLUDE_PIPELINE_ACTIONS_COMMON_H__
+#define __INCLUDE_PIPELINE_ACTIONS_COMMON_H__
+
+#include <stdint.h>
+
+#include <rte_common.h>
+#include <rte_cycles.h>
+#include <rte_mbuf.h>
+#include <rte_pipeline.h>
+
+#define PIPELINE_PORT_IN_AH(f_ah, f_pkt_work, f_pkt4_work)             \
+static int                                                             \
+f_ah(                                                                  \
+       __rte_unused struct rte_pipeline *p,                            \
+       struct rte_mbuf **pkts,                                         \
+       uint32_t n_pkts,                                                \
+       void *arg)                                                      \
+{                                                                      \
+       uint32_t i;                                                     \
+                                                                       \
+       for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4)                   \
+               f_pkt4_work(&pkts[i], arg);                             \
+                                                                       \
+       for ( ; i < n_pkts; i++)                                        \
+               f_pkt_work(pkts[i], arg);                               \
+                                                                       \
+       return 0;                                                       \
+}
+
+#define PIPELINE_PORT_IN_AH_HIJACK_ALL(f_ah, f_pkt_work, f_pkt4_work) \
+static int                                                             \
+f_ah(                                                                  \
+       struct rte_pipeline *p,                         \
+       struct rte_mbuf **pkts,                                 \
+       uint32_t n_pkts,                                                \
+       void *arg)                                              \
+{                                                                      \
+       uint64_t pkt_mask = RTE_LEN2MASK(n_pkts, uint64_t);     \
+       uint32_t i;                                                     \
+                                                                       \
+       rte_pipeline_ah_packet_hijack(p, pkt_mask);     \
+                                                                       \
+       for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4)   \
+               f_pkt4_work(&pkts[i], arg);                             \
+                                                                       \
+       for ( ; i < n_pkts; i++)                                \
+               f_pkt_work(pkts[i], arg);                       \
+                                                                       \
+       return 0;                                                       \
+}
+
+#define PIPELINE_TABLE_AH_HIT(f_ah, f_pkt_work, f_pkt4_work)           \
+static int                                                             \
+f_ah(                                                                  \
+       __rte_unused struct rte_pipeline *p,                            \
+       struct rte_mbuf **pkts,                                         \
+       uint64_t pkts_in_mask,                                          \
+       struct rte_pipeline_table_entry **entries,                      \
+       void *arg)                                                      \
+{                                                                      \
+       if ((pkts_in_mask & (pkts_in_mask + 1)) == 0) {                 \
+               uint64_t n_pkts = __builtin_popcountll(pkts_in_mask);   \
+               uint32_t i;                                             \
+                                                                       \
+               for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4)           \
+                       f_pkt4_work(&pkts[i], &entries[i], arg);        \
+                                                                       \
+               for ( ; i < n_pkts; i++)                                \
+                       f_pkt_work(pkts[i], entries[i], arg);           \
+       } else                                                          \
+               for ( ; pkts_in_mask; ) {                               \
+                       uint32_t pos = __builtin_ctzll(pkts_in_mask);   \
+                       uint64_t pkt_mask = 1LLU << pos;                \
+                                                                       \
+                       pkts_in_mask &= ~pkt_mask;                      \
+                       f_pkt_work(pkts[pos], entries[pos], arg);       \
+               }                                                       \
+                                                                       \
+       return 0;                                                       \
+}
+
+#define PIPELINE_TABLE_AH_MISS(f_ah, f_pkt_work, f_pkt4_work)          \
+static int                                                             \
+f_ah(                                                                  \
+       __rte_unused struct rte_pipeline *p,                            \
+       struct rte_mbuf **pkts,                                         \
+       uint64_t pkts_in_mask,                                          \
+       struct rte_pipeline_table_entry *entry,                         \
+       void *arg)                                                      \
+{                                                                      \
+       if ((pkts_in_mask & (pkts_in_mask + 1)) == 0) {                 \
+               uint64_t n_pkts = __builtin_popcountll(pkts_in_mask);   \
+               uint32_t i;                                             \
+                                                                       \
+               for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4)           \
+                       f_pkt4_work(&pkts[i], entry, arg);              \
+                                                                       \
+               for ( ; i < n_pkts; i++)                                \
+                       f_pkt_work(pkts[i], entry, arg);                \
+       } else                                                          \
+               for ( ; pkts_in_mask; ) {                               \
+                       uint32_t pos = __builtin_ctzll(pkts_in_mask);   \
+                       uint64_t pkt_mask = 1LLU << pos;                \
+                                                                       \
+                       pkts_in_mask &= ~pkt_mask;                      \
+                       f_pkt_work(pkts[pos], entry, arg);              \
+               }                                                       \
+                                                                       \
+       return 0;                                                       \
+}
+
+#define PIPELINE_TABLE_AH_HIT_DROP_TIME(f_ah, f_pkt_work, f_pkt4_work) \
+static int                                                             \
+f_ah(                                                                  \
+       struct rte_pipeline *p,                                         \
+       struct rte_mbuf **pkts,                                         \
+       uint64_t pkts_mask,                                             \
+       struct rte_pipeline_table_entry **entries,                      \
+       void *arg)                                                      \
+{                                                                      \
+       uint64_t pkts_in_mask = pkts_mask;                              \
+       uint64_t pkts_out_mask = pkts_mask;                             \
+       uint64_t time = rte_rdtsc();                                    \
+                                                                       \
+       if ((pkts_in_mask & (pkts_in_mask + 1)) == 0) {                 \
+               uint64_t n_pkts = __builtin_popcountll(pkts_in_mask);   \
+               uint32_t i;                                             \
+                                                                       \
+               for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4) {         \
+                       uint64_t mask = f_pkt4_work(&pkts[i],           \
+                               &entries[i], arg, time);                \
+                       pkts_out_mask ^= mask << i;                     \
+               }                                                       \
+                                                                       \
+               for ( ; i < n_pkts; i++) {                              \
+                       uint64_t mask = f_pkt_work(pkts[i],             \
+                               entries[i], arg, time);                 \
+                       pkts_out_mask ^= mask << i;                     \
+               }                                                       \
+       } else                                                          \
+               for ( ; pkts_in_mask; ) {                               \
+                       uint32_t pos = __builtin_ctzll(pkts_in_mask);   \
+                       uint64_t pkt_mask = 1LLU << pos;                \
+                       uint64_t mask = f_pkt_work(pkts[pos],           \
+                               entries[pos], arg, time);               \
+                                                                       \
+                       pkts_in_mask &= ~pkt_mask;                      \
+                       pkts_out_mask ^= mask << pos;                   \
+               }                                                       \
+                                                                       \
+       rte_pipeline_ah_packet_drop(p, pkts_out_mask ^ pkts_mask);      \
+                                                                       \
+       return 0;                                                       \
+}
+
+#define PIPELINE_TABLE_AH_MISS_DROP_TIME(f_ah, f_pkt_work, f_pkt4_work)        \
+static int                                                             \
+f_ah(                                                                  \
+       struct rte_pipeline *p,                                         \
+       struct rte_mbuf **pkts,                                         \
+       uint64_t pkts_mask,                                             \
+       struct rte_pipeline_table_entry *entry,                         \
+       void *arg)                                                      \
+{                                                                      \
+       uint64_t pkts_in_mask = pkts_mask;                              \
+       uint64_t pkts_out_mask = pkts_mask;                             \
+       uint64_t time = rte_rdtsc();                                    \
+                                                                       \
+       if ((pkts_in_mask & (pkts_in_mask + 1)) == 0) {                 \
+               uint64_t n_pkts = __builtin_popcountll(pkts_in_mask);   \
+               uint32_t i;                                             \
+                                                                       \
+               for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4) {         \
+                       uint64_t mask = f_pkt4_work(&pkts[i],           \
+                               entry, arg, time);                      \
+                       pkts_out_mask ^= mask << i;                     \
+               }                                                       \
+                                                                       \
+               for ( ; i < n_pkts; i++) {                              \
+                       uint64_t mask = f_pkt_work(pkts[i], entry, arg, time);\
+                       pkts_out_mask ^= mask << i;                     \
+               }                                                       \
+       } else                                                          \
+               for ( ; pkts_in_mask; ) {                               \
+                       uint32_t pos = __builtin_ctzll(pkts_in_mask);   \
+                       uint64_t pkt_mask = 1LLU << pos;                \
+                       uint64_t mask = f_pkt_work(pkts[pos],           \
+                               entry, arg, time);              \
+                                                                       \
+                       pkts_in_mask &= ~pkt_mask;                      \
+                       pkts_out_mask ^= mask << pos;                   \
+               }                                                       \
+                                                                       \
+       rte_pipeline_ah_packet_drop(p, pkts_out_mask ^ pkts_mask);      \
+                                                                       \
+       return 0;                                                       \
+}
+
+#endif
diff --git a/common/vnf_common/pipeline_be.h b/common/vnf_common/pipeline_be.h
new file mode 100644 (file)
index 0000000..006a415
--- /dev/null
@@ -0,0 +1,288 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef __INCLUDE_PIPELINE_BE_H__
+#define __INCLUDE_PIPELINE_BE_H__
+
+#include <rte_port_ethdev.h>
+#include <rte_port_ring.h>
+#include <rte_port_frag.h>
+#include <rte_port_ras.h>
+#include <rte_port_sched.h>
+#include <rte_port_source_sink.h>
+#include <rte_pipeline.h>
+
+enum pipeline_port_in_type {
+       PIPELINE_PORT_IN_ETHDEV_READER,
+       PIPELINE_PORT_IN_RING_READER,
+       PIPELINE_PORT_IN_RING_MULTI_READER,
+       PIPELINE_PORT_IN_RING_READER_IPV4_FRAG,
+       PIPELINE_PORT_IN_RING_READER_IPV6_FRAG,
+       PIPELINE_PORT_IN_SCHED_READER,
+       PIPELINE_PORT_IN_SOURCE,
+};
+
+struct pipeline_port_in_params {
+       enum pipeline_port_in_type type;
+       union {
+               struct rte_port_ethdev_reader_params ethdev;
+               struct rte_port_ring_reader_params ring;
+               struct rte_port_ring_multi_reader_params ring_multi;
+               struct rte_port_ring_reader_ipv4_frag_params ring_ipv4_frag;
+               struct rte_port_ring_reader_ipv6_frag_params ring_ipv6_frag;
+               struct rte_port_sched_reader_params sched;
+               struct rte_port_source_params source;
+       } params;
+       uint32_t burst_size;
+};
+
+static inline void *
+pipeline_port_in_params_convert(struct pipeline_port_in_params  *p)
+{
+       switch (p->type) {
+       case PIPELINE_PORT_IN_ETHDEV_READER:
+               return (void *) &p->params.ethdev;
+       case PIPELINE_PORT_IN_RING_READER:
+               return (void *) &p->params.ring;
+       case PIPELINE_PORT_IN_RING_MULTI_READER:
+               return (void *) &p->params.ring_multi;
+       case PIPELINE_PORT_IN_RING_READER_IPV4_FRAG:
+               return (void *) &p->params.ring_ipv4_frag;
+       case PIPELINE_PORT_IN_RING_READER_IPV6_FRAG:
+               return (void *) &p->params.ring_ipv6_frag;
+       case PIPELINE_PORT_IN_SCHED_READER:
+               return (void *) &p->params.sched;
+       case PIPELINE_PORT_IN_SOURCE:
+               return (void *) &p->params.source;
+       default:
+               return NULL;
+       }
+}
+
+static inline struct rte_port_in_ops *
+pipeline_port_in_params_get_ops(struct pipeline_port_in_params  *p)
+{
+       switch (p->type) {
+       case PIPELINE_PORT_IN_ETHDEV_READER:
+               return &rte_port_ethdev_reader_ops;
+       case PIPELINE_PORT_IN_RING_READER:
+               return &rte_port_ring_reader_ops;
+       case PIPELINE_PORT_IN_RING_MULTI_READER:
+               return &rte_port_ring_multi_reader_ops;
+       case PIPELINE_PORT_IN_RING_READER_IPV4_FRAG:
+               return &rte_port_ring_reader_ipv4_frag_ops;
+       case PIPELINE_PORT_IN_RING_READER_IPV6_FRAG:
+               return &rte_port_ring_reader_ipv6_frag_ops;
+       case PIPELINE_PORT_IN_SCHED_READER:
+               return &rte_port_sched_reader_ops;
+       case PIPELINE_PORT_IN_SOURCE:
+               return &rte_port_source_ops;
+       default:
+               return NULL;
+       }
+}
+
+enum pipeline_port_out_type {
+       PIPELINE_PORT_OUT_ETHDEV_WRITER,
+       PIPELINE_PORT_OUT_ETHDEV_WRITER_NODROP,
+       PIPELINE_PORT_OUT_RING_WRITER,
+       PIPELINE_PORT_OUT_RING_MULTI_WRITER,
+       PIPELINE_PORT_OUT_RING_WRITER_NODROP,
+       PIPELINE_PORT_OUT_RING_MULTI_WRITER_NODROP,
+       PIPELINE_PORT_OUT_RING_WRITER_IPV4_RAS,
+       PIPELINE_PORT_OUT_RING_WRITER_IPV6_RAS,
+       PIPELINE_PORT_OUT_SCHED_WRITER,
+       PIPELINE_PORT_OUT_SINK,
+};
+
+struct pipeline_port_out_params {
+       enum pipeline_port_out_type type;
+       union {
+               struct rte_port_ethdev_writer_params ethdev;
+               struct rte_port_ethdev_writer_nodrop_params ethdev_nodrop;
+               struct rte_port_ring_writer_params ring;
+               struct rte_port_ring_multi_writer_params ring_multi;
+               struct rte_port_ring_writer_nodrop_params ring_nodrop;
+               struct rte_port_ring_multi_writer_nodrop_params ring_multi_nodrop;
+               struct rte_port_ring_writer_ipv4_ras_params ring_ipv4_ras;
+               struct rte_port_ring_writer_ipv6_ras_params ring_ipv6_ras;
+               struct rte_port_sched_writer_params sched;
+               struct rte_port_sink_params sink;
+       } params;
+};
+
+static inline void *
+pipeline_port_out_params_convert(struct pipeline_port_out_params  *p)
+{
+       switch (p->type) {
+       case PIPELINE_PORT_OUT_ETHDEV_WRITER:
+               return (void *) &p->params.ethdev;
+       case PIPELINE_PORT_OUT_ETHDEV_WRITER_NODROP:
+               return (void *) &p->params.ethdev_nodrop;
+       case PIPELINE_PORT_OUT_RING_WRITER:
+               return (void *) &p->params.ring;
+       case PIPELINE_PORT_OUT_RING_MULTI_WRITER:
+               return (void *) &p->params.ring_multi;
+       case PIPELINE_PORT_OUT_RING_WRITER_NODROP:
+               return (void *) &p->params.ring_nodrop;
+       case PIPELINE_PORT_OUT_RING_MULTI_WRITER_NODROP:
+               return (void *) &p->params.ring_multi_nodrop;
+       case PIPELINE_PORT_OUT_RING_WRITER_IPV4_RAS:
+               return (void *) &p->params.ring_ipv4_ras;
+       case PIPELINE_PORT_OUT_RING_WRITER_IPV6_RAS:
+               return (void *) &p->params.ring_ipv6_ras;
+       case PIPELINE_PORT_OUT_SCHED_WRITER:
+               return (void *) &p->params.sched;
+       case PIPELINE_PORT_OUT_SINK:
+               return (void *) &p->params.sink;
+       default:
+               return NULL;
+       }
+}
+
+static inline void *
+pipeline_port_out_params_get_ops(struct pipeline_port_out_params  *p)
+{
+       switch (p->type) {
+       case PIPELINE_PORT_OUT_ETHDEV_WRITER:
+               return &rte_port_ethdev_writer_ops;
+       case PIPELINE_PORT_OUT_ETHDEV_WRITER_NODROP:
+               return &rte_port_ethdev_writer_nodrop_ops;
+       case PIPELINE_PORT_OUT_RING_WRITER:
+               return &rte_port_ring_writer_ops;
+       case PIPELINE_PORT_OUT_RING_MULTI_WRITER:
+               return &rte_port_ring_multi_writer_ops;
+       case PIPELINE_PORT_OUT_RING_WRITER_NODROP:
+               return &rte_port_ring_writer_nodrop_ops;
+       case PIPELINE_PORT_OUT_RING_MULTI_WRITER_NODROP:
+               return &rte_port_ring_multi_writer_nodrop_ops;
+       case PIPELINE_PORT_OUT_RING_WRITER_IPV4_RAS:
+               return &rte_port_ring_writer_ipv4_ras_ops;
+       case PIPELINE_PORT_OUT_RING_WRITER_IPV6_RAS:
+               return &rte_port_ring_writer_ipv6_ras_ops;
+       case PIPELINE_PORT_OUT_SCHED_WRITER:
+               return &rte_port_sched_writer_ops;
+       case PIPELINE_PORT_OUT_SINK:
+               return &rte_port_sink_ops;
+       default:
+               return NULL;
+       }
+}
+
+#ifndef PIPELINE_NAME_SIZE
+#define PIPELINE_NAME_SIZE                       32
+#endif
+
+#ifndef PIPELINE_MAX_PORT_IN
+#define PIPELINE_MAX_PORT_IN                     16
+#endif
+
+#ifndef PIPELINE_MAX_PORT_OUT
+#define PIPELINE_MAX_PORT_OUT                    16
+#endif
+
+#ifndef PIPELINE_MAX_TABLES
+#define PIPELINE_MAX_TABLES                      16
+#endif
+
+#ifndef PIPELINE_MAX_MSGQ_IN
+#define PIPELINE_MAX_MSGQ_IN                     16
+#endif
+
+#ifndef PIPELINE_MAX_MSGQ_OUT
+#define PIPELINE_MAX_MSGQ_OUT                    16
+#endif
+
+#ifndef PIPELINE_MAX_ARGS
+#define PIPELINE_MAX_ARGS                        32
+#endif
+
+struct pipeline_params {
+       char name[PIPELINE_NAME_SIZE];
+
+       struct pipeline_port_in_params port_in[PIPELINE_MAX_PORT_IN];
+       struct pipeline_port_out_params port_out[PIPELINE_MAX_PORT_OUT];
+       struct rte_ring *msgq_in[PIPELINE_MAX_MSGQ_IN];
+       struct rte_ring *msgq_out[PIPELINE_MAX_MSGQ_OUT];
+
+       uint32_t n_ports_in;
+       uint32_t n_ports_out;
+       uint32_t n_msgq;
+
+       int socket_id;
+
+       char *args_name[PIPELINE_MAX_ARGS];
+       char *args_value[PIPELINE_MAX_ARGS];
+       uint32_t n_args;
+
+       uint32_t log_level;
+};
+
+/*
+ * Pipeline type back-end operations
+ */
+
+typedef void* (*pipeline_be_op_init)(struct pipeline_params *params,
+       void *arg);
+
+typedef int (*pipeline_be_op_free)(void *pipeline);
+
+typedef int (*pipeline_be_op_run)(void *pipeline);
+
+typedef int (*pipeline_be_op_timer)(void *pipeline);
+
+typedef int (*pipeline_be_op_track)(void *pipeline,
+       uint32_t port_in,
+       uint32_t *port_out);
+
+struct pipeline_be_ops {
+       pipeline_be_op_init f_init;
+       pipeline_be_op_free f_free;
+       pipeline_be_op_run f_run;
+       pipeline_be_op_timer f_timer;
+       pipeline_be_op_track f_track;
+};
+
+/* Pipeline specific config parse error messages */
+#define PIPELINE_ARG_CHECK(exp, fmt, ...)                              \
+do {                                                                   \
+       if (!(exp)) {                                                   \
+               fprintf(stderr, fmt "\n", ## __VA_ARGS__);              \
+               return -1;                                              \
+       }                                                               \
+} while (0)
+
+#define PIPELINE_PARSE_ERR_INV_VAL(exp, section, entry, val)           \
+PIPELINE_ARG_CHECK(exp, "Parse error in section \"%s\": entry \"%s\" " \
+       "has invalid value (\"%s\")", section, entry, val)
+
+#define PIPELINE_PARSE_ERR_OUT_RNG(exp, section, entry, val)           \
+PIPELINE_ARG_CHECK(exp, "Parse error in section \"%s\": entry \"%s\" " \
+       "value is out of range (\"%s\")", section, entry, val)
+
+#define PIPELINE_PARSE_ERR_DUPLICATE(exp, section, entry)              \
+PIPELINE_ARG_CHECK(exp, "Parse error in section \"%s\": duplicated "   \
+       "entry \"%s\"", section, entry)
+
+#define PIPELINE_PARSE_ERR_INV_ENT(exp, section, entry)                        \
+PIPELINE_ARG_CHECK(exp, "Parse error in section \"%s\": invalid entry "        \
+       "\"%s\"", section, entry)
+
+#define PIPELINE_PARSE_ERR_MANDATORY(exp, section, entry)              \
+PIPELINE_ARG_CHECK(exp, "Parse error in section \"%s\": mandatory "    \
+       "entry \"%s\" is missing", section, entry)
+
+#endif
diff --git a/common/vnf_common/thread.c b/common/vnf_common/thread.c
new file mode 100644 (file)
index 0000000..dcf272f
--- /dev/null
@@ -0,0 +1,305 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <rte_common.h>
+#include <rte_cycles.h>
+#include <rte_pipeline.h>
+
+#include "pipeline_common_be.h"
+#include "app.h"
+#include "thread.h"
+
+#if APP_THREAD_HEADROOM_STATS_COLLECT
+
+#define PIPELINE_RUN_REGULAR(thread, pipeline)         \
+do {                                                   \
+       uint64_t t0 = rte_rdtsc_precise();              \
+       int n_pkts = rte_pipeline_run(pipeline->p);     \
+                                                       \
+       if (n_pkts == 0) {                              \
+               uint64_t t1 = rte_rdtsc_precise();      \
+                                                       \
+               thread->headroom_cycles += t1 - t0;     \
+       }                                               \
+} while (0)
+
+
+#define PIPELINE_RUN_CUSTOM(thread, data)              \
+do {                                                   \
+       uint64_t t0 = rte_rdtsc_precise();              \
+       int n_pkts = data->f_run(data->be);             \
+                                                       \
+       if (n_pkts == 0) {                              \
+               uint64_t t1 = rte_rdtsc_precise();      \
+                                                       \
+               thread->headroom_cycles += t1 - t0;     \
+       }                                               \
+} while (0)
+
+#else
+
+#define PIPELINE_RUN_REGULAR(thread, pipeline)         \
+       rte_pipeline_run(pipeline->p)
+
+#define PIPELINE_RUN_CUSTOM(thread, data)              \
+       data->f_run(data->be)
+
+#endif
+
+static inline void *
+thread_msg_recv(struct rte_ring *r)
+{
+       void *msg;
+       int status = rte_ring_sc_dequeue(r, &msg);
+
+       if (status != 0)
+               return NULL;
+
+       return msg;
+}
+
+static inline void
+thread_msg_send(struct rte_ring *r,
+       void *msg)
+{
+       int status;
+
+       do {
+               status = rte_ring_sp_enqueue(r, msg);
+       } while (status == -ENOBUFS);
+}
+
+static int
+thread_pipeline_enable(struct app_thread_data *t,
+               struct thread_pipeline_enable_msg_req *req)
+{
+       struct app_thread_pipeline_data *p;
+
+       if (req->f_run == NULL) {
+               if (t->n_regular >= APP_MAX_THREAD_PIPELINES)
+                       return -1;
+       } else {
+               if (t->n_custom >= APP_MAX_THREAD_PIPELINES)
+                       return -1;
+       }
+
+       p = (req->f_run == NULL) ?
+               &t->regular[t->n_regular] :
+               &t->custom[t->n_custom];
+
+       p->pipeline_id = req->pipeline_id;
+       p->be = req->be;
+       p->f_run = req->f_run;
+       p->f_timer = req->f_timer;
+       p->timer_period = req->timer_period;
+       p->deadline = 0;
+
+       if (req->f_run == NULL)
+               t->n_regular++;
+       else
+               t->n_custom++;
+
+       return 0;
+}
+
+static int
+thread_pipeline_disable(struct app_thread_data *t,
+               struct thread_pipeline_disable_msg_req *req)
+{
+       uint32_t n_regular = RTE_MIN(t->n_regular, RTE_DIM(t->regular));
+       uint32_t n_custom = RTE_MIN(t->n_custom, RTE_DIM(t->custom));
+       uint32_t i;
+
+       /* search regular pipelines of current thread */
+       for (i = 0; i < n_regular; i++) {
+               if (t->regular[i].pipeline_id != req->pipeline_id)
+                       continue;
+
+               if (i < n_regular - 1)
+                       memcpy(&t->regular[i],
+                               &t->regular[i+1],
+                               (n_regular - 1 - i) * sizeof(struct app_thread_pipeline_data));
+
+               n_regular--;
+               t->n_regular = n_regular;
+
+               return 0;
+       }
+
+       /* search custom pipelines of current thread */
+       for (i = 0; i < n_custom; i++) {
+               if (t->custom[i].pipeline_id != req->pipeline_id)
+                       continue;
+
+               if (i < n_custom - 1)
+                       memcpy(&t->custom[i],
+                               &t->custom[i+1],
+                               (n_custom - 1 - i) * sizeof(struct app_thread_pipeline_data));
+
+               n_custom--;
+               t->n_custom = n_custom;
+
+               return 0;
+       }
+
+       /* return if pipeline not found */
+       return -1;
+}
+
+static int
+thread_msg_req_handle(struct app_thread_data *t)
+{
+       void *msg_ptr;
+       struct thread_msg_req *req;
+       struct thread_msg_rsp *rsp;
+
+       msg_ptr = thread_msg_recv(t->msgq_in);
+       req = msg_ptr;
+       rsp = msg_ptr;
+
+       if (req != NULL)
+               switch (req->type) {
+               case THREAD_MSG_REQ_PIPELINE_ENABLE: {
+                       rsp->status = thread_pipeline_enable(t,
+                                       (struct thread_pipeline_enable_msg_req *) req);
+                       thread_msg_send(t->msgq_out, rsp);
+                       break;
+               }
+
+               case THREAD_MSG_REQ_PIPELINE_DISABLE: {
+                       rsp->status = thread_pipeline_disable(t,
+                                       (struct thread_pipeline_disable_msg_req *) req);
+                       thread_msg_send(t->msgq_out, rsp);
+                       break;
+               }
+
+               case THREAD_MSG_REQ_HEADROOM_READ: {
+                       struct thread_headroom_read_msg_rsp *rsp =
+                               (struct thread_headroom_read_msg_rsp *)
+                               req;
+
+                       rsp->headroom_ratio = t->headroom_ratio;
+                       rsp->status = 0;
+                       thread_msg_send(t->msgq_out, rsp);
+                       break;
+               }
+               default:
+                       break;
+               }
+
+       return 0;
+}
+
+static void
+thread_headroom_update(struct app_thread_data *t, uint64_t time)
+{
+       uint64_t time_diff = time - t->headroom_time;
+
+       t->headroom_ratio =
+               ((double) t->headroom_cycles) / ((double) time_diff);
+
+       t->headroom_cycles = 0;
+       t->headroom_time = rte_rdtsc_precise();
+}
+
+int
+app_thread(void *arg)
+{
+       struct app_params *app = (struct app_params *) arg;
+       uint32_t core_id = rte_lcore_id(), i, j;
+       struct app_thread_data *t = &app->thread_data[core_id];
+
+       for (i = 0; ; i++) {
+               uint32_t n_regular = RTE_MIN(t->n_regular, RTE_DIM(t->regular));
+               uint32_t n_custom = RTE_MIN(t->n_custom, RTE_DIM(t->custom));
+
+               /* Run regular pipelines */
+               for (j = 0; j < n_regular; j++) {
+                       struct app_thread_pipeline_data *data = &t->regular[j];
+                       struct pipeline *p = data->be;
+
+                       PIPELINE_RUN_REGULAR(t, p);
+               }
+
+               /* Run custom pipelines */
+               for (j = 0; j < n_custom; j++) {
+                       struct app_thread_pipeline_data *data = &t->custom[j];
+
+                       PIPELINE_RUN_CUSTOM(t, data);
+               }
+
+               /* Timer */
+               if ((i & 0xF) == 0) {
+                       uint64_t time = rte_get_tsc_cycles();
+                       uint64_t t_deadline = UINT64_MAX;
+
+                       if (time < t->deadline)
+                               continue;
+
+                       /* Timer for regular pipelines */
+                       for (j = 0; j < n_regular; j++) {
+                               struct app_thread_pipeline_data *data =
+                                       &t->regular[j];
+                               uint64_t p_deadline = data->deadline;
+
+                               if (p_deadline <= time) {
+                                       data->f_timer(data->be);
+                                       p_deadline = time + data->timer_period;
+                                       data->deadline = p_deadline;
+                               }
+
+                               if (p_deadline < t_deadline)
+                                       t_deadline = p_deadline;
+                       }
+
+                       /* Timer for custom pipelines */
+                       for (j = 0; j < n_custom; j++) {
+                               struct app_thread_pipeline_data *data =
+                                       &t->custom[j];
+                               uint64_t p_deadline = data->deadline;
+
+                               if (p_deadline <= time) {
+                                       data->f_timer(data->be);
+                                       p_deadline = time + data->timer_period;
+                                       data->deadline = p_deadline;
+                               }
+
+                               if (p_deadline < t_deadline)
+                                       t_deadline = p_deadline;
+                       }
+
+                       /* Timer for thread message request */
+                       {
+                               uint64_t deadline = t->thread_req_deadline;
+
+                               if (deadline <= time) {
+                                       thread_msg_req_handle(t);
+                                       thread_headroom_update(t, time);
+                                       deadline = time + t->timer_period;
+                                       t->thread_req_deadline = deadline;
+                               }
+
+                               if (deadline < t_deadline)
+                                       t_deadline = deadline;
+                       }
+
+
+                       t->deadline = t_deadline;
+               }
+       }
+
+       return 0;
+}
diff --git a/common/vnf_common/thread.h b/common/vnf_common/thread.h
new file mode 100644 (file)
index 0000000..24bcd23
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef THREAD_H_
+#define THREAD_H_
+
+#include "app.h"
+#include "pipeline_be.h"
+
+enum thread_msg_req_type {
+       THREAD_MSG_REQ_PIPELINE_ENABLE = 0,
+       THREAD_MSG_REQ_PIPELINE_DISABLE,
+       THREAD_MSG_REQ_HEADROOM_READ,
+       THREAD_MSG_REQS
+};
+
+struct thread_msg_req {
+       enum thread_msg_req_type type;
+};
+
+struct thread_msg_rsp {
+       int status;
+};
+
+/*
+ * PIPELINE ENABLE
+ */
+struct thread_pipeline_enable_msg_req {
+       enum thread_msg_req_type type;
+
+       uint32_t pipeline_id;
+       void *be;
+       pipeline_be_op_run f_run;
+       pipeline_be_op_timer f_timer;
+       uint64_t timer_period;
+};
+
+struct thread_pipeline_enable_msg_rsp {
+       int status;
+};
+
+/*
+ * PIPELINE DISABLE
+ */
+struct thread_pipeline_disable_msg_req {
+       enum thread_msg_req_type type;
+
+       uint32_t pipeline_id;
+};
+
+struct thread_pipeline_disable_msg_rsp {
+       int status;
+};
+
+/*
+ * THREAD HEADROOM
+ */
+struct thread_headroom_read_msg_req {
+       enum thread_msg_req_type type;
+};
+
+struct thread_headroom_read_msg_rsp {
+       int status;
+
+       double headroom_ratio;
+};
+
+#endif /* THREAD_H_ */
diff --git a/common/vnf_common/thread_fe.c b/common/vnf_common/thread_fe.c
new file mode 100644 (file)
index 0000000..7029620
--- /dev/null
@@ -0,0 +1,480 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <rte_common.h>
+#include <rte_ring.h>
+#include <rte_malloc.h>
+#include <cmdline_rdline.h>
+#include <cmdline_parse.h>
+#include <cmdline_parse_num.h>
+#include <cmdline_parse_string.h>
+#include <cmdline_parse_ipaddr.h>
+#include <cmdline_parse_etheraddr.h>
+#include <cmdline_socket.h>
+#include <cmdline.h>
+
+#include "thread.h"
+#include "thread_fe.h"
+#include "pipeline.h"
+#include "pipeline_common_fe.h"
+#include "app.h"
+
+static inline void *
+thread_msg_send_recv(struct app_params *app,
+       uint32_t socket_id, uint32_t core_id, uint32_t ht_id,
+       void *msg,
+       uint32_t timeout_ms)
+{
+       struct rte_ring *r_req = app_thread_msgq_in_get(app,
+               socket_id, core_id, ht_id);
+       if(r_req == NULL)
+               return NULL;
+       struct rte_ring *r_rsp = app_thread_msgq_out_get(app,
+               socket_id, core_id, ht_id);
+       if(r_rsp == NULL)
+               return NULL;
+       uint64_t hz = rte_get_tsc_hz();
+       void *msg_recv;
+       uint64_t deadline;
+       int status;
+
+       /* send */
+       do {
+               status = rte_ring_sp_enqueue(r_req, (void *) msg);
+       } while (status == -ENOBUFS);
+
+       /* recv */
+       deadline = (timeout_ms) ?
+               (rte_rdtsc() + ((hz * timeout_ms) / 1000)) :
+               UINT64_MAX;
+
+       do {
+               if (rte_rdtsc() > deadline)
+                       return NULL;
+
+               status = rte_ring_sc_dequeue(r_rsp, &msg_recv);
+       } while (status != 0);
+
+       return msg_recv;
+}
+
+int
+app_pipeline_enable(struct app_params *app,
+               uint32_t socket_id,
+               uint32_t core_id,
+               uint32_t hyper_th_id,
+               uint32_t pipeline_id)
+{
+       struct thread_pipeline_enable_msg_req *req;
+       struct thread_pipeline_enable_msg_rsp *rsp;
+       int thread_id;
+       struct app_pipeline_data *p;
+       struct app_pipeline_params *p_params;
+       struct pipeline_type *p_type;
+       int status;
+
+       if (app == NULL)
+               return -1;
+
+       thread_id = cpu_core_map_get_lcore_id(app->core_map,
+                       socket_id,
+                       core_id,
+                       hyper_th_id);
+
+       if ((thread_id < 0) || !app_core_is_enabled(app, thread_id))
+               return -1;
+
+       if (app_pipeline_data(app, pipeline_id) == NULL)
+               return -1;
+
+       p = &app->pipeline_data[pipeline_id];
+       p_params = &app->pipeline_params[pipeline_id];
+       p_type = app_pipeline_type_find(app, p_params->type);
+       if (p_type == NULL)
+               return -1;
+
+       if (p->enabled == 1)
+               return -1;
+
+       req = app_msg_alloc(app);
+       if (req == NULL)
+               return -1;
+
+       req->type = THREAD_MSG_REQ_PIPELINE_ENABLE;
+       req->pipeline_id = pipeline_id;
+       req->be = p->be;
+       req->f_run = p_type->be_ops->f_run;
+       req->f_timer = p_type->be_ops->f_timer;
+       req->timer_period = p->timer_period;
+
+       rsp = thread_msg_send_recv(app,
+               socket_id, core_id, hyper_th_id, req, MSG_TIMEOUT_DEFAULT);
+       if (rsp == NULL)
+               return -1;
+
+       status = rsp->status;
+       app_msg_free(app, rsp);
+
+       if (status != 0)
+               return -1;
+
+       p->enabled = 1;
+       return 0;
+}
+
+int
+app_pipeline_disable(struct app_params *app,
+               uint32_t socket_id,
+               uint32_t core_id,
+               uint32_t hyper_th_id,
+               uint32_t pipeline_id)
+{
+       struct thread_pipeline_disable_msg_req *req;
+       struct thread_pipeline_disable_msg_rsp *rsp;
+       int thread_id;
+       struct app_pipeline_data *p;
+       int status;
+
+       if (app == NULL)
+               return -1;
+
+       thread_id = cpu_core_map_get_lcore_id(app->core_map,
+                       socket_id,
+                       core_id,
+                       hyper_th_id);
+
+       if ((thread_id < 0) || !app_core_is_enabled(app, thread_id))
+               return -1;
+
+       if (app_pipeline_data(app, pipeline_id) == NULL)
+               return -1;
+
+       p = &app->pipeline_data[pipeline_id];
+
+       if (p->enabled == 0)
+               return -1;
+
+       req = app_msg_alloc(app);
+       if (req == NULL)
+               return -1;
+
+       req->type = THREAD_MSG_REQ_PIPELINE_DISABLE;
+       req->pipeline_id = pipeline_id;
+
+       rsp = thread_msg_send_recv(app,
+               socket_id, core_id, hyper_th_id, req, MSG_TIMEOUT_DEFAULT);
+
+       if (rsp == NULL)
+               return -1;
+
+       status = rsp->status;
+       app_msg_free(app, rsp);
+
+       if (status != 0)
+               return -1;
+
+       p->enabled = 0;
+       return 0;
+}
+
+int
+app_thread_headroom(struct app_params *app,
+               uint32_t socket_id,
+               uint32_t core_id,
+               uint32_t hyper_th_id)
+{
+       struct thread_headroom_read_msg_req *req;
+       struct thread_headroom_read_msg_rsp *rsp;
+       int thread_id;
+       int status;
+
+       if (app == NULL)
+               return -1;
+
+       thread_id = cpu_core_map_get_lcore_id(app->core_map,
+                       socket_id,
+                       core_id,
+                       hyper_th_id);
+
+       if ((thread_id < 0) || !app_core_is_enabled(app, thread_id))
+               return -1;
+
+       req = app_msg_alloc(app);
+       if (req == NULL)
+               return -1;
+
+       req->type = THREAD_MSG_REQ_HEADROOM_READ;
+
+       rsp = thread_msg_send_recv(app,
+               socket_id, core_id, hyper_th_id, req, MSG_TIMEOUT_DEFAULT);
+
+       if (rsp == NULL)
+               return -1;
+
+       status = rsp->status;
+
+       if (status != 0)
+               return -1;
+
+       printf("%.3f%%\n", rsp->headroom_ratio * 100);
+
+
+       app_msg_free(app, rsp);
+
+       return 0;
+}
+
+/*
+ * pipeline enable
+ */
+
+struct cmd_pipeline_enable_result {
+       cmdline_fixed_string_t t_string;
+       cmdline_fixed_string_t t_id_string;
+       cmdline_fixed_string_t pipeline_string;
+       uint32_t pipeline_id;
+       cmdline_fixed_string_t enable_string;
+};
+
+static void
+cmd_pipeline_enable_parsed(
+       void *parsed_result,
+       __rte_unused struct cmdline *cl,
+        void *data)
+{
+       struct cmd_pipeline_enable_result *params = parsed_result;
+       struct app_params *app = data;
+       int status;
+       uint32_t core_id, socket_id, hyper_th_id;
+
+       if (parse_pipeline_core(&socket_id,
+                       &core_id,
+                       &hyper_th_id,
+                       params->t_id_string) != 0) {
+               printf("Command failed\n");
+               return;
+       }
+
+       status = app_pipeline_enable(app,
+                       socket_id,
+                       core_id,
+                       hyper_th_id,
+                       params->pipeline_id);
+
+       if (status != 0)
+               printf("Command failed\n");
+}
+
+cmdline_parse_token_string_t cmd_pipeline_enable_t_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_pipeline_enable_result, t_string, "t");
+
+cmdline_parse_token_string_t cmd_pipeline_enable_t_id_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_pipeline_enable_result, t_id_string,
+               NULL);
+
+cmdline_parse_token_string_t cmd_pipeline_enable_pipeline_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_pipeline_enable_result, pipeline_string,
+               "pipeline");
+
+cmdline_parse_token_num_t cmd_pipeline_enable_pipeline_id =
+       TOKEN_NUM_INITIALIZER(struct cmd_pipeline_enable_result, pipeline_id,
+               UINT32);
+
+cmdline_parse_token_string_t cmd_pipeline_enable_enable_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_pipeline_enable_result, enable_string,
+               "enable");
+
+cmdline_parse_inst_t cmd_pipeline_enable = {
+       .f = cmd_pipeline_enable_parsed,
+       .data = NULL,
+       .help_str = "Enable pipeline on specified core",
+       .tokens = {
+               (void *)&cmd_pipeline_enable_t_string,
+               (void *)&cmd_pipeline_enable_t_id_string,
+               (void *)&cmd_pipeline_enable_pipeline_string,
+               (void *)&cmd_pipeline_enable_pipeline_id,
+               (void *)&cmd_pipeline_enable_enable_string,
+               NULL,
+       },
+};
+
+/*
+ * pipeline disable
+ */
+
+struct cmd_pipeline_disable_result {
+       cmdline_fixed_string_t t_string;
+       cmdline_fixed_string_t t_id_string;
+       cmdline_fixed_string_t pipeline_string;
+       uint32_t pipeline_id;
+       cmdline_fixed_string_t disable_string;
+};
+
+static void
+cmd_pipeline_disable_parsed(
+       void *parsed_result,
+       __rte_unused struct cmdline *cl,
+        void *data)
+{
+       struct cmd_pipeline_disable_result *params = parsed_result;
+       struct app_params *app = data;
+       int status;
+       uint32_t core_id, socket_id, hyper_th_id;
+
+       if (parse_pipeline_core(&socket_id,
+                       &core_id,
+                       &hyper_th_id,
+                       params->t_id_string) != 0) {
+               printf("Command failed\n");
+               return;
+       }
+
+       status = app_pipeline_disable(app,
+                       socket_id,
+                       core_id,
+                       hyper_th_id,
+                       params->pipeline_id);
+
+       if (status != 0)
+               printf("Command failed\n");
+}
+
+cmdline_parse_token_string_t cmd_pipeline_disable_t_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_pipeline_disable_result, t_string, "t");
+
+cmdline_parse_token_string_t cmd_pipeline_disable_t_id_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_pipeline_disable_result, t_id_string,
+               NULL);
+
+cmdline_parse_token_string_t cmd_pipeline_disable_pipeline_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_pipeline_disable_result,
+               pipeline_string, "pipeline");
+
+cmdline_parse_token_num_t cmd_pipeline_disable_pipeline_id =
+       TOKEN_NUM_INITIALIZER(struct cmd_pipeline_disable_result, pipeline_id,
+               UINT32);
+
+cmdline_parse_token_string_t cmd_pipeline_disable_disable_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_pipeline_disable_result, disable_string,
+               "disable");
+
+cmdline_parse_inst_t cmd_pipeline_disable = {
+       .f = cmd_pipeline_disable_parsed,
+       .data = NULL,
+       .help_str = "Disable pipeline on specified core",
+       .tokens = {
+               (void *)&cmd_pipeline_disable_t_string,
+               (void *)&cmd_pipeline_disable_t_id_string,
+               (void *)&cmd_pipeline_disable_pipeline_string,
+               (void *)&cmd_pipeline_disable_pipeline_id,
+               (void *)&cmd_pipeline_disable_disable_string,
+               NULL,
+       },
+};
+
+
+/*
+ * thread headroom
+ */
+
+struct cmd_thread_headroom_result {
+       cmdline_fixed_string_t t_string;
+       cmdline_fixed_string_t t_id_string;
+       cmdline_fixed_string_t headroom_string;
+};
+
+static void
+cmd_thread_headroom_parsed(
+       void *parsed_result,
+       __rte_unused struct cmdline *cl,
+        void *data)
+{
+       struct cmd_thread_headroom_result *params = parsed_result;
+       struct app_params *app = data;
+       int status;
+       uint32_t core_id, socket_id, hyper_th_id;
+
+       if (parse_pipeline_core(&socket_id,
+                       &core_id,
+                       &hyper_th_id,
+                       params->t_id_string) != 0) {
+               printf("Command failed\n");
+               return;
+       }
+
+       status = app_thread_headroom(app,
+                       socket_id,
+                       core_id,
+                       hyper_th_id);
+
+       if (status != 0)
+               printf("Command failed\n");
+}
+
+cmdline_parse_token_string_t cmd_thread_headroom_t_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_thread_headroom_result,
+       t_string, "t");
+
+cmdline_parse_token_string_t cmd_thread_headroom_t_id_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_thread_headroom_result,
+       t_id_string, NULL);
+
+cmdline_parse_token_string_t cmd_thread_headroom_headroom_string =
+       TOKEN_STRING_INITIALIZER(struct cmd_thread_headroom_result,
+               headroom_string, "headroom");
+
+cmdline_parse_inst_t cmd_thread_headroom = {
+       .f = cmd_thread_headroom_parsed,
+       .data = NULL,
+       .help_str = "Display thread headroom",
+       .tokens = {
+               (void *)&cmd_thread_headroom_t_string,
+               (void *)&cmd_thread_headroom_t_id_string,
+               (void *)&cmd_thread_headroom_headroom_string,
+               NULL,
+       },
+};
+
+
+static cmdline_parse_ctx_t thread_cmds[] = {
+       (cmdline_parse_inst_t *) &cmd_pipeline_enable,
+       (cmdline_parse_inst_t *) &cmd_pipeline_disable,
+       (cmdline_parse_inst_t *) &cmd_thread_headroom,
+       NULL,
+};
+
+int
+app_pipeline_thread_cmd_push(struct app_params *app)
+{
+       uint32_t n_cmds, i;
+
+       /* Check for available slots in the application commands array */
+       n_cmds = RTE_DIM(thread_cmds) - 1;
+       if (n_cmds > APP_MAX_CMDS - app->n_cmds)
+               return -ENOMEM;
+
+       /* Push thread commands into the application */
+       memcpy(&app->cmds[app->n_cmds], thread_cmds,
+               n_cmds * sizeof(cmdline_parse_ctx_t));
+
+       for (i = 0; i < n_cmds; i++)
+               app->cmds[app->n_cmds + i]->data = app;
+
+       app->n_cmds += n_cmds;
+       app->cmds[app->n_cmds] = NULL;
+
+       return 0;
+}
diff --git a/common/vnf_common/thread_fe.h b/common/vnf_common/thread_fe.h
new file mode 100644 (file)
index 0000000..7499bff
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef THREAD_FE_H_
+#define THREAD_FE_H_
+
+static inline struct rte_ring *
+app_thread_msgq_in_get(struct app_params *app,
+               uint32_t socket_id, uint32_t core_id, uint32_t ht_id)
+{
+       char msgq_name[32];
+       ssize_t param_idx;
+
+       snprintf(msgq_name, sizeof(msgq_name),
+               "MSGQ-REQ-CORE-s%" PRIu32 "c%" PRIu32 "%s",
+               socket_id,
+               core_id,
+               (ht_id) ? "h" : "");
+       param_idx = APP_PARAM_FIND(app->msgq_params, msgq_name);
+
+       if (param_idx < 0)
+               return NULL;
+
+       return app->msgq[param_idx];
+}
+
+static inline struct rte_ring *
+app_thread_msgq_out_get(struct app_params *app,
+               uint32_t socket_id, uint32_t core_id, uint32_t ht_id)
+{
+       char msgq_name[32];
+       ssize_t param_idx;
+
+       snprintf(msgq_name, sizeof(msgq_name),
+               "MSGQ-RSP-CORE-s%" PRIu32 "c%" PRIu32 "%s",
+               socket_id,
+               core_id,
+               (ht_id) ? "h" : "");
+       param_idx = APP_PARAM_FIND(app->msgq_params, msgq_name);
+
+       if (param_idx < 0)
+               return NULL;
+
+       return app->msgq[param_idx];
+
+}
+
+int
+app_pipeline_thread_cmd_push(struct app_params *app);
+
+int
+app_pipeline_enable(struct app_params *app,
+               uint32_t core_id,
+               uint32_t socket_id,
+               uint32_t hyper_th_id,
+               uint32_t pipeline_id);
+
+int
+app_pipeline_disable(struct app_params *app,
+               uint32_t core_id,
+               uint32_t socket_id,
+               uint32_t hyper_th_id,
+               uint32_t pipeline_id);
+
+int
+app_thread_headroom(struct app_params *app,
+               uint32_t core_id,
+               uint32_t socket_id,
+               uint32_t hyper_th_id);
+
+#endif /* THREAD_FE_H_ */
diff --git a/common/vnf_common/vnf_common.c b/common/vnf_common/vnf_common.c
new file mode 100644 (file)
index 0000000..6ce815b
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <stdint.h>
+#include <stdio.h>
+#include "vnf_common.h"
+#include "pipeline_arpicmp_be.h"
+#ifndef VNF_ACL
+#include "lib_arp.h"
+#endif
+
+uint8_t in_port_dir_a[PIPELINE_MAX_PORT_IN];
+uint8_t prv_to_pub_map[PIPELINE_MAX_PORT_IN];
+uint8_t pub_to_prv_map[PIPELINE_MAX_PORT_IN];
+uint8_t prv_in_port_a[PIPELINE_MAX_PORT_IN];
+uint8_t prv_que_port_index[PIPELINE_MAX_PORT_IN];
+uint8_t in_port_egress_prv[PIPELINE_MAX_PORT_IN];
+
+uint8_t get_in_port_dir(uint8_t in_port_id)
+{
+       return in_port_dir_a[in_port_id];
+}
+
+uint8_t is_phy_port_privte(uint16_t phy_port)
+{
+       return in_port_dir_a[phy_port];
+}
+
+uint8_t is_port_index_privte(uint16_t phy_port)
+{
+       return in_port_egress_prv[phy_port];
+}
+
+uint32_t get_prv_to_pub_port(uint32_t *ip_addr, uint8_t type)
+{
+       uint32_t dest_if = 0xff;
+
+       switch (type) {
+       case 4:
+       {
+               uint32_t nhip;
+               nhip = get_nh(ip_addr[0], &dest_if);
+
+               if (nhip)
+                       return dest_if;
+               return 0xff;
+       }
+       break;
+       case 6:
+       {
+               uint8_t nhipv6[16];
+               get_nh_ipv6((uint8_t *)ip_addr, &dest_if, &nhipv6[0]);
+               if (dest_if != 0xff)
+                       return dest_if;
+               return 0xff;
+       }
+       break;
+       }
+       return 0xff;
+}
+
+uint32_t get_pub_to_prv_port(uint32_t *ip_addr, uint8_t type)
+{
+       uint32_t dest_if = 0xff;
+
+       switch (type) {
+       case 4:
+       {
+               uint32_t nhip;
+               nhip = get_nh(ip_addr[0], &dest_if);
+
+               if (nhip)
+                       return dest_if;
+               return 0xff;
+       }
+       break;
+       case 6:
+       {
+               uint8_t nhipv6[16];
+               get_nh_ipv6((uint8_t *)ip_addr, &dest_if, &nhipv6[0]);
+               if (dest_if != 0xff)
+                       return dest_if;
+               return 0xff;
+       }
+       break;
+       }
+       return 0xff;
+}
+
+void show_ports_info(void)
+{
+       printf("\nin_port_dir_a: %d %d %d %d %d", in_port_dir_a[0],
+       in_port_dir_a[1], in_port_dir_a[2], in_port_dir_a[3],
+       in_port_dir_a[4]);
+
+       uint8_t i = 0, j = 0;
+
+       printf("\nprv_to_pub_map: ");
+       for (i = 0; i < PIPELINE_MAX_PORT_IN; i++) {
+               if (prv_to_pub_map[i] != 0xff)
+                       printf("(%d,%d)  ", i, prv_to_pub_map[i]);
+       }
+
+       printf("\npub_to_prv_map: ");
+       for (i = 0; i < PIPELINE_MAX_PORT_IN; i++) {
+               if (pub_to_prv_map[i] != 0xff)
+                       printf("(%d,%d)  ", i, pub_to_prv_map[i]);
+       }
+
+       printf("\n%d entries in Ports MAC List\n", link_hw_addr_array_idx);
+       for (j = 0; j < link_hw_addr_array_idx; j++) {
+               struct ether_addr *link_hw_addr = get_link_hw_addr(j);
+
+               for (i = 0; i < 6; i++)
+                       printf(" %02x ", ((struct ether_addr *)link_hw_addr)->addr_bytes[i]);
+               printf("\n");
+       }
+}
+
+void trim(char *input)
+{
+       int i, j = 0;
+       int len = strlen(input);
+       char result[len + 1];
+
+       memset(result, 0, sizeof(result));
+       for (i = 0; input[i] != '\0'; i++) {
+               if (!isspace(input[i]))
+                       result[j++] = input[i];
+       }
+
+       strncpy(input, result, len);
+}
diff --git a/common/vnf_common/vnf_common.h b/common/vnf_common/vnf_common.h
new file mode 100644 (file)
index 0000000..a6b1aaa
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef __INCLUDE_VNF_COMMON_H__
+#define __INCLUDE_VNF_COMMON_H__
+
+#include <rte_pipeline.h>
+#include <rte_ether.h>
+
+#define MBUF_HDR_ROOM 256
+#define ETH_HDR_SIZE  14
+#define IP_HDR_SRC_ADR_OFST 12
+#define IP_HDR_DST_ADR_OFST 16
+#define IP_HDR_PROTOCOL_OFST 9
+#define IP_HDR_SIZE  20
+#define IPV6_HDR_SRC_ADR_OFST 8
+#define IPV6_HDR_DST_ADR_OFST 24
+#define IPV6_HDR_PROTOCOL_OFST 6
+#define IPV6_HDR_SIZE  40
+
+#define ETH_TYPE_ARP     0x0806
+#define ETH_TYPE_IPV4    0x0800
+
+#define IP_PROTOCOL_ICMP 1
+#define IP_PROTOCOL_TCP  6
+#define IP_PROTOCOL_UDP  17
+
+#define ETH_TYPE_IPV6    0x86DD
+#define IP_PROTOCOL_ICMPV6 58
+
+#define PKT_ING_DIR 0
+#define PKT_EGR_DIR 1
+
+#ifndef PIPELINE_MAX_PORT_IN
+#define PIPELINE_MAX_PORT_IN 16
+#endif
+
+#define RTE_PIPELINE_MAX_NAME_SZ 124
+
+#define INVALID_DESTIF 255
+
+enum {
+       VNF_PRV_PORT_ID,
+       VNF_PUB_PORT_ID,
+};
+void show_ports_info(void);
+void trim(char *input);
+uint8_t get_in_port_dir(uint8_t in_port_id);
+uint8_t is_phy_port_privte(uint16_t phy_port);
+uint32_t get_prv_to_pub_port(uint32_t *ip_addr, uint8_t type);
+uint32_t get_pub_to_prv_port(uint32_t *ip_addr, uint8_t type);
+
+static inline void drop_pkt(uint32_t pkt_num, uint64_t *mask)
+{
+       *mask ^= 1LLU << pkt_num;
+}
+
+extern uint8_t in_port_dir_a[PIPELINE_MAX_PORT_IN];
+extern uint8_t prv_to_pub_map[PIPELINE_MAX_PORT_IN];
+extern uint8_t pub_to_prv_map[PIPELINE_MAX_PORT_IN];
+extern uint8_t prv_in_port_a[PIPELINE_MAX_PORT_IN];
+
+extern uint32_t link_hw_addr_array_idx;
+
+struct rte_port_in {
+       /* Input parameters */
+       struct rte_port_in_ops ops;
+       rte_pipeline_port_in_action_handler f_action;
+       void *arg_ah;
+       uint32_t burst_size;
+
+       /* The table to which this port is connected */
+       uint32_t table_id;
+
+       /* Handle to low-level port */
+       void *h_port;
+
+       /* List of enabled ports */
+       struct rte_port_in *next;
+
+       /* Statistics */
+       uint64_t n_pkts_dropped_by_ah;
+};
+
+struct rte_port_out {
+       /* Input parameters */
+       struct rte_port_out_ops ops;
+       rte_pipeline_port_out_action_handler f_action;
+       void *arg_ah;
+
+       /* Handle to low-level port */
+       void *h_port;
+
+       /* Statistics */
+       uint64_t n_pkts_dropped_by_ah;
+};
+
+struct rte_table {
+       /* Input parameters */
+       struct rte_table_ops ops;
+       rte_pipeline_table_action_handler_hit f_action_hit;
+       rte_pipeline_table_action_handler_miss f_action_miss;
+       void *arg_ah;
+       struct rte_pipeline_table_entry *default_entry;
+       uint32_t entry_size;
+
+       uint32_t table_next_id;
+       uint32_t table_next_id_valid;
+
+       /* Handle to the low-level table object */
+       void *h_table;
+
+       /* Statistics */
+       uint64_t n_pkts_dropped_by_lkp_hit_ah;
+       uint64_t n_pkts_dropped_by_lkp_miss_ah;
+       uint64_t n_pkts_dropped_lkp_hit;
+       uint64_t n_pkts_dropped_lkp_miss;
+};
+
+
+struct rte_pipeline {
+       /* Input parameters */
+       char name[RTE_PIPELINE_MAX_NAME_SZ];
+       int socket_id;
+       uint32_t offset_port_id;
+
+       /* Internal tables */
+       struct rte_port_in ports_in[RTE_PIPELINE_PORT_IN_MAX];
+       struct rte_port_out ports_out[RTE_PIPELINE_PORT_OUT_MAX];
+       struct rte_table tables[RTE_PIPELINE_TABLE_MAX];
+
+       /* Occupancy of internal tables */
+       uint32_t num_ports_in;
+       uint32_t num_ports_out;
+       uint32_t num_tables;
+
+       /* List of enabled ports */
+       uint64_t enabled_port_in_mask;
+       struct rte_port_in *port_in_next;
+
+       /* Pipeline run structures */
+       struct rte_mbuf *pkts[RTE_PORT_IN_BURST_SIZE_MAX];
+       struct rte_pipeline_table_entry *entries[RTE_PORT_IN_BURST_SIZE_MAX];
+       uint64_t action_mask0[RTE_PIPELINE_ACTIONS];
+       uint64_t action_mask1[RTE_PIPELINE_ACTIONS];
+       uint64_t pkts_mask;
+       uint64_t n_pkts_ah_drop;
+       uint64_t pkts_drop_mask;
+} __rte_cache_aligned;
+
+/* RTE_ DPDK LIB structures to get HWQ & SWQ info */
+struct rte_port_ethdev_writer {
+        struct rte_port_out_stats stats;
+
+        struct rte_mbuf *tx_buf[2 * RTE_PORT_IN_BURST_SIZE_MAX];
+        uint32_t tx_burst_sz;
+        uint16_t tx_buf_count;
+        uint64_t bsz_mask;
+        uint16_t queue_id;
+        uint8_t port_id;
+};
+struct rte_port_ethdev_reader {
+        struct rte_port_in_stats stats;
+
+        uint16_t queue_id;
+        uint8_t port_id;
+};
+struct rte_port_ring_writer {
+        struct rte_port_out_stats stats;
+
+        struct rte_mbuf *tx_buf[2 * RTE_PORT_IN_BURST_SIZE_MAX];
+        struct rte_ring *ring;
+        uint32_t tx_burst_sz;
+        uint32_t tx_buf_count;
+        uint64_t bsz_mask;
+        uint32_t is_multi;
+};
+struct rte_port_ring_reader {
+        struct rte_port_in_stats stats;
+
+        struct rte_ring *ring;
+};
+
+uint8_t get_in_port_dir(uint8_t in_port_id);
+uint8_t is_phy_port_privte(uint16_t phy_port);
+uint8_t is_port_index_privte(uint16_t phy_port);
+#endif
diff --git a/common/vnf_common/vnf_define.h b/common/vnf_common/vnf_define.h
new file mode 100644 (file)
index 0000000..380ada5
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef __INCLUDE_VNF_DEFINE_H__
+#define __INCLUDE_VNF_DEFINE_H__
+#define DEBUG_LEVEL_4 4
+#define PKT_BUFFER_SIZE 64
+#define PVT_PUB_MAP 2
+#define IPV6_ADD_SIZE 16
+#define TWO_BYTE_PRINT 3
+#define VERSION_NO_BYTE 4
+#define BIT_CARRY 16
+#define HW_ADDR_SIZE 20
+#define IPV6_ADD_CMP_MULTI 13
+#define DIV_CONV_HZ_SEC 1000
+#endif