blob: 3c0df6284705325f4af1e880806fecadbbd24328 [file] [log] [blame]
Renato Botelho do Coutoead1e532019-10-31 13:31:07 -05001#!/usr/bin/env python3
Steven9cd2d7a2017-12-20 12:43:01 -08002
Steven9cd2d7a2017-12-20 12:43:01 -08003import unittest
4
Steven9cd2d7a2017-12-20 12:43:01 -08005from scapy.packet import Raw
6from scapy.layers.l2 import Ether
7from scapy.layers.inet import IP, UDP
Steven Luongdc2abbe2020-07-28 12:28:03 -07008
Dave Wallace8800f732023-08-31 00:47:44 -04009from framework import VppTestCase
10from asfframework import 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
Dmitry Valter34fa0ce2024-03-11 10:38:46 +000013from config import config
Steven9cd2d7a2017-12-20 12:43:01 -080014
15
16class TestBondInterface(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020017 """Bond Test Case"""
Steven9cd2d7a2017-12-20 12:43:01 -080018
19 @classmethod
20 def setUpClass(cls):
21 super(TestBondInterface, cls).setUpClass()
22 # Test variables
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020023 cls.pkts_per_burst = 257 # Number of packets per burst
Steven9cd2d7a2017-12-20 12:43:01 -080024 # 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):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020048 """Bond traffic test"""
Steven9cd2d7a2017-12-20 12:43:01 -080049
50 # topology
51 #
52 # RX-> TX->
53 #
Steven Luong4c4223e2020-07-15 08:44:54 -070054 # pg2 ------+ +------pg0 (member)
Steven9cd2d7a2017-12-20 12:43:01 -080055 # | |
56 # BondEthernet0 (10.10.10.1)
57 # | |
Steven Luong4c4223e2020-07-15 08:44:54 -070058 # pg3 ------+ +------pg1 (memberx)
Steven9cd2d7a2017-12-20 12:43:01 -080059 #
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
Steven Luongea717862020-07-30 07:31:40 -070065 bond0 = VppBondInterface(
66 self,
67 mode=VppEnum.vl_api_bond_mode_t.BOND_API_MODE_XOR,
68 lb=VppEnum.vl_api_bond_lb_algo_t.BOND_API_LB_ALGO_L34,
69 numa_only=0,
70 use_custom_mac=1,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020071 mac_address=mac,
72 )
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(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020076 sw_if_index=bond0.sw_if_index, prefix="10.10.10.1/24"
77 )
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
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200101 p2 = (
102 Ether(src=bond0_mac, dst=self.pg2.local_mac)
103 / IP(src=self.pg2.local_ip4, dst="10.10.10.12")
104 / UDP(sport=1235, dport=1235)
105 / Raw(b"\xa5" * 100)
106 )
Steven9cd2d7a2017-12-20 12:43:01 -0800107 self.pg2.add_stream(p2)
108
109 # generate a packet from pg3 -> BondEthernet0 -> pg0
110 # BondEthernet0 TX hashes this packet to pg0
111 # notice the ip address and ports are different than p2 packet
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200112 p3 = (
113 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(b"\xa5" * 100)
117 )
Steven9cd2d7a2017-12-20 12:43:01 -0800118 self.pg3.add_stream(p3)
119
120 self.pg_enable_capture(self.pg_interfaces)
121
122 # set up the static arp entries pointing to the BondEthernet0 interface
123 # so that it does not try to resolve the ip address
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200124 self.logger.info(
125 self.vapi.cli(
126 "set ip neighbor static BondEthernet0 10.10.10.12 abcd.abcd.0002"
127 )
128 )
129 self.logger.info(
130 self.vapi.cli(
131 "set ip neighbor static BondEthernet0 10.10.10.11 abcd.abcd.0004"
132 )
133 )
Steven9cd2d7a2017-12-20 12:43:01 -0800134
135 # clear the interface counters
136 self.logger.info(self.vapi.cli("clear interfaces"))
137
138 self.pg_start()
139
140 self.logger.info("check the interface counters")
141
142 # verify counters
143
144 # BondEthernet0 tx bytes = 284
145 intfs = self.vapi.cli("show interface BondEthernet0").split("\n")
146 found = 0
147 for intf in intfs:
148 if "tx bytes" in intf and "284" in intf:
149 found = 1
150 self.assertEqual(found, 1)
151
Steven0d883012018-05-11 11:06:23 -0700152 # BondEthernet0 tx bytes = 284
153 intfs = self.vapi.cli("show interface BondEthernet0").split("\n")
Steven9cd2d7a2017-12-20 12:43:01 -0800154 found = 0
155 for intf in intfs:
Steven0d883012018-05-11 11:06:23 -0700156 if "tx bytes" in intf and "284" in intf:
Steven9cd2d7a2017-12-20 12:43:01 -0800157 found = 1
158 self.assertEqual(found, 1)
159
160 # pg2 rx bytes = 142
161 intfs = self.vapi.cli("show interface pg2").split("\n")
162 found = 0
163 for intf in intfs:
164 if "rx bytes" in intf and "142" in intf:
165 found = 1
166 self.assertEqual(found, 1)
167
168 # pg3 rx bytes = 142
169 intfs = self.vapi.cli("show interface pg3").split("\n")
170 found = 0
171 for intf in intfs:
172 if "rx bytes" in intf and "142" in intf:
173 found = 1
174 self.assertEqual(found, 1)
175
176 bond0.remove_vpp_config()
177
Dmitry Valter34fa0ce2024-03-11 10:38:46 +0000178 @unittest.skipIf(
179 "lacp" in config.excluded_plugins, "Exclude tests requiring LACP plugin"
180 )
Steven Luong4c4223e2020-07-15 08:44:54 -0700181 def test_bond_add_member(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200182 """Bond add_member/detach member test"""
Steven9cd2d7a2017-12-20 12:43:01 -0800183
Vladimir Isaev72e31bc2020-02-04 11:54:27 +0300184 # create interface (BondEthernet0) and set bond mode to LACP
Steven9cd2d7a2017-12-20 12:43:01 -0800185 self.logger.info("create bond")
Steven Luongea717862020-07-30 07:31:40 -0700186 bond0 = VppBondInterface(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200187 self, mode=VppEnum.vl_api_bond_mode_t.BOND_API_MODE_LACP, enable_gso=0
188 )
Steven9cd2d7a2017-12-20 12:43:01 -0800189 bond0.add_vpp_config()
190 bond0.admin_up()
191
Steven Luong4c4223e2020-07-15 08:44:54 -0700192 # verify that interfaces can be added as_member and detached two times
Vladimir Isaev72e31bc2020-02-04 11:54:27 +0300193 for i in range(2):
194 # verify pg0 and pg1 not in BondEthernet0
Steven Luong4c4223e2020-07-15 08:44:54 -0700195 if_dump = self.vapi.sw_member_interface_dump(bond0.sw_if_index)
Vladimir Isaev72e31bc2020-02-04 11:54:27 +0300196 self.assertFalse(self.pg0.is_interface_config_in_dump(if_dump))
197 self.assertFalse(self.pg1.is_interface_config_in_dump(if_dump))
Steven9cd2d7a2017-12-20 12:43:01 -0800198
Steven Luong4c4223e2020-07-15 08:44:54 -0700199 # add_member pg0 and pg1 to BondEthernet0
200 self.logger.info("bond add_member interface pg0 to BondEthernet0")
201 bond0.add_member_vpp_bond_interface(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200202 sw_if_index=self.pg0.sw_if_index, is_passive=0, is_long_timeout=0
203 )
Steven9cd2d7a2017-12-20 12:43:01 -0800204
Steven Luong4c4223e2020-07-15 08:44:54 -0700205 self.logger.info("bond add_member interface pg1 to BondEthernet0")
206 bond0.add_member_vpp_bond_interface(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200207 sw_if_index=self.pg1.sw_if_index, is_passive=0, is_long_timeout=0
208 )
Steven Luong4c4223e2020-07-15 08:44:54 -0700209 # verify both members in BondEthernet0
210 if_dump = self.vapi.sw_member_interface_dump(bond0.sw_if_index)
Vladimir Isaev72e31bc2020-02-04 11:54:27 +0300211 self.assertTrue(self.pg0.is_interface_config_in_dump(if_dump))
212 self.assertTrue(self.pg1.is_interface_config_in_dump(if_dump))
Steven9cd2d7a2017-12-20 12:43:01 -0800213
Vladimir Isaev72e31bc2020-02-04 11:54:27 +0300214 # detach interface pg0
215 self.logger.info("detach interface pg0")
216 bond0.detach_vpp_bond_interface(sw_if_index=self.pg0.sw_if_index)
Steven9cd2d7a2017-12-20 12:43:01 -0800217
Vladimir Isaev72e31bc2020-02-04 11:54:27 +0300218 # verify pg0 is not in BondEthernet0, but pg1 is
Steven Luong4c4223e2020-07-15 08:44:54 -0700219 if_dump = self.vapi.sw_member_interface_dump(bond0.sw_if_index)
Vladimir Isaev72e31bc2020-02-04 11:54:27 +0300220 self.assertFalse(self.pg0.is_interface_config_in_dump(if_dump))
221 self.assertTrue(self.pg1.is_interface_config_in_dump(if_dump))
Steven9cd2d7a2017-12-20 12:43:01 -0800222
Vladimir Isaev72e31bc2020-02-04 11:54:27 +0300223 # detach interface pg1
224 self.logger.info("detach interface pg1")
225 bond0.detach_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index)
Steven9cd2d7a2017-12-20 12:43:01 -0800226
Vladimir Isaev72e31bc2020-02-04 11:54:27 +0300227 # verify pg0 and pg1 not in BondEthernet0
Steven Luong4c4223e2020-07-15 08:44:54 -0700228 if_dump = self.vapi.sw_member_interface_dump(bond0.sw_if_index)
Vladimir Isaev72e31bc2020-02-04 11:54:27 +0300229 self.assertFalse(self.pg0.is_interface_config_in_dump(if_dump))
230 self.assertFalse(self.pg1.is_interface_config_in_dump(if_dump))
Steven9cd2d7a2017-12-20 12:43:01 -0800231
232 bond0.remove_vpp_config()
233
Dmitry Valter34fa0ce2024-03-11 10:38:46 +0000234 @unittest.skipIf(
235 "lacp" in config.excluded_plugins, "Exclude tests requiring LACP plugin"
236 )
Steven9cd2d7a2017-12-20 12:43:01 -0800237 def test_bond(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200238 """Bond add/delete interface test"""
Steven9cd2d7a2017-12-20 12:43:01 -0800239 self.logger.info("Bond add interfaces")
240
241 # create interface 1 (BondEthernet0)
Steven Luongea717862020-07-30 07:31:40 -0700242 bond0 = VppBondInterface(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200243 self, mode=VppEnum.vl_api_bond_mode_t.BOND_API_MODE_LACP
244 )
Steven9cd2d7a2017-12-20 12:43:01 -0800245 bond0.add_vpp_config()
246 bond0.admin_up()
247
248 # create interface 2 (BondEthernet1)
Steven Luongea717862020-07-30 07:31:40 -0700249 bond1 = VppBondInterface(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200250 self, mode=VppEnum.vl_api_bond_mode_t.BOND_API_MODE_XOR
251 )
Steven9cd2d7a2017-12-20 12:43:01 -0800252 bond1.add_vpp_config()
253 bond1.admin_up()
254
255 # verify both interfaces in the show
256 ifs = self.vapi.cli("show interface")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200257 self.assertIn("BondEthernet0", ifs)
258 self.assertIn("BondEthernet1", ifs)
Steven9cd2d7a2017-12-20 12:43:01 -0800259
260 # verify they are in the dump also
Steven Luong4c4223e2020-07-15 08:44:54 -0700261 if_dump = self.vapi.sw_bond_interface_dump(sw_if_index=0xFFFFFFFF)
Steven9cd2d7a2017-12-20 12:43:01 -0800262 self.assertTrue(bond0.is_interface_config_in_dump(if_dump))
263 self.assertTrue(bond1.is_interface_config_in_dump(if_dump))
264
265 # delete BondEthernet1
266 self.logger.info("Deleting BondEthernet1")
267 bond1.remove_vpp_config()
268
269 self.logger.info("Verifying BondEthernet1 is deleted")
270
271 ifs = self.vapi.cli("show interface")
272 # verify BondEthernet0 still in the show
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200273 self.assertIn("BondEthernet0", ifs)
Steven9cd2d7a2017-12-20 12:43:01 -0800274
275 # verify BondEthernet1 not in the show
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200276 self.assertNotIn("BondEthernet1", ifs)
Steven9cd2d7a2017-12-20 12:43:01 -0800277
278 # verify BondEthernet1 is not in the dump
Steven Luong4c4223e2020-07-15 08:44:54 -0700279 if_dump = self.vapi.sw_bond_interface_dump(sw_if_index=0xFFFFFFFF)
Steven9cd2d7a2017-12-20 12:43:01 -0800280 self.assertFalse(bond1.is_interface_config_in_dump(if_dump))
281
282 # verify BondEthernet0 is still in the dump
283 self.assertTrue(bond0.is_interface_config_in_dump(if_dump))
284
285 # delete BondEthernet0
286 self.logger.info("Deleting BondEthernet0")
287 bond0.remove_vpp_config()
288
289 self.logger.info("Verifying BondEthernet0 is deleted")
290
291 # verify BondEthernet0 not in the show
292 ifs = self.vapi.cli("show interface")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200293 self.assertNotIn("BondEthernet0", ifs)
Steven9cd2d7a2017-12-20 12:43:01 -0800294
295 # verify BondEthernet0 is not in the dump
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200296 if_dump = self.vapi.sw_bond_interface_dump(sw_if_index=bond0.sw_if_index)
Steven9cd2d7a2017-12-20 12:43:01 -0800297 self.assertFalse(bond0.is_interface_config_in_dump(if_dump))
298
Steven Luongdc2abbe2020-07-28 12:28:03 -0700299 def test_bond_link(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200300 """Bond hw interface link state test"""
Steven Luongdc2abbe2020-07-28 12:28:03 -0700301
302 # for convenience
303 bond_modes = VppEnum.vl_api_bond_mode_t
304 intf_flags = VppEnum.vl_api_if_status_flags_t
305
306 # create interface 1 (BondEthernet0)
307 self.logger.info("Create bond interface")
308 # use round-robin mode to avoid negotiation required by LACP
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200309 bond0 = VppBondInterface(self, mode=bond_modes.BOND_API_MODE_ROUND_ROBIN)
Steven Luongdc2abbe2020-07-28 12:28:03 -0700310 bond0.add_vpp_config()
311
312 # set bond admin up.
313 self.logger.info("set interface BondEthernet0 admin up")
314 bond0.admin_up()
315 # confirm link up
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200316 bond0.assert_interface_state(
317 intf_flags.IF_STATUS_API_FLAG_ADMIN_UP,
318 intf_flags.IF_STATUS_API_FLAG_LINK_UP,
319 )
Steven Luongdc2abbe2020-07-28 12:28:03 -0700320
321 # toggle bond admin state
322 self.logger.info("toggle interface BondEthernet0")
323 bond0.admin_down()
324 bond0.admin_up()
325
326 # confirm link is still up
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200327 bond0.assert_interface_state(
328 intf_flags.IF_STATUS_API_FLAG_ADMIN_UP,
329 intf_flags.IF_STATUS_API_FLAG_LINK_UP,
330 )
Steven Luongdc2abbe2020-07-28 12:28:03 -0700331
332 # delete BondEthernet0
333 self.logger.info("Deleting BondEthernet0")
334 bond0.remove_vpp_config()
335
Steven Luonga1876b82019-08-20 16:58:00 -0700336
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200337if __name__ == "__main__":
Steven9cd2d7a2017-12-20 12:43:01 -0800338 unittest.main(testRunner=VppTestRunner)