/* SPDX-License-Identifier: BSD-3-Clause * Copyright(c) 2010-2018 Intel Corporation */ #include #include #include #include #include #include #include #include "cli.h" #include "cryptodev.h" #include "kni.h" #include "link.h" #include "mempool.h" #include "parser.h" #include "pipeline.h" #include "swq.h" #include "tap.h" #include "thread.h" #include "tmgr.h" #ifndef CMD_MAX_TOKENS #define CMD_MAX_TOKENS 256 #endif #define MSG_OUT_OF_MEMORY "Not enough memory.\n" #define MSG_CMD_UNKNOWN "Unknown command \"%s\".\n" #define MSG_CMD_UNIMPLEM "Command \"%s\" not implemented.\n" #define MSG_ARG_NOT_ENOUGH "Not enough arguments for command \"%s\".\n" #define MSG_ARG_TOO_MANY "Too many arguments for command \"%s\".\n" #define MSG_ARG_MISMATCH "Wrong number of arguments for command \"%s\".\n" #define MSG_ARG_NOT_FOUND "Argument \"%s\" not found.\n" #define MSG_ARG_INVALID "Invalid value for argument \"%s\".\n" #define MSG_FILE_ERR "Error in file \"%s\" at line %u.\n" #define MSG_FILE_NOT_ENOUGH "Not enough rules in file \"%s\".\n" #define MSG_CMD_FAIL "Command \"%s\" failed.\n" static int is_comment(char *in) { if ((strlen(in) && index("!#%;", in[0])) || (strncmp(in, "//", 2) == 0) || (strncmp(in, "--", 2) == 0)) return 1; return 0; } static const char cmd_mempool_help[] = "mempool \n" " buffer \n" " pool \n" " cache \n" " cpu \n"; static void cmd_mempool(char **tokens, uint32_t n_tokens, char *out, size_t out_size) { struct mempool_params p; char *name; struct mempool *mempool; if (n_tokens != 10) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } name = tokens[1]; if (strcmp(tokens[2], "buffer") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buffer"); return; } if (parser_read_uint32(&p.buffer_size, tokens[3]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "buffer_size"); return; } if (strcmp(tokens[4], "pool") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pool"); return; } if (parser_read_uint32(&p.pool_size, tokens[5]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "pool_size"); return; } if (strcmp(tokens[6], "cache") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cache"); return; } if (parser_read_uint32(&p.cache_size, tokens[7]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "cache_size"); return; } if (strcmp(tokens[8], "cpu") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu"); return; } if (parser_read_uint32(&p.cpu_id, tokens[9]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id"); return; } mempool = mempool_create(name, &p); if (mempool == NULL) { snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); return; } } static const char cmd_link_help[] = "link \n" " dev | port \n" " rxq \n" " txq \n" " promiscuous on | off\n" " [rss ... ]\n"; static void cmd_link(char **tokens, uint32_t n_tokens, char *out, size_t out_size) { struct link_params p; struct link_params_rss rss; struct link *link; char *name; memset(&p, 0, sizeof(p)); if ((n_tokens < 13) || (n_tokens > 14 + LINK_RXQ_RSS_MAX)) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } name = tokens[1]; if (strcmp(tokens[2], "dev") == 0) p.dev_name = tokens[3]; else if (strcmp(tokens[2], "port") == 0) { p.dev_name = NULL; if (parser_read_uint16(&p.port_id, tokens[3]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); return; } } else { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dev or port"); return; } if (strcmp(tokens[4], "rxq") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq"); return; } if (parser_read_uint32(&p.rx.n_queues, tokens[5]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "n_queues"); return; } if (parser_read_uint32(&p.rx.queue_size, tokens[6]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "queue_size"); return; } p.rx.mempool_name = tokens[7]; if (strcmp(tokens[8], "txq") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq"); return; } if (parser_read_uint32(&p.tx.n_queues, tokens[9]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "n_queues"); return; } if (parser_read_uint32(&p.tx.queue_size, tokens[10]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "queue_size"); return; } if (strcmp(tokens[11], "promiscuous") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "promiscuous"); return; } if (strcmp(tokens[12], "on") == 0) p.promiscuous = 1; else if (strcmp(tokens[12], "off") == 0) p.promiscuous = 0; else { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "on or off"); return; } /* RSS */ p.rx.rss = NULL; if (n_tokens > 13) { uint32_t queue_id, i; if (strcmp(tokens[13], "rss") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rss"); return; } p.rx.rss = &rss; rss.n_queues = 0; for (i = 14; i < n_tokens; i++) { if (parser_read_uint32(&queue_id, tokens[i]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "queue_id"); return; } rss.queue_id[rss.n_queues] = queue_id; rss.n_queues++; } } link = link_create(name, &p); if (link == NULL) { snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); return; } } /* Print the link stats and info */ static void print_link_info(struct link *link, char *out, size_t out_size) { struct rte_eth_stats stats; struct ether_addr mac_addr; struct rte_eth_link eth_link; uint16_t mtu; memset(&stats, 0, sizeof(stats)); rte_eth_stats_get(link->port_id, &stats); rte_eth_macaddr_get(link->port_id, &mac_addr); rte_eth_link_get(link->port_id, ð_link); rte_eth_dev_get_mtu(link->port_id, &mtu); snprintf(out, out_size, "\n" "%s: flags=<%s> mtu %u\n" "\tether %02X:%02X:%02X:%02X:%02X:%02X rxqueues %u txqueues %u\n" "\tport# %u speed %u Mbps\n" "\tRX packets %" PRIu64" bytes %" PRIu64"\n" "\tRX errors %" PRIu64" missed %" PRIu64" no-mbuf %" PRIu64"\n" "\tTX packets %" PRIu64" bytes %" PRIu64"\n" "\tTX errors %" PRIu64"\n", 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], link->n_rxq, link->n_txq, link->port_id, eth_link.link_speed, stats.ipackets, stats.ibytes, stats.ierrors, stats.imissed, stats.rx_nombuf, stats.opackets, stats.obytes, stats.oerrors); } /* * link show [] */ static void cmd_link_show(char **tokens, uint32_t n_tokens, char *out, size_t out_size) { struct link *link; char *link_name; if (n_tokens != 2 && n_tokens != 3) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } if (n_tokens == 2) { link = link_next(NULL); while (link != NULL) { out_size = out_size - strlen(out); out = &out[strlen(out)]; print_link_info(link, out, out_size); link = link_next(link); } } else { out_size = out_size - strlen(out); out = &out[strlen(out)]; link_name = tokens[2]; link = link_find(link_name); if (link == NULL) { snprintf(out, out_size, MSG_ARG_INVALID, "Link does not exist"); return; } print_link_info(link, out, out_size); } } static const char cmd_swq_help[] = "swq \n" " size \n" " cpu \n"; static void cmd_swq(char **tokens, uint32_t n_tokens, char *out, size_t out_size) { struct swq_params p; char *name; struct swq *swq; 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], "cpu") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu"); return; } if (parser_read_uint32(&p.cpu_id, tokens[5]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id"); return; } swq = swq_create(name, &p); if (swq == NULL) { snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); return; } } static const char cmd_tmgr_subport_profile_help[] = "tmgr subport profile\n" " \n" " \n" " \n"; static void cmd_tmgr_subport_profile(char **tokens, uint32_t n_tokens, char *out, size_t out_size) { struct rte_sched_subport_params p; int status, i; if (n_tokens != 10) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } if (parser_read_uint32(&p.tb_rate, tokens[3]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "tb_rate"); return; } if (parser_read_uint32(&p.tb_size, tokens[4]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "tb_size"); return; } for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) if (parser_read_uint32(&p.tc_rate[i], tokens[5 + i]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "tc_rate"); return; } if (parser_read_uint32(&p.tc_period, tokens[9]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "tc_period"); return; } status = tmgr_subport_profile_add(&p); if (status != 0) { snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); return; } } static const char cmd_tmgr_pipe_profile_help[] = "tmgr pipe profile\n" " \n" " \n" " \n" " \n" " \n"; static void cmd_tmgr_pipe_profile(char **tokens, uint32_t n_tokens, char *out, size_t out_size) { struct rte_sched_pipe_params p; int status, i; if (n_tokens != 27) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } if (parser_read_uint32(&p.tb_rate, tokens[3]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "tb_rate"); return; } if (parser_read_uint32(&p.tb_size, tokens[4]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "tb_size"); return; } for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) if (parser_read_uint32(&p.tc_rate[i], tokens[5 + i]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "tc_rate"); return; } if (parser_read_uint32(&p.tc_period, tokens[9]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "tc_period"); return; } #ifdef RTE_SCHED_SUBPORT_TC_OV if (parser_read_uint8(&p.tc_ov_weight, tokens[10]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "tc_ov_weight"); return; } #endif for (i = 0; i < RTE_SCHED_QUEUES_PER_PIPE; i++) if (parser_read_uint8(&p.wrr_weights[i], tokens[11 + i]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "wrr_weights"); return; } status = tmgr_pipe_profile_add(&p); if (status != 0) { snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); return; } } static const char cmd_tmgr_help[] = "tmgr \n" " rate \n" " spp \n" " pps \n" " qsize \n" " fo \n" " mtu \n" " cpu \n"; static void cmd_tmgr(char **tokens, uint32_t n_tokens, char *out, size_t out_size) { struct tmgr_port_params p; char *name; struct tmgr_port *tmgr_port; int i; if (n_tokens != 19) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } name = tokens[1]; if (strcmp(tokens[2], "rate") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rate"); return; } if (parser_read_uint32(&p.rate, tokens[3]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "rate"); return; } if (strcmp(tokens[4], "spp") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp"); return; } if (parser_read_uint32(&p.n_subports_per_port, tokens[5]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "n_subports_per_port"); return; } if (strcmp(tokens[6], "pps") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps"); return; } if (parser_read_uint32(&p.n_pipes_per_subport, tokens[7]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "n_pipes_per_subport"); return; } if (strcmp(tokens[8], "qsize") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "qsize"); return; } for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) if (parser_read_uint16(&p.qsize[i], tokens[9 + i]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "qsize"); return; } if (strcmp(tokens[13], "fo") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fo"); return; } if (parser_read_uint32(&p.frame_overhead, tokens[14]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "frame_overhead"); return; } if (strcmp(tokens[15], "mtu") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mtu"); return; } if (parser_read_uint32(&p.mtu, tokens[16]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "mtu"); return; } if (strcmp(tokens[17], "cpu") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu"); return; } if (parser_read_uint32(&p.cpu_id, tokens[18]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id"); return; } tmgr_port = tmgr_port_create(name, &p); if (tmgr_port == NULL) { snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); return; } } static const char cmd_tmgr_subport_help[] = "tmgr subport \n" " profile \n"; static void cmd_tmgr_subport(char **tokens, uint32_t n_tokens, char *out, size_t out_size) { uint32_t subport_id, subport_profile_id; int status; char *name; if (n_tokens != 6) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } name = tokens[1]; if (parser_read_uint32(&subport_id, tokens[3]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "subport_id"); return; } if (parser_read_uint32(&subport_profile_id, tokens[5]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "subport_profile_id"); return; } status = tmgr_subport_config(name, subport_id, subport_profile_id); if (status) { snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); return; } } static const char cmd_tmgr_subport_pipe_help[] = "tmgr subport pipe\n" " from to \n" " profile \n"; static void cmd_tmgr_subport_pipe(char **tokens, uint32_t n_tokens, char *out, size_t out_size) { uint32_t subport_id, pipe_id_first, pipe_id_last, pipe_profile_id; int status; char *name; if (n_tokens != 11) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } name = tokens[1]; if (parser_read_uint32(&subport_id, tokens[3]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "subport_id"); return; } if (strcmp(tokens[4], "pipe") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipe"); return; } if (strcmp(tokens[5], "from") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from"); return; } if (parser_read_uint32(&pipe_id_first, tokens[6]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "pipe_id_first"); return; } if (strcmp(tokens[7], "to") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to"); return; } if (parser_read_uint32(&pipe_id_last, tokens[8]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "pipe_id_last"); return; } if (strcmp(tokens[9], "profile") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); return; } if (parser_read_uint32(&pipe_profile_id, tokens[10]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "pipe_profile_id"); return; } status = tmgr_pipe_config(name, subport_id, pipe_id_first, pipe_id_last, pipe_profile_id); if (status) { 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) { char *name; struct tap *tap; if (n_tokens != 2) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } name = tokens[1]; tap = tap_create(name); if (tap == NULL) { snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); return; } } static const char cmd_kni_help[] = "kni \n" " link \n" " mempool \n" " [thread ]\n"; static void cmd_kni(char **tokens, uint32_t n_tokens, char *out, size_t out_size) { struct kni_params p; char *name; struct kni *kni; memset(&p, 0, sizeof(p)); if ((n_tokens != 6) && (n_tokens != 8)) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } name = tokens[1]; if (strcmp(tokens[2], "link") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "link"); return; } p.link_name = tokens[3]; if (strcmp(tokens[4], "mempool") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mempool"); return; } p.mempool_name = tokens[5]; if (n_tokens == 8) { if (strcmp(tokens[6], "thread") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "thread"); return; } if (parser_read_uint32(&p.thread_id, tokens[7]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "thread_id"); return; } p.force_bind = 1; } else p.force_bind = 0; kni = kni_create(name, &p); if (kni == NULL) { snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); return; } } static const char cmd_cryptodev_help[] = "cryptodev \n" " dev | dev_id \n" " queue \n"; static void cmd_cryptodev(char **tokens, uint32_t n_tokens, char *out, size_t out_size) { struct cryptodev_params params; char *name; memset(¶ms, 0, sizeof(params)); if (n_tokens != 7) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } name = tokens[1]; if (strcmp(tokens[2], "dev") == 0) params.dev_name = tokens[3]; else if (strcmp(tokens[2], "dev_id") == 0) { if (parser_read_uint32(¶ms.dev_id, tokens[3]) < 0) { snprintf(out, out_size, MSG_ARG_INVALID, "dev_id"); return; } } else { snprintf(out, out_size, MSG_ARG_INVALID, "cryptodev"); return; } if (strcmp(tokens[4], "queue")) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "4"); return; } if (parser_read_uint32(¶ms.n_queues, tokens[5]) < 0) { snprintf(out, out_size, MSG_ARG_INVALID, "q"); return; } if (parser_read_uint32(¶ms.queue_size, tokens[6]) < 0) { snprintf(out, out_size, MSG_ARG_INVALID, "queue_size"); return; } if (cryptodev_create(name, ¶ms) == NULL) { snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); return; } } static const char cmd_port_in_action_profile_help[] = "port in action profile \n" " [filter match | mismatch offset mask key port ]\n" " [balance offset mask port ... ]\n"; static void cmd_port_in_action_profile(char **tokens, uint32_t n_tokens, char *out, size_t out_size) { struct port_in_action_profile_params p; struct port_in_action_profile *ap; char *name; uint32_t t0; memset(&p, 0, sizeof(p)); if (n_tokens < 5) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } if (strcmp(tokens[1], "in") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in"); return; } if (strcmp(tokens[2], "action") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action"); return; } if (strcmp(tokens[3], "profile") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); return; } name = tokens[4]; t0 = 5; if ((t0 < n_tokens) && (strcmp(tokens[t0], "filter") == 0)) { uint32_t size; if (n_tokens < t0 + 10) { snprintf(out, out_size, MSG_ARG_MISMATCH, "port in action profile filter"); return; } if (strcmp(tokens[t0 + 1], "match") == 0) p.fltr.filter_on_match = 1; else if (strcmp(tokens[t0 + 1], "mismatch") == 0) p.fltr.filter_on_match = 0; else { snprintf(out, out_size, MSG_ARG_INVALID, "match or mismatch"); return; } if (strcmp(tokens[t0 + 2], "offset") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); return; } if (parser_read_uint32(&p.fltr.key_offset, tokens[t0 + 3]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); return; } if (strcmp(tokens[t0 + 4], "mask") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask"); return; } size = RTE_PORT_IN_ACTION_FLTR_KEY_SIZE; if ((parse_hex_string(tokens[t0 + 5], p.fltr.key_mask, &size) != 0) || (size != RTE_PORT_IN_ACTION_FLTR_KEY_SIZE)) { snprintf(out, out_size, MSG_ARG_INVALID, "key_mask"); return; } if (strcmp(tokens[t0 + 6], "key") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key"); return; } size = RTE_PORT_IN_ACTION_FLTR_KEY_SIZE; if ((parse_hex_string(tokens[t0 + 7], p.fltr.key, &size) != 0) || (size != RTE_PORT_IN_ACTION_FLTR_KEY_SIZE)) { snprintf(out, out_size, MSG_ARG_INVALID, "key_value"); return; } if (strcmp(tokens[t0 + 8], "port") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); return; } if (parser_read_uint32(&p.fltr.port_id, tokens[t0 + 9]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); return; } p.action_mask |= 1LLU << RTE_PORT_IN_ACTION_FLTR; t0 += 10; } /* filter */ if ((t0 < n_tokens) && (strcmp(tokens[t0], "balance") == 0)) { uint32_t i; if (n_tokens < t0 + 22) { snprintf(out, out_size, MSG_ARG_MISMATCH, "port in action profile balance"); return; } if (strcmp(tokens[t0 + 1], "offset") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); return; } if (parser_read_uint32(&p.lb.key_offset, tokens[t0 + 2]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); return; } if (strcmp(tokens[t0 + 3], "mask") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask"); return; } p.lb.key_size = RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX; if (parse_hex_string(tokens[t0 + 4], p.lb.key_mask, &p.lb.key_size) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "key_mask"); return; } if (strcmp(tokens[t0 + 5], "port") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); return; } for (i = 0; i < 16; i++) if (parser_read_uint32(&p.lb.port_id[i], tokens[t0 + 6 + i]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); return; } p.action_mask |= 1LLU << RTE_PORT_IN_ACTION_LB; t0 += 22; } /* balance */ if (t0 < n_tokens) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } ap = port_in_action_profile_create(name, &p); if (ap == NULL) { snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); return; } } static const char cmd_table_action_profile_help[] = "table action profile \n" " ipv4 | ipv6\n" " offset \n" " fwd\n" " [balance offset mask outoffset ]\n" " [meter srtcm | trtcm\n" " tc \n" " stats none | pkts | bytes | both]\n" " [tm spp pps ]\n" " [encap ether | vlan | qinq | mpls | pppoe |\n" " vxlan offset ipv4 | ipv6 vlan on | off]\n" " [nat src | dst\n" " proto udp | tcp]\n" " [ttl drop | fwd\n" " stats none | pkts]\n" " [stats pkts | bytes | both]\n" " [time]\n" " [sym_crypto dev offset " " mempool_create \n" " mempool_init ]\n" " [tag]\n" " [decap]\n"; static void cmd_table_action_profile(char **tokens, uint32_t n_tokens, char *out, size_t out_size) { struct table_action_profile_params p; struct table_action_profile *ap; char *name; uint32_t t0; memset(&p, 0, sizeof(p)); if (n_tokens < 8) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } if (strcmp(tokens[1], "action") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action"); return; } if (strcmp(tokens[2], "profile") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); return; } name = tokens[3]; if (strcmp(tokens[4], "ipv4") == 0) p.common.ip_version = 1; else if (strcmp(tokens[4], "ipv6") == 0) p.common.ip_version = 0; else { snprintf(out, out_size, MSG_ARG_INVALID, "ipv4 or ipv6"); return; } if (strcmp(tokens[5], "offset") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); return; } if (parser_read_uint32(&p.common.ip_offset, tokens[6]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "ip_offset"); return; } if (strcmp(tokens[7], "fwd") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fwd"); return; } p.action_mask |= 1LLU << RTE_TABLE_ACTION_FWD; t0 = 8; if ((t0 < n_tokens) && (strcmp(tokens[t0], "balance") == 0)) { if (n_tokens < t0 + 7) { snprintf(out, out_size, MSG_ARG_MISMATCH, "table action profile balance"); return; } if (strcmp(tokens[t0 + 1], "offset") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); return; } if (parser_read_uint32(&p.lb.key_offset, tokens[t0 + 2]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); return; } if (strcmp(tokens[t0 + 3], "mask") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask"); return; } p.lb.key_size = RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX; if (parse_hex_string(tokens[t0 + 4], p.lb.key_mask, &p.lb.key_size) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "key_mask"); return; } if (strcmp(tokens[t0 + 5], "outoffset") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "outoffset"); return; } if (parser_read_uint32(&p.lb.out_offset, tokens[t0 + 6]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "out_offset"); return; } p.action_mask |= 1LLU << RTE_TABLE_ACTION_LB; t0 += 7; } /* balance */ if ((t0 < n_tokens) && (strcmp(tokens[t0], "meter") == 0)) { if (n_tokens < t0 + 6) { snprintf(out, out_size, MSG_ARG_MISMATCH, "table action profile meter"); return; } if (strcmp(tokens[t0 + 1], "srtcm") == 0) p.mtr.alg = RTE_TABLE_ACTION_METER_SRTCM; else if (strcmp(tokens[t0 + 1], "trtcm") == 0) p.mtr.alg = RTE_TABLE_ACTION_METER_TRTCM; else { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "srtcm or trtcm"); return; } if (strcmp(tokens[t0 + 2], "tc") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc"); return; } if (parser_read_uint32(&p.mtr.n_tc, tokens[t0 + 3]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "n_tc"); return; } if (strcmp(tokens[t0 + 4], "stats") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); return; } if (strcmp(tokens[t0 + 5], "none") == 0) { p.mtr.n_packets_enabled = 0; p.mtr.n_bytes_enabled = 0; } else if (strcmp(tokens[t0 + 5], "pkts") == 0) { p.mtr.n_packets_enabled = 1; p.mtr.n_bytes_enabled = 0; } else if (strcmp(tokens[t0 + 5], "bytes") == 0) { p.mtr.n_packets_enabled = 0; p.mtr.n_bytes_enabled = 1; } else if (strcmp(tokens[t0 + 5], "both") == 0) { p.mtr.n_packets_enabled = 1; p.mtr.n_bytes_enabled = 1; } else { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "none or pkts or bytes or both"); return; } p.action_mask |= 1LLU << RTE_TABLE_ACTION_MTR; t0 += 6; } /* meter */ if ((t0 < n_tokens) && (strcmp(tokens[t0], "tm") == 0)) { if (n_tokens < t0 + 5) { snprintf(out, out_size, MSG_ARG_MISMATCH, "table action profile tm"); return; } if (strcmp(tokens[t0 + 1], "spp") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp"); return; } if (parser_read_uint32(&p.tm.n_subports_per_port, tokens[t0 + 2]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "n_subports_per_port"); return; } if (strcmp(tokens[t0 + 3], "pps") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps"); return; } if (parser_read_uint32(&p.tm.n_pipes_per_subport, tokens[t0 + 4]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "n_pipes_per_subport"); return; } p.action_mask |= 1LLU << RTE_TABLE_ACTION_TM; t0 += 5; } /* tm */ if ((t0 < n_tokens) && (strcmp(tokens[t0], "encap") == 0)) { uint32_t n_extra_tokens = 0; if (n_tokens < t0 + 2) { snprintf(out, out_size, MSG_ARG_MISMATCH, "action profile encap"); return; } if (strcmp(tokens[t0 + 1], "ether") == 0) p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_ETHER; else if (strcmp(tokens[t0 + 1], "vlan") == 0) p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_VLAN; else if (strcmp(tokens[t0 + 1], "qinq") == 0) p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_QINQ; else if (strcmp(tokens[t0 + 1], "mpls") == 0) p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_MPLS; else if (strcmp(tokens[t0 + 1], "pppoe") == 0) p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_PPPOE; else if (strcmp(tokens[t0 + 1], "vxlan") == 0) { if (n_tokens < t0 + 2 + 5) { snprintf(out, out_size, MSG_ARG_MISMATCH, "action profile encap vxlan"); return; } if (strcmp(tokens[t0 + 2], "offset") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "vxlan: offset"); return; } if (parser_read_uint32(&p.encap.vxlan.data_offset, tokens[t0 + 2 + 1]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "vxlan: ether_offset"); return; } if (strcmp(tokens[t0 + 2 + 2], "ipv4") == 0) p.encap.vxlan.ip_version = 1; else if (strcmp(tokens[t0 + 2 + 2], "ipv6") == 0) p.encap.vxlan.ip_version = 0; else { snprintf(out, out_size, MSG_ARG_INVALID, "vxlan: ipv4 or ipv6"); return; } if (strcmp(tokens[t0 + 2 + 3], "vlan") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "vxlan: vlan"); return; } if (strcmp(tokens[t0 + 2 + 4], "on") == 0) p.encap.vxlan.vlan = 1; else if (strcmp(tokens[t0 + 2 + 4], "off") == 0) p.encap.vxlan.vlan = 0; else { snprintf(out, out_size, MSG_ARG_INVALID, "vxlan: on or off"); return; } p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_VXLAN; n_extra_tokens = 5; } else { snprintf(out, out_size, MSG_ARG_MISMATCH, "encap"); return; } p.action_mask |= 1LLU << RTE_TABLE_ACTION_ENCAP; t0 += 2 + n_extra_tokens; } /* encap */ if ((t0 < n_tokens) && (strcmp(tokens[t0], "nat") == 0)) { if (n_tokens < t0 + 4) { snprintf(out, out_size, MSG_ARG_MISMATCH, "table action profile nat"); return; } if (strcmp(tokens[t0 + 1], "src") == 0) p.nat.source_nat = 1; else if (strcmp(tokens[t0 + 1], "dst") == 0) p.nat.source_nat = 0; else { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "src or dst"); return; } if (strcmp(tokens[t0 + 2], "proto") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "proto"); return; } if (strcmp(tokens[t0 + 3], "tcp") == 0) p.nat.proto = 0x06; else if (strcmp(tokens[t0 + 3], "udp") == 0) p.nat.proto = 0x11; else { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tcp or udp"); return; } p.action_mask |= 1LLU << RTE_TABLE_ACTION_NAT; t0 += 4; } /* nat */ if ((t0 < n_tokens) && (strcmp(tokens[t0], "ttl") == 0)) { if (n_tokens < t0 + 4) { snprintf(out, out_size, MSG_ARG_MISMATCH, "table action profile ttl"); return; } if (strcmp(tokens[t0 + 1], "drop") == 0) p.ttl.drop = 1; else if (strcmp(tokens[t0 + 1], "fwd") == 0) p.ttl.drop = 0; else { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "drop or fwd"); return; } if (strcmp(tokens[t0 + 2], "stats") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); return; } if (strcmp(tokens[t0 + 3], "none") == 0) p.ttl.n_packets_enabled = 0; else if (strcmp(tokens[t0 + 3], "pkts") == 0) p.ttl.n_packets_enabled = 1; else { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "none or pkts"); return; } p.action_mask |= 1LLU << RTE_TABLE_ACTION_TTL; t0 += 4; } /* ttl */ if ((t0 < n_tokens) && (strcmp(tokens[t0], "stats") == 0)) { if (n_tokens < t0 + 2) { snprintf(out, out_size, MSG_ARG_MISMATCH, "table action profile stats"); return; } if (strcmp(tokens[t0 + 1], "pkts") == 0) { p.stats.n_packets_enabled = 1; p.stats.n_bytes_enabled = 0; } else if (strcmp(tokens[t0 + 1], "bytes") == 0) { p.stats.n_packets_enabled = 0; p.stats.n_bytes_enabled = 1; } else if (strcmp(tokens[t0 + 1], "both") == 0) { p.stats.n_packets_enabled = 1; p.stats.n_bytes_enabled = 1; } else { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pkts or bytes or both"); return; } p.action_mask |= 1LLU << RTE_TABLE_ACTION_STATS; t0 += 2; } /* stats */ if ((t0 < n_tokens) && (strcmp(tokens[t0], "time") == 0)) { p.action_mask |= 1LLU << RTE_TABLE_ACTION_TIME; t0 += 1; } /* time */ if ((t0 < n_tokens) && (strcmp(tokens[t0], "sym_crypto") == 0)) { struct cryptodev *cryptodev; struct mempool *mempool; if (n_tokens < t0 + 9 || strcmp(tokens[t0 + 1], "dev") || strcmp(tokens[t0 + 3], "offset") || strcmp(tokens[t0 + 5], "mempool_create") || strcmp(tokens[t0 + 7], "mempool_init")) { snprintf(out, out_size, MSG_ARG_MISMATCH, "table action profile sym_crypto"); return; } cryptodev = cryptodev_find(tokens[t0 + 2]); if (cryptodev == NULL) { snprintf(out, out_size, MSG_ARG_INVALID, "table action profile sym_crypto"); return; } p.sym_crypto.cryptodev_id = cryptodev->dev_id; if (parser_read_uint32(&p.sym_crypto.op_offset, tokens[t0 + 4]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "table action profile sym_crypto"); return; } mempool = mempool_find(tokens[t0 + 6]); if (mempool == NULL) { snprintf(out, out_size, MSG_ARG_INVALID, "table action profile sym_crypto"); return; } p.sym_crypto.mp_create = mempool->m; mempool = mempool_find(tokens[t0 + 8]); if (mempool == NULL) { snprintf(out, out_size, MSG_ARG_INVALID, "table action profile sym_crypto"); return; } p.sym_crypto.mp_init = mempool->m; p.action_mask |= 1LLU << RTE_TABLE_ACTION_SYM_CRYPTO; t0 += 9; } /* sym_crypto */ if ((t0 < n_tokens) && (strcmp(tokens[t0], "tag") == 0)) { p.action_mask |= 1LLU << RTE_TABLE_ACTION_TAG; t0 += 1; } /* tag */ if ((t0 < n_tokens) && (strcmp(tokens[t0], "decap") == 0)) { p.action_mask |= 1LLU << RTE_TABLE_ACTION_DECAP; t0 += 1; } /* decap */ if (t0 < n_tokens) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } ap = table_action_profile_create(name, &p); if (ap == NULL) { snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); return; } } static const char cmd_pipeline_help[] = "pipeline \n" " period \n" " offset_port_id \n" " cpu \n"; static void cmd_pipeline(char **tokens, uint32_t n_tokens, char *out, size_t out_size) { struct pipeline_params p; char *name; struct pipeline *pipeline; if (n_tokens != 8) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } name = tokens[1]; if (strcmp(tokens[2], "period") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "period"); return; } if (parser_read_uint32(&p.timer_period_ms, tokens[3]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "timer_period_ms"); return; } if (strcmp(tokens[4], "offset_port_id") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset_port_id"); return; } if (parser_read_uint32(&p.offset_port_id, tokens[5]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "offset_port_id"); return; } if (strcmp(tokens[6], "cpu") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu"); return; } if (parser_read_uint32(&p.cpu_id, tokens[7]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id"); return; } pipeline = pipeline_create(name, &p); if (pipeline == NULL) { snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); return; } } static const char cmd_pipeline_port_in_help[] = "pipeline port in\n" " bsz \n" " link rxq \n" " | swq \n" " | tmgr \n" " | tap mempool mtu \n" " | kni \n" " | source mempool file bpp \n" " | cryptodev rxq \n" " [action ]\n" " [disabled]\n"; static void cmd_pipeline_port_in(char **tokens, uint32_t n_tokens, char *out, size_t out_size) { struct port_in_params p; char *pipeline_name; uint32_t t0; int enabled, status; if (n_tokens < 7) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } pipeline_name = tokens[1]; if (strcmp(tokens[2], "port") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); return; } if (strcmp(tokens[3], "in") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in"); return; } if (strcmp(tokens[4], "bsz") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz"); return; } if (parser_read_uint32(&p.burst_size, tokens[5]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "burst_size"); return; } t0 = 6; if (strcmp(tokens[t0], "link") == 0) { if (n_tokens < t0 + 4) { snprintf(out, out_size, MSG_ARG_MISMATCH, "pipeline port in link"); return; } p.type = PORT_IN_RXQ; p.dev_name = tokens[t0 + 1]; if (strcmp(tokens[t0 + 2], "rxq") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq"); return; } if (parser_read_uint16(&p.rxq.queue_id, tokens[t0 + 3]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "queue_id"); return; } t0 += 4; } else if (strcmp(tokens[t0], "swq") == 0) { if (n_tokens < t0 + 2) { snprintf(out, out_size, MSG_ARG_MISMATCH, "pipeline port in swq"); return; } p.type = PORT_IN_SWQ; p.dev_name = tokens[t0 + 1]; t0 += 2; } else if (strcmp(tokens[t0], "tmgr") == 0) { if (n_tokens < t0 + 2) { snprintf(out, out_size, MSG_ARG_MISMATCH, "pipeline port in tmgr"); return; } p.type = PORT_IN_TMGR; p.dev_name = tokens[t0 + 1]; t0 += 2; } else if (strcmp(tokens[t0], "tap") == 0) { if (n_tokens < t0 + 6) { snprintf(out, out_size, MSG_ARG_MISMATCH, "pipeline port in tap"); return; } p.type = PORT_IN_TAP; p.dev_name = tokens[t0 + 1]; if (strcmp(tokens[t0 + 2], "mempool") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mempool"); return; } p.tap.mempool_name = tokens[t0 + 3]; if (strcmp(tokens[t0 + 4], "mtu") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mtu"); return; } if (parser_read_uint32(&p.tap.mtu, tokens[t0 + 5]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "mtu"); return; } t0 += 6; } else if (strcmp(tokens[t0], "kni") == 0) { if (n_tokens < t0 + 2) { snprintf(out, out_size, MSG_ARG_MISMATCH, "pipeline port in kni"); return; } p.type = PORT_IN_KNI; p.dev_name = tokens[t0 + 1]; t0 += 2; } else if (strcmp(tokens[t0], "source") == 0) { if (n_tokens < t0 + 6) { snprintf(out, out_size, MSG_ARG_MISMATCH, "pipeline port in source"); return; } p.type = PORT_IN_SOURCE; p.dev_name = NULL; if (strcmp(tokens[t0 + 1], "mempool") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mempool"); return; } p.source.mempool_name = tokens[t0 + 2]; if (strcmp(tokens[t0 + 3], "file") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "file"); return; } p.source.file_name = tokens[t0 + 4]; if (strcmp(tokens[t0 + 5], "bpp") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bpp"); return; } if (parser_read_uint32(&p.source.n_bytes_per_pkt, tokens[t0 + 6]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "n_bytes_per_pkt"); return; } t0 += 7; } else if (strcmp(tokens[t0], "cryptodev") == 0) { if (n_tokens < t0 + 3) { snprintf(out, out_size, MSG_ARG_MISMATCH, "pipeline port in cryptodev"); return; } p.type = PORT_IN_CRYPTODEV; p.dev_name = tokens[t0 + 1]; if (parser_read_uint16(&p.rxq.queue_id, tokens[t0 + 3]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "rxq"); return; } p.cryptodev.arg_callback = NULL; p.cryptodev.f_callback = NULL; t0 += 4; } else { snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); return; } p.action_profile_name = NULL; if ((n_tokens > t0) && (strcmp(tokens[t0], "action") == 0)) { if (n_tokens < t0 + 2) { snprintf(out, out_size, MSG_ARG_MISMATCH, "action"); return; } p.action_profile_name = tokens[t0 + 1]; t0 += 2; } enabled = 1; if ((n_tokens > t0) && (strcmp(tokens[t0], "disabled") == 0)) { enabled = 0; t0 += 1; } if (n_tokens != t0) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } status = pipeline_port_in_create(pipeline_name, &p, enabled); if (status) { snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); return; } } static const char cmd_pipeline_port_out_help[] = "pipeline port out\n" " bsz \n" " link txq \n" " | swq \n" " | tmgr \n" " | tap \n" " | kni \n" " | sink [file pkts ]\n" " | cryptodev txq offset \n"; static void cmd_pipeline_port_out(char **tokens, uint32_t n_tokens, char *out, size_t out_size) { struct port_out_params p; char *pipeline_name; int status; memset(&p, 0, sizeof(p)); if (n_tokens < 7) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } pipeline_name = tokens[1]; if (strcmp(tokens[2], "port") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); return; } if (strcmp(tokens[3], "out") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out"); return; } if (strcmp(tokens[4], "bsz") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz"); return; } if (parser_read_uint32(&p.burst_size, tokens[5]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "burst_size"); return; } if (strcmp(tokens[6], "link") == 0) { if (n_tokens != 10) { snprintf(out, out_size, MSG_ARG_MISMATCH, "pipeline port out link"); return; } p.type = PORT_OUT_TXQ; p.dev_name = tokens[7]; if (strcmp(tokens[8], "txq") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq"); return; } if (parser_read_uint16(&p.txq.queue_id, tokens[9]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "queue_id"); return; } } else if (strcmp(tokens[6], "swq") == 0) { if (n_tokens != 8) { snprintf(out, out_size, MSG_ARG_MISMATCH, "pipeline port out swq"); return; } p.type = PORT_OUT_SWQ; p.dev_name = tokens[7]; } else if (strcmp(tokens[6], "tmgr") == 0) { if (n_tokens != 8) { snprintf(out, out_size, MSG_ARG_MISMATCH, "pipeline port out tmgr"); return; } p.type = PORT_OUT_TMGR; p.dev_name = tokens[7]; } else if (strcmp(tokens[6], "tap") == 0) { if (n_tokens != 8) { snprintf(out, out_size, MSG_ARG_MISMATCH, "pipeline port out tap"); return; } p.type = PORT_OUT_TAP; p.dev_name = tokens[7]; } else if (strcmp(tokens[6], "kni") == 0) { if (n_tokens != 8) { snprintf(out, out_size, MSG_ARG_MISMATCH, "pipeline port out kni"); return; } p.type = PORT_OUT_KNI; p.dev_name = tokens[7]; } else if (strcmp(tokens[6], "sink") == 0) { if ((n_tokens != 7) && (n_tokens != 11)) { snprintf(out, out_size, MSG_ARG_MISMATCH, "pipeline port out sink"); return; } p.type = PORT_OUT_SINK; p.dev_name = NULL; if (n_tokens == 7) { p.sink.file_name = NULL; p.sink.max_n_pkts = 0; } else { if (strcmp(tokens[7], "file") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "file"); return; } p.sink.file_name = tokens[8]; if (strcmp(tokens[9], "pkts") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pkts"); return; } if (parser_read_uint32(&p.sink.max_n_pkts, tokens[10]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "max_n_pkts"); return; } } } else if (strcmp(tokens[6], "cryptodev") == 0) { if (n_tokens != 12) { snprintf(out, out_size, MSG_ARG_MISMATCH, "pipeline port out cryptodev"); return; } p.type = PORT_OUT_CRYPTODEV; p.dev_name = tokens[7]; if (strcmp(tokens[8], "txq")) { snprintf(out, out_size, MSG_ARG_MISMATCH, "pipeline port out cryptodev"); return; } if (parser_read_uint16(&p.cryptodev.queue_id, tokens[9]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "queue_id"); return; } if (strcmp(tokens[10], "offset")) { snprintf(out, out_size, MSG_ARG_MISMATCH, "pipeline port out cryptodev"); return; } if (parser_read_uint32(&p.cryptodev.op_offset, tokens[11]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "queue_id"); return; } } else { snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); return; } status = pipeline_port_out_create(pipeline_name, &p); if (status) { snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); return; } } static const char cmd_pipeline_table_help[] = "pipeline table\n" " match\n" " acl\n" " ipv4 | ipv6\n" " offset \n" " size \n" " | array\n" " offset \n" " size \n" " | hash\n" " ext | lru\n" " key \n" " mask \n" " offset \n" " buckets \n" " size \n" " | lpm\n" " ipv4 | ipv6\n" " offset \n" " size \n" " | stub\n" " [action ]\n"; static void cmd_pipeline_table(char **tokens, uint32_t n_tokens, char *out, size_t out_size) { uint8_t key_mask[TABLE_RULE_MATCH_SIZE_MAX]; struct table_params p; char *pipeline_name; uint32_t t0; int status; if (n_tokens < 5) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } pipeline_name = tokens[1]; if (strcmp(tokens[2], "table") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); return; } if (strcmp(tokens[3], "match") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match"); return; } t0 = 4; if (strcmp(tokens[t0], "acl") == 0) { if (n_tokens < t0 + 6) { snprintf(out, out_size, MSG_ARG_MISMATCH, "pipeline table acl"); return; } p.match_type = TABLE_ACL; if (strcmp(tokens[t0 + 1], "ipv4") == 0) p.match.acl.ip_version = 1; else if (strcmp(tokens[t0 + 1], "ipv6") == 0) p.match.acl.ip_version = 0; else { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "ipv4 or ipv6"); return; } if (strcmp(tokens[t0 + 2], "offset") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); return; } if (parser_read_uint32(&p.match.acl.ip_header_offset, tokens[t0 + 3]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "ip_header_offset"); return; } if (strcmp(tokens[t0 + 4], "size") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); return; } if (parser_read_uint32(&p.match.acl.n_rules, tokens[t0 + 5]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "n_rules"); return; } t0 += 6; } else if (strcmp(tokens[t0], "array") == 0) { if (n_tokens < t0 + 5) { snprintf(out, out_size, MSG_ARG_MISMATCH, "pipeline table array"); return; } p.match_type = TABLE_ARRAY; if (strcmp(tokens[t0 + 1], "offset") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); return; } if (parser_read_uint32(&p.match.array.key_offset, tokens[t0 + 2]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); return; } if (strcmp(tokens[t0 + 3], "size") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); return; } if (parser_read_uint32(&p.match.array.n_keys, tokens[t0 + 4]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "n_keys"); return; } t0 += 5; } else if (strcmp(tokens[t0], "hash") == 0) { uint32_t key_mask_size = TABLE_RULE_MATCH_SIZE_MAX; if (n_tokens < t0 + 12) { snprintf(out, out_size, MSG_ARG_MISMATCH, "pipeline table hash"); return; } p.match_type = TABLE_HASH; if (strcmp(tokens[t0 + 1], "ext") == 0) p.match.hash.extendable_bucket = 1; else if (strcmp(tokens[t0 + 1], "lru") == 0) p.match.hash.extendable_bucket = 0; else { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "ext or lru"); return; } if (strcmp(tokens[t0 + 2], "key") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key"); return; } if ((parser_read_uint32(&p.match.hash.key_size, tokens[t0 + 3]) != 0) || (p.match.hash.key_size == 0) || (p.match.hash.key_size > TABLE_RULE_MATCH_SIZE_MAX)) { snprintf(out, out_size, MSG_ARG_INVALID, "key_size"); return; } if (strcmp(tokens[t0 + 4], "mask") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask"); return; } if ((parse_hex_string(tokens[t0 + 5], key_mask, &key_mask_size) != 0) || (key_mask_size != p.match.hash.key_size)) { snprintf(out, out_size, MSG_ARG_INVALID, "key_mask"); return; } p.match.hash.key_mask = key_mask; if (strcmp(tokens[t0 + 6], "offset") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); return; } if (parser_read_uint32(&p.match.hash.key_offset, tokens[t0 + 7]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); return; } if (strcmp(tokens[t0 + 8], "buckets") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buckets"); return; } if (parser_read_uint32(&p.match.hash.n_buckets, tokens[t0 + 9]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "n_buckets"); return; } if (strcmp(tokens[t0 + 10], "size") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); return; } if (parser_read_uint32(&p.match.hash.n_keys, tokens[t0 + 11]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "n_keys"); return; } t0 += 12; } else if (strcmp(tokens[t0], "lpm") == 0) { if (n_tokens < t0 + 6) { snprintf(out, out_size, MSG_ARG_MISMATCH, "pipeline table lpm"); return; } p.match_type = TABLE_LPM; if (strcmp(tokens[t0 + 1], "ipv4") == 0) p.match.lpm.key_size = 4; else if (strcmp(tokens[t0 + 1], "ipv6") == 0) p.match.lpm.key_size = 16; else { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "ipv4 or ipv6"); return; } if (strcmp(tokens[t0 + 2], "offset") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); return; } if (parser_read_uint32(&p.match.lpm.key_offset, tokens[t0 + 3]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); return; } if (strcmp(tokens[t0 + 4], "size") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); return; } if (parser_read_uint32(&p.match.lpm.n_rules, tokens[t0 + 5]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "n_rules"); return; } t0 += 6; } else if (strcmp(tokens[t0], "stub") == 0) { p.match_type = TABLE_STUB; t0 += 1; } else { snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); return; } p.action_profile_name = NULL; if ((n_tokens > t0) && (strcmp(tokens[t0], "action") == 0)) { if (n_tokens < t0 + 2) { snprintf(out, out_size, MSG_ARG_MISMATCH, "action"); return; } p.action_profile_name = tokens[t0 + 1]; t0 += 2; } if (n_tokens > t0) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } status = pipeline_table_create(pipeline_name, &p); if (status) { snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); return; } } static const char cmd_pipeline_port_in_table_help[] = "pipeline port in table \n"; static void cmd_pipeline_port_in_table(char **tokens, uint32_t n_tokens, char *out, size_t out_size) { char *pipeline_name; uint32_t port_id, table_id; int status; if (n_tokens != 7) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } pipeline_name = tokens[1]; if (strcmp(tokens[2], "port") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); return; } if (strcmp(tokens[3], "in") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in"); return; } if (parser_read_uint32(&port_id, tokens[4]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); return; } if (strcmp(tokens[5], "table") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); return; } if (parser_read_uint32(&table_id, tokens[6]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); return; } status = pipeline_port_in_connect_to_table(pipeline_name, port_id, table_id); if (status) { snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); return; } } static const char cmd_pipeline_port_in_stats_help[] = "pipeline port in stats read [clear]\n"; #define MSG_PIPELINE_PORT_IN_STATS \ "Pkts in: %" PRIu64 "\n" \ "Pkts dropped by AH: %" PRIu64 "\n" \ "Pkts dropped by other: %" PRIu64 "\n" static void cmd_pipeline_port_in_stats(char **tokens, uint32_t n_tokens, char *out, size_t out_size) { struct rte_pipeline_port_in_stats stats; char *pipeline_name; uint32_t port_id; int clear, status; if ((n_tokens != 7) && (n_tokens != 8)) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } pipeline_name = tokens[1]; if (strcmp(tokens[2], "port") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); return; } if (strcmp(tokens[3], "in") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in"); return; } if (parser_read_uint32(&port_id, tokens[4]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); return; } if (strcmp(tokens[5], "stats") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); return; } if (strcmp(tokens[6], "read") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read"); return; } clear = 0; if (n_tokens == 8) { if (strcmp(tokens[7], "clear") != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "clear"); return; } clear = 1; } status = pipeline_port_in_stats_read(pipeline_name, port_id, &stats, clear); if (status) { snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); return; } snprintf(out, out_size, MSG_PIPELINE_PORT_IN_STATS, stats.stats.n_pkts_in, stats.n_pkts_dropped_by_ah, stats.stats.n_pkts_drop); } static const char cmd_pipeline_port_in_enable_help[] = "pipeline port in enable\n"; static void cmd_pipeline_port_in_enable(char **tokens, uint32_t n_tokens, char *out, size_t out_size) { char *pipeline_name; uint32_t port_id; int status; if (n_tokens != 6) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } pipeline_name = tokens[1]; if (strcmp(tokens[2], "port") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); return; } if (strcmp(tokens[3], "in") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in"); return; } if (parser_read_uint32(&port_id, tokens[4]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); return; } if (strcmp(tokens[5], "enable") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable"); return; } status = pipeline_port_in_enable(pipeline_name, port_id); if (status) { snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); return; } } static const char cmd_pipeline_port_in_disable_help[] = "pipeline port in disable\n"; static void cmd_pipeline_port_in_disable(char **tokens, uint32_t n_tokens, char *out, size_t out_size) { char *pipeline_name; uint32_t port_id; int status; if (n_tokens != 6) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } pipeline_name = tokens[1]; if (strcmp(tokens[2], "port") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); return; } if (strcmp(tokens[3], "in") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in"); return; } if (parser_read_uint32(&port_id, tokens[4]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); return; } if (strcmp(tokens[5], "disable") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable"); return; } status = pipeline_port_in_disable(pipeline_name, port_id); if (status) { snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); return; } } static const char cmd_pipeline_port_out_stats_help[] = "pipeline port out stats read [clear]\n"; #define MSG_PIPELINE_PORT_OUT_STATS \ "Pkts in: %" PRIu64 "\n" \ "Pkts dropped by AH: %" PRIu64 "\n" \ "Pkts dropped by other: %" PRIu64 "\n" static void cmd_pipeline_port_out_stats(char **tokens, uint32_t n_tokens, char *out, size_t out_size) { struct rte_pipeline_port_out_stats stats; char *pipeline_name; uint32_t port_id; int clear, status; if ((n_tokens != 7) && (n_tokens != 8)) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } pipeline_name = tokens[1]; if (strcmp(tokens[2], "port") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); return; } if (strcmp(tokens[3], "out") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out"); return; } if (parser_read_uint32(&port_id, tokens[4]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); return; } if (strcmp(tokens[5], "stats") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); return; } if (strcmp(tokens[6], "read") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read"); return; } clear = 0; if (n_tokens == 8) { if (strcmp(tokens[7], "clear") != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "clear"); return; } clear = 1; } status = pipeline_port_out_stats_read(pipeline_name, port_id, &stats, clear); if (status) { snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); return; } snprintf(out, out_size, MSG_PIPELINE_PORT_OUT_STATS, stats.stats.n_pkts_in, stats.n_pkts_dropped_by_ah, stats.stats.n_pkts_drop); } static const char cmd_pipeline_table_stats_help[] = "pipeline table stats read [clear]\n"; #define MSG_PIPELINE_TABLE_STATS \ "Pkts in: %" PRIu64 "\n" \ "Pkts in with lookup miss: %" PRIu64 "\n" \ "Pkts in with lookup hit dropped by AH: %" PRIu64 "\n" \ "Pkts in with lookup hit dropped by others: %" PRIu64 "\n" \ "Pkts in with lookup miss dropped by AH: %" PRIu64 "\n" \ "Pkts in with lookup miss dropped by others: %" PRIu64 "\n" static void cmd_pipeline_table_stats(char **tokens, uint32_t n_tokens, char *out, size_t out_size) { struct rte_pipeline_table_stats stats; char *pipeline_name; uint32_t table_id; int clear, status; if ((n_tokens != 6) && (n_tokens != 7)) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } pipeline_name = tokens[1]; if (strcmp(tokens[2], "table") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); return; } if (parser_read_uint32(&table_id, tokens[3]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); return; } if (strcmp(tokens[4], "stats") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); return; } if (strcmp(tokens[5], "read") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read"); return; } clear = 0; if (n_tokens == 7) { if (strcmp(tokens[6], "clear") != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "clear"); return; } clear = 1; } status = pipeline_table_stats_read(pipeline_name, table_id, &stats, clear); if (status) { snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); return; } snprintf(out, out_size, MSG_PIPELINE_TABLE_STATS, stats.stats.n_pkts_in, stats.stats.n_pkts_lookup_miss, stats.n_pkts_dropped_by_lkp_hit_ah, stats.n_pkts_dropped_lkp_hit, stats.n_pkts_dropped_by_lkp_miss_ah, stats.n_pkts_dropped_lkp_miss); } /** * ::= * * match * acl * priority * ipv4 | ipv6 * * | array * | hash * raw * | ipv4_5tuple * | ipv6_5tuple * | ipv4_addr * | ipv6_addr * | qinq * | lpm * ipv4 | ipv6 */ struct pkt_key_qinq { uint16_t ethertype_svlan; uint16_t svlan; uint16_t ethertype_cvlan; uint16_t cvlan; } __attribute__((__packed__)); struct pkt_key_ipv4_5tuple { uint8_t time_to_live; uint8_t proto; uint16_t hdr_checksum; uint32_t sa; uint32_t da; uint16_t sp; uint16_t dp; } __attribute__((__packed__)); struct pkt_key_ipv6_5tuple { uint16_t payload_length; uint8_t proto; uint8_t hop_limit; uint8_t sa[16]; uint8_t da[16]; uint16_t sp; uint16_t dp; } __attribute__((__packed__)); struct pkt_key_ipv4_addr { uint32_t addr; } __attribute__((__packed__)); struct pkt_key_ipv6_addr { uint8_t addr[16]; } __attribute__((__packed__)); static uint32_t parse_match(char **tokens, uint32_t n_tokens, char *out, size_t out_size, struct table_rule_match *m) { memset(m, 0, sizeof(*m)); if (n_tokens < 2) return 0; if (strcmp(tokens[0], "match") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match"); return 0; } if (strcmp(tokens[1], "acl") == 0) { if (n_tokens < 14) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return 0; } m->match_type = TABLE_ACL; if (strcmp(tokens[2], "priority") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "priority"); return 0; } if (parser_read_uint32(&m->match.acl.priority, tokens[3]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "priority"); return 0; } if (strcmp(tokens[4], "ipv4") == 0) { struct in_addr saddr, daddr; m->match.acl.ip_version = 1; if (parse_ipv4_addr(tokens[5], &saddr) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "sa"); return 0; } m->match.acl.ipv4.sa = rte_be_to_cpu_32(saddr.s_addr); if (parse_ipv4_addr(tokens[7], &daddr) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "da"); return 0; } m->match.acl.ipv4.da = rte_be_to_cpu_32(daddr.s_addr); } else if (strcmp(tokens[4], "ipv6") == 0) { struct in6_addr saddr, daddr; m->match.acl.ip_version = 0; if (parse_ipv6_addr(tokens[5], &saddr) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "sa"); return 0; } memcpy(m->match.acl.ipv6.sa, saddr.s6_addr, 16); if (parse_ipv6_addr(tokens[7], &daddr) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "da"); return 0; } memcpy(m->match.acl.ipv6.da, daddr.s6_addr, 16); } else { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "ipv4 or ipv6"); return 0; } if (parser_read_uint32(&m->match.acl.sa_depth, tokens[6]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "sa_depth"); return 0; } if (parser_read_uint32(&m->match.acl.da_depth, tokens[8]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "da_depth"); return 0; } if (parser_read_uint16(&m->match.acl.sp0, tokens[9]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "sp0"); return 0; } if (parser_read_uint16(&m->match.acl.sp1, tokens[10]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "sp1"); return 0; } if (parser_read_uint16(&m->match.acl.dp0, tokens[11]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "dp0"); return 0; } if (parser_read_uint16(&m->match.acl.dp1, tokens[12]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "dp1"); return 0; } if (parser_read_uint8(&m->match.acl.proto, tokens[13]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "proto"); return 0; } m->match.acl.proto_mask = 0xff; return 14; } /* acl */ if (strcmp(tokens[1], "array") == 0) { if (n_tokens < 3) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return 0; } m->match_type = TABLE_ARRAY; if (parser_read_uint32(&m->match.array.pos, tokens[2]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "pos"); return 0; } return 3; } /* array */ if (strcmp(tokens[1], "hash") == 0) { if (n_tokens < 3) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return 0; } m->match_type = TABLE_HASH; if (strcmp(tokens[2], "raw") == 0) { uint32_t key_size = TABLE_RULE_MATCH_SIZE_MAX; if (n_tokens < 4) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return 0; } if (parse_hex_string(tokens[3], m->match.hash.key, &key_size) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "key"); return 0; } return 4; } /* hash raw */ if (strcmp(tokens[2], "ipv4_5tuple") == 0) { struct pkt_key_ipv4_5tuple *ipv4 = (struct pkt_key_ipv4_5tuple *) m->match.hash.key; struct in_addr saddr, daddr; uint16_t sp, dp; uint8_t proto; if (n_tokens < 8) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return 0; } if (parse_ipv4_addr(tokens[3], &saddr) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "sa"); return 0; } if (parse_ipv4_addr(tokens[4], &daddr) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "da"); return 0; } if (parser_read_uint16(&sp, tokens[5]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "sp"); return 0; } if (parser_read_uint16(&dp, tokens[6]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "dp"); return 0; } if (parser_read_uint8(&proto, tokens[7]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "proto"); return 0; } ipv4->sa = saddr.s_addr; ipv4->da = daddr.s_addr; ipv4->sp = rte_cpu_to_be_16(sp); ipv4->dp = rte_cpu_to_be_16(dp); ipv4->proto = proto; return 8; } /* hash ipv4_5tuple */ if (strcmp(tokens[2], "ipv6_5tuple") == 0) { struct pkt_key_ipv6_5tuple *ipv6 = (struct pkt_key_ipv6_5tuple *) m->match.hash.key; struct in6_addr saddr, daddr; uint16_t sp, dp; uint8_t proto; if (n_tokens < 8) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return 0; } if (parse_ipv6_addr(tokens[3], &saddr) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "sa"); return 0; } if (parse_ipv6_addr(tokens[4], &daddr) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "da"); return 0; } if (parser_read_uint16(&sp, tokens[5]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "sp"); return 0; } if (parser_read_uint16(&dp, tokens[6]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "dp"); return 0; } if (parser_read_uint8(&proto, tokens[7]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "proto"); return 0; } memcpy(ipv6->sa, saddr.s6_addr, 16); memcpy(ipv6->da, daddr.s6_addr, 16); ipv6->sp = rte_cpu_to_be_16(sp); ipv6->dp = rte_cpu_to_be_16(dp); ipv6->proto = proto; return 8; } /* hash ipv6_5tuple */ if (strcmp(tokens[2], "ipv4_addr") == 0) { struct pkt_key_ipv4_addr *ipv4_addr = (struct pkt_key_ipv4_addr *) m->match.hash.key; struct in_addr addr; if (n_tokens < 4) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return 0; } if (parse_ipv4_addr(tokens[3], &addr) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "addr"); return 0; } ipv4_addr->addr = addr.s_addr; return 4; } /* hash ipv4_addr */ if (strcmp(tokens[2], "ipv6_addr") == 0) { struct pkt_key_ipv6_addr *ipv6_addr = (struct pkt_key_ipv6_addr *) m->match.hash.key; struct in6_addr addr; if (n_tokens < 4) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return 0; } if (parse_ipv6_addr(tokens[3], &addr) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "addr"); return 0; } memcpy(ipv6_addr->addr, addr.s6_addr, 16); return 4; } /* hash ipv6_5tuple */ if (strcmp(tokens[2], "qinq") == 0) { struct pkt_key_qinq *qinq = (struct pkt_key_qinq *) m->match.hash.key; uint16_t svlan, cvlan; if (n_tokens < 5) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return 0; } if ((parser_read_uint16(&svlan, tokens[3]) != 0) || (svlan > 0xFFF)) { snprintf(out, out_size, MSG_ARG_INVALID, "svlan"); return 0; } if ((parser_read_uint16(&cvlan, tokens[4]) != 0) || (cvlan > 0xFFF)) { snprintf(out, out_size, MSG_ARG_INVALID, "cvlan"); return 0; } qinq->svlan = rte_cpu_to_be_16(svlan); qinq->cvlan = rte_cpu_to_be_16(cvlan); return 5; } /* hash qinq */ snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return 0; } /* hash */ if (strcmp(tokens[1], "lpm") == 0) { if (n_tokens < 5) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return 0; } m->match_type = TABLE_LPM; if (strcmp(tokens[2], "ipv4") == 0) { struct in_addr addr; m->match.lpm.ip_version = 1; if (parse_ipv4_addr(tokens[3], &addr) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "addr"); return 0; } m->match.lpm.ipv4 = rte_be_to_cpu_32(addr.s_addr); } else if (strcmp(tokens[2], "ipv6") == 0) { struct in6_addr addr; m->match.lpm.ip_version = 0; if (parse_ipv6_addr(tokens[3], &addr) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "addr"); return 0; } memcpy(m->match.lpm.ipv6, addr.s6_addr, 16); } else { snprintf(out, out_size, MSG_ARG_MISMATCH, "ipv4 or ipv6"); return 0; } if (parser_read_uint8(&m->match.lpm.depth, tokens[4]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "depth"); return 0; } return 5; } /* lpm */ snprintf(out, out_size, MSG_ARG_MISMATCH, "acl or array or hash or lpm"); return 0; } /** * table_action ::= * * action * fwd * drop * | port * | meta * | table * [balance ... ] * [meter * tc0 meter policer g y r * [tc1 meter policer g y r * tc2 meter policer g y r * tc3 meter policer g y r ]] * [tm subport pipe ] * [encap * ether * | vlan * | qinq * | mpls unicast | multicast * * label0