Tests: Refactor tearDown show command logging, add lifecycle markers.
[vpp.git] / test / test_bond.py
1 #!/usr/bin/env python
2
3 import socket
4 import unittest
5
6 from framework import VppTestCase, VppTestRunner
7 from scapy.packet import Raw
8 from scapy.layers.l2 import Ether
9 from scapy.layers.inet import IP, UDP
10 from vpp_bond_interface import VppBondInterface
11 from vpp_papi import MACAddress
12
13
14 class TestBondInterface(VppTestCase):
15     """Bond Test Case
16
17     """
18
19     @classmethod
20     def setUpClass(cls):
21         super(TestBondInterface, cls).setUpClass()
22         # Test variables
23         cls.pkts_per_burst = 257    # Number of packets per burst
24         # create 3 pg interfaces
25         cls.create_pg_interfaces(range(4))
26
27         # packet sizes
28         cls.pg_if_packet_sizes = [64, 512, 1518]  # , 9018]
29
30         # setup all interfaces
31         for i in cls.pg_interfaces:
32             i.admin_up()
33
34     @classmethod
35     def tearDownClass(cls):
36         super(TestBondInterface, cls).tearDownClass()
37
38     def setUp(self):
39         super(TestBondInterface, self).setUp()
40
41     def tearDown(self):
42         super(TestBondInterface, self).tearDown()
43
44     def show_commands_at_teardown(self):
45         self.logger.info(self.vapi.ppcli("show interface"))
46
47     def test_bond_traffic(self):
48         """ Bond traffic test """
49
50         # topology
51         #
52         # RX->              TX->
53         #
54         # pg2 ------+        +------pg0 (slave)
55         #           |        |
56         #          BondEthernet0 (10.10.10.1)
57         #           |        |
58         # pg3 ------+        +------pg1 (slave)
59         #
60
61         # create interface (BondEthernet0)
62         #        self.logger.info("create bond")
63         bond0_mac = "02:fe:38:30:59:3c"
64         mac = MACAddress(bond0_mac).packed
65         bond0 = VppBondInterface(self,
66                                  mode=3,
67                                  lb=1,
68                                  use_custom_mac=1,
69                                  mac_address=mac)
70         bond0.add_vpp_config()
71         bond0.admin_up()
72         bond0_addr = socket.inet_pton(socket.AF_INET, "10.10.10.1")
73         self.vapi.sw_interface_add_del_address(sw_if_index=bond0.sw_if_index,
74                                                address=bond0_addr,
75                                                address_length=24)
76
77         self.pg2.config_ip4()
78         self.pg2.resolve_arp()
79         self.pg3.config_ip4()
80         self.pg3.resolve_arp()
81
82         self.logger.info(self.vapi.cli("show interface"))
83         self.logger.info(self.vapi.cli("show interface address"))
84         self.logger.info(self.vapi.cli("show ip arp"))
85
86         # enslave pg0 and pg1 to BondEthernet0
87         self.logger.info("bond enslave interface pg0 to BondEthernet0")
88         bond0.enslave_vpp_bond_interface(sw_if_index=self.pg0.sw_if_index,
89                                          is_passive=0,
90                                          is_long_timeout=0)
91         self.logger.info("bond enslave interface pg1 to BondEthernet0")
92         bond0.enslave_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index,
93                                          is_passive=0,
94                                          is_long_timeout=0)
95
96         # verify both slaves in BondEthernet0
97         if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index)
98         self.assertTrue(self.pg0.is_interface_config_in_dump(if_dump))
99         self.assertTrue(self.pg1.is_interface_config_in_dump(if_dump))
100
101         # generate a packet from pg2 -> BondEthernet0 -> pg1
102         # BondEthernet0 TX hashes this packet to pg1
103         p2 = (Ether(src=bond0_mac, dst=self.pg2.local_mac) /
104               IP(src=self.pg2.local_ip4, dst="10.10.10.12") /
105               UDP(sport=1235, dport=1235) /
106               Raw('\xa5' * 100))
107         self.pg2.add_stream(p2)
108
109         # generate a packet from pg3 -> BondEthernet0 -> pg0
110         # BondEthernet0 TX hashes this packet to pg0
111         # notice the ip address and ports are different than p2 packet
112         p3 = (Ether(src=bond0_mac, dst=self.pg3.local_mac) /
113               IP(src=self.pg3.local_ip4, dst="10.10.10.11") /
114               UDP(sport=1234, dport=1234) /
115               Raw('\xa5' * 100))
116         self.pg3.add_stream(p3)
117
118         self.pg_enable_capture(self.pg_interfaces)
119
120         # set up the static arp entries pointing to the BondEthernet0 interface
121         # so that it does not try to resolve the ip address
122         self.logger.info(self.vapi.cli(
123             "set ip arp static BondEthernet0 10.10.10.12 abcd.abcd.0002"))
124         self.logger.info(self.vapi.cli(
125             "set ip arp static BondEthernet0 10.10.10.11 abcd.abcd.0004"))
126
127         # clear the interface counters
128         self.logger.info(self.vapi.cli("clear interfaces"))
129
130         self.pg_start()
131
132         self.logger.info("check the interface counters")
133
134         # verify counters
135
136         # BondEthernet0 tx bytes = 284
137         intfs = self.vapi.cli("show interface BondEthernet0").split("\n")
138         found = 0
139         for intf in intfs:
140             if "tx bytes" in intf and "284" in intf:
141                 found = 1
142         self.assertEqual(found, 1)
143
144         # BondEthernet0 tx bytes = 284
145         intfs = self.vapi.cli("show interface BondEthernet0").split("\n")
146         found = 0
147         for intf in intfs:
148             if "tx bytes" in intf and "284" in intf:
149                 found = 1
150         self.assertEqual(found, 1)
151
152         # pg2 rx bytes = 142
153         intfs = self.vapi.cli("show interface pg2").split("\n")
154         found = 0
155         for intf in intfs:
156             if "rx bytes" in intf and "142" in intf:
157                 found = 1
158         self.assertEqual(found, 1)
159
160         # pg3 rx bytes = 142
161         intfs = self.vapi.cli("show interface pg3").split("\n")
162         found = 0
163         for intf in intfs:
164             if "rx bytes" in intf and "142" in intf:
165                 found = 1
166         self.assertEqual(found, 1)
167
168         bond0.remove_vpp_config()
169
170     def test_bond_enslave(self):
171         """ Bond enslave/detach slave test """
172
173         # create interface (BondEthernet0)
174         self.logger.info("create bond")
175         bond0 = VppBondInterface(self, mode=3)
176         bond0.add_vpp_config()
177         bond0.admin_up()
178
179         # verify pg0 and pg1 not in BondEthernet0
180         if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index)
181         self.assertFalse(self.pg0.is_interface_config_in_dump(if_dump))
182         self.assertFalse(self.pg1.is_interface_config_in_dump(if_dump))
183
184         # enslave pg0 and pg1 to BondEthernet0
185         self.logger.info("bond enslave interface pg0 to BondEthernet0")
186         bond0.enslave_vpp_bond_interface(sw_if_index=self.pg0.sw_if_index,
187                                          is_passive=0,
188                                          is_long_timeout=0)
189
190         self.logger.info("bond enslave interface pg1 to BondEthernet0")
191         bond0.enslave_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index,
192                                          is_passive=0,
193                                          is_long_timeout=0)
194
195         # verify both slaves in BondEthernet0
196         if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index)
197         self.assertTrue(self.pg0.is_interface_config_in_dump(if_dump))
198         self.assertTrue(self.pg1.is_interface_config_in_dump(if_dump))
199
200         # detach interface pg0
201         self.logger.info("detach interface pg0")
202         bond0.detach_vpp_bond_interface(sw_if_index=self.pg0.sw_if_index)
203
204         # verify pg0 is not in BondEthernet0, but pg1 is
205         if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index)
206         self.assertFalse(self.pg0.is_interface_config_in_dump(if_dump))
207         self.assertTrue(self.pg1.is_interface_config_in_dump(if_dump))
208
209         # detach interface pg1
210         self.logger.info("detach interface pg1")
211         bond0.detach_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index)
212
213         # verify pg0 and pg1 not in BondEthernet0
214         if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index)
215         self.assertFalse(self.pg0.is_interface_config_in_dump(if_dump))
216         self.assertFalse(self.pg1.is_interface_config_in_dump(if_dump))
217
218         bond0.remove_vpp_config()
219
220     def test_bond(self):
221         """ Bond add/delete interface test """
222         self.logger.info("Bond add interfaces")
223
224         # create interface 1 (BondEthernet0)
225         bond0 = VppBondInterface(self, mode=5)
226         bond0.add_vpp_config()
227         bond0.admin_up()
228
229         # create interface 2 (BondEthernet1)
230         bond1 = VppBondInterface(self, mode=3)
231         bond1.add_vpp_config()
232         bond1.admin_up()
233
234         # verify both interfaces in the show
235         ifs = self.vapi.cli("show interface")
236         self.assertIn('BondEthernet0', ifs)
237         self.assertIn('BondEthernet1', ifs)
238
239         # verify they are in the dump also
240         if_dump = self.vapi.sw_interface_bond_dump()
241         self.assertTrue(bond0.is_interface_config_in_dump(if_dump))
242         self.assertTrue(bond1.is_interface_config_in_dump(if_dump))
243
244         # delete BondEthernet1
245         self.logger.info("Deleting BondEthernet1")
246         bond1.remove_vpp_config()
247
248         self.logger.info("Verifying BondEthernet1 is deleted")
249
250         ifs = self.vapi.cli("show interface")
251         # verify BondEthernet0 still in the show
252         self.assertIn('BondEthernet0', ifs)
253
254         # verify BondEthernet1 not in the show
255         self.assertNotIn('BondEthernet1', ifs)
256
257         # verify BondEthernet1 is not in the dump
258         if_dump = self.vapi.sw_interface_bond_dump()
259         self.assertFalse(bond1.is_interface_config_in_dump(if_dump))
260
261         # verify BondEthernet0 is still in the dump
262         self.assertTrue(bond0.is_interface_config_in_dump(if_dump))
263
264         # delete BondEthernet0
265         self.logger.info("Deleting BondEthernet0")
266         bond0.remove_vpp_config()
267
268         self.logger.info("Verifying BondEthernet0 is deleted")
269
270         # verify BondEthernet0 not in the show
271         ifs = self.vapi.cli("show interface")
272         self.assertNotIn('BondEthernet0', ifs)
273
274         # verify BondEthernet0 is not in the dump
275         if_dump = self.vapi.sw_interface_bond_dump()
276         self.assertFalse(bond0.is_interface_config_in_dump(if_dump))
277
278 if __name__ == '__main__':
279     unittest.main(testRunner=VppTestRunner)