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