From f0bfb2b0c8467154990b49beafb991b7515e37e3 Mon Sep 17 00:00:00 2001 From: Deepak S Date: Mon, 17 Apr 2017 23:03:43 -0700 Subject: vCGNAPT VNF initial check-in MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit JIRA: SAMPLEVNF-5 The vCGNAPT implementation contains following features: • Static and dynamic Network address translation. • Static and dynamic Network address and port translation • ARP (request, response, gratuitous) • ICMP (terminal echo, echo response, pass-through) • ICMPv6 and ND • UDP, TCP and ICMP protocol pass-through • Multithread support and Multiple physical port support • Limiting max ports per client • Limiting max clients per public IP address • Live Session tracking to NAT flow • NAT64 – connectivity between IPv6 access network to IPv4 data • PCP - Port Control protocol • SIP functionality • FTP functionality Change-Id: I5ebb44ae60e32dd6da5e793efd91a6831a4d30a7 Signed-off-by: Deepak S --- VNFs/vCGNAPT/pipeline/pipeline_cgnapt_be.c | 10963 +++++++++++++++++++++++++++ 1 file changed, 10963 insertions(+) create mode 100644 VNFs/vCGNAPT/pipeline/pipeline_cgnapt_be.c (limited to 'VNFs/vCGNAPT/pipeline/pipeline_cgnapt_be.c') diff --git a/VNFs/vCGNAPT/pipeline/pipeline_cgnapt_be.c b/VNFs/vCGNAPT/pipeline/pipeline_cgnapt_be.c new file mode 100644 index 00000000..9a05a4da --- /dev/null +++ b/VNFs/vCGNAPT/pipeline/pipeline_cgnapt_be.c @@ -0,0 +1,10963 @@ +/* +// 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 + * Pipeline CG-NAPT BE Implementation. + * + * Implementation of Pipeline CG-NAPT Back End (BE). + * Provides NAPT service on dataplane packets. + * Runs on a core as defined in the config file. + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pipeline_cgnapt_be.h" +#include "pipeline_cgnapt_common.h" +#include "pipeline_actions_common.h" +#include "hash_func.h" +#include "pipeline_arpicmp_be.h" +#include "vnf_common.h" +#include "app.h" +#include "pipeline_common_be.h" +#include "vnf_common.h" +#include "lib_sip_alg.h" +#include "lib_icmpv6.h" + +#include "pipeline_common_fe.h" +#ifdef CT_CGNAT +#include "rte_ct_tcp.h" +#include "rte_cnxn_tracking.h" +#endif +#ifdef FTP_ALG +#include "lib_ftp_alg.h" +#endif +#ifdef PCP_ENABLE +#include "cgnapt_pcp_be.h" +#endif + +/* To maintain all cgnapt pipeline pointers used for all stats */ +struct pipeline_cgnapt *all_pipeline_cgnapt[128]; +uint8_t n_cgnapt_pipeline; + +/* To know egress or ingress port */ +static uint8_t cgnapt_in_port_egress_prv[PIPELINE_MAX_PORT_IN]; +static uint8_t cgnapt_prv_que_port_index[PIPELINE_MAX_PORT_IN]; + +/* Max port per client declarations */ + +struct rte_hash_parameters max_port_per_client_hash_params = { + .name = "MAX_PORT_PER_CLIENT", + .entries = MAX_DYN_ENTRY, + .key_len = sizeof(struct max_port_per_client_key), + .hash_func = rte_jhash, + .hash_func_init_val = 0, +}; +#ifdef CT_CGNAT +struct rte_ct_cnxn_tracker *cgnat_cnxn_tracker; +#endif + +/***** Common Port Allocation declarations *****/ + +struct rte_ring *port_alloc_ring[MAX_CGNAPT_SETS] = { NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL }; +const char *napt_port_alloc_ring_name[MAX_CGNAPT_SETS] = { + "NAPT_PORT_ALLOC_0 ", + "NAPT_PORT_ALLOC_1 ", + "NAPT_PORT_ALLOC_2 ", + "NAPT_PORT_ALLOC_3 ", + "NAPT_PORT_ALLOC_4 ", + "NAPT_PORT_ALLOC_5 ", + "NAPT_PORT_ALLOC_6 ", + "NAPT_PORT_ALLOC_7 " +}; + +int vnf_set_count = -1; + +struct app_params *myApp; + +/***** Common Port Allocation declarations *****/ +int napt_port_alloc_elem_count; + +/***** Common Table declarations *****/ +struct rte_hash_parameters napt_common_table_hash_params = { + .name = "NAPT_COM_TBL", + .entries = MAX_NAPT_ENTRIES, + .key_len = sizeof(struct pipeline_cgnapt_entry_key), + .hash_func = rte_jhash, + .hash_func_init_val = 0, + .extra_flag = 1, +}; + +/***** ARP local cache *****/ +uint8_t link_hw_laddr_valid[MAX_NUM_LOCAL_MAC_ADDRESS] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +struct ether_addr link_hw_laddr[MAX_NUM_LOCAL_MAC_ADDRESS] = { + {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, + {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, + {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, + {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, + {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, + {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, + {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, + {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, + {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, + {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, + {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, + {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, + {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, + {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, + {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, + {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} } +}; + +/****** NAT64 declarations *****/ + +uint8_t well_known_prefix[16] = { + 0x00, 0x64, 0xff, 0x9b, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 +}; + +static uint32_t local_get_nh_ipv4( + uint32_t ip, + uint32_t *port, + uint32_t *nhip, + struct pipeline_cgnapt *p_nat); + +static void do_local_nh_ipv4_cache( + uint32_t dest_if, + struct pipeline_cgnapt *p_nat); + +static uint32_t local_get_nh_ipv6( + uint8_t *ip, + uint32_t *port, + uint8_t nhip[], + struct pipeline_cgnapt *p_nat); + +static void do_local_nh_ipv6_cache( + uint32_t dest_if, + struct pipeline_cgnapt *p_nat); + +static uint8_t check_arp_icmp( + struct rte_mbuf *pkt, + uint64_t pkt_mask, + struct pipeline_cgnapt *p_nat); + +/* Finds next power of two for n. If n itself + * is a power of two then returns n + * + * @param n + * Value usually 32-bit value + * + * @return + * Value after roundup to power of 2 +*/ +uint64_t nextPowerOf2(uint64_t n) +{ + n--; + n |= n >> 1; + n |= n >> 2; + n |= n >> 4; + n |= n >> 8; + n |= n >> 16; + n |= n >> 32; + n++; + return n; +} + +/** + * Function to get MAC addr of local link + * + * @params out_port + * Physical port number + * + * @return + * Outport Link MAC addr + */ + +struct ether_addr *get_local_link_hw_addr(uint8_t out_port) +{ + return &link_hw_laddr[out_port]; +} + +/** + * Function to get MAC addr from array instead of hash table + * + * @params out_port + * Physical port number + * + * @return + * Outport Link MAC addr + */ + +uint8_t local_dest_mac_present(uint8_t out_port) +{ + return link_hw_laddr_valid[out_port]; +} + +/** + * Function to get IPv4-IP NH from thread local array + * + * @params ip + * IPv4 - IP + * @params port + * NH port number + * @params nhip + * NHIP of IPv4 type + * @params p_nat + * CGNAPT pipeline ptr + * + * @return + * 1 on success, 0 for failure + */ + +static uint32_t local_get_nh_ipv4( + uint32_t ip, + uint32_t *port, + uint32_t *nhip, + struct pipeline_cgnapt *p_nat) +{ + int i; + for (i = 0; i < p_nat->local_lib_arp_route_ent_cnt; i++) { + if (((p_nat->local_lib_arp_route_table[i].ip & + p_nat->local_lib_arp_route_table[i].mask) == + (ip & p_nat->local_lib_arp_route_table[i].mask))) { + *port = p_nat->local_lib_arp_route_table[i].port; + + *nhip = p_nat->local_lib_arp_route_table[i].nh; + return 1; + } + } + return 0; +} + +/** + * Function to make local copy for NH of type IPv4 + * + * @params dest_if + * Physical port number + * @params p_nat + * CGNAPT pipeline ptr + * + */ + +static void do_local_nh_ipv4_cache( + uint32_t dest_if, + struct pipeline_cgnapt *p_nat) +{ + + /* Search for the entry and do local copy */ + int i; + + for (i = 0; i < MAX_ARP_RT_ENTRY; i++) { + if (lib_arp_route_table[i].port == dest_if) { + + struct lib_arp_route_table_entry *lentry = + &p_nat->local_lib_arp_route_table + [p_nat->local_lib_arp_route_ent_cnt]; + + lentry->ip = lib_arp_route_table[i].ip; + lentry->mask = lib_arp_route_table[i].mask; + lentry->port = lib_arp_route_table[i].port; + lentry->nh = lib_arp_route_table[i].nh; + + p_nat->local_lib_arp_route_ent_cnt++; + break; + } + } +} + + +/** + * Function to get IPv6-IP NH from thread local array + * + * @params ip + * Pointer to starting addr of IPv6 + * @params port + * NH port number + * @params nhip + * NHIP of IPv6 type + * @params p_nat + * CGNAPT pipeline ptr + * + * @return + * 1 on success, 0 for failure + */ + +static uint32_t local_get_nh_ipv6( + uint8_t *ip, + uint32_t *port, + uint8_t nhip[], + struct pipeline_cgnapt *p_nat) +{ + int i = 0; + uint8_t netmask_ipv6[16]; + uint8_t k = 0, l = 0, depthflags = 0, depthflags1 = 0; + + for (i = 0; i < p_nat->local_lib_nd_route_ent_cnt; i++) { + + convert_prefixlen_to_netmask_ipv6( + p_nat->local_lib_nd_route_table[i].depth, + netmask_ipv6); + + for (k = 0; k < 16; k++) + if (p_nat->local_lib_nd_route_table[i].ipv6[k] & + netmask_ipv6[k]) + depthflags++; + + for (l = 0; l < 16; l++) + if (ip[l] & netmask_ipv6[l]) + depthflags1++; + + int j = 0; + if (depthflags == depthflags1) { + *port = p_nat->local_lib_nd_route_table[i].port; + + for (j = 0; j < 16; j++) + nhip[j] = p_nat->local_lib_nd_route_table[i]. + nhipv6[j]; + return 1; + } + + depthflags = 0; + depthflags1 = 0; + } + return 0; +} + + +/** + * Function to make local copy for NH of type IPv6 + * + * @params dest_if + * Physical port number + * @params p_nat + * CGNAPT pipeline ptr + * + */ + +static void do_local_nh_ipv6_cache( + uint32_t dest_if, + struct pipeline_cgnapt *p_nat) +{ + /* Search for the entry and do local copy */ + int i, l; + for (i = 0; i < MAX_ND_RT_ENTRY; i++) { + + if (lib_nd_route_table[i].port == dest_if) { + + struct lib_nd_route_table_entry *lentry = + &p_nat->local_lib_nd_route_table + [p_nat->local_lib_nd_route_ent_cnt]; + + for (l = 0; l < 16; l++) { + lentry->ipv6[l] = + lib_nd_route_table[i].ipv6[l]; + lentry->nhipv6[l] = + lib_nd_route_table[i].nhipv6[l]; + } + lentry->depth = lib_nd_route_table[i].depth; + lentry->port = lib_nd_route_table[i].port; + + p_nat->local_lib_nd_route_ent_cnt++; + break; + } //if + } //for +} + +#ifdef SIP_ALG +/* Commented code may be required for future usage, Please keep it*/ +#if 0 +static int retrieve_cgnapt_entry_alg( + struct pipeline_cgnapt_entry_key *key, + struct cgnapt_table_entry **entry_ptr1, + struct cgnapt_table_entry **entry_ptr2) +{ + #ifdef CGNAPT_DBG_PRNT + printf("retrieve_cgnapt_entry key detail Entry:" + "0x%x, %d, %d\n", key->ip, key->port, + key->pid); + #endif + + int position = rte_hash_lookup(napt_common_table, key); + if (position < 0) { + printf("Invalid cgnapt entry position(first_key): %d\n", + position); + return 0; + } + + *entry_ptr1 = &napt_hash_tbl_entries[position]; + + uint32_t prv_ip = (*entry_ptr1)->data.prv_ip; + uint32_t prv_port = (*entry_ptr1)->data.prv_port; + uint32_t prv_phy_port = (*entry_ptr1)->data.prv_phy_port; + + struct pipeline_cgnapt_entry_key second_key; + second_key.ip = prv_ip; + second_key.port = prv_port; + second_key.pid = prv_phy_port; + + position = rte_hash_lookup(napt_common_table, &second_key); + if (position < 0) { + printf("Invalid cgnapt entry position(second_key): %d\n", + position); + return 0; + } + + *entry_ptr2 = &napt_hash_tbl_entries[position]; + + return 1; +} +#endif + +int add_dynamic_cgnapt_entry_alg( + struct pipeline *p, + struct pipeline_cgnapt_entry_key *key, + struct cgnapt_table_entry **entry_ptr1, + struct cgnapt_table_entry **entry_ptr2) +{ + int port_num = 0, ret; + + struct pipeline_cgnapt *p_nat = (struct pipeline_cgnapt *)p; + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG >= 1) { + printf("Th%d add_dynamic_cgnapt_entry key detail Entry:" + "0x%x, %d, %d\n", p_nat->pipeline_num, key->ip, key->port, + key->pid); + } + #endif + + int32_t position = rte_hash_lookup(napt_common_table, key); + if (position >= 0) { + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG >= 1) { + printf("%s: cgnapt entry exists in " + "position(first_key): %d\n", __func__, position); + } + #endif + *entry_ptr1 = &napt_hash_tbl_entries[position]; + /* not required, as it is not used in the caller */ + *entry_ptr2 = NULL; + return 1; + } + + + ret = increment_max_port_counter(key->ip, key->pid, p_nat); + if (ret == MAX_PORT_INC_ERROR) { + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 1) + printf("add_dynamic_cgnapt_entry:" + "increment_max_port_counter-1 failed\n"); + #endif + + return 0; + } + + if (ret == MAX_PORT_INC_REACHED) { + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 1) + printf("add_dynamic_cgnapt_entry:" + "increment_max_port_counter-2 failed\n"); + #endif + + return 0; + } + + uint32_t public_ip; + port_num = get_free_iport(p_nat, &public_ip); + + if (port_num == -1) { + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 2) { + printf("add_dynamic_cgnapt_entry: %d\n", port_num); + printf("add_dynamic_cgnapt_entry key detail:0x%x, " + "%d, %d\n", key->ip, key->port, key->pid); + } + #endif + + return 0; + } + + /* check for max_clients_per_ip */ + if (rte_atomic16_read + (&all_public_ip + [rte_jhash(&public_ip, 4, 0) % 16].count) == + p_nat->max_clients_per_ip) { + /* For now just bail out + * In future we can think about + * retrying getting a new iport + */ + release_iport(port_num, public_ip, p_nat); + + return 0; + } + + rte_atomic16_inc(&all_public_ip + [rte_jhash(&public_ip, 4, 0) % + 16].count); + + #ifdef CGNAPT_DBG_PRNT + if ((rte_jhash(&public_ip, 4, 0) % 16) == 8) + printf("pub ip:%x coutn:%d\n", public_ip, + rte_atomic16_read(&all_public_ip + [rte_jhash(&public_ip, 4, 0) % 16].count)); + #endif + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 0) { + printf("add_dynamic_cgnapt_entry: %d\n", + port_num); + printf("add_dynamic_cgnapt_entry key detail: " + "0x%x, %d, %d\n", key->ip, key->port, key->pid); + } + #endif + + struct cgnapt_table_entry entry = { + .head = { + .action = RTE_PIPELINE_ACTION_PORT, + /* made it configurable below */ + {.port_id = p->port_out_id[0]}, + }, + + .data = { + .prv_port = key->port, + .pub_ip = public_ip, + .pub_port = port_num, + .prv_phy_port = key->pid, + .pub_phy_port = get_pub_to_prv_port( + &public_ip, + IP_VERSION_4), + .ttl = 0, + /* if(timeout == -1) : static entry + * if(timeout == 0 ) : dynamic entry + * if(timeout > 0 ) : PCP requested entry + */ + .timeout = 0, + #ifdef PCP_ENABLE + .timer = NULL, + #endif + } + }; + + entry.data.u.prv_ip = key->ip; + entry.data.type = CGNAPT_ENTRY_IPV4; + + entry.head.port_id = entry.data.pub_phy_port; /* outgoing port info */ + + struct pipeline_cgnapt_entry_key second_key; + /* Need to add a second ingress entry */ + second_key.ip = public_ip; + second_key.port = port_num; + second_key.pid = 0xffff; + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 2) + printf("add_dynamic_cgnapt_entry second key detail:" + "0x%x, %d, %d\n", second_key.ip, second_key.port, + second_key.pid); + #endif + + int32_t position1 = rte_hash_add_key(napt_common_table, (void *)key); + + if (position1 < 0) { + printf("CG-NAPT entry add failed ...returning " + "without adding ... %d\n", position1); + return 0; + } + + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG) { + printf("add_dynamic_cgnapt_entry:"); + print_key(key); + print_cgnapt_entry(&entry); + } + #endif + + memcpy(&napt_hash_tbl_entries[position1], &entry, + sizeof(struct cgnapt_table_entry)); + + /* this pointer is returned to pkt miss function */ + *entry_ptr1 = &napt_hash_tbl_entries[position1]; + + p_nat->n_cgnapt_entry_added++; + p_nat->dynCgnaptCount++; + + /* Now modify the forward port for reverse entry */ + + /* outgoing port info */ + entry.head.port_id = entry.data.prv_phy_port; + + int32_t position2 = rte_hash_add_key(napt_common_table, &second_key); + + if (position2 < 0) { + printf("CG-NAPT entry reverse bulk add failed ..." + "returning with fwd add ...%d\n", + position2); + return 0; + } + + memcpy(&napt_hash_tbl_entries[position2], &entry, + sizeof(struct cgnapt_table_entry)); + + *entry_ptr2 = &napt_hash_tbl_entries[position2]; + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG >= 1) { + printf("add_dynamic_cgnapt_entry position: %d, %d\n", + position1, position2); + printf("add_dynamic_cgnapt_entry: entry_ptr1: %p, " + "entry_ptr2: %p\n", *entry_ptr1, *entry_ptr2); + } + #endif + + timer_thread_enqueue(key, &second_key, *entry_ptr1, + *entry_ptr2, (struct pipeline *)p_nat); + + p_nat->n_cgnapt_entry_added++; + p_nat->dynCgnaptCount++; + + return 1; +} + +#endif + +void hw_checksum(struct rte_mbuf *pkt, enum PKT_TYPE ver) +{ + struct tcp_hdr *tcp = NULL; + struct udp_hdr *udp = NULL; + struct icmp_hdr *icmp = NULL; + uint8_t *protocol; + void *ip_header = NULL; + uint16_t prot_offset = 0; + uint32_t pkt_type_is_ipv4 = 1; + int temp = 0; + pkt->ol_flags |= PKT_TX_IP_CKSUM; + pkt->l2_len = ETH_HDR_SIZE; + + + + switch (ver) { + case PKT_TYPE_IPV4to6: + temp = -20; + case PKT_TYPE_IPV6: + + ip_header = RTE_MBUF_METADATA_UINT32_PTR(pkt, + MBUF_HDR_ROOM + ETH_HDR_SIZE + temp); + + pkt_type_is_ipv4 = 0; + pkt->ol_flags |= PKT_TX_IPV6; + pkt->l3_len = + sizeof(struct ipv6_hdr); + tcp = (struct tcp_hdr *) + ((unsigned char *)ip_header + + sizeof(struct ipv6_hdr)); + udp = (struct udp_hdr *) + ((unsigned char *)ip_header + + sizeof(struct ipv6_hdr)); + icmp = (struct icmp_hdr *) + ((unsigned char *)ip_header + + sizeof(struct ipv6_hdr)); + + prot_offset = PROT_OFST_IP6 + temp; + break; + case PKT_TYPE_IPV6to4: + temp = 20; + case PKT_TYPE_IPV4: + + ip_header = RTE_MBUF_METADATA_UINT32_PTR(pkt, + MBUF_HDR_ROOM + ETH_HDR_SIZE + temp); + + pkt->ol_flags |= PKT_TX_IPV4; + pkt->l3_len = + sizeof(struct ipv4_hdr); + tcp = (struct tcp_hdr *) + ((unsigned char *)ip_header + + sizeof(struct ipv4_hdr)); + udp = (struct udp_hdr *) + ((unsigned char *)ip_header + + sizeof(struct ipv4_hdr)); + icmp = (struct icmp_hdr *) + ((unsigned char *)ip_header + + sizeof(struct ipv4_hdr)); + struct ipv4_hdr *ip_hdr = + (struct ipv4_hdr *)ip_header; + ip_hdr->hdr_checksum = 0; + + prot_offset = PROT_OFST_IP4 + temp; + break; + default: + printf("hw_checksum: pkt version is invalid\n"); + } + protocol = (uint8_t *) RTE_MBUF_METADATA_UINT8_PTR(pkt, + prot_offset); + + switch (*protocol) { + case IP_PROTOCOL_TCP: /* 6 */ + tcp->cksum = 0; + pkt->ol_flags |= PKT_TX_TCP_CKSUM; + if (pkt_type_is_ipv4) { + tcp->cksum = rte_ipv4_phdr_cksum( + (struct ipv4_hdr *)ip_header, + pkt->ol_flags); + } else { + tcp->cksum = rte_ipv6_phdr_cksum( + (struct ipv6_hdr *)ip_header, + pkt->ol_flags); + } + break; + case IP_PROTOCOL_UDP: /* 17 */ + udp->dgram_cksum = 0; + pkt->ol_flags |= PKT_TX_UDP_CKSUM; + if (pkt_type_is_ipv4) { + udp->dgram_cksum = + rte_ipv4_phdr_cksum( + (struct ipv4_hdr *)ip_header, + pkt->ol_flags); + } else { + udp->dgram_cksum = + rte_ipv6_phdr_cksum( + (struct ipv6_hdr *)ip_header, + pkt->ol_flags); + } + break; + case IP_PROTOCOL_ICMP: /* 1 */ + if (pkt_type_is_ipv4) { + /* ICMP checksum code */ + struct ipv4_hdr *ip_hdr = + (struct ipv4_hdr *)ip_header; + int size = rte_bswap16(ip_hdr->total_length) - 20; + icmp->icmp_cksum = 0; + icmp->icmp_cksum = + ~rte_raw_cksum(icmp, + size); + } + break; + + default: + printf("hw_checksum() : Neither TCP or UDP pkt\n"); + break; + } +} + + +void sw_checksum(struct rte_mbuf *pkt, enum PKT_TYPE ver) +{ + struct tcp_hdr *tcp = NULL; + struct udp_hdr *udp = NULL; + struct icmp_hdr *icmp = NULL; + uint8_t *protocol; + void *ip_header = NULL; + uint16_t prot_offset = 0; + uint32_t pkt_type_is_ipv4 = 1; + int temp = 0; + + switch (ver) { + case PKT_TYPE_IPV4to6: + temp = -20; + case PKT_TYPE_IPV6: + + ip_header = RTE_MBUF_METADATA_UINT32_PTR(pkt, + MBUF_HDR_ROOM + ETH_HDR_SIZE + temp); + + pkt_type_is_ipv4 = 0; + tcp = (struct tcp_hdr *) + ((unsigned char *)ip_header + + sizeof(struct ipv6_hdr)); + udp = (struct udp_hdr *) + ((unsigned char *)ip_header + + sizeof(struct ipv6_hdr)); + icmp = (struct icmp_hdr *) + ((unsigned char *)ip_header + + sizeof(struct ipv6_hdr)); + + prot_offset = PROT_OFST_IP6 + temp; + break; + case PKT_TYPE_IPV6to4: + temp = 20; + case PKT_TYPE_IPV4: + + ip_header = RTE_MBUF_METADATA_UINT32_PTR(pkt, + MBUF_HDR_ROOM + ETH_HDR_SIZE + temp); + + tcp = (struct tcp_hdr *) + ((unsigned char *)ip_header + + sizeof(struct ipv4_hdr)); + udp = (struct udp_hdr *) + ((unsigned char *)ip_header + + sizeof(struct ipv4_hdr)); + icmp = (struct icmp_hdr *) + ((unsigned char *)ip_header + + sizeof(struct ipv4_hdr)); + + prot_offset = PROT_OFST_IP4 + temp; + break; + default: + printf("sw_checksum: pkt version is invalid\n"); + } + protocol = (uint8_t *) RTE_MBUF_METADATA_UINT8_PTR(pkt, + prot_offset); + + switch (*protocol) { + case IP_PROTOCOL_TCP: /* 6 */ + tcp->cksum = 0; + if (pkt_type_is_ipv4) { + struct ipv4_hdr *ip_hdr = + (struct ipv4_hdr *)ip_header; + tcp->cksum = rte_ipv4_udptcp_cksum(ip_hdr, + (void *)tcp); + ip_hdr->hdr_checksum = 0; + ip_hdr->hdr_checksum = rte_ipv4_cksum( + (struct ipv4_hdr *)ip_hdr); + } else { + tcp->cksum = rte_ipv6_udptcp_cksum( + (struct ipv6_hdr *) + ip_header, (void *)tcp); + } + break; + case IP_PROTOCOL_UDP: /* 17 */ + udp->dgram_cksum = 0; + if (pkt_type_is_ipv4) { + struct ipv4_hdr *ip_hdr = + (struct ipv4_hdr *)ip_header; + udp->dgram_cksum = rte_ipv4_udptcp_cksum( + ip_hdr, (void *)udp); + ip_hdr->hdr_checksum = 0; + ip_hdr->hdr_checksum = rte_ipv4_cksum(ip_hdr); + } else { + udp->dgram_cksum = rte_ipv6_udptcp_cksum( + (struct ipv6_hdr *) + ip_header, (void *)udp); + } + break; + case IP_PROTOCOL_ICMP: /* 1 */ + if (pkt_type_is_ipv4) { + /* ICMP checksum code */ + struct ipv4_hdr *ip_hdr = + (struct ipv4_hdr *)ip_header; + int size = rte_bswap16(ip_hdr->total_length) - 20; + icmp->icmp_cksum = 0; + icmp->icmp_cksum = + ~rte_raw_cksum(icmp, + size); + ip_hdr->hdr_checksum = 0; + ip_hdr->hdr_checksum = rte_ipv4_cksum(ip_hdr); + } + break; + + default: + printf("sw_checksum() : Neither TCP or UDP pkt\n"); + break; + } +} + +static uint8_t check_arp_icmp( + struct rte_mbuf *pkt, + uint64_t pkt_mask, + struct pipeline_cgnapt *p_nat) +{ + uint32_t eth_proto_offset = MBUF_HDR_ROOM + 12; + uint16_t *eth_proto = RTE_MBUF_METADATA_UINT16_PTR( + pkt, eth_proto_offset); + struct app_link_params *link; + uint8_t solicited_node_multicast_addr[16] = { + 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0xff, 0x00, 0x00, 0x00}; + + /* ARP outport number */ + uint16_t out_port = p_nat->p.n_ports_out - 1; + + uint8_t *protocol; + uint32_t prot_offset; + + link = &myApp->link_params[pkt->port]; + + + switch (rte_be_to_cpu_16(*eth_proto)) { + + case ETH_TYPE_ARP: + + rte_pipeline_port_out_packet_insert( + p_nat->p.p, + out_port, + pkt); + + /* + * Pkt mask should be changed, and not changing the + * drop mask + */ + p_nat->invalid_packets |= pkt_mask; + p_nat->arpicmpPktCount++; + + return 0; + break; + case ETH_TYPE_IPV4: { + /* 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); + prot_offset = MBUF_HDR_ROOM + ETH_HDR_SIZE + + IP_HDR_PROTOCOL_OFST; + protocol = RTE_MBUF_METADATA_UINT8_PTR(pkt, + prot_offset); + 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_nat->p.p, out_port, pkt); + + /* + * Pkt mask should be changed, + * and not changing the drop mask + */ + + p_nat->invalid_packets |= pkt_mask; + p_nat->arpicmpPktCount++; + + return 0; + } + } + return 1; + } + break; + + #ifdef IPV6 + case ETH_TYPE_IPV6: + if (dual_stack_enable) { + + /* Commented code may be required for future usage, + * Please keep it + */ + //uint32_t dst_addr_offset = MBUF_HDR_ROOM + + // ETH_HDR_SIZE + IPV6_HDR_DST_ADR_OFST; + //uint32_t *dst_addr = + // RTE_MBUF_METADATA_UINT32_PTR(pkt, + // dst_addr_offset); + uint32_t prot_offset_ipv6 = MBUF_HDR_ROOM + + ETH_HDR_SIZE + IPV6_HDR_PROTOCOL_OFST; + struct ipv6_hdr *ipv6_h; + + ipv6_h = (struct ipv6_hdr *) MBUF_HDR_ROOM + + ETH_HDR_SIZE; + protocol = RTE_MBUF_METADATA_UINT8_PTR(pkt, + prot_offset_ipv6); + + if (ipv6_h->proto == ICMPV6_PROTOCOL_ID) { + if (!memcmp(ipv6_h->dst_addr, link->ipv6, 16) + || !memcmp(ipv6_h->dst_addr, + solicited_node_multicast_addr, 13)) { + rte_pipeline_port_out_packet_insert( + p_nat->p.p, out_port, pkt); + /* + * Pkt mask should be changed, + * and not changing the drop mask + */ + p_nat->invalid_packets |= pkt_mask; + p_nat->arpicmpPktCount++; + } else { + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount1++; + #endif + } + return 0; + } + } + break; + #endif + default: + return 1; + } + return 1; +} + +/** + * Function to create common NAPT table + * Called during pipeline initialization + * Creates the common NAPT table + * If it is not already created and stores its pointer + * in global napt_common_table pointer. + * + * @params nFlows + * Max number of NAPT flows. This parameter is configurable via config file. + * + * @return + * 0 on success, negative on error. + */ +int create_napt_common_table(uint32_t nFlows) +{ + if (napt_common_table != NULL) { + printf("napt_common_table already exists.\n"); + return -1; + } + + napt_common_table = rte_hash_create(&napt_common_table_hash_params); + + if (napt_common_table == NULL) { + printf("napt_common_table creation failed.\n"); + return -2; + } + + uint32_t number_of_entries = nFlows; + + uint32_t size = + RTE_CACHE_LINE_ROUNDUP(sizeof(struct cgnapt_table_entry) * + number_of_entries); + napt_hash_tbl_entries = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE); + + if (napt_hash_tbl_entries == NULL) { + printf("napt_hash_tbl_entries creation failed. %d, %d\n", + nFlows, (int)sizeof(struct cgnapt_table_entry)); + return -3; + } + + return 0; +} + +/** + * Function to initialize bulk port allocation data structures + * Called during pipeline initialization. + * + * Creates the port alloc ring for the VNF_set this pipeline belongs + * + * Creates global port allocation buffer pool + * + * Initializes the port alloc ring according to config data + * + * @param p_nat + * A pointer to struct pipeline_cgnapt + * + * @return + * 0 on success, negative on error. + */ +int napt_port_alloc_init(struct pipeline_cgnapt *p_nat) +{ + p_nat->allocated_ports = NULL; + p_nat->free_ports = NULL; + + uint32_t vnf_set_num = p_nat->vnf_set; + /*uint32_t vnf_set_num = get_vnf_set_num(p_nat->pipeline_num); */ + + printf("VNF set number for CGNAPT %d is %d.\n", p_nat->pipeline_num, + vnf_set_num); + if (vnf_set_num == 0xFF) { + printf("VNF set number for CGNAPT %d is invalid %d.\n", + p_nat->pipeline_num, vnf_set_num); + return -1; + } + + p_nat->port_alloc_ring = port_alloc_ring[vnf_set_num]; + if (p_nat->port_alloc_ring != NULL) { + printf("CGNAPT%d port_alloc_ring already exists.\n", + p_nat->pipeline_num); + return 1; + } + + printf("napt_port_alloc_elem_count :%d\n", + napt_port_alloc_elem_count); + napt_port_alloc_elem_count += 1; + napt_port_alloc_elem_count = + nextPowerOf2(napt_port_alloc_elem_count); + printf("Next power of napt_port_alloc_elem_count: %d\n", + napt_port_alloc_elem_count); + + port_alloc_ring[vnf_set_num] = + rte_ring_create(napt_port_alloc_ring_name[vnf_set_num], + napt_port_alloc_elem_count, rte_socket_id(), 0); + p_nat->port_alloc_ring = port_alloc_ring[vnf_set_num]; + if (p_nat->port_alloc_ring == NULL) { + printf("CGNAPT%d - Failed to create port_alloc_ring\n", + p_nat->pipeline_num); + return -1; + } + + /* Create port alloc buffer */ + /* Only one pool is enough for all vnf sets */ + if (napt_port_pool == NULL) { + + napt_port_pool = rte_mempool_create( + "napt_port_pool", + napt_port_alloc_elem_count, + sizeof(struct napt_port_alloc_elem), + 0, 0, NULL, NULL, NULL, + NULL, rte_socket_id(), 0); + } + + if (napt_port_pool == NULL) { + printf("CGNAPT - Create port pool failed\n"); + return -1; + } + + /* Add all available public IP addresses and ports to the ring */ + uint32_t i, j = 0; + +#ifdef NAT_ONLY_CONFIG_REQ + if (nat_only_config_flag) { + printf("******* pub_ip_range_count:%d ***********\n", + p_nat->pub_ip_range_count); + /* Initialize all public IP's addresses */ + int if_addrs; + uint32_t max_ips_remain; + + for (if_addrs = 0; if_addrs < p_nat->pub_ip_range_count; + if_addrs++) { + /* Add all available addresses to the ring */ + + for (i = p_nat->pub_ip_range[if_addrs].start_ip; + i <= p_nat->pub_ip_range[if_addrs].end_ip;) { + /* 1. Get a port alloc buffer from napt_port_pool */ + void *portsBuf; + + if (j == 0) { + /* get new napt_port_alloc_elem from pool */ + if (rte_mempool_get(napt_port_pool, + &portsBuf) < 0) { + printf("CGNAPT - Error in getting port " + "alloc buffer\n"); + return -1; + } + } + + /* 2. Populate it with available ports and ip addr */ + struct napt_port_alloc_elem *pb = + (struct napt_port_alloc_elem *)portsBuf; + + int temp; + temp = p_nat->pub_ip_range[if_addrs].end_ip - + i + 1; + + /* Check if remaining port count is greater + * than or equals to bulk count, if not give + * remaining count ports than giving bulk count + */ + if (temp < NUM_NAPT_PORT_BULK_ALLOC) + max_ips_remain = temp; + else + max_ips_remain = + NUM_NAPT_PORT_BULK_ALLOC; + + for (j = 0; j < max_ips_remain; j++) { + pb->count = j + 1; + pb->ip_addr[j] = i + j; + pb->ports[j] = 0; + if ((i + j) == + p_nat->pub_ip_range[if_addrs]. + end_ip) + break; + } + + /* 3. add the port alloc buffer to ring */ + if (rte_ring_enqueue(p_nat->port_alloc_ring, + portsBuf) != 0) { + printf("CGNAPT%d - Enqueue error - i %d,", + p_nat->pipeline_num, i); + printf("j %d, if_addrs %d, pb %p\n", + j, if_addrs, pb); + rte_ring_dump(stdout, + p_nat->port_alloc_ring); + rte_mempool_put(napt_port_pool, + portsBuf); + return -1; + } + + /* reset j and advance i */ + j = 0; + i += max_ips_remain; + } + } + + return 1; + } +#endif + + printf("******* p_nat->pub_ip_count:%d ***********\n", + p_nat->pub_ip_count); + /* Initialize all public IP's ports */ + int if_ports; + uint32_t max_ports_remain; + + for (if_ports = 0; if_ports < p_nat->pub_ip_count; if_ports++) { + /* Add all available ports to the ring */ + + for (i = p_nat->pub_ip_port_set[if_ports].start_port; + i <= p_nat->pub_ip_port_set[if_ports].end_port;) { + /* 1. Get a port alloc buffer from napt_port_pool */ + void *portsBuf; + + if (j == 0) { + /* get new napt_port_alloc_elem from pool */ + if (rte_mempool_get(napt_port_pool, &portsBuf) < + 0) { + printf("CGNAPT - Error in getting " + "port alloc buffer\n"); + return -1; + } + } + + /* 2. Populate it with available ports and ip addr */ + struct napt_port_alloc_elem *pb = + (struct napt_port_alloc_elem *)portsBuf; + + int temp; + temp = p_nat->pub_ip_port_set[if_ports].end_port - + i + 1; + /* Check if remaining port count is greater + * than or equals to bulk count, if not give + * remaining count ports than giving bulk count + */ + if (temp < NUM_NAPT_PORT_BULK_ALLOC) + max_ports_remain = temp; + else + max_ports_remain = + NUM_NAPT_PORT_BULK_ALLOC; + + for (j = 0; j < max_ports_remain; j++) { + pb->count = j + 1; + pb->ip_addr[j] = + p_nat->pub_ip_port_set[if_ports].ip; + pb->ports[j] = i + j; + if ((i + j) == p_nat->pub_ip_port_set + [if_ports].end_port) + break; + } + + /* 3. add the port alloc buffer to ring */ + if (rte_ring_enqueue(p_nat->port_alloc_ring, + portsBuf) != 0) { + printf("CGNAPT%d - Enqueue error - i %d, j %d, " + " if_ports %d, pb %p\n", p_nat->pipeline_num, + i, j, if_ports, pb); + + rte_ring_dump(stdout, p_nat->port_alloc_ring); + rte_mempool_put(napt_port_pool, portsBuf); + return -1; + } + + /* reset j and advance i */ + j = 0; + i += max_ports_remain; + } + } + + return 1; +} + +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_cgnapt_msg_req_custom_handler, +}; + +static pipeline_msg_req_handler custom_handlers[] = { + [PIPELINE_CGNAPT_MSG_REQ_ENTRY_ADD] = + pipeline_cgnapt_msg_req_entry_add_handler, + [PIPELINE_CGNAPT_MSG_REQ_ENTRY_DEL] = + pipeline_cgnapt_msg_req_entry_del_handler, + [PIPELINE_CGNAPT_MSG_REQ_ENTRY_SYNC] = + pipeline_cgnapt_msg_req_entry_sync_handler, + [PIPELINE_CGNAPT_MSG_REQ_ENTRY_DBG] = + pipeline_cgnapt_msg_req_entry_dbg_handler, + [PIPELINE_CGNAPT_MSG_REQ_ENTRY_ADDM] = + pipeline_cgnapt_msg_req_entry_addm_handler, + [PIPELINE_CGNAPT_MSG_REQ_VER] = + pipeline_cgnapt_msg_req_ver_handler, + [PIPELINE_CGNAPT_MSG_REQ_NSP_ADD] = + pipeline_cgnapt_msg_req_nsp_add_handler, + [PIPELINE_CGNAPT_MSG_REQ_NSP_DEL] = + pipeline_cgnapt_msg_req_nsp_del_handler, + + #ifdef PCP_ENABLE + [PIPELINE_CGNAPT_MSG_REQ_PCP] = + pipeline_cgnapt_msg_req_pcp_handler, + #endif +}; + +/** + * Function to convert an IPv6 packet to IPv4 packet + * + * @param pkt + * A pointer to packet mbuf + * @param in_ipv6_hdr + * A pointer to IPv6 header in the given pkt + * + */ +static void +convert_ipv6_to_ipv4(struct rte_mbuf *pkt, struct ipv6_hdr *in_ipv6_hdr) +{ + uint32_t ip_hdr_offset = MBUF_HDR_ROOM + ETH_HDR_SIZE; + + uint8_t *eth_hdr_p = RTE_MBUF_METADATA_UINT8_PTR(pkt, MBUF_HDR_ROOM); + uint8_t *ipv6_hdr_p = RTE_MBUF_METADATA_UINT8_PTR(pkt, ip_hdr_offset); + + struct ether_hdr eth_hdr; + struct ipv4_hdr *ipv4_hdr_p; + uint16_t frag_off = 0x4000; + struct cgnapt_nsp_node *ll = nsp_ll; + uint8_t ipv4_dest[4]; + int nsp = 0; + + memcpy(ð_hdr, eth_hdr_p, sizeof(struct ether_hdr)); + memcpy(in_ipv6_hdr, ipv6_hdr_p, sizeof(struct ipv6_hdr)); + + eth_hdr.ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4); + + char *data_area_p = rte_pktmbuf_adj(pkt, 20); + if (data_area_p == NULL) { + printf("convert_ipv6_to_ipv4:data_area_p is NULL\n"); + return; + } + ipv4_hdr_p = (struct ipv4_hdr *)(data_area_p + ETH_HDR_SIZE); + memset(ipv4_hdr_p, 0, sizeof(struct ipv4_hdr)); + + memcpy(data_area_p, ð_hdr, sizeof(struct ether_hdr)); + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG == 1) + printf("convert_ipv6_to_ipv4: eth_hdr_p(%p), data_area_p(%p), " + "ipv4_hdr_p(%p)\n", eth_hdr_p, data_area_p, ipv4_hdr_p); + #endif + + ipv4_hdr_p->version_ihl = 0x4 << 4 | 0x5; + ipv4_hdr_p->type_of_service = + rte_be_to_cpu_32(in_ipv6_hdr->vtc_flow) & 0x0ff00000 >> 20; + ipv4_hdr_p->total_length = + rte_cpu_to_be_16(rte_be_to_cpu_16( + in_ipv6_hdr->payload_len) + 20); + ipv4_hdr_p->packet_id = 0; + ipv4_hdr_p->fragment_offset = rte_cpu_to_be_16(frag_off); + ipv4_hdr_p->time_to_live = in_ipv6_hdr->hop_limits; + ipv4_hdr_p->next_proto_id = in_ipv6_hdr->proto; + ipv4_hdr_p->hdr_checksum = 0; + ipv4_hdr_p->src_addr = 0; + + while (ll != NULL) { + if (!memcmp + (&in_ipv6_hdr->dst_addr[0], &ll->nsp.prefix[0], + ll->nsp.depth / 8)) { + if (ll->nsp.depth == 32) + memcpy(&ipv4_dest[0], &in_ipv6_hdr->dst_addr[4], + 4); + else if (ll->nsp.depth == 40) { + ipv4_dest[0] = in_ipv6_hdr->dst_addr[5]; + ipv4_dest[1] = in_ipv6_hdr->dst_addr[6]; + ipv4_dest[2] = in_ipv6_hdr->dst_addr[7]; + ipv4_dest[3] = in_ipv6_hdr->dst_addr[9]; + } else if (ll->nsp.depth == 48) { + ipv4_dest[0] = in_ipv6_hdr->dst_addr[6]; + ipv4_dest[1] = in_ipv6_hdr->dst_addr[7]; + ipv4_dest[2] = in_ipv6_hdr->dst_addr[9]; + ipv4_dest[3] = in_ipv6_hdr->dst_addr[10]; + } else if (ll->nsp.depth == 56) { + ipv4_dest[0] = in_ipv6_hdr->dst_addr[7]; + ipv4_dest[1] = in_ipv6_hdr->dst_addr[9]; + ipv4_dest[2] = in_ipv6_hdr->dst_addr[10]; + ipv4_dest[3] = in_ipv6_hdr->dst_addr[11]; + } else if (ll->nsp.depth == 64) { + ipv4_dest[0] = in_ipv6_hdr->dst_addr[9]; + ipv4_dest[1] = in_ipv6_hdr->dst_addr[10]; + ipv4_dest[2] = in_ipv6_hdr->dst_addr[11]; + ipv4_dest[3] = in_ipv6_hdr->dst_addr[12]; + } else if (ll->nsp.depth == 96) { + ipv4_dest[0] = in_ipv6_hdr->dst_addr[12]; + ipv4_dest[1] = in_ipv6_hdr->dst_addr[13]; + ipv4_dest[2] = in_ipv6_hdr->dst_addr[14]; + ipv4_dest[3] = in_ipv6_hdr->dst_addr[15]; + } + + nsp = 1; + break; + } + + ll = ll->next; + } + + if (nsp) + memcpy(&ipv4_hdr_p->dst_addr, &ipv4_dest[0], 4); + else + memcpy(&ipv4_hdr_p->dst_addr, &in_ipv6_hdr->dst_addr[12], 4); + +} + +/** + * Function to convert an IPv4 packet to IPv6 packet + * + * @param pkt + * A pointer to packet mbuf + * @param in_ipv4_hdr + * A pointer to IPv4 header in the given pkt + * + */ +static void +convert_ipv4_to_ipv6(struct rte_mbuf *pkt, struct ipv4_hdr *in_ipv4_hdr) +{ + uint32_t ip_hdr_offset = MBUF_HDR_ROOM + ETH_HDR_SIZE; + + uint8_t *eth_hdr_p = RTE_MBUF_METADATA_UINT8_PTR(pkt, MBUF_HDR_ROOM); + uint8_t *ipv4_hdr_p = RTE_MBUF_METADATA_UINT8_PTR(pkt, ip_hdr_offset); + + struct ether_hdr eth_hdr; + struct ipv6_hdr *ipv6_hdr_p; + + memcpy(ð_hdr, eth_hdr_p, sizeof(struct ether_hdr)); + memcpy(in_ipv4_hdr, ipv4_hdr_p, sizeof(struct ipv4_hdr)); + + eth_hdr.ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6); + + char *data_area_p = rte_pktmbuf_prepend(pkt, 20); + if (data_area_p == NULL) { + printf("convert_ipv4_to_ipv6:data_area_p is NULL\n"); + return; + } + ipv6_hdr_p = (struct ipv6_hdr *)(data_area_p + ETH_HDR_SIZE); + memset(ipv6_hdr_p, 0, sizeof(struct ipv6_hdr)); + + memcpy(data_area_p, ð_hdr, sizeof(struct ether_hdr)); + + ipv6_hdr_p->vtc_flow = + rte_cpu_to_be_32((0x6 << 28) | + (in_ipv4_hdr->type_of_service << 20)); + ipv6_hdr_p->payload_len = + rte_cpu_to_be_16(rte_be_to_cpu_16( + in_ipv4_hdr->total_length) - 20); + ipv6_hdr_p->proto = in_ipv4_hdr->next_proto_id; + ipv6_hdr_p->hop_limits = in_ipv4_hdr->time_to_live; + + ipv6_hdr_p->src_addr[0] = 0x00; + ipv6_hdr_p->src_addr[1] = 0x64; + ipv6_hdr_p->src_addr[2] = 0xff; + ipv6_hdr_p->src_addr[3] = 0x9b; + ipv6_hdr_p->src_addr[4] = 0x00; + ipv6_hdr_p->src_addr[5] = 0x00; + ipv6_hdr_p->src_addr[6] = 0x00; + ipv6_hdr_p->src_addr[7] = 0x00; + ipv6_hdr_p->src_addr[8] = 0x00; + ipv6_hdr_p->src_addr[9] = 0x00; + ipv6_hdr_p->src_addr[10] = 0x00; + ipv6_hdr_p->src_addr[11] = 0x00; + memcpy(&ipv6_hdr_p->src_addr[12], &in_ipv4_hdr->src_addr, 4); + + memset(&ipv6_hdr_p->dst_addr, 0, 16); + + return; + +} + +/** + * Output port handler + * + * @param pkt + * A pointer to packet mbuf + * @param arg + * Unused void pointer + * + */ +#ifdef PIPELINE_CGNAPT_INSTRUMENTATION +static void +pkt_work_cgnapt_out(__rte_unused struct rte_mbuf *pkt, __rte_unused void *arg) +{ +#ifdef PIPELINE_CGNAPT_INSTRUMENTATION + if ((cgnapt_num_func_to_inst == 5) + && (cgnapt_inst_index < INST_ARRAY_SIZE)) { + if (cgnapt_inst5_flag == 0) { + uint8_t *inst5_sig = + RTE_MBUF_METADATA_UINT8_PTR(pkt, + CGNAPT_INST5_OFST); + if (*inst5_sig == CGNAPT_INST5_SIG) { + cgnapt_inst5_flag = 1; + inst_end_time[cgnapt_inst_index] = + rte_get_tsc_cycles(); + cgnapt_inst_index++; + } + } + } +#endif + + /* cgnapt_pkt_out_count++; */ + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG) + print_pkt(pkt); + #endif +} +#endif + +/** + * Output port handler to handle 4 pkts + * + * @param pkt + * A pointer to packet mbuf + * @param arg + * Inport handler argument pointer + * + */ +#ifdef PIPELINE_CGNAPT_INSTRUMENTATION +static void pkt4_work_cgnapt_out(struct rte_mbuf **pkt, void *arg) +{ + (void)pkt; + (void)arg; +/* TO BE IMPLEMENTED IF REQUIRED */ +} +#endif + +#ifdef PIPELINE_CGNAPT_INSTRUMENTATION +PIPELINE_CGNAPT_PORT_OUT_AH(port_out_ah_cgnapt, + pkt_work_cgnapt_out, pkt4_work_cgnapt_out); + +PIPELINE_CGNAPT_PORT_OUT_BAH(port_out_ah_cgnapt_bulk, + pkt_work_cgnapt_out, pkt4_work_cgnapt_out); +#endif + +/** + * Function to validate the packet and return version + * + * @param pkt + * A pointer to packet mbuf + * + * @return + * IP version of the valid pkt, -1 if invalid pkt + */ +int rte_get_pkt_ver(struct rte_mbuf *pkt) +{ + uint32_t eth_proto_offset = MBUF_HDR_ROOM + 12; + uint16_t *eth_proto = + RTE_MBUF_METADATA_UINT16_PTR(pkt, eth_proto_offset); + + if (*eth_proto == rte_be_to_cpu_16(ETHER_TYPE_IPv4)) + return IP_VERSION_4; + + if (dual_stack_enable + && (*eth_proto == rte_be_to_cpu_16(ETHER_TYPE_IPv6))) + return IP_VERSION_6; + + /* Check the protocol first, if not UDP or TCP return */ + + return -1; +} + +/** + * A method to print the NAPT entry + * + * @param ent + * A pointer to struct cgnapt_table_entry + */ +void my_print_entry(struct cgnapt_table_entry *ent) +{ + printf("CGNAPT key:\n"); + printf("entry_type :%d\n", ent->data.type); + printf("prv_ip: %x %x %x %x\n", ent->data.u.u32_prv_ipv6[0], + ent->data.u.u32_prv_ipv6[1], ent->data.u.u32_prv_ipv6[2], + ent->data.u.u32_prv_ipv6[3]); + printf("prv_port:%d\n", ent->data.prv_port); + + printf("pub_ip:%x\n", ent->data.pub_ip); + printf("prv_phy_port:%d\n", ent->data.prv_phy_port); + printf("pub_phy_port:%d\n", ent->data.pub_phy_port); +} + +/** + * Function to print common CGNAPT table entries + * + */ +void print_common_table(void) +{ + uint32_t count = 0; + const void *key; + void *data; + uint32_t next = 0; + int32_t index = 0; + do { + index = rte_hash_iterate(napt_common_table, + &key, &data, &next); + + if ((index != -EINVAL) && (index != -ENOENT)) { + printf("\n%04d ", count); + //print_key((struct pipeline_cgnapt_entry_key *)key); + rte_hexdump(stdout, "KEY", key, + sizeof(struct pipeline_cgnapt_entry_key)); + int32_t position = rte_hash_lookup( + napt_common_table, key); + print_cgnapt_entry(&napt_hash_tbl_entries[position]); + } + + count++; + } while (index != -ENOENT); +} + +/** + * Input port handler for mixed traffic + * This is the main method in this file when running in mixed traffic mode. + * Starting from the packet burst it filters unwanted packets, + * calculates keys, does lookup and then based on the lookup + * updates NAPT table and does packet NAPT translation. + * + * @param rte_p + * A pointer to struct rte_pipeline + * @param pkts + * A pointer to array of packets mbuf + * @param n_pkts + * Number of packets in the burst + * @param arg + * Void pointer + * + * @return + * int that is not checked by caller + */ + +static int cgnapt_in_port_ah_mix(struct rte_pipeline *rte_p, + struct rte_mbuf **pkts, + uint32_t n_pkts, void *arg) +{ +/* +* Code flow +* +* 1. Read packet version, if invalid drop the packet +* 2. Check protocol, if not UDP or TCP drop the packet +* 3. Bring all valid packets together - useful for bulk lookup +* and calculate key for all packets +* a. If IPv4 : calculate key with full IP +* b. If IPv6 : calculate key with last 32-bit of IP +* 4. Do bulk lookup with rte_hash_lookup_bulk(), if something went wrong +* drop all packets +* 5. For lookup hit packets, read entry from table +* 6. For lookup miss packets, add dynamic entry to table +* 7. If pkt is IPv6 +* a. If egress pkt, convert to IPv4 and NAPT it +* b. If ingress, drop the pkt +* 8. If pkt is IPv4 +* a. If egress pkt, NAPT it. Get MAC +* b. If first ingress pkt (with no egress entry), drop the pkt +* If not first ingress pkt +* I. If IPv6 converted packet, convert back to IPv6, + NAPT it & get MAC +* II. If IPv4 packet, NAPT it & get MAC +* 9. Send all packets out to corresponding ports +*/ + struct pipeline_cgnapt_in_port_h_arg *ap = arg; + struct pipeline_cgnapt *p_nat = ap->p; + uint8_t compacting_map[RTE_HASH_LOOKUP_BULK_MAX]; + uint32_t packets_for_lookup = 0; + uint32_t i; + + p_nat->valid_packets = 0; + p_nat->invalid_packets = 0; + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 1) + printf("cgnapt_key hit fn: %" PRIu32 "\n", n_pkts); + #endif + + p_nat->pkt_burst_cnt = 0; /* for dynamic napt */ + + uint16_t phy_port = 0; + uint16_t *src_port = NULL; + uint16_t *dst_port = NULL; + uint32_t *src_addr = NULL; + uint32_t *dst_addr = NULL; + uint8_t *protocol = NULL; + uint8_t *eth_dest = NULL; + uint8_t *eth_src = NULL; + uint16_t src_port_offset = 0; + uint16_t dst_port_offset = 0; + uint16_t src_addr_offset = 0; + uint16_t dst_addr_offset = 0; + uint16_t prot_offset = 0; + uint16_t eth_offset = 0; + int ver = 0; + + enum PKT_TYPE pkt_type = PKT_TYPE_IPV4; + + src_port_offset = SRC_PRT_OFST_IP4_TCP; + dst_port_offset = DST_PRT_OFST_IP4_TCP; + + for (i = 0; i < n_pkts; i++) { + p_nat->receivedPktCount++; + + /* bitmask representing only this packet */ + uint64_t pkt_mask = 1LLU << i; + + /* remember this pkt as valid pkt */ + p_nat->valid_packets |= pkt_mask; + + struct rte_mbuf *pkt = pkts[i]; + + if (enable_hwlb) + if (!check_arp_icmp(pkt, pkt_mask, p_nat)) + continue; + + int ver = rte_get_pkt_ver(pkt); + + #ifdef CGNAPT_DBG_PRNT + printf("ver no. of the pkt:%d\n", ver); + #endif + + if (unlikely(ver < 0)) { + /* Not a valid pkt , ignore. */ + /* remember invalid packets to be dropped */ + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount1++; + #endif + continue; + } + if (ver == 4) + prot_offset = PROT_OFST_IP4; + else + prot_offset = PROT_OFST_IP6; + protocol = + (uint8_t *) RTE_MBUF_METADATA_UINT32_PTR(pkt, + prot_offset); + if (! + (*protocol == IP_PROTOCOL_TCP + || *protocol == IP_PROTOCOL_UDP + || *protocol == IP_PROTOCOL_ICMP)) { + /* remember invalid packets to be dropped */ + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount2++; + #endif + continue; + } + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 4) + print_pkt(pkt); + #endif + + #ifdef PCP_ENABLE + /* Handling PCP + * 1. Handel PCP for egress traffic + * 2. If PCP, then give response (send pkt) from the same port + * 3. Drop the PCP packet, should not be added in the NAPT table + */ + if (pcp_enable) { + if (*protocol == IP_PROTOCOL_UDP) { + struct udp_hdr *udp; + if (ver == 4) + udp = (struct udp_hdr *) + RTE_MBUF_METADATA_UINT8_PTR(pkt, + IPV4_UDP_OFST); + else + udp = (struct udp_hdr *) + RTE_MBUF_METADATA_UINT8_PTR(pkt, + IPV6_UDP_OFST); + + if (rte_bswap16(udp->dst_port) == + PCP_SERVER_PORT) { + handle_pcp_req(pkt, ver, p_nat); + p_nat->invalid_packets |= pkt_mask; + continue; + } + } + } + #endif + + if (ver == 4) { + + src_addr = + RTE_MBUF_METADATA_UINT32_PTR(pkt, + SRC_ADR_OFST_IP4); + dst_addr = + RTE_MBUF_METADATA_UINT32_PTR(pkt, + DST_ADR_OFST_IP4); + + if ((*protocol == IP_PROTOCOL_TCP) + || (*protocol == IP_PROTOCOL_UDP)) { + + src_port_offset = SRC_PRT_OFST_IP4_TCP; + dst_port_offset = DST_PRT_OFST_IP4_TCP; + + } else if (*protocol == IP_PROTOCOL_ICMP) { + /* Identifier */ + src_port_offset = IDEN_OFST_IP4_ICMP; + /* Sequence number */ + dst_port_offset = SEQN_OFST_IP4_ICMP; + } + + src_port = + RTE_MBUF_METADATA_UINT16_PTR(pkt, + src_port_offset); + dst_port = + RTE_MBUF_METADATA_UINT16_PTR(pkt, + dst_port_offset); + } else { + + src_addr = + RTE_MBUF_METADATA_UINT32_PTR(pkt, + SRC_ADR_OFST_IP6); + dst_addr = + RTE_MBUF_METADATA_UINT32_PTR(pkt, + DST_ADR_OFST_IP6); + src_port = + RTE_MBUF_METADATA_UINT16_PTR(pkt, + SRC_PRT_OFST_IP6); + dst_port = + RTE_MBUF_METADATA_UINT16_PTR(pkt, + DST_PRT_OFST_IP6); + } + /* need to create compacted table of pointers to + * pass to bulk lookup + */ + + compacting_map[packets_for_lookup] = i; + + //phy_port = RTE_MBUF_METADATA_UINT16_PTR(pkt, phyport_offset); + phy_port = pkt->port; + + struct pipeline_cgnapt_entry_key key; + + memset(&key, 0, sizeof(struct pipeline_cgnapt_entry_key)); + + key.pid = phy_port; + if (get_in_port_dir(phy_port)) { + /* Egress */ + if (ver == 4) + key.ip = rte_bswap32(*src_addr); + else + key.ip = rte_bswap32(src_addr[3]); + key.port = rte_bswap16(*src_port); + + #ifdef NAT_ONLY_CONFIG_REQ + if (nat_only_config_flag) + key.port = 0xffff; + #endif + } else { + /* Ingress */ + key.ip = rte_bswap32(*dst_addr); + + if (*protocol == IP_PROTOCOL_ICMP) { + /* common table lookupkey preparation from + * incoming ICMP Packet- Indentifier field + */ + key.port = rte_bswap16(*src_port); + } else { + key.port = rte_bswap16(*dst_port); + } + + #ifdef NAT_ONLY_CONFIG_REQ + if (nat_only_config_flag) + key.port = 0xffff; + #endif + + key.pid = 0xffff; + } + + memcpy(&(p_nat->keys[packets_for_lookup]), &key, + sizeof(struct pipeline_cgnapt_entry_key)); + p_nat->key_ptrs[packets_for_lookup] = + &(p_nat->keys[packets_for_lookup]); + packets_for_lookup++; + } + + if (unlikely(packets_for_lookup == 0)) { + /* no suitable packet for lookup */ + rte_pipeline_ah_packet_drop(rte_p, p_nat->valid_packets); + return p_nat->valid_packets; + } + + /* lookup entries in the common napt table */ + + int lookup_result = rte_hash_lookup_bulk(napt_common_table, + (const void **) + &p_nat->key_ptrs, + packets_for_lookup, + &p_nat->lkup_indx[0]); + + if (unlikely(lookup_result < 0)) { + /* unknown error, just discard all packets */ + printf("Unexpected hash lookup error %d, discarding all " + "packets", lookup_result); + rte_pipeline_ah_packet_drop(rte_p, p_nat->valid_packets); + return 0; + } + //struct rte_pipeline_table_entry *entries[64]; + /* Now one by one check the result of our bulk lookup */ + + for (i = 0; i < packets_for_lookup; i++) { + /* index into hash table entries */ + int hash_table_entry = p_nat->lkup_indx[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; + + struct cgnapt_table_entry *entry = NULL; + if (hash_table_entry < 0) { + + /* try to add new entry */ + struct rte_pipeline_table_entry *table_entry = NULL; + + uint64_t dropmask = + pkt_miss_cgnapt(p_nat->key_ptrs[i], + pkts[pkt_index], + &table_entry, + &p_nat->valid_packets, + pkt_index, + (void *)p_nat); + + if (!table_entry) { + /* ICMP Error message generation for + * Destination Host unreachable + */ + if (*protocol == IP_PROTOCOL_ICMP) { + cgnapt_icmp_pkt = pkts[pkt_index]; + send_icmp_dest_unreachable_msg(); + } + + /* Drop packet by adding to invalid pkt mask */ + + p_nat->invalid_packets |= dropmask; + #ifdef CGNAPT_DEBUGGING + if (p_nat->kpc2++ < 5) { + printf("in_ah Th: %d", + p_nat->pipeline_num); + print_key(p_nat->key_ptrs[i]); + } + #endif + + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount3++; + #endif + continue; + } + + entry = (struct cgnapt_table_entry *)table_entry; + } else { + /* entry found for this packet */ + entry = &napt_hash_tbl_entries[hash_table_entry]; + } + + /* apply napt and mac changes */ + + p_nat->entries[pkt_index] = &(entry->head); + + phy_port = pkts[pkt_index]->port; + + struct ipv6_hdr ipv6_hdr; + struct ipv4_hdr ipv4_hdr; + + ver = rte_get_pkt_ver(pkts[pkt_index]); + #ifdef CGNAPT_DEBUGGING + if (CGNAPT_DEBUG >= 1) { + printf("ver:%d\n", ver); + printf("entry->data.type:%d\n", entry->data.type); + } + #endif + if ((ver == 6) && (entry->data.type == CGNAPT_ENTRY_IPV6) + && is_phy_port_privte(phy_port)) { + convert_ipv6_to_ipv4(pkts[pkt_index], &ipv6_hdr); + + pkt_type = PKT_TYPE_IPV6to4; + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG >= 1) + printf("pkt_work_cganpt: " + "convert_ipv6_to_ipv4\n"); + #endif + + struct cgnapt_nsp_node *ll = nsp_ll; + int nsp = 0; + while (ll != NULL) { + if (!memcmp(&ipv6_hdr.dst_addr[0], + &ll->nsp.prefix[0], + ll->nsp.depth / 8)) { + nsp = 1; + break; + } + ll = ll->next; + } + + if (!nsp + && !memcmp(&ipv6_hdr.dst_addr[0], + &well_known_prefix[0], 12)) { + nsp = 1; + } + + if (!nsp) { + p_nat->invalid_packets |= 1LLU << pkt_index; + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount5++; + #endif + continue; + } + + } + + /* As packet is already converted into IPv4 we must not operate + * IPv6 offsets on packet + * Only perform IPv4 operations + */ + + if (ver == 6) { + + src_port_offset = SRC_PRT_OFST_IP6t4; + dst_port_offset = DST_PRT_OFST_IP6t4; + src_addr_offset = SRC_ADR_OFST_IP6t4; + dst_addr_offset = DST_ADR_OFST_IP6t4; + prot_offset = PROT_OFST_IP6t4; + eth_offset = ETH_OFST_IP6t4; + + } else { + + if ((*protocol == IP_PROTOCOL_TCP) + || (*protocol == IP_PROTOCOL_UDP)) { + src_port_offset = SRC_PRT_OFST_IP4_TCP; + dst_port_offset = DST_PRT_OFST_IP4_TCP; + } else if (*protocol == IP_PROTOCOL_ICMP) { + /* Identifier */ + src_port_offset = IDEN_OFST_IP4_ICMP; + /* Sequence number */ + dst_port_offset = SEQN_OFST_IP4_ICMP; + } + + src_addr_offset = SRC_ADR_OFST_IP4; + dst_addr_offset = DST_ADR_OFST_IP4; + prot_offset = PROT_OFST_IP4; + eth_offset = MBUF_HDR_ROOM; + + } + + src_addr = + RTE_MBUF_METADATA_UINT32_PTR(pkts[pkt_index], + src_addr_offset); + dst_addr = + RTE_MBUF_METADATA_UINT32_PTR(pkts[pkt_index], + dst_addr_offset); + src_port = + RTE_MBUF_METADATA_UINT16_PTR(pkts[pkt_index], + src_port_offset); + dst_port = + RTE_MBUF_METADATA_UINT16_PTR(pkts[pkt_index], + dst_port_offset); + protocol = + RTE_MBUF_METADATA_UINT8_PTR(pkts[pkt_index], + prot_offset); + + eth_dest = + RTE_MBUF_METADATA_UINT8_PTR(pkts[pkt_index], + eth_offset); + eth_src = + RTE_MBUF_METADATA_UINT8_PTR(pkts[pkt_index], + eth_offset + 6); + + if (entry->data.ttl == NAPT_ENTRY_STALE) + entry->data.ttl = NAPT_ENTRY_VALID; + + struct ether_addr hw_addr; + uint32_t dest_address = 0; + uint8_t nh_ipv6[16]; + uint32_t nhip = 0; + + uint32_t dest_if = 0xff; + uint32_t ret; + + uint16_t *outport_id = + RTE_MBUF_METADATA_UINT16_PTR(pkts[pkt_index], + cgnapt_meta_offset); + + if (is_phy_port_privte(phy_port)) { + + if (*protocol == IP_PROTOCOL_UDP + && rte_be_to_cpu_16(*dst_port) == 53) { + p_nat->invalid_packets |= 1LLU << pkt_index; + p_nat->naptDroppedPktCount++; + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount6++; + #endif + continue; + } + + dest_address = rte_bswap32(*dst_addr); + ret = local_get_nh_ipv4(dest_address, &dest_if, + &nhip, p_nat); + if (!ret) { + dest_if = get_prv_to_pub_port(&dest_address, + IP_VERSION_4); + if (dest_if == INVALID_DESTIF) { + p_nat->invalid_packets |= + 1LLU << pkt_index; + p_nat->naptDroppedPktCount++; + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount6++; + #endif + continue; + } + do_local_nh_ipv4_cache(dest_if, p_nat); + } + + *outport_id = p_nat->outport_id[dest_if]; + int ret; + ret = get_dest_mac_addr_port(dest_address, + &dest_if, &hw_addr); + + if (ret == ARP_FOUND) { + memcpy(eth_dest, &hw_addr, + sizeof(struct ether_addr)); + memcpy(eth_src, get_link_hw_addr(dest_if), + sizeof(struct ether_addr)); + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 2) { + printf("MAC found for ip 0x%x, port %d - " + "%02x:%02x:%02x:%02x:%02x:%02x\n", + dest_address, *outport_id, + hw_addr.addr_bytes[0], hw_addr.addr_bytes[1], + hw_addr.addr_bytes[2], hw_addr.addr_bytes[3], + hw_addr.addr_bytes[4], hw_addr.addr_bytes[5]); + + printf("Dest MAC before - " + "%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]); + } + #endif + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 2) { + printf("Dest MAC after - " + "%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]); + } + #endif + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 4) + print_pkt(pkts[pkt_index]); + #endif + + } else{ + if (ret == ARP_NOT_FOUND) { + /* Commented code may be required + * for future use, Please keep it */ + //request_arp(*outport_id, nhip, + // p_nat->p.p); + printf("%s: ARP Not Found, nhip: %x, " + "outport_id: %d\n", __func__, nhip, + *outport_id); + } + + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount4++; + #endif + continue; + } + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 2) + printf("Egress: \tphy_port:%d\t " + "get_prv_to_pub():%d \tout_port:%d\n", + phy_port, dest_if, + *outport_id); + #endif + + /* Egress */ + *src_addr = rte_bswap32(entry->data.pub_ip); + + #ifdef NAT_ONLY_CONFIG_REQ + if (!nat_only_config_flag) { + #endif + *src_port = rte_bswap16(entry->data.pub_port); + #ifdef NAT_ONLY_CONFIG_REQ + } + #endif + + p_nat->enaptedPktCount++; + } else { + /* Ingress */ + if (*protocol == IP_PROTOCOL_UDP + && rte_be_to_cpu_16(*src_port) == 53) { + p_nat->invalid_packets |= 1LLU << pkt_index; + p_nat->naptDroppedPktCount++; + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount6++; + #endif + continue; + } + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 2) + printf("Ingress: \tphy_port:%d\t " + "get_pub_to_prv():%d \tout_port%d\n", + phy_port, dest_if, + *outport_id); + #endif + + if (entry->data.type == CGNAPT_ENTRY_IPV6) { + convert_ipv4_to_ipv6(pkts[pkt_index], + &ipv4_hdr); + pkt_type = PKT_TYPE_IPV4to6; + /* Ethernet MTU check */ + if ((rte_pktmbuf_data_len(pkts[pkt_index]) - + 14) > 1500) { + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + continue; + } + + eth_dest = eth_dest - 20; + eth_src = eth_src - 20; + + dst_port_offset = DST_PRT_OFST_IP4t6; + dst_addr_offset = DST_ADR_OFST_IP4t6; + dst_addr = + RTE_MBUF_METADATA_UINT32_PTR( + pkts[pkt_index], + dst_addr_offset); + dst_port = + RTE_MBUF_METADATA_UINT16_PTR( + pkts[pkt_index], + dst_port_offset); + + memcpy((uint8_t *) &dst_addr[0], + &entry->data.u.prv_ipv6[0], 16); + memset(nh_ipv6, 0, 16); + + ret = local_get_nh_ipv6((uint8_t *)&dst_addr[0], + &dest_if, &nh_ipv6[0], p_nat); + + if (!ret) { + dest_if = get_prv_to_pub_port( + &dst_addr[0], + IP_VERSION_6); + if (dest_if == INVALID_DESTIF) { + p_nat->invalid_packets |= + 1LLU << pkt_index; + p_nat->naptDroppedPktCount++; + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount6++; + #endif + continue; + } + do_local_nh_ipv6_cache(dest_if, p_nat); + } + *outport_id = p_nat->outport_id[dest_if]; + + if (get_dest_mac_address_ipv6_port((uint8_t *) + &dst_addr[0], &dest_if, + &hw_addr, &nh_ipv6[0])){ + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 2) { + printf("MAC found for ip 0x%x, port %d - " + "%02x:%02x:%02x:%02x:%02x:%02x\n", + dest_address, *outport_id, + hw_addr.addr_bytes[0], + hw_addr.addr_bytes[1], hw_addr.addr_bytes[2], + hw_addr.addr_bytes[3], hw_addr.addr_bytes[4], + hw_addr.addr_bytes[5]); + + printf("Dest MAC before - " + "%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]); + } + #endif + memcpy(eth_dest, &hw_addr, + sizeof(struct ether_addr)); + memcpy(eth_src, get_link_hw_addr( + dest_if), + sizeof(struct ether_addr)); + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 2) { + printf("Dest MAC after - " + "%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]); + } + #endif + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 4) + print_pkt(pkts[pkt_index]); + #endif + } else { + + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount4++; + #endif + continue; + } + + #ifdef NAT_ONLY_CONFIG_REQ + if (!nat_only_config_flag) { + #endif + *dst_port = + rte_bswap16(entry->data.prv_port); + #ifdef NAT_ONLY_CONFIG_REQ + } + #endif + + } else { + *dst_addr = rte_bswap32(entry->data.u.prv_ip); + dest_address = entry->data.u.prv_ip; + ret = local_get_nh_ipv4(dest_address, &dest_if, + &nhip, p_nat); + if (!ret) { + dest_if = get_pub_to_prv_port( + &dest_address, IP_VERSION_4); + if (dest_if == INVALID_DESTIF) { + p_nat->invalid_packets |= + 1LLU << pkt_index; + p_nat->naptDroppedPktCount++; + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount6++; + #endif + continue; + } + do_local_nh_ipv4_cache(dest_if, p_nat); + }; + + *outport_id = p_nat->outport_id[dest_if]; + int ret; + ret = get_dest_mac_addr_port(dest_address, + &dest_if, &hw_addr); + + if (ret == ARP_FOUND) { + memcpy(eth_dest, &hw_addr, + sizeof(struct ether_addr)); + memcpy(eth_src, get_link_hw_addr( + dest_if), + sizeof(struct ether_addr)); + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 2) { + printf("MAC found for ip 0x%x, port %d - " + "%02x:%02x:%02x:%02x:%02x:%02x\n", + dest_address, *outport_id, + hw_addr.addr_bytes[0], hw_addr.addr_bytes[1], + hw_addr.addr_bytes[2], hw_addr.addr_bytes[3], + hw_addr.addr_bytes[4], hw_addr.addr_bytes[5]); + + printf("Dest MAC before - " + "%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]); + } + #endif + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 2) { + printf("Dest MAC after - " + "%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]); + } + #endif + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 4) + print_pkt(pkts[pkt_index]); + #endif + + } else { + if (ret == ARP_NOT_FOUND) { + printf("%s: ARP Not Found, nhip: %x, " + "outport_id: %d\n", __func__, nhip, + *outport_id); + } + //request_arp(*outport_id, + // nhip, p_nat->p.p); + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount4++; + #endif + continue; + } + + if (*protocol == IP_PROTOCOL_ICMP) { + // Query ID reverse translation done here + *src_port = + rte_bswap16(entry->data.prv_port); + } else { + #ifdef NAT_ONLY_CONFIG_REQ + if (!nat_only_config_flag) { + #endif + *dst_port = + rte_bswap16(entry-> + data.prv_port); + #ifdef NAT_ONLY_CONFIG_REQ + } + #endif + } + } + + p_nat->inaptedPktCount++; + } + + p_nat->naptedPktCount++; + + #ifdef HW_CHECKSUM_REQ + if (p_nat->hw_checksum_reqd) + hw_checksum(pkts[pkt_index], pkt_type); + else + #endif + sw_checksum(pkts[pkt_index], pkt_type); + } + + if (p_nat->invalid_packets) { + /* get rid of invalid packets */ + rte_pipeline_ah_packet_drop(rte_p, p_nat->invalid_packets); + + p_nat->valid_packets &= ~(p_nat->invalid_packets); + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 1) { + printf("valid_packets:0x%jx\n", p_nat->valid_packets); + printf("rte_valid_packets :0x%jx\n", rte_p->pkts_mask); + printf("invalid_packets:0x%jx\n", + p_nat->invalid_packets); + printf("rte_invalid_packets :0x%jx\n", + rte_p->pkts_drop_mask); + printf("Total pkts dropped :0x%jx\n", + rte_p->n_pkts_ah_drop); + } + #endif + } + + return p_nat->valid_packets; +} + +/** + * Input port handler for IPv4 private traffic + * Starting from the packet burst it filters unwanted packets, + * calculates keys, does lookup and then based on the lookup + * updates NAPT table and does packet NAPT translation. + * + * @param rte_p + * A pointer to struct rte_pipeline + * @param pkts + * A pointer to array of packets mbuf + * @param n_pkts + * Number of packets in the burst + * @param arg + * Void pointer + * + * @return + * int that is not checked by caller + */ + +static int cgnapt_in_port_ah_ipv4_prv(struct rte_pipeline *rte_p, + struct rte_mbuf **pkts, + uint32_t n_pkts, void *arg) +{ + uint32_t i, j; + struct pipeline_cgnapt_in_port_h_arg *ap = arg; + struct pipeline_cgnapt *p_nat = ap->p; + + #ifdef CGNAPT_TIMING_INST + uint64_t entry_timestamp = 0, exit_timestamp; + + if (p_nat->time_measurements_on) { + entry_timestamp = rte_get_tsc_cycles(); + /* check since exit ts not valid first time through */ + if (likely(p_nat->in_port_exit_timestamp)) + p_nat->external_time_sum += + entry_timestamp - p_nat->in_port_exit_timestamp; + } + #endif + + p_nat->pkt_burst_cnt = 0; /* for dynamic napt */ + p_nat->valid_packets = rte_p->pkts_mask; /*n_pkts; */ + p_nat->invalid_packets = 0; + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 1) + printf("cgnapt_key hit fn: %" PRIu32 "\n", n_pkts); + #endif + + /* prefetching for mbufs should be done here */ + for (j = 0; j < n_pkts; j++) + rte_prefetch0(pkts[j]); + + for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4) + pkt4_work_cgnapt_key_ipv4_prv(&pkts[i], i, arg, p_nat); + + for (; i < n_pkts; i++) + pkt_work_cgnapt_key_ipv4_prv(pkts[i], i, arg, p_nat); + + p_nat->valid_packets &= ~(p_nat->invalid_packets); + + if (unlikely(p_nat->valid_packets == 0)) { + /* no suitable packet for lookup */ + rte_pipeline_ah_packet_drop(rte_p, p_nat->invalid_packets); + return p_nat->valid_packets; + } + + /* lookup entries in the common napt table */ + + int lookup_result = rte_hash_lookup_bulk( + napt_common_table, + (const void **)&p_nat->key_ptrs, + /* should be minus num invalid pkts */ + n_pkts, + /*new pipeline data member */ + &p_nat->lkup_indx[0]); + + if (unlikely(lookup_result < 0)) { + /* unknown error, just discard all packets */ + printf("Unexpected hash lookup error %d, discarding " + "all packets", lookup_result); + rte_pipeline_ah_packet_drop(rte_p, p_nat->valid_packets); + return 0; + } + + /* Now call second stage of pipeline to one by one + * check the result of our bulk lookup + */ + + /* prefetching for table entries should be done here */ + for (j = 0; j < n_pkts; j++) { + if (p_nat->lkup_indx[j] >= 0) + rte_prefetch0(&napt_hash_tbl_entries + [p_nat->lkup_indx[j]]); + } + + for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4) + pkt4_work_cgnapt_ipv4_prv(pkts, i, arg, p_nat); + + for (; i < n_pkts; i++) + pkt_work_cgnapt_ipv4_prv(pkts, i, arg, p_nat); + + if (p_nat->invalid_packets) { + /* get rid of invalid packets */ + rte_pipeline_ah_packet_drop(rte_p, p_nat->invalid_packets); + + p_nat->valid_packets &= ~(p_nat->invalid_packets); + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 1) { + printf("valid_packets:0x%jx\n", p_nat->valid_packets); + printf("rte_valid_packets :0x%jx\n", rte_p->pkts_mask); + printf("invalid_packets:0x%jx\n", + p_nat->invalid_packets); + printf("rte_invalid_packets :0x%jx\n", + rte_p->pkts_drop_mask); + printf("Total pkts dropped :0x%jx\n", + rte_p->n_pkts_ah_drop); + } + #endif + } + + #ifdef CGNAPT_TIMING_INST + if (p_nat->time_measurements_on) { + exit_timestamp = rte_get_tsc_cycles(); + p_nat->in_port_exit_timestamp = exit_timestamp; + p_nat->internal_time_sum += exit_timestamp - entry_timestamp; + p_nat->time_measurements++; + if (p_nat->time_measurements == p_nat->max_time_mesurements) + p_nat->time_measurements_on = 0; + } + #endif + + return p_nat->valid_packets; +} + +/** + * Input port handler for IPv4 public traffic + * Starting from the packet burst it filters unwanted packets, + * calculates keys, does lookup and then based on the lookup + * updates NAPT table and does packet NAPT translation. + * + * @param rte_p + * A pointer to struct rte_pipeline + * @param pkts + * A pointer to array of packets mbuf + * @param n_pkts + * Number of packets in the burst + * @param arg + * Void pointer + * + * @return + * int that is not checked by caller + */ +static int cgnapt_in_port_ah_ipv4_pub(struct rte_pipeline *rte_p, + struct rte_mbuf **pkts, + uint32_t n_pkts, void *arg) +{ + uint32_t i, j; + struct pipeline_cgnapt_in_port_h_arg *ap = arg; + struct pipeline_cgnapt *p_nat = ap->p; + + #ifdef CGNAPT_TIMING_INST + uint64_t entry_timestamp = 0, exit_timestamp; + + if (p_nat->time_measurements_on) { + entry_timestamp = rte_get_tsc_cycles(); + + /* check since exit ts not valid first time through */ + if (likely(p_nat->in_port_exit_timestamp)) + p_nat->external_time_sum += + entry_timestamp - p_nat->in_port_exit_timestamp; + } + #endif + + p_nat->pkt_burst_cnt = 0; /* for dynamic napt */ + p_nat->valid_packets = rte_p->pkts_mask; /*n_pkts; */ + p_nat->invalid_packets = 0; + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 1) + printf("cgnapt_key hit fn: %" PRIu32 "\n", n_pkts); + #endif + + /* prefetching for mbufs should be done here */ + for (j = 0; j < n_pkts; j++) + rte_prefetch0(pkts[j]); + + for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4) + pkt4_work_cgnapt_key_ipv4_pub(&pkts[i], i, arg, p_nat); + + for (; i < n_pkts; i++) + pkt_work_cgnapt_key_ipv4_pub(pkts[i], i, arg, p_nat); + + p_nat->valid_packets &= ~(p_nat->invalid_packets); + + if (unlikely(p_nat->valid_packets == 0)) { + /* no suitable packet for lookup */ + rte_pipeline_ah_packet_drop(rte_p, p_nat->invalid_packets); + return p_nat->valid_packets; + } + + /* lookup entries in the common napt table */ + + int lookup_result = rte_hash_lookup_bulk( + napt_common_table, + (const void **)&p_nat->key_ptrs, + /* should be minus num invalid pkts */ + n_pkts, + /*new pipeline data member */ + &p_nat->lkup_indx[0]); + + if (unlikely(lookup_result < 0)) { + /* unknown error, just discard all packets */ + printf("Unexpected hash lookup error %d, discarding " + "all packets", lookup_result); + rte_pipeline_ah_packet_drop(rte_p, p_nat->valid_packets); + return 0; + } + + /* Now call second stage of pipeline to one by one + * check the result of our bulk lookup + */ + + /* prefetching for table entries should be done here */ + for (j = 0; j < n_pkts; j++) { + if (p_nat->lkup_indx[j] >= 0) + rte_prefetch0(&napt_hash_tbl_entries + [p_nat->lkup_indx[j]]); + } + + for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4) + pkt4_work_cgnapt_ipv4_pub(pkts, i, arg, p_nat); + + for (; i < n_pkts; i++) + pkt_work_cgnapt_ipv4_pub(pkts, i, arg, p_nat); + + if (p_nat->invalid_packets) { + /* get rid of invalid packets */ + rte_pipeline_ah_packet_drop(rte_p, p_nat->invalid_packets); + + p_nat->valid_packets &= ~(p_nat->invalid_packets); + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 1) { + printf("valid_packets:0x%jx\n", p_nat->valid_packets); + printf("rte_valid_packets :0x%jx\n", rte_p->pkts_mask); + printf("invalid_packets:0x%jx\n", + p_nat->invalid_packets); + printf("rte_invalid_packets :0x%jx\n", + rte_p->pkts_drop_mask); + printf("Total pkts dropped :0x%jx\n", + rte_p->n_pkts_ah_drop); + } + #endif + } + + #ifdef CGNAPT_TIMING_INST + if (p_nat->time_measurements_on) { + exit_timestamp = rte_get_tsc_cycles(); + p_nat->in_port_exit_timestamp = exit_timestamp; + + p_nat->internal_time_sum += exit_timestamp - entry_timestamp; + p_nat->time_measurements++; + if (p_nat->time_measurements == p_nat->max_time_mesurements) + p_nat->time_measurements_on = 0; + } + #endif + + return p_nat->valid_packets; +} + +/** + * NAPT key calculation function for IPv4 private traffic + * which handles 4 pkts + * + * @param pkt + * A pointer to array of packets mbuf + * @param in_pkt_num + * Starting pkt number of pkts + * @param arg + * Void pointer + * @param p_nat + * A pointer to main CGNAPT structure + * + */ +void +pkt4_work_cgnapt_key_ipv4_prv( + struct rte_mbuf **pkt, + uint32_t pkt_num, + __rte_unused void *arg, + struct pipeline_cgnapt *p_nat) +{ + p_nat->receivedPktCount += 4; + /* bitmask representing only this packet */ + uint64_t pkt_mask0 = 1LLU << pkt_num; + uint64_t pkt_mask1 = 1LLU << (pkt_num + 1); + uint64_t pkt_mask2 = 1LLU << (pkt_num + 2); + uint64_t pkt_mask3 = 1LLU << (pkt_num + 3); + + uint8_t protocol0 = RTE_MBUF_METADATA_UINT8(pkt[0], + PROT_OFST_IP4); + uint8_t protocol1 = RTE_MBUF_METADATA_UINT8(pkt[1], + PROT_OFST_IP4); + uint8_t protocol2 = RTE_MBUF_METADATA_UINT8(pkt[2], + PROT_OFST_IP4); + uint8_t protocol3 = RTE_MBUF_METADATA_UINT8(pkt[3], + PROT_OFST_IP4); + + uint32_t src_addr0 = RTE_MBUF_METADATA_UINT32(pkt[0], + SRC_ADR_OFST_IP4); + uint32_t src_addr1 = RTE_MBUF_METADATA_UINT32(pkt[1], + SRC_ADR_OFST_IP4); + uint32_t src_addr2 = RTE_MBUF_METADATA_UINT32(pkt[2], + SRC_ADR_OFST_IP4); + uint32_t src_addr3 = RTE_MBUF_METADATA_UINT32(pkt[3], + SRC_ADR_OFST_IP4); + + uint16_t src_port_offset0; + uint16_t src_port_offset1; + uint16_t src_port_offset2; + uint16_t src_port_offset3; + + uint16_t src_port0; + uint16_t src_port1; + uint16_t src_port2; + uint16_t src_port3; + + uint16_t phy_port0 = pkt[0]->port; + uint16_t phy_port1 = pkt[1]->port; + uint16_t phy_port2 = pkt[2]->port; + uint16_t phy_port3 = pkt[3]->port; + + struct pipeline_cgnapt_entry_key key0; + struct pipeline_cgnapt_entry_key key1; + struct pipeline_cgnapt_entry_key key2; + struct pipeline_cgnapt_entry_key key3; + + memset(&key0, 0, sizeof(struct pipeline_cgnapt_entry_key)); + memset(&key1, 0, sizeof(struct pipeline_cgnapt_entry_key)); + memset(&key2, 0, sizeof(struct pipeline_cgnapt_entry_key)); + memset(&key3, 0, sizeof(struct pipeline_cgnapt_entry_key)); + +/* --0-- */ + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 4) + print_pkt(pkt[0]); + #endif + + if (enable_hwlb) { + if (!check_arp_icmp(pkt[0], pkt_mask0, p_nat)) + goto PKT1; + } + + switch (protocol0) { + case IP_PROTOCOL_UDP: + { + #ifdef PCP_ENABLE + if (pcp_enable) { + struct udp_hdr *udp; + + udp = (struct udp_hdr *) + RTE_MBUF_METADATA_UINT8_PTR(pkt[0], + IPV4_UDP_OFST); + + if (rte_bswap16(udp->dst_port) == + PCP_SERVER_PORT) { + handle_pcp_req(pkt[0], IPV4_SZ, p_nat); + p_nat->invalid_packets |= pkt_mask0; + goto PKT1; + } + } + #endif + } + case IP_PROTOCOL_TCP: + + src_port_offset0 = SRC_PRT_OFST_IP4_TCP; + src_port0 = RTE_MBUF_METADATA_UINT16(pkt[0], + src_port_offset0); + + break; + + case IP_PROTOCOL_ICMP: + /* Identifier */ + src_port_offset0 = MBUF_HDR_ROOM + ETH_HDR_SIZE + + IP_HDR_SIZE + 4; + src_port0 = RTE_MBUF_METADATA_UINT16(pkt[0], + src_port_offset0); + + break; + + default: + /* remember invalid packets to be dropped */ + p_nat->invalid_packets |= pkt_mask0; + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount2++; + #endif + goto PKT1; + } + + key0.pid = phy_port0; + key0.ip = rte_bswap32(src_addr0); + key0.port = rte_bswap16(src_port0); + + #ifdef NAT_ONLY_CONFIG_REQ + if (nat_only_config_flag) + key0.port = 0xffff; + #endif + + memcpy(&p_nat->keys[pkt_num], &key0, + sizeof(struct pipeline_cgnapt_entry_key)); + p_nat->key_ptrs[pkt_num] = &p_nat->keys[pkt_num]; + +/* --1-- */ +PKT1: + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 4) + print_pkt(pkt[1]); + #endif + + if (enable_hwlb) { + if (!check_arp_icmp(pkt[1], pkt_mask1, p_nat)) + goto PKT2; + } + switch (protocol1) { + case IP_PROTOCOL_UDP: + { + #ifdef PCP_ENABLE + if (pcp_enable) { + struct udp_hdr *udp; + + udp = (struct udp_hdr *) + RTE_MBUF_METADATA_UINT8_PTR(pkt[1], + IPV4_UDP_OFST); + + if (rte_bswap16(udp->dst_port) == + PCP_SERVER_PORT) { + handle_pcp_req(pkt[1], IPV4_SZ, p_nat); + p_nat->invalid_packets |= pkt_mask1; + goto PKT2; + } + } + #endif + } + case IP_PROTOCOL_TCP: + + src_port_offset1 = SRC_PRT_OFST_IP4_TCP; + src_port1 = RTE_MBUF_METADATA_UINT16(pkt[1], + src_port_offset1); + + break; + + case IP_PROTOCOL_ICMP: + /* Identifier */ + src_port_offset1 = MBUF_HDR_ROOM + ETH_HDR_SIZE + + IP_HDR_SIZE + 4; + src_port1 = RTE_MBUF_METADATA_UINT16(pkt[1], + src_port_offset1); + + break; + + default: + /* remember invalid packets to be dropped */ + p_nat->invalid_packets |= pkt_mask1; + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount2++; + #endif + goto PKT2; + } + + key1.pid = phy_port1; + key1.ip = rte_bswap32(src_addr1); + key1.port = rte_bswap16(src_port1); + + #ifdef NAT_ONLY_CONFIG_REQ + if (nat_only_config_flag) + key1.port = 0xffff; + #endif + + memcpy(&p_nat->keys[pkt_num + 1], &key1, + sizeof(struct pipeline_cgnapt_entry_key)); + p_nat->key_ptrs[pkt_num + 1] = &p_nat->keys[pkt_num + 1]; + +/* --2-- */ +PKT2: + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 4) + print_pkt(pkt[2]); + #endif + + if (enable_hwlb) { + if (!check_arp_icmp(pkt[2], pkt_mask2, p_nat)) + goto PKT3; + } + + switch (protocol2) { + case IP_PROTOCOL_UDP: + { + #ifdef PCP_ENABLE + if (pcp_enable) { + struct udp_hdr *udp; + + udp = (struct udp_hdr *) + RTE_MBUF_METADATA_UINT8_PTR(pkt[2], + IPV4_UDP_OFST); + + if (rte_bswap16(udp->dst_port) == + PCP_SERVER_PORT) { + handle_pcp_req(pkt[2], IPV4_SZ, p_nat); + p_nat->invalid_packets |= pkt_mask2; + goto PKT3; + } + } + #endif + } + case IP_PROTOCOL_TCP: + + src_port_offset2 = SRC_PRT_OFST_IP4_TCP; + src_port2 = RTE_MBUF_METADATA_UINT16(pkt[2], + src_port_offset2); + + break; + + case IP_PROTOCOL_ICMP: + /* Identifier */ + src_port_offset2 = MBUF_HDR_ROOM + ETH_HDR_SIZE + + IP_HDR_SIZE + 4; + src_port2 = RTE_MBUF_METADATA_UINT16(pkt[2], + src_port_offset2); + + break; + + default: + /* remember invalid packets to be dropped */ + p_nat->invalid_packets |= pkt_mask2; + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount2++; + #endif + goto PKT3; + } + + key2.pid = phy_port2; + key2.ip = rte_bswap32(src_addr2); + key2.port = rte_bswap16(src_port2); + + #ifdef NAT_ONLY_CONFIG_REQ + if (nat_only_config_flag) + key2.port = 0xffff; + #endif + + memcpy(&p_nat->keys[pkt_num + 2], &key2, + sizeof(struct pipeline_cgnapt_entry_key)); + p_nat->key_ptrs[pkt_num + 2] = &p_nat->keys[pkt_num + 2]; + +/* --3-- */ +PKT3: + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 4) + print_pkt(pkt[3]); + #endif + if (enable_hwlb) { + if (!check_arp_icmp(pkt[3], pkt_mask3, p_nat)) + return; + } + + switch (protocol3) { + case IP_PROTOCOL_UDP: + { + #ifdef PCP_ENABLE + if (pcp_enable) { + struct udp_hdr *udp; + + udp = (struct udp_hdr *) + RTE_MBUF_METADATA_UINT8_PTR(pkt[3], + IPV4_UDP_OFST); + + if (rte_bswap16(udp->dst_port) == + PCP_SERVER_PORT) { + handle_pcp_req(pkt[3], IPV4_SZ, p_nat); + p_nat->invalid_packets |= pkt_mask3; + return; + } + } + #endif + } + case IP_PROTOCOL_TCP: + + src_port_offset3 = SRC_PRT_OFST_IP4_TCP; + src_port3 = RTE_MBUF_METADATA_UINT16(pkt[3], + src_port_offset3); + + break; + + case IP_PROTOCOL_ICMP: + /* Identifier */ + src_port_offset3 = MBUF_HDR_ROOM + ETH_HDR_SIZE + + IP_HDR_SIZE + 4; + src_port3 = RTE_MBUF_METADATA_UINT16(pkt[3], + src_port_offset3); + + break; + + default: + /* remember invalid packets to be dropped */ + p_nat->invalid_packets |= pkt_mask3; + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount2++; + #endif + return; + } + + key3.pid = phy_port3; + key3.ip = rte_bswap32(src_addr3); + key3.port = rte_bswap16(src_port3); + + #ifdef NAT_ONLY_CONFIG_REQ + if (nat_only_config_flag) + key3.port = 0xffff; + #endif + + memcpy(&p_nat->keys[pkt_num + 3], &key3, + sizeof(struct pipeline_cgnapt_entry_key)); + p_nat->key_ptrs[pkt_num + 3] = &p_nat->keys[pkt_num + 3]; +} + +/** + * NAPT key calculation function for IPv4 public traffic + * which handles 4 pkts + * + * @param pkt + * A pointer to array of packets mbuf + * @param in_pkt_num + * Starting pkt number of pkts + * @param arg + * Void pointer + * @param p_nat + * A pointer to main CGNAPT structure + * + */ +void +pkt4_work_cgnapt_key_ipv4_pub( + struct rte_mbuf **pkt, + uint32_t pkt_num, + __rte_unused void *arg, + struct pipeline_cgnapt *p_nat) +{ + p_nat->receivedPktCount += 4; + /* bitmask representing only this packet */ + uint64_t pkt_mask0 = 1LLU << pkt_num; + uint64_t pkt_mask1 = 1LLU << (pkt_num + 1); + uint64_t pkt_mask2 = 1LLU << (pkt_num + 2); + uint64_t pkt_mask3 = 1LLU << (pkt_num + 3); + + uint8_t protocol0 = RTE_MBUF_METADATA_UINT8(pkt[0], + PROT_OFST_IP4); + uint8_t protocol1 = RTE_MBUF_METADATA_UINT8(pkt[1], + PROT_OFST_IP4); + uint8_t protocol2 = RTE_MBUF_METADATA_UINT8(pkt[2], + PROT_OFST_IP4); + uint8_t protocol3 = RTE_MBUF_METADATA_UINT8(pkt[3], + PROT_OFST_IP4); + + uint32_t dst_addr0 = RTE_MBUF_METADATA_UINT32(pkt[0], + DST_ADR_OFST_IP4); + uint32_t dst_addr1 = RTE_MBUF_METADATA_UINT32(pkt[1], + DST_ADR_OFST_IP4); + uint32_t dst_addr2 = RTE_MBUF_METADATA_UINT32(pkt[2], + DST_ADR_OFST_IP4); + uint32_t dst_addr3 = RTE_MBUF_METADATA_UINT32(pkt[3], + DST_ADR_OFST_IP4); + + uint16_t src_port_offset0; + uint16_t src_port_offset1; + uint16_t src_port_offset2; + uint16_t src_port_offset3; + + uint16_t dst_port_offset0; + uint16_t dst_port_offset1; + uint16_t dst_port_offset2; + uint16_t dst_port_offset3; + + uint16_t src_port0; + uint16_t src_port1; + uint16_t src_port2; + uint16_t src_port3; + + uint16_t dst_port0; + uint16_t dst_port1; + uint16_t dst_port2; + uint16_t dst_port3; + + struct pipeline_cgnapt_entry_key key0; + struct pipeline_cgnapt_entry_key key1; + struct pipeline_cgnapt_entry_key key2; + struct pipeline_cgnapt_entry_key key3; + + memset(&key0, 0, sizeof(struct pipeline_cgnapt_entry_key)); + memset(&key1, 0, sizeof(struct pipeline_cgnapt_entry_key)); + memset(&key2, 0, sizeof(struct pipeline_cgnapt_entry_key)); + memset(&key3, 0, sizeof(struct pipeline_cgnapt_entry_key)); + +/* --0-- */ + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 4) + print_pkt(pkt[0]); + #endif + + if (enable_hwlb) { + if (!check_arp_icmp(pkt[0], pkt_mask0, p_nat)) + goto PKT1; + } + + switch (protocol0) { + case IP_PROTOCOL_UDP: + case IP_PROTOCOL_TCP: + + src_port_offset0 = SRC_PRT_OFST_IP4_TCP; + dst_port_offset0 = DST_PRT_OFST_IP4_TCP; + + src_port0 = RTE_MBUF_METADATA_UINT16(pkt[0], + src_port_offset0); + dst_port0 = RTE_MBUF_METADATA_UINT16(pkt[0], + dst_port_offset0); + + key0.port = rte_bswap16(dst_port0); + + break; + + case IP_PROTOCOL_ICMP: + /* Identifier */ + src_port_offset0 = MBUF_HDR_ROOM + ETH_HDR_SIZE + + IP_HDR_SIZE + 4; + /*Sequence number */ + dst_port_offset0 = MBUF_HDR_ROOM + ETH_HDR_SIZE + + IP_HDR_SIZE + 6; + + src_port0 = RTE_MBUF_METADATA_UINT16(pkt[0], + src_port_offset0); + dst_port0 = RTE_MBUF_METADATA_UINT16(pkt[0], + dst_port_offset0); + + key0.port = rte_bswap16(src_port0); + + break; + + default: + /* remember invalid packets to be dropped */ + p_nat->invalid_packets |= pkt_mask0; + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount2++; + #endif + goto PKT1; + } + + key0.pid = 0xffff; + key0.ip = rte_bswap32(dst_addr0); + + #ifdef NAT_ONLY_CONFIG_REQ + if (nat_only_config_flag) + key0.port = 0xffff; + #endif + + memcpy(&p_nat->keys[pkt_num], &key0, + sizeof(struct pipeline_cgnapt_entry_key)); + p_nat->key_ptrs[pkt_num] = &p_nat->keys[pkt_num]; + +/* --1-- */ +PKT1: + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 4) + print_pkt(pkt[1]); + #endif + + if (enable_hwlb) { + if (!check_arp_icmp(pkt[1], pkt_mask1, p_nat)) + goto PKT2; + } + + switch (protocol1) { + case IP_PROTOCOL_UDP: + case IP_PROTOCOL_TCP: + + src_port_offset1 = SRC_PRT_OFST_IP4_TCP; + dst_port_offset1 = DST_PRT_OFST_IP4_TCP; + + src_port1 = RTE_MBUF_METADATA_UINT16(pkt[1], + src_port_offset1); + dst_port1 = RTE_MBUF_METADATA_UINT16(pkt[1], + dst_port_offset1); + + key1.port = rte_bswap16(dst_port1); + + break; + + case IP_PROTOCOL_ICMP: + /* Identifier */ + src_port_offset1 = MBUF_HDR_ROOM + ETH_HDR_SIZE + + IP_HDR_SIZE + 4; + /*Sequence number */ + dst_port_offset1 = MBUF_HDR_ROOM + ETH_HDR_SIZE + + IP_HDR_SIZE + 6; + + src_port1 = RTE_MBUF_METADATA_UINT16(pkt[1], + src_port_offset1); + dst_port1 = RTE_MBUF_METADATA_UINT16(pkt[1], + dst_port_offset1); + + key1.port = rte_bswap16(src_port1); + break; + + default: + /* remember invalid packets to be dropped */ + p_nat->invalid_packets |= pkt_mask1; + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount2++; + #endif + goto PKT2; + } + + key1.pid = 0xffff; + key1.ip = rte_bswap32(dst_addr1); + + #ifdef NAT_ONLY_CONFIG_REQ + if (nat_only_config_flag) + key1.port = 0xffff; + #endif + + memcpy(&p_nat->keys[pkt_num + 1], &key1, + sizeof(struct pipeline_cgnapt_entry_key)); + p_nat->key_ptrs[pkt_num + 1] = &p_nat->keys[pkt_num + 1]; + +/* --2-- */ +PKT2: + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 4) + print_pkt(pkt[2]); + #endif + + if (enable_hwlb) { + if (!check_arp_icmp(pkt[2], pkt_mask2, p_nat)) + goto PKT3; + } + + switch (protocol2) { + case IP_PROTOCOL_UDP: + case IP_PROTOCOL_TCP: + + src_port_offset2 = SRC_PRT_OFST_IP4_TCP; + dst_port_offset2 = DST_PRT_OFST_IP4_TCP; + + src_port2 = RTE_MBUF_METADATA_UINT16(pkt[2], + src_port_offset2); + dst_port2 = RTE_MBUF_METADATA_UINT16(pkt[2], + dst_port_offset2); + + key2.port = rte_bswap16(dst_port2); + + break; + + case IP_PROTOCOL_ICMP: + /* Identifier */ + src_port_offset2 = MBUF_HDR_ROOM + ETH_HDR_SIZE + + IP_HDR_SIZE + 4; + /*Sequence number */ + dst_port_offset2 = MBUF_HDR_ROOM + ETH_HDR_SIZE + + IP_HDR_SIZE + 6; + + src_port2 = RTE_MBUF_METADATA_UINT16(pkt[2], + src_port_offset2); + dst_port2 = RTE_MBUF_METADATA_UINT16(pkt[2], + dst_port_offset2); + + key2.port = rte_bswap16(src_port2); + + break; + + default: + /* remember invalid packets to be dropped */ + p_nat->invalid_packets |= pkt_mask2; + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount2++; + #endif + goto PKT3; + } + + key2.pid = 0xffff; + key2.ip = rte_bswap32(dst_addr2); + + #ifdef NAT_ONLY_CONFIG_REQ + if (nat_only_config_flag) + key2.port = 0xffff; + #endif + + memcpy(&p_nat->keys[pkt_num + 2], &key2, + sizeof(struct pipeline_cgnapt_entry_key)); + p_nat->key_ptrs[pkt_num + 2] = &p_nat->keys[pkt_num + 2]; + +/* --3-- */ +PKT3: + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 4) + print_pkt(pkt[3]); + #endif + + if (enable_hwlb) { + if (!check_arp_icmp(pkt[3], pkt_mask3, p_nat)) + return; + } + + switch (protocol3) { + case IP_PROTOCOL_UDP: + case IP_PROTOCOL_TCP: + + src_port_offset3 = SRC_PRT_OFST_IP4_TCP; + dst_port_offset3 = DST_PRT_OFST_IP4_TCP; + + src_port3 = RTE_MBUF_METADATA_UINT16(pkt[3], + src_port_offset3); + dst_port3 = RTE_MBUF_METADATA_UINT16(pkt[3], + dst_port_offset3); + + key3.port = rte_bswap16(dst_port3); + + break; + + case IP_PROTOCOL_ICMP: + /* Identifier */ + src_port_offset3 = MBUF_HDR_ROOM + ETH_HDR_SIZE + + IP_HDR_SIZE + 4; + /*Sequence number */ + dst_port_offset3 = MBUF_HDR_ROOM + ETH_HDR_SIZE + + IP_HDR_SIZE + 6; + + src_port3 = RTE_MBUF_METADATA_UINT16(pkt[3], + src_port_offset3); + dst_port3 = RTE_MBUF_METADATA_UINT16(pkt[3], + dst_port_offset3); + + key3.port = rte_bswap16(src_port3); + + break; + + default: + /* remember invalid packets to be dropped */ + p_nat->invalid_packets |= pkt_mask3; + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount2++; + #endif + return; + } + + key3.pid = 0xffff; + key3.ip = rte_bswap32(dst_addr3); + + #ifdef NAT_ONLY_CONFIG_REQ + if (nat_only_config_flag) + key3.port = 0xffff; + #endif + + memcpy(&p_nat->keys[pkt_num + 3], &key3, + sizeof(struct pipeline_cgnapt_entry_key)); + p_nat->key_ptrs[pkt_num + 3] = &p_nat->keys[pkt_num + 3]; +} + +/** + * NAPT key calculation function for IPv4 private traffic + * which handles 1 pkt + * + * @param pkt + * A pointer to array of packets mbuf + * @param in_pkt_num + * Pkt number of pkts + * @param arg + * Void pointer + * @param p_nat + * A pointer to main CGNAPT structure + * + */ +void +pkt_work_cgnapt_key_ipv4_prv( + struct rte_mbuf *pkt, + uint32_t pkt_num, + __rte_unused void *arg, + struct pipeline_cgnapt *p_nat) +{ + /* Egress */ + p_nat->receivedPktCount++; + + /* bitmask representing only this packet */ + uint64_t pkt_mask = 1LLU << pkt_num; + uint8_t protocol = RTE_MBUF_METADATA_UINT8(pkt, PROT_OFST_IP4); + + uint32_t src_addr = RTE_MBUF_METADATA_UINT32(pkt, SRC_ADR_OFST_IP4); + + uint16_t src_port_offset; + + uint16_t src_port; + + uint16_t phy_port = pkt->port; + struct pipeline_cgnapt_entry_key key; + + memset(&key, 0, sizeof(struct pipeline_cgnapt_entry_key)); + + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 4) + print_pkt(pkt); + #endif + + if (enable_hwlb) { + if (!check_arp_icmp(pkt, pkt_mask, p_nat)) + return; + } + + switch (protocol) { + case IP_PROTOCOL_UDP: + { + #ifdef PCP_ENABLE + if (pcp_enable) { + struct udp_hdr *udp; + + udp = (struct udp_hdr *) + RTE_MBUF_METADATA_UINT8_PTR(pkt, + IPV4_UDP_OFST); + + if (rte_bswap16(udp->dst_port) == + PCP_SERVER_PORT) { + handle_pcp_req(pkt, IPV4_SZ, p_nat); + p_nat->invalid_packets |= pkt_mask; + return; + } + } + #endif + } + case IP_PROTOCOL_TCP: + + src_port_offset = SRC_PRT_OFST_IP4_TCP; + src_port = RTE_MBUF_METADATA_UINT16(pkt, src_port_offset); + + key.port = rte_bswap16(src_port); + + break; + case IP_PROTOCOL_ICMP: + /* Identifier */ + src_port_offset = MBUF_HDR_ROOM + ETH_HDR_SIZE + + IP_HDR_SIZE + 4; + src_port = RTE_MBUF_METADATA_UINT16(pkt, src_port_offset); + + key.port = rte_bswap16(src_port); + + break; + default: + /* remember invalid packets to be dropped */ + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount2++; + #endif + return; + } + + key.pid = phy_port; + key.ip = rte_bswap32(src_addr); + + #ifdef NAT_ONLY_CONFIG_REQ + if (nat_only_config_flag) + key.port = 0xffff; + #endif + + memcpy(&p_nat->keys[pkt_num], &key, + sizeof(struct pipeline_cgnapt_entry_key)); + p_nat->key_ptrs[pkt_num] = &p_nat->keys[pkt_num]; +} + +/** + * NAPT key calculation function for IPv4 public traffic + * which handles 1 pkt + * + * @param pkt + * A pointer to array of packets mbuf + * @param in_pkt_num + * Pkt number of pkts + * @param arg + * Void pointer + * @param p_nat + * A pointer to main CGNAPT structure + * + */ +void +pkt_work_cgnapt_key_ipv4_pub( + struct rte_mbuf *pkt, + uint32_t pkt_num, + __rte_unused void *arg, + struct pipeline_cgnapt *p_nat) +{ + p_nat->receivedPktCount++; + + /* bitmask representing only this packet */ + uint64_t pkt_mask = 1LLU << pkt_num; + uint8_t protocol = RTE_MBUF_METADATA_UINT8(pkt, PROT_OFST_IP4); + uint32_t dst_addr = RTE_MBUF_METADATA_UINT32(pkt, DST_ADR_OFST_IP4); + uint16_t src_port_offset; + uint16_t dst_port_offset; + uint16_t src_port; + uint16_t dst_port; + struct pipeline_cgnapt_entry_key key; + memset(&key, 0, sizeof(struct pipeline_cgnapt_entry_key)); + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 4) + print_pkt(pkt); + #endif + + if (enable_hwlb) { + if (!check_arp_icmp(pkt, pkt_mask, p_nat)) + return; + } + + switch (protocol) { + case IP_PROTOCOL_UDP: + case IP_PROTOCOL_TCP: + src_port_offset = SRC_PRT_OFST_IP4_TCP; + dst_port_offset = DST_PRT_OFST_IP4_TCP; + + src_port = RTE_MBUF_METADATA_UINT16(pkt, src_port_offset); + dst_port = RTE_MBUF_METADATA_UINT16(pkt, dst_port_offset); + + key.port = rte_bswap16(dst_port); + break; + case IP_PROTOCOL_ICMP: + /* Identifier */ + src_port_offset = MBUF_HDR_ROOM + ETH_HDR_SIZE + + IP_HDR_SIZE + 4; + dst_port_offset = MBUF_HDR_ROOM + ETH_HDR_SIZE + + IP_HDR_SIZE + 6; + + src_port = RTE_MBUF_METADATA_UINT16(pkt, src_port_offset); + dst_port = RTE_MBUF_METADATA_UINT16(pkt, dst_port_offset); + + /* common table lookupkey preparation from incoming + * ICMP Packet- Indentifier field + */ + key.port = rte_bswap16(src_port); + break; + default: + /* remember invalid packets to be dropped */ + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount2++; + #endif + return; + } + + key.ip = rte_bswap32(dst_addr); + + #ifdef NAT_ONLY_CONFIG_REQ + if (nat_only_config_flag) + key.port = 0xffff; + #endif + + key.pid = 0xffff; + + memcpy(&p_nat->keys[pkt_num], &key, + sizeof(struct pipeline_cgnapt_entry_key)); + p_nat->key_ptrs[pkt_num] = &p_nat->keys[pkt_num]; +} + + +/** + * NAPT function for IPv4 private traffic which handles 1 pkt + * + * @param pkts + * A pointer to array of packet mbuf + * @param in_pkt_num + * Pkt number of pkt + * @param arg + * Void pointer + * @param p_nat + * A pointer to main CGNAPT structure + * + */ +void +pkt_work_cgnapt_ipv4_prv( + struct rte_mbuf **pkts, + uint32_t pkt_num, + __rte_unused void *arg, + struct pipeline_cgnapt *p_nat) +{ + #ifdef CT_CGNAT + struct rte_CT_helper ct_helper; + memset(&ct_helper, 0, sizeof(struct rte_CT_helper)); + #endif + + /* index into hash table entries */ + int hash_table_entry = p_nat->lkup_indx[pkt_num]; + /*bitmask representing only this packet */ + uint64_t pkt_mask = 1LLU << pkt_num; + struct rte_mbuf *pkt = pkts[pkt_num]; + + uint8_t protocol = RTE_MBUF_METADATA_UINT8(pkt, PROT_OFST_IP4); + + uint32_t dest_if = 0xff; /* Added for Multiport */ + uint16_t *outport_id = + RTE_MBUF_METADATA_UINT16_PTR(pkt, cgnapt_meta_offset); + + struct cgnapt_table_entry *entry = NULL; + + enum PKT_TYPE pkt_type = PKT_TYPE_IPV4; + + if (hash_table_entry < 0) { + + /* try to add new entry */ + struct rte_pipeline_table_entry *table_entry = NULL; + + uint64_t dropmask = pkt_miss_cgnapt(p_nat->key_ptrs[pkt_num], + pkt, &table_entry, + &p_nat->valid_packets, pkt_num, + (void *)p_nat); + + if (!table_entry) { + /* ICMP Error message generation for Destination + * Host unreachable + */ + if (protocol == IP_PROTOCOL_ICMP) { + cgnapt_icmp_pkt = pkt; + send_icmp_dest_unreachable_msg(); + } + + /* Drop packet by adding to invalid pkt mask */ + + p_nat->invalid_packets |= dropmask; + #ifdef CGNAPT_DEBUGGING + if (p_nat->kpc2++ < 5) { + printf("in_ah Th: %d", p_nat->pipeline_num); + print_key(p_nat->key_ptrs[pkt_num]); + } + #endif + + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount3++; + #endif + return; + } + + entry = (struct cgnapt_table_entry *)table_entry; + } else { + /* entry found for this packet */ + entry = &napt_hash_tbl_entries[hash_table_entry]; + } + + /* apply napt and mac changes */ + + p_nat->entries[pkt_num] = &(entry->head); + + uint32_t *src_addr = + RTE_MBUF_METADATA_UINT32_PTR(pkt, SRC_ADR_OFST_IP4); + uint32_t *dst_addr = + RTE_MBUF_METADATA_UINT32_PTR(pkt, DST_ADR_OFST_IP4); + uint16_t src_port_offset = 0; + uint16_t dst_port_offset = 0; + uint16_t *src_port; + uint16_t *dst_port; + + switch (protocol) { + case IP_PROTOCOL_TCP: + src_port_offset = SRC_PRT_OFST_IP4_TCP; + dst_port_offset = DST_PRT_OFST_IP4_TCP; + src_port = RTE_MBUF_METADATA_UINT16_PTR(pkt, src_port_offset); + dst_port = RTE_MBUF_METADATA_UINT16_PTR(pkt, dst_port_offset); + + #ifdef CT_CGNAT + if ((rte_be_to_cpu_16(*src_port) == 21) || + rte_be_to_cpu_16(*dst_port) == 21) { + + #ifdef ALGDBG + printf("cgnapt_ct_process: pkt_mask: % "PRIu64", " + "pkt_num: %d\n", pkt_mask, pkt_num); + #endif + + pkt_mask = cgnapt_ct_process(cgnat_cnxn_tracker, pkts, + pkt_mask, &ct_helper); + } + #endif + break; + case IP_PROTOCOL_UDP: + src_port_offset = SRC_PRT_OFST_IP4_TCP; + dst_port_offset = DST_PRT_OFST_IP4_TCP; + src_port = RTE_MBUF_METADATA_UINT16_PTR(pkt, src_port_offset); + dst_port = RTE_MBUF_METADATA_UINT16_PTR(pkt, dst_port_offset); + break; + case IP_PROTOCOL_ICMP: + /* Identifier */ + src_port_offset = MBUF_HDR_ROOM + ETH_HDR_SIZE + + IP_HDR_SIZE + 4; + /*Sequence number */ + dst_port_offset = MBUF_HDR_ROOM + ETH_HDR_SIZE + + IP_HDR_SIZE + 6; + src_port = RTE_MBUF_METADATA_UINT16_PTR(pkt, src_port_offset); + dst_port = RTE_MBUF_METADATA_UINT16_PTR(pkt, dst_port_offset); + break; + } + + 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 (entry->data.ttl == NAPT_ENTRY_STALE) + entry->data.ttl = NAPT_ENTRY_VALID; + + struct ether_addr hw_addr; + uint32_t dest_address = 0; + + /* Egress */ + if (unlikely(protocol == IP_PROTOCOL_UDP + && rte_be_to_cpu_16(*dst_port) == 53)) { + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount6++; + #endif + return; + } + + dest_address = rte_bswap32(*dst_addr); + /*Multiport Changes */ + uint32_t nhip = 0; + uint32_t ret; + ret = local_get_nh_ipv4(dest_address, &dest_if, &nhip, p_nat); + if (!ret) { + dest_if = get_prv_to_pub_port(&dest_address, IP_VERSION_4); + + if (dest_if == INVALID_DESTIF) { + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount6++; + #endif + return; + } + + do_local_nh_ipv4_cache(dest_if, p_nat); + } + + *outport_id = p_nat->outport_id[dest_if]; + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 2) + printf("Egress: \tphy_port:%d\t get_prv_to_pub():%d " + "\tout_port:%d\n", pkt->port, dest_if, + *outport_id); + #endif + + if (local_dest_mac_present(dest_if)) { + memcpy(eth_dest, + get_local_link_hw_addr(dest_if), + sizeof(struct ether_addr)); + memcpy(eth_src, get_link_hw_addr(dest_if), + sizeof(struct ether_addr)); + } else { + int ret; + ret = get_dest_mac_addr_port(dest_address, &dest_if, &hw_addr); + + if (unlikely(ret != ARP_FOUND)) { + + if (unlikely(ret == ARP_NOT_FOUND)) { + //request_arp(*outport_id, nhip, p_nat->p.p); + printf("%s: ARP Not Found, nhip: %x, " + "outport_id: %d\n", __func__, nhip, + *outport_id); + } + + /* Drop the pkt */ + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount4++; + #endif + return; + + } + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 2) { + printf("MAC found for ip 0x%x, port %d - %02x:%02x: " + "%02x:%02x:%02x:%02x\n", dest_address, + *outport_id, + hw_addr.addr_bytes[0], hw_addr.addr_bytes[1], + hw_addr.addr_bytes[2], hw_addr.addr_bytes[3], + hw_addr.addr_bytes[4], hw_addr.addr_bytes[5]); + + printf("Dest MAC before - %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]); + } + + #endif + + memcpy(eth_dest, &hw_addr, sizeof(struct ether_addr)); + + link_hw_laddr_valid[dest_if] = 1; + memcpy(&link_hw_laddr[dest_if], &hw_addr, + sizeof(struct ether_addr)); + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 2) { + printf("Dest MAC after - %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]); + } + #endif + + memcpy(eth_src, get_link_hw_addr(dest_if), + sizeof(struct ether_addr)); + } + + { + /* Egress */ + *src_addr = rte_bswap32(entry->data.pub_ip); + + + #ifdef NAT_ONLY_CONFIG_REQ + if (!nat_only_config_flag) { + #endif + *src_port = rte_bswap16(entry->data.pub_port); + #ifdef NAT_ONLY_CONFIG_REQ + } + #endif + + #ifdef SIP_ALG + uint16_t rtp_port = 0, rtcp_port = 0; + struct cgnapt_table_entry *entry_ptr1 = NULL, + *entry_ptr2 = NULL, *entry_ptr3 = NULL, + *entry_ptr4 = NULL; + + if (unlikely(protocol == IP_PROTOCOL_UDP + && (rte_be_to_cpu_16(*dst_port) == 5060 + || rte_be_to_cpu_16(*src_port) == 5060))) { + + int ret = natSipAlgGetAudioPorts(pkt, &rtp_port, + &rtcp_port); + /* Commented code may be required for debug + * and future use, Please keep it*/ + #if 0 + if (ret < 0) { + printf("%s: Wrong SIP ALG packet1\n", + __func__); + p_nat->invalid_packets |= pkt_mask; + + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount4++; + #endif + return; + } + #endif + + if (ret >= 0 && rtp_port != 0) { + struct pipeline_cgnapt_entry_key rtp_key; + rtp_key.ip = entry->data.u.prv_ip; + rtp_key.port = rtp_port; + rtp_key.pid = entry->data.prv_phy_port; + + if (add_dynamic_cgnapt_entry_alg( + (struct pipeline *)p_nat, &rtp_key, + &entry_ptr1, &entry_ptr2) == 0) { + printf("%s: Wrong SIP ALG packet2\n", + __func__); + p_nat->invalid_packets |= pkt_mask; + + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount4++; + #endif + return; + } + } + + if (ret >= 0 && rtcp_port != 0) { + struct pipeline_cgnapt_entry_key rtcp_key; + rtcp_key.ip = entry->data.u.prv_ip; + rtcp_key.port = rtcp_port; + rtcp_key.pid = entry->data.prv_phy_port; + + if (add_dynamic_cgnapt_entry_alg( + (struct pipeline *)p_nat, &rtcp_key, + &entry_ptr3, &entry_ptr4) == 0) { + printf("%s: Wrong SIP ALG packet3\n", + __func__); + p_nat->invalid_packets |= pkt_mask; + + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount4++; + #endif + return; + } + + } + //if(entry_ptr1 != NULL && entry_ptr3 != NULL) + if (sip_alg_dpi(pkt, PRIVATE, entry->data.pub_ip, + entry->data.pub_port, entry->data.u.prv_ip, + entry->data.prv_port, (rtp_port == 0) ? 0 : + entry_ptr1->data.pub_port, + (rtcp_port == 0) ? 0 : + entry_ptr3->data.pub_port) == 0) { + + printf("%s: Wrong SIP ALG packet4\n", + __func__); + p_nat->invalid_packets |= pkt_mask; + + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount4++; + #endif + return; + } + } + #endif /* SIP_ALG */ + + #ifdef FTP_ALG + + #ifdef ALGDBG + printf("@CGNAT-pktwork ct_position :%d, pkt_num %d pkt_mask= " + "%" PRIu64 "\n", ct_position, pkt_num, pkt_mask); + #endif + + if ((rte_be_to_cpu_16(*src_port) == 21) || + rte_be_to_cpu_16(*dst_port) == 21) { + + int32_t ct_position = cgnat_cnxn_tracker->positions[pkt_num]; + if (ct_position < 0){ + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + return; + } + /* Commented code may be required for future usage, + * Please keep it + */ + //if (cgnat_cnxn_tracker->hash_table_entries + // [ct_position].alg_bypass_flag != BYPASS) + { + struct pipeline_cgnapt_entry_key data_channel_entry_key; + + data_channel_entry_key.ip = entry->data.pub_ip; + data_channel_entry_key.port = entry->data.pub_port; + data_channel_entry_key.pid = pkt->port; + ftp_alg_dpi(p_nat, &data_channel_entry_key, pkt, + cgnat_cnxn_tracker, ct_position, PRIVATE); + } + } + #endif /* FTP_ALG */ + + p_nat->enaptedPktCount++; + } + + p_nat->naptedPktCount++; + + #ifdef HW_CHECKSUM_REQ + if (p_nat->hw_checksum_reqd) + hw_checksum(pkt, pkt_type); + else + #endif + sw_checksum(pkt, pkt_type); + +} + + +/** + * NAPT function for IPv4 public traffic which handles 1 pkt + * + * @param pkts + * A pointer to array of packet mbuf + * @param in_pkt_num + * Pkt number of pkt + * @param arg + * Void pointer + * @param p_nat + * A pointer to main CGNAPT structure + * + */ +void +pkt_work_cgnapt_ipv4_pub( + struct rte_mbuf **pkts, + uint32_t pkt_num, + __rte_unused void *arg, + struct pipeline_cgnapt *p_nat) +{ + + #ifdef CT_CGNAT + struct rte_CT_helper ct_helper; + memset(&ct_helper, 0, sizeof(struct rte_CT_helper)); + #endif + + /* index into hash table entries */ + int hash_table_entry = p_nat->lkup_indx[pkt_num]; + /*bitmask representing only this packet */ + uint64_t pkt_mask = 1LLU << pkt_num; + struct rte_mbuf *pkt = pkts[pkt_num]; + + uint8_t protocol = RTE_MBUF_METADATA_UINT8(pkt, PROT_OFST_IP4); + + uint32_t dest_if = 0xff; /* Added for Multiport */ + uint16_t *outport_id = + RTE_MBUF_METADATA_UINT16_PTR(pkt, cgnapt_meta_offset); + + struct cgnapt_table_entry *entry = NULL; + + enum PKT_TYPE pkt_type = PKT_TYPE_IPV4; + + if (hash_table_entry < 0) { + + /* try to add new entry */ + struct rte_pipeline_table_entry *table_entry = NULL; + + uint64_t dropmask = pkt_miss_cgnapt(p_nat->key_ptrs[pkt_num], + pkt, &table_entry, + &p_nat->valid_packets, pkt_num, + (void *)p_nat); + + if (!table_entry) { + /* ICMP Error message generation for + * Destination Host unreachable + */ + if (protocol == IP_PROTOCOL_ICMP) { + cgnapt_icmp_pkt = pkt; + send_icmp_dest_unreachable_msg(); + } + + /* Drop packet by adding to invalid pkt mask */ + + p_nat->invalid_packets |= dropmask; + #ifdef CGNAPT_DEBUGGING + if (p_nat->kpc2++ < 5) { + printf("in_ah Th: %d", p_nat->pipeline_num); + print_key(p_nat->key_ptrs[pkt_num]); + } + #endif + + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount3++; + #endif + return; + } + + entry = (struct cgnapt_table_entry *)table_entry; + } else { + /* entry found for this packet */ + entry = &napt_hash_tbl_entries[hash_table_entry]; + } + + /* apply napt and mac changes */ + + p_nat->entries[pkt_num] = &(entry->head); + + uint32_t *dst_addr = + RTE_MBUF_METADATA_UINT32_PTR(pkt, DST_ADR_OFST_IP4); + uint16_t src_port_offset = 0; + uint16_t dst_port_offset = 0; + + if ((protocol == IP_PROTOCOL_TCP) || (protocol == IP_PROTOCOL_UDP)) { + src_port_offset = SRC_PRT_OFST_IP4_TCP; + dst_port_offset = DST_PRT_OFST_IP4_TCP; + } else if (protocol == IP_PROTOCOL_ICMP) { + /* Identifier */ + src_port_offset = MBUF_HDR_ROOM + + ETH_HDR_SIZE + + IP_HDR_SIZE + 4; + /*Sequence number */ + dst_port_offset = MBUF_HDR_ROOM + + ETH_HDR_SIZE + + IP_HDR_SIZE + 6; + } + + uint16_t *src_port = RTE_MBUF_METADATA_UINT16_PTR(pkt, src_port_offset); + uint16_t *dst_port = RTE_MBUF_METADATA_UINT16_PTR(pkt, dst_port_offset); + + 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 (entry->data.ttl == NAPT_ENTRY_STALE) + entry->data.ttl = NAPT_ENTRY_VALID; + + struct ether_addr hw_addr; + uint32_t dest_address = 0; + + /* Multiport Changes */ + uint32_t nhip = 0; + uint32_t ret; + + { + /* Ingress */ + if (unlikely(protocol == IP_PROTOCOL_UDP + && rte_be_to_cpu_16(*src_port) == 53)) { + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount6++; + #endif + return; + } + + dest_address = entry->data.u.prv_ip; + + ret = local_get_nh_ipv4(dest_address, &dest_if, &nhip, p_nat); + if (!ret) { + dest_if = get_prv_to_pub_port(&dest_address, IP_VERSION_4); + + if (dest_if == INVALID_DESTIF) { + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount6++; + #endif + return; + } + + do_local_nh_ipv4_cache(dest_if, p_nat); + } + + *outport_id = p_nat->outport_id[dest_if]; + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 2) + printf("Ingress: \tphy_port:%d\t get_pub_to_prv():%d " + "\tout_port%d\n", pkt->port, dest_if, *outport_id); + #endif + } + + if (local_dest_mac_present(dest_if)) { + memcpy(eth_dest, + get_local_link_hw_addr(dest_if), + sizeof(struct ether_addr)); + memcpy(eth_src, get_link_hw_addr(dest_if), + sizeof(struct ether_addr)); + } else { + int ret; + ret = get_dest_mac_addr_port(dest_address, &dest_if, &hw_addr); + + if (unlikely(ret != ARP_FOUND)) { + + if (unlikely(ret == ARP_NOT_FOUND)) { + /* Commented code may be required for debug + * and future use, Please keep it */ + //request_arp(*outport_id, nhip, p_nat->p.p); + printf("%s: ARP Not Found, nhip: %x, " + "outport_id: %d\n", __func__, nhip, + *outport_id); + + } + + /* Drop the pkt */ + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount4++; + #endif + return; + + } + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 2) { + printf + ("MAC found for ip 0x%x, port %d - %02x:%02x: " + "%02x:%02x:%02x:%02x\n", dest_address, + *outport_id, + hw_addr.addr_bytes[0], hw_addr.addr_bytes[1], + hw_addr.addr_bytes[2], hw_addr.addr_bytes[3], + hw_addr.addr_bytes[4], hw_addr.addr_bytes[5] + ); + + printf + ("Dest MAC before - %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]); + } + #endif + + memcpy(eth_dest, &hw_addr, sizeof(struct ether_addr)); + + link_hw_laddr_valid[dest_if] = 1; + memcpy(&link_hw_laddr[dest_if], &hw_addr, + sizeof(struct ether_addr)); + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 2) { + printf("Dest MAC after - " + "%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]); + } + #endif + + memcpy(eth_src, get_link_hw_addr(dest_if), + sizeof(struct ether_addr)); + } + + { + /* Ingress */ + + *dst_addr = rte_bswap32(entry->data.u.prv_ip); + if (protocol == IP_PROTOCOL_ICMP) { + /* Query ID reverse translation done here */ + /* dont care sequence num */ + *src_port = rte_bswap16(entry->data.prv_port); + } else { + + #ifdef NAT_ONLY_CONFIG_REQ + if (!nat_only_config_flag) { + #endif + *dst_port = rte_bswap16(entry->data.prv_port); + + #ifdef NAT_ONLY_CONFIG_REQ + } + #endif + #ifdef CT_CGNAT + if ((rte_be_to_cpu_16(*src_port) == 21) || + rte_be_to_cpu_16(*dst_port) == 21) { + pkt_mask = cgnapt_ct_process(cgnat_cnxn_tracker, pkts, + pkt_mask, &ct_helper); + } + #endif + } + + #ifdef SIP_ALG + uint16_t rtp_port = 0, rtcp_port = 0; + struct cgnapt_table_entry *entry_ptr1 = NULL, + *entry_ptr3 = NULL; + + /* Commented code may be required for debug + * and future use, Please keep it */ + #if 0 + struct cgnapt_table_entry *entry_ptr2 = NULL, + *entry_ptr4 = NULL; + #endif + + if (unlikely(protocol == IP_PROTOCOL_UDP + && (rte_be_to_cpu_16(*dst_port) == 5060 + || rte_be_to_cpu_16(*src_port) == 5060))) { + /* Commented code may be required for future usage, + * Please keep it + */ + #if 0 + int ret = natSipAlgGetAudioPorts(pkt, &rtp_port, + &rtcp_port); + if (ret < 0) { + printf("%s: Wrong SIP ALG packet1\n", + __func__); + p_nat->invalid_packets |= pkt_mask; + + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount4++; + #endif + return; + } + if (rtp_port != 0) { + struct pipeline_cgnapt_entry_key rtp_key; + rtp_key.ip = entry->data.pub_ip; + rtp_key.port = rtp_port; + rtp_key.pid = 0xffff; + + if (retrieve_cgnapt_entry_alg(&rtp_key, + &entry_ptr1, &entry_ptr2) == 0) { + printf("%s: Wrong SIP ALG packet2\n", + __func__); + p_nat->invalid_packets |= pkt_mask; + + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount4++; + #endif + return; + } + } + + if (rtcp_port != 0) { + struct pipeline_cgnapt_entry_key rtcp_key; + rtcp_key.ip = entry->data.pub_ip; + rtcp_key.port = rtcp_port; + rtcp_key.pid = 0xffff; + + if (retrieve_cgnapt_entry_alg(&rtcp_key, + &entry_ptr3, &entry_ptr4) == 0) { + printf("%s: Wrong SIP ALG packet3\n", + __func__); + p_nat->invalid_packets |= pkt_mask; + + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount4++; + #endif + return; + } + + } + #endif + + if (sip_alg_dpi(pkt, PUBLIC, entry->data.u.prv_ip, + entry->data.prv_port, entry->data.pub_ip, + entry->data.pub_port, (rtp_port == 0) ? 0 : + entry_ptr1->data.prv_port, + (rtcp_port == 0) ? 0 : + entry_ptr3->data.prv_port) == 0) { + + printf("%s: Wrong SIP ALG packet4\n", + __func__); + p_nat->invalid_packets |= pkt_mask; + + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount4++; + #endif + return; + + } + } + #endif /* SIP_ALG */ + + #ifdef FTP_ALG + if ((rte_be_to_cpu_16(*src_port) == 21) || + rte_be_to_cpu_16(*dst_port) == 21) { + int32_t ct_position = cgnat_cnxn_tracker-> + positions[pkt_num]; + if (ct_position < 0){ + p_nat->invalid_packets |= pkt_mask; + + p_nat->naptDroppedPktCount++; + return; + } + #ifdef ALGDBG + rte_hexdump(stdout, "CT Entry", &cgnat_cnxn_tracker-> + hash_table_entries[ct_position].key, 40); + #endif + + /* Commented code may be required for debug + * and future use, Please keep it*/ + //if (cgnat_cnxn_tracker->hash_table_entries + // [ct_position].alg_bypass_flag != BYPASS) + { + /*enable ALG DPI */ + struct pipeline_cgnapt_entry_key + data_channel_entry_key; + + data_channel_entry_key.ip = entry->data.pub_ip; + data_channel_entry_key.port = entry->data.pub_port; + data_channel_entry_key.pid = 0xffff; + //printf("pkt_work_pub ftp_alg_dpi\n"); + ftp_alg_dpi(p_nat, &data_channel_entry_key, pkt, + cgnat_cnxn_tracker, ct_position, PUBLIC); + + } + } + #endif + + p_nat->inaptedPktCount++; + } + + p_nat->naptedPktCount++; + + #ifdef HW_CHECKSUM_REQ + if (p_nat->hw_checksum_reqd) + hw_checksum(pkt, pkt_type); + else + #endif + sw_checksum(pkt, pkt_type); +} + + +/** + * NAPT function for IPv4 private traffic which handles 4 pkts + * + * @param pkts + * A pointer to array of packets mbuf + * @param in_pkt_num + * Starting pkt number of pkts + * @param arg + * Void pointer + * @param p_nat + * A pointer to main CGNAPT structure + * + */ +void +pkt4_work_cgnapt_ipv4_prv( + struct rte_mbuf **pkts, + uint32_t in_pkt_num, + __rte_unused void *arg, + struct pipeline_cgnapt *p_nat) +{ + uint32_t dest_if = 0xff; /* Added for Multiport */ + struct rte_mbuf *pkt; + uint8_t i; + uint8_t pkt_num; + enum PKT_TYPE pkt_type = PKT_TYPE_IPV4; + + #ifdef CT_CGNAT + struct rte_CT_helper ct_helper; + memset(&ct_helper, 0, sizeof(struct rte_CT_helper)); + #endif + + for (i = 0; i < 4; i++) { + pkt_num = in_pkt_num + i; + pkt = pkts[pkt_num]; + + /* index into hash table entries */ + int hash_table_entry = p_nat->lkup_indx[pkt_num]; + /*bitmask representing only this packet */ + uint64_t pkt_mask = 1LLU << pkt_num; + + uint8_t protocol = RTE_MBUF_METADATA_UINT8(pkt, PROT_OFST_IP4); + + uint16_t *outport_id = + RTE_MBUF_METADATA_UINT16_PTR(pkt, cgnapt_meta_offset); + + struct cgnapt_table_entry *entry = NULL; + + if (hash_table_entry < 0) { + + /* try to add new entry */ + struct rte_pipeline_table_entry *table_entry = NULL; + + uint64_t dropmask = + pkt_miss_cgnapt(p_nat->key_ptrs[pkt_num], pkt, + &table_entry, + &p_nat->valid_packets, pkt_num, + (void *)p_nat); + + if (!table_entry) { + /* ICMP Error message generation for + * Destination Host unreachable + */ + if (protocol == IP_PROTOCOL_ICMP) { + cgnapt_icmp_pkt = pkt; + send_icmp_dest_unreachable_msg(); + } + + /* Drop packet by adding to invalid pkt mask */ + + p_nat->invalid_packets |= dropmask; + + #ifdef CGNAPT_DEBUGGING + if (p_nat->kpc2++ < 5) { + printf("in_ah Th: %d", + p_nat->pipeline_num); + print_key(p_nat->key_ptrs[pkt_num]); + } + #endif + + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount3++; + #endif + continue; + } + + entry = (struct cgnapt_table_entry *)table_entry; + } else { + /* entry found for this packet */ + entry = &napt_hash_tbl_entries[hash_table_entry]; + } + + /* apply napt and mac changes */ + + p_nat->entries[pkt_num] = &(entry->head); + + uint32_t *src_addr = + RTE_MBUF_METADATA_UINT32_PTR(pkt, SRC_ADR_OFST_IP4); + uint32_t *dst_addr = + RTE_MBUF_METADATA_UINT32_PTR(pkt, DST_ADR_OFST_IP4); + uint16_t src_port_offset = 0; + uint16_t dst_port_offset = 0; + uint16_t *src_port; + uint16_t *dst_port; + + #if 0 + if ((protocol == IP_PROTOCOL_TCP) + || (protocol == IP_PROTOCOL_UDP)) { + src_port_offset = SRC_PRT_OFST_IP4_TCP; + dst_port_offset = DST_PRT_OFST_IP4_TCP; + } else if (protocol == IP_PROTOCOL_ICMP) { + /* Identifier */ + src_port_offset = MBUF_HDR_ROOM + + ETH_HDR_SIZE + + IP_HDR_SIZE + 4; + /*Sequence number */ + dst_port_offset = MBUF_HDR_ROOM + + ETH_HDR_SIZE + + IP_HDR_SIZE + 6; + } + #endif + + switch (protocol) { + case IP_PROTOCOL_TCP: + src_port_offset = SRC_PRT_OFST_IP4_TCP; + dst_port_offset = DST_PRT_OFST_IP4_TCP; + src_port = RTE_MBUF_METADATA_UINT16_PTR(pkt, + src_port_offset); + dst_port = RTE_MBUF_METADATA_UINT16_PTR(pkt, + dst_port_offset); + + #ifdef CT_CGNAT + if ((rte_be_to_cpu_16(*src_port) == 21) || + rte_be_to_cpu_16(*dst_port) == 21) { + + //To process CT , pkt_mask does it need + //to be complemented ?? + #ifdef ALGDBG + printf("cgnapt_ct_process: pkt_mask: " + "% "PRIu64", pkt_num: %d\n", + pkt_mask, pkt_num); + #endif + + pkt_mask = cgnapt_ct_process( + cgnat_cnxn_tracker, pkts, + pkt_mask, &ct_helper); + } + #endif + break; + case IP_PROTOCOL_UDP: + src_port_offset = SRC_PRT_OFST_IP4_TCP; + dst_port_offset = DST_PRT_OFST_IP4_TCP; + src_port = RTE_MBUF_METADATA_UINT16_PTR(pkt, + src_port_offset); + dst_port = RTE_MBUF_METADATA_UINT16_PTR(pkt, + dst_port_offset); + break; + case IP_PROTOCOL_ICMP: + /* Identifier */ + src_port_offset = MBUF_HDR_ROOM + ETH_HDR_SIZE + + IP_HDR_SIZE + 4; + /*Sequence number */ + dst_port_offset = MBUF_HDR_ROOM + ETH_HDR_SIZE + + IP_HDR_SIZE + 6; + src_port = RTE_MBUF_METADATA_UINT16_PTR(pkt, + src_port_offset); + dst_port = RTE_MBUF_METADATA_UINT16_PTR(pkt, + dst_port_offset); + break; + } + + + 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 (entry->data.ttl == NAPT_ENTRY_STALE) + entry->data.ttl = NAPT_ENTRY_VALID; + + struct ether_addr hw_addr; + uint32_t dest_address = 0; + /*Multiport Changes */ + uint32_t nhip = 0; + uint32_t ret; + + { + + /* Egress */ + if (unlikely(protocol == IP_PROTOCOL_UDP + && rte_be_to_cpu_16(*dst_port) == 53)) { + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount6++; + #endif + continue; + } + + dest_address = rte_bswap32(*dst_addr); + ret = local_get_nh_ipv4(dest_address, &dest_if, &nhip, p_nat); + if (!ret) { + dest_if = get_prv_to_pub_port(&dest_address, + IP_VERSION_4); + if (dest_if == INVALID_DESTIF) { + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount6++; + #endif + continue; + } + do_local_nh_ipv4_cache(dest_if, p_nat); + } + *outport_id = p_nat->outport_id[dest_if]; + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 2) + printf("Egress: \tphy_port:%d\t " + "get_prv_to_pub():%d \tout_port:%d\n", + pkt->port, dest_if, *outport_id); + #endif + } + + if (local_dest_mac_present(dest_if)) { + memcpy(eth_dest, + get_local_link_hw_addr(dest_if), + sizeof(struct ether_addr)); + memcpy(eth_src, + get_link_hw_addr(dest_if), + sizeof(struct ether_addr)); + } else { + int ret; + ret = get_dest_mac_addr_port(dest_address, &dest_if, &hw_addr); + + if (unlikely(ret != ARP_FOUND)) { + + if (unlikely(ret == ARP_NOT_FOUND)) { + printf("%s: ARP Not Found, nhip: %x, " + "outport_id: %d\n", __func__, nhip, + *outport_id); + //request_arp(*outport_id, nhip, p_nat->p.p); + } + + /* Drop the pkt */ + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount4++; + #endif + continue; + + } + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 2) { + printf("MAC found for ip 0x%x, port %d - " + "%02x:%02x:%02x:%02x:%02x:%02x\n", + dest_address, + *outport_id, + hw_addr.addr_bytes[0], + hw_addr.addr_bytes[1], + hw_addr.addr_bytes[2], + hw_addr.addr_bytes[3], + hw_addr.addr_bytes[4], + hw_addr.addr_bytes[5] + ); + + printf("Dest MAC before - " + "%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]); + } + #endif + + memcpy(eth_dest, &hw_addr, sizeof(struct ether_addr)); + + link_hw_laddr_valid[dest_if] = 1; + memcpy(&link_hw_laddr[dest_if], &hw_addr, + sizeof(struct ether_addr)); + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 2) { + printf("Dest MAC after - " + "%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]); + } + #endif + + memcpy(eth_src, + get_link_hw_addr(dest_if), + sizeof(struct ether_addr)); + } + + { + /* Egress */ + *src_addr = rte_bswap32(entry->data.pub_ip); + + #ifdef NAT_ONLY_CONFIG_REQ + if (!nat_only_config_flag) { + #endif + *src_port = rte_bswap16(entry->data.pub_port); + #ifdef NAT_ONLY_CONFIG_REQ + } + #endif + + #ifdef SIP_ALG + uint16_t rtp_port = 0, rtcp_port = 0; + struct cgnapt_table_entry *entry_ptr1 = NULL, + *entry_ptr2 = NULL, *entry_ptr3 = NULL, + *entry_ptr4 = NULL; + + if (unlikely(protocol == IP_PROTOCOL_UDP + && (rte_be_to_cpu_16(*dst_port) == 5060 + || rte_be_to_cpu_16(*src_port) == 5060))) { + + int ret = natSipAlgGetAudioPorts(pkt, + &rtp_port, &rtcp_port); + /* Commented code may be required for future usage, + * Please keep it + */ + #if 0 + if (ret < 0) { + printf("%s: Wrong SIP ALG packet1\n", + __func__); + p_nat->invalid_packets |= pkt_mask; + + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount4++; + #endif + continue; + } + #endif + + if (ret >= 0 && rtp_port != 0) { + struct pipeline_cgnapt_entry_key rtp_key; + rtp_key.ip = entry->data.u.prv_ip; + rtp_key.port = rtp_port; + rtp_key.pid = entry->data.prv_phy_port; + + if (add_dynamic_cgnapt_entry_alg( + (struct pipeline *)p_nat, &rtp_key, + &entry_ptr1, &entry_ptr2) == 0) { + printf("%s: Wrong SIP ALG packet2\n", + __func__); + p_nat->invalid_packets |= pkt_mask; + + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount4++; + #endif + continue; + } + } + + if (ret >= 0 && rtcp_port != 0) { + struct pipeline_cgnapt_entry_key rtcp_key; + rtcp_key.ip = entry->data.u.prv_ip; + rtcp_key.port = rtcp_port; + rtcp_key.pid = entry->data.prv_phy_port; + + if (add_dynamic_cgnapt_entry_alg( + (struct pipeline *)p_nat, &rtcp_key, + &entry_ptr3, &entry_ptr4) == 0) { + + printf("%s: Wrong SIP ALG packet3\n", + __func__); + p_nat->invalid_packets |= pkt_mask; + + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount4++; + #endif + continue; + } + + } + //if(entry_ptr1 != NULL && entry_ptr3 != NULL) + if (sip_alg_dpi(pkt, PRIVATE, + entry->data.pub_ip, + entry->data.pub_port, + entry->data.u.prv_ip, + entry->data.prv_port, + (rtp_port == 0) ? 0 : + entry_ptr1->data.pub_port, + (rtcp_port == 0) ? 0 : + entry_ptr3->data.pub_port) == 0) { + + printf("%s: Wrong SIP ALG packet4\n", + __func__); + p_nat->invalid_packets |= pkt_mask; + + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount4++; + #endif + continue; + } + } + #endif /* SIP_ALG */ + + #ifdef FTP_ALG + if ((rte_be_to_cpu_16(*src_port) == 21) || + rte_be_to_cpu_16(*dst_port) == 21) { + + int32_t ct_position = + cgnat_cnxn_tracker->positions[pkt_num]; + #ifdef ALGDBG + printf("@CGNAT-pkt4work ct_position :%d, pkt_num %d " + "pkt_mask = %" PRIu64 "\n", ct_position, + pkt_num, pkt_mask); + #endif + + if (ct_position < 0){ + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + continue; + } + if (cgnat_cnxn_tracker->hash_table_entries[ct_position]. + alg_bypass_flag != BYPASS){ + + struct pipeline_cgnapt_entry_key + data_channel_entry_key; + /*enable ALG DPI */ + data_channel_entry_key.ip = + entry->data.pub_ip; + data_channel_entry_key.port = + entry->data.pub_port; + data_channel_entry_key.pid = 0xffff; + + ftp_alg_dpi(p_nat, &data_channel_entry_key, + pkt, cgnat_cnxn_tracker, ct_position, + PRIVATE); + + } + } + #endif + p_nat->enaptedPktCount++; + } + + p_nat->naptedPktCount++; + + #ifdef HW_CHECKSUM_REQ + if (p_nat->hw_checksum_reqd) + hw_checksum(pkt, pkt_type); + else + #endif + sw_checksum(pkt, pkt_type); + } +} + +/** + * NAPT function for IPv4 public traffic which handles 4 pkts + * + * @param pkts + * A pointer to array of packets mbuf + * @param in_pkt_num + * Starting pkt number of pkts + * @param arg + * Void pointer + * @param p_nat + * A pointer to main CGNAPT structure + * + */ +void +pkt4_work_cgnapt_ipv4_pub( + struct rte_mbuf **pkts, + uint32_t in_pkt_num, + __rte_unused void *arg, + struct pipeline_cgnapt *p_nat) +{ + #ifdef CT_CGNAT + struct rte_CT_helper ct_helper; + memset(&ct_helper, 0, sizeof(struct rte_CT_helper)); + #endif + struct rte_mbuf *pkt; + uint8_t i; + uint8_t pkt_num; + enum PKT_TYPE pkt_type = PKT_TYPE_IPV4; + + for (i = 0; i < 4; i++) { + pkt_num = in_pkt_num + i; + pkt = pkts[pkt_num]; + + /* index into hash table entries */ + int hash_table_entry = p_nat->lkup_indx[pkt_num]; + /*bitmask representing only this packet */ + uint64_t pkt_mask = 1LLU << pkt_num; + + uint8_t protocol = RTE_MBUF_METADATA_UINT8(pkt, PROT_OFST_IP4); + + uint32_t dest_if = 0xff; /* Added for Multiport */ + uint16_t *outport_id = + RTE_MBUF_METADATA_UINT16_PTR(pkt, cgnapt_meta_offset); + + struct cgnapt_table_entry *entry = NULL; + + if (hash_table_entry < 0) { + + /* try to add new entry */ + struct rte_pipeline_table_entry *table_entry = NULL; + + uint64_t dropmask = + pkt_miss_cgnapt(p_nat->key_ptrs[pkt_num], pkt, + &table_entry, + &p_nat->valid_packets, pkt_num, + (void *)p_nat); + + if (!table_entry) { + /* ICMP Error message generation for + * Destination Host unreachable + */ + if (protocol == IP_PROTOCOL_ICMP) { + cgnapt_icmp_pkt = pkt; + send_icmp_dest_unreachable_msg(); + } + + /* Drop packet by adding to invalid pkt mask */ + + p_nat->invalid_packets |= dropmask; + + #ifdef CGNAPT_DEBUGGING + if (p_nat->kpc2++ < 5) { + printf("in_ah Th: %d", + p_nat->pipeline_num); + print_key(p_nat->key_ptrs[pkt_num]); + } + #endif + + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount3++; + #endif + + continue; + } + + entry = (struct cgnapt_table_entry *)table_entry; + } else { + /* entry found for this packet */ + entry = &napt_hash_tbl_entries[hash_table_entry]; + } + + /* apply napt and mac changes */ + + p_nat->entries[pkt_num] = &(entry->head); + + uint32_t *dst_addr = + RTE_MBUF_METADATA_UINT32_PTR(pkt, DST_ADR_OFST_IP4); + uint16_t src_port_offset = 0; + uint16_t dst_port_offset = 0; + + if ((protocol == IP_PROTOCOL_TCP) + || (protocol == IP_PROTOCOL_UDP)) { + src_port_offset = SRC_PRT_OFST_IP4_TCP; + dst_port_offset = DST_PRT_OFST_IP4_TCP; + } else if (protocol == IP_PROTOCOL_ICMP) { + /* Identifier */ + src_port_offset = MBUF_HDR_ROOM + + ETH_HDR_SIZE + + IP_HDR_SIZE + 4; + /*Sequence number */ + dst_port_offset = MBUF_HDR_ROOM + + ETH_HDR_SIZE + + IP_HDR_SIZE + 6; + } + + uint16_t *src_port = + RTE_MBUF_METADATA_UINT16_PTR(pkt, src_port_offset); + uint16_t *dst_port = + RTE_MBUF_METADATA_UINT16_PTR(pkt, dst_port_offset); + + 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 (entry->data.ttl == NAPT_ENTRY_STALE) + entry->data.ttl = NAPT_ENTRY_VALID; + + struct ether_addr hw_addr; + uint32_t dest_address = 0; + /* Multiport Changes */ + uint32_t nhip = 0; + uint32_t ret; + + /* Ingress */ + { + if (unlikely(protocol == IP_PROTOCOL_UDP + && rte_be_to_cpu_16(*src_port) == 53)) { + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount6++; + #endif + continue; + } + + dest_address = entry->data.u.prv_ip; + ret = local_get_nh_ipv4(dest_address, &dest_if, &nhip, p_nat); + if (!ret) { + dest_if = get_prv_to_pub_port(&dest_address, IP_VERSION_4); + + if (dest_if == INVALID_DESTIF) { + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount6++; + #endif + continue; + } + + do_local_nh_ipv4_cache(dest_if, p_nat); + } + + *outport_id = p_nat->outport_id[dest_if]; + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 2) + printf("Ingress: \tphy_port:%d\t " + "get_pub_to_prv():%d \tout_port%d\n", + pkt->port, dest_if, + *outport_id); + #endif + } + + if (local_dest_mac_present(dest_if)) { + memcpy(eth_dest, + get_local_link_hw_addr(dest_if), + sizeof(struct ether_addr)); + memcpy(eth_src, + get_link_hw_addr(dest_if), + sizeof(struct ether_addr)); + } else { + int ret; + ret = get_dest_mac_addr_port(dest_address, &dest_if, &hw_addr); + + if (unlikely(ret != ARP_FOUND)) { + + if (unlikely(ret == ARP_NOT_FOUND)) { + printf("%s: ARP Not Found, nhip: %x, " + "outport_id: %d\n", __func__, nhip, + *outport_id); + //request_arp(*outport_id, nhip, p_nat->p.p); + } + + /* Drop the pkt */ + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount4++; + #endif + continue; + + } + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 2) { + printf("MAC found for ip 0x%x, port %d - " + "%02x:%02x:%02x:%02x:%02x:%02x\n", + dest_address, *outport_id, + hw_addr.addr_bytes[0], + hw_addr.addr_bytes[1], + hw_addr.addr_bytes[2], + hw_addr.addr_bytes[3], + hw_addr.addr_bytes[4], + hw_addr.addr_bytes[5] + ); + + printf("Dest MAC before - " + "%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]); + } + #endif + + memcpy(eth_dest, &hw_addr, sizeof(struct ether_addr)); + + link_hw_laddr_valid[dest_if] = 1; + memcpy(&link_hw_laddr[dest_if], + &hw_addr, sizeof(struct ether_addr)); + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 2) { + printf("Dest MAC after - %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]); + } + #endif + + memcpy(eth_src, + get_link_hw_addr(dest_if), + sizeof(struct ether_addr)); + } + + { + /* Ingress */ + + *dst_addr = rte_bswap32(entry->data.u.prv_ip); + if (protocol == IP_PROTOCOL_ICMP) { + /* Query ID reverse translation done here */ + *src_port = rte_bswap16(entry->data.prv_port); + /* dont care sequence num */ + } else { + #ifdef NAT_ONLY_CONFIG_REQ + if (!nat_only_config_flag) { + #endif + *dst_port = + rte_bswap16(entry->data.prv_port); + #ifdef NAT_ONLY_CONFIG_REQ + } + #endif + + #ifdef CT_CGNAT + if ((rte_be_to_cpu_16(*src_port) == 21) || + rte_be_to_cpu_16(*dst_port) == 21) { + pkt_mask = cgnapt_ct_process( + cgnat_cnxn_tracker, pkts, + pkt_mask, &ct_helper); + } + #endif + } + + #ifdef SIP_ALG + uint16_t rtp_port = 0, rtcp_port = 0; + struct cgnapt_table_entry *entry_ptr1 = NULL, + *entry_ptr3 = NULL; + /* Commented code may be required for future usage, + * Please keep it + */ + #if 0 + struct cgnapt_table_entry *entry_ptr2 = NULL, + *entry_ptr4 = NULL; + #endif + + if (unlikely(protocol == IP_PROTOCOL_UDP + && (rte_be_to_cpu_16(*dst_port) == 5060 + || rte_be_to_cpu_16(*src_port) == 5060))) { + /* Commented code may be required for future usage, + * Please keep it + */ + #if 0 + int ret = natSipAlgGetAudioPorts(pkt, + &rtp_port, &rtcp_port); + if (ret < 0) { + printf("%s: Wrong SIP ALG packet1\n", + __func__); + p_nat->invalid_packets |= pkt_mask; + + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount4++; + #endif + return; + } + + if (rtp_port != 0) { + struct pipeline_cgnapt_entry_key rtp_key; + rtp_key.ip = entry->data.pub_ip; + rtp_key.port = rtp_port; + rtp_key.pid = 0xffff; + + if (retrieve_cgnapt_entry_alg(&rtp_key, + &entry_ptr1, &entry_ptr2) == 0) { + printf("%s: Wrong SIP ALG packet2\n", + __func__); + p_nat->invalid_packets |= pkt_mask; + + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount4++; + #endif + return; + } + } + + if (rtcp_port != 0) { + struct pipeline_cgnapt_entry_key rtcp_key; + rtcp_key.ip = entry->data.pub_ip; + rtcp_key.port = rtcp_port; + rtcp_key.pid = 0xffff; + + if (retrieve_cgnapt_entry_alg(&rtcp_key, + &entry_ptr3, &entry_ptr4) == 0) { + printf("%s: Wrong SIP ALG packet3\n", + __func__); + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount4++; + #endif + return; + } + + } + #endif + if (sip_alg_dpi(pkt, PUBLIC, + entry->data.u.prv_ip, + entry->data.prv_port, + entry->data.pub_ip, + entry->data.pub_port, + (rtp_port == 0) ? 0 : + entry_ptr1->data.prv_port, + (rtcp_port == 0) ? 0 : + entry_ptr3->data.prv_port) == 0) { + + printf("%s: Wrong SIP ALG packet4\n", + __func__); + p_nat->invalid_packets |= pkt_mask; + + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount4++; + #endif + continue; + } + } + #endif /* SIP_ALG */ + + #ifdef FTP_ALG + if ((rte_be_to_cpu_16(*src_port) == 21) || + rte_be_to_cpu_16(*dst_port) == 21) { + + int32_t ct_position = + cgnat_cnxn_tracker->positions[pkt_num]; + if (ct_position < 0){ + p_nat->invalid_packets |= pkt_mask; + + p_nat->naptDroppedPktCount++; + continue; + } + if (cgnat_cnxn_tracker->hash_table_entries + [ct_position].alg_bypass_flag != BYPASS){ + + struct pipeline_cgnapt_entry_key + data_channel_entry_key; + + /*enable ALG DPI */ + data_channel_entry_key.ip = + entry->data.pub_ip; + data_channel_entry_key.port = + entry->data.pub_port; + data_channel_entry_key.pid = 0xffff; + + ftp_alg_dpi(p_nat, &data_channel_entry_key, + pkt, cgnat_cnxn_tracker, + ct_position, PUBLIC); + + } + } + #endif + p_nat->inaptedPktCount++; + } + + p_nat->naptedPktCount++; + + #ifdef HW_CHECKSUM_REQ + if (p_nat->hw_checksum_reqd) + hw_checksum(pkt, pkt_type); + else + #endif + sw_checksum(pkt, pkt_type); + } +} + +/** + * NAPT key calculation function for IPv6 private traffic + * which handles 1 pkt + * + * @param pkt + * A pointer to array of packets mbuf + * @param in_pkt_num + * Pkt number of pkts + * @param arg + * Void pointer + * @param p_nat + * A pointer to main CGNAPT structure + * + */ +void +pkt_work_cgnapt_key_ipv6_prv( + struct rte_mbuf *pkt, + uint32_t pkt_num, + __rte_unused void *arg, + struct pipeline_cgnapt *p_nat) +{ + /* Egress */ + p_nat->receivedPktCount++; + + /* bitmask representing only this packet */ + uint64_t pkt_mask = 1LLU << pkt_num; + + uint8_t protocol = RTE_MBUF_METADATA_UINT8(pkt, PROT_OFST_IP6); + uint32_t *src_addr = RTE_MBUF_METADATA_UINT32_PTR(pkt, + SRC_ADR_OFST_IP6); + uint16_t src_port = RTE_MBUF_METADATA_UINT16(pkt, SRC_PRT_OFST_IP6); + + uint16_t phy_port = pkt->port; + struct pipeline_cgnapt_entry_key key; + + memset(&key, 0, sizeof(struct pipeline_cgnapt_entry_key)); + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 4) + print_pkt(pkt); + #endif + + if (enable_hwlb) { + if (!check_arp_icmp(pkt, pkt_mask, p_nat)) + return; + } + + switch (protocol) { + case IP_PROTOCOL_UDP: + { + #ifdef PCP_ENABLE + if (pcp_enable) { + struct udp_hdr *udp; + + udp = (struct udp_hdr *) + RTE_MBUF_METADATA_UINT8_PTR(pkt, + IPV6_UDP_OFST); + + if (rte_bswap16(udp->dst_port) == + PCP_SERVER_PORT) { + handle_pcp_req(pkt, IPV6_SZ, p_nat); + p_nat->invalid_packets |= pkt_mask; + return; + } + } + #endif + } + case IP_PROTOCOL_TCP: + case IP_PROTOCOL_ICMP: + /*we don't need icmp check in ipv6 */ + break; + + default: + printf("wrong protocol: %d\n", protocol); + /* remember invalid packets to be dropped */ + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount2++; + #endif + return; + } + + key.pid = phy_port; + key.ip = rte_bswap32(src_addr[3]); + key.port = rte_bswap16(src_port); + + #ifdef NAT_ONLY_CONFIG_REQ + if (nat_only_config_flag) + key.port = 0xffff; + #endif + + memcpy(&p_nat->keys[pkt_num], &key, + sizeof(struct pipeline_cgnapt_entry_key)); + p_nat->key_ptrs[pkt_num] = &p_nat->keys[pkt_num]; +} + +/** + * NAPT key calculation function for IPv6 public traffic + * which handles 1 pkt + * + * @param pkt + * A pointer to array of packets mbuf + * @param in_pkt_num + * Pkt number of pkts + * @param arg + * Void pointer + * @param p_nat + * A pointer to main CGNAPT structure + * + */ +void +pkt_work_cgnapt_key_ipv6_pub( + struct rte_mbuf *pkt, + uint32_t pkt_num, + __rte_unused void *arg, + struct pipeline_cgnapt *p_nat) +{ + + /* Ingress */ + p_nat->receivedPktCount++; + + /* bitmask representing only this packet */ + uint64_t pkt_mask = 1LLU << pkt_num; + + uint8_t protocol = RTE_MBUF_METADATA_UINT8(pkt, PROT_OFST_IP4); + + uint32_t *dst_addr = RTE_MBUF_METADATA_UINT32_PTR(pkt, + DST_ADR_OFST_IP4); + uint16_t dst_port = RTE_MBUF_METADATA_UINT16(pkt, + DST_PRT_OFST_IP4_TCP); + + struct pipeline_cgnapt_entry_key key; + + memset(&key, 0, sizeof(struct pipeline_cgnapt_entry_key)); + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 4) + print_pkt(pkt); + #endif + + if (enable_hwlb) { + if (!check_arp_icmp(pkt, pkt_mask, p_nat)) + return; + } + + switch (protocol) { + + case IP_PROTOCOL_UDP: + case IP_PROTOCOL_TCP: + case IP_PROTOCOL_ICMP: + /*we don't need icmp check in ipv6 */ + break; + + default: + /* remember invalid packets to be dropped */ + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount2++; + #endif + return; + } + + key.pid = 0xffff; + key.ip = rte_bswap32(dst_addr[0]); + key.port = rte_bswap16(dst_port); + + #ifdef NAT_ONLY_CONFIG_REQ + if (nat_only_config_flag) + key.port = 0xffff; + #endif + + memcpy(&p_nat->keys[pkt_num], &key, + sizeof(struct pipeline_cgnapt_entry_key)); + p_nat->key_ptrs[pkt_num] = &p_nat->keys[pkt_num]; +} + +/** + * NAPT key calculation function for IPv6 private traffic + * which handles 4 pkts + * + * @param pkt + * A pointer to array of packets mbuf + * @param in_pkt_num + * Starting pkt number of pkts + * @param arg + * Void pointer + * @param p_nat + * A pointer to main CGNAPT structure + * + */ +void +pkt4_work_cgnapt_key_ipv6_prv( + struct rte_mbuf **pkt, + uint32_t pkt_num, + __rte_unused void *arg, + struct pipeline_cgnapt *p_nat) +{ + p_nat->receivedPktCount += 4; + + /* bitmask representing only this packet */ + uint64_t pkt_mask0 = 1LLU << pkt_num; + uint64_t pkt_mask1 = 1LLU << (pkt_num + 1); + uint64_t pkt_mask2 = 1LLU << (pkt_num + 2); + uint64_t pkt_mask3 = 1LLU << (pkt_num + 3); + + uint8_t protocol0 = RTE_MBUF_METADATA_UINT8(pkt[0], + PROT_OFST_IP6); + uint8_t protocol1 = RTE_MBUF_METADATA_UINT8(pkt[1], + PROT_OFST_IP6); + uint8_t protocol2 = RTE_MBUF_METADATA_UINT8(pkt[2], + PROT_OFST_IP6); + uint8_t protocol3 = RTE_MBUF_METADATA_UINT8(pkt[3], + PROT_OFST_IP6); + + uint32_t *src_addr0 = RTE_MBUF_METADATA_UINT32_PTR(pkt[0], + SRC_ADR_OFST_IP6); + uint32_t *src_addr1 = RTE_MBUF_METADATA_UINT32_PTR(pkt[1], + SRC_ADR_OFST_IP6); + uint32_t *src_addr2 = RTE_MBUF_METADATA_UINT32_PTR(pkt[2], + SRC_ADR_OFST_IP6); + uint32_t *src_addr3 = RTE_MBUF_METADATA_UINT32_PTR(pkt[3], + SRC_ADR_OFST_IP6); + + uint16_t src_port0 = RTE_MBUF_METADATA_UINT16(pkt[0], + SRC_PRT_OFST_IP6); + uint16_t src_port1 = RTE_MBUF_METADATA_UINT16(pkt[1], + SRC_PRT_OFST_IP6); + uint16_t src_port2 = RTE_MBUF_METADATA_UINT16(pkt[2], + SRC_PRT_OFST_IP6); + uint16_t src_port3 = RTE_MBUF_METADATA_UINT16(pkt[3], + SRC_PRT_OFST_IP6); + + uint16_t phy_port0 = pkt[0]->port; + uint16_t phy_port1 = pkt[1]->port; + uint16_t phy_port2 = pkt[2]->port; + uint16_t phy_port3 = pkt[3]->port; + + struct pipeline_cgnapt_entry_key key0; + struct pipeline_cgnapt_entry_key key1; + struct pipeline_cgnapt_entry_key key2; + struct pipeline_cgnapt_entry_key key3; + + memset(&key0, 0, sizeof(struct pipeline_cgnapt_entry_key)); + memset(&key1, 0, sizeof(struct pipeline_cgnapt_entry_key)); + memset(&key2, 0, sizeof(struct pipeline_cgnapt_entry_key)); + memset(&key3, 0, sizeof(struct pipeline_cgnapt_entry_key)); + + + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 4) + print_pkt(pkt[0]); + #endif + + if (enable_hwlb) { + if (!check_arp_icmp(pkt[0], pkt_mask0, p_nat)) + goto PKT1; + } + + switch (protocol0) { + + case IP_PROTOCOL_UDP: + { + #ifdef PCP_ENABLE + if (pcp_enable) { + struct udp_hdr *udp; + + udp = (struct udp_hdr *) + RTE_MBUF_METADATA_UINT8_PTR(pkt[0], + IPV6_UDP_OFST); + + if (rte_bswap16(udp->dst_port) == + PCP_SERVER_PORT) { + handle_pcp_req(pkt[0], IPV6_SZ, p_nat); + p_nat->invalid_packets |= pkt_mask0; + goto PKT1; + } + } + #endif + } + case IP_PROTOCOL_TCP: + case IP_PROTOCOL_ICMP: + /*we don't need icmp check in ipv6 */ + break; + + default: + /* remember invalid packets to be dropped */ + p_nat->invalid_packets |= pkt_mask0; + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount2++; + #endif + + goto PKT1; + } + + + key0.pid = phy_port0; + key0.ip = rte_bswap32(src_addr0[3]); + key0.port = rte_bswap16(src_port0); + + #ifdef NAT_ONLY_CONFIG_REQ + if (nat_only_config_flag) + key0.port = 0xffff; + #endif + + memcpy(&p_nat->keys[pkt_num], &key0, + sizeof(struct pipeline_cgnapt_entry_key)); + p_nat->key_ptrs[pkt_num] = &p_nat->keys[pkt_num]; + + PKT1: + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 4) + print_pkt(pkt[1]); + #endif + + if (enable_hwlb) { + if (!check_arp_icmp(pkt[1], pkt_mask1, p_nat)) + goto PKT2; + } + + switch (protocol1) { + case IP_PROTOCOL_UDP: + { + #ifdef PCP_ENABLE + if (pcp_enable) { + struct udp_hdr *udp; + + udp = (struct udp_hdr *) + RTE_MBUF_METADATA_UINT8_PTR(pkt[1], + IPV6_UDP_OFST); + + if (rte_bswap16(udp->dst_port) == + PCP_SERVER_PORT) { + handle_pcp_req(pkt[1], IPV6_SZ, p_nat); + p_nat->invalid_packets |= pkt_mask1; + goto PKT2; + } + } + #endif + } + case IP_PROTOCOL_TCP: + case IP_PROTOCOL_ICMP: + /*we don't need icmp check in ipv6 */ + break; + + default: + /* remember invalid packets to be dropped */ + p_nat->invalid_packets |= pkt_mask1; + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount2++; + #endif + + goto PKT2; + } + + key1.pid = phy_port1; + key1.ip = rte_bswap32(src_addr1[3]); + key1.port = rte_bswap16(src_port1); + + #ifdef NAT_ONLY_CONFIG_REQ + if (nat_only_config_flag) + key1.port = 0xffff; + #endif + + memcpy(&p_nat->keys[pkt_num + 1], &key1, + sizeof(struct pipeline_cgnapt_entry_key)); + p_nat->key_ptrs[pkt_num + 1] = &p_nat->keys[pkt_num + 1]; + + PKT2: + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 4) + print_pkt(pkt[2]); + #endif + + if (enable_hwlb) { + if (!check_arp_icmp(pkt[2], pkt_mask2, p_nat)) + goto PKT3; + } + + switch (protocol2) { + case IP_PROTOCOL_UDP: + { + #ifdef PCP_ENABLE + if (pcp_enable) { + struct udp_hdr *udp; + + udp = (struct udp_hdr *) + RTE_MBUF_METADATA_UINT8_PTR(pkt[2], + IPV6_UDP_OFST); + + if (rte_bswap16(udp->dst_port) == + PCP_SERVER_PORT) { + handle_pcp_req(pkt[2], IPV6_SZ, p_nat); + p_nat->invalid_packets |= pkt_mask2; + goto PKT3; + } + } + #endif + } + case IP_PROTOCOL_TCP: + case IP_PROTOCOL_ICMP: + /*we don't need icmp check in ipv6 */ + break; + + default: + /* remember invalid packets to be dropped */ + p_nat->invalid_packets |= pkt_mask2; + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount2++; + #endif + + goto PKT3; + } + + key2.pid = phy_port2; + key2.ip = rte_bswap32(src_addr2[3]); + key2.port = rte_bswap16(src_port2); + + #ifdef NAT_ONLY_CONFIG_REQ + if (nat_only_config_flag) + key2.port = 0xffff; + #endif + + memcpy(&p_nat->keys[pkt_num + 2], &key2, + sizeof(struct pipeline_cgnapt_entry_key)); + p_nat->key_ptrs[pkt_num + 2] = &p_nat->keys[pkt_num + 2]; + + PKT3: + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 4) + print_pkt(pkt[3]); + #endif + + if (enable_hwlb) { + if (!check_arp_icmp(pkt[3], pkt_mask3, p_nat)) + return; + } + + switch (protocol3) { + case IP_PROTOCOL_UDP: + { + #ifdef PCP_ENABLE + if (pcp_enable) { + struct udp_hdr *udp; + + udp = (struct udp_hdr *) + RTE_MBUF_METADATA_UINT8_PTR(pkt[3], + IPV6_UDP_OFST); + + if (rte_bswap16(udp->dst_port) == + PCP_SERVER_PORT) { + handle_pcp_req(pkt[3], IPV6_SZ, p_nat); + p_nat->invalid_packets |= pkt_mask3; + return; + } + } + #endif + } + case IP_PROTOCOL_TCP: + case IP_PROTOCOL_ICMP: + /*we don't need icmp check in ipv6 */ + break; + + default: + /* remember invalid packets to be dropped */ + p_nat->invalid_packets |= pkt_mask2; + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount2++; + #endif + + return; + } + + key3.pid = phy_port3; + key3.ip = rte_bswap32(src_addr3[3]); + key3.port = rte_bswap16(src_port3); + + #ifdef NAT_ONLY_CONFIG_REQ + if (nat_only_config_flag) + key3.port = 0xffff; + #endif + + memcpy(&p_nat->keys[pkt_num + 3], &key3, + sizeof(struct pipeline_cgnapt_entry_key)); + p_nat->key_ptrs[pkt_num + 3] = &p_nat->keys[pkt_num + 3]; + + +} + +/** + * NAPT key calculation function for IPv4 public traffic + * which handles 4 pkts + * + * @param pkt + * A pointer to array of packets mbuf + * @param in_pkt_num + * Starting pkt number of pkts + * @param arg + * Void pointer + * @param p_nat + * A pointer to main CGNAPT structure + * + */ +void +pkt4_work_cgnapt_key_ipv6_pub( + struct rte_mbuf **pkt, + uint32_t pkt_num, + __rte_unused void *arg, + struct pipeline_cgnapt *p_nat) +{ + p_nat->receivedPktCount += 4; + + /* bitmask representing only this packet */ + uint64_t pkt_mask0 = 1LLU << pkt_num; + uint64_t pkt_mask1 = 1LLU << (pkt_num + 1); + uint64_t pkt_mask2 = 1LLU << (pkt_num + 2); + uint64_t pkt_mask3 = 1LLU << (pkt_num + 3); + + uint8_t protocol0 = RTE_MBUF_METADATA_UINT8(pkt[0], + PROT_OFST_IP4); + uint8_t protocol1 = RTE_MBUF_METADATA_UINT8(pkt[1], + PROT_OFST_IP4); + uint8_t protocol2 = RTE_MBUF_METADATA_UINT8(pkt[2], + PROT_OFST_IP4); + uint8_t protocol3 = RTE_MBUF_METADATA_UINT8(pkt[3], + PROT_OFST_IP4); + + uint32_t *dst_addr0 = RTE_MBUF_METADATA_UINT32_PTR(pkt[0], + DST_ADR_OFST_IP4); + uint32_t *dst_addr1 = RTE_MBUF_METADATA_UINT32_PTR(pkt[1], + DST_ADR_OFST_IP4); + uint32_t *dst_addr2 = RTE_MBUF_METADATA_UINT32_PTR(pkt[2], + DST_ADR_OFST_IP4); + uint32_t *dst_addr3 = RTE_MBUF_METADATA_UINT32_PTR(pkt[3], + DST_ADR_OFST_IP4); + + uint16_t dst_port0 = RTE_MBUF_METADATA_UINT16(pkt[0], + DST_PRT_OFST_IP4_TCP); + uint16_t dst_port1 = RTE_MBUF_METADATA_UINT16(pkt[1], + DST_PRT_OFST_IP4_TCP); + uint16_t dst_port2 = RTE_MBUF_METADATA_UINT16(pkt[2], + DST_PRT_OFST_IP4_TCP); + uint16_t dst_port3 = RTE_MBUF_METADATA_UINT16(pkt[3], + DST_PRT_OFST_IP4_TCP); + + struct pipeline_cgnapt_entry_key key0; + struct pipeline_cgnapt_entry_key key1; + struct pipeline_cgnapt_entry_key key2; + struct pipeline_cgnapt_entry_key key3; + + memset(&key0, 0, sizeof(struct pipeline_cgnapt_entry_key)); + memset(&key1, 0, sizeof(struct pipeline_cgnapt_entry_key)); + memset(&key2, 0, sizeof(struct pipeline_cgnapt_entry_key)); + memset(&key3, 0, sizeof(struct pipeline_cgnapt_entry_key)); + +/* --0-- */ + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 4) + print_pkt(pkt[0]); + #endif + + if (enable_hwlb) { + if (!check_arp_icmp(pkt[0], pkt_mask0, p_nat)) + goto PKT1; + } + + switch (protocol0) { + + case IP_PROTOCOL_TCP: + case IP_PROTOCOL_UDP: + case IP_PROTOCOL_ICMP: + /*we don't need icmp check in ipv6 */ + break; + + default: + /* remember invalid packets to be dropped */ + p_nat->invalid_packets |= pkt_mask0; + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount2++; + #endif + goto PKT1; + } + + key0.pid = 0xffff; + key0.ip = rte_bswap32(dst_addr0[0]); + key0.port = rte_bswap16(dst_port0); + + #ifdef NAT_ONLY_CONFIG_REQ + if (nat_only_config_flag) + key0.port = 0xffff; + #endif + + memcpy(&p_nat->keys[pkt_num], &key0, + sizeof(struct pipeline_cgnapt_entry_key)); + p_nat->key_ptrs[pkt_num] = &p_nat->keys[pkt_num]; + + +/* --1-- */ + +PKT1: + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 4) + print_pkt(pkt[1]); + #endif + + if (enable_hwlb) { + if (!check_arp_icmp(pkt[1], pkt_mask1, p_nat)) + goto PKT2; + } + + switch (protocol1) { + + case IP_PROTOCOL_TCP: + case IP_PROTOCOL_UDP: + case IP_PROTOCOL_ICMP: + /*we don't need icmp check in ipv6 */ + break; + + default: + /* remember invalid packets to be dropped */ + p_nat->invalid_packets |= pkt_mask1; + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount2++; + #endif + goto PKT2; + } + + key1.pid = 0xffff; + key1.ip = rte_bswap32(dst_addr1[0]); + key1.port = rte_bswap16(dst_port1); + + #ifdef NAT_ONLY_CONFIG_REQ + if (nat_only_config_flag) + key1.port = 0xffff; + #endif + + memcpy(&p_nat->keys[pkt_num + 1], &key1, + sizeof(struct pipeline_cgnapt_entry_key)); + p_nat->key_ptrs[pkt_num + 1] = &p_nat->keys[pkt_num + 1]; + + +/* --2-- */ + +PKT2: + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 4) + print_pkt(pkt[2]); + #endif + + if (enable_hwlb) { + if (!check_arp_icmp(pkt[2], pkt_mask2, p_nat)) + goto PKT3; + } + + switch (protocol2) { + + case IP_PROTOCOL_TCP: + case IP_PROTOCOL_UDP: + case IP_PROTOCOL_ICMP: + /*we don't need icmp check in ipv6 */ + break; + + default: + /* remember invalid packets to be dropped */ + p_nat->invalid_packets |= pkt_mask2; + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount2++; + #endif + goto PKT3; + } + + key2.pid = 0xffff; + key2.ip = rte_bswap32(dst_addr2[0]); + key2.port = rte_bswap16(dst_port2); + + #ifdef NAT_ONLY_CONFIG_REQ + if (nat_only_config_flag) + key2.port = 0xffff; + #endif + + memcpy(&p_nat->keys[pkt_num + 2], &key2, + sizeof(struct pipeline_cgnapt_entry_key)); + + p_nat->key_ptrs[pkt_num + 2] = &p_nat->keys[pkt_num + 2]; + + +/* --3-- */ + +PKT3: + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 4) + print_pkt(pkt[3]); + #endif + + if (enable_hwlb) { + if (!check_arp_icmp(pkt[3], pkt_mask3, p_nat)) + return; + } + + switch (protocol3) { + + case IP_PROTOCOL_TCP: + case IP_PROTOCOL_UDP: + case IP_PROTOCOL_ICMP: + /*we don't need icmp check in ipv6 */ + break; + + default: + /* remember invalid packets to be dropped */ + p_nat->invalid_packets |= pkt_mask3; + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount2++; + #endif + return; + } + + key3.pid = 0xffff; + key3.ip = rte_bswap32(dst_addr3[0]); + key3.port = rte_bswap16(dst_port3); + + #ifdef NAT_ONLY_CONFIG_REQ + if (nat_only_config_flag) + key3.port = 0xffff; + #endif + + memcpy(&p_nat->keys[pkt_num + 3], &key3, + sizeof(struct pipeline_cgnapt_entry_key)); + + p_nat->key_ptrs[pkt_num + 3] = &p_nat->keys[pkt_num + 3]; +} + +/** + * NAPT function for IPv6 private traffic which handles 1 pkt + * + * @param pkts + * A pointer to array of packet mbuf + * @param in_pkt_num + * Pkt number of pkt + * @param arg + * Void pointer + * @param p_nat + * A pointer to main CGNAPT structure + * + */ +void +pkt_work_cgnapt_ipv6_prv( + struct rte_mbuf *pkt, + uint32_t pkt_num, + __rte_unused void *arg, + struct pipeline_cgnapt *p_nat) +{ + + /* index into hash table entries */ + int hash_table_entry = p_nat->lkup_indx[pkt_num]; + + /*bitmask representing only this packet */ + uint64_t pkt_mask = 1LLU << pkt_num; + + uint8_t protocol = RTE_MBUF_METADATA_UINT8(pkt, PROT_OFST_IP6); + + /* Added for Multiport */ + uint32_t dest_if = INVALID_DESTIF; + uint16_t *outport_id = RTE_MBUF_METADATA_UINT16_PTR(pkt, + cgnapt_meta_offset); + + struct cgnapt_table_entry *entry = NULL; + enum PKT_TYPE pkt_type = PKT_TYPE_IPV6to4; + + if (hash_table_entry < 0) { + + /* try to add new entry */ + struct rte_pipeline_table_entry *table_entry = NULL; + + uint64_t dropmask = pkt_miss_cgnapt(p_nat->key_ptrs[pkt_num], + pkt, &table_entry, + &p_nat->valid_packets, pkt_num, + (void *)p_nat); + + if (!table_entry) { + /* ICMP Error message generation for + * Destination Host unreachable + */ + /* Do we need this check for ipv6? */ + if (protocol == IP_PROTOCOL_ICMP) { + cgnapt_icmp_pkt = pkt; + send_icmp_dest_unreachable_msg(); + } + + /* Drop packet by adding to invalid pkt mask */ + + p_nat->invalid_packets |= dropmask; + + #ifdef CGNAPT_DEBUGGING + if (p_nat->kpc2++ < 5) { + printf("in_ah Th: %d", p_nat->pipeline_num); + print_key(p_nat->key_ptrs[pkt_num]); + } + #endif + + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount3++; + #endif + + return; + } + + entry = (struct cgnapt_table_entry *)table_entry; + } else { + /* entry found for this packet */ + entry = &napt_hash_tbl_entries[hash_table_entry]; + } + + /* apply napt and mac changes */ + + p_nat->entries[pkt_num] = &(entry->head); + + struct ipv6_hdr ipv6_hdr; + + struct ether_addr hw_addr; + uint32_t dest_address = 0; + uint32_t nhip = 0; + /* Egress */ + { + + convert_ipv6_to_ipv4(pkt, &ipv6_hdr); + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG == 1) + printf("pkt_work_cganpt: convert_ipv6_to_ipv4\n"); + #endif + + struct cgnapt_nsp_node *ll = nsp_ll; + int nsp = 0; + + while (ll != NULL) { + if (!memcmp + (&ipv6_hdr.dst_addr[0], &ll->nsp.prefix[0], + ll->nsp.depth / 8)) { + nsp = 1; + break; + } + ll = ll->next; + } + + if (!nsp + && !memcmp(&ipv6_hdr.dst_addr[0], &well_known_prefix[0], + 12)) { + nsp = 1; + } + + if (!nsp) { + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount5++; + #endif + + return; + } + + } + + /* As packet is already converted into IPv4 we must not + * operate IPv6 offsets on packet + * Only perform IPv4 operations + */ + + uint32_t *src_addr = + RTE_MBUF_METADATA_UINT32_PTR(pkt, SRC_ADR_OFST_IP6t4); + uint32_t *dst_addr = + RTE_MBUF_METADATA_UINT32_PTR(pkt, DST_ADR_OFST_IP6t4); + uint16_t *src_port = + RTE_MBUF_METADATA_UINT16_PTR(pkt, SRC_PRT_OFST_IP6t4); + uint16_t *dst_port = + RTE_MBUF_METADATA_UINT16_PTR(pkt, DST_PRT_OFST_IP6t4); + + uint8_t *eth_dest = RTE_MBUF_METADATA_UINT8_PTR(pkt, + ETH_OFST_IP6t4); + uint8_t *eth_src = RTE_MBUF_METADATA_UINT8_PTR(pkt, + ETH_OFST_IP6t4 + 6); + + if (entry->data.ttl == NAPT_ENTRY_STALE) + entry->data.ttl = NAPT_ENTRY_VALID; + { + /* Egress */ + if (unlikely(protocol == IP_PROTOCOL_UDP + && rte_be_to_cpu_16(*dst_port) == 53)) { + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount6++; + #endif + + return; + } + + dest_address = rte_bswap32(*dst_addr); + /*Multiport Changes */ + uint32_t nhip = 0; + uint32_t ret; + ret = local_get_nh_ipv4(dest_address, &dest_if, &nhip, p_nat); + if (!ret) { + dest_if = get_prv_to_pub_port(&dest_address, IP_VERSION_4); + + if (dest_if == INVALID_DESTIF) { + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount6++; + #endif + return; + } + + do_local_nh_ipv4_cache(dest_if, p_nat); + } + *outport_id = p_nat->outport_id[dest_if]; + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 2) + printf("Egress: \tphy_port:%d\t get_prv_to_pub():%d " + "\tout_port:%d\n", pkt->port, + dest_if, *outport_id); + #endif + } + + #ifdef CGNAPT_DBG_PRNT + static int static_count; + + if (static_count++ < 10) { + print_pkt(pkt); + my_print_entry(entry); + printf("dest-offset:%d\n", DST_ADR_OFST_IP4); + printf("dest_add:%x\n", entry->data.u.prv_ip); + printf("dest_add:%x\n", *dst_addr); + printf("DST_ADR_OFST_IP6:%d\n", DST_ADR_OFST_IP6); + } + #endif + + if (local_dest_mac_present(dest_if)) { + memcpy(eth_dest, + get_local_link_hw_addr(dest_if), + sizeof(struct ether_addr)); + memcpy(eth_src, get_link_hw_addr(dest_if), + sizeof(struct ether_addr)); + } else { + int ret; + ret = get_dest_mac_addr_port(dest_address, &dest_if, &hw_addr); + + if (unlikely(ret != ARP_FOUND)) { + + if (unlikely(ret == ARP_NOT_FOUND)) { + printf("%s: ARP Not Found, nhip: %x, " + "outport_id: %d\n", __func__, nhip, + *outport_id); + //request_arp(*outport_id, nhip, p_nat->p.p); + } + + /* Drop the pkt */ + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount4++; + #endif + return; + + } + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 2) { + printf("MAC found for ip 0x%x, port %d - %02x:%02x: " + "%02x:%02x:%02x:%02x\n", dest_address, + *outport_id, + hw_addr.addr_bytes[0], hw_addr.addr_bytes[1], + hw_addr.addr_bytes[2], hw_addr.addr_bytes[3], + hw_addr.addr_bytes[4], hw_addr.addr_bytes[5]); + + printf("Dest MAC before - %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]); + } + #endif + + memcpy(eth_dest, &hw_addr, sizeof(struct ether_addr)); + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 2) { + printf("Dest MAC after - " + "%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]); + } + #endif + + memcpy(eth_src, get_link_hw_addr(dest_if), + sizeof(struct ether_addr)); + } + + { + /* Egress */ + *src_addr = rte_bswap32(entry->data.pub_ip); + + #ifdef NAT_ONLY_CONFIG_REQ + if (!nat_only_config_flag) { + #endif + *src_port = rte_bswap16(entry->data.pub_port); + + #ifdef NAT_ONLY_CONFIG_REQ + } + #endif + + p_nat->enaptedPktCount++; + } + + p_nat->naptedPktCount++; + + #ifdef HW_CHECKSUM_REQ + if (p_nat->hw_checksum_reqd) + hw_checksum(pkt, pkt_type); + else + #endif + sw_checksum(pkt, pkt_type); +} + + +/** + * NAPT function for IPv6 public traffic which handles 1 pkt + * + * @param pkts + * A pointer to array of packet mbuf + * @param in_pkt_num + * Pkt number of pkt + * @param arg + * Void pointer + * @param p_nat + * A pointer to main CGNAPT structure + * + */ +void +pkt_work_cgnapt_ipv6_pub( + struct rte_mbuf *pkt, + uint32_t pkt_num, + __rte_unused void *arg, + struct pipeline_cgnapt *p_nat) +{ + + /* index into hash table entries */ + int hash_table_entry = p_nat->lkup_indx[pkt_num]; + /*bitmask representing only this packet */ + uint64_t pkt_mask = 1LLU << pkt_num; + + uint8_t protocol = RTE_MBUF_METADATA_UINT8(pkt, PROT_OFST_IP4); + + uint32_t dest_if = INVALID_DESTIF; /* Added for Multiport */ + uint16_t *outport_id = + RTE_MBUF_METADATA_UINT16_PTR(pkt, cgnapt_meta_offset); + struct cgnapt_table_entry *entry = NULL; + + enum PKT_TYPE pkt_type = PKT_TYPE_IPV4to6; + + if (hash_table_entry < 0) { + + /* Drop ingress initial traffic */ + + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount3++; + if (p_nat->kpc2++ < 5) { + printf("in_ah Th: %d", p_nat->pipeline_num); + print_key(p_nat->key_ptrs[pkt_num]); + } + #endif + + return; + + } else { + /* entry found for this packet */ + entry = &napt_hash_tbl_entries[hash_table_entry]; + } + + /* apply napt and mac changes */ + + p_nat->entries[pkt_num] = &(entry->head); + if (entry->data.type != CGNAPT_ENTRY_IPV6) { + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + return; + } + + struct ipv4_hdr ipv4_hdr; + uint16_t *src_port = + RTE_MBUF_METADATA_UINT16_PTR(pkt, SRC_PRT_OFST_IP4_TCP); + + 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 (entry->data.ttl == NAPT_ENTRY_STALE) + entry->data.ttl = NAPT_ENTRY_VALID; + + struct ether_addr hw_addr; + uint8_t dest_addr_ipv6[16]; + uint8_t nh_ipv6[16]; + + /* Ingress */ + { + + if (unlikely(protocol == IP_PROTOCOL_UDP + && rte_be_to_cpu_16(*src_port) == 53)) { + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount6++; + #endif + return; + } + + memcpy(&dest_addr_ipv6[0], &entry->data.u.prv_ipv6[0], 16); + uint8_t nhipv6[16]; + int ret; + ret = local_get_nh_ipv6(&dest_addr_ipv6[0], &dest_if, + &nhipv6[0], p_nat); + if (!ret) { + dest_if = get_prv_to_pub_port((uint32_t *) + &dest_addr_ipv6[0], + IP_VERSION_6); + + if (dest_if == INVALID_DESTIF) { + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount6++; + #endif + return; + } + + do_local_nh_ipv6_cache(dest_if, p_nat); + } + *outport_id = p_nat->outport_id[dest_if]; + } + + #ifdef CGNAPT_DEBUGGING + static int static_count; + + if (static_count++ < 10) { + print_pkt(pkt); + my_print_entry(entry); + printf("dest-offset:%d\n", DST_ADR_OFST_IP4); + printf("dest_add:%x\n", entry->data.u.prv_ip); + printf("DST_ADR_OFST_IP6:%d\n", DST_ADR_OFST_IP6); + } + #endif + + memset(nh_ipv6, 0, 16); + if (get_dest_mac_address_ipv6_port( + &dest_addr_ipv6[0], + &dest_if, + &hw_addr, + &nh_ipv6[0])) { + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 2) { + printf("MAC found for ip 0x%x, port %d - " + "%02x:%02x:%02x:%02x:%02x:%02x\n", + *((uint32_t *)dest_addr_ipv6 + 12), + *outport_id, + hw_addr.addr_bytes[0], + hw_addr.addr_bytes[1], hw_addr.addr_bytes[2], + hw_addr.addr_bytes[3], hw_addr.addr_bytes[4], + hw_addr.addr_bytes[5]); + + printf("Dest MAC before - " + "%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]); + } + #endif + + memcpy(eth_dest, &hw_addr, sizeof(struct ether_addr)); + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 2) { + printf("Dest MAC after - " + "%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]); + } + #endif + + memcpy(eth_src, get_link_hw_addr(dest_if), + sizeof(struct ether_addr)); + } else { + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount4++; + #endif + + return; + } + /* Ingress */ + { + + convert_ipv4_to_ipv6(pkt, &ipv4_hdr); + + /* Ethernet MTU check */ + if ((rte_pktmbuf_data_len(pkt) - 14) > 1500) { + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + return; + } + uint32_t *dst_addr = + RTE_MBUF_METADATA_UINT32_PTR(pkt, DST_ADR_OFST_IP4t6); + uint16_t *dst_port = + RTE_MBUF_METADATA_UINT16_PTR(pkt, DST_PRT_OFST_IP4t6); + + memcpy((uint8_t *) &dst_addr[0], &entry->data.u.prv_ipv6[0], + 16); + + #ifdef NAT_ONLY_CONFIG_REQ + if (!nat_only_config_flag) { + #endif + *dst_port = rte_bswap16(entry->data.prv_port); + + #ifdef NAT_ONLY_CONFIG_REQ + } + #endif + + p_nat->inaptedPktCount++; + } + + p_nat->naptedPktCount++; + + #ifdef HW_CHECKSUM_REQ + if (p_nat->hw_checksum_reqd) + hw_checksum(pkt, pkt_type); + else + #endif + sw_checksum(pkt, pkt_type); +} + + +/** + * NAPT function for IPv6 private traffic which handles 4 pkts + * + * @param pkts + * A pointer to array of packets mbuf + * @param in_pkt_num + * Starting pkt number of pkts + * @param arg + * Void pointer + * @param p_nat + * A pointer to main CGNAPT structure + * + */ +void +pkt4_work_cgnapt_ipv6_prv( + struct rte_mbuf **pkts, + uint32_t in_pkt_num, + __rte_unused void *arg, + struct pipeline_cgnapt *p_nat) +{ + struct rte_mbuf *pkt; + uint8_t i; + uint8_t pkt_num; + + enum PKT_TYPE pkt_type = PKT_TYPE_IPV6to4; + + for (i = 0; i < 4; i++) { + pkt_num = in_pkt_num + i; + pkt = pkts[i]; + + /* index into hash table entries */ + int hash_table_entry = p_nat->lkup_indx[pkt_num]; + /*bitmask representing only this packet */ + uint64_t pkt_mask = 1LLU << pkt_num; + + uint8_t protocol = RTE_MBUF_METADATA_UINT8(pkt, PROT_OFST_IP6); + uint32_t dest_if = INVALID_DESTIF; + uint16_t *outport_id = + RTE_MBUF_METADATA_UINT16_PTR(pkt, cgnapt_meta_offset); + struct cgnapt_table_entry *entry = NULL; + + if (hash_table_entry < 0) { + + /* try to add new entry */ + struct rte_pipeline_table_entry *table_entry = NULL; + + uint64_t dropmask = + pkt_miss_cgnapt(p_nat->key_ptrs[pkt_num], pkt, + &table_entry, + &p_nat->valid_packets, pkt_num, + (void *)p_nat); + + if (!table_entry) { + /* ICMP Error message generation for + * Destination Host unreachable + */ + /* Do we need this check for ipv6? */ + if (protocol == IP_PROTOCOL_ICMP) { + cgnapt_icmp_pkt = pkt; + send_icmp_dest_unreachable_msg(); + } + + /* Drop packet by adding to invalid pkt mask */ + + p_nat->invalid_packets |= dropmask; + + #ifdef CGNAPT_DEBUGGING + if (p_nat->kpc2++ < 5) { + printf("in_ah Th: %d", + p_nat->pipeline_num); + print_key(p_nat->key_ptrs[pkt_num]); + } + #endif + + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount3++; + #endif + + continue; + } + + entry = (struct cgnapt_table_entry *)table_entry; + } else { + /* entry found for this packet */ + entry = &napt_hash_tbl_entries[hash_table_entry]; + } + + /* apply napt and mac changes */ + + p_nat->entries[pkt_num] = &(entry->head); + + struct ipv6_hdr ipv6_hdr; + struct ether_addr hw_addr; + uint32_t dest_address = 0; + uint8_t nh_ipv6[16]; + uint32_t nhip = 0; + + /* Egress */ + { + convert_ipv6_to_ipv4(pkt, &ipv6_hdr); + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG >= 1) + printf("pkt_work_cganpt: " + "convert_ipv6_to_ipv4\n"); + #endif + + struct cgnapt_nsp_node *ll = nsp_ll; + int nsp = 0; + + while (ll != NULL) { + if (!memcmp(&ipv6_hdr.dst_addr[0], + &ll->nsp.prefix[0], + ll->nsp.depth / 8)) { + nsp = 1; + break; + } + ll = ll->next; + } + + if (!nsp + && !memcmp(&ipv6_hdr.dst_addr[0], + &well_known_prefix[0], 12)) { + nsp = 1; + } + + if (!nsp) { + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount5++; + #endif + continue; + } + + } + + /* As packet is already converted into IPv4 we must not + * operate IPv6 offsets on packet only perform IPv4 operations + */ + + uint32_t *src_addr = + RTE_MBUF_METADATA_UINT32_PTR(pkt, SRC_ADR_OFST_IP6t4); + uint32_t *dst_addr = + RTE_MBUF_METADATA_UINT32_PTR(pkt, DST_ADR_OFST_IP6t4); + uint16_t *src_port = + RTE_MBUF_METADATA_UINT16_PTR(pkt, SRC_PRT_OFST_IP6t4); + uint16_t *dst_port = + RTE_MBUF_METADATA_UINT16_PTR(pkt, DST_PRT_OFST_IP6t4); + + uint8_t *eth_dest = + RTE_MBUF_METADATA_UINT8_PTR(pkt, ETH_OFST_IP6t4); + uint8_t *eth_src = + RTE_MBUF_METADATA_UINT8_PTR(pkt, ETH_OFST_IP6t4 + 6); + + if (entry->data.ttl == NAPT_ENTRY_STALE) + entry->data.ttl = NAPT_ENTRY_VALID; + + /* Egress */ + { + + if (unlikely(protocol == IP_PROTOCOL_UDP + && rte_be_to_cpu_16(*dst_port) == 53)) { + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount6++; + #endif + continue; + } + + dest_address = rte_bswap32(*dst_addr); + uint32_t nhip; + uint32_t ret; + ret = local_get_nh_ipv4(dest_address, &dest_if, &nhip, p_nat); + if (!ret) { + dest_if = get_prv_to_pub_port(&dest_address, IP_VERSION_4); + + if (dest_if == INVALID_DESTIF) { + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount6++; + #endif + continue; + } + + do_local_nh_ipv4_cache(dest_if, p_nat); + } + *outport_id = p_nat->outport_id[dest_if]; + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 2) + printf("Egress: \tphy_port:%d\t" + "get_prv_to_pub():%d \tout_port:%d\n", + pkt->port, dest_if, *outport_id); + #endif + } + + #ifdef CGNAPT_DEBUGGING + static int static_count; + + if (static_count++ < 10) { + print_pkt(pkt); + my_print_entry(entry); + printf("dest-offset:%d\n", DST_ADR_OFST_IP4); + printf("dest_add:%x\n", entry->data.u.prv_ip); + printf("dest_add:%x\n", *dst_addr); + printf("DST_ADR_OFST_IP6:%d\n", DST_ADR_OFST_IP6); + } + #endif + + memset(nh_ipv6, 0, 16); + + { + int ret; + ret = get_dest_mac_addr_port(dest_address, &dest_if, &hw_addr); + + if (unlikely(ret != ARP_FOUND)) { + + if (unlikely(ret == ARP_NOT_FOUND)) { + /* Commented code may be required for debug + * and future use, Please keep it */ + //request_arp(*outport_id, nhip, p_nat->p.p); + printf("%s: ARP Not Found, nhip: %x, " + "outport_id: %d\n", __func__, nhip, + *outport_id); + } + + /* Drop the pkt */ + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount4++; + #endif + continue; + + } + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 2) { + printf("MAC found for ip 0x%x, port %d - " + "%02x:%02x:%02x:%02x:%02x:%02x\n", + dest_address, *outport_id, + hw_addr.addr_bytes[0], + hw_addr.addr_bytes[1], + hw_addr.addr_bytes[2], + hw_addr.addr_bytes[3], + hw_addr.addr_bytes[4], + hw_addr.addr_bytes[5] + ); + + printf("Dest MAC before - " + "%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]); + } + #endif + + memcpy(eth_dest, &hw_addr, sizeof(struct ether_addr)); + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 2) { + printf("Dest MAC after - " + "%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]); + } + #endif + + memcpy(eth_src, + get_link_hw_addr(dest_if), + sizeof(struct ether_addr)); + } + + { + /* Egress */ + *src_addr = rte_bswap32(entry->data.pub_ip); + + #ifdef NAT_ONLY_CONFIG_REQ + if (!nat_only_config_flag) { + #endif + *src_port = rte_bswap16(entry->data.pub_port); + + #ifdef NAT_ONLY_CONFIG_REQ + } + #endif + + p_nat->enaptedPktCount++; + } + + p_nat->naptedPktCount++; + + #ifdef HW_CHECKSUM_REQ + if (p_nat->hw_checksum_reqd) + hw_checksum(pkt, pkt_type); + else + #endif + sw_checksum(pkt, pkt_type); + } +} + +/** + * NAPT function for IPv6 public traffic which handles 4 pkts + * + * @param pkts + * A pointer to array of packets mbuf + * @param in_pkt_num + * Starting pkt number of pkts + * @param arg + * Void pointer + * @param p_nat + * A pointer to main CGNAPT structure + * + */ +void +pkt4_work_cgnapt_ipv6_pub( + struct rte_mbuf **pkts, + uint32_t in_pkt_num, + __rte_unused void *arg, + struct pipeline_cgnapt *p_nat) +{ + struct rte_mbuf *pkt; + uint8_t i; + uint8_t pkt_num; + + enum PKT_TYPE pkt_type = PKT_TYPE_IPV4to6; + + for (i = 0; i < 4; i++) { + pkt_num = in_pkt_num + i; + pkt = pkts[i]; + + /* index into hash table entries */ + int hash_table_entry = p_nat->lkup_indx[pkt_num]; + /*bitmask representing only this packet */ + uint64_t pkt_mask = 1LLU << pkt_num; + + uint8_t protocol = RTE_MBUF_METADATA_UINT8(pkt, PROT_OFST_IP4); + uint16_t *outport_id = + RTE_MBUF_METADATA_UINT16_PTR(pkt, cgnapt_meta_offset); + struct cgnapt_table_entry *entry = NULL; + + if (hash_table_entry < 0) { + + /* Drop ingress initial traffic */ + + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount3++; + if (p_nat->kpc2++ < 5) { + printf("in_ah Th: %d", p_nat->pipeline_num); + print_key(p_nat->key_ptrs[pkt_num]); + } + #endif + + continue; + + } else { + /* entry found for this packet */ + entry = &napt_hash_tbl_entries[hash_table_entry]; + } + + /* apply napt and mac changes */ + + p_nat->entries[pkt_num] = &(entry->head); + if (entry->data.type != CGNAPT_ENTRY_IPV6) { + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + continue; + } + + struct ipv4_hdr ipv4_hdr; + + uint16_t *src_port = + RTE_MBUF_METADATA_UINT16_PTR(pkt, SRC_PRT_OFST_IP4_TCP); + + 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 (entry->data.ttl == NAPT_ENTRY_STALE) + entry->data.ttl = NAPT_ENTRY_VALID; + + struct ether_addr hw_addr; + uint8_t dest_addr_ipv6[16]; + uint8_t nh_ipv6[16]; + uint32_t dest_if = INVALID_DESTIF; + /* Ingress */ + { + + if (unlikely(protocol == IP_PROTOCOL_UDP + && rte_be_to_cpu_16(*src_port) == 53)) { + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount6++; + #endif + continue; + } + + memcpy(&dest_addr_ipv6[0], &entry->data.u.prv_ipv6[0], + 16); + uint8_t nhipv6[16]; + int ret; + ret = local_get_nh_ipv6(&dest_addr_ipv6[0], &dest_if, + &nhipv6[0], p_nat); + if (!ret) { + dest_if = get_prv_to_pub_port((uint32_t *) + &dest_addr_ipv6[0], IP_VERSION_6); + + if (dest_if == INVALID_DESTIF) { + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount6++; + #endif + return; + } + + do_local_nh_ipv6_cache(dest_if, p_nat); + } + + *outport_id = p_nat->outport_id[dest_if]; + } + + #ifdef CGNAPT_DEBUGGING + static int static_count; + + if (static_count++ < 10) { + print_pkt(pkt); + my_print_entry(entry); + printf("dest-offset:%d\n", DST_ADR_OFST_IP4); + printf("dest_add:%x\n", entry->data.u.prv_ip); + printf("DST_ADR_OFST_IP6:%d\n", DST_ADR_OFST_IP6); + } + #endif + + memset(nh_ipv6, 0, 16); + if (get_dest_mac_address_ipv6 + (&dest_addr_ipv6[0], &dest_if, + &hw_addr, &nh_ipv6[0])) { + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 2) { + printf("MAC found for ip 0x%x, port %d - " + "%02x:%02x:%02x:%02x:%02x:%02x\n", + *((uint32_t *)dest_addr_ipv6 + 12), + *outport_id, + hw_addr.addr_bytes[0], hw_addr.addr_bytes[1], + hw_addr.addr_bytes[2], hw_addr.addr_bytes[3], + hw_addr.addr_bytes[4], hw_addr.addr_bytes[5]); + + printf("Dest MAC before - " + "%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]); + } + #endif + + memcpy(eth_dest, &hw_addr, sizeof(struct ether_addr)); + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 2) { + printf("Dest MAC after - " + "%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]); + } + #endif + + memcpy(eth_src, + get_link_hw_addr(dest_if), + sizeof(struct ether_addr)); + } else { + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->naptDroppedPktCount4++; + #endif + + continue; + } + + { + /* Ingress */ + + convert_ipv4_to_ipv6(pkt, &ipv4_hdr); + + /* Ethernet MTU check */ + if ((rte_pktmbuf_data_len(pkt) - 14) > 1500) { + p_nat->invalid_packets |= pkt_mask; + p_nat->naptDroppedPktCount++; + continue; + } + uint32_t *dst_addr = RTE_MBUF_METADATA_UINT32_PTR(pkt, + DST_ADR_OFST_IP4t6); + uint16_t *dst_port = RTE_MBUF_METADATA_UINT16_PTR(pkt, + DST_PRT_OFST_IP4t6); + + memcpy((uint8_t *) &dst_addr[0], + &entry->data.u.prv_ipv6[0], 16); + + #ifdef NAT_ONLY_CONFIG_REQ + if (!nat_only_config_flag) { + #endif + *dst_port = rte_bswap16(entry->data.prv_port); + + #ifdef NAT_ONLY_CONFIG_REQ + } + #endif + + p_nat->inaptedPktCount++; + } + + p_nat->naptedPktCount++; + + #ifdef HW_CHECKSUM_REQ + if (p_nat->hw_checksum_reqd) + hw_checksum(pkt, pkt_type); + else + #endif + sw_checksum(pkt, pkt_type); + } +} + +/** + * Input port handler for IPv6 private traffic + * Starting from the packet burst it filters unwanted packets, + * calculates keys, does lookup and then based on the lookup + * updates NAPT table and does packet NAPT translation. + * + * @param rte_p + * A pointer to struct rte_pipeline + * @param pkts + * A pointer to array of packets mbuf + * @param n_pkts + * Number of packets in the burst + * @param arg + * Void pointer + * + * @return + * int that is not checked by caller + */ +static int cgnapt_in_port_ah_ipv6_prv(struct rte_pipeline *rte_p, + struct rte_mbuf **pkts, + uint32_t n_pkts, void *arg) +{ + uint32_t i, j; + struct pipeline_cgnapt_in_port_h_arg *ap = arg; + struct pipeline_cgnapt *p_nat = ap->p; + + p_nat->pkt_burst_cnt = 0; /* for dynamic napt */ + p_nat->valid_packets = rte_p->pkts_mask; /*n_pkts; */ + p_nat->invalid_packets = 0; + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 1) + printf("cgnapt_key hit fn: %" PRIu32 "\n", n_pkts); + #endif + + /* prefetching for mbufs should be done here */ + for (j = 0; j < n_pkts; j++) + rte_prefetch0(pkts[j]); + + for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4) + pkt4_work_cgnapt_key_ipv6_prv(&pkts[i], i, arg, p_nat); + + for (; i < n_pkts; i++) + pkt_work_cgnapt_key_ipv6_prv(pkts[i], i, arg, p_nat); + + p_nat->valid_packets &= ~(p_nat->invalid_packets); + + if (unlikely(p_nat->valid_packets == 0)) { + /* no suitable packet for lookup */ + rte_pipeline_ah_packet_drop(rte_p, p_nat->invalid_packets); + return p_nat->valid_packets; + } + + /* lookup entries in the common napt table */ + + int lookup_result = rte_hash_lookup_bulk( + napt_common_table, + (const void **) &p_nat->key_ptrs, + /* should be minus num invalid pkts */ + n_pkts, + /*new pipeline data member */ + &p_nat->lkup_indx[0]); + + if (unlikely(lookup_result < 0)) { + /* unknown error, just discard all packets */ + printf("Unexpected hash lookup error %d, " + "discarding all packets", + lookup_result); + rte_pipeline_ah_packet_drop(rte_p, p_nat->valid_packets); + return 0; + } + + /* Now call second stage of pipeline to one by one + * check the result of our bulk lookup + */ + + /* prefetching for table entries should be done here */ + for (j = 0; j < n_pkts; j++) { + if (p_nat->lkup_indx[j] >= 0) + rte_prefetch0(&napt_hash_tbl_entries + [p_nat->lkup_indx[j]]); + } + + for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4) + pkt4_work_cgnapt_ipv6_prv(&pkts[i], i, arg, p_nat); + + for (; i < n_pkts; i++) + pkt_work_cgnapt_ipv6_prv(pkts[i], i, arg, p_nat); + + if (p_nat->invalid_packets) { + /* get rid of invalid packets */ + rte_pipeline_ah_packet_drop(rte_p, p_nat->invalid_packets); + + p_nat->valid_packets &= ~(p_nat->invalid_packets); + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 1) { + printf("valid_packets:0x%jx\n", p_nat->valid_packets); + printf("rte_valid_packets :0x%jx\n", rte_p->pkts_mask); + printf("invalid_packets:0x%jx\n", + p_nat->invalid_packets); + printf("rte_invalid_packets :0x%jx\n", + rte_p->pkts_drop_mask); + printf("Total pkts dropped :0x%jx\n", + rte_p->n_pkts_ah_drop); + } + #endif + } + + return p_nat->valid_packets; +} + + +/** + * Input port handler for IPv6 public traffic + * Starting from the packet burst it filters unwanted packets, + * calculates keys, does lookup and then based on the lookup + * updates NAPT table and does packet NAPT translation. + * + * @param rte_p + * A pointer to struct rte_pipeline + * @param pkts + * A pointer to array of packets mbuf + * @param n_pkts + * Number of packets in the burst + * @param arg + * Void pointer + * + * @return + * int that is not checked by caller + */ +static int cgnapt_in_port_ah_ipv6_pub(struct rte_pipeline *rte_p, + struct rte_mbuf **pkts, + uint32_t n_pkts, void *arg) +{ + uint32_t i, j; + struct pipeline_cgnapt_in_port_h_arg *ap = arg; + struct pipeline_cgnapt *p_nat = ap->p; + + p_nat->pkt_burst_cnt = 0; /* for dynamic napt */ + p_nat->valid_packets = rte_p->pkts_mask; /*n_pkts; */ + p_nat->invalid_packets = 0; + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 1) + printf("cgnapt_key hit fn: %" PRIu32 "\n", n_pkts); + #endif + + /* prefetching for mbufs should be done here */ + for (j = 0; j < n_pkts; j++) + rte_prefetch0(pkts[j]); + + for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4) + pkt4_work_cgnapt_key_ipv6_pub(&pkts[i], i, arg, p_nat); + + for (; i < n_pkts; i++) + pkt_work_cgnapt_key_ipv6_pub(pkts[i], i, arg, p_nat); + + p_nat->valid_packets &= ~(p_nat->invalid_packets); + + if (unlikely(p_nat->valid_packets == 0)) { + /* no suitable packet for lookup */ + rte_pipeline_ah_packet_drop(rte_p, p_nat->invalid_packets); + return p_nat->valid_packets; + } + + /* lookup entries in the common napt table */ + + int lookup_result = rte_hash_lookup_bulk( + napt_common_table, + (const void **) &p_nat->key_ptrs, + /* should be minus num invalid pkts */ + n_pkts, + /*new pipeline data member */ + &p_nat->lkup_indx[0]); + + if (unlikely(lookup_result < 0)) { + /* unknown error, just discard all packets */ + printf("Unexpected hash lookup error %d, " + "discarding all packets", + lookup_result); + rte_pipeline_ah_packet_drop(rte_p, p_nat->valid_packets); + return 0; + } + + /* Now call second stage of pipeline to one by one + * check the result of our bulk lookup + */ + + /* prefetching for table entries should be done here */ + for (j = 0; j < n_pkts; j++) { + if (p_nat->lkup_indx[j] >= 0) + rte_prefetch0(&napt_hash_tbl_entries + [p_nat->lkup_indx[j]]); + } + + for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4) + pkt4_work_cgnapt_ipv6_pub(&pkts[i], i, arg, p_nat); + + for (; i < n_pkts; i++) + pkt_work_cgnapt_ipv6_pub(pkts[i], i, arg, p_nat); + + if (p_nat->invalid_packets) { + /* get rid of invalid packets */ + rte_pipeline_ah_packet_drop(rte_p, p_nat->invalid_packets); + + p_nat->valid_packets &= ~(p_nat->invalid_packets); + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 1) { + printf("valid_packets:0x%jx\n", p_nat->valid_packets); + printf("rte_valid_packets :0x%jx\n", rte_p->pkts_mask); + printf("invalid_packets:0x%jx\n", + p_nat->invalid_packets); + printf("rte_invalid_packets :0x%jx\n", + rte_p->pkts_drop_mask); + printf("Total pkts dropped :0x%jx\n", + rte_p->n_pkts_ah_drop); + } + #endif + } + + return p_nat->valid_packets; +} + +/** + * Function to send ICMP dest unreachable msg + * + */ +void send_icmp_dest_unreachable_msg(void) +{ + + struct ether_hdr *eth_h; + struct ipv4_hdr *ip_h; + struct icmp_hdr *icmp_h; + struct rte_mbuf *icmp_pkt = cgnapt_icmp_pkt; + + if (icmp_pkt == NULL) { + if (ARPICMP_DEBUG) + printf("Error allocating icmp_pkt rte_mbuf\n"); + return; + } + uint16_t port_id; + port_id = icmp_pkt->port; + + struct app_link_params *link; + link = &mylink[port_id]; + 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)); + + struct ether_addr gw_addr; + struct ether_addr dst_addr; + ether_addr_copy(ð_h->s_addr, &dst_addr); + rte_eth_macaddr_get(port_id, &gw_addr); + ether_addr_copy(&gw_addr, ð_h->s_addr); + ether_addr_copy(&dst_addr, ð_h->d_addr); + + eth_h->ether_type = CHECK_ENDIAN_16(ETHER_TYPE_IPv4); + 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; + + uint32_t *src_addr; + uint32_t src_addr_offset = + MBUF_HDR_ROOM + ETH_HDR_SIZE + IP_HDR_SRC_ADR_OFST; + src_addr = + RTE_MBUF_METADATA_UINT32_PTR(cgnapt_icmp_pkt, src_addr_offset); + + ip_h->dst_addr = *src_addr; + ip_h->src_addr = rte_bswap32(link->ip); + + ip_h->dst_addr = *src_addr; + ip_h->src_addr = rte_bswap32(link->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; + if (ARPICMP_DEBUG) { + printf("Sending ICMP error message - " + "Destination Unreachable\n"); + } + rte_pipeline_port_out_packet_insert(myP, port_id, icmp_pkt); +} + +/** + * Function to add a dynamic NAPT entry pair + * + * @param p + * A pointer to struct pipeline + * @param key + * A pointer to struct pipeline_cgnapt_entry_key + * @param time_out + * expairy time of an dynamic or PCP req entry + * @param src_addr + * uint8_t pointer of source address + * + * @return + * A pointer to struct cgnapt_table_entry for added entry + */ + +struct cgnapt_table_entry *add_dynamic_cgnapt_entry( + struct pipeline *p, + struct pipeline_cgnapt_entry_key *key, + uint32_t timeout, + uint8_t pkt_type, + uint8_t *src_addr, + uint8_t *err) +{ + int port_num = 0; + void *entry_ptr, *ret_ptr; + int ret = 0, i; + + struct pipeline_cgnapt *p_nat = (struct pipeline_cgnapt *)p; + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG >= 1) { + printf("Th%d add_dynamic_cgnapt_entry key detail Entry:" + "0x%x, %d, %d\n", p_nat->pipeline_num, key->ip, key->port, + key->pid); + } + #endif + + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX && i < p_nat->pkt_burst_cnt; + i++) { + if (p_nat->cgnapt_dyn_ent_table[i].ip == key->ip + && p_nat->cgnapt_dyn_ent_table[i].port == key->port + && p_nat->cgnapt_dyn_ent_table[i].pid == key->pid) { + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 1) + printf("add_dynamic_cgnapt_entry:pkt_burst " + "array key matched!!!\n"); + #endif + + return &napt_hash_tbl_entries + [p_nat->cgnapt_dyn_ent_index[i]]; + } + } + + #ifdef NAT_ONLY_CONFIG_REQ + if (!nat_only_config_flag) { + #endif + + ret = increment_max_port_counter(key->ip, key->pid, p_nat); + if (ret == MAX_PORT_INC_ERROR) { + + #ifdef CGNAPT_DEBUGGING + p_nat->missedpktcount5++; + #endif + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 1) + printf("add_dynamic_cgnapt_entry:" + "increment_max_port_counter-1 failed\n"); + #endif + + *err = 1; + return NULL; + } + + if (ret == MAX_PORT_INC_REACHED) { + + #ifdef CGNAPT_DEBUGGING + p_nat->missedpktcount6++; + #endif + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 1) + printf("add_dynamic_cgnapt_entry:" + "increment_max_port_counter-2 failed\n"); + #endif + + *err = 1; + return NULL; + } + + #ifdef NAT_ONLY_CONFIG_REQ + } + #endif + + uint32_t public_ip; + port_num = get_free_iport(p_nat, &public_ip); + + if (port_num == -1) { + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 2) { + printf("add_dynamic_cgnapt_entry: %d\n", port_num); + printf("add_dynamic_cgnapt_entry key detail:0x%x, " + "%d, %d\n", key->ip, key->port, key->pid); + } + #endif + + #ifdef CGNAPT_DEBUGGING + p_nat->missedpktcount7++; + #endif + + *err = 1; + return NULL; + } + + #ifdef NAT_ONLY_CONFIG_REQ + if (!nat_only_config_flag) { + #endif + + if (ret == 2) { //MPPC_NEW_ENTRY + + /* check for max_clients_per_ip */ + if (rte_atomic16_read + (&all_public_ip + [rte_jhash(&public_ip, 4, 0) % + CGNAPT_MAX_PUB_IP].count) == + p_nat->max_clients_per_ip) { + + /* For now just bail out + * In future we can think about + * retrying getting a new iport + */ + + release_iport(port_num, public_ip, p_nat); + + #ifdef CGNAPT_DEBUGGING + p_nat->missedpktcount10++; + #endif + *err = 1; + return NULL; + } + + rte_atomic16_inc(&all_public_ip + [rte_jhash(&public_ip, 4, 0) % + CGNAPT_MAX_PUB_IP].count); + + #ifdef CGNAPT_DBG_PRNT + if ((rte_jhash(&public_ip, 4, 0) % + CGNAPT_MAX_PUB_IP) == 8) + printf("pub ip:%x coutn:%d\n", public_ip, + rte_atomic16_read(&all_public_ip + [rte_jhash(&public_ip, 4, 0) % + CGNAPT_MAX_PUB_IP].count)); + #endif + + } + #ifdef NAT_ONLY_CONFIG_REQ + } + #endif + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 0) { + printf("add_dynamic_cgnapt_entry: %d\n", + port_num); + printf("add_dynamic_cgnapt_entry key detail: " + "0x%x, %d, %d\n", key->ip, key->port, key->pid); + } + #endif + + struct cgnapt_table_entry entry = { + .head = { + .action = RTE_PIPELINE_ACTION_PORT, + /* made it configurable below */ + {.port_id = p->port_out_id[0]}, + }, + + .data = { + .prv_port = key->port, + .pub_ip = public_ip, + .pub_port = port_num, + .prv_phy_port = key->pid, + .pub_phy_port = get_pub_to_prv_port( + &public_ip, + IP_VERSION_4), + .ttl = 0, + /* if(timeout == -1) : static entry + * if(timeout == 0 ) : dynamic entry + * if(timeout > 0 ) : PCP requested entry + */ + .timeout = timeout > 0 ? timeout : 0, + #ifdef PCP_ENABLE + .timer = NULL, + #endif + } + }; + + #ifdef NAT_ONLY_CONFIG_REQ + if (nat_only_config_flag) { + entry.data.prv_port = 0xffff; + entry.data.pub_port = 0xffff; + } + #endif + + if (pkt_type == CGNAPT_ENTRY_IPV6) { + entry.data.type = CGNAPT_ENTRY_IPV6; + memcpy(&entry.data.u.prv_ipv6[0], src_addr, 16); + } else { + entry.data.u.prv_ip = key->ip; + entry.data.type = CGNAPT_ENTRY_IPV4; + } + + //entry.head.port_id = CGNAPT_PUB_PORT_ID; /* outgoing port info */ + entry.head.port_id = entry.data.pub_phy_port; /* outgoing port info */ + + struct pipeline_cgnapt_entry_key second_key; + /* Need to add a second ingress entry */ + second_key.ip = public_ip; + second_key.port = port_num; + second_key.pid = 0xffff; + + #ifdef NAT_ONLY_CONFIG_REQ + if (nat_only_config_flag) + second_key.port = 0xffff; + #endif + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 2) + printf("add_dynamic_cgnapt_entry second key detail:" + "0x%x, %d, %d\n", second_key.ip, second_key.port, + second_key.pid); + #endif + + int32_t position = rte_hash_add_key(napt_common_table, (void *)key); + + if (position < 0) { + #ifdef CGNAPT_DEBUGGING + p_nat->missedpktcount8++; + #endif + + printf("CG-NAPT entry add failed ...returning " + "without adding ... %d\n", position); + *err = 1; + return NULL; + } + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG) { + printf("add_dynamic_cgnapt_entry\n"); + print_key(key); + print_cgnapt_entry(&entry); + } + #endif + + memcpy(&napt_hash_tbl_entries[position], &entry, + sizeof(struct cgnapt_table_entry)); + + /* this pointer is returned to pkt miss function */ + ret_ptr = &napt_hash_tbl_entries[position]; + + p_nat->n_cgnapt_entry_added++; + p_nat->dynCgnaptCount++; + + /* Now modify the forward port for reverse entry */ + + /* outgoing port info */ + //entry.head.port_id = CGNAPT_PRV_PORT_ID; + /* outgoing port info */ + entry.head.port_id = entry.data.prv_phy_port; + + int32_t position2 = rte_hash_add_key(napt_common_table, &second_key); + + if (position2 < 0) { + #ifdef CGNAPT_DEBUGGING + p_nat->missedpktcount9++; + #endif + printf("CG-NAPT entry reverse bulk add failed ..." + "returning with fwd add ...%d\n", + position2); + *err = 1; + return NULL; + } + + memcpy(&napt_hash_tbl_entries[position2], &entry, + sizeof(struct cgnapt_table_entry)); + + entry_ptr = &napt_hash_tbl_entries[position2]; + + timer_thread_enqueue(key, &second_key, ret_ptr, + entry_ptr, (struct pipeline *)p_nat); + + p_nat->n_cgnapt_entry_added++; + p_nat->dynCgnaptCount++; + + if (p_nat->pkt_burst_cnt < RTE_PORT_IN_BURST_SIZE_MAX) { + memcpy(&p_nat->cgnapt_dyn_ent_table[p_nat->pkt_burst_cnt], key, + sizeof(struct pipeline_cgnapt_entry_key)); + p_nat->cgnapt_dyn_ent_index[p_nat->pkt_burst_cnt] = position; + p_nat->pkt_burst_cnt++; + } + return ret_ptr; +} + +int pkt_miss_cgnapt_count; +/** + * Function handle a missed NAPT entry lookup + * Will attempt to add a dynamic entry pair. + * + * @param p + * A pointer to struct pipeline + * @param key + * A pointer to struct pipeline_cgnapt_entry_key + * @param pkt + * A pointer to pkt struct rte_mbuf + * @param pkt_mask + * uint64_t pointer to pkt mask + * @param table_entry + * A pointer to struct rte_pipeline_table_entry to be created and returned + * @param pkt_num + * number of this pkt in current burst + * + * @return + * A uint64_t mask for drop packets + */ +uint64_t +pkt_miss_cgnapt(struct pipeline_cgnapt_entry_key *key, + struct rte_mbuf *pkt, + struct rte_pipeline_table_entry **table_entry, + __rte_unused uint64_t *pkts_mask, + uint32_t pkt_num, void *arg) +{ + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 0) + printf("\n pkt_miss_cgnapt\n"); + #endif + /* In egress case + * get src address + * see if get_port passes for this src address + * if passed add a new egress entry and a + * corresponding new ingress entry + * return the fwd entry to calling function using input pointer + * else if get_port fails drop packet + */ + + struct pipeline_cgnapt *p_nat = (struct pipeline_cgnapt *)arg; + + uint32_t eth_proto_offset = MBUF_HDR_ROOM + 12; + uint32_t src_addr_offset_ipv6 = + MBUF_HDR_ROOM + ETH_HDR_SIZE + IPV6_HDR_SRC_ADR_OFST; + uint16_t phy_port = pkt->port; + + uint16_t *eth_proto = + RTE_MBUF_METADATA_UINT16_PTR(pkt, eth_proto_offset); + + uint8_t *src_addr = NULL; + uint8_t src_addr_ipv6[16]; + uint8_t pkt_type = CGNAPT_ENTRY_IPV4; + /* To drop the packet */ + uint64_t drop_mask = 0; + + if (p_nat->is_static_cgnapt) { + drop_mask |= 1LLU << pkt_num; + p_nat->missedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->missedpktcount1++; + #endif + return drop_mask; + } + + if (rte_be_to_cpu_16(*eth_proto) == ETHER_TYPE_IPv6) { + src_addr = + RTE_MBUF_METADATA_UINT8_PTR(pkt, src_addr_offset_ipv6); + pkt_type = CGNAPT_ENTRY_IPV6; + memcpy(src_addr_ipv6, src_addr, 16); + } + + uint8_t err = 0; + + /* some validation first */ + if (is_phy_port_privte(phy_port)) { + /* dynamic NAPT entry creation */ + *table_entry = (struct rte_pipeline_table_entry *) + add_dynamic_cgnapt_entry( + (struct pipeline *)&p_nat->p, + key, + DYNAMIC_CGNAPT_TIMEOUT, + pkt_type, + src_addr_ipv6, &err); + + if (!(*table_entry)) { + if (err) { + drop_mask |= 1LLU << pkt_num; + p_nat->missedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->missedpktcount2++; + #endif + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 1) + printf("Add Dynamic NAT entry failed " + "in pkt!!!\n"); + #endif + } else { + #ifdef CGNAPT_DEBUGGING + p_nat->missedpktcount11++; + #endif + } + + } + + } else if (!is_phy_port_privte(phy_port)) { + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG >= 2) { + printf("Initial Ingress entry creation NOT ALLOWED " + "%d\n", phy_port); + } + #endif + + drop_mask |= 1LLU << pkt_num; + p_nat->missedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->missedpktcount3++; + #endif + } else { + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 1) + printf("NOT a PRIVATE or PUBLIC port!!!!!\n"); + #endif + + drop_mask |= 1LLU << pkt_num; + p_nat->missedPktCount++; + + #ifdef CGNAPT_DEBUGGING + p_nat->missedpktcount4++; + #endif + } + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 5) + print_pkt(pkt); + #endif + + return drop_mask; +} + +int numprints; + +/** + * Function to print the contents of a packet + * + * @param pkt + * A pointer to pkt struct rte_mbuf + */ +void print_pkt(struct rte_mbuf *pkt) +{ + int i = 0, j = 0; + + printf("\nPacket Contents:\n"); + + uint8_t *rd = RTE_MBUF_METADATA_UINT8_PTR(pkt, 0); + + for (i = 0; i < 20; i++) { + for (j = 0; j < 20; j++) + printf("%02x ", rd[(20 * i) + j]); + + printf("\n"); + } +} + +rte_table_hash_op_hash cgnapt_hash_func[] = { + hash_default_key8, + hash_default_key16, + hash_default_key24, + hash_default_key32, + hash_default_key40, + hash_default_key48, + hash_default_key56, + hash_default_key64 +}; + +/** + * Function to parse incoming pipeline arguments + * Called during pipeline initialization + * + * @param p + * A pointer to struct pipeline_cgnapt + * @param params + * A pointer to struct pipeline_params + * + * @return + * 0 if success, negative if failure + */ +static int +pipeline_cgnapt_parse_args(struct pipeline_cgnapt *p, + struct pipeline_params *params) +{ + uint32_t n_flows_present = 0; + uint32_t key_offset_present = 0; + uint32_t key_size_present = 0; + uint32_t hash_offset_present = 0; + uint32_t n_entries_present = 0; + uint32_t max_port_present = 0; + uint32_t max_client_present = 0; + uint32_t public_ip_range_present = 0; + uint32_t public_ip_port_range_present = 0; + uint32_t i; + uint8_t public_ip_count = 0; + uint8_t public_ip_range_count = 0; + uint8_t dest_if_offset_present = 0; + uint8_t cgnapt_meta_offset_present = 0; + uint8_t prv_que_handler_present = 0; + uint8_t n_prv_in_port = 0; + + if (CGNAPT_DEBUG > 2) { + printf("CGNAPT pipeline_cgnapt_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 (CGNAPT_DEBUG > 2) { + printf("CGNAPT args[%d]: %s %d, %s\n", i, arg_name, + atoi(arg_value), arg_value); + } + 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 == NULL) { + printf("string is null\n"); + printf("invalid prv_que_handler value/n"); + return -1; + } + printf("string is :%s\n", token); + + /* walk through other tokens */ + while (token != NULL) { + printf(" %s\n", token); + rxport = atoi(token); + cgnapt_prv_que_port_index[n_prv_in_port++] = + rxport; + if (rxport < PIPELINE_MAX_PORT_IN) + cgnapt_in_port_egress_prv[rxport] = 1; + token = strtok(NULL, ","); + } + + if (n_prv_in_port == 0) { + printf("VNF common parse err - " + "no prv RX phy port\n"); + return -1; + } + continue; + } + + if (strcmp(arg_name, "cgnapt_meta_offset") == 0) { + if (cgnapt_meta_offset_present) { + printf("CG-NAPT parse error:"); + printf("cgnapt_meta_offset initizlized " + "mulitple times\n"); + return -1; + } + cgnapt_meta_offset_present = 1; + int temp; + temp = atoi(arg_value); + + if (temp > 256) { + printf("cgnapt_meta_offset is invalid :"); + printf("Not be more than metadata size\n"); + return -1; + } + cgnapt_meta_offset = (uint16_t) temp; + } + if (strcmp(arg_name, "vnf_set") == 0) + vnf_set_count++; + + if (strcmp(arg_name, "public_ip_range") == 0) { + public_ip_range_present = 1; + if (public_ip_port_range_present) { + printf("CG-NAPT parse error:"); + printf("public_ip_range with " + "public_ip_port_range_present\n"); + return -1; + } + + p->pub_ip_range = rte_realloc(p->pub_ip_range, + sizeof(struct + pub_ip_range), + RTE_CACHE_LINE_SIZE); + + if (!p->pub_ip_range) { + printf("Memory allocation failed for " + "pub_ip_range\n"); + return -1; + } + + uint32_t sip = 0, eip = 0; + + if (sscanf(arg_value, "(%x,%x)", &sip, &eip) != 2) { + printf("public_ip_range is invalid\n"); + return -1; + } + + if (sip <= 0 || eip <= 0 || sip >= eip) { + printf("public_ip_range is invalid %x-%x\n", + sip, eip); + return -1; + } + + printf("public_ip_range: %d-%d\n", + p->pub_ip_range[public_ip_range_count]. + start_ip = sip, + p->pub_ip_range[public_ip_range_count]. + end_ip = eip); + + p->pub_ip_range_count = ++public_ip_range_count; + continue; + } + + if (strcmp(arg_name, "public_ip_port_range") == 0) { + public_ip_port_range_present = 1; + if (nat_only_config_flag || public_ip_range_present) { + + printf("CG-NAPT parse error:"); + printf("nat_only_config_flag OR "); + printf("public_ip_range_present with " + "public_ip_port_range_present\n"); + return -1; + } + + p->pub_ip_port_set = rte_realloc( + p->pub_ip_port_set, + sizeof(struct pub_ip_port_set), + RTE_CACHE_LINE_SIZE); + + if (!p->pub_ip_port_set) { + printf("Memory allocation failed for " + "public IP\n"); + return -1; + } + + uint32_t ip = 0; + int sp = 0, ep = 0; + + if (sscanf(arg_value, "%x:(%d,%d)", + &ip, &sp, &ep) != 3) { + printf("Public IP or Port-range is invalid\n"); + return -1; + } + + if (ip <= 0 || sp <= 0 || ep <= 0 || sp > ep) { + printf("Public IP or Port-range is invalid " + "%x:%d-%d\n", ip, sp, ep); + return -1; + } + + printf("public_ip: 0x%x Range:%d-%d\n", + p->pub_ip_port_set[public_ip_count].ip = ip, + p->pub_ip_port_set[public_ip_count].start_port = sp, + p->pub_ip_port_set[public_ip_count].end_port = ep); + + napt_port_alloc_elem_count += (ep - sp + 1); + printf("parse - napt_port_alloc_elem_count :%d\n", + napt_port_alloc_elem_count); + + /* Store all public IPs of all CGNAPT threads + * in the global variable + */ + /* to revisit indexing */ + all_public_ip[rte_jhash(&ip, 4, 0) % + CGNAPT_MAX_PUB_IP].ip = ip; + p->pub_ip_count = ++public_ip_count; + printf("public_ip_count:%d hash:%d\n", public_ip_count, + rte_jhash(&ip, 4, 0) % CGNAPT_MAX_PUB_IP); + continue; + } + + /* hw_checksum_reqd */ + if (strcmp(arg_name, "hw_checksum_reqd") == 0) { + int temp; + temp = atoi(arg_value); + if ((temp != 0) && (temp != 1)) { + printf("hw_checksum_reqd is invalid\n"); + return -1; + } + p->hw_checksum_reqd = temp; + continue; + } + + /* nat_only_config_flag */ + if (strcmp(arg_name, "nat_only_config_flag") == 0) { + nat_only_config_flag = 1; + if (public_ip_port_range_present) { + + printf("CG-NAPT parse error:"); + printf("nat_only_config_flag with " + "public_ip_port_range_present\n"); + return -1; + } + continue; + } + + /* max_port_per_client */ + if (strcmp(arg_name, "max_port_per_client") == 0) { + if (max_port_present) { + printf("CG-NAPT Parse Error: " + "duplicate max_port_per_client\n"); + return -1; + } + max_port_present = 1; + + int max = 0; + max = atoi(arg_value); + if (max <= 0) { + printf("max_port_per_client is invalid !!!\n"); + return -1; + } + + p->max_port_per_client = (uint16_t) max; + + if (p->max_port_per_client <= 0) { + printf("max port per client is invalid\n"); + return -1; + } + + printf("max_port_per_client comp: %d\n", + p->max_port_per_client); + continue; + } + + /* max_clients_per_ip */ + if (strcmp(arg_name, "max_clients_per_ip") == 0) { + if (max_client_present) { + printf("CG-NAPT parse Error: duplicate " + "max_clients_per_ip\n"); + return -1; + } + max_client_present = 1; + + if (nat_only_config_flag) { + printf("CG-NAPT parse error:"); + printf("nat_only_config_flag with " + "max_clients_per_ip\n"); + return -1; + } + + int max = 0; + max = atoi(arg_value); + if (max <= 0) { + printf("max_clients_per_ip is invalid !!!\n"); + return -1; + } + + p->max_clients_per_ip = (uint16_t) max; + + if (p->max_clients_per_ip <= 0) { + printf("max_clients_per_ip is invalid\n"); + return -1; + } + + printf("max_clients_per_ip: %d\n", + p->max_clients_per_ip); + continue; + } + + /* n_entries */ + if (strcmp(arg_name, "n_entries") == 0) { + if (n_entries_present) + return -1; + n_entries_present = 1; + + p->n_entries = atoi(arg_value); + if (p->n_entries == 0) + return -1; + + continue; + } + + /* n_flows */ + if (strcmp(arg_name, "n_flows") == 0) { + if (n_flows_present) + return -1; + n_flows_present = 1; + + p->n_flows = atoi(arg_value); + if (p->n_flows == 0) + return -1; + + napt_common_table_hash_params.entries = p->n_flows; + continue; + } + /* dest_if_offset Multiport Changes */ + if (strcmp(arg_name, "dest_if_offset") == 0) { + if (dest_if_offset_present) + return -1; + //dest_if_offset_present = 1; + + dest_if_offset = atoi(arg_value); + + continue; + } + + /* key_offset */ + if (strcmp(arg_name, "key_offset") == 0) { + if (key_offset_present) + return -1; + key_offset_present = 1; + + p->key_offset = atoi(arg_value); + + continue; + } + + /* key_size */ + if (strcmp(arg_name, "key_size") == 0) { + if (key_size_present) + return -1; + key_size_present = 1; + + p->key_size = atoi(arg_value); + if ((p->key_size == 0) || + (p->key_size > PIPELINE_CGNAPT_KEY_MAX_SIZE) || + (p->key_size % 8)) + return -1; + + continue; + } + + /* hash_offset */ + if (strcmp(arg_name, "hash_offset") == 0) { + if (hash_offset_present) + return -1; + hash_offset_present = 1; + + p->hash_offset = atoi(arg_value); + + continue; + } + + /* traffic_type */ + if (strcmp(arg_name, "pkt_type") == 0) { + if (strcmp(arg_value, "ipv4") == 0) { + p->traffic_type = TRAFFIC_TYPE_IPV4; + printf("Traffic is set to IPv4\n"); + } else if (strcmp(arg_value, "ipv6") == 0) { + p->traffic_type = TRAFFIC_TYPE_IPV6; + printf("Traffic is set to IPv6\n"); + } + continue; + } + + /* cgnapt_debug */ + if (strcmp(arg_name, "cgnapt_debug") == 0) { + CGNAPT_DEBUG = atoi(arg_value); + + continue; + } + + /* any other Unknown argument return -1 */ + } + + #ifdef NAT_ONLY_CONFIG_REQ + if (nat_only_config_flag) { + if (!public_ip_range_count) { + printf("No public_ip_range %d for NAT only config.\n", + public_ip_range_count); + printf("Running static NAT only configuration\n"); + p->is_static_cgnapt = 1; + } + } + #else + + if (!p->max_port_per_client) + p->is_static_cgnapt = 1; + #endif + + /* Check that mandatory arguments are present */ + if ((n_flows_present == 0) || + (cgnapt_meta_offset_present == 0)) + return -1; + + return 0; + +} + +/** + * Function to initialize the pipeline + * + * @param params + * A pointer to struct pipeline_params + * @param arg + * Void pointer - points to app params + * + * @return + * void pointer to the pipeline, NULL 0 if failure + */ +static void *pipeline_cgnapt_init(struct pipeline_params *params, void *arg) + /* (struct app_params *app) save it for use in port in handler */ +{ + struct pipeline *p; + struct pipeline_cgnapt *p_nat; + 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_cgnapt)); + p = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE); + p_nat = (struct pipeline_cgnapt *)p; + if (p == NULL) + return NULL; + + all_pipeline_cgnapt[n_cgnapt_pipeline++] = p_nat; + + strcpy(p->name, params->name); + p->log_level = params->log_level; + + PLOG(p, HIGH, "CG-NAPT"); + /* Initialize all counters and arrays */ + + p_nat->n_cgnapt_entry_deleted = 0; + p_nat->n_cgnapt_entry_added = 0; + p_nat->naptedPktCount = 0; + p_nat->naptDroppedPktCount = 0; + p_nat->inaptedPktCount = 0; + p_nat->enaptedPktCount = 0; + p_nat->receivedPktCount = 0; + p_nat->missedPktCount = 0; + p_nat->dynCgnaptCount = 0; + p_nat->arpicmpPktCount = 0; + + p_nat->app_params_addr = (uint64_t) arg; + for (i = 0; i < PIPELINE_MAX_PORT_IN; i++) { + p_nat->links_map[i] = 0xff; + p_nat->outport_id[i] = 0xff; + cgnapt_in_port_egress_prv[i] = 0; + cgnapt_prv_que_port_index[i] = 0; + } + p_nat->pipeline_num = 0xff; + p_nat->hw_checksum_reqd = 0; + p_nat->pub_ip_port_set = NULL; + p_nat->pub_ip_count = 0; + p_nat->traffic_type = TRAFFIC_TYPE_MIX; + p_nat->vnf_set = 0xff; + + /* For every init it should be reset */ + napt_port_alloc_elem_count = 0; + + #ifdef CGNAPT_TIMING_INST + p_nat->in_port_exit_timestamp = 0; + p_nat->external_time_sum = 0; + p_nat->internal_time_sum = 0; + p_nat->time_measurements = 0; + p_nat->max_time_mesurements = 10000; + p_nat->time_measurements_on = 0; + #endif + + #ifdef CGNAPT_DEBUGGING + + p_nat->naptDebugCount = 0; + + p_nat->naptDroppedPktCount1 = 0; + p_nat->naptDroppedPktCount2 = 0; + p_nat->naptDroppedPktCount3 = 0; + p_nat->naptDroppedPktCount4 = 0; + p_nat->naptDroppedPktCount5 = 0; + p_nat->naptDroppedPktCount6 = 0; + + p_nat->missedpktcount1 = 0; + p_nat->missedpktcount2 = 0; + p_nat->missedpktcount3 = 0; + p_nat->missedpktcount4 = 0; + p_nat->missedpktcount5 = 0; + p_nat->missedpktcount6 = 0; + p_nat->missedpktcount7 = 0; + p_nat->missedpktcount8 = 0; + p_nat->missedpktcount9 = 0; + p_nat->missedpktcount10 = 0; + p_nat->missedpktcount11 = 0; + p_nat->missedpktcount12 = 0; + + p_nat->max_port_dec_err1 = 0; + p_nat->max_port_dec_err2 = 0; + p_nat->max_port_dec_err3 = 0; + p_nat->max_port_dec_success = 0; + + p_nat->pfb_err = 0; + p_nat->pfb_ret = 0; + p_nat->pfb_get = 0; + p_nat->pfb_suc = 0; + p_nat->gfp_suc = 0; + p_nat->gfp_get = 0; + p_nat->gfp_ret = 0; + p_nat->gfp_err = 0; + + p_nat->kpc2 = 0; + p_nat->kpc1 = 0; + #endif + + #ifdef SIP_ALG + static int sip_enabled; + if (!sip_enabled) + lib_sip_alg_init(); + sip_enabled = 1; + #endif /* SIP_ALG */ + + /*struct rte_pipeline_table_entry *entries[RTE_HASH_LOOKUP_BULK_MAX];*/ + /* bitmap of valid packets */ + p_nat->valid_packets = 0; + /* bitmap of invalid packets to be dropped */ + p_nat->invalid_packets = 0; + + for (i = 0; i < RTE_HASH_LOOKUP_BULK_MAX; i++) + p_nat->key_ptrs[i] = &(p_nat->keys[i]); + + p_nat->port_alloc_ring = NULL; + + /* Parse arguments */ + if (pipeline_cgnapt_parse_args(p_nat, params)) + return NULL; + + p_nat->vnf_set = vnf_set_count; + + /* Pipeline */ + { + struct rte_pipeline_params pipeline_params = { + .name = params->name, + .socket_id = params->socket_id, + .offset_port_id = cgnapt_meta_offset, + }; + + p->p = rte_pipeline_create(&pipeline_params); + if (p->p == NULL) { + rte_free(p); + return NULL; + } + myP = p->p; + } + + #ifdef PIPELINE_CGNAPT_INSTRUMENTATION + + uint32_t instr_size = + RTE_CACHE_LINE_ROUNDUP((sizeof(uint64_t)) * + (INST_ARRAY_SIZE)); + inst_start_time = + (uint64_t *) rte_zmalloc(NULL, instr_size, + RTE_CACHE_LINE_SIZE); + inst_end_time = + (uint64_t *) rte_zmalloc(NULL, instr_size, + RTE_CACHE_LINE_SIZE); + inst_diff_time = + (uint32_t *) rte_zmalloc(NULL, instr_size / 2, + RTE_CACHE_LINE_SIZE); + if ((inst_start_time == NULL) || (inst_end_time == NULL) + || (inst_diff_time == NULL)) { + printf("Inst array alloc failed .... "); + return NULL; + } + #endif + + /* Memory allocation for in_port_h_arg */ + in_ports_arg_size = RTE_CACHE_LINE_ROUNDUP( + (sizeof(struct pipeline_cgnapt_in_port_h_arg)) * + (params->n_ports_in)); + struct pipeline_cgnapt_in_port_h_arg *ap = + (struct pipeline_cgnapt_in_port_h_arg *) + rte_zmalloc(NULL, + in_ports_arg_size, + RTE_CACHE_LINE_SIZE); + if (ap == NULL) + return NULL; + + myApp = (struct app_params *) arg; + + /* Input ports */ + p->n_ports_in = params->n_ports_in; + for (i = 0; i < p->n_ports_in; i++) { + /* passing our cgnapt pipeline in call back arg */ + (ap[i]).p = p_nat; + (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 = cgnapt_in_port_ah_mix, + .arg_ah = &(ap[i]), + .burst_size = params->port_in[i].burst_size, + }; + + #ifdef PIPELINE_CGNAPT_INSTRUMENTATION + if (i == 0) + instrumentation_port_in_arg = &(ap[i]); + #endif + + if (p_nat->traffic_type == TRAFFIC_TYPE_IPV4) { + /* Private in-port handler */ + /* Multiport changes */ + if (cgnapt_in_port_egress_prv[i]) { + port_params.f_action = + cgnapt_in_port_ah_ipv4_prv; + printf("CGNAPT port %d is IPv4 Prv\n", i); + } else{ + port_params.f_action = + cgnapt_in_port_ah_ipv4_pub; + printf("CGNAPT port %d is IPv4 Pub\n", i); + } + } + + if (p_nat->traffic_type == TRAFFIC_TYPE_IPV6) { + if (cgnapt_in_port_egress_prv[i]) { + port_params.f_action = + cgnapt_in_port_ah_ipv6_prv; + printf("CGNAPT port %d is IPv6 Prv\n", i); + } else{ + port_params.f_action = + cgnapt_in_port_ah_ipv6_pub; + printf("CGNAPT port %d is IPv6 Pub\n", i); + } + } + + 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 */ + 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( + ¶ms->port_out[i]), + .arg_create = pipeline_port_out_params_convert( + ¶ms->port_out[i]), + #ifdef PIPELINE_CGNAPT_INSTRUMENTATION + .f_action = port_out_ah_cgnapt, + #else + .f_action = NULL, + #endif + .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 ignore; + ignore = sscanf(params->name, "PIPELINE%d", &pipeline_num); + if (ignore != 1) { + printf("Not able to read pipeline number\n"); + return NULL; + } + p_nat->pipeline_num = (uint8_t) pipeline_num; + register_pipeline_Qs(p_nat->pipeline_num, p); + set_link_map(p_nat->pipeline_num, p, p_nat->links_map); + set_outport_id(p_nat->pipeline_num, p, p_nat->outport_id); + + /* Tables */ + p->n_tables = 1; + { + + if (napt_common_table == NULL) { + if (create_napt_common_table(p_nat->n_flows)) { + PLOG(p, HIGH, + "CG-NAPT create_napt_common_table failed."); + return NULL; + } + } + + 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; + } + struct rte_pipeline_table_entry default_entry = { + .action = RTE_PIPELINE_ACTION_PORT_META + }; + struct rte_pipeline_table_entry *default_entry_ptr; + 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; + } + } + + /* 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)); + memcpy(p_nat->custom_handlers, + custom_handlers, sizeof(p_nat->custom_handlers)); + + if (!p_nat->is_static_cgnapt) { + printf("Initializing dyn napt components ... %d\n", + p_nat->pipeline_num); + if (napt_port_alloc_init(p_nat) == -1) { + printf("Error - napt_port_alloc_init failed - %d\n", + p_nat->pipeline_num); + return NULL; + } + int rc = 0; + + if (max_port_per_client_hash == NULL) { + rc = init_max_port_per_client(p_nat); + if (rc < 0) { + printf("CGNAPT Error - " + "init_max_port_per_client failed %d", rc); + return NULL; + } + } + + } + + if (!icmp_pool_init) { + icmp_pool_init = 1; + /* create the arp_icmp mbuf rx pool */ + cgnapt_icmp_pktmbuf_tx_pool = + rte_pktmbuf_pool_create("icmp_mbuf_tx_pool", 63, 32, 0, + RTE_MBUF_DEFAULT_BUF_SIZE, + rte_socket_id()); + if (cgnapt_icmp_pktmbuf_tx_pool == NULL) { + PLOG(p, HIGH, "ICMP mbuf pool create failed."); + return NULL; + } + + cgnapt_icmp_pkt = + rte_pktmbuf_alloc(cgnapt_icmp_pktmbuf_tx_pool); + + if (cgnapt_icmp_pkt == NULL) { + printf("Failed to allocate cgnapt_icmp_pkt\n"); + return NULL; + } + } + + #ifdef CT_CGNAT + + cgnat_cnxn_tracker = rte_zmalloc(NULL, rte_ct_get_cnxn_tracker_size(), + RTE_CACHE_LINE_SIZE); + + if (cgnat_cnxn_tracker == NULL) { + printf("CGNAPT CT memory not allocated\n"); + return NULL; + } + rte_ct_initialize_default_timeouts(cgnat_cnxn_tracker); + + printf("CGNAPT CT Flows %d\n", p_nat->n_flows); + int ret; + ret = rte_ct_initialize_cnxn_tracker(cgnat_cnxn_tracker, + p_nat->n_flows, + "CGNAT_CT_COMMON_TABLE"); + if (ret == -1) + return NULL; + #endif + + #ifdef FTP_ALG + lib_ftp_alg_init(); + #endif + + #ifdef PCP_ENABLE + if (pcp_init() == PCP_INIT_SUCCESS) + printf("PCP contents are initialized successfully\n"); + else + printf("Error in initializing PCP contents\n"); + #endif + + return p; +} + +/** + * Function for pipeline cleanup + * + * @param pipeline + * A void pointer to pipeline + * + * @return + * 0 + */ +static int pipeline_cgnapt_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_cgnapt_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; +} + +/** + * Function for pipeline timers + * + * @param pipeline + * A void pointer to pipeline + * + * @return + * 0 + */ +static int pipeline_cgnapt_timer(void *pipeline) +{ + struct pipeline_cgnapt *p_nat = (struct pipeline_cgnapt *)pipeline; + + pipeline_msg_req_handle(&p_nat->p); + + rte_pipeline_flush(((struct pipeline *)p_nat)->p); + + return 0; +} + +/** + * 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_cgnapt_msg_req_custom_handler(struct pipeline *p, void *msg) +{ + struct pipeline_cgnapt *p_nat = (struct pipeline_cgnapt *)p; + struct pipeline_custom_msg_req *req = msg; + pipeline_msg_req_handler f_handle; + + f_handle = (req->subtype < PIPELINE_CGNAPT_MSG_REQS) ? + p_nat->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); +} + +/** + * Function for adding NSP data + * + * @param pipeline + * A void pointer to pipeline + * @param msg + * void pointer for incoming data + * + * @return + * void pointer of response + */ +void *pipeline_cgnapt_msg_req_nsp_add_handler( + __rte_unused struct pipeline *p, + void *msg) +{ + struct pipeline_cgnapt_nsp_add_msg_req *req = msg; + struct pipeline_cgnapt_nsp_add_msg_rsp *rsp = msg; + int size = 0; + struct cgnapt_nsp_node *node = NULL, *ll = nsp_ll; + + if (! + (req->nsp.depth == 32 || req->nsp.depth == 40 + || req->nsp.depth == 48 || req->nsp.depth == 56 + || req->nsp.depth == 64 || req->nsp.depth == 96)) { + rsp->status = 0xE; + rsp->key_found = 0; + return rsp; + } + + printf("be initial cond\n"); + if (nsp_ll == NULL) { + size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct cgnapt_nsp_node)); + node = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE); + if (node == NULL) { + printf("be 1st cond\n"); + rsp->status = 0xE; + rsp->key_found = 0; + return rsp; + } + + memcpy(&node->nsp, &req->nsp, + sizeof(struct pipeline_cgnapt_nsp_t)); + node->next = NULL; + nsp_ll = node; + } else { + while (ll != NULL) { + if (!memcmp(ll->nsp.prefix, req->nsp.prefix, 16) + && ll->nsp.depth == req->nsp.depth) { + printf("be 2st cond\n"); + rsp->status = 0xE; + rsp->key_found = 1; + return rsp; + } + ll = ll->next; + } + + size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct cgnapt_nsp_node)); + node = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE); + if (node == NULL) { + printf("be 3st cond\n"); + rsp->status = 0xE; + rsp->key_found = 0; + return rsp; + } + + memcpy(&node->nsp, &req->nsp, + sizeof(struct pipeline_cgnapt_nsp_t)); + node->next = nsp_ll; + nsp_ll = node; + } + + rsp->status = 0; + rsp->key_found = 0; + + printf("be 4st cond\n"); + return rsp; +} + +/** + * Function for deleting NSP data + * + * @param pipeline + * A void pointer to pipeline + * @param msg + * void pointer for incoming data + * + * @return + * void pointer of response + */ +void *pipeline_cgnapt_msg_req_nsp_del_handler( + __rte_unused struct pipeline *p, + void *msg) +{ + struct pipeline_cgnapt_nsp_del_msg_req *req = msg; + struct pipeline_cgnapt_nsp_del_msg_rsp *rsp = msg; + struct cgnapt_nsp_node *prev = NULL, *ll = nsp_ll; + + while (ll != NULL) { + if (!memcmp(ll->nsp.prefix, req->nsp.prefix, 16) + && ll->nsp.depth == req->nsp.depth) { + if (prev != NULL) + prev->next = ll->next; + else + nsp_ll = NULL; + + rte_free(ll); + + rsp->status = 0; + rsp->key_found = 1; + + return rsp; + } + + prev = ll; + ll = ll->next; + } + + rsp->status = 0xE; + rsp->key_found = 0; + + return rsp; +} + +/** + * Function for adding NAPT entry + * + * @param pipeline + * A void pointer to pipeline + * @param msg + * void pointer for incoming data + * + * @return + * void pointer of response + */ +void *pipeline_cgnapt_msg_req_entry_add_handler(struct pipeline *p, void *msg) +{ + struct pipeline_cgnapt_entry_add_msg_req *req = msg; + struct pipeline_cgnapt *p_nat = (struct pipeline_cgnapt *)p; + uint8_t type = req->data.type; + uint32_t src_ip = (type == CGNAPT_ENTRY_IPV4) ? + req->data.u.prv_ip : + rte_bswap32(req->data.u.u32_prv_ipv6[3]); + + uint8_t src_ipv6[16]; + + uint32_t dest_ip = req->data.pub_ip; + uint16_t src_port = req->data.prv_port; + uint16_t dest_port = req->data.pub_port; + uint16_t rx_port = req->data.prv_phy_port; + uint32_t ttl = req->data.ttl; + + if (type == CGNAPT_ENTRY_IPV6) + memcpy(src_ipv6, req->data.u.prv_ipv6, 16); + + printf("CG-NAPT addm - PrvIP %x, PrvPort %d,", src_ip, src_port); + printf("PubIP %x, PubPort %d,", dest_ip, dest_port); + + printf("PhyPort %d, ttl %u,", rx_port, ttl); + printf("entry_type %d\n", type); + + #ifdef NAT_ONLY_CONFIG_REQ + if (nat_only_config_flag) { + if (!p_nat->is_static_cgnapt) { + int i; + + for (i = 0; i < p_nat->pub_ip_range_count; i++) { + if (((dest_ip >= p_nat->pub_ip_range[i].start_ip) + && (dest_ip <= p_nat->pub_ip_range[i].end_ip))) { + printf("Error - static port cannot be in Dynamic " + "port range"); + printf("%x-%x\n", p_nat->pub_ip_range[i].start_ip, + p_nat->pub_ip_range[i].end_ip); + return msg; + } + } + } + + if (pipeline_cgnapt_msg_req_entry_addm_pair(p, msg, + src_ip, src_port, + dest_ip, dest_port, + rx_port, ttl, + type, src_ipv6)) { + printf("Error - "); + printf("pipeline_cgnapt_msg_req_entry_addm_handler\n"); + return msg; + } + + printf("Success - pipeline_cgnapt_msg_req_entry_addm_handler"); + printf("added %d rule pairs.\n", count); + + return msg; + } + #endif + + if (!p_nat->is_static_cgnapt) { + int i; + + for (i = 0; i < p_nat->pub_ip_count; i++) { + /* Check port range if same Public-IP */ + if (dest_ip != p_nat->pub_ip_port_set[i].ip) + continue; + if (((dest_port >= p_nat->pub_ip_port_set[i].start_port) && + (dest_port <= p_nat->pub_ip_port_set[i].end_port))) { + printf("Error - port cannot be in Dynamic " + "port range %d-%d\n", + p_nat->pub_ip_port_set[i].start_port, + p_nat->pub_ip_port_set[i].end_port); + return msg; + } + } + } + + if (pipeline_cgnapt_msg_req_entry_addm_pair + (p, msg, src_ip, src_port, dest_ip, dest_port, rx_port, + ttl, type, src_ipv6)) { + printf("Error - pipeline_cgnapt_msg_req_entry_add_handler\n"); + return msg; + } + + + printf("\nSuccess - pipeline_cgnapt_msg_req_entry_add_handler " + "added\n"); + + return msg; +} + +/** + * Function for adding a NAPT entry pair + * + * @param pipeline + * A void pointer to pipeline + * @param msg + * void pointer for incoming data + * @param src_ip + * source ip address + * @param src_port + * source port + * @param dest_ip + * destination ip address + * @param dest_port + * destination port + * @param rx_port + * Physical receive port + * @param ttl + * time to live value + * @param type + * type of entry IPv4 vs IPv6 + * @param src_ipv6[] + * uint8_t array of IPv6 address + * + * @return + * 0 if success, negative if fails + */ +int +pipeline_cgnapt_msg_req_entry_addm_pair( + struct pipeline *p, __rte_unused void *msg, + uint32_t src_ip, uint16_t src_port, + uint32_t dest_ip, uint16_t dest_port, + uint16_t rx_port, uint32_t ttl, + uint8_t type, uint8_t src_ipv6[16]) +{ + + struct pipeline_cgnapt_entry_key key; + struct pipeline_cgnapt *p_nat = (struct pipeline_cgnapt *)p; + + key.ip = src_ip; + key.port = src_port; + key.pid = rx_port; + + struct cgnapt_table_entry entry = { + .head = { + .action = RTE_PIPELINE_ACTION_PORT, + .port_id = CGNAPT_PUB_PORT_ID, + }, + + .data = { + /*.prv_ip = src_ip, */ + .prv_port = src_port, + .pub_ip = dest_ip, + .pub_port = dest_port, + .prv_phy_port = rx_port, + .pub_phy_port = get_prv_to_pub_port(&dest_ip, + IP_VERSION_4), + .ttl = ttl, + .timeout = STATIC_CGNAPT_TIMEOUT, + #ifdef PCP_ENABLE + .timer = NULL, + #endif + } + }; + + if (type == CGNAPT_ENTRY_IPV4) { + entry.data.type = CGNAPT_ENTRY_IPV4; + entry.data.u.prv_ip = src_ip; + } else { + entry.data.type = CGNAPT_ENTRY_IPV6; + memcpy(entry.data.u.prv_ipv6, src_ipv6, 16); + } + + /* Also need to add a paired entry on our own */ + /* + * Need to change key + * Need to change entry header + * Will keep the same entry and take care + * of translation in table hit handler + */ + struct pipeline_cgnapt_entry_key second_key; + + /* Need to add a second ingress entry */ + second_key.ip = dest_ip; + second_key.port = dest_port; + second_key.pid = 0xffff; + + #ifdef NAT_ONLY_CONFIG_REQ + if (nat_only_config_flag) { + key.port = 0xffff; + entry.data.pub_port = 0xffff; + second_key.port = 0xffff; + } + #endif + + if (CGNAPT_DEBUG > 2) + printf("key.ip %x, key.port %d", key.ip, key.port); + printf("key.pid %d, in_type %d,", key.pid, type); + printf("entry_type %d\n", entry.data.type); + + int32_t position = rte_hash_add_key(napt_common_table, &key); + + if (position < 0) { + printf("CG-NAPT entry bulk add failed"); + printf(" ... returning without adding ...\n"); + return -1; + } + + memcpy(&napt_hash_tbl_entries[position], &entry, + sizeof(struct cgnapt_table_entry)); + + #ifdef CGNAPT_DEBUGGING + if (p_nat->kpc1++ < 5) + print_key(&key); + #endif + + p_nat->n_cgnapt_entry_added++; + + /* Now modify the forward port for reverse entry */ + entry.head.port_id = CGNAPT_PRV_PORT_ID; + + position = rte_hash_add_key(napt_common_table, &second_key); + + if (position < 0) { + printf("CG-NAPT entry reverse bulk add failed"); + printf(" ... returning with fwd add ...%d\n", position); + return 2; + } + + memcpy(&napt_hash_tbl_entries[position], &entry, + sizeof(struct cgnapt_table_entry)); + + #ifdef CGNAPT_DEBUGGING + if (p_nat->kpc1 < 5) + print_key(&second_key); + #endif + + p_nat->n_cgnapt_entry_added++; + return 0; +} + +/** + * Function for adding multiple NAPT entries + * + * @param pipeline + * A void pointer to pipeline + * @param msg + * void pointer for incoming data + * + * @return + * void pointer of response + */ +void *pipeline_cgnapt_msg_req_entry_addm_handler(struct pipeline *p, void *msg) +{ + struct pipeline_cgnapt_entry_addm_msg_req *req = msg; + struct pipeline_cgnapt *p_nat = (struct pipeline_cgnapt *)p; + uint32_t uenum = 0; + uint32_t max_ue = req->data.num_ue; + uint8_t type = req->data.type; + uint32_t src_ip = (type == CGNAPT_ENTRY_IPV4) ? + req->data.u.prv_ip : + rte_bswap32(req->data.u.u32_prv_ipv6[3]); + + uint8_t src_ipv6[16]; + + uint32_t dest_ip = req->data.pub_ip; + uint16_t src_port = req->data.prv_port; + uint16_t dest_port = req->data.pub_port; + uint16_t rx_port = req->data.prv_phy_port; + uint32_t ttl = req->data.ttl; + uint16_t max_src_port = req->data.prv_port_max; + uint16_t max_dest_port = req->data.pub_port_max; + uint32_t count = 0; + uint16_t src_port_start = src_port; + uint16_t dest_port_start = dest_port; + uint32_t src_ip_temp; + + if (type == CGNAPT_ENTRY_IPV6) + memcpy(src_ipv6, req->data.u.prv_ipv6, 16); + + printf("CG-NAPT addm - PrvIP %x, PrvPort %d,", src_ip, src_port); + printf("PubIP %x, PubPort %d,", dest_ip, dest_port); + printf("PhyPort %d, ttl %u, NumUe %d,", rx_port, ttl, max_ue); + printf("mPrvPort %d, mPubPort %d,", max_src_port, max_dest_port); + printf("entry_type %d\n", type); + + #ifdef NAT_ONLY_CONFIG_REQ + if (nat_only_config_flag) { + if (!p_nat->is_static_cgnapt) { + int i; + + for (i = 0; i < p_nat->pub_ip_range_count; i++) { + if (((dest_ip >= p_nat->pub_ip_range[i].start_ip) + && (dest_ip <= p_nat->pub_ip_range[i].end_ip)) || + (((dest_ip + max_ue) >= + p_nat->pub_ip_range[i].start_ip) && + ((dest_ip + max_ue) <= + p_nat->pub_ip_range[i].end_ip))) { + printf("Error - static port cannot be in Dynamic " + "port range"); + printf("%x-%x\n", p_nat->pub_ip_range[i].start_ip, + p_nat->pub_ip_range[i].end_ip); + + return msg; + } + } + } + + for (uenum = 0; uenum < max_ue; uenum++) { + + if (pipeline_cgnapt_msg_req_entry_addm_pair(p, msg, + src_ip, src_port, + dest_ip, dest_port, + rx_port, ttl, + type, src_ipv6)) { + printf("Error - "); + printf("pipeline_cgnapt_msg_req_entry_addm_handler\n"); + return msg; + } + + count++; + + src_ip++; + dest_ip++; + } + + printf("Success - pipeline_cgnapt_msg_req_entry_addm_handler"); + printf("added %d rule pairs.\n", count); + + return msg; + } + #endif + + if (!p_nat->is_static_cgnapt) { + int i; + + for (i = 0; i < p_nat->pub_ip_count; i++) { + /* Check port range if same Public-IP */ + if (dest_ip != p_nat->pub_ip_port_set[i].ip) + continue; + if (((dest_port >= p_nat->pub_ip_port_set[i].start_port) && + (dest_port <= p_nat->pub_ip_port_set[i].end_port)) || + ((max_dest_port >= p_nat->pub_ip_port_set[i].start_port) + && max_dest_port <= p_nat->pub_ip_port_set[i].end_port)) { + printf("Error - port cannot be in Dynamic port range %d-%d\n", + p_nat->pub_ip_port_set[i].start_port, + p_nat->pub_ip_port_set[i].end_port); + return msg; + } + } + } + + for (uenum = 0; uenum < max_ue; uenum++) { + if (pipeline_cgnapt_msg_req_entry_addm_pair + (p, msg, src_ip, src_port, dest_ip, dest_port, rx_port, + ttl, type, src_ipv6)) { + printf("Error - pipeline_cgnapt_msg_req_entry_addm_handler\n"); + return msg; + } + + count++; + + src_port++; + if (src_port > max_src_port) { + src_port = src_port_start; + src_ip++; + if (req->data.type == CGNAPT_ENTRY_IPV6) { + src_ip_temp = rte_bswap32(src_ip); + memcpy(&src_ipv6[12], &src_ip_temp, 4); + } + } + dest_port++; + if (dest_port > max_dest_port) { + dest_port = dest_port_start; + dest_ip++; + } + } + + printf("\nSuccess - pipeline_cgnapt_msg_req_entry_addm_handler added"); + printf("%d rule pairs.\n", count); + + return msg; +} + +/** + * Function for deleting NAPT entry + * + * @param pipeline + * A void pointer to pipeline + * @param msg + * void pointer for incoming data + * + * @return + * void pointer of response + */ +void *pipeline_cgnapt_msg_req_entry_del_handler(struct pipeline *p, void *msg) +{ + struct pipeline_cgnapt_entry_delete_msg_req *req = msg; + struct pipeline_cgnapt_entry_delete_msg_rsp *rsp = msg; + struct pipeline_cgnapt *p_nat = (struct pipeline_cgnapt *)p; + + if (CGNAPT_DEBUG) { + uint8_t *KeyP = (void *)(&req->key); + int i = 0; + + printf("pipeline_cgnapt_msg_req_entry_del_handler - Key: "); + for (i = 0; i < (int)sizeof(struct pipeline_cgnapt_entry_key); + i++) + printf(" %02x", KeyP[i]); + printf(" ,KeySize %u\n", + (int)sizeof(struct pipeline_cgnapt_entry_key)); + } + + struct cgnapt_table_entry entry; + + /* If ingress key */ + if (!is_phy_port_privte(req->key.pid)) + req->key.pid = 0xffff; + + #ifdef NAT_ONLY_CONFIG_REQ + if (nat_only_config_flag) + req->key.port = 0xffff; + #endif + + int32_t position; + position = rte_hash_lookup(napt_common_table, &req->key); + if (position == -ENOENT) { + printf("Entry not found\n"); + return NULL; + } + memcpy(&entry, &napt_hash_tbl_entries[position], + sizeof(struct cgnapt_table_entry)); + position = rte_hash_del_key(napt_common_table, &req->key); + p_nat->n_cgnapt_entry_deleted++; + + struct pipeline_cgnapt_entry_key second_key; + + if (is_phy_port_privte(req->key.pid)) { + /* key is for egress - make second key for ingress */ + second_key.ip = entry.data.pub_ip; + second_key.port = entry.data.pub_port; + second_key.pid = 0xffff; + + } else { + /* key is for ingress - make second key for egress */ + second_key.ip = entry.data.u.prv_ip; + second_key.port = entry.data.prv_port; + second_key.pid = entry.data.prv_phy_port; + } + + #ifdef NAT_ONLY_CONFIG_REQ + if (nat_only_config_flag) + second_key.port = 0xffff; + #endif + + position = rte_hash_del_key(napt_common_table, &second_key); + p_nat->n_cgnapt_entry_deleted++; + + return rsp; +} + +void *pipeline_cgnapt_msg_req_entry_sync_handler(struct pipeline *p, void *msg) +{ + struct pipeline_cgnapt_entry_delete_msg_req *req = msg; + struct pipeline_cgnapt_entry_delete_msg_rsp *rsp = msg; + + rsp->status = rte_pipeline_table_entry_delete( + p->p, + p->table_id[0], + &req->key, + &rsp->key_found, NULL); + + return rsp; +} + +/** + * Function to print the NAPT key + * + * @param key + * A pointer to struct pipeline_cgnapt_entry_key + */ +void print_key(struct pipeline_cgnapt_entry_key *key) +{ + uint8_t *KeyP = (void *)(key); + int i = 0; + + printf("\nKey: "); + for (i = 0; i < (int)sizeof(struct pipeline_cgnapt_entry_key); i++) + printf(" %02x", KeyP[i]); +} + +/** + * Function to print the table entry + * + * @param entry + * A pointer to struct rte_pipeline_table_entry + */ +void print_entry1(struct rte_pipeline_table_entry *entry) +{ + uint8_t *entryP = (void *)(entry); + int i = 0; + + printf("Entry: "); + for (i = 0; i < (int)sizeof(struct rte_pipeline_table_entry); i++) + printf(" %02x", entryP[i]); +} + +/** + * Function to print the NAPT table entry + * + * @param entry + * A pointer to struct cgnapt_table_entry + */ +void print_cgnapt_entry(struct cgnapt_table_entry *entry) +{ + uint8_t *entryP = (void *)(entry); + int i = 0; + + printf("CGNAPT Entry: "); + for (i = 0; i < (int)sizeof(struct cgnapt_table_entry); i++) + printf(" %02x", entryP[i]); + printf(" size:%d\n", (int)sizeof(struct cgnapt_table_entry)); +} + +/** + * Function to get a free port + * + * @param p_nat + * A pointer to struct pipeline_cgnapt + * @param public_ip + * A uint32_t pointer to return corresponding ip address + * + * @return + * free port number, 0 if error + */ +int get_free_iport(struct pipeline_cgnapt *p_nat, uint32_t *public_ip) +{ + int port = -1; + /* If we don't have a valid napt_port_alloc_elem get one from + * port_alloc_ring + */ + if (p_nat->allocated_ports == NULL) { + void *ports; + int ret; + + ret = rte_ring_dequeue(p_nat->port_alloc_ring, &ports); + if (ret == 0) { + p_nat->allocated_ports = + (struct napt_port_alloc_elem *)ports; + + #ifdef CGNAPT_DEBUGGING + p_nat->gfp_get++; + #endif + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 3) + printf("p_nat->allocated_ports %p\n", + p_nat->allocated_ports); + #endif + } else { + printf("CGNAPT Err - get_free_iport rte_ring_dequeue " + "failed"); + printf("%d, %d, %d\n", rte_ring_count( + p_nat->port_alloc_ring), rte_ring_free_count( + p_nat->port_alloc_ring), ret); + + #ifdef CGNAPT_DEBUGGING + #ifdef CGNAPT_DBG_PRNT + printf("Th%d GFP:: %" PRIu64 ", %" PRIu64 ", " + "%" PRIu64", %" PRIu64 ",\n", p_nat->pipeline_num, + p_nat->gfp_get, p_nat->gfp_ret, p_nat->gfp_suc, + p_nat->gfp_err); + + p_nat->gfp_err++; + #endif + #endif + return port; + } + } + + /* get the port from index count-1 and decrease count */ + port = p_nat->allocated_ports->ports + [p_nat->allocated_ports->count - 1]; + *public_ip = p_nat->allocated_ports->ip_addr + [p_nat->allocated_ports->count - 1]; + + p_nat->allocated_ports->count -= 1; + + /* if count is zero, return buffer to mem pool */ + if (p_nat->allocated_ports->count == 0) { + rte_mempool_put(napt_port_pool, p_nat->allocated_ports); + + #ifdef CGNAPT_DEBUGGING + p_nat->gfp_ret++; + #ifdef CGNAPT_DBG_PRNT + printf("Th%d Returned to pool p_nat->allocated_ports %p,", + p_nat->pipeline_num, p_nat->allocated_ports); + printf("%" PRIu64 ", %" PRIu64 ",", + p_nat->gfp_get, p_nat->gfp_ret); + printf("%" PRIu64 ", %" PRIu64 ",\n", + p_nat->gfp_suc, p_nat->gfp_err); + #endif + #endif + + p_nat->allocated_ports = NULL; + } + + #ifdef CGNAPT_DEBUGGING + p_nat->gfp_suc++; + #endif + + return port; +} + +/** + * Function to free a port + * + * @param port_num + * Port number to free + * @param public_ip + * Corresponding ip address + * @param p_nat + * A pointer to struct pipeline_cgnapt + * + */ +void release_iport(uint16_t port_num, uint32_t public_ip, + struct pipeline_cgnapt *p_nat) +{ + /* If we don't have a valid napt_port_alloc_elem get one + * from mem pool + */ + if (p_nat->free_ports == NULL) { + void *ports; + + #ifdef CGNAPT_DEBUGGING + p_nat->pfb_get++; + #endif + + if (rte_mempool_get(napt_port_pool, &ports) < 0) { + #ifdef CGNAPT_DEBUGGING + p_nat->pfb_err++; + #endif + printf("CGNAPT release_iport error in getting " + "port alloc buffer\n"); + return; + } + + p_nat->free_ports = (struct napt_port_alloc_elem *)ports; + p_nat->free_ports->count = 0; + } + + /* put the port at index count and increase count */ + p_nat->free_ports->ip_addr[p_nat->free_ports->count] = public_ip; + p_nat->free_ports->ports[p_nat->free_ports->count] = port_num; + p_nat->free_ports->count += 1; + + /* if napt_port_alloc_elem is full add it to ring */ + { + + #ifdef CGNAPT_DEBUGGING + p_nat->pfb_ret++; + #endif + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG >= 2) { + printf("CGNAPT port_alloc_ring before EnQ Cnt %d, Free %d\n", + rte_ring_count(p_nat->port_alloc_ring), + rte_ring_free_count(p_nat->port_alloc_ring)); + } + #endif + + if (rte_ring_enqueue(p_nat->port_alloc_ring, + (void *)p_nat->free_ports) != 0) { + printf("CGNAPT release_iport Enqueue error %p\n", + p_nat->free_ports); + + #ifdef CGNAPT_DEBUGGING + p_nat->pfb_err++; + #endif + } + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG >= 2) { + printf("CGNAPT port_alloc_ring after EnQ Cnt %d", + rte_ring_count(p_nat->port_alloc_ring)); + printf("Free %d\n", + rte_ring_free_count(p_nat->port_alloc_ring)); + } + #endif + + p_nat->free_ports = NULL; + } + + #ifdef CGNAPT_DEBUGGING + p_nat->pfb_suc++; + #endif +} + +/** + * Function to initialize max ports per client data structures + * Called during dynamic NAPT initialization. + * + * @param p_nat + * A pointer to struct pipeline_cgnapt + * + * @return + * 0 if success, negative if error + */ +int init_max_port_per_client( + __rte_unused struct pipeline_cgnapt *p_nat) +{ + if (max_port_per_client_hash) + return -1; + + /*MPPC_ALREADY_EXISTS */ + + int i = 0; + + max_port_per_client_hash = + rte_hash_create(&max_port_per_client_hash_params); + if (!max_port_per_client_hash) + return -2; + + /*MPPC_HASH_CREATE_ERROR */ + + max_port_per_client_array = + rte_zmalloc(NULL, + sizeof(struct max_port_per_client) * MAX_DYN_ENTRY, + RTE_CACHE_LINE_SIZE); + if (!max_port_per_client_array) + return -3; + + /*MPPC_ARRAY_CREATE_ERROR */ + + for (i = 0; i < MAX_DYN_ENTRY; i++) { + max_port_per_client_array[i].prv_ip = 0; + max_port_per_client_array[i].prv_phy_port = 0; + max_port_per_client_array[i].max_port_cnt = 0; + } + + return 0; + /*MPPC_SUCCESS */ +} + +/** + * Function to check if max ports for a client is reached + * + * @param prv_ip_param + * A uint32_t ip address of client + * @param prv_phy_port_param + * A uint32_t physical port id of the client + * @param p_nat + * A pointer to struct pipeline_cgnapt + * + * @return + * 0 if max port not reached, 1 if reached, -1 if error + */ +int is_max_port_per_client_reached(uint32_t prv_ip_param, + uint32_t prv_phy_port_param, + struct pipeline_cgnapt *p_nat) +{ + int index = MAX_PORT_INVALID_KEY; + + struct max_port_per_client_key key = { + .prv_ip = prv_ip_param, + .prv_phy_port = prv_phy_port_param, + }; + + index = rte_hash_lookup(max_port_per_client_hash, (const void *)&key); + + if (index < 0) + return MAX_PORT_INVALID_KEY; + + if (max_port_per_client_array[index].max_port_cnt >= + p_nat->max_port_per_client) + return MAX_PORT_REACHED; + + return MAX_PORT_NOT_REACHED; +} + +/** + * Function to increase max ports for a client + * + * @param prv_ip_param + * A uint32_t ip address of client + * @param prv_phy_port_param + * A uint32_t physical port id of the client + * @param p_nat + * A pointer to struct pipeline_cgnapt + * + * @return + * 0 if max port reached, 1 if success, 2 if new entry, -1 if error + */ +int increment_max_port_counter(uint32_t prv_ip_param, + uint32_t prv_phy_port_param, + struct pipeline_cgnapt *p_nat) +{ + int index = MAX_PORT_INC_ERROR; + + struct max_port_per_client_key key = { + .prv_ip = prv_ip_param, + .prv_phy_port = prv_phy_port_param, + }; + + index = rte_hash_lookup(max_port_per_client_hash, (const void *)&key); + + if (index == -EINVAL) + return MAX_PORT_INC_ERROR; + + if (index == -ENOENT) { + if (max_port_per_client_add_entry(prv_ip_param, + prv_phy_port_param, + p_nat) <= 0) + return MAX_PORT_INC_ERROR; + + return 2; /*return MAX_PORT_NEW_ENTRY; */ + } + + if (CGNAPT_DEBUG > 2) + printf("%s: max_port_cnt(%d), p_nat_max(%d)\n", __func__, + max_port_per_client_array[index].max_port_cnt, + p_nat->max_port_per_client); + + if (max_port_per_client_array[index].max_port_cnt < + p_nat->max_port_per_client) { + max_port_per_client_array[index].max_port_cnt++; + return MAX_PORT_INC_SUCCESS; + } + + return MAX_PORT_INC_REACHED; +} + +/** + * Function to decrease max ports for a client + * + * @param prv_ip_param + * A uint32_t ip address of client + * @param prv_phy_port_param + * A uint32_t physical port id of the client + * @param p_nat + * A pointer to struct pipeline_cgnapt + * + * @return + * 0 if count already 0, 1 if success, -1 if error + */ +int decrement_max_port_counter(uint32_t prv_ip_param, + uint32_t prv_phy_port_param, + struct pipeline_cgnapt *p_nat) +{ + int index = MAX_PORT_DEC_ERROR; + + struct max_port_per_client_key key = { + .prv_ip = prv_ip_param, + .prv_phy_port = prv_phy_port_param, + }; + + index = rte_hash_lookup(max_port_per_client_hash, (const void *)&key); + if (index < 0) { + + #ifdef CGNAPT_DEBUGGING + p_nat->max_port_dec_err1++; + #endif + return MAX_PORT_DEC_ERROR; + + } + + if (max_port_per_client_array[index].max_port_cnt > 0) { + /* If it is the last port,ret this info which is used for + * max_cli_per_pub_ip + */ + + max_port_per_client_array[index].max_port_cnt--; + /* Count should be atomic but we are good as we have only + * one task handling this counter at a time (core affinity) + */ + } + + if (max_port_per_client_array[index].max_port_cnt <= 0) { + if (max_port_per_client_del_entry + (prv_ip_param, prv_phy_port_param, p_nat) <= 0) { + + #ifdef CGNAPT_DEBUGGING + p_nat->max_port_dec_err2++; + #endif + return MAX_PORT_DEC_ERROR; + } + + #ifdef CGNAPT_DEBUGGING + p_nat->max_port_dec_err3++; + #endif + + return MAX_PORT_DEC_REACHED; + } + + #ifdef CGNAPT_DEBUGGING + p_nat->max_port_dec_success++; + #endif + + return MAX_PORT_DEC_SUCCESS; +} + +/** + * Function to add a max ports per client entry + * + * @param prv_ip_param + * A uint32_t ip address of client + * @param prv_phy_port_param + * A uint32_t physical port id of the client + * @param p_nat + * A pointer to struct pipeline_cgnapt + * + * @return + * 0 no success, 1 if success, -1 if error + */ +int max_port_per_client_add_entry( + uint32_t prv_ip_param, + uint32_t prv_phy_port_param, + __rte_unused struct pipeline_cgnapt *p_nat) +{ + int index = MAX_PORT_ADD_ERROR; + + struct max_port_per_client_key key = { + .prv_ip = prv_ip_param, + .prv_phy_port = prv_phy_port_param, + }; + + index = rte_hash_lookup(max_port_per_client_hash, (const void *)&key); + if (index == -EINVAL) + return MAX_PORT_ADD_ERROR; + + if (index >= 0) + return MAX_PORT_ADD_UNSUCCESS; + + if (index == -ENOENT) { + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 2) + printf("max_port_per_client_add_entry fn: " + "Entry does not exist\n"); + #endif + + index = + rte_hash_add_key(max_port_per_client_hash, + (const void *)&key); + if (index == -ENOSPC) + return MAX_PORT_ADD_UNSUCCESS; + + #ifdef CGNAPT_DBG_PRNT + if (CGNAPT_DEBUG > 2) + printf("max_port_per_client_add_entry fn:" + "Add entry index(%d)\n", index); + #endif + + max_port_per_client_array[index].prv_ip = prv_ip_param; + max_port_per_client_array[index].prv_phy_port = + prv_phy_port_param; + } + + max_port_per_client_array[index].max_port_cnt++; + return MAX_PORT_ADD_SUCCESS; +} + +/** + * Function to delete a max ports per client entry + * + * @param prv_ip_param + * A uint32_t ip address of client + * @param prv_phy_port_param + * A uint32_t physical port id of the client + * @param p_nat + * A pointer to struct pipeline_cgnapt + * + * @return + * 0 no success, 1 if success, -1 if error + */ +int max_port_per_client_del_entry( + uint32_t prv_ip_param, + uint32_t prv_phy_port_param, + __rte_unused struct pipeline_cgnapt *p_nat) +{ + int index = MAX_PORT_DEL_ERROR; + + struct max_port_per_client_key key = { + .prv_ip = prv_ip_param, + .prv_phy_port = prv_phy_port_param, + }; + + index = rte_hash_lookup(max_port_per_client_hash, (const void *)&key); + + if (index == -EINVAL) + return MAX_PORT_DEL_ERROR; + + if (index == -ENOENT) + return MAX_PORT_DEL_UNSUCCESS; + + index = rte_hash_del_key(max_port_per_client_hash, (const void *)&key); + max_port_per_client_array[index].prv_ip = 0; + max_port_per_client_array[index].prv_phy_port = 0; + max_port_per_client_array[index].max_port_cnt = 0; + + return MAX_PORT_DEL_SUCCESS; +} + +/** + * Function to execute debug commands + * + * @param p + * A pointer to struct pipeline + * @param msg + * void pointer to incoming arguments + */ +void *pipeline_cgnapt_msg_req_entry_dbg_handler(struct pipeline *p, void *msg) +{ + struct pipeline_cgnapt_entry_delete_msg_rsp *rsp = msg; + uint8_t *Msg = msg; + struct pipeline_cgnapt *p_nat = (struct pipeline_cgnapt *)p; + + rsp->status = 0; + + if (Msg[CGNAPT_DBG_CMD_OFST] == CGNAPT_DBG_CMD_STATS_SHOW) { + printf("\nCG-NAPT Packet Stats:\n"); + printf("Received %" PRIu64 ",", p_nat->receivedPktCount); + printf("Missed %" PRIu64 ",", p_nat->missedPktCount); + printf("Dropped %" PRIu64 ",", p_nat->naptDroppedPktCount); + printf("Translated %" PRIu64 ",", p_nat->naptedPktCount); + printf("ingress %" PRIu64 ",", p_nat->inaptedPktCount); + printf("egress %" PRIu64 "\n", p_nat->enaptedPktCount); + printf("arp pkts %" PRIu64 "\n", p_nat->arpicmpPktCount); + + #ifdef CGNAPT_DEBUGGING + printf("\n Drop detail 1:%" PRIu64 ",", + p_nat->naptDroppedPktCount1); + printf("\n Drop detail 2:%" PRIu64 ",", + p_nat->naptDroppedPktCount2); + printf("\n Drop detail 3:%" PRIu64 ",", + p_nat->naptDroppedPktCount3); + printf("\n Drop detail 4:%" PRIu64 ",", + p_nat->naptDroppedPktCount4); + printf("\n Drop detail 5:%" PRIu64 ",", + p_nat->naptDroppedPktCount5); + printf("\n Drop detail 6:%" PRIu64 "", + p_nat->naptDroppedPktCount6); + + printf("\nPkt_miss: %" PRIu64 " %" PRIu64 "", + p_nat->missedpktcount1, + p_nat->missedpktcount2); + printf("\nPkt_miss: %" PRIu64 " %" PRIu64 "", + p_nat->missedpktcount3, + p_nat->missedpktcount4); + printf("\nPkt_miss: %" PRIu64 " %" PRIu64 "", + p_nat->missedpktcount5, + p_nat->missedpktcount6); + printf("\nPkt_miss: %" PRIu64 " %" PRIu64 "", + p_nat->missedpktcount7, + p_nat->missedpktcount8); + printf("\nPkt_miss: %" PRIu64 " %" PRIu64 "", + p_nat->missedpktcount9, + p_nat->missedpktcount10); + + #endif + + return rsp; + } + + if (Msg[CGNAPT_DBG_CMD_OFST] == CGNAPT_DBG_CMD_STATS_CLEAR) { + printf("\nCG-NAPT Packet Stats:\n"); + printf("Received %" PRIu64 ",", p_nat->receivedPktCount); + printf("Missed %" PRIu64 ",", p_nat->missedPktCount); + printf("Dropped %" PRIu64 ",", p_nat->naptDroppedPktCount); + printf("Translated %" PRIu64 ",", p_nat->naptedPktCount); + printf("ingress %" PRIu64 ",", p_nat->inaptedPktCount); + printf("egress %" PRIu64 "\n", p_nat->enaptedPktCount); + printf("arp pkts %" PRIu64 "\n", p_nat->arpicmpPktCount); + + p_nat->naptedPktCount = 0; + p_nat->naptDroppedPktCount = 0; + p_nat->inaptedPktCount = 0; + p_nat->enaptedPktCount = 0; + p_nat->receivedPktCount = 0; + p_nat->missedPktCount = 0; + p_nat->arpicmpPktCount = 0; + printf("CG-NAPT Packet Stats cleared\n"); + return rsp; + } + + if (Msg[CGNAPT_DBG_CMD_OFST] == CGNAPT_DBG_CMD_DBG_LEVEL) { + CGNAPT_DEBUG = Msg[CGNAPT_DBG_CMD_OFST + 1]; + printf("CG-NAPT debug level set to %d\n", CGNAPT_DEBUG); + return rsp; + } + + if (Msg[CGNAPT_DBG_CMD_OFST] == CGNAPT_DBG_CMD_DBG_SHOW) { + + printf("\nNAPT entries - added %" PRIu64 ",", + p_nat->n_cgnapt_entry_added); + printf("deleted %" PRIu64 ",", p_nat->n_cgnapt_entry_deleted); + printf("current %" PRIu64 "", p_nat->n_cgnapt_entry_added - + p_nat->n_cgnapt_entry_deleted); + + printf("\nCG-NAPT Packet Stats:\n"); + printf("Received %" PRIu64 ",", p_nat->receivedPktCount); + printf("Missed %" PRIu64 ",", p_nat->missedPktCount); + printf("Dropped %" PRIu64 ",", p_nat->naptDroppedPktCount); + printf("Translated %" PRIu64 ",", p_nat->naptedPktCount); + printf("ingress %" PRIu64 ",", p_nat->inaptedPktCount); + printf("egress %" PRIu64 "\n", p_nat->enaptedPktCount); + printf("arp pkts %" PRIu64 "\n", p_nat->arpicmpPktCount); + + return rsp; + } + #ifdef PIPELINE_CGNAPT_INSTRUMENTATION + if (Msg[CGNAPT_DBG_CMD_OFST] == CGNAPT_DBG_CMD_INSTRUMENTATION) { + if (Msg[CGNAPT_DBG_CMD_OFST1] == + CGNAPT_CMD_INSTRUMENTATION_SUB0) { + + int index = 0; + uint32_t diff_sum = 0; + + printf("CG-NAPT Instrumentation ...\n"); + printf("Instrumentation data collected for fn# %d\n", + cgnapt_num_func_to_inst); + printf("Current collection index %d\n", + cgnapt_inst_index); + + if (Msg[CGNAPT_DBG_CMD_OFST + 2] == 2) { + printf("Timer Start:\n"); + + for (index = 0; index < INST_ARRAY_SIZE; index++) { + if ((index % 5) == 0) + printf("\n"); + printf(" 0x%jx", inst_start_time[index]); + } + printf("\n\nTimer End:\n"); + + for (index = 0; index < INST_ARRAY_SIZE; index++) { + if ((index % 5) == 0) + printf("\n"); + printf(" 0x%jx", inst_end_time[index]); + } + } + + for (index = 0; index < INST_ARRAY_SIZE; index++) { + inst_diff_time[index] = (uint32_t) (inst_end_time[index] - + inst_start_time[index]); + } + + if (Msg[CGNAPT_DBG_CMD_OFST + 2] == + CGNAPT_CMD_INSTRUMENTATION_SUB1) { + printf("\n\nTimer Diff:\n"); + + for (index = 0; index < INST_ARRAY_SIZE; index++) { + if (Msg[CGNAPT_DBG_CMD_OFST + 2] == + CGNAPT_CMD_INSTRUMENTATION_SUB1) { + if ((index % 5) == 0) + printf("\n"); + printf(" 0x%08x", inst_diff_time[index]); + } + + diff_sum += inst_diff_time[index]; + } + + printf("\ndiff_sum %u, INST_ARRAY_SIZE %d, Ave Time %u\n", + diff_sum, INST_ARRAY_SIZE, (diff_sum / INST_ARRAY_SIZE)); + } else if (Msg[CGNAPT_DBG_CMD_OFST + 1] == + CGNAPT_CMD_INSTRUMENTATION_SUB1) { + /* p plid entry dbg 7 1 0 + * p plid entry dbg 7 1 1 <--- pkt_work_cgnapt + * p plid entry dbg 7 1 2 <--- pkt4_work_cgnapt + * p plid entry dbg 7 1 3 <--- pkt_work_cgnapt_key + * p plid entry dbg 7 1 4 <--- pkt4_work_cgnapt_key + * p plid entry dbg 7 1 5 <--- in port ah to out port ah + * - pkt life in the system + * p plid entry dbg 7 1 6 <--- how long this instrumentation + * itself is taking + */ + cgnapt_inst_index = 0; + cgnapt_num_func_to_inst = Msg[CGNAPT_DBG_CMD_OFST + 2]; + printf("Instrumentation data collection started for fn# %d\n", + cgnapt_num_func_to_inst); + } else if (Msg[CGNAPT_DBG_CMD_OFST + 1] == + CGNAPT_CMD_INSTRUMENTATION_SUB2) { + /* p plid entry dbg 7 2 0 + * Test all major functions by calling them multiple times + * pkt_work_cgnapt, pkt4_work_cgnapt, pkt_work_cgnapt_key, + * pkt4_work_cgnapt_key + */ + if (cgnapt_test_pktmbuf_pool == NULL) { + cgnapt_test_pktmbuf_pool = rte_pktmbuf_pool_create( + "cgnapt_test_pktmbuf_pool", 63, 32, 0, + RTE_MBUF_DEFAULT_BUF_SIZE, + rte_socket_id()); + } + + if (cgnapt_test_pktmbuf_pool == NULL) + printf("CGNAPT test mbuf pool create failed.\n"); + + struct rte_mbuf *cgnapt_test_pkt0 = + rte_pktmbuf_alloc(cgnapt_test_pktmbuf_pool); + if (cgnapt_test_pkt0 == NULL) + printf("CGNAPT test pkt 0 alloc failed."); + struct rte_mbuf *cgnapt_test_pkt1 = + rte_pktmbuf_alloc(cgnapt_test_pktmbuf_pool); + if (cgnapt_test_pkt1 == NULL) + printf("CGNAPT test pkt 1 alloc failed."); + struct rte_mbuf *cgnapt_test_pkt2 = + rte_pktmbuf_alloc(cgnapt_test_pktmbuf_pool); + if (cgnapt_test_pkt2 == NULL) + printf("CGNAPT test pkt 2 alloc failed."); + struct rte_mbuf *cgnapt_test_pkt3 = + rte_pktmbuf_alloc(cgnapt_test_pktmbuf_pool); + if (cgnapt_test_pkt3 == NULL) + printf("CGNAPT test pkt 3 alloc failed."); + + struct rte_mbuf *cgnapt_test_pkts[4]; + + cgnapt_test_pkts[0] = cgnapt_test_pkt0; + cgnapt_test_pkts[1] = cgnapt_test_pkt1; + cgnapt_test_pkts[2] = cgnapt_test_pkt2; + cgnapt_test_pkts[3] = cgnapt_test_pkt3; + + uint32_t src_addr_offset = + MBUF_HDR_ROOM + ETH_HDR_SIZE + IP_HDR_SRC_ADR_OFST; + /* 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; + /* header room + eth hdr size + + * dst_aadr offset in ip header + */ + uint32_t prot_offset = + MBUF_HDR_ROOM + ETH_HDR_SIZE + IP_HDR_PROTOCOL_OFST; + /* header room + eth hdr size + + * srprotocol char offset in ip header + */ + int pktCnt = 0, entCnt = 0, exCnt = 0; + + for (pktCnt = 0; pktCnt < 4; pktCnt++) { + uint32_t *src_addr = + RTE_MBUF_METADATA_UINT32_PTR + (cgnapt_test_pkts[pktCnt], src_addr_offset); + uint32_t *dst_addr = + RTE_MBUF_METADATA_UINT32_PTR + (cgnapt_test_pkts[pktCnt], dst_addr_offset); + uint8_t *protocol = + RTE_MBUF_METADATA_UINT8_PTR(cgnapt_test_pkts + [pktCnt], + prot_offset); + uint8_t *phy_port = + RTE_MBUF_METADATA_UINT8_PTR(cgnapt_test_pkts + [pktCnt], 70); + uint8_t *eth_dest = + RTE_MBUF_METADATA_UINT8_PTR(cgnapt_test_pkts + [pktCnt], + MBUF_HDR_ROOM); + uint8_t *eth_src = + RTE_MBUF_METADATA_UINT8_PTR( + cgnapt_test_pkts[pktCnt], + MBUF_HDR_ROOM + + 6); + uint16_t *src_port = + RTE_MBUF_METADATA_UINT16_PTR + (cgnapt_test_pkts[pktCnt], + MBUF_HDR_ROOM + ETH_HDR_SIZE + + IP_HDR_SIZE); + uint16_t *dst_port = + RTE_MBUF_METADATA_UINT16_PTR + (cgnapt_test_pkts[pktCnt], + MBUF_HDR_ROOM + ETH_HDR_SIZE + + IP_HDR_SIZE + 2); + *src_addr = 0xc0a80001; + *dst_addr = 0x90418634; + *protocol = 0x6; + *phy_port = 0; + *src_port = 1234; + *dst_port = 4000; + eth_src[0] = 0xAB; + eth_src[1] = 0xAB; + eth_src[2] = 0xAB; + eth_src[3] = 0xAB; + eth_src[4] = 0xAB; + eth_src[5] = 0xAB; + eth_dest[0] = 0x90; + eth_dest[1] = 0xE2; + eth_dest[2] = 0xba; + eth_dest[3] = 0x54; + eth_dest[4] = 0x67; + eth_dest[5] = 0xc8; + } + struct rte_pipeline_table_entry *table_entries[4]; + struct cgnapt_table_entry ctable_entries[4]; + table_entries[0] = (struct rte_pipeline_table_entry *) + &ctable_entries[0]; + table_entries[1] = (struct rte_pipeline_table_entry *) + &ctable_entries[1]; + table_entries[2] = (struct rte_pipeline_table_entry *) + &ctable_entries[2]; + table_entries[3] = (struct rte_pipeline_table_entry *) + &ctable_entries[3]; + for (entCnt = 0; entCnt < 4; entCnt++) { + ctable_entries[entCnt].head.action = + RTE_PIPELINE_ACTION_PORT; + ctable_entries[entCnt].head.port_id = 0; + + ctable_entries[entCnt].data.prv_ip = 0x01020304; + ctable_entries[entCnt].data.prv_port = 1234; + ctable_entries[entCnt].data.pub_ip = 0x0a0b0c0d; + ctable_entries[entCnt].data.pub_port = 4000; + ctable_entries[entCnt].data.prv_phy_port = 0; + ctable_entries[entCnt].data.pub_phy_port = 1; + ctable_entries[entCnt].data.ttl = 500; + } + + uint64_t time1 = rte_get_tsc_cycles(); + + for (exCnt = 0; exCnt < 1000; exCnt++) { + pkt_work_cgnapt_key(cgnapt_test_pkts[0], + instrumentation_port_in_arg); + } + uint64_t time2 = rte_get_tsc_cycles(); + + printf("times for %d times execution of " + "pkt_work_cgnapt_key 0x%jx", + exCnt, time1); + printf(", 0x%jx, diff %" PRIu64 "\n", time2, + time2 - time1); + + time1 = rte_get_tsc_cycles(); + for (exCnt = 0; exCnt < 1000000; exCnt++) { + pkt_work_cgnapt_key(cgnapt_test_pkts[0], + instrumentation_port_in_arg); + } + time2 = rte_get_tsc_cycles(); + printf("times for %d times execution of " + "pkt_work_cgnapt_key 0x%jx", exCnt, time1); + printf("0x%jx, diff %" PRIu64 "\n", time2, + time2 - time1); + + time1 = rte_get_tsc_cycles(); + for (exCnt = 0; exCnt < 1000; exCnt++) { + pkt4_work_cgnapt_key(cgnapt_test_pkts, + instrumentation_port_in_arg); + } + time2 = rte_get_tsc_cycles(); + printf("times for %d times execution of " + "pkt4_work_cgnapt_key 0x%jx", + exCnt, time1); + printf(" 0x%jx, diff %" PRIu64 "\n", time2, + time2 - time1); + + time1 = rte_get_tsc_cycles(); + for (exCnt = 0; exCnt < 1000000; exCnt++) { + pkt4_work_cgnapt_key(cgnapt_test_pkts, + instrumentation_port_in_arg); + } + time2 = rte_get_tsc_cycles(); + printf("times for %d times execution of " + "pkt4_work_cgnapt_key 0x%jx", + exCnt, time1); + printf("0x%jx, diff %" PRIu64 "\n", time2, + time2 - time1); + + uint64_t mask = 0xff; + + time1 = rte_get_tsc_cycles(); + for (exCnt = 0; exCnt < 1000; exCnt++) { + pkt_work_cgnapt(cgnapt_test_pkts[0], + table_entries[0], 3, &mask, + NULL); + } + time2 = rte_get_tsc_cycles(); + printf("times for %d times execution of " + "pkt_work_cgnapt 0x%jx", + exCnt, time1); + printf("0x%jx, diff %" PRIu64 "\n", time2, + time2 - time1); + + time1 = rte_get_tsc_cycles(); + for (exCnt = 0; exCnt < 1000000; exCnt++) { + pkt_work_cgnapt(cgnapt_test_pkts[0], + table_entries[0], 3, &mask, + NULL); + } + time2 = rte_get_tsc_cycles(); + printf("times for %d times execution of " + "pkt_work_cgnapt 0x%jx", + exCnt, time1); + printf("0x%jx, diff %" PRIu64 "\n", time2, + time2 - time1); + + time1 = rte_get_tsc_cycles(); + for (exCnt = 0; exCnt < 1000; exCnt++) { + pkt4_work_cgnapt(cgnapt_test_pkts, + table_entries, 0, &mask, NULL); + } + time2 = rte_get_tsc_cycles(); + printf("times for %d times execution of " + "pkt4_work_cgnapt 0x%jx", + exCnt, time1); + printf("0x%jx, diff % " PRIu64 "\n", time2, + time2 - time1); + + int idummy = ctable_entries[0].data.prv_port; + + idummy++; + + } + } + return rsp; + } + #endif + + if (Msg[CGNAPT_DBG_CMD_OFST] == CGNAPT_DBG_CMD_LS_ENTRY) { + printf("CG-NAPT be entries are:\n"); + printf("Pipeline pointer %p\n", p); + return rsp; + } + + if (Msg[CGNAPT_DBG_CMD_OFST] == CGNAPT_DBG_CMD_DYN) { + printf("Total Number of dynamic napt entries: %" PRIu64 "\n", + p_nat->dynCgnaptCount); + + #ifdef CGNAPT_DEBUGGING + printf("MAX PORT PER CLIENT:"); + printf("%" PRIu64 ",%" PRIu64 ",%" PRIu64 "\n", + p_nat->max_port_dec_err1, p_nat->max_port_dec_err2, + p_nat->max_port_dec_err3); + printf("MPPC success : %" PRIu64 "\n", + p_nat->max_port_dec_success); + + printf("Release port:err:%" PRIu64 ",ret::%" PRIu64 ",get::%" + PRIu64 ",suc::%" PRIu64 "\n", p_nat->pfb_err, + p_nat->pfb_ret, p_nat->pfb_get, p_nat->pfb_suc); + printf("Get port::err:%" PRIu64 ",ret::%" PRIu64 ",get::%" + PRIu64 ",suc::%" PRIu64 "\n", p_nat->gfp_err, + p_nat->gfp_ret, p_nat->gfp_get, p_nat->gfp_suc); + printf("Ring Info:\n"); + rte_ring_dump(stdout, p_nat->port_alloc_ring); + #endif + return rsp; + } + if (Msg[CGNAPT_DBG_CMD_OFST] == CGNAPT_DBG_CMD_IPV6) { + dual_stack_enable = Msg[CGNAPT_DBG_CMD_OFST + 1]; + printf("Dual Stack option set: %x\n", dual_stack_enable); + return rsp; + } + + if (Msg[CGNAPT_DBG_CMD_OFST] == CGNAPT_DBG_CMD_MAPS_INFO) { + pipelines_port_info(); + pipelines_map_info(); + return rsp; + } + + if (Msg[CGNAPT_DBG_CMD_OFST] == CGNAPT_DBG_CMD_ITER_COM_TBL) { + uint32_t count = 0; + const void *key; + void *data; + uint32_t next = 0; + int32_t index = 0; + + do { + index = + rte_hash_iterate(napt_common_table, &key, &data, + &next); + + if ((index != -EINVAL) && (index != -ENOENT)) { + printf("\n%04d ", count); + rte_hexdump(stdout, "KEY", key, + sizeof(struct + pipeline_cgnapt_entry_key)); + + //print_key((struct pipeline_cgnapt_entry_key *) + // key); + int32_t position = + rte_hash_lookup(napt_common_table, + key); + print_cgnapt_entry(&napt_hash_tbl_entries + [position]); + } + + count++; + } while (index != -ENOENT); + return rsp; + } + + if (Msg[CGNAPT_DBG_CMD_OFST] == CGNAPT_DBG_CMD_IF_STATS) { + + struct app_params *app = + (struct app_params *)p_nat->app_params_addr; + uint8_t cmd[2]; + + cmd[0] = Msg[CGNAPT_DBG_CMD_OFST + 1]; + cmd[1] = Msg[CGNAPT_DBG_CMD_OFST + 2]; + switch (cmd[0]) { + case CGNAPT_IF_STATS_HWQ: + printf("n_pktq_hwq_int :%d\n", app->n_pktq_hwq_in); + printf("n_pktq_hwq_out :%d\n", app->n_pktq_hwq_out); + printf("\n"); + uint8_t i, j; + + for (i = 0; i < app->n_pktq_hwq_in; i++) { + struct rte_eth_stats stats; + + rte_eth_stats_get(p_nat->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 "", + stats.ipackets); + printf("\n\topackets : %" PRIu64 "", + stats.opackets); + printf("\n\tierrors : %" PRIu64 "", + stats.ierrors); + printf("\n\toerrors : %" PRIu64 "", + stats.oerrors); + printf("\n\trx_nombuf: %" PRIu64 "", + stats.rx_nombuf); + printf("\n"); + 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; + + case CGNAPT_IF_STATS_SWQ: + + printf("n_pktq_swq :%d\n", app->n_pktq_swq); + + if (cmd[1] < app->n_pktq_swq) { + rte_ring_dump(stdout, app->swq[cmd[1]]); + return rsp; + } + printf("SWQ number is invalid\n"); + return rsp; + + case CGNAPT_IF_STATS_OTH: + printf("\n"); + printf("config_file:%s\n", app->config_file); + printf("script_file:%s\n", app->script_file); + printf("parser_file:%s\n", app->parser_file); + printf("output_file:%s\n", app->output_file); + printf("n_msgq :%d\n", app->n_msgq); + printf("n_pktq_tm :%d\n", app->n_pktq_tm); + printf("n_pktq_source :%d\n", app->n_pktq_source); + printf("n_pktq_sink :%d\n", app->n_pktq_sink); + printf("n_pipelines :%d\n", app->n_pipelines); + printf("\n"); + return rsp; + default: + printf("Command does not match\n\n"); + return rsp; + + } /* switch */ + + return rsp; + } + + if (Msg[CGNAPT_DBG_CMD_OFST] == CGNAPT_DBG_MAX_CLI_PER_PUB_IP) { + if (nat_only_config_flag) { + printf("Command not supported for NAT only config.\n"); + return rsp; + } + uint16_t ii; + + printf("\tPublic IP: Num Clients\n"); + for (ii = 0; ii < CGNAPT_MAX_PUB_IP; ii++) + printf("\t%x : %7d\n", all_public_ip[ii].ip, + rte_atomic16_read(&all_public_ip[ii].count)); + return rsp; + } + + if (Msg[CGNAPT_DBG_CMD_OFST] == CGNAPT_DBG_PUB_IP_LIST) { + + int i; + for (i = 0; i < p_nat->pub_ip_count; i++) + printf("%x : (%d,%d)\n", p_nat->pub_ip_port_set[i].ip, + p_nat->pub_ip_port_set[i].start_port, + p_nat->pub_ip_port_set[i].end_port); + return rsp; + } + + #ifdef CGNAPT_TIMING_INST + if (Msg[CGNAPT_DBG_CMD_OFST] == CGNAPT_DBG_TIMING_INST) { + if (Msg[CGNAPT_DBG_CMD_OFST + 1] == 0) { + p_nat->time_measurements_on = 1; + p_nat->time_measurements = 0; + printf("CGNAPT timing instrumentation turned on.\n"); + printf("Max samples %d\n", p_nat->max_time_mesurements); + } + if (Msg[CGNAPT_DBG_CMD_OFST + 1] == 1) { + p_nat->time_measurements_on = 0; + printf("CGNAPT timing instrumentation turned off.\n"); + printf("Cur Samples %d\n", p_nat->time_measurements); + } + if (Msg[CGNAPT_DBG_CMD_OFST + 1] == 2) { + uint64_t sum = p_nat->external_time_sum + + p_nat->internal_time_sum; + uint64_t isump = (p_nat->internal_time_sum * 100) / sum; + uint64_t esump = (p_nat->external_time_sum * 100) / sum; + printf("CGNAPT timing instrumentation status ...\n"); + printf("Max Count %d, Cur Count %d, Status %d (1=ON)\n", + p_nat->max_time_mesurements, + p_nat->time_measurements, + p_nat->time_measurements_on); + printf("Internal Time Sum %" PRIu64 " , Ave %" PRIu64 + ", percent %" PRIu64 "\n", + p_nat->internal_time_sum, + (p_nat->internal_time_sum / + p_nat->time_measurements), isump); + printf("External Time Sum %" PRIu64 " , Ave %" PRIu64 + ", percent %" PRIu64 "\n", + p_nat->external_time_sum, + (p_nat->external_time_sum / + p_nat->time_measurements), esump); + } + + return rsp; + } + #endif + + if (Msg[CGNAPT_DBG_CMD_OFST] == CGNAPT_DBG_CMD_PRINT_NSP) { + struct cgnapt_nsp_node *ll = nsp_ll; + + while (ll != NULL) { + fprintf(stderr, "NSP Prefix/Depth=>%x%x:%x%x:%x%x: " + "%x%x:%x%x:%x%x:%x%x:%x%x/%d", + ll->nsp.prefix[0], ll->nsp.prefix[1], + ll->nsp.prefix[2], ll->nsp.prefix[3], + ll->nsp.prefix[4], ll->nsp.prefix[5], + ll->nsp.prefix[6], ll->nsp.prefix[7], + ll->nsp.prefix[8], ll->nsp.prefix[9], + ll->nsp.prefix[10], ll->nsp.prefix[11], + ll->nsp.prefix[12], ll->nsp.prefix[13], + ll->nsp.prefix[14], ll->nsp.prefix[15], + ll->nsp.depth); + + ll = ll->next; + } + + return rsp; + } + + printf("CG-NAPT debug handler called with wrong args %x %x\n", Msg[0], + Msg[1]); + int i = 0; + + for (i = 0; i < 20; i++) + printf("%02x ", Msg[i]); + printf("\n"); + return rsp; +} + +/** + * Function to print num of clients per IP address + * + */ +void print_num_ip_clients(void) +{ + if (nat_only_config_flag) { + printf("Command not supported for NAT only config.\n"); + return; + } + + uint16_t ii; + printf("\tPublic IP: Num Clients\n"); + for (ii = 0; ii < CGNAPT_MAX_PUB_IP; ii++) + printf("\t%08x : %7d\n", all_public_ip[ii].ip, + rte_atomic16_read(&all_public_ip[ii].count)); +} + +/** + * Function to print CGNAPT version info + * + * @param p + * An unused pointer to struct pipeline + * @param msg + * void pointer to incoming arguments + */ +void *pipeline_cgnapt_msg_req_ver_handler(__rte_unused struct pipeline *p, + void *msg) +{ + struct pipeline_cgnapt_entry_delete_msg_rsp *rsp = msg; + uint8_t *Msg = msg; + + rsp->status = 0; + + printf("CG-NAPT debug handler called with args %x %x, offset %d\n", + Msg[CGNAPT_VER_CMD_OFST], Msg[CGNAPT_VER_CMD_OFST + 1], + CGNAPT_VER_CMD_OFST); + + if (Msg[CGNAPT_VER_CMD_OFST] == CGNAPT_VER_CMD_VER) { + printf("CGNAPT Version %s\n", CGNAPT_VERSION); + return rsp; + } + printf("CG-NAPT Version handler called with wrong args %x %x\n", + Msg[0], Msg[1]); + int i = 0; + + for (i = 0; i < 20; i++) + printf("%02x ", Msg[i]); + printf("\n"); + return rsp; +} + +/** + * Function to show CGNAPT stats + * + */ +void all_cgnapt_stats(void) +{ + int i; + struct pipeline_cgnapt *p_nat; + uint64_t receivedPktCount = 0; + uint64_t missedPktCount = 0; + uint64_t naptDroppedPktCount = 0; + uint64_t naptedPktCount = 0; + uint64_t inaptedPktCount = 0; + uint64_t enaptedPktCount = 0; + uint64_t arpicmpPktCount = 0; + + printf("\nCG-NAPT Packet Stats:\n"); + for (i = 0; i < n_cgnapt_pipeline; i++) { + p_nat = all_pipeline_cgnapt[i]; + + receivedPktCount += p_nat->receivedPktCount; + missedPktCount += p_nat->missedPktCount; + naptDroppedPktCount += p_nat->naptDroppedPktCount; + naptedPktCount += p_nat->naptedPktCount; + inaptedPktCount += p_nat->inaptedPktCount; + enaptedPktCount += p_nat->enaptedPktCount; + arpicmpPktCount += p_nat->arpicmpPktCount; + + printf("pipeline %d stats:\n", p_nat->pipeline_num); + printf("Received %" PRIu64 ",", p_nat->receivedPktCount); + printf("Missed %" PRIu64 ",", p_nat->missedPktCount); + printf("Dropped %" PRIu64 ",", p_nat->naptDroppedPktCount); + printf("Translated %" PRIu64 ",", p_nat->naptedPktCount); + printf("ingress %" PRIu64 ",", p_nat->inaptedPktCount); + printf("egress %" PRIu64 "\n", p_nat->enaptedPktCount); + printf("arpicmp pkts %" PRIu64 "\n", p_nat->arpicmpPktCount); + + + #ifdef CGNAPT_DEBUGGING + printf("\n Drop detail 1:%" PRIu64 ",", + p_nat->naptDroppedPktCount1); + printf("\n Drop detail 2:%" PRIu64 ",", + p_nat->naptDroppedPktCount2); + printf("\n Drop detail 3:%" PRIu64 ",", + p_nat->naptDroppedPktCount3); + printf("\n Drop detail 4:%" PRIu64 ",", + p_nat->naptDroppedPktCount4); + printf("\n Drop detail 5:%" PRIu64 ",", + p_nat->naptDroppedPktCount5); + printf("\n Drop detail 6:%" PRIu64 "", + p_nat->naptDroppedPktCount6); + + printf("\nPkt_miss: %" PRIu64 " %" PRIu64 "", + p_nat->missedpktcount1, + p_nat->missedpktcount2); + printf("\nPkt_miss: %" PRIu64 " %" PRIu64 "", + p_nat->missedpktcount3, + p_nat->missedpktcount4); + printf("\nPkt_miss: %" PRIu64 " %" PRIu64 "", + p_nat->missedpktcount5, + p_nat->missedpktcount6); + printf("\nPkt_miss: %" PRIu64 " %" PRIu64 "", + p_nat->missedpktcount7, + p_nat->missedpktcount8); + printf("\nPkt_miss: %" PRIu64 " %" PRIu64 "", + p_nat->missedpktcount9, + p_nat->missedpktcount10); + + #endif + + } + + printf("\nTotal pipeline stats:\n"); + printf("Received %" PRIu64 ",", receivedPktCount); + printf("Missed %" PRIu64 ",", missedPktCount); + printf("Dropped %" PRIu64 ",", naptDroppedPktCount); + printf("Translated %" PRIu64 ",", naptedPktCount); + printf("ingress %" PRIu64 ",", inaptedPktCount); + printf("egress %" PRIu64 "\n", enaptedPktCount); + printf("arpicmp pkts %" PRIu64 "\n", arpicmpPktCount); +} + +void all_cgnapt_clear_stats(void) +{ + int i; + struct pipeline_cgnapt *p_nat; + printf("\nCG-NAPT Packet Stats:\n"); + for (i = 0; i < n_cgnapt_pipeline; i++) { + p_nat = all_pipeline_cgnapt[i]; + + printf("pipeline %d stats:\n", p_nat->pipeline_num); + printf("Received %" PRIu64 ",", p_nat->receivedPktCount); + printf("Missed %" PRIu64 ",", p_nat->missedPktCount); + printf("Dropped %" PRIu64 ",", p_nat->naptDroppedPktCount); + printf("Translated %" PRIu64 ",", p_nat->naptedPktCount); + printf("ingress %" PRIu64 ",", p_nat->inaptedPktCount); + printf("egress %" PRIu64 "\n", p_nat->enaptedPktCount); + printf("arpicmp pkts %" PRIu64 "\n", p_nat->arpicmpPktCount); + + p_nat->receivedPktCount = 0; + p_nat->missedPktCount = 0; + p_nat->naptDroppedPktCount = 0; + p_nat->naptedPktCount = 0; + p_nat->inaptedPktCount = 0; + p_nat->enaptedPktCount = 0; + p_nat->arpicmpPktCount = 0; + + #ifdef CGNAPT_DEBUGGING + printf("\n Drop detail 1:%" PRIu64 ",", + p_nat->naptDroppedPktCount1); + printf("\n Drop detail 2:%" PRIu64 ",", + p_nat->naptDroppedPktCount2); + printf("\n Drop detail 3:%" PRIu64 ",", + p_nat->naptDroppedPktCount3); + printf("\n Drop detail 4:%" PRIu64 ",", + p_nat->naptDroppedPktCount4); + printf("\n Drop detail 5:%" PRIu64 ",", + p_nat->naptDroppedPktCount5); + printf("\n Drop detail 6:%" PRIu64 "", + p_nat->naptDroppedPktCount6); + + printf("\nPkt_miss: %" PRIu64 " %" PRIu64 "", + p_nat->missedpktcount1, + p_nat->missedpktcount2); + printf("\nPkt_miss: %" PRIu64 " %" PRIu64 "", + p_nat->missedpktcount3, + p_nat->missedpktcount4); + printf("\nPkt_miss: %" PRIu64 " %" PRIu64 "", + p_nat->missedpktcount5, + p_nat->missedpktcount6); + printf("\nPkt_miss: %" PRIu64 " %" PRIu64 "", + p_nat->missedpktcount7, + p_nat->missedpktcount8); + printf("\nPkt_miss: %" PRIu64 " %" PRIu64 "", + p_nat->missedpktcount9, + p_nat->missedpktcount10); + + #endif + + } +} + +/** + * Function to print common CGNAPT table entries + * + */ +void print_static_cgnapt_entries(void) +{ + uint32_t count = 0; + const void *key; + void *data; + uint32_t next = 0; + int32_t index = 0; + struct cgnapt_table_entry *entry; + do { + index = rte_hash_iterate(napt_common_table, + &key, &data, &next); + + if ((index != -EINVAL) && (index != -ENOENT)) { + printf("\n%04d ", count); + rte_hexdump(stdout, "KEY", key, + sizeof(struct pipeline_cgnapt_entry_key)); + int32_t position = rte_hash_lookup( + napt_common_table, key); + entry = &napt_hash_tbl_entries[position]; + + if (entry->data.timeout == STATIC_CGNAPT_TIMEOUT) + rte_hexdump(stdout, "Entry", + (const void *)entry, + sizeof(struct cgnapt_table_entry)); + } + + count++; + } while (index != -ENOENT); +} + +/** + * Function to show CGNAPT stats + * + */ + +struct pipeline_be_ops pipeline_cgnapt_be_ops = { + .f_init = pipeline_cgnapt_init, + .f_free = pipeline_cgnapt_free, + .f_run = NULL, + .f_timer = pipeline_cgnapt_timer, + .f_track = pipeline_cgnapt_track, +}; -- cgit 1.2.3-korg