aboutsummaryrefslogtreecommitdiff
path: root/platform/linux-dpdk/odp_packet_dpdk.c
diff options
context:
space:
mode:
authorZoltan Kiss <zoltan.kiss@linaro.org>2016-01-20 17:15:18 +0000
committerZoltan Kiss <zoltan.kiss@linaro.org>2016-01-25 14:54:48 +0000
commitc6aee2829bc5badf05ba6074f496a3b92bbd52f7 (patch)
tree4a49901861d3270267447a61afec570c6e584dd6 /platform/linux-dpdk/odp_packet_dpdk.c
parentc986883f6184aa3f22ae28e0b7419ce751fd7bfc (diff)
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 <zoltan.kiss@linaro.org>
Diffstat (limited to 'platform/linux-dpdk/odp_packet_dpdk.c')
-rw-r--r--platform/linux-dpdk/odp_packet_dpdk.c269
1 files changed, 265 insertions, 4 deletions
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 <odp/system_info.h>
#include <odp_debug_internal.h>
+#include <odp_packet_io_internal.h>
#include <odp_packet_dpdk.h>
#include <net/if.h>
#include <math.h>
+/* 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
+};