Support packets in flight
[samplevnf.git] / common / VIL / l2l3_stack / l3fwd_lpm6.c
1 /*
2 // Copyright (c) 2017 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16
17 #include "l3fwd_common.h"
18 #include "l3fwd_lpm4.h"
19 #include "l3fwd_lpm6.h"
20 #include "l3fwd_common.h"
21 #include "interface.h"
22 #include "l2_proto.h"
23 #include "lib_arp.h"
24 #include "lib_icmpv6.h"
25
26 /* Declare Global variables */
27
28 /* Global for IPV6 */
29 void *lpm6_table; /**< lpm6 table handler */
30 struct rte_hash *l2_adj_ipv6_hash_handle;  /**< IPv6 l2 adjacency table handler */
31 struct rte_hash *fib_path_ipv6_hash_handle;  /**< IPv6 fib path hash table handler */
32 extern uint8_t nh_links[MAX_SUPPORTED_FIB_PATHS][HASH_BUCKET_SIZE];
33 extern l3_stats_t stats; /**< L3 statistics */
34
35 static struct ipv6_protocol_type *proto_type[2];
36
37 int lpm6_init(void)
38 {
39
40         /* Initiliaze LPMv6 params */
41
42         struct rte_table_lpm_ipv6_params lpm6_params = {
43                 .name = "LPMv6",
44                 .n_rules = IPV6_L3FWD_LPM_MAX_RULES,
45                 .number_tbl8s = IPV6_L3FWD_LPM_NUMBER_TBL8S,
46                 .entry_unique_size = sizeof(struct ipv6_fib_info),
47                 .offset = 128,
48         };
49
50         /* Create LPMv6 tables */
51         lpm6_table =
52                         rte_table_lpm_ipv6_ops.f_create(&lpm6_params, rte_socket_id(),
53                                                         sizeof(struct ipv6_fib_info));
54         if (lpm6_table == NULL) {
55                 printf("Failed to create LPM IPV6 table\n");
56                 return 0;
57         }
58
59         /*Initialize IPv6 params for l2 Adj  */
60         struct rte_hash_parameters l2_adj_ipv6_params = {
61                 .name = "l2_ADJ_IPV6_HASH",
62                 .entries = 64,
63                 .key_len = sizeof(struct l2_adj_key_ipv6),
64                 .hash_func = rte_jhash,
65                 .hash_func_init_val = 0,
66         };
67
68         l2_adj_ipv6_hash_handle = rte_hash_create(&l2_adj_ipv6_params);
69         if (l2_adj_ipv6_hash_handle == NULL) {
70                 printf("ND for IPV6 rte_hash_create failed.\n");
71                 return 0;
72         } else {
73                 printf("ND IPV6_hash_handle %p\n\n",
74                                          (void *)l2_adj_ipv6_hash_handle);
75         }
76
77         /*Initialize Fib PAth hassh params  */
78         struct rte_hash_parameters fib_path_ipv6_params = {
79                 .name = "FIB_PATH_IPV6_HASH",
80                 .entries = 64,
81                 .key_len = sizeof(struct fib_path_key_ipv6),
82                 .hash_func = rte_jhash,
83                 .hash_func_init_val = 0,
84                 .extra_flag = 1,
85         };
86
87         /* Create FIB PATH Hash tables */
88         fib_path_ipv6_hash_handle = rte_hash_create(&fib_path_ipv6_params);
89
90         if (fib_path_ipv6_hash_handle == NULL) {
91                 printf("FIB path rte_hash_create failed\n");
92                 return 0;
93         }
94         return 1;
95 }
96
97 int lpm6_table_route_add(struct ipv6_routing_info *data)
98 {
99
100         struct ipv6_routing_info *fib = data;
101         /* Populate the Key */
102         struct rte_table_lpm_ipv6_key lpm6_key;
103         uint8_t i;
104         for (i = 0; i < 16; i++) {
105                 lpm6_key.ip[i] = fib->dst_ipv6[i];
106         }
107         lpm6_key.depth = fib->depth;
108
109         static int Total_route_count;
110         struct ipv6_fib_info entry;
111         for (i = 0; i < 16; i++) {
112                 entry.dst_ipv6[i] = fib->dst_ipv6[i];
113         }
114         entry.depth = fib->depth;
115         entry.fib_nh_size = fib->fib_nh_size;
116
117 #if MULTIPATH_FEAT
118         if (entry.fib_nh_size == 0 || entry.fib_nh_size > MAX_FIB_PATHS)
119 #else
120         if (entry.fib_nh_size != 1)     /**< For Single FIB_PATH */
121 #endif
122         {
123                 printf
124                                 ("Route's can't be configured!!, entry.fib_nh_size = %d\n",
125                                  entry.fib_nh_size);
126                 return 0;
127         }
128
129         /* Populate L2 adj and precomputes l2 encap string */
130 #if MULTIPATH_FEAT
131         for (i = 0; i < entry.fib_nh_size; i++)
132 #else
133         for (i = 0; i < 1; i++)
134 #endif
135         {
136                 struct ipv6_fib_path *ipv6_fib_path_addr = NULL;
137                 ipv6_fib_path_addr =
138                                 populate_ipv6_fib_path(fib->nh_ipv6[i], fib->out_port[i]);
139
140                 if (ipv6_fib_path_addr) {
141                         entry.path[i] = ipv6_fib_path_addr;
142                         printf("Fib path for IPv6 destination = "
143                                                  "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:"
144                                                  "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x/%u) ==> fib_path Addr :%p, L2_adj Addr ;%p\n",
145                                                  lpm6_key.ip[0], lpm6_key.ip[1], lpm6_key.ip[2],
146                                                  lpm6_key.ip[3], lpm6_key.ip[4], lpm6_key.ip[5],
147                                                  lpm6_key.ip[6], lpm6_key.ip[7], lpm6_key.ip[8],
148                                                  lpm6_key.ip[9], lpm6_key.ip[10], lpm6_key.ip[11],
149                                                  lpm6_key.ip[12], lpm6_key.ip[13],
150                                                  lpm6_key.ip[14], lpm6_key.ip[15], fib->depth,
151                                                  ipv6_fib_path_addr,
152                                                  (void *)entry.path[i]->l2_adj_ipv6_ptr);
153                 } else {
154                         printf("Fib path for IPv6 destination = "
155                                                  "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:"
156                                                  "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x/%u) ==> fib_path Addr : NULL\n",
157                                                  lpm6_key.ip[0], lpm6_key.ip[1], lpm6_key.ip[2],
158                                                  lpm6_key.ip[3], lpm6_key.ip[4], lpm6_key.ip[5],
159                                                  lpm6_key.ip[6], lpm6_key.ip[7], lpm6_key.ip[8],
160                                                  lpm6_key.ip[9], lpm6_key.ip[10], lpm6_key.ip[11],
161                                                  lpm6_key.ip[12], lpm6_key.ip[13],
162                                                  lpm6_key.ip[14], lpm6_key.ip[15], fib->depth);
163                         entry.path[i] = NULL;   /**< setting all other fib_paths to NULL */
164                 }
165         }
166
167         int key_found, ret;
168         void *entry_ptr;
169
170         /* Adding a IP route in LPMv6 table */
171         printf("%s, Line %u \n", __FUNCTION__, __LINE__);
172
173         ret =
174                         rte_table_lpm_ipv6_ops.f_add(lpm6_table, (void *)&lpm6_key, &entry,
175                                          &key_found, &entry_ptr);
176         printf("%s, Line %u \n", __FUNCTION__, __LINE__);
177
178         if (ret) {
179                 printf("Failed to Add IP route in LPMv6\n");
180                 return 0;
181         }
182         printf("Added route to IPv6 LPM table (IPv6 destination = "
183                                  "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:"
184                                  "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x/%u)\n",
185                                  lpm6_key.ip[0], lpm6_key.ip[1], lpm6_key.ip[2], lpm6_key.ip[3],
186                                  lpm6_key.ip[4], lpm6_key.ip[5], lpm6_key.ip[6], lpm6_key.ip[7],
187                                  lpm6_key.ip[8], lpm6_key.ip[9], lpm6_key.ip[10], lpm6_key.ip[11],
188                                  lpm6_key.ip[12], lpm6_key.ip[13], lpm6_key.ip[14],
189                                  lpm6_key.ip[15], fib->depth);
190
191         Total_route_count++;
192         printf("Total Routed Added : %u, Key_found: %d\n", Total_route_count,
193                                  key_found);
194
195         if (Total_route_count == 2)
196                 ipv6_iterate__hash_table();
197
198         return 1;
199 }
200
201 int
202 lpm6_table_route_delete(uint8_t dst_ipv6[RTE_LPM_IPV6_ADDR_SIZE], uint8_t depth)
203 {
204
205         /* Populate the Key */
206         struct rte_table_lpm_ipv6_key lpm6_key;
207         memcpy(&lpm6_key.ip, &dst_ipv6, sizeof(RTE_LPM_IPV6_ADDR_SIZE));
208         lpm6_key.depth = depth;
209         int key_found, ret;
210         char *entry = NULL;
211         entry = rte_zmalloc(NULL, 512, RTE_CACHE_LINE_SIZE);
212         /* Delete a IP route in LPMv6 table */
213         ret =
214                         rte_table_lpm_ipv6_ops.f_delete(lpm6_table, &lpm6_key, &key_found,
215                                                         entry);
216
217         if (ret) {
218                 printf("Failed to Delete IP route from LPMv6 table\n");
219                 return 0;
220         }
221
222         printf("Deleted route from IPv6 LPM table (IPv6 destination = "
223                                  "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:"
224                                  "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x/%u, key_found = %d\n",
225                                  lpm6_key.ip[0], lpm6_key.ip[1], lpm6_key.ip[2], lpm6_key.ip[3],
226                                  lpm6_key.ip[4], lpm6_key.ip[5], lpm6_key.ip[6], lpm6_key.ip[7],
227                                  lpm6_key.ip[8], lpm6_key.ip[9], lpm6_key.ip[10], lpm6_key.ip[11],
228                                  lpm6_key.ip[12], lpm6_key.ip[13], lpm6_key.ip[14],
229                                  lpm6_key.ip[15], lpm6_key.depth, key_found);
230
231         /* Deleting a L2 Adj entry if refcount is 1, Else decrement Refcount */
232         remove_ipv6_fib_l2_adj_entry(entry);
233         rte_free(entry);        // free memory
234         return 1;
235 }
236
237 int
238 lpm6_table_lookup(struct rte_mbuf **pkts_burst,
239                         uint16_t nb_pkts,
240                         uint64_t pkts_mask,
241                         l2_phy_interface_t *port_ptr[RTE_PORT_IN_BURST_SIZE_MAX],
242                         uint64_t *hit_mask)
243 {
244         struct ipv6_routing_table_entry
245                         *ipv6_entries[RTE_PORT_IN_BURST_SIZE_MAX];
246         uint64_t lookup_hit_mask_ipv6 = 0;
247         int status;
248         uint64_t lookup_miss_mask = pkts_mask;
249         /*Populate the key offset in META DATA */
250         uint32_t dst_addr_offset =
251                         MBUF_HDR_ROOM + ETH_HDR_SIZE + IP_HDR_DST_ADR_OFST_IPV6;
252         uint64_t pkts_key_mask = pkts_mask;
253
254         //for(i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++)
255         for (; pkts_key_mask;) {
256 /**< Populate key offset in META DATA for all valid pkts */
257                 uint8_t pos = (uint8_t) __builtin_ctzll(pkts_key_mask);
258                 uint64_t pkt_mask = 1LLU << pos;
259                 pkts_key_mask &= ~pkt_mask;
260
261                 uint8_t *lpm6_key;
262                 uint8_t dst_addr[RTE_LPM_IPV6_ADDR_SIZE];
263                 memcpy(dst_addr,
264                                          (uint8_t *) RTE_MBUF_METADATA_UINT32_PTR(pkts_burst[pos],
265                                                                 dst_addr_offset),
266                                          RTE_LPM_IPV6_ADDR_SIZE);
267                 lpm6_key =
268                                 (uint8_t *) RTE_MBUF_METADATA_UINT8_PTR(pkts_burst[pos],
269                                                                         128);
270                 memcpy(lpm6_key, dst_addr, RTE_LPM_IPV6_ADDR_SIZE);
271         }
272         /* Lookup for IP route in LPM6 table */
273         printf(" IPV6 Lookup Mask Before = %p, nb_pkts :%u\n",
274                                  (void *)pkts_mask, nb_pkts);
275         status =
276                         rte_table_lpm_ops.f_lookup(lpm6_table, pkts_burst, pkts_mask,
277                                                          &lookup_hit_mask_ipv6,
278                                                          (void **)ipv6_entries);
279         if (status) {
280                 printf("LPM Lookup failed for IP route\n");
281                 return 0;
282         }
283         printf(" IPV6 Lookup Mask After = %p\n", (void *)lookup_hit_mask_ipv6);
284         lookup_miss_mask = lookup_miss_mask & (~lookup_hit_mask_ipv6);
285         if (L3FWD_DEBUG) {
286                 printf("AFTER lookup_hit_mask = %p, lookup_miss_mask =%p\n",
287                                          (void *)lookup_hit_mask_ipv6, (void *)lookup_miss_mask);
288         }
289
290         for (; lookup_miss_mask;) {
291 /**< Drop packets for lookup_miss_mask */
292                 uint8_t pos = (uint8_t) __builtin_ctzll(lookup_miss_mask);
293                 uint64_t pkt_mask = 1LLU << pos;
294                 lookup_miss_mask &= ~pkt_mask;
295                 rte_pktmbuf_free(pkts_burst[pos]);
296                 pkts_burst[pos] = NULL;
297                 if (L3FWD_DEBUG)
298                         printf("\n DROP PKT IPV4 Lookup_miss_Mask  = %p\n",
299                                                  (void *)lookup_miss_mask);
300
301         }
302         *hit_mask = lookup_hit_mask_ipv6;
303         for (; lookup_hit_mask_ipv6;) {
304                 uint8_t pos = (uint8_t) __builtin_ctzll(lookup_hit_mask_ipv6);
305                 uint64_t pkt_mask = 1LLU << pos;
306                 lookup_hit_mask_ipv6 &= ~pkt_mask;
307                 struct rte_mbuf *pkt = pkts_burst[pos];
308
309                 struct ipv6_fib_info *entry =
310                                 (struct ipv6_fib_info *)ipv6_entries[pos];
311
312 #if MULTIPATH_FEAT
313
314                 uint8_t ecmp_path = ipv6_hash_load_balance(pkts_burst[pos]);
315                 uint8_t selected_path = 0;
316                 struct ipv6_fib_path *fib_path = NULL;
317                 if (((entry->fib_nh_size != 0)
318                                  && (entry->fib_nh_size - 1) < MAX_SUPPORTED_FIB_PATHS)
319                                 && ((ecmp_path != 0) && (ecmp_path - 1) < HASH_BUCKET_SIZE))
320                         selected_path =
321                                         nh_links[entry->fib_nh_size - 1][ecmp_path - 1];
322                 if (selected_path < MAX_FIB_PATHS)
323                         fib_path = entry->path[selected_path];
324                 printf
325                                 ("Total supported Path :%u, Hashed ECMP Key : %u, selected Fib_path: %u\n",
326                                  entry->fib_nh_size, ecmp_path, selected_path);
327 #else
328                 struct ipv6_fib_path *fib_path = entry->path[0];
329 #endif
330                 if (fib_path == NULL) {
331                         printf("Fib_path is NULL, ND has not resolved\n");
332                         rte_pktmbuf_free(pkt);
333                         pkts_burst[pos] = NULL;
334                         stats.nb_l3_drop_pkt++;  /**< Peg the L3 Drop counter */
335                         *hit_mask &= ~pkt_mask; /**< Remove this pkt from port Mask */
336                         printf
337                                         ("Fib_path is NULL, ND has not resolved, DROPPED UNKNOWN PKT\n");
338                         continue;
339                 }
340
341                 if (fib_path->l2_adj_ipv6_ptr->flags == L2_ADJ_UNRESOLVED) {
342                         rte_pktmbuf_free(pkts_burst[pos]);
343                         pkts_burst[pos] = NULL;
344                         *hit_mask &= ~pkt_mask; /**< Remove this pkt from port Mask */
345                         if (L3FWD_DEBUG)
346                                 printf
347                                                 ("L2_ADJ_UNRESOLVED, DROPPED UNKNOWN PKT\n");
348                         continue;
349                 }
350
351                 uint8_t *eth_dest =
352                                 RTE_MBUF_METADATA_UINT8_PTR(pkt, MBUF_HDR_ROOM);
353                 uint8_t *eth_src =
354                                 RTE_MBUF_METADATA_UINT8_PTR(pkt, MBUF_HDR_ROOM + 6);
355                 if (L3FWD_DEBUG) {
356                         printf
357                                 ("MAC BEFORE- DST MAC %02x:%02x:%02x:%02x"
358                                  ":%02x:%02x, "
359                                  "SRC MAC %02x:%02x:%02x:%02x:"
360                                  "%02x:%02x \n",
361                                  eth_dest[0], eth_dest[1], eth_dest[2],
362                                  eth_dest[3],
363                                  eth_dest[4], eth_dest[5], eth_src[0],
364                                  eth_src[1],
365                                  eth_src[2], eth_src[3],
366                                  eth_src[4], eth_src[5]);
367                 }
368
369                 /* Rewrite the packet with L2 string  */
370                 memcpy(eth_dest, fib_path->l2_adj_ipv6_ptr->l2_string,
371                                          sizeof(struct ether_addr) * 2 + 2);
372
373                 if (L3FWD_DEBUG) {
374                         printf
375                                 ("MAC AFTER DST MAC %02x:%02x:%02x:%02x:%02x:%02x,"
376                                  "SRC MAC %02x:%02x:%02x:%02x:"
377                                  "%02x:%02x\n", eth_dest[0],
378                                  eth_dest[1], eth_dest[2], eth_dest[3],
379                                  eth_dest[4],
380                                  eth_dest[5], eth_src[0], eth_src[1],
381                                  eth_src[2],
382                                  eth_src[3], eth_src[4], eth_src[5]);
383                 }
384                 port_ptr[pos] = fib_path->l2_adj_ipv6_ptr->phy_port;
385
386                 //fib_path->l2_adj_ipv6_ptr->phy_port->transmit_single_pkt(fib_path->l2_adj_ipv6_ptr->phy_port, pkt);
387                 if (L3FWD_DEBUG)
388                         printf("Successfully sent to port %u \n\r",
389                                                  fib_path->out_port);
390         }
391         return 1;
392 }
393
394 void l3fwd_rx_ipv6_packets(struct rte_mbuf **m, uint16_t nb_pkts,
395                                  uint64_t valid_pkts_mask, l2_phy_interface_t *port)
396 {
397         if (!port)
398                 return;
399         if (L3FWD_DEBUG) {
400                 printf
401                                 ("l3fwd_rx_ipv6_packets_received BEFORE DROP: nb_pkts: %u, from in_port %u, valid_pkts_mask:%"
402                                  PRIu64 "\n", nb_pkts, port->pmdid, valid_pkts_mask);
403         }
404         uint64_t pkts_for_process = valid_pkts_mask;
405
406         struct ipv6_hdr *ipv6_hdr;
407         //struct ether_hdr *eth_h;
408         uint64_t icmp_pkts_mask = valid_pkts_mask;
409         uint64_t ipv6_forward_pkts_mask = valid_pkts_mask;
410         uint16_t nb_icmpv6_pkt = 0;
411         uint16_t nb_l3_pkt = 0;
412
413         uint8_t configured_port_ipv6[RTE_LPM_IPV6_ADDR_SIZE] = { 0 };
414         int8_t solicited_node_multicast_addr[RTE_LPM_IPV6_ADDR_SIZE] = {
415                 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
416                 0x01, 0xff, 0x00, 0x00, 0x00 };
417         uint8_t dest_ipv6_addr[RTE_LPM_IPV6_ADDR_SIZE];
418
419         memset(dest_ipv6_addr, 0, RTE_LPM_IPV6_ADDR_SIZE);
420
421         printf("\n%s : LINE # %u\n", __FUNCTION__, __LINE__);
422         int ii;
423         if (port->ipv6_list != NULL) {
424                 for (ii = 0; ii < 16; ii += 1) {
425                         configured_port_ipv6[ii] =
426                                         ((ipv6list_t *) (port->ipv6_list))->ipaddr[ii];
427                 }
428         }
429         //      memcpy(&configured_port_ipv6, &(((ipv6list_t*)(port->ipv6_list))->ipaddr), RTE_LPM_IPV6_ADDR_SIZE);
430
431         for (ii = 0; ii < 16; ii += 2) {
432                 if (port && port->ipv6_list)
433                         printf("%02X%02X ",
434                                                  ((ipv6list_t *) (port->ipv6_list))->ipaddr[ii],
435                                                  ((ipv6list_t *) (port->ipv6_list))->ipaddr[ii +
436                                                                                 1]);
437         }
438
439         printf("\n%s : LINE # %u\n", __FUNCTION__, __LINE__);
440         for (ii = 0; ii < 16; ii += 2) {
441                 printf("%02X%02X ", configured_port_ipv6[ii],
442                                          configured_port_ipv6[ii + 1]);
443         }
444
445         for (; pkts_for_process;) {
446 /**< process only valid packets.*/
447                 printf("\n%s : LINE # %u\n", __FUNCTION__, __LINE__);
448                 uint8_t pos = (uint8_t) __builtin_ctzll(pkts_for_process);
449                 uint64_t pkt_mask = 1LLU << pos;    /**< bitmask representing only this packet */
450                 pkts_for_process &= ~pkt_mask;                  /**< remove this packet from the mask */
451                 //printf("\n%s : LINE # %u\n", __FUNCTION__, __LINE__);
452                 //eth_h = rte_pktmbuf_mtod(m[pos], struct ether_hdr *);
453                 printf("\n%s : LINE #%u,  POS%u\n", __FUNCTION__, __LINE__,
454                                          pos);
455                 //ipv6_hdr = (struct ipv6_hdr *)((char *)eth_h + sizeof(struct ether_hdr));
456                 if (m[pos] == NULL) {
457                         printf("\n%s : M_POS IS NULLLLLLL, LINE: %u\n",
458                                                  __FUNCTION__, __LINE__);
459                         return;
460                 }
461                 ipv6_hdr =
462                                 rte_pktmbuf_mtod_offset(m[pos], struct ipv6_hdr *,
463                                                         sizeof(struct ether_hdr));
464                 printf("\n%s : LINE # %u\n", __FUNCTION__, __LINE__);
465                 for (ii = 0; ii < 13; ii += 1) {
466                         dest_ipv6_addr[ii] = ipv6_hdr->dst_addr[ii];
467                 }
468
469                 printf("\n");
470                 printf("\n%s : LINE # %u\n", __FUNCTION__, __LINE__);
471                 for (ii = 0; ii < 16; ii += 2) {
472                         printf("%02X%02X ", ipv6_hdr->dst_addr[ii],
473                                                  ipv6_hdr->dst_addr[ii + 1]);
474                 }
475                 printf("\n");
476                 printf("\n%s : LINE # %u\n", __FUNCTION__, __LINE__);
477                 for (ii = 0; ii < 16; ii += 2) {
478                         printf("%02X%02X ", dest_ipv6_addr[ii],
479                                                  dest_ipv6_addr[ii + 1]);
480                 }
481
482                 printf("\n%s : LINE # %u", __FUNCTION__, __LINE__);
483                 if ((ipv6_hdr->proto == IPPROTO_ICMPV6) &&
484                                 (!memcmp
485                                  (&ipv6_hdr->dst_addr, &configured_port_ipv6[0],
486                                         RTE_LPM_IPV6_ADDR_SIZE)
487                                  || !memcmp(&dest_ipv6_addr[0],
488                                 &solicited_node_multicast_addr[0],
489                                 RTE_LPM_IPV6_ADDR_SIZE))) {
490                         ipv6_forward_pkts_mask &= ~pkt_mask;  /**< Its  ICMP, remove this packet from the ipv6_forward_pkts_mask*/
491                         stats.nb_rx_l3_icmp_pkt++;   /**< Increment stats for ICMP PKT */
492                         nb_icmpv6_pkt++;
493                 } else{         // Forward the packet
494                         icmp_pkts_mask &= ~pkt_mask;   /**< Not ICMP, remove this packet from the icmp_pkts_mask*/
495                         stats.nb_rx_l3_pkt++;
496                         nb_l3_pkt++;     /**< Increment stats for L3 PKT */
497                 }
498         }
499
500         if (icmp_pkts_mask) {
501                 if (L3FWD_DEBUG)
502                         printf
503                                         ("\n RECEiVED LOCAL ICMP PKT at L3...\n PROCESSING ICMP LOCAL PKT...\n");
504                 proto_type[IP_LOCAL]->func(m, nb_icmpv6_pkt, icmp_pkts_mask,
505                                                  port);
506         }
507
508         if (ipv6_forward_pkts_mask) {
509                 if (L3FWD_DEBUG)
510                         printf
511                                         ("\n RECEIVED L3 PKT, \n\n FORWARDING L3 PKT....\n");
512                 proto_type[IP_REMOTE]->func(m, nb_l3_pkt,
513                                                         ipv6_forward_pkts_mask, port);
514         }
515 }
516
517 struct ipv6_fib_path *populate_ipv6_fib_path(uint8_t
518                                                          nh_ipv6[RTE_LPM_IPV6_ADDR_SIZE],
519                                                          uint8_t portid)
520 {
521
522         struct fib_path_key_ipv6 path_key;
523         uint8_t i;
524         for (i = 0; i < 16; i++) {
525                 path_key.nh_ipv6[i] = nh_ipv6[i];
526         }
527         path_key.out_port = portid;
528         path_key.filler1 = 0;
529         path_key.filler2 = 0;
530         path_key.filler3 = 0;
531
532         struct ipv6_fib_path *fib_data = NULL;
533         /* Populate fib_path if it is present in FIB_PATH cuckoo HAsh Table */
534         fib_data = retrieve_ipv6_fib_path_entry(path_key);
535
536         if (fib_data) {
537
538                 printf(" Fib path entry exists for IPv6 destination = "
539                                          "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:"
540                                          "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x and out port :%u\n",
541                                          nh_ipv6[0], nh_ipv6[1], nh_ipv6[2], nh_ipv6[3],
542                                          nh_ipv6[4], nh_ipv6[5], nh_ipv6[6], nh_ipv6[7],
543                                          nh_ipv6[8], nh_ipv6[9], nh_ipv6[10], nh_ipv6[11],
544                                          nh_ipv6[12], nh_ipv6[13], nh_ipv6[14], nh_ipv6[15],
545                                          portid);
546
547                 fib_data->refcount++;
548                 return fib_data;        // Entry Exists. Return True (1)
549         } else {
550                 printf("IPv6 fib_path entry Doesn't Exists.......\n");
551         }
552
553         /* populate L2 Adj */
554         fib_data = NULL;
555         struct l2_adj_ipv6_entry *l2_adj_ptr = NULL;
556         l2_adj_ptr = populate_ipv6_l2_adj(nh_ipv6, portid);
557
558         if (l2_adj_ptr) {
559
560                 uint32_t size =
561                                 RTE_CACHE_LINE_ROUNDUP(sizeof(struct ipv6_fib_path));
562                 fib_data = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
563
564                 for (i = 0; i < 16; i++) {
565                         fib_data->nh_ipv6[i] = nh_ipv6[i];
566                 }
567                 fib_data->out_port = portid;
568                 //memcpy(fib_data->nh_ipv6, &nh_ipv6, RTE_LPM_IPV6_ADDR_SIZE);
569
570                 fib_data->refcount++;
571                 fib_data->l2_adj_ipv6_ptr = l2_adj_ptr;
572
573                 /* Store the received MAC Address in L2 Adj HAsh Table */
574                 rte_hash_add_key_data(fib_path_ipv6_hash_handle, &path_key,
575                                                         fib_data);
576                 printf
577                                 (" ND resolution success l2_adj_entry %p\n, ipv6_fib_path_addr %p",
578                                  l2_adj_ptr, fib_data);
579                 return fib_data;
580         } else {
581                 printf
582                                 ("ND resolution failed and unable to write fib path in fib_path cuckoo hash\n");
583         }
584         return NULL;
585
586 }
587
588 struct l2_adj_ipv6_entry *populate_ipv6_l2_adj(uint8_t
589                                                                  nh_ipv6[RTE_LPM_IPV6_ADDR_SIZE],
590                                                                  uint8_t portid)
591 {
592
593         struct l2_adj_key_ipv6 l2_adj_key;
594         uint8_t i;
595         for (i = 0; i < 16; i++) {
596                 l2_adj_key.nh_ipv6[i] = nh_ipv6[i];
597         }
598         l2_adj_key.out_port_id = portid;
599         l2_adj_key.filler1 = 0;
600         l2_adj_key.filler2 = 0;
601         l2_adj_key.filler3 = 0;
602
603         struct l2_adj_ipv6_entry *adj_data = NULL;
604         struct ether_addr eth_dst;
605         /* Populate L2 adj if the MAC Address is present in L2 Adj HAsh Table */
606         adj_data = retrieve_ipv6_l2_adj_entry(l2_adj_key);
607
608         if (adj_data) {
609
610                 printf("ipv6_l2_adj_entry exists for Next Hop IPv6 = "
611                                          "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:"
612                                          "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x and out port :%u\n",
613                                          nh_ipv6[0], nh_ipv6[1], nh_ipv6[2], nh_ipv6[3],
614                                          nh_ipv6[4], nh_ipv6[5], nh_ipv6[6], nh_ipv6[7],
615                                          nh_ipv6[8], nh_ipv6[9], nh_ipv6[10], nh_ipv6[11],
616                                          nh_ipv6[12], nh_ipv6[13], nh_ipv6[14], nh_ipv6[15],
617                                          portid);
618
619                 ether_addr_copy(&adj_data->eth_addr, &eth_dst);
620                 adj_data->refcount++;
621                 return adj_data;        // Entry Exists. Return True (1)
622         }
623
624         struct ether_addr eth_src;
625         uint16_t ether_type = 0x086DD;
626         l2_phy_interface_t *port;
627         port = ifm_get_port(portid);
628         if (port == NULL) {
629                 printf("PORT %u IS DOWN.. Unable to process !\n", portid);
630                 return NULL;
631         }
632
633         memcpy(&eth_src, &port->macaddr, sizeof(struct ether_addr));
634         uint32_t size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct l2_adj_entry));
635         adj_data = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
636         if (adj_data == NULL) {
637                 printf("L2 Adjacency memory allocation failed !\n");
638                 return NULL;
639         }
640
641         adj_data->out_port_id = portid;
642         //memcpy(adj_data->nh_ipv6, &nh_ipv6, RTE_LPM_IPV6_ADDR_SIZE);
643         for (i = 0; i < 16; i++) {
644                 adj_data->nh_ipv6[i] = nh_ipv6[i];
645         }
646         adj_data->refcount++;
647         adj_data->phy_port = port;
648
649         rte_hash_add_key_data(l2_adj_ipv6_hash_handle, &l2_adj_key, adj_data);
650
651         /* Query ND to get L2 Adj */
652         if (get_dest_mac_for_nexthop_ipv6(nh_ipv6, portid, &eth_dst)) {
653                 /* Store the received MAC Address in L2 Adj HAsh Table */
654                 ether_addr_copy(&eth_dst, &adj_data->eth_addr);
655
656                 /* Precompute the L2 string encapsulation */
657                 memcpy(&adj_data->l2_string, &eth_dst,
658                                          sizeof(struct ether_addr));
659                 memcpy(&adj_data->l2_string[6], &eth_src,
660                                          sizeof(struct ether_addr));
661                 memcpy(&adj_data->l2_string[12], &ether_type, 2);
662
663                 adj_data->flags = L2_ADJ_RESOLVED;
664                 printf
665                                 (" ND resolution successful and stored in ipv6_l2_adj_entry %p\n",
666                                  adj_data);
667
668                 return adj_data;
669         } else {
670                 adj_data->flags = L2_ADJ_UNRESOLVED;
671                 printf
672                                 ("ND resolution failed and unable to write in ipv6_l2_adj_entry\n");
673         }
674         return NULL;
675 }
676
677 struct l2_adj_ipv6_entry *retrieve_ipv6_l2_adj_entry(struct l2_adj_key_ipv6
678                                                                  l2_adj_key)
679 {
680         struct l2_adj_ipv6_entry *ret_l2_adj_data = NULL;
681
682         int ret =
683                         rte_hash_lookup_data(l2_adj_ipv6_hash_handle, &l2_adj_key,
684                                  (void **)&ret_l2_adj_data);
685         if (ret < 0) {
686                 printf
687                                 ("L2 Adj hash lookup failed ret %d, EINVAL %d, ENOENT %d\n",
688                                  ret, EINVAL, ENOENT);
689         } else {
690                 printf("L2 Adj hash lookup Successful..!!!\n");
691                 return ret_l2_adj_data;
692         }
693         return NULL;
694 }
695
696 int get_dest_mac_for_nexthop_ipv6(uint8_t nh_ipv6[RTE_LPM_IPV6_ADDR_SIZE],
697                                         uint32_t out_phy_port,
698                                         struct ether_addr *hw_addr)
699 {
700         struct nd_entry_data *nd_data = NULL;
701         struct nd_key_ipv6 tmp_nd_key;
702         uint8_t i;
703         for (i = 0; i < 16; i++) {
704                 tmp_nd_key.ipv6[i] = nh_ipv6[i];
705         }
706         tmp_nd_key.port_id = out_phy_port;
707
708         nd_data = retrieve_nd_entry(tmp_nd_key, DYNAMIC_ND);
709         if (nd_data == NULL) {
710                 printf("ND entry is not found\n");
711                 return 0;
712         }
713         ether_addr_copy(&nd_data->eth_addr, hw_addr);
714
715         return 1;
716 }
717
718 struct ipv6_fib_path *retrieve_ipv6_fib_path_entry(struct fib_path_key_ipv6
719                                                          path_key)
720 {
721
722         struct ipv6_fib_path *ret_fib_path_data = NULL;
723         int ret =
724                         rte_hash_lookup_data(fib_path_ipv6_hash_handle, &path_key,
725                                  (void **)&ret_fib_path_data);
726         if (ret < 0) {
727                 printf
728                                 ("FIB Path Adj hash lookup failed ret %d, EINVAL %d, ENOENT %d\n",
729                                  ret, EINVAL, ENOENT);
730                 return NULL;
731         } else {
732                 return ret_fib_path_data;
733         }
734 }
735
736 void remove_ipv6_fib_l2_adj_entry(void *entry)
737 {
738         struct ipv6_fib_info entry1;
739         memcpy(&entry1, entry, sizeof(struct ipv6_fib_info));
740
741         struct ipv6_fib_path *fib_path_addr = entry1.path[0];   //fib_info->path[0];
742         if (fib_path_addr->refcount > 1) {
743                 printf("BEFORE fib_path entry is not Removed! nh_iPv6 = "
744                                          "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:"
745                                          "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x and out port :%u, refcount :%d\n",
746                                          fib_path_addr->nh_ipv6[0], fib_path_addr->nh_ipv6[1],
747                                          fib_path_addr->nh_ipv6[2], fib_path_addr->nh_ipv6[3],
748                                          fib_path_addr->nh_ipv6[4], fib_path_addr->nh_ipv6[5],
749                                          fib_path_addr->nh_ipv6[6], fib_path_addr->nh_ipv6[7],
750                                          fib_path_addr->nh_ipv6[8], fib_path_addr->nh_ipv6[9],
751                                          fib_path_addr->nh_ipv6[10], fib_path_addr->nh_ipv6[11],
752                                          fib_path_addr->nh_ipv6[12], fib_path_addr->nh_ipv6[13],
753                                          fib_path_addr->nh_ipv6[14], fib_path_addr->nh_ipv6[15],
754                                          fib_path_addr->out_port, fib_path_addr->refcount);
755                 fib_path_addr->refcount--;      // Just decrement the refcount this entry is still referred
756                 printf("AFTER fib_path entry is not Removed! nh_iPv6 = "
757                                          "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:"
758                                          "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x and out port :%u, refcount :%d\n",
759                                          fib_path_addr->nh_ipv6[0], fib_path_addr->nh_ipv6[1],
760                                          fib_path_addr->nh_ipv6[2], fib_path_addr->nh_ipv6[3],
761                                          fib_path_addr->nh_ipv6[4], fib_path_addr->nh_ipv6[5],
762                                          fib_path_addr->nh_ipv6[6], fib_path_addr->nh_ipv6[7],
763                                          fib_path_addr->nh_ipv6[8], fib_path_addr->nh_ipv6[9],
764                                          fib_path_addr->nh_ipv6[10], fib_path_addr->nh_ipv6[11],
765                                          fib_path_addr->nh_ipv6[12], fib_path_addr->nh_ipv6[13],
766                                          fib_path_addr->nh_ipv6[14], fib_path_addr->nh_ipv6[15],
767                                          fib_path_addr->out_port, fib_path_addr->refcount);
768         } else {                        // Refcount is 1 so delete both fib_path and l2_adj_entry
769
770                 struct l2_adj_ipv6_entry *adj_addr = NULL;
771                 adj_addr = fib_path_addr->l2_adj_ipv6_ptr;
772
773                 if (adj_addr != NULL) { //l2_adj_entry is has some entry in hash table
774                         printf("%s: CHECK   %d\n\r", __FUNCTION__, __LINE__);
775                         struct l2_adj_key_ipv6 l2_adj_key;
776                         memcpy(&l2_adj_key.nh_ipv6, fib_path_addr->nh_ipv6,
777                                                  RTE_LPM_IPV6_ADDR_SIZE);
778                         l2_adj_key.out_port_id =
779                                         fib_path_addr->out_port,
780                                         rte_hash_del_key(l2_adj_ipv6_hash_handle,
781                                                          &l2_adj_key);
782                         rte_free(adj_addr);     // free memory
783                         adj_addr = NULL;
784                 }
785
786                 struct fib_path_key_ipv6 path_key;
787                 memcpy(&path_key.nh_ipv6, fib_path_addr->nh_ipv6,
788                                          RTE_LPM_IPV6_ADDR_SIZE);
789                 path_key.out_port = fib_path_addr->out_port;
790                 rte_hash_del_key(fib_path_ipv6_hash_handle, &path_key);
791                 rte_free(fib_path_addr);        //Free the memory
792                 fib_path_addr = NULL;
793         }
794 }
795
796 int is_valid_ipv6_pkt(struct ipv6_hdr *pkt, uint32_t link_len)
797 {
798         if (link_len < sizeof(struct ipv4_hdr))
799                 return -1;
800         if (rte_cpu_to_be_16(pkt->payload_len) < sizeof(struct ipv6_hdr))
801                 return -1;
802
803         return 0;
804 }
805
806 void
807 ipv6_l3_protocol_type_add(uint8_t protocol_type,
808                                 void (*func) (struct rte_mbuf **, uint16_t, uint64_t,
809                                         l2_phy_interface_t *))
810 {
811         switch (protocol_type) {
812         case IPPROTO_ICMPV6:
813                 proto_type[IP_LOCAL] =
814                                 rte_malloc(NULL, sizeof(struct ip_protocol_type),
815                                                  RTE_CACHE_LINE_SIZE);
816                 proto_type[IP_LOCAL]->protocol_type = protocol_type;
817                 proto_type[IP_LOCAL]->func = func;
818                 break;
819
820         case IPPROTO_TCP:       // Time being treared as Remote forwarding
821         case IPPROTO_UDP:
822                 proto_type[IP_REMOTE] =
823                                 rte_malloc(NULL, sizeof(struct ip_protocol_type),
824                                                  RTE_CACHE_LINE_SIZE);
825                 proto_type[IP_REMOTE]->protocol_type = protocol_type;
826                 proto_type[IP_REMOTE]->func = func;
827                 break;
828         }
829 }
830
831 void
832 ipv6_local_deliver(struct rte_mbuf **pkt_burst, __rte_unused uint16_t nb_rx,
833                          uint64_t icmp_pkt_mask, l2_phy_interface_t *port)
834 {
835         for (; icmp_pkt_mask;) {
836 /**< process only valid packets.*/
837                 uint8_t pos = (uint8_t) __builtin_ctzll(icmp_pkt_mask);
838                 uint64_t pkt_mask = 1LLU << pos;   /**< bitmask representing only this packet */
839                 icmp_pkt_mask &= ~pkt_mask;     /**< remove this packet from the mask */
840
841                 process_icmpv6_pkt(pkt_burst[pos], port);
842         }
843 }
844
845 void
846 ipv6_forward_deliver(struct rte_mbuf **pkt_burst, uint16_t nb_pkts,
847                                  uint64_t ipv6_forward_pkts_mask, l2_phy_interface_t *port)
848 {
849         if (L3FWD_DEBUG) {
850                 printf
851                                 ("ip_forward_deliver BEFORE DROP: nb_pkts: %u\n from in_port %u",
852                                  nb_pkts, port->pmdid);
853         }
854         uint64_t pkts_for_process = ipv6_forward_pkts_mask;
855
856         struct ipv6_hdr *ipv6_hdr;
857         l2_phy_interface_t *port_ptr[RTE_PORT_IN_BURST_SIZE_MAX];
858         uint64_t hit_mask = 0;
859
860         for (; pkts_for_process;) {
861 /**< process only valid packets.*/
862                 uint8_t pos = (uint8_t) __builtin_ctzll(pkts_for_process);
863                 uint64_t pkt_mask = 1LLU << pos;   /**< bitmask representing only this packet */
864                 pkts_for_process &= ~pkt_mask;           /**< remove this packet from the mask */
865                 ipv6_hdr =
866                                 rte_pktmbuf_mtod_offset(pkt_burst[pos], struct ipv6_hdr *,
867                                                         sizeof(struct ether_hdr));
868                 /* Make sure the IPv4 packet is valid  */
869
870                 if (is_valid_ipv6_pkt(ipv6_hdr, pkt_burst[pos]->pkt_len) < 0) {
871                         rte_pktmbuf_free(pkt_burst[pos]);   /**< Drop the Unknown IPv4 Packet */
872                         pkt_burst[pos] = NULL;
873                         ipv6_forward_pkts_mask &= ~(1LLU << pos);  /**< That will clear bit of that position*/
874                         nb_pkts--;
875                         stats.nb_l3_drop_pkt++;
876                 }
877         }
878
879         if (L3FWD_DEBUG) {
880                 printf
881                                 ("\nl3fwd_rx_ipv4_packets_received AFTER DROP: nb_pkts: %u, valid_Pkts_mask :%lu\n",
882                                  nb_pkts, ipv6_forward_pkts_mask);
883         }
884
885         /* Lookup for IP destination in LPMv4 table */
886         lpm6_table_lookup(pkt_burst, nb_pkts, ipv6_forward_pkts_mask, port_ptr,
887                                 &hit_mask);
888 }
889
890 uint8_t ipv6_hash_load_balance(struct rte_mbuf *mbuf)
891 {
892         uint32_t src_addr_offset =
893                         MBUF_HDR_ROOM + ETH_HDR_SIZE + IP_HDR_SRC_ADR_OFST_IPV6;
894         uint32_t dst_addr_offset =
895                         MBUF_HDR_ROOM + ETH_HDR_SIZE + IP_HDR_DST_ADR_OFST_IPV6;
896         uint8_t src_addr[RTE_LPM_IPV6_ADDR_SIZE];
897         uint8_t dst_addr[RTE_LPM_IPV6_ADDR_SIZE];
898
899         memcpy(&src_addr,
900                                  (uint8_t *) RTE_MBUF_METADATA_UINT32_PTR(mbuf, src_addr_offset),
901                                  RTE_LPM_IPV6_ADDR_SIZE);
902         memcpy(&dst_addr,
903                                  (uint8_t *) RTE_MBUF_METADATA_UINT32_PTR(mbuf, dst_addr_offset),
904                                  RTE_LPM_IPV6_ADDR_SIZE);
905         uint32_t hash_key1 = 0; /* STORE Accumulated value of SRC IP in key1 variable */
906         uint32_t hash_key2 = 0; /* STORE Accumulated value of DST IP in key2 variable */
907         uint8_t i;
908         for (i = 0; i < RTE_LPM_IPV6_ADDR_SIZE; i++) {
909                 hash_key1 += src_addr[i];       /* Accumulate */
910                 hash_key2 += dst_addr[i];       /* Accumulate */
911         }
912         hash_key1 = hash_key1 ^ hash_key2;      /* XOR With SRC and DST IP, Result is hask_key1 */
913         hash_key2 = hash_key1;  /* MOVE The result to hask_key2 */
914         hash_key1 = rotr32(hash_key1, RTE_LPM_IPV6_ADDR_SIZE);  /* Circular Rotate to 16 bit */
915         hash_key1 = hash_key1 ^ hash_key2;      /* XOR With Key1 with Key2 */
916
917         hash_key2 = hash_key1;  /* MOVE The result to hask_key2 */
918
919         hash_key1 = rotr32(hash_key1, 8);       /* Circular Rotate to 8 bit */
920         hash_key1 = hash_key1 ^ hash_key2;      /* XOR With Key1 with Key2 */
921
922         hash_key1 = hash_key1 & (HASH_BUCKET_SIZE - 1); /* MASK the KEY with BUCKET SIZE */
923         if (L3FWD_DEBUG)
924                 printf("Hash Result_key: %d, \n", hash_key1);
925         return hash_key1;
926 }
927
928 void
929 resolve_ipv6_l2_adj(uint8_t nh_ipv6[RTE_LPM_IPV6_ADDR_SIZE], uint8_t portid,
930                                 struct ether_addr *hw_addr)
931 {
932         struct l2_adj_ipv6_entry *adj_data = NULL;
933         struct ether_addr eth_dst;
934         uint16_t ether_type = 0x086DD;
935
936         struct l2_adj_key_ipv6 l2_adj_key;
937         memcpy(&l2_adj_key.nh_ipv6, &nh_ipv6, RTE_LPM_IPV6_ADDR_SIZE);
938         l2_adj_key.out_port_id = portid;
939
940         adj_data = retrieve_ipv6_l2_adj_entry(l2_adj_key);
941         if (adj_data) {
942                 if (adj_data->flags == L2_ADJ_UNRESOLVED
943                                 || memcmp(&adj_data->eth_addr, hw_addr, 6)) {
944                         ether_addr_copy(hw_addr, &adj_data->eth_addr);
945
946                         /* Precompute the L2 string encapsulation */
947                         memcpy(&adj_data->l2_string, hw_addr,
948                                                  sizeof(struct ether_addr));
949                         memcpy(&adj_data->l2_string[6],
950                                                  &adj_data->phy_port->macaddr,
951                                                  sizeof(struct ether_addr));
952                         memcpy(&adj_data->l2_string[12], &ether_type, 2);
953
954                         adj_data->flags = L2_ADJ_RESOLVED;
955                 }
956
957                 return;
958         }
959
960         l2_phy_interface_t *port;
961         port = ifm_get_port(portid);
962         if (port == NULL) {
963                 printf("PORT %u IS DOWN..! Unable to Process\n", portid);
964                 return;
965         }
966         uint32_t size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct l2_adj_entry));
967         adj_data = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
968         if (adj_data == NULL) {
969                 printf("L2 Adjacency memory allocation failed !\n");
970                 return;
971         }
972
973         adj_data->out_port_id = portid;
974         memcpy(adj_data->nh_ipv6, &nh_ipv6, RTE_LPM_IPV6_ADDR_SIZE);
975
976         adj_data->phy_port = port;
977
978         ether_addr_copy(&eth_dst, &adj_data->eth_addr);
979
980         /* Precompute the L2 string encapsulation */
981         memcpy(&adj_data->l2_string, hw_addr, sizeof(struct ether_addr));
982         memcpy(&adj_data->l2_string[6], &port->macaddr,
983                                  sizeof(struct ether_addr));
984         memcpy(&adj_data->l2_string[12], &ether_type, 2);
985
986         adj_data->flags = L2_ADJ_RESOLVED;
987
988         /* Store the received MAC Address in L2 Adj HAsh Table */
989         rte_hash_add_key_data(l2_adj_ipv6_hash_handle, &l2_adj_key, adj_data);
990
991         printf(" ND resolution successful and stored in ipv6_l2_adj_entry %p\n",
992                                  adj_data);
993 }
994
995 void ipv6_iterate__hash_table(void)
996 {
997         const void *next_key;
998         void *next_data;
999         uint32_t iter = 0;
1000         uint8_t ii;
1001         printf("\n\t\t\t IPv6 FIB_path Cache table....");
1002         printf
1003                         ("\n------------------------------------------------------------------------------");
1004         printf
1005                         ("\n\tNextHop IP \t\t\t\t Port   Refcount   l2_adj_ptr_addrress\n\n");
1006         printf
1007                         ("--------------------------------------------------------------------------------\n");
1008
1009         while (rte_hash_iterate
1010                                  (fib_path_ipv6_hash_handle, &next_key, &next_data, &iter) >= 0) {
1011                 struct ipv6_fib_path *tmp_data =
1012                                 (struct ipv6_fib_path *)next_data;
1013                 struct fib_path_key_ipv6 tmp_key;
1014                 memcpy(&tmp_key, next_key, sizeof(tmp_key));
1015                 for (ii = 0; ii < 16; ii += 2) {
1016                         printf("%02X%02X ", tmp_data->nh_ipv6[ii],
1017                                                  tmp_data->nh_ipv6[ii + 1]);
1018                 }
1019                 printf(" \t %u \t %u \t %p\n", tmp_data->out_port,
1020                                          tmp_data->refcount, tmp_data->l2_adj_ipv6_ptr);
1021
1022         }
1023
1024         iter = 0;
1025
1026         printf("\n\t\t\t L2 ADJ Cache table.....");
1027         printf
1028                         ("\n----------------------------------------------------------------------------------\n");
1029         printf
1030                         ("\tNextHop IP  \t\t\t\t Port \t  l2 Encap string \t l2_Phy_interface\n");
1031         printf
1032                         ("\n------------------------------------------------------------------------------------\n");
1033         while (rte_hash_iterate
1034                                  (l2_adj_ipv6_hash_handle, &next_key, &next_data, &iter) >= 0) {
1035                 struct l2_adj_ipv6_entry *l2_data =
1036                                 (struct l2_adj_ipv6_entry *)next_data;
1037                 struct l2_adj_key_ipv6 l2_key;
1038                 memcpy(&l2_key, next_key, sizeof(l2_key));
1039                 for (ii = 0; ii < 16; ii += 2) {
1040                         printf("%02X%02X ", l2_data->nh_ipv6[ii],
1041                                                  l2_data->nh_ipv6[ii + 1]);
1042                 }
1043                 printf(" \t%u\t%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x\t%p\n",
1044                                          l2_data->out_port_id,
1045                                          l2_data->l2_string[0],
1046                                          l2_data->l2_string[1],
1047                                          l2_data->l2_string[2],
1048                                          l2_data->l2_string[3],
1049                                          l2_data->l2_string[4],
1050                                          l2_data->l2_string[5],
1051                                          l2_data->l2_string[6],
1052                                          l2_data->l2_string[7],
1053                                          l2_data->l2_string[8],
1054                                          l2_data->l2_string[9],
1055                                          l2_data->l2_string[10],
1056                                          l2_data->l2_string[11], l2_data->phy_port);
1057         }
1058 }