+union table_rule_match_low_level {
+ struct rte_table_acl_rule_add_params acl_add;
+ struct rte_table_acl_rule_delete_params acl_delete;
+ struct rte_table_array_key array;
+ uint8_t hash[TABLE_RULE_MATCH_SIZE_MAX];
+ struct rte_table_lpm_key lpm_ipv4;
+ struct rte_table_lpm_ipv6_key lpm_ipv6;
+};
+
+static int
+match_convert(struct table_rule_match *mh,
+ union table_rule_match_low_level *ml,
+ int add);
+
+static int
+action_convert(struct rte_table_action *a,
+ struct table_rule_action *action,
+ struct rte_pipeline_table_entry *data);
+
+struct table_ll {
+ struct rte_pipeline *p;
+ int table_id;
+ struct rte_table_action *a;
+ int bulk_supported;
+};
+
+static int
+table_rule_add_bulk_ll(struct table_ll *table,
+ struct table_rule_list *list,
+ uint32_t *n_rules)
+{
+ union table_rule_match_low_level *match_ll = NULL;
+ uint8_t *action_ll = NULL;
+ void **match_ll_ptr = NULL;
+ struct rte_pipeline_table_entry **action_ll_ptr = NULL;
+ struct rte_pipeline_table_entry **entries_ptr = NULL;
+ int *found = NULL;
+ struct table_rule *rule;
+ uint32_t n, i;
+ int status = 0;
+
+ n = 0;
+ TAILQ_FOREACH(rule, list, node)
+ n++;
+
+ /* Memory allocation */
+ match_ll = calloc(n, sizeof(union table_rule_match_low_level));
+ action_ll = calloc(n, TABLE_RULE_ACTION_SIZE_MAX);
+
+ match_ll_ptr = calloc(n, sizeof(void *));
+ action_ll_ptr = calloc(n, sizeof(struct rte_pipeline_table_entry *));
+
+ entries_ptr = calloc(n, sizeof(struct rte_pipeline_table_entry *));
+ found = calloc(n, sizeof(int));
+
+ if (match_ll == NULL ||
+ action_ll == NULL ||
+ match_ll_ptr == NULL ||
+ action_ll_ptr == NULL ||
+ entries_ptr == NULL ||
+ found == NULL) {
+ status = -ENOMEM;
+ goto table_rule_add_bulk_ll_free;
+ }
+
+ /* Init */
+ for (i = 0; i < n; i++) {
+ match_ll_ptr[i] = (void *)&match_ll[i];
+ action_ll_ptr[i] = (struct rte_pipeline_table_entry *)
+ &action_ll[i * TABLE_RULE_ACTION_SIZE_MAX];
+ }
+
+ /* Rule (match, action) conversion */
+ i = 0;
+ TAILQ_FOREACH(rule, list, node) {
+ status = match_convert(&rule->match, match_ll_ptr[i], 1);
+ if (status)
+ goto table_rule_add_bulk_ll_free;
+
+ status = action_convert(table->a, &rule->action, action_ll_ptr[i]);
+ if (status)
+ goto table_rule_add_bulk_ll_free;
+
+ i++;
+ }
+
+ /* Add rule (match, action) to table */
+ if (table->bulk_supported) {
+ status = rte_pipeline_table_entry_add_bulk(table->p,
+ table->table_id,
+ match_ll_ptr,
+ action_ll_ptr,
+ n,
+ found,
+ entries_ptr);
+ if (status)
+ goto table_rule_add_bulk_ll_free;
+ } else
+ for (i = 0; i < n; i++) {
+ status = rte_pipeline_table_entry_add(table->p,
+ table->table_id,
+ match_ll_ptr[i],
+ action_ll_ptr[i],
+ &found[i],
+ &entries_ptr[i]);
+ if (status) {
+ if (i == 0)
+ goto table_rule_add_bulk_ll_free;
+
+ /* No roll-back. */
+ status = 0;
+ n = i;
+ break;
+ }
+ }
+
+ /* Write back to the rule list. */
+ i = 0;
+ TAILQ_FOREACH(rule, list, node) {
+ if (i >= n)
+ break;
+
+ rule->data = entries_ptr[i];
+
+ i++;
+ }
+
+ *n_rules = n;
+
+ /* Free */
+table_rule_add_bulk_ll_free:
+ free(found);
+ free(entries_ptr);
+ free(action_ll_ptr);
+ free(match_ll_ptr);
+ free(action_ll);
+ free(match_ll);
+
+ return status;
+}
+