nat: nat66 to plugin 53/27753/7
authorOle Troan <ot@cisco.com>
Wed, 1 Jul 2020 11:16:16 +0000 (13:16 +0200)
committerAndrew Yourtchenko <ayourtch@gmail.com>
Thu, 2 Jul 2020 13:13:27 +0000 (13:13 +0000)
Type: refactor
Change-Id: I8c1f0c02a4522c1f9e461ddadd59938579ec00c6
Signed-off-by: Ole Troan <ot@cisco.com>
17 files changed:
extras/vom/vom/nat_binding_cmds.hpp
extras/vom/vom/nat_static_cmds.cpp
extras/vom/vom/nat_static_cmds.hpp
src/plugins/nat/CMakeLists.txt
src/plugins/nat/nat.api
src/plugins/nat/nat.c
src/plugins/nat/nat66/nat66.api [new file with mode: 0644]
src/plugins/nat/nat66/nat66.c [moved from src/plugins/nat/nat66.c with 84% similarity]
src/plugins/nat/nat66/nat66.h [moved from src/plugins/nat/nat66.h with 63% similarity]
src/plugins/nat/nat66/nat66_api.c [new file with mode: 0644]
src/plugins/nat/nat66/nat66_cli.c [moved from src/plugins/nat/nat66_cli.c with 98% similarity]
src/plugins/nat/nat66/nat66_in2out.c [moved from src/plugins/nat/nat66_in2out.c with 98% similarity]
src/plugins/nat/nat66/nat66_out2in.c [moved from src/plugins/nat/nat66_out2in.c with 99% similarity]
src/plugins/nat/nat_api.c
src/plugins/nat/nat_types.api [new file with mode: 0644]
src/plugins/nat/test/test_nat.py
src/plugins/nat/test/test_nat66.py [new file with mode: 0644]

index 9b59d0d..40507e0 100644 (file)
@@ -21,6 +21,7 @@
 #include "vom/rpc_cmd.hpp"
 
 #include <vapi/nat.api.vapi.hpp>
+#include <vapi/nat66.api.vapi.hpp>
 
 namespace VOM {
 namespace nat_binding_cmds {
@@ -253,8 +254,8 @@ private:
 
 /////
 /**
-* A functor class that binds a NAT configuration to an input interface
-*/
+ * A functor class that binds a NAT configuration to an input interface
+ */
 class bind_66_input_cmd
   : public rpc_cmd<HW::item<bool>, vapi::Nat66_add_del_interface>
 {
index 0c4d728..7e2b05f 100644 (file)
@@ -16,6 +16,7 @@
 #include "vom/nat_static_cmds.hpp"
 
 DEFINE_VAPI_MSG_IDS_NAT_API_JSON;
+DEFINE_VAPI_MSG_IDS_NAT66_API_JSON;
 
 namespace VOM {
 namespace nat_static_cmds {
@@ -28,8 +29,7 @@ create_44_cmd::create_44_cmd(HW::item<bool>& item,
   , m_id(id)
   , m_inside(inside)
   , m_outside(outside)
-{
-}
+{}
 
 bool
 create_44_cmd::operator==(const create_44_cmd& other) const
@@ -77,8 +77,7 @@ delete_44_cmd::delete_44_cmd(HW::item<bool>& item,
   , m_id(id)
   , m_inside(inside)
   , m_outside(outside)
-{
-}
+{}
 
 bool
 delete_44_cmd::operator==(const delete_44_cmd& other) const
@@ -153,8 +152,7 @@ create_66_cmd::create_66_cmd(HW::item<bool>& item,
   , m_id(id)
   , m_inside(inside)
   , m_outside(outside)
-{
-}
+{}
 
 bool
 create_66_cmd::operator==(const create_66_cmd& other) const
@@ -198,8 +196,7 @@ delete_66_cmd::delete_66_cmd(HW::item<bool>& item,
   , m_id(id)
   , m_inside(inside)
   , m_outside(outside)
-{
-}
+{}
 
 bool
 delete_66_cmd::operator==(const delete_66_cmd& other) const
index 8d514d8..2213ef5 100644 (file)
@@ -20,6 +20,7 @@
 #include "vom/dump_cmd.hpp"
 
 #include <vapi/nat.api.vapi.hpp>
+#include <vapi/nat66.api.vapi.hpp>
 
 namespace VOM {
 namespace nat_static_cmds {
index 8803ee0..5ce8b8a 100644 (file)
@@ -43,10 +43,6 @@ add_vpp_plugin(nat
   nat64_in2out.c
   nat64_out2in.c
   nat64_db.c
-  nat66.c
-  nat66_cli.c
-  nat66_in2out.c
-  nat66_out2in.c
   nat_affinity.c
   nat_format.c
   nat_syslog.c
@@ -60,8 +56,6 @@ add_vpp_plugin(nat
   nat44_handoff.c
   nat64_in2out.c
   nat64_out2in.c
-  nat66_in2out.c
-  nat66_out2in.c
   nat_det_in2out.c
   nat_det_out2in.c
   out2in.c
@@ -69,6 +63,7 @@ add_vpp_plugin(nat
 
   API_FILES
   nat.api
+  nat_types.api
 
   API_TEST_SOURCES
   nat_test.c
@@ -101,3 +96,23 @@ add_vpp_plugin(dslite
 
   LINK_LIBRARIES nat
 )
+
+add_vpp_plugin(nat66
+  SOURCES
+  nat_syslog.c
+  nat66/nat66.c
+  nat66/nat66_cli.c
+  nat66/nat66_api.c
+  nat66/nat66_in2out.c
+  nat66/nat66_out2in.c
+
+  MULTIARCH_SOURCES
+  nat66/nat66_in2out.c
+  nat66/nat66_out2in.c
+
+  API_FILES
+  nat66/nat66.api
+  nat_types.api
+
+  LINK_LIBRARIES nat
+)
index 134f3e0..cd50c19 100644 (file)
@@ -16,6 +16,7 @@
 option version = "5.2.0";
 import "vnet/ip/ip_types.api";
 import "vnet/interface_types.api";
+import "plugins/nat/nat_types.api";
 
 /**
  * @file nat.api
@@ -29,19 +30,6 @@ import "vnet/interface_types.api";
  * Common NAT plugin APIs
  */
 
-enum nat_config_flags : u8
-{
-  NAT_IS_NONE = 0x00,
-  NAT_IS_TWICE_NAT = 0x01,
-  NAT_IS_SELF_TWICE_NAT = 0x02,
-  NAT_IS_OUT2IN_ONLY = 0x04,
-  NAT_IS_ADDR_ONLY = 0x08,
-  NAT_IS_OUTSIDE = 0x10,
-  NAT_IS_INSIDE = 0x20,
-  NAT_IS_STATIC = 0x40,
-  NAT_IS_EXT_HOST_VALID = 0x80,
-};
-
 /** \brief Control ping from client to api server request
     @param client_index - opaque cookie to identify the sender
     @param context - sender context, to match reply w/ request
@@ -1398,86 +1386,3 @@ autoreply define nat64_add_del_interface_addr {
   bool is_add;
   vl_api_interface_index_t sw_if_index;
 };
-
-/*
- * NAT66 APIs
- */
-/** \brief Enable/disable NAT66 feature on the interface
-    @param client_index - opaque cookie to identify the sender
-    @param context - sender context, to match reply w/ request
-    @param is_add - true if add, false if delete
-    @param flags - flag NAT_IS_INSIDE if interface is inside or
-                   interface is outside,
-    @param sw_if_index - software index of the interface
-*/
-autoreply define nat66_add_del_interface {
-  u32 client_index;
-  u32 context;
-  bool is_add;
-  vl_api_nat_config_flags_t flags;
-  vl_api_interface_index_t sw_if_index;
-};
-
-/** \brief Dump interfaces with NAT66 feature
-    @param client_index - opaque cookie to identify the sender
-    @param context - sender context, to match reply w/ request
-*/
-define nat66_interface_dump {
-  u32 client_index;
-  u32 context;
-};
-
-/** \brief NAT66 interface details response
-    @param context - sender context, to match reply w/ request
-    @param flags - flag NAT_IS_INSIDE if interface is inside or
-                   interface is outside,
-    @param sw_if_index - software index of the interface
-*/
-define nat66_interface_details {
-  u32 context;
-  vl_api_nat_config_flags_t flags;
-  vl_api_interface_index_t sw_if_index;
-};
-
-/** \brief Add/delete 1:1 NAT66
-    @param client_index - opaque cookie to identify the sender
-    @param context - sender context, to match reply w/ request
-    @param is_add - true if add, false if delete
-    @param local_ip_address - local IPv6 address
-    @param external_ip_address - external IPv6 address
-    @param vrf_id - VRF id of tenant
-*/
-autoreply define nat66_add_del_static_mapping {
-  u32 client_index;
-  u32 context;
-  bool is_add;
-  vl_api_ip6_address_t local_ip_address;
-  vl_api_ip6_address_t external_ip_address;
-  u32 vrf_id;
-};
-
-/** \brief Dump NAT66 static mappings
-    @param client_index - opaque cookie to identify the sender
-    @param context - sender context, to match reply w/ request
-*/
-define nat66_static_mapping_dump {
-  u32 client_index;
-  u32 context;
-};
-
-/** \brief NAT66 static mapping details response
-    @param context - sender context, to match reply w/ request
-    @param local_ip_address - local IPv6 address
-    @param external_ip_address - external IPv6 address
-    @param vrf_id - VRF id of tenant
-    @param total_bytes - count of bytes sent through static mapping
-    @param total_pkts - count of pakets sent through static mapping
-*/
-define nat66_static_mapping_details {
-  u32 context;
-  vl_api_ip6_address_t local_ip_address;
-  vl_api_ip6_address_t external_ip_address;
-  u32 vrf_id;
-  u64 total_bytes;
-  u64 total_pkts;
-};
index 60ef22f..c4c5dd8 100644 (file)
@@ -24,7 +24,6 @@
 #include <nat/nat_ipfix_logging.h>
 #include <nat/nat_det.h>
 #include <nat/nat64.h>
-#include <nat/nat66.h>
 #include <nat/nat_inlines.h>
 #include <nat/nat44/inlines.h>
 #include <nat/nat_affinity.h>
@@ -2598,8 +2597,6 @@ snat_init (vlib_main_t * vm)
   if (error)
     return error;
 
-  nat66_init (vm);
-
   ip4_table_bind_callback_t cbt4 = {
     .function = snat_ip4_table_bind,
   };
@@ -3913,7 +3910,6 @@ static clib_error_t *
 snat_config (vlib_main_t * vm, unformat_input_t * input)
 {
   snat_main_t *sm = &snat_main;
-  nat66_main_t *nm = &nat66_main;
   snat_main_per_thread_data_t *tsm;
 
   u32 static_mapping_buckets = 1024;
@@ -4075,10 +4071,6 @@ snat_config (vlib_main_t * vm, unformat_input_t * input)
   sm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
                                                             outside_vrf_id,
                                                             nat_fib_src_hi);
-  nm->outside_vrf_id = outside_ip6_vrf_id;
-  nm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
-                                                            outside_ip6_vrf_id,
-                                                            nat_fib_src_hi);
   sm->inside_vrf_id = inside_vrf_id;
   sm->inside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
                                                            inside_vrf_id,
diff --git a/src/plugins/nat/nat66/nat66.api b/src/plugins/nat/nat66/nat66.api
new file mode 100644 (file)
index 0000000..6906e41
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2020 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+option version = "1.0.0";
+import "vnet/ip/ip_types.api";
+import "vnet/interface_types.api";
+import "plugins/nat/nat_types.api";
+
+/** \brief Enable/disable NAT66 feature on the interface
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param is_add - true if add, false if delete
+    @param flags - flag NAT_IS_INSIDE if interface is inside or
+                   interface is outside,
+    @param sw_if_index - software index of the interface
+*/
+autoreply define nat66_add_del_interface {
+  u32 client_index;
+  u32 context;
+  bool is_add;
+  vl_api_nat_config_flags_t flags;
+  vl_api_interface_index_t sw_if_index;
+};
+
+/** \brief Dump interfaces with NAT66 feature
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+*/
+define nat66_interface_dump {
+  u32 client_index;
+  u32 context;
+};
+
+/** \brief NAT66 interface details response
+    @param context - sender context, to match reply w/ request
+    @param flags - flag NAT_IS_INSIDE if interface is inside or
+                   interface is outside,
+    @param sw_if_index - software index of the interface
+*/
+define nat66_interface_details {
+  u32 context;
+  vl_api_nat_config_flags_t flags;
+  vl_api_interface_index_t sw_if_index;
+};
+
+/** \brief Add/delete 1:1 NAT66
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param is_add - true if add, false if delete
+    @param local_ip_address - local IPv6 address
+    @param external_ip_address - external IPv6 address
+    @param vrf_id - VRF id of tenant
+*/
+autoreply define nat66_add_del_static_mapping {
+  u32 client_index;
+  u32 context;
+  bool is_add;
+  vl_api_ip6_address_t local_ip_address;
+  vl_api_ip6_address_t external_ip_address;
+  u32 vrf_id;
+};
+
+/** \brief Dump NAT66 static mappings
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+*/
+define nat66_static_mapping_dump {
+  u32 client_index;
+  u32 context;
+};
+
+/** \brief NAT66 static mapping details response
+    @param context - sender context, to match reply w/ request
+    @param local_ip_address - local IPv6 address
+    @param external_ip_address - external IPv6 address
+    @param vrf_id - VRF id of tenant
+    @param total_bytes - count of bytes sent through static mapping
+    @param total_pkts - count of pakets sent through static mapping
+*/
+define nat66_static_mapping_details {
+  u32 context;
+  vl_api_ip6_address_t local_ip_address;
+  vl_api_ip6_address_t external_ip_address;
+  u32 vrf_id;
+  u64 total_bytes;
+  u64 total_pkts;
+};
similarity index 84%
rename from src/plugins/nat/nat66.c
rename to src/plugins/nat/nat66/nat66.c
index 3ac773c..36d5d73 100644 (file)
  * @brief NAT66 implementation
  */
 
-#include <nat/nat66.h>
+#include <vpp/app/version.h>
+#include <vnet/plugin/plugin.h>
+#include <nat/nat66/nat66.h>
 #include <vnet/fib/fib_table.h>
 #include <vnet/ip/reass/ip6_sv_reass.h>
 
 nat66_main_t nat66_main;
+fib_source_t nat_fib_src_hi;
 
 /* *INDENT-OFF* */
 
@@ -41,8 +44,8 @@ VNET_FEATURE_INIT (nat66_out2in, static) = {
 
 /* *INDENT-ON* */
 
-
-void
+clib_error_t *nat66_plugin_api_hookup (vlib_main_t * vm);
+static clib_error_t *
 nat66_init (vlib_main_t * vm)
 {
   nat66_main_t *nm = &nat66_main;
@@ -62,13 +65,19 @@ nat66_init (vlib_main_t * vm)
                         static_mapping_buckets, static_mapping_memory_size);
 
   nm->session_counters.name = "session counters";
+
+  nat_fib_src_hi = fib_source_allocate ("nat66-hi",
+                                       FIB_SOURCE_PRIORITY_HI,
+                                       FIB_SOURCE_BH_SIMPLE);
+
+  return nat66_plugin_api_hookup (vm);
 }
 
 int
 nat66_interface_add_del (u32 sw_if_index, u8 is_inside, u8 is_add)
 {
   nat66_main_t *nm = &nat66_main;
-  snat_interface_t *interface = 0, *i;
+  nat66_interface_t *interface = 0, *i;
   const char *feature_name;
 
   /* *INDENT-OFF* */
@@ -90,8 +99,8 @@ nat66_interface_add_del (u32 sw_if_index, u8 is_inside, u8 is_add)
       pool_get (nm->interfaces, interface);
       interface->sw_if_index = sw_if_index;
       interface->flags =
-       is_inside ? NAT_INTERFACE_FLAG_IS_INSIDE :
-       NAT_INTERFACE_FLAG_IS_OUTSIDE;
+       is_inside ? NAT66_INTERFACE_FLAG_IS_INSIDE :
+       NAT66_INTERFACE_FLAG_IS_OUTSIDE;
     }
   else
     {
@@ -113,7 +122,7 @@ void
 nat66_interfaces_walk (nat66_interface_walk_fn_t fn, void *ctx)
 {
   nat66_main_t *nm = &nat66_main;
-  snat_interface_t *i = 0;
+  nat66_interface_t *i = 0;
 
   /* *INDENT-OFF* */
   pool_foreach (i, nm->interfaces,
@@ -191,7 +200,7 @@ nat66_static_mapping_add_del (ip6_address_t * l_addr, ip6_address_t * e_addr,
       kv.key[2] = sm_key.as_u64[2];
       kv.value = sm - nm->sm;
       if (clib_bihash_add_del_24_8 (&nm->sm_l, &kv, 1))
-       nat_elog_warn ("nat66-static-map-by-local add key failed");
+       nat66_elog_warn ("nat66-static-map-by-local add key failed");
       sm_key.addr.as_u64[0] = e_addr->as_u64[0];
       sm_key.addr.as_u64[1] = e_addr->as_u64[1];
       sm_key.fib_index = 0;
@@ -199,7 +208,7 @@ nat66_static_mapping_add_del (ip6_address_t * l_addr, ip6_address_t * e_addr,
       kv.key[1] = sm_key.as_u64[1];
       kv.key[2] = sm_key.as_u64[2];
       if (clib_bihash_add_del_24_8 (&nm->sm_e, &kv, 1))
-       nat_elog_warn ("nat66-static-map-by-external add key failed");
+       nat66_elog_warn ("nat66-static-map-by-external add key failed");
 
       vlib_validate_combined_counter (&nm->session_counters, kv.value);
       vlib_zero_combined_counter (&nm->session_counters, kv.value);
@@ -211,7 +220,7 @@ nat66_static_mapping_add_del (ip6_address_t * l_addr, ip6_address_t * e_addr,
 
       kv.value = sm - nm->sm;
       if (clib_bihash_add_del_24_8 (&nm->sm_l, &kv, 0))
-       nat_elog_warn ("nat66-static-map-by-local delete key failed");
+       nat66_elog_warn ("nat66-static-map-by-local delete key failed");
       sm_key.addr.as_u64[0] = e_addr->as_u64[0];
       sm_key.addr.as_u64[1] = e_addr->as_u64[1];
       sm_key.fib_index = 0;
@@ -219,7 +228,7 @@ nat66_static_mapping_add_del (ip6_address_t * l_addr, ip6_address_t * e_addr,
       kv.key[1] = sm_key.as_u64[1];
       kv.key[2] = sm_key.as_u64[2];
       if (clib_bihash_add_del_24_8 (&nm->sm_e, &kv, 0))
-       nat_elog_warn ("nat66-static-map-by-external delete key failed");
+       nat66_elog_warn ("nat66-static-map-by-external delete key failed");
       fib_table_unlock (sm->fib_index, FIB_PROTOCOL_IP6, nat_fib_src_hi);
       pool_put (nm->sm, sm);
     }
@@ -242,6 +251,30 @@ nat66_static_mappings_walk (nat66_static_mapping_walk_fn_t fn, void *ctx)
   /* *INDENT-ON* */
 }
 
+/*static*/ void
+nat66_config (void)
+{
+  nat66_main_t *nm = &nat66_main;
+  u32 outside_ip6_vrf_id = 0;
+
+  nm->outside_vrf_id = outside_ip6_vrf_id;
+  nm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
+                                                            outside_ip6_vrf_id,
+                                                            nat_fib_src_hi);
+
+}
+
+/* *INDENT-OFF* */
+VLIB_PLUGIN_REGISTER () =
+{
+ .version = VPP_BUILD_VER,
+ .description = "NAT66",
+};
+
+VLIB_INIT_FUNCTION (nat66_init);
+
+/* *INDENT-ON* */
+
 /*
  * fd.io coding-style-patch-verification: ON
  *
similarity index 63%
rename from src/plugins/nat/nat66.h
rename to src/plugins/nat/nat66/nat66.h
index 7b0ffed..9757f03 100644 (file)
@@ -19,8 +19,8 @@
 #ifndef __included_nat66_h__
 #define __included_nat66_h__
 
+#include <vnet/ip/ip.h>
 #include <vppinfra/bihash_24_8.h>
-#include <nat/nat.h>
 
 typedef struct
 {
@@ -43,10 +43,20 @@ typedef struct
   };
 } nat66_sm_key_t;
 
+typedef struct
+{
+  u32 sw_if_index;
+  u8 flags;
+} nat66_interface_t;
+#define NAT66_INTERFACE_FLAG_IS_INSIDE 1
+#define NAT66_INTERFACE_FLAG_IS_OUTSIDE 2
+#define nat66_interface_is_inside(i) i->flags & NAT66_INTERFACE_FLAG_IS_INSIDE
+#define nat66_interface_is_outside(i) i->flags & NAT66_INTERFACE_FLAG_IS_OUTSIDE
+
 typedef struct
 {
   /** Interface pool */
-  snat_interface_t *interfaces;
+  nat66_interface_t *interfaces;
   /** Static mapping pool */
   nat66_static_mapping_t *sm;
   /** Static mapping by local address lookup table */
@@ -61,14 +71,35 @@ typedef struct
 
   u32 outside_vrf_id;
   u32 outside_fib_index;
+
+  u16 msg_id_base;
+  u8 log_level;
 } nat66_main_t;
 
+#define nat66_elog(_level, _str)                         \
+do                                                       \
+  {                                                      \
+    nat66_main_t *nm = &nat66_main;                      \
+    if (PREDICT_FALSE (nm->log_level >= _level))         \
+      {                                                  \
+        ELOG_TYPE_DECLARE (e) =                          \
+          {                                              \
+            .format = "nat66-msg " _str,                 \
+            .format_args = "",                           \
+          };                                             \
+        ELOG_DATA (&vlib_global_main.elog_main, e);      \
+      }                                                  \
+  } while (0);
+
+#define nat66_elog_warn(nat_elog_str) \
+  nat66_elog(0x02, "[warning] " nat_elog_str)
+
+
 extern nat66_main_t nat66_main;
 extern vlib_node_registration_t nat66_in2out_node;
 extern vlib_node_registration_t nat66_out2in_node;
 
-void nat66_init (vlib_main_t * vm);
-typedef int (*nat66_interface_walk_fn_t) (snat_interface_t * i, void *ctx);
+typedef int (*nat66_interface_walk_fn_t) (nat66_interface_t * i, void *ctx);
 void nat66_interfaces_walk (nat66_interface_walk_fn_t fn, void *ctx);
 int nat66_interface_add_del (u32 sw_if_index, u8 is_inside, u8 is_add);
 typedef int (*nat66_static_mapping_walk_fn_t) (nat66_static_mapping_t * sm,
diff --git a/src/plugins/nat/nat66/nat66_api.c b/src/plugins/nat/nat66/nat66_api.c
new file mode 100644 (file)
index 0000000..2a2b3cc
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2020 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vlibmemory/api.h>
+#include <nat/nat66/nat66.h>
+#include <nat/nat66/nat66.api_enum.h>
+#include <nat/nat66/nat66.api_types.h>
+#include <vnet/fib/fib_table.h>
+
+#define REPLY_MSG_ID_BASE nm->msg_id_base
+#include <vlibapi/api_helper_macros.h>
+
+/*************/
+/*** NAT66 ***/
+/*************/
+
+static void
+vl_api_nat66_add_del_interface_t_handler (vl_api_nat66_add_del_interface_t *
+                                         mp)
+{
+  nat66_main_t *nm = &nat66_main;
+  vl_api_nat66_add_del_interface_reply_t *rmp;
+  int rv = 0;
+
+  VALIDATE_SW_IF_INDEX (mp);
+
+  rv =
+    nat66_interface_add_del (ntohl (mp->sw_if_index),
+                            mp->flags & NAT_IS_INSIDE, mp->is_add);
+
+  BAD_SW_IF_INDEX_LABEL;
+
+  REPLY_MACRO (VL_API_NAT66_ADD_DEL_INTERFACE_REPLY);
+}
+
+static void
+  vl_api_nat66_add_del_static_mapping_t_handler
+  (vl_api_nat66_add_del_static_mapping_t * mp)
+{
+  nat66_main_t *nm = &nat66_main;
+  vl_api_nat66_add_del_static_mapping_reply_t *rmp;
+  ip6_address_t l_addr, e_addr;
+  int rv = 0;
+
+  memcpy (&l_addr.as_u8, mp->local_ip_address, 16);
+  memcpy (&e_addr.as_u8, mp->external_ip_address, 16);
+
+  rv =
+    nat66_static_mapping_add_del (&l_addr, &e_addr,
+                                 clib_net_to_host_u32 (mp->vrf_id),
+                                 mp->is_add);
+
+  REPLY_MACRO (VL_API_NAT66_ADD_DEL_STATIC_MAPPING_REPLY);
+}
+
+typedef struct nat66_api_walk_ctx_t_
+{
+  vl_api_registration_t *rp;
+  u32 context;
+} nat66_api_walk_ctx_t;
+
+static int
+nat66_api_interface_walk (nat66_interface_t * i, void *arg)
+{
+  vl_api_nat66_interface_details_t *rmp;
+  nat66_main_t *nm = &nat66_main;
+  nat66_api_walk_ctx_t *ctx = arg;
+
+  rmp = vl_msg_api_alloc (sizeof (*rmp));
+  clib_memset (rmp, 0, sizeof (*rmp));
+  rmp->_vl_msg_id = ntohs (VL_API_NAT66_INTERFACE_DETAILS + nm->msg_id_base);
+  rmp->sw_if_index = ntohl (i->sw_if_index);
+  if (nat66_interface_is_inside (i))
+    rmp->flags |= NAT_IS_INSIDE;
+  rmp->context = ctx->context;
+
+  vl_api_send_msg (ctx->rp, (u8 *) rmp);
+
+  return 0;
+}
+
+static void
+vl_api_nat66_interface_dump_t_handler (vl_api_nat66_interface_dump_t * mp)
+{
+  vl_api_registration_t *rp;
+
+  rp = vl_api_client_index_to_registration (mp->client_index);
+  if (rp == 0)
+    return;
+
+  nat66_api_walk_ctx_t ctx = {
+    .rp = rp,
+    .context = mp->context,
+  };
+
+  nat66_interfaces_walk (nat66_api_interface_walk, &ctx);
+}
+
+static int
+nat66_api_static_mapping_walk (nat66_static_mapping_t * m, void *arg)
+{
+  vl_api_nat66_static_mapping_details_t *rmp;
+  nat66_main_t *nm = &nat66_main;
+  nat66_api_walk_ctx_t *ctx = arg;
+  fib_table_t *fib;
+  vlib_counter_t vc;
+
+  fib = fib_table_get (m->fib_index, FIB_PROTOCOL_IP6);
+  if (!fib)
+    return -1;
+
+  vlib_get_combined_counter (&nm->session_counters, m - nm->sm, &vc);
+
+  rmp = vl_msg_api_alloc (sizeof (*rmp));
+  clib_memset (rmp, 0, sizeof (*rmp));
+  rmp->_vl_msg_id =
+    ntohs (VL_API_NAT66_STATIC_MAPPING_DETAILS + nm->msg_id_base);
+  clib_memcpy (rmp->local_ip_address, &m->l_addr, 16);
+  clib_memcpy (rmp->external_ip_address, &m->e_addr, 16);
+  rmp->vrf_id = ntohl (fib->ft_table_id);
+  rmp->total_bytes = clib_host_to_net_u64 (vc.bytes);
+  rmp->total_pkts = clib_host_to_net_u64 (vc.packets);
+  rmp->context = ctx->context;
+
+  vl_api_send_msg (ctx->rp, (u8 *) rmp);
+
+  return 0;
+}
+
+static void
+vl_api_nat66_static_mapping_dump_t_handler (vl_api_nat66_static_mapping_dump_t
+                                           * mp)
+{
+  vl_api_registration_t *rp;
+
+  rp = vl_api_client_index_to_registration (mp->client_index);
+  if (rp == 0)
+    return;
+
+  nat66_api_walk_ctx_t ctx = {
+    .rp = rp,
+    .context = mp->context,
+  };
+
+  nat66_static_mappings_walk (nat66_api_static_mapping_walk, &ctx);
+}
+
+/* API definitions */
+#include <vnet/format_fns.h>
+#include <nat/nat66/nat66.api.c>
+
+/* Set up the API message handling tables */
+clib_error_t *
+nat66_plugin_api_hookup (vlib_main_t * vm)
+{
+  nat66_main_t *nm = &nat66_main;
+
+  nm->msg_id_base = setup_message_id_table ();
+
+  return 0;
+}
similarity index 98%
rename from src/plugins/nat/nat66_cli.c
rename to src/plugins/nat/nat66/nat66_cli.c
index d34c171..da96387 100644 (file)
@@ -17,8 +17,7 @@
  * @brief NAT66 CLI
  */
 
-#include <nat/nat66.h>
-#include <nat/nat.h>
+#include <nat/nat66/nat66.h>
 #include <vnet/fib/fib_table.h>
 
 static clib_error_t *
@@ -136,14 +135,14 @@ done:
 }
 
 static int
-nat66_cli_interface_walk (snat_interface_t * i, void *ctx)
+nat66_cli_interface_walk (nat66_interface_t * i, void *ctx)
 {
   vlib_main_t *vm = ctx;
   vnet_main_t *vnm = vnet_get_main ();
 
   vlib_cli_output (vm, " %U %s", format_vnet_sw_interface_name, vnm,
                   vnet_get_sw_interface (vnm, i->sw_if_index),
-                  nat_interface_is_inside (i) ? "in" : "out");
+                  nat66_interface_is_inside (i) ? "in" : "out");
   return 0;
 }
 
similarity index 98%
rename from src/plugins/nat/nat66_in2out.c
rename to src/plugins/nat/nat66/nat66_in2out.c
index 437d665..5a027e2 100644 (file)
@@ -17,7 +17,7 @@
  * @brief NAT66 inside to outside network translation
  */
 
-#include <nat/nat66.h>
+#include <nat/nat66/nat66.h>
 #include <vnet/ip/ip6_to_ip4.h>
 #include <vnet/fib/fib_table.h>
 
@@ -72,7 +72,7 @@ nat66_not_translate (u32 rx_fib_index, ip6_address_t ip6_addr)
 {
   nat66_main_t *nm = &nat66_main;
   u32 sw_if_index;
-  snat_interface_t *i;
+  nat66_interface_t *i;
   fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
   fib_prefix_t pfx = {
     .fp_proto = FIB_PROTOCOL_IP6,
@@ -99,7 +99,7 @@ nat66_not_translate (u32 rx_fib_index, ip6_address_t ip6_addr)
   pool_foreach (i, nm->interfaces,
   ({
     /* NAT packet aimed at outside interface */
-    if (nat_interface_is_outside (i) && sw_if_index == i->sw_if_index)
+    if (nat66_interface_is_outside (i) && sw_if_index == i->sw_if_index)
       return 0;
   }));
   /* *INDENT-ON* */
similarity index 99%
rename from src/plugins/nat/nat66_out2in.c
rename to src/plugins/nat/nat66/nat66_out2in.c
index 8386cd3..563ad6f 100644 (file)
@@ -17,7 +17,7 @@
  * @brief NAT66 outside to inside network translation
  */
 
-#include <nat/nat66.h>
+#include <nat/nat66/nat66.h>
 #include <vnet/ip/ip6_to_ip4.h>
 #include <vnet/fib/fib_table.h>
 
index 9d1ed1b..b447395 100644 (file)
@@ -21,7 +21,6 @@
 #include <nat/nat.h>
 #include <nat/nat_det.h>
 #include <nat/nat64.h>
-#include <nat/nat66.h>
 #include <nat/nat_inlines.h>
 #include <nat/nat44/inlines.h>
 #include <nat/nat_ha.h>
@@ -3035,194 +3034,6 @@ static void *vl_api_nat64_add_del_interface_addr_t_print
   FINISH;
 }
 
-/*************/
-/*** NAT66 ***/
-/*************/
-
-static void
-vl_api_nat66_add_del_interface_t_handler (vl_api_nat66_add_del_interface_t *
-                                         mp)
-{
-  snat_main_t *sm = &snat_main;
-  vl_api_nat66_add_del_interface_reply_t *rmp;
-  int rv = 0;
-
-  VALIDATE_SW_IF_INDEX (mp);
-
-  rv =
-    nat66_interface_add_del (ntohl (mp->sw_if_index),
-                            mp->flags & NAT_API_IS_INSIDE, mp->is_add);
-
-  BAD_SW_IF_INDEX_LABEL;
-
-  REPLY_MACRO (VL_API_NAT66_ADD_DEL_INTERFACE_REPLY);
-}
-
-static void *
-vl_api_nat66_add_del_interface_t_print (vl_api_nat66_add_del_interface_t * mp,
-                                       void *handle)
-{
-  u8 *s;
-
-  s = format (0, "SCRIPT: nat66_add_del_interface ");
-  s = format (s, "sw_if_index %d %s %s",
-             clib_host_to_net_u32 (mp->sw_if_index),
-             mp->flags & NAT_API_IS_INSIDE ? "in" : "out",
-             mp->is_add ? "" : "del");
-
-  FINISH;
-}
-
-static void
-  vl_api_nat66_add_del_static_mapping_t_handler
-  (vl_api_nat66_add_del_static_mapping_t * mp)
-{
-  snat_main_t *sm = &snat_main;
-  vl_api_nat66_add_del_static_mapping_reply_t *rmp;
-  ip6_address_t l_addr, e_addr;
-  int rv = 0;
-
-  memcpy (&l_addr.as_u8, mp->local_ip_address, 16);
-  memcpy (&e_addr.as_u8, mp->external_ip_address, 16);
-
-  rv =
-    nat66_static_mapping_add_del (&l_addr, &e_addr,
-                                 clib_net_to_host_u32 (mp->vrf_id),
-                                 mp->is_add);
-
-  REPLY_MACRO (VL_API_NAT66_ADD_DEL_STATIC_MAPPING_REPLY);
-}
-
-static void *vl_api_nat66_add_del_static_mapping_t_print
-  (vl_api_nat66_add_del_static_mapping_t * mp, void *handle)
-{
-  u8 *s;
-
-  s = format (0, "SCRIPT: nat66_add_del_static_mapping ");
-  s = format (s, "local_ip_address %U external_ip_address %U vrf_id %d %s",
-             format_ip6_address, mp->local_ip_address,
-             format_ip6_address, mp->external_ip_address,
-             clib_net_to_host_u32 (mp->vrf_id), mp->is_add ? "" : "del");
-
-  FINISH;
-}
-
-typedef struct nat66_api_walk_ctx_t_
-{
-  vl_api_registration_t *rp;
-  u32 context;
-} nat66_api_walk_ctx_t;
-
-static int
-nat66_api_interface_walk (snat_interface_t * i, void *arg)
-{
-  vl_api_nat66_interface_details_t *rmp;
-  snat_main_t *sm = &snat_main;
-  nat66_api_walk_ctx_t *ctx = arg;
-
-  rmp = vl_msg_api_alloc (sizeof (*rmp));
-  clib_memset (rmp, 0, sizeof (*rmp));
-  rmp->_vl_msg_id = ntohs (VL_API_NAT66_INTERFACE_DETAILS + sm->msg_id_base);
-  rmp->sw_if_index = ntohl (i->sw_if_index);
-  if (nat_interface_is_inside (i))
-    rmp->flags |= NAT_API_IS_INSIDE;
-  rmp->context = ctx->context;
-
-  vl_api_send_msg (ctx->rp, (u8 *) rmp);
-
-  return 0;
-}
-
-static void
-vl_api_nat66_interface_dump_t_handler (vl_api_nat66_interface_dump_t * mp)
-{
-  vl_api_registration_t *rp;
-
-  rp = vl_api_client_index_to_registration (mp->client_index);
-  if (rp == 0)
-    return;
-
-  nat66_api_walk_ctx_t ctx = {
-    .rp = rp,
-    .context = mp->context,
-  };
-
-  nat66_interfaces_walk (nat66_api_interface_walk, &ctx);
-}
-
-static void *
-vl_api_nat66_interface_dump_t_print (vl_api_nat66_interface_dump_t * mp,
-                                    void *handle)
-{
-  u8 *s;
-
-  s = format (0, "SCRIPT: nat66_interface_dump ");
-
-  FINISH;
-}
-
-static int
-nat66_api_static_mapping_walk (nat66_static_mapping_t * m, void *arg)
-{
-  vl_api_nat66_static_mapping_details_t *rmp;
-  nat66_main_t *nm = &nat66_main;
-  snat_main_t *sm = &snat_main;
-  nat66_api_walk_ctx_t *ctx = arg;
-  fib_table_t *fib;
-  vlib_counter_t vc;
-
-  fib = fib_table_get (m->fib_index, FIB_PROTOCOL_IP6);
-  if (!fib)
-    return -1;
-
-  vlib_get_combined_counter (&nm->session_counters, m - nm->sm, &vc);
-
-  rmp = vl_msg_api_alloc (sizeof (*rmp));
-  clib_memset (rmp, 0, sizeof (*rmp));
-  rmp->_vl_msg_id =
-    ntohs (VL_API_NAT66_STATIC_MAPPING_DETAILS + sm->msg_id_base);
-  clib_memcpy (rmp->local_ip_address, &m->l_addr, 16);
-  clib_memcpy (rmp->external_ip_address, &m->e_addr, 16);
-  rmp->vrf_id = ntohl (fib->ft_table_id);
-  rmp->total_bytes = clib_host_to_net_u64 (vc.bytes);
-  rmp->total_pkts = clib_host_to_net_u64 (vc.packets);
-  rmp->context = ctx->context;
-
-  vl_api_send_msg (ctx->rp, (u8 *) rmp);
-
-  return 0;
-}
-
-static void
-vl_api_nat66_static_mapping_dump_t_handler (vl_api_nat66_static_mapping_dump_t
-                                           * mp)
-{
-  vl_api_registration_t *rp;
-
-  rp = vl_api_client_index_to_registration (mp->client_index);
-  if (rp == 0)
-    return;
-
-  nat66_api_walk_ctx_t ctx = {
-    .rp = rp,
-    .context = mp->context,
-  };
-
-  nat66_static_mappings_walk (nat66_api_static_mapping_walk, &ctx);
-}
-
-static void *
-vl_api_nat66_static_mapping_dump_t_print (vl_api_nat66_static_mapping_dump_t *
-                                         mp, void *handle)
-{
-  u8 *s;
-
-  s = format (0, "SCRIPT: nat66_static_mapping_dump ");
-
-  FINISH;
-}
-
-
 /* List of message types that this plugin understands */
 #define foreach_snat_plugin_api_msg                                     \
 _(NAT_CONTROL_PING, nat_control_ping)                                   \
@@ -3284,11 +3095,7 @@ _(NAT64_BIB_DUMP, nat64_bib_dump)                                       \
 _(NAT64_ST_DUMP, nat64_st_dump)                                         \
 _(NAT64_ADD_DEL_PREFIX, nat64_add_del_prefix)                           \
 _(NAT64_PREFIX_DUMP, nat64_prefix_dump)                                 \
-_(NAT64_ADD_DEL_INTERFACE_ADDR, nat64_add_del_interface_addr)           \
-_(NAT66_ADD_DEL_INTERFACE, nat66_add_del_interface)                     \
-_(NAT66_INTERFACE_DUMP, nat66_interface_dump)                           \
-_(NAT66_ADD_DEL_STATIC_MAPPING, nat66_add_del_static_mapping)           \
-_(NAT66_STATIC_MAPPING_DUMP, nat66_static_mapping_dump)
+_(NAT64_ADD_DEL_INTERFACE_ADDR, nat64_add_del_interface_addr)
 
 /* Set up the API message handling tables */
 static clib_error_t *
diff --git a/src/plugins/nat/nat_types.api b/src/plugins/nat/nat_types.api
new file mode 100644 (file)
index 0000000..f348e61
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2020 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+option version = "0.0.1";
+
+enum nat_config_flags : u8
+{
+  NAT_IS_NONE = 0x00,
+  NAT_IS_TWICE_NAT = 0x01,
+  NAT_IS_SELF_TWICE_NAT = 0x02,
+  NAT_IS_OUT2IN_ONLY = 0x04,
+  NAT_IS_ADDR_ONLY = 0x08,
+  NAT_IS_OUTSIDE = 0x10,
+  NAT_IS_INSIDE = 0x20,
+  NAT_IS_STATIC = 0x40,
+  NAT_IS_EXT_HOST_VALID = 0x80,
+};
index 640e803..78c20ee 100644 (file)
@@ -9506,158 +9506,5 @@ class TestNAT64(MethodHolder):
         self.logger.info(self.vapi.cli("show nat64 session table all"))
 
 
-class TestNAT66(MethodHolder):
-    """ NAT66 Test Cases """
-
-    @classmethod
-    def setUpClass(cls):
-        super(TestNAT66, cls).setUpClass()
-
-        cls.nat_addr = 'fd01:ff::2'
-
-        cls.create_pg_interfaces(range(2))
-        cls.interfaces = list(cls.pg_interfaces)
-
-        for i in cls.interfaces:
-            i.admin_up()
-            i.config_ip6()
-            i.configure_ipv6_neighbors()
-
-    @classmethod
-    def tearDownClass(cls):
-        super(TestNAT66, cls).tearDownClass()
-
-    def test_static(self):
-        """ 1:1 NAT66 test """
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat66_add_del_interface(is_add=1, flags=flags,
-                                          sw_if_index=self.pg0.sw_if_index)
-        self.vapi.nat66_add_del_interface(is_add=1,
-                                          sw_if_index=self.pg1.sw_if_index)
-        self.vapi.nat66_add_del_static_mapping(
-            local_ip_address=self.pg0.remote_ip6,
-            external_ip_address=self.nat_addr,
-            is_add=1)
-
-        # in2out
-        pkts = []
-        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
-             IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) /
-             TCP())
-        pkts.append(p)
-        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
-             IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) /
-             UDP())
-        pkts.append(p)
-        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
-             IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) /
-             ICMPv6EchoRequest())
-        pkts.append(p)
-        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
-             IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) /
-             GRE() / IP() / TCP())
-        pkts.append(p)
-        self.pg0.add_stream(pkts)
-        self.pg_enable_capture(self.pg_interfaces)
-        self.pg_start()
-        capture = self.pg1.get_capture(len(pkts))
-
-        for packet in capture:
-            try:
-                self.assertEqual(packet[IPv6].src, self.nat_addr)
-                self.assertEqual(packet[IPv6].dst, self.pg1.remote_ip6)
-                self.assert_packet_checksums_valid(packet)
-            except:
-                self.logger.error(ppp("Unexpected or invalid packet:", packet))
-                raise
-
-        # out2in
-        pkts = []
-        p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
-             IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) /
-             TCP())
-        pkts.append(p)
-        p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
-             IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) /
-             UDP())
-        pkts.append(p)
-        p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
-             IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) /
-             ICMPv6EchoReply())
-        pkts.append(p)
-        p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
-             IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) /
-             GRE() / IP() / TCP())
-        pkts.append(p)
-        self.pg1.add_stream(pkts)
-        self.pg_enable_capture(self.pg_interfaces)
-        self.pg_start()
-        capture = self.pg0.get_capture(len(pkts))
-        for packet in capture:
-            try:
-                self.assertEqual(packet[IPv6].src, self.pg1.remote_ip6)
-                self.assertEqual(packet[IPv6].dst, self.pg0.remote_ip6)
-                self.assert_packet_checksums_valid(packet)
-            except:
-                self.logger.error(ppp("Unexpected or invalid packet:", packet))
-                raise
-
-        sm = self.vapi.nat66_static_mapping_dump()
-        self.assertEqual(len(sm), 1)
-        self.assertEqual(sm[0].total_pkts, 8)
-
-    def test_check_no_translate(self):
-        """ NAT66 translate only when egress interface is outside interface """
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat66_add_del_interface(is_add=1, flags=flags,
-                                          sw_if_index=self.pg0.sw_if_index)
-        self.vapi.nat66_add_del_interface(is_add=1, flags=flags,
-                                          sw_if_index=self.pg1.sw_if_index)
-        self.vapi.nat66_add_del_static_mapping(
-            local_ip_address=self.pg0.remote_ip6,
-            external_ip_address=self.nat_addr,
-            is_add=1)
-
-        # in2out
-        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
-             IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) /
-             UDP())
-        self.pg0.add_stream([p])
-        self.pg_enable_capture(self.pg_interfaces)
-        self.pg_start()
-        capture = self.pg1.get_capture(1)
-        packet = capture[0]
-        try:
-            self.assertEqual(packet[IPv6].src, self.pg0.remote_ip6)
-            self.assertEqual(packet[IPv6].dst, self.pg1.remote_ip6)
-        except:
-            self.logger.error(ppp("Unexpected or invalid packet:", packet))
-            raise
-
-    def clear_nat66(self):
-        """
-        Clear NAT66 configuration.
-        """
-        interfaces = self.vapi.nat66_interface_dump()
-        for intf in interfaces:
-            self.vapi.nat66_add_del_interface(is_add=0, flags=intf.flags,
-                                              sw_if_index=intf.sw_if_index)
-
-        static_mappings = self.vapi.nat66_static_mapping_dump()
-        for sm in static_mappings:
-            self.vapi.nat66_add_del_static_mapping(
-                local_ip_address=sm.local_ip_address,
-                external_ip_address=sm.external_ip_address, vrf_id=sm.vrf_id,
-                is_add=0)
-
-    def tearDown(self):
-        super(TestNAT66, self).tearDown()
-        self.clear_nat66()
-
-    def show_commands_at_teardown(self):
-        self.logger.info(self.vapi.cli("show nat66 interfaces"))
-        self.logger.info(self.vapi.cli("show nat66 static mappings"))
-
-
 if __name__ == '__main__':
     unittest.main(testRunner=VppTestRunner)
diff --git a/src/plugins/nat/test/test_nat66.py b/src/plugins/nat/test/test_nat66.py
new file mode 100644 (file)
index 0000000..bd1b50b
--- /dev/null
@@ -0,0 +1,196 @@
+#!/usr/bin/env python3
+
+import ipaddress
+import random
+import socket
+import struct
+import unittest
+from io import BytesIO
+from time import sleep
+
+import scapy.compat
+from framework import VppTestCase, VppTestRunner, running_extended_tests
+from ipfix import IPFIX, Set, Template, Data, IPFIXDecoder
+from scapy.all import bind_layers, Packet, ByteEnumField, ShortField, \
+    IPField, IntField, LongField, XByteField, FlagsField, FieldLenField, \
+    PacketListField
+from scapy.data import IP_PROTOS
+from scapy.layers.inet import IP, TCP, UDP, ICMP
+from scapy.layers.inet import IPerror, TCPerror, UDPerror, ICMPerror
+from scapy.layers.inet6 import ICMPv6DestUnreach, IPerror6, IPv6ExtHdrFragment
+from scapy.layers.inet6 import IPv6, ICMPv6EchoRequest, ICMPv6EchoReply, \
+    ICMPv6ND_NS, ICMPv6ND_NA, ICMPv6NDOptDstLLAddr, fragment6
+from scapy.layers.l2 import Ether, ARP, GRE
+from scapy.packet import Raw
+from syslog_rfc5424_parser import SyslogMessage, ParseError
+from syslog_rfc5424_parser.constants import SyslogSeverity
+from util import ip4_range
+from util import ppc, ppp
+from vpp_acl import AclRule, VppAcl, VppAclInterface
+from vpp_ip_route import VppIpRoute, VppRoutePath
+from vpp_neighbor import VppNeighbor
+from vpp_papi import VppEnum
+
+
+class MethodHolder(VppTestCase):
+    """ NAT create capture and verify method holder """
+    @property
+    def config_flags(self):
+        return VppEnum.vl_api_nat_config_flags_t
+
+
+class TestNAT66(MethodHolder):
+    """ NAT66 Test Cases """
+
+    @classmethod
+    def setUpClass(cls):
+        super(TestNAT66, cls).setUpClass()
+
+        cls.nat_addr = 'fd01:ff::2'
+
+        cls.create_pg_interfaces(range(2))
+        cls.interfaces = list(cls.pg_interfaces)
+
+        for i in cls.interfaces:
+            i.admin_up()
+            i.config_ip6()
+            i.configure_ipv6_neighbors()
+
+    @classmethod
+    def tearDownClass(cls):
+        super(TestNAT66, cls).tearDownClass()
+
+    def test_static(self):
+        """ 1:1 NAT66 test """
+        flags = self.config_flags.NAT_IS_INSIDE
+        self.vapi.nat66_add_del_interface(is_add=1, flags=flags,
+                                          sw_if_index=self.pg0.sw_if_index)
+        self.vapi.nat66_add_del_interface(is_add=1,
+                                          sw_if_index=self.pg1.sw_if_index)
+        self.vapi.nat66_add_del_static_mapping(
+            local_ip_address=self.pg0.remote_ip6,
+            external_ip_address=self.nat_addr,
+            is_add=1)
+
+        # in2out
+        pkts = []
+        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
+             IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) /
+             TCP())
+        pkts.append(p)
+        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
+             IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) /
+             UDP())
+        pkts.append(p)
+        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
+             IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) /
+             ICMPv6EchoRequest())
+        pkts.append(p)
+        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
+             IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) /
+             GRE() / IP() / TCP())
+        pkts.append(p)
+        self.pg0.add_stream(pkts)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+        capture = self.pg1.get_capture(len(pkts))
+
+        for packet in capture:
+            try:
+                self.assertEqual(packet[IPv6].src, self.nat_addr)
+                self.assertEqual(packet[IPv6].dst, self.pg1.remote_ip6)
+                self.assert_packet_checksums_valid(packet)
+            except:
+                self.logger.error(ppp("Unexpected or invalid packet:", packet))
+                raise
+
+        # out2in
+        pkts = []
+        p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
+             IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) /
+             TCP())
+        pkts.append(p)
+        p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
+             IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) /
+             UDP())
+        pkts.append(p)
+        p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
+             IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) /
+             ICMPv6EchoReply())
+        pkts.append(p)
+        p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
+             IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) /
+             GRE() / IP() / TCP())
+        pkts.append(p)
+        self.pg1.add_stream(pkts)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+        capture = self.pg0.get_capture(len(pkts))
+        for packet in capture:
+            try:
+                self.assertEqual(packet[IPv6].src, self.pg1.remote_ip6)
+                self.assertEqual(packet[IPv6].dst, self.pg0.remote_ip6)
+                self.assert_packet_checksums_valid(packet)
+            except:
+                self.logger.error(ppp("Unexpected or invalid packet:", packet))
+                raise
+
+        sm = self.vapi.nat66_static_mapping_dump()
+        self.assertEqual(len(sm), 1)
+        self.assertEqual(sm[0].total_pkts, 8)
+
+    def test_check_no_translate(self):
+        """ NAT66 translate only when egress interface is outside interface """
+        flags = self.config_flags.NAT_IS_INSIDE
+        self.vapi.nat66_add_del_interface(is_add=1, flags=flags,
+                                          sw_if_index=self.pg0.sw_if_index)
+        self.vapi.nat66_add_del_interface(is_add=1, flags=flags,
+                                          sw_if_index=self.pg1.sw_if_index)
+        self.vapi.nat66_add_del_static_mapping(
+            local_ip_address=self.pg0.remote_ip6,
+            external_ip_address=self.nat_addr,
+            is_add=1)
+
+        # in2out
+        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
+             IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) /
+             UDP())
+        self.pg0.add_stream([p])
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+        capture = self.pg1.get_capture(1)
+        packet = capture[0]
+        try:
+            self.assertEqual(packet[IPv6].src, self.pg0.remote_ip6)
+            self.assertEqual(packet[IPv6].dst, self.pg1.remote_ip6)
+        except:
+            self.logger.error(ppp("Unexpected or invalid packet:", packet))
+            raise
+
+    def clear_nat66(self):
+        """
+        Clear NAT66 configuration.
+        """
+        interfaces = self.vapi.nat66_interface_dump()
+        for intf in interfaces:
+            self.vapi.nat66_add_del_interface(is_add=0, flags=intf.flags,
+                                              sw_if_index=intf.sw_if_index)
+
+        static_mappings = self.vapi.nat66_static_mapping_dump()
+        for sm in static_mappings:
+            self.vapi.nat66_add_del_static_mapping(
+                local_ip_address=sm.local_ip_address,
+                external_ip_address=sm.external_ip_address, vrf_id=sm.vrf_id,
+                is_add=0)
+
+    def tearDown(self):
+        super(TestNAT66, self).tearDown()
+        self.clear_nat66()
+
+    def show_commands_at_teardown(self):
+        self.logger.info(self.vapi.cli("show nat66 interfaces"))
+        self.logger.info(self.vapi.cli("show nat66 static mappings"))
+
+
+if __name__ == '__main__':
+    unittest.main(testRunner=VppTestRunner)