blob: ffa9218b0c383b2d1fe87afb582ff310e17f0777 [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
Dmitry Valter34fa0ce2024-03-11 10:38:46 +000011from config import config
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -070012
13import scapy.compat
snaramre5d4b8912019-12-13 23:39:35 +000014from scapy.layers.l2 import Ether
15from scapy.packet import Raw
Alexander Chernavin31b1a6c2020-01-17 08:31:04 -050016from scapy.layers.inet import IP, UDP, ICMP, TCP
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020017from scapy.layers.inet6 import (
18 IPv6,
19 ICMPv6TimeExceeded,
20 IPv6ExtHdrFragment,
21 ICMPv6EchoRequest,
22 ICMPv6DestUnreach,
23)
Neale Ranns80823802017-02-20 18:23:41 -080024
25
Dmitry Valter34fa0ce2024-03-11 10:38:46 +000026@unittest.skipIf("map" in config.excluded_plugins, "Exclude MAP plugin tests")
Neale Ranns80823802017-02-20 18:23:41 -080027class TestMAP(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020028 """MAP Test Case"""
Neale Ranns80823802017-02-20 18:23:41 -080029
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -070030 @classmethod
31 def setUpClass(cls):
32 super(TestMAP, cls).setUpClass()
33
34 @classmethod
35 def tearDownClass(cls):
36 super(TestMAP, cls).tearDownClass()
37
Neale Ranns80823802017-02-20 18:23:41 -080038 def setUp(self):
39 super(TestMAP, self).setUp()
40
41 # create 2 pg interfaces
42 self.create_pg_interfaces(range(4))
43
44 # pg0 is 'inside' IPv4
45 self.pg0.admin_up()
46 self.pg0.config_ip4()
47 self.pg0.resolve_arp()
Alexander Chernavinf145c152020-02-11 09:57:09 -050048 self.pg0.generate_remote_hosts(2)
49 self.pg0.configure_ipv4_neighbors()
Neale Ranns80823802017-02-20 18:23:41 -080050
51 # pg1 is 'outside' IPv6
52 self.pg1.admin_up()
53 self.pg1.config_ip6()
54 self.pg1.generate_remote_hosts(4)
55 self.pg1.configure_ipv6_neighbors()
56
57 def tearDown(self):
58 super(TestMAP, self).tearDown()
Maxime Peim23d13c02023-08-01 11:29:15 +020059
Neale Ranns80823802017-02-20 18:23:41 -080060 for i in self.pg_interfaces:
Maxime Peim23d13c02023-08-01 11:29:15 +020061 for t in (0, 1):
62 self.vapi.map_if_enable_disable(
63 is_enable=0, sw_if_index=i.sw_if_index, is_translation=t
64 )
Neale Ranns80823802017-02-20 18:23:41 -080065 i.unconfig_ip4()
66 i.unconfig_ip6()
67 i.admin_down()
68
Klement Sekeraa025b3e2019-08-21 10:53:14 +000069 def send_and_assert_encapped(self, packets, ip6_src, ip6_dst, dmac=None):
Neale Ranns80823802017-02-20 18:23:41 -080070 if not dmac:
71 dmac = self.pg1.remote_mac
72
Klement Sekeraa025b3e2019-08-21 10:53:14 +000073 self.pg0.add_stream(packets)
Neale Ranns80823802017-02-20 18:23:41 -080074
75 self.pg_enable_capture(self.pg_interfaces)
76 self.pg_start()
77
Klement Sekeraa025b3e2019-08-21 10:53:14 +000078 capture = self.pg1.get_capture(len(packets))
79 for rx, tx in zip(capture, packets):
80 self.assertEqual(rx[Ether].dst, dmac)
81 self.assertEqual(rx[IP].src, tx[IP].src)
82 self.assertEqual(rx[IPv6].src, ip6_src)
83 self.assertEqual(rx[IPv6].dst, ip6_dst)
Neale Ranns80823802017-02-20 18:23:41 -080084
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020085 def send_and_assert_encapped_one(self, packet, ip6_src, ip6_dst, dmac=None):
Klement Sekeraa025b3e2019-08-21 10:53:14 +000086 return self.send_and_assert_encapped([packet], ip6_src, ip6_dst, dmac)
Neale Ranns80823802017-02-20 18:23:41 -080087
Paul Vinciguerra4d376f62019-05-24 06:36:26 -040088 def test_api_map_domain_dump(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020089 map_dst = "2001::/64"
90 map_src = "3000::1/128"
91 client_pfx = "192.168.0.0/16"
92 tag = "MAP-E tag."
93 index = self.vapi.map_add_domain(
94 ip4_prefix=client_pfx, ip6_prefix=map_dst, ip6_src=map_src, tag=tag
95 ).index
Paul Vinciguerra4d376f62019-05-24 06:36:26 -040096 rv = self.vapi.map_domain_dump()
97
98 # restore the state early so as to not impact subsequent tests.
99 # If an assert fails, we will not get the chance to do it at the end.
100 self.vapi.map_del_domain(index=index)
101
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200102 self.assertGreater(len(rv), 0, "Expected output from 'map_domain_dump'")
Paul Vinciguerra4d376f62019-05-24 06:36:26 -0400103
104 # typedefs are returned as ipaddress objects.
105 # wrap results in str() ugh! to avoid the need to call unicode.
106 self.assertEqual(str(rv[0].ip4_prefix), client_pfx)
107 self.assertEqual(str(rv[0].ip6_prefix), map_dst)
108 self.assertEqual(str(rv[0].ip6_src), map_src)
109
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200110 self.assertEqual(rv[0].tag, tag, "output produced incorrect tag value.")
Paul Vinciguerra4d376f62019-05-24 06:36:26 -0400111
Ole Troanf5db3712020-05-20 15:47:06 +0200112 def create_domains(self, ip4_pfx_str, ip6_pfx_str, ip6_src_str):
113 ip4_pfx = ipaddress.ip_network(ip4_pfx_str)
114 ip6_dst = ipaddress.ip_network(ip6_pfx_str)
115 mod = ip4_pfx.num_addresses / 1024
116 indicies = []
117 for i in range(ip4_pfx.num_addresses):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200118 rv = self.vapi.map_add_domain(
119 ip6_prefix=ip6_pfx_str,
120 ip4_prefix=str(ip4_pfx[i]) + "/32",
121 ip6_src=ip6_src_str,
122 )
Ole Troanf5db3712020-05-20 15:47:06 +0200123 indicies.append(rv.index)
124 return indicies
125
126 def test_api_map_domains_get(self):
127 # Create a bunch of domains
Ole Troan4376ab22021-03-03 10:40:05 +0100128 no_domains = 4096 # This must be large enough to ensure VPP suspends
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200129 domains = self.create_domains("130.67.0.0/20", "2001::/32", "2001::1/128")
Ole Troan4376ab22021-03-03 10:40:05 +0100130 self.assertEqual(len(domains), no_domains)
Ole Troanf5db3712020-05-20 15:47:06 +0200131
132 d = []
133 cursor = 0
134
135 # Invalid cursor
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200136 rv, details = self.vapi.map_domains_get(cursor=no_domains + 10)
Ole Troanf5db3712020-05-20 15:47:06 +0200137 self.assertEqual(rv.retval, -7)
138
139 # Delete a domain in the middle of walk
140 rv, details = self.vapi.map_domains_get(cursor=0)
141 self.assertEqual(rv.retval, -165)
142 self.vapi.map_del_domain(index=rv.cursor)
143 domains.remove(rv.cursor)
144
145 # Continue at point of deleted cursor
146 rv, details = self.vapi.map_domains_get(cursor=rv.cursor)
Ole Troan9bf487f2021-03-30 00:51:41 +0200147 self.assertIn(rv.retval, [0, -165])
Ole Troanf5db3712020-05-20 15:47:06 +0200148
149 d = list(self.vapi.vpp.details_iter(self.vapi.map_domains_get))
Ole Troan4376ab22021-03-03 10:40:05 +0100150 self.assertEqual(len(d), no_domains - 1)
Ole Troanf5db3712020-05-20 15:47:06 +0200151
152 # Clean up
153 for i in domains:
154 self.vapi.map_del_domain(index=i)
155
Jon Loeligerb15ad952019-11-14 16:44:40 -0600156 def test_map_e_udp(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200157 """MAP-E UDP"""
Neale Ranns80823802017-02-20 18:23:41 -0800158
159 #
160 # Add a route to the MAP-BR
161 #
162 map_br_pfx = "2001::"
Klement Sekeraa025b3e2019-08-21 10:53:14 +0000163 map_br_pfx_len = 32
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200164 map_route = VppIpRoute(
165 self,
166 map_br_pfx,
167 map_br_pfx_len,
168 [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index)],
169 )
Neale Ranns80823802017-02-20 18:23:41 -0800170 map_route.add_vpp_config()
171
172 #
173 # Add a domain that maps from pg0 to pg1
174 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200175 map_dst = "2001::/32"
176 map_src = "3000::1/128"
177 client_pfx = "192.168.0.0/16"
178 map_translated_addr = "2001:0:101:7000:0:c0a8:101:7"
179 tag = "MAP-E tag."
180 self.vapi.map_add_domain(
181 ip4_prefix=client_pfx,
182 ip6_prefix=map_dst,
183 ip6_src=map_src,
184 ea_bits_len=20,
185 psid_offset=4,
186 psid_length=4,
187 tag=tag,
188 )
Neale Ranns80823802017-02-20 18:23:41 -0800189
Klement Sekeraa025b3e2019-08-21 10:53:14 +0000190 self.vapi.map_param_set_security_check(enable=1, fragments=1)
191
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600192 # Enable MAP on interface.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200193 self.vapi.map_if_enable_disable(
194 is_enable=1, sw_if_index=self.pg0.sw_if_index, is_translation=0
195 )
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600196
197 # Ensure MAP doesn't steal all packets!
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200198 v4 = (
199 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
200 / IP(src=self.pg0.remote_ip4, dst=self.pg0.remote_ip4)
201 / UDP(sport=20000, dport=10000)
202 / Raw(b"\xa5" * 100)
203 )
Ole Troaneb284a12019-10-09 13:33:19 +0200204 rx = self.send_and_expect(self.pg0, v4 * 4, self.pg0)
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600205 v4_reply = v4[1]
206 v4_reply.ttl -= 1
207 for p in rx:
208 self.validate(p[1], v4_reply)
209
Neale Ranns80823802017-02-20 18:23:41 -0800210 #
211 # Fire in a v4 packet that will be encapped to the BR
212 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200213 v4 = (
214 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
215 / IP(src=self.pg0.remote_ip4, dst="192.168.1.1")
216 / UDP(sport=20000, dport=10000)
217 / Raw(b"\xa5" * 100)
218 )
Neale Ranns80823802017-02-20 18:23:41 -0800219
Ole Troaneb284a12019-10-09 13:33:19 +0200220 self.send_and_assert_encapped(v4 * 4, "3000::1", map_translated_addr)
Klement Sekeraa025b3e2019-08-21 10:53:14 +0000221
Klement Sekeraa025b3e2019-08-21 10:53:14 +0000222 #
223 # Verify reordered fragments are able to pass as well
224 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200225 v4 = (
226 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
227 / IP(id=1, src=self.pg0.remote_ip4, dst="192.168.1.1")
228 / UDP(sport=20000, dport=10000)
229 / Raw(b"\xa5" * 1000)
230 )
Klement Sekeraa025b3e2019-08-21 10:53:14 +0000231
232 frags = fragment_rfc791(v4, 400)
233 frags.reverse()
234
235 self.send_and_assert_encapped(frags, "3000::1", map_translated_addr)
236
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600237 # Enable MAP on interface.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200238 self.vapi.map_if_enable_disable(
239 is_enable=1, sw_if_index=self.pg1.sw_if_index, is_translation=0
240 )
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600241
242 # Ensure MAP doesn't steal all packets
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200243 v6 = (
244 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
245 / IPv6(src=self.pg1.remote_ip6, dst=self.pg1.remote_ip6)
246 / UDP(sport=20000, dport=10000)
247 / Raw(b"\xa5" * 100)
248 )
249 rx = self.send_and_expect(self.pg1, v6 * 1, self.pg1)
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600250 v6_reply = v6[1]
251 v6_reply.hlim -= 1
252 for p in rx:
253 self.validate(p[1], v6_reply)
254
Neale Ranns80823802017-02-20 18:23:41 -0800255 #
256 # Fire in a V6 encapped packet.
Klement Sekeraa025b3e2019-08-21 10:53:14 +0000257 # expect a decapped packet on the inside ip4 link
Neale Ranns80823802017-02-20 18:23:41 -0800258 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200259 p = (
260 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
261 / IPv6(dst="3000::1", src=map_translated_addr)
262 / IP(dst=self.pg0.remote_ip4, src="192.168.1.1")
263 / UDP(sport=10000, dport=20000)
264 / Raw(b"\xa5" * 100)
265 )
Neale Ranns80823802017-02-20 18:23:41 -0800266
267 self.pg1.add_stream(p)
268
269 self.pg_enable_capture(self.pg_interfaces)
270 self.pg_start()
271
272 rx = self.pg0.get_capture(1)
273 rx = rx[0]
274
275 self.assertFalse(rx.haslayer(IPv6))
276 self.assertEqual(rx[IP].src, p[IP].src)
277 self.assertEqual(rx[IP].dst, p[IP].dst)
278
279 #
Klement Sekeraa025b3e2019-08-21 10:53:14 +0000280 # Verify encapped reordered fragments pass as well
281 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200282 p = (
283 IP(id=1, dst=self.pg0.remote_ip4, src="192.168.1.1")
284 / UDP(sport=10000, dport=20000)
285 / Raw(b"\xa5" * 1500)
286 )
Klement Sekeraa025b3e2019-08-21 10:53:14 +0000287 frags = fragment_rfc791(p, 400)
288 frags.reverse()
289
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200290 stream = (
291 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
292 / IPv6(dst="3000::1", src=map_translated_addr)
293 / x
294 for x in frags
295 )
Klement Sekeraa025b3e2019-08-21 10:53:14 +0000296
297 self.pg1.add_stream(stream)
298
299 self.pg_enable_capture(self.pg_interfaces)
300 self.pg_start()
301
302 rx = self.pg0.get_capture(len(frags))
303
304 for r in rx:
305 self.assertFalse(r.haslayer(IPv6))
306 self.assertEqual(r[IP].src, p[IP].src)
307 self.assertEqual(r[IP].dst, p[IP].dst)
308
Klement Sekera7b2e9fb2019-10-01 13:00:22 +0000309 # Verify that fragments pass even if ipv6 layer is fragmented
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200310 stream = (IPv6(dst="3000::1", src=map_translated_addr) / x for x in frags)
Klement Sekera7b2e9fb2019-10-01 13:00:22 +0000311
312 v6_stream = [
313 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / x
314 for i in range(len(frags))
315 for x in fragment_rfc8200(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200316 IPv6(dst="3000::1", src=map_translated_addr) / frags[i], i, 200
317 )
318 ]
Klement Sekera7b2e9fb2019-10-01 13:00:22 +0000319
320 self.pg1.add_stream(v6_stream)
321
322 self.pg_enable_capture(self.pg_interfaces)
323 self.pg_start()
324
325 rx = self.pg0.get_capture(len(frags))
326
327 for r in rx:
328 self.assertFalse(r.haslayer(IPv6))
329 self.assertEqual(r[IP].src, p[IP].src)
330 self.assertEqual(r[IP].dst, p[IP].dst)
331
Klement Sekeraa025b3e2019-08-21 10:53:14 +0000332 #
Neale Ranns80823802017-02-20 18:23:41 -0800333 # Pre-resolve. No API for this!!
334 #
335 self.vapi.ppcli("map params pre-resolve ip6-nh 4001::1")
336
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200337 self.send_and_assert_no_replies(self.pg0, v4, "resolved via default route")
Neale Ranns80823802017-02-20 18:23:41 -0800338
339 #
340 # Add a route to 4001::1. Expect the encapped traffic to be
341 # sent via that routes next-hop
342 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200343 pre_res_route = VppIpRoute(
344 self,
345 "4001::1",
346 128,
347 [VppRoutePath(self.pg1.remote_hosts[2].ip6, self.pg1.sw_if_index)],
348 )
Neale Ranns80823802017-02-20 18:23:41 -0800349 pre_res_route.add_vpp_config()
350
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200351 self.send_and_assert_encapped_one(
352 v4, "3000::1", map_translated_addr, dmac=self.pg1.remote_hosts[2].mac
353 )
Neale Ranns80823802017-02-20 18:23:41 -0800354
355 #
356 # change the route to the pre-solved next-hop
357 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200358 pre_res_route.modify(
359 [VppRoutePath(self.pg1.remote_hosts[3].ip6, self.pg1.sw_if_index)]
360 )
Neale Ranns69b7aa42017-03-10 03:04:12 -0800361 pre_res_route.add_vpp_config()
Neale Ranns80823802017-02-20 18:23:41 -0800362
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200363 self.send_and_assert_encapped_one(
364 v4, "3000::1", map_translated_addr, dmac=self.pg1.remote_hosts[3].mac
365 )
Neale Ranns80823802017-02-20 18:23:41 -0800366
Neale Ranns69b7aa42017-03-10 03:04:12 -0800367 #
368 # cleanup. The test infra's object registry will ensure
369 # the route is really gone and thus that the unresolve worked.
370 #
371 pre_res_route.remove_vpp_config()
372 self.vapi.ppcli("map params pre-resolve del ip6-nh 4001::1")
373
Ole Troaneb284a12019-10-09 13:33:19 +0200374 def test_map_e_inner_frag(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200375 """MAP-E Inner fragmentation"""
Ole Troaneb284a12019-10-09 13:33:19 +0200376
377 #
378 # Add a route to the MAP-BR
379 #
380 map_br_pfx = "2001::"
381 map_br_pfx_len = 32
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200382 map_route = VppIpRoute(
383 self,
384 map_br_pfx,
385 map_br_pfx_len,
386 [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index)],
387 )
Ole Troaneb284a12019-10-09 13:33:19 +0200388 map_route.add_vpp_config()
389
390 #
391 # Add a domain that maps from pg0 to pg1
392 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200393 map_dst = "2001::/32"
394 map_src = "3000::1/128"
395 client_pfx = "192.168.0.0/16"
396 map_translated_addr = "2001:0:101:7000:0:c0a8:101:7"
397 tag = "MAP-E tag."
398 self.vapi.map_add_domain(
399 ip4_prefix=client_pfx,
400 ip6_prefix=map_dst,
401 ip6_src=map_src,
402 ea_bits_len=20,
403 psid_offset=4,
404 psid_length=4,
405 mtu=1000,
406 tag=tag,
407 )
Ole Troaneb284a12019-10-09 13:33:19 +0200408
409 # Enable MAP on interface.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200410 self.vapi.map_if_enable_disable(
411 is_enable=1, sw_if_index=self.pg0.sw_if_index, is_translation=0
412 )
Ole Troaneb284a12019-10-09 13:33:19 +0200413
414 # Enable inner fragmentation
415 self.vapi.map_param_set_fragmentation(inner=1)
416
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200417 v4 = (
418 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
419 / IP(src=self.pg0.remote_ip4, dst="192.168.1.1")
420 / UDP(sport=20000, dport=10000)
421 / Raw(b"\xa5" * 1300)
422 )
Ole Troaneb284a12019-10-09 13:33:19 +0200423
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200424 self.pg_send(self.pg0, v4 * 1)
Ole Troaneb284a12019-10-09 13:33:19 +0200425 rx = self.pg1.get_capture(2)
426
Neale Ranns346c2472022-03-08 13:24:28 +0000427 # 1000-sizeof(ip6_header_t) = 960.
428 frags = fragment_rfc791(v4[1], 960)
Ole Troaneb284a12019-10-09 13:33:19 +0200429 frags[0].id = 0
430 frags[1].id = 0
431 frags[0].ttl -= 1
432 frags[1].ttl -= 1
433 frags[0].chksum = 0
434 frags[1].chksum = 0
435
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200436 v6_reply1 = IPv6(src="3000::1", dst=map_translated_addr, hlim=63) / frags[0]
437 v6_reply2 = IPv6(src="3000::1", dst=map_translated_addr, hlim=63) / frags[1]
Ole Troaneb284a12019-10-09 13:33:19 +0200438 rx[0][1].fl = 0
439 rx[1][1].fl = 0
440 rx[0][1][IP].id = 0
441 rx[1][1][IP].id = 0
442 rx[0][1][IP].chksum = 0
443 rx[1][1][IP].chksum = 0
444
445 self.validate(rx[0][1], v6_reply1)
446 self.validate(rx[1][1], v6_reply2)
447
Jon Loeligerb15ad952019-11-14 16:44:40 -0600448 def test_map_e_tcp_mss(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200449 """MAP-E TCP MSS"""
Jon Loeligerb15ad952019-11-14 16:44:40 -0600450
451 #
452 # Add a route to the MAP-BR
453 #
454 map_br_pfx = "2001::"
455 map_br_pfx_len = 32
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200456 map_route = VppIpRoute(
457 self,
458 map_br_pfx,
459 map_br_pfx_len,
460 [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index)],
461 )
Jon Loeligerb15ad952019-11-14 16:44:40 -0600462 map_route.add_vpp_config()
463
464 #
465 # Add a domain that maps from pg0 to pg1
466 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200467 map_dst = "2001::/32"
468 map_src = "3000::1/128"
469 client_pfx = "192.168.0.0/16"
470 map_translated_addr = "2001:0:101:5000:0:c0a8:101:5"
471 tag = "MAP-E TCP tag."
472 self.vapi.map_add_domain(
473 ip4_prefix=client_pfx,
474 ip6_prefix=map_dst,
475 ip6_src=map_src,
476 ea_bits_len=20,
477 psid_offset=4,
478 psid_length=4,
479 tag=tag,
480 )
Jon Loeligerb15ad952019-11-14 16:44:40 -0600481
482 # Enable MAP on pg0 interface.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200483 self.vapi.map_if_enable_disable(
484 is_enable=1, sw_if_index=self.pg0.sw_if_index, is_translation=0
485 )
Jon Loeligerb15ad952019-11-14 16:44:40 -0600486
487 # Enable MAP on pg1 interface.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200488 self.vapi.map_if_enable_disable(
489 is_enable=1, sw_if_index=self.pg1.sw_if_index, is_translation=0
490 )
Jon Loeligerb15ad952019-11-14 16:44:40 -0600491
492 # TCP MSS clamping
493 mss_clamp = 1300
494 self.vapi.map_param_set_tcp(mss_clamp)
495
496 #
497 # Send a v4 packet that will be encapped.
498 #
Steven Luonge4238aa2024-04-19 09:49:20 -0700499 p_ether = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200500 p_ip4 = IP(src=self.pg0.remote_ip4, dst="192.168.1.1")
501 p_tcp = TCP(sport=20000, dport=30000, flags="S", options=[("MSS", 1455)])
Jon Loeligerb15ad952019-11-14 16:44:40 -0600502 p4 = p_ether / p_ip4 / p_tcp
503
504 self.pg1.add_stream(p4)
505 self.pg_enable_capture(self.pg_interfaces)
506 self.pg_start()
507
508 rx = self.pg1.get_capture(1)
509 rx = rx[0]
510
511 self.assertTrue(rx.haslayer(IPv6))
512 self.assertEqual(rx[IP].src, p4[IP].src)
513 self.assertEqual(rx[IP].dst, p4[IP].dst)
514 self.assertEqual(rx[IPv6].src, "3000::1")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200515 self.assertEqual(rx[TCP].options, TCP(options=[("MSS", mss_clamp)]).options)
Jon Loeligerb15ad952019-11-14 16:44:40 -0600516
Ole Troan9be93c82018-09-28 14:28:00 +0200517 def validate(self, rx, expected):
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -0700518 self.assertEqual(rx, expected.__class__(scapy.compat.raw(expected)))
Ole Troan9be93c82018-09-28 14:28:00 +0200519
Vladimir Isaev92511312020-02-26 14:41:46 +0300520 def validate_frag6(self, p6_frag, p_ip6_expected):
Alexander Chernavin31b1a6c2020-01-17 08:31:04 -0500521 self.assertFalse(p6_frag.haslayer(IP))
522 self.assertTrue(p6_frag.haslayer(IPv6))
523 self.assertTrue(p6_frag.haslayer(IPv6ExtHdrFragment))
524 self.assertEqual(p6_frag[IPv6].src, p_ip6_expected.src)
525 self.assertEqual(p6_frag[IPv6].dst, p_ip6_expected.dst)
526
Vladimir Isaev92511312020-02-26 14:41:46 +0300527 def validate_frag_payload_len6(self, rx, proto, payload_len_expected):
Alexander Chernavin31b1a6c2020-01-17 08:31:04 -0500528 payload_total = 0
529 for p in rx:
530 payload_total += p[IPv6].plen
531
532 # First fragment has proto
533 payload_total -= len(proto())
534
535 # Every fragment has IPv6 fragment header
536 payload_total -= len(IPv6ExtHdrFragment()) * len(rx)
537
538 self.assertEqual(payload_total, payload_len_expected)
539
Vladimir Isaev92511312020-02-26 14:41:46 +0300540 def validate_frag4(self, p4_frag, p_ip4_expected):
541 self.assertFalse(p4_frag.haslayer(IPv6))
542 self.assertTrue(p4_frag.haslayer(IP))
543 self.assertTrue(p4_frag[IP].frag != 0 or p4_frag[IP].flags.MF)
544 self.assertEqual(p4_frag[IP].src, p_ip4_expected.src)
545 self.assertEqual(p4_frag[IP].dst, p_ip4_expected.dst)
546
547 def validate_frag_payload_len4(self, rx, proto, payload_len_expected):
548 payload_total = 0
549 for p in rx:
550 payload_total += len(p[IP].payload)
551
552 # First fragment has proto
553 payload_total -= len(proto())
554
555 self.assertEqual(payload_total, payload_len_expected)
556
Ole Troan9be93c82018-09-28 14:28:00 +0200557 def payload(self, len):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200558 return "x" * len
Ole Troan9be93c82018-09-28 14:28:00 +0200559
560 def test_map_t(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200561 """MAP-T"""
Ole Troan9be93c82018-09-28 14:28:00 +0200562
563 #
564 # Add a domain that maps from pg0 to pg1
565 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200566 map_dst = "2001:db8::/32"
567 map_src = "1234:5678:90ab:cdef::/64"
568 ip4_pfx = "192.168.0.0/24"
569 tag = "MAP-T Tag."
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600570
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200571 self.vapi.map_add_domain(
572 ip6_prefix=map_dst,
573 ip4_prefix=ip4_pfx,
574 ip6_src=map_src,
575 ea_bits_len=16,
576 psid_offset=6,
577 psid_length=4,
578 mtu=1500,
579 tag=tag,
580 )
Ole Troan9be93c82018-09-28 14:28:00 +0200581
582 # Enable MAP-T on interfaces.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200583 self.vapi.map_if_enable_disable(
584 is_enable=1, sw_if_index=self.pg0.sw_if_index, is_translation=1
585 )
586 self.vapi.map_if_enable_disable(
587 is_enable=1, sw_if_index=self.pg1.sw_if_index, is_translation=1
588 )
Ole Troan9be93c82018-09-28 14:28:00 +0200589
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600590 # Ensure MAP doesn't steal all packets!
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200591 v4 = (
592 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
593 / IP(src=self.pg0.remote_ip4, dst=self.pg0.remote_ip4)
594 / UDP(sport=20000, dport=10000)
595 / Raw(b"\xa5" * 100)
596 )
597 rx = self.send_and_expect(self.pg0, v4 * 1, self.pg0)
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600598 v4_reply = v4[1]
599 v4_reply.ttl -= 1
600 for p in rx:
601 self.validate(p[1], v4_reply)
602 # Ensure MAP doesn't steal all packets
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200603 v6 = (
604 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
605 / IPv6(src=self.pg1.remote_ip6, dst=self.pg1.remote_ip6)
606 / UDP(sport=20000, dport=10000)
607 / Raw(b"\xa5" * 100)
608 )
609 rx = self.send_and_expect(self.pg1, v6 * 1, self.pg1)
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600610 v6_reply = v6[1]
611 v6_reply.hlim -= 1
612 for p in rx:
613 self.validate(p[1], v6_reply)
Ole Troan9be93c82018-09-28 14:28:00 +0200614
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200615 map_route = VppIpRoute(
616 self,
617 "2001:db8::",
618 32,
619 [
620 VppRoutePath(
621 self.pg1.remote_ip6,
622 self.pg1.sw_if_index,
623 proto=DpoProto.DPO_PROTO_IP6,
624 )
625 ],
626 )
Ole Troan9be93c82018-09-28 14:28:00 +0200627 map_route.add_vpp_config()
628
629 #
630 # Send a v4 packet that will be translated
631 #
632 p_ether = Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200633 p_ip4 = IP(src=self.pg0.remote_ip4, dst="192.168.0.1")
634 payload = TCP(sport=0xABCD, dport=0xABCD)
Ole Troan9be93c82018-09-28 14:28:00 +0200635
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200636 p4 = p_ether / p_ip4 / payload
637 p6_translated = (
638 IPv6(src="1234:5678:90ab:cdef:ac:1001:200:0", dst="2001:db8:1f0::c0a8:1:f")
639 / payload
640 )
Ole Troan9be93c82018-09-28 14:28:00 +0200641 p6_translated.hlim -= 1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200642 rx = self.send_and_expect(self.pg0, p4 * 1, self.pg1)
Ole Troan9be93c82018-09-28 14:28:00 +0200643 for p in rx:
644 self.validate(p[1], p6_translated)
645
646 # Send back an IPv6 packet that will be "untranslated"
647 p_ether6 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200648 p_ip6 = IPv6(
649 src="2001:db8:1f0::c0a8:1:f", dst="1234:5678:90ab:cdef:ac:1001:200:0"
650 )
651 p6 = p_ether6 / p_ip6 / payload
652 p4_translated = IP(src="192.168.0.1", dst=self.pg0.remote_ip4) / payload
Ole Troan9be93c82018-09-28 14:28:00 +0200653 p4_translated.id = 0
654 p4_translated.ttl -= 1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200655 rx = self.send_and_expect(self.pg1, p6 * 1, self.pg0)
Ole Troan9be93c82018-09-28 14:28:00 +0200656 for p in rx:
657 self.validate(p[1], p4_translated)
658
Alexander Chernavin56817e22020-01-23 08:09:40 -0500659 # IPv4 TTL=0
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200660 ip4_ttl_expired = IP(src=self.pg0.remote_ip4, dst="192.168.0.1", ttl=0)
661 p4 = p_ether / ip4_ttl_expired / payload
Ole Troan9be93c82018-09-28 14:28:00 +0200662
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200663 icmp4_reply = (
Maxime Peim2cc14de2024-02-12 10:08:03 +0100664 IP(id=0, ttl=255, src=self.pg0.local_ip4, dst=self.pg0.remote_ip4)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200665 / ICMP(type="time-exceeded", code="ttl-zero-during-transit")
666 / IP(src=self.pg0.remote_ip4, dst="192.168.0.1", ttl=0)
667 / payload
668 )
669 rx = self.send_and_expect(self.pg0, p4 * 1, self.pg0)
Ole Troan9be93c82018-09-28 14:28:00 +0200670 for p in rx:
671 self.validate(p[1], icmp4_reply)
672
Alexander Chernavin56817e22020-01-23 08:09:40 -0500673 # IPv4 TTL=1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200674 ip4_ttl_expired = IP(src=self.pg0.remote_ip4, dst="192.168.0.1", ttl=1)
675 p4 = p_ether / ip4_ttl_expired / payload
Ole Troan9be93c82018-09-28 14:28:00 +0200676
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200677 icmp4_reply = (
Maxime Peim2cc14de2024-02-12 10:08:03 +0100678 IP(id=0, ttl=255, src=self.pg0.local_ip4, dst=self.pg0.remote_ip4)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200679 / ICMP(type="time-exceeded", code="ttl-zero-during-transit")
680 / IP(src=self.pg0.remote_ip4, dst="192.168.0.1", ttl=1)
681 / payload
682 )
683 rx = self.send_and_expect(self.pg0, p4 * 1, self.pg0)
Ole Troan9be93c82018-09-28 14:28:00 +0200684 for p in rx:
685 self.validate(p[1], icmp4_reply)
Ole Troan9be93c82018-09-28 14:28:00 +0200686
Vladimir Ratnikovb1bd8762020-03-18 08:20:08 -0400687 # IPv6 Hop limit at BR
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200688 ip6_hlim_expired = IPv6(
689 hlim=1,
690 src="2001:db8:1ab::c0a8:1:ab",
691 dst="1234:5678:90ab:cdef:ac:1001:200:0",
692 )
693 p6 = p_ether6 / ip6_hlim_expired / payload
Vladimir Ratnikovb1bd8762020-03-18 08:20:08 -0400694
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200695 icmp6_reply = (
696 IPv6(hlim=255, src=self.pg1.local_ip6, dst="2001:db8:1ab::c0a8:1:ab")
697 / ICMPv6TimeExceeded(code=0)
698 / IPv6(
699 src="2001:db8:1ab::c0a8:1:ab",
700 dst="1234:5678:90ab:cdef:ac:1001:200:0",
701 hlim=1,
702 )
703 / payload
704 )
705 rx = self.send_and_expect(self.pg1, p6 * 1, self.pg1)
Vladimir Ratnikovb1bd8762020-03-18 08:20:08 -0400706 for p in rx:
707 self.validate(p[1], icmp6_reply)
708
709 # IPv6 Hop limit beyond BR
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200710 ip6_hlim_expired = IPv6(
711 hlim=0,
712 src="2001:db8:1ab::c0a8:1:ab",
713 dst="1234:5678:90ab:cdef:ac:1001:200:0",
714 )
715 p6 = p_ether6 / ip6_hlim_expired / payload
Ole Troan9be93c82018-09-28 14:28:00 +0200716
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200717 icmp6_reply = (
718 IPv6(hlim=255, src=self.pg1.local_ip6, dst="2001:db8:1ab::c0a8:1:ab")
719 / ICMPv6TimeExceeded(code=0)
720 / IPv6(
721 src="2001:db8:1ab::c0a8:1:ab",
722 dst="1234:5678:90ab:cdef:ac:1001:200:0",
723 hlim=0,
724 )
725 / payload
726 )
727 rx = self.send_and_expect(self.pg1, p6 * 1, self.pg1)
Ole Troan9be93c82018-09-28 14:28:00 +0200728 for p in rx:
729 self.validate(p[1], icmp6_reply)
730
731 # IPv4 Well-known port
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200732 p_ip4 = IP(src=self.pg0.remote_ip4, dst="192.168.0.1")
Ole Troan9be93c82018-09-28 14:28:00 +0200733 payload = UDP(sport=200, dport=200)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200734 p4 = p_ether / p_ip4 / payload
735 self.send_and_assert_no_replies(self.pg0, p4 * 1)
Ole Troan9be93c82018-09-28 14:28:00 +0200736
737 # IPv6 Well-known port
738 payload = UDP(sport=200, dport=200)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200739 p6 = p_ether6 / p_ip6 / payload
740 self.send_and_assert_no_replies(self.pg1, p6 * 1)
Ole Troan9be93c82018-09-28 14:28:00 +0200741
Alexander Chernavin8af24b12020-01-31 09:19:49 -0500742 # UDP packet fragmentation
Alexander Chernavin31b1a6c2020-01-17 08:31:04 -0500743 payload_len = 1453
744 payload = UDP(sport=40000, dport=4000) / self.payload(payload_len)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200745 p4 = p_ether / p_ip4 / payload
Ole Troan9be93c82018-09-28 14:28:00 +0200746 self.pg_enable_capture()
747 self.pg0.add_stream(p4)
748 self.pg_start()
749 rx = self.pg1.get_capture(2)
Alexander Chernavin31b1a6c2020-01-17 08:31:04 -0500750
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200751 p_ip6_translated = IPv6(
752 src="1234:5678:90ab:cdef:ac:1001:200:0", dst="2001:db8:1e0::c0a8:1:e"
753 )
Ole Troan9be93c82018-09-28 14:28:00 +0200754 for p in rx:
Vladimir Isaev92511312020-02-26 14:41:46 +0300755 self.validate_frag6(p, p_ip6_translated)
Alexander Chernavin31b1a6c2020-01-17 08:31:04 -0500756
Vladimir Isaev92511312020-02-26 14:41:46 +0300757 self.validate_frag_payload_len6(rx, UDP, payload_len)
Ole Troan9be93c82018-09-28 14:28:00 +0200758
Alexander Chernavin8af24b12020-01-31 09:19:49 -0500759 # UDP packet fragmentation send fragments
Vladimir Isaev92511312020-02-26 14:41:46 +0300760 payload_len = 1453
Alexander Chernavin31b1a6c2020-01-17 08:31:04 -0500761 payload = UDP(sport=40000, dport=4000) / self.payload(payload_len)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200762 p4 = p_ether / p_ip4 / payload
Alexander Chernavin31b1a6c2020-01-17 08:31:04 -0500763 frags = fragment_rfc791(p4, fragsize=1000)
Ole Troan9be93c82018-09-28 14:28:00 +0200764 self.pg_enable_capture()
765 self.pg0.add_stream(frags)
766 self.pg_start()
767 rx = self.pg1.get_capture(2)
Alexander Chernavin31b1a6c2020-01-17 08:31:04 -0500768
Ole Troan9be93c82018-09-28 14:28:00 +0200769 for p in rx:
Vladimir Isaev92511312020-02-26 14:41:46 +0300770 self.validate_frag6(p, p_ip6_translated)
Alexander Chernavin31b1a6c2020-01-17 08:31:04 -0500771
Vladimir Isaev92511312020-02-26 14:41:46 +0300772 self.validate_frag_payload_len6(rx, UDP, payload_len)
773
774 # Send back an fragmented IPv6 UDP packet that will be "untranslated"
775 payload = UDP(sport=4000, dport=40000) / self.payload(payload_len)
776 p_ether6 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200777 p_ip6 = IPv6(
778 src="2001:db8:1e0::c0a8:1:e", dst="1234:5678:90ab:cdef:ac:1001:200:0"
779 )
780 p6 = p_ether6 / p_ip6 / payload
781 frags6 = fragment_rfc8200(p6, identification=0xDCBA, fragsize=1000)
Vladimir Isaev92511312020-02-26 14:41:46 +0300782
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200783 p_ip4_translated = IP(src="192.168.0.1", dst=self.pg0.remote_ip4)
784 p4_translated = p_ip4_translated / payload
Vladimir Isaev92511312020-02-26 14:41:46 +0300785 p4_translated.id = 0
786 p4_translated.ttl -= 1
787
788 self.pg_enable_capture()
789 self.pg1.add_stream(frags6)
790 self.pg_start()
791 rx = self.pg0.get_capture(2)
792
793 for p in rx:
794 self.validate_frag4(p, p4_translated)
795
796 self.validate_frag_payload_len4(rx, UDP, payload_len)
Klement Sekera640edcd2019-09-23 09:00:30 +0000797
Alexander Chernavin8af24b12020-01-31 09:19:49 -0500798 # ICMP packet fragmentation
799 payload = ICMP(id=6529) / self.payload(payload_len)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200800 p4 = p_ether / p_ip4 / payload
Alexander Chernavin8af24b12020-01-31 09:19:49 -0500801 self.pg_enable_capture()
802 self.pg0.add_stream(p4)
803 self.pg_start()
804 rx = self.pg1.get_capture(2)
805
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200806 p_ip6_translated = IPv6(
807 src="1234:5678:90ab:cdef:ac:1001:200:0", dst="2001:db8:160::c0a8:1:6"
808 )
Alexander Chernavin8af24b12020-01-31 09:19:49 -0500809 for p in rx:
Vladimir Isaev92511312020-02-26 14:41:46 +0300810 self.validate_frag6(p, p_ip6_translated)
Alexander Chernavin8af24b12020-01-31 09:19:49 -0500811
Vladimir Isaev92511312020-02-26 14:41:46 +0300812 self.validate_frag_payload_len6(rx, ICMPv6EchoRequest, payload_len)
Alexander Chernavin8af24b12020-01-31 09:19:49 -0500813
814 # ICMP packet fragmentation send fragments
815 payload = ICMP(id=6529) / self.payload(payload_len)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200816 p4 = p_ether / p_ip4 / payload
Alexander Chernavin8af24b12020-01-31 09:19:49 -0500817 frags = fragment_rfc791(p4, fragsize=1000)
818 self.pg_enable_capture()
819 self.pg0.add_stream(frags)
820 self.pg_start()
821 rx = self.pg1.get_capture(2)
822
823 for p in rx:
Vladimir Isaev92511312020-02-26 14:41:46 +0300824 self.validate_frag6(p, p_ip6_translated)
Alexander Chernavin8af24b12020-01-31 09:19:49 -0500825
Vladimir Isaev92511312020-02-26 14:41:46 +0300826 self.validate_frag_payload_len6(rx, ICMPv6EchoRequest, payload_len)
Ole Troan9be93c82018-09-28 14:28:00 +0200827
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600828 # TCP MSS clamping
829 self.vapi.map_param_set_tcp(1300)
830
831 #
832 # Send a v4 TCP SYN packet that will be translated and MSS clamped
833 #
834 p_ether = Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200835 p_ip4 = IP(src=self.pg0.remote_ip4, dst="192.168.0.1")
836 payload = TCP(sport=0xABCD, dport=0xABCD, flags="S", options=[("MSS", 1460)])
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600837
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200838 p4 = p_ether / p_ip4 / payload
839 p6_translated = (
840 IPv6(src="1234:5678:90ab:cdef:ac:1001:200:0", dst="2001:db8:1f0::c0a8:1:f")
841 / payload
842 )
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600843 p6_translated.hlim -= 1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200844 p6_translated[TCP].options = [("MSS", 1300)]
845 rx = self.send_and_expect(self.pg0, p4 * 1, self.pg1)
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600846 for p in rx:
847 self.validate(p[1], p6_translated)
848
849 # Send back an IPv6 packet that will be "untranslated"
850 p_ether6 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200851 p_ip6 = IPv6(
852 src="2001:db8:1f0::c0a8:1:f", dst="1234:5678:90ab:cdef:ac:1001:200:0"
853 )
854 p6 = p_ether6 / p_ip6 / payload
855 p4_translated = IP(src="192.168.0.1", dst=self.pg0.remote_ip4) / payload
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600856 p4_translated.id = 0
857 p4_translated.ttl -= 1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200858 p4_translated[TCP].options = [("MSS", 1300)]
859 rx = self.send_and_expect(self.pg1, p6 * 1, self.pg0)
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600860 for p in rx:
861 self.validate(p[1], p4_translated)
862
Alexander Chernavinb728a3c2020-02-05 09:05:06 -0500863 # TCP MSS clamping cleanup
864 self.vapi.map_param_set_tcp(0)
865
866 # Enable icmp6 param to get back ICMPv6 unreachable messages in case
867 # of security check fails
868 self.vapi.map_param_set_icmp6(enable_unreachable=1)
869
870 # Send back an IPv6 packet that will be droppped due to security
871 # check fail
872 p_ether6 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200873 p_ip6_sec_check_fail = IPv6(
874 src="2001:db8:1fe::c0a8:1:f", dst="1234:5678:90ab:cdef:ac:1001:200:0"
875 )
876 payload = TCP(sport=0xABCD, dport=0xABCD)
877 p6 = p_ether6 / p_ip6_sec_check_fail / payload
Alexander Chernavinb728a3c2020-02-05 09:05:06 -0500878
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200879 self.pg_send(self.pg1, p6 * 1)
Alexander Chernavinb728a3c2020-02-05 09:05:06 -0500880 self.pg0.get_capture(0, timeout=1)
881 rx = self.pg1.get_capture(1)
882
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200883 icmp6_reply = (
884 IPv6(hlim=255, src=self.pg1.local_ip6, dst="2001:db8:1fe::c0a8:1:f")
885 / ICMPv6DestUnreach(code=5)
886 / p_ip6_sec_check_fail
887 / payload
888 )
Alexander Chernavinb728a3c2020-02-05 09:05:06 -0500889
890 for p in rx:
891 self.validate(p[1], icmp6_reply)
892
893 # ICMPv6 unreachable messages cleanup
894 self.vapi.map_param_set_icmp6(enable_unreachable=0)
895
Matthew Smith9f356962019-12-04 15:02:46 -0600896 def test_map_t_ip6_psid(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200897 """MAP-T v6->v4 PSID validation"""
Matthew Smith9f356962019-12-04 15:02:46 -0600898
899 #
900 # Add a domain that maps from pg0 to pg1
901 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200902 map_dst = "2001:db8::/32"
903 map_src = "1234:5678:90ab:cdef::/64"
904 ip4_pfx = "192.168.0.0/24"
905 tag = "MAP-T Test Domain"
Matthew Smith9f356962019-12-04 15:02:46 -0600906
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200907 self.vapi.map_add_domain(
908 ip6_prefix=map_dst,
909 ip4_prefix=ip4_pfx,
910 ip6_src=map_src,
911 ea_bits_len=16,
912 psid_offset=6,
913 psid_length=4,
914 mtu=1500,
915 tag=tag,
916 )
Matthew Smith9f356962019-12-04 15:02:46 -0600917
918 # Enable MAP-T on interfaces.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200919 self.vapi.map_if_enable_disable(
920 is_enable=1, sw_if_index=self.pg0.sw_if_index, is_translation=1
921 )
922 self.vapi.map_if_enable_disable(
923 is_enable=1, sw_if_index=self.pg1.sw_if_index, is_translation=1
924 )
Matthew Smith9f356962019-12-04 15:02:46 -0600925
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200926 map_route = VppIpRoute(
927 self,
928 "2001:db8::",
929 32,
930 [
931 VppRoutePath(
932 self.pg1.remote_ip6,
933 self.pg1.sw_if_index,
934 proto=DpoProto.DPO_PROTO_IP6,
935 )
936 ],
937 )
Matthew Smith9f356962019-12-04 15:02:46 -0600938 map_route.add_vpp_config()
939
940 p_ether6 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200941 p_ip6 = IPv6(
942 src="2001:db8:1f0::c0a8:1:f", dst="1234:5678:90ab:cdef:ac:1001:200:0"
943 )
Matthew Smith9f356962019-12-04 15:02:46 -0600944
945 # Send good IPv6 source port, ensure translated IPv4 received
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200946 payload = TCP(sport=0xABCD, dport=80)
947 p6 = p_ether6 / p_ip6 / payload
948 p4_translated = IP(src="192.168.0.1", dst=self.pg0.remote_ip4) / payload
Matthew Smith9f356962019-12-04 15:02:46 -0600949 p4_translated.id = 0
950 p4_translated.ttl -= 1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200951 rx = self.send_and_expect(self.pg1, p6 * 1, self.pg0)
Matthew Smith9f356962019-12-04 15:02:46 -0600952 for p in rx:
953 self.validate(p[1], p4_translated)
954
955 # Send bad IPv6 source port, ensure translated IPv4 not received
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200956 payload = TCP(sport=0xDCBA, dport=80)
957 p6 = p_ether6 / p_ip6 / payload
958 self.send_and_assert_no_replies(self.pg1, p6 * 1)
Ole Troan9be93c82018-09-28 14:28:00 +0200959
Alexander Chernavinf145c152020-02-11 09:57:09 -0500960 def test_map_t_pre_resolve(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200961 """MAP-T pre-resolve"""
Alexander Chernavinf145c152020-02-11 09:57:09 -0500962
963 # Add a domain that maps from pg0 to pg1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200964 map_dst = "2001:db8::/32"
965 map_src = "1234:5678:90ab:cdef::/64"
966 ip4_pfx = "192.168.0.0/24"
967 tag = "MAP-T Test Domain."
Alexander Chernavinf145c152020-02-11 09:57:09 -0500968
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200969 self.vapi.map_add_domain(
970 ip6_prefix=map_dst,
971 ip4_prefix=ip4_pfx,
972 ip6_src=map_src,
973 ea_bits_len=16,
974 psid_offset=6,
975 psid_length=4,
976 mtu=1500,
977 tag=tag,
978 )
Alexander Chernavinf145c152020-02-11 09:57:09 -0500979
980 # Enable MAP-T on interfaces.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200981 self.vapi.map_if_enable_disable(
982 is_enable=1, sw_if_index=self.pg0.sw_if_index, is_translation=1
983 )
984 self.vapi.map_if_enable_disable(
985 is_enable=1, sw_if_index=self.pg1.sw_if_index, is_translation=1
986 )
Alexander Chernavinf145c152020-02-11 09:57:09 -0500987
988 # Enable pre-resolve option
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200989 self.vapi.map_param_add_del_pre_resolve(
990 ip4_nh_address="10.1.2.3", ip6_nh_address="4001::1", is_add=1
991 )
Alexander Chernavinf145c152020-02-11 09:57:09 -0500992
993 # Add a route to 4001::1 and expect the translated traffic to be
994 # sent via that route next-hop.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200995 pre_res_route6 = VppIpRoute(
996 self,
997 "4001::1",
998 128,
999 [VppRoutePath(self.pg1.remote_hosts[2].ip6, self.pg1.sw_if_index)],
1000 )
Alexander Chernavinf145c152020-02-11 09:57:09 -05001001 pre_res_route6.add_vpp_config()
1002
1003 # Add a route to 10.1.2.3 and expect the "untranslated" traffic to be
1004 # sent via that route next-hop.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001005 pre_res_route4 = VppIpRoute(
1006 self,
1007 "10.1.2.3",
1008 32,
1009 [VppRoutePath(self.pg0.remote_hosts[1].ip4, self.pg0.sw_if_index)],
1010 )
Alexander Chernavinf145c152020-02-11 09:57:09 -05001011 pre_res_route4.add_vpp_config()
1012
1013 # Send an IPv4 packet that will be translated
1014 p_ether = Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001015 p_ip4 = IP(src=self.pg0.remote_ip4, dst="192.168.0.1")
1016 payload = TCP(sport=0xABCD, dport=0xABCD)
1017 p4 = p_ether / p_ip4 / payload
Alexander Chernavinf145c152020-02-11 09:57:09 -05001018
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001019 p6_translated = (
1020 IPv6(src="1234:5678:90ab:cdef:ac:1001:200:0", dst="2001:db8:1f0::c0a8:1:f")
1021 / payload
1022 )
Alexander Chernavinf145c152020-02-11 09:57:09 -05001023 p6_translated.hlim -= 1
1024
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001025 rx = self.send_and_expect(self.pg0, p4 * 1, self.pg1)
Alexander Chernavinf145c152020-02-11 09:57:09 -05001026 for p in rx:
1027 self.assertEqual(p[Ether].dst, self.pg1.remote_hosts[2].mac)
1028 self.validate(p[1], p6_translated)
1029
1030 # Send back an IPv6 packet that will be "untranslated"
1031 p_ether6 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001032 p_ip6 = IPv6(
1033 src="2001:db8:1f0::c0a8:1:f", dst="1234:5678:90ab:cdef:ac:1001:200:0"
1034 )
1035 p6 = p_ether6 / p_ip6 / payload
Alexander Chernavinf145c152020-02-11 09:57:09 -05001036
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001037 p4_translated = IP(src="192.168.0.1", dst=self.pg0.remote_ip4) / payload
Alexander Chernavinf145c152020-02-11 09:57:09 -05001038 p4_translated.id = 0
1039 p4_translated.ttl -= 1
1040
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001041 rx = self.send_and_expect(self.pg1, p6 * 1, self.pg0)
Alexander Chernavinf145c152020-02-11 09:57:09 -05001042 for p in rx:
1043 self.assertEqual(p[Ether].dst, self.pg0.remote_hosts[1].mac)
1044 self.validate(p[1], p4_translated)
1045
1046 # Cleanup pre-resolve option
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001047 self.vapi.map_param_add_del_pre_resolve(
1048 ip4_nh_address="10.1.2.3", ip6_nh_address="4001::1", is_add=0
1049 )
Alexander Chernavinf145c152020-02-11 09:57:09 -05001050
Ole Troanf5db3712020-05-20 15:47:06 +02001051
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001052if __name__ == "__main__":
Neale Ranns80823802017-02-20 18:23:41 -08001053 unittest.main(testRunner=VppTestRunner)