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