NAT44: Apply transitory timeout on TCP RST (VPP-1494) 94/16094/2
authorMatus Fabian <matfabia@cisco.com>
Wed, 21 Nov 2018 12:53:10 +0000 (04:53 -0800)
committerOle Trøan <otroan@employees.org>
Thu, 22 Nov 2018 06:29:52 +0000 (06:29 +0000)
RFC7857 section 2.2.

Change-Id: I031af5fe379b72262e83fd8565c34fa1b772f2c8
Signed-off-by: Matus Fabian <matfabia@cisco.com>
src/plugins/nat/nat.h
src/plugins/nat/nat_inlines.h
test/test_nat.py

index 02d4aae..3162e41 100644 (file)
@@ -165,6 +165,7 @@ typedef enum
 #define NAT44_SES_O2I_FIN_ACK 8
 #define NAT44_SES_I2O_SYN 16
 #define NAT44_SES_O2I_SYN 32
+#define NAT44_SES_RST     64
 
 /* Session flags */
 #define SNAT_SESSION_FLAG_STATIC_MAPPING       1
index 0b4f810..38cfc37 100644 (file)
@@ -200,6 +200,10 @@ always_inline int
 nat44_set_tcp_session_state_i2o (snat_main_t * sm, snat_session_t * ses,
                                 tcp_header_t * tcp, u32 thread_index)
 {
+  if ((ses->state == 0) && (tcp->flags & TCP_FLAG_RST))
+    ses->state = NAT44_SES_RST;
+  if ((ses->state == NAT44_SES_RST) && !(tcp->flags & TCP_FLAG_RST))
+    ses->state = 0;
   if ((tcp->flags & TCP_FLAG_ACK) && (ses->state & NAT44_SES_I2O_SYN) &&
       (ses->state & NAT44_SES_O2I_SYN))
     ses->state = 0;
@@ -231,6 +235,10 @@ always_inline int
 nat44_set_tcp_session_state_o2i (snat_main_t * sm, snat_session_t * ses,
                                 tcp_header_t * tcp, u32 thread_index)
 {
+  if ((ses->state == 0) && (tcp->flags & TCP_FLAG_RST))
+    ses->state = NAT44_SES_RST;
+  if ((ses->state == NAT44_SES_RST) && !(tcp->flags & TCP_FLAG_RST))
+    ses->state = 0;
   if ((tcp->flags & TCP_FLAG_ACK) && (ses->state & NAT44_SES_I2O_SYN) &&
       (ses->state & NAT44_SES_O2I_SYN))
     ses->state = 0;
index bc47623..d3849da 100644 (file)
@@ -5674,6 +5674,57 @@ class TestNAT44EndpointDependent(MethodHolder):
             nsessions = nsessions + user.nsessions
         self.assertLess(nsessions, 2 * max_sessions)
 
+    @unittest.skipUnless(running_extended_tests(), "part of extended tests")
+    def test_session_rst_timeout(self):
+        """ NAT44 session RST timeouts """
+        self.nat44_add_address(self.nat_addr)
+        self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
+        self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
+                                                  is_inside=0)
+        self.vapi.nat_set_timeouts(tcp_transitory=5)
+
+        nat44_config = self.vapi.nat_show_config()
+
+        self.initiate_tcp_session(self.pg0, self.pg1)
+        p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
+             IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
+             TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
+                 flags="R"))
+        self.pg0.add_stream(p)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+        self.pg1.get_capture(1)
+
+        pkts_num = nat44_config.max_translations_per_user - 1
+        pkts = []
+        for i in range(0, pkts_num):
+            p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
+                 IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
+                 UDP(sport=1025 + i, dport=53))
+            pkts.append(p)
+        self.pg0.add_stream(pkts)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+        self.pg1.get_capture(pkts_num)
+
+        sleep(6)
+
+        p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
+             IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
+             TCP(sport=self.tcp_port_in + 1, dport=self.tcp_external_port + 1,
+                 flags="S"))
+        self.pg0.add_stream(p)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+        self.pg1.get_capture(1)
+
+        nsessions = 0
+        users = self.vapi.nat44_user_dump()
+        self.assertEqual(len(users), 1)
+        self.assertEqual(users[0].ip_address, self.pg0.remote_ip4n)
+        self.assertEqual(users[0].nsessions,
+                         nat44_config.max_translations_per_user)
+
     @unittest.skipUnless(running_extended_tests(), "part of extended tests")
     def test_session_limit_per_user(self):
         """ Maximum sessions per user limit """