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