summaryrefslogtreecommitdiffstats
path: root/src/CMakeLists.txt
AgeCommit message (Expand)AuthorFilesLines
2019-11-27misc: add address sanitizer heap instrumentationBenoƮt Ganne1-0/+11
2019-11-22build: add build types helpstring to cmake projectDamjan Marion1-0/+9
2019-11-08build: use cmake build typesDamjan Marion1-8/+33
2019-03-28AppImage packagingDave Barach1-1/+1
2019-03-18Fix build with newer linux headersDamjan Marion1-1/+1
2019-01-29cmake: fix out-of-git-tree buildDamjan Marion1-10/+1
2019-01-26cmake: add support for linking with DPDK shared libsDamjan Marion1-1/+1
2019-01-20Rework of debian packagingDamjan Marion1-1/+1
2019-01-18cmake: print all flagsDamjan Marion1-8/+19
2019-01-18Look for plugins in target triplet subdirDamjan Marion1-0/+1
2019-01-17cmake: initial cross-compilation supportDamjan Marion1-0/+11
2018-09-20rename vpp-dpdk-dev to vpp-ext-depsDamjan Marion1-0/+1
2018-09-14cpack: add deb/rpm packaging to VPP moduleDamjan Marion1-0/+9
2018-09-12cmake: create cmake VPP module, update sample-plugin so it uses itDamjan Marion1-1/+2
2018-09-12Always use 'lib' instead of 'lib64'Damjan Marion1-1/+1
2018-09-03Compile vppinfra on macOSDamjan Marion1-6/+12
2018-09-02Switch to cmakeDamjan Marion1-0/+1
2018-08-31cmake: detect vpp version, set soversion, pretty config printDamjan Marion1-5/+41
2018-08-30cmake: a bit of packaging workDamjan Marion1-1/+1
2018-08-28cmake: Add perftool to cmake buildMohsin Kazmi1-1/+1
2018-08-28cmake: add g2 and elftool toolsDamjan Marion1-1/+1
2018-08-28cmake: install vppapigenDamjan Marion1-3/+7
2018-08-27cmake: fix clang build and few minor fixesDamjan Marion1-0/+5
2018-08-27CMake: fix install lib and iOMA missing symbolNeale Ranns1-1/+1
2018-08-27cmake: add vapi buildDamjan Marion1-1/+1
2018-08-26cmake: add add_vpp_library and add_vpp_executable macrosDamjan Marion1-10/+2
2018-08-26cmake: move functions to src/cmakeDamjan Marion1-151/+7
2018-08-25cmake: add more headers to the install listDamjan Marion1-1/+1
2018-08-23CMake: Add Cmake support for VatMohsin Kazmi1-3/+1
2018-08-22CMake: install .json files in ROOT/share/... for papi.Neale Ranns1-4/+11
2018-08-20CMake: generate .json from .api filesNeale Ranns1-3/+20
2018-08-20Detect support for memfd_create at compilationPierre Pfister1-1/+14
2018-08-20CMakeLists file for vpp-apiNeale Ranns1-1/+1
2018-08-18cmake: highlight warning and error messagesDamjan Marion1-0/+23
2018-08-17CMake as an alternative to autotools (experimental)Damjan Marion1-0/+161
'#n664'>664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920
/*
 *------------------------------------------------------------------
 * 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 <vnet/vnet.h>
#include <vnet/plugin/plugin.h>

#include <vnet/interface.h>
#include <vnet/api_errno.h>
#include <vnet/ip/ip_types_api.h>
#include <vnet/ethernet/ethernet_types_api.h>
#include <vpp/app/version.h>

#include <gbp/gbp.h>
#include <gbp/gbp_learn.h>
#include <gbp/gbp_itf.h>
#include <gbp/gbp_vxlan.h>
#include <gbp/gbp_bridge_domain.h>
#include <gbp/gbp_route_domain.h>

#include <vlibapi/api.h>
#include <vlibmemory/api.h>

/* define message IDs */
#include <gbp/gbp_msg_enum.h>

#define vl_typedefs		/* define message structures */
#include <gbp/gbp_all_api_h.h>
#undef vl_typedefs

#define vl_endianfun		/* define message structures */
#include <gbp/gbp_all_api_h.h>
#undef vl_endianfun

/* instantiate all the print functions we know about */
#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
#define vl_printfun
#include <gbp/gbp_all_api_h.h>
#undef vl_printfun

/* Get the API version number */
#define vl_api_version(n,v) static u32 api_version=(v);
#include <gbp/gbp_all_api_h.h>
#undef vl_api_version

#include <vlibapi/api_helper_macros.h>

#define foreach_gbp_api_msg                                 \
  _(GBP_ENDPOINT_ADD, gbp_endpoint_add)                     \
  _(GBP_ENDPOINT_DEL, gbp_endpoint_del)                     \
  _(GBP_ENDPOINT_DUMP, gbp_endpoint_dump)                   \
  _(GBP_SUBNET_ADD_DEL, gbp_subnet_add_del)                 \
  _(GBP_SUBNET_DUMP, gbp_subnet_dump)                       \
  _(GBP_ENDPOINT_GROUP_ADD, gbp_endpoint_group_add)         \
  _(GBP_ENDPOINT_GROUP_DEL, gbp_endpoint_group_del)         \
  _(GBP_ENDPOINT_GROUP_DUMP, gbp_endpoint_group_dump)       \
  _(GBP_BRIDGE_DOMAIN_ADD, gbp_bridge_domain_add)           \
  _(GBP_BRIDGE_DOMAIN_DEL, gbp_bridge_domain_del)           \
  _(GBP_BRIDGE_DOMAIN_DUMP, gbp_bridge_domain_dump)         \
  _(GBP_ROUTE_DOMAIN_ADD, gbp_route_domain_add)             \
  _(GBP_ROUTE_DOMAIN_DEL, gbp_route_domain_del)             \
  _(GBP_ROUTE_DOMAIN_DUMP, gbp_route_domain_dump)           \
  _(GBP_RECIRC_ADD_DEL, gbp_recirc_add_del)                 \
  _(GBP_RECIRC_DUMP, gbp_recirc_dump)                       \
  _(GBP_CONTRACT_ADD_DEL, gbp_contract_add_del)             \
  _(GBP_CONTRACT_DUMP, gbp_contract_dump)                   \
  _(GBP_ENDPOINT_LEARN_SET_INACTIVE_THRESHOLD, gbp_endpoint_learn_set_inactive_threshold) \
  _(GBP_VXLAN_TUNNEL_ADD, gbp_vxlan_tunnel_add)                         \
  _(GBP_VXLAN_TUNNEL_DEL, gbp_vxlan_tunnel_del)                         \
  _(GBP_VXLAN_TUNNEL_DUMP, gbp_vxlan_tunnel_dump)

gbp_main_t gbp_main;

static u16 msg_id_base;

#define GBP_MSG_BASE msg_id_base

static gbp_endpoint_flags_t
gbp_endpoint_flags_decode (vl_api_gbp_endpoint_flags_t v)
{
  gbp_endpoint_flags_t f = GBP_ENDPOINT_FLAG_NONE;

  v = ntohl (v);

  if (v & BOUNCE)
    f |= GBP_ENDPOINT_FLAG_BOUNCE;
  if (v & REMOTE)
    f |= GBP_ENDPOINT_FLAG_REMOTE;
  if (v & LEARNT)
    f |= GBP_ENDPOINT_FLAG_LEARNT;

  return (f);
}

static vl_api_gbp_endpoint_flags_t
gbp_endpoint_flags_encode (gbp_endpoint_flags_t f)
{
  vl_api_gbp_endpoint_flags_t v = 0;


  if (f & GBP_ENDPOINT_FLAG_BOUNCE)
    v |= BOUNCE;
  if (f & GBP_ENDPOINT_FLAG_REMOTE)
    v |= REMOTE;
  if (f & GBP_ENDPOINT_FLAG_LEARNT)
    v |= LEARNT;

  v = htonl (v);

  return (v);
}

static void
vl_api_gbp_endpoint_add_t_handler (vl_api_gbp_endpoint_add_t * mp)
{
  vl_api_gbp_endpoint_add_reply_t *rmp;
  gbp_endpoint_flags_t gef;
  u32 sw_if_index, handle;
  ip46_address_t *ips;
  mac_address_t mac;
  int rv = 0, ii;

  VALIDATE_SW_IF_INDEX (&(mp->endpoint));

  gef = gbp_endpoint_flags_decode (mp->endpoint.flags), ips = NULL;
  sw_if_index = ntohl (mp->endpoint.sw_if_index);

  if (mp->endpoint.n_ips)
    {
      vec_validate (ips, mp->endpoint.n_ips - 1);

      vec_foreach_index (ii, ips)
      {
	ip_address_decode (&mp->endpoint.ips[ii], &ips[ii]);
      }
    }
  mac_address_decode (&mp->endpoint.mac, &mac);

  if (GBP_ENDPOINT_FLAG_REMOTE & gef)
    {
      ip46_address_t tun_src, tun_dst;

      ip_address_decode (&mp->endpoint.tun.src, &tun_src);
      ip_address_decode (&mp->endpoint.tun.dst, &tun_dst);

      rv = gbp_endpoint_update (sw_if_index, ips, &mac,
				ntohs (mp->endpoint.epg_id),
				gef, &tun_src, &tun_dst, &handle);
    }
  else
    {
      rv = gbp_endpoint_update (sw_if_index, ips, &mac,
				ntohs (mp->endpoint.epg_id),
				gef, NULL, NULL, &handle);
    }
  BAD_SW_IF_INDEX_LABEL;

  /* *INDENT-OFF* */
  REPLY_MACRO2 (VL_API_GBP_ENDPOINT_ADD_REPLY + GBP_MSG_BASE,
  ({
    rmp->handle = htonl (handle);
  }));
  /* *INDENT-ON* */
}

static void
vl_api_gbp_endpoint_del_t_handler (vl_api_gbp_endpoint_del_t * mp)
{
  vl_api_gbp_endpoint_del_reply_t *rmp;
  int rv = 0;

  gbp_endpoint_delete (ntohl (mp->handle));

  REPLY_MACRO (VL_API_GBP_ENDPOINT_DEL_REPLY + GBP_MSG_BASE);
}

static void
  vl_api_gbp_endpoint_learn_set_inactive_threshold_t_handler
  (vl_api_gbp_endpoint_learn_set_inactive_threshold_t * mp)
{
  vl_api_gbp_endpoint_learn_set_inactive_threshold_reply_t *rmp;
  int rv = 0;

  gbp_learn_set_inactive_threshold (ntohl (mp->threshold));

  REPLY_MACRO (VL_API_GBP_ENDPOINT_LEARN_SET_INACTIVE_THRESHOLD_REPLY +
	       GBP_MSG_BASE);
}

typedef struct gbp_walk_ctx_t_
{
  vl_api_registration_t *reg;
  u32 context;
} gbp_walk_ctx_t;

static walk_rc_t
gbp_endpoint_send_details (index_t gei, void *args)
{
  vl_api_gbp_endpoint_details_t *mp;
  gbp_endpoint_t *ge;
  gbp_walk_ctx_t *ctx;
  u8 n_ips, ii;

  ctx = args;
  ge = gbp_endpoint_get (gei);

  n_ips = vec_len (ge->ge_ips);
  mp = vl_msg_api_alloc (sizeof (*mp) + (sizeof (*mp->endpoint.ips) * n_ips));
  if (!mp)
    return 1;

  clib_memset (mp, 0, sizeof (*mp));
  mp->_vl_msg_id = ntohs (VL_API_GBP_ENDPOINT_DETAILS + GBP_MSG_BASE);
  mp->context = ctx->context;

  if (gbp_endpoint_is_remote (ge))
    {
      mp->endpoint.sw_if_index = ntohl (ge->tun.ge_parent_sw_if_index);
      ip_address_encode (&ge->tun.ge_src, IP46_TYPE_ANY,
			 &mp->endpoint.tun.src);
      ip_address_encode (&ge->tun.ge_dst, IP46_TYPE_ANY,
			 &mp->endpoint.tun.dst);
    }
  else
    {
      mp->endpoint.sw_if_index = ntohl (ge->ge_sw_if_index);
    }
  mp->endpoint.epg_id = ntohs (ge->ge_epg_id);
  mp->endpoint.n_ips = n_ips;
  mp->endpoint.flags = gbp_endpoint_flags_encode (ge->ge_flags);
  mp->handle = htonl (gei);
  mp->age = vlib_time_now (vlib_get_main ()) - ge->ge_last_time;
  mac_address_encode (&ge->ge_mac, &mp->endpoint.mac);

  vec_foreach_index (ii, ge->ge_ips)
  {
    ip_address_encode (&ge->ge_ips[ii], IP46_TYPE_ANY, &mp->endpoint.ips[ii]);
  }

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

  return (WALK_CONTINUE);
}

static void
vl_api_gbp_endpoint_dump_t_handler (vl_api_gbp_endpoint_dump_t * mp)
{
  vl_api_registration_t *reg;

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

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

  gbp_endpoint_walk (gbp_endpoint_send_details, &ctx);
}

static void
  vl_api_gbp_endpoint_group_add_t_handler
  (vl_api_gbp_endpoint_group_add_t * mp)
{
  vl_api_gbp_endpoint_group_add_reply_t *rmp;
  int rv = 0;

  rv = gbp_endpoint_group_add_and_lock (ntohs (mp->epg.epg_id),
					ntohl (mp->epg.bd_id),
					ntohl (mp->epg.rd_id),
					ntohl (mp->epg.uplink_sw_if_index));

  REPLY_MACRO (VL_API_GBP_ENDPOINT_GROUP_ADD_REPLY + GBP_MSG_BASE);
}

static void
  vl_api_gbp_endpoint_group_del_t_handler
  (vl_api_gbp_endpoint_group_del_t * mp)
{
  vl_api_gbp_endpoint_group_del_reply_t *rmp;
  int rv = 0;

  rv = gbp_endpoint_group_delete (ntohs (mp->epg_id));

  REPLY_MACRO (VL_API_GBP_ENDPOINT_GROUP_DEL_REPLY + GBP_MSG_BASE);
}

static gbp_bridge_domain_flags_t
gbp_bridge_domain_flags_from_api (vl_api_gbp_bridge_domain_flags_t a)
{
  gbp_bridge_domain_flags_t g;

  g = GBP_BD_FLAG_NONE;
  a = clib_net_to_host_u32 (a);

  if (a & GBP_BD_API_FLAG_DO_NOT_LEARN)
    g |= GBP_BD_FLAG_DO_NOT_LEARN;

  return (g);
}

static void
vl_api_gbp_bridge_domain_add_t_handler (vl_api_gbp_bridge_domain_add_t * mp)
{
  vl_api_gbp_bridge_domain_add_reply_t *rmp;
  int rv = 0;

  rv = gbp_bridge_domain_add_and_lock (ntohl (mp->bd.bd_id),
				       gbp_bridge_domain_flags_from_api
				       (mp->bd.flags),
				       ntohl (mp->bd.bvi_sw_if_index),
				       ntohl (mp->bd.uu_fwd_sw_if_index));

  REPLY_MACRO (VL_API_GBP_BRIDGE_DOMAIN_ADD_REPLY + GBP_MSG_BASE);
}

static void
vl_api_gbp_bridge_domain_del_t_handler (vl_api_gbp_bridge_domain_del_t * mp)
{
  vl_api_gbp_bridge_domain_del_reply_t *rmp;
  int rv = 0;

  rv = gbp_bridge_domain_delete (ntohl (mp->bd_id));

  REPLY_MACRO (VL_API_GBP_BRIDGE_DOMAIN_DEL_REPLY + GBP_MSG_BASE);
}

static void
vl_api_gbp_route_domain_add_t_handler (vl_api_gbp_route_domain_add_t * mp)
{
  vl_api_gbp_route_domain_add_reply_t *rmp;
  int rv = 0;

  rv = gbp_route_domain_add_and_lock (ntohl (mp->rd.rd_id),
				      ntohl (mp->rd.ip4_table_id),
				      ntohl (mp->rd.ip6_table_id),
				      ntohl (mp->rd.ip4_uu_sw_if_index),
				      ntohl (mp->rd.ip6_uu_sw_if_index));

  REPLY_MACRO (VL_API_GBP_ROUTE_DOMAIN_ADD_REPLY + GBP_MSG_BASE);
}

static void
vl_api_gbp_route_domain_del_t_handler (vl_api_gbp_route_domain_del_t * mp)
{
  vl_api_gbp_route_domain_del_reply_t *rmp;
  int rv = 0;

  rv = gbp_route_domain_delete (ntohl (mp->rd_id));

  REPLY_MACRO (VL_API_GBP_ROUTE_DOMAIN_DEL_REPLY + GBP_MSG_BASE);
}

static int
gub_subnet_type_from_api (vl_api_gbp_subnet_type_t a, gbp_subnet_type_t * t)
{
  a = clib_net_to_host_u32 (a);

  switch (a)
    {
    case GBP_API_SUBNET_TRANSPORT:
      *t = GBP_SUBNET_TRANSPORT;
      return (0);
    case GBP_API_SUBNET_STITCHED_INTERNAL:
      *t = GBP_SUBNET_STITCHED_INTERNAL;
      return (0);
    case GBP_API_SUBNET_STITCHED_EXTERNAL:
      *t = GBP_SUBNET_STITCHED_EXTERNAL;
      return (0);
    }

  return (-1);
}

static void
vl_api_gbp_subnet_add_del_t_handler (vl_api_gbp_subnet_add_del_t * mp)
{
  vl_api_gbp_subnet_add_del_reply_t *rmp;
  gbp_subnet_type_t type;
  fib_prefix_t pfx;
  int rv = 0;

  ip_prefix_decode (&mp->subnet.prefix, &pfx);

  rv = gub_subnet_type_from_api (mp->subnet.type, &type);

  if (0 != rv)
    goto out;

  if (mp->is_add)
    rv = gbp_subnet_add (ntohl (mp->subnet.rd_id),
			 &pfx, type,
			 ntohl (mp->subnet.sw_if_index),
			 ntohs (mp->subnet.epg_id));
  else
    rv = gbp_subnet_del (ntohl (mp->subnet.rd_id), &pfx);

out:
  REPLY_MACRO (VL_API_GBP_SUBNET_ADD_DEL_REPLY + GBP_MSG_BASE);
}

static vl_api_gbp_subnet_type_t
gub_subnet_type_to_api (gbp_subnet_type_t t)
{
  vl_api_gbp_subnet_type_t a = 0;

  switch (t)
    {
    case GBP_SUBNET_TRANSPORT:
      a = GBP_API_SUBNET_TRANSPORT;
      break;
    case GBP_SUBNET_STITCHED_INTERNAL:
      a = GBP_API_SUBNET_STITCHED_INTERNAL;
      break;
    case GBP_SUBNET_STITCHED_EXTERNAL:
      a = GBP_API_SUBNET_STITCHED_EXTERNAL;
      break;
    }

  a = clib_host_to_net_u32 (a);

  return (a);
}

static walk_rc_t
gbp_subnet_send_details (u32 rd_id,
			 const fib_prefix_t * pfx,
			 gbp_subnet_type_t type,
			 u32 sw_if_index, epg_id_t epg, void *args)
{
  vl_api_gbp_subnet_details_t *mp;
  gbp_walk_ctx_t *ctx;

  ctx = args;
  mp = vl_msg_api_alloc (sizeof (*mp));
  if (!mp)
    return 1;

  clib_memset (mp, 0, sizeof (*mp));
  mp->_vl_msg_id = ntohs (VL_API_GBP_SUBNET_DETAILS + GBP_MSG_BASE);
  mp->context = ctx->context;

  mp->subnet.type = gub_subnet_type_to_api (type);
  mp->subnet.sw_if_index = ntohl (sw_if_index);
  mp->subnet.epg_id = ntohs (epg);
  mp->subnet.rd_id = ntohl (rd_id);
  ip_prefix_encode (pfx, &mp->subnet.prefix);

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

  return (WALK_CONTINUE);
}

static void
vl_api_gbp_subnet_dump_t_handler (vl_api_gbp_subnet_dump_t * mp)
{
  vl_api_registration_t *reg;

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

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

  gbp_subnet_walk (gbp_subnet_send_details, &ctx);
}

static int
gbp_endpoint_group_send_details (gbp_endpoint_group_t * gg, void *args)
{
  vl_api_gbp_endpoint_group_details_t *mp;
  gbp_walk_ctx_t *ctx;

  ctx = args;
  mp = vl_msg_api_alloc (sizeof (*mp));
  if (!mp)
    return 1;

  clib_memset (mp, 0, sizeof (*mp));
  mp->_vl_msg_id = ntohs (VL_API_GBP_ENDPOINT_GROUP_DETAILS + GBP_MSG_BASE);
  mp->context = ctx->context;

  mp->epg.uplink_sw_if_index = ntohl (gg->gg_uplink_sw_if_index);
  mp->epg.epg_id = ntohs (gg->gg_id);
  mp->epg.bd_id = ntohl (gbp_endpoint_group_get_bd_id (gg));
  mp->epg.rd_id = ntohl (gg->gg_rd);

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

  return (1);
}

static void
vl_api_gbp_endpoint_group_dump_t_handler (vl_api_gbp_endpoint_group_dump_t *
					  mp)
{
  vl_api_registration_t *reg;

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

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

  gbp_endpoint_group_walk (gbp_endpoint_group_send_details, &ctx);
}

static int
gbp_bridge_domain_send_details (gbp_bridge_domain_t * gb, void *args)
{
  vl_api_gbp_bridge_domain_details_t *mp;
  gbp_walk_ctx_t *ctx;

  ctx = args;
  mp = vl_msg_api_alloc (sizeof (*mp));
  if (!mp)
    return 1;

  memset (mp, 0, sizeof (*mp));
  mp->_vl_msg_id = ntohs (VL_API_GBP_BRIDGE_DOMAIN_DETAILS + GBP_MSG_BASE);
  mp->context = ctx->context;

  mp->bd.bd_id = ntohl (gb->gb_bd_id);
  mp->bd.bvi_sw_if_index = ntohl (gb->gb_bvi_sw_if_index);
  mp->bd.uu_fwd_sw_if_index = ntohl (gb->gb_uu_fwd_sw_if_index);

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

  return (1);
}

static void
vl_api_gbp_bridge_domain_dump_t_handler (vl_api_gbp_bridge_domain_dump_t * mp)
{
  vl_api_registration_t *reg;

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

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

  gbp_bridge_domain_walk (gbp_bridge_domain_send_details, &ctx);
}

static int
gbp_route_domain_send_details (gbp_route_domain_t * grd, void *args)
{
  vl_api_gbp_route_domain_details_t *mp;
  gbp_walk_ctx_t *ctx;

  ctx = args;
  mp = vl_msg_api_alloc (sizeof (*mp));
  if (!mp)
    return 1;

  memset (mp, 0, sizeof (*mp));
  mp->_vl_msg_id = ntohs (VL_API_GBP_ROUTE_DOMAIN_DETAILS + GBP_MSG_BASE);
  mp->context = ctx->context;

  mp->rd.rd_id = ntohl (grd->grd_id);
  mp->rd.ip4_uu_sw_if_index =
    ntohl (grd->grd_uu_sw_if_index[FIB_PROTOCOL_IP4]);
  mp->rd.ip6_uu_sw_if_index =
    ntohl (grd->grd_uu_sw_if_index[FIB_PROTOCOL_IP6]);

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

  return (1);
}

static void
vl_api_gbp_route_domain_dump_t_handler (vl_api_gbp_route_domain_dump_t * mp)
{
  vl_api_registration_t *reg;

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

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

  gbp_route_domain_walk (gbp_route_domain_send_details, &ctx);
}

static void
vl_api_gbp_recirc_add_del_t_handler (vl_api_gbp_recirc_add_del_t * mp)
{
  vl_api_gbp_recirc_add_del_reply_t *rmp;
  u32 sw_if_index;
  int rv = 0;

  sw_if_index = ntohl (mp->recirc.sw_if_index);
  if (!vnet_sw_if_index_is_api_valid (sw_if_index))
    goto bad_sw_if_index;

  if (mp->is_add)
    gbp_recirc_add (sw_if_index,
		    ntohs (mp->recirc.epg_id), mp->recirc.is_ext);
  else
    gbp_recirc_delete (sw_if_index);

  BAD_SW_IF_INDEX_LABEL;

  REPLY_MACRO (VL_API_GBP_RECIRC_ADD_DEL_REPLY + GBP_MSG_BASE);
}

static int
gbp_recirc_send_details (gbp_recirc_t * gr, void *args)
{
  vl_api_gbp_recirc_details_t *mp;
  gbp_walk_ctx_t *ctx;

  ctx = args;
  mp = vl_msg_api_alloc (sizeof (*mp));
  if (!mp)
    return 1;

  clib_memset (mp, 0, sizeof (*mp));
  mp->_vl_msg_id = ntohs (VL_API_GBP_RECIRC_DETAILS + GBP_MSG_BASE);
  mp->context = ctx->context;

  mp->recirc.epg_id = ntohs (gr->gr_epg);
  mp->recirc.sw_if_index = ntohl (gr->gr_sw_if_index);
  mp->recirc.is_ext = ntohl (gr->gr_is_ext);

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

  return (1);
}

static void
vl_api_gbp_recirc_dump_t_handler (vl_api_gbp_recirc_dump_t * mp)
{
  vl_api_registration_t *reg;

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

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

  gbp_recirc_walk (gbp_recirc_send_details, &ctx);
}

static void
vl_api_gbp_contract_add_del_t_handler (vl_api_gbp_contract_add_del_t * mp)
{
  vl_api_gbp_contract_add_del_reply_t *rmp;
  int rv = 0;

  if (mp->is_add)
    gbp_contract_update (ntohs (mp->contract.src_epg),
			 ntohs (mp->contract.dst_epg),
			 ntohl (mp->contract.acl_index));
  else
    gbp_contract_delete (ntohs (mp->contract.src_epg),
			 ntohs (mp->contract.dst_epg));

  REPLY_MACRO (VL_API_GBP_CONTRACT_ADD_DEL_REPLY + GBP_MSG_BASE);
}

static int
gbp_contract_send_details (gbp_contract_t * gbpc, void *args)
{
  vl_api_gbp_contract_details_t *mp;
  gbp_walk_ctx_t *ctx;

  ctx = args;
  mp = vl_msg_api_alloc (sizeof (*mp));
  if (!mp)
    return 1;

  clib_memset (mp, 0, sizeof (*mp));
  mp->_vl_msg_id = ntohs (VL_API_GBP_CONTRACT_DETAILS + GBP_MSG_BASE);
  mp->context = ctx->context;

  mp->contract.src_epg = ntohs (gbpc->gc_key.gck_src);
  mp->contract.dst_epg = ntohs (gbpc->gc_key.gck_dst);
  mp->contract.acl_index = ntohl (gbpc->gc_value.gc_acl_index);

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

  return (1);
}

static void
vl_api_gbp_contract_dump_t_handler (vl_api_gbp_contract_dump_t * mp)
{
  vl_api_registration_t *reg;

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

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

  gbp_contract_walk (gbp_contract_send_details, &ctx);
}

static int
gbp_vxlan_tunnel_mode_2_layer (vl_api_gbp_vxlan_tunnel_mode_t mode,
			       gbp_vxlan_tunnel_layer_t * l)
{
  mode = clib_net_to_host_u32 (mode);

  switch (mode)
    {
    case GBP_VXLAN_TUNNEL_MODE_L2:
      *l = GBP_VXLAN_TUN_L2;
      return (0);
    case GBP_VXLAN_TUNNEL_MODE_L3:
      *l = GBP_VXLAN_TUN_L3;
      return (0);
    }
  return (-1);
}

static void
vl_api_gbp_vxlan_tunnel_add_t_handler (vl_api_gbp_vxlan_tunnel_add_t * mp)
{
  vl_api_gbp_vxlan_tunnel_add_reply_t *rmp;
  gbp_vxlan_tunnel_layer_t layer;
  u32 sw_if_index;
  int rv = 0;

  rv = gbp_vxlan_tunnel_mode_2_layer (mp->tunnel.mode, &layer);

  if (0 != rv)
    goto out;

  rv = gbp_vxlan_tunnel_add (ntohl (mp->tunnel.vni),
			     layer,
			     ntohl (mp->tunnel.bd_rd_id), &sw_if_index);

out:
  /* *INDENT-OFF* */
  REPLY_MACRO2 (VL_API_GBP_VXLAN_TUNNEL_ADD_REPLY + GBP_MSG_BASE,
  ({
    rmp->sw_if_index = htonl (sw_if_index);
  }));
  /* *INDENT-ON* */
}

static void
vl_api_gbp_vxlan_tunnel_del_t_handler (vl_api_gbp_vxlan_tunnel_add_t * mp)
{
  vl_api_gbp_vxlan_tunnel_del_reply_t *rmp;
  int rv = 0;

  rv = gbp_vxlan_tunnel_del (ntohl (mp->tunnel.vni));

  REPLY_MACRO (VL_API_GBP_VXLAN_TUNNEL_DEL_REPLY + GBP_MSG_BASE);
}

static vl_api_gbp_vxlan_tunnel_mode_t
gbp_vxlan_tunnel_layer_2_mode (gbp_vxlan_tunnel_layer_t layer)
{
  vl_api_gbp_vxlan_tunnel_mode_t mode = GBP_VXLAN_TUNNEL_MODE_L2;

  switch (layer)
    {
    case GBP_VXLAN_TUN_L2:
      mode = GBP_VXLAN_TUNNEL_MODE_L2;
      break;
    case GBP_VXLAN_TUN_L3:
      mode = GBP_VXLAN_TUNNEL_MODE_L3;
      break;
    }
  mode = clib_host_to_net_u32 (mode);

  return (mode);
}

static walk_rc_t
gbp_vxlan_tunnel_send_details (gbp_vxlan_tunnel_t * gt, void *args)
{
  vl_api_gbp_vxlan_tunnel_details_t *mp;
  gbp_walk_ctx_t *ctx;

  ctx = args;
  mp = vl_msg_api_alloc (sizeof (*mp));
  if (!mp)
    return 1;

  memset (mp, 0, sizeof (*mp));
  mp->_vl_msg_id = htons (VL_API_GBP_VXLAN_TUNNEL_DETAILS + GBP_MSG_BASE);
  mp->context = ctx->context;

  mp->tunnel.vni = htonl (gt->gt_vni);
  mp->tunnel.mode = gbp_vxlan_tunnel_layer_2_mode (gt->gt_layer);
  mp->tunnel.bd_rd_id = htonl (gt->gt_bd_rd_id);

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

  return (1);
}

static void
vl_api_gbp_vxlan_tunnel_dump_t_handler (vl_api_gbp_vxlan_tunnel_dump_t * mp)
{
  vl_api_registration_t *reg;

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

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

  gbp_vxlan_walk (gbp_vxlan_tunnel_send_details, &ctx);
}

/*
 * gbp_api_hookup
 * Add vpe's API message handlers to the table.
 * vlib has already mapped shared memory and
 * added the client registration handlers.
 * See .../vlib-api/vlibmemory/memclnt_vlib.c:memclnt_process()
 */
#define vl_msg_name_crc_list
#include <gbp/gbp_all_api_h.h>
#undef vl_msg_name_crc_list

static void
setup_message_id_table (api_main_t * am)
{
#define _(id,n,crc)                                     \
  vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + GBP_MSG_BASE);
  foreach_vl_msg_name_crc_gbp;
#undef _
}

static void
gbp_api_hookup (vlib_main_t * vm)
{
#define _(N,n)                                                  \
    vl_msg_api_set_handlers(VL_API_##N + GBP_MSG_BASE,          \
                            #n,                                 \
                            vl_api_##n##_t_handler,             \
                            vl_noop_handler,                    \
                            vl_api_##n##_t_endian,              \
                            vl_api_##n##_t_print,               \
                            sizeof(vl_api_##n##_t), 1);
  foreach_gbp_api_msg;
#undef _
}

static clib_error_t *
gbp_init (vlib_main_t * vm)
{
  api_main_t *am = &api_main;
  gbp_main_t *gbpm = &gbp_main;
  u8 *name = format (0, "gbp_%08x%c", api_version, 0);

  gbpm->gbp_acl_user_id = ~0;

  /* Ask for a correctly-sized block of API message decode slots */
  msg_id_base = vl_msg_api_get_msg_ids ((char *) name,
					VL_MSG_FIRST_AVAILABLE);
  gbp_api_hookup (vm);

  /* Add our API messages to the global name_crc hash table */
  setup_message_id_table (am);

  vec_free (name);
  return (NULL);
}

VLIB_API_INIT_FUNCTION (gbp_init);

/* *INDENT-OFF* */
VLIB_PLUGIN_REGISTER () = {
    .version = VPP_BUILD_VER,
    .description = "Group Based Policy",
};
/* *INDENT-ON* */


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