X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=examples%2Fpipeline%2Fcli.c;h=edae63dae686893ff2031c6b12ef7f77deb23dbf;hb=a4c1146c754b4b8cceb1c615df2a20138c09d25a;hp=5800cc98edac7eec0e83254e6211ea0c4a747adf;hpb=03665a4893e456cd3255557837137c958700abde;p=dpdk.git diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c index 5800cc98ed..edae63dae6 100644 --- a/examples/pipeline/cli.c +++ b/examples/pipeline/cli.c @@ -10,7 +10,9 @@ #include #include #include +#include #include +#include #include #include @@ -53,7 +55,7 @@ parser_read_uint64(uint64_t *value, const char *p) if (!isdigit(*p)) return -EINVAL; - val = strtoul(p, &next, 10); + val = strtoul(p, &next, 0); if (p == next) return -EINVAL; @@ -374,7 +376,7 @@ print_link_info(struct link *link, char *out, size_t out_size) snprintf(out, out_size, "\n" "%s: flags=<%s> mtu %u\n" - "\tether %02X:%02X:%02X:%02X:%02X:%02X rxqueues %u txqueues %u\n" + "\tether " RTE_ETHER_ADDR_PRT_FMT " rxqueues %u txqueues %u\n" "\tport# %u speed %s\n" "\tRX packets %" PRIu64" bytes %" PRIu64"\n" "\tRX errors %" PRIu64" missed %" PRIu64" no-mbuf %" PRIu64"\n" @@ -383,9 +385,7 @@ print_link_info(struct link *link, char *out, size_t out_size) link->name, eth_link.link_status == 0 ? "DOWN" : "UP", mtu, - mac_addr.addr_bytes[0], mac_addr.addr_bytes[1], - mac_addr.addr_bytes[2], mac_addr.addr_bytes[3], - mac_addr.addr_bytes[4], mac_addr.addr_bytes[5], + RTE_ETHER_ADDR_BYTES(&mac_addr), link->n_rxq, link->n_txq, link->port_id, @@ -444,6 +444,80 @@ cmd_link_show(char **tokens, } } +static const char cmd_ring_help[] = +"ring size numa \n"; + +static void +cmd_ring(char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size, + void *obj) +{ + struct ring_params p; + char *name; + struct ring *ring; + + if (n_tokens != 6) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } + + name = tokens[1]; + + if (strcmp(tokens[2], "size") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); + return; + } + + if (parser_read_uint32(&p.size, tokens[3]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "size"); + return; + } + + if (strcmp(tokens[4], "numa") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "numa"); + return; + } + + if (parser_read_uint32(&p.numa_node, tokens[5]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "numa_node"); + return; + } + + ring = ring_create(obj, name, &p); + if (!ring) { + snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); + return; + } +} + +static const char cmd_tap_help[] = +"tap \n"; + +static void +cmd_tap(char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size, + void *obj) +{ + struct tap *tap; + char *name; + + if (n_tokens < 2) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } + name = tokens[1]; + + tap = tap_create(obj, name); + if (tap == NULL) { + snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); + return; + } +} + static const char cmd_pipeline_create_help[] = "pipeline create \n"; @@ -480,7 +554,9 @@ cmd_pipeline_create(char **tokens, static const char cmd_pipeline_port_in_help[] = "pipeline port in \n" " link rxq bsz \n" -" source \n"; +" ring bsz \n" +" | source loop \n" +" | tap mempool mtu bsz \n"; static void cmd_pipeline_port_in(char **tokens, @@ -567,11 +643,46 @@ cmd_pipeline_port_in(char **tokens, port_id, "ethdev", ¶ms); + } else if (strcmp(tokens[t0], "ring") == 0) { + struct rte_swx_port_ring_reader_params params; + struct ring *ring; + + if (n_tokens < t0 + 4) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline port in ring"); + return; + } + + ring = ring_find(obj, tokens[t0 + 1]); + if (!ring) { + snprintf(out, out_size, MSG_ARG_INVALID, + "ring_name"); + return; + } + params.name = ring->name; + + if (strcmp(tokens[t0 + 2], "bsz") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz"); + return; + } + + if (parser_read_uint32(¶ms.burst_size, tokens[t0 + 3])) { + snprintf(out, out_size, MSG_ARG_INVALID, + "burst_size"); + return; + } + + t0 += 4; + + status = rte_swx_pipeline_port_in_config(p->p, + port_id, + "ring", + ¶ms); } else if (strcmp(tokens[t0], "source") == 0) { struct rte_swx_port_source_params params; struct mempool *mp; - if (n_tokens < t0 + 3) { + if (n_tokens < t0 + 5) { snprintf(out, out_size, MSG_ARG_MISMATCH, "pipeline port in source"); return; @@ -587,12 +698,85 @@ cmd_pipeline_port_in(char **tokens, params.file_name = tokens[t0 + 2]; - t0 += 3; + if (strcmp(tokens[t0 + 3], "loop") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "loop"); + return; + } + + if (parser_read_uint64(¶ms.n_loops, tokens[t0 + 4])) { + snprintf(out, out_size, MSG_ARG_INVALID, + "n_loops"); + return; + } + + t0 += 5; status = rte_swx_pipeline_port_in_config(p->p, port_id, "source", ¶ms); + } else if (strcmp(tokens[t0], "tap") == 0) { + struct rte_swx_port_fd_reader_params params; + struct tap *tap; + struct mempool *mp; + + if (n_tokens < t0 + 8) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline port in tap"); + return; + } + + tap = tap_find(obj, tokens[t0 + 1]); + if (!tap) { + snprintf(out, out_size, MSG_ARG_INVALID, + "tap_name"); + return; + } + params.fd = tap->fd; + + if (strcmp(tokens[t0 + 2], "mempool") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, + "mempool"); + return; + } + + mp = mempool_find(obj, tokens[t0 + 3]); + if (!mp) { + snprintf(out, out_size, MSG_ARG_INVALID, + "mempool_name"); + return; + } + params.mempool = mp->m; + + if (strcmp(tokens[t0 + 4], "mtu") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, + "mtu"); + return; + } + + if (parser_read_uint32(¶ms.mtu, tokens[t0 + 5]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "mtu"); + return; + } + + if (strcmp(tokens[t0 + 6], "bsz") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz"); + return; + } + + if (parser_read_uint32(¶ms.burst_size, tokens[t0 + 7])) { + snprintf(out, out_size, MSG_ARG_INVALID, + "burst_size"); + return; + } + + t0 += 8; + + status = rte_swx_pipeline_port_in_config(p->p, + port_id, + "fd", + ¶ms); + } else { snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); return; @@ -612,7 +796,9 @@ cmd_pipeline_port_in(char **tokens, static const char cmd_pipeline_port_out_help[] = "pipeline port out \n" " link txq bsz \n" -" | sink | none\n"; +" ring bsz \n" +" | sink | none\n" +" | tap bsz \n"; static void cmd_pipeline_port_out(char **tokens, @@ -699,6 +885,41 @@ cmd_pipeline_port_out(char **tokens, port_id, "ethdev", ¶ms); + } else if (strcmp(tokens[t0], "ring") == 0) { + struct rte_swx_port_ring_writer_params params; + struct ring *ring; + + if (n_tokens < t0 + 4) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline port out link"); + return; + } + + ring = ring_find(obj, tokens[t0 + 1]); + if (!ring) { + snprintf(out, out_size, MSG_ARG_INVALID, + "ring_name"); + return; + } + params.name = ring->name; + + if (strcmp(tokens[t0 + 2], "bsz") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz"); + return; + } + + if (parser_read_uint32(¶ms.burst_size, tokens[t0 + 3])) { + snprintf(out, out_size, MSG_ARG_INVALID, + "burst_size"); + return; + } + + t0 += 4; + + status = rte_swx_pipeline_port_out_config(p->p, + port_id, + "ring", + ¶ms); } else if (strcmp(tokens[t0], "sink") == 0) { struct rte_swx_port_sink_params params; @@ -711,6 +932,41 @@ cmd_pipeline_port_out(char **tokens, port_id, "sink", ¶ms); + } else if (strcmp(tokens[t0], "tap") == 0) { + struct rte_swx_port_fd_writer_params params; + struct tap *tap; + + if (n_tokens < t0 + 4) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline port out tap"); + return; + } + + tap = tap_find(obj, tokens[t0 + 1]); + if (!tap) { + snprintf(out, out_size, MSG_ARG_INVALID, + "tap_name"); + return; + } + params.fd = tap->fd; + + if (strcmp(tokens[t0 + 2], "bsz") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz"); + return; + } + + if (parser_read_uint32(¶ms.burst_size, tokens[t0 + 3])) { + snprintf(out, out_size, MSG_ARG_INVALID, + "burst_size"); + return; + } + + t0 += 4; + + status = rte_swx_pipeline_port_out_config(p->p, + port_id, + "fd", + ¶ms); } else { snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); return; @@ -779,25 +1035,88 @@ cmd_pipeline_build(char **tokens, } } -static const char cmd_pipeline_table_update_help[] = -"pipeline table update " -" "; +static void +table_entry_free(struct rte_swx_table_entry *entry) +{ + if (!entry) + return; + + free(entry->key); + free(entry->key_mask); + free(entry->action_data); + free(entry); +} + +#ifndef MAX_LINE_SIZE +#define MAX_LINE_SIZE 2048 +#endif + +static int +pipeline_table_entries_add(struct rte_swx_ctl_pipeline *p, + const char *table_name, + FILE *file, + uint32_t *file_line_number) +{ + char *line = NULL; + uint32_t line_id = 0; + int status = 0; + + /* Buffer allocation. */ + line = malloc(MAX_LINE_SIZE); + if (!line) + return -ENOMEM; + + /* File read. */ + for (line_id = 1; ; line_id++) { + struct rte_swx_table_entry *entry; + int is_blank_or_comment; + + if (fgets(line, MAX_LINE_SIZE, file) == NULL) + break; + + entry = rte_swx_ctl_pipeline_table_entry_read(p, + table_name, + line, + &is_blank_or_comment); + if (!entry) { + if (is_blank_or_comment) + continue; + + status = -EINVAL; + goto error; + } + + status = rte_swx_ctl_pipeline_table_entry_add(p, + table_name, + entry); + table_entry_free(entry); + if (status) + goto error; + } + +error: + free(line); + *file_line_number = line_id; + return status; +} + +static const char cmd_pipeline_table_add_help[] = +"pipeline table add \n"; static void -cmd_pipeline_table_update(char **tokens, - uint32_t n_tokens, - char *out, - size_t out_size, - void *obj) +cmd_pipeline_table_add(char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size, + void *obj) { struct pipeline *p; - char *pipeline_name, *table_name, *line = NULL; - char *file_name_add, *file_name_delete, *file_name_default; - FILE *file_add = NULL, *file_delete = NULL, *file_default = NULL; - uint32_t line_id; + char *pipeline_name, *table_name, *file_name; + FILE *file = NULL; + uint32_t file_line_number = 0; int status; - if (n_tokens != 8) { + if (n_tokens != 6) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } @@ -809,174 +1128,1383 @@ cmd_pipeline_table_update(char **tokens, return; } - if (strcmp(tokens[2], "table") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); - return; - } - table_name = tokens[3]; - if (strcmp(tokens[4], "update") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "update"); + file_name = tokens[5]; + file = fopen(file_name, "r"); + if (!file) { + snprintf(out, out_size, "Cannot open file %s.\n", file_name); return; } - file_name_add = tokens[5]; - file_name_delete = tokens[6]; - file_name_default = tokens[7]; + status = pipeline_table_entries_add(p->ctl, + table_name, + file, + &file_line_number); + if (status) + snprintf(out, out_size, "Invalid entry in file %s at line %u\n", + file_name, + file_line_number); - /* File open. */ - if (strcmp(file_name_add, "none")) { - file_add = fopen(file_name_add, "r"); - if (!file_add) { - snprintf(out, out_size, "Cannot open file %s", - file_name_add); - goto error; - } - } + fclose(file); +} + +static int +pipeline_table_entries_delete(struct rte_swx_ctl_pipeline *p, + const char *table_name, + FILE *file, + uint32_t *file_line_number) +{ + char *line = NULL; + uint32_t line_id = 0; + int status = 0; - if (strcmp(file_name_delete, "none")) { - file_delete = fopen(file_name_delete, "r"); - if (!file_delete) { - snprintf(out, out_size, "Cannot open file %s", - file_name_delete); + /* Buffer allocation. */ + line = malloc(MAX_LINE_SIZE); + if (!line) + return -ENOMEM; + + /* File read. */ + for (line_id = 1; ; line_id++) { + struct rte_swx_table_entry *entry; + int is_blank_or_comment; + + if (fgets(line, MAX_LINE_SIZE, file) == NULL) + break; + + entry = rte_swx_ctl_pipeline_table_entry_read(p, + table_name, + line, + &is_blank_or_comment); + if (!entry) { + if (is_blank_or_comment) + continue; + + status = -EINVAL; goto error; } - } - if (strcmp(file_name_default, "none")) { - file_default = fopen(file_name_default, "r"); - if (!file_default) { - snprintf(out, out_size, "Cannot open file %s", - file_name_default); + status = rte_swx_ctl_pipeline_table_entry_delete(p, + table_name, + entry); + table_entry_free(entry); + if (status) goto error; - } } - if (!file_add && !file_delete && !file_default) { - snprintf(out, out_size, "Nothing to be done."); +error: + *file_line_number = line_id; + free(line); + return status; +} + +static const char cmd_pipeline_table_delete_help[] = +"pipeline table delete \n"; + +static void +cmd_pipeline_table_delete(char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size, + void *obj) +{ + struct pipeline *p; + char *pipeline_name, *table_name, *file_name; + FILE *file = NULL; + uint32_t file_line_number = 0; + int status; + + if (n_tokens != 6) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } - /* Buffer allocation. */ - line = malloc(2048); - if (!line) { - snprintf(out, out_size, MSG_OUT_OF_MEMORY); - goto error; + pipeline_name = tokens[1]; + p = pipeline_find(obj, pipeline_name); + if (!p || !p->ctl) { + snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); + return; } - /* Add. */ - if (file_add) - for (line_id = 1; ; line_id++) { - struct rte_swx_table_entry *entry; + table_name = tokens[3]; - if (fgets(line, 2048, file_add) == NULL) - break; + file_name = tokens[5]; + file = fopen(file_name, "r"); + if (!file) { + snprintf(out, out_size, "Cannot open file %s.\n", file_name); + return; + } - entry = rte_swx_ctl_pipeline_table_entry_read(p->ctl, - table_name, - line); - if (!entry) { - snprintf(out, out_size, MSG_FILE_ERR, - file_name_add, line_id); - goto error; - } + status = pipeline_table_entries_delete(p->ctl, + table_name, + file, + &file_line_number); + if (status) + snprintf(out, out_size, "Invalid entry in file %s at line %u\n", + file_name, + file_line_number); - status = rte_swx_ctl_pipeline_table_entry_add(p->ctl, - table_name, - entry); - if (status) { - snprintf(out, out_size, - "Invalid entry in file %s at line %u", - file_name_add, line_id); - goto error; - } - } + fclose(file); +} +static int +pipeline_table_default_entry_add(struct rte_swx_ctl_pipeline *p, + const char *table_name, + FILE *file, + uint32_t *file_line_number) +{ + char *line = NULL; + uint32_t line_id = 0; + int status = 0; - /* Delete. */ - if (file_delete) - for (line_id = 1; ; line_id++) { - struct rte_swx_table_entry *entry; + /* Buffer allocation. */ + line = malloc(MAX_LINE_SIZE); + if (!line) + return -ENOMEM; - if (fgets(line, 2048, file_delete) == NULL) - break; + /* File read. */ + for (line_id = 1; ; line_id++) { + struct rte_swx_table_entry *entry; + int is_blank_or_comment; - entry = rte_swx_ctl_pipeline_table_entry_read(p->ctl, - table_name, - line); - if (!entry) { - snprintf(out, out_size, MSG_FILE_ERR, - file_name_delete, line_id); - goto error; - } + if (fgets(line, MAX_LINE_SIZE, file) == NULL) + break; - status = rte_swx_ctl_pipeline_table_entry_delete(p->ctl, - table_name, - entry); - if (status) { - snprintf(out, out_size, - "Invalid entry in file %s at line %u", - file_name_delete, line_id); - goto error; - } - } + entry = rte_swx_ctl_pipeline_table_entry_read(p, + table_name, + line, + &is_blank_or_comment); + if (!entry) { + if (is_blank_or_comment) + continue; - /* Default. */ - if (file_default) - for (line_id = 1; ; line_id++) { - struct rte_swx_table_entry *entry; + status = -EINVAL; + goto error; + } - if (fgets(line, 2048, file_default) == NULL) - break; + status = rte_swx_ctl_pipeline_table_default_entry_add(p, + table_name, + entry); + table_entry_free(entry); + if (status) + goto error; + } - entry = rte_swx_ctl_pipeline_table_entry_read(p->ctl, - table_name, - line); - if (!entry) { - snprintf(out, out_size, MSG_FILE_ERR, - file_name_default, line_id); - goto error; - } +error: + *file_line_number = line_id; + free(line); + return status; +} + +static const char cmd_pipeline_table_default_help[] = +"pipeline table default \n"; + +static void +cmd_pipeline_table_default(char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size, + void *obj) +{ + struct pipeline *p; + char *pipeline_name, *table_name, *file_name; + FILE *file = NULL; + uint32_t file_line_number = 0; + int status; + + if (n_tokens != 6) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } + + pipeline_name = tokens[1]; + p = pipeline_find(obj, pipeline_name); + if (!p || !p->ctl) { + snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); + return; + } + + table_name = tokens[3]; + + file_name = tokens[5]; + file = fopen(file_name, "r"); + if (!file) { + snprintf(out, out_size, "Cannot open file %s.\n", file_name); + return; + } + + status = pipeline_table_default_entry_add(p->ctl, + table_name, + file, + &file_line_number); + if (status) + snprintf(out, out_size, "Invalid entry in file %s at line %u\n", + file_name, + file_line_number); + + fclose(file); +} + +static const char cmd_pipeline_table_show_help[] = +"pipeline table show [filename]\n"; + +static void +cmd_pipeline_table_show(char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size, + void *obj) +{ + struct pipeline *p; + char *pipeline_name, *table_name; + FILE *file = NULL; + int status; + + if (n_tokens != 5 && n_tokens != 6) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } + + pipeline_name = tokens[1]; + p = pipeline_find(obj, pipeline_name); + if (!p || !p->ctl) { + snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); + return; + } + + table_name = tokens[3]; + file = (n_tokens == 6) ? fopen(tokens[5], "w") : stdout; + if (!file) { + snprintf(out, out_size, "Cannot open file %s.\n", tokens[5]); + return; + } + + status = rte_swx_ctl_pipeline_table_fprintf(file, p->ctl, table_name); + if (status) + snprintf(out, out_size, MSG_ARG_INVALID, "table_name"); + + if (file) + fclose(file); +} + +static const char cmd_pipeline_selector_group_add_help[] = +"pipeline selector group add\n"; + +static void +cmd_pipeline_selector_group_add(char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size, + void *obj) +{ + struct pipeline *p; + char *pipeline_name, *selector_name; + uint32_t group_id; + int status; + + if (n_tokens != 6) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } + + pipeline_name = tokens[1]; + p = pipeline_find(obj, pipeline_name); + if (!p || !p->ctl) { + snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); + return; + } + + if (strcmp(tokens[2], "selector") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "selector"); + return; + } + + selector_name = tokens[3]; + + if (strcmp(tokens[4], "group") || + strcmp(tokens[5], "add")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "group add"); + return; + } + + status = rte_swx_ctl_pipeline_selector_group_add(p->ctl, + selector_name, + &group_id); + if (status) + snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); + else + snprintf(out, out_size, "Group ID: %u\n", group_id); +} + +static const char cmd_pipeline_selector_group_delete_help[] = +"pipeline selector group delete \n"; + +static void +cmd_pipeline_selector_group_delete(char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size, + void *obj) +{ + struct pipeline *p; + char *pipeline_name, *selector_name; + uint32_t group_id; + int status; + + if (n_tokens != 7) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } + + pipeline_name = tokens[1]; + p = pipeline_find(obj, pipeline_name); + if (!p || !p->ctl) { + snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); + return; + } + + if (strcmp(tokens[2], "selector") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "selector"); + return; + } + + selector_name = tokens[3]; + + if (strcmp(tokens[4], "group") || + strcmp(tokens[5], "delete")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "group delete"); + return; + } + + if (parser_read_uint32(&group_id, tokens[6]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "group_id"); + return; + } + + status = rte_swx_ctl_pipeline_selector_group_delete(p->ctl, + selector_name, + group_id); + if (status) + snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); +} + +#define GROUP_MEMBER_INFO_TOKENS_MAX 6 + +static int +token_is_comment(const char *token) +{ + if ((token[0] == '#') || + (token[0] == ';') || + ((token[0] == '/') && (token[1] == '/'))) + return 1; /* TRUE. */ + + return 0; /* FALSE. */ +} + +static int +pipeline_selector_group_member_read(const char *string, + uint32_t *group_id, + uint32_t *member_id, + uint32_t *weight, + int *is_blank_or_comment) +{ + char *token_array[GROUP_MEMBER_INFO_TOKENS_MAX], **tokens; + char *s0 = NULL, *s; + uint32_t n_tokens = 0, group_id_val = 0, member_id_val = 0, weight_val = 0; + int blank_or_comment = 0; + + /* Check input arguments. */ + if (!string || !string[0]) + goto error; + + /* Memory allocation. */ + s0 = strdup(string); + if (!s0) + goto error; + + /* Parse the string into tokens. */ + for (s = s0; ; ) { + char *token; + + token = strtok_r(s, " \f\n\r\t\v", &s); + if (!token || token_is_comment(token)) + break; + + if (n_tokens >= GROUP_MEMBER_INFO_TOKENS_MAX) + goto error; + + token_array[n_tokens] = token; + n_tokens++; + } + + if (!n_tokens) { + blank_or_comment = 1; + goto error; + } + + tokens = token_array; + + if (n_tokens < 4 || + strcmp(tokens[0], "group") || + strcmp(tokens[2], "member")) + goto error; + + /* + * Group ID. + */ + if (parser_read_uint32(&group_id_val, tokens[1]) != 0) + goto error; + *group_id = group_id_val; + + /* + * Member ID. + */ + if (parser_read_uint32(&member_id_val, tokens[3]) != 0) + goto error; + *member_id = member_id_val; + + tokens += 4; + n_tokens -= 4; + + /* + * Weight. + */ + if (n_tokens && !strcmp(tokens[0], "weight")) { + if (n_tokens < 2) + goto error; + + if (parser_read_uint32(&weight_val, tokens[1]) != 0) + goto error; + *weight = weight_val; + + tokens += 2; + n_tokens -= 2; + } + + if (n_tokens) + goto error; + + free(s0); + return 0; + +error: + free(s0); + if (is_blank_or_comment) + *is_blank_or_comment = blank_or_comment; + return -EINVAL; +} + +static int +pipeline_selector_group_members_add(struct rte_swx_ctl_pipeline *p, + const char *selector_name, + FILE *file, + uint32_t *file_line_number) +{ + char *line = NULL; + uint32_t line_id = 0; + int status = 0; + + /* Buffer allocation. */ + line = malloc(MAX_LINE_SIZE); + if (!line) + return -ENOMEM; + + /* File read. */ + for (line_id = 1; ; line_id++) { + uint32_t group_id, member_id, weight; + int is_blank_or_comment; + + if (fgets(line, MAX_LINE_SIZE, file) == NULL) + break; + + status = pipeline_selector_group_member_read(line, + &group_id, + &member_id, + &weight, + &is_blank_or_comment); + if (status) { + if (is_blank_or_comment) + continue; + + goto error; + } + + status = rte_swx_ctl_pipeline_selector_group_member_add(p, + selector_name, + group_id, + member_id, + weight); + if (status) + goto error; + } + +error: + free(line); + *file_line_number = line_id; + return status; +} + +static const char cmd_pipeline_selector_group_member_add_help[] = +"pipeline selector group member add "; + +static void +cmd_pipeline_selector_group_member_add(char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size, + void *obj) +{ + struct pipeline *p; + char *pipeline_name, *selector_name, *file_name; + FILE *file = NULL; + uint32_t file_line_number = 0; + int status; + + if (n_tokens != 8) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } + + pipeline_name = tokens[1]; + p = pipeline_find(obj, pipeline_name); + if (!p || !p->ctl) { + snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); + return; + } + + if (strcmp(tokens[2], "selector") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "selector"); + return; + } + + selector_name = tokens[3]; + + if (strcmp(tokens[4], "group") || + strcmp(tokens[5], "member") || + strcmp(tokens[6], "add")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "group member add"); + return; + } + + file_name = tokens[7]; + file = fopen(file_name, "r"); + if (!file) { + snprintf(out, out_size, "Cannot open file %s.\n", file_name); + return; + } + + status = pipeline_selector_group_members_add(p->ctl, + selector_name, + file, + &file_line_number); + if (status) + snprintf(out, out_size, "Invalid entry in file %s at line %u\n", + file_name, + file_line_number); + + fclose(file); +} + +static int +pipeline_selector_group_members_delete(struct rte_swx_ctl_pipeline *p, + const char *selector_name, + FILE *file, + uint32_t *file_line_number) +{ + char *line = NULL; + uint32_t line_id = 0; + int status = 0; + + /* Buffer allocation. */ + line = malloc(MAX_LINE_SIZE); + if (!line) + return -ENOMEM; + + /* File read. */ + for (line_id = 1; ; line_id++) { + uint32_t group_id, member_id, weight; + int is_blank_or_comment; + + if (fgets(line, MAX_LINE_SIZE, file) == NULL) + break; + + status = pipeline_selector_group_member_read(line, + &group_id, + &member_id, + &weight, + &is_blank_or_comment); + if (status) { + if (is_blank_or_comment) + continue; + + goto error; + } + + status = rte_swx_ctl_pipeline_selector_group_member_delete(p, + selector_name, + group_id, + member_id); + if (status) + goto error; + } + +error: + free(line); + *file_line_number = line_id; + return status; +} + +static const char cmd_pipeline_selector_group_member_delete_help[] = +"pipeline selector group member delete "; + +static void +cmd_pipeline_selector_group_member_delete(char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size, + void *obj) +{ + struct pipeline *p; + char *pipeline_name, *selector_name, *file_name; + FILE *file = NULL; + uint32_t file_line_number = 0; + int status; + + if (n_tokens != 8) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } + + pipeline_name = tokens[1]; + p = pipeline_find(obj, pipeline_name); + if (!p || !p->ctl) { + snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); + return; + } + + if (strcmp(tokens[2], "selector") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "selector"); + return; + } + + selector_name = tokens[3]; + + if (strcmp(tokens[4], "group") || + strcmp(tokens[5], "member") || + strcmp(tokens[6], "delete")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "group member delete"); + return; + } + + file_name = tokens[7]; + file = fopen(file_name, "r"); + if (!file) { + snprintf(out, out_size, "Cannot open file %s.\n", file_name); + return; + } + + status = pipeline_selector_group_members_delete(p->ctl, + selector_name, + file, + &file_line_number); + if (status) + snprintf(out, out_size, "Invalid entry in file %s at line %u\n", + file_name, + file_line_number); + + fclose(file); +} + +static const char cmd_pipeline_selector_show_help[] = +"pipeline selector show [filename]\n"; + +static void +cmd_pipeline_selector_show(char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size, + void *obj) +{ + struct pipeline *p; + char *pipeline_name, *selector_name; + FILE *file = NULL; + int status; + + if (n_tokens != 5 && n_tokens != 6) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } + + pipeline_name = tokens[1]; + p = pipeline_find(obj, pipeline_name); + if (!p || !p->ctl) { + snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); + return; + } + + selector_name = tokens[3]; + + file = (n_tokens == 6) ? fopen(tokens[5], "w") : stdout; + if (!file) { + snprintf(out, out_size, "Cannot open file %s.\n", tokens[5]); + return; + } + + status = rte_swx_ctl_pipeline_selector_fprintf(file, p->ctl, selector_name); + if (status) + snprintf(out, out_size, MSG_ARG_INVALID, "selector_name"); + + if (file) + fclose(file); +} + +static int +pipeline_learner_default_entry_add(struct rte_swx_ctl_pipeline *p, + const char *learner_name, + FILE *file, + uint32_t *file_line_number) +{ + char *line = NULL; + uint32_t line_id = 0; + int status = 0; + + /* Buffer allocation. */ + line = malloc(MAX_LINE_SIZE); + if (!line) + return -ENOMEM; + + /* File read. */ + for (line_id = 1; ; line_id++) { + struct rte_swx_table_entry *entry; + int is_blank_or_comment; + + if (fgets(line, MAX_LINE_SIZE, file) == NULL) + break; + + entry = rte_swx_ctl_pipeline_learner_default_entry_read(p, + learner_name, + line, + &is_blank_or_comment); + if (!entry) { + if (is_blank_or_comment) + continue; + + status = -EINVAL; + goto error; + } + + status = rte_swx_ctl_pipeline_learner_default_entry_add(p, + learner_name, + entry); + table_entry_free(entry); + if (status) + goto error; + } + +error: + *file_line_number = line_id; + free(line); + return status; +} + +static const char cmd_pipeline_learner_default_help[] = +"pipeline learner default \n"; + +static void +cmd_pipeline_learner_default(char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size, + void *obj) +{ + struct pipeline *p; + char *pipeline_name, *learner_name, *file_name; + FILE *file = NULL; + uint32_t file_line_number = 0; + int status; + + if (n_tokens != 6) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } + + pipeline_name = tokens[1]; + p = pipeline_find(obj, pipeline_name); + if (!p || !p->ctl) { + snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); + return; + } + + learner_name = tokens[3]; + + file_name = tokens[5]; + file = fopen(file_name, "r"); + if (!file) { + snprintf(out, out_size, "Cannot open file %s.\n", file_name); + return; + } + + status = pipeline_learner_default_entry_add(p->ctl, + learner_name, + file, + &file_line_number); + if (status) + snprintf(out, out_size, "Invalid entry in file %s at line %u\n", + file_name, + file_line_number); + + fclose(file); +} + +static const char cmd_pipeline_commit_help[] = +"pipeline commit\n"; + +static void +cmd_pipeline_commit(char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size, + void *obj) +{ + struct pipeline *p; + char *pipeline_name; + int status; + + if (n_tokens != 3) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } + + pipeline_name = tokens[1]; + p = pipeline_find(obj, pipeline_name); + if (!p || !p->ctl) { + snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); + return; + } + + status = rte_swx_ctl_pipeline_commit(p->ctl, 1); + if (status) + snprintf(out, out_size, "Commit failed. " + "Use \"commit\" to retry or \"abort\" to discard the pending work.\n"); +} + +static const char cmd_pipeline_abort_help[] = +"pipeline abort\n"; + +static void +cmd_pipeline_abort(char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size, + void *obj) +{ + struct pipeline *p; + char *pipeline_name; + + if (n_tokens != 3) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } + + pipeline_name = tokens[1]; + p = pipeline_find(obj, pipeline_name); + if (!p || !p->ctl) { + snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); + return; + } + + rte_swx_ctl_pipeline_abort(p->ctl); +} + +static const char cmd_pipeline_regrd_help[] = +"pipeline regrd \n"; + +static void +cmd_pipeline_regrd(char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size, + void *obj) +{ + struct pipeline *p; + const char *name; + uint64_t value; + uint32_t idx; + int status; + + if (n_tokens != 5) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } + + p = pipeline_find(obj, tokens[1]); + if (!p || !p->ctl) { + snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); + return; + } + + if (strcmp(tokens[2], "regrd")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "regrd"); + return; + } + + name = tokens[3]; + + if (parser_read_uint32(&idx, tokens[4])) { + snprintf(out, out_size, MSG_ARG_INVALID, "index"); + return; + } + + status = rte_swx_ctl_pipeline_regarray_read(p->p, name, idx, &value); + if (status) { + snprintf(out, out_size, "Command failed.\n"); + return; + } + + snprintf(out, out_size, "0x%" PRIx64 "\n", value); +} + +static const char cmd_pipeline_regwr_help[] = +"pipeline regwr \n"; + +static void +cmd_pipeline_regwr(char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size, + void *obj) +{ + struct pipeline *p; + const char *name; + uint64_t value; + uint32_t idx; + int status; + + if (n_tokens != 6) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } + + p = pipeline_find(obj, tokens[1]); + if (!p || !p->ctl) { + snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); + return; + } + + if (strcmp(tokens[2], "regwr")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "regwr"); + return; + } + + name = tokens[3]; + + if (parser_read_uint32(&idx, tokens[4])) { + snprintf(out, out_size, MSG_ARG_INVALID, "index"); + return; + } + + if (parser_read_uint64(&value, tokens[5])) { + snprintf(out, out_size, MSG_ARG_INVALID, "value"); + return; + } + + status = rte_swx_ctl_pipeline_regarray_write(p->p, name, idx, value); + if (status) { + snprintf(out, out_size, "Command failed.\n"); + return; + } +} + +static const char cmd_pipeline_meter_profile_add_help[] = +"pipeline meter profile add " + "cir pir cbs pbs \n"; + +static void +cmd_pipeline_meter_profile_add(char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size, + void *obj) +{ + struct rte_meter_trtcm_params params; + struct pipeline *p; + const char *profile_name; + int status; + + if (n_tokens != 14) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } + + p = pipeline_find(obj, tokens[1]); + if (!p || !p->ctl) { + snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); + return; + } + + if (strcmp(tokens[2], "meter")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); + return; + } + + if (strcmp(tokens[3], "profile")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); + return; + } + + profile_name = tokens[4]; + + if (strcmp(tokens[5], "add")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add"); + return; + } + + if (strcmp(tokens[6], "cir")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir"); + return; + } + + if (parser_read_uint64(¶ms.cir, tokens[7])) { + snprintf(out, out_size, MSG_ARG_INVALID, "cir"); + return; + } + + if (strcmp(tokens[8], "pir")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pir"); + return; + } + + if (parser_read_uint64(¶ms.pir, tokens[9])) { + snprintf(out, out_size, MSG_ARG_INVALID, "pir"); + return; + } + + if (strcmp(tokens[10], "cbs")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs"); + return; + } + + if (parser_read_uint64(¶ms.cbs, tokens[11])) { + snprintf(out, out_size, MSG_ARG_INVALID, "cbs"); + return; + } + + if (strcmp(tokens[12], "pbs")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pbs"); + return; + } + + if (parser_read_uint64(¶ms.pbs, tokens[13])) { + snprintf(out, out_size, MSG_ARG_INVALID, "pbs"); + return; + } + + status = rte_swx_ctl_meter_profile_add(p->p, profile_name, ¶ms); + if (status) { + snprintf(out, out_size, "Command failed.\n"); + return; + } +} + +static const char cmd_pipeline_meter_profile_delete_help[] = +"pipeline meter profile delete\n"; + +static void +cmd_pipeline_meter_profile_delete(char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size, + void *obj) +{ + struct pipeline *p; + const char *profile_name; + int status; + + if (n_tokens != 6) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } + + p = pipeline_find(obj, tokens[1]); + if (!p || !p->ctl) { + snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); + return; + } + + if (strcmp(tokens[2], "meter")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); + return; + } + + if (strcmp(tokens[3], "profile")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); + return; + } + + profile_name = tokens[4]; + + if (strcmp(tokens[5], "delete")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete"); + return; + } + + status = rte_swx_ctl_meter_profile_delete(p->p, profile_name); + if (status) { + snprintf(out, out_size, "Command failed.\n"); + return; + } +} + +static const char cmd_pipeline_meter_reset_help[] = +"pipeline meter from to " + "reset\n"; + +static void +cmd_pipeline_meter_reset(char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size, + void *obj) +{ + struct pipeline *p; + const char *name; + uint32_t idx0 = 0, idx1 = 0; + + if (n_tokens != 9) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } + + p = pipeline_find(obj, tokens[1]); + if (!p || !p->ctl) { + snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); + return; + } + + if (strcmp(tokens[2], "meter")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); + return; + } + + name = tokens[3]; + + if (strcmp(tokens[4], "from")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from"); + return; + } + + if (parser_read_uint32(&idx0, tokens[5])) { + snprintf(out, out_size, MSG_ARG_INVALID, "index0"); + return; + } + + if (strcmp(tokens[6], "to")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to"); + return; + } + + if (parser_read_uint32(&idx1, tokens[7]) || (idx1 < idx0)) { + snprintf(out, out_size, MSG_ARG_INVALID, "index1"); + return; + } + + if (strcmp(tokens[8], "reset")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "reset"); + return; + } + + for ( ; idx0 <= idx1; idx0++) { + int status; + + status = rte_swx_ctl_meter_reset(p->p, name, idx0); + if (status) { + snprintf(out, out_size, "Command failed for index %u.\n", idx0); + return; + } + } +} + +static const char cmd_pipeline_meter_set_help[] = +"pipeline meter from to " + "set profile \n"; + +static void +cmd_pipeline_meter_set(char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size, + void *obj) +{ + struct pipeline *p; + const char *name, *profile_name; + uint32_t idx0 = 0, idx1 = 0; + + if (n_tokens != 11) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } + + p = pipeline_find(obj, tokens[1]); + if (!p || !p->ctl) { + snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); + return; + } + + if (strcmp(tokens[2], "meter")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); + return; + } + + name = tokens[3]; + + if (strcmp(tokens[4], "from")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from"); + return; + } + + if (parser_read_uint32(&idx0, tokens[5])) { + snprintf(out, out_size, MSG_ARG_INVALID, "index0"); + return; + } + + if (strcmp(tokens[6], "to")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to"); + return; + } + + if (parser_read_uint32(&idx1, tokens[7]) || (idx1 < idx0)) { + snprintf(out, out_size, MSG_ARG_INVALID, "index1"); + return; + } + + if (strcmp(tokens[8], "set")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "set"); + return; + } + + if (strcmp(tokens[9], "profile")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); + return; + } + + profile_name = tokens[10]; + + for ( ; idx0 <= idx1; idx0++) { + int status; + + status = rte_swx_ctl_meter_set(p->p, name, idx0, profile_name); + if (status) { + snprintf(out, out_size, "Command failed for index %u.\n", idx0); + return; + } + } +} + +static const char cmd_pipeline_meter_stats_help[] = +"pipeline meter from to " + "stats\n"; + +static void +cmd_pipeline_meter_stats(char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size, + void *obj) +{ + struct rte_swx_ctl_meter_stats stats; + struct pipeline *p; + const char *name; + uint32_t idx0 = 0, idx1 = 0; + + if (n_tokens != 9) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } - status = rte_swx_ctl_pipeline_table_default_entry_add(p->ctl, - table_name, - entry); - if (status) { - snprintf(out, out_size, - "Invalid entry in file %s at line %u", - file_name_default, line_id); - goto error; - } - } + p = pipeline_find(obj, tokens[1]); + if (!p || !p->ctl) { + snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); + return; + } - status = rte_swx_ctl_pipeline_commit(p->ctl, 1); - if (status) { - snprintf(out, out_size, "Commit failed."); - goto error; + if (strcmp(tokens[2], "meter")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); + return; + } + + name = tokens[3]; + + if (strcmp(tokens[4], "from")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from"); + return; } + if (parser_read_uint32(&idx0, tokens[5])) { + snprintf(out, out_size, MSG_ARG_INVALID, "index0"); + return; + } - rte_swx_ctl_pipeline_table_fprintf(stdout, p->ctl, table_name); + if (strcmp(tokens[6], "to")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to"); + return; + } - free(line); - if (file_add) - fclose(file_add); - if (file_delete) - fclose(file_delete); - if (file_default) - fclose(file_default); - return; + if (parser_read_uint32(&idx1, tokens[7]) || (idx1 < idx0)) { + snprintf(out, out_size, MSG_ARG_INVALID, "index1"); + return; + } -error: - rte_swx_ctl_pipeline_abort(p->ctl); - free(line); - if (file_add) - fclose(file_add); - if (file_delete) - fclose(file_delete); - if (file_default) - fclose(file_default); + if (strcmp(tokens[8], "stats")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); + return; + } + + /* Table header. */ + snprintf(out, out_size, "+-%7s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+\n", + "-------", + "----------------", "----------------", "----------------", + "----------------", "----------------", "----------------"); + out_size -= strlen(out); + out += strlen(out); + + snprintf(out, out_size, "| %4s | %16s | %16s | %16s | %16s | %16s | %16s |\n", + "METER #", + "GREEN (packets)", "YELLOW (packets)", "RED (packets)", + "GREEN (bytes)", "YELLOW (bytes)", "RED (bytes)"); + out_size -= strlen(out); + out += strlen(out); + + snprintf(out, out_size, "+-%7s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+\n", + "-------", + "----------------", "----------------", "----------------", + "----------------", "----------------", "----------------"); + out_size -= strlen(out); + out += strlen(out); + + /* Table rows. */ + for ( ; idx0 <= idx1; idx0++) { + int status; + + status = rte_swx_ctl_meter_stats_read(p->p, name, idx0, &stats); + if (status) { + snprintf(out, out_size, "Pipeline meter stats error at index %u.\n", idx0); + out_size -= strlen(out); + out += strlen(out); + return; + } + + snprintf(out, out_size, "| %7d | %16" PRIx64 " | %16" PRIx64 " | %16" PRIx64 + " | %16" PRIx64 " | %16" PRIx64 " | %16" PRIx64 " |\n", + idx0, + stats.n_pkts[RTE_COLOR_GREEN], + stats.n_pkts[RTE_COLOR_YELLOW], + stats.n_pkts[RTE_COLOR_RED], + stats.n_bytes[RTE_COLOR_GREEN], + stats.n_bytes[RTE_COLOR_YELLOW], + stats.n_bytes[RTE_COLOR_RED]); + out_size -= strlen(out); + out += strlen(out); + } } static const char cmd_pipeline_stats_help[] = @@ -1034,7 +2562,7 @@ cmd_pipeline_stats(char **tokens, out += strlen(out); } - snprintf(out, out_size, "Output ports:\n"); + snprintf(out, out_size, "\nOutput ports:\n"); out_size -= strlen(out); out += strlen(out); @@ -1043,12 +2571,129 @@ cmd_pipeline_stats(char **tokens, rte_swx_ctl_pipeline_port_out_stats_read(p->p, i, &stats); - snprintf(out, out_size, "\tPort %u:" - " packets %" PRIu64 - " bytes %" PRIu64 "\n", - i, stats.n_pkts, stats.n_bytes); + if (i != info.n_ports_out - 1) + snprintf(out, out_size, "\tPort %u:" + " packets %" PRIu64 + " bytes %" PRIu64 "\n", + i, stats.n_pkts, stats.n_bytes); + else + snprintf(out, out_size, "\tDROP:" + " packets %" PRIu64 + " bytes %" PRIu64 "\n", + stats.n_pkts, stats.n_bytes); + + out_size -= strlen(out); + out += strlen(out); + } + + snprintf(out, out_size, "\nTables:\n"); + out_size -= strlen(out); + out += strlen(out); + + for (i = 0; i < info.n_tables; i++) { + struct rte_swx_ctl_table_info table_info; + uint64_t n_pkts_action[info.n_actions]; + struct rte_swx_table_stats stats = { + .n_pkts_hit = 0, + .n_pkts_miss = 0, + .n_pkts_action = n_pkts_action, + }; + uint32_t j; + + status = rte_swx_ctl_table_info_get(p->p, i, &table_info); + if (status) { + snprintf(out, out_size, "Table info get error."); + return; + } + + status = rte_swx_ctl_pipeline_table_stats_read(p->p, table_info.name, &stats); + if (status) { + snprintf(out, out_size, "Table stats read error."); + return; + } + + snprintf(out, out_size, "\tTable %s:\n" + "\t\tHit (packets): %" PRIu64 "\n" + "\t\tMiss (packets): %" PRIu64 "\n", + table_info.name, + stats.n_pkts_hit, + stats.n_pkts_miss); + out_size -= strlen(out); + out += strlen(out); + + for (j = 0; j < info.n_actions; j++) { + struct rte_swx_ctl_action_info action_info; + + status = rte_swx_ctl_action_info_get(p->p, j, &action_info); + if (status) { + snprintf(out, out_size, "Action info get error."); + return; + } + + snprintf(out, out_size, "\t\tAction %s (packets): %" PRIu64 "\n", + action_info.name, + stats.n_pkts_action[j]); + out_size -= strlen(out); + out += strlen(out); + } + } + + snprintf(out, out_size, "\nLearner tables:\n"); + out_size -= strlen(out); + out += strlen(out); + + for (i = 0; i < info.n_learners; i++) { + struct rte_swx_ctl_learner_info learner_info; + uint64_t n_pkts_action[info.n_actions]; + struct rte_swx_learner_stats stats = { + .n_pkts_hit = 0, + .n_pkts_miss = 0, + .n_pkts_action = n_pkts_action, + }; + uint32_t j; + + status = rte_swx_ctl_learner_info_get(p->p, i, &learner_info); + if (status) { + snprintf(out, out_size, "Learner table info get error."); + return; + } + + status = rte_swx_ctl_pipeline_learner_stats_read(p->p, learner_info.name, &stats); + if (status) { + snprintf(out, out_size, "Learner table stats read error."); + return; + } + + snprintf(out, out_size, "\tLearner table %s:\n" + "\t\tHit (packets): %" PRIu64 "\n" + "\t\tMiss (packets): %" PRIu64 "\n" + "\t\tLearn OK (packets): %" PRIu64 "\n" + "\t\tLearn error (packets): %" PRIu64 "\n" + "\t\tForget (packets): %" PRIu64 "\n", + learner_info.name, + stats.n_pkts_hit, + stats.n_pkts_miss, + stats.n_pkts_learn_ok, + stats.n_pkts_learn_err, + stats.n_pkts_forget); out_size -= strlen(out); out += strlen(out); + + for (j = 0; j < info.n_actions; j++) { + struct rte_swx_ctl_action_info action_info; + + status = rte_swx_ctl_action_info_get(p->p, j, &action_info); + if (status) { + snprintf(out, out_size, "Action info get error."); + return; + } + + snprintf(out, out_size, "\t\tAction %s (packets): %" PRIu64 "\n", + action_info.name, + stats.n_pkts_action[j]); + out_size -= strlen(out); + out += strlen(out); + } } } @@ -1163,7 +2808,37 @@ cmd_help(char **tokens, if (n_tokens == 0) { snprintf(out, out_size, - "Type 'help ' for command details.\n\n"); + "Type 'help ' for command details.\n\n" + "List of commands:\n" + "\tmempool\n" + "\tlink\n" + "\ttap\n" + "\tpipeline create\n" + "\tpipeline port in\n" + "\tpipeline port out\n" + "\tpipeline build\n" + "\tpipeline table add\n" + "\tpipeline table delete\n" + "\tpipeline table default\n" + "\tpipeline table show\n" + "\tpipeline selector group add\n" + "\tpipeline selector group delete\n" + "\tpipeline selector group member add\n" + "\tpipeline selector group member delete\n" + "\tpipeline selector show\n" + "\tpipeline learner default\n" + "\tpipeline commit\n" + "\tpipeline abort\n" + "\tpipeline regrd\n" + "\tpipeline regwr\n" + "\tpipeline meter profile add\n" + "\tpipeline meter profile delete\n" + "\tpipeline meter reset\n" + "\tpipeline meter set\n" + "\tpipeline meter stats\n" + "\tpipeline stats\n" + "\tthread pipeline enable\n" + "\tthread pipeline disable\n\n"); return; } @@ -1177,21 +2852,31 @@ cmd_help(char **tokens, return; } + if (strcmp(tokens[0], "ring") == 0) { + snprintf(out, out_size, "\n%s\n", cmd_ring_help); + return; + } + + if (strcmp(tokens[0], "tap") == 0) { + snprintf(out, out_size, "\n%s\n", cmd_tap_help); + return; + } + if ((strcmp(tokens[0], "pipeline") == 0) && - ((n_tokens == 1) && (strcmp(tokens[2], "create")) == 0)) { + (n_tokens == 2) && (strcmp(tokens[1], "create") == 0)) { snprintf(out, out_size, "\n%s\n", cmd_pipeline_create_help); return; } if ((strcmp(tokens[0], "pipeline") == 0) && - (strcmp(tokens[1], "port") == 0)) { - if ((n_tokens == 3) && (strcmp(tokens[2], "in")) == 0) { + (n_tokens == 3) && (strcmp(tokens[1], "port") == 0)) { + if (strcmp(tokens[2], "in") == 0) { snprintf(out, out_size, "\n%s\n", cmd_pipeline_port_in_help); return; } - if ((n_tokens == 3) && (strcmp(tokens[2], "out")) == 0) { + if (strcmp(tokens[2], "out") == 0) { snprintf(out, out_size, "\n%s\n", cmd_pipeline_port_out_help); return; @@ -1199,20 +2884,174 @@ cmd_help(char **tokens, } if ((strcmp(tokens[0], "pipeline") == 0) && - ((n_tokens >= 2) && (strcmp(tokens[2], "build")) == 0)) { + (n_tokens == 2) && (strcmp(tokens[1], "build") == 0)) { snprintf(out, out_size, "\n%s\n", cmd_pipeline_build_help); return; } if ((strcmp(tokens[0], "pipeline") == 0) && - ((n_tokens >= 2) && (strcmp(tokens[2], "table")) == 0)) { + (n_tokens == 3) && + (strcmp(tokens[1], "table") == 0) && + (strcmp(tokens[2], "add") == 0)) { + snprintf(out, out_size, "\n%s\n", + cmd_pipeline_table_add_help); + return; + } + + if ((strcmp(tokens[0], "pipeline") == 0) && + (n_tokens == 3) && + (strcmp(tokens[1], "table") == 0) && + (strcmp(tokens[2], "delete") == 0)) { + snprintf(out, out_size, "\n%s\n", + cmd_pipeline_table_delete_help); + return; + } + + if ((strcmp(tokens[0], "pipeline") == 0) && + (n_tokens == 3) && + (strcmp(tokens[1], "table") == 0) && + (strcmp(tokens[2], "default") == 0)) { + snprintf(out, out_size, "\n%s\n", + cmd_pipeline_table_default_help); + return; + } + + if ((strcmp(tokens[0], "pipeline") == 0) && + (n_tokens == 3) && + (strcmp(tokens[1], "table") == 0) && + (strcmp(tokens[2], "show") == 0)) { + snprintf(out, out_size, "\n%s\n", + cmd_pipeline_table_show_help); + return; + } + + if ((strcmp(tokens[0], "pipeline") == 0) && + (n_tokens == 4) && + (strcmp(tokens[1], "selector") == 0) && + (strcmp(tokens[2], "group") == 0) && + (strcmp(tokens[3], "add") == 0)) { + snprintf(out, out_size, "\n%s\n", + cmd_pipeline_selector_group_add_help); + return; + } + + if ((strcmp(tokens[0], "pipeline") == 0) && + (n_tokens == 4) && + (strcmp(tokens[1], "selector") == 0) && + (strcmp(tokens[2], "group") == 0) && + (strcmp(tokens[3], "delete") == 0)) { + snprintf(out, out_size, "\n%s\n", + cmd_pipeline_selector_group_delete_help); + return; + } + + if ((strcmp(tokens[0], "pipeline") == 0) && + (n_tokens == 5) && + (strcmp(tokens[1], "selector") == 0) && + (strcmp(tokens[2], "group") == 0) && + (strcmp(tokens[3], "member") == 0) && + (strcmp(tokens[4], "add") == 0)) { snprintf(out, out_size, "\n%s\n", - cmd_pipeline_table_update_help); + cmd_pipeline_selector_group_member_add_help); return; } if ((strcmp(tokens[0], "pipeline") == 0) && - ((n_tokens >= 2) && (strcmp(tokens[2], "stats")) == 0)) { + (n_tokens == 5) && + (strcmp(tokens[1], "selector") == 0) && + (strcmp(tokens[2], "group") == 0) && + (strcmp(tokens[3], "member") == 0) && + (strcmp(tokens[4], "delete") == 0)) { + snprintf(out, out_size, "\n%s\n", + cmd_pipeline_selector_group_member_delete_help); + return; + } + + if ((strcmp(tokens[0], "pipeline") == 0) && + (n_tokens == 3) && + (strcmp(tokens[1], "selector") == 0) && + (strcmp(tokens[2], "show") == 0)) { + snprintf(out, out_size, "\n%s\n", + cmd_pipeline_selector_show_help); + return; + } + + if ((strcmp(tokens[0], "pipeline") == 0) && + (n_tokens == 3) && + (strcmp(tokens[1], "learner") == 0) && + (strcmp(tokens[2], "default") == 0)) { + snprintf(out, out_size, "\n%s\n", + cmd_pipeline_learner_default_help); + return; + } + + if ((strcmp(tokens[0], "pipeline") == 0) && + (n_tokens == 2) && + (strcmp(tokens[1], "commit") == 0)) { + snprintf(out, out_size, "\n%s\n", + cmd_pipeline_commit_help); + return; + } + + if ((strcmp(tokens[0], "pipeline") == 0) && + (n_tokens == 2) && + (strcmp(tokens[1], "abort") == 0)) { + snprintf(out, out_size, "\n%s\n", + cmd_pipeline_abort_help); + return; + } + + if ((strcmp(tokens[0], "pipeline") == 0) && + (n_tokens == 2) && (strcmp(tokens[1], "regrd") == 0)) { + snprintf(out, out_size, "\n%s\n", cmd_pipeline_regrd_help); + return; + } + + if ((strcmp(tokens[0], "pipeline") == 0) && + (n_tokens == 2) && (strcmp(tokens[1], "regwr") == 0)) { + snprintf(out, out_size, "\n%s\n", cmd_pipeline_regwr_help); + return; + } + + if (!strcmp(tokens[0], "pipeline") && + (n_tokens == 4) && !strcmp(tokens[1], "meter") + && !strcmp(tokens[2], "profile") + && !strcmp(tokens[3], "add")) { + snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_profile_add_help); + return; + } + + if (!strcmp(tokens[0], "pipeline") && + (n_tokens == 4) && !strcmp(tokens[1], "meter") + && !strcmp(tokens[2], "profile") + && !strcmp(tokens[3], "delete")) { + snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_profile_delete_help); + return; + } + + if (!strcmp(tokens[0], "pipeline") && + (n_tokens == 3) && !strcmp(tokens[1], "meter") + && !strcmp(tokens[2], "reset")) { + snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_reset_help); + return; + } + + if (!strcmp(tokens[0], "pipeline") && + (n_tokens == 3) && !strcmp(tokens[1], "meter") + && !strcmp(tokens[2], "set")) { + snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_set_help); + return; + } + + if (!strcmp(tokens[0], "pipeline") && + (n_tokens == 3) && !strcmp(tokens[1], "meter") + && !strcmp(tokens[2], "stats")) { + snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_stats_help); + return; + } + + if ((strcmp(tokens[0], "pipeline") == 0) && + (n_tokens == 2) && (strcmp(tokens[1], "stats") == 0)) { snprintf(out, out_size, "\n%s\n", cmd_pipeline_stats_help); return; } @@ -1266,7 +3105,7 @@ cli_process(char *in, char *out, size_t out_size, void *obj) } if (strcmp(tokens[0], "link") == 0) { - if (strcmp(tokens[1], "show") == 0) { + if ((n_tokens >= 2) && (strcmp(tokens[1], "show") == 0)) { cmd_link_show(tokens, n_tokens, out, out_size, obj); return; } @@ -1275,6 +3114,16 @@ cli_process(char *in, char *out, size_t out_size, void *obj) return; } + if (strcmp(tokens[0], "ring") == 0) { + cmd_ring(tokens, n_tokens, out, out_size, obj); + return; + } + + if (strcmp(tokens[0], "tap") == 0) { + cmd_tap(tokens, n_tokens, out, out_size, obj); + return; + } + if (strcmp(tokens[0], "pipeline") == 0) { if ((n_tokens >= 3) && (strcmp(tokens[2], "create") == 0)) { @@ -1306,13 +3155,155 @@ cli_process(char *in, char *out, size_t out_size, void *obj) return; } + if ((n_tokens >= 5) && + (strcmp(tokens[2], "table") == 0) && + (strcmp(tokens[4], "add") == 0)) { + cmd_pipeline_table_add(tokens, n_tokens, out, + out_size, obj); + return; + } + + if ((n_tokens >= 5) && + (strcmp(tokens[2], "table") == 0) && + (strcmp(tokens[4], "delete") == 0)) { + cmd_pipeline_table_delete(tokens, n_tokens, out, + out_size, obj); + return; + } + + if ((n_tokens >= 5) && + (strcmp(tokens[2], "table") == 0) && + (strcmp(tokens[4], "default") == 0)) { + cmd_pipeline_table_default(tokens, n_tokens, out, + out_size, obj); + return; + } + + if ((n_tokens >= 5) && + (strcmp(tokens[2], "table") == 0) && + (strcmp(tokens[4], "show") == 0)) { + cmd_pipeline_table_show(tokens, n_tokens, out, + out_size, obj); + return; + } + + if ((n_tokens >= 6) && + (strcmp(tokens[2], "selector") == 0) && + (strcmp(tokens[4], "group") == 0) && + (strcmp(tokens[5], "add") == 0)) { + cmd_pipeline_selector_group_add(tokens, n_tokens, out, + out_size, obj); + return; + } + + if ((n_tokens >= 6) && + (strcmp(tokens[2], "selector") == 0) && + (strcmp(tokens[4], "group") == 0) && + (strcmp(tokens[5], "delete") == 0)) { + cmd_pipeline_selector_group_delete(tokens, n_tokens, out, + out_size, obj); + return; + } + + if ((n_tokens >= 7) && + (strcmp(tokens[2], "selector") == 0) && + (strcmp(tokens[4], "group") == 0) && + (strcmp(tokens[5], "member") == 0) && + (strcmp(tokens[6], "add") == 0)) { + cmd_pipeline_selector_group_member_add(tokens, n_tokens, out, + out_size, obj); + return; + } + + if ((n_tokens >= 7) && + (strcmp(tokens[2], "selector") == 0) && + (strcmp(tokens[4], "group") == 0) && + (strcmp(tokens[5], "member") == 0) && + (strcmp(tokens[6], "delete") == 0)) { + cmd_pipeline_selector_group_member_delete(tokens, n_tokens, out, + out_size, obj); + return; + } + + if ((n_tokens >= 5) && + (strcmp(tokens[2], "selector") == 0) && + (strcmp(tokens[4], "show") == 0)) { + cmd_pipeline_selector_show(tokens, n_tokens, out, + out_size, obj); + return; + } + + if ((n_tokens >= 5) && + (strcmp(tokens[2], "learner") == 0) && + (strcmp(tokens[4], "default") == 0)) { + cmd_pipeline_learner_default(tokens, n_tokens, out, + out_size, obj); + return; + } + + if ((n_tokens >= 3) && + (strcmp(tokens[2], "commit") == 0)) { + cmd_pipeline_commit(tokens, n_tokens, out, + out_size, obj); + return; + } + if ((n_tokens >= 3) && - (strcmp(tokens[2], "table") == 0)) { - cmd_pipeline_table_update(tokens, n_tokens, out, + (strcmp(tokens[2], "abort") == 0)) { + cmd_pipeline_abort(tokens, n_tokens, out, out_size, obj); return; } + if ((n_tokens >= 3) && + (strcmp(tokens[2], "regrd") == 0)) { + cmd_pipeline_regrd(tokens, n_tokens, out, out_size, obj); + return; + } + + if ((n_tokens >= 3) && + (strcmp(tokens[2], "regwr") == 0)) { + cmd_pipeline_regwr(tokens, n_tokens, out, out_size, obj); + return; + } + + if ((n_tokens >= 6) && + (strcmp(tokens[2], "meter") == 0) && + (strcmp(tokens[3], "profile") == 0) && + (strcmp(tokens[5], "add") == 0)) { + cmd_pipeline_meter_profile_add(tokens, n_tokens, out, out_size, obj); + return; + } + + if ((n_tokens >= 6) && + (strcmp(tokens[2], "meter") == 0) && + (strcmp(tokens[3], "profile") == 0) && + (strcmp(tokens[5], "delete") == 0)) { + cmd_pipeline_meter_profile_delete(tokens, n_tokens, out, out_size, obj); + return; + } + + if ((n_tokens >= 9) && + (strcmp(tokens[2], "meter") == 0) && + (strcmp(tokens[8], "reset") == 0)) { + cmd_pipeline_meter_reset(tokens, n_tokens, out, out_size, obj); + return; + } + + if ((n_tokens >= 9) && + (strcmp(tokens[2], "meter") == 0) && + (strcmp(tokens[8], "set") == 0)) { + cmd_pipeline_meter_set(tokens, n_tokens, out, out_size, obj); + return; + } + + if ((n_tokens >= 9) && + (strcmp(tokens[2], "meter") == 0) && + (strcmp(tokens[8], "stats") == 0)) { + cmd_pipeline_meter_stats(tokens, n_tokens, out, out_size, obj); + return; + } + if ((n_tokens >= 3) && (strcmp(tokens[2], "stats") == 0)) { cmd_pipeline_stats(tokens, n_tokens, out, out_size,