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