1*d30ea906Sjfb8856606 /* SPDX-License-Identifier: BSD-3-Clause 2*d30ea906Sjfb8856606 * Copyright(c) 2017 Intel Corporation 32bfe3f2eSlogwang */ 42bfe3f2eSlogwang 52bfe3f2eSlogwang #include <stdint.h> 62bfe3f2eSlogwang #include <inttypes.h> 72bfe3f2eSlogwang #include <getopt.h> 82bfe3f2eSlogwang 92bfe3f2eSlogwang #include <rte_eal.h> 102bfe3f2eSlogwang #include <rte_ethdev.h> 112bfe3f2eSlogwang #include <rte_cycles.h> 122bfe3f2eSlogwang #include <rte_lcore.h> 132bfe3f2eSlogwang #include <rte_mbuf.h> 142bfe3f2eSlogwang #include <rte_flow.h> 152bfe3f2eSlogwang #include <rte_flow_classify.h> 162bfe3f2eSlogwang #include <rte_table_acl.h> 172bfe3f2eSlogwang 18*d30ea906Sjfb8856606 #define RX_RING_SIZE 1024 19*d30ea906Sjfb8856606 #define TX_RING_SIZE 1024 202bfe3f2eSlogwang 212bfe3f2eSlogwang #define NUM_MBUFS 8191 222bfe3f2eSlogwang #define MBUF_CACHE_SIZE 250 232bfe3f2eSlogwang #define BURST_SIZE 32 242bfe3f2eSlogwang 252bfe3f2eSlogwang #define MAX_NUM_CLASSIFY 30 262bfe3f2eSlogwang #define FLOW_CLASSIFY_MAX_RULE_NUM 91 272bfe3f2eSlogwang #define FLOW_CLASSIFY_MAX_PRIORITY 8 282bfe3f2eSlogwang #define FLOW_CLASSIFIER_NAME_SIZE 64 292bfe3f2eSlogwang 302bfe3f2eSlogwang #define COMMENT_LEAD_CHAR ('#') 312bfe3f2eSlogwang #define OPTION_RULE_IPV4 "rule_ipv4" 322bfe3f2eSlogwang #define RTE_LOGTYPE_FLOW_CLASSIFY RTE_LOGTYPE_USER3 332bfe3f2eSlogwang #define flow_classify_log(format, ...) \ 342bfe3f2eSlogwang RTE_LOG(ERR, FLOW_CLASSIFY, format, ##__VA_ARGS__) 352bfe3f2eSlogwang 362bfe3f2eSlogwang #define uint32_t_to_char(ip, a, b, c, d) do {\ 372bfe3f2eSlogwang *a = (unsigned char)(ip >> 24 & 0xff);\ 382bfe3f2eSlogwang *b = (unsigned char)(ip >> 16 & 0xff);\ 392bfe3f2eSlogwang *c = (unsigned char)(ip >> 8 & 0xff);\ 402bfe3f2eSlogwang *d = (unsigned char)(ip & 0xff);\ 412bfe3f2eSlogwang } while (0) 422bfe3f2eSlogwang 432bfe3f2eSlogwang enum { 442bfe3f2eSlogwang CB_FLD_SRC_ADDR, 452bfe3f2eSlogwang CB_FLD_DST_ADDR, 462bfe3f2eSlogwang CB_FLD_SRC_PORT, 472bfe3f2eSlogwang CB_FLD_SRC_PORT_DLM, 482bfe3f2eSlogwang CB_FLD_SRC_PORT_MASK, 492bfe3f2eSlogwang CB_FLD_DST_PORT, 502bfe3f2eSlogwang CB_FLD_DST_PORT_DLM, 512bfe3f2eSlogwang CB_FLD_DST_PORT_MASK, 522bfe3f2eSlogwang CB_FLD_PROTO, 532bfe3f2eSlogwang CB_FLD_PRIORITY, 542bfe3f2eSlogwang CB_FLD_NUM, 552bfe3f2eSlogwang }; 562bfe3f2eSlogwang 572bfe3f2eSlogwang static struct{ 582bfe3f2eSlogwang const char *rule_ipv4_name; 592bfe3f2eSlogwang } parm_config; 602bfe3f2eSlogwang const char cb_port_delim[] = ":"; 612bfe3f2eSlogwang 622bfe3f2eSlogwang static const struct rte_eth_conf port_conf_default = { 63*d30ea906Sjfb8856606 .rxmode = { 64*d30ea906Sjfb8856606 .max_rx_pkt_len = ETHER_MAX_LEN, 65*d30ea906Sjfb8856606 }, 662bfe3f2eSlogwang }; 672bfe3f2eSlogwang 682bfe3f2eSlogwang struct flow_classifier { 692bfe3f2eSlogwang struct rte_flow_classifier *cls; 702bfe3f2eSlogwang }; 712bfe3f2eSlogwang 722bfe3f2eSlogwang struct flow_classifier_acl { 732bfe3f2eSlogwang struct flow_classifier cls; 742bfe3f2eSlogwang } __rte_cache_aligned; 752bfe3f2eSlogwang 762bfe3f2eSlogwang /* ACL field definitions for IPv4 5 tuple rule */ 772bfe3f2eSlogwang 782bfe3f2eSlogwang enum { 792bfe3f2eSlogwang PROTO_FIELD_IPV4, 802bfe3f2eSlogwang SRC_FIELD_IPV4, 812bfe3f2eSlogwang DST_FIELD_IPV4, 822bfe3f2eSlogwang SRCP_FIELD_IPV4, 832bfe3f2eSlogwang DSTP_FIELD_IPV4, 842bfe3f2eSlogwang NUM_FIELDS_IPV4 852bfe3f2eSlogwang }; 862bfe3f2eSlogwang 872bfe3f2eSlogwang enum { 882bfe3f2eSlogwang PROTO_INPUT_IPV4, 892bfe3f2eSlogwang SRC_INPUT_IPV4, 902bfe3f2eSlogwang DST_INPUT_IPV4, 912bfe3f2eSlogwang SRCP_DESTP_INPUT_IPV4 922bfe3f2eSlogwang }; 932bfe3f2eSlogwang 942bfe3f2eSlogwang static struct rte_acl_field_def ipv4_defs[NUM_FIELDS_IPV4] = { 952bfe3f2eSlogwang /* first input field - always one byte long. */ 962bfe3f2eSlogwang { 972bfe3f2eSlogwang .type = RTE_ACL_FIELD_TYPE_BITMASK, 982bfe3f2eSlogwang .size = sizeof(uint8_t), 992bfe3f2eSlogwang .field_index = PROTO_FIELD_IPV4, 1002bfe3f2eSlogwang .input_index = PROTO_INPUT_IPV4, 1012bfe3f2eSlogwang .offset = sizeof(struct ether_hdr) + 1022bfe3f2eSlogwang offsetof(struct ipv4_hdr, next_proto_id), 1032bfe3f2eSlogwang }, 1042bfe3f2eSlogwang /* next input field (IPv4 source address) - 4 consecutive bytes. */ 1052bfe3f2eSlogwang { 1062bfe3f2eSlogwang /* rte_flow uses a bit mask for IPv4 addresses */ 1072bfe3f2eSlogwang .type = RTE_ACL_FIELD_TYPE_BITMASK, 1082bfe3f2eSlogwang .size = sizeof(uint32_t), 1092bfe3f2eSlogwang .field_index = SRC_FIELD_IPV4, 1102bfe3f2eSlogwang .input_index = SRC_INPUT_IPV4, 1112bfe3f2eSlogwang .offset = sizeof(struct ether_hdr) + 1122bfe3f2eSlogwang offsetof(struct ipv4_hdr, src_addr), 1132bfe3f2eSlogwang }, 1142bfe3f2eSlogwang /* next input field (IPv4 destination address) - 4 consecutive bytes. */ 1152bfe3f2eSlogwang { 1162bfe3f2eSlogwang /* rte_flow uses a bit mask for IPv4 addresses */ 1172bfe3f2eSlogwang .type = RTE_ACL_FIELD_TYPE_BITMASK, 1182bfe3f2eSlogwang .size = sizeof(uint32_t), 1192bfe3f2eSlogwang .field_index = DST_FIELD_IPV4, 1202bfe3f2eSlogwang .input_index = DST_INPUT_IPV4, 1212bfe3f2eSlogwang .offset = sizeof(struct ether_hdr) + 1222bfe3f2eSlogwang offsetof(struct ipv4_hdr, dst_addr), 1232bfe3f2eSlogwang }, 1242bfe3f2eSlogwang /* 1252bfe3f2eSlogwang * Next 2 fields (src & dst ports) form 4 consecutive bytes. 1262bfe3f2eSlogwang * They share the same input index. 1272bfe3f2eSlogwang */ 1282bfe3f2eSlogwang { 1292bfe3f2eSlogwang /* rte_flow uses a bit mask for protocol ports */ 1302bfe3f2eSlogwang .type = RTE_ACL_FIELD_TYPE_BITMASK, 1312bfe3f2eSlogwang .size = sizeof(uint16_t), 1322bfe3f2eSlogwang .field_index = SRCP_FIELD_IPV4, 1332bfe3f2eSlogwang .input_index = SRCP_DESTP_INPUT_IPV4, 1342bfe3f2eSlogwang .offset = sizeof(struct ether_hdr) + 1352bfe3f2eSlogwang sizeof(struct ipv4_hdr) + 1362bfe3f2eSlogwang offsetof(struct tcp_hdr, src_port), 1372bfe3f2eSlogwang }, 1382bfe3f2eSlogwang { 1392bfe3f2eSlogwang /* rte_flow uses a bit mask for protocol ports */ 1402bfe3f2eSlogwang .type = RTE_ACL_FIELD_TYPE_BITMASK, 1412bfe3f2eSlogwang .size = sizeof(uint16_t), 1422bfe3f2eSlogwang .field_index = DSTP_FIELD_IPV4, 1432bfe3f2eSlogwang .input_index = SRCP_DESTP_INPUT_IPV4, 1442bfe3f2eSlogwang .offset = sizeof(struct ether_hdr) + 1452bfe3f2eSlogwang sizeof(struct ipv4_hdr) + 1462bfe3f2eSlogwang offsetof(struct tcp_hdr, dst_port), 1472bfe3f2eSlogwang }, 1482bfe3f2eSlogwang }; 1492bfe3f2eSlogwang 1502bfe3f2eSlogwang /* flow classify data */ 1512bfe3f2eSlogwang static int num_classify_rules; 1522bfe3f2eSlogwang static struct rte_flow_classify_rule *rules[MAX_NUM_CLASSIFY]; 1532bfe3f2eSlogwang static struct rte_flow_classify_ipv4_5tuple_stats ntuple_stats; 1542bfe3f2eSlogwang static struct rte_flow_classify_stats classify_stats = { 1552bfe3f2eSlogwang .stats = (void **)&ntuple_stats 1562bfe3f2eSlogwang }; 1572bfe3f2eSlogwang 1582bfe3f2eSlogwang /* parameters for rte_flow_classify_validate and 1592bfe3f2eSlogwang * rte_flow_classify_table_entry_add functions 1602bfe3f2eSlogwang */ 1612bfe3f2eSlogwang 1622bfe3f2eSlogwang static struct rte_flow_item eth_item = { RTE_FLOW_ITEM_TYPE_ETH, 1632bfe3f2eSlogwang 0, 0, 0 }; 1642bfe3f2eSlogwang static struct rte_flow_item end_item = { RTE_FLOW_ITEM_TYPE_END, 1652bfe3f2eSlogwang 0, 0, 0 }; 1662bfe3f2eSlogwang 1672bfe3f2eSlogwang /* sample actions: 1682bfe3f2eSlogwang * "actions count / end" 1692bfe3f2eSlogwang */ 170*d30ea906Sjfb8856606 struct rte_flow_query_count count = { 171*d30ea906Sjfb8856606 .reset = 1, 172*d30ea906Sjfb8856606 .hits_set = 1, 173*d30ea906Sjfb8856606 .bytes_set = 1, 174*d30ea906Sjfb8856606 .hits = 0, 175*d30ea906Sjfb8856606 .bytes = 0, 176*d30ea906Sjfb8856606 }; 177*d30ea906Sjfb8856606 static struct rte_flow_action count_action = { RTE_FLOW_ACTION_TYPE_COUNT, 178*d30ea906Sjfb8856606 &count}; 1792bfe3f2eSlogwang static struct rte_flow_action end_action = { RTE_FLOW_ACTION_TYPE_END, 0}; 1802bfe3f2eSlogwang static struct rte_flow_action actions[2]; 1812bfe3f2eSlogwang 1822bfe3f2eSlogwang /* sample attributes */ 1832bfe3f2eSlogwang static struct rte_flow_attr attr; 1842bfe3f2eSlogwang 1852bfe3f2eSlogwang /* flow_classify.c: * Based on DPDK skeleton forwarding example. */ 1862bfe3f2eSlogwang 1872bfe3f2eSlogwang /* 1882bfe3f2eSlogwang * Initializes a given port using global settings and with the RX buffers 1892bfe3f2eSlogwang * coming from the mbuf_pool passed as a parameter. 1902bfe3f2eSlogwang */ 1912bfe3f2eSlogwang static inline int 1922bfe3f2eSlogwang port_init(uint8_t port, struct rte_mempool *mbuf_pool) 1932bfe3f2eSlogwang { 1942bfe3f2eSlogwang struct rte_eth_conf port_conf = port_conf_default; 1952bfe3f2eSlogwang struct ether_addr addr; 1962bfe3f2eSlogwang const uint16_t rx_rings = 1, tx_rings = 1; 1972bfe3f2eSlogwang int retval; 1982bfe3f2eSlogwang uint16_t q; 199*d30ea906Sjfb8856606 struct rte_eth_dev_info dev_info; 200*d30ea906Sjfb8856606 struct rte_eth_txconf txconf; 2012bfe3f2eSlogwang 202*d30ea906Sjfb8856606 if (!rte_eth_dev_is_valid_port(port)) 2032bfe3f2eSlogwang return -1; 2042bfe3f2eSlogwang 205*d30ea906Sjfb8856606 rte_eth_dev_info_get(port, &dev_info); 206*d30ea906Sjfb8856606 if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE) 207*d30ea906Sjfb8856606 port_conf.txmode.offloads |= 208*d30ea906Sjfb8856606 DEV_TX_OFFLOAD_MBUF_FAST_FREE; 209*d30ea906Sjfb8856606 2102bfe3f2eSlogwang /* Configure the Ethernet device. */ 2112bfe3f2eSlogwang retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf); 2122bfe3f2eSlogwang if (retval != 0) 2132bfe3f2eSlogwang return retval; 2142bfe3f2eSlogwang 2152bfe3f2eSlogwang /* Allocate and set up 1 RX queue per Ethernet port. */ 2162bfe3f2eSlogwang for (q = 0; q < rx_rings; q++) { 2172bfe3f2eSlogwang retval = rte_eth_rx_queue_setup(port, q, RX_RING_SIZE, 2182bfe3f2eSlogwang rte_eth_dev_socket_id(port), NULL, mbuf_pool); 2192bfe3f2eSlogwang if (retval < 0) 2202bfe3f2eSlogwang return retval; 2212bfe3f2eSlogwang } 2222bfe3f2eSlogwang 223*d30ea906Sjfb8856606 txconf = dev_info.default_txconf; 224*d30ea906Sjfb8856606 txconf.offloads = port_conf.txmode.offloads; 2252bfe3f2eSlogwang /* Allocate and set up 1 TX queue per Ethernet port. */ 2262bfe3f2eSlogwang for (q = 0; q < tx_rings; q++) { 2272bfe3f2eSlogwang retval = rte_eth_tx_queue_setup(port, q, TX_RING_SIZE, 228*d30ea906Sjfb8856606 rte_eth_dev_socket_id(port), &txconf); 2292bfe3f2eSlogwang if (retval < 0) 2302bfe3f2eSlogwang return retval; 2312bfe3f2eSlogwang } 2322bfe3f2eSlogwang 2332bfe3f2eSlogwang /* Start the Ethernet port. */ 2342bfe3f2eSlogwang retval = rte_eth_dev_start(port); 2352bfe3f2eSlogwang if (retval < 0) 2362bfe3f2eSlogwang return retval; 2372bfe3f2eSlogwang 2382bfe3f2eSlogwang /* Display the port MAC address. */ 2392bfe3f2eSlogwang rte_eth_macaddr_get(port, &addr); 2402bfe3f2eSlogwang printf("Port %u MAC: %02" PRIx8 " %02" PRIx8 " %02" PRIx8 2412bfe3f2eSlogwang " %02" PRIx8 " %02" PRIx8 " %02" PRIx8 "\n", 2422bfe3f2eSlogwang port, 2432bfe3f2eSlogwang addr.addr_bytes[0], addr.addr_bytes[1], 2442bfe3f2eSlogwang addr.addr_bytes[2], addr.addr_bytes[3], 2452bfe3f2eSlogwang addr.addr_bytes[4], addr.addr_bytes[5]); 2462bfe3f2eSlogwang 2472bfe3f2eSlogwang /* Enable RX in promiscuous mode for the Ethernet device. */ 2482bfe3f2eSlogwang rte_eth_promiscuous_enable(port); 2492bfe3f2eSlogwang 2502bfe3f2eSlogwang return 0; 2512bfe3f2eSlogwang } 2522bfe3f2eSlogwang 2532bfe3f2eSlogwang /* 2542bfe3f2eSlogwang * The lcore main. This is the main thread that does the work, reading from 2552bfe3f2eSlogwang * an input port classifying the packets and writing to an output port. 2562bfe3f2eSlogwang */ 2572bfe3f2eSlogwang static __attribute__((noreturn)) void 2582bfe3f2eSlogwang lcore_main(struct flow_classifier *cls_app) 2592bfe3f2eSlogwang { 260*d30ea906Sjfb8856606 uint16_t port; 2612bfe3f2eSlogwang int ret; 2622bfe3f2eSlogwang int i = 0; 2632bfe3f2eSlogwang 2642bfe3f2eSlogwang ret = rte_flow_classify_table_entry_delete(cls_app->cls, 265*d30ea906Sjfb8856606 rules[7]); 2662bfe3f2eSlogwang if (ret) 2672bfe3f2eSlogwang printf("table_entry_delete failed [7] %d\n\n", ret); 2682bfe3f2eSlogwang else 2692bfe3f2eSlogwang printf("table_entry_delete succeeded [7]\n\n"); 2702bfe3f2eSlogwang 2712bfe3f2eSlogwang /* 2722bfe3f2eSlogwang * Check that the port is on the same NUMA node as the polling thread 2732bfe3f2eSlogwang * for best performance. 2742bfe3f2eSlogwang */ 275*d30ea906Sjfb8856606 RTE_ETH_FOREACH_DEV(port) 2762bfe3f2eSlogwang if (rte_eth_dev_socket_id(port) > 0 && 2772bfe3f2eSlogwang rte_eth_dev_socket_id(port) != (int)rte_socket_id()) { 2782bfe3f2eSlogwang printf("\n\n"); 2792bfe3f2eSlogwang printf("WARNING: port %u is on remote NUMA node\n", 2802bfe3f2eSlogwang port); 2812bfe3f2eSlogwang printf("to polling thread.\n"); 2822bfe3f2eSlogwang printf("Performance will not be optimal.\n"); 2835af785ecSfengbojiang(姜凤波) } 284*d30ea906Sjfb8856606 printf("\nCore %u forwarding packets. ", rte_lcore_id()); 285*d30ea906Sjfb8856606 printf("[Ctrl+C to quit]\n"); 286*d30ea906Sjfb8856606 2872bfe3f2eSlogwang /* Run until the application is quit or killed. */ 2882bfe3f2eSlogwang for (;;) { 2892bfe3f2eSlogwang /* 2902bfe3f2eSlogwang * Receive packets on a port, classify them and forward them 2912bfe3f2eSlogwang * on the paired port. 2922bfe3f2eSlogwang * The mapping is 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2, etc. 2932bfe3f2eSlogwang */ 294*d30ea906Sjfb8856606 RTE_ETH_FOREACH_DEV(port) { 2952bfe3f2eSlogwang /* Get burst of RX packets, from first port of pair. */ 2962bfe3f2eSlogwang struct rte_mbuf *bufs[BURST_SIZE]; 2972bfe3f2eSlogwang const uint16_t nb_rx = rte_eth_rx_burst(port, 0, 2982bfe3f2eSlogwang bufs, BURST_SIZE); 2992bfe3f2eSlogwang 3002bfe3f2eSlogwang if (unlikely(nb_rx == 0)) 3012bfe3f2eSlogwang continue; 3022bfe3f2eSlogwang 3032bfe3f2eSlogwang for (i = 0; i < MAX_NUM_CLASSIFY; i++) { 3042bfe3f2eSlogwang if (rules[i]) { 3052bfe3f2eSlogwang ret = rte_flow_classifier_query( 3062bfe3f2eSlogwang cls_app->cls, 3072bfe3f2eSlogwang bufs, nb_rx, rules[i], 3082bfe3f2eSlogwang &classify_stats); 3092bfe3f2eSlogwang if (ret) 3102bfe3f2eSlogwang printf( 3112bfe3f2eSlogwang "rule [%d] query failed ret [%d]\n\n", 3122bfe3f2eSlogwang i, ret); 3132bfe3f2eSlogwang else { 3142bfe3f2eSlogwang printf( 3152bfe3f2eSlogwang "rule[%d] count=%"PRIu64"\n", 3162bfe3f2eSlogwang i, ntuple_stats.counter1); 3172bfe3f2eSlogwang 3182bfe3f2eSlogwang printf("proto = %d\n", 3192bfe3f2eSlogwang ntuple_stats.ipv4_5tuple.proto); 3202bfe3f2eSlogwang } 3212bfe3f2eSlogwang } 3222bfe3f2eSlogwang } 3232bfe3f2eSlogwang 3242bfe3f2eSlogwang /* Send burst of TX packets, to second port of pair. */ 3252bfe3f2eSlogwang const uint16_t nb_tx = rte_eth_tx_burst(port ^ 1, 0, 3262bfe3f2eSlogwang bufs, nb_rx); 3272bfe3f2eSlogwang 3282bfe3f2eSlogwang /* Free any unsent packets. */ 3292bfe3f2eSlogwang if (unlikely(nb_tx < nb_rx)) { 3302bfe3f2eSlogwang uint16_t buf; 3312bfe3f2eSlogwang 3322bfe3f2eSlogwang for (buf = nb_tx; buf < nb_rx; buf++) 3332bfe3f2eSlogwang rte_pktmbuf_free(bufs[buf]); 3342bfe3f2eSlogwang } 3352bfe3f2eSlogwang } 3362bfe3f2eSlogwang } 3372bfe3f2eSlogwang } 3382bfe3f2eSlogwang 3392bfe3f2eSlogwang /* 3402bfe3f2eSlogwang * Parse IPv4 5 tuple rules file, ipv4_rules_file.txt. 3412bfe3f2eSlogwang * Expected format: 3422bfe3f2eSlogwang * <src_ipv4_addr>'/'<masklen> <space> \ 3432bfe3f2eSlogwang * <dst_ipv4_addr>'/'<masklen> <space> \ 3442bfe3f2eSlogwang * <src_port> <space> ":" <src_port_mask> <space> \ 3452bfe3f2eSlogwang * <dst_port> <space> ":" <dst_port_mask> <space> \ 3462bfe3f2eSlogwang * <proto>'/'<proto_mask> <space> \ 3472bfe3f2eSlogwang * <priority> 3482bfe3f2eSlogwang */ 3492bfe3f2eSlogwang 3502bfe3f2eSlogwang static int 3512bfe3f2eSlogwang get_cb_field(char **in, uint32_t *fd, int base, unsigned long lim, 3522bfe3f2eSlogwang char dlm) 3532bfe3f2eSlogwang { 3542bfe3f2eSlogwang unsigned long val; 3552bfe3f2eSlogwang char *end; 3562bfe3f2eSlogwang 3572bfe3f2eSlogwang errno = 0; 3582bfe3f2eSlogwang val = strtoul(*in, &end, base); 3592bfe3f2eSlogwang if (errno != 0 || end[0] != dlm || val > lim) 3602bfe3f2eSlogwang return -EINVAL; 3612bfe3f2eSlogwang *fd = (uint32_t)val; 3622bfe3f2eSlogwang *in = end + 1; 3632bfe3f2eSlogwang return 0; 3642bfe3f2eSlogwang } 3652bfe3f2eSlogwang 3662bfe3f2eSlogwang static int 3672bfe3f2eSlogwang parse_ipv4_net(char *in, uint32_t *addr, uint32_t *mask_len) 3682bfe3f2eSlogwang { 3692bfe3f2eSlogwang uint32_t a, b, c, d, m; 3702bfe3f2eSlogwang 3712bfe3f2eSlogwang if (get_cb_field(&in, &a, 0, UINT8_MAX, '.')) 3722bfe3f2eSlogwang return -EINVAL; 3732bfe3f2eSlogwang if (get_cb_field(&in, &b, 0, UINT8_MAX, '.')) 3742bfe3f2eSlogwang return -EINVAL; 3752bfe3f2eSlogwang if (get_cb_field(&in, &c, 0, UINT8_MAX, '.')) 3762bfe3f2eSlogwang return -EINVAL; 3772bfe3f2eSlogwang if (get_cb_field(&in, &d, 0, UINT8_MAX, '/')) 3782bfe3f2eSlogwang return -EINVAL; 3792bfe3f2eSlogwang if (get_cb_field(&in, &m, 0, sizeof(uint32_t) * CHAR_BIT, 0)) 3802bfe3f2eSlogwang return -EINVAL; 3812bfe3f2eSlogwang 3822bfe3f2eSlogwang addr[0] = IPv4(a, b, c, d); 3832bfe3f2eSlogwang mask_len[0] = m; 3842bfe3f2eSlogwang return 0; 3852bfe3f2eSlogwang } 3862bfe3f2eSlogwang 3872bfe3f2eSlogwang static int 3882bfe3f2eSlogwang parse_ipv4_5tuple_rule(char *str, struct rte_eth_ntuple_filter *ntuple_filter) 3892bfe3f2eSlogwang { 3902bfe3f2eSlogwang int i, ret; 3912bfe3f2eSlogwang char *s, *sp, *in[CB_FLD_NUM]; 3922bfe3f2eSlogwang static const char *dlm = " \t\n"; 3932bfe3f2eSlogwang int dim = CB_FLD_NUM; 3942bfe3f2eSlogwang uint32_t temp; 3952bfe3f2eSlogwang 3962bfe3f2eSlogwang s = str; 3972bfe3f2eSlogwang for (i = 0; i != dim; i++, s = NULL) { 3982bfe3f2eSlogwang in[i] = strtok_r(s, dlm, &sp); 3992bfe3f2eSlogwang if (in[i] == NULL) 4002bfe3f2eSlogwang return -EINVAL; 4012bfe3f2eSlogwang } 4022bfe3f2eSlogwang 4032bfe3f2eSlogwang ret = parse_ipv4_net(in[CB_FLD_SRC_ADDR], 4042bfe3f2eSlogwang &ntuple_filter->src_ip, 4052bfe3f2eSlogwang &ntuple_filter->src_ip_mask); 4062bfe3f2eSlogwang if (ret != 0) { 4072bfe3f2eSlogwang flow_classify_log("failed to read source address/mask: %s\n", 4082bfe3f2eSlogwang in[CB_FLD_SRC_ADDR]); 4092bfe3f2eSlogwang return ret; 4102bfe3f2eSlogwang } 4112bfe3f2eSlogwang 4122bfe3f2eSlogwang ret = parse_ipv4_net(in[CB_FLD_DST_ADDR], 4132bfe3f2eSlogwang &ntuple_filter->dst_ip, 4142bfe3f2eSlogwang &ntuple_filter->dst_ip_mask); 4152bfe3f2eSlogwang if (ret != 0) { 4162bfe3f2eSlogwang flow_classify_log("failed to read source address/mask: %s\n", 4172bfe3f2eSlogwang in[CB_FLD_DST_ADDR]); 4182bfe3f2eSlogwang return ret; 4192bfe3f2eSlogwang } 4202bfe3f2eSlogwang 4212bfe3f2eSlogwang if (get_cb_field(&in[CB_FLD_SRC_PORT], &temp, 0, UINT16_MAX, 0)) 4222bfe3f2eSlogwang return -EINVAL; 4232bfe3f2eSlogwang ntuple_filter->src_port = (uint16_t)temp; 4242bfe3f2eSlogwang 4252bfe3f2eSlogwang if (strncmp(in[CB_FLD_SRC_PORT_DLM], cb_port_delim, 4262bfe3f2eSlogwang sizeof(cb_port_delim)) != 0) 4272bfe3f2eSlogwang return -EINVAL; 4282bfe3f2eSlogwang 4292bfe3f2eSlogwang if (get_cb_field(&in[CB_FLD_SRC_PORT_MASK], &temp, 0, UINT16_MAX, 0)) 4302bfe3f2eSlogwang return -EINVAL; 4312bfe3f2eSlogwang ntuple_filter->src_port_mask = (uint16_t)temp; 4322bfe3f2eSlogwang 4332bfe3f2eSlogwang if (get_cb_field(&in[CB_FLD_DST_PORT], &temp, 0, UINT16_MAX, 0)) 4342bfe3f2eSlogwang return -EINVAL; 4352bfe3f2eSlogwang ntuple_filter->dst_port = (uint16_t)temp; 4362bfe3f2eSlogwang 4372bfe3f2eSlogwang if (strncmp(in[CB_FLD_DST_PORT_DLM], cb_port_delim, 4382bfe3f2eSlogwang sizeof(cb_port_delim)) != 0) 4392bfe3f2eSlogwang return -EINVAL; 4402bfe3f2eSlogwang 4412bfe3f2eSlogwang if (get_cb_field(&in[CB_FLD_DST_PORT_MASK], &temp, 0, UINT16_MAX, 0)) 4422bfe3f2eSlogwang return -EINVAL; 4432bfe3f2eSlogwang ntuple_filter->dst_port_mask = (uint16_t)temp; 4442bfe3f2eSlogwang 4452bfe3f2eSlogwang if (get_cb_field(&in[CB_FLD_PROTO], &temp, 0, UINT8_MAX, '/')) 4462bfe3f2eSlogwang return -EINVAL; 4472bfe3f2eSlogwang ntuple_filter->proto = (uint8_t)temp; 4482bfe3f2eSlogwang 4492bfe3f2eSlogwang if (get_cb_field(&in[CB_FLD_PROTO], &temp, 0, UINT8_MAX, 0)) 4502bfe3f2eSlogwang return -EINVAL; 4512bfe3f2eSlogwang ntuple_filter->proto_mask = (uint8_t)temp; 4522bfe3f2eSlogwang 4532bfe3f2eSlogwang if (get_cb_field(&in[CB_FLD_PRIORITY], &temp, 0, UINT16_MAX, 0)) 4542bfe3f2eSlogwang return -EINVAL; 4552bfe3f2eSlogwang ntuple_filter->priority = (uint16_t)temp; 4562bfe3f2eSlogwang if (ntuple_filter->priority > FLOW_CLASSIFY_MAX_PRIORITY) 4572bfe3f2eSlogwang ret = -EINVAL; 4582bfe3f2eSlogwang 4592bfe3f2eSlogwang return ret; 4602bfe3f2eSlogwang } 4612bfe3f2eSlogwang 4622bfe3f2eSlogwang /* Bypass comment and empty lines */ 4632bfe3f2eSlogwang static inline int 4642bfe3f2eSlogwang is_bypass_line(char *buff) 4652bfe3f2eSlogwang { 4662bfe3f2eSlogwang int i = 0; 4672bfe3f2eSlogwang 4682bfe3f2eSlogwang /* comment line */ 4692bfe3f2eSlogwang if (buff[0] == COMMENT_LEAD_CHAR) 4702bfe3f2eSlogwang return 1; 4712bfe3f2eSlogwang /* empty line */ 4722bfe3f2eSlogwang while (buff[i] != '\0') { 4732bfe3f2eSlogwang if (!isspace(buff[i])) 4742bfe3f2eSlogwang return 0; 4752bfe3f2eSlogwang i++; 4762bfe3f2eSlogwang } 4772bfe3f2eSlogwang return 1; 4782bfe3f2eSlogwang } 4792bfe3f2eSlogwang 4802bfe3f2eSlogwang static uint32_t 4812bfe3f2eSlogwang convert_depth_to_bitmask(uint32_t depth_val) 4822bfe3f2eSlogwang { 4832bfe3f2eSlogwang uint32_t bitmask = 0; 4842bfe3f2eSlogwang int i, j; 4852bfe3f2eSlogwang 4862bfe3f2eSlogwang for (i = depth_val, j = 0; i > 0; i--, j++) 4872bfe3f2eSlogwang bitmask |= (1 << (31 - j)); 4882bfe3f2eSlogwang return bitmask; 4892bfe3f2eSlogwang } 4902bfe3f2eSlogwang 4912bfe3f2eSlogwang static int 4922bfe3f2eSlogwang add_classify_rule(struct rte_eth_ntuple_filter *ntuple_filter, 4932bfe3f2eSlogwang struct flow_classifier *cls_app) 4942bfe3f2eSlogwang { 4952bfe3f2eSlogwang int ret = -1; 4962bfe3f2eSlogwang int key_found; 4972bfe3f2eSlogwang struct rte_flow_error error; 4982bfe3f2eSlogwang struct rte_flow_item_ipv4 ipv4_spec; 4992bfe3f2eSlogwang struct rte_flow_item_ipv4 ipv4_mask; 5002bfe3f2eSlogwang struct rte_flow_item ipv4_udp_item; 5012bfe3f2eSlogwang struct rte_flow_item ipv4_tcp_item; 5022bfe3f2eSlogwang struct rte_flow_item ipv4_sctp_item; 5032bfe3f2eSlogwang struct rte_flow_item_udp udp_spec; 5042bfe3f2eSlogwang struct rte_flow_item_udp udp_mask; 5052bfe3f2eSlogwang struct rte_flow_item udp_item; 5062bfe3f2eSlogwang struct rte_flow_item_tcp tcp_spec; 5072bfe3f2eSlogwang struct rte_flow_item_tcp tcp_mask; 5082bfe3f2eSlogwang struct rte_flow_item tcp_item; 5092bfe3f2eSlogwang struct rte_flow_item_sctp sctp_spec; 5102bfe3f2eSlogwang struct rte_flow_item_sctp sctp_mask; 5112bfe3f2eSlogwang struct rte_flow_item sctp_item; 5122bfe3f2eSlogwang struct rte_flow_item pattern_ipv4_5tuple[4]; 5132bfe3f2eSlogwang struct rte_flow_classify_rule *rule; 5142bfe3f2eSlogwang uint8_t ipv4_proto; 5152bfe3f2eSlogwang 5162bfe3f2eSlogwang if (num_classify_rules >= MAX_NUM_CLASSIFY) { 5172bfe3f2eSlogwang printf( 5182bfe3f2eSlogwang "\nINFO: classify rule capacity %d reached\n", 5192bfe3f2eSlogwang num_classify_rules); 5202bfe3f2eSlogwang return ret; 5212bfe3f2eSlogwang } 5222bfe3f2eSlogwang 5232bfe3f2eSlogwang /* set up parameters for validate and add */ 5242bfe3f2eSlogwang memset(&ipv4_spec, 0, sizeof(ipv4_spec)); 5252bfe3f2eSlogwang ipv4_spec.hdr.next_proto_id = ntuple_filter->proto; 5262bfe3f2eSlogwang ipv4_spec.hdr.src_addr = ntuple_filter->src_ip; 5272bfe3f2eSlogwang ipv4_spec.hdr.dst_addr = ntuple_filter->dst_ip; 5282bfe3f2eSlogwang ipv4_proto = ipv4_spec.hdr.next_proto_id; 5292bfe3f2eSlogwang 5302bfe3f2eSlogwang memset(&ipv4_mask, 0, sizeof(ipv4_mask)); 5312bfe3f2eSlogwang ipv4_mask.hdr.next_proto_id = ntuple_filter->proto_mask; 5322bfe3f2eSlogwang ipv4_mask.hdr.src_addr = ntuple_filter->src_ip_mask; 5332bfe3f2eSlogwang ipv4_mask.hdr.src_addr = 5342bfe3f2eSlogwang convert_depth_to_bitmask(ipv4_mask.hdr.src_addr); 5352bfe3f2eSlogwang ipv4_mask.hdr.dst_addr = ntuple_filter->dst_ip_mask; 5362bfe3f2eSlogwang ipv4_mask.hdr.dst_addr = 5372bfe3f2eSlogwang convert_depth_to_bitmask(ipv4_mask.hdr.dst_addr); 5382bfe3f2eSlogwang 5392bfe3f2eSlogwang switch (ipv4_proto) { 5402bfe3f2eSlogwang case IPPROTO_UDP: 5412bfe3f2eSlogwang ipv4_udp_item.type = RTE_FLOW_ITEM_TYPE_IPV4; 5422bfe3f2eSlogwang ipv4_udp_item.spec = &ipv4_spec; 5432bfe3f2eSlogwang ipv4_udp_item.mask = &ipv4_mask; 5442bfe3f2eSlogwang ipv4_udp_item.last = NULL; 5452bfe3f2eSlogwang 5462bfe3f2eSlogwang udp_spec.hdr.src_port = ntuple_filter->src_port; 5472bfe3f2eSlogwang udp_spec.hdr.dst_port = ntuple_filter->dst_port; 5482bfe3f2eSlogwang udp_spec.hdr.dgram_len = 0; 5492bfe3f2eSlogwang udp_spec.hdr.dgram_cksum = 0; 5502bfe3f2eSlogwang 5512bfe3f2eSlogwang udp_mask.hdr.src_port = ntuple_filter->src_port_mask; 5522bfe3f2eSlogwang udp_mask.hdr.dst_port = ntuple_filter->dst_port_mask; 5532bfe3f2eSlogwang udp_mask.hdr.dgram_len = 0; 5542bfe3f2eSlogwang udp_mask.hdr.dgram_cksum = 0; 5552bfe3f2eSlogwang 5562bfe3f2eSlogwang udp_item.type = RTE_FLOW_ITEM_TYPE_UDP; 5572bfe3f2eSlogwang udp_item.spec = &udp_spec; 5582bfe3f2eSlogwang udp_item.mask = &udp_mask; 5592bfe3f2eSlogwang udp_item.last = NULL; 5602bfe3f2eSlogwang 5612bfe3f2eSlogwang attr.priority = ntuple_filter->priority; 5622bfe3f2eSlogwang pattern_ipv4_5tuple[1] = ipv4_udp_item; 5632bfe3f2eSlogwang pattern_ipv4_5tuple[2] = udp_item; 5642bfe3f2eSlogwang break; 5652bfe3f2eSlogwang case IPPROTO_TCP: 5662bfe3f2eSlogwang ipv4_tcp_item.type = RTE_FLOW_ITEM_TYPE_IPV4; 5672bfe3f2eSlogwang ipv4_tcp_item.spec = &ipv4_spec; 5682bfe3f2eSlogwang ipv4_tcp_item.mask = &ipv4_mask; 5692bfe3f2eSlogwang ipv4_tcp_item.last = NULL; 5702bfe3f2eSlogwang 5712bfe3f2eSlogwang memset(&tcp_spec, 0, sizeof(tcp_spec)); 5722bfe3f2eSlogwang tcp_spec.hdr.src_port = ntuple_filter->src_port; 5732bfe3f2eSlogwang tcp_spec.hdr.dst_port = ntuple_filter->dst_port; 5742bfe3f2eSlogwang 5752bfe3f2eSlogwang memset(&tcp_mask, 0, sizeof(tcp_mask)); 5762bfe3f2eSlogwang tcp_mask.hdr.src_port = ntuple_filter->src_port_mask; 5772bfe3f2eSlogwang tcp_mask.hdr.dst_port = ntuple_filter->dst_port_mask; 5782bfe3f2eSlogwang 5792bfe3f2eSlogwang tcp_item.type = RTE_FLOW_ITEM_TYPE_TCP; 5802bfe3f2eSlogwang tcp_item.spec = &tcp_spec; 5812bfe3f2eSlogwang tcp_item.mask = &tcp_mask; 5822bfe3f2eSlogwang tcp_item.last = NULL; 5832bfe3f2eSlogwang 5842bfe3f2eSlogwang attr.priority = ntuple_filter->priority; 5852bfe3f2eSlogwang pattern_ipv4_5tuple[1] = ipv4_tcp_item; 5862bfe3f2eSlogwang pattern_ipv4_5tuple[2] = tcp_item; 5872bfe3f2eSlogwang break; 5882bfe3f2eSlogwang case IPPROTO_SCTP: 5892bfe3f2eSlogwang ipv4_sctp_item.type = RTE_FLOW_ITEM_TYPE_IPV4; 5902bfe3f2eSlogwang ipv4_sctp_item.spec = &ipv4_spec; 5912bfe3f2eSlogwang ipv4_sctp_item.mask = &ipv4_mask; 5922bfe3f2eSlogwang ipv4_sctp_item.last = NULL; 5932bfe3f2eSlogwang 5942bfe3f2eSlogwang sctp_spec.hdr.src_port = ntuple_filter->src_port; 5952bfe3f2eSlogwang sctp_spec.hdr.dst_port = ntuple_filter->dst_port; 5962bfe3f2eSlogwang sctp_spec.hdr.cksum = 0; 5972bfe3f2eSlogwang sctp_spec.hdr.tag = 0; 5982bfe3f2eSlogwang 5992bfe3f2eSlogwang sctp_mask.hdr.src_port = ntuple_filter->src_port_mask; 6002bfe3f2eSlogwang sctp_mask.hdr.dst_port = ntuple_filter->dst_port_mask; 6012bfe3f2eSlogwang sctp_mask.hdr.cksum = 0; 6022bfe3f2eSlogwang sctp_mask.hdr.tag = 0; 6032bfe3f2eSlogwang 6042bfe3f2eSlogwang sctp_item.type = RTE_FLOW_ITEM_TYPE_SCTP; 6052bfe3f2eSlogwang sctp_item.spec = &sctp_spec; 6062bfe3f2eSlogwang sctp_item.mask = &sctp_mask; 6072bfe3f2eSlogwang sctp_item.last = NULL; 6082bfe3f2eSlogwang 6092bfe3f2eSlogwang attr.priority = ntuple_filter->priority; 6102bfe3f2eSlogwang pattern_ipv4_5tuple[1] = ipv4_sctp_item; 6112bfe3f2eSlogwang pattern_ipv4_5tuple[2] = sctp_item; 6122bfe3f2eSlogwang break; 6132bfe3f2eSlogwang default: 6142bfe3f2eSlogwang return ret; 6152bfe3f2eSlogwang } 6162bfe3f2eSlogwang 6172bfe3f2eSlogwang attr.ingress = 1; 6182bfe3f2eSlogwang pattern_ipv4_5tuple[0] = eth_item; 6192bfe3f2eSlogwang pattern_ipv4_5tuple[3] = end_item; 6202bfe3f2eSlogwang actions[0] = count_action; 6212bfe3f2eSlogwang actions[1] = end_action; 6222bfe3f2eSlogwang 623*d30ea906Sjfb8856606 /* Validate and add rule */ 624*d30ea906Sjfb8856606 ret = rte_flow_classify_validate(cls_app->cls, &attr, 625*d30ea906Sjfb8856606 pattern_ipv4_5tuple, actions, &error); 626*d30ea906Sjfb8856606 if (ret) { 627*d30ea906Sjfb8856606 printf("table entry validate failed ipv4_proto = %u\n", 628*d30ea906Sjfb8856606 ipv4_proto); 629*d30ea906Sjfb8856606 return ret; 630*d30ea906Sjfb8856606 } 631*d30ea906Sjfb8856606 6322bfe3f2eSlogwang rule = rte_flow_classify_table_entry_add( 633*d30ea906Sjfb8856606 cls_app->cls, &attr, pattern_ipv4_5tuple, 634*d30ea906Sjfb8856606 actions, &key_found, &error); 6352bfe3f2eSlogwang if (rule == NULL) { 6362bfe3f2eSlogwang printf("table entry add failed ipv4_proto = %u\n", 6372bfe3f2eSlogwang ipv4_proto); 6382bfe3f2eSlogwang ret = -1; 6392bfe3f2eSlogwang return ret; 6402bfe3f2eSlogwang } 6412bfe3f2eSlogwang 6422bfe3f2eSlogwang rules[num_classify_rules] = rule; 6432bfe3f2eSlogwang num_classify_rules++; 6442bfe3f2eSlogwang return 0; 6452bfe3f2eSlogwang } 6462bfe3f2eSlogwang 6472bfe3f2eSlogwang static int 6482bfe3f2eSlogwang add_rules(const char *rule_path, struct flow_classifier *cls_app) 6492bfe3f2eSlogwang { 6502bfe3f2eSlogwang FILE *fh; 6512bfe3f2eSlogwang char buff[LINE_MAX]; 6522bfe3f2eSlogwang unsigned int i = 0; 6532bfe3f2eSlogwang unsigned int total_num = 0; 6542bfe3f2eSlogwang struct rte_eth_ntuple_filter ntuple_filter; 6552bfe3f2eSlogwang int ret; 6562bfe3f2eSlogwang 6572bfe3f2eSlogwang fh = fopen(rule_path, "rb"); 6582bfe3f2eSlogwang if (fh == NULL) 6592bfe3f2eSlogwang rte_exit(EXIT_FAILURE, "%s: fopen %s failed\n", __func__, 6602bfe3f2eSlogwang rule_path); 6612bfe3f2eSlogwang 6622bfe3f2eSlogwang ret = fseek(fh, 0, SEEK_SET); 6632bfe3f2eSlogwang if (ret) 6642bfe3f2eSlogwang rte_exit(EXIT_FAILURE, "%s: fseek %d failed\n", __func__, 6652bfe3f2eSlogwang ret); 6662bfe3f2eSlogwang 6672bfe3f2eSlogwang i = 0; 6682bfe3f2eSlogwang while (fgets(buff, LINE_MAX, fh) != NULL) { 6692bfe3f2eSlogwang i++; 6702bfe3f2eSlogwang 6712bfe3f2eSlogwang if (is_bypass_line(buff)) 6722bfe3f2eSlogwang continue; 6732bfe3f2eSlogwang 6742bfe3f2eSlogwang if (total_num >= FLOW_CLASSIFY_MAX_RULE_NUM - 1) { 6752bfe3f2eSlogwang printf("\nINFO: classify rule capacity %d reached\n", 6762bfe3f2eSlogwang total_num); 6772bfe3f2eSlogwang break; 6782bfe3f2eSlogwang } 6792bfe3f2eSlogwang 6802bfe3f2eSlogwang if (parse_ipv4_5tuple_rule(buff, &ntuple_filter) != 0) 6812bfe3f2eSlogwang rte_exit(EXIT_FAILURE, 6822bfe3f2eSlogwang "%s Line %u: parse rules error\n", 6832bfe3f2eSlogwang rule_path, i); 6842bfe3f2eSlogwang 6852bfe3f2eSlogwang if (add_classify_rule(&ntuple_filter, cls_app) != 0) 6862bfe3f2eSlogwang rte_exit(EXIT_FAILURE, "add rule error\n"); 6872bfe3f2eSlogwang 6882bfe3f2eSlogwang total_num++; 6892bfe3f2eSlogwang } 6902bfe3f2eSlogwang 6912bfe3f2eSlogwang fclose(fh); 6922bfe3f2eSlogwang return 0; 6932bfe3f2eSlogwang } 6942bfe3f2eSlogwang 6952bfe3f2eSlogwang /* display usage */ 6962bfe3f2eSlogwang static void 6972bfe3f2eSlogwang print_usage(const char *prgname) 6982bfe3f2eSlogwang { 6992bfe3f2eSlogwang printf("%s usage:\n", prgname); 7002bfe3f2eSlogwang printf("[EAL options] -- --"OPTION_RULE_IPV4"=FILE: "); 7012bfe3f2eSlogwang printf("specify the ipv4 rules file.\n"); 7022bfe3f2eSlogwang printf("Each rule occupies one line in the file.\n"); 7032bfe3f2eSlogwang } 7042bfe3f2eSlogwang 7052bfe3f2eSlogwang /* Parse the argument given in the command line of the application */ 7062bfe3f2eSlogwang static int 7072bfe3f2eSlogwang parse_args(int argc, char **argv) 7082bfe3f2eSlogwang { 7092bfe3f2eSlogwang int opt, ret; 7102bfe3f2eSlogwang char **argvopt; 7112bfe3f2eSlogwang int option_index; 7122bfe3f2eSlogwang char *prgname = argv[0]; 7132bfe3f2eSlogwang static struct option lgopts[] = { 7142bfe3f2eSlogwang {OPTION_RULE_IPV4, 1, 0, 0}, 7152bfe3f2eSlogwang {NULL, 0, 0, 0} 7162bfe3f2eSlogwang }; 7172bfe3f2eSlogwang 7182bfe3f2eSlogwang argvopt = argv; 7192bfe3f2eSlogwang 7202bfe3f2eSlogwang while ((opt = getopt_long(argc, argvopt, "", 7212bfe3f2eSlogwang lgopts, &option_index)) != EOF) { 7222bfe3f2eSlogwang 7232bfe3f2eSlogwang switch (opt) { 7242bfe3f2eSlogwang /* long options */ 7252bfe3f2eSlogwang case 0: 7262bfe3f2eSlogwang if (!strncmp(lgopts[option_index].name, 7272bfe3f2eSlogwang OPTION_RULE_IPV4, 7282bfe3f2eSlogwang sizeof(OPTION_RULE_IPV4))) 7292bfe3f2eSlogwang parm_config.rule_ipv4_name = optarg; 7302bfe3f2eSlogwang break; 7312bfe3f2eSlogwang default: 7322bfe3f2eSlogwang print_usage(prgname); 7332bfe3f2eSlogwang return -1; 7342bfe3f2eSlogwang } 7352bfe3f2eSlogwang } 7362bfe3f2eSlogwang 7372bfe3f2eSlogwang if (optind >= 0) 7382bfe3f2eSlogwang argv[optind-1] = prgname; 7392bfe3f2eSlogwang 7402bfe3f2eSlogwang ret = optind-1; 7412bfe3f2eSlogwang optind = 1; /* reset getopt lib */ 7422bfe3f2eSlogwang return ret; 7432bfe3f2eSlogwang } 7442bfe3f2eSlogwang 7452bfe3f2eSlogwang /* 7462bfe3f2eSlogwang * The main function, which does initialization and calls the lcore_main 7472bfe3f2eSlogwang * function. 7482bfe3f2eSlogwang */ 7492bfe3f2eSlogwang int 7502bfe3f2eSlogwang main(int argc, char *argv[]) 7512bfe3f2eSlogwang { 7522bfe3f2eSlogwang struct rte_mempool *mbuf_pool; 753*d30ea906Sjfb8856606 uint16_t nb_ports; 754*d30ea906Sjfb8856606 uint16_t portid; 7552bfe3f2eSlogwang int ret; 7562bfe3f2eSlogwang int socket_id; 7572bfe3f2eSlogwang struct rte_table_acl_params table_acl_params; 7582bfe3f2eSlogwang struct rte_flow_classify_table_params cls_table_params; 7592bfe3f2eSlogwang struct flow_classifier *cls_app; 7602bfe3f2eSlogwang struct rte_flow_classifier_params cls_params; 7612bfe3f2eSlogwang uint32_t size; 7622bfe3f2eSlogwang 7632bfe3f2eSlogwang /* Initialize the Environment Abstraction Layer (EAL). */ 7642bfe3f2eSlogwang ret = rte_eal_init(argc, argv); 7652bfe3f2eSlogwang if (ret < 0) 7662bfe3f2eSlogwang rte_exit(EXIT_FAILURE, "Error with EAL initialization\n"); 7672bfe3f2eSlogwang 7682bfe3f2eSlogwang argc -= ret; 7692bfe3f2eSlogwang argv += ret; 7702bfe3f2eSlogwang 7712bfe3f2eSlogwang /* parse application arguments (after the EAL ones) */ 7722bfe3f2eSlogwang ret = parse_args(argc, argv); 7732bfe3f2eSlogwang if (ret < 0) 7742bfe3f2eSlogwang rte_exit(EXIT_FAILURE, "Invalid flow_classify parameters\n"); 7752bfe3f2eSlogwang 7762bfe3f2eSlogwang /* Check that there is an even number of ports to send/receive on. */ 777*d30ea906Sjfb8856606 nb_ports = rte_eth_dev_count_avail(); 7782bfe3f2eSlogwang if (nb_ports < 2 || (nb_ports & 1)) 7792bfe3f2eSlogwang rte_exit(EXIT_FAILURE, "Error: number of ports must be even\n"); 7802bfe3f2eSlogwang 7812bfe3f2eSlogwang /* Creates a new mempool in memory to hold the mbufs. */ 7822bfe3f2eSlogwang mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", NUM_MBUFS * nb_ports, 7832bfe3f2eSlogwang MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id()); 7842bfe3f2eSlogwang 7852bfe3f2eSlogwang if (mbuf_pool == NULL) 7862bfe3f2eSlogwang rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n"); 7872bfe3f2eSlogwang 7882bfe3f2eSlogwang /* Initialize all ports. */ 789*d30ea906Sjfb8856606 RTE_ETH_FOREACH_DEV(portid) 7902bfe3f2eSlogwang if (port_init(portid, mbuf_pool) != 0) 7912bfe3f2eSlogwang rte_exit(EXIT_FAILURE, "Cannot init port %"PRIu8 "\n", 7922bfe3f2eSlogwang portid); 7932bfe3f2eSlogwang 7942bfe3f2eSlogwang if (rte_lcore_count() > 1) 7952bfe3f2eSlogwang printf("\nWARNING: Too many lcores enabled. Only 1 used.\n"); 7962bfe3f2eSlogwang 7972bfe3f2eSlogwang socket_id = rte_eth_dev_socket_id(0); 7982bfe3f2eSlogwang 7992bfe3f2eSlogwang /* Memory allocation */ 8002bfe3f2eSlogwang size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct flow_classifier_acl)); 8012bfe3f2eSlogwang cls_app = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE); 8022bfe3f2eSlogwang if (cls_app == NULL) 8032bfe3f2eSlogwang rte_exit(EXIT_FAILURE, "Cannot allocate classifier memory\n"); 8042bfe3f2eSlogwang 8052bfe3f2eSlogwang cls_params.name = "flow_classifier"; 8062bfe3f2eSlogwang cls_params.socket_id = socket_id; 8072bfe3f2eSlogwang 8082bfe3f2eSlogwang cls_app->cls = rte_flow_classifier_create(&cls_params); 8092bfe3f2eSlogwang if (cls_app->cls == NULL) { 8102bfe3f2eSlogwang rte_free(cls_app); 8112bfe3f2eSlogwang rte_exit(EXIT_FAILURE, "Cannot create classifier\n"); 8122bfe3f2eSlogwang } 8132bfe3f2eSlogwang 8142bfe3f2eSlogwang /* initialise ACL table params */ 8152bfe3f2eSlogwang table_acl_params.name = "table_acl_ipv4_5tuple"; 8162bfe3f2eSlogwang table_acl_params.n_rules = FLOW_CLASSIFY_MAX_RULE_NUM; 8172bfe3f2eSlogwang table_acl_params.n_rule_fields = RTE_DIM(ipv4_defs); 8182bfe3f2eSlogwang memcpy(table_acl_params.field_format, ipv4_defs, sizeof(ipv4_defs)); 8192bfe3f2eSlogwang 8202bfe3f2eSlogwang /* initialise table create params */ 821*d30ea906Sjfb8856606 cls_table_params.ops = &rte_table_acl_ops; 822*d30ea906Sjfb8856606 cls_table_params.arg_create = &table_acl_params; 823*d30ea906Sjfb8856606 cls_table_params.type = RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE; 8242bfe3f2eSlogwang 825*d30ea906Sjfb8856606 ret = rte_flow_classify_table_create(cls_app->cls, &cls_table_params); 8262bfe3f2eSlogwang if (ret) { 8272bfe3f2eSlogwang rte_flow_classifier_free(cls_app->cls); 8282bfe3f2eSlogwang rte_free(cls_app); 8292bfe3f2eSlogwang rte_exit(EXIT_FAILURE, "Failed to create classifier table\n"); 8302bfe3f2eSlogwang } 8312bfe3f2eSlogwang 8322bfe3f2eSlogwang /* read file of IPv4 5 tuple rules and initialize parameters 8332bfe3f2eSlogwang * for rte_flow_classify_validate and rte_flow_classify_table_entry_add 8342bfe3f2eSlogwang * API's. 8352bfe3f2eSlogwang */ 8362bfe3f2eSlogwang if (add_rules(parm_config.rule_ipv4_name, cls_app)) { 8372bfe3f2eSlogwang rte_flow_classifier_free(cls_app->cls); 8382bfe3f2eSlogwang rte_free(cls_app); 8392bfe3f2eSlogwang rte_exit(EXIT_FAILURE, "Failed to add rules\n"); 8402bfe3f2eSlogwang } 8412bfe3f2eSlogwang 8422bfe3f2eSlogwang /* Call lcore_main on the master core only. */ 8432bfe3f2eSlogwang lcore_main(cls_app); 8442bfe3f2eSlogwang 8452bfe3f2eSlogwang return 0; 8462bfe3f2eSlogwang } 847