[PATCH 2/2] net/sfc: support updating indirect VXLAN encap action

Ivan Malov ivan.malov at arknetworks.am
Thu Aug 10 20:06:56 CEST 2023


Such updates are helpful as they let applications avoid
costly flow re-insertions when the header data changes.

Signed-off-by: Ivan Malov <ivan.malov at arknetworks.am>
Reviewed-by: Andy Moreton <andy.moreton at amd.com>
---
 drivers/common/sfc_efx/base/efx.h     |  9 +++
 drivers/common/sfc_efx/base/efx_mae.c | 80 ++++++++++++++++++++++++
 drivers/common/sfc_efx/version.map    |  1 +
 drivers/net/sfc/sfc_flow.c            | 35 +++++++++++
 drivers/net/sfc/sfc_mae.c             | 88 +++++++++++++++++++++++++++
 drivers/net/sfc/sfc_mae.h             |  5 ++
 6 files changed, 218 insertions(+)

diff --git a/drivers/common/sfc_efx/base/efx.h b/drivers/common/sfc_efx/base/efx.h
index efefea717f..b4d8cfe9d8 100644
--- a/drivers/common/sfc_efx/base/efx.h
+++ b/drivers/common/sfc_efx/base/efx.h
@@ -4811,6 +4811,15 @@ efx_mae_encap_header_alloc(
 	__in				size_t header_size,
 	__out				efx_mae_eh_id_t *eh_idp);
 
+LIBEFX_API
+extern	__checkReturn			efx_rc_t
+efx_mae_encap_header_update(
+	__in				efx_nic_t *enp,
+	__in				efx_mae_eh_id_t *eh_idp,
+	__in				efx_tunnel_protocol_t encap_type,
+	__in_bcount(header_size)	const uint8_t *header_data,
+	__in				size_t header_size);
+
 LIBEFX_API
 extern	__checkReturn			efx_rc_t
 efx_mae_encap_header_free(
diff --git a/drivers/common/sfc_efx/base/efx_mae.c b/drivers/common/sfc_efx/base/efx_mae.c
index d36cdc71be..0d7b24d351 100644
--- a/drivers/common/sfc_efx/base/efx_mae.c
+++ b/drivers/common/sfc_efx/base/efx_mae.c
@@ -2937,6 +2937,86 @@ efx_mae_encap_header_alloc(
 	EFSYS_PROBE(fail6);
 fail5:
 	EFSYS_PROBE(fail5);
+fail4:
+	EFSYS_PROBE(fail4);
+fail3:
+	EFSYS_PROBE(fail3);
+fail2:
+	EFSYS_PROBE(fail2);
+fail1:
+	EFSYS_PROBE1(fail1, efx_rc_t, rc);
+	return (rc);
+}
+
+	__checkReturn			efx_rc_t
+efx_mae_encap_header_update(
+	__in				efx_nic_t *enp,
+	__in				efx_mae_eh_id_t *eh_idp,
+	__in				efx_tunnel_protocol_t encap_type,
+	__in_bcount(header_size)	const uint8_t *header_data,
+	__in				size_t header_size)
+{
+	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
+	efx_mcdi_req_t req;
+	EFX_MCDI_DECLARE_BUF(payload,
+	    MC_CMD_MAE_ENCAP_HEADER_UPDATE_IN_LENMAX_MCDI2,
+	    MC_CMD_MAE_ENCAP_HEADER_UPDATE_OUT_LEN);
+	uint32_t encap_type_mcdi;
+	efx_rc_t rc;
+
+	if (encp->enc_mae_supported == B_FALSE) {
+		rc = ENOTSUP;
+		goto fail1;
+	}
+
+	switch (encap_type) {
+	case EFX_TUNNEL_PROTOCOL_NONE:
+		encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NONE;
+		break;
+	case EFX_TUNNEL_PROTOCOL_VXLAN:
+		encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_VXLAN;
+		break;
+	case EFX_TUNNEL_PROTOCOL_GENEVE:
+		encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_GENEVE;
+		break;
+	case EFX_TUNNEL_PROTOCOL_NVGRE:
+		encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NVGRE;
+		break;
+	default:
+		rc = ENOTSUP;
+		goto fail2;
+	}
+
+	if (header_size >
+	   MC_CMD_MAE_ENCAP_HEADER_UPDATE_IN_HDR_DATA_MAXNUM_MCDI2) {
+		rc = EINVAL;
+		goto fail3;
+	}
+
+	req.emr_cmd = MC_CMD_MAE_ENCAP_HEADER_UPDATE;
+	req.emr_in_buf = payload;
+	req.emr_in_length = MC_CMD_MAE_ENCAP_HEADER_UPDATE_IN_LEN(header_size);
+	req.emr_out_buf = payload;
+	req.emr_out_length = MC_CMD_MAE_ENCAP_HEADER_UPDATE_OUT_LEN;
+
+	MCDI_IN_SET_DWORD(req,
+	    MAE_ENCAP_HEADER_UPDATE_IN_EH_ID, eh_idp->id);
+
+	MCDI_IN_SET_DWORD(req,
+	    MAE_ENCAP_HEADER_UPDATE_IN_ENCAP_TYPE, encap_type_mcdi);
+
+	memcpy(MCDI_IN2(req, uint8_t, MAE_ENCAP_HEADER_UPDATE_IN_HDR_DATA),
+	    header_data, header_size);
+
+	efx_mcdi_execute(enp, &req);
+
+	if (req.emr_rc != 0) {
+		rc = req.emr_rc;
+		goto fail4;
+	}
+
+	return (0);
+
 fail4:
 	EFSYS_PROBE(fail4);
 fail3:
diff --git a/drivers/common/sfc_efx/version.map b/drivers/common/sfc_efx/version.map
index 40c97ad2b4..43e8e52ab9 100644
--- a/drivers/common/sfc_efx/version.map
+++ b/drivers/common/sfc_efx/version.map
@@ -123,6 +123,7 @@ INTERNAL {
 	efx_mae_counters_stream_stop;
 	efx_mae_encap_header_alloc;
 	efx_mae_encap_header_free;
+	efx_mae_encap_header_update;
 	efx_mae_fini;
 	efx_mae_get_limits;
 	efx_mae_init;
diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c
index a35f20770d..1b50aefe5c 100644
--- a/drivers/net/sfc/sfc_flow.c
+++ b/drivers/net/sfc/sfc_flow.c
@@ -2864,6 +2864,40 @@ sfc_flow_action_handle_destroy(struct rte_eth_dev *dev,
 	return rc;
 }
 
+static int
+sfc_flow_action_handle_update(struct rte_eth_dev *dev,
+			      struct rte_flow_action_handle *handle,
+			      const void *update, struct rte_flow_error *error)
+{
+	struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
+	struct rte_flow_action_handle *entry;
+	int rc = EINVAL;
+
+	sfc_adapter_lock(sa);
+
+	TAILQ_FOREACH(entry, &sa->flow_indir_actions, entries) {
+		if (entry != handle)
+			continue;
+
+		if (entry->transfer) {
+			rc = sfc_mae_indir_action_update(sa, handle,
+							 update, error);
+		} else {
+			SFC_ASSERT(B_FALSE);
+		}
+
+		goto exit;
+	}
+
+	rc = rte_flow_error_set(error, ENOENT,
+				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+				"indirect action handle not found");
+
+exit:
+	sfc_adapter_unlock(sa);
+	return rc;
+}
+
 static int
 sfc_flow_action_handle_query(struct rte_eth_dev *dev,
 			     const struct rte_flow_action_handle *handle,
@@ -2907,6 +2941,7 @@ const struct rte_flow_ops sfc_flow_ops = {
 	.isolate = sfc_flow_isolate,
 	.action_handle_create = sfc_flow_action_handle_create,
 	.action_handle_destroy = sfc_flow_action_handle_destroy,
+	.action_handle_update = sfc_flow_action_handle_update,
 	.action_handle_query = sfc_flow_action_handle_query,
 	.tunnel_decap_set = sfc_ft_decap_set,
 	.tunnel_match = sfc_ft_match,
diff --git a/drivers/net/sfc/sfc_mae.c b/drivers/net/sfc/sfc_mae.c
index 45a66307d2..2bfb918275 100644
--- a/drivers/net/sfc/sfc_mae.c
+++ b/drivers/net/sfc/sfc_mae.c
@@ -749,6 +749,50 @@ sfc_mae_encap_header_del(struct sfc_adapter *sa,
 	sfc_dbg(sa, "deleted encap_header=%p", encap_header);
 }
 
+static int
+sfc_mae_encap_header_update(struct sfc_adapter *sa,
+			    struct sfc_mae_encap_header *encap_header)
+{
+	const struct sfc_mae_bounce_eh *bounce_eh = &sa->mae.bounce_eh;
+	struct sfc_mae_fw_rsrc *fw_rsrc;
+	uint8_t *buf;
+	int ret;
+
+	if (bounce_eh->type != encap_header->type ||
+	    bounce_eh->size == 0)
+		return EINVAL;
+
+	buf = rte_malloc("sfc_mae_encap_header_buf", bounce_eh->size, 0);
+	if (buf == NULL)
+		return ENOMEM;
+
+	rte_memcpy(buf, bounce_eh->buf, bounce_eh->size);
+
+	fw_rsrc = &encap_header->fw_rsrc;
+
+	if (fw_rsrc->refcnt > 0) {
+		SFC_ASSERT(fw_rsrc->eh_id.id != EFX_MAE_RSRC_ID_INVALID);
+
+		ret = efx_mae_encap_header_update(sa->nic, &fw_rsrc->eh_id,
+						  encap_header->type, buf,
+						  bounce_eh->size);
+		if (ret != 0) {
+			sfc_err(sa, "failed to update encap_header=%p: %s",
+				encap_header, strerror(ret));
+			rte_free(buf);
+			return ret;
+		}
+	}
+
+	encap_header->size = bounce_eh->size;
+	rte_free(encap_header->buf);
+	encap_header->buf = buf;
+
+	sfc_dbg(sa, "updated encap_header=%p", encap_header);
+
+	return 0;
+}
+
 static int
 sfc_mae_encap_header_enable(struct sfc_adapter *sa,
 			    struct sfc_mae_encap_header *encap_header,
@@ -5288,6 +5332,50 @@ sfc_mae_indir_action_destroy(struct sfc_adapter *sa,
 				  NULL, "indirect action is still in use");
 }
 
+int
+sfc_mae_indir_action_update(struct sfc_adapter *sa,
+			    struct rte_flow_action_handle *handle,
+			    const void *update, struct rte_flow_error *error)
+{
+	const struct rte_flow_action *action = update;
+	struct sfc_mae *mae = &sa->mae;
+	bool custom_error = false;
+	int ret;
+
+	SFC_ASSERT(sfc_adapter_is_locked(sa));
+	SFC_ASSERT(action != NULL);
+	SFC_ASSERT(handle != NULL);
+
+	switch (handle->type) {
+	case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
+		/* Cleanup after previous encap. header bounce buffer usage. */
+		sfc_mae_bounce_eh_invalidate(&mae->bounce_eh);
+
+		ret = sfc_mae_rule_parse_action_vxlan_encap(mae, action->conf,
+							    NULL, error);
+		if (ret != 0) {
+			custom_error = true;
+			break;
+		}
+
+		ret = sfc_mae_encap_header_update(sa, handle->encap_header);
+		break;
+	default:
+		ret = ENOTSUP;
+	}
+
+	if (custom_error)
+		return ret;
+
+	if (ret != 0) {
+		return rte_flow_error_set(error, ret,
+				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+				"failed to parse indirect action to mae object");
+	}
+
+	return 0;
+}
+
 int
 sfc_mae_indir_action_query(struct sfc_adapter *sa,
 			   const struct rte_flow_action_handle *handle,
diff --git a/drivers/net/sfc/sfc_mae.h b/drivers/net/sfc/sfc_mae.h
index 4b928f876b..7f4c3324bd 100644
--- a/drivers/net/sfc/sfc_mae.h
+++ b/drivers/net/sfc/sfc_mae.h
@@ -422,6 +422,11 @@ int sfc_mae_indir_action_destroy(struct sfc_adapter *sa,
 				 const struct rte_flow_action_handle *handle,
 				 struct rte_flow_error *error);
 
+int sfc_mae_indir_action_update(struct sfc_adapter *sa,
+				struct rte_flow_action_handle *handle,
+				const void *update,
+				struct rte_flow_error *error);
+
 int sfc_mae_indir_action_query(struct sfc_adapter *sa,
 			       const struct rte_flow_action_handle *handle,
 			       void *data, struct rte_flow_error *error);
-- 
2.31.1



More information about the dev mailing list