Added l2fwd usecase for graph Signed-off-by: Rakesh Kudurumalla <rkuduruma...@marvell.com> --- app/graph/cli.c | 1 + app/graph/examples/l2fwd.cli | 41 ++++++++++ app/graph/graph.c | 8 +- app/graph/l2fwd.c | 148 +++++++++++++++++++++++++++++++++++ app/graph/l2fwd.h | 11 +++ app/graph/meson.build | 2 + app/graph/module_api.h | 2 + app/graph/portfwd.c | 110 ++++++++++++++++++++++++++ app/graph/portfwd.h | 21 +++++ app/graph/portfwd_priv.h | 14 ++++ 10 files changed, 357 insertions(+), 1 deletion(-) create mode 100644 app/graph/examples/l2fwd.cli create mode 100644 app/graph/l2fwd.c create mode 100644 app/graph/l2fwd.h create mode 100644 app/graph/portfwd.c create mode 100644 app/graph/portfwd.h create mode 100644 app/graph/portfwd_priv.h
diff --git a/app/graph/cli.c b/app/graph/cli.c index 30b12312d6..76f5b8e670 100644 --- a/app/graph/cli.c +++ b/app/graph/cli.c @@ -32,6 +32,7 @@ cmdline_parse_ctx_t modules_ctx[] = { (cmdline_parse_inst_t *)ðdev_prom_mode_cmd_ctx, (cmdline_parse_inst_t *)ðdev_ip4_cmd_ctx, (cmdline_parse_inst_t *)ðdev_ip6_cmd_ctx, + (cmdline_parse_inst_t *)ðdev_forward_cmd_ctx, (cmdline_parse_inst_t *)ðdev_cmd_ctx, (cmdline_parse_inst_t *)ðdev_help_cmd_ctx, (cmdline_parse_inst_t *)ðdev_rx_cmd_ctx, diff --git a/app/graph/examples/l2fwd.cli b/app/graph/examples/l2fwd.cli new file mode 100644 index 0000000000..af24a5836a --- /dev/null +++ b/app/graph/examples/l2fwd.cli @@ -0,0 +1,41 @@ +; SPDX-License-Identifier: BSD-3-Clause +; Copyright(c) 2023 Marvell. + +; +; Graph configuration for given usecase +; +graph l2fwd coremask 0xff bsz 32 tmo 10 model default pcap_enable 1 num_pcap_pkts 100000 pcap_file /tmp/output.pcap + +; +; Mempools to be attached with ethdev +; +mempool mempool0 size 8192 buffers 4000 cache 256 numa 0 + +; +; DPDK devices and configuration. +; +; Note: Customize the parameters below to match your setup. +; +ethdev 0002:01:00.1 rxq 1 txq 8 mempool0 +ethdev 0002:01:00.4 rxq 1 txq 8 mempool0 +ethdev 0002:01:00.6 rxq 1 txq 8 mempool0 +ethdev 0002:02:00.0 rxq 1 txq 8 mempool0 + +; +; L2 mac forwarding rules +; +ethdev forward 0002:01:00.4 0002:02:00.0 +ethdev forward 0002:01:00.1 0002:01:00.6 + +; +; Port-Queue-Core mapping for ethdev_rx node +; +ethdev_rx map port 0002:02:00.0 queue 0 core 1 +ethdev_rx map port 0002:01:00.6 queue 0 core 2 + +; +; Graph start command to create graph. +; +; Note: No more command should come after this. +; +graph start diff --git a/app/graph/graph.c b/app/graph/graph.c index a65723a196..4e0441f1a7 100644 --- a/app/graph/graph.c +++ b/app/graph/graph.c @@ -24,7 +24,7 @@ cmd_graph_help[] = "graph <usecases> bsz <size> tmo <ns> coremask <bitmask> " "model <rtc | mcd | default> pcap_enable <0 | 1> num_pcap_pkts <num>" "pcap_file <output_capture_file>"; -static const char * const supported_usecases[] = {"l3fwd"}; +static const char * const supported_usecases[] = {"l3fwd", "l2fwd"}; struct graph_config graph_config; bool graph_started; @@ -273,6 +273,12 @@ cli_graph_start(__rte_unused void *parsed_result, __rte_unused struct cmdline *c break; } } + if (!strcmp(graph_config.usecases[i].name, "l2fwd")) { + if (graph_config.usecases[i].enabled) { + rc = usecase_l2fwd_configure(conf, nb_conf, nb_graphs); + break; + } + } } if (!rc) diff --git a/app/graph/l2fwd.c b/app/graph/l2fwd.c new file mode 100644 index 0000000000..1f18d69ea8 --- /dev/null +++ b/app/graph/l2fwd.c @@ -0,0 +1,148 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Marvell. + */ + +#include <errno.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <rte_common.h> +#include <rte_ethdev.h> +#include <rte_graph.h> +#include <rte_graph_worker.h> +#include <rte_lcore.h> +#include <rte_node_eth_api.h> + +#include "module_api.h" + +static int +l2fwd_pattern_configure(void) +{ + struct rte_graph_param graph_conf; + const char **node_patterns; + uint64_t pcap_pkts_count; + struct lcore_conf *qconf; + uint16_t nb_patterns; + uint8_t pcap_ena; + char *pcap_file; + int lcore_id; + + nb_patterns = 0; + node_patterns = malloc((ETHDEV_RX_QUEUE_PER_LCORE_MAX + nb_patterns) * + sizeof(*node_patterns)); + if (!node_patterns) + return -ENOMEM; + + memset(&graph_conf, 0, sizeof(graph_conf)); + graph_conf.node_patterns = node_patterns; + + /* Pcap config */ + graph_pcap_config_get(&pcap_ena, &pcap_pkts_count, &pcap_file); + graph_conf.pcap_enable = pcap_ena; + graph_conf.num_pkt_to_capture = pcap_pkts_count; + graph_conf.pcap_filename = strdup(pcap_file); + + for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { + rte_graph_t graph_id; + rte_edge_t i; + + if (rte_lcore_is_enabled(lcore_id) == 0) + continue; + + qconf = &lcore_conf[lcore_id]; + + /* Skip graph creation if no source exists */ + if (!qconf->n_rx_queue) + continue; + + /* Add rx node patterns of this lcore */ + for (i = 0; i < qconf->n_rx_queue; i++) { + graph_conf.node_patterns[nb_patterns + i] = + qconf->rx_queue_list[i].node_name; + } + + graph_conf.nb_node_patterns = nb_patterns + i; + graph_conf.socket_id = rte_lcore_to_socket_id(lcore_id); + + snprintf(qconf->name, sizeof(qconf->name), "worker_%u", + lcore_id); + + graph_id = rte_graph_create(qconf->name, &graph_conf); + if (graph_id == RTE_GRAPH_ID_INVALID) + rte_exit(EXIT_FAILURE, + "rte_graph_create(): graph_id invalid" + " for lcore %u\n", lcore_id); + + qconf->graph_id = graph_id; + qconf->graph = rte_graph_lookup(qconf->name); + /* >8 End of graph initialization. */ + if (!qconf->graph) + rte_exit(EXIT_FAILURE, + "rte_graph_lookup(): graph %s not found\n", + qconf->name); + } + + /* Launch per-lcore init on every worker lcore */ + rte_eal_mp_remote_launch(graph_walk_start, NULL, SKIP_MAIN); + + /* Accumulate and print stats on main until exit */ + if (rte_graph_has_stats_feature() && app_graph_stats_enabled()) + graph_stats_print(); + + return 0; +} + +static int +ethdev_rx_to_tx_node_link(uint32_t lcore_id) +{ + struct port_forwarding *port_fwd = NULL; + char name[RTE_NODE_NAMESIZE]; + const char *next_node = name; + struct lcore_conf *qconf; + uint16_t queue, port_id; + rte_node_t rx_id; + int rc; + + qconf = &lcore_conf[lcore_id]; + + for (queue = 0; queue < qconf->n_rx_queue; ++queue) { + port_id = qconf->rx_queue_list[queue].port_id; + port_fwd = find_pf_entry_rx_port(port_id); + if (port_fwd) { + rx_id = rte_node_from_name(qconf->rx_queue_list[queue].node_name); + snprintf(name, sizeof(name), "ethdev_tx-%u", port_fwd->tx_port); + rte_node_edge_update(rx_id, RTE_EDGE_ID_INVALID, &next_node, 1); + rc = rte_node_ethdev_rx_next_update(rx_id, name); + if (rc) + return rc; + } + } + return 0; +} + + +int +usecase_l2fwd_configure(struct rte_node_ethdev_config *conf, uint16_t nb_confs, uint16_t nb_graphs) +{ + uint32_t lcore_id; + int rc; + + rc = rte_node_eth_config(conf, nb_confs, nb_graphs); + if (rc) + rte_exit(EXIT_FAILURE, "rte_node_eth_config: err=%d\n", rc); + + for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { + rc = ethdev_rx_to_tx_node_link(lcore_id); + if (rc) + rte_exit(EXIT_FAILURE, "rte_node_eth_config: err=%d\n", rc); + } + + rc = l2fwd_pattern_configure(); + if (rc) + rte_exit(EXIT_FAILURE, "l2fwd_pattern_failure: err=%d\n", rc); + + return rc; +} diff --git a/app/graph/l2fwd.h b/app/graph/l2fwd.h new file mode 100644 index 0000000000..3486ce52b2 --- /dev/null +++ b/app/graph/l2fwd.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Marvell. + */ + +#ifndef APP_GRAPH_L2FWD_H +#define APP_GRAPH_L2FWD_H + +int usecase_l2fwd_configure(struct rte_node_ethdev_config *conf, uint16_t nb_conf, + uint16_t nb_graphs); + +#endif diff --git a/app/graph/meson.build b/app/graph/meson.build index 5b0f966d99..d8b1f63988 100644 --- a/app/graph/meson.build +++ b/app/graph/meson.build @@ -17,9 +17,11 @@ sources = files( 'graph.c', 'ip4_route.c', 'ip6_route.c', + 'l2fwd.c', 'l3fwd.c', 'main.c', 'mempool.c', 'neigh.c', + 'portfwd.c', 'utils.c', ) diff --git a/app/graph/module_api.h b/app/graph/module_api.h index 7193e0b616..751d6cfb3b 100644 --- a/app/graph/module_api.h +++ b/app/graph/module_api.h @@ -13,9 +13,11 @@ #include "ethdev.h" #include "ethdev_rx.h" #include "graph.h" +#include "l2fwd.h" #include "l3fwd.h" #include "mempool.h" #include "neigh.h" +#include "portfwd.h" #include "route.h" #include "utils.h" diff --git a/app/graph/portfwd.c b/app/graph/portfwd.c new file mode 100644 index 0000000000..6c4b54e1db --- /dev/null +++ b/app/graph/portfwd.c @@ -0,0 +1,110 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Marvell. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <cmdline_parse.h> +#include <cmdline_parse_num.h> +#include <cmdline_parse_string.h> +#include <cmdline_socket.h> +#include <rte_ethdev.h> +#include <rte_node_ip4_api.h> + +#include "module_api.h" +#include "portfwd_priv.h" + +static const char +cmd_ethdev_l2fwd_help[] = "ethdev forward <tx_dev_name> <rx_dev_name>"; + +static struct prt_fw pfw = TAILQ_HEAD_INITIALIZER(pfw); + +struct port_forwarding * +find_pf_entry_rx_port(uint16_t portid_rx) +{ + struct port_forwarding *port_fwd; + + TAILQ_FOREACH(port_fwd, &pfw, next) { + if (port_fwd->rx_port == portid_rx) + return port_fwd; + } + return NULL; +} + +static struct port_forwarding * +find_l2_entry(uint16_t portid_tx, uint16_t portid_rx) +{ + struct port_forwarding *port_fwd; + + TAILQ_FOREACH(port_fwd, &pfw, next) { + if ((port_fwd->tx_port == portid_tx) && + (port_fwd->rx_port == portid_rx)) + return port_fwd; + } + return NULL; +} + +static int +ethdev_pfw_config(char *tx_name, char *rx_name) +{ + struct port_forwarding *pfwd; + uint16_t portid_rx = 0; + uint16_t portid_tx = 0; + int rc; + + rc = rte_eth_dev_get_port_by_name(tx_name, &portid_tx); + if (rc < 0) + return rc; + + rc = rte_eth_dev_get_port_by_name(rx_name, &portid_rx); + if (rc < 0) + return rc; + + pfwd = find_l2_entry(portid_tx, portid_rx); + if (!pfwd) { + pfwd = malloc(sizeof(struct port_forwarding)); + pfwd->tx_port = portid_tx; + pfwd->rx_port = portid_rx; + TAILQ_INSERT_TAIL(&pfw, pfwd, next); + return 0; + } + + return rc; +} + +static void +cli_ethdev_forward(void *parsed_result, __rte_unused struct cmdline *cl, void *data __rte_unused) +{ + struct ethdev_fwd_cmd_tokens *res = parsed_result; + int rc = -EINVAL; + + rc = ethdev_pfw_config(res->tx_dev, res->rx_dev); + if (rc < 0) + printf(MSG_CMD_FAIL, res->cmd); +} + + +cmdline_parse_token_string_t ethdev_l2_cmd = + TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, cmd, "ethdev"); +cmdline_parse_token_string_t ethdev_fwd_cmd = + TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, fwd, "forward"); +cmdline_parse_token_string_t ethdev_tx_device = + TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, tx_dev, NULL); +cmdline_parse_token_string_t ethdev_rx_device = + TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, rx_dev, NULL); + +cmdline_parse_inst_t ethdev_forward_cmd_ctx = { + .f = cli_ethdev_forward, + .data = NULL, + .help_str = cmd_ethdev_l2fwd_help, + .tokens = { + (void *)ðdev_l2_cmd, + (void *)ðdev_fwd_cmd, + (void *)ðdev_tx_device, + (void *)ðdev_rx_device, + NULL, + }, +}; + diff --git a/app/graph/portfwd.h b/app/graph/portfwd.h new file mode 100644 index 0000000000..420fa73746 --- /dev/null +++ b/app/graph/portfwd.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Marvell. + */ + +#ifndef APP_GRAPH_PORTFWD_H +#define APP_GRAPH_PORTFWD_H + +extern cmdline_parse_inst_t ethdev_forward_cmd_ctx; + +struct port_forwarding { + TAILQ_ENTRY(port_forwarding) next; + uint16_t tx_port; + uint16_t rx_port; + bool is_used; +} __rte_cache_aligned; + +TAILQ_HEAD(prt_fw, port_forwarding); + +struct port_forwarding *find_pf_entry_rx_port(uint16_t portid_rx); + +#endif diff --git a/app/graph/portfwd_priv.h b/app/graph/portfwd_priv.h new file mode 100644 index 0000000000..9da1ce6e68 --- /dev/null +++ b/app/graph/portfwd_priv.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Marvell. + */ + +#ifndef APP_GRAPH_PORTFWD_PRIV_H +#define APP_GRAPH_PORTFWD_PRIV_H + +struct ethdev_fwd_cmd_tokens { + cmdline_fixed_string_t cmd; + cmdline_fixed_string_t fwd; + cmdline_fixed_string_t tx_dev; + cmdline_fixed_string_t rx_dev; +}; +#endif -- 2.25.1