1 /* $FreeBSD$ */ 2 #include <sys/types.h> 3 #include <sys/stat.h> 4 #include <sys/ioctl.h> 5 #include <sys/mman.h> 6 #include <fcntl.h> 7 #include <inttypes.h> 8 #include <stdlib.h> 9 #include <stdio.h> 10 #include <stdarg.h> 11 #include <string.h> 12 #include <unistd.h> 13 #include <errno.h> 14 #include <net/netmap_user.h> 15 #define LIBNETMAP_NOTHREADSAFE 16 #include "libnetmap.h" 17 18 struct nmport_cleanup_d { 19 struct nmport_cleanup_d *next; 20 void (*cleanup)(struct nmport_cleanup_d *, struct nmport_d *); 21 }; 22 23 static void 24 nmport_push_cleanup(struct nmport_d *d, struct nmport_cleanup_d *c) 25 { 26 c->next = d->clist; 27 d->clist = c; 28 } 29 30 static void 31 nmport_pop_cleanup(struct nmport_d *d) 32 { 33 struct nmport_cleanup_d *top; 34 35 top = d->clist; 36 d->clist = d->clist->next; 37 (*top->cleanup)(top, d); 38 nmctx_free(d->ctx, top); 39 } 40 41 void nmport_do_cleanup(struct nmport_d *d) 42 { 43 while (d->clist != NULL) { 44 nmport_pop_cleanup(d); 45 } 46 } 47 48 static struct nmport_d * 49 nmport_new_with_ctx(struct nmctx *ctx) 50 { 51 struct nmport_d *d; 52 53 /* allocate a descriptor */ 54 d = nmctx_malloc(ctx, sizeof(*d)); 55 if (d == NULL) { 56 nmctx_ferror(ctx, "cannot allocate nmport descriptor"); 57 goto out; 58 } 59 memset(d, 0, sizeof(*d)); 60 61 nmreq_header_init(&d->hdr, NETMAP_REQ_REGISTER, &d->reg); 62 63 d->ctx = ctx; 64 d->fd = -1; 65 66 out: 67 return d; 68 } 69 70 struct nmport_d * 71 nmport_new(void) 72 { 73 struct nmctx *ctx = nmctx_get(); 74 return nmport_new_with_ctx(ctx); 75 } 76 77 78 void 79 nmport_delete(struct nmport_d *d) 80 { 81 nmctx_free(d->ctx, d); 82 } 83 84 void 85 nmport_extmem_cleanup(struct nmport_cleanup_d *c, struct nmport_d *d) 86 { 87 (void)c; 88 89 if (d->extmem == NULL) 90 return; 91 92 nmreq_remove_option(&d->hdr, &d->extmem->nro_opt); 93 nmctx_free(d->ctx, d->extmem); 94 d->extmem = NULL; 95 } 96 97 98 int 99 nmport_extmem(struct nmport_d *d, void *base, size_t size) 100 { 101 struct nmctx *ctx = d->ctx; 102 struct nmport_cleanup_d *clnup = NULL; 103 104 if (d->register_done) { 105 nmctx_ferror(ctx, "%s: cannot set extmem of an already registered port", d->hdr.nr_name); 106 errno = EINVAL; 107 return -1; 108 } 109 110 if (d->extmem != NULL) { 111 nmctx_ferror(ctx, "%s: extmem already in use", d->hdr.nr_name); 112 errno = EINVAL; 113 return -1; 114 } 115 116 clnup = (struct nmport_cleanup_d *)nmctx_malloc(ctx, sizeof(*clnup)); 117 if (clnup == NULL) { 118 nmctx_ferror(ctx, "failed to allocate cleanup descriptor"); 119 errno = ENOMEM; 120 return -1; 121 } 122 123 d->extmem = nmctx_malloc(ctx, sizeof(*d->extmem)); 124 if (d->extmem == NULL) { 125 nmctx_ferror(ctx, "%s: cannot allocate extmem option", d->hdr.nr_name); 126 nmctx_free(ctx, clnup); 127 errno = ENOMEM; 128 return -1; 129 } 130 memset(d->extmem, 0, sizeof(*d->extmem)); 131 d->extmem->nro_usrptr = (uintptr_t)base; 132 d->extmem->nro_opt.nro_reqtype = NETMAP_REQ_OPT_EXTMEM; 133 d->extmem->nro_info.nr_memsize = size; 134 nmreq_push_option(&d->hdr, &d->extmem->nro_opt); 135 136 clnup->cleanup = nmport_extmem_cleanup; 137 nmport_push_cleanup(d, clnup); 138 139 return 0; 140 } 141 142 struct nmport_extmem_from_file_cleanup_d { 143 struct nmport_cleanup_d up; 144 void *p; 145 size_t size; 146 }; 147 148 void nmport_extmem_from_file_cleanup(struct nmport_cleanup_d *c, 149 struct nmport_d *d) 150 { 151 struct nmport_extmem_from_file_cleanup_d *cc = 152 (struct nmport_extmem_from_file_cleanup_d *)c; 153 154 munmap(cc->p, cc->size); 155 } 156 157 int 158 nmport_extmem_from_file(struct nmport_d *d, const char *fname) 159 { 160 struct nmctx *ctx = d->ctx; 161 int fd = -1; 162 off_t mapsize; 163 void *p; 164 struct nmport_extmem_from_file_cleanup_d *clnup = NULL; 165 166 clnup = nmctx_malloc(ctx, sizeof(*clnup)); 167 if (clnup == NULL) { 168 nmctx_ferror(ctx, "cannot allocate cleanup descriptor"); 169 errno = ENOMEM; 170 goto fail; 171 } 172 173 fd = open(fname, O_RDWR); 174 if (fd < 0) { 175 nmctx_ferror(ctx, "cannot open '%s': %s", fname, strerror(errno)); 176 goto fail; 177 } 178 mapsize = lseek(fd, 0, SEEK_END); 179 if (mapsize < 0) { 180 nmctx_ferror(ctx, "failed to obtain filesize of '%s': %s", fname, strerror(errno)); 181 goto fail; 182 } 183 p = mmap(0, mapsize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 184 if (p == MAP_FAILED) { 185 nmctx_ferror(ctx, "cannot mmap '%s': %s", fname, strerror(errno)); 186 goto fail; 187 } 188 close(fd); 189 190 clnup->p = p; 191 clnup->size = mapsize; 192 clnup->up.cleanup = nmport_extmem_from_file_cleanup; 193 nmport_push_cleanup(d, &clnup->up); 194 195 if (nmport_extmem(d, p, mapsize) < 0) 196 goto fail; 197 198 return 0; 199 200 fail: 201 if (fd >= 0) 202 close(fd); 203 if (clnup != NULL) { 204 if (clnup->p != MAP_FAILED) 205 nmport_pop_cleanup(d); 206 else 207 nmctx_free(ctx, clnup); 208 } 209 return -1; 210 } 211 212 struct nmreq_pools_info* 213 nmport_extmem_getinfo(struct nmport_d *d) 214 { 215 if (d->extmem == NULL) 216 return NULL; 217 return &d->extmem->nro_info; 218 } 219 220 /* head of the list of options */ 221 static struct nmreq_opt_parser *nmport_opt_parsers; 222 223 #define NPOPT_PARSER(o) nmport_opt_##o##_parser 224 #define NPOPT_DESC(o) nmport_opt_##o##_desc 225 #define NPOPT_NRKEYS(o) (NPOPT_DESC(o).nr_keys) 226 #define NPOPT_DECL(o, f) \ 227 static int NPOPT_PARSER(o)(struct nmreq_parse_ctx *); \ 228 static struct nmreq_opt_parser NPOPT_DESC(o) = { \ 229 .prefix = #o, \ 230 .parse = NPOPT_PARSER(o), \ 231 .flags = (f), \ 232 .default_key = -1, \ 233 .nr_keys = 0, \ 234 .next = NULL, \ 235 }; \ 236 static void __attribute__((constructor)) \ 237 nmport_opt_##o##_ctor(void) \ 238 { \ 239 NPOPT_DESC(o).next = nmport_opt_parsers; \ 240 nmport_opt_parsers = &NPOPT_DESC(o); \ 241 } 242 struct nmport_key_desc { 243 struct nmreq_opt_parser *option; 244 const char *key; 245 unsigned int flags; 246 int id; 247 }; 248 static void 249 nmport_opt_key_ctor(struct nmport_key_desc *k) 250 { 251 struct nmreq_opt_parser *o = k->option; 252 struct nmreq_opt_key *ok; 253 254 k->id = o->nr_keys; 255 ok = &o->keys[k->id]; 256 ok->key = k->key; 257 ok->id = k->id; 258 ok->flags = k->flags; 259 o->nr_keys++; 260 if (ok->flags & NMREQ_OPTK_DEFAULT) 261 o->default_key = ok->id; 262 } 263 #define NPKEY_DESC(o, k) nmport_opt_##o##_key_##k##_desc 264 #define NPKEY_ID(o, k) (NPKEY_DESC(o, k).id) 265 #define NPKEY_DECL(o, k, f) \ 266 static struct nmport_key_desc NPKEY_DESC(o, k) = { \ 267 .option = &NPOPT_DESC(o), \ 268 .key = #k, \ 269 .flags = (f), \ 270 .id = -1, \ 271 }; \ 272 static void __attribute__((constructor)) \ 273 nmport_opt_##o##_key_##k##_ctor(void) \ 274 { \ 275 nmport_opt_key_ctor(&NPKEY_DESC(o, k)); \ 276 } 277 #define nmport_key(p, o, k) ((p)->keys[NPKEY_ID(o, k)]) 278 #define nmport_defkey(p, o) ((p)->keys[NPOPT_DESC(o).default_key]) 279 280 NPOPT_DECL(share, 0) 281 NPKEY_DECL(share, port, NMREQ_OPTK_DEFAULT|NMREQ_OPTK_MUSTSET) 282 NPOPT_DECL(extmem, 0) 283 NPKEY_DECL(extmem, file, NMREQ_OPTK_DEFAULT|NMREQ_OPTK_MUSTSET) 284 NPKEY_DECL(extmem, if_num, 0) 285 NPKEY_DECL(extmem, if_size, 0) 286 NPKEY_DECL(extmem, ring_num, 0) 287 NPKEY_DECL(extmem, ring_size, 0) 288 NPKEY_DECL(extmem, buf_num, 0) 289 NPKEY_DECL(extmem, buf_size, 0) 290 NPOPT_DECL(conf, 0) 291 NPKEY_DECL(conf, rings, 0) 292 NPKEY_DECL(conf, host_rings, 0) 293 NPKEY_DECL(conf, slots, 0) 294 NPKEY_DECL(conf, tx_rings, 0) 295 NPKEY_DECL(conf, rx_rings, 0) 296 NPKEY_DECL(conf, host_tx_rings, 0) 297 NPKEY_DECL(conf, host_rx_rings, 0) 298 NPKEY_DECL(conf, tx_slots, 0) 299 NPKEY_DECL(conf, rx_slots, 0) 300 301 302 static int 303 NPOPT_PARSER(share)(struct nmreq_parse_ctx *p) 304 { 305 struct nmctx *ctx = p->ctx; 306 struct nmport_d *d = p->token; 307 int32_t mem_id; 308 const char *v = nmport_defkey(p, share); 309 310 mem_id = nmreq_get_mem_id(&v, ctx); 311 if (mem_id < 0) 312 return -1; 313 if (d->reg.nr_mem_id && d->reg.nr_mem_id != mem_id) { 314 nmctx_ferror(ctx, "cannot set mem_id to %"PRId32", already set to %"PRIu16"", 315 mem_id, d->reg.nr_mem_id); 316 errno = EINVAL; 317 return -1; 318 } 319 d->reg.nr_mem_id = mem_id; 320 return 0; 321 } 322 323 static int 324 NPOPT_PARSER(extmem)(struct nmreq_parse_ctx *p) 325 { 326 struct nmport_d *d; 327 struct nmreq_pools_info *pi; 328 int i; 329 330 d = p->token; 331 332 if (nmport_extmem_from_file(d, nmport_key(p, extmem, file)) < 0) 333 return -1; 334 335 pi = &d->extmem->nro_info; 336 337 for (i = 0; i < NPOPT_NRKEYS(extmem); i++) { 338 const char *k = p->keys[i]; 339 uint32_t v; 340 341 if (k == NULL) 342 continue; 343 344 v = atoi(k); 345 if (i == NPKEY_ID(extmem, if_num)) { 346 pi->nr_if_pool_objtotal = v; 347 } else if (i == NPKEY_ID(extmem, if_size)) { 348 pi->nr_if_pool_objsize = v; 349 } else if (i == NPKEY_ID(extmem, ring_num)) { 350 pi->nr_ring_pool_objtotal = v; 351 } else if (i == NPKEY_ID(extmem, ring_size)) { 352 pi->nr_ring_pool_objsize = v; 353 } else if (i == NPKEY_ID(extmem, buf_num)) { 354 pi->nr_buf_pool_objtotal = v; 355 } else if (i == NPKEY_ID(extmem, buf_size)) { 356 pi->nr_buf_pool_objsize = v; 357 } 358 } 359 return 0; 360 } 361 362 static int 363 NPOPT_PARSER(conf)(struct nmreq_parse_ctx *p) 364 { 365 struct nmport_d *d; 366 367 d = p->token; 368 369 if (nmport_key(p, conf, rings) != NULL) { 370 uint16_t nr_rings = atoi(nmport_key(p, conf, rings)); 371 d->reg.nr_tx_rings = nr_rings; 372 d->reg.nr_rx_rings = nr_rings; 373 } 374 if (nmport_key(p, conf, host_rings) != NULL) { 375 uint16_t nr_rings = atoi(nmport_key(p, conf, host_rings)); 376 d->reg.nr_host_tx_rings = nr_rings; 377 d->reg.nr_host_rx_rings = nr_rings; 378 } 379 if (nmport_key(p, conf, slots) != NULL) { 380 uint32_t nr_slots = atoi(nmport_key(p, conf, slots)); 381 d->reg.nr_tx_slots = nr_slots; 382 d->reg.nr_rx_slots = nr_slots; 383 } 384 if (nmport_key(p, conf, tx_rings) != NULL) { 385 d->reg.nr_tx_rings = atoi(nmport_key(p, conf, tx_rings)); 386 } 387 if (nmport_key(p, conf, rx_rings) != NULL) { 388 d->reg.nr_rx_rings = atoi(nmport_key(p, conf, rx_rings)); 389 } 390 if (nmport_key(p, conf, host_tx_rings) != NULL) { 391 d->reg.nr_host_tx_rings = atoi(nmport_key(p, conf, host_tx_rings)); 392 } 393 if (nmport_key(p, conf, host_rx_rings) != NULL) { 394 d->reg.nr_host_rx_rings = atoi(nmport_key(p, conf, host_rx_rings)); 395 } 396 if (nmport_key(p, conf, tx_slots) != NULL) { 397 d->reg.nr_tx_slots = atoi(nmport_key(p, conf, tx_slots)); 398 } 399 if (nmport_key(p, conf, rx_slots) != NULL) { 400 d->reg.nr_rx_slots = atoi(nmport_key(p, conf, rx_slots)); 401 } 402 return 0; 403 } 404 405 void 406 nmport_disable_option(const char *opt) 407 { 408 struct nmreq_opt_parser *p; 409 410 for (p = nmport_opt_parsers; p != NULL; p = p->next) { 411 if (!strcmp(p->prefix, opt)) { 412 p->flags |= NMREQ_OPTF_DISABLED; 413 } 414 } 415 } 416 417 int 418 nmport_enable_option(const char *opt) 419 { 420 struct nmreq_opt_parser *p; 421 422 for (p = nmport_opt_parsers; p != NULL; p = p->next) { 423 if (!strcmp(p->prefix, opt)) { 424 p->flags &= ~NMREQ_OPTF_DISABLED; 425 return 0; 426 } 427 } 428 errno = EOPNOTSUPP; 429 return -1; 430 } 431 432 433 int 434 nmport_parse(struct nmport_d *d, const char *ifname) 435 { 436 const char *scan = ifname; 437 438 if (nmreq_header_decode(&scan, &d->hdr, d->ctx) < 0) { 439 goto err; 440 } 441 442 /* parse the register request */ 443 if (nmreq_register_decode(&scan, &d->reg, d->ctx) < 0) { 444 goto err; 445 } 446 447 /* parse the options, if any */ 448 if (nmreq_options_decode(scan, nmport_opt_parsers, d, d->ctx) < 0) { 449 goto err; 450 } 451 return 0; 452 453 err: 454 nmport_undo_parse(d); 455 return -1; 456 } 457 458 void 459 nmport_undo_parse(struct nmport_d *d) 460 { 461 nmport_do_cleanup(d); 462 memset(&d->reg, 0, sizeof(d->reg)); 463 memset(&d->hdr, 0, sizeof(d->hdr)); 464 } 465 466 struct nmport_d * 467 nmport_prepare(const char *ifname) 468 { 469 struct nmport_d *d; 470 471 /* allocate a descriptor */ 472 d = nmport_new(); 473 if (d == NULL) 474 goto err; 475 476 /* parse the header */ 477 if (nmport_parse(d, ifname) < 0) 478 goto err; 479 480 return d; 481 482 err: 483 nmport_undo_prepare(d); 484 return NULL; 485 } 486 487 void 488 nmport_undo_prepare(struct nmport_d *d) 489 { 490 if (d == NULL) 491 return; 492 nmport_undo_parse(d); 493 nmport_delete(d); 494 } 495 496 int 497 nmport_register(struct nmport_d *d) 498 { 499 struct nmctx *ctx = d->ctx; 500 501 if (d->register_done) { 502 errno = EINVAL; 503 nmctx_ferror(ctx, "%s: already registered", d->hdr.nr_name); 504 return -1; 505 } 506 507 d->fd = open("/dev/netmap", O_RDWR); 508 if (d->fd < 0) { 509 nmctx_ferror(ctx, "/dev/netmap: %s", strerror(errno)); 510 goto err; 511 } 512 513 if (ioctl(d->fd, NIOCCTRL, &d->hdr) < 0) { 514 struct nmreq_option *o; 515 int option_errors = 0; 516 517 nmreq_foreach_option(&d->hdr, o) { 518 if (o->nro_status) { 519 nmctx_ferror(ctx, "%s: option %s: %s", 520 d->hdr.nr_name, 521 nmreq_option_name(o->nro_reqtype), 522 strerror(o->nro_status)); 523 option_errors++; 524 } 525 526 } 527 if (!option_errors) 528 nmctx_ferror(ctx, "%s: %s", d->hdr.nr_name, strerror(errno)); 529 goto err; 530 } 531 532 d->register_done = 1; 533 534 return 0; 535 536 err: 537 nmport_undo_register(d); 538 return -1; 539 } 540 541 void 542 nmport_undo_register(struct nmport_d *d) 543 { 544 if (d->fd >= 0) 545 close(d->fd); 546 d->fd = -1; 547 d->register_done = 0; 548 } 549 550 /* lookup the mem_id in the mem-list: do a new mmap() if 551 * not found, reuse existing otherwise 552 */ 553 int 554 nmport_mmap(struct nmport_d *d) 555 { 556 struct nmctx *ctx = d->ctx; 557 struct nmem_d *m = NULL; 558 u_int num_tx, num_rx; 559 int i; 560 561 if (d->mmap_done) { 562 errno = EINVAL; 563 nmctx_ferror(ctx, "%s: already mapped", d->hdr.nr_name); 564 return -1; 565 } 566 567 if (!d->register_done) { 568 errno = EINVAL; 569 nmctx_ferror(ctx, "cannot map unregistered port"); 570 return -1; 571 } 572 573 nmctx_lock(ctx); 574 575 for (m = ctx->mem_descs; m != NULL; m = m->next) 576 if (m->mem_id == d->reg.nr_mem_id) 577 break; 578 579 if (m == NULL) { 580 m = nmctx_malloc(ctx, sizeof(*m)); 581 if (m == NULL) { 582 nmctx_ferror(ctx, "cannot allocate memory descriptor"); 583 goto err; 584 } 585 memset(m, 0, sizeof(*m)); 586 if (d->extmem != NULL) { 587 m->mem = (void *)d->extmem->nro_usrptr; 588 m->size = d->extmem->nro_info.nr_memsize; 589 m->is_extmem = 1; 590 } else { 591 m->mem = mmap(NULL, d->reg.nr_memsize, PROT_READ|PROT_WRITE, 592 MAP_SHARED, d->fd, 0); 593 if (m->mem == MAP_FAILED) { 594 nmctx_ferror(ctx, "mmap: %s", strerror(errno)); 595 goto err; 596 } 597 m->size = d->reg.nr_memsize; 598 } 599 m->mem_id = d->reg.nr_mem_id; 600 m->next = ctx->mem_descs; 601 if (ctx->mem_descs != NULL) 602 ctx->mem_descs->prev = m; 603 ctx->mem_descs = m; 604 } 605 m->refcount++; 606 607 nmctx_unlock(ctx); 608 609 d->mem = m; 610 611 d->nifp = NETMAP_IF(m->mem, d->reg.nr_offset); 612 613 num_tx = d->reg.nr_tx_rings + d->nifp->ni_host_tx_rings; 614 for (i = 0; i < num_tx && !d->nifp->ring_ofs[i]; i++) 615 ; 616 d->first_tx_ring = i; 617 for ( ; i < num_tx && d->nifp->ring_ofs[i]; i++) 618 ; 619 d->last_tx_ring = i - 1; 620 621 num_rx = d->reg.nr_rx_rings + d->nifp->ni_host_rx_rings; 622 for (i = 0; i < num_rx && !d->nifp->ring_ofs[i + num_tx]; i++) 623 ; 624 d->first_rx_ring = i; 625 for ( ; i < num_rx && d->nifp->ring_ofs[i + num_tx]; i++) 626 ; 627 d->last_rx_ring = i - 1; 628 629 d->mmap_done = 1; 630 631 return 0; 632 633 err: 634 nmctx_unlock(ctx); 635 nmport_undo_mmap(d); 636 return -1; 637 } 638 639 void 640 nmport_undo_mmap(struct nmport_d *d) 641 { 642 struct nmem_d *m; 643 struct nmctx *ctx = d->ctx; 644 645 m = d->mem; 646 if (m == NULL) 647 return; 648 nmctx_lock(ctx); 649 m->refcount--; 650 if (m->refcount <= 0) { 651 if (!m->is_extmem && m->mem != MAP_FAILED) 652 munmap(m->mem, m->size); 653 /* extract from the list and free */ 654 if (m->next != NULL) 655 m->next->prev = m->prev; 656 if (m->prev != NULL) 657 m->prev->next = m->next; 658 else 659 ctx->mem_descs = m->next; 660 nmctx_free(ctx, m); 661 d->mem = NULL; 662 } 663 nmctx_unlock(ctx); 664 d->mmap_done = 0; 665 d->mem = NULL; 666 d->nifp = NULL; 667 d->first_tx_ring = 0; 668 d->last_tx_ring = 0; 669 d->first_rx_ring = 0; 670 d->last_rx_ring = 0; 671 d->cur_tx_ring = 0; 672 d->cur_rx_ring = 0; 673 } 674 675 int 676 nmport_open_desc(struct nmport_d *d) 677 { 678 if (nmport_register(d) < 0) 679 goto err; 680 681 if (nmport_mmap(d) < 0) 682 goto err; 683 684 return 0; 685 err: 686 nmport_undo_open_desc(d); 687 return -1; 688 } 689 690 void 691 nmport_undo_open_desc(struct nmport_d *d) 692 { 693 nmport_undo_mmap(d); 694 nmport_undo_register(d); 695 } 696 697 698 struct nmport_d * 699 nmport_open(const char *ifname) 700 { 701 struct nmport_d *d; 702 703 /* prepare the descriptor */ 704 d = nmport_prepare(ifname); 705 if (d == NULL) 706 goto err; 707 708 /* open netmap and register */ 709 if (nmport_open_desc(d) < 0) 710 goto err; 711 712 return d; 713 714 err: 715 nmport_close(d); 716 return NULL; 717 } 718 719 void 720 nmport_close(struct nmport_d *d) 721 { 722 if (d == NULL) 723 return; 724 nmport_undo_open_desc(d); 725 nmport_undo_prepare(d); 726 } 727 728 struct nmport_d * 729 nmport_clone(struct nmport_d *d) 730 { 731 struct nmport_d *c; 732 struct nmctx *ctx; 733 734 ctx = d->ctx; 735 736 if (d->extmem != NULL && !d->register_done) { 737 errno = EINVAL; 738 nmctx_ferror(ctx, "cannot clone unregistered port that is using extmem"); 739 return NULL; 740 } 741 742 c = nmport_new_with_ctx(ctx); 743 if (c == NULL) 744 return NULL; 745 /* copy the output of parse */ 746 c->hdr = d->hdr; 747 /* redirect the pointer to the body */ 748 c->hdr.nr_body = (uintptr_t)&c->reg; 749 /* options are not cloned */ 750 c->hdr.nr_options = 0; 751 c->reg = d->reg; /* this also copies the mem_id */ 752 /* put the new port in an un-registered, unmapped state */ 753 c->fd = -1; 754 c->nifp = NULL; 755 c->register_done = 0; 756 c->mem = NULL; 757 c->extmem = NULL; 758 c->mmap_done = 0; 759 c->first_tx_ring = 0; 760 c->last_tx_ring = 0; 761 c->first_rx_ring = 0; 762 c->last_rx_ring = 0; 763 c->cur_tx_ring = 0; 764 c->cur_rx_ring = 0; 765 766 return c; 767 } 768 769 int 770 nmport_inject(struct nmport_d *d, const void *buf, size_t size) 771 { 772 u_int c, n = d->last_tx_ring - d->first_tx_ring + 1, 773 ri = d->cur_tx_ring; 774 775 for (c = 0; c < n ; c++, ri++) { 776 /* compute current ring to use */ 777 struct netmap_ring *ring; 778 uint32_t i, j, idx; 779 size_t rem; 780 781 if (ri > d->last_tx_ring) 782 ri = d->first_tx_ring; 783 ring = NETMAP_TXRING(d->nifp, ri); 784 rem = size; 785 j = ring->cur; 786 while (rem > ring->nr_buf_size && j != ring->tail) { 787 rem -= ring->nr_buf_size; 788 j = nm_ring_next(ring, j); 789 } 790 if (j == ring->tail && rem > 0) 791 continue; 792 i = ring->cur; 793 while (i != j) { 794 idx = ring->slot[i].buf_idx; 795 ring->slot[i].len = ring->nr_buf_size; 796 ring->slot[i].flags = NS_MOREFRAG; 797 nm_pkt_copy(buf, NETMAP_BUF(ring, idx), ring->nr_buf_size); 798 i = nm_ring_next(ring, i); 799 buf = (char *)buf + ring->nr_buf_size; 800 } 801 idx = ring->slot[i].buf_idx; 802 ring->slot[i].len = rem; 803 ring->slot[i].flags = 0; 804 nm_pkt_copy(buf, NETMAP_BUF(ring, idx), rem); 805 ring->head = ring->cur = nm_ring_next(ring, i); 806 d->cur_tx_ring = ri; 807 return size; 808 } 809 return 0; /* fail */ 810 } 811