bonding lacp: replace slave string with member
[vpp.git] / test / test_bond.py
1 #!/usr/bin/env python3
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 (member)
55         #           |        |
56         #          BondEthernet0 (10.10.10.1)
57         #           |        |
58         # pg3 ------+        +------pg1 (memberx)
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                                  numa_only=0,
69                                  use_custom_mac=1,
70                                  mac_address=mac)
71         bond0.add_vpp_config()
72         bond0.admin_up()
73         self.vapi.sw_interface_add_del_address(
74             sw_if_index=bond0.sw_if_index,
75             prefix="10.10.10.1/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 neighbors"))
85
86         # add member pg0 and pg1 to BondEthernet0
87         self.logger.info("bond add member interface pg0 to BondEthernet0")
88         bond0.add_member_vpp_bond_interface(sw_if_index=self.pg0.sw_if_index)
89         self.logger.info("bond add_member interface pg1 to BondEthernet0")
90         bond0.add_member_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index)
91
92         # verify both members in BondEthernet0
93         if_dump = self.vapi.sw_member_interface_dump(bond0.sw_if_index)
94         self.assertTrue(self.pg0.is_interface_config_in_dump(if_dump))
95         self.assertTrue(self.pg1.is_interface_config_in_dump(if_dump))
96
97         # generate a packet from pg2 -> BondEthernet0 -> pg1
98         # BondEthernet0 TX hashes this packet to pg1
99         p2 = (Ether(src=bond0_mac, dst=self.pg2.local_mac) /
100               IP(src=self.pg2.local_ip4, dst="10.10.10.12") /
101               UDP(sport=1235, dport=1235) /
102               Raw(b'\xa5' * 100))
103         self.pg2.add_stream(p2)
104
105         # generate a packet from pg3 -> BondEthernet0 -> pg0
106         # BondEthernet0 TX hashes this packet to pg0
107         # notice the ip address and ports are different than p2 packet
108         p3 = (Ether(src=bond0_mac, dst=self.pg3.local_mac) /
109               IP(src=self.pg3.local_ip4, dst="10.10.10.11") /
110               UDP(sport=1234, dport=1234) /
111               Raw(b'\xa5' * 100))
112         self.pg3.add_stream(p3)
113
114         self.pg_enable_capture(self.pg_interfaces)
115
116         # set up the static arp entries pointing to the BondEthernet0 interface
117         # so that it does not try to resolve the ip address
118         self.logger.info(self.vapi.cli(
119             "set ip neighbor static BondEthernet0 10.10.10.12 abcd.abcd.0002"))
120         self.logger.info(self.vapi.cli(
121             "set ip neighbor static BondEthernet0 10.10.10.11 abcd.abcd.0004"))
122
123         # clear the interface counters
124         self.logger.info(self.vapi.cli("clear interfaces"))
125
126         self.pg_start()
127
128         self.logger.info("check the interface counters")
129
130         # verify counters
131
132         # BondEthernet0 tx bytes = 284
133         intfs = self.vapi.cli("show interface BondEthernet0").split("\n")
134         found = 0
135         for intf in intfs:
136             if "tx bytes" in intf and "284" in intf:
137                 found = 1
138         self.assertEqual(found, 1)
139
140         # BondEthernet0 tx bytes = 284
141         intfs = self.vapi.cli("show interface BondEthernet0").split("\n")
142         found = 0
143         for intf in intfs:
144             if "tx bytes" in intf and "284" in intf:
145                 found = 1
146         self.assertEqual(found, 1)
147
148         # pg2 rx bytes = 142
149         intfs = self.vapi.cli("show interface pg2").split("\n")
150         found = 0
151         for intf in intfs:
152             if "rx bytes" in intf and "142" in intf:
153                 found = 1
154         self.assertEqual(found, 1)
155
156         # pg3 rx bytes = 142
157         intfs = self.vapi.cli("show interface pg3").split("\n")
158         found = 0
159         for intf in intfs:
160             if "rx bytes" in intf and "142" in intf:
161                 found = 1
162         self.assertEqual(found, 1)
163
164         bond0.remove_vpp_config()
165
166     def test_bond_add_member(self):
167         """ Bond add_member/detach member test """
168
169         # create interface (BondEthernet0) and set bond mode to LACP
170         self.logger.info("create bond")
171         bond0 = VppBondInterface(self, mode=5)
172         bond0.add_vpp_config()
173         bond0.admin_up()
174
175         # verify that interfaces can be added as_member and detached two times
176         for i in range(2):
177             # verify pg0 and pg1 not in BondEthernet0
178             if_dump = self.vapi.sw_member_interface_dump(bond0.sw_if_index)
179             self.assertFalse(self.pg0.is_interface_config_in_dump(if_dump))
180             self.assertFalse(self.pg1.is_interface_config_in_dump(if_dump))
181
182             # add_member pg0 and pg1 to BondEthernet0
183             self.logger.info("bond add_member interface pg0 to BondEthernet0")
184             bond0.add_member_vpp_bond_interface(
185                 sw_if_index=self.pg0.sw_if_index,
186                 is_passive=0,
187                 is_long_timeout=0)
188
189             self.logger.info("bond add_member interface pg1 to BondEthernet0")
190             bond0.add_member_vpp_bond_interface(
191                 sw_if_index=self.pg1.sw_if_index,
192                 is_passive=0,
193                 is_long_timeout=0)
194             # verify both members in BondEthernet0
195             if_dump = self.vapi.sw_member_interface_dump(bond0.sw_if_index)
196             self.assertTrue(self.pg0.is_interface_config_in_dump(if_dump))
197             self.assertTrue(self.pg1.is_interface_config_in_dump(if_dump))
198
199             # detach interface pg0
200             self.logger.info("detach interface pg0")
201             bond0.detach_vpp_bond_interface(sw_if_index=self.pg0.sw_if_index)
202
203             # verify pg0 is not in BondEthernet0, but pg1 is
204             if_dump = self.vapi.sw_member_interface_dump(bond0.sw_if_index)
205             self.assertFalse(self.pg0.is_interface_config_in_dump(if_dump))
206             self.assertTrue(self.pg1.is_interface_config_in_dump(if_dump))
207
208             # detach interface pg1
209             self.logger.info("detach interface pg1")
210             bond0.detach_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index)
211
212             # verify pg0 and pg1 not in BondEthernet0
213             if_dump = self.vapi.sw_member_interface_dump(bond0.sw_if_index)
214             self.assertFalse(self.pg0.is_interface_config_in_dump(if_dump))
215             self.assertFalse(self.pg1.is_interface_config_in_dump(if_dump))
216
217         bond0.remove_vpp_config()
218
219     def test_bond(self):
220         """ Bond add/delete interface test """
221         self.logger.info("Bond add interfaces")
222
223         # create interface 1 (BondEthernet0)
224         bond0 = VppBondInterface(self, mode=5)
225         bond0.add_vpp_config()
226         bond0.admin_up()
227
228         # create interface 2 (BondEthernet1)
229         bond1 = VppBondInterface(self, mode=3)
230         bond1.add_vpp_config()
231         bond1.admin_up()
232
233         # verify both interfaces in the show
234         ifs = self.vapi.cli("show interface")
235         self.assertIn('BondEthernet0', ifs)
236         self.assertIn('BondEthernet1', ifs)
237
238         # verify they are in the dump also
239         if_dump = self.vapi.sw_bond_interface_dump(sw_if_index=0xFFFFFFFF)
240         self.assertTrue(bond0.is_interface_config_in_dump(if_dump))
241         self.assertTrue(bond1.is_interface_config_in_dump(if_dump))
242
243         # delete BondEthernet1
244         self.logger.info("Deleting BondEthernet1")
245         bond1.remove_vpp_config()
246
247         self.logger.info("Verifying BondEthernet1 is deleted")
248
249         ifs = self.vapi.cli("show interface")
250         # verify BondEthernet0 still in the show
251         self.assertIn('BondEthernet0', ifs)
252
253         # verify BondEthernet1 not in the show
254         self.assertNotIn('BondEthernet1', ifs)
255
256         # verify BondEthernet1 is not in the dump
257         if_dump = self.vapi.sw_bond_interface_dump(sw_if_index=0xFFFFFFFF)
258         self.assertFalse(bond1.is_interface_config_in_dump(if_dump))
259
260         # verify BondEthernet0 is still in the dump
261         self.assertTrue(bond0.is_interface_config_in_dump(if_dump))
262
263         # delete BondEthernet0
264         self.logger.info("Deleting BondEthernet0")
265         bond0.remove_vpp_config()
266
267         self.logger.info("Verifying BondEthernet0 is deleted")
268
269         # verify BondEthernet0 not in the show
270         ifs = self.vapi.cli("show interface")
271         self.assertNotIn('BondEthernet0', ifs)
272
273         # verify BondEthernet0 is not in the dump
274         if_dump = self.vapi.sw_bond_interface_dump(
275             sw_if_index=bond0.sw_if_index)
276         self.assertFalse(bond0.is_interface_config_in_dump(if_dump))
277
278
279 if __name__ == '__main__':
280     unittest.main(testRunner=VppTestRunner)