diff --git a/examples/ipsec-secgw/esp.c b/examples/ipsec-secgw/esp.c
index bfa7ff7217..3762d61597 100644
--- a/examples/ipsec-secgw/esp.c
+++ b/examples/ipsec-secgw/esp.c
@@ -265,9 +265,9 @@ esp_outbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 
 	RTE_ASSERT(IS_TUNNEL(sa->flags) || IS_TRANSPORT(sa->flags));
 
-	if (likely(IS_IP4_TUNNEL(sa->flags)))
+	if (likely((IS_TUNNEL(sa->flags) && IS_IP4(sa->flags))))
 		ip_hdr_len = sizeof(struct ip);
-	else if (IS_IP6_TUNNEL(sa->flags))
+	else if ((IS_TUNNEL(sa->flags) && IS_IP6(sa->flags)))
 		ip_hdr_len = sizeof(struct ip6_hdr);
 	else if (!IS_TRANSPORT(sa->flags)) {
 		RTE_LOG(ERR, IPSEC_ESP, "Unsupported SA flags: 0x%x\n",
@@ -308,7 +308,8 @@ esp_outbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 				&sa->src, &sa->dst);
 		esp = (struct rte_esp_hdr *)(ip6 + 1);
 		break;
-	case TRANSPORT:
+	case IP4_TRANSPORT:
+	case IP6_TRANSPORT:
 		new_ip = (uint8_t *)rte_pktmbuf_prepend(m,
 				sizeof(struct rte_esp_hdr) + sa->iv_len);
 		memmove(new_ip, ip4, ip_hdr_len);
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c
index 6d516e2221..46fb49d91e 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -2299,9 +2299,6 @@ port_init(uint16_t portid, uint64_t req_rx_offloads, uint64_t req_tx_offloads)
 		/* Pre-populate pkt offloads based on capabilities */
 		qconf->outbound.ipv4_offloads = PKT_TX_IPV4;
 		qconf->outbound.ipv6_offloads = PKT_TX_IPV6;
-		if (local_port_conf.txmode.offloads & DEV_TX_OFFLOAD_IPV4_CKSUM)
-			qconf->outbound.ipv4_offloads |= PKT_TX_IP_CKSUM;
-
 		tx_queueid++;
 
 		/* init RX queues */
diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c
index 5b032fecfb..aa68e4f827 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -24,7 +24,7 @@ set_ipsec_conf(struct ipsec_sa *sa, struct rte_security_ipsec_xform *ipsec)
 	if (ipsec->mode == RTE_SECURITY_IPSEC_SA_MODE_TUNNEL) {
 		struct rte_security_ipsec_tunnel_param *tunnel =
 				&ipsec->tunnel;
-		if (IS_IP4_TUNNEL(sa->flags)) {
+		if (IS_TUNNEL(sa->flags) && IS_IP4(sa->flags)) {
 			tunnel->type =
 				RTE_SECURITY_IPSEC_TUNNEL_IPV4;
 			tunnel->ipv4.ttl = IPDEFTTL;
@@ -34,7 +34,7 @@ set_ipsec_conf(struct ipsec_sa *sa, struct rte_security_ipsec_xform *ipsec)
 
 			memcpy((uint8_t *)&tunnel->ipv4.dst_ip,
 				(uint8_t *)&sa->dst.ip.ip4, 4);
-		} else if (IS_IP6_TUNNEL(sa->flags)) {
+		} else if (IS_TUNNEL(sa->flags) && IS_IP6(sa->flags)) {
 			tunnel->type =
 				RTE_SECURITY_IPSEC_TUNNEL_IPV6;
 			tunnel->ipv6.hlimit = IPDEFTTL;
@@ -163,262 +163,196 @@ create_inline_session(struct socket_ctx *skt_ctx, struct ipsec_sa *sa,
 {
 	int32_t ret = 0;
 	struct rte_security_ctx *sec_ctx;
+	const struct rte_security_capability *sec_cap;
 	struct rte_security_session_conf sess_conf = {
 		.action_type = ips->type,
 		.protocol = RTE_SECURITY_PROTOCOL_IPSEC,
 		{.ipsec = {
-			.spi = sa->spi,
+			.spi = htonl(sa->spi),
 			.salt = sa->salt,
 			.options = { 0 },
 			.replay_win_sz = 0,
 			.direction = sa->direction,
-			.proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
-			.mode = (sa->flags == IP4_TUNNEL ||
-					sa->flags == IP6_TUNNEL) ?
-					RTE_SECURITY_IPSEC_SA_MODE_TUNNEL :
-					RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT,
+			.proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP
 		} },
 		.crypto_xform = sa->xforms,
 		.userdata = NULL,
 	};
 
-	RTE_LOG_DP(DEBUG, IPSEC, "Create session for SA spi %u on port %u\n",
-		sa->spi, sa->portid);
+	if (IS_TRANSPORT(sa->flags)) {
+		sess_conf.ipsec.mode = RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT;
+		/**
+		 * TODO: address this in rte_security API
+		 * Use tunnel parameters to pass both transport IP addresses
+		 */
+		if (IS_IP4(sa->flags)) {
+			sess_conf.ipsec.tunnel.type =
+				RTE_SECURITY_IPSEC_TUNNEL_IPV4;
 
-	if (ips->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO) {
-		struct rte_flow_error err;
-		const struct rte_security_capability *sec_cap;
-		int ret = 0;
-
-		sec_ctx = (struct rte_security_ctx *)
-					rte_eth_dev_get_sec_ctx(
-					sa->portid);
-		if (sec_ctx == NULL) {
-			RTE_LOG(ERR, IPSEC,
-				" rte_eth_dev_get_sec_ctx failed\n");
-			return -1;
-		}
+			sess_conf.ipsec.tunnel.ipv4.src_ip.s_addr =
+				sa->src.ip.ip4;
+			sess_conf.ipsec.tunnel.ipv4.dst_ip.s_addr =
+				sa->dst.ip.ip4;
+		} else if (IS_IP6(sa->flags)) {
+			sess_conf.ipsec.tunnel.type =
+				RTE_SECURITY_IPSEC_TUNNEL_IPV6;
 
-		ips->security.ses = rte_security_session_create(sec_ctx,
-				&sess_conf, skt_ctx->session_pool,
-				skt_ctx->session_priv_pool);
-		if (ips->security.ses == NULL) {
-			RTE_LOG(ERR, IPSEC,
-				"SEC Session init failed: err: %d\n", ret);
-			return -1;
+			memcpy(sess_conf.ipsec.tunnel.ipv6.src_addr.s6_addr,
+				sa->src.ip.ip6.ip6_b, 16);
+			memcpy(sess_conf.ipsec.tunnel.ipv6.dst_addr.s6_addr,
+				sa->dst.ip.ip6.ip6_b, 16);
 		}
+	} else if (IS_TUNNEL(sa->flags)) {
+		sess_conf.ipsec.mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL;
 
-		sec_cap = rte_security_capabilities_get(sec_ctx);
-
-		/* iterate until ESP tunnel*/
-		while (sec_cap->action != RTE_SECURITY_ACTION_TYPE_NONE) {
-			if (sec_cap->action == ips->type &&
-			    sec_cap->protocol ==
-				RTE_SECURITY_PROTOCOL_IPSEC &&
-			    sec_cap->ipsec.mode ==
-				RTE_SECURITY_IPSEC_SA_MODE_TUNNEL &&
-			    sec_cap->ipsec.direction == sa->direction)
-				break;
-			sec_cap++;
-		}
+		if (IS_IP4(sa->flags)) {
+			sess_conf.ipsec.tunnel.type =
+				RTE_SECURITY_IPSEC_TUNNEL_IPV4;
 
-		if (sec_cap->action == RTE_SECURITY_ACTION_TYPE_NONE) {
-			RTE_LOG(ERR, IPSEC,
-				"No suitable security capability found\n");
+			sess_conf.ipsec.tunnel.ipv4.src_ip.s_addr =
+				sa->src.ip.ip4;
+			sess_conf.ipsec.tunnel.ipv4.dst_ip.s_addr =
+				sa->dst.ip.ip4;
+		} else if (IS_IP6(sa->flags)) {
+			sess_conf.ipsec.tunnel.type =
+				RTE_SECURITY_IPSEC_TUNNEL_IPV6;
+
+			memcpy(sess_conf.ipsec.tunnel.ipv6.src_addr.s6_addr,
+				sa->src.ip.ip6.ip6_b, 16);
+			memcpy(sess_conf.ipsec.tunnel.ipv6.dst_addr.s6_addr,
+				sa->dst.ip.ip6.ip6_b, 16);
+		} else {
+			RTE_LOG(ERR, IPSEC, "invalid tunnel type\n");
 			return -1;
 		}
+	}
 
-		ips->security.ol_flags = sec_cap->ol_flags;
-		ips->security.ctx = sec_ctx;
-		sa->pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
+	if (IS_NATT_UDP_TUNNEL(sa->flags)) {
+		sess_conf.ipsec.options.udp_encap = 1;
 
-		if (IS_IP6(sa->flags)) {
-			sa->pattern[1].mask = &rte_flow_item_ipv6_mask;
-			sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6;
-			sa->pattern[1].spec = &sa->ipv6_spec;
+		sess_conf.ipsec.udp.sport = htons(sa->udp.sport);
+		sess_conf.ipsec.udp.dport = htons(sa->udp.dport);
+	}
 
-			memcpy(sa->ipv6_spec.hdr.dst_addr,
-				sa->dst.ip.ip6.ip6_b, 16);
-			memcpy(sa->ipv6_spec.hdr.src_addr,
-			       sa->src.ip.ip6.ip6_b, 16);
-		} else if (IS_IP4(sa->flags)) {
-			sa->pattern[1].mask = &rte_flow_item_ipv4_mask;
-			sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
-			sa->pattern[1].spec = &sa->ipv4_spec;
-
-			sa->ipv4_spec.hdr.dst_addr = sa->dst.ip.ip4;
-			sa->ipv4_spec.hdr.src_addr = sa->src.ip.ip4;
-		}
+	struct rte_flow_action_security action_security;
+	struct rte_flow_error err;
+
+	RTE_LOG_DP(DEBUG, IPSEC, "Create session for SA spi %u on port %u\n",
+		sa->spi, sa->portid);
+
+	sec_ctx = (struct rte_security_ctx *)
+				rte_eth_dev_get_sec_ctx(sa->portid);
+	if (sec_ctx == NULL) {
+		RTE_LOG(ERR, IPSEC,
+			" rte_eth_dev_get_sec_ctx failed\n");
+		return -1;
+	}
+
+	ips->security.ses = rte_security_session_create(sec_ctx,
+			&sess_conf, skt_ctx->session_pool,
+			skt_ctx->session_priv_pool);
+	if (ips->security.ses == NULL) {
+		RTE_LOG(ERR, IPSEC,
+			"SEC Session init failed: err: %d\n", ret);
+		return -1;
+	}
+
+	ips->security.ctx = sec_ctx;
+
+	sec_cap = rte_security_capabilities_get(sec_ctx);
+
+	ips->security.ol_flags = sec_cap->ol_flags;
+
+	if (sa->direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS)
+		return 0;
+
+	sa->pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
+	sa->pattern[0].spec = NULL;
+
+	if (IS_IP6(sa->flags)) {
+		memcpy(sa->ipv6_spec.hdr.dst_addr,
+			sa->dst.ip.ip6.ip6_b, 16);
+		memcpy(sa->ipv6_spec.hdr.src_addr,
+			sa->src.ip.ip6.ip6_b, 16);
+
+		sa->pattern[1].mask = &rte_flow_item_ipv6_mask;
+		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6;
+		sa->pattern[1].spec = &sa->ipv6_spec;
+
+	} else if (IS_IP4(sa->flags)) {
+		sa->ipv4_spec.hdr.dst_addr = sa->dst.ip.ip4;
+		sa->ipv4_spec.hdr.src_addr = sa->src.ip.ip4;
+
+		sa->pattern[1].mask = &rte_flow_item_ipv4_mask;
+		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
+		sa->pattern[1].spec = &sa->ipv4_spec;
+	}
+
+	if (IS_NATT_UDP_TUNNEL(sa->flags)) {
+
+		sa->udp_spec.hdr.dst_port = rte_cpu_to_be_16(sa->udp.dport);
+		sa->udp_spec.hdr.src_port = rte_cpu_to_be_16(sa->udp.sport);
+
+		sa->pattern[2].mask = &rte_flow_item_udp_mask;
+		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_UDP;
+		sa->pattern[2].spec = &sa->udp_spec;
+
+		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
+
+		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_ESP;
+		sa->pattern[3].spec = &sa->esp_spec;
+		sa->pattern[3].mask = &rte_flow_item_esp_mask;
+
+		sa->pattern[4].type = RTE_FLOW_ITEM_TYPE_END;
+	} else {
+		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
 
 		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
 		sa->pattern[2].spec = &sa->esp_spec;
 		sa->pattern[2].mask = &rte_flow_item_esp_mask;
-		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
 
 		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+	}
 
-		sa->action[0].type = RTE_FLOW_ACTION_TYPE_SECURITY;
-		sa->action[0].conf = ips->security.ses;
-
-		sa->action[1].type = RTE_FLOW_ACTION_TYPE_END;
-
-		sa->attr.egress = (sa->direction ==
-				RTE_SECURITY_IPSEC_SA_DIR_EGRESS);
-		sa->attr.ingress = (sa->direction ==
-				RTE_SECURITY_IPSEC_SA_DIR_INGRESS);
-		if (sa->attr.ingress) {
-			uint8_t rss_key[40];
-			struct rte_eth_rss_conf rss_conf = {
-				.rss_key = rss_key,
-				.rss_key_len = 40,
-			};
-			struct rte_eth_dev_info dev_info;
-			uint16_t queue[RTE_MAX_QUEUES_PER_PORT];
-			struct rte_flow_action_rss action_rss;
-			unsigned int i;
-			unsigned int j;
-
-			/* Don't create flow if default flow is created */
-			if (flow_info_tbl[sa->portid].rx_def_flow)
-				return 0;
-
-			ret = rte_eth_dev_info_get(sa->portid, &dev_info);
-			if (ret != 0) {
-				RTE_LOG(ERR, IPSEC,
-					"Error during getting device (port %u) info: %s\n",
-					sa->portid, strerror(-ret));
-				return ret;
-			}
-
-			sa->action[2].type = RTE_FLOW_ACTION_TYPE_END;
-			/* Try RSS. */
-			sa->action[1].type = RTE_FLOW_ACTION_TYPE_RSS;
-			sa->action[1].conf = &action_rss;
-			ret = rte_eth_dev_rss_hash_conf_get(sa->portid,
-					&rss_conf);
-			if (ret != 0) {
-				RTE_LOG(ERR, IPSEC,
-					"rte_eth_dev_rss_hash_conf_get:ret=%d\n",
-					ret);
-				return -1;
-			}
-			for (i = 0, j = 0; i < dev_info.nb_rx_queues; ++i)
-				queue[j++] = i;
-
-			action_rss = (struct rte_flow_action_rss){
-					.types = rss_conf.rss_hf,
-					.key_len = rss_conf.rss_key_len,
-					.queue_num = j,
-					.key = rss_key,
-					.queue = queue,
-			};
-			ret = rte_flow_validate(sa->portid, &sa->attr,
-						sa->pattern, sa->action,
-						&err);
-			if (!ret)
-				goto flow_create;
-			/* Try Queue. */
-			sa->action[1].type = RTE_FLOW_ACTION_TYPE_QUEUE;
-			sa->action[1].conf =
-				&(struct rte_flow_action_queue){
-				.index = 0,
-			};
-			ret = rte_flow_validate(sa->portid, &sa->attr,
-						sa->pattern, sa->action,
-						&err);
-			/* Try End. */
-			sa->action[1].type = RTE_FLOW_ACTION_TYPE_END;
-			sa->action[1].conf = NULL;
-			ret = rte_flow_validate(sa->portid, &sa->attr,
-						sa->pattern, sa->action,
-						&err);
-			if (ret)
-				goto flow_create_failure;
-		} else if (sa->attr.egress &&
-				(ips->security.ol_flags &
-					RTE_SECURITY_TX_HW_TRAILER_OFFLOAD)) {
-			sa->action[1].type =
-					RTE_FLOW_ACTION_TYPE_PASSTHRU;
-			sa->action[2].type =
-					RTE_FLOW_ACTION_TYPE_END;
-		}
-flow_create:
-		sa->flow = rte_flow_create(sa->portid,
-				&sa->attr, sa->pattern, sa->action, &err);
-		if (sa->flow == NULL) {
-flow_create_failure:
-			RTE_LOG(ERR, IPSEC,
-				"Failed to create ipsec flow msg: %s\n",
-				err.message);
-			return -1;
-		}
-	} else if (ips->type ==	RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL) {
-		const struct rte_security_capability *sec_cap;
+	action_security.security_session = ips->security.ses;
 
-		sec_ctx = (struct rte_security_ctx *)
-				rte_eth_dev_get_sec_ctx(sa->portid);
+	sa->action[0].type = RTE_FLOW_ACTION_TYPE_SECURITY;
+	sa->action[0].conf = &action_security;
 
-		if (sec_ctx == NULL) {
-			RTE_LOG(ERR, IPSEC,
-				"Ethernet device doesn't have security features registered\n");
-			return -1;
-		}
 
-		/* Set IPsec parameters in conf */
-		set_ipsec_conf(sa, &(sess_conf.ipsec));
-
-		/* Save SA as userdata for the security session. When
-		 * the packet is received, this userdata will be
-		 * retrieved using the metadata from the packet.
-		 *
-		 * The PMD is expected to set similar metadata for other
-		 * operations, like rte_eth_event, which are tied to
-		 * security session. In such cases, the userdata could
-		 * be obtained to uniquely identify the security
-		 * parameters denoted.
-		 */
+	sa->action[1].type = RTE_FLOW_ACTION_TYPE_END;
+	sa->action[1].conf = NULL;
 
-		sess_conf.userdata = (void *) sa;
+	sa->attr.egress = (sa->direction ==
+			RTE_SECURITY_IPSEC_SA_DIR_EGRESS);
 
-		ips->security.ses = rte_security_session_create(sec_ctx,
-					&sess_conf, skt_ctx->session_pool,
-					skt_ctx->session_priv_pool);
-		if (ips->security.ses == NULL) {
-			RTE_LOG(ERR, IPSEC,
-				"SEC Session init failed: err: %d\n", ret);
-			return -1;
-		}
+	if (sa->attr.egress)
+		return 0;
 
-		sec_cap = rte_security_capabilities_get(sec_ctx);
-		if (sec_cap == NULL) {
-			RTE_LOG(ERR, IPSEC,
-				"No capabilities registered\n");
-			return -1;
-		}
+	sa->attr.ingress = (sa->direction ==
+			RTE_SECURITY_IPSEC_SA_DIR_INGRESS);
 
-		/* iterate until ESP tunnel*/
-		while (sec_cap->action !=
-				RTE_SECURITY_ACTION_TYPE_NONE) {
-			if (sec_cap->action == ips->type &&
-			    sec_cap->protocol ==
-				RTE_SECURITY_PROTOCOL_IPSEC &&
-			    sec_cap->ipsec.mode ==
-				sess_conf.ipsec.mode &&
-			    sec_cap->ipsec.direction == sa->direction)
-				break;
-			sec_cap++;
-		}
 
-		if (sec_cap->action == RTE_SECURITY_ACTION_TYPE_NONE) {
-			RTE_LOG(ERR, IPSEC,
-				"No suitable security capability found\n");
-			return -1;
-		}
+	ret = rte_flow_validate(sa->portid,
+				&sa->attr,
+				sa->pattern,
+				sa->action,
+				&err);
+	if (ret)
+		goto flow_create_failure;
 
-		ips->security.ol_flags = sec_cap->ol_flags;
-		ips->security.ctx = sec_ctx;
+	sa->flow = rte_flow_create(sa->portid, &sa->attr, sa->pattern,
+					sa->action, &err);
+	if (sa->flow == NULL) {
+flow_create_failure:
+		RTE_LOG(ERR, IPSEC,
+			"Failed to create ipsec flow msg: %s\n",
+			err.message);
+		return -1;
 	}
 
+	sa->cdev_id_qp = 0;
+
 	return 0;
 }
 
@@ -427,23 +361,28 @@ create_ipsec_esp_flow(struct ipsec_sa *sa)
 {
 	int ret = 0;
 	struct rte_flow_error err;
+
 	if (sa->direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) {
 		RTE_LOG(ERR, IPSEC,
 			"No Flow director rule for Egress traffic\n");
 		return -1;
 	}
-	if (sa->flags == TRANSPORT) {
+
+	if (IS_TRANSPORT(sa->flags)) {
 		RTE_LOG(ERR, IPSEC,
 			"No Flow director rule for transport mode\n");
 		return -1;
 	}
+
 	sa->action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
 	sa->pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
 	sa->action[0].conf = &(struct rte_flow_action_queue) {
 				.index = sa->fdir_qid,
 	};
+
 	sa->attr.egress = 0;
 	sa->attr.ingress = 1;
+
 	if (IS_IP6(sa->flags)) {
 		sa->pattern[1].mask = &rte_flow_item_ipv6_mask;
 		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6;
diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
index ae5058de27..b496b4a936 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -122,11 +122,15 @@ struct ipsec_sa {
 	uint16_t flags;
 #define IP4_TUNNEL (1 << 0)
 #define IP6_TUNNEL (1 << 1)
-#define TRANSPORT  (1 << 2)
+#define NATT_UDP_TUNNEL  (1 << 2)
 #define IP4_TRANSPORT (1 << 3)
 #define IP6_TRANSPORT (1 << 4)
 	struct ip_addr src;
 	struct ip_addr dst;
+	struct {
+		uint16_t sport;
+		uint16_t dport;
+	} udp;
 	uint8_t cipher_key[MAX_KEY_SIZE];
 	uint16_t cipher_key_len;
 	uint8_t auth_key[MAX_KEY_SIZE];
@@ -142,7 +146,7 @@ struct ipsec_sa {
 	uint8_t fdir_qid;
 	uint8_t fdir_flag;
 
-#define MAX_RTE_FLOW_PATTERN (4)
+#define MAX_RTE_FLOW_PATTERN (5)
 #define MAX_RTE_FLOW_ACTIONS (3)
 	struct rte_flow_item pattern[MAX_RTE_FLOW_PATTERN];
 	struct rte_flow_action action[MAX_RTE_FLOW_ACTIONS];
@@ -151,6 +155,7 @@ struct ipsec_sa {
 		struct rte_flow_item_ipv4 ipv4_spec;
 		struct rte_flow_item_ipv6 ipv6_spec;
 	};
+	struct rte_flow_item_udp udp_spec;
 	struct rte_flow_item_esp esp_spec;
 	struct rte_flow *flow;
 	struct rte_security_session_conf sess_conf;
@@ -181,18 +186,16 @@ struct ipsec_mbuf_metadata {
 	uint8_t buf[32];
 } __rte_cache_aligned;
 
-#define IS_TRANSPORT(flags) ((flags) & TRANSPORT)
+#define IS_TRANSPORT(flags) ((flags) & (IP4_TRANSPORT | IP6_TRANSPORT))
 
 #define IS_TUNNEL(flags) ((flags) & (IP4_TUNNEL | IP6_TUNNEL))
 
+#define IS_NATT_UDP_TUNNEL(flags) ((flags) & NATT_UDP_TUNNEL)
+
 #define IS_IP4(flags) ((flags) & (IP4_TUNNEL | IP4_TRANSPORT))
 
 #define IS_IP6(flags) ((flags) & (IP6_TUNNEL | IP6_TRANSPORT))
 
-#define IS_IP4_TUNNEL(flags) ((flags) & IP4_TUNNEL)
-
-#define IS_IP6_TUNNEL(flags) ((flags) & IP6_TUNNEL)
-
 /*
  * Macro for getting ipsec_sa flags statuses without version of protocol
  * used for transport (IP4_TRANSPORT and IP6_TRANSPORT flags).
@@ -200,7 +203,7 @@ struct ipsec_mbuf_metadata {
 #define WITHOUT_TRANSPORT_VERSION(flags) \
 		((flags) & (IP4_TUNNEL | \
 			IP6_TUNNEL | \
-			TRANSPORT))
+			(IP4_TRANSPORT | IP6_TRANSPORT)))
 
 struct cdev_qp {
 	uint16_t id;
diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c
index 17a28556c9..d5943f8cdc 100644
--- a/examples/ipsec-secgw/sa.c
+++ b/examples/ipsec-secgw/sa.c
@@ -17,6 +17,7 @@
 #include <rte_byteorder.h>
 #include <rte_errno.h>
 #include <rte_ip.h>
+#include <rte_udp.h>
 #include <rte_random.h>
 #include <rte_ethdev.h>
 #include <rte_malloc.h>
@@ -339,13 +340,28 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 			if (strcmp(tokens[ti], "ipv4-tunnel") == 0) {
 				sa_cnt->nb_v4++;
 				rule->flags = IP4_TUNNEL;
+			} else if (strcmp(tokens[ti], "ipv4-udp-tunnel") == 0) {
+				sa_cnt->nb_v4++;
+				rule->flags = IP4_TUNNEL | NATT_UDP_TUNNEL;
+				rule->udp.sport = 0;
+				rule->udp.dport = 4500;
 			} else if (strcmp(tokens[ti], "ipv6-tunnel") == 0) {
 				sa_cnt->nb_v6++;
 				rule->flags = IP6_TUNNEL;
+			} else if (strcmp(tokens[ti], "ipv6-udp-tunnel") == 0) {
+				sa_cnt->nb_v6++;
+				rule->flags = IP6_TUNNEL | NATT_UDP_TUNNEL;
 			} else if (strcmp(tokens[ti], "transport") == 0) {
 				sa_cnt->nb_v4++;
 				sa_cnt->nb_v6++;
-				rule->flags = TRANSPORT;
+				rule->flags = IP4_TRANSPORT | IP6_TRANSPORT;
+			} else if (strcmp(tokens[ti], "udp-transport") == 0) {
+				sa_cnt->nb_v4++;
+				sa_cnt->nb_v6++;
+				rule->flags = IP4_TRANSPORT | IP6_TRANSPORT |
+						NATT_UDP_TUNNEL;
+				rule->udp.sport = 0;
+				rule->udp.dport = 4500;
 			} else {
 				APP_CHECK(0, status, "unrecognized "
 					"input \"%s\"", tokens[ti]);
@@ -548,7 +564,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 			if (status->status < 0)
 				return;
 
-			if (IS_IP4_TUNNEL(rule->flags)) {
+			if (IS_IP4(rule->flags) && IS_TUNNEL(rule->flags)) {
 				struct in_addr ip;
 
 				APP_CHECK(parse_ipv4_addr(tokens[ti],
@@ -560,7 +576,8 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 					return;
 				rule->src.ip.ip4 = rte_bswap32(
 					(uint32_t)ip.s_addr);
-			} else if (IS_IP6_TUNNEL(rule->flags)) {
+			} else if (IS_IP6(rule->flags) &&
+					IS_TUNNEL(rule->flags)) {
 				struct in6_addr ip;
 
 				APP_CHECK(parse_ipv6_addr(tokens[ti], &ip,
@@ -591,7 +608,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 			if (status->status < 0)
 				return;
 
-			if (IS_IP4_TUNNEL(rule->flags)) {
+			if (IS_IP4(rule->flags) && IS_TUNNEL(rule->flags)) {
 				struct in_addr ip;
 
 				APP_CHECK(parse_ipv4_addr(tokens[ti],
@@ -603,7 +620,8 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 					return;
 				rule->dst.ip.ip4 = rte_bswap32(
 					(uint32_t)ip.s_addr);
-			} else if (IS_IP6_TUNNEL(rule->flags)) {
+			} else if (IS_IP6(rule->flags) &&
+					IS_TUNNEL(rule->flags)) {
 				struct in6_addr ip;
 
 				APP_CHECK(parse_ipv6_addr(tokens[ti], &ip,
@@ -832,19 +850,19 @@ print_one_sa_rule(const struct ipsec_sa *sa, int inbound)
 	const struct rte_ipsec_session *ips;
 	const struct rte_ipsec_session *fallback_ips;
 
-	printf("\tspi_%s(%3u):", inbound?"in":"out", sa->spi);
+	printf("\tspi_%s (%3u):", inbound?"in":"out", sa->spi);
 
 	for (i = 0; i < RTE_DIM(cipher_algos); i++) {
 		if (cipher_algos[i].algo == sa->cipher_algo &&
 				cipher_algos[i].key_len == sa->cipher_key_len) {
-			printf("%s ", cipher_algos[i].keyword);
+			printf(" %s", cipher_algos[i].keyword);
 			break;
 		}
 	}
 
 	for (i = 0; i < RTE_DIM(auth_algos); i++) {
 		if (auth_algos[i].algo == sa->auth_algo) {
-			printf("%s ", auth_algos[i].keyword);
+			printf(" %s", auth_algos[i].keyword);
 			break;
 		}
 	}
@@ -852,23 +870,29 @@ print_one_sa_rule(const struct ipsec_sa *sa, int inbound)
 	for (i = 0; i < RTE_DIM(aead_algos); i++) {
 		if (aead_algos[i].algo == sa->aead_algo &&
 				aead_algos[i].key_len-4 == sa->cipher_key_len) {
-			printf("%s ", aead_algos[i].keyword);
+			printf(" %s ", aead_algos[i].keyword);
 			break;
 		}
 	}
 
-	printf("mode:");
+	printf(", mode:");
+
+	if (IS_IP4(sa->flags) && IS_TUNNEL(sa->flags)) {
 
-	switch (WITHOUT_TRANSPORT_VERSION(sa->flags)) {
-	case IP4_TUNNEL:
-		printf("IP4Tunnel ");
+		if (IS_NATT_UDP_TUNNEL(sa->flags))
+			printf("IP4Tunnel NAT-T (");
+		else
+			printf("IP4Tunnel (");
 		uint32_t_to_char(sa->src.ip.ip4, &a, &b, &c, &d);
 		printf("%hhu.%hhu.%hhu.%hhu ", d, c, b, a);
 		uint32_t_to_char(sa->dst.ip.ip4, &a, &b, &c, &d);
 		printf("%hhu.%hhu.%hhu.%hhu", d, c, b, a);
-		break;
-	case IP6_TUNNEL:
-		printf("IP6Tunnel ");
+	} else if (IS_IP6(sa->flags) && IS_TUNNEL(sa->flags)) {
+
+		if (IS_NATT_UDP_TUNNEL(sa->flags))
+			printf("IP6Tunnel NAT-T (");
+		else
+			printf("IP6Tunnel (");
 		for (i = 0; i < 16; i++) {
 			if (i % 2 && i != 15)
 				printf("%.2x:", sa->src.ip.ip6.ip6_b[i]);
@@ -882,14 +906,15 @@ print_one_sa_rule(const struct ipsec_sa *sa, int inbound)
 			else
 				printf("%.2x", sa->dst.ip.ip6.ip6_b[i]);
 		}
-		break;
-	case TRANSPORT:
-		printf("Transport ");
-		break;
+	} else if (IS_TRANSPORT(sa->flags)) {
+		if (IS_NATT_UDP_TUNNEL(sa->flags))
+			printf("Transport NAT-T (");
+		else
+			printf("Transport (");
 	}
 
 	ips = &sa->sessions[IPSEC_SESSION_PRIMARY];
-	printf(" type:");
+	printf("), type: ");
 	switch (ips->type) {
 	case RTE_SECURITY_ACTION_TYPE_NONE:
 		printf("no-offload ");
@@ -1053,7 +1078,11 @@ sa_add_address_inline_crypto(struct ipsec_sa *sa)
 	protocol = get_spi_proto(sa->spi, sa->direction, ip_addr, mask);
 	if (protocol < 0)
 		return protocol;
-	else if (protocol == IPPROTO_IPIP) {
+
+	/* Clear transport bits before selecting IP4/IP6 */
+	sa->flags &= ~(IP4_TRANSPORT | IP6_TRANSPORT);
+
+	if (protocol == IPPROTO_IPIP) {
 		sa->flags |= IP4_TRANSPORT;
 		if (mask[0] == IP4_FULL_MASK &&
 				mask[1] == IP4_FULL_MASK &&
@@ -1131,12 +1160,7 @@ sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
 				return -EINVAL;
 		}
 
-		switch (WITHOUT_TRANSPORT_VERSION(sa->flags)) {
-		case IP4_TUNNEL:
-			sa->src.ip.ip4 = rte_cpu_to_be_32(sa->src.ip.ip4);
-			sa->dst.ip.ip4 = rte_cpu_to_be_32(sa->dst.ip.ip4);
-			break;
-		case TRANSPORT:
+		if (IS_TRANSPORT(sa->flags)) {
 			if (ips->type ==
 				RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO) {
 				inline_status =
@@ -1144,11 +1168,25 @@ sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
 				if (inline_status < 0)
 					return inline_status;
 			}
-			break;
+		} else if (IS_TUNNEL(sa->flags)) {
+			if (IS_IP4(sa->flags)) {
+				sa->src.ip.ip4 =
+					rte_cpu_to_be_32(sa->src.ip.ip4);
+				sa->dst.ip.ip4 =
+					rte_cpu_to_be_32(sa->dst.ip.ip4);
+			}
+
 		}
 
-		if (sa->aead_algo == RTE_CRYPTO_AEAD_AES_GCM) {
-			iv_length = 12;
+
+		if (sa->aead_algo == RTE_CRYPTO_AEAD_AES_GCM ||
+			sa->aead_algo == RTE_CRYPTO_AEAD_AES_CCM ||
+			sa->aead_algo == RTE_CRYPTO_AEAD_CHACHA20_POLY1305) {
+
+			if (ips->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO)
+				iv_length = 8;
+			else
+				iv_length = 12;
 
 			sa_ctx->xf[idx].a.type = RTE_CRYPTO_SYM_XFORM_AEAD;
 			sa_ctx->xf[idx].a.aead.algo = sa->aead_algo;
@@ -1285,9 +1323,21 @@ fill_ipsec_app_sa_prm(struct rte_ipsec_sa_prm *prm,
 	prm->ipsec_xform.replay_win_sz = app_prm->window_size;
 }
 
+struct udp_ipv4_tunnel {
+	struct rte_ipv4_hdr v4;
+	struct rte_udp_hdr udp;
+} __rte_packed;
+
+struct udp_ipv6_tunnel {
+	struct rte_ipv6_hdr v6;
+	struct rte_udp_hdr udp;
+} __rte_packed;
+
 static int
 fill_ipsec_sa_prm(struct rte_ipsec_sa_prm *prm, const struct ipsec_sa *ss,
-	const struct rte_ipv4_hdr *v4, struct rte_ipv6_hdr *v6)
+	const struct rte_ipv4_hdr *v4, struct rte_ipv6_hdr *v6,
+	const struct udp_ipv4_tunnel *udp_ipv4,
+	const struct udp_ipv6_tunnel *udp_ipv6)
 {
 	int32_t rc;
 
@@ -1311,22 +1361,49 @@ fill_ipsec_sa_prm(struct rte_ipsec_sa_prm *prm, const struct ipsec_sa *ss,
 	prm->ipsec_xform.mode = (IS_TRANSPORT(ss->flags)) ?
 		RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT :
 		RTE_SECURITY_IPSEC_SA_MODE_TUNNEL;
+	prm->ipsec_xform.options.udp_encap =
+			(IS_NATT_UDP_TUNNEL(ss->flags)) ? 1 : 0;
 	prm->ipsec_xform.options.ecn = 1;
 	prm->ipsec_xform.options.copy_dscp = 1;
 
-	if (IS_IP4_TUNNEL(ss->flags)) {
-		prm->ipsec_xform.tunnel.type = RTE_SECURITY_IPSEC_TUNNEL_IPV4;
-		prm->tun.hdr_len = sizeof(*v4);
-		prm->tun.next_proto = rc;
-		prm->tun.hdr = v4;
-	} else if (IS_IP6_TUNNEL(ss->flags)) {
-		prm->ipsec_xform.tunnel.type = RTE_SECURITY_IPSEC_TUNNEL_IPV6;
-		prm->tun.hdr_len = sizeof(*v6);
-		prm->tun.next_proto = rc;
-		prm->tun.hdr = v6;
-	} else {
+	if (IS_TRANSPORT(ss->flags)) {
 		/* transport mode */
 		prm->trs.proto = rc;
+	} else if (IS_TUNNEL(ss->flags)) {
+		prm->tun.hdr_l3_off = 0;
+
+		/* tunnel mode */
+		if (IS_IP4(ss->flags)) {
+			prm->ipsec_xform.tunnel.type =
+					RTE_SECURITY_IPSEC_TUNNEL_IPV4;
+			prm->tun.next_proto = rc;
+			prm->tun.hdr_l3_len = sizeof(*v4);
+
+			if (IS_NATT_UDP_TUNNEL(ss->flags)) {
+				prm->tun.hdr_len = sizeof(*udp_ipv4);
+				prm->tun.hdr = udp_ipv4;
+
+			} else {
+				prm->tun.hdr_len = sizeof(*v4);
+				prm->tun.hdr = v4;
+			}
+
+		} else if (IS_IP6(ss->flags)) {
+			prm->ipsec_xform.tunnel.type =
+					RTE_SECURITY_IPSEC_TUNNEL_IPV6;
+			prm->tun.next_proto = rc;
+			prm->tun.hdr_l3_len = sizeof(*v6);
+
+			if (IS_NATT_UDP_TUNNEL(ss->flags)) {
+
+				prm->tun.hdr_len = sizeof(*udp_ipv6);
+				prm->tun.hdr = udp_ipv6;
+
+			} else {
+				prm->tun.hdr_len = sizeof(*v6);
+				prm->tun.hdr = v6;
+			}
+		}
 	}
 
 	/* setup crypto section */
@@ -1362,25 +1439,66 @@ ipsec_sa_init(struct ipsec_sa *lsa, struct rte_ipsec_sa *sa, uint32_t sa_size)
 	int rc;
 	struct rte_ipsec_sa_prm prm;
 	struct rte_ipsec_session *ips;
-	struct rte_ipv4_hdr v4  = {
-		.version_ihl = IPVERSION << 4 |
-			sizeof(v4) / RTE_IPV4_IHL_MULTIPLIER,
-		.time_to_live = IPDEFTTL,
-		.next_proto_id = IPPROTO_ESP,
-		.src_addr = lsa->src.ip.ip4,
-		.dst_addr = lsa->dst.ip.ip4,
-	};
-	struct rte_ipv6_hdr v6 = {
-		.vtc_flow = htonl(IP6_VERSION << 28),
-		.proto = IPPROTO_ESP,
-	};
-
-	if (IS_IP6_TUNNEL(lsa->flags)) {
-		memcpy(v6.src_addr, lsa->src.ip.ip6.ip6_b, sizeof(v6.src_addr));
-		memcpy(v6.dst_addr, lsa->dst.ip.ip6.ip6_b, sizeof(v6.dst_addr));
+	struct rte_ipv4_hdr v4;
+	struct rte_ipv6_hdr v6;
+	struct udp_ipv4_tunnel udp_ipv4;
+	struct udp_ipv6_tunnel udp_ipv6;
+
+
+	if (IS_TUNNEL(lsa->flags) && IS_NATT_UDP_TUNNEL(lsa->flags)) {
+		if (IS_IP4(lsa->flags)) {
+
+			udp_ipv4.v4.version_ihl = IPVERSION << 4 | sizeof(v4) /
+					RTE_IPV4_IHL_MULTIPLIER;
+			udp_ipv4.v4.time_to_live = IPDEFTTL;
+			udp_ipv4.v4.next_proto_id = IPPROTO_UDP;
+			udp_ipv4.v4.src_addr = lsa->src.ip.ip4;
+			udp_ipv4.v4.dst_addr = lsa->dst.ip.ip4;
+
+			udp_ipv4.udp.src_port =
+					rte_cpu_to_be_16(lsa->udp.sport);
+			udp_ipv4.udp.dst_port =
+					rte_cpu_to_be_16(lsa->udp.dport);
+
+		} else if (IS_IP6(lsa->flags)) {
+
+			udp_ipv6.v6.vtc_flow = htonl(IP6_VERSION << 28),
+			udp_ipv6.v6.proto = IPPROTO_UDP,
+			memcpy(udp_ipv6.v6.src_addr, lsa->src.ip.ip6.ip6_b,
+					sizeof(udp_ipv6.v6.src_addr));
+			memcpy(udp_ipv6.v6.dst_addr, lsa->dst.ip.ip6.ip6_b,
+					sizeof(udp_ipv6.v6.dst_addr));
+
+			udp_ipv6.udp.src_port =
+					rte_cpu_to_be_16(lsa->udp.sport);
+			udp_ipv6.udp.dst_port =
+					rte_cpu_to_be_16(lsa->udp.dport);
+		}
+
+	} else if (IS_TUNNEL(lsa->flags)) {
+
+		if (IS_IP4(lsa->flags)) {
+			v4.version_ihl = IPVERSION << 4 | sizeof(v4) /
+					RTE_IPV4_IHL_MULTIPLIER;
+			v4.time_to_live = IPDEFTTL;
+			v4.next_proto_id = IPPROTO_ESP;
+			v4.src_addr = lsa->src.ip.ip4;
+			v4.dst_addr = lsa->dst.ip.ip4;
+
+		} else if (IS_IP6(lsa->flags)) {
+
+			v6.vtc_flow = htonl(IP6_VERSION << 28),
+			v6.proto = IPPROTO_ESP,
+			memcpy(v6.src_addr, lsa->src.ip.ip6.ip6_b,
+					sizeof(v6.src_addr));
+			memcpy(v6.dst_addr, lsa->dst.ip.ip6.ip6_b,
+					sizeof(v6.dst_addr));
+
+		}
+
 	}
 
-	rc = fill_ipsec_sa_prm(&prm, lsa, &v4, &v6);
+	rc = fill_ipsec_sa_prm(&prm, lsa, &v4, &v6, &udp_ipv4, &udp_ipv6);
 	if (rc == 0)
 		rc = rte_ipsec_sa_init(sa, &prm, sa_size);
 	if (rc < 0)
@@ -1415,7 +1533,7 @@ ipsec_satbl_init(struct sa_ctx *ctx, uint32_t nb_ent, int32_t socket)
 
 	/* determine SA size */
 	idx = 0;
-	fill_ipsec_sa_prm(&prm, ctx->sa + idx, NULL, NULL);
+	fill_ipsec_sa_prm(&prm, ctx->sa + idx, NULL, NULL, NULL, NULL);
 	sz = rte_ipsec_sa_size(&prm);
 	if (sz < 0) {
 		RTE_LOG(ERR, IPSEC, "%s(%p, %u, %d): "
diff --git a/examples/ipsec-secgw/sad.c b/examples/ipsec-secgw/sad.c
index 5b2c0e6792..191fc79faf 100644
--- a/examples/ipsec-secgw/sad.c
+++ b/examples/ipsec-secgw/sad.c
@@ -25,8 +25,8 @@ ipsec_sad_add(struct ipsec_sad *sad, struct ipsec_sa *sa)
 	/* spi field is common for ipv4 and ipv6 key types */
 	key.v4.spi = rte_cpu_to_be_32(sa->spi);
 	lookup_key[0] = &key;
-	switch (WITHOUT_TRANSPORT_VERSION(sa->flags)) {
-	case IP4_TUNNEL:
+
+	if (IS_IP4(sa->flags) && IS_TUNNEL(sa->flags)) {
 		rte_ipsec_sad_lookup(sad->sad_v4, lookup_key, &tmp, 1);
 		if (tmp != NULL)
 			return -EEXIST;
@@ -35,8 +35,7 @@ ipsec_sad_add(struct ipsec_sad *sad, struct ipsec_sa *sa)
 			RTE_IPSEC_SAD_SPI_ONLY, sa);
 		if (ret != 0)
 			return ret;
-		break;
-	case IP6_TUNNEL:
+	} else if (IS_IP6(sa->flags) && IS_TUNNEL(sa->flags)) {
 		rte_ipsec_sad_lookup(sad->sad_v6, lookup_key, &tmp, 1);
 		if (tmp != NULL)
 			return -EEXIST;
@@ -45,8 +44,7 @@ ipsec_sad_add(struct ipsec_sad *sad, struct ipsec_sa *sa)
 			RTE_IPSEC_SAD_SPI_ONLY, sa);
 		if (ret != 0)
 			return ret;
-		break;
-	case TRANSPORT:
+	} else if (IS_TRANSPORT(sa->flags)) {
 		if (sp4_spi_present(sa->spi, 1, NULL, NULL) >= 0) {
 			rte_ipsec_sad_lookup(sad->sad_v4, lookup_key, &tmp, 1);
 			if (tmp != NULL)
diff --git a/examples/ipsec-secgw/sad.h b/examples/ipsec-secgw/sad.h
index 3224b6252c..6813a47942 100644
--- a/examples/ipsec-secgw/sad.h
+++ b/examples/ipsec-secgw/sad.h
@@ -29,16 +29,16 @@ static inline int
 cmp_sa_key(struct ipsec_sa *sa, int is_v4, struct rte_ipv4_hdr *ipv4,
 	struct rte_ipv6_hdr *ipv6)
 {
-	int sa_type = WITHOUT_TRANSPORT_VERSION(sa->flags);
-	if ((sa_type == TRANSPORT) ||
-			/* IPv4 check */
-			(is_v4 && (sa_type == IP4_TUNNEL) &&
-			(sa->src.ip.ip4 == ipv4->src_addr) &&
-			(sa->dst.ip.ip4 == ipv4->dst_addr)) ||
-			/* IPv6 check */
-			(!is_v4 && (sa_type == IP6_TUNNEL) &&
-			(!memcmp(sa->src.ip.ip6.ip6, ipv6->src_addr, 16)) &&
-			(!memcmp(sa->dst.ip.ip6.ip6, ipv6->dst_addr, 16))))
+
+	if (IS_TRANSPORT(sa->flags) ||
+		/* IPv4 check */
+		(is_v4 && IS_IP4(sa->flags) &&
+		(sa->src.ip.ip4 == ipv4->src_addr) &&
+		(sa->dst.ip.ip4 == ipv4->dst_addr)) ||
+		/* IPv6 check */
+		(!is_v4 && IS_IP6(sa->flags) &&
+		(!memcmp(sa->src.ip.ip6.ip6, ipv6->src_addr, 16)) &&
+		(!memcmp(sa->dst.ip.ip6.ip6, ipv6->dst_addr, 16))))
 		return 1;
 
 	return 0;
