blob: 9926d230564810356bc3ee6f712a69a6177a4d4c [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
34 def setUp(self):
35 super(TestBondInterface, self).setUp()
36
37 def tearDown(self):
38 super(TestBondInterface, self).tearDown()
39 if not self.vpp_dead:
40 self.logger.info(self.vapi.ppcli("show interface"))
41
42 def test_bond_traffic(self):
43 """ Bond traffic test """
44
45 # topology
46 #
47 # RX-> TX->
48 #
49 # pg2 ------+ +------pg0 (slave)
50 # | |
51 # BondEthernet0 (10.10.10.1)
52 # | |
53 # pg3 ------+ +------pg1 (slave)
54 #
55
56 # create interface (BondEthernet0)
57 # self.logger.info("create bond")
58 bond0_mac = "02:fe:38:30:59:3c"
Ole Troan8006c6a2018-12-17 12:02:26 +010059 mac = MACAddress(bond0_mac).packed
Steven9cd2d7a2017-12-20 12:43:01 -080060 bond0 = VppBondInterface(self,
61 mode=3,
62 lb=1,
63 use_custom_mac=1,
64 mac_address=mac)
65 bond0.add_vpp_config()
66 bond0.admin_up()
67 bond0_addr = socket.inet_pton(socket.AF_INET, "10.10.10.1")
68 self.vapi.sw_interface_add_del_address(bond0.sw_if_index,
69 bond0_addr,
70 24)
71
72 self.pg2.config_ip4()
73 self.pg2.resolve_arp()
74 self.pg3.config_ip4()
75 self.pg3.resolve_arp()
76
77 self.logger.info(self.vapi.cli("show interface"))
78 self.logger.info(self.vapi.cli("show interface address"))
79 self.logger.info(self.vapi.cli("show ip arp"))
80
81 # enslave pg0 and pg1 to BondEthernet0
82 self.logger.info("bond enslave interface pg0 to BondEthernet0")
83 bond0.enslave_vpp_bond_interface(sw_if_index=self.pg0.sw_if_index,
84 is_passive=0,
85 is_long_timeout=0)
86 self.logger.info("bond enslave interface pg1 to BondEthernet0")
87 bond0.enslave_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index,
88 is_passive=0,
89 is_long_timeout=0)
90
91 # verify both slaves in BondEthernet0
92 if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index)
93 self.assertTrue(self.pg0.is_interface_config_in_dump(if_dump))
94 self.assertTrue(self.pg1.is_interface_config_in_dump(if_dump))
95
96 # generate a packet from pg2 -> BondEthernet0 -> pg1
97 # BondEthernet0 TX hashes this packet to pg1
98 p2 = (Ether(src=bond0_mac, dst=self.pg2.local_mac) /
99 IP(src=self.pg2.local_ip4, dst="10.10.10.12") /
100 UDP(sport=1235, dport=1235) /
101 Raw('\xa5' * 100))
102 self.pg2.add_stream(p2)
103
104 # generate a packet from pg3 -> BondEthernet0 -> pg0
105 # BondEthernet0 TX hashes this packet to pg0
106 # notice the ip address and ports are different than p2 packet
107 p3 = (Ether(src=bond0_mac, dst=self.pg3.local_mac) /
108 IP(src=self.pg3.local_ip4, dst="10.10.10.11") /
109 UDP(sport=1234, dport=1234) /
110 Raw('\xa5' * 100))
111 self.pg3.add_stream(p3)
112
113 self.pg_enable_capture(self.pg_interfaces)
114
115 # set up the static arp entries pointing to the BondEthernet0 interface
116 # so that it does not try to resolve the ip address
117 self.logger.info(self.vapi.cli(
118 "set ip arp static BondEthernet0 10.10.10.12 abcd.abcd.0002"))
119 self.logger.info(self.vapi.cli(
120 "set ip arp static BondEthernet0 10.10.10.11 abcd.abcd.0004"))
121
122 # clear the interface counters
123 self.logger.info(self.vapi.cli("clear interfaces"))
124
125 self.pg_start()
126
127 self.logger.info("check the interface counters")
128
129 # verify counters
130
131 # BondEthernet0 tx bytes = 284
132 intfs = self.vapi.cli("show interface BondEthernet0").split("\n")
133 found = 0
134 for intf in intfs:
135 if "tx bytes" in intf and "284" in intf:
136 found = 1
137 self.assertEqual(found, 1)
138
Steven0d883012018-05-11 11:06:23 -0700139 # BondEthernet0 tx bytes = 284
140 intfs = self.vapi.cli("show interface BondEthernet0").split("\n")
Steven9cd2d7a2017-12-20 12:43:01 -0800141 found = 0
142 for intf in intfs:
Steven0d883012018-05-11 11:06:23 -0700143 if "tx bytes" in intf and "284" in intf:
Steven9cd2d7a2017-12-20 12:43:01 -0800144 found = 1
145 self.assertEqual(found, 1)
146
147 # pg2 rx bytes = 142
148 intfs = self.vapi.cli("show interface pg2").split("\n")
149 found = 0
150 for intf in intfs:
151 if "rx bytes" in intf and "142" in intf:
152 found = 1
153 self.assertEqual(found, 1)
154
155 # pg3 rx bytes = 142
156 intfs = self.vapi.cli("show interface pg3").split("\n")
157 found = 0
158 for intf in intfs:
159 if "rx bytes" in intf and "142" in intf:
160 found = 1
161 self.assertEqual(found, 1)
162
163 bond0.remove_vpp_config()
164
165 def test_bond_enslave(self):
166 """ Bond enslave/detach slave test """
167
168 # create interface (BondEthernet0)
169 self.logger.info("create bond")
170 bond0 = VppBondInterface(self, mode=3)
171 bond0.add_vpp_config()
172 bond0.admin_up()
173
174 # verify pg0 and pg1 not in BondEthernet0
175 if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index)
176 self.assertFalse(self.pg0.is_interface_config_in_dump(if_dump))
177 self.assertFalse(self.pg1.is_interface_config_in_dump(if_dump))
178
179 # enslave pg0 and pg1 to BondEthernet0
180 self.logger.info("bond enslave interface pg0 to BondEthernet0")
181 bond0.enslave_vpp_bond_interface(sw_if_index=self.pg0.sw_if_index,
182 is_passive=0,
183 is_long_timeout=0)
184
185 self.logger.info("bond enslave interface pg1 to BondEthernet0")
186 bond0.enslave_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index,
187 is_passive=0,
188 is_long_timeout=0)
189
190 # verify both slaves in BondEthernet0
191 if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index)
192 self.assertTrue(self.pg0.is_interface_config_in_dump(if_dump))
193 self.assertTrue(self.pg1.is_interface_config_in_dump(if_dump))
194
195 # detach interface pg0
196 self.logger.info("detach interface pg0")
197 bond0.detach_vpp_bond_interface(sw_if_index=self.pg0.sw_if_index)
198
199 # verify pg0 is not in BondEthernet0, but pg1 is
200 if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index)
201 self.assertFalse(self.pg0.is_interface_config_in_dump(if_dump))
202 self.assertTrue(self.pg1.is_interface_config_in_dump(if_dump))
203
204 # detach interface pg1
205 self.logger.info("detach interface pg1")
206 bond0.detach_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index)
207
208 # verify pg0 and pg1 not in BondEthernet0
209 if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index)
210 self.assertFalse(self.pg0.is_interface_config_in_dump(if_dump))
211 self.assertFalse(self.pg1.is_interface_config_in_dump(if_dump))
212
213 bond0.remove_vpp_config()
214
215 def test_bond(self):
216 """ Bond add/delete interface test """
217 self.logger.info("Bond add interfaces")
218
219 # create interface 1 (BondEthernet0)
220 bond0 = VppBondInterface(self, mode=5)
221 bond0.add_vpp_config()
222 bond0.admin_up()
223
224 # create interface 2 (BondEthernet1)
225 bond1 = VppBondInterface(self, mode=3)
226 bond1.add_vpp_config()
227 bond1.admin_up()
228
229 # verify both interfaces in the show
230 ifs = self.vapi.cli("show interface")
231 self.assertNotEqual(ifs.find('BondEthernet0'), -1)
232 self.assertNotEqual(ifs.find('BondEthernet1'), -1)
233
234 # verify they are in the dump also
235 if_dump = self.vapi.sw_interface_bond_dump()
236 self.assertTrue(bond0.is_interface_config_in_dump(if_dump))
237 self.assertTrue(bond1.is_interface_config_in_dump(if_dump))
238
239 # delete BondEthernet1
240 self.logger.info("Deleting BondEthernet1")
241 bond1.remove_vpp_config()
242
243 self.logger.info("Verifying BondEthernet1 is deleted")
244
245 ifs = self.vapi.cli("show interface")
246 # verify BondEthernet0 still in the show
247 self.assertNotEqual(ifs.find('BondEthernet0'), -1)
248
249 # verify BondEthernet1 not in the show
250 self.assertEqual(ifs.find('BondEthernet1'), -1)
251
252 # verify BondEthernet1 is not in the dump
253 if_dump = self.vapi.sw_interface_bond_dump()
254 self.assertFalse(bond1.is_interface_config_in_dump(if_dump))
255
256 # verify BondEthernet0 is still in the dump
257 self.assertTrue(bond0.is_interface_config_in_dump(if_dump))
258
259 # delete BondEthernet0
260 self.logger.info("Deleting BondEthernet0")
261 bond0.remove_vpp_config()
262
263 self.logger.info("Verifying BondEthernet0 is deleted")
264
265 # verify BondEthernet0 not in the show
266 ifs = self.vapi.cli("show interface")
267 self.assertEqual(ifs.find('BondEthernet0'), -1)
268
269 # verify BondEthernet0 is not in the dump
270 if_dump = self.vapi.sw_interface_bond_dump()
271 self.assertFalse(bond0.is_interface_config_in_dump(if_dump))
272
273if __name__ == '__main__':
274 unittest.main(testRunner=VppTestRunner)