blob: 83395e0bd72824a030c66ed41252c237377e0b62 [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
Neale Rannse294de62020-12-21 09:52:24 +00006from scapy.contrib.mpls import MPLS
Ole Troan282093f2018-09-19 12:38:51 +02007from scapy.all import fragment, fragment6, RandShort, defragment6
Ole Troan46c1c112018-03-14 20:39:40 +01008from framework import VppTestCase, VppTestRunner
Neale Rannsc0a93142018-09-05 15:42:26 -07009from vpp_ip import DpoProto
Neale Rannse294de62020-12-21 09:52:24 +000010from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpTable, FibPathProto, \
11 VppMplsLabel, VppMplsRoute, VppMplsTable
Neale Ranns95346962019-11-25 13:04:44 +000012from vpp_ipip_tun_interface import VppIpIpTunInterface
Neale Ranns28287212019-12-16 00:53:11 +000013from vpp_teib import VppTeib
Neale Ranns95346962019-11-25 13:04:44 +000014from vpp_papi import VppEnum
Ole Troan46c1c112018-03-14 20:39:40 +010015from socket import AF_INET, AF_INET6, inet_pton
Ole Troan7f991832018-12-06 17:35:12 +010016from util import reassemble4
17
Ole Troan298c6952018-03-08 12:30:43 +010018""" Testipip is a subclass of VPPTestCase classes.
19
20IPIP tests.
21
22"""
23
24
Neale Ranns95346962019-11-25 13:04:44 +000025def ipip_add_tunnel(test, src, dst, table_id=0, dscp=0x0,
26 flags=0):
Neale Rannscbd08242019-05-26 11:34:27 -070027 """ 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,
Neale Ranns95346962019-11-25 13:04:44 +000034 'dscp': dscp,
35 'flags': flags
Neale Rannscbd08242019-05-26 11:34:27 -070036 }
37 )
38
Neale Ranns95346962019-11-25 13:04:44 +000039# 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
41N_PACKETS = 64 - 1
42
Neale Rannscbd08242019-05-26 11:34:27 -070043
Ole Troan298c6952018-03-08 12:30:43 +010044class TestIPIP(VppTestCase):
45 """ IPIP Test Case """
46
47 @classmethod
48 def setUpClass(cls):
49 super(TestIPIP, cls).setUpClass()
Neale Ranns256b67b2020-09-02 14:46:53 +000050 cls.create_pg_interfaces(range(3))
Ole Troan46c1c112018-03-14 20:39:40 +010051 cls.interfaces = list(cls.pg_interfaces)
Ole Troan298c6952018-03-08 12:30:43 +010052
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -070053 @classmethod
54 def tearDownClass(cls):
55 super(TestIPIP, cls).tearDownClass()
56
Paul Vinciguerra741865b2018-11-27 06:01:22 -080057 def setUp(self):
58 super(TestIPIP, self).setUp()
Neale Ranns256b67b2020-09-02 14:46:53 +000059 self.table = VppIpTable(self, 1, register=False)
60 self.table.add_vpp_config()
61
Paul Vinciguerra741865b2018-11-27 06:01:22 -080062 for i in self.interfaces:
Ole Troan46c1c112018-03-14 20:39:40 +010063 i.admin_up()
Neale Ranns256b67b2020-09-02 14:46:53 +000064
65 self.pg2.set_table_ip4(self.table.table_id)
66 for i in self.interfaces:
Ole Troan46c1c112018-03-14 20:39:40 +010067 i.config_ip4()
68 i.config_ip6()
69 i.disable_ipv6_ra()
70 i.resolve_arp()
71 i.resolve_ndp()
Ole Troan298c6952018-03-08 12:30:43 +010072
73 def tearDown(self):
74 super(TestIPIP, self).tearDown()
75 if not self.vpp_dead:
Ole Troan46c1c112018-03-14 20:39:40 +010076 for i in self.pg_interfaces:
77 i.unconfig_ip4()
78 i.unconfig_ip6()
Neale Ranns256b67b2020-09-02 14:46:53 +000079 i.set_table_ip4(0)
Ole Troan46c1c112018-03-14 20:39:40 +010080 i.admin_down()
Ole Troan298c6952018-03-08 12:30:43 +010081
Neale Ranns256b67b2020-09-02 14:46:53 +000082 self.table.remove_vpp_config()
83
Ole Troan298c6952018-03-08 12:30:43 +010084 def validate(self, rx, expected):
Ole Troan7f991832018-12-06 17:35:12 +010085 self.assertEqual(rx, expected.__class__(expected))
Ole Troan298c6952018-03-08 12:30:43 +010086
Ole Troan282093f2018-09-19 12:38:51 +020087 def generate_ip4_frags(self, payload_length, fragment_size):
Ole Troan7eb9d962018-08-10 14:39:48 +020088 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
Neale Ranns95346962019-11-25 13:04:44 +000099 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
Ole Troan298c6952018-03-08 12:30:43 +0100126 def test_ipip4(self):
127 """ ip{v4,v6} over ip4 test """
Ole Troan298c6952018-03-08 12:30:43 +0100128
Neale Ranns95346962019-11-25 13:04:44 +0000129 self.pg1.generate_remote_hosts(5)
130 self.pg1.configure_ipv4_neighbors()
Neale Ranns59ff9182019-12-29 23:55:18 +0000131 e = VppEnum.vl_api_tunnel_encap_decap_flags_t
Neale Ranns95346962019-11-25 13:04:44 +0000132 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)
Ole Troan298c6952018-03-08 12:30:43 +0100135
Neale Ranns95346962019-11-25 13:04:44 +0000136 # 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
Ole Troan298c6952018-03-08 12:30:43 +0100141
Neale Ranns95346962019-11-25 13:04:44 +0000142 # 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,
Neale Ranns59ff9182019-12-29 23:55:18 +0000148 flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP)
149 tun_dscp.add_vpp_config()
Neale Ranns95346962019-11-25 13:04:44 +0000150 # 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,
Neale Ranns59ff9182019-12-29 23:55:18 +0000156 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()
Neale Ranns95346962019-11-25 13:04:44 +0000159 # 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,
Neale Ranns59ff9182019-12-29 23:55:18 +0000166 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()
Neale Ranns95346962019-11-25 13:04:44 +0000170 # 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,
Neale Ranns59ff9182019-12-29 23:55:18 +0000178 flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DF)
179 tun.add_vpp_config()
Ole Troan298c6952018-03-08 12:30:43 +0100180
Neale Ranns95346962019-11-25 13:04:44 +0000181 # array of all the tunnels
182 tuns = [tun_dscp, tun_dscp_ecn, tun_ecn, tun]
Ole Troan298c6952018-03-08 12:30:43 +0100183
Neale Ranns95346962019-11-25 13:04:44 +0000184 # 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]
Ole Troan298c6952018-03-08 12:30:43 +0100239
240 # IPv4 in to IPv4 tunnel
Neale Ranns95346962019-11-25 13:04:44 +0000241 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)
Ole Troan298c6952018-03-08 12:30:43 +0100244
Neale Ranns95346962019-11-25 13:04:44 +0000245 # 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 #
Ole Troan298c6952018-03-08 12:30:43 +0100286 # Decapsulation
Neale Ranns95346962019-11-25 13:04:44 +0000287 #
288 n_packets_decapped = 0
289 self.p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
Ole Troan298c6952018-03-08 12:30:43 +0100290
291 # IPv4 tunnel to IPv4
Neale Ranns95346962019-11-25 13:04:44 +0000292 tcs = [0, dscp, dscp_ecn, ecn]
293
294 # one overlay packet and all combinations of its encap
Ole Troan298c6952018-03-08 12:30:43 +0100295 p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
Neale Ranns95346962019-11-25 13:04:44 +0000296 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)
Ole Troan298c6952018-03-08 12:30:43 +0100311
Ole Troan233e4682019-05-16 15:01:34 +0200312 err = self.statistics.get_err_counter(
Ole Troan58492a82018-09-04 13:19:12 +0200313 '/err/ipip4-input/packets decapsulated')
Neale Ranns95346962019-11-25 13:04:44 +0000314 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)
Ole Troan73202102018-08-31 00:29:48 +0200336
Ole Troan298c6952018-03-08 12:30:43 +0100337 # IPv4 tunnel to IPv6
Neale Ranns95346962019-11-25 13:04:44 +0000338 # 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]
Ole Troan298c6952018-03-08 12:30:43 +0100343 p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
Neale Ranns95346962019-11-25 13:04:44 +0000344 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)
Ole Troan298c6952018-03-08 12:30:43 +0100355
Ole Troan233e4682019-05-16 15:01:34 +0200356 err = self.statistics.get_err_counter(
Ole Troan58492a82018-09-04 13:19:12 +0200357 '/err/ipip4-input/packets decapsulated')
Neale Ranns95346962019-11-25 13:04:44 +0000358 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)
Ole Troan73202102018-08-31 00:29:48 +0200382
Ole Troan7eb9d962018-08-10 14:39:48 +0200383 #
Ole Troan4146c652018-08-08 22:23:19 +0200384 # Fragmentation / Reassembly and Re-fragmentation
Ole Troan7eb9d962018-08-10 14:39:48 +0200385 #
Ole Troan4146c652018-08-08 22:23:19 +0200386 rv = self.vapi.ip_reassembly_enable_disable(
387 sw_if_index=self.pg1.sw_if_index,
388 enable_ip4=1)
Ole Troan4146c652018-08-08 22:23:19 +0200389
Klement Sekera3a343d42019-05-16 14:35:46 +0200390 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
Ole Troan7eb9d962018-08-10 14:39:48 +0200395 # Send lots of fragments, verify reassembled packet
Ole Troan282093f2018-09-19 12:38:51 +0200396 frags, p4_reply = self.generate_ip4_frags(3131, 1400)
Ole Troan7eb9d962018-08-10 14:39:48 +0200397 f = []
398 for i in range(0, 1000):
399 f.extend(frags)
400 self.pg1.add_stream(f)
Ole Troan4146c652018-08-08 22:23:19 +0200401 self.pg_enable_capture()
Ole Troan4146c652018-08-08 22:23:19 +0200402 self.pg_start()
Ole Troan7eb9d962018-08-10 14:39:48 +0200403 rx = self.pg0.get_capture(1000)
Neale Ranns95346962019-11-25 13:04:44 +0000404 n_packets_decapped += 1000
Ole Troan7eb9d962018-08-10 14:39:48 +0200405
Ole Troan4146c652018-08-08 22:23:19 +0200406 for p in rx:
407 self.validate(p[1], p4_reply)
408
Ole Troan233e4682019-05-16 15:01:34 +0200409 err = self.statistics.get_err_counter(
Ole Troan58492a82018-09-04 13:19:12 +0200410 '/err/ipip4-input/packets decapsulated')
Neale Ranns95346962019-11-25 13:04:44 +0000411 self.assertEqual(err, n_packets_decapped)
Ole Troan73202102018-08-31 00:29:48 +0200412
Ole Troan7eb9d962018-08-10 14:39:48 +0200413 f = []
414 r = []
415 for i in range(1, 90):
Ole Troan282093f2018-09-19 12:38:51 +0200416 frags, p4_reply = self.generate_ip4_frags(i * 100, 1000)
Ole Troan7eb9d962018-08-10 14:39:48 +0200417 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
Ole Troan4146c652018-08-08 22:23:19 +0200428 # Now try with re-fragmentation
Ole Troan7eb9d962018-08-10 14:39:48 +0200429 #
430 # Send fragments to tunnel head-end, for the tunnel head end
431 # to reassemble and then refragment
432 #
Ole Troan4146c652018-08-08 22:23:19 +0200433 self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [576, 0, 0, 0])
Ole Troan282093f2018-09-19 12:38:51 +0200434 frags, p4_reply = self.generate_ip4_frags(3123, 1200)
Ole Troan4146c652018-08-08 22:23:19 +0200435 self.pg_enable_capture()
436 self.pg1.add_stream(frags)
437 self.pg_start()
438 rx = self.pg0.get_capture(6)
Ole Troan7f991832018-12-06 17:35:12 +0100439 reass_pkt = reassemble4(rx)
Ole Troan4146c652018-08-08 22:23:19 +0200440 p4_reply.id = 256
441 self.validate(reass_pkt, p4_reply)
442
Ole Troan7eb9d962018-08-10 14:39:48 +0200443 self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [1600, 0, 0, 0])
Ole Troan282093f2018-09-19 12:38:51 +0200444 frags, p4_reply = self.generate_ip4_frags(3123, 1200)
Ole Troan7eb9d962018-08-10 14:39:48 +0200445 self.pg_enable_capture()
446 self.pg1.add_stream(frags)
447 self.pg_start()
448 rx = self.pg0.get_capture(2)
Ole Troan7f991832018-12-06 17:35:12 +0100449 reass_pkt = reassemble4(rx)
Ole Troan7eb9d962018-08-10 14:39:48 +0200450 p4_reply.id = 512
451 self.validate(reass_pkt, p4_reply)
452
Neale Ranns0b6a8572019-10-30 17:34:14 +0000453 # send large packets through the tunnel, expect them to be fragmented
Neale Ranns95346962019-11-25 13:04:44 +0000454 self.vapi.sw_interface_set_mtu(tun_dscp.sw_if_index, [600, 0, 0, 0])
Neale Ranns0b6a8572019-10-30 17:34:14 +0000455
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
Ole Troan282093f2018-09-19 12:38:51 +0200468 def test_ipip_create(self):
469 """ ipip create / delete interface test """
Neale Rannscbd08242019-05-26 11:34:27 -0700470 rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5')
Ole Troan282093f2018-09-19 12:38:51 +0200471 sw_if_index = rv.sw_if_index
472 self.vapi.ipip_del_tunnel(sw_if_index)
Ole Troan298c6952018-03-08 12:30:43 +0100473
Ole Troan282093f2018-09-19 12:38:51 +0200474 def test_ipip_vrf_create(self):
475 """ ipip create / delete interface VRF test """
476
477 t = VppIpTable(self, 20)
478 t.add_vpp_config()
Neale Rannscbd08242019-05-26 11:34:27 -0700479 rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5', table_id=20)
Ole Troan282093f2018-09-19 12:38:51 +0200480 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
Neale Ranns14053c92019-12-29 23:55:18 +0000486 def test_mipip4(self):
487 """ p2mp IPv4 tunnel Tests """
488
Neale Ranns256b67b2020-09-02 14:46:53 +0000489 for itf in self.pg_interfaces[:2]:
Neale Ranns14053c92019-12-29 23:55:18 +0000490 #
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 #
Neale Ranns28287212019-12-16 00:53:11 +0000542 # Add a TEIB entry resolves the peer
Neale Ranns14053c92019-12-29 23:55:18 +0000543 #
Neale Ranns28287212019-12-16 00:53:11 +0000544 teib = VppTeib(self, ipip_if,
Neale Ranns14053c92019-12-29 23:55:18 +0000545 ipip_if._remote_hosts[ii].ip4,
546 itf._remote_hosts[ii].ip4)
Neale Ranns03ce4622020-02-03 10:55:09 +0000547 teib.add_vpp_config()
Neale Ranns14053c92019-12-29 23:55:18 +0000548 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 #
Neale Ranns28287212019-12-16 00:53:11 +0000580 # delete and re-add the TEIB
Neale Ranns14053c92019-12-29 23:55:18 +0000581 #
Neale Ranns03ce4622020-02-03 10:55:09 +0000582 teib.remove_vpp_config()
Neale Ranns14053c92019-12-29 23:55:18 +0000583 self.send_and_assert_no_replies(self.pg0, tx_e)
584 self.send_and_assert_no_replies(self.pg0, tx_i)
585
Neale Ranns03ce4622020-02-03 10:55:09 +0000586 teib.add_vpp_config()
Neale Ranns14053c92019-12-29 23:55:18 +0000587 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
Neale Ranns256b67b2020-09-02 14:46:53 +0000593 #
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
Neale Ranns14053c92019-12-29 23:55:18 +0000628 ipip_if.admin_down()
629 ipip_if.unconfig_ip4()
Neale Ranns256b67b2020-09-02 14:46:53 +0000630 ipip_if.set_table_ip4(0)
Neale Ranns14053c92019-12-29 23:55:18 +0000631
Ole Troan282093f2018-09-19 12:38:51 +0200632
633class 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
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -0700642 @classmethod
643 def tearDownClass(cls):
644 super(TestIPIP6, cls).tearDownClass()
645
Ole Troan282093f2018-09-19 12:38:51 +0200646 def setUp(self):
Paul Vinciguerra8d991d92019-01-25 14:05:48 -0800647 super(TestIPIP6, self).setUp()
Ole Troan282093f2018-09-19 12:38:51 +0200648 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):
Ole Troan298c6952018-03-08 12:30:43 +0100667 # IPv6 transport
Neale Rannscbd08242019-05-26 11:34:27 -0700668 rv = ipip_add_tunnel(self,
669 self.pg0.local_ip6,
Neale Ranns95346962019-11-25 13:04:44 +0000670 self.pg1.remote_ip6)
Ole Troan298c6952018-03-08 12:30:43 +0100671
672 sw_if_index = rv.sw_if_index
Ole Troan282093f2018-09-19 12:38:51 +0200673 self.tunnel_if_index = sw_if_index
Ole Troan46c1c112018-03-14 20:39:40 +0100674 self.vapi.sw_interface_set_flags(sw_if_index, 1)
675 self.vapi.sw_interface_set_unnumbered(
Ole Troan9a475372019-03-05 16:58:24 +0100676 sw_if_index=self.pg0.sw_if_index,
677 unnumbered_sw_if_index=sw_if_index)
Ole Troan298c6952018-03-08 12:30:43 +0100678
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,
Neale Ranns097fa662018-05-01 05:17:55 -0700684 proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)])
Ole Troan298c6952018-03-08 12:30:43 +0100685 ip4_via_tunnel.add_vpp_config()
686
687 ip6_via_tunnel = VppIpRoute(
688 self, "dead::", 16,
689 [VppRoutePath("::",
690 sw_if_index,
Neale Ranns097fa662018-05-01 05:17:55 -0700691 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
Ole Troan298c6952018-03-08 12:30:43 +0100692 ip6_via_tunnel.add_vpp_config()
693
Ole Troan282093f2018-09-19 12:38:51 +0200694 self.tunnel_ip6_via_tunnel = ip6_via_tunnel
695 self.tunnel_ip4_via_tunnel = ip4_via_tunnel
Ole Troan298c6952018-03-08 12:30:43 +0100696
Ole Troan282093f2018-09-19 12:38:51 +0200697 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):
Ole Troan7f991832018-12-06 17:35:12 +0100705 self.assertEqual(rx, expected.__class__(expected))
Ole Troan282093f2018-09-19 12:38:51 +0200706
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
Ole Troan298c6952018-03-08 12:30:43 +0100741 # IPv6 in to IPv6 tunnel
742 p6 = (p_ether / p_ip6 / p_payload)
Ole Troand57f6362018-05-24 13:21:43 +0200743 p6_reply = (IPv6(src=self.pg0.local_ip6, dst=self.pg1.remote_ip6,
Neale Ranns95346962019-11-25 13:04:44 +0000744 hlim=64) /
Ole Troand57f6362018-05-24 13:21:43 +0200745 p_ip6 / p_payload)
Ole Troan298c6952018-03-08 12:30:43 +0100746 p6_reply[1].hlim -= 1
Ole Troan9a475372019-03-05 16:58:24 +0100747 rx = self.send_and_expect(self.pg0, p6 * 11, self.pg1)
Ole Troan298c6952018-03-08 12:30:43 +0100748 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,
Neale Ranns95346962019-11-25 13:04:44 +0000754 dst=self.pg1.remote_ip6, hlim=64) /
Ole Troand57f6362018-05-24 13:21:43 +0200755 p_ip4 / p_payload)
Ole Troan298c6952018-03-08 12:30:43 +0100756 p4_reply[1].ttl -= 1
Ole Troan9a475372019-03-05 16:58:24 +0100757 rx = self.send_and_expect(self.pg0, p4 * 11, self.pg1)
Ole Troan298c6952018-03-08 12:30:43 +0100758 for p in rx:
759 self.validate(p[1], p4_reply)
760
Ole Troan282093f2018-09-19 12:38:51 +0200761 def test_decap(self):
762 """ ip{v4,v6} over ip6 test decap """
Ole Troan298c6952018-03-08 12:30:43 +0100763
764 p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
Ole Troan282093f2018-09-19 12:38:51 +0200765 p_ip6 = IPv6(src="1::1", dst="DEAD::1", tc=42, nh='UDP')
Ole Troan298c6952018-03-08 12:30:43 +0100766 p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
Ole Troan282093f2018-09-19 12:38:51 +0200767 p_payload = UDP(sport=1234, dport=1234)
768
769 # Decapsulation
770 # IPv6 tunnel to IPv4
771
Ole Troan298c6952018-03-08 12:30:43 +0100772 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
Ole Troan9a475372019-03-05 16:58:24 +0100776 rx = self.send_and_expect(self.pg1, p4 * 11, self.pg0)
Ole Troan298c6952018-03-08 12:30:43 +0100777 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
Ole Troan9a475372019-03-05 16:58:24 +0100786 rx = self.send_and_expect(self.pg1, p6 * 11, self.pg0)
Ole Troan298c6952018-03-08 12:30:43 +0100787 for p in rx:
788 self.validate(p[1], p6_reply)
789
Neale Ranns95346962019-11-25 13:04:44 +0000790 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()
Neale Ranns59ff9182019-12-29 23:55:18 +0000822 e = VppEnum.vl_api_tunnel_encap_decap_flags_t
Neale Ranns95346962019-11-25 13:04:44 +0000823 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,
Neale Ranns59ff9182019-12-29 23:55:18 +0000839 flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP)
840 tun_dscp.add_vpp_config()
Neale Ranns95346962019-11-25 13:04:44 +0000841 # 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,
Neale Ranns59ff9182019-12-29 23:55:18 +0000847 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()
Neale Ranns95346962019-11-25 13:04:44 +0000850 # 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,
Neale Ranns59ff9182019-12-29 23:55:18 +0000857 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()
Neale Ranns95346962019-11-25 13:04:44 +0000861 # 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,
Neale Ranns59ff9182019-12-29 23:55:18 +0000869 flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DF)
870 tun.add_vpp_config()
Neale Ranns95346962019-11-25 13:04:44 +0000871
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
Ole Troan282093f2018-09-19 12:38:51 +02001058 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
Klement Sekera3a343d42019-05-16 14:35:46 +02001073 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
Ole Troan282093f2018-09-19 12:38:51 +02001078 # Send lots of fragments, verify reassembled packet
Ole Troan233e4682019-05-16 15:01:34 +02001079 before_cnt = self.statistics.get_err_counter(
Ole Troan282093f2018-09-19 12:38:51 +02001080 '/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
Ole Troan233e4682019-05-16 15:01:34 +02001093 cnt = self.statistics.get_err_counter(
Ole Troan282093f2018-09-19 12:38:51 +02001094 '/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,
Neale Ranns95346962019-11-25 13:04:44 +00001122 hlim=63) /
Ole Troan282093f2018-09-19 12:38:51 +02001123 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
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -07001131 # of same type / Ethernet header first
Ole Troan282093f2018-09-19 12:38:51 +02001132 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
Ole Troan298c6952018-03-08 12:30:43 +01001153 def test_ipip_create(self):
1154 """ ipip create / delete interface test """
Neale Rannscbd08242019-05-26 11:34:27 -07001155 rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5')
Ole Troan298c6952018-03-08 12:30:43 +01001156 sw_if_index = rv.sw_if_index
Ole Troan46c1c112018-03-14 20:39:40 +01001157 self.vapi.ipip_del_tunnel(sw_if_index)
Ole Troan298c6952018-03-08 12:30:43 +01001158
Neale Ranns61502112018-08-22 00:21:14 -07001159 def test_ipip_vrf_create(self):
1160 """ ipip create / delete interface VRF test """
1161
1162 t = VppIpTable(self, 20)
1163 t.add_vpp_config()
Neale Rannscbd08242019-05-26 11:34:27 -07001164 rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5', table_id=20)
Neale Ranns61502112018-08-22 00:21:14 -07001165 sw_if_index = rv.sw_if_index
1166 self.vapi.ipip_del_tunnel(sw_if_index)
1167
Ole Troan4146c652018-08-08 22:23:19 +02001168 def payload(self, len):
1169 return 'x' * len
1170
Ole Troan298c6952018-03-08 12:30:43 +01001171
Neale Rannse294de62020-12-21 09:52:24 +00001172class 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
Ole Troan298c6952018-03-08 12:30:43 +01001318if __name__ == '__main__':
1319 unittest.main(testRunner=VppTestRunner)