aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEmanuele Di Pascale <lele84@gmail.com>2022-03-29 12:29:23 +0200
committerEmanuele Di Pascale <lele84@gmail.com>2022-04-01 18:10:35 +0200
commit7539e4b5522b015a715ba49eed4477b8cece1b86 (patch)
tree9f181557091c4125d1561f606fa40f4d0f5d2ef5 /src
parent2518dca440f1ef41500d73067fe44318b782b98d (diff)
vrrp: add stats support and update API
Add simple counter statistics to VRRP, based on a subset of those defined in RFC8347. Add an update API that allows in-place modification of an existing instance. The method returns a vrrp_index which can be used both for retrieving statistics and to modify non-key parameters. Also add a delete method which will take that vrrp_index as parameter. Type: improvement Signed-off-by: Emanuele Di Pascale <lele84@gmail.com> Change-Id: I2cd11467b4dbd9dfdb5aa748783144b4883dba57
Diffstat (limited to 'src')
-rw-r--r--src/plugins/vrrp/node.c10
-rw-r--r--src/plugins/vrrp/vrrp.api51
-rw-r--r--src/plugins/vrrp/vrrp.c274
-rw-r--r--src/plugins/vrrp/vrrp.h43
-rw-r--r--src/plugins/vrrp/vrrp_api.c105
-rw-r--r--src/plugins/vrrp/vrrp_cli.c2
-rw-r--r--src/plugins/vrrp/vrrp_packet.c6
-rw-r--r--src/plugins/vrrp/vrrp_test.c170
8 files changed, 643 insertions, 18 deletions
diff --git a/src/plugins/vrrp/node.c b/src/plugins/vrrp/node.c
index c6b619ec74c..3cf4ec49635 100644
--- a/src/plugins/vrrp/node.c
+++ b/src/plugins/vrrp/node.c
@@ -130,6 +130,7 @@ vrrp_input_process_master (vrrp_vr_t *vr, vrrp_input_process_args_t *args)
{
clib_warning ("Received shutdown message from a peer on VR %U",
format_vrrp_vr_key, vr);
+ vrrp_incr_stat_counter (VRRP_STAT_COUNTER_PRIO0_RCVD, vr->stat_index);
vrrp_adv_send (vr, 0);
vrrp_vr_timer_set (vr, VRRP_VR_TIMER_ADV);
return;
@@ -167,6 +168,7 @@ vrrp_input_process_backup (vrrp_vr_t *vr, vrrp_input_process_args_t *args)
{
clib_warning ("Master for VR %U is shutting down", format_vrrp_vr_key,
vr);
+ vrrp_incr_stat_counter (VRRP_STAT_COUNTER_PRIO0_RCVD, vr->stat_index);
vrt->master_down_int = vrt->skew;
vrrp_vr_timer_set (vr, VRRP_VR_TIMER_MASTER_DOWN);
return;
@@ -201,6 +203,8 @@ vrrp_input_process (vrrp_input_process_args_t * args)
return;
}
+ vrrp_incr_stat_counter (VRRP_STAT_COUNTER_ADV_RCVD, vr->stat_index);
+
switch (vr->runtime.state)
{
case VRRP_VR_STATE_INIT:
@@ -607,6 +611,7 @@ vrrp_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
if (*ttl0 != 255)
{
error0 = VRRP_ERROR_BAD_TTL;
+ vrrp_incr_err_counter (VRRP_ERR_COUNTER_TTL);
goto trace;
}
@@ -614,6 +619,7 @@ vrrp_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
if ((vrrp0->vrrp_version_and_type >> 4) != 3)
{
error0 = VRRP_ERROR_NOT_VERSION_3;
+ vrrp_incr_err_counter (VRRP_ERR_COUNTER_VERSION);
goto trace;
}
@@ -622,6 +628,7 @@ vrrp_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
((u32) vrrp0->n_addrs) * addr_len)
{
error0 = VRRP_ERROR_INCOMPLETE_PKT;
+ vrrp_incr_err_counter (VRRP_ERR_COUNTER_PKT_LEN);
goto trace;
}
@@ -629,6 +636,7 @@ vrrp_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
if (rx_csum0 != vrrp_adv_csum (ip0, vrrp0, is_ipv6, payload_len0))
{
error0 = VRRP_ERROR_BAD_CHECKSUM;
+ vrrp_incr_err_counter (VRRP_ERR_COUNTER_CHKSUM);
goto trace;
}
@@ -638,6 +646,7 @@ vrrp_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
vrrp0->vr_id, is_ipv6)))
{
error0 = VRRP_ERROR_UNKNOWN_VR;
+ vrrp_incr_err_counter (VRRP_ERR_COUNTER_VRID);
goto trace;
}
@@ -646,6 +655,7 @@ vrrp_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
if (vrrp0->n_addrs != vec_len (vr0->config.vr_addrs))
{
error0 = VRRP_ERROR_ADDR_MISMATCH;
+ vrrp_incr_err_counter (VRRP_ERR_COUNTER_ADDR_LIST);
goto trace;
}
diff --git a/src/plugins/vrrp/vrrp.api b/src/plugins/vrrp/vrrp.api
index a34b06ffc57..03193e99a2c 100644
--- a/src/plugins/vrrp/vrrp.api
+++ b/src/plugins/vrrp/vrrp.api
@@ -5,7 +5,7 @@
*
*/
-option version = "1.0.1";
+option version = "1.1.1";
import "vnet/interface_types.api";
import "vnet/ip/ip_types.api";
@@ -60,6 +60,55 @@ autoreply define vrrp_vr_add_del {
vl_api_address_t addrs[n_addrs];
};
+/** @brief Replace an existing VRRP virtual router in-place or create a new one
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param vrrp_index - an existing VRRP entry to replace, or 0xffffffff to crate a new one
+ @param sw_if_index - interface backed up by this vr
+ @param vr_id - the VR ID advertised by this vr
+ @param priority - the priority advertised for this vr
+ @param interval - interval between advertisements in centiseconds
+ @param flags - bit flags for booleans - preempt, accept, unicast, ipv6
+ @param n_addrs - number of addresses being backed up by this vr
+ @param addrs - the addresses backed up by this vr
+*/
+define vrrp_vr_update {
+ u32 client_index;
+ u32 context;
+ u32 vrrp_index;
+ vl_api_interface_index_t sw_if_index;
+ u8 vr_id;
+ u8 priority;
+ u16 interval;
+ vl_api_vrrp_vr_flags_t flags;
+ u8 n_addrs;
+ vl_api_address_t addrs[n_addrs];
+};
+
+/**
+ * @brief Reply to a VRRP add/replace
+ * @param context - returned sender context, to match reply w/ request
+ * @param vrrp_index - index of the updated or newly created VRRP instance
+ * @param retval 0 - no error
+ */
+define vrrp_vr_update_reply {
+ u32 context;
+ i32 retval;
+ u32 vrrp_index;
+};
+
+/**
+ * @brief Delete an existing VRRP instance
+ * @param client_index - opaque cookie to identify the sender
+ * @param context - returned sender context, to match reply w/ request
+ * @param vrrp_index - index of the VRRP instance to delete
+ */
+autoreply define vrrp_vr_del {
+ u32 client_index;
+ u32 context;
+ u32 vrrp_index;
+};
+
/** \brief VRRP: dump virtual router data
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
diff --git a/src/plugins/vrrp/vrrp.c b/src/plugins/vrrp/vrrp.c
index 99533edaca0..d28905379b2 100644
--- a/src/plugins/vrrp/vrrp.c
+++ b/src/plugins/vrrp/vrrp.c
@@ -32,6 +32,97 @@ static const mac_address_t ipv6_vmac = {
.bytes = {0x00, 0x00, 0x5e, 0x00, 0x02, 0x00}
};
+vlib_simple_counter_main_t vrrp_errs[] = {
+ /* Total number of VRRP packets received with invalid checksum */
+ {
+ .name = "CHKSUM_ERRS",
+ .stat_segment_name = "/net/vrrp/chksum-errs",
+ },
+ /* Total number of VRRP packets received with unknown or unsupported version
+ */
+ {
+ .name = "VERSION_ERRS",
+ .stat_segment_name = "/net/vrrp/version-errs",
+ },
+ /* Total number of VRRP packets received with invalid VRID */
+ {
+ .name = "VRID_ERRS",
+ .stat_segment_name = "/net/vrrp/vrid-errs",
+ },
+ /* Total number of VRRP packets received with TTL/Hop limit != 255 */
+ {
+ .name = "TTL_ERRS",
+ .stat_segment_name = "/net/vrrp/ttl-errs",
+ },
+ /* Number of packets received with an address list not matching the locally
+ configured one */
+ {
+ .name = "ADDR_LIST_ERRS",
+ .stat_segment_name = "/net/vrrp/addr-list-errs",
+ },
+ /* Number of packets received with a length less than the VRRP header */
+ {
+ .name = "PACKET_LEN_ERRS",
+ .stat_segment_name = "/net/vrrp/packet-len-errs",
+ },
+};
+
+void
+vrrp_incr_err_counter (vrrp_err_counter_t err_type)
+{
+ if (err_type >= VRRP_ERR_COUNTER_MAX)
+ {
+ clib_warning ("Attempt to increse error counter of unknown type %u",
+ err_type);
+ return;
+ }
+ vlib_increment_simple_counter (&vrrp_errs[err_type],
+ vlib_get_main ()->thread_index, 0, 1);
+}
+
+// per-VRRP statistics
+
+/* Number of times a VRRP instance has transitioned to master */
+vlib_simple_counter_main_t vrrp_stats[] = {
+ {
+ .name = "MASTER_TRANS",
+ .stat_segment_name = "/net/vrrp/master-trans",
+ },
+ /* Number of VRRP advertisements sent by a VRRP instance */
+ {
+ .name = "ADV_SENT",
+ .stat_segment_name = "/net/vrrp/adv-sent",
+ },
+ /* Number of VRRP advertisements received by a VRRP instance */
+ {
+ .name = "ADV_RCVD",
+ .stat_segment_name = "/net/vrrp/adv-rcvd",
+ },
+ /* Number of VRRP priority-0 packets sent by a VRRP instance */
+ {
+ .name = "PRIO0_SENT",
+ .stat_segment_name = "/net/vrrp/prio0-sent",
+ },
+ /* Number of VRRP priority-0 packets received by a VRRP instance */
+ {
+ .name = "PRIO0_RCVD",
+ .stat_segment_name = "/net/vrrp/prio0-rcvd",
+ },
+};
+
+void
+vrrp_incr_stat_counter (vrrp_stat_counter_t stat_type, u32 stat_index)
+{
+ if (stat_type >= VRRP_STAT_COUNTER_MAX)
+ {
+ clib_warning ("Attempt to increse stat counter of unknown type %u",
+ stat_type);
+ return;
+ }
+ vlib_increment_simple_counter (
+ &vrrp_stats[stat_type], vlib_get_main ()->thread_index, stat_index, 1);
+}
+
typedef struct
{
vrrp_vr_key_t key;
@@ -290,6 +381,7 @@ vrrp_vr_transition (vrrp_vr_t * vr, vrrp_vr_state_t new_state, void *data)
if (new_state == VRRP_VR_STATE_MASTER)
{
+ vrrp_incr_stat_counter (VRRP_STAT_COUNTER_MASTER_TRANS, vr->stat_index);
/* RFC 5798 sec 6.4.1 (105) - startup event for VR with priority 255
* sec 6.4.2 (365) - master down timer fires on backup VR
*/
@@ -505,7 +597,7 @@ vrrp_vr_valid_addrs_owner (vrrp_vr_config_t * vr_conf)
}
static int
-vrrp_vr_valid_addrs_unused (vrrp_vr_config_t * vr_conf)
+vrrp_vr_valid_addrs_unused (vrrp_vr_config_t *vr_conf, index_t vrrp_index)
{
ip46_address_t *vr_addr;
u8 is_ipv6 = (vr_conf->flags & VRRP_VR_IPV6) != 0;
@@ -517,7 +609,7 @@ vrrp_vr_valid_addrs_unused (vrrp_vr_config_t * vr_conf)
addr = (is_ipv6) ? (void *) &vr_addr->ip6 : (void *) &vr_addr->ip4;
vr_index = vrrp_vr_lookup_address (vr_conf->sw_if_index, is_ipv6, addr);
- if (vr_index != ~0)
+ if (vr_index != ~0 && vrrp_index != vr_index)
return VNET_API_ERROR_ADDRESS_IN_USE;
}
@@ -525,7 +617,7 @@ vrrp_vr_valid_addrs_unused (vrrp_vr_config_t * vr_conf)
}
static int
-vrrp_vr_valid_addrs (vrrp_vr_config_t * vr_conf)
+vrrp_vr_valid_addrs (vrrp_vr_config_t *vr_conf, index_t vrrp_index)
{
int ret = 0;
@@ -535,7 +627,7 @@ vrrp_vr_valid_addrs (vrrp_vr_config_t * vr_conf)
return ret;
/* make sure no other VR has already configured any of the VR addresses */
- ret = vrrp_vr_valid_addrs_unused (vr_conf);
+ ret = vrrp_vr_valid_addrs_unused (vr_conf, vrrp_index);
return ret;
}
@@ -613,9 +705,149 @@ vrrp_vr_addrs_add_del (vrrp_vr_t * vr, u8 is_add, ip46_address_t * vr_addrs)
}
}
+int
+vrrp_vr_update (index_t *vrrp_index, vrrp_vr_config_t *vr_conf)
+{
+ index_t index = *vrrp_index;
+ vrrp_main_t *vrm = &vrrp_main;
+ vrrp_vr_t *vr = NULL;
+ vrrp_vr_key_t key = { 0 };
+ uint8_t must_restart = 0;
+ int ret = 0;
+
+ /* no valid index -> create and return allocated index */
+ if (index == INDEX_INVALID)
+ {
+ return vrrp_vr_add_del (1, vr_conf, vrrp_index);
+ }
+ /* update: lookup vrrp instance */
+ if (pool_is_free_index (vrm->vrs, index))
+ return (VNET_API_ERROR_NO_SUCH_ENTRY);
+
+ /* fetch existing VR */
+ vr = pool_elt_at_index (vrm->vrs, index);
+
+ /* populate key */
+ key.vr_id = vr->config.vr_id;
+ key.is_ipv6 = !!(vr->config.flags & VRRP_VR_IPV6);
+ ;
+ key.sw_if_index = vr->config.sw_if_index;
+
+ /* Do not allow changes to the keys of the VRRP instance */
+ if (vr_conf->vr_id != key.vr_id || vr_conf->sw_if_index != key.sw_if_index ||
+ !!(vr_conf->flags & VRRP_VR_IPV6) != key.is_ipv6)
+ {
+ clib_warning ("Attempt to change VR ID, IP version or interface index "
+ "for VRRP instance with index %u",
+ index);
+ return VNET_API_ERROR_INVALID_ARGUMENT;
+ }
+
+ /* were IPvX addresses included ? */
+ if (!vec_len (vr_conf->vr_addrs))
+ {
+ clib_warning ("Conf of VR %u for IPv%d on sw_if_index %u "
+ " does not contain IP addresses",
+ key.vr_id, key.is_ipv6 ? 6 : 4, key.sw_if_index);
+ return VNET_API_ERROR_INVALID_SRC_ADDRESS;
+ }
+
+ /* Make sure the addresses are ok to use */
+ if ((ret = vrrp_vr_valid_addrs (vr_conf, index)) < 0)
+ return ret;
+
+ /* stop it if needed */
+ must_restart = (vr->runtime.state != VRRP_VR_STATE_INIT);
+ if (must_restart)
+ vrrp_vr_start_stop (0, &key);
+
+ /* overwrite new config */
+ vr->config.priority = vr_conf->priority;
+ vr->config.adv_interval = vr_conf->adv_interval;
+ vr->config.flags = vr_conf->flags;
+
+ /* check if any address has changed */
+ ip46_address_t *vr_addr, *conf_addr;
+ uint8_t found;
+ vec_foreach (vr_addr, vr->config.vr_addrs)
+ {
+ found = 0;
+ vec_foreach (conf_addr, vr_conf->vr_addrs)
+ {
+ if (ip46_address_is_equal (vr_addr, conf_addr))
+ {
+ found = 1;
+ break;
+ }
+ }
+ if (!found)
+ {
+ vrrp_vr_addr_add_del (vr, 0, vr_addr);
+ }
+ }
+ vec_foreach (conf_addr, vr_conf->vr_addrs)
+ {
+ found = 0;
+ vec_foreach (vr_addr, vr->config.vr_addrs)
+ {
+ if (ip46_address_is_equal (vr_addr, conf_addr))
+ {
+ found = 1;
+ break;
+ }
+ }
+ if (!found)
+ {
+ vrrp_vr_addr_add_del (vr, 1, conf_addr);
+ }
+ }
+
+ /* restart it if needed */
+ if (must_restart)
+ vrrp_vr_start_stop (1, &key);
+
+ return 0;
+}
+
+static void
+vrrp_vr_del_common (vrrp_vr_t *vr, vrrp_vr_key_t *key)
+{
+ vrrp_main_t *vrm = &vrrp_main;
+
+ vrrp_vr_tracking_ifs_add_del (vr, vr->tracking.interfaces, 0);
+ vrrp_vr_addrs_add_del (vr, 0, vr->config.vr_addrs);
+ mhash_unset (&vrm->vr_index_by_key, key, 0);
+ vec_free (vr->config.peer_addrs);
+ vec_free (vr->config.vr_addrs);
+ vec_free (vr->tracking.interfaces);
+ pool_put (vrm->vrs, vr);
+}
+
+int
+vrrp_vr_del (index_t vrrp_index)
+{
+ vrrp_main_t *vrm = &vrrp_main;
+ vrrp_vr_key_t key;
+ vrrp_vr_t *vr = 0;
+
+ if (pool_is_free_index (vrm->vrs, vrrp_index))
+ {
+ return (VNET_API_ERROR_NO_SUCH_ENTRY);
+ }
+ else
+ {
+ vr = pool_elt_at_index (vrm->vrs, vrrp_index);
+ key.sw_if_index = vr->config.sw_if_index;
+ key.vr_id = vr->config.vr_id;
+ key.is_ipv6 = vrrp_vr_is_ipv6 (vr);
+ vrrp_vr_del_common (vr, &key);
+ return 0;
+ }
+}
+
/* Action function shared between message handler and debug CLI */
int
-vrrp_vr_add_del (u8 is_add, vrrp_vr_config_t * vr_conf)
+vrrp_vr_add_del (u8 is_add, vrrp_vr_config_t *vr_conf, index_t *ret_index)
{
vrrp_main_t *vrm = &vrrp_main;
vnet_main_t *vnm = vnet_get_main ();
@@ -657,7 +889,7 @@ vrrp_vr_add_del (u8 is_add, vrrp_vr_config_t * vr_conf)
}
/* Make sure the addresses are ok to use */
- if ((ret = vrrp_vr_valid_addrs (vr_conf)) < 0)
+ if ((ret = vrrp_vr_valid_addrs (vr_conf, INDEX_INVALID)) < 0)
return ret;
pool_get_zero (vrm->vrs, vr);
@@ -675,6 +907,20 @@ vrrp_vr_add_del (u8 is_add, vrrp_vr_config_t * vr_conf)
vr->runtime.mac = (key.is_ipv6) ? ipv6_vmac : ipv4_vmac;
vr->runtime.mac.bytes[5] = vr_conf->vr_id;
+ /* recall pool index for stats */
+ vr->stat_index = vr_index;
+ /* and return it if we were asked to */
+ if (ret_index != NULL)
+ {
+ *ret_index = vr_index;
+ }
+ /* allocate & reset stats */
+ for (int i = 0; i < VRRP_STAT_COUNTER_MAX; i++)
+ {
+ vlib_validate_simple_counter (&vrrp_stats[i], vr_index);
+ vlib_zero_simple_counter (&vrrp_stats[i], vr_index);
+ }
+
mhash_set (&vrm->vr_index_by_key, &key, vr_index, 0);
}
else
@@ -688,14 +934,7 @@ vrrp_vr_add_del (u8 is_add, vrrp_vr_config_t * vr_conf)
vr_index = p[0];
vr = pool_elt_at_index (vrm->vrs, vr_index);
-
- vrrp_vr_tracking_ifs_add_del (vr, vr->tracking.interfaces, is_add);
- vrrp_vr_addrs_add_del (vr, is_add, vr->config.vr_addrs);
- mhash_unset (&vrm->vr_index_by_key, &key, 0);
- vec_free (vr->config.peer_addrs);
- vec_free (vr->config.vr_addrs);
- vec_free (vr->tracking.interfaces);
- pool_put (vrm->vrs, vr);
+ vrrp_vr_del_common (vr, &key);
}
vrrp_intf_vr_add_del (is_add, vr_conf->sw_if_index, vr_index, key.is_ipv6);
@@ -1263,6 +1502,13 @@ vrrp_init (vlib_main_t * vm)
vrrp_ip6_delegate_id = ip6_link_delegate_register (&vrrp_ip6_delegate_vft);
+ /* allocate & reset error counters */
+ for (int i = 0; i < VRRP_ERR_COUNTER_MAX; i++)
+ {
+ vlib_validate_simple_counter (&vrrp_errs[i], 0);
+ vlib_zero_simple_counter (&vrrp_errs[i], 0);
+ }
+
return error;
}
diff --git a/src/plugins/vrrp/vrrp.h b/src/plugins/vrrp/vrrp.h
index c9325921959..cf529a153a4 100644
--- a/src/plugins/vrrp/vrrp.h
+++ b/src/plugins/vrrp/vrrp.h
@@ -108,6 +108,7 @@ typedef struct vrrp_vr
vrrp_vr_config_t config;
vrrp_vr_runtime_t runtime;
vrrp_vr_tracking_t tracking;
+ u32 stat_index;
} vrrp_vr_t;
/* Timers */
@@ -185,9 +186,46 @@ extern vlib_node_registration_t vrrp_periodic_node;
#define VRRP_EVENT_VR_STOP 2
#define VRRP_EVENT_PERIODIC_ENABLE_DISABLE 3
+/* global error counter types */
+#define foreach_vrrp_err_counter \
+ _ (CHKSUM, 0) \
+ _ (VERSION, 1) \
+ _ (VRID, 2) \
+ _ (TTL, 3) \
+ _ (ADDR_LIST, 4) \
+ _ (PKT_LEN, 5)
+
+typedef enum vrrp_err_counter_
+{
+#define _(sym, val) VRRP_ERR_COUNTER_##sym = val,
+ foreach_vrrp_err_counter
+#undef _
+} vrrp_err_counter_t;
+
+#define VRRP_ERR_COUNTER_MAX 6
+
+/* per-instance stats */
+#define foreach_vrrp_stat_counter \
+ _ (MASTER_TRANS, 0) \
+ _ (ADV_SENT, 1) \
+ _ (ADV_RCVD, 2) \
+ _ (PRIO0_SENT, 3) \
+ _ (PRIO0_RCVD, 4)
+
+typedef enum vrrp_stat_counter_
+{
+#define _(sym, val) VRRP_STAT_COUNTER_##sym = val,
+ foreach_vrrp_stat_counter
+#undef _
+} vrrp_stat_counter_t;
+
+#define VRRP_STAT_COUNTER_MAX 5
+
clib_error_t *vrrp_plugin_api_hookup (vlib_main_t * vm);
-int vrrp_vr_add_del (u8 is_add, vrrp_vr_config_t * conf);
+int vrrp_vr_add_del (u8 is_add, vrrp_vr_config_t *conf, index_t *ret_index);
+int vrrp_vr_update (index_t *vrrp_index, vrrp_vr_config_t *vr_conf);
+int vrrp_vr_del (index_t vrrp_index);
int vrrp_vr_start_stop (u8 is_start, vrrp_vr_key_t * vr_key);
extern u8 *format_vrrp_vr (u8 * s, va_list * args);
extern u8 *format_vrrp_vr_key (u8 * s, va_list * args);
@@ -209,6 +247,9 @@ int vrrp_vr_tracking_ifs_add_del (vrrp_vr_t * vr,
u8 is_add);
void vrrp_vr_event (vrrp_vr_t * vr, vrrp_vr_state_t new_state);
+// stats
+void vrrp_incr_err_counter (vrrp_err_counter_t err_type);
+void vrrp_incr_stat_counter (vrrp_stat_counter_t stat_type, u32 stat_index);
always_inline void
vrrp_vr_skew_compute (vrrp_vr_t * vr)
diff --git a/src/plugins/vrrp/vrrp_api.c b/src/plugins/vrrp/vrrp_api.c
index 9a206fa6cdc..5eb0ffc6f20 100644
--- a/src/plugins/vrrp/vrrp_api.c
+++ b/src/plugins/vrrp/vrrp_api.c
@@ -25,6 +25,109 @@
/* API message handlers */
static void
+vl_api_vrrp_vr_update_t_handler (vl_api_vrrp_vr_update_t *mp)
+{
+ vl_api_vrrp_vr_update_reply_t *rmp;
+ vrrp_vr_config_t vr_conf;
+ u32 api_flags;
+ u32 vrrp_index = INDEX_INVALID;
+ 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;
+
+ 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
+ {
+ vrrp_index = ntohl (mp->vrrp_index);
+ rv = vrrp_vr_update (&vrrp_index, &vr_conf);
+ }
+
+ vec_free (addrs);
+
+ BAD_SW_IF_INDEX_LABEL;
+ // clang-format off
+ REPLY_MACRO2 (VL_API_VRRP_VR_UPDATE_REPLY,
+ ({
+ rmp->vrrp_index = htonl (vrrp_index);
+ }));
+ // clang-format on
+}
+
+static void
+vl_api_vrrp_vr_del_t_handler (vl_api_vrrp_vr_del_t *mp)
+{
+ vl_api_vrrp_vr_del_reply_t *rmp;
+ int rv;
+
+ rv = vrrp_vr_del (ntohl (mp->vrrp_index));
+
+ REPLY_MACRO (VL_API_VRRP_VR_DEL_REPLY);
+}
+
+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;
@@ -103,7 +206,7 @@ vl_api_vrrp_vr_add_del_t_handler (vl_api_vrrp_vr_add_del_t * mp)
rv = VNET_API_ERROR_INVALID_VALUE;
}
else
- rv = vrrp_vr_add_del (mp->is_add, &vr_conf);
+ rv = vrrp_vr_add_del (mp->is_add, &vr_conf, NULL);
vec_free (addrs);
diff --git a/src/plugins/vrrp/vrrp_cli.c b/src/plugins/vrrp/vrrp_cli.c
index a154a11a8fa..437b896839c 100644
--- a/src/plugins/vrrp/vrrp_cli.c
+++ b/src/plugins/vrrp/vrrp_cli.c
@@ -102,7 +102,7 @@ vrrp_vr_add_del_command_fn (vlib_main_t * vm,
vr_conf.adv_interval = (u16) interval;
vr_conf.vr_addrs = addrs;
- rv = vrrp_vr_add_del (is_add, &vr_conf);
+ rv = vrrp_vr_add_del (is_add, &vr_conf, NULL);
switch (rv)
{
diff --git a/src/plugins/vrrp/vrrp_packet.c b/src/plugins/vrrp/vrrp_packet.c
index 89a6ede605e..0ae73aa9d0a 100644
--- a/src/plugins/vrrp/vrrp_packet.c
+++ b/src/plugins/vrrp/vrrp_packet.c
@@ -354,6 +354,12 @@ vrrp_adv_send (vrrp_vr_t * vr, int shutdown)
vlib_put_frame_to_node (vm, node_index, to_frame);
+ vrrp_incr_stat_counter (VRRP_STAT_COUNTER_ADV_SENT, vr->stat_index);
+ if (shutdown)
+ {
+ vrrp_incr_stat_counter (VRRP_STAT_COUNTER_PRIO0_SENT, vr->stat_index);
+ }
+
vec_free (bi);
return 0;
diff --git a/src/plugins/vrrp/vrrp_test.c b/src/plugins/vrrp/vrrp_test.c
index 194e6adfc42..d2f79f65c3f 100644
--- a/src/plugins/vrrp/vrrp_test.c
+++ b/src/plugins/vrrp/vrrp_test.c
@@ -35,6 +35,176 @@ vrrp_test_main_t vrrp_test_main;
#include <vlibapi/vat_helper_macros.h>
static int
+api_vrrp_vr_update (vat_main_t *vam)
+{
+ unformat_input_t *i = vam->input;
+ u32 sw_if_index = ~0;
+ u32 vr_id, priority, interval, vrrp_index;
+ u8 is_ipv6, no_preempt, accept_mode, vr_unicast;
+ u8 n_addrs4, n_addrs6;
+ vl_api_vrrp_vr_update_t *mp;
+ vl_api_address_t *api_addr;
+ ip46_address_t *ip_addr, *ip_addrs = 0;
+ ip46_address_t addr;
+ int ret = 0;
+
+ interval = priority = 100;
+ n_addrs4 = n_addrs6 = 0;
+ vr_id = is_ipv6 = no_preempt = accept_mode = vr_unicast = 0;
+ vrrp_index = INDEX_INVALID;
+
+ clib_memset (&addr, 0, sizeof (addr));
+
+ /* Parse args required to build the message */
+ while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index))
+ ;
+ else if (unformat (i, "sw_if_index %u", &sw_if_index))
+ ;
+ else if (unformat (i, "vr_id %u", &vr_id))
+ ;
+ else if (unformat (i, "vrrp_index %u", &vrrp_index))
+ ;
+ else if (unformat (i, "ipv6"))
+ is_ipv6 = 1;
+ else if (unformat (i, "priority %u", &priority))
+ ;
+ else if (unformat (i, "interval %u", &interval))
+ ;
+ else if (unformat (i, "no_preempt"))
+ no_preempt = 1;
+ else if (unformat (i, "accept_mode"))
+ accept_mode = 1;
+ else if (unformat (i, "unicast"))
+ vr_unicast = 1;
+ else if (unformat (i, "%U", unformat_ip4_address, &addr.ip4))
+ {
+ vec_add1 (ip_addrs, addr);
+ n_addrs4++;
+ clib_memset (&addr, 0, sizeof (addr));
+ }
+ else if (unformat (i, "%U", unformat_ip6_address, &addr.ip6))
+ {
+ vec_add1 (ip_addrs, addr);
+ n_addrs6++;
+ clib_memset (&addr, 0, sizeof (addr));
+ }
+ else
+ break;
+ }
+
+ if (sw_if_index == ~0)
+ {
+ errmsg ("Interface not set\n");
+ ret = -99;
+ }
+ else if (n_addrs4 && (n_addrs6 || is_ipv6))
+ {
+ errmsg ("Address family mismatch\n");
+ ret = -99;
+ }
+
+ if (ret)
+ goto done;
+
+ /* Construct the API message */
+ M2 (VRRP_VR_UPDATE, mp, vec_len (ip_addrs) * sizeof (*api_addr));
+
+ mp->vrrp_index = htonl (vrrp_index);
+ mp->sw_if_index = ntohl (sw_if_index);
+ mp->vr_id = vr_id;
+ mp->priority = priority;
+ mp->interval = htons (interval);
+ mp->flags = VRRP_API_VR_PREEMPT; /* preempt by default */
+
+ if (no_preempt)
+ mp->flags &= ~VRRP_API_VR_PREEMPT;
+
+ if (accept_mode)
+ mp->flags |= VRRP_API_VR_ACCEPT;
+
+ if (vr_unicast)
+ mp->flags |= VRRP_API_VR_UNICAST;
+
+ if (is_ipv6)
+ mp->flags |= VRRP_API_VR_IPV6;
+
+ mp->flags = htonl (mp->flags);
+
+ mp->n_addrs = n_addrs4 + n_addrs6;
+ api_addr = mp->addrs;
+
+ vec_foreach (ip_addr, ip_addrs)
+ {
+ void *src, *dst;
+ int len;
+
+ if (is_ipv6)
+ {
+ api_addr->af = ADDRESS_IP6;
+ src = &ip_addr->ip6;
+ dst = &api_addr->un.ip6;
+ len = sizeof (api_addr->un.ip6);
+ }
+ else
+ {
+ api_addr->af = ADDRESS_IP4;
+ src = &ip_addr->ip4;
+ dst = &api_addr->un.ip4;
+ len = sizeof (api_addr->un.ip4);
+ }
+ clib_memcpy (dst, src, len);
+ api_addr++;
+ }
+
+ /* send it... */
+ S (mp);
+
+ /* Wait for a reply... */
+ W (ret);
+
+done:
+ vec_free (ip_addrs);
+
+ return ret;
+}
+
+static void
+vl_api_vrrp_vr_update_reply_t_handler (vl_api_vrrp_vr_update_reply_t *mp)
+{
+}
+
+static int
+api_vrrp_vr_del (vat_main_t *vam)
+{
+ unformat_input_t *i = vam->input;
+ vl_api_vrrp_vr_del_t *mp;
+ u32 vrrp_index = INDEX_INVALID;
+ int ret;
+
+ while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (i, "vrrp_index %u", &vrrp_index))
+ ;
+ else
+ break;
+ }
+
+ /* Construct the API message */
+ M (VRRP_VR_DEL, mp);
+ mp->vrrp_index = htonl (vrrp_index);
+
+ /* send it... */
+ S (mp);
+
+ /* Wait for a reply... */
+ W (ret);
+
+ return ret;
+}
+
+static int
api_vrrp_vr_add_del (vat_main_t * vam)
{
unformat_input_t *i = vam->input;