1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (C) IGEL Co.,Ltd. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of IGEL Co.,Ltd. nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <rte_mbuf.h> 35 #include <rte_ethdev.h> 36 #include <rte_ethdev_vdev.h> 37 #include <rte_malloc.h> 38 #include <rte_memcpy.h> 39 #include <rte_vdev.h> 40 #include <rte_kvargs.h> 41 #include <rte_spinlock.h> 42 43 #define ETH_NULL_PACKET_SIZE_ARG "size" 44 #define ETH_NULL_PACKET_COPY_ARG "copy" 45 46 static unsigned default_packet_size = 64; 47 static unsigned default_packet_copy; 48 49 static const char *valid_arguments[] = { 50 ETH_NULL_PACKET_SIZE_ARG, 51 ETH_NULL_PACKET_COPY_ARG, 52 "driver", 53 NULL 54 }; 55 56 struct pmd_internals; 57 58 struct null_queue { 59 struct pmd_internals *internals; 60 61 struct rte_mempool *mb_pool; 62 struct rte_mbuf *dummy_packet; 63 64 rte_atomic64_t rx_pkts; 65 rte_atomic64_t tx_pkts; 66 rte_atomic64_t err_pkts; 67 }; 68 69 struct pmd_internals { 70 unsigned packet_size; 71 unsigned packet_copy; 72 uint8_t port_id; 73 74 struct null_queue rx_null_queues[RTE_MAX_QUEUES_PER_PORT]; 75 struct null_queue tx_null_queues[RTE_MAX_QUEUES_PER_PORT]; 76 77 /** Bit mask of RSS offloads, the bit offset also means flow type */ 78 uint64_t flow_type_rss_offloads; 79 80 rte_spinlock_t rss_lock; 81 82 uint16_t reta_size; 83 struct rte_eth_rss_reta_entry64 reta_conf[ETH_RSS_RETA_SIZE_128 / 84 RTE_RETA_GROUP_SIZE]; 85 86 uint8_t rss_key[40]; /**< 40-byte hash key. */ 87 }; 88 89 90 static struct ether_addr eth_addr = { .addr_bytes = {0} }; 91 static struct rte_eth_link pmd_link = { 92 .link_speed = ETH_SPEED_NUM_10G, 93 .link_duplex = ETH_LINK_FULL_DUPLEX, 94 .link_status = ETH_LINK_DOWN, 95 .link_autoneg = ETH_LINK_SPEED_AUTONEG, 96 }; 97 98 static uint16_t 99 eth_null_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs) 100 { 101 int i; 102 struct null_queue *h = q; 103 unsigned packet_size; 104 105 if ((q == NULL) || (bufs == NULL)) 106 return 0; 107 108 packet_size = h->internals->packet_size; 109 for (i = 0; i < nb_bufs; i++) { 110 bufs[i] = rte_pktmbuf_alloc(h->mb_pool); 111 if (!bufs[i]) 112 break; 113 bufs[i]->data_len = (uint16_t)packet_size; 114 bufs[i]->pkt_len = packet_size; 115 bufs[i]->port = h->internals->port_id; 116 } 117 118 rte_atomic64_add(&(h->rx_pkts), i); 119 120 return i; 121 } 122 123 static uint16_t 124 eth_null_copy_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs) 125 { 126 int i; 127 struct null_queue *h = q; 128 unsigned packet_size; 129 130 if ((q == NULL) || (bufs == NULL)) 131 return 0; 132 133 packet_size = h->internals->packet_size; 134 for (i = 0; i < nb_bufs; i++) { 135 bufs[i] = rte_pktmbuf_alloc(h->mb_pool); 136 if (!bufs[i]) 137 break; 138 rte_memcpy(rte_pktmbuf_mtod(bufs[i], void *), h->dummy_packet, 139 packet_size); 140 bufs[i]->data_len = (uint16_t)packet_size; 141 bufs[i]->pkt_len = packet_size; 142 bufs[i]->port = h->internals->port_id; 143 } 144 145 rte_atomic64_add(&(h->rx_pkts), i); 146 147 return i; 148 } 149 150 static uint16_t 151 eth_null_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs) 152 { 153 int i; 154 struct null_queue *h = q; 155 156 if ((q == NULL) || (bufs == NULL)) 157 return 0; 158 159 for (i = 0; i < nb_bufs; i++) 160 rte_pktmbuf_free(bufs[i]); 161 162 rte_atomic64_add(&(h->tx_pkts), i); 163 164 return i; 165 } 166 167 static uint16_t 168 eth_null_copy_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs) 169 { 170 int i; 171 struct null_queue *h = q; 172 unsigned packet_size; 173 174 if ((q == NULL) || (bufs == NULL)) 175 return 0; 176 177 packet_size = h->internals->packet_size; 178 for (i = 0; i < nb_bufs; i++) { 179 rte_memcpy(h->dummy_packet, rte_pktmbuf_mtod(bufs[i], void *), 180 packet_size); 181 rte_pktmbuf_free(bufs[i]); 182 } 183 184 rte_atomic64_add(&(h->tx_pkts), i); 185 186 return i; 187 } 188 189 static int 190 eth_dev_configure(struct rte_eth_dev *dev __rte_unused) 191 { 192 return 0; 193 } 194 195 static int 196 eth_dev_start(struct rte_eth_dev *dev) 197 { 198 if (dev == NULL) 199 return -EINVAL; 200 201 dev->data->dev_link.link_status = ETH_LINK_UP; 202 return 0; 203 } 204 205 static void 206 eth_dev_stop(struct rte_eth_dev *dev) 207 { 208 if (dev == NULL) 209 return; 210 211 dev->data->dev_link.link_status = ETH_LINK_DOWN; 212 } 213 214 static int 215 eth_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id, 216 uint16_t nb_rx_desc __rte_unused, 217 unsigned int socket_id __rte_unused, 218 const struct rte_eth_rxconf *rx_conf __rte_unused, 219 struct rte_mempool *mb_pool) 220 { 221 struct rte_mbuf *dummy_packet; 222 struct pmd_internals *internals; 223 unsigned packet_size; 224 225 if ((dev == NULL) || (mb_pool == NULL)) 226 return -EINVAL; 227 228 internals = dev->data->dev_private; 229 230 if (rx_queue_id >= dev->data->nb_rx_queues) 231 return -ENODEV; 232 233 packet_size = internals->packet_size; 234 235 internals->rx_null_queues[rx_queue_id].mb_pool = mb_pool; 236 dev->data->rx_queues[rx_queue_id] = 237 &internals->rx_null_queues[rx_queue_id]; 238 dummy_packet = rte_zmalloc_socket(NULL, 239 packet_size, 0, dev->data->numa_node); 240 if (dummy_packet == NULL) 241 return -ENOMEM; 242 243 internals->rx_null_queues[rx_queue_id].internals = internals; 244 internals->rx_null_queues[rx_queue_id].dummy_packet = dummy_packet; 245 246 return 0; 247 } 248 249 static int 250 eth_tx_queue_setup(struct rte_eth_dev *dev, uint16_t tx_queue_id, 251 uint16_t nb_tx_desc __rte_unused, 252 unsigned int socket_id __rte_unused, 253 const struct rte_eth_txconf *tx_conf __rte_unused) 254 { 255 struct rte_mbuf *dummy_packet; 256 struct pmd_internals *internals; 257 unsigned packet_size; 258 259 if (dev == NULL) 260 return -EINVAL; 261 262 internals = dev->data->dev_private; 263 264 if (tx_queue_id >= dev->data->nb_tx_queues) 265 return -ENODEV; 266 267 packet_size = internals->packet_size; 268 269 dev->data->tx_queues[tx_queue_id] = 270 &internals->tx_null_queues[tx_queue_id]; 271 dummy_packet = rte_zmalloc_socket(NULL, 272 packet_size, 0, dev->data->numa_node); 273 if (dummy_packet == NULL) 274 return -ENOMEM; 275 276 internals->tx_null_queues[tx_queue_id].internals = internals; 277 internals->tx_null_queues[tx_queue_id].dummy_packet = dummy_packet; 278 279 return 0; 280 } 281 282 283 static void 284 eth_dev_info(struct rte_eth_dev *dev, 285 struct rte_eth_dev_info *dev_info) 286 { 287 struct pmd_internals *internals; 288 289 if ((dev == NULL) || (dev_info == NULL)) 290 return; 291 292 internals = dev->data->dev_private; 293 dev_info->max_mac_addrs = 1; 294 dev_info->max_rx_pktlen = (uint32_t)-1; 295 dev_info->max_rx_queues = RTE_DIM(internals->rx_null_queues); 296 dev_info->max_tx_queues = RTE_DIM(internals->tx_null_queues); 297 dev_info->min_rx_bufsize = 0; 298 dev_info->reta_size = internals->reta_size; 299 dev_info->flow_type_rss_offloads = internals->flow_type_rss_offloads; 300 } 301 302 static void 303 eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *igb_stats) 304 { 305 unsigned i, num_stats; 306 unsigned long rx_total = 0, tx_total = 0, tx_err_total = 0; 307 const struct pmd_internals *internal; 308 309 if ((dev == NULL) || (igb_stats == NULL)) 310 return; 311 312 internal = dev->data->dev_private; 313 num_stats = RTE_MIN((unsigned)RTE_ETHDEV_QUEUE_STAT_CNTRS, 314 RTE_MIN(dev->data->nb_rx_queues, 315 RTE_DIM(internal->rx_null_queues))); 316 for (i = 0; i < num_stats; i++) { 317 igb_stats->q_ipackets[i] = 318 internal->rx_null_queues[i].rx_pkts.cnt; 319 rx_total += igb_stats->q_ipackets[i]; 320 } 321 322 num_stats = RTE_MIN((unsigned)RTE_ETHDEV_QUEUE_STAT_CNTRS, 323 RTE_MIN(dev->data->nb_tx_queues, 324 RTE_DIM(internal->tx_null_queues))); 325 for (i = 0; i < num_stats; i++) { 326 igb_stats->q_opackets[i] = 327 internal->tx_null_queues[i].tx_pkts.cnt; 328 igb_stats->q_errors[i] = 329 internal->tx_null_queues[i].err_pkts.cnt; 330 tx_total += igb_stats->q_opackets[i]; 331 tx_err_total += igb_stats->q_errors[i]; 332 } 333 334 igb_stats->ipackets = rx_total; 335 igb_stats->opackets = tx_total; 336 igb_stats->oerrors = tx_err_total; 337 } 338 339 static void 340 eth_stats_reset(struct rte_eth_dev *dev) 341 { 342 unsigned i; 343 struct pmd_internals *internal; 344 345 if (dev == NULL) 346 return; 347 348 internal = dev->data->dev_private; 349 for (i = 0; i < RTE_DIM(internal->rx_null_queues); i++) 350 internal->rx_null_queues[i].rx_pkts.cnt = 0; 351 for (i = 0; i < RTE_DIM(internal->tx_null_queues); i++) { 352 internal->tx_null_queues[i].tx_pkts.cnt = 0; 353 internal->tx_null_queues[i].err_pkts.cnt = 0; 354 } 355 } 356 357 static void 358 eth_queue_release(void *q) 359 { 360 struct null_queue *nq; 361 362 if (q == NULL) 363 return; 364 365 nq = q; 366 rte_free(nq->dummy_packet); 367 } 368 369 static int 370 eth_link_update(struct rte_eth_dev *dev __rte_unused, 371 int wait_to_complete __rte_unused) { return 0; } 372 373 static int 374 eth_rss_reta_update(struct rte_eth_dev *dev, 375 struct rte_eth_rss_reta_entry64 *reta_conf, uint16_t reta_size) 376 { 377 int i, j; 378 struct pmd_internals *internal = dev->data->dev_private; 379 380 if (reta_size != internal->reta_size) 381 return -EINVAL; 382 383 rte_spinlock_lock(&internal->rss_lock); 384 385 /* Copy RETA table */ 386 for (i = 0; i < (internal->reta_size / RTE_RETA_GROUP_SIZE); i++) { 387 internal->reta_conf[i].mask = reta_conf[i].mask; 388 for (j = 0; j < RTE_RETA_GROUP_SIZE; j++) 389 if ((reta_conf[i].mask >> j) & 0x01) 390 internal->reta_conf[i].reta[j] = reta_conf[i].reta[j]; 391 } 392 393 rte_spinlock_unlock(&internal->rss_lock); 394 395 return 0; 396 } 397 398 static int 399 eth_rss_reta_query(struct rte_eth_dev *dev, 400 struct rte_eth_rss_reta_entry64 *reta_conf, uint16_t reta_size) 401 { 402 int i, j; 403 struct pmd_internals *internal = dev->data->dev_private; 404 405 if (reta_size != internal->reta_size) 406 return -EINVAL; 407 408 rte_spinlock_lock(&internal->rss_lock); 409 410 /* Copy RETA table */ 411 for (i = 0; i < (internal->reta_size / RTE_RETA_GROUP_SIZE); i++) { 412 for (j = 0; j < RTE_RETA_GROUP_SIZE; j++) 413 if ((reta_conf[i].mask >> j) & 0x01) 414 reta_conf[i].reta[j] = internal->reta_conf[i].reta[j]; 415 } 416 417 rte_spinlock_unlock(&internal->rss_lock); 418 419 return 0; 420 } 421 422 static int 423 eth_rss_hash_update(struct rte_eth_dev *dev, struct rte_eth_rss_conf *rss_conf) 424 { 425 struct pmd_internals *internal = dev->data->dev_private; 426 427 rte_spinlock_lock(&internal->rss_lock); 428 429 if ((rss_conf->rss_hf & internal->flow_type_rss_offloads) != 0) 430 dev->data->dev_conf.rx_adv_conf.rss_conf.rss_hf = 431 rss_conf->rss_hf & internal->flow_type_rss_offloads; 432 433 if (rss_conf->rss_key) 434 rte_memcpy(internal->rss_key, rss_conf->rss_key, 40); 435 436 rte_spinlock_unlock(&internal->rss_lock); 437 438 return 0; 439 } 440 441 static int 442 eth_rss_hash_conf_get(struct rte_eth_dev *dev, 443 struct rte_eth_rss_conf *rss_conf) 444 { 445 struct pmd_internals *internal = dev->data->dev_private; 446 447 rte_spinlock_lock(&internal->rss_lock); 448 449 rss_conf->rss_hf = dev->data->dev_conf.rx_adv_conf.rss_conf.rss_hf; 450 if (rss_conf->rss_key) 451 rte_memcpy(rss_conf->rss_key, internal->rss_key, 40); 452 453 rte_spinlock_unlock(&internal->rss_lock); 454 455 return 0; 456 } 457 458 static const struct eth_dev_ops ops = { 459 .dev_start = eth_dev_start, 460 .dev_stop = eth_dev_stop, 461 .dev_configure = eth_dev_configure, 462 .dev_infos_get = eth_dev_info, 463 .rx_queue_setup = eth_rx_queue_setup, 464 .tx_queue_setup = eth_tx_queue_setup, 465 .rx_queue_release = eth_queue_release, 466 .tx_queue_release = eth_queue_release, 467 .link_update = eth_link_update, 468 .stats_get = eth_stats_get, 469 .stats_reset = eth_stats_reset, 470 .reta_update = eth_rss_reta_update, 471 .reta_query = eth_rss_reta_query, 472 .rss_hash_update = eth_rss_hash_update, 473 .rss_hash_conf_get = eth_rss_hash_conf_get 474 }; 475 476 static struct rte_vdev_driver pmd_null_drv; 477 478 static int 479 eth_dev_null_create(struct rte_vdev_device *dev, 480 unsigned packet_size, 481 unsigned packet_copy) 482 { 483 const unsigned nb_rx_queues = 1; 484 const unsigned nb_tx_queues = 1; 485 struct rte_eth_dev_data *data = NULL; 486 struct pmd_internals *internals = NULL; 487 struct rte_eth_dev *eth_dev = NULL; 488 489 static const uint8_t default_rss_key[40] = { 490 0x6D, 0x5A, 0x56, 0xDA, 0x25, 0x5B, 0x0E, 0xC2, 0x41, 0x67, 0x25, 0x3D, 491 0x43, 0xA3, 0x8F, 0xB0, 0xD0, 0xCA, 0x2B, 0xCB, 0xAE, 0x7B, 0x30, 0xB4, 492 0x77, 0xCB, 0x2D, 0xA3, 0x80, 0x30, 0xF2, 0x0C, 0x6A, 0x42, 0xB7, 0x3B, 493 0xBE, 0xAC, 0x01, 0xFA 494 }; 495 496 if (dev->device.numa_node == SOCKET_ID_ANY) 497 dev->device.numa_node = rte_socket_id(); 498 499 RTE_LOG(INFO, PMD, "Creating null ethdev on numa socket %u\n", 500 dev->device.numa_node); 501 502 /* now do all data allocation - for eth_dev structure, dummy pci driver 503 * and internal (private) data 504 */ 505 data = rte_zmalloc_socket(rte_vdev_device_name(dev), sizeof(*data), 0, 506 dev->device.numa_node); 507 if (!data) 508 return -ENOMEM; 509 510 eth_dev = rte_eth_vdev_allocate(dev, sizeof(*internals)); 511 if (!eth_dev) { 512 rte_free(data); 513 return -ENOMEM; 514 } 515 516 /* now put it all together 517 * - store queue data in internals, 518 * - store numa_node info in ethdev data 519 * - point eth_dev_data to internals 520 * - and point eth_dev structure to new eth_dev_data structure 521 */ 522 /* NOTE: we'll replace the data element, of originally allocated eth_dev 523 * so the nulls are local per-process */ 524 525 internals = eth_dev->data->dev_private; 526 internals->packet_size = packet_size; 527 internals->packet_copy = packet_copy; 528 internals->port_id = eth_dev->data->port_id; 529 530 internals->flow_type_rss_offloads = ETH_RSS_PROTO_MASK; 531 internals->reta_size = RTE_DIM(internals->reta_conf) * RTE_RETA_GROUP_SIZE; 532 533 rte_memcpy(internals->rss_key, default_rss_key, 40); 534 535 rte_memcpy(data, eth_dev->data, sizeof(*data)); 536 data->nb_rx_queues = (uint16_t)nb_rx_queues; 537 data->nb_tx_queues = (uint16_t)nb_tx_queues; 538 data->dev_link = pmd_link; 539 data->mac_addrs = ð_addr; 540 541 eth_dev->data = data; 542 eth_dev->dev_ops = &ops; 543 544 data->dev_flags = RTE_ETH_DEV_DETACHABLE; 545 546 /* finally assign rx and tx ops */ 547 if (packet_copy) { 548 eth_dev->rx_pkt_burst = eth_null_copy_rx; 549 eth_dev->tx_pkt_burst = eth_null_copy_tx; 550 } else { 551 eth_dev->rx_pkt_burst = eth_null_rx; 552 eth_dev->tx_pkt_burst = eth_null_tx; 553 } 554 555 return 0; 556 } 557 558 static inline int 559 get_packet_size_arg(const char *key __rte_unused, 560 const char *value, void *extra_args) 561 { 562 const char *a = value; 563 unsigned *packet_size = extra_args; 564 565 if ((value == NULL) || (extra_args == NULL)) 566 return -EINVAL; 567 568 *packet_size = (unsigned)strtoul(a, NULL, 0); 569 if (*packet_size == UINT_MAX) 570 return -1; 571 572 return 0; 573 } 574 575 static inline int 576 get_packet_copy_arg(const char *key __rte_unused, 577 const char *value, void *extra_args) 578 { 579 const char *a = value; 580 unsigned *packet_copy = extra_args; 581 582 if ((value == NULL) || (extra_args == NULL)) 583 return -EINVAL; 584 585 *packet_copy = (unsigned)strtoul(a, NULL, 0); 586 if (*packet_copy == UINT_MAX) 587 return -1; 588 589 return 0; 590 } 591 592 static int 593 rte_pmd_null_probe(struct rte_vdev_device *dev) 594 { 595 const char *name, *params; 596 unsigned packet_size = default_packet_size; 597 unsigned packet_copy = default_packet_copy; 598 struct rte_kvargs *kvlist = NULL; 599 int ret; 600 601 if (!dev) 602 return -EINVAL; 603 604 name = rte_vdev_device_name(dev); 605 params = rte_vdev_device_args(dev); 606 RTE_LOG(INFO, PMD, "Initializing pmd_null for %s\n", name); 607 608 if (params != NULL) { 609 kvlist = rte_kvargs_parse(params, valid_arguments); 610 if (kvlist == NULL) 611 return -1; 612 613 if (rte_kvargs_count(kvlist, ETH_NULL_PACKET_SIZE_ARG) == 1) { 614 615 ret = rte_kvargs_process(kvlist, 616 ETH_NULL_PACKET_SIZE_ARG, 617 &get_packet_size_arg, &packet_size); 618 if (ret < 0) 619 goto free_kvlist; 620 } 621 622 if (rte_kvargs_count(kvlist, ETH_NULL_PACKET_COPY_ARG) == 1) { 623 624 ret = rte_kvargs_process(kvlist, 625 ETH_NULL_PACKET_COPY_ARG, 626 &get_packet_copy_arg, &packet_copy); 627 if (ret < 0) 628 goto free_kvlist; 629 } 630 } 631 632 RTE_LOG(INFO, PMD, "Configure pmd_null: packet size is %d, " 633 "packet copy is %s\n", packet_size, 634 packet_copy ? "enabled" : "disabled"); 635 636 ret = eth_dev_null_create(dev, packet_size, packet_copy); 637 638 free_kvlist: 639 if (kvlist) 640 rte_kvargs_free(kvlist); 641 return ret; 642 } 643 644 static int 645 rte_pmd_null_remove(struct rte_vdev_device *dev) 646 { 647 struct rte_eth_dev *eth_dev = NULL; 648 649 if (!dev) 650 return -EINVAL; 651 652 RTE_LOG(INFO, PMD, "Closing null ethdev on numa socket %u\n", 653 rte_socket_id()); 654 655 /* find the ethdev entry */ 656 eth_dev = rte_eth_dev_allocated(rte_vdev_device_name(dev)); 657 if (eth_dev == NULL) 658 return -1; 659 660 rte_free(eth_dev->data->dev_private); 661 rte_free(eth_dev->data); 662 663 rte_eth_dev_release_port(eth_dev); 664 665 return 0; 666 } 667 668 static struct rte_vdev_driver pmd_null_drv = { 669 .probe = rte_pmd_null_probe, 670 .remove = rte_pmd_null_remove, 671 }; 672 673 RTE_PMD_REGISTER_VDEV(net_null, pmd_null_drv); 674 RTE_PMD_REGISTER_ALIAS(net_null, eth_null); 675 RTE_PMD_REGISTER_PARAM_STRING(net_null, 676 "size=<int> " 677 "copy=<int>"); 678