/
phprus
/
github_dpdk
Обзор
Документация
Войти
/
phprus
/
github_dpdk
Код
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
app/graph/graph.c
451 строка
11 KB
Nitin Saxena
app/graph: add custom feature nodes for IPv4 output arc
10 июн 2025, 19:22
10 июн 2025, 19:22
08cea83
Код
Авторство
О чём код?
/* 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_graph_worker.h> #include <rte_graph_feature_arc_worker.h> #include <rte_log.h> #include "graph_priv.h" #include "module_api.h" #define RTE_LOGTYPE_APP_GRAPH RTE_LOGTYPE_USER1 static const char cmd_graph_help[] = "graph <usecases> coremask <bitmask> bsz <size> tmo <ns> " "model <rtc | mcd | default> pcap_enable <0 | 1> num_pcap_pkts <num>" "pcap_file <output_capture_file>"; static const char * const supported_usecases[] = {"l3fwd", "l2fwd"}; struct graph_config graph_config; bool graph_started; /* Check the link rc of all ports in up to 9s, and print them finally */ static void check_all_ports_link_status(uint32_t port_mask) { #define CHECK_INTERVAL 100 /* 100ms */ #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */ char link_rc_text[RTE_ETH_LINK_MAX_STR_LEN]; uint8_t count, all_ports_up, print_flag = 0; struct rte_eth_link link; uint16_t portid; int rc; printf("\nChecking link status..."); fflush(stdout); for (count = 0; count <= MAX_CHECK_TIME; count++) { if (force_quit) return; all_ports_up = 1; RTE_ETH_FOREACH_DEV(portid) { if (force_quit) return; if ((port_mask & (1 << portid)) == 0) continue; memset(&link, 0, sizeof(link)); rc = rte_eth_link_get_nowait(portid, &link); if (rc < 0) { all_ports_up = 0; if (print_flag == 1) printf("Port %u link get failed: %s\n", portid, rte_strerror(-rc)); continue; } /* Print link rc if flag set */ if (print_flag == 1) { rte_eth_link_to_str(link_rc_text, sizeof(link_rc_text), &link); printf("Port %d %s\n", portid, link_rc_text); continue; } /* Clear all_ports_up flag if any link down */ if (link.link_status == RTE_ETH_LINK_DOWN) { all_ports_up = 0; break; } } /* After finally printing all link rc, get out */ if (print_flag == 1) break; if (all_ports_up == 0) { printf("."); fflush(stdout); rte_delay_ms(CHECK_INTERVAL); } /* Set the print_flag if all ports up or timeout */ if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) { print_flag = 1; printf("Done\n"); } } } static bool parser_usecases_read(char *usecases) { bool valid = false; uint32_t i, j = 0; char *token, *saveptr = NULL; token = strtok_r(usecases, ",", &saveptr); while (token != NULL) { for (i = 0; i < RTE_DIM(supported_usecases); i++) { if (strcmp(supported_usecases[i], token) == 0) { graph_config.usecases[j].enabled = true; rte_strscpy(graph_config.usecases[j].name, token, 31); valid = true; j++; break; } } token = strtok_r(NULL, ",", &saveptr); } return valid; } static uint64_t graph_worker_count_get(void) { uint64_t nb_worker = 0; uint64_t coremask; coremask = graph_config.params.coremask; while (coremask) { if (coremask & 0x1) nb_worker++; coremask = (coremask >> 1); } return nb_worker; } static struct rte_node_ethdev_config * graph_rxtx_node_config_get(uint32_t *num_conf, uint32_t *num_graphs) { uint32_t n_tx_queue, nb_conf = 0, lcore_id; uint16_t queueid, portid, nb_graphs = 0; uint8_t nb_rx_queue, queue; struct lcore_conf *qconf; n_tx_queue = graph_worker_count_get(); if (n_tx_queue > RTE_MAX_ETHPORTS) n_tx_queue = RTE_MAX_ETHPORTS; RTE_ETH_FOREACH_DEV(portid) { /* Skip ports that are not enabled */ if ((enabled_port_mask & (1 << portid)) == 0) { printf("\nSkipping disabled port %d\n", portid); continue; } nb_rx_queue = ethdev_rx_num_rx_queues_get(portid); /* Setup ethdev node config */ ethdev_conf[nb_conf].port_id = portid; ethdev_conf[nb_conf].num_rx_queues = nb_rx_queue; ethdev_conf[nb_conf].num_tx_queues = n_tx_queue; ethdev_conf[nb_conf].mp = ethdev_mempool_list_by_portid(portid); ethdev_conf[nb_conf].mp_count = 1; /* Check with pools */ nb_conf++; } for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { if (rte_lcore_is_enabled(lcore_id) == 0) continue; qconf = &lcore_conf[lcore_id]; printf("\nInitializing rx queues on lcore %u ... ", lcore_id); fflush(stdout); /* Init RX queues */ for (queue = 0; queue < qconf->n_rx_queue; ++queue) { portid = qconf->rx_queue_list[queue].port_id; queueid = qconf->rx_queue_list[queue].queue_id; /* Add this queue node to its graph */ snprintf(qconf->rx_queue_list[queue].node_name, RTE_NODE_NAMESIZE, "ethdev_rx-%u-%u", portid, queueid); } if (qconf->n_rx_queue) nb_graphs++; } printf("\n"); ethdev_start(); check_all_ports_link_status(enabled_port_mask); *num_conf = nb_conf; *num_graphs = nb_graphs; return ethdev_conf; } static void graph_stats_print_to_file(void) { struct rte_graph_cluster_stats_param s_param; struct rte_graph_cluster_stats *stats; const char *pattern = "worker_*"; FILE *fp = NULL; size_t sz, len; /* Prepare stats object */ fp = fopen("/tmp/graph_stats.txt", "w+"); if (fp == NULL) rte_exit(EXIT_FAILURE, "Error in opening stats file\n"); memset(&s_param, 0, sizeof(s_param)); s_param.f = fp; s_param.socket_id = SOCKET_ID_ANY; s_param.graph_patterns = &pattern; s_param.nb_graph_patterns = 1; stats = rte_graph_cluster_stats_create(&s_param); if (stats == NULL) rte_exit(EXIT_FAILURE, "Unable to create stats object\n"); /* Clear screen and move to top left */ rte_graph_cluster_stats_get(stats, 0); rte_delay_ms(1E3); fseek(fp, 0L, SEEK_END); sz = ftell(fp); fseek(fp, 0L, SEEK_SET); len = strlen(conn->msg_out); conn->msg_out += len; sz = fread(conn->msg_out, sizeof(char), sz, fp); len = strlen(conn->msg_out); conn->msg_out_len_max -= len; rte_graph_cluster_stats_destroy(stats); fclose(fp); } void cmd_graph_stats_show_parsed(__rte_unused void *parsed_result, __rte_unused struct cmdline *cl, __rte_unused void *data) { graph_stats_print_to_file(); } bool graph_status_get(void) { return graph_started; } void cmd_graph_start_parsed(__rte_unused void *parsed_result, __rte_unused struct cmdline *cl, __rte_unused void *data) { struct rte_node_ethdev_config *conf; uint32_t nb_graphs = 0, nb_conf, i; int rc = -EINVAL; if (app_graph_feature_arc_enabled()) rte_graph_feature_arc_init(0); conf = graph_rxtx_node_config_get(&nb_conf, &nb_graphs); for (i = 0; i < MAX_GRAPH_USECASES; i++) { if (!strcmp(graph_config.usecases[i].name, "l3fwd")) { if (graph_config.usecases[i].enabled) { rc = usecase_l3fwd_configure(conf, nb_conf, nb_graphs); 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) graph_started = true; } static int graph_config_add(char *usecases, struct graph_config *config) { uint64_t lcore_id, core_num; uint64_t eal_coremask = 0; if (!parser_usecases_read(usecases)) return -EINVAL; for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { if (rte_lcore_is_enabled(lcore_id)) eal_coremask |= RTE_BIT64(lcore_id); } for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { core_num = 1 << lcore_id; if (config->params.coremask & core_num) { if (eal_coremask & core_num) continue; else return -EINVAL; } } graph_config.params.bsz = config->params.bsz; graph_config.params.tmo = config->params.tmo; graph_config.params.coremask = config->params.coremask; graph_config.model = config->model; graph_config.pcap_ena = config->pcap_ena; graph_config.num_pcap_pkts = config->num_pcap_pkts; graph_config.pcap_file = strdup(config->pcap_file); return 0; } void graph_pcap_config_get(uint8_t *pcap_ena, uint64_t *num_pkts, char **file) { *pcap_ena = graph_config.pcap_ena; *num_pkts = graph_config.num_pcap_pkts; *file = graph_config.pcap_file; } int graph_walk_start(void *conf) { struct lcore_conf *qconf; struct rte_graph *graph; uint32_t lcore_id; RTE_SET_USED(conf); lcore_id = rte_lcore_id(); qconf = &lcore_conf[lcore_id]; graph = qconf->graph; if (!graph) { RTE_LOG(INFO, APP_GRAPH, "Lcore %u has nothing to do\n", lcore_id); return 0; } RTE_LOG(INFO, APP_GRAPH, "Entering main loop on lcore %u, graph %s(%p)\n", lcore_id, qconf->name, graph); while (likely(!force_quit)) rte_graph_walk(graph); return 0; } void graph_stats_print(void) { const char topLeft[] = {27, '[', '1', ';', '1', 'H', '\0'}; const char clr[] = {27, '[', '2', 'J', '\0'}; struct rte_graph_cluster_stats_param s_param; struct rte_graph_cluster_stats *stats; const char *pattern = "worker_*"; /* Prepare stats object */ memset(&s_param, 0, sizeof(s_param)); s_param.f = stdout; s_param.socket_id = SOCKET_ID_ANY; s_param.graph_patterns = &pattern; s_param.nb_graph_patterns = 1; stats = rte_graph_cluster_stats_create(&s_param); if (stats == NULL) rte_exit(EXIT_FAILURE, "Unable to create stats object\n"); while (!force_quit) { /* Clear screen and move to top left */ printf("%s%s", clr, topLeft); rte_graph_cluster_stats_get(stats, 0); rte_delay_ms(1E3); if (app_graph_exit()) force_quit = true; } rte_graph_cluster_stats_destroy(stats); } uint64_t graph_coremask_get(void) { return graph_config.params.coremask; } void cmd_graph_parsed(void *parsed_result, __rte_unused struct cmdline *cl, __rte_unused void *data) { struct cmd_graph_result *res = parsed_result; struct graph_config config; char *model_name; uint8_t model; int rc; model_name = res->model_name; if (strcmp(model_name, "default") == 0) { model = GRAPH_MODEL_RTC; } else if (strcmp(model_name, "rtc") == 0) { model = GRAPH_MODEL_RTC; } else if (strcmp(model_name, "mcd") == 0) { model = GRAPH_MODEL_MCD; } else { printf(MSG_ARG_NOT_FOUND, "model arguments"); return; } config.params.bsz = res->size; config.params.tmo = res->ns; config.params.coremask = res->mask; config.model = model; config.pcap_ena = res->pcap_ena; config.num_pcap_pkts = res->num_pcap_pkts; config.pcap_file = res->pcap_file; rc = graph_config_add(res->usecase, &config); if (rc < 0) { cli_exit(); printf(MSG_CMD_FAIL, res->graph); rte_exit(EXIT_FAILURE, "coremask is Invalid\n"); } } void cmd_help_graph_parsed(__rte_unused void *parsed_result, __rte_unused struct cmdline *cl, __rte_unused void *data) { size_t len; len = strlen(conn->msg_out); conn->msg_out += len; snprintf(conn->msg_out, conn->msg_out_len_max, "\n%s\n%s\n%s\n%s\n", "----------------------------- graph command help -----------------------------", cmd_graph_help, "graph start", "graph stats show"); len = strlen(conn->msg_out); conn->msg_out_len_max -= len; }