summaryrefslogtreecommitdiffstats
path: root/src/vnet/devices
AgeCommit message (Expand)AuthorFilesLines
2017-02-14vhost-user: fix crash when descriptor points to unknown regionDamjan Marion1-1/+2
2017-02-06vlib: remove algned/unaligned buffers schemeDamjan Marion1-118/+13
2017-02-04dpdk: move to uio_pci_genericDamjan Marion1-1/+1
2017-02-03vhost-user: fix missing speculative enqueue unwindSteven1-0/+4
2017-02-02dpdk: fix crypto coverity warningSergio Gonzalez Monroy1-1/+2
2017-01-27dpdk: rework cryptodev ipsec build and setupSergio Gonzalez Monroy11-166/+287
2017-01-27dpdk : incorrect rx filter being installedPavel Kotucek3-1/+20
2017-01-19af_packet: multithreading supportMohsin KAZMI4-11/+86
2017-01-18Fix coverity warnings, VPP-608Dave Barach1-2/+6
2017-01-17Fix crash on deleting activated vhost-user - VPP-603Wojciech Dec1-3/+4
2017-01-17dpdk: remove duplicate code in buffers.cDamjan Marion1-122/+9
2017-01-16dpdk: add 'show dpdk version' cliDamjan Marion1-0/+20
2017-01-16dpdk: register rte_delay_us callback from vnetDamjan Marion1-0/+90
2017-01-14vlib: add buffer and thread callbacksDamjan Marion7-10/+827
2017-01-14VPP-279: Document changes for vnet/vnet/devicesBilly McFall3-3/+97
2017-01-13VPP-580: Host Interface created via Command Line Arg is misnamedBilly McFall1-1/+1
2017-01-10VPP-585: vhost-user interface deletion leaks memory.Ole Troan1-0/+7
2017-01-10API refactoring : dpdkPavel Kotucek2-0/+349
2017-01-09VPP-279: af_packet via Command-line Arg should no longer be supportedBilly McFall1-0/+3
2017-01-06VPP-279: doxygen documentation for host interface CLI commandsBilly McFall2-2/+65
2017-01-03VPP-574: fix VPP hang during security group configuration on a suspended VMAndrew Yourtchenko1-0/+4
2017-01-03Fix crash on null vhost-user socket - VPP-573Wojciech Dec1-0/+5
2016-12-28Reorganize source tree to use single autotools instanceDamjan Marion47-0/+22733
oat */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */ }
/*
 * Copyright (c) 2020 Cisco and/or its affiliates.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <vppinfra/clib.h>
#include <vppinfra/mem.h>
#include <vppinfra/time.h>
#include <vppinfra/format.h>
#include <vppinfra/clib_error.h>

/* while usage of dlmalloc APIs is genrally discouraged, in this particular
 * case there is significant benefit of calling them directly due to
 * smaller memory consuption (no wwp and headroom space) */
#include <vppinfra/dlmalloc.h>

#define CLIB_MEM_BULK_DEFAULT_MIN_ELTS_PER_CHUNK 32

typedef struct clib_mem_bulk_chunk_hdr
{
  u32 freelist;
  u32 n_free;
  struct clib_mem_bulk_chunk_hdr *prev, *next;
} clib_mem_bulk_chunk_hdr_t;

typedef struct
{
  u32 elt_sz;
  u32 chunk_hdr_sz;
  u32 elts_per_chunk;
  u32 align;
  u32 chunk_align;
  void *mspace;
  clib_mem_bulk_chunk_hdr_t *full_chunks, *avail_chunks;
} clib_mem_bulk_t;

static inline uword
bulk_chunk_size (clib_mem_bulk_t *b)
{
  return (uword) b->elts_per_chunk * b->elt_sz + b->chunk_hdr_sz;
}

__clib_export clib_mem_bulk_handle_t
clib_mem_bulk_init (u32 elt_sz, u32 align, u32 min_elts_per_chunk)
{
  clib_mem_heap_t *heap = clib_mem_get_heap ();
  clib_mem_bulk_t *b;
  uword sz;

  if ((b = mspace_memalign (heap->mspace, 16, sizeof (clib_mem_bulk_t))) == 0)
    return 0;

  if (align < 16)
    align = 16;

  if (min_elts_per_chunk == 0)
    min_elts_per_chunk = CLIB_MEM_BULK_DEFAULT_MIN_ELTS_PER_CHUNK;

  clib_mem_unpoison (b, sizeof (clib_mem_bulk_t));
  clib_memset (b, 0, sizeof (clib_mem_bulk_t));
  b->mspace = heap->mspace;
  b->align = align;
  b->elt_sz = round_pow2 (elt_sz, align);
  b->chunk_hdr_sz = round_pow2 (sizeof (clib_mem_bulk_chunk_hdr_t), align);
  b->elts_per_chunk = min_elts_per_chunk;
  sz = bulk_chunk_size (b);
  b->chunk_align = max_pow2 (sz);
  b->elts_per_chunk += (b->chunk_align - sz) / b->elt_sz;
  return b;
}

__clib_export void
clib_mem_bulk_destroy (clib_mem_bulk_handle_t h)
{
  clib_mem_bulk_t *b = h;
  clib_mem_bulk_chunk_hdr_t *c, *next;
  void *ms = b->mspace;

  c = b->full_chunks;

again:
  while (c)
    {
      next = c->next;
      clib_mem_poison (c, bulk_chunk_size (b));
      mspace_free (ms, c);
      c = next;
    }

  if (b->avail_chunks)
    {
      c = b->avail_chunks;
      b->avail_chunks = 0;
      goto again;
    }

  clib_mem_poison (b, sizeof (clib_mem_bulk_t));
  mspace_free (ms, b);
}

static inline void *
get_chunk_elt_ptr (clib_mem_bulk_t *b, clib_mem_bulk_chunk_hdr_t *c, u32 index)
{
  return (u8 *) c + b->chunk_hdr_sz + index * b->elt_sz;
}

static inline void
add_to_chunk_list (clib_mem_bulk_chunk_hdr_t **first,
		   clib_mem_bulk_chunk_hdr_t *c)
{
  c->next = *first;
  c->prev = 0;
  if (c->next)
    c->next->prev = c;
  *first = c;
}

static inline void
remove_from_chunk_list (clib_mem_bulk_chunk_hdr_t **first,
			clib_mem_bulk_chunk_hdr_t *c)
{
  if (c->next)
    c->next->prev = c->prev;
  if (c->prev)
    c->prev->next = c->next;
  else
    *first = c->next;
}

__clib_export void *
clib_mem_bulk_alloc (clib_mem_bulk_handle_t h)
{
  clib_mem_bulk_t *b = h;
  clib_mem_bulk_chunk_hdr_t *c = b->avail_chunks;
  u32 elt_idx;

  if (b->avail_chunks == 0)
    {
      u32 i, sz = bulk_chunk_size (b);
      c = mspace_memalign (b->mspace, b->chunk_align, sz);
      clib_mem_unpoison (c, sz);
      clib_memset (c, 0, sizeof (clib_mem_bulk_chunk_hdr_t));
      b->avail_chunks = c;
      c->n_free = b->elts_per_chunk;

      /* populate freelist */
      for (i = 0; i < b->elts_per_chunk - 1; i++)
	*((u32 *) get_chunk_elt_ptr (b, c, i)) = i + 1;
      *((u32 *) get_chunk_elt_ptr (b, c, i)) = ~0;
    }

  ASSERT (c->freelist != ~0);
  elt_idx = c->freelist;
  c->freelist = *((u32 *) get_chunk_elt_ptr (b, c, elt_idx));
  c->n_free--;

  if (c->n_free == 0)
    {
      /* chunk is full */
      ASSERT (c->freelist == ~0);
      remove_from_chunk_list (&b->avail_chunks, c);
      add_to_chunk_list (&b->full_chunks, c);
    }

  return get_chunk_elt_ptr (b, c, elt_idx);
}

__clib_export void
clib_mem_bulk_free (clib_mem_bulk_handle_t h, void *p)
{
  clib_mem_bulk_t *b = h;
  uword offset = (uword) p & (b->chunk_align - 1);
  clib_mem_bulk_chunk_hdr_t *c = (void *) ((u8 *) p - offset);
  u32 elt_idx = (offset - b->chunk_hdr_sz) / b->elt_sz;

  ASSERT (elt_idx < b->elts_per_chunk);
  ASSERT (get_chunk_elt_ptr (b, c, elt_idx) == p);

  c->n_free++;

  if (c->n_free == b->elts_per_chunk)
    {
      /* chunk is empty - give it back */
      remove_from_chunk_list (&b->avail_chunks, c);
      clib_mem_poison (c, bulk_chunk_size (b));
      mspace_free (b->mspace, c);
      return;
    }

  if (c->n_free == 1)
    {
      /* move chunk to avail chunks */
      remove_from_chunk_list (&b->full_chunks, c);
      add_to_chunk_list (&b->avail_chunks, c);
    }

  /* add elt to freelist */
  *(u32 *) p = c->freelist;
  c->freelist = elt_idx;
}

__clib_export u8 *
format_clib_mem_bulk (u8 *s, va_list *args)
{
  clib_mem_bulk_t *b = va_arg (*args, clib_mem_bulk_handle_t);
  clib_mem_bulk_chunk_hdr_t *c;
  uword n_chunks = 0, n_free_elts = 0, n_elts, chunk_sz;

  c = b->full_chunks;
  while (c)
    {
      n_chunks++;
      c = c->next;
    }

  c = b->avail_chunks;
  while (c)
    {
      n_chunks++;
      n_free_elts += c->n_free;
      c = c->next;
    }

  n_elts = n_chunks * b->elts_per_chunk;
  chunk_sz = b->chunk_hdr_sz + (uword) b->elts_per_chunk * b->elt_sz;

  s = format (s, "%u bytes/elt, align %u, chunk-align %u, ", b->elt_sz,
	      b->align, b->chunk_align);
  s = format (s, "%u elts-per-chunk, chunk size %lu bytes", b->elts_per_chunk,
	      chunk_sz);

  if (n_chunks == 0)
    return format (s, "\nempty");

  s = format (s, "\n%lu chunks allocated, ", n_chunks);
  s = format (s, "%lu / %lu free elts (%.1f%%), ", n_free_elts, n_elts,
	      (f64) n_free_elts * 100 / n_elts);
  s = format (s, "%lu bytes of memory consumed", n_chunks * chunk_sz);

  return s;
}