vrrp: asynchronous events on VR state change 15/29315/3
authorMatthew Smith <mgsmith@netgate.com>
Thu, 8 Oct 2020 16:11:27 +0000 (11:11 -0500)
committerDamjan Marion <dmarion@me.com>
Sat, 24 Oct 2020 09:28:56 +0000 (09:28 +0000)
Type: feature

Add API message for an API client to subscribe/unsubscribe to receive
an event when a VRRP VR changes state. Add code to build and send the
events.

Change-Id: Ie92cadd4850d4352c1aaa79c4b0a7daa0f3b04e7
Signed-off-by: Matthew Smith <mgsmith@netgate.com>
src/plugins/vrrp/vrrp.api
src/plugins/vrrp/vrrp.c
src/plugins/vrrp/vrrp.h
src/plugins/vrrp/vrrp_api.c
src/plugins/vrrp/vrrp_test.c
src/vlibapi/api_helper_macros.h

index da485ad..a34b06f 100644 (file)
@@ -242,3 +242,38 @@ define vrrp_vr_track_if_details {
   u8 n_ifs;
   vl_api_vrrp_vr_track_if_t ifs[n_ifs];
 };
+
+/** \brief Notification about VRRP VR state change event
+    @param client_index - opaque cookie to identify the sender
+    @param pid - client pid registered to receive notification
+    @param vr - configuration parameters identifying the VR
+    @param old_state - old state of VR
+    @param new_state - new state of VR
+*/
+define vrrp_vr_event
+{
+  u32 client_index;
+  u32 pid;
+  vl_api_vrrp_vr_key_t vr;
+  vl_api_vrrp_vr_state_t old_state;
+  vl_api_vrrp_vr_state_t new_state;
+};
+
+service {
+  rpc want_vrrp_vr_events returns want_vrrp_vr_events_reply
+    events vrrp_vr_event;
+};
+
+/** \brief Register for VRRP VR state change events
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param enable_disable - 1 to register, 0 to cancel registration
+    @param pid - sender's pid
+*/
+autoreply define want_vrrp_vr_events
+{
+  u32 client_index;
+  u32 context;
+  bool enable_disable;
+  u32 pid;
+};
index 37ee9ec..771cd70 100644 (file)
@@ -351,6 +351,8 @@ vrrp_vr_transition (vrrp_vr_t * vr, vrrp_vr_state_t new_state, void *data)
   /* add/delete virtual MAC address on NIC if necessary */
   vrrp_vr_transition_vmac (vr, new_state);
 
+  vrrp_vr_event (vr, new_state);
+
   vr->runtime.state = new_state;
 }
 
index 0eda5d6..c932592 100644 (file)
@@ -207,6 +207,7 @@ int vrrp_vr_tracking_if_add_del (vrrp_vr_t * vr, u32 sw_if_index,
 int vrrp_vr_tracking_ifs_add_del (vrrp_vr_t * vr,
                                  vrrp_vr_tracking_if_t * track_ifs,
                                  u8 is_add);
+void vrrp_vr_event (vrrp_vr_t * vr, vrrp_vr_state_t new_state);
 
 
 always_inline void
index 500569e..27ca56a 100644 (file)
 #include <vrrp/vrrp.api_enum.h>
 #include <vrrp/vrrp.api_types.h>
 
-#define REPLY_MSG_ID_BASE vmp->msg_id_base
+#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)
 {
-  vrrp_main_t *vmp = &vrrp_main;
   vl_api_vrrp_vr_add_del_reply_t *rmp;
   vrrp_vr_config_t vr_conf;
   u32 api_flags;
@@ -112,6 +111,19 @@ vl_api_vrrp_vr_add_del_t_handler (vl_api_vrrp_vr_add_del_t * mp)
   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)
@@ -150,23 +162,7 @@ send_vrrp_vr_details (vrrp_vr_t * vr, vl_api_registration_t * reg,
   mp->config.flags = htonl (api_flags);
 
   /* runtime */
-  switch (vr->runtime.state)
-    {
-    case VRRP_VR_STATE_INIT:
-      mp->runtime.state = htonl (VRRP_API_VR_STATE_INIT);
-      break;
-    case VRRP_VR_STATE_BACKUP:
-      mp->runtime.state = htonl (VRRP_API_VR_STATE_BACKUP);
-      break;
-    case VRRP_VR_STATE_MASTER:
-      mp->runtime.state = htonl (VRRP_API_VR_STATE_MASTER);
-      break;
-    case VRRP_VR_STATE_INTF_DOWN:
-      mp->runtime.state = htonl (VRRP_API_VR_STATE_INTF_DOWN);
-      break;
-    default:
-      break;
-    }
+  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);
@@ -234,7 +230,6 @@ vl_api_vrrp_vr_dump_t_handler (vl_api_vrrp_vr_dump_t * mp)
 static void
 vl_api_vrrp_vr_start_stop_t_handler (vl_api_vrrp_vr_start_stop_t * mp)
 {
-  vrrp_main_t *vmp = &vrrp_main;
   vl_api_vrrp_vr_start_stop_reply_t *rmp;
   vrrp_vr_key_t vr_key;
   int rv;
@@ -253,7 +248,6 @@ vl_api_vrrp_vr_start_stop_t_handler (vl_api_vrrp_vr_start_stop_t * mp)
 static void
 vl_api_vrrp_vr_set_peers_t_handler (vl_api_vrrp_vr_set_peers_t * mp)
 {
-  vrrp_main_t *vmp = &vrrp_main;
   vl_api_vrrp_vr_set_peers_reply_t *rmp;
   vrrp_vr_key_t vr_key;
   ip46_address_t *peer_addrs = 0;
@@ -385,7 +379,6 @@ static void
   vl_api_vrrp_vr_track_if_add_del_t_handler
   (vl_api_vrrp_vr_track_if_add_del_t * mp)
 {
-  vrrp_main_t *vmp = &vrrp_main;
   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;
@@ -486,6 +479,49 @@ vl_api_vrrp_vr_track_if_dump_t_handler (vl_api_vrrp_vr_track_if_dump_t * mp)
   /* *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 *
index eaa0c40..199f541 100644 (file)
@@ -690,6 +690,38 @@ vl_api_vrrp_vr_peer_details_t_handler (vl_api_vrrp_vr_peer_details_t * mp)
   fformat (vam->ofp, "\n");
 }
 
+static int
+api_want_vrrp_vr_events (vat_main_t * vam)
+{
+  unformat_input_t *i = vam->input;
+  vl_api_want_vrrp_vr_events_t *mp;
+  int enable = -1;
+  int ret;
+
+  while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (i, "enable"))
+       enable = 1;
+      else if (unformat (i, "disable"))
+       enable = 0;
+      else
+       break;
+    }
+
+  if (enable == -1)
+    {
+      errmsg ("missing enable|disable");
+      return -99;
+    }
+
+  M (WANT_VRRP_VR_EVENTS, mp);
+  mp->enable_disable = enable;
+  S (mp);
+  W (ret);
+
+  return ret;
+}
+
 #include <vrrp/vrrp.api_test.c>
 /*
  * fd.io coding-style-patch-verification: ON
index 983b688..8064d67 100644 (file)
@@ -390,7 +390,8 @@ _(bfd_events)                                   \
 _(l2_arp_term_events)                           \
 _(ip6_ra_events)                                \
 _(dhcp6_pd_reply_events)                        \
-_(dhcp6_reply_events)
+_(dhcp6_reply_events)                          \
+_(vrrp_vr_events)
 
 typedef struct
 {