dpdk/examples/link_status_interrupt/main.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright(c) 2010-2016 Intel Corporation
   3 */
   4
   5#include <stdio.h>
   6#include <stdlib.h>
   7#include <string.h>
   8#include <stdint.h>
   9#include <inttypes.h>
  10#include <sys/types.h>
  11#include <sys/queue.h>
  12#include <setjmp.h>
  13#include <stdarg.h>
  14#include <ctype.h>
  15#include <errno.h>
  16#include <getopt.h>
  17
  18#include <rte_common.h>
  19#include <rte_log.h>
  20#include <rte_malloc.h>
  21#include <rte_memory.h>
  22#include <rte_memcpy.h>
  23#include <rte_eal.h>
  24#include <rte_launch.h>
  25#include <rte_cycles.h>
  26#include <rte_prefetch.h>
  27#include <rte_lcore.h>
  28#include <rte_per_lcore.h>
  29#include <rte_branch_prediction.h>
  30#include <rte_interrupts.h>
  31#include <rte_random.h>
  32#include <rte_debug.h>
  33#include <rte_ether.h>
  34#include <rte_ethdev.h>
  35#include <rte_mempool.h>
  36#include <rte_mbuf.h>
  37
  38#define RTE_LOGTYPE_LSI RTE_LOGTYPE_USER1
  39
  40#define NB_MBUF   8192
  41
  42#define MAX_PKT_BURST 32
  43#define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
  44
  45/*
  46 * Configurable number of RX/TX ring descriptors
  47 */
  48#define RTE_TEST_RX_DESC_DEFAULT 1024
  49#define RTE_TEST_TX_DESC_DEFAULT 1024
  50static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
  51static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
  52
  53/* ethernet addresses of ports */
  54static struct rte_ether_addr lsi_ports_eth_addr[RTE_MAX_ETHPORTS];
  55
  56/* mask of enabled ports */
  57static uint32_t lsi_enabled_port_mask = 0;
  58
  59static unsigned int lsi_rx_queue_per_lcore = 1;
  60
  61/* destination port for L2 forwarding */
  62static unsigned lsi_dst_ports[RTE_MAX_ETHPORTS] = {0};
  63
  64#define MAX_PKT_BURST 32
  65
  66#define MAX_RX_QUEUE_PER_LCORE 16
  67#define MAX_TX_QUEUE_PER_PORT 16
  68/* List of queues must be polled for a give lcore. 8< */
  69struct lcore_queue_conf {
  70        unsigned n_rx_port;
  71        unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE];
  72        unsigned tx_queue_id;
  73} __rte_cache_aligned;
  74struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];
  75/* >8 End of list of queues to be polled. */
  76
  77struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS];
  78
  79/* Global configuration stored in a static structure. 8< */
  80static struct rte_eth_conf port_conf = {
  81        .rxmode = {
  82                .split_hdr_size = 0,
  83        },
  84        .txmode = {
  85                .mq_mode = RTE_ETH_MQ_TX_NONE,
  86        },
  87        .intr_conf = {
  88                .lsc = 1, /**< lsc interrupt feature enabled */
  89        },
  90};
  91/* >8 End of global configuration stored in a static structure. */
  92
  93struct rte_mempool * lsi_pktmbuf_pool = NULL;
  94
  95/* Per-port statistics struct */
  96struct lsi_port_statistics {
  97        uint64_t tx;
  98        uint64_t rx;
  99        uint64_t dropped;
 100} __rte_cache_aligned;
 101struct lsi_port_statistics port_statistics[RTE_MAX_ETHPORTS];
 102
 103/* A tsc-based timer responsible for triggering statistics printout */
 104#define TIMER_MILLISECOND 2000000ULL /* around 1ms at 2 Ghz */
 105#define MAX_TIMER_PERIOD 86400 /* 1 day max */
 106static int64_t timer_period = 10 * TIMER_MILLISECOND * 1000; /* default period is 10 seconds */
 107
 108/* Print out statistics on packets dropped */
 109static void
 110print_stats(void)
 111{
 112        struct rte_eth_link link;
 113        uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
 114        uint16_t portid;
 115
 116        total_packets_dropped = 0;
 117        total_packets_tx = 0;
 118        total_packets_rx = 0;
 119
 120        const char clr[] = { 27, '[', '2', 'J', '\0' };
 121        const char topLeft[] = { 27, '[', '1', ';', '1', 'H','\0' };
 122        int link_get_err;
 123
 124                /* Clear screen and move to top left */
 125        printf("%s%s", clr, topLeft);
 126
 127        printf("\nPort statistics ====================================");
 128
 129        for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
 130                /* skip ports that are not enabled */
 131                if ((lsi_enabled_port_mask & (1 << portid)) == 0)
 132                        continue;
 133
 134                memset(&link, 0, sizeof(link));
 135                link_get_err = rte_eth_link_get_nowait(portid, &link);
 136                printf("\nStatistics for port %u ------------------------------"
 137                           "\nLink status: %25s"
 138                           "\nLink speed: %26s"
 139                           "\nLink duplex: %25s"
 140                           "\nPackets sent: %24"PRIu64
 141                           "\nPackets received: %20"PRIu64
 142                           "\nPackets dropped: %21"PRIu64,
 143                           portid,
 144                           link_get_err < 0 ? "Link get failed" :
 145                           (link.link_status ? "Link up" : "Link down"),
 146                           link_get_err < 0 ? "0" :
 147                           rte_eth_link_speed_to_str(link.link_speed),
 148                           link_get_err < 0 ? "Link get failed" :
 149                           (link.link_duplex == RTE_ETH_LINK_FULL_DUPLEX ?
 150                                        "full-duplex" : "half-duplex"),
 151                           port_statistics[portid].tx,
 152                           port_statistics[portid].rx,
 153                           port_statistics[portid].dropped);
 154
 155                total_packets_dropped += port_statistics[portid].dropped;
 156                total_packets_tx += port_statistics[portid].tx;
 157                total_packets_rx += port_statistics[portid].rx;
 158        }
 159        printf("\nAggregate statistics ==============================="
 160                   "\nTotal packets sent: %18"PRIu64
 161                   "\nTotal packets received: %14"PRIu64
 162                   "\nTotal packets dropped: %15"PRIu64,
 163                   total_packets_tx,
 164                   total_packets_rx,
 165                   total_packets_dropped);
 166        printf("\n====================================================\n");
 167
 168        fflush(stdout);
 169}
 170
 171/* Replacing the source and destination MAC addresses. 8< */
 172static void
 173lsi_simple_forward(struct rte_mbuf *m, unsigned portid)
 174{
 175        struct rte_ether_hdr *eth;
 176        void *tmp;
 177        unsigned dst_port = lsi_dst_ports[portid];
 178        int sent;
 179        struct rte_eth_dev_tx_buffer *buffer;
 180
 181        eth = rte_pktmbuf_mtod(m, struct rte_ether_hdr *);
 182
 183        /* 02:00:00:00:00:xx */
 184        tmp = &eth->dst_addr.addr_bytes[0];
 185        *((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40);
 186
 187        /* src addr */
 188        rte_ether_addr_copy(&lsi_ports_eth_addr[dst_port], &eth->src_addr);
 189
 190        buffer = tx_buffer[dst_port];
 191        sent = rte_eth_tx_buffer(dst_port, 0, buffer, m);
 192        if (sent)
 193                port_statistics[dst_port].tx += sent;
 194}
 195/* >8 End of replacing the source and destination MAC addresses. */
 196
 197/* main processing loop */
 198static void
 199lsi_main_loop(void)
 200{
 201        struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
 202        struct rte_mbuf *m;
 203        unsigned lcore_id;
 204        unsigned sent;
 205        uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc;
 206        unsigned i, j, portid, nb_rx;
 207        struct lcore_queue_conf *qconf;
 208        const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S *
 209                        BURST_TX_DRAIN_US;
 210        struct rte_eth_dev_tx_buffer *buffer;
 211
 212        prev_tsc = 0;
 213        timer_tsc = 0;
 214
 215        lcore_id = rte_lcore_id();
 216        qconf = &lcore_queue_conf[lcore_id];
 217
 218        if (qconf->n_rx_port == 0) {
 219                RTE_LOG(INFO, LSI, "lcore %u has nothing to do\n", lcore_id);
 220                return;
 221        }
 222
 223        RTE_LOG(INFO, LSI, "entering main loop on lcore %u\n", lcore_id);
 224
 225        for (i = 0; i < qconf->n_rx_port; i++) {
 226
 227                portid = qconf->rx_port_list[i];
 228                RTE_LOG(INFO, LSI, " -- lcoreid=%u portid=%u\n", lcore_id,
 229                        portid);
 230        }
 231
 232        while (1) {
 233
 234                /* Draining TX queue in its main loop. 8< */
 235                cur_tsc = rte_rdtsc();
 236
 237                /*
 238                 * TX burst queue drain
 239                 */
 240                diff_tsc = cur_tsc - prev_tsc;
 241                if (unlikely(diff_tsc > drain_tsc)) {
 242
 243                        for (i = 0; i < qconf->n_rx_port; i++) {
 244
 245                                portid = lsi_dst_ports[qconf->rx_port_list[i]];
 246                                buffer = tx_buffer[portid];
 247
 248                                sent = rte_eth_tx_buffer_flush(portid, 0, buffer);
 249                                if (sent)
 250                                        port_statistics[portid].tx += sent;
 251
 252                        }
 253
 254                        /* if timer is enabled */
 255                        if (timer_period > 0) {
 256
 257                                /* advance the timer */
 258                                timer_tsc += diff_tsc;
 259
 260                                /* if timer has reached its timeout */
 261                                if (unlikely(timer_tsc >= (uint64_t) timer_period)) {
 262
 263                                        /* do this only on main core */
 264                                        if (lcore_id == rte_get_main_lcore()) {
 265                                                print_stats();
 266                                                /* reset the timer */
 267                                                timer_tsc = 0;
 268                                        }
 269                                }
 270                        }
 271
 272                        prev_tsc = cur_tsc;
 273                }
 274                /* >8 End of draining TX queue in its main loop. */
 275
 276                /* Read packet from RX queues. 8< */
 277                for (i = 0; i < qconf->n_rx_port; i++) {
 278
 279                        portid = qconf->rx_port_list[i];
 280                        nb_rx = rte_eth_rx_burst((uint8_t) portid, 0,
 281                                                 pkts_burst, MAX_PKT_BURST);
 282
 283                        port_statistics[portid].rx += nb_rx;
 284
 285                        for (j = 0; j < nb_rx; j++) {
 286                                m = pkts_burst[j];
 287                                rte_prefetch0(rte_pktmbuf_mtod(m, void *));
 288                                lsi_simple_forward(m, portid);
 289                        }
 290                }
 291                /* >8 End of reading packet from RX queues. */
 292        }
 293}
 294
 295static int
 296lsi_launch_one_lcore(__rte_unused void *dummy)
 297{
 298        lsi_main_loop();
 299        return 0;
 300}
 301
 302/* display usage */
 303static void
 304lsi_usage(const char *prgname)
 305{
 306        printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n"
 307                "  -p PORTMASK: hexadecimal bitmask of ports to configure\n"
 308                "  -q NQ: number of queue (=ports) per lcore (default is 1)\n"
 309                "  -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default, 86400 maximum)\n",
 310                        prgname);
 311}
 312
 313static int
 314lsi_parse_portmask(const char *portmask)
 315{
 316        char *end = NULL;
 317        unsigned long pm;
 318
 319        /* parse hexadecimal string */
 320        pm = strtoul(portmask, &end, 16);
 321        if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
 322                return 0;
 323
 324        return pm;
 325}
 326
 327static unsigned int
 328lsi_parse_nqueue(const char *q_arg)
 329{
 330        char *end = NULL;
 331        unsigned long n;
 332
 333        /* parse hexadecimal string */
 334        n = strtoul(q_arg, &end, 10);
 335        if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
 336                return 0;
 337        if (n == 0)
 338                return 0;
 339        if (n >= MAX_RX_QUEUE_PER_LCORE)
 340                return 0;
 341
 342        return n;
 343}
 344
 345static int
 346lsi_parse_timer_period(const char *q_arg)
 347{
 348        char *end = NULL;
 349        int n;
 350
 351        /* parse number string */
 352        n = strtol(q_arg, &end, 10);
 353        if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
 354                return -1;
 355        if (n >= MAX_TIMER_PERIOD)
 356                return -1;
 357
 358        return n;
 359}
 360
 361/* Parse the argument given in the command line of the application */
 362static int
 363lsi_parse_args(int argc, char **argv)
 364{
 365        int opt, ret;
 366        char **argvopt;
 367        int option_index;
 368        char *prgname = argv[0];
 369        static struct option lgopts[] = {
 370                {NULL, 0, 0, 0}
 371        };
 372
 373        argvopt = argv;
 374
 375        while ((opt = getopt_long(argc, argvopt, "p:q:T:",
 376                                  lgopts, &option_index)) != EOF) {
 377
 378                switch (opt) {
 379                /* portmask */
 380                case 'p':
 381                        lsi_enabled_port_mask = lsi_parse_portmask(optarg);
 382                        if (lsi_enabled_port_mask == 0) {
 383                                printf("invalid portmask\n");
 384                                lsi_usage(prgname);
 385                                return -1;
 386                        }
 387                        break;
 388
 389                /* nqueue */
 390                case 'q':
 391                        lsi_rx_queue_per_lcore = lsi_parse_nqueue(optarg);
 392                        if (lsi_rx_queue_per_lcore == 0) {
 393                                printf("invalid queue number\n");
 394                                lsi_usage(prgname);
 395                                return -1;
 396                        }
 397                        break;
 398
 399                /* timer period */
 400                case 'T':
 401                        timer_period = lsi_parse_timer_period(optarg) * 1000 * TIMER_MILLISECOND;
 402                        if (timer_period < 0) {
 403                                printf("invalid timer period\n");
 404                                lsi_usage(prgname);
 405                                return -1;
 406                        }
 407                        break;
 408
 409                /* long options */
 410                case 0:
 411                        lsi_usage(prgname);
 412                        return -1;
 413
 414                default:
 415                        lsi_usage(prgname);
 416                        return -1;
 417                }
 418        }
 419
 420        if (optind >= 0)
 421                argv[optind-1] = prgname;
 422
 423        ret = optind-1;
 424        optind = 1; /* reset getopt lib */
 425        return ret;
 426}
 427
 428/**
 429 * It will be called as the callback for specified port after a LSI interrupt
 430 * has been fully handled. This callback needs to be implemented carefully as
 431 * it will be called in the interrupt host thread which is different from the
 432 * application main thread.
 433 *
 434 * @param port_id
 435 *  Port id.
 436 * @param type
 437 *  event type.
 438 * @param param
 439 *  Pointer to(address of) the parameters.
 440 *
 441 * @return
 442 *  int.
 443 */
 444
 445/* lsi_event_callback 8< */
 446static int
 447lsi_event_callback(uint16_t port_id, enum rte_eth_event_type type, void *param,
 448                    void *ret_param)
 449{
 450        struct rte_eth_link link;
 451        int ret;
 452        char link_status_text[RTE_ETH_LINK_MAX_STR_LEN];
 453
 454        RTE_SET_USED(param);
 455        RTE_SET_USED(ret_param);
 456
 457        printf("\n\nIn registered callback...\n");
 458        printf("Event type: %s\n", type == RTE_ETH_EVENT_INTR_LSC ? "LSC interrupt" : "unknown event");
 459        ret = rte_eth_link_get_nowait(port_id, &link);
 460        if (ret < 0) {
 461                printf("Failed link get on port %d: %s\n",
 462                       port_id, rte_strerror(-ret));
 463                return ret;
 464        }
 465        rte_eth_link_to_str(link_status_text, sizeof(link_status_text), &link);
 466        printf("Port %d %s\n\n", port_id, link_status_text);
 467
 468        return 0;
 469}
 470/* >8 End of registering one or more callbacks. */
 471
 472/* Check the link status of all ports in up to 9s, and print them finally */
 473static void
 474check_all_ports_link_status(uint16_t port_num, uint32_t port_mask)
 475{
 476#define CHECK_INTERVAL 100 /* 100ms */
 477#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
 478        uint8_t count, all_ports_up, print_flag = 0;
 479        uint16_t portid;
 480        struct rte_eth_link link;
 481        int ret;
 482        char link_status_text[RTE_ETH_LINK_MAX_STR_LEN];
 483
 484        printf("\nChecking link status");
 485        fflush(stdout);
 486        for (count = 0; count <= MAX_CHECK_TIME; count++) {
 487                all_ports_up = 1;
 488                for (portid = 0; portid < port_num; portid++) {
 489                        if ((port_mask & (1 << portid)) == 0)
 490                                continue;
 491                        memset(&link, 0, sizeof(link));
 492                        ret = rte_eth_link_get_nowait(portid, &link);
 493                        if (ret < 0) {
 494                                all_ports_up = 0;
 495                                if (print_flag == 1)
 496                                        printf("Port %u link get failed: %s\n",
 497                                                portid, rte_strerror(-ret));
 498                                continue;
 499                        }
 500                        /* print link status if flag set */
 501                        if (print_flag == 1) {
 502                                rte_eth_link_to_str(link_status_text,
 503                                        sizeof(link_status_text), &link);
 504                                printf("Port %d %s", portid,
 505                                       link_status_text);
 506                                continue;
 507                        }
 508                        /* clear all_ports_up flag if any link down */
 509                        if (link.link_status == RTE_ETH_LINK_DOWN) {
 510                                all_ports_up = 0;
 511                                break;
 512                        }
 513                }
 514                /* after finally printing all link status, get out */
 515                if (print_flag == 1)
 516                        break;
 517
 518                if (all_ports_up == 0) {
 519                        printf(".");
 520                        fflush(stdout);
 521                        rte_delay_ms(CHECK_INTERVAL);
 522                }
 523
 524                /* set the print_flag if all ports up or timeout */
 525                if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
 526                        print_flag = 1;
 527                        printf("done\n");
 528                }
 529        }
 530}
 531
 532int
 533main(int argc, char **argv)
 534{
 535        struct lcore_queue_conf *qconf;
 536        int ret;
 537        uint16_t nb_ports;
 538        uint16_t portid, portid_last = 0;
 539        unsigned lcore_id, rx_lcore_id;
 540        unsigned nb_ports_in_mask = 0;
 541
 542        /* init EAL */
 543        ret = rte_eal_init(argc, argv);
 544        if (ret < 0)
 545                rte_exit(EXIT_FAILURE, "rte_eal_init failed");
 546        argc -= ret;
 547        argv += ret;
 548
 549        /* parse application arguments (after the EAL ones) */
 550        ret = lsi_parse_args(argc, argv);
 551        if (ret < 0)
 552                rte_exit(EXIT_FAILURE, "Invalid arguments");
 553
 554        /* create the mbuf pool */
 555        lsi_pktmbuf_pool =
 556                rte_pktmbuf_pool_create("mbuf_pool", NB_MBUF, 32, 0,
 557                        RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
 558        if (lsi_pktmbuf_pool == NULL)
 559                rte_panic("Cannot init mbuf pool\n");
 560
 561        nb_ports = rte_eth_dev_count_avail();
 562        if (nb_ports == 0)
 563                rte_panic("No Ethernet port - bye\n");
 564
 565        /* Each logical core is assigned a dedicated TX queue on each port. 8< */
 566        for (portid = 0; portid < nb_ports; portid++) {
 567                /* skip ports that are not enabled */
 568                if ((lsi_enabled_port_mask & (1 << portid)) == 0)
 569                        continue;
 570
 571                /* save the destination port id */
 572                if (nb_ports_in_mask % 2) {
 573                        lsi_dst_ports[portid] = portid_last;
 574                        lsi_dst_ports[portid_last] = portid;
 575                }
 576                else
 577                        portid_last = portid;
 578
 579                nb_ports_in_mask++;
 580        }
 581        /* >8 End of assigning logical core. */
 582        if (nb_ports_in_mask < 2 || nb_ports_in_mask % 2)
 583                rte_exit(EXIT_FAILURE, "Current enabled port number is %u, "
 584                                "but it should be even and at least 2\n",
 585                                nb_ports_in_mask);
 586
 587        rx_lcore_id = 0;
 588        qconf = &lcore_queue_conf[rx_lcore_id];
 589
 590        /* Initialize the port/queue configuration of each logical core */
 591        for (portid = 0; portid < nb_ports; portid++) {
 592                /* skip ports that are not enabled */
 593                if ((lsi_enabled_port_mask & (1 << portid)) == 0)
 594                        continue;
 595
 596                /* get the lcore_id for this port */
 597                while (rte_lcore_is_enabled(rx_lcore_id) == 0 ||
 598                       lcore_queue_conf[rx_lcore_id].n_rx_port ==
 599                       lsi_rx_queue_per_lcore) {
 600
 601                        rx_lcore_id++;
 602                        if (rx_lcore_id >= RTE_MAX_LCORE)
 603                                rte_exit(EXIT_FAILURE, "Not enough cores\n");
 604                }
 605                if (qconf != &lcore_queue_conf[rx_lcore_id])
 606                        /* Assigned a new logical core in the loop above. */
 607                        qconf = &lcore_queue_conf[rx_lcore_id];
 608
 609                qconf->rx_port_list[qconf->n_rx_port] = portid;
 610                qconf->n_rx_port++;
 611                printf("Lcore %u: RX port %u\n",rx_lcore_id, (unsigned) portid);
 612        }
 613
 614        /* Initialise each port */
 615        for (portid = 0; portid < nb_ports; portid++) {
 616                struct rte_eth_rxconf rxq_conf;
 617                struct rte_eth_txconf txq_conf;
 618                struct rte_eth_conf local_port_conf = port_conf;
 619                struct rte_eth_dev_info dev_info;
 620
 621                /* skip ports that are not enabled */
 622                if ((lsi_enabled_port_mask & (1 << portid)) == 0) {
 623                        printf("Skipping disabled port %u\n", (unsigned) portid);
 624                        continue;
 625                }
 626                /* init port */
 627                printf("Initializing port %u... ", (unsigned) portid);
 628                fflush(stdout);
 629
 630                ret = rte_eth_dev_info_get(portid, &dev_info);
 631                if (ret != 0)
 632                        rte_exit(EXIT_FAILURE,
 633                                "Error during getting device (port %u) info: %s\n",
 634                                portid, strerror(-ret));
 635
 636                if (dev_info.tx_offload_capa & RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE)
 637                        local_port_conf.txmode.offloads |=
 638                                RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE;
 639                /* Configure RX and TX queues. 8< */
 640                ret = rte_eth_dev_configure(portid, 1, 1, &local_port_conf);
 641                if (ret < 0)
 642                        rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%u\n",
 643                                  ret, (unsigned) portid);
 644                /* >8 End of configure RX and TX queues. */
 645
 646                ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd,
 647                                                       &nb_txd);
 648                if (ret < 0)
 649                        rte_exit(EXIT_FAILURE,
 650                                 "rte_eth_dev_adjust_nb_rx_tx_desc: err=%d, port=%u\n",
 651                                 ret, (unsigned) portid);
 652
 653                /* register lsi interrupt callback, need to be after
 654                 * rte_eth_dev_configure(). if (intr_conf.lsc == 0), no
 655                 * lsc interrupt will be present, and below callback to
 656                 * be registered will never be called.
 657                 */
 658
 659                /* RTE callback register. 8< */
 660                rte_eth_dev_callback_register(portid,
 661                        RTE_ETH_EVENT_INTR_LSC, lsi_event_callback, NULL);
 662                /* >8 End of registering lsi interrupt callback. */
 663
 664                ret = rte_eth_macaddr_get(portid,
 665                                    &lsi_ports_eth_addr[portid]);
 666                if (ret < 0)
 667                        rte_exit(EXIT_FAILURE,
 668                                 "rte_eth_macaddr_get: err=%d, port=%u\n",
 669                                 ret, (unsigned int)portid);
 670
 671                /* init one RX queue */
 672                fflush(stdout);
 673                rxq_conf = dev_info.default_rxconf;
 674                rxq_conf.offloads = local_port_conf.rxmode.offloads;
 675                /* RX queue initialization. 8< */
 676                ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd,
 677                                             rte_eth_dev_socket_id(portid),
 678                                             &rxq_conf,
 679                                             lsi_pktmbuf_pool);
 680                if (ret < 0)
 681                        rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup: err=%d, port=%u\n",
 682                                  ret, (unsigned) portid);
 683                /* >8 End of RX queue initialization. */
 684
 685                /* init one TX queue logical core on each port. 8< */
 686                fflush(stdout);
 687                txq_conf = dev_info.default_txconf;
 688                txq_conf.offloads = local_port_conf.txmode.offloads;
 689                ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
 690                                rte_eth_dev_socket_id(portid),
 691                                &txq_conf);
 692                if (ret < 0)
 693                        rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup: err=%d,port=%u\n",
 694                                  ret, (unsigned) portid);
 695                /* >8 End of init one TX queue. */
 696
 697                /* Initialize TX buffers */
 698                tx_buffer[portid] = rte_zmalloc_socket("tx_buffer",
 699                                RTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0,
 700                                rte_eth_dev_socket_id(portid));
 701                if (tx_buffer[portid] == NULL)
 702                        rte_exit(EXIT_FAILURE, "Cannot allocate buffer for tx on port %u\n",
 703                                        (unsigned) portid);
 704
 705                rte_eth_tx_buffer_init(tx_buffer[portid], MAX_PKT_BURST);
 706
 707                ret = rte_eth_tx_buffer_set_err_callback(tx_buffer[portid],
 708                                rte_eth_tx_buffer_count_callback,
 709                                &port_statistics[portid].dropped);
 710                if (ret < 0)
 711                        rte_exit(EXIT_FAILURE, "Cannot set error callback for "
 712                                        "tx buffer on port %u\n", (unsigned) portid);
 713
 714                /* Start device */
 715                ret = rte_eth_dev_start(portid);
 716                if (ret < 0)
 717                        rte_exit(EXIT_FAILURE, "rte_eth_dev_start: err=%d, port=%u\n",
 718                                  ret, (unsigned) portid);
 719                printf("done:\n");
 720
 721                ret = rte_eth_promiscuous_enable(portid);
 722                if (ret != 0)
 723                        rte_exit(EXIT_FAILURE,
 724                                "rte_eth_promiscuous_enable: err=%s, port=%u\n",
 725                                rte_strerror(-ret), portid);
 726
 727                printf("Port %u, MAC address: " RTE_ETHER_ADDR_PRT_FMT "\n\n",
 728                                (unsigned) portid,
 729                        RTE_ETHER_ADDR_BYTES(&lsi_ports_eth_addr[portid]));
 730
 731                /* initialize port stats */
 732                memset(&port_statistics, 0, sizeof(port_statistics));
 733        }
 734
 735        check_all_ports_link_status(nb_ports, lsi_enabled_port_mask);
 736
 737        /* launch per-lcore init on every lcore */
 738        rte_eal_mp_remote_launch(lsi_launch_one_lcore, NULL, CALL_MAIN);
 739        RTE_LCORE_FOREACH_WORKER(lcore_id) {
 740                if (rte_eal_wait_lcore(lcore_id) < 0)
 741                        return -1;
 742        }
 743
 744        /* clean up the EAL */
 745        rte_eal_cleanup();
 746
 747        return 0;
 748}
 749