blob: b88605b3a2fa74534d2ec753acaaa3a1b6c3b30d [file] [log] [blame]
Ole Troan2c6639c2019-12-19 11:55:54 +01001#!/usr/bin/env python3
2
3import socket
Dmitry Valter34fa0ce2024-03-11 10:38:46 +00004import unittest
Ole Troan2c6639c2019-12-19 11:55:54 +01005
Dave Wallace8800f732023-08-31 00:47:44 -04006from asfframework import tag_fixme_vpp_workers
7from framework import VppTestCase
Ole Troan2c6639c2019-12-19 11:55:54 +01008
Ole Troan2c6639c2019-12-19 11:55:54 +01009from scapy.layers.inet import IP, TCP, UDP, ICMP
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020010from scapy.layers.inet6 import (
11 IPv6,
12 ICMPv6EchoRequest,
13 ICMPv6EchoReply,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020014)
Dave Wallace8800f732023-08-31 00:47:44 -040015from scapy.layers.l2 import Ether
Ole Troan2c6639c2019-12-19 11:55:54 +010016from scapy.data import IP_PROTOS
Dave Wallace8800f732023-08-31 00:47:44 -040017from scapy.packet import Raw
Ole Troan2c6639c2019-12-19 11:55:54 +010018from syslog_rfc5424_parser import SyslogMessage, ParseError
Dave Wallace8800f732023-08-31 00:47:44 -040019from syslog_rfc5424_parser.constants import SyslogSeverity
20from vpp_ip_route import VppIpRoute, VppRoutePath
Dmitry Valter34fa0ce2024-03-11 10:38:46 +000021from config import config
Ole Troan2c6639c2019-12-19 11:55:54 +010022
23
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +000024@tag_fixme_vpp_workers
Dmitry Valter34fa0ce2024-03-11 10:38:46 +000025@unittest.skipIf("nat" in config.excluded_plugins, "Exclude NAT plugin tests")
Ole Troan2c6639c2019-12-19 11:55:54 +010026class TestDSlite(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020027 """DS-Lite Test Cases"""
Ole Troan2c6639c2019-12-19 11:55:54 +010028
29 @classmethod
30 def setUpClass(cls):
31 super(TestDSlite, cls).setUpClass()
32
33 try:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020034 cls.nat_addr = "10.0.0.3"
Ole Troan2c6639c2019-12-19 11:55:54 +010035
36 cls.create_pg_interfaces(range(3))
37 cls.pg0.admin_up()
38 cls.pg0.config_ip4()
39 cls.pg0.resolve_arp()
40 cls.pg1.admin_up()
41 cls.pg1.config_ip6()
42 cls.pg1.generate_remote_hosts(2)
43 cls.pg1.configure_ipv6_neighbors()
44 cls.pg2.admin_up()
45 cls.pg2.config_ip4()
46 cls.pg2.resolve_arp()
47
48 except Exception:
49 super(TestDSlite, cls).tearDownClass()
50 raise
51
52 @classmethod
53 def tearDownClass(cls):
54 super(TestDSlite, cls).tearDownClass()
55
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020056 def verify_syslog_apmadd(self, data, isaddr, isport, xsaddr, xsport, sv6enc, proto):
57 message = data.decode("utf-8")
Ole Troan2c6639c2019-12-19 11:55:54 +010058 try:
59 message = SyslogMessage.parse(message)
60 except ParseError as e:
61 self.logger.error(e)
62 else:
63 self.assertEqual(message.severity, SyslogSeverity.info)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020064 self.assertEqual(message.appname, "NAT")
65 self.assertEqual(message.msgid, "APMADD")
66 sd_params = message.sd.get("napmap")
Ole Troan2c6639c2019-12-19 11:55:54 +010067 self.assertTrue(sd_params is not None)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020068 self.assertEqual(sd_params.get("IATYP"), "IPv4")
69 self.assertEqual(sd_params.get("ISADDR"), isaddr)
70 self.assertEqual(sd_params.get("ISPORT"), "%d" % isport)
71 self.assertEqual(sd_params.get("XATYP"), "IPv4")
72 self.assertEqual(sd_params.get("XSADDR"), xsaddr)
73 self.assertEqual(sd_params.get("XSPORT"), "%d" % xsport)
74 self.assertEqual(sd_params.get("PROTO"), "%d" % proto)
75 self.assertTrue(sd_params.get("SSUBIX") is not None)
76 self.assertEqual(sd_params.get("SV6ENC"), sv6enc)
Ole Troan2c6639c2019-12-19 11:55:54 +010077
78 def test_dslite(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020079 """Test DS-Lite"""
80 self.vapi.dslite_add_del_pool_addr_range(
81 start_addr=self.nat_addr, end_addr=self.nat_addr, is_add=1
82 )
83 aftr_ip4 = "192.0.0.1"
84 aftr_ip6 = "2001:db8:85a3::8a2e:370:1"
Ole Troan2c6639c2019-12-19 11:55:54 +010085 self.vapi.dslite_set_aftr_addr(ip4_addr=aftr_ip4, ip6_addr=aftr_ip6)
86 self.vapi.syslog_set_sender(self.pg2.local_ip4, self.pg2.remote_ip4)
87
88 # UDP
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020089 p = (
90 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
91 / IPv6(dst=aftr_ip6, src=self.pg1.remote_hosts[0].ip6)
92 / IP(dst=self.pg0.remote_ip4, src="192.168.1.1")
93 / UDP(sport=20000, dport=10000)
94 )
Ole Troan2c6639c2019-12-19 11:55:54 +010095 self.pg1.add_stream(p)
96 self.pg_enable_capture(self.pg_interfaces)
97 self.pg_start()
98 capture = self.pg0.get_capture(1)
99 capture = capture[0]
100 self.assertFalse(capture.haslayer(IPv6))
101 self.assertEqual(capture[IP].src, self.nat_addr)
102 self.assertEqual(capture[IP].dst, self.pg0.remote_ip4)
103 self.assertNotEqual(capture[UDP].sport, 20000)
104 self.assertEqual(capture[UDP].dport, 10000)
105 self.assert_packet_checksums_valid(capture)
106 out_port = capture[UDP].sport
107 capture = self.pg2.get_capture(1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200108 self.verify_syslog_apmadd(
109 capture[0][Raw].load,
110 "192.168.1.1",
111 20000,
112 self.nat_addr,
113 out_port,
114 self.pg1.remote_hosts[0].ip6,
115 IP_PROTOS.udp,
116 )
Ole Troan2c6639c2019-12-19 11:55:54 +0100117
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200118 p = (
119 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
120 / IP(dst=self.nat_addr, src=self.pg0.remote_ip4)
121 / UDP(sport=10000, dport=out_port)
122 )
Ole Troan2c6639c2019-12-19 11:55:54 +0100123 self.pg0.add_stream(p)
124 self.pg_enable_capture(self.pg_interfaces)
125 self.pg_start()
126 capture = self.pg1.get_capture(1)
127 capture = capture[0]
128 self.assertEqual(capture[IPv6].src, aftr_ip6)
129 self.assertEqual(capture[IPv6].dst, self.pg1.remote_hosts[0].ip6)
130 self.assertEqual(capture[IP].src, self.pg0.remote_ip4)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200131 self.assertEqual(capture[IP].dst, "192.168.1.1")
Ole Troan2c6639c2019-12-19 11:55:54 +0100132 self.assertEqual(capture[UDP].sport, 10000)
133 self.assertEqual(capture[UDP].dport, 20000)
134 self.assert_packet_checksums_valid(capture)
135
136 # TCP
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200137 p = (
138 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
139 / IPv6(dst=aftr_ip6, src=self.pg1.remote_hosts[1].ip6)
140 / IP(dst=self.pg0.remote_ip4, src="192.168.1.1")
141 / TCP(sport=20001, dport=10001)
142 )
Ole Troan2c6639c2019-12-19 11:55:54 +0100143 self.pg1.add_stream(p)
144 self.pg_enable_capture(self.pg_interfaces)
145 self.pg_start()
146 capture = self.pg0.get_capture(1)
147 capture = capture[0]
148 self.assertFalse(capture.haslayer(IPv6))
149 self.assertEqual(capture[IP].src, self.nat_addr)
150 self.assertEqual(capture[IP].dst, self.pg0.remote_ip4)
151 self.assertNotEqual(capture[TCP].sport, 20001)
152 self.assertEqual(capture[TCP].dport, 10001)
153 self.assert_packet_checksums_valid(capture)
154 out_port = capture[TCP].sport
155
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200156 p = (
157 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
158 / IP(dst=self.nat_addr, src=self.pg0.remote_ip4)
159 / TCP(sport=10001, dport=out_port)
160 )
Ole Troan2c6639c2019-12-19 11:55:54 +0100161 self.pg0.add_stream(p)
162 self.pg_enable_capture(self.pg_interfaces)
163 self.pg_start()
164 capture = self.pg1.get_capture(1)
165 capture = capture[0]
166 self.assertEqual(capture[IPv6].src, aftr_ip6)
167 self.assertEqual(capture[IPv6].dst, self.pg1.remote_hosts[1].ip6)
168 self.assertEqual(capture[IP].src, self.pg0.remote_ip4)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200169 self.assertEqual(capture[IP].dst, "192.168.1.1")
Ole Troan2c6639c2019-12-19 11:55:54 +0100170 self.assertEqual(capture[TCP].sport, 10001)
171 self.assertEqual(capture[TCP].dport, 20001)
172 self.assert_packet_checksums_valid(capture)
173
174 # ICMP
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200175 p = (
176 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
177 / IPv6(dst=aftr_ip6, src=self.pg1.remote_hosts[1].ip6)
178 / IP(dst=self.pg0.remote_ip4, src="192.168.1.1")
179 / ICMP(id=4000, type="echo-request")
180 )
Ole Troan2c6639c2019-12-19 11:55:54 +0100181 self.pg1.add_stream(p)
182 self.pg_enable_capture(self.pg_interfaces)
183 self.pg_start()
184 capture = self.pg0.get_capture(1)
185 capture = capture[0]
186 self.assertFalse(capture.haslayer(IPv6))
187 self.assertEqual(capture[IP].src, self.nat_addr)
188 self.assertEqual(capture[IP].dst, self.pg0.remote_ip4)
189 self.assertNotEqual(capture[ICMP].id, 4000)
190 self.assert_packet_checksums_valid(capture)
191 out_id = capture[ICMP].id
192
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200193 p = (
194 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
195 / IP(dst=self.nat_addr, src=self.pg0.remote_ip4)
196 / ICMP(id=out_id, type="echo-reply")
197 )
Ole Troan2c6639c2019-12-19 11:55:54 +0100198 self.pg0.add_stream(p)
199 self.pg_enable_capture(self.pg_interfaces)
200 self.pg_start()
201 capture = self.pg1.get_capture(1)
202 capture = capture[0]
203 self.assertEqual(capture[IPv6].src, aftr_ip6)
204 self.assertEqual(capture[IPv6].dst, self.pg1.remote_hosts[1].ip6)
205 self.assertEqual(capture[IP].src, self.pg0.remote_ip4)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200206 self.assertEqual(capture[IP].dst, "192.168.1.1")
Ole Troan2c6639c2019-12-19 11:55:54 +0100207 self.assertEqual(capture[ICMP].id, 4000)
208 self.assert_packet_checksums_valid(capture)
209
210 # ping DS-Lite AFTR tunnel endpoint address
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200211 p = (
212 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
213 / IPv6(src=self.pg1.remote_hosts[1].ip6, dst=aftr_ip6)
214 / ICMPv6EchoRequest()
215 )
Ole Troan2c6639c2019-12-19 11:55:54 +0100216 self.pg1.add_stream(p)
217 self.pg_enable_capture(self.pg_interfaces)
218 self.pg_start()
219 capture = self.pg1.get_capture(1)
220 capture = capture[0]
221 self.assertEqual(capture[IPv6].src, aftr_ip6)
222 self.assertEqual(capture[IPv6].dst, self.pg1.remote_hosts[1].ip6)
223 self.assertTrue(capture.haslayer(ICMPv6EchoReply))
224
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200225 b4s = self.statistics.get_counter("/dslite/total-b4s")
Ole Troan2c6639c2019-12-19 11:55:54 +0100226 self.assertEqual(b4s[0][0], 2)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200227 sessions = self.statistics.get_counter("/dslite/total-sessions")
Ole Troan2c6639c2019-12-19 11:55:54 +0100228 self.assertEqual(sessions[0][0], 3)
229
230 def tearDown(self):
231 super(TestDSlite, self).tearDown()
232
233 def show_commands_at_teardown(self):
234 self.logger.info(self.vapi.cli("show dslite pool"))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200235 self.logger.info(self.vapi.cli("show dslite aftr-tunnel-endpoint-address"))
Ole Troan2c6639c2019-12-19 11:55:54 +0100236 self.logger.info(self.vapi.cli("show dslite sessions"))
237
238
Dmitry Valter34fa0ce2024-03-11 10:38:46 +0000239@unittest.skipIf("nat" in config.excluded_plugins, "Exclude NAT plugin tests")
Vladimir Ratnikov958919f2020-04-13 06:36:19 -0400240class TestDSliteCE(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200241 """DS-Lite CE Test Cases"""
Ole Troan2c6639c2019-12-19 11:55:54 +0100242
243 @classmethod
244 def setUpConstants(cls):
245 super(TestDSliteCE, cls).setUpConstants()
Vladimir Ratnikov958919f2020-04-13 06:36:19 -0400246 cls.vpp_cmdline.extend(["dslite", "{", "ce", "}"])
Ole Troan2c6639c2019-12-19 11:55:54 +0100247
248 @classmethod
249 def setUpClass(cls):
250 super(TestDSliteCE, cls).setUpClass()
251
252 try:
253 cls.create_pg_interfaces(range(2))
254 cls.pg0.admin_up()
255 cls.pg0.config_ip4()
256 cls.pg0.resolve_arp()
257 cls.pg1.admin_up()
258 cls.pg1.config_ip6()
259 cls.pg1.generate_remote_hosts(1)
260 cls.pg1.configure_ipv6_neighbors()
261
262 except Exception:
263 super(TestDSliteCE, cls).tearDownClass()
264 raise
265
266 @classmethod
267 def tearDownClass(cls):
268 super(TestDSliteCE, cls).tearDownClass()
269
270 def test_dslite_ce(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200271 """Test DS-Lite CE"""
272 b4_ip4 = "192.0.0.2"
273 b4_ip6 = "2001:db8:62aa::375e:f4c1:1"
Ole Troan2c6639c2019-12-19 11:55:54 +0100274 self.vapi.dslite_set_b4_addr(ip4_addr=b4_ip4, ip6_addr=b4_ip6)
275
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200276 aftr_ip4 = "192.0.0.1"
277 aftr_ip6 = "2001:db8:85a3::8a2e:370:1"
Ole Troan2c6639c2019-12-19 11:55:54 +0100278 aftr_ip6_n = socket.inet_pton(socket.AF_INET6, aftr_ip6)
279 self.vapi.dslite_set_aftr_addr(ip4_addr=aftr_ip4, ip6_addr=aftr_ip6)
280
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200281 r1 = VppIpRoute(
282 self,
283 aftr_ip6,
284 128,
285 [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index)],
286 )
Ole Troan2c6639c2019-12-19 11:55:54 +0100287 r1.add_vpp_config()
288
289 # UDP encapsulation
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200290 p = (
291 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
292 / IP(dst=self.pg1.remote_ip4, src=self.pg0.remote_ip4)
293 / UDP(sport=10000, dport=20000)
294 )
Ole Troan2c6639c2019-12-19 11:55:54 +0100295 self.pg0.add_stream(p)
296 self.pg_enable_capture(self.pg_interfaces)
297 self.pg_start()
298 capture = self.pg1.get_capture(1)
299 capture = capture[0]
300 self.assertEqual(capture[IPv6].src, b4_ip6)
301 self.assertEqual(capture[IPv6].dst, aftr_ip6)
302 self.assertEqual(capture[IP].src, self.pg0.remote_ip4)
303 self.assertEqual(capture[IP].dst, self.pg1.remote_ip4)
304 self.assertEqual(capture[UDP].sport, 10000)
305 self.assertEqual(capture[UDP].dport, 20000)
306 self.assert_packet_checksums_valid(capture)
307
308 # UDP decapsulation
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200309 p = (
310 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
311 / IPv6(dst=b4_ip6, src=aftr_ip6)
312 / IP(dst=self.pg0.remote_ip4, src=self.pg1.remote_ip4)
313 / UDP(sport=20000, dport=10000)
314 )
Ole Troan2c6639c2019-12-19 11:55:54 +0100315 self.pg1.add_stream(p)
316 self.pg_enable_capture(self.pg_interfaces)
317 self.pg_start()
318 capture = self.pg0.get_capture(1)
319 capture = capture[0]
320 self.assertFalse(capture.haslayer(IPv6))
321 self.assertEqual(capture[IP].src, self.pg1.remote_ip4)
322 self.assertEqual(capture[IP].dst, self.pg0.remote_ip4)
323 self.assertEqual(capture[UDP].sport, 20000)
324 self.assertEqual(capture[UDP].dport, 10000)
325 self.assert_packet_checksums_valid(capture)
326
327 # ping DS-Lite B4 tunnel endpoint address
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200328 p = (
329 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
330 / IPv6(src=self.pg1.remote_hosts[0].ip6, dst=b4_ip6)
331 / ICMPv6EchoRequest()
332 )
Ole Troan2c6639c2019-12-19 11:55:54 +0100333 self.pg1.add_stream(p)
334 self.pg_enable_capture(self.pg_interfaces)
335 self.pg_start()
336 capture = self.pg1.get_capture(1)
337 capture = capture[0]
338 self.assertEqual(capture[IPv6].src, b4_ip6)
339 self.assertEqual(capture[IPv6].dst, self.pg1.remote_hosts[0].ip6)
340 self.assertTrue(capture.haslayer(ICMPv6EchoReply))
341
342 def tearDown(self):
343 super(TestDSliteCE, self).tearDown()
344
345 def show_commands_at_teardown(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200346 self.logger.info(self.vapi.cli("show dslite aftr-tunnel-endpoint-address"))
347 self.logger.info(self.vapi.cli("show dslite b4-tunnel-endpoint-address"))