dpdk/examples/ntb/ntb_fwd.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright(c) 2019 Intel Corporation
   3 */
   4#include <stdint.h>
   5#include <stdio.h>
   6#include <inttypes.h>
   7#include <unistd.h>
   8#include <signal.h>
   9#include <string.h>
  10#include <getopt.h>
  11
  12#include <cmdline_parse_string.h>
  13#include <cmdline_socket.h>
  14#include <cmdline.h>
  15#include <rte_common.h>
  16#include <rte_rawdev.h>
  17#include <rte_ethdev.h>
  18#include <rte_malloc.h>
  19#include <rte_lcore.h>
  20#include <rte_cycles.h>
  21#include <rte_pmd_ntb.h>
  22#include <rte_mbuf_pool_ops.h>
  23
  24/* Per-port statistics struct */
  25struct ntb_port_statistics {
  26        uint64_t tx;
  27        uint64_t rx;
  28} __rte_cache_aligned;
  29/* Port 0: NTB dev, Port 1: ethdev when iofwd. */
  30struct ntb_port_statistics ntb_port_stats[2];
  31
  32struct ntb_fwd_stream {
  33        uint16_t tx_port;
  34        uint16_t rx_port;
  35        uint16_t qp_id;
  36        uint8_t tx_ntb;  /* If ntb device is tx port. */
  37};
  38
  39struct ntb_fwd_lcore_conf {
  40        uint16_t stream_id;
  41        uint16_t nb_stream;
  42        uint8_t stopped;
  43};
  44
  45enum ntb_fwd_mode {
  46        FILE_TRANS = 0,
  47        RXONLY,
  48        TXONLY,
  49        IOFWD,
  50        MAX_FWD_MODE,
  51};
  52static const char *const fwd_mode_s[] = {
  53        "file-trans",
  54        "rxonly",
  55        "txonly",
  56        "iofwd",
  57        NULL,
  58};
  59static enum ntb_fwd_mode fwd_mode = MAX_FWD_MODE;
  60
  61static struct ntb_fwd_lcore_conf fwd_lcore_conf[RTE_MAX_LCORE];
  62static struct ntb_fwd_stream *fwd_streams;
  63
  64static struct rte_mempool *mbuf_pool;
  65
  66#define NTB_DRV_NAME_LEN 7
  67#define MEMPOOL_CACHE_SIZE 256
  68
  69static uint8_t in_test;
  70static uint8_t interactive = 1;
  71static uint16_t eth_port_id = RTE_MAX_ETHPORTS;
  72static uint16_t dev_id;
  73
  74/* Number of queues, default set as 1 */
  75static uint16_t num_queues = 1;
  76static uint16_t ntb_buf_size = RTE_MBUF_DEFAULT_BUF_SIZE;
  77
  78/* Configurable number of descriptors */
  79#define NTB_DEFAULT_NUM_DESCS 1024
  80static uint16_t nb_desc = NTB_DEFAULT_NUM_DESCS;
  81
  82static uint16_t tx_free_thresh;
  83
  84#define NTB_MAX_PKT_BURST 32
  85#define NTB_DFLT_PKT_BURST 32
  86static uint16_t pkt_burst = NTB_DFLT_PKT_BURST;
  87
  88#define BURST_TX_RETRIES 64
  89
  90static struct rte_eth_conf eth_port_conf = {
  91        .rxmode = {
  92                .mq_mode = ETH_MQ_RX_RSS,
  93                .split_hdr_size = 0,
  94        },
  95        .rx_adv_conf = {
  96                .rss_conf = {
  97                        .rss_key = NULL,
  98                        .rss_hf = ETH_RSS_IP,
  99                },
 100        },
 101        .txmode = {
 102                .mq_mode = ETH_MQ_TX_NONE,
 103        },
 104};
 105
 106/* *** Help command with introduction. *** */
 107struct cmd_help_result {
 108        cmdline_fixed_string_t help;
 109};
 110
 111static void
 112cmd_help_parsed(__rte_unused void *parsed_result,
 113                struct cmdline *cl,
 114                __rte_unused void *data)
 115{
 116        cmdline_printf(
 117                cl,
 118                "\n"
 119                "The following commands are currently available:\n\n"
 120                "Control:\n"
 121                "    quit                                      :"
 122                " Quit the application.\n"
 123                "\nTransmission:\n"
 124                "    send [path]                               :"
 125                " Send [path] file. Only take effect in file-trans mode\n"
 126                "    start                                     :"
 127                " Start transmissions.\n"
 128                "    stop                                      :"
 129                " Stop transmissions.\n"
 130                "    clear/show port stats                     :"
 131                " Clear/show port stats.\n"
 132                "    set fwd file-trans/rxonly/txonly/iofwd    :"
 133                " Set packet forwarding mode.\n"
 134        );
 135
 136}
 137
 138cmdline_parse_token_string_t cmd_help_help =
 139        TOKEN_STRING_INITIALIZER(struct cmd_help_result, help, "help");
 140
 141cmdline_parse_inst_t cmd_help = {
 142        .f = cmd_help_parsed,
 143        .data = NULL,
 144        .help_str = "show help",
 145        .tokens = {
 146                (void *)&cmd_help_help,
 147                NULL,
 148        },
 149};
 150
 151/* *** QUIT *** */
 152struct cmd_quit_result {
 153        cmdline_fixed_string_t quit;
 154};
 155
 156static void
 157cmd_quit_parsed(__rte_unused void *parsed_result,
 158                struct cmdline *cl,
 159                __rte_unused void *data)
 160{
 161        struct ntb_fwd_lcore_conf *conf;
 162        uint32_t lcore_id;
 163
 164        /* Stop transmission first. */
 165        RTE_LCORE_FOREACH_WORKER(lcore_id) {
 166                conf = &fwd_lcore_conf[lcore_id];
 167
 168                if (!conf->nb_stream)
 169                        continue;
 170
 171                if (conf->stopped)
 172                        continue;
 173
 174                conf->stopped = 1;
 175        }
 176        printf("\nWaiting for lcores to finish...\n");
 177        rte_eal_mp_wait_lcore();
 178        in_test = 0;
 179
 180        /* Stop traffic and Close port. */
 181        rte_rawdev_stop(dev_id);
 182        rte_rawdev_close(dev_id);
 183        if (eth_port_id < RTE_MAX_ETHPORTS && fwd_mode == IOFWD) {
 184                rte_eth_dev_stop(eth_port_id);
 185                rte_eth_dev_close(eth_port_id);
 186        }
 187
 188        cmdline_quit(cl);
 189}
 190
 191cmdline_parse_token_string_t cmd_quit_quit =
 192                TOKEN_STRING_INITIALIZER(struct cmd_quit_result, quit, "quit");
 193
 194cmdline_parse_inst_t cmd_quit = {
 195        .f = cmd_quit_parsed,
 196        .data = NULL,
 197        .help_str = "exit application",
 198        .tokens = {
 199                (void *)&cmd_quit_quit,
 200                NULL,
 201        },
 202};
 203
 204/* *** SEND FILE PARAMETERS *** */
 205struct cmd_sendfile_result {
 206        cmdline_fixed_string_t send_string;
 207        char filepath[];
 208};
 209
 210static void
 211cmd_sendfile_parsed(void *parsed_result,
 212                    __rte_unused struct cmdline *cl,
 213                    __rte_unused void *data)
 214{
 215        struct cmd_sendfile_result *res = parsed_result;
 216        struct rte_rawdev_buf *pkts_send[NTB_MAX_PKT_BURST];
 217        struct rte_mbuf *mbuf_send[NTB_MAX_PKT_BURST];
 218        uint64_t size, count, i, j, nb_burst;
 219        uint16_t nb_tx, buf_size;
 220        unsigned int nb_pkt;
 221        size_t queue_id = 0;
 222        uint16_t retry = 0;
 223        uint32_t val;
 224        FILE *file;
 225        int ret;
 226
 227        if (num_queues != 1) {
 228                printf("File transmission only supports 1 queue.\n");
 229                num_queues = 1;
 230        }
 231
 232        file = fopen(res->filepath, "r");
 233        if (file == NULL) {
 234                printf("Fail to open the file.\n");
 235                return;
 236        }
 237
 238        if (fseek(file, 0, SEEK_END) < 0) {
 239                printf("Fail to get file size.\n");
 240                fclose(file);
 241                return;
 242        }
 243        size = ftell(file);
 244        if (fseek(file, 0, SEEK_SET) < 0) {
 245                printf("Fail to get file size.\n");
 246                fclose(file);
 247                return;
 248        }
 249
 250        /* Tell remote about the file size. */
 251        val = size >> 32;
 252        rte_rawdev_set_attr(dev_id, "spad_user_0", val);
 253        val = size;
 254        rte_rawdev_set_attr(dev_id, "spad_user_1", val);
 255        printf("Sending file, size is %"PRIu64"\n", size);
 256
 257        for (i = 0; i < NTB_MAX_PKT_BURST; i++)
 258                pkts_send[i] = (struct rte_rawdev_buf *)
 259                                malloc(sizeof(struct rte_rawdev_buf));
 260
 261        buf_size = ntb_buf_size - RTE_PKTMBUF_HEADROOM;
 262        count = (size + buf_size - 1) / buf_size;
 263        nb_burst = (count + pkt_burst - 1) / pkt_burst;
 264
 265        for (i = 0; i < nb_burst; i++) {
 266                val = RTE_MIN(count, pkt_burst);
 267                if (rte_mempool_get_bulk(mbuf_pool, (void **)mbuf_send,
 268                                        val) == 0) {
 269                        for (nb_pkt = 0; nb_pkt < val; nb_pkt++) {
 270                                mbuf_send[nb_pkt]->port = dev_id;
 271                                mbuf_send[nb_pkt]->data_len =
 272                                fread(rte_pktmbuf_mtod(mbuf_send[nb_pkt],
 273                                        void *), 1, buf_size, file);
 274                                mbuf_send[nb_pkt]->pkt_len =
 275                                        mbuf_send[nb_pkt]->data_len;
 276                                pkts_send[nb_pkt]->buf_addr = mbuf_send[nb_pkt];
 277                        }
 278                } else {
 279                        for (nb_pkt = 0; nb_pkt < val; nb_pkt++) {
 280                                mbuf_send[nb_pkt] =
 281                                        rte_mbuf_raw_alloc(mbuf_pool);
 282                                if (mbuf_send[nb_pkt] == NULL)
 283                                        break;
 284                                mbuf_send[nb_pkt]->port = dev_id;
 285                                mbuf_send[nb_pkt]->data_len =
 286                                fread(rte_pktmbuf_mtod(mbuf_send[nb_pkt],
 287                                        void *), 1, buf_size, file);
 288                                mbuf_send[nb_pkt]->pkt_len =
 289                                        mbuf_send[nb_pkt]->data_len;
 290                                pkts_send[nb_pkt]->buf_addr = mbuf_send[nb_pkt];
 291                        }
 292                }
 293
 294                ret = rte_rawdev_enqueue_buffers(dev_id, pkts_send, nb_pkt,
 295                                                (void *)queue_id);
 296                if (ret < 0) {
 297                        printf("Enqueue failed with err %d\n", ret);
 298                        for (j = 0; j < nb_pkt; j++)
 299                                rte_pktmbuf_free(mbuf_send[j]);
 300                        goto clean;
 301                }
 302                nb_tx = ret;
 303                while (nb_tx != nb_pkt && retry < BURST_TX_RETRIES) {
 304                        rte_delay_us(1);
 305                        ret = rte_rawdev_enqueue_buffers(dev_id,
 306                                        &pkts_send[nb_tx], nb_pkt - nb_tx,
 307                                        (void *)queue_id);
 308                        if (ret < 0) {
 309                                printf("Enqueue failed with err %d\n", ret);
 310                                for (j = nb_tx; j < nb_pkt; j++)
 311                                        rte_pktmbuf_free(mbuf_send[j]);
 312                                goto clean;
 313                        }
 314                        nb_tx += ret;
 315                }
 316                count -= nb_pkt;
 317        }
 318
 319        /* Clear register after file sending done. */
 320        rte_rawdev_set_attr(dev_id, "spad_user_0", 0);
 321        rte_rawdev_set_attr(dev_id, "spad_user_1", 0);
 322        printf("Done sending file.\n");
 323
 324clean:
 325        for (i = 0; i < NTB_MAX_PKT_BURST; i++)
 326                free(pkts_send[i]);
 327        fclose(file);
 328}
 329
 330cmdline_parse_token_string_t cmd_send_file_send =
 331        TOKEN_STRING_INITIALIZER(struct cmd_sendfile_result, send_string,
 332                                 "send");
 333cmdline_parse_token_string_t cmd_send_file_filepath =
 334        TOKEN_STRING_INITIALIZER(struct cmd_sendfile_result, filepath, NULL);
 335
 336
 337cmdline_parse_inst_t cmd_send_file = {
 338        .f = cmd_sendfile_parsed,
 339        .data = NULL,
 340        .help_str = "send <file_path>",
 341        .tokens = {
 342                (void *)&cmd_send_file_send,
 343                (void *)&cmd_send_file_filepath,
 344                NULL,
 345        },
 346};
 347
 348#define RECV_FILE_LEN 30
 349static int
 350start_polling_recv_file(void *param)
 351{
 352        struct rte_rawdev_buf *pkts_recv[NTB_MAX_PKT_BURST];
 353        struct ntb_fwd_lcore_conf *conf = param;
 354        struct rte_mbuf *mbuf;
 355        char filepath[RECV_FILE_LEN];
 356        uint64_t val, size, file_len;
 357        uint16_t nb_rx, i, file_no;
 358        size_t queue_id = 0;
 359        FILE *file;
 360        int ret;
 361
 362        for (i = 0; i < NTB_MAX_PKT_BURST; i++)
 363                pkts_recv[i] = (struct rte_rawdev_buf *)
 364                                malloc(sizeof(struct rte_rawdev_buf));
 365
 366        file_no = 0;
 367        while (!conf->stopped) {
 368                snprintf(filepath, RECV_FILE_LEN, "ntb_recv_file%d", file_no);
 369                file = fopen(filepath, "w");
 370                if (file == NULL) {
 371                        printf("Fail to open the file.\n");
 372                        return -EINVAL;
 373                }
 374
 375                rte_rawdev_get_attr(dev_id, "spad_user_0", &val);
 376                size = val << 32;
 377                rte_rawdev_get_attr(dev_id, "spad_user_1", &val);
 378                size |= val;
 379
 380                if (!size) {
 381                        fclose(file);
 382                        continue;
 383                }
 384
 385                file_len = 0;
 386                nb_rx = NTB_MAX_PKT_BURST;
 387                while (file_len < size && !conf->stopped) {
 388                        ret = rte_rawdev_dequeue_buffers(dev_id, pkts_recv,
 389                                        pkt_burst, (void *)queue_id);
 390                        if (ret < 0) {
 391                                printf("Dequeue failed with err %d\n", ret);
 392                                fclose(file);
 393                                goto clean;
 394                        }
 395                        nb_rx = ret;
 396                        ntb_port_stats[0].rx += nb_rx;
 397                        for (i = 0; i < nb_rx; i++) {
 398                                mbuf = pkts_recv[i]->buf_addr;
 399                                fwrite(rte_pktmbuf_mtod(mbuf, void *), 1,
 400                                        mbuf->data_len, file);
 401                                file_len += mbuf->data_len;
 402                                rte_pktmbuf_free(mbuf);
 403                                pkts_recv[i]->buf_addr = NULL;
 404                        }
 405                }
 406
 407                printf("Received file (size: %" PRIu64 ") from peer to %s.\n",
 408                        size, filepath);
 409                fclose(file);
 410                file_no++;
 411        }
 412
 413clean:
 414        for (i = 0; i < NTB_MAX_PKT_BURST; i++)
 415                free(pkts_recv[i]);
 416        return 0;
 417}
 418
 419static int
 420start_iofwd_per_lcore(void *param)
 421{
 422        struct rte_rawdev_buf *ntb_buf[NTB_MAX_PKT_BURST];
 423        struct rte_mbuf *pkts_burst[NTB_MAX_PKT_BURST];
 424        struct ntb_fwd_lcore_conf *conf = param;
 425        struct ntb_fwd_stream fs;
 426        uint16_t nb_rx, nb_tx;
 427        int i, j, ret;
 428
 429        for (i = 0; i < NTB_MAX_PKT_BURST; i++)
 430                ntb_buf[i] = (struct rte_rawdev_buf *)
 431                             malloc(sizeof(struct rte_rawdev_buf));
 432
 433        while (!conf->stopped) {
 434                for (i = 0; i < conf->nb_stream; i++) {
 435                        fs = fwd_streams[conf->stream_id + i];
 436                        if (fs.tx_ntb) {
 437                                nb_rx = rte_eth_rx_burst(fs.rx_port,
 438                                                fs.qp_id, pkts_burst,
 439                                                pkt_burst);
 440                                if (unlikely(nb_rx == 0))
 441                                        continue;
 442                                for (j = 0; j < nb_rx; j++)
 443                                        ntb_buf[j]->buf_addr = pkts_burst[j];
 444                                ret = rte_rawdev_enqueue_buffers(fs.tx_port,
 445                                                ntb_buf, nb_rx,
 446                                                (void *)(size_t)fs.qp_id);
 447                                if (ret < 0) {
 448                                        printf("Enqueue failed with err %d\n",
 449                                                ret);
 450                                        for (j = 0; j < nb_rx; j++)
 451                                                rte_pktmbuf_free(pkts_burst[j]);
 452                                        goto clean;
 453                                }
 454                                nb_tx = ret;
 455                                ntb_port_stats[0].tx += nb_tx;
 456                                ntb_port_stats[1].rx += nb_rx;
 457                        } else {
 458                                ret = rte_rawdev_dequeue_buffers(fs.rx_port,
 459                                                ntb_buf, pkt_burst,
 460                                                (void *)(size_t)fs.qp_id);
 461                                if (ret < 0) {
 462                                        printf("Dequeue failed with err %d\n",
 463                                                ret);
 464                                        goto clean;
 465                                }
 466                                nb_rx = ret;
 467                                if (unlikely(nb_rx == 0))
 468                                        continue;
 469                                for (j = 0; j < nb_rx; j++)
 470                                        pkts_burst[j] = ntb_buf[j]->buf_addr;
 471                                nb_tx = rte_eth_tx_burst(fs.tx_port,
 472                                        fs.qp_id, pkts_burst, nb_rx);
 473                                ntb_port_stats[1].tx += nb_tx;
 474                                ntb_port_stats[0].rx += nb_rx;
 475                        }
 476                        if (unlikely(nb_tx < nb_rx)) {
 477                                do {
 478                                        rte_pktmbuf_free(pkts_burst[nb_tx]);
 479                                } while (++nb_tx < nb_rx);
 480                        }
 481                }
 482        }
 483
 484clean:
 485        for (i = 0; i < NTB_MAX_PKT_BURST; i++)
 486                free(ntb_buf[i]);
 487
 488        return 0;
 489}
 490
 491static int
 492start_rxonly_per_lcore(void *param)
 493{
 494        struct rte_rawdev_buf *ntb_buf[NTB_MAX_PKT_BURST];
 495        struct ntb_fwd_lcore_conf *conf = param;
 496        struct ntb_fwd_stream fs;
 497        uint16_t nb_rx;
 498        int i, j, ret;
 499
 500        for (i = 0; i < NTB_MAX_PKT_BURST; i++)
 501                ntb_buf[i] = (struct rte_rawdev_buf *)
 502                             malloc(sizeof(struct rte_rawdev_buf));
 503
 504        while (!conf->stopped) {
 505                for (i = 0; i < conf->nb_stream; i++) {
 506                        fs = fwd_streams[conf->stream_id + i];
 507                        ret = rte_rawdev_dequeue_buffers(fs.rx_port,
 508                              ntb_buf, pkt_burst, (void *)(size_t)fs.qp_id);
 509                        if (ret < 0) {
 510                                printf("Dequeue failed with err %d\n", ret);
 511                                goto clean;
 512                        }
 513                        nb_rx = ret;
 514                        if (unlikely(nb_rx == 0))
 515                                continue;
 516                        ntb_port_stats[0].rx += nb_rx;
 517
 518                        for (j = 0; j < nb_rx; j++)
 519                                rte_pktmbuf_free(ntb_buf[j]->buf_addr);
 520                }
 521        }
 522
 523clean:
 524        for (i = 0; i < NTB_MAX_PKT_BURST; i++)
 525                free(ntb_buf[i]);
 526
 527        return 0;
 528}
 529
 530
 531static int
 532start_txonly_per_lcore(void *param)
 533{
 534        struct rte_rawdev_buf *ntb_buf[NTB_MAX_PKT_BURST];
 535        struct rte_mbuf *pkts_burst[NTB_MAX_PKT_BURST];
 536        struct ntb_fwd_lcore_conf *conf = param;
 537        struct ntb_fwd_stream fs;
 538        uint16_t nb_pkt, nb_tx;
 539        int i, j, ret;
 540
 541        for (i = 0; i < NTB_MAX_PKT_BURST; i++)
 542                ntb_buf[i] = (struct rte_rawdev_buf *)
 543                             malloc(sizeof(struct rte_rawdev_buf));
 544
 545        while (!conf->stopped) {
 546                for (i = 0; i < conf->nb_stream; i++) {
 547                        fs = fwd_streams[conf->stream_id + i];
 548                        if (rte_mempool_get_bulk(mbuf_pool, (void **)pkts_burst,
 549                                  pkt_burst) == 0) {
 550                                for (nb_pkt = 0; nb_pkt < pkt_burst; nb_pkt++) {
 551                                        pkts_burst[nb_pkt]->port = dev_id;
 552                                        pkts_burst[nb_pkt]->data_len =
 553                                                pkts_burst[nb_pkt]->buf_len -
 554                                                RTE_PKTMBUF_HEADROOM;
 555                                        pkts_burst[nb_pkt]->pkt_len =
 556                                                pkts_burst[nb_pkt]->data_len;
 557                                        ntb_buf[nb_pkt]->buf_addr =
 558                                                pkts_burst[nb_pkt];
 559                                }
 560                        } else {
 561                                for (nb_pkt = 0; nb_pkt < pkt_burst; nb_pkt++) {
 562                                        pkts_burst[nb_pkt] =
 563                                                rte_pktmbuf_alloc(mbuf_pool);
 564                                        if (pkts_burst[nb_pkt] == NULL)
 565                                                break;
 566                                        pkts_burst[nb_pkt]->port = dev_id;
 567                                        pkts_burst[nb_pkt]->data_len =
 568                                                pkts_burst[nb_pkt]->buf_len -
 569                                                RTE_PKTMBUF_HEADROOM;
 570                                        pkts_burst[nb_pkt]->pkt_len =
 571                                                pkts_burst[nb_pkt]->data_len;
 572                                        ntb_buf[nb_pkt]->buf_addr =
 573                                                pkts_burst[nb_pkt];
 574                                }
 575                        }
 576                        ret = rte_rawdev_enqueue_buffers(fs.tx_port, ntb_buf,
 577                                        nb_pkt, (void *)(size_t)fs.qp_id);
 578                        if (ret < 0) {
 579                                printf("Enqueue failed with err %d\n", ret);
 580                                for (j = 0; j < nb_pkt; j++)
 581                                        rte_pktmbuf_free(pkts_burst[j]);
 582                                goto clean;
 583                        }
 584                        nb_tx = ret;
 585                        ntb_port_stats[0].tx += nb_tx;
 586                        if (unlikely(nb_tx < nb_pkt)) {
 587                                do {
 588                                        rte_pktmbuf_free(pkts_burst[nb_tx]);
 589                                } while (++nb_tx < nb_pkt);
 590                        }
 591                }
 592        }
 593
 594clean:
 595        for (i = 0; i < NTB_MAX_PKT_BURST; i++)
 596                free(ntb_buf[i]);
 597
 598        return 0;
 599}
 600
 601static int
 602ntb_fwd_config_setup(void)
 603{
 604        uint16_t i;
 605
 606        /* Make sure iofwd has valid ethdev. */
 607        if (fwd_mode == IOFWD && eth_port_id >= RTE_MAX_ETHPORTS) {
 608                printf("No ethdev, cannot be in iofwd mode.");
 609                return -EINVAL;
 610        }
 611
 612        if (fwd_mode == IOFWD) {
 613                fwd_streams = rte_zmalloc("ntb_fwd: fwd_streams",
 614                        sizeof(struct ntb_fwd_stream) * num_queues * 2,
 615                        RTE_CACHE_LINE_SIZE);
 616                for (i = 0; i < num_queues; i++) {
 617                        fwd_streams[i * 2].qp_id = i;
 618                        fwd_streams[i * 2].tx_port = dev_id;
 619                        fwd_streams[i * 2].rx_port = eth_port_id;
 620                        fwd_streams[i * 2].tx_ntb = 1;
 621
 622                        fwd_streams[i * 2 + 1].qp_id = i;
 623                        fwd_streams[i * 2 + 1].tx_port = eth_port_id;
 624                        fwd_streams[i * 2 + 1].rx_port = dev_id;
 625                        fwd_streams[i * 2 + 1].tx_ntb = 0;
 626                }
 627                return 0;
 628        }
 629
 630        if (fwd_mode == RXONLY || fwd_mode == FILE_TRANS) {
 631                /* Only support 1 queue in file-trans for in order. */
 632                if (fwd_mode == FILE_TRANS)
 633                        num_queues = 1;
 634
 635                fwd_streams = rte_zmalloc("ntb_fwd: fwd_streams",
 636                                sizeof(struct ntb_fwd_stream) * num_queues,
 637                                RTE_CACHE_LINE_SIZE);
 638                for (i = 0; i < num_queues; i++) {
 639                        fwd_streams[i].qp_id = i;
 640                        fwd_streams[i].tx_port = RTE_MAX_ETHPORTS;
 641                        fwd_streams[i].rx_port = dev_id;
 642                        fwd_streams[i].tx_ntb = 0;
 643                }
 644                return 0;
 645        }
 646
 647        if (fwd_mode == TXONLY) {
 648                fwd_streams = rte_zmalloc("ntb_fwd: fwd_streams",
 649                                sizeof(struct ntb_fwd_stream) * num_queues,
 650                                RTE_CACHE_LINE_SIZE);
 651                for (i = 0; i < num_queues; i++) {
 652                        fwd_streams[i].qp_id = i;
 653                        fwd_streams[i].tx_port = dev_id;
 654                        fwd_streams[i].rx_port = RTE_MAX_ETHPORTS;
 655                        fwd_streams[i].tx_ntb = 1;
 656                }
 657        }
 658        return 0;
 659}
 660
 661static void
 662assign_stream_to_lcores(void)
 663{
 664        struct ntb_fwd_lcore_conf *conf;
 665        struct ntb_fwd_stream *fs;
 666        uint16_t nb_streams, sm_per_lcore, sm_id, i;
 667        uint32_t lcore_id;
 668        uint8_t lcore_num, nb_extra;
 669
 670        lcore_num = rte_lcore_count();
 671        /* Exclude main core */
 672        lcore_num--;
 673
 674        nb_streams = (fwd_mode == IOFWD) ? num_queues * 2 : num_queues;
 675
 676        sm_per_lcore = nb_streams / lcore_num;
 677        nb_extra = nb_streams % lcore_num;
 678        sm_id = 0;
 679        i = 0;
 680
 681        RTE_LCORE_FOREACH_WORKER(lcore_id) {
 682                conf = &fwd_lcore_conf[lcore_id];
 683
 684                if (i < nb_extra) {
 685                        conf->nb_stream = sm_per_lcore + 1;
 686                        conf->stream_id = sm_id;
 687                        sm_id = sm_id + sm_per_lcore + 1;
 688                } else {
 689                        conf->nb_stream = sm_per_lcore;
 690                        conf->stream_id = sm_id;
 691                        sm_id = sm_id + sm_per_lcore;
 692                }
 693
 694                i++;
 695                if (sm_id >= nb_streams)
 696                        break;
 697        }
 698
 699        /* Print packet forwading config. */
 700        RTE_LCORE_FOREACH_WORKER(lcore_id) {
 701                conf = &fwd_lcore_conf[lcore_id];
 702
 703                if (!conf->nb_stream)
 704                        continue;
 705
 706                printf("Streams on Lcore %u :\n", lcore_id);
 707                for (i = 0; i < conf->nb_stream; i++) {
 708                        fs = &fwd_streams[conf->stream_id + i];
 709                        if (fwd_mode == IOFWD)
 710                                printf(" + Stream %u : %s%u RX -> %s%u TX,"
 711                                        " Q=%u\n", conf->stream_id + i,
 712                                        fs->tx_ntb ? "Eth" : "NTB", fs->rx_port,
 713                                        fs->tx_ntb ? "NTB" : "Eth", fs->tx_port,
 714                                        fs->qp_id);
 715                        if (fwd_mode == FILE_TRANS || fwd_mode == RXONLY)
 716                                printf(" + Stream %u : %s%u RX only\n",
 717                                        conf->stream_id, "NTB", fs->rx_port);
 718                        if (fwd_mode == TXONLY)
 719                                printf(" + Stream %u : %s%u TX only\n",
 720                                        conf->stream_id, "NTB", fs->tx_port);
 721                }
 722        }
 723}
 724
 725static void
 726start_pkt_fwd(void)
 727{
 728        struct ntb_fwd_lcore_conf *conf;
 729        struct rte_eth_link eth_link;
 730        uint32_t lcore_id;
 731        int ret, i;
 732        char link_status_text[RTE_ETH_LINK_MAX_STR_LEN];
 733
 734        ret = ntb_fwd_config_setup();
 735        if (ret < 0) {
 736                printf("Cannot start traffic. Please reset fwd mode.\n");
 737                return;
 738        }
 739
 740        /* If using iofwd, checking ethdev link status first. */
 741        if (fwd_mode == IOFWD) {
 742                printf("Checking eth link status...\n");
 743                /* Wait for eth link up at most 100 times. */
 744                for (i = 0; i < 100; i++) {
 745                        ret = rte_eth_link_get(eth_port_id, &eth_link);
 746                        if (ret < 0) {
 747                                printf("Link get failed with err %d\n", ret);
 748                                return;
 749                        }
 750                        if (eth_link.link_status) {
 751                                rte_eth_link_to_str(link_status_text,
 752                                        sizeof(link_status_text),
 753                                        &eth_link);
 754                                printf("Eth%u %s\n", eth_port_id,
 755                                       link_status_text);
 756                                break;
 757                        }
 758                }
 759                if (!eth_link.link_status) {
 760                        printf("Eth%u link down. Cannot start traffic.\n",
 761                                eth_port_id);
 762                        return;
 763                }
 764        }
 765
 766        assign_stream_to_lcores();
 767        in_test = 1;
 768
 769        RTE_LCORE_FOREACH_WORKER(lcore_id) {
 770                conf = &fwd_lcore_conf[lcore_id];
 771
 772                if (!conf->nb_stream)
 773                        continue;
 774
 775                conf->stopped = 0;
 776                if (fwd_mode == FILE_TRANS)
 777                        rte_eal_remote_launch(start_polling_recv_file,
 778                                              conf, lcore_id);
 779                else if (fwd_mode == IOFWD)
 780                        rte_eal_remote_launch(start_iofwd_per_lcore,
 781                                              conf, lcore_id);
 782                else if (fwd_mode == RXONLY)
 783                        rte_eal_remote_launch(start_rxonly_per_lcore,
 784                                              conf, lcore_id);
 785                else if (fwd_mode == TXONLY)
 786                        rte_eal_remote_launch(start_txonly_per_lcore,
 787                                              conf, lcore_id);
 788        }
 789}
 790
 791/* *** START FWD PARAMETERS *** */
 792struct cmd_start_result {
 793        cmdline_fixed_string_t start;
 794};
 795
 796static void
 797cmd_start_parsed(__rte_unused void *parsed_result,
 798                            __rte_unused struct cmdline *cl,
 799                            __rte_unused void *data)
 800{
 801        start_pkt_fwd();
 802}
 803
 804cmdline_parse_token_string_t cmd_start_start =
 805                TOKEN_STRING_INITIALIZER(struct cmd_start_result, start, "start");
 806
 807cmdline_parse_inst_t cmd_start = {
 808        .f = cmd_start_parsed,
 809        .data = NULL,
 810        .help_str = "start pkt fwd between ntb and ethdev",
 811        .tokens = {
 812                (void *)&cmd_start_start,
 813                NULL,
 814        },
 815};
 816
 817/* *** STOP *** */
 818struct cmd_stop_result {
 819        cmdline_fixed_string_t stop;
 820};
 821
 822static void
 823cmd_stop_parsed(__rte_unused void *parsed_result,
 824                __rte_unused struct cmdline *cl,
 825                __rte_unused void *data)
 826{
 827        struct ntb_fwd_lcore_conf *conf;
 828        uint32_t lcore_id;
 829
 830        RTE_LCORE_FOREACH_WORKER(lcore_id) {
 831                conf = &fwd_lcore_conf[lcore_id];
 832
 833                if (!conf->nb_stream)
 834                        continue;
 835
 836                if (conf->stopped)
 837                        continue;
 838
 839                conf->stopped = 1;
 840        }
 841        printf("\nWaiting for lcores to finish...\n");
 842        rte_eal_mp_wait_lcore();
 843        in_test = 0;
 844        printf("\nDone.\n");
 845}
 846
 847cmdline_parse_token_string_t cmd_stop_stop =
 848                TOKEN_STRING_INITIALIZER(struct cmd_stop_result, stop, "stop");
 849
 850cmdline_parse_inst_t cmd_stop = {
 851        .f = cmd_stop_parsed,
 852        .data = NULL,
 853        .help_str = "stop: Stop packet forwarding",
 854        .tokens = {
 855                (void *)&cmd_stop_stop,
 856                NULL,
 857        },
 858};
 859
 860static void
 861ntb_stats_clear(void)
 862{
 863        int nb_ids, i;
 864        uint32_t *ids;
 865
 866        /* Clear NTB dev stats */
 867        nb_ids = rte_rawdev_xstats_names_get(dev_id, NULL, 0);
 868        if (nb_ids  < 0) {
 869                printf("Error: Cannot get count of xstats\n");
 870                return;
 871        }
 872        ids = malloc(sizeof(uint32_t) * nb_ids);
 873        for (i = 0; i < nb_ids; i++)
 874                ids[i] = i;
 875        rte_rawdev_xstats_reset(dev_id, ids, nb_ids);
 876        printf("\n  statistics for NTB port %d cleared\n", dev_id);
 877
 878        /* Clear Ethdev stats if have any */
 879        if (fwd_mode == IOFWD && eth_port_id != RTE_MAX_ETHPORTS) {
 880                rte_eth_stats_reset(eth_port_id);
 881                printf("\n  statistics for ETH port %d cleared\n", eth_port_id);
 882        }
 883}
 884
 885static inline void
 886ntb_calculate_throughput(uint16_t port) {
 887        uint64_t diff_pkts_rx, diff_pkts_tx, diff_cycles;
 888        uint64_t mpps_rx, mpps_tx;
 889        static uint64_t prev_pkts_rx[2];
 890        static uint64_t prev_pkts_tx[2];
 891        static uint64_t prev_cycles[2];
 892
 893        diff_cycles = prev_cycles[port];
 894        prev_cycles[port] = rte_rdtsc();
 895        if (diff_cycles > 0)
 896                diff_cycles = prev_cycles[port] - diff_cycles;
 897        diff_pkts_rx = (ntb_port_stats[port].rx > prev_pkts_rx[port]) ?
 898                (ntb_port_stats[port].rx - prev_pkts_rx[port]) : 0;
 899        diff_pkts_tx = (ntb_port_stats[port].tx > prev_pkts_tx[port]) ?
 900                (ntb_port_stats[port].tx - prev_pkts_tx[port]) : 0;
 901        prev_pkts_rx[port] = ntb_port_stats[port].rx;
 902        prev_pkts_tx[port] = ntb_port_stats[port].tx;
 903        mpps_rx = diff_cycles > 0 ?
 904                diff_pkts_rx * rte_get_tsc_hz() / diff_cycles : 0;
 905        mpps_tx = diff_cycles > 0 ?
 906                diff_pkts_tx * rte_get_tsc_hz() / diff_cycles : 0;
 907        printf("  Throughput (since last show)\n");
 908        printf("  Rx-pps: %12"PRIu64"\n  Tx-pps: %12"PRIu64"\n",
 909                        mpps_rx, mpps_tx);
 910
 911}
 912
 913static void
 914ntb_stats_display(void)
 915{
 916        struct rte_rawdev_xstats_name *xstats_names;
 917        struct rte_eth_stats stats;
 918        uint64_t *values;
 919        uint32_t *ids;
 920        int nb_ids, i;
 921
 922        printf("###### statistics for NTB port %d #######\n", dev_id);
 923
 924        /* Get NTB dev stats and stats names */
 925        nb_ids = rte_rawdev_xstats_names_get(dev_id, NULL, 0);
 926        if (nb_ids  < 0) {
 927                printf("Error: Cannot get count of xstats\n");
 928                return;
 929        }
 930        xstats_names = malloc(sizeof(struct rte_rawdev_xstats_name) * nb_ids);
 931        if (xstats_names == NULL) {
 932                printf("Cannot allocate memory for xstats lookup\n");
 933                return;
 934        }
 935        if (nb_ids != rte_rawdev_xstats_names_get(
 936                        dev_id, xstats_names, nb_ids)) {
 937                printf("Error: Cannot get xstats lookup\n");
 938                free(xstats_names);
 939                return;
 940        }
 941        ids = malloc(sizeof(uint32_t) * nb_ids);
 942        for (i = 0; i < nb_ids; i++)
 943                ids[i] = i;
 944        values = malloc(sizeof(uint64_t) * nb_ids);
 945        if (nb_ids != rte_rawdev_xstats_get(dev_id, ids, values, nb_ids)) {
 946                printf("Error: Unable to get xstats\n");
 947                free(xstats_names);
 948                free(values);
 949                free(ids);
 950                return;
 951        }
 952
 953        /* Display NTB dev stats */
 954        for (i = 0; i < nb_ids; i++)
 955                printf("  %s: %"PRIu64"\n", xstats_names[i].name, values[i]);
 956        ntb_calculate_throughput(0);
 957
 958        /* Get Ethdev stats if have any */
 959        if (fwd_mode == IOFWD && eth_port_id != RTE_MAX_ETHPORTS) {
 960                printf("###### statistics for ETH port %d ######\n",
 961                        eth_port_id);
 962                rte_eth_stats_get(eth_port_id, &stats);
 963                printf("  RX-packets: %"PRIu64"\n", stats.ipackets);
 964                printf("  RX-bytes: %"PRIu64"\n", stats.ibytes);
 965                printf("  RX-errors: %"PRIu64"\n", stats.ierrors);
 966                printf("  RX-missed: %"PRIu64"\n", stats.imissed);
 967                printf("  TX-packets: %"PRIu64"\n", stats.opackets);
 968                printf("  TX-bytes: %"PRIu64"\n", stats.obytes);
 969                printf("  TX-errors: %"PRIu64"\n", stats.oerrors);
 970                ntb_calculate_throughput(1);
 971        }
 972
 973        free(xstats_names);
 974        free(values);
 975        free(ids);
 976}
 977
 978/* *** SHOW/CLEAR PORT STATS *** */
 979struct cmd_stats_result {
 980        cmdline_fixed_string_t show;
 981        cmdline_fixed_string_t port;
 982        cmdline_fixed_string_t stats;
 983};
 984
 985static void
 986cmd_stats_parsed(void *parsed_result,
 987                 __rte_unused struct cmdline *cl,
 988                 __rte_unused void *data)
 989{
 990        struct cmd_stats_result *res = parsed_result;
 991        if (!strcmp(res->show, "clear"))
 992                ntb_stats_clear();
 993        else
 994                ntb_stats_display();
 995}
 996
 997cmdline_parse_token_string_t cmd_stats_show =
 998        TOKEN_STRING_INITIALIZER(struct cmd_stats_result, show, "show#clear");
 999cmdline_parse_token_string_t cmd_stats_port =
1000        TOKEN_STRING_INITIALIZER(struct cmd_stats_result, port, "port");
1001cmdline_parse_token_string_t cmd_stats_stats =
1002        TOKEN_STRING_INITIALIZER(struct cmd_stats_result, stats, "stats");
1003
1004
1005cmdline_parse_inst_t cmd_stats = {
1006        .f = cmd_stats_parsed,
1007        .data = NULL,
1008        .help_str = "show|clear port stats",
1009        .tokens = {
1010                (void *)&cmd_stats_show,
1011                (void *)&cmd_stats_port,
1012                (void *)&cmd_stats_stats,
1013                NULL,
1014        },
1015};
1016
1017/* *** SET FORWARDING MODE *** */
1018struct cmd_set_fwd_mode_result {
1019        cmdline_fixed_string_t set;
1020        cmdline_fixed_string_t fwd;
1021        cmdline_fixed_string_t mode;
1022};
1023
1024static void
1025cmd_set_fwd_mode_parsed(__rte_unused void *parsed_result,
1026                        __rte_unused struct cmdline *cl,
1027                        __rte_unused void *data)
1028{
1029        struct cmd_set_fwd_mode_result *res = parsed_result;
1030        int i;
1031
1032        if (in_test) {
1033                printf("Please stop traffic first.\n");
1034                return;
1035        }
1036
1037        for (i = 0; i < MAX_FWD_MODE; i++) {
1038                if (!strcmp(res->mode, fwd_mode_s[i])) {
1039                        fwd_mode = i;
1040                        return;
1041                }
1042        }
1043        printf("Invalid %s packet forwarding mode.\n", res->mode);
1044}
1045
1046cmdline_parse_token_string_t cmd_setfwd_set =
1047        TOKEN_STRING_INITIALIZER(struct cmd_set_fwd_mode_result, set, "set");
1048cmdline_parse_token_string_t cmd_setfwd_fwd =
1049        TOKEN_STRING_INITIALIZER(struct cmd_set_fwd_mode_result, fwd, "fwd");
1050cmdline_parse_token_string_t cmd_setfwd_mode =
1051        TOKEN_STRING_INITIALIZER(struct cmd_set_fwd_mode_result, mode,
1052                                "file-trans#iofwd#txonly#rxonly");
1053
1054cmdline_parse_inst_t cmd_set_fwd_mode = {
1055        .f = cmd_set_fwd_mode_parsed,
1056        .data = NULL,
1057        .help_str = "set forwarding mode as file-trans|rxonly|txonly|iofwd",
1058        .tokens = {
1059                (void *)&cmd_setfwd_set,
1060                (void *)&cmd_setfwd_fwd,
1061                (void *)&cmd_setfwd_mode,
1062                NULL,
1063        },
1064};
1065
1066/* list of instructions */
1067cmdline_parse_ctx_t main_ctx[] = {
1068        (cmdline_parse_inst_t *)&cmd_help,
1069        (cmdline_parse_inst_t *)&cmd_send_file,
1070        (cmdline_parse_inst_t *)&cmd_start,
1071        (cmdline_parse_inst_t *)&cmd_stop,
1072        (cmdline_parse_inst_t *)&cmd_stats,
1073        (cmdline_parse_inst_t *)&cmd_set_fwd_mode,
1074        (cmdline_parse_inst_t *)&cmd_quit,
1075        NULL,
1076};
1077
1078/* prompt function, called from main on MAIN lcore */
1079static void
1080prompt(void)
1081{
1082        struct cmdline *cl;
1083
1084        cl = cmdline_stdin_new(main_ctx, "ntb> ");
1085        if (cl == NULL)
1086                return;
1087
1088        cmdline_interact(cl);
1089        cmdline_stdin_exit(cl);
1090}
1091
1092static void
1093signal_handler(int signum)
1094{
1095        if (signum == SIGINT || signum == SIGTERM) {
1096                printf("\nSignal %d received, preparing to exit...\n", signum);
1097                signal(signum, SIG_DFL);
1098                kill(getpid(), signum);
1099        }
1100}
1101
1102#define OPT_BUF_SIZE         "buf-size"
1103#define OPT_FWD_MODE         "fwd-mode"
1104#define OPT_NB_DESC          "nb-desc"
1105#define OPT_TXFREET          "txfreet"
1106#define OPT_BURST            "burst"
1107#define OPT_QP               "qp"
1108
1109enum {
1110        /* long options mapped to a short option */
1111        OPT_NO_ZERO_COPY_NUM = 1,
1112        OPT_BUF_SIZE_NUM,
1113        OPT_FWD_MODE_NUM,
1114        OPT_NB_DESC_NUM,
1115        OPT_TXFREET_NUM,
1116        OPT_BURST_NUM,
1117        OPT_QP_NUM,
1118};
1119
1120static const char short_options[] =
1121        "i" /* interactive mode */
1122        ;
1123
1124static const struct option lgopts[] = {
1125        {OPT_BUF_SIZE,     1, NULL, OPT_BUF_SIZE_NUM     },
1126        {OPT_FWD_MODE,     1, NULL, OPT_FWD_MODE_NUM     },
1127        {OPT_NB_DESC,      1, NULL, OPT_NB_DESC_NUM      },
1128        {OPT_TXFREET,      1, NULL, OPT_TXFREET_NUM      },
1129        {OPT_BURST,        1, NULL, OPT_BURST_NUM        },
1130        {OPT_QP,           1, NULL, OPT_QP_NUM           },
1131        {0,                0, NULL, 0                    }
1132};
1133
1134static void
1135ntb_usage(const char *prgname)
1136{
1137        printf("%s [EAL options] -- [options]\n"
1138               "-i: run in interactive mode.\n"
1139               "-qp=N: set number of queues as N (N > 0, default: 1).\n"
1140               "--fwd-mode=N: set fwd mode (N: file-trans | rxonly | "
1141               "txonly | iofwd, default: file-trans)\n"
1142               "--buf-size=N: set mbuf dataroom size as N (0 < N < 65535,"
1143               " default: 2048).\n"
1144               "--nb-desc=N: set number of descriptors as N (%u <= N <= %u,"
1145               " default: 1024).\n"
1146               "--txfreet=N: set tx free thresh for NTB driver as N. (N >= 0)\n"
1147               "--burst=N: set pkt burst as N (0 < N <= %u default: 32).\n",
1148               prgname, NTB_MIN_DESC_SIZE, NTB_MAX_DESC_SIZE,
1149               NTB_MAX_PKT_BURST);
1150}
1151
1152static void
1153ntb_parse_args(int argc, char **argv)
1154{
1155        char *prgname = argv[0], **argvopt = argv;
1156        int opt, opt_idx, n, i;
1157
1158        while ((opt = getopt_long(argc, argvopt, short_options,
1159                                lgopts, &opt_idx)) != EOF) {
1160                switch (opt) {
1161                case 'i':
1162                        printf("Interactive-mode selected.\n");
1163                        interactive = 1;
1164                        break;
1165                case OPT_QP_NUM:
1166                        n = atoi(optarg);
1167                        if (n > 0)
1168                                num_queues = n;
1169                        else
1170                                rte_exit(EXIT_FAILURE, "q must be > 0.\n");
1171                        break;
1172                case OPT_BUF_SIZE_NUM:
1173                        n = atoi(optarg);
1174                        if (n > RTE_PKTMBUF_HEADROOM && n <= 0xFFFF)
1175                                ntb_buf_size = n;
1176                        else
1177                                rte_exit(EXIT_FAILURE, "buf-size must be > "
1178                                        "%u and < 65536.\n",
1179                                        RTE_PKTMBUF_HEADROOM);
1180                        break;
1181                case OPT_FWD_MODE_NUM:
1182                        for (i = 0; i < MAX_FWD_MODE; i++) {
1183                                if (!strcmp(optarg, fwd_mode_s[i])) {
1184                                        fwd_mode = i;
1185                                        break;
1186                                }
1187                        }
1188                        if (i == MAX_FWD_MODE)
1189                                rte_exit(EXIT_FAILURE, "Unsupported mode. "
1190                                "(Should be: file-trans | rxonly | txonly "
1191                                "| iofwd)\n");
1192                        break;
1193                case OPT_NB_DESC_NUM:
1194                        n = atoi(optarg);
1195                        if (n >= NTB_MIN_DESC_SIZE && n <= NTB_MAX_DESC_SIZE)
1196                                nb_desc = n;
1197                        else
1198                                rte_exit(EXIT_FAILURE, "nb-desc must be within"
1199                                        " [%u, %u].\n", NTB_MIN_DESC_SIZE,
1200                                        NTB_MAX_DESC_SIZE);
1201                        break;
1202                case OPT_TXFREET_NUM:
1203                        n = atoi(optarg);
1204                        if (n >= 0)
1205                                tx_free_thresh = n;
1206                        else
1207                                rte_exit(EXIT_FAILURE, "txfreet must be"
1208                                        " >= 0\n");
1209                        break;
1210                case OPT_BURST_NUM:
1211                        n = atoi(optarg);
1212                        if (n > 0 && n <= NTB_MAX_PKT_BURST)
1213                                pkt_burst = n;
1214                        else
1215                                rte_exit(EXIT_FAILURE, "burst must be within "
1216                                        "(0, %u].\n", NTB_MAX_PKT_BURST);
1217                        break;
1218
1219                default:
1220                        ntb_usage(prgname);
1221                        rte_exit(EXIT_FAILURE,
1222                                 "Command line is incomplete or incorrect.\n");
1223                        break;
1224                }
1225        }
1226}
1227
1228static void
1229ntb_mempool_mz_free(__rte_unused struct rte_mempool_memhdr *memhdr,
1230                void *opaque)
1231{
1232        const struct rte_memzone *mz = opaque;
1233        rte_memzone_free(mz);
1234}
1235
1236static struct rte_mempool *
1237ntb_mbuf_pool_create(uint16_t mbuf_seg_size, uint32_t nb_mbuf,
1238                     struct ntb_dev_info ntb_info,
1239                     struct ntb_dev_config *ntb_conf,
1240                     unsigned int socket_id)
1241{
1242        size_t mz_len, total_elt_sz, max_mz_len, left_sz;
1243        struct rte_pktmbuf_pool_private mbp_priv;
1244        char pool_name[RTE_MEMPOOL_NAMESIZE];
1245        char mz_name[RTE_MEMZONE_NAMESIZE];
1246        const struct rte_memzone *mz;
1247        struct rte_mempool *mp;
1248        uint64_t align;
1249        uint32_t mz_id;
1250        int ret;
1251
1252        snprintf(pool_name, sizeof(pool_name), "ntb_mbuf_pool_%u", socket_id);
1253        mp = rte_mempool_create_empty(pool_name, nb_mbuf,
1254                                      (mbuf_seg_size + sizeof(struct rte_mbuf)),
1255                                      MEMPOOL_CACHE_SIZE,
1256                                      sizeof(struct rte_pktmbuf_pool_private),
1257                                      socket_id, 0);
1258        if (mp == NULL)
1259                return NULL;
1260
1261        if (rte_mempool_set_ops_byname(mp, rte_mbuf_best_mempool_ops(), NULL)) {
1262                printf("error setting mempool handler\n");
1263                goto fail;
1264        }
1265
1266        memset(&mbp_priv, 0, sizeof(mbp_priv));
1267        mbp_priv.mbuf_data_room_size = mbuf_seg_size;
1268        mbp_priv.mbuf_priv_size = 0;
1269        rte_pktmbuf_pool_init(mp, &mbp_priv);
1270
1271        ntb_conf->mz_list = rte_zmalloc("ntb_memzone_list",
1272                                sizeof(struct rte_memzone *) *
1273                                ntb_info.mw_cnt, 0);
1274        if (ntb_conf->mz_list == NULL)
1275                goto fail;
1276
1277        /* Put ntb header on mw0. */
1278        if (ntb_info.mw_size[0] < ntb_info.ntb_hdr_size) {
1279                printf("mw0 (size: %" PRIu64 ") is not enough for ntb hdr"
1280                       " (size: %u)\n", ntb_info.mw_size[0],
1281                       ntb_info.ntb_hdr_size);
1282                goto fail;
1283        }
1284
1285        total_elt_sz = mp->header_size + mp->elt_size + mp->trailer_size;
1286        left_sz = total_elt_sz * nb_mbuf;
1287        for (mz_id = 0; mz_id < ntb_info.mw_cnt; mz_id++) {
1288                /* If populated mbuf is enough, no need to reserve extra mz. */
1289                if (!left_sz)
1290                        break;
1291                snprintf(mz_name, sizeof(mz_name), "ntb_mw_%d", mz_id);
1292                align = ntb_info.mw_size_align ? ntb_info.mw_size[mz_id] :
1293                        RTE_CACHE_LINE_SIZE;
1294                /* Reserve ntb header space on memzone 0. */
1295                max_mz_len = mz_id ? ntb_info.mw_size[mz_id] :
1296                             ntb_info.mw_size[mz_id] - ntb_info.ntb_hdr_size;
1297                mz_len = left_sz <= max_mz_len ? left_sz :
1298                        (max_mz_len / total_elt_sz * total_elt_sz);
1299                if (!mz_len)
1300                        continue;
1301                mz = rte_memzone_reserve_aligned(mz_name, mz_len, socket_id,
1302                                        RTE_MEMZONE_IOVA_CONTIG, align);
1303                if (mz == NULL) {
1304                        printf("Cannot allocate %" PRIu64 " aligned memzone"
1305                                " %u\n", align, mz_id);
1306                        goto fail;
1307                }
1308                left_sz -= mz_len;
1309
1310                /* Reserve ntb header space on memzone 0. */
1311                if (mz_id)
1312                        ret = rte_mempool_populate_iova(mp, mz->addr, mz->iova,
1313                                        mz->len, ntb_mempool_mz_free,
1314                                        (void *)(uintptr_t)mz);
1315                else
1316                        ret = rte_mempool_populate_iova(mp,
1317                                        (void *)((size_t)mz->addr +
1318                                        ntb_info.ntb_hdr_size),
1319                                        mz->iova + ntb_info.ntb_hdr_size,
1320                                        mz->len - ntb_info.ntb_hdr_size,
1321                                        ntb_mempool_mz_free,
1322                                        (void *)(uintptr_t)mz);
1323                if (ret <= 0) {
1324                        rte_memzone_free(mz);
1325                        rte_mempool_free(mp);
1326                        return NULL;
1327                }
1328
1329                ntb_conf->mz_list[mz_id] = mz;
1330        }
1331        if (left_sz) {
1332                printf("mw space is not enough for mempool.\n");
1333                goto fail;
1334        }
1335
1336        ntb_conf->mz_num = mz_id;
1337        rte_mempool_obj_iter(mp, rte_pktmbuf_init, NULL);
1338
1339        return mp;
1340fail:
1341        rte_mempool_free(mp);
1342        return NULL;
1343}
1344
1345int
1346main(int argc, char **argv)
1347{
1348        struct rte_eth_conf eth_pconf = eth_port_conf;
1349        struct rte_rawdev_info ntb_rawdev_conf;
1350        struct rte_rawdev_info ntb_rawdev_info;
1351        struct rte_eth_dev_info ethdev_info;
1352        struct rte_eth_rxconf eth_rx_conf;
1353        struct rte_eth_txconf eth_tx_conf;
1354        struct ntb_queue_conf ntb_q_conf;
1355        struct ntb_dev_config ntb_conf;
1356        struct ntb_dev_info ntb_info;
1357        uint64_t ntb_link_status;
1358        uint32_t nb_mbuf;
1359        int ret, i;
1360
1361        signal(SIGINT, signal_handler);
1362        signal(SIGTERM, signal_handler);
1363
1364        ret = rte_eal_init(argc, argv);
1365        if (ret < 0)
1366                rte_exit(EXIT_FAILURE, "Error with EAL initialization.\n");
1367
1368        if (rte_lcore_count() < 2)
1369                rte_exit(EXIT_FAILURE, "Need at least 2 cores\n");
1370
1371        /* Find 1st ntb rawdev. */
1372        for (i = 0; i < RTE_RAWDEV_MAX_DEVS; i++)
1373                if (rte_rawdevs[i].driver_name &&
1374                    (strncmp(rte_rawdevs[i].driver_name, "raw_ntb",
1375                    NTB_DRV_NAME_LEN) == 0) && (rte_rawdevs[i].attached == 1))
1376                        break;
1377
1378        if (i == RTE_RAWDEV_MAX_DEVS)
1379                rte_exit(EXIT_FAILURE, "Cannot find any ntb device.\n");
1380
1381        dev_id = i;
1382
1383        argc -= ret;
1384        argv += ret;
1385
1386        ntb_parse_args(argc, argv);
1387
1388        rte_rawdev_set_attr(dev_id, NTB_QUEUE_SZ_NAME, nb_desc);
1389        printf("Set queue size as %u.\n", nb_desc);
1390        rte_rawdev_set_attr(dev_id, NTB_QUEUE_NUM_NAME, num_queues);
1391        printf("Set queue number as %u.\n", num_queues);
1392        ntb_rawdev_info.dev_private = (rte_rawdev_obj_t)(&ntb_info);
1393        rte_rawdev_info_get(dev_id, &ntb_rawdev_info, sizeof(ntb_info));
1394
1395        nb_mbuf = nb_desc * num_queues * 2 * 2 + rte_lcore_count() *
1396                  MEMPOOL_CACHE_SIZE;
1397        mbuf_pool = ntb_mbuf_pool_create(ntb_buf_size, nb_mbuf, ntb_info,
1398                                         &ntb_conf, rte_socket_id());
1399        if (mbuf_pool == NULL)
1400                rte_exit(EXIT_FAILURE, "Cannot create mbuf pool.\n");
1401
1402        ntb_conf.num_queues = num_queues;
1403        ntb_conf.queue_size = nb_desc;
1404        ntb_rawdev_conf.dev_private = (rte_rawdev_obj_t)(&ntb_conf);
1405        ret = rte_rawdev_configure(dev_id, &ntb_rawdev_conf, sizeof(ntb_conf));
1406        if (ret)
1407                rte_exit(EXIT_FAILURE, "Can't config ntb dev: err=%d, "
1408                        "port=%u\n", ret, dev_id);
1409
1410        ntb_q_conf.tx_free_thresh = tx_free_thresh;
1411        ntb_q_conf.nb_desc = nb_desc;
1412        ntb_q_conf.rx_mp = mbuf_pool;
1413        for (i = 0; i < num_queues; i++) {
1414                /* Setup rawdev queue */
1415                ret = rte_rawdev_queue_setup(dev_id, i, &ntb_q_conf,
1416                                sizeof(ntb_q_conf));
1417                if (ret < 0)
1418                        rte_exit(EXIT_FAILURE,
1419                                "Failed to setup ntb queue %u.\n", i);
1420        }
1421
1422        /* Waiting for peer dev up at most 100s.*/
1423        printf("Checking ntb link status...\n");
1424        for (i = 0; i < 1000; i++) {
1425                rte_rawdev_get_attr(dev_id, NTB_LINK_STATUS_NAME,
1426                                    &ntb_link_status);
1427                if (ntb_link_status) {
1428                        printf("Peer dev ready, ntb link up.\n");
1429                        break;
1430                }
1431                rte_delay_ms(100);
1432        }
1433        rte_rawdev_get_attr(dev_id, NTB_LINK_STATUS_NAME, &ntb_link_status);
1434        if (ntb_link_status == 0)
1435                printf("Expire 100s. Link is not up. Please restart app.\n");
1436
1437        ret = rte_rawdev_start(dev_id);
1438        if (ret < 0)
1439                rte_exit(EXIT_FAILURE, "rte_rawdev_start: err=%d, port=%u\n",
1440                        ret, dev_id);
1441
1442        /* Find 1st ethdev */
1443        eth_port_id = rte_eth_find_next(0);
1444
1445        if (eth_port_id < RTE_MAX_ETHPORTS) {
1446                rte_eth_dev_info_get(eth_port_id, &ethdev_info);
1447                eth_pconf.rx_adv_conf.rss_conf.rss_hf &=
1448                                ethdev_info.flow_type_rss_offloads;
1449                ret = rte_eth_dev_configure(eth_port_id, num_queues,
1450                                            num_queues, &eth_pconf);
1451                if (ret)
1452                        rte_exit(EXIT_FAILURE, "Can't config ethdev: err=%d, "
1453                                "port=%u\n", ret, eth_port_id);
1454                eth_rx_conf = ethdev_info.default_rxconf;
1455                eth_rx_conf.offloads = eth_pconf.rxmode.offloads;
1456                eth_tx_conf = ethdev_info.default_txconf;
1457                eth_tx_conf.offloads = eth_pconf.txmode.offloads;
1458
1459                /* Setup ethdev queue if ethdev exists */
1460                for (i = 0; i < num_queues; i++) {
1461                        ret = rte_eth_rx_queue_setup(eth_port_id, i, nb_desc,
1462                                        rte_eth_dev_socket_id(eth_port_id),
1463                                        &eth_rx_conf, mbuf_pool);
1464                        if (ret < 0)
1465                                rte_exit(EXIT_FAILURE,
1466                                        "Failed to setup eth rxq %u.\n", i);
1467                        ret = rte_eth_tx_queue_setup(eth_port_id, i, nb_desc,
1468                                        rte_eth_dev_socket_id(eth_port_id),
1469                                        &eth_tx_conf);
1470                        if (ret < 0)
1471                                rte_exit(EXIT_FAILURE,
1472                                        "Failed to setup eth txq %u.\n", i);
1473                }
1474
1475                ret = rte_eth_dev_start(eth_port_id);
1476                if (ret < 0)
1477                        rte_exit(EXIT_FAILURE, "rte_eth_dev_start: err=%d, "
1478                                "port=%u\n", ret, eth_port_id);
1479        }
1480
1481        /* initialize port stats */
1482        memset(&ntb_port_stats, 0, sizeof(ntb_port_stats));
1483
1484        /* Set default fwd mode if user doesn't set it. */
1485        if (fwd_mode == MAX_FWD_MODE && eth_port_id < RTE_MAX_ETHPORTS) {
1486                printf("Set default fwd mode as iofwd.\n");
1487                fwd_mode = IOFWD;
1488        }
1489        if (fwd_mode == MAX_FWD_MODE) {
1490                printf("Set default fwd mode as file-trans.\n");
1491                fwd_mode = FILE_TRANS;
1492        }
1493
1494        if (interactive) {
1495                sleep(1);
1496                prompt();
1497        } else {
1498                start_pkt_fwd();
1499        }
1500
1501        /* clean up the EAL */
1502        rte_eal_cleanup();
1503
1504        return 0;
1505}
1506