ipsec: IPSec protection for multi-point tunnel interfaces
[vpp.git] / test / test_ipip.py
1 #!/usr/bin/env python3
2 """IP{4,6} over IP{v,6} tunnel functional tests"""
3
4 import unittest
5 from scapy.layers.inet6 import IPv6, Ether, IP, UDP, IPv6ExtHdrFragment, Raw
6 from scapy.all import fragment, fragment6, RandShort, defragment6
7 from framework import VppTestCase, VppTestRunner
8 from vpp_ip import DpoProto
9 from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpTable, FibPathProto
10 from vpp_ipip_tun_interface import VppIpIpTunInterface
11 from vpp_teib import VppTeib
12 from vpp_papi import VppEnum
13 from socket import AF_INET, AF_INET6, inet_pton
14 from util import reassemble4
15
16 """ Testipip is a subclass of  VPPTestCase classes.
17
18 IPIP tests.
19
20 """
21
22
23 def ipip_add_tunnel(test, src, dst, table_id=0, dscp=0x0,
24                     flags=0):
25     """ Add a IPIP tunnel """
26     return test.vapi.ipip_add_tunnel(
27         tunnel={
28             'src': src,
29             'dst': dst,
30             'table_id': table_id,
31             'instance': 0xffffffff,
32             'dscp': dscp,
33             'flags': flags
34         }
35     )
36
37 # the number of packets to send when injecting traffic.
38 # a multiple of 8 minus one, so we test all by 8/4/2/1 loops
39 N_PACKETS = 64 - 1
40
41
42 class TestIPIP(VppTestCase):
43     """ IPIP Test Case """
44
45     @classmethod
46     def setUpClass(cls):
47         super(TestIPIP, cls).setUpClass()
48         cls.create_pg_interfaces(range(2))
49         cls.interfaces = list(cls.pg_interfaces)
50
51     @classmethod
52     def tearDownClass(cls):
53         super(TestIPIP, cls).tearDownClass()
54
55     def setUp(self):
56         super(TestIPIP, self).setUp()
57         for i in self.interfaces:
58             i.admin_up()
59             i.config_ip4()
60             i.config_ip6()
61             i.disable_ipv6_ra()
62             i.resolve_arp()
63             i.resolve_ndp()
64
65     def tearDown(self):
66         super(TestIPIP, self).tearDown()
67         if not self.vpp_dead:
68             for i in self.pg_interfaces:
69                 i.unconfig_ip4()
70                 i.unconfig_ip6()
71                 i.admin_down()
72
73     def validate(self, rx, expected):
74         self.assertEqual(rx, expected.__class__(expected))
75
76     def generate_ip4_frags(self, payload_length, fragment_size):
77         p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
78         p_payload = UDP(sport=1234, dport=1234) / self.payload(payload_length)
79         p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
80         outer_ip4 = (p_ether / IP(src=self.pg1.remote_ip4,
81                                   id=RandShort(),
82                                   dst=self.pg0.local_ip4) / p_ip4 / p_payload)
83         frags = fragment(outer_ip4, fragment_size)
84         p4_reply = (p_ip4 / p_payload)
85         p4_reply.ttl -= 1
86         return frags, p4_reply
87
88     def verify_ip4ip4_encaps(self, a, p_ip4s, p_ip4_encaps):
89         for i, p_ip4 in enumerate(p_ip4s):
90             p_ip4.dst = a
91             p4 = (self.p_ether / p_ip4 / self.p_payload)
92             p_ip4_inner = p_ip4
93             p_ip4_inner.ttl -= 1
94             p4_reply = (p_ip4_encaps[i] / p_ip4_inner / self.p_payload)
95             p4_reply.ttl -= 1
96             p4_reply.id = 0
97             rx = self.send_and_expect(self.pg0, p4 * N_PACKETS, self.pg1)
98             for p in rx:
99                 self.validate(p[1], p4_reply)
100                 self.assert_packet_checksums_valid(p)
101
102     def verify_ip6ip4_encaps(self, a, p_ip6s, p_ip4_encaps):
103         for i, p_ip6 in enumerate(p_ip6s):
104             p_ip6.dst = a
105             p6 = (self.p_ether / p_ip6 / self.p_payload)
106             p_inner_ip6 = p_ip6
107             p_inner_ip6.hlim -= 1
108             p6_reply = (p_ip4_encaps[i] / p_inner_ip6 / self.p_payload)
109             p6_reply.ttl -= 1
110             rx = self.send_and_expect(self.pg0, p6 * N_PACKETS, self.pg1)
111             for p in rx:
112                 self.validate(p[1], p6_reply)
113                 self.assert_packet_checksums_valid(p)
114
115     def test_ipip4(self):
116         """ ip{v4,v6} over ip4 test """
117
118         self.pg1.generate_remote_hosts(5)
119         self.pg1.configure_ipv4_neighbors()
120         e = VppEnum.vl_api_tunnel_encap_decap_flags_t
121         d = VppEnum.vl_api_ip_dscp_t
122         self.p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
123         self.p_payload = UDP(sport=1234, dport=1234) / Raw(b'X' * 100)
124
125         # create a TOS byte by shifting a DSCP code point 2 bits. those 2 bits
126         # are for the ECN.
127         dscp = d.IP_API_DSCP_AF31 << 2
128         ecn = 3
129         dscp_ecn = d.IP_API_DSCP_AF31 << 2 | ecn
130
131         # IPv4 transport that copies the DCSP from the payload
132         tun_dscp = VppIpIpTunInterface(
133             self,
134             self.pg0,
135             self.pg0.local_ip4,
136             self.pg1.remote_hosts[0].ip4,
137             flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP)
138         tun_dscp.add_vpp_config()
139         # IPv4 transport that copies the DCSP and ECN from the payload
140         tun_dscp_ecn = VppIpIpTunInterface(
141             self,
142             self.pg0,
143             self.pg0.local_ip4,
144             self.pg1.remote_hosts[1].ip4,
145             flags=(e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP |
146                    e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN))
147         tun_dscp_ecn.add_vpp_config()
148         # IPv4 transport that copies the ECN from the payload and sets the
149         # DF bit on encap. copies the ECN on decap
150         tun_ecn = VppIpIpTunInterface(
151             self,
152             self.pg0,
153             self.pg0.local_ip4,
154             self.pg1.remote_hosts[2].ip4,
155             flags=(e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN |
156                    e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_SET_DF |
157                    e.TUNNEL_API_ENCAP_DECAP_FLAG_DECAP_COPY_ECN))
158         tun_ecn.add_vpp_config()
159         # IPv4 transport that sets a fixed DSCP in the encap and copies
160         # the DF bit
161         tun = VppIpIpTunInterface(
162             self,
163             self.pg0,
164             self.pg0.local_ip4,
165             self.pg1.remote_hosts[3].ip4,
166             dscp=d.IP_API_DSCP_AF11,
167             flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DF)
168         tun.add_vpp_config()
169
170         # array of all the tunnels
171         tuns = [tun_dscp, tun_dscp_ecn, tun_ecn, tun]
172
173         # addresses for prefixes routed via each tunnel
174         a4s = ["" for i in range(len(tuns))]
175         a6s = ["" for i in range(len(tuns))]
176
177         # IP headers with each combination of DSCp/ECN tested
178         p_ip6s = [IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=dscp),
179                   IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=dscp_ecn),
180                   IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=ecn),
181                   IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=0xff)]
182         p_ip4s = [IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp, flags='DF'),
183                   IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp_ecn),
184                   IP(src="1.2.3.4", dst="130.67.0.1", tos=ecn),
185                   IP(src="1.2.3.4", dst="130.67.0.1", tos=0xff)]
186
187         # Configure each tunnel
188         for i, t in enumerate(tuns):
189             # Set interface up and enable IP on it
190             self.vapi.sw_interface_set_flags(t.sw_if_index, 1)
191             self.vapi.sw_interface_set_unnumbered(
192                 sw_if_index=self.pg0.sw_if_index,
193                 unnumbered_sw_if_index=t.sw_if_index)
194
195             # prefix for route / destination address for packets
196             a4s[i] = "130.67.%d.0" % i
197             a6s[i] = "dead:%d::" % i
198
199             # Add IPv4 and IPv6 routes via tunnel interface
200             ip4_via_tunnel = VppIpRoute(
201                 self, a4s[i], 24,
202                 [VppRoutePath("0.0.0.0",
203                               t.sw_if_index,
204                               proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)])
205             ip4_via_tunnel.add_vpp_config()
206
207             ip6_via_tunnel = VppIpRoute(
208                 self, a6s[i], 64,
209                 [VppRoutePath("::",
210                               t.sw_if_index,
211                               proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
212             ip6_via_tunnel.add_vpp_config()
213
214         #
215         # Encapsulation
216         #
217
218         # tun_dscp copies only the dscp
219         # expected TC values are thus only the DCSP value is present from the
220         # inner
221         exp_tcs = [dscp, dscp, 0, 0xfc]
222         p_ip44_encaps = [IP(src=self.pg0.local_ip4,
223                             dst=tun_dscp.dst,
224                             tos=tc) for tc in exp_tcs]
225         p_ip64_encaps = [IP(src=self.pg0.local_ip4,
226                             dst=tun_dscp.dst,
227                             proto='ipv6', id=0, tos=tc) for tc in exp_tcs]
228
229         # IPv4 in to IPv4 tunnel
230         self.verify_ip4ip4_encaps(a4s[0], p_ip4s, p_ip44_encaps)
231         # IPv6 in to IPv4 tunnel
232         self.verify_ip6ip4_encaps(a6s[0], p_ip6s, p_ip64_encaps)
233
234         # tun_dscp_ecn copies the dscp and the ecn
235         exp_tcs = [dscp, dscp_ecn, ecn, 0xff]
236         p_ip44_encaps = [IP(src=self.pg0.local_ip4,
237                             dst=tun_dscp_ecn.dst,
238                             tos=tc) for tc in exp_tcs]
239         p_ip64_encaps = [IP(src=self.pg0.local_ip4,
240                             dst=tun_dscp_ecn.dst,
241                             proto='ipv6', id=0, tos=tc) for tc in exp_tcs]
242
243         self.verify_ip4ip4_encaps(a4s[1], p_ip4s, p_ip44_encaps)
244         self.verify_ip6ip4_encaps(a6s[1], p_ip6s, p_ip64_encaps)
245
246         # tun_ecn copies only the ecn and always sets DF
247         exp_tcs = [0, ecn, ecn, ecn]
248         p_ip44_encaps = [IP(src=self.pg0.local_ip4,
249                             dst=tun_ecn.dst,
250                             flags='DF', tos=tc) for tc in exp_tcs]
251         p_ip64_encaps = [IP(src=self.pg0.local_ip4,
252                             dst=tun_ecn.dst,
253                             flags='DF', proto='ipv6', id=0, tos=tc)
254                          for tc in exp_tcs]
255
256         self.verify_ip4ip4_encaps(a4s[2], p_ip4s, p_ip44_encaps)
257         self.verify_ip6ip4_encaps(a6s[2], p_ip6s, p_ip64_encaps)
258
259         # tun sets a fixed dscp and copies DF
260         fixed_dscp = tun.dscp << 2
261         flags = ['DF', 0, 0, 0]
262         p_ip44_encaps = [IP(src=self.pg0.local_ip4,
263                             dst=tun.dst,
264                             flags=f,
265                             tos=fixed_dscp) for f in flags]
266         p_ip64_encaps = [IP(src=self.pg0.local_ip4,
267                             dst=tun.dst,
268                             proto='ipv6', id=0,
269                             tos=fixed_dscp) for i in range(len(p_ip4s))]
270
271         self.verify_ip4ip4_encaps(a4s[3], p_ip4s, p_ip44_encaps)
272         self.verify_ip6ip4_encaps(a6s[3], p_ip6s, p_ip64_encaps)
273
274         #
275         # Decapsulation
276         #
277         n_packets_decapped = 0
278         self.p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
279
280         # IPv4 tunnel to IPv4
281         tcs = [0, dscp, dscp_ecn, ecn]
282
283         # one overlay packet and all combinations of its encap
284         p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
285         p_ip4_encaps = [IP(src=tun.dst,
286                            dst=self.pg0.local_ip4,
287                            tos=tc) for tc in tcs]
288
289         # for each encap tun will produce the same inner packet because it does
290         # not copy up fields from the payload
291         for p_ip4_encap in p_ip4_encaps:
292             p4 = (self.p_ether / p_ip4_encap / p_ip4 / self.p_payload)
293             p4_reply = (p_ip4 / self.p_payload)
294             p4_reply.ttl -= 1
295             rx = self.send_and_expect(self.pg1, p4 * N_PACKETS, self.pg0)
296             n_packets_decapped += N_PACKETS
297             for p in rx:
298                 self.validate(p[1], p4_reply)
299                 self.assert_packet_checksums_valid(p)
300
301         err = self.statistics.get_err_counter(
302             '/err/ipip4-input/packets decapsulated')
303         self.assertEqual(err, n_packets_decapped)
304
305         # tun_ecn copies the ECN bits from the encap to the inner
306         p_ip4_encaps = [IP(src=tun_ecn.dst,
307                            dst=self.pg0.local_ip4,
308                            tos=tc) for tc in tcs]
309         p_ip4_replys = [p_ip4.copy() for i in range(len(p_ip4_encaps))]
310         p_ip4_replys[2].tos = ecn
311         p_ip4_replys[3].tos = ecn
312         for i, p_ip4_encap in enumerate(p_ip4_encaps):
313             p4 = (self.p_ether / p_ip4_encap / p_ip4 / self.p_payload)
314             p4_reply = (p_ip4_replys[i] / self.p_payload)
315             p4_reply.ttl -= 1
316             rx = self.send_and_expect(self.pg1, p4 * N_PACKETS, self.pg0)
317             n_packets_decapped += N_PACKETS
318             for p in rx:
319                 self.validate(p[1], p4_reply)
320                 self.assert_packet_checksums_valid(p)
321
322         err = self.statistics.get_err_counter(
323             '/err/ipip4-input/packets decapsulated')
324         self.assertEqual(err, n_packets_decapped)
325
326         # IPv4 tunnel to IPv6
327         # for each encap tun will produce the same inner packet because it does
328         # not copy up fields from the payload
329         p_ip4_encaps = [IP(src=tun.dst,
330                            dst=self.pg0.local_ip4,
331                            tos=tc) for tc in tcs]
332         p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
333         for p_ip4_encap in p_ip4_encaps:
334             p6 = (self.p_ether /
335                   p_ip4_encap / p_ip6 /
336                   self.p_payload)
337             p6_reply = (p_ip6 / self.p_payload)
338             p6_reply.hlim = 63
339             rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
340             n_packets_decapped += N_PACKETS
341             for p in rx:
342                 self.validate(p[1], p6_reply)
343                 self.assert_packet_checksums_valid(p)
344
345         err = self.statistics.get_err_counter(
346             '/err/ipip4-input/packets decapsulated')
347         self.assertEqual(err, n_packets_decapped)
348
349         # IPv4 tunnel to IPv6
350         # tun_ecn copies the ECN bits from the encap to the inner
351         p_ip4_encaps = [IP(src=tun_ecn.dst,
352                            dst=self.pg0.local_ip4,
353                            tos=tc) for tc in tcs]
354         p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
355         p_ip6_replys = [p_ip6.copy() for i in range(len(p_ip4_encaps))]
356         p_ip6_replys[2].tc = ecn
357         p_ip6_replys[3].tc = ecn
358         for i, p_ip4_encap in enumerate(p_ip4_encaps):
359             p6 = (self.p_ether / p_ip4_encap / p_ip6 / self.p_payload)
360             p6_reply = (p_ip6_replys[i] / self.p_payload)
361             p6_reply.hlim = 63
362             rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
363             n_packets_decapped += N_PACKETS
364             for p in rx:
365                 self.validate(p[1], p6_reply)
366                 self.assert_packet_checksums_valid(p)
367
368         err = self.statistics.get_err_counter(
369             '/err/ipip4-input/packets decapsulated')
370         self.assertEqual(err, n_packets_decapped)
371
372         #
373         # Fragmentation / Reassembly and Re-fragmentation
374         #
375         rv = self.vapi.ip_reassembly_enable_disable(
376             sw_if_index=self.pg1.sw_if_index,
377             enable_ip4=1)
378
379         self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=1000,
380                                     max_reassembly_length=1000,
381                                     expire_walk_interval_ms=10000,
382                                     is_ip6=0)
383
384         # Send lots of fragments, verify reassembled packet
385         frags, p4_reply = self.generate_ip4_frags(3131, 1400)
386         f = []
387         for i in range(0, 1000):
388             f.extend(frags)
389         self.pg1.add_stream(f)
390         self.pg_enable_capture()
391         self.pg_start()
392         rx = self.pg0.get_capture(1000)
393         n_packets_decapped += 1000
394
395         for p in rx:
396             self.validate(p[1], p4_reply)
397
398         err = self.statistics.get_err_counter(
399             '/err/ipip4-input/packets decapsulated')
400         self.assertEqual(err, n_packets_decapped)
401
402         f = []
403         r = []
404         for i in range(1, 90):
405             frags, p4_reply = self.generate_ip4_frags(i * 100, 1000)
406             f.extend(frags)
407             r.extend(p4_reply)
408         self.pg_enable_capture()
409         self.pg1.add_stream(f)
410         self.pg_start()
411         rx = self.pg0.get_capture(89)
412         i = 0
413         for p in rx:
414             self.validate(p[1], r[i])
415             i += 1
416
417         # Now try with re-fragmentation
418         #
419         # Send fragments to tunnel head-end, for the tunnel head end
420         # to reassemble and then refragment
421         #
422         self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [576, 0, 0, 0])
423         frags, p4_reply = self.generate_ip4_frags(3123, 1200)
424         self.pg_enable_capture()
425         self.pg1.add_stream(frags)
426         self.pg_start()
427         rx = self.pg0.get_capture(6)
428         reass_pkt = reassemble4(rx)
429         p4_reply.id = 256
430         self.validate(reass_pkt, p4_reply)
431
432         self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [1600, 0, 0, 0])
433         frags, p4_reply = self.generate_ip4_frags(3123, 1200)
434         self.pg_enable_capture()
435         self.pg1.add_stream(frags)
436         self.pg_start()
437         rx = self.pg0.get_capture(2)
438         reass_pkt = reassemble4(rx)
439         p4_reply.id = 512
440         self.validate(reass_pkt, p4_reply)
441
442         # send large packets through the tunnel, expect them to be fragmented
443         self.vapi.sw_interface_set_mtu(tun_dscp.sw_if_index, [600, 0, 0, 0])
444
445         p4 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
446               IP(src="1.2.3.4", dst="130.67.0.1", tos=42) /
447               UDP(sport=1234, dport=1234) / Raw(b'Q' * 1000))
448         rx = self.send_and_expect(self.pg0, p4 * 15, self.pg1, 30)
449         inners = []
450         for p in rx:
451             inners.append(p[IP].payload)
452         reass_pkt = reassemble4(inners)
453         for p in reass_pkt:
454             self.assert_packet_checksums_valid(p)
455             self.assertEqual(p[IP].ttl, 63)
456
457     def test_ipip_create(self):
458         """ ipip create / delete interface test """
459         rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5')
460         sw_if_index = rv.sw_if_index
461         self.vapi.ipip_del_tunnel(sw_if_index)
462
463     def test_ipip_vrf_create(self):
464         """ ipip create / delete interface VRF test """
465
466         t = VppIpTable(self, 20)
467         t.add_vpp_config()
468         rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5', table_id=20)
469         sw_if_index = rv.sw_if_index
470         self.vapi.ipip_del_tunnel(sw_if_index)
471
472     def payload(self, len):
473         return 'x' * len
474
475     def test_mipip4(self):
476         """ p2mp IPv4 tunnel Tests """
477
478         for itf in self.pg_interfaces:
479             #
480             # one underlay nh for each overlay/tunnel peer
481             #
482             itf.generate_remote_hosts(4)
483             itf.configure_ipv4_neighbors()
484
485             #
486             # Create an p2mo IPIP tunnel.
487             #  - set it admin up
488             #  - assign an IP Addres
489             #  - Add a route via the tunnel
490             #
491             ipip_if = VppIpIpTunInterface(self, itf,
492                                           itf.local_ip4,
493                                           "0.0.0.0",
494                                           mode=(VppEnum.vl_api_tunnel_mode_t.
495                                                 TUNNEL_API_MODE_MP))
496             ipip_if.add_vpp_config()
497             ipip_if.admin_up()
498             ipip_if.config_ip4()
499             ipip_if.generate_remote_hosts(4)
500
501             self.logger.info(self.vapi.cli("sh adj"))
502             self.logger.info(self.vapi.cli("sh ip fib"))
503
504             #
505             # ensure we don't match to the tunnel if the source address
506             # is all zeros
507             #
508             # tx = self.create_tunnel_stream_4o4(self.pg0,
509             #                                    "0.0.0.0",
510             #                                    itf.local_ip4,
511             #                                    self.pg0.local_ip4,
512             #                                    self.pg0.remote_ip4)
513             # self.send_and_assert_no_replies(self.pg0, tx)
514
515             #
516             # for-each peer
517             #
518             for ii in range(1, 4):
519                 route_addr = "4.4.4.%d" % ii
520
521                 #
522                 # route traffic via the peer
523                 #
524                 route_via_tun = VppIpRoute(
525                     self, route_addr, 32,
526                     [VppRoutePath(ipip_if._remote_hosts[ii].ip4,
527                                   ipip_if.sw_if_index)])
528                 route_via_tun.add_vpp_config()
529
530                 #
531                 # Add a TEIB entry resolves the peer
532                 #
533                 teib = VppTeib(self, ipip_if,
534                                ipip_if._remote_hosts[ii].ip4,
535                                itf._remote_hosts[ii].ip4)
536                 teib.add_vpp_config()
537                 self.logger.info(self.vapi.cli("sh adj nbr ipip0 %s" %
538                                                ipip_if._remote_hosts[ii].ip4))
539
540                 #
541                 # Send a packet stream that is routed into the tunnel
542                 #  - packets are IPIP encapped
543                 #
544                 inner = (IP(dst=route_addr, src="5.5.5.5") /
545                          UDP(sport=1234, dport=1234) /
546                          Raw(b'0x44' * 100))
547                 tx_e = [(Ether(dst=self.pg0.local_mac,
548                                src=self.pg0.remote_mac) /
549                          inner) for x in range(63)]
550
551                 rxs = self.send_and_expect(self.pg0, tx_e, itf)
552
553                 for rx in rxs:
554                     self.assertEqual(rx[IP].src, itf.local_ip4)
555                     self.assertEqual(rx[IP].dst, itf._remote_hosts[ii].ip4)
556
557                 tx_i = [(Ether(dst=self.pg0.local_mac,
558                                src=self.pg0.remote_mac) /
559                          IP(src=itf._remote_hosts[ii].ip4,
560                             dst=itf.local_ip4) /
561                          IP(src=self.pg0.local_ip4, dst=self.pg0.remote_ip4) /
562                          UDP(sport=1234, dport=1234) /
563                          Raw(b'0x44' * 100)) for x in range(63)]
564
565                 self.logger.info(self.vapi.cli("sh ipip tunnel-hash"))
566                 rx = self.send_and_expect(self.pg0, tx_i, self.pg0)
567
568                 #
569                 # delete and re-add the TEIB
570                 #
571                 teib.remove_vpp_config()
572                 self.send_and_assert_no_replies(self.pg0, tx_e)
573                 self.send_and_assert_no_replies(self.pg0, tx_i)
574
575                 teib.add_vpp_config()
576                 rx = self.send_and_expect(self.pg0, tx_e, itf)
577                 for rx in rxs:
578                     self.assertEqual(rx[IP].src, itf.local_ip4)
579                     self.assertEqual(rx[IP].dst, itf._remote_hosts[ii].ip4)
580                 rx = self.send_and_expect(self.pg0, tx_i, self.pg0)
581
582             ipip_if.admin_down()
583             ipip_if.unconfig_ip4()
584
585
586 class TestIPIP6(VppTestCase):
587     """ IPIP6 Test Case """
588
589     @classmethod
590     def setUpClass(cls):
591         super(TestIPIP6, cls).setUpClass()
592         cls.create_pg_interfaces(range(2))
593         cls.interfaces = list(cls.pg_interfaces)
594
595     @classmethod
596     def tearDownClass(cls):
597         super(TestIPIP6, cls).tearDownClass()
598
599     def setUp(self):
600         super(TestIPIP6, self).setUp()
601         for i in self.interfaces:
602             i.admin_up()
603             i.config_ip4()
604             i.config_ip6()
605             i.disable_ipv6_ra()
606             i.resolve_arp()
607             i.resolve_ndp()
608         self.setup_tunnel()
609
610     def tearDown(self):
611         if not self.vpp_dead:
612             self.destroy_tunnel()
613             for i in self.pg_interfaces:
614                 i.unconfig_ip4()
615                 i.unconfig_ip6()
616                 i.admin_down()
617             super(TestIPIP6, self).tearDown()
618
619     def setup_tunnel(self):
620         # IPv6 transport
621         rv = ipip_add_tunnel(self,
622                              self.pg0.local_ip6,
623                              self.pg1.remote_ip6)
624
625         sw_if_index = rv.sw_if_index
626         self.tunnel_if_index = sw_if_index
627         self.vapi.sw_interface_set_flags(sw_if_index, 1)
628         self.vapi.sw_interface_set_unnumbered(
629             sw_if_index=self.pg0.sw_if_index,
630             unnumbered_sw_if_index=sw_if_index)
631
632         # Add IPv4 and IPv6 routes via tunnel interface
633         ip4_via_tunnel = VppIpRoute(
634             self, "130.67.0.0", 16,
635             [VppRoutePath("0.0.0.0",
636                           sw_if_index,
637                           proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)])
638         ip4_via_tunnel.add_vpp_config()
639
640         ip6_via_tunnel = VppIpRoute(
641             self, "dead::", 16,
642             [VppRoutePath("::",
643                           sw_if_index,
644                           proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
645         ip6_via_tunnel.add_vpp_config()
646
647         self.tunnel_ip6_via_tunnel = ip6_via_tunnel
648         self.tunnel_ip4_via_tunnel = ip4_via_tunnel
649
650     def destroy_tunnel(self):
651         # IPv6 transport
652         self.tunnel_ip4_via_tunnel.remove_vpp_config()
653         self.tunnel_ip6_via_tunnel.remove_vpp_config()
654
655         rv = self.vapi.ipip_del_tunnel(sw_if_index=self.tunnel_if_index)
656
657     def validate(self, rx, expected):
658         self.assertEqual(rx, expected.__class__(expected))
659
660     def generate_ip6_frags(self, payload_length, fragment_size):
661         p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
662         p_payload = UDP(sport=1234, dport=1234) / self.payload(payload_length)
663         p_ip6 = IPv6(src="1::1", dst=self.pg0.remote_ip6)
664         outer_ip6 = (p_ether / IPv6(src=self.pg1.remote_ip6,
665                                     dst=self.pg0.local_ip6) /
666                      IPv6ExtHdrFragment() / p_ip6 / p_payload)
667         frags = fragment6(outer_ip6, fragment_size)
668         p6_reply = (p_ip6 / p_payload)
669         p6_reply.hlim -= 1
670         return frags, p6_reply
671
672     def generate_ip6_hairpin_frags(self, payload_length, fragment_size):
673         p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
674         p_payload = UDP(sport=1234, dport=1234) / self.payload(payload_length)
675         p_ip6 = IPv6(src="1::1", dst="dead::1")
676         outer_ip6 = (p_ether / IPv6(src=self.pg1.remote_ip6,
677                                     dst=self.pg0.local_ip6) /
678                      IPv6ExtHdrFragment() / p_ip6 / p_payload)
679         frags = fragment6(outer_ip6, fragment_size)
680         p_ip6.hlim -= 1
681         p6_reply = (IPv6(src=self.pg0.local_ip6, dst=self.pg1.remote_ip6,
682                          hlim=63) / p_ip6 / p_payload)
683
684         return frags, p6_reply
685
686     def test_encap(self):
687         """ ip{v4,v6} over ip6 test encap """
688         p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
689         p_ip6 = IPv6(src="1::1", dst="DEAD::1", tc=42, nh='UDP')
690         p_ip4 = IP(src="1.2.3.4", dst="130.67.0.1", tos=42)
691         p_payload = UDP(sport=1234, dport=1234)
692
693         # Encapsulation
694         # IPv6 in to IPv6 tunnel
695         p6 = (p_ether / p_ip6 / p_payload)
696         p6_reply = (IPv6(src=self.pg0.local_ip6, dst=self.pg1.remote_ip6,
697                          hlim=64) /
698                     p_ip6 / p_payload)
699         p6_reply[1].hlim -= 1
700         rx = self.send_and_expect(self.pg0, p6 * 11, self.pg1)
701         for p in rx:
702             self.validate(p[1], p6_reply)
703
704         # IPv4 in to IPv6 tunnel
705         p4 = (p_ether / p_ip4 / p_payload)
706         p4_reply = (IPv6(src=self.pg0.local_ip6,
707                          dst=self.pg1.remote_ip6, hlim=64) /
708                     p_ip4 / p_payload)
709         p4_reply[1].ttl -= 1
710         rx = self.send_and_expect(self.pg0, p4 * 11, self.pg1)
711         for p in rx:
712             self.validate(p[1], p4_reply)
713
714     def test_decap(self):
715         """ ip{v4,v6} over ip6 test decap """
716
717         p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
718         p_ip6 = IPv6(src="1::1", dst="DEAD::1", tc=42, nh='UDP')
719         p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
720         p_payload = UDP(sport=1234, dport=1234)
721
722         # Decapsulation
723         # IPv6 tunnel to IPv4
724
725         p4 = (p_ether / IPv6(src=self.pg1.remote_ip6,
726                              dst=self.pg0.local_ip6) / p_ip4 / p_payload)
727         p4_reply = (p_ip4 / p_payload)
728         p4_reply.ttl -= 1
729         rx = self.send_and_expect(self.pg1, p4 * 11, self.pg0)
730         for p in rx:
731             self.validate(p[1], p4_reply)
732
733         # IPv6 tunnel to IPv6
734         p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
735         p6 = (p_ether / IPv6(src=self.pg1.remote_ip6,
736                              dst=self.pg0.local_ip6) / p_ip6 / p_payload)
737         p6_reply = (p_ip6 / p_payload)
738         p6_reply.hlim = 63
739         rx = self.send_and_expect(self.pg1, p6 * 11, self.pg0)
740         for p in rx:
741             self.validate(p[1], p6_reply)
742
743     def verify_ip4ip6_encaps(self, a, p_ip4s, p_ip6_encaps):
744         for i, p_ip4 in enumerate(p_ip4s):
745             p_ip4.dst = a
746             p4 = (self.p_ether / p_ip4 / self.p_payload)
747             p_ip4_inner = p_ip4
748             p_ip4_inner.ttl -= 1
749             p6_reply = (p_ip6_encaps[i] / p_ip4_inner / self.p_payload)
750             rx = self.send_and_expect(self.pg0, p4 * N_PACKETS, self.pg1)
751             for p in rx:
752                 self.validate(p[1], p6_reply)
753                 self.assert_packet_checksums_valid(p)
754
755     def verify_ip6ip6_encaps(self, a, p_ip6s, p_ip6_encaps):
756         for i, p_ip6 in enumerate(p_ip6s):
757             p_ip6.dst = a
758             p6 = (self.p_ether / p_ip6 / self.p_payload)
759             p_inner_ip6 = p_ip6
760             p_inner_ip6.hlim -= 1
761             p6_reply = (p_ip6_encaps[i] / p_inner_ip6 / self.p_payload)
762             rx = self.send_and_expect(self.pg0, p6 * N_PACKETS, self.pg1)
763             for p in rx:
764                 self.validate(p[1], p6_reply)
765                 self.assert_packet_checksums_valid(p)
766
767     def test_ipip6(self):
768         """ ip{v4,v6} over ip6 test """
769
770         # that's annoying
771         self.destroy_tunnel()
772
773         self.pg1.generate_remote_hosts(5)
774         self.pg1.configure_ipv6_neighbors()
775         e = VppEnum.vl_api_tunnel_encap_decap_flags_t
776         d = VppEnum.vl_api_ip_dscp_t
777         self.p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
778         self.p_payload = UDP(sport=1234, dport=1234) / Raw(b'X' * 100)
779
780         # create a TOS byte by shifting a DSCP code point 2 bits. those 2 bits
781         # are for the ECN.
782         dscp = d.IP_API_DSCP_AF31 << 2
783         ecn = 3
784         dscp_ecn = d.IP_API_DSCP_AF31 << 2 | ecn
785
786         # IPv4 transport that copies the DCSP from the payload
787         tun_dscp = VppIpIpTunInterface(
788             self,
789             self.pg0,
790             self.pg0.local_ip6,
791             self.pg1.remote_hosts[0].ip6,
792             flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP)
793         tun_dscp.add_vpp_config()
794         # IPv4 transport that copies the DCSP and ECN from the payload
795         tun_dscp_ecn = VppIpIpTunInterface(
796             self,
797             self.pg0,
798             self.pg0.local_ip6,
799             self.pg1.remote_hosts[1].ip6,
800             flags=(e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP |
801                    e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN))
802         tun_dscp_ecn.add_vpp_config()
803         # IPv4 transport that copies the ECN from the payload and sets the
804         # DF bit on encap. copies the ECN on decap
805         tun_ecn = VppIpIpTunInterface(
806             self,
807             self.pg0,
808             self.pg0.local_ip6,
809             self.pg1.remote_hosts[2].ip6,
810             flags=(e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN |
811                    e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_SET_DF |
812                    e.TUNNEL_API_ENCAP_DECAP_FLAG_DECAP_COPY_ECN))
813         tun_ecn.add_vpp_config()
814         # IPv4 transport that sets a fixed DSCP in the encap and copies
815         # the DF bit
816         tun = VppIpIpTunInterface(
817             self,
818             self.pg0,
819             self.pg0.local_ip6,
820             self.pg1.remote_hosts[3].ip6,
821             dscp=d.IP_API_DSCP_AF11,
822             flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DF)
823         tun.add_vpp_config()
824
825         # array of all the tunnels
826         tuns = [tun_dscp, tun_dscp_ecn, tun_ecn, tun]
827
828         # addresses for prefixes routed via each tunnel
829         a4s = ["" for i in range(len(tuns))]
830         a6s = ["" for i in range(len(tuns))]
831
832         # IP headers for inner packets with each combination of DSCp/ECN tested
833         p_ip6s = [IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=dscp),
834                   IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=dscp_ecn),
835                   IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=ecn),
836                   IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=0xff)]
837         p_ip4s = [IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp, flags='DF'),
838                   IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp_ecn),
839                   IP(src="1.2.3.4", dst="130.67.0.1", tos=ecn),
840                   IP(src="1.2.3.4", dst="130.67.0.1", tos=0xff)]
841
842         # Configure each tunnel
843         for i, t in enumerate(tuns):
844             # Set interface up and enable IP on it
845             self.vapi.sw_interface_set_flags(t.sw_if_index, 1)
846             self.vapi.sw_interface_set_unnumbered(
847                 sw_if_index=self.pg0.sw_if_index,
848                 unnumbered_sw_if_index=t.sw_if_index)
849
850             # prefix for route / destination address for packets
851             a4s[i] = "130.67.%d.0" % i
852             a6s[i] = "dead:%d::" % i
853
854             # Add IPv4 and IPv6 routes via tunnel interface
855             ip4_via_tunnel = VppIpRoute(
856                 self, a4s[i], 24,
857                 [VppRoutePath("0.0.0.0",
858                               t.sw_if_index,
859                               proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)])
860             ip4_via_tunnel.add_vpp_config()
861
862             ip6_via_tunnel = VppIpRoute(
863                 self, a6s[i], 64,
864                 [VppRoutePath("::",
865                               t.sw_if_index,
866                               proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
867             ip6_via_tunnel.add_vpp_config()
868
869         #
870         # Encapsulation
871         #
872
873         # tun_dscp copies only the dscp
874         # expected TC values are thus only the DCSP value is present from the
875         # inner
876         exp_tcs = [dscp, dscp, 0, 0xfc]
877         p_ip6_encaps = [IPv6(src=self.pg0.local_ip6,
878                              dst=tun_dscp.dst,
879                              tc=tc) for tc in exp_tcs]
880
881         # IPv4 in to IPv4 tunnel
882         self.verify_ip4ip6_encaps(a4s[0], p_ip4s, p_ip6_encaps)
883         # IPv6 in to IPv4 tunnel
884         self.verify_ip6ip6_encaps(a6s[0], p_ip6s, p_ip6_encaps)
885
886         # tun_dscp_ecn copies the dscp and the ecn
887         exp_tcs = [dscp, dscp_ecn, ecn, 0xff]
888         p_ip6_encaps = [IPv6(src=self.pg0.local_ip6,
889                              dst=tun_dscp_ecn.dst,
890                              tc=tc) for tc in exp_tcs]
891
892         self.verify_ip4ip6_encaps(a4s[1], p_ip4s, p_ip6_encaps)
893         self.verify_ip6ip6_encaps(a6s[1], p_ip6s, p_ip6_encaps)
894
895         # tun_ecn copies only the ecn and always sets DF
896         exp_tcs = [0, ecn, ecn, ecn]
897         p_ip6_encaps = [IPv6(src=self.pg0.local_ip6,
898                              dst=tun_ecn.dst,
899                              tc=tc) for tc in exp_tcs]
900
901         self.verify_ip4ip6_encaps(a4s[2], p_ip4s, p_ip6_encaps)
902         self.verify_ip6ip6_encaps(a6s[2], p_ip6s, p_ip6_encaps)
903
904         # tun sets a fixed dscp
905         fixed_dscp = tun.dscp << 2
906         p_ip6_encaps = [IPv6(src=self.pg0.local_ip6,
907                              dst=tun.dst,
908                              tc=fixed_dscp) for i in range(len(p_ip4s))]
909
910         self.verify_ip4ip6_encaps(a4s[3], p_ip4s, p_ip6_encaps)
911         self.verify_ip6ip6_encaps(a6s[3], p_ip6s, p_ip6_encaps)
912
913         #
914         # Decapsulation
915         #
916         n_packets_decapped = self.statistics.get_err_counter(
917             '/err/ipip6-input/packets decapsulated')
918
919         self.p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
920
921         # IPv6 tunnel to IPv4
922         tcs = [0, dscp, dscp_ecn, ecn]
923
924         # one overlay packet and all combinations of its encap
925         p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
926         p_ip6_encaps = [IPv6(src=tun.dst,
927                              dst=self.pg0.local_ip6,
928                              tc=tc) for tc in tcs]
929
930         # for each encap tun will produce the same inner packet because it does
931         # not copy up fields from the payload
932         for p_ip6_encap in p_ip6_encaps:
933             p6 = (self.p_ether / p_ip6_encap / p_ip4 / self.p_payload)
934             p4_reply = (p_ip4 / self.p_payload)
935             p4_reply.ttl -= 1
936             rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
937             n_packets_decapped += N_PACKETS
938             for p in rx:
939                 self.validate(p[1], p4_reply)
940                 self.assert_packet_checksums_valid(p)
941
942         err = self.statistics.get_err_counter(
943             '/err/ipip6-input/packets decapsulated')
944         self.assertEqual(err, n_packets_decapped)
945
946         # tun_ecn copies the ECN bits from the encap to the inner
947         p_ip6_encaps = [IPv6(src=tun_ecn.dst,
948                              dst=self.pg0.local_ip6,
949                              tc=tc) for tc in tcs]
950         p_ip4_replys = [p_ip4.copy() for i in range(len(p_ip6_encaps))]
951         p_ip4_replys[2].tos = ecn
952         p_ip4_replys[3].tos = ecn
953         for i, p_ip6_encap in enumerate(p_ip6_encaps):
954             p6 = (self.p_ether / p_ip6_encap / p_ip4 / self.p_payload)
955             p4_reply = (p_ip4_replys[i] / self.p_payload)
956             p4_reply.ttl -= 1
957             rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
958             n_packets_decapped += N_PACKETS
959             for p in rx:
960                 self.validate(p[1], p4_reply)
961                 self.assert_packet_checksums_valid(p)
962
963         err = self.statistics.get_err_counter(
964             '/err/ipip6-input/packets decapsulated')
965         self.assertEqual(err, n_packets_decapped)
966
967         # IPv6 tunnel to IPv6
968         # for each encap tun will produce the same inner packet because it does
969         # not copy up fields from the payload
970         p_ip6_encaps = [IPv6(src=tun.dst,
971                              dst=self.pg0.local_ip6,
972                              tc=tc) for tc in tcs]
973         p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
974         for p_ip6_encap in p_ip6_encaps:
975             p6 = (self.p_ether / p_ip6_encap / p_ip6 / self.p_payload)
976             p6_reply = (p_ip6 / self.p_payload)
977             p6_reply.hlim = 63
978             rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
979             n_packets_decapped += N_PACKETS
980             for p in rx:
981                 self.validate(p[1], p6_reply)
982                 self.assert_packet_checksums_valid(p)
983
984         err = self.statistics.get_err_counter(
985             '/err/ipip6-input/packets decapsulated')
986         self.assertEqual(err, n_packets_decapped)
987
988         # IPv6 tunnel to IPv6
989         # tun_ecn copies the ECN bits from the encap to the inner
990         p_ip6_encaps = [IPv6(src=tun_ecn.dst,
991                              dst=self.pg0.local_ip6,
992                              tc=tc) for tc in tcs]
993         p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
994         p_ip6_replys = [p_ip6.copy() for i in range(len(p_ip6_encaps))]
995         p_ip6_replys[2].tc = ecn
996         p_ip6_replys[3].tc = ecn
997         for i, p_ip6_encap in enumerate(p_ip6_encaps):
998             p6 = (self.p_ether / p_ip6_encap / p_ip6 / self.p_payload)
999             p6_reply = (p_ip6_replys[i] / self.p_payload)
1000             p6_reply.hlim = 63
1001             rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
1002             n_packets_decapped += N_PACKETS
1003             for p in rx:
1004                 self.validate(p[1], p6_reply)
1005                 self.assert_packet_checksums_valid(p)
1006
1007         err = self.statistics.get_err_counter(
1008             '/err/ipip6-input/packets decapsulated')
1009         self.assertEqual(err, n_packets_decapped)
1010
1011     def test_frag(self):
1012         """ ip{v4,v6} over ip6 test frag """
1013
1014         p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
1015         p_ip6 = IPv6(src="1::1", dst="DEAD::1", tc=42, nh='UDP')
1016         p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
1017         p_payload = UDP(sport=1234, dport=1234)
1018
1019         #
1020         # Fragmentation / Reassembly and Re-fragmentation
1021         #
1022         rv = self.vapi.ip_reassembly_enable_disable(
1023             sw_if_index=self.pg1.sw_if_index,
1024             enable_ip6=1)
1025
1026         self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=1000,
1027                                     max_reassembly_length=1000,
1028                                     expire_walk_interval_ms=10000,
1029                                     is_ip6=1)
1030
1031         # Send lots of fragments, verify reassembled packet
1032         before_cnt = self.statistics.get_err_counter(
1033             '/err/ipip6-input/packets decapsulated')
1034         frags, p6_reply = self.generate_ip6_frags(3131, 1400)
1035         f = []
1036         for i in range(0, 1000):
1037             f.extend(frags)
1038         self.pg1.add_stream(f)
1039         self.pg_enable_capture()
1040         self.pg_start()
1041         rx = self.pg0.get_capture(1000)
1042
1043         for p in rx:
1044             self.validate(p[1], p6_reply)
1045
1046         cnt = self.statistics.get_err_counter(
1047             '/err/ipip6-input/packets decapsulated')
1048         self.assertEqual(cnt, before_cnt + 1000)
1049
1050         f = []
1051         r = []
1052         # TODO: Check out why reassembly of atomic fragments don't work
1053         for i in range(10, 90):
1054             frags, p6_reply = self.generate_ip6_frags(i * 100, 1000)
1055             f.extend(frags)
1056             r.extend(p6_reply)
1057         self.pg_enable_capture()
1058         self.pg1.add_stream(f)
1059         self.pg_start()
1060         rx = self.pg0.get_capture(80)
1061         i = 0
1062         for p in rx:
1063             self.validate(p[1], r[i])
1064             i += 1
1065
1066         # Simple fragmentation
1067         p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1068         self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1280, 0, 0, 0])
1069
1070         # IPv6 in to IPv6 tunnel
1071         p_payload = UDP(sport=1234, dport=1234) / self.payload(1300)
1072
1073         p6 = (p_ether / p_ip6 / p_payload)
1074         p6_reply = (IPv6(src=self.pg0.local_ip6, dst=self.pg1.remote_ip6,
1075                          hlim=63) /
1076                     p_ip6 / p_payload)
1077         p6_reply[1].hlim -= 1
1078         self.pg_enable_capture()
1079         self.pg0.add_stream(p6)
1080         self.pg_start()
1081         rx = self.pg1.get_capture(2)
1082
1083         # Scapy defragment doesn't deal well with multiple layers
1084         # of same type / Ethernet header first
1085         f = [p[1] for p in rx]
1086         reass_pkt = defragment6(f)
1087         self.validate(reass_pkt, p6_reply)
1088
1089         # Now try with re-fragmentation
1090         #
1091         # Send large fragments to tunnel head-end, for the tunnel head end
1092         # to reassemble and then refragment out the tunnel again.
1093         # Hair-pinning
1094         #
1095         self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1280, 0, 0, 0])
1096         frags, p6_reply = self.generate_ip6_hairpin_frags(8000, 1200)
1097         self.pg_enable_capture()
1098         self.pg1.add_stream(frags)
1099         self.pg_start()
1100         rx = self.pg1.get_capture(7)
1101         f = [p[1] for p in rx]
1102         reass_pkt = defragment6(f)
1103         p6_reply.id = 256
1104         self.validate(reass_pkt, p6_reply)
1105
1106     def test_ipip_create(self):
1107         """ ipip create / delete interface test """
1108         rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5')
1109         sw_if_index = rv.sw_if_index
1110         self.vapi.ipip_del_tunnel(sw_if_index)
1111
1112     def test_ipip_vrf_create(self):
1113         """ ipip create / delete interface VRF test """
1114
1115         t = VppIpTable(self, 20)
1116         t.add_vpp_config()
1117         rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5', table_id=20)
1118         sw_if_index = rv.sw_if_index
1119         self.vapi.ipip_del_tunnel(sw_if_index)
1120
1121     def payload(self, len):
1122         return 'x' * len
1123
1124
1125 if __name__ == '__main__':
1126     unittest.main(testRunner=VppTestRunner)