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