1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (C) 2012-2014 Matteo Landi 5 * Copyright (C) 2012-2016 Luigi Rizzo 6 * Copyright (C) 2012-2016 Giuseppe Lettieri 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #ifdef linux 32 #include "bsd_glue.h" 33 #endif /* linux */ 34 35 #ifdef __APPLE__ 36 #include "osx_glue.h" 37 #endif /* __APPLE__ */ 38 39 #ifdef __FreeBSD__ 40 #include <sys/types.h> 41 #include <sys/domainset.h> 42 #include <sys/limits.h> 43 #include <sys/malloc.h> 44 #include <sys/kernel.h> /* MALLOC_DEFINE */ 45 #include <sys/proc.h> 46 #include <vm/vm.h> /* vtophys */ 47 #include <vm/pmap.h> /* vtophys */ 48 #include <sys/socket.h> /* sockaddrs */ 49 #include <sys/selinfo.h> 50 #include <sys/sysctl.h> 51 #include <net/if.h> 52 #include <net/if_var.h> 53 #include <net/vnet.h> 54 #include <machine/bus.h> /* bus_dmamap_* */ 55 56 /* M_NETMAP only used in here */ 57 MALLOC_DECLARE(M_NETMAP); 58 MALLOC_DEFINE(M_NETMAP, "netmap", "Network memory map"); 59 60 #endif /* __FreeBSD__ */ 61 62 #ifdef _WIN32 63 #include <win_glue.h> 64 #endif 65 66 #include <net/netmap.h> 67 #include <dev/netmap/netmap_kern.h> 68 #include <net/netmap_virt.h> 69 #include "netmap_mem2.h" 70 71 #ifdef _WIN32_USE_SMALL_GENERIC_DEVICES_MEMORY 72 #define NETMAP_BUF_MAX_NUM 8*4096 /* if too big takes too much time to allocate */ 73 #else 74 #define NETMAP_BUF_MAX_NUM 20*4096*2 /* large machine */ 75 #endif 76 77 #define NETMAP_POOL_MAX_NAMSZ 32 78 79 80 enum { 81 NETMAP_IF_POOL = 0, 82 NETMAP_RING_POOL, 83 NETMAP_BUF_POOL, 84 NETMAP_POOLS_NR 85 }; 86 87 88 struct netmap_obj_params { 89 u_int size; 90 u_int num; 91 92 u_int last_size; 93 u_int last_num; 94 }; 95 96 struct netmap_obj_pool { 97 char name[NETMAP_POOL_MAX_NAMSZ]; /* name of the allocator */ 98 99 /* ---------------------------------------------------*/ 100 /* these are only meaningful if the pool is finalized */ 101 /* (see 'finalized' field in netmap_mem_d) */ 102 size_t memtotal; /* actual total memory space */ 103 104 struct lut_entry *lut; /* virt,phys addresses, objtotal entries */ 105 uint32_t *bitmap; /* one bit per buffer, 1 means free */ 106 uint32_t *invalid_bitmap;/* one bit per buffer, 1 means invalid */ 107 uint32_t bitmap_slots; /* number of uint32 entries in bitmap */ 108 109 u_int objtotal; /* actual total number of objects. */ 110 u_int numclusters; /* actual number of clusters */ 111 u_int objfree; /* number of free objects. */ 112 113 int alloc_done; /* we have allocated the memory */ 114 /* ---------------------------------------------------*/ 115 116 /* limits */ 117 u_int objminsize; /* minimum object size */ 118 u_int objmaxsize; /* maximum object size */ 119 u_int nummin; /* minimum number of objects */ 120 u_int nummax; /* maximum number of objects */ 121 122 /* these are changed only by config */ 123 u_int _objtotal; /* total number of objects */ 124 u_int _objsize; /* object size */ 125 u_int _clustsize; /* cluster size */ 126 u_int _clustentries; /* objects per cluster */ 127 u_int _numclusters; /* number of clusters */ 128 129 /* requested values */ 130 u_int r_objtotal; 131 u_int r_objsize; 132 }; 133 134 #define NMA_LOCK_T NM_MTX_T 135 #define NMA_LOCK_INIT(n) NM_MTX_INIT((n)->nm_mtx) 136 #define NMA_LOCK_DESTROY(n) NM_MTX_DESTROY((n)->nm_mtx) 137 #define NMA_LOCK(n) NM_MTX_LOCK((n)->nm_mtx) 138 #define NMA_SPINLOCK(n) NM_MTX_SPINLOCK((n)->nm_mtx) 139 #define NMA_UNLOCK(n) NM_MTX_UNLOCK((n)->nm_mtx) 140 141 struct netmap_mem_ops { 142 int (*nmd_get_lut)(struct netmap_mem_d *, struct netmap_lut*); 143 int (*nmd_get_info)(struct netmap_mem_d *, uint64_t *size, 144 u_int *memflags, uint16_t *id); 145 146 vm_paddr_t (*nmd_ofstophys)(struct netmap_mem_d *, vm_ooffset_t); 147 int (*nmd_config)(struct netmap_mem_d *); 148 int (*nmd_finalize)(struct netmap_mem_d *, struct netmap_adapter *); 149 void (*nmd_deref)(struct netmap_mem_d *, struct netmap_adapter *); 150 ssize_t (*nmd_if_offset)(struct netmap_mem_d *, const void *vaddr); 151 void (*nmd_delete)(struct netmap_mem_d *); 152 153 struct netmap_if * (*nmd_if_new)(struct netmap_mem_d *, 154 struct netmap_adapter *, struct netmap_priv_d *); 155 void (*nmd_if_delete)(struct netmap_mem_d *, 156 struct netmap_adapter *, struct netmap_if *); 157 int (*nmd_rings_create)(struct netmap_mem_d *, 158 struct netmap_adapter *); 159 void (*nmd_rings_delete)(struct netmap_mem_d *, 160 struct netmap_adapter *); 161 }; 162 163 struct netmap_mem_d { 164 NMA_LOCK_T nm_mtx; /* protect the allocator */ 165 size_t nm_totalsize; /* shorthand */ 166 167 u_int flags; 168 #define NETMAP_MEM_FINALIZED 0x1 /* preallocation done */ 169 #define NETMAP_MEM_HIDDEN 0x8 /* being prepared */ 170 #define NETMAP_MEM_NOMAP 0x10 /* do not map/unmap pdevs */ 171 int lasterr; /* last error for curr config */ 172 int active; /* active users */ 173 int refcount; 174 /* the three allocators */ 175 struct netmap_obj_pool pools[NETMAP_POOLS_NR]; 176 177 nm_memid_t nm_id; /* allocator identifier */ 178 int nm_grp; /* iommu group id */ 179 int nm_numa_domain; /* local NUMA domain */ 180 181 /* list of all existing allocators, sorted by nm_id */ 182 struct netmap_mem_d *prev, *next; 183 184 const struct netmap_mem_ops *ops; 185 186 struct netmap_obj_params params[NETMAP_POOLS_NR]; 187 188 #define NM_MEM_NAMESZ 16 189 char name[NM_MEM_NAMESZ]; 190 }; 191 192 int 193 netmap_mem_get_lut(struct netmap_mem_d *nmd, struct netmap_lut *lut) 194 { 195 int rv; 196 197 NMA_LOCK(nmd); 198 rv = nmd->ops->nmd_get_lut(nmd, lut); 199 NMA_UNLOCK(nmd); 200 201 return rv; 202 } 203 204 int 205 netmap_mem_get_info(struct netmap_mem_d *nmd, uint64_t *size, 206 u_int *memflags, nm_memid_t *memid) 207 { 208 int rv; 209 210 NMA_LOCK(nmd); 211 rv = nmd->ops->nmd_get_info(nmd, size, memflags, memid); 212 NMA_UNLOCK(nmd); 213 214 return rv; 215 } 216 217 vm_paddr_t 218 netmap_mem_ofstophys(struct netmap_mem_d *nmd, vm_ooffset_t off) 219 { 220 vm_paddr_t pa; 221 222 #if defined(__FreeBSD__) 223 /* This function is called by netmap_dev_pager_fault(), which holds a 224 * non-sleepable lock since FreeBSD 12. Since we cannot sleep, we 225 * spin on the trylock. */ 226 NMA_SPINLOCK(nmd); 227 #else 228 NMA_LOCK(nmd); 229 #endif 230 pa = nmd->ops->nmd_ofstophys(nmd, off); 231 NMA_UNLOCK(nmd); 232 233 return pa; 234 } 235 236 static int 237 netmap_mem_config(struct netmap_mem_d *nmd) 238 { 239 if (nmd->active) { 240 /* already in use. Not fatal, but we 241 * cannot change the configuration 242 */ 243 return 0; 244 } 245 246 return nmd->ops->nmd_config(nmd); 247 } 248 249 ssize_t 250 netmap_mem_if_offset(struct netmap_mem_d *nmd, const void *off) 251 { 252 ssize_t rv; 253 254 NMA_LOCK(nmd); 255 rv = nmd->ops->nmd_if_offset(nmd, off); 256 NMA_UNLOCK(nmd); 257 258 return rv; 259 } 260 261 static void 262 netmap_mem_delete(struct netmap_mem_d *nmd) 263 { 264 nmd->ops->nmd_delete(nmd); 265 } 266 267 struct netmap_if * 268 netmap_mem_if_new(struct netmap_adapter *na, struct netmap_priv_d *priv) 269 { 270 struct netmap_if *nifp; 271 struct netmap_mem_d *nmd = na->nm_mem; 272 273 NMA_LOCK(nmd); 274 nifp = nmd->ops->nmd_if_new(nmd, na, priv); 275 NMA_UNLOCK(nmd); 276 277 return nifp; 278 } 279 280 void 281 netmap_mem_if_delete(struct netmap_adapter *na, struct netmap_if *nif) 282 { 283 struct netmap_mem_d *nmd = na->nm_mem; 284 285 NMA_LOCK(nmd); 286 nmd->ops->nmd_if_delete(nmd, na, nif); 287 NMA_UNLOCK(nmd); 288 } 289 290 int 291 netmap_mem_rings_create(struct netmap_adapter *na) 292 { 293 int rv; 294 struct netmap_mem_d *nmd = na->nm_mem; 295 296 NMA_LOCK(nmd); 297 rv = nmd->ops->nmd_rings_create(nmd, na); 298 NMA_UNLOCK(nmd); 299 300 return rv; 301 } 302 303 void 304 netmap_mem_rings_delete(struct netmap_adapter *na) 305 { 306 struct netmap_mem_d *nmd = na->nm_mem; 307 308 NMA_LOCK(nmd); 309 nmd->ops->nmd_rings_delete(nmd, na); 310 NMA_UNLOCK(nmd); 311 } 312 313 static int netmap_mem_map(struct netmap_obj_pool *, struct netmap_adapter *); 314 static int netmap_mem_unmap(struct netmap_obj_pool *, struct netmap_adapter *); 315 static int nm_mem_check_group(struct netmap_mem_d *, void *); 316 static void nm_mem_release_id(struct netmap_mem_d *); 317 318 nm_memid_t 319 netmap_mem_get_id(struct netmap_mem_d *nmd) 320 { 321 return nmd->nm_id; 322 } 323 324 #ifdef NM_DEBUG_MEM_PUTGET 325 #define NM_DBG_REFC(nmd, func, line) \ 326 nm_prinf("%s:%d mem[%d:%d] -> %d", func, line, (nmd)->nm_id, (nmd)->nm_grp, (nmd)->refcount); 327 #else 328 #define NM_DBG_REFC(nmd, func, line) 329 #endif 330 331 /* circular list of all existing allocators */ 332 static struct netmap_mem_d *netmap_last_mem_d = &nm_mem; 333 static NM_MTX_T nm_mem_list_lock; 334 335 struct netmap_mem_d * 336 __netmap_mem_get(struct netmap_mem_d *nmd, const char *func, int line) 337 { 338 NM_MTX_LOCK(nm_mem_list_lock); 339 nmd->refcount++; 340 NM_DBG_REFC(nmd, func, line); 341 NM_MTX_UNLOCK(nm_mem_list_lock); 342 return nmd; 343 } 344 345 void 346 __netmap_mem_put(struct netmap_mem_d *nmd, const char *func, int line) 347 { 348 int last; 349 NM_MTX_LOCK(nm_mem_list_lock); 350 last = (--nmd->refcount == 0); 351 if (last) 352 nm_mem_release_id(nmd); 353 NM_DBG_REFC(nmd, func, line); 354 NM_MTX_UNLOCK(nm_mem_list_lock); 355 if (last) 356 netmap_mem_delete(nmd); 357 } 358 359 int 360 netmap_mem_finalize(struct netmap_mem_d *nmd, struct netmap_adapter *na) 361 { 362 int lasterr = 0; 363 if (nm_mem_check_group(nmd, na->pdev) < 0) { 364 return ENOMEM; 365 } 366 367 NMA_LOCK(nmd); 368 369 if (netmap_mem_config(nmd)) 370 goto out; 371 372 nmd->active++; 373 374 nmd->lasterr = nmd->ops->nmd_finalize(nmd, na); 375 376 if (!nmd->lasterr && !(nmd->flags & NETMAP_MEM_NOMAP)) { 377 nmd->lasterr = netmap_mem_map(&nmd->pools[NETMAP_BUF_POOL], na); 378 } 379 380 out: 381 lasterr = nmd->lasterr; 382 NMA_UNLOCK(nmd); 383 384 if (lasterr) 385 netmap_mem_deref(nmd, na); 386 387 return lasterr; 388 } 389 390 static int 391 nm_isset(uint32_t *bitmap, u_int i) 392 { 393 return bitmap[ (i>>5) ] & ( 1U << (i & 31U) ); 394 } 395 396 397 static int 398 netmap_init_obj_allocator_bitmap(struct netmap_obj_pool *p) 399 { 400 u_int n, j; 401 402 if (p->bitmap == NULL) { 403 /* Allocate the bitmap */ 404 n = (p->objtotal + 31) / 32; 405 p->bitmap = nm_os_malloc(sizeof(p->bitmap[0]) * n); 406 if (p->bitmap == NULL) { 407 nm_prerr("Unable to create bitmap (%d entries) for allocator '%s'", (int)n, 408 p->name); 409 return ENOMEM; 410 } 411 p->bitmap_slots = n; 412 } else { 413 memset(p->bitmap, 0, p->bitmap_slots * sizeof(p->bitmap[0])); 414 } 415 416 p->objfree = 0; 417 /* 418 * Set all the bits in the bitmap that have 419 * corresponding buffers to 1 to indicate they are 420 * free. 421 */ 422 for (j = 0; j < p->objtotal; j++) { 423 if (p->invalid_bitmap && nm_isset(p->invalid_bitmap, j)) { 424 if (netmap_debug & NM_DEBUG_MEM) 425 nm_prinf("skipping %s %d", p->name, j); 426 continue; 427 } 428 p->bitmap[ (j>>5) ] |= ( 1U << (j & 31U) ); 429 p->objfree++; 430 } 431 432 if (netmap_verbose) 433 nm_prinf("%s free %u", p->name, p->objfree); 434 if (p->objfree == 0) { 435 if (netmap_verbose) 436 nm_prerr("%s: no objects available", p->name); 437 return ENOMEM; 438 } 439 440 return 0; 441 } 442 443 static int 444 netmap_mem_init_bitmaps(struct netmap_mem_d *nmd) 445 { 446 int i, error = 0; 447 448 for (i = 0; i < NETMAP_POOLS_NR; i++) { 449 struct netmap_obj_pool *p = &nmd->pools[i]; 450 451 error = netmap_init_obj_allocator_bitmap(p); 452 if (error) 453 return error; 454 } 455 456 /* 457 * buffers 0 and 1 are reserved 458 */ 459 if (nmd->pools[NETMAP_BUF_POOL].objfree < 2) { 460 nm_prerr("%s: not enough buffers", nmd->pools[NETMAP_BUF_POOL].name); 461 return ENOMEM; 462 } 463 464 nmd->pools[NETMAP_BUF_POOL].objfree -= 2; 465 if (nmd->pools[NETMAP_BUF_POOL].bitmap) { 466 /* XXX This check is a workaround that prevents a 467 * NULL pointer crash which currently happens only 468 * with ptnetmap guests. 469 * Removed shared-info --> is the bug still there? */ 470 nmd->pools[NETMAP_BUF_POOL].bitmap[0] = ~3U; 471 } 472 return 0; 473 } 474 475 int 476 netmap_mem_deref(struct netmap_mem_d *nmd, struct netmap_adapter *na) 477 { 478 int last_user = 0; 479 NMA_LOCK(nmd); 480 if (na->active_fds <= 0 && !(nmd->flags & NETMAP_MEM_NOMAP)) 481 netmap_mem_unmap(&nmd->pools[NETMAP_BUF_POOL], na); 482 if (nmd->active == 1) { 483 last_user = 1; 484 /* 485 * Reset the allocator when it falls out of use so that any 486 * pool resources leaked by unclean application exits are 487 * reclaimed. 488 */ 489 netmap_mem_init_bitmaps(nmd); 490 } 491 nmd->ops->nmd_deref(nmd, na); 492 493 nmd->active--; 494 if (last_user) { 495 nmd->lasterr = 0; 496 } 497 498 NMA_UNLOCK(nmd); 499 return last_user; 500 } 501 502 503 /* accessor functions */ 504 static int 505 netmap_mem2_get_lut(struct netmap_mem_d *nmd, struct netmap_lut *lut) 506 { 507 lut->lut = nmd->pools[NETMAP_BUF_POOL].lut; 508 #ifdef __FreeBSD__ 509 lut->plut = lut->lut; 510 #endif 511 lut->objtotal = nmd->pools[NETMAP_BUF_POOL].objtotal; 512 lut->objsize = nmd->pools[NETMAP_BUF_POOL]._objsize; 513 514 return 0; 515 } 516 517 static struct netmap_obj_params netmap_min_priv_params[NETMAP_POOLS_NR] = { 518 [NETMAP_IF_POOL] = { 519 .size = 1024, 520 .num = 2, 521 }, 522 [NETMAP_RING_POOL] = { 523 .size = 5*PAGE_SIZE, 524 .num = 4, 525 }, 526 [NETMAP_BUF_POOL] = { 527 .size = 2048, 528 .num = 4098, 529 }, 530 }; 531 532 533 /* 534 * nm_mem is the memory allocator used for all physical interfaces 535 * running in netmap mode. 536 * Virtual (VALE) ports will have each its own allocator. 537 */ 538 extern const struct netmap_mem_ops netmap_mem_global_ops; /* forward */ 539 struct netmap_mem_d nm_mem = { /* Our memory allocator. */ 540 .pools = { 541 [NETMAP_IF_POOL] = { 542 .name = "netmap_if", 543 .objminsize = sizeof(struct netmap_if), 544 .objmaxsize = 4096, 545 .nummin = 10, /* don't be stingy */ 546 .nummax = 10000, /* XXX very large */ 547 }, 548 [NETMAP_RING_POOL] = { 549 .name = "netmap_ring", 550 .objminsize = sizeof(struct netmap_ring), 551 .objmaxsize = 32*PAGE_SIZE, 552 .nummin = 2, 553 .nummax = 1024, 554 }, 555 [NETMAP_BUF_POOL] = { 556 .name = "netmap_buf", 557 .objminsize = 64, 558 .objmaxsize = 65536, 559 .nummin = 4, 560 .nummax = 1000000, /* one million! */ 561 }, 562 }, 563 564 .params = { 565 [NETMAP_IF_POOL] = { 566 .size = 1024, 567 .num = 100, 568 }, 569 [NETMAP_RING_POOL] = { 570 .size = 9*PAGE_SIZE, 571 .num = 200, 572 }, 573 [NETMAP_BUF_POOL] = { 574 .size = 2048, 575 .num = NETMAP_BUF_MAX_NUM, 576 }, 577 }, 578 579 .nm_id = 1, 580 .nm_grp = -1, 581 .nm_numa_domain = -1, 582 583 .prev = &nm_mem, 584 .next = &nm_mem, 585 586 .ops = &netmap_mem_global_ops, 587 588 .name = "1" 589 }; 590 591 static struct netmap_mem_d nm_mem_blueprint; 592 593 /* blueprint for the private memory allocators */ 594 /* XXX clang is not happy about using name as a print format */ 595 static const struct netmap_mem_d nm_blueprint = { 596 .pools = { 597 [NETMAP_IF_POOL] = { 598 .name = "%s_if", 599 .objminsize = sizeof(struct netmap_if), 600 .objmaxsize = 4096, 601 .nummin = 1, 602 .nummax = 100, 603 }, 604 [NETMAP_RING_POOL] = { 605 .name = "%s_ring", 606 .objminsize = sizeof(struct netmap_ring), 607 .objmaxsize = 32*PAGE_SIZE, 608 .nummin = 2, 609 .nummax = 1024, 610 }, 611 [NETMAP_BUF_POOL] = { 612 .name = "%s_buf", 613 .objminsize = 64, 614 .objmaxsize = 65536, 615 .nummin = 4, 616 .nummax = 1000000, /* one million! */ 617 }, 618 }, 619 620 .nm_grp = -1, 621 .nm_numa_domain = -1, 622 623 .flags = NETMAP_MEM_PRIVATE, 624 625 .ops = &netmap_mem_global_ops, 626 }; 627 628 /* memory allocator related sysctls */ 629 630 #define STRINGIFY(x) #x 631 632 #define DECLARE_SYSCTLS(id, name) \ 633 SYSBEGIN(mem2_ ## name); \ 634 SYSCTL_INT(_dev_netmap, OID_AUTO, name##_size, \ 635 CTLFLAG_RWTUN, &nm_mem.params[id].size, 0, \ 636 "Requested size of netmap " STRINGIFY(name) "s"); \ 637 SYSCTL_INT(_dev_netmap, OID_AUTO, name##_curr_size, \ 638 CTLFLAG_RD, &nm_mem.pools[id]._objsize, 0, \ 639 "Current size of netmap " STRINGIFY(name) "s"); \ 640 SYSCTL_INT(_dev_netmap, OID_AUTO, name##_num, \ 641 CTLFLAG_RWTUN, &nm_mem.params[id].num, 0, \ 642 "Requested number of netmap " STRINGIFY(name) "s"); \ 643 SYSCTL_INT(_dev_netmap, OID_AUTO, name##_curr_num, \ 644 CTLFLAG_RD, &nm_mem.pools[id].objtotal, 0, \ 645 "Current number of netmap " STRINGIFY(name) "s"); \ 646 SYSCTL_INT(_dev_netmap, OID_AUTO, priv_##name##_size, \ 647 CTLFLAG_RWTUN, &netmap_min_priv_params[id].size, 0, \ 648 "Default size of private netmap " STRINGIFY(name) "s"); \ 649 SYSCTL_INT(_dev_netmap, OID_AUTO, priv_##name##_num, \ 650 CTLFLAG_RWTUN, &netmap_min_priv_params[id].num, 0, \ 651 "Default number of private netmap " STRINGIFY(name) "s"); \ 652 SYSEND 653 654 SYSCTL_DECL(_dev_netmap); 655 DECLARE_SYSCTLS(NETMAP_IF_POOL, if); 656 DECLARE_SYSCTLS(NETMAP_RING_POOL, ring); 657 DECLARE_SYSCTLS(NETMAP_BUF_POOL, buf); 658 659 int netmap_port_numa_affinity = 0; 660 SYSCTL_INT(_dev_netmap, OID_AUTO, port_numa_affinity, 661 CTLFLAG_RDTUN, &netmap_port_numa_affinity, 0, 662 "Use NUMA-local memory for memory pools when possible"); 663 664 /* call with nm_mem_list_lock held */ 665 static int 666 nm_mem_assign_id_locked(struct netmap_mem_d *nmd, int grp_id, int domain) 667 { 668 nm_memid_t id; 669 struct netmap_mem_d *scan = netmap_last_mem_d; 670 int error = ENOMEM; 671 672 do { 673 /* we rely on unsigned wrap around */ 674 id = scan->nm_id + 1; 675 if (id == 0) /* reserve 0 as error value */ 676 id = 1; 677 scan = scan->next; 678 if (id != scan->nm_id) { 679 nmd->nm_id = id; 680 nmd->nm_grp = grp_id; 681 nmd->nm_numa_domain = domain; 682 nmd->prev = scan->prev; 683 nmd->next = scan; 684 scan->prev->next = nmd; 685 scan->prev = nmd; 686 netmap_last_mem_d = nmd; 687 nmd->refcount = 1; 688 NM_DBG_REFC(nmd, __FUNCTION__, __LINE__); 689 error = 0; 690 break; 691 } 692 } while (scan != netmap_last_mem_d); 693 694 return error; 695 } 696 697 /* call with nm_mem_list_lock *not* held */ 698 static int 699 nm_mem_assign_id(struct netmap_mem_d *nmd, int grp_id) 700 { 701 int ret; 702 703 NM_MTX_LOCK(nm_mem_list_lock); 704 ret = nm_mem_assign_id_locked(nmd, grp_id, -1); 705 NM_MTX_UNLOCK(nm_mem_list_lock); 706 707 return ret; 708 } 709 710 /* call with nm_mem_list_lock held */ 711 static void 712 nm_mem_release_id(struct netmap_mem_d *nmd) 713 { 714 nmd->prev->next = nmd->next; 715 nmd->next->prev = nmd->prev; 716 717 if (netmap_last_mem_d == nmd) 718 netmap_last_mem_d = nmd->prev; 719 720 nmd->prev = nmd->next = NULL; 721 } 722 723 struct netmap_mem_d * 724 netmap_mem_find(nm_memid_t id) 725 { 726 struct netmap_mem_d *nmd; 727 728 NM_MTX_LOCK(nm_mem_list_lock); 729 nmd = netmap_last_mem_d; 730 do { 731 if (!(nmd->flags & NETMAP_MEM_HIDDEN) && nmd->nm_id == id) { 732 nmd->refcount++; 733 NM_DBG_REFC(nmd, __FUNCTION__, __LINE__); 734 NM_MTX_UNLOCK(nm_mem_list_lock); 735 return nmd; 736 } 737 nmd = nmd->next; 738 } while (nmd != netmap_last_mem_d); 739 NM_MTX_UNLOCK(nm_mem_list_lock); 740 return NULL; 741 } 742 743 static int 744 nm_mem_check_group(struct netmap_mem_d *nmd, void *dev) 745 { 746 int err = 0, id; 747 748 /* Skip not hw adapters. 749 * Vale port can use particular allocator through vale-ctl -m option 750 */ 751 if (!dev) 752 return 0; 753 id = nm_iommu_group_id(dev); 754 if (netmap_debug & NM_DEBUG_MEM) 755 nm_prinf("iommu_group %d", id); 756 757 NMA_LOCK(nmd); 758 759 if (nmd->nm_grp != id) { 760 if (netmap_verbose) 761 nm_prerr("iommu group mismatch: %d vs %d", 762 nmd->nm_grp, id); 763 nmd->lasterr = err = ENOMEM; 764 } 765 766 NMA_UNLOCK(nmd); 767 return err; 768 } 769 770 static struct lut_entry * 771 nm_alloc_lut(u_int nobj) 772 { 773 size_t n = sizeof(struct lut_entry) * nobj; 774 struct lut_entry *lut; 775 #ifdef linux 776 lut = vmalloc(n); 777 #else 778 lut = nm_os_malloc(n); 779 #endif 780 return lut; 781 } 782 783 static void 784 nm_free_lut(struct lut_entry *lut, u_int objtotal) 785 { 786 bzero(lut, sizeof(struct lut_entry) * objtotal); 787 #ifdef linux 788 vfree(lut); 789 #else 790 nm_os_free(lut); 791 #endif 792 } 793 794 #if defined(linux) || defined(_WIN32) 795 static struct plut_entry * 796 nm_alloc_plut(u_int nobj) 797 { 798 size_t n = sizeof(struct plut_entry) * nobj; 799 struct plut_entry *lut; 800 lut = vmalloc(n); 801 return lut; 802 } 803 804 static void 805 nm_free_plut(struct plut_entry * lut) 806 { 807 vfree(lut); 808 } 809 #endif /* linux or _WIN32 */ 810 811 812 /* 813 * First, find the allocator that contains the requested offset, 814 * then locate the cluster through a lookup table. 815 */ 816 static vm_paddr_t 817 netmap_mem2_ofstophys(struct netmap_mem_d* nmd, vm_ooffset_t offset) 818 { 819 int i; 820 vm_ooffset_t o = offset; 821 vm_paddr_t pa; 822 struct netmap_obj_pool *p; 823 824 p = nmd->pools; 825 826 for (i = 0; i < NETMAP_POOLS_NR; offset -= p[i].memtotal, i++) { 827 if (offset >= p[i].memtotal) 828 continue; 829 // now lookup the cluster's address 830 #ifndef _WIN32 831 pa = vtophys(p[i].lut[offset / p[i]._objsize].vaddr) + 832 offset % p[i]._objsize; 833 #else 834 pa = vtophys(p[i].lut[offset / p[i]._objsize].vaddr); 835 pa.QuadPart += offset % p[i]._objsize; 836 #endif 837 return pa; 838 } 839 /* this is only in case of errors */ 840 nm_prerr("invalid ofs 0x%x out of 0x%zx 0x%zx 0x%zx", (u_int)o, 841 p[NETMAP_IF_POOL].memtotal, 842 p[NETMAP_IF_POOL].memtotal 843 + p[NETMAP_RING_POOL].memtotal, 844 p[NETMAP_IF_POOL].memtotal 845 + p[NETMAP_RING_POOL].memtotal 846 + p[NETMAP_BUF_POOL].memtotal); 847 #ifndef _WIN32 848 return 0; /* bad address */ 849 #else 850 vm_paddr_t res; 851 res.QuadPart = 0; 852 return res; 853 #endif 854 } 855 856 #ifdef _WIN32 857 858 /* 859 * win32_build_virtual_memory_for_userspace 860 * 861 * This function get all the object making part of the pools and maps 862 * a contiguous virtual memory space for the userspace 863 * It works this way 864 * 1 - allocate a Memory Descriptor List wide as the sum 865 * of the memory needed for the pools 866 * 2 - cycle all the objects in every pool and for every object do 867 * 868 * 2a - cycle all the objects in every pool, get the list 869 * of the physical address descriptors 870 * 2b - calculate the offset in the array of pages descriptor in the 871 * main MDL 872 * 2c - copy the descriptors of the object in the main MDL 873 * 874 * 3 - return the resulting MDL that needs to be mapped in userland 875 * 876 * In this way we will have an MDL that describes all the memory for the 877 * objects in a single object 878 */ 879 880 PMDL 881 win32_build_user_vm_map(struct netmap_mem_d* nmd) 882 { 883 u_int memflags, ofs = 0; 884 PMDL mainMdl, tempMdl; 885 uint64_t memsize; 886 int i, j; 887 888 if (netmap_mem_get_info(nmd, &memsize, &memflags, NULL)) { 889 nm_prerr("memory not finalised yet"); 890 return NULL; 891 } 892 893 mainMdl = IoAllocateMdl(NULL, memsize, FALSE, FALSE, NULL); 894 if (mainMdl == NULL) { 895 nm_prerr("failed to allocate mdl"); 896 return NULL; 897 } 898 899 NMA_LOCK(nmd); 900 for (i = 0; i < NETMAP_POOLS_NR; i++) { 901 struct netmap_obj_pool *p = &nmd->pools[i]; 902 int clsz = p->_clustsize; 903 int clobjs = p->_clustentries; /* objects per cluster */ 904 int mdl_len = sizeof(PFN_NUMBER) * BYTES_TO_PAGES(clsz); 905 PPFN_NUMBER pSrc, pDst; 906 907 /* each pool has a different cluster size so we need to reallocate */ 908 tempMdl = IoAllocateMdl(p->lut[0].vaddr, clsz, FALSE, FALSE, NULL); 909 if (tempMdl == NULL) { 910 NMA_UNLOCK(nmd); 911 nm_prerr("fail to allocate tempMdl"); 912 IoFreeMdl(mainMdl); 913 return NULL; 914 } 915 pSrc = MmGetMdlPfnArray(tempMdl); 916 /* create one entry per cluster, the lut[] has one entry per object */ 917 for (j = 0; j < p->numclusters; j++, ofs += clsz) { 918 pDst = &MmGetMdlPfnArray(mainMdl)[BYTES_TO_PAGES(ofs)]; 919 MmInitializeMdl(tempMdl, p->lut[j*clobjs].vaddr, clsz); 920 MmBuildMdlForNonPagedPool(tempMdl); /* compute physical page addresses */ 921 RtlCopyMemory(pDst, pSrc, mdl_len); /* copy the page descriptors */ 922 mainMdl->MdlFlags = tempMdl->MdlFlags; /* XXX what is in here ? */ 923 } 924 IoFreeMdl(tempMdl); 925 } 926 NMA_UNLOCK(nmd); 927 return mainMdl; 928 } 929 930 #endif /* _WIN32 */ 931 932 /* 933 * helper function for OS-specific mmap routines (currently only windows). 934 * Given an nmd and a pool index, returns the cluster size and number of clusters. 935 * Returns 0 if memory is finalised and the pool is valid, otherwise 1. 936 * It should be called under NMA_LOCK(nmd) otherwise the underlying info can change. 937 */ 938 939 int 940 netmap_mem2_get_pool_info(struct netmap_mem_d* nmd, u_int pool, u_int *clustsize, u_int *numclusters) 941 { 942 if (!nmd || !clustsize || !numclusters || pool >= NETMAP_POOLS_NR) 943 return 1; /* invalid arguments */ 944 // NMA_LOCK_ASSERT(nmd); 945 if (!(nmd->flags & NETMAP_MEM_FINALIZED)) { 946 *clustsize = *numclusters = 0; 947 return 1; /* not ready yet */ 948 } 949 *clustsize = nmd->pools[pool]._clustsize; 950 *numclusters = nmd->pools[pool].numclusters; 951 return 0; /* success */ 952 } 953 954 static int 955 netmap_mem2_get_info(struct netmap_mem_d* nmd, uint64_t* size, 956 u_int *memflags, nm_memid_t *id) 957 { 958 int error = 0; 959 error = netmap_mem_config(nmd); 960 if (error) 961 goto out; 962 if (size) { 963 if (nmd->flags & NETMAP_MEM_FINALIZED) { 964 *size = nmd->nm_totalsize; 965 } else { 966 int i; 967 *size = 0; 968 for (i = 0; i < NETMAP_POOLS_NR; i++) { 969 struct netmap_obj_pool *p = nmd->pools + i; 970 *size += ((size_t)p->_numclusters * (size_t)p->_clustsize); 971 } 972 } 973 } 974 if (memflags) 975 *memflags = nmd->flags; 976 if (id) 977 *id = nmd->nm_id; 978 out: 979 return error; 980 } 981 982 /* 983 * we store objects by kernel address, need to find the offset 984 * within the pool to export the value to userspace. 985 * Algorithm: scan until we find the cluster, then add the 986 * actual offset in the cluster 987 */ 988 static ssize_t 989 netmap_obj_offset(struct netmap_obj_pool *p, const void *vaddr) 990 { 991 int i, k = p->_clustentries, n = p->objtotal; 992 ssize_t ofs = 0; 993 994 for (i = 0; i < n; i += k, ofs += p->_clustsize) { 995 const char *base = p->lut[i].vaddr; 996 ssize_t relofs = (const char *) vaddr - base; 997 998 if (relofs < 0 || relofs >= p->_clustsize) 999 continue; 1000 1001 ofs = ofs + relofs; 1002 nm_prdis("%s: return offset %d (cluster %d) for pointer %p", 1003 p->name, ofs, i, vaddr); 1004 return ofs; 1005 } 1006 nm_prerr("address %p is not contained inside any cluster (%s)", 1007 vaddr, p->name); 1008 return 0; /* An error occurred */ 1009 } 1010 1011 /* Helper functions which convert virtual addresses to offsets */ 1012 #define netmap_if_offset(n, v) \ 1013 netmap_obj_offset(&(n)->pools[NETMAP_IF_POOL], (v)) 1014 1015 #define netmap_ring_offset(n, v) \ 1016 ((n)->pools[NETMAP_IF_POOL].memtotal + \ 1017 netmap_obj_offset(&(n)->pools[NETMAP_RING_POOL], (v))) 1018 1019 static ssize_t 1020 netmap_mem2_if_offset(struct netmap_mem_d *nmd, const void *addr) 1021 { 1022 return netmap_if_offset(nmd, addr); 1023 } 1024 1025 /* 1026 * report the index, and use start position as a hint, 1027 * otherwise buffer allocation becomes terribly expensive. 1028 */ 1029 static void * 1030 netmap_obj_malloc(struct netmap_obj_pool *p, u_int len, uint32_t *start, uint32_t *index) 1031 { 1032 uint32_t i = 0; /* index in the bitmap */ 1033 uint32_t mask, j = 0; /* slot counter */ 1034 void *vaddr = NULL; 1035 1036 if (len > p->_objsize) { 1037 nm_prerr("%s request size %d too large", p->name, len); 1038 return NULL; 1039 } 1040 1041 if (p->objfree == 0) { 1042 nm_prerr("no more %s objects", p->name); 1043 return NULL; 1044 } 1045 if (start) 1046 i = *start; 1047 1048 /* termination is guaranteed by p->free, but better check bounds on i */ 1049 while (vaddr == NULL && i < p->bitmap_slots) { 1050 uint32_t cur = p->bitmap[i]; 1051 if (cur == 0) { /* bitmask is fully used */ 1052 i++; 1053 continue; 1054 } 1055 /* locate a slot */ 1056 for (j = 0, mask = 1; (cur & mask) == 0; j++, mask <<= 1) 1057 ; 1058 1059 p->bitmap[i] &= ~mask; /* mark object as in use */ 1060 p->objfree--; 1061 1062 vaddr = p->lut[i * 32 + j].vaddr; 1063 if (index) 1064 *index = i * 32 + j; 1065 } 1066 nm_prdis("%s allocator: allocated object @ [%d][%d]: vaddr %p",p->name, i, j, vaddr); 1067 1068 if (start) 1069 *start = i; 1070 return vaddr; 1071 } 1072 1073 1074 /* 1075 * free by index, not by address. 1076 * XXX should we also cleanup the content ? 1077 */ 1078 static int 1079 netmap_obj_free(struct netmap_obj_pool *p, uint32_t j) 1080 { 1081 uint32_t *ptr, mask; 1082 1083 if (j >= p->objtotal) { 1084 nm_prerr("invalid index %u, max %u", j, p->objtotal); 1085 return 1; 1086 } 1087 ptr = &p->bitmap[j / 32]; 1088 mask = (1 << (j % 32)); 1089 if (*ptr & mask) { 1090 nm_prerr("ouch, double free on buffer %d", j); 1091 return 1; 1092 } else { 1093 *ptr |= mask; 1094 p->objfree++; 1095 return 0; 1096 } 1097 } 1098 1099 /* 1100 * free by address. This is slow but is only used for a few 1101 * objects (rings, nifp) 1102 */ 1103 static void 1104 netmap_obj_free_va(struct netmap_obj_pool *p, void *vaddr) 1105 { 1106 u_int i, j, n = p->numclusters; 1107 1108 for (i = 0, j = 0; i < n; i++, j += p->_clustentries) { 1109 void *base = p->lut[i * p->_clustentries].vaddr; 1110 ssize_t relofs = (ssize_t) vaddr - (ssize_t) base; 1111 1112 /* Given address, is out of the scope of the current cluster.*/ 1113 if (base == NULL || vaddr < base || relofs >= p->_clustsize) 1114 continue; 1115 1116 j = j + relofs / p->_objsize; 1117 /* KASSERT(j != 0, ("Cannot free object 0")); */ 1118 netmap_obj_free(p, j); 1119 return; 1120 } 1121 nm_prerr("address %p is not contained inside any cluster (%s)", 1122 vaddr, p->name); 1123 } 1124 1125 unsigned 1126 netmap_mem_bufsize(struct netmap_mem_d *nmd) 1127 { 1128 return nmd->pools[NETMAP_BUF_POOL]._objsize; 1129 } 1130 1131 #define netmap_if_malloc(n, len) netmap_obj_malloc(&(n)->pools[NETMAP_IF_POOL], len, NULL, NULL) 1132 #define netmap_if_free(n, v) netmap_obj_free_va(&(n)->pools[NETMAP_IF_POOL], (v)) 1133 #define netmap_ring_malloc(n, len) netmap_obj_malloc(&(n)->pools[NETMAP_RING_POOL], len, NULL, NULL) 1134 #define netmap_ring_free(n, v) netmap_obj_free_va(&(n)->pools[NETMAP_RING_POOL], (v)) 1135 #define netmap_buf_malloc(n, _pos, _index) \ 1136 netmap_obj_malloc(&(n)->pools[NETMAP_BUF_POOL], netmap_mem_bufsize(n), _pos, _index) 1137 1138 1139 #if 0 /* currently unused */ 1140 /* Return the index associated to the given packet buffer */ 1141 #define netmap_buf_index(n, v) \ 1142 (netmap_obj_offset(&(n)->pools[NETMAP_BUF_POOL], (v)) / NETMAP_BDG_BUF_SIZE(n)) 1143 #endif 1144 1145 /* 1146 * allocate extra buffers in a linked list. 1147 * returns the actual number. 1148 */ 1149 uint32_t 1150 netmap_extra_alloc(struct netmap_adapter *na, uint32_t *head, uint32_t n) 1151 { 1152 struct netmap_mem_d *nmd = na->nm_mem; 1153 uint32_t i, pos = 0; /* opaque, scan position in the bitmap */ 1154 1155 NMA_LOCK(nmd); 1156 1157 *head = 0; /* default, 'null' index ie empty list */ 1158 for (i = 0 ; i < n; i++) { 1159 uint32_t cur = *head; /* save current head */ 1160 uint32_t *p = netmap_buf_malloc(nmd, &pos, head); 1161 if (p == NULL) { 1162 nm_prerr("no more buffers after %d of %d", i, n); 1163 *head = cur; /* restore */ 1164 break; 1165 } 1166 nm_prdis(5, "allocate buffer %d -> %d", *head, cur); 1167 *p = cur; /* link to previous head */ 1168 } 1169 1170 NMA_UNLOCK(nmd); 1171 1172 return i; 1173 } 1174 1175 static void 1176 netmap_extra_free(struct netmap_adapter *na, uint32_t head) 1177 { 1178 struct lut_entry *lut = na->na_lut.lut; 1179 struct netmap_mem_d *nmd = na->nm_mem; 1180 struct netmap_obj_pool *p = &nmd->pools[NETMAP_BUF_POOL]; 1181 uint32_t i, cur, *buf; 1182 1183 nm_prdis("freeing the extra list"); 1184 for (i = 0; head >=2 && head < p->objtotal; i++) { 1185 cur = head; 1186 buf = lut[head].vaddr; 1187 head = *buf; 1188 *buf = 0; 1189 if (netmap_obj_free(p, cur)) 1190 break; 1191 } 1192 if (head != 0) 1193 nm_prerr("breaking with head %d", head); 1194 if (netmap_debug & NM_DEBUG_MEM) 1195 nm_prinf("freed %d buffers", i); 1196 } 1197 1198 1199 /* Return nonzero on error */ 1200 static int 1201 netmap_new_bufs(struct netmap_mem_d *nmd, struct netmap_slot *slot, u_int n) 1202 { 1203 struct netmap_obj_pool *p = &nmd->pools[NETMAP_BUF_POOL]; 1204 u_int i = 0; /* slot counter */ 1205 uint32_t pos = 0; /* slot in p->bitmap */ 1206 uint32_t index = 0; /* buffer index */ 1207 1208 for (i = 0; i < n; i++) { 1209 void *vaddr = netmap_buf_malloc(nmd, &pos, &index); 1210 if (vaddr == NULL) { 1211 nm_prerr("no more buffers after %d of %d", i, n); 1212 goto cleanup; 1213 } 1214 slot[i].buf_idx = index; 1215 slot[i].len = p->_objsize; 1216 slot[i].flags = 0; 1217 slot[i].ptr = 0; 1218 } 1219 1220 nm_prdis("%s: allocated %d buffers, %d available, first at %d", p->name, n, p->objfree, pos); 1221 return (0); 1222 1223 cleanup: 1224 while (i > 0) { 1225 i--; 1226 netmap_obj_free(p, slot[i].buf_idx); 1227 } 1228 bzero(slot, n * sizeof(slot[0])); 1229 return (ENOMEM); 1230 } 1231 1232 static void 1233 netmap_mem_set_ring(struct netmap_mem_d *nmd, struct netmap_slot *slot, u_int n, uint32_t index) 1234 { 1235 struct netmap_obj_pool *p = &nmd->pools[NETMAP_BUF_POOL]; 1236 u_int i; 1237 1238 for (i = 0; i < n; i++) { 1239 slot[i].buf_idx = index; 1240 slot[i].len = p->_objsize; 1241 slot[i].flags = 0; 1242 } 1243 } 1244 1245 1246 static void 1247 netmap_free_buf(struct netmap_mem_d *nmd, uint32_t i) 1248 { 1249 struct netmap_obj_pool *p = &nmd->pools[NETMAP_BUF_POOL]; 1250 1251 if (i < 2 || i >= p->objtotal) { 1252 nm_prerr("Cannot free buf#%d: should be in [2, %d[", i, p->objtotal); 1253 return; 1254 } 1255 netmap_obj_free(p, i); 1256 } 1257 1258 1259 static void 1260 netmap_free_bufs(struct netmap_mem_d *nmd, struct netmap_slot *slot, u_int n) 1261 { 1262 u_int i; 1263 1264 for (i = 0; i < n; i++) { 1265 if (slot[i].buf_idx > 1) 1266 netmap_free_buf(nmd, slot[i].buf_idx); 1267 } 1268 nm_prdis("%s: released some buffers, available: %u", 1269 p->name, p->objfree); 1270 } 1271 1272 static void 1273 netmap_reset_obj_allocator(struct netmap_obj_pool *p) 1274 { 1275 1276 if (p == NULL) 1277 return; 1278 if (p->bitmap) 1279 nm_os_free(p->bitmap); 1280 p->bitmap = NULL; 1281 if (p->invalid_bitmap) 1282 nm_os_free(p->invalid_bitmap); 1283 p->invalid_bitmap = NULL; 1284 if (!p->alloc_done) { 1285 /* allocation was done by somebody else. 1286 * Let them clean up after themselves. 1287 */ 1288 return; 1289 } 1290 if (p->lut) { 1291 u_int i; 1292 1293 /* 1294 * Free each cluster allocated in 1295 * netmap_finalize_obj_allocator(). The cluster start 1296 * addresses are stored at multiples of p->_clusterentries 1297 * in the lut. 1298 */ 1299 for (i = 0; i < p->objtotal; i += p->_clustentries) { 1300 free(p->lut[i].vaddr, M_NETMAP); 1301 } 1302 nm_free_lut(p->lut, p->objtotal); 1303 } 1304 p->lut = NULL; 1305 p->objtotal = 0; 1306 p->memtotal = 0; 1307 p->numclusters = 0; 1308 p->objfree = 0; 1309 p->alloc_done = 0; 1310 } 1311 1312 /* 1313 * Free all resources related to an allocator. 1314 */ 1315 static void 1316 netmap_destroy_obj_allocator(struct netmap_obj_pool *p) 1317 { 1318 if (p == NULL) 1319 return; 1320 netmap_reset_obj_allocator(p); 1321 } 1322 1323 /* 1324 * We receive a request for objtotal objects, of size objsize each. 1325 * Internally we may round up both numbers, as we allocate objects 1326 * in small clusters multiple of the page size. 1327 * We need to keep track of objtotal and clustentries, 1328 * as they are needed when freeing memory. 1329 * 1330 * XXX note -- userspace needs the buffers to be contiguous, 1331 * so we cannot afford gaps at the end of a cluster. 1332 */ 1333 1334 1335 /* call with NMA_LOCK held */ 1336 static int 1337 netmap_config_obj_allocator(struct netmap_obj_pool *p, u_int objtotal, u_int objsize) 1338 { 1339 int i; 1340 u_int clustsize; /* the cluster size, multiple of page size */ 1341 u_int clustentries; /* how many objects per entry */ 1342 1343 /* we store the current request, so we can 1344 * detect configuration changes later */ 1345 p->r_objtotal = objtotal; 1346 p->r_objsize = objsize; 1347 1348 #define MAX_CLUSTSIZE (1<<22) // 4 MB 1349 #define LINE_ROUND NM_BUF_ALIGN // 64 1350 if (objsize >= MAX_CLUSTSIZE) { 1351 /* we could do it but there is no point */ 1352 nm_prerr("unsupported allocation for %d bytes", objsize); 1353 return EINVAL; 1354 } 1355 /* make sure objsize is a multiple of LINE_ROUND */ 1356 i = (objsize & (LINE_ROUND - 1)); 1357 if (i) { 1358 nm_prinf("aligning object by %d bytes", LINE_ROUND - i); 1359 objsize += LINE_ROUND - i; 1360 } 1361 if (objsize < p->objminsize || objsize > p->objmaxsize) { 1362 nm_prerr("requested objsize %d out of range [%d, %d]", 1363 objsize, p->objminsize, p->objmaxsize); 1364 return EINVAL; 1365 } 1366 if (objtotal < p->nummin || objtotal > p->nummax) { 1367 nm_prerr("requested objtotal %d out of range [%d, %d]", 1368 objtotal, p->nummin, p->nummax); 1369 return EINVAL; 1370 } 1371 /* 1372 * Compute number of objects using a brute-force approach: 1373 * given a max cluster size, 1374 * we try to fill it with objects keeping track of the 1375 * wasted space to the next page boundary. 1376 */ 1377 for (clustentries = 0, i = 1;; i++) { 1378 u_int delta, used = i * objsize; 1379 if (used > MAX_CLUSTSIZE) 1380 break; 1381 delta = used % PAGE_SIZE; 1382 if (delta == 0) { // exact solution 1383 clustentries = i; 1384 break; 1385 } 1386 } 1387 /* exact solution not found */ 1388 if (clustentries == 0) { 1389 nm_prerr("unsupported allocation for %d bytes", objsize); 1390 return EINVAL; 1391 } 1392 /* compute clustsize */ 1393 clustsize = clustentries * objsize; 1394 if (netmap_debug & NM_DEBUG_MEM) 1395 nm_prinf("objsize %d clustsize %d objects %d", 1396 objsize, clustsize, clustentries); 1397 1398 /* 1399 * The number of clusters is n = ceil(objtotal/clustentries) 1400 * objtotal' = n * clustentries 1401 */ 1402 p->_clustentries = clustentries; 1403 p->_clustsize = clustsize; 1404 p->_numclusters = (objtotal + clustentries - 1) / clustentries; 1405 1406 /* actual values (may be larger than requested) */ 1407 p->_objsize = objsize; 1408 p->_objtotal = p->_numclusters * clustentries; 1409 1410 return 0; 1411 } 1412 1413 /* call with NMA_LOCK held */ 1414 static int 1415 netmap_finalize_obj_allocator(struct netmap_mem_d *nmd, struct netmap_obj_pool *p) 1416 { 1417 int i; /* must be signed */ 1418 1419 if (p->lut) { 1420 /* if the lut is already there we assume that also all the 1421 * clusters have already been allocated, possibly by somebody 1422 * else (e.g., extmem). In the latter case, the alloc_done flag 1423 * will remain at zero, so that we will not attempt to 1424 * deallocate the clusters by ourselves in 1425 * netmap_reset_obj_allocator. 1426 */ 1427 return 0; 1428 } 1429 1430 /* optimistically assume we have enough memory */ 1431 p->numclusters = p->_numclusters; 1432 p->objtotal = p->_objtotal; 1433 p->alloc_done = 1; 1434 1435 p->lut = nm_alloc_lut(p->objtotal); 1436 if (p->lut == NULL) { 1437 nm_prerr("Unable to create lookup table for '%s'", p->name); 1438 goto clean; 1439 } 1440 1441 /* 1442 * Allocate clusters, init pointers 1443 */ 1444 1445 for (i = 0; i < (int)p->objtotal;) { 1446 int lim = i + p->_clustentries; 1447 char *clust; 1448 1449 /* 1450 * XXX Note, we only need contigmalloc() for buffers attached 1451 * to native interfaces. In all other cases (nifp, netmap rings 1452 * and even buffers for VALE ports or emulated interfaces) we 1453 * can live with standard malloc, because the hardware will not 1454 * access the pages directly. 1455 */ 1456 if (nmd->nm_numa_domain == -1) { 1457 clust = contigmalloc(p->_clustsize, M_NETMAP, 1458 M_NOWAIT | M_ZERO, (size_t)0, -1UL, PAGE_SIZE, 0); 1459 } else { 1460 struct domainset *ds; 1461 1462 ds = DOMAINSET_PREF(nmd->nm_numa_domain); 1463 clust = contigmalloc_domainset(p->_clustsize, M_NETMAP, 1464 ds, M_NOWAIT | M_ZERO, (size_t)0, -1UL, PAGE_SIZE, 0); 1465 } 1466 if (clust == NULL) { 1467 /* 1468 * If we get here, there is a severe memory shortage, 1469 * so halve the allocated memory to reclaim some. 1470 */ 1471 nm_prerr("Unable to create cluster at %d for '%s' allocator", 1472 i, p->name); 1473 if (i < 2) /* nothing to halve */ 1474 goto out; 1475 lim = i / 2; 1476 for (i--; i >= lim; i--) { 1477 if (i % p->_clustentries == 0 && p->lut[i].vaddr) 1478 free(p->lut[i].vaddr, M_NETMAP); 1479 p->lut[i].vaddr = NULL; 1480 } 1481 out: 1482 p->objtotal = i; 1483 /* we may have stopped in the middle of a cluster */ 1484 p->numclusters = (i + p->_clustentries - 1) / p->_clustentries; 1485 break; 1486 } 1487 /* 1488 * Set lut state for all buffers in the current cluster. 1489 * 1490 * [i, lim) is the set of buffer indexes that cover the 1491 * current cluster. 1492 * 1493 * 'clust' is really the address of the current buffer in 1494 * the current cluster as we index through it with a stride 1495 * of p->_objsize. 1496 */ 1497 for (; i < lim; i++, clust += p->_objsize) { 1498 p->lut[i].vaddr = clust; 1499 #if !defined(linux) && !defined(_WIN32) 1500 p->lut[i].paddr = vtophys(clust); 1501 #endif 1502 } 1503 } 1504 p->memtotal = (size_t)p->numclusters * (size_t)p->_clustsize; 1505 if (netmap_verbose) 1506 nm_prinf("Pre-allocated %d clusters (%d/%zuKB) for '%s'", 1507 p->numclusters, p->_clustsize >> 10, 1508 p->memtotal >> 10, p->name); 1509 1510 return 0; 1511 1512 clean: 1513 netmap_reset_obj_allocator(p); 1514 return ENOMEM; 1515 } 1516 1517 /* call with lock held */ 1518 static int 1519 netmap_mem_params_changed(struct netmap_obj_params* p) 1520 { 1521 int i, rv = 0; 1522 1523 for (i = 0; i < NETMAP_POOLS_NR; i++) { 1524 if (p[i].last_size != p[i].size || p[i].last_num != p[i].num) { 1525 p[i].last_size = p[i].size; 1526 p[i].last_num = p[i].num; 1527 rv = 1; 1528 } 1529 } 1530 return rv; 1531 } 1532 1533 static void 1534 netmap_mem_reset_all(struct netmap_mem_d *nmd) 1535 { 1536 int i; 1537 1538 if (netmap_debug & NM_DEBUG_MEM) 1539 nm_prinf("resetting %p", nmd); 1540 for (i = 0; i < NETMAP_POOLS_NR; i++) { 1541 netmap_reset_obj_allocator(&nmd->pools[i]); 1542 } 1543 nmd->flags &= ~NETMAP_MEM_FINALIZED; 1544 } 1545 1546 static int 1547 netmap_mem_unmap(struct netmap_obj_pool *p, struct netmap_adapter *na) 1548 { 1549 int i, lim = p->objtotal; 1550 struct netmap_lut *lut; 1551 if (na == NULL || na->pdev == NULL) 1552 return 0; 1553 1554 lut = &na->na_lut; 1555 1556 1557 1558 #if defined(__FreeBSD__) 1559 /* On FreeBSD mapping and unmapping is performed by the txsync 1560 * and rxsync routine, packet by packet. */ 1561 (void)i; 1562 (void)lim; 1563 (void)lut; 1564 #elif defined(_WIN32) 1565 (void)i; 1566 (void)lim; 1567 (void)lut; 1568 nm_prerr("unsupported on Windows"); 1569 #else /* linux */ 1570 nm_prdis("unmapping and freeing plut for %s", na->name); 1571 if (lut->plut == NULL || na->pdev == NULL) 1572 return 0; 1573 for (i = 0; i < lim; i += p->_clustentries) { 1574 if (lut->plut[i].paddr) 1575 netmap_unload_map(na, (bus_dma_tag_t) na->pdev, &lut->plut[i].paddr, p->_clustsize); 1576 } 1577 nm_free_plut(lut->plut); 1578 lut->plut = NULL; 1579 #endif /* linux */ 1580 1581 return 0; 1582 } 1583 1584 static int 1585 netmap_mem_map(struct netmap_obj_pool *p, struct netmap_adapter *na) 1586 { 1587 int error = 0; 1588 int i, lim = p->objtotal; 1589 struct netmap_lut *lut = &na->na_lut; 1590 1591 if (na->pdev == NULL) 1592 return 0; 1593 1594 #if defined(__FreeBSD__) 1595 /* On FreeBSD mapping and unmapping is performed by the txsync 1596 * and rxsync routine, packet by packet. */ 1597 (void)i; 1598 (void)lim; 1599 (void)lut; 1600 #elif defined(_WIN32) 1601 (void)i; 1602 (void)lim; 1603 (void)lut; 1604 nm_prerr("unsupported on Windows"); 1605 #else /* linux */ 1606 1607 if (lut->plut != NULL) { 1608 nm_prdis("plut already allocated for %s", na->name); 1609 return 0; 1610 } 1611 1612 nm_prdis("allocating physical lut for %s", na->name); 1613 lut->plut = nm_alloc_plut(lim); 1614 if (lut->plut == NULL) { 1615 nm_prerr("Failed to allocate physical lut for %s", na->name); 1616 return ENOMEM; 1617 } 1618 1619 for (i = 0; i < lim; i += p->_clustentries) { 1620 lut->plut[i].paddr = 0; 1621 } 1622 1623 for (i = 0; i < lim; i += p->_clustentries) { 1624 int j; 1625 1626 if (p->lut[i].vaddr == NULL) 1627 continue; 1628 1629 error = netmap_load_map(na, (bus_dma_tag_t) na->pdev, &lut->plut[i].paddr, 1630 p->lut[i].vaddr, p->_clustsize); 1631 if (error) { 1632 nm_prerr("Failed to map cluster #%d from the %s pool", i, p->name); 1633 break; 1634 } 1635 1636 for (j = 1; j < p->_clustentries; j++) { 1637 lut->plut[i + j].paddr = lut->plut[i + j - 1].paddr + p->_objsize; 1638 } 1639 } 1640 1641 if (error) 1642 netmap_mem_unmap(p, na); 1643 1644 #endif /* linux */ 1645 1646 return error; 1647 } 1648 1649 static int 1650 netmap_mem_finalize_all(struct netmap_mem_d *nmd) 1651 { 1652 int i; 1653 if (nmd->flags & NETMAP_MEM_FINALIZED) 1654 return 0; 1655 nmd->lasterr = 0; 1656 nmd->nm_totalsize = 0; 1657 for (i = 0; i < NETMAP_POOLS_NR; i++) { 1658 nmd->lasterr = netmap_finalize_obj_allocator(nmd, &nmd->pools[i]); 1659 if (nmd->lasterr) 1660 goto error; 1661 nmd->nm_totalsize += nmd->pools[i].memtotal; 1662 } 1663 nmd->nm_totalsize = (nmd->nm_totalsize + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); 1664 nmd->lasterr = netmap_mem_init_bitmaps(nmd); 1665 if (nmd->lasterr) 1666 goto error; 1667 1668 nmd->flags |= NETMAP_MEM_FINALIZED; 1669 1670 if (netmap_verbose) 1671 nm_prinf("interfaces %zd KB, rings %zd KB, buffers %zd MB", 1672 nmd->pools[NETMAP_IF_POOL].memtotal >> 10, 1673 nmd->pools[NETMAP_RING_POOL].memtotal >> 10, 1674 nmd->pools[NETMAP_BUF_POOL].memtotal >> 20); 1675 1676 if (netmap_verbose) 1677 nm_prinf("Free buffers: %d", nmd->pools[NETMAP_BUF_POOL].objfree); 1678 1679 1680 return 0; 1681 error: 1682 netmap_mem_reset_all(nmd); 1683 return nmd->lasterr; 1684 } 1685 1686 /* 1687 * allocator for private memory 1688 */ 1689 static void * 1690 _netmap_mem_private_new(size_t size, struct netmap_obj_params *p, int grp_id, 1691 const struct netmap_mem_ops *ops, uint64_t memtotal, int *perr) 1692 { 1693 struct netmap_mem_d *d = NULL; 1694 int i, err = 0; 1695 int checksz = 0; 1696 1697 /* if memtotal is !=0 we check that the request fits the available 1698 * memory. Moreover, any surprlus memory is assigned to buffers. 1699 */ 1700 checksz = (memtotal > 0); 1701 1702 d = nm_os_malloc(size); 1703 if (d == NULL) { 1704 err = ENOMEM; 1705 goto error; 1706 } 1707 1708 *d = nm_blueprint; 1709 d->ops = ops; 1710 1711 err = nm_mem_assign_id(d, grp_id); 1712 if (err) 1713 goto error_free; 1714 snprintf(d->name, NM_MEM_NAMESZ, "%d", d->nm_id); 1715 1716 for (i = 0; i < NETMAP_POOLS_NR; i++) { 1717 snprintf(d->pools[i].name, NETMAP_POOL_MAX_NAMSZ, 1718 nm_blueprint.pools[i].name, 1719 d->name); 1720 if (checksz) { 1721 uint64_t poolsz = (uint64_t)p[i].num * p[i].size; 1722 if (memtotal < poolsz) { 1723 nm_prerr("%s: request too large", d->pools[i].name); 1724 err = ENOMEM; 1725 goto error_rel_id; 1726 } 1727 memtotal -= poolsz; 1728 } 1729 d->params[i].num = p[i].num; 1730 d->params[i].size = p[i].size; 1731 } 1732 if (checksz && memtotal > 0) { 1733 uint64_t sz = d->params[NETMAP_BUF_POOL].size; 1734 uint64_t n = (memtotal + sz - 1) / sz; 1735 1736 if (n) { 1737 if (netmap_verbose) { 1738 nm_prinf("%s: adding %llu more buffers", 1739 d->pools[NETMAP_BUF_POOL].name, 1740 (unsigned long long)n); 1741 } 1742 d->params[NETMAP_BUF_POOL].num += n; 1743 } 1744 } 1745 1746 NMA_LOCK_INIT(d); 1747 1748 err = netmap_mem_config(d); 1749 if (err) 1750 goto error_destroy_lock; 1751 1752 d->flags &= ~NETMAP_MEM_FINALIZED; 1753 1754 return d; 1755 1756 error_destroy_lock: 1757 NMA_LOCK_DESTROY(d); 1758 error_rel_id: 1759 nm_mem_release_id(d); 1760 error_free: 1761 nm_os_free(d); 1762 error: 1763 if (perr) 1764 *perr = err; 1765 return NULL; 1766 } 1767 1768 struct netmap_mem_d * 1769 netmap_mem_private_new(u_int txr, u_int txd, u_int rxr, u_int rxd, 1770 u_int extra_bufs, u_int npipes, int *perr) 1771 { 1772 struct netmap_mem_d *d = NULL; 1773 struct netmap_obj_params p[NETMAP_POOLS_NR]; 1774 int i; 1775 u_int v, maxd; 1776 /* account for the fake host rings */ 1777 txr++; 1778 rxr++; 1779 1780 /* copy the min values */ 1781 for (i = 0; i < NETMAP_POOLS_NR; i++) { 1782 p[i] = netmap_min_priv_params[i]; 1783 } 1784 1785 /* possibly increase them to fit user request */ 1786 v = sizeof(struct netmap_if) + sizeof(ssize_t) * (txr + rxr); 1787 if (p[NETMAP_IF_POOL].size < v) 1788 p[NETMAP_IF_POOL].size = v; 1789 v = 2 + 4 * npipes; 1790 if (p[NETMAP_IF_POOL].num < v) 1791 p[NETMAP_IF_POOL].num = v; 1792 maxd = (txd > rxd) ? txd : rxd; 1793 v = sizeof(struct netmap_ring) + sizeof(struct netmap_slot) * maxd; 1794 if (p[NETMAP_RING_POOL].size < v) 1795 p[NETMAP_RING_POOL].size = v; 1796 /* each pipe endpoint needs two tx rings (1 normal + 1 host, fake) 1797 * and two rx rings (again, 1 normal and 1 fake host) 1798 */ 1799 v = txr + rxr + 8 * npipes; 1800 if (p[NETMAP_RING_POOL].num < v) 1801 p[NETMAP_RING_POOL].num = v; 1802 /* for each pipe we only need the buffers for the 4 "real" rings. 1803 * On the other end, the pipe ring dimension may be different from 1804 * the parent port ring dimension. As a compromise, we allocate twice the 1805 * space actually needed if the pipe rings were the same size as the parent rings 1806 */ 1807 v = (4 * npipes + rxr) * rxd + (4 * npipes + txr) * txd + 2 + extra_bufs; 1808 /* the +2 is for the tx and rx fake buffers (indices 0 and 1) */ 1809 if (p[NETMAP_BUF_POOL].num < v) 1810 p[NETMAP_BUF_POOL].num = v; 1811 1812 if (netmap_verbose) 1813 nm_prinf("req if %d*%d ring %d*%d buf %d*%d", 1814 p[NETMAP_IF_POOL].num, 1815 p[NETMAP_IF_POOL].size, 1816 p[NETMAP_RING_POOL].num, 1817 p[NETMAP_RING_POOL].size, 1818 p[NETMAP_BUF_POOL].num, 1819 p[NETMAP_BUF_POOL].size); 1820 1821 d = _netmap_mem_private_new(sizeof(*d), p, -1, &netmap_mem_global_ops, 0, perr); 1822 1823 return d; 1824 } 1825 1826 /* Reference IOMMU and NUMA local allocator - find existing or create new, 1827 * for non-hw adapters, fall back to global allocator. 1828 */ 1829 struct netmap_mem_d * 1830 netmap_mem_get_allocator(struct netmap_adapter *na) 1831 { 1832 int i, domain, err, grp_id; 1833 struct netmap_mem_d *nmd; 1834 1835 if (na == NULL || na->pdev == NULL) 1836 return netmap_mem_get(&nm_mem); 1837 1838 domain = nm_numa_domain(na->pdev); 1839 grp_id = nm_iommu_group_id(na->pdev); 1840 1841 NM_MTX_LOCK(nm_mem_list_lock); 1842 nmd = netmap_last_mem_d; 1843 do { 1844 if (!(nmd->flags & NETMAP_MEM_HIDDEN) && 1845 nmd->nm_grp == grp_id && nmd->nm_numa_domain == domain) { 1846 nmd->refcount++; 1847 NM_DBG_REFC(nmd, __FUNCTION__, __LINE__); 1848 NM_MTX_UNLOCK(nm_mem_list_lock); 1849 return nmd; 1850 } 1851 nmd = nmd->next; 1852 } while (nmd != netmap_last_mem_d); 1853 1854 nmd = nm_os_malloc(sizeof(*nmd)); 1855 if (nmd == NULL) 1856 goto error; 1857 1858 *nmd = nm_mem_blueprint; 1859 1860 err = nm_mem_assign_id_locked(nmd, grp_id, domain); 1861 if (err) 1862 goto error_free; 1863 1864 snprintf(nmd->name, sizeof(nmd->name), "%d", nmd->nm_id); 1865 1866 for (i = 0; i < NETMAP_POOLS_NR; i++) { 1867 snprintf(nmd->pools[i].name, NETMAP_POOL_MAX_NAMSZ, "%s-%s", 1868 nm_mem_blueprint.pools[i].name, nmd->name); 1869 } 1870 1871 NMA_LOCK_INIT(nmd); 1872 1873 NM_MTX_UNLOCK(nm_mem_list_lock); 1874 return nmd; 1875 1876 error_free: 1877 nm_os_free(nmd); 1878 error: 1879 NM_MTX_UNLOCK(nm_mem_list_lock); 1880 return NULL; 1881 } 1882 1883 /* call with lock held */ 1884 static int 1885 netmap_mem2_config(struct netmap_mem_d *nmd) 1886 { 1887 int i; 1888 1889 if (!netmap_mem_params_changed(nmd->params)) 1890 goto out; 1891 1892 nm_prdis("reconfiguring"); 1893 1894 if (nmd->flags & NETMAP_MEM_FINALIZED) { 1895 /* reset previous allocation */ 1896 for (i = 0; i < NETMAP_POOLS_NR; i++) { 1897 netmap_reset_obj_allocator(&nmd->pools[i]); 1898 } 1899 nmd->flags &= ~NETMAP_MEM_FINALIZED; 1900 } 1901 1902 for (i = 0; i < NETMAP_POOLS_NR; i++) { 1903 nmd->lasterr = netmap_config_obj_allocator(&nmd->pools[i], 1904 nmd->params[i].num, nmd->params[i].size); 1905 if (nmd->lasterr) 1906 goto out; 1907 } 1908 1909 out: 1910 1911 return nmd->lasterr; 1912 } 1913 1914 static int 1915 netmap_mem2_finalize(struct netmap_mem_d *nmd, struct netmap_adapter *na) 1916 { 1917 if (nmd->flags & NETMAP_MEM_FINALIZED) 1918 goto out; 1919 1920 if (netmap_mem_finalize_all(nmd)) 1921 goto out; 1922 1923 nmd->lasterr = 0; 1924 1925 out: 1926 return nmd->lasterr; 1927 } 1928 1929 static void 1930 netmap_mem2_delete(struct netmap_mem_d *nmd) 1931 { 1932 int i; 1933 1934 for (i = 0; i < NETMAP_POOLS_NR; i++) { 1935 netmap_destroy_obj_allocator(&nmd->pools[i]); 1936 } 1937 1938 NMA_LOCK_DESTROY(nmd); 1939 if (nmd != &nm_mem) 1940 nm_os_free(nmd); 1941 } 1942 1943 #ifdef WITH_EXTMEM 1944 /* doubly linekd list of all existing external allocators */ 1945 static struct netmap_mem_ext *netmap_mem_ext_list = NULL; 1946 NM_MTX_T nm_mem_ext_list_lock; 1947 #endif /* WITH_EXTMEM */ 1948 1949 int 1950 netmap_mem_init(void) 1951 { 1952 nm_mem_blueprint = nm_mem; 1953 NM_MTX_INIT(nm_mem_list_lock); 1954 NMA_LOCK_INIT(&nm_mem); 1955 netmap_mem_get(&nm_mem); 1956 #ifdef WITH_EXTMEM 1957 NM_MTX_INIT(nm_mem_ext_list_lock); 1958 #endif /* WITH_EXTMEM */ 1959 return (0); 1960 } 1961 1962 void 1963 netmap_mem_fini(void) 1964 { 1965 netmap_mem_put(&nm_mem); 1966 } 1967 1968 static int 1969 netmap_mem_ring_needed(struct netmap_kring *kring) 1970 { 1971 return kring->ring == NULL && 1972 (kring->users > 0 || 1973 (kring->nr_kflags & NKR_NEEDRING)); 1974 } 1975 1976 static int 1977 netmap_mem_ring_todelete(struct netmap_kring *kring) 1978 { 1979 return kring->ring != NULL && 1980 kring->users == 0 && 1981 !(kring->nr_kflags & NKR_NEEDRING); 1982 } 1983 1984 1985 /* call with NMA_LOCK held * 1986 * 1987 * Allocate netmap rings and buffers for this card 1988 * The rings are contiguous, but have variable size. 1989 * The kring array must follow the layout described 1990 * in netmap_krings_create(). 1991 */ 1992 static int 1993 netmap_mem2_rings_create(struct netmap_mem_d *nmd, struct netmap_adapter *na) 1994 { 1995 enum txrx t; 1996 int error; 1997 1998 for_rx_tx(t) { 1999 u_int i; 2000 2001 for (i = 0; i < netmap_all_rings(na, t); i++) { 2002 struct netmap_kring *kring = NMR(na, t)[i]; 2003 struct netmap_ring *ring = kring->ring; 2004 u_int len, ndesc; 2005 2006 if (!netmap_mem_ring_needed(kring)) { 2007 /* unneeded, or already created by somebody else */ 2008 if (netmap_debug & NM_DEBUG_MEM) 2009 nm_prinf("NOT creating ring %s (ring %p, users %d neekring %d)", 2010 kring->name, ring, kring->users, kring->nr_kflags & NKR_NEEDRING); 2011 continue; 2012 } 2013 if (netmap_debug & NM_DEBUG_MEM) 2014 nm_prinf("creating %s", kring->name); 2015 ndesc = kring->nkr_num_slots; 2016 if (ndesc >= UINT_MAX / sizeof(struct netmap_slot)) { 2017 error = EINVAL; 2018 goto cleanup; 2019 } 2020 len = ndesc * sizeof(struct netmap_slot); 2021 if (len + sizeof(struct netmap_ring) < len) { 2022 error = EINVAL; 2023 goto cleanup; 2024 } 2025 len += sizeof(struct netmap_ring); 2026 ring = netmap_ring_malloc(nmd, len); 2027 if (ring == NULL) { 2028 nm_prerr("Cannot allocate %s_ring", nm_txrx2str(t)); 2029 error = ENOMEM; 2030 goto cleanup; 2031 } 2032 nm_prdis("txring at %p", ring); 2033 kring->ring = ring; 2034 *(uint32_t *)(uintptr_t)&ring->num_slots = ndesc; 2035 *(int64_t *)(uintptr_t)&ring->buf_ofs = 2036 (nmd->pools[NETMAP_IF_POOL].memtotal + 2037 nmd->pools[NETMAP_RING_POOL].memtotal) - 2038 netmap_ring_offset(nmd, ring); 2039 2040 /* copy values from kring */ 2041 ring->head = kring->rhead; 2042 ring->cur = kring->rcur; 2043 ring->tail = kring->rtail; 2044 *(uint32_t *)(uintptr_t)&ring->nr_buf_size = 2045 netmap_mem_bufsize(nmd); 2046 nm_prdis("%s h %d c %d t %d", kring->name, 2047 ring->head, ring->cur, ring->tail); 2048 nm_prdis("initializing slots for %s_ring", nm_txrx2str(t)); 2049 if (!(kring->nr_kflags & NKR_FAKERING)) { 2050 /* this is a real ring */ 2051 if (netmap_debug & NM_DEBUG_MEM) 2052 nm_prinf("allocating buffers for %s", kring->name); 2053 if (netmap_new_bufs(nmd, ring->slot, ndesc)) { 2054 nm_prerr( 2055 "Cannot allocate buffers for %s_ring", 2056 nm_txrx2str(t)); 2057 error = ENOMEM; 2058 goto cleanup; 2059 } 2060 } else { 2061 /* this is a fake ring, set all indices to 0 */ 2062 if (netmap_debug & NM_DEBUG_MEM) 2063 nm_prinf("NOT allocating buffers for %s", kring->name); 2064 netmap_mem_set_ring(nmd, ring->slot, ndesc, 0); 2065 } 2066 /* ring info */ 2067 *(uint16_t *)(uintptr_t)&ring->ringid = kring->ring_id; 2068 *(uint16_t *)(uintptr_t)&ring->dir = kring->tx; 2069 } 2070 } 2071 2072 return 0; 2073 2074 cleanup: 2075 /* we cannot actually cleanup here, since we don't own kring->users 2076 * and kring->nr_klags & NKR_NEEDRING. The caller must decrement 2077 * the first or zero-out the second, then call netmap_free_rings() 2078 * to do the cleanup 2079 */ 2080 2081 return error; 2082 } 2083 2084 static void 2085 netmap_mem2_rings_delete(struct netmap_mem_d *nmd, struct netmap_adapter *na) 2086 { 2087 enum txrx t; 2088 2089 for_rx_tx(t) { 2090 u_int i; 2091 for (i = 0; i < netmap_all_rings(na, t); i++) { 2092 struct netmap_kring *kring = NMR(na, t)[i]; 2093 struct netmap_ring *ring = kring->ring; 2094 2095 if (!netmap_mem_ring_todelete(kring)) { 2096 if (netmap_debug & NM_DEBUG_MEM) 2097 nm_prinf("NOT deleting ring %s (ring %p, users %d neekring %d)", 2098 kring->name, ring, kring->users, kring->nr_kflags & NKR_NEEDRING); 2099 continue; 2100 } 2101 if (netmap_debug & NM_DEBUG_MEM) 2102 nm_prinf("deleting ring %s", kring->name); 2103 if (!(kring->nr_kflags & NKR_FAKERING)) { 2104 nm_prdis("freeing bufs for %s", kring->name); 2105 netmap_free_bufs(nmd, ring->slot, kring->nkr_num_slots); 2106 } else { 2107 nm_prdis("NOT freeing bufs for %s", kring->name); 2108 } 2109 netmap_ring_free(nmd, ring); 2110 kring->ring = NULL; 2111 } 2112 } 2113 } 2114 2115 /* call with NMA_LOCK held */ 2116 /* 2117 * Allocate the per-fd structure netmap_if. 2118 * 2119 * We assume that the configuration stored in na 2120 * (number of tx/rx rings and descs) does not change while 2121 * the interface is in netmap mode. 2122 */ 2123 static struct netmap_if * 2124 netmap_mem2_if_new(struct netmap_mem_d *nmd, 2125 struct netmap_adapter *na, struct netmap_priv_d *priv) 2126 { 2127 struct netmap_if *nifp; 2128 ssize_t base; /* handy for relative offsets between rings and nifp */ 2129 u_int i, len, n[NR_TXRX], ntot; 2130 enum txrx t; 2131 2132 ntot = 0; 2133 for_rx_tx(t) { 2134 /* account for the (eventually fake) host rings */ 2135 n[t] = netmap_all_rings(na, t); 2136 ntot += n[t]; 2137 } 2138 /* 2139 * the descriptor is followed inline by an array of offsets 2140 * to the tx and rx rings in the shared memory region. 2141 */ 2142 2143 len = sizeof(struct netmap_if) + (ntot * sizeof(ssize_t)); 2144 nifp = netmap_if_malloc(nmd, len); 2145 if (nifp == NULL) { 2146 return NULL; 2147 } 2148 2149 /* initialize base fields -- override const */ 2150 *(u_int *)(uintptr_t)&nifp->ni_tx_rings = na->num_tx_rings; 2151 *(u_int *)(uintptr_t)&nifp->ni_rx_rings = na->num_rx_rings; 2152 *(u_int *)(uintptr_t)&nifp->ni_host_tx_rings = 2153 (na->num_host_tx_rings ? na->num_host_tx_rings : 1); 2154 *(u_int *)(uintptr_t)&nifp->ni_host_rx_rings = 2155 (na->num_host_rx_rings ? na->num_host_rx_rings : 1); 2156 strlcpy(nifp->ni_name, na->name, sizeof(nifp->ni_name)); 2157 2158 /* 2159 * fill the slots for the rx and tx rings. They contain the offset 2160 * between the ring and nifp, so the information is usable in 2161 * userspace to reach the ring from the nifp. 2162 */ 2163 base = netmap_if_offset(nmd, nifp); 2164 for (i = 0; i < n[NR_TX]; i++) { 2165 /* XXX instead of ofs == 0 maybe use the offset of an error 2166 * ring, like we do for buffers? */ 2167 ssize_t ofs = 0; 2168 2169 if (na->tx_rings[i]->ring != NULL && i >= priv->np_qfirst[NR_TX] 2170 && i < priv->np_qlast[NR_TX]) { 2171 ofs = netmap_ring_offset(nmd, 2172 na->tx_rings[i]->ring) - base; 2173 } 2174 *(ssize_t *)(uintptr_t)&nifp->ring_ofs[i] = ofs; 2175 } 2176 for (i = 0; i < n[NR_RX]; i++) { 2177 /* XXX instead of ofs == 0 maybe use the offset of an error 2178 * ring, like we do for buffers? */ 2179 ssize_t ofs = 0; 2180 2181 if (na->rx_rings[i]->ring != NULL && i >= priv->np_qfirst[NR_RX] 2182 && i < priv->np_qlast[NR_RX]) { 2183 ofs = netmap_ring_offset(nmd, 2184 na->rx_rings[i]->ring) - base; 2185 } 2186 *(ssize_t *)(uintptr_t)&nifp->ring_ofs[i+n[NR_TX]] = ofs; 2187 } 2188 2189 return (nifp); 2190 } 2191 2192 static void 2193 netmap_mem2_if_delete(struct netmap_mem_d *nmd, 2194 struct netmap_adapter *na, struct netmap_if *nifp) 2195 { 2196 if (nifp == NULL) 2197 /* nothing to do */ 2198 return; 2199 if (nifp->ni_bufs_head) 2200 netmap_extra_free(na, nifp->ni_bufs_head); 2201 netmap_if_free(nmd, nifp); 2202 } 2203 2204 static void 2205 netmap_mem2_deref(struct netmap_mem_d *nmd, struct netmap_adapter *na) 2206 { 2207 2208 if (netmap_debug & NM_DEBUG_MEM) 2209 nm_prinf("active = %d", nmd->active); 2210 2211 } 2212 2213 const struct netmap_mem_ops netmap_mem_global_ops = { 2214 .nmd_get_lut = netmap_mem2_get_lut, 2215 .nmd_get_info = netmap_mem2_get_info, 2216 .nmd_ofstophys = netmap_mem2_ofstophys, 2217 .nmd_config = netmap_mem2_config, 2218 .nmd_finalize = netmap_mem2_finalize, 2219 .nmd_deref = netmap_mem2_deref, 2220 .nmd_delete = netmap_mem2_delete, 2221 .nmd_if_offset = netmap_mem2_if_offset, 2222 .nmd_if_new = netmap_mem2_if_new, 2223 .nmd_if_delete = netmap_mem2_if_delete, 2224 .nmd_rings_create = netmap_mem2_rings_create, 2225 .nmd_rings_delete = netmap_mem2_rings_delete 2226 }; 2227 2228 int 2229 netmap_mem_pools_info_get(struct nmreq_pools_info *req, 2230 struct netmap_mem_d *nmd) 2231 { 2232 int ret; 2233 2234 ret = netmap_mem_get_info(nmd, &req->nr_memsize, NULL, 2235 &req->nr_mem_id); 2236 if (ret) { 2237 return ret; 2238 } 2239 2240 NMA_LOCK(nmd); 2241 req->nr_if_pool_offset = 0; 2242 req->nr_if_pool_objtotal = nmd->pools[NETMAP_IF_POOL].objtotal; 2243 req->nr_if_pool_objsize = nmd->pools[NETMAP_IF_POOL]._objsize; 2244 2245 req->nr_ring_pool_offset = nmd->pools[NETMAP_IF_POOL].memtotal; 2246 req->nr_ring_pool_objtotal = nmd->pools[NETMAP_RING_POOL].objtotal; 2247 req->nr_ring_pool_objsize = nmd->pools[NETMAP_RING_POOL]._objsize; 2248 2249 req->nr_buf_pool_offset = nmd->pools[NETMAP_IF_POOL].memtotal + 2250 nmd->pools[NETMAP_RING_POOL].memtotal; 2251 req->nr_buf_pool_objtotal = nmd->pools[NETMAP_BUF_POOL].objtotal; 2252 req->nr_buf_pool_objsize = nmd->pools[NETMAP_BUF_POOL]._objsize; 2253 NMA_UNLOCK(nmd); 2254 2255 return 0; 2256 } 2257 2258 #ifdef WITH_EXTMEM 2259 struct netmap_mem_ext { 2260 struct netmap_mem_d up; 2261 2262 struct nm_os_extmem *os; 2263 struct netmap_mem_ext *next, *prev; 2264 }; 2265 2266 /* call with nm_mem_list_lock held */ 2267 static void 2268 netmap_mem_ext_register(struct netmap_mem_ext *e) 2269 { 2270 NM_MTX_LOCK(nm_mem_ext_list_lock); 2271 if (netmap_mem_ext_list) 2272 netmap_mem_ext_list->prev = e; 2273 e->next = netmap_mem_ext_list; 2274 netmap_mem_ext_list = e; 2275 e->prev = NULL; 2276 NM_MTX_UNLOCK(nm_mem_ext_list_lock); 2277 } 2278 2279 /* call with nm_mem_list_lock held */ 2280 static void 2281 netmap_mem_ext_unregister(struct netmap_mem_ext *e) 2282 { 2283 if (e->prev) 2284 e->prev->next = e->next; 2285 else 2286 netmap_mem_ext_list = e->next; 2287 if (e->next) 2288 e->next->prev = e->prev; 2289 e->prev = e->next = NULL; 2290 } 2291 2292 static struct netmap_mem_ext * 2293 netmap_mem_ext_search(struct nm_os_extmem *os) 2294 { 2295 struct netmap_mem_ext *e; 2296 2297 NM_MTX_LOCK(nm_mem_ext_list_lock); 2298 for (e = netmap_mem_ext_list; e; e = e->next) { 2299 if (nm_os_extmem_isequal(e->os, os)) { 2300 netmap_mem_get(&e->up); 2301 break; 2302 } 2303 } 2304 NM_MTX_UNLOCK(nm_mem_ext_list_lock); 2305 return e; 2306 } 2307 2308 2309 static void 2310 netmap_mem_ext_delete(struct netmap_mem_d *d) 2311 { 2312 int i; 2313 struct netmap_mem_ext *e = 2314 (struct netmap_mem_ext *)d; 2315 2316 netmap_mem_ext_unregister(e); 2317 2318 for (i = 0; i < NETMAP_POOLS_NR; i++) { 2319 struct netmap_obj_pool *p = &d->pools[i]; 2320 2321 if (p->lut) { 2322 nm_free_lut(p->lut, p->objtotal); 2323 p->lut = NULL; 2324 } 2325 } 2326 if (e->os) 2327 nm_os_extmem_delete(e->os); 2328 netmap_mem2_delete(d); 2329 } 2330 2331 static int 2332 netmap_mem_ext_config(struct netmap_mem_d *nmd) 2333 { 2334 return 0; 2335 } 2336 2337 struct netmap_mem_ops netmap_mem_ext_ops = { 2338 .nmd_get_lut = netmap_mem2_get_lut, 2339 .nmd_get_info = netmap_mem2_get_info, 2340 .nmd_ofstophys = netmap_mem2_ofstophys, 2341 .nmd_config = netmap_mem_ext_config, 2342 .nmd_finalize = netmap_mem2_finalize, 2343 .nmd_deref = netmap_mem2_deref, 2344 .nmd_delete = netmap_mem_ext_delete, 2345 .nmd_if_offset = netmap_mem2_if_offset, 2346 .nmd_if_new = netmap_mem2_if_new, 2347 .nmd_if_delete = netmap_mem2_if_delete, 2348 .nmd_rings_create = netmap_mem2_rings_create, 2349 .nmd_rings_delete = netmap_mem2_rings_delete 2350 }; 2351 2352 struct netmap_mem_d * 2353 netmap_mem_ext_create(uint64_t usrptr, struct nmreq_pools_info *pi, int *perror) 2354 { 2355 int error = 0; 2356 int i, j; 2357 struct netmap_mem_ext *nme; 2358 char *clust; 2359 size_t off; 2360 struct nm_os_extmem *os = NULL; 2361 int nr_pages; 2362 2363 // XXX sanity checks 2364 if (pi->nr_if_pool_objtotal == 0) 2365 pi->nr_if_pool_objtotal = netmap_min_priv_params[NETMAP_IF_POOL].num; 2366 if (pi->nr_if_pool_objsize == 0) 2367 pi->nr_if_pool_objsize = netmap_min_priv_params[NETMAP_IF_POOL].size; 2368 if (pi->nr_ring_pool_objtotal == 0) 2369 pi->nr_ring_pool_objtotal = netmap_min_priv_params[NETMAP_RING_POOL].num; 2370 if (pi->nr_ring_pool_objsize == 0) 2371 pi->nr_ring_pool_objsize = netmap_min_priv_params[NETMAP_RING_POOL].size; 2372 if (pi->nr_buf_pool_objtotal == 0) 2373 pi->nr_buf_pool_objtotal = netmap_min_priv_params[NETMAP_BUF_POOL].num; 2374 if (pi->nr_buf_pool_objsize == 0) 2375 pi->nr_buf_pool_objsize = netmap_min_priv_params[NETMAP_BUF_POOL].size; 2376 if (netmap_verbose & NM_DEBUG_MEM) 2377 nm_prinf("if %d %d ring %d %d buf %d %d", 2378 pi->nr_if_pool_objtotal, pi->nr_if_pool_objsize, 2379 pi->nr_ring_pool_objtotal, pi->nr_ring_pool_objsize, 2380 pi->nr_buf_pool_objtotal, pi->nr_buf_pool_objsize); 2381 2382 os = nm_os_extmem_create(usrptr, pi, &error); 2383 if (os == NULL) { 2384 nm_prerr("os extmem creation failed"); 2385 goto out; 2386 } 2387 2388 nme = netmap_mem_ext_search(os); 2389 if (nme) { 2390 nm_os_extmem_delete(os); 2391 return &nme->up; 2392 } 2393 if (netmap_verbose & NM_DEBUG_MEM) 2394 nm_prinf("not found, creating new"); 2395 2396 nme = _netmap_mem_private_new(sizeof(*nme), 2397 2398 (struct netmap_obj_params[]){ 2399 { pi->nr_if_pool_objsize, pi->nr_if_pool_objtotal }, 2400 { pi->nr_ring_pool_objsize, pi->nr_ring_pool_objtotal }, 2401 { pi->nr_buf_pool_objsize, pi->nr_buf_pool_objtotal }}, 2402 -1, 2403 &netmap_mem_ext_ops, 2404 pi->nr_memsize, 2405 &error); 2406 if (nme == NULL) 2407 goto out_unmap; 2408 2409 nr_pages = nm_os_extmem_nr_pages(os); 2410 2411 /* from now on pages will be released by nme destructor; 2412 * we let res = 0 to prevent release in out_unmap below 2413 */ 2414 nme->os = os; 2415 os = NULL; /* pass ownership */ 2416 2417 clust = nm_os_extmem_nextpage(nme->os); 2418 off = 0; 2419 for (i = 0; i < NETMAP_POOLS_NR; i++) { 2420 struct netmap_obj_pool *p = &nme->up.pools[i]; 2421 struct netmap_obj_params *o = &nme->up.params[i]; 2422 2423 p->_objsize = o->size; 2424 p->_clustsize = o->size; 2425 p->_clustentries = 1; 2426 2427 p->lut = nm_alloc_lut(o->num); 2428 if (p->lut == NULL) { 2429 error = ENOMEM; 2430 goto out_delete; 2431 } 2432 2433 p->bitmap_slots = (o->num + sizeof(uint32_t) - 1) / sizeof(uint32_t); 2434 p->invalid_bitmap = nm_os_malloc(sizeof(uint32_t) * p->bitmap_slots); 2435 if (p->invalid_bitmap == NULL) { 2436 error = ENOMEM; 2437 goto out_delete; 2438 } 2439 2440 if (nr_pages == 0) { 2441 p->objtotal = 0; 2442 p->memtotal = 0; 2443 p->objfree = 0; 2444 continue; 2445 } 2446 2447 for (j = 0; j < o->num && nr_pages > 0; j++) { 2448 size_t noff; 2449 2450 p->lut[j].vaddr = clust + off; 2451 #if !defined(linux) && !defined(_WIN32) 2452 p->lut[j].paddr = vtophys(p->lut[j].vaddr); 2453 #endif 2454 nm_prdis("%s %d at %p", p->name, j, p->lut[j].vaddr); 2455 noff = off + p->_objsize; 2456 if (noff < PAGE_SIZE) { 2457 off = noff; 2458 continue; 2459 } 2460 nm_prdis("too big, recomputing offset..."); 2461 while (noff >= PAGE_SIZE) { 2462 char *old_clust = clust; 2463 noff -= PAGE_SIZE; 2464 clust = nm_os_extmem_nextpage(nme->os); 2465 nr_pages--; 2466 nm_prdis("noff %zu page %p nr_pages %d", noff, 2467 page_to_virt(*pages), nr_pages); 2468 if (noff > 0 && !nm_isset(p->invalid_bitmap, j) && 2469 (nr_pages == 0 || 2470 old_clust + PAGE_SIZE != clust)) 2471 { 2472 /* out of space or non contiguous, 2473 * drop this object 2474 * */ 2475 p->invalid_bitmap[ (j>>5) ] |= 1U << (j & 31U); 2476 nm_prdis("non contiguous at off %zu, drop", noff); 2477 } 2478 if (nr_pages == 0) 2479 break; 2480 } 2481 off = noff; 2482 } 2483 p->objtotal = j; 2484 p->numclusters = p->objtotal; 2485 p->memtotal = j * (size_t)p->_objsize; 2486 nm_prdis("%d memtotal %zu", j, p->memtotal); 2487 } 2488 2489 netmap_mem_ext_register(nme); 2490 2491 return &nme->up; 2492 2493 out_delete: 2494 netmap_mem_put(&nme->up); 2495 out_unmap: 2496 if (os) 2497 nm_os_extmem_delete(os); 2498 out: 2499 if (perror) 2500 *perror = error; 2501 return NULL; 2502 2503 } 2504 #endif /* WITH_EXTMEM */ 2505 2506 2507 #ifdef WITH_PTNETMAP 2508 struct mem_pt_if { 2509 struct mem_pt_if *next; 2510 if_t ifp; 2511 unsigned int nifp_offset; 2512 }; 2513 2514 /* Netmap allocator for ptnetmap guests. */ 2515 struct netmap_mem_ptg { 2516 struct netmap_mem_d up; 2517 2518 vm_paddr_t nm_paddr; /* physical address in the guest */ 2519 void *nm_addr; /* virtual address in the guest */ 2520 struct netmap_lut buf_lut; /* lookup table for BUF pool in the guest */ 2521 nm_memid_t host_mem_id; /* allocator identifier in the host */ 2522 struct ptnetmap_memdev *ptn_dev;/* ptnetmap memdev */ 2523 struct mem_pt_if *pt_ifs; /* list of interfaces in passthrough */ 2524 }; 2525 2526 /* Link a passthrough interface to a passthrough netmap allocator. */ 2527 static int 2528 netmap_mem_pt_guest_ifp_add(struct netmap_mem_d *nmd, if_t ifp, 2529 unsigned int nifp_offset) 2530 { 2531 struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)nmd; 2532 struct mem_pt_if *ptif = nm_os_malloc(sizeof(*ptif)); 2533 2534 if (!ptif) { 2535 return ENOMEM; 2536 } 2537 2538 NMA_LOCK(nmd); 2539 2540 ptif->ifp = ifp; 2541 ptif->nifp_offset = nifp_offset; 2542 2543 if (ptnmd->pt_ifs) { 2544 ptif->next = ptnmd->pt_ifs; 2545 } 2546 ptnmd->pt_ifs = ptif; 2547 2548 NMA_UNLOCK(nmd); 2549 2550 nm_prinf("ifp=%s,nifp_offset=%u", 2551 if_name(ptif->ifp), ptif->nifp_offset); 2552 2553 return 0; 2554 } 2555 2556 /* Called with NMA_LOCK(nmd) held. */ 2557 static struct mem_pt_if * 2558 netmap_mem_pt_guest_ifp_lookup(struct netmap_mem_d *nmd, if_t ifp) 2559 { 2560 struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)nmd; 2561 struct mem_pt_if *curr; 2562 2563 for (curr = ptnmd->pt_ifs; curr; curr = curr->next) { 2564 if (curr->ifp == ifp) { 2565 return curr; 2566 } 2567 } 2568 2569 return NULL; 2570 } 2571 2572 /* Unlink a passthrough interface from a passthrough netmap allocator. */ 2573 int 2574 netmap_mem_pt_guest_ifp_del(struct netmap_mem_d *nmd, if_t ifp) 2575 { 2576 struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)nmd; 2577 struct mem_pt_if *prev = NULL; 2578 struct mem_pt_if *curr; 2579 int ret = -1; 2580 2581 NMA_LOCK(nmd); 2582 2583 for (curr = ptnmd->pt_ifs; curr; curr = curr->next) { 2584 if (curr->ifp == ifp) { 2585 if (prev) { 2586 prev->next = curr->next; 2587 } else { 2588 ptnmd->pt_ifs = curr->next; 2589 } 2590 nm_prinf("removed (ifp=%s,nifp_offset=%u)", 2591 if_name(curr->ifp), curr->nifp_offset); 2592 nm_os_free(curr); 2593 ret = 0; 2594 break; 2595 } 2596 prev = curr; 2597 } 2598 2599 NMA_UNLOCK(nmd); 2600 2601 return ret; 2602 } 2603 2604 static int 2605 netmap_mem_pt_guest_get_lut(struct netmap_mem_d *nmd, struct netmap_lut *lut) 2606 { 2607 struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)nmd; 2608 2609 if (!(nmd->flags & NETMAP_MEM_FINALIZED)) { 2610 return EINVAL; 2611 } 2612 2613 *lut = ptnmd->buf_lut; 2614 return 0; 2615 } 2616 2617 static int 2618 netmap_mem_pt_guest_get_info(struct netmap_mem_d *nmd, uint64_t *size, 2619 u_int *memflags, uint16_t *id) 2620 { 2621 int error = 0; 2622 2623 error = nmd->ops->nmd_config(nmd); 2624 if (error) 2625 goto out; 2626 2627 if (size) 2628 *size = nmd->nm_totalsize; 2629 if (memflags) 2630 *memflags = nmd->flags; 2631 if (id) 2632 *id = nmd->nm_id; 2633 2634 out: 2635 2636 return error; 2637 } 2638 2639 static vm_paddr_t 2640 netmap_mem_pt_guest_ofstophys(struct netmap_mem_d *nmd, vm_ooffset_t off) 2641 { 2642 struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)nmd; 2643 vm_paddr_t paddr; 2644 /* if the offset is valid, just return csb->base_addr + off */ 2645 paddr = (vm_paddr_t)(ptnmd->nm_paddr + off); 2646 nm_prdis("off %lx padr %lx", off, (unsigned long)paddr); 2647 return paddr; 2648 } 2649 2650 static int 2651 netmap_mem_pt_guest_config(struct netmap_mem_d *nmd) 2652 { 2653 /* nothing to do, we are configured on creation 2654 * and configuration never changes thereafter 2655 */ 2656 return 0; 2657 } 2658 2659 static int 2660 netmap_mem_pt_guest_finalize(struct netmap_mem_d *nmd, struct netmap_adapter *na) 2661 { 2662 struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)nmd; 2663 uint64_t mem_size; 2664 uint32_t bufsize; 2665 uint32_t nbuffers; 2666 uint32_t poolofs; 2667 vm_paddr_t paddr; 2668 char *vaddr; 2669 int i; 2670 int error = 0; 2671 2672 if (nmd->flags & NETMAP_MEM_FINALIZED) 2673 goto out; 2674 2675 if (ptnmd->ptn_dev == NULL) { 2676 nm_prerr("ptnetmap memdev not attached"); 2677 error = ENOMEM; 2678 goto out; 2679 } 2680 /* Map memory through ptnetmap-memdev BAR. */ 2681 error = nm_os_pt_memdev_iomap(ptnmd->ptn_dev, &ptnmd->nm_paddr, 2682 &ptnmd->nm_addr, &mem_size); 2683 if (error) 2684 goto out; 2685 2686 /* Initialize the lut using the information contained in the 2687 * ptnetmap memory device. */ 2688 bufsize = nm_os_pt_memdev_ioread(ptnmd->ptn_dev, 2689 PTNET_MDEV_IO_BUF_POOL_OBJSZ); 2690 nbuffers = nm_os_pt_memdev_ioread(ptnmd->ptn_dev, 2691 PTNET_MDEV_IO_BUF_POOL_OBJNUM); 2692 2693 /* allocate the lut */ 2694 if (ptnmd->buf_lut.lut == NULL) { 2695 nm_prinf("allocating lut"); 2696 ptnmd->buf_lut.lut = nm_alloc_lut(nbuffers); 2697 if (ptnmd->buf_lut.lut == NULL) { 2698 nm_prerr("lut allocation failed"); 2699 return ENOMEM; 2700 } 2701 } 2702 2703 /* we have physically contiguous memory mapped through PCI BAR */ 2704 poolofs = nm_os_pt_memdev_ioread(ptnmd->ptn_dev, 2705 PTNET_MDEV_IO_BUF_POOL_OFS); 2706 vaddr = (char *)(ptnmd->nm_addr) + poolofs; 2707 paddr = ptnmd->nm_paddr + poolofs; 2708 2709 for (i = 0; i < nbuffers; i++) { 2710 ptnmd->buf_lut.lut[i].vaddr = vaddr; 2711 vaddr += bufsize; 2712 paddr += bufsize; 2713 } 2714 2715 ptnmd->buf_lut.objtotal = nbuffers; 2716 ptnmd->buf_lut.objsize = bufsize; 2717 nmd->nm_totalsize = mem_size; 2718 2719 /* Initialize these fields as are needed by 2720 * netmap_mem_bufsize(). 2721 * XXX please improve this, why do we need this 2722 * replication? maybe we nmd->pools[] should no be 2723 * there for the guest allocator? */ 2724 nmd->pools[NETMAP_BUF_POOL]._objsize = bufsize; 2725 nmd->pools[NETMAP_BUF_POOL]._objtotal = nbuffers; 2726 2727 nmd->flags |= NETMAP_MEM_FINALIZED; 2728 out: 2729 return error; 2730 } 2731 2732 static void 2733 netmap_mem_pt_guest_deref(struct netmap_mem_d *nmd, struct netmap_adapter *na) 2734 { 2735 struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)nmd; 2736 2737 if (nmd->active == 1 && 2738 (nmd->flags & NETMAP_MEM_FINALIZED)) { 2739 nmd->flags &= ~NETMAP_MEM_FINALIZED; 2740 /* unmap ptnetmap-memdev memory */ 2741 if (ptnmd->ptn_dev) { 2742 nm_os_pt_memdev_iounmap(ptnmd->ptn_dev); 2743 } 2744 ptnmd->nm_addr = NULL; 2745 ptnmd->nm_paddr = 0; 2746 } 2747 } 2748 2749 static ssize_t 2750 netmap_mem_pt_guest_if_offset(struct netmap_mem_d *nmd, const void *vaddr) 2751 { 2752 struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)nmd; 2753 2754 return (const char *)(vaddr) - (char *)(ptnmd->nm_addr); 2755 } 2756 2757 static void 2758 netmap_mem_pt_guest_delete(struct netmap_mem_d *nmd) 2759 { 2760 if (nmd == NULL) 2761 return; 2762 if (netmap_verbose) 2763 nm_prinf("deleting %p", nmd); 2764 if (nmd->active > 0) 2765 nm_prerr("bug: deleting mem allocator with active=%d!", nmd->active); 2766 if (netmap_verbose) 2767 nm_prinf("done deleting %p", nmd); 2768 NMA_LOCK_DESTROY(nmd); 2769 nm_os_free(nmd); 2770 } 2771 2772 static struct netmap_if * 2773 netmap_mem_pt_guest_if_new(struct netmap_mem_d *nmd, 2774 struct netmap_adapter *na, struct netmap_priv_d *priv) 2775 { 2776 struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)nmd; 2777 struct mem_pt_if *ptif; 2778 struct netmap_if *nifp = NULL; 2779 2780 ptif = netmap_mem_pt_guest_ifp_lookup(nmd, na->ifp); 2781 if (ptif == NULL) { 2782 nm_prerr("interface %s is not in passthrough", na->name); 2783 goto out; 2784 } 2785 2786 nifp = (struct netmap_if *)((char *)(ptnmd->nm_addr) + 2787 ptif->nifp_offset); 2788 out: 2789 return nifp; 2790 } 2791 2792 static void 2793 netmap_mem_pt_guest_if_delete(struct netmap_mem_d * nmd, 2794 struct netmap_adapter *na, struct netmap_if *nifp) 2795 { 2796 struct mem_pt_if *ptif; 2797 2798 ptif = netmap_mem_pt_guest_ifp_lookup(nmd, na->ifp); 2799 if (ptif == NULL) { 2800 nm_prerr("interface %s is not in passthrough", na->name); 2801 } 2802 } 2803 2804 static int 2805 netmap_mem_pt_guest_rings_create(struct netmap_mem_d *nmd, 2806 struct netmap_adapter *na) 2807 { 2808 struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)nmd; 2809 struct mem_pt_if *ptif; 2810 struct netmap_if *nifp; 2811 int i, error = -1; 2812 2813 ptif = netmap_mem_pt_guest_ifp_lookup(nmd, na->ifp); 2814 if (ptif == NULL) { 2815 nm_prerr("interface %s is not in passthrough", na->name); 2816 goto out; 2817 } 2818 2819 2820 /* point each kring to the corresponding backend ring */ 2821 nifp = (struct netmap_if *)((char *)ptnmd->nm_addr + ptif->nifp_offset); 2822 for (i = 0; i < netmap_all_rings(na, NR_TX); i++) { 2823 struct netmap_kring *kring = na->tx_rings[i]; 2824 if (kring->ring) 2825 continue; 2826 kring->ring = (struct netmap_ring *) 2827 ((char *)nifp + nifp->ring_ofs[i]); 2828 } 2829 for (i = 0; i < netmap_all_rings(na, NR_RX); i++) { 2830 struct netmap_kring *kring = na->rx_rings[i]; 2831 if (kring->ring) 2832 continue; 2833 kring->ring = (struct netmap_ring *) 2834 ((char *)nifp + 2835 nifp->ring_ofs[netmap_all_rings(na, NR_TX) + i]); 2836 } 2837 2838 error = 0; 2839 out: 2840 return error; 2841 } 2842 2843 static void 2844 netmap_mem_pt_guest_rings_delete(struct netmap_mem_d *nmd, struct netmap_adapter *na) 2845 { 2846 #if 0 2847 enum txrx t; 2848 2849 for_rx_tx(t) { 2850 u_int i; 2851 for (i = 0; i < nma_get_nrings(na, t) + 1; i++) { 2852 struct netmap_kring *kring = &NMR(na, t)[i]; 2853 2854 kring->ring = NULL; 2855 } 2856 } 2857 #endif 2858 (void)nmd; 2859 (void)na; 2860 } 2861 2862 static struct netmap_mem_ops netmap_mem_pt_guest_ops = { 2863 .nmd_get_lut = netmap_mem_pt_guest_get_lut, 2864 .nmd_get_info = netmap_mem_pt_guest_get_info, 2865 .nmd_ofstophys = netmap_mem_pt_guest_ofstophys, 2866 .nmd_config = netmap_mem_pt_guest_config, 2867 .nmd_finalize = netmap_mem_pt_guest_finalize, 2868 .nmd_deref = netmap_mem_pt_guest_deref, 2869 .nmd_if_offset = netmap_mem_pt_guest_if_offset, 2870 .nmd_delete = netmap_mem_pt_guest_delete, 2871 .nmd_if_new = netmap_mem_pt_guest_if_new, 2872 .nmd_if_delete = netmap_mem_pt_guest_if_delete, 2873 .nmd_rings_create = netmap_mem_pt_guest_rings_create, 2874 .nmd_rings_delete = netmap_mem_pt_guest_rings_delete 2875 }; 2876 2877 /* Called with nm_mem_list_lock held. */ 2878 static struct netmap_mem_d * 2879 netmap_mem_pt_guest_find_memid(nm_memid_t mem_id) 2880 { 2881 struct netmap_mem_d *mem = NULL; 2882 struct netmap_mem_d *scan = netmap_last_mem_d; 2883 2884 do { 2885 /* find ptnetmap allocator through host ID */ 2886 if (scan->ops->nmd_deref == netmap_mem_pt_guest_deref && 2887 ((struct netmap_mem_ptg *)(scan))->host_mem_id == mem_id) { 2888 mem = scan; 2889 mem->refcount++; 2890 NM_DBG_REFC(mem, __FUNCTION__, __LINE__); 2891 break; 2892 } 2893 scan = scan->next; 2894 } while (scan != netmap_last_mem_d); 2895 2896 return mem; 2897 } 2898 2899 /* Called with nm_mem_list_lock held. */ 2900 static struct netmap_mem_d * 2901 netmap_mem_pt_guest_create(nm_memid_t mem_id) 2902 { 2903 struct netmap_mem_ptg *ptnmd; 2904 int err = 0; 2905 2906 ptnmd = nm_os_malloc(sizeof(struct netmap_mem_ptg)); 2907 if (ptnmd == NULL) { 2908 err = ENOMEM; 2909 goto error; 2910 } 2911 2912 ptnmd->up.ops = &netmap_mem_pt_guest_ops; 2913 ptnmd->host_mem_id = mem_id; 2914 ptnmd->pt_ifs = NULL; 2915 2916 /* Assign new id in the guest (We have the lock) */ 2917 err = nm_mem_assign_id_locked(&ptnmd->up, -1, -1); 2918 if (err) 2919 goto error; 2920 2921 ptnmd->up.flags &= ~NETMAP_MEM_FINALIZED; 2922 ptnmd->up.flags |= NETMAP_MEM_IO; 2923 2924 NMA_LOCK_INIT(&ptnmd->up); 2925 2926 snprintf(ptnmd->up.name, NM_MEM_NAMESZ, "%d", ptnmd->up.nm_id); 2927 2928 2929 return &ptnmd->up; 2930 error: 2931 netmap_mem_pt_guest_delete(&ptnmd->up); 2932 return NULL; 2933 } 2934 2935 /* 2936 * find host id in guest allocators and create guest allocator 2937 * if it is not there 2938 */ 2939 static struct netmap_mem_d * 2940 netmap_mem_pt_guest_get(nm_memid_t mem_id) 2941 { 2942 struct netmap_mem_d *nmd; 2943 2944 NM_MTX_LOCK(nm_mem_list_lock); 2945 nmd = netmap_mem_pt_guest_find_memid(mem_id); 2946 if (nmd == NULL) { 2947 nmd = netmap_mem_pt_guest_create(mem_id); 2948 } 2949 NM_MTX_UNLOCK(nm_mem_list_lock); 2950 2951 return nmd; 2952 } 2953 2954 /* 2955 * The guest allocator can be created by ptnetmap_memdev (during the device 2956 * attach) or by ptnetmap device (ptnet), during the netmap_attach. 2957 * 2958 * The order is not important (we have different order in LINUX and FreeBSD). 2959 * The first one, creates the device, and the second one simply attaches it. 2960 */ 2961 2962 /* Called when ptnetmap_memdev is attaching, to attach a new allocator in 2963 * the guest */ 2964 struct netmap_mem_d * 2965 netmap_mem_pt_guest_attach(struct ptnetmap_memdev *ptn_dev, nm_memid_t mem_id) 2966 { 2967 struct netmap_mem_d *nmd; 2968 struct netmap_mem_ptg *ptnmd; 2969 2970 nmd = netmap_mem_pt_guest_get(mem_id); 2971 2972 /* assign this device to the guest allocator */ 2973 if (nmd) { 2974 ptnmd = (struct netmap_mem_ptg *)nmd; 2975 ptnmd->ptn_dev = ptn_dev; 2976 } 2977 2978 return nmd; 2979 } 2980 2981 /* Called when ptnet device is attaching */ 2982 struct netmap_mem_d * 2983 netmap_mem_pt_guest_new(if_t ifp, 2984 unsigned int nifp_offset, 2985 unsigned int memid) 2986 { 2987 struct netmap_mem_d *nmd; 2988 2989 if (ifp == NULL) { 2990 return NULL; 2991 } 2992 2993 nmd = netmap_mem_pt_guest_get((nm_memid_t)memid); 2994 2995 if (nmd) { 2996 netmap_mem_pt_guest_ifp_add(nmd, ifp, nifp_offset); 2997 } 2998 2999 return nmd; 3000 } 3001 3002 #endif /* WITH_PTNETMAP */ 3003