summaryrefslogtreecommitdiffstats
path: root/src/vpp-api/vapi/vapi_c_gen.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/vpp-api/vapi/vapi_c_gen.py')
-rwxr-xr-xsrc/vpp-api/vapi/vapi_c_gen.py188
1 files changed, 35 insertions, 153 deletions
diff --git a/src/vpp-api/vapi/vapi_c_gen.py b/src/vpp-api/vapi/vapi_c_gen.py
index 2bc1eef87e5..ef6e2663cf4 100755
--- a/src/vpp-api/vapi/vapi_c_gen.py
+++ b/src/vpp-api/vapi/vapi_c_gen.py
@@ -26,7 +26,7 @@ class CField(Field):
def get_swap_to_be_code(self, struct, var):
if self.len is not None:
if self.len > 0:
- return "do { int i; for (i = 0; i < %d; ++i) { %s } }"\
+ return "do { unsigned i; for (i = 0; i < %d; ++i) { %s } }"\
" while(0);" % (
self.len,
self.type.get_swap_to_be_code(struct, "%s[i]" % var))
@@ -38,7 +38,7 @@ class CField(Field):
else:
nelem_field = "%s%s" % (struct, self.nelem_field.name)
return (
- "do { int i; for (i = 0; i < %s; ++i) { %s } }"
+ "do { unsigned i; for (i = 0; i < %s; ++i) { %s } }"
" while(0);" %
(nelem_field, self.type.get_swap_to_be_code(
struct, "%s[i]" % var)))
@@ -47,14 +47,14 @@ class CField(Field):
def get_swap_to_host_code(self, struct, var):
if self.len is not None:
if self.len > 0:
- return "do { int i; for (i = 0; i < %d; ++i) { %s } }"\
+ return "do { unsigned i; for (i = 0; i < %d; ++i) { %s } }"\
" while(0);" % (
self.len,
self.type.get_swap_to_host_code(struct, "%s[i]" % var))
else:
# nelem_field already swapped to host here...
return (
- "do { int i; for (i = 0; i < %s%s; ++i) { %s } }"
+ "do { unsigned i; for (i = 0; i < %s%s; ++i) { %s } }"
" while(0);" %
(struct, self.nelem_field.name,
self.type.get_swap_to_host_code(
@@ -199,14 +199,17 @@ class CMessage (Message):
def get_alloc_func_name(self):
return "vapi_alloc_%s" % self.name
+ def get_alloc_vla_param_names(self):
+ return [self.get_alloc_func_vla_field_length_name(f)
+ for f in self.fields
+ if f.nelem_field is not None]
+
def get_alloc_func_decl(self):
return "%s* %s(struct vapi_ctx_s *ctx%s)" % (
self.get_c_name(),
self.get_alloc_func_name(),
- "".join([", size_t %s" %
- self.get_alloc_func_vla_field_length_name(f)
- for f in self.fields
- if f.nelem_field is not None]))
+ "".join([", size_t %s" % n for n in
+ self.get_alloc_vla_param_names()]))
def get_alloc_func_def(self):
extra = []
@@ -228,7 +231,8 @@ class CMessage (Message):
for f in self.fields
if f.nelem_field is not None
])),
- " msg = vapi_msg_alloc(ctx, size);",
+ " /* cast here required to play nicely with C++ world ... */",
+ " msg = (%s*)vapi_msg_alloc(ctx, size);" % self.get_c_name(),
" if (!msg) {",
" return NULL;",
" }",
@@ -441,7 +445,7 @@ class CMessage (Message):
def get_event_cb_func_decl(self):
if not self.is_reply():
raise Exception(
- "Cannot register event callback for non-reply function")
+ "Cannot register event callback for non-reply message")
if self.has_payload():
return "\n".join([
"void vapi_set_%s_event_cb (" %
@@ -498,7 +502,7 @@ class CMessage (Message):
' offsetof(%s, context),' % self.header.get_c_name()
if has_context else ' 0,',
(' offsetof(%s, payload),' % self.get_c_name())
- if self.has_payload() else '-1,',
+ if self.has_payload() else ' ~0,',
' sizeof(%s),' % self.get_c_name(),
' (generic_swap_fn_t)%s,' % self.get_swap_to_be_func_name(),
' (generic_swap_fn_t)%s,' % self.get_swap_to_host_func_name(),
@@ -529,8 +533,8 @@ vapi_send_with_control_ping (vapi_ctx_t ctx, void *msg, u32 context)
"""
-def gen_json_header(parser, logger, j, io):
- logger.info("Generating header `%s'" % io.name)
+def gen_json_unified_header(parser, logger, j, io, name):
+ logger.info("Generating header `%s'" % name)
orig_stdout = sys.stdout
sys.stdout = io
include_guard = "__included_%s" % (
@@ -538,131 +542,22 @@ def gen_json_header(parser, logger, j, io):
print("#ifndef %s" % include_guard)
print("#define %s" % include_guard)
print("")
- print("#include <vapi_internal.h>")
- print("")
- if io.name == "vpe.api.vapi.h":
- print("static inline vapi_error_e vapi_send_with_control_ping "
- "(vapi_ctx_t ctx, void * msg, u32 context);")
- print("")
- for m in parser.messages_by_json[j].values():
- print("extern vapi_msg_id_t %s;" % m.get_msg_id_name())
- print("")
- for t in parser.types_by_json[j].values():
- try:
- print("%s" % t.get_c_def())
- print("")
- except:
- pass
- for t in parser.types_by_json[j].values():
- print("%s;" % t.get_swap_to_be_func_decl())
- print("")
- print("%s;" % t.get_swap_to_host_func_decl())
- print("")
- for m in parser.messages_by_json[j].values():
- print("%s" % m.get_c_def())
- print("")
- for m in parser.messages_by_json[j].values():
- if not m.is_reply():
- print("%s;" % m.get_alloc_func_decl())
- print("")
- print("%s;" % m.get_op_func_decl())
- if m.has_payload():
- print("%s;" % m.get_swap_payload_to_be_func_decl())
- print("")
- print("%s;" % m.get_swap_payload_to_host_func_decl())
- print("")
- print("%s;" % m.get_calc_msg_size_func_decl())
- print("")
- print("%s;" % m.get_swap_to_host_func_decl())
- print("")
- print("%s;" % m.get_swap_to_be_func_decl())
- print("")
- for m in parser.messages_by_json[j].values():
- if not m.is_reply():
- continue
- print("%s;" % m.get_event_cb_func_decl())
- print("")
-
- if io.name == "vpe.api.vapi.h":
- print("%s" % vapi_send_with_control_ping)
- print("")
-
- print("#endif")
- sys.stdout = orig_stdout
-
-
-def gen_json_code(parser, logger, j, io):
- logger.info("Generating code `%s'" % io.name)
- orig_stdout = sys.stdout
- sys.stdout = io
- print("#include <%s>" % json_to_header_name(j))
print("#include <stdlib.h>")
print("#include <stddef.h>")
print("#include <arpa/inet.h>")
- print("#include <vapi_internal.h>")
- print("#include <vapi_dbg.h>")
- print("")
- for t in parser.types_by_json[j].values():
- print("%s" % t.get_swap_to_be_func_def())
- print("")
- print("%s" % t.get_swap_to_host_func_def())
- print("")
- for m in parser.messages_by_json[j].values():
- if m.has_payload():
- print("%s" % m.get_swap_payload_to_be_func_def())
- print("")
- print("%s" % m.get_swap_payload_to_host_func_def())
- print("")
- print("%s" % m.get_calc_msg_size_func_def())
- print("")
- print("%s" % m.get_swap_to_be_func_def())
- print("")
- print("%s" % m.get_swap_to_host_func_def())
- print("")
- for m in parser.messages_by_json[j].values():
- if m.is_reply():
- continue
- print("%s" % m.get_alloc_func_def())
- print("")
- print("%s" % m.get_op_func_def())
- print("")
+ print("#include <vapi/vapi_internal.h>")
+ print("#include <vapi/vapi.h>")
+ print("#include <vapi/vapi_dbg.h>")
print("")
- for m in parser.messages_by_json[j].values():
- print("%s" % m.get_c_constructor())
- print("")
- print("")
- for m in parser.messages_by_json[j].values():
- if not m.is_reply():
- continue
- print("%s;" % m.get_event_cb_func_def())
- print("")
- print("")
- for m in parser.messages_by_json[j].values():
- print("vapi_msg_id_t %s;" % m.get_msg_id_name())
- sys.stdout = orig_stdout
-
-
-def gen_json_unified_header(parser, logger, j, io):
- logger.info("Generating header `%s'" % io.name)
- orig_stdout = sys.stdout
- sys.stdout = io
- include_guard = "__included_%s" % (
- j.replace(".", "_").replace("/", "_").replace("-", "_"))
- print("#ifndef %s" % include_guard)
- print("#define %s" % include_guard)
- print("")
- print("#include <vapi_internal.h>")
- print("#include <vapi.h>")
- print("#include <stdlib.h>")
- print("#include <stddef.h>")
- print("#include <arpa/inet.h>")
- print("#include <vapi_dbg.h>")
- if io.name == "vpe.api.vapi.h":
+ print("#ifdef __cplusplus")
+ print("extern \"C\" {")
+ print("#endif")
+ if name == "vpe.api.vapi.h":
print("")
print("static inline vapi_error_e vapi_send_with_control_ping "
"(vapi_ctx_t ctx, void * msg, u32 context);")
else:
- print("#include <vpe.api.vapi.h>")
+ print("#include <vapi/vpe.api.vapi.h>")
print("")
for m in parser.messages_by_json[j].values():
print("extern vapi_msg_id_t %s;" % m.get_msg_id_name())
@@ -725,46 +620,33 @@ def gen_json_unified_header(parser, logger, j, io):
print("")
print("")
- if io.name == "vpe.api.vapi.h":
+ if name == "vpe.api.vapi.h":
print("%s" % vapi_send_with_control_ping)
print("")
+ print("#ifdef __cplusplus")
+ print("}")
+ print("#endif")
+ print("")
print("#endif")
sys.stdout = orig_stdout
-def json_to_header_name(json_name):
+def json_to_c_header_name(json_name):
if json_name.endswith(".json"):
return "%s.vapi.h" % os.path.splitext(json_name)[0]
raise Exception("Unexpected json name `%s'!" % json_name)
-def json_to_code_name(json_name):
- if json_name.endswith(".json"):
- return "%s.vapi.c" % os.path.splitext(json_name)[0]
- raise Exception("Unexpected json name `%s'!" % json_name)
-
-
-def gen_c_headers_and_code(parser, logger, prefix):
- if prefix == "" or prefix is None:
- prefix = ""
- else:
- prefix = "%s/" % prefix
- for j in parser.json_files:
- with open('%s%s' % (prefix, json_to_header_name(j)), "w") as io:
- gen_json_header(parser, logger, j, io)
- with open('%s%s' % (prefix, json_to_code_name(j)), "w") as io:
- gen_json_code(parser, logger, j, io)
-
-
def gen_c_unified_headers(parser, logger, prefix):
if prefix == "" or prefix is None:
prefix = ""
else:
prefix = "%s/" % prefix
for j in parser.json_files:
- with open('%s%s' % (prefix, json_to_header_name(j)), "w") as io:
- gen_json_unified_header(parser, logger, j, io)
+ with open('%s%s' % (prefix, json_to_c_header_name(j)), "w") as io:
+ gen_json_unified_header(
+ parser, logger, j, io, json_to_c_header_name(j))
if __name__ == '__main__':
@@ -784,7 +666,7 @@ if __name__ == '__main__':
logger = logging.getLogger("VAPI C GEN")
logger.setLevel(log_level)
- argparser = argparse.ArgumentParser(description="VPP JSON API parser")
+ argparser = argparse.ArgumentParser(description="VPP C API generator")
argparser.add_argument('files', metavar='api-file', action='append',
type=str, help='json api file'
'(may be specified multiple times)')
nce */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */ }
/*
 * gbp.h : Group Based Policy
 *
 * Copyright (c) 2018 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 <plugins/gbp/gbp_endpoint.h>
#include <plugins/gbp/gbp_endpoint_group.h>

#include <vnet/ethernet/arp_packet.h>

/**
 * IP4 destintion address to destination EPG mapping table
 */
typedef struct gbp_ip4_to_epg_db_t_
{
  /**
   * use a simple hash table
   */
  uword *g4ie_hash;
} gbp_ip4_to_epg_db_t;

static gbp_ip4_to_epg_db_t gbp_ip4_to_epg_db;

/**
 * IP6 destintion address to destination EPG mapping table
 */
typedef struct gbp_ip6_to_epg_db_t_
{
  /**
   * use a memroy hash table
   */
  uword *g6ie_hash;
} gbp_ip6_to_epg_db_t;

static gbp_ip6_to_epg_db_t gbp_ip6_to_epg_db;


const static gbp_itf_t ITF_INVALID = {
  .gi_epg = EPG_INVALID,
  .gi_ref_count = 0,
};

gbp_itf_to_epg_db_t gbp_itf_to_epg_db;

/**
 * Pool of GBP endpoints
 */
static gbp_endpoint_t *gbp_endpoint_pool;

/**
 * DB of endpoints
 */
static uword *gbp_endpoint_db;

static void
gbp_ip_epg_update (const ip46_address_t * ip, epg_id_t epg_id)
{
  /*
   * we are dealing only with addresses here so this limited
   * is_ip4 check is ok
   */
  if (ip46_address_is_ip4 (ip))
    {
      hash_set (gbp_ip4_to_epg_db.g4ie_hash, ip->ip4.as_u32, epg_id);
    }
  else
    {
      hash_set_mem (gbp_ip6_to_epg_db.g6ie_hash, &ip->ip6, epg_id);
    }
}

static void
gbp_ip_epg_delete (const ip46_address_t * ip)
{
  if (ip46_address_is_ip4 (ip))
    {
      hash_unset (gbp_ip4_to_epg_db.g4ie_hash, ip->ip4.as_u32);
    }
  else
    {
      hash_unset_mem (gbp_ip6_to_epg_db.g6ie_hash, &ip->ip6);
    }
}

void
gbp_itf_epg_update (u32 sw_if_index, epg_id_t src_epg, u8 do_policy)
{
  vec_validate_init_empty (gbp_itf_to_epg_db.gte_vec,
			   sw_if_index, ITF_INVALID);

  if (0 == gbp_itf_to_epg_db.gte_vec[sw_if_index].gi_ref_count)
    {
      l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_GBP_SRC_CLASSIFY,
				  1);
      l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_GBP_FWD, 1);
      if (do_policy)
	l2output_intf_bitmap_enable (sw_if_index, L2OUTPUT_FEAT_GBP_POLICY,
				     1);
    }
  gbp_itf_to_epg_db.gte_vec[sw_if_index].gi_epg = src_epg;
  gbp_itf_to_epg_db.gte_vec[sw_if_index].gi_ref_count++;
}

void
gbp_itf_epg_delete (u32 sw_if_index)
{
  if (vec_len (gbp_itf_to_epg_db.gte_vec) <= sw_if_index)
    return;

  if (1 == gbp_itf_to_epg_db.gte_vec[sw_if_index].gi_ref_count)
    {
      gbp_itf_to_epg_db.gte_vec[sw_if_index].gi_epg = EPG_INVALID;

      l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_GBP_SRC_CLASSIFY,
				  0);
      l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_GBP_FWD, 0);
      l2output_intf_bitmap_enable (sw_if_index, L2OUTPUT_FEAT_GBP_POLICY, 0);
    }
  gbp_itf_to_epg_db.gte_vec[sw_if_index].gi_ref_count--;
}

int
gbp_endpoint_update (u32 sw_if_index,
		     const ip46_address_t * ip, epg_id_t epg_id)
{
  gbp_endpoint_key_t key = {
    .gek_ip = *ip,
    .gek_sw_if_index = sw_if_index,
  };
  gbp_endpoint_group_t *gepg;
  gbp_endpoint_t *gbpe;
  uword *p;

  gepg = gbp_endpoint_group_find (epg_id);

  if (NULL == gepg)
    return (VNET_API_ERROR_NO_SUCH_ENTRY);

  p = hash_get_mem (gbp_endpoint_db, &key);

  if (p)
    {
      gbpe = pool_elt_at_index (gbp_endpoint_pool, p[0]);
    }
  else
    {
      pool_get (gbp_endpoint_pool, gbpe);

      gbpe->ge_key = clib_mem_alloc (sizeof (gbp_endpoint_key_t));
      clib_memcpy (gbpe->ge_key, &key, sizeof (gbp_endpoint_key_t));

      hash_set_mem (gbp_endpoint_db, gbpe->ge_key, gbpe - gbp_endpoint_pool);
    }

  gbpe->ge_epg_id = epg_id;

  gbp_itf_epg_update (gbpe->ge_key->gek_sw_if_index, gbpe->ge_epg_id, 1);

  if (!ip46_address_is_zero (&gbpe->ge_key->gek_ip))
    gbp_ip_epg_update (&gbpe->ge_key->gek_ip, gbpe->ge_epg_id);

  /*
   * send a gratuitous ARP on the EPG's uplink. this is done so that if
   * this EP has moved from some other place in the 'fabric', upstream
   * devices are informed
   */
  if (ip46_address_is_ip4 (&gbpe->ge_key->gek_ip))
    send_ip4_garp_w_addr (vlib_get_main (),
			  &gbpe->ge_key->gek_ip.ip4,
			  gepg->gepg_uplink_sw_if_index);
  else
    send_ip6_na_w_addr (vlib_get_main (),
			&gbpe->ge_key->gek_ip.ip6,
			gepg->gepg_uplink_sw_if_index);

  return (0);
}

void
gbp_endpoint_delete (u32 sw_if_index, const ip46_address_t * ip)
{
  gbp_endpoint_key_t key = {
    .gek_ip = *ip,
    .gek_sw_if_index = sw_if_index,
  };
  gbp_endpoint_t *gbpe;
  uword *p;

  p = hash_get_mem (gbp_endpoint_db, &key);

  if (p)
    {
      gbpe = pool_elt_at_index (gbp_endpoint_pool, p[0]);

      hash_unset_mem (gbp_endpoint_db, gbpe->ge_key);

      gbp_itf_epg_delete (gbpe->ge_key->gek_sw_if_index);
      if (!ip46_address_is_zero (&gbpe->ge_key->gek_ip))
	gbp_ip_epg_delete (&gbpe->ge_key->gek_ip);

      clib_mem_free (gbpe->ge_key);

      pool_put (gbp_endpoint_pool, gbpe);
    }
}

void
gbp_endpoint_walk (gbp_endpoint_cb_t cb, void *ctx)
{
  gbp_endpoint_t *gbpe;

  /* *INDENT-OFF* */
  pool_foreach(gbpe, gbp_endpoint_pool,
  {
    if (!cb(gbpe, ctx))
      break;
  });
  /* *INDENT-ON* */
}

static clib_error_t *
gbp_endpoint_cli (vlib_main_t * vm,
		  unformat_input_t * input, vlib_cli_command_t * cmd)
{
  vnet_main_t *vnm = vnet_get_main ();
  epg_id_t epg_id = EPG_INVALID;
  ip46_address_t ip = { };
  u32 sw_if_index = ~0;
  u8 add = 1;

  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
    {
      if (unformat (input, "%U", unformat_vnet_sw_interface,
		    vnm, &sw_if_index))
	;
      else if (unformat (input, "add"))
	add = 1;
      else if (unformat (input, "del"))
	add = 0;
      else if (unformat (input, "epg %d", &epg_id))
	;
      else if (unformat (input, "ip %U", unformat_ip4_address, &ip.ip4))
	;
      else if (unformat (input, "ip %U", unformat_ip6_address, &ip.ip6))
	;
      else
	break;
    }

  if (~0 == sw_if_index)
    return clib_error_return (0, "interface must be specified");
  if (EPG_INVALID == epg_id)
    return clib_error_return (0, "EPG-ID must be specified");
  if (ip46_address_is_zero (&ip))
    return clib_error_return (0, "IP address must be specified");

  if (add)
    gbp_endpoint_update (sw_if_index, &ip, epg_id);
  else
    gbp_endpoint_delete (sw_if_index, &ip);

  return (NULL);
}


/*?
 * Configure a GBP Endpoint
 *
 * @cliexpar
 * @cliexstart{set gbp endpoint [del] <interface> epg <ID> ip <IP>}
 * @cliexend
 ?*/
/* *INDENT-OFF* */
VLIB_CLI_COMMAND (gbp_endpoint_cli_node, static) = {
  .path = "gbp endpoint",
  .short_help = "gbp endpoint [del] <interface> epg <ID> ip <IP>",
  .function = gbp_endpoint_cli,
};
/* *INDENT-ON* */

static int
gbp_endpoint_show_one (gbp_endpoint_t * gbpe, void *ctx)
{
  vnet_main_t *vnm = vnet_get_main ();
  vlib_main_t *vm;

  vm = ctx;
  vlib_cli_output (vm, "  {%U, %U} -> %d",
		   format_vnet_sw_if_index_name, vnm,
		   gbpe->ge_key->gek_sw_if_index,
		   format_ip46_address, &gbpe->ge_key->gek_ip, IP46_TYPE_ANY,
		   gbpe->ge_epg_id);

  return (1);
}

static clib_error_t *
gbp_endpoint_show (vlib_main_t * vm,
		   unformat_input_t * input, vlib_cli_command_t * cmd)
{
  vnet_main_t *vnm = vnet_get_main ();
  ip46_address_t ip, *ipp;
  epg_id_t epg_id;
  u32 sw_if_index;

  vlib_cli_output (vm, "Endpoints:");
  gbp_endpoint_walk (gbp_endpoint_show_one, vm);

  vlib_cli_output (vm, "\nSource interface to EPG:");

  vec_foreach_index (sw_if_index, gbp_itf_to_epg_db.gte_vec)
  {
    if (EPG_INVALID != gbp_itf_to_epg_db.gte_vec[sw_if_index].gi_epg)
      {
	vlib_cli_output (vm, "  %U -> %d",
			 format_vnet_sw_if_index_name, vnm, sw_if_index,
			 gbp_itf_to_epg_db.gte_vec[sw_if_index].gi_epg);
      }
  }

  vlib_cli_output (vm, "\nDestination IP4 to EPG:");

  /* *INDENT-OFF* */
  hash_foreach (ip.ip4.as_u32, epg_id, gbp_ip4_to_epg_db.g4ie_hash,
  {
    vlib_cli_output (vm, "  %U -> %d", format_ip46_address, &ip,
                     IP46_TYPE_IP4, epg_id);
  });
  /* *INDENT-ON* */

  vlib_cli_output (vm, "\nDestination IP6 to EPG:");

  /* *INDENT-OFF* */
  hash_foreach_mem (ipp, epg_id, gbp_ip6_to_epg_db.g6ie_hash,
  {
    vlib_cli_output (vm, "  %U -> %d", format_ip46_address, ipp,
                     IP46_TYPE_IP6, epg_id);
  });
  /* *INDENT-ON* */

  return (NULL);
}


/*?
 * Show Group Based Policy Endpoints and derived information
 *
 * @cliexpar
 * @cliexstart{show gbp endpoint}
 * @cliexend
 ?*/
/* *INDENT-OFF* */
VLIB_CLI_COMMAND (gbp_endpoint_show_node, static) = {
  .path = "show gbp endpoint",
  .short_help = "show gbp endpoint\n",
  .function = gbp_endpoint_show,
};
/* *INDENT-ON* */

static clib_error_t *
gbp_endpoint_init (vlib_main_t * vm)
{
  gbp_endpoint_db = hash_create_mem (0,
				     sizeof (gbp_endpoint_key_t),
				     sizeof (u32));
  gbp_ip6_to_epg_db.g6ie_hash =
    hash_create_mem (0, sizeof (ip6_address_t), sizeof (u32));
  return 0;
}

VLIB_INIT_FUNCTION (gbp_endpoint_init);

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