FD.io VPP  v16.06
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 <vlib/unix/physmem.h>
41 
43 
44 static void *
46 {
48  uword lo_offset, hi_offset;
49  uword * to_free = 0;
50 
51 #if DPDK > 0
52  clib_warning ("unsafe alloc!");
53 #endif
54 
55  /* IO memory is always at least cache aligned. */
56  alignment = clib_max (alignment, CLIB_CACHE_LINE_BYTES);
57 
58  while (1)
59  {
60  mheap_get_aligned (pm->heap, n_bytes,
61  /* align */ alignment,
62  /* align offset */ 0,
63  &lo_offset);
64 
65  /* Allocation failed? */
66  if (lo_offset == ~0)
67  break;
68 
69  /* Make sure allocation does not span DMA physical chunk boundary. */
70  hi_offset = lo_offset + n_bytes - 1;
71 
72  if ((lo_offset >> vpm->log2_n_bytes_per_page) ==
73  (hi_offset >> vpm->log2_n_bytes_per_page))
74  break;
75 
76  /* Allocation would span chunk boundary, queue it to be freed as soon as
77  we find suitable chunk. */
78  vec_add1 (to_free, lo_offset);
79  }
80 
81  if (to_free != 0)
82  {
83  uword i;
84  for (i = 0; i < vec_len (to_free); i++)
85  mheap_put (pm->heap, to_free[i]);
86  vec_free (to_free);
87  }
88 
89  return lo_offset != ~0 ? pm->heap + lo_offset : 0;
90 }
91 
92 static void unix_physmem_free (void * x)
93 {
95 
96  /* Return object to region's heap. */
97  mheap_put (pm->heap, x - pm->heap);
98 }
99 
100 static void htlb_shutdown(void)
101 {
103 
104  if (! pm->shmid)
105  return;
106  shmctl (pm->shmid, IPC_RMID, 0);
107  pm->shmid = 0;
108 }
109 
110 /* try to use huge TLB pgs if possible */
111 static int htlb_init (vlib_main_t * vm)
112 {
113  vlib_physmem_main_t * vpm = &vm->physmem_main;
115  u64 hugepagesize, pagesize;
116  u64 pfn, seek_loc;
117  u64 cur, physaddr, ptbits;
118  int fd, i;
119 
120  pm->shmid = shmget (11 /* key, my amp goes to 11 */, pm->mem_size,
121  IPC_CREAT | SHM_HUGETLB | SHM_R | SHM_W);
122  if (pm->shmid < 0)
123  {
124  clib_unix_warning ("shmget");
125  return 0;
126  }
127 
128  pm->mem = shmat (pm->shmid, NULL, 0 /* flags */);
129  if (pm->mem == 0)
130  {
131  shmctl (pm->shmid, IPC_RMID, 0);
132  return 0;
133  }
134 
135  memset (pm->mem, 0, pm->mem_size);
136 
137  /* $$$ get page size info from /proc/meminfo */
138  hugepagesize = 2<<20;
139  pagesize = 4<<10;
140  vpm->log2_n_bytes_per_page = min_log2 (hugepagesize);
141  vec_resize (vpm->page_table, pm->mem_size / hugepagesize);
142 
144  vpm->virtual.start = pointer_to_uword (pm->mem);
145  vpm->virtual.size = pm->mem_size;
146  vpm->virtual.end = vpm->virtual.start + vpm->virtual.size;
147 
148  fd = open("/proc/self/pagemap", O_RDONLY);
149 
150  if (fd < 0)
151  {
152  (void) shmdt (pm->mem);
153  return 0;
154  }
155 
157  (pm->mem, pm->mem_size,
158  /* Don't want mheap mmap/munmap with IO memory. */
160 
161  cur = pointer_to_uword(pm->mem);
162  i = 0;
163 
164  while (cur < pointer_to_uword(pm->mem) + pm->mem_size)
165  {
166  pfn = (u64) cur / pagesize;
167  seek_loc = pfn * sizeof (u64);
168  if (lseek (fd, seek_loc, SEEK_SET) != seek_loc)
169  {
170  clib_unix_warning ("lseek to 0x%llx", seek_loc);
171  shmctl (pm->shmid, IPC_RMID, 0);
172  close(fd);
173  return 0;
174  }
175  if (read (fd, &ptbits, sizeof (ptbits)) != (sizeof(ptbits)))
176  {
177  clib_unix_warning ("read ptbits");
178  shmctl (pm->shmid, IPC_RMID, 0);
179  close(fd);
180  return 0;
181  }
182 
183  /* bits 0-54 are the physical page number */
184  physaddr = (ptbits & 0x7fffffffffffffULL) * pagesize;
185  if (CLIB_DEBUG > 1)
186  fformat(stderr, "pm: virtual 0x%llx physical 0x%llx\n",
187  cur, physaddr);
188  vpm->page_table[i++] = physaddr;
189 
190  cur += hugepagesize;
191  }
192  close(fd);
193  atexit (htlb_shutdown);
194  return 1;
195 }
196 
198  physmem_main_t * pm, int) __attribute__ ((weak));
200 {
201  return 0;
202 }
203 
204 clib_error_t * unix_physmem_init (vlib_main_t * vm, int physical_memory_required)
205 {
206  vlib_physmem_main_t * vpm = &vm->physmem_main;
208  clib_error_t * error = 0;
209  char * dev_uio_dma_file = "/dev/uio-dma";
210  int using_fake_memory = 0;
211 
212  /* Avoid multiple calls. */
213  if (vm->os_physmem_alloc_aligned)
214  return error;
215 
218  pm->mem = MAP_FAILED;
219 
220  if (pm->mem_size == 0)
221  pm->mem_size = 16 << 20;
222 
223  /* OK, Mr. App, you tell us */
224  if (vlib_app_physmem_init (vm, pm, physical_memory_required))
225  return 0;
226 
227  if (physical_memory_required)
228  {
229  if (!pm->no_hugepages && htlb_init(vm))
230  {
231  fformat(stderr, "%s: use huge pages\n", __FUNCTION__);
232  return 0;
233  }
234  pm->uio_dma_fd = open (dev_uio_dma_file, O_RDWR);
235  }
236  else
237  pm->uio_dma_fd = -1;
238 
239  if (pm->uio_dma_fd < 0)
240  {
241  if (physical_memory_required)
242  {
243  error = clib_error_return_unix (0, "open `%s'", dev_uio_dma_file);
244  goto done;
245  }
246 
247  using_fake_memory = 1;
248  pm->mem = mmap (0, pm->mem_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
249  if (pm->mem == MAP_FAILED)
250  {
251  error = clib_error_return_unix (0, "mmap");
252  goto done;
253  }
254 
255  pm->heap = mheap_alloc (pm->mem, pm->mem_size);
256 
257  /* Identity map with a single page. */
259  vec_add1 (vpm->page_table, pointer_to_uword (pm->mem));
260  }
261  else
262  error = clib_error_return (0, "uio_dma deprecated");
263 
265  vpm->virtual.start = pointer_to_uword (pm->mem);
266  vpm->virtual.size = pm->mem_size;
267  vpm->virtual.end = vpm->virtual.start + vpm->virtual.size;
268 
269  if (using_fake_memory)
270  fformat(stderr, "%s: use fake dma pages\n", __FUNCTION__);
271  else
272  fformat(stderr, "%s: use uio dma pages\n", __FUNCTION__);
273 
274  done:
275  if (error)
276  {
277  if (pm->mem != MAP_FAILED)
278  munmap (pm->mem, pm->mem_size);
279  if (pm->uio_dma_fd >= 0)
280  {
281  close (pm->uio_dma_fd);
282  pm->uio_dma_fd = -1;
283  }
284  }
285  return error;
286 }
287 
288 static clib_error_t *
290  unformat_input_t * input,
291  vlib_cli_command_t * cmd)
292 {
293 #if DPDK > 0
294  vlib_cli_output (vm, "Not supported with DPDK drivers.");
295 #else
297 
298  if (pm->heap)
299  vlib_cli_output (vm, "%U", format_mheap, pm->heap, /* verbose */ 0);
300  else
301  vlib_cli_output (vm, "No physmem allocated.");
302 #endif
303  return 0;
304 }
305 
306 VLIB_CLI_COMMAND (show_physmem_command, static) = {
307  .path = "show physmem",
308  .short_help = "Show physical memory allocation",
309  .function = show_physmem,
310 };
311 
312 static clib_error_t *
314  unformat_input_t * input,
315  vlib_cli_command_t * cmd)
316 {
317  cpu_set_t set;
318  cpu_set_t *setp = &set;
319  int i, rv;
320  u8 *s = 0;
321  int first_set_bit_in_run = -1;
322  int last_set_bit_in_run = -1;
323  int output_done = 0;
324 
325  rv = sched_getaffinity (0 /* pid, 0 = this proc */,
326  sizeof (*setp), setp);
327  if (rv < 0)
328  {
329  vlib_cli_output (vm, "Couldn't get affinity mask: %s\n",
330  strerror(errno));
331  return 0;
332  }
333 
334  for (i = 0; i < 64; i++)
335  {
336  if (CPU_ISSET(i, setp))
337  {
338  if (first_set_bit_in_run == -1)
339  {
340  first_set_bit_in_run = i;
341  last_set_bit_in_run = i;
342  if (output_done)
343  s = format (s, ",");
344  s = format (s, "%d-", i);
345  output_done = 1;
346  }
347  else
348  {
349  if (i == (last_set_bit_in_run+1))
350  last_set_bit_in_run = i;
351  }
352  }
353  else
354  {
355  if (first_set_bit_in_run != -1)
356  {
357  if (first_set_bit_in_run == (i-1))
358  {
359  _vec_len (s) -= 2 + ((first_set_bit_in_run/10));
360  }
361  s = format (s, "%d", last_set_bit_in_run);
362  first_set_bit_in_run = -1;
363  last_set_bit_in_run = -1;
364  }
365  }
366  }
367 
368  if (first_set_bit_in_run != -1)
369  s = format (s, "%d", first_set_bit_in_run);
370 
371  vlib_cli_output (vm, "Process runs on: %v", s);
372  return 0;
373 }
374 
375 VLIB_CLI_COMMAND (show_affinity_command, static) = {
376  .path = "show affinity",
377  .short_help = "Show process cpu affinity",
378  .function = show_affinity,
379 };
380 
381 static clib_error_t *
383  unformat_input_t * input,
384  vlib_cli_command_t * cmd)
385 {
386  cpu_set_t set;
387  cpu_set_t *setp = &set;
388  int i, rv;
389  int another_round;
390  u32 first, last;
391 
392  memset (setp, 0, sizeof (*setp));
393 
394  do {
395  another_round = 0;
396  if (unformat (input, "%d-%d,", &first, &last))
397  {
398  if (first > 64 || last > 64)
399  {
400  barf1:
401  vlib_cli_output (vm, "range %d-%d invalid", first, last);
402  return 0;
403  }
404 
405  for (i = first; i <= last; i++)
406  CPU_SET(i, setp);
407  another_round = 1;
408  }
409  else if (unformat (input, "%d-%d", &first, &last))
410  {
411  if (first > 64 || last > 64)
412  goto barf1;
413 
414  for (i = first; i <= last; i++)
415  CPU_SET(i, setp);
416  }
417  else if (unformat (input, "%d,", &first))
418  {
419  if (first > 64)
420  {
421  barf2:
422  vlib_cli_output (vm, "cpu %d invalid", first);
423  return 0;
424  }
425  CPU_SET(first, setp);
426  another_round = 1;
427  }
428  else if (unformat (input, "%d", &first))
429  {
430  if (first > 64)
431  goto barf2;
432 
433  CPU_SET(first, setp);
434  }
435  } while (another_round);
436 
437  rv = sched_setaffinity (0 /* pid, 0 = this proc */,
438  sizeof (*setp), setp);
439 
440  if (rv < 0)
441  {
442  vlib_cli_output (vm, "Couldn't get affinity mask: %s\n",
443  strerror(errno));
444  return 0;
445  }
446  return show_affinity (vm, input, cmd);
447 }
448 
449 VLIB_CLI_COMMAND (set_affinity_command, static) = {
450  .path = "set affinity",
451  .short_help = "Set process cpu affinity",
452  .function = set_affinity,
453 };
454 
455 static clib_error_t *
457 {
459  u32 size_in_mb;
460 
462  {
463  if (unformat (input, "no-huge") || unformat (input, "no-huge-pages"))
464  pm->no_hugepages = 1;
465 
466  else if (unformat(input, "size-in-mb %d", &size_in_mb) ||
467  unformat(input, "size %d", &size_in_mb))
468  pm->mem_size = size_in_mb << 20;
469  else
470  return unformat_parse_error (input);
471  }
472 
473  unformat_free (input);
474  return 0;
475 }
476 
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:267
uword unformat(unformat_input_t *i, char *fmt,...)
Definition: unformat.c:942
static void(BVT(clib_bihash)*h, BVT(clib_bihash_value)*v)
static clib_error_t * set_affinity(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: physmem.c:382
vlib_physmem_main_t physmem_main
Definition: main.h:105
void * mheap_alloc(void *memory, uword size)
Definition: mheap.c:908
always_inline void unformat_free(unformat_input_t *i)
Definition: format.h:160
#define UNFORMAT_END_OF_INPUT
Definition: format.h:142
#define NULL
Definition: clib.h:55
uword mem_size
Definition: physmem.h:46
void *(* os_physmem_alloc_aligned)(vlib_physmem_main_t *pm, uword n_bytes, uword alignment)
Definition: main.h:109
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:480
static physmem_main_t physmem_main
Definition: physmem.c:42
u8 * format_mheap(u8 *s, va_list *va)
Definition: mheap.c:1113
int vlib_app_physmem_init(vlib_main_t *vm, physmem_main_t *pm, int)
Definition: physmem.c:199
always_inline uword unformat_check_input(unformat_input_t *i)
Definition: format.h:168
always_inline heap_elt_t * last(heap_header_t *h)
Definition: heap.c:51
static int htlb_init(vlib_main_t *vm)
Definition: physmem.c:111
#define MHEAP_FLAG_DISABLE_VM
void * mem
Definition: physmem.h:43
#define clib_warning(format, args...)
Definition: error.h:59
unsigned long u64
Definition: types.h:89
#define vec_resize(V, N)
Resize a vector (no header, unspecified alignment) Add N elements to end of given vector V...
Definition: vec.h:199
static uword pointer_to_uword(const void *p)
Definition: types.h:131
always_inline heap_elt_t * first(heap_header_t *h)
Definition: heap.c:54
#define clib_error_return_unix(e, args...)
Definition: error.h:115
#define unformat_parse_error(input)
Definition: format.h:265
static clib_error_t * vlib_physmem_configure(vlib_main_t *vm, unformat_input_t *input)
Definition: physmem.c:456
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:538
static void * unix_physmem_alloc_aligned(vlib_physmem_main_t *vpm, uword n_bytes, uword alignment)
Definition: physmem.c:45
static void htlb_shutdown(void)
Definition: physmem.c:100
static clib_error_t * show_affinity(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: physmem.c:313
void * heap
Definition: physmem.h:49
#define VLIB_EARLY_CONFIG_FUNCTION(x, n,...)
Definition: init.h:137
void * mheap_get_aligned(void *v, uword n_user_data_bytes, uword align, uword align_offset, uword *offset_return)
Definition: mheap.c:621
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:298
#define clib_unix_warning(format, args...)
Definition: error.h:68
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:150
void * mheap_alloc_with_flags(void *memory, uword memory_size, uword flags)
Definition: mheap.c:842
unsigned int u32
Definition: types.h:88
int no_hugepages
Definition: physmem.h:55
u8 * format(u8 *s, char *fmt,...)
Definition: format.c:405
int uio_dma_fd
Definition: physmem.h:40
#define clib_max(x, y)
Definition: clib.h:288
uword log2_n_bytes_per_page
Definition: physmem.h:50
u64 uword
Definition: types.h:112
static void unix_physmem_free(void *x)
Definition: physmem.c:92
static clib_error_t * show_physmem(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: physmem.c:289
void mheap_put(void *v, uword uoffset)
Definition: mheap.c:728
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
unsigned char u8
Definition: types.h:56
clib_error_t * unix_physmem_init(vlib_main_t *vm, int physical_memory_required)
Definition: physmem.c:204
word fformat(FILE *f, char *fmt,...)
Definition: format.c:437
vlib_physmem_region_t virtual
Definition: physmem.h:48
always_inline uword min_log2(uword x)
Definition: clib.h:181
#define clib_error_return(e, args...)
Definition: error.h:112
struct _unformat_input_t unformat_input_t
always_inline uword pow2_mask(uword x)
Definition: clib.h:242
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:67
void(* os_physmem_free)(void *x)
Definition: main.h:112