--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_common.h>
+#include <rte_byteorder.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+
+#include "rte_port_in_action.h"
+
+/**
+ * RTE_PORT_IN_ACTION_FLTR
+ */
+static int
+fltr_cfg_check(struct rte_port_in_action_fltr_config *cfg)
+{
+ if (cfg == NULL)
+ return -1;
+
+ return 0;
+}
+
+struct fltr_data {
+ uint32_t port_id;
+};
+
+static void
+fltr_init(struct fltr_data *data,
+ struct rte_port_in_action_fltr_config *cfg)
+{
+ data->port_id = cfg->port_id;
+}
+
+static int
+fltr_apply(struct fltr_data *data,
+ struct rte_port_in_action_fltr_params *p)
+{
+ /* Check input arguments */
+ if (p == NULL)
+ return -1;
+
+ data->port_id = p->port_id;
+
+ return 0;
+}
+
+/**
+ * RTE_PORT_IN_ACTION_LB
+ */
+static int
+lb_cfg_check(struct rte_port_in_action_lb_config *cfg)
+{
+ if ((cfg == NULL) ||
+ (cfg->key_size < RTE_PORT_IN_ACTION_LB_KEY_SIZE_MIN) ||
+ (cfg->key_size > RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX) ||
+ (!rte_is_power_of_2(cfg->key_size)) ||
+ (cfg->f_hash == NULL))
+ return -1;
+
+ return 0;
+}
+
+struct lb_data {
+ uint32_t port_id[RTE_PORT_IN_ACTION_LB_TABLE_SIZE];
+};
+
+static void
+lb_init(struct lb_data *data,
+ struct rte_port_in_action_lb_config *cfg)
+{
+ memcpy(data->port_id, cfg->port_id, sizeof(cfg->port_id));
+}
+
+static int
+lb_apply(struct lb_data *data,
+ struct rte_port_in_action_lb_params *p)
+{
+ /* Check input arguments */
+ if (p == NULL)
+ return -1;
+
+ memcpy(data->port_id, p->port_id, sizeof(p->port_id));
+
+ return 0;
+}
+
+/**
+ * Action profile
+ */
+static int
+action_valid(enum rte_port_in_action_type action)
+{
+ switch (action) {
+ case RTE_PORT_IN_ACTION_FLTR:
+ case RTE_PORT_IN_ACTION_LB:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+#define RTE_PORT_IN_ACTION_MAX 64
+
+struct ap_config {
+ uint64_t action_mask;
+ struct rte_port_in_action_fltr_config fltr;
+ struct rte_port_in_action_lb_config lb;
+};
+
+static size_t
+action_cfg_size(enum rte_port_in_action_type action)
+{
+ switch (action) {
+ case RTE_PORT_IN_ACTION_FLTR:
+ return sizeof(struct rte_port_in_action_fltr_config);
+ case RTE_PORT_IN_ACTION_LB:
+ return sizeof(struct rte_port_in_action_lb_config);
+ default:
+ return 0;
+ }
+}
+
+static void*
+action_cfg_get(struct ap_config *ap_config,
+ enum rte_port_in_action_type type)
+{
+ switch (type) {
+ case RTE_PORT_IN_ACTION_FLTR:
+ return &ap_config->fltr;
+
+ case RTE_PORT_IN_ACTION_LB:
+ return &ap_config->lb;
+
+ default:
+ return NULL;
+ }
+}
+
+static void
+action_cfg_set(struct ap_config *ap_config,
+ enum rte_port_in_action_type type,
+ void *action_cfg)
+{
+ void *dst = action_cfg_get(ap_config, type);
+
+ if (dst)
+ memcpy(dst, action_cfg, action_cfg_size(type));
+
+ ap_config->action_mask |= 1LLU << type;
+}
+
+struct ap_data {
+ size_t offset[RTE_PORT_IN_ACTION_MAX];
+ size_t total_size;
+};
+
+static size_t
+action_data_size(enum rte_port_in_action_type action,
+ struct ap_config *ap_config __rte_unused)
+{
+ switch (action) {
+ case RTE_PORT_IN_ACTION_FLTR:
+ return sizeof(struct fltr_data);
+
+ case RTE_PORT_IN_ACTION_LB:
+ return sizeof(struct lb_data);
+
+ default:
+ return 0;
+ }
+}
+
+static void
+action_data_offset_set(struct ap_data *ap_data,
+ struct ap_config *ap_config)
+{
+ uint64_t action_mask = ap_config->action_mask;
+ size_t offset;
+ uint32_t action;
+
+ memset(ap_data->offset, 0, sizeof(ap_data->offset));
+
+ offset = 0;
+ for (action = 0; action < RTE_PORT_IN_ACTION_MAX; action++)
+ if (action_mask & (1LLU << action)) {
+ ap_data->offset[action] = offset;
+ offset += action_data_size((enum rte_port_in_action_type)action,
+ ap_config);
+ }
+
+ ap_data->total_size = offset;
+}
+
+struct rte_port_in_action_profile {
+ struct ap_config cfg;
+ struct ap_data data;
+ int frozen;
+};
+
+struct rte_port_in_action_profile *
+rte_port_in_action_profile_create(uint32_t socket_id)
+{
+ struct rte_port_in_action_profile *ap;
+
+ /* Memory allocation */
+ ap = rte_zmalloc_socket(NULL,
+ sizeof(struct rte_port_in_action_profile),
+ RTE_CACHE_LINE_SIZE,
+ socket_id);
+ if (ap == NULL)
+ return NULL;
+
+ return ap;
+}
+
+int
+rte_port_in_action_profile_action_register(struct rte_port_in_action_profile *profile,
+ enum rte_port_in_action_type type,
+ void *action_config)
+{
+ int status;
+
+ /* Check input arguments */
+ if ((profile == NULL) ||
+ profile->frozen ||
+ (action_valid(type) == 0) ||
+ (profile->cfg.action_mask & (1LLU << type)) ||
+ ((action_cfg_size(type) == 0) && action_config) ||
+ (action_cfg_size(type) && (action_config == NULL)))
+ return -EINVAL;
+
+ switch (type) {
+ case RTE_PORT_IN_ACTION_FLTR:
+ status = fltr_cfg_check(action_config);
+ break;
+
+ case RTE_PORT_IN_ACTION_LB:
+ status = lb_cfg_check(action_config);
+ break;
+
+ default:
+ status = 0;
+ break;
+ }
+
+ if (status)
+ return status;
+
+ /* Action enable */
+ action_cfg_set(&profile->cfg, type, action_config);
+
+ return 0;
+}
+
+int
+rte_port_in_action_profile_freeze(struct rte_port_in_action_profile *profile)
+{
+ if (profile->frozen)
+ return -EBUSY;
+
+ action_data_offset_set(&profile->data, &profile->cfg);
+ profile->frozen = 1;
+
+ return 0;
+}
+
+int
+rte_port_in_action_profile_free(struct rte_port_in_action_profile *profile)
+{
+ if (profile == NULL)
+ return 0;
+
+ free(profile);
+ return 0;
+}
+
+/**
+ * Action
+ */
+struct rte_port_in_action {
+ struct ap_config cfg;
+ struct ap_data data;
+ uint8_t memory[0] __rte_cache_aligned;
+};
+
+static __rte_always_inline void *
+action_data_get(struct rte_port_in_action *action,
+ enum rte_port_in_action_type type)
+{
+ size_t offset = action->data.offset[type];
+
+ return &action->memory[offset];
+}
+
+static void
+action_data_init(struct rte_port_in_action *action,
+ enum rte_port_in_action_type type)
+{
+ void *data = action_data_get(action, type);
+
+ switch (type) {
+ case RTE_PORT_IN_ACTION_FLTR:
+ fltr_init(data, &action->cfg.fltr);
+ return;
+
+ case RTE_PORT_IN_ACTION_LB:
+ lb_init(data, &action->cfg.lb);
+ return;
+
+ default:
+ return;
+ }
+}
+
+struct rte_port_in_action *
+rte_port_in_action_create(struct rte_port_in_action_profile *profile,
+ uint32_t socket_id)
+{
+ struct rte_port_in_action *action;
+ size_t size;
+ uint32_t i;
+
+ /* Check input arguments */
+ if ((profile == NULL) ||
+ (profile->frozen == 0))
+ return NULL;
+
+ /* Memory allocation */
+ size = sizeof(struct rte_port_in_action) + profile->data.total_size;
+ size = RTE_CACHE_LINE_ROUNDUP(size);
+
+ action = rte_zmalloc_socket(NULL,
+ size,
+ RTE_CACHE_LINE_SIZE,
+ socket_id);
+ if (action == NULL)
+ return NULL;
+
+ /* Initialization */
+ memcpy(&action->cfg, &profile->cfg, sizeof(profile->cfg));
+ memcpy(&action->data, &profile->data, sizeof(profile->data));
+
+ for (i = 0; i < RTE_PORT_IN_ACTION_MAX; i++)
+ if (action->cfg.action_mask & (1LLU << i))
+ action_data_init(action,
+ (enum rte_port_in_action_type)i);
+
+ return action;
+}
+
+int
+rte_port_in_action_apply(struct rte_port_in_action *action,
+ enum rte_port_in_action_type type,
+ void *action_params)
+{
+ void *action_data;
+
+ /* Check input arguments */
+ if ((action == NULL) ||
+ (action_valid(type) == 0) ||
+ ((action->cfg.action_mask & (1LLU << type)) == 0) ||
+ (action_params == NULL))
+ return -EINVAL;
+
+ /* Data update */
+ action_data = action_data_get(action, type);
+
+ switch (type) {
+ case RTE_PORT_IN_ACTION_FLTR:
+ return fltr_apply(action_data,
+ action_params);
+
+ case RTE_PORT_IN_ACTION_LB:
+ return lb_apply(action_data,
+ action_params);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int
+ah_filter_on_match(struct rte_pipeline *p,
+ struct rte_mbuf **pkts,
+ uint32_t n_pkts,
+ void *arg)
+{
+ struct rte_port_in_action *action = arg;
+ struct rte_port_in_action_fltr_config *cfg = &action->cfg.fltr;
+ uint64_t *key_mask = (uint64_t *) cfg->key_mask;
+ uint64_t *key = (uint64_t *) cfg->key;
+ uint32_t key_offset = cfg->key_offset;
+ struct fltr_data *data = action_data_get(action,
+ RTE_PORT_IN_ACTION_FLTR);
+ uint32_t i;
+
+ for (i = 0; i < n_pkts; i++) {
+ struct rte_mbuf *pkt = pkts[i];
+ uint64_t *pkt_key = RTE_MBUF_METADATA_UINT64_PTR(pkt,
+ key_offset);
+
+ uint64_t xor0 = (pkt_key[0] & key_mask[0]) ^ key[0];
+ uint64_t xor1 = (pkt_key[1] & key_mask[1]) ^ key[1];
+ uint64_t or = xor0 | xor1;
+
+ if (or == 0) {
+ rte_pipeline_ah_packet_hijack(p, 1LLU << i);
+ rte_pipeline_port_out_packet_insert(p,
+ data->port_id, pkt);
+ }
+ }
+
+ return 0;
+}
+
+static int
+ah_filter_on_mismatch(struct rte_pipeline *p,
+ struct rte_mbuf **pkts,
+ uint32_t n_pkts,
+ void *arg)
+{
+ struct rte_port_in_action *action = arg;
+ struct rte_port_in_action_fltr_config *cfg = &action->cfg.fltr;
+ uint64_t *key_mask = (uint64_t *) cfg->key_mask;
+ uint64_t *key = (uint64_t *) cfg->key;
+ uint32_t key_offset = cfg->key_offset;
+ struct fltr_data *data = action_data_get(action,
+ RTE_PORT_IN_ACTION_FLTR);
+ uint32_t i;
+
+ for (i = 0; i < n_pkts; i++) {
+ struct rte_mbuf *pkt = pkts[i];
+ uint64_t *pkt_key = RTE_MBUF_METADATA_UINT64_PTR(pkt,
+ key_offset);
+
+ uint64_t xor0 = (pkt_key[0] & key_mask[0]) ^ key[0];
+ uint64_t xor1 = (pkt_key[1] & key_mask[1]) ^ key[1];
+ uint64_t or = xor0 | xor1;
+
+ if (or) {
+ rte_pipeline_ah_packet_hijack(p, 1LLU << i);
+ rte_pipeline_port_out_packet_insert(p,
+ data->port_id, pkt);
+ }
+ }
+
+ return 0;
+}
+
+static int
+ah_lb(struct rte_pipeline *p,
+ struct rte_mbuf **pkts,
+ uint32_t n_pkts,
+ void *arg)
+{
+ struct rte_port_in_action *action = arg;
+ struct rte_port_in_action_lb_config *cfg = &action->cfg.lb;
+ struct lb_data *data = action_data_get(action, RTE_PORT_IN_ACTION_LB);
+ uint64_t pkt_mask = RTE_LEN2MASK(n_pkts, uint64_t);
+ uint32_t i;
+
+ rte_pipeline_ah_packet_hijack(p, pkt_mask);
+
+ for (i = 0; i < n_pkts; i++) {
+ struct rte_mbuf *pkt = pkts[i];
+ uint8_t *pkt_key = RTE_MBUF_METADATA_UINT8_PTR(pkt,
+ cfg->key_offset);
+
+ uint64_t digest = cfg->f_hash(pkt_key,
+ cfg->key_mask,
+ cfg->key_size,
+ cfg->seed);
+ uint64_t pos = digest & (RTE_PORT_IN_ACTION_LB_TABLE_SIZE - 1);
+ uint32_t port_id = data->port_id[pos];
+
+ rte_pipeline_port_out_packet_insert(p, port_id, pkt);
+ }
+
+ return 0;
+}
+
+static rte_pipeline_port_in_action_handler
+ah_selector(struct rte_port_in_action *action)
+{
+ if (action->cfg.action_mask == 0)
+ return NULL;
+
+ if (action->cfg.action_mask == 1LLU << RTE_PORT_IN_ACTION_FLTR)
+ return (action->cfg.fltr.filter_on_match) ?
+ ah_filter_on_match : ah_filter_on_mismatch;
+
+ if (action->cfg.action_mask == 1LLU << RTE_PORT_IN_ACTION_LB)
+ return ah_lb;
+
+ return NULL;
+}
+
+int
+rte_port_in_action_params_get(struct rte_port_in_action *action,
+ struct rte_pipeline_port_in_params *params)
+{
+ rte_pipeline_port_in_action_handler f_action;
+
+ /* Check input arguments */
+ if ((action == NULL) ||
+ (params == NULL))
+ return -EINVAL;
+
+ f_action = ah_selector(action);
+
+ /* Fill in params */
+ params->f_action = f_action;
+ params->arg_ah = (f_action) ? action : NULL;
+
+ return 0;
+}
+
+int
+rte_port_in_action_free(struct rte_port_in_action *action)
+{
+ if (action == NULL)
+ return 0;
+
+ rte_free(action);
+
+ return 0;
+}
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#ifndef __INCLUDE_RTE_PORT_IN_ACTION_H__
+#define __INCLUDE_RTE_PORT_IN_ACTION_H__
+
+/**
+ * @file
+ * RTE Pipeline Input Port Actions
+ *
+ * This API provides a common set of actions for pipeline input ports to speed
+ * up application development.
+ *
+ * Each pipeline input port can be assigned an action handler to be executed
+ * on every input packet during the pipeline execution. The pipeline library
+ * allows the user to define his own input port actions by providing customized
+ * input port action handler. While the user can still follow this process, this
+ * API is intended to provide a quicker development alternative for a set of
+ * predefined actions.
+ *
+ * The typical steps to use this API are:
+ * - Define an input port action profile. This is a configuration template that
+ * can potentially be shared by multiple input ports from the same or
+ * different pipelines, with different input ports from the same pipeline
+ * able to use different action profiles. For every input port using a given
+ * action profile, the profile defines the set of actions and the action
+ * configuration to be executed by the input port. API functions:
+ * rte_port_in_action_profile_create(),
+ * rte_port_in_action_profile_action_register(),
+ * rte_port_in_action_profile_freeze().
+ *
+ * - Instantiate the input port action profile to create input port action
+ * objects. Each pipeline input port has its own action object.
+ * API functions: rte_port_in_action_create().
+ *
+ * - Use the input port action object to generate the input port action handler
+ * invoked by the pipeline. API functions:
+ * rte_port_in_action_params_get().
+ *
+ * - Use the input port action object to generate the internal data structures
+ * used by the input port action handler based on given action parameters.
+ * API functions: rte_port_in_action_apply().
+ *
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+#include <rte_compat.h>
+#include <rte_table_hash.h>
+
+#include "rte_pipeline.h"
+
+/** Input port actions. */
+enum rte_port_in_action_type {
+ /** Filter selected input packets. */
+ RTE_PORT_IN_ACTION_FLTR = 0,
+
+ /** Load balance. */
+ RTE_PORT_IN_ACTION_LB,
+};
+
+/**
+ * RTE_PORT_IN_ACTION_FLTR
+ */
+/** Filter key size (number of bytes) */
+#define RTE_PORT_IN_ACTION_FLTR_KEY_SIZE 16
+
+/** Filter action configuration (per action profile). */
+struct rte_port_in_action_fltr_config {
+ /** Key offset within the input packet buffer. Offset 0 points to the
+ * first byte of the MBUF structure.
+ */
+ uint32_t key_offset;
+
+ /** Key mask. */
+ uint8_t key_mask[RTE_PORT_IN_ACTION_FLTR_KEY_SIZE];
+
+ /** Key value. */
+ uint8_t key[RTE_PORT_IN_ACTION_FLTR_KEY_SIZE];
+
+ /** When non-zero, all the input packets that match the *key* (with the
+ * *key_mask* applied) are sent to the pipeline output port *port_id*.
+ * When zero, all the input packets that do NOT match the *key* (with
+ * *key_mask* applied) are sent to the pipeline output port *port_id*.
+ */
+ int filter_on_match;
+
+ /** Pipeline output port ID to send the filtered input packets to.
+ * Can be updated later.
+ *
+ * @see struct rte_port_in_action_fltr_params
+ */
+ uint32_t port_id;
+};
+
+/** Filter action parameters (per action). */
+struct rte_port_in_action_fltr_params {
+ /** Pipeline output port ID to send the filtered input packets to. */
+ uint32_t port_id;
+};
+
+/**
+ * RTE_PORT_IN_ACTION_LB
+ */
+/** Load balance key size min (number of bytes). */
+#define RTE_PORT_IN_ACTION_LB_KEY_SIZE_MIN 8
+
+/** Load balance key size max (number of bytes). */
+#define RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX 64
+
+/** Load balance table size. */
+#define RTE_PORT_IN_ACTION_LB_TABLE_SIZE 16
+
+/** Load balance action configuration (per action profile). */
+struct rte_port_in_action_lb_config {
+ /** Key size (number of bytes). */
+ uint32_t key_size;
+
+ /** Key offset within the input packet buffer. Offset 0 points to the
+ * first byte of the MBUF structure.
+ */
+ uint32_t key_offset;
+
+ /** Key mask(*key_size* bytes are valid). */
+ uint8_t key_mask[RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX];
+
+ /** Hash function. */
+ rte_table_hash_op_hash f_hash;
+
+ /** Seed value for *f_hash*. */
+ uint64_t seed;
+
+ /** Table defining the weight of each pipeline output port. The weights
+ * are set in 1/RTE_PORT_IN_ACTION_LB_TABLE_SIZE increments. To assign a
+ * weight of N/RTE_PORT_IN_ACTION_LB_TABLE_SIZE to a given output port
+ * (0 <= N <= RTE_PORT_IN_ACTION_LB_TABLE_SIZE), the output port needs
+ * to show up exactly N times in this table. Can be updated later.
+ *
+ * @see struct rte_port_in_action_lb_params
+ */
+ uint32_t port_id[RTE_PORT_IN_ACTION_LB_TABLE_SIZE];
+};
+
+/** Load balance action parameters (per action). */
+struct rte_port_in_action_lb_params {
+ /** Table defining the weight of each pipeline output port. The weights
+ * are set in 1/RTE_PORT_IN_ACTION_LB_TABLE_SIZE increments. To assign a
+ * weight of N/RTE_PORT_IN_ACTION_LB_TABLE_SIZE to a given output port
+ * (0 <= N <= RTE_PORT_IN_ACTION_LB_TABLE_SIZE), the output port needs
+ * to show up exactly N times in this table.
+ */
+ uint32_t port_id[RTE_PORT_IN_ACTION_LB_TABLE_SIZE];
+};
+
+/**
+ * Input port action profile.
+ */
+struct rte_port_in_action_profile;
+
+/**
+ * Input port action profile create.
+ *
+ * @param[in] socket_id
+ * CPU socket ID for the internal data structures memory allocation.
+ * @return
+ * Input port action profile handle on success, NULL otherwise.
+ */
+struct rte_port_in_action_profile * __rte_experimental
+rte_port_in_action_profile_create(uint32_t socket_id);
+
+/**
+ * Input port action profile free.
+ *
+ * @param[in] profile
+ * Input port action profile handle (needs to be valid).
+ * @return
+ * Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_port_in_action_profile_free(struct rte_port_in_action_profile *profile);
+
+/**
+ * Input port action profile action register.
+ *
+ * @param[in] profile
+ * Input port action profile handle (needs to be valid and not in frozen
+ * state).
+ * @param[in] type
+ * Specific input port action to be registered for *profile*.
+ * @param[in] action_config
+ * Configuration for the *type* action.
+ * If struct rte_port_in_action_*type*_config is defined, it needs to point to
+ * a valid instance of this structure, otherwise it needs to be set to NULL.
+ * @return
+ * Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_port_in_action_profile_action_register(
+ struct rte_port_in_action_profile *profile,
+ enum rte_port_in_action_type type,
+ void *action_config);
+
+/**
+ * Input port action profile freeze.
+ *
+ * Once this function is called successfully, the given profile enters the
+ * frozen state with the following immediate effects: no more actions can be
+ * registered for this profile, so the profile can be instantiated to create
+ * input port action objects.
+ *
+ * @param[in] profile
+ * Input port profile action handle (needs to be valid and not in frozen
+ * state).
+ * @return
+ * Zero on success, non-zero error code otherwise.
+ *
+ * @see rte_port_in_action_create()
+ */
+int __rte_experimental
+rte_port_in_action_profile_freeze(struct rte_port_in_action_profile *profile);
+
+/**
+ * Input port action.
+ */
+struct rte_port_in_action;
+
+/**
+ * Input port action create.
+ *
+ * Instantiates the given input port action profile to create an input port
+ * action object.
+ *
+ * @param[in] profile
+ * Input port profile action handle (needs to be valid and in frozen state).
+ * @param[in] socket_id
+ * CPU socket ID where the internal data structures required by the new input
+ * port action object should be allocated.
+ * @return
+ * Handle to input port action object on success, NULL on error.
+ */
+struct rte_port_in_action * __rte_experimental
+rte_port_in_action_create(struct rte_port_in_action_profile *profile,
+ uint32_t socket_id);
+
+/**
+ * Input port action free.
+ *
+ * @param[in] action
+ * Handle to input port action object (needs to be valid).
+ * @return
+ * Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_port_in_action_free(struct rte_port_in_action *action);
+
+/**
+ * Input port params get.
+ *
+ * @param[in] action
+ * Handle to input port action object (needs to be valid).
+ * @param[inout] params
+ * Pipeline input port parameters (needs to be pre-allocated).
+ * @return
+ * Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_port_in_action_params_get(struct rte_port_in_action *action,
+ struct rte_pipeline_port_in_params *params);
+
+/**
+ * Input port action apply.
+ *
+ * @param[in] action
+ * Handle to input port action object (needs to be valid).
+ * @param[in] type
+ * Specific input port action previously registered for the input port action
+ * profile of the *action* object.
+ * @param[in] action_params
+ * Parameters for the *type* action.
+ * If struct rte_port_in_action_*type*_params is defined, it needs to point to
+ * a valid instance of this structure, otherwise it needs to be set to NULL.
+ * @return
+ * Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_port_in_action_apply(struct rte_port_in_action *action,
+ enum rte_port_in_action_type type,
+ void *action_params);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __INCLUDE_RTE_PORT_IN_ACTION_H__ */