hs-test: temp skip some tests
[vpp.git] / src / plugins / wireguard / wireguard_api.c
1 /*
2  * Copyright (c) 2020 Cisco and/or its affiliates.
3  * Copyright (c) 2020 Doc.ai and/or its affiliates.
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <vnet/vnet.h>
18 #include <vlibmemory/api.h>
19
20 #include <vnet/format_fns.h>
21 #include <vnet/ip/ip_types_api.h>
22 #include <vlibapi/api.h>
23
24 #include <wireguard/wireguard.api_enum.h>
25 #include <wireguard/wireguard.api_types.h>
26
27 #include <wireguard/wireguard_key.h>
28 #include <wireguard/wireguard.h>
29 #include <wireguard/wireguard_if.h>
30
31 #define REPLY_MSG_ID_BASE wmp->msg_id_base
32 #include <wireguard/wireguard_peer.h>
33 #include <vlibapi/api_helper_macros.h>
34
35 static void
36   vl_api_wireguard_interface_create_t_handler
37   (vl_api_wireguard_interface_create_t * mp)
38 {
39   vl_api_wireguard_interface_create_reply_t *rmp;
40   wg_main_t *wmp = &wg_main;
41   u8 private_key[NOISE_PUBLIC_KEY_LEN];
42   ip_address_t src;
43   u32 sw_if_index = ~0;
44   int rv = 0;
45
46   wg_feature_init (wmp);
47
48   ip_address_decode2 (&mp->interface.src_ip, &src);
49
50   if (mp->generate_key)
51     curve25519_gen_secret (private_key);
52   else
53     clib_memcpy (private_key, mp->interface.private_key, NOISE_PUBLIC_KEY_LEN);
54
55   rv = wg_if_create (ntohl (mp->interface.user_instance), private_key,
56                      ntohs (mp->interface.port), &src, &sw_if_index);
57
58   REPLY_MACRO2(VL_API_WIREGUARD_INTERFACE_CREATE_REPLY,
59   {
60     rmp->sw_if_index = htonl(sw_if_index);
61   });
62 }
63
64 static void
65   vl_api_wireguard_interface_delete_t_handler
66   (vl_api_wireguard_interface_delete_t * mp)
67 {
68   vl_api_wireguard_interface_delete_reply_t *rmp;
69   wg_main_t *wmp = &wg_main;
70   int rv = 0;
71
72   wg_feature_init (wmp);
73
74   VALIDATE_SW_IF_INDEX (mp);
75
76   rv = wg_if_delete (ntohl (mp->sw_if_index));
77
78   BAD_SW_IF_INDEX_LABEL;
79
80   REPLY_MACRO(VL_API_WIREGUARD_INTERFACE_DELETE_REPLY);
81 }
82
83 typedef struct wg_deatils_walk_t_
84 {
85   vl_api_registration_t *reg;
86   u32 context;
87   u8 show_private_key;
88 } wg_deatils_walk_t;
89
90 static walk_rc_t
91 wireguard_if_send_details (index_t wgii, void *data)
92 {
93   vl_api_wireguard_interface_details_t *rmp;
94   wg_deatils_walk_t *ctx = data;
95   const wg_if_t *wgi;
96   const noise_local_t *local;
97
98   wgi = wg_if_get (wgii);
99   local = noise_local_get (wgi->local_idx);
100
101   rmp = vl_msg_api_alloc_zero (sizeof (*rmp));
102   rmp->_vl_msg_id = htons (VL_API_WIREGUARD_INTERFACE_DETAILS +
103                            wg_main.msg_id_base);
104
105   if (ctx->show_private_key)
106     clib_memcpy (rmp->interface.private_key,
107                  local->l_private, NOISE_PUBLIC_KEY_LEN);
108   clib_memcpy (rmp->interface.public_key,
109                local->l_public, NOISE_PUBLIC_KEY_LEN);
110   rmp->interface.sw_if_index = htonl (wgi->sw_if_index);
111   rmp->interface.port = htons (wgi->port);
112   rmp->interface.user_instance = htonl (wgi->user_instance);
113   ip_address_encode2 (&wgi->src_ip, &rmp->interface.src_ip);
114
115   rmp->context = ctx->context;
116
117   vl_api_send_msg (ctx->reg, (u8 *) rmp);
118
119   return (WALK_CONTINUE);
120 }
121
122 static void
123 vl_api_wireguard_interface_dump_t_handler (vl_api_wireguard_interface_dump_t *
124                                            mp)
125 {
126   vl_api_registration_t *reg;
127   wg_main_t *wmp = &wg_main;
128
129   wg_feature_init (wmp);
130
131   reg = vl_api_client_index_to_registration (mp->client_index);
132   if (reg == 0)
133     return;
134
135   wg_deatils_walk_t ctx = {
136     .reg = reg,
137     .context = mp->context,
138     .show_private_key = mp->show_private_key,
139   };
140
141   u32 sw_if_index = ntohl (mp->sw_if_index);
142   if (sw_if_index == ~0)
143     wg_if_walk (wireguard_if_send_details, &ctx);
144   else
145     {
146       index_t wgii = wg_if_find_by_sw_if_index (sw_if_index);
147       if (wgii != INDEX_INVALID)
148         wireguard_if_send_details (wgii, &ctx);
149     }
150 }
151
152 static void
153 vl_api_wireguard_peer_add_t_handler (vl_api_wireguard_peer_add_t * mp)
154 {
155   vl_api_wireguard_peer_add_reply_t *rmp;
156   wg_main_t *wmp = &wg_main;
157   index_t peeri = INDEX_INVALID;
158   int ii, rv = 0;
159
160   ip_address_t endpoint;
161   fib_prefix_t *allowed_ips = NULL;
162
163   VALIDATE_SW_IF_INDEX (&(mp->peer));
164
165   if (0 == mp->peer.n_allowed_ips)
166     {
167       rv = VNET_API_ERROR_INVALID_VALUE;
168       goto done;
169     }
170
171   wg_feature_init (wmp);
172
173   vec_validate (allowed_ips, mp->peer.n_allowed_ips - 1);
174   ip_address_decode2 (&mp->peer.endpoint, &endpoint);
175
176   for (ii = 0; ii < mp->peer.n_allowed_ips; ii++)
177     ip_prefix_decode (&mp->peer.allowed_ips[ii], &allowed_ips[ii]);
178
179   rv = wg_peer_add (ntohl (mp->peer.sw_if_index), mp->peer.public_key,
180                     ntohl (mp->peer.table_id), &ip_addr_46 (&endpoint),
181                     allowed_ips, ntohs (mp->peer.port),
182                     ntohs (mp->peer.persistent_keepalive), &peeri);
183
184   vec_free (allowed_ips);
185 done:
186   BAD_SW_IF_INDEX_LABEL;
187
188   REPLY_MACRO2(VL_API_WIREGUARD_PEER_ADD_REPLY,
189   {
190     rmp->peer_index = ntohl (peeri);
191   });
192 }
193
194 static void
195 vl_api_wireguard_peer_remove_t_handler (vl_api_wireguard_peer_remove_t * mp)
196 {
197   vl_api_wireguard_peer_remove_reply_t *rmp;
198   wg_main_t *wmp = &wg_main;
199   int rv = 0;
200
201   wg_feature_init (wmp);
202
203   rv = wg_peer_remove (ntohl (mp->peer_index));
204
205   REPLY_MACRO(VL_API_WIREGUARD_PEER_REMOVE_REPLY);
206 }
207
208 static walk_rc_t
209 wg_api_send_peers_details (index_t peeri, void *data)
210 {
211   vl_api_wireguard_peers_details_t *rmp;
212   wg_deatils_walk_t *ctx = data;
213   const wg_peer_t *peer;
214   u8 n_allowed_ips;
215   size_t ss;
216
217   if (pool_is_free_index (wg_peer_pool, peeri))
218     return (WALK_CONTINUE);
219
220   peer = wg_peer_get (peeri);
221
222   n_allowed_ips = vec_len (peer->allowed_ips);
223
224   ss = (sizeof (*rmp) + (n_allowed_ips * sizeof (rmp->peer.allowed_ips[0])));
225
226   rmp = vl_msg_api_alloc_zero (ss);
227
228   rmp->_vl_msg_id = htons (VL_API_WIREGUARD_PEERS_DETAILS +
229                            wg_main.msg_id_base);
230
231   rmp->peer.peer_index = htonl (peeri);
232   rmp->peer.flags = peer->flags;
233   clib_memcpy (rmp->peer.public_key,
234                peer->remote.r_public, NOISE_PUBLIC_KEY_LEN);
235
236   ip_address_encode (&peer->dst.addr, IP46_TYPE_ANY, &rmp->peer.endpoint);
237   rmp->peer.port = htons (peer->dst.port);
238   rmp->peer.n_allowed_ips = n_allowed_ips;
239   rmp->peer.sw_if_index = htonl (peer->wg_sw_if_index);
240   rmp->peer.persistent_keepalive = htons (peer->persistent_keepalive_interval);
241   rmp->peer.table_id = htonl (peer->table_id);
242
243   int ii;
244   for (ii = 0; ii < n_allowed_ips; ii++)
245     ip_prefix_encode (&peer->allowed_ips[ii], &rmp->peer.allowed_ips[ii]);
246
247   rmp->context = ctx->context;
248
249   vl_api_send_msg (ctx->reg, (u8 *) rmp);
250
251   return (WALK_CONTINUE);
252 }
253
254 static void
255 vl_api_wireguard_peers_dump_t_handler (vl_api_wireguard_peers_dump_t * mp)
256 {
257   vl_api_registration_t *reg;
258   wg_main_t *wmp = &wg_main;
259
260   wg_feature_init (wmp);
261
262   reg = vl_api_client_index_to_registration (mp->client_index);
263   if (reg == NULL)
264     return;
265
266   wg_deatils_walk_t ctx = {
267     .reg = reg,
268     .context = mp->context,
269   };
270
271   if (mp->peer_index == ~0)
272     wg_peer_walk (wg_api_send_peers_details, &ctx);
273   else
274     wg_api_send_peers_details (ntohl (mp->peer_index), &ctx);
275 }
276
277 static vpe_client_registration_t *
278 wg_api_client_lookup (wg_peer_t *peer, u32 client_index)
279 {
280   uword *p;
281   vpe_client_registration_t *api_client = NULL;
282
283   p = hash_get (peer->api_client_by_client_index, client_index);
284   if (p)
285     api_client = vec_elt_at_index (peer->api_clients, p[0]);
286
287   return api_client;
288 }
289
290 static walk_rc_t
291 wg_api_update_peer_api_client (index_t peeri, void *data)
292 {
293   if (pool_is_free_index (wg_peer_pool, peeri))
294     return (WALK_CONTINUE);
295
296   vl_api_want_wireguard_peer_events_t *mp = data;
297   wg_peer_t *peer = wg_peer_get (peeri);
298
299   if (ntohl (mp->sw_if_index) != ~0 &&
300       ntohl (mp->sw_if_index) != peer->wg_sw_if_index)
301     {
302       return (WALK_CONTINUE);
303     }
304
305   vpe_client_registration_t *api_client;
306
307   api_client = wg_api_client_lookup (peer, mp->client_index);
308
309   if (api_client)
310     {
311       if (mp->enable_disable)
312         {
313           return (WALK_CONTINUE);
314         }
315       hash_unset (peer->api_client_by_client_index, api_client->client_index);
316       pool_put (peer->api_clients, api_client);
317     }
318   if (mp->enable_disable)
319     {
320       pool_get (peer->api_clients, api_client);
321       clib_memset (api_client, 0, sizeof (vpe_client_registration_t));
322       api_client->client_index = mp->client_index;
323       api_client->client_pid = mp->pid;
324       hash_set (peer->api_client_by_client_index, mp->client_index,
325                 api_client - peer->api_clients);
326     }
327
328   return (WALK_CONTINUE);
329 }
330
331 static void
332 vl_api_want_wireguard_peer_events_t_handler (
333   vl_api_want_wireguard_peer_events_t *mp)
334 {
335   wg_main_t *wmp = &wg_main;
336   vl_api_want_wireguard_peer_events_reply_t *rmp;
337   int rv = 0;
338
339   wg_feature_init (wmp);
340
341   if (mp->peer_index == ~0)
342     wg_peer_walk (wg_api_update_peer_api_client, mp);
343   else
344     wg_api_update_peer_api_client (ntohl (mp->peer_index), mp);
345
346   REPLY_MACRO (VL_API_WANT_WIREGUARD_PEER_EVENTS_REPLY);
347 }
348
349 static void
350 wg_api_send_peer_event (vl_api_registration_t *rp, index_t peer_index,
351                         wg_peer_flags flags)
352 {
353   vl_api_wireguard_peer_event_t *mp = vl_msg_api_alloc (sizeof (*mp));
354   clib_memset (mp, 0, sizeof (*mp));
355
356   mp->_vl_msg_id = htons (VL_API_WIREGUARD_PEER_EVENT + wg_main.msg_id_base);
357   mp->peer_index = htonl (peer_index);
358   mp->flags = flags;
359
360   vl_api_send_msg (rp, (u8 *) mp);
361 }
362
363 typedef struct
364 {
365   index_t peeri;
366   wg_peer_flags flags;
367 } wg_api_peer_event_args_t;
368
369 static void
370 wg_api_peer_event_cb (wg_api_peer_event_args_t *args)
371 {
372   wg_peer_t *peer = wg_peer_get (args->peeri);
373   vpe_client_registration_t *api_client;
374   vl_api_registration_t *rp;
375
376   pool_foreach (api_client, peer->api_clients)
377     {
378       rp = vl_api_client_index_to_registration (api_client->client_index);
379       if (rp)
380         {
381           wg_api_send_peer_event (rp, args->peeri, args->flags);
382         }
383     };
384 }
385
386 void
387 wg_api_peer_event (index_t peeri, wg_peer_flags flags)
388 {
389   wg_api_peer_event_args_t args = {
390     .peeri = peeri,
391     .flags = flags,
392   };
393
394   vl_api_rpc_call_main_thread (wg_api_peer_event_cb, (u8 *) &args,
395                                sizeof (args));
396 }
397
398 static void
399 vl_api_wg_set_async_mode_t_handler (vl_api_wg_set_async_mode_t *mp)
400 {
401   wg_main_t *wmp = &wg_main;
402   vl_api_wg_set_async_mode_reply_t *rmp;
403   int rv = 0;
404
405   wg_set_async_mode (mp->async_enable);
406
407   REPLY_MACRO (VL_API_WG_SET_ASYNC_MODE_REPLY);
408 }
409
410 /* set tup the API message handling tables */
411 #include <wireguard/wireguard.api.c>
412 static clib_error_t *
413 wg_api_hookup (vlib_main_t * vm)
414 {
415   wg_main_t *wmp = &wg_main;
416   wmp->msg_id_base = setup_message_id_table ();
417   return 0;
418 }
419
420 VLIB_API_INIT_FUNCTION (wg_api_hookup);
421
422 /*
423  * fd.io coding-style-patch-verification: ON
424  *
425  * Local Variables:
426  * eval: (c-set-style "gnu")
427  * End:
428  */