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