FD.io VPP  v18.10-34-gcce845e
Vector Packet Processing
physmem.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /*
16  * physmem.c: Unix physical memory
17  *
18  * Copyright (c) 2008 Eliot Dresselhaus
19  *
20  * Permission is hereby granted, free of charge, to any person obtaining
21  * a copy of this software and associated documentation files (the
22  * "Software"), to deal in the Software without restriction, including
23  * without limitation the rights to use, copy, modify, merge, publish,
24  * distribute, sublicense, and/or sell copies of the Software, and to
25  * permit persons to whom the Software is furnished to do so, subject to
26  * the following conditions:
27  *
28  * The above copyright notice and this permission notice shall be
29  * included in all copies or substantial portions of the Software.
30  *
31  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38  */
39 
40 #include <unistd.h>
41 #include <sys/types.h>
42 #include <sys/mount.h>
43 #include <sys/mman.h>
44 #include <sys/fcntl.h>
45 #include <sys/stat.h>
46 #include <unistd.h>
47 
48 #include <vppinfra/linux/syscall.h>
49 #include <vppinfra/linux/sysfs.h>
50 #include <vlib/vlib.h>
51 #include <vlib/physmem.h>
52 #include <vlib/unix/unix.h>
53 #include <vlib/pci/pci.h>
54 #include <vlib/linux/vfio.h>
55 
56 static void *
58  uword n_bytes, uword alignment)
59 {
61  uword lo_offset, hi_offset;
62  uword *to_free = 0;
63 
64  if (pr->heap == 0)
65  return 0;
66 
67  /* IO memory is always at least cache aligned. */
68  alignment = clib_max (alignment, CLIB_CACHE_LINE_BYTES);
69 
70  while (1)
71  {
72 #if USE_DLMALLOC == 0
73 
74  mheap_get_aligned (pr->heap, n_bytes,
75  /* align */ alignment,
76  /* align offset */ 0,
77  &lo_offset);
78 #else
79  lo_offset = (uword) mspace_get_aligned (pr->heap, n_bytes,
80  alignment, ~0ULL /* offset */ );
81  if (lo_offset == 0)
82  lo_offset = ~0ULL;
83 #endif
84 
85  /* Allocation failed? */
86  if (lo_offset == ~0)
87  break;
88 
89  /* Make sure allocation does not span DMA physical chunk boundary. */
90  hi_offset = lo_offset + n_bytes - 1;
91 
92  if (((pointer_to_uword (pr->heap) + lo_offset) >> pr->log2_page_size) ==
93  ((pointer_to_uword (pr->heap) + hi_offset) >> pr->log2_page_size))
94  break;
95 
96  /* Allocation would span chunk boundary, queue it to be freed as soon as
97  we find suitable chunk. */
98  vec_add1 (to_free, lo_offset);
99  }
100 
101  if (to_free != 0)
102  {
103  uword i;
104  for (i = 0; i < vec_len (to_free); i++)
105  {
106 #if USE_DLMALLOC == 0
107  mheap_put (pr->heap, to_free[i]);
108 #else
109  mspace_put_no_offset (pr->heap, (void *) to_free[i]);
110 #endif
111  }
112  vec_free (to_free);
113  }
114 
115 #if USE_DLMALLOC == 0
116  return lo_offset != ~0 ? (void *) (pr->heap + lo_offset) : 0;
117 #else
118  return lo_offset != ~0 ? (void *) lo_offset : 0;
119 #endif
120 }
121 
122 static void
124 {
126  /* Return object to region's heap. */
127 #if USE_DLMALLOC == 0
128  mheap_put (pr->heap, x - pr->heap);
129 #else
130  mspace_put_no_offset (pr->heap, x);
131 #endif
132 }
133 
134 static clib_error_t *
136  u8 numa_node, u32 flags,
138 {
141  clib_error_t *error = 0;
142  clib_mem_vm_alloc_t alloc = { 0 };
143  int i;
144 
145  pool_get (vpm->regions, pr);
146 
147  if ((pr - vpm->regions) >= 256)
148  {
149  error = clib_error_return (0, "maximum number of regions reached");
150  goto error;
151  }
152 
153  alloc.name = name;
154  alloc.size = size;
155  alloc.numa_node = numa_node;
156 
157  alloc.flags = (flags & VLIB_PHYSMEM_F_SHARED) ?
159 
160  if ((flags & VLIB_PHYSMEM_F_HUGETLB))
161  {
162  alloc.flags |= CLIB_MEM_VM_F_HUGETLB;
165  }
166  else
167  {
169  }
170 
171  error = clib_mem_vm_ext_alloc (&alloc);
172  if (error)
173  goto error;
174 
175  pr->index = pr - vpm->regions;
176  pr->flags = flags;
177  pr->fd = alloc.fd;
178  pr->mem = alloc.addr;
179  pr->log2_page_size = alloc.log2_page_size;
180  pr->n_pages = alloc.n_pages;
181  pr->size = (u64) pr->n_pages << (u64) pr->log2_page_size;
182  pr->page_mask = (1 << pr->log2_page_size) - 1;
183  pr->numa_node = numa_node;
184  pr->name = format (0, "%s%c", name, 0);
185 
186  for (i = 0; i < pr->n_pages; i++)
187  {
188  void *ptr = pr->mem + ((u64) i << pr->log2_page_size);
189  int node;
190  if ((move_pages (0, 1, &ptr, 0, &node, 0) == 0) && (numa_node != node))
191  {
192  clib_warning ("physmem page for region \'%s\' allocated on the"
193  " wrong numa node (requested %u actual %u)",
194  pr->name, pr->numa_node, node, i);
195  break;
196  }
197  }
198 
200  pr->n_pages);
201 
203 
204  if (flags & VLIB_PHYSMEM_F_INIT_MHEAP)
205  {
206 #if USE_DLMALLOC == 0
207  pr->heap = mheap_alloc_with_flags (pr->mem, pr->size,
208  /* Don't want mheap mmap/munmap with IO memory. */
211 #else
212  pr->heap = create_mspace_with_base (pr->mem, pr->size, 1 /* locked */ );
214 #endif
215  }
216 
217  *idx = pr->index;
218 
219  goto done;
220 
221 error:
222  memset (pr, 0, sizeof (*pr));
223  pool_put (vpm->regions, pr);
224 
225 done:
226  return error;
227 }
228 
229 static void
231 {
234 
235  if (pr->fd > 0)
236  close (pr->fd);
237  munmap (pr->mem, pr->size);
238  vec_free (pr->name);
239  pool_put (vpm->regions, pr);
240 }
241 
242 clib_error_t *
244 {
246  clib_error_t *error = 0;
247  u64 *pt = 0;
248 
249  /* Avoid multiple calls. */
250  if (vm->os_physmem_alloc_aligned)
251  return error;
252 
253  /* check if pagemap is accessible */
254  pt = clib_mem_vm_get_paddr (&pt, min_log2 (sysconf (_SC_PAGESIZE)), 1);
255  if (pt[0])
257  vec_free (pt);
258 
259  if ((error = linux_vfio_init (vm)))
260  return error;
261 
266 
267  return error;
268 }
269 
270 static clib_error_t *
272  unformat_input_t * input, vlib_cli_command_t * cmd)
273 {
276 
277  /* *INDENT-OFF* */
278  pool_foreach (pr, vpm->regions, (
279  {
280  vlib_cli_output (vm, "index %u name '%s' page-size %uKB num-pages %d "
281  "numa-node %u fd %d\n",
282  pr->index, pr->name, (1 << (pr->log2_page_size -10)),
283  pr->n_pages, pr->numa_node, pr->fd);
284  if (pr->heap)
285  vlib_cli_output (vm, " %U", format_mheap, pr->heap, /* verbose */ 1);
286  else
287  vlib_cli_output (vm, " no heap\n");
288  }));
289  /* *INDENT-ON* */
290  return 0;
291 }
292 
293 /* *INDENT-OFF* */
294 VLIB_CLI_COMMAND (show_physmem_command, static) = {
295  .path = "show physmem",
296  .short_help = "Show physical memory allocation",
297  .function = show_physmem,
298 };
299 /* *INDENT-ON* */
300 
301 /*
302  * fd.io coding-style-patch-verification: ON
303  *
304  * Local Variables:
305  * eval: (c-set-style "gnu")
306  * End:
307  */
#define CLIB_MEM_VM_F_HUGETLB
Definition: mem.h:363
#define VLIB_PHYSMEM_F_INIT_MHEAP
Definition: physmem.h:57
void linux_vfio_dma_map_regions(vlib_main_t *vm)
Definition: vfio.c:77
#define VLIB_PHYSMEM_F_HUGETLB
Definition: physmem.h:58
void(* os_physmem_region_free)(struct vlib_main_t *vm, vlib_physmem_region_index_t idx)
Definition: main.h:124
#define CLIB_MEM_VM_F_NUMA_PREFER
Definition: mem.h:364
unsigned long u64
Definition: types.h:89
void * addr
Pointer to allocated memory, set on successful allocation.
Definition: mem.h:382
static clib_error_t * unix_physmem_region_alloc(vlib_main_t *vm, char *name, u32 size, u8 numa_node, u32 flags, vlib_physmem_region_index_t *idx)
Definition: physmem.c:135
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:523
int i
int numa_node
numa node preference.
Definition: mem.h:381
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
#define MHEAP_FLAG_THREAD_SAFE
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:228
unsigned char u8
Definition: types.h:56
static uword min_log2(uword x)
Definition: clib.h:140
static void * unix_physmem_alloc_aligned(vlib_main_t *vm, vlib_physmem_region_index_t idx, uword n_bytes, uword alignment)
Definition: physmem.c:57
#define VLIB_PHYSMEM_F_SHARED
Definition: physmem.h:59
DLMALLOC_EXPORT mspace create_mspace_with_base(void *base, size_t capacity, int locked)
#define VLIB_PHYSMEM_MAIN_F_HAVE_PAGEMAP
Definition: physmem.h:71
DLMALLOC_EXPORT void * mspace_get_aligned(mspace msp, unsigned long long n_user_data_bytes, unsigned long long align, unsigned long long align_offset)
memset(h->entries, 0, sizeof(h->entries[0])*entries)
clib_error_t * clib_mem_vm_ext_alloc(clib_mem_vm_alloc_t *a)
Definition: mem.c:80
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:443
void(* os_physmem_free)(struct vlib_main_t *vm, vlib_physmem_region_index_t idx, void *x)
Definition: main.h:130
#define MHEAP_FLAG_DISABLE_VM
char * name
Name for memory allocation, set by caller.
Definition: mem.h:379
void *(* os_physmem_alloc_aligned)(struct vlib_main_t *vm, vlib_physmem_region_index_t idx, uword n_bytes, uword alignment)
Definition: main.h:127
#define clib_error_return(e, args...)
Definition: error.h:99
DLMALLOC_EXPORT void mspace_put_no_offset(mspace msp, void *p)
uword size
Allocation size, set by caller.
Definition: mem.h:380
unsigned int u32
Definition: types.h:88
static vlib_physmem_region_t * vlib_physmem_get_region(vlib_main_t *vm, u8 index)
Definition: physmem_funcs.h:44
#define CLIB_MEM_VM_F_SHARED
Definition: mem.h:362
uword size
int fd
File descriptor, set on successful allocation if CLIB_MEM_VM_F_SHARED is set.
Definition: mem.h:383
DLMALLOC_EXPORT void mspace_disable_expand(mspace msp)
struct _unformat_input_t unformat_input_t
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:274
#define CLIB_MEM_VM_F_NUMA_FORCE
Definition: mem.h:365
clib_error_t * linux_vfio_init(vlib_main_t *vm)
Definition: vfio.c:229
u8 name[64]
Definition: memclnt.api:151
u32 flags
Definition: vhost_user.h:115
vlib_main_t * vm
Definition: buffer.c:294
void * mheap_get_aligned(void *v, uword n_user_data_bytes, uword align, uword align_offset, uword *offset_return)
Definition: mheap.c:643
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:339
#define clib_warning(format, args...)
Definition: error.h:59
u32 flags
vm allocation flags: CLIB_MEM_VM_F_SHARED: request shared memory, file descriptor will be provided ...
Definition: mem.h:368
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:155
void * mheap_alloc_with_flags(void *memory, uword memory_size, uword flags)
Definition: mheap.c:885
#define CLIB_MEM_VM_F_HUGETLB_PREALLOC
Definition: mem.h:366
#define CLIB_MEM_VM_F_LOCKED
Definition: mem.h:367
static void unix_physmem_free(vlib_main_t *vm, vlib_physmem_region_index_t idx, void *x)
Definition: physmem.c:123
static uword pointer_to_uword(const void *p)
Definition: types.h:131
vlib_physmem_region_index_t index
Definition: physmem.h:47
#define clib_max(x, y)
Definition: clib.h:284
static clib_error_t * show_physmem(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: physmem.c:271
void mheap_put(void *v, uword uoffset)
Definition: mheap.c:771
static void unix_physmem_region_free(vlib_main_t *vm, vlib_physmem_region_index_t idx)
Definition: physmem.c:230
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
u64 uword
Definition: types.h:112
u64 * clib_mem_vm_get_paddr(void *mem, int log2_page_size, int n_pages)
Definition: mem.c:256
clib_error_t * unix_physmem_init(vlib_main_t *vm)
Definition: physmem.c:243
vlib_physmem_main_t physmem_main
Definition: main.c:64
int log2_page_size
Definition: mem.h:384
static long move_pages(int pid, unsigned long count, void **pages, const int *nodes, int *status, int flags)
Definition: syscall.h:36
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:59
clib_error_t *(* os_physmem_region_alloc)(struct vlib_main_t *vm, char *name, u32 size, u8 numa_node, u32 flags, vlib_physmem_region_index_t *idx)
Definition: main.h:118
u8 vlib_physmem_region_index_t
Definition: physmem.h:43
vlib_physmem_region_t * regions
Definition: physmem.h:73