/* // Copyright (c) 2017 Intel Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ #include "l3fwd_common.h" #include "l3fwd_lpm4.h" #include "l3fwd_lpm6.h" #include "l3fwd_common.h" #include "interface.h" #include "l2_proto.h" #include "lib_arp.h" #include "lib_icmpv6.h" /* Declare Global variables */ /* Global for IPV6 */ void *lpm6_table; /**< lpm6 table handler */ struct rte_hash *l2_adj_ipv6_hash_handle; /**< IPv6 l2 adjacency table handler */ struct rte_hash *fib_path_ipv6_hash_handle; /**< IPv6 fib path hash table handler */ extern uint8_t nh_links[MAX_SUPPORTED_FIB_PATHS][HASH_BUCKET_SIZE]; extern l3_stats_t stats; /**< L3 statistics */ static struct ipv6_protocol_type *proto_type[2]; int lpm6_init(void) { /* Initiliaze LPMv6 params */ struct rte_table_lpm_ipv6_params lpm6_params = { .name = "LPMv6", .n_rules = IPV6_L3FWD_LPM_MAX_RULES, .number_tbl8s = IPV6_L3FWD_LPM_NUMBER_TBL8S, .entry_unique_size = sizeof(struct ipv6_fib_info), .offset = 128, }; /* Create LPMv6 tables */ lpm6_table = rte_table_lpm_ipv6_ops.f_create(&lpm6_params, rte_socket_id(), sizeof(struct ipv6_fib_info)); if (lpm6_table == NULL) { printf("Failed to create LPM IPV6 table\n"); return 0; } /*Initialize IPv6 params for l2 Adj */ struct rte_hash_parameters l2_adj_ipv6_params = { .name = "l2_ADJ_IPV6_HASH", .entries = 64, .key_len = sizeof(struct l2_adj_key_ipv6), .hash_func = rte_jhash, .hash_func_init_val = 0, }; l2_adj_ipv6_hash_handle = rte_hash_create(&l2_adj_ipv6_params); if (l2_adj_ipv6_hash_handle == NULL) { printf("ND for IPV6 rte_hash_create failed.\n"); return 0; } else { printf("ND IPV6_hash_handle %p\n\n", (void *)l2_adj_ipv6_hash_handle); } /*Initialize Fib PAth hassh params */ struct rte_hash_parameters fib_path_ipv6_params = { .name = "FIB_PATH_IPV6_HASH", .entries = 64, .key_len = sizeof(struct fib_path_key_ipv6), .hash_func = rte_jhash, .hash_func_init_val = 0, .extra_flag = 1, }; /* Create FIB PATH Hash tables */ fib_path_ipv6_hash_handle = rte_hash_create(&fib_path_ipv6_params); if (fib_path_ipv6_hash_handle == NULL) { printf("FIB path rte_hash_create failed\n"); return 0; } return 1; } int lpm6_table_route_add(struct ipv6_routing_info *data) { struct ipv6_routing_info *fib = data; /* Populate the Key */ struct rte_table_lpm_ipv6_key lpm6_key; uint8_t i; for (i = 0; i < 16; i++) { lpm6_key.ip[i] = fib->dst_ipv6[i]; } lpm6_key.depth = fib->depth; static int Total_route_count; struct ipv6_fib_info entry; for (i = 0; i < 16; i++) { entry.dst_ipv6[i] = fib->dst_ipv6[i]; } entry.depth = fib->depth; entry.fib_nh_size = fib->fib_nh_size; #if MULTIPATH_FEAT if (entry.fib_nh_size == 0 || entry.fib_nh_size > MAX_FIB_PATHS) #else if (entry.fib_nh_size != 1) /**< For Single FIB_PATH */ #endif { printf ("Route's can't be configured!!, entry.fib_nh_size = %d\n", entry.fib_nh_size); return 0; } /* Populate L2 adj and precomputes l2 encap string */ #if MULTIPATH_FEAT for (i = 0; i < entry.fib_nh_size; i++) #else for (i = 0; i < 1; i++) #endif { struct ipv6_fib_path *ipv6_fib_path_addr = NULL; ipv6_fib_path_addr = populate_ipv6_fib_path(fib->nh_ipv6[i], fib->out_port[i]); if (ipv6_fib_path_addr) { entry.path[i] = ipv6_fib_path_addr; printf("Fib path for IPv6 destination = " "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:" "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x/%u) ==> fib_path Addr :%p, L2_adj Addr ;%p\n", lpm6_key.ip[0], lpm6_key.ip[1], lpm6_key.ip[2], lpm6_key.ip[3], lpm6_key.ip[4], lpm6_key.ip[5], lpm6_key.ip[6], lpm6_key.ip[7], lpm6_key.ip[8], lpm6_key.ip[9], lpm6_key.ip[10], lpm6_key.ip[11], lpm6_key.ip[12], lpm6_key.ip[13], lpm6_key.ip[14], lpm6_key.ip[15], fib->depth, ipv6_fib_path_addr, (void *)entry.path[i]->l2_adj_ipv6_ptr); } else { printf("Fib path for IPv6 destination = " "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:" "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x/%u) ==> fib_path Addr : NULL\n", lpm6_key.ip[0], lpm6_key.ip[1], lpm6_key.ip[2], lpm6_key.ip[3], lpm6_key.ip[4], lpm6_key.ip[5], lpm6_key.ip[6], lpm6_key.ip[7], lpm6_key.ip[8], lpm6_key.ip[9], lpm6_key.ip[10], lpm6_key.ip[11], lpm6_key.ip[12], lpm6_key.ip[13], lpm6_key.ip[14], lpm6_key.ip[15], fib->depth); entry.path[i] = NULL; /**< setting all other fib_paths to NULL */ } } int key_found, ret; void *entry_ptr; /* Adding a IP route in LPMv6 table */ printf("%s, Line %u \n", __FUNCTION__, __LINE__); ret = rte_table_lpm_ipv6_ops.f_add(lpm6_table, (void *)&lpm6_key, &entry, &key_found, &entry_ptr); printf("%s, Line %u \n", __FUNCTION__, __LINE__); if (ret) { printf("Failed to Add IP route in LPMv6\n"); return 0; } printf("Added route to IPv6 LPM table (IPv6 destination = " "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:" "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x/%u)\n", lpm6_key.ip[0], lpm6_key.ip[1], lpm6_key.ip[2], lpm6_key.ip[3], lpm6_key.ip[4], lpm6_key.ip[5], lpm6_key.ip[6], lpm6_key.ip[7], lpm6_key.ip[8], lpm6_key.ip[9], lpm6_key.ip[10], lpm6_key.ip[11], lpm6_key.ip[12], lpm6_key.ip[13], lpm6_key.ip[14], lpm6_key.ip[15], fib->depth); Total_route_count++; printf("Total Routed Added : %u, Key_found: %d\n", Total_route_count, key_found); if (Total_route_count == 2) ipv6_iterate__hash_table(); return 1; } int lpm6_table_route_delete(uint8_t dst_ipv6[RTE_LPM_IPV6_ADDR_SIZE], uint8_t depth) { /* Populate the Key */ struct rte_table_lpm_ipv6_key lpm6_key; memcpy(&lpm6_key.ip, &dst_ipv6, sizeof(RTE_LPM_IPV6_ADDR_SIZE)); lpm6_key.depth = depth; int key_found, ret; char *entry = NULL; entry = rte_zmalloc(NULL, 512, RTE_CACHE_LINE_SIZE); /* Delete a IP route in LPMv6 table */ ret = rte_table_lpm_ipv6_ops.f_delete(lpm6_table, &lpm6_key, &key_found, entry); if (ret) { printf("Failed to Delete IP route from LPMv6 table\n"); return 0; } printf("Deleted route from IPv6 LPM table (IPv6 destination = " "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:" "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x/%u, key_found = %d\n", lpm6_key.ip[0], lpm6_key.ip[1], lpm6_key.ip[2], lpm6_key.ip[3], lpm6_key.ip[4], lpm6_key.ip[5], lpm6_key.ip[6], lpm6_key.ip[7], lpm6_key.ip[8], lpm6_key.ip[9], lpm6_key.ip[10], lpm6_key.ip[11], lpm6_key.ip[12], lpm6_key.ip[13], lpm6_key.ip[14], lpm6_key.ip[15], lpm6_key.depth, key_found); /* Deleting a L2 Adj entry if refcount is 1, Else decrement Refcount */ remove_ipv6_fib_l2_adj_entry(entry); rte_free(entry); // free memory return 1; } int lpm6_table_lookup(struct rte_mbuf **pkts_burst, uint16_t nb_pkts, uint64_t pkts_mask, l2_phy_interface_t *port_ptr[RTE_PORT_IN_BURST_SIZE_MAX], uint64_t *hit_mask) { struct ipv6_routing_table_entry *ipv6_entries[RTE_PORT_IN_BURST_SIZE_MAX]; uint64_t lookup_hit_mask_ipv6 = 0; int status; uint64_t lookup_miss_mask = pkts_mask; /*Populate the key offset in META DATA */ uint32_t dst_addr_offset = MBUF_HDR_ROOM + ETH_HDR_SIZE + IP_HDR_DST_ADR_OFST_IPV6; uint64_t pkts_key_mask = pkts_mask; //for(i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) for (; pkts_key_mask;) { /**< Populate key offset in META DATA for all valid pkts */ uint8_t pos = (uint8_t) __builtin_ctzll(pkts_key_mask); uint64_t pkt_mask = 1LLU << pos; pkts_key_mask &= ~pkt_mask; uint8_t *lpm6_key; uint8_t dst_addr[RTE_LPM_IPV6_ADDR_SIZE]; memcpy(dst_addr, (uint8_t *) RTE_MBUF_METADATA_UINT32_PTR(pkts_burst[pos], dst_addr_offset), RTE_LPM_IPV6_ADDR_SIZE); lpm6_key = (uint8_t *) RTE_MBUF_METADATA_UINT8_PTR(pkts_burst[pos], 128); memcpy(lpm6_key, dst_addr, RTE_LPM_IPV6_ADDR_SIZE); } /* Lookup for IP route in LPM6 table */ printf(" IPV6 Lookup Mask Before = %p, nb_pkts :%u\n", (void *)pkts_mask, nb_pkts); status = rte_table_lpm_ops.f_lookup(lpm6_table, pkts_burst, pkts_mask, &lookup_hit_mask_ipv6, (void **)ipv6_entries); if (status) { printf("LPM Lookup failed for IP route\n"); return 0; } printf(" IPV6 Lookup Mask After = %p\n", (void *)lookup_hit_mask_ipv6); lookup_miss_mask = lookup_miss_mask & (~lookup_hit_mask_ipv6); if (L3FWD_DEBUG) { printf("AFTER lookup_hit_mask = %p, lookup_miss_mask =%p\n", (void *)lookup_hit_mask_ipv6, (void *)lookup_miss_mask); } for (; lookup_miss_mask;) { /**< Drop packets for lookup_miss_mask */ uint8_t pos = (uint8_t) __builtin_ctzll(lookup_miss_mask); uint64_t pkt_mask = 1LLU << pos; lookup_miss_mask &= ~pkt_mask; rte_pktmbuf_free(pkts_burst[pos]); pkts_burst[pos] = NULL; if (L3FWD_DEBUG) printf("\n DROP PKT IPV4 Lookup_miss_Mask = %p\n", (void *)lookup_miss_mask); } *hit_mask = lookup_hit_mask_ipv6; for (; lookup_hit_mask_ipv6;) { uint8_t pos = (uint8_t) __builtin_ctzll(lookup_hit_mask_ipv6); uint64_t pkt_mask = 1LLU << pos; lookup_hit_mask_ipv6 &= ~pkt_mask; struct rte_mbuf *pkt = pkts_burst[pos]; struct ipv6_fib_info *entry = (struct ipv6_fib_info *)ipv6_entries[pos]; #if MULTIPATH_FEAT uint8_t ecmp_path = ipv6_hash_load_balance(pkts_burst[pos]); uint8_t selected_path = 0; struct ipv6_fib_path *fib_path = NULL; if (((entry->fib_nh_size != 0) && (entry->fib_nh_size - 1) < MAX_SUPPORTED_FIB_PATHS) && ((ecmp_path != 0) && (ecmp_path - 1) < HASH_BUCKET_SIZE)) selected_path = nh_links[entry->fib_nh_size - 1][ecmp_path - 1]; if (selected_path < MAX_FIB_PATHS) fib_path = entry->path[selected_path]; printf ("Total supported Path :%u, Hashed ECMP Key : %u, selected Fib_path: %u\n", entry->fib_nh_size, ecmp_path, selected_path); #else struct ipv6_fib_path *fib_path = entry->path[0]; #endif if (fib_path == NULL) { printf("Fib_path is NULL, ND has not resolved\n"); rte_pktmbuf_free(pkt); pkts_burst[pos] = NULL; stats.nb_l3_drop_pkt++; /**< Peg the L3 Drop counter */ *hit_mask &= ~pkt_mask; /**< Remove this pkt from port Mask */ printf ("Fib_path is NULL, ND has not resolved, DROPPED UNKNOWN PKT\n"); continue; } if (fib_path->l2_adj_ipv6_ptr->flags == L2_ADJ_UNRESOLVED) { rte_pktmbuf_free(pkts_burst[pos]); pkts_burst[pos] = NULL; *hit_mask &= ~pkt_mask; /**< Remove this pkt from port Mask */ if (L3FWD_DEBUG) printf ("L2_ADJ_UNRESOLVED, DROPPED UNKNOWN PKT\n"); continue; } uint8_t *eth_dest = RTE_MBUF_METADATA_UINT8_PTR(pkt, MBUF_HDR_ROOM); uint8_t *eth_src = RTE_MBUF_METADATA_UINT8_PTR(pkt, MBUF_HDR_ROOM + 6); if (L3FWD_DEBUG) { printf ("MAC BEFORE- DST MAC %02x:%02x:%02x:%02x" ":%02x:%02x, " "SRC MAC %02x:%02x:%02x:%02x:" "%02x:%02x \n", eth_dest[0], eth_dest[1], eth_dest[2], eth_dest[3], eth_dest[4], eth_dest[5], eth_src[0], eth_src[1], eth_src[2], eth_src[3], eth_src[4], eth_src[5]); } /* Rewrite the packet with L2 string */ memcpy(eth_dest, fib_path->l2_adj_ipv6_ptr->l2_string, sizeof(struct ether_addr) * 2 + 2); if (L3FWD_DEBUG) { printf ("MAC AFTER DST MAC %02x:%02x:%02x:%02x:%02x:%02x," "SRC MAC %02x:%02x:%02x:%02x:" "%02x:%02x\n", eth_dest[0], eth_dest[1], eth_dest[2], eth_dest[3], eth_dest[4], eth_dest[5], eth_src[0], eth_src[1], eth_src[2], eth_src[3], eth_src[4], eth_src[5]); } port_ptr[pos] = fib_path->l2_adj_ipv6_ptr->phy_port; //fib_path->l2_adj_ipv6_ptr->phy_port->transmit_single_pkt(fib_path->l2_adj_ipv6_ptr->phy_port, pkt); if (L3FWD_DEBUG) printf("Successfully sent to port %u \n\r", fib_path->out_port); } return 1; } void l3fwd_rx_ipv6_packets(struct rte_mbuf **m, uint16_t nb_pkts, uint64_t valid_pkts_mask, l2_phy_interface_t *port) { if (!port) return; if (L3FWD_DEBUG) { printf ("l3fwd_rx_ipv6_packets_received BEFORE DROP: nb_pkts: %u, from in_port %u, valid_pkts_mask:%" PRIu64 "\n", nb_pkts, port->pmdid, valid_pkts_mask); } uint64_t pkts_for_process = valid_pkts_mask; struct ipv6_hdr *ipv6_hdr; //struct ether_hdr *eth_h; uint64_t icmp_pkts_mask = valid_pkts_mask; uint64_t ipv6_forward_pkts_mask = valid_pkts_mask; uint16_t nb_icmpv6_pkt = 0; uint16_t nb_l3_pkt = 0; uint8_t configured_port_ipv6[RTE_LPM_IPV6_ADDR_SIZE] = { 0 }; int8_t solicited_node_multicast_addr[RTE_LPM_IPV6_ADDR_SIZE] = { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x00, 0x00, 0x00 }; uint8_t dest_ipv6_addr[RTE_LPM_IPV6_ADDR_SIZE]; memset(dest_ipv6_addr, 0, RTE_LPM_IPV6_ADDR_SIZE); printf("\n%s : LINE # %u\n", __FUNCTION__, __LINE__); int ii; if (port->ipv6_list != NULL) { for (ii = 0; ii < 16; ii += 1) { configured_port_ipv6[ii] = ((ipv6list_t *) (port->ipv6_list))->ipaddr[ii]; } } // memcpy(&configured_port_ipv6, &(((ipv6list_t*)(port->ipv6_list))->ipaddr), RTE_LPM_IPV6_ADDR_SIZE); for (ii = 0; ii < 16; ii += 2) { if (port && port->ipv6_list) printf("%02X%02X ", ((ipv6list_t *) (port->ipv6_list))->ipaddr[ii], ((ipv6list_t *) (port->ipv6_list))->ipaddr[ii + 1]); } printf("\n%s : LINE # %u\n", __FUNCTION__, __LINE__); for (ii = 0; ii < 16; ii += 2) { printf("%02X%02X ", configured_port_ipv6[ii], configured_port_ipv6[ii + 1]); } for (; pkts_for_process;) { /**< process only valid packets.*/ printf("\n%s : LINE # %u\n", __FUNCTION__, __LINE__); uint8_t pos = (uint8_t) __builtin_ctzll(pkts_for_process); uint64_t pkt_mask = 1LLU << pos; /**< bitmask representing only this packet */ pkts_for_process &= ~pkt_mask; /**< remove this packet from the mask */ //printf("\n%s : LINE # %u\n", __FUNCTION__, __LINE__); //eth_h = rte_pktmbuf_mtod(m[pos], struct ether_hdr *); printf("\n%s : LINE #%u, POS%u\n", __FUNCTION__, __LINE__, pos); //ipv6_hdr = (struct ipv6_hdr *)((char *)eth_h + sizeof(struct ether_hdr)); if (m[pos] == NULL) { printf("\n%s : M_POS IS NULLLLLLL, LINE: %u\n", __FUNCTION__, __LINE__); return; } ipv6_hdr = rte_pktmbuf_mtod_offset(m[pos], struct ipv6_hdr *, sizeof(struct ether_hdr)); printf("\n%s : LINE # %u\n", __FUNCTION__, __LINE__); for (ii = 0; ii < 13; ii += 1) { dest_ipv6_addr[ii] = ipv6_hdr->dst_addr[ii]; } printf("\n"); printf("\n%s : LINE # %u\n", __FUNCTION__, __LINE__); for (ii = 0; ii < 16; ii += 2) { printf("%02X%02X ", ipv6_hdr->dst_addr[ii], ipv6_hdr->dst_addr[ii + 1]); } printf("\n"); printf("\n%s : LINE # %u\n", __FUNCTION__, __LINE__); for (ii = 0; ii < 16; ii += 2) { printf("%02X%02X ", dest_ipv6_addr[ii], dest_ipv6_addr[ii + 1]); } printf("\n%s : LINE # %u", __FUNCTION__, __LINE__); if ((ipv6_hdr->proto == IPPROTO_ICMPV6) && (!memcmp (&ipv6_hdr->dst_addr, &configured_port_ipv6[0], RTE_LPM_IPV6_ADDR_SIZE) || !memcmp(&dest_ipv6_addr[0], &solicited_node_multicast_addr[0], RTE_LPM_IPV6_ADDR_SIZE))) { ipv6_forward_pkts_mask &= ~pkt_mask; /**< Its ICMP, remove this packet from the ipv6_forward_pkts_mask*/ stats.nb_rx_l3_icmp_pkt++; /**< Increment stats for ICMP PKT */ nb_icmpv6_pkt++; } else{ // Forward the packet icmp_pkts_mask &= ~pkt_mask; /**< Not ICMP, remove this packet from the icmp_pkts_mask*/ stats.nb_rx_l3_pkt++; nb_l3_pkt++; /**< Increment stats for L3 PKT */ } } if (icmp_pkts_mask) { if (L3FWD_DEBUG) printf ("\n RECEiVED LOCAL ICMP PKT at L3...\n PROCESSING ICMP LOCAL PKT...\n"); proto_type[IP_LOCAL]->func(m, nb_icmpv6_pkt, icmp_pkts_mask, port); } if (ipv6_forward_pkts_mask) { if (L3FWD_DEBUG) printf ("\n RECEIVED L3 PKT, \n\n FORWARDING L3 PKT....\n"); proto_type[IP_REMOTE]->func(m, nb_l3_pkt, ipv6_forward_pkts_mask, port); } } struct ipv6_fib_path *populate_ipv6_fib_path(uint8_t nh_ipv6[RTE_LPM_IPV6_ADDR_SIZE], uint8_t portid) { struct fib_path_key_ipv6 path_key; uint8_t i; for (i = 0; i < 16; i++) { path_key.nh_ipv6[i] = nh_ipv6[i]; } path_key.out_port = portid; path_key.filler1 = 0; path_key.filler2 = 0; path_key.filler3 = 0; struct ipv6_fib_path *fib_data = NULL; /* Populate fib_path if it is present in FIB_PATH cuckoo HAsh Table */ fib_data = retrieve_ipv6_fib_path_entry(path_key); if (fib_data) { printf(" Fib path entry exists for IPv6 destination = " "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:" "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x and out port :%u\n", nh_ipv6[0], nh_ipv6[1], nh_ipv6[2], nh_ipv6[3], nh_ipv6[4], nh_ipv6[5], nh_ipv6[6], nh_ipv6[7], nh_ipv6[8], nh_ipv6[9], nh_ipv6[10], nh_ipv6[11], nh_ipv6[12], nh_ipv6[13], nh_ipv6[14], nh_ipv6[15], portid); fib_data->refcount++; return fib_data; // Entry Exists. Return True (1) } else { printf("IPv6 fib_path entry Doesn't Exists.......\n"); } /* populate L2 Adj */ fib_data = NULL; struct l2_adj_ipv6_entry *l2_adj_ptr = NULL; l2_adj_ptr = populate_ipv6_l2_adj(nh_ipv6, portid); if (l2_adj_ptr) { uint32_t size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct ipv6_fib_path)); fib_data = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE); for (i = 0; i < 16; i++) { fib_data->nh_ipv6[i] = nh_ipv6[i]; } fib_data->out_port = portid; //memcpy(fib_data->nh_ipv6, &nh_ipv6, RTE_LPM_IPV6_ADDR_SIZE); fib_data->refcount++; fib_data->l2_adj_ipv6_ptr = l2_adj_ptr; /* Store the received MAC Address in L2 Adj HAsh Table */ rte_hash_add_key_data(fib_path_ipv6_hash_handle, &path_key, fib_data); printf (" ND resolution success l2_adj_entry %p\n, ipv6_fib_path_addr %p", l2_adj_ptr, fib_data); return fib_data; } else { printf ("ND resolution failed and unable to write fib path in fib_path cuckoo hash\n"); } return NULL; } struct l2_adj_ipv6_entry *populate_ipv6_l2_adj(uint8_t nh_ipv6[RTE_LPM_IPV6_ADDR_SIZE], uint8_t portid) { struct l2_adj_key_ipv6 l2_adj_key; uint8_t i; for (i = 0; i < 16; i++) { l2_adj_key.nh_ipv6[i] = nh_ipv6[i]; } l2_adj_key.out_port_id = portid; l2_adj_key.filler1 = 0; l2_adj_key.filler2 = 0; l2_adj_key.filler3 = 0; struct l2_adj_ipv6_entry *adj_data = NULL; struct ether_addr eth_dst; /* Populate L2 adj if the MAC Address is present in L2 Adj HAsh Table */ adj_data = retrieve_ipv6_l2_adj_entry(l2_adj_key); if (adj_data) { printf("ipv6_l2_adj_entry exists for Next Hop IPv6 = " "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:" "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x and out port :%u\n", nh_ipv6[0], nh_ipv6[1], nh_ipv6[2], nh_ipv6[3], nh_ipv6[4], nh_ipv6[5], nh_ipv6[6], nh_ipv6[7], nh_ipv6[8], nh_ipv6[9], nh_ipv6[10], nh_ipv6[11], nh_ipv6[12], nh_ipv6[13], nh_ipv6[14], nh_ipv6[15], portid); ether_addr_copy(&adj_data->eth_addr, ð_dst); adj_data->refcount++; return adj_data; // Entry Exists. Return True (1) } struct ether_addr eth_src; uint16_t ether_type = 0x086DD; l2_phy_interface_t *port; port = ifm_get_port(portid); if (port == NULL) { printf("PORT %u IS DOWN.. Unable to process !\n", portid); return NULL; } memcpy(ð_src, &port->macaddr, sizeof(struct ether_addr)); uint32_t size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct l2_adj_entry)); adj_data = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE); if (adj_data == NULL) { printf("L2 Adjacency memory allocation failed !\n"); return NULL; } adj_data->out_port_id = portid; //memcpy(adj_data->nh_ipv6, &nh_ipv6, RTE_LPM_IPV6_ADDR_SIZE); for (i = 0; i < 16; i++) { adj_data->nh_ipv6[i] = nh_ipv6[i]; } adj_data->refcount++; adj_data->phy_port = port; rte_hash_add_key_data(l2_adj_ipv6_hash_handle, &l2_adj_key, adj_data); /* Query ND to get L2 Adj */ if (get_dest_mac_for_nexthop_ipv6(nh_ipv6, portid, ð_dst)) { /* Store the received MAC Address in L2 Adj HAsh Table */ ether_addr_copy(ð_dst, &adj_data->eth_addr); /* Precompute the L2 string encapsulation */ memcpy(&adj_data->l2_string, ð_dst, sizeof(struct ether_addr)); memcpy(&adj_data->l2_string[6], ð_src, sizeof(struct ether_addr)); memcpy(&adj_data->l2_string[12], ðer_type, 2); adj_data->flags = L2_ADJ_RESOLVED; printf (" ND resolution successful and stored in ipv6_l2_adj_entry %p\n", adj_data); return adj_data; } else { adj_data->flags = L2_ADJ_UNRESOLVED; printf ("ND resolution failed and unable to write in ipv6_l2_adj_entry\n"); } return NULL; } struct l2_adj_ipv6_entry *retrieve_ipv6_l2_adj_entry(struct l2_adj_key_ipv6 l2_adj_key) { struct l2_adj_ipv6_entry *ret_l2_adj_data = NULL; int ret = rte_hash_lookup_data(l2_adj_ipv6_hash_handle, &l2_adj_key, (void **)&ret_l2_adj_data); if (ret < 0) { printf ("L2 Adj hash lookup failed ret %d, EINVAL %d, ENOENT %d\n", ret, EINVAL, ENOENT); } else { printf("L2 Adj hash lookup Successful..!!!\n"); return ret_l2_adj_data; } return NULL; } int get_dest_mac_for_nexthop_ipv6(uint8_t nh_ipv6[RTE_LPM_IPV6_ADDR_SIZE], uint32_t out_phy_port, struct ether_addr *hw_addr) { struct nd_entry_data *nd_data = NULL; struct nd_key_ipv6 tmp_nd_key; uint8_t i; for (i = 0; i < 16; i++) { tmp_nd_key.ipv6[i] = nh_ipv6[i]; } tmp_nd_key.port_id = out_phy_port; nd_data = retrieve_nd_entry(tmp_nd_key, DYNAMIC_ND); if (nd_data == NULL) { printf("ND entry is not found\n"); return 0; } ether_addr_copy(&nd_data->eth_addr, hw_addr); return 1; } struct ipv6_fib_path *retrieve_ipv6_fib_path_entry(struct fib_path_key_ipv6 path_key) { struct ipv6_fib_path *ret_fib_path_data = NULL; int ret = rte_hash_lookup_data(fib_path_ipv6_hash_handle, &path_key, (void **)&ret_fib_path_data); if (ret < 0) { printf ("FIB Path Adj hash lookup failed ret %d, EINVAL %d, ENOENT %d\n", ret, EINVAL, ENOENT); return NULL; } else { return ret_fib_path_data; } } void remove_ipv6_fib_l2_adj_entry(void *entry) { struct ipv6_fib_info entry1; memcpy(&entry1, entry, sizeof(struct ipv6_fib_info)); struct ipv6_fib_path *fib_path_addr = entry1.path[0]; //fib_info->path[0]; if (fib_path_addr->refcount > 1) { printf("BEFORE fib_path entry is not Removed! nh_iPv6 = " "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:" "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x and out port :%u, refcount :%d\n", fib_path_addr->nh_ipv6[0], fib_path_addr->nh_ipv6[1], fib_path_addr->nh_ipv6[2], fib_path_addr->nh_ipv6[3], fib_path_addr->nh_ipv6[4], fib_path_addr->nh_ipv6[5], fib_path_addr->nh_ipv6[6], fib_path_addr->nh_ipv6[7], fib_path_addr->nh_ipv6[8], fib_path_addr->nh_ipv6[9], fib_path_addr->nh_ipv6[10], fib_path_addr->nh_ipv6[11], fib_path_addr->nh_ipv6[12], fib_path_addr->nh_ipv6[13], fib_path_addr->nh_ipv6[14], fib_path_addr->nh_ipv6[15], fib_path_addr->out_port, fib_path_addr->refcount); fib_path_addr->refcount--; // Just decrement the refcount this entry is still referred printf("AFTER fib_path entry is not Removed! nh_iPv6 = " "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:" "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x and out port :%u, refcount :%d\n", fib_path_addr->nh_ipv6[0], fib_path_addr->nh_ipv6[1], fib_path_addr->nh_ipv6[2], fib_path_addr->nh_ipv6[3], fib_path_addr->nh_ipv6[4], fib_path_addr->nh_ipv6[5], fib_path_addr->nh_ipv6[6], fib_path_addr->nh_ipv6[7], fib_path_addr->nh_ipv6[8], fib_path_addr->nh_ipv6[9], fib_path_addr->nh_ipv6[10], fib_path_addr->nh_ipv6[11], fib_path_addr->nh_ipv6[12], fib_path_addr->nh_ipv6[13], fib_path_addr->nh_ipv6[14], fib_path_addr->nh_ipv6[15], fib_path_addr->out_port, fib_path_addr->refcount); } else { // Refcount is 1 so delete both fib_path and l2_adj_entry struct l2_adj_ipv6_entry *adj_addr = NULL; adj_addr = fib_path_addr->l2_adj_ipv6_ptr; if (adj_addr != NULL) { //l2_adj_entry is has some entry in hash table printf("%s: CHECK %d\n\r", __FUNCTION__, __LINE__); struct l2_adj_key_ipv6 l2_adj_key; memcpy(&l2_adj_key.nh_ipv6, fib_path_addr->nh_ipv6, RTE_LPM_IPV6_ADDR_SIZE); l2_adj_key.out_port_id = fib_path_addr->out_port, rte_hash_del_key(l2_adj_ipv6_hash_handle, &l2_adj_key); rte_free(adj_addr); // free memory adj_addr = NULL; } struct fib_path_key_ipv6 path_key; memcpy(&path_key.nh_ipv6, fib_path_addr->nh_ipv6, RTE_LPM_IPV6_ADDR_SIZE); path_key.out_port = fib_path_addr->out_port; rte_hash_del_key(fib_path_ipv6_hash_handle, &path_key); rte_free(fib_path_addr); //Free the memory fib_path_addr = NULL; } } int is_valid_ipv6_pkt(struct ipv6_hdr *pkt, uint32_t link_len) { if (link_len < sizeof(struct ipv4_hdr)) return -1; if (rte_cpu_to_be_16(pkt->payload_len) < sizeof(struct ipv6_hdr)) return -1; return 0; } void ipv6_l3_protocol_type_add(uint8_t protocol_type, void (*func) (struct rte_mbuf **, uint16_t, uint64_t, l2_phy_interface_t *)) { switch (protocol_type) { case IPPROTO_ICMPV6: proto_type[IP_LOCAL] = rte_malloc(NULL, sizeof(struct ip_protocol_type), RTE_CACHE_LINE_SIZE); proto_type[IP_LOCAL]->protocol_type = protocol_type; proto_type[IP_LOCAL]->func = func; break; case IPPROTO_TCP: // Time being treared as Remote forwarding case IPPROTO_UDP: proto_type[IP_REMOTE] = rte_malloc(NULL, sizeof(struct ip_protocol_type), RTE_CACHE_LINE_SIZE); proto_type[IP_REMOTE]->protocol_type = protocol_type; proto_type[IP_REMOTE]->func = func; break; } } void ipv6_local_deliver(struct rte_mbuf **pkt_burst, __rte_unused uint16_t nb_rx, uint64_t icmp_pkt_mask, l2_phy_interface_t *port) { for (; icmp_pkt_mask;) { /**< process only valid packets.*/ uint8_t pos = (uint8_t) __builtin_ctzll(icmp_pkt_mask); uint64_t pkt_mask = 1LLU << pos; /**< bitmask representing only this packet */ icmp_pkt_mask &= ~pkt_mask; /**< remove this packet from the mask */ process_icmpv6_pkt(pkt_burst[pos], port); } } void ipv6_forward_deliver(struct rte_mbuf **pkt_burst, uint16_t nb_pkts, uint64_t ipv6_forward_pkts_mask, l2_phy_interface_t *port) { if (L3FWD_DEBUG) { printf ("ip_forward_deliver BEFORE DROP: nb_pkts: %u\n from in_port %u", nb_pkts, port->pmdid); } uint64_t pkts_for_process = ipv6_forward_pkts_mask; struct ipv6_hdr *ipv6_hdr; l2_phy_interface_t *port_ptr[RTE_PORT_IN_BURST_SIZE_MAX]; uint64_t hit_mask = 0; for (; pkts_for_process;) { /**< process only valid packets.*/ uint8_t pos = (uint8_t) __builtin_ctzll(pkts_for_process); uint64_t pkt_mask = 1LLU << pos; /**< bitmask representing only this packet */ pkts_for_process &= ~pkt_mask; /**< remove this packet from the mask */ ipv6_hdr = rte_pktmbuf_mtod_offset(pkt_burst[pos], struct ipv6_hdr *, sizeof(struct ether_hdr)); /* Make sure the IPv4 packet is valid */ if (is_valid_ipv6_pkt(ipv6_hdr, pkt_burst[pos]->pkt_len) < 0) { rte_pktmbuf_free(pkt_burst[pos]); /**< Drop the Unknown IPv4 Packet */ pkt_burst[pos] = NULL; ipv6_forward_pkts_mask &= ~(1LLU << pos); /**< That will clear bit of that position*/ nb_pkts--; stats.nb_l3_drop_pkt++; } } if (L3FWD_DEBUG) { printf ("\nl3fwd_rx_ipv4_packets_received AFTER DROP: nb_pkts: %u, valid_Pkts_mask :%lu\n", nb_pkts, ipv6_forward_pkts_mask); } /* Lookup for IP destination in LPMv4 table */ lpm6_table_lookup(pkt_burst, nb_pkts, ipv6_forward_pkts_mask, port_ptr, &hit_mask); } uint8_t ipv6_hash_load_balance(struct rte_mbuf *mbuf) { uint32_t src_addr_offset = MBUF_HDR_ROOM + ETH_HDR_SIZE + IP_HDR_SRC_ADR_OFST_IPV6; uint32_t dst_addr_offset = MBUF_HDR_ROOM + ETH_HDR_SIZE + IP_HDR_DST_ADR_OFST_IPV6; uint8_t src_addr[RTE_LPM_IPV6_ADDR_SIZE]; uint8_t dst_addr[RTE_LPM_IPV6_ADDR_SIZE]; memcpy(&src_addr, (uint8_t *) RTE_MBUF_METADATA_UINT32_PTR(mbuf, src_addr_offset), RTE_LPM_IPV6_ADDR_SIZE); memcpy(&dst_addr, (uint8_t *) RTE_MBUF_METADATA_UINT32_PTR(mbuf, dst_addr_offset), RTE_LPM_IPV6_ADDR_SIZE); uint32_t hash_key1 = 0; /* STORE Accumulated value of SRC IP in key1 variable */ uint32_t hash_key2 = 0; /* STORE Accumulated value of DST IP in key2 variable */ uint8_t i; for (i = 0; i < RTE_LPM_IPV6_ADDR_SIZE; i++) { hash_key1 += src_addr[i]; /* Accumulate */ hash_key2 += dst_addr[i]; /* Accumulate */ } hash_key1 = hash_key1 ^ hash_key2; /* XOR With SRC and DST IP, Result is hask_key1 */ hash_key2 = hash_key1; /* MOVE The result to hask_key2 */ hash_key1 = rotr32(hash_key1, RTE_LPM_IPV6_ADDR_SIZE); /* Circular Rotate to 16 bit */ hash_key1 = hash_key1 ^ hash_key2; /* XOR With Key1 with Key2 */ hash_key2 = hash_key1; /* MOVE The result to hask_key2 */ hash_key1 = rotr32(hash_key1, 8); /* Circular Rotate to 8 bit */ hash_key1 = hash_key1 ^ hash_key2; /* XOR With Key1 with Key2 */ hash_key1 = hash_key1 & (HASH_BUCKET_SIZE - 1); /* MASK the KEY with BUCKET SIZE */ if (L3FWD_DEBUG) printf("Hash Result_key: %d, \n", hash_key1); return hash_key1; } void resolve_ipv6_l2_adj(uint8_t nh_ipv6[RTE_LPM_IPV6_ADDR_SIZE], uint8_t portid, struct ether_addr *hw_addr) { struct l2_adj_ipv6_entry *adj_data = NULL; struct ether_addr eth_dst; uint16_t ether_type = 0x086DD; struct l2_adj_key_ipv6 l2_adj_key; memcpy(&l2_adj_key.nh_ipv6, &nh_ipv6, RTE_LPM_IPV6_ADDR_SIZE); l2_adj_key.out_port_id = portid; adj_data = retrieve_ipv6_l2_adj_entry(l2_adj_key); if (adj_data) { if (adj_data->flags == L2_ADJ_UNRESOLVED || memcmp(&adj_data->eth_addr, hw_addr, 6)) { ether_addr_copy(hw_addr, &adj_data->eth_addr); /* Precompute the L2 string encapsulation */ memcpy(&adj_data->l2_string, hw_addr, sizeof(struct ether_addr)); memcpy(&adj_data->l2_string[6], &adj_data->phy_port->macaddr, sizeof(struct ether_addr)); memcpy(&adj_data->l2_string[12], ðer_type, 2); adj_data->flags = L2_ADJ_RESOLVED; } return; } l2_phy_interface_t *port; port = ifm_get_port(portid); if (port == NULL) { printf("PORT %u IS DOWN..! Unable to Process\n", portid); return; } uint32_t size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct l2_adj_entry)); adj_data = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE); if (adj_data == NULL) { printf("L2 Adjacency memory allocation failed !\n"); return; } adj_data->out_port_id = portid; memcpy(adj_data->nh_ipv6, &nh_ipv6, RTE_LPM_IPV6_ADDR_SIZE); adj_data->phy_port = port; ether_addr_copy(ð_dst, &adj_data->eth_addr); /* Precompute the L2 string encapsulation */ memcpy(&adj_data->l2_string, hw_addr, sizeof(struct ether_addr)); memcpy(&adj_data->l2_string[6], &port->macaddr, sizeof(struct ether_addr)); memcpy(&adj_data->l2_string[12], ðer_type, 2); adj_data->flags = L2_ADJ_RESOLVED; /* Store the received MAC Address in L2 Adj HAsh Table */ rte_hash_add_key_data(l2_adj_ipv6_hash_handle, &l2_adj_key, adj_data); printf(" ND resolution successful and stored in ipv6_l2_adj_entry %p\n", adj_data); } void ipv6_iterate__hash_table(void) { const void *next_key; void *next_data; uint32_t iter = 0; uint8_t ii; printf("\n\t\t\t IPv6 FIB_path Cache table...."); printf ("\n------------------------------------------------------------------------------"); printf ("\n\tNextHop IP \t\t\t\t Port Refcount l2_adj_ptr_addrress\n\n"); printf ("--------------------------------------------------------------------------------\n"); while (rte_hash_iterate (fib_path_ipv6_hash_handle, &next_key, &next_data, &iter) >= 0) { struct ipv6_fib_path *tmp_data = (struct ipv6_fib_path *)next_data; struct fib_path_key_ipv6 tmp_key; memcpy(&tmp_key, next_key, sizeof(tmp_key)); for (ii = 0; ii < 16; ii += 2) { printf("%02X%02X ", tmp_data->nh_ipv6[ii], tmp_data->nh_ipv6[ii + 1]); } printf(" \t %u \t %u \t %p\n", tmp_data->out_port, tmp_data->refcount, tmp_data->l2_adj_ipv6_ptr); } iter = 0; printf("\n\t\t\t L2 ADJ Cache table....."); printf ("\n----------------------------------------------------------------------------------\n"); printf ("\tNextHop IP \t\t\t\t Port \t l2 Encap string \t l2_Phy_interface\n"); printf ("\n------------------------------------------------------------------------------------\n"); while (rte_hash_iterate (l2_adj_ipv6_hash_handle, &next_key, &next_data, &iter) >= 0) { struct l2_adj_ipv6_entry *l2_data = (struct l2_adj_ipv6_entry *)next_data; struct l2_adj_key_ipv6 l2_key; memcpy(&l2_key, next_key, sizeof(l2_key)); for (ii = 0; ii < 16; ii += 2) { printf("%02X%02X ", l2_data->nh_ipv6[ii], l2_data->nh_ipv6[ii + 1]); } printf(" \t%u\t%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x\t%p\n", l2_data->out_port_id, l2_data->l2_string[0], l2_data->l2_string[1], l2_data->l2_string[2], l2_data->l2_string[3], l2_data->l2_string[4], l2_data->l2_string[5], l2_data->l2_string[6], l2_data->l2_string[7], l2_data->l2_string[8], l2_data->l2_string[9], l2_data->l2_string[10], l2_data->l2_string[11], l2_data->phy_port); } }