@@ -38,6 +38,7 @@ extern "C" {
#include <odp/shared_memory.h>
#include <odp/buffer.h>
#include <odp/pool.h>
+#include <odp/pktout.h>
#include <odp/queue.h>
#include <odp/ticketlock.h>
#include <odp/time.h>
new file mode 100644
@@ -0,0 +1,276 @@
+/* Copyright (c) 2015, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/**
+ * @file
+ *
+ * ODP packet descriptor
+ */
+
+#ifndef ODP_API_PACKET_OUT_H_
+#define ODP_API_PACKET_OUT_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <odp/std_types.h>
+#include <odp/buffer.h>
+#include <odp/packet_io.h>
+#include <odp/schedule.h>
+
+/**
+ * Number of packet output scheduling priorities per pktio interface
+ * This function returns the number of pktout scheduling priority
+ * supported in the platform per pktio interface.
+ *
+ * @param[in] pktio pktio handle
+ *
+ * @retval Number of packet output scheduling priorities
+ * @retval 1 if the pktio does not support pktout priority
+ */
+int odp_pktout_num_prio(odp_pktio_t pktio);
+
+/**
+* Gets the total number of hierarchy level supported by the platform
+* for output packet shaping and scheduling
+*
+* @return Total number of hierarchy supported
+*/
+uint8_t odp_pktout_num_heirarchy(void);
+
+/* Get Maximum nuber of packet output queues that can be attached with
+* the given pktio interface. This will be the total number of packet output
+* queues supported by the pktio interface. This number is different from the
+* pktout node which are points in the hierarchial tree.
+*
+* @param[in] pktio pktio handle
+*
+* @retval Number of output queues that can be attached to the
+* given pktio handle
+* @retval 1 if the pktout scheduling is not supported
+*/
+uint32_t odp_pktout_max_queues(odp_pktio_t pktio);
+
+/* Assign outq to pktio interface
+* Sets the outq into the pktio interface, Any queues that maybe previously
+* associated with this pktio will be superseded by this queue array.
+* The number of queues associate in the pktio interface must not exceed the
+* maximum supported output queue given by odp_pktout_max_queues() function
+* for the same pktio interface.
+* Calling this function with num_queues set to zero will disassociate all
+* the queues that are linked to this pktio interface
+*
+* @param[in] pktio pktio handle
+* @param[in] queue_hdl[] Array of queue handles
+* @param[in] num_queues Number of queue handles in the array
+*
+* @return Number of queues associated
+* <0 in case of failure
+*/
+int odp_pktout_set_queues(odp_pktio_t pktio,
+ odp_pktout_queue_t queue_hdl[],
+ uint32_t num_queues);
+
+/*
+* Get the packet output queues which are associated with the
+* pktio interface. This function is used to read the list of
+* queues which are currently associated with the given pktio interface
+*
+* @param[in] pktio pktio handle
+* @param[out] queue_hdl Array of queue handle
+* @param[in/out] queue_elements During input will be the size of the queue
+* array and output will be the number of
+* elements written to queue_hdl
+*
+* @return 0 on success
+* @retval <0 on failure
+*/
+int odp_pktout_queues(odp_pktio_t pktio,
+ odp_pktout_queue_t queue_hdl[],
+ uint32_t *queue_elements);
+
+#define MAX_PKTOUT_PRIO 10
+
+/** Pktio PKTOUT queue parameters
+* @note: The below parameter is just a placeholder and the actual
+* signature of the parameter will be modified once hierarchial
+* information is added to the parameters.
+*/
+typedef struct odp_pktout_queue_param_t {
+ int num; /**< number of queues */
+ odp_schedule_prio_t prio[MAX_PKTOUT_PRIO]; /**< priority value */
+} odp_pktout_queue_param_t;
+
+/* Creates the outq for the given pktio interface
+* This function overrides any previously associated queues with the interface
+* The queues created using this function will be of type ODP_QUEUE_TYE_PKTOUT
+* @param[in] pktio_id pktio handle
+* @param[in] qparam parameter for queue creation
+* @param[out] queue[] Array of created queue handles
+*
+* @return Number of queues created
+* <0 on failure
+*
+*/
+int odp_pktout_queue_create(odp_pktio_t pktio_id,
+ odp_pktout_queue_param_t param,
+ odp_pktout_queue_t queue[]);
+
+/** Packet out queue level parameters **/
+
+/**
+* Get packet output queue priority
+* Returns the priority of the packet output queue
+*
+* @param[in] queue_hdl Packet out queue handle
+*
+* @return Priority value of the input queue
+* @retval <0 on failure
+*/
+int odp_pktout_queue_priority(odp_pktout_queue_t queue_hdl);
+
+/**
+* Sets the queue limit in terms of number of packets.
+* This limit determines the amount of data that a queue is allowed to accept.
+* The queue will not receive any packet beyond the set limit and will return
+* an error value.
+*
+* @param[in] queue_hdl Queue Handle
+* @param[in] pkt_cnt Maximum number of packets the queue may contain
+*
+* @return Packet limit set
+* @retval <0 on failure
+*
+* @note This function is called only for ODP_QUEUE_TYPE_PKTOUT
+**/
+int odp_pktout_queue_limit_set(odp_pktout_queue_t queue_hdl, uint32_t pkt_cnt);
+
+/**
+* Gets the number of packets limit set on the queue
+* This function is used to get the limit in terms of number of packet which is
+* set on the given queue
+*
+* @param[in] queue_hdl Queue Handle
+*
+* @return Packet limit set
+* @retval <0 on failure
+*
+* @note This function is called only for ODP_QUEUE_TYPE_PKTOUT
+**/
+int odp_pktout_queue_limit(odp_pktout_queue_t queue_hdl);
+
+/**
+* Queue depth in terms of the number of packets
+* Gets the current depth of the queue in terms of the number of packets
+* which can be used by the application to find the current load on the queue
+*
+* @param[in] queue_hdl Queue handle
+*
+* @return Current packets count in the queue
+* @retval <0 on failure
+*
+* @note This function is called only for ODP_QUEUE_TYPE_PKTOUT
+**/
+int odp_pktout_queue_packets(odp_pktout_queue_t queue_hdl);
+
+/**
+* Queue depth in terms of the number of octets
+* Gets the current depth of the queue in terms of the number of Octets
+* which can be used by the application to find the current load on the queue
+*
+* @param[in] queue_hdl Queue handle
+*
+* @return Current octect count in the queue
+* @retval <0 on failure
+* @note This function is called only for ODP_QUEUE_TYPE_PKTOUT
+*/
+int odp_pktout_queue_octets(odp_pktout_queue_t queue_hdl);
+
+/**
+* Set Committed Information Rate and Committed Burst size
+* sets cir and cbs on the packet out queue.
+* cir is set in kbps and CBS is in bytes.
+*
+* @param[in] queue_hdl Queue handle
+* @param[in] rate_kbps CIR rate in kbps
+* @param[in] burst_bytes CBS in bytes
+*
+* @retval 0 on success
+* @retval <0 on failure
+**/
+int odp_pktout_cir_set(odp_pktout_queue_t queue_hdl,
+ uint32_t rate_kbps, uint32_t burst_bytes);
+
+/**
+* Set Peak Information Rate and Peak Burst size
+* sets pir and pbs on the packet out queue.
+* pir is set in kbps and PBS is in bytes.
+*
+* @param[in] queue_hdl Queue handle
+* @param[in] rate_kbps PIR rate in kbps
+* @param[in] burst_bytes PBS in bytes
+*
+* @retval 0 on success
+* @retval <0 on failure
+**/
+
+int odp_pktout_pir_set(odp_pktout_queue_t queue_hdl,
+ uint32_t rate_kbps, uint32_t burst_bytes);
+
+/**
+* Port level rate limitting
+* sets the rate limiting and burst size at the interface level
+* This value will be equal to the line rate
+*
+* @param[in] pktio Pktio handle
+* @param[in] rate_kbps Port level rate in kbps
+* @param[in] burst_bytes Port level burst bytes
+*
+* @retval 0 on success
+* @retval <0 on failure
+*/
+int odp_pktio_rate_set(odp_pktio_t pktio, uint32_t rate_kbps,
+ uint32_t burst_bytes);
+
+/**
+* Packet output queue enq
+* Enqueues the packet into odp_pktout_queue_t queue.
+*
+* @param[in] pkt Packet handle
+* @param[in] queue Packet output queue handle
+*
+* @retval 0 Success
+* @retval <0 Failure
+*/
+int odp_pktout_enq(odp_pktout_queue_t queue, odp_packet_t pkt);
+
+/**
+* Packet output queue enqueue with feedback
+* Enqueues the packet into odp_pktout_queue_t queue.
+* Additionally this function returns the depth of the packet output queue
+* interms of the number of packets before this packet is enqueued.
+*
+* @retval >0 Number of Packets to the packet limit, before this packet.
+* @retval 0 Queue full.
+* @retval <0 Failure
+*/
+int32_t odp_pktout_enq_depth(odp_pktout_queue_t queue, odp_packet_t pkt);
+
+/**
+* Packet output queue priority
+*
+* @param queue Packet output queue handle
+*
+* @return Packet output queue schedule priority
+*/
+odp_schedule_prio_t odp_pktout_sched_prio(odp_pktout_queue_t queue);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
@@ -4,6 +4,7 @@ include $(top_srcdir)/platform/Makefile.inc
AM_CFLAGS += -I$(srcdir)/include
AM_CFLAGS += -I$(top_srcdir)/include
AM_CFLAGS += -I$(top_srcdir)/helper/include
+AM_CFLAGS += -g
SUBDIRS = test
@@ -58,6 +59,7 @@ odpplatinclude_HEADERS = \
$(top_srcdir)/platform/linux-generic/include/odp/plat/crypto_types.h \
$(top_srcdir)/platform/linux-generic/include/odp/plat/event_types.h \
$(top_srcdir)/platform/linux-generic/include/odp/plat/packet_types.h \
+ $(top_srcdir)/platform/linux-generic/include/odp/plat/pktout_types.h \
$(top_srcdir)/platform/linux-generic/include/odp/plat/packet_io_types.h \
$(top_srcdir)/platform/linux-generic/include/odp/plat/pool_types.h \
$(top_srcdir)/platform/linux-generic/include/odp/plat/queue_types.h \
@@ -91,6 +93,7 @@ odpapiinclude_HEADERS = \
$(top_srcdir)/include/odp/api/packet.h \
$(top_srcdir)/include/odp/api/packet_flags.h \
$(top_srcdir)/include/odp/api/packet_io.h \
+ $(top_srcdir)/include/odp/api/pktout.h \
$(top_srcdir)/include/odp/api/pool.h \
$(top_srcdir)/include/odp/api/queue.h \
$(top_srcdir)/include/odp/api/random.h \
@@ -153,6 +156,7 @@ __LIB__libodp_la_SOURCES = \
odp_impl.c \
../../helper/linux.c \
odp_packet.c \
+ odp_packet_out.c \
odp_packet_flags.c \
odp_packet_io.c \
odp_packet_socket.c \
new file mode 100644
@@ -0,0 +1,30 @@
+/* Copyright (c) 2015, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/**
+ * @file
+ *
+ * ODP queue
+ */
+
+#ifndef ODP_PLAT_PKTOUT_H_
+#define ODP_PLAT_PKTOUT_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <odp/std_types.h>
+#include <odp/plat/event_types.h>
+#include <odp/plat/pktout_types.h>
+
+#include <odp/api/pktout.h>
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
new file mode 100644
@@ -0,0 +1,44 @@
+/* Copyright (c) 2015, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/**
+ * @file
+ *
+ * ODP Packet output queue
+ */
+
+#ifndef ODP_PKTOUT_TYPES_H_
+#define ODP_PKTOUT_TYPES_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <odp/std_types.h>
+#include <odp/plat/strong_types.h>
+
+typedef ODP_HANDLE_T(odp_pktout_queue_t);
+
+#define ODP_PKTOUT_INVALID _odp_cast_scalar(odp_pktout_queue_t, 0)
+
+#define MAX_PKTOUT_QUEUE 10
+
+#define PKTIO_MAX_PRIORITY 10
+
+#define ODP_PKTOUT_QUEUES 1024
+
+#define ODP_CONFID_PKTOUT_PRIOS 10
+
+#define PKTOUT_QUEUE_PER_PRIO 10
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
@@ -64,6 +64,9 @@ int odp_classification_term_global(void);
int odp_queue_init_global(void);
int odp_queue_term_global(void);
+int odp_pktout_init_global(void);
+int odp_pktout_term_global(void);
+
int odp_crypto_init_global(void);
int odp_crypto_term_global(void);
@@ -23,10 +23,12 @@ extern "C" {
#include <odp_classification_datamodel.h>
#include <odp_align_internal.h>
#include <odp_debug_internal.h>
-
+#include <odp_packet_out_internal.h>
+#include <odp/pktout.h>
#include <odp/config.h>
#include <odp/hints.h>
#include <linux/if.h>
+#include <odp/helper/linux.h>
/**
* Packet IO types
@@ -53,6 +55,12 @@ struct pktio_entry {
char name[IFNAMSIZ]; /**< name of pktio provided to
pktio_open() */
odp_bool_t promisc; /**< promiscuous mode state */
+ int max_pktout_queues;
+ int priority;
+ pktout_node_entry_t root_node;
+ odp_pktout_queue_t pktout[MAX_PKTOUT_QUEUE];
+ odph_linux_pthread_t pktout_thread;
+ int num_hierarchy;
};
typedef union {
@@ -88,6 +96,8 @@ static inline pktio_entry_t *get_pktio_entry(odp_pktio_t pktio)
int pktin_poll(pktio_entry_t *entry);
+int __odp_pktio_send(pktio_entry_t *entry, odp_packet_t pkt_table[], int len);
+
#ifdef __cplusplus
}
#endif
new file mode 100644
@@ -0,0 +1,164 @@
+/* Copyright (c) 2013, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ODP_PKTOUT_INTERNAL_H_
+#define ODP_PKTOUT_INTERNAL_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <odp/pktout.h>
+#include <odp_buffer_internal.h>
+#include <odp_align_internal.h>
+#include <odp/packet_io.h>
+#include <odp/align.h>
+#include <time.h>
+#include <odp/helper/ring.h>
+
+#define USE_TICKETLOCK
+
+#ifdef USE_TICKETLOCK
+#include <odp/ticketlock.h>
+#else
+#include <odp/spinlock.h>
+#endif
+
+#define QUEUE_MULTI_MAX 8
+
+#define QUEUE_STATUS_FREE 0
+#define QUEUE_STATUS_DESTROYED 1
+#define QUEUE_STATUS_READY 2
+#define QUEUE_STATUS_NOTSCHED 3
+#define QUEUE_STATUS_SCHED 4
+
+#define QUEUE_CIR_KBPS 0 /* 0kbps */
+#define QUEUE_CBS_BYTE 2000 /* 2000 bytes */
+#define QUEUE_PIR_KBPS 0 /* 0 kbps */
+#define QUEUE_PBS_BYTE 4000 /* 4000 bytes */
+
+#define NODE_CIR_KBPS 20 /* 20 kbps */
+#define NODE_CBS_BYTE 4000 /* 4000 bytes */
+#define NODE_PIR_KBPS 40 /* 40 kbps */
+#define NODE_PBS_BYTE 6000 /* 4000 bytes */
+
+typedef struct pktout_shaper_param_s {
+ odp_atomic_u64_t cir_kbps;
+ odp_atomic_u64_t cbs_byte;
+ odp_atomic_u64_t cur_cir;
+ odp_atomic_u64_t pir_kbps;
+ odp_atomic_u64_t pbs_byte;
+ odp_atomic_u64_t cur_pir;
+ odp_atomic_u64_t time;
+} pktout_shaper_param_t;
+
+struct pktout_entry_s {
+#ifdef USE_TICKETLOCK
+ odp_ticketlock_t lock ODP_ALIGNED_CACHE;
+#else
+ odp_spinlock_t lock ODP_ALIGNED_CACHE;
+#endif
+
+ int status;
+ odp_pktout_queue_t handle;
+ odph_ring_t *ring;
+ odp_pktout_queue_param_t param;
+ int priority;
+ odp_pktio_t pktio;
+ char name[ODP_QUEUE_NAME_LEN];
+ pktout_shaper_param_t shaper;
+ uint32_t limit_pkt;
+ uint32_t limit_oct;
+};
+
+typedef union pktout_entry_u {
+ struct pktout_entry_s s;
+ uint8_t pad[ODP_CACHE_LINE_SIZE_ROUNDUP(sizeof(struct pktout_entry_s))];
+} pktout_entry_t;
+
+struct pktout_node_entry_s {
+ int num_child;
+ int is_leaf;
+ int is_root;
+ int priority;
+ pktout_shaper_param_t shaper;
+ uint32_t pri_count[ODP_CONFID_PKTOUT_PRIOS];
+ void *pri_queue[ODP_CONFID_PKTOUT_PRIOS][PKTOUT_QUEUE_PER_PRIO];
+};
+
+typedef union pktout_node_entry_u {
+ struct pktout_node_entry_s s;
+ uint8_t pad[ODP_CACHE_LINE_SIZE_ROUNDUP(sizeof
+ (struct pktout_node_entry_s))];
+} pktout_node_entry_t;
+
+pktout_entry_t *get_pktout_qentry(uint32_t pktout_id);
+
+odp_packet_t deq_pktout_queue(pktout_entry_t *queue, uint64_t *traffic);
+
+odp_packet_t deq_pktout_node(pktout_node_entry_t *node, uint64_t *traffic);
+
+odp_packet_t __deq_pktout_node(pktout_node_entry_t *node, uint64_t *traffic);
+
+void *__send_packet(void *args);
+
+static inline uint32_t pktout_to_id(odp_pktout_queue_t handle)
+{
+ return _odp_typeval(handle) - 1;
+}
+
+static inline odp_pktout_queue_t pktout_from_id(uint32_t pktout_id)
+{
+ return _odp_cast_scalar(odp_pktout_queue_t, pktout_id + 1);
+}
+
+int pktout_schedule_queue_init(pktout_entry_t *pktout,
+ pktout_node_entry_t *node);
+
+typedef odp_packet_t (*deq_pktout_node_func_t)(pktout_node_entry_t *node);
+typedef odp_packet_t (*deq_pktout_queue_func_t)(pktout_entry_t *queue);
+
+static inline void pktout_init(pktout_entry_t *queue)
+{
+ queue->s.pktio = ODP_PKTIO_INVALID;
+ queue->s.limit_pkt = 1024;
+ queue->s.limit_oct = 1024 * 524;
+ odp_atomic_init_u64(&queue->s.shaper.cir_kbps, QUEUE_CIR_KBPS * 1000);
+ odp_atomic_init_u64(&queue->s.shaper.cbs_byte, QUEUE_CBS_BYTE * 1000);
+ odp_atomic_init_u64(&queue->s.shaper.pir_kbps, QUEUE_PIR_KBPS * 1000);
+ odp_atomic_init_u64(&queue->s.shaper.pbs_byte, QUEUE_PBS_BYTE * 1000);
+ odp_atomic_init_u64(&queue->s.shaper.cur_cir, 0);
+ odp_atomic_init_u64(&queue->s.shaper.cur_pir, 0);
+ odp_atomic_init_u64(&queue->s.shaper.time, time(NULL));
+ queue->s.ring = odph_ring_create(queue->s.name, queue->s.limit_pkt, 0);
+}
+
+static inline void pktout_node_init(pktout_node_entry_t *node)
+{
+ node->s.num_child = 0;
+ node->s.is_leaf = 0;
+ node->s.priority = PKTIO_MAX_PRIORITY;
+ int i, j;
+
+ odp_atomic_init_u64(&node->s.shaper.cir_kbps, NODE_CIR_KBPS * 1000);
+ odp_atomic_init_u64(&node->s.shaper.cbs_byte, NODE_CBS_BYTE);
+ odp_atomic_init_u64(&node->s.shaper.pir_kbps, NODE_PIR_KBPS * 1000);
+ odp_atomic_init_u64(&node->s.shaper.pbs_byte, NODE_PBS_BYTE);
+ odp_atomic_init_u64(&node->s.shaper.cur_cir, 0);
+ odp_atomic_init_u64(&node->s.shaper.cur_pir, 0);
+ odp_atomic_init_u64(&node->s.shaper.time, time(NULL));
+ for (i = 0; i < ODP_CONFID_PKTOUT_PRIOS; i++) {
+ node->s.pri_count[i] = 0;
+ for (j = 0; j < PKTOUT_QUEUE_PER_PRIO; j++)
+ node->s.pri_queue[i][j] = NULL;
+ }
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
@@ -52,6 +52,11 @@ int odp_init_global(odp_init_t *params,
return -1;
}
+ if (odp_pktout_init_global()) {
+ ODP_ERR("ODP packet out init failed.\n");
+ return -1;
+ }
+
if (odp_pktio_init_global()) {
ODP_ERR("ODP packet io init failed.\n");
return -1;
@@ -9,6 +9,7 @@
#include <odp_packet_io_queue.h>
#include <odp/packet.h>
#include <odp_packet_internal.h>
+#include <odp_packet_out_internal.h>
#include <odp_internal.h>
#include <odp/spinlock.h>
#include <odp/shared_memory.h>
@@ -76,6 +77,8 @@ int odp_pktio_init_global(void)
queue_entry = queue_to_qentry(qid);
queue_entry->s.pktout = _odp_cast_scalar(odp_pktio_t, id);
+ pktio_entry->s.root_node.s.is_root = 1;
+ pktout_node_init(&pktio_entry->s.root_node);
}
return 0;
@@ -244,6 +247,7 @@ static odp_pktio_t setup_pktio_entry(const char *dev, odp_pool_t pool)
odp_pktio_t id;
pktio_entry_t *pktio_entry;
int ret;
+ int cpu;
if (strlen(dev) >= IFNAMSIZ) {
/* ioctl names limitation */
@@ -278,7 +282,19 @@ static odp_pktio_t setup_pktio_entry(const char *dev, odp_pool_t pool)
unlock_entry_classifier(pktio_entry);
}
+ pktio_entry->s.priority = PKTIO_MAX_PRIORITY;
+
pktio_entry->s.handle = id;
+ odp_cpumask_t cpumask;
+ odp_cpumask_t mask;
+ /* These functions are planned to be modified in the new API
+ version and the same will be reflected once in the repo */
+ odph_linux_cpumask_default(&cpumask, 1);
+ odp_cpumask_zero(&mask);
+ cpu = odp_cpumask_first(&cpumask);
+ odp_cpumask_set(&mask, cpu);
+ odph_linux_pthread_create(&pktio_entry->s.pktout_thread, &mask,
+ __send_packet, pktio_entry);
return id;
}
@@ -297,7 +313,6 @@ odp_pktio_t odp_pktio_open(const char *dev, odp_pool_t pool)
odp_spinlock_lock(&pktio_tbl->lock);
id = setup_pktio_entry(dev, pool);
odp_spinlock_unlock(&pktio_tbl->lock);
-
return id;
}
@@ -441,33 +456,39 @@ static int enq_loopback(pktio_entry_t *pktio_entry, odp_packet_t pkt_tbl[],
int odp_pktio_send(odp_pktio_t id, odp_packet_t pkt_table[], int len)
{
- pktio_entry_t *pktio_entry = get_pktio_entry(id);
- int pkts;
+ pktio_entry_t *entry = get_pktio_entry(id);
- if (pktio_entry == NULL)
+ if (!entry)
return -1;
+ return __odp_pktio_send(entry, pkt_table, len);
+}
- lock_entry(pktio_entry);
- switch (pktio_entry->s.type) {
+int __odp_pktio_send(pktio_entry_t *entry, odp_packet_t pkt_table[], int len)
+{
+ int pkts;
+
+ /* todo further optimization required in these functions */
+ lock_entry(entry);
+ switch (entry->s.type) {
case ODP_PKTIO_TYPE_SOCKET_BASIC:
- pkts = send_pkt_sock_basic(&pktio_entry->s.pkt_sock,
- pkt_table, len);
+ pkts = send_pkt_sock_basic(&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);
+ pkts = send_pkt_sock_mmsg(&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);
+ pkts = send_pkt_sock_mmap(&entry->s.pkt_sock_mmap,
+ pkt_table, len);
break;
case ODP_PKTIO_TYPE_LOOPBACK:
- pkts = enq_loopback(pktio_entry, pkt_table, len);
+ pkts = enq_loopback(entry, pkt_table, len);
break;
default:
pkts = -1;
}
- unlock_entry(pktio_entry);
+ unlock_entry(entry);
return pkts;
}
new file mode 100644
@@ -0,0 +1,454 @@
+/* Copyright (c) 2015, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <odp/pktout.h>
+#include <odp_packet_out_internal.h>
+#include <odp/std_types.h>
+#include <odp/align.h>
+#include <odp/buffer.h>
+#include <odp_buffer_internal.h>
+#include <odp_pool_internal.h>
+#include <odp_buffer_inlines.h>
+#include <odp_internal.h>
+#include <odp/shared_memory.h>
+#include <odp_schedule_internal.h>
+#include <odp/config.h>
+#include <odp_packet_io_internal.h>
+#include <odp_packet_out_internal.h>
+#include <odp_packet_io_queue.h>
+#include <odp_debug_internal.h>
+#include <odp/hints.h>
+#include <odp/sync.h>
+#include <odp/helper/ip.h>
+#include <unistd.h>
+
+#ifdef USE_TICKETLOCK
+#include <odp/ticketlock.h>
+#define LOCK(a) odp_ticketlock_lock(a)
+#define UNLOCK(a) odp_ticketlock_unlock(a)
+#define LOCK_INIT(a) odp_ticketlock_init(a)
+#else
+#include <odp/spinlock.h>
+#define LOCK(a) odp_spinlock_lock(a)
+#define UNLOCK(a) odp_spinlock_unlock(a)
+#define LOCK_INIT(a) odp_spinlock_init(a)
+#endif
+
+/* todo redefine this */
+#define MAX_BURST 10
+
+typedef struct queue_table_t {
+ pktout_entry_t pktout_queue[ODP_PKTOUT_QUEUES];
+} pktout_queue_table_t;
+
+static pktout_queue_table_t *pktout_tbl;
+
+pktout_entry_t *get_pktout_qentry(uint32_t queue_id)
+{
+ return &pktout_tbl->pktout_queue[queue_id];
+}
+
+int odp_pktout_init_global(void)
+{
+ uint32_t i;
+ odp_shm_t shm;
+
+ ODP_DBG("Queue init ... ");
+
+ shm = odp_shm_reserve("odp_pktout_queues",
+ sizeof(pktout_queue_table_t),
+ sizeof(pktout_entry_t), 0);
+
+ pktout_tbl = odp_shm_addr(shm);
+
+ if (!pktout_tbl)
+ return -1;
+
+ memset(pktout_tbl, 0, sizeof(pktout_queue_table_t));
+
+ for (i = 0; i < ODP_PKTOUT_QUEUES; i++) {
+ /* init locks */
+ pktout_entry_t *pktout;
+
+ pktout = get_pktout_qentry(i);
+ LOCK_INIT(&pktout->s.lock);
+
+ pktout->s.handle = pktout_from_id(i);
+ }
+
+ ODP_DBG("done\n");
+ ODP_DBG("Pktout queue init global\n");
+ ODP_DBG(" struct pktout_entry_s size %zu\n",
+ sizeof(struct pktout_entry_s));
+ ODP_DBG(" pktout_entry_t size %zu\n",
+ sizeof(pktout_entry_t));
+ ODP_DBG("\n");
+ /** Init odp ring attached with pktout queues */
+ odph_ring_tailq_init();
+ return 0;
+}
+
+int pktout_schedule_queue_init(pktout_entry_t *pktout,
+ pktout_node_entry_t *node)
+{
+ int priority;
+ int pri_count;
+
+ node->s.is_leaf = 1;
+ priority = pktout->s.priority;
+ pri_count = node->s.pri_count[priority]++;
+ node->s.pri_queue[priority][pri_count] = pktout;
+ return 0;
+}
+
+int odp_pktout_num_prio(odp_pktio_t pktio)
+{
+ pktio_entry_t *entry;
+
+ entry = get_pktio_entry(pktio);
+ if (!entry)
+ return -1;
+
+ return entry->s.priority;
+}
+
+uint8_t odp_pktout_num_heirarchy(void)
+{
+ /** Linux-generic implementation can support multiple hierarchy
+ but the current API version only supports only hierarchy level*/
+ return 1;
+}
+
+uint32_t odp_pktout_max_queues(odp_pktio_t pktio)
+{
+ pktio_entry_t *entry = get_pktio_entry(pktio);
+
+ return entry->s.max_pktout_queues;
+}
+
+int odp_pktout_queue_create(odp_pktio_t pktio_id,
+ odp_pktout_queue_param_t param,
+ odp_pktout_queue_t queue_hdl[])
+{
+ uint32_t i;
+ int j;
+ pktout_entry_t *queue;
+ odp_pktout_queue_t handle = ODP_PKTOUT_INVALID;
+ pktio_entry_t *entry = get_pktio_entry(pktio_id);
+ pktout_node_entry_t *node = &entry->s.root_node;
+
+ for (j = 0; j < param.num; j++) {
+ for (i = 0; i < ODP_PKTOUT_QUEUES; i++) {
+ queue = &pktout_tbl->pktout_queue[i];
+
+ if (queue->s.status != QUEUE_STATUS_FREE)
+ continue;
+
+ LOCK(&queue->s.lock);
+ if (queue->s.status == QUEUE_STATUS_FREE) {
+ sprintf(queue->s.name, "%s%d",
+ "pktout", (j + i));
+ pktout_init(queue);
+
+ queue->s.priority = param.prio[j];
+
+ queue->s.status = QUEUE_STATUS_READY;
+ queue->s.pktio = pktio_id;
+
+ handle = queue->s.handle;
+ UNLOCK(&queue->s.lock);
+ break;
+ }
+ UNLOCK(&queue->s.lock);
+ }
+ if (i != ODP_PKTOUT_QUEUES)
+ queue_hdl[j] = handle;
+ else
+ break;
+
+ if (handle != ODP_PKTOUT_INVALID) {
+ if (pktout_schedule_queue_init(queue, node)) {
+ ODP_ERR("pktout schedule queue init failed\n");
+ return -1;
+ }
+ }
+ }
+
+ return j;
+}
+
+int odp_pktout_queue_limit_set(odp_pktout_queue_t queue_hdl, uint32_t pkt_cnt)
+{
+ uint32_t id;
+ pktout_entry_t *entry;
+
+ id = pktout_to_id(queue_hdl);
+ entry = get_pktout_qentry(id);
+ entry->s.limit_pkt = pkt_cnt;
+ /* current implementation uses a fixed limit and once API
+ gets finalized the implementation will use the value set
+ by this function */
+ return 1;
+}
+
+int odp_pktout_queue_limit(odp_pktout_queue_t queue_hdl)
+{
+ uint32_t id;
+ pktout_entry_t *entry;
+
+ id = pktout_to_id(queue_hdl);
+ entry = get_pktout_qentry(id);
+ return entry->s.limit_pkt;
+}
+
+int odp_pktout_queue_priority(odp_pktout_queue_t queue_hdl)
+{
+ uint32_t id;
+ pktout_entry_t *entry;
+
+ id = pktout_to_id(queue_hdl);
+ entry = get_pktout_qentry(id);
+ return entry->s.priority;
+}
+
+int odp_pktout_queue_packets(odp_pktout_queue_t queue_hdl)
+{
+ uint32_t id;
+ pktout_entry_t *queue;
+
+ id = pktout_to_id(queue_hdl);
+ queue = get_pktout_qentry(id);
+ return odph_ring_count(queue->s.ring);
+}
+
+int odp_pktout_queue_octets(odp_pktout_queue_t queue_hdl ODP_UNUSED)
+{
+ return 0;
+}
+
+odp_packet_t __deq_pktout_node(pktout_node_entry_t *node, uint64_t *traffic)
+{
+ int i, j;
+ int priority;
+ int num_queue;
+ odp_packet_t pkt;
+ pktout_node_entry_t *child;
+ pktout_entry_t *queue;
+
+ pkt = ODP_PACKET_INVALID;
+ priority = node->s.priority;
+
+ for (i = 0; i < priority; i++) {
+ num_queue = node->s.pri_count[i];
+ for (j = 0; j < num_queue; j++) {
+ if (node->s.is_leaf) {
+ queue = node->s.pri_queue[i][j];
+ pkt = deq_pktout_queue(queue, traffic);
+ } else {
+ child = node->s.pri_queue[i][j];
+ pkt = deq_pktout_node(child, traffic);
+ }
+ if (pkt != ODP_PACKET_INVALID)
+ break;
+ }
+ if (pkt != ODP_PACKET_INVALID)
+ break;
+ }
+ return pkt;
+}
+
+odp_packet_t deq_pktout_node(pktout_node_entry_t *node, uint64_t *traffic)
+{
+ odp_packet_t pkt = ODP_PACKET_INVALID;
+
+ uint64_t cur_time;
+ uint64_t node_time;
+ uint64_t cir;
+ uint64_t pir;
+
+ cur_time = time(NULL);
+ node_time = odp_atomic_load_u64(&node->s.shaper.time);
+ cir = odp_atomic_load_u64(&node->s.shaper.cir_kbps);
+ pir = odp_atomic_load_u64(&node->s.shaper.pir_kbps);
+
+ if (node_time < cur_time) {
+ /* this snippet reached once every second and resets the
+ cir and pir values*/
+ if (odp_atomic_load_u64(&node->s.shaper.cur_cir) > cir)
+ odp_atomic_sub_u64(&node->s.shaper.cur_cir, cir);
+ else
+ odp_atomic_store_u64(&node->s.shaper.cur_cir, 0);
+
+ if (odp_atomic_load_u64(&node->s.shaper.cur_pir) > pir)
+ odp_atomic_sub_u64(&node->s.shaper.cur_pir, pir);
+ else
+ odp_atomic_store_u64(&node->s.shaper.cur_pir, 0);
+
+ odp_atomic_store_u64(&node->s.shaper.time, cur_time);
+ if (node->s.is_root)
+ *traffic = 0;
+ }
+
+ /* in the input if *traffic is not zero then the queues are
+ requested to dispatch the peak traffic. in the output this
+ *traffic denotes the data dequeued in bits */
+
+ if (odp_atomic_load_u64(&node->s.shaper.cur_cir) < cir) {
+ pkt = __deq_pktout_node(node, traffic);
+ odp_atomic_add_u64(&node->s.shaper.cur_cir, *traffic);
+ odp_atomic_add_u64(&node->s.shaper.cur_pir, *traffic);
+ } else if (*traffic) {
+ if (odp_atomic_load_u64(&node->s.shaper.cur_pir) < pir) {
+ pkt = __deq_pktout_node(node, traffic);
+ odp_atomic_add_u64(&node->s.shaper.cur_pir, *traffic);
+ }
+ }
+ if (node->s.is_root)
+ if (pkt == ODP_PACKET_INVALID)
+ *traffic = 1;
+ return pkt;
+}
+
+odp_packet_t deq_pktout_queue(pktout_entry_t *queue, uint64_t *traffic)
+{
+ void *pkt_tbl[1];
+ int ret;
+ uint64_t cur_time;
+ uint64_t queue_time;
+ uint64_t cir;
+ uint64_t pir;
+ odph_ipv4hdr_t *ip;
+
+ cur_time = time(NULL);
+ queue_time = odp_atomic_load_u64(&queue->s.shaper.time);
+ cir = odp_atomic_load_u64(&queue->s.shaper.cir_kbps);
+ pir = odp_atomic_load_u64(&queue->s.shaper.pir_kbps);
+
+ if (queue_time < cur_time) {
+ if (odp_atomic_load_u64(&queue->s.shaper.cur_cir) > cir)
+ odp_atomic_sub_u64(&queue->s.shaper.cur_cir, cir);
+ else
+ odp_atomic_store_u64(&queue->s.shaper.cur_cir, 0);
+
+ if (odp_atomic_load_u64(&queue->s.shaper.cur_pir) > pir)
+ odp_atomic_sub_u64(&queue->s.shaper.cur_pir, pir);
+ else
+ odp_atomic_store_u64(&queue->s.shaper.cur_pir, 0);
+
+ odp_atomic_store_u64(&queue->s.shaper.time, cur_time);
+ }
+
+ if (odp_atomic_load_u64(&queue->s.shaper.cur_cir) < cir) {
+ ret = odph_ring_mc_dequeue_bulk(queue->s.ring, pkt_tbl, 1);
+ if (0 > ret)
+ /*todo: check for ENOENT */
+ return ODP_PACKET_INVALID;
+
+ ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(pkt_tbl[0], NULL);
+ *traffic = odp_be_to_cpu_16(ip->tot_len);
+ *traffic = (*traffic) * 8;
+ odp_atomic_add_u64(&queue->s.shaper.cur_cir, *traffic);
+ odp_atomic_add_u64(&queue->s.shaper.cur_pir, *traffic);
+ return (odp_packet_t)pkt_tbl[0];
+ } else if (*traffic) {
+ if (odp_atomic_load_u64(&queue->s.shaper.cur_pir) < pir) {
+ ret = odph_ring_mc_dequeue_bulk(queue->s.ring,
+ pkt_tbl, 1);
+ if (0 > ret)
+ return ODP_PACKET_INVALID;
+
+ ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(pkt_tbl[0],
+ NULL);
+ *traffic = odp_be_to_cpu_16(ip->tot_len);
+ *traffic = (*traffic) * 8;
+ odp_atomic_add_u64(&queue->s.shaper.cur_pir, *traffic);
+ return (odp_packet_t)pkt_tbl[0];
+ }
+ }
+ return ODP_PACKET_INVALID;
+}
+
+void *__send_packet(void *pktio)
+{
+ /* goes over the loop and send the packet for the pktio */
+ pktio_entry_t *entry;
+ pktout_node_entry_t *node;
+ odp_packet_t pkt_tbl[1];
+
+ entry = (pktio_entry_t *)pktio;
+ node = &entry->s.root_node;
+ uint64_t traffic;
+
+ while (1) {
+ traffic = 0;
+ pkt_tbl[0] = deq_pktout_node(node, &traffic);
+ if (pkt_tbl[0] != ODP_PACKET_INVALID)
+ __odp_pktio_send(pktio, pkt_tbl, 1);
+ }
+ return NULL;
+}
+
+int odp_pktout_enq(odp_pktout_queue_t queue_hdl, odp_packet_t pkt)
+{
+ uint32_t id;
+ pktout_entry_t *queue;
+ void *pkt_tbl[1];
+ int ret;
+
+ id = pktout_to_id(queue_hdl);
+ queue = get_pktout_qentry(id);
+ pkt_tbl[0] = pkt;
+ /** todo check the return value */
+ ret = odph_ring_mp_enqueue_bulk(queue->s.ring, pkt_tbl, 1);
+ if (ret == -ENOBUFS)
+ return ret;
+
+ return 0;
+}
+
+int odp_pktout_cir_set(odp_pktout_queue_t queue_hdl,
+ uint32_t rate_kbps, uint32_t burst_bytes)
+{
+ uint32_t id;
+ pktout_entry_t *queue;
+
+ id = pktout_to_id(queue_hdl);
+ queue = get_pktout_qentry(id);
+ odp_atomic_store_u64(&queue->s.shaper.cir_kbps, rate_kbps * 1000);
+ odp_atomic_store_u64(&queue->s.shaper.cbs_byte, burst_bytes);
+ return 0;
+}
+
+int odp_pktout_pir_set(odp_pktout_queue_t queue_hdl,
+ uint32_t rate_kbps, uint32_t burst_bytes)
+{
+ uint32_t id;
+ pktout_entry_t *queue;
+
+ id = pktout_to_id(queue_hdl);
+ queue = get_pktout_qentry(id);
+ odp_atomic_store_u64(&queue->s.shaper.pir_kbps, rate_kbps * 1000);
+ odp_atomic_store_u64(&queue->s.shaper.pbs_byte, burst_bytes);
+ return 0;
+}
+
+int odp_pktio_rate_set(odp_pktio_t pktio, uint32_t rate_kbps,
+ uint32_t burst_bytes)
+{
+ pktio_entry_t *entry;
+ pktout_node_entry_t *node;
+
+ entry = get_pktio_entry(pktio);
+ if (!entry)
+ return -1;
+ node = &entry->s.root_node;
+
+ odp_atomic_store_u64(&node->s.shaper.cir_kbps, rate_kbps * 1000);
+ odp_atomic_store_u64(&node->s.shaper.cbs_byte, burst_bytes);
+ odp_atomic_store_u64(&node->s.shaper.pir_kbps, rate_kbps * 1000);
+ odp_atomic_store_u64(&node->s.shaper.pbs_byte, burst_bytes);
+ return 0;
+}