nat: "users" dump for ED-NAT 43/27043/3
authorKlement Sekera <ksekera@cisco.com>
Wed, 13 May 2020 11:35:57 +0000 (11:35 +0000)
committerOle Trøan <otroan@employees.org>
Thu, 14 May 2020 12:47:12 +0000 (12:47 +0000)
Since the removal of "users" concept in ED-NAT nat44_user_dump API
returns empty array. This brings back previous behaviour at
a considerable runtime cost until a better API is introduced.

Type: improvement
Change-Id: I5a45923cfeb6b8ebe6fc906601264d6567386991
Signed-off-by: Klement Sekera <ksekera@cisco.com>
src/plugins/nat/nat.h
src/plugins/nat/nat_api.c
src/plugins/nat/test/test_nat.py
test/requirements-3.txt

index d0882e0..8ec0c62 100644 (file)
@@ -1428,6 +1428,7 @@ typedef struct
   u16 src_port, dst_port;
 } tcp_udp_header_t;
 
+u8 *format_user_kvp (u8 * s, va_list * args);
 #endif /* __included_nat_h__ */
 /*
  * fd.io coding-style-patch-verification: ON
index 37af77d..201c9d4 100644 (file)
@@ -1585,6 +1585,62 @@ send_nat44_user_details (snat_user_t * u, vl_api_registration_t * reg,
   vl_api_send_msg (reg, (u8 *) rmp);
 }
 
+static void
+nat_ed_user_create_helper (snat_main_per_thread_data_t * tsm,
+                          snat_session_t * s)
+{
+  snat_user_key_t k;
+  k.addr = s->in2out.addr;
+  k.fib_index = s->in2out.fib_index;
+  clib_bihash_kv_8_8_t key, value;
+  key.key = k.as_u64;
+  snat_user_t *u;
+  if (clib_bihash_search_8_8 (&tsm->user_hash, &key, &value))
+    {
+      pool_get (tsm->users, u);
+      u->addr = k.addr;
+      u->fib_index = k.fib_index;
+      u->nsessions = 0;
+      u->nstaticsessions = 0;
+      key.value = u - tsm->users;
+      clib_bihash_add_del_8_8 (&tsm->user_hash, &key, 1);
+    }
+  else
+    {
+      u = pool_elt_at_index (tsm->users, value.value);
+    }
+  if (snat_is_session_static (s))
+    {
+      ++u->nstaticsessions;
+    }
+  else
+    {
+      ++u->nsessions;
+    }
+}
+
+static void
+nat_ed_users_create (snat_main_per_thread_data_t * tsm)
+{
+  snat_session_t *s;
+  /* *INDENT-OFF* */
+  pool_foreach (s, tsm->sessions, { nat_ed_user_create_helper (tsm, s); });
+  /* *INDENT-ON* */
+}
+
+static void
+nat_ed_users_destroy (snat_main_per_thread_data_t * tsm)
+{
+  snat_user_t *u;
+  /* *INDENT-OFF* */
+  pool_flush (u, tsm->users, { });
+  /* *INDENT-ON* */
+  clib_bihash_free_8_8 (&tsm->user_hash);
+  clib_bihash_init_8_8 (&tsm->user_hash, "users", snat_main.user_buckets,
+                       snat_main.user_memory_size);
+  clib_bihash_set_kvp_format_fn_8_8 (&tsm->user_hash, format_user_kvp);
+}
+
 static void
 vl_api_nat44_user_dump_t_handler (vl_api_nat44_user_dump_t * mp)
 {
@@ -1603,10 +1659,18 @@ vl_api_nat44_user_dump_t_handler (vl_api_nat44_user_dump_t * mp)
   /* *INDENT-OFF* */
   vec_foreach (tsm, sm->per_thread_data)
     {
+      if (sm->endpoint_dependent)
+       {
+         nat_ed_users_create (tsm);
+       }
       pool_foreach (u, tsm->users,
       ({
         send_nat44_user_details (u, reg, mp->context);
       }));
+      if (sm->endpoint_dependent)
+       {
+         nat_ed_users_destroy (tsm);
+       }
     }
   /* *INDENT-ON* */
 }
index 1b3c7e7..c2f5f51 100644 (file)
@@ -7090,6 +7090,111 @@ class TestNAT44EndpointDependent(MethodHolder):
         capture = self.pg2.get_capture(1)
         self.verify_syslog_sess(capture[0][Raw].load, False)
 
+    def test_ed_users_dump(self):
+        """ API test - nat44_user_dump """
+        flags = self.config_flags.NAT_IS_INSIDE
+        self.vapi.nat44_interface_add_del_feature(
+            sw_if_index=self.pg0.sw_if_index,
+            flags=flags, is_add=1)
+        self.vapi.nat44_interface_add_del_feature(
+            sw_if_index=self.pg1.sw_if_index,
+            is_add=1)
+        self.vapi.nat44_forwarding_enable_disable(enable=1)
+
+        real_ip = self.pg0.remote_ip4
+        alias_ip = self.nat_addr
+        flags = self.config_flags.NAT_IS_ADDR_ONLY
+        self.vapi.nat44_add_del_static_mapping(is_add=1,
+                                               local_ip_address=real_ip,
+                                               external_ip_address=alias_ip,
+                                               external_sw_if_index=0xFFFFFFFF,
+                                               flags=flags)
+
+        users = self.vapi.nat44_user_dump()
+        self.assertEqual(len(users), 0)
+        try:
+            # in2out - static mapping match
+
+            pkts = self.create_stream_out(self.pg1)
+            self.pg1.add_stream(pkts)
+            self.pg_enable_capture(self.pg_interfaces)
+            self.pg_start()
+            capture = self.pg0.get_capture(len(pkts))
+            self.verify_capture_in(capture, self.pg0)
+
+            pkts = self.create_stream_in(self.pg0, self.pg1)
+            self.pg0.add_stream(pkts)
+            self.pg_enable_capture(self.pg_interfaces)
+            self.pg_start()
+            capture = self.pg1.get_capture(len(pkts))
+            self.verify_capture_out(capture, same_port=True)
+
+            users = self.vapi.nat44_user_dump()
+            self.assertEqual(len(users), 1)
+            static_user = users[0]
+            self.assertEqual(static_user.nstaticsessions, 3)
+            self.assertEqual(static_user.nsessions, 0)
+
+            # in2out - no static mapping match
+
+            host0 = self.pg0.remote_hosts[0]
+            self.pg0.remote_hosts[0] = self.pg0.remote_hosts[1]
+            try:
+                pkts = self.create_stream_out(self.pg1,
+                                              dst_ip=self.pg0.remote_ip4,
+                                              use_inside_ports=True)
+                self.pg1.add_stream(pkts)
+                self.pg_enable_capture(self.pg_interfaces)
+                self.pg_start()
+                capture = self.pg0.get_capture(len(pkts))
+                self.verify_capture_in(capture, self.pg0)
+
+                pkts = self.create_stream_in(self.pg0, self.pg1)
+                self.pg0.add_stream(pkts)
+                self.pg_enable_capture(self.pg_interfaces)
+                self.pg_start()
+                capture = self.pg1.get_capture(len(pkts))
+                self.verify_capture_out(capture, nat_ip=self.pg0.remote_ip4,
+                                        same_port=True)
+            finally:
+                self.pg0.remote_hosts[0] = host0
+
+            users = self.vapi.nat44_user_dump()
+            self.assertEqual(len(users), 2)
+            if str(users[0].ip_address) == self.pg0.remote_hosts[0].ip4:
+                non_static_user = users[1]
+                static_user = users[0]
+            else:
+                non_static_user = users[0]
+                static_user = users[1]
+            self.assertEqual(static_user.nstaticsessions, 3)
+            self.assertEqual(static_user.nsessions, 0)
+            self.assertEqual(non_static_user.nstaticsessions, 0)
+            self.assertEqual(non_static_user.nsessions, 3)
+
+            users = self.vapi.nat44_user_dump()
+            self.assertEqual(len(users), 2)
+            if str(users[0].ip_address) == self.pg0.remote_hosts[0].ip4:
+                non_static_user = users[1]
+                static_user = users[0]
+            else:
+                non_static_user = users[0]
+                static_user = users[1]
+            self.assertEqual(static_user.nstaticsessions, 3)
+            self.assertEqual(static_user.nsessions, 0)
+            self.assertEqual(non_static_user.nstaticsessions, 0)
+            self.assertEqual(non_static_user.nsessions, 3)
+
+        finally:
+            self.vapi.nat44_forwarding_enable_disable(enable=0)
+            flags = self.config_flags.NAT_IS_ADDR_ONLY
+            self.vapi.nat44_add_del_static_mapping(
+                is_add=0,
+                local_ip_address=real_ip,
+                external_ip_address=alias_ip,
+                external_sw_if_index=0xFFFFFFFF,
+                flags=flags)
+
     def tearDown(self):
         super(TestNAT44EndpointDependent, self).tearDown()
         if not self.vpp_dead:
index a32dc6e..a77c089 100644 (file)
@@ -258,4 +258,4 @@ urllib3==1.25.8 \
 
 # WARNING: The following packages were not pinned, but pip requires them to be
 # pinned when the requirements file includes hashes. Consider using the --allow-unsafe flag.
-# setuptools==46.1.3        # via sphinx
+# setuptools==46.2.0        # via sphinx