1ea9382dcSThomas Monjalon /* SPDX-License-Identifier: BSD-3-Clause 2ea9382dcSThomas Monjalon * Copyright 2017 Mellanox Technologies, Ltd 34a3ef59aSOri Kam */ 44a3ef59aSOri Kam 54a3ef59aSOri Kam #include <stdio.h> 64a3ef59aSOri Kam #include <stdlib.h> 74a3ef59aSOri Kam #include <string.h> 84a3ef59aSOri Kam #include <stdint.h> 94a3ef59aSOri Kam #include <inttypes.h> 104a3ef59aSOri Kam #include <sys/types.h> 114a3ef59aSOri Kam #include <sys/queue.h> 124a3ef59aSOri Kam #include <setjmp.h> 134a3ef59aSOri Kam #include <stdarg.h> 144a3ef59aSOri Kam #include <ctype.h> 154a3ef59aSOri Kam #include <errno.h> 164a3ef59aSOri Kam #include <getopt.h> 174a3ef59aSOri Kam #include <signal.h> 184a3ef59aSOri Kam #include <stdbool.h> 194a3ef59aSOri Kam 204a3ef59aSOri Kam #include <rte_eal.h> 214a3ef59aSOri Kam #include <rte_common.h> 224a3ef59aSOri Kam #include <rte_malloc.h> 234a3ef59aSOri Kam #include <rte_ether.h> 244a3ef59aSOri Kam #include <rte_ethdev.h> 254a3ef59aSOri Kam #include <rte_mempool.h> 264a3ef59aSOri Kam #include <rte_mbuf.h> 274a3ef59aSOri Kam #include <rte_net.h> 284a3ef59aSOri Kam #include <rte_flow.h> 29429cede1SBeilei Xing #include <rte_cycles.h> 30*16158f34SShani Peretz #include <rte_argparse.h> 31*16158f34SShani Peretz 32*16158f34SShani Peretz #include "common.h" 33*16158f34SShani Peretz 34*16158f34SShani Peretz /* Template API enabled by default. */ 35*16158f34SShani Peretz static int use_template_api = 1; 364a3ef59aSOri Kam 374a3ef59aSOri Kam static volatile bool force_quit; 386014215aSZhiyong Yang static uint16_t port_id; 394a3ef59aSOri Kam static uint16_t nr_queues = 5; 404a3ef59aSOri Kam struct rte_mempool *mbuf_pool; 414a3ef59aSOri Kam struct rte_flow *flow; 424a3ef59aSOri Kam 43*16158f34SShani Peretz #define MAX_QUEUE_SIZE 256 444a3ef59aSOri Kam 454a3ef59aSOri Kam static inline void 466d13ea8eSOlivier Matz print_ether_addr(const char *what, struct rte_ether_addr *eth_addr) 474a3ef59aSOri Kam { 4835b2d13fSOlivier Matz char buf[RTE_ETHER_ADDR_FMT_SIZE]; 4935b2d13fSOlivier Matz rte_ether_format_addr(buf, RTE_ETHER_ADDR_FMT_SIZE, eth_addr); 504a3ef59aSOri Kam printf("%s%s", what, buf); 514a3ef59aSOri Kam } 524a3ef59aSOri Kam 53b55efbabSIvan Ilchenko static int 544a3ef59aSOri Kam main_loop(void) 554a3ef59aSOri Kam { 564a3ef59aSOri Kam struct rte_mbuf *mbufs[32]; 576d13ea8eSOlivier Matz struct rte_ether_hdr *eth_hdr; 584a3ef59aSOri Kam struct rte_flow_error error; 594a3ef59aSOri Kam uint16_t nb_rx; 604a3ef59aSOri Kam uint16_t i; 614a3ef59aSOri Kam uint16_t j; 62b55efbabSIvan Ilchenko int ret; 634a3ef59aSOri Kam 64*16158f34SShani Peretz /* Reading the packets from all queues. */ 654a3ef59aSOri Kam while (!force_quit) { 664a3ef59aSOri Kam for (i = 0; i < nr_queues; i++) { 674a3ef59aSOri Kam nb_rx = rte_eth_rx_burst(port_id, 684a3ef59aSOri Kam i, mbufs, 32); 694a3ef59aSOri Kam if (nb_rx) { 704a3ef59aSOri Kam for (j = 0; j < nb_rx; j++) { 714a3ef59aSOri Kam struct rte_mbuf *m = mbufs[j]; 724a3ef59aSOri Kam 734a3ef59aSOri Kam eth_hdr = rte_pktmbuf_mtod(m, 746d13ea8eSOlivier Matz struct rte_ether_hdr *); 754a3ef59aSOri Kam print_ether_addr("src=", 7604d43857SDmitry Kozlyuk ð_hdr->src_addr); 774a3ef59aSOri Kam print_ether_addr(" - dst=", 7804d43857SDmitry Kozlyuk ð_hdr->dst_addr); 794a3ef59aSOri Kam printf(" - queue=0x%x", 804a3ef59aSOri Kam (unsigned int)i); 814a3ef59aSOri Kam printf("\n"); 824a3ef59aSOri Kam 834a3ef59aSOri Kam rte_pktmbuf_free(m); 844a3ef59aSOri Kam } 854a3ef59aSOri Kam } 864a3ef59aSOri Kam } 874a3ef59aSOri Kam } 884a3ef59aSOri Kam 894a3ef59aSOri Kam /* closing and releasing resources */ 904a3ef59aSOri Kam rte_flow_flush(port_id, &error); 91b55efbabSIvan Ilchenko ret = rte_eth_dev_stop(port_id); 92b55efbabSIvan Ilchenko if (ret < 0) 93b55efbabSIvan Ilchenko printf("Failed to stop port %u: %s", 94b55efbabSIvan Ilchenko port_id, rte_strerror(-ret)); 954a3ef59aSOri Kam rte_eth_dev_close(port_id); 96b55efbabSIvan Ilchenko return ret; 974a3ef59aSOri Kam } 984a3ef59aSOri Kam 99429cede1SBeilei Xing #define CHECK_INTERVAL 1000 /* 100ms */ 100429cede1SBeilei Xing #define MAX_REPEAT_TIMES 90 /* 9s (90 * 100ms) in total */ 101429cede1SBeilei Xing 1024a3ef59aSOri Kam static void 1034a3ef59aSOri Kam assert_link_status(void) 1044a3ef59aSOri Kam { 1054a3ef59aSOri Kam struct rte_eth_link link; 106429cede1SBeilei Xing uint8_t rep_cnt = MAX_REPEAT_TIMES; 10722e5c73bSIgor Romanov int link_get_err = -EINVAL; 1084a3ef59aSOri Kam 1094a3ef59aSOri Kam memset(&link, 0, sizeof(link)); 110429cede1SBeilei Xing do { 11122e5c73bSIgor Romanov link_get_err = rte_eth_link_get(port_id, &link); 112295968d1SFerruh Yigit if (link_get_err == 0 && link.link_status == RTE_ETH_LINK_UP) 113429cede1SBeilei Xing break; 114429cede1SBeilei Xing rte_delay_ms(CHECK_INTERVAL); 115429cede1SBeilei Xing } while (--rep_cnt); 116429cede1SBeilei Xing 11722e5c73bSIgor Romanov if (link_get_err < 0) 11822e5c73bSIgor Romanov rte_exit(EXIT_FAILURE, ":: error: link get is failing: %s\n", 11922e5c73bSIgor Romanov rte_strerror(-link_get_err)); 120295968d1SFerruh Yigit if (link.link_status == RTE_ETH_LINK_DOWN) 1214a3ef59aSOri Kam rte_exit(EXIT_FAILURE, ":: error: link is still down\n"); 1224a3ef59aSOri Kam } 1234a3ef59aSOri Kam 124*16158f34SShani Peretz static void 125*16158f34SShani Peretz configure_port_template(uint16_t port_id) 126*16158f34SShani Peretz { 127*16158f34SShani Peretz int ret; 128*16158f34SShani Peretz uint16_t std_queue; 129*16158f34SShani Peretz struct rte_flow_error error; 130*16158f34SShani Peretz struct rte_flow_queue_attr queue_attr[RTE_MAX_LCORE]; 131*16158f34SShani Peretz const struct rte_flow_queue_attr *attr_list[RTE_MAX_LCORE]; 132*16158f34SShani Peretz struct rte_flow_port_attr port_attr = { .nb_counters = 1 /* rules count */ }; 133*16158f34SShani Peretz 134*16158f34SShani Peretz for (std_queue = 0; std_queue < RTE_MAX_LCORE; std_queue++) { 135*16158f34SShani Peretz queue_attr[std_queue].size = MAX_QUEUE_SIZE; 136*16158f34SShani Peretz attr_list[std_queue] = &queue_attr[std_queue]; 137*16158f34SShani Peretz } 138*16158f34SShani Peretz 139*16158f34SShani Peretz ret = rte_flow_configure(port_id, &port_attr, 140*16158f34SShani Peretz 1, attr_list, &error); 141*16158f34SShani Peretz if (ret != 0) 142*16158f34SShani Peretz rte_exit(EXIT_FAILURE, 143*16158f34SShani Peretz "rte_flow_configure:err=%d, port=%u\n", 144*16158f34SShani Peretz ret, port_id); 145*16158f34SShani Peretz printf(":: Configuring template port [%d] Done ..\n", port_id); 146*16158f34SShani Peretz } 147*16158f34SShani Peretz 1484a3ef59aSOri Kam static void 1494a3ef59aSOri Kam init_port(void) 1504a3ef59aSOri Kam { 1514a3ef59aSOri Kam int ret; 1524a3ef59aSOri Kam uint16_t i; 153*16158f34SShani Peretz /* Ethernet port configured with default settings. */ 1544a3ef59aSOri Kam struct rte_eth_conf port_conf = { 155feca6c42SWei Zhao .txmode = { 156feca6c42SWei Zhao .offloads = 157295968d1SFerruh Yigit RTE_ETH_TX_OFFLOAD_VLAN_INSERT | 158295968d1SFerruh Yigit RTE_ETH_TX_OFFLOAD_IPV4_CKSUM | 159295968d1SFerruh Yigit RTE_ETH_TX_OFFLOAD_UDP_CKSUM | 160295968d1SFerruh Yigit RTE_ETH_TX_OFFLOAD_TCP_CKSUM | 161295968d1SFerruh Yigit RTE_ETH_TX_OFFLOAD_SCTP_CKSUM | 162295968d1SFerruh Yigit RTE_ETH_TX_OFFLOAD_TCP_TSO, 163feca6c42SWei Zhao }, 1644a3ef59aSOri Kam }; 165feca6c42SWei Zhao struct rte_eth_txconf txq_conf; 166e6bb3077SShahaf Shuler struct rte_eth_rxconf rxq_conf; 167feca6c42SWei Zhao struct rte_eth_dev_info dev_info; 1684a3ef59aSOri Kam 169d9a66c56SIvan Ilchenko ret = rte_eth_dev_info_get(port_id, &dev_info); 170d9a66c56SIvan Ilchenko if (ret != 0) 171d9a66c56SIvan Ilchenko rte_exit(EXIT_FAILURE, 172d9a66c56SIvan Ilchenko "Error during getting device (port %u) info: %s\n", 173d9a66c56SIvan Ilchenko port_id, strerror(-ret)); 174d9a66c56SIvan Ilchenko 175a5e7c52dSOri Kam port_conf.txmode.offloads &= dev_info.tx_offload_capa; 1764a3ef59aSOri Kam printf(":: initializing port: %d\n", port_id); 1774a3ef59aSOri Kam ret = rte_eth_dev_configure(port_id, 1784a3ef59aSOri Kam nr_queues, nr_queues, &port_conf); 1794a3ef59aSOri Kam if (ret < 0) { 1804a3ef59aSOri Kam rte_exit(EXIT_FAILURE, 1814a3ef59aSOri Kam ":: cannot configure device: err=%d, port=%u\n", 1824a3ef59aSOri Kam ret, port_id); 1834a3ef59aSOri Kam } 1844a3ef59aSOri Kam 185e6bb3077SShahaf Shuler rxq_conf = dev_info.default_rxconf; 186e6bb3077SShahaf Shuler rxq_conf.offloads = port_conf.rxmode.offloads; 1879a212dc0SConor Fogarty 188*16158f34SShani Peretz /* Configuring number of RX and TX queues connected to single port. */ 1894a3ef59aSOri Kam for (i = 0; i < nr_queues; i++) { 1904a3ef59aSOri Kam ret = rte_eth_rx_queue_setup(port_id, i, 512, 1914a3ef59aSOri Kam rte_eth_dev_socket_id(port_id), 192e6bb3077SShahaf Shuler &rxq_conf, 1934a3ef59aSOri Kam mbuf_pool); 1944a3ef59aSOri Kam if (ret < 0) { 1954a3ef59aSOri Kam rte_exit(EXIT_FAILURE, 1964a3ef59aSOri Kam ":: Rx queue setup failed: err=%d, port=%u\n", 1974a3ef59aSOri Kam ret, port_id); 1984a3ef59aSOri Kam } 1994a3ef59aSOri Kam } 2004a3ef59aSOri Kam 201feca6c42SWei Zhao txq_conf = dev_info.default_txconf; 202feca6c42SWei Zhao txq_conf.offloads = port_conf.txmode.offloads; 203feca6c42SWei Zhao 204feca6c42SWei Zhao for (i = 0; i < nr_queues; i++) { 205feca6c42SWei Zhao ret = rte_eth_tx_queue_setup(port_id, i, 512, 206feca6c42SWei Zhao rte_eth_dev_socket_id(port_id), 207feca6c42SWei Zhao &txq_conf); 208feca6c42SWei Zhao if (ret < 0) { 209feca6c42SWei Zhao rte_exit(EXIT_FAILURE, 210feca6c42SWei Zhao ":: Tx queue setup failed: err=%d, port=%u\n", 211feca6c42SWei Zhao ret, port_id); 212feca6c42SWei Zhao } 213feca6c42SWei Zhao } 214feca6c42SWei Zhao 215*16158f34SShani Peretz /* Setting the RX port to promiscuous mode. */ 216f430bbceSIvan Ilchenko ret = rte_eth_promiscuous_enable(port_id); 217f430bbceSIvan Ilchenko if (ret != 0) 218f430bbceSIvan Ilchenko rte_exit(EXIT_FAILURE, 219f430bbceSIvan Ilchenko ":: promiscuous mode enable failed: err=%s, port=%u\n", 220f430bbceSIvan Ilchenko rte_strerror(-ret), port_id); 221f430bbceSIvan Ilchenko 2224a3ef59aSOri Kam ret = rte_eth_dev_start(port_id); 2234a3ef59aSOri Kam if (ret < 0) { 2244a3ef59aSOri Kam rte_exit(EXIT_FAILURE, 2254a3ef59aSOri Kam "rte_eth_dev_start:err=%d, port=%u\n", 2264a3ef59aSOri Kam ret, port_id); 2274a3ef59aSOri Kam } 2284a3ef59aSOri Kam 2294a3ef59aSOri Kam assert_link_status(); 2304a3ef59aSOri Kam 2314a3ef59aSOri Kam printf(":: initializing port: %d done\n", port_id); 232*16158f34SShani Peretz 233*16158f34SShani Peretz if (use_template_api == 0) 234*16158f34SShani Peretz return; 235*16158f34SShani Peretz 236*16158f34SShani Peretz /* Adds rules engine configuration. 8< */ 237*16158f34SShani Peretz ret = rte_eth_dev_stop(port_id); 238*16158f34SShani Peretz if (ret < 0) 239*16158f34SShani Peretz rte_exit(EXIT_FAILURE, 240*16158f34SShani Peretz "rte_eth_dev_stop:err=%d, port=%u\n", 241*16158f34SShani Peretz ret, port_id); 242*16158f34SShani Peretz 243*16158f34SShani Peretz configure_port_template(port_id); 244*16158f34SShani Peretz ret = rte_eth_dev_start(port_id); 245*16158f34SShani Peretz if (ret < 0) 246*16158f34SShani Peretz rte_exit(EXIT_FAILURE, 247*16158f34SShani Peretz "rte_eth_dev_start:err=%d, port=%u\n", 248*16158f34SShani Peretz ret, port_id); 249*16158f34SShani Peretz /* >8 End of adding rules engine configuration. */ 2504a3ef59aSOri Kam } 2514a3ef59aSOri Kam 2524a3ef59aSOri Kam static void 2534a3ef59aSOri Kam signal_handler(int signum) 2544a3ef59aSOri Kam { 2554a3ef59aSOri Kam if (signum == SIGINT || signum == SIGTERM) { 2564a3ef59aSOri Kam printf("\n\nSignal %d received, preparing to exit...\n", 2574a3ef59aSOri Kam signum); 2584a3ef59aSOri Kam force_quit = true; 2594a3ef59aSOri Kam } 2604a3ef59aSOri Kam } 2614a3ef59aSOri Kam 262*16158f34SShani Peretz /* Parse the argument given in the command line of the application */ 263*16158f34SShani Peretz static int 264*16158f34SShani Peretz flow_filtering_parse_args(int argc, char **argv) 265*16158f34SShani Peretz { 266*16158f34SShani Peretz static struct rte_argparse obj = { 267*16158f34SShani Peretz .prog_name = "flow_filtering", 268*16158f34SShani Peretz .usage = "[EAL options] -- [optional parameters]", 269*16158f34SShani Peretz .descriptor = NULL, 270*16158f34SShani Peretz .epilog = NULL, 271*16158f34SShani Peretz .exit_on_error = false, 272*16158f34SShani Peretz .callback = NULL, 273*16158f34SShani Peretz .opaque = NULL, 274*16158f34SShani Peretz .args = { 275*16158f34SShani Peretz { "--template", NULL, "Enable template API flow", 276*16158f34SShani Peretz &use_template_api, (void *)1, 277*16158f34SShani Peretz RTE_ARGPARSE_ARG_NO_VALUE | RTE_ARGPARSE_ARG_VALUE_INT, 278*16158f34SShani Peretz }, 279*16158f34SShani Peretz { "--non-template", NULL, "Enable non template API flow", 280*16158f34SShani Peretz &use_template_api, (void *)0, 281*16158f34SShani Peretz RTE_ARGPARSE_ARG_NO_VALUE | RTE_ARGPARSE_ARG_VALUE_INT, 282*16158f34SShani Peretz }, 283*16158f34SShani Peretz ARGPARSE_ARG_END(), 284*16158f34SShani Peretz }, 285*16158f34SShani Peretz }; 286*16158f34SShani Peretz 287*16158f34SShani Peretz return rte_argparse_parse(&obj, argc, argv); 288*16158f34SShani Peretz } 289*16158f34SShani Peretz 2904a3ef59aSOri Kam int 2914a3ef59aSOri Kam main(int argc, char **argv) 2924a3ef59aSOri Kam { 2934a3ef59aSOri Kam int ret; 294d9a42a69SThomas Monjalon uint16_t nr_ports; 2954a3ef59aSOri Kam struct rte_flow_error error; 2964a3ef59aSOri Kam 2979a212dc0SConor Fogarty /* Initialize EAL. 8< */ 2984a3ef59aSOri Kam ret = rte_eal_init(argc, argv); 2994a3ef59aSOri Kam if (ret < 0) 3004a3ef59aSOri Kam rte_exit(EXIT_FAILURE, ":: invalid EAL arguments\n"); 3019a212dc0SConor Fogarty /* >8 End of Initialization of EAL. */ 302*16158f34SShani Peretz argc -= ret; 303*16158f34SShani Peretz argv += ret; 3044a3ef59aSOri Kam 3054a3ef59aSOri Kam force_quit = false; 3064a3ef59aSOri Kam signal(SIGINT, signal_handler); 3074a3ef59aSOri Kam signal(SIGTERM, signal_handler); 3084a3ef59aSOri Kam 309*16158f34SShani Peretz /* Parse application arguments (after the EAL ones) */ 310*16158f34SShani Peretz ret = flow_filtering_parse_args(argc, argv); 311*16158f34SShani Peretz if (ret < 0) 312*16158f34SShani Peretz rte_exit(EXIT_FAILURE, "Invalid flow filtering arguments\n"); 313*16158f34SShani Peretz 314d9a42a69SThomas Monjalon nr_ports = rte_eth_dev_count_avail(); 3154a3ef59aSOri Kam if (nr_ports == 0) 3164a3ef59aSOri Kam rte_exit(EXIT_FAILURE, ":: no Ethernet ports found\n"); 3174a3ef59aSOri Kam port_id = 0; 3184a3ef59aSOri Kam if (nr_ports != 1) { 3194a3ef59aSOri Kam printf(":: warn: %d ports detected, but we use only one: port %u\n", 3204a3ef59aSOri Kam nr_ports, port_id); 3214a3ef59aSOri Kam } 322*16158f34SShani Peretz 3239a212dc0SConor Fogarty /* Allocates a mempool to hold the mbufs. 8< */ 3244a3ef59aSOri Kam mbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", 4096, 128, 0, 3254a3ef59aSOri Kam RTE_MBUF_DEFAULT_BUF_SIZE, 3264a3ef59aSOri Kam rte_socket_id()); 3279a212dc0SConor Fogarty /* >8 End of allocating a mempool to hold the mbufs. */ 3284a3ef59aSOri Kam if (mbuf_pool == NULL) 3294a3ef59aSOri Kam rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n"); 3304a3ef59aSOri Kam 3319a212dc0SConor Fogarty /* Initializes all the ports using the user defined init_port(). 8< */ 3324a3ef59aSOri Kam init_port(); 3339a212dc0SConor Fogarty /* >8 End of Initializing the ports using user defined init_port(). */ 3344a3ef59aSOri Kam 335*16158f34SShani Peretz /* Function responsible for creating the flow rule. 8< */ 336*16158f34SShani Peretz flow = generate_flow_skeleton(port_id, &error, use_template_api); 337*16158f34SShani Peretz /* >8 End of function responsible for creating the flow rule. */ 338*16158f34SShani Peretz 3394a3ef59aSOri Kam if (!flow) { 3404a3ef59aSOri Kam printf("Flow can't be created %d message: %s\n", 3414a3ef59aSOri Kam error.type, 3424a3ef59aSOri Kam error.message ? error.message : "(no stated reason)"); 3434a3ef59aSOri Kam rte_exit(EXIT_FAILURE, "error in creating flow"); 3444a3ef59aSOri Kam } 345*16158f34SShani Peretz printf("Flow created!!:\n"); 3464a3ef59aSOri Kam 3479a212dc0SConor Fogarty /* Launching main_loop(). 8< */ 34810aa3757SChengchang Tang ret = main_loop(); 3499a212dc0SConor Fogarty /* >8 End of launching main_loop(). */ 35010aa3757SChengchang Tang 35110aa3757SChengchang Tang /* clean up the EAL */ 35210aa3757SChengchang Tang rte_eal_cleanup(); 35310aa3757SChengchang Tang 35410aa3757SChengchang Tang return ret; 3554a3ef59aSOri Kam } 356