2 // Copyright (c) 2017 Intel Corporation
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
8 // http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "l3fwd_common.h"
18 #include "l3fwd_lpm4.h"
19 #include "l3fwd_lpm6.h"
20 #include "l3fwd_common.h"
21 #include "interface.h"
24 #include "lib_icmpv6.h"
26 /* Declare Global variables */
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 */
35 static struct ipv6_protocol_type *proto_type[2];
40 /* Initiliaze LPMv6 params */
42 struct rte_table_lpm_ipv6_params lpm6_params = {
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),
50 /* Create LPMv6 tables */
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");
59 /*Initialize IPv6 params for l2 Adj */
60 struct rte_hash_parameters l2_adj_ipv6_params = {
61 .name = "l2_ADJ_IPV6_HASH",
63 .key_len = sizeof(struct l2_adj_key_ipv6),
64 .hash_func = rte_jhash,
65 .hash_func_init_val = 0,
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");
73 printf("ND IPV6_hash_handle %p\n\n",
74 (void *)l2_adj_ipv6_hash_handle);
77 /*Initialize Fib PAth hassh params */
78 struct rte_hash_parameters fib_path_ipv6_params = {
79 .name = "FIB_PATH_IPV6_HASH",
81 .key_len = sizeof(struct fib_path_key_ipv6),
82 .hash_func = rte_jhash,
83 .hash_func_init_val = 0,
87 /* Create FIB PATH Hash tables */
88 fib_path_ipv6_hash_handle = rte_hash_create(&fib_path_ipv6_params);
90 if (fib_path_ipv6_hash_handle == NULL) {
91 printf("FIB path rte_hash_create failed\n");
97 int lpm6_table_route_add(struct ipv6_routing_info *data)
100 struct ipv6_routing_info *fib = data;
101 /* Populate the Key */
102 struct rte_table_lpm_ipv6_key lpm6_key;
104 for (i = 0; i < 16; i++) {
105 lpm6_key.ip[i] = fib->dst_ipv6[i];
107 lpm6_key.depth = fib->depth;
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];
114 entry.depth = fib->depth;
115 entry.fib_nh_size = fib->fib_nh_size;
118 if (entry.fib_nh_size == 0 || entry.fib_nh_size > MAX_FIB_PATHS)
120 if (entry.fib_nh_size != 1) /**< For Single FIB_PATH */
124 ("Route's can't be configured!!, entry.fib_nh_size = %d\n",
129 /* Populate L2 adj and precomputes l2 encap string */
131 for (i = 0; i < entry.fib_nh_size; i++)
133 for (i = 0; i < 1; i++)
136 struct ipv6_fib_path *ipv6_fib_path_addr = NULL;
138 populate_ipv6_fib_path(fib->nh_ipv6[i], fib->out_port[i]);
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,
152 (void *)entry.path[i]->l2_adj_ipv6_ptr);
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 */
170 /* Adding a IP route in LPMv6 table */
171 printf("%s, Line %u \n", __FUNCTION__, __LINE__);
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__);
179 printf("Failed to Add IP route in LPMv6\n");
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);
192 printf("Total Routed Added : %u, Key_found: %d\n", Total_route_count,
195 if (Total_route_count == 2)
196 ipv6_iterate__hash_table();
202 lpm6_table_route_delete(uint8_t dst_ipv6[RTE_LPM_IPV6_ADDR_SIZE], uint8_t depth)
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;
211 entry = rte_zmalloc(NULL, 512, RTE_CACHE_LINE_SIZE);
212 /* Delete a IP route in LPMv6 table */
214 rte_table_lpm_ipv6_ops.f_delete(lpm6_table, &lpm6_key, &key_found,
218 printf("Failed to Delete IP route from LPMv6 table\n");
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);
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
238 lpm6_table_lookup(struct rte_mbuf **pkts_burst,
241 l2_phy_interface_t *port_ptr[RTE_PORT_IN_BURST_SIZE_MAX],
244 struct ipv6_routing_table_entry
245 *ipv6_entries[RTE_PORT_IN_BURST_SIZE_MAX];
246 uint64_t lookup_hit_mask_ipv6 = 0;
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;
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;
262 uint8_t dst_addr[RTE_LPM_IPV6_ADDR_SIZE];
264 (uint8_t *) RTE_MBUF_METADATA_UINT32_PTR(pkts_burst[pos],
266 RTE_LPM_IPV6_ADDR_SIZE);
268 (uint8_t *) RTE_MBUF_METADATA_UINT8_PTR(pkts_burst[pos],
270 memcpy(lpm6_key, dst_addr, RTE_LPM_IPV6_ADDR_SIZE);
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);
276 rte_table_lpm_ops.f_lookup(lpm6_table, pkts_burst, pkts_mask,
277 &lookup_hit_mask_ipv6,
278 (void **)ipv6_entries);
280 printf("LPM Lookup failed for IP route\n");
283 printf(" IPV6 Lookup Mask After = %p\n", (void *)lookup_hit_mask_ipv6);
284 lookup_miss_mask = lookup_miss_mask & (~lookup_hit_mask_ipv6);
286 printf("AFTER lookup_hit_mask = %p, lookup_miss_mask =%p\n",
287 (void *)lookup_hit_mask_ipv6, (void *)lookup_miss_mask);
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;
298 printf("\n DROP PKT IPV4 Lookup_miss_Mask = %p\n",
299 (void *)lookup_miss_mask);
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];
309 struct ipv6_fib_info *entry =
310 (struct ipv6_fib_info *)ipv6_entries[pos];
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))
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];
325 ("Total supported Path :%u, Hashed ECMP Key : %u, selected Fib_path: %u\n",
326 entry->fib_nh_size, ecmp_path, selected_path);
328 struct ipv6_fib_path *fib_path = entry->path[0];
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 */
337 ("Fib_path is NULL, ND has not resolved, DROPPED UNKNOWN PKT\n");
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 */
347 ("L2_ADJ_UNRESOLVED, DROPPED UNKNOWN PKT\n");
352 RTE_MBUF_METADATA_UINT8_PTR(pkt, MBUF_HDR_ROOM);
354 RTE_MBUF_METADATA_UINT8_PTR(pkt, MBUF_HDR_ROOM + 6);
357 ("MAC BEFORE- DST MAC %02x:%02x:%02x:%02x"
359 "SRC MAC %02x:%02x:%02x:%02x:"
361 eth_dest[0], eth_dest[1], eth_dest[2],
363 eth_dest[4], eth_dest[5], eth_src[0],
365 eth_src[2], eth_src[3],
366 eth_src[4], eth_src[5]);
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);
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],
380 eth_dest[5], eth_src[0], eth_src[1],
382 eth_src[3], eth_src[4], eth_src[5]);
384 port_ptr[pos] = fib_path->l2_adj_ipv6_ptr->phy_port;
386 //fib_path->l2_adj_ipv6_ptr->phy_port->transmit_single_pkt(fib_path->l2_adj_ipv6_ptr->phy_port, pkt);
388 printf("Successfully sent to port %u \n\r",
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)
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);
404 uint64_t pkts_for_process = valid_pkts_mask;
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;
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];
419 memset(dest_ipv6_addr, 0, RTE_LPM_IPV6_ADDR_SIZE);
421 printf("\n%s : LINE # %u\n", __FUNCTION__, __LINE__);
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];
429 // memcpy(&configured_port_ipv6, &(((ipv6list_t*)(port->ipv6_list))->ipaddr), RTE_LPM_IPV6_ADDR_SIZE);
431 for (ii = 0; ii < 16; ii += 2) {
432 if (port && port->ipv6_list)
434 ((ipv6list_t *) (port->ipv6_list))->ipaddr[ii],
435 ((ipv6list_t *) (port->ipv6_list))->ipaddr[ii +
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]);
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__,
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__);
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];
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]);
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]);
482 printf("\n%s : LINE # %u", __FUNCTION__, __LINE__);
483 if ((ipv6_hdr->proto == IPPROTO_ICMPV6) &&
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 */
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 */
500 if (icmp_pkts_mask) {
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,
508 if (ipv6_forward_pkts_mask) {
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);
517 struct ipv6_fib_path *populate_ipv6_fib_path(uint8_t
518 nh_ipv6[RTE_LPM_IPV6_ADDR_SIZE],
522 struct fib_path_key_ipv6 path_key;
524 for (i = 0; i < 16; i++) {
525 path_key.nh_ipv6[i] = nh_ipv6[i];
527 path_key.out_port = portid;
528 path_key.filler1 = 0;
529 path_key.filler2 = 0;
530 path_key.filler3 = 0;
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);
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],
547 fib_data->refcount++;
548 return fib_data; // Entry Exists. Return True (1)
550 printf("IPv6 fib_path entry Doesn't Exists.......\n");
553 /* populate L2 Adj */
555 struct l2_adj_ipv6_entry *l2_adj_ptr = NULL;
556 l2_adj_ptr = populate_ipv6_l2_adj(nh_ipv6, portid);
561 RTE_CACHE_LINE_ROUNDUP(sizeof(struct ipv6_fib_path));
562 fib_data = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
564 for (i = 0; i < 16; i++) {
565 fib_data->nh_ipv6[i] = nh_ipv6[i];
567 fib_data->out_port = portid;
568 //memcpy(fib_data->nh_ipv6, &nh_ipv6, RTE_LPM_IPV6_ADDR_SIZE);
570 fib_data->refcount++;
571 fib_data->l2_adj_ipv6_ptr = l2_adj_ptr;
573 /* Store the received MAC Address in L2 Adj HAsh Table */
574 rte_hash_add_key_data(fib_path_ipv6_hash_handle, &path_key,
577 (" ND resolution success l2_adj_entry %p\n, ipv6_fib_path_addr %p",
578 l2_adj_ptr, fib_data);
582 ("ND resolution failed and unable to write fib path in fib_path cuckoo hash\n");
588 struct l2_adj_ipv6_entry *populate_ipv6_l2_adj(uint8_t
589 nh_ipv6[RTE_LPM_IPV6_ADDR_SIZE],
593 struct l2_adj_key_ipv6 l2_adj_key;
595 for (i = 0; i < 16; i++) {
596 l2_adj_key.nh_ipv6[i] = nh_ipv6[i];
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;
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);
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],
619 ether_addr_copy(&adj_data->eth_addr, ð_dst);
620 adj_data->refcount++;
621 return adj_data; // Entry Exists. Return True (1)
624 struct ether_addr eth_src;
625 uint16_t ether_type = 0x086DD;
626 l2_phy_interface_t *port;
627 port = ifm_get_port(portid);
629 printf("PORT %u IS DOWN.. Unable to process !\n", portid);
633 memcpy(ð_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");
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];
646 adj_data->refcount++;
647 adj_data->phy_port = port;
649 rte_hash_add_key_data(l2_adj_ipv6_hash_handle, &l2_adj_key, adj_data);
651 /* Query ND to get L2 Adj */
652 if (get_dest_mac_for_nexthop_ipv6(nh_ipv6, portid, ð_dst)) {
653 /* Store the received MAC Address in L2 Adj HAsh Table */
654 ether_addr_copy(ð_dst, &adj_data->eth_addr);
656 /* Precompute the L2 string encapsulation */
657 memcpy(&adj_data->l2_string, ð_dst,
658 sizeof(struct ether_addr));
659 memcpy(&adj_data->l2_string[6], ð_src,
660 sizeof(struct ether_addr));
661 memcpy(&adj_data->l2_string[12], ðer_type, 2);
663 adj_data->flags = L2_ADJ_RESOLVED;
665 (" ND resolution successful and stored in ipv6_l2_adj_entry %p\n",
670 adj_data->flags = L2_ADJ_UNRESOLVED;
672 ("ND resolution failed and unable to write in ipv6_l2_adj_entry\n");
677 struct l2_adj_ipv6_entry *retrieve_ipv6_l2_adj_entry(struct l2_adj_key_ipv6
680 struct l2_adj_ipv6_entry *ret_l2_adj_data = NULL;
683 rte_hash_lookup_data(l2_adj_ipv6_hash_handle, &l2_adj_key,
684 (void **)&ret_l2_adj_data);
687 ("L2 Adj hash lookup failed ret %d, EINVAL %d, ENOENT %d\n",
688 ret, EINVAL, ENOENT);
690 printf("L2 Adj hash lookup Successful..!!!\n");
691 return ret_l2_adj_data;
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)
700 struct nd_entry_data *nd_data = NULL;
701 struct nd_key_ipv6 tmp_nd_key;
703 for (i = 0; i < 16; i++) {
704 tmp_nd_key.ipv6[i] = nh_ipv6[i];
706 tmp_nd_key.port_id = out_phy_port;
708 nd_data = retrieve_nd_entry(tmp_nd_key, DYNAMIC_ND);
709 if (nd_data == NULL) {
710 printf("ND entry is not found\n");
713 ether_addr_copy(&nd_data->eth_addr, hw_addr);
718 struct ipv6_fib_path *retrieve_ipv6_fib_path_entry(struct fib_path_key_ipv6
722 struct ipv6_fib_path *ret_fib_path_data = NULL;
724 rte_hash_lookup_data(fib_path_ipv6_hash_handle, &path_key,
725 (void **)&ret_fib_path_data);
728 ("FIB Path Adj hash lookup failed ret %d, EINVAL %d, ENOENT %d\n",
729 ret, EINVAL, ENOENT);
732 return ret_fib_path_data;
736 void remove_ipv6_fib_l2_adj_entry(void *entry)
738 struct ipv6_fib_info entry1;
739 memcpy(&entry1, entry, sizeof(struct ipv6_fib_info));
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
770 struct l2_adj_ipv6_entry *adj_addr = NULL;
771 adj_addr = fib_path_addr->l2_adj_ipv6_ptr;
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,
782 rte_free(adj_addr); // free memory
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;
796 int is_valid_ipv6_pkt(struct ipv6_hdr *pkt, uint32_t link_len)
798 if (link_len < sizeof(struct ipv4_hdr))
800 if (rte_cpu_to_be_16(pkt->payload_len) < sizeof(struct ipv6_hdr))
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 *))
811 switch (protocol_type) {
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;
820 case IPPROTO_TCP: // Time being treared as Remote forwarding
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;
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)
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 */
841 process_icmpv6_pkt(pkt_burst[pos], port);
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)
851 ("ip_forward_deliver BEFORE DROP: nb_pkts: %u\n from in_port %u",
852 nb_pkts, port->pmdid);
854 uint64_t pkts_for_process = ipv6_forward_pkts_mask;
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;
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 */
866 rte_pktmbuf_mtod_offset(pkt_burst[pos], struct ipv6_hdr *,
867 sizeof(struct ether_hdr));
868 /* Make sure the IPv4 packet is valid */
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*/
875 stats.nb_l3_drop_pkt++;
881 ("\nl3fwd_rx_ipv4_packets_received AFTER DROP: nb_pkts: %u, valid_Pkts_mask :%lu\n",
882 nb_pkts, ipv6_forward_pkts_mask);
885 /* Lookup for IP destination in LPMv4 table */
886 lpm6_table_lookup(pkt_burst, nb_pkts, ipv6_forward_pkts_mask, port_ptr,
890 uint8_t ipv6_hash_load_balance(struct rte_mbuf *mbuf)
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];
900 (uint8_t *) RTE_MBUF_METADATA_UINT32_PTR(mbuf, src_addr_offset),
901 RTE_LPM_IPV6_ADDR_SIZE);
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 */
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 */
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 */
917 hash_key2 = hash_key1; /* MOVE The result to hask_key2 */
919 hash_key1 = rotr32(hash_key1, 8); /* Circular Rotate to 8 bit */
920 hash_key1 = hash_key1 ^ hash_key2; /* XOR With Key1 with Key2 */
922 hash_key1 = hash_key1 & (HASH_BUCKET_SIZE - 1); /* MASK the KEY with BUCKET SIZE */
924 printf("Hash Result_key: %d, \n", hash_key1);
929 resolve_ipv6_l2_adj(uint8_t nh_ipv6[RTE_LPM_IPV6_ADDR_SIZE], uint8_t portid,
930 struct ether_addr *hw_addr)
932 struct l2_adj_ipv6_entry *adj_data = NULL;
933 struct ether_addr eth_dst;
934 uint16_t ether_type = 0x086DD;
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;
940 adj_data = retrieve_ipv6_l2_adj_entry(l2_adj_key);
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);
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], ðer_type, 2);
954 adj_data->flags = L2_ADJ_RESOLVED;
960 l2_phy_interface_t *port;
961 port = ifm_get_port(portid);
963 printf("PORT %u IS DOWN..! Unable to Process\n", portid);
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");
973 adj_data->out_port_id = portid;
974 memcpy(adj_data->nh_ipv6, &nh_ipv6, RTE_LPM_IPV6_ADDR_SIZE);
976 adj_data->phy_port = port;
978 ether_addr_copy(ð_dst, &adj_data->eth_addr);
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], ðer_type, 2);
986 adj_data->flags = L2_ADJ_RESOLVED;
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);
991 printf(" ND resolution successful and stored in ipv6_l2_adj_entry %p\n",
995 void ipv6_iterate__hash_table(void)
997 const void *next_key;
1001 printf("\n\t\t\t IPv6 FIB_path Cache table....");
1003 ("\n------------------------------------------------------------------------------");
1005 ("\n\tNextHop IP \t\t\t\t Port Refcount l2_adj_ptr_addrress\n\n");
1007 ("--------------------------------------------------------------------------------\n");
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]);
1019 printf(" \t %u \t %u \t %p\n", tmp_data->out_port,
1020 tmp_data->refcount, tmp_data->l2_adj_ipv6_ptr);
1026 printf("\n\t\t\t L2 ADJ Cache table.....");
1028 ("\n----------------------------------------------------------------------------------\n");
1030 ("\tNextHop IP \t\t\t\t Port \t l2 Encap string \t l2_Phy_interface\n");
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]);
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);