aboutsummaryrefslogtreecommitdiff
path: root/platform/linux-generic/odp_packet_io.c
diff options
context:
space:
mode:
Diffstat (limited to 'platform/linux-generic/odp_packet_io.c')
-rw-r--r--platform/linux-generic/odp_packet_io.c537
1 files changed, 537 insertions, 0 deletions
diff --git a/platform/linux-generic/odp_packet_io.c b/platform/linux-generic/odp_packet_io.c
new file mode 100644
index 000000000..33ade1031
--- /dev/null
+++ b/platform/linux-generic/odp_packet_io.c
@@ -0,0 +1,537 @@
+/* Copyright (c) 2013, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <odp_packet_io.h>
+#include <odp_packet_io_internal.h>
+#include <odp_packet_io_queue.h>
+#include <odp_packet.h>
+#include <odp_packet_internal.h>
+#include <odp_internal.h>
+#include <odp_spinlock.h>
+#include <odp_shared_memory.h>
+#include <odp_packet_socket.h>
+#ifdef ODP_HAVE_NETMAP
+#include <odp_packet_netmap.h>
+#endif
+#include <odp_hints.h>
+#include <odp_config.h>
+#include <odp_queue_internal.h>
+#include <odp_schedule_internal.h>
+#include <odp_debug.h>
+
+#include <odp_pktio_socket.h>
+#ifdef ODP_HAVE_NETMAP
+#include <odp_pktio_netmap.h>
+#endif
+
+#include <string.h>
+
+typedef struct {
+ pktio_entry_t entries[ODP_CONFIG_PKTIO_ENTRIES];
+} pktio_table_t;
+
+static pktio_table_t *pktio_tbl;
+
+
+static pktio_entry_t *get_entry(odp_pktio_t id)
+{
+ if (odp_unlikely(id == ODP_PKTIO_INVALID ||
+ id > ODP_CONFIG_PKTIO_ENTRIES))
+ return NULL;
+
+ return &pktio_tbl->entries[id - 1];
+}
+
+int odp_pktio_init_global(void)
+{
+ char name[ODP_QUEUE_NAME_LEN];
+ pktio_entry_t *pktio_entry;
+ queue_entry_t *queue_entry;
+ odp_queue_t qid;
+ int id;
+
+ pktio_tbl = odp_shm_reserve("odp_pktio_entries",
+ sizeof(pktio_table_t),
+ sizeof(pktio_entry_t));
+ if (pktio_tbl == NULL)
+ return -1;
+
+ memset(pktio_tbl, 0, sizeof(pktio_table_t));
+
+ for (id = 1; id <= ODP_CONFIG_PKTIO_ENTRIES; ++id) {
+ pktio_entry = get_entry(id);
+
+ odp_spinlock_init(&pktio_entry->s.lock);
+
+ /* Create a default output queue for each pktio resource */
+ snprintf(name, sizeof(name), "%i-pktio_outq_default", (int)id);
+ name[ODP_QUEUE_NAME_LEN-1] = '\0';
+
+ qid = odp_queue_create(name, ODP_QUEUE_TYPE_PKTOUT, NULL);
+ if (qid == ODP_QUEUE_INVALID)
+ return -1;
+ pktio_entry->s.outq_default = qid;
+
+ queue_entry = queue_to_qentry(qid);
+ queue_entry->s.pktout = id;
+ }
+
+ return 0;
+}
+
+int odp_pktio_init_local(void)
+{
+ return 0;
+}
+
+static int is_free(pktio_entry_t *entry)
+{
+ return (entry->s.taken == 0);
+}
+
+static void set_free(pktio_entry_t *entry)
+{
+ entry->s.taken = 0;
+}
+
+static void set_taken(pktio_entry_t *entry)
+{
+ entry->s.taken = 1;
+}
+
+static void lock_entry(pktio_entry_t *entry)
+{
+ odp_spinlock_lock(&entry->s.lock);
+}
+
+static void unlock_entry(pktio_entry_t *entry)
+{
+ odp_spinlock_unlock(&entry->s.lock);
+}
+
+static void init_pktio_entry(pktio_entry_t *entry, odp_pktio_params_t *params)
+{
+ set_taken(entry);
+ entry->s.inq_default = ODP_QUEUE_INVALID;
+ switch (params->type) {
+ case ODP_PKTIO_TYPE_SOCKET_BASIC:
+ case ODP_PKTIO_TYPE_SOCKET_MMSG:
+ case ODP_PKTIO_TYPE_SOCKET_MMAP:
+ memset(&entry->s.pkt_sock, 0, sizeof(entry->s.pkt_sock));
+ memset(&entry->s.pkt_sock_mmap, 0,
+ sizeof(entry->s.pkt_sock_mmap));
+ break;
+#ifdef ODP_HAVE_NETMAP
+ case ODP_PKTIO_TYPE_NETMAP:
+ memset(&entry->s.pkt_nm, 0, sizeof(entry->s.pkt_nm));
+ break;
+#endif
+ default:
+ ODP_ERR("Packet I/O type not supported. Please recompile\n");
+ break;
+ }
+ /* Save pktio parameters, type is the most useful */
+ memcpy(&entry->s.params, params, sizeof(*params));
+}
+
+static odp_pktio_t alloc_lock_pktio_entry(odp_pktio_params_t *params)
+{
+ odp_pktio_t id;
+ pktio_entry_t *entry;
+ int i;
+
+ for (i = 0; i < ODP_CONFIG_PKTIO_ENTRIES; ++i) {
+ entry = &pktio_tbl->entries[i];
+ if (is_free(entry)) {
+ lock_entry(entry);
+ if (is_free(entry)) {
+ init_pktio_entry(entry, params);
+ id = i + 1;
+ return id; /* return with entry locked! */
+ }
+ unlock_entry(entry);
+ }
+ }
+
+ return ODP_PKTIO_INVALID;
+}
+
+static int free_pktio_entry(odp_pktio_t id)
+{
+ pktio_entry_t *entry = get_entry(id);
+
+ if (entry == NULL)
+ return -1;
+
+ set_free(entry);
+
+ return 0;
+}
+
+odp_pktio_t odp_pktio_open(const char *dev, odp_buffer_pool_t pool,
+ odp_pktio_params_t *params)
+{
+ odp_pktio_t id;
+ pktio_entry_t *pktio_entry;
+ int res;
+
+ if (params == NULL) {
+ ODP_ERR("Invalid pktio params\n");
+ return ODP_PKTIO_INVALID;
+ }
+
+ switch (params->type) {
+ case ODP_PKTIO_TYPE_SOCKET_BASIC:
+ case ODP_PKTIO_TYPE_SOCKET_MMSG:
+ case ODP_PKTIO_TYPE_SOCKET_MMAP:
+ ODP_DBG("Allocating socket pktio\n");
+ break;
+#ifdef ODP_HAVE_NETMAP
+ case ODP_PKTIO_TYPE_NETMAP:
+ ODP_DBG("Allocating netmap pktio\n");
+ break;
+#endif
+ default:
+ ODP_ERR("Invalid pktio type: %02x\n", params->type);
+ return ODP_PKTIO_INVALID;
+ }
+
+ id = alloc_lock_pktio_entry(params);
+ if (id == ODP_PKTIO_INVALID) {
+ ODP_ERR("No resources available.\n");
+ return ODP_PKTIO_INVALID;
+ }
+ /* if successful, alloc_pktio_entry() returns with the entry locked */
+
+ pktio_entry = get_entry(id);
+
+ switch (params->type) {
+ case ODP_PKTIO_TYPE_SOCKET_BASIC:
+ case ODP_PKTIO_TYPE_SOCKET_MMSG:
+ res = setup_pkt_sock(&pktio_entry->s.pkt_sock, dev, pool);
+ if (res == -1) {
+ close_pkt_sock(&pktio_entry->s.pkt_sock);
+ free_pktio_entry(id);
+ id = ODP_PKTIO_INVALID;
+ }
+ break;
+ case ODP_PKTIO_TYPE_SOCKET_MMAP:
+ res = setup_pkt_sock_mmap(&pktio_entry->s.pkt_sock_mmap, dev,
+ pool, params->sock_params.fanout);
+ if (res == -1) {
+ close_pkt_sock_mmap(&pktio_entry->s.pkt_sock_mmap);
+ free_pktio_entry(id);
+ id = ODP_PKTIO_INVALID;
+ }
+ break;
+#ifdef ODP_HAVE_NETMAP
+ case ODP_PKTIO_TYPE_NETMAP:
+
+ res = setup_pkt_netmap(&pktio_entry->s.pkt_nm, dev,
+ pool, &params->nm_params);
+ if (res == -1) {
+ close_pkt_netmap(&pktio_entry->s.pkt_nm);
+ free_pktio_entry(id);
+ id = ODP_PKTIO_INVALID;
+ }
+ break;
+#endif
+ default:
+ free_pktio_entry(id);
+ id = ODP_PKTIO_INVALID;
+ ODP_ERR("This type of I/O is not supported. Please recompile.\n");
+ break;
+ }
+
+ unlock_entry(pktio_entry);
+ return id;
+}
+
+int odp_pktio_close(odp_pktio_t id)
+{
+ pktio_entry_t *entry;
+ int res = -1;
+
+ entry = get_entry(id);
+ if (entry == NULL)
+ return -1;
+
+ lock_entry(entry);
+ if (!is_free(entry)) {
+ switch (entry->s.params.type) {
+ case ODP_PKTIO_TYPE_SOCKET_BASIC:
+ case ODP_PKTIO_TYPE_SOCKET_MMSG:
+ res = close_pkt_sock(&entry->s.pkt_sock);
+ break;
+ case ODP_PKTIO_TYPE_SOCKET_MMAP:
+ res = close_pkt_sock_mmap(&entry->s.pkt_sock_mmap);
+ break;
+#ifdef ODP_HAVE_NETMAP
+ case ODP_PKTIO_TYPE_NETMAP:
+ res = close_pkt_netmap(&entry->s.pkt_nm);
+ break;
+#endif
+ default:
+ break;
+ res |= free_pktio_entry(id);
+ }
+ }
+ unlock_entry(entry);
+
+ if (res != 0)
+ return -1;
+
+ return 0;
+}
+
+void odp_pktio_set_input(odp_packet_t pkt, odp_pktio_t pktio)
+{
+ odp_packet_hdr(pkt)->input = pktio;
+}
+
+odp_pktio_t odp_pktio_get_input(odp_packet_t pkt)
+{
+ return odp_packet_hdr(pkt)->input;
+}
+
+int odp_pktio_recv(odp_pktio_t id, odp_packet_t pkt_table[], unsigned len)
+{
+ pktio_entry_t *pktio_entry = get_entry(id);
+ int pkts;
+ int i;
+
+ if (pktio_entry == NULL)
+ return -1;
+
+ lock_entry(pktio_entry);
+ switch (pktio_entry->s.params.type) {
+ case ODP_PKTIO_TYPE_SOCKET_BASIC:
+ pkts = recv_pkt_sock_basic(&pktio_entry->s.pkt_sock,
+ pkt_table, len);
+ break;
+ case ODP_PKTIO_TYPE_SOCKET_MMSG:
+ pkts = recv_pkt_sock_mmsg(&pktio_entry->s.pkt_sock,
+ pkt_table, len);
+ break;
+ case ODP_PKTIO_TYPE_SOCKET_MMAP:
+ pkts = recv_pkt_sock_mmap(&pktio_entry->s.pkt_sock_mmap,
+ pkt_table, len);
+ break;
+#ifdef ODP_HAVE_NETMAP
+ case ODP_PKTIO_TYPE_NETMAP:
+ pkts = recv_pkt_netmap(&pktio_entry->s.pkt_nm, pkt_table, len);
+ break;
+#endif
+ default:
+ pkts = -1;
+ break;
+ }
+
+ unlock_entry(pktio_entry);
+ if (pkts < 0)
+ return pkts;
+
+ for (i = 0; i < pkts; ++i)
+ odp_pktio_set_input(pkt_table[i], id);
+
+ return pkts;
+}
+
+int odp_pktio_send(odp_pktio_t id, odp_packet_t pkt_table[], unsigned len)
+{
+ pktio_entry_t *pktio_entry = get_entry(id);
+ int pkts;
+
+ if (pktio_entry == NULL)
+ return -1;
+
+ lock_entry(pktio_entry);
+ switch (pktio_entry->s.params.type) {
+ case ODP_PKTIO_TYPE_SOCKET_BASIC:
+ pkts = send_pkt_sock_basic(&pktio_entry->s.pkt_sock,
+ pkt_table, len);
+ break;
+ case ODP_PKTIO_TYPE_SOCKET_MMSG:
+ pkts = send_pkt_sock_mmsg(&pktio_entry->s.pkt_sock,
+ pkt_table, len);
+ break;
+ case ODP_PKTIO_TYPE_SOCKET_MMAP:
+ pkts = send_pkt_sock_mmap(&pktio_entry->s.pkt_sock_mmap,
+ pkt_table, len);
+ break;
+#ifdef ODP_HAVE_NETMAP
+ case ODP_PKTIO_TYPE_NETMAP:
+ pkts = send_pkt_netmap(&pktio_entry->s.pkt_nm,
+ pkt_table, len);
+ break;
+#endif
+ default:
+ pkts = -1;
+ }
+ unlock_entry(pktio_entry);
+
+ return pkts;
+}
+
+int odp_pktio_inq_setdef(odp_pktio_t id, odp_queue_t queue)
+{
+ pktio_entry_t *pktio_entry = get_entry(id);
+ queue_entry_t *qentry = queue_to_qentry(queue);
+
+ if (pktio_entry == NULL || qentry == NULL)
+ return -1;
+
+ if (qentry->s.type != ODP_QUEUE_TYPE_PKTIN)
+ return -1;
+
+ lock_entry(pktio_entry);
+ pktio_entry->s.inq_default = queue;
+ unlock_entry(pktio_entry);
+
+ queue_lock(qentry);
+ qentry->s.pktin = id;
+ qentry->s.status = QUEUE_STATUS_SCHED;
+ queue_unlock(qentry);
+
+ odp_schedule_queue(queue, qentry->s.param.sched.prio);
+
+ return 0;
+}
+
+int odp_pktio_inq_remdef(odp_pktio_t id)
+{
+ return odp_pktio_inq_setdef(id, ODP_QUEUE_INVALID);
+}
+
+odp_queue_t odp_pktio_inq_getdef(odp_pktio_t id)
+{
+ pktio_entry_t *pktio_entry = get_entry(id);
+
+ if (pktio_entry == NULL)
+ return ODP_QUEUE_INVALID;
+
+ return pktio_entry->s.inq_default;
+}
+
+odp_queue_t odp_pktio_outq_getdef(odp_pktio_t id)
+{
+ pktio_entry_t *pktio_entry = get_entry(id);
+
+ if (pktio_entry == NULL)
+ return ODP_QUEUE_INVALID;
+
+ return pktio_entry->s.outq_default;
+}
+
+int pktout_enqueue(queue_entry_t *qentry, odp_buffer_hdr_t *buf_hdr)
+{
+ odp_packet_t pkt = odp_packet_from_buffer(buf_hdr->handle.handle);
+ int len = 1;
+ int nbr;
+
+ nbr = odp_pktio_send(qentry->s.pktout, &pkt, len);
+ return (nbr == len ? 0 : -1);
+}
+
+odp_buffer_hdr_t *pktout_dequeue(queue_entry_t *qentry)
+{
+ (void)qentry;
+ return NULL;
+}
+
+int pktout_enq_multi(queue_entry_t *qentry, odp_buffer_hdr_t *buf_hdr[],
+ int num)
+{
+ odp_packet_t pkt_tbl[QUEUE_MULTI_MAX];
+ int nbr;
+ int i;
+
+ for (i = 0; i < num; ++i)
+ pkt_tbl[i] = odp_packet_from_buffer(buf_hdr[i]->handle.handle);
+
+ nbr = odp_pktio_send(qentry->s.pktout, pkt_tbl, num);
+ return (nbr == num ? 0 : -1);
+}
+
+int pktout_deq_multi(queue_entry_t *qentry, odp_buffer_hdr_t *buf_hdr[],
+ int num)
+{
+ (void)qentry;
+ (void)buf_hdr;
+ (void)num;
+
+ return 0;
+}
+
+int pktin_enqueue(queue_entry_t *qentry, odp_buffer_hdr_t *buf_hdr)
+{
+ /* Use default action */
+ return queue_enq(qentry, buf_hdr);
+}
+
+odp_buffer_hdr_t *pktin_dequeue(queue_entry_t *qentry)
+{
+ odp_buffer_hdr_t *buf_hdr;
+
+ buf_hdr = queue_deq(qentry);
+
+ if (buf_hdr == NULL) {
+ odp_packet_t pkt;
+ odp_buffer_t buf;
+ odp_packet_t pkt_tbl[QUEUE_MULTI_MAX];
+ odp_buffer_hdr_t *tmp_hdr_tbl[QUEUE_MULTI_MAX];
+ int pkts, i, j;
+
+ pkts = odp_pktio_recv(qentry->s.pktin, pkt_tbl,
+ QUEUE_MULTI_MAX);
+
+ if (pkts > 0) {
+ pkt = pkt_tbl[0];
+ buf = odp_buffer_from_packet(pkt);
+ buf_hdr = odp_buf_to_hdr(buf);
+
+ for (i = 1, j = 0; i < pkts; ++i) {
+ buf = odp_buffer_from_packet(pkt_tbl[i]);
+ tmp_hdr_tbl[j++] = odp_buf_to_hdr(buf);
+ }
+ queue_enq_multi(qentry, tmp_hdr_tbl, j);
+ }
+ }
+
+ return buf_hdr;
+}
+
+int pktin_enq_multi(queue_entry_t *qentry, odp_buffer_hdr_t *buf_hdr[], int num)
+{
+ /* Use default action */
+ return queue_enq_multi(qentry, buf_hdr, num);
+}
+
+int pktin_deq_multi(queue_entry_t *qentry, odp_buffer_hdr_t *buf_hdr[], int num)
+{
+ int nbr;
+
+ nbr = queue_deq_multi(qentry, buf_hdr, num);
+
+ if (nbr < num) {
+ odp_packet_t pkt_tbl[QUEUE_MULTI_MAX];
+ odp_buffer_hdr_t *tmp_hdr_tbl[QUEUE_MULTI_MAX];
+ odp_buffer_t buf;
+ int pkts, i;
+
+ pkts = odp_pktio_recv(qentry->s.pktin, pkt_tbl,
+ QUEUE_MULTI_MAX);
+ if (pkts > 0) {
+ for (i = 0; i < pkts; ++i) {
+ buf = odp_buffer_from_packet(pkt_tbl[i]);
+ tmp_hdr_tbl[i] = odp_buf_to_hdr(buf);
+ }
+ queue_enq_multi(qentry, tmp_hdr_tbl, pkts);
+ }
+ }
+
+ return nbr;
+}