ipsec: Support MPLS over IPSec[46] interface 64/30664/6
authorNeale Ranns <nranns@cisco.com>
Mon, 21 Dec 2020 13:19:10 +0000 (13:19 +0000)
committerOle Tr�an <otroan@employees.org>
Mon, 18 Jan 2021 08:35:52 +0000 (08:35 +0000)
Type: feature

Signed-off-by: Neale Ranns <nranns@cisco.com>
Change-Id: I89dc3815eabfee135cd5b3c910dea5e2e2ef1333

13 files changed:
src/plugins/dpdk/ipsec/ipsec.c
src/vnet/ip/ip_punt_drop.c
src/vnet/ipsec/esp.h
src/vnet/ipsec/esp_decrypt.c
src/vnet/ipsec/esp_encrypt.c
src/vnet/ipsec/ipsec.c
src/vnet/ipsec/ipsec.h
src/vnet/ipsec/ipsec_handoff.c
src/vnet/ipsec/ipsec_tun.c
src/vnet/mpls/mpls_output.c
src/vnet/tunnel/tunnel_dp.h
test/patches/scapy-2.4.3/ipsec.patch
test/test_ipsec_tun_if_esp.py

index c7fd922..5d9e10b 100644 (file)
@@ -1063,19 +1063,12 @@ dpdk_ipsec_main_init (vlib_main_t * vm)
       return 0;
     }
 
       return 0;
     }
 
-
-  u32 idx = ipsec_register_esp_backend (vm, im, "dpdk backend",
-                                       "dpdk-esp4-encrypt",
-                                       "dpdk-esp4-encrypt-tun",
-                                       "dpdk-esp4-decrypt",
-                                       "dpdk-esp4-decrypt",
-                                       "dpdk-esp6-encrypt",
-                                       "dpdk-esp6-encrypt-tun",
-                                       "dpdk-esp6-decrypt",
-                                       "dpdk-esp6-decrypt",
-                                       dpdk_ipsec_check_support,
-                                       add_del_sa_session,
-                                       dpdk_ipsec_enable_disable);
+  u32 idx = ipsec_register_esp_backend (
+    vm, im, "dpdk backend", "dpdk-esp4-encrypt", "dpdk-esp4-encrypt-tun",
+    "dpdk-esp4-decrypt", "dpdk-esp4-decrypt", "dpdk-esp6-encrypt",
+    "dpdk-esp6-encrypt-tun", "dpdk-esp6-decrypt", "dpdk-esp6-decrypt",
+    "error-drop", dpdk_ipsec_check_support, add_del_sa_session,
+    dpdk_ipsec_enable_disable);
   int rv;
   if (im->esp_current_backend == ~0)
     {
   int rv;
   if (im->esp_current_backend == ~0)
     {
index ce1631f..f77a0ad 100644 (file)
@@ -15,8 +15,6 @@
 
 #include <vnet/ip/ip.h>
 #include <vnet/ip/ip_punt_drop.h>
 
 #include <vnet/ip/ip.h>
 #include <vnet/ip/ip_punt_drop.h>
-#include <vnet/policer/policer.h>
-#include <vnet/policer/police_inlines.h>
 #include <vnet/fib/fib_path_list.h>
 
 ip_punt_redirect_cfg_t ip_punt_redirect_cfg;
 #include <vnet/fib/fib_path_list.h>
 
 ip_punt_redirect_cfg_t ip_punt_redirect_cfg;
index 0121015..d24b5ea 100644 (file)
@@ -235,6 +235,7 @@ typedef struct
   u32 esp6_post_next;
   u32 esp4_tun_post_next;
   u32 esp6_tun_post_next;
   u32 esp6_post_next;
   u32 esp4_tun_post_next;
   u32 esp6_tun_post_next;
+  u32 esp_mpls_tun_post_next;
 } esp_async_post_next_t;
 
 extern esp_async_post_next_t esp_encrypt_async_next;
 } esp_async_post_next_t;
 
 extern esp_async_post_next_t esp_encrypt_async_next;
index 1390f80..f5b6232 100644 (file)
 
 #include <vnet/gre/packet.h>
 
 
 #include <vnet/gre/packet.h>
 
-#define foreach_esp_decrypt_next                \
-_(DROP, "error-drop")                           \
-_(IP4_INPUT, "ip4-input-no-checksum")           \
-_(IP6_INPUT, "ip6-input")                       \
-_(L2_INPUT, "l2-input")                         \
-_(HANDOFF, "handoff")
+#define foreach_esp_decrypt_next                                              \
+  _ (DROP, "error-drop")                                                      \
+  _ (IP4_INPUT, "ip4-input-no-checksum")                                      \
+  _ (IP6_INPUT, "ip6-input")                                                  \
+  _ (L2_INPUT, "l2-input")                                                    \
+  _ (MPLS_INPUT, "mpls-input")                                                \
+  _ (HANDOFF, "handoff")
 
 #define _(v, s) ESP_DECRYPT_NEXT_##v,
 typedef enum
 
 #define _(v, s) ESP_DECRYPT_NEXT_##v,
 typedef enum
@@ -42,11 +43,12 @@ typedef enum
     ESP_DECRYPT_N_NEXT,
 } esp_decrypt_next_t;
 
     ESP_DECRYPT_N_NEXT,
 } esp_decrypt_next_t;
 
-#define foreach_esp_decrypt_post_next                  \
-_(DROP, "error-drop")                                  \
-_(IP4_INPUT, "ip4-input-no-checksum")                  \
-_(IP6_INPUT, "ip6-input")                              \
-_(L2_INPUT, "l2-input")
+#define foreach_esp_decrypt_post_next                                         \
+  _ (DROP, "error-drop")                                                      \
+  _ (IP4_INPUT, "ip4-input-no-checksum")                                      \
+  _ (IP6_INPUT, "ip6-input")                                                  \
+  _ (MPLS_INPUT, "mpls-input")                                                \
+  _ (L2_INPUT, "l2-input")
 
 #define _(v, s) ESP_DECRYPT_POST_NEXT_##v,
 typedef enum
 
 #define _(v, s) ESP_DECRYPT_POST_NEXT_##v,
 typedef enum
@@ -913,6 +915,13 @@ esp_decrypt_post_crypto (vlib_main_t * vm, vlib_node_runtime_t * node,
          b->current_length = pd->current_length - adv;
          esp_remove_tail (vm, b, lb, tail);
        }
          b->current_length = pd->current_length - adv;
          esp_remove_tail (vm, b, lb, tail);
        }
+      else if (next_header == IP_PROTOCOL_MPLS_IN_IP)
+       {
+         next[0] = ESP_DECRYPT_NEXT_MPLS_INPUT;
+         b->current_data = pd->current_data + adv;
+         b->current_length = pd->current_length - adv;
+         esp_remove_tail (vm, b, lb, tail);
+       }
       else
        {
          if (is_tun && next_header == IP_PROTOCOL_GRE)
       else
        {
          if (is_tun && next_header == IP_PROTOCOL_GRE)
@@ -1457,6 +1466,7 @@ VLIB_REGISTER_NODE (esp4_decrypt_node) = {
     [ESP_DECRYPT_NEXT_DROP] = "ip4-drop",
     [ESP_DECRYPT_NEXT_IP4_INPUT] = "ip4-input-no-checksum",
     [ESP_DECRYPT_NEXT_IP6_INPUT] = "ip6-input",
     [ESP_DECRYPT_NEXT_DROP] = "ip4-drop",
     [ESP_DECRYPT_NEXT_IP4_INPUT] = "ip4-input-no-checksum",
     [ESP_DECRYPT_NEXT_IP6_INPUT] = "ip6-input",
+    [ESP_DECRYPT_NEXT_MPLS_INPUT] = "mpls-drop",
     [ESP_DECRYPT_NEXT_L2_INPUT] = "l2-input",
     [ESP_DECRYPT_NEXT_HANDOFF] = "esp4-decrypt-handoff",
   },
     [ESP_DECRYPT_NEXT_L2_INPUT] = "l2-input",
     [ESP_DECRYPT_NEXT_HANDOFF] = "esp4-decrypt-handoff",
   },
@@ -1488,6 +1498,7 @@ VLIB_REGISTER_NODE (esp6_decrypt_node) = {
     [ESP_DECRYPT_NEXT_DROP] = "ip6-drop",
     [ESP_DECRYPT_NEXT_IP4_INPUT] = "ip4-input-no-checksum",
     [ESP_DECRYPT_NEXT_IP6_INPUT] = "ip6-input",
     [ESP_DECRYPT_NEXT_DROP] = "ip6-drop",
     [ESP_DECRYPT_NEXT_IP4_INPUT] = "ip4-input-no-checksum",
     [ESP_DECRYPT_NEXT_IP6_INPUT] = "ip6-input",
+    [ESP_DECRYPT_NEXT_MPLS_INPUT] = "mpls-drop",
     [ESP_DECRYPT_NEXT_L2_INPUT] = "l2-input",
     [ESP_DECRYPT_NEXT_HANDOFF]=  "esp6-decrypt-handoff",
   },
     [ESP_DECRYPT_NEXT_L2_INPUT] = "l2-input",
     [ESP_DECRYPT_NEXT_HANDOFF]=  "esp6-decrypt-handoff",
   },
@@ -1517,6 +1528,7 @@ VLIB_REGISTER_NODE (esp4_decrypt_tun_node) = {
     [ESP_DECRYPT_NEXT_DROP] = "ip4-drop",
     [ESP_DECRYPT_NEXT_IP4_INPUT] = "ip4-input-no-checksum",
     [ESP_DECRYPT_NEXT_IP6_INPUT] = "ip6-input",
     [ESP_DECRYPT_NEXT_DROP] = "ip4-drop",
     [ESP_DECRYPT_NEXT_IP4_INPUT] = "ip4-input-no-checksum",
     [ESP_DECRYPT_NEXT_IP6_INPUT] = "ip6-input",
+    [ESP_DECRYPT_NEXT_MPLS_INPUT] = "mpls-input",
     [ESP_DECRYPT_NEXT_L2_INPUT] = "l2-input",
     [ESP_DECRYPT_NEXT_HANDOFF] = "esp4-decrypt-tun-handoff",
   },
     [ESP_DECRYPT_NEXT_L2_INPUT] = "l2-input",
     [ESP_DECRYPT_NEXT_HANDOFF] = "esp4-decrypt-tun-handoff",
   },
@@ -1546,6 +1558,7 @@ VLIB_REGISTER_NODE (esp6_decrypt_tun_node) = {
     [ESP_DECRYPT_NEXT_DROP] = "ip6-drop",
     [ESP_DECRYPT_NEXT_IP4_INPUT] = "ip4-input-no-checksum",
     [ESP_DECRYPT_NEXT_IP6_INPUT] = "ip6-input",
     [ESP_DECRYPT_NEXT_DROP] = "ip6-drop",
     [ESP_DECRYPT_NEXT_IP4_INPUT] = "ip4-input-no-checksum",
     [ESP_DECRYPT_NEXT_IP6_INPUT] = "ip6-input",
+    [ESP_DECRYPT_NEXT_MPLS_INPUT] = "mpls-input",
     [ESP_DECRYPT_NEXT_L2_INPUT] = "l2-input",
     [ESP_DECRYPT_NEXT_HANDOFF]=  "esp6-decrypt-tun-handoff",
   },
     [ESP_DECRYPT_NEXT_L2_INPUT] = "l2-input",
     [ESP_DECRYPT_NEXT_HANDOFF]=  "esp6-decrypt-tun-handoff",
   },
index a231694..bd6e764 100644 (file)
 #include <vnet/ipsec/esp.h>
 #include <vnet/tunnel/tunnel_dp.h>
 
 #include <vnet/ipsec/esp.h>
 #include <vnet/tunnel/tunnel_dp.h>
 
-#define foreach_esp_encrypt_next                   \
-_(DROP4, "ip4-drop")                               \
-_(DROP6, "ip6-drop")                               \
-_(HANDOFF4, "handoff4")                            \
-_(HANDOFF6, "handoff6")                            \
-_(INTERFACE_OUTPUT, "interface-output")
+#define foreach_esp_encrypt_next                                              \
+  _ (DROP4, "ip4-drop")                                                       \
+  _ (DROP6, "ip6-drop")                                                       \
+  _ (DROP_MPLS, "mpls-drop")                                                  \
+  _ (HANDOFF4, "handoff4")                                                    \
+  _ (HANDOFF6, "handoff6")                                                    \
+  _ (HANDOFF_MPLS, "handoff-mpls")                                            \
+  _ (INTERFACE_OUTPUT, "interface-output")
 
 #define _(v, s) ESP_ENCRYPT_NEXT_##v,
 typedef enum
 
 #define _(v, s) ESP_ENCRYPT_NEXT_##v,
 typedef enum
@@ -555,8 +557,8 @@ out:
 }
 
 always_inline uword
 }
 
 always_inline uword
-esp_encrypt_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
-                   vlib_frame_t * frame, int is_ip6, int is_tun,
+esp_encrypt_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
+                   vlib_frame_t *frame, vnet_link_t lt, int is_tun,
                    u16 async_next)
 {
   ipsec_main_t *im = &ipsec_main;
                    u16 async_next)
 {
   ipsec_main_t *im = &ipsec_main;
@@ -578,7 +580,14 @@ esp_encrypt_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
   vnet_crypto_async_frame_t *async_frame = 0;
   int is_async = im->async_mode;
   vnet_crypto_async_op_id_t last_async_op = ~0;
   vnet_crypto_async_frame_t *async_frame = 0;
   int is_async = im->async_mode;
   vnet_crypto_async_op_id_t last_async_op = ~0;
-  u16 drop_next = (is_ip6 ? ESP_ENCRYPT_NEXT_DROP6 : ESP_ENCRYPT_NEXT_DROP4);
+  u16 drop_next =
+    (lt == VNET_LINK_IP6 ? ESP_ENCRYPT_NEXT_DROP6 :
+                          (lt == VNET_LINK_IP4 ? ESP_ENCRYPT_NEXT_DROP4 :
+                                                 ESP_ENCRYPT_NEXT_DROP_MPLS));
+  u16 handoff_next = (lt == VNET_LINK_IP6 ?
+                       ESP_ENCRYPT_NEXT_HANDOFF6 :
+                       (lt == VNET_LINK_IP4 ? ESP_ENCRYPT_NEXT_HANDOFF4 :
+                                              ESP_ENCRYPT_NEXT_HANDOFF_MPLS));
   u16 n_async_drop = 0;
 
   vlib_get_buffers (vm, from, b, n_left);
   u16 n_async_drop = 0;
 
   vlib_get_buffers (vm, from, b, n_left);
@@ -672,9 +681,7 @@ esp_encrypt_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
       if (PREDICT_FALSE (thread_index != sa0->encrypt_thread_index))
        {
          esp_set_next_index (is_async, from, nexts, from[b - bufs],
       if (PREDICT_FALSE (thread_index != sa0->encrypt_thread_index))
        {
          esp_set_next_index (is_async, from, nexts, from[b - bufs],
-                             &n_async_drop,
-                             (is_ip6 ? ESP_ENCRYPT_NEXT_HANDOFF6 :
-                              ESP_ENCRYPT_NEXT_HANDOFF4), next);
+                             &n_async_drop, handoff_next, next);
          goto trace;
        }
 
          goto trace;
        }
 
@@ -746,20 +753,30 @@ esp_encrypt_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
              ip6 = (ip6_header_t *) (payload - hdr_len);
              clib_memcpy_fast (ip6, &sa0->ip6_hdr, sizeof (ip6_header_t));
 
              ip6 = (ip6_header_t *) (payload - hdr_len);
              clib_memcpy_fast (ip6, &sa0->ip6_hdr, sizeof (ip6_header_t));
 
-             if (is_ip6)
+             if (VNET_LINK_IP6 == lt)
                {
                  *next_hdr_ptr = IP_PROTOCOL_IPV6;
                  tunnel_encap_fixup_6o6 (sa0->tunnel_flags,
                                          (const ip6_header_t *) payload,
                                          ip6);
                }
                {
                  *next_hdr_ptr = IP_PROTOCOL_IPV6;
                  tunnel_encap_fixup_6o6 (sa0->tunnel_flags,
                                          (const ip6_header_t *) payload,
                                          ip6);
                }
-             else
+             else if (VNET_LINK_IP4 == lt)
                {
                  *next_hdr_ptr = IP_PROTOCOL_IP_IN_IP;
                  tunnel_encap_fixup_4o6 (sa0->tunnel_flags,
                                          (const ip4_header_t *) payload,
                                          ip6);
                }
                {
                  *next_hdr_ptr = IP_PROTOCOL_IP_IN_IP;
                  tunnel_encap_fixup_4o6 (sa0->tunnel_flags,
                                          (const ip4_header_t *) payload,
                                          ip6);
                }
+             else if (VNET_LINK_MPLS == lt)
+               {
+                 *next_hdr_ptr = IP_PROTOCOL_MPLS_IN_IP;
+                 tunnel_encap_fixup_mplso6 (
+                   sa0->tunnel_flags, (const mpls_unicast_header_t *) payload,
+                   ip6);
+               }
+             else
+               ASSERT (0);
+
              len = payload_len_total + hdr_len - len;
              ip6->payload_length = clib_net_to_host_u16 (len);
            }
              len = payload_len_total + hdr_len - len;
              ip6->payload_length = clib_net_to_host_u16 (len);
            }
@@ -771,20 +788,30 @@ esp_encrypt_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
              ip4 = (ip4_header_t *) (payload - hdr_len);
              clib_memcpy_fast (ip4, &sa0->ip4_hdr, sizeof (ip4_header_t));
 
              ip4 = (ip4_header_t *) (payload - hdr_len);
              clib_memcpy_fast (ip4, &sa0->ip4_hdr, sizeof (ip4_header_t));
 
-             if (is_ip6)
+             if (VNET_LINK_IP6 == lt)
                {
                  *next_hdr_ptr = IP_PROTOCOL_IPV6;
                  tunnel_encap_fixup_6o4_w_chksum (sa0->tunnel_flags,
                                                   (const ip6_header_t *)
                                                   payload, ip4);
                }
                {
                  *next_hdr_ptr = IP_PROTOCOL_IPV6;
                  tunnel_encap_fixup_6o4_w_chksum (sa0->tunnel_flags,
                                                   (const ip6_header_t *)
                                                   payload, ip4);
                }
-             else
+             else if (VNET_LINK_IP4 == lt)
                {
                  *next_hdr_ptr = IP_PROTOCOL_IP_IN_IP;
                  tunnel_encap_fixup_4o4_w_chksum (sa0->tunnel_flags,
                                                   (const ip4_header_t *)
                                                   payload, ip4);
                }
                {
                  *next_hdr_ptr = IP_PROTOCOL_IP_IN_IP;
                  tunnel_encap_fixup_4o4_w_chksum (sa0->tunnel_flags,
                                                   (const ip4_header_t *)
                                                   payload, ip4);
                }
+             else if (VNET_LINK_MPLS == lt)
+               {
+                 *next_hdr_ptr = IP_PROTOCOL_MPLS_IN_IP;
+                 tunnel_encap_fixup_mplso4_w_chksum (
+                   sa0->tunnel_flags, (const mpls_unicast_header_t *) payload,
+                   ip4);
+               }
+             else
+               ASSERT (0);
+
              len = payload_len_total + hdr_len;
              esp_update_ip4_hdr (ip4, len, /* is_transport */ 0, 0);
            }
              len = payload_len_total + hdr_len;
              esp_update_ip4_hdr (ip4, len, /* is_transport */ 0, 0);
            }
@@ -806,9 +833,10 @@ esp_encrypt_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
          u16 udp_len = 0;
          u8 *old_ip_hdr = vlib_buffer_get_current (b[0]);
 
          u16 udp_len = 0;
          u8 *old_ip_hdr = vlib_buffer_get_current (b[0]);
 
-         ip_len = is_ip6 ?
-           esp_get_ip6_hdr_len ((ip6_header_t *) old_ip_hdr, &ext_hdr) :
-           ip4_header_bytes ((ip4_header_t *) old_ip_hdr);
+         ip_len =
+           (VNET_LINK_IP6 == lt ?
+              esp_get_ip6_hdr_len ((ip6_header_t *) old_ip_hdr, &ext_hdr) :
+              ip4_header_bytes ((ip4_header_t *) old_ip_hdr));
 
          vlib_buffer_advance (b[0], ip_len);
          payload = vlib_buffer_get_current (b[0]);
 
          vlib_buffer_advance (b[0], ip_len);
          payload = vlib_buffer_get_current (b[0]);
@@ -856,7 +884,7 @@ esp_encrypt_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
          else
            l2_len = 0;
 
          else
            l2_len = 0;
 
-         if (is_ip6)
+         if (VNET_LINK_IP6 == lt)
            {
              ip6_header_t *ip6 = (ip6_header_t *) (old_ip_hdr);
              if (PREDICT_TRUE (NULL == ext_hdr))
            {
              ip6_header_t *ip6 = (ip6_header_t *) (old_ip_hdr);
              if (PREDICT_TRUE (NULL == ext_hdr))
@@ -873,7 +901,7 @@ esp_encrypt_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
                clib_host_to_net_u16 (payload_len_total + hdr_len - l2_len -
                                      sizeof (ip6_header_t));
            }
                clib_host_to_net_u16 (payload_len_total + hdr_len - l2_len -
                                      sizeof (ip6_header_t));
            }
-         else
+         else if (VNET_LINK_IP4 == lt)
            {
              u16 len;
              ip4_header_t *ip4 = (ip4_header_t *) (old_ip_hdr);
            {
              u16 len;
              ip4_header_t *ip4 = (ip4_header_t *) (old_ip_hdr);
@@ -1096,7 +1124,7 @@ VLIB_NODE_FN (esp4_encrypt_node) (vlib_main_t * vm,
                                  vlib_node_runtime_t * node,
                                  vlib_frame_t * from_frame)
 {
                                  vlib_node_runtime_t * node,
                                  vlib_frame_t * from_frame)
 {
-  return esp_encrypt_inline (vm, node, from_frame, 0 /* is_ip6 */ , 0,
+  return esp_encrypt_inline (vm, node, from_frame, VNET_LINK_IP4, 0,
                             esp_encrypt_async_next.esp4_post_next);
 }
 
                             esp_encrypt_async_next.esp4_post_next);
 }
 
@@ -1107,17 +1135,17 @@ VLIB_REGISTER_NODE (esp4_encrypt_node) = {
   .format_trace = format_esp_encrypt_trace,
   .type = VLIB_NODE_TYPE_INTERNAL,
 
   .format_trace = format_esp_encrypt_trace,
   .type = VLIB_NODE_TYPE_INTERNAL,
 
-  .n_errors = ARRAY_LEN(esp_encrypt_error_strings),
+  .n_errors = ARRAY_LEN (esp_encrypt_error_strings),
   .error_strings = esp_encrypt_error_strings,
 
   .n_next_nodes = ESP_ENCRYPT_N_NEXT,
   .error_strings = esp_encrypt_error_strings,
 
   .n_next_nodes = ESP_ENCRYPT_N_NEXT,
-  .next_nodes = {
-    [ESP_ENCRYPT_NEXT_DROP4] = "ip4-drop",
-    [ESP_ENCRYPT_NEXT_DROP6] = "ip6-drop",
-    [ESP_ENCRYPT_NEXT_HANDOFF4] = "esp4-encrypt-handoff",
-    [ESP_ENCRYPT_NEXT_HANDOFF6] = "esp6-encrypt-handoff",
-    [ESP_ENCRYPT_NEXT_INTERFACE_OUTPUT] = "interface-output"
-  },
+  .next_nodes = { [ESP_ENCRYPT_NEXT_DROP4] = "ip4-drop",
+                 [ESP_ENCRYPT_NEXT_DROP6] = "ip6-drop",
+                 [ESP_ENCRYPT_NEXT_DROP_MPLS] = "mpls-drop",
+                 [ESP_ENCRYPT_NEXT_HANDOFF4] = "esp4-encrypt-handoff",
+                 [ESP_ENCRYPT_NEXT_HANDOFF6] = "esp6-encrypt-handoff",
+                 [ESP_ENCRYPT_NEXT_HANDOFF_MPLS] = "error-drop",
+                 [ESP_ENCRYPT_NEXT_INTERFACE_OUTPUT] = "interface-output" },
 };
 /* *INDENT-ON* */
 
 };
 /* *INDENT-ON* */
 
@@ -1145,7 +1173,7 @@ VLIB_NODE_FN (esp6_encrypt_node) (vlib_main_t * vm,
                                  vlib_node_runtime_t * node,
                                  vlib_frame_t * from_frame)
 {
                                  vlib_node_runtime_t * node,
                                  vlib_frame_t * from_frame)
 {
-  return esp_encrypt_inline (vm, node, from_frame, 1 /* is_ip6 */ , 0,
+  return esp_encrypt_inline (vm, node, from_frame, VNET_LINK_IP6, 0,
                             esp_encrypt_async_next.esp6_post_next);
 }
 
                             esp_encrypt_async_next.esp6_post_next);
 }
 
@@ -1186,7 +1214,7 @@ VLIB_NODE_FN (esp4_encrypt_tun_node) (vlib_main_t * vm,
                                      vlib_node_runtime_t * node,
                                      vlib_frame_t * from_frame)
 {
                                      vlib_node_runtime_t * node,
                                      vlib_frame_t * from_frame)
 {
-  return esp_encrypt_inline (vm, node, from_frame, 0 /* is_ip6 */ , 1,
+  return esp_encrypt_inline (vm, node, from_frame, VNET_LINK_IP4, 1,
                             esp_encrypt_async_next.esp4_tun_post_next);
 }
 
                             esp_encrypt_async_next.esp4_tun_post_next);
 }
 
@@ -1204,8 +1232,10 @@ VLIB_REGISTER_NODE (esp4_encrypt_tun_node) = {
   .next_nodes = {
     [ESP_ENCRYPT_NEXT_DROP4] = "ip4-drop",
     [ESP_ENCRYPT_NEXT_DROP6] = "ip6-drop",
   .next_nodes = {
     [ESP_ENCRYPT_NEXT_DROP4] = "ip4-drop",
     [ESP_ENCRYPT_NEXT_DROP6] = "ip6-drop",
+    [ESP_ENCRYPT_NEXT_DROP_MPLS] = "mpls-drop",
     [ESP_ENCRYPT_NEXT_HANDOFF4] = "esp4-encrypt-tun-handoff",
     [ESP_ENCRYPT_NEXT_HANDOFF4] = "esp4-encrypt-tun-handoff",
-    [ESP_ENCRYPT_NEXT_HANDOFF6] = "error-drop",
+    [ESP_ENCRYPT_NEXT_HANDOFF6] = "esp6-encrypt-tun-handoff",
+    [ESP_ENCRYPT_NEXT_HANDOFF_MPLS] = "esp-mpls-encrypt-tun-handoff",
     [ESP_ENCRYPT_NEXT_INTERFACE_OUTPUT] = "adj-midchain-tx",
   },
 };
     [ESP_ENCRYPT_NEXT_INTERFACE_OUTPUT] = "adj-midchain-tx",
   },
 };
@@ -1234,7 +1264,7 @@ VLIB_NODE_FN (esp6_encrypt_tun_node) (vlib_main_t * vm,
                                      vlib_node_runtime_t * node,
                                      vlib_frame_t * from_frame)
 {
                                      vlib_node_runtime_t * node,
                                      vlib_frame_t * from_frame)
 {
-  return esp_encrypt_inline (vm, node, from_frame, 1 /* is_ip6 */ , 1,
+  return esp_encrypt_inline (vm, node, from_frame, VNET_LINK_IP6, 1,
                             esp_encrypt_async_next.esp6_tun_post_next);
 }
 
                             esp_encrypt_async_next.esp6_tun_post_next);
 }
 
@@ -1252,8 +1282,10 @@ VLIB_REGISTER_NODE (esp6_encrypt_tun_node) = {
   .next_nodes = {
     [ESP_ENCRYPT_NEXT_DROP4] = "ip4-drop",
     [ESP_ENCRYPT_NEXT_DROP6] = "ip6-drop",
   .next_nodes = {
     [ESP_ENCRYPT_NEXT_DROP4] = "ip4-drop",
     [ESP_ENCRYPT_NEXT_DROP6] = "ip6-drop",
-    [ESP_ENCRYPT_NEXT_HANDOFF4] = "error-drop",
+    [ESP_ENCRYPT_NEXT_DROP_MPLS] = "mpls-drop",
+    [ESP_ENCRYPT_NEXT_HANDOFF4] = "esp4-encrypt-tun-handoff",
     [ESP_ENCRYPT_NEXT_HANDOFF6] = "esp6-encrypt-tun-handoff",
     [ESP_ENCRYPT_NEXT_HANDOFF6] = "esp6-encrypt-tun-handoff",
+    [ESP_ENCRYPT_NEXT_HANDOFF_MPLS] = "esp-mpls-encrypt-tun-handoff",
     [ESP_ENCRYPT_NEXT_INTERFACE_OUTPUT] = "adj-midchain-tx",
   },
 };
     [ESP_ENCRYPT_NEXT_INTERFACE_OUTPUT] = "adj-midchain-tx",
   },
 };
@@ -1273,13 +1305,58 @@ VLIB_REGISTER_NODE (esp6_encrypt_tun_post_node) = {
   .vector_size = sizeof (u32),
   .format_trace = format_esp_post_encrypt_trace,
   .type = VLIB_NODE_TYPE_INTERNAL,
   .vector_size = sizeof (u32),
   .format_trace = format_esp_post_encrypt_trace,
   .type = VLIB_NODE_TYPE_INTERNAL,
-  .sibling_of = "esp6-encrypt-tun",
+  .sibling_of = "esp-mpls-encrypt-tun",
 
 
-  .n_errors = ARRAY_LEN(esp_encrypt_error_strings),
+  .n_errors = ARRAY_LEN (esp_encrypt_error_strings),
   .error_strings = esp_encrypt_error_strings,
 };
 /* *INDENT-ON* */
 
   .error_strings = esp_encrypt_error_strings,
 };
 /* *INDENT-ON* */
 
+VLIB_NODE_FN (esp_mpls_encrypt_tun_node)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
+{
+  return esp_encrypt_inline (vm, node, from_frame, VNET_LINK_MPLS, 1,
+                            esp_encrypt_async_next.esp_mpls_tun_post_next);
+}
+
+VLIB_REGISTER_NODE (esp_mpls_encrypt_tun_node) = {
+  .name = "esp-mpls-encrypt-tun",
+  .vector_size = sizeof (u32),
+  .format_trace = format_esp_encrypt_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+
+  .n_errors = ARRAY_LEN(esp_encrypt_error_strings),
+  .error_strings = esp_encrypt_error_strings,
+
+  .n_next_nodes = ESP_ENCRYPT_N_NEXT,
+  .next_nodes = {
+    [ESP_ENCRYPT_NEXT_DROP4] = "ip4-drop",
+    [ESP_ENCRYPT_NEXT_DROP6] = "ip6-drop",
+    [ESP_ENCRYPT_NEXT_DROP_MPLS] = "mpls-drop",
+    [ESP_ENCRYPT_NEXT_HANDOFF4] = "esp4-encrypt-tun-handoff",
+    [ESP_ENCRYPT_NEXT_HANDOFF6] = "esp6-encrypt-tun-handoff",
+    [ESP_ENCRYPT_NEXT_HANDOFF_MPLS] = "esp-mpls-encrypt-tun-handoff",
+    [ESP_ENCRYPT_NEXT_INTERFACE_OUTPUT] = "adj-midchain-tx",
+  },
+};
+
+VLIB_NODE_FN (esp_mpls_encrypt_tun_post_node)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
+{
+  return esp_encrypt_post_inline (vm, node, from_frame);
+}
+
+VLIB_REGISTER_NODE (esp_mpls_encrypt_tun_post_node) = {
+  .name = "esp-mpls-encrypt-tun-post",
+  .vector_size = sizeof (u32),
+  .format_trace = format_esp_post_encrypt_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .sibling_of = "esp-mpls-encrypt-tun",
+
+  .n_errors = ARRAY_LEN (esp_encrypt_error_strings),
+  .error_strings = esp_encrypt_error_strings,
+};
+
 typedef struct
 {
   u32 sa_index;
 typedef struct
 {
   u32 sa_index;
index 1d92676..b63b2a7 100644 (file)
@@ -208,19 +208,16 @@ ipsec_register_ah_backend (vlib_main_t * vm, ipsec_main_t * im,
 }
 
 u32
 }
 
 u32
-ipsec_register_esp_backend (vlib_main_t * vm, ipsec_main_t * im,
-                           const char *name,
-                           const char *esp4_encrypt_node_name,
-                           const char *esp4_encrypt_node_tun_name,
-                           const char *esp4_decrypt_node_name,
-                           const char *esp4_decrypt_tun_node_name,
-                           const char *esp6_encrypt_node_name,
-                           const char *esp6_encrypt_node_tun_name,
-                           const char *esp6_decrypt_node_name,
-                           const char *esp6_decrypt_tun_node_name,
-                           check_support_cb_t esp_check_support_cb,
-                           add_del_sa_sess_cb_t esp_add_del_sa_sess_cb,
-                           enable_disable_cb_t enable_disable_cb)
+ipsec_register_esp_backend (
+  vlib_main_t *vm, ipsec_main_t *im, const char *name,
+  const char *esp4_encrypt_node_name, const char *esp4_encrypt_node_tun_name,
+  const char *esp4_decrypt_node_name, const char *esp4_decrypt_tun_node_name,
+  const char *esp6_encrypt_node_name, const char *esp6_encrypt_node_tun_name,
+  const char *esp6_decrypt_node_name, const char *esp6_decrypt_tun_node_name,
+  const char *esp_mpls_encrypt_node_tun_name,
+  check_support_cb_t esp_check_support_cb,
+  add_del_sa_sess_cb_t esp_add_del_sa_sess_cb,
+  enable_disable_cb_t enable_disable_cb)
 {
   ipsec_esp_backend_t *b;
 
 {
   ipsec_esp_backend_t *b;
 
@@ -244,6 +241,8 @@ ipsec_register_esp_backend (vlib_main_t * vm, ipsec_main_t * im,
 
   b->esp6_encrypt_tun_node_index =
     vlib_get_node_by_name (vm, (u8 *) esp6_encrypt_node_tun_name)->index;
 
   b->esp6_encrypt_tun_node_index =
     vlib_get_node_by_name (vm, (u8 *) esp6_encrypt_node_tun_name)->index;
+  b->esp_mpls_encrypt_tun_node_index =
+    vlib_get_node_by_name (vm, (u8 *) esp_mpls_encrypt_node_tun_name)->index;
   b->esp4_encrypt_tun_node_index =
     vlib_get_node_by_name (vm, (u8 *) esp4_encrypt_node_tun_name)->index;
 
   b->esp4_encrypt_tun_node_index =
     vlib_get_node_by_name (vm, (u8 *) esp4_encrypt_node_tun_name)->index;
 
@@ -326,6 +325,7 @@ ipsec_select_esp_backend (ipsec_main_t * im, u32 backend_idx)
   im->esp6_decrypt_tun_next_index = b->esp6_decrypt_tun_next_index;
   im->esp4_encrypt_tun_node_index = b->esp4_encrypt_tun_node_index;
   im->esp6_encrypt_tun_node_index = b->esp6_encrypt_tun_node_index;
   im->esp6_decrypt_tun_next_index = b->esp6_decrypt_tun_next_index;
   im->esp4_encrypt_tun_node_index = b->esp4_encrypt_tun_node_index;
   im->esp6_encrypt_tun_node_index = b->esp6_encrypt_tun_node_index;
+  im->esp_mpls_encrypt_tun_node_index = b->esp_mpls_encrypt_tun_node_index;
 
   if (b->enable_disable_cb)
     {
 
   if (b->enable_disable_cb)
     {
@@ -373,6 +373,8 @@ crypto_engine_backend_register_post_node (vlib_main_t * vm)
     vnet_crypto_register_post_node (vm, "esp4-encrypt-tun-post");
   eit->esp6_tun_post_next =
     vnet_crypto_register_post_node (vm, "esp6-encrypt-tun-post");
     vnet_crypto_register_post_node (vm, "esp4-encrypt-tun-post");
   eit->esp6_tun_post_next =
     vnet_crypto_register_post_node (vm, "esp6-encrypt-tun-post");
+  eit->esp_mpls_tun_post_next =
+    vnet_crypto_register_post_node (vm, "esp-mpls-encrypt-tun-post");
 
   dit = &esp_decrypt_async_next;
   dit->esp4_post_next =
 
   dit = &esp_decrypt_async_next;
   dit->esp4_post_next =
@@ -423,17 +425,11 @@ ipsec_init (vlib_main_t * vm)
   ASSERT (0 == rv);
   (void) (rv);                 // avoid warning
 
   ASSERT (0 == rv);
   (void) (rv);                 // avoid warning
 
-  idx = ipsec_register_esp_backend (vm, im, "crypto engine backend",
-                                   "esp4-encrypt",
-                                   "esp4-encrypt-tun",
-                                   "esp4-decrypt",
-                                   "esp4-decrypt-tun",
-                                   "esp6-encrypt",
-                                   "esp6-encrypt-tun",
-                                   "esp6-decrypt",
-                                   "esp6-decrypt-tun",
-                                   ipsec_check_esp_support,
-                                   NULL, crypto_dispatch_enable_disable);
+  idx = ipsec_register_esp_backend (
+    vm, im, "crypto engine backend", "esp4-encrypt", "esp4-encrypt-tun",
+    "esp4-decrypt", "esp4-decrypt-tun", "esp6-encrypt", "esp6-encrypt-tun",
+    "esp6-decrypt", "esp6-decrypt-tun", "esp-mpls-encrypt-tun",
+    ipsec_check_esp_support, NULL, crypto_dispatch_enable_disable);
   im->esp_default_backend = idx;
 
   rv = ipsec_select_esp_backend (im, idx);
   im->esp_default_backend = idx;
 
   rv = ipsec_select_esp_backend (im, idx);
@@ -562,6 +558,8 @@ ipsec_init (vlib_main_t * vm)
     vlib_frame_queue_main_init (esp4_encrypt_tun_node.index, 0);
   im->esp6_enc_tun_fq_index =
     vlib_frame_queue_main_init (esp6_encrypt_tun_node.index, 0);
     vlib_frame_queue_main_init (esp4_encrypt_tun_node.index, 0);
   im->esp6_enc_tun_fq_index =
     vlib_frame_queue_main_init (esp6_encrypt_tun_node.index, 0);
+  im->esp_mpls_enc_tun_fq_index =
+    vlib_frame_queue_main_init (esp_mpls_encrypt_tun_node.index, 0);
   im->esp4_dec_tun_fq_index =
     vlib_frame_queue_main_init (esp4_decrypt_tun_node.index, 0);
   im->esp6_dec_tun_fq_index =
   im->esp4_dec_tun_fq_index =
     vlib_frame_queue_main_init (esp4_decrypt_tun_node.index, 0);
   im->esp6_dec_tun_fq_index =
index 97ef626..c370fb1 100644 (file)
@@ -74,6 +74,7 @@ typedef struct
   u32 esp6_decrypt_tun_node_index;
   u32 esp6_decrypt_tun_next_index;
   u32 esp6_encrypt_tun_node_index;
   u32 esp6_decrypt_tun_node_index;
   u32 esp6_decrypt_tun_next_index;
   u32 esp6_encrypt_tun_node_index;
+  u32 esp_mpls_encrypt_tun_node_index;
 } ipsec_esp_backend_t;
 
 typedef struct
 } ipsec_esp_backend_t;
 
 typedef struct
@@ -145,6 +146,7 @@ typedef struct
   u32 esp6_decrypt_node_index;
   u32 esp6_decrypt_tun_node_index;
   u32 esp6_encrypt_tun_node_index;
   u32 esp6_decrypt_node_index;
   u32 esp6_decrypt_tun_node_index;
   u32 esp6_encrypt_tun_node_index;
+  u32 esp_mpls_encrypt_tun_node_index;
   u32 ah6_encrypt_node_index;
   u32 ah6_decrypt_node_index;
   /* next node indices */
   u32 ah6_encrypt_node_index;
   u32 ah6_decrypt_node_index;
   /* next node indices */
@@ -201,6 +203,7 @@ typedef struct
   u32 esp6_dec_fq_index;
   u32 esp4_enc_tun_fq_index;
   u32 esp6_enc_tun_fq_index;
   u32 esp6_dec_fq_index;
   u32 esp4_enc_tun_fq_index;
   u32 esp6_enc_tun_fq_index;
+  u32 esp_mpls_enc_tun_fq_index;
   u32 esp4_dec_tun_fq_index;
   u32 esp6_dec_tun_fq_index;
 
   u32 esp4_dec_tun_fq_index;
   u32 esp6_dec_tun_fq_index;
 
@@ -231,6 +234,7 @@ extern vlib_node_registration_t esp6_encrypt_node;
 extern vlib_node_registration_t esp6_decrypt_node;
 extern vlib_node_registration_t esp4_encrypt_tun_node;
 extern vlib_node_registration_t esp6_encrypt_tun_node;
 extern vlib_node_registration_t esp6_decrypt_node;
 extern vlib_node_registration_t esp4_encrypt_tun_node;
 extern vlib_node_registration_t esp6_encrypt_tun_node;
+extern vlib_node_registration_t esp_mpls_encrypt_tun_node;
 extern vlib_node_registration_t esp4_decrypt_tun_node;
 extern vlib_node_registration_t esp6_decrypt_tun_node;
 extern vlib_node_registration_t ipsec4_tun_input_node;
 extern vlib_node_registration_t esp4_decrypt_tun_node;
 extern vlib_node_registration_t esp6_decrypt_tun_node;
 extern vlib_node_registration_t ipsec4_tun_input_node;
@@ -266,19 +270,16 @@ u32 ipsec_register_ah_backend (vlib_main_t * vm, ipsec_main_t * im,
                               check_support_cb_t ah_check_support_cb,
                               add_del_sa_sess_cb_t ah_add_del_sa_sess_cb);
 
                               check_support_cb_t ah_check_support_cb,
                               add_del_sa_sess_cb_t ah_add_del_sa_sess_cb);
 
-u32 ipsec_register_esp_backend (vlib_main_t * vm, ipsec_main_t * im,
-                               const char *name,
-                               const char *esp4_encrypt_node_name,
-                               const char *esp4_encrypt_tun_node_name,
-                               const char *esp4_decrypt_node_name,
-                               const char *esp4_decrypt_tun_node_name,
-                               const char *esp6_encrypt_node_name,
-                               const char *esp6_encrypt_tun_node_name,
-                               const char *esp6_decrypt_node_name,
-                               const char *esp6_decrypt_tun_node_name,
-                               check_support_cb_t esp_check_support_cb,
-                               add_del_sa_sess_cb_t esp_add_del_sa_sess_cb,
-                               enable_disable_cb_t enable_disable_cb);
+u32 ipsec_register_esp_backend (
+  vlib_main_t *vm, ipsec_main_t *im, const char *name,
+  const char *esp4_encrypt_node_name, const char *esp4_encrypt_tun_node_name,
+  const char *esp4_decrypt_node_name, const char *esp4_decrypt_tun_node_name,
+  const char *esp6_encrypt_node_name, const char *esp6_encrypt_tun_node_name,
+  const char *esp6_decrypt_node_name, const char *esp6_decrypt_tun_node_name,
+  const char *esp_mpls_encrypt_tun_node_name,
+  check_support_cb_t esp_check_support_cb,
+  add_del_sa_sess_cb_t esp_add_del_sa_sess_cb,
+  enable_disable_cb_t enable_disable_cb);
 
 int ipsec_select_ah_backend (ipsec_main_t * im, u32 ah_backend_idx);
 int ipsec_select_esp_backend (ipsec_main_t * im, u32 esp_backend_idx);
 
 int ipsec_select_ah_backend (ipsec_main_t * im, u32 ah_backend_idx);
 int ipsec_select_esp_backend (ipsec_main_t * im, u32 esp_backend_idx);
index 4446f1e..87eb801 100644 (file)
@@ -220,6 +220,15 @@ VLIB_NODE_FN (esp6_encrypt_tun_handoff) (vlib_main_t * vm,
                        true);
 }
 
                        true);
 }
 
+VLIB_NODE_FN (esp_mpls_encrypt_tun_handoff)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
+{
+  ipsec_main_t *im = &ipsec_main;
+
+  return ipsec_handoff (vm, node, from_frame, im->esp_mpls_enc_tun_fq_index,
+                       true);
+}
+
 VLIB_NODE_FN (esp4_decrypt_handoff) (vlib_main_t * vm,
                                     vlib_node_runtime_t * node,
                                     vlib_frame_t * from_frame)
 VLIB_NODE_FN (esp4_decrypt_handoff) (vlib_main_t * vm,
                                     vlib_node_runtime_t * node,
                                     vlib_frame_t * from_frame)
@@ -343,6 +352,18 @@ VLIB_REGISTER_NODE (esp6_encrypt_tun_handoff) = {
     [0] = "error-drop",
   },
 };
     [0] = "error-drop",
   },
 };
+VLIB_REGISTER_NODE (esp_mpls_encrypt_tun_handoff) = {
+  .name = "esp-mpls-encrypt-tun-handoff",
+  .vector_size = sizeof (u32),
+  .format_trace = format_ipsec_handoff_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN(ipsec_handoff_error_strings),
+  .error_strings = ipsec_handoff_error_strings,
+  .n_next_nodes = 1,
+  .next_nodes = {
+    [0] = "error-drop",
+  },
+};
 VLIB_REGISTER_NODE (esp4_decrypt_handoff) = {
   .name = "esp4-decrypt-handoff",
   .vector_size = sizeof (u32),
 VLIB_REGISTER_NODE (esp4_decrypt_handoff) = {
   .name = "esp4-decrypt-handoff",
   .vector_size = sizeof (u32),
index c3f50a6..ea60ab4 100644 (file)
@@ -141,33 +141,48 @@ ipsec_tun_protect_get_adj_next (vnet_link_t linkt,
 {
   ipsec_main_t *im;
   ipsec_sa_t *sa;
 {
   ipsec_main_t *im;
   ipsec_sa_t *sa;
-  bool is_ip4;
   u32 next;
 
   u32 next;
 
-
-  if (itp->itp_flags & IPSEC_PROTECT_ITF)
-    is_ip4 = linkt == VNET_LINK_IP4;
-  else
-    is_ip4 = ip46_address_is_ip4 (&itp->itp_tun.src);
+  if (!(itp->itp_flags & IPSEC_PROTECT_ITF))
+    {
+      if (ip46_address_is_ip4 (&itp->itp_tun.src))
+       linkt = VNET_LINK_IP4;
+      else
+       linkt = VNET_LINK_IP6;
+    }
 
   sa = ipsec_sa_get (itp->itp_out_sa);
   im = &ipsec_main;
 
   sa = ipsec_sa_get (itp->itp_out_sa);
   im = &ipsec_main;
+  next = 0;
 
   if ((sa->crypto_alg == IPSEC_CRYPTO_ALG_NONE &&
        sa->integ_alg == IPSEC_INTEG_ALG_NONE) &&
       !(itp->itp_flags & IPSEC_PROTECT_ITF))
 
   if ((sa->crypto_alg == IPSEC_CRYPTO_ALG_NONE &&
        sa->integ_alg == IPSEC_INTEG_ALG_NONE) &&
       !(itp->itp_flags & IPSEC_PROTECT_ITF))
-    next = (is_ip4 ?
-           im->esp4_no_crypto_tun_node_index :
-           im->esp6_no_crypto_tun_node_index);
+    next = (VNET_LINK_IP4 == linkt ? im->esp4_no_crypto_tun_node_index :
+                                    im->esp6_no_crypto_tun_node_index);
   else if (itp->itp_flags & IPSEC_PROTECT_L2)
   else if (itp->itp_flags & IPSEC_PROTECT_L2)
-    next = (is_ip4 ?
-           im->esp4_encrypt_l2_tun_node_index :
-           im->esp6_encrypt_l2_tun_node_index);
+    next = (VNET_LINK_IP4 == linkt ? im->esp4_encrypt_l2_tun_node_index :
+                                    im->esp6_encrypt_l2_tun_node_index);
   else
   else
-    next = (is_ip4 ?
-           im->esp4_encrypt_tun_node_index :
-           im->esp6_encrypt_tun_node_index);
-
+    {
+      switch (linkt)
+       {
+       case VNET_LINK_IP4:
+         next = im->esp4_encrypt_tun_node_index;
+         break;
+       case VNET_LINK_IP6:
+         next = im->esp6_encrypt_tun_node_index;
+         break;
+       case VNET_LINK_MPLS:
+         next = im->esp_mpls_encrypt_tun_node_index;
+         break;
+       case VNET_LINK_ARP:
+       case VNET_LINK_NSH:
+       case VNET_LINK_ETHERNET:
+         ASSERT (0);
+         break;
+       }
+    }
   return (next);
 }
 
   return (next);
 }
 
index 4783a7e..a1d2d3b 100644 (file)
@@ -19,6 +19,7 @@
 #include <vnet/ip/ip.h>
 #include <vnet/mpls/mpls.h>
 #include <vnet/ip/ip_frag.h>
 #include <vnet/ip/ip.h>
 #include <vnet/mpls/mpls.h>
 #include <vnet/ip/ip_frag.h>
+#include <vnet/adj/adj_dp.h>
 
 typedef struct {
   /* Adjacency taken. */
 
 typedef struct {
   /* Adjacency taken. */
@@ -199,36 +200,32 @@ mpls_output_inline (vlib_main_t * vm,
             }
           if (mode == MPLS_OUTPUT_MIDCHAIN_MODE)
           {
             }
           if (mode == MPLS_OUTPUT_MIDCHAIN_MODE)
           {
-             adj0->sub_type.midchain.fixup_func
-                (vm, adj0, p0,
-                 adj0->sub_type.midchain.fixup_data);
-             adj1->sub_type.midchain.fixup_func
-                (vm, adj1, p1,
-                 adj1->sub_type.midchain.fixup_data);
-          }
+           adj_midchain_fixup (vm, adj0, p0, VNET_LINK_MPLS);
+           adj_midchain_fixup (vm, adj1, p1, VNET_LINK_MPLS);
+         }
 
 
-          p0->error = error_node->errors[error0];
-          p1->error = error_node->errors[error1];
+         p0->error = error_node->errors[error0];
+         p1->error = error_node->errors[error1];
 
 
-          if (PREDICT_FALSE(p0->flags & VLIB_BUFFER_IS_TRACED))
-            {
-              mpls_output_trace_t *tr = vlib_add_trace (vm, node,
-                                                        p0, sizeof (*tr));
-              tr->adj_index = vnet_buffer(p0)->ip.adj_index[VLIB_TX];
-              tr->flow_hash = vnet_buffer(p0)->ip.flow_hash;
-            }
-          if (PREDICT_FALSE(p1->flags & VLIB_BUFFER_IS_TRACED))
-            {
-              mpls_output_trace_t *tr = vlib_add_trace (vm, node,
-                                                        p1, sizeof (*tr));
-              tr->adj_index = vnet_buffer(p1)->ip.adj_index[VLIB_TX];
-              tr->flow_hash = vnet_buffer(p1)->ip.flow_hash;
-            }
+         if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED))
+           {
+             mpls_output_trace_t *tr =
+               vlib_add_trace (vm, node, p0, sizeof (*tr));
+             tr->adj_index = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
+             tr->flow_hash = vnet_buffer (p0)->ip.flow_hash;
+           }
+         if (PREDICT_FALSE (p1->flags & VLIB_BUFFER_IS_TRACED))
+           {
+             mpls_output_trace_t *tr =
+               vlib_add_trace (vm, node, p1, sizeof (*tr));
+             tr->adj_index = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
+             tr->flow_hash = vnet_buffer (p1)->ip.flow_hash;
+           }
 
 
-          vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
-                                           to_next, n_left_to_next,
-                                           pi0, pi1, next0, next1);
-        }
+         vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
+                                          n_left_to_next, pi0, pi1, next0,
+                                          next1);
+       }
 
       while (n_left_from > 0 && n_left_to_next > 0)
         {
 
       while (n_left_from > 0 && n_left_to_next > 0)
         {
@@ -288,12 +285,10 @@ mpls_output_inline (vlib_main_t * vm,
             }
           if (mode == MPLS_OUTPUT_MIDCHAIN_MODE)
           {
             }
           if (mode == MPLS_OUTPUT_MIDCHAIN_MODE)
           {
-             adj0->sub_type.midchain.fixup_func
-                (vm, adj0, p0,
-                 adj0->sub_type.midchain.fixup_data);
-          }
+           adj_midchain_fixup (vm, adj0, p0, VNET_LINK_MPLS);
+         }
 
 
-          p0->error = error_node->errors[error0];
+         p0->error = error_node->errors[error0];
 
          from += 1;
          n_left_from -= 1;
 
          from += 1;
          n_left_from -= 1;
index d6f07b5..deef408 100644 (file)
@@ -68,6 +68,26 @@ tunnel_encap_fixup_4o4_w_chksum (tunnel_encap_decap_flags_t flags,
     }
 }
 
     }
 }
 
+static_always_inline void
+tunnel_encap_fixup_mplso4_w_chksum (tunnel_encap_decap_flags_t flags,
+                                   const mpls_unicast_header_t *inner,
+                                   ip4_header_t *outer)
+{
+  if (flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP)
+    {
+      ip_csum_t sum = outer->checksum;
+      u8 tos = outer->tos;
+
+      if (flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP)
+       ip4_header_set_dscp (outer,
+                            vnet_mpls_uc_get_exp (inner->label_exp_s_ttl));
+
+      sum =
+       ip_csum_update (outer->checksum, tos, outer->tos, ip4_header_t, tos);
+      outer->checksum = ip_csum_fold (sum);
+    }
+}
+
 static_always_inline void
 tunnel_encap_fixup_6o4 (tunnel_encap_decap_flags_t flags,
                        const ip6_header_t * inner, ip4_header_t * outer)
 static_always_inline void
 tunnel_encap_fixup_6o4 (tunnel_encap_decap_flags_t flags,
                        const ip6_header_t * inner, ip4_header_t * outer)
index d97de7f..12c24e5 100644 (file)
@@ -1,8 +1,16 @@
 diff --git a/scapy/layers/ipsec.py b/scapy/layers/ipsec.py
 diff --git a/scapy/layers/ipsec.py b/scapy/layers/ipsec.py
-index ae057ee1..24a1f6ea 100644
+index ae057ee1..d7a21e8b 100644
 --- a/scapy/layers/ipsec.py
 +++ b/scapy/layers/ipsec.py
 --- a/scapy/layers/ipsec.py
 +++ b/scapy/layers/ipsec.py
-@@ -138,6 +138,7 @@ bind_layers(IP, ESP, proto=socket.IPPROTO_ESP)
+@@ -56,6 +56,7 @@ from scapy.fields import ByteEnumField, ByteField, IntField, PacketField, \
+     ShortField, StrField, XIntField, XStrField, XStrLenField
+ from scapy.packet import Packet, bind_layers, Raw
+ from scapy.layers.inet import IP, UDP
++from scapy.contrib.mpls import MPLS
+ import scapy.modules.six as six
+ from scapy.modules.six.moves import range
+ from scapy.layers.inet6 import IPv6, IPv6ExtHdrHopByHop, IPv6ExtHdrDestOpt, \
+@@ -138,6 +139,7 @@ bind_layers(IP, ESP, proto=socket.IPPROTO_ESP)
  bind_layers(IPv6, ESP, nh=socket.IPPROTO_ESP)
  bind_layers(UDP, ESP, dport=4500)  # NAT-Traversal encapsulation
  bind_layers(UDP, ESP, sport=4500)  # NAT-Traversal encapsulation
  bind_layers(IPv6, ESP, nh=socket.IPPROTO_ESP)
  bind_layers(UDP, ESP, dport=4500)  # NAT-Traversal encapsulation
  bind_layers(UDP, ESP, sport=4500)  # NAT-Traversal encapsulation
@@ -10,7 +18,7 @@ index ae057ee1..24a1f6ea 100644
  
  ###############################################################################
  
  
  ###############################################################################
  
-@@ -359,11 +360,8 @@ class CryptAlgo(object):
+@@ -359,11 +361,8 @@ class CryptAlgo(object):
              encryptor = cipher.encryptor()
  
              if self.is_aead:
              encryptor = cipher.encryptor()
  
              if self.is_aead:
@@ -24,7 +32,7 @@ index ae057ee1..24a1f6ea 100644
                  data = encryptor.update(data) + encryptor.finalize()
                  data += encryptor.tag[:self.icv_size]
              else:
                  data = encryptor.update(data) + encryptor.finalize()
                  data += encryptor.tag[:self.icv_size]
              else:
-@@ -400,12 +398,7 @@ class CryptAlgo(object):
+@@ -400,12 +399,7 @@ class CryptAlgo(object):
  
              if self.is_aead:
                  # Tag value check is done during the finalize method
  
              if self.is_aead:
                  # Tag value check is done during the finalize method
@@ -38,7 +46,7 @@ index ae057ee1..24a1f6ea 100644
              try:
                  data = decryptor.update(data) + decryptor.finalize()
              except InvalidTag as err:
              try:
                  data = decryptor.update(data) + decryptor.finalize()
              except InvalidTag as err:
-@@ -445,6 +438,7 @@ if algorithms:
+@@ -445,6 +439,7 @@ if algorithms:
      CRYPT_ALGOS['AES-CTR'] = CryptAlgo('AES-CTR',
                                         cipher=algorithms.AES,
                                         mode=modes.CTR,
      CRYPT_ALGOS['AES-CTR'] = CryptAlgo('AES-CTR',
                                         cipher=algorithms.AES,
                                         mode=modes.CTR,
@@ -46,7 +54,7 @@ index ae057ee1..24a1f6ea 100644
                                         iv_size=8,
                                         salt_size=4,
                                         format_mode_iv=_aes_ctr_format_mode_iv)
                                         iv_size=8,
                                         salt_size=4,
                                         format_mode_iv=_aes_ctr_format_mode_iv)
-@@ -452,6 +446,7 @@ if algorithms:
+@@ -452,6 +447,7 @@ if algorithms:
      CRYPT_ALGOS['AES-GCM'] = CryptAlgo('AES-GCM',
                                         cipher=algorithms.AES,
                                         mode=modes.GCM,
      CRYPT_ALGOS['AES-GCM'] = CryptAlgo('AES-GCM',
                                         cipher=algorithms.AES,
                                         mode=modes.GCM,
@@ -54,7 +62,7 @@ index ae057ee1..24a1f6ea 100644
                                         salt_size=4,
                                         iv_size=8,
                                         icv_size=16,
                                         salt_size=4,
                                         iv_size=8,
                                         icv_size=16,
-@@ -460,6 +455,7 @@ if algorithms:
+@@ -460,6 +456,7 @@ if algorithms:
          CRYPT_ALGOS['AES-CCM'] = CryptAlgo('AES-CCM',
                                             cipher=algorithms.AES,
                                             mode=modes.CCM,
          CRYPT_ALGOS['AES-CCM'] = CryptAlgo('AES-CCM',
                                             cipher=algorithms.AES,
                                             mode=modes.CCM,
@@ -62,7 +70,7 @@ index ae057ee1..24a1f6ea 100644
                                             iv_size=8,
                                             salt_size=3,
                                             icv_size=16,
                                             iv_size=8,
                                             salt_size=3,
                                             icv_size=16,
-@@ -544,7 +540,7 @@ class AuthAlgo(object):
+@@ -544,7 +541,7 @@ class AuthAlgo(object):
          else:
              return self.mac(key, self.digestmod(), default_backend())
  
          else:
              return self.mac(key, self.digestmod(), default_backend())
  
@@ -71,7 +79,7 @@ index ae057ee1..24a1f6ea 100644
          """
          Sign an IPsec (ESP or AH) packet with this algo.
  
          """
          Sign an IPsec (ESP or AH) packet with this algo.
  
-@@ -560,16 +556,20 @@ class AuthAlgo(object):
+@@ -560,16 +557,20 @@ class AuthAlgo(object):
  
          if pkt.haslayer(ESP):
              mac.update(raw(pkt[ESP]))
  
          if pkt.haslayer(ESP):
              mac.update(raw(pkt[ESP]))
@@ -93,7 +101,7 @@ index ae057ee1..24a1f6ea 100644
          """
          Check that the integrity check value (icv) of a packet is valid.
  
          """
          Check that the integrity check value (icv) of a packet is valid.
  
-@@ -600,6 +600,8 @@ class AuthAlgo(object):
+@@ -600,6 +601,8 @@ class AuthAlgo(object):
              clone = zero_mutable_fields(pkt.copy(), sending=False)
  
          mac.update(raw(clone))
              clone = zero_mutable_fields(pkt.copy(), sending=False)
  
          mac.update(raw(clone))
@@ -102,7 +110,16 @@ index ae057ee1..24a1f6ea 100644
          computed_icv = mac.finalize()[:self.icv_size]
  
          # XXX: Cannot use mac.verify because the ICV can be truncated
          computed_icv = mac.finalize()[:self.icv_size]
  
          # XXX: Cannot use mac.verify because the ICV can be truncated
-@@ -862,6 +864,23 @@ class SecurityAssociation(object):
+@@ -788,7 +791,7 @@ class SecurityAssociation(object):
+     This class is responsible of "encryption" and "decryption" of IPsec packets.  # noqa: E501
+     """
+-    SUPPORTED_PROTOS = (IP, IPv6)
++    SUPPORTED_PROTOS = (IP, IPv6, MPLS)
+     def __init__(self, proto, spi, seq_num=1, crypt_algo=None, crypt_key=None,
+                  auth_algo=None, auth_key=None, tunnel_header=None, nat_t_header=None, esn_en=False, esn=0):   # noqa: E501
+@@ -862,6 +865,23 @@ class SecurityAssociation(object):
                  raise TypeError('nat_t_header must be %s' % UDP.name)
          self.nat_t_header = nat_t_header
  
                  raise TypeError('nat_t_header must be %s' % UDP.name)
          self.nat_t_header = nat_t_header
  
@@ -126,7 +143,7 @@ index ae057ee1..24a1f6ea 100644
      def check_spi(self, pkt):
          if pkt.spi != self.spi:
              raise TypeError('packet spi=0x%x does not match the SA spi=0x%x' %
      def check_spi(self, pkt):
          if pkt.spi != self.spi:
              raise TypeError('packet spi=0x%x does not match the SA spi=0x%x' %
-@@ -875,7 +894,8 @@ class SecurityAssociation(object):
+@@ -875,7 +895,8 @@ class SecurityAssociation(object):
              if len(iv) != self.crypt_algo.iv_size:
                  raise TypeError('iv length must be %s' % self.crypt_algo.iv_size)  # noqa: E501
  
              if len(iv) != self.crypt_algo.iv_size:
                  raise TypeError('iv length must be %s' % self.crypt_algo.iv_size)  # noqa: E501
  
@@ -136,7 +153,7 @@ index ae057ee1..24a1f6ea 100644
  
          if self.tunnel_header:
              tunnel = self.tunnel_header.copy()
  
          if self.tunnel_header:
              tunnel = self.tunnel_header.copy()
-@@ -899,7 +919,7 @@ class SecurityAssociation(object):
+@@ -899,7 +920,7 @@ class SecurityAssociation(object):
                                        esn_en=esn_en or self.esn_en,
                                        esn=esn or self.esn)
  
                                        esn_en=esn_en or self.esn_en,
                                        esn=esn or self.esn)
  
@@ -145,7 +162,7 @@ index ae057ee1..24a1f6ea 100644
  
          if self.nat_t_header:
              nat_t_header = self.nat_t_header.copy()
  
          if self.nat_t_header:
              nat_t_header = self.nat_t_header.copy()
-@@ -926,7 +946,8 @@ class SecurityAssociation(object):
+@@ -926,7 +947,8 @@ class SecurityAssociation(object):
  
      def _encrypt_ah(self, pkt, seq_num=None):
  
  
      def _encrypt_ah(self, pkt, seq_num=None):
  
@@ -155,7 +172,7 @@ index ae057ee1..24a1f6ea 100644
                  icv=b"\x00" * self.auth_algo.icv_size)
  
          if self.tunnel_header:
                  icv=b"\x00" * self.auth_algo.icv_size)
  
          if self.tunnel_header:
-@@ -966,7 +987,8 @@ class SecurityAssociation(object):
+@@ -966,7 +988,8 @@ class SecurityAssociation(object):
          else:
              ip_header.plen = len(ip_header.payload) + len(ah) + len(payload)
  
          else:
              ip_header.plen = len(ip_header.payload) + len(ah) + len(payload)
  
@@ -165,7 +182,7 @@ index ae057ee1..24a1f6ea 100644
  
          # sequence number must always change, unless specified by the user
          if seq_num is None:
  
          # sequence number must always change, unless specified by the user
          if seq_num is None:
-@@ -1003,11 +1025,12 @@ class SecurityAssociation(object):
+@@ -1003,11 +1026,12 @@ class SecurityAssociation(object):
  
      def _decrypt_esp(self, pkt, verify=True, esn_en=None, esn=None):
  
  
      def _decrypt_esp(self, pkt, verify=True, esn_en=None, esn=None):
  
@@ -179,7 +196,7 @@ index ae057ee1..24a1f6ea 100644
  
          esp = self.crypt_algo.decrypt(self, encrypted, self.crypt_key,
                                        self.crypt_algo.icv_size or
  
          esp = self.crypt_algo.decrypt(self, encrypted, self.crypt_key,
                                        self.crypt_algo.icv_size or
-@@ -1048,9 +1071,10 @@ class SecurityAssociation(object):
+@@ -1048,9 +1072,10 @@ class SecurityAssociation(object):
  
      def _decrypt_ah(self, pkt, verify=True):
  
  
      def _decrypt_ah(self, pkt, verify=True):
  
index 7e36d13..5bcd9dd 100644 (file)
@@ -7,13 +7,15 @@ from scapy.layers.l2 import Ether, GRE, Dot1Q
 from scapy.packet import Raw
 from scapy.layers.inet import IP, UDP
 from scapy.layers.inet6 import IPv6
 from scapy.packet import Raw
 from scapy.layers.inet import IP, UDP
 from scapy.layers.inet6 import IPv6
+from scapy.contrib.mpls import MPLS
 from framework import VppTestRunner
 from template_ipsec import TemplateIpsec, IpsecTun4Tests, IpsecTun6Tests, \
     IpsecTun4, IpsecTun6,  IpsecTcpTests, mk_scapy_crypt_key, \
     IpsecTun6HandoffTests, IpsecTun4HandoffTests, config_tun_params
 from vpp_gre_interface import VppGreInterface
 from vpp_ipip_tun_interface import VppIpIpTunInterface
 from framework import VppTestRunner
 from template_ipsec import TemplateIpsec, IpsecTun4Tests, IpsecTun6Tests, \
     IpsecTun4, IpsecTun6,  IpsecTcpTests, mk_scapy_crypt_key, \
     IpsecTun6HandoffTests, IpsecTun4HandoffTests, config_tun_params
 from vpp_gre_interface import VppGreInterface
 from vpp_ipip_tun_interface import VppIpIpTunInterface
-from vpp_ip_route import VppIpRoute, VppRoutePath, DpoProto
+from vpp_ip_route import VppIpRoute, VppRoutePath, DpoProto, VppMplsLabel, \
+    VppMplsTable, VppMplsRoute, FibPathProto
 from vpp_ipsec import VppIpsecSA, VppIpsecTunProtect, VppIpsecInterface
 from vpp_l2 import VppBridgeDomain, VppBridgeDomainPort
 from vpp_sub_interface import L2_VTR_OP, VppDot1QSubint
 from vpp_ipsec import VppIpsecSA, VppIpsecTunProtect, VppIpsecInterface
 from vpp_l2 import VppBridgeDomain, VppBridgeDomainPort
 from vpp_sub_interface import L2_VTR_OP, VppDot1QSubint
@@ -2570,6 +2572,82 @@ class TestIpsecItf4(TemplateIpsec,
         self.unconfig_network(p)
 
 
         self.unconfig_network(p)
 
 
+class TestIpsecItf4MPLS(TemplateIpsec,
+                        TemplateIpsecItf4,
+                        IpsecTun4):
+    """ IPsec Interface MPLSoIPv4 """
+
+    tun4_encrypt_node_name = "esp-mpls-encrypt-tun"
+
+    def setUp(self):
+        super(TestIpsecItf4MPLS, self).setUp()
+
+        self.tun_if = self.pg0
+
+    def tearDown(self):
+        super(TestIpsecItf4MPLS, self).tearDown()
+
+    def gen_encrypt_pkts(self, p, sa, sw_intf, src, dst, count=1,
+                         payload_size=100):
+        return [Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac) /
+                sa.encrypt(MPLS(label=44, ttl=3) /
+                           IP(src=src, dst=dst) /
+                           UDP(sport=1166, dport=2233) /
+                           Raw(b'X' * payload_size))
+                for i in range(count)]
+
+    def verify_encrypted(self, p, sa, rxs):
+        for rx in rxs:
+            try:
+                pkt = sa.decrypt(rx[IP])
+                if not pkt.haslayer(IP):
+                    pkt = IP(pkt[Raw].load)
+                self.assert_packet_checksums_valid(pkt)
+                self.assert_equal(pkt[MPLS].label, 44)
+                self.assert_equal(pkt[IP].dst, p.remote_tun_if_host)
+            except (IndexError, AssertionError):
+                self.logger.debug(ppp("Unexpected packet:", rx))
+                try:
+                    self.logger.debug(ppp("Decrypted packet:", pkt))
+                except:
+                    pass
+                raise
+
+    def test_tun_mpls_o_ip4(self):
+        """IPSEC interface MPLS over IPv4"""
+
+        n_pkts = 127
+        p = self.ipv4_params
+        f = FibPathProto
+
+        tbl = VppMplsTable(self, 0)
+        tbl.add_vpp_config()
+
+        self.config_network(p)
+        # deag MPLS routes from the tunnel
+        r4 = VppMplsRoute(self, 44, 1,
+                          [VppRoutePath(
+                              self.pg1.remote_ip4,
+                              self.pg1.sw_if_index)]).add_vpp_config()
+        p.route.modify([VppRoutePath(p.tun_if.remote_ip4,
+                                     p.tun_if.sw_if_index,
+                                     labels=[VppMplsLabel(44)])])
+        p.tun_if.enable_mpls()
+
+        self.config_sa_tun(p,
+                           self.pg0.local_ip4,
+                           self.pg0.remote_ip4)
+        self.config_protect(p)
+
+        self.verify_tun_44(p, count=n_pkts)
+
+        # cleanup
+        p.tun_if.disable_mpls()
+        self.unconfig_protect(p)
+        self.unconfig_sa(p)
+        self.unconfig_network(p)
+
+
 class TemplateIpsecItf6(object):
     """ IPsec Interface IPv6 """
 
 class TemplateIpsecItf6(object):
     """ IPsec Interface IPv6 """
 
@@ -2848,5 +2926,82 @@ class TestIpsecMIfEsp4(TemplateIpsec, IpsecTun4):
             self.verify_tun_44(p, count=N_PKTS)
 
 
             self.verify_tun_44(p, count=N_PKTS)
 
 
+class TestIpsecItf6MPLS(TemplateIpsec,
+                        TemplateIpsecItf6,
+                        IpsecTun6):
+    """ IPsec Interface MPLSoIPv6 """
+
+    tun6_encrypt_node_name = "esp-mpls-encrypt-tun"
+
+    def setUp(self):
+        super(TestIpsecItf6MPLS, self).setUp()
+
+        self.tun_if = self.pg0
+
+    def tearDown(self):
+        super(TestIpsecItf6MPLS, self).tearDown()
+
+    def gen_encrypt_pkts6(self, p, sa, sw_intf, src, dst, count=1,
+                          payload_size=100):
+        return [Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac) /
+                sa.encrypt(MPLS(label=66, ttl=3) /
+                           IPv6(src=src, dst=dst) /
+                           UDP(sport=1166, dport=2233) /
+                           Raw(b'X' * payload_size))
+                for i in range(count)]
+
+    def verify_encrypted6(self, p, sa, rxs):
+        for rx in rxs:
+            try:
+                pkt = sa.decrypt(rx[IPv6])
+                if not pkt.haslayer(IPv6):
+                    pkt = IP(pkt[Raw].load)
+                self.assert_packet_checksums_valid(pkt)
+                self.assert_equal(pkt[MPLS].label, 66)
+                self.assert_equal(pkt[IPv6].dst, p.remote_tun_if_host)
+            except (IndexError, AssertionError):
+                self.logger.debug(ppp("Unexpected packet:", rx))
+                try:
+                    self.logger.debug(ppp("Decrypted packet:", pkt))
+                except:
+                    pass
+                raise
+
+    def test_tun_mpls_o_ip6(self):
+        """IPSEC interface MPLS over IPv6"""
+
+        n_pkts = 127
+        p = self.ipv6_params
+        f = FibPathProto
+
+        tbl = VppMplsTable(self, 0)
+        tbl.add_vpp_config()
+
+        self.config_network(p)
+        # deag MPLS routes from the tunnel
+        r6 = VppMplsRoute(self, 66, 1,
+                          [VppRoutePath(
+                              self.pg1.remote_ip6,
+                              self.pg1.sw_if_index)],
+                          eos_proto=f.FIB_PATH_NH_PROTO_IP6).add_vpp_config()
+        p.route.modify([VppRoutePath(p.tun_if.remote_ip6,
+                                     p.tun_if.sw_if_index,
+                                     labels=[VppMplsLabel(66)])])
+        p.tun_if.enable_mpls()
+
+        self.config_sa_tun(p,
+                           self.pg0.local_ip6,
+                           self.pg0.remote_ip6)
+        self.config_protect(p)
+
+        self.verify_tun_66(p, count=n_pkts)
+
+        # cleanup
+        p.tun_if.disable_mpls()
+        self.unconfig_protect(p)
+        self.unconfig_sa(p)
+        self.unconfig_network(p)
+
+
 if __name__ == '__main__':
     unittest.main(testRunner=VppTestRunner)
 if __name__ == '__main__':
     unittest.main(testRunner=VppTestRunner)