/*
// 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 <interface.h>
#include <rte_byteorder.h>
#include <lib_arp.h>
#include <tsx.h>

interface_main_t ifm;
int USE_RTM_LOCKS = 0;
rte_rwlock_t rwlock;
uint8_t ifm_debug;
static int prev_state;

void config_ifm_debug(int dbg, int flag)
{
	switch (dbg) {
	case IFM_DEBUG_CONFIG:
		if (flag) {
			ifm_debug |= IFM_DEBUG_CONFIG;
		} else {
			ifm_debug &= ~IFM_DEBUG_CONFIG;
		}
		break;
	case IFM_DEBUG_RXTX:
		if (flag) {
			ifm_debug |= IFM_DEBUG_RXTX;
		} else {
			ifm_debug &= ~IFM_DEBUG_RXTX;
		}
		break;
	case IFM_DEBUG_LOCKS:
		if (flag) {
			ifm_debug |= IFM_DEBUG_LOCKS;
		} else {
			ifm_debug &= ~IFM_DEBUG_LOCKS;
		}
		break;
	case IFM_DEBUG:
		if (flag) {
			ifm_debug |= IFM_DEBUG;
		} else {
			ifm_debug &= ~IFM_DEBUG;
		}
		break;
	}
}

void ifm_init(void)
{
	int i = 0;
	config_ifm_debug(IFM_DEBUG_CONFIG, 1);
	if (can_use_intel_core_4th_gen_features()) {
		if (ifm_debug & IFM_DEBUG_CONFIG)
			RTE_LOG(INFO, IFM, "TSX not currently supported...\n\r");
		USE_RTM_LOCKS = 0;
	} else {
		if (ifm_debug & IFM_DEBUG_CONFIG)
			RTE_LOG(INFO, IFM, "TSX not supported\n\r");
		USE_RTM_LOCKS = 0;
	}
	if (USE_RTM_LOCKS)
		rtm_init();
	else
		rte_rwlock_init(&rwlock);

	for (i = 0; i < IFM_MAX_PORTARR_SZ; i++) {
		if (ifm_debug & IFM_DEBUG_LOCKS)
			RTE_LOG(INFO, IFM, "%s: Acquiring WR lock @ %d\n\r",
				__FUNCTION__, __LINE__);
		if (USE_RTM_LOCKS)
			rtm_lock();
		else
			rte_rwlock_write_lock(&rwlock);

		ifm.port_list[i] = NULL;
		if (ifm_debug & IFM_DEBUG_LOCKS)
			RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
				__FUNCTION__, __LINE__);
		if (USE_RTM_LOCKS)
			rtm_unlock();
		else
			rte_rwlock_write_unlock(&rwlock);
	}
	ifm.nport_intialized = rte_eth_dev_count();
	ifm.nport_configured = 0;
	RTE_LOG(INFO, IFM, "IFM_INIT: Number of ports initialized during "
		"PCI probing %u.\n\r", ifm.nport_intialized);
}

void ifm_remove_port_details(uint8_t portid)
{
	if (ifm.port_list[portid] != NULL) {
		if (ifm_debug & IFM_DEBUG_LOCKS)
			RTE_LOG(INFO, IFM, "%s: Acquiring lock %d\n\r",
				__FUNCTION__, __LINE__);
		if (USE_RTM_LOCKS)
			rtm_lock();
		else
			rte_rwlock_write_lock(&rwlock);
		l2_phy_interface_t *port = ifm.port_list[portid];
		ifm.port_list[portid] = NULL;
		if (ifm_debug & IFM_DEBUG_CONFIG)
			RTE_LOG(INFO, IFM, "%s: NULL set for port %u\n\r",
				__FUNCTION__, portid);
		rte_free(port);
		if (ifm_debug & IFM_DEBUG_LOCKS)
			RTE_LOG(INFO, IFM, "%s: Releasing lock @ %d\n\r",
				__FUNCTION__, __LINE__);

		if (USE_RTM_LOCKS)
			rtm_unlock();
		else
			rte_rwlock_write_unlock(&rwlock);
	} else {
		if (ifm_debug & IFM_DEBUG_LOCKS)
			RTE_LOG(INFO, IFM,
				"%s: Failed to remove port details.Port %u info"
				" is already Null.\n\r", __FUNCTION__, portid);
	}
}

l2_phy_interface_t *ifm_get_port(uint8_t port_id)
{
	l2_phy_interface_t *port = NULL;
	if (ifm_debug & IFM_DEBUG_LOCKS)
		RTE_LOG(INFO, IFM, "%s: Acquiring lock @ %d\n\r", __FUNCTION__,
			__LINE__);

	if (USE_RTM_LOCKS)
		rtm_lock();
	else
		rte_rwlock_read_lock(&rwlock);

	port = ifm.port_list[port_id];

	if (port == NULL) {
		/*RTE_LOG(ERR, IFM, "%s: Port %u info not found... configure it first.\n\r",
			 __FUNCTION__, port_id);
		 */
		if (ifm_debug & IFM_DEBUG_LOCKS)
			RTE_LOG(INFO, IFM, "%s: Releasing RD lock @ %d\n\r",
				__FUNCTION__, __LINE__);
		if (USE_RTM_LOCKS)
			rtm_unlock();
		else
			rte_rwlock_read_unlock(&rwlock);
		return NULL;
	}
	if (port->pmdid == port_id) {
		/*RTE_LOG(INFO, IFM, "%s: Port %u found....\n\r",
			 __FUNCTION__, port_id); */
		if (ifm_debug & IFM_DEBUG_LOCKS)
			RTE_LOG(INFO, IFM, "%s: Releasing lock @ %d\n\r",
				__FUNCTION__, __LINE__);

		if (USE_RTM_LOCKS)
			rtm_unlock();
		else
			rte_rwlock_read_unlock(&rwlock);
		return port;
	} else {

/*		RTE_LOG(INFO, IFM,"%s: Mismatch given port %u port in loc %u\n\r",__FUNCTION__,port_id,
				ifm.port_list[port_id]->pmdid);
*/
	}
	if (ifm_debug & IFM_DEBUG_LOCKS)
		RTE_LOG(INFO, IFM, "%s: Releasing lock @ %d\n\r", __FUNCTION__,
			__LINE__);
	if (USE_RTM_LOCKS)
		rtm_unlock();
	else
		rte_rwlock_read_unlock(&rwlock);
	return NULL;
}

l2_phy_interface_t *ifm_get_first_port(void)
{
	l2_phy_interface_t *port = NULL;
	if (ifm_debug & IFM_DEBUG_LOCKS)
		RTE_LOG(INFO, IFM, "%s: Acquiring lock @ %d\n\r", __FUNCTION__,
			__LINE__);

	if (USE_RTM_LOCKS)
		rtm_lock();
	else
		rte_rwlock_read_lock(&rwlock);
	port = ifm.port_list[0];
	if (port == NULL) {
		/*RTE_LOG(ERR, IFM, "%s: Port info not found... configure it first.\n\r",
			 __FUNCTION__); */
		if (ifm_debug & IFM_DEBUG_LOCKS)
			RTE_LOG(INFO, IFM, "%s: Releasing lock @ %d\n\r",
				__FUNCTION__, __LINE__);
		if (USE_RTM_LOCKS)
			rtm_unlock();
		else
			rte_rwlock_read_unlock(&rwlock);
		return NULL;
	}
	/*RTE_LOG(ERR, IFM, "%s: Port  %u info is found...%p\n\r",
		 __FUNCTION__, port->pmdid, port); */
	if (ifm_debug & IFM_DEBUG_LOCKS)
		RTE_LOG(INFO, IFM, "%s: Releasing lock @ %d\n\r", __FUNCTION__,
			__LINE__);
	if (USE_RTM_LOCKS)
		rtm_unlock();
	else
		rte_rwlock_read_unlock(&rwlock);
	return port;
}

l2_phy_interface_t *ifm_get_next_port(uint8_t port_id)
{
	l2_phy_interface_t *port = NULL;
	if (ifm_debug & IFM_DEBUG_LOCKS)
		RTE_LOG(INFO, IFM, "%s: Acquiring lock @ %d\n\r", __FUNCTION__,
			__LINE__);
	if (USE_RTM_LOCKS)
		rtm_lock();
	else
		rte_rwlock_read_lock(&rwlock);
	port = ifm.port_list[port_id + 1];
	if (port == NULL) {
		if (ifm_debug & IFM_DEBUG_LOCKS)
			RTE_LOG(INFO, IFM, "%s: Releasing lock @ %d\n\r",
				__FUNCTION__, __LINE__);
		if (USE_RTM_LOCKS)
			rtm_unlock();
		else
			rte_rwlock_read_unlock(&rwlock);
		return NULL;
	}
	/*RTE_LOG(ERR, IFM, "%s: Port  %u info is found...\n\r",
		 __FUNCTION__, port_id); */
	if (ifm_debug & IFM_DEBUG_LOCKS)
		RTE_LOG(INFO, IFM, "%s: Releasing lock @ %d\n\r", __FUNCTION__,
			__LINE__);

	if (USE_RTM_LOCKS)
		rtm_unlock();
	else
		rte_rwlock_read_unlock(&rwlock);
	return port;
}

l2_phy_interface_t *ifm_get_port_by_name(const char *name)
{
	l2_phy_interface_t *port = NULL;
	int i;
	if (ifm_debug & IFM_DEBUG_LOCKS)
		RTE_LOG(INFO, IFM, "%s: Acquiring lock @ %d\n\r", __FUNCTION__,
			__LINE__);

	if (USE_RTM_LOCKS)
		rtm_lock();
	else
		rte_rwlock_read_lock(&rwlock);
	for (i = 0; i < RTE_MAX_ETHPORTS && ifm.port_list[i]; i++) {
		port = ifm.port_list[i];
		if (strcmp(name, port->ifname) == 0) {
			if (ifm_debug & IFM_DEBUG_CONFIG)
				RTE_LOG(INFO, IFM, "FOUND! port %u %s\n\r",
					port->pmdid, port->ifname);
			if (ifm_debug & IFM_DEBUG_LOCKS)
				RTE_LOG(INFO, IFM,
					"%s: Releasing lock @ %d\n\r",
					__FUNCTION__, __LINE__);
			if (USE_RTM_LOCKS)
				rtm_unlock();
			else
				rte_rwlock_read_unlock(&rwlock);
			return port;
		}
	}
	if (ifm_debug & IFM_DEBUG_LOCKS)
		RTE_LOG(INFO, IFM, "%s: Releasing lock @ %d\n\r", __FUNCTION__,
			__LINE__);
	if (USE_RTM_LOCKS)
		rtm_unlock();
	else
		rte_rwlock_read_unlock(&rwlock);
	return NULL;
}

void lsi_event_callback(uint8_t port_id, enum rte_eth_event_type type,
			void *param)
{
	struct rte_eth_link link;
	l2_phy_interface_t *port;
	int nclients = ifm.nclient;
	int i;

	RTE_SET_USED(param);
	RTE_SET_USED(type);

	if (ifm_debug & IFM_DEBUG_LOCKS)
		RTE_LOG(INFO, IFM, "%s: Acquiring WR lock @ %d\n\r",
			__FUNCTION__, __LINE__);
	if (USE_RTM_LOCKS) {
		rtm_lock();
	} else {
		rte_rwlock_write_lock(&rwlock);
	}
	rte_eth_link_get(port_id, &link);
	for (i = 0; i < nclients; i++)
		ifm.if_client[i].cb_linkupdate(port_id, link.link_status);
	port = ifm.port_list[port_id];
	if (port == NULL) {
		RTE_LOG(ERR, IFM,
			"%s: Port %u info not found... configure it first.\n\r",
			__FUNCTION__, port_id);
	}
	if (port != NULL && port->pmdid == port_id) {
		if (link.link_status) {
			port->link_status = IFM_ETH_LINK_UP;
			port->link_speed = link.link_speed;
			port->link_duplex = link.link_duplex;
			RTE_LOG(INFO, IFM,
				"EVENT-- PORT %u Link UP - Speed %u Mbps - %s.\n",
				port_id, (unsigned)link.link_speed,
				(link.link_duplex ==
				 ETH_LINK_FULL_DUPLEX) ? ("full-duplex")
				: ("half-duplex"));
			if (port->flags & IFM_MASTER) {
				port->flags |= IFM_BONDED;
				port->bond_config->active_slave_count =
						rte_eth_bond_active_slaves_get(port->pmdid,
									 port->
									 bond_config->
									 active_slaves,
									 RTE_MAX_ETHPORTS);
				struct ether_addr new_mac;
				rte_eth_macaddr_get(port->pmdid,
								(struct ether_addr *)
								&new_mac);
				if (memcmp
						(&new_mac, port->macaddr,
						 sizeof(struct ether_addr))) {
					RTE_LOG(INFO, IFM,
						"Bond port %u MAC has changed.\n\r",
						port->pmdid);
				} else {
					RTE_LOG(INFO, IFM,
						"Bond port %u MAC remains same\n\r",
						port->pmdid);
				}
			}
			if (port->flags & IFM_SLAVE) {
				uint8_t master_portid =
						port->bond_config->bond_portid;
				struct rte_eth_link linkstatus;
				rte_eth_link_get(master_portid, &linkstatus);
				RTE_LOG(INFO, IFM, "Port %u 's Master(%u) status is %u\n\r", port_id,
						master_portid, linkstatus.link_status);
			}
			if (ifm_debug & IFM_DEBUG_LOCKS)
				RTE_LOG(INFO, IFM,
					"%s: Releasing WR lock @ %d\n\r",
					__FUNCTION__, __LINE__);

			if (USE_RTM_LOCKS) {
				rtm_unlock();
			} else {
				rte_rwlock_write_unlock(&rwlock);
			}
			if (port->ipv4_list != NULL) {
				if (ifm_debug & IFM_DEBUG_CONFIG)
					RTE_LOG(INFO, IFM,
						"Sending garp on port %u\n\r",
						port->pmdid);
				if (!prev_state) {
					send_gratuitous_arp(port);
					prev_state = 1;
				}
			}
#if 0
			else {
				if (ifm_debug & IFM_DEBUG_CONFIG)
					RTE_LOG(INFO, IFM,
						"IP is not enabled on port %u, not sending GARP\n\r",
						port->pmdid);
			}
#endif
		} else {
			if (port->flags & IFM_MASTER) {
				port->flags &= ~IFM_BONDED;
				//RTE_LOG(INFO, IFM, "IFM_MASTER port, resetting IFM_BONDED. %u\n\r", port->flags);
			}
			port->link_status = IFM_ETH_LINK_DOWN;
			RTE_LOG(INFO, IFM, "EVENT-- PORT %u is Link DOWN.\n",
				port_id);
			if (port->flags & IFM_SLAVE) {
				struct rte_eth_link linkstatus;
				uint8_t master_portid =
						port->bond_config->bond_portid;
				rte_eth_link_get_nowait(master_portid,
							&linkstatus);
				RTE_LOG(INFO, IFM,
					"Port %u 's Master(%u) status is %u\n\r",
					port_id, master_portid,
					linkstatus.link_status);
			}
			if (ifm_debug & IFM_DEBUG_LOCKS)
				RTE_LOG(INFO, IFM,
					"%s: Releasing WR lock @ %d\n\r",
					__FUNCTION__, __LINE__);
			if (USE_RTM_LOCKS) {
				rtm_unlock();
			} else {
				rte_rwlock_write_unlock(&rwlock);
			}
			prev_state = 0;
		}
	}
	//print_interface_details();
}

void ifm_update_linkstatus(uint8_t port_id, uint16_t linkstatus)
{
	struct rte_eth_link link;
	l2_phy_interface_t *port;
	if (ifm_debug & IFM_DEBUG_LOCKS)
		RTE_LOG(INFO, IFM, "%s: Acquiring lock @ %d\n\r", __FUNCTION__,
			__LINE__);

	if (USE_RTM_LOCKS) {
		rtm_lock();
	} else {
		rte_rwlock_write_lock(&rwlock);
	}
	port = ifm.port_list[port_id];

	if (port == NULL) {
		RTE_LOG(ERR, IFM,
			"%s: Port %u info not found... configure it first.\n\r",
			__FUNCTION__, port_id);
	}
	if (port != NULL && port->pmdid == port_id) {
		rte_eth_link_get(port_id, &link);
		if (linkstatus == IFM_ETH_LINK_UP) {
			port->admin_status = IFM_ETH_LINK_UP;
			port->link_status = IFM_ETH_LINK_UP;
			if(!link.link_status) {
				if (rte_eth_dev_set_link_up(port_id) < 0) {
					RTE_LOG(INFO, IFM,
							"%s:Port %u admin up is unsuccessful\n\r",
							__FUNCTION__, port->pmdid);
				} else {
					if (ifm_debug & IFM_DEBUG_LOCKS)
						RTE_LOG(INFO, IFM,
								"%s: Releasing lock @ %d\n\r",
								__FUNCTION__, __LINE__);

					if (USE_RTM_LOCKS) {
						rtm_unlock();
					} else {
						rte_rwlock_write_unlock(&rwlock);
					}
					if (ifm_debug & IFM_DEBUG_CONFIG)
						RTE_LOG(INFO, IFM,
								"%s:Port %u admin up...\n\r",
								__FUNCTION__, port->pmdid);
					send_gratuitous_arp(port);
					return;
				}
			}
		} else if (linkstatus == IFM_ETH_LINK_DOWN)
		{
			int status;
			port->admin_status = IFM_ETH_LINK_DOWN;
			port->link_status = IFM_ETH_LINK_DOWN;
			/* need to check the following if */
			if(link.link_status) {
				status = rte_eth_dev_set_link_down(port_id);
				if (status < 0)
				{
					printf("(%" PRIu32 "): PMD set link down... continuing...%"
							PRId32 "\n", port_id, status);
				}
			}
		}
	}
	if (ifm_debug & IFM_DEBUG_LOCKS)
		RTE_LOG(INFO, IFM, "%s: Releasing lock @ %d\n\r", __FUNCTION__,
			__LINE__);

	if (USE_RTM_LOCKS) {
		rtm_unlock();
	} else {
		rte_rwlock_write_unlock(&rwlock);
	}
}

void ifm_set_l2_interface_mtu(uint8_t port_id, uint16_t mtu)
{
	int ret;
	l2_phy_interface_t *port;
	port = ifm.port_list[port_id];
	if (port == NULL) {
		RTE_LOG(ERR, IFM,
			"%s: Port %u info not found... configure it first.\n\r",
			__FUNCTION__, port_id);
	}

	if (port != NULL && port->pmdid == port_id) {
		ret = rte_eth_dev_set_mtu(port_id, mtu);
		if (ret != 0)
			RTE_LOG(INFO, IFM,
				"set_l2_interface_mtu: Set MTU failed. ret=%d\n",
				ret);
		else {
			if (ifm_debug & IFM_DEBUG_LOCKS)
				RTE_LOG(INFO, IFM,
					"%s: Acquiring lock @ %d\n\r",
					__FUNCTION__, __LINE__);

			if (USE_RTM_LOCKS) {
				rtm_lock();
			} else {
				rte_rwlock_write_lock(&rwlock);
			}
			port->mtu = mtu;
			if (ifm_debug & IFM_DEBUG_LOCKS)
				RTE_LOG(INFO, IFM,
					"%s: Releasing lock @ %d\n\r",
					__FUNCTION__, __LINE__);

			if (USE_RTM_LOCKS) {
				rtm_unlock();
			} else {
				rte_rwlock_write_unlock(&rwlock);
			}
			return;
		}
	}
}

void ifm_set_port_promisc(uint8_t port_id, uint8_t enable)
{
	l2_phy_interface_t *port;
	if (ifm_debug & IFM_DEBUG_LOCKS)
		RTE_LOG(INFO, IFM, "%s: Acquiring WR lock @ %d\n\r",
			__FUNCTION__, __LINE__);
	if (USE_RTM_LOCKS) {
		rtm_lock();
	} else {
		rte_rwlock_write_lock(&rwlock);
	}
	port = ifm.port_list[port_id];
	if (port == NULL) {
		RTE_LOG(ERR, IFM,
			"%s: Port %u info not found... configure it first.\n\r",
			__FUNCTION__, port_id);
	}
	if (port != NULL && port->pmdid == port_id) {
		if (enable == 1) {
			rte_eth_promiscuous_enable(port_id);
			port->promisc = 1;
		} else {
			rte_eth_promiscuous_disable(port_id);
			port->promisc = 0;
		}
	}
	if (ifm_debug & IFM_DEBUG_LOCKS)
		RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
			__FUNCTION__, __LINE__);
	if (USE_RTM_LOCKS) {
		rtm_unlock();
	} else {
		rte_rwlock_write_unlock(&rwlock);
	}
}

int32_t ifm_get_nactive_ports(void)
{
	return ifm.nport_configured;
}

int32_t ifm_get_nports_initialized(void)
{
	return ifm.nport_intialized;
}

uint16_t ifm_receive_bulk_pkts(uint8_t port_id, uint16_t qid,
						 struct rte_mbuf **rx_pkts)
{
	uint64_t no_of_rcvd_pkt;
	no_of_rcvd_pkt =
			rte_eth_rx_burst(port_id, qid, rx_pkts, IFM_BURST_SIZE);
	if (ifm_debug & IFM_DEBUG_RXTX)
		RTE_LOG(INFO, IFM,
			"ifm_receive_bulk_pkts: port_id %u no_of_rcvd_pkt %lu\n\r",
			port_id, no_of_rcvd_pkt);
	return no_of_rcvd_pkt;
}

uint16_t ifm_transmit_bulk_pkts(l2_phy_interface_t *port,
				struct rte_mbuf **tx_pkts, uint64_t npkts)
{
	uint32_t burst_tx_delay_time = IFM_BURST_TX_WAIT_US;
	uint32_t burst_tx_retry_num = IFM_BURST_TX_RETRIES;
	uint32_t retry;
	uint32_t no_of_tx_pkt;
	if (ifm_debug & IFM_DEBUG_LOCKS)
		RTE_LOG(INFO, IFM, "%s: Acquiring RD lock @ %d\n\r",
			__FUNCTION__, __LINE__);
	if (USE_RTM_LOCKS) {
		rtm_lock();
	} else {
		rte_rwlock_read_lock(&rwlock);
	}
	no_of_tx_pkt = rte_eth_tx_burst(port->pmdid, IFM_TX_DEFAULT_Q, tx_pkts,
					npkts);
	if (unlikely(no_of_tx_pkt < npkts)) {
		retry = 0;
		while (no_of_tx_pkt < IFM_BURST_SIZE
					 && retry++ < burst_tx_retry_num) {
			rte_delay_us(burst_tx_delay_time);
			no_of_tx_pkt =
					rte_eth_tx_burst(port->pmdid, IFM_TX_DEFAULT_Q,
							 &tx_pkts[no_of_tx_pkt],
							 IFM_BURST_SIZE - no_of_tx_pkt);
		}
	}
	if (ifm_debug & IFM_DEBUG_RXTX)
		RTE_LOG(INFO, IFM,
			"ifm_transmit_bulk_pkts: no_of_tx_pkt %u\n\r",
			no_of_tx_pkt);
	if (ifm_debug & IFM_DEBUG_LOCKS)
		RTE_LOG(INFO, IFM, "%s: Releasing RD lock @ %d\n\r",
			__FUNCTION__, __LINE__);
	if (USE_RTM_LOCKS) {
		rtm_unlock();
	} else {
		rte_rwlock_read_unlock(&rwlock);
	}
	return no_of_tx_pkt;
}

int ifm_transmit_single_pkt(l2_phy_interface_t *port, struct rte_mbuf *tx_pkts)
{
	uint64_t tx_npkts = 0;
	if (tx_pkts == NULL || port == NULL) {
		RTE_LOG(INFO, IFM,
			"ifm_transmit_single_pkt: tx_pkts and port are NULL ");
		return IFM_FAILURE;
	}
	if (ifm_debug & IFM_DEBUG_RXTX)
		RTE_LOG(INFO, IFM,
			"ifm_transmit_single_pkt: port->pmdid %u\n\r",
			port->pmdid);
	if (ifm_debug & IFM_DEBUG_LOCKS)
		RTE_LOG(INFO, IFM, "%s: Acquiring RD lock @ %d\n\r",
			__FUNCTION__, __LINE__);

	if (USE_RTM_LOCKS) {
		rtm_lock();
	} else {
		rte_rwlock_read_lock(&rwlock);
	}
	tx_npkts =
			rte_eth_tx_buffer(port->pmdid, IFM_TX_DEFAULT_Q, port->tx_buffer,
						tx_pkts);
	if (ifm_debug & IFM_DEBUG_RXTX)
		RTE_LOG(INFO, IFM,
			"ifm_transmit_single_pkt: port->pmdid %u No of packets buffered %lu\n\r",
			port->pmdid, tx_npkts);
	if (ifm_debug & IFM_DEBUG_LOCKS)
		RTE_LOG(INFO, IFM, "%s: Releasing RW lock @ %d\n\r",
			__FUNCTION__, __LINE__);

	if (USE_RTM_LOCKS) {
		rtm_unlock();
	} else {
		rte_rwlock_read_unlock(&rwlock);
	}
	if (ifm_debug & IFM_DEBUG_LOCKS)
		RTE_LOG(INFO, IFM, "%s: Acquiring WR lock @ %d\n\r",
			__FUNCTION__, __LINE__);

	if (USE_RTM_LOCKS) {
		rtm_lock();
	} else {
		rte_rwlock_write_lock(&rwlock);
	}
	port->n_txpkts +=
			rte_eth_tx_buffer_flush(port->pmdid, IFM_TX_DEFAULT_Q,
						port->tx_buffer);
	if (ifm_debug & IFM_DEBUG_LOCKS)
		RTE_LOG(INFO, IFM, "%s: Releasing WR lock @ %d\n\r",
			__FUNCTION__, __LINE__);

	if (USE_RTM_LOCKS) {
		rtm_unlock();
	} else {
		rte_rwlock_write_unlock(&rwlock);
	}
	if (ifm_debug & IFM_DEBUG_RXTX)
		RTE_LOG(INFO, IFM,
			"ifm_transmit_single_pkt: no of pkts flushed %lu\n\r",
			port->n_txpkts);
	return tx_npkts;
}

int16_t ifm_add_ipv4_port(uint8_t port_id, uint32_t ipaddr, uint32_t addrlen)
{
	l2_phy_interface_t *port;
	ipv4list_t *ipconf;
	if (ifm_debug & IFM_DEBUG_LOCKS)
		RTE_LOG(INFO, IFM, "%s: Acquiring lock @ %d\n\r", __FUNCTION__,
			__LINE__);

	if (USE_RTM_LOCKS) {
		rtm_lock();
	} else {
		rte_rwlock_write_lock(&rwlock);
	}
	port = ifm.port_list[port_id];
	if (port == NULL) {
		RTE_LOG(ERR, IFM,
			"%s: Port %u info not found... configure it first.\n\r",
			__FUNCTION__, port_id);
	}
	if (port != NULL && port->pmdid == port_id) {
		ipconf = (ipv4list_t *) rte_zmalloc(NULL, sizeof(ipv4list_t),
								RTE_CACHE_LINE_SIZE);
		if (ipconf != NULL) {
			ipconf->next = NULL;
			//ipconf->ipaddr = rte_bswap32(ipaddr);
			ipconf->ipaddr = ipaddr;
			ipconf->port = port;
			ipconf->addrlen = addrlen;
			if (port->ipv4_list == NULL)
				port->flags |= IFM_IPV4_ENABLED;
			ipconf->next = (ipv4list_t *) port->ipv4_list;
			port->ipv4_list = (ipv4list_t *) ipconf;
			if (ifm_debug & IFM_DEBUG_LOCKS)
				RTE_LOG(INFO, IFM,
					"%s: Releasing lock @ %d\n\r",
					__FUNCTION__, __LINE__);

			if (USE_RTM_LOCKS) {
				rtm_unlock();
			} else {
				rte_rwlock_write_unlock(&rwlock);
			}
			return 0;
		}
	}
	if (ifm_debug & IFM_DEBUG_LOCKS)
		RTE_LOG(INFO, IFM, "%s: Releasing lock @ %d\n\r", __FUNCTION__,
			__LINE__);

	if (USE_RTM_LOCKS) {
		rtm_unlock();
	} else {
		rte_rwlock_write_unlock(&rwlock);
	}
	return -1;
}

int16_t ifm_remove_ipv4_port(uint8_t port_id, uint32_t ipaddr,
						uint32_t addrlen)
{
	l2_phy_interface_t *port;
	ipv4list_t *iplist, *previplist = NULL;
	if (ifm_debug & IFM_DEBUG_LOCKS)
		RTE_LOG(INFO, IFM, "%s: Acquiring lock @ %d\n\r", __FUNCTION__,
			__LINE__);

	if (USE_RTM_LOCKS) {
		rtm_lock();
	} else {
		rte_rwlock_write_lock(&rwlock);
	}
	port = ifm.port_list[port_id];
	if (port == NULL) {
		RTE_LOG(ERR, IFM,
			"%s: Port %u info not found... configure it first.\n\r",
			__FUNCTION__, port_id);
	}
	if (port != NULL && port->pmdid == port_id) {
		if (port->ipv4_list == NULL) {
			if (ifm_debug & IFM_DEBUG_LOCKS)
				RTE_LOG(INFO, IFM,
					"%s: Releasing lock @ %d\n\r",
					__FUNCTION__, __LINE__);

			if (USE_RTM_LOCKS) {
				rtm_unlock();
			} else {
				rte_rwlock_write_unlock(&rwlock);
			}
			return -1;
		}
		iplist = (ipv4list_t *) port->ipv4_list;
		while (iplist != NULL) {
			if (addrlen == iplist->addrlen &&
					memcpy(&iplist->ipaddr, &ipaddr, addrlen)) {
				if (iplist == port->ipv4_list) {
					port->ipv4_list = iplist->next;
				} else {
					if (previplist != NULL)
						previplist->next = iplist->next;
				}
				port->flags &= ~IFM_IPV4_ENABLED;
				rte_free(iplist);
				if (ifm_debug & IFM_DEBUG_LOCKS)
					RTE_LOG(INFO, IFM,
						"%s: Releasing lock @ %d\n\r",
						__FUNCTION__, __LINE__);

				if (USE_RTM_LOCKS) {
					rtm_unlock();
				} else {
					rte_rwlock_write_unlock(&rwlock);
				}
				return 0;
			} else {
				previplist = iplist;
				iplist = iplist->next;
			}
		}
	}
	if (ifm_debug & IFM_DEBUG_LOCKS)
		RTE_LOG(INFO, IFM, "%s: Releasing lock @ %d\n\r", __FUNCTION__,
			__LINE__);

	if (USE_RTM_LOCKS) {
		rtm_unlock();
	} else {
		rte_rwlock_write_unlock(&rwlock);
	}
	return -1;
}

int8_t ifm_add_ipv6_port(uint8_t port_id, uint8_t ip6addr[], uint32_t addrlen)
{
	l2_phy_interface_t *port;
	ipv6list_t *ip6conf;
	if (ifm_debug & IFM_DEBUG_LOCKS)
		RTE_LOG(INFO, IFM, "%s: Acquiring lock @ %d\n\r", __FUNCTION__,
			__LINE__);

	if (USE_RTM_LOCKS) {
		rtm_lock();
	} else {
		rte_rwlock_write_lock(&rwlock);
	}
	port = ifm.port_list[port_id];
	if (port == NULL) {
		RTE_LOG(ERR, IFM,
			"%s: Port %u info not found... configure it first.\n\r",
			__FUNCTION__, port_id);
	}
	if (port != NULL && port->pmdid == port_id) {
		ip6conf = (ipv6list_t *) rte_zmalloc(NULL, sizeof(ipv6list_t),
								 RTE_CACHE_LINE_SIZE);
		if (ip6conf != NULL) {
			ip6conf->next = NULL;
			memcpy(ip6conf->ipaddr, ip6addr, IFM_IPV6_ADDR_SIZE);
			ip6conf->port = port;
			ip6conf->addrlen = addrlen;

			if (port->ipv6_list == NULL) {
				port->flags |= IFM_IPV6_ENABLED;
			}
			ip6conf->next = (ipv6list_t *) port->ipv6_list;
			port->ipv6_list = (ipv6list_t *) ip6conf;
			if (ifm_debug & IFM_DEBUG_LOCKS)
				RTE_LOG(INFO, IFM,
					"%s: Releasing lock @ %d\n\r",
					__FUNCTION__, __LINE__);

			if (USE_RTM_LOCKS) {
				rtm_unlock();
			} else {
				rte_rwlock_write_unlock(&rwlock);
			}
			return 0;
		}
	}
	if (ifm_debug & IFM_DEBUG_LOCKS)
		RTE_LOG(INFO, IFM, "%s: Releasing lock @ %d\n\r", __FUNCTION__,
			__LINE__);

	if (USE_RTM_LOCKS) {
		rtm_unlock();
	} else {
		rte_rwlock_write_unlock(&rwlock);
	}
	return -1;
}

int16_t ifm_remove_ipv6_port(uint8_t port_id, uint32_t ip6addr,
						uint32_t addrlen)
{
	l2_phy_interface_t *port;
	ipv6list_t *ip6list, *previp6list = NULL;

	if (ifm_debug & IFM_DEBUG_LOCKS)
		RTE_LOG(INFO, IFM, "%s: Acquiring lock @ %d\n\r", __FUNCTION__,
			__LINE__);
	if (USE_RTM_LOCKS)
		rtm_lock();
	else
		rte_rwlock_write_lock(&rwlock);
	port = ifm.port_list[port_id];
	if (port == NULL) {
		if (ifm_debug & IFM_DEBUG_LOCKS)
			RTE_LOG(INFO, IFM, "%s: Releasing lock @ %d\n\r",
				__FUNCTION__, __LINE__);
		if (USE_RTM_LOCKS) {
			rtm_unlock();
		} else {
			rte_rwlock_write_unlock(&rwlock);
		}
		RTE_LOG(ERR, IFM,
			"%s: Port %u info not found... configure it first.\n\r",
			__FUNCTION__, port_id);
	}
	if (port != NULL && port->pmdid == port_id) {
		if (port->ipv6_list == NULL) {
			if (ifm_debug & IFM_DEBUG_LOCKS)
				RTE_LOG(INFO, IFM,
					"%s: Releasing lock @ %d\n\r",
					__FUNCTION__, __LINE__);

			if (USE_RTM_LOCKS) {
				rtm_unlock();
			} else {
				rte_rwlock_write_unlock(&rwlock);
			}
			return -1;
		}
		ip6list = (ipv6list_t *) port->ipv6_list;
		while (ip6list != NULL) {
			if (addrlen == ip6list->addrlen &&
					memcpy(&ip6list->ipaddr, &ip6addr, addrlen)) {
				if (ip6list == port->ipv6_list) {
					port->ipv6_list = ip6list->next;
				} else {
					if (previp6list != NULL)
						previp6list->next =
								ip6list->next;
				}
				port->flags &= ~IFM_IPV6_ENABLED;
				rte_free(ip6list);
				if (ifm_debug & IFM_DEBUG_LOCKS)
					RTE_LOG(INFO, IFM,
						"%s: Releasing lock @ %d\n\r",
						__FUNCTION__, __LINE__);

				if (USE_RTM_LOCKS) {
					rtm_unlock();
				} else {
					rte_rwlock_write_unlock(&rwlock);
				}
				return 0;
			} else {
				previp6list = ip6list;
				ip6list = ip6list->next;
			}
		}
	}
	if (ifm_debug & IFM_DEBUG_LOCKS)
		RTE_LOG(INFO, IFM, "%s: Releasing lock @ %d\n\r", __FUNCTION__,
			__LINE__);
	if (USE_RTM_LOCKS)
		rtm_unlock();
	else
		rte_rwlock_write_unlock(&rwlock);
	return -1;
}

int32_t ifm_chk_port_ipv4_enabled(uint8_t port_id)
{
	l2_phy_interface_t *port;

	if (ifm_debug & IFM_DEBUG_LOCKS)
		RTE_LOG(INFO, IFM, "%s: Acquiring RD lock @ %d\n\r",
			__FUNCTION__, __LINE__);
	if (USE_RTM_LOCKS)
		rtm_lock();
	else
		rte_rwlock_read_lock(&rwlock);
	port = ifm.port_list[port_id];
	if (port == NULL) {
		RTE_LOG(ERR, IFM,
			"%s: Port %u info not found... configure it first.\n\r",
			__FUNCTION__, port_id);
		if (ifm_debug & IFM_DEBUG_LOCKS)
			RTE_LOG(INFO, IFM, "%s: Releasing lock @ %d\n\r",
				__FUNCTION__, __LINE__);
		if (USE_RTM_LOCKS)
			rtm_unlock();
		else
			rte_rwlock_read_unlock(&rwlock);
		return IFM_FAILURE;
	}
	if ((port->flags & IFM_IPV4_ENABLED) == 0) {
		if (ifm_debug & IFM_DEBUG_LOCKS)
			RTE_LOG(INFO, IFM, "%s: Releasing lock @ %d\n\r",
				__FUNCTION__, __LINE__);
		if (USE_RTM_LOCKS)
			rtm_unlock();
		else
			rte_rwlock_read_unlock(&rwlock);
		return 0;
	} else {
		if (ifm_debug & IFM_DEBUG_LOCKS)
			RTE_LOG(INFO, IFM, "%s: Releasing lock @ %d\n\r",
				__FUNCTION__, __LINE__);
		if (USE_RTM_LOCKS)
			rtm_unlock();
		else
			rte_rwlock_read_unlock(&rwlock);
		return 1;
	}
}

int32_t ifm_chk_port_ipv6_enabled(uint8_t port_id)
{
	l2_phy_interface_t *port;

	if (ifm_debug & IFM_DEBUG_LOCKS)
		RTE_LOG(INFO, IFM, "%s: Acquiring RD lock @ %d\n\r",
			__FUNCTION__, __LINE__);
	if (USE_RTM_LOCKS)
		rtm_lock();
	else
		rte_rwlock_read_lock(&rwlock);

	port = ifm.port_list[port_id];
	if (port == NULL) {
		if (ifm_debug & IFM_DEBUG)
			RTE_LOG(ERR, IFM, "%s: Port %u info not found..."
				" configure it first.\n\r",
				__FUNCTION__, port_id);
		if (ifm_debug & IFM_DEBUG_LOCKS)
			RTE_LOG(INFO, IFM, "%s: Releasing RD lock @ %d\n\r",
				__FUNCTION__, __LINE__);
		if (USE_RTM_LOCKS)
			rtm_unlock();
		else
			rte_rwlock_read_unlock(&rwlock);
		return IFM_FAILURE;
	}
	if ((port->flags & IFM_IPV6_ENABLED) == 0) {
		if (ifm_debug & IFM_DEBUG_LOCKS)
			RTE_LOG(INFO, IFM, "%s: Releasing RD lock @ %d\n\r",
				__FUNCTION__, __LINE__);
		if (USE_RTM_LOCKS)
			rtm_unlock();
		else
			rte_rwlock_read_unlock(&rwlock);
		return 0;
	} else {
		if (ifm_debug & IFM_DEBUG_LOCKS)
			RTE_LOG(INFO, IFM, "%s: Releasing RD lock @ %d\n\r",
				__FUNCTION__, __LINE__);
		if (USE_RTM_LOCKS)
			rtm_unlock();
		else
			rte_rwlock_read_unlock(&rwlock);
		return 1;
	}
}

void ifm_register_for_linkupdate(uint32_t clientid,
				 void (*cb_linkupdate) (uint8_t, unsigned int))
{
	ifm.if_client[ifm.nclient].cb_linkupdate = cb_linkupdate;
	ifm.if_client[ifm.nclient].clientid = clientid;
	ifm.nclient++;
}

int ifm_port_setup(uint8_t port_id, port_config_t *pconfig)
{
	int status, sock;
	char buf[12];
	struct rte_eth_dev_info dev_info;
	struct rte_eth_link linkstatus;
	l2_phy_interface_t *port = NULL;

	if (!ifm.nport_intialized) {
		RTE_LOG(ERR, IFM, "%s: Failed to configure port %u. 0 ports"
			"were intialized during PCI probe...\n\r",
			__FUNCTION__, port_id);
		return IFM_FAILURE;
	}
	if (ifm_debug & IFM_DEBUG_CONFIG)
		RTE_LOG(INFO, IFM, "%s: Configuring port %u with "
			"nrxq: %u, ntxq: %u\n\r", __FUNCTION__,
			port_id, pconfig->nrx_queue, pconfig->ntx_queue);
	if (ifm_debug & IFM_DEBUG_LOCKS)
		RTE_LOG(INFO, IFM, "%s: Acquiring WR lock1 @ %d\n\r",
			__FUNCTION__, __LINE__);
	if (USE_RTM_LOCKS)
		rtm_lock();
	else
		rte_rwlock_write_lock(&rwlock);

	if (ifm.port_list[port_id] == NULL) {
		ifm.port_list[port_id] =
				(l2_phy_interface_t *) rte_zmalloc(NULL,
									 sizeof
									 (l2_phy_interface_t),
									 RTE_CACHE_LINE_SIZE);
		ifm.port_list[port_id]->pmdid = port_id;
	}
	if (ifm_debug & IFM_DEBUG_LOCKS)
		RTE_LOG(INFO, IFM, "%s: Releasing WR lock1 @ %d\n\r",
			__FUNCTION__, __LINE__);
	if (USE_RTM_LOCKS)
		rtm_unlock();
	else
		rte_rwlock_write_unlock(&rwlock);

	rte_eth_link_get(port_id, &linkstatus);
	if (linkstatus.link_status) {
		if (ifm_debug & IFM_DEBUG_CONFIG) {
			RTE_LOG(INFO, IFM, "%s: %u is up.Stop it before"
				" reconfiguring.\n\r", __FUNCTION__, port_id);
		}
		rte_eth_dev_stop(port_id);
	}
	/*Configure an Ethernet device. rets 0 on success queue */
	status = rte_eth_dev_configure(port_id, pconfig->nrx_queue,
							 pconfig->ntx_queue, &pconfig->port_conf);
	if (status < 0) {
		ifm_remove_port_details(port_id);
		RTE_LOG(ERR, IFM, "%s: rte_eth_dev_configure is failed"
			"for port %u.\n\r", __FUNCTION__, port_id);
		return IFM_FAILURE;
	}
	status = rte_eth_dev_callback_register(port_id,
								 RTE_ETH_EVENT_INTR_LSC,
								 lsi_event_callback, NULL);
	if (status < 0) {
		ifm_remove_port_details(port_id);
		RTE_LOG(ERR, IFM, "%s: rte_eth_dev_callback_register()"
			" failed for port %u.\n\r", __FUNCTION__, port_id);
		return IFM_FAILURE;
	}
	/*promiscuous mode is enabled set it */
	if (pconfig->promisc)
		rte_eth_promiscuous_enable(port_id);

	sock = rte_eth_dev_socket_id(port_id);
	if (sock == -1)
		RTE_LOG(ERR, IFM, "%s: Warning: rte_eth_dev_socket_id,"
			" port_id value is"
			"out of range %u\n\r", __FUNCTION__, port_id);
	/*Port initialization */
	int ntxqs;
	for (ntxqs = 0; ntxqs < pconfig->ntx_queue; ntxqs++) {
		status = rte_eth_tx_queue_setup(port_id, ntxqs,
						IFM_TX_DESC_DEFAULT, sock,
						&(pconfig->tx_conf));
		if (status < 0) {
			ifm_remove_port_details(port_id);
			RTE_LOG(ERR, IFM, "%s: rte_eth_tx_queue_setup failed"
				" for port %u\n\r", __FUNCTION__, port_id);
			return IFM_FAILURE;
		}
	}
	port = ifm_get_port(port_id);
	if (port == NULL) {
		RTE_LOG(INFO, IFM, "%s: Port is NULL @ %d\n\r", __FUNCTION__,
			__LINE__);
		return IFM_FAILURE;
	}

	if (ifm_debug & IFM_DEBUG_LOCKS)
		RTE_LOG(INFO, IFM, "%s: Acquiring WR lock 2 @ %d\n\r",
			__FUNCTION__, __LINE__);
	if (USE_RTM_LOCKS)
		rtm_lock();
	else
		rte_rwlock_write_lock(&rwlock);

	if (port->tx_buf_len == 0) {
		port->tx_buf_len = RTE_ETH_TX_BUFFER_SIZE(IFM_BURST_SIZE);
	}
	port->tx_buffer = rte_zmalloc_socket("tx_buffer", port->tx_buf_len, 0,
							 rte_eth_dev_socket_id(port_id));

	if (port->tx_buffer == NULL) {
		ifm_remove_port_details(port_id);
		RTE_LOG(ERR, IFM, "%s: Failed to allocate tx buffers for"
			" port %u\n\r", __FUNCTION__, port_id);
		if (ifm_debug & IFM_DEBUG_LOCKS)
			RTE_LOG(INFO, IFM, "%s: Releasing WR lock2 %d\n\r",
				__FUNCTION__, __LINE__);
		if (USE_RTM_LOCKS)
			rtm_unlock();
		else
			rte_rwlock_write_unlock(&rwlock);
		return IFM_FAILURE;
	}
	rte_eth_tx_buffer_init(port->tx_buffer, IFM_BURST_SIZE);

	sprintf(buf, "MEMPOOL%d", port_id);
	port->mempool = rte_mempool_create(buf,
						 pconfig->mempool.pool_size,
						 pconfig->mempool.buffer_size,
						 pconfig->mempool.cache_size,
						 sizeof(struct
							rte_pktmbuf_pool_private),
						 rte_pktmbuf_pool_init, NULL,
						 rte_pktmbuf_init, NULL, sock, 0);
	if (port->mempool == NULL) {
		ifm_remove_port_details(port_id);
		RTE_LOG(ERR, IFM, "%s: rte_mempool_create is failed for port"
			" %u. Error: %s\n\r",
			__FUNCTION__, port_id, rte_strerror(rte_errno));
		if (ifm_debug & IFM_DEBUG_LOCKS)
			RTE_LOG(INFO, IFM, "%s: Releasing WR lock2 %d\n\r",
				__FUNCTION__, __LINE__);
		if (USE_RTM_LOCKS)
			rtm_unlock();
		else
			rte_rwlock_write_unlock(&rwlock);
		return IFM_FAILURE;
	}
	int nrxqs;
	for (nrxqs = 0; nrxqs < pconfig->nrx_queue; nrxqs++) {
		status = rte_eth_rx_queue_setup(port_id, nrxqs,
						IFM_RX_DESC_DEFAULT, sock,
						&(pconfig->rx_conf),
						port->mempool);
		if (status < 0) {
			ifm_remove_port_details(port_id);
			RTE_LOG(ERR, IFM,
				"%s: rte_eth_rx_queue_setup is failed "
				"for port %u queue %u. Error: %s\n\r",
				__FUNCTION__, port_id, nrxqs,
				rte_strerror(rte_errno));
			if (ifm_debug & IFM_DEBUG_LOCKS)
				RTE_LOG(INFO, IFM,
					"%s: Releasing WR lock2 %d\n\r",
					__FUNCTION__, __LINE__);
			if (USE_RTM_LOCKS)
				rtm_unlock();
			else
				rte_rwlock_write_unlock(&rwlock);
			return IFM_FAILURE;
		}
	}
	/*Start link */
	if (ifm_debug & IFM_DEBUG_LOCKS)
		RTE_LOG(INFO, IFM, "%s: Releasing WR lock2  @ %d\n\r",
			__FUNCTION__, __LINE__);
	if (USE_RTM_LOCKS)
		rtm_unlock();
	else
		rte_rwlock_write_unlock(&rwlock);
	status = rte_eth_dev_start(port_id);
	if (status < 0) {
		ifm_remove_port_details(port_id);
		RTE_LOG(ERR, IFM, "%s: rte_eth_dev_start is failed for"
			" port %u.\n\r", __FUNCTION__, port_id);
		return IFM_FAILURE;
	}
	rte_delay_ms(5000);
	/*Get device info and populate interface structure */
	if (ifm_debug & IFM_DEBUG_LOCKS)
		RTE_LOG(INFO, IFM, "%s: Acquiring WR lock3 @ %d\n\r",
			__FUNCTION__, __LINE__);
	if (USE_RTM_LOCKS)
		rtm_lock();
	else
		rte_rwlock_write_lock(&rwlock);
	rte_eth_macaddr_get(port_id, (struct ether_addr *)port->macaddr);
	if (pconfig->promisc)
		port->promisc = 1;
	rte_eth_link_get(port_id, &linkstatus);
	/*Link status */
	port->link_duplex = linkstatus.link_duplex;
	port->link_autoneg = linkstatus.link_autoneg;
	port->link_speed = linkstatus.link_speed;
	port->admin_status = pconfig->state;

	/*Get dev_info */
	memset(&dev_info, 0, sizeof(dev_info));
	rte_eth_dev_info_get(port_id, &dev_info);
	port->min_rx_bufsize = dev_info.min_rx_bufsize;
	port->max_rx_pktlen = dev_info.max_rx_pktlen;
	port->max_rx_queues = dev_info.max_rx_queues;
	port->max_tx_queues = dev_info.max_tx_queues;
	rte_eth_dev_get_mtu(port_id, &(port->mtu));

	/*Add rx and tx packet function ptrs */
	port->retrieve_bulk_pkts = &ifm_receive_bulk_pkts;
	port->transmit_bulk_pkts = &ifm_transmit_bulk_pkts;
	port->transmit_single_pkt = &ifm_transmit_single_pkt;
	if (ifm_debug & IFM_DEBUG_LOCKS)
		RTE_LOG(INFO, IFM, "%s: Releasing WR3 lock @ %d\n\r",
			__FUNCTION__, __LINE__);
	if (USE_RTM_LOCKS)
		rtm_unlock();
	else
		rte_rwlock_write_unlock(&rwlock);
	RTE_LOG(INFO, IFM, "%s: Port %u is successfully configured.\n\r",
		__FUNCTION__, port_id);
	return IFM_SUCCESS;
}

int ifm_configure_ports(port_config_t *pconfig)
{
	uint8_t port_id;
	int status = 0;
	if (!ifm.nport_intialized) {
		RTE_LOG(ERR, IFM, "%s, Configuring ports failed. Zero ports "
			"are intialized during PCI probe", __FUNCTION__);
		return IFM_FAILURE;
	}
	if (pconfig == NULL) {
		RTE_LOG(ERR, IFM, "%s, Configuring ports failed. "
			"Param pconfig is NULL\n\r", __FUNCTION__);
		return IFM_FAILURE;
	}

	/*Initialize all ports */
	for (port_id = 0; port_id < ifm.nport_intialized; port_id++) {
		if (ifm_debug & IFM_DEBUG_CONFIG)
			RTE_LOG(INFO, IFM, "Call ifm_port_setup %u\n\r",
				port_id);
		status =
				ifm_port_setup(pconfig[port_id].port_id, &pconfig[port_id]);
		if (status == IFM_SUCCESS)
			ifm.nport_configured++;
	}
	if (!ifm.nport_configured) {
		RTE_LOG(ERR, IFM, "%s: Zero ports are configured\n\r",
			__FUNCTION__);
		return IFM_FAILURE;
	}
	RTE_LOG(INFO, IFM, "%s: Number of ports sucessfully configured:"
		" %d\n\r", __FUNCTION__, ifm.nport_configured);
	return IFM_SUCCESS;
}

void print_interface_details(void)
{
	l2_phy_interface_t *port;
	int i = 0;
	struct sockaddr_in ip;
	printf("\n\r");

	if (ifm_debug & IFM_DEBUG_LOCKS)
		RTE_LOG(INFO, IFM, "%s: Acquiring RW lock @ %d\n\r",
			__FUNCTION__, __LINE__);
	if (USE_RTM_LOCKS)
		rtm_lock();
	else
		rte_rwlock_read_lock(&rwlock);

	for (i = 0; i < RTE_MAX_ETHPORTS && ifm.port_list[i]; i++) {
		port = ifm.port_list[i];
		printf(" %u", port->pmdid);
		if (port->ifname && strlen(port->ifname)) {
			printf(" (%s)\t", port->ifname);
		} else
			printf("\t\t");
		printf("MAC:%02x:%02x:%02x:%02x:%02x:%02x Adminstate:%s"
					 " Operstate:%s \n\r",
					 port->macaddr[0], port->macaddr[1],
					 port->macaddr[2], port->macaddr[3],
					 port->macaddr[4], port->macaddr[5],
					 port->admin_status ? "UP" : "DOWN",
					 port->link_status ? "UP" : "DOWN");
		printf("\t\t");
		printf("Speed: %u, %s-duplex\n\r", port->link_speed,
					 port->link_duplex ? "full" : "half");
		printf("\t\t");

		if (port->ipv4_list != NULL) {
			ip.sin_addr.s_addr =
					(unsigned long)((ipv4list_t *) (port->ipv4_list))->
					ipaddr;
			printf("IP: %s/%d", inet_ntoa(ip.sin_addr),
						 ((ipv4list_t *) (port->ipv4_list))->addrlen);
		} else {
			printf("IP: NA");
		}

		printf("\r\n");
		printf("\t\t");
		if (port->ipv6_list != NULL) {
			uint8_t *addr =
					((ipv6list_t *) (port->ipv6_list))->ipaddr;
			printf
					("IPv6: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
					 addr[0], addr[1], addr[2], addr[3], addr[4],
					 addr[5], addr[6], addr[7], addr[8], addr[9],
					 addr[10], addr[11], addr[12], addr[13], addr[14],
					 addr[15]);
		} else {
			printf("IPv6: NA");
		}

		if (port->flags & IFM_SLAVE) {
			printf("  IFM_SLAVE ");
			printf(" MasterPort: %u",
						 port->bond_config->bond_portid);
		}
		if (port->flags & IFM_MASTER) {
			printf("  IFM_MASTER ");
			printf("  Mode: %u", port->bond_config->mode);
			printf("  PrimaryPort: %u", port->bond_config->primary);
			printf("\n\r");
			printf("\t\tSlavePortCount: %u",
						 port->bond_config->slave_count);
			printf(" SlavePorts:");
			int i;
			for (i = 0; i < port->bond_config->slave_count; i++) {
				printf(" %u ", port->bond_config->slaves[i]);
			}
			printf(" ActivePortCount: %u",
						 port->bond_config->active_slave_count);
			printf(" ActivePorts:");
			for (i = 0; i < port->bond_config->active_slave_count;
					 i++) {
				printf(" %u ",
							 port->bond_config->active_slaves[i]);
			}
			printf("\n\r");
			printf("\t\t");
			printf("Link_monitor_freq: %u ms ",
						 port->bond_config->internal_ms);
			printf(" Link_up_prop_delay: %u ms ",
						 port->bond_config->link_up_delay_ms);
			printf(" Link_down_prop_delay: %u ms ",
						 port->bond_config->link_down_delay_ms);
			printf("\n\r");
			printf("\t\t");
			printf("Xmit_policy: %u",
						 port->bond_config->xmit_policy);
		}
		printf("\n\r");
		printf("\t\t");
		printf("n_rxpkts: %" PRIu64 " ,n_txpkts: %" PRIu64 " ,",
					 port->n_rxpkts, port->n_txpkts);
		struct rte_eth_stats eth_stats;
		rte_eth_stats_get(port->pmdid, &eth_stats);
		printf("pkts_in: %" PRIu64 " ,", eth_stats.ipackets);
		printf("pkts_out: %" PRIu64 " ", eth_stats.opackets);
		printf("\n\r");
		printf("\t\t");
		printf("in_errs: %" PRIu64 " ,", eth_stats.ierrors);
		printf("in_missed: %" PRIu64 " ,", eth_stats.imissed);
		printf("out_errs: %" PRIu64 " ,", eth_stats.oerrors);
		printf("mbuf_errs: %" PRIu64 " ", eth_stats.rx_nombuf);
		printf("\n\r");
		printf("\n\r");
	}
	if (ifm_debug & IFM_DEBUG_LOCKS)
		RTE_LOG(INFO, IFM, "%s: Releasing RW lock @ %d\n\r",
			__FUNCTION__, __LINE__);
	if (USE_RTM_LOCKS)
		rtm_unlock();
	else
		rte_rwlock_read_unlock(&rwlock);
}