blob: d1ae77ad3f5e39dc2d69a913d5632269987e48ba [file] [log] [blame]
Steven9cd2d7a2017-12-20 12:43:01 -08001#!/usr/bin/env python
2
3import socket
4import unittest
5
6from framework import VppTestCase, VppTestRunner
7from scapy.packet import Raw
8from scapy.layers.l2 import Ether
9from scapy.layers.inet import IP, UDP
Steven9cd2d7a2017-12-20 12:43:01 -080010from vpp_bond_interface import VppBondInterface
Ole Troan8006c6a2018-12-17 12:02:26 +010011from vpp_papi import MACAddress
Steven9cd2d7a2017-12-20 12:43:01 -080012
13
14class 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
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -070034 @classmethod
35 def tearDownClass(cls):
36 super(TestBondInterface, cls).tearDownClass()
37
Steven9cd2d7a2017-12-20 12:43:01 -080038 def setUp(self):
39 super(TestBondInterface, self).setUp()
40
41 def tearDown(self):
42 super(TestBondInterface, self).tearDown()
Paul Vinciguerra90cf21b2019-03-13 09:23:05 -070043
44 def show_commands_at_teardown(self):
45 self.logger.info(self.vapi.ppcli("show interface"))
Steven9cd2d7a2017-12-20 12:43:01 -080046
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"
Ole Troan8006c6a2018-12-17 12:02:26 +010064 mac = MACAddress(bond0_mac).packed
Steven9cd2d7a2017-12-20 12:43:01 -080065 bond0 = VppBondInterface(self,
66 mode=3,
67 lb=1,
Zhiyong Yang751e3f32019-06-26 05:49:14 -040068 numa_only=0,
Steven9cd2d7a2017-12-20 12:43:01 -080069 use_custom_mac=1,
70 mac_address=mac)
71 bond0.add_vpp_config()
72 bond0.admin_up()
Ole Trøan3b0d7e42019-03-15 16:14:41 +000073 bond0_addr = socket.inet_pton(socket.AF_INET, "10.10.10.1")
74 self.vapi.sw_interface_add_del_address(sw_if_index=bond0.sw_if_index,
75 address=bond0_addr,
76 address_length=24)
Steven9cd2d7a2017-12-20 12:43:01 -080077
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 is_passive=0,
91 is_long_timeout=0)
92 self.logger.info("bond enslave interface pg1 to BondEthernet0")
93 bond0.enslave_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index,
94 is_passive=0,
95 is_long_timeout=0)
96
97 # verify both slaves in BondEthernet0
98 if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index)
99 self.assertTrue(self.pg0.is_interface_config_in_dump(if_dump))
100 self.assertTrue(self.pg1.is_interface_config_in_dump(if_dump))
101
102 # generate a packet from pg2 -> BondEthernet0 -> pg1
103 # BondEthernet0 TX hashes this packet to pg1
104 p2 = (Ether(src=bond0_mac, dst=self.pg2.local_mac) /
105 IP(src=self.pg2.local_ip4, dst="10.10.10.12") /
106 UDP(sport=1235, dport=1235) /
107 Raw('\xa5' * 100))
108 self.pg2.add_stream(p2)
109
110 # generate a packet from pg3 -> BondEthernet0 -> pg0
111 # BondEthernet0 TX hashes this packet to pg0
112 # notice the ip address and ports are different than p2 packet
113 p3 = (Ether(src=bond0_mac, dst=self.pg3.local_mac) /
114 IP(src=self.pg3.local_ip4, dst="10.10.10.11") /
115 UDP(sport=1234, dport=1234) /
116 Raw('\xa5' * 100))
117 self.pg3.add_stream(p3)
118
119 self.pg_enable_capture(self.pg_interfaces)
120
121 # set up the static arp entries pointing to the BondEthernet0 interface
122 # so that it does not try to resolve the ip address
123 self.logger.info(self.vapi.cli(
124 "set ip arp static BondEthernet0 10.10.10.12 abcd.abcd.0002"))
125 self.logger.info(self.vapi.cli(
126 "set ip arp static BondEthernet0 10.10.10.11 abcd.abcd.0004"))
127
128 # clear the interface counters
129 self.logger.info(self.vapi.cli("clear interfaces"))
130
131 self.pg_start()
132
133 self.logger.info("check the interface counters")
134
135 # verify counters
136
137 # BondEthernet0 tx bytes = 284
138 intfs = self.vapi.cli("show interface BondEthernet0").split("\n")
139 found = 0
140 for intf in intfs:
141 if "tx bytes" in intf and "284" in intf:
142 found = 1
143 self.assertEqual(found, 1)
144
Steven0d883012018-05-11 11:06:23 -0700145 # BondEthernet0 tx bytes = 284
146 intfs = self.vapi.cli("show interface BondEthernet0").split("\n")
Steven9cd2d7a2017-12-20 12:43:01 -0800147 found = 0
148 for intf in intfs:
Steven0d883012018-05-11 11:06:23 -0700149 if "tx bytes" in intf and "284" in intf:
Steven9cd2d7a2017-12-20 12:43:01 -0800150 found = 1
151 self.assertEqual(found, 1)
152
153 # pg2 rx bytes = 142
154 intfs = self.vapi.cli("show interface pg2").split("\n")
155 found = 0
156 for intf in intfs:
157 if "rx bytes" in intf and "142" in intf:
158 found = 1
159 self.assertEqual(found, 1)
160
161 # pg3 rx bytes = 142
162 intfs = self.vapi.cli("show interface pg3").split("\n")
163 found = 0
164 for intf in intfs:
165 if "rx bytes" in intf and "142" in intf:
166 found = 1
167 self.assertEqual(found, 1)
168
169 bond0.remove_vpp_config()
170
171 def test_bond_enslave(self):
172 """ Bond enslave/detach slave test """
173
174 # create interface (BondEthernet0)
175 self.logger.info("create bond")
176 bond0 = VppBondInterface(self, mode=3)
177 bond0.add_vpp_config()
178 bond0.admin_up()
179
180 # verify pg0 and pg1 not in BondEthernet0
181 if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index)
182 self.assertFalse(self.pg0.is_interface_config_in_dump(if_dump))
183 self.assertFalse(self.pg1.is_interface_config_in_dump(if_dump))
184
185 # enslave pg0 and pg1 to BondEthernet0
186 self.logger.info("bond enslave interface pg0 to BondEthernet0")
187 bond0.enslave_vpp_bond_interface(sw_if_index=self.pg0.sw_if_index,
188 is_passive=0,
189 is_long_timeout=0)
190
191 self.logger.info("bond enslave interface pg1 to BondEthernet0")
192 bond0.enslave_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index,
193 is_passive=0,
194 is_long_timeout=0)
195
196 # verify both slaves in BondEthernet0
197 if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index)
198 self.assertTrue(self.pg0.is_interface_config_in_dump(if_dump))
199 self.assertTrue(self.pg1.is_interface_config_in_dump(if_dump))
200
201 # detach interface pg0
202 self.logger.info("detach interface pg0")
203 bond0.detach_vpp_bond_interface(sw_if_index=self.pg0.sw_if_index)
204
205 # verify pg0 is not in BondEthernet0, but pg1 is
206 if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index)
207 self.assertFalse(self.pg0.is_interface_config_in_dump(if_dump))
208 self.assertTrue(self.pg1.is_interface_config_in_dump(if_dump))
209
210 # detach interface pg1
211 self.logger.info("detach interface pg1")
212 bond0.detach_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index)
213
214 # verify pg0 and pg1 not in BondEthernet0
215 if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index)
216 self.assertFalse(self.pg0.is_interface_config_in_dump(if_dump))
217 self.assertFalse(self.pg1.is_interface_config_in_dump(if_dump))
218
219 bond0.remove_vpp_config()
220
221 def test_bond(self):
222 """ Bond add/delete interface test """
223 self.logger.info("Bond add interfaces")
224
225 # create interface 1 (BondEthernet0)
226 bond0 = VppBondInterface(self, mode=5)
227 bond0.add_vpp_config()
228 bond0.admin_up()
229
230 # create interface 2 (BondEthernet1)
231 bond1 = VppBondInterface(self, mode=3)
232 bond1.add_vpp_config()
233 bond1.admin_up()
234
235 # verify both interfaces in the show
236 ifs = self.vapi.cli("show interface")
Paul Vinciguerra9a6dafd2019-03-06 15:11:28 -0800237 self.assertIn('BondEthernet0', ifs)
238 self.assertIn('BondEthernet1', ifs)
Steven9cd2d7a2017-12-20 12:43:01 -0800239
240 # verify they are in the dump also
241 if_dump = self.vapi.sw_interface_bond_dump()
242 self.assertTrue(bond0.is_interface_config_in_dump(if_dump))
243 self.assertTrue(bond1.is_interface_config_in_dump(if_dump))
244
245 # delete BondEthernet1
246 self.logger.info("Deleting BondEthernet1")
247 bond1.remove_vpp_config()
248
249 self.logger.info("Verifying BondEthernet1 is deleted")
250
251 ifs = self.vapi.cli("show interface")
252 # verify BondEthernet0 still in the show
Paul Vinciguerra9a6dafd2019-03-06 15:11:28 -0800253 self.assertIn('BondEthernet0', ifs)
Steven9cd2d7a2017-12-20 12:43:01 -0800254
255 # verify BondEthernet1 not in the show
Paul Vinciguerra9a6dafd2019-03-06 15:11:28 -0800256 self.assertNotIn('BondEthernet1', ifs)
Steven9cd2d7a2017-12-20 12:43:01 -0800257
258 # verify BondEthernet1 is not in the dump
259 if_dump = self.vapi.sw_interface_bond_dump()
260 self.assertFalse(bond1.is_interface_config_in_dump(if_dump))
261
262 # verify BondEthernet0 is still in the dump
263 self.assertTrue(bond0.is_interface_config_in_dump(if_dump))
264
265 # delete BondEthernet0
266 self.logger.info("Deleting BondEthernet0")
267 bond0.remove_vpp_config()
268
269 self.logger.info("Verifying BondEthernet0 is deleted")
270
271 # verify BondEthernet0 not in the show
272 ifs = self.vapi.cli("show interface")
Paul Vinciguerra9a6dafd2019-03-06 15:11:28 -0800273 self.assertNotIn('BondEthernet0', ifs)
Steven9cd2d7a2017-12-20 12:43:01 -0800274
275 # verify BondEthernet0 is not in the dump
276 if_dump = self.vapi.sw_interface_bond_dump()
277 self.assertFalse(bond0.is_interface_config_in_dump(if_dump))
278
279if __name__ == '__main__':
280 unittest.main(testRunner=VppTestRunner)