summaryrefslogtreecommitdiffstats
path: root/src/plugins/nat/lib/nat_syslog.c
diff options
context:
space:
mode:
authorFilip Varga <fivarga@cisco.com>2020-11-09 12:24:03 +0100
committerOle Tr�an <otroan@employees.org>2020-11-13 15:45:23 +0000
commit25fd8ad03e6ef321604437fe8fc56ab2b3858cd7 (patch)
treef362bfad633f80ebad6c811dbf7c98ef5a701ddb /src/plugins/nat/lib/nat_syslog.c
parente655240550f0670279b0ca40942887715b8f514e (diff)
nat: cleanup & reorganization
Fixed compatibility issue between nat ei and nat ed modes. Moved nat syslogging to nat librarry. Deprecating apis that will be integrated in upcoming candidate configuration patch. Type: refactor Change-Id: I334b1b05b81b74667c5c76a05f768442e0dcf7e8 Signed-off-by: Filip Varga <fivarga@cisco.com>
Diffstat (limited to 'src/plugins/nat/lib/nat_syslog.c')
-rw-r--r--src/plugins/nat/lib/nat_syslog.c288
1 files changed, 288 insertions, 0 deletions
diff --git a/src/plugins/nat/lib/nat_syslog.c b/src/plugins/nat/lib/nat_syslog.c
new file mode 100644
index 00000000000..2c395bf7fd8
--- /dev/null
+++ b/src/plugins/nat/lib/nat_syslog.c
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 2020 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.
+ */
+/**
+ * @file
+ * @brief NAT syslog logging
+ */
+#include <vnet/fib/fib_table.h>
+#include <vnet/ip/ip.h>
+#include <vnet/syslog/syslog.h>
+
+#include <nat/lib/nat_syslog.h>
+#include <nat/lib/inlines.h>
+
+#define NAT_FACILITY SYSLOG_FACILITY_LOCAL0
+
+#define NAT_APPNAME "NAT"
+
+#define SADD_SDEL_SEVERITY SYSLOG_SEVERITY_INFORMATIONAL
+#define APMADD_APMDEL_SEVERITY SYSLOG_SEVERITY_INFORMATIONAL
+
+#define SADD_MSGID "SADD"
+#define SDEL_MSGID "SDEL"
+#define APMADD_MSGID "APMADD"
+#define APMDEL_MSGID "APMDEL"
+
+#define NSESS_SDID "nsess"
+#define NAPMAP_SDID "napmap"
+
+#define SSUBIX_SDPARAM_NAME "SSUBIX"
+#define SVLAN_SDPARAM_NAME "SVLAN"
+#define IATYP_SDPARAM_NAME "IATYP"
+#define ISADDR_SDPARAM_NAME "ISADDR"
+#define ISPORT_SDPARAM_NAME "ISPORT"
+#define IDADDR_SDPARAM_NAME "IDADDR"
+#define IDPORT_SDPARAM_NAME "IDPORT"
+#define XATYP_SDPARAM_NAME "XATYP"
+#define XSADDR_SDPARAM_NAME "XSADDR"
+#define XSPORT_SDPARAM_NAME "XSPORT"
+#define XDADDR_SDPARAM_NAME "XDADDR"
+#define XDPORT_SDPARAM_NAME "XDPORT"
+#define PROTO_SDPARAM_NAME "PROTO"
+#define SV6ENC_SDPARAM_NAME "SV6ENC"
+
+#define IATYP_IPV4 "IPv4"
+#define IATYP_IPV6 "IPv6"
+
+static inline void
+nat_syslog_nat44_apmap (u32 ssubix, u32 sfibix, ip4_address_t * isaddr,
+ u16 isport, ip4_address_t * xsaddr, u16 xsport,
+ nat_protocol_t proto, u8 is_add,
+ ip6_address_t * sv6enc)
+{
+ syslog_msg_t syslog_msg;
+ fib_table_t *fib;
+
+ if (!syslog_is_enabled ())
+ return;
+
+ if (syslog_severity_filter_block (APMADD_APMDEL_SEVERITY))
+ return;
+
+ syslog_msg_init (&syslog_msg, NAT_FACILITY, APMADD_APMDEL_SEVERITY,
+ NAT_APPNAME, is_add ? APMADD_MSGID : APMDEL_MSGID);
+
+ syslog_msg_sd_init (&syslog_msg, NAPMAP_SDID);
+ syslog_msg_add_sd_param (&syslog_msg, SSUBIX_SDPARAM_NAME, "%d", ssubix);
+ if (sv6enc)
+ {
+ syslog_msg_add_sd_param (&syslog_msg, SV6ENC_SDPARAM_NAME, "%U",
+ format_ip6_address, sv6enc);
+ }
+ else
+ {
+ fib = fib_table_get (sfibix, FIB_PROTOCOL_IP4);
+ syslog_msg_add_sd_param (&syslog_msg, SVLAN_SDPARAM_NAME, "%d",
+ fib->ft_table_id);
+ }
+ syslog_msg_add_sd_param (&syslog_msg, IATYP_SDPARAM_NAME, IATYP_IPV4);
+ syslog_msg_add_sd_param (&syslog_msg, ISADDR_SDPARAM_NAME, "%U",
+ format_ip4_address, isaddr);
+ syslog_msg_add_sd_param (&syslog_msg, ISPORT_SDPARAM_NAME, "%d",
+ clib_net_to_host_u16 (isport));
+ syslog_msg_add_sd_param (&syslog_msg, XATYP_SDPARAM_NAME, IATYP_IPV4);
+ syslog_msg_add_sd_param (&syslog_msg, XSADDR_SDPARAM_NAME, "%U",
+ format_ip4_address, xsaddr);
+ syslog_msg_add_sd_param (&syslog_msg, XSPORT_SDPARAM_NAME, "%d",
+ clib_net_to_host_u16 (xsport));
+ syslog_msg_add_sd_param (&syslog_msg, PROTO_SDPARAM_NAME, "%d",
+ nat_proto_to_ip_proto (proto));
+
+ syslog_msg_send (&syslog_msg);
+}
+
+void
+nat_syslog_nat44_apmadd (u32 ssubix, u32 sfibix, ip4_address_t * isaddr,
+ u16 isport, ip4_address_t * xsaddr, u16 xsport,
+ nat_protocol_t proto)
+{
+ nat_syslog_nat44_apmap (ssubix, sfibix, isaddr, isport, xsaddr, xsport,
+ proto, 1, 0);
+}
+
+void
+nat_syslog_nat44_apmdel (u32 ssubix, u32 sfibix, ip4_address_t * isaddr,
+ u16 isport, ip4_address_t * xsaddr, u16 xsport,
+ nat_protocol_t proto)
+{
+ nat_syslog_nat44_apmap (ssubix, sfibix, isaddr, isport, xsaddr, xsport,
+ proto, 0, 0);
+}
+
+void
+nat_syslog_dslite_apmadd (u32 ssubix, ip6_address_t * sv6enc,
+ ip4_address_t * isaddr, u16 isport,
+ ip4_address_t * xsaddr, u16 xsport,
+ nat_protocol_t proto)
+{
+ nat_syslog_nat44_apmap (ssubix, 0, isaddr, isport, xsaddr, xsport,
+ proto, 1, sv6enc);
+}
+
+void
+nat_syslog_dslite_apmdel (u32 ssubix, ip6_address_t * sv6enc,
+ ip4_address_t * isaddr, u16 isport,
+ ip4_address_t * xsaddr, u16 xsport,
+ nat_protocol_t proto)
+{
+ nat_syslog_nat44_apmap (ssubix, 0, isaddr, isport, xsaddr, xsport,
+ proto, 0, sv6enc);
+}
+
+static inline void
+nat_syslog_nat44_sess (u32 ssubix, u32 sfibix, ip4_address_t * isaddr,
+ u16 isport, ip4_address_t * xsaddr, u16 xsport,
+ ip4_address_t * idaddr, u16 idport,
+ ip4_address_t * xdaddr, u16 xdport,
+ nat_protocol_t proto, u8 is_add, u8 is_twicenat)
+{
+ syslog_msg_t syslog_msg;
+ fib_table_t *fib;
+
+ if (!syslog_is_enabled ())
+ return;
+
+ if (syslog_severity_filter_block (SADD_SDEL_SEVERITY))
+ return;
+
+ fib = fib_table_get (sfibix, FIB_PROTOCOL_IP4);
+
+ syslog_msg_init (&syslog_msg, NAT_FACILITY, SADD_SDEL_SEVERITY, NAT_APPNAME,
+ is_add ? SADD_MSGID : SDEL_MSGID);
+
+ syslog_msg_sd_init (&syslog_msg, NSESS_SDID);
+ syslog_msg_add_sd_param (&syslog_msg, SSUBIX_SDPARAM_NAME, "%d", ssubix);
+ syslog_msg_add_sd_param (&syslog_msg, SVLAN_SDPARAM_NAME, "%d",
+ fib->ft_table_id);
+ syslog_msg_add_sd_param (&syslog_msg, IATYP_SDPARAM_NAME, IATYP_IPV4);
+ syslog_msg_add_sd_param (&syslog_msg, ISADDR_SDPARAM_NAME, "%U",
+ format_ip4_address, isaddr);
+ syslog_msg_add_sd_param (&syslog_msg, ISPORT_SDPARAM_NAME, "%d",
+ clib_net_to_host_u16 (isport));
+ syslog_msg_add_sd_param (&syslog_msg, XATYP_SDPARAM_NAME, IATYP_IPV4);
+ syslog_msg_add_sd_param (&syslog_msg, XSADDR_SDPARAM_NAME, "%U",
+ format_ip4_address, xsaddr);
+ syslog_msg_add_sd_param (&syslog_msg, XSPORT_SDPARAM_NAME, "%d",
+ clib_net_to_host_u16 (xsport));
+ syslog_msg_add_sd_param (&syslog_msg, PROTO_SDPARAM_NAME, "%d",
+ nat_proto_to_ip_proto (proto));
+ syslog_msg_add_sd_param (&syslog_msg, XDADDR_SDPARAM_NAME, "%U",
+ format_ip4_address, xdaddr);
+ syslog_msg_add_sd_param (&syslog_msg, XDPORT_SDPARAM_NAME, "%d",
+ clib_net_to_host_u16 (xdport));
+ if (is_twicenat)
+ {
+ syslog_msg_add_sd_param (&syslog_msg, IDADDR_SDPARAM_NAME, "%U",
+ format_ip4_address, idaddr);
+ syslog_msg_add_sd_param (&syslog_msg, IDPORT_SDPARAM_NAME, "%d",
+ clib_net_to_host_u16 (idport));
+ }
+
+ syslog_msg_send (&syslog_msg);
+}
+
+void
+nat_syslog_nat44_sadd (u32 ssubix, u32 sfibix, ip4_address_t * isaddr,
+ u16 isport, ip4_address_t * idaddr, u16 idport,
+ ip4_address_t * xsaddr, u16 xsport,
+ ip4_address_t * xdaddr, u16 xdport,
+ nat_protocol_t proto, u8 is_twicenat)
+{
+ nat_syslog_nat44_sess (ssubix, sfibix, isaddr, isport, xsaddr, xsport,
+ idaddr, idport, xdaddr, xdport, proto, 1,
+ is_twicenat);
+}
+
+void
+nat_syslog_nat44_sdel (u32 ssubix, u32 sfibix, ip4_address_t * isaddr,
+ u16 isport, ip4_address_t * idaddr, u16 idport,
+ ip4_address_t * xsaddr, u16 xsport,
+ ip4_address_t * xdaddr, u16 xdport,
+ nat_protocol_t proto, u8 is_twicenat)
+{
+ nat_syslog_nat44_sess (ssubix, sfibix, isaddr, isport, xsaddr, xsport,
+ idaddr, idport, xdaddr, xdport, proto, 0,
+ is_twicenat);
+}
+
+static inline void
+nat_syslog_nat64_sess (u32 sfibix, ip6_address_t * isaddr, u16 isport,
+ ip4_address_t * xsaddr, u16 xsport,
+ ip4_address_t * xdaddr, u16 xdport,
+ nat_protocol_t proto, u8 is_add)
+{
+ syslog_msg_t syslog_msg;
+ fib_table_t *fib;
+
+ if (!syslog_is_enabled ())
+ return;
+
+ if (syslog_severity_filter_block (SADD_SDEL_SEVERITY))
+ return;
+
+ fib = fib_table_get (sfibix, FIB_PROTOCOL_IP6);
+
+ syslog_msg_init (&syslog_msg, NAT_FACILITY, SADD_SDEL_SEVERITY, NAT_APPNAME,
+ is_add ? SADD_MSGID : SDEL_MSGID);
+
+ syslog_msg_sd_init (&syslog_msg, NSESS_SDID);
+ syslog_msg_add_sd_param (&syslog_msg, SVLAN_SDPARAM_NAME, "%d",
+ fib->ft_table_id);
+ syslog_msg_add_sd_param (&syslog_msg, IATYP_SDPARAM_NAME, IATYP_IPV6);
+ syslog_msg_add_sd_param (&syslog_msg, ISADDR_SDPARAM_NAME, "%U",
+ format_ip6_address, isaddr);
+ syslog_msg_add_sd_param (&syslog_msg, ISPORT_SDPARAM_NAME, "%d",
+ clib_net_to_host_u16 (isport));
+ syslog_msg_add_sd_param (&syslog_msg, XATYP_SDPARAM_NAME, IATYP_IPV4);
+ syslog_msg_add_sd_param (&syslog_msg, XSADDR_SDPARAM_NAME, "%U",
+ format_ip4_address, xsaddr);
+ syslog_msg_add_sd_param (&syslog_msg, XSPORT_SDPARAM_NAME, "%d",
+ clib_net_to_host_u16 (xsport));
+ syslog_msg_add_sd_param (&syslog_msg, PROTO_SDPARAM_NAME, "%d", proto);
+ syslog_msg_add_sd_param (&syslog_msg, XDADDR_SDPARAM_NAME, "%U",
+ format_ip4_address, xdaddr);
+ syslog_msg_add_sd_param (&syslog_msg, XDPORT_SDPARAM_NAME, "%d",
+ clib_net_to_host_u16 (xdport));
+
+ syslog_msg_send (&syslog_msg);
+}
+
+void
+nat_syslog_nat64_sadd (u32 sfibix, ip6_address_t * isaddr, u16 isport,
+ ip4_address_t * xsaddr, u16 xsport,
+ ip4_address_t * xdaddr, u16 xdport,
+ nat_protocol_t proto)
+{
+ nat_syslog_nat64_sess (sfibix, isaddr, isport, xsaddr, xsport, xdaddr,
+ xdport, proto, 1);
+}
+
+void
+nat_syslog_nat64_sdel (u32 sfibix, ip6_address_t * isaddr, u16 isport,
+ ip4_address_t * xsaddr, u16 xsport,
+ ip4_address_t * xdaddr, u16 xdport,
+ nat_protocol_t proto)
+{
+ nat_syslog_nat64_sess (sfibix, isaddr, isport, xsaddr, xsport, xdaddr,
+ xdport, proto, 0);
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
unction.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 */ }
/*
 * vrrp.c - vpp vrrp plug-in
 *
 * Copyright 2019-2020 Rubicon Communications, LLC (Netgate)
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 */

#include <vnet/vnet.h>
#include <vnet/plugin/plugin.h>
#include <vrrp/vrrp.h>

#include <vlibapi/api.h>
#include <vlibmemory/api.h>
#include <vpp/app/version.h>

/* define message IDs */
#include <vnet/format_fns.h>
#include <vrrp/vrrp.api_enum.h>
#include <vrrp/vrrp.api_types.h>

#define REPLY_MSG_ID_BASE vrrp_main.msg_id_base
#include <vlibapi/api_helper_macros.h>

/* API message handlers */
static void
vl_api_vrrp_vr_add_del_t_handler (vl_api_vrrp_vr_add_del_t * mp)
{
  vl_api_vrrp_vr_add_del_reply_t *rmp;
  vrrp_vr_config_t vr_conf;
  u32 api_flags;
  ip46_address_t *addrs = 0;
  int rv;

  VALIDATE_SW_IF_INDEX (mp);

  api_flags = htonl (mp->flags);

  clib_memset (&vr_conf, 0, sizeof (vr_conf));

  vr_conf.sw_if_index = ntohl (mp->sw_if_index);
  vr_conf.vr_id = mp->vr_id;
  vr_conf.priority = mp->priority;
  vr_conf.adv_interval = ntohs (mp->interval);

  if (api_flags & VRRP_API_VR_PREEMPT)
    vr_conf.flags |= VRRP_VR_PREEMPT;

  if (api_flags & VRRP_API_VR_ACCEPT)
    vr_conf.flags |= VRRP_VR_ACCEPT;

  if (api_flags & VRRP_API_VR_UNICAST)
    vr_conf.flags |= VRRP_VR_UNICAST;

  if (api_flags & VRRP_API_VR_IPV6)
    vr_conf.flags |= VRRP_VR_IPV6;

  if (mp->is_add)
    {
      int i;

      for (i = 0; i < mp->n_addrs; i++)
	{
	  ip46_address_t *addr;
	  void *src, *dst;
	  int len;

	  vec_add2 (addrs, addr, 1);

	  if (ntohl (mp->addrs[i].af) == ADDRESS_IP4)
	    {
	      src = &mp->addrs[i].un.ip4;
	      dst = &addr->ip4;
	      len = sizeof (addr->ip4);
	    }
	  else
	    {
	      src = &mp->addrs[i].un.ip6;
	      dst = &addr->ip6;
	      len = sizeof (addr->ip6);
	    }

	  clib_memcpy (dst, src, len);
	}

      vr_conf.vr_addrs = addrs;
    }

  if (vr_conf.priority == 0)
    {
      clib_warning ("VR priority must be > 0");
      rv = VNET_API_ERROR_INVALID_VALUE;
    }
  else if (vr_conf.adv_interval == 0)
    {
      clib_warning ("VR advertisement interval must be > 0");
      rv = VNET_API_ERROR_INVALID_VALUE;
    }
  else if (vr_conf.vr_id == 0)
    {
      clib_warning ("VR ID must be > 0");
      rv = VNET_API_ERROR_INVALID_VALUE;
    }
  else
    rv = vrrp_vr_add_del (mp->is_add, &vr_conf);

  vec_free (addrs);

  BAD_SW_IF_INDEX_LABEL;
  REPLY_MACRO (VL_API_VRRP_VR_ADD_DEL_REPLY);
}

static vl_api_vrrp_vr_state_t
vrrp_vr_state_encode (vrrp_vr_state_t vr_state)
{
  if (vr_state == VRRP_VR_STATE_BACKUP)
    return VRRP_API_VR_STATE_BACKUP;
  if (vr_state == VRRP_VR_STATE_MASTER)
    return VRRP_API_VR_STATE_MASTER;
  if (vr_state == VRRP_VR_STATE_INTF_DOWN)
    return VRRP_API_VR_STATE_INTF_DOWN;

  return VRRP_API_VR_STATE_INIT;
}

static void
send_vrrp_vr_details (vrrp_vr_t * vr, vl_api_registration_t * reg,
		      u32 context)
{
  vrrp_main_t *vmp = &vrrp_main;
  vl_api_vrrp_vr_details_t *mp;
  int n_addrs, msg_size;
  ip46_address_t *addr;
  vl_api_address_t *api_addr;
  u32 api_flags = 0;

  n_addrs = vec_len (vr->config.vr_addrs);
  msg_size = sizeof (*mp) + n_addrs * sizeof (*api_addr);
  mp = vl_msg_api_alloc (msg_size);
  if (!mp)
    return;
  clib_memset (mp, 0, msg_size);
  mp->_vl_msg_id = htons (VL_API_VRRP_VR_DETAILS + vmp->msg_id_base);
  mp->context = context;

  /* config */
  mp->config.sw_if_index = htonl (vr->config.sw_if_index);
  mp->config.vr_id = vr->config.vr_id;
  mp->config.priority = vr->config.priority;
  mp->config.interval = htons (vr->config.adv_interval);

  if (vr->config.flags & VRRP_VR_PREEMPT)
    api_flags |= VRRP_API_VR_PREEMPT;
  if (vr->config.flags & VRRP_VR_ACCEPT)
    api_flags |= VRRP_API_VR_ACCEPT;
  if (vrrp_vr_is_unicast (vr))
    api_flags |= VRRP_API_VR_UNICAST;
  if (vrrp_vr_is_ipv6 (vr))
    api_flags |= VRRP_API_VR_IPV6;

  mp->config.flags = htonl (api_flags);

  /* runtime */
  mp->runtime.state = htonl (vrrp_vr_state_encode (vr->runtime.state));

  mp->runtime.master_adv_int = htons (vr->runtime.master_adv_int);
  mp->runtime.skew = htons (vr->runtime.skew);
  mp->runtime.master_down_int = htons (vr->runtime.master_down_int);
  clib_memcpy (&mp->runtime.mac, &vr->runtime.mac, sizeof (vr->runtime.mac));

  mp->runtime.tracking.interfaces_dec = htonl (vr->tracking.interfaces_dec);
  mp->runtime.tracking.priority = vrrp_vr_priority (vr);

  /* addrs */
  mp->n_addrs = vec_len (vr->config.vr_addrs);
  api_addr = mp->addrs;
  vec_foreach (addr, vr->config.vr_addrs)
  {
    void *src, *dst;
    size_t len;

    if (vrrp_vr_is_ipv6 (vr))
      {
	api_addr->af = ADDRESS_IP6;
	dst = &api_addr->un.ip6;
	src = &addr->ip6;
	len = sizeof (addr->ip6);
      }
    else
      {
	api_addr->af = ADDRESS_IP4;
	dst = &api_addr->un.ip4;
	src = &addr->ip4;
	len = sizeof (addr->ip4);
      }
    clib_memcpy (dst, src, len);
    api_addr++;
  }

  vl_api_send_msg (reg, (u8 *) mp);
}

static void
vl_api_vrrp_vr_dump_t_handler (vl_api_vrrp_vr_dump_t * mp)
{
  vrrp_main_t *vmp = &vrrp_main;
  vl_api_registration_t *reg;
  vrrp_vr_t *vr;
  u32 sw_if_index;

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

  sw_if_index = htonl (mp->sw_if_index);

  /* *INDENT-OFF* */
  pool_foreach (vr, vmp->vrs)  {

    if (sw_if_index && (sw_if_index != ~0) &&
	(sw_if_index != vr->config.sw_if_index))
      continue;

    send_vrrp_vr_details (vr, reg, mp->context);
  }
  /* *INDENT-ON* */
}

static void
vl_api_vrrp_vr_start_stop_t_handler (vl_api_vrrp_vr_start_stop_t * mp)
{
  vl_api_vrrp_vr_start_stop_reply_t *rmp;
  vrrp_vr_key_t vr_key;
  int rv;

  clib_memset (&vr_key, 0, sizeof (vr_key));

  vr_key.sw_if_index = ntohl (mp->sw_if_index);
  vr_key.vr_id = mp->vr_id;
  vr_key.is_ipv6 = (mp->is_ipv6 != 0);

  rv = vrrp_vr_start_stop ((mp->is_start != 0), &vr_key);

  REPLY_MACRO (VL_API_VRRP_VR_START_STOP_REPLY);
}

static void
vl_api_vrrp_vr_set_peers_t_handler (vl_api_vrrp_vr_set_peers_t * mp)
{
  vl_api_vrrp_vr_set_peers_reply_t *rmp;
  vrrp_vr_key_t vr_key;
  ip46_address_t *peer_addrs = 0;
  int i;
  int rv;

  clib_memset (&vr_key, 0, sizeof (vr_key));

  vr_key.sw_if_index = ntohl (mp->sw_if_index);
  vr_key.vr_id = mp->vr_id;
  vr_key.is_ipv6 = (mp->is_ipv6 != 0);

  for (i = 0; i < mp->n_addrs; i++)
    {
      ip46_address_t *peer;

      vec_add2 (peer_addrs, peer, 1);

      if (mp->is_ipv6)
	clib_memcpy (&peer->ip6, mp->addrs[i].un.ip6, 16);
      else
	clib_memcpy (&peer->ip4, mp->addrs[i].un.ip4, 4);
    }

  rv = vrrp_vr_set_peers (&vr_key, peer_addrs);

  vec_free (peer_addrs);
  REPLY_MACRO (VL_API_VRRP_VR_SET_PEERS_REPLY);
}

static void
send_vrrp_vr_peer_details (vrrp_vr_t * vr, vl_api_registration_t * reg,
			   u32 context)
{
  vrrp_main_t *vmp = &vrrp_main;
  vl_api_vrrp_vr_peer_details_t *mp;
  int n_addrs, msg_size;
  ip46_address_t *addr;
  vl_api_address_t *api_addr;

  n_addrs = vec_len (vr->config.peer_addrs);
  msg_size = sizeof (*mp) + n_addrs * sizeof (*api_addr);
  mp = vl_msg_api_alloc (msg_size);
  if (!mp)
    return;
  clib_memset (mp, 0, msg_size);
  mp->_vl_msg_id = htons (VL_API_VRRP_VR_PEER_DETAILS + vmp->msg_id_base);
  mp->context = context;

  mp->sw_if_index = htonl (vr->config.sw_if_index);
  mp->vr_id = vr->config.vr_id;
  mp->is_ipv6 = vrrp_vr_is_ipv6 (vr);

  /* addrs */
  mp->n_peer_addrs = n_addrs;
  api_addr = mp->peer_addrs;
  vec_foreach (addr, vr->config.peer_addrs)
  {
    void *src, *dst;
    size_t len;

    if (vrrp_vr_is_ipv6 (vr))
      {
	api_addr->af = ADDRESS_IP6;
	dst = &api_addr->un.ip6;
	src = &addr->ip6;
	len = sizeof (addr->ip6);
      }
    else
      {
	api_addr->af = ADDRESS_IP4;
	dst = &api_addr->un.ip4;
	src = &addr->ip4;
	len = sizeof (addr->ip4);
      }
    clib_memcpy (dst, src, len);
    api_addr++;
  }

  vl_api_send_msg (reg, (u8 *) mp);
}

static void
vl_api_vrrp_vr_peer_dump_t_handler (vl_api_vrrp_vr_peer_dump_t * mp)
{
  vrrp_main_t *vmp = &vrrp_main;
  vl_api_registration_t *reg;
  vrrp_vr_t *vr;
  vrrp_vr_key_t vr_key;

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

  vr_key.sw_if_index = ntohl (mp->sw_if_index);

  if (vr_key.sw_if_index && (vr_key.sw_if_index != ~0))
    {
      uword *p;
      u32 vr_index = ~0;

      vr_key.vr_id = mp->vr_id;
      vr_key.is_ipv6 = mp->is_ipv6;

      p = mhash_get (&vmp->vr_index_by_key, &vr_key);
      if (!p)
	return;

      vr_index = p[0];
      vr = pool_elt_at_index (vmp->vrs, vr_index);
      send_vrrp_vr_peer_details (vr, reg, mp->context);

      return;
    }

  /* *INDENT-OFF* */
  pool_foreach (vr, vmp->vrs)  {

    if (!vec_len (vr->config.peer_addrs))
      continue;

    send_vrrp_vr_details (vr, reg, mp->context);

  }
  /* *INDENT-ON* */
}

static void
  vl_api_vrrp_vr_track_if_add_del_t_handler
  (vl_api_vrrp_vr_track_if_add_del_t * mp)
{
  vl_api_vrrp_vr_track_if_add_del_reply_t *rmp;
  vrrp_vr_t *vr;
  vrrp_vr_tracking_if_t *track_if, *track_ifs = 0;
  int rv = 0, i;

  /* lookup VR and return error if it does not exist */
  vr =
    vrrp_vr_lookup (ntohl (mp->sw_if_index), mp->vr_id, (mp->is_ipv6 != 0));
  if (!vr)
    {
      rv = VNET_API_ERROR_INVALID_VALUE;
      goto done;
    }

  for (i = 0; i < mp->n_ifs; i++)
    {
      vl_api_vrrp_vr_track_if_t *api_track_if = &mp->ifs[i];

      vec_add2 (track_ifs, track_if, 1);
      track_if->sw_if_index = ntohl (api_track_if->sw_if_index);
      track_if->priority = api_track_if->priority;
    }

  rv = vrrp_vr_tracking_ifs_add_del (vr, track_ifs, mp->is_add != 0);

done:
  vec_free (track_ifs);
  REPLY_MACRO (VL_API_VRRP_VR_TRACK_IF_ADD_DEL_REPLY);
}

static void
send_vrrp_vr_track_if_details (vrrp_vr_t * vr, vl_api_registration_t * reg,
			       u32 context)
{
  vrrp_main_t *vmp = &vrrp_main;
  vl_api_vrrp_vr_track_if_details_t *mp;
  int n_ifs, msg_size;
  vl_api_vrrp_vr_track_if_t *api_track_if;
  vrrp_vr_tracking_if_t *track_if;

  if (!vr)
    return;

  n_ifs = vec_len (vr->tracking.interfaces);
  msg_size = sizeof (*mp) + n_ifs * sizeof (*api_track_if);
  mp = vl_msg_api_alloc (msg_size);
  if (!mp)
    return;
  clib_memset (mp, 0, msg_size);
  mp->_vl_msg_id = htons (VL_API_VRRP_VR_TRACK_IF_DETAILS + vmp->msg_id_base);
  mp->context = context;

  mp->sw_if_index = htonl (vr->config.sw_if_index);
  mp->vr_id = vr->config.vr_id;
  mp->is_ipv6 = vrrp_vr_is_ipv6 (vr);

  /* tracked interfaces */
  mp->n_ifs = n_ifs;
  api_track_if = mp->ifs;
  vec_foreach (track_if, vr->tracking.interfaces)
  {
    api_track_if->sw_if_index = htonl (track_if->sw_if_index);
    api_track_if->priority = track_if->priority;
    api_track_if += 1;
  }

  vl_api_send_msg (reg, (u8 *) mp);
}

static void
vl_api_vrrp_vr_track_if_dump_t_handler (vl_api_vrrp_vr_track_if_dump_t * mp)
{
  vrrp_main_t *vmp = &vrrp_main;
  vl_api_registration_t *reg;
  vrrp_vr_t *vr;

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

  if (!mp->dump_all)
    {
      vr = vrrp_vr_lookup (ntohl (mp->sw_if_index), mp->vr_id, mp->is_ipv6);
      send_vrrp_vr_track_if_details (vr, reg, mp->context);

      return;
    }

  /* *INDENT-OFF* */
  pool_foreach (vr, vmp->vrs)  {

    if (!vec_len (vr->tracking.interfaces))
      continue;

    send_vrrp_vr_track_if_details (vr, reg, mp->context);

  }
  /* *INDENT-ON* */
}

static void
send_vrrp_vr_event (vpe_client_registration_t * reg,
		    vl_api_registration_t * vl_reg,
		    vrrp_vr_t * vr, vrrp_vr_state_t new_state)
{
  vrrp_main_t *vmp = &vrrp_main;
  vl_api_vrrp_vr_event_t *mp;

  mp = vl_msg_api_alloc (sizeof (*mp));

  clib_memset (mp, 0, sizeof (*mp));
  mp->_vl_msg_id = ntohs (VL_API_VRRP_VR_EVENT + vmp->msg_id_base);
  mp->client_index = reg->client_index;
  mp->pid = reg->client_pid;
  mp->vr.sw_if_index = ntohl (vr->config.sw_if_index);
  mp->vr.vr_id = vr->config.vr_id;
  mp->vr.is_ipv6 = ((vr->config.flags & VRRP_VR_IPV6) != 0);

  mp->old_state = htonl (vrrp_vr_state_encode (vr->runtime.state));
  mp->new_state = htonl (vrrp_vr_state_encode (new_state));

  vl_api_send_msg (vl_reg, (u8 *) mp);
}

void
vrrp_vr_event (vrrp_vr_t * vr, vrrp_vr_state_t new_state)
{
  vpe_api_main_t *vam = &vpe_api_main;
  vpe_client_registration_t *reg;
  vl_api_registration_t *vl_reg;

  /* *INDENT-OFF* */
  pool_foreach (reg, vam->vrrp_vr_events_registrations)
   {
    vl_reg = vl_api_client_index_to_registration (reg->client_index);
    if (vl_reg)
      send_vrrp_vr_event (reg, vl_reg, vr, new_state);
  }
  /* *INDENT-ON* */
}

pub_sub_handler (vrrp_vr_events, VRRP_VR_EVENTS);

/* Set up the API message handling tables */
#include <vrrp/vrrp.api.c>
clib_error_t *
vrrp_plugin_api_hookup (vlib_main_t * vm)
{
  vrrp_main_t *vmp = &vrrp_main;

  /* Ask for a correctly-sized block of API message decode slots */
  vmp->msg_id_base = setup_message_id_table ();

  return 0;
}

/* *INDENT-ON* */

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