blob: b54a1f1deb58d3c67a53fc7f9b21f290112753cb [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
10from util import mactobinary
11from vpp_bond_interface import VppBondInterface
12
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"
59 mac = mactobinary(bond0_mac)
60 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
139 # pg0 tx bytes = 142
140 intfs = self.vapi.cli("show interface pg0").split("\n")
141 found = 0
142 for intf in intfs:
143 if "tx bytes" in intf and "142" in intf:
144 found = 1
145 self.assertEqual(found, 1)
146
147 # pg0 tx bytes = 142
148 intfs = self.vapi.cli("show interface pg1").split("\n")
149 found = 0
150 for intf in intfs:
151 if "tx bytes" in intf and "142" in intf:
152 found = 1
153 self.assertEqual(found, 1)
154
155 # pg2 rx bytes = 142
156 intfs = self.vapi.cli("show interface pg2").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 # pg3 rx bytes = 142
164 intfs = self.vapi.cli("show interface pg3").split("\n")
165 found = 0
166 for intf in intfs:
167 if "rx bytes" in intf and "142" in intf:
168 found = 1
169 self.assertEqual(found, 1)
170
171 bond0.remove_vpp_config()
172
173 def test_bond_enslave(self):
174 """ Bond enslave/detach slave test """
175
176 # create interface (BondEthernet0)
177 self.logger.info("create bond")
178 bond0 = VppBondInterface(self, mode=3)
179 bond0.add_vpp_config()
180 bond0.admin_up()
181
182 # verify pg0 and pg1 not in BondEthernet0
183 if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index)
184 self.assertFalse(self.pg0.is_interface_config_in_dump(if_dump))
185 self.assertFalse(self.pg1.is_interface_config_in_dump(if_dump))
186
187 # enslave pg0 and pg1 to BondEthernet0
188 self.logger.info("bond enslave interface pg0 to BondEthernet0")
189 bond0.enslave_vpp_bond_interface(sw_if_index=self.pg0.sw_if_index,
190 is_passive=0,
191 is_long_timeout=0)
192
193 self.logger.info("bond enslave interface pg1 to BondEthernet0")
194 bond0.enslave_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index,
195 is_passive=0,
196 is_long_timeout=0)
197
198 # verify both slaves in BondEthernet0
199 if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index)
200 self.assertTrue(self.pg0.is_interface_config_in_dump(if_dump))
201 self.assertTrue(self.pg1.is_interface_config_in_dump(if_dump))
202
203 # detach interface pg0
204 self.logger.info("detach interface pg0")
205 bond0.detach_vpp_bond_interface(sw_if_index=self.pg0.sw_if_index)
206
207 # verify pg0 is not in BondEthernet0, but pg1 is
208 if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index)
209 self.assertFalse(self.pg0.is_interface_config_in_dump(if_dump))
210 self.assertTrue(self.pg1.is_interface_config_in_dump(if_dump))
211
212 # detach interface pg1
213 self.logger.info("detach interface pg1")
214 bond0.detach_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index)
215
216 # verify pg0 and pg1 not in BondEthernet0
217 if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index)
218 self.assertFalse(self.pg0.is_interface_config_in_dump(if_dump))
219 self.assertFalse(self.pg1.is_interface_config_in_dump(if_dump))
220
221 bond0.remove_vpp_config()
222
223 def test_bond(self):
224 """ Bond add/delete interface test """
225 self.logger.info("Bond add interfaces")
226
227 # create interface 1 (BondEthernet0)
228 bond0 = VppBondInterface(self, mode=5)
229 bond0.add_vpp_config()
230 bond0.admin_up()
231
232 # create interface 2 (BondEthernet1)
233 bond1 = VppBondInterface(self, mode=3)
234 bond1.add_vpp_config()
235 bond1.admin_up()
236
237 # verify both interfaces in the show
238 ifs = self.vapi.cli("show interface")
239 self.assertNotEqual(ifs.find('BondEthernet0'), -1)
240 self.assertNotEqual(ifs.find('BondEthernet1'), -1)
241
242 # verify they are in the dump also
243 if_dump = self.vapi.sw_interface_bond_dump()
244 self.assertTrue(bond0.is_interface_config_in_dump(if_dump))
245 self.assertTrue(bond1.is_interface_config_in_dump(if_dump))
246
247 # delete BondEthernet1
248 self.logger.info("Deleting BondEthernet1")
249 bond1.remove_vpp_config()
250
251 self.logger.info("Verifying BondEthernet1 is deleted")
252
253 ifs = self.vapi.cli("show interface")
254 # verify BondEthernet0 still in the show
255 self.assertNotEqual(ifs.find('BondEthernet0'), -1)
256
257 # verify BondEthernet1 not in the show
258 self.assertEqual(ifs.find('BondEthernet1'), -1)
259
260 # verify BondEthernet1 is not in the dump
261 if_dump = self.vapi.sw_interface_bond_dump()
262 self.assertFalse(bond1.is_interface_config_in_dump(if_dump))
263
264 # verify BondEthernet0 is still in the dump
265 self.assertTrue(bond0.is_interface_config_in_dump(if_dump))
266
267 # delete BondEthernet0
268 self.logger.info("Deleting BondEthernet0")
269 bond0.remove_vpp_config()
270
271 self.logger.info("Verifying BondEthernet0 is deleted")
272
273 # verify BondEthernet0 not in the show
274 ifs = self.vapi.cli("show interface")
275 self.assertEqual(ifs.find('BondEthernet0'), -1)
276
277 # verify BondEthernet0 is not in the dump
278 if_dump = self.vapi.sw_interface_bond_dump()
279 self.assertFalse(bond0.is_interface_config_in_dump(if_dump))
280
281if __name__ == '__main__':
282 unittest.main(testRunner=VppTestRunner)