diff --git a/config/common_bsdapp b/config/common_bsdapp
index 9177db1..eca9299 100644
--- a/config/common_bsdapp
+++ b/config/common_bsdapp
@@ -282,6 +282,12 @@ CONFIG_RTE_LIBRTE_HASH=y
 CONFIG_RTE_LIBRTE_HASH_DEBUG=n
 
 #
+# Compile librte_headroom
+#
+CONFIG_RTE_LIBRTE_HEADROOM=y
+CONFIG_RTE_HEADROOM_MAX_JOBS=32
+
+#
 # Compile librte_lpm
 #
 CONFIG_RTE_LIBRTE_LPM=y
diff --git a/config/common_linuxapp b/config/common_linuxapp
index 2f9643b..54c9458 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -290,6 +290,12 @@ CONFIG_RTE_LIBRTE_HASH=y
 CONFIG_RTE_LIBRTE_HASH_DEBUG=n
 
 #
+# Compile librte_headroom
+#
+CONFIG_RTE_LIBRTE_HEADROOM=y
+CONFIG_RTE_HEADROOM_MAX_JOBS=32
+
+#
 # Compile librte_lpm
 #
 CONFIG_RTE_LIBRTE_LPM=y
diff --git a/lib/Makefile b/lib/Makefile
index 0ffc982..ab9e474 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -53,6 +53,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_VMXNET3_PMD) += librte_pmd_vmxnet3
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_XENVIRT) += librte_pmd_xenvirt
 DIRS-$(CONFIG_RTE_LIBRTE_VHOST) += librte_vhost
 DIRS-$(CONFIG_RTE_LIBRTE_HASH) += librte_hash
+DIRS-$(CONFIG_RTE_LIBRTE_HEADROOM) += librte_headroom
 DIRS-$(CONFIG_RTE_LIBRTE_LPM) += librte_lpm
 DIRS-$(CONFIG_RTE_LIBRTE_ACL) += librte_acl
 DIRS-$(CONFIG_RTE_LIBRTE_NET) += librte_net
diff --git a/lib/librte_headroom/Makefile b/lib/librte_headroom/Makefile
new file mode 100644
index 0000000..f0137e3
--- /dev/null
+++ b/lib/librte_headroom/Makefile
@@ -0,0 +1,50 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2010-2014 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_headroom.a
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR)
+
+# all source are stored in SRCS-y
+SRCS-$(CONFIG_RTE_LIBRTE_HEADROOM) := rte_headroom.c
+
+# install this header file
+SYMLINK-$(CONFIG_RTE_LIBRTE_HEADROOM)-include := rte_headroom.h
+
+# this lib needs eal
+DEPDIRS-$(CONFIG_RTE_LIBRTE_HEADROOM) += lib/librte_eal
+DEPDIRS-$(CONFIG_RTE_LIBRTE_HEADROOM) += lib/librte_mbuf
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_headroom/rte_headroom.c b/lib/librte_headroom/rte_headroom.c
new file mode 100644
index 0000000..5f19c83
--- /dev/null
+++ b/lib/librte_headroom/rte_headroom.c
@@ -0,0 +1,368 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 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 <string.h>
+#include <errno.h>
+
+#include <rte_errno.h>
+#include <rte_common.h>
+#include <rte_cycles.h>
+#include <rte_branch_prediction.h>
+#include <rte_debug.h>
+
+#include "rte_headroom.h"
+
+/* Those are steps used to adjust job period.
+ * Experiments show that for forwarding apps the up step must be less than down
+ * step to achieve optimal performance.
+ */
+#define JOB_UPDATE_STEP_UP    1
+#define JOB_UPDATE_STEP_DOWN  4
+
+/*
+ * Default update function that implements simple period adjustment.
+ */
+static void
+default_update_function(struct rte_headroom_job *job, int64_t result)
+{
+	int64_t err = job->job_target - result;
+
+	/* Job is happy. Nothing to do */
+	if (err == 0)
+		return;
+
+	if (err > 0) {
+		if (job->period + JOB_UPDATE_STEP_UP < job->max_period)
+			job->period += JOB_UPDATE_STEP_UP;
+	} else {
+		if (job->min_period + JOB_UPDATE_STEP_DOWN < job->period)
+			job->period -= JOB_UPDATE_STEP_DOWN;
+	}
+}
+
+static uint32_t
+select_next_job(struct rte_headroom *hdr)
+{
+	const uint64_t now = rte_get_timer_cycles();
+	const uint32_t count = hdr->job_count;
+	uint32_t idx = hdr->job_idx;
+
+	for (; idx < count; idx++) {
+		if (hdr->jobs[idx].next_exec_time <= now)
+			break;
+	}
+
+	hdr->job_idx = idx;
+	return idx;
+}
+
+static void
+default_loop_hook(__rte_unused struct rte_headroom *hdr)
+{
+	rte_pause();
+}
+
+static void
+default_idle_hook(__rte_unused struct rte_headroom *hdr)
+{
+	rte_pause();
+}
+
+int
+rte_headroom_init(struct rte_headroom *hdr)
+{
+	if (hdr == NULL)
+		return -EINVAL;
+
+	memset(hdr, 0, sizeof(*hdr));
+
+	/* Set some initial values */
+	hdr->idle_hook = &default_idle_hook;
+	hdr->loop_hook = &default_loop_hook;
+
+	hdr->user_data = NULL;
+
+	return 0;
+}
+
+void
+rte_headroom_deinit(struct rte_headroom *hdr)
+{
+	RTE_VERIFY(hdr != NULL);
+
+	hdr->job_count = 0;
+	hdr->job_idx = 0;
+}
+
+void
+rte_headroom_set_user_data(struct rte_headroom *hdr, void *user_data)
+{
+	hdr->user_data = user_data;
+}
+
+void
+rte_headroom_set_loop_hook(struct rte_headroom *hdr,
+		rte_headroom_idle_hook_t loop_end_hook)
+{
+	if (loop_end_hook == NULL)
+		loop_end_hook = default_loop_hook;
+
+	hdr->loop_hook = loop_end_hook;
+}
+
+void
+rte_headroom_set_idle_hook(struct rte_headroom *hdr,
+		rte_headroom_idle_hook_t idle_hook)
+{
+	if (idle_hook == NULL)
+		idle_hook = default_idle_hook;
+
+	hdr->idle_hook = idle_hook;
+}
+
+static void
+update_stats(struct rte_headroom_stats *stats, uint64_t idle, uint64_t runtime)
+{
+	stats->idle += idle;
+
+	if (idle < stats->idle_min)
+		stats->idle_min = idle;
+
+	if (idle > stats->idle_max)
+		stats->idle_max = idle;
+
+	stats->run_time += runtime;
+
+	if (runtime < stats->run_time_min)
+		stats->run_time_min = runtime;
+
+	if (runtime > stats->run_time_max)
+		stats->run_time_max = runtime;
+
+	stats->exec_cnt++;
+}
+
+int
+rte_headroom_next_job(struct rte_headroom *hdr)
+{
+	uint64_t start_time, run_time, idle_time = 0, now;
+	int64_t retval;
+	struct rte_headroom_job *job;
+
+	if (unlikely(hdr == NULL))
+		return -EINVAL;
+
+	if (unlikely(hdr->job_count == 0))
+		return -ENOENT;
+
+	/* Wait for any job to be ready. */
+	if (unlikely(select_next_job(hdr) == hdr->job_count)) {
+		/* All jobs done. Update statisctics and go next loop */
+		update_stats(&hdr->stats, hdr->loop_idle, hdr->loop_runtime);
+		hdr->loop_idle = 0;
+		hdr->loop_runtime = 0;
+		hdr->job_idx = 0;
+
+		/* Execute loop end hook. */
+		(*hdr->loop_hook)(hdr);
+
+		/* Get ready job or wait for first one to became ready */
+		 while (select_next_job(hdr) == hdr->job_count) {
+			 hdr->job_idx = 0;
+			(*hdr->idle_hook)(hdr);
+		}
+	}
+
+	/* Calculate idle time counter for this job. Idle time is a time from
+	 * execution finish to next job became ready. */
+	start_time = rte_get_timer_cycles();
+	idle_time = start_time - hdr->loop_end_time;
+
+	job = &hdr->jobs[hdr->job_idx];
+	retval = (*job->job_cb)(job);
+
+	(*job->update_period_cb)(job, retval);
+	job->next_exec_time += job->period;
+
+	now = rte_get_timer_cycles();
+	if (job->next_exec_time < now)
+		job->next_exec_time = now;
+
+	run_time = now - start_time;
+
+	/* Update job stats. */
+	update_stats(&job->stats, idle_time, run_time);
+
+	/* Update this loop stats. */
+	hdr->loop_idle += idle_time;
+	hdr->loop_runtime += run_time;
+
+	/* Mark time when this iteration ended */
+	hdr->loop_end_time = rte_get_timer_cycles();
+
+	/* Try next job. */
+	hdr->job_idx++;
+
+	/* Job finished */
+	return 0;
+}
+
+struct rte_headroom_job *
+rte_headroom_find_job(struct rte_headroom *hdr,
+		rte_headroom_job_callbak_t job_cb, void *job_data)
+{
+	size_t i;
+
+	if (unlikely(job_cb == NULL)) {
+		rte_errno = EINVAL;
+		return NULL;
+	}
+
+	/* Search the array. */
+	for (i = 0; i < hdr->job_count; i++) {
+		if (hdr->jobs[i].job_cb == job_cb &&
+			hdr->jobs[i].job_data == job_data)
+			return &hdr->jobs[i];
+	}
+
+	if (hdr->job_count == 0)
+		rte_errno = ENOENT;
+
+	return NULL;
+}
+
+struct rte_headroom_job *
+rte_headroom_find_job_by_name(struct rte_headroom *hdr,	const char *job_name)
+{
+	size_t i;
+
+	if (unlikely(job_name == NULL)) {
+		rte_errno = EINVAL;
+		return NULL;
+	}
+
+	/* Search the array. */
+	for (i = 0; i < hdr->job_count; i++) {
+		if (hdr->jobs[i].name[0] == '\0')
+			continue;
+
+		if (strcmp(hdr->jobs[i].name, job_name) == 0)
+			return &hdr->jobs[i];
+	}
+
+	if (hdr->job_count == 0)
+		rte_errno = ENOENT;
+
+	return NULL;
+}
+
+int
+rte_headroom_add_job(struct rte_headroom *hdr, const char *name,
+	rte_headroom_job_callbak_t job_cb, void *job_data, uint64_t min_period,
+	uint64_t max_period, uint64_t initial_period, int64_t target,
+	struct rte_headroom_job **job_handle)
+{
+	struct rte_headroom_job *job;
+
+	if (hdr == NULL || job_cb == NULL)
+		return -EINVAL;
+
+	/* Add job by finding free slot. */
+	if (hdr->job_count == RTE_DIM(hdr->jobs))
+		return -ENOBUFS;
+
+	job = &hdr->jobs[hdr->job_count];
+	hdr->job_count++;
+
+	memset(job, 0, sizeof(*job));
+	job->next_exec_time = rte_get_timer_cycles();
+	job->job_cb = job_cb;
+	job->job_data = job_data;
+
+	job->update_period_cb = default_update_function;
+
+	if (initial_period <= min_period)
+		job->period = min_period;
+	else if (initial_period >= max_period)
+		job->period = max_period;
+	else
+		job->period = initial_period;
+
+	job->min_period = min_period;
+	job->max_period = max_period;
+	job->job_target = target;
+
+	if (name != NULL)
+		strncpy(job->name, name, RTE_DIM(job->name));
+	else
+		memset(job->name, 0, sizeof(job->name));
+
+	job->headroom = hdr;
+
+	if (job_handle)
+		*job_handle = job;
+	return 0;
+}
+
+int
+rte_headroom_del_job(struct rte_headroom_job *job)
+{
+	struct rte_headroom *hdr;
+	size_t cnt, idx;
+
+	if (unlikely(job == NULL))
+		return -EINVAL;
+
+	hdr = job->headroom;
+	RTE_VERIFY(hdr->jobs < job &&
+			(size_t)(job - hdr->jobs) < RTE_DIM(hdr->jobs));
+
+	idx = job - hdr->jobs;
+	cnt = hdr->job_count - idx - 1;
+	hdr->job_count--;
+
+	if (cnt > 0)
+		memmove(&hdr->jobs[idx], &hdr->jobs[idx + 1], sizeof(*job) * cnt);
+
+	return hdr->job_count;
+}
+
+void
+rte_headroom_set_update_period_function(struct rte_headroom_job *job,
+		rte_headroom_update_fn_t update_pedriod_cb)
+{
+	if (update_pedriod_cb == NULL)
+		update_pedriod_cb = default_update_function;
+
+	job->update_period_cb = update_pedriod_cb;
+}
diff --git a/lib/librte_headroom/rte_headroom.h b/lib/librte_headroom/rte_headroom.h
new file mode 100644
index 0000000..20f99fd
--- /dev/null
+++ b/lib/librte_headroom/rte_headroom.h
@@ -0,0 +1,481 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 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 HEADROOM_H_
+#define HEADROOM_H_
+
+#include <stdint.h>
+
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if RTE_HEADROOM_MAX_JOBS < 1 || RTE_HEADROOM_MAX_JOBS >= 0xFFFF
+# error Define RTE_HEADROOM_MAX_JOBS to be greater 1 and less 65535
+#endif
+
+/* Forward declarations. */
+struct rte_headroom;
+struct rte_headroom_job;
+
+typedef void (*rte_headroom_idle_hook_t)(struct rte_headroom *hdr);
+typedef void (*rte_headroom_loop_hook_t)(struct rte_headroom *hdr);
+typedef int64_t (*rte_headroom_job_callbak_t)(struct rte_headroom_job *job);
+
+/**
+ * This function should calculate new period and set it using
+ * rte_headroom_set_period() function. Time spent in this function will be
+ * added to job's runtime.
+ *
+ * @param job
+ *  The job data structure handler.
+ * @param job_result
+ *  Result of calling job callback.
+ */
+typedef void (*rte_headroom_update_fn_t)(struct rte_headroom_job *job,
+		int64_t job_result);
+
+struct rte_headroom_stats {
+	uint64_t idle;
+	/**< Sum of idle time before this job became ready. */
+
+	uint64_t idle_min;
+	/**< Minimum idle time. */
+
+	uint64_t idle_max;
+	/**< Maximum idle time. */
+
+	uint64_t run_time;
+	/**< Total time that this job was executing. */
+
+	uint64_t run_time_min;
+	/**< Minimum execute time. */
+
+	uint64_t run_time_max;
+	/**< Minimum execute time. */
+
+	uint64_t exec_cnt;
+	/**< Task execute count. */
+};
+
+struct rte_headroom_job {
+	uint64_t next_exec_time;
+	/**< Next time when job should be executed. */
+
+	rte_headroom_job_callbak_t job_cb;
+	/**< Callback function for this job. */
+
+	void *job_data;
+	/**< Pointer to custom job's data. */
+
+	rte_headroom_update_fn_t update_period_cb;
+	/**< Period update callback. */
+
+	uint64_t period;
+	/**< Estitmated period of execution. */
+
+	uint64_t min_period;
+	/**< Minimum period. */
+
+	uint64_t max_period;
+	/**< Maximum period. */
+
+	struct rte_headroom_stats stats;
+
+	int64_t job_target;
+	/**< Desired value for this job. */
+
+#define RTE_HEADROOM_JOB_NAMESIZE 32
+	char name[RTE_HEADROOM_JOB_NAMESIZE];
+	/**< Name of this job */
+
+	struct rte_headroom *headroom;
+	/**< Hedroom object that this job belong to. */
+} __rte_cache_aligned;
+
+struct rte_headroom {
+	struct rte_headroom_job jobs[RTE_HEADROOM_MAX_JOBS];
+	/**< Array of job objects. */
+	uint32_t job_count;
+	/**< Job count. */
+	uint32_t job_idx;
+	/**< Index of job that is executing. */
+	struct rte_headroom_stats stats;
+
+	uint64_t loop_end_time;
+	/**< Time when last loop finished its execution. */
+
+	uint64_t loop_idle;
+	uint64_t loop_runtime;
+	/**< This loop idle time. */
+
+	rte_headroom_idle_hook_t idle_hook;
+	rte_headroom_loop_hook_t loop_hook;
+
+	void *user_data;
+	/**< User specified data for all user hooks. Not used by default hooks. */
+} __rte_cache_aligned;
+
+/**
+ * Allocate resource and initialize given headroom object with default
+ * values.
+ *
+ * @param hdr
+ *  The headroom object to be initialized.
+ *
+ * @return
+ *  0 if successfull or negative error value:
+ *  -EINVAL - if hdr is NULL
+ */
+int
+rte_headroom_init(struct rte_headroom *hdr);
+
+/**
+ * Deallocate any reserved resource make headroom object invalid.
+ *
+ * @pre All jobs from headroom object
+ *
+ * @param hdr The headroom object to be initialized.
+ */
+void
+rte_headroom_deinit(struct rte_headroom *hdr);
+
+/**
+ * Set new user data for headroom hooks.
+ *
+ * @param hdr
+ *  Headroom object to change a hook.
+ * @param loop_hook
+ *  New hook function. Can be NULL.
+ */
+void
+rte_headroom_set_user_data(struct rte_headroom *hdr, void *user_data);
+
+/**
+ * Set hook function executed when all jobs are executed in this loop turn.
+ *
+ * Time spent in this function is considered idle and counted as headroom. User
+ * application should not do any time consuming tasks in this hook as it can
+ * delay execution of job that became ready during time spent in this function.
+ *
+ * @param hdr
+ *  Headroom object to change a hook.
+ * @param loop_hook
+ *  New hook function. Can be NULL.
+ */
+void
+rte_headroom_set_loop_hook(struct rte_headroom *hdr,
+		rte_headroom_idle_hook_t loop_end_hook);
+
+/**
+ * Set hook function executed when no job is ready to execute (idle loop).
+ *
+ * Time spent in this function is considered idle and counted as headroom. User
+ * application should not do any time consuming tasks in this hook as it can
+ * delay execution of job that became ready during time spent in this function.
+ *
+ * @param hdr
+ *  Headroom object to change a hook.
+ * @param idle_hook
+ *  New hook function. Can be NULL.
+ */
+void
+rte_headroom_set_idle_hook(struct rte_headroom *hdr,
+		rte_headroom_idle_hook_t idle_hook);
+
+/**
+ * Wait for next job to be ready and execute it.
+ *
+ * @param headroom
+ *  Headroom object that contains jobs.
+ *
+ * @return
+ *  0 on success or negative error code:
+ *  -EINVAL if hdr is NULL.
+ *  -ENOENT if there is no added jobs.
+ */
+int
+rte_headroom_next_job(struct rte_headroom *hdr);
+
+/**
+ * Return first job handle that match callback and data parameter.
+ *
+ * @param hdr
+ *  Headroom obcjet to be searched.
+ * @param job_cb
+ *  Job callback to find.
+ * @param job_data
+ *  Job's private data pointer to find.
+ *
+ * @return
+ *  Job object
+ *  NULL if job is not found.
+ *  NULL and set rte_errno:
+ *   EINVAL if job_cb is NULL
+ *   ENOENT if there is no jobs added to headroom object
+ */
+struct rte_headroom_job *
+rte_headroom_find_job(struct rte_headroom *hdr,
+		rte_headroom_job_callbak_t job_cb, void *job_data);
+
+/**
+ * Return first job handle that match given name. Jobs without name
+ * can't be found.
+ *
+ * @param hdr
+ *  Headroom obcjet to be searched.
+ * @param job_name
+ *  Name of job to be found.
+ *
+ * @return
+ *  Job object
+ *  NULL if job is not found.
+ *  NULL and set rte_errno:
+ *   EINVAL if job_name is NULL
+ *   ENOENT if there is no jobs added to headroom object
+ */
+struct rte_headroom_job *
+rte_headroom_find_job_by_name(struct rte_headroom *hdr,	const char *job_name);
+
+/**
+ * Return current number of jobs in headroom object.
+ * @param hdr
+ *  Headroom object to interrogate.
+ * @return
+ *  Number of jobs.
+ */
+static inline uint16_t
+rte_headroom_job_count(struct rte_headroom *hdr)
+{
+	return hdr->job_count;
+}
+
+/**
+ * Add new job to headroom object.
+ *
+ * @param hdr The headroom object to which job will be added.
+ * @param name Name of ne job. Can be NULL.
+ * @param job_cb Callback for this job.
+ * @param job_data Job's private data pointer.
+ * @param job_handle Output - added job handle. Can be NULL.
+ *
+ * @return 0 on success or negative error code:
+ *  -EINVAL if hdr or job_cb is NULL.
+ *  -ENOBUFS if there is no space in headroom object to add new job.
+ */
+int
+rte_headroom_add_job(struct rte_headroom *hdr, const char *name,
+	rte_headroom_job_callbak_t job_cb, void *job_data, uint64_t min_period,
+	uint64_t max_period, uint64_t initial_period, int64_t target,
+	struct rte_headroom_job **job_handle);
+
+/**
+ * Remove given job from headroom.
+ *
+ * @param job
+ *  Job to be removed.
+ *
+ * @return
+ *  Count of remaining jobs in headroom to which belong removed job or negative
+ *  error value:
+ *   -EINVAL job is NULL
+ */
+int
+rte_headroom_del_job(struct rte_headroom_job *job);
+
+/**
+ * Set job desired target value. Difference between target and job callback
+ * return value must be used to properly adjust job execute period value.
+ * @param job
+ *  The job object.
+ * @param target
+ *  New target.
+ */
+static inline void
+rte_headroom_set_target(struct rte_headroom_job *job, int64_t target)
+{
+	job->job_target = target;
+}
+
+/**
+ * Set execute period of given job.
+ *
+ * @param job
+ *  The job ocbject.
+ * @param period
+ *  New period value.
+ * @param saturate
+ *  If zero, skip period saturatation to min, max range.
+ */
+static inline void
+rte_headroom_set_period(struct rte_headroom_job *job, uint64_t period,
+		uint8_t saturate)
+{
+	if (saturate != 0) {
+		if (period < job->min_period)
+			period = job->min_period;
+		else if (period > job->max_period)
+			period = job->max_period;
+	}
+
+	job->period = period;
+}
+
+/**
+ * Set minimum execute period of given job.
+ *
+ * @param job
+ *  The job ocject.
+ * @param period
+ *  New minimum period value.
+ */
+static inline void
+rte_headroom_set_min_period(struct rte_headroom_job *job, uint64_t period)
+{
+	job->min_period = period;
+	if (job->period < period)
+		job->period = period;
+}
+
+/**
+ * Set maximum execute period of given job.
+ *
+ * @param job
+ *  The job ocject.
+ * @param period
+ *  New maximum period value.
+ */
+static inline void
+rte_headroom_set_max_period(struct rte_headroom_job *job, uint64_t period)
+{
+	job->max_period = period;
+	if (job->period > period)
+		job->period = period;
+}
+
+/**
+ * Set update period callback that is invoked after task finish his job.
+ * If application want to
+ *
+ * @param job
+ *  Job object.
+ * @param update_pedriod_cb
+ *  Callback to set. If NULL restore default update function.
+ */
+void
+rte_headroom_set_update_period_function(struct rte_headroom_job *job,
+		rte_headroom_update_fn_t update_pedriod_cb);
+
+/**
+ * Retive job stats
+ *
+ * @param job
+ *  Job which statistics will be copied.
+ * @param stats
+ *  The output stats buffer.
+ *
+ */
+static inline void
+rte_headroom_get_job_stats(struct rte_headroom_job *job,
+		struct rte_headroom_stats *stats)
+{
+	rte_memcpy(stats, &job->stats, sizeof(job->stats));
+}
+
+/**
+ * Function resets job statistics.
+ *
+ * @param job
+ *  Job which statistics will be reset.
+ */
+static inline void
+rte_headroom_reset_job_stats(struct rte_headroom_job *job)
+{
+	struct rte_headroom_stats *s = &job->stats;
+
+	s->idle = 0;
+	s->idle_min = UINT64_MAX;
+	s->idle_max = 0;
+
+	s->run_time = 0;
+	s->run_time_min = UINT64_MAX;
+	s->run_time_max = 0;
+
+	s->exec_cnt = 0;
+}
+
+/**
+ * Retive headroom stats
+ *
+ * @param hdr
+ *  Headroom which statistics will be copied.
+ * @param stats
+ *  The output stats buffer.
+ */
+static inline void
+rte_headroom_get_stats(struct rte_headroom *hdr,
+		struct rte_headroom_stats *stats)
+{
+	rte_memcpy(stats, &hdr->stats, sizeof(hdr->stats));
+}
+
+/**
+ * Function resets headroom statistics.
+ *
+ * @param hdr
+ *  Headroom which statistics will be reset.
+ */
+static inline void
+rte_headroom_reset_stats(struct rte_headroom *hdr)
+{
+	struct rte_headroom_stats *s = &hdr->stats;
+
+	s->idle = 0;
+	s->idle_min = UINT64_MAX;
+	s->idle_max = 0;
+
+	s->run_time = 0;
+	s->run_time_min = UINT64_MAX;
+	s->run_time_max = 0;
+
+	s->exec_cnt = 0;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HEADROOM_H_ */
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 40afb2c..bc2af88 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -103,6 +103,10 @@ ifeq ($(CONFIG_RTE_LIBRTE_HASH),y)
 LDLIBS += -lrte_hash
 endif
 
+ifeq ($(CONFIG_RTE_LIBRTE_HEADROOM),y)
+LDLIBS += -lrte_headroom
+endif
+
 ifeq ($(CONFIG_RTE_LIBRTE_LPM),y)
 LDLIBS += -lrte_lpm
 endif
