blob: dd4a6453977bf28b363e44f82a47f2012a9e4d6e [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
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()
Jakub Grajciar053204a2019-03-18 13:17:53 +010073 self.vapi.sw_interface_add_del_address(
74 sw_if_index=bond0.sw_if_index,
Neale Rannsefd7bc22019-11-11 08:32:34 +000075 prefix="10.10.10.1/24")
Steven9cd2d7a2017-12-20 12:43:01 -080076
77 self.pg2.config_ip4()
78 self.pg2.resolve_arp()
79 self.pg3.config_ip4()
80 self.pg3.resolve_arp()
81
82 self.logger.info(self.vapi.cli("show interface"))
83 self.logger.info(self.vapi.cli("show interface address"))
Neale Rannscbe25aa2019-09-30 10:53:31 +000084 self.logger.info(self.vapi.cli("show ip neighbors"))
Steven9cd2d7a2017-12-20 12:43:01 -080085
86 # enslave pg0 and pg1 to BondEthernet0
87 self.logger.info("bond enslave interface pg0 to BondEthernet0")
Steven Luonga1876b82019-08-20 16:58:00 -070088 bond0.enslave_vpp_bond_interface(sw_if_index=self.pg0.sw_if_index)
Steven9cd2d7a2017-12-20 12:43:01 -080089 self.logger.info("bond enslave interface pg1 to BondEthernet0")
Steven Luonga1876b82019-08-20 16:58:00 -070090 bond0.enslave_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index)
Steven9cd2d7a2017-12-20 12:43:01 -080091
92 # verify both slaves in BondEthernet0
93 if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index)
94 self.assertTrue(self.pg0.is_interface_config_in_dump(if_dump))
95 self.assertTrue(self.pg1.is_interface_config_in_dump(if_dump))
96
97 # generate a packet from pg2 -> BondEthernet0 -> pg1
98 # BondEthernet0 TX hashes this packet to pg1
99 p2 = (Ether(src=bond0_mac, dst=self.pg2.local_mac) /
100 IP(src=self.pg2.local_ip4, dst="10.10.10.12") /
101 UDP(sport=1235, dport=1235) /
Ole Troanf6dee6c2019-10-21 20:41:44 +0200102 Raw(b'\xa5' * 100))
Steven9cd2d7a2017-12-20 12:43:01 -0800103 self.pg2.add_stream(p2)
104
105 # generate a packet from pg3 -> BondEthernet0 -> pg0
106 # BondEthernet0 TX hashes this packet to pg0
107 # notice the ip address and ports are different than p2 packet
108 p3 = (Ether(src=bond0_mac, dst=self.pg3.local_mac) /
109 IP(src=self.pg3.local_ip4, dst="10.10.10.11") /
110 UDP(sport=1234, dport=1234) /
Ole Troanf6dee6c2019-10-21 20:41:44 +0200111 Raw(b'\xa5' * 100))
Steven9cd2d7a2017-12-20 12:43:01 -0800112 self.pg3.add_stream(p3)
113
114 self.pg_enable_capture(self.pg_interfaces)
115
116 # set up the static arp entries pointing to the BondEthernet0 interface
117 # so that it does not try to resolve the ip address
118 self.logger.info(self.vapi.cli(
Neale Rannscbe25aa2019-09-30 10:53:31 +0000119 "set ip neighbor static BondEthernet0 10.10.10.12 abcd.abcd.0002"))
Steven9cd2d7a2017-12-20 12:43:01 -0800120 self.logger.info(self.vapi.cli(
Neale Rannscbe25aa2019-09-30 10:53:31 +0000121 "set ip neighbor static BondEthernet0 10.10.10.11 abcd.abcd.0004"))
Steven9cd2d7a2017-12-20 12:43:01 -0800122
123 # clear the interface counters
124 self.logger.info(self.vapi.cli("clear interfaces"))
125
126 self.pg_start()
127
128 self.logger.info("check the interface counters")
129
130 # verify counters
131
132 # BondEthernet0 tx bytes = 284
133 intfs = self.vapi.cli("show interface BondEthernet0").split("\n")
134 found = 0
135 for intf in intfs:
136 if "tx bytes" in intf and "284" in intf:
137 found = 1
138 self.assertEqual(found, 1)
139
Steven0d883012018-05-11 11:06:23 -0700140 # BondEthernet0 tx bytes = 284
141 intfs = self.vapi.cli("show interface BondEthernet0").split("\n")
Steven9cd2d7a2017-12-20 12:43:01 -0800142 found = 0
143 for intf in intfs:
Steven0d883012018-05-11 11:06:23 -0700144 if "tx bytes" in intf and "284" in intf:
Steven9cd2d7a2017-12-20 12:43:01 -0800145 found = 1
146 self.assertEqual(found, 1)
147
148 # pg2 rx bytes = 142
149 intfs = self.vapi.cli("show interface pg2").split("\n")
150 found = 0
151 for intf in intfs:
152 if "rx bytes" in intf and "142" in intf:
153 found = 1
154 self.assertEqual(found, 1)
155
156 # pg3 rx bytes = 142
157 intfs = self.vapi.cli("show interface pg3").split("\n")
158 found = 0
159 for intf in intfs:
160 if "rx bytes" in intf and "142" in intf:
161 found = 1
162 self.assertEqual(found, 1)
163
164 bond0.remove_vpp_config()
165
166 def test_bond_enslave(self):
167 """ Bond enslave/detach slave test """
168
Vladimir Isaev72e31bc2020-02-04 11:54:27 +0300169 # create interface (BondEthernet0) and set bond mode to LACP
Steven9cd2d7a2017-12-20 12:43:01 -0800170 self.logger.info("create bond")
Vladimir Isaev72e31bc2020-02-04 11:54:27 +0300171 bond0 = VppBondInterface(self, mode=5)
Steven9cd2d7a2017-12-20 12:43:01 -0800172 bond0.add_vpp_config()
173 bond0.admin_up()
174
Vladimir Isaev72e31bc2020-02-04 11:54:27 +0300175 # verify that interfaces can be enslaved and detached two times
176 for i in range(2):
177 # verify pg0 and pg1 not in BondEthernet0
178 if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index)
179 self.assertFalse(self.pg0.is_interface_config_in_dump(if_dump))
180 self.assertFalse(self.pg1.is_interface_config_in_dump(if_dump))
Steven9cd2d7a2017-12-20 12:43:01 -0800181
Vladimir Isaev72e31bc2020-02-04 11:54:27 +0300182 # enslave pg0 and pg1 to BondEthernet0
183 self.logger.info("bond enslave interface pg0 to BondEthernet0")
184 bond0.enslave_vpp_bond_interface(sw_if_index=self.pg0.sw_if_index,
185 is_passive=0,
186 is_long_timeout=0)
Steven9cd2d7a2017-12-20 12:43:01 -0800187
Vladimir Isaev72e31bc2020-02-04 11:54:27 +0300188 self.logger.info("bond enslave interface pg1 to BondEthernet0")
189 bond0.enslave_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index,
190 is_passive=0,
191 is_long_timeout=0)
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))
Steven9cd2d7a2017-12-20 12:43:01 -0800196
Vladimir Isaev72e31bc2020-02-04 11:54:27 +0300197 # detach interface pg0
198 self.logger.info("detach interface pg0")
199 bond0.detach_vpp_bond_interface(sw_if_index=self.pg0.sw_if_index)
Steven9cd2d7a2017-12-20 12:43:01 -0800200
Vladimir Isaev72e31bc2020-02-04 11:54:27 +0300201 # 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))
Steven9cd2d7a2017-12-20 12:43:01 -0800205
Vladimir Isaev72e31bc2020-02-04 11:54:27 +0300206 # detach interface pg1
207 self.logger.info("detach interface pg1")
208 bond0.detach_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index)
Steven9cd2d7a2017-12-20 12:43:01 -0800209
Vladimir Isaev72e31bc2020-02-04 11:54:27 +0300210 # 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))
Steven9cd2d7a2017-12-20 12:43:01 -0800214
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)