diff options
-rw-r--r-- | src/plugins/snat/snat.api | 35 | ||||
-rw-r--r-- | src/plugins/snat/snat.c | 69 | ||||
-rw-r--r-- | src/plugins/snat/snat_test.c | 52 | ||||
-rw-r--r-- | test/test_snat.py | 98 | ||||
-rw-r--r-- | test/vpp_papi_provider.py | 15 |
5 files changed, 226 insertions, 43 deletions
diff --git a/src/plugins/snat/snat.api b/src/plugins/snat/snat.api index 5990eae5a24..e92675de867 100644 --- a/src/plugins/snat/snat.api +++ b/src/plugins/snat/snat.api @@ -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; +}; diff --git a/src/plugins/snat/snat.c b/src/plugins/snat/snat.c index 594afa62c80..c6783e47b6d 100644 --- a/src/plugins/snat/snat.c +++ b/src/plugins/snat/snat.c @@ -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 */ diff --git a/src/plugins/snat/snat_test.c b/src/plugins/snat/snat_test.c index 14e8d1990b7..905b8fac66c 100644 --- a/src/plugins/snat/snat_test.c +++ b/src/plugins/snat/snat_test.c @@ -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) diff --git a/test/test_snat.py b/test/test_snat.py index fe5af418aea..f90d9067850 100644 --- a/test/test_snat.py +++ b/test/test_snat.py @@ -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) diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py index a485cefcf96..d94c0cb6207 100644 --- a/test/vpp_papi_provider.py +++ b/test/vpp_papi_provider.py @@ -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) |