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