summaryrefslogtreecommitdiffstats
path: root/README.md
blob: 4cc283b5e530fd12246a33599306cb375fdc26ac (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
Vector Packet Processing
========================

## Introduction

The VPP platform is an extensible framework that provides out-of-the-box
production quality switch/router functionality. It is the open source version
of Cisco's Vector Packet Processing (VPP) technology: a high performance,
packet-processing stack that can run on commodity CPUs.

The benefits of this implementation of VPP are its high performance, proven
technology, its modularity and flexibility, and rich feature set.

For more information on VPP and its features please visit the
[FD.io website](http://fd.io/) and
[What is VPP?](https://wiki.fd.io/view/VPP/What_is_VPP%3F) pages.


## Changes

Details of the changes leading up to this version of VPP can be found under
@ref release_notes.


## Directory layout

| Directory name         | Description                                 |
| ---------------------- | ------------------------------------------- |
|      build-data        | Build metadata                              |
|      build-root        | Build output directory                      |
|      doxygen           | Documentation generator configuration       |
|      dpdk              | DPDK patches and build infrastructure       |
| @ref extras/libmemif   | Client library for memif                    |
| @ref src/examples      | VPP example code                            |
| @ref src/plugins       | VPP bundled plugins directory               |
| @ref src/svm           | Shared virtual memory allocation library    |
|      src/tests         | Standalone tests (not part of test harness) |
|      src/vat           | VPP API test program                        |
| @ref src/vlib          | VPP application library                     |
| @ref src/vlibapi       | VPP API library                             |
| @ref src/vlibmemory    | VPP Memory management                       |
| @ref src/vnet          | VPP networking                              |
| @ref src/vpp           | VPP application                             |
| @ref src/vpp-api       | VPP application API bindings                |
| @ref src/vppinfra      | VPP core library                            |
| @ref src/vpp/api       | Not-yet-relocated API bindings              |
|      test              | Unit tests and Python test harness          |

## Getting started

In general anyone interested in building, developing or running VPP should
consult the [VPP wiki](https://wiki.fd.io/view/VPP) for more complete
documentation.

In particular, readers are recommended to take a look at [Pulling, Building,
Running, Hacking, Pushing](https://wiki.fd.io/view/VPP/Pulling,_Building,_Run
ning,_Hacking_and_Pushing_VPP_Code) which provides extensive step-by-step
coverage of the topic.

For the impatient, some salient information is distilled below.


### Quick-start: On an existing Linux host

To install system dependencies, build VPP and then install it, simply run the
build script. This should be performed a non-privileged user with `sudo`
access from the project base directory:

    ./extras/vagrant/build.sh

If you want a more fine-grained approach because you intend to do some
development work, the `Makefile` in the root directory of the source tree
provides several convenience shortcuts as `make` targets that may be of
interest. To see the available targets run:

    make


### Quick-start: Vagrant

The directory `extras/vagrant` contains a `VagrantFile` and supporting
scripts to bootstrap a working VPP inside a Vagrant-managed Virtual Machine.
This VM can then be used to test concepts with VPP or as a development
platform to extend VPP. Some obvious caveats apply when using a VM for VPP
since its performance will never match that of bare metal; if your work is
timing or performance sensitive, consider using bare metal in addition or
instead of the VM.

For this to work you will need a working installation of Vagrant. Instructions
for this can be found [on the Setting up Vagrant wiki page]
(https://wiki.fd.io/view/DEV/Setting_Up_Vagrant).


## More information

Several modules provide documentation, see @subpage user_doc for more
end-user-oriented information. Also see @subpage dev_doc for developer notes.

Visit the [VPP wiki](https://wiki.fd.io/view/VPP) for details on more
advanced building strategies and other development notes.


## Test Framework

There is PyDoc generated documentation available for the VPP test framework.
See @ref test_framework_doc for details.
light .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .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) 2015 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.
 */
/*
 * config.c: feature configuration
 *
 * Copyright (c) 2008 Eliot Dresselhaus
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <vnet/vnet.h>

static vnet_config_feature_t *
duplicate_feature_vector (vnet_config_feature_t * feature_vector)
{
  vnet_config_feature_t *result, *f;

  result = vec_dup (feature_vector);
  vec_foreach (f, result) f->feature_config = vec_dup (f->feature_config);

  return result;
}

static void
free_feature_vector (vnet_config_feature_t * feature_vector)
{
  vnet_config_feature_t *f;

  vec_foreach (f, feature_vector) vnet_config_feature_free (f);
  vec_free (feature_vector);
}

static u32
add_next (vlib_main_t * vm,
	  vnet_config_main_t * cm, u32 last_node_index, u32 this_node_index)
{
  u32 i, ni = ~0;

  if (last_node_index != ~0)
    return vlib_node_add_next (vm, last_node_index, this_node_index);

  for (i = 0; i < vec_len (cm->start_node_indices); i++)
    {
      u32 tmp;
      tmp =
	vlib_node_add_next (vm, cm->start_node_indices[i], this_node_index);
      if (ni == ~0)
	ni = tmp;
      /* Start nodes to first must agree on next indices. */
      ASSERT (ni == tmp);
    }

  return ni;
}

static vnet_config_t *
find_config_with_features (vlib_main_t * vm,
			   vnet_config_main_t * cm,
			   vnet_config_feature_t * feature_vector)
{
  u32 last_node_index = ~0;
  vnet_config_feature_t *f;
  u32 *config_string;
  uword *p;
  vnet_config_t *c;

  config_string = cm->config_string_temp;
  cm->config_string_temp = 0;
  if (config_string)
    _vec_len (config_string) = 0;

  vec_foreach (f, feature_vector)
  {
    /* Connect node graph. */
    f->next_index = add_next (vm, cm, last_node_index, f->node_index);
    last_node_index = f->node_index;

    /* Store next index in config string. */
    vec_add1 (config_string, f->next_index);

    /* Store feature config. */
    vec_add (config_string, f->feature_config, vec_len (f->feature_config));
  }

  /* Terminate config string with next for end node. */
  if (last_node_index == ~0 || last_node_index != cm->end_node_index)
    {
      u32 next_index = add_next (vm, cm, last_node_index, cm->end_node_index);
      vec_add1 (config_string, next_index);
    }

  /* See if config string is unique. */
  p = hash_get_mem (cm->config_string_hash, config_string);
  if (p)
    {
      /* Not unique.  Share existing config. */
      cm->config_string_temp = config_string;	/* we'll use it again later. */
      free_feature_vector (feature_vector);
      c = pool_elt_at_index (cm->config_pool, p[0]);
    }
  else
    {
      u32 *d;

      pool_get (cm->config_pool, c);
      c->index = c - cm->config_pool;
      c->features = feature_vector;
      c->config_string_vector = config_string;

      /* Allocate copy of config string in heap.
         VLIB buffers will maintain pointers to heap as they read out
         configuration data. */
      c->config_string_heap_index
	= heap_alloc (cm->config_string_heap, vec_len (config_string) + 1,
		      c->config_string_heap_handle);

      /* First element in heap points back to pool index. */
      d =
	vec_elt_at_index (cm->config_string_heap,
			  c->config_string_heap_index);
      d[0] = c->index;
      clib_memcpy (d + 1, config_string, vec_bytes (config_string));
      hash_set_mem (cm->config_string_hash, config_string, c->index);

      c->reference_count = 0;	/* will be incremented by caller. */
    }

  return c;
}

void
vnet_config_init (vlib_main_t * vm,
		  vnet_config_main_t * cm,
		  char *start_node_names[],
		  int n_start_node_names,
		  char *feature_node_names[], int n_feature_node_names)
{
  vlib_node_t *n;
  u32 i;

  memset (cm, 0, sizeof (cm[0]));

  cm->config_string_hash =
    hash_create_vec (0,
		     STRUCT_SIZE_OF (vnet_config_t, config_string_vector[0]),
		     sizeof (uword));

  ASSERT (n_feature_node_names >= 1);

  vec_resize (cm->start_node_indices, n_start_node_names);
  for (i = 0; i < n_start_node_names; i++)
    {
      n = vlib_get_node_by_name (vm, (u8 *) start_node_names[i]);
      /* Given node name must exist. */
      ASSERT (n != 0);
      cm->start_node_indices[i] = n->index;
    }

  vec_resize (cm->node_index_by_feature_index, n_feature_node_names);
  for (i = 0; i < n_feature_node_names; i++)
    {
      if (!feature_node_names[i])
	cm->node_index_by_feature_index[i] = ~0;
      else
	{
	  n = vlib_get_node_by_name (vm, (u8 *) feature_node_names[i]);
	  /* Given node may exist in plug-in library which is not present */
	  if (n)
	    {
	      if (i + 1 == n_feature_node_names)
		cm->end_node_index = n->index;
	      cm->node_index_by_feature_index[i] = n->index;
	    }
	  else
	    cm->node_index_by_feature_index[i] = ~0;
	}
    }
}

static void
remove_reference (vnet_config_main_t * cm, vnet_config_t * c)
{
  ASSERT (c->reference_count > 0);
  c->reference_count -= 1;
  if (c->reference_count == 0)
    {
      hash_unset (cm->config_string_hash, c->config_string_vector);
      vnet_config_free (cm, c);
      pool_put (cm->config_pool, c);
    }
}

static int
feature_cmp (void *a1, void *a2)
{
  vnet_config_feature_t *f1 = a1;
  vnet_config_feature_t *f2 = a2;

  return (int) f1->feature_index - f2->feature_index;
}

always_inline u32 *
vnet_get_config_heap (vnet_config_main_t * cm, u32 ci)
{
  return heap_elt_at_index (cm->config_string_heap, ci);
}

u32
vnet_config_add_feature (vlib_main_t * vm,
			 vnet_config_main_t * cm,
			 u32 config_string_heap_index,
			 u32 feature_index,
			 void *feature_config, u32 n_feature_config_bytes)
{
  vnet_config_t *old, *new;
  vnet_config_feature_t *new_features, *f;
  u32 n_feature_config_u32s;
  u32 node_index = vec_elt (cm->node_index_by_feature_index, feature_index);

  if (node_index == ~0)		// feature node does not exist
    return config_string_heap_index;	// return original config index

  if (config_string_heap_index == ~0)
    {
      old = 0;
      new_features = 0;
    }
  else
    {
      u32 *p = vnet_get_config_heap (cm, config_string_heap_index);
      old = pool_elt_at_index (cm->config_pool, p[-1]);
      new_features = old->features;
      if (new_features)
	new_features = duplicate_feature_vector (new_features);
    }

  vec_add2 (new_features, f, 1);
  f->feature_index = feature_index;
  f->node_index = node_index;

  n_feature_config_u32s =
    round_pow2 (n_feature_config_bytes,
		sizeof (f->feature_config[0])) /
    sizeof (f->feature_config[0]);
  vec_add (f->feature_config, feature_config, n_feature_config_u32s);

  /* Sort (prioritize) features. */
  if (vec_len (new_features) > 1)
    vec_sort_with_function (new_features, feature_cmp);

  if (old)
    remove_reference (cm, old);

  new = find_config_with_features (vm, cm, new_features);
  new->reference_count += 1;

  /*
   * User gets pointer to config string first element
   * (which defines the pool index
   * this config string comes from).
   */
  vec_validate (cm->config_pool_index_by_user_index,
		new->config_string_heap_index + 1);
  cm->config_pool_index_by_user_index[new->config_string_heap_index + 1]
    = new - cm->config_pool;
  return new->config_string_heap_index + 1;
}

u32
vnet_config_del_feature (vlib_main_t * vm,
			 vnet_config_main_t * cm,
			 u32 config_string_heap_index,
			 u32 feature_index,
			 void *feature_config, u32 n_feature_config_bytes)
{
  vnet_config_t *old, *new;
  vnet_config_feature_t *new_features, *f;
  u32 n_feature_config_u32s;

  {
    u32 *p = vnet_get_config_heap (cm, config_string_heap_index);

    old = pool_elt_at_index (cm->config_pool, p[-1]);
  }

  n_feature_config_u32s =
    round_pow2 (n_feature_config_bytes,
		sizeof (f->feature_config[0])) /
    sizeof (f->feature_config[0]);

  /* Find feature with same index and opaque data. */
  vec_foreach (f, old->features)
  {
    if (f->feature_index == feature_index
	&& vec_len (f->feature_config) == n_feature_config_u32s
	&& (n_feature_config_u32s == 0
	    || !memcmp (f->feature_config, feature_config,
			n_feature_config_bytes)))
      break;
  }

  /* Feature not found. */
  if (f >= vec_end (old->features))
    return config_string_heap_index;	// return original config index

  new_features = duplicate_feature_vector (old->features);
  f = new_features + (f - old->features);
  vnet_config_feature_free (f);
  vec_delete (new_features, 1, f - new_features);

  /* must remove old from config_pool now as it may be expanded and change
     memory location if the following function find_config_with_features()
     adds a new config because none of existing config's has matching features
     and so can be reused */
  remove_reference (cm, old);
  new = find_config_with_features (vm, cm, new_features);
  new->reference_count += 1;

  vec_validate (cm->config_pool_index_by_user_index,
		new->config_string_heap_index + 1);
  cm->config_pool_index_by_user_index[new->config_string_heap_index + 1]
    = new - cm->config_pool;
  return new->config_string_heap_index + 1;
}

/*
 * fd.io coding-style-patch-verification: ON
 *
 * Local Variables:
 * eval: (c-set-style "gnu")
 * End:
 */