wireguard: add events for peer
[vpp.git] / src / plugins / wireguard / wireguard_api.c
index 5dd4f86..d97ea8e 100644 (file)
@@ -27,9 +27,9 @@
 #include <wireguard/wireguard_key.h>
 #include <wireguard/wireguard.h>
 #include <wireguard/wireguard_if.h>
-#include <wireguard/wireguard_peer.h>
 
 #define REPLY_MSG_ID_BASE wmp->msg_id_base
+#include <wireguard/wireguard_peer.h>
 #include <vlibapi/api_helper_macros.h>
 
 static void
@@ -55,12 +55,10 @@ static void
   rv = wg_if_create (ntohl (mp->interface.user_instance), private_key,
                     ntohs (mp->interface.port), &src, &sw_if_index);
 
-  /* *INDENT-OFF* */
   REPLY_MACRO2(VL_API_WIREGUARD_INTERFACE_CREATE_REPLY,
   {
     rmp->sw_if_index = htonl(sw_if_index);
   });
-  /* *INDENT-ON* */
 }
 
 static void
@@ -79,9 +77,7 @@ static void
 
   BAD_SW_IF_INDEX_LABEL;
 
-  /* *INDENT-OFF* */
   REPLY_MACRO(VL_API_WIREGUARD_INTERFACE_DELETE_REPLY);
-  /* *INDENT-ON* */
 }
 
 typedef struct wg_deatils_walk_t_
@@ -179,12 +175,11 @@ vl_api_wireguard_peer_add_t_handler (vl_api_wireguard_peer_add_t * mp)
   vec_free (allowed_ips);
 done:
   BAD_SW_IF_INDEX_LABEL;
-  /* *INDENT-OFF* */
+
   REPLY_MACRO2(VL_API_WIREGUARD_PEER_ADD_REPLY,
   {
     rmp->peer_index = ntohl (peeri);
   });
-  /* *INDENT-ON* */
 }
 
 static void
@@ -198,13 +193,11 @@ vl_api_wireguard_peer_remove_t_handler (vl_api_wireguard_peer_remove_t * mp)
 
   rv = wg_peer_remove (ntohl (mp->peer_index));
 
-  /* *INDENT-OFF* */
   REPLY_MACRO(VL_API_WIREGUARD_PEER_REMOVE_REPLY);
-  /* *INDENT-ON* */
 }
 
 static walk_rc_t
-send_wg_peers_details (index_t peeri, void *data)
+wg_api_send_peers_details (index_t peeri, void *data)
 {
   vl_api_wireguard_peers_details_t *rmp;
   wg_deatils_walk_t *ctx = data;
@@ -212,7 +205,11 @@ send_wg_peers_details (index_t peeri, void *data)
   u8 n_allowed_ips;
   size_t ss;
 
+  if (pool_is_free_index (wg_peer_pool, peeri))
+    return (WALK_CONTINUE);
+
   peer = wg_peer_get (peeri);
+
   n_allowed_ips = vec_len (peer->allowed_ips);
 
   ss = (sizeof (*rmp) + (n_allowed_ips * sizeof (rmp->peer.allowed_ips[0])));
@@ -222,8 +219,7 @@ send_wg_peers_details (index_t peeri, void *data)
   rmp->_vl_msg_id = htons (VL_API_WIREGUARD_PEERS_DETAILS +
                           wg_main.msg_id_base);
 
-  if (peer->is_dead)
-    rmp->peer.flags = WIREGUARD_PEER_STATUS_DEAD;
+  rmp->peer.flags = peer->flags;
   clib_memcpy (rmp->peer.public_key,
               peer->remote.r_public, NOISE_PUBLIC_KEY_LEN);
 
@@ -260,7 +256,113 @@ vl_api_wireguard_peers_dump_t_handler (vl_api_wireguard_peers_dump_t * mp)
     .context = mp->context,
   };
 
-  wg_peer_walk (send_wg_peers_details, &ctx);
+  if (mp->peer_index == ~0)
+    wg_peer_walk (wg_api_send_peers_details, &ctx);
+  else
+    wg_api_send_peers_details (mp->peer_index, &ctx);
+}
+
+static vpe_client_registration_t *
+wg_api_client_lookup (wg_peer_t *peer, u32 client_index)
+{
+  uword *p;
+  vpe_client_registration_t *api_client = NULL;
+
+  p = hash_get (peer->api_client_by_client_index, client_index);
+  if (p)
+    api_client = vec_elt_at_index (peer->api_clients, p[0]);
+
+  return api_client;
+}
+
+static walk_rc_t
+wg_api_update_peer_api_client (index_t peeri, void *data)
+{
+  if (pool_is_free_index (wg_peer_pool, peeri))
+    return (WALK_CONTINUE);
+
+  vl_api_want_wireguard_peer_events_t *mp = data;
+  wg_peer_t *peer = wg_peer_get (peeri);
+
+  if (ntohl (mp->sw_if_index) != ~0 &&
+      ntohl (mp->sw_if_index) != peer->wg_sw_if_index)
+    {
+      return (WALK_CONTINUE);
+    }
+
+  vpe_client_registration_t *api_client;
+
+  api_client = wg_api_client_lookup (peer, mp->client_index);
+
+  if (api_client)
+    {
+      if (mp->enable_disable)
+       {
+         return (WALK_CONTINUE);
+       }
+      hash_unset (peer->api_client_by_client_index, api_client->client_index);
+      pool_put (peer->api_clients, api_client);
+    }
+  if (mp->enable_disable)
+    {
+      pool_get (peer->api_clients, api_client);
+      clib_memset (api_client, 0, sizeof (vpe_client_registration_t));
+      api_client->client_index = mp->client_index;
+      api_client->client_pid = mp->pid;
+      hash_set (peer->api_client_by_client_index, mp->client_index,
+               api_client - peer->api_clients);
+    }
+
+  return (WALK_CONTINUE);
+}
+
+static void
+vl_api_want_wireguard_peer_events_t_handler (
+  vl_api_want_wireguard_peer_events_t *mp)
+{
+  wg_main_t *wmp = &wg_main;
+  vl_api_want_wireguard_peer_events_reply_t *rmp;
+  int rv = 0;
+
+  wg_feature_init (wmp);
+
+  if (mp->peer_index == ~0)
+    wg_peer_walk (wg_api_update_peer_api_client, mp);
+  else
+    wg_api_update_peer_api_client (ntohl (mp->peer_index), mp);
+
+  REPLY_MACRO (VL_API_WANT_WIREGUARD_PEER_EVENTS_REPLY);
+}
+
+void
+wg_api_send_peer_event (vl_api_registration_t *rp, index_t peer_index,
+                       wg_peer_flags flags)
+{
+  vl_api_wireguard_peer_event_t *mp = vl_msg_api_alloc (sizeof (*mp));
+  clib_memset (mp, 0, sizeof (*mp));
+
+  mp->_vl_msg_id = htons (VL_API_WIREGUARD_PEER_EVENT + wg_main.msg_id_base);
+  mp->peer_index = htonl (peer_index);
+  mp->flags = flags;
+
+  vl_api_send_msg (rp, (u8 *) mp);
+}
+
+void
+wg_api_peer_event (index_t peeri, wg_peer_flags flags)
+{
+  wg_peer_t *peer = wg_peer_get (peeri);
+  vpe_client_registration_t *api_client;
+  vl_api_registration_t *rp;
+
+  pool_foreach (api_client, peer->api_clients)
+    {
+      rp = vl_api_client_index_to_registration (api_client->client_index);
+      if (rp)
+       {
+         wg_api_send_peer_event (rp, peeri, flags);
+       }
+    };
 }
 
 /* set tup the API message handling tables */