wireguard: add ipv6 support 09/32009/12
authorArtem Glazychev <artem.glazychev@xored.com>
Thu, 3 Jun 2021 13:11:54 +0000 (20:11 +0700)
committerEd Warnicke <hagbard@gmail.com>
Wed, 6 Oct 2021 17:57:46 +0000 (17:57 +0000)
Type: improvement
Signed-off-by: Artem Glazychev <artem.glazychev@xored.com>
Change-Id: If1a7e82ce163c4c4acaa5acf45ad2b88371396f6

15 files changed:
src/plugins/wireguard/wireguard.c [changed mode: 0755->0644]
src/plugins/wireguard/wireguard.h
src/plugins/wireguard/wireguard_api.c
src/plugins/wireguard/wireguard_cli.c [changed mode: 0755->0644]
src/plugins/wireguard/wireguard_cookie.c [changed mode: 0755->0644]
src/plugins/wireguard/wireguard_cookie.h [changed mode: 0755->0644]
src/plugins/wireguard/wireguard_handoff.c
src/plugins/wireguard/wireguard_if.c
src/plugins/wireguard/wireguard_if.h
src/plugins/wireguard/wireguard_input.c
src/plugins/wireguard/wireguard_output_tun.c [changed mode: 0755->0644]
src/plugins/wireguard/wireguard_peer.c
src/plugins/wireguard/wireguard_peer.h
src/plugins/wireguard/wireguard_send.c [changed mode: 0755->0644]
test/test_wireguard.py

old mode 100755 (executable)
new mode 100644 (file)
index 5842229..8438cc1
@@ -15,7 +15,6 @@
 
 #include <vnet/vnet.h>
 #include <vnet/plugin/plugin.h>
 
 #include <vnet/vnet.h>
 #include <vnet/plugin/plugin.h>
-#include <vnet/ipip/ipip.h>
 #include <vpp/app/version.h>
 
 #include <wireguard/wireguard_send.h>
 #include <vpp/app/version.h>
 
 #include <wireguard/wireguard_send.h>
@@ -32,9 +31,12 @@ wg_init (vlib_main_t * vm)
 
   wmp->vlib_main = vm;
 
 
   wmp->vlib_main = vm;
 
-  wmp->in_fq_index = vlib_frame_queue_main_init (wg_input_node.index, 0);
-  wmp->out_fq_index =
-    vlib_frame_queue_main_init (wg_output_tun_node.index, 0);
+  wmp->in4_fq_index = vlib_frame_queue_main_init (wg4_input_node.index, 0);
+  wmp->in6_fq_index = vlib_frame_queue_main_init (wg6_input_node.index, 0);
+  wmp->out4_fq_index =
+    vlib_frame_queue_main_init (wg4_output_tun_node.index, 0);
+  wmp->out6_fq_index =
+    vlib_frame_queue_main_init (wg6_output_tun_node.index, 0);
 
   vlib_thread_main_t *tm = vlib_get_thread_main ();
 
 
   vlib_thread_main_t *tm = vlib_get_thread_main ();
 
@@ -50,13 +52,18 @@ VLIB_INIT_FUNCTION (wg_init);
 
 /* *INDENT-OFF* */
 
 
 /* *INDENT-OFF* */
 
-VNET_FEATURE_INIT (wg_output_tun, static) =
-{
+VNET_FEATURE_INIT (wg4_output_tun, static) = {
   .arc_name = "ip4-output",
   .arc_name = "ip4-output",
-  .node_name = "wg-output-tun",
+  .node_name = "wg4-output-tun",
   .runs_after = VNET_FEATURES ("gso-ip4"),
 };
 
   .runs_after = VNET_FEATURES ("gso-ip4"),
 };
 
+VNET_FEATURE_INIT (wg6_output_tun, static) = {
+  .arc_name = "ip6-output",
+  .node_name = "wg6-output-tun",
+  .runs_after = VNET_FEATURES ("gso-ip6"),
+};
+
 VLIB_PLUGIN_REGISTER () =
 {
   .version = VPP_BUILD_VER,
 VLIB_PLUGIN_REGISTER () =
 {
   .version = VPP_BUILD_VER,
index ef308c4..829c9e6 100755 (executable)
 
 #define WG_DEFAULT_DATA_SIZE 2048
 
 
 #define WG_DEFAULT_DATA_SIZE 2048
 
-extern vlib_node_registration_t wg_input_node;
-extern vlib_node_registration_t wg_output_tun_node;
+extern vlib_node_registration_t wg4_input_node;
+extern vlib_node_registration_t wg6_input_node;
+extern vlib_node_registration_t wg4_output_tun_node;
+extern vlib_node_registration_t wg6_output_tun_node;
 
 typedef struct wg_per_thread_data_t_
 {
 
 typedef struct wg_per_thread_data_t_
 {
@@ -37,8 +39,10 @@ typedef struct
 
   wg_index_table_t index_table;
 
 
   wg_index_table_t index_table;
 
-  u32 in_fq_index;
-  u32 out_fq_index;
+  u32 in4_fq_index;
+  u32 in6_fq_index;
+  u32 out4_fq_index;
+  u32 out6_fq_index;
 
   wg_per_thread_data_t *per_thread_data;
   u8 feature_init;
 
   wg_per_thread_data_t *per_thread_data;
   u8 feature_init;
index 3f17f65..5dd4f86 100644 (file)
@@ -47,19 +47,13 @@ static void
 
   ip_address_decode2 (&mp->interface.src_ip, &src);
 
 
   ip_address_decode2 (&mp->interface.src_ip, &src);
 
-  if (AF_IP6 == ip_addr_version (&src))
-    rv = VNET_API_ERROR_INVALID_PROTOCOL;
+  if (mp->generate_key)
+    curve25519_gen_secret (private_key);
   else
   else
-    {
-      if (mp->generate_key)
-       curve25519_gen_secret (private_key);
-      else
-       clib_memcpy (private_key, mp->interface.private_key,
-                    NOISE_PUBLIC_KEY_LEN);
-
-      rv = wg_if_create (ntohl (mp->interface.user_instance), private_key,
-                        ntohs (mp->interface.port), &src, &sw_if_index);
-    }
+    clib_memcpy (private_key, mp->interface.private_key, NOISE_PUBLIC_KEY_LEN);
+
+  rv = wg_if_create (ntohl (mp->interface.user_instance), private_key,
+                    ntohs (mp->interface.port), &src, &sw_if_index);
 
   /* *INDENT-OFF* */
   REPLY_MACRO2(VL_API_WIREGUARD_INTERFACE_CREATE_REPLY,
 
   /* *INDENT-OFF* */
   REPLY_MACRO2(VL_API_WIREGUARD_INTERFACE_CREATE_REPLY,
@@ -177,19 +171,10 @@ vl_api_wireguard_peer_add_t_handler (vl_api_wireguard_peer_add_t * mp)
   for (ii = 0; ii < mp->peer.n_allowed_ips; ii++)
     ip_prefix_decode (&mp->peer.allowed_ips[ii], &allowed_ips[ii]);
 
   for (ii = 0; ii < mp->peer.n_allowed_ips; ii++)
     ip_prefix_decode (&mp->peer.allowed_ips[ii], &allowed_ips[ii]);
 
-  if (AF_IP6 == ip_addr_version (&endpoint) ||
-      FIB_PROTOCOL_IP6 == allowed_ips[0].fp_proto)
-    /* ip6 currently not supported, but the API needs to support it
-     * else we'll need to change it later, and that's a PITA */
-    rv = VNET_API_ERROR_INVALID_PROTOCOL;
-  else
-    rv = wg_peer_add (ntohl (mp->peer.sw_if_index),
-                     mp->peer.public_key,
-                     ntohl (mp->peer.table_id),
-                     &ip_addr_46 (&endpoint),
-                     allowed_ips,
-                     ntohs (mp->peer.port),
-                     ntohs (mp->peer.persistent_keepalive), &peeri);
+  rv = wg_peer_add (ntohl (mp->peer.sw_if_index), mp->peer.public_key,
+                   ntohl (mp->peer.table_id), &ip_addr_46 (&endpoint),
+                   allowed_ips, ntohs (mp->peer.port),
+                   ntohs (mp->peer.persistent_keepalive), &peeri);
 
   vec_free (allowed_ips);
 done:
 
   vec_free (allowed_ips);
 done:
old mode 100755 (executable)
new mode 100644 (file)
index 3b4bf56..05275f7
@@ -213,16 +213,8 @@ wg_peer_add_command_fn (vlib_main_t * vm,
        }
     }
 
        }
     }
 
-  if (AF_IP6 == ip_addr_version (&ip) ||
-      FIB_PROTOCOL_IP6 == allowed_ip.fp_proto)
-    rv = VNET_API_ERROR_INVALID_PROTOCOL;
-  else
-    rv = wg_peer_add (tun_sw_if_index,
-                     public_key,
-                     table_id,
-                     &ip_addr_46 (&ip),
-                     allowed_ips,
-                     portDst, persistent_keepalive, &peer_index);
+  rv = wg_peer_add (tun_sw_if_index, public_key, table_id, &ip_addr_46 (&ip),
+                   allowed_ips, portDst, persistent_keepalive, &peer_index);
 
   switch (rv)
     {
 
   switch (rv)
     {
old mode 100755 (executable)
new mode 100644 (file)
index f54ce71..c4279b7
@@ -29,9 +29,9 @@ static void cookie_macs_mac1 (message_macs_t *, const void *, size_t,
                              const uint8_t[COOKIE_KEY_SIZE]);
 static void cookie_macs_mac2 (message_macs_t *, const void *, size_t,
                              const uint8_t[COOKIE_COOKIE_SIZE]);
                              const uint8_t[COOKIE_KEY_SIZE]);
 static void cookie_macs_mac2 (message_macs_t *, const void *, size_t,
                              const uint8_t[COOKIE_COOKIE_SIZE]);
-static void cookie_checker_make_cookie (vlib_main_t * vm, cookie_checker_t *,
+static void cookie_checker_make_cookie (vlib_main_t *vm, cookie_checker_t *,
                                        uint8_t[COOKIE_COOKIE_SIZE],
                                        uint8_t[COOKIE_COOKIE_SIZE],
-                                       ip4_address_t ip4, u16 udp_port);
+                                       ip46_address_t *ip, u16 udp_port);
 
 /* Public Functions */
 void
 
 /* Public Functions */
 void
@@ -76,9 +76,9 @@ cookie_maker_mac (cookie_maker_t * cp, message_macs_t * cm, void *buf,
 }
 
 enum cookie_mac_state
 }
 
 enum cookie_mac_state
-cookie_checker_validate_macs (vlib_main_t * vm, cookie_checker_t * cc,
-                             message_macs_t * cm, void *buf, size_t len,
-                             bool busy, ip4_address_t ip4, u16 udp_port)
+cookie_checker_validate_macs (vlib_main_t *vm, cookie_checker_t *cc,
+                             message_macs_t *cm, void *buf, size_t len,
+                             bool busy, ip46_address_t *ip, u16 udp_port)
 {
   message_macs_t our_cm;
   uint8_t cookie[COOKIE_COOKIE_SIZE];
 {
   message_macs_t our_cm;
   uint8_t cookie[COOKIE_COOKIE_SIZE];
@@ -93,7 +93,7 @@ cookie_checker_validate_macs (vlib_main_t * vm, cookie_checker_t * cc,
   if (!busy)
     return VALID_MAC_BUT_NO_COOKIE;
 
   if (!busy)
     return VALID_MAC_BUT_NO_COOKIE;
 
-  cookie_checker_make_cookie (vm, cc, cookie, ip4, udp_port);
+  cookie_checker_make_cookie (vm, cc, cookie, ip, udp_port);
   cookie_macs_mac2 (&our_cm, buf, len, cookie);
 
   /* If the mac2 is invalid, we want to send a cookie response */
   cookie_macs_mac2 (&our_cm, buf, len, cookie);
 
   /* If the mac2 is invalid, we want to send a cookie response */
@@ -139,9 +139,9 @@ cookie_macs_mac2 (message_macs_t * cm, const void *buf, size_t len,
 }
 
 static void
 }
 
 static void
-cookie_checker_make_cookie (vlib_main_t * vm, cookie_checker_t * cc,
+cookie_checker_make_cookie (vlib_main_t *vm, cookie_checker_t *cc,
                            uint8_t cookie[COOKIE_COOKIE_SIZE],
                            uint8_t cookie[COOKIE_COOKIE_SIZE],
-                           ip4_address_t ip4, u16 udp_port)
+                           ip46_address_t *ip, u16 udp_port)
 {
   blake2s_state_t state;
 
 {
   blake2s_state_t state;
 
@@ -155,7 +155,14 @@ cookie_checker_make_cookie (vlib_main_t * vm, cookie_checker_t * cc,
   blake2s_init_key (&state, COOKIE_COOKIE_SIZE, cc->cc_secret,
                    COOKIE_SECRET_SIZE);
 
   blake2s_init_key (&state, COOKIE_COOKIE_SIZE, cc->cc_secret,
                    COOKIE_SECRET_SIZE);
 
-  blake2s_update (&state, ip4.as_u8, sizeof (ip4_address_t));  //TODO: IP6
+  if (ip46_address_is_ip4 (ip))
+    {
+      blake2s_update (&state, ip->ip4.as_u8, sizeof (ip4_address_t));
+    }
+  else
+    {
+      blake2s_update (&state, ip->ip6.as_u8, sizeof (ip6_address_t));
+    }
   blake2s_update (&state, (u8 *) & udp_port, sizeof (u16));
   blake2s_final (&state, cookie, COOKIE_COOKIE_SIZE);
 }
   blake2s_update (&state, (u8 *) & udp_port, sizeof (u16));
   blake2s_final (&state, cookie, COOKIE_COOKIE_SIZE);
 }
old mode 100755 (executable)
new mode 100644 (file)
index 489cce8..6ef418f
@@ -18,7 +18,7 @@
 #ifndef __included_wg_cookie_h__
 #define __included_wg_cookie_h__
 
 #ifndef __included_wg_cookie_h__
 #define __included_wg_cookie_h__
 
-#include <vnet/ip/ip4_packet.h>
+#include <vnet/ip/ip46_address.h>
 #include <wireguard/wireguard_noise.h>
 
 enum cookie_mac_state
 #include <wireguard/wireguard_noise.h>
 
 enum cookie_mac_state
@@ -83,12 +83,10 @@ typedef struct cookie_checker
 void cookie_maker_init (cookie_maker_t *, const uint8_t[COOKIE_INPUT_SIZE]);
 void cookie_checker_update (cookie_checker_t *, uint8_t[COOKIE_INPUT_SIZE]);
 void cookie_maker_mac (cookie_maker_t *, message_macs_t *, void *, size_t);
 void cookie_maker_init (cookie_maker_t *, const uint8_t[COOKIE_INPUT_SIZE]);
 void cookie_checker_update (cookie_checker_t *, uint8_t[COOKIE_INPUT_SIZE]);
 void cookie_maker_mac (cookie_maker_t *, message_macs_t *, void *, size_t);
-enum cookie_mac_state cookie_checker_validate_macs (vlib_main_t * vm,
-                                                   cookie_checker_t *,
-                                                   message_macs_t *, void *,
-                                                   size_t, bool,
-                                                   ip4_address_t ip4,
-                                                   u16 udp_port);
+enum cookie_mac_state
+cookie_checker_validate_macs (vlib_main_t *vm, cookie_checker_t *,
+                             message_macs_t *, void *, size_t, bool,
+                             ip46_address_t *ip, u16 udp_port);
 
 #endif /* __included_wg_cookie_h__ */
 
 
 #endif /* __included_wg_cookie_h__ */
 
index d3e37b3..5f3dc14 100644 (file)
@@ -129,40 +129,78 @@ wg_handoff (vlib_main_t * vm,
   return n_enq;
 }
 
   return n_enq;
 }
 
-VLIB_NODE_FN (wg_handshake_handoff) (vlib_main_t * vm,
-                                    vlib_node_runtime_t * node,
-                                    vlib_frame_t * from_frame)
+VLIB_NODE_FN (wg4_handshake_handoff)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
 {
   wg_main_t *wmp = &wg_main;
 
 {
   wg_main_t *wmp = &wg_main;
 
-  return wg_handoff (vm, node, from_frame, wmp->in_fq_index,
+  return wg_handoff (vm, node, from_frame, wmp->in4_fq_index,
                     WG_HANDOFF_HANDSHAKE);
 }
 
                     WG_HANDOFF_HANDSHAKE);
 }
 
-VLIB_NODE_FN (wg_input_data_handoff) (vlib_main_t * vm,
-                                     vlib_node_runtime_t * node,
-                                     vlib_frame_t * from_frame)
+VLIB_NODE_FN (wg6_handshake_handoff)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
 {
   wg_main_t *wmp = &wg_main;
 
 {
   wg_main_t *wmp = &wg_main;
 
-  return wg_handoff (vm, node, from_frame, wmp->in_fq_index,
+  return wg_handoff (vm, node, from_frame, wmp->in6_fq_index,
+                    WG_HANDOFF_HANDSHAKE);
+}
+
+VLIB_NODE_FN (wg4_input_data_handoff)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
+{
+  wg_main_t *wmp = &wg_main;
+
+  return wg_handoff (vm, node, from_frame, wmp->in4_fq_index,
+                    WG_HANDOFF_INP_DATA);
+}
+
+VLIB_NODE_FN (wg6_input_data_handoff)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
+{
+  wg_main_t *wmp = &wg_main;
+
+  return wg_handoff (vm, node, from_frame, wmp->in6_fq_index,
                     WG_HANDOFF_INP_DATA);
 }
 
                     WG_HANDOFF_INP_DATA);
 }
 
-VLIB_NODE_FN (wg_output_tun_handoff) (vlib_main_t * vm,
-                                     vlib_node_runtime_t * node,
-                                     vlib_frame_t * from_frame)
+VLIB_NODE_FN (wg4_output_tun_handoff)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
 {
   wg_main_t *wmp = &wg_main;
 
 {
   wg_main_t *wmp = &wg_main;
 
-  return wg_handoff (vm, node, from_frame, wmp->out_fq_index,
+  return wg_handoff (vm, node, from_frame, wmp->out4_fq_index,
+                    WG_HANDOFF_OUT_TUN);
+}
+
+VLIB_NODE_FN (wg6_output_tun_handoff)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
+{
+  wg_main_t *wmp = &wg_main;
+
+  return wg_handoff (vm, node, from_frame, wmp->out6_fq_index,
                     WG_HANDOFF_OUT_TUN);
 }
 
 /* *INDENT-OFF* */
                     WG_HANDOFF_OUT_TUN);
 }
 
 /* *INDENT-OFF* */
-VLIB_REGISTER_NODE (wg_handshake_handoff) =
+VLIB_REGISTER_NODE (wg4_handshake_handoff) =
+{
+  .name = "wg4-handshake-handoff",
+  .vector_size = sizeof (u32),
+  .format_trace = format_wg_handoff_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN (wg_handoff_error_strings),
+  .error_strings = wg_handoff_error_strings,
+  .n_next_nodes = 1,
+  .next_nodes = {
+    [0] = "error-drop",
+  },
+};
+
+VLIB_REGISTER_NODE (wg6_handshake_handoff) =
 {
 {
-  .name = "wg-handshake-handoff",
+  .name = "wg6-handshake-handoff",
   .vector_size = sizeof (u32),
   .format_trace = format_wg_handoff_trace,
   .type = VLIB_NODE_TYPE_INTERNAL,
   .vector_size = sizeof (u32),
   .format_trace = format_wg_handoff_trace,
   .type = VLIB_NODE_TYPE_INTERNAL,
@@ -174,9 +212,9 @@ VLIB_REGISTER_NODE (wg_handshake_handoff) =
   },
 };
 
   },
 };
 
-VLIB_REGISTER_NODE (wg_input_data_handoff) =
+VLIB_REGISTER_NODE (wg4_input_data_handoff) =
 {
 {
-  .name = "wg-input-data-handoff",
+  .name = "wg4-input-data-handoff",
   .vector_size = sizeof (u32),
   .format_trace = format_wg_handoff_trace,
   .type = VLIB_NODE_TYPE_INTERNAL,
   .vector_size = sizeof (u32),
   .format_trace = format_wg_handoff_trace,
   .type = VLIB_NODE_TYPE_INTERNAL,
@@ -188,9 +226,37 @@ VLIB_REGISTER_NODE (wg_input_data_handoff) =
   },
 };
 
   },
 };
 
-VLIB_REGISTER_NODE (wg_output_tun_handoff) =
+VLIB_REGISTER_NODE (wg6_input_data_handoff) =
+{
+  .name = "wg6-input-data-handoff",
+  .vector_size = sizeof (u32),
+  .format_trace = format_wg_handoff_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN (wg_handoff_error_strings),
+  .error_strings = wg_handoff_error_strings,
+  .n_next_nodes = 1,
+  .next_nodes = {
+    [0] = "error-drop",
+  },
+};
+
+VLIB_REGISTER_NODE (wg4_output_tun_handoff) =
+{
+  .name = "wg4-output-tun-handoff",
+  .vector_size = sizeof (u32),
+  .format_trace = format_wg_handoff_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN (wg_handoff_error_strings),
+  .error_strings = wg_handoff_error_strings,
+  .n_next_nodes = 1,
+  .next_nodes =  {
+    [0] = "error-drop",
+  },
+};
+
+VLIB_REGISTER_NODE (wg6_output_tun_handoff) =
 {
 {
-  .name = "wg-output-tun-handoff",
+  .name = "wg6-output-tun-handoff",
   .vector_size = sizeof (u32),
   .format_trace = format_wg_handoff_trace,
   .type = VLIB_NODE_TYPE_INTERNAL,
   .vector_size = sizeof (u32),
   .format_trace = format_wg_handoff_trace,
   .type = VLIB_NODE_TYPE_INTERNAL,
index 0866d24..ad8f42c 100644 (file)
@@ -49,7 +49,6 @@ format_wg_if (u8 * s, va_list * args)
   noise_local_t *local = noise_local_get (wgi->local_idx);
   u8 key[NOISE_KEY_LEN_BASE64];
 
   noise_local_t *local = noise_local_get (wgi->local_idx);
   u8 key[NOISE_KEY_LEN_BASE64];
 
-
   s = format (s, "[%d] %U src:%U port:%d",
              wgii,
              format_vnet_sw_if_index_name, vnet_get_main (),
   s = format (s, "[%d] %U src:%U port:%d",
              wgii,
              format_vnet_sw_if_index_name, vnet_get_main (),
@@ -290,7 +289,12 @@ wg_if_create (u32 user_instance,
 
   vec_validate_init_empty (wg_if_indexes_by_port, port, NULL);
   if (vec_len (wg_if_indexes_by_port[port]) == 0)
 
   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);
+    {
+      udp_register_dst_port (vlib_get_main (), port, wg4_input_node.index,
+                            UDP_IP4);
+      udp_register_dst_port (vlib_get_main (), port, wg6_input_node.index,
+                            UDP_IP6);
+    }
 
   vec_add1 (wg_if_indexes_by_port[port], t_idx);
 
 
   vec_add1 (wg_if_indexes_by_port[port], t_idx);
 
@@ -350,7 +354,10 @@ wg_if_delete (u32 sw_if_index)
        }
     }
   if (vec_len (ifs) == 0)
        }
     }
   if (vec_len (ifs) == 0)
-    udp_unregister_dst_port (vlib_get_main (), wg_if->port, 1);
+    {
+      udp_unregister_dst_port (vlib_get_main (), wg_if->port, 1);
+      udp_unregister_dst_port (vlib_get_main (), wg_if->port, 0);
+    }
 
   vnet_delete_hw_interface (vnm, hw->hw_if_index);
   pool_put_index (noise_local_pool, wg_if->local_idx);
 
   vnet_delete_hw_interface (vnm, hw->hw_if_index);
   pool_put_index (noise_local_pool, wg_if->local_idx);
@@ -365,8 +372,12 @@ wg_if_peer_add (wg_if_t * wgi, index_t peeri)
   hash_set (wgi->peers, peeri, peeri);
 
   if (1 == hash_elts (wgi->peers))
   hash_set (wgi->peers, peeri, peeri);
 
   if (1 == hash_elts (wgi->peers))
-    vnet_feature_enable_disable ("ip4-output", "wg-output-tun",
-                                wgi->sw_if_index, 1, 0, 0);
+    {
+      vnet_feature_enable_disable ("ip4-output", "wg4-output-tun",
+                                  wgi->sw_if_index, 1, 0, 0);
+      vnet_feature_enable_disable ("ip6-output", "wg6-output-tun",
+                                  wgi->sw_if_index, 1, 0, 0);
+    }
 }
 
 void
 }
 
 void
@@ -375,8 +386,12 @@ wg_if_peer_remove (wg_if_t * wgi, index_t peeri)
   hash_unset (wgi->peers, peeri);
 
   if (0 == hash_elts (wgi->peers))
   hash_unset (wgi->peers, peeri);
 
   if (0 == hash_elts (wgi->peers))
-    vnet_feature_enable_disable ("ip4-output", "wg-output-tun",
-                                wgi->sw_if_index, 0, 0, 0);
+    {
+      vnet_feature_enable_disable ("ip4-output", "wg4-output-tun",
+                                  wgi->sw_if_index, 0, 0, 0);
+      vnet_feature_enable_disable ("ip6-output", "wg6-output-tun",
+                                  wgi->sw_if_index, 0, 0, 0);
+    }
 }
 
 void
 }
 
 void
index 3153a38..0a042cb 100644 (file)
@@ -31,8 +31,6 @@ typedef struct wg_if_t_
   cookie_checker_t cookie_checker;
   u16 port;
 
   cookie_checker_t cookie_checker;
   u16 port;
 
-  wg_index_table_t index_table;
-
   /* Source IP address for originated packets */
   ip_address_t src_ip;
 
   /* Source IP address for originated packets */
   ip_address_t src_ip;
 
index ad002dc..6a0623e 100644 (file)
@@ -79,11 +79,11 @@ format_wg_input_trace (u8 * s, va_list * args)
 
   wg_input_trace_t *t = va_arg (*args, wg_input_trace_t *);
 
 
   wg_input_trace_t *t = va_arg (*args, wg_input_trace_t *);
 
-  s = format (s, "WG input: \n");
-  s = format (s, "  Type: %U\n", format_wg_message_type, t->type);
-  s = format (s, "  peer: %d\n", t->peer);
-  s = format (s, "  Length: %d\n", t->current_length);
-  s = format (s, "  Keepalive: %s", t->is_keepalive ? "true" : "false");
+  s = format (s, "Wireguard input: \n");
+  s = format (s, "    Type: %U\n", format_wg_message_type, t->type);
+  s = format (s, "    Peer: %d\n", t->peer);
+  s = format (s, "    Length: %d\n", t->current_length);
+  s = format (s, "    Keepalive: %s", t->is_keepalive ? "true" : "false");
 
   return s;
 }
 
   return s;
 }
@@ -93,6 +93,7 @@ typedef enum
   WG_INPUT_NEXT_HANDOFF_HANDSHAKE,
   WG_INPUT_NEXT_HANDOFF_DATA,
   WG_INPUT_NEXT_IP4_INPUT,
   WG_INPUT_NEXT_HANDOFF_HANDSHAKE,
   WG_INPUT_NEXT_HANDOFF_DATA,
   WG_INPUT_NEXT_IP4_INPUT,
+  WG_INPUT_NEXT_IP6_INPUT,
   WG_INPUT_NEXT_PUNT,
   WG_INPUT_NEXT_ERROR,
   WG_INPUT_N_NEXT,
   WG_INPUT_NEXT_PUNT,
   WG_INPUT_NEXT_ERROR,
   WG_INPUT_N_NEXT,
@@ -108,8 +109,15 @@ typedef enum
 /*     } */
 /* } */
 
 /*     } */
 /* } */
 
+static u8
+is_ip4_header (u8 *data)
+{
+  return (data[0] >> 4) == 0x4;
+}
+
 static wg_input_error_t
 static wg_input_error_t
-wg_handshake_process (vlib_main_t * vm, wg_main_t * wmp, vlib_buffer_t * b)
+wg_handshake_process (vlib_main_t *vm, wg_main_t *wmp, vlib_buffer_t *b,
+                     u32 node_idx, u8 is_ip4)
 {
   ASSERT (vm->thread_index == 0);
 
 {
   ASSERT (vm->thread_index == 0);
 
@@ -122,10 +130,21 @@ wg_handshake_process (vlib_main_t * vm, wg_main_t * wmp, vlib_buffer_t * b)
 
   void *current_b_data = vlib_buffer_get_current (b);
 
 
   void *current_b_data = vlib_buffer_get_current (b);
 
+  ip46_address_t src_ip;
+  if (is_ip4)
+    {
+      ip4_header_t *iph4 =
+       current_b_data - sizeof (udp_header_t) - sizeof (ip4_header_t);
+      ip46_address_set_ip4 (&src_ip, &iph4->src_address);
+    }
+  else
+    {
+      ip6_header_t *iph6 =
+       current_b_data - sizeof (udp_header_t) - sizeof (ip6_header_t);
+      ip46_address_set_ip6 (&src_ip, &iph6->src_address);
+    }
+
   udp_header_t *uhd = current_b_data - sizeof (udp_header_t);
   udp_header_t *uhd = current_b_data - sizeof (udp_header_t);
-  ip4_header_t *iph =
-    current_b_data - sizeof (udp_header_t) - sizeof (ip4_header_t);
-  ip4_address_t ip4_src = iph->src_address;
   u16 udp_src_port = clib_host_to_net_u16 (uhd->src_port);;
   u16 udp_dst_port = clib_host_to_net_u16 (uhd->dst_port);;
 
   u16 udp_src_port = clib_host_to_net_u16 (uhd->src_port);;
   u16 udp_dst_port = clib_host_to_net_u16 (uhd->dst_port);;
 
@@ -168,7 +187,7 @@ wg_handshake_process (vlib_main_t * vm, wg_main_t * wmp, vlib_buffer_t * b)
 
       mac_state = cookie_checker_validate_macs (
        vm, &wg_if->cookie_checker, macs, current_b_data, len, under_load,
 
       mac_state = cookie_checker_validate_macs (
        vm, &wg_if->cookie_checker, macs, current_b_data, len, under_load,
-       ip4_src, udp_src_port);
+       &src_ip, udp_src_port);
       if (mac_state == INVALID_MAC)
        {
          wg_if = NULL;
       if (mac_state == INVALID_MAC)
        {
          wg_if = NULL;
@@ -214,7 +233,7 @@ wg_handshake_process (vlib_main_t * vm, wg_main_t * wmp, vlib_buffer_t * b)
        // set_peer_address (peer, ip4_src, udp_src_port);
        if (PREDICT_FALSE (!wg_send_handshake_response (vm, peer)))
          {
        // set_peer_address (peer, ip4_src, udp_src_port);
        if (PREDICT_FALSE (!wg_send_handshake_response (vm, peer)))
          {
-           vlib_node_increment_counter (vm, wg_input_node.index,
+           vlib_node_increment_counter (vm, node_idx,
                                         WG_INPUT_ERROR_HANDSHAKE_SEND, 1);
          }
        break;
                                         WG_INPUT_ERROR_HANDSHAKE_SEND, 1);
          }
        break;
@@ -254,9 +273,8 @@ wg_handshake_process (vlib_main_t * vm, wg_main_t * wmp, vlib_buffer_t * b)
            wg_timers_handshake_complete (peer);
            if (PREDICT_FALSE (!wg_send_keepalive (vm, peer)))
              {
            wg_timers_handshake_complete (peer);
            if (PREDICT_FALSE (!wg_send_keepalive (vm, peer)))
              {
-               vlib_node_increment_counter (vm, wg_input_node.index,
-                                            WG_INPUT_ERROR_KEEPALIVE_SEND,
-                                            1);
+               vlib_node_increment_counter (vm, node_idx,
+                                            WG_INPUT_ERROR_KEEPALIVE_SEND, 1);
              }
          }
        break;
              }
          }
        break;
@@ -270,9 +288,9 @@ wg_handshake_process (vlib_main_t * vm, wg_main_t * wmp, vlib_buffer_t * b)
   return WG_INPUT_ERROR_NONE;
 }
 
   return WG_INPUT_ERROR_NONE;
 }
 
-VLIB_NODE_FN (wg_input_node) (vlib_main_t * vm,
-                             vlib_node_runtime_t * node,
-                             vlib_frame_t * frame)
+always_inline uword
+wg_input_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
+                vlib_frame_t *frame, u8 is_ip4)
 {
   message_type_t header_type;
   u32 n_left_from;
 {
   message_type_t header_type;
   u32 n_left_from;
@@ -382,7 +400,20 @@ VLIB_NODE_FN (wg_input_node) (vlib_main_t * vm,
 
          wg_timers_data_received (peer);
 
 
          wg_timers_data_received (peer);
 
-         ip4_header_t *iph = vlib_buffer_get_current (b[0]);
+         ip46_address_t src_ip;
+         u8 is_ip4_inner = is_ip4_header (vlib_buffer_get_current (b[0]));
+         if (is_ip4_inner)
+           {
+             ip46_address_set_ip4 (
+               &src_ip, &((ip4_header_t *) vlib_buffer_get_current (b[0]))
+                           ->src_address);
+           }
+         else
+           {
+             ip46_address_set_ip6 (
+               &src_ip, &((ip6_header_t *) vlib_buffer_get_current (b[0]))
+                           ->src_address);
+           }
 
          const fib_prefix_t *allowed_ip;
          bool allowed = false;
 
          const fib_prefix_t *allowed_ip;
          bool allowed = false;
@@ -392,9 +423,10 @@ VLIB_NODE_FN (wg_input_node) (vlib_main_t * vm,
           * is that there aren't many allowed IPs and thus a linear
           * walk is fater than an ACL
           */
           * is that there aren't many allowed IPs and thus a linear
           * walk is fater than an ACL
           */
+
          vec_foreach (allowed_ip, peer->allowed_ips)
          {
          vec_foreach (allowed_ip, peer->allowed_ips)
          {
-           if (fib_prefix_is_cover_addr_4 (allowed_ip, &iph->src_address))
+           if (fib_prefix_is_cover_addr_46 (allowed_ip, &src_ip))
              {
                allowed = true;
                break;
              {
                allowed = true;
                break;
@@ -403,7 +435,8 @@ VLIB_NODE_FN (wg_input_node) (vlib_main_t * vm,
          if (allowed)
            {
              vnet_buffer (b[0])->sw_if_index[VLIB_RX] = peer->wg_sw_if_index;
          if (allowed)
            {
              vnet_buffer (b[0])->sw_if_index[VLIB_RX] = peer->wg_sw_if_index;
-             next[0] = WG_INPUT_NEXT_IP4_INPUT;
+             next[0] = is_ip4_inner ? WG_INPUT_NEXT_IP4_INPUT :
+                                      WG_INPUT_NEXT_IP6_INPUT;
            }
        }
       else
            }
        }
       else
@@ -417,7 +450,8 @@ VLIB_NODE_FN (wg_input_node) (vlib_main_t * vm,
              goto next;
            }
 
              goto next;
            }
 
-         wg_input_error_t ret = wg_handshake_process (vm, wmp, b[0]);
+         wg_input_error_t ret =
+           wg_handshake_process (vm, wmp, b[0], node->node_index, is_ip4);
          if (ret != WG_INPUT_ERROR_NONE)
            {
              next[0] = WG_INPUT_NEXT_ERROR;
          if (ret != WG_INPUT_ERROR_NONE)
            {
              next[0] = WG_INPUT_NEXT_ERROR;
@@ -445,10 +479,42 @@ VLIB_NODE_FN (wg_input_node) (vlib_main_t * vm,
   return frame->n_vectors;
 }
 
   return frame->n_vectors;
 }
 
+VLIB_NODE_FN (wg4_input_node)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
+{
+  return wg_input_inline (vm, node, frame, /* is_ip4 */ 1);
+}
+
+VLIB_NODE_FN (wg6_input_node)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
+{
+  return wg_input_inline (vm, node, frame, /* is_ip4 */ 0);
+}
+
 /* *INDENT-OFF* */
 /* *INDENT-OFF* */
-VLIB_REGISTER_NODE (wg_input_node) =
+VLIB_REGISTER_NODE (wg4_input_node) =
+{
+  .name = "wg4-input",
+  .vector_size = sizeof (u32),
+  .format_trace = format_wg_input_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN (wg_input_error_strings),
+  .error_strings = wg_input_error_strings,
+  .n_next_nodes = WG_INPUT_N_NEXT,
+  /* edit / add dispositions here */
+  .next_nodes = {
+        [WG_INPUT_NEXT_HANDOFF_HANDSHAKE] = "wg4-handshake-handoff",
+        [WG_INPUT_NEXT_HANDOFF_DATA] = "wg4-input-data-handoff",
+        [WG_INPUT_NEXT_IP4_INPUT] = "ip4-input-no-checksum",
+        [WG_INPUT_NEXT_IP6_INPUT] = "ip6-input",
+        [WG_INPUT_NEXT_PUNT] = "error-punt",
+        [WG_INPUT_NEXT_ERROR] = "error-drop",
+  },
+};
+
+VLIB_REGISTER_NODE (wg6_input_node) =
 {
 {
-  .name = "wg-input",
+  .name = "wg6-input",
   .vector_size = sizeof (u32),
   .format_trace = format_wg_input_trace,
   .type = VLIB_NODE_TYPE_INTERNAL,
   .vector_size = sizeof (u32),
   .format_trace = format_wg_input_trace,
   .type = VLIB_NODE_TYPE_INTERNAL,
@@ -457,9 +523,10 @@ VLIB_REGISTER_NODE (wg_input_node) =
   .n_next_nodes = WG_INPUT_N_NEXT,
   /* edit / add dispositions here */
   .next_nodes = {
   .n_next_nodes = WG_INPUT_N_NEXT,
   /* edit / add dispositions here */
   .next_nodes = {
-        [WG_INPUT_NEXT_HANDOFF_HANDSHAKE] = "wg-handshake-handoff",
-        [WG_INPUT_NEXT_HANDOFF_DATA] = "wg-input-data-handoff",
+        [WG_INPUT_NEXT_HANDOFF_HANDSHAKE] = "wg6-handshake-handoff",
+        [WG_INPUT_NEXT_HANDOFF_DATA] = "wg6-input-data-handoff",
         [WG_INPUT_NEXT_IP4_INPUT] = "ip4-input-no-checksum",
         [WG_INPUT_NEXT_IP4_INPUT] = "ip4-input-no-checksum",
+        [WG_INPUT_NEXT_IP6_INPUT] = "ip6-input",
         [WG_INPUT_NEXT_PUNT] = "error-punt",
         [WG_INPUT_NEXT_ERROR] = "error-drop",
   },
         [WG_INPUT_NEXT_PUNT] = "error-punt",
         [WG_INPUT_NEXT_ERROR] = "error-drop",
   },
old mode 100755 (executable)
new mode 100644 (file)
index 53a8797..80ba950
@@ -51,18 +51,28 @@ typedef enum
 
 typedef struct
 {
 
 typedef struct
 {
-  ip4_udp_header_t hdr;
   index_t peer;
   index_t peer;
+  u8 header[sizeof (ip6_udp_header_t)];
+  u8 is_ip4;
 } wg_output_tun_trace_t;
 
 u8 *
 format_ip4_udp_header (u8 * s, va_list * args)
 {
 } wg_output_tun_trace_t;
 
 u8 *
 format_ip4_udp_header (u8 * s, va_list * args)
 {
-  ip4_udp_header_t *hdr = va_arg (*args, ip4_udp_header_t *);
+  ip4_udp_header_t *hdr4 = va_arg (*args, ip4_udp_header_t *);
 
 
-  s = format (s, "%U:$U",
-             format_ip4_header, &hdr->ip4, format_udp_header, &hdr->udp);
+  s = format (s, "%U:$U", format_ip4_header, &hdr4->ip4, format_udp_header,
+             &hdr4->udp);
+  return (s);
+}
+
+u8 *
+format_ip6_udp_header (u8 *s, va_list *args)
+{
+  ip6_udp_header_t *hdr6 = va_arg (*args, ip6_udp_header_t *);
 
 
+  s = format (s, "%U:$U", format_ip6_header, &hdr6->ip6, format_udp_header,
+             &hdr6->udp);
   return (s);
 }
 
   return (s);
 }
 
@@ -76,16 +86,22 @@ format_wg_output_tun_trace (u8 * s, va_list * args)
   wg_output_tun_trace_t *t = va_arg (*args, wg_output_tun_trace_t *);
 
   s = format (s, "peer: %d\n", t->peer);
   wg_output_tun_trace_t *t = va_arg (*args, wg_output_tun_trace_t *);
 
   s = format (s, "peer: %d\n", t->peer);
-  s = format (s, "  Encrypted packet: %U", format_ip4_udp_header, &t->hdr);
+  s = format (s, "  Encrypted packet: ");
+
+  s = t->is_ip4 ? format (s, "%U", format_ip4_udp_header, t->header) :
+                 format (s, "%U", format_ip6_udp_header, t->header);
   return s;
 }
 
   return s;
 }
 
-VLIB_NODE_FN (wg_output_tun_node) (vlib_main_t * vm,
-                                  vlib_node_runtime_t * node,
-                                  vlib_frame_t * frame)
+/* is_ip4 - inner header flag */
+always_inline uword
+wg_output_tun_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
+                     vlib_frame_t *frame, u8 is_ip4)
 {
   u32 n_left_from;
   u32 *from;
 {
   u32 n_left_from;
   u32 *from;
+  ip4_udp_header_t *hdr4_out = NULL;
+  ip6_udp_header_t *hdr6_out = NULL;
   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
   u16 nexts[VLIB_FRAME_SIZE], *next;
   u32 thread_index = vm->thread_index;
   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
   u16 nexts[VLIB_FRAME_SIZE], *next;
   u32 thread_index = vm->thread_index;
@@ -102,12 +118,11 @@ VLIB_NODE_FN (wg_output_tun_node) (vlib_main_t * vm,
 
   while (n_left_from > 0)
     {
 
   while (n_left_from > 0)
     {
-      ip4_udp_header_t *hdr = vlib_buffer_get_current (b[0]);
-      u8 *plain_data = (vlib_buffer_get_current (b[0]) +
-                       sizeof (ip4_udp_header_t));
-      u16 plain_data_len =
-       clib_net_to_host_u16 (((ip4_header_t *) plain_data)->length);
       index_t peeri;
       index_t peeri;
+      u8 iph_offset = 0;
+      u8 is_ip4_out = 1;
+      u8 *plain_data;
+      u16 plain_data_len;
 
       next[0] = WG_OUTPUT_NEXT_ERROR;
       peeri =
 
       next[0] = WG_OUTPUT_NEXT_ERROR;
       peeri =
@@ -119,7 +134,6 @@ VLIB_NODE_FN (wg_output_tun_node) (vlib_main_t * vm,
          b[0]->error = node->errors[WG_OUTPUT_ERROR_PEER];
          goto out;
        }
          b[0]->error = node->errors[WG_OUTPUT_ERROR_PEER];
          goto out;
        }
-
       if (PREDICT_FALSE (~0 == peer->output_thread_index))
        {
          /* this is the first packet to use this peer, claim the peer
       if (PREDICT_FALSE (~0 == peer->output_thread_index))
        {
          /* this is the first packet to use this peer, claim the peer
@@ -141,6 +155,21 @@ VLIB_NODE_FN (wg_output_tun_node) (vlib_main_t * vm,
          b[0]->error = node->errors[WG_OUTPUT_ERROR_KEYPAIR];
          goto out;
        }
          b[0]->error = node->errors[WG_OUTPUT_ERROR_KEYPAIR];
          goto out;
        }
+
+      is_ip4_out = ip46_address_is_ip4 (&peer->src.addr);
+      if (is_ip4_out)
+       {
+         hdr4_out = vlib_buffer_get_current (b[0]);
+       }
+      else
+       {
+         hdr6_out = vlib_buffer_get_current (b[0]);
+       }
+
+      iph_offset = vnet_buffer (b[0])->ip.save_rewrite_length;
+      plain_data = vlib_buffer_get_current (b[0]) + iph_offset;
+      plain_data_len = vlib_buffer_length_in_chain (vm, b[0]) - iph_offset;
+
       size_t encrypted_packet_len = message_data_len (plain_data_len);
 
       /*
       size_t encrypted_packet_len = message_data_len (plain_data_len);
 
       /*
@@ -159,13 +188,10 @@ VLIB_NODE_FN (wg_output_tun_node) (vlib_main_t * vm,
        (message_data_t *) wmp->per_thread_data[thread_index].data;
 
       enum noise_state_crypt state;
        (message_data_t *) wmp->per_thread_data[thread_index].data;
 
       enum noise_state_crypt state;
-      state =
-       noise_remote_encrypt (vm,
-                             &peer->remote,
-                             &encrypted_packet->receiver_index,
-                             &encrypted_packet->counter, plain_data,
-                             plain_data_len,
-                             encrypted_packet->encrypted_data);
+      state = noise_remote_encrypt (
+       vm, &peer->remote, &encrypted_packet->receiver_index,
+       &encrypted_packet->counter, plain_data, plain_data_len,
+       encrypted_packet->encrypted_data);
 
       if (PREDICT_FALSE (state == SC_KEEP_KEY_FRESH))
        {
 
       if (PREDICT_FALSE (state == SC_KEEP_KEY_FRESH))
        {
@@ -184,12 +210,24 @@ VLIB_NODE_FN (wg_output_tun_node) (vlib_main_t * vm,
 
       clib_memcpy (plain_data, (u8 *) encrypted_packet, encrypted_packet_len);
 
 
       clib_memcpy (plain_data, (u8 *) encrypted_packet, encrypted_packet_len);
 
-      hdr->udp.length = clib_host_to_net_u16 (encrypted_packet_len +
-                                             sizeof (udp_header_t));
-      b[0]->current_length = (encrypted_packet_len +
-                             sizeof (ip4_header_t) + sizeof (udp_header_t));
-      ip4_header_set_len_w_chksum
-       (&hdr->ip4, clib_host_to_net_u16 (b[0]->current_length));
+      if (is_ip4_out)
+       {
+         hdr4_out->udp.length = clib_host_to_net_u16 (encrypted_packet_len +
+                                                      sizeof (udp_header_t));
+         b[0]->current_length =
+           (encrypted_packet_len + sizeof (ip4_udp_header_t));
+         ip4_header_set_len_w_chksum (
+           &hdr4_out->ip4, clib_host_to_net_u16 (b[0]->current_length));
+       }
+      else
+       {
+         hdr6_out->udp.length = clib_host_to_net_u16 (encrypted_packet_len +
+                                                      sizeof (udp_header_t));
+         b[0]->current_length =
+           (encrypted_packet_len + sizeof (ip6_udp_header_t));
+         hdr6_out->ip6.payload_length =
+           clib_host_to_net_u16 (b[0]->current_length);
+       }
 
       wg_timers_any_authenticated_packet_sent (peer);
       wg_timers_data_sent (peer);
 
       wg_timers_any_authenticated_packet_sent (peer);
       wg_timers_data_sent (peer);
@@ -201,9 +239,15 @@ VLIB_NODE_FN (wg_output_tun_node) (vlib_main_t * vm,
        {
          wg_output_tun_trace_t *t =
            vlib_add_trace (vm, node, b[0], sizeof (*t));
        {
          wg_output_tun_trace_t *t =
            vlib_add_trace (vm, node, b[0], sizeof (*t));
-         t->hdr = *hdr;
+
          t->peer = peeri;
          t->peer = peeri;
+         t->is_ip4 = is_ip4_out;
+         if (hdr4_out)
+           clib_memcpy (t->header, hdr4_out, sizeof (*hdr4_out));
+         else if (hdr6_out)
+           clib_memcpy (t->header, hdr6_out, sizeof (*hdr6_out));
        }
        }
+
     next:
       n_left_from -= 1;
       next += 1;
     next:
       n_left_from -= 1;
       next += 1;
@@ -214,10 +258,38 @@ VLIB_NODE_FN (wg_output_tun_node) (vlib_main_t * vm,
   return frame->n_vectors;
 }
 
   return frame->n_vectors;
 }
 
+VLIB_NODE_FN (wg4_output_tun_node)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
+{
+  return wg_output_tun_inline (vm, node, frame, /* is_ip4 */ 1);
+}
+
+VLIB_NODE_FN (wg6_output_tun_node)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
+{
+  return wg_output_tun_inline (vm, node, frame, /* is_ip4 */ 0);
+}
+
 /* *INDENT-OFF* */
 /* *INDENT-OFF* */
-VLIB_REGISTER_NODE (wg_output_tun_node) =
+VLIB_REGISTER_NODE (wg4_output_tun_node) =
+{
+  .name = "wg4-output-tun",
+  .vector_size = sizeof (u32),
+  .format_trace = format_wg_output_tun_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN (wg_output_error_strings),
+  .error_strings = wg_output_error_strings,
+  .n_next_nodes = WG_OUTPUT_N_NEXT,
+  .next_nodes = {
+        [WG_OUTPUT_NEXT_HANDOFF] = "wg4-output-tun-handoff",
+        [WG_OUTPUT_NEXT_INTERFACE_OUTPUT] = "adj-midchain-tx",
+        [WG_OUTPUT_NEXT_ERROR] = "error-drop",
+  },
+};
+
+VLIB_REGISTER_NODE (wg6_output_tun_node) =
 {
 {
-  .name = "wg-output-tun",
+  .name = "wg6-output-tun",
   .vector_size = sizeof (u32),
   .format_trace = format_wg_output_tun_trace,
   .type = VLIB_NODE_TYPE_INTERNAL,
   .vector_size = sizeof (u32),
   .format_trace = format_wg_output_tun_trace,
   .type = VLIB_NODE_TYPE_INTERNAL,
@@ -225,7 +297,7 @@ VLIB_REGISTER_NODE (wg_output_tun_node) =
   .error_strings = wg_output_error_strings,
   .n_next_nodes = WG_OUTPUT_N_NEXT,
   .next_nodes = {
   .error_strings = wg_output_error_strings,
   .n_next_nodes = WG_OUTPUT_N_NEXT,
   .next_nodes = {
-        [WG_OUTPUT_NEXT_HANDOFF] = "wg-output-tun-handoff",
+        [WG_OUTPUT_NEXT_HANDOFF] = "wg6-output-tun-handoff",
         [WG_OUTPUT_NEXT_INTERFACE_OUTPUT] = "adj-midchain-tx",
         [WG_OUTPUT_NEXT_ERROR] = "error-drop",
   },
         [WG_OUTPUT_NEXT_INTERFACE_OUTPUT] = "adj-midchain-tx",
         [WG_OUTPUT_NEXT_ERROR] = "error-drop",
   },
index d4a85a2..fb54014 100644 (file)
@@ -22,6 +22,7 @@
 #include <wireguard/wireguard_key.h>
 #include <wireguard/wireguard_send.h>
 #include <wireguard/wireguard.h>
 #include <wireguard/wireguard_key.h>
 #include <wireguard/wireguard_send.h>
 #include <wireguard/wireguard.h>
+#include <vnet/tunnel/tunnel_dp.h>
 
 wg_peer_t *wg_peer_pool;
 
 
 wg_peer_t *wg_peer_pool;
 
@@ -91,25 +92,44 @@ wg_peer_init (vlib_main_t * vm, wg_peer_t * peer)
 }
 
 static u8 *
 }
 
 static u8 *
-wg_peer_build_rewrite (const wg_peer_t * peer)
+wg_peer_build_rewrite (const wg_peer_t *peer, u8 is_ip4)
 {
 {
-  // v4 only for now
-  ip4_udp_header_t *hdr;
   u8 *rewrite = NULL;
   u8 *rewrite = NULL;
+  if (is_ip4)
+    {
+      ip4_udp_header_t *hdr;
+
+      vec_validate (rewrite, sizeof (*hdr) - 1);
+      hdr = (ip4_udp_header_t *) rewrite;
+
+      hdr->ip4.ip_version_and_header_length = 0x45;
+      hdr->ip4.ttl = 64;
+      hdr->ip4.src_address = peer->src.addr.ip4;
+      hdr->ip4.dst_address = peer->dst.addr.ip4;
+      hdr->ip4.protocol = IP_PROTOCOL_UDP;
+      hdr->ip4.checksum = ip4_header_checksum (&hdr->ip4);
+
+      hdr->udp.src_port = clib_host_to_net_u16 (peer->src.port);
+      hdr->udp.dst_port = clib_host_to_net_u16 (peer->dst.port);
+      hdr->udp.checksum = 0;
+    }
+  else
+    {
+      ip6_udp_header_t *hdr;
 
 
-  vec_validate (rewrite, sizeof (*hdr) - 1);
-  hdr = (ip4_udp_header_t *) rewrite;
+      vec_validate (rewrite, sizeof (*hdr) - 1);
+      hdr = (ip6_udp_header_t *) rewrite;
 
 
-  hdr->ip4.ip_version_and_header_length = 0x45;
-  hdr->ip4.ttl = 64;
-  hdr->ip4.src_address = peer->src.addr.ip4;
-  hdr->ip4.dst_address = peer->dst.addr.ip4;
-  hdr->ip4.protocol = IP_PROTOCOL_UDP;
-  hdr->ip4.checksum = ip4_header_checksum (&hdr->ip4);
+      hdr->ip6.ip_version_traffic_class_and_flow_label = 0x60;
+      ip6_address_copy (&hdr->ip6.src_address, &peer->src.addr.ip6);
+      ip6_address_copy (&hdr->ip6.dst_address, &peer->dst.addr.ip6);
+      hdr->ip6.protocol = IP_PROTOCOL_UDP;
+      hdr->ip6.hop_limit = 64;
 
 
-  hdr->udp.src_port = clib_host_to_net_u16 (peer->src.port);
-  hdr->udp.dst_port = clib_host_to_net_u16 (peer->dst.port);
-  hdr->udp.checksum = 0;
+      hdr->udp.src_port = clib_host_to_net_u16 (peer->src.port);
+      hdr->udp.dst_port = clib_host_to_net_u16 (peer->dst.port);
+      hdr->udp.checksum = 0;
+    }
 
   return (rewrite);
 }
 
   return (rewrite);
 }
@@ -120,12 +140,15 @@ wg_peer_adj_stack (wg_peer_t *peer, adj_index_t ai)
   ip_adjacency_t *adj;
   u32 sw_if_index;
   wg_if_t *wgi;
   ip_adjacency_t *adj;
   u32 sw_if_index;
   wg_if_t *wgi;
+  fib_protocol_t fib_proto;
 
   if (!adj_is_valid (ai))
     return;
 
   adj = adj_get (ai);
   sw_if_index = adj->rewrite_header.sw_if_index;
 
   if (!adj_is_valid (ai))
     return;
 
   adj = adj_get (ai);
   sw_if_index = adj->rewrite_header.sw_if_index;
+  u8 is_ip4 = ip46_address_is_ip4 (&peer->src.addr);
+  fib_proto = is_ip4 ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6;
 
   wgi = wg_if_get (wg_if_find_by_sw_if_index (sw_if_index));
 
 
   wgi = wg_if_get (wg_if_find_by_sw_if_index (sw_if_index));
 
@@ -140,19 +163,76 @@ wg_peer_adj_stack (wg_peer_t *peer, adj_index_t ai)
     {
       /* *INDENT-OFF* */
       fib_prefix_t dst = {
     {
       /* *INDENT-OFF* */
       fib_prefix_t dst = {
-        .fp_len = 32,
-        .fp_proto = FIB_PROTOCOL_IP4,
-        .fp_addr = peer->dst.addr,
+       .fp_len = is_ip4 ? 32 : 128,
+       .fp_proto = fib_proto,
+       .fp_addr = peer->dst.addr,
       };
       /* *INDENT-ON* */
       u32 fib_index;
 
       };
       /* *INDENT-ON* */
       u32 fib_index;
 
-      fib_index = fib_table_find (FIB_PROTOCOL_IP4, peer->table_id);
+      fib_index = fib_table_find (fib_proto, peer->table_id);
 
       adj_midchain_delegate_stack (ai, fib_index, &dst);
     }
 }
 
 
       adj_midchain_delegate_stack (ai, fib_index, &dst);
     }
 }
 
+static void
+wg_peer_66_fixup (vlib_main_t *vm, const ip_adjacency_t *adj, vlib_buffer_t *b,
+                 const void *data)
+{
+  u8 iph_offset = 0;
+  ip6_header_t *ip6_out;
+  ip6_header_t *ip6_in;
+
+  /* Must set locally originated otherwise we're not allowed to
+     fragment the packet later */
+  b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
+
+  ip6_out = vlib_buffer_get_current (b);
+  iph_offset = vnet_buffer (b)->ip.save_rewrite_length;
+  ip6_in = vlib_buffer_get_current (b) + iph_offset;
+
+  ip6_out->ip_version_traffic_class_and_flow_label =
+    ip6_in->ip_version_traffic_class_and_flow_label;
+}
+
+static void
+wg_peer_46_fixup (vlib_main_t *vm, const ip_adjacency_t *adj, vlib_buffer_t *b,
+                 const void *data)
+{
+  u8 iph_offset = 0;
+  ip6_header_t *ip6_out;
+  ip4_header_t *ip4_in;
+
+  /* Must set locally originated otherwise we're not allowed to
+     fragment the packet later */
+  b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
+
+  ip6_out = vlib_buffer_get_current (b);
+  iph_offset = vnet_buffer (b)->ip.save_rewrite_length;
+  ip4_in = vlib_buffer_get_current (b) + iph_offset;
+
+  u32 vtcfl = 0x6 << 28;
+  vtcfl |= ip4_in->tos << 20;
+  vtcfl |= vnet_buffer (b)->ip.flow_hash & 0x000fffff;
+
+  ip6_out->ip_version_traffic_class_and_flow_label =
+    clib_host_to_net_u32 (vtcfl);
+}
+
+static adj_midchain_fixup_t
+wg_peer_get_fixup (wg_peer_t *peer, vnet_link_t lt)
+{
+  if (!ip46_address_is_ip4 (&peer->dst.addr))
+    {
+      if (lt == VNET_LINK_IP4)
+       return (wg_peer_46_fixup);
+      if (lt == VNET_LINK_IP6)
+       return (wg_peer_66_fixup);
+    }
+  return (NULL);
+}
+
 walk_rc_t
 wg_peer_if_admin_state_change (index_t peeri, void *data)
 {
 walk_rc_t
 wg_peer_if_admin_state_change (index_t peeri, void *data)
 {
@@ -170,6 +250,7 @@ walk_rc_t
 wg_peer_if_adj_change (index_t peeri, void *data)
 {
   adj_index_t *adj_index = data;
 wg_peer_if_adj_change (index_t peeri, void *data)
 {
   adj_index_t *adj_index = data;
+  adj_midchain_fixup_t fixup;
   ip_adjacency_t *adj;
   wg_peer_t *peer;
   fib_prefix_t *allowed_ip;
   ip_adjacency_t *adj;
   wg_peer_t *peer;
   fib_prefix_t *allowed_ip;
@@ -179,15 +260,16 @@ wg_peer_if_adj_change (index_t peeri, void *data)
   peer = wg_peer_get (peeri);
   vec_foreach (allowed_ip, peer->allowed_ips)
     {
   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))
+      if (fib_prefix_is_cover_addr_46 (allowed_ip,
+                                      &adj->sub_type.nbr.next_hop))
        {
          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;
 
        {
          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,
+         fixup = wg_peer_get_fixup (peer, adj_get_link_type (*adj_index));
+         adj_nbr_midchain_update_rewrite (*adj_index, fixup, NULL,
                                           ADJ_FLAG_MIDCHAIN_IP_STACK,
                                           vec_dup (peer->rewrite));
 
                                           ADJ_FLAG_MIDCHAIN_IP_STACK,
                                           vec_dup (peer->rewrite));
 
@@ -236,7 +318,9 @@ wg_peer_fill (vlib_main_t *vm, wg_peer_t *peer, u32 table_id,
 
   ip_address_to_46 (&wgi->src_ip, &peer->src.addr);
   peer->src.port = wgi->port;
 
   ip_address_to_46 (&wgi->src_ip, &peer->src.addr);
   peer->src.port = wgi->port;
-  peer->rewrite = wg_peer_build_rewrite (peer);
+
+  u8 is_ip4 = ip46_address_is_ip4 (&peer->dst.addr);
+  peer->rewrite = wg_peer_build_rewrite (peer, is_ip4);
 
   u32 ii;
   vec_validate (peer->allowed_ips, vec_len (allowed_ips) - 1);
 
   u32 ii;
   vec_validate (peer->allowed_ips, vec_len (allowed_ips) - 1);
index e23feb7..c719ac1 100644 (file)
@@ -31,7 +31,14 @@ typedef struct ip4_udp_header_t_
   udp_header_t udp;
 } __clib_packed ip4_udp_header_t;
 
   udp_header_t udp;
 } __clib_packed ip4_udp_header_t;
 
+typedef struct ip6_udp_header_t_
+{
+  ip6_header_t ip6;
+  udp_header_t udp;
+} __clib_packed ip6_udp_header_t;
+
 u8 *format_ip4_udp_header (u8 * s, va_list * va);
 u8 *format_ip4_udp_header (u8 * s, va_list * va);
+u8 *format_ip6_udp_header (u8 *s, va_list *va);
 
 typedef struct wg_peer_endpoint_t_
 {
 
 typedef struct wg_peer_endpoint_t_
 {
@@ -141,15 +148,16 @@ wg_peer_assign_thread (u32 thread_id)
 }
 
 static_always_inline bool
 }
 
 static_always_inline bool
-fib_prefix_is_cover_addr_4 (const fib_prefix_t *p1, const ip4_address_t *ip4)
+fib_prefix_is_cover_addr_46 (const fib_prefix_t *p1, const ip46_address_t *ip)
 {
   switch (p1->fp_proto)
     {
     case FIB_PROTOCOL_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);
+      return (ip4_destination_matches_route (&ip4_main, &p1->fp_addr.ip4,
+                                            &ip->ip4, p1->fp_len) != 0);
     case FIB_PROTOCOL_IP6:
     case FIB_PROTOCOL_IP6:
-      return (false);
+      return (ip6_destination_matches_route (&ip6_main, &p1->fp_addr.ip6,
+                                            &ip->ip6, p1->fp_len) != 0);
     case FIB_PROTOCOL_MPLS:
       break;
     }
     case FIB_PROTOCOL_MPLS:
       break;
     }
old mode 100755 (executable)
new mode 100644 (file)
index f492e05..4451e00
 #include <wireguard/wireguard_send.h>
 
 static int
 #include <wireguard/wireguard_send.h>
 
 static int
-ip46_enqueue_packet (vlib_main_t * vm, u32 bi0, int is_ip6)
+ip46_enqueue_packet (vlib_main_t *vm, u32 bi0, int is_ip4)
 {
   vlib_frame_t *f = 0;
   u32 lookup_node_index =
 {
   vlib_frame_t *f = 0;
   u32 lookup_node_index =
-    is_ip6 ? ip6_lookup_node.index : ip4_lookup_node.index;
+    is_ip4 ? ip4_lookup_node.index : ip6_lookup_node.index;
 
   f = vlib_get_frame_to_node (vm, lookup_node_index);
   /* f can not be NULL here - frame allocation failure causes panic */
 
   f = vlib_get_frame_to_node (vm, lookup_node_index);
   /* f can not be NULL here - frame allocation failure causes panic */
@@ -41,25 +41,41 @@ ip46_enqueue_packet (vlib_main_t * vm, u32 bi0, int is_ip6)
 }
 
 static void
 }
 
 static void
-wg_buffer_prepend_rewrite (vlib_buffer_t * b0, const wg_peer_t * peer)
+wg_buffer_prepend_rewrite (vlib_buffer_t *b0, const wg_peer_t *peer, u8 is_ip4)
 {
 {
-  ip4_udp_header_t *hdr;
+  if (is_ip4)
+    {
+      ip4_udp_header_t *hdr4;
+
+      vlib_buffer_advance (b0, -sizeof (*hdr4));
 
 
-  vlib_buffer_advance (b0, -sizeof (*hdr));
+      hdr4 = vlib_buffer_get_current (b0);
+      clib_memcpy (hdr4, peer->rewrite, vec_len (peer->rewrite));
 
 
-  hdr = vlib_buffer_get_current (b0);
-  clib_memcpy (hdr, peer->rewrite, vec_len (peer->rewrite));
+      hdr4->udp.length =
+       clib_host_to_net_u16 (b0->current_length - sizeof (ip4_header_t));
+      ip4_header_set_len_w_chksum (&hdr4->ip4,
+                                  clib_host_to_net_u16 (b0->current_length));
+    }
+  else
+    {
+      ip6_udp_header_t *hdr6;
 
 
-  hdr->udp.length =
-    clib_host_to_net_u16 (b0->current_length - sizeof (ip4_header_t));
-  ip4_header_set_len_w_chksum (&hdr->ip4,
-                              clib_host_to_net_u16 (b0->current_length));
+      vlib_buffer_advance (b0, -sizeof (*hdr6));
+
+      hdr6 = vlib_buffer_get_current (b0);
+      clib_memcpy (hdr6, peer->rewrite, vec_len (peer->rewrite));
+
+      hdr6->udp.length =
+       clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
+
+      hdr6->ip6.payload_length = clib_host_to_net_u16 (b0->current_length);
+    }
 }
 
 static bool
 }
 
 static bool
-wg_create_buffer (vlib_main_t * vm,
-                 const wg_peer_t * peer,
-                 const u8 * packet, u32 packet_len, u32 * bi)
+wg_create_buffer (vlib_main_t *vm, const wg_peer_t *peer, const u8 *packet,
+                 u32 packet_len, u32 *bi, u8 is_ip4)
 {
   u32 n_buf0 = 0;
   vlib_buffer_t *b0;
 {
   u32 n_buf0 = 0;
   vlib_buffer_t *b0;
@@ -75,7 +91,7 @@ wg_create_buffer (vlib_main_t * vm,
 
   b0->current_length = packet_len;
 
 
   b0->current_length = packet_len;
 
-  wg_buffer_prepend_rewrite (b0, peer);
+  wg_buffer_prepend_rewrite (b0, peer, is_ip4);
 
   return true;
 }
 
   return true;
 }
@@ -113,11 +129,13 @@ wg_send_handshake (vlib_main_t * vm, wg_peer_t * peer, bool is_retry)
   else
     return false;
 
   else
     return false;
 
+  u8 is_ip4 = ip46_address_is_ip4 (&peer->dst.addr);
   u32 bi0 = 0;
   u32 bi0 = 0;
-  if (!wg_create_buffer (vm, peer, (u8 *) & packet, sizeof (packet), &bi0))
+  if (!wg_create_buffer (vm, peer, (u8 *) &packet, sizeof (packet), &bi0,
+                        is_ip4))
     return false;
 
     return false;
 
-  ip46_enqueue_packet (vm, bi0, false);
+  ip46_enqueue_packet (vm, bi0, is_ip4);
   return true;
 }
 
   return true;
 }
 
@@ -185,15 +203,17 @@ wg_send_keepalive (vlib_main_t * vm, wg_peer_t * peer)
       goto out;
     }
 
       goto out;
     }
 
+  u8 is_ip4 = ip46_address_is_ip4 (&peer->dst.addr);
   packet->header.type = MESSAGE_DATA;
 
   packet->header.type = MESSAGE_DATA;
 
-  if (!wg_create_buffer (vm, peer, (u8 *) packet, size_of_packet, &bi0))
+  if (!wg_create_buffer (vm, peer, (u8 *) packet, size_of_packet, &bi0,
+                        is_ip4))
     {
       ret = false;
       goto out;
     }
 
     {
       ret = false;
       goto out;
     }
 
-  ip46_enqueue_packet (vm, bi0, false);
+  ip46_enqueue_packet (vm, bi0, is_ip4);
 
   wg_timers_any_authenticated_packet_sent (peer);
   wg_timers_any_authenticated_packet_traversal (peer);
 
   wg_timers_any_authenticated_packet_sent (peer);
   wg_timers_any_authenticated_packet_traversal (peer);
@@ -226,11 +246,12 @@ wg_send_handshake_response (vlib_main_t * vm, wg_peer_t * peer)
          peer->last_sent_handshake = vlib_time_now (vm);
 
          u32 bi0 = 0;
          peer->last_sent_handshake = vlib_time_now (vm);
 
          u32 bi0 = 0;
-         if (!wg_create_buffer (vm, peer, (u8 *) & packet,
-                                sizeof (packet), &bi0))
+         u8 is_ip4 = ip46_address_is_ip4 (&peer->dst.addr);
+         if (!wg_create_buffer (vm, peer, (u8 *) &packet, sizeof (packet),
+                                &bi0, is_ip4))
            return false;
 
            return false;
 
-         ip46_enqueue_packet (vm, bi0, false);
+         ip46_enqueue_packet (vm, bi0, is_ip4);
        }
       else
        return false;
        }
       else
        return false;
index 96c1bc0..65ebd8d 100755 (executable)
@@ -9,6 +9,7 @@ from scapy.packet import Packet
 from scapy.packet import Raw
 from scapy.layers.l2 import Ether, ARP
 from scapy.layers.inet import IP, UDP
 from scapy.packet import Raw
 from scapy.layers.l2 import Ether, ARP
 from scapy.layers.inet import IP, UDP
+from scapy.layers.inet6 import IPv6
 from scapy.contrib.wireguard import Wireguard, WireguardResponse, \
     WireguardInitiation, WireguardTransport
 from cryptography.hazmat.primitives.asymmetric.x25519 import \
 from scapy.contrib.wireguard import Wireguard, WireguardResponse, \
     WireguardInitiation, WireguardTransport
 from cryptography.hazmat.primitives.asymmetric.x25519 import \
@@ -98,8 +99,8 @@ class VppWgInterface(VppInterface):
         return "wireguard-%d" % self._sw_if_index
 
 
         return "wireguard-%d" % self._sw_if_index
 
 
-def find_route(test, prefix, table_id=0):
-    routes = test.vapi.ip_route_dump(table_id, False)
+def find_route(test, prefix, is_ip6, table_id=0):
+    routes = test.vapi.ip_route_dump(table_id, is_ip6)
 
     for e in routes:
         if table_id == e.route.table_id \
 
     for e in routes:
         if table_id == e.route.table_id \
@@ -134,7 +135,7 @@ class VppWgPeer(VppObject):
 
         self.noise = NoiseConnection.from_name(NOISE_HANDSHAKE_NAME)
 
 
         self.noise = NoiseConnection.from_name(NOISE_HANDSHAKE_NAME)
 
-    def add_vpp_config(self):
+    def add_vpp_config(self, is_ip6=False):
         rv = self._test.vapi.wireguard_peer_add(
             peer={
                 'public_key': self.public_key_bytes(),
         rv = self._test.vapi.wireguard_peer_add(
             peer={
                 'public_key': self.public_key_bytes(),
@@ -179,10 +180,15 @@ class VppWgPeer(VppObject):
     def set_responder(self):
         self.noise.set_as_responder()
 
     def set_responder(self):
         self.noise.set_as_responder()
 
-    def mk_tunnel_header(self, tx_itf):
-        return (Ether(dst=tx_itf.local_mac, src=tx_itf.remote_mac) /
-                IP(src=self.endpoint, dst=self.itf.src) /
-                UDP(sport=self.port, dport=self.itf.port))
+    def mk_tunnel_header(self, tx_itf, is_ip6=False):
+        if is_ip6 is False:
+            return (Ether(dst=tx_itf.local_mac, src=tx_itf.remote_mac) /
+                    IP(src=self.endpoint, dst=self.itf.src) /
+                    UDP(sport=self.port, dport=self.itf.port))
+        else:
+            return (Ether(dst=tx_itf.local_mac, src=tx_itf.remote_mac) /
+                    IPv6(src=self.endpoint, dst=self.itf.src) /
+                    UDP(sport=self.port, dport=self.itf.port))
 
     def noise_init(self, public_key=None):
         self.noise.set_prologue(NOISE_IDENTIFIER_NAME)
 
     def noise_init(self, public_key=None):
         self.noise.set_prologue(NOISE_IDENTIFIER_NAME)
@@ -202,7 +208,7 @@ class VppWgPeer(VppObject):
 
         self.noise.start_handshake()
 
 
         self.noise.start_handshake()
 
-    def mk_handshake(self, tx_itf, public_key=None):
+    def mk_handshake(self, tx_itf, is_ip6=False, public_key=None):
         self.noise.set_as_initiator()
         self.noise_init(public_key)
 
         self.noise.set_as_initiator()
         self.noise_init(public_key)
 
@@ -232,21 +238,25 @@ class VppWgPeer(VppObject):
                                               key=mac_key).digest()
         p[WireguardInitiation].mac2 = bytearray(16)
 
                                               key=mac_key).digest()
         p[WireguardInitiation].mac2 = bytearray(16)
 
-        p = (self.mk_tunnel_header(tx_itf) / p)
+        p = (self.mk_tunnel_header(tx_itf, is_ip6) / p)
 
         return p
 
 
         return p
 
-    def verify_header(self, p):
-        self._test.assertEqual(p[IP].src, self.itf.src)
-        self._test.assertEqual(p[IP].dst, self.endpoint)
+    def verify_header(self, p, is_ip6=False):
+        if is_ip6 is False:
+            self._test.assertEqual(p[IP].src, self.itf.src)
+            self._test.assertEqual(p[IP].dst, self.endpoint)
+        else:
+            self._test.assertEqual(p[IPv6].src, self.itf.src)
+            self._test.assertEqual(p[IPv6].dst, self.endpoint)
         self._test.assertEqual(p[UDP].sport, self.itf.port)
         self._test.assertEqual(p[UDP].dport, self.port)
         self._test.assert_packet_checksums_valid(p)
 
         self._test.assertEqual(p[UDP].sport, self.itf.port)
         self._test.assertEqual(p[UDP].dport, self.port)
         self._test.assert_packet_checksums_valid(p)
 
-    def consume_init(self, p, tx_itf):
+    def consume_init(self, p, tx_itf, is_ip6=False):
         self.noise.set_as_responder()
         self.noise_init(self.itf.public_key)
         self.noise.set_as_responder()
         self.noise_init(self.itf.public_key)
-        self.verify_header(p)
+        self.verify_header(p, is_ip6)
 
         init = Wireguard(p[Raw])
 
 
         init = Wireguard(p[Raw])
 
@@ -281,13 +291,13 @@ class VppWgPeer(VppObject):
                        key=mac_key).digest()
         resp[WireguardResponse].mac1 = mac1
 
                        key=mac_key).digest()
         resp[WireguardResponse].mac1 = mac1
 
-        resp = (self.mk_tunnel_header(tx_itf) / resp)
+        resp = (self.mk_tunnel_header(tx_itf, is_ip6) / resp)
         self._test.assertTrue(self.noise.handshake_finished)
 
         return resp
 
         self._test.assertTrue(self.noise.handshake_finished)
 
         return resp
 
-    def consume_response(self, p):
-        self.verify_header(p)
+    def consume_response(self, p, is_ip6=False):
+        self.verify_header(p, is_ip6)
 
         resp = Wireguard(p[Raw])
 
 
         resp = Wireguard(p[Raw])
 
@@ -302,8 +312,8 @@ class VppWgPeer(VppObject):
         self._test.assertEqual(payload, b'')
         self._test.assertTrue(self.noise.handshake_finished)
 
         self._test.assertEqual(payload, b'')
         self._test.assertTrue(self.noise.handshake_finished)
 
-    def decrypt_transport(self, p):
-        self.verify_header(p)
+    def decrypt_transport(self, p, is_ip6=False):
+        self.verify_header(p, is_ip6)
 
         p = Wireguard(p[Raw])
         self._test.assertEqual(p[Wireguard].message_type, 4)
 
         p = Wireguard(p[Raw])
         self._test.assertEqual(p[Wireguard].message_type, 4)
@@ -318,13 +328,20 @@ class VppWgPeer(VppObject):
     def encrypt_transport(self, p):
         return self.noise.encrypt(bytes(p))
 
     def encrypt_transport(self, p):
         return self.noise.encrypt(bytes(p))
 
-    def validate_encapped(self, rxs, tx):
+    def validate_encapped(self, rxs, tx, is_ip6=False):
         for rx in rxs:
         for rx in rxs:
-            rx = IP(self.decrypt_transport(rx))
+            if is_ip6 is False:
+                rx = IP(self.decrypt_transport(rx))
 
 
-            # chech the oringial packet is present
-            self._test.assertEqual(rx[IP].dst, tx[IP].dst)
-            self._test.assertEqual(rx[IP].ttl, tx[IP].ttl-1)
+                # chech the oringial packet is present
+                self._test.assertEqual(rx[IP].dst, tx[IP].dst)
+                self._test.assertEqual(rx[IP].ttl, tx[IP].ttl-1)
+            else:
+                rx = IPv6(self.decrypt_transport(rx))
+
+                # chech the oringial packet is present
+                self._test.assertEqual(rx[IPv6].dst, tx[IPv6].dst)
+                self._test.assertEqual(rx[IPv6].ttl, tx[IPv6].ttl-1)
 
 
 class TestWg(VppTestCase):
 
 
 class TestWg(VppTestCase):
@@ -332,6 +349,17 @@ class TestWg(VppTestCase):
 
     error_str = compile(r"Error")
 
 
     error_str = compile(r"Error")
 
+    wg4_output_node_name = '/err/wg4-output-tun/'
+    wg4_input_node_name = '/err/wg4-input/'
+    wg6_output_node_name = '/err/wg6-output-tun/'
+    wg6_input_node_name = '/err/wg6-input/'
+    kp4_error = wg4_output_node_name + "Keypair error"
+    mac4_error = wg4_input_node_name + "Invalid MAC handshake"
+    peer4_error = wg4_input_node_name + "Peer error"
+    kp6_error = wg6_output_node_name + "Keypair error"
+    mac6_error = wg6_input_node_name + "Invalid MAC handshake"
+    peer6_error = wg6_input_node_name + "Peer error"
+
     @classmethod
     def setUpClass(cls):
         super(TestWg, cls).setUpClass()
     @classmethod
     def setUpClass(cls):
         super(TestWg, cls).setUpClass()
@@ -340,7 +368,9 @@ class TestWg(VppTestCase):
             for i in cls.pg_interfaces:
                 i.admin_up()
                 i.config_ip4()
             for i in cls.pg_interfaces:
                 i.admin_up()
                 i.config_ip4()
+                i.config_ip6()
                 i.resolve_arp()
                 i.resolve_arp()
+                i.resolve_ndp()
 
         except Exception:
             super(TestWg, cls).tearDownClass()
 
         except Exception:
             super(TestWg, cls).tearDownClass()
@@ -350,6 +380,15 @@ class TestWg(VppTestCase):
     def tearDownClass(cls):
         super(TestWg, cls).tearDownClass()
 
     def tearDownClass(cls):
         super(TestWg, cls).tearDownClass()
 
+    def setUp(self):
+        super(VppTestCase, self).setUp()
+        self.base_kp4_err = self.statistics.get_err_counter(self.kp4_error)
+        self.base_mac4_err = self.statistics.get_err_counter(self.mac4_error)
+        self.base_peer4_err = self.statistics.get_err_counter(self.peer4_error)
+        self.base_kp6_err = self.statistics.get_err_counter(self.kp6_error)
+        self.base_mac6_err = self.statistics.get_err_counter(self.mac6_error)
+        self.base_peer6_err = self.statistics.get_err_counter(self.peer6_error)
+
     def test_wg_interface(self):
         """ Simple interface creation """
         port = 12312
     def test_wg_interface(self):
         """ Simple interface creation """
         port = 12312
@@ -409,9 +448,6 @@ class TestWg(VppTestCase):
 
     def test_wg_peer_resp(self):
         """ Send handshake response """
 
     def test_wg_peer_resp(self):
         """ Send handshake response """
-        wg_output_node_name = '/err/wg-output-tun/'
-        wg_input_node_name = '/err/wg-input/'
-
         port = 12323
 
         # Create interfaces
         port = 12323
 
         # Create interfaces
@@ -481,10 +517,8 @@ class TestWg(VppTestCase):
         peer_1.remove_vpp_config()
         wg0.remove_vpp_config()
 
         peer_1.remove_vpp_config()
         wg0.remove_vpp_config()
 
-    def test_wg_peer_init(self):
-        """ Send handshake init """
-        wg_output_node_name = '/err/wg-output-tun/'
-        wg_input_node_name = '/err/wg-input/'
+    def test_wg_peer_v4o4(self):
+        """ Test v4o4"""
 
         port = 12333
 
 
         port = 12333
 
@@ -514,23 +548,23 @@ class TestWg(VppTestCase):
              UDP(sport=555, dport=556) /
              Raw())
         self.send_and_assert_no_replies(self.pg0, [p])
              UDP(sport=555, dport=556) /
              Raw())
         self.send_and_assert_no_replies(self.pg0, [p])
-
-        kp_error = wg_output_node_name + "Keypair error"
-        self.assertEqual(1, self.statistics.get_err_counter(kp_error))
+        self.assertEqual(self.base_kp4_err + 1,
+                         self.statistics.get_err_counter(self.kp4_error))
 
         # send a handsake from the peer with an invalid MAC
         p = peer_1.mk_handshake(self.pg1)
         p[WireguardInitiation].mac1 = b'foobar'
         self.send_and_assert_no_replies(self.pg1, [p])
 
         # send a handsake from the peer with an invalid MAC
         p = peer_1.mk_handshake(self.pg1)
         p[WireguardInitiation].mac1 = b'foobar'
         self.send_and_assert_no_replies(self.pg1, [p])
-        self.assertEqual(1, self.statistics.get_err_counter(
-            wg_input_node_name + "Invalid MAC handshake"))
+        self.assertEqual(self.base_mac4_err + 1,
+                         self.statistics.get_err_counter(self.mac4_error))
 
         # send a handsake from the peer but signed by the wrong key.
         p = peer_1.mk_handshake(self.pg1,
 
         # send a handsake from the peer but signed by the wrong key.
         p = peer_1.mk_handshake(self.pg1,
+                                False,
                                 X25519PrivateKey.generate().public_key())
         self.send_and_assert_no_replies(self.pg1, [p])
                                 X25519PrivateKey.generate().public_key())
         self.send_and_assert_no_replies(self.pg1, [p])
-        self.assertEqual(1, self.statistics.get_err_counter(
-            wg_input_node_name + "Peer error"))
+        self.assertEqual(self.base_peer4_err + 1,
+                         self.statistics.get_err_counter(self.peer4_error))
 
         # send a valid handsake init for which we expect a response
         p = peer_1.mk_handshake(self.pg1)
 
         # send a valid handsake init for which we expect a response
         p = peer_1.mk_handshake(self.pg1)
@@ -546,7 +580,8 @@ class TestWg(VppTestCase):
              UDP(sport=555, dport=556) /
              Raw())
         self.send_and_assert_no_replies(self.pg0, [p])
              UDP(sport=555, dport=556) /
              Raw())
         self.send_and_assert_no_replies(self.pg0, [p])
-        self.assertEqual(2, self.statistics.get_err_counter(kp_error))
+        self.assertEqual(self.base_kp4_err + 2,
+                         self.statistics.get_err_counter(self.kp4_error))
 
         # send a data packet from the peer through the tunnel
         # this completes the handshake
 
         # send a data packet from the peer through the tunnel
         # this completes the handshake
@@ -602,9 +637,373 @@ class TestWg(VppTestCase):
         peer_1.remove_vpp_config()
         wg0.remove_vpp_config()
 
         peer_1.remove_vpp_config()
         wg0.remove_vpp_config()
 
+    def test_wg_peer_v6o6(self):
+        """ Test v6o6"""
+
+        port = 12343
+
+        # Create interfaces
+        wg0 = VppWgInterface(self,
+                             self.pg1.local_ip6,
+                             port).add_vpp_config()
+        wg0.admin_up()
+        wg0.config_ip6()
+
+        peer_1 = VppWgPeer(self,
+                           wg0,
+                           self.pg1.remote_ip6,
+                           port+1,
+                           ["1::3:0/112"]).add_vpp_config(True)
+        self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
+
+        r1 = VppIpRoute(self, "1::3:0", 112,
+                        [VppRoutePath("1::3:1",
+                                      wg0.sw_if_index)]).add_vpp_config()
+
+        # route a packet into the wg interface
+        #  use the allowed-ip prefix
+        #  this is dropped because the peer is not initiated
+
+        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
+             IPv6(src=self.pg0.remote_ip6, dst="1::3:2") /
+             UDP(sport=555, dport=556) /
+             Raw())
+        self.send_and_assert_no_replies(self.pg0, [p])
+
+        self.assertEqual(self.base_kp6_err + 1,
+                         self.statistics.get_err_counter(self.kp6_error))
+
+        # send a handsake from the peer with an invalid MAC
+        p = peer_1.mk_handshake(self.pg1, True)
+        p[WireguardInitiation].mac1 = b'foobar'
+        self.send_and_assert_no_replies(self.pg1, [p])
+
+        self.assertEqual(self.base_mac6_err + 1,
+                         self.statistics.get_err_counter(self.mac6_error))
+
+        # send a handsake from the peer but signed by the wrong key.
+        p = peer_1.mk_handshake(self.pg1,
+                                True,
+                                X25519PrivateKey.generate().public_key())
+        self.send_and_assert_no_replies(self.pg1, [p])
+        self.assertEqual(self.base_peer6_err + 1,
+                         self.statistics.get_err_counter(self.peer6_error))
+
+        # send a valid handsake init for which we expect a response
+        p = peer_1.mk_handshake(self.pg1, True)
+
+        rx = self.send_and_expect(self.pg1, [p], self.pg1)
+
+        peer_1.consume_response(rx[0], True)
+
+        # route a packet into the wg interface
+        #  this is dropped because the peer is still not initiated
+        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
+             IPv6(src=self.pg0.remote_ip6, dst="1::3:2") /
+             UDP(sport=555, dport=556) /
+             Raw())
+        self.send_and_assert_no_replies(self.pg0, [p])
+        self.assertEqual(self.base_kp6_err + 2,
+                         self.statistics.get_err_counter(self.kp6_error))
+
+        # send a data packet from the peer through the tunnel
+        # this completes the handshake
+        p = (IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20) /
+             UDP(sport=222, dport=223) /
+             Raw())
+        d = peer_1.encrypt_transport(p)
+        p = (peer_1.mk_tunnel_header(self.pg1, True) /
+             (Wireguard(message_type=4, reserved_zero=0) /
+              WireguardTransport(receiver_index=peer_1.sender,
+                                 counter=0,
+                                 encrypted_encapsulated_packet=d)))
+        rxs = self.send_and_expect(self.pg1, [p], self.pg0)
+
+        for rx in rxs:
+            self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
+            self.assertEqual(rx[IPv6].hlim, 19)
+
+        # send a packets that are routed into the tunnel
+        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
+             IPv6(src=self.pg0.remote_ip6, dst="1::3:2") /
+             UDP(sport=555, dport=556) /
+             Raw(b'\x00' * 80))
+
+        rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
+
+        for rx in rxs:
+            rx = IPv6(peer_1.decrypt_transport(rx, True))
+
+            # chech the oringial packet is present
+            self.assertEqual(rx[IPv6].dst, p[IPv6].dst)
+            self.assertEqual(rx[IPv6].hlim, p[IPv6].hlim-1)
+
+        # send packets into the tunnel, expect to receive them on
+        # the other side
+        p = [(peer_1.mk_tunnel_header(self.pg1, True) /
+              Wireguard(message_type=4, reserved_zero=0) /
+              WireguardTransport(
+                  receiver_index=peer_1.sender,
+                  counter=ii+1,
+                  encrypted_encapsulated_packet=peer_1.encrypt_transport(
+                      (IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20) /
+                       UDP(sport=222, dport=223) /
+                       Raw())))) for ii in range(255)]
+
+        rxs = self.send_and_expect(self.pg1, p, self.pg0)
+
+        for rx in rxs:
+            self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
+            self.assertEqual(rx[IPv6].hlim, 19)
+
+        r1.remove_vpp_config()
+        peer_1.remove_vpp_config()
+        wg0.remove_vpp_config()
+
+    def test_wg_peer_v6o4(self):
+        """ Test v6o4"""
+
+        port = 12353
+
+        # Create interfaces
+        wg0 = VppWgInterface(self,
+                             self.pg1.local_ip4,
+                             port).add_vpp_config()
+        wg0.admin_up()
+        wg0.config_ip6()
+
+        peer_1 = VppWgPeer(self,
+                           wg0,
+                           self.pg1.remote_ip4,
+                           port+1,
+                           ["1::3:0/112"]).add_vpp_config(True)
+        self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
+
+        r1 = VppIpRoute(self, "1::3:0", 112,
+                        [VppRoutePath("1::3:1",
+                                      wg0.sw_if_index)]).add_vpp_config()
+
+        # route a packet into the wg interface
+        #  use the allowed-ip prefix
+        #  this is dropped because the peer is not initiated
+        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
+             IPv6(src=self.pg0.remote_ip6, dst="1::3:2") /
+             UDP(sport=555, dport=556) /
+             Raw())
+        self.send_and_assert_no_replies(self.pg0, [p])
+        self.assertEqual(self.base_kp6_err + 1,
+                         self.statistics.get_err_counter(self.kp6_error))
+
+        # send a handsake from the peer with an invalid MAC
+        p = peer_1.mk_handshake(self.pg1)
+        p[WireguardInitiation].mac1 = b'foobar'
+        self.send_and_assert_no_replies(self.pg1, [p])
+
+        self.assertEqual(self.base_mac4_err + 1,
+                         self.statistics.get_err_counter(self.mac4_error))
+
+        # send a handsake from the peer but signed by the wrong key.
+        p = peer_1.mk_handshake(self.pg1,
+                                False,
+                                X25519PrivateKey.generate().public_key())
+        self.send_and_assert_no_replies(self.pg1, [p])
+        self.assertEqual(self.base_peer4_err + 1,
+                         self.statistics.get_err_counter(self.peer4_error))
+
+        # send a valid handsake init for which we expect a response
+        p = peer_1.mk_handshake(self.pg1)
+
+        rx = self.send_and_expect(self.pg1, [p], self.pg1)
+
+        peer_1.consume_response(rx[0])
+
+        # route a packet into the wg interface
+        #  this is dropped because the peer is still not initiated
+        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
+             IPv6(src=self.pg0.remote_ip6, dst="1::3:2") /
+             UDP(sport=555, dport=556) /
+             Raw())
+        self.send_and_assert_no_replies(self.pg0, [p])
+        self.assertEqual(self.base_kp6_err + 2,
+                         self.statistics.get_err_counter(self.kp6_error))
+
+        # send a data packet from the peer through the tunnel
+        # this completes the handshake
+        p = (IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20) /
+             UDP(sport=222, dport=223) /
+             Raw())
+        d = peer_1.encrypt_transport(p)
+        p = (peer_1.mk_tunnel_header(self.pg1) /
+             (Wireguard(message_type=4, reserved_zero=0) /
+              WireguardTransport(receiver_index=peer_1.sender,
+                                 counter=0,
+                                 encrypted_encapsulated_packet=d)))
+        rxs = self.send_and_expect(self.pg1, [p], self.pg0)
+
+        for rx in rxs:
+            self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
+            self.assertEqual(rx[IPv6].hlim, 19)
+
+        # send a packets that are routed into the tunnel
+        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
+             IPv6(src=self.pg0.remote_ip6, dst="1::3:2") /
+             UDP(sport=555, dport=556) /
+             Raw(b'\x00' * 80))
+
+        rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
+
+        for rx in rxs:
+            rx = IPv6(peer_1.decrypt_transport(rx))
+
+            # chech the oringial packet is present
+            self.assertEqual(rx[IPv6].dst, p[IPv6].dst)
+            self.assertEqual(rx[IPv6].hlim, p[IPv6].hlim-1)
+
+        # send packets into the tunnel, expect to receive them on
+        # the other side
+        p = [(peer_1.mk_tunnel_header(self.pg1) /
+              Wireguard(message_type=4, reserved_zero=0) /
+              WireguardTransport(
+                  receiver_index=peer_1.sender,
+                  counter=ii+1,
+                  encrypted_encapsulated_packet=peer_1.encrypt_transport(
+                      (IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20) /
+                       UDP(sport=222, dport=223) /
+                       Raw())))) for ii in range(255)]
+
+        rxs = self.send_and_expect(self.pg1, p, self.pg0)
+
+        for rx in rxs:
+            self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
+            self.assertEqual(rx[IPv6].hlim, 19)
+
+        r1.remove_vpp_config()
+        peer_1.remove_vpp_config()
+        wg0.remove_vpp_config()
+
+    def test_wg_peer_v4o6(self):
+        """ Test v4o6"""
+
+        port = 12363
+
+        # Create interfaces
+        wg0 = VppWgInterface(self,
+                             self.pg1.local_ip6,
+                             port).add_vpp_config()
+        wg0.admin_up()
+        wg0.config_ip4()
+
+        peer_1 = VppWgPeer(self,
+                           wg0,
+                           self.pg1.remote_ip6,
+                           port+1,
+                           ["10.11.3.0/24"]).add_vpp_config()
+        self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
+
+        r1 = VppIpRoute(self, "10.11.3.0", 24,
+                        [VppRoutePath("10.11.3.1",
+                                      wg0.sw_if_index)]).add_vpp_config()
+
+        # route a packet into the wg interface
+        #  use the allowed-ip prefix
+        #  this is dropped because the peer is not initiated
+        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
+             IP(src=self.pg0.remote_ip4, dst="10.11.3.2") /
+             UDP(sport=555, dport=556) /
+             Raw())
+        self.send_and_assert_no_replies(self.pg0, [p])
+        self.assertEqual(self.base_kp4_err + 1,
+                         self.statistics.get_err_counter(self.kp4_error))
+
+        # send a handsake from the peer with an invalid MAC
+        p = peer_1.mk_handshake(self.pg1, True)
+        p[WireguardInitiation].mac1 = b'foobar'
+        self.send_and_assert_no_replies(self.pg1, [p])
+        self.assertEqual(self.base_mac6_err + 1,
+                         self.statistics.get_err_counter(self.mac6_error))
+
+        # send a handsake from the peer but signed by the wrong key.
+        p = peer_1.mk_handshake(self.pg1,
+                                True,
+                                X25519PrivateKey.generate().public_key())
+        self.send_and_assert_no_replies(self.pg1, [p])
+        self.assertEqual(self.base_peer6_err + 1,
+                         self.statistics.get_err_counter(self.peer6_error))
+
+        # send a valid handsake init for which we expect a response
+        p = peer_1.mk_handshake(self.pg1, True)
+
+        rx = self.send_and_expect(self.pg1, [p], self.pg1)
+
+        peer_1.consume_response(rx[0], True)
+
+        # route a packet into the wg interface
+        #  this is dropped because the peer is still not initiated
+        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
+             IP(src=self.pg0.remote_ip4, dst="10.11.3.2") /
+             UDP(sport=555, dport=556) /
+             Raw())
+        self.send_and_assert_no_replies(self.pg0, [p])
+        self.assertEqual(self.base_kp4_err + 2,
+                         self.statistics.get_err_counter(self.kp4_error))
+
+        # send a data packet from the peer through the tunnel
+        # this completes the handshake
+        p = (IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20) /
+             UDP(sport=222, dport=223) /
+             Raw())
+        d = peer_1.encrypt_transport(p)
+        p = (peer_1.mk_tunnel_header(self.pg1, True) /
+             (Wireguard(message_type=4, reserved_zero=0) /
+              WireguardTransport(receiver_index=peer_1.sender,
+                                 counter=0,
+                                 encrypted_encapsulated_packet=d)))
+        rxs = self.send_and_expect(self.pg1, [p], self.pg0)
+
+        for rx in rxs:
+            self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
+            self.assertEqual(rx[IP].ttl, 19)
+
+        # send a packets that are routed into the tunnel
+        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
+             IP(src=self.pg0.remote_ip4, dst="10.11.3.2") /
+             UDP(sport=555, dport=556) /
+             Raw(b'\x00' * 80))
+
+        rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
+
+        for rx in rxs:
+            rx = IP(peer_1.decrypt_transport(rx, True))
+
+            # chech the oringial packet is present
+            self.assertEqual(rx[IP].dst, p[IP].dst)
+            self.assertEqual(rx[IP].ttl, p[IP].ttl-1)
+
+        # send packets into the tunnel, expect to receive them on
+        # the other side
+        p = [(peer_1.mk_tunnel_header(self.pg1, True) /
+              Wireguard(message_type=4, reserved_zero=0) /
+              WireguardTransport(
+                  receiver_index=peer_1.sender,
+                  counter=ii+1,
+                  encrypted_encapsulated_packet=peer_1.encrypt_transport(
+                      (IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20) /
+                       UDP(sport=222, dport=223) /
+                       Raw())))) for ii in range(255)]
+
+        rxs = self.send_and_expect(self.pg1, p, self.pg0)
+
+        for rx in rxs:
+            self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
+            self.assertEqual(rx[IP].ttl, 19)
+
+        r1.remove_vpp_config()
+        peer_1.remove_vpp_config()
+        wg0.remove_vpp_config()
+
     def test_wg_multi_peer(self):
         """ multiple peer setup """
     def test_wg_multi_peer(self):
         """ multiple peer setup """
-        port = 12343
+        port = 12373
 
         # Create interfaces
         wg0 = VppWgInterface(self,
 
         # Create interfaces
         wg0 = VppWgInterface(self,
@@ -784,10 +1183,8 @@ class WireguardHandoffTests(TestWg):
 
     def test_wg_peer_init(self):
         """ Handoff """
 
     def test_wg_peer_init(self):
         """ Handoff """
-        wg_output_node_name = '/err/wg-output-tun/'
-        wg_input_node_name = '/err/wg-input/'
 
 
-        port = 12353
+        port = 12383
 
         # Create interfaces
         wg0 = VppWgInterface(self,
 
         # Create interfaces
         wg0 = VppWgInterface(self,
@@ -844,14 +1241,14 @@ class WireguardHandoffTests(TestWg):
 
         # send packets into the tunnel, from the other worker
         p = [(peer_1.mk_tunnel_header(self.pg1) /
 
         # send packets into the tunnel, from the other worker
         p = [(peer_1.mk_tunnel_header(self.pg1) /
-              Wireguard(message_type=4, reserved_zero=0) /
-              WireguardTransport(
-                  receiver_index=peer_1.sender,
-                  counter=ii+1,
-                  encrypted_encapsulated_packet=peer_1.encrypt_transport(
-                      (IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20) /
-                       UDP(sport=222, dport=223) /
-                       Raw())))) for ii in range(255)]
+             Wireguard(message_type=4, reserved_zero=0) /
+             WireguardTransport(
+                 receiver_index=peer_1.sender,
+                 counter=ii+1,
+                 encrypted_encapsulated_packet=peer_1.encrypt_transport(
+                     (IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20) /
+                      UDP(sport=222, dport=223) /
+                      Raw())))) for ii in range(255)]
 
         rxs = self.send_and_expect(self.pg1, p, self.pg0, worker=1)
 
 
         rxs = self.send_and_expect(self.pg1, p, self.pg0, worker=1)