dpdk/examples/ip_pipeline/pipeline.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright(c) 2010-2018 Intel Corporation
   3 */
   4
   5#include <stdlib.h>
   6#include <string.h>
   7
   8#include <rte_common.h>
   9#include <rte_ip.h>
  10#include <rte_tcp.h>
  11
  12#include <rte_string_fns.h>
  13#include <rte_port_ethdev.h>
  14#ifdef RTE_LIB_KNI
  15#include <rte_port_kni.h>
  16#endif
  17#include <rte_port_ring.h>
  18#include <rte_port_source_sink.h>
  19#include <rte_port_fd.h>
  20#include <rte_port_sched.h>
  21#include <rte_port_sym_crypto.h>
  22
  23#include <rte_table_acl.h>
  24#include <rte_table_array.h>
  25#include <rte_table_hash.h>
  26#include <rte_table_hash_func.h>
  27#include <rte_table_lpm.h>
  28#include <rte_table_lpm_ipv6.h>
  29#include <rte_table_stub.h>
  30
  31#ifdef RTE_LIB_KNI
  32#include "kni.h"
  33#endif
  34#include "link.h"
  35#include "mempool.h"
  36#include "pipeline.h"
  37#include "tap.h"
  38#include "tmgr.h"
  39#include "swq.h"
  40#include "cryptodev.h"
  41
  42#ifndef PIPELINE_MSGQ_SIZE
  43#define PIPELINE_MSGQ_SIZE                                 64
  44#endif
  45
  46#ifndef TABLE_LPM_NUMBER_TBL8
  47#define TABLE_LPM_NUMBER_TBL8                              256
  48#endif
  49
  50static struct pipeline_list pipeline_list;
  51
  52int
  53pipeline_init(void)
  54{
  55        TAILQ_INIT(&pipeline_list);
  56
  57        return 0;
  58}
  59
  60struct pipeline *
  61pipeline_find(const char *name)
  62{
  63        struct pipeline *pipeline;
  64
  65        if (name == NULL)
  66                return NULL;
  67
  68        TAILQ_FOREACH(pipeline, &pipeline_list, node)
  69                if (strcmp(name, pipeline->name) == 0)
  70                        return pipeline;
  71
  72        return NULL;
  73}
  74
  75struct pipeline *
  76pipeline_create(const char *name, struct pipeline_params *params)
  77{
  78        char msgq_name[NAME_MAX];
  79        struct rte_pipeline_params pp;
  80        struct pipeline *pipeline;
  81        struct rte_pipeline *p;
  82        struct rte_ring *msgq_req;
  83        struct rte_ring *msgq_rsp;
  84
  85        /* Check input params */
  86        if ((name == NULL) ||
  87                pipeline_find(name) ||
  88                (params == NULL) ||
  89                (params->timer_period_ms == 0))
  90                return NULL;
  91
  92        /* Resource create */
  93        snprintf(msgq_name, sizeof(msgq_name), "%s-MSGQ-REQ", name);
  94
  95        msgq_req = rte_ring_create(msgq_name,
  96                PIPELINE_MSGQ_SIZE,
  97                params->cpu_id,
  98                RING_F_SP_ENQ | RING_F_SC_DEQ);
  99        if (msgq_req == NULL)
 100                return NULL;
 101
 102        snprintf(msgq_name, sizeof(msgq_name), "%s-MSGQ-RSP", name);
 103
 104        msgq_rsp = rte_ring_create(msgq_name,
 105                PIPELINE_MSGQ_SIZE,
 106                params->cpu_id,
 107                RING_F_SP_ENQ | RING_F_SC_DEQ);
 108        if (msgq_rsp == NULL) {
 109                rte_ring_free(msgq_req);
 110                return NULL;
 111        }
 112
 113        pp.name = name;
 114        pp.socket_id = (int) params->cpu_id;
 115        pp.offset_port_id = params->offset_port_id;
 116
 117        p = rte_pipeline_create(&pp);
 118        if (p == NULL) {
 119                rte_ring_free(msgq_rsp);
 120                rte_ring_free(msgq_req);
 121                return NULL;
 122        }
 123
 124        /* Node allocation */
 125        pipeline = calloc(1, sizeof(struct pipeline));
 126        if (pipeline == NULL) {
 127                rte_pipeline_free(p);
 128                rte_ring_free(msgq_rsp);
 129                rte_ring_free(msgq_req);
 130                return NULL;
 131        }
 132
 133        /* Node fill in */
 134        strlcpy(pipeline->name, name, sizeof(pipeline->name));
 135        pipeline->p = p;
 136        pipeline->n_ports_in = 0;
 137        pipeline->n_ports_out = 0;
 138        pipeline->n_tables = 0;
 139        pipeline->msgq_req = msgq_req;
 140        pipeline->msgq_rsp = msgq_rsp;
 141        pipeline->timer_period_ms = params->timer_period_ms;
 142        pipeline->enabled = 0;
 143        pipeline->cpu_id = params->cpu_id;
 144
 145        /* Node add to list */
 146        TAILQ_INSERT_TAIL(&pipeline_list, pipeline, node);
 147
 148        return pipeline;
 149}
 150
 151int
 152pipeline_port_in_create(const char *pipeline_name,
 153        struct port_in_params *params,
 154        int enabled)
 155{
 156        struct rte_pipeline_port_in_params p;
 157
 158        union {
 159                struct rte_port_ethdev_reader_params ethdev;
 160                struct rte_port_ring_reader_params ring;
 161                struct rte_port_sched_reader_params sched;
 162                struct rte_port_fd_reader_params fd;
 163#ifdef RTE_LIB_KNI
 164                struct rte_port_kni_reader_params kni;
 165#endif
 166                struct rte_port_source_params source;
 167                struct rte_port_sym_crypto_reader_params sym_crypto;
 168        } pp;
 169
 170        struct pipeline *pipeline;
 171        struct port_in *port_in;
 172        struct port_in_action_profile *ap;
 173        struct rte_port_in_action *action;
 174        uint32_t port_id;
 175        int status;
 176
 177        memset(&p, 0, sizeof(p));
 178        memset(&pp, 0, sizeof(pp));
 179
 180        /* Check input params */
 181        if ((pipeline_name == NULL) ||
 182                (params == NULL) ||
 183                (params->burst_size == 0) ||
 184                (params->burst_size > RTE_PORT_IN_BURST_SIZE_MAX))
 185                return -1;
 186
 187        pipeline = pipeline_find(pipeline_name);
 188        if (pipeline == NULL)
 189                return -1;
 190
 191        ap = NULL;
 192        if (params->action_profile_name) {
 193                ap = port_in_action_profile_find(params->action_profile_name);
 194                if (ap == NULL)
 195                        return -1;
 196        }
 197
 198        switch (params->type) {
 199        case PORT_IN_RXQ:
 200        {
 201                struct link *link;
 202
 203                link = link_find(params->dev_name);
 204                if (link == NULL)
 205                        return -1;
 206
 207                if (params->rxq.queue_id >= link->n_rxq)
 208                        return -1;
 209
 210                pp.ethdev.port_id = link->port_id;
 211                pp.ethdev.queue_id = params->rxq.queue_id;
 212
 213                p.ops = &rte_port_ethdev_reader_ops;
 214                p.arg_create = &pp.ethdev;
 215                break;
 216        }
 217
 218        case PORT_IN_SWQ:
 219        {
 220                struct swq *swq;
 221
 222                swq = swq_find(params->dev_name);
 223                if (swq == NULL)
 224                        return -1;
 225
 226                pp.ring.ring = swq->r;
 227
 228                p.ops = &rte_port_ring_reader_ops;
 229                p.arg_create = &pp.ring;
 230                break;
 231        }
 232
 233        case PORT_IN_TMGR:
 234        {
 235                struct tmgr_port *tmgr_port;
 236
 237                tmgr_port = tmgr_port_find(params->dev_name);
 238                if (tmgr_port == NULL)
 239                        return -1;
 240
 241                pp.sched.sched = tmgr_port->s;
 242
 243                p.ops = &rte_port_sched_reader_ops;
 244                p.arg_create = &pp.sched;
 245                break;
 246        }
 247
 248        case PORT_IN_TAP:
 249        {
 250                struct tap *tap;
 251                struct mempool *mempool;
 252
 253                tap = tap_find(params->dev_name);
 254                mempool = mempool_find(params->tap.mempool_name);
 255                if ((tap == NULL) || (mempool == NULL))
 256                        return -1;
 257
 258                pp.fd.fd = tap->fd;
 259                pp.fd.mempool = mempool->m;
 260                pp.fd.mtu = params->tap.mtu;
 261
 262                p.ops = &rte_port_fd_reader_ops;
 263                p.arg_create = &pp.fd;
 264                break;
 265        }
 266
 267#ifdef RTE_LIB_KNI
 268        case PORT_IN_KNI:
 269        {
 270                struct kni *kni;
 271
 272                kni = kni_find(params->dev_name);
 273                if (kni == NULL)
 274                        return -1;
 275
 276                pp.kni.kni = kni->k;
 277
 278                p.ops = &rte_port_kni_reader_ops;
 279                p.arg_create = &pp.kni;
 280                break;
 281        }
 282#endif
 283
 284        case PORT_IN_SOURCE:
 285        {
 286                struct mempool *mempool;
 287
 288                mempool = mempool_find(params->source.mempool_name);
 289                if (mempool == NULL)
 290                        return -1;
 291
 292                pp.source.mempool = mempool->m;
 293                pp.source.file_name = params->source.file_name;
 294                pp.source.n_bytes_per_pkt = params->source.n_bytes_per_pkt;
 295
 296                p.ops = &rte_port_source_ops;
 297                p.arg_create = &pp.source;
 298                break;
 299        }
 300
 301        case PORT_IN_CRYPTODEV:
 302        {
 303                struct cryptodev *cryptodev;
 304
 305                cryptodev = cryptodev_find(params->dev_name);
 306                if (cryptodev == NULL)
 307                        return -1;
 308
 309                if (params->rxq.queue_id > cryptodev->n_queues - 1)
 310                        return -1;
 311
 312                pp.sym_crypto.cryptodev_id = cryptodev->dev_id;
 313                pp.sym_crypto.queue_id = params->cryptodev.queue_id;
 314                pp.sym_crypto.f_callback = params->cryptodev.f_callback;
 315                pp.sym_crypto.arg_callback = params->cryptodev.arg_callback;
 316                p.ops = &rte_port_sym_crypto_reader_ops;
 317                p.arg_create = &pp.sym_crypto;
 318
 319                break;
 320        }
 321
 322        default:
 323                return -1;
 324        }
 325
 326        p.burst_size = params->burst_size;
 327
 328        /* Resource create */
 329        action = NULL;
 330        p.f_action = NULL;
 331        p.arg_ah = NULL;
 332
 333        if (ap) {
 334                action = rte_port_in_action_create(ap->ap,
 335                        pipeline->cpu_id);
 336                if (action == NULL)
 337                        return -1;
 338
 339                status = rte_port_in_action_params_get(
 340                        action,
 341                        &p);
 342                if (status) {
 343                        rte_port_in_action_free(action);
 344                        return -1;
 345                }
 346        }
 347
 348        status = rte_pipeline_port_in_create(pipeline->p,
 349                &p,
 350                &port_id);
 351        if (status) {
 352                rte_port_in_action_free(action);
 353                return -1;
 354        }
 355
 356        if (enabled)
 357                rte_pipeline_port_in_enable(pipeline->p, port_id);
 358
 359        /* Pipeline */
 360        port_in = &pipeline->port_in[pipeline->n_ports_in];
 361        memcpy(&port_in->params, params, sizeof(*params));
 362        port_in->ap = ap;
 363        port_in->a = action;
 364        pipeline->n_ports_in++;
 365
 366        return 0;
 367}
 368
 369int
 370pipeline_port_in_connect_to_table(const char *pipeline_name,
 371        uint32_t port_id,
 372        uint32_t table_id)
 373{
 374        struct pipeline *pipeline;
 375        int status;
 376
 377        /* Check input params */
 378        if (pipeline_name == NULL)
 379                return -1;
 380
 381        pipeline = pipeline_find(pipeline_name);
 382        if ((pipeline == NULL) ||
 383                (port_id >= pipeline->n_ports_in) ||
 384                (table_id >= pipeline->n_tables))
 385                return -1;
 386
 387        /* Resource */
 388        status = rte_pipeline_port_in_connect_to_table(pipeline->p,
 389                port_id,
 390                table_id);
 391
 392        return status;
 393
 394}
 395
 396int
 397pipeline_port_out_create(const char *pipeline_name,
 398        struct port_out_params *params)
 399{
 400        struct rte_pipeline_port_out_params p;
 401
 402        union {
 403                struct rte_port_ethdev_writer_params ethdev;
 404                struct rte_port_ring_writer_params ring;
 405                struct rte_port_sched_writer_params sched;
 406                struct rte_port_fd_writer_params fd;
 407#ifdef RTE_LIB_KNI
 408                struct rte_port_kni_writer_params kni;
 409#endif
 410                struct rte_port_sink_params sink;
 411                struct rte_port_sym_crypto_writer_params sym_crypto;
 412        } pp;
 413
 414        union {
 415                struct rte_port_ethdev_writer_nodrop_params ethdev;
 416                struct rte_port_ring_writer_nodrop_params ring;
 417                struct rte_port_fd_writer_nodrop_params fd;
 418#ifdef RTE_LIB_KNI
 419                struct rte_port_kni_writer_nodrop_params kni;
 420#endif
 421                struct rte_port_sym_crypto_writer_nodrop_params sym_crypto;
 422        } pp_nodrop;
 423
 424        struct pipeline *pipeline;
 425        uint32_t port_id;
 426        int status;
 427
 428        memset(&p, 0, sizeof(p));
 429        memset(&pp, 0, sizeof(pp));
 430        memset(&pp_nodrop, 0, sizeof(pp_nodrop));
 431
 432        /* Check input params */
 433        if ((pipeline_name == NULL) ||
 434                (params == NULL) ||
 435                (params->burst_size == 0) ||
 436                (params->burst_size > RTE_PORT_IN_BURST_SIZE_MAX))
 437                return -1;
 438
 439        pipeline = pipeline_find(pipeline_name);
 440        if (pipeline == NULL)
 441                return -1;
 442
 443        switch (params->type) {
 444        case PORT_OUT_TXQ:
 445        {
 446                struct link *link;
 447
 448                link = link_find(params->dev_name);
 449                if (link == NULL)
 450                        return -1;
 451
 452                if (params->txq.queue_id >= link->n_txq)
 453                        return -1;
 454
 455                pp.ethdev.port_id = link->port_id;
 456                pp.ethdev.queue_id = params->txq.queue_id;
 457                pp.ethdev.tx_burst_sz = params->burst_size;
 458
 459                pp_nodrop.ethdev.port_id = link->port_id;
 460                pp_nodrop.ethdev.queue_id = params->txq.queue_id;
 461                pp_nodrop.ethdev.tx_burst_sz = params->burst_size;
 462                pp_nodrop.ethdev.n_retries = params->n_retries;
 463
 464                if (params->retry == 0) {
 465                        p.ops = &rte_port_ethdev_writer_ops;
 466                        p.arg_create = &pp.ethdev;
 467                } else {
 468                        p.ops = &rte_port_ethdev_writer_nodrop_ops;
 469                        p.arg_create = &pp_nodrop.ethdev;
 470                }
 471                break;
 472        }
 473
 474        case PORT_OUT_SWQ:
 475        {
 476                struct swq *swq;
 477
 478                swq = swq_find(params->dev_name);
 479                if (swq == NULL)
 480                        return -1;
 481
 482                pp.ring.ring = swq->r;
 483                pp.ring.tx_burst_sz = params->burst_size;
 484
 485                pp_nodrop.ring.ring = swq->r;
 486                pp_nodrop.ring.tx_burst_sz = params->burst_size;
 487                pp_nodrop.ring.n_retries = params->n_retries;
 488
 489                if (params->retry == 0) {
 490                        p.ops = &rte_port_ring_writer_ops;
 491                        p.arg_create = &pp.ring;
 492                } else {
 493                        p.ops = &rte_port_ring_writer_nodrop_ops;
 494                        p.arg_create = &pp_nodrop.ring;
 495                }
 496                break;
 497        }
 498
 499        case PORT_OUT_TMGR:
 500        {
 501                struct tmgr_port *tmgr_port;
 502
 503                tmgr_port = tmgr_port_find(params->dev_name);
 504                if (tmgr_port == NULL)
 505                        return -1;
 506
 507                pp.sched.sched = tmgr_port->s;
 508                pp.sched.tx_burst_sz = params->burst_size;
 509
 510                p.ops = &rte_port_sched_writer_ops;
 511                p.arg_create = &pp.sched;
 512                break;
 513        }
 514
 515        case PORT_OUT_TAP:
 516        {
 517                struct tap *tap;
 518
 519                tap = tap_find(params->dev_name);
 520                if (tap == NULL)
 521                        return -1;
 522
 523                pp.fd.fd = tap->fd;
 524                pp.fd.tx_burst_sz = params->burst_size;
 525
 526                pp_nodrop.fd.fd = tap->fd;
 527                pp_nodrop.fd.tx_burst_sz = params->burst_size;
 528                pp_nodrop.fd.n_retries = params->n_retries;
 529
 530                if (params->retry == 0) {
 531                        p.ops = &rte_port_fd_writer_ops;
 532                        p.arg_create = &pp.fd;
 533                } else {
 534                        p.ops = &rte_port_fd_writer_nodrop_ops;
 535                        p.arg_create = &pp_nodrop.fd;
 536                }
 537                break;
 538        }
 539
 540#ifdef RTE_LIB_KNI
 541        case PORT_OUT_KNI:
 542        {
 543                struct kni *kni;
 544
 545                kni = kni_find(params->dev_name);
 546                if (kni == NULL)
 547                        return -1;
 548
 549                pp.kni.kni = kni->k;
 550                pp.kni.tx_burst_sz = params->burst_size;
 551
 552                pp_nodrop.kni.kni = kni->k;
 553                pp_nodrop.kni.tx_burst_sz = params->burst_size;
 554                pp_nodrop.kni.n_retries = params->n_retries;
 555
 556                if (params->retry == 0) {
 557                        p.ops = &rte_port_kni_writer_ops;
 558                        p.arg_create = &pp.kni;
 559                } else {
 560                        p.ops = &rte_port_kni_writer_nodrop_ops;
 561                        p.arg_create = &pp_nodrop.kni;
 562                }
 563                break;
 564        }
 565#endif
 566
 567        case PORT_OUT_SINK:
 568        {
 569                pp.sink.file_name = params->sink.file_name;
 570                pp.sink.max_n_pkts = params->sink.max_n_pkts;
 571
 572                p.ops = &rte_port_sink_ops;
 573                p.arg_create = &pp.sink;
 574                break;
 575        }
 576
 577        case PORT_OUT_CRYPTODEV:
 578        {
 579                struct cryptodev *cryptodev;
 580
 581                cryptodev = cryptodev_find(params->dev_name);
 582                if (cryptodev == NULL)
 583                        return -1;
 584
 585                if (params->cryptodev.queue_id >= cryptodev->n_queues)
 586                        return -1;
 587
 588                pp.sym_crypto.cryptodev_id = cryptodev->dev_id;
 589                pp.sym_crypto.queue_id = params->cryptodev.queue_id;
 590                pp.sym_crypto.tx_burst_sz = params->burst_size;
 591                pp.sym_crypto.crypto_op_offset = params->cryptodev.op_offset;
 592
 593                pp_nodrop.sym_crypto.cryptodev_id = cryptodev->dev_id;
 594                pp_nodrop.sym_crypto.queue_id = params->cryptodev.queue_id;
 595                pp_nodrop.sym_crypto.tx_burst_sz = params->burst_size;
 596                pp_nodrop.sym_crypto.n_retries = params->retry;
 597                pp_nodrop.sym_crypto.crypto_op_offset =
 598                                params->cryptodev.op_offset;
 599
 600                if (params->retry == 0) {
 601                        p.ops = &rte_port_sym_crypto_writer_ops;
 602                        p.arg_create = &pp.sym_crypto;
 603                } else {
 604                        p.ops = &rte_port_sym_crypto_writer_nodrop_ops;
 605                        p.arg_create = &pp_nodrop.sym_crypto;
 606                }
 607
 608                break;
 609        }
 610
 611        default:
 612                return -1;
 613        }
 614
 615        p.f_action = NULL;
 616        p.arg_ah = NULL;
 617
 618        /* Resource create */
 619        status = rte_pipeline_port_out_create(pipeline->p,
 620                &p,
 621                &port_id);
 622
 623        if (status)
 624                return -1;
 625
 626        /* Pipeline */
 627        pipeline->n_ports_out++;
 628
 629        return 0;
 630}
 631
 632static const struct rte_acl_field_def table_acl_field_format_ipv4[] = {
 633        /* Protocol */
 634        [0] = {
 635                .type = RTE_ACL_FIELD_TYPE_BITMASK,
 636                .size = sizeof(uint8_t),
 637                .field_index = 0,
 638                .input_index = 0,
 639                .offset = offsetof(struct rte_ipv4_hdr, next_proto_id),
 640        },
 641
 642        /* Source IP address (IPv4) */
 643        [1] = {
 644                .type = RTE_ACL_FIELD_TYPE_MASK,
 645                .size = sizeof(uint32_t),
 646                .field_index = 1,
 647                .input_index = 1,
 648                .offset = offsetof(struct rte_ipv4_hdr, src_addr),
 649        },
 650
 651        /* Destination IP address (IPv4) */
 652        [2] = {
 653                .type = RTE_ACL_FIELD_TYPE_MASK,
 654                .size = sizeof(uint32_t),
 655                .field_index = 2,
 656                .input_index = 2,
 657                .offset = offsetof(struct rte_ipv4_hdr, dst_addr),
 658        },
 659
 660        /* Source Port */
 661        [3] = {
 662                .type = RTE_ACL_FIELD_TYPE_RANGE,
 663                .size = sizeof(uint16_t),
 664                .field_index = 3,
 665                .input_index = 3,
 666                .offset = sizeof(struct rte_ipv4_hdr) +
 667                        offsetof(struct rte_tcp_hdr, src_port),
 668        },
 669
 670        /* Destination Port */
 671        [4] = {
 672                .type = RTE_ACL_FIELD_TYPE_RANGE,
 673                .size = sizeof(uint16_t),
 674                .field_index = 4,
 675                .input_index = 3,
 676                .offset = sizeof(struct rte_ipv4_hdr) +
 677                        offsetof(struct rte_tcp_hdr, dst_port),
 678        },
 679};
 680
 681static const struct rte_acl_field_def table_acl_field_format_ipv6[] = {
 682        /* Protocol */
 683        [0] = {
 684                .type = RTE_ACL_FIELD_TYPE_BITMASK,
 685                .size = sizeof(uint8_t),
 686                .field_index = 0,
 687                .input_index = 0,
 688                .offset = offsetof(struct rte_ipv6_hdr, proto),
 689        },
 690
 691        /* Source IP address (IPv6) */
 692        [1] = {
 693                .type = RTE_ACL_FIELD_TYPE_MASK,
 694                .size = sizeof(uint32_t),
 695                .field_index = 1,
 696                .input_index = 1,
 697                .offset = offsetof(struct rte_ipv6_hdr, src_addr[0]),
 698        },
 699
 700        [2] = {
 701                .type = RTE_ACL_FIELD_TYPE_MASK,
 702                .size = sizeof(uint32_t),
 703                .field_index = 2,
 704                .input_index = 2,
 705                .offset = offsetof(struct rte_ipv6_hdr, src_addr[4]),
 706        },
 707
 708        [3] = {
 709                .type = RTE_ACL_FIELD_TYPE_MASK,
 710                .size = sizeof(uint32_t),
 711                .field_index = 3,
 712                .input_index = 3,
 713                .offset = offsetof(struct rte_ipv6_hdr, src_addr[8]),
 714        },
 715
 716        [4] = {
 717                .type = RTE_ACL_FIELD_TYPE_MASK,
 718                .size = sizeof(uint32_t),
 719                .field_index = 4,
 720                .input_index = 4,
 721                .offset = offsetof(struct rte_ipv6_hdr, src_addr[12]),
 722        },
 723
 724        /* Destination IP address (IPv6) */
 725        [5] = {
 726                .type = RTE_ACL_FIELD_TYPE_MASK,
 727                .size = sizeof(uint32_t),
 728                .field_index = 5,
 729                .input_index = 5,
 730                .offset = offsetof(struct rte_ipv6_hdr, dst_addr[0]),
 731        },
 732
 733        [6] = {
 734                .type = RTE_ACL_FIELD_TYPE_MASK,
 735                .size = sizeof(uint32_t),
 736                .field_index = 6,
 737                .input_index = 6,
 738                .offset = offsetof(struct rte_ipv6_hdr, dst_addr[4]),
 739        },
 740
 741        [7] = {
 742                .type = RTE_ACL_FIELD_TYPE_MASK,
 743                .size = sizeof(uint32_t),
 744                .field_index = 7,
 745                .input_index = 7,
 746                .offset = offsetof(struct rte_ipv6_hdr, dst_addr[8]),
 747        },
 748
 749        [8] = {
 750                .type = RTE_ACL_FIELD_TYPE_MASK,
 751                .size = sizeof(uint32_t),
 752                .field_index = 8,
 753                .input_index = 8,
 754                .offset = offsetof(struct rte_ipv6_hdr, dst_addr[12]),
 755        },
 756
 757        /* Source Port */
 758        [9] = {
 759                .type = RTE_ACL_FIELD_TYPE_RANGE,
 760                .size = sizeof(uint16_t),
 761                .field_index = 9,
 762                .input_index = 9,
 763                .offset = sizeof(struct rte_ipv6_hdr) +
 764                        offsetof(struct rte_tcp_hdr, src_port),
 765        },
 766
 767        /* Destination Port */
 768        [10] = {
 769                .type = RTE_ACL_FIELD_TYPE_RANGE,
 770                .size = sizeof(uint16_t),
 771                .field_index = 10,
 772                .input_index = 9,
 773                .offset = sizeof(struct rte_ipv6_hdr) +
 774                        offsetof(struct rte_tcp_hdr, dst_port),
 775        },
 776};
 777
 778int
 779pipeline_table_create(const char *pipeline_name,
 780        struct table_params *params)
 781{
 782        char name[NAME_MAX];
 783        struct rte_pipeline_table_params p;
 784
 785        union {
 786                struct rte_table_acl_params acl;
 787                struct rte_table_array_params array;
 788                struct rte_table_hash_params hash;
 789                struct rte_table_lpm_params lpm;
 790                struct rte_table_lpm_ipv6_params lpm_ipv6;
 791        } pp;
 792
 793        struct pipeline *pipeline;
 794        struct table *table;
 795        struct table_action_profile *ap;
 796        struct rte_table_action *action;
 797        uint32_t table_id;
 798        int status;
 799
 800        memset(&p, 0, sizeof(p));
 801        memset(&pp, 0, sizeof(pp));
 802
 803        /* Check input params */
 804        if ((pipeline_name == NULL) ||
 805                (params == NULL))
 806                return -1;
 807
 808        pipeline = pipeline_find(pipeline_name);
 809        if ((pipeline == NULL) ||
 810                (pipeline->n_tables >= RTE_PIPELINE_TABLE_MAX))
 811                return -1;
 812
 813        ap = NULL;
 814        if (params->action_profile_name) {
 815                ap = table_action_profile_find(params->action_profile_name);
 816                if (ap == NULL)
 817                        return -1;
 818        }
 819
 820        snprintf(name, NAME_MAX, "%s_table%u",
 821                pipeline_name, pipeline->n_tables);
 822
 823        switch (params->match_type) {
 824        case TABLE_ACL:
 825        {
 826                uint32_t ip_header_offset = params->match.acl.ip_header_offset -
 827                        (sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM);
 828                uint32_t i;
 829
 830                if (params->match.acl.n_rules == 0)
 831                        return -1;
 832
 833                pp.acl.name = name;
 834                pp.acl.n_rules = params->match.acl.n_rules;
 835                if (params->match.acl.ip_version) {
 836                        memcpy(&pp.acl.field_format,
 837                                &table_acl_field_format_ipv4,
 838                                sizeof(table_acl_field_format_ipv4));
 839                        pp.acl.n_rule_fields =
 840                                RTE_DIM(table_acl_field_format_ipv4);
 841                } else {
 842                        memcpy(&pp.acl.field_format,
 843                                &table_acl_field_format_ipv6,
 844                                sizeof(table_acl_field_format_ipv6));
 845                        pp.acl.n_rule_fields =
 846                                RTE_DIM(table_acl_field_format_ipv6);
 847                }
 848
 849                for (i = 0; i < pp.acl.n_rule_fields; i++)
 850                        pp.acl.field_format[i].offset += ip_header_offset;
 851
 852                p.ops = &rte_table_acl_ops;
 853                p.arg_create = &pp.acl;
 854                break;
 855        }
 856
 857        case TABLE_ARRAY:
 858        {
 859                if (params->match.array.n_keys == 0)
 860                        return -1;
 861
 862                pp.array.n_entries = params->match.array.n_keys;
 863                pp.array.offset = params->match.array.key_offset;
 864
 865                p.ops = &rte_table_array_ops;
 866                p.arg_create = &pp.array;
 867                break;
 868        }
 869
 870        case TABLE_HASH:
 871        {
 872                struct rte_table_ops *ops;
 873                rte_table_hash_op_hash f_hash;
 874
 875                if (params->match.hash.n_keys == 0)
 876                        return -1;
 877
 878                switch (params->match.hash.key_size) {
 879                case  8:
 880                        f_hash = rte_table_hash_crc_key8;
 881                        break;
 882                case 16:
 883                        f_hash = rte_table_hash_crc_key16;
 884                        break;
 885                case 24:
 886                        f_hash = rte_table_hash_crc_key24;
 887                        break;
 888                case 32:
 889                        f_hash = rte_table_hash_crc_key32;
 890                        break;
 891                case 40:
 892                        f_hash = rte_table_hash_crc_key40;
 893                        break;
 894                case 48:
 895                        f_hash = rte_table_hash_crc_key48;
 896                        break;
 897                case 56:
 898                        f_hash = rte_table_hash_crc_key56;
 899                        break;
 900                case 64:
 901                        f_hash = rte_table_hash_crc_key64;
 902                        break;
 903                default:
 904                        return -1;
 905                }
 906
 907                pp.hash.name = name;
 908                pp.hash.key_size = params->match.hash.key_size;
 909                pp.hash.key_offset = params->match.hash.key_offset;
 910                pp.hash.key_mask = params->match.hash.key_mask;
 911                pp.hash.n_keys = params->match.hash.n_keys;
 912                pp.hash.n_buckets = params->match.hash.n_buckets;
 913                pp.hash.f_hash = f_hash;
 914                pp.hash.seed = 0;
 915
 916                if (params->match.hash.extendable_bucket)
 917                        switch (params->match.hash.key_size) {
 918                        case  8:
 919                                ops = &rte_table_hash_key8_ext_ops;
 920                                break;
 921                        case 16:
 922                                ops = &rte_table_hash_key16_ext_ops;
 923                                break;
 924                        default:
 925                                ops = &rte_table_hash_ext_ops;
 926                        }
 927                else
 928                        switch (params->match.hash.key_size) {
 929                        case  8:
 930                                ops = &rte_table_hash_key8_lru_ops;
 931                                break;
 932                        case 16:
 933                                ops = &rte_table_hash_key16_lru_ops;
 934                                break;
 935                        default:
 936                                ops = &rte_table_hash_lru_ops;
 937                        }
 938
 939                p.ops = ops;
 940                p.arg_create = &pp.hash;
 941                break;
 942        }
 943
 944        case TABLE_LPM:
 945        {
 946                if (params->match.lpm.n_rules == 0)
 947                        return -1;
 948
 949                switch (params->match.lpm.key_size) {
 950                case 4:
 951                {
 952                        pp.lpm.name = name;
 953                        pp.lpm.n_rules = params->match.lpm.n_rules;
 954                        pp.lpm.number_tbl8s = TABLE_LPM_NUMBER_TBL8;
 955                        pp.lpm.flags = 0;
 956                        pp.lpm.entry_unique_size = p.action_data_size +
 957                                sizeof(struct rte_pipeline_table_entry);
 958                        pp.lpm.offset = params->match.lpm.key_offset;
 959
 960                        p.ops = &rte_table_lpm_ops;
 961                        p.arg_create = &pp.lpm;
 962                        break;
 963                }
 964
 965                case 16:
 966                {
 967                        pp.lpm_ipv6.name = name;
 968                        pp.lpm_ipv6.n_rules = params->match.lpm.n_rules;
 969                        pp.lpm_ipv6.number_tbl8s = TABLE_LPM_NUMBER_TBL8;
 970                        pp.lpm_ipv6.entry_unique_size = p.action_data_size +
 971                                sizeof(struct rte_pipeline_table_entry);
 972                        pp.lpm_ipv6.offset = params->match.lpm.key_offset;
 973
 974                        p.ops = &rte_table_lpm_ipv6_ops;
 975                        p.arg_create = &pp.lpm_ipv6;
 976                        break;
 977                }
 978
 979                default:
 980                        return -1;
 981                }
 982
 983                break;
 984        }
 985
 986        case TABLE_STUB:
 987        {
 988                p.ops = &rte_table_stub_ops;
 989                p.arg_create = NULL;
 990                break;
 991        }
 992
 993        default:
 994                return -1;
 995        }
 996
 997        /* Resource create */
 998        action = NULL;
 999        p.f_action_hit = NULL;
1000        p.f_action_miss = NULL;
1001        p.arg_ah = NULL;
1002
1003        if (ap) {
1004                action = rte_table_action_create(ap->ap,
1005                        pipeline->cpu_id);
1006                if (action == NULL)
1007                        return -1;
1008
1009                status = rte_table_action_table_params_get(
1010                        action,
1011                        &p);
1012                if (status ||
1013                        ((p.action_data_size +
1014                        sizeof(struct rte_pipeline_table_entry)) >
1015                        TABLE_RULE_ACTION_SIZE_MAX)) {
1016                        rte_table_action_free(action);
1017                        return -1;
1018                }
1019        }
1020
1021        if (params->match_type == TABLE_LPM) {
1022                if (params->match.lpm.key_size == 4)
1023                        pp.lpm.entry_unique_size = p.action_data_size +
1024                                sizeof(struct rte_pipeline_table_entry);
1025
1026                if (params->match.lpm.key_size == 16)
1027                        pp.lpm_ipv6.entry_unique_size = p.action_data_size +
1028                                sizeof(struct rte_pipeline_table_entry);
1029        }
1030
1031        status = rte_pipeline_table_create(pipeline->p,
1032                &p,
1033                &table_id);
1034        if (status) {
1035                rte_table_action_free(action);
1036                return -1;
1037        }
1038
1039        /* Pipeline */
1040        table = &pipeline->table[pipeline->n_tables];
1041        memcpy(&table->params, params, sizeof(*params));
1042        table->ap = ap;
1043        table->a = action;
1044        TAILQ_INIT(&table->rules);
1045        table->rule_default = NULL;
1046
1047        pipeline->n_tables++;
1048
1049        return 0;
1050}
1051
1052struct table_rule *
1053table_rule_find(struct table *table,
1054    struct table_rule_match *match)
1055{
1056        struct table_rule *rule;
1057
1058        TAILQ_FOREACH(rule, &table->rules, node)
1059                if (memcmp(&rule->match, match, sizeof(*match)) == 0)
1060                        return rule;
1061
1062        return NULL;
1063}
1064
1065void
1066table_rule_add(struct table *table,
1067    struct table_rule *new_rule)
1068{
1069        struct table_rule *existing_rule;
1070
1071        existing_rule = table_rule_find(table, &new_rule->match);
1072        if (existing_rule == NULL)
1073                TAILQ_INSERT_TAIL(&table->rules, new_rule, node);
1074        else {
1075                TAILQ_INSERT_AFTER(&table->rules, existing_rule, new_rule, node);
1076                TAILQ_REMOVE(&table->rules, existing_rule, node);
1077                free(existing_rule);
1078        }
1079}
1080
1081void
1082table_rule_add_bulk(struct table *table,
1083    struct table_rule_list *list,
1084    uint32_t n_rules)
1085{
1086        uint32_t i;
1087
1088        for (i = 0; i < n_rules; i++) {
1089                struct table_rule *existing_rule, *new_rule;
1090
1091                new_rule = TAILQ_FIRST(list);
1092                if (new_rule == NULL)
1093                        break;
1094
1095                TAILQ_REMOVE(list, new_rule, node);
1096
1097                existing_rule = table_rule_find(table, &new_rule->match);
1098                if (existing_rule == NULL)
1099                        TAILQ_INSERT_TAIL(&table->rules, new_rule, node);
1100                else {
1101                        TAILQ_INSERT_AFTER(&table->rules, existing_rule, new_rule, node);
1102                        TAILQ_REMOVE(&table->rules, existing_rule, node);
1103                        free(existing_rule);
1104                }
1105        }
1106}
1107
1108void
1109table_rule_delete(struct table *table,
1110    struct table_rule_match *match)
1111{
1112        struct table_rule *rule;
1113
1114        rule = table_rule_find(table, match);
1115        if (rule == NULL)
1116                return;
1117
1118        TAILQ_REMOVE(&table->rules, rule, node);
1119        free(rule);
1120}
1121
1122void
1123table_rule_default_add(struct table *table,
1124        struct table_rule *rule)
1125{
1126        free(table->rule_default);
1127        table->rule_default = rule;
1128}
1129
1130void
1131table_rule_default_delete(struct table *table)
1132{
1133        free(table->rule_default);
1134        table->rule_default = NULL;
1135}
1136