FD.io VPP  v20.09-64-g4f7b92f0a
Vector Packet Processing
wireguard_if.c
Go to the documentation of this file.
1 
3 #include <vnet/udp/udp.h>
4 
7 #include <wireguard/wireguard.h>
9 
10 /* pool of interfaces */
12 
13 /* bitmap of Allocated WG_ITF instances */
15 
16 /* vector of interfaces key'd on their sw_if_index */
18 
19 /* vector of interfaces key'd on their UDP port (in network order) */
21 
22 static u8 *
23 format_wg_if_name (u8 * s, va_list * args)
24 {
25  u32 dev_instance = va_arg (*args, u32);
26  return format (s, "wg%d", dev_instance);
27 }
28 
29 u8 *
30 format_wg_if (u8 * s, va_list * args)
31 {
32  index_t wgii = va_arg (*args, u32);
33  wg_if_t *wgi = wg_if_get (wgii);
34  noise_local_t *local = noise_local_get (wgi->local_idx);
36 
37 
38  s = format (s, "[%d] %U src:%U port:%d",
39  wgii,
41  wgi->sw_if_index, format_ip_address, &wgi->src_ip, wgi->port);
42 
44 
45  s = format (s, " private-key:%s", key);
46  s =
47  format (s, " %U", format_hex_bytes, local->l_private,
49 
51 
52  s = format (s, " public-key:%s", key);
53 
54  s =
55  format (s, " %U", format_hex_bytes, local->l_public,
57 
58  s = format (s, " mac-key: %U", format_hex_bytes,
60 
61  return (s);
62 }
63 
64 index_t
66 {
67  if (vec_len (wg_if_index_by_sw_if_index) <= sw_if_index)
68  return INDEX_INVALID;
70  if (ti == ~0)
71  return INDEX_INVALID;
72 
73  return (ti);
74 }
75 
76 static walk_rc_t
78 {
79  uint8_t *public = data;
80  wg_peer_t *peer = wg_peer_get (peeri);
81 
82  if (!memcmp (peer->remote.r_public, public, NOISE_PUBLIC_KEY_LEN))
83  return (WALK_STOP);
84  return (WALK_CONTINUE);
85 }
86 
87 static noise_remote_t *
88 wg_remote_get (const uint8_t public[NOISE_PUBLIC_KEY_LEN])
89 {
90  index_t peeri;
91 
92  peeri = wg_peer_walk (wg_if_find_peer_by_public_key, (void *) public);
93 
94  if (INDEX_INVALID != peeri)
95  return &wg_peer_get (peeri)->remote;
96 
97  return NULL;
98 }
99 
100 static uint32_t
102 {
103  wg_main_t *wmp = &wg_main;
104  u32 rnd_seed = (u32) (vlib_time_now (wmp->vlib_main) * 1e6);
105  u32 ret =
106  wg_index_table_add (&wmp->index_table, remote->r_peer_idx, rnd_seed);
107  return ret;
108 }
109 
110 static void
111 wg_index_drop (uint32_t key)
112 {
113  wg_main_t *wmp = &wg_main;
114  wg_index_table_del (&wmp->index_table, key);
115 }
116 
117 static clib_error_t *
119 {
121  index_t wgii;
122  u32 hw_flags;
123 
124  hi = vnet_get_hw_interface (vnm, hw_if_index);
125  hw_flags = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP ?
127  vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
128 
130 
132 
133  return (NULL);
134 }
135 
136 void
138 {
139  /* The peers manage the adjacencies */
140 }
141 
142 
143 /* *INDENT-OFF* */
144 VNET_DEVICE_CLASS (wg_if_device_class) = {
145  .name = "Wireguard Tunnel",
146  .format_device_name = format_wg_if_name,
147  .admin_up_down_function = wg_if_admin_up_down,
148 };
149 
150 VNET_HW_INTERFACE_CLASS(wg_hw_interface_class) = {
151  .name = "Wireguard",
152  .update_adjacency = wg_if_update_adj,
154 };
155 /* *INDENT-ON* */
156 
157 /*
158  * Maintain a bitmap of allocated wg_if instance numbers.
159  */
160 #define WG_ITF_MAX_INSTANCE (16 * 1024)
161 
162 static u32
164 {
165  /*
166  * Check for dynamically allocated instance number.
167  */
168  if (~0 == want)
169  {
170  u32 bit;
171 
173  if (bit >= WG_ITF_MAX_INSTANCE)
174  {
175  return ~0;
176  }
178  return bit;
179  }
180 
181  /*
182  * In range?
183  */
184  if (want >= WG_ITF_MAX_INSTANCE)
185  {
186  return ~0;
187  }
188 
189  /*
190  * Already in use?
191  */
192  if (clib_bitmap_get (wg_if_instances, want))
193  {
194  return ~0;
195  }
196 
197  /*
198  * Grant allocation request.
199  */
201 
202  return want;
203 }
204 
205 static int
207 {
208  if (instance >= WG_ITF_MAX_INSTANCE)
209  {
210  return -1;
211  }
212 
213  if (clib_bitmap_get (wg_if_instances, instance) == 0)
214  {
215  return -1;
216  }
217 
219  return 0;
220 }
221 
222 
223 int
224 wg_if_create (u32 user_instance,
226  u16 port, const ip_address_t * src_ip, u32 * sw_if_indexp)
227 {
228  vnet_main_t *vnm = vnet_get_main ();
229  u32 instance, hw_if_index;
231  wg_if_t *wg_if;
232  noise_local_t *local;
233 
234  ASSERT (sw_if_indexp);
235 
236  *sw_if_indexp = (u32) ~ 0;
237 
238  /*
239  * Allocate a wg_if instance. Either select on dynamically
240  * or try to use the desired user_instance number.
241  */
242  instance = wg_if_instance_alloc (user_instance);
243  if (instance == ~0)
244  return VNET_API_ERROR_INVALID_REGISTRATION;
245 
246  /* *INDENT-OFF* */
247  struct noise_upcall upcall = {
248  .u_remote_get = wg_remote_get,
249  .u_index_set = wg_index_set,
250  .u_index_drop = wg_index_drop,
251  };
252  /* *INDENT-ON* */
253 
254  pool_get (noise_local_pool, local);
255 
256  noise_local_init (local, &upcall);
257  if (!noise_local_set_private (local, private_key))
258  {
259  pool_put (noise_local_pool, local);
260  wg_if_instance_free (instance);
261  return VNET_API_ERROR_INVALID_REGISTRATION;
262  }
263 
264  pool_get (wg_if_pool, wg_if);
265 
266  /* tunnel index (or instance) */
267  u32 t_idx = wg_if - wg_if_pool;
268 
269  wg_if->user_instance = instance;
270  if (~0 == wg_if->user_instance)
271  wg_if->user_instance = t_idx;
272 
274 
277 
278  wg_if->port = port;
279  wg_if->local_idx = local - noise_local_pool;
281 
282  hw_if_index = vnet_register_interface (vnm,
283  wg_if_device_class.index,
284  t_idx,
285  wg_hw_interface_class.index, t_idx);
286 
287  hi = vnet_get_hw_interface (vnm, hw_if_index);
288 
290  INDEX_INVALID);
292 
293  ip_address_copy (&wg_if->src_ip, src_ip);
294  wg_if->sw_if_index = *sw_if_indexp = hi->sw_if_index;
295 
296  return 0;
297 }
298 
299 int
301 {
302  vnet_main_t *vnm = vnet_get_main ();
303 
304  if (pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index))
305  return VNET_API_ERROR_INVALID_SW_IF_INDEX;
306 
307  vnet_hw_interface_t *hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
308  if (hw == 0 || hw->dev_class_index != wg_if_device_class.index)
309  return VNET_API_ERROR_INVALID_VALUE;
310 
311  wg_if_t *wg_if;
312  wg_if = wg_if_get (wg_if_find_by_sw_if_index (sw_if_index));
313  if (NULL == wg_if)
314  return VNET_API_ERROR_INVALID_SW_IF_INDEX_2;
315 
316  if (wg_if_instance_free (wg_if->user_instance) < 0)
317  return VNET_API_ERROR_INVALID_VALUE_2;
318 
323  pool_put (wg_if_pool, wg_if);
324 
325  return 0;
326 }
327 
328 void
330 {
331  hash_set (wgi->peers, peeri, peeri);
332 
333  if (1 == hash_elts (wgi->peers))
334  vnet_feature_enable_disable ("ip4-output", "wg-output-tun",
335  wgi->sw_if_index, 1, 0, 0);
336 }
337 
338 void
340 {
341  hash_unset (wgi->peers, peeri);
342 
343  if (0 == hash_elts (wgi->peers))
344  vnet_feature_enable_disable ("ip4-output", "wg-output-tun",
345  wgi->sw_if_index, 0, 0, 0);
346 }
347 
348 void
350 {
351  index_t wgii;
352 
353  /* *INDENT-OFF* */
354  pool_foreach_index (wgii, wg_if_pool,
355  {
356  if (WALK_STOP == fn(wgii, data))
357  break;
358  });
359  /* *INDENT-ON* */
360 }
361 
362 index_t
364 {
365  index_t peeri, val;
366 
367  /* *INDENT-OFF* */
368  hash_foreach (peeri, val, wgi->peers,
369  {
370  if (WALK_STOP == fn(wgi, peeri, data))
371  return peeri;
372  });
373  /* *INDENT-ON* */
374 
375  return INDEX_INVALID;
376 }
377 
378 
379 static void
381  uword opaque,
382  u32 sw_if_index, u32 new_fib_index, u32 old_fib_index)
383 {
384  wg_if_t *wg_if;
385 
386  wg_if = wg_if_get (wg_if_find_by_sw_if_index (sw_if_index));
387  if (NULL == wg_if)
388  return;
389 
391  .af = AF_IP4,
392  .old_fib_index = old_fib_index,
393  .new_fib_index = new_fib_index,
394  };
395 
397 }
398 
399 static void
401  uword opaque,
402  u32 sw_if_index, u32 new_fib_index, u32 old_fib_index)
403 {
404  wg_if_t *wg_if;
405 
406  wg_if = wg_if_get (wg_if_find_by_sw_if_index (sw_if_index));
407  if (NULL == wg_if)
408  return;
409 
411  .af = AF_IP6,
412  .old_fib_index = old_fib_index,
413  .new_fib_index = new_fib_index,
414  };
415 
417 }
418 
419 static clib_error_t *
421 {
422  {
425  };
427  }
428  {
431  };
433  }
434 
435  return (NULL);
436 }
437 
438 /* *INDENT-OFF* */
440 {
441  .runs_after = VLIB_INITS("ip_main_init"),
442 };
443 /* *INDENT-ON* */
444 
445 
446 /*
447  * fd.io coding-style-patch-verification: ON
448  *
449  * Local Variables:
450  * eval: (c-set-style "gnu")
451  * End:
452  */
#define NOISE_KEY_LEN_BASE64
uword * peers
Definition: wireguard_if.h:39
#define hash_set(h, key, value)
Definition: hash.h:255
ip4_table_bind_function_t * function
Definition: ip4.h:93
#define hash_unset(h, key)
Definition: hash.h:261
vl_api_wireguard_peer_flags_t flags
Definition: wireguard.api:103
void noise_local_init(noise_local_t *l, struct noise_upcall *upcall)
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
static vnet_hw_interface_t * vnet_get_sup_hw_interface(vnet_main_t *vnm, u32 sw_if_index)
void wg_if_peer_add(wg_if_t *wgi, index_t peeri)
Definition: wireguard_if.c:329
vnet_interface_main_t interface_main
Definition: vnet.h:59
static_always_inline wg_if_t * wg_if_get(index_t wgii)
Definition: wireguard_if.h:67
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:333
static uword * wg_if_instances
Definition: wireguard_if.c:14
a non-broadcast multiple access interface
Definition: interface.h:390
static vnet_hw_interface_t * vnet_get_hw_interface(vnet_main_t *vnm, u32 hw_if_index)
index_t wg_peer_walk(wg_peer_walk_cb_t fn, void *data)
u32 index_t
A Data-Path Object is an object that represents actions that are applied to packets are they are swit...
Definition: dpo.h:41
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:592
wg_if_t * wg_if_pool
Data-plane exposed functions.
Definition: wireguard_if.c:11
static int wg_if_instance_free(u32 instance)
Definition: wireguard_if.c:206
static uword * clib_bitmap_set(uword *ai, uword i, uword value)
Sets the ith bit of a bitmap to new_value Removes trailing zeros from the bitmap. ...
Definition: bitmap.h:167
walk_rc_t(* wg_if_walk_cb_t)(index_t wgi, void *data)
Definition: wireguard_if.h:51
vlib_main_t * vm
Definition: in2out_ed.c:1582
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:252
uint8_t r_public[NOISE_PUBLIC_KEY_LEN]
bool key_to_base64(const u8 *src, size_t src_len, u8 *out)
format_function_t format_vnet_sw_if_index_name
unsigned char u8
Definition: types.h:56
u8 data[128]
Definition: ipsec_types.api:89
index_t wg_if_find_by_sw_if_index(u32 sw_if_index)
Definition: wireguard_if.c:65
enum walk_rc_t_ walk_rc_t
Walk return code.
static u32 wg_if_instance_alloc(u32 want)
Definition: wireguard_if.c:163
noise_remote_t remote
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:173
#define hash_foreach(key_var, value_var, h, body)
Definition: hash.h:442
u8 * format_hex_bytes(u8 *s, va_list *va)
Definition: std-formats.c:84
index_t wg_if_peer_walk(wg_if_t *wgi, wg_if_peer_walk_cb_t fn, void *data)
Definition: wireguard_if.c:363
int wg_if_delete(u32 sw_if_index)
Definition: wireguard_if.c:300
unsigned int u32
Definition: types.h:88
index_t * wg_if_index_by_port
Definition: wireguard_if.c:20
static u8 * format_wg_if_name(u8 *s, va_list *args)
Definition: wireguard_if.c:23
u32 local_idx
Definition: wireguard_if.h:29
u32 vnet_register_interface(vnet_main_t *vnm, u32 dev_class_index, u32 dev_instance, u32 hw_class_index, u32 hw_instance)
Definition: interface.c:768
static void wg_if_table_bind_v6(ip6_main_t *im, uword opaque, u32 sw_if_index, u32 new_fib_index, u32 old_fib_index)
Definition: wireguard_if.c:400
#define NOISE_PUBLIC_KEY_LEN
vlib_node_registration_t wg_input_node
(constructor) VLIB_REGISTER_NODE (wg_input_node)
u8 * format_wg_if(u8 *s, va_list *args)
Definition: wireguard_if.c:30
u8 private_key[32]
Definition: wireguard.api:34
void wg_if_peer_remove(wg_if_t *wgi, index_t peeri)
Definition: wireguard_if.c:339
long ctx[MAX_CONNS]
Definition: main.c:144
unsigned short u16
Definition: types.h:57
static noise_remote_t * wg_remote_get(const uint8_t public[NOISE_PUBLIC_KEY_LEN])
Definition: wireguard_if.c:88
void wg_index_table_del(wg_index_table_t *table, u32 key)
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:302
ip6_table_bind_callback_t * table_bind_callbacks
Functions to call when interface to table biding changes.
Definition: ip6.h:220
ip6_main_t ip6_main
Definition: ip6_forward.c:2781
bool noise_local_set_private(noise_local_t *l, const uint8_t private[NOISE_PUBLIC_KEY_LEN])
uint8_t l_public[NOISE_PUBLIC_KEY_LEN]
vl_api_address_t peer
Definition: teib.api:28
static uint32_t wg_index_set(noise_remote_t *remote)
Definition: wireguard_if.c:101
static clib_error_t * wg_if_module_init(vlib_main_t *vm)
Definition: wireguard_if.c:420
int user_instance
Definition: wireguard_if.h:24
walk_rc_t(* wg_if_peer_walk_cb_t)(wg_if_t *wgi, index_t peeri, void *data)
Definition: wireguard_if.h:54
ip_address_t src_ip
Definition: wireguard_if.h:36
void udp_unregister_dst_port(vlib_main_t *vm, udp_dst_port_t dst_port, u8 is_ip4)
Definition: udp_local.c:506
u8 * format_ip_address(u8 *s, va_list *args)
Definition: ip_types.c:21
static clib_error_t * wg_if_admin_up_down(vnet_main_t *vnm, u32 hw_if_index, u32 flags)
Definition: wireguard_if.c:118
#define pool_is_free_index(P, I)
Use free bitmap to query whether given index is free.
Definition: pool.h:299
u32 adj_index_t
An index for adjacencies.
Definition: adj_types.h:30
static uword clib_bitmap_get(uword *ai, uword i)
Gets the ith bit value from a bitmap.
Definition: bitmap.h:197
wg_index_table_t index_table
Definition: wireguard.h:38
static index_t * wg_if_index_by_sw_if_index
Definition: wireguard_if.c:17
#define pool_put_index(p, i)
Free pool element with given index.
Definition: pool.h:331
static uword hash_elts(void *v)
Definition: hash.h:118
#define ASSERT(truth)
uint32_t r_peer_idx
wg_main_t wg_main
Definition: wireguard.c:27
walk_rc_t wg_peer_if_table_change(wg_if_t *wgi, index_t peeri, void *data)
IPv4 main type.
Definition: ip4.h:106
u32 wg_index_table_add(wg_index_table_t *table, u32 peer_pool_idx, u32 rnd_seed)
VNET_HW_INTERFACE_CLASS(wg_hw_interface_class)
VNET_DEVICE_CLASS(wg_if_device_class)
void wg_if_walk(wg_if_walk_cb_t fn, void *data)
Definition: wireguard_if.c:349
void wg_if_update_adj(vnet_main_t *vnm, u32 sw_if_index, adj_index_t ai)
Definition: wireguard_if.c:137
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
vl_api_ip4_address_t hi
Definition: arp.api:37
void vnet_delete_hw_interface(vnet_main_t *vnm, u32 hw_if_index)
Definition: interface.c:984
ip4_table_bind_callback_t * table_bind_callbacks
Functions to call when interface to table biding changes.
Definition: ip4.h:147
typedef key
Definition: ipsec_types.api:85
uint8_t l_private[NOISE_PUBLIC_KEY_LEN]
static void wg_index_drop(uint32_t key)
Definition: wireguard_if.c:111
static void wg_if_table_bind_v4(ip4_main_t *im, uword opaque, u32 sw_if_index, u32 new_fib_index, u32 old_fib_index)
Definition: wireguard_if.c:380
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
walk_rc_t wg_peer_if_admin_state_change(wg_if_t *wgi, index_t peeri, void *data)
static walk_rc_t wg_if_find_peer_by_public_key(index_t peeri, void *data)
Definition: wireguard_if.c:77
u32 instance
Definition: gre.api:51
#define INDEX_INVALID
Invalid index - used when no index is known blazoned capitals INVALID speak volumes where ~0 does not...
Definition: dpo.h:47
clib_error_t * vnet_hw_interface_set_flags(vnet_main_t *vnm, u32 hw_if_index, vnet_hw_interface_flags_t flags)
Definition: interface.c:498
u64 uword
Definition: types.h:112
vnet_sw_interface_t * sw_interfaces
Definition: interface.h:872
vl_api_address_t src_ip
Definition: wireguard.api:36
vlib_main_t * vlib_main
Definition: wireguard.h:34
ip6_table_bind_function_t * function
Definition: ip6.h:116
u16 port
Definition: lb_types.api:72
#define WG_ITF_MAX_INSTANCE
Definition: wireguard_if.c:160
void ip_address_copy(ip_address_t *dst, const ip_address_t *src)
Definition: ip_types.c:130
ip4_main_t ip4_main
Global ip4 main structure.
Definition: ip4_forward.c:1144
static_always_inline noise_local_t * noise_local_get(uint32_t locali)
int wg_if_create(u32 user_instance, const u8 private_key[NOISE_PUBLIC_KEY_LEN], u16 port, const ip_address_t *src_ip, u32 *sw_if_indexp)
Definition: wireguard_if.c:224
uint8_t cc_mac1_key[COOKIE_KEY_SIZE]
void udp_register_dst_port(vlib_main_t *vm, udp_dst_port_t dst_port, u32 node_index, u8 is_ip4)
Definition: udp_local.c:468
cookie_checker_t cookie_checker
Definition: wireguard_if.h:30
#define pool_foreach_index(i, v, body)
Iterate pool by index.
Definition: pool.h:558
static uword clib_bitmap_first_clear(uword *ai)
Return the lowest numbered clear bit in a bitmap.
Definition: bitmap.h:445
#define vec_validate_init_empty(V, I, INIT)
Make sure vector is long enough for given index and initialize empty space (no header, unspecified alignment)
Definition: vec.h:556
noise_local_t * noise_local_pool
static wg_peer_t * wg_peer_get(index_t peeri)
u32 sw_if_index
Definition: wireguard_if.h:25
#define VLIB_INITS(...)
Definition: init.h:357
vl_api_interface_index_t sw_if_index
Definition: wireguard.api:33
int vnet_feature_enable_disable(const char *arc_name, const char *node_name, u32 sw_if_index, int enable_disable, void *feature_config, u32 n_feature_config_bytes)
Definition: feature.c:303