diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/test_bond.py | 282 | ||||
-rw-r--r-- | test/vpp_bond_interface.py | 48 | ||||
-rw-r--r-- | test/vpp_papi_provider.py | 75 |
3 files changed, 405 insertions, 0 deletions
diff --git a/test/test_bond.py b/test/test_bond.py new file mode 100644 index 00000000000..b54a1f1deb5 --- /dev/null +++ b/test/test_bond.py @@ -0,0 +1,282 @@ +#!/usr/bin/env python + +import socket +import unittest + +from framework import VppTestCase, VppTestRunner +from scapy.packet import Raw +from scapy.layers.l2 import Ether +from scapy.layers.inet import IP, UDP +from util import mactobinary +from vpp_bond_interface import VppBondInterface + + +class TestBondInterface(VppTestCase): + """Bond Test Case + + """ + + @classmethod + def setUpClass(cls): + super(TestBondInterface, cls).setUpClass() + # Test variables + cls.pkts_per_burst = 257 # Number of packets per burst + # create 3 pg interfaces + cls.create_pg_interfaces(range(4)) + + # packet sizes + cls.pg_if_packet_sizes = [64, 512, 1518] # , 9018] + + # setup all interfaces + for i in cls.pg_interfaces: + i.admin_up() + + def setUp(self): + super(TestBondInterface, self).setUp() + + def tearDown(self): + super(TestBondInterface, self).tearDown() + if not self.vpp_dead: + self.logger.info(self.vapi.ppcli("show interface")) + + def test_bond_traffic(self): + """ Bond traffic test """ + + # topology + # + # RX-> TX-> + # + # pg2 ------+ +------pg0 (slave) + # | | + # BondEthernet0 (10.10.10.1) + # | | + # pg3 ------+ +------pg1 (slave) + # + + # create interface (BondEthernet0) + # self.logger.info("create bond") + bond0_mac = "02:fe:38:30:59:3c" + mac = mactobinary(bond0_mac) + bond0 = VppBondInterface(self, + mode=3, + lb=1, + use_custom_mac=1, + mac_address=mac) + bond0.add_vpp_config() + bond0.admin_up() + bond0_addr = socket.inet_pton(socket.AF_INET, "10.10.10.1") + self.vapi.sw_interface_add_del_address(bond0.sw_if_index, + bond0_addr, + 24) + + self.pg2.config_ip4() + self.pg2.resolve_arp() + self.pg3.config_ip4() + self.pg3.resolve_arp() + + self.logger.info(self.vapi.cli("show interface")) + self.logger.info(self.vapi.cli("show interface address")) + self.logger.info(self.vapi.cli("show ip arp")) + + # enslave pg0 and pg1 to BondEthernet0 + self.logger.info("bond enslave interface pg0 to BondEthernet0") + bond0.enslave_vpp_bond_interface(sw_if_index=self.pg0.sw_if_index, + is_passive=0, + is_long_timeout=0) + self.logger.info("bond enslave interface pg1 to BondEthernet0") + bond0.enslave_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index, + is_passive=0, + is_long_timeout=0) + + # verify both slaves in BondEthernet0 + if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index) + self.assertTrue(self.pg0.is_interface_config_in_dump(if_dump)) + self.assertTrue(self.pg1.is_interface_config_in_dump(if_dump)) + + # generate a packet from pg2 -> BondEthernet0 -> pg1 + # BondEthernet0 TX hashes this packet to pg1 + p2 = (Ether(src=bond0_mac, dst=self.pg2.local_mac) / + IP(src=self.pg2.local_ip4, dst="10.10.10.12") / + UDP(sport=1235, dport=1235) / + Raw('\xa5' * 100)) + self.pg2.add_stream(p2) + + # generate a packet from pg3 -> BondEthernet0 -> pg0 + # BondEthernet0 TX hashes this packet to pg0 + # notice the ip address and ports are different than p2 packet + p3 = (Ether(src=bond0_mac, dst=self.pg3.local_mac) / + IP(src=self.pg3.local_ip4, dst="10.10.10.11") / + UDP(sport=1234, dport=1234) / + Raw('\xa5' * 100)) + self.pg3.add_stream(p3) + + self.pg_enable_capture(self.pg_interfaces) + + # set up the static arp entries pointing to the BondEthernet0 interface + # so that it does not try to resolve the ip address + self.logger.info(self.vapi.cli( + "set ip arp static BondEthernet0 10.10.10.12 abcd.abcd.0002")) + self.logger.info(self.vapi.cli( + "set ip arp static BondEthernet0 10.10.10.11 abcd.abcd.0004")) + + # clear the interface counters + self.logger.info(self.vapi.cli("clear interfaces")) + + self.pg_start() + + self.logger.info("check the interface counters") + + # verify counters + + # BondEthernet0 tx bytes = 284 + intfs = self.vapi.cli("show interface BondEthernet0").split("\n") + found = 0 + for intf in intfs: + if "tx bytes" in intf and "284" in intf: + found = 1 + self.assertEqual(found, 1) + + # pg0 tx bytes = 142 + intfs = self.vapi.cli("show interface pg0").split("\n") + found = 0 + for intf in intfs: + if "tx bytes" in intf and "142" in intf: + found = 1 + self.assertEqual(found, 1) + + # pg0 tx bytes = 142 + intfs = self.vapi.cli("show interface pg1").split("\n") + found = 0 + for intf in intfs: + if "tx bytes" in intf and "142" in intf: + found = 1 + self.assertEqual(found, 1) + + # pg2 rx bytes = 142 + intfs = self.vapi.cli("show interface pg2").split("\n") + found = 0 + for intf in intfs: + if "rx bytes" in intf and "142" in intf: + found = 1 + self.assertEqual(found, 1) + + # pg3 rx bytes = 142 + intfs = self.vapi.cli("show interface pg3").split("\n") + found = 0 + for intf in intfs: + if "rx bytes" in intf and "142" in intf: + found = 1 + self.assertEqual(found, 1) + + bond0.remove_vpp_config() + + def test_bond_enslave(self): + """ Bond enslave/detach slave test """ + + # create interface (BondEthernet0) + self.logger.info("create bond") + bond0 = VppBondInterface(self, mode=3) + bond0.add_vpp_config() + bond0.admin_up() + + # verify pg0 and pg1 not in BondEthernet0 + if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index) + self.assertFalse(self.pg0.is_interface_config_in_dump(if_dump)) + self.assertFalse(self.pg1.is_interface_config_in_dump(if_dump)) + + # enslave pg0 and pg1 to BondEthernet0 + self.logger.info("bond enslave interface pg0 to BondEthernet0") + bond0.enslave_vpp_bond_interface(sw_if_index=self.pg0.sw_if_index, + is_passive=0, + is_long_timeout=0) + + self.logger.info("bond enslave interface pg1 to BondEthernet0") + bond0.enslave_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index, + is_passive=0, + is_long_timeout=0) + + # verify both slaves in BondEthernet0 + if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index) + self.assertTrue(self.pg0.is_interface_config_in_dump(if_dump)) + self.assertTrue(self.pg1.is_interface_config_in_dump(if_dump)) + + # detach interface pg0 + self.logger.info("detach interface pg0") + bond0.detach_vpp_bond_interface(sw_if_index=self.pg0.sw_if_index) + + # verify pg0 is not in BondEthernet0, but pg1 is + if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index) + self.assertFalse(self.pg0.is_interface_config_in_dump(if_dump)) + self.assertTrue(self.pg1.is_interface_config_in_dump(if_dump)) + + # detach interface pg1 + self.logger.info("detach interface pg1") + bond0.detach_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index) + + # verify pg0 and pg1 not in BondEthernet0 + if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index) + self.assertFalse(self.pg0.is_interface_config_in_dump(if_dump)) + self.assertFalse(self.pg1.is_interface_config_in_dump(if_dump)) + + bond0.remove_vpp_config() + + def test_bond(self): + """ Bond add/delete interface test """ + self.logger.info("Bond add interfaces") + + # create interface 1 (BondEthernet0) + bond0 = VppBondInterface(self, mode=5) + bond0.add_vpp_config() + bond0.admin_up() + + # create interface 2 (BondEthernet1) + bond1 = VppBondInterface(self, mode=3) + bond1.add_vpp_config() + bond1.admin_up() + + # verify both interfaces in the show + ifs = self.vapi.cli("show interface") + self.assertNotEqual(ifs.find('BondEthernet0'), -1) + self.assertNotEqual(ifs.find('BondEthernet1'), -1) + + # verify they are in the dump also + if_dump = self.vapi.sw_interface_bond_dump() + self.assertTrue(bond0.is_interface_config_in_dump(if_dump)) + self.assertTrue(bond1.is_interface_config_in_dump(if_dump)) + + # delete BondEthernet1 + self.logger.info("Deleting BondEthernet1") + bond1.remove_vpp_config() + + self.logger.info("Verifying BondEthernet1 is deleted") + + ifs = self.vapi.cli("show interface") + # verify BondEthernet0 still in the show + self.assertNotEqual(ifs.find('BondEthernet0'), -1) + + # verify BondEthernet1 not in the show + self.assertEqual(ifs.find('BondEthernet1'), -1) + + # verify BondEthernet1 is not in the dump + if_dump = self.vapi.sw_interface_bond_dump() + self.assertFalse(bond1.is_interface_config_in_dump(if_dump)) + + # verify BondEthernet0 is still in the dump + self.assertTrue(bond0.is_interface_config_in_dump(if_dump)) + + # delete BondEthernet0 + self.logger.info("Deleting BondEthernet0") + bond0.remove_vpp_config() + + self.logger.info("Verifying BondEthernet0 is deleted") + + # verify BondEthernet0 not in the show + ifs = self.vapi.cli("show interface") + self.assertEqual(ifs.find('BondEthernet0'), -1) + + # verify BondEthernet0 is not in the dump + if_dump = self.vapi.sw_interface_bond_dump() + self.assertFalse(bond0.is_interface_config_in_dump(if_dump)) + +if __name__ == '__main__': + unittest.main(testRunner=VppTestRunner) diff --git a/test/vpp_bond_interface.py b/test/vpp_bond_interface.py new file mode 100644 index 00000000000..1c33e1cecd6 --- /dev/null +++ b/test/vpp_bond_interface.py @@ -0,0 +1,48 @@ +from vpp_object import VppObject +from vpp_interface import VppInterface + + +class VppBondInterface(VppInterface): + """VPP bond interface.""" + + def __init__(self, test, mode, lb=0, + use_custom_mac=0, mac_address=''): + + """ Create VPP Bond interface """ + self._test = test + self.mode = mode + self.lb = lb + self.use_custom_mac = use_custom_mac + self.mac_address = mac_address + self._sw_if_index = 0 + super(VppBondInterface, self).__init__(test) + + def add_vpp_config(self): + r = self.test.vapi.bond_create(self.mode, + self.lb, + self.use_custom_mac, + self.mac_address) + self._sw_if_index = r.sw_if_index + + def remove_vpp_config(self): + self.test.vapi.bond_delete(self.sw_if_index) + + def enslave_vpp_bond_interface(self, + sw_if_index, + is_passive, + is_long_timeout): + self.test.vapi.bond_enslave(sw_if_index, + self.sw_if_index, + is_passive, + is_long_timeout) + + def detach_vpp_bond_interface(self, + sw_if_index): + self.test.vapi.bond_detach_slave(sw_if_index) + + def is_interface_config_in_dump(self, dump): + for i in dump: + if i.sw_if_index == self.sw_if_index: + return True + else: + return False diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py index 65cf766ffff..5517174590d 100644 --- a/test/vpp_papi_provider.py +++ b/test/vpp_papi_provider.py @@ -3341,3 +3341,78 @@ class VppPapiProvider(object): def want_igmp_events(self, enable=1): return self.api(self.papi.want_igmp_events, {'enable': enable, 'pid': os.getpid()}) + + def bond_create( + self, + mode, + lb, + use_custom_mac, + mac_address=''): + """ + :param mode: mode + :param lb: load balance + :param use_custom_mac: use custom mac + :param mac_address: mac address + """ + return self.api( + self.papi.bond_create, + {'mode': mode, + 'lb': lb, + 'use_custom_mac': use_custom_mac, + 'mac_address': mac_address + }) + + def bond_delete( + self, + sw_if_index): + """ + :param sw_if_index: interface the operation is applied to + """ + return self.api(self.papi.bond_delete, + {'sw_if_index': sw_if_index}) + + def bond_enslave( + self, + sw_if_index, + bond_sw_if_index, + is_passive, + is_long_timeout): + """ + :param sw_if_index: slave sw_if_index + :param bond_sw_if_index: bond sw_if_index + :param is_passive: is passive lacp speaker + :param is_long_time: 90 seconds timeout instead of 3 seconds timeout + """ + return self.api( + self.papi.bond_enslave, + {'sw_if_index': sw_if_index, + 'bond_sw_if_index': bond_sw_if_index, + 'is_passive': is_passive, + 'is_long_timeout': is_long_timeout + }) + + def bond_detach_slave( + self, + sw_if_index): + """ + :param sw_if_index: slave interface the operation is applied to + """ + return self.api(self.papi.bond_detach_slave, + {'sw_if_index': sw_if_index}) + + def sw_interface_slave_dump( + self, + sw_if_index): + """ + :param sw_if_index: bond sw_if_index + """ + return self.api(self.papi.sw_interface_slave_dump, + {'sw_if_index': sw_if_index}) + + def sw_interface_bond_dump( + self): + """ + + """ + return self.api(self.papi.sw_interface_bond_dump, + {}) |