diff --git a/include/odp.h b/include/odp.h
index 2bac510..b8df7d3 100644
--- a/include/odp.h
+++ b/include/odp.h
@@ -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>
diff --git a/include/odp/api/pktout.h b/include/odp/api/pktout.h
new file mode 100644
index 0000000..0d64a61
--- /dev/null
+++ b/include/odp/api/pktout.h
@@ -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
diff --git a/platform/linux-generic/Makefile.am b/platform/linux-generic/Makefile.am
index 66f0474..ddb8c7c 100644
--- a/platform/linux-generic/Makefile.am
+++ b/platform/linux-generic/Makefile.am
@@ -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 \
diff --git a/platform/linux-generic/include/odp/pktout.h b/platform/linux-generic/include/odp/pktout.h
new file mode 100644
index 0000000..16628f0
--- /dev/null
+++ b/platform/linux-generic/include/odp/pktout.h
@@ -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
diff --git a/platform/linux-generic/include/odp/plat/pktout_types.h b/platform/linux-generic/include/odp/plat/pktout_types.h
new file mode 100644
index 0000000..2902eef
--- /dev/null
+++ b/platform/linux-generic/include/odp/plat/pktout_types.h
@@ -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
diff --git a/platform/linux-generic/include/odp_internal.h b/platform/linux-generic/include/odp_internal.h
index 8c5d339..186906f 100644
--- a/platform/linux-generic/include/odp_internal.h
+++ b/platform/linux-generic/include/odp_internal.h
@@ -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);
 
diff --git a/platform/linux-generic/include/odp_packet_io_internal.h b/platform/linux-generic/include/odp_packet_io_internal.h
index 18b59ef..367d1e2 100644
--- a/platform/linux-generic/include/odp_packet_io_internal.h
+++ b/platform/linux-generic/include/odp_packet_io_internal.h
@@ -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
diff --git a/platform/linux-generic/include/odp_packet_out_internal.h b/platform/linux-generic/include/odp_packet_out_internal.h
new file mode 100644
index 0000000..f68fb6e
--- /dev/null
+++ b/platform/linux-generic/include/odp_packet_out_internal.h
@@ -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
diff --git a/platform/linux-generic/odp_init.c b/platform/linux-generic/odp_init.c
index bf36e68..1f1a55f 100644
--- a/platform/linux-generic/odp_init.c
+++ b/platform/linux-generic/odp_init.c
@@ -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;
diff --git a/platform/linux-generic/odp_packet_io.c b/platform/linux-generic/odp_packet_io.c
index 5ae24b9..765f763 100644
--- a/platform/linux-generic/odp_packet_io.c
+++ b/platform/linux-generic/odp_packet_io.c
@@ -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;
 }
diff --git a/platform/linux-generic/odp_packet_out.c b/platform/linux-generic/odp_packet_out.c
new file mode 100644
index 0000000..b4d262a
--- /dev/null
+++ b/platform/linux-generic/odp_packet_out.c
@@ -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;
+}
