blob: 8f18c07341dd508de3e1a5b933074853c9a68127 [file] [log] [blame]
Renato Botelho do Coutoead1e532019-10-31 13:31:07 -05001#!/usr/bin/env python3
Ole Troan46c1c112018-03-14 20:39:40 +01002"""IP{4,6} over IP{v,6} tunnel functional tests"""
Ole Troan298c6952018-03-08 12:30:43 +01003
4import unittest
Neale Ranns0b6a8572019-10-30 17:34:14 +00005from scapy.layers.inet6 import IPv6, Ether, IP, UDP, IPv6ExtHdrFragment, Raw
Ole Troan282093f2018-09-19 12:38:51 +02006from scapy.all import fragment, fragment6, RandShort, defragment6
Ole Troan46c1c112018-03-14 20:39:40 +01007from framework import VppTestCase, VppTestRunner
Neale Rannsc0a93142018-09-05 15:42:26 -07008from vpp_ip import DpoProto
Neale Ranns097fa662018-05-01 05:17:55 -07009from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpTable, FibPathProto
Neale Ranns95346962019-11-25 13:04:44 +000010from vpp_ipip_tun_interface import VppIpIpTunInterface
Neale Ranns28287212019-12-16 00:53:11 +000011from vpp_teib import VppTeib
Neale Ranns95346962019-11-25 13:04:44 +000012from vpp_papi import VppEnum
Ole Troan46c1c112018-03-14 20:39:40 +010013from socket import AF_INET, AF_INET6, inet_pton
Ole Troan7f991832018-12-06 17:35:12 +010014from util import reassemble4
15
Ole Troan298c6952018-03-08 12:30:43 +010016""" Testipip is a subclass of VPPTestCase classes.
17
18IPIP tests.
19
20"""
21
22
Neale Ranns95346962019-11-25 13:04:44 +000023def ipip_add_tunnel(test, src, dst, table_id=0, dscp=0x0,
24 flags=0):
Neale Rannscbd08242019-05-26 11:34:27 -070025 """ 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,
Neale Ranns95346962019-11-25 13:04:44 +000032 'dscp': dscp,
33 'flags': flags
Neale Rannscbd08242019-05-26 11:34:27 -070034 }
35 )
36
Neale Ranns95346962019-11-25 13:04:44 +000037# 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
39N_PACKETS = 64 - 1
40
Neale Rannscbd08242019-05-26 11:34:27 -070041
Ole Troan298c6952018-03-08 12:30:43 +010042class TestIPIP(VppTestCase):
43 """ IPIP Test Case """
44
45 @classmethod
46 def setUpClass(cls):
47 super(TestIPIP, cls).setUpClass()
Neale Ranns256b67b2020-09-02 14:46:53 +000048 cls.create_pg_interfaces(range(3))
Ole Troan46c1c112018-03-14 20:39:40 +010049 cls.interfaces = list(cls.pg_interfaces)
Ole Troan298c6952018-03-08 12:30:43 +010050
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -070051 @classmethod
52 def tearDownClass(cls):
53 super(TestIPIP, cls).tearDownClass()
54
Paul Vinciguerra741865b2018-11-27 06:01:22 -080055 def setUp(self):
56 super(TestIPIP, self).setUp()
Neale Ranns256b67b2020-09-02 14:46:53 +000057 self.table = VppIpTable(self, 1, register=False)
58 self.table.add_vpp_config()
59
Paul Vinciguerra741865b2018-11-27 06:01:22 -080060 for i in self.interfaces:
Ole Troan46c1c112018-03-14 20:39:40 +010061 i.admin_up()
Neale Ranns256b67b2020-09-02 14:46:53 +000062
63 self.pg2.set_table_ip4(self.table.table_id)
64 for i in self.interfaces:
Ole Troan46c1c112018-03-14 20:39:40 +010065 i.config_ip4()
66 i.config_ip6()
67 i.disable_ipv6_ra()
68 i.resolve_arp()
69 i.resolve_ndp()
Ole Troan298c6952018-03-08 12:30:43 +010070
71 def tearDown(self):
72 super(TestIPIP, self).tearDown()
73 if not self.vpp_dead:
Ole Troan46c1c112018-03-14 20:39:40 +010074 for i in self.pg_interfaces:
75 i.unconfig_ip4()
76 i.unconfig_ip6()
Neale Ranns256b67b2020-09-02 14:46:53 +000077 i.set_table_ip4(0)
Ole Troan46c1c112018-03-14 20:39:40 +010078 i.admin_down()
Ole Troan298c6952018-03-08 12:30:43 +010079
Neale Ranns256b67b2020-09-02 14:46:53 +000080 self.table.remove_vpp_config()
81
Ole Troan298c6952018-03-08 12:30:43 +010082 def validate(self, rx, expected):
Ole Troan7f991832018-12-06 17:35:12 +010083 self.assertEqual(rx, expected.__class__(expected))
Ole Troan298c6952018-03-08 12:30:43 +010084
Ole Troan282093f2018-09-19 12:38:51 +020085 def generate_ip4_frags(self, payload_length, fragment_size):
Ole Troan7eb9d962018-08-10 14:39:48 +020086 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
Neale Ranns95346962019-11-25 13:04:44 +000097 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
Ole Troan298c6952018-03-08 12:30:43 +0100124 def test_ipip4(self):
125 """ ip{v4,v6} over ip4 test """
Ole Troan298c6952018-03-08 12:30:43 +0100126
Neale Ranns95346962019-11-25 13:04:44 +0000127 self.pg1.generate_remote_hosts(5)
128 self.pg1.configure_ipv4_neighbors()
Neale Ranns59ff9182019-12-29 23:55:18 +0000129 e = VppEnum.vl_api_tunnel_encap_decap_flags_t
Neale Ranns95346962019-11-25 13:04:44 +0000130 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)
Ole Troan298c6952018-03-08 12:30:43 +0100133
Neale Ranns95346962019-11-25 13:04:44 +0000134 # 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
Ole Troan298c6952018-03-08 12:30:43 +0100139
Neale Ranns95346962019-11-25 13:04:44 +0000140 # 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,
Neale Ranns59ff9182019-12-29 23:55:18 +0000146 flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP)
147 tun_dscp.add_vpp_config()
Neale Ranns95346962019-11-25 13:04:44 +0000148 # 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,
Neale Ranns59ff9182019-12-29 23:55:18 +0000154 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()
Neale Ranns95346962019-11-25 13:04:44 +0000157 # 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,
Neale Ranns59ff9182019-12-29 23:55:18 +0000164 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()
Neale Ranns95346962019-11-25 13:04:44 +0000168 # 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,
Neale Ranns59ff9182019-12-29 23:55:18 +0000176 flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DF)
177 tun.add_vpp_config()
Ole Troan298c6952018-03-08 12:30:43 +0100178
Neale Ranns95346962019-11-25 13:04:44 +0000179 # array of all the tunnels
180 tuns = [tun_dscp, tun_dscp_ecn, tun_ecn, tun]
Ole Troan298c6952018-03-08 12:30:43 +0100181
Neale Ranns95346962019-11-25 13:04:44 +0000182 # 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]
Ole Troan298c6952018-03-08 12:30:43 +0100237
238 # IPv4 in to IPv4 tunnel
Neale Ranns95346962019-11-25 13:04:44 +0000239 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)
Ole Troan298c6952018-03-08 12:30:43 +0100242
Neale Ranns95346962019-11-25 13:04:44 +0000243 # 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 #
Ole Troan298c6952018-03-08 12:30:43 +0100284 # Decapsulation
Neale Ranns95346962019-11-25 13:04:44 +0000285 #
286 n_packets_decapped = 0
287 self.p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
Ole Troan298c6952018-03-08 12:30:43 +0100288
289 # IPv4 tunnel to IPv4
Neale Ranns95346962019-11-25 13:04:44 +0000290 tcs = [0, dscp, dscp_ecn, ecn]
291
292 # one overlay packet and all combinations of its encap
Ole Troan298c6952018-03-08 12:30:43 +0100293 p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
Neale Ranns95346962019-11-25 13:04:44 +0000294 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)
Ole Troan298c6952018-03-08 12:30:43 +0100309
Ole Troan233e4682019-05-16 15:01:34 +0200310 err = self.statistics.get_err_counter(
Ole Troan58492a82018-09-04 13:19:12 +0200311 '/err/ipip4-input/packets decapsulated')
Neale Ranns95346962019-11-25 13:04:44 +0000312 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)
Ole Troan73202102018-08-31 00:29:48 +0200334
Ole Troan298c6952018-03-08 12:30:43 +0100335 # IPv4 tunnel to IPv6
Neale Ranns95346962019-11-25 13:04:44 +0000336 # 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]
Ole Troan298c6952018-03-08 12:30:43 +0100341 p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
Neale Ranns95346962019-11-25 13:04:44 +0000342 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)
Ole Troan298c6952018-03-08 12:30:43 +0100353
Ole Troan233e4682019-05-16 15:01:34 +0200354 err = self.statistics.get_err_counter(
Ole Troan58492a82018-09-04 13:19:12 +0200355 '/err/ipip4-input/packets decapsulated')
Neale Ranns95346962019-11-25 13:04:44 +0000356 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)
Ole Troan73202102018-08-31 00:29:48 +0200380
Ole Troan7eb9d962018-08-10 14:39:48 +0200381 #
Ole Troan4146c652018-08-08 22:23:19 +0200382 # Fragmentation / Reassembly and Re-fragmentation
Ole Troan7eb9d962018-08-10 14:39:48 +0200383 #
Ole Troan4146c652018-08-08 22:23:19 +0200384 rv = self.vapi.ip_reassembly_enable_disable(
385 sw_if_index=self.pg1.sw_if_index,
386 enable_ip4=1)
Ole Troan4146c652018-08-08 22:23:19 +0200387
Klement Sekera3a343d42019-05-16 14:35:46 +0200388 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
Ole Troan7eb9d962018-08-10 14:39:48 +0200393 # Send lots of fragments, verify reassembled packet
Ole Troan282093f2018-09-19 12:38:51 +0200394 frags, p4_reply = self.generate_ip4_frags(3131, 1400)
Ole Troan7eb9d962018-08-10 14:39:48 +0200395 f = []
396 for i in range(0, 1000):
397 f.extend(frags)
398 self.pg1.add_stream(f)
Ole Troan4146c652018-08-08 22:23:19 +0200399 self.pg_enable_capture()
Ole Troan4146c652018-08-08 22:23:19 +0200400 self.pg_start()
Ole Troan7eb9d962018-08-10 14:39:48 +0200401 rx = self.pg0.get_capture(1000)
Neale Ranns95346962019-11-25 13:04:44 +0000402 n_packets_decapped += 1000
Ole Troan7eb9d962018-08-10 14:39:48 +0200403
Ole Troan4146c652018-08-08 22:23:19 +0200404 for p in rx:
405 self.validate(p[1], p4_reply)
406
Ole Troan233e4682019-05-16 15:01:34 +0200407 err = self.statistics.get_err_counter(
Ole Troan58492a82018-09-04 13:19:12 +0200408 '/err/ipip4-input/packets decapsulated')
Neale Ranns95346962019-11-25 13:04:44 +0000409 self.assertEqual(err, n_packets_decapped)
Ole Troan73202102018-08-31 00:29:48 +0200410
Ole Troan7eb9d962018-08-10 14:39:48 +0200411 f = []
412 r = []
413 for i in range(1, 90):
Ole Troan282093f2018-09-19 12:38:51 +0200414 frags, p4_reply = self.generate_ip4_frags(i * 100, 1000)
Ole Troan7eb9d962018-08-10 14:39:48 +0200415 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
Ole Troan4146c652018-08-08 22:23:19 +0200426 # Now try with re-fragmentation
Ole Troan7eb9d962018-08-10 14:39:48 +0200427 #
428 # Send fragments to tunnel head-end, for the tunnel head end
429 # to reassemble and then refragment
430 #
Ole Troan4146c652018-08-08 22:23:19 +0200431 self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [576, 0, 0, 0])
Ole Troan282093f2018-09-19 12:38:51 +0200432 frags, p4_reply = self.generate_ip4_frags(3123, 1200)
Ole Troan4146c652018-08-08 22:23:19 +0200433 self.pg_enable_capture()
434 self.pg1.add_stream(frags)
435 self.pg_start()
436 rx = self.pg0.get_capture(6)
Ole Troan7f991832018-12-06 17:35:12 +0100437 reass_pkt = reassemble4(rx)
Ole Troan4146c652018-08-08 22:23:19 +0200438 p4_reply.id = 256
439 self.validate(reass_pkt, p4_reply)
440
Ole Troan7eb9d962018-08-10 14:39:48 +0200441 self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [1600, 0, 0, 0])
Ole Troan282093f2018-09-19 12:38:51 +0200442 frags, p4_reply = self.generate_ip4_frags(3123, 1200)
Ole Troan7eb9d962018-08-10 14:39:48 +0200443 self.pg_enable_capture()
444 self.pg1.add_stream(frags)
445 self.pg_start()
446 rx = self.pg0.get_capture(2)
Ole Troan7f991832018-12-06 17:35:12 +0100447 reass_pkt = reassemble4(rx)
Ole Troan7eb9d962018-08-10 14:39:48 +0200448 p4_reply.id = 512
449 self.validate(reass_pkt, p4_reply)
450
Neale Ranns0b6a8572019-10-30 17:34:14 +0000451 # send large packets through the tunnel, expect them to be fragmented
Neale Ranns95346962019-11-25 13:04:44 +0000452 self.vapi.sw_interface_set_mtu(tun_dscp.sw_if_index, [600, 0, 0, 0])
Neale Ranns0b6a8572019-10-30 17:34:14 +0000453
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
Ole Troan282093f2018-09-19 12:38:51 +0200466 def test_ipip_create(self):
467 """ ipip create / delete interface test """
Neale Rannscbd08242019-05-26 11:34:27 -0700468 rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5')
Ole Troan282093f2018-09-19 12:38:51 +0200469 sw_if_index = rv.sw_if_index
470 self.vapi.ipip_del_tunnel(sw_if_index)
Ole Troan298c6952018-03-08 12:30:43 +0100471
Ole Troan282093f2018-09-19 12:38:51 +0200472 def test_ipip_vrf_create(self):
473 """ ipip create / delete interface VRF test """
474
475 t = VppIpTable(self, 20)
476 t.add_vpp_config()
Neale Rannscbd08242019-05-26 11:34:27 -0700477 rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5', table_id=20)
Ole Troan282093f2018-09-19 12:38:51 +0200478 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
Neale Ranns14053c92019-12-29 23:55:18 +0000484 def test_mipip4(self):
485 """ p2mp IPv4 tunnel Tests """
486
Neale Ranns256b67b2020-09-02 14:46:53 +0000487 for itf in self.pg_interfaces[:2]:
Neale Ranns14053c92019-12-29 23:55:18 +0000488 #
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 #
Neale Ranns28287212019-12-16 00:53:11 +0000540 # Add a TEIB entry resolves the peer
Neale Ranns14053c92019-12-29 23:55:18 +0000541 #
Neale Ranns28287212019-12-16 00:53:11 +0000542 teib = VppTeib(self, ipip_if,
Neale Ranns14053c92019-12-29 23:55:18 +0000543 ipip_if._remote_hosts[ii].ip4,
544 itf._remote_hosts[ii].ip4)
Neale Ranns03ce4622020-02-03 10:55:09 +0000545 teib.add_vpp_config()
Neale Ranns14053c92019-12-29 23:55:18 +0000546 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 #
Neale Ranns28287212019-12-16 00:53:11 +0000578 # delete and re-add the TEIB
Neale Ranns14053c92019-12-29 23:55:18 +0000579 #
Neale Ranns03ce4622020-02-03 10:55:09 +0000580 teib.remove_vpp_config()
Neale Ranns14053c92019-12-29 23:55:18 +0000581 self.send_and_assert_no_replies(self.pg0, tx_e)
582 self.send_and_assert_no_replies(self.pg0, tx_i)
583
Neale Ranns03ce4622020-02-03 10:55:09 +0000584 teib.add_vpp_config()
Neale Ranns14053c92019-12-29 23:55:18 +0000585 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
Neale Ranns256b67b2020-09-02 14:46:53 +0000591 #
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
Neale Ranns14053c92019-12-29 23:55:18 +0000626 ipip_if.admin_down()
627 ipip_if.unconfig_ip4()
Neale Ranns256b67b2020-09-02 14:46:53 +0000628 ipip_if.set_table_ip4(0)
Neale Ranns14053c92019-12-29 23:55:18 +0000629
Ole Troan282093f2018-09-19 12:38:51 +0200630
631class 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
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -0700640 @classmethod
641 def tearDownClass(cls):
642 super(TestIPIP6, cls).tearDownClass()
643
Ole Troan282093f2018-09-19 12:38:51 +0200644 def setUp(self):
Paul Vinciguerra8d991d92019-01-25 14:05:48 -0800645 super(TestIPIP6, self).setUp()
Ole Troan282093f2018-09-19 12:38:51 +0200646 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):
Ole Troan298c6952018-03-08 12:30:43 +0100665 # IPv6 transport
Neale Rannscbd08242019-05-26 11:34:27 -0700666 rv = ipip_add_tunnel(self,
667 self.pg0.local_ip6,
Neale Ranns95346962019-11-25 13:04:44 +0000668 self.pg1.remote_ip6)
Ole Troan298c6952018-03-08 12:30:43 +0100669
670 sw_if_index = rv.sw_if_index
Ole Troan282093f2018-09-19 12:38:51 +0200671 self.tunnel_if_index = sw_if_index
Ole Troan46c1c112018-03-14 20:39:40 +0100672 self.vapi.sw_interface_set_flags(sw_if_index, 1)
673 self.vapi.sw_interface_set_unnumbered(
Ole Troan9a475372019-03-05 16:58:24 +0100674 sw_if_index=self.pg0.sw_if_index,
675 unnumbered_sw_if_index=sw_if_index)
Ole Troan298c6952018-03-08 12:30:43 +0100676
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,
Neale Ranns097fa662018-05-01 05:17:55 -0700682 proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)])
Ole Troan298c6952018-03-08 12:30:43 +0100683 ip4_via_tunnel.add_vpp_config()
684
685 ip6_via_tunnel = VppIpRoute(
686 self, "dead::", 16,
687 [VppRoutePath("::",
688 sw_if_index,
Neale Ranns097fa662018-05-01 05:17:55 -0700689 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
Ole Troan298c6952018-03-08 12:30:43 +0100690 ip6_via_tunnel.add_vpp_config()
691
Ole Troan282093f2018-09-19 12:38:51 +0200692 self.tunnel_ip6_via_tunnel = ip6_via_tunnel
693 self.tunnel_ip4_via_tunnel = ip4_via_tunnel
Ole Troan298c6952018-03-08 12:30:43 +0100694
Ole Troan282093f2018-09-19 12:38:51 +0200695 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):
Ole Troan7f991832018-12-06 17:35:12 +0100703 self.assertEqual(rx, expected.__class__(expected))
Ole Troan282093f2018-09-19 12:38:51 +0200704
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
Ole Troan298c6952018-03-08 12:30:43 +0100739 # IPv6 in to IPv6 tunnel
740 p6 = (p_ether / p_ip6 / p_payload)
Ole Troand57f6362018-05-24 13:21:43 +0200741 p6_reply = (IPv6(src=self.pg0.local_ip6, dst=self.pg1.remote_ip6,
Neale Ranns95346962019-11-25 13:04:44 +0000742 hlim=64) /
Ole Troand57f6362018-05-24 13:21:43 +0200743 p_ip6 / p_payload)
Ole Troan298c6952018-03-08 12:30:43 +0100744 p6_reply[1].hlim -= 1
Ole Troan9a475372019-03-05 16:58:24 +0100745 rx = self.send_and_expect(self.pg0, p6 * 11, self.pg1)
Ole Troan298c6952018-03-08 12:30:43 +0100746 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,
Neale Ranns95346962019-11-25 13:04:44 +0000752 dst=self.pg1.remote_ip6, hlim=64) /
Ole Troand57f6362018-05-24 13:21:43 +0200753 p_ip4 / p_payload)
Ole Troan298c6952018-03-08 12:30:43 +0100754 p4_reply[1].ttl -= 1
Ole Troan9a475372019-03-05 16:58:24 +0100755 rx = self.send_and_expect(self.pg0, p4 * 11, self.pg1)
Ole Troan298c6952018-03-08 12:30:43 +0100756 for p in rx:
757 self.validate(p[1], p4_reply)
758
Ole Troan282093f2018-09-19 12:38:51 +0200759 def test_decap(self):
760 """ ip{v4,v6} over ip6 test decap """
Ole Troan298c6952018-03-08 12:30:43 +0100761
762 p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
Ole Troan282093f2018-09-19 12:38:51 +0200763 p_ip6 = IPv6(src="1::1", dst="DEAD::1", tc=42, nh='UDP')
Ole Troan298c6952018-03-08 12:30:43 +0100764 p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
Ole Troan282093f2018-09-19 12:38:51 +0200765 p_payload = UDP(sport=1234, dport=1234)
766
767 # Decapsulation
768 # IPv6 tunnel to IPv4
769
Ole Troan298c6952018-03-08 12:30:43 +0100770 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
Ole Troan9a475372019-03-05 16:58:24 +0100774 rx = self.send_and_expect(self.pg1, p4 * 11, self.pg0)
Ole Troan298c6952018-03-08 12:30:43 +0100775 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
Ole Troan9a475372019-03-05 16:58:24 +0100784 rx = self.send_and_expect(self.pg1, p6 * 11, self.pg0)
Ole Troan298c6952018-03-08 12:30:43 +0100785 for p in rx:
786 self.validate(p[1], p6_reply)
787
Neale Ranns95346962019-11-25 13:04:44 +0000788 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()
Neale Ranns59ff9182019-12-29 23:55:18 +0000820 e = VppEnum.vl_api_tunnel_encap_decap_flags_t
Neale Ranns95346962019-11-25 13:04:44 +0000821 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,
Neale Ranns59ff9182019-12-29 23:55:18 +0000837 flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP)
838 tun_dscp.add_vpp_config()
Neale Ranns95346962019-11-25 13:04:44 +0000839 # 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,
Neale Ranns59ff9182019-12-29 23:55:18 +0000845 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()
Neale Ranns95346962019-11-25 13:04:44 +0000848 # 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,
Neale Ranns59ff9182019-12-29 23:55:18 +0000855 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()
Neale Ranns95346962019-11-25 13:04:44 +0000859 # 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,
Neale Ranns59ff9182019-12-29 23:55:18 +0000867 flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DF)
868 tun.add_vpp_config()
Neale Ranns95346962019-11-25 13:04:44 +0000869
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
Ole Troan282093f2018-09-19 12:38:51 +02001056 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
Klement Sekera3a343d42019-05-16 14:35:46 +02001071 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
Ole Troan282093f2018-09-19 12:38:51 +02001076 # Send lots of fragments, verify reassembled packet
Ole Troan233e4682019-05-16 15:01:34 +02001077 before_cnt = self.statistics.get_err_counter(
Ole Troan282093f2018-09-19 12:38:51 +02001078 '/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
Ole Troan233e4682019-05-16 15:01:34 +02001091 cnt = self.statistics.get_err_counter(
Ole Troan282093f2018-09-19 12:38:51 +02001092 '/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,
Neale Ranns95346962019-11-25 13:04:44 +00001120 hlim=63) /
Ole Troan282093f2018-09-19 12:38:51 +02001121 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
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -07001129 # of same type / Ethernet header first
Ole Troan282093f2018-09-19 12:38:51 +02001130 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
Ole Troan298c6952018-03-08 12:30:43 +01001151 def test_ipip_create(self):
1152 """ ipip create / delete interface test """
Neale Rannscbd08242019-05-26 11:34:27 -07001153 rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5')
Ole Troan298c6952018-03-08 12:30:43 +01001154 sw_if_index = rv.sw_if_index
Ole Troan46c1c112018-03-14 20:39:40 +01001155 self.vapi.ipip_del_tunnel(sw_if_index)
Ole Troan298c6952018-03-08 12:30:43 +01001156
Neale Ranns61502112018-08-22 00:21:14 -07001157 def test_ipip_vrf_create(self):
1158 """ ipip create / delete interface VRF test """
1159
1160 t = VppIpTable(self, 20)
1161 t.add_vpp_config()
Neale Rannscbd08242019-05-26 11:34:27 -07001162 rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5', table_id=20)
Neale Ranns61502112018-08-22 00:21:14 -07001163 sw_if_index = rv.sw_if_index
1164 self.vapi.ipip_del_tunnel(sw_if_index)
1165
Ole Troan4146c652018-08-08 22:23:19 +02001166 def payload(self, len):
1167 return 'x' * len
1168
Ole Troan298c6952018-03-08 12:30:43 +01001169
1170if __name__ == '__main__':
1171 unittest.main(testRunner=VppTestRunner)