blob: c5d786fc5269acfd1bfc15b626847c4c4bcd6bca [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
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,
Neale Rannsefd7bc22019-11-11 08:32:34 +000076 prefix="10.10.10.1/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"))
Neale Rannscbe25aa2019-09-30 10:53:31 +000085 self.logger.info(self.vapi.cli("show ip neighbors"))
Steven9cd2d7a2017-12-20 12:43:01 -080086
Steven Luong4c4223e2020-07-15 08:44:54 -070087 # add member pg0 and pg1 to BondEthernet0
88 self.logger.info("bond add member interface pg0 to BondEthernet0")
89 bond0.add_member_vpp_bond_interface(sw_if_index=self.pg0.sw_if_index)
90 self.logger.info("bond add_member interface pg1 to BondEthernet0")
91 bond0.add_member_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index)
Steven9cd2d7a2017-12-20 12:43:01 -080092
Steven Luong4c4223e2020-07-15 08:44:54 -070093 # verify both members in BondEthernet0
94 if_dump = self.vapi.sw_member_interface_dump(bond0.sw_if_index)
Steven9cd2d7a2017-12-20 12:43:01 -080095 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) /
Ole Troanf6dee6c2019-10-21 20:41:44 +0200103 Raw(b'\xa5' * 100))
Steven9cd2d7a2017-12-20 12:43:01 -0800104 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) /
Ole Troanf6dee6c2019-10-21 20:41:44 +0200112 Raw(b'\xa5' * 100))
Steven9cd2d7a2017-12-20 12:43:01 -0800113 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(
Neale Rannscbe25aa2019-09-30 10:53:31 +0000120 "set ip neighbor static BondEthernet0 10.10.10.12 abcd.abcd.0002"))
Steven9cd2d7a2017-12-20 12:43:01 -0800121 self.logger.info(self.vapi.cli(
Neale Rannscbe25aa2019-09-30 10:53:31 +0000122 "set ip neighbor static BondEthernet0 10.10.10.11 abcd.abcd.0004"))
Steven9cd2d7a2017-12-20 12:43:01 -0800123
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
Steven Luong4c4223e2020-07-15 08:44:54 -0700167 def test_bond_add_member(self):
168 """ Bond add_member/detach member test """
Steven9cd2d7a2017-12-20 12:43:01 -0800169
Vladimir Isaev72e31bc2020-02-04 11:54:27 +0300170 # create interface (BondEthernet0) and set bond mode to LACP
Steven9cd2d7a2017-12-20 12:43:01 -0800171 self.logger.info("create bond")
Vladimir Isaev72e31bc2020-02-04 11:54:27 +0300172 bond0 = VppBondInterface(self, mode=5)
Steven9cd2d7a2017-12-20 12:43:01 -0800173 bond0.add_vpp_config()
174 bond0.admin_up()
175
Steven Luong4c4223e2020-07-15 08:44:54 -0700176 # verify that interfaces can be added as_member and detached two times
Vladimir Isaev72e31bc2020-02-04 11:54:27 +0300177 for i in range(2):
178 # verify pg0 and pg1 not in BondEthernet0
Steven Luong4c4223e2020-07-15 08:44:54 -0700179 if_dump = self.vapi.sw_member_interface_dump(bond0.sw_if_index)
Vladimir Isaev72e31bc2020-02-04 11:54:27 +0300180 self.assertFalse(self.pg0.is_interface_config_in_dump(if_dump))
181 self.assertFalse(self.pg1.is_interface_config_in_dump(if_dump))
Steven9cd2d7a2017-12-20 12:43:01 -0800182
Steven Luong4c4223e2020-07-15 08:44:54 -0700183 # add_member pg0 and pg1 to BondEthernet0
184 self.logger.info("bond add_member interface pg0 to BondEthernet0")
185 bond0.add_member_vpp_bond_interface(
186 sw_if_index=self.pg0.sw_if_index,
187 is_passive=0,
188 is_long_timeout=0)
Steven9cd2d7a2017-12-20 12:43:01 -0800189
Steven Luong4c4223e2020-07-15 08:44:54 -0700190 self.logger.info("bond add_member interface pg1 to BondEthernet0")
191 bond0.add_member_vpp_bond_interface(
192 sw_if_index=self.pg1.sw_if_index,
193 is_passive=0,
194 is_long_timeout=0)
195 # verify both members in BondEthernet0
196 if_dump = self.vapi.sw_member_interface_dump(bond0.sw_if_index)
Vladimir Isaev72e31bc2020-02-04 11:54:27 +0300197 self.assertTrue(self.pg0.is_interface_config_in_dump(if_dump))
198 self.assertTrue(self.pg1.is_interface_config_in_dump(if_dump))
Steven9cd2d7a2017-12-20 12:43:01 -0800199
Vladimir Isaev72e31bc2020-02-04 11:54:27 +0300200 # detach interface pg0
201 self.logger.info("detach interface pg0")
202 bond0.detach_vpp_bond_interface(sw_if_index=self.pg0.sw_if_index)
Steven9cd2d7a2017-12-20 12:43:01 -0800203
Vladimir Isaev72e31bc2020-02-04 11:54:27 +0300204 # verify pg0 is not in BondEthernet0, but pg1 is
Steven Luong4c4223e2020-07-15 08:44:54 -0700205 if_dump = self.vapi.sw_member_interface_dump(bond0.sw_if_index)
Vladimir Isaev72e31bc2020-02-04 11:54:27 +0300206 self.assertFalse(self.pg0.is_interface_config_in_dump(if_dump))
207 self.assertTrue(self.pg1.is_interface_config_in_dump(if_dump))
Steven9cd2d7a2017-12-20 12:43:01 -0800208
Vladimir Isaev72e31bc2020-02-04 11:54:27 +0300209 # detach interface pg1
210 self.logger.info("detach interface pg1")
211 bond0.detach_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index)
Steven9cd2d7a2017-12-20 12:43:01 -0800212
Vladimir Isaev72e31bc2020-02-04 11:54:27 +0300213 # verify pg0 and pg1 not in BondEthernet0
Steven Luong4c4223e2020-07-15 08:44:54 -0700214 if_dump = self.vapi.sw_member_interface_dump(bond0.sw_if_index)
Vladimir Isaev72e31bc2020-02-04 11:54:27 +0300215 self.assertFalse(self.pg0.is_interface_config_in_dump(if_dump))
216 self.assertFalse(self.pg1.is_interface_config_in_dump(if_dump))
Steven9cd2d7a2017-12-20 12:43:01 -0800217
218 bond0.remove_vpp_config()
219
220 def test_bond(self):
221 """ Bond add/delete interface test """
222 self.logger.info("Bond add interfaces")
223
224 # create interface 1 (BondEthernet0)
225 bond0 = VppBondInterface(self, mode=5)
226 bond0.add_vpp_config()
227 bond0.admin_up()
228
229 # create interface 2 (BondEthernet1)
230 bond1 = VppBondInterface(self, mode=3)
231 bond1.add_vpp_config()
232 bond1.admin_up()
233
234 # verify both interfaces in the show
235 ifs = self.vapi.cli("show interface")
Paul Vinciguerra9a6dafd2019-03-06 15:11:28 -0800236 self.assertIn('BondEthernet0', ifs)
237 self.assertIn('BondEthernet1', ifs)
Steven9cd2d7a2017-12-20 12:43:01 -0800238
239 # verify they are in the dump also
Steven Luong4c4223e2020-07-15 08:44:54 -0700240 if_dump = self.vapi.sw_bond_interface_dump(sw_if_index=0xFFFFFFFF)
Steven9cd2d7a2017-12-20 12:43:01 -0800241 self.assertTrue(bond0.is_interface_config_in_dump(if_dump))
242 self.assertTrue(bond1.is_interface_config_in_dump(if_dump))
243
244 # delete BondEthernet1
245 self.logger.info("Deleting BondEthernet1")
246 bond1.remove_vpp_config()
247
248 self.logger.info("Verifying BondEthernet1 is deleted")
249
250 ifs = self.vapi.cli("show interface")
251 # verify BondEthernet0 still in the show
Paul Vinciguerra9a6dafd2019-03-06 15:11:28 -0800252 self.assertIn('BondEthernet0', ifs)
Steven9cd2d7a2017-12-20 12:43:01 -0800253
254 # verify BondEthernet1 not in the show
Paul Vinciguerra9a6dafd2019-03-06 15:11:28 -0800255 self.assertNotIn('BondEthernet1', ifs)
Steven9cd2d7a2017-12-20 12:43:01 -0800256
257 # verify BondEthernet1 is not in the dump
Steven Luong4c4223e2020-07-15 08:44:54 -0700258 if_dump = self.vapi.sw_bond_interface_dump(sw_if_index=0xFFFFFFFF)
Steven9cd2d7a2017-12-20 12:43:01 -0800259 self.assertFalse(bond1.is_interface_config_in_dump(if_dump))
260
261 # verify BondEthernet0 is still in the dump
262 self.assertTrue(bond0.is_interface_config_in_dump(if_dump))
263
264 # delete BondEthernet0
265 self.logger.info("Deleting BondEthernet0")
266 bond0.remove_vpp_config()
267
268 self.logger.info("Verifying BondEthernet0 is deleted")
269
270 # verify BondEthernet0 not in the show
271 ifs = self.vapi.cli("show interface")
Paul Vinciguerra9a6dafd2019-03-06 15:11:28 -0800272 self.assertNotIn('BondEthernet0', ifs)
Steven9cd2d7a2017-12-20 12:43:01 -0800273
274 # verify BondEthernet0 is not in the dump
Steven Luong4c4223e2020-07-15 08:44:54 -0700275 if_dump = self.vapi.sw_bond_interface_dump(
276 sw_if_index=bond0.sw_if_index)
Steven9cd2d7a2017-12-20 12:43:01 -0800277 self.assertFalse(bond0.is_interface_config_in_dump(if_dump))
278
Steven Luongdc2abbe2020-07-28 12:28:03 -0700279 def test_bond_link(self):
280 """ Bond hw interface link state test """
281
282 # for convenience
283 bond_modes = VppEnum.vl_api_bond_mode_t
284 intf_flags = VppEnum.vl_api_if_status_flags_t
285
286 # create interface 1 (BondEthernet0)
287 self.logger.info("Create bond interface")
288 # use round-robin mode to avoid negotiation required by LACP
289 bond0 = VppBondInterface(self,
290 mode=bond_modes.BOND_API_MODE_ROUND_ROBIN)
291 bond0.add_vpp_config()
292
293 # set bond admin up.
294 self.logger.info("set interface BondEthernet0 admin up")
295 bond0.admin_up()
296 # confirm link up
297 bond0.assert_interface_state(intf_flags.IF_STATUS_API_FLAG_ADMIN_UP,
298 intf_flags.IF_STATUS_API_FLAG_LINK_UP)
299
300 # toggle bond admin state
301 self.logger.info("toggle interface BondEthernet0")
302 bond0.admin_down()
303 bond0.admin_up()
304
305 # confirm link is still up
306 bond0.assert_interface_state(intf_flags.IF_STATUS_API_FLAG_ADMIN_UP,
307 intf_flags.IF_STATUS_API_FLAG_LINK_UP)
308
309 # delete BondEthernet0
310 self.logger.info("Deleting BondEthernet0")
311 bond0.remove_vpp_config()
312
Steven Luonga1876b82019-08-20 16:58:00 -0700313
Steven9cd2d7a2017-12-20 12:43:01 -0800314if __name__ == '__main__':
315 unittest.main(testRunner=VppTestRunner)