diff --git a/libibverbs/CMakeLists.txt b/libibverbs/CMakeLists.txt
index 04f5b1b..b0e57b5 100644
--- a/libibverbs/CMakeLists.txt
+++ b/libibverbs/CMakeLists.txt
@@ -31,6 +31,7 @@ rdma_library(ibverbs "${CMAKE_CURRENT_BINARY_DIR}/libibverbs.map"
   cmd.c
   cmd_cq.c
   cmd_fallback.c
+  cmd_flow_action.c
   cmd_ioctl.c
   compat-1_0.c
   device.c
diff --git a/libibverbs/cmd_flow_action.c b/libibverbs/cmd_flow_action.c
new file mode 100644
index 0000000..122ad04
--- /dev/null
+++ b/libibverbs/cmd_flow_action.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2018 Mellanox Technologies, Ltd.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <infiniband/cmd_ioctl.h>
+#include <rdma/ib_user_ioctl_cmds.h>
+#include <infiniband/driver.h>
+
+static void scrub_esp_encap(struct ibv_flow_action_esp_encap *esp_encap)
+{
+	scrub_ptr_attr(esp_encap->val_ptr);
+	scrub_ptr_attr(esp_encap->next_ptr);
+}
+
+static int copy_flow_action_esp(struct ibv_flow_action_esp_attr *esp,
+				struct ibv_command_buffer *cmd)
+{
+	if (esp->comp_mask & IBV_FLOW_ACTION_ESP_MASK_ESN)
+		fill_attr_in(cmd, UVERBS_ATTR_FLOW_ACTION_ESP_ESN,
+			     &esp->esn, sizeof(esp->esn));
+
+	if (esp->keymat_ptr)
+		fill_attr_in_enum(cmd, UVERBS_ATTR_FLOW_ACTION_ESP_KEYMAT,
+				  esp->keymat_proto,
+				  esp->keymat_ptr, esp->keymat_len);
+	if (esp->replay_ptr)
+		fill_attr_in_enum(cmd, UVERBS_ATTR_FLOW_ACTION_ESP_REPLAY,
+				  esp->replay_proto,
+				  esp->replay_ptr, esp->replay_len);
+	if (esp->esp_encap) {
+		scrub_esp_encap(esp->esp_encap);
+		fill_attr_in_ptr(cmd, UVERBS_ATTR_FLOW_ACTION_ESP_ENCAP,
+				 esp->esp_encap);
+	}
+	if (esp->esp_attr)
+		fill_attr_in_ptr(cmd, UVERBS_ATTR_FLOW_ACTION_ESP_ATTRS,
+				 esp->esp_attr);
+
+	return 0;
+}
+
+#define FLOW_ACTION_ESP_ATTRS_NUM	6
+int ibv_cmd_create_flow_action_esp(struct ibv_context *ctx,
+				   struct ibv_flow_action_esp_attr *attr,
+				   struct verbs_flow_action *flow_action,
+				   struct ibv_command_buffer *driver)
+{
+	DECLARE_COMMAND_BUFFER_LINK(cmd, UVERBS_OBJECT_FLOW_ACTION,
+				     UVERBS_METHOD_FLOW_ACTION_ESP_CREATE,
+				     FLOW_ACTION_ESP_ATTRS_NUM,
+				     driver);
+	struct ib_uverbs_attr *handle =
+		fill_attr_out_obj(cmd, UVERBS_ATTR_FLOW_ACTION_ESP_HANDLE);
+	int ret;
+
+	ret = copy_flow_action_esp(attr, cmd);
+	if (ret)
+		return ret;
+
+	ret = execute_ioctl(ctx, cmd);
+	if (ret)
+		return errno;
+
+	flow_action->action.context = ctx;
+	flow_action->type = IBV_FLOW_ACTION_ESP;
+	flow_action->handle = read_attr_obj(UVERBS_ATTR_FLOW_ACTION_ESP_HANDLE,
+					    handle);
+
+	return 0;
+}
+
+int ibv_cmd_modify_flow_action_esp(struct verbs_flow_action *flow_action,
+				   struct ibv_flow_action_esp_attr *attr,
+				   struct ibv_command_buffer *driver)
+{
+	DECLARE_COMMAND_BUFFER_LINK(cmd, UVERBS_OBJECT_FLOW_ACTION,
+				     UVERBS_METHOD_FLOW_ACTION_ESP_MODIFY,
+				     FLOW_ACTION_ESP_ATTRS_NUM, driver);
+	int ret;
+
+	fill_attr_in_obj(cmd, UVERBS_ATTR_FLOW_ACTION_ESP_HANDLE,
+			 flow_action->handle);
+
+	ret = copy_flow_action_esp(attr, cmd);
+	if (ret)
+		return ret;
+
+	return execute_ioctl(flow_action->action.context, cmd);
+}
+
+int ibv_cmd_destroy_flow_action(struct verbs_flow_action *action)
+{
+	DECLARE_COMMAND_BUFFER(cmd, UVERBS_OBJECT_FLOW_ACTION,
+			       UVERBS_METHOD_FLOW_ACTION_DESTROY, 1);
+
+	fill_attr_in_obj(cmd, UVERBS_ATTR_DESTROY_FLOW_ACTION_HANDLE,
+			 action->handle);
+	return execute_ioctl(action->action.context, cmd);
+}
+
diff --git a/libibverbs/cmd_ioctl.h b/libibverbs/cmd_ioctl.h
index 94814c1..862ac66 100644
--- a/libibverbs/cmd_ioctl.h
+++ b/libibverbs/cmd_ioctl.h
@@ -39,6 +39,7 @@
 #include <assert.h>
 #include <rdma/rdma_user_ioctl_cmds.h>
 #include <infiniband/verbs.h>
+#include <ccan/container_of.h>
 
 static inline uint64_t ioctl_ptr_to_u64(const void *ptr)
 {
@@ -57,6 +58,18 @@ static inline uint64_t ioctl_ptr_to_u64(const void *ptr)
 #endif
 }
 
+static inline void scrub_ptr_attr(void *ptr)
+{
+#if UINTPTR_MAX == UINT64_MAX
+	/* Do nothing */
+#else
+	RDMA_UAPI_PTR(void *, data) *scrub_data;
+
+	scrub_data = container_of(ptr, typeof(*scrub_data), data);
+	scrub_data->data_data_u64 = ioctl_ptr_to_u64(scrub_data->data);
+#endif
+}
+
 /*
  * The command buffer is organized as a linked list of blocks of attributes.
  * Each stack frame allocates its block and then calls up toward to core code
diff --git a/libibverbs/driver.h b/libibverbs/driver.h
index a4097c0..55622fc 100644
--- a/libibverbs/driver.h
+++ b/libibverbs/driver.h
@@ -42,6 +42,7 @@
 #include <config.h>
 #include <stdbool.h>
 #include <rdma/rdma_user_ioctl_cmds.h>
+#include <infiniband/cmd_ioctl.h>
 
 struct verbs_device;
 
@@ -89,6 +90,17 @@ struct verbs_qp {
 	struct verbs_xrcd       *xrcd;
 };
 
+enum ibv_flow_action_type {
+	IBV_FLOW_ACTION_UNSPECIFIED,
+	IBV_FLOW_ACTION_ESP = 1,
+};
+
+struct verbs_flow_action {
+	struct ibv_flow_action		action;
+	uint32_t			handle;
+	enum ibv_flow_action_type	type;
+};
+
 enum {
 	VERBS_MATCH_SENTINEL = 0,
 	VERBS_MATCH_PCI = 1,
@@ -202,6 +214,8 @@ struct verbs_context_ops {
 		struct ibv_cq_init_attr_ex *init_attr);
 	struct ibv_flow *(*create_flow)(struct ibv_qp *qp,
 					struct ibv_flow_attr *flow_attr);
+	struct ibv_flow_action *(*create_flow_action_esp)(struct ibv_context *context,
+							  struct ibv_flow_action_esp_attr *attr);
 	struct ibv_qp *(*create_qp)(struct ibv_pd *pd,
 				    struct ibv_qp_init_attr *attr);
 	struct ibv_qp *(*create_qp_ex)(
@@ -224,6 +238,7 @@ struct verbs_context_ops {
 	int (*destroy_ah)(struct ibv_ah *ah);
 	int (*destroy_cq)(struct ibv_cq *cq);
 	int (*destroy_flow)(struct ibv_flow *flow);
+	int (*destroy_flow_action)(struct ibv_flow_action *action);
 	int (*destroy_qp)(struct ibv_qp *qp);
 	int (*destroy_rwq_ind_table)(struct ibv_rwq_ind_table *rwq_ind_table);
 	int (*destroy_srq)(struct ibv_srq *srq);
@@ -232,6 +247,8 @@ struct verbs_context_ops {
 			    uint16_t lid);
 	int (*get_srq_num)(struct ibv_srq *srq, uint32_t *srq_num);
 	int (*modify_cq)(struct ibv_cq *cq, struct ibv_modify_cq_attr *attr);
+	int (*modify_flow_action_esp)(struct ibv_flow_action *action,
+				      struct ibv_flow_action_esp_attr *attr);
 	int (*modify_qp)(struct ibv_qp *qp, struct ibv_qp_attr *attr,
 			 int attr_mask);
 	int (*modify_qp_rate_limit)(struct ibv_qp *qp,
@@ -330,6 +347,13 @@ int ibv_cmd_query_device(struct ibv_context *context,
 			 struct ibv_device_attr *device_attr,
 			 uint64_t *raw_fw_ver,
 			 struct ibv_query_device *cmd, size_t cmd_size);
+int ibv_cmd_create_flow_action_esp(struct ibv_context *ctx,
+				   struct ibv_flow_action_esp_attr *attr,
+				   struct verbs_flow_action *flow_action,
+				   struct ibv_command_buffer *driver);
+int ibv_cmd_modify_flow_action_esp(struct verbs_flow_action *flow_action,
+				   struct ibv_flow_action_esp_attr *attr,
+				   struct ibv_command_buffer *driver);
 int ibv_cmd_query_device_ex(struct ibv_context *context,
 			    const struct ibv_query_device_ex_input *input,
 			    struct ibv_device_attr_ex *attr, size_t attr_size,
@@ -475,6 +499,7 @@ int ibv_cmd_create_wq(struct ibv_context *context,
 		      size_t resp_core_size,
 		      size_t resp_size);
 
+int ibv_cmd_destroy_flow_action(struct verbs_flow_action *action);
 int ibv_cmd_modify_wq(struct ibv_wq *wq, struct ibv_wq_attr *attr,
 		      struct ibv_modify_wq *cmd, size_t cmd_core_size,
 		      size_t cmd_size);
diff --git a/libibverbs/dummy_ops.c b/libibverbs/dummy_ops.c
index c67ad83..2e5a8cb 100644
--- a/libibverbs/dummy_ops.c
+++ b/libibverbs/dummy_ops.c
@@ -113,6 +113,13 @@ static struct ibv_flow *create_flow(struct ibv_qp *qp,
 	return NULL;
 }
 
+static struct ibv_flow_action *create_flow_action_esp(struct ibv_context *context,
+						      struct ibv_flow_action_esp_attr *attr)
+{
+	errno = ENOSYS;
+	return NULL;
+}
+
 static struct ibv_qp *create_qp(struct ibv_pd *pd,
 				struct ibv_qp_init_attr *attr)
 {
@@ -192,6 +199,11 @@ static int destroy_flow(struct ibv_flow *flow)
 	return ENOSYS;
 }
 
+static int destroy_flow_action(struct ibv_flow_action *action)
+{
+	return ENOSYS;
+}
+
 static int destroy_qp(struct ibv_qp *qp)
 {
 	return ENOSYS;
@@ -228,6 +240,12 @@ static int modify_cq(struct ibv_cq *cq, struct ibv_modify_cq_attr *attr)
 	return ENOSYS;
 }
 
+static int modify_flow_action_esp(struct ibv_flow_action *action,
+				  struct ibv_flow_action_esp_attr *attr)
+{
+	return ENOSYS;
+}
+
 static int modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, int attr_mask)
 {
 	return ENOSYS;
@@ -378,6 +396,7 @@ const struct verbs_context_ops verbs_dummy_ops = {
 	create_cq,
 	create_cq_ex,
 	create_flow,
+	create_flow_action_esp,
 	create_qp,
 	create_qp_ex,
 	create_rwq_ind_table,
@@ -391,6 +410,7 @@ const struct verbs_context_ops verbs_dummy_ops = {
 	destroy_ah,
 	destroy_cq,
 	destroy_flow,
+	destroy_flow_action,
 	destroy_qp,
 	destroy_rwq_ind_table,
 	destroy_srq,
@@ -398,6 +418,7 @@ const struct verbs_context_ops verbs_dummy_ops = {
 	detach_mcast,
 	get_srq_num,
 	modify_cq,
+	modify_flow_action_esp,
 	modify_qp,
 	modify_qp_rate_limit,
 	modify_srq,
@@ -456,6 +477,7 @@ void verbs_set_ops(struct verbs_context *vctx,
 	SET_OP(ctx, create_cq);
 	SET_OP(vctx, create_cq_ex);
 	SET_OP2(vctx, ibv_create_flow, create_flow);
+	SET_OP(vctx, create_flow_action_esp);
 	SET_OP(ctx, create_qp);
 	SET_OP(vctx, create_qp_ex);
 	SET_OP(vctx, create_rwq_ind_table);
@@ -469,6 +491,7 @@ void verbs_set_ops(struct verbs_context *vctx,
 	SET_OP(ctx, destroy_ah);
 	SET_OP(ctx, destroy_cq);
 	SET_OP2(vctx, ibv_destroy_flow, destroy_flow);
+	SET_OP(vctx, destroy_flow_action);
 	SET_OP(ctx, destroy_qp);
 	SET_OP(vctx, destroy_rwq_ind_table);
 	SET_OP(ctx, destroy_srq);
@@ -476,6 +499,7 @@ void verbs_set_ops(struct verbs_context *vctx,
 	SET_OP(ctx, detach_mcast);
 	SET_OP(vctx, get_srq_num);
 	SET_OP(vctx, modify_cq);
+	SET_OP(vctx, modify_flow_action_esp);
 	SET_OP(ctx, modify_qp);
 	SET_OP(vctx, modify_qp_rate_limit);
 	SET_OP(ctx, modify_srq);
diff --git a/libibverbs/libibverbs.map.in b/libibverbs/libibverbs.map.in
index e97548d..2eb02c8 100644
--- a/libibverbs/libibverbs.map.in
+++ b/libibverbs/libibverbs.map.in
@@ -123,6 +123,7 @@ IBVERBS_PRIVATE_@IBVERBS_PABI_VERSION@ {
 		ibv_cmd_create_cq;
 		ibv_cmd_create_cq_ex;
 		ibv_cmd_create_flow;
+		ibv_cmd_create_flow_action_esp;
 		ibv_cmd_create_qp;
 		ibv_cmd_create_qp_ex2;
 		ibv_cmd_create_qp_ex;
@@ -136,12 +137,14 @@ IBVERBS_PRIVATE_@IBVERBS_PABI_VERSION@ {
 		ibv_cmd_destroy_ah;
 		ibv_cmd_destroy_cq;
 		ibv_cmd_destroy_flow;
+		ibv_cmd_destroy_flow_action;
 		ibv_cmd_destroy_qp;
 		ibv_cmd_destroy_rwq_ind_table;
 		ibv_cmd_destroy_srq;
 		ibv_cmd_destroy_wq;
 		ibv_cmd_detach_mcast;
 		ibv_cmd_get_context;
+		ibv_cmd_modify_flow_action_esp;
 		ibv_cmd_modify_qp;
 		ibv_cmd_modify_qp_ex;
 		ibv_cmd_modify_srq;
diff --git a/libibverbs/verbs.h b/libibverbs/verbs.h
index b4bb85d..4e4a658 100644
--- a/libibverbs/verbs.h
+++ b/libibverbs/verbs.h
@@ -1518,6 +1518,31 @@ struct ibv_flow {
 	uint32_t	   handle;
 };
 
+struct ibv_flow_action {
+	struct ibv_context *context;
+};
+
+enum ibv_flow_action_esp_mask {
+	IBV_FLOW_ACTION_ESP_MASK_ESN    = 1UL << 0,
+};
+
+struct ibv_flow_action_esp_attr {
+	struct ibv_flow_action_esp *esp_attr;
+
+	enum ibv_flow_action_esp_keymat	keymat_proto;
+	uint16_t		keymat_len;
+	void			*keymat_ptr;
+
+	enum ibv_flow_action_esp_replay replay_proto;
+	uint16_t                replay_len;
+	void                    *replay_ptr;
+
+	struct ibv_flow_action_esp_encap *esp_encap;
+
+	uint32_t		comp_mask; /* Use enum ibv_flow_action_esp_mask */
+	uint32_t		esn;
+};
+
 struct ibv_device;
 struct ibv_context;
 
@@ -1665,6 +1690,11 @@ struct ibv_values_ex {
 
 struct verbs_context {
 	/*  "grows up" - new fields go here */
+	int (*modify_flow_action_esp)(struct ibv_flow_action *action,
+				      struct ibv_flow_action_esp_attr *attr);
+	int (*destroy_flow_action)(struct ibv_flow_action *action);
+	struct ibv_flow_action *(*create_flow_action_esp)(struct ibv_context *context,
+							  struct ibv_flow_action_esp_attr *attr);
 	int (*modify_qp_rate_limit)(struct ibv_qp *qp,
 				    struct ibv_qp_rate_limit_attr *attr);
 	struct ibv_pd *(*alloc_parent_domain)(struct ibv_context *context,
@@ -1859,6 +1889,45 @@ static inline int ibv_destroy_flow(struct ibv_flow *flow_id)
 	return vctx->ibv_destroy_flow(flow_id);
 }
 
+static inline struct ibv_flow_action *
+ibv_create_flow_action_esp(struct ibv_context *ctx,
+			   struct ibv_flow_action_esp_attr *esp)
+{
+	struct verbs_context *vctx = verbs_get_ctx_op(ctx,
+						      create_flow_action_esp);
+
+	if (!vctx) {
+		errno = ENOSYS;
+		return NULL;
+	}
+
+	return vctx->create_flow_action_esp(ctx, esp);
+}
+
+static inline int
+ibv_modify_flow_action_esp(struct ibv_flow_action *action,
+			   struct ibv_flow_action_esp_attr *esp)
+{
+	struct verbs_context *vctx = verbs_get_ctx_op(action->context,
+						      modify_flow_action_esp);
+
+	if (!vctx)
+		return ENOSYS;
+
+	return vctx->modify_flow_action_esp(action, esp);
+}
+
+static inline int ibv_destroy_flow_action(struct ibv_flow_action *action)
+{
+	struct verbs_context *vctx = verbs_get_ctx_op(action->context,
+						      destroy_flow_action);
+
+	if (!vctx)
+		return ENOSYS;
+
+	return vctx->destroy_flow_action(action);
+}
+
 /**
  * ibv_open_xrcd - Open an extended connection domain
  */
