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
netmap_mem_get_lut(struct netmap_mem_d * nmd,struct netmap_lut * lut)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
netmap_mem_get_info(struct netmap_mem_d * nmd,uint64_t * size,u_int * memflags,nm_memid_t * memid)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
netmap_mem_ofstophys(struct netmap_mem_d * nmd,vm_ooffset_t off)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
netmap_mem_config(struct netmap_mem_d * nmd)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
netmap_mem_if_offset(struct netmap_mem_d * nmd,const void * off)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
netmap_mem_delete(struct netmap_mem_d * nmd)262 netmap_mem_delete(struct netmap_mem_d *nmd)
263 {
264 nmd->ops->nmd_delete(nmd);
265 }
266
267 struct netmap_if *
netmap_mem_if_new(struct netmap_adapter * na,struct netmap_priv_d * priv)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
netmap_mem_if_delete(struct netmap_adapter * na,struct netmap_if * nif)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
netmap_mem_rings_create(struct netmap_adapter * na)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
netmap_mem_rings_delete(struct netmap_adapter * na)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
netmap_mem_get_id(struct netmap_mem_d * nmd)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 *
__netmap_mem_get(struct netmap_mem_d * nmd,const char * func,int line)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
__netmap_mem_put(struct netmap_mem_d * nmd,const char * func,int line)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
netmap_mem_finalize(struct netmap_mem_d * nmd,struct netmap_adapter * na)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
nm_isset(uint32_t * bitmap,u_int i)391 nm_isset(uint32_t *bitmap, u_int i)
392 {
393 return bitmap[ (i>>5) ] & ( 1U << (i & 31U) );
394 }
395
396
397 static int
netmap_init_obj_allocator_bitmap(struct netmap_obj_pool * p)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
netmap_mem_init_bitmaps(struct netmap_mem_d * nmd)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
netmap_mem_deref(struct netmap_mem_d * nmd,struct netmap_adapter * na)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
netmap_mem2_get_lut(struct netmap_mem_d * nmd,struct netmap_lut * lut)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
nm_mem_assign_id_locked(struct netmap_mem_d * nmd,int grp_id,int domain)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
nm_mem_assign_id(struct netmap_mem_d * nmd,int grp_id)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
nm_mem_release_id(struct netmap_mem_d * nmd)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 *
netmap_mem_find(nm_memid_t id)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
nm_mem_check_group(struct netmap_mem_d * nmd,void * dev)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 *
nm_alloc_lut(u_int nobj)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
nm_free_lut(struct lut_entry * lut,u_int objtotal)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 *
nm_alloc_plut(u_int nobj)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
nm_free_plut(struct plut_entry * lut)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
netmap_mem2_ofstophys(struct netmap_mem_d * nmd,vm_ooffset_t offset)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
win32_build_user_vm_map(struct netmap_mem_d * nmd)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
netmap_mem2_get_pool_info(struct netmap_mem_d * nmd,u_int pool,u_int * clustsize,u_int * numclusters)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
netmap_mem2_get_info(struct netmap_mem_d * nmd,uint64_t * size,u_int * memflags,nm_memid_t * id)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
netmap_obj_offset(struct netmap_obj_pool * p,const void * vaddr)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
netmap_mem2_if_offset(struct netmap_mem_d * nmd,const void * addr)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 *
netmap_obj_malloc(struct netmap_obj_pool * p,u_int len,uint32_t * start,uint32_t * index)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
netmap_obj_free(struct netmap_obj_pool * p,uint32_t j)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
netmap_obj_free_va(struct netmap_obj_pool * p,void * vaddr)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
netmap_mem_bufsize(struct netmap_mem_d * nmd)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
netmap_extra_alloc(struct netmap_adapter * na,uint32_t * head,uint32_t n)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
netmap_extra_free(struct netmap_adapter * na,uint32_t head)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
netmap_new_bufs(struct netmap_mem_d * nmd,struct netmap_slot * slot,u_int n)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
netmap_mem_set_ring(struct netmap_mem_d * nmd,struct netmap_slot * slot,u_int n,uint32_t index)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
netmap_free_buf(struct netmap_mem_d * nmd,uint32_t i)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
netmap_free_bufs(struct netmap_mem_d * nmd,struct netmap_slot * slot,u_int n)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
netmap_reset_obj_allocator(struct netmap_obj_pool * p)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
netmap_destroy_obj_allocator(struct netmap_obj_pool * p)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
netmap_config_obj_allocator(struct netmap_obj_pool * p,u_int objtotal,u_int objsize)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
netmap_finalize_obj_allocator(struct netmap_mem_d * nmd,struct netmap_obj_pool * p)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
netmap_mem_params_changed(struct netmap_obj_params * p)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
netmap_mem_reset_all(struct netmap_mem_d * nmd)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
netmap_mem_unmap(struct netmap_obj_pool * p,struct netmap_adapter * na)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
netmap_mem_map(struct netmap_obj_pool * p,struct netmap_adapter * na)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
netmap_mem_finalize_all(struct netmap_mem_d * nmd)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 *
_netmap_mem_private_new(size_t size,struct netmap_obj_params * p,int grp_id,const struct netmap_mem_ops * ops,uint64_t memtotal,int * perr)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 *
netmap_mem_private_new(u_int txr,u_int txd,u_int rxr,u_int rxd,u_int extra_bufs,u_int npipes,int * perr)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 *
netmap_mem_get_allocator(struct netmap_adapter * na)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
netmap_mem2_config(struct netmap_mem_d * nmd)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
netmap_mem2_finalize(struct netmap_mem_d * nmd,struct netmap_adapter * na)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
netmap_mem2_delete(struct netmap_mem_d * nmd)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
netmap_mem_init(void)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
netmap_mem_fini(void)1963 netmap_mem_fini(void)
1964 {
1965 netmap_mem_put(&nm_mem);
1966 }
1967
1968 static int
netmap_mem_ring_needed(struct netmap_kring * kring)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
netmap_mem_ring_todelete(struct netmap_kring * kring)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
netmap_mem2_rings_create(struct netmap_mem_d * nmd,struct netmap_adapter * na)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
netmap_mem2_rings_delete(struct netmap_mem_d * nmd,struct netmap_adapter * na)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 *
netmap_mem2_if_new(struct netmap_mem_d * nmd,struct netmap_adapter * na,struct netmap_priv_d * priv)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
netmap_mem2_if_delete(struct netmap_mem_d * nmd,struct netmap_adapter * na,struct netmap_if * nifp)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
netmap_mem2_deref(struct netmap_mem_d * nmd,struct netmap_adapter * na)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
netmap_mem_pools_info_get(struct nmreq_pools_info * req,struct netmap_mem_d * nmd)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
netmap_mem_ext_register(struct netmap_mem_ext * e)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
netmap_mem_ext_unregister(struct netmap_mem_ext * e)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 *
netmap_mem_ext_search(struct nm_os_extmem * os)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
netmap_mem_ext_delete(struct netmap_mem_d * d)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
netmap_mem_ext_config(struct netmap_mem_d * nmd)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 *
netmap_mem_ext_create(uint64_t usrptr,struct nmreq_pools_info * pi,int * perror)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
netmap_mem_pt_guest_ifp_add(struct netmap_mem_d * nmd,if_t ifp,unsigned int nifp_offset)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 *
netmap_mem_pt_guest_ifp_lookup(struct netmap_mem_d * nmd,if_t ifp)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
netmap_mem_pt_guest_ifp_del(struct netmap_mem_d * nmd,if_t ifp)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
netmap_mem_pt_guest_get_lut(struct netmap_mem_d * nmd,struct netmap_lut * lut)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
netmap_mem_pt_guest_get_info(struct netmap_mem_d * nmd,uint64_t * size,u_int * memflags,uint16_t * id)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
netmap_mem_pt_guest_ofstophys(struct netmap_mem_d * nmd,vm_ooffset_t off)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
netmap_mem_pt_guest_config(struct netmap_mem_d * nmd)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
netmap_mem_pt_guest_finalize(struct netmap_mem_d * nmd,struct netmap_adapter * na)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
netmap_mem_pt_guest_deref(struct netmap_mem_d * nmd,struct netmap_adapter * na)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
netmap_mem_pt_guest_if_offset(struct netmap_mem_d * nmd,const void * vaddr)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
netmap_mem_pt_guest_delete(struct netmap_mem_d * nmd)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 *
netmap_mem_pt_guest_if_new(struct netmap_mem_d * nmd,struct netmap_adapter * na,struct netmap_priv_d * priv)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
netmap_mem_pt_guest_if_delete(struct netmap_mem_d * nmd,struct netmap_adapter * na,struct netmap_if * nifp)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
netmap_mem_pt_guest_rings_create(struct netmap_mem_d * nmd,struct netmap_adapter * na)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
netmap_mem_pt_guest_rings_delete(struct netmap_mem_d * nmd,struct netmap_adapter * na)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 *
netmap_mem_pt_guest_find_memid(nm_memid_t mem_id)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 *
netmap_mem_pt_guest_create(nm_memid_t mem_id)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 *
netmap_mem_pt_guest_get(nm_memid_t mem_id)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 *
netmap_mem_pt_guest_attach(struct ptnetmap_memdev * ptn_dev,nm_memid_t mem_id)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 *
netmap_mem_pt_guest_new(if_t ifp,unsigned int nifp_offset,unsigned int memid)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