1d30ea906Sjfb8856606 /* SPDX-License-Identifier: BSD-3-Clause
2d30ea906Sjfb8856606 * 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
18d30ea906Sjfb8856606 #define RX_RING_SIZE 1024
19d30ea906Sjfb8856606 #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 = {
63d30ea906Sjfb8856606 .rxmode = {
644418919fSjohnjiang .max_rx_pkt_len = RTE_ETHER_MAX_LEN,
65d30ea906Sjfb8856606 },
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,
1014418919fSjohnjiang .offset = sizeof(struct rte_ether_hdr) +
1024418919fSjohnjiang offsetof(struct rte_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,
1114418919fSjohnjiang .offset = sizeof(struct rte_ether_hdr) +
1124418919fSjohnjiang offsetof(struct rte_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,
1214418919fSjohnjiang .offset = sizeof(struct rte_ether_hdr) +
1224418919fSjohnjiang offsetof(struct rte_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,
1344418919fSjohnjiang .offset = sizeof(struct rte_ether_hdr) +
1354418919fSjohnjiang sizeof(struct rte_ipv4_hdr) +
1364418919fSjohnjiang offsetof(struct rte_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,
1444418919fSjohnjiang .offset = sizeof(struct rte_ether_hdr) +
1454418919fSjohnjiang sizeof(struct rte_ipv4_hdr) +
1464418919fSjohnjiang offsetof(struct rte_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 */
170d30ea906Sjfb8856606 struct rte_flow_query_count count = {
171d30ea906Sjfb8856606 .reset = 1,
172d30ea906Sjfb8856606 .hits_set = 1,
173d30ea906Sjfb8856606 .bytes_set = 1,
174d30ea906Sjfb8856606 .hits = 0,
175d30ea906Sjfb8856606 .bytes = 0,
176d30ea906Sjfb8856606 };
177d30ea906Sjfb8856606 static struct rte_flow_action count_action = { RTE_FLOW_ACTION_TYPE_COUNT,
178d30ea906Sjfb8856606 &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
port_init(uint8_t port,struct rte_mempool * mbuf_pool)1922bfe3f2eSlogwang port_init(uint8_t port, struct rte_mempool *mbuf_pool)
1932bfe3f2eSlogwang {
1942bfe3f2eSlogwang struct rte_eth_conf port_conf = port_conf_default;
1954418919fSjohnjiang struct rte_ether_addr addr;
1962bfe3f2eSlogwang const uint16_t rx_rings = 1, tx_rings = 1;
1972bfe3f2eSlogwang int retval;
1982bfe3f2eSlogwang uint16_t q;
199d30ea906Sjfb8856606 struct rte_eth_dev_info dev_info;
200d30ea906Sjfb8856606 struct rte_eth_txconf txconf;
2012bfe3f2eSlogwang
202d30ea906Sjfb8856606 if (!rte_eth_dev_is_valid_port(port))
2032bfe3f2eSlogwang return -1;
2042bfe3f2eSlogwang
2054418919fSjohnjiang retval = rte_eth_dev_info_get(port, &dev_info);
2064418919fSjohnjiang if (retval != 0) {
2074418919fSjohnjiang printf("Error during getting device (port %u) info: %s\n",
2084418919fSjohnjiang port, strerror(-retval));
2094418919fSjohnjiang return retval;
2104418919fSjohnjiang }
2114418919fSjohnjiang
212d30ea906Sjfb8856606 if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
213d30ea906Sjfb8856606 port_conf.txmode.offloads |=
214d30ea906Sjfb8856606 DEV_TX_OFFLOAD_MBUF_FAST_FREE;
215d30ea906Sjfb8856606
2162bfe3f2eSlogwang /* Configure the Ethernet device. */
2172bfe3f2eSlogwang retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf);
2182bfe3f2eSlogwang if (retval != 0)
2192bfe3f2eSlogwang return retval;
2202bfe3f2eSlogwang
2212bfe3f2eSlogwang /* Allocate and set up 1 RX queue per Ethernet port. */
2222bfe3f2eSlogwang for (q = 0; q < rx_rings; q++) {
2232bfe3f2eSlogwang retval = rte_eth_rx_queue_setup(port, q, RX_RING_SIZE,
2242bfe3f2eSlogwang rte_eth_dev_socket_id(port), NULL, mbuf_pool);
2252bfe3f2eSlogwang if (retval < 0)
2262bfe3f2eSlogwang return retval;
2272bfe3f2eSlogwang }
2282bfe3f2eSlogwang
229d30ea906Sjfb8856606 txconf = dev_info.default_txconf;
230d30ea906Sjfb8856606 txconf.offloads = port_conf.txmode.offloads;
2312bfe3f2eSlogwang /* Allocate and set up 1 TX queue per Ethernet port. */
2322bfe3f2eSlogwang for (q = 0; q < tx_rings; q++) {
2332bfe3f2eSlogwang retval = rte_eth_tx_queue_setup(port, q, TX_RING_SIZE,
234d30ea906Sjfb8856606 rte_eth_dev_socket_id(port), &txconf);
2352bfe3f2eSlogwang if (retval < 0)
2362bfe3f2eSlogwang return retval;
2372bfe3f2eSlogwang }
2382bfe3f2eSlogwang
2392bfe3f2eSlogwang /* Start the Ethernet port. */
2402bfe3f2eSlogwang retval = rte_eth_dev_start(port);
2412bfe3f2eSlogwang if (retval < 0)
2422bfe3f2eSlogwang return retval;
2432bfe3f2eSlogwang
2442bfe3f2eSlogwang /* Display the port MAC address. */
2454418919fSjohnjiang retval = rte_eth_macaddr_get(port, &addr);
2464418919fSjohnjiang if (retval != 0)
2474418919fSjohnjiang return retval;
2484418919fSjohnjiang
2492bfe3f2eSlogwang printf("Port %u MAC: %02" PRIx8 " %02" PRIx8 " %02" PRIx8
2502bfe3f2eSlogwang " %02" PRIx8 " %02" PRIx8 " %02" PRIx8 "\n",
2512bfe3f2eSlogwang port,
2522bfe3f2eSlogwang addr.addr_bytes[0], addr.addr_bytes[1],
2532bfe3f2eSlogwang addr.addr_bytes[2], addr.addr_bytes[3],
2542bfe3f2eSlogwang addr.addr_bytes[4], addr.addr_bytes[5]);
2552bfe3f2eSlogwang
2562bfe3f2eSlogwang /* Enable RX in promiscuous mode for the Ethernet device. */
2574418919fSjohnjiang retval = rte_eth_promiscuous_enable(port);
2584418919fSjohnjiang if (retval != 0)
2594418919fSjohnjiang return retval;
2602bfe3f2eSlogwang
2612bfe3f2eSlogwang return 0;
2622bfe3f2eSlogwang }
2632bfe3f2eSlogwang
2642bfe3f2eSlogwang /*
2652bfe3f2eSlogwang * The lcore main. This is the main thread that does the work, reading from
2662bfe3f2eSlogwang * an input port classifying the packets and writing to an output port.
2672bfe3f2eSlogwang */
268*2d9fd380Sjfb8856606 static __rte_noreturn void
lcore_main(struct flow_classifier * cls_app)2692bfe3f2eSlogwang lcore_main(struct flow_classifier *cls_app)
2702bfe3f2eSlogwang {
271d30ea906Sjfb8856606 uint16_t port;
2722bfe3f2eSlogwang int ret;
2732bfe3f2eSlogwang int i = 0;
2742bfe3f2eSlogwang
2752bfe3f2eSlogwang ret = rte_flow_classify_table_entry_delete(cls_app->cls,
276d30ea906Sjfb8856606 rules[7]);
2772bfe3f2eSlogwang if (ret)
2782bfe3f2eSlogwang printf("table_entry_delete failed [7] %d\n\n", ret);
2792bfe3f2eSlogwang else
2802bfe3f2eSlogwang printf("table_entry_delete succeeded [7]\n\n");
2812bfe3f2eSlogwang
2822bfe3f2eSlogwang /*
2832bfe3f2eSlogwang * Check that the port is on the same NUMA node as the polling thread
2842bfe3f2eSlogwang * for best performance.
2852bfe3f2eSlogwang */
286d30ea906Sjfb8856606 RTE_ETH_FOREACH_DEV(port)
2872bfe3f2eSlogwang if (rte_eth_dev_socket_id(port) > 0 &&
2882bfe3f2eSlogwang rte_eth_dev_socket_id(port) != (int)rte_socket_id()) {
2892bfe3f2eSlogwang printf("\n\n");
2902bfe3f2eSlogwang printf("WARNING: port %u is on remote NUMA node\n",
2912bfe3f2eSlogwang port);
2922bfe3f2eSlogwang printf("to polling thread.\n");
2932bfe3f2eSlogwang printf("Performance will not be optimal.\n");
2945af785ecSfengbojiang(姜凤波) }
295d30ea906Sjfb8856606 printf("\nCore %u forwarding packets. ", rte_lcore_id());
296d30ea906Sjfb8856606 printf("[Ctrl+C to quit]\n");
297d30ea906Sjfb8856606
2982bfe3f2eSlogwang /* Run until the application is quit or killed. */
2992bfe3f2eSlogwang for (;;) {
3002bfe3f2eSlogwang /*
3012bfe3f2eSlogwang * Receive packets on a port, classify them and forward them
3022bfe3f2eSlogwang * on the paired port.
3032bfe3f2eSlogwang * The mapping is 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2, etc.
3042bfe3f2eSlogwang */
305d30ea906Sjfb8856606 RTE_ETH_FOREACH_DEV(port) {
3062bfe3f2eSlogwang /* Get burst of RX packets, from first port of pair. */
3072bfe3f2eSlogwang struct rte_mbuf *bufs[BURST_SIZE];
3082bfe3f2eSlogwang const uint16_t nb_rx = rte_eth_rx_burst(port, 0,
3092bfe3f2eSlogwang bufs, BURST_SIZE);
3102bfe3f2eSlogwang
3112bfe3f2eSlogwang if (unlikely(nb_rx == 0))
3122bfe3f2eSlogwang continue;
3132bfe3f2eSlogwang
3142bfe3f2eSlogwang for (i = 0; i < MAX_NUM_CLASSIFY; i++) {
3152bfe3f2eSlogwang if (rules[i]) {
3162bfe3f2eSlogwang ret = rte_flow_classifier_query(
3172bfe3f2eSlogwang cls_app->cls,
3182bfe3f2eSlogwang bufs, nb_rx, rules[i],
3192bfe3f2eSlogwang &classify_stats);
3202bfe3f2eSlogwang if (ret)
3212bfe3f2eSlogwang printf(
3222bfe3f2eSlogwang "rule [%d] query failed ret [%d]\n\n",
3232bfe3f2eSlogwang i, ret);
3242bfe3f2eSlogwang else {
3252bfe3f2eSlogwang printf(
3262bfe3f2eSlogwang "rule[%d] count=%"PRIu64"\n",
3272bfe3f2eSlogwang i, ntuple_stats.counter1);
3282bfe3f2eSlogwang
3292bfe3f2eSlogwang printf("proto = %d\n",
3302bfe3f2eSlogwang ntuple_stats.ipv4_5tuple.proto);
3312bfe3f2eSlogwang }
3322bfe3f2eSlogwang }
3332bfe3f2eSlogwang }
3342bfe3f2eSlogwang
3352bfe3f2eSlogwang /* Send burst of TX packets, to second port of pair. */
3362bfe3f2eSlogwang const uint16_t nb_tx = rte_eth_tx_burst(port ^ 1, 0,
3372bfe3f2eSlogwang bufs, nb_rx);
3382bfe3f2eSlogwang
3392bfe3f2eSlogwang /* Free any unsent packets. */
3402bfe3f2eSlogwang if (unlikely(nb_tx < nb_rx)) {
3412bfe3f2eSlogwang uint16_t buf;
3422bfe3f2eSlogwang
3432bfe3f2eSlogwang for (buf = nb_tx; buf < nb_rx; buf++)
3442bfe3f2eSlogwang rte_pktmbuf_free(bufs[buf]);
3452bfe3f2eSlogwang }
3462bfe3f2eSlogwang }
3472bfe3f2eSlogwang }
3482bfe3f2eSlogwang }
3492bfe3f2eSlogwang
3502bfe3f2eSlogwang /*
3512bfe3f2eSlogwang * Parse IPv4 5 tuple rules file, ipv4_rules_file.txt.
3522bfe3f2eSlogwang * Expected format:
3532bfe3f2eSlogwang * <src_ipv4_addr>'/'<masklen> <space> \
3542bfe3f2eSlogwang * <dst_ipv4_addr>'/'<masklen> <space> \
3552bfe3f2eSlogwang * <src_port> <space> ":" <src_port_mask> <space> \
3562bfe3f2eSlogwang * <dst_port> <space> ":" <dst_port_mask> <space> \
3572bfe3f2eSlogwang * <proto>'/'<proto_mask> <space> \
3582bfe3f2eSlogwang * <priority>
3592bfe3f2eSlogwang */
3602bfe3f2eSlogwang
3612bfe3f2eSlogwang static int
get_cb_field(char ** in,uint32_t * fd,int base,unsigned long lim,char dlm)3622bfe3f2eSlogwang get_cb_field(char **in, uint32_t *fd, int base, unsigned long lim,
3632bfe3f2eSlogwang char dlm)
3642bfe3f2eSlogwang {
3652bfe3f2eSlogwang unsigned long val;
3662bfe3f2eSlogwang char *end;
3672bfe3f2eSlogwang
3682bfe3f2eSlogwang errno = 0;
3692bfe3f2eSlogwang val = strtoul(*in, &end, base);
3702bfe3f2eSlogwang if (errno != 0 || end[0] != dlm || val > lim)
3712bfe3f2eSlogwang return -EINVAL;
3722bfe3f2eSlogwang *fd = (uint32_t)val;
3732bfe3f2eSlogwang *in = end + 1;
3742bfe3f2eSlogwang return 0;
3752bfe3f2eSlogwang }
3762bfe3f2eSlogwang
3772bfe3f2eSlogwang static int
parse_ipv4_net(char * in,uint32_t * addr,uint32_t * mask_len)3782bfe3f2eSlogwang parse_ipv4_net(char *in, uint32_t *addr, uint32_t *mask_len)
3792bfe3f2eSlogwang {
3802bfe3f2eSlogwang uint32_t a, b, c, d, m;
3812bfe3f2eSlogwang
3822bfe3f2eSlogwang if (get_cb_field(&in, &a, 0, UINT8_MAX, '.'))
3832bfe3f2eSlogwang return -EINVAL;
3842bfe3f2eSlogwang if (get_cb_field(&in, &b, 0, UINT8_MAX, '.'))
3852bfe3f2eSlogwang return -EINVAL;
3862bfe3f2eSlogwang if (get_cb_field(&in, &c, 0, UINT8_MAX, '.'))
3872bfe3f2eSlogwang return -EINVAL;
3882bfe3f2eSlogwang if (get_cb_field(&in, &d, 0, UINT8_MAX, '/'))
3892bfe3f2eSlogwang return -EINVAL;
3902bfe3f2eSlogwang if (get_cb_field(&in, &m, 0, sizeof(uint32_t) * CHAR_BIT, 0))
3912bfe3f2eSlogwang return -EINVAL;
3922bfe3f2eSlogwang
3934418919fSjohnjiang addr[0] = RTE_IPV4(a, b, c, d);
3942bfe3f2eSlogwang mask_len[0] = m;
3952bfe3f2eSlogwang return 0;
3962bfe3f2eSlogwang }
3972bfe3f2eSlogwang
3982bfe3f2eSlogwang static int
parse_ipv4_5tuple_rule(char * str,struct rte_eth_ntuple_filter * ntuple_filter)3992bfe3f2eSlogwang parse_ipv4_5tuple_rule(char *str, struct rte_eth_ntuple_filter *ntuple_filter)
4002bfe3f2eSlogwang {
4012bfe3f2eSlogwang int i, ret;
4022bfe3f2eSlogwang char *s, *sp, *in[CB_FLD_NUM];
4032bfe3f2eSlogwang static const char *dlm = " \t\n";
4042bfe3f2eSlogwang int dim = CB_FLD_NUM;
4052bfe3f2eSlogwang uint32_t temp;
4062bfe3f2eSlogwang
4072bfe3f2eSlogwang s = str;
4082bfe3f2eSlogwang for (i = 0; i != dim; i++, s = NULL) {
4092bfe3f2eSlogwang in[i] = strtok_r(s, dlm, &sp);
4102bfe3f2eSlogwang if (in[i] == NULL)
4112bfe3f2eSlogwang return -EINVAL;
4122bfe3f2eSlogwang }
4132bfe3f2eSlogwang
4142bfe3f2eSlogwang ret = parse_ipv4_net(in[CB_FLD_SRC_ADDR],
4152bfe3f2eSlogwang &ntuple_filter->src_ip,
4162bfe3f2eSlogwang &ntuple_filter->src_ip_mask);
4172bfe3f2eSlogwang if (ret != 0) {
4182bfe3f2eSlogwang flow_classify_log("failed to read source address/mask: %s\n",
4192bfe3f2eSlogwang in[CB_FLD_SRC_ADDR]);
4202bfe3f2eSlogwang return ret;
4212bfe3f2eSlogwang }
4222bfe3f2eSlogwang
4232bfe3f2eSlogwang ret = parse_ipv4_net(in[CB_FLD_DST_ADDR],
4242bfe3f2eSlogwang &ntuple_filter->dst_ip,
4252bfe3f2eSlogwang &ntuple_filter->dst_ip_mask);
4262bfe3f2eSlogwang if (ret != 0) {
4272bfe3f2eSlogwang flow_classify_log("failed to read source address/mask: %s\n",
4282bfe3f2eSlogwang in[CB_FLD_DST_ADDR]);
4292bfe3f2eSlogwang return ret;
4302bfe3f2eSlogwang }
4312bfe3f2eSlogwang
4322bfe3f2eSlogwang if (get_cb_field(&in[CB_FLD_SRC_PORT], &temp, 0, UINT16_MAX, 0))
4332bfe3f2eSlogwang return -EINVAL;
4342bfe3f2eSlogwang ntuple_filter->src_port = (uint16_t)temp;
4352bfe3f2eSlogwang
4362bfe3f2eSlogwang if (strncmp(in[CB_FLD_SRC_PORT_DLM], cb_port_delim,
4372bfe3f2eSlogwang sizeof(cb_port_delim)) != 0)
4382bfe3f2eSlogwang return -EINVAL;
4392bfe3f2eSlogwang
4402bfe3f2eSlogwang if (get_cb_field(&in[CB_FLD_SRC_PORT_MASK], &temp, 0, UINT16_MAX, 0))
4412bfe3f2eSlogwang return -EINVAL;
4422bfe3f2eSlogwang ntuple_filter->src_port_mask = (uint16_t)temp;
4432bfe3f2eSlogwang
4442bfe3f2eSlogwang if (get_cb_field(&in[CB_FLD_DST_PORT], &temp, 0, UINT16_MAX, 0))
4452bfe3f2eSlogwang return -EINVAL;
4462bfe3f2eSlogwang ntuple_filter->dst_port = (uint16_t)temp;
4472bfe3f2eSlogwang
4482bfe3f2eSlogwang if (strncmp(in[CB_FLD_DST_PORT_DLM], cb_port_delim,
4492bfe3f2eSlogwang sizeof(cb_port_delim)) != 0)
4502bfe3f2eSlogwang return -EINVAL;
4512bfe3f2eSlogwang
4522bfe3f2eSlogwang if (get_cb_field(&in[CB_FLD_DST_PORT_MASK], &temp, 0, UINT16_MAX, 0))
4532bfe3f2eSlogwang return -EINVAL;
4542bfe3f2eSlogwang ntuple_filter->dst_port_mask = (uint16_t)temp;
4552bfe3f2eSlogwang
4562bfe3f2eSlogwang if (get_cb_field(&in[CB_FLD_PROTO], &temp, 0, UINT8_MAX, '/'))
4572bfe3f2eSlogwang return -EINVAL;
4582bfe3f2eSlogwang ntuple_filter->proto = (uint8_t)temp;
4592bfe3f2eSlogwang
4602bfe3f2eSlogwang if (get_cb_field(&in[CB_FLD_PROTO], &temp, 0, UINT8_MAX, 0))
4612bfe3f2eSlogwang return -EINVAL;
4622bfe3f2eSlogwang ntuple_filter->proto_mask = (uint8_t)temp;
4632bfe3f2eSlogwang
4642bfe3f2eSlogwang if (get_cb_field(&in[CB_FLD_PRIORITY], &temp, 0, UINT16_MAX, 0))
4652bfe3f2eSlogwang return -EINVAL;
4662bfe3f2eSlogwang ntuple_filter->priority = (uint16_t)temp;
4672bfe3f2eSlogwang if (ntuple_filter->priority > FLOW_CLASSIFY_MAX_PRIORITY)
4682bfe3f2eSlogwang ret = -EINVAL;
4692bfe3f2eSlogwang
4702bfe3f2eSlogwang return ret;
4712bfe3f2eSlogwang }
4722bfe3f2eSlogwang
4732bfe3f2eSlogwang /* Bypass comment and empty lines */
4742bfe3f2eSlogwang static inline int
is_bypass_line(char * buff)4752bfe3f2eSlogwang is_bypass_line(char *buff)
4762bfe3f2eSlogwang {
4772bfe3f2eSlogwang int i = 0;
4782bfe3f2eSlogwang
4792bfe3f2eSlogwang /* comment line */
4802bfe3f2eSlogwang if (buff[0] == COMMENT_LEAD_CHAR)
4812bfe3f2eSlogwang return 1;
4822bfe3f2eSlogwang /* empty line */
4832bfe3f2eSlogwang while (buff[i] != '\0') {
4842bfe3f2eSlogwang if (!isspace(buff[i]))
4852bfe3f2eSlogwang return 0;
4862bfe3f2eSlogwang i++;
4872bfe3f2eSlogwang }
4882bfe3f2eSlogwang return 1;
4892bfe3f2eSlogwang }
4902bfe3f2eSlogwang
4912bfe3f2eSlogwang static uint32_t
convert_depth_to_bitmask(uint32_t depth_val)4922bfe3f2eSlogwang convert_depth_to_bitmask(uint32_t depth_val)
4932bfe3f2eSlogwang {
4942bfe3f2eSlogwang uint32_t bitmask = 0;
4952bfe3f2eSlogwang int i, j;
4962bfe3f2eSlogwang
4972bfe3f2eSlogwang for (i = depth_val, j = 0; i > 0; i--, j++)
4982bfe3f2eSlogwang bitmask |= (1 << (31 - j));
4992bfe3f2eSlogwang return bitmask;
5002bfe3f2eSlogwang }
5012bfe3f2eSlogwang
5022bfe3f2eSlogwang static int
add_classify_rule(struct rte_eth_ntuple_filter * ntuple_filter,struct flow_classifier * cls_app)5032bfe3f2eSlogwang add_classify_rule(struct rte_eth_ntuple_filter *ntuple_filter,
5042bfe3f2eSlogwang struct flow_classifier *cls_app)
5052bfe3f2eSlogwang {
5062bfe3f2eSlogwang int ret = -1;
5072bfe3f2eSlogwang int key_found;
5082bfe3f2eSlogwang struct rte_flow_error error;
5092bfe3f2eSlogwang struct rte_flow_item_ipv4 ipv4_spec;
5102bfe3f2eSlogwang struct rte_flow_item_ipv4 ipv4_mask;
5112bfe3f2eSlogwang struct rte_flow_item ipv4_udp_item;
5122bfe3f2eSlogwang struct rte_flow_item ipv4_tcp_item;
5132bfe3f2eSlogwang struct rte_flow_item ipv4_sctp_item;
5142bfe3f2eSlogwang struct rte_flow_item_udp udp_spec;
5152bfe3f2eSlogwang struct rte_flow_item_udp udp_mask;
5162bfe3f2eSlogwang struct rte_flow_item udp_item;
5172bfe3f2eSlogwang struct rte_flow_item_tcp tcp_spec;
5182bfe3f2eSlogwang struct rte_flow_item_tcp tcp_mask;
5192bfe3f2eSlogwang struct rte_flow_item tcp_item;
5202bfe3f2eSlogwang struct rte_flow_item_sctp sctp_spec;
5212bfe3f2eSlogwang struct rte_flow_item_sctp sctp_mask;
5222bfe3f2eSlogwang struct rte_flow_item sctp_item;
5232bfe3f2eSlogwang struct rte_flow_item pattern_ipv4_5tuple[4];
5242bfe3f2eSlogwang struct rte_flow_classify_rule *rule;
5252bfe3f2eSlogwang uint8_t ipv4_proto;
5262bfe3f2eSlogwang
5272bfe3f2eSlogwang if (num_classify_rules >= MAX_NUM_CLASSIFY) {
5282bfe3f2eSlogwang printf(
5292bfe3f2eSlogwang "\nINFO: classify rule capacity %d reached\n",
5302bfe3f2eSlogwang num_classify_rules);
5312bfe3f2eSlogwang return ret;
5322bfe3f2eSlogwang }
5332bfe3f2eSlogwang
5342bfe3f2eSlogwang /* set up parameters for validate and add */
5352bfe3f2eSlogwang memset(&ipv4_spec, 0, sizeof(ipv4_spec));
5362bfe3f2eSlogwang ipv4_spec.hdr.next_proto_id = ntuple_filter->proto;
5372bfe3f2eSlogwang ipv4_spec.hdr.src_addr = ntuple_filter->src_ip;
5382bfe3f2eSlogwang ipv4_spec.hdr.dst_addr = ntuple_filter->dst_ip;
5392bfe3f2eSlogwang ipv4_proto = ipv4_spec.hdr.next_proto_id;
5402bfe3f2eSlogwang
5412bfe3f2eSlogwang memset(&ipv4_mask, 0, sizeof(ipv4_mask));
5422bfe3f2eSlogwang ipv4_mask.hdr.next_proto_id = ntuple_filter->proto_mask;
5432bfe3f2eSlogwang ipv4_mask.hdr.src_addr = ntuple_filter->src_ip_mask;
5442bfe3f2eSlogwang ipv4_mask.hdr.src_addr =
5452bfe3f2eSlogwang convert_depth_to_bitmask(ipv4_mask.hdr.src_addr);
5462bfe3f2eSlogwang ipv4_mask.hdr.dst_addr = ntuple_filter->dst_ip_mask;
5472bfe3f2eSlogwang ipv4_mask.hdr.dst_addr =
5482bfe3f2eSlogwang convert_depth_to_bitmask(ipv4_mask.hdr.dst_addr);
5492bfe3f2eSlogwang
5502bfe3f2eSlogwang switch (ipv4_proto) {
5512bfe3f2eSlogwang case IPPROTO_UDP:
5522bfe3f2eSlogwang ipv4_udp_item.type = RTE_FLOW_ITEM_TYPE_IPV4;
5532bfe3f2eSlogwang ipv4_udp_item.spec = &ipv4_spec;
5542bfe3f2eSlogwang ipv4_udp_item.mask = &ipv4_mask;
5552bfe3f2eSlogwang ipv4_udp_item.last = NULL;
5562bfe3f2eSlogwang
5572bfe3f2eSlogwang udp_spec.hdr.src_port = ntuple_filter->src_port;
5582bfe3f2eSlogwang udp_spec.hdr.dst_port = ntuple_filter->dst_port;
5592bfe3f2eSlogwang udp_spec.hdr.dgram_len = 0;
5602bfe3f2eSlogwang udp_spec.hdr.dgram_cksum = 0;
5612bfe3f2eSlogwang
5622bfe3f2eSlogwang udp_mask.hdr.src_port = ntuple_filter->src_port_mask;
5632bfe3f2eSlogwang udp_mask.hdr.dst_port = ntuple_filter->dst_port_mask;
5642bfe3f2eSlogwang udp_mask.hdr.dgram_len = 0;
5652bfe3f2eSlogwang udp_mask.hdr.dgram_cksum = 0;
5662bfe3f2eSlogwang
5672bfe3f2eSlogwang udp_item.type = RTE_FLOW_ITEM_TYPE_UDP;
5682bfe3f2eSlogwang udp_item.spec = &udp_spec;
5692bfe3f2eSlogwang udp_item.mask = &udp_mask;
5702bfe3f2eSlogwang udp_item.last = NULL;
5712bfe3f2eSlogwang
5722bfe3f2eSlogwang attr.priority = ntuple_filter->priority;
5732bfe3f2eSlogwang pattern_ipv4_5tuple[1] = ipv4_udp_item;
5742bfe3f2eSlogwang pattern_ipv4_5tuple[2] = udp_item;
5752bfe3f2eSlogwang break;
5762bfe3f2eSlogwang case IPPROTO_TCP:
5772bfe3f2eSlogwang ipv4_tcp_item.type = RTE_FLOW_ITEM_TYPE_IPV4;
5782bfe3f2eSlogwang ipv4_tcp_item.spec = &ipv4_spec;
5792bfe3f2eSlogwang ipv4_tcp_item.mask = &ipv4_mask;
5802bfe3f2eSlogwang ipv4_tcp_item.last = NULL;
5812bfe3f2eSlogwang
5822bfe3f2eSlogwang memset(&tcp_spec, 0, sizeof(tcp_spec));
5832bfe3f2eSlogwang tcp_spec.hdr.src_port = ntuple_filter->src_port;
5842bfe3f2eSlogwang tcp_spec.hdr.dst_port = ntuple_filter->dst_port;
5852bfe3f2eSlogwang
5862bfe3f2eSlogwang memset(&tcp_mask, 0, sizeof(tcp_mask));
5872bfe3f2eSlogwang tcp_mask.hdr.src_port = ntuple_filter->src_port_mask;
5882bfe3f2eSlogwang tcp_mask.hdr.dst_port = ntuple_filter->dst_port_mask;
5892bfe3f2eSlogwang
5902bfe3f2eSlogwang tcp_item.type = RTE_FLOW_ITEM_TYPE_TCP;
5912bfe3f2eSlogwang tcp_item.spec = &tcp_spec;
5922bfe3f2eSlogwang tcp_item.mask = &tcp_mask;
5932bfe3f2eSlogwang tcp_item.last = NULL;
5942bfe3f2eSlogwang
5952bfe3f2eSlogwang attr.priority = ntuple_filter->priority;
5962bfe3f2eSlogwang pattern_ipv4_5tuple[1] = ipv4_tcp_item;
5972bfe3f2eSlogwang pattern_ipv4_5tuple[2] = tcp_item;
5982bfe3f2eSlogwang break;
5992bfe3f2eSlogwang case IPPROTO_SCTP:
6002bfe3f2eSlogwang ipv4_sctp_item.type = RTE_FLOW_ITEM_TYPE_IPV4;
6012bfe3f2eSlogwang ipv4_sctp_item.spec = &ipv4_spec;
6022bfe3f2eSlogwang ipv4_sctp_item.mask = &ipv4_mask;
6032bfe3f2eSlogwang ipv4_sctp_item.last = NULL;
6042bfe3f2eSlogwang
6052bfe3f2eSlogwang sctp_spec.hdr.src_port = ntuple_filter->src_port;
6062bfe3f2eSlogwang sctp_spec.hdr.dst_port = ntuple_filter->dst_port;
6072bfe3f2eSlogwang sctp_spec.hdr.cksum = 0;
6082bfe3f2eSlogwang sctp_spec.hdr.tag = 0;
6092bfe3f2eSlogwang
6102bfe3f2eSlogwang sctp_mask.hdr.src_port = ntuple_filter->src_port_mask;
6112bfe3f2eSlogwang sctp_mask.hdr.dst_port = ntuple_filter->dst_port_mask;
6122bfe3f2eSlogwang sctp_mask.hdr.cksum = 0;
6132bfe3f2eSlogwang sctp_mask.hdr.tag = 0;
6142bfe3f2eSlogwang
6152bfe3f2eSlogwang sctp_item.type = RTE_FLOW_ITEM_TYPE_SCTP;
6162bfe3f2eSlogwang sctp_item.spec = &sctp_spec;
6172bfe3f2eSlogwang sctp_item.mask = &sctp_mask;
6182bfe3f2eSlogwang sctp_item.last = NULL;
6192bfe3f2eSlogwang
6202bfe3f2eSlogwang attr.priority = ntuple_filter->priority;
6212bfe3f2eSlogwang pattern_ipv4_5tuple[1] = ipv4_sctp_item;
6222bfe3f2eSlogwang pattern_ipv4_5tuple[2] = sctp_item;
6232bfe3f2eSlogwang break;
6242bfe3f2eSlogwang default:
6252bfe3f2eSlogwang return ret;
6262bfe3f2eSlogwang }
6272bfe3f2eSlogwang
6282bfe3f2eSlogwang attr.ingress = 1;
6292bfe3f2eSlogwang pattern_ipv4_5tuple[0] = eth_item;
6302bfe3f2eSlogwang pattern_ipv4_5tuple[3] = end_item;
6312bfe3f2eSlogwang actions[0] = count_action;
6322bfe3f2eSlogwang actions[1] = end_action;
6332bfe3f2eSlogwang
634d30ea906Sjfb8856606 /* Validate and add rule */
635d30ea906Sjfb8856606 ret = rte_flow_classify_validate(cls_app->cls, &attr,
636d30ea906Sjfb8856606 pattern_ipv4_5tuple, actions, &error);
637d30ea906Sjfb8856606 if (ret) {
638d30ea906Sjfb8856606 printf("table entry validate failed ipv4_proto = %u\n",
639d30ea906Sjfb8856606 ipv4_proto);
640d30ea906Sjfb8856606 return ret;
641d30ea906Sjfb8856606 }
642d30ea906Sjfb8856606
6432bfe3f2eSlogwang rule = rte_flow_classify_table_entry_add(
644d30ea906Sjfb8856606 cls_app->cls, &attr, pattern_ipv4_5tuple,
645d30ea906Sjfb8856606 actions, &key_found, &error);
6462bfe3f2eSlogwang if (rule == NULL) {
6472bfe3f2eSlogwang printf("table entry add failed ipv4_proto = %u\n",
6482bfe3f2eSlogwang ipv4_proto);
6492bfe3f2eSlogwang ret = -1;
6502bfe3f2eSlogwang return ret;
6512bfe3f2eSlogwang }
6522bfe3f2eSlogwang
6532bfe3f2eSlogwang rules[num_classify_rules] = rule;
6542bfe3f2eSlogwang num_classify_rules++;
6552bfe3f2eSlogwang return 0;
6562bfe3f2eSlogwang }
6572bfe3f2eSlogwang
6582bfe3f2eSlogwang static int
add_rules(const char * rule_path,struct flow_classifier * cls_app)6592bfe3f2eSlogwang add_rules(const char *rule_path, struct flow_classifier *cls_app)
6602bfe3f2eSlogwang {
6612bfe3f2eSlogwang FILE *fh;
6622bfe3f2eSlogwang char buff[LINE_MAX];
6632bfe3f2eSlogwang unsigned int i = 0;
6642bfe3f2eSlogwang unsigned int total_num = 0;
6652bfe3f2eSlogwang struct rte_eth_ntuple_filter ntuple_filter;
6662bfe3f2eSlogwang int ret;
6672bfe3f2eSlogwang
6682bfe3f2eSlogwang fh = fopen(rule_path, "rb");
6692bfe3f2eSlogwang if (fh == NULL)
6702bfe3f2eSlogwang rte_exit(EXIT_FAILURE, "%s: fopen %s failed\n", __func__,
6712bfe3f2eSlogwang rule_path);
6722bfe3f2eSlogwang
6732bfe3f2eSlogwang ret = fseek(fh, 0, SEEK_SET);
6742bfe3f2eSlogwang if (ret)
6752bfe3f2eSlogwang rte_exit(EXIT_FAILURE, "%s: fseek %d failed\n", __func__,
6762bfe3f2eSlogwang ret);
6772bfe3f2eSlogwang
6782bfe3f2eSlogwang i = 0;
6792bfe3f2eSlogwang while (fgets(buff, LINE_MAX, fh) != NULL) {
6802bfe3f2eSlogwang i++;
6812bfe3f2eSlogwang
6822bfe3f2eSlogwang if (is_bypass_line(buff))
6832bfe3f2eSlogwang continue;
6842bfe3f2eSlogwang
6852bfe3f2eSlogwang if (total_num >= FLOW_CLASSIFY_MAX_RULE_NUM - 1) {
6862bfe3f2eSlogwang printf("\nINFO: classify rule capacity %d reached\n",
6872bfe3f2eSlogwang total_num);
6882bfe3f2eSlogwang break;
6892bfe3f2eSlogwang }
6902bfe3f2eSlogwang
6912bfe3f2eSlogwang if (parse_ipv4_5tuple_rule(buff, &ntuple_filter) != 0)
6922bfe3f2eSlogwang rte_exit(EXIT_FAILURE,
6932bfe3f2eSlogwang "%s Line %u: parse rules error\n",
6942bfe3f2eSlogwang rule_path, i);
6952bfe3f2eSlogwang
6962bfe3f2eSlogwang if (add_classify_rule(&ntuple_filter, cls_app) != 0)
6972bfe3f2eSlogwang rte_exit(EXIT_FAILURE, "add rule error\n");
6982bfe3f2eSlogwang
6992bfe3f2eSlogwang total_num++;
7002bfe3f2eSlogwang }
7012bfe3f2eSlogwang
7022bfe3f2eSlogwang fclose(fh);
7032bfe3f2eSlogwang return 0;
7042bfe3f2eSlogwang }
7052bfe3f2eSlogwang
7062bfe3f2eSlogwang /* display usage */
7072bfe3f2eSlogwang static void
print_usage(const char * prgname)7082bfe3f2eSlogwang print_usage(const char *prgname)
7092bfe3f2eSlogwang {
7102bfe3f2eSlogwang printf("%s usage:\n", prgname);
7112bfe3f2eSlogwang printf("[EAL options] -- --"OPTION_RULE_IPV4"=FILE: ");
7122bfe3f2eSlogwang printf("specify the ipv4 rules file.\n");
7132bfe3f2eSlogwang printf("Each rule occupies one line in the file.\n");
7142bfe3f2eSlogwang }
7152bfe3f2eSlogwang
7162bfe3f2eSlogwang /* Parse the argument given in the command line of the application */
7172bfe3f2eSlogwang static int
parse_args(int argc,char ** argv)7182bfe3f2eSlogwang parse_args(int argc, char **argv)
7192bfe3f2eSlogwang {
7202bfe3f2eSlogwang int opt, ret;
7212bfe3f2eSlogwang char **argvopt;
7222bfe3f2eSlogwang int option_index;
7232bfe3f2eSlogwang char *prgname = argv[0];
7242bfe3f2eSlogwang static struct option lgopts[] = {
7252bfe3f2eSlogwang {OPTION_RULE_IPV4, 1, 0, 0},
7262bfe3f2eSlogwang {NULL, 0, 0, 0}
7272bfe3f2eSlogwang };
7282bfe3f2eSlogwang
7292bfe3f2eSlogwang argvopt = argv;
7302bfe3f2eSlogwang
7312bfe3f2eSlogwang while ((opt = getopt_long(argc, argvopt, "",
7322bfe3f2eSlogwang lgopts, &option_index)) != EOF) {
7332bfe3f2eSlogwang
7342bfe3f2eSlogwang switch (opt) {
7352bfe3f2eSlogwang /* long options */
7362bfe3f2eSlogwang case 0:
7372bfe3f2eSlogwang if (!strncmp(lgopts[option_index].name,
7382bfe3f2eSlogwang OPTION_RULE_IPV4,
7392bfe3f2eSlogwang sizeof(OPTION_RULE_IPV4)))
7402bfe3f2eSlogwang parm_config.rule_ipv4_name = optarg;
7412bfe3f2eSlogwang break;
7422bfe3f2eSlogwang default:
7432bfe3f2eSlogwang print_usage(prgname);
7442bfe3f2eSlogwang return -1;
7452bfe3f2eSlogwang }
7462bfe3f2eSlogwang }
7472bfe3f2eSlogwang
7482bfe3f2eSlogwang if (optind >= 0)
7492bfe3f2eSlogwang argv[optind-1] = prgname;
7502bfe3f2eSlogwang
7512bfe3f2eSlogwang ret = optind-1;
7522bfe3f2eSlogwang optind = 1; /* reset getopt lib */
7532bfe3f2eSlogwang return ret;
7542bfe3f2eSlogwang }
7552bfe3f2eSlogwang
7562bfe3f2eSlogwang /*
7572bfe3f2eSlogwang * The main function, which does initialization and calls the lcore_main
7582bfe3f2eSlogwang * function.
7592bfe3f2eSlogwang */
7602bfe3f2eSlogwang int
main(int argc,char * argv[])7612bfe3f2eSlogwang main(int argc, char *argv[])
7622bfe3f2eSlogwang {
7632bfe3f2eSlogwang struct rte_mempool *mbuf_pool;
764d30ea906Sjfb8856606 uint16_t nb_ports;
765d30ea906Sjfb8856606 uint16_t portid;
7662bfe3f2eSlogwang int ret;
7672bfe3f2eSlogwang int socket_id;
7682bfe3f2eSlogwang struct rte_table_acl_params table_acl_params;
7692bfe3f2eSlogwang struct rte_flow_classify_table_params cls_table_params;
7702bfe3f2eSlogwang struct flow_classifier *cls_app;
7712bfe3f2eSlogwang struct rte_flow_classifier_params cls_params;
7722bfe3f2eSlogwang uint32_t size;
7732bfe3f2eSlogwang
7742bfe3f2eSlogwang /* Initialize the Environment Abstraction Layer (EAL). */
7752bfe3f2eSlogwang ret = rte_eal_init(argc, argv);
7762bfe3f2eSlogwang if (ret < 0)
7772bfe3f2eSlogwang rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
7782bfe3f2eSlogwang
7792bfe3f2eSlogwang argc -= ret;
7802bfe3f2eSlogwang argv += ret;
7812bfe3f2eSlogwang
7822bfe3f2eSlogwang /* parse application arguments (after the EAL ones) */
7832bfe3f2eSlogwang ret = parse_args(argc, argv);
7842bfe3f2eSlogwang if (ret < 0)
7852bfe3f2eSlogwang rte_exit(EXIT_FAILURE, "Invalid flow_classify parameters\n");
7862bfe3f2eSlogwang
7872bfe3f2eSlogwang /* Check that there is an even number of ports to send/receive on. */
788d30ea906Sjfb8856606 nb_ports = rte_eth_dev_count_avail();
7892bfe3f2eSlogwang if (nb_ports < 2 || (nb_ports & 1))
7902bfe3f2eSlogwang rte_exit(EXIT_FAILURE, "Error: number of ports must be even\n");
7912bfe3f2eSlogwang
7922bfe3f2eSlogwang /* Creates a new mempool in memory to hold the mbufs. */
7932bfe3f2eSlogwang mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", NUM_MBUFS * nb_ports,
7942bfe3f2eSlogwang MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
7952bfe3f2eSlogwang
7962bfe3f2eSlogwang if (mbuf_pool == NULL)
7972bfe3f2eSlogwang rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
7982bfe3f2eSlogwang
7992bfe3f2eSlogwang /* Initialize all ports. */
800d30ea906Sjfb8856606 RTE_ETH_FOREACH_DEV(portid)
8012bfe3f2eSlogwang if (port_init(portid, mbuf_pool) != 0)
8022bfe3f2eSlogwang rte_exit(EXIT_FAILURE, "Cannot init port %"PRIu8 "\n",
8032bfe3f2eSlogwang portid);
8042bfe3f2eSlogwang
8052bfe3f2eSlogwang if (rte_lcore_count() > 1)
8062bfe3f2eSlogwang printf("\nWARNING: Too many lcores enabled. Only 1 used.\n");
8072bfe3f2eSlogwang
8082bfe3f2eSlogwang socket_id = rte_eth_dev_socket_id(0);
8092bfe3f2eSlogwang
8102bfe3f2eSlogwang /* Memory allocation */
8112bfe3f2eSlogwang size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct flow_classifier_acl));
8122bfe3f2eSlogwang cls_app = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
8132bfe3f2eSlogwang if (cls_app == NULL)
8142bfe3f2eSlogwang rte_exit(EXIT_FAILURE, "Cannot allocate classifier memory\n");
8152bfe3f2eSlogwang
8162bfe3f2eSlogwang cls_params.name = "flow_classifier";
8172bfe3f2eSlogwang cls_params.socket_id = socket_id;
8182bfe3f2eSlogwang
8192bfe3f2eSlogwang cls_app->cls = rte_flow_classifier_create(&cls_params);
8202bfe3f2eSlogwang if (cls_app->cls == NULL) {
8212bfe3f2eSlogwang rte_free(cls_app);
8222bfe3f2eSlogwang rte_exit(EXIT_FAILURE, "Cannot create classifier\n");
8232bfe3f2eSlogwang }
8242bfe3f2eSlogwang
8252bfe3f2eSlogwang /* initialise ACL table params */
8262bfe3f2eSlogwang table_acl_params.name = "table_acl_ipv4_5tuple";
8272bfe3f2eSlogwang table_acl_params.n_rules = FLOW_CLASSIFY_MAX_RULE_NUM;
8282bfe3f2eSlogwang table_acl_params.n_rule_fields = RTE_DIM(ipv4_defs);
8292bfe3f2eSlogwang memcpy(table_acl_params.field_format, ipv4_defs, sizeof(ipv4_defs));
8302bfe3f2eSlogwang
8312bfe3f2eSlogwang /* initialise table create params */
832d30ea906Sjfb8856606 cls_table_params.ops = &rte_table_acl_ops;
833d30ea906Sjfb8856606 cls_table_params.arg_create = &table_acl_params;
834d30ea906Sjfb8856606 cls_table_params.type = RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE;
8352bfe3f2eSlogwang
836d30ea906Sjfb8856606 ret = rte_flow_classify_table_create(cls_app->cls, &cls_table_params);
8372bfe3f2eSlogwang if (ret) {
8382bfe3f2eSlogwang rte_flow_classifier_free(cls_app->cls);
8392bfe3f2eSlogwang rte_free(cls_app);
8402bfe3f2eSlogwang rte_exit(EXIT_FAILURE, "Failed to create classifier table\n");
8412bfe3f2eSlogwang }
8422bfe3f2eSlogwang
8432bfe3f2eSlogwang /* read file of IPv4 5 tuple rules and initialize parameters
8442bfe3f2eSlogwang * for rte_flow_classify_validate and rte_flow_classify_table_entry_add
8452bfe3f2eSlogwang * API's.
8462bfe3f2eSlogwang */
8472bfe3f2eSlogwang if (add_rules(parm_config.rule_ipv4_name, cls_app)) {
8482bfe3f2eSlogwang rte_flow_classifier_free(cls_app->cls);
8492bfe3f2eSlogwang rte_free(cls_app);
8502bfe3f2eSlogwang rte_exit(EXIT_FAILURE, "Failed to add rules\n");
8512bfe3f2eSlogwang }
8522bfe3f2eSlogwang
853*2d9fd380Sjfb8856606 /* Call lcore_main on the main core only. */
8542bfe3f2eSlogwang lcore_main(cls_app);
8552bfe3f2eSlogwang
8562bfe3f2eSlogwang return 0;
8572bfe3f2eSlogwang }
858