blob: 27da15c5ab5148ad56bd4dcbdfa7fecd8610e5be [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
Jakub Grajciar053204a2019-03-18 13:17:53 +010012from vpp_ip import VppIpPrefix
Steven9cd2d7a2017-12-20 12:43:01 -080013
14
15class 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
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -070035 @classmethod
36 def tearDownClass(cls):
37 super(TestBondInterface, cls).tearDownClass()
38
Steven9cd2d7a2017-12-20 12:43:01 -080039 def setUp(self):
40 super(TestBondInterface, self).setUp()
41
42 def tearDown(self):
43 super(TestBondInterface, self).tearDown()
Paul Vinciguerra90cf21b2019-03-13 09:23:05 -070044
45 def show_commands_at_teardown(self):
46 self.logger.info(self.vapi.ppcli("show interface"))
Steven9cd2d7a2017-12-20 12:43:01 -080047
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"
Ole Troan8006c6a2018-12-17 12:02:26 +010065 mac = MACAddress(bond0_mac).packed
Steven9cd2d7a2017-12-20 12:43:01 -080066 bond0 = VppBondInterface(self,
67 mode=3,
68 lb=1,
Zhiyong Yang751e3f32019-06-26 05:49:14 -040069 numa_only=0,
Steven9cd2d7a2017-12-20 12:43:01 -080070 use_custom_mac=1,
71 mac_address=mac)
72 bond0.add_vpp_config()
73 bond0.admin_up()
Jakub Grajciar053204a2019-03-18 13:17:53 +010074 self.vapi.sw_interface_add_del_address(
75 sw_if_index=bond0.sw_if_index,
76 prefix=VppIpPrefix("10.10.10.1", 24).encode())
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")
Steven Luonga1876b82019-08-20 16:58:00 -070089 bond0.enslave_vpp_bond_interface(sw_if_index=self.pg0.sw_if_index)
Steven9cd2d7a2017-12-20 12:43:01 -080090 self.logger.info("bond enslave interface pg1 to BondEthernet0")
Steven Luonga1876b82019-08-20 16:58:00 -070091 bond0.enslave_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index)
Steven9cd2d7a2017-12-20 12:43:01 -080092
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
Steven0d883012018-05-11 11:06:23 -0700141 # BondEthernet0 tx bytes = 284
142 intfs = self.vapi.cli("show interface BondEthernet0").split("\n")
Steven9cd2d7a2017-12-20 12:43:01 -0800143 found = 0
144 for intf in intfs:
Steven0d883012018-05-11 11:06:23 -0700145 if "tx bytes" in intf and "284" in intf:
Steven9cd2d7a2017-12-20 12:43:01 -0800146 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")
Paul Vinciguerra9a6dafd2019-03-06 15:11:28 -0800233 self.assertIn('BondEthernet0', ifs)
234 self.assertIn('BondEthernet1', ifs)
Steven9cd2d7a2017-12-20 12:43:01 -0800235
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
Paul Vinciguerra9a6dafd2019-03-06 15:11:28 -0800249 self.assertIn('BondEthernet0', ifs)
Steven9cd2d7a2017-12-20 12:43:01 -0800250
251 # verify BondEthernet1 not in the show
Paul Vinciguerra9a6dafd2019-03-06 15:11:28 -0800252 self.assertNotIn('BondEthernet1', ifs)
Steven9cd2d7a2017-12-20 12:43:01 -0800253
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")
Paul Vinciguerra9a6dafd2019-03-06 15:11:28 -0800269 self.assertNotIn('BondEthernet0', ifs)
Steven9cd2d7a2017-12-20 12:43:01 -0800270
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
Steven Luonga1876b82019-08-20 16:58:00 -0700275
Steven9cd2d7a2017-12-20 12:43:01 -0800276if __name__ == '__main__':
277 unittest.main(testRunner=VppTestRunner)