summaryrefslogtreecommitdiffstats
path: root/src/vnet/ip-neighbor/ip_neighbor_api.c
blob: 81af86211de9840d0030bdeee9901a1947b839cf (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

@media only all and (prefers-color-scheme: dark) {
.highlight .hll { background-color: #49483e }
.highlight .c { color: #75715e } /* Comment */
.highlight .err { color: #960050; background-color: #1e0010 } /* Error */
.highlight .k { color: #66d9ef } /* Keyword */
.highlight .l { color: #ae81ff } /* Literal */
.highlight .n { color: #f8f8f2 } /* Name */
.highlight .o { color: #f92672 } /* Operator */
.highlight .p { color: #f8f8f2 } /* Punctuation */
.highlight .ch { color: #75715e } /* Comment.Hashbang */
.highlight .cm { color: #75715e } /* Comment.Multiline */
.highlight .cp { color: #75715e } /* Comment.Preproc */
.highlight .cpf { color: #75715e } /* Comment.PreprocFile */
.highlight .c1 { color: #75715e } /* Comment.Single */
.highlight .cs { color: #75715e } /* Comment.Special */
.highlight .gd { color: #f92672 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gi { color: #a6e22e } /* Generic.Inserted */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #75715e } /* Generic.Subheading */
.highlight .kc { color: #66d9ef } /* Keyword.Constant */
.highlight .kd { color: #66d9ef } /* Keyword.Declaration */
.highlight .kn { color: #f92672 } /* Keyword.Namespace */
.highlight .kp { color: #66d9ef } /* Keyword.Pseudo */
.highlight .kr { color: #66d9ef } /* Keyword.Reserved */
.highlight .kt { color: #66d9ef } /* 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 */
}
Changes needed to DPDK are stored here as git patch files. Maintaining these
files using “git format-patch” and “git am” will make it simpler to manage
these changes. Patches made to DPDK should only be temporary until they are
accepted upstream and made available in the next DPDK release.

The following is the method used to generate these patches:

1. Git clone the package to a new directory:
 # git clone http://dpdk.org/git/dpdk dpdk

2. Create a branch based on the release you wish to patch.
Note, “git tag” will show you all the release tags. The following example is
for release tag “v2.2.0” and will create a branch named “two_dot_two”.
 # cd <root dir>
 # git checkout -b two_dot_two v2.2.0

3. Apply all the existing patches to this new branch.
 # git am </path/to/existing/patches/*>

4. Make your changes and commit your change to your repository.
 # <edit files>
 # git commit -s

5. Create the patch files with format-patch. This creates all the patch files
for your branch (two_dot_two), with your latest commits as the last ones.
 # git format-patch main..two_dot_two

6. Copy, add and commit the new patches into the patches directory.
'n358' href='#n358'>358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
/*
 *------------------------------------------------------------------
 * ip_api.c - vnet ip api
 *
 * Copyright (c) 2016 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 <stddef.h>

#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 <vlibapi/api.h>
#include <vlibmemory/api.h>

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

static u16 msg_id_base;
#define REPLY_MSG_ID_BASE msg_id_base

#include <vlibapi/api_helper_macros.h>

#include <vnet/format_fns.h>

static vl_api_ip_neighbor_flags_t
ip_neighbor_flags_encode (ip_neighbor_flags_t f)
{
  vl_api_ip_neighbor_flags_t v = IP_API_NEIGHBOR_FLAG_NONE;

  if (f & IP_NEIGHBOR_FLAG_STATIC)
    v |= IP_API_NEIGHBOR_FLAG_STATIC;
  if (f & IP_NEIGHBOR_FLAG_NO_FIB_ENTRY)
    v |= IP_API_NEIGHBOR_FLAG_NO_FIB_ENTRY;

  return (v);
}

static void
ip_neighbor_encode (vl_api_ip_neighbor_t * api, const ip_neighbor_t * ipn)
{
  api->sw_if_index = htonl (ipn->ipn_key->ipnk_sw_if_index);
  api->flags = ip_neighbor_flags_encode (ipn->ipn_flags);

  ip_address_encode2 (&ipn->ipn_key->ipnk_ip, &api->ip_address);
  mac_address_encode (&ipn->ipn_mac, api->mac_address);
}

void
ip_neighbor_handle_event (ip_neighbor_event_t * ipne)
{
  vl_api_registration_t *reg;
  ip_neighbor_t *ipn;

  ipn = &ipne->ipne_nbr;

  if (NULL == ipn)
    /* Client can cancel, die, etc. */
    return;

  /* Customer(s) requesting event for this neighbor */
  reg = vl_api_client_index_to_registration (ipne->ipne_watch.ipw_client);
  if (!reg)
    return;

  if (vl_api_can_send_msg (reg))
    {
      if (1 == ipne->ipne_watch.ipw_api_version)
	{
	  vl_api_ip_neighbor_event_t *mp;

	  mp = vl_msg_api_alloc (sizeof (*mp));
	  clib_memset (mp, 0, sizeof (*mp));
	  mp->_vl_msg_id =
	    ntohs (VL_API_IP_NEIGHBOR_EVENT + REPLY_MSG_ID_BASE);
	  mp->client_index = ipne->ipne_watch.ipw_client;
	  mp->pid = ipne->ipne_watch.ipw_pid;

	  ip_neighbor_encode (&mp->neighbor, ipn);

	  vl_api_send_msg (reg, (u8 *) mp);
	}
      else if (2 == ipne->ipne_watch.ipw_api_version)
	{
	  vl_api_ip_neighbor_event_v2_t *mp;

	  mp = vl_msg_api_alloc (sizeof (*mp));
	  clib_memset (mp, 0, sizeof (*mp));
	  mp->_vl_msg_id =
	    ntohs (VL_API_IP_NEIGHBOR_EVENT_V2 + REPLY_MSG_ID_BASE);
	  mp->client_index = ipne->ipne_watch.ipw_client;
	  mp->pid = ipne->ipne_watch.ipw_pid;
	  mp->flags = clib_host_to_net_u32 (ipne->ipne_flags);

	  ip_neighbor_encode (&mp->neighbor, ipn);

	  vl_api_send_msg (reg, (u8 *) mp);
	}
    }
  else
    {
      static f64 last_time;
      /*
       * Throttle syslog msgs.
       * It's pretty tempting to just revoke the registration...
       */
      if (vlib_time_now (vlib_get_main ()) > last_time + 10.0)
	{
	  clib_warning ("neighbor event for %U to pid %d: queue stuffed!",
			format_ip_address, &ipn->ipn_key->ipnk_ip,
			ipne->ipne_watch.ipw_pid);
	  last_time = vlib_time_now (vlib_get_main ());
	}
    }

  ip_neighbor_free (ipn);
}

typedef struct ip_neighbor_dump_ctx_t_
{
  vl_api_registration_t *reg;
  u32 context;
} ip_neighbor_dump_ctx_t;

static walk_rc_t
send_ip_neighbor_details (index_t ipni, void *arg)
{
  ip_neighbor_dump_ctx_t *ctx = arg;
  vl_api_ip_neighbor_details_t *mp;
  ip_neighbor_t *ipn;

  ipn = ip_neighbor_get (ipni);
  mp = vl_msg_api_alloc (sizeof (*mp));
  clib_memset (mp, 0, sizeof (*mp));
  mp->_vl_msg_id = ntohs (VL_API_IP_NEIGHBOR_DETAILS + REPLY_MSG_ID_BASE);
  mp->context = ctx->context;
  mp->age =
    clib_host_to_net_f64 ((vlib_time_now (vlib_get_main ()) -
			   ipn->ipn_time_last_updated));
  ip_neighbor_encode (&mp->neighbor, ipn);

  vl_api_send_msg (ctx->reg, (u8 *) mp);

  return (WALK_CONTINUE);
}

static void
vl_api_ip_neighbor_dump_t_handler (vl_api_ip_neighbor_dump_t * mp)
{
  vl_api_registration_t *reg;
  ip_address_family_t af;
  int rv;

  reg = vl_api_client_index_to_registration (mp->client_index);
  if (!reg)
    return;

  u32 sw_if_index = ntohl (mp->sw_if_index);

  rv = ip_address_family_decode (mp->af, &af);

  if (rv)
    return;

  ip_neighbor_dump_ctx_t ctx = {
    .reg = reg,
    .context = mp->context,
  };

  // walk all neighbours on all interfaces
  ip_neighbor_walk (af, sw_if_index, send_ip_neighbor_details, &ctx);
}

static ip_neighbor_flags_t
ip_neighbor_flags_decode (vl_api_ip_neighbor_flags_t v)
{
  ip_neighbor_flags_t f = IP_NEIGHBOR_FLAG_NONE;

  if (v & IP_API_NEIGHBOR_FLAG_STATIC)
    f |= IP_NEIGHBOR_FLAG_STATIC;
  if (v & IP_API_NEIGHBOR_FLAG_NO_FIB_ENTRY)
    f |= IP_NEIGHBOR_FLAG_NO_FIB_ENTRY;

  return (f);
}

static void
vl_api_ip_neighbor_add_del_t_handler (vl_api_ip_neighbor_add_del_t * mp,
				      vlib_main_t * vm)
{
  vl_api_ip_neighbor_add_del_reply_t *rmp;
  ip_neighbor_flags_t flags;
  u32 stats_index = ~0;
  ip_address_t ip = ip_address_initializer;
  mac_address_t mac;
  int rv;

  VALIDATE_SW_IF_INDEX ((&mp->neighbor));

  flags = ip_neighbor_flags_decode (mp->neighbor.flags);
  ip_address_decode2 (&mp->neighbor.ip_address, &ip);
  mac_address_decode (mp->neighbor.mac_address, &mac);

  /* must be static or dynamic, default to dynamic */
  if (!(flags & IP_NEIGHBOR_FLAG_STATIC) &&
      !(flags & IP_NEIGHBOR_FLAG_DYNAMIC))
    flags |= IP_NEIGHBOR_FLAG_DYNAMIC;

  /*
   * there's no validation here of the ND/ARP entry being added.
   * The expectation is that the FIB will ensure that nothing bad
   * will come of adding bogus entries.
   */
  if (mp->is_add)
    rv = ip_neighbor_add (&ip, &mac,
			  ntohl (mp->neighbor.sw_if_index),
			  flags, &stats_index);
  else
    rv = ip_neighbor_del (&ip, ntohl (mp->neighbor.sw_if_index));

  BAD_SW_IF_INDEX_LABEL;

  /* *INDENT-OFF* */
  REPLY_MACRO2 (VL_API_IP_NEIGHBOR_ADD_DEL_REPLY,
  ({
    rmp->stats_index = htonl (stats_index);
  }));
  /* *INDENT-ON* */
}

static void
vl_api_want_ip_neighbor_events_t_handler (vl_api_want_ip_neighbor_events_t *
					  mp)
{
  vl_api_want_ip_neighbor_events_reply_t *rmp;
  ip_address_t ip;
  int rv = 0;

  if (mp->sw_if_index != ~0)
    VALIDATE_SW_IF_INDEX (mp);
  ip_address_decode2 (&mp->ip, &ip);

  ip_neighbor_watcher_t watch = {
    .ipw_client = mp->client_index,
    .ipw_pid = mp->pid,
    .ipw_api_version = 1,
  };

  if (mp->enable)
    ip_neighbor_watch (&ip, ntohl (mp->sw_if_index), &watch);
  else
    ip_neighbor_unwatch (&ip, ntohl (mp->sw_if_index), &watch);

  BAD_SW_IF_INDEX_LABEL;
  REPLY_MACRO (VL_API_WANT_IP_NEIGHBOR_EVENTS_REPLY);
}

static void
  vl_api_want_ip_neighbor_events_v2_t_handler
  (vl_api_want_ip_neighbor_events_v2_t * mp)
{
  vl_api_want_ip_neighbor_events_reply_t *rmp;
  ip_address_t ip;
  int rv = 0;

  if (mp->sw_if_index != ~0)
    VALIDATE_SW_IF_INDEX (mp);
  ip_address_decode2 (&mp->ip, &ip);

  ip_neighbor_watcher_t watch = {
    .ipw_client = mp->client_index,
    .ipw_pid = mp->pid,
    .ipw_api_version = 2,
  };

  if (mp->enable)
    ip_neighbor_watch (&ip, ntohl (mp->sw_if_index), &watch);
  else
    ip_neighbor_unwatch (&ip, ntohl (mp->sw_if_index), &watch);

  BAD_SW_IF_INDEX_LABEL;
  REPLY_MACRO (VL_API_WANT_IP_NEIGHBOR_EVENTS_V2_REPLY);
}

static void
vl_api_ip_neighbor_config_t_handler (vl_api_ip_neighbor_config_t * mp)
{
  vl_api_ip_neighbor_config_reply_t *rmp;
  ip_address_family_t af;
  int rv;

  rv = ip_address_family_decode (mp->af, &af);

  if (!rv)
    rv = ip_neighbor_config (af,
			     ntohl (mp->max_number),
			     ntohl (mp->max_age), mp->recycle);

  REPLY_MACRO (VL_API_IP_NEIGHBOR_CONFIG_REPLY);
}

static void
vl_api_ip_neighbor_replace_begin_t_handler (vl_api_ip_neighbor_replace_begin_t
					    * mp)
{
  vl_api_ip_neighbor_replace_begin_reply_t *rmp;
  int rv = 0;

  ip_neighbor_mark (AF_IP4);
  ip_neighbor_mark (AF_IP6);

  REPLY_MACRO (VL_API_IP_NEIGHBOR_REPLACE_BEGIN_REPLY);
}

static void
vl_api_ip_neighbor_replace_end_t_handler (vl_api_ip_neighbor_replace_end_t *
					  mp)
{
  vl_api_ip_neighbor_replace_end_reply_t *rmp;
  int rv = 0;

  ip_neighbor_sweep (AF_IP4);
  ip_neighbor_sweep (AF_IP6);

  REPLY_MACRO (VL_API_IP_NEIGHBOR_REPLACE_END_REPLY);
}

static void
vl_api_ip_neighbor_flush_t_handler (vl_api_ip_neighbor_flush_t * mp)
{
  vl_api_ip_neighbor_flush_reply_t *rmp;
  ip_address_family_t af;
  int rv;

  if (mp->sw_if_index != ~0)
    VALIDATE_SW_IF_INDEX (mp);

  rv = ip_address_family_decode (mp->af, &af);

  if (!rv)
    ip_neighbor_del_all (af, ntohl (mp->sw_if_index));

  BAD_SW_IF_INDEX_LABEL;
  REPLY_MACRO (VL_API_IP_NEIGHBOR_FLUSH_REPLY);
}

#define vl_msg_name_crc_list
#include <vnet/ip-neighbor/ip_neighbor.api.h>
#undef vl_msg_name_crc_list

#include <vnet/ip-neighbor/ip_neighbor.api.c>

static clib_error_t *
ip_neighbor_api_init (vlib_main_t * vm)
{
  /* Ask for a correctly-sized block of API message decode slots */
  msg_id_base = setup_message_id_table ();

  return 0;
}

VLIB_API_INIT_FUNCTION (ip_neighbor_api_init);

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