+/**
+ * Generate internal flow rules.
+ *
+ * @param priv
+ * Pointer to private structure.
+ * @param[out] error
+ * Perform verbose error reporting if not NULL.
+ *
+ * @return
+ * 0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+mlx4_flow_internal(struct priv *priv, struct rte_flow_error *error)
+{
+ struct rte_flow_attr attr = {
+ .ingress = 1,
+ };
+ struct rte_flow_item pattern[] = {
+ {
+ .type = MLX4_FLOW_ITEM_TYPE_INTERNAL,
+ },
+ {
+ .type = RTE_FLOW_ITEM_TYPE_ETH,
+ .spec = &(struct rte_flow_item_eth){
+ .dst = priv->mac,
+ },
+ .mask = &(struct rte_flow_item_eth){
+ .dst.addr_bytes = "\xff\xff\xff\xff\xff\xff",
+ },
+ },
+ {
+ .type = RTE_FLOW_ITEM_TYPE_END,
+ },
+ };
+ struct rte_flow_action actions[] = {
+ {
+ .type = RTE_FLOW_ACTION_TYPE_QUEUE,
+ .conf = &(struct rte_flow_action_queue){
+ .index = 0,
+ },
+ },
+ {
+ .type = RTE_FLOW_ACTION_TYPE_END,
+ },
+ };
+
+ if (!mlx4_flow_create(priv->dev, &attr, pattern, actions, error))
+ return -rte_errno;
+ return 0;
+}
+
+/**
+ * Synchronize flow rules.
+ *
+ * This function synchronizes flow rules with the state of the device by
+ * taking into account isolated mode and whether target queues are
+ * configured.
+ *
+ * @param priv
+ * Pointer to private structure.
+ *
+ * @return
+ * 0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+int
+mlx4_flow_sync(struct priv *priv)
+{
+ struct rte_flow *flow;
+ int ret;
+
+ /* Internal flow rules are guaranteed to come first in the list. */
+ if (priv->isolated) {
+ /*
+ * Get rid of them in isolated mode, stop at the first
+ * non-internal rule found.
+ */
+ for (flow = LIST_FIRST(&priv->flows);
+ flow && flow->internal;
+ flow = LIST_FIRST(&priv->flows))
+ claim_zero(mlx4_flow_destroy(priv->dev, flow, NULL));
+ } else if (!LIST_FIRST(&priv->flows) ||
+ !LIST_FIRST(&priv->flows)->internal) {
+ /*
+ * If the first rule is not internal outside isolated mode,
+ * they must be added back.
+ */
+ ret = mlx4_flow_internal(priv, NULL);
+ if (ret)
+ return ret;
+ }
+ if (priv->started)
+ return mlx4_flow_start(priv);
+ mlx4_flow_stop(priv);
+ return 0;
+}
+
+/**
+ * Clean up all flow rules.
+ *
+ * Unlike mlx4_flow_flush(), this function takes care of all remaining flow
+ * rules regardless of whether they are internal or user-configured.
+ *
+ * @param priv
+ * Pointer to private structure.
+ */
+void
+mlx4_flow_clean(struct priv *priv)
+{
+ struct rte_flow *flow;
+
+ while ((flow = LIST_FIRST(&priv->flows)))
+ mlx4_flow_destroy(priv->dev, flow, NULL);
+}
+