summaryrefslogtreecommitdiffstats
path: root/src/tests/vnet/README
blob: 10579e50e339859b733ad3ff4576294102fe6e01 (plain)
1
2
3
4
5
6
7
8
9
10
Unit test infrastructure for vnet

To run unit tests do the following:

  1. build vpp with 'vpp_enable_tests = yes' in build-data/platforms/vpp.mk

  2. go to build-root/build-$tag-$arch/vnet

  3. run
    $ make check
} /* Keyword.Type */ .highlight .ld { color: #e6db74 } /* Literal.Date */ .highlight .m { color: #ae81ff } /* Literal.Number */ .highlight .s { color: #e6db74 } /* Literal.String */ .highlight .na { color: #a6e22e } /* Name.Attribute */ .highlight .nb { color: #f8f8f2 } /* Name.Builtin */ .highlight .nc { color: #a6e22e } /* Name.Class */ .highlight .no { color: #66d9ef } /* Name.Constant */ .highlight .nd { color: #a6e22e } /* Name.Decorator */ .highlight .ni { color: #f8f8f2 } /* Name.Entity */ .highlight .ne { color: #a6e22e } /* Name.Exception */ .highlight .nf { color: #a6e22e } /* Name.Function */ .highlight .nl { color: #f8f8f2 } /* Name.Label */ .highlight .nn { color: #f8f8f2 } /* Name.Namespace */ .highlight .nx { color: #a6e22e } /* Name.Other */ .highlight .py { color: #f8f8f2 } /* Name.Property */ .highlight .nt { color: #f92672 } /* Name.Tag */ .highlight .nv { color: #f8f8f2 } /* Name.Variable */ .highlight .ow { color: #f92672 } /* Operator.Word */ .highlight .w { color: #f8f8f2 } /* Text.Whitespace */ .highlight .mb { color: #ae81ff } /* Literal.Number.Bin */ .highlight .mf { color: #ae81ff } /* Literal.Number.Float */ .highlight .mh { color: #ae81ff } /* Literal.Number.Hex */ .highlight .mi { color: #ae81ff } /* Literal.Number.Integer */ .highlight .mo { color: #ae81ff } /* Literal.Number.Oct */ .highlight .sa { color: #e6db74 } /* Literal.String.Affix */ .highlight .sb { color: #e6db74 } /* Literal.String.Backtick */ .highlight .sc { color: #e6db74 } /* Literal.String.Char */ .highlight .dl { color: #e6db74 } /* Literal.String.Delimiter */ .highlight .sd { color: #e6db74 } /* Literal.String.Doc */ .highlight .s2 { color: #e6db74 } /* Literal.String.Double */ .highlight .se { color: #ae81ff } /* Literal.String.Escape */ .highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */ .highlight .si { color: #e6db74 } /* Literal.String.Interpol */ .highlight .sx { color: #e6db74 } /* Literal.String.Other */ .highlight .sr { color: #e6db74 } /* Literal.String.Regex */ .highlight .s1 { color: #e6db74 } /* Literal.String.Single */ .highlight .ss { color: #e6db74 } /* Literal.String.Symbol */ .highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #a6e22e } /* Name.Function.Magic */ .highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */ .highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */ .highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */ .highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */ .highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */ } @media (prefers-color-scheme: light) { .highlight .hll { background-color: #ffffcc } .highlight .c { color: #888888 } /* Comment */ .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ .highlight .k { color: #008800; font-weight: bold } /* Keyword */ .highlight .ch { color: #888888 } /* Comment.Hashbang */ .highlight .cm { color: #888888 } /* Comment.Multiline */ .highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */ .highlight .cpf { color: #888888 } /* Comment.PreprocFile */ .highlight .c1 { color: #888888 } /* Comment.Single */ .highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */ .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .gr { color: #aa0000 } /* Generic.Error */ .highlight .gh { color: #333333 } /* Generic.Heading */ .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ .highlight .go { color: #888888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .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 */ }
/*
 * ip_neighboor_watch.c; IP neighbor watching
 *
 * Copyright (c) 2019 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 <vnet/ip-neighbor/ip_neighbor.h>
#include <vnet/ip-neighbor/ip_neighbor_watch.h>
#include <vnet/ip/ip_types_api.h>
#include <vnet/ethernet/ethernet_types_api.h>

#include <vnet/ip-neighbor/ip_neighbor.api_enum.h>
#include <vnet/ip-neighbor/ip_neighbor.api_types.h>

#include <vlibmemory/api.h>

/**
 * Database of registered watchers
 * The key for a watcher is {type, sw_if_index, addreess}
 * interface=~0 / address=all-zeros imples any.
 */
typedef struct ip_neighbor_watch_db_t_
{
  mhash_t ipnwdb_hash;
} ip_neighbor_watch_db_t;

static ip_neighbor_watch_db_t ipnw_db;

static uword
ip_neighbor_event_process (vlib_main_t * vm,
			   vlib_node_runtime_t * rt, vlib_frame_t * f)
{
  ip_neighbor_event_t *ipne, *ipnes = NULL;
  uword event_type = ~0;

  while (1)
    {
      vlib_process_wait_for_event (vm);

      ipnes = vlib_process_get_event_data (vm, &event_type);

      switch (event_type)
	{
	default:
	  vec_foreach (ipne, ipnes) ip_neighbor_handle_event (ipne);
	  break;

	case ~0:
	  /* timeout - */
	  break;
	}

      vec_reset_length (ipnes);
    }
  return 0;
}

/* *INDENT-OFF* */
VLIB_REGISTER_NODE (ip_neighbor_event_process_node) = {
  .function = ip_neighbor_event_process,
  .type = VLIB_NODE_TYPE_PROCESS,
  .name = "ip-neighbor-event",
};
/* *INDENT-ON* */


static clib_error_t *
want_ip_neighbor_events_reaper (u32 client_index)
{
  ip_neighbor_key_t *key, *empty_keys = NULL;
  ip_neighbor_watcher_t *watchers;
  uword *v;
  i32 pos;

  /* walk the entire IP neighbour DB and removes the client's registrations */
  /* *INDENT-OFF* */
  mhash_foreach(key, v, &ipnw_db.ipnwdb_hash,
  ({
    watchers = (ip_neighbor_watcher_t*) *v;

    vec_foreach_index_backwards (pos, watchers) {
      if (watchers[pos].ipw_client == client_index)
        vec_del1(watchers, pos);
    }

    if (vec_len(watchers) == 0)
      vec_add1 (empty_keys, *key);
  }));
  /* *INDENT-OFF* */

  vec_foreach (key, empty_keys)
    mhash_unset (&ipnw_db.ipnwdb_hash, key, NULL);
  vec_free (empty_keys);
  return (NULL);
}

VL_MSG_API_REAPER_FUNCTION (want_ip_neighbor_events_reaper);

static int
ip_neighbor_watch_cmp (const ip_neighbor_watcher_t * w1,
                       const ip_neighbor_watcher_t * w2)
{
  return (0 == clib_memcmp (w1, w2, sizeof(*w1)));
}

void
ip_neighbor_watch (const ip_address_t * ip,
		   u32 sw_if_index,
                   const ip_neighbor_watcher_t * watch)
{
  ip_neighbor_key_t key = {
    .ipnk_ip = *ip,
    .ipnk_sw_if_index = (sw_if_index == 0 ? ~0 : sw_if_index),
  };
  ip_neighbor_watcher_t *ipws = NULL;
  uword *p;

  p = mhash_get (&ipnw_db.ipnwdb_hash, &key);

  if (p)
    {
      ipws = (ip_neighbor_watcher_t*) p[0];

      if (~0 != vec_search_with_function (ipws, watch,
                                          ip_neighbor_watch_cmp))
        /* duplicate */
        return;
    }

  vec_add1 (ipws, *watch);

  mhash_set (&ipnw_db.ipnwdb_hash, &key, (uword) ipws, NULL);
}

void
ip_neighbor_unwatch (const ip_address_t * ip,
		     u32 sw_if_index,
                     const ip_neighbor_watcher_t * watch)
{
  ip_neighbor_key_t key = {
    .ipnk_ip = *ip,
    .ipnk_sw_if_index = (sw_if_index == 0 ? ~0 : sw_if_index),
  };
  ip_neighbor_watcher_t *ipws = NULL;
  uword *p;
  u32 pos;

  p = mhash_get (&ipnw_db.ipnwdb_hash, &key);

  if (!p)
    return;

  ipws = (ip_neighbor_watcher_t*) p[0];

  pos = vec_search_with_function (ipws, watch, ip_neighbor_watch_cmp);

  if (~0 == pos)
    return;

  vec_del1 (ipws, pos);

  if (vec_len(ipws) == 0)
    mhash_unset (&ipnw_db.ipnwdb_hash, &key, NULL);
}

static void
ip_neighbor_signal (ip_neighbor_watcher_t *watchers,
                    index_t ipni,
                    ip_neighbor_event_flags_t flags)
{
  ip_neighbor_watcher_t *watcher;

  vec_foreach (watcher, watchers) {
    ip_neighbor_event_t *ipne;

    ipne = vlib_process_signal_event_data (vlib_get_main(),
                                           ip_neighbor_event_process_node.index,
                                           0, 1, sizeof(*ipne));
    ipne->ipne_watch = *watcher;
    ipne->ipne_flags = flags;
    ip_neighbor_clone(ip_neighbor_get(ipni), &ipne->ipne_nbr);
  }
}

void
ip_neighbor_publish (index_t ipni,
                     ip_neighbor_event_flags_t flags)
{
  const ip_neighbor_t *ipn;
  ip_neighbor_key_t key;
  uword *p;

  ipn = ip_neighbor_get (ipni);

  clib_memcpy (&key, ipn->ipn_key, sizeof (key));

  /* Search the DB from longest to shortest key */
  p = mhash_get (&ipnw_db.ipnwdb_hash, &key);

  if (p) {
    ip_neighbor_signal ((ip_neighbor_watcher_t*) p[0], ipni, flags);
  }

  ip_address_reset (&key.ipnk_ip);
  p = mhash_get (&ipnw_db.ipnwdb_hash, &key);

  if (p) {
    ip_neighbor_signal ((ip_neighbor_watcher_t*) p[0], ipni, flags);
  }

  key.ipnk_sw_if_index = ~0;
  p = mhash_get (&ipnw_db.ipnwdb_hash, &key);

  if (p) {
    ip_neighbor_signal ((ip_neighbor_watcher_t*) p[0], ipni, flags);
  }
}

static clib_error_t *
ip_neighbor_watchers_show (vlib_main_t * vm,
                           unformat_input_t * input,
                           vlib_cli_command_t * cmd)
{
  ip_neighbor_watcher_t *watchers, *watcher;
  ip_neighbor_key_t *key;
  uword *v;

  /* *INDENT-OFF* */
  mhash_foreach(key, v, &ipnw_db.ipnwdb_hash,
  ({
    watchers = (ip_neighbor_watcher_t*) *v;

    ASSERT(vec_len(watchers));
    vlib_cli_output (vm, "Key: %U", format_ip_neighbor_key, key);

    vec_foreach (watcher, watchers)
      vlib_cli_output (vm, "  %U", format_ip_neighbor_watcher, watcher);
  }));
  /* *INDENT-ON* */
  return (NULL);
}

/* *INDENT-OFF* */
VLIB_CLI_COMMAND (show_ip_neighbor_watchers_cmd_node, static) = {
  .path = "show ip neighbor-watcher",
  .function = ip_neighbor_watchers_show,
  .short_help = "show ip neighbors-watcher",
};
/* *INDENT-ON* */

static clib_error_t *
ip_neighbor_watch_init (vlib_main_t * vm)
{
  mhash_init (&ipnw_db.ipnwdb_hash,
	      sizeof (ip_neighbor_watcher_t *), sizeof (ip_neighbor_key_t));
  return (NULL);
}

/* *INDENT-OFF* */
VLIB_INIT_FUNCTION (ip_neighbor_watch_init) =
{
  .runs_after = VLIB_INITS("ip_neighbor_init"),
};
/* *INDENT-ON* */


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