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
12 from vpp_ip import VppIpPrefix
15 class TestBondInterface(VppTestCase):
22 super(TestBondInterface, cls).setUpClass()
24 cls.pkts_per_burst = 257 # Number of packets per burst
25 # create 3 pg interfaces
26 cls.create_pg_interfaces(range(4))
29 cls.pg_if_packet_sizes = [64, 512, 1518] # , 9018]
31 # setup all interfaces
32 for i in cls.pg_interfaces:
36 def tearDownClass(cls):
37 super(TestBondInterface, cls).tearDownClass()
40 super(TestBondInterface, self).setUp()
43 super(TestBondInterface, self).tearDown()
45 def show_commands_at_teardown(self):
46 self.logger.info(self.vapi.ppcli("show interface"))
48 def test_bond_traffic(self):
49 """ Bond traffic test """
55 # pg2 ------+ +------pg0 (slave)
57 # BondEthernet0 (10.10.10.1)
59 # pg3 ------+ +------pg1 (slave)
62 # create interface (BondEthernet0)
63 # self.logger.info("create bond")
64 bond0_mac = "02:fe:38:30:59:3c"
65 mac = MACAddress(bond0_mac).packed
66 bond0 = VppBondInterface(self,
72 bond0.add_vpp_config()
74 self.vapi.sw_interface_add_del_address(
75 sw_if_index=bond0.sw_if_index,
76 prefix=VppIpPrefix("10.10.10.1", 24).encode())
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)
90 self.logger.info("bond enslave interface pg1 to BondEthernet0")
91 bond0.enslave_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index)
93 # verify both slaves in BondEthernet0
94 if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index)
95 self.assertTrue(self.pg0.is_interface_config_in_dump(if_dump))
96 self.assertTrue(self.pg1.is_interface_config_in_dump(if_dump))
98 # generate a packet from pg2 -> BondEthernet0 -> pg1
99 # BondEthernet0 TX hashes this packet to pg1
100 p2 = (Ether(src=bond0_mac, dst=self.pg2.local_mac) /
101 IP(src=self.pg2.local_ip4, dst="10.10.10.12") /
102 UDP(sport=1235, dport=1235) /
104 self.pg2.add_stream(p2)
106 # generate a packet from pg3 -> BondEthernet0 -> pg0
107 # BondEthernet0 TX hashes this packet to pg0
108 # notice the ip address and ports are different than p2 packet
109 p3 = (Ether(src=bond0_mac, dst=self.pg3.local_mac) /
110 IP(src=self.pg3.local_ip4, dst="10.10.10.11") /
111 UDP(sport=1234, dport=1234) /
113 self.pg3.add_stream(p3)
115 self.pg_enable_capture(self.pg_interfaces)
117 # set up the static arp entries pointing to the BondEthernet0 interface
118 # so that it does not try to resolve the ip address
119 self.logger.info(self.vapi.cli(
120 "set ip arp static BondEthernet0 10.10.10.12 abcd.abcd.0002"))
121 self.logger.info(self.vapi.cli(
122 "set ip arp static BondEthernet0 10.10.10.11 abcd.abcd.0004"))
124 # clear the interface counters
125 self.logger.info(self.vapi.cli("clear interfaces"))
129 self.logger.info("check the interface counters")
133 # BondEthernet0 tx bytes = 284
134 intfs = self.vapi.cli("show interface BondEthernet0").split("\n")
137 if "tx bytes" in intf and "284" in intf:
139 self.assertEqual(found, 1)
141 # BondEthernet0 tx bytes = 284
142 intfs = self.vapi.cli("show interface BondEthernet0").split("\n")
145 if "tx bytes" in intf and "284" in intf:
147 self.assertEqual(found, 1)
150 intfs = self.vapi.cli("show interface pg2").split("\n")
153 if "rx bytes" in intf and "142" in intf:
155 self.assertEqual(found, 1)
158 intfs = self.vapi.cli("show interface pg3").split("\n")
161 if "rx bytes" in intf and "142" in intf:
163 self.assertEqual(found, 1)
165 bond0.remove_vpp_config()
167 def test_bond_enslave(self):
168 """ Bond enslave/detach slave test """
170 # create interface (BondEthernet0)
171 self.logger.info("create bond")
172 bond0 = VppBondInterface(self, mode=3)
173 bond0.add_vpp_config()
176 # verify pg0 and pg1 not in BondEthernet0
177 if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index)
178 self.assertFalse(self.pg0.is_interface_config_in_dump(if_dump))
179 self.assertFalse(self.pg1.is_interface_config_in_dump(if_dump))
181 # enslave pg0 and pg1 to BondEthernet0
182 self.logger.info("bond enslave interface pg0 to BondEthernet0")
183 bond0.enslave_vpp_bond_interface(sw_if_index=self.pg0.sw_if_index,
187 self.logger.info("bond enslave interface pg1 to BondEthernet0")
188 bond0.enslave_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index,
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))
197 # detach interface pg0
198 self.logger.info("detach interface pg0")
199 bond0.detach_vpp_bond_interface(sw_if_index=self.pg0.sw_if_index)
201 # 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))
206 # detach interface pg1
207 self.logger.info("detach interface pg1")
208 bond0.detach_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index)
210 # 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))
215 bond0.remove_vpp_config()
218 """ Bond add/delete interface test """
219 self.logger.info("Bond add interfaces")
221 # create interface 1 (BondEthernet0)
222 bond0 = VppBondInterface(self, mode=5)
223 bond0.add_vpp_config()
226 # create interface 2 (BondEthernet1)
227 bond1 = VppBondInterface(self, mode=3)
228 bond1.add_vpp_config()
231 # verify both interfaces in the show
232 ifs = self.vapi.cli("show interface")
233 self.assertIn('BondEthernet0', ifs)
234 self.assertIn('BondEthernet1', ifs)
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))
241 # delete BondEthernet1
242 self.logger.info("Deleting BondEthernet1")
243 bond1.remove_vpp_config()
245 self.logger.info("Verifying BondEthernet1 is deleted")
247 ifs = self.vapi.cli("show interface")
248 # verify BondEthernet0 still in the show
249 self.assertIn('BondEthernet0', ifs)
251 # verify BondEthernet1 not in the show
252 self.assertNotIn('BondEthernet1', ifs)
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))
258 # verify BondEthernet0 is still in the dump
259 self.assertTrue(bond0.is_interface_config_in_dump(if_dump))
261 # delete BondEthernet0
262 self.logger.info("Deleting BondEthernet0")
263 bond0.remove_vpp_config()
265 self.logger.info("Verifying BondEthernet0 is deleted")
267 # verify BondEthernet0 not in the show
268 ifs = self.vapi.cli("show interface")
269 self.assertNotIn('BondEthernet0', ifs)
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))
276 if __name__ == '__main__':
277 unittest.main(testRunner=VppTestRunner)