diff options
Diffstat (limited to 'host/lib/transport/uhd-dpdk/uhd_dpdk_driver.c')
-rw-r--r-- | host/lib/transport/uhd-dpdk/uhd_dpdk_driver.c | 624 |
1 files changed, 0 insertions, 624 deletions
diff --git a/host/lib/transport/uhd-dpdk/uhd_dpdk_driver.c b/host/lib/transport/uhd-dpdk/uhd_dpdk_driver.c deleted file mode 100644 index 7b4cf8df5..000000000 --- a/host/lib/transport/uhd-dpdk/uhd_dpdk_driver.c +++ /dev/null @@ -1,624 +0,0 @@ -// -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// -#include "uhd_dpdk_driver.h" -#include "uhd_dpdk_fops.h" -#include "uhd_dpdk_udp.h" -#include "uhd_dpdk_wait.h" -#include <rte_malloc.h> -#include <rte_mempool.h> -#include <arpa/inet.h> -#include <unistd.h> - -int _uhd_dpdk_arp_reply(struct uhd_dpdk_port *port, struct arp_hdr *arp_req) -{ - struct rte_mbuf *mbuf; - struct ether_hdr *hdr; - struct arp_hdr *arp_frame; - - mbuf = rte_pktmbuf_alloc(port->parent->tx_pktbuf_pool); - if (unlikely(mbuf == NULL)) { - RTE_LOG(WARNING, MEMPOOL, "Could not allocate packet buffer for ARP response\n"); - return -ENOMEM; - } - - hdr = rte_pktmbuf_mtod(mbuf, struct ether_hdr *); - arp_frame = (struct arp_hdr *) &hdr[1]; - - ether_addr_copy(&arp_req->arp_data.arp_sha, &hdr->d_addr); - ether_addr_copy(&port->mac_addr, &hdr->s_addr); - hdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_ARP); - - arp_frame->arp_hrd = rte_cpu_to_be_16(ARP_HRD_ETHER); - arp_frame->arp_pro = rte_cpu_to_be_16(ETHER_TYPE_IPv4); - arp_frame->arp_hln = 6; - arp_frame->arp_pln = 4; - arp_frame->arp_op = rte_cpu_to_be_16(ARP_OP_REPLY); - ether_addr_copy(&port->mac_addr, &arp_frame->arp_data.arp_sha); - arp_frame->arp_data.arp_sip = port->ipv4_addr; - ether_addr_copy(&hdr->d_addr, &arp_frame->arp_data.arp_tha); - arp_frame->arp_data.arp_tip = arp_req->arp_data.arp_sip; - - mbuf->pkt_len = 42; - mbuf->data_len = 42; - - if (rte_eth_tx_burst(port->id, 0, &mbuf, 1) != 1) { - RTE_LOG(WARNING, RING, "%s: TX descriptor ring is full\n", __func__); - rte_pktmbuf_free(mbuf); - return -EAGAIN; - } - return 0; -} - -int _uhd_dpdk_process_arp(struct uhd_dpdk_port *port, struct arp_hdr *arp_frame) -{ - uint32_t dest_ip = arp_frame->arp_data.arp_sip; - struct ether_addr dest_addr = arp_frame->arp_data.arp_sha; - - /* Add entry to ARP table */ - struct uhd_dpdk_arp_entry *entry = NULL; - rte_hash_lookup_data(port->arp_table, &dest_ip, (void **) &entry); - if (!entry) { - entry = rte_zmalloc(NULL, sizeof(*entry), 0); - if (!entry) { - return -ENOMEM; - } - LIST_INIT(&entry->pending_list); - ether_addr_copy(&dest_addr, &entry->mac_addr); - if (rte_hash_add_key_data(port->arp_table, &dest_ip, entry) < 0) { - rte_free(entry); - return -ENOSPC; - } - } else { - struct uhd_dpdk_config_req *req = NULL; - ether_addr_copy(&dest_addr, &entry->mac_addr); - /* Now wake any config reqs waiting for the ARP */ - LIST_FOREACH(req, &entry->pending_list, entry) { - _uhd_dpdk_config_req_compl(req, 0); - } - while (entry->pending_list.lh_first != NULL) { - LIST_REMOVE(entry->pending_list.lh_first, entry); - } - } - - /* Respond if this was an ARP request */ - if (arp_frame->arp_op == rte_cpu_to_be_16(ARP_OP_REQUEST) && - arp_frame->arp_data.arp_tip == port->ipv4_addr) { - _uhd_dpdk_arp_reply(port, arp_frame); - } - - return 0; -} - -/* Send ARP request */ -int _uhd_dpdk_arp_request(struct uhd_dpdk_port *port, uint32_t ip) -{ - struct rte_mbuf *mbuf; - struct ether_hdr *hdr; - struct arp_hdr *arp_frame; - - mbuf = rte_pktmbuf_alloc(port->parent->tx_pktbuf_pool); - if (unlikely(mbuf == NULL)) { - RTE_LOG(WARNING, MEMPOOL, "Could not allocate packet buffer for ARP request\n"); - return -ENOMEM; - } - - hdr = rte_pktmbuf_mtod(mbuf, struct ether_hdr *); - arp_frame = (struct arp_hdr *) &hdr[1]; - - memset(hdr->d_addr.addr_bytes, 0xFF, ETHER_ADDR_LEN); - ether_addr_copy(&port->mac_addr, &hdr->s_addr); - hdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_ARP); - - arp_frame->arp_hrd = rte_cpu_to_be_16(ARP_HRD_ETHER); - arp_frame->arp_pro = rte_cpu_to_be_16(ETHER_TYPE_IPv4); - arp_frame->arp_hln = 6; - arp_frame->arp_pln = 4; - arp_frame->arp_op = rte_cpu_to_be_16(ARP_OP_REQUEST); - ether_addr_copy(&port->mac_addr, &arp_frame->arp_data.arp_sha); - arp_frame->arp_data.arp_sip = port->ipv4_addr; - memset(arp_frame->arp_data.arp_tha.addr_bytes, 0x00, ETHER_ADDR_LEN); - arp_frame->arp_data.arp_tip = ip; - - mbuf->pkt_len = 42; - mbuf->data_len = 42; - - if (rte_eth_tx_burst(port->id, 0, &mbuf, 1) != 1) { - RTE_LOG(WARNING, RING, "%s: TX descriptor ring is full\n", __func__); - rte_pktmbuf_free(mbuf); - return -EAGAIN; - } - return 0; -} - -int _uhd_dpdk_process_udp(struct uhd_dpdk_port *port, struct rte_mbuf *mbuf, - struct udp_hdr *pkt, bool bcast) -{ - int status = 0; - struct uhd_dpdk_ipv4_5tuple ht_key = { - .sock_type = UHD_DPDK_SOCK_UDP, - .src_ip = 0, - .src_port = 0, - .dst_ip = 0, - .dst_port = pkt->dst_port - }; - - struct uhd_dpdk_rx_entry *entry = NULL; - rte_hash_lookup_data(port->rx_table, &ht_key, (void **) &entry); - if (!entry) { - status = -ENODEV; - //RTE_LOG(WARNING, USER1, "%s: Dropping packet to UDP port %d\n", __func__, ntohs(pkt->dst_port)); - goto udp_rx_drop; - } - - struct uhd_dpdk_udp_priv *pdata = (struct uhd_dpdk_udp_priv *) entry->sock->priv; - if (bcast && pdata->filter_bcast) { - // Filter broadcast packets if not listening - goto udp_rx_drop; - } - status = rte_ring_enqueue(entry->sock->rx_ring, mbuf); - if (entry->waiter) { - _uhd_dpdk_waiter_wake(entry->waiter, port->parent); - entry->waiter = NULL; - } - if (status) { - pdata->dropped_pkts++; - goto udp_rx_drop; - } - pdata->xferd_pkts++; - return 0; - -udp_rx_drop: - rte_pktmbuf_free(mbuf); - return status; -} - -int _uhd_dpdk_process_ipv4(struct uhd_dpdk_port *port, struct rte_mbuf *mbuf, - struct ipv4_hdr *pkt) -{ - bool bcast = is_broadcast(port, pkt->dst_addr); - if (pkt->dst_addr != port->ipv4_addr && !bcast) { - rte_pktmbuf_free(mbuf); - return -ENODEV; - } - if (pkt->next_proto_id == 0x11) { - return _uhd_dpdk_process_udp(port, mbuf, (struct udp_hdr *) &pkt[1], bcast); - } - rte_pktmbuf_free(mbuf); - return -EINVAL; -} - -static int _uhd_dpdk_fill_ipv4_addr(struct uhd_dpdk_port *port, - struct rte_mbuf *mbuf) -{ - struct ether_hdr *eth_hdr = rte_pktmbuf_mtod(mbuf, struct ether_hdr *); - struct ipv4_hdr *ip_hdr = (struct ipv4_hdr *) ð_hdr[1]; - if (is_broadcast(port, ip_hdr->dst_addr)) { - memset(eth_hdr->d_addr.addr_bytes, 0xff, ETHER_ADDR_LEN); - } else { - /* Lookup dest_addr */ - struct uhd_dpdk_arp_entry *entry = NULL; - rte_hash_lookup_data(port->arp_table, &ip_hdr->dst_addr, (void **) &entry); - if (!entry) { - RTE_LOG(ERR, USER1, "TX packet on port %d to addr 0x%08x has no ARP entry\n", port->id, ip_hdr->dst_addr); - return -ENODEV; - } - - ether_addr_copy(&entry->mac_addr, ð_hdr->d_addr); - } - return 0; -} - -static int _uhd_dpdk_send(struct uhd_dpdk_port *port, - struct uhd_dpdk_tx_queue *txq, - struct rte_ring *q) -{ - struct rte_mbuf *buf; - - unsigned int num_tx = rte_ring_count(q); - num_tx = (num_tx < UHD_DPDK_TX_BURST_SIZE) ? num_tx : UHD_DPDK_TX_BURST_SIZE; - for (unsigned int i = 0; i < num_tx; i++) { - int status = rte_ring_dequeue(q, (void **) &buf); - if (status) { - RTE_LOG(ERR, USER1, "%s: Q Count doesn't match actual\n", __func__); - break; - } - struct ether_hdr *eth_hdr = rte_pktmbuf_mtod(buf, struct ether_hdr *); - if (eth_hdr->ether_type == rte_cpu_to_be_16(ETHER_TYPE_IPv4)) { - status = _uhd_dpdk_fill_ipv4_addr(port, buf); - if (status) { - return status; - } - } - - status = rte_eth_tx_prepare(port->id, 0, &buf, 1); - if (status != 1) { - status = rte_ring_enqueue(txq->retry_queue, buf); - if (status) { - RTE_LOG(WARNING, USER1, "%s: Could not re-enqueue pkt %d\n", __func__, i); - rte_pktmbuf_free(buf); - } - num_tx = i; - break; - } - - status = rte_eth_tx_burst(port->id, 0, &buf, 1); /* Automatically frees mbuf */ - if (status != 1) { - status = rte_ring_enqueue(txq->retry_queue, buf); - if (status) { - RTE_LOG(WARNING, USER1, "%s: Could not re-enqueue pkt %d\n", __func__, i); - rte_pktmbuf_free(buf); - } - num_tx = i; - break; - } - } - - return num_tx; -} - -static inline int _uhd_dpdk_restore_bufs(struct uhd_dpdk_port *port, - struct uhd_dpdk_tx_queue *q, - unsigned int num_bufs) -{ - /* Allocate more buffers to replace the sent ones */ - struct rte_mbuf *freebufs[UHD_DPDK_TXQ_SIZE]; - int status = rte_pktmbuf_alloc_bulk(port->parent->tx_pktbuf_pool, freebufs, num_bufs); - if (status) { - RTE_LOG(ERR, USER1, "%d %s: Could not restore %u pktmbufs in bulk!\n", status, __func__, num_bufs); - } - - /* Enqueue the buffers for the user thread to retrieve */ - unsigned int enqd = rte_ring_enqueue_bulk(q->freebufs, (void **) freebufs, num_bufs, NULL); - if (q->waiter && rte_ring_count(q->freebufs) > 0) { - _uhd_dpdk_waiter_wake(q->waiter, port->parent); - q->waiter = NULL; - } - if (enqd != num_bufs) { - RTE_LOG(ERR, USER1, "Could not enqueue pktmbufs!\n"); - return status; - } - - return num_bufs; -} - -static inline void _uhd_dpdk_disable_ports(struct uhd_dpdk_thread *t) -{ - struct uhd_dpdk_port *port = NULL; - LIST_FOREACH(port, &t->port_list, port_entry) { - rte_eth_dev_stop(port->id); - } -} - -static inline int _uhd_dpdk_driver_cleanup(struct uhd_dpdk_thread *t) -{ - /* Close sockets upon request, but reply to other service requests with - * errors - */ - struct uhd_dpdk_config_req *sock_req; - if (rte_ring_dequeue(t->sock_req_ring, (void **) &sock_req)) { - switch (sock_req->req_type) { - case UHD_DPDK_SOCK_CLOSE: - _uhd_dpdk_sock_release(sock_req); - break; - default: - _uhd_dpdk_config_req_compl(sock_req, -ENODEV); - break; - } - } - - /* Do nothing if there are users remaining */ - struct uhd_dpdk_port *port = NULL; - LIST_FOREACH(port, &t->port_list, port_entry) { - /* Check for RX sockets */ - const void *hash_key; - void *hash_sock; - uint32_t hash_next = 0; - if (rte_hash_iterate(port->rx_table, &hash_key, - &hash_sock, &hash_next) != -ENOENT) - return -EAGAIN; - - /* Check for TX sockets */ - struct uhd_dpdk_tx_queue *q = NULL; - LIST_FOREACH(q, &port->txq_list, entry) { - if (!LIST_EMPTY(&q->tx_list)) - return -EAGAIN; - } - } - - /* Now clean up waiters - * TODO: Determine if better to wake threads - */ - int num_waiters = rte_ring_count(t->waiter_ring); - for (int i = 0; i < num_waiters; i++) { - struct uhd_dpdk_wait_req *req = NULL; - rte_ring_dequeue(t->waiter_ring, (void **) &req); - uhd_dpdk_waiter_put(req); - } - if (rte_ring_count(t->waiter_ring)) - return -EAGAIN; - - /* Now can free memory, except sock_req_ring and waiter_ring */ - LIST_FOREACH(port, &t->port_list, port_entry) { - rte_hash_free(port->rx_table); - - struct uhd_dpdk_tx_queue *q = LIST_FIRST(&port->txq_list); - while (!LIST_EMPTY(&port->txq_list)) { - struct uhd_dpdk_tx_queue *nextq = LIST_NEXT(q, entry); - while (!rte_ring_empty(q->queue)) { - struct rte_buf *buf = NULL; - rte_ring_dequeue(q->queue, (void **) &buf); - rte_free(buf); - } - while (!rte_ring_empty(q->freebufs)) { - struct rte_buf *buf = NULL; - rte_ring_dequeue(q->freebufs, (void **) &buf); - rte_free(buf); - } - while (!rte_ring_empty(q->retry_queue)) { - struct rte_buf *buf = NULL; - rte_ring_dequeue(q->retry_queue, (void **) &buf); - rte_free(buf); - } - rte_ring_free(q->queue); - rte_ring_free(q->freebufs); - rte_ring_free(q->retry_queue); - rte_free(q); - q = nextq; - } - - const void *arp_key; - uint32_t arp_key_next = 0; - struct uhd_dpdk_arp_entry *arp_entry = NULL; - while (rte_hash_iterate(port->arp_table, &arp_key, - (void **) &arp_entry, &arp_key_next) >= 0) { - rte_free(arp_entry); - } - rte_hash_free(port->arp_table); - } - - return 0; -} - -static inline int _uhd_dpdk_service_config_req(struct rte_ring *sock_req_ring) -{ - int status = 0; - struct uhd_dpdk_config_req *sock_req; - if (rte_ring_dequeue(sock_req_ring, (void **) &sock_req) == 0) { - if (sock_req) { - /* FIXME: Not checking return vals */ - switch (sock_req->req_type) { - case UHD_DPDK_SOCK_OPEN: - _uhd_dpdk_sock_setup(sock_req); - break; - case UHD_DPDK_SOCK_CLOSE: - _uhd_dpdk_sock_release(sock_req); - break; - case UHD_DPDK_LCORE_TERM: - RTE_LOG(INFO, EAL, "Terminating lcore %u\n", rte_lcore_id()); - status = 1; - _uhd_dpdk_config_req_compl(sock_req, 0); - break; - default: - RTE_LOG(ERR, USER2, "Invalid socket request %d\n", sock_req->req_type); - break; - } - } else { - RTE_LOG(ERR, USER1, "%s: NULL service request received\n", __func__); - } - } - return status; -} - -/* Do a burst of RX on port */ -static inline void _uhd_dpdk_rx_burst(struct uhd_dpdk_port *port) -{ - struct ether_hdr *hdr; - char *l2_data; - struct rte_mbuf *bufs[UHD_DPDK_RX_BURST_SIZE]; - const uint16_t num_rx = rte_eth_rx_burst(port->id, 0, - bufs, UHD_DPDK_RX_BURST_SIZE); - if (unlikely(num_rx == 0)) { - return; - } - - for (int buf = 0; buf < num_rx; buf++) { - uint64_t ol_flags = bufs[buf]->ol_flags; - hdr = rte_pktmbuf_mtod(bufs[buf], struct ether_hdr *); - l2_data = (char *) &hdr[1]; - switch (rte_be_to_cpu_16(hdr->ether_type)) { - case ETHER_TYPE_ARP: - _uhd_dpdk_process_arp(port, (struct arp_hdr *) l2_data); - rte_pktmbuf_free(bufs[buf]); - break; - case ETHER_TYPE_IPv4: - if ((ol_flags & PKT_RX_IP_CKSUM_MASK) == PKT_RX_IP_CKSUM_BAD) { - RTE_LOG(WARNING, RING, "Buf %d: Bad IP cksum\n", buf); - } else if ((ol_flags & PKT_RX_IP_CKSUM_MASK) == PKT_RX_IP_CKSUM_NONE) { - RTE_LOG(WARNING, RING, "Buf %d: Missing IP cksum\n", buf); - } else { - _uhd_dpdk_process_ipv4(port, bufs[buf], (struct ipv4_hdr *) l2_data); - } - break; - default: - rte_pktmbuf_free(bufs[buf]); - break; - } - } -} - -/* Do a burst of TX on port's tx q */ -static inline int _uhd_dpdk_tx_burst(struct uhd_dpdk_port *port, - struct uhd_dpdk_tx_queue *q) -{ - if (!rte_ring_empty(q->retry_queue)) { - int num_retry = _uhd_dpdk_send(port, q, q->retry_queue); - _uhd_dpdk_restore_bufs(port, q, num_retry); - if (!rte_ring_empty(q->retry_queue)) { - return -EAGAIN; - } - } - if (rte_ring_empty(q->queue)) { - return 0; - } - int num_tx = _uhd_dpdk_send(port, q, q->queue); - if (num_tx > 0) { - _uhd_dpdk_restore_bufs(port, q, num_tx); - return 0; - } else { - return num_tx; - } -} - -/* Process threads requesting to block on RX */ -static inline void _uhd_dpdk_process_rx_wait(struct uhd_dpdk_thread *t, - struct uhd_dpdk_wait_req *req) -{ - struct uhd_dpdk_socket *sock = req->sock; - if (!sock) - goto rx_wait_skip; - if (!sock->port) - goto rx_wait_skip; - if (!sock->port->rx_table) - goto rx_wait_skip; - - if (!rte_ring_empty(sock->rx_ring)) - goto rx_wait_skip; - - struct uhd_dpdk_ipv4_5tuple ht_key; - if (_uhd_dpdk_sock_rx_key(sock, &ht_key)) - goto rx_wait_skip; - - struct uhd_dpdk_rx_entry *entry = NULL; - rte_hash_lookup_data(sock->port->rx_table, &ht_key, (void **) &entry); - entry->waiter = req; - return; - -rx_wait_skip: - _uhd_dpdk_waiter_wake(req, t); -} - -/* Process threads requesting to block on TX bufs*/ -static inline void _uhd_dpdk_process_tx_buf_wait(struct uhd_dpdk_thread *t, - struct uhd_dpdk_wait_req *req) -{ - struct uhd_dpdk_socket *sock = req->sock; - if (!sock) - goto tx_wait_skip; - if (!sock->port) - goto tx_wait_skip; - if (!sock->tx_queue) - goto tx_wait_skip; - - struct uhd_dpdk_tx_queue *q = sock->tx_queue; - if (!q->freebufs || !q->retry_queue || !q->queue) - goto tx_wait_skip; - - if (!rte_ring_empty(q->freebufs)) - goto tx_wait_skip; - - sock->tx_queue->waiter = req; - - // Attempt to restore bufs only if failed before - unsigned int num_bufs = sock->tx_buf_count + rte_ring_count(q->queue) + - rte_ring_count(q->retry_queue); - unsigned int max_bufs = rte_ring_get_capacity(q->freebufs); - if (num_bufs < max_bufs) { - _uhd_dpdk_restore_bufs(sock->port, q, max_bufs - num_bufs); - } - return; - -tx_wait_skip: - _uhd_dpdk_waiter_wake(req, t); -} - -/* Process threads making requests to wait */ -static inline void _uhd_dpdk_process_waiters(struct uhd_dpdk_thread *t) -{ - int num_waiters = rte_ring_count(t->waiter_ring); - num_waiters = (num_waiters > UHD_DPDK_MAX_PENDING_SOCK_REQS) ? - UHD_DPDK_MAX_PENDING_SOCK_REQS : - num_waiters; - for (int i = 0; i < num_waiters; i++) { - /* Dequeue */ - struct uhd_dpdk_wait_req *req = NULL; - if (rte_ring_dequeue(t->waiter_ring, (void **) &req)) - break; - switch (req->reason) { - case UHD_DPDK_WAIT_SIMPLE: - _uhd_dpdk_waiter_wake(req, t); - break; - case UHD_DPDK_WAIT_RX: - _uhd_dpdk_process_rx_wait(t, req); - break; - default: - RTE_LOG(ERR, USER2, "Invalid reason associated with wait request\n"); - _uhd_dpdk_waiter_wake(req, t); - break; - } - } -} - -int _uhd_dpdk_driver_main(void *arg) -{ - - /* Don't currently have use for arguments */ - if (arg) - return -EINVAL; - - /* Check that this is a valid lcore */ - unsigned int lcore_id = rte_lcore_id(); - if (lcore_id == LCORE_ID_ANY) - return -ENODEV; - - /* Check that this lcore has ports */ - struct uhd_dpdk_thread *t = &ctx->threads[lcore_id]; - if (t->lcore != lcore_id) - return -ENODEV; - - pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), - &t->cpu_affinity); - char name[16]; - snprintf(name, sizeof(name), "dpdk-io_%u", lcore_id); - pthread_setname_np(pthread_self(), name); - - RTE_LOG(INFO, USER2, "Thread %d started\n", lcore_id); - int status = 0; - while (!status) { - /* Check for open()/close()/term() requests and service 1 at a time */ - status = _uhd_dpdk_service_config_req(t->sock_req_ring); - /* For each port, attempt to receive packets and process */ - struct uhd_dpdk_port *port = NULL; - LIST_FOREACH(port, &t->port_list, port_entry) { - _uhd_dpdk_rx_burst(port); - } - - /* TODO: Handle waiter_ring - * Also use it for config_req wake retries - * Also take care of RX table with new struct w/ waiter - * (construction, adding, destruction) - */ - _uhd_dpdk_process_waiters(t); - - /* For each port's TX queues, do TX */ - LIST_FOREACH(port, &t->port_list, port_entry) { - struct uhd_dpdk_tx_queue *q = NULL; - LIST_FOREACH(q, &port->txq_list, entry) { - if (_uhd_dpdk_tx_burst(port, q)) - break; - } - } - } - - /* Now turn off ports */ - _uhd_dpdk_disable_ports(t); - - /* Now clean up before exiting */ - int cleaning = -EAGAIN; - while (cleaning == -EAGAIN) { - cleaning = _uhd_dpdk_driver_cleanup(t); - } - return status; -} |