blob: 1887417a5e0d093624266bccd8d61bb2b7c7724f [file] [log] [blame]
Ole Troan46c1c112018-03-14 20:39:40 +01001#!/usr/bin/env python
2"""IP{4,6} over IP{v,6} tunnel functional tests"""
Ole Troan298c6952018-03-08 12:30:43 +01003
4import unittest
Ole Troan282093f2018-09-19 12:38:51 +02005from scapy.layers.inet6 import IPv6, Ether, IP, UDP, IPv6ExtHdrFragment
6from 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
Ole Troan46c1c112018-03-14 20:39:40 +010010from socket import AF_INET, AF_INET6, inet_pton
Ole Troan7f991832018-12-06 17:35:12 +010011from util import reassemble4
12
Ole Troan298c6952018-03-08 12:30:43 +010013""" Testipip is a subclass of VPPTestCase classes.
14
15IPIP tests.
16
17"""
18
19
Neale Rannscbd08242019-05-26 11:34:27 -070020def ipip_add_tunnel(test, src, dst, table_id=0, tc_tos=0xff):
21 """ Add a IPIP tunnel """
22 return test.vapi.ipip_add_tunnel(
23 tunnel={
24 'src': src,
25 'dst': dst,
26 'table_id': table_id,
27 'instance': 0xffffffff,
28 'tc_tos': tc_tos
29 }
30 )
31
32
Ole Troan298c6952018-03-08 12:30:43 +010033class TestIPIP(VppTestCase):
34 """ IPIP Test Case """
35
36 @classmethod
37 def setUpClass(cls):
38 super(TestIPIP, cls).setUpClass()
Ole Troan46c1c112018-03-14 20:39:40 +010039 cls.create_pg_interfaces(range(2))
40 cls.interfaces = list(cls.pg_interfaces)
Ole Troan298c6952018-03-08 12:30:43 +010041
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -070042 @classmethod
43 def tearDownClass(cls):
44 super(TestIPIP, cls).tearDownClass()
45
Paul Vinciguerra741865b2018-11-27 06:01:22 -080046 def setUp(self):
47 super(TestIPIP, self).setUp()
48 for i in self.interfaces:
Ole Troan46c1c112018-03-14 20:39:40 +010049 i.admin_up()
50 i.config_ip4()
51 i.config_ip6()
52 i.disable_ipv6_ra()
53 i.resolve_arp()
54 i.resolve_ndp()
Ole Troan298c6952018-03-08 12:30:43 +010055
56 def tearDown(self):
57 super(TestIPIP, self).tearDown()
58 if not self.vpp_dead:
Ole Troan46c1c112018-03-14 20:39:40 +010059 for i in self.pg_interfaces:
60 i.unconfig_ip4()
61 i.unconfig_ip6()
62 i.admin_down()
Ole Troan298c6952018-03-08 12:30:43 +010063
64 def validate(self, rx, expected):
Ole Troan7f991832018-12-06 17:35:12 +010065 self.assertEqual(rx, expected.__class__(expected))
Ole Troan298c6952018-03-08 12:30:43 +010066
Ole Troan282093f2018-09-19 12:38:51 +020067 def generate_ip4_frags(self, payload_length, fragment_size):
Ole Troan7eb9d962018-08-10 14:39:48 +020068 p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
69 p_payload = UDP(sport=1234, dport=1234) / self.payload(payload_length)
70 p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
71 outer_ip4 = (p_ether / IP(src=self.pg1.remote_ip4,
72 id=RandShort(),
73 dst=self.pg0.local_ip4) / p_ip4 / p_payload)
74 frags = fragment(outer_ip4, fragment_size)
75 p4_reply = (p_ip4 / p_payload)
76 p4_reply.ttl -= 1
77 return frags, p4_reply
78
Ole Troan298c6952018-03-08 12:30:43 +010079 def test_ipip4(self):
80 """ ip{v4,v6} over ip4 test """
81 p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
Ole Troand57f6362018-05-24 13:21:43 +020082 p_ip6 = IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=42)
83 p_ip4 = IP(src="1.2.3.4", dst="130.67.0.1", tos=42)
Damjan Marionfe7d4a22018-04-13 19:43:39 +020084 p_payload = UDP(sport=1234, dport=1234)
Ole Troan298c6952018-03-08 12:30:43 +010085
86 # IPv4 transport
Neale Rannscbd08242019-05-26 11:34:27 -070087 rv = ipip_add_tunnel(self,
88 self.pg0.local_ip4,
89 self.pg1.remote_ip4,
90 tc_tos=0xFF)
Ole Troan298c6952018-03-08 12:30:43 +010091 sw_if_index = rv.sw_if_index
92
93 # Set interface up and enable IP on it
Ole Troan46c1c112018-03-14 20:39:40 +010094 self.vapi.sw_interface_set_flags(sw_if_index, 1)
95 self.vapi.sw_interface_set_unnumbered(
Ole Troan9a475372019-03-05 16:58:24 +010096 sw_if_index=self.pg0.sw_if_index,
97 unnumbered_sw_if_index=sw_if_index)
Ole Troan298c6952018-03-08 12:30:43 +010098
99 # Add IPv4 and IPv6 routes via tunnel interface
100 ip4_via_tunnel = VppIpRoute(
101 self, "130.67.0.0", 16,
102 [VppRoutePath("0.0.0.0",
103 sw_if_index,
Neale Ranns097fa662018-05-01 05:17:55 -0700104 proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)])
Ole Troan298c6952018-03-08 12:30:43 +0100105 ip4_via_tunnel.add_vpp_config()
106
107 ip6_via_tunnel = VppIpRoute(
108 self, "dead::", 16,
109 [VppRoutePath("::",
110 sw_if_index,
Neale Ranns097fa662018-05-01 05:17:55 -0700111 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
Ole Troan298c6952018-03-08 12:30:43 +0100112 ip6_via_tunnel.add_vpp_config()
113
114 # IPv6 in to IPv4 tunnel
115 p6 = (p_ether / p_ip6 / p_payload)
116 p_inner_ip6 = p_ip6
117 p_inner_ip6.hlim -= 1
118 p6_reply = (IP(src=self.pg0.local_ip4, dst=self.pg1.remote_ip4,
Ole Troand57f6362018-05-24 13:21:43 +0200119 proto='ipv6', id=0, tos=42) / p_inner_ip6 / p_payload)
Ole Troan298c6952018-03-08 12:30:43 +0100120 p6_reply.ttl -= 1
Ole Troan9a475372019-03-05 16:58:24 +0100121 rx = self.send_and_expect(self.pg0, p6 * 10, self.pg1)
Ole Troan298c6952018-03-08 12:30:43 +0100122 for p in rx:
123 self.validate(p[1], p6_reply)
124
125 # IPv4 in to IPv4 tunnel
126 p4 = (p_ether / p_ip4 / p_payload)
127 p_ip4_inner = p_ip4
128 p_ip4_inner.ttl -= 1
Ole Troand57f6362018-05-24 13:21:43 +0200129 p4_reply = (IP(src=self.pg0.local_ip4, dst=self.pg1.remote_ip4,
130 tos=42) /
131 p_ip4_inner / p_payload)
Ole Troan298c6952018-03-08 12:30:43 +0100132 p4_reply.ttl -= 1
133 p4_reply.id = 0
Ole Troan9a475372019-03-05 16:58:24 +0100134 rx = self.send_and_expect(self.pg0, p4 * 10, self.pg1)
Ole Troan298c6952018-03-08 12:30:43 +0100135 for p in rx:
136 self.validate(p[1], p4_reply)
137
138 # Decapsulation
139 p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
140
141 # IPv4 tunnel to IPv4
142 p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
143 p4 = (p_ether / IP(src=self.pg1.remote_ip4,
144 dst=self.pg0.local_ip4) / p_ip4 / p_payload)
145 p4_reply = (p_ip4 / p_payload)
146 p4_reply.ttl -= 1
Ole Troan9a475372019-03-05 16:58:24 +0100147 rx = self.send_and_expect(self.pg1, p4 * 10, self.pg0)
Ole Troan298c6952018-03-08 12:30:43 +0100148 for p in rx:
149 self.validate(p[1], p4_reply)
150
Ole Troan233e4682019-05-16 15:01:34 +0200151 err = self.statistics.get_err_counter(
Ole Troan58492a82018-09-04 13:19:12 +0200152 '/err/ipip4-input/packets decapsulated')
153 self.assertEqual(err, 10)
Ole Troan73202102018-08-31 00:29:48 +0200154
Ole Troan298c6952018-03-08 12:30:43 +0100155 # IPv4 tunnel to IPv6
156 p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
157 p6 = (p_ether / IP(src=self.pg1.remote_ip4,
158 dst=self.pg0.local_ip4) / p_ip6 / p_payload)
159 p6_reply = (p_ip6 / p_payload)
160 p6_reply.hlim = 63
Ole Troan9a475372019-03-05 16:58:24 +0100161 rx = self.send_and_expect(self.pg1, p6 * 10, self.pg0)
Ole Troan298c6952018-03-08 12:30:43 +0100162 for p in rx:
163 self.validate(p[1], p6_reply)
164
Ole Troan233e4682019-05-16 15:01:34 +0200165 err = self.statistics.get_err_counter(
Ole Troan58492a82018-09-04 13:19:12 +0200166 '/err/ipip4-input/packets decapsulated')
167 self.assertEqual(err, 20)
Ole Troan73202102018-08-31 00:29:48 +0200168
Ole Troan7eb9d962018-08-10 14:39:48 +0200169 #
Ole Troan4146c652018-08-08 22:23:19 +0200170 # Fragmentation / Reassembly and Re-fragmentation
Ole Troan7eb9d962018-08-10 14:39:48 +0200171 #
Ole Troan4146c652018-08-08 22:23:19 +0200172 rv = self.vapi.ip_reassembly_enable_disable(
173 sw_if_index=self.pg1.sw_if_index,
174 enable_ip4=1)
Ole Troan4146c652018-08-08 22:23:19 +0200175
Klement Sekera3a343d42019-05-16 14:35:46 +0200176 self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=1000,
177 max_reassembly_length=1000,
178 expire_walk_interval_ms=10000,
179 is_ip6=0)
180
Ole Troan7eb9d962018-08-10 14:39:48 +0200181 # Send lots of fragments, verify reassembled packet
Ole Troan282093f2018-09-19 12:38:51 +0200182 frags, p4_reply = self.generate_ip4_frags(3131, 1400)
Ole Troan7eb9d962018-08-10 14:39:48 +0200183 f = []
184 for i in range(0, 1000):
185 f.extend(frags)
186 self.pg1.add_stream(f)
Ole Troan4146c652018-08-08 22:23:19 +0200187 self.pg_enable_capture()
Ole Troan4146c652018-08-08 22:23:19 +0200188 self.pg_start()
Ole Troan7eb9d962018-08-10 14:39:48 +0200189 rx = self.pg0.get_capture(1000)
190
Ole Troan4146c652018-08-08 22:23:19 +0200191 for p in rx:
192 self.validate(p[1], p4_reply)
193
Ole Troan233e4682019-05-16 15:01:34 +0200194 err = self.statistics.get_err_counter(
Ole Troan58492a82018-09-04 13:19:12 +0200195 '/err/ipip4-input/packets decapsulated')
196 self.assertEqual(err, 1020)
Ole Troan73202102018-08-31 00:29:48 +0200197
Ole Troan7eb9d962018-08-10 14:39:48 +0200198 f = []
199 r = []
200 for i in range(1, 90):
Ole Troan282093f2018-09-19 12:38:51 +0200201 frags, p4_reply = self.generate_ip4_frags(i * 100, 1000)
Ole Troan7eb9d962018-08-10 14:39:48 +0200202 f.extend(frags)
203 r.extend(p4_reply)
204 self.pg_enable_capture()
205 self.pg1.add_stream(f)
206 self.pg_start()
207 rx = self.pg0.get_capture(89)
208 i = 0
209 for p in rx:
210 self.validate(p[1], r[i])
211 i += 1
212
Ole Troan4146c652018-08-08 22:23:19 +0200213 # Now try with re-fragmentation
Ole Troan7eb9d962018-08-10 14:39:48 +0200214 #
215 # Send fragments to tunnel head-end, for the tunnel head end
216 # to reassemble and then refragment
217 #
Ole Troan4146c652018-08-08 22:23:19 +0200218 self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [576, 0, 0, 0])
Ole Troan282093f2018-09-19 12:38:51 +0200219 frags, p4_reply = self.generate_ip4_frags(3123, 1200)
Ole Troan4146c652018-08-08 22:23:19 +0200220 self.pg_enable_capture()
221 self.pg1.add_stream(frags)
222 self.pg_start()
223 rx = self.pg0.get_capture(6)
Ole Troan7f991832018-12-06 17:35:12 +0100224 reass_pkt = reassemble4(rx)
Ole Troan4146c652018-08-08 22:23:19 +0200225 p4_reply.ttl -= 1
226 p4_reply.id = 256
227 self.validate(reass_pkt, p4_reply)
228
Ole Troan7eb9d962018-08-10 14:39:48 +0200229 self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [1600, 0, 0, 0])
Ole Troan282093f2018-09-19 12:38:51 +0200230 frags, p4_reply = self.generate_ip4_frags(3123, 1200)
Ole Troan7eb9d962018-08-10 14:39:48 +0200231 self.pg_enable_capture()
232 self.pg1.add_stream(frags)
233 self.pg_start()
234 rx = self.pg0.get_capture(2)
Ole Troan7f991832018-12-06 17:35:12 +0100235 reass_pkt = reassemble4(rx)
Ole Troan7eb9d962018-08-10 14:39:48 +0200236 p4_reply.ttl -= 1
237 p4_reply.id = 512
238 self.validate(reass_pkt, p4_reply)
239
Ole Troan282093f2018-09-19 12:38:51 +0200240 def test_ipip_create(self):
241 """ ipip create / delete interface test """
Neale Rannscbd08242019-05-26 11:34:27 -0700242 rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5')
Ole Troan282093f2018-09-19 12:38:51 +0200243 sw_if_index = rv.sw_if_index
244 self.vapi.ipip_del_tunnel(sw_if_index)
Ole Troan298c6952018-03-08 12:30:43 +0100245
Ole Troan282093f2018-09-19 12:38:51 +0200246 def test_ipip_vrf_create(self):
247 """ ipip create / delete interface VRF test """
248
249 t = VppIpTable(self, 20)
250 t.add_vpp_config()
Neale Rannscbd08242019-05-26 11:34:27 -0700251 rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5', table_id=20)
Ole Troan282093f2018-09-19 12:38:51 +0200252 sw_if_index = rv.sw_if_index
253 self.vapi.ipip_del_tunnel(sw_if_index)
254
255 def payload(self, len):
256 return 'x' * len
257
258
259class TestIPIP6(VppTestCase):
260 """ IPIP6 Test Case """
261
262 @classmethod
263 def setUpClass(cls):
264 super(TestIPIP6, cls).setUpClass()
265 cls.create_pg_interfaces(range(2))
266 cls.interfaces = list(cls.pg_interfaces)
267
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -0700268 @classmethod
269 def tearDownClass(cls):
270 super(TestIPIP6, cls).tearDownClass()
271
Ole Troan282093f2018-09-19 12:38:51 +0200272 def setUp(self):
Paul Vinciguerra8d991d92019-01-25 14:05:48 -0800273 super(TestIPIP6, self).setUp()
Ole Troan282093f2018-09-19 12:38:51 +0200274 for i in self.interfaces:
275 i.admin_up()
276 i.config_ip4()
277 i.config_ip6()
278 i.disable_ipv6_ra()
279 i.resolve_arp()
280 i.resolve_ndp()
281 self.setup_tunnel()
282
283 def tearDown(self):
284 if not self.vpp_dead:
285 self.destroy_tunnel()
286 for i in self.pg_interfaces:
287 i.unconfig_ip4()
288 i.unconfig_ip6()
289 i.admin_down()
290 super(TestIPIP6, self).tearDown()
291
292 def setup_tunnel(self):
Ole Troan298c6952018-03-08 12:30:43 +0100293 # IPv6 transport
Neale Rannscbd08242019-05-26 11:34:27 -0700294 rv = ipip_add_tunnel(self,
295 self.pg0.local_ip6,
296 self.pg1.remote_ip6,
297 tc_tos=255)
Ole Troan298c6952018-03-08 12:30:43 +0100298
299 sw_if_index = rv.sw_if_index
Ole Troan282093f2018-09-19 12:38:51 +0200300 self.tunnel_if_index = sw_if_index
Ole Troan46c1c112018-03-14 20:39:40 +0100301 self.vapi.sw_interface_set_flags(sw_if_index, 1)
302 self.vapi.sw_interface_set_unnumbered(
Ole Troan9a475372019-03-05 16:58:24 +0100303 sw_if_index=self.pg0.sw_if_index,
304 unnumbered_sw_if_index=sw_if_index)
Ole Troan298c6952018-03-08 12:30:43 +0100305
306 # Add IPv4 and IPv6 routes via tunnel interface
307 ip4_via_tunnel = VppIpRoute(
308 self, "130.67.0.0", 16,
309 [VppRoutePath("0.0.0.0",
310 sw_if_index,
Neale Ranns097fa662018-05-01 05:17:55 -0700311 proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)])
Ole Troan298c6952018-03-08 12:30:43 +0100312 ip4_via_tunnel.add_vpp_config()
313
314 ip6_via_tunnel = VppIpRoute(
315 self, "dead::", 16,
316 [VppRoutePath("::",
317 sw_if_index,
Neale Ranns097fa662018-05-01 05:17:55 -0700318 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
Ole Troan298c6952018-03-08 12:30:43 +0100319 ip6_via_tunnel.add_vpp_config()
320
Ole Troan282093f2018-09-19 12:38:51 +0200321 self.tunnel_ip6_via_tunnel = ip6_via_tunnel
322 self.tunnel_ip4_via_tunnel = ip4_via_tunnel
Ole Troan298c6952018-03-08 12:30:43 +0100323
Ole Troan282093f2018-09-19 12:38:51 +0200324 def destroy_tunnel(self):
325 # IPv6 transport
326 self.tunnel_ip4_via_tunnel.remove_vpp_config()
327 self.tunnel_ip6_via_tunnel.remove_vpp_config()
328
329 rv = self.vapi.ipip_del_tunnel(sw_if_index=self.tunnel_if_index)
330
331 def validate(self, rx, expected):
Ole Troan7f991832018-12-06 17:35:12 +0100332 self.assertEqual(rx, expected.__class__(expected))
Ole Troan282093f2018-09-19 12:38:51 +0200333
334 def generate_ip6_frags(self, payload_length, fragment_size):
335 p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
336 p_payload = UDP(sport=1234, dport=1234) / self.payload(payload_length)
337 p_ip6 = IPv6(src="1::1", dst=self.pg0.remote_ip6)
338 outer_ip6 = (p_ether / IPv6(src=self.pg1.remote_ip6,
339 dst=self.pg0.local_ip6) /
340 IPv6ExtHdrFragment() / p_ip6 / p_payload)
341 frags = fragment6(outer_ip6, fragment_size)
342 p6_reply = (p_ip6 / p_payload)
343 p6_reply.hlim -= 1
344 return frags, p6_reply
345
346 def generate_ip6_hairpin_frags(self, payload_length, fragment_size):
347 p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
348 p_payload = UDP(sport=1234, dport=1234) / self.payload(payload_length)
349 p_ip6 = IPv6(src="1::1", dst="dead::1")
350 outer_ip6 = (p_ether / IPv6(src=self.pg1.remote_ip6,
351 dst=self.pg0.local_ip6) /
352 IPv6ExtHdrFragment() / p_ip6 / p_payload)
353 frags = fragment6(outer_ip6, fragment_size)
354 p_ip6.hlim -= 1
355 p6_reply = (IPv6(src=self.pg0.local_ip6, dst=self.pg1.remote_ip6,
356 hlim=63) / p_ip6 / p_payload)
357
358 return frags, p6_reply
359
360 def test_encap(self):
361 """ ip{v4,v6} over ip6 test encap """
362 p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
363 p_ip6 = IPv6(src="1::1", dst="DEAD::1", tc=42, nh='UDP')
364 p_ip4 = IP(src="1.2.3.4", dst="130.67.0.1", tos=42)
365 p_payload = UDP(sport=1234, dport=1234)
366
367 # Encapsulation
Ole Troan298c6952018-03-08 12:30:43 +0100368 # IPv6 in to IPv6 tunnel
369 p6 = (p_ether / p_ip6 / p_payload)
Ole Troand57f6362018-05-24 13:21:43 +0200370 p6_reply = (IPv6(src=self.pg0.local_ip6, dst=self.pg1.remote_ip6,
Ole Troan282093f2018-09-19 12:38:51 +0200371 hlim=64, tc=42) /
Ole Troand57f6362018-05-24 13:21:43 +0200372 p_ip6 / p_payload)
Ole Troan298c6952018-03-08 12:30:43 +0100373 p6_reply[1].hlim -= 1
Ole Troan9a475372019-03-05 16:58:24 +0100374 rx = self.send_and_expect(self.pg0, p6 * 11, self.pg1)
Ole Troan298c6952018-03-08 12:30:43 +0100375 for p in rx:
376 self.validate(p[1], p6_reply)
377
378 # IPv4 in to IPv6 tunnel
379 p4 = (p_ether / p_ip4 / p_payload)
380 p4_reply = (IPv6(src=self.pg0.local_ip6,
Ole Troan282093f2018-09-19 12:38:51 +0200381 dst=self.pg1.remote_ip6, hlim=64, tc=42) /
Ole Troand57f6362018-05-24 13:21:43 +0200382 p_ip4 / p_payload)
Ole Troan298c6952018-03-08 12:30:43 +0100383 p4_reply[1].ttl -= 1
Ole Troan9a475372019-03-05 16:58:24 +0100384 rx = self.send_and_expect(self.pg0, p4 * 11, self.pg1)
Ole Troan298c6952018-03-08 12:30:43 +0100385 for p in rx:
386 self.validate(p[1], p4_reply)
387
Ole Troan282093f2018-09-19 12:38:51 +0200388 def test_decap(self):
389 """ ip{v4,v6} over ip6 test decap """
Ole Troan298c6952018-03-08 12:30:43 +0100390
391 p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
Ole Troan282093f2018-09-19 12:38:51 +0200392 p_ip6 = IPv6(src="1::1", dst="DEAD::1", tc=42, nh='UDP')
Ole Troan298c6952018-03-08 12:30:43 +0100393 p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
Ole Troan282093f2018-09-19 12:38:51 +0200394 p_payload = UDP(sport=1234, dport=1234)
395
396 # Decapsulation
397 # IPv6 tunnel to IPv4
398
Ole Troan298c6952018-03-08 12:30:43 +0100399 p4 = (p_ether / IPv6(src=self.pg1.remote_ip6,
400 dst=self.pg0.local_ip6) / p_ip4 / p_payload)
401 p4_reply = (p_ip4 / p_payload)
402 p4_reply.ttl -= 1
Ole Troan9a475372019-03-05 16:58:24 +0100403 rx = self.send_and_expect(self.pg1, p4 * 11, self.pg0)
Ole Troan298c6952018-03-08 12:30:43 +0100404 for p in rx:
405 self.validate(p[1], p4_reply)
406
407 # IPv6 tunnel to IPv6
408 p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
409 p6 = (p_ether / IPv6(src=self.pg1.remote_ip6,
410 dst=self.pg0.local_ip6) / p_ip6 / p_payload)
411 p6_reply = (p_ip6 / p_payload)
412 p6_reply.hlim = 63
Ole Troan9a475372019-03-05 16:58:24 +0100413 rx = self.send_and_expect(self.pg1, p6 * 11, self.pg0)
Ole Troan298c6952018-03-08 12:30:43 +0100414 for p in rx:
415 self.validate(p[1], p6_reply)
416
Ole Troan282093f2018-09-19 12:38:51 +0200417 def test_frag(self):
418 """ ip{v4,v6} over ip6 test frag """
419
420 p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
421 p_ip6 = IPv6(src="1::1", dst="DEAD::1", tc=42, nh='UDP')
422 p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
423 p_payload = UDP(sport=1234, dport=1234)
424
425 #
426 # Fragmentation / Reassembly and Re-fragmentation
427 #
428 rv = self.vapi.ip_reassembly_enable_disable(
429 sw_if_index=self.pg1.sw_if_index,
430 enable_ip6=1)
431
Klement Sekera3a343d42019-05-16 14:35:46 +0200432 self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=1000,
433 max_reassembly_length=1000,
434 expire_walk_interval_ms=10000,
435 is_ip6=1)
436
Ole Troan282093f2018-09-19 12:38:51 +0200437 # Send lots of fragments, verify reassembled packet
Ole Troan233e4682019-05-16 15:01:34 +0200438 before_cnt = self.statistics.get_err_counter(
Ole Troan282093f2018-09-19 12:38:51 +0200439 '/err/ipip6-input/packets decapsulated')
440 frags, p6_reply = self.generate_ip6_frags(3131, 1400)
441 f = []
442 for i in range(0, 1000):
443 f.extend(frags)
444 self.pg1.add_stream(f)
445 self.pg_enable_capture()
446 self.pg_start()
447 rx = self.pg0.get_capture(1000)
448
449 for p in rx:
450 self.validate(p[1], p6_reply)
451
Ole Troan233e4682019-05-16 15:01:34 +0200452 cnt = self.statistics.get_err_counter(
Ole Troan282093f2018-09-19 12:38:51 +0200453 '/err/ipip6-input/packets decapsulated')
454 self.assertEqual(cnt, before_cnt + 1000)
455
456 f = []
457 r = []
458 # TODO: Check out why reassembly of atomic fragments don't work
459 for i in range(10, 90):
460 frags, p6_reply = self.generate_ip6_frags(i * 100, 1000)
461 f.extend(frags)
462 r.extend(p6_reply)
463 self.pg_enable_capture()
464 self.pg1.add_stream(f)
465 self.pg_start()
466 rx = self.pg0.get_capture(80)
467 i = 0
468 for p in rx:
469 self.validate(p[1], r[i])
470 i += 1
471
472 # Simple fragmentation
473 p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
474 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1280, 0, 0, 0])
475
476 # IPv6 in to IPv6 tunnel
477 p_payload = UDP(sport=1234, dport=1234) / self.payload(1300)
478
479 p6 = (p_ether / p_ip6 / p_payload)
480 p6_reply = (IPv6(src=self.pg0.local_ip6, dst=self.pg1.remote_ip6,
481 hlim=63, tc=42) /
482 p_ip6 / p_payload)
483 p6_reply[1].hlim -= 1
484 self.pg_enable_capture()
485 self.pg0.add_stream(p6)
486 self.pg_start()
487 rx = self.pg1.get_capture(2)
488
489 # Scapy defragment doesn't deal well with multiple layers
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700490 # of same type / Ethernet header first
Ole Troan282093f2018-09-19 12:38:51 +0200491 f = [p[1] for p in rx]
492 reass_pkt = defragment6(f)
493 self.validate(reass_pkt, p6_reply)
494
495 # Now try with re-fragmentation
496 #
497 # Send large fragments to tunnel head-end, for the tunnel head end
498 # to reassemble and then refragment out the tunnel again.
499 # Hair-pinning
500 #
501 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1280, 0, 0, 0])
502 frags, p6_reply = self.generate_ip6_hairpin_frags(8000, 1200)
503 self.pg_enable_capture()
504 self.pg1.add_stream(frags)
505 self.pg_start()
506 rx = self.pg1.get_capture(7)
507 f = [p[1] for p in rx]
508 reass_pkt = defragment6(f)
509 p6_reply.id = 256
510 self.validate(reass_pkt, p6_reply)
511
Ole Troan298c6952018-03-08 12:30:43 +0100512 def test_ipip_create(self):
513 """ ipip create / delete interface test """
Neale Rannscbd08242019-05-26 11:34:27 -0700514 rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5')
Ole Troan298c6952018-03-08 12:30:43 +0100515 sw_if_index = rv.sw_if_index
Ole Troan46c1c112018-03-14 20:39:40 +0100516 self.vapi.ipip_del_tunnel(sw_if_index)
Ole Troan298c6952018-03-08 12:30:43 +0100517
Neale Ranns61502112018-08-22 00:21:14 -0700518 def test_ipip_vrf_create(self):
519 """ ipip create / delete interface VRF test """
520
521 t = VppIpTable(self, 20)
522 t.add_vpp_config()
Neale Rannscbd08242019-05-26 11:34:27 -0700523 rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5', table_id=20)
Neale Ranns61502112018-08-22 00:21:14 -0700524 sw_if_index = rv.sw_if_index
525 self.vapi.ipip_del_tunnel(sw_if_index)
526
Ole Troan4146c652018-08-08 22:23:19 +0200527 def payload(self, len):
528 return 'x' * len
529
Ole Troan298c6952018-03-08 12:30:43 +0100530
531if __name__ == '__main__':
532 unittest.main(testRunner=VppTestRunner)