diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c
index 1a32c71..83ffa5d 100644
--- a/lib/librte_pipeline/rte_table_action.c
+++ b/lib/librte_pipeline/rte_table_action.c
@@ -45,6 +45,55 @@ fwd_apply(struct fwd_data *data,
 }
 
 /**
+ * RTE_TABLE_ACTION_LB
+ */
+static int
+lb_cfg_check(struct rte_table_action_lb_config *cfg)
+{
+	if ((cfg == NULL) ||
+		(cfg->key_size < RTE_TABLE_ACTION_LB_KEY_SIZE_MIN) ||
+		(cfg->key_size > RTE_TABLE_ACTION_LB_KEY_SIZE_MAX) ||
+		(!rte_is_power_of_2(cfg->key_size)) ||
+		(cfg->f_hash == NULL))
+		return -1;
+
+	return 0;
+}
+
+struct lb_data {
+	uint32_t out[RTE_TABLE_ACTION_LB_TABLE_SIZE];
+} __attribute__((__packed__));
+
+static int
+lb_apply(struct lb_data *data,
+	struct rte_table_action_lb_params *p)
+{
+	memcpy(data->out, p->out, sizeof(data->out));
+
+	return 0;
+}
+
+static __rte_always_inline void
+pkt_work_lb(struct rte_mbuf *mbuf,
+	struct lb_data *data,
+	struct rte_table_action_lb_config *cfg)
+{
+	uint8_t *pkt_key = RTE_MBUF_METADATA_UINT8_PTR(mbuf, cfg->key_offset);
+	uint32_t *out = RTE_MBUF_METADATA_UINT32_PTR(mbuf, cfg->out_offset);
+	uint64_t digest, pos;
+	uint32_t out_val;
+
+	digest = cfg->f_hash(pkt_key,
+		cfg->key_mask,
+		cfg->key_size,
+		cfg->seed);
+	pos = digest & (RTE_TABLE_ACTION_LB_TABLE_SIZE - 1);
+	out_val = data->out[pos];
+
+	*out = out_val;
+}
+
+/**
  * RTE_TABLE_ACTION_MTR
  */
 static int
@@ -1178,6 +1227,7 @@ action_valid(enum rte_table_action_type action)
 {
 	switch (action) {
 	case RTE_TABLE_ACTION_FWD:
+	case RTE_TABLE_ACTION_LB:
 	case RTE_TABLE_ACTION_MTR:
 	case RTE_TABLE_ACTION_TM:
 	case RTE_TABLE_ACTION_ENCAP:
@@ -1197,6 +1247,7 @@ action_valid(enum rte_table_action_type action)
 struct ap_config {
 	uint64_t action_mask;
 	struct rte_table_action_common_config common;
+	struct rte_table_action_lb_config lb;
 	struct rte_table_action_mtr_config mtr;
 	struct rte_table_action_tm_config tm;
 	struct rte_table_action_encap_config encap;
@@ -1209,6 +1260,8 @@ static size_t
 action_cfg_size(enum rte_table_action_type action)
 {
 	switch (action) {
+	case RTE_TABLE_ACTION_LB:
+		return sizeof(struct rte_table_action_lb_config);
 	case RTE_TABLE_ACTION_MTR:
 		return sizeof(struct rte_table_action_mtr_config);
 	case RTE_TABLE_ACTION_TM:
@@ -1231,6 +1284,9 @@ action_cfg_get(struct ap_config *ap_config,
 	enum rte_table_action_type type)
 {
 	switch (type) {
+	case RTE_TABLE_ACTION_LB:
+		return &ap_config->lb;
+
 	case RTE_TABLE_ACTION_MTR:
 		return &ap_config->mtr;
 
@@ -1280,6 +1336,9 @@ action_data_size(enum rte_table_action_type action,
 	case RTE_TABLE_ACTION_FWD:
 		return sizeof(struct fwd_data);
 
+	case RTE_TABLE_ACTION_LB:
+		return sizeof(struct lb_data);
+
 	case RTE_TABLE_ACTION_MTR:
 		return mtr_data_size(&ap_config->mtr);
 
@@ -1373,6 +1432,10 @@ rte_table_action_profile_action_register(struct rte_table_action_profile *profil
 		return -EINVAL;
 
 	switch (type) {
+	case RTE_TABLE_ACTION_LB:
+		status = lb_cfg_check(action_config);
+		break;
+
 	case RTE_TABLE_ACTION_MTR:
 		status = mtr_cfg_check(action_config);
 		break;
@@ -1507,6 +1570,10 @@ rte_table_action_apply(struct rte_table_action *action,
 		return fwd_apply(action_data,
 			action_params);
 
+	case RTE_TABLE_ACTION_LB:
+		return lb_apply(action_data,
+			action_params);
+
 	case RTE_TABLE_ACTION_MTR:
 		return mtr_apply(action_data,
 			action_params,
@@ -1822,6 +1889,14 @@ pkt_work(struct rte_mbuf *mbuf,
 			rte_ntohs(hdr->payload_len) + sizeof(struct ipv6_hdr);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_LB)) {
+		void *data =
+			action_data_get(table_entry, action, RTE_TABLE_ACTION_LB);
+
+		pkt_work_lb(mbuf,
+			data,
+			&cfg->lb);
+	}
 	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
 		void *data =
 			action_data_get(table_entry, action, RTE_TABLE_ACTION_MTR);
@@ -1961,6 +2036,33 @@ pkt4_work(struct rte_mbuf **mbufs,
 			rte_ntohs(hdr3->payload_len) + sizeof(struct ipv6_hdr);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_LB)) {
+		void *data0 =
+			action_data_get(table_entry0, action, RTE_TABLE_ACTION_LB);
+		void *data1 =
+			action_data_get(table_entry1, action, RTE_TABLE_ACTION_LB);
+		void *data2 =
+			action_data_get(table_entry2, action, RTE_TABLE_ACTION_LB);
+		void *data3 =
+			action_data_get(table_entry3, action, RTE_TABLE_ACTION_LB);
+
+		pkt_work_lb(mbuf0,
+			data0,
+			&cfg->lb);
+
+		pkt_work_lb(mbuf1,
+			data1,
+			&cfg->lb);
+
+		pkt_work_lb(mbuf2,
+			data2,
+			&cfg->lb);
+
+		pkt_work_lb(mbuf3,
+			data3,
+			&cfg->lb);
+	}
+
 	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
 		void *data0 =
 			action_data_get(table_entry0, action, RTE_TABLE_ACTION_MTR);
diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h
index e9b30ab..c7f751a 100644
--- a/lib/librte_pipeline/rte_table_action.h
+++ b/lib/librte_pipeline/rte_table_action.h
@@ -61,6 +61,7 @@ extern "C" {
 #include <rte_compat.h>
 #include <rte_ether.h>
 #include <rte_meter.h>
+#include <rte_table_hash.h>
 
 #include "rte_pipeline.h"
 
@@ -69,6 +70,9 @@ enum rte_table_action_type {
 	/** Forward to next pipeline table, output port or drop. */
 	RTE_TABLE_ACTION_FWD = 0,
 
+	/**  Load balance. */
+	RTE_TABLE_ACTION_LB,
+
 	/**  Traffic Metering and Policing. */
 	RTE_TABLE_ACTION_MTR,
 
@@ -117,6 +121,54 @@ struct rte_table_action_fwd_params {
 };
 
 /**
+ * RTE_TABLE_ACTION_LB
+ */
+/** Load balance key size min (number of bytes). */
+#define RTE_TABLE_ACTION_LB_KEY_SIZE_MIN                    8
+
+/** Load balance key size max (number of bytes). */
+#define RTE_TABLE_ACTION_LB_KEY_SIZE_MAX                    64
+
+/** Load balance table size. */
+#define RTE_TABLE_ACTION_LB_TABLE_SIZE                      8
+
+/** Load balance action configuration (per table action profile). */
+struct rte_table_action_lb_config {
+	/** Key size (number of bytes). */
+	uint32_t key_size;
+
+	/** Key offset within the input packet buffer. Offset 0 points to the
+	 * first byte of the MBUF structure.
+	 */
+	uint32_t key_offset;
+
+	/** Key mask (*key_size* bytes are valid). */
+	uint8_t key_mask[RTE_TABLE_ACTION_LB_KEY_SIZE_MAX];
+
+	/** Hash function. */
+	rte_table_hash_op_hash f_hash;
+
+	/** Seed value for *f_hash*. */
+	uint64_t seed;
+
+	/** Output value offset within the input packet buffer. Offset 0 points
+	 * to the first byte of the MBUF structure.
+	 */
+	uint32_t out_offset;
+};
+
+/** Load balance action parameters (per table rule). */
+struct rte_table_action_lb_params {
+	/** Table defining the output values and their weights. The weights are
+	 * set in 1/RTE_TABLE_ACTION_LB_TABLE_SIZE increments. To assign a
+	 * weight of N/RTE_TABLE_ACTION_LB_TABLE_SIZE to a given output value
+	 * (0 <= N <= RTE_TABLE_ACTION_LB_TABLE_SIZE), the same output value
+	 * needs to show up exactly N times in this table.
+	 */
+	uint32_t out[RTE_TABLE_ACTION_LB_TABLE_SIZE];
+};
+
+/**
  * RTE_TABLE_ACTION_MTR
  */
 /** Max number of traffic classes (TCs). */
