From 51cd08d9a3f2826088d122e2a5683315c77a2786 Mon Sep 17 00:00:00 2001 From: Vishwesh M Rudramuni Date: Tue, 18 Apr 2017 19:41:40 +0530 Subject: 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 [Push patch to gerrit] Signed-off-by: Deepak S --- common/VIL/pipeline_arpicmp/pipeline_arpicmp_be.c | 3484 +++++++++++++++++++++ 1 file changed, 3484 insertions(+) create mode 100644 common/VIL/pipeline_arpicmp/pipeline_arpicmp_be.c (limited to 'common/VIL/pipeline_arpicmp/pipeline_arpicmp_be.c') 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 + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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, ð_h->d_addr); + ether_addr_copy((struct ether_addr *) + &arp_port_addresses[port_id].mac_addr, ð_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, ð_h->d_addr); + ether_addr_copy((struct ether_addr *) + &arp_port_addresses[port_id].mac_addr, ð_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(ð_h->s_addr, ð_h->d_addr); + + // set sender mac address - + ether_addr_copy((struct ether_addr *)& + arp_port_addresses[in_port_id].mac_addr, + ð_h->s_addr); + + arp_h->arp_op = rte_cpu_to_be_16(ARP_OP_REPLY); + ether_addr_copy(ð_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(ð_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, ð_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(ð_h->s_addr, + ð_h->d_addr); + ether_addr_copy((struct ether_addr *) + &arp_port_addresses + [in_port_id].mac_addr, + ð_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, + ð_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(ð_h->s_addr, + ð_h->d_addr); + ether_addr_copy((struct ether_addr *) + &icmpv6_port_addresses + [in_port_id].mac_addr, + ð_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 = ð_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(ð_h->s_addr, + ð_h->d_addr); + ether_addr_copy((struct ether_addr *) + &icmpv6_port_addresses + [in_port_id].mac_addr, + ð_h->s_addr); + + // set sender mac address + ether_addr_copy(ð_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 = ð_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, ð_h->d_addr); + ether_addr_copy((struct ether_addr *)&icmpv6_port_addresses[port_id]. + mac_addr, ð_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(¶ms-> + port_in[i]), + .arg_create = + pipeline_port_in_params_convert(¶ms-> + 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(¶ms-> + port_out[i]), + .arg_create = + pipeline_port_out_params_convert(¶ms-> + 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, +}; -- cgit 1.2.3-korg