summaryrefslogtreecommitdiffstats
path: root/common/VIL
diff options
context:
space:
mode:
authorVishwesh M Rudramuni <vishweshmr@gmail.com>2017-04-18 19:41:40 +0530
committerDeepak S <deepak.s@linux.intel.com>2017-04-18 02:59:07 -0700
commit51cd08d9a3f2826088d122e2a5683315c77a2786 (patch)
tree3fac17a8f7bf362f0c77f1003615b2063d900d35 /common/VIL
parent03aef84e240c5be8813634735d825420129f1460 (diff)
common: Adding common library for sample vnf
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>
Diffstat (limited to 'common/VIL')
-rw-r--r--common/VIL/acl/lib_acl.c1203
-rw-r--r--common/VIL/acl/lib_acl.h127
-rw-r--r--common/VIL/alg/lib_ftp_alg.c917
-rw-r--r--common/VIL/alg/lib_ftp_alg.h102
-rw-r--r--common/VIL/alg/lib_sip_alg.c2257
-rw-r--r--common/VIL/alg/lib_sip_alg.h156
-rw-r--r--common/VIL/conntrack/rte_cnxn_tracking.c1804
-rw-r--r--common/VIL/conntrack/rte_cnxn_tracking.h413
-rw-r--r--common/VIL/conntrack/rte_ct_synproxy.c873
-rw-r--r--common/VIL/conntrack/rte_ct_tcp.c1116
-rw-r--r--common/VIL/conntrack/rte_ct_tcp.h484
-rw-r--r--common/VIL/conntrack/rte_ct_udp.c49
-rw-r--r--common/VIL/l2l3_stack/Makefile35
-rw-r--r--common/VIL/l2l3_stack/bond.c1595
-rw-r--r--common/VIL/l2l3_stack/build/.interface.o.d180
-rw-r--r--common/VIL/l2l3_stack/build/.l2_proto.o.d175
-rw-r--r--common/VIL/l2l3_stack/build/.main.o.d209
-rw-r--r--common/VIL/l2l3_stack/hle.c43
-rw-r--r--common/VIL/l2l3_stack/hle.h40
-rw-r--r--common/VIL/l2l3_stack/interface.c1478
-rw-r--r--common/VIL/l2l3_stack/interface.h873
-rw-r--r--common/VIL/l2l3_stack/l2_proto.c239
-rw-r--r--common/VIL/l2l3_stack/l2_proto.h150
-rw-r--r--common/VIL/l2l3_stack/l3fwd_common.h111
-rw-r--r--common/VIL/l2l3_stack/l3fwd_lpm4.c1119
-rw-r--r--common/VIL/l2l3_stack/l3fwd_lpm4.h374
-rw-r--r--common/VIL/l2l3_stack/l3fwd_lpm6.c1058
-rw-r--r--common/VIL/l2l3_stack/l3fwd_lpm6.h315
-rw-r--r--common/VIL/l2l3_stack/l3fwd_main.c145
-rw-r--r--common/VIL/l2l3_stack/lib_arp.c2655
-rw-r--r--common/VIL/l2l3_stack/lib_arp.h506
-rw-r--r--common/VIL/l2l3_stack/lib_icmpv6.c410
-rw-r--r--common/VIL/l2l3_stack/lib_icmpv6.h113
-rw-r--r--common/VIL/l2l3_stack/main_l2l3.c304
-rw-r--r--common/VIL/l2l3_stack/tsx.c167
-rw-r--r--common/VIL/l2l3_stack/tsx.h38
-rw-r--r--common/VIL/pipeline_arpicmp/pipeline_arpicmp.c2118
-rw-r--r--common/VIL/pipeline_arpicmp/pipeline_arpicmp.h122
-rw-r--r--common/VIL/pipeline_arpicmp/pipeline_arpicmp_be.c3484
-rw-r--r--common/VIL/pipeline_arpicmp/pipeline_arpicmp_be.h343
-rw-r--r--common/VIL/pipeline_common/pipeline_common_be.c189
-rw-r--r--common/VIL/pipeline_common/pipeline_common_be.h146
-rw-r--r--common/VIL/pipeline_common/pipeline_common_fe.c1429
-rw-r--r--common/VIL/pipeline_common/pipeline_common_fe.h231
-rw-r--r--common/VIL/pipeline_loadb/pipeline_loadb.c493
-rw-r--r--common/VIL/pipeline_loadb/pipeline_loadb.h29
-rw-r--r--common/VIL/pipeline_loadb/pipeline_loadb_be.c1417
-rw-r--r--common/VIL/pipeline_loadb/pipeline_loadb_be.h149
-rw-r--r--common/VIL/pipeline_master/pipeline_master.c30
-rw-r--r--common/VIL/pipeline_master/pipeline_master.h24
-rw-r--r--common/VIL/pipeline_master/pipeline_master_be.c134
-rw-r--r--common/VIL/pipeline_master/pipeline_master_be.h24
-rw-r--r--common/VIL/pipeline_passthrough/pipeline_passthrough.c30
-rw-r--r--common/VIL/pipeline_passthrough/pipeline_passthrough.h24
-rw-r--r--common/VIL/pipeline_passthrough/pipeline_passthrough_be.c787
-rw-r--r--common/VIL/pipeline_passthrough/pipeline_passthrough_be.h42
-rw-r--r--common/VIL/pipeline_txrx/pipeline_txrx.c151
-rw-r--r--common/VIL/pipeline_txrx/pipeline_txrx.h28
-rw-r--r--common/VIL/pipeline_txrx/pipeline_txrx_be.c915
-rw-r--r--common/VIL/pipeline_txrx/pipeline_txrx_be.h76
60 files changed, 34248 insertions, 0 deletions
diff --git a/common/VIL/acl/lib_acl.c b/common/VIL/acl/lib_acl.c
new file mode 100644
index 00000000..279727ef
--- /dev/null
+++ b/common/VIL/acl/lib_acl.c
@@ -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
index 00000000..6eaaf55f
--- /dev/null
+++ b/common/VIL/acl/lib_acl.h
@@ -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
index 00000000..0a8a0e6d
--- /dev/null
+++ b/common/VIL/alg/lib_ftp_alg.c
@@ -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
index 00000000..875d6276
--- /dev/null
+++ b/common/VIL/alg/lib_ftp_alg.h
@@ -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
index 00000000..9940d59a
--- /dev/null
+++ b/common/VIL/alg/lib_sip_alg.c
@@ -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
index 00000000..b320a4f4
--- /dev/null
+++ b/common/VIL/alg/lib_sip_alg.h
@@ -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
index 00000000..461ed422
--- /dev/null
+++ b/common/VIL/conntrack/rte_cnxn_tracking.c
@@ -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
index 00000000..1efb60ef
--- /dev/null
+++ b/common/VIL/conntrack/rte_cnxn_tracking.h
@@ -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
index 00000000..967596d1
--- /dev/null
+++ b/common/VIL/conntrack/rte_ct_synproxy.c
@@ -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
index 00000000..073c63ed
--- /dev/null
+++ b/common/VIL/conntrack/rte_ct_tcp.c
@@ -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
index 00000000..391200c6
--- /dev/null
+++ b/common/VIL/conntrack/rte_ct_tcp.h
@@ -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
index 00000000..88f3a9a4
--- /dev/null
+++ b/common/VIL/conntrack/rte_ct_udp.c
@@ -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
index 00000000..b85bf1d4
--- /dev/null
+++ b/common/VIL/l2l3_stack/Makefile
@@ -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
index 00000000..8fd11712
--- /dev/null
+++ b/common/VIL/l2l3_stack/bond.c
@@ -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
index 00000000..582958f4
--- /dev/null
+++ b/common/VIL/l2l3_stack/build/.interface.o.d
@@ -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
index 00000000..13bcf504
--- /dev/null
+++ b/common/VIL/l2l3_stack/build/.l2_proto.o.d
@@ -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
index 00000000..9d27accd
--- /dev/null
+++ b/common/VIL/l2l3_stack/build/.main.o.d
@@ -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
index 00000000..a0661b32
--- /dev/null
+++ b/common/VIL/l2l3_stack/hle.c
@@ -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
index 00000000..21da710d
--- /dev/null
+++ b/common/VIL/l2l3_stack/hle.h
@@ -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
index 00000000..84c390da
--- /dev/null
+++ b/common/VIL/l2l3_stack/interface.c
@@ -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
index 00000000..0f654fa1
--- /dev/null
+++ b/common/VIL/l2l3_stack/interface.h
@@ -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
index 00000000..44c50b08
--- /dev/null
+++ b/common/VIL/l2l3_stack/l2_proto.c
@@ -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
index 00000000..05466070
--- /dev/null
+++ b/common/VIL/l2l3_stack/l2_proto.h
@@ -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
index 00000000..cece57c0
--- /dev/null
+++ b/common/VIL/l2l3_stack/l3fwd_common.h
@@ -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
index 00000000..081038b6
--- /dev/null
+++ b/common/VIL/l2l3_stack/l3fwd_lpm4.c
@@ -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
index 00000000..69e62368
--- /dev/null
+++ b/common/VIL/l2l3_stack/l3fwd_lpm4.h
@@ -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
index 00000000..7aa7fb6a
--- /dev/null
+++ b/common/VIL/l2l3_stack/l3fwd_lpm6.c
@@ -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
index 00000000..fdd8287a
--- /dev/null
+++ b/common/VIL/l2l3_stack/l3fwd_lpm6.h
@@ -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
index 00000000..247d8876
--- /dev/null
+++ b/common/VIL/l2l3_stack/l3fwd_main.c
@@ -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
index 00000000..042dd39c
--- /dev/null
+++ b/common/VIL/l2l3_stack/lib_arp.c
@@ -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
index 00000000..33875679
--- /dev/null
+++ b/common/VIL/l2l3_stack/lib_arp.h
@@ -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
index 00000000..44f30cbf
--- /dev/null
+++ b/common/VIL/l2l3_stack/lib_icmpv6.c
@@ -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
index 00000000..e9ccca14
--- /dev/null
+++ b/common/VIL/l2l3_stack/lib_icmpv6.h
@@ -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
index 00000000..08c97641
--- /dev/null
+++ b/common/VIL/l2l3_stack/main_l2l3.c
@@ -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
index 00000000..a361c945
--- /dev/null
+++ b/common/VIL/l2l3_stack/tsx.c
@@ -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
index 00000000..8b748165
--- /dev/null
+++ b/common/VIL/l2l3_stack/tsx.h
@@ -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
index 00000000..1ea9e749
--- /dev/null
+++ b/common/VIL/pipeline_arpicmp/pipeline_arpicmp.c
@@ -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
index 00000000..1efb14e2
--- /dev/null
+++ b/common/VIL/pipeline_arpicmp/pipeline_arpicmp.h
@@ -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
index 00000000..7238bd1d
--- /dev/null
+++ b/common/VIL/pipeline_arpicmp/pipeline_arpicmp_be.c
@@ -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
index 00000000..2c7fce2e
--- /dev/null
+++ b/common/VIL/pipeline_arpicmp/pipeline_arpicmp_be.h
@@ -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
index 00000000..66e2c5bc
--- /dev/null
+++ b/common/VIL/pipeline_common/pipeline_common_be.c
@@ -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
index 00000000..f3e937e6
--- /dev/null
+++ b/common/VIL/pipeline_common/pipeline_common_be.h
@@ -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
index 00000000..5df29779
--- /dev/null
+++ b/common/VIL/pipeline_common/pipeline_common_fe.c
@@ -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
index 00000000..fd53cc1d
--- /dev/null
+++ b/common/VIL/pipeline_common/pipeline_common_fe.h
@@ -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
index 00000000..fdcc17ae
--- /dev/null
+++ b/common/VIL/pipeline_loadb/pipeline_loadb.c
@@ -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
index 00000000..866a6eab
--- /dev/null
+++ b/common/VIL/pipeline_loadb/pipeline_loadb.h
@@ -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
index 00000000..c7910127
--- /dev/null
+++ b/common/VIL/pipeline_loadb/pipeline_loadb_be.c
@@ -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
index 00000000..a948f4cb
--- /dev/null
+++ b/common/VIL/pipeline_loadb/pipeline_loadb_be.h
@@ -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
index 00000000..bfab32ac
--- /dev/null
+++ b/common/VIL/pipeline_master/pipeline_master.c
@@ -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
index 00000000..d39afb5f
--- /dev/null
+++ b/common/VIL/pipeline_master/pipeline_master.h
@@ -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
index 00000000..425e2334
--- /dev/null
+++ b/common/VIL/pipeline_master/pipeline_master_be.c
@@ -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
index 00000000..fceb6849
--- /dev/null
+++ b/common/VIL/pipeline_master/pipeline_master_be.h
@@ -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
index 00000000..0463f8ef
--- /dev/null
+++ b/common/VIL/pipeline_passthrough/pipeline_passthrough.c
@@ -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
index 00000000..9b650eb4
--- /dev/null
+++ b/common/VIL/pipeline_passthrough/pipeline_passthrough.h
@@ -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
index 00000000..5b74d75b
--- /dev/null
+++ b/common/VIL/pipeline_passthrough/pipeline_passthrough_be.c
@@ -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
index 00000000..442734f6
--- /dev/null
+++ b/common/VIL/pipeline_passthrough/pipeline_passthrough_be.h
@@ -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
index 00000000..c1fc075f
--- /dev/null
+++ b/common/VIL/pipeline_txrx/pipeline_txrx.c
@@ -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
index 00000000..99069246
--- /dev/null
+++ b/common/VIL/pipeline_txrx/pipeline_txrx.h
@@ -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
index 00000000..9e7645dd
--- /dev/null
+++ b/common/VIL/pipeline_txrx/pipeline_txrx_be.c
@@ -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
index 00000000..f794729e
--- /dev/null
+++ b/common/VIL/pipeline_txrx/pipeline_txrx_be.h
@@ -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