blob: cb4166ab5dbfcb50f6bbb91ab70c429e01046d77 [file] [log] [blame]
Renato Botelho do Coutoead1e532019-10-31 13:31:07 -05001#!/usr/bin/env python3
Ole Troan46c1c112018-03-14 20:39:40 +01002"""IP{4,6} over IP{v,6} tunnel functional tests"""
Ole Troan298c6952018-03-08 12:30:43 +01003
4import unittest
Neale Ranns0b6a8572019-10-30 17:34:14 +00005from scapy.layers.inet6 import IPv6, Ether, IP, UDP, IPv6ExtHdrFragment, Raw
Ole Troan282093f2018-09-19 12:38:51 +02006from scapy.all import fragment, fragment6, RandShort, defragment6
Ole Troan46c1c112018-03-14 20:39:40 +01007from framework import VppTestCase, VppTestRunner
Neale Rannsc0a93142018-09-05 15:42:26 -07008from vpp_ip import DpoProto
Neale Ranns097fa662018-05-01 05:17:55 -07009from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpTable, FibPathProto
Neale Ranns95346962019-11-25 13:04:44 +000010from vpp_ipip_tun_interface import VppIpIpTunInterface
11from vpp_papi import VppEnum
Ole Troan46c1c112018-03-14 20:39:40 +010012from socket import AF_INET, AF_INET6, inet_pton
Ole Troan7f991832018-12-06 17:35:12 +010013from util import reassemble4
14
Ole Troan298c6952018-03-08 12:30:43 +010015""" Testipip is a subclass of VPPTestCase classes.
16
17IPIP tests.
18
19"""
20
21
Neale Ranns95346962019-11-25 13:04:44 +000022def ipip_add_tunnel(test, src, dst, table_id=0, dscp=0x0,
23 flags=0):
Neale Rannscbd08242019-05-26 11:34:27 -070024 """ Add a IPIP tunnel """
25 return test.vapi.ipip_add_tunnel(
26 tunnel={
27 'src': src,
28 'dst': dst,
29 'table_id': table_id,
30 'instance': 0xffffffff,
Neale Ranns95346962019-11-25 13:04:44 +000031 'dscp': dscp,
32 'flags': flags
Neale Rannscbd08242019-05-26 11:34:27 -070033 }
34 )
35
Neale Ranns95346962019-11-25 13:04:44 +000036# the number of packets to send when injecting traffic.
37# a multiple of 8 minus one, so we test all by 8/4/2/1 loops
38N_PACKETS = 64 - 1
39
Neale Rannscbd08242019-05-26 11:34:27 -070040
Ole Troan298c6952018-03-08 12:30:43 +010041class TestIPIP(VppTestCase):
42 """ IPIP Test Case """
43
44 @classmethod
45 def setUpClass(cls):
46 super(TestIPIP, cls).setUpClass()
Ole Troan46c1c112018-03-14 20:39:40 +010047 cls.create_pg_interfaces(range(2))
48 cls.interfaces = list(cls.pg_interfaces)
Ole Troan298c6952018-03-08 12:30:43 +010049
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -070050 @classmethod
51 def tearDownClass(cls):
52 super(TestIPIP, cls).tearDownClass()
53
Paul Vinciguerra741865b2018-11-27 06:01:22 -080054 def setUp(self):
55 super(TestIPIP, self).setUp()
56 for i in self.interfaces:
Ole Troan46c1c112018-03-14 20:39:40 +010057 i.admin_up()
58 i.config_ip4()
59 i.config_ip6()
60 i.disable_ipv6_ra()
61 i.resolve_arp()
62 i.resolve_ndp()
Ole Troan298c6952018-03-08 12:30:43 +010063
64 def tearDown(self):
65 super(TestIPIP, self).tearDown()
66 if not self.vpp_dead:
Ole Troan46c1c112018-03-14 20:39:40 +010067 for i in self.pg_interfaces:
68 i.unconfig_ip4()
69 i.unconfig_ip6()
70 i.admin_down()
Ole Troan298c6952018-03-08 12:30:43 +010071
72 def validate(self, rx, expected):
Ole Troan7f991832018-12-06 17:35:12 +010073 self.assertEqual(rx, expected.__class__(expected))
Ole Troan298c6952018-03-08 12:30:43 +010074
Ole Troan282093f2018-09-19 12:38:51 +020075 def generate_ip4_frags(self, payload_length, fragment_size):
Ole Troan7eb9d962018-08-10 14:39:48 +020076 p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
77 p_payload = UDP(sport=1234, dport=1234) / self.payload(payload_length)
78 p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
79 outer_ip4 = (p_ether / IP(src=self.pg1.remote_ip4,
80 id=RandShort(),
81 dst=self.pg0.local_ip4) / p_ip4 / p_payload)
82 frags = fragment(outer_ip4, fragment_size)
83 p4_reply = (p_ip4 / p_payload)
84 p4_reply.ttl -= 1
85 return frags, p4_reply
86
Neale Ranns95346962019-11-25 13:04:44 +000087 def verify_ip4ip4_encaps(self, a, p_ip4s, p_ip4_encaps):
88 for i, p_ip4 in enumerate(p_ip4s):
89 p_ip4.dst = a
90 p4 = (self.p_ether / p_ip4 / self.p_payload)
91 p_ip4_inner = p_ip4
92 p_ip4_inner.ttl -= 1
93 p4_reply = (p_ip4_encaps[i] / p_ip4_inner / self.p_payload)
94 p4_reply.ttl -= 1
95 p4_reply.id = 0
96 rx = self.send_and_expect(self.pg0, p4 * N_PACKETS, self.pg1)
97 for p in rx:
98 self.validate(p[1], p4_reply)
99 self.assert_packet_checksums_valid(p)
100
101 def verify_ip6ip4_encaps(self, a, p_ip6s, p_ip4_encaps):
102 for i, p_ip6 in enumerate(p_ip6s):
103 p_ip6.dst = a
104 p6 = (self.p_ether / p_ip6 / self.p_payload)
105 p_inner_ip6 = p_ip6
106 p_inner_ip6.hlim -= 1
107 p6_reply = (p_ip4_encaps[i] / p_inner_ip6 / self.p_payload)
108 p6_reply.ttl -= 1
109 rx = self.send_and_expect(self.pg0, p6 * N_PACKETS, self.pg1)
110 for p in rx:
111 self.validate(p[1], p6_reply)
112 self.assert_packet_checksums_valid(p)
113
Ole Troan298c6952018-03-08 12:30:43 +0100114 def test_ipip4(self):
115 """ ip{v4,v6} over ip4 test """
Ole Troan298c6952018-03-08 12:30:43 +0100116
Neale Ranns95346962019-11-25 13:04:44 +0000117 self.pg1.generate_remote_hosts(5)
118 self.pg1.configure_ipv4_neighbors()
119 e = VppEnum.vl_api_ipip_tunnel_flags_t
120 d = VppEnum.vl_api_ip_dscp_t
121 self.p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
122 self.p_payload = UDP(sport=1234, dport=1234) / Raw(b'X' * 100)
Ole Troan298c6952018-03-08 12:30:43 +0100123
Neale Ranns95346962019-11-25 13:04:44 +0000124 # create a TOS byte by shifting a DSCP code point 2 bits. those 2 bits
125 # are for the ECN.
126 dscp = d.IP_API_DSCP_AF31 << 2
127 ecn = 3
128 dscp_ecn = d.IP_API_DSCP_AF31 << 2 | ecn
Ole Troan298c6952018-03-08 12:30:43 +0100129
Neale Ranns95346962019-11-25 13:04:44 +0000130 # IPv4 transport that copies the DCSP from the payload
131 tun_dscp = VppIpIpTunInterface(
132 self,
133 self.pg0,
134 self.pg0.local_ip4,
135 self.pg1.remote_hosts[0].ip4,
136 flags=e.IPIP_TUNNEL_API_FLAG_ENCAP_COPY_DSCP).add_vpp_config()
137 # IPv4 transport that copies the DCSP and ECN from the payload
138 tun_dscp_ecn = VppIpIpTunInterface(
139 self,
140 self.pg0,
141 self.pg0.local_ip4,
142 self.pg1.remote_hosts[1].ip4,
143 flags=(e.IPIP_TUNNEL_API_FLAG_ENCAP_COPY_DSCP |
144 e.IPIP_TUNNEL_API_FLAG_ENCAP_COPY_ECN)).add_vpp_config()
145 # IPv4 transport that copies the ECN from the payload and sets the
146 # DF bit on encap. copies the ECN on decap
147 tun_ecn = VppIpIpTunInterface(
148 self,
149 self.pg0,
150 self.pg0.local_ip4,
151 self.pg1.remote_hosts[2].ip4,
152 flags=(e.IPIP_TUNNEL_API_FLAG_ENCAP_COPY_ECN |
153 e.IPIP_TUNNEL_API_FLAG_ENCAP_SET_DF |
154 e.IPIP_TUNNEL_API_FLAG_DECAP_COPY_ECN)).add_vpp_config()
155 # IPv4 transport that sets a fixed DSCP in the encap and copies
156 # the DF bit
157 tun = VppIpIpTunInterface(
158 self,
159 self.pg0,
160 self.pg0.local_ip4,
161 self.pg1.remote_hosts[3].ip4,
162 dscp=d.IP_API_DSCP_AF11,
163 flags=e.IPIP_TUNNEL_API_FLAG_ENCAP_COPY_DF).add_vpp_config()
Ole Troan298c6952018-03-08 12:30:43 +0100164
Neale Ranns95346962019-11-25 13:04:44 +0000165 # array of all the tunnels
166 tuns = [tun_dscp, tun_dscp_ecn, tun_ecn, tun]
Ole Troan298c6952018-03-08 12:30:43 +0100167
Neale Ranns95346962019-11-25 13:04:44 +0000168 # addresses for prefixes routed via each tunnel
169 a4s = ["" for i in range(len(tuns))]
170 a6s = ["" for i in range(len(tuns))]
171
172 # IP headers with each combination of DSCp/ECN tested
173 p_ip6s = [IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=dscp),
174 IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=dscp_ecn),
175 IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=ecn),
176 IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=0xff)]
177 p_ip4s = [IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp, flags='DF'),
178 IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp_ecn),
179 IP(src="1.2.3.4", dst="130.67.0.1", tos=ecn),
180 IP(src="1.2.3.4", dst="130.67.0.1", tos=0xff)]
181
182 # Configure each tunnel
183 for i, t in enumerate(tuns):
184 # Set interface up and enable IP on it
185 self.vapi.sw_interface_set_flags(t.sw_if_index, 1)
186 self.vapi.sw_interface_set_unnumbered(
187 sw_if_index=self.pg0.sw_if_index,
188 unnumbered_sw_if_index=t.sw_if_index)
189
190 # prefix for route / destination address for packets
191 a4s[i] = "130.67.%d.0" % i
192 a6s[i] = "dead:%d::" % i
193
194 # Add IPv4 and IPv6 routes via tunnel interface
195 ip4_via_tunnel = VppIpRoute(
196 self, a4s[i], 24,
197 [VppRoutePath("0.0.0.0",
198 t.sw_if_index,
199 proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)])
200 ip4_via_tunnel.add_vpp_config()
201
202 ip6_via_tunnel = VppIpRoute(
203 self, a6s[i], 64,
204 [VppRoutePath("::",
205 t.sw_if_index,
206 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
207 ip6_via_tunnel.add_vpp_config()
208
209 #
210 # Encapsulation
211 #
212
213 # tun_dscp copies only the dscp
214 # expected TC values are thus only the DCSP value is present from the
215 # inner
216 exp_tcs = [dscp, dscp, 0, 0xfc]
217 p_ip44_encaps = [IP(src=self.pg0.local_ip4,
218 dst=tun_dscp.dst,
219 tos=tc) for tc in exp_tcs]
220 p_ip64_encaps = [IP(src=self.pg0.local_ip4,
221 dst=tun_dscp.dst,
222 proto='ipv6', id=0, tos=tc) for tc in exp_tcs]
Ole Troan298c6952018-03-08 12:30:43 +0100223
224 # IPv4 in to IPv4 tunnel
Neale Ranns95346962019-11-25 13:04:44 +0000225 self.verify_ip4ip4_encaps(a4s[0], p_ip4s, p_ip44_encaps)
226 # IPv6 in to IPv4 tunnel
227 self.verify_ip6ip4_encaps(a6s[0], p_ip6s, p_ip64_encaps)
Ole Troan298c6952018-03-08 12:30:43 +0100228
Neale Ranns95346962019-11-25 13:04:44 +0000229 # tun_dscp_ecn copies the dscp and the ecn
230 exp_tcs = [dscp, dscp_ecn, ecn, 0xff]
231 p_ip44_encaps = [IP(src=self.pg0.local_ip4,
232 dst=tun_dscp_ecn.dst,
233 tos=tc) for tc in exp_tcs]
234 p_ip64_encaps = [IP(src=self.pg0.local_ip4,
235 dst=tun_dscp_ecn.dst,
236 proto='ipv6', id=0, tos=tc) for tc in exp_tcs]
237
238 self.verify_ip4ip4_encaps(a4s[1], p_ip4s, p_ip44_encaps)
239 self.verify_ip6ip4_encaps(a6s[1], p_ip6s, p_ip64_encaps)
240
241 # tun_ecn copies only the ecn and always sets DF
242 exp_tcs = [0, ecn, ecn, ecn]
243 p_ip44_encaps = [IP(src=self.pg0.local_ip4,
244 dst=tun_ecn.dst,
245 flags='DF', tos=tc) for tc in exp_tcs]
246 p_ip64_encaps = [IP(src=self.pg0.local_ip4,
247 dst=tun_ecn.dst,
248 flags='DF', proto='ipv6', id=0, tos=tc)
249 for tc in exp_tcs]
250
251 self.verify_ip4ip4_encaps(a4s[2], p_ip4s, p_ip44_encaps)
252 self.verify_ip6ip4_encaps(a6s[2], p_ip6s, p_ip64_encaps)
253
254 # tun sets a fixed dscp and copies DF
255 fixed_dscp = tun.dscp << 2
256 flags = ['DF', 0, 0, 0]
257 p_ip44_encaps = [IP(src=self.pg0.local_ip4,
258 dst=tun.dst,
259 flags=f,
260 tos=fixed_dscp) for f in flags]
261 p_ip64_encaps = [IP(src=self.pg0.local_ip4,
262 dst=tun.dst,
263 proto='ipv6', id=0,
264 tos=fixed_dscp) for i in range(len(p_ip4s))]
265
266 self.verify_ip4ip4_encaps(a4s[3], p_ip4s, p_ip44_encaps)
267 self.verify_ip6ip4_encaps(a6s[3], p_ip6s, p_ip64_encaps)
268
269 #
Ole Troan298c6952018-03-08 12:30:43 +0100270 # Decapsulation
Neale Ranns95346962019-11-25 13:04:44 +0000271 #
272 n_packets_decapped = 0
273 self.p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
Ole Troan298c6952018-03-08 12:30:43 +0100274
275 # IPv4 tunnel to IPv4
Neale Ranns95346962019-11-25 13:04:44 +0000276 tcs = [0, dscp, dscp_ecn, ecn]
277
278 # one overlay packet and all combinations of its encap
Ole Troan298c6952018-03-08 12:30:43 +0100279 p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
Neale Ranns95346962019-11-25 13:04:44 +0000280 p_ip4_encaps = [IP(src=tun.dst,
281 dst=self.pg0.local_ip4,
282 tos=tc) for tc in tcs]
283
284 # for each encap tun will produce the same inner packet because it does
285 # not copy up fields from the payload
286 for p_ip4_encap in p_ip4_encaps:
287 p4 = (self.p_ether / p_ip4_encap / p_ip4 / self.p_payload)
288 p4_reply = (p_ip4 / self.p_payload)
289 p4_reply.ttl -= 1
290 rx = self.send_and_expect(self.pg1, p4 * N_PACKETS, self.pg0)
291 n_packets_decapped += N_PACKETS
292 for p in rx:
293 self.validate(p[1], p4_reply)
294 self.assert_packet_checksums_valid(p)
Ole Troan298c6952018-03-08 12:30:43 +0100295
Ole Troan233e4682019-05-16 15:01:34 +0200296 err = self.statistics.get_err_counter(
Ole Troan58492a82018-09-04 13:19:12 +0200297 '/err/ipip4-input/packets decapsulated')
Neale Ranns95346962019-11-25 13:04:44 +0000298 self.assertEqual(err, n_packets_decapped)
299
300 # tun_ecn copies the ECN bits from the encap to the inner
301 p_ip4_encaps = [IP(src=tun_ecn.dst,
302 dst=self.pg0.local_ip4,
303 tos=tc) for tc in tcs]
304 p_ip4_replys = [p_ip4.copy() for i in range(len(p_ip4_encaps))]
305 p_ip4_replys[2].tos = ecn
306 p_ip4_replys[3].tos = ecn
307 for i, p_ip4_encap in enumerate(p_ip4_encaps):
308 p4 = (self.p_ether / p_ip4_encap / p_ip4 / self.p_payload)
309 p4_reply = (p_ip4_replys[i] / self.p_payload)
310 p4_reply.ttl -= 1
311 rx = self.send_and_expect(self.pg1, p4 * N_PACKETS, self.pg0)
312 n_packets_decapped += N_PACKETS
313 for p in rx:
314 self.validate(p[1], p4_reply)
315 self.assert_packet_checksums_valid(p)
316
317 err = self.statistics.get_err_counter(
318 '/err/ipip4-input/packets decapsulated')
319 self.assertEqual(err, n_packets_decapped)
Ole Troan73202102018-08-31 00:29:48 +0200320
Ole Troan298c6952018-03-08 12:30:43 +0100321 # IPv4 tunnel to IPv6
Neale Ranns95346962019-11-25 13:04:44 +0000322 # for each encap tun will produce the same inner packet because it does
323 # not copy up fields from the payload
324 p_ip4_encaps = [IP(src=tun.dst,
325 dst=self.pg0.local_ip4,
326 tos=tc) for tc in tcs]
Ole Troan298c6952018-03-08 12:30:43 +0100327 p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
Neale Ranns95346962019-11-25 13:04:44 +0000328 for p_ip4_encap in p_ip4_encaps:
329 p6 = (self.p_ether /
330 p_ip4_encap / p_ip6 /
331 self.p_payload)
332 p6_reply = (p_ip6 / self.p_payload)
333 p6_reply.hlim = 63
334 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
335 n_packets_decapped += N_PACKETS
336 for p in rx:
337 self.validate(p[1], p6_reply)
338 self.assert_packet_checksums_valid(p)
Ole Troan298c6952018-03-08 12:30:43 +0100339
Ole Troan233e4682019-05-16 15:01:34 +0200340 err = self.statistics.get_err_counter(
Ole Troan58492a82018-09-04 13:19:12 +0200341 '/err/ipip4-input/packets decapsulated')
Neale Ranns95346962019-11-25 13:04:44 +0000342 self.assertEqual(err, n_packets_decapped)
343
344 # IPv4 tunnel to IPv6
345 # tun_ecn copies the ECN bits from the encap to the inner
346 p_ip4_encaps = [IP(src=tun_ecn.dst,
347 dst=self.pg0.local_ip4,
348 tos=tc) for tc in tcs]
349 p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
350 p_ip6_replys = [p_ip6.copy() for i in range(len(p_ip4_encaps))]
351 p_ip6_replys[2].tc = ecn
352 p_ip6_replys[3].tc = ecn
353 for i, p_ip4_encap in enumerate(p_ip4_encaps):
354 p6 = (self.p_ether / p_ip4_encap / p_ip6 / self.p_payload)
355 p6_reply = (p_ip6_replys[i] / self.p_payload)
356 p6_reply.hlim = 63
357 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
358 n_packets_decapped += N_PACKETS
359 for p in rx:
360 self.validate(p[1], p6_reply)
361 self.assert_packet_checksums_valid(p)
362
363 err = self.statistics.get_err_counter(
364 '/err/ipip4-input/packets decapsulated')
365 self.assertEqual(err, n_packets_decapped)
Ole Troan73202102018-08-31 00:29:48 +0200366
Ole Troan7eb9d962018-08-10 14:39:48 +0200367 #
Ole Troan4146c652018-08-08 22:23:19 +0200368 # Fragmentation / Reassembly and Re-fragmentation
Ole Troan7eb9d962018-08-10 14:39:48 +0200369 #
Ole Troan4146c652018-08-08 22:23:19 +0200370 rv = self.vapi.ip_reassembly_enable_disable(
371 sw_if_index=self.pg1.sw_if_index,
372 enable_ip4=1)
Ole Troan4146c652018-08-08 22:23:19 +0200373
Klement Sekera3a343d42019-05-16 14:35:46 +0200374 self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=1000,
375 max_reassembly_length=1000,
376 expire_walk_interval_ms=10000,
377 is_ip6=0)
378
Ole Troan7eb9d962018-08-10 14:39:48 +0200379 # Send lots of fragments, verify reassembled packet
Ole Troan282093f2018-09-19 12:38:51 +0200380 frags, p4_reply = self.generate_ip4_frags(3131, 1400)
Ole Troan7eb9d962018-08-10 14:39:48 +0200381 f = []
382 for i in range(0, 1000):
383 f.extend(frags)
384 self.pg1.add_stream(f)
Ole Troan4146c652018-08-08 22:23:19 +0200385 self.pg_enable_capture()
Ole Troan4146c652018-08-08 22:23:19 +0200386 self.pg_start()
Ole Troan7eb9d962018-08-10 14:39:48 +0200387 rx = self.pg0.get_capture(1000)
Neale Ranns95346962019-11-25 13:04:44 +0000388 n_packets_decapped += 1000
Ole Troan7eb9d962018-08-10 14:39:48 +0200389
Ole Troan4146c652018-08-08 22:23:19 +0200390 for p in rx:
391 self.validate(p[1], p4_reply)
392
Ole Troan233e4682019-05-16 15:01:34 +0200393 err = self.statistics.get_err_counter(
Ole Troan58492a82018-09-04 13:19:12 +0200394 '/err/ipip4-input/packets decapsulated')
Neale Ranns95346962019-11-25 13:04:44 +0000395 self.assertEqual(err, n_packets_decapped)
Ole Troan73202102018-08-31 00:29:48 +0200396
Ole Troan7eb9d962018-08-10 14:39:48 +0200397 f = []
398 r = []
399 for i in range(1, 90):
Ole Troan282093f2018-09-19 12:38:51 +0200400 frags, p4_reply = self.generate_ip4_frags(i * 100, 1000)
Ole Troan7eb9d962018-08-10 14:39:48 +0200401 f.extend(frags)
402 r.extend(p4_reply)
403 self.pg_enable_capture()
404 self.pg1.add_stream(f)
405 self.pg_start()
406 rx = self.pg0.get_capture(89)
407 i = 0
408 for p in rx:
409 self.validate(p[1], r[i])
410 i += 1
411
Ole Troan4146c652018-08-08 22:23:19 +0200412 # Now try with re-fragmentation
Ole Troan7eb9d962018-08-10 14:39:48 +0200413 #
414 # Send fragments to tunnel head-end, for the tunnel head end
415 # to reassemble and then refragment
416 #
Ole Troan4146c652018-08-08 22:23:19 +0200417 self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [576, 0, 0, 0])
Ole Troan282093f2018-09-19 12:38:51 +0200418 frags, p4_reply = self.generate_ip4_frags(3123, 1200)
Ole Troan4146c652018-08-08 22:23:19 +0200419 self.pg_enable_capture()
420 self.pg1.add_stream(frags)
421 self.pg_start()
422 rx = self.pg0.get_capture(6)
Ole Troan7f991832018-12-06 17:35:12 +0100423 reass_pkt = reassemble4(rx)
Ole Troan4146c652018-08-08 22:23:19 +0200424 p4_reply.id = 256
425 self.validate(reass_pkt, p4_reply)
426
Ole Troan7eb9d962018-08-10 14:39:48 +0200427 self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [1600, 0, 0, 0])
Ole Troan282093f2018-09-19 12:38:51 +0200428 frags, p4_reply = self.generate_ip4_frags(3123, 1200)
Ole Troan7eb9d962018-08-10 14:39:48 +0200429 self.pg_enable_capture()
430 self.pg1.add_stream(frags)
431 self.pg_start()
432 rx = self.pg0.get_capture(2)
Ole Troan7f991832018-12-06 17:35:12 +0100433 reass_pkt = reassemble4(rx)
Ole Troan7eb9d962018-08-10 14:39:48 +0200434 p4_reply.id = 512
435 self.validate(reass_pkt, p4_reply)
436
Neale Ranns0b6a8572019-10-30 17:34:14 +0000437 # send large packets through the tunnel, expect them to be fragmented
Neale Ranns95346962019-11-25 13:04:44 +0000438 self.vapi.sw_interface_set_mtu(tun_dscp.sw_if_index, [600, 0, 0, 0])
Neale Ranns0b6a8572019-10-30 17:34:14 +0000439
440 p4 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
441 IP(src="1.2.3.4", dst="130.67.0.1", tos=42) /
442 UDP(sport=1234, dport=1234) / Raw(b'Q' * 1000))
443 rx = self.send_and_expect(self.pg0, p4 * 15, self.pg1, 30)
444 inners = []
445 for p in rx:
446 inners.append(p[IP].payload)
447 reass_pkt = reassemble4(inners)
448 for p in reass_pkt:
449 self.assert_packet_checksums_valid(p)
450 self.assertEqual(p[IP].ttl, 63)
451
Ole Troan282093f2018-09-19 12:38:51 +0200452 def test_ipip_create(self):
453 """ ipip create / delete interface test """
Neale Rannscbd08242019-05-26 11:34:27 -0700454 rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5')
Ole Troan282093f2018-09-19 12:38:51 +0200455 sw_if_index = rv.sw_if_index
456 self.vapi.ipip_del_tunnel(sw_if_index)
Ole Troan298c6952018-03-08 12:30:43 +0100457
Ole Troan282093f2018-09-19 12:38:51 +0200458 def test_ipip_vrf_create(self):
459 """ ipip create / delete interface VRF test """
460
461 t = VppIpTable(self, 20)
462 t.add_vpp_config()
Neale Rannscbd08242019-05-26 11:34:27 -0700463 rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5', table_id=20)
Ole Troan282093f2018-09-19 12:38:51 +0200464 sw_if_index = rv.sw_if_index
465 self.vapi.ipip_del_tunnel(sw_if_index)
466
467 def payload(self, len):
468 return 'x' * len
469
470
471class TestIPIP6(VppTestCase):
472 """ IPIP6 Test Case """
473
474 @classmethod
475 def setUpClass(cls):
476 super(TestIPIP6, cls).setUpClass()
477 cls.create_pg_interfaces(range(2))
478 cls.interfaces = list(cls.pg_interfaces)
479
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -0700480 @classmethod
481 def tearDownClass(cls):
482 super(TestIPIP6, cls).tearDownClass()
483
Ole Troan282093f2018-09-19 12:38:51 +0200484 def setUp(self):
Paul Vinciguerra8d991d92019-01-25 14:05:48 -0800485 super(TestIPIP6, self).setUp()
Ole Troan282093f2018-09-19 12:38:51 +0200486 for i in self.interfaces:
487 i.admin_up()
488 i.config_ip4()
489 i.config_ip6()
490 i.disable_ipv6_ra()
491 i.resolve_arp()
492 i.resolve_ndp()
493 self.setup_tunnel()
494
495 def tearDown(self):
496 if not self.vpp_dead:
497 self.destroy_tunnel()
498 for i in self.pg_interfaces:
499 i.unconfig_ip4()
500 i.unconfig_ip6()
501 i.admin_down()
502 super(TestIPIP6, self).tearDown()
503
504 def setup_tunnel(self):
Ole Troan298c6952018-03-08 12:30:43 +0100505 # IPv6 transport
Neale Rannscbd08242019-05-26 11:34:27 -0700506 rv = ipip_add_tunnel(self,
507 self.pg0.local_ip6,
Neale Ranns95346962019-11-25 13:04:44 +0000508 self.pg1.remote_ip6)
Ole Troan298c6952018-03-08 12:30:43 +0100509
510 sw_if_index = rv.sw_if_index
Ole Troan282093f2018-09-19 12:38:51 +0200511 self.tunnel_if_index = sw_if_index
Ole Troan46c1c112018-03-14 20:39:40 +0100512 self.vapi.sw_interface_set_flags(sw_if_index, 1)
513 self.vapi.sw_interface_set_unnumbered(
Ole Troan9a475372019-03-05 16:58:24 +0100514 sw_if_index=self.pg0.sw_if_index,
515 unnumbered_sw_if_index=sw_if_index)
Ole Troan298c6952018-03-08 12:30:43 +0100516
517 # Add IPv4 and IPv6 routes via tunnel interface
518 ip4_via_tunnel = VppIpRoute(
519 self, "130.67.0.0", 16,
520 [VppRoutePath("0.0.0.0",
521 sw_if_index,
Neale Ranns097fa662018-05-01 05:17:55 -0700522 proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)])
Ole Troan298c6952018-03-08 12:30:43 +0100523 ip4_via_tunnel.add_vpp_config()
524
525 ip6_via_tunnel = VppIpRoute(
526 self, "dead::", 16,
527 [VppRoutePath("::",
528 sw_if_index,
Neale Ranns097fa662018-05-01 05:17:55 -0700529 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
Ole Troan298c6952018-03-08 12:30:43 +0100530 ip6_via_tunnel.add_vpp_config()
531
Ole Troan282093f2018-09-19 12:38:51 +0200532 self.tunnel_ip6_via_tunnel = ip6_via_tunnel
533 self.tunnel_ip4_via_tunnel = ip4_via_tunnel
Ole Troan298c6952018-03-08 12:30:43 +0100534
Ole Troan282093f2018-09-19 12:38:51 +0200535 def destroy_tunnel(self):
536 # IPv6 transport
537 self.tunnel_ip4_via_tunnel.remove_vpp_config()
538 self.tunnel_ip6_via_tunnel.remove_vpp_config()
539
540 rv = self.vapi.ipip_del_tunnel(sw_if_index=self.tunnel_if_index)
541
542 def validate(self, rx, expected):
Ole Troan7f991832018-12-06 17:35:12 +0100543 self.assertEqual(rx, expected.__class__(expected))
Ole Troan282093f2018-09-19 12:38:51 +0200544
545 def generate_ip6_frags(self, payload_length, fragment_size):
546 p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
547 p_payload = UDP(sport=1234, dport=1234) / self.payload(payload_length)
548 p_ip6 = IPv6(src="1::1", dst=self.pg0.remote_ip6)
549 outer_ip6 = (p_ether / IPv6(src=self.pg1.remote_ip6,
550 dst=self.pg0.local_ip6) /
551 IPv6ExtHdrFragment() / p_ip6 / p_payload)
552 frags = fragment6(outer_ip6, fragment_size)
553 p6_reply = (p_ip6 / p_payload)
554 p6_reply.hlim -= 1
555 return frags, p6_reply
556
557 def generate_ip6_hairpin_frags(self, payload_length, fragment_size):
558 p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
559 p_payload = UDP(sport=1234, dport=1234) / self.payload(payload_length)
560 p_ip6 = IPv6(src="1::1", dst="dead::1")
561 outer_ip6 = (p_ether / IPv6(src=self.pg1.remote_ip6,
562 dst=self.pg0.local_ip6) /
563 IPv6ExtHdrFragment() / p_ip6 / p_payload)
564 frags = fragment6(outer_ip6, fragment_size)
565 p_ip6.hlim -= 1
566 p6_reply = (IPv6(src=self.pg0.local_ip6, dst=self.pg1.remote_ip6,
567 hlim=63) / p_ip6 / p_payload)
568
569 return frags, p6_reply
570
571 def test_encap(self):
572 """ ip{v4,v6} over ip6 test encap """
573 p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
574 p_ip6 = IPv6(src="1::1", dst="DEAD::1", tc=42, nh='UDP')
575 p_ip4 = IP(src="1.2.3.4", dst="130.67.0.1", tos=42)
576 p_payload = UDP(sport=1234, dport=1234)
577
578 # Encapsulation
Ole Troan298c6952018-03-08 12:30:43 +0100579 # IPv6 in to IPv6 tunnel
580 p6 = (p_ether / p_ip6 / p_payload)
Ole Troand57f6362018-05-24 13:21:43 +0200581 p6_reply = (IPv6(src=self.pg0.local_ip6, dst=self.pg1.remote_ip6,
Neale Ranns95346962019-11-25 13:04:44 +0000582 hlim=64) /
Ole Troand57f6362018-05-24 13:21:43 +0200583 p_ip6 / p_payload)
Ole Troan298c6952018-03-08 12:30:43 +0100584 p6_reply[1].hlim -= 1
Ole Troan9a475372019-03-05 16:58:24 +0100585 rx = self.send_and_expect(self.pg0, p6 * 11, self.pg1)
Ole Troan298c6952018-03-08 12:30:43 +0100586 for p in rx:
587 self.validate(p[1], p6_reply)
588
589 # IPv4 in to IPv6 tunnel
590 p4 = (p_ether / p_ip4 / p_payload)
591 p4_reply = (IPv6(src=self.pg0.local_ip6,
Neale Ranns95346962019-11-25 13:04:44 +0000592 dst=self.pg1.remote_ip6, hlim=64) /
Ole Troand57f6362018-05-24 13:21:43 +0200593 p_ip4 / p_payload)
Ole Troan298c6952018-03-08 12:30:43 +0100594 p4_reply[1].ttl -= 1
Ole Troan9a475372019-03-05 16:58:24 +0100595 rx = self.send_and_expect(self.pg0, p4 * 11, self.pg1)
Ole Troan298c6952018-03-08 12:30:43 +0100596 for p in rx:
597 self.validate(p[1], p4_reply)
598
Ole Troan282093f2018-09-19 12:38:51 +0200599 def test_decap(self):
600 """ ip{v4,v6} over ip6 test decap """
Ole Troan298c6952018-03-08 12:30:43 +0100601
602 p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
Ole Troan282093f2018-09-19 12:38:51 +0200603 p_ip6 = IPv6(src="1::1", dst="DEAD::1", tc=42, nh='UDP')
Ole Troan298c6952018-03-08 12:30:43 +0100604 p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
Ole Troan282093f2018-09-19 12:38:51 +0200605 p_payload = UDP(sport=1234, dport=1234)
606
607 # Decapsulation
608 # IPv6 tunnel to IPv4
609
Ole Troan298c6952018-03-08 12:30:43 +0100610 p4 = (p_ether / IPv6(src=self.pg1.remote_ip6,
611 dst=self.pg0.local_ip6) / p_ip4 / p_payload)
612 p4_reply = (p_ip4 / p_payload)
613 p4_reply.ttl -= 1
Ole Troan9a475372019-03-05 16:58:24 +0100614 rx = self.send_and_expect(self.pg1, p4 * 11, self.pg0)
Ole Troan298c6952018-03-08 12:30:43 +0100615 for p in rx:
616 self.validate(p[1], p4_reply)
617
618 # IPv6 tunnel to IPv6
619 p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
620 p6 = (p_ether / IPv6(src=self.pg1.remote_ip6,
621 dst=self.pg0.local_ip6) / p_ip6 / p_payload)
622 p6_reply = (p_ip6 / p_payload)
623 p6_reply.hlim = 63
Ole Troan9a475372019-03-05 16:58:24 +0100624 rx = self.send_and_expect(self.pg1, p6 * 11, self.pg0)
Ole Troan298c6952018-03-08 12:30:43 +0100625 for p in rx:
626 self.validate(p[1], p6_reply)
627
Neale Ranns95346962019-11-25 13:04:44 +0000628 def verify_ip4ip6_encaps(self, a, p_ip4s, p_ip6_encaps):
629 for i, p_ip4 in enumerate(p_ip4s):
630 p_ip4.dst = a
631 p4 = (self.p_ether / p_ip4 / self.p_payload)
632 p_ip4_inner = p_ip4
633 p_ip4_inner.ttl -= 1
634 p6_reply = (p_ip6_encaps[i] / p_ip4_inner / self.p_payload)
635 rx = self.send_and_expect(self.pg0, p4 * N_PACKETS, self.pg1)
636 for p in rx:
637 self.validate(p[1], p6_reply)
638 self.assert_packet_checksums_valid(p)
639
640 def verify_ip6ip6_encaps(self, a, p_ip6s, p_ip6_encaps):
641 for i, p_ip6 in enumerate(p_ip6s):
642 p_ip6.dst = a
643 p6 = (self.p_ether / p_ip6 / self.p_payload)
644 p_inner_ip6 = p_ip6
645 p_inner_ip6.hlim -= 1
646 p6_reply = (p_ip6_encaps[i] / p_inner_ip6 / self.p_payload)
647 rx = self.send_and_expect(self.pg0, p6 * N_PACKETS, self.pg1)
648 for p in rx:
649 self.validate(p[1], p6_reply)
650 self.assert_packet_checksums_valid(p)
651
652 def test_ipip6(self):
653 """ ip{v4,v6} over ip6 test """
654
655 # that's annoying
656 self.destroy_tunnel()
657
658 self.pg1.generate_remote_hosts(5)
659 self.pg1.configure_ipv6_neighbors()
660 e = VppEnum.vl_api_ipip_tunnel_flags_t
661 d = VppEnum.vl_api_ip_dscp_t
662 self.p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
663 self.p_payload = UDP(sport=1234, dport=1234) / Raw(b'X' * 100)
664
665 # create a TOS byte by shifting a DSCP code point 2 bits. those 2 bits
666 # are for the ECN.
667 dscp = d.IP_API_DSCP_AF31 << 2
668 ecn = 3
669 dscp_ecn = d.IP_API_DSCP_AF31 << 2 | ecn
670
671 # IPv4 transport that copies the DCSP from the payload
672 tun_dscp = VppIpIpTunInterface(
673 self,
674 self.pg0,
675 self.pg0.local_ip6,
676 self.pg1.remote_hosts[0].ip6,
677 flags=e.IPIP_TUNNEL_API_FLAG_ENCAP_COPY_DSCP).add_vpp_config()
678 # IPv4 transport that copies the DCSP and ECN from the payload
679 tun_dscp_ecn = VppIpIpTunInterface(
680 self,
681 self.pg0,
682 self.pg0.local_ip6,
683 self.pg1.remote_hosts[1].ip6,
684 flags=(e.IPIP_TUNNEL_API_FLAG_ENCAP_COPY_DSCP |
685 e.IPIP_TUNNEL_API_FLAG_ENCAP_COPY_ECN)).add_vpp_config()
686 # IPv4 transport that copies the ECN from the payload and sets the
687 # DF bit on encap. copies the ECN on decap
688 tun_ecn = VppIpIpTunInterface(
689 self,
690 self.pg0,
691 self.pg0.local_ip6,
692 self.pg1.remote_hosts[2].ip6,
693 flags=(e.IPIP_TUNNEL_API_FLAG_ENCAP_COPY_ECN |
694 e.IPIP_TUNNEL_API_FLAG_ENCAP_SET_DF |
695 e.IPIP_TUNNEL_API_FLAG_DECAP_COPY_ECN)).add_vpp_config()
696 # IPv4 transport that sets a fixed DSCP in the encap and copies
697 # the DF bit
698 tun = VppIpIpTunInterface(
699 self,
700 self.pg0,
701 self.pg0.local_ip6,
702 self.pg1.remote_hosts[3].ip6,
703 dscp=d.IP_API_DSCP_AF11,
704 flags=e.IPIP_TUNNEL_API_FLAG_ENCAP_COPY_DF).add_vpp_config()
705
706 # array of all the tunnels
707 tuns = [tun_dscp, tun_dscp_ecn, tun_ecn, tun]
708
709 # addresses for prefixes routed via each tunnel
710 a4s = ["" for i in range(len(tuns))]
711 a6s = ["" for i in range(len(tuns))]
712
713 # IP headers for inner packets with each combination of DSCp/ECN tested
714 p_ip6s = [IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=dscp),
715 IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=dscp_ecn),
716 IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=ecn),
717 IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=0xff)]
718 p_ip4s = [IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp, flags='DF'),
719 IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp_ecn),
720 IP(src="1.2.3.4", dst="130.67.0.1", tos=ecn),
721 IP(src="1.2.3.4", dst="130.67.0.1", tos=0xff)]
722
723 # Configure each tunnel
724 for i, t in enumerate(tuns):
725 # Set interface up and enable IP on it
726 self.vapi.sw_interface_set_flags(t.sw_if_index, 1)
727 self.vapi.sw_interface_set_unnumbered(
728 sw_if_index=self.pg0.sw_if_index,
729 unnumbered_sw_if_index=t.sw_if_index)
730
731 # prefix for route / destination address for packets
732 a4s[i] = "130.67.%d.0" % i
733 a6s[i] = "dead:%d::" % i
734
735 # Add IPv4 and IPv6 routes via tunnel interface
736 ip4_via_tunnel = VppIpRoute(
737 self, a4s[i], 24,
738 [VppRoutePath("0.0.0.0",
739 t.sw_if_index,
740 proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)])
741 ip4_via_tunnel.add_vpp_config()
742
743 ip6_via_tunnel = VppIpRoute(
744 self, a6s[i], 64,
745 [VppRoutePath("::",
746 t.sw_if_index,
747 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
748 ip6_via_tunnel.add_vpp_config()
749
750 #
751 # Encapsulation
752 #
753
754 # tun_dscp copies only the dscp
755 # expected TC values are thus only the DCSP value is present from the
756 # inner
757 exp_tcs = [dscp, dscp, 0, 0xfc]
758 p_ip6_encaps = [IPv6(src=self.pg0.local_ip6,
759 dst=tun_dscp.dst,
760 tc=tc) for tc in exp_tcs]
761
762 # IPv4 in to IPv4 tunnel
763 self.verify_ip4ip6_encaps(a4s[0], p_ip4s, p_ip6_encaps)
764 # IPv6 in to IPv4 tunnel
765 self.verify_ip6ip6_encaps(a6s[0], p_ip6s, p_ip6_encaps)
766
767 # tun_dscp_ecn copies the dscp and the ecn
768 exp_tcs = [dscp, dscp_ecn, ecn, 0xff]
769 p_ip6_encaps = [IPv6(src=self.pg0.local_ip6,
770 dst=tun_dscp_ecn.dst,
771 tc=tc) for tc in exp_tcs]
772
773 self.verify_ip4ip6_encaps(a4s[1], p_ip4s, p_ip6_encaps)
774 self.verify_ip6ip6_encaps(a6s[1], p_ip6s, p_ip6_encaps)
775
776 # tun_ecn copies only the ecn and always sets DF
777 exp_tcs = [0, ecn, ecn, ecn]
778 p_ip6_encaps = [IPv6(src=self.pg0.local_ip6,
779 dst=tun_ecn.dst,
780 tc=tc) for tc in exp_tcs]
781
782 self.verify_ip4ip6_encaps(a4s[2], p_ip4s, p_ip6_encaps)
783 self.verify_ip6ip6_encaps(a6s[2], p_ip6s, p_ip6_encaps)
784
785 # tun sets a fixed dscp
786 fixed_dscp = tun.dscp << 2
787 p_ip6_encaps = [IPv6(src=self.pg0.local_ip6,
788 dst=tun.dst,
789 tc=fixed_dscp) for i in range(len(p_ip4s))]
790
791 self.verify_ip4ip6_encaps(a4s[3], p_ip4s, p_ip6_encaps)
792 self.verify_ip6ip6_encaps(a6s[3], p_ip6s, p_ip6_encaps)
793
794 #
795 # Decapsulation
796 #
797 n_packets_decapped = self.statistics.get_err_counter(
798 '/err/ipip6-input/packets decapsulated')
799
800 self.p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
801
802 # IPv6 tunnel to IPv4
803 tcs = [0, dscp, dscp_ecn, ecn]
804
805 # one overlay packet and all combinations of its encap
806 p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
807 p_ip6_encaps = [IPv6(src=tun.dst,
808 dst=self.pg0.local_ip6,
809 tc=tc) for tc in tcs]
810
811 # for each encap tun will produce the same inner packet because it does
812 # not copy up fields from the payload
813 for p_ip6_encap in p_ip6_encaps:
814 p6 = (self.p_ether / p_ip6_encap / p_ip4 / self.p_payload)
815 p4_reply = (p_ip4 / self.p_payload)
816 p4_reply.ttl -= 1
817 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
818 n_packets_decapped += N_PACKETS
819 for p in rx:
820 self.validate(p[1], p4_reply)
821 self.assert_packet_checksums_valid(p)
822
823 err = self.statistics.get_err_counter(
824 '/err/ipip6-input/packets decapsulated')
825 self.assertEqual(err, n_packets_decapped)
826
827 # tun_ecn copies the ECN bits from the encap to the inner
828 p_ip6_encaps = [IPv6(src=tun_ecn.dst,
829 dst=self.pg0.local_ip6,
830 tc=tc) for tc in tcs]
831 p_ip4_replys = [p_ip4.copy() for i in range(len(p_ip6_encaps))]
832 p_ip4_replys[2].tos = ecn
833 p_ip4_replys[3].tos = ecn
834 for i, p_ip6_encap in enumerate(p_ip6_encaps):
835 p6 = (self.p_ether / p_ip6_encap / p_ip4 / self.p_payload)
836 p4_reply = (p_ip4_replys[i] / self.p_payload)
837 p4_reply.ttl -= 1
838 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
839 n_packets_decapped += N_PACKETS
840 for p in rx:
841 self.validate(p[1], p4_reply)
842 self.assert_packet_checksums_valid(p)
843
844 err = self.statistics.get_err_counter(
845 '/err/ipip6-input/packets decapsulated')
846 self.assertEqual(err, n_packets_decapped)
847
848 # IPv6 tunnel to IPv6
849 # for each encap tun will produce the same inner packet because it does
850 # not copy up fields from the payload
851 p_ip6_encaps = [IPv6(src=tun.dst,
852 dst=self.pg0.local_ip6,
853 tc=tc) for tc in tcs]
854 p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
855 for p_ip6_encap in p_ip6_encaps:
856 p6 = (self.p_ether / p_ip6_encap / p_ip6 / self.p_payload)
857 p6_reply = (p_ip6 / self.p_payload)
858 p6_reply.hlim = 63
859 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
860 n_packets_decapped += N_PACKETS
861 for p in rx:
862 self.validate(p[1], p6_reply)
863 self.assert_packet_checksums_valid(p)
864
865 err = self.statistics.get_err_counter(
866 '/err/ipip6-input/packets decapsulated')
867 self.assertEqual(err, n_packets_decapped)
868
869 # IPv6 tunnel to IPv6
870 # tun_ecn copies the ECN bits from the encap to the inner
871 p_ip6_encaps = [IPv6(src=tun_ecn.dst,
872 dst=self.pg0.local_ip6,
873 tc=tc) for tc in tcs]
874 p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
875 p_ip6_replys = [p_ip6.copy() for i in range(len(p_ip6_encaps))]
876 p_ip6_replys[2].tc = ecn
877 p_ip6_replys[3].tc = ecn
878 for i, p_ip6_encap in enumerate(p_ip6_encaps):
879 p6 = (self.p_ether / p_ip6_encap / p_ip6 / self.p_payload)
880 p6_reply = (p_ip6_replys[i] / self.p_payload)
881 p6_reply.hlim = 63
882 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
883 n_packets_decapped += N_PACKETS
884 for p in rx:
885 self.validate(p[1], p6_reply)
886 self.assert_packet_checksums_valid(p)
887
888 err = self.statistics.get_err_counter(
889 '/err/ipip6-input/packets decapsulated')
890 self.assertEqual(err, n_packets_decapped)
891
Ole Troan282093f2018-09-19 12:38:51 +0200892 def test_frag(self):
893 """ ip{v4,v6} over ip6 test frag """
894
895 p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
896 p_ip6 = IPv6(src="1::1", dst="DEAD::1", tc=42, nh='UDP')
897 p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
898 p_payload = UDP(sport=1234, dport=1234)
899
900 #
901 # Fragmentation / Reassembly and Re-fragmentation
902 #
903 rv = self.vapi.ip_reassembly_enable_disable(
904 sw_if_index=self.pg1.sw_if_index,
905 enable_ip6=1)
906
Klement Sekera3a343d42019-05-16 14:35:46 +0200907 self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=1000,
908 max_reassembly_length=1000,
909 expire_walk_interval_ms=10000,
910 is_ip6=1)
911
Ole Troan282093f2018-09-19 12:38:51 +0200912 # Send lots of fragments, verify reassembled packet
Ole Troan233e4682019-05-16 15:01:34 +0200913 before_cnt = self.statistics.get_err_counter(
Ole Troan282093f2018-09-19 12:38:51 +0200914 '/err/ipip6-input/packets decapsulated')
915 frags, p6_reply = self.generate_ip6_frags(3131, 1400)
916 f = []
917 for i in range(0, 1000):
918 f.extend(frags)
919 self.pg1.add_stream(f)
920 self.pg_enable_capture()
921 self.pg_start()
922 rx = self.pg0.get_capture(1000)
923
924 for p in rx:
925 self.validate(p[1], p6_reply)
926
Ole Troan233e4682019-05-16 15:01:34 +0200927 cnt = self.statistics.get_err_counter(
Ole Troan282093f2018-09-19 12:38:51 +0200928 '/err/ipip6-input/packets decapsulated')
929 self.assertEqual(cnt, before_cnt + 1000)
930
931 f = []
932 r = []
933 # TODO: Check out why reassembly of atomic fragments don't work
934 for i in range(10, 90):
935 frags, p6_reply = self.generate_ip6_frags(i * 100, 1000)
936 f.extend(frags)
937 r.extend(p6_reply)
938 self.pg_enable_capture()
939 self.pg1.add_stream(f)
940 self.pg_start()
941 rx = self.pg0.get_capture(80)
942 i = 0
943 for p in rx:
944 self.validate(p[1], r[i])
945 i += 1
946
947 # Simple fragmentation
948 p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
949 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1280, 0, 0, 0])
950
951 # IPv6 in to IPv6 tunnel
952 p_payload = UDP(sport=1234, dport=1234) / self.payload(1300)
953
954 p6 = (p_ether / p_ip6 / p_payload)
955 p6_reply = (IPv6(src=self.pg0.local_ip6, dst=self.pg1.remote_ip6,
Neale Ranns95346962019-11-25 13:04:44 +0000956 hlim=63) /
Ole Troan282093f2018-09-19 12:38:51 +0200957 p_ip6 / p_payload)
958 p6_reply[1].hlim -= 1
959 self.pg_enable_capture()
960 self.pg0.add_stream(p6)
961 self.pg_start()
962 rx = self.pg1.get_capture(2)
963
964 # Scapy defragment doesn't deal well with multiple layers
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700965 # of same type / Ethernet header first
Ole Troan282093f2018-09-19 12:38:51 +0200966 f = [p[1] for p in rx]
967 reass_pkt = defragment6(f)
968 self.validate(reass_pkt, p6_reply)
969
970 # Now try with re-fragmentation
971 #
972 # Send large fragments to tunnel head-end, for the tunnel head end
973 # to reassemble and then refragment out the tunnel again.
974 # Hair-pinning
975 #
976 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1280, 0, 0, 0])
977 frags, p6_reply = self.generate_ip6_hairpin_frags(8000, 1200)
978 self.pg_enable_capture()
979 self.pg1.add_stream(frags)
980 self.pg_start()
981 rx = self.pg1.get_capture(7)
982 f = [p[1] for p in rx]
983 reass_pkt = defragment6(f)
984 p6_reply.id = 256
985 self.validate(reass_pkt, p6_reply)
986
Ole Troan298c6952018-03-08 12:30:43 +0100987 def test_ipip_create(self):
988 """ ipip create / delete interface test """
Neale Rannscbd08242019-05-26 11:34:27 -0700989 rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5')
Ole Troan298c6952018-03-08 12:30:43 +0100990 sw_if_index = rv.sw_if_index
Ole Troan46c1c112018-03-14 20:39:40 +0100991 self.vapi.ipip_del_tunnel(sw_if_index)
Ole Troan298c6952018-03-08 12:30:43 +0100992
Neale Ranns61502112018-08-22 00:21:14 -0700993 def test_ipip_vrf_create(self):
994 """ ipip create / delete interface VRF test """
995
996 t = VppIpTable(self, 20)
997 t.add_vpp_config()
Neale Rannscbd08242019-05-26 11:34:27 -0700998 rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5', table_id=20)
Neale Ranns61502112018-08-22 00:21:14 -0700999 sw_if_index = rv.sw_if_index
1000 self.vapi.ipip_del_tunnel(sw_if_index)
1001
Ole Troan4146c652018-08-08 22:23:19 +02001002 def payload(self, len):
1003 return 'x' * len
1004
Ole Troan298c6952018-03-08 12:30:43 +01001005
1006if __name__ == '__main__':
1007 unittest.main(testRunner=VppTestRunner)