1bab16ddaSBernard Iremonger /*- 2bab16ddaSBernard Iremonger * BSD LICENSE 3bab16ddaSBernard Iremonger * 4bab16ddaSBernard Iremonger * Copyright(c) 2017 Intel Corporation. All rights reserved. 5bab16ddaSBernard Iremonger * All rights reserved. 6bab16ddaSBernard Iremonger * 7bab16ddaSBernard Iremonger * Redistribution and use in source and binary forms, with or without 8bab16ddaSBernard Iremonger * modification, are permitted provided that the following conditions 9bab16ddaSBernard Iremonger * are met: 10bab16ddaSBernard Iremonger * 11bab16ddaSBernard Iremonger * * Redistributions of source code must retain the above copyright 12bab16ddaSBernard Iremonger * notice, this list of conditions and the following disclaimer. 13bab16ddaSBernard Iremonger * * Redistributions in binary form must reproduce the above copyright 14bab16ddaSBernard Iremonger * notice, this list of conditions and the following disclaimer in 15bab16ddaSBernard Iremonger * the documentation and/or other materials provided with the 16bab16ddaSBernard Iremonger * distribution. 17bab16ddaSBernard Iremonger * * Neither the name of Intel Corporation nor the names of its 18bab16ddaSBernard Iremonger * contributors may be used to endorse or promote products derived 19bab16ddaSBernard Iremonger * from this software without specific prior written permission. 20bab16ddaSBernard Iremonger * 21bab16ddaSBernard Iremonger * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22bab16ddaSBernard Iremonger * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23bab16ddaSBernard Iremonger * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24bab16ddaSBernard Iremonger * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25bab16ddaSBernard Iremonger * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26bab16ddaSBernard Iremonger * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27bab16ddaSBernard Iremonger * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28bab16ddaSBernard Iremonger * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29bab16ddaSBernard Iremonger * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30bab16ddaSBernard Iremonger * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31bab16ddaSBernard Iremonger * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32bab16ddaSBernard Iremonger */ 33bab16ddaSBernard Iremonger 34bab16ddaSBernard Iremonger #include <stdint.h> 35bab16ddaSBernard Iremonger #include <inttypes.h> 36bab16ddaSBernard Iremonger #include <getopt.h> 37bab16ddaSBernard Iremonger 38bab16ddaSBernard Iremonger #include <rte_eal.h> 39bab16ddaSBernard Iremonger #include <rte_ethdev.h> 40bab16ddaSBernard Iremonger #include <rte_cycles.h> 41bab16ddaSBernard Iremonger #include <rte_lcore.h> 42bab16ddaSBernard Iremonger #include <rte_mbuf.h> 43bab16ddaSBernard Iremonger #include <rte_flow.h> 44bab16ddaSBernard Iremonger #include <rte_flow_classify.h> 45bab16ddaSBernard Iremonger #include <rte_table_acl.h> 46bab16ddaSBernard Iremonger 47bab16ddaSBernard Iremonger #define RX_RING_SIZE 128 48bab16ddaSBernard Iremonger #define TX_RING_SIZE 512 49bab16ddaSBernard Iremonger 50bab16ddaSBernard Iremonger #define NUM_MBUFS 8191 51bab16ddaSBernard Iremonger #define MBUF_CACHE_SIZE 250 52bab16ddaSBernard Iremonger #define BURST_SIZE 32 53bab16ddaSBernard Iremonger 54bab16ddaSBernard Iremonger #define MAX_NUM_CLASSIFY 30 55bab16ddaSBernard Iremonger #define FLOW_CLASSIFY_MAX_RULE_NUM 91 56bab16ddaSBernard Iremonger #define FLOW_CLASSIFY_MAX_PRIORITY 8 57bab16ddaSBernard Iremonger #define FLOW_CLASSIFIER_NAME_SIZE 64 58bab16ddaSBernard Iremonger 59bab16ddaSBernard Iremonger #define COMMENT_LEAD_CHAR ('#') 60bab16ddaSBernard Iremonger #define OPTION_RULE_IPV4 "rule_ipv4" 61bab16ddaSBernard Iremonger #define RTE_LOGTYPE_FLOW_CLASSIFY RTE_LOGTYPE_USER3 62bab16ddaSBernard Iremonger #define flow_classify_log(format, ...) \ 63bab16ddaSBernard Iremonger RTE_LOG(ERR, FLOW_CLASSIFY, format, ##__VA_ARGS__) 64bab16ddaSBernard Iremonger 65bab16ddaSBernard Iremonger #define uint32_t_to_char(ip, a, b, c, d) do {\ 66bab16ddaSBernard Iremonger *a = (unsigned char)(ip >> 24 & 0xff);\ 67bab16ddaSBernard Iremonger *b = (unsigned char)(ip >> 16 & 0xff);\ 68bab16ddaSBernard Iremonger *c = (unsigned char)(ip >> 8 & 0xff);\ 69bab16ddaSBernard Iremonger *d = (unsigned char)(ip & 0xff);\ 70bab16ddaSBernard Iremonger } while (0) 71bab16ddaSBernard Iremonger 72bab16ddaSBernard Iremonger enum { 73bab16ddaSBernard Iremonger CB_FLD_SRC_ADDR, 74bab16ddaSBernard Iremonger CB_FLD_DST_ADDR, 75bab16ddaSBernard Iremonger CB_FLD_SRC_PORT, 76bab16ddaSBernard Iremonger CB_FLD_SRC_PORT_DLM, 77bab16ddaSBernard Iremonger CB_FLD_SRC_PORT_MASK, 78bab16ddaSBernard Iremonger CB_FLD_DST_PORT, 79bab16ddaSBernard Iremonger CB_FLD_DST_PORT_DLM, 80bab16ddaSBernard Iremonger CB_FLD_DST_PORT_MASK, 81bab16ddaSBernard Iremonger CB_FLD_PROTO, 82bab16ddaSBernard Iremonger CB_FLD_PRIORITY, 83bab16ddaSBernard Iremonger CB_FLD_NUM, 84bab16ddaSBernard Iremonger }; 85bab16ddaSBernard Iremonger 86bab16ddaSBernard Iremonger static struct{ 87bab16ddaSBernard Iremonger const char *rule_ipv4_name; 88bab16ddaSBernard Iremonger } parm_config; 89bab16ddaSBernard Iremonger const char cb_port_delim[] = ":"; 90bab16ddaSBernard Iremonger 91bab16ddaSBernard Iremonger static const struct rte_eth_conf port_conf_default = { 92bab16ddaSBernard Iremonger .rxmode = { .max_rx_pkt_len = ETHER_MAX_LEN } 93bab16ddaSBernard Iremonger }; 94bab16ddaSBernard Iremonger 95bab16ddaSBernard Iremonger struct flow_classifier { 96bab16ddaSBernard Iremonger struct rte_flow_classifier *cls; 97bab16ddaSBernard Iremonger uint32_t table_id[RTE_FLOW_CLASSIFY_TABLE_MAX]; 98bab16ddaSBernard Iremonger }; 99bab16ddaSBernard Iremonger 100bab16ddaSBernard Iremonger struct flow_classifier_acl { 101bab16ddaSBernard Iremonger struct flow_classifier cls; 102bab16ddaSBernard Iremonger } __rte_cache_aligned; 103bab16ddaSBernard Iremonger 104bab16ddaSBernard Iremonger /* ACL field definitions for IPv4 5 tuple rule */ 105bab16ddaSBernard Iremonger 106bab16ddaSBernard Iremonger enum { 107bab16ddaSBernard Iremonger PROTO_FIELD_IPV4, 108bab16ddaSBernard Iremonger SRC_FIELD_IPV4, 109bab16ddaSBernard Iremonger DST_FIELD_IPV4, 110bab16ddaSBernard Iremonger SRCP_FIELD_IPV4, 111bab16ddaSBernard Iremonger DSTP_FIELD_IPV4, 112bab16ddaSBernard Iremonger NUM_FIELDS_IPV4 113bab16ddaSBernard Iremonger }; 114bab16ddaSBernard Iremonger 115bab16ddaSBernard Iremonger enum { 116bab16ddaSBernard Iremonger PROTO_INPUT_IPV4, 117bab16ddaSBernard Iremonger SRC_INPUT_IPV4, 118bab16ddaSBernard Iremonger DST_INPUT_IPV4, 119bab16ddaSBernard Iremonger SRCP_DESTP_INPUT_IPV4 120bab16ddaSBernard Iremonger }; 121bab16ddaSBernard Iremonger 122bab16ddaSBernard Iremonger static struct rte_acl_field_def ipv4_defs[NUM_FIELDS_IPV4] = { 123bab16ddaSBernard Iremonger /* first input field - always one byte long. */ 124bab16ddaSBernard Iremonger { 125bab16ddaSBernard Iremonger .type = RTE_ACL_FIELD_TYPE_BITMASK, 126bab16ddaSBernard Iremonger .size = sizeof(uint8_t), 127bab16ddaSBernard Iremonger .field_index = PROTO_FIELD_IPV4, 128bab16ddaSBernard Iremonger .input_index = PROTO_INPUT_IPV4, 129bab16ddaSBernard Iremonger .offset = sizeof(struct ether_hdr) + 130bab16ddaSBernard Iremonger offsetof(struct ipv4_hdr, next_proto_id), 131bab16ddaSBernard Iremonger }, 132bab16ddaSBernard Iremonger /* next input field (IPv4 source address) - 4 consecutive bytes. */ 133bab16ddaSBernard Iremonger { 134bab16ddaSBernard Iremonger /* rte_flow uses a bit mask for IPv4 addresses */ 135bab16ddaSBernard Iremonger .type = RTE_ACL_FIELD_TYPE_BITMASK, 136bab16ddaSBernard Iremonger .size = sizeof(uint32_t), 137bab16ddaSBernard Iremonger .field_index = SRC_FIELD_IPV4, 138bab16ddaSBernard Iremonger .input_index = SRC_INPUT_IPV4, 139bab16ddaSBernard Iremonger .offset = sizeof(struct ether_hdr) + 140bab16ddaSBernard Iremonger offsetof(struct ipv4_hdr, src_addr), 141bab16ddaSBernard Iremonger }, 142bab16ddaSBernard Iremonger /* next input field (IPv4 destination address) - 4 consecutive bytes. */ 143bab16ddaSBernard Iremonger { 144bab16ddaSBernard Iremonger /* rte_flow uses a bit mask for IPv4 addresses */ 145bab16ddaSBernard Iremonger .type = RTE_ACL_FIELD_TYPE_BITMASK, 146bab16ddaSBernard Iremonger .size = sizeof(uint32_t), 147bab16ddaSBernard Iremonger .field_index = DST_FIELD_IPV4, 148bab16ddaSBernard Iremonger .input_index = DST_INPUT_IPV4, 149bab16ddaSBernard Iremonger .offset = sizeof(struct ether_hdr) + 150bab16ddaSBernard Iremonger offsetof(struct ipv4_hdr, dst_addr), 151bab16ddaSBernard Iremonger }, 152bab16ddaSBernard Iremonger /* 153bab16ddaSBernard Iremonger * Next 2 fields (src & dst ports) form 4 consecutive bytes. 154bab16ddaSBernard Iremonger * They share the same input index. 155bab16ddaSBernard Iremonger */ 156bab16ddaSBernard Iremonger { 157bab16ddaSBernard Iremonger /* rte_flow uses a bit mask for protocol ports */ 158bab16ddaSBernard Iremonger .type = RTE_ACL_FIELD_TYPE_BITMASK, 159bab16ddaSBernard Iremonger .size = sizeof(uint16_t), 160bab16ddaSBernard Iremonger .field_index = SRCP_FIELD_IPV4, 161bab16ddaSBernard Iremonger .input_index = SRCP_DESTP_INPUT_IPV4, 162bab16ddaSBernard Iremonger .offset = sizeof(struct ether_hdr) + 163bab16ddaSBernard Iremonger sizeof(struct ipv4_hdr) + 164bab16ddaSBernard Iremonger offsetof(struct tcp_hdr, src_port), 165bab16ddaSBernard Iremonger }, 166bab16ddaSBernard Iremonger { 167bab16ddaSBernard Iremonger /* rte_flow uses a bit mask for protocol ports */ 168bab16ddaSBernard Iremonger .type = RTE_ACL_FIELD_TYPE_BITMASK, 169bab16ddaSBernard Iremonger .size = sizeof(uint16_t), 170bab16ddaSBernard Iremonger .field_index = DSTP_FIELD_IPV4, 171bab16ddaSBernard Iremonger .input_index = SRCP_DESTP_INPUT_IPV4, 172bab16ddaSBernard Iremonger .offset = sizeof(struct ether_hdr) + 173bab16ddaSBernard Iremonger sizeof(struct ipv4_hdr) + 174bab16ddaSBernard Iremonger offsetof(struct tcp_hdr, dst_port), 175bab16ddaSBernard Iremonger }, 176bab16ddaSBernard Iremonger }; 177bab16ddaSBernard Iremonger 178bab16ddaSBernard Iremonger /* flow classify data */ 179bab16ddaSBernard Iremonger static int num_classify_rules; 180bab16ddaSBernard Iremonger static struct rte_flow_classify_rule *rules[MAX_NUM_CLASSIFY]; 181bab16ddaSBernard Iremonger static struct rte_flow_classify_ipv4_5tuple_stats ntuple_stats; 182bab16ddaSBernard Iremonger static struct rte_flow_classify_stats classify_stats = { 183bab16ddaSBernard Iremonger .stats = (void **)&ntuple_stats 184bab16ddaSBernard Iremonger }; 185bab16ddaSBernard Iremonger 186bab16ddaSBernard Iremonger /* parameters for rte_flow_classify_validate and 187bab16ddaSBernard Iremonger * rte_flow_classify_table_entry_add functions 188bab16ddaSBernard Iremonger */ 189bab16ddaSBernard Iremonger 190bab16ddaSBernard Iremonger static struct rte_flow_item eth_item = { RTE_FLOW_ITEM_TYPE_ETH, 191bab16ddaSBernard Iremonger 0, 0, 0 }; 192bab16ddaSBernard Iremonger static struct rte_flow_item end_item = { RTE_FLOW_ITEM_TYPE_END, 193bab16ddaSBernard Iremonger 0, 0, 0 }; 194bab16ddaSBernard Iremonger 195bab16ddaSBernard Iremonger /* sample actions: 196bab16ddaSBernard Iremonger * "actions count / end" 197bab16ddaSBernard Iremonger */ 198bab16ddaSBernard Iremonger static struct rte_flow_action count_action = { RTE_FLOW_ACTION_TYPE_COUNT, 0}; 199bab16ddaSBernard Iremonger static struct rte_flow_action end_action = { RTE_FLOW_ACTION_TYPE_END, 0}; 200bab16ddaSBernard Iremonger static struct rte_flow_action actions[2]; 201bab16ddaSBernard Iremonger 202bab16ddaSBernard Iremonger /* sample attributes */ 203bab16ddaSBernard Iremonger static struct rte_flow_attr attr; 204bab16ddaSBernard Iremonger 205bab16ddaSBernard Iremonger /* flow_classify.c: * Based on DPDK skeleton forwarding example. */ 206bab16ddaSBernard Iremonger 207bab16ddaSBernard Iremonger /* 208bab16ddaSBernard Iremonger * Initializes a given port using global settings and with the RX buffers 209bab16ddaSBernard Iremonger * coming from the mbuf_pool passed as a parameter. 210bab16ddaSBernard Iremonger */ 211bab16ddaSBernard Iremonger static inline int 212bab16ddaSBernard Iremonger port_init(uint8_t port, struct rte_mempool *mbuf_pool) 213bab16ddaSBernard Iremonger { 214bab16ddaSBernard Iremonger struct rte_eth_conf port_conf = port_conf_default; 215bab16ddaSBernard Iremonger struct ether_addr addr; 216bab16ddaSBernard Iremonger const uint16_t rx_rings = 1, tx_rings = 1; 217bab16ddaSBernard Iremonger int retval; 218bab16ddaSBernard Iremonger uint16_t q; 219bab16ddaSBernard Iremonger 220bab16ddaSBernard Iremonger if (port >= rte_eth_dev_count()) 221bab16ddaSBernard Iremonger return -1; 222bab16ddaSBernard Iremonger 223bab16ddaSBernard Iremonger /* Configure the Ethernet device. */ 224bab16ddaSBernard Iremonger retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf); 225bab16ddaSBernard Iremonger if (retval != 0) 226bab16ddaSBernard Iremonger return retval; 227bab16ddaSBernard Iremonger 228bab16ddaSBernard Iremonger /* Allocate and set up 1 RX queue per Ethernet port. */ 229bab16ddaSBernard Iremonger for (q = 0; q < rx_rings; q++) { 230bab16ddaSBernard Iremonger retval = rte_eth_rx_queue_setup(port, q, RX_RING_SIZE, 231bab16ddaSBernard Iremonger rte_eth_dev_socket_id(port), NULL, mbuf_pool); 232bab16ddaSBernard Iremonger if (retval < 0) 233bab16ddaSBernard Iremonger return retval; 234bab16ddaSBernard Iremonger } 235bab16ddaSBernard Iremonger 236bab16ddaSBernard Iremonger /* Allocate and set up 1 TX queue per Ethernet port. */ 237bab16ddaSBernard Iremonger for (q = 0; q < tx_rings; q++) { 238bab16ddaSBernard Iremonger retval = rte_eth_tx_queue_setup(port, q, TX_RING_SIZE, 239bab16ddaSBernard Iremonger rte_eth_dev_socket_id(port), NULL); 240bab16ddaSBernard Iremonger if (retval < 0) 241bab16ddaSBernard Iremonger return retval; 242bab16ddaSBernard Iremonger } 243bab16ddaSBernard Iremonger 244bab16ddaSBernard Iremonger /* Start the Ethernet port. */ 245bab16ddaSBernard Iremonger retval = rte_eth_dev_start(port); 246bab16ddaSBernard Iremonger if (retval < 0) 247bab16ddaSBernard Iremonger return retval; 248bab16ddaSBernard Iremonger 249bab16ddaSBernard Iremonger /* Display the port MAC address. */ 250bab16ddaSBernard Iremonger rte_eth_macaddr_get(port, &addr); 251bab16ddaSBernard Iremonger printf("Port %u MAC: %02" PRIx8 " %02" PRIx8 " %02" PRIx8 252bab16ddaSBernard Iremonger " %02" PRIx8 " %02" PRIx8 " %02" PRIx8 "\n", 253bab16ddaSBernard Iremonger port, 254bab16ddaSBernard Iremonger addr.addr_bytes[0], addr.addr_bytes[1], 255bab16ddaSBernard Iremonger addr.addr_bytes[2], addr.addr_bytes[3], 256bab16ddaSBernard Iremonger addr.addr_bytes[4], addr.addr_bytes[5]); 257bab16ddaSBernard Iremonger 258bab16ddaSBernard Iremonger /* Enable RX in promiscuous mode for the Ethernet device. */ 259bab16ddaSBernard Iremonger rte_eth_promiscuous_enable(port); 260bab16ddaSBernard Iremonger 261bab16ddaSBernard Iremonger return 0; 262bab16ddaSBernard Iremonger } 263bab16ddaSBernard Iremonger 264bab16ddaSBernard Iremonger /* 265bab16ddaSBernard Iremonger * The lcore main. This is the main thread that does the work, reading from 266bab16ddaSBernard Iremonger * an input port classifying the packets and writing to an output port. 267bab16ddaSBernard Iremonger */ 268bab16ddaSBernard Iremonger static __attribute__((noreturn)) void 269bab16ddaSBernard Iremonger lcore_main(struct flow_classifier *cls_app) 270bab16ddaSBernard Iremonger { 271bab16ddaSBernard Iremonger const uint8_t nb_ports = rte_eth_dev_count(); 272bab16ddaSBernard Iremonger uint8_t port; 273bab16ddaSBernard Iremonger int ret; 274bab16ddaSBernard Iremonger int i = 0; 275bab16ddaSBernard Iremonger 276bab16ddaSBernard Iremonger ret = rte_flow_classify_table_entry_delete(cls_app->cls, 277bab16ddaSBernard Iremonger cls_app->table_id[0], rules[7]); 278bab16ddaSBernard Iremonger if (ret) 279bab16ddaSBernard Iremonger printf("table_entry_delete failed [7] %d\n\n", ret); 280bab16ddaSBernard Iremonger else 281bab16ddaSBernard Iremonger printf("table_entry_delete succeeded [7]\n\n"); 282bab16ddaSBernard Iremonger 283bab16ddaSBernard Iremonger /* 284bab16ddaSBernard Iremonger * Check that the port is on the same NUMA node as the polling thread 285bab16ddaSBernard Iremonger * for best performance. 286bab16ddaSBernard Iremonger */ 287bab16ddaSBernard Iremonger for (port = 0; port < nb_ports; port++) 288bab16ddaSBernard Iremonger if (rte_eth_dev_socket_id(port) > 0 && 289bab16ddaSBernard Iremonger rte_eth_dev_socket_id(port) != (int)rte_socket_id()) { 290bab16ddaSBernard Iremonger printf("\n\n"); 291bab16ddaSBernard Iremonger printf("WARNING: port %u is on remote NUMA node\n", 292bab16ddaSBernard Iremonger port); 293bab16ddaSBernard Iremonger printf("to polling thread.\n"); 294bab16ddaSBernard Iremonger printf("Performance will not be optimal.\n"); 295bab16ddaSBernard Iremonger 296bab16ddaSBernard Iremonger printf("\nCore %u forwarding packets. ", 297bab16ddaSBernard Iremonger rte_lcore_id()); 298bab16ddaSBernard Iremonger printf("[Ctrl+C to quit]\n"); 299bab16ddaSBernard Iremonger } 300bab16ddaSBernard Iremonger /* Run until the application is quit or killed. */ 301bab16ddaSBernard Iremonger for (;;) { 302bab16ddaSBernard Iremonger /* 303bab16ddaSBernard Iremonger * Receive packets on a port, classify them and forward them 304bab16ddaSBernard Iremonger * on the paired port. 305bab16ddaSBernard Iremonger * The mapping is 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2, etc. 306bab16ddaSBernard Iremonger */ 307bab16ddaSBernard Iremonger for (port = 0; port < nb_ports; port++) { 308bab16ddaSBernard Iremonger /* Get burst of RX packets, from first port of pair. */ 309bab16ddaSBernard Iremonger struct rte_mbuf *bufs[BURST_SIZE]; 310bab16ddaSBernard Iremonger const uint16_t nb_rx = rte_eth_rx_burst(port, 0, 311bab16ddaSBernard Iremonger bufs, BURST_SIZE); 312bab16ddaSBernard Iremonger 313bab16ddaSBernard Iremonger if (unlikely(nb_rx == 0)) 314bab16ddaSBernard Iremonger continue; 315bab16ddaSBernard Iremonger 316bab16ddaSBernard Iremonger for (i = 0; i < MAX_NUM_CLASSIFY; i++) { 317bab16ddaSBernard Iremonger if (rules[i]) { 318bab16ddaSBernard Iremonger ret = rte_flow_classifier_query( 319bab16ddaSBernard Iremonger cls_app->cls, 320bab16ddaSBernard Iremonger cls_app->table_id[0], 321bab16ddaSBernard Iremonger bufs, nb_rx, rules[i], 322bab16ddaSBernard Iremonger &classify_stats); 323bab16ddaSBernard Iremonger if (ret) 324bab16ddaSBernard Iremonger printf( 325bab16ddaSBernard Iremonger "rule [%d] query failed ret [%d]\n\n", 326bab16ddaSBernard Iremonger i, ret); 327bab16ddaSBernard Iremonger else { 328bab16ddaSBernard Iremonger printf( 329bab16ddaSBernard Iremonger "rule[%d] count=%"PRIu64"\n", 330bab16ddaSBernard Iremonger i, ntuple_stats.counter1); 331bab16ddaSBernard Iremonger 332bab16ddaSBernard Iremonger printf("proto = %d\n", 333bab16ddaSBernard Iremonger ntuple_stats.ipv4_5tuple.proto); 334bab16ddaSBernard Iremonger } 335bab16ddaSBernard Iremonger } 336bab16ddaSBernard Iremonger } 337bab16ddaSBernard Iremonger 338bab16ddaSBernard Iremonger /* Send burst of TX packets, to second port of pair. */ 339bab16ddaSBernard Iremonger const uint16_t nb_tx = rte_eth_tx_burst(port ^ 1, 0, 340bab16ddaSBernard Iremonger bufs, nb_rx); 341bab16ddaSBernard Iremonger 342bab16ddaSBernard Iremonger /* Free any unsent packets. */ 343bab16ddaSBernard Iremonger if (unlikely(nb_tx < nb_rx)) { 344bab16ddaSBernard Iremonger uint16_t buf; 345bab16ddaSBernard Iremonger 346bab16ddaSBernard Iremonger for (buf = nb_tx; buf < nb_rx; buf++) 347bab16ddaSBernard Iremonger rte_pktmbuf_free(bufs[buf]); 348bab16ddaSBernard Iremonger } 349bab16ddaSBernard Iremonger } 350bab16ddaSBernard Iremonger } 351bab16ddaSBernard Iremonger } 352bab16ddaSBernard Iremonger 353bab16ddaSBernard Iremonger /* 354bab16ddaSBernard Iremonger * Parse IPv4 5 tuple rules file, ipv4_rules_file.txt. 355bab16ddaSBernard Iremonger * Expected format: 356bab16ddaSBernard Iremonger * <src_ipv4_addr>'/'<masklen> <space> \ 357bab16ddaSBernard Iremonger * <dst_ipv4_addr>'/'<masklen> <space> \ 358bab16ddaSBernard Iremonger * <src_port> <space> ":" <src_port_mask> <space> \ 359bab16ddaSBernard Iremonger * <dst_port> <space> ":" <dst_port_mask> <space> \ 360bab16ddaSBernard Iremonger * <proto>'/'<proto_mask> <space> \ 361bab16ddaSBernard Iremonger * <priority> 362bab16ddaSBernard Iremonger */ 363bab16ddaSBernard Iremonger 364bab16ddaSBernard Iremonger static int 365bab16ddaSBernard Iremonger get_cb_field(char **in, uint32_t *fd, int base, unsigned long lim, 366bab16ddaSBernard Iremonger char dlm) 367bab16ddaSBernard Iremonger { 368bab16ddaSBernard Iremonger unsigned long val; 369bab16ddaSBernard Iremonger char *end; 370bab16ddaSBernard Iremonger 371bab16ddaSBernard Iremonger errno = 0; 372bab16ddaSBernard Iremonger val = strtoul(*in, &end, base); 373bab16ddaSBernard Iremonger if (errno != 0 || end[0] != dlm || val > lim) 374bab16ddaSBernard Iremonger return -EINVAL; 375bab16ddaSBernard Iremonger *fd = (uint32_t)val; 376bab16ddaSBernard Iremonger *in = end + 1; 377bab16ddaSBernard Iremonger return 0; 378bab16ddaSBernard Iremonger } 379bab16ddaSBernard Iremonger 380bab16ddaSBernard Iremonger static int 381bab16ddaSBernard Iremonger parse_ipv4_net(char *in, uint32_t *addr, uint32_t *mask_len) 382bab16ddaSBernard Iremonger { 383bab16ddaSBernard Iremonger uint32_t a, b, c, d, m; 384bab16ddaSBernard Iremonger 385bab16ddaSBernard Iremonger if (get_cb_field(&in, &a, 0, UINT8_MAX, '.')) 386bab16ddaSBernard Iremonger return -EINVAL; 387bab16ddaSBernard Iremonger if (get_cb_field(&in, &b, 0, UINT8_MAX, '.')) 388bab16ddaSBernard Iremonger return -EINVAL; 389bab16ddaSBernard Iremonger if (get_cb_field(&in, &c, 0, UINT8_MAX, '.')) 390bab16ddaSBernard Iremonger return -EINVAL; 391bab16ddaSBernard Iremonger if (get_cb_field(&in, &d, 0, UINT8_MAX, '/')) 392bab16ddaSBernard Iremonger return -EINVAL; 393bab16ddaSBernard Iremonger if (get_cb_field(&in, &m, 0, sizeof(uint32_t) * CHAR_BIT, 0)) 394bab16ddaSBernard Iremonger return -EINVAL; 395bab16ddaSBernard Iremonger 396bab16ddaSBernard Iremonger addr[0] = IPv4(a, b, c, d); 397bab16ddaSBernard Iremonger mask_len[0] = m; 398bab16ddaSBernard Iremonger return 0; 399bab16ddaSBernard Iremonger } 400bab16ddaSBernard Iremonger 401bab16ddaSBernard Iremonger static int 402bab16ddaSBernard Iremonger parse_ipv4_5tuple_rule(char *str, struct rte_eth_ntuple_filter *ntuple_filter) 403bab16ddaSBernard Iremonger { 404bab16ddaSBernard Iremonger int i, ret; 405bab16ddaSBernard Iremonger char *s, *sp, *in[CB_FLD_NUM]; 406bab16ddaSBernard Iremonger static const char *dlm = " \t\n"; 407bab16ddaSBernard Iremonger int dim = CB_FLD_NUM; 408bab16ddaSBernard Iremonger uint32_t temp; 409bab16ddaSBernard Iremonger 410bab16ddaSBernard Iremonger s = str; 411bab16ddaSBernard Iremonger for (i = 0; i != dim; i++, s = NULL) { 412bab16ddaSBernard Iremonger in[i] = strtok_r(s, dlm, &sp); 413bab16ddaSBernard Iremonger if (in[i] == NULL) 414bab16ddaSBernard Iremonger return -EINVAL; 415bab16ddaSBernard Iremonger } 416bab16ddaSBernard Iremonger 417bab16ddaSBernard Iremonger ret = parse_ipv4_net(in[CB_FLD_SRC_ADDR], 418bab16ddaSBernard Iremonger &ntuple_filter->src_ip, 419bab16ddaSBernard Iremonger &ntuple_filter->src_ip_mask); 420bab16ddaSBernard Iremonger if (ret != 0) { 421bab16ddaSBernard Iremonger flow_classify_log("failed to read source address/mask: %s\n", 422bab16ddaSBernard Iremonger in[CB_FLD_SRC_ADDR]); 423bab16ddaSBernard Iremonger return ret; 424bab16ddaSBernard Iremonger } 425bab16ddaSBernard Iremonger 426bab16ddaSBernard Iremonger ret = parse_ipv4_net(in[CB_FLD_DST_ADDR], 427bab16ddaSBernard Iremonger &ntuple_filter->dst_ip, 428bab16ddaSBernard Iremonger &ntuple_filter->dst_ip_mask); 429bab16ddaSBernard Iremonger if (ret != 0) { 430bab16ddaSBernard Iremonger flow_classify_log("failed to read source address/mask: %s\n", 431bab16ddaSBernard Iremonger in[CB_FLD_DST_ADDR]); 432bab16ddaSBernard Iremonger return ret; 433bab16ddaSBernard Iremonger } 434bab16ddaSBernard Iremonger 435bab16ddaSBernard Iremonger if (get_cb_field(&in[CB_FLD_SRC_PORT], &temp, 0, UINT16_MAX, 0)) 436bab16ddaSBernard Iremonger return -EINVAL; 437bab16ddaSBernard Iremonger ntuple_filter->src_port = (uint16_t)temp; 438bab16ddaSBernard Iremonger 439bab16ddaSBernard Iremonger if (strncmp(in[CB_FLD_SRC_PORT_DLM], cb_port_delim, 440bab16ddaSBernard Iremonger sizeof(cb_port_delim)) != 0) 441bab16ddaSBernard Iremonger return -EINVAL; 442bab16ddaSBernard Iremonger 443bab16ddaSBernard Iremonger if (get_cb_field(&in[CB_FLD_SRC_PORT_MASK], &temp, 0, UINT16_MAX, 0)) 444bab16ddaSBernard Iremonger return -EINVAL; 445bab16ddaSBernard Iremonger ntuple_filter->src_port_mask = (uint16_t)temp; 446bab16ddaSBernard Iremonger 447bab16ddaSBernard Iremonger if (get_cb_field(&in[CB_FLD_DST_PORT], &temp, 0, UINT16_MAX, 0)) 448bab16ddaSBernard Iremonger return -EINVAL; 449bab16ddaSBernard Iremonger ntuple_filter->dst_port = (uint16_t)temp; 450bab16ddaSBernard Iremonger 451bab16ddaSBernard Iremonger if (strncmp(in[CB_FLD_DST_PORT_DLM], cb_port_delim, 452bab16ddaSBernard Iremonger sizeof(cb_port_delim)) != 0) 453bab16ddaSBernard Iremonger return -EINVAL; 454bab16ddaSBernard Iremonger 455bab16ddaSBernard Iremonger if (get_cb_field(&in[CB_FLD_DST_PORT_MASK], &temp, 0, UINT16_MAX, 0)) 456bab16ddaSBernard Iremonger return -EINVAL; 457bab16ddaSBernard Iremonger ntuple_filter->dst_port_mask = (uint16_t)temp; 458bab16ddaSBernard Iremonger 459bab16ddaSBernard Iremonger if (get_cb_field(&in[CB_FLD_PROTO], &temp, 0, UINT8_MAX, '/')) 460bab16ddaSBernard Iremonger return -EINVAL; 461bab16ddaSBernard Iremonger ntuple_filter->proto = (uint8_t)temp; 462bab16ddaSBernard Iremonger 463bab16ddaSBernard Iremonger if (get_cb_field(&in[CB_FLD_PROTO], &temp, 0, UINT8_MAX, 0)) 464bab16ddaSBernard Iremonger return -EINVAL; 465bab16ddaSBernard Iremonger ntuple_filter->proto_mask = (uint8_t)temp; 466bab16ddaSBernard Iremonger 467bab16ddaSBernard Iremonger if (get_cb_field(&in[CB_FLD_PRIORITY], &temp, 0, UINT16_MAX, 0)) 468bab16ddaSBernard Iremonger return -EINVAL; 469bab16ddaSBernard Iremonger ntuple_filter->priority = (uint16_t)temp; 470bab16ddaSBernard Iremonger if (ntuple_filter->priority > FLOW_CLASSIFY_MAX_PRIORITY) 471bab16ddaSBernard Iremonger ret = -EINVAL; 472bab16ddaSBernard Iremonger 473bab16ddaSBernard Iremonger return ret; 474bab16ddaSBernard Iremonger } 475bab16ddaSBernard Iremonger 476bab16ddaSBernard Iremonger /* Bypass comment and empty lines */ 477bab16ddaSBernard Iremonger static inline int 478bab16ddaSBernard Iremonger is_bypass_line(char *buff) 479bab16ddaSBernard Iremonger { 480bab16ddaSBernard Iremonger int i = 0; 481bab16ddaSBernard Iremonger 482bab16ddaSBernard Iremonger /* comment line */ 483bab16ddaSBernard Iremonger if (buff[0] == COMMENT_LEAD_CHAR) 484bab16ddaSBernard Iremonger return 1; 485bab16ddaSBernard Iremonger /* empty line */ 486bab16ddaSBernard Iremonger while (buff[i] != '\0') { 487bab16ddaSBernard Iremonger if (!isspace(buff[i])) 488bab16ddaSBernard Iremonger return 0; 489bab16ddaSBernard Iremonger i++; 490bab16ddaSBernard Iremonger } 491bab16ddaSBernard Iremonger return 1; 492bab16ddaSBernard Iremonger } 493bab16ddaSBernard Iremonger 494bab16ddaSBernard Iremonger static uint32_t 495bab16ddaSBernard Iremonger convert_depth_to_bitmask(uint32_t depth_val) 496bab16ddaSBernard Iremonger { 497bab16ddaSBernard Iremonger uint32_t bitmask = 0; 498bab16ddaSBernard Iremonger int i, j; 499bab16ddaSBernard Iremonger 500bab16ddaSBernard Iremonger for (i = depth_val, j = 0; i > 0; i--, j++) 501bab16ddaSBernard Iremonger bitmask |= (1 << (31 - j)); 502bab16ddaSBernard Iremonger return bitmask; 503bab16ddaSBernard Iremonger } 504bab16ddaSBernard Iremonger 505bab16ddaSBernard Iremonger static int 506bab16ddaSBernard Iremonger add_classify_rule(struct rte_eth_ntuple_filter *ntuple_filter, 507bab16ddaSBernard Iremonger struct flow_classifier *cls_app) 508bab16ddaSBernard Iremonger { 509bab16ddaSBernard Iremonger int ret = -1; 510bab16ddaSBernard Iremonger int key_found; 511bab16ddaSBernard Iremonger struct rte_flow_error error; 512bab16ddaSBernard Iremonger struct rte_flow_item_ipv4 ipv4_spec; 513bab16ddaSBernard Iremonger struct rte_flow_item_ipv4 ipv4_mask; 514bab16ddaSBernard Iremonger struct rte_flow_item ipv4_udp_item; 515bab16ddaSBernard Iremonger struct rte_flow_item ipv4_tcp_item; 516bab16ddaSBernard Iremonger struct rte_flow_item ipv4_sctp_item; 517bab16ddaSBernard Iremonger struct rte_flow_item_udp udp_spec; 518bab16ddaSBernard Iremonger struct rte_flow_item_udp udp_mask; 519bab16ddaSBernard Iremonger struct rte_flow_item udp_item; 520bab16ddaSBernard Iremonger struct rte_flow_item_tcp tcp_spec; 521bab16ddaSBernard Iremonger struct rte_flow_item_tcp tcp_mask; 522bab16ddaSBernard Iremonger struct rte_flow_item tcp_item; 523bab16ddaSBernard Iremonger struct rte_flow_item_sctp sctp_spec; 524bab16ddaSBernard Iremonger struct rte_flow_item_sctp sctp_mask; 525bab16ddaSBernard Iremonger struct rte_flow_item sctp_item; 526bab16ddaSBernard Iremonger struct rte_flow_item pattern_ipv4_5tuple[4]; 527bab16ddaSBernard Iremonger struct rte_flow_classify_rule *rule; 528bab16ddaSBernard Iremonger uint8_t ipv4_proto; 529bab16ddaSBernard Iremonger 530bab16ddaSBernard Iremonger if (num_classify_rules >= MAX_NUM_CLASSIFY) { 531bab16ddaSBernard Iremonger printf( 532bab16ddaSBernard Iremonger "\nINFO: classify rule capacity %d reached\n", 533bab16ddaSBernard Iremonger num_classify_rules); 534bab16ddaSBernard Iremonger return ret; 535bab16ddaSBernard Iremonger } 536bab16ddaSBernard Iremonger 537bab16ddaSBernard Iremonger /* set up parameters for validate and add */ 538bab16ddaSBernard Iremonger memset(&ipv4_spec, 0, sizeof(ipv4_spec)); 539bab16ddaSBernard Iremonger ipv4_spec.hdr.next_proto_id = ntuple_filter->proto; 540bab16ddaSBernard Iremonger ipv4_spec.hdr.src_addr = ntuple_filter->src_ip; 541bab16ddaSBernard Iremonger ipv4_spec.hdr.dst_addr = ntuple_filter->dst_ip; 542bab16ddaSBernard Iremonger ipv4_proto = ipv4_spec.hdr.next_proto_id; 543bab16ddaSBernard Iremonger 544bab16ddaSBernard Iremonger memset(&ipv4_mask, 0, sizeof(ipv4_mask)); 545bab16ddaSBernard Iremonger ipv4_mask.hdr.next_proto_id = ntuple_filter->proto_mask; 546bab16ddaSBernard Iremonger ipv4_mask.hdr.src_addr = ntuple_filter->src_ip_mask; 547bab16ddaSBernard Iremonger ipv4_mask.hdr.src_addr = 548bab16ddaSBernard Iremonger convert_depth_to_bitmask(ipv4_mask.hdr.src_addr); 549bab16ddaSBernard Iremonger ipv4_mask.hdr.dst_addr = ntuple_filter->dst_ip_mask; 550bab16ddaSBernard Iremonger ipv4_mask.hdr.dst_addr = 551bab16ddaSBernard Iremonger convert_depth_to_bitmask(ipv4_mask.hdr.dst_addr); 552bab16ddaSBernard Iremonger 553bab16ddaSBernard Iremonger switch (ipv4_proto) { 554bab16ddaSBernard Iremonger case IPPROTO_UDP: 555bab16ddaSBernard Iremonger ipv4_udp_item.type = RTE_FLOW_ITEM_TYPE_IPV4; 556bab16ddaSBernard Iremonger ipv4_udp_item.spec = &ipv4_spec; 557bab16ddaSBernard Iremonger ipv4_udp_item.mask = &ipv4_mask; 558bab16ddaSBernard Iremonger ipv4_udp_item.last = NULL; 559bab16ddaSBernard Iremonger 560bab16ddaSBernard Iremonger udp_spec.hdr.src_port = ntuple_filter->src_port; 561bab16ddaSBernard Iremonger udp_spec.hdr.dst_port = ntuple_filter->dst_port; 562bab16ddaSBernard Iremonger udp_spec.hdr.dgram_len = 0; 563bab16ddaSBernard Iremonger udp_spec.hdr.dgram_cksum = 0; 564bab16ddaSBernard Iremonger 565bab16ddaSBernard Iremonger udp_mask.hdr.src_port = ntuple_filter->src_port_mask; 566bab16ddaSBernard Iremonger udp_mask.hdr.dst_port = ntuple_filter->dst_port_mask; 567bab16ddaSBernard Iremonger udp_mask.hdr.dgram_len = 0; 568bab16ddaSBernard Iremonger udp_mask.hdr.dgram_cksum = 0; 569bab16ddaSBernard Iremonger 570bab16ddaSBernard Iremonger udp_item.type = RTE_FLOW_ITEM_TYPE_UDP; 571bab16ddaSBernard Iremonger udp_item.spec = &udp_spec; 572bab16ddaSBernard Iremonger udp_item.mask = &udp_mask; 573bab16ddaSBernard Iremonger udp_item.last = NULL; 574bab16ddaSBernard Iremonger 575bab16ddaSBernard Iremonger attr.priority = ntuple_filter->priority; 576bab16ddaSBernard Iremonger pattern_ipv4_5tuple[1] = ipv4_udp_item; 577bab16ddaSBernard Iremonger pattern_ipv4_5tuple[2] = udp_item; 578bab16ddaSBernard Iremonger break; 579bab16ddaSBernard Iremonger case IPPROTO_TCP: 580bab16ddaSBernard Iremonger ipv4_tcp_item.type = RTE_FLOW_ITEM_TYPE_IPV4; 581bab16ddaSBernard Iremonger ipv4_tcp_item.spec = &ipv4_spec; 582bab16ddaSBernard Iremonger ipv4_tcp_item.mask = &ipv4_mask; 583bab16ddaSBernard Iremonger ipv4_tcp_item.last = NULL; 584bab16ddaSBernard Iremonger 585bab16ddaSBernard Iremonger memset(&tcp_spec, 0, sizeof(tcp_spec)); 586bab16ddaSBernard Iremonger tcp_spec.hdr.src_port = ntuple_filter->src_port; 587bab16ddaSBernard Iremonger tcp_spec.hdr.dst_port = ntuple_filter->dst_port; 588bab16ddaSBernard Iremonger 589bab16ddaSBernard Iremonger memset(&tcp_mask, 0, sizeof(tcp_mask)); 590bab16ddaSBernard Iremonger tcp_mask.hdr.src_port = ntuple_filter->src_port_mask; 591bab16ddaSBernard Iremonger tcp_mask.hdr.dst_port = ntuple_filter->dst_port_mask; 592bab16ddaSBernard Iremonger 593bab16ddaSBernard Iremonger tcp_item.type = RTE_FLOW_ITEM_TYPE_TCP; 594bab16ddaSBernard Iremonger tcp_item.spec = &tcp_spec; 595bab16ddaSBernard Iremonger tcp_item.mask = &tcp_mask; 596bab16ddaSBernard Iremonger tcp_item.last = NULL; 597bab16ddaSBernard Iremonger 598bab16ddaSBernard Iremonger attr.priority = ntuple_filter->priority; 599bab16ddaSBernard Iremonger pattern_ipv4_5tuple[1] = ipv4_tcp_item; 600bab16ddaSBernard Iremonger pattern_ipv4_5tuple[2] = tcp_item; 601bab16ddaSBernard Iremonger break; 602bab16ddaSBernard Iremonger case IPPROTO_SCTP: 603bab16ddaSBernard Iremonger ipv4_sctp_item.type = RTE_FLOW_ITEM_TYPE_IPV4; 604bab16ddaSBernard Iremonger ipv4_sctp_item.spec = &ipv4_spec; 605bab16ddaSBernard Iremonger ipv4_sctp_item.mask = &ipv4_mask; 606bab16ddaSBernard Iremonger ipv4_sctp_item.last = NULL; 607bab16ddaSBernard Iremonger 608bab16ddaSBernard Iremonger sctp_spec.hdr.src_port = ntuple_filter->src_port; 609bab16ddaSBernard Iremonger sctp_spec.hdr.dst_port = ntuple_filter->dst_port; 610bab16ddaSBernard Iremonger sctp_spec.hdr.cksum = 0; 611bab16ddaSBernard Iremonger sctp_spec.hdr.tag = 0; 612bab16ddaSBernard Iremonger 613bab16ddaSBernard Iremonger sctp_mask.hdr.src_port = ntuple_filter->src_port_mask; 614bab16ddaSBernard Iremonger sctp_mask.hdr.dst_port = ntuple_filter->dst_port_mask; 615bab16ddaSBernard Iremonger sctp_mask.hdr.cksum = 0; 616bab16ddaSBernard Iremonger sctp_mask.hdr.tag = 0; 617bab16ddaSBernard Iremonger 618bab16ddaSBernard Iremonger sctp_item.type = RTE_FLOW_ITEM_TYPE_SCTP; 619bab16ddaSBernard Iremonger sctp_item.spec = &sctp_spec; 620bab16ddaSBernard Iremonger sctp_item.mask = &sctp_mask; 621bab16ddaSBernard Iremonger sctp_item.last = NULL; 622bab16ddaSBernard Iremonger 623bab16ddaSBernard Iremonger attr.priority = ntuple_filter->priority; 624bab16ddaSBernard Iremonger pattern_ipv4_5tuple[1] = ipv4_sctp_item; 625bab16ddaSBernard Iremonger pattern_ipv4_5tuple[2] = sctp_item; 626bab16ddaSBernard Iremonger break; 627bab16ddaSBernard Iremonger default: 628bab16ddaSBernard Iremonger return ret; 629bab16ddaSBernard Iremonger } 630bab16ddaSBernard Iremonger 631bab16ddaSBernard Iremonger attr.ingress = 1; 632bab16ddaSBernard Iremonger pattern_ipv4_5tuple[0] = eth_item; 633bab16ddaSBernard Iremonger pattern_ipv4_5tuple[3] = end_item; 634bab16ddaSBernard Iremonger actions[0] = count_action; 635bab16ddaSBernard Iremonger actions[1] = end_action; 636bab16ddaSBernard Iremonger 637bab16ddaSBernard Iremonger rule = rte_flow_classify_table_entry_add( 638bab16ddaSBernard Iremonger cls_app->cls, cls_app->table_id[0], &key_found, 639bab16ddaSBernard Iremonger &attr, pattern_ipv4_5tuple, actions, &error); 640bab16ddaSBernard Iremonger if (rule == NULL) { 641bab16ddaSBernard Iremonger printf("table entry add failed ipv4_proto = %u\n", 642bab16ddaSBernard Iremonger ipv4_proto); 643bab16ddaSBernard Iremonger ret = -1; 644bab16ddaSBernard Iremonger return ret; 645bab16ddaSBernard Iremonger } 646bab16ddaSBernard Iremonger 647bab16ddaSBernard Iremonger rules[num_classify_rules] = rule; 648bab16ddaSBernard Iremonger num_classify_rules++; 649bab16ddaSBernard Iremonger return 0; 650bab16ddaSBernard Iremonger } 651bab16ddaSBernard Iremonger 652bab16ddaSBernard Iremonger static int 653bab16ddaSBernard Iremonger add_rules(const char *rule_path, struct flow_classifier *cls_app) 654bab16ddaSBernard Iremonger { 655bab16ddaSBernard Iremonger FILE *fh; 656bab16ddaSBernard Iremonger char buff[LINE_MAX]; 657bab16ddaSBernard Iremonger unsigned int i = 0; 658bab16ddaSBernard Iremonger unsigned int total_num = 0; 659bab16ddaSBernard Iremonger struct rte_eth_ntuple_filter ntuple_filter; 660*c044ffaaSBernard Iremonger int ret; 661bab16ddaSBernard Iremonger 662bab16ddaSBernard Iremonger fh = fopen(rule_path, "rb"); 663bab16ddaSBernard Iremonger if (fh == NULL) 664*c044ffaaSBernard Iremonger rte_exit(EXIT_FAILURE, "%s: fopen %s failed\n", __func__, 665bab16ddaSBernard Iremonger rule_path); 666bab16ddaSBernard Iremonger 667*c044ffaaSBernard Iremonger ret = fseek(fh, 0, SEEK_SET); 668*c044ffaaSBernard Iremonger if (ret) 669*c044ffaaSBernard Iremonger rte_exit(EXIT_FAILURE, "%s: fseek %d failed\n", __func__, 670*c044ffaaSBernard Iremonger ret); 671bab16ddaSBernard Iremonger 672bab16ddaSBernard Iremonger i = 0; 673bab16ddaSBernard Iremonger while (fgets(buff, LINE_MAX, fh) != NULL) { 674bab16ddaSBernard Iremonger i++; 675bab16ddaSBernard Iremonger 676bab16ddaSBernard Iremonger if (is_bypass_line(buff)) 677bab16ddaSBernard Iremonger continue; 678bab16ddaSBernard Iremonger 679bab16ddaSBernard Iremonger if (total_num >= FLOW_CLASSIFY_MAX_RULE_NUM - 1) { 680bab16ddaSBernard Iremonger printf("\nINFO: classify rule capacity %d reached\n", 681bab16ddaSBernard Iremonger total_num); 682bab16ddaSBernard Iremonger break; 683bab16ddaSBernard Iremonger } 684bab16ddaSBernard Iremonger 685bab16ddaSBernard Iremonger if (parse_ipv4_5tuple_rule(buff, &ntuple_filter) != 0) 686bab16ddaSBernard Iremonger rte_exit(EXIT_FAILURE, 687bab16ddaSBernard Iremonger "%s Line %u: parse rules error\n", 688bab16ddaSBernard Iremonger rule_path, i); 689bab16ddaSBernard Iremonger 690bab16ddaSBernard Iremonger if (add_classify_rule(&ntuple_filter, cls_app) != 0) 691bab16ddaSBernard Iremonger rte_exit(EXIT_FAILURE, "add rule error\n"); 692bab16ddaSBernard Iremonger 693bab16ddaSBernard Iremonger total_num++; 694bab16ddaSBernard Iremonger } 695bab16ddaSBernard Iremonger 696bab16ddaSBernard Iremonger fclose(fh); 697bab16ddaSBernard Iremonger return 0; 698bab16ddaSBernard Iremonger } 699bab16ddaSBernard Iremonger 700bab16ddaSBernard Iremonger /* display usage */ 701bab16ddaSBernard Iremonger static void 702bab16ddaSBernard Iremonger print_usage(const char *prgname) 703bab16ddaSBernard Iremonger { 704bab16ddaSBernard Iremonger printf("%s usage:\n", prgname); 705bab16ddaSBernard Iremonger printf("[EAL options] -- --"OPTION_RULE_IPV4"=FILE: "); 706bab16ddaSBernard Iremonger printf("specify the ipv4 rules file.\n"); 707bab16ddaSBernard Iremonger printf("Each rule occupies one line in the file.\n"); 708bab16ddaSBernard Iremonger } 709bab16ddaSBernard Iremonger 710bab16ddaSBernard Iremonger /* Parse the argument given in the command line of the application */ 711bab16ddaSBernard Iremonger static int 712bab16ddaSBernard Iremonger parse_args(int argc, char **argv) 713bab16ddaSBernard Iremonger { 714bab16ddaSBernard Iremonger int opt, ret; 715bab16ddaSBernard Iremonger char **argvopt; 716bab16ddaSBernard Iremonger int option_index; 717bab16ddaSBernard Iremonger char *prgname = argv[0]; 718bab16ddaSBernard Iremonger static struct option lgopts[] = { 719bab16ddaSBernard Iremonger {OPTION_RULE_IPV4, 1, 0, 0}, 720bab16ddaSBernard Iremonger {NULL, 0, 0, 0} 721bab16ddaSBernard Iremonger }; 722bab16ddaSBernard Iremonger 723bab16ddaSBernard Iremonger argvopt = argv; 724bab16ddaSBernard Iremonger 725bab16ddaSBernard Iremonger while ((opt = getopt_long(argc, argvopt, "", 726bab16ddaSBernard Iremonger lgopts, &option_index)) != EOF) { 727bab16ddaSBernard Iremonger 728bab16ddaSBernard Iremonger switch (opt) { 729bab16ddaSBernard Iremonger /* long options */ 730bab16ddaSBernard Iremonger case 0: 731bab16ddaSBernard Iremonger if (!strncmp(lgopts[option_index].name, 732bab16ddaSBernard Iremonger OPTION_RULE_IPV4, 733bab16ddaSBernard Iremonger sizeof(OPTION_RULE_IPV4))) 734bab16ddaSBernard Iremonger parm_config.rule_ipv4_name = optarg; 735bab16ddaSBernard Iremonger break; 736bab16ddaSBernard Iremonger default: 737bab16ddaSBernard Iremonger print_usage(prgname); 738bab16ddaSBernard Iremonger return -1; 739bab16ddaSBernard Iremonger } 740bab16ddaSBernard Iremonger } 741bab16ddaSBernard Iremonger 742bab16ddaSBernard Iremonger if (optind >= 0) 743bab16ddaSBernard Iremonger argv[optind-1] = prgname; 744bab16ddaSBernard Iremonger 745bab16ddaSBernard Iremonger ret = optind-1; 746bab16ddaSBernard Iremonger optind = 1; /* reset getopt lib */ 747bab16ddaSBernard Iremonger return ret; 748bab16ddaSBernard Iremonger } 749bab16ddaSBernard Iremonger 750bab16ddaSBernard Iremonger /* 751bab16ddaSBernard Iremonger * The main function, which does initialization and calls the lcore_main 752bab16ddaSBernard Iremonger * function. 753bab16ddaSBernard Iremonger */ 754bab16ddaSBernard Iremonger int 755bab16ddaSBernard Iremonger main(int argc, char *argv[]) 756bab16ddaSBernard Iremonger { 757bab16ddaSBernard Iremonger struct rte_mempool *mbuf_pool; 758bab16ddaSBernard Iremonger uint8_t nb_ports; 759bab16ddaSBernard Iremonger uint8_t portid; 760bab16ddaSBernard Iremonger int ret; 761bab16ddaSBernard Iremonger int socket_id; 762bab16ddaSBernard Iremonger struct rte_table_acl_params table_acl_params; 763bab16ddaSBernard Iremonger struct rte_flow_classify_table_params cls_table_params; 764bab16ddaSBernard Iremonger struct flow_classifier *cls_app; 765bab16ddaSBernard Iremonger struct rte_flow_classifier_params cls_params; 766bab16ddaSBernard Iremonger uint32_t size; 767bab16ddaSBernard Iremonger 768bab16ddaSBernard Iremonger /* Initialize the Environment Abstraction Layer (EAL). */ 769bab16ddaSBernard Iremonger ret = rte_eal_init(argc, argv); 770bab16ddaSBernard Iremonger if (ret < 0) 771bab16ddaSBernard Iremonger rte_exit(EXIT_FAILURE, "Error with EAL initialization\n"); 772bab16ddaSBernard Iremonger 773bab16ddaSBernard Iremonger argc -= ret; 774bab16ddaSBernard Iremonger argv += ret; 775bab16ddaSBernard Iremonger 776bab16ddaSBernard Iremonger /* parse application arguments (after the EAL ones) */ 777bab16ddaSBernard Iremonger ret = parse_args(argc, argv); 778bab16ddaSBernard Iremonger if (ret < 0) 779bab16ddaSBernard Iremonger rte_exit(EXIT_FAILURE, "Invalid flow_classify parameters\n"); 780bab16ddaSBernard Iremonger 781bab16ddaSBernard Iremonger /* Check that there is an even number of ports to send/receive on. */ 782bab16ddaSBernard Iremonger nb_ports = rte_eth_dev_count(); 783bab16ddaSBernard Iremonger if (nb_ports < 2 || (nb_ports & 1)) 784bab16ddaSBernard Iremonger rte_exit(EXIT_FAILURE, "Error: number of ports must be even\n"); 785bab16ddaSBernard Iremonger 786bab16ddaSBernard Iremonger /* Creates a new mempool in memory to hold the mbufs. */ 787bab16ddaSBernard Iremonger mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", NUM_MBUFS * nb_ports, 788bab16ddaSBernard Iremonger MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id()); 789bab16ddaSBernard Iremonger 790bab16ddaSBernard Iremonger if (mbuf_pool == NULL) 791bab16ddaSBernard Iremonger rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n"); 792bab16ddaSBernard Iremonger 793bab16ddaSBernard Iremonger /* Initialize all ports. */ 794bab16ddaSBernard Iremonger for (portid = 0; portid < nb_ports; portid++) 795bab16ddaSBernard Iremonger if (port_init(portid, mbuf_pool) != 0) 796bab16ddaSBernard Iremonger rte_exit(EXIT_FAILURE, "Cannot init port %"PRIu8 "\n", 797bab16ddaSBernard Iremonger portid); 798bab16ddaSBernard Iremonger 799bab16ddaSBernard Iremonger if (rte_lcore_count() > 1) 800bab16ddaSBernard Iremonger printf("\nWARNING: Too many lcores enabled. Only 1 used.\n"); 801bab16ddaSBernard Iremonger 802bab16ddaSBernard Iremonger socket_id = rte_eth_dev_socket_id(0); 803bab16ddaSBernard Iremonger 804bab16ddaSBernard Iremonger /* Memory allocation */ 805bab16ddaSBernard Iremonger size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct flow_classifier_acl)); 806bab16ddaSBernard Iremonger cls_app = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE); 807bab16ddaSBernard Iremonger if (cls_app == NULL) 808bab16ddaSBernard Iremonger rte_exit(EXIT_FAILURE, "Cannot allocate classifier memory\n"); 809bab16ddaSBernard Iremonger 810bab16ddaSBernard Iremonger cls_params.name = "flow_classifier"; 811bab16ddaSBernard Iremonger cls_params.socket_id = socket_id; 812bab16ddaSBernard Iremonger cls_params.type = RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL; 813bab16ddaSBernard Iremonger 814bab16ddaSBernard Iremonger cls_app->cls = rte_flow_classifier_create(&cls_params); 815bab16ddaSBernard Iremonger if (cls_app->cls == NULL) { 816bab16ddaSBernard Iremonger rte_free(cls_app); 817bab16ddaSBernard Iremonger rte_exit(EXIT_FAILURE, "Cannot create classifier\n"); 818bab16ddaSBernard Iremonger } 819bab16ddaSBernard Iremonger 820bab16ddaSBernard Iremonger /* initialise ACL table params */ 821bab16ddaSBernard Iremonger table_acl_params.name = "table_acl_ipv4_5tuple"; 822bab16ddaSBernard Iremonger table_acl_params.n_rules = FLOW_CLASSIFY_MAX_RULE_NUM; 823bab16ddaSBernard Iremonger table_acl_params.n_rule_fields = RTE_DIM(ipv4_defs); 824bab16ddaSBernard Iremonger memcpy(table_acl_params.field_format, ipv4_defs, sizeof(ipv4_defs)); 825bab16ddaSBernard Iremonger 826bab16ddaSBernard Iremonger /* initialise table create params */ 827bab16ddaSBernard Iremonger cls_table_params.ops = &rte_table_acl_ops, 828bab16ddaSBernard Iremonger cls_table_params.arg_create = &table_acl_params, 829bab16ddaSBernard Iremonger 830bab16ddaSBernard Iremonger ret = rte_flow_classify_table_create(cls_app->cls, &cls_table_params, 831bab16ddaSBernard Iremonger &cls_app->table_id[0]); 832bab16ddaSBernard Iremonger if (ret) { 833bab16ddaSBernard Iremonger rte_flow_classifier_free(cls_app->cls); 834bab16ddaSBernard Iremonger rte_free(cls_app); 835bab16ddaSBernard Iremonger rte_exit(EXIT_FAILURE, "Failed to create classifier table\n"); 836bab16ddaSBernard Iremonger } 837bab16ddaSBernard Iremonger 838bab16ddaSBernard Iremonger /* read file of IPv4 5 tuple rules and initialize parameters 839bab16ddaSBernard Iremonger * for rte_flow_classify_validate and rte_flow_classify_table_entry_add 840bab16ddaSBernard Iremonger * API's. 841bab16ddaSBernard Iremonger */ 842bab16ddaSBernard Iremonger if (add_rules(parm_config.rule_ipv4_name, cls_app)) { 843bab16ddaSBernard Iremonger rte_flow_classifier_free(cls_app->cls); 844bab16ddaSBernard Iremonger rte_free(cls_app); 845bab16ddaSBernard Iremonger rte_exit(EXIT_FAILURE, "Failed to add rules\n"); 846bab16ddaSBernard Iremonger } 847bab16ddaSBernard Iremonger 848bab16ddaSBernard Iremonger /* Call lcore_main on the master core only. */ 849bab16ddaSBernard Iremonger lcore_main(cls_app); 850bab16ddaSBernard Iremonger 851bab16ddaSBernard Iremonger return 0; 852bab16ddaSBernard Iremonger } 853