blob: c65c5df7cda1e45b4ba6473bc810c815078431e7 [file] [log] [blame]
Renato Botelho do Coutoead1e532019-10-31 13:31:07 -05001#!/usr/bin/env python3
Neale Ranns80823802017-02-20 18:23:41 -08002
Paul Vinciguerra4d376f62019-05-24 06:36:26 -04003import ipaddress
Neale Ranns80823802017-02-20 18:23:41 -08004import unittest
Neale Ranns80823802017-02-20 18:23:41 -08005
Dave Wallace8800f732023-08-31 00:47:44 -04006from framework import VppTestCase
7from asfframework import VppTestRunner
Paul Vinciguerraa279d9c2019-02-28 09:00:09 -08008from vpp_ip import DpoProto
Neale Rannsc0a93142018-09-05 15:42:26 -07009from vpp_ip_route import VppIpRoute, VppRoutePath
Klement Sekera7b2e9fb2019-10-01 13:00:22 +000010from util import fragment_rfc791, fragment_rfc8200
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -070011
12import scapy.compat
snaramre5d4b8912019-12-13 23:39:35 +000013from scapy.layers.l2 import Ether
14from scapy.packet import Raw
Alexander Chernavin31b1a6c2020-01-17 08:31:04 -050015from scapy.layers.inet import IP, UDP, ICMP, TCP
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020016from scapy.layers.inet6 import (
17 IPv6,
18 ICMPv6TimeExceeded,
19 IPv6ExtHdrFragment,
20 ICMPv6EchoRequest,
21 ICMPv6DestUnreach,
22)
Neale Ranns80823802017-02-20 18:23:41 -080023
24
25class TestMAP(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020026 """MAP Test Case"""
Neale Ranns80823802017-02-20 18:23:41 -080027
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -070028 @classmethod
29 def setUpClass(cls):
30 super(TestMAP, cls).setUpClass()
31
32 @classmethod
33 def tearDownClass(cls):
34 super(TestMAP, cls).tearDownClass()
35
Neale Ranns80823802017-02-20 18:23:41 -080036 def setUp(self):
37 super(TestMAP, self).setUp()
38
39 # create 2 pg interfaces
40 self.create_pg_interfaces(range(4))
41
42 # pg0 is 'inside' IPv4
43 self.pg0.admin_up()
44 self.pg0.config_ip4()
45 self.pg0.resolve_arp()
Alexander Chernavinf145c152020-02-11 09:57:09 -050046 self.pg0.generate_remote_hosts(2)
47 self.pg0.configure_ipv4_neighbors()
Neale Ranns80823802017-02-20 18:23:41 -080048
49 # pg1 is 'outside' IPv6
50 self.pg1.admin_up()
51 self.pg1.config_ip6()
52 self.pg1.generate_remote_hosts(4)
53 self.pg1.configure_ipv6_neighbors()
54
55 def tearDown(self):
56 super(TestMAP, self).tearDown()
Maxime Peim23d13c02023-08-01 11:29:15 +020057
Neale Ranns80823802017-02-20 18:23:41 -080058 for i in self.pg_interfaces:
Maxime Peim23d13c02023-08-01 11:29:15 +020059 for t in (0, 1):
60 self.vapi.map_if_enable_disable(
61 is_enable=0, sw_if_index=i.sw_if_index, is_translation=t
62 )
Neale Ranns80823802017-02-20 18:23:41 -080063 i.unconfig_ip4()
64 i.unconfig_ip6()
65 i.admin_down()
66
Klement Sekeraa025b3e2019-08-21 10:53:14 +000067 def send_and_assert_encapped(self, packets, ip6_src, ip6_dst, dmac=None):
Neale Ranns80823802017-02-20 18:23:41 -080068 if not dmac:
69 dmac = self.pg1.remote_mac
70
Klement Sekeraa025b3e2019-08-21 10:53:14 +000071 self.pg0.add_stream(packets)
Neale Ranns80823802017-02-20 18:23:41 -080072
73 self.pg_enable_capture(self.pg_interfaces)
74 self.pg_start()
75
Klement Sekeraa025b3e2019-08-21 10:53:14 +000076 capture = self.pg1.get_capture(len(packets))
77 for rx, tx in zip(capture, packets):
78 self.assertEqual(rx[Ether].dst, dmac)
79 self.assertEqual(rx[IP].src, tx[IP].src)
80 self.assertEqual(rx[IPv6].src, ip6_src)
81 self.assertEqual(rx[IPv6].dst, ip6_dst)
Neale Ranns80823802017-02-20 18:23:41 -080082
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020083 def send_and_assert_encapped_one(self, packet, ip6_src, ip6_dst, dmac=None):
Klement Sekeraa025b3e2019-08-21 10:53:14 +000084 return self.send_and_assert_encapped([packet], ip6_src, ip6_dst, dmac)
Neale Ranns80823802017-02-20 18:23:41 -080085
Paul Vinciguerra4d376f62019-05-24 06:36:26 -040086 def test_api_map_domain_dump(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020087 map_dst = "2001::/64"
88 map_src = "3000::1/128"
89 client_pfx = "192.168.0.0/16"
90 tag = "MAP-E tag."
91 index = self.vapi.map_add_domain(
92 ip4_prefix=client_pfx, ip6_prefix=map_dst, ip6_src=map_src, tag=tag
93 ).index
Paul Vinciguerra4d376f62019-05-24 06:36:26 -040094 rv = self.vapi.map_domain_dump()
95
96 # restore the state early so as to not impact subsequent tests.
97 # If an assert fails, we will not get the chance to do it at the end.
98 self.vapi.map_del_domain(index=index)
99
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200100 self.assertGreater(len(rv), 0, "Expected output from 'map_domain_dump'")
Paul Vinciguerra4d376f62019-05-24 06:36:26 -0400101
102 # typedefs are returned as ipaddress objects.
103 # wrap results in str() ugh! to avoid the need to call unicode.
104 self.assertEqual(str(rv[0].ip4_prefix), client_pfx)
105 self.assertEqual(str(rv[0].ip6_prefix), map_dst)
106 self.assertEqual(str(rv[0].ip6_src), map_src)
107
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200108 self.assertEqual(rv[0].tag, tag, "output produced incorrect tag value.")
Paul Vinciguerra4d376f62019-05-24 06:36:26 -0400109
Ole Troanf5db3712020-05-20 15:47:06 +0200110 def create_domains(self, ip4_pfx_str, ip6_pfx_str, ip6_src_str):
111 ip4_pfx = ipaddress.ip_network(ip4_pfx_str)
112 ip6_dst = ipaddress.ip_network(ip6_pfx_str)
113 mod = ip4_pfx.num_addresses / 1024
114 indicies = []
115 for i in range(ip4_pfx.num_addresses):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200116 rv = self.vapi.map_add_domain(
117 ip6_prefix=ip6_pfx_str,
118 ip4_prefix=str(ip4_pfx[i]) + "/32",
119 ip6_src=ip6_src_str,
120 )
Ole Troanf5db3712020-05-20 15:47:06 +0200121 indicies.append(rv.index)
122 return indicies
123
124 def test_api_map_domains_get(self):
125 # Create a bunch of domains
Ole Troan4376ab22021-03-03 10:40:05 +0100126 no_domains = 4096 # This must be large enough to ensure VPP suspends
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200127 domains = self.create_domains("130.67.0.0/20", "2001::/32", "2001::1/128")
Ole Troan4376ab22021-03-03 10:40:05 +0100128 self.assertEqual(len(domains), no_domains)
Ole Troanf5db3712020-05-20 15:47:06 +0200129
130 d = []
131 cursor = 0
132
133 # Invalid cursor
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200134 rv, details = self.vapi.map_domains_get(cursor=no_domains + 10)
Ole Troanf5db3712020-05-20 15:47:06 +0200135 self.assertEqual(rv.retval, -7)
136
137 # Delete a domain in the middle of walk
138 rv, details = self.vapi.map_domains_get(cursor=0)
139 self.assertEqual(rv.retval, -165)
140 self.vapi.map_del_domain(index=rv.cursor)
141 domains.remove(rv.cursor)
142
143 # Continue at point of deleted cursor
144 rv, details = self.vapi.map_domains_get(cursor=rv.cursor)
Ole Troan9bf487f2021-03-30 00:51:41 +0200145 self.assertIn(rv.retval, [0, -165])
Ole Troanf5db3712020-05-20 15:47:06 +0200146
147 d = list(self.vapi.vpp.details_iter(self.vapi.map_domains_get))
Ole Troan4376ab22021-03-03 10:40:05 +0100148 self.assertEqual(len(d), no_domains - 1)
Ole Troanf5db3712020-05-20 15:47:06 +0200149
150 # Clean up
151 for i in domains:
152 self.vapi.map_del_domain(index=i)
153
Jon Loeligerb15ad952019-11-14 16:44:40 -0600154 def test_map_e_udp(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200155 """MAP-E UDP"""
Neale Ranns80823802017-02-20 18:23:41 -0800156
157 #
158 # Add a route to the MAP-BR
159 #
160 map_br_pfx = "2001::"
Klement Sekeraa025b3e2019-08-21 10:53:14 +0000161 map_br_pfx_len = 32
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200162 map_route = VppIpRoute(
163 self,
164 map_br_pfx,
165 map_br_pfx_len,
166 [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index)],
167 )
Neale Ranns80823802017-02-20 18:23:41 -0800168 map_route.add_vpp_config()
169
170 #
171 # Add a domain that maps from pg0 to pg1
172 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200173 map_dst = "2001::/32"
174 map_src = "3000::1/128"
175 client_pfx = "192.168.0.0/16"
176 map_translated_addr = "2001:0:101:7000:0:c0a8:101:7"
177 tag = "MAP-E tag."
178 self.vapi.map_add_domain(
179 ip4_prefix=client_pfx,
180 ip6_prefix=map_dst,
181 ip6_src=map_src,
182 ea_bits_len=20,
183 psid_offset=4,
184 psid_length=4,
185 tag=tag,
186 )
Neale Ranns80823802017-02-20 18:23:41 -0800187
Klement Sekeraa025b3e2019-08-21 10:53:14 +0000188 self.vapi.map_param_set_security_check(enable=1, fragments=1)
189
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600190 # Enable MAP on interface.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200191 self.vapi.map_if_enable_disable(
192 is_enable=1, sw_if_index=self.pg0.sw_if_index, is_translation=0
193 )
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600194
195 # Ensure MAP doesn't steal all packets!
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200196 v4 = (
197 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
198 / IP(src=self.pg0.remote_ip4, dst=self.pg0.remote_ip4)
199 / UDP(sport=20000, dport=10000)
200 / Raw(b"\xa5" * 100)
201 )
Ole Troaneb284a12019-10-09 13:33:19 +0200202 rx = self.send_and_expect(self.pg0, v4 * 4, self.pg0)
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600203 v4_reply = v4[1]
204 v4_reply.ttl -= 1
205 for p in rx:
206 self.validate(p[1], v4_reply)
207
Neale Ranns80823802017-02-20 18:23:41 -0800208 #
209 # Fire in a v4 packet that will be encapped to the BR
210 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200211 v4 = (
212 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
213 / IP(src=self.pg0.remote_ip4, dst="192.168.1.1")
214 / UDP(sport=20000, dport=10000)
215 / Raw(b"\xa5" * 100)
216 )
Neale Ranns80823802017-02-20 18:23:41 -0800217
Ole Troaneb284a12019-10-09 13:33:19 +0200218 self.send_and_assert_encapped(v4 * 4, "3000::1", map_translated_addr)
Klement Sekeraa025b3e2019-08-21 10:53:14 +0000219
Klement Sekeraa025b3e2019-08-21 10:53:14 +0000220 #
221 # Verify reordered fragments are able to pass as well
222 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200223 v4 = (
224 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
225 / IP(id=1, src=self.pg0.remote_ip4, dst="192.168.1.1")
226 / UDP(sport=20000, dport=10000)
227 / Raw(b"\xa5" * 1000)
228 )
Klement Sekeraa025b3e2019-08-21 10:53:14 +0000229
230 frags = fragment_rfc791(v4, 400)
231 frags.reverse()
232
233 self.send_and_assert_encapped(frags, "3000::1", map_translated_addr)
234
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600235 # Enable MAP on interface.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200236 self.vapi.map_if_enable_disable(
237 is_enable=1, sw_if_index=self.pg1.sw_if_index, is_translation=0
238 )
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600239
240 # Ensure MAP doesn't steal all packets
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200241 v6 = (
242 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
243 / IPv6(src=self.pg1.remote_ip6, dst=self.pg1.remote_ip6)
244 / UDP(sport=20000, dport=10000)
245 / Raw(b"\xa5" * 100)
246 )
247 rx = self.send_and_expect(self.pg1, v6 * 1, self.pg1)
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600248 v6_reply = v6[1]
249 v6_reply.hlim -= 1
250 for p in rx:
251 self.validate(p[1], v6_reply)
252
Neale Ranns80823802017-02-20 18:23:41 -0800253 #
254 # Fire in a V6 encapped packet.
Klement Sekeraa025b3e2019-08-21 10:53:14 +0000255 # expect a decapped packet on the inside ip4 link
Neale Ranns80823802017-02-20 18:23:41 -0800256 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200257 p = (
258 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
259 / IPv6(dst="3000::1", src=map_translated_addr)
260 / IP(dst=self.pg0.remote_ip4, src="192.168.1.1")
261 / UDP(sport=10000, dport=20000)
262 / Raw(b"\xa5" * 100)
263 )
Neale Ranns80823802017-02-20 18:23:41 -0800264
265 self.pg1.add_stream(p)
266
267 self.pg_enable_capture(self.pg_interfaces)
268 self.pg_start()
269
270 rx = self.pg0.get_capture(1)
271 rx = rx[0]
272
273 self.assertFalse(rx.haslayer(IPv6))
274 self.assertEqual(rx[IP].src, p[IP].src)
275 self.assertEqual(rx[IP].dst, p[IP].dst)
276
277 #
Klement Sekeraa025b3e2019-08-21 10:53:14 +0000278 # Verify encapped reordered fragments pass as well
279 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200280 p = (
281 IP(id=1, dst=self.pg0.remote_ip4, src="192.168.1.1")
282 / UDP(sport=10000, dport=20000)
283 / Raw(b"\xa5" * 1500)
284 )
Klement Sekeraa025b3e2019-08-21 10:53:14 +0000285 frags = fragment_rfc791(p, 400)
286 frags.reverse()
287
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200288 stream = (
289 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
290 / IPv6(dst="3000::1", src=map_translated_addr)
291 / x
292 for x in frags
293 )
Klement Sekeraa025b3e2019-08-21 10:53:14 +0000294
295 self.pg1.add_stream(stream)
296
297 self.pg_enable_capture(self.pg_interfaces)
298 self.pg_start()
299
300 rx = self.pg0.get_capture(len(frags))
301
302 for r in rx:
303 self.assertFalse(r.haslayer(IPv6))
304 self.assertEqual(r[IP].src, p[IP].src)
305 self.assertEqual(r[IP].dst, p[IP].dst)
306
Klement Sekera7b2e9fb2019-10-01 13:00:22 +0000307 # Verify that fragments pass even if ipv6 layer is fragmented
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200308 stream = (IPv6(dst="3000::1", src=map_translated_addr) / x for x in frags)
Klement Sekera7b2e9fb2019-10-01 13:00:22 +0000309
310 v6_stream = [
311 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / x
312 for i in range(len(frags))
313 for x in fragment_rfc8200(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200314 IPv6(dst="3000::1", src=map_translated_addr) / frags[i], i, 200
315 )
316 ]
Klement Sekera7b2e9fb2019-10-01 13:00:22 +0000317
318 self.pg1.add_stream(v6_stream)
319
320 self.pg_enable_capture(self.pg_interfaces)
321 self.pg_start()
322
323 rx = self.pg0.get_capture(len(frags))
324
325 for r in rx:
326 self.assertFalse(r.haslayer(IPv6))
327 self.assertEqual(r[IP].src, p[IP].src)
328 self.assertEqual(r[IP].dst, p[IP].dst)
329
Klement Sekeraa025b3e2019-08-21 10:53:14 +0000330 #
Neale Ranns80823802017-02-20 18:23:41 -0800331 # Pre-resolve. No API for this!!
332 #
333 self.vapi.ppcli("map params pre-resolve ip6-nh 4001::1")
334
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200335 self.send_and_assert_no_replies(self.pg0, v4, "resolved via default route")
Neale Ranns80823802017-02-20 18:23:41 -0800336
337 #
338 # Add a route to 4001::1. Expect the encapped traffic to be
339 # sent via that routes next-hop
340 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200341 pre_res_route = VppIpRoute(
342 self,
343 "4001::1",
344 128,
345 [VppRoutePath(self.pg1.remote_hosts[2].ip6, self.pg1.sw_if_index)],
346 )
Neale Ranns80823802017-02-20 18:23:41 -0800347 pre_res_route.add_vpp_config()
348
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200349 self.send_and_assert_encapped_one(
350 v4, "3000::1", map_translated_addr, dmac=self.pg1.remote_hosts[2].mac
351 )
Neale Ranns80823802017-02-20 18:23:41 -0800352
353 #
354 # change the route to the pre-solved next-hop
355 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200356 pre_res_route.modify(
357 [VppRoutePath(self.pg1.remote_hosts[3].ip6, self.pg1.sw_if_index)]
358 )
Neale Ranns69b7aa42017-03-10 03:04:12 -0800359 pre_res_route.add_vpp_config()
Neale Ranns80823802017-02-20 18:23:41 -0800360
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200361 self.send_and_assert_encapped_one(
362 v4, "3000::1", map_translated_addr, dmac=self.pg1.remote_hosts[3].mac
363 )
Neale Ranns80823802017-02-20 18:23:41 -0800364
Neale Ranns69b7aa42017-03-10 03:04:12 -0800365 #
366 # cleanup. The test infra's object registry will ensure
367 # the route is really gone and thus that the unresolve worked.
368 #
369 pre_res_route.remove_vpp_config()
370 self.vapi.ppcli("map params pre-resolve del ip6-nh 4001::1")
371
Ole Troaneb284a12019-10-09 13:33:19 +0200372 def test_map_e_inner_frag(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200373 """MAP-E Inner fragmentation"""
Ole Troaneb284a12019-10-09 13:33:19 +0200374
375 #
376 # Add a route to the MAP-BR
377 #
378 map_br_pfx = "2001::"
379 map_br_pfx_len = 32
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200380 map_route = VppIpRoute(
381 self,
382 map_br_pfx,
383 map_br_pfx_len,
384 [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index)],
385 )
Ole Troaneb284a12019-10-09 13:33:19 +0200386 map_route.add_vpp_config()
387
388 #
389 # Add a domain that maps from pg0 to pg1
390 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200391 map_dst = "2001::/32"
392 map_src = "3000::1/128"
393 client_pfx = "192.168.0.0/16"
394 map_translated_addr = "2001:0:101:7000:0:c0a8:101:7"
395 tag = "MAP-E tag."
396 self.vapi.map_add_domain(
397 ip4_prefix=client_pfx,
398 ip6_prefix=map_dst,
399 ip6_src=map_src,
400 ea_bits_len=20,
401 psid_offset=4,
402 psid_length=4,
403 mtu=1000,
404 tag=tag,
405 )
Ole Troaneb284a12019-10-09 13:33:19 +0200406
407 # Enable MAP on interface.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200408 self.vapi.map_if_enable_disable(
409 is_enable=1, sw_if_index=self.pg0.sw_if_index, is_translation=0
410 )
Ole Troaneb284a12019-10-09 13:33:19 +0200411
412 # Enable inner fragmentation
413 self.vapi.map_param_set_fragmentation(inner=1)
414
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200415 v4 = (
416 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
417 / IP(src=self.pg0.remote_ip4, dst="192.168.1.1")
418 / UDP(sport=20000, dport=10000)
419 / Raw(b"\xa5" * 1300)
420 )
Ole Troaneb284a12019-10-09 13:33:19 +0200421
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200422 self.pg_send(self.pg0, v4 * 1)
Ole Troaneb284a12019-10-09 13:33:19 +0200423 rx = self.pg1.get_capture(2)
424
Neale Ranns346c2472022-03-08 13:24:28 +0000425 # 1000-sizeof(ip6_header_t) = 960.
426 frags = fragment_rfc791(v4[1], 960)
Ole Troaneb284a12019-10-09 13:33:19 +0200427 frags[0].id = 0
428 frags[1].id = 0
429 frags[0].ttl -= 1
430 frags[1].ttl -= 1
431 frags[0].chksum = 0
432 frags[1].chksum = 0
433
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200434 v6_reply1 = IPv6(src="3000::1", dst=map_translated_addr, hlim=63) / frags[0]
435 v6_reply2 = IPv6(src="3000::1", dst=map_translated_addr, hlim=63) / frags[1]
Ole Troaneb284a12019-10-09 13:33:19 +0200436 rx[0][1].fl = 0
437 rx[1][1].fl = 0
438 rx[0][1][IP].id = 0
439 rx[1][1][IP].id = 0
440 rx[0][1][IP].chksum = 0
441 rx[1][1][IP].chksum = 0
442
443 self.validate(rx[0][1], v6_reply1)
444 self.validate(rx[1][1], v6_reply2)
445
Jon Loeligerb15ad952019-11-14 16:44:40 -0600446 def test_map_e_tcp_mss(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200447 """MAP-E TCP MSS"""
Jon Loeligerb15ad952019-11-14 16:44:40 -0600448
449 #
450 # Add a route to the MAP-BR
451 #
452 map_br_pfx = "2001::"
453 map_br_pfx_len = 32
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200454 map_route = VppIpRoute(
455 self,
456 map_br_pfx,
457 map_br_pfx_len,
458 [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index)],
459 )
Jon Loeligerb15ad952019-11-14 16:44:40 -0600460 map_route.add_vpp_config()
461
462 #
463 # Add a domain that maps from pg0 to pg1
464 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200465 map_dst = "2001::/32"
466 map_src = "3000::1/128"
467 client_pfx = "192.168.0.0/16"
468 map_translated_addr = "2001:0:101:5000:0:c0a8:101:5"
469 tag = "MAP-E TCP tag."
470 self.vapi.map_add_domain(
471 ip4_prefix=client_pfx,
472 ip6_prefix=map_dst,
473 ip6_src=map_src,
474 ea_bits_len=20,
475 psid_offset=4,
476 psid_length=4,
477 tag=tag,
478 )
Jon Loeligerb15ad952019-11-14 16:44:40 -0600479
480 # Enable MAP on pg0 interface.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200481 self.vapi.map_if_enable_disable(
482 is_enable=1, sw_if_index=self.pg0.sw_if_index, is_translation=0
483 )
Jon Loeligerb15ad952019-11-14 16:44:40 -0600484
485 # Enable MAP on pg1 interface.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200486 self.vapi.map_if_enable_disable(
487 is_enable=1, sw_if_index=self.pg1.sw_if_index, is_translation=0
488 )
Jon Loeligerb15ad952019-11-14 16:44:40 -0600489
490 # TCP MSS clamping
491 mss_clamp = 1300
492 self.vapi.map_param_set_tcp(mss_clamp)
493
494 #
495 # Send a v4 packet that will be encapped.
496 #
Steven Luonge4238aa2024-04-19 09:49:20 -0700497 p_ether = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200498 p_ip4 = IP(src=self.pg0.remote_ip4, dst="192.168.1.1")
499 p_tcp = TCP(sport=20000, dport=30000, flags="S", options=[("MSS", 1455)])
Jon Loeligerb15ad952019-11-14 16:44:40 -0600500 p4 = p_ether / p_ip4 / p_tcp
501
502 self.pg1.add_stream(p4)
503 self.pg_enable_capture(self.pg_interfaces)
504 self.pg_start()
505
506 rx = self.pg1.get_capture(1)
507 rx = rx[0]
508
509 self.assertTrue(rx.haslayer(IPv6))
510 self.assertEqual(rx[IP].src, p4[IP].src)
511 self.assertEqual(rx[IP].dst, p4[IP].dst)
512 self.assertEqual(rx[IPv6].src, "3000::1")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200513 self.assertEqual(rx[TCP].options, TCP(options=[("MSS", mss_clamp)]).options)
Jon Loeligerb15ad952019-11-14 16:44:40 -0600514
Ole Troan9be93c82018-09-28 14:28:00 +0200515 def validate(self, rx, expected):
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -0700516 self.assertEqual(rx, expected.__class__(scapy.compat.raw(expected)))
Ole Troan9be93c82018-09-28 14:28:00 +0200517
Vladimir Isaev92511312020-02-26 14:41:46 +0300518 def validate_frag6(self, p6_frag, p_ip6_expected):
Alexander Chernavin31b1a6c2020-01-17 08:31:04 -0500519 self.assertFalse(p6_frag.haslayer(IP))
520 self.assertTrue(p6_frag.haslayer(IPv6))
521 self.assertTrue(p6_frag.haslayer(IPv6ExtHdrFragment))
522 self.assertEqual(p6_frag[IPv6].src, p_ip6_expected.src)
523 self.assertEqual(p6_frag[IPv6].dst, p_ip6_expected.dst)
524
Vladimir Isaev92511312020-02-26 14:41:46 +0300525 def validate_frag_payload_len6(self, rx, proto, payload_len_expected):
Alexander Chernavin31b1a6c2020-01-17 08:31:04 -0500526 payload_total = 0
527 for p in rx:
528 payload_total += p[IPv6].plen
529
530 # First fragment has proto
531 payload_total -= len(proto())
532
533 # Every fragment has IPv6 fragment header
534 payload_total -= len(IPv6ExtHdrFragment()) * len(rx)
535
536 self.assertEqual(payload_total, payload_len_expected)
537
Vladimir Isaev92511312020-02-26 14:41:46 +0300538 def validate_frag4(self, p4_frag, p_ip4_expected):
539 self.assertFalse(p4_frag.haslayer(IPv6))
540 self.assertTrue(p4_frag.haslayer(IP))
541 self.assertTrue(p4_frag[IP].frag != 0 or p4_frag[IP].flags.MF)
542 self.assertEqual(p4_frag[IP].src, p_ip4_expected.src)
543 self.assertEqual(p4_frag[IP].dst, p_ip4_expected.dst)
544
545 def validate_frag_payload_len4(self, rx, proto, payload_len_expected):
546 payload_total = 0
547 for p in rx:
548 payload_total += len(p[IP].payload)
549
550 # First fragment has proto
551 payload_total -= len(proto())
552
553 self.assertEqual(payload_total, payload_len_expected)
554
Ole Troan9be93c82018-09-28 14:28:00 +0200555 def payload(self, len):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200556 return "x" * len
Ole Troan9be93c82018-09-28 14:28:00 +0200557
558 def test_map_t(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200559 """MAP-T"""
Ole Troan9be93c82018-09-28 14:28:00 +0200560
561 #
562 # Add a domain that maps from pg0 to pg1
563 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200564 map_dst = "2001:db8::/32"
565 map_src = "1234:5678:90ab:cdef::/64"
566 ip4_pfx = "192.168.0.0/24"
567 tag = "MAP-T Tag."
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600568
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200569 self.vapi.map_add_domain(
570 ip6_prefix=map_dst,
571 ip4_prefix=ip4_pfx,
572 ip6_src=map_src,
573 ea_bits_len=16,
574 psid_offset=6,
575 psid_length=4,
576 mtu=1500,
577 tag=tag,
578 )
Ole Troan9be93c82018-09-28 14:28:00 +0200579
580 # Enable MAP-T on interfaces.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200581 self.vapi.map_if_enable_disable(
582 is_enable=1, sw_if_index=self.pg0.sw_if_index, is_translation=1
583 )
584 self.vapi.map_if_enable_disable(
585 is_enable=1, sw_if_index=self.pg1.sw_if_index, is_translation=1
586 )
Ole Troan9be93c82018-09-28 14:28:00 +0200587
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600588 # Ensure MAP doesn't steal all packets!
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200589 v4 = (
590 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
591 / IP(src=self.pg0.remote_ip4, dst=self.pg0.remote_ip4)
592 / UDP(sport=20000, dport=10000)
593 / Raw(b"\xa5" * 100)
594 )
595 rx = self.send_and_expect(self.pg0, v4 * 1, self.pg0)
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600596 v4_reply = v4[1]
597 v4_reply.ttl -= 1
598 for p in rx:
599 self.validate(p[1], v4_reply)
600 # Ensure MAP doesn't steal all packets
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200601 v6 = (
602 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
603 / IPv6(src=self.pg1.remote_ip6, dst=self.pg1.remote_ip6)
604 / UDP(sport=20000, dport=10000)
605 / Raw(b"\xa5" * 100)
606 )
607 rx = self.send_and_expect(self.pg1, v6 * 1, self.pg1)
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600608 v6_reply = v6[1]
609 v6_reply.hlim -= 1
610 for p in rx:
611 self.validate(p[1], v6_reply)
Ole Troan9be93c82018-09-28 14:28:00 +0200612
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200613 map_route = VppIpRoute(
614 self,
615 "2001:db8::",
616 32,
617 [
618 VppRoutePath(
619 self.pg1.remote_ip6,
620 self.pg1.sw_if_index,
621 proto=DpoProto.DPO_PROTO_IP6,
622 )
623 ],
624 )
Ole Troan9be93c82018-09-28 14:28:00 +0200625 map_route.add_vpp_config()
626
627 #
628 # Send a v4 packet that will be translated
629 #
630 p_ether = Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200631 p_ip4 = IP(src=self.pg0.remote_ip4, dst="192.168.0.1")
632 payload = TCP(sport=0xABCD, dport=0xABCD)
Ole Troan9be93c82018-09-28 14:28:00 +0200633
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200634 p4 = p_ether / p_ip4 / payload
635 p6_translated = (
636 IPv6(src="1234:5678:90ab:cdef:ac:1001:200:0", dst="2001:db8:1f0::c0a8:1:f")
637 / payload
638 )
Ole Troan9be93c82018-09-28 14:28:00 +0200639 p6_translated.hlim -= 1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200640 rx = self.send_and_expect(self.pg0, p4 * 1, self.pg1)
Ole Troan9be93c82018-09-28 14:28:00 +0200641 for p in rx:
642 self.validate(p[1], p6_translated)
643
644 # Send back an IPv6 packet that will be "untranslated"
645 p_ether6 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200646 p_ip6 = IPv6(
647 src="2001:db8:1f0::c0a8:1:f", dst="1234:5678:90ab:cdef:ac:1001:200:0"
648 )
649 p6 = p_ether6 / p_ip6 / payload
650 p4_translated = IP(src="192.168.0.1", dst=self.pg0.remote_ip4) / payload
Ole Troan9be93c82018-09-28 14:28:00 +0200651 p4_translated.id = 0
652 p4_translated.ttl -= 1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200653 rx = self.send_and_expect(self.pg1, p6 * 1, self.pg0)
Ole Troan9be93c82018-09-28 14:28:00 +0200654 for p in rx:
655 self.validate(p[1], p4_translated)
656
Alexander Chernavin56817e22020-01-23 08:09:40 -0500657 # IPv4 TTL=0
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200658 ip4_ttl_expired = IP(src=self.pg0.remote_ip4, dst="192.168.0.1", ttl=0)
659 p4 = p_ether / ip4_ttl_expired / payload
Ole Troan9be93c82018-09-28 14:28:00 +0200660
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200661 icmp4_reply = (
Maxime Peim2cc14de2024-02-12 10:08:03 +0100662 IP(id=0, ttl=255, src=self.pg0.local_ip4, dst=self.pg0.remote_ip4)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200663 / ICMP(type="time-exceeded", code="ttl-zero-during-transit")
664 / IP(src=self.pg0.remote_ip4, dst="192.168.0.1", ttl=0)
665 / payload
666 )
667 rx = self.send_and_expect(self.pg0, p4 * 1, self.pg0)
Ole Troan9be93c82018-09-28 14:28:00 +0200668 for p in rx:
669 self.validate(p[1], icmp4_reply)
670
Alexander Chernavin56817e22020-01-23 08:09:40 -0500671 # IPv4 TTL=1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200672 ip4_ttl_expired = IP(src=self.pg0.remote_ip4, dst="192.168.0.1", ttl=1)
673 p4 = p_ether / ip4_ttl_expired / payload
Ole Troan9be93c82018-09-28 14:28:00 +0200674
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200675 icmp4_reply = (
Maxime Peim2cc14de2024-02-12 10:08:03 +0100676 IP(id=0, ttl=255, src=self.pg0.local_ip4, dst=self.pg0.remote_ip4)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200677 / ICMP(type="time-exceeded", code="ttl-zero-during-transit")
678 / IP(src=self.pg0.remote_ip4, dst="192.168.0.1", ttl=1)
679 / payload
680 )
681 rx = self.send_and_expect(self.pg0, p4 * 1, self.pg0)
Ole Troan9be93c82018-09-28 14:28:00 +0200682 for p in rx:
683 self.validate(p[1], icmp4_reply)
Ole Troan9be93c82018-09-28 14:28:00 +0200684
Vladimir Ratnikovb1bd8762020-03-18 08:20:08 -0400685 # IPv6 Hop limit at BR
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200686 ip6_hlim_expired = IPv6(
687 hlim=1,
688 src="2001:db8:1ab::c0a8:1:ab",
689 dst="1234:5678:90ab:cdef:ac:1001:200:0",
690 )
691 p6 = p_ether6 / ip6_hlim_expired / payload
Vladimir Ratnikovb1bd8762020-03-18 08:20:08 -0400692
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200693 icmp6_reply = (
694 IPv6(hlim=255, src=self.pg1.local_ip6, dst="2001:db8:1ab::c0a8:1:ab")
695 / ICMPv6TimeExceeded(code=0)
696 / IPv6(
697 src="2001:db8:1ab::c0a8:1:ab",
698 dst="1234:5678:90ab:cdef:ac:1001:200:0",
699 hlim=1,
700 )
701 / payload
702 )
703 rx = self.send_and_expect(self.pg1, p6 * 1, self.pg1)
Vladimir Ratnikovb1bd8762020-03-18 08:20:08 -0400704 for p in rx:
705 self.validate(p[1], icmp6_reply)
706
707 # IPv6 Hop limit beyond BR
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200708 ip6_hlim_expired = IPv6(
709 hlim=0,
710 src="2001:db8:1ab::c0a8:1:ab",
711 dst="1234:5678:90ab:cdef:ac:1001:200:0",
712 )
713 p6 = p_ether6 / ip6_hlim_expired / payload
Ole Troan9be93c82018-09-28 14:28:00 +0200714
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200715 icmp6_reply = (
716 IPv6(hlim=255, src=self.pg1.local_ip6, dst="2001:db8:1ab::c0a8:1:ab")
717 / ICMPv6TimeExceeded(code=0)
718 / IPv6(
719 src="2001:db8:1ab::c0a8:1:ab",
720 dst="1234:5678:90ab:cdef:ac:1001:200:0",
721 hlim=0,
722 )
723 / payload
724 )
725 rx = self.send_and_expect(self.pg1, p6 * 1, self.pg1)
Ole Troan9be93c82018-09-28 14:28:00 +0200726 for p in rx:
727 self.validate(p[1], icmp6_reply)
728
729 # IPv4 Well-known port
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200730 p_ip4 = IP(src=self.pg0.remote_ip4, dst="192.168.0.1")
Ole Troan9be93c82018-09-28 14:28:00 +0200731 payload = UDP(sport=200, dport=200)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200732 p4 = p_ether / p_ip4 / payload
733 self.send_and_assert_no_replies(self.pg0, p4 * 1)
Ole Troan9be93c82018-09-28 14:28:00 +0200734
735 # IPv6 Well-known port
736 payload = UDP(sport=200, dport=200)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200737 p6 = p_ether6 / p_ip6 / payload
738 self.send_and_assert_no_replies(self.pg1, p6 * 1)
Ole Troan9be93c82018-09-28 14:28:00 +0200739
Alexander Chernavin8af24b12020-01-31 09:19:49 -0500740 # UDP packet fragmentation
Alexander Chernavin31b1a6c2020-01-17 08:31:04 -0500741 payload_len = 1453
742 payload = UDP(sport=40000, dport=4000) / self.payload(payload_len)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200743 p4 = p_ether / p_ip4 / payload
Ole Troan9be93c82018-09-28 14:28:00 +0200744 self.pg_enable_capture()
745 self.pg0.add_stream(p4)
746 self.pg_start()
747 rx = self.pg1.get_capture(2)
Alexander Chernavin31b1a6c2020-01-17 08:31:04 -0500748
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200749 p_ip6_translated = IPv6(
750 src="1234:5678:90ab:cdef:ac:1001:200:0", dst="2001:db8:1e0::c0a8:1:e"
751 )
Ole Troan9be93c82018-09-28 14:28:00 +0200752 for p in rx:
Vladimir Isaev92511312020-02-26 14:41:46 +0300753 self.validate_frag6(p, p_ip6_translated)
Alexander Chernavin31b1a6c2020-01-17 08:31:04 -0500754
Vladimir Isaev92511312020-02-26 14:41:46 +0300755 self.validate_frag_payload_len6(rx, UDP, payload_len)
Ole Troan9be93c82018-09-28 14:28:00 +0200756
Alexander Chernavin8af24b12020-01-31 09:19:49 -0500757 # UDP packet fragmentation send fragments
Vladimir Isaev92511312020-02-26 14:41:46 +0300758 payload_len = 1453
Alexander Chernavin31b1a6c2020-01-17 08:31:04 -0500759 payload = UDP(sport=40000, dport=4000) / self.payload(payload_len)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200760 p4 = p_ether / p_ip4 / payload
Alexander Chernavin31b1a6c2020-01-17 08:31:04 -0500761 frags = fragment_rfc791(p4, fragsize=1000)
Ole Troan9be93c82018-09-28 14:28:00 +0200762 self.pg_enable_capture()
763 self.pg0.add_stream(frags)
764 self.pg_start()
765 rx = self.pg1.get_capture(2)
Alexander Chernavin31b1a6c2020-01-17 08:31:04 -0500766
Ole Troan9be93c82018-09-28 14:28:00 +0200767 for p in rx:
Vladimir Isaev92511312020-02-26 14:41:46 +0300768 self.validate_frag6(p, p_ip6_translated)
Alexander Chernavin31b1a6c2020-01-17 08:31:04 -0500769
Vladimir Isaev92511312020-02-26 14:41:46 +0300770 self.validate_frag_payload_len6(rx, UDP, payload_len)
771
772 # Send back an fragmented IPv6 UDP packet that will be "untranslated"
773 payload = UDP(sport=4000, dport=40000) / self.payload(payload_len)
774 p_ether6 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200775 p_ip6 = IPv6(
776 src="2001:db8:1e0::c0a8:1:e", dst="1234:5678:90ab:cdef:ac:1001:200:0"
777 )
778 p6 = p_ether6 / p_ip6 / payload
779 frags6 = fragment_rfc8200(p6, identification=0xDCBA, fragsize=1000)
Vladimir Isaev92511312020-02-26 14:41:46 +0300780
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200781 p_ip4_translated = IP(src="192.168.0.1", dst=self.pg0.remote_ip4)
782 p4_translated = p_ip4_translated / payload
Vladimir Isaev92511312020-02-26 14:41:46 +0300783 p4_translated.id = 0
784 p4_translated.ttl -= 1
785
786 self.pg_enable_capture()
787 self.pg1.add_stream(frags6)
788 self.pg_start()
789 rx = self.pg0.get_capture(2)
790
791 for p in rx:
792 self.validate_frag4(p, p4_translated)
793
794 self.validate_frag_payload_len4(rx, UDP, payload_len)
Klement Sekera640edcd2019-09-23 09:00:30 +0000795
Alexander Chernavin8af24b12020-01-31 09:19:49 -0500796 # ICMP packet fragmentation
797 payload = ICMP(id=6529) / self.payload(payload_len)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200798 p4 = p_ether / p_ip4 / payload
Alexander Chernavin8af24b12020-01-31 09:19:49 -0500799 self.pg_enable_capture()
800 self.pg0.add_stream(p4)
801 self.pg_start()
802 rx = self.pg1.get_capture(2)
803
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200804 p_ip6_translated = IPv6(
805 src="1234:5678:90ab:cdef:ac:1001:200:0", dst="2001:db8:160::c0a8:1:6"
806 )
Alexander Chernavin8af24b12020-01-31 09:19:49 -0500807 for p in rx:
Vladimir Isaev92511312020-02-26 14:41:46 +0300808 self.validate_frag6(p, p_ip6_translated)
Alexander Chernavin8af24b12020-01-31 09:19:49 -0500809
Vladimir Isaev92511312020-02-26 14:41:46 +0300810 self.validate_frag_payload_len6(rx, ICMPv6EchoRequest, payload_len)
Alexander Chernavin8af24b12020-01-31 09:19:49 -0500811
812 # ICMP packet fragmentation send fragments
813 payload = ICMP(id=6529) / self.payload(payload_len)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200814 p4 = p_ether / p_ip4 / payload
Alexander Chernavin8af24b12020-01-31 09:19:49 -0500815 frags = fragment_rfc791(p4, fragsize=1000)
816 self.pg_enable_capture()
817 self.pg0.add_stream(frags)
818 self.pg_start()
819 rx = self.pg1.get_capture(2)
820
821 for p in rx:
Vladimir Isaev92511312020-02-26 14:41:46 +0300822 self.validate_frag6(p, p_ip6_translated)
Alexander Chernavin8af24b12020-01-31 09:19:49 -0500823
Vladimir Isaev92511312020-02-26 14:41:46 +0300824 self.validate_frag_payload_len6(rx, ICMPv6EchoRequest, payload_len)
Ole Troan9be93c82018-09-28 14:28:00 +0200825
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600826 # TCP MSS clamping
827 self.vapi.map_param_set_tcp(1300)
828
829 #
830 # Send a v4 TCP SYN packet that will be translated and MSS clamped
831 #
832 p_ether = Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200833 p_ip4 = IP(src=self.pg0.remote_ip4, dst="192.168.0.1")
834 payload = TCP(sport=0xABCD, dport=0xABCD, flags="S", options=[("MSS", 1460)])
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600835
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200836 p4 = p_ether / p_ip4 / payload
837 p6_translated = (
838 IPv6(src="1234:5678:90ab:cdef:ac:1001:200:0", dst="2001:db8:1f0::c0a8:1:f")
839 / payload
840 )
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600841 p6_translated.hlim -= 1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200842 p6_translated[TCP].options = [("MSS", 1300)]
843 rx = self.send_and_expect(self.pg0, p4 * 1, self.pg1)
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600844 for p in rx:
845 self.validate(p[1], p6_translated)
846
847 # Send back an IPv6 packet that will be "untranslated"
848 p_ether6 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200849 p_ip6 = IPv6(
850 src="2001:db8:1f0::c0a8:1:f", dst="1234:5678:90ab:cdef:ac:1001:200:0"
851 )
852 p6 = p_ether6 / p_ip6 / payload
853 p4_translated = IP(src="192.168.0.1", dst=self.pg0.remote_ip4) / payload
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600854 p4_translated.id = 0
855 p4_translated.ttl -= 1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200856 p4_translated[TCP].options = [("MSS", 1300)]
857 rx = self.send_and_expect(self.pg1, p6 * 1, self.pg0)
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600858 for p in rx:
859 self.validate(p[1], p4_translated)
860
Alexander Chernavinb728a3c2020-02-05 09:05:06 -0500861 # TCP MSS clamping cleanup
862 self.vapi.map_param_set_tcp(0)
863
864 # Enable icmp6 param to get back ICMPv6 unreachable messages in case
865 # of security check fails
866 self.vapi.map_param_set_icmp6(enable_unreachable=1)
867
868 # Send back an IPv6 packet that will be droppped due to security
869 # check fail
870 p_ether6 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200871 p_ip6_sec_check_fail = IPv6(
872 src="2001:db8:1fe::c0a8:1:f", dst="1234:5678:90ab:cdef:ac:1001:200:0"
873 )
874 payload = TCP(sport=0xABCD, dport=0xABCD)
875 p6 = p_ether6 / p_ip6_sec_check_fail / payload
Alexander Chernavinb728a3c2020-02-05 09:05:06 -0500876
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200877 self.pg_send(self.pg1, p6 * 1)
Alexander Chernavinb728a3c2020-02-05 09:05:06 -0500878 self.pg0.get_capture(0, timeout=1)
879 rx = self.pg1.get_capture(1)
880
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200881 icmp6_reply = (
882 IPv6(hlim=255, src=self.pg1.local_ip6, dst="2001:db8:1fe::c0a8:1:f")
883 / ICMPv6DestUnreach(code=5)
884 / p_ip6_sec_check_fail
885 / payload
886 )
Alexander Chernavinb728a3c2020-02-05 09:05:06 -0500887
888 for p in rx:
889 self.validate(p[1], icmp6_reply)
890
891 # ICMPv6 unreachable messages cleanup
892 self.vapi.map_param_set_icmp6(enable_unreachable=0)
893
Matthew Smith9f356962019-12-04 15:02:46 -0600894 def test_map_t_ip6_psid(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200895 """MAP-T v6->v4 PSID validation"""
Matthew Smith9f356962019-12-04 15:02:46 -0600896
897 #
898 # Add a domain that maps from pg0 to pg1
899 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200900 map_dst = "2001:db8::/32"
901 map_src = "1234:5678:90ab:cdef::/64"
902 ip4_pfx = "192.168.0.0/24"
903 tag = "MAP-T Test Domain"
Matthew Smith9f356962019-12-04 15:02:46 -0600904
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200905 self.vapi.map_add_domain(
906 ip6_prefix=map_dst,
907 ip4_prefix=ip4_pfx,
908 ip6_src=map_src,
909 ea_bits_len=16,
910 psid_offset=6,
911 psid_length=4,
912 mtu=1500,
913 tag=tag,
914 )
Matthew Smith9f356962019-12-04 15:02:46 -0600915
916 # Enable MAP-T on interfaces.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200917 self.vapi.map_if_enable_disable(
918 is_enable=1, sw_if_index=self.pg0.sw_if_index, is_translation=1
919 )
920 self.vapi.map_if_enable_disable(
921 is_enable=1, sw_if_index=self.pg1.sw_if_index, is_translation=1
922 )
Matthew Smith9f356962019-12-04 15:02:46 -0600923
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200924 map_route = VppIpRoute(
925 self,
926 "2001:db8::",
927 32,
928 [
929 VppRoutePath(
930 self.pg1.remote_ip6,
931 self.pg1.sw_if_index,
932 proto=DpoProto.DPO_PROTO_IP6,
933 )
934 ],
935 )
Matthew Smith9f356962019-12-04 15:02:46 -0600936 map_route.add_vpp_config()
937
938 p_ether6 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200939 p_ip6 = IPv6(
940 src="2001:db8:1f0::c0a8:1:f", dst="1234:5678:90ab:cdef:ac:1001:200:0"
941 )
Matthew Smith9f356962019-12-04 15:02:46 -0600942
943 # Send good IPv6 source port, ensure translated IPv4 received
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200944 payload = TCP(sport=0xABCD, dport=80)
945 p6 = p_ether6 / p_ip6 / payload
946 p4_translated = IP(src="192.168.0.1", dst=self.pg0.remote_ip4) / payload
Matthew Smith9f356962019-12-04 15:02:46 -0600947 p4_translated.id = 0
948 p4_translated.ttl -= 1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200949 rx = self.send_and_expect(self.pg1, p6 * 1, self.pg0)
Matthew Smith9f356962019-12-04 15:02:46 -0600950 for p in rx:
951 self.validate(p[1], p4_translated)
952
953 # Send bad IPv6 source port, ensure translated IPv4 not received
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200954 payload = TCP(sport=0xDCBA, dport=80)
955 p6 = p_ether6 / p_ip6 / payload
956 self.send_and_assert_no_replies(self.pg1, p6 * 1)
Ole Troan9be93c82018-09-28 14:28:00 +0200957
Alexander Chernavinf145c152020-02-11 09:57:09 -0500958 def test_map_t_pre_resolve(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200959 """MAP-T pre-resolve"""
Alexander Chernavinf145c152020-02-11 09:57:09 -0500960
961 # Add a domain that maps from pg0 to pg1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200962 map_dst = "2001:db8::/32"
963 map_src = "1234:5678:90ab:cdef::/64"
964 ip4_pfx = "192.168.0.0/24"
965 tag = "MAP-T Test Domain."
Alexander Chernavinf145c152020-02-11 09:57:09 -0500966
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200967 self.vapi.map_add_domain(
968 ip6_prefix=map_dst,
969 ip4_prefix=ip4_pfx,
970 ip6_src=map_src,
971 ea_bits_len=16,
972 psid_offset=6,
973 psid_length=4,
974 mtu=1500,
975 tag=tag,
976 )
Alexander Chernavinf145c152020-02-11 09:57:09 -0500977
978 # Enable MAP-T on interfaces.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200979 self.vapi.map_if_enable_disable(
980 is_enable=1, sw_if_index=self.pg0.sw_if_index, is_translation=1
981 )
982 self.vapi.map_if_enable_disable(
983 is_enable=1, sw_if_index=self.pg1.sw_if_index, is_translation=1
984 )
Alexander Chernavinf145c152020-02-11 09:57:09 -0500985
986 # Enable pre-resolve option
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200987 self.vapi.map_param_add_del_pre_resolve(
988 ip4_nh_address="10.1.2.3", ip6_nh_address="4001::1", is_add=1
989 )
Alexander Chernavinf145c152020-02-11 09:57:09 -0500990
991 # Add a route to 4001::1 and expect the translated traffic to be
992 # sent via that route next-hop.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200993 pre_res_route6 = VppIpRoute(
994 self,
995 "4001::1",
996 128,
997 [VppRoutePath(self.pg1.remote_hosts[2].ip6, self.pg1.sw_if_index)],
998 )
Alexander Chernavinf145c152020-02-11 09:57:09 -0500999 pre_res_route6.add_vpp_config()
1000
1001 # Add a route to 10.1.2.3 and expect the "untranslated" traffic to be
1002 # sent via that route next-hop.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001003 pre_res_route4 = VppIpRoute(
1004 self,
1005 "10.1.2.3",
1006 32,
1007 [VppRoutePath(self.pg0.remote_hosts[1].ip4, self.pg0.sw_if_index)],
1008 )
Alexander Chernavinf145c152020-02-11 09:57:09 -05001009 pre_res_route4.add_vpp_config()
1010
1011 # Send an IPv4 packet that will be translated
1012 p_ether = Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001013 p_ip4 = IP(src=self.pg0.remote_ip4, dst="192.168.0.1")
1014 payload = TCP(sport=0xABCD, dport=0xABCD)
1015 p4 = p_ether / p_ip4 / payload
Alexander Chernavinf145c152020-02-11 09:57:09 -05001016
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001017 p6_translated = (
1018 IPv6(src="1234:5678:90ab:cdef:ac:1001:200:0", dst="2001:db8:1f0::c0a8:1:f")
1019 / payload
1020 )
Alexander Chernavinf145c152020-02-11 09:57:09 -05001021 p6_translated.hlim -= 1
1022
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001023 rx = self.send_and_expect(self.pg0, p4 * 1, self.pg1)
Alexander Chernavinf145c152020-02-11 09:57:09 -05001024 for p in rx:
1025 self.assertEqual(p[Ether].dst, self.pg1.remote_hosts[2].mac)
1026 self.validate(p[1], p6_translated)
1027
1028 # Send back an IPv6 packet that will be "untranslated"
1029 p_ether6 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001030 p_ip6 = IPv6(
1031 src="2001:db8:1f0::c0a8:1:f", dst="1234:5678:90ab:cdef:ac:1001:200:0"
1032 )
1033 p6 = p_ether6 / p_ip6 / payload
Alexander Chernavinf145c152020-02-11 09:57:09 -05001034
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001035 p4_translated = IP(src="192.168.0.1", dst=self.pg0.remote_ip4) / payload
Alexander Chernavinf145c152020-02-11 09:57:09 -05001036 p4_translated.id = 0
1037 p4_translated.ttl -= 1
1038
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001039 rx = self.send_and_expect(self.pg1, p6 * 1, self.pg0)
Alexander Chernavinf145c152020-02-11 09:57:09 -05001040 for p in rx:
1041 self.assertEqual(p[Ether].dst, self.pg0.remote_hosts[1].mac)
1042 self.validate(p[1], p4_translated)
1043
1044 # Cleanup pre-resolve option
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001045 self.vapi.map_param_add_del_pre_resolve(
1046 ip4_nh_address="10.1.2.3", ip6_nh_address="4001::1", is_add=0
1047 )
Alexander Chernavinf145c152020-02-11 09:57:09 -05001048
Ole Troanf5db3712020-05-20 15:47:06 +02001049
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001050if __name__ == "__main__":
Neale Ranns80823802017-02-20 18:23:41 -08001051 unittest.main(testRunner=VppTestRunner)