@@ -70,6 +70,7 @@ Features
- Flow aging support
- Flow metering, including meter policy API.
- Flow update. Update of the action list for specific flow
+- Asynchronous flow support
Limitations
~~~~~~~~~~~
@@ -167,6 +167,7 @@ New Features
* Added age rte flow action support
* Added meter flow metering and flow policy support
* Added flow actions update support
+ * Added asynchronous flow support
* **Added cryptodev queue pair reset support.**
@@ -339,6 +339,12 @@ struct flow_handle {
uint8_t flm_rqi;
uint8_t flm_qfi;
uint8_t flm_scrub_prof;
+
+ /* Flow specific pointer to application template table cell stored during
+ * flow create.
+ */
+ struct flow_template_table_cell *template_table_cell;
+ bool flm_async;
};
};
};
@@ -347,8 +353,38 @@ struct flow_pattern_template {
};
struct flow_actions_template {
+ struct nic_flow_def *fd;
+
+ uint32_t num_dest_port;
+ uint32_t num_queues;
};
+
+struct flow_template_table_cell {
+ atomic_int status;
+ atomic_int counter;
+
+ uint32_t flm_db_idx_counter;
+ uint32_t flm_db_idxs[RES_COUNT];
+
+ uint32_t flm_key_id;
+ uint32_t flm_ft;
+
+ uint16_t flm_rpl_ext_ptr;
+ uint8_t flm_scrub_prof;
+};
+
struct flow_template_table {
+ struct flow_pattern_template **pattern_templates;
+ uint8_t nb_pattern_templates;
+
+ struct flow_actions_template **actions_templates;
+ uint8_t nb_actions_templates;
+
+ struct flow_template_table_cell *pattern_action_pairs;
+
+ struct rte_flow_attr attr;
+ uint16_t forced_vlan_vid;
+ uint16_t caller_id;
};
void km_attach_ndev_resource_management(struct km_flow_def_s *km, void **handle);
@@ -1077,6 +1077,43 @@ static int flow_configure(struct flow_eth_dev *dev, uint8_t caller_id,
nb_queue, queue_attr, error);
}
+/*
+ * Flow Asynchronous operation API
+ */
+
+static struct flow_handle *
+flow_async_create(struct flow_eth_dev *dev, uint32_t queue_id,
+ const struct rte_flow_op_attr *op_attr, struct flow_template_table *template_table,
+ const struct rte_flow_item pattern[], uint8_t pattern_template_index,
+ const struct rte_flow_action actions[], uint8_t actions_template_index, void *user_data,
+ struct rte_flow_error *error)
+{
+ const struct profile_inline_ops *profile_inline_ops = get_profile_inline_ops();
+
+ if (profile_inline_ops == NULL) {
+ NT_LOG_DBGX(ERR, FILTER, "profile_inline module uninitialized");
+ return NULL;
+ }
+
+ return profile_inline_ops->flow_async_create_profile_inline(dev, queue_id, op_attr,
+ template_table, pattern, pattern_template_index, actions,
+ actions_template_index, user_data, error);
+}
+
+static int flow_async_destroy(struct flow_eth_dev *dev, uint32_t queue_id,
+ const struct rte_flow_op_attr *op_attr, struct flow_handle *flow,
+ void *user_data, struct rte_flow_error *error)
+{
+ const struct profile_inline_ops *profile_inline_ops = get_profile_inline_ops();
+
+ if (profile_inline_ops == NULL) {
+ NT_LOG_DBGX(ERR, FILTER, "profile_inline module uninitialized");
+ return -1;
+ }
+
+ return profile_inline_ops->flow_async_destroy_profile_inline(dev, queue_id, op_attr, flow,
+ user_data, error);
+}
int flow_get_flm_stats(struct flow_nic_dev *ndev, uint64_t *data, uint64_t size)
{
const struct profile_inline_ops *profile_inline_ops = get_profile_inline_ops();
@@ -1113,6 +1150,8 @@ static const struct flow_filter_ops ops = {
*/
.flow_info_get = flow_info_get,
.flow_configure = flow_configure,
+ .flow_async_create = flow_async_create,
+ .flow_async_destroy = flow_async_destroy,
/*
* Other
@@ -393,6 +393,19 @@ void hw_db_inline_deref_idxs(struct flow_nic_dev *ndev, void *db_handle, struct
}
}
+struct hw_db_idx *hw_db_inline_find_idx(struct flow_nic_dev *ndev, void *db_handle,
+ enum hw_db_idx_type type, struct hw_db_idx *idxs, uint32_t size)
+{
+ (void)ndev;
+ (void)db_handle;
+ for (uint32_t i = 0; i < size; ++i) {
+ if (idxs[i].type == type)
+ return &idxs[i];
+ }
+
+ return NULL;
+}
+
void hw_db_inline_dump(struct flow_nic_dev *ndev, void *db_handle, const struct hw_db_idx *idxs,
uint32_t size, FILE *file)
{
@@ -287,6 +287,8 @@ void hw_db_inline_deref_idxs(struct flow_nic_dev *ndev, void *db_handle, struct
uint32_t size);
const void *hw_db_inline_find_data(struct flow_nic_dev *ndev, void *db_handle,
enum hw_db_idx_type type, struct hw_db_idx *idxs, uint32_t size);
+struct hw_db_idx *hw_db_inline_find_idx(struct flow_nic_dev *ndev, void *db_handle,
+ enum hw_db_idx_type type, struct hw_db_idx *idxs, uint32_t size);
void hw_db_inline_dump(struct flow_nic_dev *ndev, void *db_handle, const struct hw_db_idx *idxs,
uint32_t size, FILE *file);
void hw_db_inline_dump_cfn(struct flow_nic_dev *ndev, void *db_handle, FILE *file);
@@ -3,7 +3,6 @@
* Copyright(c) 2023 Napatech A/S
*/
-#include "generic/rte_spinlock.h"
#include "ntlog.h"
#include "nt_util.h"
@@ -64,6 +63,11 @@
#define POLICING_PARAMETER_OFFSET 4096
#define SIZE_CONVERTER 1099.511627776
+#define CELL_STATUS_UNINITIALIZED 0
+#define CELL_STATUS_INITIALIZING 1
+#define CELL_STATUS_INITIALIZED_TYPE_FLOW 2
+#define CELL_STATUS_INITIALIZED_TYPE_FLM 3
+
struct flm_mtr_stat_s {
struct dual_buckets_s *buckets;
atomic_uint_fast64_t n_pkt;
@@ -1034,6 +1038,17 @@ static int flm_flow_programming(struct flow_handle *fh, uint32_t flm_op)
return 0;
}
+static inline const void *memcpy_or(void *dest, const void *src, size_t count)
+{
+ unsigned char *dest_ptr = (unsigned char *)dest;
+ const unsigned char *src_ptr = (const unsigned char *)src;
+
+ for (size_t i = 0; i < count; ++i)
+ dest_ptr[i] |= src_ptr[i];
+
+ return dest;
+}
+
/*
* This function must be callable without locking any mutexes
*/
@@ -4341,6 +4356,9 @@ int flow_destroy_profile_inline(struct flow_eth_dev *dev, struct flow_handle *fl
{
int err = 0;
+ if (flow && flow->type == FLOW_HANDLE_TYPE_FLM && flow->flm_async)
+ return flow_async_destroy_profile_inline(dev, 0, NULL, flow, NULL, error);
+
flow_nic_set_error(ERR_SUCCESS, error);
if (flow) {
@@ -5485,6 +5503,232 @@ int flow_configure_profile_inline(struct flow_eth_dev *dev, uint8_t caller_id,
return -1;
}
+struct flow_handle *flow_async_create_profile_inline(struct flow_eth_dev *dev,
+ uint32_t queue_id,
+ const struct rte_flow_op_attr *op_attr,
+ struct flow_template_table *template_table,
+ const struct rte_flow_item pattern[],
+ uint8_t pattern_template_index,
+ const struct rte_flow_action actions[],
+ uint8_t actions_template_index,
+ void *user_data,
+ struct rte_flow_error *error)
+{
+ (void)queue_id;
+ (void)op_attr;
+ struct flow_handle *fh = NULL;
+ int res, status;
+
+ const uint32_t pattern_action_index =
+ (uint32_t)template_table->nb_actions_templates * pattern_template_index +
+ actions_template_index;
+ struct flow_template_table_cell *pattern_action_pair =
+ &template_table->pattern_action_pairs[pattern_action_index];
+
+ uint32_t num_dest_port =
+ template_table->actions_templates[actions_template_index]->num_dest_port;
+ uint32_t num_queues =
+ template_table->actions_templates[actions_template_index]->num_queues;
+
+ uint32_t port_id = UINT32_MAX;
+ uint32_t packet_data[10];
+ uint32_t packet_mask[10];
+ struct flm_flow_key_def_s key_def;
+
+ flow_nic_set_error(ERR_SUCCESS, error);
+
+ struct nic_flow_def *fd = malloc(sizeof(struct nic_flow_def));
+
+ if (fd == NULL) {
+ error->type = RTE_FLOW_ERROR_TYPE_UNSPECIFIED;
+ error->message = "Failed to allocate flow_def";
+ goto err_exit;
+ }
+
+ memcpy(fd, template_table->actions_templates[actions_template_index]->fd,
+ sizeof(struct nic_flow_def));
+
+ res = interpret_flow_elements(dev, pattern, fd, error,
+ template_table->forced_vlan_vid, &port_id, packet_data,
+ packet_mask, &key_def);
+
+ if (res)
+ goto err_exit;
+
+ if (port_id == UINT32_MAX)
+ port_id = dev->port_id;
+
+ {
+ uint32_t num_dest_port_tmp = 0;
+ uint32_t num_queues_tmp = 0;
+
+ struct nic_flow_def action_fd = { 0 };
+ prepare_nic_flow_def(&action_fd);
+
+ res = interpret_flow_actions(dev, actions, NULL, &action_fd, error,
+ &num_dest_port_tmp, &num_queues_tmp);
+
+ if (res)
+ goto err_exit;
+
+ /* Copy FLM unique actions: modify_field, meter, encap/decap and age */
+ memcpy_or(fd->mtr_ids, action_fd.mtr_ids, sizeof(action_fd.mtr_ids));
+ memcpy_or(&fd->tun_hdr, &action_fd.tun_hdr, sizeof(struct tunnel_header_s));
+ memcpy_or(fd->modify_field, action_fd.modify_field,
+ sizeof(action_fd.modify_field));
+ fd->modify_field_count = action_fd.modify_field_count;
+ memcpy_or(&fd->age, &action_fd.age, sizeof(struct rte_flow_action_age));
+ }
+
+ status = atomic_load(&pattern_action_pair->status);
+
+ /* Initializing template entry */
+ if (status < CELL_STATUS_INITIALIZED_TYPE_FLOW) {
+ if (status == CELL_STATUS_UNINITIALIZED &&
+ atomic_compare_exchange_strong(&pattern_action_pair->status, &status,
+ CELL_STATUS_INITIALIZING)) {
+ rte_spinlock_lock(&dev->ndev->mtx);
+
+ fh = create_flow_filter(dev, fd, &template_table->attr,
+ template_table->forced_vlan_vid, template_table->caller_id,
+ error, port_id, num_dest_port, num_queues, packet_data,
+ packet_mask, &key_def);
+
+ rte_spinlock_unlock(&dev->ndev->mtx);
+
+ if (fh == NULL) {
+ /* reset status to CELL_STATUS_UNINITIALIZED to avoid a deadlock */
+ atomic_store(&pattern_action_pair->status,
+ CELL_STATUS_UNINITIALIZED);
+ goto err_exit;
+ }
+
+ if (fh->type == FLOW_HANDLE_TYPE_FLM) {
+ rte_spinlock_lock(&dev->ndev->mtx);
+
+ struct hw_db_idx *flm_ft_idx =
+ hw_db_inline_find_idx(dev->ndev, dev->ndev->hw_db_handle,
+ HW_DB_IDX_TYPE_FLM_FT,
+ (struct hw_db_idx *)fh->flm_db_idxs,
+ fh->flm_db_idx_counter);
+
+ rte_spinlock_unlock(&dev->ndev->mtx);
+
+ pattern_action_pair->flm_db_idx_counter = fh->flm_db_idx_counter;
+ memcpy(pattern_action_pair->flm_db_idxs, fh->flm_db_idxs,
+ sizeof(struct hw_db_idx) * fh->flm_db_idx_counter);
+
+ pattern_action_pair->flm_key_id = fh->flm_kid;
+ pattern_action_pair->flm_ft = flm_ft_idx->id1;
+
+ pattern_action_pair->flm_rpl_ext_ptr = fh->flm_rpl_ext_ptr;
+ pattern_action_pair->flm_scrub_prof = fh->flm_scrub_prof;
+
+ atomic_store(&pattern_action_pair->status,
+ CELL_STATUS_INITIALIZED_TYPE_FLM);
+
+ /* increment template table cell reference */
+ atomic_fetch_add(&pattern_action_pair->counter, 1);
+ fh->template_table_cell = pattern_action_pair;
+ fh->flm_async = true;
+
+ } else {
+ atomic_store(&pattern_action_pair->status,
+ CELL_STATUS_INITIALIZED_TYPE_FLOW);
+ }
+
+ } else {
+ do {
+ nt_os_wait_usec(1);
+ status = atomic_load(&pattern_action_pair->status);
+ } while (status == CELL_STATUS_INITIALIZING);
+
+ /* error handling in case that create_flow_filter() will fail in the other
+ * thread
+ */
+ if (status == CELL_STATUS_UNINITIALIZED)
+ goto err_exit;
+ }
+ }
+
+ /* FLM learn */
+ if (fh == NULL && status == CELL_STATUS_INITIALIZED_TYPE_FLM) {
+ fh = calloc(1, sizeof(struct flow_handle));
+
+ fh->type = FLOW_HANDLE_TYPE_FLM;
+ fh->dev = dev;
+ fh->caller_id = template_table->caller_id;
+ fh->user_data = user_data;
+
+ copy_fd_to_fh_flm(fh, fd, packet_data, pattern_action_pair->flm_key_id,
+ pattern_action_pair->flm_ft,
+ pattern_action_pair->flm_rpl_ext_ptr,
+ pattern_action_pair->flm_scrub_prof,
+ template_table->attr.priority & 0x3);
+
+ free(fd);
+
+ flm_flow_programming(fh, NT_FLM_OP_LEARN);
+
+ nic_insert_flow_flm(dev->ndev, fh);
+
+ /* increment template table cell reference */
+ atomic_fetch_add(&pattern_action_pair->counter, 1);
+ fh->template_table_cell = pattern_action_pair;
+ fh->flm_async = true;
+
+ } else if (fh == NULL) {
+ rte_spinlock_lock(&dev->ndev->mtx);
+
+ fh = create_flow_filter(dev, fd, &template_table->attr,
+ template_table->forced_vlan_vid, template_table->caller_id,
+ error, port_id, num_dest_port, num_queues, packet_data,
+ packet_mask, &key_def);
+
+ rte_spinlock_unlock(&dev->ndev->mtx);
+
+ if (fh == NULL)
+ goto err_exit;
+ }
+
+ if (fh) {
+ fh->caller_id = template_table->caller_id;
+ fh->user_data = user_data;
+ }
+
+ return fh;
+
+err_exit:
+ free(fd);
+ free(fh);
+
+ return NULL;
+}
+
+int flow_async_destroy_profile_inline(struct flow_eth_dev *dev, uint32_t queue_id,
+ const struct rte_flow_op_attr *op_attr, struct flow_handle *flow,
+ void *user_data, struct rte_flow_error *error)
+{
+ (void)queue_id;
+ (void)op_attr;
+ (void)user_data;
+
+ if (flow->type == FLOW_HANDLE_TYPE_FLOW)
+ return flow_destroy_profile_inline(dev, flow, error);
+
+ if (flm_flow_programming(flow, NT_FLM_OP_UNLEARN)) {
+ NT_LOG(ERR, FILTER, "FAILED to destroy flow: %p", flow);
+ flow_nic_set_error(ERR_REMOVE_FLOW_FAILED, error);
+ return -1;
+ }
+
+ nic_remove_flow_flm(dev->ndev, flow);
+
+ free(flow);
+
+ return 0;
+}
+
static const struct profile_inline_ops ops = {
/*
* Management
@@ -5509,6 +5753,8 @@ static const struct profile_inline_ops ops = {
.flow_get_flm_stats_profile_inline = flow_get_flm_stats_profile_inline,
.flow_info_get_profile_inline = flow_info_get_profile_inline,
.flow_configure_profile_inline = flow_configure_profile_inline,
+ .flow_async_create_profile_inline = flow_async_create_profile_inline,
+ .flow_async_destroy_profile_inline = flow_async_destroy_profile_inline,
/*
* NT Flow FLM Meter API
*/
@@ -69,6 +69,20 @@ int flow_nic_set_hasher_fields_inline(struct flow_nic_dev *ndev,
int flow_get_flm_stats_profile_inline(struct flow_nic_dev *ndev, uint64_t *data, uint64_t size);
+/*
+ * RTE flow asynchronous operations functions
+ */
+
+struct flow_handle *flow_async_create_profile_inline(struct flow_eth_dev *dev, uint32_t queue_id,
+ const struct rte_flow_op_attr *op_attr,
+ struct flow_template_table *template_table, const struct rte_flow_item pattern[],
+ uint8_t pattern_template_index, const struct rte_flow_action actions[],
+ uint8_t actions_template_index, void *user_data, struct rte_flow_error *error);
+
+int flow_async_destroy_profile_inline(struct flow_eth_dev *dev, uint32_t queue_id,
+ const struct rte_flow_op_attr *op_attr, struct flow_handle *flow,
+ void *user_data, struct rte_flow_error *error);
+
int flow_info_get_profile_inline(struct flow_eth_dev *dev, uint8_t caller_id,
struct rte_flow_port_info *port_info,
struct rte_flow_queue_info *queue_info, struct rte_flow_error *error);
@@ -310,6 +310,21 @@ struct profile_inline_ops {
uint32_t nb_contexts,
struct rte_flow_error *error);
+ /*
+ * RTE flow asynchronous operations functions
+ */
+
+ struct flow_handle *(*flow_async_create_profile_inline)(struct flow_eth_dev *dev,
+ uint32_t queue_id, const struct rte_flow_op_attr *op_attr,
+ struct flow_template_table *template_table, const struct rte_flow_item pattern[],
+ uint8_t rte_pattern_template_index, const struct rte_flow_action actions[],
+ uint8_t rte_actions_template_index, void *user_data, struct rte_flow_error *error);
+
+ int (*flow_async_destroy_profile_inline)(struct flow_eth_dev *dev, uint32_t queue_id,
+ const struct rte_flow_op_attr *op_attr,
+ struct flow_handle *flow, void *user_data,
+ struct rte_flow_error *error);
+
int (*flow_nic_set_hasher_fields_inline)(struct flow_nic_dev *ndev,
int hsh_idx,
struct nt_eth_rss_conf rss_conf);