blob: 16e9607cedcd6cfb65669ceae055b596ccac6a04 [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
6from framework import VppTestCase, VppTestRunner
Paul Vinciguerraa279d9c2019-02-28 09:00:09 -08007from vpp_ip import DpoProto
Neale Rannsc0a93142018-09-05 15:42:26 -07008from vpp_ip_route import VppIpRoute, VppRoutePath
Klement Sekera7b2e9fb2019-10-01 13:00:22 +00009from util import fragment_rfc791, fragment_rfc8200
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -070010
11import scapy.compat
snaramre5d4b8912019-12-13 23:39:35 +000012from scapy.layers.l2 import Ether
13from scapy.packet import Raw
Alexander Chernavin31b1a6c2020-01-17 08:31:04 -050014from scapy.layers.inet import IP, UDP, ICMP, TCP
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020015from scapy.layers.inet6 import (
16 IPv6,
17 ICMPv6TimeExceeded,
18 IPv6ExtHdrFragment,
19 ICMPv6EchoRequest,
20 ICMPv6DestUnreach,
21)
Neale Ranns80823802017-02-20 18:23:41 -080022
23
24class TestMAP(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020025 """MAP Test Case"""
Neale Ranns80823802017-02-20 18:23:41 -080026
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -070027 @classmethod
28 def setUpClass(cls):
29 super(TestMAP, cls).setUpClass()
30
31 @classmethod
32 def tearDownClass(cls):
33 super(TestMAP, cls).tearDownClass()
34
Neale Ranns80823802017-02-20 18:23:41 -080035 def setUp(self):
36 super(TestMAP, self).setUp()
37
38 # create 2 pg interfaces
39 self.create_pg_interfaces(range(4))
40
41 # pg0 is 'inside' IPv4
42 self.pg0.admin_up()
43 self.pg0.config_ip4()
44 self.pg0.resolve_arp()
Alexander Chernavinf145c152020-02-11 09:57:09 -050045 self.pg0.generate_remote_hosts(2)
46 self.pg0.configure_ipv4_neighbors()
Neale Ranns80823802017-02-20 18:23:41 -080047
48 # pg1 is 'outside' IPv6
49 self.pg1.admin_up()
50 self.pg1.config_ip6()
51 self.pg1.generate_remote_hosts(4)
52 self.pg1.configure_ipv6_neighbors()
53
54 def tearDown(self):
55 super(TestMAP, self).tearDown()
56 for i in self.pg_interfaces:
57 i.unconfig_ip4()
58 i.unconfig_ip6()
59 i.admin_down()
60
Klement Sekeraa025b3e2019-08-21 10:53:14 +000061 def send_and_assert_encapped(self, packets, ip6_src, ip6_dst, dmac=None):
Neale Ranns80823802017-02-20 18:23:41 -080062 if not dmac:
63 dmac = self.pg1.remote_mac
64
Klement Sekeraa025b3e2019-08-21 10:53:14 +000065 self.pg0.add_stream(packets)
Neale Ranns80823802017-02-20 18:23:41 -080066
67 self.pg_enable_capture(self.pg_interfaces)
68 self.pg_start()
69
Klement Sekeraa025b3e2019-08-21 10:53:14 +000070 capture = self.pg1.get_capture(len(packets))
71 for rx, tx in zip(capture, packets):
72 self.assertEqual(rx[Ether].dst, dmac)
73 self.assertEqual(rx[IP].src, tx[IP].src)
74 self.assertEqual(rx[IPv6].src, ip6_src)
75 self.assertEqual(rx[IPv6].dst, ip6_dst)
Neale Ranns80823802017-02-20 18:23:41 -080076
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020077 def send_and_assert_encapped_one(self, packet, ip6_src, ip6_dst, dmac=None):
Klement Sekeraa025b3e2019-08-21 10:53:14 +000078 return self.send_and_assert_encapped([packet], ip6_src, ip6_dst, dmac)
Neale Ranns80823802017-02-20 18:23:41 -080079
Paul Vinciguerra4d376f62019-05-24 06:36:26 -040080 def test_api_map_domain_dump(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020081 map_dst = "2001::/64"
82 map_src = "3000::1/128"
83 client_pfx = "192.168.0.0/16"
84 tag = "MAP-E tag."
85 index = self.vapi.map_add_domain(
86 ip4_prefix=client_pfx, ip6_prefix=map_dst, ip6_src=map_src, tag=tag
87 ).index
Paul Vinciguerra4d376f62019-05-24 06:36:26 -040088 rv = self.vapi.map_domain_dump()
89
90 # restore the state early so as to not impact subsequent tests.
91 # If an assert fails, we will not get the chance to do it at the end.
92 self.vapi.map_del_domain(index=index)
93
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020094 self.assertGreater(len(rv), 0, "Expected output from 'map_domain_dump'")
Paul Vinciguerra4d376f62019-05-24 06:36:26 -040095
96 # typedefs are returned as ipaddress objects.
97 # wrap results in str() ugh! to avoid the need to call unicode.
98 self.assertEqual(str(rv[0].ip4_prefix), client_pfx)
99 self.assertEqual(str(rv[0].ip6_prefix), map_dst)
100 self.assertEqual(str(rv[0].ip6_src), map_src)
101
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200102 self.assertEqual(rv[0].tag, tag, "output produced incorrect tag value.")
Paul Vinciguerra4d376f62019-05-24 06:36:26 -0400103
Ole Troanf5db3712020-05-20 15:47:06 +0200104 def create_domains(self, ip4_pfx_str, ip6_pfx_str, ip6_src_str):
105 ip4_pfx = ipaddress.ip_network(ip4_pfx_str)
106 ip6_dst = ipaddress.ip_network(ip6_pfx_str)
107 mod = ip4_pfx.num_addresses / 1024
108 indicies = []
109 for i in range(ip4_pfx.num_addresses):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200110 rv = self.vapi.map_add_domain(
111 ip6_prefix=ip6_pfx_str,
112 ip4_prefix=str(ip4_pfx[i]) + "/32",
113 ip6_src=ip6_src_str,
114 )
Ole Troanf5db3712020-05-20 15:47:06 +0200115 indicies.append(rv.index)
116 return indicies
117
118 def test_api_map_domains_get(self):
119 # Create a bunch of domains
Ole Troan4376ab22021-03-03 10:40:05 +0100120 no_domains = 4096 # This must be large enough to ensure VPP suspends
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200121 domains = self.create_domains("130.67.0.0/20", "2001::/32", "2001::1/128")
Ole Troan4376ab22021-03-03 10:40:05 +0100122 self.assertEqual(len(domains), no_domains)
Ole Troanf5db3712020-05-20 15:47:06 +0200123
124 d = []
125 cursor = 0
126
127 # Invalid cursor
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200128 rv, details = self.vapi.map_domains_get(cursor=no_domains + 10)
Ole Troanf5db3712020-05-20 15:47:06 +0200129 self.assertEqual(rv.retval, -7)
130
131 # Delete a domain in the middle of walk
132 rv, details = self.vapi.map_domains_get(cursor=0)
133 self.assertEqual(rv.retval, -165)
134 self.vapi.map_del_domain(index=rv.cursor)
135 domains.remove(rv.cursor)
136
137 # Continue at point of deleted cursor
138 rv, details = self.vapi.map_domains_get(cursor=rv.cursor)
Ole Troan9bf487f2021-03-30 00:51:41 +0200139 self.assertIn(rv.retval, [0, -165])
Ole Troanf5db3712020-05-20 15:47:06 +0200140
141 d = list(self.vapi.vpp.details_iter(self.vapi.map_domains_get))
Ole Troan4376ab22021-03-03 10:40:05 +0100142 self.assertEqual(len(d), no_domains - 1)
Ole Troanf5db3712020-05-20 15:47:06 +0200143
144 # Clean up
145 for i in domains:
146 self.vapi.map_del_domain(index=i)
147
Jon Loeligerb15ad952019-11-14 16:44:40 -0600148 def test_map_e_udp(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200149 """MAP-E UDP"""
Neale Ranns80823802017-02-20 18:23:41 -0800150
151 #
152 # Add a route to the MAP-BR
153 #
154 map_br_pfx = "2001::"
Klement Sekeraa025b3e2019-08-21 10:53:14 +0000155 map_br_pfx_len = 32
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200156 map_route = VppIpRoute(
157 self,
158 map_br_pfx,
159 map_br_pfx_len,
160 [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index)],
161 )
Neale Ranns80823802017-02-20 18:23:41 -0800162 map_route.add_vpp_config()
163
164 #
165 # Add a domain that maps from pg0 to pg1
166 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200167 map_dst = "2001::/32"
168 map_src = "3000::1/128"
169 client_pfx = "192.168.0.0/16"
170 map_translated_addr = "2001:0:101:7000:0:c0a8:101:7"
171 tag = "MAP-E tag."
172 self.vapi.map_add_domain(
173 ip4_prefix=client_pfx,
174 ip6_prefix=map_dst,
175 ip6_src=map_src,
176 ea_bits_len=20,
177 psid_offset=4,
178 psid_length=4,
179 tag=tag,
180 )
Neale Ranns80823802017-02-20 18:23:41 -0800181
Klement Sekeraa025b3e2019-08-21 10:53:14 +0000182 self.vapi.map_param_set_security_check(enable=1, fragments=1)
183
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600184 # Enable MAP on interface.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200185 self.vapi.map_if_enable_disable(
186 is_enable=1, sw_if_index=self.pg0.sw_if_index, is_translation=0
187 )
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600188
189 # Ensure MAP doesn't steal all packets!
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200190 v4 = (
191 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
192 / IP(src=self.pg0.remote_ip4, dst=self.pg0.remote_ip4)
193 / UDP(sport=20000, dport=10000)
194 / Raw(b"\xa5" * 100)
195 )
Ole Troaneb284a12019-10-09 13:33:19 +0200196 rx = self.send_and_expect(self.pg0, v4 * 4, self.pg0)
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600197 v4_reply = v4[1]
198 v4_reply.ttl -= 1
199 for p in rx:
200 self.validate(p[1], v4_reply)
201
Neale Ranns80823802017-02-20 18:23:41 -0800202 #
203 # Fire in a v4 packet that will be encapped to the BR
204 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200205 v4 = (
206 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
207 / IP(src=self.pg0.remote_ip4, dst="192.168.1.1")
208 / UDP(sport=20000, dport=10000)
209 / Raw(b"\xa5" * 100)
210 )
Neale Ranns80823802017-02-20 18:23:41 -0800211
Ole Troaneb284a12019-10-09 13:33:19 +0200212 self.send_and_assert_encapped(v4 * 4, "3000::1", map_translated_addr)
Klement Sekeraa025b3e2019-08-21 10:53:14 +0000213
Klement Sekeraa025b3e2019-08-21 10:53:14 +0000214 #
215 # Verify reordered fragments are able to pass as well
216 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200217 v4 = (
218 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
219 / IP(id=1, src=self.pg0.remote_ip4, dst="192.168.1.1")
220 / UDP(sport=20000, dport=10000)
221 / Raw(b"\xa5" * 1000)
222 )
Klement Sekeraa025b3e2019-08-21 10:53:14 +0000223
224 frags = fragment_rfc791(v4, 400)
225 frags.reverse()
226
227 self.send_and_assert_encapped(frags, "3000::1", map_translated_addr)
228
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600229 # Enable MAP on interface.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200230 self.vapi.map_if_enable_disable(
231 is_enable=1, sw_if_index=self.pg1.sw_if_index, is_translation=0
232 )
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600233
234 # Ensure MAP doesn't steal all packets
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200235 v6 = (
236 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
237 / IPv6(src=self.pg1.remote_ip6, dst=self.pg1.remote_ip6)
238 / UDP(sport=20000, dport=10000)
239 / Raw(b"\xa5" * 100)
240 )
241 rx = self.send_and_expect(self.pg1, v6 * 1, self.pg1)
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600242 v6_reply = v6[1]
243 v6_reply.hlim -= 1
244 for p in rx:
245 self.validate(p[1], v6_reply)
246
Neale Ranns80823802017-02-20 18:23:41 -0800247 #
248 # Fire in a V6 encapped packet.
Klement Sekeraa025b3e2019-08-21 10:53:14 +0000249 # expect a decapped packet on the inside ip4 link
Neale Ranns80823802017-02-20 18:23:41 -0800250 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200251 p = (
252 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
253 / IPv6(dst="3000::1", src=map_translated_addr)
254 / IP(dst=self.pg0.remote_ip4, src="192.168.1.1")
255 / UDP(sport=10000, dport=20000)
256 / Raw(b"\xa5" * 100)
257 )
Neale Ranns80823802017-02-20 18:23:41 -0800258
259 self.pg1.add_stream(p)
260
261 self.pg_enable_capture(self.pg_interfaces)
262 self.pg_start()
263
264 rx = self.pg0.get_capture(1)
265 rx = rx[0]
266
267 self.assertFalse(rx.haslayer(IPv6))
268 self.assertEqual(rx[IP].src, p[IP].src)
269 self.assertEqual(rx[IP].dst, p[IP].dst)
270
271 #
Klement Sekeraa025b3e2019-08-21 10:53:14 +0000272 # Verify encapped reordered fragments pass as well
273 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200274 p = (
275 IP(id=1, dst=self.pg0.remote_ip4, src="192.168.1.1")
276 / UDP(sport=10000, dport=20000)
277 / Raw(b"\xa5" * 1500)
278 )
Klement Sekeraa025b3e2019-08-21 10:53:14 +0000279 frags = fragment_rfc791(p, 400)
280 frags.reverse()
281
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200282 stream = (
283 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
284 / IPv6(dst="3000::1", src=map_translated_addr)
285 / x
286 for x in frags
287 )
Klement Sekeraa025b3e2019-08-21 10:53:14 +0000288
289 self.pg1.add_stream(stream)
290
291 self.pg_enable_capture(self.pg_interfaces)
292 self.pg_start()
293
294 rx = self.pg0.get_capture(len(frags))
295
296 for r in rx:
297 self.assertFalse(r.haslayer(IPv6))
298 self.assertEqual(r[IP].src, p[IP].src)
299 self.assertEqual(r[IP].dst, p[IP].dst)
300
Klement Sekera7b2e9fb2019-10-01 13:00:22 +0000301 # Verify that fragments pass even if ipv6 layer is fragmented
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200302 stream = (IPv6(dst="3000::1", src=map_translated_addr) / x for x in frags)
Klement Sekera7b2e9fb2019-10-01 13:00:22 +0000303
304 v6_stream = [
305 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / x
306 for i in range(len(frags))
307 for x in fragment_rfc8200(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200308 IPv6(dst="3000::1", src=map_translated_addr) / frags[i], i, 200
309 )
310 ]
Klement Sekera7b2e9fb2019-10-01 13:00:22 +0000311
312 self.pg1.add_stream(v6_stream)
313
314 self.pg_enable_capture(self.pg_interfaces)
315 self.pg_start()
316
317 rx = self.pg0.get_capture(len(frags))
318
319 for r in rx:
320 self.assertFalse(r.haslayer(IPv6))
321 self.assertEqual(r[IP].src, p[IP].src)
322 self.assertEqual(r[IP].dst, p[IP].dst)
323
Klement Sekeraa025b3e2019-08-21 10:53:14 +0000324 #
Neale Ranns80823802017-02-20 18:23:41 -0800325 # Pre-resolve. No API for this!!
326 #
327 self.vapi.ppcli("map params pre-resolve ip6-nh 4001::1")
328
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200329 self.send_and_assert_no_replies(self.pg0, v4, "resolved via default route")
Neale Ranns80823802017-02-20 18:23:41 -0800330
331 #
332 # Add a route to 4001::1. Expect the encapped traffic to be
333 # sent via that routes next-hop
334 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200335 pre_res_route = VppIpRoute(
336 self,
337 "4001::1",
338 128,
339 [VppRoutePath(self.pg1.remote_hosts[2].ip6, self.pg1.sw_if_index)],
340 )
Neale Ranns80823802017-02-20 18:23:41 -0800341 pre_res_route.add_vpp_config()
342
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200343 self.send_and_assert_encapped_one(
344 v4, "3000::1", map_translated_addr, dmac=self.pg1.remote_hosts[2].mac
345 )
Neale Ranns80823802017-02-20 18:23:41 -0800346
347 #
348 # change the route to the pre-solved next-hop
349 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200350 pre_res_route.modify(
351 [VppRoutePath(self.pg1.remote_hosts[3].ip6, self.pg1.sw_if_index)]
352 )
Neale Ranns69b7aa42017-03-10 03:04:12 -0800353 pre_res_route.add_vpp_config()
Neale Ranns80823802017-02-20 18:23:41 -0800354
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200355 self.send_and_assert_encapped_one(
356 v4, "3000::1", map_translated_addr, dmac=self.pg1.remote_hosts[3].mac
357 )
Neale Ranns80823802017-02-20 18:23:41 -0800358
Neale Ranns69b7aa42017-03-10 03:04:12 -0800359 #
360 # cleanup. The test infra's object registry will ensure
361 # the route is really gone and thus that the unresolve worked.
362 #
363 pre_res_route.remove_vpp_config()
364 self.vapi.ppcli("map params pre-resolve del ip6-nh 4001::1")
365
Ole Troaneb284a12019-10-09 13:33:19 +0200366 def test_map_e_inner_frag(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200367 """MAP-E Inner fragmentation"""
Ole Troaneb284a12019-10-09 13:33:19 +0200368
369 #
370 # Add a route to the MAP-BR
371 #
372 map_br_pfx = "2001::"
373 map_br_pfx_len = 32
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200374 map_route = VppIpRoute(
375 self,
376 map_br_pfx,
377 map_br_pfx_len,
378 [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index)],
379 )
Ole Troaneb284a12019-10-09 13:33:19 +0200380 map_route.add_vpp_config()
381
382 #
383 # Add a domain that maps from pg0 to pg1
384 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200385 map_dst = "2001::/32"
386 map_src = "3000::1/128"
387 client_pfx = "192.168.0.0/16"
388 map_translated_addr = "2001:0:101:7000:0:c0a8:101:7"
389 tag = "MAP-E tag."
390 self.vapi.map_add_domain(
391 ip4_prefix=client_pfx,
392 ip6_prefix=map_dst,
393 ip6_src=map_src,
394 ea_bits_len=20,
395 psid_offset=4,
396 psid_length=4,
397 mtu=1000,
398 tag=tag,
399 )
Ole Troaneb284a12019-10-09 13:33:19 +0200400
401 # Enable MAP on interface.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200402 self.vapi.map_if_enable_disable(
403 is_enable=1, sw_if_index=self.pg0.sw_if_index, is_translation=0
404 )
Ole Troaneb284a12019-10-09 13:33:19 +0200405
406 # Enable inner fragmentation
407 self.vapi.map_param_set_fragmentation(inner=1)
408
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200409 v4 = (
410 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
411 / IP(src=self.pg0.remote_ip4, dst="192.168.1.1")
412 / UDP(sport=20000, dport=10000)
413 / Raw(b"\xa5" * 1300)
414 )
Ole Troaneb284a12019-10-09 13:33:19 +0200415
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200416 self.pg_send(self.pg0, v4 * 1)
Ole Troaneb284a12019-10-09 13:33:19 +0200417 rx = self.pg1.get_capture(2)
418
Neale Ranns346c2472022-03-08 13:24:28 +0000419 # 1000-sizeof(ip6_header_t) = 960.
420 frags = fragment_rfc791(v4[1], 960)
Ole Troaneb284a12019-10-09 13:33:19 +0200421 frags[0].id = 0
422 frags[1].id = 0
423 frags[0].ttl -= 1
424 frags[1].ttl -= 1
425 frags[0].chksum = 0
426 frags[1].chksum = 0
427
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200428 v6_reply1 = IPv6(src="3000::1", dst=map_translated_addr, hlim=63) / frags[0]
429 v6_reply2 = IPv6(src="3000::1", dst=map_translated_addr, hlim=63) / frags[1]
Ole Troaneb284a12019-10-09 13:33:19 +0200430 rx[0][1].fl = 0
431 rx[1][1].fl = 0
432 rx[0][1][IP].id = 0
433 rx[1][1][IP].id = 0
434 rx[0][1][IP].chksum = 0
435 rx[1][1][IP].chksum = 0
436
437 self.validate(rx[0][1], v6_reply1)
438 self.validate(rx[1][1], v6_reply2)
439
Jon Loeligerb15ad952019-11-14 16:44:40 -0600440 def test_map_e_tcp_mss(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200441 """MAP-E TCP MSS"""
Jon Loeligerb15ad952019-11-14 16:44:40 -0600442
443 #
444 # Add a route to the MAP-BR
445 #
446 map_br_pfx = "2001::"
447 map_br_pfx_len = 32
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200448 map_route = VppIpRoute(
449 self,
450 map_br_pfx,
451 map_br_pfx_len,
452 [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index)],
453 )
Jon Loeligerb15ad952019-11-14 16:44:40 -0600454 map_route.add_vpp_config()
455
456 #
457 # Add a domain that maps from pg0 to pg1
458 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200459 map_dst = "2001::/32"
460 map_src = "3000::1/128"
461 client_pfx = "192.168.0.0/16"
462 map_translated_addr = "2001:0:101:5000:0:c0a8:101:5"
463 tag = "MAP-E TCP tag."
464 self.vapi.map_add_domain(
465 ip4_prefix=client_pfx,
466 ip6_prefix=map_dst,
467 ip6_src=map_src,
468 ea_bits_len=20,
469 psid_offset=4,
470 psid_length=4,
471 tag=tag,
472 )
Jon Loeligerb15ad952019-11-14 16:44:40 -0600473
474 # Enable MAP on pg0 interface.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200475 self.vapi.map_if_enable_disable(
476 is_enable=1, sw_if_index=self.pg0.sw_if_index, is_translation=0
477 )
Jon Loeligerb15ad952019-11-14 16:44:40 -0600478
479 # Enable MAP on pg1 interface.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200480 self.vapi.map_if_enable_disable(
481 is_enable=1, sw_if_index=self.pg1.sw_if_index, is_translation=0
482 )
Jon Loeligerb15ad952019-11-14 16:44:40 -0600483
484 # TCP MSS clamping
485 mss_clamp = 1300
486 self.vapi.map_param_set_tcp(mss_clamp)
487
488 #
489 # Send a v4 packet that will be encapped.
490 #
491 p_ether = Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200492 p_ip4 = IP(src=self.pg0.remote_ip4, dst="192.168.1.1")
493 p_tcp = TCP(sport=20000, dport=30000, flags="S", options=[("MSS", 1455)])
Jon Loeligerb15ad952019-11-14 16:44:40 -0600494 p4 = p_ether / p_ip4 / p_tcp
495
496 self.pg1.add_stream(p4)
497 self.pg_enable_capture(self.pg_interfaces)
498 self.pg_start()
499
500 rx = self.pg1.get_capture(1)
501 rx = rx[0]
502
503 self.assertTrue(rx.haslayer(IPv6))
504 self.assertEqual(rx[IP].src, p4[IP].src)
505 self.assertEqual(rx[IP].dst, p4[IP].dst)
506 self.assertEqual(rx[IPv6].src, "3000::1")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200507 self.assertEqual(rx[TCP].options, TCP(options=[("MSS", mss_clamp)]).options)
Jon Loeligerb15ad952019-11-14 16:44:40 -0600508
Ole Troan9be93c82018-09-28 14:28:00 +0200509 def validate(self, rx, expected):
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -0700510 self.assertEqual(rx, expected.__class__(scapy.compat.raw(expected)))
Ole Troan9be93c82018-09-28 14:28:00 +0200511
Vladimir Isaev92511312020-02-26 14:41:46 +0300512 def validate_frag6(self, p6_frag, p_ip6_expected):
Alexander Chernavin31b1a6c2020-01-17 08:31:04 -0500513 self.assertFalse(p6_frag.haslayer(IP))
514 self.assertTrue(p6_frag.haslayer(IPv6))
515 self.assertTrue(p6_frag.haslayer(IPv6ExtHdrFragment))
516 self.assertEqual(p6_frag[IPv6].src, p_ip6_expected.src)
517 self.assertEqual(p6_frag[IPv6].dst, p_ip6_expected.dst)
518
Vladimir Isaev92511312020-02-26 14:41:46 +0300519 def validate_frag_payload_len6(self, rx, proto, payload_len_expected):
Alexander Chernavin31b1a6c2020-01-17 08:31:04 -0500520 payload_total = 0
521 for p in rx:
522 payload_total += p[IPv6].plen
523
524 # First fragment has proto
525 payload_total -= len(proto())
526
527 # Every fragment has IPv6 fragment header
528 payload_total -= len(IPv6ExtHdrFragment()) * len(rx)
529
530 self.assertEqual(payload_total, payload_len_expected)
531
Vladimir Isaev92511312020-02-26 14:41:46 +0300532 def validate_frag4(self, p4_frag, p_ip4_expected):
533 self.assertFalse(p4_frag.haslayer(IPv6))
534 self.assertTrue(p4_frag.haslayer(IP))
535 self.assertTrue(p4_frag[IP].frag != 0 or p4_frag[IP].flags.MF)
536 self.assertEqual(p4_frag[IP].src, p_ip4_expected.src)
537 self.assertEqual(p4_frag[IP].dst, p_ip4_expected.dst)
538
539 def validate_frag_payload_len4(self, rx, proto, payload_len_expected):
540 payload_total = 0
541 for p in rx:
542 payload_total += len(p[IP].payload)
543
544 # First fragment has proto
545 payload_total -= len(proto())
546
547 self.assertEqual(payload_total, payload_len_expected)
548
Ole Troan9be93c82018-09-28 14:28:00 +0200549 def payload(self, len):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200550 return "x" * len
Ole Troan9be93c82018-09-28 14:28:00 +0200551
552 def test_map_t(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200553 """MAP-T"""
Ole Troan9be93c82018-09-28 14:28:00 +0200554
555 #
556 # Add a domain that maps from pg0 to pg1
557 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200558 map_dst = "2001:db8::/32"
559 map_src = "1234:5678:90ab:cdef::/64"
560 ip4_pfx = "192.168.0.0/24"
561 tag = "MAP-T Tag."
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600562
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200563 self.vapi.map_add_domain(
564 ip6_prefix=map_dst,
565 ip4_prefix=ip4_pfx,
566 ip6_src=map_src,
567 ea_bits_len=16,
568 psid_offset=6,
569 psid_length=4,
570 mtu=1500,
571 tag=tag,
572 )
Ole Troan9be93c82018-09-28 14:28:00 +0200573
574 # Enable MAP-T on interfaces.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200575 self.vapi.map_if_enable_disable(
576 is_enable=1, sw_if_index=self.pg0.sw_if_index, is_translation=1
577 )
578 self.vapi.map_if_enable_disable(
579 is_enable=1, sw_if_index=self.pg1.sw_if_index, is_translation=1
580 )
Ole Troan9be93c82018-09-28 14:28:00 +0200581
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600582 # Ensure MAP doesn't steal all packets!
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200583 v4 = (
584 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
585 / IP(src=self.pg0.remote_ip4, dst=self.pg0.remote_ip4)
586 / UDP(sport=20000, dport=10000)
587 / Raw(b"\xa5" * 100)
588 )
589 rx = self.send_and_expect(self.pg0, v4 * 1, self.pg0)
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600590 v4_reply = v4[1]
591 v4_reply.ttl -= 1
592 for p in rx:
593 self.validate(p[1], v4_reply)
594 # Ensure MAP doesn't steal all packets
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200595 v6 = (
596 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
597 / IPv6(src=self.pg1.remote_ip6, dst=self.pg1.remote_ip6)
598 / UDP(sport=20000, dport=10000)
599 / Raw(b"\xa5" * 100)
600 )
601 rx = self.send_and_expect(self.pg1, v6 * 1, self.pg1)
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600602 v6_reply = v6[1]
603 v6_reply.hlim -= 1
604 for p in rx:
605 self.validate(p[1], v6_reply)
Ole Troan9be93c82018-09-28 14:28:00 +0200606
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200607 map_route = VppIpRoute(
608 self,
609 "2001:db8::",
610 32,
611 [
612 VppRoutePath(
613 self.pg1.remote_ip6,
614 self.pg1.sw_if_index,
615 proto=DpoProto.DPO_PROTO_IP6,
616 )
617 ],
618 )
Ole Troan9be93c82018-09-28 14:28:00 +0200619 map_route.add_vpp_config()
620
621 #
622 # Send a v4 packet that will be translated
623 #
624 p_ether = Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200625 p_ip4 = IP(src=self.pg0.remote_ip4, dst="192.168.0.1")
626 payload = TCP(sport=0xABCD, dport=0xABCD)
Ole Troan9be93c82018-09-28 14:28:00 +0200627
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200628 p4 = p_ether / p_ip4 / payload
629 p6_translated = (
630 IPv6(src="1234:5678:90ab:cdef:ac:1001:200:0", dst="2001:db8:1f0::c0a8:1:f")
631 / payload
632 )
Ole Troan9be93c82018-09-28 14:28:00 +0200633 p6_translated.hlim -= 1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200634 rx = self.send_and_expect(self.pg0, p4 * 1, self.pg1)
Ole Troan9be93c82018-09-28 14:28:00 +0200635 for p in rx:
636 self.validate(p[1], p6_translated)
637
638 # Send back an IPv6 packet that will be "untranslated"
639 p_ether6 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200640 p_ip6 = IPv6(
641 src="2001:db8:1f0::c0a8:1:f", dst="1234:5678:90ab:cdef:ac:1001:200:0"
642 )
643 p6 = p_ether6 / p_ip6 / payload
644 p4_translated = IP(src="192.168.0.1", dst=self.pg0.remote_ip4) / payload
Ole Troan9be93c82018-09-28 14:28:00 +0200645 p4_translated.id = 0
646 p4_translated.ttl -= 1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200647 rx = self.send_and_expect(self.pg1, p6 * 1, self.pg0)
Ole Troan9be93c82018-09-28 14:28:00 +0200648 for p in rx:
649 self.validate(p[1], p4_translated)
650
Alexander Chernavin56817e22020-01-23 08:09:40 -0500651 # IPv4 TTL=0
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200652 ip4_ttl_expired = IP(src=self.pg0.remote_ip4, dst="192.168.0.1", ttl=0)
653 p4 = p_ether / ip4_ttl_expired / payload
Ole Troan9be93c82018-09-28 14:28:00 +0200654
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200655 icmp4_reply = (
656 IP(id=0, ttl=254, src=self.pg0.local_ip4, dst=self.pg0.remote_ip4)
657 / ICMP(type="time-exceeded", code="ttl-zero-during-transit")
658 / IP(src=self.pg0.remote_ip4, dst="192.168.0.1", ttl=0)
659 / payload
660 )
661 rx = self.send_and_expect(self.pg0, p4 * 1, self.pg0)
Ole Troan9be93c82018-09-28 14:28:00 +0200662 for p in rx:
663 self.validate(p[1], icmp4_reply)
664
Alexander Chernavin56817e22020-01-23 08:09:40 -0500665 # IPv4 TTL=1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200666 ip4_ttl_expired = IP(src=self.pg0.remote_ip4, dst="192.168.0.1", ttl=1)
667 p4 = p_ether / ip4_ttl_expired / payload
Ole Troan9be93c82018-09-28 14:28:00 +0200668
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200669 icmp4_reply = (
670 IP(id=0, ttl=254, src=self.pg0.local_ip4, dst=self.pg0.remote_ip4)
671 / ICMP(type="time-exceeded", code="ttl-zero-during-transit")
672 / IP(src=self.pg0.remote_ip4, dst="192.168.0.1", ttl=1)
673 / payload
674 )
675 rx = self.send_and_expect(self.pg0, p4 * 1, self.pg0)
Ole Troan9be93c82018-09-28 14:28:00 +0200676 for p in rx:
677 self.validate(p[1], icmp4_reply)
Ole Troan9be93c82018-09-28 14:28:00 +0200678
Vladimir Ratnikovb1bd8762020-03-18 08:20:08 -0400679 # IPv6 Hop limit at BR
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200680 ip6_hlim_expired = IPv6(
681 hlim=1,
682 src="2001:db8:1ab::c0a8:1:ab",
683 dst="1234:5678:90ab:cdef:ac:1001:200:0",
684 )
685 p6 = p_ether6 / ip6_hlim_expired / payload
Vladimir Ratnikovb1bd8762020-03-18 08:20:08 -0400686
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200687 icmp6_reply = (
688 IPv6(hlim=255, src=self.pg1.local_ip6, dst="2001:db8:1ab::c0a8:1:ab")
689 / ICMPv6TimeExceeded(code=0)
690 / IPv6(
691 src="2001:db8:1ab::c0a8:1:ab",
692 dst="1234:5678:90ab:cdef:ac:1001:200:0",
693 hlim=1,
694 )
695 / payload
696 )
697 rx = self.send_and_expect(self.pg1, p6 * 1, self.pg1)
Vladimir Ratnikovb1bd8762020-03-18 08:20:08 -0400698 for p in rx:
699 self.validate(p[1], icmp6_reply)
700
701 # IPv6 Hop limit beyond BR
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200702 ip6_hlim_expired = IPv6(
703 hlim=0,
704 src="2001:db8:1ab::c0a8:1:ab",
705 dst="1234:5678:90ab:cdef:ac:1001:200:0",
706 )
707 p6 = p_ether6 / ip6_hlim_expired / payload
Ole Troan9be93c82018-09-28 14:28:00 +0200708
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200709 icmp6_reply = (
710 IPv6(hlim=255, src=self.pg1.local_ip6, dst="2001:db8:1ab::c0a8:1:ab")
711 / ICMPv6TimeExceeded(code=0)
712 / IPv6(
713 src="2001:db8:1ab::c0a8:1:ab",
714 dst="1234:5678:90ab:cdef:ac:1001:200:0",
715 hlim=0,
716 )
717 / payload
718 )
719 rx = self.send_and_expect(self.pg1, p6 * 1, self.pg1)
Ole Troan9be93c82018-09-28 14:28:00 +0200720 for p in rx:
721 self.validate(p[1], icmp6_reply)
722
723 # IPv4 Well-known port
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200724 p_ip4 = IP(src=self.pg0.remote_ip4, dst="192.168.0.1")
Ole Troan9be93c82018-09-28 14:28:00 +0200725 payload = UDP(sport=200, dport=200)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200726 p4 = p_ether / p_ip4 / payload
727 self.send_and_assert_no_replies(self.pg0, p4 * 1)
Ole Troan9be93c82018-09-28 14:28:00 +0200728
729 # IPv6 Well-known port
730 payload = UDP(sport=200, dport=200)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200731 p6 = p_ether6 / p_ip6 / payload
732 self.send_and_assert_no_replies(self.pg1, p6 * 1)
Ole Troan9be93c82018-09-28 14:28:00 +0200733
Alexander Chernavin8af24b12020-01-31 09:19:49 -0500734 # UDP packet fragmentation
Alexander Chernavin31b1a6c2020-01-17 08:31:04 -0500735 payload_len = 1453
736 payload = UDP(sport=40000, dport=4000) / self.payload(payload_len)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200737 p4 = p_ether / p_ip4 / payload
Ole Troan9be93c82018-09-28 14:28:00 +0200738 self.pg_enable_capture()
739 self.pg0.add_stream(p4)
740 self.pg_start()
741 rx = self.pg1.get_capture(2)
Alexander Chernavin31b1a6c2020-01-17 08:31:04 -0500742
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200743 p_ip6_translated = IPv6(
744 src="1234:5678:90ab:cdef:ac:1001:200:0", dst="2001:db8:1e0::c0a8:1:e"
745 )
Ole Troan9be93c82018-09-28 14:28:00 +0200746 for p in rx:
Vladimir Isaev92511312020-02-26 14:41:46 +0300747 self.validate_frag6(p, p_ip6_translated)
Alexander Chernavin31b1a6c2020-01-17 08:31:04 -0500748
Vladimir Isaev92511312020-02-26 14:41:46 +0300749 self.validate_frag_payload_len6(rx, UDP, payload_len)
Ole Troan9be93c82018-09-28 14:28:00 +0200750
Alexander Chernavin8af24b12020-01-31 09:19:49 -0500751 # UDP packet fragmentation send fragments
Vladimir Isaev92511312020-02-26 14:41:46 +0300752 payload_len = 1453
Alexander Chernavin31b1a6c2020-01-17 08:31:04 -0500753 payload = UDP(sport=40000, dport=4000) / self.payload(payload_len)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200754 p4 = p_ether / p_ip4 / payload
Alexander Chernavin31b1a6c2020-01-17 08:31:04 -0500755 frags = fragment_rfc791(p4, fragsize=1000)
Ole Troan9be93c82018-09-28 14:28:00 +0200756 self.pg_enable_capture()
757 self.pg0.add_stream(frags)
758 self.pg_start()
759 rx = self.pg1.get_capture(2)
Alexander Chernavin31b1a6c2020-01-17 08:31:04 -0500760
Ole Troan9be93c82018-09-28 14:28:00 +0200761 for p in rx:
Vladimir Isaev92511312020-02-26 14:41:46 +0300762 self.validate_frag6(p, p_ip6_translated)
Alexander Chernavin31b1a6c2020-01-17 08:31:04 -0500763
Vladimir Isaev92511312020-02-26 14:41:46 +0300764 self.validate_frag_payload_len6(rx, UDP, payload_len)
765
766 # Send back an fragmented IPv6 UDP packet that will be "untranslated"
767 payload = UDP(sport=4000, dport=40000) / self.payload(payload_len)
768 p_ether6 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200769 p_ip6 = IPv6(
770 src="2001:db8:1e0::c0a8:1:e", dst="1234:5678:90ab:cdef:ac:1001:200:0"
771 )
772 p6 = p_ether6 / p_ip6 / payload
773 frags6 = fragment_rfc8200(p6, identification=0xDCBA, fragsize=1000)
Vladimir Isaev92511312020-02-26 14:41:46 +0300774
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200775 p_ip4_translated = IP(src="192.168.0.1", dst=self.pg0.remote_ip4)
776 p4_translated = p_ip4_translated / payload
Vladimir Isaev92511312020-02-26 14:41:46 +0300777 p4_translated.id = 0
778 p4_translated.ttl -= 1
779
780 self.pg_enable_capture()
781 self.pg1.add_stream(frags6)
782 self.pg_start()
783 rx = self.pg0.get_capture(2)
784
785 for p in rx:
786 self.validate_frag4(p, p4_translated)
787
788 self.validate_frag_payload_len4(rx, UDP, payload_len)
Klement Sekera640edcd2019-09-23 09:00:30 +0000789
Alexander Chernavin8af24b12020-01-31 09:19:49 -0500790 # ICMP packet fragmentation
791 payload = ICMP(id=6529) / self.payload(payload_len)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200792 p4 = p_ether / p_ip4 / payload
Alexander Chernavin8af24b12020-01-31 09:19:49 -0500793 self.pg_enable_capture()
794 self.pg0.add_stream(p4)
795 self.pg_start()
796 rx = self.pg1.get_capture(2)
797
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200798 p_ip6_translated = IPv6(
799 src="1234:5678:90ab:cdef:ac:1001:200:0", dst="2001:db8:160::c0a8:1:6"
800 )
Alexander Chernavin8af24b12020-01-31 09:19:49 -0500801 for p in rx:
Vladimir Isaev92511312020-02-26 14:41:46 +0300802 self.validate_frag6(p, p_ip6_translated)
Alexander Chernavin8af24b12020-01-31 09:19:49 -0500803
Vladimir Isaev92511312020-02-26 14:41:46 +0300804 self.validate_frag_payload_len6(rx, ICMPv6EchoRequest, payload_len)
Alexander Chernavin8af24b12020-01-31 09:19:49 -0500805
806 # ICMP packet fragmentation send fragments
807 payload = ICMP(id=6529) / self.payload(payload_len)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200808 p4 = p_ether / p_ip4 / payload
Alexander Chernavin8af24b12020-01-31 09:19:49 -0500809 frags = fragment_rfc791(p4, fragsize=1000)
810 self.pg_enable_capture()
811 self.pg0.add_stream(frags)
812 self.pg_start()
813 rx = self.pg1.get_capture(2)
814
815 for p in rx:
Vladimir Isaev92511312020-02-26 14:41:46 +0300816 self.validate_frag6(p, p_ip6_translated)
Alexander Chernavin8af24b12020-01-31 09:19:49 -0500817
Vladimir Isaev92511312020-02-26 14:41:46 +0300818 self.validate_frag_payload_len6(rx, ICMPv6EchoRequest, payload_len)
Ole Troan9be93c82018-09-28 14:28:00 +0200819
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600820 # TCP MSS clamping
821 self.vapi.map_param_set_tcp(1300)
822
823 #
824 # Send a v4 TCP SYN packet that will be translated and MSS clamped
825 #
826 p_ether = Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200827 p_ip4 = IP(src=self.pg0.remote_ip4, dst="192.168.0.1")
828 payload = TCP(sport=0xABCD, dport=0xABCD, flags="S", options=[("MSS", 1460)])
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600829
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200830 p4 = p_ether / p_ip4 / payload
831 p6_translated = (
832 IPv6(src="1234:5678:90ab:cdef:ac:1001:200:0", dst="2001:db8:1f0::c0a8:1:f")
833 / payload
834 )
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600835 p6_translated.hlim -= 1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200836 p6_translated[TCP].options = [("MSS", 1300)]
837 rx = self.send_and_expect(self.pg0, p4 * 1, self.pg1)
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600838 for p in rx:
839 self.validate(p[1], p6_translated)
840
841 # Send back an IPv6 packet that will be "untranslated"
842 p_ether6 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200843 p_ip6 = IPv6(
844 src="2001:db8:1f0::c0a8:1:f", dst="1234:5678:90ab:cdef:ac:1001:200:0"
845 )
846 p6 = p_ether6 / p_ip6 / payload
847 p4_translated = IP(src="192.168.0.1", dst=self.pg0.remote_ip4) / payload
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600848 p4_translated.id = 0
849 p4_translated.ttl -= 1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200850 p4_translated[TCP].options = [("MSS", 1300)]
851 rx = self.send_and_expect(self.pg1, p6 * 1, self.pg0)
Jon Loeligerfc7344f2018-12-20 11:47:30 -0600852 for p in rx:
853 self.validate(p[1], p4_translated)
854
Alexander Chernavinb728a3c2020-02-05 09:05:06 -0500855 # TCP MSS clamping cleanup
856 self.vapi.map_param_set_tcp(0)
857
858 # Enable icmp6 param to get back ICMPv6 unreachable messages in case
859 # of security check fails
860 self.vapi.map_param_set_icmp6(enable_unreachable=1)
861
862 # Send back an IPv6 packet that will be droppped due to security
863 # check fail
864 p_ether6 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200865 p_ip6_sec_check_fail = IPv6(
866 src="2001:db8:1fe::c0a8:1:f", dst="1234:5678:90ab:cdef:ac:1001:200:0"
867 )
868 payload = TCP(sport=0xABCD, dport=0xABCD)
869 p6 = p_ether6 / p_ip6_sec_check_fail / payload
Alexander Chernavinb728a3c2020-02-05 09:05:06 -0500870
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200871 self.pg_send(self.pg1, p6 * 1)
Alexander Chernavinb728a3c2020-02-05 09:05:06 -0500872 self.pg0.get_capture(0, timeout=1)
873 rx = self.pg1.get_capture(1)
874
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200875 icmp6_reply = (
876 IPv6(hlim=255, src=self.pg1.local_ip6, dst="2001:db8:1fe::c0a8:1:f")
877 / ICMPv6DestUnreach(code=5)
878 / p_ip6_sec_check_fail
879 / payload
880 )
Alexander Chernavinb728a3c2020-02-05 09:05:06 -0500881
882 for p in rx:
883 self.validate(p[1], icmp6_reply)
884
885 # ICMPv6 unreachable messages cleanup
886 self.vapi.map_param_set_icmp6(enable_unreachable=0)
887
Matthew Smith9f356962019-12-04 15:02:46 -0600888 def test_map_t_ip6_psid(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200889 """MAP-T v6->v4 PSID validation"""
Matthew Smith9f356962019-12-04 15:02:46 -0600890
891 #
892 # Add a domain that maps from pg0 to pg1
893 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200894 map_dst = "2001:db8::/32"
895 map_src = "1234:5678:90ab:cdef::/64"
896 ip4_pfx = "192.168.0.0/24"
897 tag = "MAP-T Test Domain"
Matthew Smith9f356962019-12-04 15:02:46 -0600898
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200899 self.vapi.map_add_domain(
900 ip6_prefix=map_dst,
901 ip4_prefix=ip4_pfx,
902 ip6_src=map_src,
903 ea_bits_len=16,
904 psid_offset=6,
905 psid_length=4,
906 mtu=1500,
907 tag=tag,
908 )
Matthew Smith9f356962019-12-04 15:02:46 -0600909
910 # Enable MAP-T on interfaces.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200911 self.vapi.map_if_enable_disable(
912 is_enable=1, sw_if_index=self.pg0.sw_if_index, is_translation=1
913 )
914 self.vapi.map_if_enable_disable(
915 is_enable=1, sw_if_index=self.pg1.sw_if_index, is_translation=1
916 )
Matthew Smith9f356962019-12-04 15:02:46 -0600917
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200918 map_route = VppIpRoute(
919 self,
920 "2001:db8::",
921 32,
922 [
923 VppRoutePath(
924 self.pg1.remote_ip6,
925 self.pg1.sw_if_index,
926 proto=DpoProto.DPO_PROTO_IP6,
927 )
928 ],
929 )
Matthew Smith9f356962019-12-04 15:02:46 -0600930 map_route.add_vpp_config()
931
932 p_ether6 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200933 p_ip6 = IPv6(
934 src="2001:db8:1f0::c0a8:1:f", dst="1234:5678:90ab:cdef:ac:1001:200:0"
935 )
Matthew Smith9f356962019-12-04 15:02:46 -0600936
937 # Send good IPv6 source port, ensure translated IPv4 received
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200938 payload = TCP(sport=0xABCD, dport=80)
939 p6 = p_ether6 / p_ip6 / payload
940 p4_translated = IP(src="192.168.0.1", dst=self.pg0.remote_ip4) / payload
Matthew Smith9f356962019-12-04 15:02:46 -0600941 p4_translated.id = 0
942 p4_translated.ttl -= 1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200943 rx = self.send_and_expect(self.pg1, p6 * 1, self.pg0)
Matthew Smith9f356962019-12-04 15:02:46 -0600944 for p in rx:
945 self.validate(p[1], p4_translated)
946
947 # Send bad IPv6 source port, ensure translated IPv4 not received
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200948 payload = TCP(sport=0xDCBA, dport=80)
949 p6 = p_ether6 / p_ip6 / payload
950 self.send_and_assert_no_replies(self.pg1, p6 * 1)
Ole Troan9be93c82018-09-28 14:28:00 +0200951
Alexander Chernavinf145c152020-02-11 09:57:09 -0500952 def test_map_t_pre_resolve(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200953 """MAP-T pre-resolve"""
Alexander Chernavinf145c152020-02-11 09:57:09 -0500954
955 # Add a domain that maps from pg0 to pg1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200956 map_dst = "2001:db8::/32"
957 map_src = "1234:5678:90ab:cdef::/64"
958 ip4_pfx = "192.168.0.0/24"
959 tag = "MAP-T Test Domain."
Alexander Chernavinf145c152020-02-11 09:57:09 -0500960
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200961 self.vapi.map_add_domain(
962 ip6_prefix=map_dst,
963 ip4_prefix=ip4_pfx,
964 ip6_src=map_src,
965 ea_bits_len=16,
966 psid_offset=6,
967 psid_length=4,
968 mtu=1500,
969 tag=tag,
970 )
Alexander Chernavinf145c152020-02-11 09:57:09 -0500971
972 # Enable MAP-T on interfaces.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200973 self.vapi.map_if_enable_disable(
974 is_enable=1, sw_if_index=self.pg0.sw_if_index, is_translation=1
975 )
976 self.vapi.map_if_enable_disable(
977 is_enable=1, sw_if_index=self.pg1.sw_if_index, is_translation=1
978 )
Alexander Chernavinf145c152020-02-11 09:57:09 -0500979
980 # Enable pre-resolve option
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200981 self.vapi.map_param_add_del_pre_resolve(
982 ip4_nh_address="10.1.2.3", ip6_nh_address="4001::1", is_add=1
983 )
Alexander Chernavinf145c152020-02-11 09:57:09 -0500984
985 # Add a route to 4001::1 and expect the translated traffic to be
986 # sent via that route next-hop.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200987 pre_res_route6 = VppIpRoute(
988 self,
989 "4001::1",
990 128,
991 [VppRoutePath(self.pg1.remote_hosts[2].ip6, self.pg1.sw_if_index)],
992 )
Alexander Chernavinf145c152020-02-11 09:57:09 -0500993 pre_res_route6.add_vpp_config()
994
995 # Add a route to 10.1.2.3 and expect the "untranslated" traffic to be
996 # sent via that route next-hop.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200997 pre_res_route4 = VppIpRoute(
998 self,
999 "10.1.2.3",
1000 32,
1001 [VppRoutePath(self.pg0.remote_hosts[1].ip4, self.pg0.sw_if_index)],
1002 )
Alexander Chernavinf145c152020-02-11 09:57:09 -05001003 pre_res_route4.add_vpp_config()
1004
1005 # Send an IPv4 packet that will be translated
1006 p_ether = Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001007 p_ip4 = IP(src=self.pg0.remote_ip4, dst="192.168.0.1")
1008 payload = TCP(sport=0xABCD, dport=0xABCD)
1009 p4 = p_ether / p_ip4 / payload
Alexander Chernavinf145c152020-02-11 09:57:09 -05001010
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001011 p6_translated = (
1012 IPv6(src="1234:5678:90ab:cdef:ac:1001:200:0", dst="2001:db8:1f0::c0a8:1:f")
1013 / payload
1014 )
Alexander Chernavinf145c152020-02-11 09:57:09 -05001015 p6_translated.hlim -= 1
1016
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001017 rx = self.send_and_expect(self.pg0, p4 * 1, self.pg1)
Alexander Chernavinf145c152020-02-11 09:57:09 -05001018 for p in rx:
1019 self.assertEqual(p[Ether].dst, self.pg1.remote_hosts[2].mac)
1020 self.validate(p[1], p6_translated)
1021
1022 # Send back an IPv6 packet that will be "untranslated"
1023 p_ether6 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001024 p_ip6 = IPv6(
1025 src="2001:db8:1f0::c0a8:1:f", dst="1234:5678:90ab:cdef:ac:1001:200:0"
1026 )
1027 p6 = p_ether6 / p_ip6 / payload
Alexander Chernavinf145c152020-02-11 09:57:09 -05001028
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001029 p4_translated = IP(src="192.168.0.1", dst=self.pg0.remote_ip4) / payload
Alexander Chernavinf145c152020-02-11 09:57:09 -05001030 p4_translated.id = 0
1031 p4_translated.ttl -= 1
1032
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001033 rx = self.send_and_expect(self.pg1, p6 * 1, self.pg0)
Alexander Chernavinf145c152020-02-11 09:57:09 -05001034 for p in rx:
1035 self.assertEqual(p[Ether].dst, self.pg0.remote_hosts[1].mac)
1036 self.validate(p[1], p4_translated)
1037
1038 # Cleanup pre-resolve option
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001039 self.vapi.map_param_add_del_pre_resolve(
1040 ip4_nh_address="10.1.2.3", ip6_nh_address="4001::1", is_add=0
1041 )
Alexander Chernavinf145c152020-02-11 09:57:09 -05001042
Ole Troanf5db3712020-05-20 15:47:06 +02001043
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001044if __name__ == "__main__":
Neale Ranns80823802017-02-20 18:23:41 -08001045 unittest.main(testRunner=VppTestRunner)