blob: 03f0eea4c7e0d153de0dbd9a4ff2e63a0962096f [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
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,
68 use_custom_mac=1,
69 mac_address=mac)
70 bond0.add_vpp_config()
71 bond0.admin_up()
Ole Trøan3b0d7e42019-03-15 16:14:41 +000072 bond0_addr = socket.inet_pton(socket.AF_INET, "10.10.10.1")
73 self.vapi.sw_interface_add_del_address(sw_if_index=bond0.sw_if_index,
74 address=bond0_addr,
75 address_length=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"))
84 self.logger.info(self.vapi.cli("show ip arp"))
85
86 # enslave pg0 and pg1 to BondEthernet0
87 self.logger.info("bond enslave interface pg0 to BondEthernet0")
88 bond0.enslave_vpp_bond_interface(sw_if_index=self.pg0.sw_if_index,
89 is_passive=0,
90 is_long_timeout=0)
91 self.logger.info("bond enslave interface pg1 to BondEthernet0")
92 bond0.enslave_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index,
93 is_passive=0,
94 is_long_timeout=0)
95
96 # verify both slaves in BondEthernet0
97 if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index)
98 self.assertTrue(self.pg0.is_interface_config_in_dump(if_dump))
99 self.assertTrue(self.pg1.is_interface_config_in_dump(if_dump))
100
101 # generate a packet from pg2 -> BondEthernet0 -> pg1
102 # BondEthernet0 TX hashes this packet to pg1
103 p2 = (Ether(src=bond0_mac, dst=self.pg2.local_mac) /
104 IP(src=self.pg2.local_ip4, dst="10.10.10.12") /
105 UDP(sport=1235, dport=1235) /
106 Raw('\xa5' * 100))
107 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
112 p3 = (Ether(src=bond0_mac, dst=self.pg3.local_mac) /
113 IP(src=self.pg3.local_ip4, dst="10.10.10.11") /
114 UDP(sport=1234, dport=1234) /
115 Raw('\xa5' * 100))
116 self.pg3.add_stream(p3)
117
118 self.pg_enable_capture(self.pg_interfaces)
119
120 # set up the static arp entries pointing to the BondEthernet0 interface
121 # so that it does not try to resolve the ip address
122 self.logger.info(self.vapi.cli(
123 "set ip arp static BondEthernet0 10.10.10.12 abcd.abcd.0002"))
124 self.logger.info(self.vapi.cli(
125 "set ip arp static BondEthernet0 10.10.10.11 abcd.abcd.0004"))
126
127 # clear the interface counters
128 self.logger.info(self.vapi.cli("clear interfaces"))
129
130 self.pg_start()
131
132 self.logger.info("check the interface counters")
133
134 # verify counters
135
136 # BondEthernet0 tx bytes = 284
137 intfs = self.vapi.cli("show interface BondEthernet0").split("\n")
138 found = 0
139 for intf in intfs:
140 if "tx bytes" in intf and "284" in intf:
141 found = 1
142 self.assertEqual(found, 1)
143
Steven0d883012018-05-11 11:06:23 -0700144 # BondEthernet0 tx bytes = 284
145 intfs = self.vapi.cli("show interface BondEthernet0").split("\n")
Steven9cd2d7a2017-12-20 12:43:01 -0800146 found = 0
147 for intf in intfs:
Steven0d883012018-05-11 11:06:23 -0700148 if "tx bytes" in intf and "284" in intf:
Steven9cd2d7a2017-12-20 12:43:01 -0800149 found = 1
150 self.assertEqual(found, 1)
151
152 # pg2 rx bytes = 142
153 intfs = self.vapi.cli("show interface pg2").split("\n")
154 found = 0
155 for intf in intfs:
156 if "rx bytes" in intf and "142" in intf:
157 found = 1
158 self.assertEqual(found, 1)
159
160 # pg3 rx bytes = 142
161 intfs = self.vapi.cli("show interface pg3").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 bond0.remove_vpp_config()
169
170 def test_bond_enslave(self):
171 """ Bond enslave/detach slave test """
172
173 # create interface (BondEthernet0)
174 self.logger.info("create bond")
175 bond0 = VppBondInterface(self, mode=3)
176 bond0.add_vpp_config()
177 bond0.admin_up()
178
179 # verify pg0 and pg1 not in BondEthernet0
180 if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index)
181 self.assertFalse(self.pg0.is_interface_config_in_dump(if_dump))
182 self.assertFalse(self.pg1.is_interface_config_in_dump(if_dump))
183
184 # enslave pg0 and pg1 to BondEthernet0
185 self.logger.info("bond enslave interface pg0 to BondEthernet0")
186 bond0.enslave_vpp_bond_interface(sw_if_index=self.pg0.sw_if_index,
187 is_passive=0,
188 is_long_timeout=0)
189
190 self.logger.info("bond enslave interface pg1 to BondEthernet0")
191 bond0.enslave_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index,
192 is_passive=0,
193 is_long_timeout=0)
194
195 # verify both slaves in BondEthernet0
196 if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index)
197 self.assertTrue(self.pg0.is_interface_config_in_dump(if_dump))
198 self.assertTrue(self.pg1.is_interface_config_in_dump(if_dump))
199
200 # detach interface pg0
201 self.logger.info("detach interface pg0")
202 bond0.detach_vpp_bond_interface(sw_if_index=self.pg0.sw_if_index)
203
204 # verify pg0 is not in BondEthernet0, but pg1 is
205 if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index)
206 self.assertFalse(self.pg0.is_interface_config_in_dump(if_dump))
207 self.assertTrue(self.pg1.is_interface_config_in_dump(if_dump))
208
209 # detach interface pg1
210 self.logger.info("detach interface pg1")
211 bond0.detach_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index)
212
213 # verify pg0 and pg1 not in BondEthernet0
214 if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index)
215 self.assertFalse(self.pg0.is_interface_config_in_dump(if_dump))
216 self.assertFalse(self.pg1.is_interface_config_in_dump(if_dump))
217
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
240 if_dump = self.vapi.sw_interface_bond_dump()
241 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
258 if_dump = self.vapi.sw_interface_bond_dump()
259 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
275 if_dump = self.vapi.sw_interface_bond_dump()
276 self.assertFalse(bond0.is_interface_config_in_dump(if_dump))
277
278if __name__ == '__main__':
279 unittest.main(testRunner=VppTestRunner)