-/******************************************************************************
-*
-* Copyright (c) 2019 Intel.
-*
-* 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.
-*
-*******************************************************************************/
-
-
-/**
- * @brief This file has all definitions for the Ethernet Data Interface Layer
- * @file ethernet.c
- * @ingroup group_lte_source_auxlib
- * @author Intel Corporation
- **/
-
-
-#include <stdio.h>
-#include <string.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <errno.h>
-#include <sys/queue.h>
-#include <err.h>
-#include <assert.h>
-
-#include <linux/limits.h>
-#include <sys/types.h>
-#include <stdlib.h>
-#include <math.h>
-
-#include <rte_config.h>
-#include <rte_common.h>
-#include <rte_log.h>
-#include <rte_memory.h>
-#include <rte_memcpy.h>
-#include <rte_memzone.h>
-#include <rte_eal.h>
-#include <rte_per_lcore.h>
-#include <rte_launch.h>
-#include <rte_atomic.h>
-#include <rte_cycles.h>
-#include <rte_prefetch.h>
-#include <rte_lcore.h>
-#include <rte_per_lcore.h>
-#include <rte_branch_prediction.h>
-#include <rte_interrupts.h>
-#include <rte_pci.h>
-#include <rte_debug.h>
-#include <rte_ether.h>
-#include <rte_ethdev.h>
-#include <rte_ring.h>
-#include <rte_mempool.h>
-#include <rte_mbuf.h>
-#include <rte_errno.h>
-
-#include "ethernet.h"
-#include "ethdi.h"
-
-/* Our mbuf pools. */
-struct rte_mempool *_eth_mbuf_pool = NULL;
-struct rte_mempool *_eth_mbuf_pool_inderect = NULL;
-struct rte_mempool *_eth_mbuf_pool_rx = NULL;
-struct rte_mempool *_eth_mbuf_pool_small = NULL;
-struct rte_mempool *_eth_mbuf_pool_big = NULL;
-
-struct rte_mempool *socket_direct_pool = NULL;
-struct rte_mempool *socket_indirect_pool = NULL;
-
-
-/*
- * Make sure the ring indexes are big enough to cover buf space x2
- * This ring-buffer maintains the property head - tail <= RINGSIZE.
- * head == tail: ring buffer empty
- * head - tail == RINGSIZE: ring buffer full
- */
-typedef uint16_t ring_idx;
-static struct {
- ring_idx head;
- ring_idx read_head;
- ring_idx tail;
- char buf[1024]; /* needs power of 2! */
-} io_ring = { {0}, 0, 0};
-
-#define RINGSIZE sizeof(io_ring.buf)
-#define RINGMASK (RINGSIZE - 1)
-
-int __xran_delayed_msg(const char *fmt, ...)
-{
-#if 0
- va_list ap;
- int msg_len;
- char localbuf[RINGSIZE];
- ring_idx old_head, new_head;
- ring_idx copy_len;
-
- /* first prep a copy of the message on the local stack */
- va_start(ap, fmt);
- msg_len = vsnprintf(localbuf, RINGSIZE, fmt, ap);
- va_end(ap);
-
- /* atomically reserve space in the ring */
- for (;;) {
- old_head = io_ring.head; /* snapshot head */
- /* free always within range of [0, RINGSIZE] - proof by induction */
- const ring_idx free = RINGSIZE - (old_head - io_ring.tail);
-
- copy_len = RTE_MIN(msg_len, free);
- if (copy_len <= 0)
- return 0; /* vsnprintf error or ringbuff full. Drop log. */
-
- new_head = old_head + copy_len;
- RTE_ASSERT((ring_idx)(new_head - io_ring.tail) <= RINGSIZE);
-
- if (likely(__atomic_compare_exchange_n(&io_ring.head, &old_head,
- new_head, 0, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)))
- break;
- }
-
- /* Now copy data in at ease. */
- const int copy_start = (old_head & RINGMASK);
- if (copy_start < (new_head & RINGMASK)) /* no wrap */
- memcpy(io_ring.buf + copy_start, localbuf, copy_len);
- else { /* wrap-around */
- const int chunk_len = RINGSIZE - copy_start;
-
- memcpy(io_ring.buf + copy_start, localbuf, chunk_len);
- memcpy(io_ring.buf, localbuf + chunk_len, copy_len - chunk_len);
- }
-
- /* wait for previous writes to complete before updating read_head. */
- while (io_ring.read_head != old_head)
- rte_pause();
- io_ring.read_head = new_head;
-
-
- return copy_len;
- #endif
- return 0;
-}
-
-/*
- * Display part of the message stored in the ring buffer.
- * Might require multiple calls to print the full message.
- * Will return 0 when nothing left to print.
- */
-#if 0
-int xran_show_delayed_message(void)
-{
- ring_idx tail = io_ring.tail;
- ring_idx wlen = io_ring.read_head - tail; /* always within [0, RINGSIZE] */
-
- if (wlen <= 0)
- return 0;
-
- tail &= RINGMASK; /* modulo the range down now that we have wlen */
-
- /* Make sure we're not going over buffer end. Next call will wrap. */
- if (tail + wlen > RINGSIZE)
- wlen = RINGSIZE - tail;
-
- RTE_ASSERT(tail + wlen <= RINGSIZE);
-
- /* We use write() here to avoid recaculating string length in fwrite(). */
- const ssize_t written = write(STDOUT_FILENO, io_ring.buf + tail, wlen);
- if (written <= 0)
- return 0; /* To avoid moving tail the wrong way on error. */
-
- /* Move tail up. Only we touch it. And we only print from one core. */
- io_ring.tail += written;
-
- return written; /* next invocation will print the rest if any */
-}
-#endif
-
-void xran_init_mbuf_pool(void)
-{
- /* Init the buffer pool */
- if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
- _eth_mbuf_pool = rte_pktmbuf_pool_create("mempool", NUM_MBUFS,
- MBUF_CACHE, 0, MBUF_POOL_ELEMENT, rte_socket_id());
-#ifdef XRAN_ATTACH_MBUF
- _eth_mbuf_pool_inderect = rte_pktmbuf_pool_create("mempool_indirect", NUM_MBUFS,
- MBUF_CACHE, 0, MBUF_POOL_ELEMENT, rte_socket_id());*/
-#endif
- _eth_mbuf_pool_rx = rte_pktmbuf_pool_create("mempool_rx", NUM_MBUFS,
- MBUF_CACHE, 0, MBUF_POOL_ELEMENT, rte_socket_id());
- _eth_mbuf_pool_small = rte_pktmbuf_pool_create("mempool_small",
- NUM_MBUFS, MBUF_CACHE, 0, MBUF_POOL_ELM_SMALL, rte_socket_id());
- _eth_mbuf_pool_big = rte_pktmbuf_pool_create("mempool_big",
- NUM_MBUFS_BIG, 0, 0, MBUF_POOL_ELM_BIG, rte_socket_id());
- } else {
- _eth_mbuf_pool = rte_mempool_lookup("mempool");
- _eth_mbuf_pool_inderect = rte_mempool_lookup("mempool_indirect");
- _eth_mbuf_pool_rx = rte_mempool_lookup("mempool_rx");
- _eth_mbuf_pool_small = rte_mempool_lookup("mempool_small");
- _eth_mbuf_pool_big = rte_mempool_lookup("mempool_big");
- }
- if (_eth_mbuf_pool == NULL)
- rte_panic("Cannot create mbuf pool: %s\n", rte_strerror(rte_errno));
-#ifdef XRAN_ATTACH_MBUF
- if (_eth_mbuf_pool_inderect == NULL)
- rte_panic("Cannot create mbuf pool: %s\n", rte_strerror(rte_errno));
-#endif
- if (_eth_mbuf_pool_rx == NULL)
- rte_panic("Cannot create mbuf pool: %s\n", rte_strerror(rte_errno));
- if (_eth_mbuf_pool_small == NULL)
- rte_panic("Cannot create small mbuf pool: %s\n", rte_strerror(rte_errno));
- if (_eth_mbuf_pool_big == NULL)
- rte_panic("Cannot create big mbuf pool: %s\n", rte_strerror(rte_errno));
-
- if (socket_direct_pool == NULL)
- socket_direct_pool = _eth_mbuf_pool;
-
- if (socket_indirect_pool == NULL)
- socket_indirect_pool = _eth_mbuf_pool_inderect;
-}
-
-/* Init NIC port, then start the port */
-void xran_init_port(int p_id, struct ether_addr *p_lls_cu_addr)
-{
- static uint16_t nb_rxd = BURST_SIZE;
- static uint16_t nb_txd = BURST_SIZE;
- struct ether_addr addr;
- struct rte_eth_rxmode rxmode =
- { .split_hdr_size = 0,
- .max_rx_pkt_len = MAX_RX_LEN,
- .offloads=(DEV_RX_OFFLOAD_JUMBO_FRAME|DEV_RX_OFFLOAD_CRC_STRIP)
- };
- struct rte_eth_txmode txmode = {
- .mq_mode = ETH_MQ_TX_NONE
- };
- struct rte_eth_conf port_conf = {
- .rxmode = rxmode,
- .txmode = txmode
- };
- struct rte_eth_rxconf rxq_conf;
- struct rte_eth_txconf txq_conf;
-
- int ret;
- struct rte_eth_dev_info dev_info;
- const char *drv_name = "";
- int sock_id = rte_eth_dev_socket_id(p_id);
-
- rte_eth_dev_info_get(p_id, &dev_info);
- if (dev_info.driver_name)
- drv_name = dev_info.driver_name;
- printf("initializing port %d for TX, drv=%s\n", p_id, drv_name);
-
- rte_eth_macaddr_get(p_id, &addr);
-
- printf("Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8
- " %02"PRIx8" %02"PRIx8" %02"PRIx8"\n",
- (unsigned)p_id,
- addr.addr_bytes[0], addr.addr_bytes[1], addr.addr_bytes[2],
- addr.addr_bytes[3], addr.addr_bytes[4], addr.addr_bytes[5]);
-
- /* Init port */
- ret = rte_eth_dev_configure(p_id, 1, 1, &port_conf);
- if (ret < 0)
- rte_panic("Cannot configure port %u (%d)\n", p_id, ret);
-
- ret = rte_eth_dev_adjust_nb_rx_tx_desc(p_id, &nb_rxd,&nb_txd);
-
- if (ret < 0) {
- printf("\n");
- rte_exit(EXIT_FAILURE, "Cannot adjust number of "
- "descriptors: err=%d, port=%d\n", ret, p_id);
- }
- printf("Port %u: nb_rxd %d nb_txd %d\n", p_id, nb_rxd, nb_txd);
-
- /* Init RX queues */
- rxq_conf = dev_info.default_rxconf;
- ret = rte_eth_rx_queue_setup(p_id, 0, nb_rxd,
- sock_id, &rxq_conf, _eth_mbuf_pool_rx);
- if (ret < 0)
- rte_panic("Cannot init RX for port %u (%d)\n",
- p_id, ret);
-
- /* Init TX queues */
- txq_conf = dev_info.default_txconf;
- ret = rte_eth_tx_queue_setup(p_id, 0, nb_txd, sock_id, &txq_conf);
- if (ret < 0)
- rte_panic("Cannot init TX for port %u (%d)\n",
- p_id, ret);
-
- /* Start port */
- ret = rte_eth_dev_start(p_id);
- if (ret < 0)
- rte_panic("Cannot start port %u (%d)\n", p_id, ret);
-
-// rte_eth_promiscuous_enable(p_id);
-}
-
-#if 0
-void xran_memdump(void *addr, int len)
-{
- int i;
- char tmp_buf[len * 2 + len / 16 + 1];
- char *p = tmp_buf;
-
- return;
-#if 0
- for (i = 0; i < len; ++i) {
- sprintf(p, "%.2X ", ((uint8_t *)addr)[i]);
- if (i % 16 == 15)
- *p++ = '\n';
- }
- *p = 0;
- nlog("%s", tmp_buf);
-#endif
-}
-
-/* Prepend ethernet header, possibly vlan tag. */
-void xran_add_eth_hdr(struct ether_addr *dst, uint16_t ethertype, struct rte_mbuf *mb)
-{
- /* add in the ethernet header */
- struct ether_hdr *const h = (void *)rte_pktmbuf_prepend(mb, sizeof(*h));
-
- PANIC_ON(h == NULL, "mbuf prepend of ether_hdr failed");
-
- /* Fill in the ethernet header. */
- rte_eth_macaddr_get(mb->port, &h->s_addr); /* set source addr */
- h->d_addr = *dst; /* set dst addr */
- h->ether_type = rte_cpu_to_be_16(ethertype); /* ethertype too */
-
-#if defined(DPDKIO_DEBUG) && DPDKIO_DEBUG > 1
- {
- char dst[ETHER_ADDR_FMT_SIZE] = "(empty)";
- char src[ETHER_ADDR_FMT_SIZE] = "(empty)";
-
- nlog("*** packet for TX below (len %d) ***", rte_pktmbuf_pkt_len(mb));
- ether_format_addr(src, sizeof(src), &h->s_addr);
- ether_format_addr(dst, sizeof(dst), &h->d_addr);
- nlog("src: %s dst: %s ethertype: %.4X", src, dst, ethertype);
- }
-#endif
-#ifdef VLAN_SUPPORT
- mb->vlan_tci = FLEXRAN_UP_VLAN_TAG;
- dlog("Inserting vlan tag of %d", FLEXRAN_UP_VLAN_TAG);
- rte_vlan_insert(&mb);
-#endif
-}
-
-int xran_send_mbuf(struct ether_addr *dst, struct rte_mbuf *mb)
-{
- xran_add_eth_hdr(dst, ETHER_TYPE_ETHDI, mb);
-
- if (rte_eth_tx_burst(mb->port, 0, &mb, 1) == 1)
- return 1;
-
- elog("packet sending failed on port %d", mb->port);
- rte_pktmbuf_free(mb);
-
- return 0; /* fail */
-}
-
-int xran_send_message_burst(int dst_id, int pkt_type, void *body, int len)
-{
- struct rte_mbuf *mbufs[BURST_SIZE];
- int i;
- uint8_t *src = body;
- const struct xran_ethdi_ctx *const ctx = xran_ethdi_get_ctx();
-
- /* We're limited by maximum mbuf size on the receive size.
- * We can change this but this would be a bigger rework. */
- RTE_ASSERT(len < MBUF_POOL_ELM_BIG);
-
- /* Allocate the required number of mbufs. */
- const uint8_t count = ceilf((float)len / MAX_DATA_SIZE);
- if (rte_pktmbuf_alloc_bulk(_eth_mbuf_pool, mbufs, count) != 0)
- rte_panic("Failed to allocate %d mbufs\n", count);
-
- nlog("burst transfer with data size %lu", MAX_DATA_SIZE);
- for (i = 0; len > 0; ++i) {
- char *p;
- struct burst_hdr *bhdr;
- struct ethdi_hdr *edi_hdr;
-
- /* Setup the ethdi_hdr. */
- edi_hdr = (void *)rte_pktmbuf_append(mbufs[i], sizeof(*edi_hdr));
- if (edi_hdr == NULL)
- rte_panic("append of ethdi_hdr failed\n");
- edi_hdr->pkt_type = PKT_BURST;
- /* edi_hdr->source_id setup in tx_from_ring */
- edi_hdr->dest_id = dst_id;
-
- /* Setup the burst header */
- bhdr = (void *)rte_pktmbuf_append(mbufs[i], sizeof(*bhdr));
- if (bhdr == NULL) /* append failed. */
- rte_panic("mbuf prepend of burst_hdr failed\n");
- bhdr->original_type = pkt_type;
- bhdr->pkt_idx = i; /* save the index of the burst chunk. */
- bhdr->total_pkts = count;
-
- /* now copy in the actual data */
- const int curr_data_len = RTE_MIN(len, MAX_TX_LEN -
- rte_pktmbuf_pkt_len(mbufs[i]) - sizeof(struct ether_hdr));
- p = (void *)rte_pktmbuf_append(mbufs[i], curr_data_len);
- if (p == NULL)
- rte_panic("mbuf append of %d data bytes failed\n", curr_data_len);
- /* This copy is unavoidable, as we're splitting one big buffer
- * into multiple mbufs. */
- rte_memcpy(p, src, curr_data_len);
-
- dlog("curr_data_len[%d] = %d", i, curr_data_len);
- dlog("packet %d size %d", i, rte_pktmbuf_pkt_len(mbufs[i]));
-
- /* Update our source data pointer and remaining length. */
- len -= curr_data_len;
- src += curr_data_len;
- }
-
- /* Now enqueue the full prepared burst. */
- i = rte_ring_enqueue_bulk(ctx->tx_ring[0], (void **)mbufs, count, NULL);
- PANIC_ON(i != count, "failed to enqueue all mbufs: %d/%d", i, count);
- dlog("%d packets enqueued on port %d.", count, ctx->io_cfg.port);
-
- return 1;
-}
-
-#endif
-
-/* Prepend ethernet header, possibly vlan tag. */
-void xran_add_eth_hdr_vlan(struct ether_addr *dst, uint16_t ethertype, struct rte_mbuf *mb, uint16_t vlan_tci)
-{
- /* add in the ethernet header */
- struct ether_hdr *h = (struct ether_hdr *)rte_pktmbuf_mtod(mb, struct ether_hdr*);
-
- PANIC_ON(h == NULL, "mbuf prepend of ether_hdr failed");
-
- /* Fill in the ethernet header. */
- rte_eth_macaddr_get(mb->port, &h->s_addr); /* set source addr */
- h->d_addr = *dst; /* set dst addr */
- h->ether_type = rte_cpu_to_be_16(ethertype); /* ethertype too */
-
-#if defined(DPDKIO_DEBUG) && DPDKIO_DEBUG > 1
- {
- char dst[ETHER_ADDR_FMT_SIZE] = "(empty)";
- char src[ETHER_ADDR_FMT_SIZE] = "(empty)";
-
- nlog("*** packet for TX below (len %d) ***", rte_pktmbuf_pkt_len(mb));
- ether_format_addr(src, sizeof(src), &h->s_addr);
- ether_format_addr(dst, sizeof(dst), &h->d_addr);
- nlog("src: %s dst: %s ethertype: %.4X", src, dst, ethertype);
- }
-#endif
-#ifdef VLAN_SUPPORT
- mb->vlan_tci = vlan_tci;
- dlog("Inserting vlan tag of %d", vlan_tci);
- rte_vlan_insert(&mb);
-#endif
-}
-
-
+/******************************************************************************\r
+*\r
+* Copyright (c) 2019 Intel.\r
+*\r
+* Licensed under the Apache License, Version 2.0 (the "License");\r
+* you may not use this file except in compliance with the License.\r
+* You may obtain a copy of the License at\r
+*\r
+* http://www.apache.org/licenses/LICENSE-2.0\r
+*\r
+* Unless required by applicable law or agreed to in writing, software\r
+* distributed under the License is distributed on an "AS IS" BASIS,\r
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+* See the License for the specific language governing permissions and\r
+* limitations under the License.\r
+*\r
+*******************************************************************************/\r
+\r
+/**\r
+ * @brief This file has all definitions for the Ethernet Data Interface Layer\r
+ * @file ethernet.c\r
+ * @ingroup group_lte_source_auxlib\r
+ * @author Intel Corporation\r
+ **/\r
+\r
+\r
+#include <stdio.h>\r
+#include <string.h>\r
+#include <stdint.h>\r
+#include <unistd.h>\r
+#include <errno.h>\r
+#include <sys/queue.h>\r
+#include <err.h>\r
+#include <assert.h>\r
+\r
+#include <linux/limits.h>\r
+#include <sys/types.h>\r
+#include <stdlib.h>\r
+#include <math.h>\r
+\r
+#include <rte_config.h>\r
+#include <rte_common.h>\r
+#include <rte_log.h>\r
+#include <rte_memory.h>\r
+#include <rte_memcpy.h>\r
+#include <rte_memzone.h>\r
+#include <rte_eal.h>\r
+#include <rte_per_lcore.h>\r
+#include <rte_launch.h>\r
+#include <rte_atomic.h>\r
+#include <rte_cycles.h>\r
+#include <rte_prefetch.h>\r
+#include <rte_lcore.h>\r
+#include <rte_per_lcore.h>\r
+#include <rte_branch_prediction.h>\r
+#include <rte_interrupts.h>\r
+#include <rte_pci.h>\r
+#include <rte_debug.h>\r
+#include <rte_ether.h>\r
+#include <rte_ethdev.h>\r
+#include <rte_ring.h>\r
+#include <rte_mempool.h>\r
+#include <rte_mbuf.h>\r
+#include <rte_errno.h>\r
+\r
+#include "ethernet.h"\r
+#include "ethdi.h"\r
+\r
+/* Our mbuf pools. */\r
+struct rte_mempool *_eth_mbuf_pool = NULL;\r
+struct rte_mempool *_eth_mbuf_pool_inderect = NULL;\r
+struct rte_mempool *_eth_mbuf_pool_rx = NULL;\r
+struct rte_mempool *_eth_mbuf_pool_small = NULL;\r
+struct rte_mempool *_eth_mbuf_pool_big = NULL;\r
+\r
+struct rte_mempool *socket_direct_pool = NULL;\r
+struct rte_mempool *socket_indirect_pool = NULL;\r
+\r
+\r
+/*\r
+ * Make sure the ring indexes are big enough to cover buf space x2\r
+ * This ring-buffer maintains the property head - tail <= RINGSIZE.\r
+ * head == tail: ring buffer empty\r
+ * head - tail == RINGSIZE: ring buffer full\r
+ */\r
+typedef uint16_t ring_idx;\r
+static struct {\r
+ ring_idx head;\r
+ ring_idx read_head;\r
+ ring_idx tail;\r
+ char buf[1024]; /* needs power of 2! */\r
+} io_ring = { {0}, 0, 0};\r
+\r
+#define RINGSIZE sizeof(io_ring.buf)\r
+#define RINGMASK (RINGSIZE - 1)\r
+\r
+int __xran_delayed_msg(const char *fmt, ...)\r
+{\r
+#if 0\r
+ va_list ap;\r
+ int msg_len;\r
+ char localbuf[RINGSIZE];\r
+ ring_idx old_head, new_head;\r
+ ring_idx copy_len;\r
+\r
+ /* first prep a copy of the message on the local stack */\r
+ va_start(ap, fmt);\r
+ msg_len = vsnprintf(localbuf, RINGSIZE, fmt, ap);\r
+ va_end(ap);\r
+\r
+ /* atomically reserve space in the ring */\r
+ for (;;) {\r
+ old_head = io_ring.head; /* snapshot head */\r
+ /* free always within range of [0, RINGSIZE] - proof by induction */\r
+ const ring_idx free = RINGSIZE - (old_head - io_ring.tail);\r
+\r
+ copy_len = RTE_MIN(msg_len, free);\r
+ if (copy_len <= 0)\r
+ return 0; /* vsnprintf error or ringbuff full. Drop log. */\r
+\r
+ new_head = old_head + copy_len;\r
+ RTE_ASSERT((ring_idx)(new_head - io_ring.tail) <= RINGSIZE);\r
+\r
+ if (likely(__atomic_compare_exchange_n(&io_ring.head, &old_head,\r
+ new_head, 0, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)))\r
+ break;\r
+ }\r
+\r
+ /* Now copy data in at ease. */\r
+ const int copy_start = (old_head & RINGMASK);\r
+ if (copy_start < (new_head & RINGMASK)) /* no wrap */\r
+ memcpy(io_ring.buf + copy_start, localbuf, copy_len);\r
+ else { /* wrap-around */\r
+ const int chunk_len = RINGSIZE - copy_start;\r
+\r
+ memcpy(io_ring.buf + copy_start, localbuf, chunk_len);\r
+ memcpy(io_ring.buf, localbuf + chunk_len, copy_len - chunk_len);\r
+ }\r
+\r
+ /* wait for previous writes to complete before updating read_head. */\r
+ while (io_ring.read_head != old_head)\r
+ rte_pause();\r
+ io_ring.read_head = new_head;\r
+\r
+\r
+ return copy_len;\r
+ #endif\r
+ return 0;\r
+}\r
+\r
+/*\r
+ * Display part of the message stored in the ring buffer.\r
+ * Might require multiple calls to print the full message.\r
+ * Will return 0 when nothing left to print.\r
+ */\r
+#if 0\r
+int xran_show_delayed_message(void)\r
+{\r
+ ring_idx tail = io_ring.tail;\r
+ ring_idx wlen = io_ring.read_head - tail; /* always within [0, RINGSIZE] */\r
+\r
+ if (wlen <= 0)\r
+ return 0;\r
+\r
+ tail &= RINGMASK; /* modulo the range down now that we have wlen */\r
+\r
+ /* Make sure we're not going over buffer end. Next call will wrap. */\r
+ if (tail + wlen > RINGSIZE)\r
+ wlen = RINGSIZE - tail;\r
+\r
+ RTE_ASSERT(tail + wlen <= RINGSIZE);\r
+\r
+ /* We use write() here to avoid recaculating string length in fwrite(). */\r
+ const ssize_t written = write(STDOUT_FILENO, io_ring.buf + tail, wlen);\r
+ if (written <= 0)\r
+ return 0; /* To avoid moving tail the wrong way on error. */\r
+\r
+ /* Move tail up. Only we touch it. And we only print from one core. */\r
+ io_ring.tail += written;\r
+\r
+ return written; /* next invocation will print the rest if any */\r
+}\r
+#endif\r
+\r
+void xran_init_mbuf_pool(void)\r
+{\r
+ /* Init the buffer pool */\r
+ if (rte_eal_process_type() == RTE_PROC_PRIMARY) {\r
+ _eth_mbuf_pool = rte_pktmbuf_pool_create("mempool", NUM_MBUFS,\r
+ MBUF_CACHE, 0, MBUF_POOL_ELEMENT, rte_socket_id());\r
+#ifdef XRAN_ATTACH_MBUF\r
+ _eth_mbuf_pool_inderect = rte_pktmbuf_pool_create("mempool_indirect", NUM_MBUFS,\r
+ MBUF_CACHE, 0, MBUF_POOL_ELEMENT, rte_socket_id());*/\r
+#endif\r
+ _eth_mbuf_pool_rx = rte_pktmbuf_pool_create("mempool_rx", NUM_MBUFS,\r
+ MBUF_CACHE, 0, MBUF_POOL_ELEMENT, rte_socket_id());\r
+ _eth_mbuf_pool_small = rte_pktmbuf_pool_create("mempool_small",\r
+ NUM_MBUFS, MBUF_CACHE, 0, MBUF_POOL_ELM_SMALL, rte_socket_id());\r
+ _eth_mbuf_pool_big = rte_pktmbuf_pool_create("mempool_big",\r
+ NUM_MBUFS_BIG, 0, 0, MBUF_POOL_ELM_BIG, rte_socket_id());\r
+ } else {\r
+ _eth_mbuf_pool = rte_mempool_lookup("mempool");\r
+ _eth_mbuf_pool_inderect = rte_mempool_lookup("mempool_indirect");\r
+ _eth_mbuf_pool_rx = rte_mempool_lookup("mempool_rx");\r
+ _eth_mbuf_pool_small = rte_mempool_lookup("mempool_small");\r
+ _eth_mbuf_pool_big = rte_mempool_lookup("mempool_big");\r
+ }\r
+ if (_eth_mbuf_pool == NULL)\r
+ rte_panic("Cannot create mbuf pool: %s\n", rte_strerror(rte_errno));\r
+#ifdef XRAN_ATTACH_MBUF\r
+ if (_eth_mbuf_pool_inderect == NULL)\r
+ rte_panic("Cannot create mbuf pool: %s\n", rte_strerror(rte_errno));\r
+#endif\r
+ if (_eth_mbuf_pool_rx == NULL)\r
+ rte_panic("Cannot create mbuf pool: %s\n", rte_strerror(rte_errno));\r
+ if (_eth_mbuf_pool_small == NULL)\r
+ rte_panic("Cannot create small mbuf pool: %s\n", rte_strerror(rte_errno));\r
+ if (_eth_mbuf_pool_big == NULL)\r
+ rte_panic("Cannot create big mbuf pool: %s\n", rte_strerror(rte_errno));\r
+\r
+ if (socket_direct_pool == NULL)\r
+ socket_direct_pool = _eth_mbuf_pool;\r
+\r
+ if (socket_indirect_pool == NULL)\r
+ socket_indirect_pool = _eth_mbuf_pool_inderect;\r
+}\r
+\r
+/* Init NIC port, then start the port */\r
+void xran_init_port(int p_id, struct ether_addr *p_lls_cu_addr)\r
+{\r
+ static uint16_t nb_rxd = BURST_SIZE;\r
+ static uint16_t nb_txd = BURST_SIZE;\r
+ struct ether_addr addr;\r
+ struct rte_eth_rxmode rxmode =\r
+ { .split_hdr_size = 0,\r
+ .max_rx_pkt_len = MAX_RX_LEN,\r
+ .offloads=(DEV_RX_OFFLOAD_JUMBO_FRAME|DEV_RX_OFFLOAD_CRC_STRIP)\r
+ };\r
+ struct rte_eth_txmode txmode = {\r
+ .mq_mode = ETH_MQ_TX_NONE\r
+ };\r
+ struct rte_eth_conf port_conf = {\r
+ .rxmode = rxmode,\r
+ .txmode = txmode\r
+ };\r
+ struct rte_eth_rxconf rxq_conf;\r
+ struct rte_eth_txconf txq_conf;\r
+\r
+ int ret;\r
+ struct rte_eth_dev_info dev_info;\r
+ const char *drv_name = "";\r
+ int sock_id = rte_eth_dev_socket_id(p_id);\r
+\r
+ rte_eth_dev_info_get(p_id, &dev_info);\r
+ if (dev_info.driver_name)\r
+ drv_name = dev_info.driver_name;\r
+ printf("initializing port %d for TX, drv=%s\n", p_id, drv_name);\r
+\r
+ rte_eth_macaddr_get(p_id, &addr);\r
+\r
+ printf("Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8\r
+ " %02"PRIx8" %02"PRIx8" %02"PRIx8"\n",\r
+ (unsigned)p_id,\r
+ addr.addr_bytes[0], addr.addr_bytes[1], addr.addr_bytes[2],\r
+ addr.addr_bytes[3], addr.addr_bytes[4], addr.addr_bytes[5]);\r
+\r
+ /* Init port */\r
+ ret = rte_eth_dev_configure(p_id, 1, 1, &port_conf);\r
+ if (ret < 0)\r
+ rte_panic("Cannot configure port %u (%d)\n", p_id, ret);\r
+\r
+ ret = rte_eth_dev_adjust_nb_rx_tx_desc(p_id, &nb_rxd,&nb_txd);\r
+\r
+ if (ret < 0) {\r
+ printf("\n");\r
+ rte_exit(EXIT_FAILURE, "Cannot adjust number of "\r
+ "descriptors: err=%d, port=%d\n", ret, p_id);\r
+ }\r
+ printf("Port %u: nb_rxd %d nb_txd %d\n", p_id, nb_rxd, nb_txd);\r
+\r
+ /* Init RX queues */\r
+ rxq_conf = dev_info.default_rxconf;\r
+ ret = rte_eth_rx_queue_setup(p_id, 0, nb_rxd,\r
+ sock_id, &rxq_conf, _eth_mbuf_pool_rx);\r
+ if (ret < 0)\r
+ rte_panic("Cannot init RX for port %u (%d)\n",\r
+ p_id, ret);\r
+\r
+ /* Init TX queues */\r
+ txq_conf = dev_info.default_txconf;\r
+ ret = rte_eth_tx_queue_setup(p_id, 0, nb_txd, sock_id, &txq_conf);\r
+ if (ret < 0)\r
+ rte_panic("Cannot init TX for port %u (%d)\n",\r
+ p_id, ret);\r
+\r
+ /* Start port */\r
+ ret = rte_eth_dev_start(p_id);\r
+ if (ret < 0)\r
+ rte_panic("Cannot start port %u (%d)\n", p_id, ret);\r
+\r
+// rte_eth_promiscuous_enable(p_id);\r
+}\r
+\r
+#if 0\r
+void xran_memdump(void *addr, int len)\r
+{\r
+ int i;\r
+ char tmp_buf[len * 2 + len / 16 + 1];\r
+ char *p = tmp_buf;\r
+\r
+ return;\r
+#if 0\r
+ for (i = 0; i < len; ++i) {\r
+ sprintf(p, "%.2X ", ((uint8_t *)addr)[i]);\r
+ if (i % 16 == 15)\r
+ *p++ = '\n';\r
+ }\r
+ *p = 0;\r
+ nlog("%s", tmp_buf);\r
+#endif\r
+}\r
+\r
+/* Prepend ethernet header, possibly vlan tag. */\r
+void xran_add_eth_hdr(struct ether_addr *dst, uint16_t ethertype, struct rte_mbuf *mb)\r
+{\r
+ /* add in the ethernet header */\r
+ struct ether_hdr *const h = (void *)rte_pktmbuf_prepend(mb, sizeof(*h));\r
+\r
+ PANIC_ON(h == NULL, "mbuf prepend of ether_hdr failed");\r
+\r
+ /* Fill in the ethernet header. */\r
+ rte_eth_macaddr_get(mb->port, &h->s_addr); /* set source addr */\r
+ h->d_addr = *dst; /* set dst addr */\r
+ h->ether_type = rte_cpu_to_be_16(ethertype); /* ethertype too */\r
+\r
+#if defined(DPDKIO_DEBUG) && DPDKIO_DEBUG > 1\r
+ {\r
+ char dst[ETHER_ADDR_FMT_SIZE] = "(empty)";\r
+ char src[ETHER_ADDR_FMT_SIZE] = "(empty)";\r
+\r
+ nlog("*** packet for TX below (len %d) ***", rte_pktmbuf_pkt_len(mb));\r
+ ether_format_addr(src, sizeof(src), &h->s_addr);\r
+ ether_format_addr(dst, sizeof(dst), &h->d_addr);\r
+ nlog("src: %s dst: %s ethertype: %.4X", src, dst, ethertype);\r
+ }\r
+#endif\r
+#ifdef VLAN_SUPPORT\r
+ mb->vlan_tci = FLEXRAN_UP_VLAN_TAG;\r
+ dlog("Inserting vlan tag of %d", FLEXRAN_UP_VLAN_TAG);\r
+ rte_vlan_insert(&mb);\r
+#endif\r
+}\r
+\r
+int xran_send_mbuf(struct ether_addr *dst, struct rte_mbuf *mb)\r
+{\r
+ xran_add_eth_hdr(dst, ETHER_TYPE_ETHDI, mb);\r
+\r
+ if (rte_eth_tx_burst(mb->port, 0, &mb, 1) == 1)\r
+ return 1;\r
+\r
+ elog("packet sending failed on port %d", mb->port);\r
+ rte_pktmbuf_free(mb);\r
+\r
+ return 0; /* fail */\r
+}\r
+\r
+int xran_send_message_burst(int dst_id, int pkt_type, void *body, int len)\r
+{\r
+ struct rte_mbuf *mbufs[BURST_SIZE];\r
+ int i;\r
+ uint8_t *src = body;\r
+ const struct xran_ethdi_ctx *const ctx = xran_ethdi_get_ctx();\r
+\r
+ /* We're limited by maximum mbuf size on the receive size.\r
+ * We can change this but this would be a bigger rework. */\r
+ RTE_ASSERT(len < MBUF_POOL_ELM_BIG);\r
+\r
+ /* Allocate the required number of mbufs. */\r
+ const uint8_t count = ceilf((float)len / MAX_DATA_SIZE);\r
+ if (rte_pktmbuf_alloc_bulk(_eth_mbuf_pool, mbufs, count) != 0)\r
+ rte_panic("Failed to allocate %d mbufs\n", count);\r
+\r
+ nlog("burst transfer with data size %lu", MAX_DATA_SIZE);\r
+ for (i = 0; len > 0; ++i) {\r
+ char *p;\r
+ struct burst_hdr *bhdr;\r
+ struct ethdi_hdr *edi_hdr;\r
+\r
+ /* Setup the ethdi_hdr. */\r
+ edi_hdr = (void *)rte_pktmbuf_append(mbufs[i], sizeof(*edi_hdr));\r
+ if (edi_hdr == NULL)\r
+ rte_panic("append of ethdi_hdr failed\n");\r
+ edi_hdr->pkt_type = PKT_BURST;\r
+ /* edi_hdr->source_id setup in tx_from_ring */\r
+ edi_hdr->dest_id = dst_id;\r
+\r
+ /* Setup the burst header */\r
+ bhdr = (void *)rte_pktmbuf_append(mbufs[i], sizeof(*bhdr));\r
+ if (bhdr == NULL) /* append failed. */\r
+ rte_panic("mbuf prepend of burst_hdr failed\n");\r
+ bhdr->original_type = pkt_type;\r
+ bhdr->pkt_idx = i; /* save the index of the burst chunk. */\r
+ bhdr->total_pkts = count;\r
+\r
+ /* now copy in the actual data */\r
+ const int curr_data_len = RTE_MIN(len, MAX_TX_LEN -\r
+ rte_pktmbuf_pkt_len(mbufs[i]) - sizeof(struct ether_hdr));\r
+ p = (void *)rte_pktmbuf_append(mbufs[i], curr_data_len);\r
+ if (p == NULL)\r
+ rte_panic("mbuf append of %d data bytes failed\n", curr_data_len);\r
+ /* This copy is unavoidable, as we're splitting one big buffer\r
+ * into multiple mbufs. */\r
+ rte_memcpy(p, src, curr_data_len);\r
+\r
+ dlog("curr_data_len[%d] = %d", i, curr_data_len);\r
+ dlog("packet %d size %d", i, rte_pktmbuf_pkt_len(mbufs[i]));\r
+\r
+ /* Update our source data pointer and remaining length. */\r
+ len -= curr_data_len;\r
+ src += curr_data_len;\r
+ }\r
+\r
+ /* Now enqueue the full prepared burst. */\r
+ i = rte_ring_enqueue_bulk(ctx->tx_ring[0], (void **)mbufs, count, NULL);\r
+ PANIC_ON(i != count, "failed to enqueue all mbufs: %d/%d", i, count);\r
+ dlog("%d packets enqueued on port %d.", count, ctx->io_cfg.port);\r
+\r
+ return 1;\r
+}\r
+\r
+#endif\r
+\r
+/* Prepend ethernet header, possibly vlan tag. */\r
+void xran_add_eth_hdr_vlan(struct ether_addr *dst, uint16_t ethertype, struct rte_mbuf *mb, uint16_t vlan_tci)\r
+{\r
+ /* add in the ethernet header */\r
+ struct ether_hdr *h = (struct ether_hdr *)rte_pktmbuf_mtod(mb, struct ether_hdr*);\r
+\r
+ PANIC_ON(h == NULL, "mbuf prepend of ether_hdr failed");\r
+\r
+ /* Fill in the ethernet header. */\r
+ rte_eth_macaddr_get(mb->port, &h->s_addr); /* set source addr */\r
+ h->d_addr = *dst; /* set dst addr */\r
+ h->ether_type = rte_cpu_to_be_16(ethertype); /* ethertype too */\r
+\r
+#if defined(DPDKIO_DEBUG) && DPDKIO_DEBUG > 1\r
+ {\r
+ char dst[ETHER_ADDR_FMT_SIZE] = "(empty)";\r
+ char src[ETHER_ADDR_FMT_SIZE] = "(empty)";\r
+\r
+ nlog("*** packet for TX below (len %d) ***", rte_pktmbuf_pkt_len(mb));\r
+ ether_format_addr(src, sizeof(src), &h->s_addr);\r
+ ether_format_addr(dst, sizeof(dst), &h->d_addr);\r
+ nlog("src: %s dst: %s ethertype: %.4X", src, dst, ethertype);\r
+ }\r
+#endif\r
+#ifdef VLAN_SUPPORT\r
+ mb->vlan_tci = vlan_tci;\r
+ dlog("Inserting vlan tag of %d", vlan_tci);\r
+ rte_vlan_insert(&mb);\r
+#endif\r
+}\r
+\r
+\r