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