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