From c6aee2829bc5badf05ba6074f496a3b92bbd52f7 Mon Sep 17 00:00:00 2001 From: Zoltan Kiss Date: Wed, 20 Jan 2016 17:15:18 +0000 Subject: linux-dpdk: packet_io: reuse linux-generic code and enable classification This patch reuses odp_packet_io.c and pktio/loop.c from linux-generic's codebase, and plugs the DPDK specific pieces from odp_packet_dpdk.c into that framework. In order to do that the following steps were taken: - sync up odp_packet_io_internal.h: this file is nearly the same, except we use only loop and our DPDK specific parts - move DPDK specific functionality to odp_packet_dpdk.c, and use those functions in dpdk_pktio_ops. The old pktio code will be deleted in a separate patch - enable classification in Makefiles and init: linux-generic code refers to that, that's why we can't do this in separate patches Signed-off-by: Zoltan Kiss --- platform/linux-dpdk/odp_packet_dpdk.c | 269 +++++++++++++++++++++++++++++++++- 1 file changed, 265 insertions(+), 4 deletions(-) (limited to 'platform/linux-dpdk/odp_packet_dpdk.c') diff --git a/platform/linux-dpdk/odp_packet_dpdk.c b/platform/linux-dpdk/odp_packet_dpdk.c index 3a24b0334..d130ac0e2 100644 --- a/platform/linux-dpdk/odp_packet_dpdk.c +++ b/platform/linux-dpdk/odp_packet_dpdk.c @@ -26,10 +26,23 @@ #include #include +#include #include #include #include +/* Ops for all implementation of pktio. + * Order matters. The first implementation to setup successfully + * will be picked. + * Array must be NULL terminated */ +const pktio_if_ops_t * const pktio_if_ops[] = { + &loopback_pktio_ops, + &dpdk_pktio_ops, + NULL +}; + +extern pktio_table_t *pktio_tbl; + /* Test if s has only digits or not. Dpdk pktio uses only digits.*/ static int _dpdk_netdev_is_valid(const char *s) { @@ -58,8 +71,8 @@ static void _dpdk_print_port_mac(uint8_t portid) eth_addr.addr_bytes[5]); } -int setup_pkt_dpdk(pkt_dpdk_t * const pkt_dpdk, const char *netdev, - odp_pool_t pool) +static int setup_pkt_dpdk(odp_pktio_t pktio ODP_UNUSED, pktio_entry_t *pktio_entry, + const char *netdev, odp_pool_t pool) { uint8_t portid = 0; uint16_t nbrxq, nbtxq; @@ -70,6 +83,7 @@ int setup_pkt_dpdk(pkt_dpdk_t * const pkt_dpdk, const char *netdev, uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT; uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT; struct rte_eth_dev_info dev_info; + pkt_dpdk_t * const pkt_dpdk = &pktio_entry->s.pkt_dpdk; struct rte_eth_conf port_conf = { .rxmode = { @@ -162,17 +176,82 @@ int setup_pkt_dpdk(pkt_dpdk_t * const pkt_dpdk, const char *netdev, return 0; } -int close_pkt_dpdk(pkt_dpdk_t * const pkt_dpdk) +static int close_pkt_dpdk(pktio_entry_t *pktio_entry) { + pkt_dpdk_t * const pkt_dpdk = &pktio_entry->s.pkt_dpdk; + rte_eth_dev_close(pkt_dpdk->portid); return 0; } -int recv_pkt_dpdk(pkt_dpdk_t * const pkt_dpdk, odp_packet_t pkt_table[], +static int start_pkt_dpdk(pktio_entry_t *pktio_entry) +{ + int ret; + + ret = rte_eth_dev_start(pktio_entry->s.pkt_dpdk.portid); + if (ret < 0) { + ODP_ERR("rte_eth_dev_start:err=%d, port=%u\n", + ret, pktio_entry->s.pkt_dpdk.portid); + return ret; + } + return 0; +} + +static int stop_pkt_dpdk(pktio_entry_t *pktio_entry) +{ + rte_eth_dev_stop(pktio_entry->s.pkt_dpdk.portid); + return 0; +} + +static unsigned rte_mempool_available(const struct rte_mempool *mp) +{ +#if RTE_MEMPOOL_CACHE_MAX_SIZE > 0 + return rte_ring_count(mp->ring) + mp->local_cache[rte_lcore_id()].len; +#else + return rte_ring_count(mp->ring); +#endif +} + +static void _odp_pktio_send_completion(pktio_entry_t *pktio_entry ODP_UNUSED) +{ + int i; + struct rte_mbuf* dummy; + pool_entry_t *pool_entry = + get_pool_entry(_odp_typeval(pktio_entry->s.pkt_dpdk.pool)); + struct rte_mempool *rte_mempool = pool_entry->s.rte_mempool; + pkt_dpdk_t * pkt_dpdk = &pktio_entry->s.pkt_dpdk; + + rte_eth_tx_burst(pkt_dpdk->portid, pkt_dpdk->queueid, &dummy, 0); + + for (i = 0; i < ODP_CONFIG_PKTIO_ENTRIES; ++i) { + pktio_entry_t *entry = &pktio_tbl->entries[i]; + + if (rte_mempool_available(rte_mempool) != 0) + return; + + if (entry == pktio_entry) + continue; + + if (odp_ticketlock_trylock(&entry->s.txl)) { + if (!is_free(entry) && + entry->s.ops == &dpdk_pktio_ops) { + pkt_dpdk = &entry->s.pkt_dpdk; + rte_eth_tx_burst(pkt_dpdk->portid, + pkt_dpdk->queueid, &dummy, 0); + } + odp_ticketlock_unlock(&entry->s.txl); + } + } + + return; +} + +static int recv_pkt_dpdk(pktio_entry_t *pktio_entry, odp_packet_t pkt_table[], unsigned len) { uint16_t nb_rx, i = 0; odp_packet_t *saved_pkt_table; + pkt_dpdk_t * const pkt_dpdk = &pktio_entry->s.pkt_dpdk; uint8_t min = pkt_dpdk->min_rx_burst; if (odp_unlikely(min > len)) { @@ -187,6 +266,17 @@ int recv_pkt_dpdk(pkt_dpdk_t * const pkt_dpdk, odp_packet_t pkt_table[], (struct rte_mbuf **)pkt_table, (uint16_t)RTE_MAX(len, min)); + if (nb_rx == 0) { + pool_entry_t *pool_entry = + get_pool_entry(_odp_typeval(pkt_dpdk->pool)); + struct rte_mempool *rte_mempool = + pool_entry->s.rte_mempool; + if (rte_mempool_available(rte_mempool) == 0) + _odp_pktio_send_completion(pktio_entry); + } + for (i = 0; i < nb_rx; ++i) + _odp_packet_reset_parse(pkt_table[i]); + if (odp_unlikely(min > len)) { memcpy(saved_pkt_table, pkt_table, len * sizeof(odp_packet_t)); @@ -198,3 +288,174 @@ int recv_pkt_dpdk(pkt_dpdk_t * const pkt_dpdk, odp_packet_t pkt_table[], return nb_rx; } + +static int send_pkt_dpdk(pktio_entry_t *pktio_entry, odp_packet_t pkt_table[], + unsigned len) +{ + int pkts; + pkt_dpdk_t * const pkt_dpdk = &pktio_entry->s.pkt_dpdk; + + pkts = rte_eth_tx_burst(pkt_dpdk->portid, pkt_dpdk->queueid, + (struct rte_mbuf **)pkt_table, len); + if (pkts) { + return pkts; + } else { + if (!rte_errno) + rte_errno = -1; + return -1; + } +} + +static int _dpdk_vdev_mtu(uint8_t port_id) +{ + struct rte_eth_dev_info dev_info = {0}; + struct ifreq ifr; + int ret; + int sockfd; + + rte_eth_dev_info_get(port_id, &dev_info); + if_indextoname(dev_info.if_index, ifr.ifr_name); + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + ret = ioctl(sockfd, SIOCGIFMTU, &ifr); + close(sockfd); + if (ret < 0) { + ODP_DBG("ioctl SIOCGIFMTU error\n"); + return -1; + } + + return ifr.ifr_mtu; +} + +static int mtu_get_pkt_dpdk(pktio_entry_t *pktio_entry) +{ + uint16_t mtu; + int ret; + + ret = rte_eth_dev_get_mtu(pktio_entry->s.pkt_dpdk.portid, + &mtu); + if (ret < 0) + return -2; + + /* some dpdk PMD vdev does not support getting mtu size, + * try to use system call if dpdk cannot get mtu value. + */ + if (mtu == 0) + mtu = _dpdk_vdev_mtu(pktio_entry->s.pkt_dpdk.portid); + return mtu; +} + +static int _dpdk_vdev_promisc_mode_set(uint8_t port_id, int enable) +{ + struct rte_eth_dev_info dev_info = {0}; + struct ifreq ifr; + int ret; + int sockfd; + + rte_eth_dev_info_get(port_id, &dev_info); + if_indextoname(dev_info.if_index, ifr.ifr_name); + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + + ret = ioctl(sockfd, SIOCGIFFLAGS, &ifr); + if (ret < 0) { + close(sockfd); + ODP_DBG("ioctl SIOCGIFFLAGS error\n"); + return -1; + } + + if (enable) + ifr.ifr_flags |= IFF_PROMISC; + else + ifr.ifr_flags &= ~(IFF_PROMISC); + + ret = ioctl(sockfd, SIOCSIFFLAGS, &ifr); + if (ret < 0) { + close(sockfd); + ODP_DBG("ioctl SIOCSIFFLAGS error\n"); + return -1; + } + + ret = ioctl(sockfd, SIOCGIFMTU, &ifr); + if (ret < 0) { + close(sockfd); + ODP_DBG("ioctl SIOCGIFMTU error\n"); + return -1; + } + + ODP_DBG("vdev promisc set to %d\n", enable); + close(sockfd); + return 0; +} + +static int promisc_mode_set_pkt_dpdk(pktio_entry_t *pktio_entry, int enable) +{ + uint8_t portid = pktio_entry->s.pkt_dpdk.portid; + if (enable) + rte_eth_promiscuous_enable(portid); + else + rte_eth_promiscuous_disable(portid); + + if (pktio_entry->s.pkt_dpdk.vdev_sysc_promisc) { + int ret = _dpdk_vdev_promisc_mode_set(portid, enable); + if (ret < 0) + ODP_DBG("vdev promisc mode fail\n"); + } + + return 0; +} + +static int _dpdk_vdev_promisc_mode(uint8_t port_id) +{ + struct rte_eth_dev_info dev_info = {0}; + struct ifreq ifr; + int ret; + int sockfd; + + rte_eth_dev_info_get(port_id, &dev_info); + if_indextoname(dev_info.if_index, ifr.ifr_name); + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + ret = ioctl(sockfd, SIOCGIFFLAGS, &ifr); + close(sockfd); + if (ret < 0) { + ODP_DBG("ioctl SIOCGIFFLAGS error\n"); + return -1; + } + + if (ifr.ifr_flags & IFF_PROMISC) { + ODP_DBG("promisc is 1\n"); + return 1; + } else + return 0; +} + +static int promisc_mode_get_pkt_dpdk(pktio_entry_t *pktio_entry) +{ + uint8_t portid = pktio_entry->s.pkt_dpdk.portid; + if (pktio_entry->s.pkt_dpdk.vdev_sysc_promisc) + return _dpdk_vdev_promisc_mode(portid); + else + return rte_eth_promiscuous_get(portid); + +} + +static int mac_get_pkt_dpdk(pktio_entry_t *pktio_entry, void *mac_addr) +{ + rte_eth_macaddr_get(pktio_entry->s.pkt_dpdk.portid, + (struct ether_addr *)mac_addr); + return ETH_ALEN; +} + + +const pktio_if_ops_t dpdk_pktio_ops = { + .init = NULL, + .term = NULL, + .open = setup_pkt_dpdk, + .close = close_pkt_dpdk, + .start = start_pkt_dpdk, + .stop = stop_pkt_dpdk, + .recv = recv_pkt_dpdk, + .send = send_pkt_dpdk, + .mtu_get = mtu_get_pkt_dpdk, + .promisc_mode_set = promisc_mode_set_pkt_dpdk, + .promisc_mode_get = promisc_mode_get_pkt_dpdk, + .mac_get = mac_get_pkt_dpdk +}; -- cgit v1.2.3