[dpdk-dev] [PATCH] lib: Initial implementation of PQoS lib with CAT and CDP support

Wojciech Andralojc wojciechx.andralojc at intel.com
Fri Jan 29 14:17:14 CET 2016


Please see initial implementation of DPDK  PQoS library which enables
Cache Allocation Technology (CAT) and its extension,
Code Data Prioritization (CDP). Current library version uses MSR registers
to program these technologies. This is due to lack of broad enabling in
OS frameworks. As the OS support becomes available the implementation
will change to make use of available OS interfaces.

Signed-off-by: Wojciech Andralojc <wojciechx.andralojc at intel.com>
---

CAT and CDP features allow to manage CPU's last level cache.
CAT introduces classes of service (COS) that essentially are bitmasks.
In current CAT implementations, a bit in a COS bitmask corresponds to
one cache way in last level cache. CPU cores can be assigned to
one of the classes. By programming CPU core assignment and
COS bitmasks applications can be given exclusive, shared,
or mixed access to CPU's last level cache.
CDP extends CAT so that there are two bitmasks per COS,
one for data and one for code. The number of classes and number of
valid bits in a COS bitmask is CPU model specific and they are
discovered by the library. By default, after reset, all CPU cores are
assigned to COS 0 and all classes are programmed to allow fill into
all cache ways. CDP is off by default. 

Patch introducing EAL parameters to configure CAT and CDP will follow.

Known issues:
- checkpatches.sh LONG_LINE warnings;
- lcore_id cannot be treated as  a logical core id anymore,
  need to retrieve logical core id corresponding to lcore_id in the library

 MAINTAINERS                                   |   4 +
 config/common_linuxapp                        |   8 +
 config/defconfig_i686-native-linuxapp-gcc     |   3 +
 config/defconfig_i686-native-linuxapp-icc     |   3 +
 config/defconfig_x86_64-native-linuxapp-clang |   3 +
 config/defconfig_x86_64-native-linuxapp-gcc   |   3 +
 config/defconfig_x86_64-native-linuxapp-icc   |   3 +
 config/defconfig_x86_x32-native-linuxapp-gcc  |   3 +
 lib/Makefile                                  |   1 +
 lib/librte_eal/common/eal_common_lcore.c      |  38 ++
 lib/librte_eal/common/eal_private.h           |   9 +
 lib/librte_eal/common/include/rte_eal.h       |   4 +
 lib/librte_eal/common/include/rte_lcore.h     | 188 ++++++++
 lib/librte_eal/common/include/rte_log.h       |   3 +
 lib/librte_eal/linuxapp/eal/Makefile          |   3 +
 lib/librte_eal/linuxapp/eal/eal.c             |   8 +
 lib/librte_eal/linuxapp/eal/eal_lcore.c       |  25 ++
 lib/librte_pqos/Makefile                      |  53 +++
 lib/librte_pqos/allocation.c                  | 561 ++++++++++++++++++++++++
 lib/librte_pqos/capabilities.c                | 598 ++++++++++++++++++++++++++
 lib/librte_pqos/rte_pqos.h                    | 248 +++++++++++
 lib/librte_pqos/rte_pqos_common.c             | 141 ++++++
 lib/librte_pqos/rte_pqos_common.h             | 183 ++++++++
 lib/librte_pqos/rte_pqos_version.map          |  16 +
 mk/rte.app.mk                                 |   2 +
 25 files changed, 2111 insertions(+)
 create mode 100644 lib/librte_pqos/Makefile
 create mode 100644 lib/librte_pqos/allocation.c
 create mode 100644 lib/librte_pqos/capabilities.c
 create mode 100644 lib/librte_pqos/rte_pqos.h
 create mode 100644 lib/librte_pqos/rte_pqos_common.c
 create mode 100644 lib/librte_pqos/rte_pqos_common.h
 create mode 100644 lib/librte_pqos/rte_pqos_version.map

diff --git a/MAINTAINERS b/MAINTAINERS
index b90aeea..aa593d7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -233,6 +233,10 @@ F: lib/librte_cryptodev/
 F: app/test/test_cryptodev*
 F: examples/l2fwd-crypto/
 
+PQoS API
+M: Kantecki, Tomasz <tomasz.kantecki at intel.com>
+K: RTE_LIBRTE_PQOS
+F: lib/librte_pqos/
 
 Drivers
 -------
diff --git a/config/common_linuxapp b/config/common_linuxapp
index 74bc515..553e640 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -99,6 +99,7 @@ CONFIG_RTE_NEXT_ABI=y
 CONFIG_RTE_LIBRTE_EAL=y
 CONFIG_RTE_MAX_LCORE=128
 CONFIG_RTE_MAX_NUMA_NODES=8
+CONFIG_RTE_MAX_PHY_PKGS=8
 CONFIG_RTE_MAX_MEMSEG=256
 CONFIG_RTE_MAX_MEMZONE=2560
 CONFIG_RTE_MAX_TAILQ=32
@@ -514,6 +515,13 @@ CONFIG_RTE_LIBRTE_VHOST_NUMA=n
 CONFIG_RTE_LIBRTE_VHOST_DEBUG=n
 
 #
+# Compile librte_pqos
+# IA only
+# LIBRTE_PQOS is for librte_pqos only
+CONFIG_RTE_LIBRTE_PQOS=n
+CONFIG_RTE_LIBRTE_PQOS_DEBUG=n
+
+#
 #Compile Xen domain0 support
 #
 CONFIG_RTE_LIBRTE_XEN_DOM0=n
diff --git a/config/defconfig_i686-native-linuxapp-gcc b/config/defconfig_i686-native-linuxapp-gcc
index a90de9b..a73b999 100644
--- a/config/defconfig_i686-native-linuxapp-gcc
+++ b/config/defconfig_i686-native-linuxapp-gcc
@@ -49,3 +49,6 @@ CONFIG_RTE_LIBRTE_KNI=n
 # Vectorized PMD is not supported on 32-bit
 #
 CONFIG_RTE_IXGBE_INC_VECTOR=n
+
+# Enable PQoS
+CONFIG_RTE_LIBRTE_PQOS=y
\ No newline at end of file
diff --git a/config/defconfig_i686-native-linuxapp-icc b/config/defconfig_i686-native-linuxapp-icc
index c021321..f454955 100644
--- a/config/defconfig_i686-native-linuxapp-icc
+++ b/config/defconfig_i686-native-linuxapp-icc
@@ -49,3 +49,6 @@ CONFIG_RTE_LIBRTE_KNI=n
 # Vectorized PMD is not supported on 32-bit
 #
 CONFIG_RTE_IXGBE_INC_VECTOR=n
+
+# Enable PQoS
+CONFIG_RTE_LIBRTE_PQOS=y
\ No newline at end of file
diff --git a/config/defconfig_x86_64-native-linuxapp-clang b/config/defconfig_x86_64-native-linuxapp-clang
index 5f3074e..57a7ad5 100644
--- a/config/defconfig_x86_64-native-linuxapp-clang
+++ b/config/defconfig_x86_64-native-linuxapp-clang
@@ -40,3 +40,6 @@ CONFIG_RTE_ARCH_64=y
 
 CONFIG_RTE_TOOLCHAIN="clang"
 CONFIG_RTE_TOOLCHAIN_CLANG=y
+
+# Enable PQoS
+CONFIG_RTE_LIBRTE_PQOS=y
\ No newline at end of file
diff --git a/config/defconfig_x86_64-native-linuxapp-gcc b/config/defconfig_x86_64-native-linuxapp-gcc
index 60baf5b..d4ba885 100644
--- a/config/defconfig_x86_64-native-linuxapp-gcc
+++ b/config/defconfig_x86_64-native-linuxapp-gcc
@@ -40,3 +40,6 @@ CONFIG_RTE_ARCH_64=y
 
 CONFIG_RTE_TOOLCHAIN="gcc"
 CONFIG_RTE_TOOLCHAIN_GCC=y
+
+# Enable PQoS
+CONFIG_RTE_LIBRTE_PQOS=y
\ No newline at end of file
diff --git a/config/defconfig_x86_64-native-linuxapp-icc b/config/defconfig_x86_64-native-linuxapp-icc
index 71d1e28..829b8f3 100644
--- a/config/defconfig_x86_64-native-linuxapp-icc
+++ b/config/defconfig_x86_64-native-linuxapp-icc
@@ -40,3 +40,6 @@ CONFIG_RTE_ARCH_64=y
 
 CONFIG_RTE_TOOLCHAIN="icc"
 CONFIG_RTE_TOOLCHAIN_ICC=y
+
+# Enable PQoS
+CONFIG_RTE_LIBRTE_PQOS=y
\ No newline at end of file
diff --git a/config/defconfig_x86_x32-native-linuxapp-gcc b/config/defconfig_x86_x32-native-linuxapp-gcc
index fb0afc4..4140a95 100644
--- a/config/defconfig_x86_x32-native-linuxapp-gcc
+++ b/config/defconfig_x86_x32-native-linuxapp-gcc
@@ -44,3 +44,6 @@ CONFIG_RTE_TOOLCHAIN_GCC=y
 # KNI is not supported on 32-bit
 #
 CONFIG_RTE_LIBRTE_KNI=n
+
+# Enable PQoS
+CONFIG_RTE_LIBRTE_PQOS=y
\ No newline at end of file
diff --git a/lib/Makefile b/lib/Makefile
index ef172ea..dca10f6 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -58,6 +58,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_PORT) += librte_port
 DIRS-$(CONFIG_RTE_LIBRTE_TABLE) += librte_table
 DIRS-$(CONFIG_RTE_LIBRTE_PIPELINE) += librte_pipeline
 DIRS-$(CONFIG_RTE_LIBRTE_REORDER) += librte_reorder
+DIRS-$(CONFIG_RTE_LIBRTE_PQOS) += librte_pqos
 
 ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y)
 DIRS-$(CONFIG_RTE_LIBRTE_KNI) += librte_kni
diff --git a/lib/librte_eal/common/eal_common_lcore.c b/lib/librte_eal/common/eal_common_lcore.c
index a4263ba..42eec8e 100644
--- a/lib/librte_eal/common/eal_common_lcore.c
+++ b/lib/librte_eal/common/eal_common_lcore.c
@@ -42,6 +42,10 @@
 #include <rte_common.h>
 #include <rte_debug.h>
 
+#ifdef RTE_LIBRTE_PQOS
+#include <rte_pqos.h>
+#endif
+
 #include "eal_private.h"
 #include "eal_thread.h"
 
@@ -93,18 +97,52 @@ rte_eal_cpu_init(void)
 				RTE_MAX_NUMA_NODES);
 #endif
 
+#ifdef RTE_LIBRTE_PQOS
+		lcore_config[lcore_id].phy_pkg_id = eal_cpu_phy_pkg_id(lcore_id);
+
+		if (lcore_config[lcore_id].phy_pkg_id < RTE_MAX_PHY_PKGS)
+			phy_pkg_config[lcore_config[lcore_id].phy_pkg_id].detected = 1;
+		else
+			rte_panic("Physical Package ID (%u) is greater than "
+				"RTE_MAX_PHY_PKGS (%d)\n",
+				lcore_config[lcore_id].phy_pkg_id,
+				RTE_MAX_PHY_PKGS);
+
+		RTE_LOG(DEBUG, EAL, "Detected lcore %u as "
+				"core %u on NUMA node %u in physical package/socket %u\n",
+				lcore_id, lcore_config[lcore_id].core_id,
+				lcore_config[lcore_id].socket_id,
+				lcore_config[lcore_id].phy_pkg_id);
+#else /* !RTE_LIBRTE_PQOS */
 		RTE_LOG(DEBUG, EAL, "Detected lcore %u as "
 				"core %u on socket %u\n",
 				lcore_id, lcore_config[lcore_id].core_id,
 				lcore_config[lcore_id].socket_id);
+#endif
 		count++;
 	}
 	/* Set the count of enabled logical cores of the EAL configuration */
 	config->lcore_count = count;
+
+#ifdef RTE_LIBRTE_PQOS
+	/* Set the count of physical packages */
+	unsigned phy_pkg_id = RTE_MAX_PHY_PKGS;
+	config->phy_pkg_count = 0;
+	RTE_PHY_PKG_FOREACH(phy_pkg_id)
+		config->phy_pkg_count++;
+#endif
+
 	RTE_LOG(DEBUG, EAL,
 		"Support maximum %u logical core(s) by configuration.\n",
 		RTE_MAX_LCORE);
+
+#ifdef RTE_LIBRTE_PQOS
+	RTE_LOG(DEBUG, EAL, "Detected %u lcore(s) in %u physical packages/sockets\n"
+			, config->lcore_count
+			, config->phy_pkg_count);
+#else /* !RTE_LIBRTE_PQOS */
 	RTE_LOG(DEBUG, EAL, "Detected %u lcore(s)\n", config->lcore_count);
+#endif
 
 	return 0;
 }
diff --git a/lib/librte_eal/common/eal_private.h b/lib/librte_eal/common/eal_private.h
index 072e672..4d3d283 100644
--- a/lib/librte_eal/common/eal_private.h
+++ b/lib/librte_eal/common/eal_private.h
@@ -346,4 +346,13 @@ int rte_eal_hugepage_init(void);
  */
 int rte_eal_hugepage_attach(void);
 
+#ifdef RTE_LIBRTE_PQOS
+/**
+ * Get cpu physical_package_id.
+ *
+ * This function is private to the EAL.
+ */
+unsigned eal_cpu_phy_pkg_id(unsigned lcore_id);
+#endif
+
 #endif /* _EAL_PRIVATE_H_ */
diff --git a/lib/librte_eal/common/include/rte_eal.h b/lib/librte_eal/common/include/rte_eal.h
index d2816a8..574c0a1 100644
--- a/lib/librte_eal/common/include/rte_eal.h
+++ b/lib/librte_eal/common/include/rte_eal.h
@@ -89,6 +89,10 @@ struct rte_config {
 	 * Intel DPDK instances
 	 */
 	struct rte_mem_config *mem_config;
+
+#ifdef RTE_LIBRTE_PQOS
+	uint32_t phy_pkg_count;        /**< Number of physical packages/sockets. */
+#endif
 } __attribute__((__packed__));
 
 /**
diff --git a/lib/librte_eal/common/include/rte_lcore.h b/lib/librte_eal/common/include/rte_lcore.h
index 25460b9..ef4235b 100644
--- a/lib/librte_eal/common/include/rte_lcore.h
+++ b/lib/librte_eal/common/include/rte_lcore.h
@@ -73,6 +73,9 @@ struct lcore_config {
 	unsigned core_id;          /**< core number on socket for this lcore */
 	int core_index;            /**< relative index, starting from 0 */
 	rte_cpuset_t cpuset;       /**< cpu set which the lcore affinity to */
+#ifdef RTE_LIBRTE_PQOS
+	unsigned phy_pkg_id;       /**< physical packaged/socket number for this lcore */
+#endif
 };
 
 /**
@@ -80,6 +83,20 @@ struct lcore_config {
  */
 extern struct lcore_config lcore_config[RTE_MAX_LCORE];
 
+#ifdef RTE_LIBRTE_PQOS
+/**
+ * Structure storing internal configuration (per-phy-pkg)
+ */
+struct phy_pkg_config {
+	unsigned detected;         /**< true if phy-pkg was detected */
+};
+
+/**
+ * List of physical packages/sockets
+ */
+extern struct phy_pkg_config phy_pkg_config[RTE_MAX_PHY_PKGS];
+#endif
+
 RTE_DECLARE_PER_LCORE(unsigned, _lcore_id);  /**< Per thread "lcore id". */
 RTE_DECLARE_PER_LCORE(rte_cpuset_t, _cpuset); /**< Per thread "cpuset". */
 
@@ -268,6 +285,177 @@ void rte_thread_get_affinity(rte_cpuset_t *cpusetp);
 #endif
 #endif
 
+#ifdef RTE_LIBRTE_PQOS
+/**
+ * Test if an lcore is valid/detected lcore in system.
+ *
+ * @param lcore_id
+ *   The identifier of the lcore, which MUST be between 0 and
+ *   RTE_MAX_LCORE-1.
+ * @return
+ *   True if the given lcore is valid; false otherwise.
+ */
+static inline unsigned
+rte_lcore_is_detected(const unsigned lcore_id)
+{
+	if (lcore_id >= RTE_MAX_LCORE)
+		return 0;
+
+	return lcore_config[lcore_id].detected;
+}
+
+/**
+ * Returns number of physical packages/sockets in CPU topology
+ *
+ * @return
+ *  - Number of CPU sockets
+ *  - 0 on error
+ */
+static inline unsigned
+rte_phy_pkg_count(void)
+{
+	return rte_eal_get_configuration()->phy_pkg_count;
+}
+
+/**
+ * Get the ID of the physical package of the specified lcore
+ *
+ * @param lcore_id
+ *   the targeted lcore, which MUST be between 0 and RTE_MAX_LCORE-1.
+ * @return
+ *   the ID of lcoreid's physical package or -1 if lcore is not valid.
+ */
+static inline int
+rte_lcore_to_phy_pkg_id(const unsigned lcore_id)
+{
+	if (lcore_id >= RTE_MAX_LCORE)
+		return -1;
+
+	return lcore_config[lcore_id].phy_pkg_id;
+}
+
+/**
+ * Get the next detected lcore ID.
+ *
+ * @param i
+ *   The current lcore (reference).
+ * @param wrap
+ *   If true, go back to 0 when RTE_MAX_LCORE is reached; otherwise,
+ *   return RTE_MAX_LCORE.
+ * @return
+ *   The next lcore_id or RTE_MAX_LCORE if not found.
+ */
+static inline unsigned
+rte_get_next_detected_lcore(unsigned i, const int wrap)
+{
+	i++;
+	if (wrap)
+		i %= RTE_MAX_LCORE;
+
+	while (i < RTE_MAX_LCORE) {
+		if (rte_lcore_is_detected(i) == 0) {
+			i++;
+			if (wrap)
+				i %= RTE_MAX_LCORE;
+			continue;
+		}
+		break;
+	}
+	return i;
+}
+
+/**
+ * Macro to browse all detected lcores.
+ */
+#define RTE_LCORE_FOREACH_DETECTED(i)				\
+	for (i = rte_get_next_detected_lcore(-1, 0);	\
+	     i < RTE_MAX_LCORE;							\
+	     i = rte_get_next_detected_lcore(i, 0))
+
+/**
+ * Test if an lcore is valid lcore in system.
+ *
+ * @param lcore_id
+ *   The identifier of the lcore, which MUST be between 0 and
+ *   RTE_MAX_LCORE-1.
+ * @return
+ *   True if the given lcore is valid; false otherwise.
+ */
+static inline unsigned
+rte_phy_pkg_is_detected(const unsigned phy_pkg_id)
+{
+	if (phy_pkg_id >= RTE_MAX_PHY_PKGS)
+		return 0;
+
+	return phy_pkg_config[phy_pkg_id].detected;
+}
+
+/**
+ * Get the next physical package/socket ID.
+ *
+ * @param i
+ *   The current physical package/socket (reference).
+ * @param wrap
+ *   If true, go back to 0 when RTE_MAX_PHY_PKGS is reached; otherwise,
+ *   return RTE_MAX_PHY_PKGS.
+ * @return
+ *   The next phy_pkg_id or RTE_MAX_PHY_PKGS if not found.
+ */
+static inline unsigned
+rte_get_next_phy_pkg(unsigned i, const int wrap)
+{
+	i++;
+	if (wrap)
+		i %= RTE_MAX_PHY_PKGS;
+
+	while (i < RTE_MAX_PHY_PKGS) {
+		if (rte_phy_pkg_is_detected(i) == 0) {
+			i++;
+			if (wrap)
+				i %= RTE_MAX_PHY_PKGS;
+			continue;
+		}
+		break;
+	}
+	return i;
+}
+/**
+ * Macro to browse all physical packages/sockets.
+ */
+#define RTE_PHY_PKG_FOREACH(i)						\
+	for (i = rte_get_next_phy_pkg(-1, 0);			\
+	     i < RTE_MAX_PHY_PKGS;						\
+	     i = rte_get_next_phy_pkg(i, 0))
+
+/**
+ * Get the first lcore ID on physical package/socket.
+ *
+* @param phy_pkg_id
+ *   the targeted phy_pkg_id, which MUST be between 0 and RTE_MAX_PHY_PKGS-1.
+ *
+ * @return
+ *   lcore_id or RTE_MAX_LCORE if not found.
+ */
+static inline unsigned
+rte_phy_pkg_id_to_lcore(const unsigned phy_pkg_id)
+{
+	unsigned lcore_id = RTE_MAX_LCORE;
+	unsigned i = 0;
+
+	if (phy_pkg_id >= RTE_MAX_PHY_PKGS)
+		return RTE_MAX_LCORE;
+
+	RTE_LCORE_FOREACH_DETECTED(i) {
+		if (lcore_config[i].phy_pkg_id == phy_pkg_id) {
+			lcore_id = i;
+			break;
+		}
+	}
+
+	return lcore_id;
+}
+#endif /* RTE_LIBRTE_PQOS */
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_eal/common/include/rte_log.h b/lib/librte_eal/common/include/rte_log.h
index 2e47e7f..d94c7b9 100644
--- a/lib/librte_eal/common/include/rte_log.h
+++ b/lib/librte_eal/common/include/rte_log.h
@@ -79,6 +79,9 @@ extern struct rte_logs rte_logs;
 #define RTE_LOGTYPE_PIPELINE 0x00008000 /**< Log related to pipeline. */
 #define RTE_LOGTYPE_MBUF    0x00010000 /**< Log related to mbuf. */
 #define RTE_LOGTYPE_CRYPTODEV 0x00020000 /**< Log related to cryptodev. */
+#ifdef RTE_LIBRTE_PQOS
+#define RTE_LOGTYPE_PQOS    0x00040000 /**< Log related to pqos. */
+#endif
 
 /* these log types can be used in an application */
 #define RTE_LOGTYPE_USER1   0x01000000 /**< User-defined log type 1. */
diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
index 26eced5..97bd360 100644
--- a/lib/librte_eal/linuxapp/eal/Makefile
+++ b/lib/librte_eal/linuxapp/eal/Makefile
@@ -45,6 +45,9 @@ CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common/include
 CFLAGS += -I$(RTE_SDK)/lib/librte_ring
 CFLAGS += -I$(RTE_SDK)/lib/librte_mempool
 CFLAGS += -I$(RTE_SDK)/lib/librte_ivshmem
+ifeq ($(CONFIG_RTE_LIBRTE_PQOS),y)
+CFLAGS += -I$(RTE_SDK)/lib/librte_pqos
+endif
 CFLAGS += $(WERROR_FLAGS) -O3
 
 # specific to linuxapp exec-env
diff --git a/lib/librte_eal/linuxapp/eal/eal.c b/lib/librte_eal/linuxapp/eal/eal.c
index 635ec36..15e806c 100644
--- a/lib/librte_eal/linuxapp/eal/eal.c
+++ b/lib/librte_eal/linuxapp/eal/eal.c
@@ -74,6 +74,9 @@
 #include <rte_version.h>
 #include <rte_atomic.h>
 #include <malloc_heap.h>
+#ifdef RTE_LIBRTE_PQOS
+#include <rte_pqos.h>
+#endif
 
 #include "eal_private.h"
 #include "eal_thread.h"
@@ -111,6 +114,11 @@ static struct rte_config rte_config = {
 /* internal configuration (per-core) */
 struct lcore_config lcore_config[RTE_MAX_LCORE];
 
+#ifdef RTE_LIBRTE_PQOS
+/* internal list of physical packages/sockets */
+struct phy_pkg_config phy_pkg_config[RTE_MAX_PHY_PKGS];
+#endif
+
 /* internal configuration */
 struct internal_config internal_config;
 
diff --git a/lib/librte_eal/linuxapp/eal/eal_lcore.c b/lib/librte_eal/linuxapp/eal/eal_lcore.c
index de5b426..ff0d9a8 100644
--- a/lib/librte_eal/linuxapp/eal/eal_lcore.c
+++ b/lib/librte_eal/linuxapp/eal/eal_lcore.c
@@ -50,6 +50,9 @@
 #define SYS_CPU_DIR "/sys/devices/system/cpu/cpu%u"
 #define CORE_ID_FILE "topology/core_id"
 #define NUMA_NODE_PATH "/sys/devices/system/node"
+#ifdef RTE_LIBRTE_PQOS
+#define PHY_PKG_ID_FILE "topology/physical_package_id"
+#endif
 
 /* Check if a cpu is present by the presence of the cpu information for it */
 int
@@ -108,3 +111,25 @@ err:
 			"for lcore %u - assuming core 0\n", SYS_CPU_DIR, lcore_id);
 	return 0;
 }
+
+#ifdef RTE_LIBRTE_PQOS
+/* Get the cpu core id value from the /sys/.../cpuX physical_package_id value */
+unsigned
+eal_cpu_phy_pkg_id(unsigned lcore_id)
+{
+	char path[PATH_MAX];
+	unsigned long id;
+
+	int len = snprintf(path, sizeof(path), SYS_CPU_DIR "/%s", lcore_id, PHY_PKG_ID_FILE);
+	if (len <= 0 || (unsigned)len >= sizeof(path))
+		goto err;
+	if (eal_parse_sysfs_value(path, &id) != 0)
+		goto err;
+	return (unsigned)id;
+
+err:
+	RTE_LOG(ERR, EAL, "Error reading physical_package_id value from %s "
+			"for lcore %u - assuming physical package 0\n", SYS_CPU_DIR, lcore_id);
+	return 0;
+}
+#endif
diff --git a/lib/librte_pqos/Makefile b/lib/librte_pqos/Makefile
new file mode 100644
index 0000000..d214940
--- /dev/null
+++ b/lib/librte_pqos/Makefile
@@ -0,0 +1,53 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2016 Intel Corporation. All rights reserved.
+#   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 Intel Corporation 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
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (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.
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+# library name
+LIB = librte_pqos.a
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR)
+
+EXPORT_MAP := rte_pqos_version.map
+
+LIBABIVER := 1
+
+# all source are stored in SRCS-y
+SRCS-$(CONFIG_RTE_LIBRTE_PQOS) := capabilities.c allocation.c rte_pqos_common.c
+
+# install this header file
+SYMLINK-$(CONFIG_RTE_LIBRTE_PQOS)-include := rte_pqos.h
+
+# this lib needs eal
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PQOS) += lib/librte_eal
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_pqos/allocation.c b/lib/librte_pqos/allocation.c
new file mode 100644
index 0000000..6913b65
--- /dev/null
+++ b/lib/librte_pqos/allocation.c
@@ -0,0 +1,561 @@
+/*
+ * BSD LICENSE
+ *
+ * Copyright(c) 2016 Intel Corporation. All rights reserved.
+ * 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 Intel Corporation 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
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (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.O
+ *
+ */
+
+/**
+ * Implementation of CAT related PQoS API
+ *
+ * Module operate directly on CAT registers.
+ */
+
+#include <inttypes.h>
+#include <pthread.h>
+#include <string.h>
+
+#include <rte_lcore.h>
+#include <rte_log.h>
+
+#include "rte_pqos.h"
+#include "rte_pqos_common.h"
+
+/**
+ * Enables or disables CDP across all CPU sockets
+ *
+ * @param enable
+ *  CDP enable/disable flag, 1 - enable, 0 - disable
+ *
+ * @return
+ *  - PQOS_RETVAL_OK success
+ *  - PQOS_RETVAL_ERROR failure
+ */
+static int
+pqos_cdp_enable(const unsigned enable)
+{
+	unsigned phy_pkg_id = RTE_MAX_PHY_PKGS;
+
+	RTE_LOG(INFO, PQOS, "%s CDP across all sockets...\n",
+		(enable) ? "Enabling" : "Disabling");
+
+	RTE_PHY_PKG_FOREACH(phy_pkg_id) {
+		uint64_t reg = 0;
+		int retval = -1;
+
+		const unsigned lcore_id = rte_phy_pkg_id_to_lcore(phy_pkg_id);
+		if (lcore_id == RTE_MAX_LCORE) {
+			RTE_LOG(ERR, PQOS, "%s:%u: Invalid physical package id: %u!\n",
+				__func__, __LINE__, phy_pkg_id);
+			return PQOS_RETVAL_ERROR;
+		}
+
+		retval = rte_msr_read(lcore_id, PQOS_MSR_L3_QOS_CFG, &reg);
+		if (retval != 0)
+			return PQOS_RETVAL_ERROR;
+
+		if (enable)
+			reg |= PQOS_MSR_L3_QOS_CFG_CDP_EN;
+		else
+			reg &= ~PQOS_MSR_L3_QOS_CFG_CDP_EN;
+
+		retval = rte_msr_write(lcore_id, PQOS_MSR_L3_QOS_CFG, reg);
+		if (retval != 0)
+			return PQOS_RETVAL_ERROR;
+	}
+
+	return PQOS_RETVAL_OK;
+}
+
+/**
+ * L3 cache allocation
+ */
+
+int
+rte_pqos_l3ca_set(const unsigned phy_pkg_id, const unsigned num_ca,
+		const struct rte_pqos_l3ca *ca)
+{
+	unsigned i = 0;
+	int retval = -1;
+
+	RTE_PQOS_ASSERT(phy_pkg_id < RTE_MAX_PHY_PKGS);
+	RTE_PQOS_ASSERT(num_ca != 0);
+	RTE_PQOS_ASSERT(ca != NULL);
+	RTE_PQOS_ASSERT(rte_pqos_cap != NULL);
+	RTE_PQOS_ASSERT(rte_pqos_cap->cap_l3ca != NULL);
+
+	rte_pqos_api_lock();
+
+	if (rte_pqos_cap == NULL || rte_pqos_cap->cap_l3ca == NULL || num_ca == 0 ||
+			num_ca > rte_pqos_cap->cap_l3ca->cos_num || ca == NULL ||
+			phy_pkg_id >= RTE_MAX_PHY_PKGS) {
+		rte_pqos_api_unlock();
+		RTE_LOG(ERR, PQOS, "%s:%u: Invalid params or PQoS not initialized!\n",
+			__func__, __LINE__);
+		return -1;
+	}
+
+	if (rte_phy_pkg_is_detected(phy_pkg_id) != 1) {
+		rte_pqos_api_unlock();
+		RTE_LOG(ERR, PQOS, "%s:%u: Invalid physical package id: %u!\n",
+			__func__, __LINE__, phy_pkg_id);
+		return -1;
+	}
+
+	const unsigned lcore_id = rte_phy_pkg_id_to_lcore(phy_pkg_id);
+	if (rte_lcore_is_detected(lcore_id) != 1) {
+		rte_pqos_api_unlock();
+		RTE_LOG(ERR, PQOS, "%s:%u: Invalid lcore id: %u!\n",
+			__func__, __LINE__,  lcore_id);
+		return -1;
+	}
+
+	if (rte_pqos_cap->cap_l3ca->cdp_on) {
+		for (i = 0; i < num_ca; i++) {
+			const uint32_t reg = (ca[i].cos_id * 2) + PQOS_MSR_L3CA_MASK_START;
+			uint64_t cmask = 0;
+			uint64_t dmask = 0;
+
+			if (ca[i].cdp) {
+				dmask = ca[i].data_mask;
+				cmask = ca[i].code_mask;
+			} else {
+				dmask = ca[i].mask;
+				cmask = ca[i].mask;
+			}
+
+			retval = rte_msr_write(lcore_id, reg, dmask);
+			if (retval != 0) {
+				rte_pqos_api_unlock();
+				return -1;
+			}
+
+			retval = rte_msr_write(lcore_id, reg + 1, cmask);
+			if (retval != 0) {
+				rte_pqos_api_unlock();
+				return -1;
+			}
+		}
+	} else {
+		for (i = 0; i < num_ca; i++) {
+			const uint32_t reg = ca[i].cos_id + PQOS_MSR_L3CA_MASK_START;
+			const uint64_t val = ca[i].mask;
+
+			if (ca[i].cdp) {
+				RTE_LOG(ERR, PQOS, "%s:%u: Attempting to set CDP COS "
+					"while CDP is disabled!\n", __func__, __LINE__);
+				rte_pqos_api_unlock();
+				return -1;
+			}
+
+			retval = rte_msr_write(lcore_id, reg, val);
+			if (retval != 0) {
+				rte_pqos_api_unlock();
+				return -1;
+			}
+		}
+	}
+
+	rte_pqos_api_unlock();
+
+	return 0;
+}
+
+int
+rte_pqos_l3ca_get(const unsigned phy_pkg_id, const unsigned max_cos_num,
+		unsigned *cos_num, struct rte_pqos_l3ca *ca)
+{
+	unsigned i = 0;
+	uint32_t reg = 0;
+
+	RTE_PQOS_ASSERT(max_cos_num > 0);
+	RTE_PQOS_ASSERT(cos_num != NULL);
+	RTE_PQOS_ASSERT(ca != NULL);
+	RTE_PQOS_ASSERT(rte_pqos_cap != NULL);
+	RTE_PQOS_ASSERT(rte_pqos_cap->cap_l3ca != NULL);
+	RTE_PQOS_ASSERT(max_cos_num >= rte_pqos_cap->cap_l3ca->cos_num);
+
+	rte_pqos_api_lock();
+
+	if (rte_pqos_cap == NULL || rte_pqos_cap->cap_l3ca == NULL ||
+			max_cos_num == 0 || max_cos_num < rte_pqos_cap->cap_l3ca->cos_num ||
+			cos_num == NULL || ca == NULL) {
+		rte_pqos_api_unlock();
+		RTE_LOG(ERR, PQOS, "%s:%u: Invalid params or PQoS not initialized!\n",
+			__func__, __LINE__);
+		return -1;
+	}
+
+	const unsigned ca_cos_num = rte_pqos_cap->cap_l3ca->cos_num;
+	const int cdp_enabled = rte_pqos_cap->cap_l3ca->cdp_on;
+
+	if (rte_phy_pkg_is_detected(phy_pkg_id) != 1) {
+		rte_pqos_api_unlock();
+		RTE_LOG(ERR, PQOS, "%s:%u: Invalid physical package id: %u!\n",
+			__func__, __LINE__, phy_pkg_id);
+		return -1;
+	}
+
+	const unsigned lcore_id = rte_phy_pkg_id_to_lcore(phy_pkg_id);
+	if (rte_lcore_is_detected(lcore_id) != 1) {
+		rte_pqos_api_unlock();
+		RTE_LOG(ERR, PQOS, "%s:%u: Invalid lcore id: %u!\n",
+			__func__, __LINE__, lcore_id);
+		return -1;
+	}
+
+	for (i = 0, reg = PQOS_MSR_L3CA_MASK_START; i < ca_cos_num; i++) {
+		uint64_t val = 0;
+		int retval = -1;
+
+		retval = rte_msr_read(lcore_id, reg++, &val);
+		if (retval != 0) {
+			rte_pqos_api_unlock();
+			return -1;
+		}
+
+		if (cdp_enabled == 0)
+			ca[i].mask = val;
+		else {
+			ca[i].data_mask = val;
+
+			retval = rte_msr_read(lcore_id, reg++, &val);
+			if (retval != 0) {
+				rte_pqos_api_unlock();
+				return -1;
+			}
+			ca[i].code_mask = val;
+		}
+
+		ca[i].cdp = cdp_enabled;
+		ca[i].cos_id = i;
+	}
+
+	*cos_num = ca_cos_num;
+
+	rte_pqos_api_unlock();
+	return 0;
+}
+
+int
+rte_pqos_l3ca_single_get(const unsigned phy_pkg_id, const unsigned cos_id,
+		struct rte_pqos_l3ca *ca)
+{
+	unsigned cos_num = 0;
+	struct rte_pqos_l3ca *temp_ca = NULL;
+	int ret = -1;
+
+	RTE_PQOS_ASSERT(ca != NULL);
+	RTE_PQOS_ASSERT(rte_pqos_cap != NULL);
+	RTE_PQOS_ASSERT(rte_pqos_cap->cap_l3ca != NULL);
+
+	if (rte_pqos_cap == NULL || rte_pqos_cap->cap_l3ca == NULL ||
+			cos_id >= rte_pqos_cap->cap_l3ca->cos_num || ca == NULL	||
+			rte_pqos_cap->cap_l3ca->cos_num == 0) {
+		RTE_LOG(ERR, PQOS, "%s:%u: Invalid params or PQoS not initialized!\n",
+			__func__, __LINE__);
+		return -1;
+	}
+
+	const unsigned max_cos_num = rte_pqos_cap->cap_l3ca->cos_num;
+	temp_ca = (struct rte_pqos_l3ca *) malloc(sizeof(*temp_ca) * max_cos_num);
+	memset(temp_ca, 0, sizeof(*temp_ca) * max_cos_num);
+
+	ret = rte_pqos_l3ca_get(phy_pkg_id, max_cos_num, &cos_num, temp_ca);
+	if (ret == 0 && cos_num > cos_id)
+		*ca = temp_ca[cos_id];
+	else
+		ret = -1;
+
+	if (temp_ca != NULL)
+		free(temp_ca);
+
+	return ret;
+}
+
+int
+rte_pqos_l3ca_assoc_set(const unsigned lcore_id, const unsigned cos_id)
+{
+	uint64_t val = 0;
+	int retval = -1;
+
+	rte_pqos_api_lock();
+
+	RTE_PQOS_ASSERT(rte_pqos_cap != NULL);
+	RTE_PQOS_ASSERT(rte_pqos_cap->cap_l3ca != NULL);
+	RTE_PQOS_ASSERT(rte_lcore_is_detected(lcore_id) == 1);
+	RTE_PQOS_ASSERT(cos_id < rte_pqos_cap->cap_l3ca->cos_num);
+
+	if (rte_pqos_cap == NULL || rte_pqos_cap->cap_l3ca == NULL ||
+			rte_lcore_is_detected(lcore_id) != 1 ||
+			cos_id >= rte_pqos_cap->cap_l3ca->cos_num) {
+		rte_pqos_api_unlock();
+		RTE_LOG(ERR, PQOS, "%s:%u: Invalid params or PQoS not initialized!\n",
+			__func__, __LINE__);
+		return -1; /**< perhaps no L3CA capability */
+	}
+
+	retval = rte_msr_read(lcore_id, PQOS_MSR_ASSOC, &val);
+	if (retval != 0) {
+		rte_pqos_api_unlock();
+		return -1;
+	}
+
+	val &= (~PQOS_MSR_ASSOC_QECOS_MASK);
+	val |= (((uint64_t) cos_id) << PQOS_MSR_ASSOC_QECOS_SHIFT);
+
+	retval = rte_msr_write(lcore_id, PQOS_MSR_ASSOC, val);
+	if (retval != 0) {
+		rte_pqos_api_unlock();
+		return -1;
+	}
+
+	rte_pqos_api_unlock();
+	return 0;
+}
+
+int
+rte_pqos_l3ca_assoc_get(const unsigned lcore_id, unsigned *cos_id)
+{
+	uint64_t val = 0;
+	int retval = -1;
+
+	rte_pqos_api_lock();
+
+	RTE_PQOS_ASSERT(rte_pqos_cap != NULL);
+	RTE_PQOS_ASSERT(rte_pqos_cap->cap_l3ca != NULL);
+	RTE_PQOS_ASSERT(rte_lcore_is_detected(lcore_id) == 1);
+
+	if (rte_pqos_cap == NULL || rte_pqos_cap->cap_l3ca == NULL ||
+			rte_lcore_is_detected(lcore_id) != 1 || cos_id == NULL ||
+			1 > rte_pqos_cap->cap_l3ca->cos_num) {
+		rte_pqos_api_unlock();
+		RTE_LOG(ERR, PQOS, "%s:%u: Invalid params or PQoS not initialized!\n",
+			__func__, __LINE__);
+		return -1;
+	}
+
+	retval = rte_msr_read(lcore_id, PQOS_MSR_ASSOC, &val);
+	if (retval != 0) {
+		rte_pqos_api_unlock();
+		return -1;
+	}
+
+	val >>= PQOS_MSR_ASSOC_QECOS_SHIFT;
+	*cos_id = (unsigned) val;
+
+	rte_pqos_api_unlock();
+	return 0;
+}
+
+int
+rte_pqos_l3ca_reset(const struct rte_pqos_cap *cap,
+		const enum rte_pqos_cdp_config cdp_cfg)
+{
+	unsigned phy_pkg_id = RTE_MAX_PHY_PKGS;
+	unsigned lcore_id = RTE_MAX_LCORE;
+	unsigned i = 0;
+	struct rte_pqos_l3ca cos = {0};
+	int ret = -1;
+
+	RTE_PQOS_ASSERT(cap != NULL);
+	RTE_PQOS_ASSERT(cap->cap_l3ca != NULL);
+	RTE_PQOS_ASSERT(cap->cap_l3ca->cos_num > 0);
+
+	if (cap == NULL || cap->cap_l3ca == NULL || 0 == cap->cap_l3ca->cos_num ||
+			cdp_cfg >= RTE_PQOS_REQUIRE_CDP_MAX) {
+		RTE_LOG(ERR, PQOS, "%s:%u: Invalid params or PQoS not initialized!\n",
+			__func__, __LINE__);
+		return -1; /**< no L3CA capability */
+	}
+
+	RTE_LOG(INFO, PQOS, "Resetting L3CA, cdp_cfg(%u)...\n", cdp_cfg);
+
+	/**
+	 * Associate all cores with COS0 first
+	 */
+	RTE_LCORE_FOREACH_DETECTED(lcore_id) {
+		ret = rte_pqos_l3ca_assoc_set(lcore_id, 0);
+		if (ret != 0) {
+			RTE_LOG(ERR, PQOS, "%s:%u: Failed to reset COS association!\n",
+				__func__, __LINE__);
+			return ret;
+		}
+	}
+
+	/**
+	 * And then change COS definition on all sockets
+	 * so that each COS allows for access to all cache ways
+	 */
+	cos.mask = (1ULL << cap->cap_l3ca->cbm_len) - 1ULL;
+	cos.cdp = 0;
+
+	RTE_PHY_PKG_FOREACH(phy_pkg_id) {
+		for (i = 0; i < cap->cap_l3ca->cos_num; i++) {
+			cos.cos_id = i;
+			ret = rte_pqos_l3ca_set(phy_pkg_id, 1, &cos);
+			if (ret != 0) {
+				RTE_LOG(ERR, PQOS, "%s:%u: Failed to reset COS configuration!\n",
+					__func__, __LINE__);
+				return ret;
+			}
+		}
+	}
+
+	rte_pqos_api_lock();
+	switch (cdp_cfg) {
+	case RTE_PQOS_REQUIRE_CDP_ON:
+		if (cap->cap_l3ca->cdp_supported == 0) {
+			RTE_LOG(ERR, PQOS, "%s:%u: CAT/CDP requested but not supported by "
+				"the platform!\n", __func__, __LINE__);
+			rte_pqos_api_unlock();
+			return -1;
+		} else if (cap->cap_l3ca->cdp_on == 0) {
+			/**
+			 * Turn on CDP
+			 */
+			RTE_LOG(INFO, PQOS, "Turning CDP ON ...\n");
+			if (pqos_cdp_enable(1) != PQOS_RETVAL_OK) {
+				RTE_LOG(ERR, PQOS, "%s:%u: CDP enable error!\n",
+					__func__, __LINE__);
+				rte_pqos_api_unlock();
+				return -1;
+			}
+			cap->cap_l3ca->cdp_on = 1;
+			cap->cap_l3ca->cos_num /= 2;
+		}
+		break;
+	case RTE_PQOS_REQUIRE_CDP_OFF:
+		if (cap->cap_l3ca->cdp_supported  == 1 && cap->cap_l3ca->cdp_on == 1) {
+			/**
+			 * Turn off CDP
+			 */
+			RTE_LOG(INFO, PQOS, "Turning CDP OFF ...\n");
+			if (pqos_cdp_enable(0) != PQOS_RETVAL_OK) {
+				RTE_LOG(ERR, PQOS, "%s:%u: CDP disable error!\n",
+					__func__, __LINE__);
+				rte_pqos_api_unlock();
+				return -1;
+			}
+			cap->cap_l3ca->cdp_on = 0;
+			cap->cap_l3ca->cos_num *= 2;
+		}
+		break;
+	case RTE_PQOS_REQUIRE_CDP_ANY:
+		break;
+	default:
+		RTE_LOG(ERR, PQOS, "%s:%u: Unrecognized CDP configuration %d!\n",
+			__func__, __LINE__, cdp_cfg);
+		rte_pqos_api_unlock();
+		return -1;
+	}
+
+	if (cdp_cfg == RTE_PQOS_REQUIRE_CDP_ON
+			|| cdp_cfg == RTE_PQOS_REQUIRE_CDP_OFF) {
+		RTE_LOG(INFO, PQOS, "After reset ...\n");
+		print_rte_pqos_cap_l3ca(cap->cap_l3ca);
+	}
+
+	rte_pqos_api_unlock();
+
+	return 0;
+}
+
+static void
+print_rte_pqos_l3ca(const unsigned phy_pkg_id, const struct rte_pqos_l3ca *l3ca)
+{
+	if (l3ca == NULL) {
+		RTE_LOG(ERR, PQOS, "%s: NULL pointer!\n", __func__);
+		return;
+	}
+
+	if (l3ca->cdp == 1) {
+		RTE_LOG(INFO, PQOS, "phy_pkg: %u, cos: %u, code_mask : %#"PRIx64""
+			", data_mask : %#"PRIx64", cdp: %u\n",
+			phy_pkg_id, l3ca->cos_id, l3ca->code_mask, l3ca->data_mask, l3ca->cdp);
+	} else {
+		RTE_LOG(INFO, PQOS, "phy_pkg: %u, cos: %u, mask: %#"PRIx64", cdp: %u\n",
+			phy_pkg_id, l3ca->cos_id, l3ca->mask, l3ca->cdp);
+	}
+}
+
+void rte_pqos_l3ca_print_cfg(void)
+{
+	if (rte_pqos_cap == NULL || rte_pqos_cap->cap_l3ca == NULL)
+		return;
+
+	unsigned cos_num = 0;
+	unsigned phy_pkg_id = RTE_MAX_PHY_PKGS;
+	unsigned lcore_id = RTE_MAX_LCORE;
+	unsigned cos_id = 0;
+	unsigned i = 0;
+	struct rte_pqos_l3ca *l3ca_ptr = NULL;
+	int ret = -1;
+
+	const unsigned max_cos_num = rte_pqos_cap->cap_l3ca->cos_num;
+	l3ca_ptr = (struct rte_pqos_l3ca *) malloc(sizeof(*l3ca_ptr) * max_cos_num);
+	if (l3ca_ptr == NULL)
+		goto exit;
+
+	memset(l3ca_ptr, 0, sizeof(*l3ca_ptr) * max_cos_num);
+
+	RTE_PHY_PKG_FOREACH(phy_pkg_id) {
+		ret = rte_pqos_l3ca_get(phy_pkg_id, max_cos_num, &cos_num, l3ca_ptr);
+		if (ret != 0) {
+			RTE_LOG(ERR, PQOS, "Failed to get COS on phy_pkg %u. rte_pqos_l3ca_get\n", phy_pkg_id);
+			goto exit;
+		}
+
+		for (i = 0; i < cos_num; i++)
+			print_rte_pqos_l3ca(phy_pkg_id, &l3ca_ptr[i]);
+
+		memset(l3ca_ptr, 0, sizeof(*l3ca_ptr) * max_cos_num);
+	}
+
+	RTE_PHY_PKG_FOREACH(phy_pkg_id) {
+		RTE_LCORE_FOREACH_DETECTED(lcore_id) {
+			if (rte_lcore_to_phy_pkg_id(lcore_id) == (int)phy_pkg_id) {
+				ret = rte_pqos_l3ca_assoc_get(lcore_id, &cos_id);
+				if (ret != 0) {
+					RTE_LOG(ERR, PQOS, "Failed to read COS associated to lcore %u"
+						" on phy_pkg %u. rte_pqos_l3ca_assoc_get\n"
+						, lcore_id, phy_pkg_id);
+					goto exit;
+				}
+
+				RTE_LOG(INFO, PQOS, "phy_pkg: %u, lcore: %u, cos: %u\n", phy_pkg_id, lcore_id, cos_id);
+			}
+		}
+	}
+
+exit:
+	if (l3ca_ptr != NULL)
+		free(l3ca_ptr);
+}
diff --git a/lib/librte_pqos/capabilities.c b/lib/librte_pqos/capabilities.c
new file mode 100644
index 0000000..2fa8d5c
--- /dev/null
+++ b/lib/librte_pqos/capabilities.c
@@ -0,0 +1,598 @@
+/*
+ * BSD LICENSE
+ *
+ * Copyright(c) 2016 Intel Corporation. All rights reserved.
+ * 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 Intel Corporation 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
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (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.O
+ *
+ */
+
+/**
+ * Implementation of PQoS capabilities detection, init and exit functions.
+ */
+
+#include <pthread.h>
+#include <string.h>
+
+#include <rte_cpuflags.h>
+#include <rte_lcore.h>
+#include <rte_log.h>
+
+#include "rte_pqos.h"
+#include "rte_pqos_common.h"
+
+static const char * const pqos_supported_brands[] = { "E5-2658 v3",
+	"E5-2648L v3", "E5-2628L v3", "E5-2618L v3", "E5-2608L v3",
+	"E5-2658A v3", "E3-1258L v4", "E3-1278L v4" };
+
+#define PQOS_CPUID_LEAF_EXTD_FUNC_SUPP 0x80000000UL
+#define PQOS_CPUID_LEAF_BRAND_START 0x80000002UL
+#define PQOS_CPUID_LEAF_BRAND_END 0x80000004UL
+#define PQOS_CPUID_LEAF_BRAND_NUM (PQOS_CPUID_LEAF_BRAND_END - PQOS_CPUID_LEAF_BRAND_START + 1)
+#define PQOS_MAX_BRAND_STRING_LEN (PQOS_CPUID_LEAF_BRAND_NUM * sizeof(cpuid_registers_t))
+
+/**
+ * This pointer is allocated and initialized in this module.
+ * Then other sub-modules use it in order to retrieve
+ * capability information.
+ */
+struct rte_pqos_cap *rte_pqos_cap;
+
+/**
+ * Detects LLC size and number of ways
+ *
+ * Retrieves information about L3 cache
+ * and calculates its size. Uses CPUID.0x04.0x03
+ *
+ * @param p_num_ways
+ *  place to store number of detected cache ways
+ *
+ * @param p_size_in_bytes
+ *  place to store size of LLC in bytes
+ *
+ * @return
+ *  - PQOS_RETVAL_OK success
+ *  - PQOS_RETVAL_PARAM bad parameters
+ */
+static int
+get_l3_cache_info(unsigned *p_num_ways, unsigned *p_size_in_bytes)
+{
+	cpuid_registers_t regs = {0};
+
+	RTE_PQOS_ASSERT(p_num_ways != NULL || p_size_in_bytes != NULL);
+	if (p_num_ways == NULL && p_size_in_bytes == NULL)
+		return PQOS_RETVAL_PARAM;
+
+	rte_cpu_get_features(0x4, 0x3, regs);
+
+	const unsigned num_ways = (regs[RTE_REG_EBX] >> 22) + 1;
+	const unsigned line_size = (regs[RTE_REG_EBX] & 0xfff) + 1;
+	const unsigned num_partitions = ((regs[RTE_REG_EBX] >> 12) & 0x3ff) + 1;
+	const unsigned num_sets = regs[RTE_REG_ECX] + 1;
+	const unsigned size_in_bytes = num_ways * num_partitions * line_size * num_sets;
+
+	if (p_num_ways != NULL)
+		*p_num_ways = num_ways;
+
+	if (p_size_in_bytes != NULL)
+		*p_size_in_bytes = size_in_bytes;
+
+	return PQOS_RETVAL_OK;
+}
+
+/**
+ * Checks CDP enable status across all CPU sockets
+ *
+ * It also validates if CDP enabling is consistent across
+ * CPU sockets.
+ * At the moment, such scenario is considered as error
+ * that requires system reboot.
+ *
+ * @param enabled
+ *  place to store CDP enabling status
+ *
+ * @return
+ *  - PQOS_RETVAL_OK success
+ *  - PQOS_RETVAL_ERROR failure
+ *  - PQOS_RETVAL_PARAM bad parameters
+ */
+static int
+cdp_is_enabled(int *enabled)
+{
+	uint64_t reg = 0;
+	unsigned phy_pkg_id = 0;
+	unsigned enabled_num = 0;
+	unsigned disabled_num = 0;
+
+	RTE_PQOS_ASSERT(enabled != NULL);
+	if (enabled == NULL)
+		return PQOS_RETVAL_PARAM;
+
+	*enabled = 0;
+
+	RTE_PHY_PKG_FOREACH(phy_pkg_id) {
+		int retval = -1;
+		const unsigned lcore_id = rte_phy_pkg_id_to_lcore(phy_pkg_id);
+		if (lcore_id == RTE_MAX_LCORE) {
+			RTE_LOG(ERR, PQOS, "%s:%u: Invalid physical package id: %u!\n",
+				__func__, __LINE__, phy_pkg_id);
+			return PQOS_RETVAL_ERROR;
+		}
+
+		retval = rte_msr_read(lcore_id, PQOS_MSR_L3_QOS_CFG, &reg);
+		if (retval != 0)
+			return PQOS_RETVAL_ERROR;
+
+		if (reg & PQOS_MSR_L3_QOS_CFG_CDP_EN)
+			enabled_num++;
+		else
+			disabled_num++;
+	}
+
+	if (disabled_num > 0 && enabled_num > 0) {
+		RTE_LOG(ERR, PQOS, "%s:%d: Inconsistent CDP settings across sockets."
+			"Please reboot your system!\n", __func__, __LINE__);
+		return PQOS_RETVAL_ERROR;
+	}
+
+	if (enabled_num > 0)
+		*enabled = 1;
+
+	RTE_LOG(INFO, PQOS, "CDP is %s\n", (*enabled) ? "enabled" : "disabled");
+
+	return PQOS_RETVAL_OK;
+}
+
+/**
+ * Detects presence of CAT based on brand string.
+ *
+ * If CPUID.0x7.0 doesn't report CAT feature
+ * platform may still support it:
+ * - we need to check brand string vs known ones
+ * - use CPUID.0x4.0x3 to get number of cache ways
+ *
+ * @param cap
+ *  CAT structure to be initialized
+ *
+ * @param cdp_cfg
+ *  CAT CDP configuration
+ *
+ * @return
+ *  - PQOS_RETVAL_OK success
+ *  - PQOS_RETVAL_NOT_SUPPORTED technology not supported
+ *  - PQOS_RETVAL_ERROR failure
+ *  - PQOS_RETVAL_PARAM bad parameters
+ */
+static int
+discover_alloc_llc_brandstr(struct rte_pqos_cap_l3ca *cap)
+{
+	cpuid_registers_t regs = {0};
+	int ret = PQOS_RETVAL_OK;
+	int match_found = 0;
+	char brand_str[PQOS_MAX_BRAND_STRING_LEN + 1] = {0};
+	uint32_t *brand_u32 = (uint32_t *) brand_str;
+	unsigned i = 0;
+	unsigned llc_size_in_bytes = 0;
+
+	RTE_PQOS_ASSERT(cap != NULL);
+	if (cap == NULL)
+		return PQOS_RETVAL_PARAM;
+
+	rte_cpu_get_features(PQOS_CPUID_LEAF_EXTD_FUNC_SUPP, 0, regs);
+
+	if (regs[RTE_REG_EAX] < PQOS_CPUID_LEAF_BRAND_END) {
+		RTE_LOG(ERR, PQOS, "%s:%u: Brand string CPUID extended functions "
+			"not supported\n", __func__, __LINE__);
+		return PQOS_RETVAL_ERROR;
+	}
+
+	for (i = 0; i < PQOS_CPUID_LEAF_BRAND_NUM; i++) {
+		rte_cpu_get_features((unsigned) PQOS_CPUID_LEAF_BRAND_START + i, 0, regs);
+		*brand_u32++ = regs[RTE_REG_EAX];
+		*brand_u32++ = regs[RTE_REG_EBX];
+		*brand_u32++ = regs[RTE_REG_ECX];
+		*brand_u32++ = regs[RTE_REG_EDX];
+	}
+
+	RTE_LOG(INFO, PQOS, "CPU brand string '%s'\n", brand_str);
+
+	/**
+	 * match brand against supported ones
+	 */
+	for (i = 0; i < RTE_DIM(pqos_supported_brands); i++)
+		if (strstr(brand_str, pqos_supported_brands[i]) != NULL) {
+			RTE_LOG(INFO, PQOS, "Cache allocation detected for model name '%s'\n",
+				brand_str);
+			match_found = 1;
+			break;
+		}
+
+	if (!match_found) {
+		RTE_LOG(WARNING, PQOS, "Cache allocation not supported on model name '%s'!\n",
+			brand_str);
+		return PQOS_RETVAL_NOT_SUPPORTED;
+	}
+
+	/**
+	 * Figure out number of ways and CBM (1:1)
+	 * using CPUID.0x4.0x3 (get_l3_cache_info)
+	 */
+	cap->cos_num = 4; /* always 4 for those CPUs */
+
+	/**
+	 * Detect number of LLC ways and LLC size
+	 * Calculate byte size of cache represented by single CBM bit
+	 */
+
+	/* CBM in 1:1 relation with ways */
+	ret = get_l3_cache_info(&cap->cbm_len, &llc_size_in_bytes);
+
+	if (ret == PQOS_RETVAL_OK) {
+		RTE_LOG(INFO, PQOS, "LLC cache size %u bytes, %u ways\n",
+			llc_size_in_bytes, cap->cbm_len);
+
+		if (cap->cbm_len == 0) {
+			RTE_LOG(ERR, PQOS, "%s:%u: Invalid number of ways\n",
+				__func__, __LINE__);
+			return PQOS_RETVAL_ERROR;
+		}
+
+		cap->cbm_bit_cache_size = llc_size_in_bytes / cap->cbm_len;
+
+		RTE_LOG(INFO, PQOS, "LLC cache size represented by single CBM bit %u bytes\n",
+			cap->cbm_bit_cache_size);
+	} else
+		RTE_LOG(ERR, PQOS, "%s:%u: Failed to get LLC cache info\n",
+			__func__, __LINE__);
+
+	return ret;
+}
+
+/**
+ * Detects presence of CAT based on CPUID
+ *
+ * @param cap
+ *  CAT structure to be initialized
+ *
+ * @param
+ *  cdp_cfg CAT CDP configuration
+ *
+ * @return
+ *  - PQOS_RETVAL_OK success
+ *  - PQOS_RETVAL_ERROR failure
+ *  - PQOS_RETVAL_PARAM bad parameters
+ *  - PQOS_RETVAL_NOT_SUPPORTED technology not supported
+ */
+static int
+discover_alloc_llc_cpuid(struct rte_pqos_cap_l3ca *cap)
+{
+	cpuid_registers_t regs = {0};
+	uint32_t res_id = 0;
+	int detected = 0;
+	unsigned llc_size_in_bytes = 0;
+	int ret = PQOS_RETVAL_OK;
+
+	RTE_PQOS_ASSERT(cap != NULL);
+	if (cap == NULL)
+		return PQOS_RETVAL_PARAM;
+
+	/**
+	 * We can go to CPUID.0x10.0 to explore
+	 * allocation capabilities
+	 */
+	rte_cpu_get_features(0x10, 0x0, regs);
+
+	res_id = regs[RTE_REG_EBX];
+
+	if (res_id & (1 << PQOS_RES_ID_L3_ALLOCATION)) {
+		/**
+		 * L3 CAT detected
+		 * - get more info about it
+		 */
+		rte_cpu_get_features(0x10, PQOS_RES_ID_L3_ALLOCATION, regs);
+
+		cap->cos_num = regs[RTE_REG_EDX] + 1;
+		cap->cbm_len = regs[RTE_REG_EAX] + 1;
+		cap->cdp_supported = (regs[RTE_REG_ECX] >> PQOS_CPUID_CAT_CDP_BIT) & 1;
+		cap->cdp_on = 0;
+		cap->cbm_contention_mask = (uint64_t) regs[RTE_REG_EBX];
+
+		if (cap->cdp_supported) {
+			/**
+			 * CDP is supported but is it on?
+			 */
+			int cdp_on = 0;
+
+			ret = cdp_is_enabled(&cdp_on);
+			if (ret != PQOS_RETVAL_OK) {
+				RTE_LOG(ERR, PQOS, "%s:%u: CDP detection error!\n",
+					__func__, __LINE__);
+				return ret;
+			}
+
+			if (cdp_on) {
+				/**
+				 * Divide number of classes by 2.
+				 * This is because CDP needs 2 bit-masks per one class.
+				 */
+				cap->cos_num = cap->cos_num / 2;
+			}
+
+			cap->cdp_on = cdp_on;
+		}
+
+		/**
+		 * Detect number of LLC ways and LLC size
+		 * Calculate byte size of cache represented by single CBM bit
+		 */
+		ret = get_l3_cache_info(NULL, &llc_size_in_bytes);
+
+		if (ret == PQOS_RETVAL_OK) {
+			cap->cbm_bit_cache_size = llc_size_in_bytes / cap->cbm_len;
+
+			RTE_LOG(INFO, PQOS, "LLC cache size %u bytes\n",
+				llc_size_in_bytes);
+			RTE_LOG(INFO, PQOS, "LLC cache size per CBM bit %u bytes\n",
+				cap->cbm_bit_cache_size);
+
+			detected = 1;
+		} else
+			RTE_LOG(ERR, PQOS, "%s:%u: Failed to get LLC cache info\n",
+				__func__, __LINE__);
+
+		res_id &= ~(1 << PQOS_RES_ID_L3_ALLOCATION);
+	}
+
+	if (res_id != 0) {
+		RTE_LOG(INFO, PQOS,
+			"Unsupported resource ID's detected: CPUID(0x10,0).ebx = 0x%x\n",
+			res_id);
+	}
+
+	if (!detected) {
+		RTE_LOG(INFO, PQOS, "No resource allocation capabilities detected.\n");
+		ret = PQOS_RETVAL_NOT_SUPPORTED;
+	}
+
+	return ret;
+}
+
+/**
+ * Discovers CAT
+ *
+ * First it tries to detects CAT through CPUID.0x7.0
+ * if this fails then falls into brand string check.
+ *
+ * Function allocates memory for CAT capabilities
+ * and returns it to the caller through \a r_cap.
+ *
+ * @param r_cap
+ *  place to store CAT capabilities structure
+ *
+ * @param cdp_cfg
+ *  CDP config passed from an application
+ *
+ * @return
+ *  - PQOS_RETVAL_OK success
+ *  - PQOS_RETVAL_ERROR failure
+ *  - PQOS_RETVAL_PARAM bad parameters
+ *  - PQOS_RETVAL_RESOURCE unable to allocate memory
+ *  - PQOS_RETVAL_NOT_SUPPORTED technology not supported
+ */
+static int
+discover_alloc_llc(struct rte_pqos_cap_l3ca **r_cap)
+{
+	cpuid_registers_t regs = {0};
+	struct rte_pqos_cap_l3ca *cap = NULL;
+	int ret = PQOS_RETVAL_ERROR;
+
+	RTE_PQOS_ASSERT(r_cap != NULL);
+	if (r_cap == NULL)
+		return PQOS_RETVAL_PARAM;
+
+	cap = (struct rte_pqos_cap_l3ca *) malloc(sizeof(*cap));
+	RTE_PQOS_ASSERT(cap != NULL);
+	if (cap == NULL)
+		return PQOS_RETVAL_RESOURCE;
+
+	memset(cap, 0, sizeof(*cap));
+
+	/**
+	 * Run CPUID.0x7.0 to check
+	 * for allocation capability (bit 15 of ebx)
+	 */
+	rte_cpu_get_features(0x7, 0x0, regs);
+
+	if ((regs[RTE_REG_EBX] & (1 << 15)) != 0) {
+		/**
+		 * Use CPUID method
+		 */
+		RTE_LOG(INFO, PQOS, "CPUID.0x7.0: CAT supported\n");
+		ret = discover_alloc_llc_cpuid(cap);
+	} else {
+		/**
+		 * Use brand string matching method
+		 */
+		ret = discover_alloc_llc_brandstr(cap);
+	}
+
+	if (ret == PQOS_RETVAL_OK) {
+		(*r_cap) = cap;
+		print_rte_pqos_cap_l3ca(cap);
+	} else {
+		RTE_LOG(INFO, PQOS, "CAT not supported.\n");
+		free(cap);
+	}
+
+	return ret;
+}
+
+/**
+ * Runs detection of platform allocation capabilities
+ *
+ * @param p_cap
+ *  place to store allocated capabilities structure
+ *
+ * @param cdp_cfg
+ *  CDP configuration passed on by an application
+ *
+ * @return
+ *  - PQOS_RETVAL_OK success
+ *  - PQOS_RETVAL_ERROR failure
+ *  - PQOS_RETVAL_PARAM bad parameters
+ *  - PQOS_RETVAL_RESOURCE unable to allocate memory
+ *  - PQOS_RETVAL_NOT_SUPPORTED technology not supported
+ */
+static int
+discover_capabilities(struct rte_pqos_cap **p_cap)
+{
+	struct rte_pqos_cap_l3ca *det_l3ca = NULL;
+	struct rte_pqos_cap *_cap = NULL;
+	int ret = PQOS_RETVAL_ERROR;
+
+	RTE_PQOS_ASSERT(p_cap != NULL);
+	if (p_cap == NULL)
+		return PQOS_RETVAL_PARAM;
+
+	/**
+	 * Cache allocation init
+	 */
+	ret = discover_alloc_llc(&det_l3ca);
+	switch (ret) {
+	case PQOS_RETVAL_OK:
+		RTE_LOG(INFO, PQOS, "L3CA capability detected\n");
+		break;
+	case PQOS_RETVAL_NOT_SUPPORTED:
+		RTE_LOG(INFO, PQOS, "L3CA capability not detected\n");
+		goto error_exit;
+	default:
+		RTE_LOG(ERR, PQOS, "%s:%u: Fatal error encounter in CAT discovery!\n",
+			__func__, __LINE__);
+		ret = PQOS_RETVAL_ERROR;
+		goto error_exit;
+	}
+
+	_cap = (struct rte_pqos_cap *) malloc(sizeof(*_cap));
+	RTE_PQOS_ASSERT(_cap != NULL);
+	if (_cap == NULL) {
+		RTE_LOG(ERR, PQOS, "%s:%u: Allocation error!\n", __func__, __LINE__);
+		ret = PQOS_RETVAL_RESOURCE;
+		goto error_exit;
+	}
+
+	memset(_cap, 0, sizeof(*_cap));
+
+	if (det_l3ca != NULL)
+		_cap->cap_l3ca = det_l3ca;
+
+	(*p_cap) = _cap;
+
+error_exit:
+	if (ret != PQOS_RETVAL_OK) {
+		if (det_l3ca != NULL)
+			free(det_l3ca);
+	}
+
+	return ret;
+}
+
+int
+rte_pqos_init(void)
+{
+	int retval = PQOS_RETVAL_ERROR;
+
+	if (rte_pqos_cap != NULL) {
+		RTE_LOG(ERR, PQOS, "%s:%u: rte_pqos already initialized!\n",
+			__func__, __LINE__);
+		return -1;
+	}
+
+	rte_pqos_api_lock();
+
+	retval = discover_capabilities(&rte_pqos_cap);
+	if (retval != PQOS_RETVAL_OK) {
+		RTE_LOG(ERR, PQOS, "%s:%u: discover_capabilities() error %d\n",
+			__func__, __LINE__,  retval);
+		goto init_error;
+	}
+
+	RTE_PQOS_ASSERT(rte_pqos_cap != NULL);
+	if (rte_pqos_cap == NULL) {
+		retval = PQOS_RETVAL_ERROR;
+		goto init_error;
+	}
+
+init_error:
+	if (retval != PQOS_RETVAL_OK) {
+		if (rte_pqos_cap != NULL)
+			free(rte_pqos_cap);
+		rte_pqos_cap = NULL;
+	}
+
+	rte_pqos_api_unlock();
+
+	return retval == PQOS_RETVAL_OK ? 0 : (PQOS_RETVAL_NOT_SUPPORTED ? -2 : -1);
+}
+
+int
+rte_pqos_exit(void)
+{
+	rte_pqos_api_lock();
+
+	if (rte_pqos_cap != NULL) {
+		if (rte_pqos_cap->cap_l3ca != NULL)
+			free((void *) rte_pqos_cap->cap_l3ca);
+
+		free((void *) rte_pqos_cap);
+
+		rte_pqos_cap = NULL;
+	}
+
+	rte_pqos_api_unlock();
+
+	return 0;
+}
+
+int
+rte_pqos_cap_get(const struct rte_pqos_cap **cap)
+{
+	RTE_PQOS_ASSERT(cap != NULL);
+	if (cap == NULL || rte_pqos_cap == NULL) {
+		RTE_LOG(ERR, PQOS, "%s:%u: Invalid params or PQoS not initialized!\n",
+			__func__, __LINE__);
+		return -1;
+	}
+
+	rte_pqos_api_lock();
+
+	*cap = rte_pqos_cap;
+
+	rte_pqos_api_unlock();
+
+	return 0;
+}
diff --git a/lib/librte_pqos/rte_pqos.h b/lib/librte_pqos/rte_pqos.h
new file mode 100644
index 0000000..9e0220b
--- /dev/null
+++ b/lib/librte_pqos/rte_pqos.h
@@ -0,0 +1,248 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *   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 Intel Corporation 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
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (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.
+ */
+
+#ifndef _RTE_PQOS_H
+#define _RTE_PQOS_H
+
+/**
+ * @file
+ * RTE PQOS Management
+ * Currently only support for L3CA (CAT) is implemented.
+ */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <rte_common.h>
+
+#ifdef RTE_LIBRTE_PQOS_DEBUG
+#include <rte_debug.h>
+#define RTE_PQOS_ASSERT(exp) do {					\
+	if (!(exp))							\
+		rte_panic("line%d\tassert \"" #exp "\" failed\n", __LINE__);\
+} while (0)
+#else /* !RTE_LIBRTE_PQOS */
+#define RTE_PQOS_ASSERT(exp) do { } while (0)
+#endif
+
+enum rte_pqos_cdp_config {
+	RTE_PQOS_REQUIRE_CDP_OFF = 0, /* app not compatible with CDP */
+	RTE_PQOS_REQUIRE_CDP_ON,      /* app requires CDP */
+	RTE_PQOS_REQUIRE_CDP_ANY,     /* app will work with any CDP setting */
+	RTE_PQOS_REQUIRE_CDP_MAX      /* "max" and "invalid" value */
+};
+
+/**
+ * Initializes PQoS module
+ *
+ * @return
+ *   - On success, returns 0.
+ *   - On failure, returns -1.
+ */
+int rte_pqos_init(void);
+
+/**
+ * Shuts down PQoS module
+ *
+ * @return
+ *   - On success, returns 0.
+ *   - On failure, returns -1.
+ *   - When CAT not supported, returns -2.
+ */
+int rte_pqos_exit(void);
+
+/* Query capabilities */
+
+/* L3 Cache Allocation (CA) capability structure */
+struct rte_pqos_cap_l3ca {
+	unsigned cos_num;             /* max number of classes of service (COS) */
+	unsigned cbm_len;             /* COS capacity bitmask (CBM) len */
+	unsigned cbm_bit_cache_size;  /* cache size represented by single CBM bit (in bytes) */
+	uint64_t cbm_contention_mask; /* CBM contention bit mask */
+
+	int cdp_supported; /* code data prioritization feature presence */
+	int cdp_on;        /* code data prioritization on or off */
+};
+
+/* Structure describing all Platform QoS capabilities */
+struct rte_pqos_cap {
+	struct rte_pqos_cap_l3ca *cap_l3ca; /* L3 Cache Allocation (CA) capability structure */
+};
+
+/* L3 cache allocation class of service data structure */
+struct rte_pqos_l3ca {
+	unsigned cos_id;   /* id of L3CA class of service */
+	int cdp;           /* data & code masks used if true */
+	union {
+		uint64_t mask; /* capacity bitmask (CBM) for L3 cache */
+		struct {
+			uint64_t data_mask;
+			uint64_t code_mask;
+		};
+	};
+};
+
+/**
+ * Retrieves PQoS capabilities data
+ *
+ * @param [out] cap
+ *  location to store PQoS (CA) capabilities information at
+ *
+ * @return
+ *   - On success, returns 0.
+ *   - On failure, returns -1.
+ */
+int rte_pqos_cap_get(const struct rte_pqos_cap **cap);
+
+/**
+ * Sets classes of service defined by \a ca on physical package/socket
+ *
+ * @param [in] phys_pkg_id
+ *  CPU physical package/socket id
+ *
+ * @param [in] cos_num
+ *  number of L3CA classes of service at \a ca
+ *
+ * @param [in] ca
+ *  table with definitions of class of service
+ *
+ * @return
+ *   - On success, returns 0.
+ *   - On failure, returns -1.
+ */
+int rte_pqos_l3ca_set(const unsigned phys_pkg_id, const unsigned cos_num,
+		const struct rte_pqos_l3ca *ca);
+
+/**
+ * Reads classes of service from physical package/socket
+ *
+ * @param [in] phys_pkg_id
+ *  CPU physical package/socket id
+ *
+ * @param [in] max_cos_num
+ *  maximum number of L3CA classes of service that can be accommodated at \a ca
+ *
+ * @param [out] cos_num
+ *  number of L3CA classes of service read into \a ca
+ *
+ * @param [out] ca
+ *  table with read classes of service
+ *
+ * @return
+ *   - On success, returns 0.
+ *   - On failure, returns -1.
+ */
+int rte_pqos_l3ca_get(const unsigned phys_pkg_id, const unsigned max_cos_num,
+		unsigned *cos_num,
+		struct rte_pqos_l3ca *ca);
+
+/**
+ * Reads single class of service from physical package/socket
+ *
+ * @param [in] phys_pkg_id
+ *  CPU physical package/socket id
+ *
+ * @param [in] cos_id
+ *  id of L3CA class of service to read
+ *
+ * @param [out] ca
+ *  read class of service
+ *
+ * @return
+ *   - On success, returns 0.
+ *   - On failure, returns -1.
+ */
+int rte_pqos_l3ca_single_get(const unsigned phys_pkg_id, const unsigned cos_id,
+		struct rte_pqos_l3ca *ca);
+
+/**
+ * Associates \a lcore with given L3CA class of service
+ *
+ * @param [in] lcore
+ *  CPU logical core id
+ *
+ * @param [in] cos_id
+ *  id of L3CA class of service
+ *
+ * @return
+ *   - On success, returns 0.
+ *   - On failure, returns -1.
+ */
+int rte_pqos_l3ca_assoc_set(const unsigned lcore, const unsigned cos_id);
+
+/**
+ * Reads association of \a lcore with L3CA class of service
+ *
+ * @param [in] lcore
+ *  CPU logical core id
+ *
+ * @param [out] cos_id
+ *  id of L3CA class of service
+ *
+ * @return
+ *   - On success, returns 0.
+ *   - On failure, returns -1.
+ */
+int rte_pqos_l3ca_assoc_get(const unsigned lcore, unsigned *cos_id);
+
+/**
+ * Resets configuration of cache allocation technology
+ * Reverts CAT state to the one after reset:
+ * - all cores associated with COS0
+ * - all COS are set to give access to all cache ways
+ *
+ * @param [in] cap
+ *  platform QoS capabilities structure returned by pqos_cap_get
+ *
+ * @param [in] cdp_cfg
+ *  CDP config
+ *
+ * @return
+ *   - On success, returns 0.
+ *   - On failure, returns -1.
+ */
+int rte_pqos_l3ca_reset(const struct rte_pqos_cap *cap,
+		const enum rte_pqos_cdp_config cdp_cfg);
+
+/**
+ * Prints out current L3CA (CAT) configuration
+ */
+void rte_pqos_l3ca_print_cfg(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_PQOS_H */
diff --git a/lib/librte_pqos/rte_pqos_common.c b/lib/librte_pqos/rte_pqos_common.c
new file mode 100644
index 0000000..30f4ded
--- /dev/null
+++ b/lib/librte_pqos/rte_pqos_common.c
@@ -0,0 +1,141 @@
+/*
+ * BSD LICENSE
+ *
+ * Copyright(c) 2016 Intel Corporation. All rights reserved.
+ * 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 Intel Corporation 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
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (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.O
+ *
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <unistd.h>
+
+#include <rte_log.h>
+
+#include "rte_pqos.h"
+#include "rte_pqos_common.h"
+
+#define CPU_MSR_PATH "/dev/cpu/%u/msr"
+
+pthread_mutex_t rte_pqos_apilock = PTHREAD_MUTEX_INITIALIZER;
+
+void
+rte_pqos_api_lock(void)
+{
+	int ret = 0;
+
+	ret = pthread_mutex_lock(&rte_pqos_apilock);
+	RTE_PQOS_ASSERT(ret == 0);
+	if (ret != 0)
+		RTE_LOG(ERR, PQOS, "%s: API lock failed!\n", __func__);
+}
+
+void
+rte_pqos_api_unlock(void)
+{
+	int ret = 0;
+
+	ret = pthread_mutex_unlock(&rte_pqos_apilock);
+	RTE_PQOS_ASSERT(ret == 0);
+	if (ret != 0)
+		RTE_LOG(ERR, PQOS, "%s: API unlock failed!\n", __func__);
+}
+
+/**
+ * Function to open CPU's MSR file
+ */
+static int
+msr_open_file(const unsigned cpuid, int flags)
+{
+	char fname[PATH_MAX] = {0};
+	int fd = -1;
+
+	snprintf(fname, sizeof(fname) - 1, CPU_MSR_PATH, cpuid);
+
+	fd = open(fname, flags);
+
+	if (fd < 0)
+		RTE_LOG(ERR, PQOS, "Error opening file '%s'! MSR driver not loaded? Try \'modprobe msr\'.\n", fname);
+
+	return fd;
+}
+
+int
+rte_msr_read(const unsigned cpuid, const uint32_t reg, uint64_t *value)
+{
+	int fd = -1;
+	int ret = -1;
+
+	if (value == NULL)
+		return -EINVAL;
+
+	fd = msr_open_file(cpuid, O_RDONLY);
+
+	if (fd >= 0) {
+		ssize_t read_ret = 0;
+
+		read_ret = pread(fd, value, sizeof(value[0]), (off_t)reg);
+
+		if (read_ret != sizeof(value[0])) {
+			RTE_LOG(ERR, PQOS, "RDMSR failed for reg[0x%x] on CPU lcore %u\n",
+				(unsigned)reg, cpuid);
+		} else
+			ret = 0;
+
+		close(fd);
+	}
+
+	return ret;
+}
+
+int
+rte_msr_write(const unsigned cpuid, const uint32_t reg, const uint64_t value)
+{
+	int fd = -1;
+	int ret = -1;
+
+	fd = msr_open_file(cpuid, O_WRONLY);
+
+	if (fd >= 0) {
+		ssize_t write_ret = 0;
+
+		write_ret = pwrite(fd, &value, sizeof(value), (off_t)reg);
+		if (write_ret != sizeof(value)) {
+			RTE_LOG(ERR, PQOS, "WRMSR failed for reg[0x%x] <- value[0x%llx] "
+					"on CPU lcore %u\n", (unsigned)reg,
+					(unsigned long long)value, cpuid);
+		} else
+			ret = 0;
+
+		close(fd);
+	}
+
+	return ret;
+}
diff --git a/lib/librte_pqos/rte_pqos_common.h b/lib/librte_pqos/rte_pqos_common.h
new file mode 100644
index 0000000..d49c290
--- /dev/null
+++ b/lib/librte_pqos/rte_pqos_common.h
@@ -0,0 +1,183 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *   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 Intel Corporation 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
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (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.
+ */
+
+#ifndef RTE_PQOS_COMMON_H_
+#define RTE_PQOS_COMMON_H_
+
+#include <pthread.h>
+
+#include <rte_log.h>
+
+/**
+ * Allocation & Monitoring association MSR register
+ *
+ * [63..<QE COS>..32][31..<RESERVED>..10][9..<RMID>..0]
+ */
+#define PQOS_MSR_ASSOC             0xC8F
+#define PQOS_MSR_ASSOC_QECOS_SHIFT 32
+#define PQOS_MSR_ASSOC_QECOS_MASK  0xffffffff00000000ULL
+
+/**
+ * Allocation class of service (COS) MSR registers
+ */
+#define PQOS_MSR_L3CA_MASK_START 0xC90
+#define PQOS_MSR_L3CA_MASK_END   0xD8F
+#define PQOS_MSR_L3CA_MASK_NUMOF \
+	(PQOS_MSR_L3CA_MASK_END - PQOS_MSR_L3CA_MASK_START + 1)
+
+/**
+ * Available types of allocation resource IDs.
+ * (matches CPUID enumeration)
+ */
+#define PQOS_RES_ID_L3_ALLOCATION    1              /**< L3 cache allocation */
+
+#define PQOS_CPUID_CAT_CDP_BIT       2              /**< CDP supported bit */
+
+#define PQOS_MSR_L3_QOS_CFG          0xC81          /**< CAT config register */
+#define PQOS_MSR_L3_QOS_CFG_CDP_EN   1ULL           /**< CDP enable bit */
+
+/*
+ * =======================================
+ * Return values
+ * =======================================
+ */
+#define PQOS_RETVAL_OK           0      /**< everything OK */
+#define PQOS_RETVAL_ERROR        1      /**< generic error */
+#define PQOS_RETVAL_PARAM        2      /**< parameter error */
+#define PQOS_RETVAL_RESOURCE     3      /**< resource error (mem allocation)*/
+#define PQOS_RETVAL_INIT         4      /**< initialization error */
+#define PQOS_RETVAL_NOT_SUPPORTED 5     /**< not supported */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * API thread safe access is secured through this mutex.
+ */
+extern pthread_mutex_t rte_pqos_apilock;
+
+/**
+ * Used to store system capability information.
+ */
+extern struct rte_pqos_cap *rte_pqos_cap;
+
+/**
+ * Functions for safe multi-threading
+ */
+
+/**
+ * Aquires lock for PQoS API use
+ *
+ * Only one thread at a time is allowed to use the API.
+ * Each PQoS API need to use api_lock and api_unlock functions.
+ */
+extern void rte_pqos_api_lock(void);
+
+/**
+ * Symmetric operation to \a _pqos_api_lock to release the lock
+ */
+extern void rte_pqos_api_unlock(void);
+
+/**
+ * API to read/write Intel Architecture Model Specific Registers (MSR).
+ */
+
+/**
+ * Function to read CPU's MSR
+ *
+ * @param [in] cpuid
+ *  CPU logical core id
+ *
+ * @param [in] reg
+ *  MSR reg to read
+ *
+ * @param [out] value
+ *  Read value of MSR reg
+ *
+ * @return
+ *  Operations status
+*/
+extern int rte_msr_read(const unsigned cpuid, const uint32_t reg,
+		uint64_t *value);
+
+/**
+ * Function to write CPU's MSR
+ *
+ * @param [in] cpuid
+ *  CPU logical core id
+ *
+ * @param [in] reg
+ *  MSR reg to write
+ *
+ * @param [in] value
+ *  Value to be written to MSR reg
+ *
+ * @return
+ *  Operations status
+*/
+extern int rte_msr_write(const unsigned cpuid, const uint32_t reg,
+		const uint64_t value);
+
+/**
+ * Helpers
+ */
+
+/**
+ * Function to print rte_pqos_cap_l3ca (system capabilities)
+ *
+ * @param [in] cap
+ *  system capabilities struct
+*/
+static inline void
+print_rte_pqos_cap_l3ca(const struct rte_pqos_cap_l3ca *cap)
+{
+	if (cap == NULL) {
+		RTE_LOG(ERR, PQOS, "%s: NULL pointer!\n", __func__);
+		return;
+	}
+
+	RTE_LOG(INFO, PQOS,
+		"CAT details: CDP support=%d, CDP on=%d, #COS=%u, CBM len=%u,"
+		"CBM contention bit-mask 0x%x\n",
+		cap->cdp_supported, cap->cdp_on,
+		cap->cos_num,
+		cap->cbm_len,
+		(unsigned int)cap->cbm_contention_mask);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* RTE_PQOS_COMMON_H_ */
diff --git a/lib/librte_pqos/rte_pqos_version.map b/lib/librte_pqos/rte_pqos_version.map
new file mode 100644
index 0000000..f529ee8
--- /dev/null
+++ b/lib/librte_pqos/rte_pqos_version.map
@@ -0,0 +1,16 @@
+DPDK_2.3 {
+	global:
+
+	rte_pqos_init;
+	rte_pqos_exit;
+	rte_pqos_cap_get;
+	rte_pqos_l3ca_set;
+	rte_pqos_l3ca_get;
+	rte_pqos_l3ca_single_get;
+	rte_pqos_l3ca_assoc_set;
+	rte_pqos_l3ca_assoc_get;
+	rte_pqos_l3ca_reset;
+	rte_pqos_l3ca_print_cfg;
+
+	local: *;
+};
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 8ecab41..b1d488c 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -88,6 +88,8 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_SCHED)          += -lrt
 
 _LDLIBS-$(CONFIG_RTE_LIBRTE_VHOST)          += -lrte_vhost
 
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PQOS)           += -lrte_pqos
+
 endif # ! CONFIG_RTE_BUILD_COMBINE_LIBS
 
 ifeq ($(CONFIG_RTE_LIBRTE_VHOST_NUMA),y)
-- 
1.9.3



More information about the dev mailing list