aboutsummaryrefslogtreecommitdiffstats
path: root/lib/libtle_glue/port.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libtle_glue/port.c')
-rw-r--r--lib/libtle_glue/port.c246
1 files changed, 246 insertions, 0 deletions
diff --git a/lib/libtle_glue/port.c b/lib/libtle_glue/port.c
new file mode 100644
index 0000000..7a4cf2e
--- /dev/null
+++ b/lib/libtle_glue/port.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2018 Ant Financial Services Group.
+ * 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 <sys/eventfd.h>
+#include <unistd.h>
+
+#include <rte_ethdev.h>
+#include <rte_eth_ring.h>
+
+#include "log.h"
+#include "ctx.h"
+#include "config.h"
+#include "internal.h"
+
+int stopped;
+
+static struct rte_mempool *mpool[RTE_MAX_NUMA_NODES];
+
+struct rte_mempool *
+get_mempool_by_socket(int32_t socket_id)
+{
+ struct rte_mempool *mp;
+ char name[RTE_MEMPOOL_NAMESIZE];
+
+ if (socket_id == SOCKET_ID_ANY)
+ socket_id = 0;
+
+ if (mpool[socket_id])
+ return mpool[socket_id];
+
+ snprintf(name, sizeof(name), "MP%u", socket_id);
+ mp = rte_pktmbuf_dynamic_pool_create(name, MAX_MBUFS - 1,
+ MBUF_PERCORE_CACHE, 0,
+ RTE_MBUF_DEFAULT_BUF_SIZE,
+ socket_id, MBUF_DYNAMIC_SIZE);
+
+ if (mp == NULL)
+ rte_panic("Failed to create mbuf mempool");
+
+ mpool[socket_id] = mp;
+ return mp;
+}
+
+static void
+update_rss_conf(uint16_t port_id)
+{
+ struct rte_eth_rss_conf rss_conf = {
+ .rss_key = NULL,
+ .rss_key_len = 0,
+ .rss_hf = ETH_RSS_IP | ETH_RSS_TCP | ETH_RSS_UDP,
+ };
+
+ if (rte_eth_dev_rss_hash_update(port_id, &rss_conf) < 0)
+ rte_panic("Failed to update rss hash");
+}
+
+static void
+queue_init(uint16_t port_id, uint16_t nb_queues,
+ struct rte_eth_dev_info *dev_info,
+ struct rte_eth_conf *port_conf)
+{
+ uint16_t q;
+ int32_t socket_id, rc;
+ uint16_t nb_rxd = 1024, nb_txd = 1024;
+ struct rte_mempool *mp;
+ struct rte_eth_txconf txq_conf = dev_info->default_txconf;
+ struct rte_eth_rxconf rxq_conf = dev_info->default_rxconf;
+
+ socket_id = rte_eth_dev_socket_id(port_id);
+ mp = get_mempool_by_socket(socket_id);
+
+ dev_info->default_rxconf.rx_drop_en = 1;
+
+ rc = rte_eth_dev_adjust_nb_rx_tx_desc(port_id, &nb_rxd, &nb_txd);
+ if (rc < 0)
+ rte_panic("Cannot adjust number of desc");
+
+ rxq_conf.offloads = port_conf->rxmode.offloads;
+ txq_conf.offloads = port_conf->txmode.offloads;
+
+ /* faster free of tx entries */
+ txq_conf.tx_free_thresh = nb_txd - 64;
+
+ for (q = 0; q < nb_queues; q++) {
+ rc = rte_eth_rx_queue_setup(port_id, q, nb_rxd,
+ socket_id, &rxq_conf, mp);
+ if (rc < 0)
+ rte_panic("rx queue=%u setup failed: %d", q, rc);
+
+ rc = setup_rx_cb(port_id, q);
+ if (rc < 0)
+ rte_panic("rx queue=%u rx setup failed: %d", q, rc);
+ }
+
+ for (q = 0; q < nb_queues; q++) {
+ rc = rte_eth_tx_queue_setup(port_id, q, nb_txd,
+ socket_id, &txq_conf);
+ if (rc < 0)
+ rte_panic("tx queue=%u setup failed: %d", q, rc);
+ }
+}
+
+uint64_t rx_offload =
+ DEV_RX_OFFLOAD_IPV4_CKSUM |
+ DEV_RX_OFFLOAD_UDP_CKSUM |
+ DEV_RX_OFFLOAD_TCP_CKSUM;
+/* nice to have:
+ DEV_RX_OFFLOAD_CRC_STRIP |
+ DEV_RX_OFFLOAD_TCP_LRO |
+ DEV_RX_OFFLOAD_HEADER_SPLIT |
+ DEV_RX_OFFLOAD_SCATTER |
+ DEV_RX_OFFLOAD_TIMESTAMP
+*/
+
+uint64_t tx_offload =
+ DEV_TX_OFFLOAD_UDP_CKSUM |
+ DEV_TX_OFFLOAD_TCP_CKSUM |
+ DEV_TX_OFFLOAD_TCP_TSO |
+ DEV_TX_OFFLOAD_MULTI_SEGS;
+
+int
+dev_rxq_wakeup(uint16_t port_id)
+{
+ int fd;
+ uint16_t qid;
+ uint32_t vec, efd_idx;
+ struct rte_eth_dev *dev;
+ struct rte_intr_handle *intr_handle;
+
+ RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+ dev = &rte_eth_devices[port_id];
+ intr_handle = dev->intr_handle;
+ if (!intr_handle)
+ return -ENOTSUP;
+ if (!intr_handle->intr_vec)
+ return -EPERM;
+
+ for (qid = 0; qid < dev->data->nb_rx_queues; qid++) {
+ vec = intr_handle->intr_vec[qid];
+ efd_idx = (vec >= RTE_INTR_VEC_RXTX_OFFSET) ?
+ (vec - RTE_INTR_VEC_RXTX_OFFSET) : vec;
+ fd = intr_handle->efds[efd_idx];
+ if (eventfd_write(fd, (eventfd_t) 1) < 0)
+ return -errno;
+ }
+
+ return 0;
+}
+
+void
+port_reconfig(void)
+{
+ int32_t rc;
+ struct rte_eth_dev_info dev_info;
+ uint16_t port_id = 0; /* We use and only use port 0 */
+ uint16_t nb_port;
+ uint16_t nb_queues = nb_ctx;
+
+ struct rte_eth_conf port_conf = {
+ .intr_conf = {
+ .rxq = 1,
+ },
+ };
+
+ /* 0. dev number check */
+ nb_port = rte_eth_dev_count_avail();
+ if (nb_port < 1 || nb_port >2)
+ rte_panic("One port is mandatory with an optional loopback device\n");
+
+ stopped = 1;
+ rte_wmb();
+ /* wake up all rxqs */
+ if (nb_ctx > 1)
+ dev_rxq_wakeup(port_id);
+
+ usleep(1); /* fix me: this cannot gurantee correctness */
+
+ rte_eth_dev_stop(port_id);
+
+ /* 1. offloading check and set*/
+ rte_eth_dev_info_get(port_id, &dev_info);
+ rx_offload &= dev_info.rx_offload_capa;
+ port_conf.rxmode.offloads = rx_offload;
+ tx_offload &= dev_info.tx_offload_capa;
+ port_conf.txmode.offloads = tx_offload;
+
+ GLUE_LOG(INFO, "configure queues = %d, offloads: rx = %"PRIx64", tx = %"PRIx64,
+ nb_queues, rx_offload, tx_offload);
+
+ /* 2. dev configure */
+ rc = rte_eth_dev_configure(port_id, nb_queues, nb_queues, &port_conf);
+ if (rc != 0)
+ rte_panic("Failed to configure device, %d", rc);
+
+ /* 3. queue setup */
+ queue_init(port_id, nb_queues, &dev_info, &port_conf);
+
+ /* 4. rss conf */
+ if (nb_queues > 1)
+ update_rss_conf(port_id);
+
+ /* 5. dev start */
+ if (rte_eth_dev_start(port_id) < 0)
+ rte_panic("Failed to start device");
+
+ stopped = 0;
+}
+
+uint16_t
+create_loopback(uint32_t socket_id)
+{
+ int ret;
+ struct rte_ring* lb_queue;
+ static uint16_t lb_port_id = 0xFFFF;
+ const char *ring_name = "loopback-ring";
+
+ if (lb_port_id != 0xFFFF)
+ return lb_port_id;
+
+ lb_queue = rte_ring_create(ring_name, MAX_PKTS_BURST * 8, socket_id,
+ RING_F_SP_ENQ | RING_F_SC_DEQ);
+ if (!lb_queue)
+ rte_panic("Failed to create ring for loopback\n");
+ ret = rte_eth_from_ring(lb_queue);
+ if (ret < 0)
+ rte_panic("Failed to create ethdev from ring\n");
+ lb_port_id = ret;
+
+ if (setup_rx_cb(lb_port_id, 0) < 0)
+ rte_panic("Failed to set up rx cb for loopback\n");
+
+ return lb_port_id;
+}