blob: 869dbaaa3afc262bff9c8cb5f75e6422f783257e [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()
Neale Ranns59ff9182019-12-29 23:55:18 +0000119 e = VppEnum.vl_api_tunnel_encap_decap_flags_t
Neale Ranns95346962019-11-25 13:04:44 +0000120 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,
Neale Ranns59ff9182019-12-29 23:55:18 +0000136 flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP)
137 tun_dscp.add_vpp_config()
Neale Ranns95346962019-11-25 13:04:44 +0000138 # IPv4 transport that copies the DCSP and ECN from the payload
139 tun_dscp_ecn = VppIpIpTunInterface(
140 self,
141 self.pg0,
142 self.pg0.local_ip4,
143 self.pg1.remote_hosts[1].ip4,
Neale Ranns59ff9182019-12-29 23:55:18 +0000144 flags=(e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP |
145 e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN))
146 tun_dscp_ecn.add_vpp_config()
Neale Ranns95346962019-11-25 13:04:44 +0000147 # IPv4 transport that copies the ECN from the payload and sets the
148 # DF bit on encap. copies the ECN on decap
149 tun_ecn = VppIpIpTunInterface(
150 self,
151 self.pg0,
152 self.pg0.local_ip4,
153 self.pg1.remote_hosts[2].ip4,
Neale Ranns59ff9182019-12-29 23:55:18 +0000154 flags=(e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN |
155 e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_SET_DF |
156 e.TUNNEL_API_ENCAP_DECAP_FLAG_DECAP_COPY_ECN))
157 tun_ecn.add_vpp_config()
Neale Ranns95346962019-11-25 13:04:44 +0000158 # IPv4 transport that sets a fixed DSCP in the encap and copies
159 # the DF bit
160 tun = VppIpIpTunInterface(
161 self,
162 self.pg0,
163 self.pg0.local_ip4,
164 self.pg1.remote_hosts[3].ip4,
165 dscp=d.IP_API_DSCP_AF11,
Neale Ranns59ff9182019-12-29 23:55:18 +0000166 flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DF)
167 tun.add_vpp_config()
Ole Troan298c6952018-03-08 12:30:43 +0100168
Neale Ranns95346962019-11-25 13:04:44 +0000169 # array of all the tunnels
170 tuns = [tun_dscp, tun_dscp_ecn, tun_ecn, tun]
Ole Troan298c6952018-03-08 12:30:43 +0100171
Neale Ranns95346962019-11-25 13:04:44 +0000172 # addresses for prefixes routed via each tunnel
173 a4s = ["" for i in range(len(tuns))]
174 a6s = ["" for i in range(len(tuns))]
175
176 # IP headers with each combination of DSCp/ECN tested
177 p_ip6s = [IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=dscp),
178 IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=dscp_ecn),
179 IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=ecn),
180 IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=0xff)]
181 p_ip4s = [IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp, flags='DF'),
182 IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp_ecn),
183 IP(src="1.2.3.4", dst="130.67.0.1", tos=ecn),
184 IP(src="1.2.3.4", dst="130.67.0.1", tos=0xff)]
185
186 # Configure each tunnel
187 for i, t in enumerate(tuns):
188 # Set interface up and enable IP on it
189 self.vapi.sw_interface_set_flags(t.sw_if_index, 1)
190 self.vapi.sw_interface_set_unnumbered(
191 sw_if_index=self.pg0.sw_if_index,
192 unnumbered_sw_if_index=t.sw_if_index)
193
194 # prefix for route / destination address for packets
195 a4s[i] = "130.67.%d.0" % i
196 a6s[i] = "dead:%d::" % i
197
198 # Add IPv4 and IPv6 routes via tunnel interface
199 ip4_via_tunnel = VppIpRoute(
200 self, a4s[i], 24,
201 [VppRoutePath("0.0.0.0",
202 t.sw_if_index,
203 proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)])
204 ip4_via_tunnel.add_vpp_config()
205
206 ip6_via_tunnel = VppIpRoute(
207 self, a6s[i], 64,
208 [VppRoutePath("::",
209 t.sw_if_index,
210 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
211 ip6_via_tunnel.add_vpp_config()
212
213 #
214 # Encapsulation
215 #
216
217 # tun_dscp copies only the dscp
218 # expected TC values are thus only the DCSP value is present from the
219 # inner
220 exp_tcs = [dscp, dscp, 0, 0xfc]
221 p_ip44_encaps = [IP(src=self.pg0.local_ip4,
222 dst=tun_dscp.dst,
223 tos=tc) for tc in exp_tcs]
224 p_ip64_encaps = [IP(src=self.pg0.local_ip4,
225 dst=tun_dscp.dst,
226 proto='ipv6', id=0, tos=tc) for tc in exp_tcs]
Ole Troan298c6952018-03-08 12:30:43 +0100227
228 # IPv4 in to IPv4 tunnel
Neale Ranns95346962019-11-25 13:04:44 +0000229 self.verify_ip4ip4_encaps(a4s[0], p_ip4s, p_ip44_encaps)
230 # IPv6 in to IPv4 tunnel
231 self.verify_ip6ip4_encaps(a6s[0], p_ip6s, p_ip64_encaps)
Ole Troan298c6952018-03-08 12:30:43 +0100232
Neale Ranns95346962019-11-25 13:04:44 +0000233 # tun_dscp_ecn copies the dscp and the ecn
234 exp_tcs = [dscp, dscp_ecn, ecn, 0xff]
235 p_ip44_encaps = [IP(src=self.pg0.local_ip4,
236 dst=tun_dscp_ecn.dst,
237 tos=tc) for tc in exp_tcs]
238 p_ip64_encaps = [IP(src=self.pg0.local_ip4,
239 dst=tun_dscp_ecn.dst,
240 proto='ipv6', id=0, tos=tc) for tc in exp_tcs]
241
242 self.verify_ip4ip4_encaps(a4s[1], p_ip4s, p_ip44_encaps)
243 self.verify_ip6ip4_encaps(a6s[1], p_ip6s, p_ip64_encaps)
244
245 # tun_ecn copies only the ecn and always sets DF
246 exp_tcs = [0, ecn, ecn, ecn]
247 p_ip44_encaps = [IP(src=self.pg0.local_ip4,
248 dst=tun_ecn.dst,
249 flags='DF', tos=tc) for tc in exp_tcs]
250 p_ip64_encaps = [IP(src=self.pg0.local_ip4,
251 dst=tun_ecn.dst,
252 flags='DF', proto='ipv6', id=0, tos=tc)
253 for tc in exp_tcs]
254
255 self.verify_ip4ip4_encaps(a4s[2], p_ip4s, p_ip44_encaps)
256 self.verify_ip6ip4_encaps(a6s[2], p_ip6s, p_ip64_encaps)
257
258 # tun sets a fixed dscp and copies DF
259 fixed_dscp = tun.dscp << 2
260 flags = ['DF', 0, 0, 0]
261 p_ip44_encaps = [IP(src=self.pg0.local_ip4,
262 dst=tun.dst,
263 flags=f,
264 tos=fixed_dscp) for f in flags]
265 p_ip64_encaps = [IP(src=self.pg0.local_ip4,
266 dst=tun.dst,
267 proto='ipv6', id=0,
268 tos=fixed_dscp) for i in range(len(p_ip4s))]
269
270 self.verify_ip4ip4_encaps(a4s[3], p_ip4s, p_ip44_encaps)
271 self.verify_ip6ip4_encaps(a6s[3], p_ip6s, p_ip64_encaps)
272
273 #
Ole Troan298c6952018-03-08 12:30:43 +0100274 # Decapsulation
Neale Ranns95346962019-11-25 13:04:44 +0000275 #
276 n_packets_decapped = 0
277 self.p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
Ole Troan298c6952018-03-08 12:30:43 +0100278
279 # IPv4 tunnel to IPv4
Neale Ranns95346962019-11-25 13:04:44 +0000280 tcs = [0, dscp, dscp_ecn, ecn]
281
282 # one overlay packet and all combinations of its encap
Ole Troan298c6952018-03-08 12:30:43 +0100283 p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
Neale Ranns95346962019-11-25 13:04:44 +0000284 p_ip4_encaps = [IP(src=tun.dst,
285 dst=self.pg0.local_ip4,
286 tos=tc) for tc in tcs]
287
288 # for each encap tun will produce the same inner packet because it does
289 # not copy up fields from the payload
290 for p_ip4_encap in p_ip4_encaps:
291 p4 = (self.p_ether / p_ip4_encap / p_ip4 / self.p_payload)
292 p4_reply = (p_ip4 / self.p_payload)
293 p4_reply.ttl -= 1
294 rx = self.send_and_expect(self.pg1, p4 * N_PACKETS, self.pg0)
295 n_packets_decapped += N_PACKETS
296 for p in rx:
297 self.validate(p[1], p4_reply)
298 self.assert_packet_checksums_valid(p)
Ole Troan298c6952018-03-08 12:30:43 +0100299
Ole Troan233e4682019-05-16 15:01:34 +0200300 err = self.statistics.get_err_counter(
Ole Troan58492a82018-09-04 13:19:12 +0200301 '/err/ipip4-input/packets decapsulated')
Neale Ranns95346962019-11-25 13:04:44 +0000302 self.assertEqual(err, n_packets_decapped)
303
304 # tun_ecn copies the ECN bits from the encap to the inner
305 p_ip4_encaps = [IP(src=tun_ecn.dst,
306 dst=self.pg0.local_ip4,
307 tos=tc) for tc in tcs]
308 p_ip4_replys = [p_ip4.copy() for i in range(len(p_ip4_encaps))]
309 p_ip4_replys[2].tos = ecn
310 p_ip4_replys[3].tos = ecn
311 for i, p_ip4_encap in enumerate(p_ip4_encaps):
312 p4 = (self.p_ether / p_ip4_encap / p_ip4 / self.p_payload)
313 p4_reply = (p_ip4_replys[i] / self.p_payload)
314 p4_reply.ttl -= 1
315 rx = self.send_and_expect(self.pg1, p4 * N_PACKETS, self.pg0)
316 n_packets_decapped += N_PACKETS
317 for p in rx:
318 self.validate(p[1], p4_reply)
319 self.assert_packet_checksums_valid(p)
320
321 err = self.statistics.get_err_counter(
322 '/err/ipip4-input/packets decapsulated')
323 self.assertEqual(err, n_packets_decapped)
Ole Troan73202102018-08-31 00:29:48 +0200324
Ole Troan298c6952018-03-08 12:30:43 +0100325 # IPv4 tunnel to IPv6
Neale Ranns95346962019-11-25 13:04:44 +0000326 # for each encap tun will produce the same inner packet because it does
327 # not copy up fields from the payload
328 p_ip4_encaps = [IP(src=tun.dst,
329 dst=self.pg0.local_ip4,
330 tos=tc) for tc in tcs]
Ole Troan298c6952018-03-08 12:30:43 +0100331 p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
Neale Ranns95346962019-11-25 13:04:44 +0000332 for p_ip4_encap in p_ip4_encaps:
333 p6 = (self.p_ether /
334 p_ip4_encap / p_ip6 /
335 self.p_payload)
336 p6_reply = (p_ip6 / self.p_payload)
337 p6_reply.hlim = 63
338 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
339 n_packets_decapped += N_PACKETS
340 for p in rx:
341 self.validate(p[1], p6_reply)
342 self.assert_packet_checksums_valid(p)
Ole Troan298c6952018-03-08 12:30:43 +0100343
Ole Troan233e4682019-05-16 15:01:34 +0200344 err = self.statistics.get_err_counter(
Ole Troan58492a82018-09-04 13:19:12 +0200345 '/err/ipip4-input/packets decapsulated')
Neale Ranns95346962019-11-25 13:04:44 +0000346 self.assertEqual(err, n_packets_decapped)
347
348 # IPv4 tunnel to IPv6
349 # tun_ecn copies the ECN bits from the encap to the inner
350 p_ip4_encaps = [IP(src=tun_ecn.dst,
351 dst=self.pg0.local_ip4,
352 tos=tc) for tc in tcs]
353 p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
354 p_ip6_replys = [p_ip6.copy() for i in range(len(p_ip4_encaps))]
355 p_ip6_replys[2].tc = ecn
356 p_ip6_replys[3].tc = ecn
357 for i, p_ip4_encap in enumerate(p_ip4_encaps):
358 p6 = (self.p_ether / p_ip4_encap / p_ip6 / self.p_payload)
359 p6_reply = (p_ip6_replys[i] / self.p_payload)
360 p6_reply.hlim = 63
361 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
362 n_packets_decapped += N_PACKETS
363 for p in rx:
364 self.validate(p[1], p6_reply)
365 self.assert_packet_checksums_valid(p)
366
367 err = self.statistics.get_err_counter(
368 '/err/ipip4-input/packets decapsulated')
369 self.assertEqual(err, n_packets_decapped)
Ole Troan73202102018-08-31 00:29:48 +0200370
Ole Troan7eb9d962018-08-10 14:39:48 +0200371 #
Ole Troan4146c652018-08-08 22:23:19 +0200372 # Fragmentation / Reassembly and Re-fragmentation
Ole Troan7eb9d962018-08-10 14:39:48 +0200373 #
Ole Troan4146c652018-08-08 22:23:19 +0200374 rv = self.vapi.ip_reassembly_enable_disable(
375 sw_if_index=self.pg1.sw_if_index,
376 enable_ip4=1)
Ole Troan4146c652018-08-08 22:23:19 +0200377
Klement Sekera3a343d42019-05-16 14:35:46 +0200378 self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=1000,
379 max_reassembly_length=1000,
380 expire_walk_interval_ms=10000,
381 is_ip6=0)
382
Ole Troan7eb9d962018-08-10 14:39:48 +0200383 # Send lots of fragments, verify reassembled packet
Ole Troan282093f2018-09-19 12:38:51 +0200384 frags, p4_reply = self.generate_ip4_frags(3131, 1400)
Ole Troan7eb9d962018-08-10 14:39:48 +0200385 f = []
386 for i in range(0, 1000):
387 f.extend(frags)
388 self.pg1.add_stream(f)
Ole Troan4146c652018-08-08 22:23:19 +0200389 self.pg_enable_capture()
Ole Troan4146c652018-08-08 22:23:19 +0200390 self.pg_start()
Ole Troan7eb9d962018-08-10 14:39:48 +0200391 rx = self.pg0.get_capture(1000)
Neale Ranns95346962019-11-25 13:04:44 +0000392 n_packets_decapped += 1000
Ole Troan7eb9d962018-08-10 14:39:48 +0200393
Ole Troan4146c652018-08-08 22:23:19 +0200394 for p in rx:
395 self.validate(p[1], p4_reply)
396
Ole Troan233e4682019-05-16 15:01:34 +0200397 err = self.statistics.get_err_counter(
Ole Troan58492a82018-09-04 13:19:12 +0200398 '/err/ipip4-input/packets decapsulated')
Neale Ranns95346962019-11-25 13:04:44 +0000399 self.assertEqual(err, n_packets_decapped)
Ole Troan73202102018-08-31 00:29:48 +0200400
Ole Troan7eb9d962018-08-10 14:39:48 +0200401 f = []
402 r = []
403 for i in range(1, 90):
Ole Troan282093f2018-09-19 12:38:51 +0200404 frags, p4_reply = self.generate_ip4_frags(i * 100, 1000)
Ole Troan7eb9d962018-08-10 14:39:48 +0200405 f.extend(frags)
406 r.extend(p4_reply)
407 self.pg_enable_capture()
408 self.pg1.add_stream(f)
409 self.pg_start()
410 rx = self.pg0.get_capture(89)
411 i = 0
412 for p in rx:
413 self.validate(p[1], r[i])
414 i += 1
415
Ole Troan4146c652018-08-08 22:23:19 +0200416 # Now try with re-fragmentation
Ole Troan7eb9d962018-08-10 14:39:48 +0200417 #
418 # Send fragments to tunnel head-end, for the tunnel head end
419 # to reassemble and then refragment
420 #
Ole Troan4146c652018-08-08 22:23:19 +0200421 self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [576, 0, 0, 0])
Ole Troan282093f2018-09-19 12:38:51 +0200422 frags, p4_reply = self.generate_ip4_frags(3123, 1200)
Ole Troan4146c652018-08-08 22:23:19 +0200423 self.pg_enable_capture()
424 self.pg1.add_stream(frags)
425 self.pg_start()
426 rx = self.pg0.get_capture(6)
Ole Troan7f991832018-12-06 17:35:12 +0100427 reass_pkt = reassemble4(rx)
Ole Troan4146c652018-08-08 22:23:19 +0200428 p4_reply.id = 256
429 self.validate(reass_pkt, p4_reply)
430
Ole Troan7eb9d962018-08-10 14:39:48 +0200431 self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [1600, 0, 0, 0])
Ole Troan282093f2018-09-19 12:38:51 +0200432 frags, p4_reply = self.generate_ip4_frags(3123, 1200)
Ole Troan7eb9d962018-08-10 14:39:48 +0200433 self.pg_enable_capture()
434 self.pg1.add_stream(frags)
435 self.pg_start()
436 rx = self.pg0.get_capture(2)
Ole Troan7f991832018-12-06 17:35:12 +0100437 reass_pkt = reassemble4(rx)
Ole Troan7eb9d962018-08-10 14:39:48 +0200438 p4_reply.id = 512
439 self.validate(reass_pkt, p4_reply)
440
Neale Ranns0b6a8572019-10-30 17:34:14 +0000441 # send large packets through the tunnel, expect them to be fragmented
Neale Ranns95346962019-11-25 13:04:44 +0000442 self.vapi.sw_interface_set_mtu(tun_dscp.sw_if_index, [600, 0, 0, 0])
Neale Ranns0b6a8572019-10-30 17:34:14 +0000443
444 p4 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
445 IP(src="1.2.3.4", dst="130.67.0.1", tos=42) /
446 UDP(sport=1234, dport=1234) / Raw(b'Q' * 1000))
447 rx = self.send_and_expect(self.pg0, p4 * 15, self.pg1, 30)
448 inners = []
449 for p in rx:
450 inners.append(p[IP].payload)
451 reass_pkt = reassemble4(inners)
452 for p in reass_pkt:
453 self.assert_packet_checksums_valid(p)
454 self.assertEqual(p[IP].ttl, 63)
455
Ole Troan282093f2018-09-19 12:38:51 +0200456 def test_ipip_create(self):
457 """ ipip create / delete interface test """
Neale Rannscbd08242019-05-26 11:34:27 -0700458 rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5')
Ole Troan282093f2018-09-19 12:38:51 +0200459 sw_if_index = rv.sw_if_index
460 self.vapi.ipip_del_tunnel(sw_if_index)
Ole Troan298c6952018-03-08 12:30:43 +0100461
Ole Troan282093f2018-09-19 12:38:51 +0200462 def test_ipip_vrf_create(self):
463 """ ipip create / delete interface VRF test """
464
465 t = VppIpTable(self, 20)
466 t.add_vpp_config()
Neale Rannscbd08242019-05-26 11:34:27 -0700467 rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5', table_id=20)
Ole Troan282093f2018-09-19 12:38:51 +0200468 sw_if_index = rv.sw_if_index
469 self.vapi.ipip_del_tunnel(sw_if_index)
470
471 def payload(self, len):
472 return 'x' * len
473
474
475class TestIPIP6(VppTestCase):
476 """ IPIP6 Test Case """
477
478 @classmethod
479 def setUpClass(cls):
480 super(TestIPIP6, cls).setUpClass()
481 cls.create_pg_interfaces(range(2))
482 cls.interfaces = list(cls.pg_interfaces)
483
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -0700484 @classmethod
485 def tearDownClass(cls):
486 super(TestIPIP6, cls).tearDownClass()
487
Ole Troan282093f2018-09-19 12:38:51 +0200488 def setUp(self):
Paul Vinciguerra8d991d92019-01-25 14:05:48 -0800489 super(TestIPIP6, self).setUp()
Ole Troan282093f2018-09-19 12:38:51 +0200490 for i in self.interfaces:
491 i.admin_up()
492 i.config_ip4()
493 i.config_ip6()
494 i.disable_ipv6_ra()
495 i.resolve_arp()
496 i.resolve_ndp()
497 self.setup_tunnel()
498
499 def tearDown(self):
500 if not self.vpp_dead:
501 self.destroy_tunnel()
502 for i in self.pg_interfaces:
503 i.unconfig_ip4()
504 i.unconfig_ip6()
505 i.admin_down()
506 super(TestIPIP6, self).tearDown()
507
508 def setup_tunnel(self):
Ole Troan298c6952018-03-08 12:30:43 +0100509 # IPv6 transport
Neale Rannscbd08242019-05-26 11:34:27 -0700510 rv = ipip_add_tunnel(self,
511 self.pg0.local_ip6,
Neale Ranns95346962019-11-25 13:04:44 +0000512 self.pg1.remote_ip6)
Ole Troan298c6952018-03-08 12:30:43 +0100513
514 sw_if_index = rv.sw_if_index
Ole Troan282093f2018-09-19 12:38:51 +0200515 self.tunnel_if_index = sw_if_index
Ole Troan46c1c112018-03-14 20:39:40 +0100516 self.vapi.sw_interface_set_flags(sw_if_index, 1)
517 self.vapi.sw_interface_set_unnumbered(
Ole Troan9a475372019-03-05 16:58:24 +0100518 sw_if_index=self.pg0.sw_if_index,
519 unnumbered_sw_if_index=sw_if_index)
Ole Troan298c6952018-03-08 12:30:43 +0100520
521 # Add IPv4 and IPv6 routes via tunnel interface
522 ip4_via_tunnel = VppIpRoute(
523 self, "130.67.0.0", 16,
524 [VppRoutePath("0.0.0.0",
525 sw_if_index,
Neale Ranns097fa662018-05-01 05:17:55 -0700526 proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)])
Ole Troan298c6952018-03-08 12:30:43 +0100527 ip4_via_tunnel.add_vpp_config()
528
529 ip6_via_tunnel = VppIpRoute(
530 self, "dead::", 16,
531 [VppRoutePath("::",
532 sw_if_index,
Neale Ranns097fa662018-05-01 05:17:55 -0700533 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
Ole Troan298c6952018-03-08 12:30:43 +0100534 ip6_via_tunnel.add_vpp_config()
535
Ole Troan282093f2018-09-19 12:38:51 +0200536 self.tunnel_ip6_via_tunnel = ip6_via_tunnel
537 self.tunnel_ip4_via_tunnel = ip4_via_tunnel
Ole Troan298c6952018-03-08 12:30:43 +0100538
Ole Troan282093f2018-09-19 12:38:51 +0200539 def destroy_tunnel(self):
540 # IPv6 transport
541 self.tunnel_ip4_via_tunnel.remove_vpp_config()
542 self.tunnel_ip6_via_tunnel.remove_vpp_config()
543
544 rv = self.vapi.ipip_del_tunnel(sw_if_index=self.tunnel_if_index)
545
546 def validate(self, rx, expected):
Ole Troan7f991832018-12-06 17:35:12 +0100547 self.assertEqual(rx, expected.__class__(expected))
Ole Troan282093f2018-09-19 12:38:51 +0200548
549 def generate_ip6_frags(self, payload_length, fragment_size):
550 p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
551 p_payload = UDP(sport=1234, dport=1234) / self.payload(payload_length)
552 p_ip6 = IPv6(src="1::1", dst=self.pg0.remote_ip6)
553 outer_ip6 = (p_ether / IPv6(src=self.pg1.remote_ip6,
554 dst=self.pg0.local_ip6) /
555 IPv6ExtHdrFragment() / p_ip6 / p_payload)
556 frags = fragment6(outer_ip6, fragment_size)
557 p6_reply = (p_ip6 / p_payload)
558 p6_reply.hlim -= 1
559 return frags, p6_reply
560
561 def generate_ip6_hairpin_frags(self, payload_length, fragment_size):
562 p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
563 p_payload = UDP(sport=1234, dport=1234) / self.payload(payload_length)
564 p_ip6 = IPv6(src="1::1", dst="dead::1")
565 outer_ip6 = (p_ether / IPv6(src=self.pg1.remote_ip6,
566 dst=self.pg0.local_ip6) /
567 IPv6ExtHdrFragment() / p_ip6 / p_payload)
568 frags = fragment6(outer_ip6, fragment_size)
569 p_ip6.hlim -= 1
570 p6_reply = (IPv6(src=self.pg0.local_ip6, dst=self.pg1.remote_ip6,
571 hlim=63) / p_ip6 / p_payload)
572
573 return frags, p6_reply
574
575 def test_encap(self):
576 """ ip{v4,v6} over ip6 test encap """
577 p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
578 p_ip6 = IPv6(src="1::1", dst="DEAD::1", tc=42, nh='UDP')
579 p_ip4 = IP(src="1.2.3.4", dst="130.67.0.1", tos=42)
580 p_payload = UDP(sport=1234, dport=1234)
581
582 # Encapsulation
Ole Troan298c6952018-03-08 12:30:43 +0100583 # IPv6 in to IPv6 tunnel
584 p6 = (p_ether / p_ip6 / p_payload)
Ole Troand57f6362018-05-24 13:21:43 +0200585 p6_reply = (IPv6(src=self.pg0.local_ip6, dst=self.pg1.remote_ip6,
Neale Ranns95346962019-11-25 13:04:44 +0000586 hlim=64) /
Ole Troand57f6362018-05-24 13:21:43 +0200587 p_ip6 / p_payload)
Ole Troan298c6952018-03-08 12:30:43 +0100588 p6_reply[1].hlim -= 1
Ole Troan9a475372019-03-05 16:58:24 +0100589 rx = self.send_and_expect(self.pg0, p6 * 11, self.pg1)
Ole Troan298c6952018-03-08 12:30:43 +0100590 for p in rx:
591 self.validate(p[1], p6_reply)
592
593 # IPv4 in to IPv6 tunnel
594 p4 = (p_ether / p_ip4 / p_payload)
595 p4_reply = (IPv6(src=self.pg0.local_ip6,
Neale Ranns95346962019-11-25 13:04:44 +0000596 dst=self.pg1.remote_ip6, hlim=64) /
Ole Troand57f6362018-05-24 13:21:43 +0200597 p_ip4 / p_payload)
Ole Troan298c6952018-03-08 12:30:43 +0100598 p4_reply[1].ttl -= 1
Ole Troan9a475372019-03-05 16:58:24 +0100599 rx = self.send_and_expect(self.pg0, p4 * 11, self.pg1)
Ole Troan298c6952018-03-08 12:30:43 +0100600 for p in rx:
601 self.validate(p[1], p4_reply)
602
Ole Troan282093f2018-09-19 12:38:51 +0200603 def test_decap(self):
604 """ ip{v4,v6} over ip6 test decap """
Ole Troan298c6952018-03-08 12:30:43 +0100605
606 p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
Ole Troan282093f2018-09-19 12:38:51 +0200607 p_ip6 = IPv6(src="1::1", dst="DEAD::1", tc=42, nh='UDP')
Ole Troan298c6952018-03-08 12:30:43 +0100608 p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
Ole Troan282093f2018-09-19 12:38:51 +0200609 p_payload = UDP(sport=1234, dport=1234)
610
611 # Decapsulation
612 # IPv6 tunnel to IPv4
613
Ole Troan298c6952018-03-08 12:30:43 +0100614 p4 = (p_ether / IPv6(src=self.pg1.remote_ip6,
615 dst=self.pg0.local_ip6) / p_ip4 / p_payload)
616 p4_reply = (p_ip4 / p_payload)
617 p4_reply.ttl -= 1
Ole Troan9a475372019-03-05 16:58:24 +0100618 rx = self.send_and_expect(self.pg1, p4 * 11, self.pg0)
Ole Troan298c6952018-03-08 12:30:43 +0100619 for p in rx:
620 self.validate(p[1], p4_reply)
621
622 # IPv6 tunnel to IPv6
623 p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
624 p6 = (p_ether / IPv6(src=self.pg1.remote_ip6,
625 dst=self.pg0.local_ip6) / p_ip6 / p_payload)
626 p6_reply = (p_ip6 / p_payload)
627 p6_reply.hlim = 63
Ole Troan9a475372019-03-05 16:58:24 +0100628 rx = self.send_and_expect(self.pg1, p6 * 11, self.pg0)
Ole Troan298c6952018-03-08 12:30:43 +0100629 for p in rx:
630 self.validate(p[1], p6_reply)
631
Neale Ranns95346962019-11-25 13:04:44 +0000632 def verify_ip4ip6_encaps(self, a, p_ip4s, p_ip6_encaps):
633 for i, p_ip4 in enumerate(p_ip4s):
634 p_ip4.dst = a
635 p4 = (self.p_ether / p_ip4 / self.p_payload)
636 p_ip4_inner = p_ip4
637 p_ip4_inner.ttl -= 1
638 p6_reply = (p_ip6_encaps[i] / p_ip4_inner / self.p_payload)
639 rx = self.send_and_expect(self.pg0, p4 * N_PACKETS, self.pg1)
640 for p in rx:
641 self.validate(p[1], p6_reply)
642 self.assert_packet_checksums_valid(p)
643
644 def verify_ip6ip6_encaps(self, a, p_ip6s, p_ip6_encaps):
645 for i, p_ip6 in enumerate(p_ip6s):
646 p_ip6.dst = a
647 p6 = (self.p_ether / p_ip6 / self.p_payload)
648 p_inner_ip6 = p_ip6
649 p_inner_ip6.hlim -= 1
650 p6_reply = (p_ip6_encaps[i] / p_inner_ip6 / self.p_payload)
651 rx = self.send_and_expect(self.pg0, p6 * N_PACKETS, self.pg1)
652 for p in rx:
653 self.validate(p[1], p6_reply)
654 self.assert_packet_checksums_valid(p)
655
656 def test_ipip6(self):
657 """ ip{v4,v6} over ip6 test """
658
659 # that's annoying
660 self.destroy_tunnel()
661
662 self.pg1.generate_remote_hosts(5)
663 self.pg1.configure_ipv6_neighbors()
Neale Ranns59ff9182019-12-29 23:55:18 +0000664 e = VppEnum.vl_api_tunnel_encap_decap_flags_t
Neale Ranns95346962019-11-25 13:04:44 +0000665 d = VppEnum.vl_api_ip_dscp_t
666 self.p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
667 self.p_payload = UDP(sport=1234, dport=1234) / Raw(b'X' * 100)
668
669 # create a TOS byte by shifting a DSCP code point 2 bits. those 2 bits
670 # are for the ECN.
671 dscp = d.IP_API_DSCP_AF31 << 2
672 ecn = 3
673 dscp_ecn = d.IP_API_DSCP_AF31 << 2 | ecn
674
675 # IPv4 transport that copies the DCSP from the payload
676 tun_dscp = VppIpIpTunInterface(
677 self,
678 self.pg0,
679 self.pg0.local_ip6,
680 self.pg1.remote_hosts[0].ip6,
Neale Ranns59ff9182019-12-29 23:55:18 +0000681 flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP)
682 tun_dscp.add_vpp_config()
Neale Ranns95346962019-11-25 13:04:44 +0000683 # IPv4 transport that copies the DCSP and ECN from the payload
684 tun_dscp_ecn = VppIpIpTunInterface(
685 self,
686 self.pg0,
687 self.pg0.local_ip6,
688 self.pg1.remote_hosts[1].ip6,
Neale Ranns59ff9182019-12-29 23:55:18 +0000689 flags=(e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP |
690 e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN))
691 tun_dscp_ecn.add_vpp_config()
Neale Ranns95346962019-11-25 13:04:44 +0000692 # IPv4 transport that copies the ECN from the payload and sets the
693 # DF bit on encap. copies the ECN on decap
694 tun_ecn = VppIpIpTunInterface(
695 self,
696 self.pg0,
697 self.pg0.local_ip6,
698 self.pg1.remote_hosts[2].ip6,
Neale Ranns59ff9182019-12-29 23:55:18 +0000699 flags=(e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN |
700 e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_SET_DF |
701 e.TUNNEL_API_ENCAP_DECAP_FLAG_DECAP_COPY_ECN))
702 tun_ecn.add_vpp_config()
Neale Ranns95346962019-11-25 13:04:44 +0000703 # IPv4 transport that sets a fixed DSCP in the encap and copies
704 # the DF bit
705 tun = VppIpIpTunInterface(
706 self,
707 self.pg0,
708 self.pg0.local_ip6,
709 self.pg1.remote_hosts[3].ip6,
710 dscp=d.IP_API_DSCP_AF11,
Neale Ranns59ff9182019-12-29 23:55:18 +0000711 flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DF)
712 tun.add_vpp_config()
Neale Ranns95346962019-11-25 13:04:44 +0000713
714 # array of all the tunnels
715 tuns = [tun_dscp, tun_dscp_ecn, tun_ecn, tun]
716
717 # addresses for prefixes routed via each tunnel
718 a4s = ["" for i in range(len(tuns))]
719 a6s = ["" for i in range(len(tuns))]
720
721 # IP headers for inner packets with each combination of DSCp/ECN tested
722 p_ip6s = [IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=dscp),
723 IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=dscp_ecn),
724 IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=ecn),
725 IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=0xff)]
726 p_ip4s = [IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp, flags='DF'),
727 IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp_ecn),
728 IP(src="1.2.3.4", dst="130.67.0.1", tos=ecn),
729 IP(src="1.2.3.4", dst="130.67.0.1", tos=0xff)]
730
731 # Configure each tunnel
732 for i, t in enumerate(tuns):
733 # Set interface up and enable IP on it
734 self.vapi.sw_interface_set_flags(t.sw_if_index, 1)
735 self.vapi.sw_interface_set_unnumbered(
736 sw_if_index=self.pg0.sw_if_index,
737 unnumbered_sw_if_index=t.sw_if_index)
738
739 # prefix for route / destination address for packets
740 a4s[i] = "130.67.%d.0" % i
741 a6s[i] = "dead:%d::" % i
742
743 # Add IPv4 and IPv6 routes via tunnel interface
744 ip4_via_tunnel = VppIpRoute(
745 self, a4s[i], 24,
746 [VppRoutePath("0.0.0.0",
747 t.sw_if_index,
748 proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)])
749 ip4_via_tunnel.add_vpp_config()
750
751 ip6_via_tunnel = VppIpRoute(
752 self, a6s[i], 64,
753 [VppRoutePath("::",
754 t.sw_if_index,
755 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
756 ip6_via_tunnel.add_vpp_config()
757
758 #
759 # Encapsulation
760 #
761
762 # tun_dscp copies only the dscp
763 # expected TC values are thus only the DCSP value is present from the
764 # inner
765 exp_tcs = [dscp, dscp, 0, 0xfc]
766 p_ip6_encaps = [IPv6(src=self.pg0.local_ip6,
767 dst=tun_dscp.dst,
768 tc=tc) for tc in exp_tcs]
769
770 # IPv4 in to IPv4 tunnel
771 self.verify_ip4ip6_encaps(a4s[0], p_ip4s, p_ip6_encaps)
772 # IPv6 in to IPv4 tunnel
773 self.verify_ip6ip6_encaps(a6s[0], p_ip6s, p_ip6_encaps)
774
775 # tun_dscp_ecn copies the dscp and the ecn
776 exp_tcs = [dscp, dscp_ecn, ecn, 0xff]
777 p_ip6_encaps = [IPv6(src=self.pg0.local_ip6,
778 dst=tun_dscp_ecn.dst,
779 tc=tc) for tc in exp_tcs]
780
781 self.verify_ip4ip6_encaps(a4s[1], p_ip4s, p_ip6_encaps)
782 self.verify_ip6ip6_encaps(a6s[1], p_ip6s, p_ip6_encaps)
783
784 # tun_ecn copies only the ecn and always sets DF
785 exp_tcs = [0, ecn, ecn, ecn]
786 p_ip6_encaps = [IPv6(src=self.pg0.local_ip6,
787 dst=tun_ecn.dst,
788 tc=tc) for tc in exp_tcs]
789
790 self.verify_ip4ip6_encaps(a4s[2], p_ip4s, p_ip6_encaps)
791 self.verify_ip6ip6_encaps(a6s[2], p_ip6s, p_ip6_encaps)
792
793 # tun sets a fixed dscp
794 fixed_dscp = tun.dscp << 2
795 p_ip6_encaps = [IPv6(src=self.pg0.local_ip6,
796 dst=tun.dst,
797 tc=fixed_dscp) for i in range(len(p_ip4s))]
798
799 self.verify_ip4ip6_encaps(a4s[3], p_ip4s, p_ip6_encaps)
800 self.verify_ip6ip6_encaps(a6s[3], p_ip6s, p_ip6_encaps)
801
802 #
803 # Decapsulation
804 #
805 n_packets_decapped = self.statistics.get_err_counter(
806 '/err/ipip6-input/packets decapsulated')
807
808 self.p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
809
810 # IPv6 tunnel to IPv4
811 tcs = [0, dscp, dscp_ecn, ecn]
812
813 # one overlay packet and all combinations of its encap
814 p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
815 p_ip6_encaps = [IPv6(src=tun.dst,
816 dst=self.pg0.local_ip6,
817 tc=tc) for tc in tcs]
818
819 # for each encap tun will produce the same inner packet because it does
820 # not copy up fields from the payload
821 for p_ip6_encap in p_ip6_encaps:
822 p6 = (self.p_ether / p_ip6_encap / p_ip4 / self.p_payload)
823 p4_reply = (p_ip4 / self.p_payload)
824 p4_reply.ttl -= 1
825 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
826 n_packets_decapped += N_PACKETS
827 for p in rx:
828 self.validate(p[1], p4_reply)
829 self.assert_packet_checksums_valid(p)
830
831 err = self.statistics.get_err_counter(
832 '/err/ipip6-input/packets decapsulated')
833 self.assertEqual(err, n_packets_decapped)
834
835 # tun_ecn copies the ECN bits from the encap to the inner
836 p_ip6_encaps = [IPv6(src=tun_ecn.dst,
837 dst=self.pg0.local_ip6,
838 tc=tc) for tc in tcs]
839 p_ip4_replys = [p_ip4.copy() for i in range(len(p_ip6_encaps))]
840 p_ip4_replys[2].tos = ecn
841 p_ip4_replys[3].tos = ecn
842 for i, p_ip6_encap in enumerate(p_ip6_encaps):
843 p6 = (self.p_ether / p_ip6_encap / p_ip4 / self.p_payload)
844 p4_reply = (p_ip4_replys[i] / self.p_payload)
845 p4_reply.ttl -= 1
846 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
847 n_packets_decapped += N_PACKETS
848 for p in rx:
849 self.validate(p[1], p4_reply)
850 self.assert_packet_checksums_valid(p)
851
852 err = self.statistics.get_err_counter(
853 '/err/ipip6-input/packets decapsulated')
854 self.assertEqual(err, n_packets_decapped)
855
856 # IPv6 tunnel to IPv6
857 # for each encap tun will produce the same inner packet because it does
858 # not copy up fields from the payload
859 p_ip6_encaps = [IPv6(src=tun.dst,
860 dst=self.pg0.local_ip6,
861 tc=tc) for tc in tcs]
862 p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
863 for p_ip6_encap in p_ip6_encaps:
864 p6 = (self.p_ether / p_ip6_encap / p_ip6 / self.p_payload)
865 p6_reply = (p_ip6 / self.p_payload)
866 p6_reply.hlim = 63
867 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
868 n_packets_decapped += N_PACKETS
869 for p in rx:
870 self.validate(p[1], p6_reply)
871 self.assert_packet_checksums_valid(p)
872
873 err = self.statistics.get_err_counter(
874 '/err/ipip6-input/packets decapsulated')
875 self.assertEqual(err, n_packets_decapped)
876
877 # IPv6 tunnel to IPv6
878 # tun_ecn copies the ECN bits from the encap to the inner
879 p_ip6_encaps = [IPv6(src=tun_ecn.dst,
880 dst=self.pg0.local_ip6,
881 tc=tc) for tc in tcs]
882 p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
883 p_ip6_replys = [p_ip6.copy() for i in range(len(p_ip6_encaps))]
884 p_ip6_replys[2].tc = ecn
885 p_ip6_replys[3].tc = ecn
886 for i, p_ip6_encap in enumerate(p_ip6_encaps):
887 p6 = (self.p_ether / p_ip6_encap / p_ip6 / self.p_payload)
888 p6_reply = (p_ip6_replys[i] / self.p_payload)
889 p6_reply.hlim = 63
890 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
891 n_packets_decapped += N_PACKETS
892 for p in rx:
893 self.validate(p[1], p6_reply)
894 self.assert_packet_checksums_valid(p)
895
896 err = self.statistics.get_err_counter(
897 '/err/ipip6-input/packets decapsulated')
898 self.assertEqual(err, n_packets_decapped)
899
Ole Troan282093f2018-09-19 12:38:51 +0200900 def test_frag(self):
901 """ ip{v4,v6} over ip6 test frag """
902
903 p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
904 p_ip6 = IPv6(src="1::1", dst="DEAD::1", tc=42, nh='UDP')
905 p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
906 p_payload = UDP(sport=1234, dport=1234)
907
908 #
909 # Fragmentation / Reassembly and Re-fragmentation
910 #
911 rv = self.vapi.ip_reassembly_enable_disable(
912 sw_if_index=self.pg1.sw_if_index,
913 enable_ip6=1)
914
Klement Sekera3a343d42019-05-16 14:35:46 +0200915 self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=1000,
916 max_reassembly_length=1000,
917 expire_walk_interval_ms=10000,
918 is_ip6=1)
919
Ole Troan282093f2018-09-19 12:38:51 +0200920 # Send lots of fragments, verify reassembled packet
Ole Troan233e4682019-05-16 15:01:34 +0200921 before_cnt = self.statistics.get_err_counter(
Ole Troan282093f2018-09-19 12:38:51 +0200922 '/err/ipip6-input/packets decapsulated')
923 frags, p6_reply = self.generate_ip6_frags(3131, 1400)
924 f = []
925 for i in range(0, 1000):
926 f.extend(frags)
927 self.pg1.add_stream(f)
928 self.pg_enable_capture()
929 self.pg_start()
930 rx = self.pg0.get_capture(1000)
931
932 for p in rx:
933 self.validate(p[1], p6_reply)
934
Ole Troan233e4682019-05-16 15:01:34 +0200935 cnt = self.statistics.get_err_counter(
Ole Troan282093f2018-09-19 12:38:51 +0200936 '/err/ipip6-input/packets decapsulated')
937 self.assertEqual(cnt, before_cnt + 1000)
938
939 f = []
940 r = []
941 # TODO: Check out why reassembly of atomic fragments don't work
942 for i in range(10, 90):
943 frags, p6_reply = self.generate_ip6_frags(i * 100, 1000)
944 f.extend(frags)
945 r.extend(p6_reply)
946 self.pg_enable_capture()
947 self.pg1.add_stream(f)
948 self.pg_start()
949 rx = self.pg0.get_capture(80)
950 i = 0
951 for p in rx:
952 self.validate(p[1], r[i])
953 i += 1
954
955 # Simple fragmentation
956 p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
957 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1280, 0, 0, 0])
958
959 # IPv6 in to IPv6 tunnel
960 p_payload = UDP(sport=1234, dport=1234) / self.payload(1300)
961
962 p6 = (p_ether / p_ip6 / p_payload)
963 p6_reply = (IPv6(src=self.pg0.local_ip6, dst=self.pg1.remote_ip6,
Neale Ranns95346962019-11-25 13:04:44 +0000964 hlim=63) /
Ole Troan282093f2018-09-19 12:38:51 +0200965 p_ip6 / p_payload)
966 p6_reply[1].hlim -= 1
967 self.pg_enable_capture()
968 self.pg0.add_stream(p6)
969 self.pg_start()
970 rx = self.pg1.get_capture(2)
971
972 # Scapy defragment doesn't deal well with multiple layers
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700973 # of same type / Ethernet header first
Ole Troan282093f2018-09-19 12:38:51 +0200974 f = [p[1] for p in rx]
975 reass_pkt = defragment6(f)
976 self.validate(reass_pkt, p6_reply)
977
978 # Now try with re-fragmentation
979 #
980 # Send large fragments to tunnel head-end, for the tunnel head end
981 # to reassemble and then refragment out the tunnel again.
982 # Hair-pinning
983 #
984 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1280, 0, 0, 0])
985 frags, p6_reply = self.generate_ip6_hairpin_frags(8000, 1200)
986 self.pg_enable_capture()
987 self.pg1.add_stream(frags)
988 self.pg_start()
989 rx = self.pg1.get_capture(7)
990 f = [p[1] for p in rx]
991 reass_pkt = defragment6(f)
992 p6_reply.id = 256
993 self.validate(reass_pkt, p6_reply)
994
Ole Troan298c6952018-03-08 12:30:43 +0100995 def test_ipip_create(self):
996 """ ipip create / delete interface test """
Neale Rannscbd08242019-05-26 11:34:27 -0700997 rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5')
Ole Troan298c6952018-03-08 12:30:43 +0100998 sw_if_index = rv.sw_if_index
Ole Troan46c1c112018-03-14 20:39:40 +0100999 self.vapi.ipip_del_tunnel(sw_if_index)
Ole Troan298c6952018-03-08 12:30:43 +01001000
Neale Ranns61502112018-08-22 00:21:14 -07001001 def test_ipip_vrf_create(self):
1002 """ ipip create / delete interface VRF test """
1003
1004 t = VppIpTable(self, 20)
1005 t.add_vpp_config()
Neale Rannscbd08242019-05-26 11:34:27 -07001006 rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5', table_id=20)
Neale Ranns61502112018-08-22 00:21:14 -07001007 sw_if_index = rv.sw_if_index
1008 self.vapi.ipip_del_tunnel(sw_if_index)
1009
Ole Troan4146c652018-08-08 22:23:19 +02001010 def payload(self, len):
1011 return 'x' * len
1012
Ole Troan298c6952018-03-08 12:30:43 +01001013
1014if __name__ == '__main__':
1015 unittest.main(testRunner=VppTestRunner)