CGN: Session dump, test naming for ports fixed 51/6451/2
authorMartin Gálik <magalik@cisco.com>
Tue, 25 Apr 2017 08:25:08 +0000 (01:25 -0700)
committerMartin Gálik <magalik@cisco.com>
Wed, 26 Apr 2017 12:17:42 +0000 (05:17 -0700)
Change-Id: Ib542b2b3ee023fbe3d0e01ceaf4b4ab7a0ec80dc
Signed-off-by: Martin Gálik <magalik@cisco.com>
src/plugins/snat/snat.api
src/plugins/snat/snat.c
src/plugins/snat/snat_test.c
test/test_snat.py
test/vpp_papi_provider.py

index 5990eae..e92675d 100644 (file)
@@ -565,3 +565,38 @@ autoreply define snat_det_close_session_in {
   u8 ext_addr[16];
   u16 ext_port;
 };
+
+/** \brief Dump S-NAT deterministic sessions
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param is_ip4 - 1 if address type is IPv4
+    @param user_addr - address of an inside user whose sessions to dump
+*/
+define snat_det_session_dump {
+  u32 client_index;
+  u32 context;
+  u8 is_ip4;
+  u8 user_addr[16];
+};
+
+/** \brief S-NAT deterministic sessions reply
+    @param context - sender context, to match reply w/ request
+    @param is_ip4 - 1 if address type is IPv4
+    @param in_port - inside port
+    @param ext_addr - external host address
+    @param ext_port - external host port
+    @param out_port - outside NAT port
+    @param state - session state
+    @param expire - session expiration timestamp
+*/
+define snat_det_session_details {
+  u32 client_index;
+  u32 context;
+  u8 is_ip4;
+  u16 in_port;
+  u8 ext_addr[16];
+  u16 ext_port;
+  u16 out_port;
+  u8 state;
+  u32 expire;
+};
index 594afa6..c6783e4 100644 (file)
@@ -1811,6 +1811,72 @@ static void *vl_api_snat_det_close_session_in_t_print
   FINISH;
 }
 
+static void
+send_snat_det_session_details
+(snat_det_session_t * s, unix_shared_memory_queue_t * q, u32 context)
+{
+  vl_api_snat_det_session_details_t * rmp;
+  snat_main_t * sm = &snat_main;
+
+  rmp = vl_msg_api_alloc (sizeof (*rmp));
+  memset (rmp, 0, sizeof (*rmp));
+  rmp->_vl_msg_id = ntohs (VL_API_SNAT_DET_SESSION_DETAILS+sm->msg_id_base);
+  rmp->is_ip4 = 1;
+  rmp->in_port = s->in_port;
+  clib_memcpy (rmp->ext_addr, &s->out.ext_host_addr, 4);
+  rmp->ext_port = s->out.ext_host_port;
+  rmp->out_port = s->out.out_port;
+  rmp->state = s->state;
+  rmp->expire = ntohl (s->expire);
+  rmp->context = context;
+
+  vl_msg_api_send_shmem (q, (u8 *) & rmp);
+}
+
+static void
+vl_api_snat_det_session_dump_t_handler
+(vl_api_snat_det_session_dump_t * mp)
+{
+  unix_shared_memory_queue_t *q;
+  snat_main_t * sm = &snat_main;
+  ip4_address_t user_addr;
+  snat_det_map_t * dm;
+  snat_det_session_t * s, empty_ses;
+  u16 i;
+
+  q = vl_api_client_index_to_input_queue (mp->client_index);
+  if (q == 0)
+    return;
+  if (!mp->is_ip4)
+    return;
+
+  memset (&empty_ses, 0, sizeof (empty_ses));
+  clib_memcpy (&user_addr, mp->user_addr, 4);
+  dm = snat_det_map_by_user (sm, &user_addr);
+  if (!dm)
+    return;
+
+  s = dm->sessions + snat_det_user_ses_offset (&user_addr, dm->in_plen);
+  for (i = 0; i < SNAT_DET_SES_PER_USER; i++)
+    {
+      if (s->out.as_u64)
+        send_snat_det_session_details (s, q, mp->context);
+      s++;
+    }
+}
+
+static void *vl_api_snat_det_session_dump_t_print
+(vl_api_snat_det_session_dump_t * mp, void * handle)
+{
+  u8 *s;
+
+  s = format (0, "SCRIPT: snat_det_session_dump ");
+  s = format (s, "user_addr %U\n",
+              format_ip4_address, mp->user_addr);
+
+  FINISH;
+}
+
 /* List of message types that this plugin understands */
 #define foreach_snat_plugin_api_msg                                     \
 _(SNAT_ADD_ADDRESS_RANGE, snat_add_address_range)                       \
@@ -1835,7 +1901,8 @@ _(SNAT_DET_MAP_DUMP, snat_det_map_dump)                                 \
 _(SNAT_DET_SET_TIMEOUTS, snat_det_set_timeouts)                         \
 _(SNAT_DET_GET_TIMEOUTS, snat_det_get_timeouts)                         \
 _(SNAT_DET_CLOSE_SESSION_OUT, snat_det_close_session_out)               \
-_(SNAT_DET_CLOSE_SESSION_IN, snat_det_close_session_in)
+_(SNAT_DET_CLOSE_SESSION_IN, snat_det_close_session_in)                 \
+_(SNAT_DET_SESSION_DUMP, snat_det_session_dump)
 
 
 /* Set up the API message handling tables */
index 14e8d19..905b8fa 100644 (file)
@@ -121,7 +121,8 @@ _(SNAT_DET_GET_TIMEOUTS_REPLY, snat_det_get_timeouts_reply)     \
 _(SNAT_DET_CLOSE_SESSION_OUT_REPLY,                             \
   snat_det_close_session_out_reply)                             \
 _(SNAT_DET_CLOSE_SESSION_IN_REPLY,                              \
-  snat_det_close_session_in_reply)
+  snat_det_close_session_in_reply)                              \
+_(SNAT_DET_SESSION_DETAILS, snat_det_session_details)
 
 static int api_snat_add_address_range (vat_main_t * vam)
 {
@@ -1033,6 +1034,52 @@ static int api_snat_det_close_session_in (vat_main_t * vam)
   return ret;
 }
 
+static void vl_api_snat_det_session_details_t_handler
+  (vl_api_snat_det_session_details_t *mp)
+{
+  snat_test_main_t * sm = &snat_test_main;
+  vat_main_t *vam = sm->vat_main;
+
+  fformat(vam->ofp, "deterministic session, external host address %U, "
+                    "external host port %d, outer port %d, inside port %d",
+          format_ip4_address, mp->ext_addr, mp->ext_port,
+          mp->out_port, mp->in_port);
+}
+
+static int api_snat_det_session_dump(vat_main_t * vam)
+{
+  unformat_input_t* i = vam->input;
+  vl_api_snat_det_session_dump_t * mp;
+  vl_api_snat_control_ping_t *mp_ping;
+  ip4_address_t user_addr;
+  int ret;
+
+  if (vam->json_output)
+    {
+      clib_warning ("JSON output not supported for snat_det_session_dump");
+      return -99;
+    }
+
+  if (unformat (i, "user_addr %U", unformat_ip4_address, &user_addr))
+    ;
+  else
+    {
+      clib_warning ("unknown input '%U'", format_unformat_error, i);
+      return -99;
+    }
+
+  M(SNAT_DET_SESSION_DUMP, mp);
+  clib_memcpy (&mp->user_addr, &user_addr, 4);
+  S(mp);
+
+  /* Use a control ping for synchronization */
+  M(SNAT_CONTROL_PING, mp_ping);
+  S(mp_ping);
+
+  W (ret);
+  return ret;
+}
+
 /* 
  * List of messages that the api test plugin sends,
  * and that the data plane plugin processes
@@ -1069,7 +1116,8 @@ _(snat_det_get_timeouts, "")                                     \
 _(snat_det_close_session_out, "<out_addr>:<out_port> "           \
   "<ext_addr>:<ext_port>")                                       \
 _(snat_det_close_session_in, "<in_addr>:<in_port> "              \
-  "<out_addr>:<out_port>")
+  "<out_addr>:<out_port>")                                       \
+_(snat_det_session_dump, "ip_address <user_addr>")
 
 static void 
 snat_vat_api_hookup (vat_main_t *vam)
index fe5af41..f90d906 100644 (file)
@@ -1332,9 +1332,9 @@ class TestDeterministicNAT(MethodHolder):
 
         try:
             cls.tcp_port_in = 6303
-            cls.tcp_port_out = 6303
+            cls.tcp_external_port = 6303
             cls.udp_port_in = 6304
-            cls.udp_port_out = 6304
+            cls.udp_external_port = 6304
             cls.icmp_id_in = 6305
             cls.snat_addr = '10.0.0.3'
 
@@ -1365,13 +1365,13 @@ class TestDeterministicNAT(MethodHolder):
         # TCP
         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
              IP(src=in_if.remote_ip4, dst=out_if.remote_ip4, ttl=ttl) /
-             TCP(sport=self.tcp_port_in, dport=self.tcp_port_out))
+             TCP(sport=self.tcp_port_in, dport=self.tcp_external_port))
         pkts.append(p)
 
         # UDP
         p = (Ether(dst=in_if.local_mac, src=in_if.remote_mac) /
              IP(src=in_if.remote_ip4, dst=out_if.remote_ip4, ttl=ttl) /
-             UDP(sport=self.udp_port_in, dport=self.udp_port_out))
+             UDP(sport=self.udp_port_in, dport=self.udp_external_port))
         pkts.append(p)
 
         # ICMP
@@ -1396,13 +1396,13 @@ class TestDeterministicNAT(MethodHolder):
         # TCP
         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
              IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
-             TCP(dport=self.tcp_external_port, sport=self.tcp_port_out))
+             TCP(dport=self.tcp_port_out, sport=self.tcp_external_port))
         pkts.append(p)
 
         # UDP
         p = (Ether(dst=out_if.local_mac, src=out_if.remote_mac) /
              IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl) /
-             UDP(dport=self.udp_external_port, sport=self.udp_port_out))
+             UDP(dport=self.udp_port_out, sport=self.udp_external_port))
         pkts.append(p)
 
         # ICMP
@@ -1429,9 +1429,9 @@ class TestDeterministicNAT(MethodHolder):
             try:
                 self.assertEqual(packet[IP].src, nat_ip)
                 if packet.haslayer(TCP):
-                    self.tcp_external_port = packet[TCP].sport
+                    self.tcp_port_out = packet[TCP].sport
                 elif packet.haslayer(UDP):
-                    self.udp_external_port = packet[UDP].sport
+                    self.udp_port_out = packet[UDP].sport
                 else:
                     self.icmp_external_id = packet[ICMP].id
             except:
@@ -1450,19 +1450,19 @@ class TestDeterministicNAT(MethodHolder):
             # SYN packet in->out
             p = (Ether(src=in_if.remote_mac, dst=in_if.local_mac) /
                  IP(src=in_if.remote_ip4, dst=out_if.remote_ip4) /
-                 TCP(sport=self.tcp_port_in, dport=self.tcp_port_out,
+                 TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
                      flags="S"))
             in_if.add_stream(p)
             self.pg_enable_capture(self.pg_interfaces)
             self.pg_start()
             capture = out_if.get_capture(1)
             p = capture[0]
-            self.tcp_external_port = p[TCP].sport
+            self.tcp_port_out = p[TCP].sport
 
             # SYN + ACK packet out->in
             p = (Ether(src=out_if.remote_mac, dst=out_if.local_mac) /
                  IP(src=out_if.remote_ip4, dst=self.snat_addr) /
-                 TCP(sport=self.tcp_port_out, dport=self.tcp_external_port,
+                 TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
                      flags="SA"))
             out_if.add_stream(p)
             self.pg_enable_capture(self.pg_interfaces)
@@ -1472,7 +1472,7 @@ class TestDeterministicNAT(MethodHolder):
             # ACK packet in->out
             p = (Ether(src=in_if.remote_mac, dst=in_if.local_mac) /
                  IP(src=in_if.remote_ip4, dst=out_if.remote_ip4) /
-                 TCP(sport=self.tcp_port_in, dport=self.tcp_port_out,
+                 TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
                      flags="A"))
             in_if.add_stream(p)
             self.pg_enable_capture(self.pg_interfaces)
@@ -1553,12 +1553,6 @@ class TestDeterministicNAT(MethodHolder):
         """ CGNAT translation test (TCP, UDP, ICMP) """
 
         nat_ip = "10.0.0.10"
-        self.tcp_port_out = 6303
-        self.udp_port_out = 6304
-        self.icmp_id_in = 6305
-        self.tcp_external_port = 7303
-        self.udp_external_port = 7304
-        self.icmp_id_out = 7305
 
         self.vapi.snat_add_det_map(self.pg0.remote_ip4n,
                                    32,
@@ -1584,12 +1578,36 @@ class TestDeterministicNAT(MethodHolder):
         capture = self.pg0.get_capture(len(pkts))
         self.verify_capture_in(capture, self.pg0)
 
+        # session dump test
+        sessions = self.vapi.snat_det_session_dump(self.pg0.remote_ip4n)
+        self.assertEqual(len(sessions), 3)
+
+        # TCP session
+        s = sessions[0]
+        self.assertEqual(s.ext_addr[:4], self.pg1.remote_ip4n)
+        self.assertEqual(s.in_port, self.tcp_port_in)
+        self.assertEqual(s.out_port, self.tcp_port_out)
+        self.assertEqual(s.ext_port, self.tcp_external_port)
+
+        # UDP session
+        s = sessions[1]
+        self.assertEqual(s.ext_addr[:4], self.pg1.remote_ip4n)
+        self.assertEqual(s.in_port, self.udp_port_in)
+        self.assertEqual(s.out_port, self.udp_port_out)
+        self.assertEqual(s.ext_port, self.udp_external_port)
+
+        # ICMP session
+        s = sessions[2]
+        self.assertEqual(s.ext_addr[:4], self.pg1.remote_ip4n)
+        self.assertEqual(s.in_port, self.icmp_id_in)
+        self.assertEqual(s.out_port, self.icmp_external_id)
+
     def test_multiple_users(self):
         """ CGNAT multiple users """
 
         nat_ip = "10.0.0.10"
         port_in = 80
-        port_out = 6303
+        external_port = 6303
 
         host0 = self.pg0.remote_hosts[0]
         host1 = self.pg0.remote_hosts[1]
@@ -1605,7 +1623,7 @@ class TestDeterministicNAT(MethodHolder):
         # host0 to out
         p = (Ether(src=host0.mac, dst=self.pg0.local_mac) /
              IP(src=host0.ip4, dst=self.pg1.remote_ip4) /
-             TCP(sport=port_in, dport=port_out))
+             TCP(sport=port_in, dport=external_port))
         self.pg0.add_stream(p)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
@@ -1616,8 +1634,8 @@ class TestDeterministicNAT(MethodHolder):
             tcp = p[TCP]
             self.assertEqual(ip.src, nat_ip)
             self.assertEqual(ip.dst, self.pg1.remote_ip4)
-            self.assertEqual(tcp.dport, port_out)
-            external_port0 = tcp.sport
+            self.assertEqual(tcp.dport, external_port)
+            port_out0 = tcp.sport
         except:
             self.logger.error(ppp("Unexpected or invalid packet:", p))
             raise
@@ -1625,7 +1643,7 @@ class TestDeterministicNAT(MethodHolder):
         # host1 to out
         p = (Ether(src=host1.mac, dst=self.pg0.local_mac) /
              IP(src=host1.ip4, dst=self.pg1.remote_ip4) /
-             TCP(sport=port_in, dport=port_out))
+             TCP(sport=port_in, dport=external_port))
         self.pg0.add_stream(p)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
@@ -1636,8 +1654,8 @@ class TestDeterministicNAT(MethodHolder):
             tcp = p[TCP]
             self.assertEqual(ip.src, nat_ip)
             self.assertEqual(ip.dst, self.pg1.remote_ip4)
-            self.assertEqual(tcp.dport, port_out)
-            external_port1 = tcp.sport
+            self.assertEqual(tcp.dport, external_port)
+            port_out1 = tcp.sport
         except:
             self.logger.error(ppp("Unexpected or invalid packet:", p))
             raise
@@ -1649,7 +1667,7 @@ class TestDeterministicNAT(MethodHolder):
         # out to host0
         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
              IP(src=self.pg1.remote_ip4, dst=nat_ip) /
-             TCP(sport=port_out, dport=external_port0))
+             TCP(sport=external_port, dport=port_out0))
         self.pg1.add_stream(p)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
@@ -1661,7 +1679,7 @@ class TestDeterministicNAT(MethodHolder):
             self.assertEqual(ip.src, self.pg1.remote_ip4)
             self.assertEqual(ip.dst, host0.ip4)
             self.assertEqual(tcp.dport, port_in)
-            self.assertEqual(tcp.sport, port_out)
+            self.assertEqual(tcp.sport, external_port)
         except:
             self.logger.error(ppp("Unexpected or invalid packet:", p))
             raise
@@ -1669,7 +1687,7 @@ class TestDeterministicNAT(MethodHolder):
         # out to host1
         p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
              IP(src=self.pg1.remote_ip4, dst=nat_ip) /
-             TCP(sport=port_out, dport=external_port1))
+             TCP(sport=external_port, dport=port_out1))
         self.pg1.add_stream(p)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
@@ -1681,23 +1699,23 @@ class TestDeterministicNAT(MethodHolder):
             self.assertEqual(ip.src, self.pg1.remote_ip4)
             self.assertEqual(ip.dst, host1.ip4)
             self.assertEqual(tcp.dport, port_in)
-            self.assertEqual(tcp.sport, port_out)
+            self.assertEqual(tcp.sport, external_port)
         except:
             self.logger.error(ppp("Unexpected or invalid packet", p))
             raise
 
         # session close api test
         self.vapi.snat_det_close_session_out(socket.inet_aton(nat_ip),
-                                             external_port1,
+                                             port_out1,
                                              self.pg1.remote_ip4n,
-                                             port_out)
+                                             external_port)
         dms = self.vapi.snat_det_map_dump()
         self.assertEqual(dms[0].ses_num, 1)
 
         self.vapi.snat_det_close_session_in(host0.ip4n,
                                             port_in,
                                             self.pg1.remote_ip4n,
-                                            port_out)
+                                            external_port)
         dms = self.vapi.snat_det_map_dump()
         self.assertEqual(dms[0].ses_num, 0)
 
@@ -1718,7 +1736,7 @@ class TestDeterministicNAT(MethodHolder):
             # FIN packet in -> out
             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_port_out,
+                 TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
                      flags="F"))
             self.pg0.add_stream(p)
             self.pg_enable_capture(self.pg_interfaces)
@@ -1730,14 +1748,14 @@ class TestDeterministicNAT(MethodHolder):
             # ACK packet out -> in
             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
                  IP(src=self.pg1.remote_ip4, dst=self.snat_addr) /
-                 TCP(sport=self.tcp_port_out, dport=self.tcp_external_port,
+                 TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
                      flags="A"))
             pkts.append(p)
 
             # FIN packet out -> in
             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
                  IP(src=self.pg1.remote_ip4, dst=self.snat_addr) /
-                 TCP(sport=self.tcp_port_out, dport=self.tcp_external_port,
+                 TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
                      flags="F"))
             pkts.append(p)
 
@@ -1749,7 +1767,7 @@ class TestDeterministicNAT(MethodHolder):
             # ACK packet in -> out
             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_port_out,
+                 TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
                      flags="A"))
             self.pg0.add_stream(p)
             self.pg_enable_capture(self.pg_interfaces)
@@ -1780,7 +1798,7 @@ class TestDeterministicNAT(MethodHolder):
             # FIN packet out -> in
             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
                  IP(src=self.pg1.remote_ip4, dst=self.snat_addr) /
-                 TCP(sport=self.tcp_port_out, dport=self.tcp_external_port,
+                 TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
                      flags="F"))
             self.pg1.add_stream(p)
             self.pg_enable_capture(self.pg_interfaces)
@@ -1792,14 +1810,14 @@ class TestDeterministicNAT(MethodHolder):
             # ACK packet in -> out
             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_port_out,
+                 TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
                      flags="A"))
             pkts.append(p)
 
             # ACK packet in -> out
             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_port_out,
+                 TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
                      flags="F"))
             pkts.append(p)
 
@@ -1811,7 +1829,7 @@ class TestDeterministicNAT(MethodHolder):
             # ACK packet out -> in
             p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
                  IP(src=self.pg1.remote_ip4, dst=self.snat_addr) /
-                 TCP(sport=self.tcp_port_out, dport=self.tcp_external_port,
+                 TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
                      flags="A"))
             self.pg1.add_stream(p)
             self.pg_enable_capture(self.pg_interfaces)
index a485cef..d94c0cb 100644 (file)
@@ -1272,6 +1272,21 @@ class VppPapiProvider(object):
              'ext_port': ext_port,
              'is_ip4': is_ip4})
 
+    def snat_det_session_dump(
+            self,
+            user_addr,
+            is_ip4=1):
+        """Dump S-NAT deterministic sessions belonging to a user
+
+        :param user_addr - inside IP address of the user
+        :param is_ip4: - 1 if address type is IPv4 (Default value = 1)
+        :return: Dictionary of S-NAT deterministic sessions
+        """
+        return self.api(
+            self.papi.snat_det_session_dump,
+            {'is_ip4': is_ip4,
+             'user_addr': user_addr})
+
     def control_ping(self):
         self.api(self.papi.control_ping)