wireguard: use the same udp-port for multi-tunnel
[vpp.git] / src / plugins / wireguard / wireguard_if.c
index b1c5cb2..0866d24 100644 (file)
@@ -32,7 +32,7 @@ static uword *wg_if_instances;
 static index_t *wg_if_index_by_sw_if_index;
 
 /* vector of interfaces key'd on their UDP port (in network order) */
-index_t *wg_if_index_by_port;
+index_t **wg_if_indexes_by_port;
 
 static u8 *
 format_wg_if_name (u8 * s, va_list * args)
@@ -253,13 +253,6 @@ wg_if_create (u32 user_instance,
 
   *sw_if_indexp = (u32) ~ 0;
 
-  /*
-   * Check if the required port is already in use
-   */
-  udp_dst_port_info_t *pi = udp_get_dst_port_info (&udp_main, port, UDP_IP4);
-  if (pi)
-    return VNET_API_ERROR_UDP_PORT_TAKEN;
-
   /*
    * Allocate a wg_if instance. Either select on dynamically
    * or try to use the desired user_instance number.
@@ -295,10 +288,11 @@ wg_if_create (u32 user_instance,
   if (~0 == wg_if->user_instance)
     wg_if->user_instance = t_idx;
 
-  udp_register_dst_port (vlib_get_main (), port, wg_input_node.index, 1);
+  vec_validate_init_empty (wg_if_indexes_by_port, port, NULL);
+  if (vec_len (wg_if_indexes_by_port[port]) == 0)
+    udp_register_dst_port (vlib_get_main (), port, wg_input_node.index, 1);
 
-  vec_validate_init_empty (wg_if_index_by_port, port, INDEX_INVALID);
-  wg_if_index_by_port[port] = wg_if - wg_if_pool;
+  vec_add1 (wg_if_indexes_by_port[port], t_idx);
 
   wg_if->port = port;
   wg_if->local_idx = local - noise_local_pool;
@@ -334,15 +328,30 @@ wg_if_delete (u32 sw_if_index)
     return VNET_API_ERROR_INVALID_VALUE;
 
   wg_if_t *wg_if;
-  wg_if = wg_if_get (wg_if_find_by_sw_if_index (sw_if_index));
+  index_t wgii = wg_if_find_by_sw_if_index (sw_if_index);
+  wg_if = wg_if_get (wgii);
   if (NULL == wg_if)
     return VNET_API_ERROR_INVALID_SW_IF_INDEX_2;
 
   if (wg_if_instance_free (wg_if->user_instance) < 0)
     return VNET_API_ERROR_INVALID_VALUE_2;
 
-  udp_unregister_dst_port (vlib_get_main (), wg_if->port, 1);
-  wg_if_index_by_port[wg_if->port] = INDEX_INVALID;
+  // Remove peers before interface deletion
+  wg_if_peer_walk (wg_if, wg_peer_if_delete, NULL);
+
+  index_t *ii;
+  index_t *ifs = wg_if_indexes_get_by_port (wg_if->port);
+  vec_foreach (ii, ifs)
+    {
+      if (*ii == wgii)
+       {
+         vec_del1 (ifs, ifs - ii);
+         break;
+       }
+    }
+  if (vec_len (ifs) == 0)
+    udp_unregister_dst_port (vlib_get_main (), wg_if->port, 1);
+
   vnet_delete_hw_interface (vnm, hw->hw_if_index);
   pool_put_index (noise_local_pool, wg_if->local_idx);
   pool_put (wg_if_pool, wg_if);