diff --git a/doc/guides/rel_notes/release_18_11.rst b/doc/guides/rel_notes/release_18_11.rst
index 1348fab06..7e405e5b9 100644
--- a/doc/guides/rel_notes/release_18_11.rst
+++ b/doc/guides/rel_notes/release_18_11.rst
@@ -81,7 +81,8 @@ New Features
   * Match items: destination MAC address.
   * Action items: push/pop/rewrite vlan header,
     rewrite IP addresses in outermost IPv4/IPv6 header,
-    rewrite port numbers in outermost TCP/UDP header.
+    rewrite port numbers in outermost TCP/UDP header,
+    swap MAC addresses in outermost Ethernet header.
 
 * **Added a devarg to use the latest supported vector path in i40e.**
   A new devarg ``use-latest-supported-vec`` was introduced to allow users to
diff --git a/drivers/net/cxgbe/base/t4_msg.h b/drivers/net/cxgbe/base/t4_msg.h
index 6494f1827..9e052b0f0 100644
--- a/drivers/net/cxgbe/base/t4_msg.h
+++ b/drivers/net/cxgbe/base/t4_msg.h
@@ -163,6 +163,9 @@ struct work_request_hdr {
 #define S_CCTRL_ECN    27
 #define V_CCTRL_ECN(x) ((x) << S_CCTRL_ECN)
 
+#define S_SACK_EN    30
+#define V_SACK_EN(x) ((x) << S_SACK_EN)
+
 #define S_T5_OPT_2_VALID    31
 #define V_T5_OPT_2_VALID(x) ((x) << S_T5_OPT_2_VALID)
 #define F_T5_OPT_2_VALID    V_T5_OPT_2_VALID(1U)
diff --git a/drivers/net/cxgbe/base/t4fw_interface.h b/drivers/net/cxgbe/base/t4fw_interface.h
index b4c95c588..06d3ef3a6 100644
--- a/drivers/net/cxgbe/base/t4fw_interface.h
+++ b/drivers/net/cxgbe/base/t4fw_interface.h
@@ -314,6 +314,9 @@ struct fw_filter2_wr {
 #define S_FW_FILTER_WR_MATCHTYPEM	0
 #define V_FW_FILTER_WR_MATCHTYPEM(x)	((x) << S_FW_FILTER_WR_MATCHTYPEM)
 
+#define S_FW_FILTER2_WR_SWAPMAC		0
+#define V_FW_FILTER2_WR_SWAPMAC(x)	((x) << S_FW_FILTER2_WR_SWAPMAC)
+
 #define S_FW_FILTER2_WR_NATMODE		5
 #define V_FW_FILTER2_WR_NATMODE(x)	((x) << S_FW_FILTER2_WR_NATMODE)
 
diff --git a/drivers/net/cxgbe/cxgbe_filter.c b/drivers/net/cxgbe/cxgbe_filter.c
index b876abf43..ef1102be3 100644
--- a/drivers/net/cxgbe/cxgbe_filter.c
+++ b/drivers/net/cxgbe/cxgbe_filter.c
@@ -92,6 +92,9 @@ int validate_filter(struct adapter *adapter, struct ch_filter_specification *fs)
 	if (!fs->cap && fs->nat_mode && !adapter->params.filter2_wr_support)
 		return -EOPNOTSUPP;
 
+	if (!fs->cap && fs->swapmac && !adapter->params.filter2_wr_support)
+		return -EOPNOTSUPP;
+
 	return 0;
 }
 
@@ -456,6 +459,7 @@ static void mk_act_open_req6(struct filter_entry *f, struct rte_mbuf *mbuf,
 			    V_RSS_QUEUE(f->fs.iq) |
 			    F_T5_OPT_2_VALID |
 			    F_RX_CHANNEL |
+			    V_SACK_EN(f->fs.swapmac) |
 			    V_CONG_CNTRL((f->fs.action == FILTER_DROP) |
 					 (f->fs.dirsteer << 1)) |
 			    V_CCTRL_ECN(f->fs.action == FILTER_SWITCH));
@@ -502,6 +506,7 @@ static void mk_act_open_req(struct filter_entry *f, struct rte_mbuf *mbuf,
 			    V_RSS_QUEUE(f->fs.iq) |
 			    F_T5_OPT_2_VALID |
 			    F_RX_CHANNEL |
+			    V_SACK_EN(f->fs.swapmac) |
 			    V_CONG_CNTRL((f->fs.action == FILTER_DROP) |
 					 (f->fs.dirsteer << 1)) |
 			    V_CCTRL_ECN(f->fs.action == FILTER_SWITCH));
@@ -773,9 +778,13 @@ int set_filter_wr(struct rte_eth_dev *dev, unsigned int fidx)
 	fwr->fp = cpu_to_be16(f->fs.val.fport);
 	fwr->fpm = cpu_to_be16(f->fs.mask.fport);
 
-	if (adapter->params.filter2_wr_support && f->fs.nat_mode) {
+	if (adapter->params.filter2_wr_support) {
+		fwr->filter_type_swapmac =
+			 V_FW_FILTER2_WR_SWAPMAC(f->fs.swapmac);
 		fwr->natmode_to_ulp_type =
-			V_FW_FILTER2_WR_ULP_TYPE(ULP_MODE_TCPDDP) |
+			V_FW_FILTER2_WR_ULP_TYPE(f->fs.nat_mode ?
+						 ULP_MODE_TCPDDP :
+						 ULP_MODE_NONE) |
 			V_FW_FILTER2_WR_NATMODE(f->fs.nat_mode);
 		memcpy(fwr->newlip, f->fs.nat_lip, sizeof(fwr->newlip));
 		memcpy(fwr->newfip, f->fs.nat_fip, sizeof(fwr->newfip));
diff --git a/drivers/net/cxgbe/cxgbe_filter.h b/drivers/net/cxgbe/cxgbe_filter.h
index 950fa0bca..b7bcbf56a 100644
--- a/drivers/net/cxgbe/cxgbe_filter.h
+++ b/drivers/net/cxgbe/cxgbe_filter.h
@@ -100,6 +100,7 @@ struct ch_filter_specification {
 	uint32_t iq:10;		/* ingress queue */
 
 	uint32_t eport:2;	/* egress port to switch packet out */
+	uint32_t swapmac:1;     /* swap SMAC/DMAC for loopback packet */
 	uint32_t newvlan:2;     /* rewrite VLAN Tag */
 	uint8_t dmac[ETHER_ADDR_LEN];   /* new destination MAC address */
 	uint16_t vlan;          /* VLAN Tag to insert */
diff --git a/drivers/net/cxgbe/cxgbe_flow.c b/drivers/net/cxgbe/cxgbe_flow.c
index 3e4acf333..ccd165b56 100644
--- a/drivers/net/cxgbe/cxgbe_flow.c
+++ b/drivers/net/cxgbe/cxgbe_flow.c
@@ -552,6 +552,16 @@ ch_rte_parse_atype_switch(const struct rte_flow_action *a,
 		fs->nat_lport = be16_to_cpu(tp_port->port);
 		*nmode |= 1 << 3;
 		break;
+	case RTE_FLOW_ACTION_TYPE_MAC_SWAP:
+		item_index = cxgbe_get_flow_item_index(items,
+						       RTE_FLOW_ITEM_TYPE_ETH);
+		if (item_index < 0)
+			return rte_flow_error_set(e, EINVAL,
+						  RTE_FLOW_ERROR_TYPE_ACTION, a,
+						  "No RTE_FLOW_ITEM_TYPE_ETH "
+						  "found");
+		fs->swapmac = 1;
+		break;
 	default:
 		/* We are not supposed to come here */
 		return rte_flow_error_set(e, EINVAL,
@@ -611,6 +621,7 @@ cxgbe_rtef_parse_actions(struct rte_flow *flow,
 		case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:
 		case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN:
 		case RTE_FLOW_ACTION_TYPE_PHY_PORT:
+		case RTE_FLOW_ACTION_TYPE_MAC_SWAP:
 		case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC:
 		case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST:
 			nat_ipv4++;
