blob: 5df86ae5b0f6a7920c99168fdb48e82d51dfd351 [file] [log] [blame]
Renato Botelho do Coutoead1e532019-10-31 13:31:07 -05001#!/usr/bin/env python3
Steven9cd2d7a2017-12-20 12:43:01 -08002
3import socket
4import unittest
5
Steven9cd2d7a2017-12-20 12:43:01 -08006from scapy.packet import Raw
7from scapy.layers.l2 import Ether
8from scapy.layers.inet import IP, UDP
Steven Luongdc2abbe2020-07-28 12:28:03 -07009
10from framework import VppTestCase, VppTestRunner
Steven9cd2d7a2017-12-20 12:43:01 -080011from vpp_bond_interface import VppBondInterface
Steven Luongdc2abbe2020-07-28 12:28:03 -070012from vpp_papi import MACAddress, VppEnum
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 #
Steven Luong4c4223e2020-07-15 08:44:54 -070055 # pg2 ------+ +------pg0 (member)
Steven9cd2d7a2017-12-20 12:43:01 -080056 # | |
57 # BondEthernet0 (10.10.10.1)
58 # | |
Steven Luong4c4223e2020-07-15 08:44:54 -070059 # pg3 ------+ +------pg1 (memberx)
Steven9cd2d7a2017-12-20 12:43:01 -080060 #
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
Steven Luongea717862020-07-30 07:31:40 -070066 bond0 = VppBondInterface(
67 self,
68 mode=VppEnum.vl_api_bond_mode_t.BOND_API_MODE_XOR,
69 lb=VppEnum.vl_api_bond_lb_algo_t.BOND_API_LB_ALGO_L34,
70 numa_only=0,
71 use_custom_mac=1,
72 mac_address=mac)
Steven9cd2d7a2017-12-20 12:43:01 -080073 bond0.add_vpp_config()
74 bond0.admin_up()
Jakub Grajciar053204a2019-03-18 13:17:53 +010075 self.vapi.sw_interface_add_del_address(
76 sw_if_index=bond0.sw_if_index,
Neale Rannsefd7bc22019-11-11 08:32:34 +000077 prefix="10.10.10.1/24")
Steven9cd2d7a2017-12-20 12:43:01 -080078
79 self.pg2.config_ip4()
80 self.pg2.resolve_arp()
81 self.pg3.config_ip4()
82 self.pg3.resolve_arp()
83
84 self.logger.info(self.vapi.cli("show interface"))
85 self.logger.info(self.vapi.cli("show interface address"))
Neale Rannscbe25aa2019-09-30 10:53:31 +000086 self.logger.info(self.vapi.cli("show ip neighbors"))
Steven9cd2d7a2017-12-20 12:43:01 -080087
Steven Luong4c4223e2020-07-15 08:44:54 -070088 # add member pg0 and pg1 to BondEthernet0
89 self.logger.info("bond add member interface pg0 to BondEthernet0")
90 bond0.add_member_vpp_bond_interface(sw_if_index=self.pg0.sw_if_index)
91 self.logger.info("bond add_member interface pg1 to BondEthernet0")
92 bond0.add_member_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index)
Steven9cd2d7a2017-12-20 12:43:01 -080093
Steven Luong4c4223e2020-07-15 08:44:54 -070094 # verify both members in BondEthernet0
95 if_dump = self.vapi.sw_member_interface_dump(bond0.sw_if_index)
Steven9cd2d7a2017-12-20 12:43:01 -080096 self.assertTrue(self.pg0.is_interface_config_in_dump(if_dump))
97 self.assertTrue(self.pg1.is_interface_config_in_dump(if_dump))
98
99 # generate a packet from pg2 -> BondEthernet0 -> pg1
100 # BondEthernet0 TX hashes this packet to pg1
101 p2 = (Ether(src=bond0_mac, dst=self.pg2.local_mac) /
102 IP(src=self.pg2.local_ip4, dst="10.10.10.12") /
103 UDP(sport=1235, dport=1235) /
Ole Troanf6dee6c2019-10-21 20:41:44 +0200104 Raw(b'\xa5' * 100))
Steven9cd2d7a2017-12-20 12:43:01 -0800105 self.pg2.add_stream(p2)
106
107 # generate a packet from pg3 -> BondEthernet0 -> pg0
108 # BondEthernet0 TX hashes this packet to pg0
109 # notice the ip address and ports are different than p2 packet
110 p3 = (Ether(src=bond0_mac, dst=self.pg3.local_mac) /
111 IP(src=self.pg3.local_ip4, dst="10.10.10.11") /
112 UDP(sport=1234, dport=1234) /
Ole Troanf6dee6c2019-10-21 20:41:44 +0200113 Raw(b'\xa5' * 100))
Steven9cd2d7a2017-12-20 12:43:01 -0800114 self.pg3.add_stream(p3)
115
116 self.pg_enable_capture(self.pg_interfaces)
117
118 # set up the static arp entries pointing to the BondEthernet0 interface
119 # so that it does not try to resolve the ip address
120 self.logger.info(self.vapi.cli(
Neale Rannscbe25aa2019-09-30 10:53:31 +0000121 "set ip neighbor static BondEthernet0 10.10.10.12 abcd.abcd.0002"))
Steven9cd2d7a2017-12-20 12:43:01 -0800122 self.logger.info(self.vapi.cli(
Neale Rannscbe25aa2019-09-30 10:53:31 +0000123 "set ip neighbor static BondEthernet0 10.10.10.11 abcd.abcd.0004"))
Steven9cd2d7a2017-12-20 12:43:01 -0800124
125 # clear the interface counters
126 self.logger.info(self.vapi.cli("clear interfaces"))
127
128 self.pg_start()
129
130 self.logger.info("check the interface counters")
131
132 # verify counters
133
134 # BondEthernet0 tx bytes = 284
135 intfs = self.vapi.cli("show interface BondEthernet0").split("\n")
136 found = 0
137 for intf in intfs:
138 if "tx bytes" in intf and "284" in intf:
139 found = 1
140 self.assertEqual(found, 1)
141
Steven0d883012018-05-11 11:06:23 -0700142 # BondEthernet0 tx bytes = 284
143 intfs = self.vapi.cli("show interface BondEthernet0").split("\n")
Steven9cd2d7a2017-12-20 12:43:01 -0800144 found = 0
145 for intf in intfs:
Steven0d883012018-05-11 11:06:23 -0700146 if "tx bytes" in intf and "284" in intf:
Steven9cd2d7a2017-12-20 12:43:01 -0800147 found = 1
148 self.assertEqual(found, 1)
149
150 # pg2 rx bytes = 142
151 intfs = self.vapi.cli("show interface pg2").split("\n")
152 found = 0
153 for intf in intfs:
154 if "rx bytes" in intf and "142" in intf:
155 found = 1
156 self.assertEqual(found, 1)
157
158 # pg3 rx bytes = 142
159 intfs = self.vapi.cli("show interface pg3").split("\n")
160 found = 0
161 for intf in intfs:
162 if "rx bytes" in intf and "142" in intf:
163 found = 1
164 self.assertEqual(found, 1)
165
166 bond0.remove_vpp_config()
167
Steven Luong4c4223e2020-07-15 08:44:54 -0700168 def test_bond_add_member(self):
169 """ Bond add_member/detach member test """
Steven9cd2d7a2017-12-20 12:43:01 -0800170
Vladimir Isaev72e31bc2020-02-04 11:54:27 +0300171 # create interface (BondEthernet0) and set bond mode to LACP
Steven9cd2d7a2017-12-20 12:43:01 -0800172 self.logger.info("create bond")
Steven Luongea717862020-07-30 07:31:40 -0700173 bond0 = VppBondInterface(
174 self,
175 mode=VppEnum.vl_api_bond_mode_t.BOND_API_MODE_LACP,
176 enable_gso=0)
Steven9cd2d7a2017-12-20 12:43:01 -0800177 bond0.add_vpp_config()
178 bond0.admin_up()
179
Steven Luong4c4223e2020-07-15 08:44:54 -0700180 # verify that interfaces can be added as_member and detached two times
Vladimir Isaev72e31bc2020-02-04 11:54:27 +0300181 for i in range(2):
182 # verify pg0 and pg1 not in BondEthernet0
Steven Luong4c4223e2020-07-15 08:44:54 -0700183 if_dump = self.vapi.sw_member_interface_dump(bond0.sw_if_index)
Vladimir Isaev72e31bc2020-02-04 11:54:27 +0300184 self.assertFalse(self.pg0.is_interface_config_in_dump(if_dump))
185 self.assertFalse(self.pg1.is_interface_config_in_dump(if_dump))
Steven9cd2d7a2017-12-20 12:43:01 -0800186
Steven Luong4c4223e2020-07-15 08:44:54 -0700187 # add_member pg0 and pg1 to BondEthernet0
188 self.logger.info("bond add_member interface pg0 to BondEthernet0")
189 bond0.add_member_vpp_bond_interface(
190 sw_if_index=self.pg0.sw_if_index,
191 is_passive=0,
192 is_long_timeout=0)
Steven9cd2d7a2017-12-20 12:43:01 -0800193
Steven Luong4c4223e2020-07-15 08:44:54 -0700194 self.logger.info("bond add_member interface pg1 to BondEthernet0")
195 bond0.add_member_vpp_bond_interface(
196 sw_if_index=self.pg1.sw_if_index,
197 is_passive=0,
198 is_long_timeout=0)
199 # verify both members in BondEthernet0
200 if_dump = self.vapi.sw_member_interface_dump(bond0.sw_if_index)
Vladimir Isaev72e31bc2020-02-04 11:54:27 +0300201 self.assertTrue(self.pg0.is_interface_config_in_dump(if_dump))
202 self.assertTrue(self.pg1.is_interface_config_in_dump(if_dump))
Steven9cd2d7a2017-12-20 12:43:01 -0800203
Vladimir Isaev72e31bc2020-02-04 11:54:27 +0300204 # detach interface pg0
205 self.logger.info("detach interface pg0")
206 bond0.detach_vpp_bond_interface(sw_if_index=self.pg0.sw_if_index)
Steven9cd2d7a2017-12-20 12:43:01 -0800207
Vladimir Isaev72e31bc2020-02-04 11:54:27 +0300208 # verify pg0 is not in BondEthernet0, but pg1 is
Steven Luong4c4223e2020-07-15 08:44:54 -0700209 if_dump = self.vapi.sw_member_interface_dump(bond0.sw_if_index)
Vladimir Isaev72e31bc2020-02-04 11:54:27 +0300210 self.assertFalse(self.pg0.is_interface_config_in_dump(if_dump))
211 self.assertTrue(self.pg1.is_interface_config_in_dump(if_dump))
Steven9cd2d7a2017-12-20 12:43:01 -0800212
Vladimir Isaev72e31bc2020-02-04 11:54:27 +0300213 # detach interface pg1
214 self.logger.info("detach interface pg1")
215 bond0.detach_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index)
Steven9cd2d7a2017-12-20 12:43:01 -0800216
Vladimir Isaev72e31bc2020-02-04 11:54:27 +0300217 # verify pg0 and pg1 not in BondEthernet0
Steven Luong4c4223e2020-07-15 08:44:54 -0700218 if_dump = self.vapi.sw_member_interface_dump(bond0.sw_if_index)
Vladimir Isaev72e31bc2020-02-04 11:54:27 +0300219 self.assertFalse(self.pg0.is_interface_config_in_dump(if_dump))
220 self.assertFalse(self.pg1.is_interface_config_in_dump(if_dump))
Steven9cd2d7a2017-12-20 12:43:01 -0800221
222 bond0.remove_vpp_config()
223
224 def test_bond(self):
225 """ Bond add/delete interface test """
226 self.logger.info("Bond add interfaces")
227
228 # create interface 1 (BondEthernet0)
Steven Luongea717862020-07-30 07:31:40 -0700229 bond0 = VppBondInterface(
230 self, mode=VppEnum.vl_api_bond_mode_t.BOND_API_MODE_LACP)
Steven9cd2d7a2017-12-20 12:43:01 -0800231 bond0.add_vpp_config()
232 bond0.admin_up()
233
234 # create interface 2 (BondEthernet1)
Steven Luongea717862020-07-30 07:31:40 -0700235 bond1 = VppBondInterface(
236 self, mode=VppEnum.vl_api_bond_mode_t.BOND_API_MODE_XOR)
Steven9cd2d7a2017-12-20 12:43:01 -0800237 bond1.add_vpp_config()
238 bond1.admin_up()
239
240 # verify both interfaces in the show
241 ifs = self.vapi.cli("show interface")
Paul Vinciguerra9a6dafd2019-03-06 15:11:28 -0800242 self.assertIn('BondEthernet0', ifs)
243 self.assertIn('BondEthernet1', ifs)
Steven9cd2d7a2017-12-20 12:43:01 -0800244
245 # verify they are in the dump also
Steven Luong4c4223e2020-07-15 08:44:54 -0700246 if_dump = self.vapi.sw_bond_interface_dump(sw_if_index=0xFFFFFFFF)
Steven9cd2d7a2017-12-20 12:43:01 -0800247 self.assertTrue(bond0.is_interface_config_in_dump(if_dump))
248 self.assertTrue(bond1.is_interface_config_in_dump(if_dump))
249
250 # delete BondEthernet1
251 self.logger.info("Deleting BondEthernet1")
252 bond1.remove_vpp_config()
253
254 self.logger.info("Verifying BondEthernet1 is deleted")
255
256 ifs = self.vapi.cli("show interface")
257 # verify BondEthernet0 still in the show
Paul Vinciguerra9a6dafd2019-03-06 15:11:28 -0800258 self.assertIn('BondEthernet0', ifs)
Steven9cd2d7a2017-12-20 12:43:01 -0800259
260 # verify BondEthernet1 not in the show
Paul Vinciguerra9a6dafd2019-03-06 15:11:28 -0800261 self.assertNotIn('BondEthernet1', ifs)
Steven9cd2d7a2017-12-20 12:43:01 -0800262
263 # verify BondEthernet1 is not in the dump
Steven Luong4c4223e2020-07-15 08:44:54 -0700264 if_dump = self.vapi.sw_bond_interface_dump(sw_if_index=0xFFFFFFFF)
Steven9cd2d7a2017-12-20 12:43:01 -0800265 self.assertFalse(bond1.is_interface_config_in_dump(if_dump))
266
267 # verify BondEthernet0 is still in the dump
268 self.assertTrue(bond0.is_interface_config_in_dump(if_dump))
269
270 # delete BondEthernet0
271 self.logger.info("Deleting BondEthernet0")
272 bond0.remove_vpp_config()
273
274 self.logger.info("Verifying BondEthernet0 is deleted")
275
276 # verify BondEthernet0 not in the show
277 ifs = self.vapi.cli("show interface")
Paul Vinciguerra9a6dafd2019-03-06 15:11:28 -0800278 self.assertNotIn('BondEthernet0', ifs)
Steven9cd2d7a2017-12-20 12:43:01 -0800279
280 # verify BondEthernet0 is not in the dump
Steven Luong4c4223e2020-07-15 08:44:54 -0700281 if_dump = self.vapi.sw_bond_interface_dump(
282 sw_if_index=bond0.sw_if_index)
Steven9cd2d7a2017-12-20 12:43:01 -0800283 self.assertFalse(bond0.is_interface_config_in_dump(if_dump))
284
Steven Luongdc2abbe2020-07-28 12:28:03 -0700285 def test_bond_link(self):
286 """ Bond hw interface link state test """
287
288 # for convenience
289 bond_modes = VppEnum.vl_api_bond_mode_t
290 intf_flags = VppEnum.vl_api_if_status_flags_t
291
292 # create interface 1 (BondEthernet0)
293 self.logger.info("Create bond interface")
294 # use round-robin mode to avoid negotiation required by LACP
295 bond0 = VppBondInterface(self,
296 mode=bond_modes.BOND_API_MODE_ROUND_ROBIN)
297 bond0.add_vpp_config()
298
299 # set bond admin up.
300 self.logger.info("set interface BondEthernet0 admin up")
301 bond0.admin_up()
302 # confirm link up
303 bond0.assert_interface_state(intf_flags.IF_STATUS_API_FLAG_ADMIN_UP,
304 intf_flags.IF_STATUS_API_FLAG_LINK_UP)
305
306 # toggle bond admin state
307 self.logger.info("toggle interface BondEthernet0")
308 bond0.admin_down()
309 bond0.admin_up()
310
311 # confirm link is still up
312 bond0.assert_interface_state(intf_flags.IF_STATUS_API_FLAG_ADMIN_UP,
313 intf_flags.IF_STATUS_API_FLAG_LINK_UP)
314
315 # delete BondEthernet0
316 self.logger.info("Deleting BondEthernet0")
317 bond0.remove_vpp_config()
318
Steven Luonga1876b82019-08-20 16:58:00 -0700319
Steven9cd2d7a2017-12-20 12:43:01 -0800320if __name__ == '__main__':
321 unittest.main(testRunner=VppTestRunner)