/* // 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, 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 ", "NAPT_PORT_ALLOC_8 ", "NAPT_PORT_ALLOC_9 ", "NAPT_PORT_ALLOC_10 ", "NAPT_PORT_ALLOC_11 ", "NAPT_PORT_ALLOC_12 ", "NAPT_PORT_ALLOC_13 ", "NAPT_PORT_ALLOC_14 ", "NAPT_PORT_ALLOC_16 " }; 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 CHECKSUM_REQ if (p_nat->hw_checksum_reqd) hw_checksum(pkts[pkt_index], pkt_type); else sw_checksum(pkts[pkt_index], pkt_type); #endif } 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 CHECKSUM_REQ if (p_nat->hw_checksum_reqd) hw_checksum(pkt, pkt_type); else sw_checksum(pkt, pkt_type); #endif } /** * 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 CHECKSUM_REQ if (p_nat->hw_checksum_reqd) hw_checksum(pkt, pkt_type); else sw_checksum(pkt, pkt_type); #endif } /** * 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 CHECKSUM_REQ if (p_nat->hw_checksum_reqd) hw_checksum(pkt, pkt_type); else sw_checksum(pkt, pkt_type); #endif } } /** * 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 CHECKSUM_REQ if (p_nat->hw_checksum_reqd) hw_checksum(pkt, pkt_type); else sw_checksum(pkt, pkt_type); #endif } } /** * 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 CHECKSUM_REQ if (p_nat->hw_checksum_reqd) hw_checksum(pkt, pkt_type); else sw_checksum(pkt, pkt_type); #endif } /** * 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 CHECKSUM_REQ if (p_nat->hw_checksum_reqd) hw_checksum(pkt, pkt_type); else sw_checksum(pkt, pkt_type); #endif } /** * 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 CHECKSUM_REQ if (p_nat->hw_checksum_reqd) hw_checksum(pkt, pkt_type); else sw_checksum(pkt, pkt_type); #endif } } /** * 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 CHECKSUM_REQ if (p_nat->hw_checksum_reqd) hw_checksum(pkt, pkt_type); else sw_checksum(pkt, pkt_type); #endif } } /** * 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, };