aboutsummaryrefslogtreecommitdiffstats
path: root/ansible/cpu_pin_teardown.yaml
blob: 7647eebdbe78ae0731944baf6b1a1e31f0f6a437 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
---
##############################################################################
# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others.
#
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Apache License, Version 2.0
# which accompanies this distribution, and is available at
# http://www.apache.org/licenses/LICENSE-2.0
##############################################################################

- hosts: compute
  roles:
      - vcpu_pin_set_reset
      - restart_nova_compute

- hosts: controller
  roles:
      - scheduler_default_filters_reset
      - restart_nova_scheduler

- hosts: localhost
  roles:
      - cpu_pin_local_teardown
'n272' href='#n272'>272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 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);
	}
}