aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/transport/uhd-dpdk/uhd_dpdk_udp.c
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib/transport/uhd-dpdk/uhd_dpdk_udp.c')
-rw-r--r--host/lib/transport/uhd-dpdk/uhd_dpdk_udp.c525
1 files changed, 0 insertions, 525 deletions
diff --git a/host/lib/transport/uhd-dpdk/uhd_dpdk_udp.c b/host/lib/transport/uhd-dpdk/uhd_dpdk_udp.c
deleted file mode 100644
index 9429cd6cb..000000000
--- a/host/lib/transport/uhd-dpdk/uhd_dpdk_udp.c
+++ /dev/null
@@ -1,525 +0,0 @@
-//
-// Copyright 2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-#include "uhd_dpdk_fops.h"
-#include "uhd_dpdk_udp.h"
-#include "uhd_dpdk_driver.h"
-#include "uhd_dpdk_wait.h"
-#include <rte_ring.h>
-#include <rte_malloc.h>
-#include <unistd.h>
-#include <sys/syscall.h>
-#include <arpa/inet.h>
-
-#define MAX_UDP_PORT 65535
-
-/************************************************
- * I/O thread ONLY
- */
-
-static int _alloc_txq(struct uhd_dpdk_port *port, pthread_t tid,
- struct uhd_dpdk_tx_queue **queue, size_t num_bufs)
-{
- *queue = NULL;
- struct uhd_dpdk_tx_queue *q = rte_zmalloc(NULL, sizeof(*q), 0);
- if (!q) {
- RTE_LOG(ERR, USER1, "%s: Cannot allocate TX queue\n", __func__);
- return -ENOMEM;
- }
- q->tid = tid;
- LIST_INIT(&q->tx_list);
-
- char name[32];
- snprintf(name, sizeof(name), "tx_q%u.%0lx", port->id, (unsigned long) q);
- q->queue = rte_ring_create(
- name,
- num_bufs,
- rte_socket_id(),
- RING_F_SC_DEQ | RING_F_SP_ENQ
- );
- snprintf(name, sizeof(name), "free_q%u.%0lx", port->id, (unsigned long) q);
- q->freebufs = rte_ring_create(
- name,
- num_bufs,
- rte_socket_id(),
- RING_F_SC_DEQ | RING_F_SP_ENQ
- );
- /* Set up retry queue */
- snprintf(name, sizeof(name), "redo_q%u.%0lx", port->id, (unsigned long) q);
- q->retry_queue = rte_ring_create(
- name,
- num_bufs,
- rte_socket_id(),
- RING_F_SC_DEQ | RING_F_SP_ENQ
- );
-
- if (!q->queue || !q->freebufs || !q->retry_queue) {
- RTE_LOG(ERR, USER1, "%s: Cannot allocate TX rings\n", __func__);
- if (q->queue)
- rte_ring_free(q->queue);
- if (q->freebufs)
- rte_ring_free(q->freebufs);
- if (q->retry_queue)
- rte_ring_free(q->retry_queue);
- rte_free(q);
- return -ENOMEM;
- }
-
- do {
- struct rte_mbuf *bufs[UHD_DPDK_TXQ_SIZE];
- num_bufs = rte_ring_free_count(q->freebufs);
- if (num_bufs > 0) {
- num_bufs = num_bufs > UHD_DPDK_TXQ_SIZE ? UHD_DPDK_TXQ_SIZE : num_bufs;
- int buf_stat = rte_pktmbuf_alloc_bulk(port->parent->tx_pktbuf_pool, bufs, num_bufs);
- if (buf_stat) {
- RTE_LOG(ERR, USER1, "%s: Cannot allocate packet buffers\n", __func__);
- goto unwind_txq;
- }
- unsigned int enqd = rte_ring_enqueue_bulk(q->freebufs, (void **) bufs, num_bufs, NULL);
- if (enqd != num_bufs) {
- RTE_LOG(ERR, USER1, "%s: Cannot enqueue freebufs\n", __func__);
- goto unwind_txq;
- }
- }
- } while (num_bufs > 0);
- LIST_INSERT_HEAD(&port->txq_list, q, entry);
- *queue = q;
- return 0;
-
-unwind_txq:
- while (!rte_ring_empty(q->freebufs)) {
- struct rte_mbuf *buf;
- if (rte_ring_dequeue(q->freebufs, (void **) &buf) == 0)
- rte_free(buf);
- }
- rte_ring_free(q->freebufs);
- rte_ring_free(q->queue);
- rte_ring_free(q->retry_queue);
- rte_free(q);
- return -ENOENT;
-}
-
-/* Finish setting up UDP socket (unless ARP needs to be done)
- * Not multi-thread safe!
- * This call should only be used by the thread servicing the port
- * In addition, the code below assumes simplex sockets and unique receive ports
- * FIXME: May need some way to help clean up abandoned socket requests (refcnt check...)
- */
-int _uhd_dpdk_udp_setup(struct uhd_dpdk_config_req *req)
-{
- int retval = 0;
- struct uhd_dpdk_socket *sock = req->sock;
- struct uhd_dpdk_udp_priv *pdata = sock->priv;
- struct uhd_dpdk_port *port = req->sock->port;
-
- struct uhd_dpdk_ipv4_5tuple ht_key = {
- .sock_type = UHD_DPDK_SOCK_UDP,
- .src_ip = 0,
- .src_port = 0,
- .dst_ip = 0,
- .dst_port = pdata->dst_port
- };
-
- /* Are we doing RX? */
- if (sock->rx_ring) {
- /* Add to rx table */
- if (pdata->dst_port == 0) {
- /* Assign unused one in a very slow fashion */
- for (uint16_t i = MAX_UDP_PORT; i > 0; i--) {
- ht_key.dst_port = htons(i);
- if (rte_hash_lookup(port->rx_table, &ht_key) == -ENOENT) {
- pdata->dst_port = htons(i);
- break;
- }
- }
- }
-
- /* Is the port STILL invalid? */
- if (pdata->dst_port == 0) {
- RTE_LOG(ERR, USER1, "%s: No available UDP ports\n", __func__);
- _uhd_dpdk_config_req_compl(req, -EADDRINUSE);
- return -EADDRINUSE;
- }
-
- ht_key.dst_port = pdata->dst_port;
- if (rte_hash_lookup(port->rx_table, &ht_key) > 0) {
- RTE_LOG(ERR, USER1, "%s: Cannot add to RX table\n", __func__);
- _uhd_dpdk_config_req_compl(req, -EADDRINUSE);
- return -EADDRINUSE;
- }
-
- size_t num_bufs = (pdata->xferd_pkts < (UHD_DPDK_RX_BURST_SIZE + 1)) ?
- UHD_DPDK_RX_BURST_SIZE + 1 : pdata->xferd_pkts;
- pdata->xferd_pkts = 0;
- char name[32];
- snprintf(name, sizeof(name), "rx_ring_udp_%u.%u", port->id, ntohs(pdata->dst_port));
- sock->rx_ring = rte_ring_create(
- name,
- num_bufs,
- rte_socket_id(),
- RING_F_SC_DEQ | RING_F_SP_ENQ
- );
- if (!sock->rx_ring) {
- RTE_LOG(ERR, USER1, "%s: Cannot allocate RX ring\n", __func__);
- _uhd_dpdk_config_req_compl(req, -ENOMEM);
- return -ENOMEM;
- }
-
- struct uhd_dpdk_rx_entry *entry = (struct uhd_dpdk_rx_entry *)
- rte_zmalloc(NULL, sizeof(*entry), 0);
- if (!entry) {
- rte_ring_free(sock->rx_ring);
- RTE_LOG(ERR, USER1, "%s: Cannot create RX entry\n", __func__);
- _uhd_dpdk_config_req_compl(req, -ENOMEM);
- return -ENOMEM;
- }
- entry->sock = sock;
- entry->waiter = NULL;
-
- retval = rte_hash_add_key_data(port->rx_table, &ht_key, entry);
- if (retval != 0) {
- RTE_LOG(WARNING, TABLE, "Could not add new RX socket to port %d: %d\n", port->id, retval);
- rte_free(entry);
- rte_ring_free(sock->rx_ring);
- _uhd_dpdk_config_req_compl(req, retval);
- return retval;
- }
- _uhd_dpdk_config_req_compl(req, 0);
- }
-
- /* Are we doing TX? */
- if (sock->tx_queue) {
- size_t num_bufs = (pdata->xferd_pkts < (UHD_DPDK_TX_BURST_SIZE + 1)) ?
- UHD_DPDK_TX_BURST_SIZE + 1 : pdata->xferd_pkts;
- pdata->xferd_pkts = 0;
- sock->tx_queue = NULL;
- struct uhd_dpdk_tx_queue *q = NULL;
- // FIXME Not sharing txq across all thread's sockets for now
- //LIST_FOREACH(q, &port->txq_list, entry) {
- // if (pthread_equal(q->tid, sock->tid)) {
- // LIST_INSERT_HEAD(&q->tx_list, sock, tx_entry);
- // sock->tx_ring = q->queue;
- // sock->rx_ring = q->freebufs;
- // break;
- // }
- //}
- if (!sock->tx_queue) {
- retval = _alloc_txq(port, sock->tid, &q, num_bufs);
- if (retval) {
- _uhd_dpdk_config_req_compl(req, retval);
- return retval;
- }
- sock->tx_queue = q;
- }
- /* If a broadcast type, just finish setup and return */
- if (is_broadcast(port, pdata->dst_ipv4_addr)) {
- LIST_INSERT_HEAD(&q->tx_list, sock, tx_entry);
- _uhd_dpdk_config_req_compl(req, 0);
- return 0;
- }
- /* Otherwise... Check for entry in ARP table */
- struct uhd_dpdk_arp_entry *entry = NULL;
- int arp_table_stat = rte_hash_lookup_data(port->arp_table, &pdata->dst_ipv4_addr, (void **) &entry);
- if (entry) {
- /* Check for null entry */
- if ((entry->mac_addr.addr_bytes[0] == 0xFF) &&
- (entry->mac_addr.addr_bytes[1] == 0xFF) &&
- (entry->mac_addr.addr_bytes[2] == 0xFF) &&
- (entry->mac_addr.addr_bytes[3] == 0xFF) &&
- (entry->mac_addr.addr_bytes[4] == 0xFF) &&
- (entry->mac_addr.addr_bytes[5] == 0xFF)) {
- arp_table_stat = -ENOENT;
- }
- } else {
- /* No entry -> Add null entry */
- entry = rte_zmalloc(NULL, sizeof(*entry), 0);
- if (!entry) {
- RTE_LOG(ERR, USER1, "%s: Cannot allocate ARP entry\n", __func__);
- _uhd_dpdk_config_req_compl(req, -ENOMEM);
- return -ENOMEM;
- }
- memset(entry->mac_addr.addr_bytes, 0xFF, ETHER_ADDR_LEN);
- LIST_INIT(&entry->pending_list);
-
- if (rte_hash_add_key_data(port->arp_table, &pdata->dst_ipv4_addr, entry) < 0) {
- rte_free(entry);
- RTE_LOG(ERR, USER1, "%s: Cannot add entry to ARP table\n", __func__);
- _uhd_dpdk_config_req_compl(req, -ENOMEM);
- return -ENOMEM;
- }
- }
-
- /* Was there a valid address? */
- if (arp_table_stat == -ENOENT) {
- /* Get valid address and have requestor continue waiting */
- int arp_stat = 0;
- do { /* Keep trying to send request if no descriptor */
- arp_stat = _uhd_dpdk_arp_request(port, pdata->dst_ipv4_addr);
- } while (arp_stat == -EAGAIN);
-
- if (arp_stat) {
- /* Config request errors out */
- RTE_LOG(ERR, USER1, "%s: Cannot make ARP request\n", __func__);
- _uhd_dpdk_config_req_compl(req, arp_stat);
- return arp_stat;
- }
- /* Append req to pending list. Will signal later. */
- LIST_INSERT_HEAD(&entry->pending_list, req, entry);
- LIST_INSERT_HEAD(&q->tx_list, sock, tx_entry);
- } else {
- /* We have a valid address. All good. */
- LIST_INSERT_HEAD(&q->tx_list, sock, tx_entry);
- _uhd_dpdk_config_req_compl(req, 0);
- }
- }
- return 0;
-}
-
-int _uhd_dpdk_udp_release(struct uhd_dpdk_config_req *req)
-{
- struct uhd_dpdk_socket *sock = req->sock;
- if (req->sock == NULL) {
- RTE_LOG(ERR, USER1, "%s: no sock in req\n", __func__);
- return -EINVAL;
- }
- struct uhd_dpdk_port *port = req->sock->port;
- struct uhd_dpdk_config_req *conf_req = NULL;
- struct uhd_dpdk_udp_priv *pdata = (struct uhd_dpdk_udp_priv *) sock->priv;
- if (pdata == NULL) {
- RTE_LOG(ERR, USER1, "%s: no pdata in sock\n", __func__);
- return -EINVAL;
- }
- if (sock->tx_queue) {
- // FIXME not sharing buffers anymore
- LIST_REMOVE(sock->tx_queue, entry);
- rte_ring_free(sock->tx_queue->queue);
- rte_ring_free(sock->tx_queue->retry_queue);
-
- /* Remove from tx_list */
- LIST_REMOVE(sock, tx_entry);
- /* Check for entry in ARP table */
- struct uhd_dpdk_arp_entry *entry = NULL;
- rte_hash_lookup_data(port->arp_table, &pdata->dst_ipv4_addr, (void **) &entry);
- if (entry) {
- LIST_FOREACH(conf_req, &entry->pending_list, entry) {
- if (conf_req->sock == sock) {
- LIST_REMOVE(conf_req, entry);
- break;
- }
- }
- }
-
- // FIXME not sharing buffers anymore
- // Remove outstanding buffers from TX queue's freebufs */
- unsigned int bufs = rte_ring_count(sock->tx_queue->freebufs);
- for (unsigned int i = 0; i < bufs; i++) {
- struct rte_mbuf *buf = NULL;
- if (rte_ring_dequeue(sock->tx_queue->freebufs, (void **) &buf)) {
- RTE_LOG(ERR, USER1, "%s: Could not dequeue freebufs\n", __func__);
- } else if (buf) {
- rte_pktmbuf_free(buf);
- }
- }
- rte_ring_free(sock->tx_queue->freebufs);
- rte_free(sock->tx_queue);
-
- /* Add outstanding buffers back to TX queue's freebufs */
- //struct rte_mbuf *freebufs[UHD_DPDK_TXQ_SIZE];
- //int status = rte_pktmbuf_alloc_bulk(port->parent->tx_pktbuf_pool, freebufs, sock->tx_buf_count);
- //if (status) {
- // RTE_LOG(ERR, USER1, "%d %s: Could not restore %u TX buffers in bulk!\n", status, __func__, sock->tx_buf_count);
- //}
-
- //unsigned int enqd = rte_ring_enqueue_bulk(sock->rx_ring, (void **) freebufs, sock->tx_buf_count, NULL);
- //if (enqd != (unsigned int) sock->tx_buf_count) {
- // RTE_LOG(ERR, USER1, "%s: Could not enqueue TX buffers!\n", __func__);
- // return status;
- //}
- } else if (sock->rx_ring) {
- struct uhd_dpdk_ipv4_5tuple ht_key = {
- .sock_type = UHD_DPDK_SOCK_UDP,
- .src_ip = 0,
- .src_port = 0,
- .dst_ip = 0,
- .dst_port = pdata->dst_port
- };
- struct uhd_dpdk_rx_entry *entry = NULL;
- rte_hash_lookup_data(port->rx_table, &ht_key, (void **) &entry);
- if (entry) {
- if (entry->waiter)
- uhd_dpdk_waiter_put(entry->waiter);
- rte_free(entry);
- }
- rte_hash_del_key(port->rx_table, &ht_key);
- struct rte_mbuf *mbuf = NULL;
- while (rte_ring_dequeue(sock->rx_ring, (void **) &mbuf) == 0) {
- rte_pktmbuf_free(mbuf);
- }
- rte_ring_free(sock->rx_ring);
- }
-
- _uhd_dpdk_config_req_compl(req, 0);
- return 0;
-}
-
-int _uhd_dpdk_udp_rx_key(struct uhd_dpdk_socket *sock,
- struct uhd_dpdk_ipv4_5tuple *key)
-{
- struct uhd_dpdk_udp_priv *pdata = (struct uhd_dpdk_udp_priv *) sock->priv;
- if (!pdata)
- return -EINVAL;
- key->sock_type = UHD_DPDK_SOCK_UDP;
- key->src_ip = 0;
- key->src_port = 0;
- key->dst_ip = 0;
- key->dst_port = pdata->dst_port;
- return 0;
-}
-
-/* Configure a socket for UDP
- */
-void uhd_dpdk_udp_open(struct uhd_dpdk_config_req *req,
- struct uhd_dpdk_sockarg_udp *arg)
-{
- if (!req)
- return;
-
- if (!arg) {
- req->retval = -EINVAL;
- return;
- }
-
- struct uhd_dpdk_socket *sock = req->sock;
- sock->tid = pthread_self();
-
- /* Create private data */
- struct uhd_dpdk_udp_priv *data = (struct uhd_dpdk_udp_priv *) rte_zmalloc(NULL, sizeof(*data), 0);
- if (!data) {
- req->retval = -ENOMEM;
- return;
- }
- sock->priv = data;
-
- data->dst_ipv4_addr = arg->dst_addr;
- if (arg->is_tx) {
- data->src_port = arg->local_port;
- data->dst_port = arg->remote_port;
- sock->tx_queue = (struct uhd_dpdk_tx_queue *) sock;
- data->xferd_pkts = arg->num_bufs;
- } else {
- data->src_port = arg->remote_port;
- data->dst_port = arg->local_port;
- sock->rx_ring = (struct rte_ring *) sock;
- data->xferd_pkts = arg->num_bufs;
- data->filter_bcast = arg->filter_bcast;
- }
-
- /* TODO: Add support for I/O thread calling (skip locking and sleep) */
- /* Add to port's config queue */
- int status = uhd_dpdk_config_req_submit(req, -1, sock->port->parent);
- if (status)
- req->retval = status;
-
- if (req->retval)
- rte_free(data);
-}
-
-void uhd_dpdk_udp_close(struct uhd_dpdk_config_req *req)
-{
- if (!req)
- return;
-
- uhd_dpdk_config_req_submit(req, -1, req->sock->port->parent);
- rte_free(req->sock->priv);
-}
-
-/*
- * Note: I/O thread will fill in destination MAC address (doesn't happen here)
- */
-static void uhd_dpdk_ipv4_prep(struct uhd_dpdk_port *port,
- struct rte_mbuf *mbuf,
- uint32_t dst_ipv4_addr,
- uint8_t proto_id,
- uint32_t payload_len)
-{
- struct ether_hdr *eth_hdr = rte_pktmbuf_mtod(mbuf, struct ether_hdr *);
- struct ipv4_hdr *ip_hdr = (struct ipv4_hdr *) &eth_hdr[1];
-
- ether_addr_copy(&port->mac_addr, &eth_hdr->s_addr);
- eth_hdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
-
- ip_hdr->version_ihl = 0x40 | 5;
- ip_hdr->type_of_service = 0;
- ip_hdr->total_length = rte_cpu_to_be_16(20 + payload_len);
- ip_hdr->packet_id = 0;
- ip_hdr->fragment_offset = rte_cpu_to_be_16(IPV4_HDR_DF_FLAG);
- ip_hdr->time_to_live = 64;
- ip_hdr->next_proto_id = proto_id;
- ip_hdr->hdr_checksum = 0; // Require HW offload
- ip_hdr->src_addr = port->ipv4_addr;
- ip_hdr->dst_addr = dst_ipv4_addr;
-
- mbuf->ol_flags = PKT_TX_IP_CKSUM | PKT_TX_IPV4;
- mbuf->l2_len = sizeof(struct ether_hdr);
- mbuf->l3_len = sizeof(struct ipv4_hdr);
- mbuf->pkt_len = sizeof(struct ether_hdr) + sizeof(struct ipv4_hdr) + payload_len;
- mbuf->data_len = sizeof(struct ether_hdr) + sizeof(struct ipv4_hdr) + payload_len;
-}
-
-int uhd_dpdk_udp_prep(struct uhd_dpdk_socket *sock,
- struct rte_mbuf *mbuf)
-{
- struct ether_hdr *eth_hdr;
- struct ipv4_hdr *ip_hdr;
- struct udp_hdr *tx_hdr;
- struct uhd_dpdk_port *port = sock->port;
- struct uhd_dpdk_udp_priv *pdata = (struct uhd_dpdk_udp_priv *) sock->priv;
-
- if (unlikely(mbuf == NULL || pdata == NULL || port == NULL))
- return -EINVAL;
-
- uint32_t udp_data_len = mbuf->data_len;
- uhd_dpdk_ipv4_prep(port,
- mbuf,
- pdata->dst_ipv4_addr,
- 0x11,
- 8 + udp_data_len);
-
- eth_hdr = rte_pktmbuf_mtod(mbuf, struct ether_hdr *);
- ip_hdr = (struct ipv4_hdr *) &eth_hdr[1];
- tx_hdr = (struct udp_hdr *) &ip_hdr[1];
-
- tx_hdr->src_port = pdata->src_port;
- tx_hdr->dst_port = pdata->dst_port;
- tx_hdr->dgram_len = rte_cpu_to_be_16(8 + udp_data_len);
- tx_hdr->dgram_cksum = 0;
- mbuf->l4_len = sizeof(struct udp_hdr);
-
- return 0;
-}
-
-int uhd_dpdk_udp_get_info(struct uhd_dpdk_socket *sock,
- struct uhd_dpdk_sockarg_udp *sockarg)
-{
- if (unlikely(sock == NULL || sockarg == NULL))
- return -EINVAL;
- if (sock->sock_type != UHD_DPDK_SOCK_UDP)
- return -EINVAL;
-
- struct uhd_dpdk_udp_priv *pdata = (struct uhd_dpdk_udp_priv *) sock->priv;
- if (sock->tx_queue) {
- sockarg->is_tx = true;
- sockarg->local_port = pdata->src_port;
- sockarg->remote_port = pdata->dst_port;
- sockarg->dst_addr = pdata->dst_ipv4_addr;
- } else {
- sockarg->is_tx = false;
- sockarg->local_port = pdata->dst_port;
- sockarg->remote_port = pdata->src_port;
- sockarg->dst_addr = 0;
- }
- return 0;
-}
-