numam-dpdk/lib/librte_ethdev/rte_flow_driver.h
Andrey Vesnovaty 4d9fd85fb5 ethdev: add shared actions to flow API
Introduce extension of flow action API enabling sharing of single
rte_flow_action in multiple flows. The API intended for PMDs, where
multiple HW offloaded flows can reuse the same HW essence/object
representing flow action and modification of such an essence/object
affects all the rules using it.

Motivation and example
===
Adding or removing one or more queues to RSS used by multiple flow rules
imposes per rule toll for current DPDK flow API; the scenario requires
for each flow sharing cloned RSS action:
- call `rte_flow_destroy()`
- call `rte_flow_create()` with modified RSS action

API for sharing action and its in-place update benefits:
- reduce the overhead of multiple RSS flow rules reconfiguration
- optimize resource utilization by sharing action across multiple
  flows

Change description
===

Shared action
===
In order to represent flow action shared by multiple flows new action
type RTE_FLOW_ACTION_TYPE_SHARED is introduced (see `enum
rte_flow_action_type`).
Actually the introduced API decouples action from any specific flow and
enables sharing of single action by its handle across multiple flows.

Shared action create/use/destroy
===
Shared action may be reused by some or none flow rules at any given
moment, i.e. shared action resides outside of the context of any flow.
Shared action represent HW resources/objects used for action offloading
implementation.
API for shared action create (see `rte_flow_shared_action_create()`):
- should allocate HW resources and make related initializations required
  for shared action implementation.
- make necessary preparations to maintain shared access to
  the action resources, configuration and state.
API for shared action destroy (see `rte_flow_shared_action_destroy()`)
should release HW resources and make related cleanups required for shared
action implementation.

In order to share some flow action reuse the handle of type
`struct rte_flow_shared_action` returned by
rte_flow_shared_action_create() as a `conf` field of
`struct rte_flow_action` (see "example" section).

If some shared action not used by any flow rule all resources allocated
by the shared action can be released by rte_flow_shared_action_destroy()
(see "example" section). The shared action handle passed as argument to
destroy API should not be used any further i.e. result of the usage is
undefined.

Shared action re-configuration
===
Shared action behavior defined by its configuration can be updated via
rte_flow_shared_action_update() (see "example" section). The shared
action update operation modifies HW related resources/objects allocated
on the action creation. The number of operations performed by the update
operation should not depend on the number of flows sharing the related
action. On return of shared action update API action behavior should be
according to updated configuration for all flows sharing the action.

Shared action query
===
Provide separate API to query shared action state (see
rte_flow_shared_action_update()). Taking a counter as an example: query
returns value aggregating all counter increments across all flow rules
sharing the counter. This API doesn't query shared action configuration
since it is controlled by rte_flow_shared_action_create() and
rte_flow_shared_action_update() APIs and no supposed to change by other
means.

example
===

struct rte_flow_action actions[2];
struct rte_flow_shared_action_conf conf;
struct rte_flow_action action;
/* skipped: initialize conf and action */
struct rte_flow_shared_action *handle =
	rte_flow_shared_action_create(port_id, &conf, &action, &error);
actions[0].type = RTE_FLOW_ACTION_TYPE_SHARED;
actions[0].conf = handle;
actions[1].type = RTE_FLOW_ACTION_TYPE_END;
/* skipped: init attr0 & pattern0 args */
struct rte_flow *flow0 = rte_flow_create(port_id, &attr0, pattern0,
					actions, error);
/* create more rules reusing shared action */
struct rte_flow *flow1 = rte_flow_create(port_id, &attr1, pattern1,
					actions, error);
/* skipped: for flows 2 till N */
struct rte_flow *flowN = rte_flow_create(port_id, &attrN, patternN,
					actions, error);
/* update shared action */
struct rte_flow_action updated_action;
/*
 * skipped: initialize updated_action according to desired action
 * configuration change
 */
rte_flow_shared_action_update(port_id, handle, &updated_action, error);
/*
 * from now on all flows 1 till N will act according to configuration of
 * updated_action
 */
/* skipped: destroy all flows 1 till N */
rte_flow_shared_action_destroy(port_id, handle, error);

Signed-off-by: Andrey Vesnovaty <andreyv@nvidia.com>
Acked-by: Ori Kam <orika@nvidia.com>
Acked-by: Ajit Khaparde <ajit.khaparde@broadcom.com>
Acked-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
2020-10-16 19:48:18 +02:00

157 lines
4.3 KiB
C

/* SPDX-License-Identifier: BSD-3-Clause
* Copyright 2016 6WIND S.A.
* Copyright 2016 Mellanox Technologies, Ltd
*/
#ifndef RTE_FLOW_DRIVER_H_
#define RTE_FLOW_DRIVER_H_
/**
* @file
* RTE generic flow API (driver side)
*
* This file provides implementation helpers for internal use by PMDs, they
* are not intended to be exposed to applications and are not subject to ABI
* versioning.
*/
#include <stdint.h>
#include "rte_ethdev.h"
#include "rte_ethdev_driver.h"
#include "rte_flow.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* Generic flow operations structure implemented and returned by PMDs.
*
* To implement this API, PMDs must handle the RTE_ETH_FILTER_GENERIC filter
* type in their .filter_ctrl callback function (struct eth_dev_ops) as well
* as the RTE_ETH_FILTER_GET filter operation.
*
* If successful, this operation must result in a pointer to a PMD-specific
* struct rte_flow_ops written to the argument address as described below:
*
* \code
*
* // PMD filter_ctrl callback
*
* static const struct rte_flow_ops pmd_flow_ops = { ... };
*
* switch (filter_type) {
* case RTE_ETH_FILTER_GENERIC:
* if (filter_op != RTE_ETH_FILTER_GET)
* return -EINVAL;
* *(const void **)arg = &pmd_flow_ops;
* return 0;
* }
*
* \endcode
*
* See also rte_flow_ops_get().
*
* These callback functions are not supposed to be used by applications
* directly, which must rely on the API defined in rte_flow.h.
*
* Public-facing wrapper functions perform a few consistency checks so that
* unimplemented (i.e. NULL) callbacks simply return -ENOTSUP. These
* callbacks otherwise only differ by their first argument (with port ID
* already resolved to a pointer to struct rte_eth_dev).
*/
struct rte_flow_ops {
/** See rte_flow_validate(). */
int (*validate)
(struct rte_eth_dev *,
const struct rte_flow_attr *,
const struct rte_flow_item [],
const struct rte_flow_action [],
struct rte_flow_error *);
/** See rte_flow_create(). */
struct rte_flow *(*create)
(struct rte_eth_dev *,
const struct rte_flow_attr *,
const struct rte_flow_item [],
const struct rte_flow_action [],
struct rte_flow_error *);
/** See rte_flow_destroy(). */
int (*destroy)
(struct rte_eth_dev *,
struct rte_flow *,
struct rte_flow_error *);
/** See rte_flow_flush(). */
int (*flush)
(struct rte_eth_dev *,
struct rte_flow_error *);
/** See rte_flow_query(). */
int (*query)
(struct rte_eth_dev *,
struct rte_flow *,
const struct rte_flow_action *,
void *,
struct rte_flow_error *);
/** See rte_flow_isolate(). */
int (*isolate)
(struct rte_eth_dev *,
int,
struct rte_flow_error *);
/** See rte_flow_dev_dump(). */
int (*dev_dump)
(struct rte_eth_dev *dev,
FILE *file,
struct rte_flow_error *error);
/** See rte_flow_get_aged_flows() */
int (*get_aged_flows)
(struct rte_eth_dev *dev,
void **context,
uint32_t nb_contexts,
struct rte_flow_error *err);
/** See rte_flow_shared_action_create() */
struct rte_flow_shared_action *(*shared_action_create)
(struct rte_eth_dev *dev,
const struct rte_flow_shared_action_conf *conf,
const struct rte_flow_action *action,
struct rte_flow_error *error);
/** See rte_flow_shared_action_destroy() */
int (*shared_action_destroy)
(struct rte_eth_dev *dev,
struct rte_flow_shared_action *shared_action,
struct rte_flow_error *error);
/** See rte_flow_shared_action_update() */
int (*shared_action_update)
(struct rte_eth_dev *dev,
struct rte_flow_shared_action *shared_action,
const struct rte_flow_action *update,
struct rte_flow_error *error);
/** See rte_flow_shared_action_query() */
int (*shared_action_query)
(struct rte_eth_dev *dev,
const struct rte_flow_shared_action *shared_action,
void *data,
struct rte_flow_error *error);
};
/**
* Get generic flow operations structure from a port.
*
* @param port_id
* Port identifier to query.
* @param[out] error
* Pointer to flow error structure.
*
* @return
* The flow operations structure associated with port_id, NULL in case of
* error, in which case rte_errno is set and the error structure contains
* additional details.
*/
const struct rte_flow_ops *
rte_flow_ops_get(uint16_t port_id, struct rte_flow_error *error);
#ifdef __cplusplus
}
#endif
#endif /* RTE_FLOW_DRIVER_H_ */