diff options
-rw-r--r-- | .gitignore | 7 | ||||
-rw-r--r-- | arch/linux-generic/source/odp_packet.c | 7 | ||||
-rw-r--r-- | arch/linux-generic/source/odp_packet_internal.h | 15 | ||||
-rw-r--r-- | arch/linux-generic/source/odp_packet_io.c | 283 | ||||
-rw-r--r-- | arch/linux-generic/source/odp_packet_io_internal.h | 66 | ||||
-rw-r--r-- | arch/linux-generic/source/odp_packet_io_queue.h | 61 | ||||
-rw-r--r-- | arch/linux-generic/source/odp_packet_socket.c | 12 | ||||
-rw-r--r-- | arch/linux-generic/source/odp_queue.c | 162 | ||||
-rw-r--r-- | arch/linux-generic/source/odp_queue_internal.h | 96 | ||||
-rw-r--r-- | arch/linux-generic/source/odp_schedule.c | 3 | ||||
-rw-r--r-- | arch/linux-generic/source/odp_spinlock.c | 13 | ||||
-rw-r--r-- | include/odp.h | 4 | ||||
-rw-r--r-- | include/odp_config.h | 5 | ||||
-rw-r--r-- | include/odp_packet.h | 3 | ||||
-rw-r--r-- | include/odp_packet_io.h | 53 | ||||
-rw-r--r-- | include/odp_queue.h | 12 | ||||
-rw-r--r-- | include/odp_spinlock.h | 5 | ||||
-rw-r--r-- | test/packet/odp_example_pktio.c | 179 |
18 files changed, 791 insertions, 195 deletions
diff --git a/.gitignore b/.gitignore index 24a9392b7..334234395 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,8 @@ *.d *~ lib/ -test/odp_app - +obj/ +test/example/odp_example +test/packet/odp_packet +test/api_test/odp_atomic +test/api_test/odp_shm diff --git a/arch/linux-generic/source/odp_packet.c b/arch/linux-generic/source/odp_packet.c index 6b0443148..88ba84c8f 100644 --- a/arch/linux-generic/source/odp_packet.c +++ b/arch/linux-generic/source/odp_packet.c @@ -44,6 +44,11 @@ odp_packet_t odp_packet_from_buffer(odp_buffer_t buf) return (odp_packet_t)buf; } +odp_buffer_t odp_buffer_from_packet(odp_packet_t pkt) +{ + return (odp_buffer_t)pkt; +} + void odp_packet_set_len(odp_packet_t pkt, size_t len) { odp_packet_hdr(pkt)->frame_len = len; @@ -56,7 +61,7 @@ size_t odp_packet_get_len(odp_packet_t pkt) uint8_t *odp_packet_payload(odp_packet_t pkt) { - return odp_packet_hdr(pkt)->payload; + return odp_buffer_addr(odp_buffer_from_packet(pkt)); } void odp_packet_print(odp_packet_t pkt) diff --git a/arch/linux-generic/source/odp_packet_internal.h b/arch/linux-generic/source/odp_packet_internal.h index e4496dcdc..f678f0993 100644 --- a/arch/linux-generic/source/odp_packet_internal.h +++ b/arch/linux-generic/source/odp_packet_internal.h @@ -42,9 +42,9 @@ extern "C" { #endif - -#include <odp_packet.h> #include <odp_buffer_internal.h> +#include <odp_packet.h> +#include <odp_packet_io.h> typedef struct odp_packet_hdr_t { @@ -56,6 +56,11 @@ typedef struct odp_packet_hdr_t { size_t l4_offset; size_t frame_len; + odp_pktio_t input; + /* @TODO: pad needed to ensure that + * sizeof(odp_packet_hdr_t) == offsetof(odp_packet_hdr_t, payload) + */ + int pad; /* size_t head_room; @@ -75,12 +80,6 @@ static inline odp_packet_hdr_t *odp_packet_hdr(odp_packet_t pkt) return (odp_packet_hdr_t *)odp_buf_to_hdr((odp_buffer_t)pkt); } -static inline struct odp_packet_hdr_t *odp_packet_payload_to_hdr(uint8_t *pload) -{ - return (struct odp_packet_hdr_t *) - ((size_t)pload - offsetof(struct odp_packet_hdr_t, payload)); -} - #ifdef __cplusplus } diff --git a/arch/linux-generic/source/odp_packet_io.c b/arch/linux-generic/source/odp_packet_io.c index 633231e57..066b8a735 100644 --- a/arch/linux-generic/source/odp_packet_io.c +++ b/arch/linux-generic/source/odp_packet_io.c @@ -28,34 +28,51 @@ * POSSIBILITY OF SUCH DAMAGE. */ - #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> +#include <odp_hints.h> +#include <odp_config.h> +#include <odp_queue_internal.h> +#include <odp_schedule_internal.h> #include <string.h> #include <stdio.h> -#define ODP_CONFIG_PKTIO_ENTRIES 512 - -typedef struct { - pkt_sock_t pkt_sock; /**< using socket API for IO */ - int taken; /**< is entry taken(1) or free(0) */ -} pktio_entry_t; +ODP_ASSERT(sizeof(odp_packet_hdr_t) == offsetof(odp_packet_hdr_t, payload), + ODP_PACKET_HEADER_T__SIZE_ERROR); typedef struct { - odp_spinlock_t tbl_lock; - pktio_entry_t entries[ODP_CONFIG_PKTIO_ENTRIES] ODP_ALIGNED_CACHE; + 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)); @@ -64,7 +81,23 @@ int odp_pktio_init_global(void) memset(pktio_tbl, 0, sizeof(pktio_table_t)); - odp_spinlock_init(&pktio_tbl->tbl_lock); + 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 = get_qentry(from_qhandle(qid)); + queue_entry->s.pktout = id; + } return 0; } @@ -76,122 +109,262 @@ int odp_pktio_init_local(void) static int is_free(pktio_entry_t *entry) { - return (entry->taken == 0); + return (entry->s.taken == 0); } static void set_free(pktio_entry_t *entry) { - entry->taken = 0; + entry->s.taken = 0; } static void set_taken(pktio_entry_t *entry) { - entry->taken = 1; + 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) { - memset(&entry->pkt_sock, 0, sizeof(entry->pkt_sock)); set_taken(entry); + entry->s.inq_default = ODP_QUEUE_INVALID; + memset(&entry->s.pkt_sock, 0, sizeof(entry->s.pkt_sock)); } -static odp_pktio_t alloc_pktio_entry(void) +static odp_pktio_t alloc_lock_pktio_entry(void) { - odp_pktio_t id = ODP_PKTIO_INVALID; + odp_pktio_t id; + pktio_entry_t *entry; int i; - odp_spinlock_lock(&pktio_tbl->tbl_lock); - for (i = 0; i < ODP_CONFIG_PKTIO_ENTRIES; ++i) { - if (is_free(&pktio_tbl->entries[i])) { - init_pktio_entry(&pktio_tbl->entries[i]); - id = i + 1; - break; + entry = &pktio_tbl->entries[i]; + if (is_free(entry)) { + lock_entry(entry); + if (is_free(entry)) { + init_pktio_entry(entry); + id = i + 1; + return id; /* return with entry locked! */ + } + unlock_entry(entry); } } - odp_spinlock_unlock(&pktio_tbl->tbl_lock); - - return id; + return ODP_PKTIO_INVALID; } static int free_pktio_entry(odp_pktio_t id) { - int i; + pktio_entry_t *entry = get_entry(id); - if (id == ODP_PKTIO_INVALID || id > ODP_CONFIG_PKTIO_ENTRIES) + if (entry == NULL) return -1; - i = id - 1; - - odp_spinlock_lock(&pktio_tbl->tbl_lock); - - set_free(&pktio_tbl->entries[i]); - - odp_spinlock_unlock(&pktio_tbl->tbl_lock); + set_free(entry); return 0; } -static pktio_entry_t *get_entry(odp_pktio_t id) -{ - if (id == ODP_PKTIO_INVALID || id > ODP_CONFIG_PKTIO_ENTRIES) - return NULL; - - return &pktio_tbl->entries[id - 1]; -} - odp_pktio_t odp_pktio_open(char *dev, odp_buffer_pool_t pool) { odp_pktio_t id; pktio_entry_t *pktio_entry; int res; - id = alloc_pktio_entry(); + id = alloc_lock_pktio_entry(); if (id == ODP_PKTIO_INVALID) { fprintf(stderr, "%s(): No resources available.\n", __func__); return ODP_PKTIO_INVALID; } + /* iff successful, alloc_pktio_entry() returns with the entry locked */ pktio_entry = get_entry(id); - if (pktio_entry == NULL) - return ODP_PKTIO_INVALID; - res = setup_pkt_sock(&pktio_entry->pkt_sock, dev, pool); - if (res == -1) - return ODP_PKTIO_INVALID; + 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; + } + unlock_entry(pktio_entry); return id; } int odp_pktio_close(odp_pktio_t id) { - pktio_entry_t *pktio_entry; + pktio_entry_t *entry; int res; - pktio_entry = get_entry(id); - if (pktio_entry == NULL) + entry = get_entry(id); + if (entry == NULL) return -1; - res = close_pkt_sock(&pktio_entry->pkt_sock); - res |= free_pktio_entry(id); + lock_entry(entry); + if (!is_free(entry)) { + res = close_pkt_sock(&entry->s.pkt_sock); + 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; - return recv_pkt_sock(&pktio_entry->pkt_sock, pkt_table, len); + if (pktio_entry == NULL) + return -1; + + lock_entry(pktio_entry); + pkts = recv_pkt_sock(&pktio_entry->s.pkt_sock, pkt_table, len); + unlock_entry(pktio_entry); + 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 sent_pkts; + + if (pktio_entry == NULL) + return -1; + + lock_entry(pktio_entry); + sent_pkts = send_pkt_sock(&pktio_entry->s.pkt_sock, pkt_table, len); + unlock_entry(pktio_entry); + + return sent_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 = get_qentry(from_qhandle(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); + + odp_spinlock_lock(&qentry->s.lock); + qentry->s.pktin = id; + qentry->s.status = QUEUE_STATUS_SCHED; + odp_spinlock_unlock(&qentry->s.lock); + + 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 *queue, 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(queue->s.pktout, &pkt, len); + return (nbr == len ? 0 : -1); +} + +odp_buffer_hdr_t *pktout_dequeue(queue_entry_t *queue) +{ + (void)queue; + return NULL; +} + +int pktin_enqueue(queue_entry_t *queue, odp_buffer_hdr_t *buf_hdr) +{ + /* Use default action */ + return queue_enq(queue, 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_buffer_hdr_t *tmp_hdr; + odp_packet_t pkt_tbl[ODP_PKTIN_QUEUE_MAX_BURST]; + int pkts, i; + + pkts = odp_pktio_recv(qentry->s.pktin, pkt_tbl, + ODP_PKTIN_QUEUE_MAX_BURST); + + if (pkts > 0) { + pkt = pkt_tbl[0]; + buf = odp_buffer_from_packet(pkt); + buf_hdr = odp_buf_to_hdr(buf); + + for (i = 1; i < pkts; ++i) { + buf = odp_buffer_from_packet(pkt_tbl[i]); + tmp_hdr = odp_buf_to_hdr(buf); + queue_enq(qentry, tmp_hdr); + } + } + } - return send_pkt_sock(&pktio_entry->pkt_sock, pkt_table, len); + return buf_hdr; } diff --git a/arch/linux-generic/source/odp_packet_io_internal.h b/arch/linux-generic/source/odp_packet_io_internal.h new file mode 100644 index 000000000..2328e187a --- /dev/null +++ b/arch/linux-generic/source/odp_packet_io_internal.h @@ -0,0 +1,66 @@ +/* Copyright (c) 2013, Linaro Limited + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Linaro Limited nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIALDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + +/** + * @file + * + * ODP packet IO - implementation internal + */ + +#ifndef ODP_PACKET_IO_INTERNAL_H_ +#define ODP_PACKET_IO_INTERNAL_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <odp_spinlock.h> +#include <odp_packet_socket.h> + +struct pktio_entry { + odp_spinlock_t lock; /**< entry spinlock */ + int taken; /**< is entry taken(1) or free(0) */ + odp_queue_t inq_default; /**< default input queue, if set */ + odp_queue_t outq_default; /**< default out queue */ + pkt_sock_t pkt_sock; /**< using socket API for IO */ +}; + +typedef union { + struct pktio_entry s; + uint8_t pad[ODP_CACHE_LINE_SIZE_ROUNDUP(sizeof(struct pktio_entry))]; +} pktio_entry_t; + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/arch/linux-generic/source/odp_packet_io_queue.h b/arch/linux-generic/source/odp_packet_io_queue.h new file mode 100644 index 000000000..f425cdf37 --- /dev/null +++ b/arch/linux-generic/source/odp_packet_io_queue.h @@ -0,0 +1,61 @@ +/* Copyright (c) 2013, Linaro Limited + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Linaro Limited nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIALDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + +/** + * @file + * + * ODP packet IO - implementation internal + */ + +#ifndef ODP_PACKET_IO_QUEUE_H_ +#define ODP_PACKET_IO_QUEUE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <odp_queue_internal.h> +#include <odp_buffer_internal.h> + +#define ODP_PKTIN_QUEUE_MAX_BURST 16 + +int pktin_enqueue(queue_entry_t *queue, odp_buffer_hdr_t *buf_hdr); +odp_buffer_hdr_t *pktin_dequeue(queue_entry_t *queue); + +int pktout_enqueue(queue_entry_t *queue, odp_buffer_hdr_t *buf_hdr); +odp_buffer_hdr_t *pktout_dequeue(queue_entry_t *queue); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/arch/linux-generic/source/odp_packet_socket.c b/arch/linux-generic/source/odp_packet_socket.c index cc33bb05c..61a1e3d12 100644 --- a/arch/linux-generic/source/odp_packet_socket.c +++ b/arch/linux-generic/source/odp_packet_socket.c @@ -243,11 +243,13 @@ int recv_pkt_sock(pkt_sock_t * const pkt_sock, socklen_t addrlen = sizeof(sll); int const sockfd = pkt_sock->sockfd; odp_packet_t pkt = ODP_PACKET_INVALID; + odp_buffer_t buf; int nb_rx = 0; for (i = 0; i < len; i++) { if (odp_likely(pkt == ODP_PACKET_INVALID)) { - pkt = (odp_packet_t) odp_buffer_alloc(pkt_sock->pool); + buf = odp_buffer_alloc(pkt_sock->pool); + pkt = odp_packet_from_buffer(buf); if (odp_unlikely(pkt == ODP_PACKET_INVALID)) break; } @@ -329,6 +331,7 @@ int recv_pkt_sock(pkt_sock_t * const pkt_sock, int msgvec_len; struct mmsghdr msgvec[ODP_PACKET_SOCKET_MAX_BURST_RX]; struct iovec iovecs[ODP_PACKET_SOCKET_MAX_BURST_RX]; + odp_buffer_t buf; int nb_rx = 0; int recv_msgs; int i; @@ -339,7 +342,8 @@ int recv_pkt_sock(pkt_sock_t * const pkt_sock, memset(msgvec, 0, sizeof(msgvec)); for (i = 0; i < (int)len; i++) { - pkt_table[i] = (odp_packet_t) odp_buffer_alloc(pkt_sock->pool); + buf = odp_buffer_alloc(pkt_sock->pool); + pkt_table[i] = odp_packet_from_buffer(buf); if (odp_unlikely(pkt_table[i] == ODP_PACKET_INVALID)) break; iovecs[i].iov_base = odp_packet_payload(pkt_table[i]); @@ -488,6 +492,7 @@ static unsigned pkt_mmap_v2_rx(int sock, struct ring *ring, unsigned frame_num, next_frame_num; uint8_t *pkt; int pkt_len; + odp_buffer_t buf; unsigned i = 0; (void)sock; @@ -503,7 +508,8 @@ static unsigned pkt_mmap_v2_rx(int sock, struct ring *ring, pkt = (uint8_t *)ppd.raw + ppd.v2->tp_h.tp_mac; pkt_len = ppd.v2->tp_h.tp_snaplen; - pkt_table[i] = (odp_packet_t)odp_buffer_alloc(pool); + buf = odp_buffer_alloc(pool); + pkt_table[i] = odp_packet_from_buffer(buf); if (odp_unlikely(pkt_table[i] == ODP_PACKET_INVALID)) break; diff --git a/arch/linux-generic/source/odp_queue.c b/arch/linux-generic/source/odp_queue.c index 27f53ba56..578350d85 100644 --- a/arch/linux-generic/source/odp_queue.c +++ b/arch/linux-generic/source/odp_queue.c @@ -29,86 +29,47 @@ */ - - +#include <odp_queue.h> +#include <odp_queue_internal.h> #include <odp_std_types.h> #include <odp_align.h> #include <odp_buffer.h> #include <odp_buffer_internal.h> #include <odp_internal.h> -#include <odp_queue.h> #include <odp_shared_memory.h> #include <odp_spinlock.h> #include <odp_schedule_internal.h> #include <odp_config.h> +#include <odp_packet_io_internal.h> +#include <odp_packet_io_queue.h> #include <stdio.h> #include <string.h> -#define QUEUE_STATUS_FREE 0 -#define QUEUE_STATUS_INIT 1 -#define QUEUE_STATUS_READY 2 -#define QUEUE_STATUS_NOTSCHED 3 -#define QUEUE_STATUS_SCHED 4 - -/* forward declaration */ -union queue_entry_u; - -struct queue_entry_s { - odp_spinlock_t lock; - int (*enqueue)(union queue_entry_u *, odp_buffer_hdr_t *); - odp_buffer_hdr_t *(*dequeue)(union queue_entry_u *); - odp_buffer_hdr_t *head; - odp_buffer_hdr_t *tail; - odp_queue_t handle; - odp_queue_type_t type; - int status; - odp_queue_param_t param; - char name[ODP_QUEUE_NAME_LEN]; -}; - - -typedef union queue_entry_u { - struct queue_entry_s s; - - uint8_t pad[ODP_CACHE_LINE_SIZE_ROUNDUP(sizeof(struct queue_entry_s))]; - -} queue_entry_t; - - typedef struct queue_table_t { queue_entry_t queue[ODP_CONFIG_QUEUES]; - } queue_table_t; - static queue_table_t *queue_tbl; -/* local function prototypes */ -static int queue_enq(queue_entry_t *queue, odp_buffer_hdr_t *buf_hdr); -static odp_buffer_hdr_t *queue_deq(queue_entry_t *queue); - - -static inline queue_entry_t *get_queue(uint32_t queue_id) +queue_entry_t *get_qentry(uint32_t queue_id) { return &queue_tbl->queue[queue_id]; } - -static inline odp_queue_t to_handle(uint32_t queue_id) +odp_queue_t to_qhandle(uint32_t queue_id) { return queue_id + 1; } -static inline uint32_t from_handle(odp_queue_t handle) +uint32_t from_qhandle(odp_queue_t handle) { return handle - 1; } - static void queue_init(queue_entry_t *queue, const char *name, odp_queue_type_t type, odp_queue_param_t *param) { @@ -125,8 +86,20 @@ static void queue_init(queue_entry_t *queue, const char *name, queue->s.param.sched.group = ODP_SCHED_GROUP_DEFAULT; } - queue->s.enqueue = queue_enq; - queue->s.dequeue = queue_deq; + switch (type) { + case ODP_QUEUE_TYPE_PKTIN: + queue->s.enqueue = pktin_enqueue; + queue->s.dequeue = pktin_dequeue; + break; + case ODP_QUEUE_TYPE_PKTOUT: + queue->s.enqueue = pktout_enqueue; + queue->s.dequeue = pktout_dequeue; + break; + default: + queue->s.enqueue = queue_enq; + queue->s.dequeue = queue_deq; + break; + } queue->s.head = NULL; queue->s.tail = NULL; @@ -150,10 +123,10 @@ int odp_queue_init_global(void) for (i = 0; i < ODP_CONFIG_QUEUES; i++) { /* init locks */ - queue_entry_t *queue = get_queue(i); + queue_entry_t *queue = get_qentry(i); odp_spinlock_init(&queue->s.lock); - queue->s.handle = to_handle(i); + queue->s.handle = to_qhandle(i); } printf("done\n"); @@ -166,6 +139,16 @@ int odp_queue_init_global(void) return 0; } +odp_queue_type_t odp_queue_type(odp_queue_t handle) +{ + queue_entry_t *queue; + uint32_t queue_id; + + queue_id = from_qhandle(handle); + queue = get_qentry(queue_id); + + return queue->s.type; +} odp_queue_t odp_queue_create(const char *name, odp_queue_type_t type, odp_queue_param_t *param) @@ -182,16 +165,15 @@ odp_queue_t odp_queue_create(const char *name, odp_queue_type_t type, odp_spinlock_lock(&queue->s.lock); if (queue->s.status == QUEUE_STATUS_FREE) { - queue->s.status = QUEUE_STATUS_INIT; - odp_spinlock_unlock(&queue->s.lock); queue_init(queue, name, type, param); - - if (type == ODP_QUEUE_TYPE_SCHED) + if (type == ODP_QUEUE_TYPE_SCHED || + type == ODP_QUEUE_TYPE_PKTIN) queue->s.status = QUEUE_STATUS_NOTSCHED; else queue->s.status = QUEUE_STATUS_READY; handle = queue->s.handle; + odp_spinlock_unlock(&queue->s.lock); break; } @@ -229,8 +211,12 @@ odp_queue_t odp_queue_lookup(const char *name) -static int queue_enq(queue_entry_t *queue, odp_buffer_hdr_t *buf_hdr) +int queue_enq(queue_entry_t *queue, odp_buffer_hdr_t *buf_hdr) { + int sched = 0; + + odp_spinlock_lock(&queue->s.lock); + if (queue->s.head == NULL) { /* Empty queue */ queue->s.head = buf_hdr; @@ -242,6 +228,17 @@ static int queue_enq(queue_entry_t *queue, odp_buffer_hdr_t *buf_hdr) buf_hdr->next = NULL; } + if (queue->s.status == QUEUE_STATUS_NOTSCHED) { + queue->s.status = QUEUE_STATUS_SCHED; + sched = 1; /* retval: schedule queue */ + } + + odp_spinlock_unlock(&queue->s.lock); + + /* Add queue to scheduling */ + if (sched == 1) + odp_schedule_queue(queue->s.handle, queue->s.param.sched.prio); + return 0; } @@ -251,51 +248,38 @@ int odp_queue_enq(odp_queue_t handle, odp_buffer_t buf) odp_buffer_hdr_t *buf_hdr; queue_entry_t *queue; uint32_t queue_id; - int sched = 0; - queue_id = from_handle(handle); - queue = get_queue(queue_id); + queue_id = from_qhandle(handle); + queue = get_qentry(queue_id); buf_hdr = odp_buf_to_hdr(buf); - odp_spinlock_lock(&queue->s.lock); - queue->s.enqueue(queue, buf_hdr); - - if (queue->s.status == QUEUE_STATUS_NOTSCHED) { - queue->s.status = QUEUE_STATUS_SCHED; - sched = 1; - } - - odp_spinlock_unlock(&queue->s.lock); - - /* Add queue to scheduling */ - if (sched) - odp_schedule_queue(handle, queue->s.param.sched.prio); - - return 0; + return queue->s.enqueue(queue, buf_hdr); } -static odp_buffer_hdr_t *queue_deq(queue_entry_t *queue) +odp_buffer_hdr_t *queue_deq(queue_entry_t *queue) { - odp_buffer_hdr_t *buf_hdr; + odp_buffer_hdr_t *buf_hdr = NULL; + + odp_spinlock_lock(&queue->s.lock); if (queue->s.head == NULL) { /* Already empty queue */ - if (queue->s.status == QUEUE_STATUS_SCHED) + if (queue->s.status == QUEUE_STATUS_SCHED && + queue->s.type != ODP_QUEUE_TYPE_PKTIN) queue->s.status = QUEUE_STATUS_NOTSCHED; + } else { + buf_hdr = queue->s.head; + queue->s.head = buf_hdr->next; + buf_hdr->next = NULL; - return NULL; + if (queue->s.head == NULL) { + /* Queue is now empty */ + queue->s.tail = NULL; + } } - - buf_hdr = queue->s.head; - queue->s.head = buf_hdr->next; - buf_hdr->next = NULL; - - if (queue->s.head == NULL) { - /* Queue is now empty */ - queue->s.tail = NULL; - } + odp_spinlock_unlock(&queue->s.lock); return buf_hdr; } @@ -307,12 +291,10 @@ odp_buffer_t odp_queue_deq(odp_queue_t handle) uint32_t queue_id; odp_buffer_hdr_t *buf_hdr; - queue_id = from_handle(handle); - queue = get_queue(queue_id); + queue_id = from_qhandle(handle); + queue = get_qentry(queue_id); - odp_spinlock_lock(&queue->s.lock); buf_hdr = queue->s.dequeue(queue); - odp_spinlock_unlock(&queue->s.lock); if (buf_hdr) return buf_hdr->handle.handle; diff --git a/arch/linux-generic/source/odp_queue_internal.h b/arch/linux-generic/source/odp_queue_internal.h new file mode 100644 index 000000000..76fd239da --- /dev/null +++ b/arch/linux-generic/source/odp_queue_internal.h @@ -0,0 +1,96 @@ +/* Copyright (c) 2013, Linaro Limited + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Linaro Limited nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIALDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + +/** + * @file + * + * ODP queue - implementation internal + */ + +#ifndef ODP_QUEUE_INTERNAL_H_ +#define ODP_QUEUE_INTERNAL_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <odp_queue.h> +#include <odp_buffer_internal.h> +#include <odp_packet_io.h> +#include <odp_spinlock.h> +#include <odp_align.h> + +#define QUEUE_STATUS_FREE 0 +#define QUEUE_STATUS_READY 1 +#define QUEUE_STATUS_NOTSCHED 2 +#define QUEUE_STATUS_SCHED 3 + +/* forward declaration */ +union queue_entry_u; + +typedef int (*enqueue_func_t)(union queue_entry_u *, odp_buffer_hdr_t *); +typedef odp_buffer_hdr_t *(*dequeue_func_t)(union queue_entry_u *); + +struct queue_entry_s { + odp_spinlock_t lock ODP_ALIGNED_CACHE; + enqueue_func_t enqueue ODP_ALIGNED_CACHE; + dequeue_func_t dequeue; + odp_buffer_hdr_t *head; + odp_buffer_hdr_t *tail; + odp_queue_t handle; + odp_queue_type_t type; + int status; + odp_queue_param_t param; + odp_pktio_t pktin; + odp_pktio_t pktout; + char name[ODP_QUEUE_NAME_LEN]; +}; + +typedef union queue_entry_u { + struct queue_entry_s s; + uint8_t pad[ODP_CACHE_LINE_SIZE_ROUNDUP(sizeof(struct queue_entry_s))]; +} queue_entry_t; + + +queue_entry_t *get_qentry(uint32_t queue_id); +odp_queue_t to_qhandle(uint32_t queue_id); +uint32_t from_qhandle(odp_queue_t handle); + +/* local function prototypes */ +int queue_enq(queue_entry_t *queue, odp_buffer_hdr_t *buf_hdr); +odp_buffer_hdr_t *queue_deq(queue_entry_t *queue); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/arch/linux-generic/source/odp_schedule.c b/arch/linux-generic/source/odp_schedule.c index 24c61e14b..d0f10af7d 100644 --- a/arch/linux-generic/source/odp_schedule.c +++ b/arch/linux-generic/source/odp_schedule.c @@ -153,7 +153,8 @@ odp_buffer_t odp_schedule(void) queue = desc->queue; buf = odp_queue_deq(queue); - if (odp_buffer_is_valid(buf)) { + if (odp_buffer_is_valid(buf) || + odp_queue_type(queue) == ODP_QUEUE_TYPE_PKTIN) { /* Continue scheduling the queue */ odp_queue_enq(pri_queue, desc_buf); } else { diff --git a/arch/linux-generic/source/odp_spinlock.c b/arch/linux-generic/source/odp_spinlock.c index 5523f1132..131329c1c 100644 --- a/arch/linux-generic/source/odp_spinlock.c +++ b/arch/linux-generic/source/odp_spinlock.c @@ -29,23 +29,20 @@ */ - - - #include <odp_spinlock.h> - void odp_spinlock_init(odp_spinlock_t *spinlock) { - __sync_lock_release(&spinlock->lock); + __sync_lock_release(&spinlock->lock); } void odp_spinlock_lock(odp_spinlock_t *spinlock) { while (__sync_lock_test_and_set(&spinlock->lock, 1)) - ; + while (spinlock->lock) + ; } @@ -57,7 +54,7 @@ int odp_spinlock_trylock(odp_spinlock_t *spinlock) void odp_spinlock_unlock(odp_spinlock_t *spinlock) { - __sync_lock_release(&spinlock->lock); + __sync_lock_release(&spinlock->lock); } @@ -68,5 +65,3 @@ int odp_spinlock_is_locked(odp_spinlock_t *spinlock) - - diff --git a/include/odp.h b/include/odp.h index 023b61a0a..758fadb97 100644 --- a/include/odp.h +++ b/include/odp.h @@ -306,11 +306,11 @@ extern "C" { #include <odp_shared_memory.h> #include <odp_buffer.h> #include <odp_buffer_pool.h> -#include <odp_packet.h> #include <odp_queue.h> #include <odp_time.h> #include <odp_schedule.h> - +#include <odp_packet.h> +#include <odp_packet_io.h> #ifdef __cplusplus } diff --git a/include/odp_config.h b/include/odp_config.h index fdd1ba53c..8e2e4e601 100644 --- a/include/odp_config.h +++ b/include/odp_config.h @@ -63,7 +63,10 @@ extern "C" { */ #define ODP_CONFIG_SCHED_PRIOS 8 - +/** + * Maximum number of packet IO resources + */ +#define ODP_CONFIG_PKTIO_ENTRIES 64 #ifdef __cplusplus } diff --git a/include/odp_packet.h b/include/odp_packet.h index d6fcf8ba2..e01515eb5 100644 --- a/include/odp_packet.h +++ b/include/odp_packet.h @@ -42,11 +42,9 @@ extern "C" { #endif - #include <odp_buffer.h> - /** * ODP packet descriptor */ @@ -60,6 +58,7 @@ void odp_packet_init(odp_packet_t pkt); void odp_packet_print(odp_packet_t pkt); odp_packet_t odp_packet_from_buffer(odp_buffer_t buf); +odp_buffer_t odp_buffer_from_packet(odp_packet_t pkt); void odp_packet_set_len(odp_packet_t pkt, size_t len); size_t odp_packet_get_len(odp_packet_t pkt); diff --git a/include/odp_packet_io.h b/include/odp_packet_io.h index be1d6699f..4cb8bc996 100644 --- a/include/odp_packet_io.h +++ b/include/odp_packet_io.h @@ -45,6 +45,7 @@ extern "C" { #include <odp_std_types.h> #include <odp_buffer_pool.h> #include <odp_packet.h> +#include <odp_queue.h> /** ODP packet IO handle */ typedef int odp_pktio_t; @@ -91,6 +92,58 @@ int odp_pktio_recv(odp_pktio_t id, odp_packet_t pkt_table[], unsigned len); */ int odp_pktio_send(odp_pktio_t id, odp_packet_t pkt_table[], unsigned len); +/** + * Set the default input queue to be associated with a pktio handle + * + * @param + */ +int odp_pktio_inq_setdef(odp_pktio_t id, odp_queue_t queue); + +/** + * Get default input queue associated with a pktio handle + * + * @param id ODP packet IO handle + * + * @return Default input queue set or ODP_QUEUE_INVALID on error + */ +odp_queue_t odp_pktio_inq_getdef(odp_pktio_t id); + +/** + * Remove default input queue (if set) + * + * @param id ODP packet IO handle + * + * @return 0 on success or -1 on error + */ +int odp_pktio_inq_remdef(odp_pktio_t id); + +/** + * Query default output queue + * + * @param id ODP packet IO handle + * + * @return Default out queue or ODP_QUEUE_INVALID on error + */ +odp_queue_t odp_pktio_outq_getdef(odp_pktio_t id); + +/** + * Store packet input handle into packet + * + * @param pkt ODP packet buffer handle + * @param id ODP packet IO handle + * + * @return + */ +void odp_pktio_set_input(odp_packet_t pkt, odp_pktio_t id); + +/** + * Get stored packet input handle from packet + * + * @param pkt ODP packet buffer handle + * + * @return Packet IO handle + */ +odp_pktio_t odp_pktio_get_input(odp_packet_t pkt); #ifdef __cplusplus } diff --git a/include/odp_queue.h b/include/odp_queue.h index 6131543f1..5c89ce653 100644 --- a/include/odp_queue.h +++ b/include/odp_queue.h @@ -62,10 +62,10 @@ typedef uint32_t odp_queue_t; */ typedef int odp_queue_type_t; -#define ODP_QUEUE_TYPE_SCHED 0 -#define ODP_QUEUE_TYPE_POLL 1 -#define ODP_QUEUE_TYPE_PKTIN 2 -#define ODP_QUEUE_TYPE_PKTOUT 3 +#define ODP_QUEUE_TYPE_SCHED 0 +#define ODP_QUEUE_TYPE_POLL 1 +#define ODP_QUEUE_TYPE_PKTIN 2 +#define ODP_QUEUE_TYPE_PKTOUT 3 /** * ODP schedule priority @@ -148,6 +148,10 @@ int odp_queue_enq(odp_queue_t queue, odp_buffer_t buf); */ odp_buffer_t odp_queue_deq(odp_queue_t queue); +/** + * + */ +odp_queue_type_t odp_queue_type(odp_queue_t handle); #ifdef __cplusplus } diff --git a/include/odp_spinlock.h b/include/odp_spinlock.h index c345e4599..ec8a9f30d 100644 --- a/include/odp_spinlock.h +++ b/include/odp_spinlock.h @@ -43,17 +43,14 @@ extern "C" { #endif - #include <odp_std_types.h> - /** * ODP spinlock */ typedef struct odp_spinlock_t { - int lock; - + int lock; } odp_spinlock_t; diff --git a/test/packet/odp_example_pktio.c b/test/packet/odp_example_pktio.c index 654df1e9a..c5e7aa19a 100644 --- a/test/packet/odp_example_pktio.c +++ b/test/packet/odp_example_pktio.c @@ -38,16 +38,21 @@ #include <string.h> #include <stdio.h> #include <getopt.h> +#include <unistd.h> #include <odp.h> #include <odp_linux.h> -#include <odp_packet_io.h> #define MAX_WORKERS 32 #define SHM_PKT_POOL_SIZE (512*2048) #define SHM_PKT_POOL_BUF_SIZE 1856 #define MAX_PKT_BURST 16 +#define APPL_MODE_PKT_BURST 0 +#define APPL_MODE_PKT_QUEUE 1 + +#define PRINT_APPL_MODE(x) printf("%s(%i)\n", #x, (x)) + /** Get rid of path in filename - only for unix-type paths using '/' */ #define NO_PATH(file_name) (strrchr((file_name), '/') ? \ strrchr((file_name), '/') + 1 : (file_name)) @@ -57,6 +62,7 @@ typedef struct { int if_count; /**< Number of interfaces to be used */ char **if_names; /**< Array of pointers to interface names */ + int mode; /**< Packet IO mode */ odp_buffer_pool_t pool; /**< Buffer pool for packet IO */ } appl_args_t; @@ -66,6 +72,7 @@ typedef struct { typedef struct { char *pktio_dev; /**< Interface name to use */ odp_buffer_pool_t pool; /**< Buffer pool for packet IO */ + int mode; /**< Thread mode */ } thread_args_t; /** @@ -87,18 +94,125 @@ static void print_info(char *progname, appl_args_t *appl_args); static void usage(char *progname); /** - * Packet IO loopback worker thread + * Packet IO loopback worker thread using ODP queues + * + * @param arg thread arguments of type 'thread_args_t *' + */ +static void *pktio_queue_thread(void *arg) +{ + int thr; + odp_buffer_pool_t pkt_pool; + odp_pktio_t pktio; + thread_args_t *thr_args; + odp_queue_t outq_def; + odp_queue_t inq_def; + char inq_name[ODP_QUEUE_NAME_LEN]; + odp_queue_param_t qparam; + odp_packet_t pkt; + odp_buffer_t buf; + int ret; + unsigned long pkt_cnt = 0; + + thr = odp_thread_id(); + thr_args = arg; + + printf("Pktio thread [%02i] starts, pktio_dev:%s\n", thr, + thr_args->pktio_dev); + + /* Lookup the packet pool */ + pkt_pool = odp_buffer_pool_lookup("packet_pool"); + if (pkt_pool == ODP_BUFFER_POOL_INVALID) { + fprintf(stderr, " [%02i] Error: pkt_pool not found\n", thr); + return NULL; + } + + /* Open a packet IO instance for this thread */ + pktio = odp_pktio_open(thr_args->pktio_dev, thr_args->pool); + if (pktio == ODP_PKTIO_INVALID) { + fprintf(stderr, " [%02i] Error: pktio create failed\n", thr); + return NULL; + } + + /* + * Create and set the default INPUT queue associated with the 'pktio' + * resource + */ + qparam.sched.prio = ODP_SCHED_PRIO_DEFAULT; + qparam.sched.sync = ODP_SCHED_SYNC_NONE; + qparam.sched.group = ODP_SCHED_GROUP_DEFAULT; + snprintf(inq_name, sizeof(inq_name), "%i-pktio_inq_def", (int)pktio); + inq_name[ODP_QUEUE_NAME_LEN - 1] = '\0'; + + inq_def = odp_queue_create(inq_name, ODP_QUEUE_TYPE_PKTIN, &qparam); + if (inq_def == ODP_QUEUE_INVALID) { + fprintf(stderr, " [%02i] Error: pktio queue creation failed\n", + thr); + return NULL; + } + + ret = odp_pktio_inq_setdef(pktio, inq_def); + if (ret != 0) { + fprintf(stderr, " [%02i] Error: default input-Q setup\n" + , thr); + return NULL; + } + + printf(" [%02i] created pktio:%02i, queue mode\n" + " default pktio%02i-INPUT queue:%u\n", + thr, pktio, pktio, inq_def); + + /* Loop packets */ + for (;;) { + odp_pktio_t pktio_tmp; + +#if 1 + /* Use schedule to get buf from any input queue */ + buf = odp_schedule_poll(); +#else + /* Always dequeue from the same input queue */ + buf = odp_queue_deq(inq_def); + if (!odp_buffer_is_valid(buf)) + continue; +#endif + + pkt = odp_packet_from_buffer(buf); + pktio_tmp = odp_pktio_get_input(pkt); + outq_def = odp_pktio_outq_getdef(pktio_tmp); + + if (outq_def == ODP_QUEUE_INVALID) { + fprintf(stderr, " [%02i] Error: def output-Q query\n", + thr); + return NULL; + } + + /* Enqueue the packet for output */ + odp_queue_enq(outq_def, buf); + + /* Print packet counts every once in a while */ + if (odp_unlikely(pkt_cnt++ % 100000 == 0)) { + printf(" [%02i] pkt_cnt:%lu\n", thr, pkt_cnt); + fflush(NULL); + } + } + + return arg; +} + +/** + * Packet IO loopback worker thread using bursts from/to IO resources * * @param arg thread arguments of type 'thread_args_t *' */ -static void *pktio_thread(void *arg) +static void *pktio_ifburst_thread(void *arg) { int thr; odp_buffer_pool_t pkt_pool; odp_pktio_t pktio; thread_args_t *thr_args; int pkts; - odp_packet_t pkt_table[MAX_PKT_BURST]; + odp_packet_t pkt_tbl[MAX_PKT_BURST]; + unsigned long pkt_cnt = 0; + unsigned long tmp = 0; thr = odp_thread_id(); thr_args = arg; @@ -119,13 +233,25 @@ static void *pktio_thread(void *arg) fprintf(stderr, " [%02i] Error: pktio create failed.\n", thr); return NULL; } - printf(" [%02i] created pktio:%i\n", thr, pktio); - /* Packet loopback */ + printf(" [%02i] created pktio:%02i, burst mode\n", + thr, pktio); + + /* Loop packets */ for (;;) { - pkts = odp_pktio_recv(pktio, pkt_table, MAX_PKT_BURST); + pkts = odp_pktio_recv(pktio, pkt_tbl, MAX_PKT_BURST); if (pkts > 0) - (void)odp_pktio_send(pktio, pkt_table, pkts); + odp_pktio_send(pktio, pkt_tbl, pkts); + + /* Print packet counts every once in a while */ + tmp += pkts; + if (odp_unlikely((tmp >= 100000) || /* OR first print: */ + ((pkt_cnt == 0) && ((tmp-1) < MAX_PKT_BURST)))) { + pkt_cnt += tmp; + printf(" [%02i] pkt_cnt:%lu\n", thr, pkt_cnt); + fflush(NULL); + tmp = 0; + } } return arg; @@ -193,14 +319,22 @@ int main(int argc, char *argv[]) /* Create and init worker threads */ memset(thread_tbl, 0, sizeof(thread_tbl)); for (i = 0; i < num_workers; ++i) { + void *(*thr_run_func) (void *); int if_idx = i % args->appl.if_count; + args->thread[i].pktio_dev = args->appl.if_names[if_idx]; args->thread[i].pool = pool; + args->thread[i].mode = args->appl.mode; + + if (args->appl.mode == APPL_MODE_PKT_BURST) + thr_run_func = pktio_ifburst_thread; + else /* APPL_MODE_PKT_QUEUE */ + thr_run_func = pktio_queue_thread; /* * Create threads one-by-one instead of all-at-once, * because each thread might get different arguments */ - odp_linux_pthread_create(thread_tbl, 1, i, pktio_thread, + odp_linux_pthread_create(thread_tbl, 1, i, thr_run_func, &args->thread[i]); } @@ -228,12 +362,15 @@ static void parse_args(int argc, char *argv[], appl_args_t *appl_args) int i; static struct option longopts[] = { {"interface", required_argument, NULL, 'i'}, /* return 'i' */ + {"mode", required_argument, NULL, 'm'}, /* return 'm' */ {"help", no_argument, NULL, 'h'}, /* return 'h' */ {NULL, 0, NULL, 0} }; + appl_args->mode = -1; /* Invalid, must be changed by parsing */ + while (1) { - opt = getopt_long(argc, argv, "+i:h", longopts, &long_index); + opt = getopt_long(argc, argv, "+i:m:h", longopts, &long_index); if (opt == -1) break; /* No more options */ @@ -282,6 +419,14 @@ static void parse_args(int argc, char *argv[], appl_args_t *appl_args) } break; + case 'm': + i = atoi(optarg); + if (i == 0) + appl_args->mode = APPL_MODE_PKT_BURST; + else + appl_args->mode = APPL_MODE_PKT_QUEUE; + break; + case 'h': usage(argv[0]); exit(EXIT_SUCCESS); @@ -292,7 +437,7 @@ static void parse_args(int argc, char *argv[], appl_args_t *appl_args) } } - if (appl_args->if_count == 0) { + if (appl_args->if_count == 0 || appl_args->mode == -1) { usage(argv[0]); exit(EXIT_FAILURE); } @@ -326,6 +471,12 @@ static void print_info(char *progname, appl_args_t *appl_args) progname, appl_args->if_count); for (i = 0; i < appl_args->if_count; ++i) printf(" %s", appl_args->if_names[i]); + printf("\n" + "Mode: "); + if (appl_args->mode == APPL_MODE_PKT_BURST) + PRINT_APPL_MODE(APPL_MODE_PKT_BURST); + else + PRINT_APPL_MODE(APPL_MODE_PKT_QUEUE); printf("\n\n"); fflush(NULL); } @@ -337,12 +488,14 @@ static void usage(char *progname) { printf("\n" "Usage: %s OPTIONS\n" - " E.g. %s -i eth1,eth2,eth3\n" + " E.g. %s -i eth1,eth2,eth3 -m 0\n" "\n" "OpenDataPlane example application.\n" "\n" "Mandatory OPTIONS:\n" - " -i, --interface Eth interfaces (comma-separated list, no spaces)\n" + " -i, --interface Eth interfaces (comma-separated, no spaces)\n" + " -m, --mode 0: Burst send&receive packets (no queues)\n" + " 1: Send&receive packets through ODP queues.\n" "\n" "Optional OPTIONS\n" " -h, --help Display help and exit.\n" |