examples/ip_pipeline: track table rules on add bulk
authorCristian Dumitrescu <cristian.dumitrescu@intel.com>
Tue, 30 Oct 2018 18:04:09 +0000 (18:04 +0000)
committerCristian Dumitrescu <cristian.dumitrescu@intel.com>
Fri, 2 Nov 2018 11:25:05 +0000 (12:25 +0100)
Support table rule tracking on table rule add bulk operation.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
examples/ip_pipeline/cli.c
examples/ip_pipeline/pipeline.h
examples/ip_pipeline/thread.c

index 65600b7..5011cad 100644 (file)
@@ -4523,7 +4523,7 @@ cmd_pipeline_table_rule_add_default(char **tokens,
 
 
 static const char cmd_pipeline_table_rule_add_bulk_help[] =
-"pipeline <pipeline_name> table <table_id> rule add bulk <file_name> <n_rules>\n"
+"pipeline <pipeline_name> table <table_id> rule add bulk <file_name>\n"
 "\n"
 "  File <file_name>:\n"
 "  - line format: match <match> action <action>\n";
@@ -4531,8 +4531,7 @@ static const char cmd_pipeline_table_rule_add_bulk_help[] =
 static int
 cli_rule_file_process(const char *file_name,
        size_t line_len_max,
-       struct table_rule_match *m,
-       struct table_rule_action *a,
+       struct table_rule_list **rule_list,
        uint32_t *n_rules,
        uint32_t *line_number,
        char *out,
@@ -4544,14 +4543,12 @@ cmd_pipeline_table_rule_add_bulk(char **tokens,
        char *out,
        size_t out_size)
 {
-       struct table_rule_match *match;
-       struct table_rule_action *action;
-       void **data;
+       struct table_rule_list *list = NULL;
        char *pipeline_name, *file_name;
-       uint32_t table_id, n_rules, n_rules_parsed, line_number;
+       uint32_t table_id, n_rules, n_rules_added, n_rules_not_added, line_number;
        int status;
 
-       if (n_tokens != 9) {
+       if (n_tokens != 8) {
                snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
                return;
        }
@@ -4585,68 +4582,33 @@ cmd_pipeline_table_rule_add_bulk(char **tokens,
 
        file_name = tokens[7];
 
-       if ((parser_read_uint32(&n_rules, tokens[8]) != 0) ||
-               (n_rules == 0)) {
-               snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
-               return;
-       }
-
-       /* Memory allocation. */
-       match = calloc(n_rules, sizeof(struct table_rule_match));
-       action = calloc(n_rules, sizeof(struct table_rule_action));
-       data = calloc(n_rules, sizeof(void *));
-       if ((match == NULL) || (action == NULL) || (data == NULL)) {
-               snprintf(out, out_size, MSG_OUT_OF_MEMORY);
-               free(data);
-               free(action);
-               free(match);
-               return;
-       }
-
-       /* Load rule file */
-       n_rules_parsed = n_rules;
+       /* Load rules from file. */
        status = cli_rule_file_process(file_name,
                1024,
-               match,
-               action,
-               &n_rules_parsed,
+               &list,
+               &n_rules,
                &line_number,
                out,
                out_size);
        if (status) {
                snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number);
-               free(data);
-               free(action);
-               free(match);
-               return;
-       }
-       if (n_rules_parsed != n_rules) {
-               snprintf(out, out_size, MSG_FILE_NOT_ENOUGH, file_name);
-               free(data);
-               free(action);
-               free(match);
                return;
        }
 
        /* Rule bulk add */
        status = pipeline_table_rule_add_bulk(pipeline_name,
                table_id,
-               match,
-               action,
-               data,
-               &n_rules);
+               list,
+               &n_rules_added,
+               &n_rules_not_added);
        if (status) {
                snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
-               free(data);
-               free(action);
-               free(match);
                return;
        }
 
-       /* Memory free */
-       free(data);
-       free(action);
-       free(match);
+       snprintf(out, out_size, "Added %u rules out of %u.\n",
+               n_rules_added,
+               n_rules);
 }
 
 
@@ -5950,44 +5912,56 @@ cli_script_process(const char *file_name,
 static int
 cli_rule_file_process(const char *file_name,
        size_t line_len_max,
-       struct table_rule_match *m,
-       struct table_rule_action *a,
+       struct table_rule_list **rule_list,
        uint32_t *n_rules,
        uint32_t *line_number,
        char *out,
        size_t out_size)
 {
-       FILE *f = NULL;
+       struct table_rule_list *list = NULL;
        char *line = NULL;
-       uint32_t rule_id, line_id;
+       FILE *f = NULL;
+       uint32_t rule_id = 0, line_id = 0;
        int status = 0;
 
        /* Check input arguments */
        if ((file_name == NULL) ||
                (strlen(file_name) == 0) ||
-               (line_len_max == 0)) {
-               *line_number = 0;
-               return -EINVAL;
+               (line_len_max == 0) ||
+               (rule_list == NULL) ||
+               (n_rules == NULL) ||
+               (line_number == NULL) ||
+               (out == NULL)) {
+               status = -EINVAL;
+               goto cli_rule_file_process_free;
        }
 
        /* Memory allocation */
+       list = malloc(sizeof(struct table_rule_list));
+       if (list == NULL) {
+               status = -ENOMEM;
+               goto cli_rule_file_process_free;
+       }
+
+       TAILQ_INIT(list);
+
        line = malloc(line_len_max + 1);
        if (line == NULL) {
-               *line_number = 0;
-               return -ENOMEM;
+               status = -ENOMEM;
+               goto cli_rule_file_process_free;
        }
 
        /* Open file */
        f = fopen(file_name, "r");
        if (f == NULL) {
-               *line_number = 0;
-               free(line);
-               return -EIO;
+               status = -EIO;
+               goto cli_rule_file_process_free;
        }
 
        /* Read file */
-       for (line_id = 1, rule_id = 0; rule_id < *n_rules; line_id++) {
+       for (line_id = 1, rule_id = 0; ; line_id++) {
                char *tokens[CMD_MAX_TOKENS];
+               struct table_rule *rule = NULL;
                uint32_t n_tokens, n_tokens_parsed, t0;
 
                /* Read next line from file. */
@@ -6003,7 +5977,7 @@ cli_rule_file_process(const char *file_name,
                status = parse_tokenize_string(line, tokens, &n_tokens);
                if (status) {
                        status = -EINVAL;
-                       break;
+                       goto cli_rule_file_process_free;
                }
 
                /* Empty line. */
@@ -6011,15 +5985,24 @@ cli_rule_file_process(const char *file_name,
                        continue;
                t0 = 0;
 
+               /* Rule alloc and insert. */
+               rule = calloc(1, sizeof(struct table_rule));
+               if (rule == NULL) {
+                       status = -ENOMEM;
+                       goto cli_rule_file_process_free;
+               }
+
+               TAILQ_INSERT_TAIL(list, rule, node);
+
                /* Rule match. */
                n_tokens_parsed = parse_match(tokens + t0,
                        n_tokens - t0,
                        out,
                        out_size,
-                       &m[rule_id]);
+                       &rule->match);
                if (n_tokens_parsed == 0) {
                        status = -EINVAL;
-                       break;
+                       goto cli_rule_file_process_free;
                }
                t0 += n_tokens_parsed;
 
@@ -6028,17 +6011,17 @@ cli_rule_file_process(const char *file_name,
                        n_tokens - t0,
                        out,
                        out_size,
-                       &a[rule_id]);
+                       &rule->action);
                if (n_tokens_parsed == 0) {
                        status = -EINVAL;
-                       break;
+                       goto cli_rule_file_process_free;
                }
                t0 += n_tokens_parsed;
 
                /* Line completed. */
                if (t0 < n_tokens) {
                        status = -EINVAL;
-                       break;
+                       goto cli_rule_file_process_free;
                }
 
                /* Increment rule count */
@@ -6051,7 +6034,31 @@ cli_rule_file_process(const char *file_name,
        /* Memory free */
        free(line);
 
+       *rule_list = list;
+       *n_rules = rule_id;
+       *line_number = line_id;
+       return 0;
+
+cli_rule_file_process_free:
+       *rule_list = NULL;
        *n_rules = rule_id;
        *line_number = line_id;
+
+       for ( ; ; ) {
+               struct table_rule *rule;
+
+               rule = TAILQ_FIRST(list);
+               if (rule == NULL)
+                       break;
+
+               TAILQ_REMOVE(list, rule, node);
+               free(rule);
+       }
+
+       if (f)
+               fclose(f);
+       free(line);
+       free(list);
+
        return status;
 }
index 58067ed..8a364a9 100644 (file)
@@ -334,10 +334,9 @@ pipeline_table_rule_add(const char *pipeline_name,
 int
 pipeline_table_rule_add_bulk(const char *pipeline_name,
        uint32_t table_id,
-       struct table_rule_match *match,
-       struct table_rule_action *action,
-       void **data,
-       uint32_t *n_rules);
+       struct table_rule_list *list,
+       uint32_t *n_rules_added,
+       uint32_t *n_rules_not_added);
 
 int
 pipeline_table_rule_add_default(const char *pipeline_name,
index 5019de9..2c0570f 100644 (file)
@@ -609,10 +609,7 @@ struct pipeline_msg_req_table_rule_add_default {
 };
 
 struct pipeline_msg_req_table_rule_add_bulk {
-       struct table_rule_match *match;
-       struct table_rule_action *action;
-       void **data;
-       uint32_t n_rules;
+       struct table_rule_list *list;
        int bulk;
 };
 
@@ -1206,6 +1203,128 @@ 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;
+}
+
 int
 pipeline_table_rule_add(const char *pipeline_name,
        uint32_t table_id,
@@ -1408,156 +1527,119 @@ pipeline_table_rule_add_default(const char *pipeline_name,
        return status;
 }
 
+static uint32_t
+table_rule_list_free(struct table_rule_list *list)
+{
+       uint32_t n = 0;
+
+       if (!list)
+               return 0;
+
+       for ( ; ; ) {
+               struct table_rule *rule;
+
+               rule = TAILQ_FIRST(list);
+               if (rule == NULL)
+                       break;
+
+               TAILQ_REMOVE(list, rule, node);
+               free(rule);
+               n++;
+       }
+
+       free(list);
+       return n;
+}
+
 int
 pipeline_table_rule_add_bulk(const char *pipeline_name,
        uint32_t table_id,
-       struct table_rule_match *match,
-       struct table_rule_action *action,
-       void **data,
-       uint32_t *n_rules)
+       struct table_rule_list *list,
+       uint32_t *n_rules_added,
+       uint32_t *n_rules_not_added)
 {
        struct pipeline *p;
+       struct table *table;
        struct pipeline_msg_req *req;
        struct pipeline_msg_rsp *rsp;
-       uint32_t i;
-       int status;
+       struct table_rule *rule;
+       int status = 0;
 
        /* Check input params */
        if ((pipeline_name == NULL) ||
-               (match == NULL) ||
-               (action == NULL) ||
-               (data == NULL) ||
-               (n_rules == NULL) ||
-               (*n_rules == 0))
-               return -1;
+               (list == NULL) ||
+               TAILQ_EMPTY(list) ||
+               (n_rules_added == NULL) ||
+               (n_rules_not_added == NULL)) {
+               table_rule_list_free(list);
+               return -EINVAL;
+       }
 
        p = pipeline_find(pipeline_name);
        if ((p == NULL) ||
-               (table_id >= p->n_tables))
-               return -1;
-
-       for (i = 0; i < *n_rules; i++)
-               if (match_check(match, p, table_id) ||
-                       action_check(action, p, table_id))
-                       return -1;
-
-       if (!pipeline_is_running(p)) {
-               struct rte_table_action *a = p->table[table_id].a;
-               union table_rule_match_low_level *match_ll;
-               uint8_t *action_ll;
-               void **match_ll_ptr;
-               struct rte_pipeline_table_entry **action_ll_ptr;
-               struct rte_pipeline_table_entry **entries_ptr =
-                       (struct rte_pipeline_table_entry **)data;
-               uint32_t bulk =
-                       (p->table[table_id].params.match_type == TABLE_ACL) ? 1 : 0;
-               int *found;
-
-               /* Memory allocation */
-               match_ll = calloc(*n_rules, sizeof(union table_rule_match_low_level));
-               action_ll = calloc(*n_rules, TABLE_RULE_ACTION_SIZE_MAX);
-               match_ll_ptr = calloc(*n_rules, sizeof(void *));
-               action_ll_ptr =
-                       calloc(*n_rules, sizeof(struct rte_pipeline_table_entry *));
-               found = calloc(*n_rules, sizeof(int));
-
-               if (match_ll == NULL ||
-                       action_ll == NULL ||
-                       match_ll_ptr == NULL ||
-                       action_ll_ptr == NULL ||
-                       found == NULL)
-                       goto fail;
-
-               for (i = 0; i < *n_rules; 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];
-               }
+               (table_id >= p->n_tables)) {
+               table_rule_list_free(list);
+               return -EINVAL;
+       }
 
-               /* Rule match conversion */
-               for (i = 0; i < *n_rules; i++) {
-                       status = match_convert(&match[i], match_ll_ptr[i], 1);
-                       if (status)
-                               goto fail;
-               }
+       table = &p->table[table_id];
 
-               /* Rule action conversion */
-               for (i = 0; i < *n_rules; i++) {
-                       status = action_convert(a, &action[i], action_ll_ptr[i]);
-                       if (status)
-                               goto fail;
+       TAILQ_FOREACH(rule, list, node)
+               if (match_check(&rule->match, p, table_id) ||
+                       action_check(&rule->action, p, table_id)) {
+                       table_rule_list_free(list);
+                       return -EINVAL;
                }
 
-               /* Add rule (match, action) to table */
-               if (bulk) {
-                       status = rte_pipeline_table_entry_add_bulk(p->p,
-                               table_id,
-                               match_ll_ptr,
-                               action_ll_ptr,
-                               *n_rules,
-                               found,
-                               entries_ptr);
-                       if (status)
-                               *n_rules = 0;
-               } else {
-                       for (i = 0; i < *n_rules; i++) {
-                               status = rte_pipeline_table_entry_add(p->p,
-                                       table_id,
-                                       match_ll_ptr[i],
-                                       action_ll_ptr[i],
-                                       &found[i],
-                                       &entries_ptr[i]);
-                               if (status) {
-                                       *n_rules = i;
-                                       break;
-                               }
-                       }
+       if (!pipeline_is_running(p)) {
+               struct table_ll table_ll = {
+                       .p = p->p,
+                       .table_id = table_id,
+                       .a = table->a,
+                       .bulk_supported = table->params.match_type == TABLE_ACL,
+               };
+
+               status = table_rule_add_bulk_ll(&table_ll, list, n_rules_added);
+               if (status) {
+                       table_rule_list_free(list);
+                       return status;
                }
 
-               /* Free */
-               free(found);
-               free(action_ll_ptr);
-               free(match_ll_ptr);
-               free(action_ll);
-               free(match_ll);
-
-               return status;
-
-fail:
-               free(found);
-               free(action_ll_ptr);
-               free(match_ll_ptr);
-               free(action_ll);
-               free(match_ll);
-
-               *n_rules = 0;
-               return -1;
+               table_rule_add_bulk(table, list, *n_rules_added);
+               *n_rules_not_added = table_rule_list_free(list);
+               return 0;
        }
 
        /* Allocate request */
        req = pipeline_msg_alloc();
-       if (req == NULL)
-               return -1;
+       if (req == NULL) {
+               table_rule_list_free(list);
+               return -ENOMEM;
+       }
 
        /* Write request */
        req->type = PIPELINE_REQ_TABLE_RULE_ADD_BULK;
        req->id = table_id;
-       req->table_rule_add_bulk.match = match;
-       req->table_rule_add_bulk.action = action;
-       req->table_rule_add_bulk.data = data;
-       req->table_rule_add_bulk.n_rules = *n_rules;
-       req->table_rule_add_bulk.bulk =
-               (p->table[table_id].params.match_type == TABLE_ACL) ? 1 : 0;
+       req->table_rule_add_bulk.list = list;
+       req->table_rule_add_bulk.bulk = table->params.match_type == TABLE_ACL;
 
        /* Send request and wait for response */
        rsp = pipeline_msg_send_recv(p, req);
-       if (rsp == NULL)
-               return -1;
+       if (rsp == NULL) {
+               table_rule_list_free(list);
+               return -ENOMEM;
+       }
 
        /* Read response */
        status = rsp->status;
-       if (status == 0)
-               *n_rules = rsp->table_rule_add_bulk.n_rules;
+       if (status == 0) {
+               *n_rules_added = rsp->table_rule_add_bulk.n_rules;
+
+               table_rule_add_bulk(table, list, *n_rules_added);
+               *n_rules_not_added = table_rule_list_free(list);
+       } else
+               table_rule_list_free(list);
+
 
        /* Free response */
        pipeline_msg_free(rsp);
@@ -2626,107 +2708,32 @@ static struct pipeline_msg_rsp *
 pipeline_msg_handle_table_rule_add_bulk(struct pipeline_data *p,
        struct pipeline_msg_req *req)
 {
-
        struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
 
        uint32_t table_id = req->id;
-       struct table_rule_match *match = req->table_rule_add_bulk.match;
-       struct table_rule_action *action = req->table_rule_add_bulk.action;
-       struct rte_pipeline_table_entry **data =
-               (struct rte_pipeline_table_entry **)req->table_rule_add_bulk.data;
-       uint32_t n_rules = req->table_rule_add_bulk.n_rules;
+       struct table_rule_list *list = req->table_rule_add_bulk.list;
        uint32_t bulk = req->table_rule_add_bulk.bulk;
 
-       struct rte_table_action *a = p->table_data[table_id].a;
-       union table_rule_match_low_level *match_ll;
-       uint8_t *action_ll;
-       void **match_ll_ptr;
-       struct rte_pipeline_table_entry **action_ll_ptr;
-       int *found, status;
-       uint32_t i;
-
-       /* Memory allocation */
-       match_ll = calloc(n_rules, sizeof(union table_rule_match_low_level));
-       action_ll = calloc(n_rules, TABLE_RULE_ACTION_SIZE_MAX);
-       match_ll_ptr = calloc(n_rules, sizeof(void *));
-       action_ll_ptr =
-               calloc(n_rules, sizeof(struct rte_pipeline_table_entry *));
-       found = calloc(n_rules, sizeof(int));
-
-       if ((match_ll == NULL) ||
-               (action_ll == NULL) ||
-               (match_ll_ptr == NULL) ||
-               (action_ll_ptr == NULL) ||
-               (found == NULL))
-               goto fail;
-
-       for (i = 0; i < n_rules; 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];
-       }
+       uint32_t n_rules_added;
+       int status;
 
-       /* Rule match conversion */
-       for (i = 0; i < n_rules; i++) {
-               status = match_convert(&match[i], match_ll_ptr[i], 1);
-               if (status)
-                       goto fail;
-       }
+       struct table_ll table_ll = {
+               .p = p->p,
+               .table_id = table_id,
+               .a = p->table_data[table_id].a,
+               .bulk_supported = bulk,
+       };
 
-       /* Rule action conversion */
-       for (i = 0; i < n_rules; i++) {
-               status = action_convert(a, &action[i], action_ll_ptr[i]);
-               if (status)
-                       goto fail;
+       status = table_rule_add_bulk_ll(&table_ll, list, &n_rules_added);
+       if (status) {
+               rsp->status = -1;
+               rsp->table_rule_add_bulk.n_rules = 0;
+               return rsp;
        }
 
-       /* Add rule (match, action) to table */
-       if (bulk) {
-               status = rte_pipeline_table_entry_add_bulk(p->p,
-                       table_id,
-                       match_ll_ptr,
-                       action_ll_ptr,
-                       n_rules,
-                       found,
-                       data);
-               if (status)
-                       n_rules = 0;
-       } else
-               for (i = 0; i < n_rules; i++) {
-                       status = rte_pipeline_table_entry_add(p->p,
-                               table_id,
-                               match_ll_ptr[i],
-                               action_ll_ptr[i],
-                               &found[i],
-                               &data[i]);
-                       if (status) {
-                               n_rules = i;
-                               break;
-                       }
-               }
-
        /* Write response */
        rsp->status = 0;
-       rsp->table_rule_add_bulk.n_rules = n_rules;
-
-       /* Free */
-       free(found);
-       free(action_ll_ptr);
-       free(match_ll_ptr);
-       free(action_ll);
-       free(match_ll);
-
-       return rsp;
-
-fail:
-       free(found);
-       free(action_ll_ptr);
-       free(match_ll_ptr);
-       free(action_ll);
-       free(match_ll);
-
-       rsp->status = -1;
-       rsp->table_rule_add_bulk.n_rules = 0;
+       rsp->table_rule_add_bulk.n_rules = n_rules_added;
        return rsp;
 }