6 from framework import VppTestCase, VppTestRunner
7 from scapy.packet import Raw
8 from scapy.layers.l2 import Ether
9 from scapy.layers.inet import IP, UDP
10 from vpp_bond_interface import VppBondInterface
11 from vpp_papi import MACAddress
14 class TestBondInterface(VppTestCase):
21 super(TestBondInterface, cls).setUpClass()
23 cls.pkts_per_burst = 257 # Number of packets per burst
24 # create 3 pg interfaces
25 cls.create_pg_interfaces(range(4))
28 cls.pg_if_packet_sizes = [64, 512, 1518] # , 9018]
30 # setup all interfaces
31 for i in cls.pg_interfaces:
35 def tearDownClass(cls):
36 super(TestBondInterface, cls).tearDownClass()
39 super(TestBondInterface, self).setUp()
42 super(TestBondInterface, self).tearDown()
44 def show_commands_at_teardown(self):
45 self.logger.info(self.vapi.ppcli("show interface"))
47 def test_bond_traffic(self):
48 """ Bond traffic test """
54 # pg2 ------+ +------pg0 (slave)
56 # BondEthernet0 (10.10.10.1)
58 # pg3 ------+ +------pg1 (slave)
61 # create interface (BondEthernet0)
62 # self.logger.info("create bond")
63 bond0_mac = "02:fe:38:30:59:3c"
64 mac = MACAddress(bond0_mac).packed
65 bond0 = VppBondInterface(self,
71 bond0.add_vpp_config()
73 bond0_addr = socket.inet_pton(socket.AF_INET, "10.10.10.1")
74 self.vapi.sw_interface_add_del_address(sw_if_index=bond0.sw_if_index,
79 self.pg2.resolve_arp()
81 self.pg3.resolve_arp()
83 self.logger.info(self.vapi.cli("show interface"))
84 self.logger.info(self.vapi.cli("show interface address"))
85 self.logger.info(self.vapi.cli("show ip arp"))
87 # enslave pg0 and pg1 to BondEthernet0
88 self.logger.info("bond enslave interface pg0 to BondEthernet0")
89 bond0.enslave_vpp_bond_interface(sw_if_index=self.pg0.sw_if_index,
92 self.logger.info("bond enslave interface pg1 to BondEthernet0")
93 bond0.enslave_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index,
97 # verify both slaves in BondEthernet0
98 if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index)
99 self.assertTrue(self.pg0.is_interface_config_in_dump(if_dump))
100 self.assertTrue(self.pg1.is_interface_config_in_dump(if_dump))
102 # generate a packet from pg2 -> BondEthernet0 -> pg1
103 # BondEthernet0 TX hashes this packet to pg1
104 p2 = (Ether(src=bond0_mac, dst=self.pg2.local_mac) /
105 IP(src=self.pg2.local_ip4, dst="10.10.10.12") /
106 UDP(sport=1235, dport=1235) /
108 self.pg2.add_stream(p2)
110 # generate a packet from pg3 -> BondEthernet0 -> pg0
111 # BondEthernet0 TX hashes this packet to pg0
112 # notice the ip address and ports are different than p2 packet
113 p3 = (Ether(src=bond0_mac, dst=self.pg3.local_mac) /
114 IP(src=self.pg3.local_ip4, dst="10.10.10.11") /
115 UDP(sport=1234, dport=1234) /
117 self.pg3.add_stream(p3)
119 self.pg_enable_capture(self.pg_interfaces)
121 # set up the static arp entries pointing to the BondEthernet0 interface
122 # so that it does not try to resolve the ip address
123 self.logger.info(self.vapi.cli(
124 "set ip arp static BondEthernet0 10.10.10.12 abcd.abcd.0002"))
125 self.logger.info(self.vapi.cli(
126 "set ip arp static BondEthernet0 10.10.10.11 abcd.abcd.0004"))
128 # clear the interface counters
129 self.logger.info(self.vapi.cli("clear interfaces"))
133 self.logger.info("check the interface counters")
137 # BondEthernet0 tx bytes = 284
138 intfs = self.vapi.cli("show interface BondEthernet0").split("\n")
141 if "tx bytes" in intf and "284" in intf:
143 self.assertEqual(found, 1)
145 # BondEthernet0 tx bytes = 284
146 intfs = self.vapi.cli("show interface BondEthernet0").split("\n")
149 if "tx bytes" in intf and "284" in intf:
151 self.assertEqual(found, 1)
154 intfs = self.vapi.cli("show interface pg2").split("\n")
157 if "rx bytes" in intf and "142" in intf:
159 self.assertEqual(found, 1)
162 intfs = self.vapi.cli("show interface pg3").split("\n")
165 if "rx bytes" in intf and "142" in intf:
167 self.assertEqual(found, 1)
169 bond0.remove_vpp_config()
171 def test_bond_enslave(self):
172 """ Bond enslave/detach slave test """
174 # create interface (BondEthernet0) and set bond mode to LACP
175 self.logger.info("create bond")
176 bond0 = VppBondInterface(self, mode=5)
177 bond0.add_vpp_config()
180 # verify that interfaces can be enslaved and detached two times
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))
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,
193 self.logger.info("bond enslave interface pg1 to BondEthernet0")
194 bond0.enslave_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index,
197 # verify both slaves in BondEthernet0
198 if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index)
199 self.assertTrue(self.pg0.is_interface_config_in_dump(if_dump))
200 self.assertTrue(self.pg1.is_interface_config_in_dump(if_dump))
202 # detach interface pg0
203 self.logger.info("detach interface pg0")
204 bond0.detach_vpp_bond_interface(sw_if_index=self.pg0.sw_if_index)
206 # verify pg0 is not in BondEthernet0, but pg1 is
207 if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index)
208 self.assertFalse(self.pg0.is_interface_config_in_dump(if_dump))
209 self.assertTrue(self.pg1.is_interface_config_in_dump(if_dump))
211 # detach interface pg1
212 self.logger.info("detach interface pg1")
213 bond0.detach_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index)
215 # verify pg0 and pg1 not in BondEthernet0
216 if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index)
217 self.assertFalse(self.pg0.is_interface_config_in_dump(if_dump))
218 self.assertFalse(self.pg1.is_interface_config_in_dump(if_dump))
220 bond0.remove_vpp_config()
223 """ Bond add/delete interface test """
224 self.logger.info("Bond add interfaces")
226 # create interface 1 (BondEthernet0)
227 bond0 = VppBondInterface(self, mode=5)
228 bond0.add_vpp_config()
231 # create interface 2 (BondEthernet1)
232 bond1 = VppBondInterface(self, mode=3)
233 bond1.add_vpp_config()
236 # verify both interfaces in the show
237 ifs = self.vapi.cli("show interface")
238 self.assertIn('BondEthernet0', ifs)
239 self.assertIn('BondEthernet1', ifs)
241 # verify they are in the dump also
242 if_dump = self.vapi.sw_interface_bond_dump()
243 self.assertTrue(bond0.is_interface_config_in_dump(if_dump))
244 self.assertTrue(bond1.is_interface_config_in_dump(if_dump))
246 # delete BondEthernet1
247 self.logger.info("Deleting BondEthernet1")
248 bond1.remove_vpp_config()
250 self.logger.info("Verifying BondEthernet1 is deleted")
252 ifs = self.vapi.cli("show interface")
253 # verify BondEthernet0 still in the show
254 self.assertIn('BondEthernet0', ifs)
256 # verify BondEthernet1 not in the show
257 self.assertNotIn('BondEthernet1', ifs)
259 # verify BondEthernet1 is not in the dump
260 if_dump = self.vapi.sw_interface_bond_dump()
261 self.assertFalse(bond1.is_interface_config_in_dump(if_dump))
263 # verify BondEthernet0 is still in the dump
264 self.assertTrue(bond0.is_interface_config_in_dump(if_dump))
266 # delete BondEthernet0
267 self.logger.info("Deleting BondEthernet0")
268 bond0.remove_vpp_config()
270 self.logger.info("Verifying BondEthernet0 is deleted")
272 # verify BondEthernet0 not in the show
273 ifs = self.vapi.cli("show interface")
274 self.assertNotIn('BondEthernet0', ifs)
276 # verify BondEthernet0 is not in the dump
277 if_dump = self.vapi.sw_interface_bond_dump()
278 self.assertFalse(bond0.is_interface_config_in_dump(if_dump))
280 if __name__ == '__main__':
281 unittest.main(testRunner=VppTestRunner)