+/**
+ * create a flow rule that sends packets with matching pc_id
+ * to selected queue.
+ *
+ * @param port_id
+ * The selected port.
+ * @param rx_q
+ * The selected target queue.
+ * @param pc_id_be
+ * The value to apply to the pc_id.
+ * @param[out] error
+ * Perform verbose error reporting if not NULL.
+ *
+ * @return
+ * A flow if the rule could be created else return NULL.
+ */
+struct rte_flow *
+generate_ecpri_flow(uint16_t port_id, uint16_t rx_q, uint16_t pc_id_be, struct rte_flow_error *error)
+{
+ struct rte_flow *flow = NULL;
+#if (RTE_VER_YEAR >= 21)
+#define MAX_PATTERN_NUM 3
+#define MAX_ACTION_NUM 2
+ struct rte_flow_attr attr;
+ struct rte_flow_item pattern[MAX_PATTERN_NUM];
+ struct rte_flow_action action[MAX_ACTION_NUM];
+
+ struct rte_flow_action_queue queue = { .index = rx_q };
+ struct rte_flow_item_ecpri ecpri_spec;
+ struct rte_flow_item_ecpri ecpri_mask;
+
+ int res;
+ print_dbg("%s\n", __FUNCTION__);
+ memset(pattern, 0, sizeof(pattern));
+ memset(action, 0, sizeof(action));
+
+ /*
+ * set the rule attribute.
+ * in this case only ingress packets will be checked.
+ */
+ memset(&attr, 0, sizeof(struct rte_flow_attr));
+ attr.ingress = 1;
+
+ /*
+ * create the action sequence.
+ * one action only, move packet to queue
+ */
+ action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
+ action[0].conf = &queue;
+ action[1].type = RTE_FLOW_ACTION_TYPE_END;
+
+ /*
+ * set the first level of the pattern (ETH).
+ * since in this example we just want to get the
+ * eCPRI we set this level to allow all.
+ */
+ pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
+
+ memset(&ecpri_spec, 0, sizeof(struct rte_flow_item_ecpri));
+ memset(&ecpri_mask, 0, sizeof(struct rte_flow_item_ecpri));
+
+ ecpri_spec.hdr.common.type = RTE_ECPRI_MSG_TYPE_IQ_DATA;
+ ecpri_spec.hdr.type0.pc_id = pc_id_be;
+
+ ecpri_mask.hdr.common.type = 0xff;
+ ecpri_mask.hdr.type0.pc_id = 0xffff;
+
+ ecpri_spec.hdr.common.u32 = rte_cpu_to_be_32(ecpri_spec.hdr.common.u32);
+
+ pattern[1].type = RTE_FLOW_ITEM_TYPE_ECPRI;
+ pattern[1].spec = &ecpri_spec;
+ pattern[1].mask = &ecpri_mask;
+
+ struct rte_flow_item_ecpri *pecpri_spec = (struct rte_flow_item_ecpri *)pattern[1].spec;
+ struct rte_flow_item_ecpri *pecpri_mask = (struct rte_flow_item_ecpri *)pattern[1].mask;
+ print_dbg("RTE_FLOW_ITEM_TYPE_ECPRI\n");
+ print_dbg("spec type %x pc_id %x\n", pecpri_spec->hdr.common.type, pecpri_spec->hdr.type0.pc_id);
+ print_dbg("mask type %x pc_id %x\n", pecpri_mask->hdr.common.type, pecpri_mask->hdr.type0.pc_id);
+
+ /* the final level must be always type end */
+ pattern[2].type = RTE_FLOW_ITEM_TYPE_END;
+
+ res = rte_flow_validate(port_id, &attr, pattern, action, error);
+ if (!res)
+ flow = rte_flow_create(port_id, &attr, pattern, action, error);
+ else {
+ rte_panic("Flow can't be created %d message: %s\n",
+ error->type,
+ error->message ? error->message : "(no stated reason)");
+ }
+#endif
+ return flow;
+}
+