dpdk/drivers/net/softnic/rte_eth_softnic_thread.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright(c) 2010-2018 Intel Corporation
   3 */
   4
   5#include <stdlib.h>
   6
   7#include <rte_common.h>
   8#include <rte_cycles.h>
   9#include <rte_lcore.h>
  10#include <rte_service_component.h>
  11#include <rte_ring.h>
  12
  13#include <rte_table_acl.h>
  14#include <rte_table_array.h>
  15#include <rte_table_hash.h>
  16#include <rte_table_lpm.h>
  17#include <rte_table_lpm_ipv6.h>
  18#include "rte_eth_softnic_internals.h"
  19
  20/**
  21 * Main thread: data plane thread init
  22 */
  23void
  24softnic_thread_free(struct pmd_internals *softnic)
  25{
  26        uint32_t i;
  27
  28        RTE_LCORE_FOREACH_WORKER(i) {
  29                struct softnic_thread *t = &softnic->thread[i];
  30
  31                /* MSGQs */
  32                if (t->msgq_req)
  33                        rte_ring_free(t->msgq_req);
  34
  35                if (t->msgq_rsp)
  36                        rte_ring_free(t->msgq_rsp);
  37        }
  38}
  39
  40int
  41softnic_thread_init(struct pmd_internals *softnic)
  42{
  43        uint32_t i;
  44
  45        for (i = 0; i < RTE_MAX_LCORE; i++) {
  46                char ring_name[NAME_MAX];
  47                struct rte_ring *msgq_req, *msgq_rsp;
  48                struct softnic_thread *t = &softnic->thread[i];
  49                struct softnic_thread_data *t_data = &softnic->thread_data[i];
  50                uint32_t cpu_id = rte_lcore_to_socket_id(i);
  51
  52                /* MSGQs */
  53                snprintf(ring_name, sizeof(ring_name), "%s-TH%u-REQ",
  54                        softnic->params.name,
  55                        i);
  56
  57                msgq_req = rte_ring_create(ring_name,
  58                        THREAD_MSGQ_SIZE,
  59                        cpu_id,
  60                        RING_F_SP_ENQ | RING_F_SC_DEQ);
  61
  62                if (msgq_req == NULL) {
  63                        softnic_thread_free(softnic);
  64                        return -1;
  65                }
  66
  67                snprintf(ring_name, sizeof(ring_name), "%s-TH%u-RSP",
  68                        softnic->params.name,
  69                        i);
  70
  71                msgq_rsp = rte_ring_create(ring_name,
  72                        THREAD_MSGQ_SIZE,
  73                        cpu_id,
  74                        RING_F_SP_ENQ | RING_F_SC_DEQ);
  75
  76                if (msgq_rsp == NULL) {
  77                        softnic_thread_free(softnic);
  78                        return -1;
  79                }
  80
  81                /* Main thread records */
  82                t->msgq_req = msgq_req;
  83                t->msgq_rsp = msgq_rsp;
  84                t->service_id = UINT32_MAX;
  85
  86                /* Data plane thread records */
  87                t_data->n_pipelines = 0;
  88                t_data->msgq_req = msgq_req;
  89                t_data->msgq_rsp = msgq_rsp;
  90                t_data->timer_period =
  91                        (rte_get_tsc_hz() * THREAD_TIMER_PERIOD_MS) / 1000;
  92                t_data->time_next = rte_get_tsc_cycles() + t_data->timer_period;
  93                t_data->time_next_min = t_data->time_next;
  94        }
  95
  96        return 0;
  97}
  98
  99static inline int
 100thread_is_valid(struct pmd_internals *softnic, uint32_t thread_id)
 101{
 102        if (thread_id == rte_get_main_lcore())
 103                return 0; /* FALSE */
 104
 105        if (softnic->params.sc && rte_lcore_has_role(thread_id, ROLE_SERVICE))
 106                return 1; /* TRUE */
 107        if (!softnic->params.sc && rte_lcore_has_role(thread_id, ROLE_RTE))
 108                return 1; /* TRUE */
 109
 110        return 0; /* FALSE */
 111}
 112
 113static inline int
 114thread_is_running(uint32_t thread_id)
 115{
 116        enum rte_lcore_state_t thread_state;
 117
 118        thread_state = rte_eal_get_lcore_state(thread_id);
 119        return (thread_state == RUNNING)? 1 : 0;
 120}
 121
 122static int32_t
 123rte_pmd_softnic_run_internal(void *arg);
 124
 125static inline int
 126thread_sc_service_up(struct pmd_internals *softnic, uint32_t thread_id)
 127{
 128        struct rte_service_spec service_params;
 129        struct softnic_thread *t = &softnic->thread[thread_id];
 130        struct rte_eth_dev *dev;
 131        int status;
 132        uint16_t port_id;
 133
 134        /* service params */
 135        status = rte_eth_dev_get_port_by_name(softnic->params.name, &port_id);
 136        if (status)
 137                return status;
 138
 139        dev = &rte_eth_devices[port_id];
 140        snprintf(service_params.name, sizeof(service_params.name), "%s_%u",
 141                softnic->params.name,
 142                thread_id);
 143        service_params.callback = rte_pmd_softnic_run_internal;
 144        service_params.callback_userdata = dev;
 145        service_params.capabilities = 0;
 146        service_params.socket_id = (int)softnic->params.cpu_id;
 147
 148        /* service register */
 149        status = rte_service_component_register(&service_params, &t->service_id);
 150        if (status)
 151                return status;
 152
 153        status = rte_service_component_runstate_set(t->service_id, 1);
 154        if (status) {
 155                rte_service_component_unregister(t->service_id);
 156                t->service_id = UINT32_MAX;
 157                return status;
 158        }
 159
 160        status = rte_service_runstate_set(t->service_id, 1);
 161        if (status) {
 162                rte_service_component_runstate_set(t->service_id, 0);
 163                rte_service_component_unregister(t->service_id);
 164                t->service_id = UINT32_MAX;
 165                return status;
 166        }
 167
 168        /* service map to thread */
 169        status = rte_service_map_lcore_set(t->service_id, thread_id, 1);
 170        if (status) {
 171                rte_service_runstate_set(t->service_id, 0);
 172                rte_service_component_runstate_set(t->service_id, 0);
 173                rte_service_component_unregister(t->service_id);
 174                t->service_id = UINT32_MAX;
 175                return status;
 176        }
 177
 178        return 0;
 179}
 180
 181static inline void
 182thread_sc_service_down(struct pmd_internals *softnic, uint32_t thread_id)
 183{
 184        struct softnic_thread *t = &softnic->thread[thread_id];
 185
 186        /* service unmap from thread */
 187        rte_service_map_lcore_set(t->service_id, thread_id, 0);
 188
 189        /* service unregister */
 190        rte_service_runstate_set(t->service_id, 0);
 191        rte_service_component_runstate_set(t->service_id, 0);
 192        rte_service_component_unregister(t->service_id);
 193
 194        t->service_id = UINT32_MAX;
 195}
 196
 197/**
 198 * Pipeline is running when:
 199 *    (A) Pipeline is mapped to a data plane thread AND
 200 *    (B) Its data plane thread is in RUNNING state.
 201 */
 202static inline int
 203pipeline_is_running(struct pipeline *p)
 204{
 205        if (p->enabled == 0)
 206                return 0;
 207
 208        return thread_is_running(p->thread_id);
 209}
 210
 211/**
 212 * Main thread & data plane threads: message passing
 213 */
 214enum thread_req_type {
 215        THREAD_REQ_PIPELINE_ENABLE = 0,
 216        THREAD_REQ_PIPELINE_DISABLE,
 217        THREAD_REQ_MAX
 218};
 219
 220struct thread_msg_req {
 221        enum thread_req_type type;
 222
 223        union {
 224                struct {
 225                        struct rte_pipeline *p;
 226                        struct {
 227                                struct rte_table_action *a;
 228                        } table[RTE_PIPELINE_TABLE_MAX];
 229                        struct rte_ring *msgq_req;
 230                        struct rte_ring *msgq_rsp;
 231                        uint32_t timer_period_ms;
 232                        uint32_t n_tables;
 233                } pipeline_enable;
 234
 235                struct {
 236                        struct rte_pipeline *p;
 237                } pipeline_disable;
 238        };
 239};
 240
 241struct thread_msg_rsp {
 242        int status;
 243};
 244
 245/**
 246 * Main thread
 247 */
 248static struct thread_msg_req *
 249thread_msg_alloc(void)
 250{
 251        size_t size = RTE_MAX(sizeof(struct thread_msg_req),
 252                sizeof(struct thread_msg_rsp));
 253
 254        return calloc(1, size);
 255}
 256
 257static void
 258thread_msg_free(struct thread_msg_rsp *rsp)
 259{
 260        free(rsp);
 261}
 262
 263static struct thread_msg_rsp *
 264thread_msg_send_recv(struct pmd_internals *softnic,
 265        uint32_t thread_id,
 266        struct thread_msg_req *req)
 267{
 268        struct softnic_thread *t = &softnic->thread[thread_id];
 269        struct rte_ring *msgq_req = t->msgq_req;
 270        struct rte_ring *msgq_rsp = t->msgq_rsp;
 271        struct thread_msg_rsp *rsp;
 272        int status;
 273
 274        /* send */
 275        do {
 276                status = rte_ring_sp_enqueue(msgq_req, req);
 277        } while (status == -ENOBUFS);
 278
 279        /* recv */
 280        do {
 281                status = rte_ring_sc_dequeue(msgq_rsp, (void **)&rsp);
 282        } while (status != 0);
 283
 284        return rsp;
 285}
 286
 287int
 288softnic_thread_pipeline_enable(struct pmd_internals *softnic,
 289        uint32_t thread_id,
 290        const char *pipeline_name)
 291{
 292        struct pipeline *p = softnic_pipeline_find(softnic, pipeline_name);
 293        struct thread_msg_req *req;
 294        struct thread_msg_rsp *rsp;
 295        uint32_t n_pipelines, i;
 296        int status;
 297
 298        /* Check input params */
 299        if (!thread_is_valid(softnic, thread_id) ||
 300                (p == NULL) ||
 301                (p->n_ports_in == 0) ||
 302                (p->n_ports_out == 0) ||
 303                (p->n_tables == 0) ||
 304                p->enabled)
 305                return -1;
 306
 307        n_pipelines = softnic_pipeline_thread_count(softnic, thread_id);
 308        if (n_pipelines >= THREAD_PIPELINES_MAX)
 309                return -1;
 310
 311        if (softnic->params.sc && (n_pipelines == 0)) {
 312                status = thread_sc_service_up(softnic, thread_id);
 313                if (status)
 314                        return status;
 315        }
 316
 317        if (!thread_is_running(thread_id)) {
 318                struct softnic_thread_data *td = &softnic->thread_data[thread_id];
 319                struct pipeline_data *tdp = &td->pipeline_data[td->n_pipelines];
 320
 321                /* Data plane thread */
 322                td->p[td->n_pipelines] = p->p;
 323
 324                tdp->p = p->p;
 325                for (i = 0; i < p->n_tables; i++)
 326                        tdp->table_data[i].a =
 327                                p->table[i].a;
 328                tdp->n_tables = p->n_tables;
 329
 330                tdp->msgq_req = p->msgq_req;
 331                tdp->msgq_rsp = p->msgq_rsp;
 332                tdp->timer_period = (rte_get_tsc_hz() * p->timer_period_ms) / 1000;
 333                tdp->time_next = rte_get_tsc_cycles() + tdp->timer_period;
 334
 335                td->n_pipelines++;
 336
 337                /* Pipeline */
 338                p->thread_id = thread_id;
 339                p->enabled = 1;
 340
 341                return 0;
 342        }
 343
 344        /* Allocate request */
 345        req = thread_msg_alloc();
 346        if (req == NULL)
 347                return -1;
 348
 349        /* Write request */
 350        req->type = THREAD_REQ_PIPELINE_ENABLE;
 351        req->pipeline_enable.p = p->p;
 352        for (i = 0; i < p->n_tables; i++)
 353                req->pipeline_enable.table[i].a =
 354                        p->table[i].a;
 355        req->pipeline_enable.msgq_req = p->msgq_req;
 356        req->pipeline_enable.msgq_rsp = p->msgq_rsp;
 357        req->pipeline_enable.timer_period_ms = p->timer_period_ms;
 358        req->pipeline_enable.n_tables = p->n_tables;
 359
 360        /* Send request and wait for response */
 361        rsp = thread_msg_send_recv(softnic, thread_id, req);
 362
 363        /* Read response */
 364        status = rsp->status;
 365
 366        /* Free response */
 367        thread_msg_free(rsp);
 368
 369        /* Request completion */
 370        if (status)
 371                return status;
 372
 373        p->thread_id = thread_id;
 374        p->enabled = 1;
 375
 376        return 0;
 377}
 378
 379int
 380softnic_thread_pipeline_disable(struct pmd_internals *softnic,
 381        uint32_t thread_id,
 382        const char *pipeline_name)
 383{
 384        struct pipeline *p = softnic_pipeline_find(softnic, pipeline_name);
 385        struct thread_msg_req *req;
 386        struct thread_msg_rsp *rsp;
 387        uint32_t n_pipelines;
 388        int status;
 389
 390        /* Check input params */
 391        if (!thread_is_valid(softnic, thread_id) ||
 392                (p == NULL) ||
 393                (p->enabled && (p->thread_id != thread_id)))
 394                return -1;
 395
 396        if (p->enabled == 0)
 397                return 0;
 398
 399        if (!thread_is_running(thread_id)) {
 400                struct softnic_thread_data *td = &softnic->thread_data[thread_id];
 401                uint32_t i;
 402
 403                for (i = 0; i < td->n_pipelines; i++) {
 404                        struct pipeline_data *tdp = &td->pipeline_data[i];
 405
 406                        if (tdp->p != p->p)
 407                                continue;
 408
 409                        /* Data plane thread */
 410                        if (i < td->n_pipelines - 1) {
 411                                struct rte_pipeline *pipeline_last =
 412                                        td->p[td->n_pipelines - 1];
 413                                struct pipeline_data *tdp_last =
 414                                        &td->pipeline_data[td->n_pipelines - 1];
 415
 416                                td->p[i] = pipeline_last;
 417                                memcpy(tdp, tdp_last, sizeof(*tdp));
 418                        }
 419
 420                        td->n_pipelines--;
 421
 422                        /* Pipeline */
 423                        p->enabled = 0;
 424
 425                        break;
 426                }
 427
 428                if (softnic->params.sc && (td->n_pipelines == 0))
 429                        thread_sc_service_down(softnic, thread_id);
 430
 431                return 0;
 432        }
 433
 434        /* Allocate request */
 435        req = thread_msg_alloc();
 436        if (req == NULL)
 437                return -1;
 438
 439        /* Write request */
 440        req->type = THREAD_REQ_PIPELINE_DISABLE;
 441        req->pipeline_disable.p = p->p;
 442
 443        /* Send request and wait for response */
 444        rsp = thread_msg_send_recv(softnic, thread_id, req);
 445
 446        /* Read response */
 447        status = rsp->status;
 448
 449        /* Free response */
 450        thread_msg_free(rsp);
 451
 452        /* Request completion */
 453        if (status)
 454                return status;
 455
 456        p->enabled = 0;
 457
 458        n_pipelines = softnic_pipeline_thread_count(softnic, thread_id);
 459        if (softnic->params.sc && (n_pipelines == 0))
 460                thread_sc_service_down(softnic, thread_id);
 461
 462        return 0;
 463}
 464
 465/**
 466 * Data plane threads: message handling
 467 */
 468static inline struct thread_msg_req *
 469thread_msg_recv(struct rte_ring *msgq_req)
 470{
 471        struct thread_msg_req *req;
 472
 473        int status = rte_ring_sc_dequeue(msgq_req, (void **)&req);
 474
 475        if (status != 0)
 476                return NULL;
 477
 478        return req;
 479}
 480
 481static inline void
 482thread_msg_send(struct rte_ring *msgq_rsp,
 483        struct thread_msg_rsp *rsp)
 484{
 485        int status;
 486
 487        do {
 488                status = rte_ring_sp_enqueue(msgq_rsp, rsp);
 489        } while (status == -ENOBUFS);
 490}
 491
 492static struct thread_msg_rsp *
 493thread_msg_handle_pipeline_enable(struct softnic_thread_data *t,
 494        struct thread_msg_req *req)
 495{
 496        struct thread_msg_rsp *rsp = (struct thread_msg_rsp *)req;
 497        struct pipeline_data *p = &t->pipeline_data[t->n_pipelines];
 498        uint32_t i;
 499
 500        /* Request */
 501        t->p[t->n_pipelines] = req->pipeline_enable.p;
 502
 503        p->p = req->pipeline_enable.p;
 504        for (i = 0; i < req->pipeline_enable.n_tables; i++)
 505                p->table_data[i].a =
 506                        req->pipeline_enable.table[i].a;
 507
 508        p->n_tables = req->pipeline_enable.n_tables;
 509
 510        p->msgq_req = req->pipeline_enable.msgq_req;
 511        p->msgq_rsp = req->pipeline_enable.msgq_rsp;
 512        p->timer_period =
 513                (rte_get_tsc_hz() * req->pipeline_enable.timer_period_ms) / 1000;
 514        p->time_next = rte_get_tsc_cycles() + p->timer_period;
 515
 516        t->n_pipelines++;
 517
 518        /* Response */
 519        rsp->status = 0;
 520        return rsp;
 521}
 522
 523static struct thread_msg_rsp *
 524thread_msg_handle_pipeline_disable(struct softnic_thread_data *t,
 525        struct thread_msg_req *req)
 526{
 527        struct thread_msg_rsp *rsp = (struct thread_msg_rsp *)req;
 528        uint32_t n_pipelines = t->n_pipelines;
 529        struct rte_pipeline *pipeline = req->pipeline_disable.p;
 530        uint32_t i;
 531
 532        /* find pipeline */
 533        for (i = 0; i < n_pipelines; i++) {
 534                struct pipeline_data *p = &t->pipeline_data[i];
 535
 536                if (p->p != pipeline)
 537                        continue;
 538
 539                if (i < n_pipelines - 1) {
 540                        struct rte_pipeline *pipeline_last =
 541                                t->p[n_pipelines - 1];
 542                        struct pipeline_data *p_last =
 543                                &t->pipeline_data[n_pipelines - 1];
 544
 545                        t->p[i] = pipeline_last;
 546                        memcpy(p, p_last, sizeof(*p));
 547                }
 548
 549                t->n_pipelines--;
 550
 551                rsp->status = 0;
 552                return rsp;
 553        }
 554
 555        /* should not get here */
 556        rsp->status = 0;
 557        return rsp;
 558}
 559
 560static void
 561thread_msg_handle(struct softnic_thread_data *t)
 562{
 563        for ( ; ; ) {
 564                struct thread_msg_req *req;
 565                struct thread_msg_rsp *rsp;
 566
 567                req = thread_msg_recv(t->msgq_req);
 568                if (req == NULL)
 569                        break;
 570
 571                switch (req->type) {
 572                case THREAD_REQ_PIPELINE_ENABLE:
 573                        rsp = thread_msg_handle_pipeline_enable(t, req);
 574                        break;
 575
 576                case THREAD_REQ_PIPELINE_DISABLE:
 577                        rsp = thread_msg_handle_pipeline_disable(t, req);
 578                        break;
 579
 580                default:
 581                        rsp = (struct thread_msg_rsp *)req;
 582                        rsp->status = -1;
 583                }
 584
 585                thread_msg_send(t->msgq_rsp, rsp);
 586        }
 587}
 588
 589/**
 590 * Main thread & data plane threads: message passing
 591 */
 592enum pipeline_req_type {
 593        /* Port IN */
 594        PIPELINE_REQ_PORT_IN_STATS_READ,
 595        PIPELINE_REQ_PORT_IN_ENABLE,
 596        PIPELINE_REQ_PORT_IN_DISABLE,
 597
 598        /* Port OUT */
 599        PIPELINE_REQ_PORT_OUT_STATS_READ,
 600
 601        /* Table */
 602        PIPELINE_REQ_TABLE_STATS_READ,
 603        PIPELINE_REQ_TABLE_RULE_ADD,
 604        PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT,
 605        PIPELINE_REQ_TABLE_RULE_ADD_BULK,
 606        PIPELINE_REQ_TABLE_RULE_DELETE,
 607        PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT,
 608        PIPELINE_REQ_TABLE_RULE_STATS_READ,
 609        PIPELINE_REQ_TABLE_MTR_PROFILE_ADD,
 610        PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE,
 611        PIPELINE_REQ_TABLE_RULE_MTR_READ,
 612        PIPELINE_REQ_TABLE_DSCP_TABLE_UPDATE,
 613        PIPELINE_REQ_TABLE_RULE_TTL_READ,
 614        PIPELINE_REQ_MAX
 615};
 616
 617struct pipeline_msg_req_port_in_stats_read {
 618        int clear;
 619};
 620
 621struct pipeline_msg_req_port_out_stats_read {
 622        int clear;
 623};
 624
 625struct pipeline_msg_req_table_stats_read {
 626        int clear;
 627};
 628
 629struct pipeline_msg_req_table_rule_add {
 630        struct softnic_table_rule_match match;
 631        struct softnic_table_rule_action action;
 632};
 633
 634struct pipeline_msg_req_table_rule_add_default {
 635        struct softnic_table_rule_action action;
 636};
 637
 638struct pipeline_msg_req_table_rule_add_bulk {
 639        struct softnic_table_rule_match *match;
 640        struct softnic_table_rule_action *action;
 641        void **data;
 642        uint32_t n_rules;
 643        int bulk;
 644};
 645
 646struct pipeline_msg_req_table_rule_delete {
 647        struct softnic_table_rule_match match;
 648};
 649
 650struct pipeline_msg_req_table_rule_stats_read {
 651        void *data;
 652        int clear;
 653};
 654
 655struct pipeline_msg_req_table_mtr_profile_add {
 656        uint32_t meter_profile_id;
 657        struct rte_table_action_meter_profile profile;
 658};
 659
 660struct pipeline_msg_req_table_mtr_profile_delete {
 661        uint32_t meter_profile_id;
 662};
 663
 664struct pipeline_msg_req_table_rule_mtr_read {
 665        void *data;
 666        uint32_t tc_mask;
 667        int clear;
 668};
 669
 670struct pipeline_msg_req_table_dscp_table_update {
 671        uint64_t dscp_mask;
 672        struct rte_table_action_dscp_table dscp_table;
 673};
 674
 675struct pipeline_msg_req_table_rule_ttl_read {
 676        void *data;
 677        int clear;
 678};
 679
 680struct pipeline_msg_req {
 681        enum pipeline_req_type type;
 682        uint32_t id; /* Port IN, port OUT or table ID */
 683
 684        RTE_STD_C11
 685        union {
 686                struct pipeline_msg_req_port_in_stats_read port_in_stats_read;
 687                struct pipeline_msg_req_port_out_stats_read port_out_stats_read;
 688                struct pipeline_msg_req_table_stats_read table_stats_read;
 689                struct pipeline_msg_req_table_rule_add table_rule_add;
 690                struct pipeline_msg_req_table_rule_add_default table_rule_add_default;
 691                struct pipeline_msg_req_table_rule_add_bulk table_rule_add_bulk;
 692                struct pipeline_msg_req_table_rule_delete table_rule_delete;
 693                struct pipeline_msg_req_table_rule_stats_read table_rule_stats_read;
 694                struct pipeline_msg_req_table_mtr_profile_add table_mtr_profile_add;
 695                struct pipeline_msg_req_table_mtr_profile_delete table_mtr_profile_delete;
 696                struct pipeline_msg_req_table_rule_mtr_read table_rule_mtr_read;
 697                struct pipeline_msg_req_table_dscp_table_update table_dscp_table_update;
 698                struct pipeline_msg_req_table_rule_ttl_read table_rule_ttl_read;
 699        };
 700};
 701
 702struct pipeline_msg_rsp_port_in_stats_read {
 703        struct rte_pipeline_port_in_stats stats;
 704};
 705
 706struct pipeline_msg_rsp_port_out_stats_read {
 707        struct rte_pipeline_port_out_stats stats;
 708};
 709
 710struct pipeline_msg_rsp_table_stats_read {
 711        struct rte_pipeline_table_stats stats;
 712};
 713
 714struct pipeline_msg_rsp_table_rule_add {
 715        void *data;
 716};
 717
 718struct pipeline_msg_rsp_table_rule_add_default {
 719        void *data;
 720};
 721
 722struct pipeline_msg_rsp_table_rule_add_bulk {
 723        uint32_t n_rules;
 724};
 725
 726struct pipeline_msg_rsp_table_rule_stats_read {
 727        struct rte_table_action_stats_counters stats;
 728};
 729
 730struct pipeline_msg_rsp_table_rule_mtr_read {
 731        struct rte_table_action_mtr_counters stats;
 732};
 733
 734struct pipeline_msg_rsp_table_rule_ttl_read {
 735        struct rte_table_action_ttl_counters stats;
 736};
 737
 738struct pipeline_msg_rsp {
 739        int status;
 740
 741        RTE_STD_C11
 742        union {
 743                struct pipeline_msg_rsp_port_in_stats_read port_in_stats_read;
 744                struct pipeline_msg_rsp_port_out_stats_read port_out_stats_read;
 745                struct pipeline_msg_rsp_table_stats_read table_stats_read;
 746                struct pipeline_msg_rsp_table_rule_add table_rule_add;
 747                struct pipeline_msg_rsp_table_rule_add_default table_rule_add_default;
 748                struct pipeline_msg_rsp_table_rule_add_bulk table_rule_add_bulk;
 749                struct pipeline_msg_rsp_table_rule_stats_read table_rule_stats_read;
 750                struct pipeline_msg_rsp_table_rule_mtr_read table_rule_mtr_read;
 751                struct pipeline_msg_rsp_table_rule_ttl_read table_rule_ttl_read;
 752        };
 753};
 754
 755/**
 756 * Main thread
 757 */
 758static struct pipeline_msg_req *
 759pipeline_msg_alloc(void)
 760{
 761        size_t size = RTE_MAX(sizeof(struct pipeline_msg_req),
 762                sizeof(struct pipeline_msg_rsp));
 763
 764        return calloc(1, size);
 765}
 766
 767static void
 768pipeline_msg_free(struct pipeline_msg_rsp *rsp)
 769{
 770        free(rsp);
 771}
 772
 773static struct pipeline_msg_rsp *
 774pipeline_msg_send_recv(struct pipeline *p,
 775        struct pipeline_msg_req *req)
 776{
 777        struct rte_ring *msgq_req = p->msgq_req;
 778        struct rte_ring *msgq_rsp = p->msgq_rsp;
 779        struct pipeline_msg_rsp *rsp;
 780        int status;
 781
 782        /* send */
 783        do {
 784                status = rte_ring_sp_enqueue(msgq_req, req);
 785        } while (status == -ENOBUFS);
 786
 787        /* recv */
 788        do {
 789                status = rte_ring_sc_dequeue(msgq_rsp, (void **)&rsp);
 790        } while (status != 0);
 791
 792        return rsp;
 793}
 794
 795int
 796softnic_pipeline_port_in_stats_read(struct pmd_internals *softnic,
 797        const char *pipeline_name,
 798        uint32_t port_id,
 799        struct rte_pipeline_port_in_stats *stats,
 800        int clear)
 801{
 802        struct pipeline *p;
 803        struct pipeline_msg_req *req;
 804        struct pipeline_msg_rsp *rsp;
 805        int status;
 806
 807        /* Check input params */
 808        if (pipeline_name == NULL ||
 809                stats == NULL)
 810                return -1;
 811
 812        p = softnic_pipeline_find(softnic, pipeline_name);
 813        if (p == NULL ||
 814                port_id >= p->n_ports_in)
 815                return -1;
 816
 817        if (!pipeline_is_running(p)) {
 818                status = rte_pipeline_port_in_stats_read(p->p,
 819                        port_id,
 820                        stats,
 821                        clear);
 822
 823                return status;
 824        }
 825
 826        /* Allocate request */
 827        req = pipeline_msg_alloc();
 828        if (req == NULL)
 829                return -1;
 830
 831        /* Write request */
 832        req->type = PIPELINE_REQ_PORT_IN_STATS_READ;
 833        req->id = port_id;
 834        req->port_in_stats_read.clear = clear;
 835
 836        /* Send request and wait for response */
 837        rsp = pipeline_msg_send_recv(p, req);
 838
 839        /* Read response */
 840        status = rsp->status;
 841        if (status)
 842                memcpy(stats, &rsp->port_in_stats_read.stats, sizeof(*stats));
 843
 844        /* Free response */
 845        pipeline_msg_free(rsp);
 846
 847        return status;
 848}
 849
 850int
 851softnic_pipeline_port_in_enable(struct pmd_internals *softnic,
 852        const char *pipeline_name,
 853        uint32_t port_id)
 854{
 855        struct pipeline *p;
 856        struct pipeline_msg_req *req;
 857        struct pipeline_msg_rsp *rsp;
 858        int status;
 859
 860        /* Check input params */
 861        if (pipeline_name == NULL)
 862                return -1;
 863
 864        p = softnic_pipeline_find(softnic, pipeline_name);
 865        if (p == NULL ||
 866                port_id >= p->n_ports_in)
 867                return -1;
 868
 869        if (!pipeline_is_running(p)) {
 870                status = rte_pipeline_port_in_enable(p->p, port_id);
 871                return status;
 872        }
 873
 874        /* Allocate request */
 875        req = pipeline_msg_alloc();
 876        if (req == NULL)
 877                return -1;
 878
 879        /* Write request */
 880        req->type = PIPELINE_REQ_PORT_IN_ENABLE;
 881        req->id = port_id;
 882
 883        /* Send request and wait for response */
 884        rsp = pipeline_msg_send_recv(p, req);
 885
 886        /* Read response */
 887        status = rsp->status;
 888
 889        /* Free response */
 890        pipeline_msg_free(rsp);
 891
 892        return status;
 893}
 894
 895int
 896softnic_pipeline_port_in_disable(struct pmd_internals *softnic,
 897        const char *pipeline_name,
 898        uint32_t port_id)
 899{
 900        struct pipeline *p;
 901        struct pipeline_msg_req *req;
 902        struct pipeline_msg_rsp *rsp;
 903        int status;
 904
 905        /* Check input params */
 906        if (pipeline_name == NULL)
 907                return -1;
 908
 909        p = softnic_pipeline_find(softnic, pipeline_name);
 910        if (p == NULL ||
 911                port_id >= p->n_ports_in)
 912                return -1;
 913
 914        if (!pipeline_is_running(p)) {
 915                status = rte_pipeline_port_in_disable(p->p, port_id);
 916                return status;
 917        }
 918
 919        /* Allocate request */
 920        req = pipeline_msg_alloc();
 921        if (req == NULL)
 922                return -1;
 923
 924        /* Write request */
 925        req->type = PIPELINE_REQ_PORT_IN_DISABLE;
 926        req->id = port_id;
 927
 928        /* Send request and wait for response */
 929        rsp = pipeline_msg_send_recv(p, req);
 930
 931        /* Read response */
 932        status = rsp->status;
 933
 934        /* Free response */
 935        pipeline_msg_free(rsp);
 936
 937        return status;
 938}
 939
 940int
 941softnic_pipeline_port_out_stats_read(struct pmd_internals *softnic,
 942        const char *pipeline_name,
 943        uint32_t port_id,
 944        struct rte_pipeline_port_out_stats *stats,
 945        int clear)
 946{
 947        struct pipeline *p;
 948        struct pipeline_msg_req *req;
 949        struct pipeline_msg_rsp *rsp;
 950        int status;
 951
 952        /* Check input params */
 953        if (pipeline_name == NULL ||
 954                stats == NULL)
 955                return -1;
 956
 957        p = softnic_pipeline_find(softnic, pipeline_name);
 958        if (p == NULL ||
 959                port_id >= p->n_ports_out)
 960                return -1;
 961
 962        if (!pipeline_is_running(p)) {
 963                status = rte_pipeline_port_out_stats_read(p->p,
 964                        port_id,
 965                        stats,
 966                        clear);
 967
 968                return status;
 969        }
 970
 971        /* Allocate request */
 972        req = pipeline_msg_alloc();
 973        if (req == NULL)
 974                return -1;
 975
 976        /* Write request */
 977        req->type = PIPELINE_REQ_PORT_OUT_STATS_READ;
 978        req->id = port_id;
 979        req->port_out_stats_read.clear = clear;
 980
 981        /* Send request and wait for response */
 982        rsp = pipeline_msg_send_recv(p, req);
 983
 984        /* Read response */
 985        status = rsp->status;
 986        if (status)
 987                memcpy(stats, &rsp->port_out_stats_read.stats, sizeof(*stats));
 988
 989        /* Free response */
 990        pipeline_msg_free(rsp);
 991
 992        return status;
 993}
 994
 995int
 996softnic_pipeline_table_stats_read(struct pmd_internals *softnic,
 997        const char *pipeline_name,
 998        uint32_t table_id,
 999        struct rte_pipeline_table_stats *stats,
1000        int clear)
1001{
1002        struct pipeline *p;
1003        struct pipeline_msg_req *req;
1004        struct pipeline_msg_rsp *rsp;
1005        int status;
1006
1007        /* Check input params */
1008        if (pipeline_name == NULL ||
1009                stats == NULL)
1010                return -1;
1011
1012        p = softnic_pipeline_find(softnic, pipeline_name);
1013        if (p == NULL ||
1014                table_id >= p->n_tables)
1015                return -1;
1016
1017        if (!pipeline_is_running(p)) {
1018                status = rte_pipeline_table_stats_read(p->p,
1019                        table_id,
1020                        stats,
1021                        clear);
1022
1023                return status;
1024        }
1025
1026        /* Allocate request */
1027        req = pipeline_msg_alloc();
1028        if (req == NULL)
1029                return -1;
1030
1031        /* Write request */
1032        req->type = PIPELINE_REQ_TABLE_STATS_READ;
1033        req->id = table_id;
1034        req->table_stats_read.clear = clear;
1035
1036        /* Send request and wait for response */
1037        rsp = pipeline_msg_send_recv(p, req);
1038
1039        /* Read response */
1040        status = rsp->status;
1041        if (status)
1042                memcpy(stats, &rsp->table_stats_read.stats, sizeof(*stats));
1043
1044        /* Free response */
1045        pipeline_msg_free(rsp);
1046
1047        return status;
1048}
1049
1050static int
1051match_check(struct softnic_table_rule_match *match,
1052        struct pipeline *p,
1053        uint32_t table_id)
1054{
1055        struct softnic_table *table;
1056
1057        if (match == NULL ||
1058                p == NULL ||
1059                table_id >= p->n_tables)
1060                return -1;
1061
1062        table = &p->table[table_id];
1063        if (match->match_type != table->params.match_type)
1064                return -1;
1065
1066        switch (match->match_type) {
1067        case TABLE_ACL:
1068        {
1069                struct softnic_table_acl_params *t = &table->params.match.acl;
1070                struct softnic_table_rule_match_acl *r = &match->match.acl;
1071
1072                if ((r->ip_version && (t->ip_version == 0)) ||
1073                        ((r->ip_version == 0) && t->ip_version))
1074                        return -1;
1075
1076                if (r->ip_version) {
1077                        if (r->sa_depth > 32 ||
1078                                r->da_depth > 32)
1079                                return -1;
1080                } else {
1081                        if (r->sa_depth > 128 ||
1082                                r->da_depth > 128)
1083                                return -1;
1084                }
1085                return 0;
1086        }
1087
1088        case TABLE_ARRAY:
1089                return 0;
1090
1091        case TABLE_HASH:
1092                return 0;
1093
1094        case TABLE_LPM:
1095        {
1096                struct softnic_table_lpm_params *t = &table->params.match.lpm;
1097                struct softnic_table_rule_match_lpm *r = &match->match.lpm;
1098
1099                if ((r->ip_version && (t->key_size != 4)) ||
1100                        ((r->ip_version == 0) && (t->key_size != 16)))
1101                        return -1;
1102
1103                if (r->ip_version) {
1104                        if (r->depth > 32)
1105                                return -1;
1106                } else {
1107                        if (r->depth > 128)
1108                                return -1;
1109                }
1110                return 0;
1111        }
1112
1113        case TABLE_STUB:
1114                return -1;
1115
1116        default:
1117                return -1;
1118        }
1119}
1120
1121static int
1122action_check(struct softnic_table_rule_action *action,
1123        struct pipeline *p,
1124        uint32_t table_id)
1125{
1126        struct softnic_table_action_profile *ap;
1127
1128        if (action == NULL ||
1129                p == NULL ||
1130                table_id >= p->n_tables)
1131                return -1;
1132
1133        ap = p->table[table_id].ap;
1134        if (action->action_mask != ap->params.action_mask)
1135                return -1;
1136
1137        if (action->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) {
1138                if (action->fwd.action == RTE_PIPELINE_ACTION_PORT &&
1139                        action->fwd.id >= p->n_ports_out)
1140                        return -1;
1141
1142                if (action->fwd.action == RTE_PIPELINE_ACTION_TABLE &&
1143                        action->fwd.id >= p->n_tables)
1144                        return -1;
1145        }
1146
1147        if (action->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
1148                uint32_t tc_mask0 = (1 << ap->params.mtr.n_tc) - 1;
1149                uint32_t tc_mask1 = action->mtr.tc_mask;
1150
1151                if (tc_mask1 != tc_mask0)
1152                        return -1;
1153        }
1154
1155        if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
1156                uint32_t n_subports_per_port =
1157                        ap->params.tm.n_subports_per_port;
1158                uint32_t n_pipes_per_subport =
1159                        ap->params.tm.n_pipes_per_subport;
1160                uint32_t subport_id = action->tm.subport_id;
1161                uint32_t pipe_id = action->tm.pipe_id;
1162
1163                if (subport_id >= n_subports_per_port ||
1164                        pipe_id >= n_pipes_per_subport)
1165                        return -1;
1166        }
1167
1168        if (action->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
1169                uint64_t encap_mask = ap->params.encap.encap_mask;
1170                enum rte_table_action_encap_type type = action->encap.type;
1171
1172                if ((encap_mask & (1LLU << type)) == 0)
1173                        return -1;
1174        }
1175
1176        if (action->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
1177                int ip_version0 = ap->params.common.ip_version;
1178                int ip_version1 = action->nat.ip_version;
1179
1180                if ((ip_version1 && (ip_version0 == 0)) ||
1181                        ((ip_version1 == 0) && ip_version0))
1182                        return -1;
1183        }
1184
1185        return 0;
1186}
1187
1188static int
1189action_default_check(struct softnic_table_rule_action *action,
1190        struct pipeline *p,
1191        uint32_t table_id)
1192{
1193        if (action == NULL ||
1194                action->action_mask != (1LLU << RTE_TABLE_ACTION_FWD) ||
1195                p == NULL ||
1196                table_id >= p->n_tables)
1197                return -1;
1198
1199        if (action->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) {
1200                if (action->fwd.action == RTE_PIPELINE_ACTION_PORT &&
1201                        action->fwd.id >= p->n_ports_out)
1202                        return -1;
1203
1204                if (action->fwd.action == RTE_PIPELINE_ACTION_TABLE &&
1205                        action->fwd.id >= p->n_tables)
1206                        return -1;
1207        }
1208
1209        return 0;
1210}
1211
1212union table_rule_match_low_level {
1213        struct rte_table_acl_rule_add_params acl_add;
1214        struct rte_table_acl_rule_delete_params acl_delete;
1215        struct rte_table_array_key array;
1216        uint8_t hash[TABLE_RULE_MATCH_SIZE_MAX];
1217        struct rte_table_lpm_key lpm_ipv4;
1218        struct rte_table_lpm_ipv6_key lpm_ipv6;
1219};
1220
1221static int
1222match_convert(struct softnic_table_rule_match *mh,
1223        union table_rule_match_low_level *ml,
1224        int add);
1225
1226static int
1227action_convert(struct rte_table_action *a,
1228        struct softnic_table_rule_action *action,
1229        struct rte_pipeline_table_entry *data);
1230
1231int
1232softnic_pipeline_table_rule_add(struct pmd_internals *softnic,
1233        const char *pipeline_name,
1234        uint32_t table_id,
1235        struct softnic_table_rule_match *match,
1236        struct softnic_table_rule_action *action,
1237        void **data)
1238{
1239        struct pipeline *p;
1240        struct pipeline_msg_req *req;
1241        struct pipeline_msg_rsp *rsp;
1242        int status;
1243
1244        /* Check input params */
1245        if (pipeline_name == NULL ||
1246                match == NULL ||
1247                action == NULL ||
1248                data == NULL)
1249                return -1;
1250
1251        p = softnic_pipeline_find(softnic, pipeline_name);
1252        if (p == NULL ||
1253                table_id >= p->n_tables ||
1254                match_check(match, p, table_id) ||
1255                action_check(action, p, table_id))
1256                return -1;
1257
1258        if (!pipeline_is_running(p)) {
1259                struct rte_table_action *a = p->table[table_id].a;
1260                union table_rule_match_low_level match_ll;
1261                struct rte_pipeline_table_entry *data_in, *data_out;
1262                int key_found;
1263                uint8_t *buffer;
1264
1265                buffer = calloc(TABLE_RULE_ACTION_SIZE_MAX, sizeof(uint8_t));
1266                if (buffer == NULL)
1267                        return -1;
1268
1269                /* Table match-action rule conversion */
1270                data_in = (struct rte_pipeline_table_entry *)buffer;
1271
1272                status = match_convert(match, &match_ll, 1);
1273                if (status) {
1274                        free(buffer);
1275                        return -1;
1276                }
1277
1278                status = action_convert(a, action, data_in);
1279                if (status) {
1280                        free(buffer);
1281                        return -1;
1282                }
1283
1284                /* Add rule (match, action) to table */
1285                status = rte_pipeline_table_entry_add(p->p,
1286                                table_id,
1287                                &match_ll,
1288                                data_in,
1289                                &key_found,
1290                                &data_out);
1291                if (status) {
1292                        free(buffer);
1293                        return -1;
1294                }
1295
1296                /* Write Response */
1297                *data = data_out;
1298
1299                free(buffer);
1300                return 0;
1301        }
1302
1303        /* Allocate request */
1304        req = pipeline_msg_alloc();
1305        if (req == NULL)
1306                return -1;
1307
1308        /* Write request */
1309        req->type = PIPELINE_REQ_TABLE_RULE_ADD;
1310        req->id = table_id;
1311        memcpy(&req->table_rule_add.match, match, sizeof(*match));
1312        memcpy(&req->table_rule_add.action, action, sizeof(*action));
1313
1314        /* Send request and wait for response */
1315        rsp = pipeline_msg_send_recv(p, req);
1316
1317        /* Read response */
1318        status = rsp->status;
1319        if (status == 0)
1320                *data = rsp->table_rule_add.data;
1321
1322        /* Free response */
1323        pipeline_msg_free(rsp);
1324
1325        return status;
1326}
1327
1328int
1329softnic_pipeline_table_rule_add_default(struct pmd_internals *softnic,
1330        const char *pipeline_name,
1331        uint32_t table_id,
1332        struct softnic_table_rule_action *action,
1333        void **data)
1334{
1335        struct pipeline *p;
1336        struct pipeline_msg_req *req;
1337        struct pipeline_msg_rsp *rsp;
1338        int status;
1339
1340        /* Check input params */
1341        if (pipeline_name == NULL ||
1342                action == NULL ||
1343                data == NULL)
1344                return -1;
1345
1346        p = softnic_pipeline_find(softnic, pipeline_name);
1347        if (p == NULL ||
1348                table_id >= p->n_tables ||
1349                action_default_check(action, p, table_id))
1350                return -1;
1351
1352        if (!pipeline_is_running(p)) {
1353                struct rte_pipeline_table_entry *data_in, *data_out;
1354                uint8_t *buffer;
1355
1356                buffer = calloc(TABLE_RULE_ACTION_SIZE_MAX, sizeof(uint8_t));
1357                if (buffer == NULL)
1358                        return -1;
1359
1360                /* Apply actions */
1361                data_in = (struct rte_pipeline_table_entry *)buffer;
1362
1363                data_in->action = action->fwd.action;
1364                if (action->fwd.action == RTE_PIPELINE_ACTION_PORT)
1365                        data_in->port_id = action->fwd.id;
1366                if (action->fwd.action == RTE_PIPELINE_ACTION_TABLE)
1367                        data_in->table_id = action->fwd.id;
1368
1369                /* Add default rule to table */
1370                status = rte_pipeline_table_default_entry_add(p->p,
1371                                table_id,
1372                                data_in,
1373                                &data_out);
1374                if (status) {
1375                        free(buffer);
1376                        return -1;
1377                }
1378
1379                /* Write Response */
1380                *data = data_out;
1381
1382                free(buffer);
1383                return 0;
1384        }
1385
1386        /* Allocate request */
1387        req = pipeline_msg_alloc();
1388        if (req == NULL)
1389                return -1;
1390
1391        /* Write request */
1392        req->type = PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT;
1393        req->id = table_id;
1394        memcpy(&req->table_rule_add_default.action, action, sizeof(*action));
1395
1396        /* Send request and wait for response */
1397        rsp = pipeline_msg_send_recv(p, req);
1398
1399        /* Read response */
1400        status = rsp->status;
1401        if (status == 0)
1402                *data = rsp->table_rule_add_default.data;
1403
1404        /* Free response */
1405        pipeline_msg_free(rsp);
1406
1407        return status;
1408}
1409
1410int
1411softnic_pipeline_table_rule_add_bulk(struct pmd_internals *softnic,
1412        const char *pipeline_name,
1413        uint32_t table_id,
1414        struct softnic_table_rule_match *match,
1415        struct softnic_table_rule_action *action,
1416        void **data,
1417        uint32_t *n_rules)
1418{
1419        struct pipeline *p;
1420        struct pipeline_msg_req *req;
1421        struct pipeline_msg_rsp *rsp;
1422        uint32_t i;
1423        int status;
1424
1425        /* Check input params */
1426        if (pipeline_name == NULL ||
1427                match == NULL ||
1428                action == NULL ||
1429                data == NULL ||
1430                n_rules == NULL ||
1431                (*n_rules == 0))
1432                return -1;
1433
1434        p = softnic_pipeline_find(softnic, pipeline_name);
1435        if (p == NULL ||
1436                table_id >= p->n_tables)
1437                return -1;
1438
1439        for (i = 0; i < *n_rules; i++)
1440                if (match_check(match, p, table_id) ||
1441                        action_check(action, p, table_id))
1442                        return -1;
1443
1444        if (!pipeline_is_running(p)) {
1445                struct rte_table_action *a = p->table[table_id].a;
1446                union table_rule_match_low_level *match_ll;
1447                uint8_t *action_ll;
1448                void **match_ll_ptr;
1449                struct rte_pipeline_table_entry **action_ll_ptr;
1450                struct rte_pipeline_table_entry **entries_ptr =
1451                        (struct rte_pipeline_table_entry **)data;
1452                uint32_t bulk =
1453                        (p->table[table_id].params.match_type == TABLE_ACL) ? 1 : 0;
1454                int *found;
1455
1456                /* Memory allocation */
1457                match_ll = calloc(*n_rules, sizeof(union table_rule_match_low_level));
1458                action_ll = calloc(*n_rules, TABLE_RULE_ACTION_SIZE_MAX);
1459                match_ll_ptr = calloc(*n_rules, sizeof(void *));
1460                action_ll_ptr =
1461                        calloc(*n_rules, sizeof(struct rte_pipeline_table_entry *));
1462                found = calloc(*n_rules, sizeof(int));
1463
1464                if (match_ll == NULL ||
1465                        action_ll == NULL ||
1466                        match_ll_ptr == NULL ||
1467                        action_ll_ptr == NULL ||
1468                        found == NULL)
1469                        goto fail;
1470
1471                for (i = 0; i < *n_rules; i++) {
1472                        match_ll_ptr[i] = (void *)&match_ll[i];
1473                        action_ll_ptr[i] =
1474                                (struct rte_pipeline_table_entry *)&action_ll[i * TABLE_RULE_ACTION_SIZE_MAX];
1475                }
1476
1477                /* Rule match conversion */
1478                for (i = 0; i < *n_rules; i++) {
1479                        status = match_convert(&match[i], match_ll_ptr[i], 1);
1480                        if (status)
1481                                goto fail;
1482                }
1483
1484                /* Rule action conversion */
1485                for (i = 0; i < *n_rules; i++) {
1486                        status = action_convert(a, &action[i], action_ll_ptr[i]);
1487                        if (status)
1488                                goto fail;
1489                }
1490
1491                /* Add rule (match, action) to table */
1492                if (bulk) {
1493                        status = rte_pipeline_table_entry_add_bulk(p->p,
1494                                table_id,
1495                                match_ll_ptr,
1496                                action_ll_ptr,
1497                                *n_rules,
1498                                found,
1499                                entries_ptr);
1500                        if (status)
1501                                *n_rules = 0;
1502                } else {
1503                        for (i = 0; i < *n_rules; i++) {
1504                                status = rte_pipeline_table_entry_add(p->p,
1505                                        table_id,
1506                                        match_ll_ptr[i],
1507                                        action_ll_ptr[i],
1508                                        &found[i],
1509                                        &entries_ptr[i]);
1510                                if (status) {
1511                                        *n_rules = i;
1512                                        break;
1513                                }
1514                        }
1515                }
1516
1517                /* Free */
1518                free(found);
1519                free(action_ll_ptr);
1520                free(match_ll_ptr);
1521                free(action_ll);
1522                free(match_ll);
1523
1524                return status;
1525
1526fail:
1527                free(found);
1528                free(action_ll_ptr);
1529                free(match_ll_ptr);
1530                free(action_ll);
1531                free(match_ll);
1532
1533                *n_rules = 0;
1534                return -1;
1535        }
1536
1537        /* Allocate request */
1538        req = pipeline_msg_alloc();
1539        if (req == NULL)
1540                return -1;
1541
1542        /* Write request */
1543        req->type = PIPELINE_REQ_TABLE_RULE_ADD_BULK;
1544        req->id = table_id;
1545        req->table_rule_add_bulk.match = match;
1546        req->table_rule_add_bulk.action = action;
1547        req->table_rule_add_bulk.data = data;
1548        req->table_rule_add_bulk.n_rules = *n_rules;
1549        req->table_rule_add_bulk.bulk =
1550                (p->table[table_id].params.match_type == TABLE_ACL) ? 1 : 0;
1551
1552        /* Send request and wait for response */
1553        rsp = pipeline_msg_send_recv(p, req);
1554
1555        /* Read response */
1556        status = rsp->status;
1557        if (status == 0)
1558                *n_rules = rsp->table_rule_add_bulk.n_rules;
1559
1560        /* Free response */
1561        pipeline_msg_free(rsp);
1562
1563        return status;
1564}
1565
1566int
1567softnic_pipeline_table_rule_delete(struct pmd_internals *softnic,
1568        const char *pipeline_name,
1569        uint32_t table_id,
1570        struct softnic_table_rule_match *match)
1571{
1572        struct pipeline *p;
1573        struct pipeline_msg_req *req;
1574        struct pipeline_msg_rsp *rsp;
1575        int status;
1576
1577        /* Check input params */
1578        if (pipeline_name == NULL ||
1579                match == NULL)
1580                return -1;
1581
1582        p = softnic_pipeline_find(softnic, pipeline_name);
1583        if (p == NULL ||
1584                table_id >= p->n_tables ||
1585                match_check(match, p, table_id))
1586                return -1;
1587
1588        if (!pipeline_is_running(p)) {
1589                union table_rule_match_low_level match_ll;
1590                int key_found;
1591
1592                status = match_convert(match, &match_ll, 0);
1593                if (status)
1594                        return -1;
1595
1596                status = rte_pipeline_table_entry_delete(p->p,
1597                                table_id,
1598                                &match_ll,
1599                                &key_found,
1600                                NULL);
1601
1602                return status;
1603        }
1604
1605        /* Allocate request */
1606        req = pipeline_msg_alloc();
1607        if (req == NULL)
1608                return -1;
1609
1610        /* Write request */
1611        req->type = PIPELINE_REQ_TABLE_RULE_DELETE;
1612        req->id = table_id;
1613        memcpy(&req->table_rule_delete.match, match, sizeof(*match));
1614
1615        /* Send request and wait for response */
1616        rsp = pipeline_msg_send_recv(p, req);
1617
1618        /* Read response */
1619        status = rsp->status;
1620
1621        /* Free response */
1622        pipeline_msg_free(rsp);
1623
1624        return status;
1625}
1626
1627int
1628softnic_pipeline_table_rule_delete_default(struct pmd_internals *softnic,
1629        const char *pipeline_name,
1630        uint32_t table_id)
1631{
1632        struct pipeline *p;
1633        struct pipeline_msg_req *req;
1634        struct pipeline_msg_rsp *rsp;
1635        int status;
1636
1637        /* Check input params */
1638        if (pipeline_name == NULL)
1639                return -1;
1640
1641        p = softnic_pipeline_find(softnic, pipeline_name);
1642        if (p == NULL ||
1643                table_id >= p->n_tables)
1644                return -1;
1645
1646        if (!pipeline_is_running(p)) {
1647                status = rte_pipeline_table_default_entry_delete(p->p,
1648                        table_id,
1649                        NULL);
1650
1651                return status;
1652        }
1653
1654        /* Allocate request */
1655        req = pipeline_msg_alloc();
1656        if (req == NULL)
1657                return -1;
1658
1659        /* Write request */
1660        req->type = PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT;
1661        req->id = table_id;
1662
1663        /* Send request and wait for response */
1664        rsp = pipeline_msg_send_recv(p, req);
1665
1666        /* Read response */
1667        status = rsp->status;
1668
1669        /* Free response */
1670        pipeline_msg_free(rsp);
1671
1672        return status;
1673}
1674
1675int
1676softnic_pipeline_table_rule_stats_read(struct pmd_internals *softnic,
1677        const char *pipeline_name,
1678        uint32_t table_id,
1679        void *data,
1680        struct rte_table_action_stats_counters *stats,
1681        int clear)
1682{
1683        struct pipeline *p;
1684        struct pipeline_msg_req *req;
1685        struct pipeline_msg_rsp *rsp;
1686        int status;
1687
1688        /* Check input params */
1689        if (pipeline_name == NULL ||
1690                data == NULL ||
1691                stats == NULL)
1692                return -1;
1693
1694        p = softnic_pipeline_find(softnic, pipeline_name);
1695        if (p == NULL ||
1696                table_id >= p->n_tables)
1697                return -1;
1698
1699        if (!pipeline_is_running(p)) {
1700                struct rte_table_action *a = p->table[table_id].a;
1701
1702                status = rte_table_action_stats_read(a,
1703                        data,
1704                        stats,
1705                        clear);
1706
1707                return status;
1708        }
1709
1710        /* Allocate request */
1711        req = pipeline_msg_alloc();
1712        if (req == NULL)
1713                return -1;
1714
1715        /* Write request */
1716        req->type = PIPELINE_REQ_TABLE_RULE_STATS_READ;
1717        req->id = table_id;
1718        req->table_rule_stats_read.data = data;
1719        req->table_rule_stats_read.clear = clear;
1720
1721        /* Send request and wait for response */
1722        rsp = pipeline_msg_send_recv(p, req);
1723
1724        /* Read response */
1725        status = rsp->status;
1726        if (status)
1727                memcpy(stats, &rsp->table_rule_stats_read.stats, sizeof(*stats));
1728
1729        /* Free response */
1730        pipeline_msg_free(rsp);
1731
1732        return status;
1733}
1734
1735int
1736softnic_pipeline_table_mtr_profile_add(struct pmd_internals *softnic,
1737        const char *pipeline_name,
1738        uint32_t table_id,
1739        uint32_t meter_profile_id,
1740        struct rte_table_action_meter_profile *profile)
1741{
1742        struct pipeline *p;
1743        struct pipeline_msg_req *req;
1744        struct pipeline_msg_rsp *rsp;
1745        struct softnic_table *table;
1746        struct softnic_table_meter_profile *mp;
1747        int status;
1748
1749        /* Check input params */
1750        if (pipeline_name == NULL ||
1751                profile == NULL)
1752                return -1;
1753
1754        p = softnic_pipeline_find(softnic, pipeline_name);
1755        if (p == NULL ||
1756                table_id >= p->n_tables)
1757                return -1;
1758
1759        table = &p->table[table_id];
1760        mp = softnic_pipeline_table_meter_profile_find(table, meter_profile_id);
1761        if (mp)
1762                return -1;
1763
1764        /* Resource Allocation */
1765        mp = calloc(1, sizeof(struct softnic_table_meter_profile));
1766        if (mp == NULL)
1767                return -1;
1768
1769        mp->meter_profile_id = meter_profile_id;
1770        memcpy(&mp->profile, profile, sizeof(mp->profile));
1771
1772        if (!pipeline_is_running(p)) {
1773                status = rte_table_action_meter_profile_add(table->a,
1774                        meter_profile_id,
1775                        profile);
1776                if (status) {
1777                        free(mp);
1778                        return status;
1779                }
1780
1781                /* Add profile to the table. */
1782                TAILQ_INSERT_TAIL(&table->meter_profiles, mp, node);
1783
1784                return status;
1785        }
1786
1787        /* Allocate request */
1788        req = pipeline_msg_alloc();
1789        if (req == NULL) {
1790                free(mp);
1791                return -1;
1792        }
1793
1794        /* Write request */
1795        req->type = PIPELINE_REQ_TABLE_MTR_PROFILE_ADD;
1796        req->id = table_id;
1797        req->table_mtr_profile_add.meter_profile_id = meter_profile_id;
1798        memcpy(&req->table_mtr_profile_add.profile, profile, sizeof(*profile));
1799
1800        /* Send request and wait for response */
1801        rsp = pipeline_msg_send_recv(p, req);
1802
1803        /* Read response */
1804        status = rsp->status;
1805        if (status == 0)
1806                TAILQ_INSERT_TAIL(&table->meter_profiles, mp, node);
1807        else
1808                free(mp);
1809
1810        /* Free response */
1811        pipeline_msg_free(rsp);
1812
1813        return status;
1814}
1815
1816int
1817softnic_pipeline_table_mtr_profile_delete(struct pmd_internals *softnic,
1818        const char *pipeline_name,
1819        uint32_t table_id,
1820        uint32_t meter_profile_id)
1821{
1822        struct pipeline *p;
1823        struct pipeline_msg_req *req;
1824        struct pipeline_msg_rsp *rsp;
1825        int status;
1826
1827        /* Check input params */
1828        if (pipeline_name == NULL)
1829                return -1;
1830
1831        p = softnic_pipeline_find(softnic, pipeline_name);
1832        if (p == NULL ||
1833                table_id >= p->n_tables)
1834                return -1;
1835
1836        if (!pipeline_is_running(p)) {
1837                struct rte_table_action *a = p->table[table_id].a;
1838
1839                status = rte_table_action_meter_profile_delete(a,
1840                                meter_profile_id);
1841
1842                return status;
1843        }
1844
1845        /* Allocate request */
1846        req = pipeline_msg_alloc();
1847        if (req == NULL)
1848                return -1;
1849
1850        /* Write request */
1851        req->type = PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE;
1852        req->id = table_id;
1853        req->table_mtr_profile_delete.meter_profile_id = meter_profile_id;
1854
1855        /* Send request and wait for response */
1856        rsp = pipeline_msg_send_recv(p, req);
1857
1858        /* Read response */
1859        status = rsp->status;
1860
1861        /* Free response */
1862        pipeline_msg_free(rsp);
1863
1864        return status;
1865}
1866
1867int
1868softnic_pipeline_table_rule_mtr_read(struct pmd_internals *softnic,
1869        const char *pipeline_name,
1870        uint32_t table_id,
1871        void *data,
1872        uint32_t tc_mask,
1873        struct rte_table_action_mtr_counters *stats,
1874        int clear)
1875{
1876        struct pipeline *p;
1877        struct pipeline_msg_req *req;
1878        struct pipeline_msg_rsp *rsp;
1879        int status;
1880
1881        /* Check input params */
1882        if (pipeline_name == NULL ||
1883                data == NULL ||
1884                stats == NULL)
1885                return -1;
1886
1887        p = softnic_pipeline_find(softnic, pipeline_name);
1888        if (p == NULL ||
1889                table_id >= p->n_tables)
1890                return -1;
1891
1892        if (!pipeline_is_running(p)) {
1893                struct rte_table_action *a = p->table[table_id].a;
1894
1895                status = rte_table_action_meter_read(a,
1896                                data,
1897                                tc_mask,
1898                                stats,
1899                                clear);
1900
1901                return status;
1902        }
1903
1904        /* Allocate request */
1905        req = pipeline_msg_alloc();
1906        if (req == NULL)
1907                return -1;
1908
1909        /* Write request */
1910        req->type = PIPELINE_REQ_TABLE_RULE_MTR_READ;
1911        req->id = table_id;
1912        req->table_rule_mtr_read.data = data;
1913        req->table_rule_mtr_read.tc_mask = tc_mask;
1914        req->table_rule_mtr_read.clear = clear;
1915
1916        /* Send request and wait for response */
1917        rsp = pipeline_msg_send_recv(p, req);
1918
1919        /* Read response */
1920        status = rsp->status;
1921        if (status)
1922                memcpy(stats, &rsp->table_rule_mtr_read.stats, sizeof(*stats));
1923
1924        /* Free response */
1925        pipeline_msg_free(rsp);
1926
1927        return status;
1928}
1929
1930int
1931softnic_pipeline_table_dscp_table_update(struct pmd_internals *softnic,
1932        const char *pipeline_name,
1933        uint32_t table_id,
1934        uint64_t dscp_mask,
1935        struct rte_table_action_dscp_table *dscp_table)
1936{
1937        struct pipeline *p;
1938        struct pipeline_msg_req *req;
1939        struct pipeline_msg_rsp *rsp;
1940        int status;
1941
1942        /* Check input params */
1943        if (pipeline_name == NULL ||
1944                dscp_table == NULL)
1945                return -1;
1946
1947        p = softnic_pipeline_find(softnic, pipeline_name);
1948        if (p == NULL ||
1949                table_id >= p->n_tables)
1950                return -1;
1951
1952        if (!pipeline_is_running(p)) {
1953                struct rte_table_action *a = p->table[table_id].a;
1954
1955                status = rte_table_action_dscp_table_update(a,
1956                                dscp_mask,
1957                                dscp_table);
1958
1959                /* Update table dscp table */
1960                if (!status)
1961                        memcpy(&p->table[table_id].dscp_table, dscp_table,
1962                                sizeof(p->table[table_id].dscp_table));
1963
1964                return status;
1965        }
1966
1967        /* Allocate request */
1968        req = pipeline_msg_alloc();
1969        if (req == NULL)
1970                return -1;
1971
1972        /* Write request */
1973        req->type = PIPELINE_REQ_TABLE_DSCP_TABLE_UPDATE;
1974        req->id = table_id;
1975        req->table_dscp_table_update.dscp_mask = dscp_mask;
1976        memcpy(&req->table_dscp_table_update.dscp_table,
1977                dscp_table, sizeof(*dscp_table));
1978
1979        /* Send request and wait for response */
1980        rsp = pipeline_msg_send_recv(p, req);
1981
1982        /* Read response */
1983        status = rsp->status;
1984
1985        /* Update table dscp table */
1986        if (!status)
1987                memcpy(&p->table[table_id].dscp_table, dscp_table,
1988                        sizeof(p->table[table_id].dscp_table));
1989
1990        /* Free response */
1991        pipeline_msg_free(rsp);
1992
1993        return status;
1994}
1995
1996int
1997softnic_pipeline_table_rule_ttl_read(struct pmd_internals *softnic,
1998        const char *pipeline_name,
1999        uint32_t table_id,
2000        void *data,
2001        struct rte_table_action_ttl_counters *stats,
2002        int clear)
2003{
2004        struct pipeline *p;
2005        struct pipeline_msg_req *req;
2006        struct pipeline_msg_rsp *rsp;
2007        int status;
2008
2009        /* Check input params */
2010        if (pipeline_name == NULL ||
2011                data == NULL ||
2012                stats == NULL)
2013                return -1;
2014
2015        p = softnic_pipeline_find(softnic, pipeline_name);
2016        if (p == NULL ||
2017                table_id >= p->n_tables)
2018                return -1;
2019
2020        if (!pipeline_is_running(p)) {
2021                struct rte_table_action *a = p->table[table_id].a;
2022
2023                status = rte_table_action_ttl_read(a,
2024                                data,
2025                                stats,
2026                                clear);
2027
2028                return status;
2029        }
2030
2031        /* Allocate request */
2032        req = pipeline_msg_alloc();
2033        if (req == NULL)
2034                return -1;
2035
2036        /* Write request */
2037        req->type = PIPELINE_REQ_TABLE_RULE_TTL_READ;
2038        req->id = table_id;
2039        req->table_rule_ttl_read.data = data;
2040        req->table_rule_ttl_read.clear = clear;
2041
2042        /* Send request and wait for response */
2043        rsp = pipeline_msg_send_recv(p, req);
2044
2045        /* Read response */
2046        status = rsp->status;
2047        if (status)
2048                memcpy(stats, &rsp->table_rule_ttl_read.stats, sizeof(*stats));
2049
2050        /* Free response */
2051        pipeline_msg_free(rsp);
2052
2053        return status;
2054}
2055
2056/**
2057 * Data plane threads: message handling
2058 */
2059static inline struct pipeline_msg_req *
2060pipeline_msg_recv(struct rte_ring *msgq_req)
2061{
2062        struct pipeline_msg_req *req;
2063
2064        int status = rte_ring_sc_dequeue(msgq_req, (void **)&req);
2065
2066        if (status != 0)
2067                return NULL;
2068
2069        return req;
2070}
2071
2072static inline void
2073pipeline_msg_send(struct rte_ring *msgq_rsp,
2074        struct pipeline_msg_rsp *rsp)
2075{
2076        int status;
2077
2078        do {
2079                status = rte_ring_sp_enqueue(msgq_rsp, rsp);
2080        } while (status == -ENOBUFS);
2081}
2082
2083static struct pipeline_msg_rsp *
2084pipeline_msg_handle_port_in_stats_read(struct pipeline_data *p,
2085        struct pipeline_msg_req *req)
2086{
2087        struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2088        uint32_t port_id = req->id;
2089        int clear = req->port_in_stats_read.clear;
2090
2091        rsp->status = rte_pipeline_port_in_stats_read(p->p,
2092                port_id,
2093                &rsp->port_in_stats_read.stats,
2094                clear);
2095
2096        return rsp;
2097}
2098
2099static struct pipeline_msg_rsp *
2100pipeline_msg_handle_port_in_enable(struct pipeline_data *p,
2101        struct pipeline_msg_req *req)
2102{
2103        struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2104        uint32_t port_id = req->id;
2105
2106        rsp->status = rte_pipeline_port_in_enable(p->p,
2107                port_id);
2108
2109        return rsp;
2110}
2111
2112static struct pipeline_msg_rsp *
2113pipeline_msg_handle_port_in_disable(struct pipeline_data *p,
2114        struct pipeline_msg_req *req)
2115{
2116        struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2117        uint32_t port_id = req->id;
2118
2119        rsp->status = rte_pipeline_port_in_disable(p->p,
2120                port_id);
2121
2122        return rsp;
2123}
2124
2125static struct pipeline_msg_rsp *
2126pipeline_msg_handle_port_out_stats_read(struct pipeline_data *p,
2127        struct pipeline_msg_req *req)
2128{
2129        struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2130        uint32_t port_id = req->id;
2131        int clear = req->port_out_stats_read.clear;
2132
2133        rsp->status = rte_pipeline_port_out_stats_read(p->p,
2134                port_id,
2135                &rsp->port_out_stats_read.stats,
2136                clear);
2137
2138        return rsp;
2139}
2140
2141static struct pipeline_msg_rsp *
2142pipeline_msg_handle_table_stats_read(struct pipeline_data *p,
2143        struct pipeline_msg_req *req)
2144{
2145        struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2146        uint32_t port_id = req->id;
2147        int clear = req->table_stats_read.clear;
2148
2149        rsp->status = rte_pipeline_table_stats_read(p->p,
2150                port_id,
2151                &rsp->table_stats_read.stats,
2152                clear);
2153
2154        return rsp;
2155}
2156
2157static int
2158match_convert_ipv6_depth(uint32_t depth, uint32_t *depth32)
2159{
2160        if (depth > 128)
2161                return -1;
2162
2163        switch (depth / 32) {
2164        case 0:
2165                depth32[0] = depth;
2166                depth32[1] = 0;
2167                depth32[2] = 0;
2168                depth32[3] = 0;
2169                return 0;
2170
2171        case 1:
2172                depth32[0] = 32;
2173                depth32[1] = depth - 32;
2174                depth32[2] = 0;
2175                depth32[3] = 0;
2176                return 0;
2177
2178        case 2:
2179                depth32[0] = 32;
2180                depth32[1] = 32;
2181                depth32[2] = depth - 64;
2182                depth32[3] = 0;
2183                return 0;
2184
2185        case 3:
2186                depth32[0] = 32;
2187                depth32[1] = 32;
2188                depth32[2] = 32;
2189                depth32[3] = depth - 96;
2190                return 0;
2191
2192        case 4:
2193                depth32[0] = 32;
2194                depth32[1] = 32;
2195                depth32[2] = 32;
2196                depth32[3] = 32;
2197                return 0;
2198
2199        default:
2200                return -1;
2201        }
2202}
2203
2204static int
2205match_convert(struct softnic_table_rule_match *mh,
2206        union table_rule_match_low_level *ml,
2207        int add)
2208{
2209        memset(ml, 0, sizeof(*ml));
2210
2211        switch (mh->match_type) {
2212        case TABLE_ACL:
2213                if (mh->match.acl.ip_version)
2214                        if (add) {
2215                                ml->acl_add.field_value[0].value.u8 =
2216                                        mh->match.acl.proto;
2217                                ml->acl_add.field_value[0].mask_range.u8 =
2218                                        mh->match.acl.proto_mask;
2219
2220                                ml->acl_add.field_value[1].value.u32 =
2221                                        mh->match.acl.ipv4.sa;
2222                                ml->acl_add.field_value[1].mask_range.u32 =
2223                                        mh->match.acl.sa_depth;
2224
2225                                ml->acl_add.field_value[2].value.u32 =
2226                                        mh->match.acl.ipv4.da;
2227                                ml->acl_add.field_value[2].mask_range.u32 =
2228                                        mh->match.acl.da_depth;
2229
2230                                ml->acl_add.field_value[3].value.u16 =
2231                                        mh->match.acl.sp0;
2232                                ml->acl_add.field_value[3].mask_range.u16 =
2233                                        mh->match.acl.sp1;
2234
2235                                ml->acl_add.field_value[4].value.u16 =
2236                                        mh->match.acl.dp0;
2237                                ml->acl_add.field_value[4].mask_range.u16 =
2238                                        mh->match.acl.dp1;
2239
2240                                ml->acl_add.priority =
2241                                        (int32_t)mh->match.acl.priority;
2242                        } else {
2243                                ml->acl_delete.field_value[0].value.u8 =
2244                                        mh->match.acl.proto;
2245                                ml->acl_delete.field_value[0].mask_range.u8 =
2246                                        mh->match.acl.proto_mask;
2247
2248                                ml->acl_delete.field_value[1].value.u32 =
2249                                        mh->match.acl.ipv4.sa;
2250                                ml->acl_delete.field_value[1].mask_range.u32 =
2251                                        mh->match.acl.sa_depth;
2252
2253                                ml->acl_delete.field_value[2].value.u32 =
2254                                        mh->match.acl.ipv4.da;
2255                                ml->acl_delete.field_value[2].mask_range.u32 =
2256                                        mh->match.acl.da_depth;
2257
2258                                ml->acl_delete.field_value[3].value.u16 =
2259                                        mh->match.acl.sp0;
2260                                ml->acl_delete.field_value[3].mask_range.u16 =
2261                                        mh->match.acl.sp1;
2262
2263                                ml->acl_delete.field_value[4].value.u16 =
2264                                        mh->match.acl.dp0;
2265                                ml->acl_delete.field_value[4].mask_range.u16 =
2266                                        mh->match.acl.dp1;
2267                        }
2268                else
2269                        if (add) {
2270                                uint32_t *sa32 =
2271                                        (uint32_t *)mh->match.acl.ipv6.sa;
2272                                uint32_t *da32 =
2273                                        (uint32_t *)mh->match.acl.ipv6.da;
2274                                uint32_t sa32_depth[4], da32_depth[4];
2275                                int status;
2276
2277                                status = match_convert_ipv6_depth(mh->match.acl.sa_depth,
2278                                        sa32_depth);
2279                                if (status)
2280                                        return status;
2281
2282                                status = match_convert_ipv6_depth(
2283                                        mh->match.acl.da_depth,
2284                                        da32_depth);
2285                                if (status)
2286                                        return status;
2287
2288                                ml->acl_add.field_value[0].value.u8 =
2289                                        mh->match.acl.proto;
2290                                ml->acl_add.field_value[0].mask_range.u8 =
2291                                        mh->match.acl.proto_mask;
2292
2293                                ml->acl_add.field_value[1].value.u32 =
2294                                        rte_be_to_cpu_32(sa32[0]);
2295                                ml->acl_add.field_value[1].mask_range.u32 =
2296                                        sa32_depth[0];
2297                                ml->acl_add.field_value[2].value.u32 =
2298                                        rte_be_to_cpu_32(sa32[1]);
2299                                ml->acl_add.field_value[2].mask_range.u32 =
2300                                        sa32_depth[1];
2301                                ml->acl_add.field_value[3].value.u32 =
2302                                        rte_be_to_cpu_32(sa32[2]);
2303                                ml->acl_add.field_value[3].mask_range.u32 =
2304                                        sa32_depth[2];
2305                                ml->acl_add.field_value[4].value.u32 =
2306                                        rte_be_to_cpu_32(sa32[3]);
2307                                ml->acl_add.field_value[4].mask_range.u32 =
2308                                        sa32_depth[3];
2309
2310                                ml->acl_add.field_value[5].value.u32 =
2311                                        rte_be_to_cpu_32(da32[0]);
2312                                ml->acl_add.field_value[5].mask_range.u32 =
2313                                        da32_depth[0];
2314                                ml->acl_add.field_value[6].value.u32 =
2315                                        rte_be_to_cpu_32(da32[1]);
2316                                ml->acl_add.field_value[6].mask_range.u32 =
2317                                        da32_depth[1];
2318                                ml->acl_add.field_value[7].value.u32 =
2319                                        rte_be_to_cpu_32(da32[2]);
2320                                ml->acl_add.field_value[7].mask_range.u32 =
2321                                        da32_depth[2];
2322                                ml->acl_add.field_value[8].value.u32 =
2323                                        rte_be_to_cpu_32(da32[3]);
2324                                ml->acl_add.field_value[8].mask_range.u32 =
2325                                        da32_depth[3];
2326
2327                                ml->acl_add.field_value[9].value.u16 =
2328                                        mh->match.acl.sp0;
2329                                ml->acl_add.field_value[9].mask_range.u16 =
2330                                        mh->match.acl.sp1;
2331
2332                                ml->acl_add.field_value[10].value.u16 =
2333                                        mh->match.acl.dp0;
2334                                ml->acl_add.field_value[10].mask_range.u16 =
2335                                        mh->match.acl.dp1;
2336
2337                                ml->acl_add.priority =
2338                                        (int32_t)mh->match.acl.priority;
2339                        } else {
2340                                uint32_t *sa32 =
2341                                        (uint32_t *)mh->match.acl.ipv6.sa;
2342                                uint32_t *da32 =
2343                                        (uint32_t *)mh->match.acl.ipv6.da;
2344                                uint32_t sa32_depth[4], da32_depth[4];
2345                                int status;
2346
2347                                status = match_convert_ipv6_depth(mh->match.acl.sa_depth,
2348                                        sa32_depth);
2349                                if (status)
2350                                        return status;
2351
2352                                status = match_convert_ipv6_depth(mh->match.acl.da_depth,
2353                                        da32_depth);
2354                                if (status)
2355                                        return status;
2356
2357                                ml->acl_delete.field_value[0].value.u8 =
2358                                        mh->match.acl.proto;
2359                                ml->acl_delete.field_value[0].mask_range.u8 =
2360                                        mh->match.acl.proto_mask;
2361
2362                                ml->acl_delete.field_value[1].value.u32 =
2363                                        rte_be_to_cpu_32(sa32[0]);
2364                                ml->acl_delete.field_value[1].mask_range.u32 =
2365                                        sa32_depth[0];
2366                                ml->acl_delete.field_value[2].value.u32 =
2367                                        rte_be_to_cpu_32(sa32[1]);
2368                                ml->acl_delete.field_value[2].mask_range.u32 =
2369                                        sa32_depth[1];
2370                                ml->acl_delete.field_value[3].value.u32 =
2371                                        rte_be_to_cpu_32(sa32[2]);
2372                                ml->acl_delete.field_value[3].mask_range.u32 =
2373                                        sa32_depth[2];
2374                                ml->acl_delete.field_value[4].value.u32 =
2375                                        rte_be_to_cpu_32(sa32[3]);
2376                                ml->acl_delete.field_value[4].mask_range.u32 =
2377                                        sa32_depth[3];
2378
2379                                ml->acl_delete.field_value[5].value.u32 =
2380                                        rte_be_to_cpu_32(da32[0]);
2381                                ml->acl_delete.field_value[5].mask_range.u32 =
2382                                        da32_depth[0];
2383                                ml->acl_delete.field_value[6].value.u32 =
2384                                        rte_be_to_cpu_32(da32[1]);
2385                                ml->acl_delete.field_value[6].mask_range.u32 =
2386                                        da32_depth[1];
2387                                ml->acl_delete.field_value[7].value.u32 =
2388                                        rte_be_to_cpu_32(da32[2]);
2389                                ml->acl_delete.field_value[7].mask_range.u32 =
2390                                        da32_depth[2];
2391                                ml->acl_delete.field_value[8].value.u32 =
2392                                        rte_be_to_cpu_32(da32[3]);
2393                                ml->acl_delete.field_value[8].mask_range.u32 =
2394                                        da32_depth[3];
2395
2396                                ml->acl_delete.field_value[9].value.u16 =
2397                                        mh->match.acl.sp0;
2398                                ml->acl_delete.field_value[9].mask_range.u16 =
2399                                        mh->match.acl.sp1;
2400
2401                                ml->acl_delete.field_value[10].value.u16 =
2402                                        mh->match.acl.dp0;
2403                                ml->acl_delete.field_value[10].mask_range.u16 =
2404                                        mh->match.acl.dp1;
2405                        }
2406                return 0;
2407
2408        case TABLE_ARRAY:
2409                ml->array.pos = mh->match.array.pos;
2410                return 0;
2411
2412        case TABLE_HASH:
2413                memcpy(ml->hash, mh->match.hash.key, sizeof(ml->hash));
2414                return 0;
2415
2416        case TABLE_LPM:
2417                if (mh->match.lpm.ip_version) {
2418                        ml->lpm_ipv4.ip = mh->match.lpm.ipv4;
2419                        ml->lpm_ipv4.depth = mh->match.lpm.depth;
2420                } else {
2421                        memcpy(ml->lpm_ipv6.ip,
2422                                mh->match.lpm.ipv6, sizeof(ml->lpm_ipv6.ip));
2423                        ml->lpm_ipv6.depth = mh->match.lpm.depth;
2424                }
2425
2426                return 0;
2427
2428        default:
2429                return -1;
2430        }
2431}
2432
2433static int
2434action_convert(struct rte_table_action *a,
2435        struct softnic_table_rule_action *action,
2436        struct rte_pipeline_table_entry *data)
2437{
2438        int status;
2439
2440        /* Apply actions */
2441        if (action->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) {
2442                status = rte_table_action_apply(a,
2443                        data,
2444                        RTE_TABLE_ACTION_FWD,
2445                        &action->fwd);
2446
2447                if (status)
2448                        return status;
2449        }
2450
2451        if (action->action_mask & (1LLU << RTE_TABLE_ACTION_LB)) {
2452                status = rte_table_action_apply(a,
2453                        data,
2454                        RTE_TABLE_ACTION_LB,
2455                        &action->lb);
2456
2457                if (status)
2458                        return status;
2459        }
2460
2461        if (action->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
2462                status = rte_table_action_apply(a,
2463                        data,
2464                        RTE_TABLE_ACTION_MTR,
2465                        &action->mtr);
2466
2467                if (status)
2468                        return status;
2469        }
2470
2471        if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
2472                status = rte_table_action_apply(a,
2473                        data,
2474                        RTE_TABLE_ACTION_TM,
2475                        &action->tm);
2476
2477                if (status)
2478                        return status;
2479        }
2480
2481        if (action->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
2482                status = rte_table_action_apply(a,
2483                        data,
2484                        RTE_TABLE_ACTION_ENCAP,
2485                        &action->encap);
2486
2487                if (status)
2488                        return status;
2489        }
2490
2491        if (action->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
2492                status = rte_table_action_apply(a,
2493                        data,
2494                        RTE_TABLE_ACTION_NAT,
2495                        &action->nat);
2496
2497                if (status)
2498                        return status;
2499        }
2500
2501        if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TTL)) {
2502                status = rte_table_action_apply(a,
2503                        data,
2504                        RTE_TABLE_ACTION_TTL,
2505                        &action->ttl);
2506
2507                if (status)
2508                        return status;
2509        }
2510
2511        if (action->action_mask & (1LLU << RTE_TABLE_ACTION_STATS)) {
2512                status = rte_table_action_apply(a,
2513                        data,
2514                        RTE_TABLE_ACTION_STATS,
2515                        &action->stats);
2516
2517                if (status)
2518                        return status;
2519        }
2520
2521        if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TIME)) {
2522                status = rte_table_action_apply(a,
2523                        data,
2524                        RTE_TABLE_ACTION_TIME,
2525                        &action->time);
2526
2527                if (status)
2528                        return status;
2529        }
2530
2531        if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TAG)) {
2532                status = rte_table_action_apply(a,
2533                        data,
2534                        RTE_TABLE_ACTION_TAG,
2535                        &action->tag);
2536
2537                if (status)
2538                        return status;
2539        }
2540
2541        if (action->action_mask & (1LLU << RTE_TABLE_ACTION_DECAP)) {
2542                status = rte_table_action_apply(a,
2543                        data,
2544                        RTE_TABLE_ACTION_DECAP,
2545                        &action->decap);
2546
2547                if (status)
2548                        return status;
2549        }
2550
2551        if (action->action_mask & (1LLU << RTE_TABLE_ACTION_SYM_CRYPTO)) {
2552                status = rte_table_action_apply(a,
2553                        data,
2554                        RTE_TABLE_ACTION_SYM_CRYPTO,
2555                        &action->sym_crypto);
2556
2557                if (status)
2558                        return status;
2559        }
2560
2561        return 0;
2562}
2563
2564static struct pipeline_msg_rsp *
2565pipeline_msg_handle_table_rule_add(struct pipeline_data *p,
2566        struct pipeline_msg_req *req)
2567{
2568        union table_rule_match_low_level match_ll;
2569        struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2570        struct softnic_table_rule_match *match = &req->table_rule_add.match;
2571        struct softnic_table_rule_action *action = &req->table_rule_add.action;
2572        struct rte_pipeline_table_entry *data_in, *data_out;
2573        uint32_t table_id = req->id;
2574        int key_found, status;
2575        struct rte_table_action *a = p->table_data[table_id].a;
2576
2577        /* Apply actions */
2578        memset(p->buffer, 0, sizeof(p->buffer));
2579        data_in = (struct rte_pipeline_table_entry *)p->buffer;
2580
2581        status = match_convert(match, &match_ll, 1);
2582        if (status) {
2583                rsp->status = -1;
2584                return rsp;
2585        }
2586
2587        status = action_convert(a, action, data_in);
2588        if (status) {
2589                rsp->status = -1;
2590                return rsp;
2591        }
2592
2593        status = rte_pipeline_table_entry_add(p->p,
2594                table_id,
2595                &match_ll,
2596                data_in,
2597                &key_found,
2598                &data_out);
2599        if (status) {
2600                rsp->status = -1;
2601                return rsp;
2602        }
2603
2604        /* Write response */
2605        rsp->status = 0;
2606        rsp->table_rule_add.data = data_out;
2607
2608        return rsp;
2609}
2610
2611static struct pipeline_msg_rsp *
2612pipeline_msg_handle_table_rule_add_default(struct pipeline_data *p,
2613        struct pipeline_msg_req *req)
2614{
2615        struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2616        struct softnic_table_rule_action *action = &req->table_rule_add_default.action;
2617        struct rte_pipeline_table_entry *data_in, *data_out;
2618        uint32_t table_id = req->id;
2619        int status;
2620
2621        /* Apply actions */
2622        memset(p->buffer, 0, sizeof(p->buffer));
2623        data_in = (struct rte_pipeline_table_entry *)p->buffer;
2624
2625        data_in->action = action->fwd.action;
2626        if (action->fwd.action == RTE_PIPELINE_ACTION_PORT)
2627                data_in->port_id = action->fwd.id;
2628        if (action->fwd.action == RTE_PIPELINE_ACTION_TABLE)
2629                data_in->table_id = action->fwd.id;
2630
2631        /* Add default rule to table */
2632        status = rte_pipeline_table_default_entry_add(p->p,
2633                table_id,
2634                data_in,
2635                &data_out);
2636        if (status) {
2637                rsp->status = -1;
2638                return rsp;
2639        }
2640
2641        /* Write response */
2642        rsp->status = 0;
2643        rsp->table_rule_add_default.data = data_out;
2644
2645        return rsp;
2646}
2647
2648static struct pipeline_msg_rsp *
2649pipeline_msg_handle_table_rule_add_bulk(struct pipeline_data *p,
2650        struct pipeline_msg_req *req)
2651{
2652        struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2653
2654        uint32_t table_id = req->id;
2655        struct softnic_table_rule_match *match = req->table_rule_add_bulk.match;
2656        struct softnic_table_rule_action *action = req->table_rule_add_bulk.action;
2657        struct rte_pipeline_table_entry **data =
2658                (struct rte_pipeline_table_entry **)req->table_rule_add_bulk.data;
2659        uint32_t n_rules = req->table_rule_add_bulk.n_rules;
2660        uint32_t bulk = req->table_rule_add_bulk.bulk;
2661
2662        struct rte_table_action *a = p->table_data[table_id].a;
2663        union table_rule_match_low_level *match_ll;
2664        uint8_t *action_ll;
2665        void **match_ll_ptr;
2666        struct rte_pipeline_table_entry **action_ll_ptr;
2667        int *found, status;
2668        uint32_t i;
2669
2670        /* Memory allocation */
2671        match_ll = calloc(n_rules, sizeof(union table_rule_match_low_level));
2672        action_ll = calloc(n_rules, TABLE_RULE_ACTION_SIZE_MAX);
2673        match_ll_ptr = calloc(n_rules, sizeof(void *));
2674        action_ll_ptr =
2675                calloc(n_rules, sizeof(struct rte_pipeline_table_entry *));
2676        found = calloc(n_rules, sizeof(int));
2677
2678        if (match_ll == NULL ||
2679                action_ll == NULL ||
2680                match_ll_ptr == NULL ||
2681                action_ll_ptr == NULL ||
2682                found == NULL)
2683                goto fail;
2684
2685        for (i = 0; i < n_rules; i++) {
2686                match_ll_ptr[i] = (void *)&match_ll[i];
2687                action_ll_ptr[i] =
2688                        (struct rte_pipeline_table_entry *)&action_ll[i * TABLE_RULE_ACTION_SIZE_MAX];
2689        }
2690
2691        /* Rule match conversion */
2692        for (i = 0; i < n_rules; i++) {
2693                status = match_convert(&match[i], match_ll_ptr[i], 1);
2694                if (status)
2695                        goto fail;
2696        }
2697
2698        /* Rule action conversion */
2699        for (i = 0; i < n_rules; i++) {
2700                status = action_convert(a, &action[i], action_ll_ptr[i]);
2701                if (status)
2702                        goto fail;
2703        }
2704
2705        /* Add rule (match, action) to table */
2706        if (bulk) {
2707                status = rte_pipeline_table_entry_add_bulk(p->p,
2708                        table_id,
2709                        match_ll_ptr,
2710                        action_ll_ptr,
2711                        n_rules,
2712                        found,
2713                        data);
2714                if (status)
2715                        n_rules = 0;
2716        } else {
2717                for (i = 0; i < n_rules; i++) {
2718                        status = rte_pipeline_table_entry_add(p->p,
2719                                table_id,
2720                                match_ll_ptr[i],
2721                                action_ll_ptr[i],
2722                                &found[i],
2723                                &data[i]);
2724                        if (status) {
2725                                n_rules = i;
2726                                break;
2727                        }
2728                }
2729        }
2730
2731        /* Write response */
2732        rsp->status = 0;
2733        rsp->table_rule_add_bulk.n_rules = n_rules;
2734
2735        /* Free */
2736        free(found);
2737        free(action_ll_ptr);
2738        free(match_ll_ptr);
2739        free(action_ll);
2740        free(match_ll);
2741
2742        return rsp;
2743
2744fail:
2745        free(found);
2746        free(action_ll_ptr);
2747        free(match_ll_ptr);
2748        free(action_ll);
2749        free(match_ll);
2750
2751        rsp->status = -1;
2752        rsp->table_rule_add_bulk.n_rules = 0;
2753        return rsp;
2754}
2755
2756static struct pipeline_msg_rsp *
2757pipeline_msg_handle_table_rule_delete(struct pipeline_data *p,
2758        struct pipeline_msg_req *req)
2759{
2760        union table_rule_match_low_level match_ll;
2761        struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2762        struct softnic_table_rule_match *match = &req->table_rule_delete.match;
2763        uint32_t table_id = req->id;
2764        int key_found, status;
2765
2766        status = match_convert(match, &match_ll, 0);
2767        if (status) {
2768                rsp->status = -1;
2769                return rsp;
2770        }
2771
2772        rsp->status = rte_pipeline_table_entry_delete(p->p,
2773                table_id,
2774                &match_ll,
2775                &key_found,
2776                NULL);
2777
2778        return rsp;
2779}
2780
2781static struct pipeline_msg_rsp *
2782pipeline_msg_handle_table_rule_delete_default(struct pipeline_data *p,
2783        struct pipeline_msg_req *req)
2784{
2785        struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2786        uint32_t table_id = req->id;
2787
2788        rsp->status = rte_pipeline_table_default_entry_delete(p->p,
2789                table_id,
2790                NULL);
2791
2792        return rsp;
2793}
2794
2795static struct pipeline_msg_rsp *
2796pipeline_msg_handle_table_rule_stats_read(struct pipeline_data *p,
2797        struct pipeline_msg_req *req)
2798{
2799        struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2800        uint32_t table_id = req->id;
2801        void *data = req->table_rule_stats_read.data;
2802        int clear = req->table_rule_stats_read.clear;
2803        struct rte_table_action *a = p->table_data[table_id].a;
2804
2805        rsp->status = rte_table_action_stats_read(a,
2806                data,
2807                &rsp->table_rule_stats_read.stats,
2808                clear);
2809
2810        return rsp;
2811}
2812
2813static struct pipeline_msg_rsp *
2814pipeline_msg_handle_table_mtr_profile_add(struct pipeline_data *p,
2815        struct pipeline_msg_req *req)
2816{
2817        struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2818        uint32_t table_id = req->id;
2819        uint32_t meter_profile_id = req->table_mtr_profile_add.meter_profile_id;
2820        struct rte_table_action_meter_profile *profile =
2821                &req->table_mtr_profile_add.profile;
2822        struct rte_table_action *a = p->table_data[table_id].a;
2823
2824        rsp->status = rte_table_action_meter_profile_add(a,
2825                meter_profile_id,
2826                profile);
2827
2828        return rsp;
2829}
2830
2831static struct pipeline_msg_rsp *
2832pipeline_msg_handle_table_mtr_profile_delete(struct pipeline_data *p,
2833        struct pipeline_msg_req *req)
2834{
2835        struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2836        uint32_t table_id = req->id;
2837        uint32_t meter_profile_id =
2838                req->table_mtr_profile_delete.meter_profile_id;
2839        struct rte_table_action *a = p->table_data[table_id].a;
2840
2841        rsp->status = rte_table_action_meter_profile_delete(a,
2842                meter_profile_id);
2843
2844        return rsp;
2845}
2846
2847static struct pipeline_msg_rsp *
2848pipeline_msg_handle_table_rule_mtr_read(struct pipeline_data *p,
2849        struct pipeline_msg_req *req)
2850{
2851        struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2852        uint32_t table_id = req->id;
2853        void *data = req->table_rule_mtr_read.data;
2854        uint32_t tc_mask = req->table_rule_mtr_read.tc_mask;
2855        int clear = req->table_rule_mtr_read.clear;
2856        struct rte_table_action *a = p->table_data[table_id].a;
2857
2858        rsp->status = rte_table_action_meter_read(a,
2859                data,
2860                tc_mask,
2861                &rsp->table_rule_mtr_read.stats,
2862                clear);
2863
2864        return rsp;
2865}
2866
2867static struct pipeline_msg_rsp *
2868pipeline_msg_handle_table_dscp_table_update(struct pipeline_data *p,
2869        struct pipeline_msg_req *req)
2870{
2871        struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2872        uint32_t table_id = req->id;
2873        uint64_t dscp_mask = req->table_dscp_table_update.dscp_mask;
2874        struct rte_table_action_dscp_table *dscp_table =
2875                &req->table_dscp_table_update.dscp_table;
2876        struct rte_table_action *a = p->table_data[table_id].a;
2877
2878        rsp->status = rte_table_action_dscp_table_update(a,
2879                dscp_mask,
2880                dscp_table);
2881
2882        return rsp;
2883}
2884
2885static struct pipeline_msg_rsp *
2886pipeline_msg_handle_table_rule_ttl_read(struct pipeline_data *p,
2887        struct pipeline_msg_req *req)
2888{
2889        struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
2890        uint32_t table_id = req->id;
2891        void *data = req->table_rule_ttl_read.data;
2892        int clear = req->table_rule_ttl_read.clear;
2893        struct rte_table_action *a = p->table_data[table_id].a;
2894
2895        rsp->status = rte_table_action_ttl_read(a,
2896                data,
2897                &rsp->table_rule_ttl_read.stats,
2898                clear);
2899
2900        return rsp;
2901}
2902
2903static void
2904pipeline_msg_handle(struct pipeline_data *p)
2905{
2906        for ( ; ; ) {
2907                struct pipeline_msg_req *req;
2908                struct pipeline_msg_rsp *rsp;
2909
2910                req = pipeline_msg_recv(p->msgq_req);
2911                if (req == NULL)
2912                        break;
2913
2914                switch (req->type) {
2915                case PIPELINE_REQ_PORT_IN_STATS_READ:
2916                        rsp = pipeline_msg_handle_port_in_stats_read(p, req);
2917                        break;
2918
2919                case PIPELINE_REQ_PORT_IN_ENABLE:
2920                        rsp = pipeline_msg_handle_port_in_enable(p, req);
2921                        break;
2922
2923                case PIPELINE_REQ_PORT_IN_DISABLE:
2924                        rsp = pipeline_msg_handle_port_in_disable(p, req);
2925                        break;
2926
2927                case PIPELINE_REQ_PORT_OUT_STATS_READ:
2928                        rsp = pipeline_msg_handle_port_out_stats_read(p, req);
2929                        break;
2930
2931                case PIPELINE_REQ_TABLE_STATS_READ:
2932                        rsp = pipeline_msg_handle_table_stats_read(p, req);
2933                        break;
2934
2935                case PIPELINE_REQ_TABLE_RULE_ADD:
2936                        rsp = pipeline_msg_handle_table_rule_add(p, req);
2937                        break;
2938
2939                case PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT:
2940                        rsp = pipeline_msg_handle_table_rule_add_default(p,     req);
2941                        break;
2942
2943                case PIPELINE_REQ_TABLE_RULE_ADD_BULK:
2944                        rsp = pipeline_msg_handle_table_rule_add_bulk(p, req);
2945                        break;
2946
2947                case PIPELINE_REQ_TABLE_RULE_DELETE:
2948                        rsp = pipeline_msg_handle_table_rule_delete(p, req);
2949                        break;
2950
2951                case PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT:
2952                        rsp = pipeline_msg_handle_table_rule_delete_default(p, req);
2953                        break;
2954
2955                case PIPELINE_REQ_TABLE_RULE_STATS_READ:
2956                        rsp = pipeline_msg_handle_table_rule_stats_read(p, req);
2957                        break;
2958
2959                case PIPELINE_REQ_TABLE_MTR_PROFILE_ADD:
2960                        rsp = pipeline_msg_handle_table_mtr_profile_add(p, req);
2961                        break;
2962
2963                case PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE:
2964                        rsp = pipeline_msg_handle_table_mtr_profile_delete(p, req);
2965                        break;
2966
2967                case PIPELINE_REQ_TABLE_RULE_MTR_READ:
2968                        rsp = pipeline_msg_handle_table_rule_mtr_read(p, req);
2969                        break;
2970
2971                case PIPELINE_REQ_TABLE_DSCP_TABLE_UPDATE:
2972                        rsp = pipeline_msg_handle_table_dscp_table_update(p, req);
2973                        break;
2974
2975                case PIPELINE_REQ_TABLE_RULE_TTL_READ:
2976                        rsp = pipeline_msg_handle_table_rule_ttl_read(p, req);
2977                        break;
2978
2979                default:
2980                        rsp = (struct pipeline_msg_rsp *)req;
2981                        rsp->status = -1;
2982                }
2983
2984                pipeline_msg_send(p->msgq_rsp, rsp);
2985        }
2986}
2987
2988/**
2989 * Data plane threads: main
2990 */
2991static int32_t
2992rte_pmd_softnic_run_internal(void *arg)
2993{
2994        struct rte_eth_dev *dev = arg;
2995        struct pmd_internals *softnic;
2996        struct softnic_thread_data *t;
2997        uint32_t thread_id, j;
2998
2999        softnic = dev->data->dev_private;
3000        thread_id = rte_lcore_id();
3001        t = &softnic->thread_data[thread_id];
3002        t->iter++;
3003
3004        /* Data Plane */
3005        for (j = 0; j < t->n_pipelines; j++)
3006                rte_pipeline_run(t->p[j]);
3007
3008        /* Control Plane */
3009        if ((t->iter & 0xFLLU) == 0) {
3010                uint64_t time = rte_get_tsc_cycles();
3011                uint64_t time_next_min = UINT64_MAX;
3012
3013                if (time < t->time_next_min)
3014                        return 0;
3015
3016                /* Pipeline message queues */
3017                for (j = 0; j < t->n_pipelines; j++) {
3018                        struct pipeline_data *p =
3019                                &t->pipeline_data[j];
3020                        uint64_t time_next = p->time_next;
3021
3022                        if (time_next <= time) {
3023                                pipeline_msg_handle(p);
3024                                rte_pipeline_flush(p->p);
3025                                time_next = time + p->timer_period;
3026                                p->time_next = time_next;
3027                        }
3028
3029                        if (time_next < time_next_min)
3030                                time_next_min = time_next;
3031                }
3032
3033                /* Thread message queues */
3034                {
3035                        uint64_t time_next = t->time_next;
3036
3037                        if (time_next <= time) {
3038                                thread_msg_handle(t);
3039                                time_next = time + t->timer_period;
3040                                t->time_next = time_next;
3041                        }
3042
3043                        if (time_next < time_next_min)
3044                                time_next_min = time_next;
3045                }
3046
3047                t->time_next_min = time_next_min;
3048        }
3049
3050        return 0;
3051}
3052
3053int
3054rte_pmd_softnic_run(uint16_t port_id)
3055{
3056        struct rte_eth_dev *dev = &rte_eth_devices[port_id];
3057
3058#ifdef RTE_LIBRTE_ETHDEV_DEBUG
3059        RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, 0);
3060#endif
3061
3062        return (int)rte_pmd_softnic_run_internal(dev);
3063}
3064