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