http: ignore http_proxy env in tests
[vpp.git] / test / test_vxlan_gpe.py
1 #!/usr/bin/env python3
2
3 from util import ip4_range
4 import unittest
5 from config import config
6 from framework import VppTestCase
7 from asfframework import VppTestRunner
8 from template_bd import BridgeDomain
9
10 from scapy.layers.l2 import Ether
11 from scapy.packet import bind_layers
12 from scapy.layers.inet import IP, UDP
13 from scapy.layers.vxlan import VXLAN
14
15 import util
16 from vpp_ip_route import VppIpRoute, VppRoutePath
17 from vpp_vxlan_gpe_tunnel import VppVxlanGpeTunnel
18 from vpp_ip import INVALID_INDEX
19
20
21 @unittest.skipUnless(config.extended, "part of extended tests")
22 class TestVxlanGpe(BridgeDomain, VppTestCase):
23     """VXLAN-GPE Test Case"""
24
25     def __init__(self, *args):
26         BridgeDomain.__init__(self)
27         VppTestCase.__init__(self, *args)
28
29     def encapsulate(self, pkt, vni):
30         """
31         Encapsulate the original payload frame by adding VXLAN-GPE header
32         with its UDP, IP and Ethernet fields
33         """
34         return (
35             Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
36             / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4)
37             / UDP(sport=self.dport, dport=self.dport, chksum=0)
38             / VXLAN(vni=vni, flags=self.flags)
39             / pkt
40         )
41
42     def ip_range(self, start, end):
43         """range of remote ip's"""
44         return ip4_range(self.pg0.remote_ip4, start, end)
45
46     def encap_mcast(self, pkt, src_ip, src_mac, vni):
47         """
48         Encapsulate the original payload frame by adding VXLAN-GPE header
49         with its UDP, IP and Ethernet fields
50         """
51         return (
52             Ether(src=src_mac, dst=self.mcast_mac)
53             / IP(src=src_ip, dst=self.mcast_ip4)
54             / UDP(sport=self.dport, dport=self.dport, chksum=0)
55             / VXLAN(vni=vni, flags=self.flags)
56             / pkt
57         )
58
59     def decapsulate(self, pkt):
60         """
61         Decapsulate the original payload frame by removing VXLAN-GPE header
62         """
63         # check if is set I and P flag
64         self.assertEqual(pkt[VXLAN].flags, 0x0C)
65         return pkt[VXLAN].payload
66
67     # Method for checking VXLAN-GPE encapsulation.
68     #
69     def check_encapsulation(self, pkt, vni, local_only=False, mcast_pkt=False):
70         # Verify source MAC is VPP_MAC and destination MAC is MY_MAC resolved
71         #  by VPP using ARP.
72         self.assertEqual(pkt[Ether].src, self.pg0.local_mac)
73         if not local_only:
74             if not mcast_pkt:
75                 self.assertEqual(pkt[Ether].dst, self.pg0.remote_mac)
76             else:
77                 self.assertEqual(pkt[Ether].dst, type(self).mcast_mac)
78         # Verify VXLAN-GPE tunnel src IP is VPP_IP and dst IP is MY_IP.
79         self.assertEqual(pkt[IP].src, self.pg0.local_ip4)
80         if not local_only:
81             if not mcast_pkt:
82                 self.assertEqual(pkt[IP].dst, self.pg0.remote_ip4)
83             else:
84                 self.assertEqual(pkt[IP].dst, type(self).mcast_ip4)
85         # Verify UDP destination port is VXLAN-GPE 4790, source UDP port
86         #  could be arbitrary.
87         self.assertEqual(pkt[UDP].dport, self.dport)
88         # Verify UDP checksum
89         self.assert_udp_checksum_valid(pkt)
90         # Verify VNI
91         self.assertEqual(pkt[VXLAN].vni, vni)
92
93     @classmethod
94     def create_vxlan_gpe_flood_test_bd(cls, vni, n_ucast_tunnels, port):
95         # Create 10 ucast vxlan tunnels under bd
96         ip_range_start = 10
97         ip_range_end = ip_range_start + n_ucast_tunnels
98         next_hop_address = cls.pg0.remote_ip4
99         for dest_ip4 in ip4_range(next_hop_address, ip_range_start, ip_range_end):
100             # add host route so dest_ip4n will not be resolved
101             rip = VppIpRoute(
102                 cls,
103                 dest_ip4,
104                 32,
105                 [VppRoutePath(next_hop_address, INVALID_INDEX)],
106                 register=False,
107             )
108             rip.add_vpp_config()
109
110             r = VppVxlanGpeTunnel(
111                 cls,
112                 src_addr=cls.pg0.local_ip4,
113                 dst_addr=dest_ip4,
114                 src_port=port,
115                 dst_port=port,
116                 vni=vni,
117             )
118             r.add_vpp_config()
119             cls.vapi.sw_interface_set_l2_bridge(rx_sw_if_index=r.sw_if_index, bd_id=vni)
120
121     @classmethod
122     def add_del_shared_mcast_dst_load(cls, port, is_add):
123         """
124         add or del tunnels sharing the same mcast dst
125         to test vxlan_gpe ref_count mechanism
126         """
127         n_shared_dst_tunnels = 20
128         vni_start = 1000
129         vni_end = vni_start + n_shared_dst_tunnels
130         for vni in range(vni_start, vni_end):
131             r = VppVxlanGpeTunnel(
132                 cls,
133                 src_addr=cls.pg0.local_ip4,
134                 dst_addr=cls.mcast_ip4,
135                 src_port=port,
136                 dst_port=port,
137                 mcast_sw_if_index=1,
138                 vni=vni,
139             )
140             if is_add:
141                 r.add_vpp_config()
142                 if r.sw_if_index == 0xFFFFFFFF:
143                     raise ValueError("bad sw_if_index: ~0")
144             else:
145                 r.remove_vpp_config()
146
147     @classmethod
148     def add_shared_mcast_dst_load(cls, port):
149         cls.add_del_shared_mcast_dst_load(port=port, is_add=1)
150
151     @classmethod
152     def del_shared_mcast_dst_load(cls, port):
153         cls.add_del_shared_mcast_dst_load(port=port, is_add=0)
154
155     @classmethod
156     def add_del_mcast_tunnels_load(cls, port, is_add):
157         """
158         add or del tunnels to test vxlan_gpe stability
159         """
160         n_distinct_dst_tunnels = 20
161         ip_range_start = 10
162         ip_range_end = ip_range_start + n_distinct_dst_tunnels
163         for dest_ip4 in ip4_range(cls.mcast_ip4, ip_range_start, ip_range_end):
164             vni = int(dest_ip4.split(".")[3])
165             r = VppVxlanGpeTunnel(
166                 cls,
167                 src_addr=cls.pg0.local_ip4,
168                 dst_addr=dest_ip4,
169                 src_port=port,
170                 dst_port=port,
171                 mcast_sw_if_index=1,
172                 vni=vni,
173             )
174             if is_add:
175                 r.add_vpp_config()
176             else:
177                 r.remove_vpp_config()
178
179     @classmethod
180     def add_mcast_tunnels_load(cls, port):
181         cls.add_del_mcast_tunnels_load(port=port, is_add=1)
182
183     @classmethod
184     def del_mcast_tunnels_load(cls, port):
185         cls.add_del_mcast_tunnels_load(port=port, is_add=0)
186
187     # Class method to start the VXLAN-GPE test case.
188     #  Overrides setUpClass method in VppTestCase class.
189     #  Python try..except statement is used to ensure that the tear down of
190     #  the class will be executed even if exception is raised.
191     #  @param cls The class pointer.
192     @classmethod
193     def setUpClass(cls):
194         super(TestVxlanGpe, cls).setUpClass()
195
196         try:
197             cls.flags = 0x0C
198
199             # Create 2 pg interfaces.
200             cls.create_pg_interfaces(range(4))
201             for pg in cls.pg_interfaces:
202                 pg.admin_up()
203
204             # Configure IPv4 addresses on VPP pg0.
205             cls.pg0.config_ip4()
206
207             # Resolve MAC address for VPP's IP address on pg0.
208             cls.pg0.resolve_arp()
209
210             # Our Multicast address
211             cls.mcast_ip4 = "239.1.1.1"
212             cls.mcast_mac = util.mcast_ip_to_mac(cls.mcast_ip4)
213         except Exception:
214             cls.tearDownClass()
215             raise
216
217     @classmethod
218     def tearDownClass(cls):
219         super(TestVxlanGpe, cls).tearDownClass()
220
221     def setUp(self):
222         super(TestVxlanGpe, self).setUp()
223
224     def createVxLANInterfaces(self, port=4790):
225         # Create VXLAN-GPE VTEP on VPP pg0, and put vxlan_gpe_tunnel0
226         # and pg1 into BD.
227         self.dport = port
228
229         self.single_tunnel_vni = 0xABCDE
230         self.single_tunnel_bd = 11
231         r = VppVxlanGpeTunnel(
232             self,
233             src_addr=self.pg0.local_ip4,
234             dst_addr=self.pg0.remote_ip4,
235             src_port=port,
236             dst_port=port,
237             vni=self.single_tunnel_vni,
238         )
239         r.add_vpp_config()
240         self.vapi.sw_interface_set_l2_bridge(
241             rx_sw_if_index=r.sw_if_index, bd_id=self.single_tunnel_bd
242         )
243         self.vapi.sw_interface_set_l2_bridge(
244             rx_sw_if_index=self.pg1.sw_if_index, bd_id=self.single_tunnel_bd
245         )
246
247         # Setup vni 2 to test multicast flooding
248         self.n_ucast_tunnels = 10
249         self.mcast_flood_bd = 12
250         self.create_vxlan_gpe_flood_test_bd(
251             self.mcast_flood_bd, self.n_ucast_tunnels, self.dport
252         )
253         r = VppVxlanGpeTunnel(
254             self,
255             src_addr=self.pg0.local_ip4,
256             dst_addr=self.mcast_ip4,
257             src_port=port,
258             dst_port=port,
259             mcast_sw_if_index=1,
260             vni=self.mcast_flood_bd,
261         )
262         r.add_vpp_config()
263         self.vapi.sw_interface_set_l2_bridge(
264             rx_sw_if_index=r.sw_if_index, bd_id=self.mcast_flood_bd
265         )
266         self.vapi.sw_interface_set_l2_bridge(
267             rx_sw_if_index=self.pg2.sw_if_index, bd_id=self.mcast_flood_bd
268         )
269
270         # Add and delete mcast tunnels to check stability
271         self.add_shared_mcast_dst_load(self.dport)
272         self.add_mcast_tunnels_load(self.dport)
273         self.del_shared_mcast_dst_load(self.dport)
274         self.del_mcast_tunnels_load(self.dport)
275
276         # Setup vni 3 to test unicast flooding
277         self.ucast_flood_bd = 13
278         self.create_vxlan_gpe_flood_test_bd(
279             self.ucast_flood_bd, self.n_ucast_tunnels, self.dport
280         )
281         self.vapi.sw_interface_set_l2_bridge(
282             rx_sw_if_index=self.pg3.sw_if_index, bd_id=self.ucast_flood_bd
283         )
284
285         # Set scapy listen custom port for VxLAN
286         bind_layers(UDP, VXLAN, dport=self.dport)
287
288     """
289     Tests with default port (4790)
290     """
291
292     def test_decap(self):
293         """Decapsulation test
294         from BridgeDoman
295         """
296         self.createVxLANInterfaces()
297         super(TestVxlanGpe, self).test_decap()
298
299     def test_encap(self):
300         """Encapsulation test
301         from BridgeDoman
302         """
303         self.createVxLANInterfaces()
304         super(TestVxlanGpe, self).test_encap()
305
306     def test_ucast_flood(self):
307         """Unicast flood test
308         from BridgeDoman
309         """
310         self.createVxLANInterfaces()
311         super(TestVxlanGpe, self).test_ucast_flood()
312
313     """
314     Tests with custom port (1112)
315     """
316
317     def test_decap_custom_port(self):
318         """Decapsulation test custom port
319         from BridgeDoman
320         """
321         self.createVxLANInterfaces(1112)
322         super(TestVxlanGpe, self).test_decap()
323
324     def test_encap_custom_port(self):
325         """Encapsulation test custom port
326         from BridgeDoman
327         """
328         self.createVxLANInterfaces(1112)
329         super(TestVxlanGpe, self).test_encap()
330
331     def test_ucast_flood_custom_port(self):
332         """Unicast flood test custom port
333         from BridgeDoman
334         """
335         self.createVxLANInterfaces(1112)
336         super(TestVxlanGpe, self).test_ucast_flood()
337
338     @unittest.skip("test disabled for vxlan-gpe")
339     def test_mcast_flood(self):
340         """inherited from BridgeDomain"""
341         pass
342
343     @unittest.skip("test disabled for vxlan-gpe")
344     def test_mcast_rcv(self):
345         """inherited from BridgeDomain"""
346         pass
347
348     # Method to define VPP actions before tear down of the test case.
349     #  Overrides tearDown method in VppTestCase class.
350     #  @param self The object pointer.
351     def tearDown(self):
352         super(TestVxlanGpe, self).tearDown()
353
354     def show_commands_at_teardown(self):
355         self.logger.info(self.vapi.cli("show bridge-domain 11 detail"))
356         self.logger.info(self.vapi.cli("show bridge-domain 12 detail"))
357         self.logger.info(self.vapi.cli("show bridge-domain 13 detail"))
358         self.logger.info(self.vapi.cli("show int"))
359         self.logger.info(self.vapi.cli("show vxlan-gpe"))
360         self.logger.info(self.vapi.cli("show trace"))
361
362
363 if __name__ == "__main__":
364     unittest.main(testRunner=VppTestRunner)