2 #include <vnet/adj/adj_midchain.h>
3 #include <vnet/udp/udp.h>
5 #include <wireguard/wireguard_messages.h>
6 #include <wireguard/wireguard_if.h>
7 #include <wireguard/wireguard.h>
9 /* pool of interfaces */
12 /* bitmap of Allocated WG_ITF instances */
13 static uword *wg_if_instances;
15 /* vector of interfaces key'd on their sw_if_index */
16 static index_t *wg_if_index_by_sw_if_index;
18 /* vector of interfaces key'd on their UDP port (in network order) */
19 index_t *wg_if_index_by_port;
22 format_wg_if_name (u8 * s, va_list * args)
24 u32 dev_instance = va_arg (*args, u32);
25 return format (s, "wg%d", dev_instance);
29 format_wg_if (u8 * s, va_list * args)
31 index_t wgii = va_arg (*args, u32);
32 wg_if_t *wgi = wg_if_get (wgii);
33 u8 key[NOISE_KEY_LEN_BASE64];
35 key_to_base64 (wgi->local.l_private, NOISE_PUBLIC_KEY_LEN, key);
37 s = format (s, "[%d] %U src:%U port:%d",
39 format_vnet_sw_if_index_name, vnet_get_main (),
40 wgi->sw_if_index, format_ip_address, &wgi->src_ip, wgi->port);
42 key_to_base64 (wgi->local.l_private, NOISE_PUBLIC_KEY_LEN, key);
44 s = format (s, " private-key:%s", key);
46 key_to_base64 (wgi->local.l_public, NOISE_PUBLIC_KEY_LEN, key);
48 s = format (s, " public-key:%s", key);
54 wg_if_find_by_sw_if_index (u32 sw_if_index)
56 if (vec_len (wg_if_index_by_sw_if_index) <= sw_if_index)
58 u32 ti = wg_if_index_by_sw_if_index[sw_if_index];
65 static noise_remote_t *
66 wg_remote_get (uint8_t public[NOISE_PUBLIC_KEY_LEN])
68 wg_main_t *wmp = &wg_main;
69 wg_peer_t *peer = NULL;
72 pool_foreach (peer_iter, wmp->peers,
74 if (!memcmp (peer_iter->remote.r_public, public, NOISE_PUBLIC_KEY_LEN))
81 return peer ? &peer->remote : NULL;
85 wg_index_set (noise_remote_t * remote)
87 wg_main_t *wmp = &wg_main;
88 u32 rnd_seed = (u32) (vlib_time_now (wmp->vlib_main) * 1e6);
90 wg_index_table_add (&wmp->index_table, remote->r_peer_idx, rnd_seed);
95 wg_index_drop (uint32_t key)
97 wg_main_t *wmp = &wg_main;
98 wg_index_table_del (&wmp->index_table, key);
101 static clib_error_t *
102 wg_if_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
104 vnet_hw_interface_t *hi;
108 hi = vnet_get_hw_interface (vnm, hw_if_index);
109 hw_flags = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP ?
110 VNET_HW_INTERFACE_FLAG_LINK_UP : 0);
111 vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
113 wgii = wg_if_find_by_sw_if_index (hi->sw_if_index);
115 wg_if_peer_walk (wg_if_get (wgii), wg_peer_if_admin_state_change, NULL);
121 wg_if_update_adj (vnet_main_t * vnm, u32 sw_if_index, adj_index_t ai)
123 /* The peers manage the adjacencies */
128 VNET_DEVICE_CLASS (wg_if_device_class) = {
129 .name = "Wireguard Tunnel",
130 .format_device_name = format_wg_if_name,
131 .admin_up_down_function = wg_if_admin_up_down,
134 VNET_HW_INTERFACE_CLASS(wg_hw_interface_class) = {
136 .update_adjacency = wg_if_update_adj,
137 .flags = VNET_HW_INTERFACE_CLASS_FLAG_NBMA,
142 * Maintain a bitmap of allocated wg_if instance numbers.
144 #define WG_ITF_MAX_INSTANCE (16 * 1024)
147 wg_if_instance_alloc (u32 want)
150 * Check for dynamically allocated instance number.
156 bit = clib_bitmap_first_clear (wg_if_instances);
157 if (bit >= WG_ITF_MAX_INSTANCE)
161 wg_if_instances = clib_bitmap_set (wg_if_instances, bit, 1);
168 if (want >= WG_ITF_MAX_INSTANCE)
176 if (clib_bitmap_get (wg_if_instances, want))
182 * Grant allocation request.
184 wg_if_instances = clib_bitmap_set (wg_if_instances, want, 1);
190 wg_if_instance_free (u32 instance)
192 if (instance >= WG_ITF_MAX_INSTANCE)
197 if (clib_bitmap_get (wg_if_instances, instance) == 0)
202 wg_if_instances = clib_bitmap_set (wg_if_instances, instance, 0);
208 wg_if_create (u32 user_instance,
209 const u8 private_key[NOISE_PUBLIC_KEY_LEN],
210 u16 port, const ip_address_t * src_ip, u32 * sw_if_indexp)
212 vnet_main_t *vnm = vnet_get_main ();
213 u32 instance, hw_if_index;
214 vnet_hw_interface_t *hi;
217 ASSERT (sw_if_indexp);
219 *sw_if_indexp = (u32) ~ 0;
222 * Allocate a wg_if instance. Either select on dynamically
223 * or try to use the desired user_instance number.
225 instance = wg_if_instance_alloc (user_instance);
227 return VNET_API_ERROR_INVALID_REGISTRATION;
229 pool_get (wg_if_pool, wg_if);
231 /* tunnel index (or instance) */
232 u32 t_idx = wg_if - wg_if_pool;
234 wg_if->user_instance = instance;
235 if (~0 == wg_if->user_instance)
236 wg_if->user_instance = t_idx;
238 udp_dst_port_info_t *pi = udp_get_dst_port_info (&udp_main, port, UDP_IP4);
240 return (VNET_API_ERROR_VALUE_EXIST);
241 udp_register_dst_port (vlib_get_main (), port, wg_input_node.index, 1);
243 vec_validate_init_empty (wg_if_index_by_port, port, INDEX_INVALID);
244 wg_if_index_by_port[port] = wg_if - wg_if_pool;
247 struct noise_upcall upcall;
248 upcall.u_remote_get = wg_remote_get;
249 upcall.u_index_set = wg_index_set;
250 upcall.u_index_drop = wg_index_drop;
252 noise_local_init (&wg_if->local, &upcall);
253 noise_local_set_private (&wg_if->local, private_key);
254 cookie_checker_update (&wg_if->cookie_checker, wg_if->local.l_public);
256 hw_if_index = vnet_register_interface (vnm,
257 wg_if_device_class.index,
259 wg_hw_interface_class.index, t_idx);
261 hi = vnet_get_hw_interface (vnm, hw_if_index);
263 vec_validate_init_empty (wg_if_index_by_sw_if_index, hi->sw_if_index,
265 wg_if_index_by_sw_if_index[hi->sw_if_index] = t_idx;
267 ip_address_copy (&wg_if->src_ip, src_ip);
268 wg_if->sw_if_index = *sw_if_indexp = hi->sw_if_index;
274 wg_if_delete (u32 sw_if_index)
276 vnet_main_t *vnm = vnet_get_main ();
278 if (pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index))
279 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
281 vnet_hw_interface_t *hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
282 if (hw == 0 || hw->dev_class_index != wg_if_device_class.index)
283 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
286 wg_if = wg_if_get (wg_if_find_by_sw_if_index (sw_if_index));
288 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
290 if (wg_if_instance_free (hw->dev_instance) < 0)
291 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
293 wg_if_index_by_port[wg_if->port] = INDEX_INVALID;
294 vnet_delete_hw_interface (vnm, hw->hw_if_index);
295 pool_put (wg_if_pool, wg_if);
301 wg_if_peer_add (wg_if_t * wgi, index_t peeri)
303 hash_set (wgi->peers, peeri, peeri);
305 if (1 == hash_elts (wgi->peers))
306 vnet_feature_enable_disable ("ip4-output", "wg-output-tun",
307 wgi->sw_if_index, 1, 0, 0);
311 wg_if_peer_remove (wg_if_t * wgi, index_t peeri)
313 hash_unset (wgi->peers, peeri);
315 if (0 == hash_elts (wgi->peers))
316 vnet_feature_enable_disable ("ip4-output", "wg-output-tun",
317 wgi->sw_if_index, 0, 0, 0);
321 wg_if_walk (wg_if_walk_cb_t fn, void *data)
326 pool_foreach_index (wgii, wg_if_pool,
328 if (WALK_STOP == fn(wgii, data))
335 wg_if_peer_walk (wg_if_t * wgi, wg_if_peer_walk_cb_t fn, void *data)
340 hash_foreach (peeri, val, wgi->peers,
342 if (WALK_STOP == fn(wgi, peeri, data))
350 wg_if_table_bind_v4 (ip4_main_t * im,
352 u32 sw_if_index, u32 new_fib_index, u32 old_fib_index)
356 wg_if = wg_if_get (wg_if_find_by_sw_if_index (sw_if_index));
360 wg_peer_table_bind_ctx_t ctx = {
362 .old_fib_index = old_fib_index,
363 .new_fib_index = new_fib_index,
366 wg_if_peer_walk (wg_if, wg_peer_if_table_change, &ctx);
370 wg_if_table_bind_v6 (ip6_main_t * im,
372 u32 sw_if_index, u32 new_fib_index, u32 old_fib_index)
376 wg_if = wg_if_get (wg_if_find_by_sw_if_index (sw_if_index));
380 wg_peer_table_bind_ctx_t ctx = {
382 .old_fib_index = old_fib_index,
383 .new_fib_index = new_fib_index,
386 wg_if_peer_walk (wg_if, wg_peer_if_table_change, &ctx);
389 static clib_error_t *
390 wg_if_module_init (vlib_main_t * vm)
393 ip4_table_bind_callback_t cb = {
394 .function = wg_if_table_bind_v4,
396 vec_add1 (ip4_main.table_bind_callbacks, cb);
399 ip6_table_bind_callback_t cb = {
400 .function = wg_if_table_bind_v6,
402 vec_add1 (ip6_main.table_bind_callbacks, cb);
409 VLIB_INIT_FUNCTION (wg_if_module_init) =
411 .runs_after = VLIB_INITS("ip_main_init"),
417 * fd.io coding-style-patch-verification: ON
420 * eval: (c-set-style "gnu")