+/**
+ * Get the sub policy of a meter.
+ *
+ * @param[in] dev
+ * Pointer to Ethernet device.
+ * @param[in] flow
+ * Parent flow structure pointer.
+ * @param[in] policy_id;
+ * Meter Policy id.
+ * @param[in] attr
+ * Flow rule attributes.
+ * @param[in] items
+ * Pattern specification (list terminated by the END pattern item).
+ * @param[out] error
+ * Perform verbose error reporting if not NULL.
+ *
+ * @return
+ * Pointer to the meter sub policy, NULL otherwise and rte_errno is set.
+ */
+static struct mlx5_flow_meter_sub_policy *
+get_meter_sub_policy(struct rte_eth_dev *dev,
+ struct rte_flow *flow,
+ uint32_t policy_id,
+ const struct rte_flow_attr *attr,
+ const struct rte_flow_item items[],
+ struct rte_flow_error *error)
+{
+ struct mlx5_flow_meter_policy *policy;
+ struct mlx5_flow_meter_sub_policy *sub_policy = NULL;
+
+ policy = mlx5_flow_meter_policy_find(dev, policy_id, NULL);
+ if (!policy) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+ "Failed to find Meter Policy.");
+ goto exit;
+ }
+ if (policy->is_rss ||
+ (policy->is_queue &&
+ !policy->sub_policys[MLX5_MTR_DOMAIN_INGRESS][0]->rix_hrxq[0])) {
+ struct mlx5_flow_workspace *wks =
+ mlx5_flow_get_thread_workspace();
+ struct mlx5_flow_rss_desc rss_desc_v[MLX5_MTR_RTE_COLORS];
+ struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS] = {0};
+ uint32_t i;
+
+ MLX5_ASSERT(wks);
+ /**
+ * This is a tmp dev_flow,
+ * no need to register any matcher for it in translate.
+ */
+ wks->skip_matcher_reg = 1;
+ for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
+ struct mlx5_flow dev_flow = {0};
+ struct mlx5_flow_handle dev_handle = { {0} };
+
+ rss_desc_v[i] = wks->rss_desc;
+ if (policy->is_rss) {
+ const void *rss_act =
+ policy->act_cnt[i].rss->conf;
+ struct rte_flow_action rss_actions[2] = {
+ [0] = {
+ .type = RTE_FLOW_ACTION_TYPE_RSS,
+ .conf = rss_act
+ },
+ [1] = {
+ .type = RTE_FLOW_ACTION_TYPE_END,
+ .conf = NULL
+ }
+ };
+
+ dev_flow.handle = &dev_handle;
+ dev_flow.ingress = attr->ingress;
+ dev_flow.flow = flow;
+ dev_flow.external = 0;
+#ifdef HAVE_IBV_FLOW_DV_SUPPORT
+ dev_flow.dv.transfer = attr->transfer;
+#endif
+ /**
+ * Translate RSS action to get rss hash fields.
+ */
+ if (flow_drv_translate(dev, &dev_flow, attr,
+ items, rss_actions, error))
+ goto exit;
+ rss_desc_v[i].key_len = MLX5_RSS_HASH_KEY_LEN;
+ rss_desc_v[i].hash_fields =
+ dev_flow.hash_fields;
+ rss_desc_v[i].queue_num =
+ rss_desc_v[i].hash_fields ?
+ rss_desc_v[i].queue_num : 1;
+ } else {
+ /* This is queue action. */
+ rss_desc_v[i].key_len = 0;
+ rss_desc_v[i].hash_fields = 0;
+ rss_desc_v[i].queue =
+ &policy->act_cnt[i].queue;
+ rss_desc_v[i].queue_num = 1;
+ }
+ rss_desc[i] = &rss_desc_v[i];
+ }
+ sub_policy = flow_drv_meter_sub_policy_rss_prepare(dev,
+ flow, policy, rss_desc);
+ } else {
+ enum mlx5_meter_domain mtr_domain =
+ attr->transfer ? MLX5_MTR_DOMAIN_TRANSFER :
+ attr->egress ? MLX5_MTR_DOMAIN_EGRESS :
+ MLX5_MTR_DOMAIN_INGRESS;
+ sub_policy = policy->sub_policys[mtr_domain][0];
+ }
+ if (!sub_policy) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+ "Failed to get meter sub-policy.");
+ goto exit;
+ }
+exit:
+ return sub_policy;
+}
+