From de3caf37c64431c199fe649256b268010ce6a4f3 Mon Sep 17 00:00:00 2001 From: Artem Glazychev Date: Thu, 20 May 2021 12:33:52 +0700 Subject: wireguard: move adjacency processing from wireguard_peer to wireguard_interface now we should add routes manually Type: improvement Change-Id: I877511a18854efdfad02939267d38a216b2ccec3 Signed-off-by: Artem Glazychev --- src/plugins/wireguard/README.md | 7 +- src/plugins/wireguard/wireguard_api.c | 3 +- src/plugins/wireguard/wireguard_if.c | 78 +----------- src/plugins/wireguard/wireguard_if.h | 3 +- src/plugins/wireguard/wireguard_input.c | 23 +--- src/plugins/wireguard/wireguard_peer.c | 210 +++++++++++++------------------- src/plugins/wireguard/wireguard_peer.h | 32 +++-- 7 files changed, 123 insertions(+), 233 deletions(-) mode change 100755 => 100644 src/plugins/wireguard/wireguard_api.c (limited to 'src') diff --git a/src/plugins/wireguard/README.md b/src/plugins/wireguard/README.md index df69d93789f..0b624b8104c 100755 --- a/src/plugins/wireguard/README.md +++ b/src/plugins/wireguard/README.md @@ -28,10 +28,15 @@ OpenSSL: ### Add a peer configuration: ``` -> vpp# wireguard peer add public-key endpoint allowed-ip dst-port persistent-keepalive [keepalive_interval] +> vpp# wireguard peer add public-key endpoint allowed-ip port persistent-keepalive [keepalive_interval] > vpp# *peer_idx* ``` +### Add routes for allowed-ip: +``` +> ip route add via +``` + ### Show config ``` > vpp# show wireguard interface diff --git a/src/plugins/wireguard/wireguard_api.c b/src/plugins/wireguard/wireguard_api.c old mode 100755 new mode 100644 index 36cc2509463..3f17f658869 --- a/src/plugins/wireguard/wireguard_api.c +++ b/src/plugins/wireguard/wireguard_api.c @@ -249,8 +249,7 @@ send_wg_peers_details (index_t peeri, void *data) int ii; for (ii = 0; ii < n_allowed_ips; ii++) - ip_prefix_encode (&peer->allowed_ips[ii].prefix, - &rmp->peer.allowed_ips[ii]); + ip_prefix_encode (&peer->allowed_ips[ii], &rmp->peer.allowed_ips[ii]); rmp->context = ctx->context; diff --git a/src/plugins/wireguard/wireguard_if.c b/src/plugins/wireguard/wireguard_if.c index f7eb5a1d9e0..b1c5cb20638 100644 --- a/src/plugins/wireguard/wireguard_if.c +++ b/src/plugins/wireguard/wireguard_if.c @@ -151,7 +151,10 @@ wg_if_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags) void wg_if_update_adj (vnet_main_t * vnm, u32 sw_if_index, adj_index_t ai) { - /* The peers manage the adjacencies */ + index_t wgii; + + wgii = wg_if_find_by_sw_if_index (sw_if_index); + wg_if_peer_walk (wg_if_get (wgii), wg_peer_if_adj_change, &ai); } @@ -387,9 +390,8 @@ wg_if_peer_walk (wg_if_t * wgi, wg_if_peer_walk_cb_t fn, void *data) index_t peeri, val; /* *INDENT-OFF* */ - hash_foreach (peeri, val, wgi->peers, - { - if (WALK_STOP == fn(wgi, peeri, data)) + hash_foreach (peeri, val, wgi->peers, { + if (WALK_STOP == fn (peeri, data)) return peeri; }); /* *INDENT-ON* */ @@ -397,74 +399,6 @@ wg_if_peer_walk (wg_if_t * wgi, wg_if_peer_walk_cb_t fn, void *data) return INDEX_INVALID; } - -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) -{ - wg_if_t *wg_if; - - wg_if = wg_if_get (wg_if_find_by_sw_if_index (sw_if_index)); - if (NULL == wg_if) - return; - - wg_peer_table_bind_ctx_t ctx = { - .af = AF_IP4, - .old_fib_index = old_fib_index, - .new_fib_index = new_fib_index, - }; - - wg_if_peer_walk (wg_if, wg_peer_if_table_change, &ctx); -} - -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) -{ - wg_if_t *wg_if; - - wg_if = wg_if_get (wg_if_find_by_sw_if_index (sw_if_index)); - if (NULL == wg_if) - return; - - wg_peer_table_bind_ctx_t ctx = { - .af = AF_IP6, - .old_fib_index = old_fib_index, - .new_fib_index = new_fib_index, - }; - - wg_if_peer_walk (wg_if, wg_peer_if_table_change, &ctx); -} - -static clib_error_t * -wg_if_module_init (vlib_main_t * vm) -{ - { - ip4_table_bind_callback_t cb = { - .function = wg_if_table_bind_v4, - }; - vec_add1 (ip4_main.table_bind_callbacks, cb); - } - { - ip6_table_bind_callback_t cb = { - .function = wg_if_table_bind_v6, - }; - vec_add1 (ip6_main.table_bind_callbacks, cb); - } - - return (NULL); -} - -/* *INDENT-OFF* */ -VLIB_INIT_FUNCTION (wg_if_module_init) = -{ - .runs_after = VLIB_INITS("ip_main_init"), -}; -/* *INDENT-ON* */ - - /* * fd.io coding-style-patch-verification: ON * diff --git a/src/plugins/wireguard/wireguard_if.h b/src/plugins/wireguard/wireguard_if.h index 7c11ad9b281..e43557b56fe 100644 --- a/src/plugins/wireguard/wireguard_if.h +++ b/src/plugins/wireguard/wireguard_if.h @@ -52,8 +52,7 @@ u8 *format_wg_if (u8 * s, va_list * va); typedef walk_rc_t (*wg_if_walk_cb_t) (index_t wgi, void *data); void wg_if_walk (wg_if_walk_cb_t fn, void *data); -typedef walk_rc_t (*wg_if_peer_walk_cb_t) (wg_if_t * wgi, index_t peeri, - void *data); +typedef walk_rc_t (*wg_if_peer_walk_cb_t) (index_t peeri, void *data); index_t wg_if_peer_walk (wg_if_t * wgi, wg_if_peer_walk_cb_t fn, void *data); void wg_if_peer_add (wg_if_t * wgi, index_t peeri); diff --git a/src/plugins/wireguard/wireguard_input.c b/src/plugins/wireguard/wireguard_input.c index 5db814292f8..8dfba7615ef 100644 --- a/src/plugins/wireguard/wireguard_input.c +++ b/src/plugins/wireguard/wireguard_input.c @@ -254,24 +254,6 @@ wg_handshake_process (vlib_main_t * vm, wg_main_t * wmp, vlib_buffer_t * b) return WG_INPUT_ERROR_NONE; } -static_always_inline bool -fib_prefix_is_cover_addr_4 (const fib_prefix_t * p1, - const ip4_address_t * ip4) -{ - switch (p1->fp_proto) - { - case FIB_PROTOCOL_IP4: - return (ip4_destination_matches_route (&ip4_main, - &p1->fp_addr.ip4, - ip4, p1->fp_len) != 0); - case FIB_PROTOCOL_IP6: - return (false); - case FIB_PROTOCOL_MPLS: - break; - } - return (false); -} - VLIB_NODE_FN (wg_input_node) (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) @@ -386,7 +368,7 @@ VLIB_NODE_FN (wg_input_node) (vlib_main_t * vm, ip4_header_t *iph = vlib_buffer_get_current (b[0]); - const wg_peer_allowed_ip_t *allowed_ip; + const fib_prefix_t *allowed_ip; bool allowed = false; /* @@ -396,8 +378,7 @@ VLIB_NODE_FN (wg_input_node) (vlib_main_t * vm, */ vec_foreach (allowed_ip, peer->allowed_ips) { - if (fib_prefix_is_cover_addr_4 (&allowed_ip->prefix, - &iph->src_address)) + if (fib_prefix_is_cover_addr_4 (allowed_ip, &iph->src_address)) { allowed = true; break; diff --git a/src/plugins/wireguard/wireguard_peer.c b/src/plugins/wireguard/wireguard_peer.c index 0c93a25f4d7..5e2011b401e 100644 --- a/src/plugins/wireguard/wireguard_peer.c +++ b/src/plugins/wireguard/wireguard_peer.c @@ -23,7 +23,6 @@ #include #include -static fib_source_t wg_fib_source; wg_peer_t *wg_peer_pool; index_t *wg_peer_by_adj_index; @@ -36,44 +35,13 @@ wg_peer_endpoint_reset (wg_peer_endpoint_t * ep) } static void -wg_peer_endpoint_init (wg_peer_endpoint_t * ep, - const ip46_address_t * addr, u16 port) +wg_peer_endpoint_init (wg_peer_endpoint_t *ep, const ip46_address_t *addr, + u16 port) { ip46_address_copy (&ep->addr, addr); ep->port = port; } -static void -wg_peer_fib_flush (wg_peer_t * peer) -{ - wg_peer_allowed_ip_t *allowed_ip; - - vec_foreach (allowed_ip, peer->allowed_ips) - { - fib_table_entry_delete_index (allowed_ip->fib_entry_index, wg_fib_source); - allowed_ip->fib_entry_index = FIB_NODE_INDEX_INVALID; - } -} - -static void -wg_peer_fib_populate (wg_peer_t * peer, u32 fib_index) -{ - wg_peer_allowed_ip_t *allowed_ip; - - vec_foreach (allowed_ip, peer->allowed_ips) - { - allowed_ip->fib_entry_index = - fib_table_entry_path_add (fib_index, - &allowed_ip->prefix, - wg_fib_source, - FIB_ENTRY_FLAG_NONE, - fib_proto_to_dpo (allowed_ip-> - prefix.fp_proto), - &peer->dst.addr, peer->wg_sw_if_index, ~0, 1, - NULL, FIB_ROUTE_PATH_FLAG_NONE); - } -} - static void wg_peer_clear (vlib_main_t * vm, wg_peer_t * peer) { @@ -91,16 +59,16 @@ wg_peer_clear (vlib_main_t * vm, wg_peer_t * peer) wg_peer_endpoint_reset (&peer->src); wg_peer_endpoint_reset (&peer->dst); - if (INDEX_INVALID != peer->adj_index) + adj_index_t *adj_index; + vec_foreach (adj_index, peer->adj_indices) { - adj_unlock (peer->adj_index); - wg_peer_by_adj_index[peer->adj_index] = INDEX_INVALID; + if (INDEX_INVALID != *adj_index) + { + wg_peer_by_adj_index[*adj_index] = INDEX_INVALID; + } } - wg_peer_fib_flush (peer); - peer->input_thread_index = ~0; peer->output_thread_index = ~0; - peer->adj_index = INDEX_INVALID; peer->timer_wheel = 0; peer->persistent_keepalive_interval = 0; peer->timer_handshake_attempts = 0; @@ -113,12 +81,12 @@ wg_peer_clear (vlib_main_t * vm, wg_peer_t * peer) peer->timer_need_another_keepalive = false; peer->is_dead = true; vec_free (peer->allowed_ips); + vec_free (peer->adj_indices); } static void wg_peer_init (vlib_main_t * vm, wg_peer_t * peer) { - peer->adj_index = INDEX_INVALID; wg_peer_clear (vm, peer); } @@ -147,13 +115,16 @@ wg_peer_build_rewrite (const wg_peer_t * peer) } static void -wg_peer_adj_stack (wg_peer_t * peer) +wg_peer_adj_stack (wg_peer_t *peer, adj_index_t ai) { ip_adjacency_t *adj; u32 sw_if_index; wg_if_t *wgi; - adj = adj_get (peer->adj_index); + if (!adj_is_valid (ai)) + return; + + adj = adj_get (ai); sw_if_index = adj->rewrite_header.sw_if_index; wgi = wg_if_get (wg_if_find_by_sw_if_index (sw_if_index)); @@ -163,7 +134,7 @@ wg_peer_adj_stack (wg_peer_t * peer) if (!vnet_sw_interface_is_admin_up (vnet_get_main (), wgi->sw_if_index)) { - adj_midchain_delegate_unstack (peer->adj_index); + adj_midchain_delegate_unstack (ai); } else { @@ -178,39 +149,69 @@ wg_peer_adj_stack (wg_peer_t * peer) fib_index = fib_table_find (FIB_PROTOCOL_IP4, peer->table_id); - adj_midchain_delegate_stack (peer->adj_index, fib_index, &dst); + adj_midchain_delegate_stack (ai, fib_index, &dst); } } walk_rc_t -wg_peer_if_admin_state_change (wg_if_t * wgi, index_t peeri, void *data) +wg_peer_if_admin_state_change (index_t peeri, void *data) { - wg_peer_adj_stack (wg_peer_get (peeri)); - + wg_peer_t *peer; + adj_index_t *adj_index; + peer = wg_peer_get (peeri); + vec_foreach (adj_index, peer->adj_indices) + { + wg_peer_adj_stack (peer, *adj_index); + } return (WALK_CONTINUE); } walk_rc_t -wg_peer_if_table_change (wg_if_t * wgi, index_t peeri, void *data) +wg_peer_if_adj_change (index_t peeri, void *data) { - wg_peer_table_bind_ctx_t *ctx = data; + adj_index_t *adj_index = data; + ip_adjacency_t *adj; wg_peer_t *peer; + fib_prefix_t *allowed_ip; - peer = wg_peer_get (peeri); + adj = adj_get (*adj_index); - wg_peer_fib_flush (peer); - wg_peer_fib_populate (peer, ctx->new_fib_index); + peer = wg_peer_get (peeri); + vec_foreach (allowed_ip, peer->allowed_ips) + { + if (fib_prefix_is_cover_addr_4 (allowed_ip, + &adj->sub_type.nbr.next_hop.ip4)) + { + vec_add1 (peer->adj_indices, *adj_index); + vec_validate_init_empty (wg_peer_by_adj_index, *adj_index, + INDEX_INVALID); + wg_peer_by_adj_index[*adj_index] = peer - wg_peer_pool; + + adj_nbr_midchain_update_rewrite (*adj_index, NULL, NULL, + ADJ_FLAG_MIDCHAIN_IP_STACK, + vec_dup (peer->rewrite)); + + wg_peer_adj_stack (peer, *adj_index); + return (WALK_STOP); + } + } return (WALK_CONTINUE); } +adj_walk_rc_t +wg_peer_adj_walk (adj_index_t ai, void *data) +{ + return wg_peer_if_adj_change ((*(index_t *) (data)), &ai) == WALK_CONTINUE ? + ADJ_WALK_RC_CONTINUE : + ADJ_WALK_RC_STOP; +} + static int -wg_peer_fill (vlib_main_t * vm, wg_peer_t * peer, - u32 table_id, - const ip46_address_t * dst, - u16 port, +wg_peer_fill (vlib_main_t *vm, wg_peer_t *peer, u32 table_id, + const ip46_address_t *dst, u16 port, u16 persistent_keepalive_interval, - const fib_prefix_t * allowed_ips, u32 wg_sw_if_index) + const fib_prefix_t *allowed_ips, u32 wg_sw_if_index) { wg_peer_endpoint_init (&peer->dst, dst, port); @@ -228,54 +229,29 @@ wg_peer_fill (vlib_main_t * vm, wg_peer_t * peer, ip_address_to_46 (&wgi->src_ip, &peer->src.addr); peer->src.port = wgi->port; - - /* - * and an adjacency for the endpoint address in the overlay - * on the wg interface - */ peer->rewrite = wg_peer_build_rewrite (peer); - peer->adj_index = adj_nbr_add_or_lock (FIB_PROTOCOL_IP4, - VNET_LINK_IP4, - &peer->dst.addr, wgi->sw_if_index); - - vec_validate_init_empty (wg_peer_by_adj_index, - peer->adj_index, INDEX_INVALID); - wg_peer_by_adj_index[peer->adj_index] = peer - wg_peer_pool; - - adj_nbr_midchain_update_rewrite (peer->adj_index, - NULL, - NULL, - ADJ_FLAG_MIDCHAIN_IP_STACK, - vec_dup (peer->rewrite)); - wg_peer_adj_stack (peer); - - /* - * add a route in the overlay to each of the allowed-ips - */ u32 ii; - vec_validate (peer->allowed_ips, vec_len (allowed_ips) - 1); - vec_foreach_index (ii, allowed_ips) { - peer->allowed_ips[ii].prefix = allowed_ips[ii]; + peer->allowed_ips[ii] = allowed_ips[ii]; } - wg_peer_fib_populate (peer, - fib_table_get_index_for_sw_if_index - (FIB_PROTOCOL_IP4, peer->wg_sw_if_index)); - + index_t perri = peer - wg_peer_pool; + fib_protocol_t proto; + FOR_EACH_FIB_IP_PROTOCOL (proto) + { + adj_nbr_walk (wg_sw_if_index, proto, wg_peer_adj_walk, &perri); + } return (0); } 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, - const fib_prefix_t * allowed_ips, - u16 port, u16 persistent_keepalive, u32 * peer_index) +wg_peer_add (u32 tun_sw_if_index, const u8 public_key[NOISE_PUBLIC_KEY_LEN], + u32 table_id, const ip46_address_t *endpoint, + const fib_prefix_t *allowed_ips, u16 port, + u16 persistent_keepalive, u32 *peer_index) { wg_if_t *wg_if; wg_peer_t *peer; @@ -374,8 +350,8 @@ format_wg_peer_endpoint (u8 * s, va_list * args) { wg_peer_endpoint_t *ep = va_arg (*args, wg_peer_endpoint_t *); - s = format (s, "%U:%d", - format_ip46_address, &ep->addr, IP46_TYPE_ANY, ep->port); + s = format (s, "%U:%d", format_ip46_address, &ep->addr, IP46_TYPE_ANY, + ep->port); return (s); } @@ -384,48 +360,34 @@ u8 * format_wg_peer (u8 * s, va_list * va) { index_t peeri = va_arg (*va, index_t); - wg_peer_allowed_ip_t *allowed_ip; + fib_prefix_t *allowed_ip; + adj_index_t *adj_index; u8 key[NOISE_KEY_LEN_BASE64]; wg_peer_t *peer; 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 adj:%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->adj_index); - s = format (s, "\n key:%=s %U", - key, format_hex_bytes, peer->remote.r_public, - NOISE_PUBLIC_KEY_LEN); + 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, "\n adj:"); + vec_foreach (adj_index, peer->adj_indices) + { + 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); s = format (s, "\n allowed-ips:"); vec_foreach (allowed_ip, peer->allowed_ips) { - s = format (s, " %U", format_fib_prefix, &allowed_ip->prefix); + s = format (s, " %U", format_fib_prefix, allowed_ip); } return s; } -static clib_error_t * -wg_peer_module_init (vlib_main_t * vm) -{ - /* - * use a priority better than interface source, so that - * if the same subnet is added to the wg interface and is - * used as an allowed IP, then the wireguard soueced prefix - * wins and traffic is routed to the endpoint rather than dropped - */ - wg_fib_source = fib_source_allocate ("wireguard", 0x2, FIB_SOURCE_BH_API); - - return (NULL); -} - -VLIB_INIT_FUNCTION (wg_peer_module_init); - /* * fd.io coding-style-patch-verification: ON * diff --git a/src/plugins/wireguard/wireguard_peer.h b/src/plugins/wireguard/wireguard_peer.h index b60c669ac0f..cf859f32b1f 100644 --- a/src/plugins/wireguard/wireguard_peer.h +++ b/src/plugins/wireguard/wireguard_peer.h @@ -33,12 +33,6 @@ typedef struct ip4_udp_header_t_ u8 *format_ip4_udp_header (u8 * s, va_list * va); -typedef struct wg_peer_allowed_ip_t_ -{ - fib_prefix_t prefix; - fib_node_index_t fib_entry_index; -} wg_peer_allowed_ip_t; - typedef struct wg_peer_endpoint_t_ { ip46_address_t addr; @@ -57,13 +51,13 @@ typedef struct wg_peer wg_peer_endpoint_t dst; wg_peer_endpoint_t src; u32 table_id; - adj_index_t adj_index; + adj_index_t *adj_indices; /* rewrite built from address information */ u8 *rewrite; /* Vector of allowed-ips */ - wg_peer_allowed_ip_t *allowed_ips; + fib_prefix_t *allowed_ips; /* The WG interface this peer is attached to */ u32 wg_sw_if_index; @@ -111,9 +105,9 @@ index_t wg_peer_walk (wg_peer_walk_cb_t fn, void *data); u8 *format_wg_peer (u8 * s, va_list * va); -walk_rc_t wg_peer_if_admin_state_change (wg_if_t * wgi, index_t peeri, - void *data); -walk_rc_t wg_peer_if_table_change (wg_if_t * wgi, index_t peeri, void *data); +walk_rc_t wg_peer_if_admin_state_change (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); /* * Expoed for the data-plane @@ -145,6 +139,22 @@ wg_peer_assign_thread (u32 thread_id) 1) : thread_id)); } +static_always_inline bool +fib_prefix_is_cover_addr_4 (const fib_prefix_t *p1, const ip4_address_t *ip4) +{ + switch (p1->fp_proto) + { + case FIB_PROTOCOL_IP4: + return (ip4_destination_matches_route (&ip4_main, &p1->fp_addr.ip4, ip4, + p1->fp_len) != 0); + case FIB_PROTOCOL_IP6: + return (false); + case FIB_PROTOCOL_MPLS: + break; + } + return (false); +} + #endif // __included_wg_peer_h__ /* -- cgit 1.2.3-korg