blob: 09a9960431116aaef66df193fbea01f34154b052 [file] [log] [blame]
Renato Botelho do Coutoead1e532019-10-31 13:31:07 -05001#!/usr/bin/env python3
Eyal Baricef1e2a2018-06-18 13:01:59 +03002
Eyal Baricef1e2a2018-06-18 13:01:59 +03003import unittest
Dave Wallace8800f732023-08-31 00:47:44 -04004from framework import VppTestCase
5from asfframework import VppTestRunner
Eyal Baricef1e2a2018-06-18 13:01:59 +03006from template_bd import BridgeDomain
7
8from scapy.layers.l2 import Ether
Artem Glazychev839dcc02020-12-01 02:39:21 +07009from scapy.packet import Raw, bind_layers
Vladimir Isaev698eb872020-05-21 16:34:17 +030010from scapy.layers.inet6 import IP, IPv6, UDP
Eyal Baricef1e2a2018-06-18 13:01:59 +030011from scapy.layers.vxlan import VXLAN
Paul Vinciguerra2f156312020-05-02 22:34:40 -040012
13import util
Neale Ranns097fa662018-05-01 05:17:55 -070014from vpp_ip_route import VppIpRoute, VppRoutePath
Jakub Grajciar7c0eb562020-03-02 13:55:31 +010015from vpp_vxlan_tunnel import VppVxlanTunnel
Neale Ranns097fa662018-05-01 05:17:55 -070016from vpp_ip import INVALID_INDEX
Dmitry Valter34fa0ce2024-03-11 10:38:46 +000017from config import config
Eyal Baricef1e2a2018-06-18 13:01:59 +030018
19
Dmitry Valter34fa0ce2024-03-11 10:38:46 +000020@unittest.skipIf("vxlan" in config.excluded_plugins, "Exclude VXLAN plugin tests")
Eyal Baridd47eca2018-07-08 08:15:56 +030021class TestVxlan6(BridgeDomain, VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020022 """VXLAN over IPv6 Test Case"""
Eyal Baricef1e2a2018-06-18 13:01:59 +030023
24 def __init__(self, *args):
25 BridgeDomain.__init__(self)
26 VppTestCase.__init__(self, *args)
27
28 def encapsulate(self, pkt, vni):
29 """
30 Encapsulate the original payload frame by adding VXLAN header with its
31 UDP, IP and Ethernet fields
32 """
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020033 return (
34 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
35 / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6)
36 / UDP(sport=self.dport, dport=self.dport, chksum=0)
37 / VXLAN(vni=vni, flags=self.flags)
38 / pkt
39 )
Eyal Baricef1e2a2018-06-18 13:01:59 +030040
41 @classmethod
42 def ip_range(cls, s, e):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020043 """range of remote ip's"""
44 tmp = cls.pg0.remote_ip6.rsplit(":", 1)[0]
Eyal Baricef1e2a2018-06-18 13:01:59 +030045 return ("%s:%x" % (tmp, i) for i in range(s, e))
46
47 def encap_mcast(self, pkt, src_ip, src_mac, vni):
48 """
49 Encapsulate the original payload frame by adding VXLAN header with its
50 UDP, IP and Ethernet fields
51 """
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020052 return (
53 Ether(src=src_mac, dst=self.mcast_mac)
54 / IPv6(src=src_ip, dst=self.mcast_ip6)
55 / UDP(sport=self.dport, dport=self.dport, chksum=0)
56 / VXLAN(vni=vni, flags=self.flags)
57 / pkt
58 )
Eyal Baricef1e2a2018-06-18 13:01:59 +030059
60 def decapsulate(self, pkt):
61 """
62 Decapsulate the original payload frame by removing VXLAN header
63 """
64 # check if is set I flag
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020065 self.assertEqual(pkt[VXLAN].flags, int("0x8", 16))
Eyal Baricef1e2a2018-06-18 13:01:59 +030066 return pkt[VXLAN].payload
67
68 # Method for checking VXLAN encapsulation.
69 #
70 def check_encapsulation(self, pkt, vni, local_only=False, mcast_pkt=False):
71 # TODO: add error messages
72 # Verify source MAC is VPP_MAC and destination MAC is MY_MAC resolved
73 # by VPP using ARP.
74 self.assertEqual(pkt[Ether].src, self.pg0.local_mac)
75 if not local_only:
76 if not mcast_pkt:
77 self.assertEqual(pkt[Ether].dst, self.pg0.remote_mac)
78 else:
79 self.assertEqual(pkt[Ether].dst, type(self).mcast_mac)
80 # Verify VXLAN tunnel source IP is VPP_IP and destination IP is MY_IP.
81 self.assertEqual(pkt[IPv6].src, self.pg0.local_ip6)
82 if not local_only:
83 if not mcast_pkt:
84 self.assertEqual(pkt[IPv6].dst, self.pg0.remote_ip6)
85 else:
86 self.assertEqual(pkt[IPv6].dst, type(self).mcast_ip6)
87 # Verify UDP destination port is VXLAN 4789, source UDP port could be
88 # arbitrary.
Artem Glazychev839dcc02020-12-01 02:39:21 +070089 self.assertEqual(pkt[UDP].dport, self.dport)
Vladimir Isaev698eb872020-05-21 16:34:17 +030090 # Verify UDP checksum
91 self.assert_udp_checksum_valid(pkt, ignore_zero_checksum=False)
Eyal Baricef1e2a2018-06-18 13:01:59 +030092 # Verify VNI
93 self.assertEqual(pkt[VXLAN].vni, vni)
94
95 @classmethod
Artem Glazychev839dcc02020-12-01 02:39:21 +070096 def create_vxlan_flood_test_bd(cls, vni, n_ucast_tunnels, port):
Eyal Baricef1e2a2018-06-18 13:01:59 +030097 # Create 10 ucast vxlan tunnels under bd
98 start = 10
99 end = start + n_ucast_tunnels
Eyal Baricef1e2a2018-06-18 13:01:59 +0300100 for dest_ip6 in cls.ip_range(start, end):
Eyal Baricef1e2a2018-06-18 13:01:59 +0300101 # add host route so dest ip will not be resolved
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200102 rip = VppIpRoute(
103 cls,
104 dest_ip6,
105 128,
106 [VppRoutePath(cls.pg0.remote_ip6, INVALID_INDEX)],
107 register=False,
108 )
Neale Ranns097fa662018-05-01 05:17:55 -0700109 rip.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200110 r = VppVxlanTunnel(
111 cls,
112 src=cls.pg0.local_ip6,
113 src_port=port,
114 dst_port=port,
115 dst=dest_ip6,
116 vni=vni,
117 )
Jakub Grajciar7c0eb562020-03-02 13:55:31 +0100118 r.add_vpp_config()
Neale Ranns097fa662018-05-01 05:17:55 -0700119 cls.vapi.sw_interface_set_l2_bridge(r.sw_if_index, bd_id=vni)
Eyal Baricef1e2a2018-06-18 13:01:59 +0300120
121 @classmethod
122 def add_mcast_tunnels_load(cls):
123 cls.add_del_mcast_tunnels_load(is_add=1)
124
125 @classmethod
126 def del_mcast_tunnels_load(cls):
127 cls.add_del_mcast_tunnels_load(is_add=0)
128
129 # Class method to start the VXLAN test case.
130 # Overrides setUpClass method in VppTestCase class.
131 # Python try..except statement is used to ensure that the tear down of
132 # the class will be executed even if exception is raised.
133 # @param cls The class pointer.
134 @classmethod
135 def setUpClass(cls):
Eyal Baridd47eca2018-07-08 08:15:56 +0300136 super(TestVxlan6, cls).setUpClass()
Eyal Baricef1e2a2018-06-18 13:01:59 +0300137
138 try:
Eyal Baricef1e2a2018-06-18 13:01:59 +0300139 cls.flags = 0x8
140
141 # Create 2 pg interfaces.
142 cls.create_pg_interfaces(range(4))
143 for pg in cls.pg_interfaces:
144 pg.admin_up()
145
Paul Vinciguerra2f156312020-05-02 22:34:40 -0400146 # Configure IPv6 addresses on VPP pg0.
Eyal Baricef1e2a2018-06-18 13:01:59 +0300147 cls.pg0.config_ip6()
148
149 # Resolve MAC address for VPP's IP address on pg0.
150 cls.pg0.resolve_ndp()
151
Paul Vinciguerra2f156312020-05-02 22:34:40 -0400152 # Our Multicast address
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200153 cls.mcast_ip6 = "ff0e::1"
Paul Vinciguerra2f156312020-05-02 22:34:40 -0400154 cls.mcast_mac = util.mcast_ip_to_mac(cls.mcast_ip6)
Eyal Baricef1e2a2018-06-18 13:01:59 +0300155 except Exception:
Eyal Baridd47eca2018-07-08 08:15:56 +0300156 super(TestVxlan6, cls).tearDownClass()
Eyal Baricef1e2a2018-06-18 13:01:59 +0300157 raise
158
Paul Vinciguerra8d991d92019-01-25 14:05:48 -0800159 @classmethod
160 def tearDownClass(cls):
161 super(TestVxlan6, cls).tearDownClass()
162
Jakub Grajciar7c0eb562020-03-02 13:55:31 +0100163 def setUp(self):
164 super(TestVxlan6, self).setUp()
Artem Glazychev839dcc02020-12-01 02:39:21 +0700165
166 def createVxLANInterfaces(self, port=4789):
Jakub Grajciar7c0eb562020-03-02 13:55:31 +0100167 # Create VXLAN VTEP on VPP pg0, and put vxlan_tunnel0 and pg1
168 # into BD.
Artem Glazychev839dcc02020-12-01 02:39:21 +0700169 self.dport = port
170
Neale Ranns91fd9102020-04-03 07:46:28 +0000171 self.single_tunnel_vni = 0x12345
Jakub Grajciar7c0eb562020-03-02 13:55:31 +0100172 self.single_tunnel_bd = 1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200173 r = VppVxlanTunnel(
174 self,
175 src=self.pg0.local_ip6,
176 dst=self.pg0.remote_ip6,
177 src_port=self.dport,
178 dst_port=self.dport,
179 vni=self.single_tunnel_vni,
180 )
Jakub Grajciar7c0eb562020-03-02 13:55:31 +0100181 r.add_vpp_config()
Jakub Grajciar7c0eb562020-03-02 13:55:31 +0100182 self.vapi.sw_interface_set_l2_bridge(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200183 rx_sw_if_index=r.sw_if_index, bd_id=self.single_tunnel_bd
184 )
185 self.vapi.sw_interface_set_l2_bridge(
186 rx_sw_if_index=self.pg1.sw_if_index, bd_id=self.single_tunnel_bd
187 )
Jakub Grajciar7c0eb562020-03-02 13:55:31 +0100188
189 # Setup vni 2 to test multicast flooding
190 self.n_ucast_tunnels = 10
191 self.mcast_flood_bd = 2
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200192 self.create_vxlan_flood_test_bd(
193 self.mcast_flood_bd, self.n_ucast_tunnels, self.dport
194 )
195 r = VppVxlanTunnel(
196 self,
197 src=self.pg0.local_ip6,
198 dst=self.mcast_ip6,
199 src_port=self.dport,
200 dst_port=self.dport,
201 mcast_sw_if_index=1,
202 vni=self.mcast_flood_bd,
203 )
Jakub Grajciar7c0eb562020-03-02 13:55:31 +0100204 r.add_vpp_config()
Jakub Grajciar7c0eb562020-03-02 13:55:31 +0100205 self.vapi.sw_interface_set_l2_bridge(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200206 rx_sw_if_index=r.sw_if_index, bd_id=self.mcast_flood_bd
207 )
208 self.vapi.sw_interface_set_l2_bridge(
209 rx_sw_if_index=self.pg2.sw_if_index, bd_id=self.mcast_flood_bd
210 )
Jakub Grajciar7c0eb562020-03-02 13:55:31 +0100211
212 # Setup vni 3 to test unicast flooding
213 self.ucast_flood_bd = 3
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200214 self.create_vxlan_flood_test_bd(
215 self.ucast_flood_bd, self.n_ucast_tunnels, self.dport
216 )
Jakub Grajciar7c0eb562020-03-02 13:55:31 +0100217 self.vapi.sw_interface_set_l2_bridge(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200218 rx_sw_if_index=self.pg3.sw_if_index, bd_id=self.ucast_flood_bd
219 )
Jakub Grajciar7c0eb562020-03-02 13:55:31 +0100220
Artem Glazychev839dcc02020-12-01 02:39:21 +0700221 # Set scapy listen custom port for VxLAN
222 bind_layers(UDP, VXLAN, dport=self.dport)
223
Eyal Baricef1e2a2018-06-18 13:01:59 +0300224 # Method to define VPP actions before tear down of the test case.
225 # Overrides tearDown method in VppTestCase class.
226 # @param self The object pointer.
227 def tearDown(self):
Eyal Baridd47eca2018-07-08 08:15:56 +0300228 super(TestVxlan6, self).tearDown()
Paul Vinciguerra90cf21b2019-03-13 09:23:05 -0700229
230 def show_commands_at_teardown(self):
231 self.logger.info(self.vapi.cli("show bridge-domain 1 detail"))
232 self.logger.info(self.vapi.cli("show bridge-domain 2 detail"))
233 self.logger.info(self.vapi.cli("show bridge-domain 3 detail"))
234 self.logger.info(self.vapi.cli("show vxlan tunnel"))
Eyal Baricef1e2a2018-06-18 13:01:59 +0300235
Artem Glazychev839dcc02020-12-01 02:39:21 +0700236 def encap_fragmented_packet(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200237 frame = (
238 Ether(src="00:00:00:00:00:02", dst="00:00:00:00:00:01")
239 / IP(src="4.3.2.1", dst="1.2.3.4")
240 / UDP(sport=20000, dport=10000)
241 / Raw(b"\xa5" * 1000)
242 )
Vladimir Isaev698eb872020-05-21 16:34:17 +0300243
244 frags = util.fragment_rfc791(frame, 400)
245
246 self.pg1.add_stream(frags)
247
248 self.pg0.enable_capture()
249
250 self.pg_start()
251
252 out = self.pg0.get_capture(3)
253
254 payload = []
255 for pkt in out:
256 payload.append(self.decapsulate(pkt))
257 self.check_encapsulation(pkt, self.single_tunnel_vni)
258
259 reassembled = util.reassemble4(payload)
260
Dave Wallacecf9356d2024-07-23 01:28:19 -0400261 self.assertEqual(Ether(bytes(frame))[IP], reassembled[IP])
Vladimir Isaev698eb872020-05-21 16:34:17 +0300262
Artem Glazychev839dcc02020-12-01 02:39:21 +0700263 """
264 Tests with default port (4789)
265 """
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200266
Artem Glazychev839dcc02020-12-01 02:39:21 +0700267 def test_decap(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200268 """Decapsulation test
Artem Glazychev839dcc02020-12-01 02:39:21 +0700269 from BridgeDoman
270 """
271 self.createVxLANInterfaces()
272 super(TestVxlan6, self).test_decap()
273
274 def test_encap(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200275 """Encapsulation test
Artem Glazychev839dcc02020-12-01 02:39:21 +0700276 from BridgeDoman
277 """
278 self.createVxLANInterfaces()
279 super(TestVxlan6, self).test_encap()
280
281 def test_encap_fragmented_packet(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200282 """Encapsulation test send fragments from pg1
Artem Glazychev839dcc02020-12-01 02:39:21 +0700283 Verify receipt of encapsulated frames on pg0
284 """
285 self.createVxLANInterfaces()
286 self.encap_fragmented_packet()
287
288 def test_ucast_flood(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200289 """Unicast flood test
Artem Glazychev839dcc02020-12-01 02:39:21 +0700290 from BridgeDoman
291 """
292 self.createVxLANInterfaces()
293 super(TestVxlan6, self).test_ucast_flood()
294
295 def test_mcast_flood(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200296 """Multicast flood test
Artem Glazychev839dcc02020-12-01 02:39:21 +0700297 from BridgeDoman
298 """
299 self.createVxLANInterfaces()
300 super(TestVxlan6, self).test_mcast_flood()
301
302 def test_mcast_rcv(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200303 """Multicast receive test
Artem Glazychev839dcc02020-12-01 02:39:21 +0700304 from BridgeDoman
305 """
306 self.createVxLANInterfaces()
307 super(TestVxlan6, self).test_mcast_rcv()
308
309 """
310 Tests with custom port
311 """
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200312
Artem Glazychev839dcc02020-12-01 02:39:21 +0700313 def test_decap_custom_port(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200314 """Decapsulation test custom port
Artem Glazychev839dcc02020-12-01 02:39:21 +0700315 from BridgeDoman
316 """
317 self.createVxLANInterfaces(1111)
318 super(TestVxlan6, self).test_decap()
319
320 def test_encap_custom_port(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200321 """Encapsulation test custom port
Artem Glazychev839dcc02020-12-01 02:39:21 +0700322 from BridgeDoman
323 """
324 self.createVxLANInterfaces(1111)
325 super(TestVxlan6, self).test_encap()
326
327 def test_ucast_flood_custom_port(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200328 """Unicast flood test custom port
Artem Glazychev839dcc02020-12-01 02:39:21 +0700329 from BridgeDoman
330 """
331 self.createVxLANInterfaces(1111)
332 super(TestVxlan6, self).test_ucast_flood()
333
334 def test_mcast_flood_custom_port(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200335 """Multicast flood test custom port
Artem Glazychev839dcc02020-12-01 02:39:21 +0700336 from BridgeDoman
337 """
338 self.createVxLANInterfaces(1111)
339 super(TestVxlan6, self).test_mcast_flood()
340
341 def test_mcast_rcv_custom_port(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200342 """Multicast receive test custom port
Artem Glazychev839dcc02020-12-01 02:39:21 +0700343 from BridgeDoman
344 """
345 self.createVxLANInterfaces(1111)
346 super(TestVxlan6, self).test_mcast_rcv()
347
Eyal Baricef1e2a2018-06-18 13:01:59 +0300348
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200349if __name__ == "__main__":
Eyal Baricef1e2a2018-06-18 13:01:59 +0300350 unittest.main(testRunner=VppTestRunner)