X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=examples%2Fl3fwd-graph%2Fmain.c;h=7f00c65609ed52ba1b46353da39fe20aed1c16ae;hb=23f7ec1d9b7ccfcfb9b9f67d33cf6cbf7f5034d3;hp=7ea7885894403a4262d98e9967c8bc7361012604;hpb=ef853f1fd97937e6a873bcb47aa71c9ece46f140;p=dpdk.git diff --git a/examples/l3fwd-graph/main.c b/examples/l3fwd-graph/main.c index 7ea7885894..7f00c65609 100644 --- a/examples/l3fwd-graph/main.c +++ b/examples/l3fwd-graph/main.c @@ -23,9 +23,13 @@ #include #include #include +#include +#include #include #include #include +#include +#include #include #include #include @@ -75,12 +79,17 @@ static uint32_t enabled_port_mask; struct lcore_rx_queue { uint16_t port_id; uint8_t queue_id; + char node_name[RTE_NODE_NAMESIZE]; }; /* Lcore conf */ struct lcore_conf { uint16_t n_rx_queue; struct lcore_rx_queue rx_queue_list[MAX_RX_QUEUE_PER_LCORE]; + + struct rte_graph *graph; + char name[RTE_GRAPH_NAMESIZE]; + rte_graph_t graph_id; } __rte_cache_aligned; static struct lcore_conf lcore_conf[RTE_MAX_LCORE]; @@ -102,23 +111,43 @@ static uint16_t nb_lcore_params = RTE_DIM(lcore_params_array_default); static struct rte_eth_conf port_conf = { .rxmode = { - .mq_mode = ETH_MQ_RX_RSS, - .max_rx_pkt_len = RTE_ETHER_MAX_LEN, + .mq_mode = RTE_ETH_MQ_RX_RSS, .split_hdr_size = 0, }, .rx_adv_conf = { .rss_conf = { .rss_key = NULL, - .rss_hf = ETH_RSS_IP, + .rss_hf = RTE_ETH_RSS_IP, }, }, .txmode = { - .mq_mode = ETH_MQ_TX_NONE, + .mq_mode = RTE_ETH_MQ_TX_NONE, }, }; +static uint32_t max_pkt_len; + static struct rte_mempool *pktmbuf_pool[RTE_MAX_ETHPORTS][NB_SOCKETS]; +static struct rte_node_ethdev_config ethdev_conf[RTE_MAX_ETHPORTS]; + +struct ipv4_l3fwd_lpm_route { + uint32_t ip; + uint8_t depth; + uint8_t if_out; +}; + +#define IPV4_L3FWD_LPM_NUM_ROUTES \ + (sizeof(ipv4_l3fwd_lpm_route_array) / \ + sizeof(ipv4_l3fwd_lpm_route_array[0])) +/* 198.18.0.0/16 are set aside for RFC2544 benchmarking. */ +static struct ipv4_l3fwd_lpm_route ipv4_l3fwd_lpm_route_array[] = { + {RTE_IPV4(198, 18, 0, 0), 24, 0}, {RTE_IPV4(198, 18, 1, 0), 24, 1}, + {RTE_IPV4(198, 18, 2, 0), 24, 2}, {RTE_IPV4(198, 18, 3, 0), 24, 3}, + {RTE_IPV4(198, 18, 4, 0), 24, 4}, {RTE_IPV4(198, 18, 5, 0), 24, 5}, + {RTE_IPV4(198, 18, 6, 0), 24, 6}, {RTE_IPV4(198, 18, 7, 0), 24, 7}, +}; + static int check_lcore_params(void) { @@ -139,8 +168,8 @@ check_lcore_params(void) return -1; } - if (lcore == rte_get_master_lcore()) { - printf("Error: lcore %u is master lcore\n", lcore); + if (lcore == rte_get_main_lcore()) { + printf("Error: lcore %u is main lcore\n", lcore); return -1; } socketid = rte_lcore_to_socket_id(lcore); @@ -231,7 +260,7 @@ print_usage(const char *prgname) " [-P]" " --config (port,queue,lcore)[,(port,queue,lcore)]" " [--eth-dest=X,MM:MM:MM:MM:MM:MM]" - " [--enable-jumbo [--max-pkt-len PKTLEN]]" + " [--max-pkt-len PKTLEN]" " [--no-numa]" " [--per-port-pool]\n\n" @@ -240,9 +269,7 @@ print_usage(const char *prgname) " --config (port,queue,lcore): Rx queue configuration\n" " --eth-dest=X,MM:MM:MM:MM:MM:MM: Ethernet destination for " "port X\n" - " --enable-jumbo: Enable jumbo frames\n" - " --max-pkt-len: Under the premise of enabling jumbo,\n" - " maximum packet length in decimal (64-9600)\n" + " --max-pkt-len PKTLEN: maximum packet length in decimal (64-9600)\n" " --no-numa: Disable numa awareness\n" " --per-port-pool: Use separate buffer pool per port\n\n", prgname); @@ -274,10 +301,7 @@ parse_portmask(const char *portmask) /* Parse hexadecimal string */ pm = strtoul(portmask, &end, 16); if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0')) - return -1; - - if (pm == 0) - return -1; + return 0; return pm; } @@ -379,7 +403,7 @@ static const char short_options[] = "p:" /* portmask */ #define CMD_LINE_OPT_CONFIG "config" #define CMD_LINE_OPT_ETH_DEST "eth-dest" #define CMD_LINE_OPT_NO_NUMA "no-numa" -#define CMD_LINE_OPT_ENABLE_JUMBO "enable-jumbo" +#define CMD_LINE_OPT_MAX_PKT_LEN "max-pkt-len" #define CMD_LINE_OPT_PER_PORT_POOL "per-port-pool" enum { /* Long options mapped to a short option */ @@ -391,7 +415,7 @@ enum { CMD_LINE_OPT_CONFIG_NUM, CMD_LINE_OPT_ETH_DEST_NUM, CMD_LINE_OPT_NO_NUMA_NUM, - CMD_LINE_OPT_ENABLE_JUMBO_NUM, + CMD_LINE_OPT_MAX_PKT_LEN_NUM, CMD_LINE_OPT_PARSE_PER_PORT_POOL, }; @@ -399,7 +423,7 @@ static const struct option lgopts[] = { {CMD_LINE_OPT_CONFIG, 1, 0, CMD_LINE_OPT_CONFIG_NUM}, {CMD_LINE_OPT_ETH_DEST, 1, 0, CMD_LINE_OPT_ETH_DEST_NUM}, {CMD_LINE_OPT_NO_NUMA, 0, 0, CMD_LINE_OPT_NO_NUMA_NUM}, - {CMD_LINE_OPT_ENABLE_JUMBO, 0, 0, CMD_LINE_OPT_ENABLE_JUMBO_NUM}, + {CMD_LINE_OPT_MAX_PKT_LEN, 1, 0, CMD_LINE_OPT_MAX_PKT_LEN_NUM}, {CMD_LINE_OPT_PER_PORT_POOL, 0, 0, CMD_LINE_OPT_PARSE_PER_PORT_POOL}, {NULL, 0, 0, 0}, }; @@ -465,28 +489,8 @@ parse_args(int argc, char **argv) numa_on = 0; break; - case CMD_LINE_OPT_ENABLE_JUMBO_NUM: { - const struct option lenopts = {"max-pkt-len", - required_argument, 0, 0}; - - port_conf.rxmode.offloads |= DEV_RX_OFFLOAD_JUMBO_FRAME; - port_conf.txmode.offloads |= DEV_TX_OFFLOAD_MULTI_SEGS; - - /* - * if no max-pkt-len set, use the default - * value RTE_ETHER_MAX_LEN. - */ - if (getopt_long(argc, argvopt, "", &lenopts, - &option_index) == 0) { - ret = parse_max_pkt_len(optarg); - if (ret < 64 || ret > MAX_JUMBO_PKT_LEN) { - fprintf(stderr, "Invalid maximum " - "packet length\n"); - print_usage(prgname); - return -1; - } - port_conf.rxmode.max_rx_pkt_len = ret; - } + case CMD_LINE_OPT_MAX_PKT_LEN_NUM: { + max_pkt_len = parse_max_pkt_len(optarg); break; } @@ -570,6 +574,8 @@ check_all_ports_link_status(uint32_t port_mask) uint8_t count, all_ports_up, print_flag = 0; struct rte_eth_link link; uint16_t portid; + int ret; + char link_status_text[RTE_ETH_LINK_MAX_STR_LEN]; printf("\nChecking link status"); fflush(stdout); @@ -584,23 +590,24 @@ check_all_ports_link_status(uint32_t port_mask) if ((port_mask & (1 << portid)) == 0) continue; memset(&link, 0, sizeof(link)); - rte_eth_link_get_nowait(portid, &link); + ret = rte_eth_link_get_nowait(portid, &link); + if (ret < 0) { + all_ports_up = 0; + if (print_flag == 1) + printf("Port %u link get failed: %s\n", + portid, rte_strerror(-ret)); + continue; + } /* Print link status if flag set */ if (print_flag == 1) { - if (link.link_status) - printf("Port%d Link Up. Speed %u Mbps " - "-%s\n", - portid, link.link_speed, - (link.link_duplex == - ETH_LINK_FULL_DUPLEX) - ? ("full-duplex") - : ("half-duplex\n")); - else - printf("Port %d Link Down\n", portid); + rte_eth_link_to_str(link_status_text, + sizeof(link_status_text), &link); + printf("Port %d %s\n", portid, + link_status_text); continue; } /* Clear all_ports_up flag if any link down */ - if (link.link_status == ETH_LINK_DOWN) { + if (link.link_status == RTE_ETH_LINK_DOWN) { all_ports_up = 0; break; } @@ -633,17 +640,126 @@ signal_handler(int signum) } } +static void +print_stats(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); + } + + rte_graph_cluster_stats_destroy(stats); +} + +/* Main processing loop. 8< */ +static int +graph_main_loop(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, L3FWD_GRAPH, "Lcore %u has nothing to do\n", + lcore_id); + return 0; + } + + RTE_LOG(INFO, L3FWD_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; +} +/* >8 End of main processing loop. */ + +static uint32_t +eth_dev_get_overhead_len(uint32_t max_rx_pktlen, uint16_t max_mtu) +{ + uint32_t overhead_len; + + if (max_mtu != UINT16_MAX && max_rx_pktlen > max_mtu) + overhead_len = max_rx_pktlen - max_mtu; + else + overhead_len = RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN; + + return overhead_len; +} + +static int +config_port_max_pkt_len(struct rte_eth_conf *conf, + struct rte_eth_dev_info *dev_info) +{ + uint32_t overhead_len; + + if (max_pkt_len == 0) + return 0; + + if (max_pkt_len < RTE_ETHER_MIN_LEN || max_pkt_len > MAX_JUMBO_PKT_LEN) + return -1; + + overhead_len = eth_dev_get_overhead_len(dev_info->max_rx_pktlen, + dev_info->max_mtu); + conf->rxmode.mtu = max_pkt_len - overhead_len; + + if (conf->rxmode.mtu > RTE_ETHER_MTU) + conf->txmode.offloads |= RTE_ETH_TX_OFFLOAD_MULTI_SEGS; + + return 0; +} + int main(int argc, char **argv) { + /* Rewrite data of src and dst ether addr */ + uint8_t rewrite_data[2 * sizeof(struct rte_ether_addr)]; + /* Graph initialization. 8< */ + static const char * const default_patterns[] = { + "ip4*", + "ethdev_tx-*", + "pkt_drop", + }; uint8_t nb_rx_queue, queue, socketid; + struct rte_graph_param graph_conf; struct rte_eth_dev_info dev_info; + uint32_t nb_ports, nb_conf = 0; uint32_t n_tx_queue, nb_lcores; struct rte_eth_txconf *txconf; - uint16_t queueid, portid; + uint16_t queueid, portid, i; + const char **node_patterns; struct lcore_conf *qconf; + uint16_t nb_graphs = 0; + uint16_t nb_patterns; + uint8_t rewrite_len; uint32_t lcore_id; - uint32_t nb_ports; int ret; /* Init EAL */ @@ -682,7 +798,7 @@ main(int argc, char **argv) nb_ports = rte_eth_dev_count_avail(); nb_lcores = rte_lcore_count(); - /* Initialize all ports */ + /* Initialize all ports. 8< */ RTE_ETH_FOREACH_DEV(portid) { struct rte_eth_conf local_port_conf = port_conf; @@ -705,9 +821,16 @@ main(int argc, char **argv) nb_rx_queue, n_tx_queue); rte_eth_dev_info_get(portid, &dev_info); - if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE) + + ret = config_port_max_pkt_len(&local_port_conf, &dev_info); + if (ret != 0) + rte_exit(EXIT_FAILURE, + "Invalid max packet length: %u (port %u)\n", + max_pkt_len, portid); + + if (dev_info.tx_offload_capa & RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE) local_port_conf.txmode.offloads |= - DEV_TX_OFFLOAD_MBUF_FAST_FREE; + RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE; local_port_conf.rx_adv_conf.rss_conf.rss_hf &= dev_info.flow_type_rss_offloads; @@ -792,6 +915,18 @@ main(int argc, char **argv) queueid++; } + /* 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; + if (!per_port_pool) + ethdev_conf[nb_conf].mp = pktmbuf_pool[0]; + + else + ethdev_conf[nb_conf].mp = pktmbuf_pool[portid]; + ethdev_conf[nb_conf].mp_count = NB_SOCKETS; + + nb_conf++; printf("\n"); } @@ -835,11 +970,25 @@ main(int argc, char **argv) "port=%d\n", ret, portid); + /* Add this queue node to its graph */ + snprintf(qconf->rx_queue_list[queue].node_name, + RTE_NODE_NAMESIZE, "ethdev_rx-%u-%u", portid, + queueid); } + + /* Alloc a graph to this lcore only if source exists */ + if (qconf->n_rx_queue) + nb_graphs++; } printf("\n"); + /* Ethdev node config, skip rx queue mapping */ + ret = rte_node_eth_config(ethdev_conf, nb_conf, nb_graphs); + /* >8 End of graph creation. */ + if (ret) + rte_exit(EXIT_FAILURE, "rte_node_eth_config: err=%d\n", ret); + /* Start ports */ RTE_ETH_FOREACH_DEV(portid) { @@ -867,15 +1016,142 @@ main(int argc, char **argv) check_all_ports_link_status(enabled_port_mask); + /* Graph Initialization */ + nb_patterns = RTE_DIM(default_patterns); + node_patterns = malloc((MAX_RX_QUEUE_PER_LCORE + nb_patterns) * + sizeof(*node_patterns)); + if (!node_patterns) + return -ENOMEM; + memcpy(node_patterns, default_patterns, + nb_patterns * sizeof(*node_patterns)); + + memset(&graph_conf, 0, sizeof(graph_conf)); + graph_conf.node_patterns = node_patterns; + + 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); + } + + memset(&rewrite_data, 0, sizeof(rewrite_data)); + rewrite_len = sizeof(rewrite_data); + + /* Add route to ip4 graph infra. 8< */ + for (i = 0; i < IPV4_L3FWD_LPM_NUM_ROUTES; i++) { + char route_str[INET6_ADDRSTRLEN * 4]; + char abuf[INET6_ADDRSTRLEN]; + struct in_addr in; + uint32_t dst_port; + + /* Skip unused ports */ + if ((1 << ipv4_l3fwd_lpm_route_array[i].if_out & + enabled_port_mask) == 0) + continue; + + dst_port = ipv4_l3fwd_lpm_route_array[i].if_out; + + in.s_addr = htonl(ipv4_l3fwd_lpm_route_array[i].ip); + snprintf(route_str, sizeof(route_str), "%s / %d (%d)", + inet_ntop(AF_INET, &in, abuf, sizeof(abuf)), + ipv4_l3fwd_lpm_route_array[i].depth, + ipv4_l3fwd_lpm_route_array[i].if_out); + + /* Use route index 'i' as next hop id */ + ret = rte_node_ip4_route_add( + ipv4_l3fwd_lpm_route_array[i].ip, + ipv4_l3fwd_lpm_route_array[i].depth, i, + RTE_NODE_IP4_LOOKUP_NEXT_REWRITE); + + if (ret < 0) + rte_exit(EXIT_FAILURE, + "Unable to add ip4 route %s to graph\n", + route_str); + + memcpy(rewrite_data, val_eth + dst_port, rewrite_len); + + /* Add next hop rewrite data for id 'i' */ + ret = rte_node_ip4_rewrite_add(i, rewrite_data, + rewrite_len, dst_port); + if (ret < 0) + rte_exit(EXIT_FAILURE, + "Unable to add next hop %u for " + "route %s\n", i, route_str); + + RTE_LOG(INFO, L3FWD_GRAPH, "Added route %s, next_hop %u\n", + route_str, i); + } + /* >8 End of adding route to ip4 graph infa. */ + + /* Launch per-lcore init on every worker lcore */ + rte_eal_mp_remote_launch(graph_main_loop, NULL, SKIP_MAIN); + + /* Accumulate and print stats on main until exit */ + if (rte_graph_has_stats_feature()) + print_stats(); + + /* Wait for worker cores to exit */ + ret = 0; + RTE_LCORE_FOREACH_WORKER(lcore_id) { + ret = rte_eal_wait_lcore(lcore_id); + /* Destroy graph */ + if (ret < 0 || rte_graph_destroy( + rte_graph_from_name(lcore_conf[lcore_id].name))) { + ret = -1; + break; + } + } + free(node_patterns); + /* Stop ports */ RTE_ETH_FOREACH_DEV(portid) { if ((enabled_port_mask & (1 << portid)) == 0) continue; printf("Closing port %d...", portid); - rte_eth_dev_stop(portid); + ret = rte_eth_dev_stop(portid); + if (ret != 0) + printf("Failed to stop port %u: %s\n", + portid, rte_strerror(-ret)); rte_eth_dev_close(portid); printf(" Done\n"); } + + /* clean up the EAL */ + rte_eal_cleanup(); printf("Bye...\n"); return ret;