aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorArtem Glazychev <artem.glazychev@xored.com>2021-06-11 00:10:00 +0700
committerEd Warnicke <hagbard@gmail.com>2021-10-06 21:32:33 +0000
commitdd630d15d3e9d13da9ed98d3171b9ec4529e4e66 (patch)
tree83b14e2ccf510b8296919b30825af28c81c49c34 /src/plugins
parent22efac3b537a3a1f0b57d5942bdb78c3190ce858 (diff)
wireguard: add events for peer
we can receive events from peer about its state: -WIREGUARD_PEER_STATUS_DEAD -WIREGUARD_PEER_ESTABLISHED Type: improvement Change-Id: Ide83fbe2cfafa79ded5bcf3f6a884c26a7583db0 Signed-off-by: Artem Glazychev <artem.glazychev@xored.com>
Diffstat (limited to 'src/plugins')
-rwxr-xr-xsrc/plugins/wireguard/wireguard.api38
-rw-r--r--src/plugins/wireguard/wireguard_api.c128
-rw-r--r--src/plugins/wireguard/wireguard_input.c11
-rw-r--r--src/plugins/wireguard/wireguard_output_tun.c3
-rw-r--r--src/plugins/wireguard/wireguard_peer.c37
-rw-r--r--src/plugins/wireguard/wireguard_peer.h24
-rw-r--r--src/plugins/wireguard/wireguard_send.c13
-rw-r--r--src/plugins/wireguard/wireguard_timer.c2
8 files changed, 223 insertions, 33 deletions
diff --git a/src/plugins/wireguard/wireguard.api b/src/plugins/wireguard/wireguard.api
index e290fc41ffc..1473d9ca39b 100755
--- a/src/plugins/wireguard/wireguard.api
+++ b/src/plugins/wireguard/wireguard.api
@@ -83,6 +83,7 @@ define wireguard_interface_details
enum wireguard_peer_flags : u8
{
WIREGUARD_PEER_STATUS_DEAD = 0x1,
+ WIREGUARD_PEER_ESTABLISHED = 0x2,
};
/** \brief Create new peer
@@ -107,6 +108,41 @@ typedef wireguard_peer
vl_api_prefix_t allowed_ips[n_allowed_ips];
};
+service {
+ rpc want_wireguard_peer_events returns want_wireguard_peer_events_reply
+ events wireguard_peer_event;
+};
+/** \brief Register for wireguard peer events
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param sw_if_index - index of the interface to dump peer info on, ~0 if on all
+ @param peer_index - index of the peer to dump info on, ~0 if on all
+ @param enable_disable - 1 => register for events, 0 => cancel registration
+ @param pid - sender's pid
+*/
+autoreply define want_wireguard_peer_events
+{
+ u32 client_index;
+ u32 context;
+ vl_api_interface_index_t sw_if_index [default=0xFFFFFFFF];
+ u32 peer_index [default=0xFFFFFFFF];
+ u32 enable_disable;
+ u32 pid;
+};
+/** \brief Interface Event generated by want_wireguard_peer_events
+ @param client_index - opaque cookie to identify the sender
+ @param pid - client pid registered to receive notification
+ @param peer_index - index of the peer for this event
+ @param deleted - interface was deleted
+*/
+define wireguard_peer_event
+{
+ u32 client_index;
+ u32 pid;
+ u32 peer_index;
+ vl_api_wireguard_peer_flags_t flags;
+};
+
/** \brief Create new peer
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@@ -140,10 +176,12 @@ autoreply define wireguard_peer_remove
/** \brief Dump all peers
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
+ @param peer_index - peer index to be dumped. If 0xFFFFFFFF dumps all peers
*/
define wireguard_peers_dump {
u32 client_index;
u32 context;
+ u32 peer_index [default=0xFFFFFFFF];
};
/** \brief Dump peers response
diff --git a/src/plugins/wireguard/wireguard_api.c b/src/plugins/wireguard/wireguard_api.c
index 5dd4f86f910..d97ea8eb1bc 100644
--- a/src/plugins/wireguard/wireguard_api.c
+++ b/src/plugins/wireguard/wireguard_api.c
@@ -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 */
diff --git a/src/plugins/wireguard/wireguard_input.c b/src/plugins/wireguard/wireguard_input.c
index 6a0623e0a76..4f5bd4de784 100644
--- a/src/plugins/wireguard/wireguard_input.c
+++ b/src/plugins/wireguard/wireguard_input.c
@@ -236,6 +236,10 @@ wg_handshake_process (vlib_main_t *vm, wg_main_t *wmp, vlib_buffer_t *b,
vlib_node_increment_counter (vm, node_idx,
WG_INPUT_ERROR_HANDSHAKE_SEND, 1);
}
+ else
+ {
+ wg_peer_update_flags (rp->r_peer_idx, WG_PEER_ESTABLISHED, true);
+ }
break;
}
case MESSAGE_HANDSHAKE_RESPONSE:
@@ -247,7 +251,7 @@ wg_handshake_process (vlib_main_t *vm, wg_main_t *wmp, vlib_buffer_t *b,
if (PREDICT_TRUE (entry != NULL))
{
peer = wg_peer_get (*entry);
- if (peer->is_dead)
+ if (wg_peer_is_dead (peer))
return WG_INPUT_ERROR_PEER;
}
else
@@ -276,6 +280,10 @@ wg_handshake_process (vlib_main_t *vm, wg_main_t *wmp, vlib_buffer_t *b,
vlib_node_increment_counter (vm, node_idx,
WG_INPUT_ERROR_KEEPALIVE_SEND, 1);
}
+ else
+ {
+ wg_peer_update_flags (*entry, WG_PEER_ESTABLISHED, true);
+ }
}
break;
}
@@ -378,6 +386,7 @@ wg_input_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
}
else if (PREDICT_FALSE (state_cr == SC_FAILED))
{
+ wg_peer_update_flags (*peer_idx, WG_PEER_ESTABLISHED, false);
next[0] = WG_INPUT_NEXT_ERROR;
b[0]->error = node->errors[WG_INPUT_ERROR_DECRYPTION];
goto out;
diff --git a/src/plugins/wireguard/wireguard_output_tun.c b/src/plugins/wireguard/wireguard_output_tun.c
index 80ba9504f0e..ec6cb7c6cfb 100644
--- a/src/plugins/wireguard/wireguard_output_tun.c
+++ b/src/plugins/wireguard/wireguard_output_tun.c
@@ -129,7 +129,7 @@ wg_output_tun_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
wg_peer_get_by_adj_index (vnet_buffer (b[0])->ip.adj_index[VLIB_TX]);
peer = wg_peer_get (peeri);
- if (!peer || peer->is_dead)
+ if (wg_peer_is_dead (peer))
{
b[0]->error = node->errors[WG_OUTPUT_ERROR_PEER];
goto out;
@@ -201,6 +201,7 @@ wg_output_tun_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
{
//TODO: Maybe wrong
wg_send_handshake_from_mt (peeri, false);
+ wg_peer_update_flags (peeri, WG_PEER_ESTABLISHED, false);
goto out;
}
diff --git a/src/plugins/wireguard/wireguard_peer.c b/src/plugins/wireguard/wireguard_peer.c
index fb540141e08..81cc74adc91 100644
--- a/src/plugins/wireguard/wireguard_peer.c
+++ b/src/plugins/wireguard/wireguard_peer.c
@@ -46,7 +46,10 @@ wg_peer_endpoint_init (wg_peer_endpoint_t *ep, const ip46_address_t *addr,
static void
wg_peer_clear (vlib_main_t * vm, wg_peer_t * peer)
{
+ index_t perri = peer - wg_peer_pool;
wg_timers_stop (peer);
+ wg_peer_update_flags (perri, WG_PEER_ESTABLISHED, false);
+ wg_peer_update_flags (perri, WG_PEER_STATUS_DEAD, true);
for (int i = 0; i < WG_N_TIMERS; i++)
{
peer->timers[i] = ~0;
@@ -80,7 +83,6 @@ wg_peer_clear (vlib_main_t * vm, wg_peer_t * peer)
peer->new_handshake_interval_tick = 0;
peer->rehandshake_interval_tick = 0;
peer->timer_need_another_keepalive = false;
- peer->is_dead = true;
vec_free (peer->allowed_ips);
vec_free (peer->adj_indices);
}
@@ -88,6 +90,8 @@ wg_peer_clear (vlib_main_t * vm, wg_peer_t * peer)
static void
wg_peer_init (vlib_main_t * vm, wg_peer_t * peer)
{
+ peer->api_client_by_client_index = hash_create (0, sizeof (u32));
+ peer->api_clients = NULL;
wg_peer_clear (vm, peer);
}
@@ -302,6 +306,7 @@ wg_peer_fill (vlib_main_t *vm, wg_peer_t *peer, u32 table_id,
u16 persistent_keepalive_interval,
const fib_prefix_t *allowed_ips, u32 wg_sw_if_index)
{
+ index_t perri = peer - wg_peer_pool;
wg_peer_endpoint_init (&peer->dst, dst, port);
peer->table_id = table_id;
@@ -309,7 +314,7 @@ wg_peer_fill (vlib_main_t *vm, wg_peer_t *peer, u32 table_id,
peer->timer_wheel = &wg_main.timer_wheel;
peer->persistent_keepalive_interval = persistent_keepalive_interval;
peer->last_sent_handshake = vlib_time_now (vm) - (REKEY_TIMEOUT + 1);
- peer->is_dead = false;
+ wg_peer_update_flags (perri, WG_PEER_STATUS_DEAD, false);
const wg_if_t *wgi = wg_if_get (wg_if_find_by_sw_if_index (wg_sw_if_index));
@@ -329,7 +334,6 @@ wg_peer_fill (vlib_main_t *vm, wg_peer_t *peer, u32 table_id,
peer->allowed_ips[ii] = allowed_ips[ii];
}
- index_t perri = peer - wg_peer_pool;
fib_protocol_t proto;
FOR_EACH_FIB_IP_PROTOCOL (proto)
{
@@ -338,6 +342,19 @@ wg_peer_fill (vlib_main_t *vm, wg_peer_t *peer, u32 table_id,
return (0);
}
+void
+wg_peer_update_flags (index_t peeri, wg_peer_flags flag, bool add_del)
+{
+ wg_peer_t *peer = wg_peer_get (peeri);
+ if ((add_del && (peer->flags & flag)) || (!add_del && !(peer->flags & flag)))
+ {
+ return;
+ }
+
+ peer->flags ^= flag;
+ wg_api_peer_event (peeri, peer->flags);
+}
+
int
wg_peer_add (u32 tun_sw_if_index, const u8 public_key[NOISE_PUBLIC_KEY_LEN],
u32 table_id, const ip46_address_t *endpoint,
@@ -388,6 +405,7 @@ wg_peer_add (u32 tun_sw_if_index, const u8 public_key[NOISE_PUBLIC_KEY_LEN],
wg_if->local_idx);
cookie_maker_init (&peer->cookie_maker, public_key);
+ wg_send_handshake (vm, peer, false);
if (peer->persistent_keepalive_interval != 0)
{
wg_send_keepalive (vm, peer);
@@ -459,14 +477,17 @@ format_wg_peer (u8 * s, va_list * va)
peer = wg_peer_get (peeri);
key_to_base64 (peer->remote.r_public, NOISE_PUBLIC_KEY_LEN, key);
- s = format (s, "[%d] endpoint:[%U->%U] %U keep-alive:%d", peeri,
- format_wg_peer_endpoint, &peer->src, format_wg_peer_endpoint,
- &peer->dst, format_vnet_sw_if_index_name, vnet_get_main (),
- peer->wg_sw_if_index, peer->persistent_keepalive_interval);
+ s = format (
+ s,
+ "[%d] endpoint:[%U->%U] %U keep-alive:%d flags: %d, api-clients count: %d",
+ peeri, format_wg_peer_endpoint, &peer->src, format_wg_peer_endpoint,
+ &peer->dst, format_vnet_sw_if_index_name, vnet_get_main (),
+ peer->wg_sw_if_index, peer->persistent_keepalive_interval, peer->flags,
+ pool_elts (peer->api_clients));
s = format (s, "\n adj:");
vec_foreach (adj_index, peer->adj_indices)
{
- s = format (s, " %d", adj_index);
+ s = format (s, " %d", *adj_index);
}
s = format (s, "\n key:%=s %U", key, format_hex_bytes,
peer->remote.r_public, NOISE_PUBLIC_KEY_LEN);
diff --git a/src/plugins/wireguard/wireguard_peer.h b/src/plugins/wireguard/wireguard_peer.h
index c719ac19511..a08fff73d68 100644
--- a/src/plugins/wireguard/wireguard_peer.h
+++ b/src/plugins/wireguard/wireguard_peer.h
@@ -17,6 +17,8 @@
#ifndef __included_wg_peer_h__
#define __included_wg_peer_h__
+#include <vlibapi/api_helper_macros.h>
+
#include <vnet/ip/ip.h>
#include <wireguard/wireguard_cookie.h>
@@ -46,6 +48,12 @@ typedef struct wg_peer_endpoint_t_
u16 port;
} wg_peer_endpoint_t;
+typedef enum
+{
+ WG_PEER_STATUS_DEAD = 0x1,
+ WG_PEER_ESTABLISHED = 0x2,
+} wg_peer_flags;
+
typedef struct wg_peer
{
noise_remote_t remote;
@@ -69,6 +77,11 @@ typedef struct wg_peer
/* The WG interface this peer is attached to */
u32 wg_sw_if_index;
+ /* API client registered for events */
+ vpe_client_registration_t *api_clients;
+ uword *api_client_by_client_index;
+ wg_peer_flags flags;
+
/* Timers */
tw_timer_wheel_16t_2w_512sl_t *timer_wheel;
u32 timers[WG_N_TIMERS];
@@ -88,8 +101,6 @@ typedef struct wg_peer
u32 rehandshake_interval_tick;
bool timer_need_another_keepalive;
-
- bool is_dead;
} wg_peer_t;
typedef struct wg_peer_table_bind_ctx_t_
@@ -117,6 +128,15 @@ walk_rc_t wg_peer_if_delete (index_t peeri, void *data);
walk_rc_t wg_peer_if_adj_change (index_t peeri, void *data);
adj_walk_rc_t wg_peer_adj_walk (adj_index_t ai, void *data);
+void wg_api_peer_event (index_t peeri, wg_peer_flags flags);
+void wg_peer_update_flags (index_t peeri, wg_peer_flags flag, bool add_del);
+
+static inline bool
+wg_peer_is_dead (wg_peer_t *peer)
+{
+ return peer && peer->flags & WG_PEER_STATUS_DEAD;
+}
+
/*
* Expoed for the data-plane
*/
diff --git a/src/plugins/wireguard/wireguard_send.c b/src/plugins/wireguard/wireguard_send.c
index 4451e000776..a5f81774a19 100644
--- a/src/plugins/wireguard/wireguard_send.c
+++ b/src/plugins/wireguard/wireguard_send.c
@@ -106,8 +106,8 @@ wg_send_handshake (vlib_main_t * vm, wg_peer_t * peer, bool is_retry)
if (!is_retry)
peer->timer_handshake_attempts = 0;
- if (!wg_birthdate_has_expired (peer->last_sent_handshake,
- REKEY_TIMEOUT) || peer->is_dead)
+ if (!wg_birthdate_has_expired (peer->last_sent_handshake, REKEY_TIMEOUT) ||
+ wg_peer_is_dead (peer))
return true;
if (noise_create_initiation (vm,
@@ -199,6 +199,7 @@ wg_send_keepalive (vlib_main_t * vm, wg_peer_t * peer)
}
else if (PREDICT_FALSE (state == SC_FAILED))
{
+ wg_peer_update_flags (peer - wg_peer_pool, WG_PEER_ESTABLISHED, false);
ret = false;
goto out;
}
@@ -252,13 +253,11 @@ wg_send_handshake_response (vlib_main_t * vm, wg_peer_t * peer)
return false;
ip46_enqueue_packet (vm, bi0, is_ip4);
+ return true;
}
- else
- return false;
+ return false;
}
- else
- return false;
- return true;
+ return false;
}
/*
diff --git a/src/plugins/wireguard/wireguard_timer.c b/src/plugins/wireguard/wireguard_timer.c
index b245b853fb5..97c861b459c 100644
--- a/src/plugins/wireguard/wireguard_timer.c
+++ b/src/plugins/wireguard/wireguard_timer.c
@@ -191,7 +191,7 @@ wg_expired_zero_key_material (vlib_main_t * vm, wg_peer_t * peer)
return;
}
- if (!peer->is_dead)
+ if (!wg_peer_is_dead (peer))
{
noise_remote_clear (vm, &peer->remote);
}