diff options
-rw-r--r-- | conf/02_vswitch.conf | 4 | ||||
-rw-r--r-- | conf/04_vnf.conf | 50 | ||||
-rw-r--r-- | conf/integration/01_testcases.conf | 235 | ||||
-rw-r--r-- | conf/integration/02_vswitch.conf | 12 | ||||
-rw-r--r-- | core/component_factory.py | 3 | ||||
-rw-r--r-- | core/vswitch_controller_ptunp.py | 238 | ||||
-rwxr-xr-x | docs/userguide/integration.rst | 49 | ||||
-rw-r--r-- | vswitches/ovs.py | 32 |
8 files changed, 604 insertions, 19 deletions
diff --git a/conf/02_vswitch.conf b/conf/02_vswitch.conf index 3d72d348..228ff057 100644 --- a/conf/02_vswitch.conf +++ b/conf/02_vswitch.conf @@ -62,6 +62,10 @@ VHOST_DEV_FILE = 'ovs-vhost-net' # location of vhost-user sockets VHOST_USER_SOCKS = ['/tmp/dpdkvhostuser0', '/tmp/dpdkvhostuser1', '/tmp/dpdkvhostuser2', '/tmp/dpdkvhostuser3', + '/tmp/dpdkvhostuser4', '/tmp/dpdkvhostuser5', + '/tmp/dpdkvhostuser6', '/tmp/dpdkvhostuser7', + '/tmp/dpdkvhostuser8', '/tmp/dpdkvhostuser9', + '/tmp/dpdkvhostuser10', '/tmp/dpdkvhostuser11', '/tmp/myport0', '/tmp/helloworld123', '/tmp/abcstuff0'] # ############################ diff --git a/conf/04_vnf.conf b/conf/04_vnf.conf index ff110d93..ec242662 100644 --- a/conf/04_vnf.conf +++ b/conf/04_vnf.conf @@ -25,15 +25,17 @@ VNF = 'QemuDpdkVhostUser' # directory which is shared to QEMU guests. Useful for exchanging files # between host and guest, VNF specific share will be created # For 2 VNFs you may use ['/tmp/qemu0_share', '/tmp/qemu1_share'] -GUEST_SHARE_DIR = ['/tmp/qemu0_share', '/tmp/qemu1_share'] +GUEST_SHARE_DIR = ['/tmp/qemu0_share', '/tmp/qemu1_share', \ + '/tmp/qemu2_share', '/tmp/qemu3_share', \ + '/tmp/qemu4_share', '/tmp/qemu5_share'] # location of guest disk image # For 2 VNFs you may use ['guest1.img', 'guest2.img'] -GUEST_IMAGE = ['', ''] +GUEST_IMAGE = ['', '', '', '', '', ''] # guarding timer for VM start up # For 2 VNFs you may use [180, 180] -GUEST_TIMEOUT = [180, 180] +GUEST_TIMEOUT = [180, 180, 180, 180, 180, 180] # packet forwarding mode supported by testpmd; Please see DPDK documentation # for comprehensive list of modes supported by your version. @@ -50,7 +52,9 @@ GUEST_TESTPMD_FWD_MODE = 'csum' # This configuration option can be overridden by CLI SCALAR option # guest_loopback, e.g. --test-params "guest_loopback=l2fwd" # For 2 VNFs you may use ['testpmd', 'l2fwd'] -GUEST_LOOPBACK = ['testpmd', 'testpmd'] +GUEST_LOOPBACK = ['testpmd', 'testpmd', \ + 'testpmd', 'testpmd', \ + 'testpmd', 'testpmd'] # username for guest image GUEST_USERNAME = 'root' @@ -81,25 +85,33 @@ LOG_FILE_GUEST_CMDS = 'guest-cmds.log' QEMU_BIN = os.path.join(QEMU_DIR, 'x86_64-softmmu/qemu-system-x86_64') # For 2 VNFs you may use ['eth0', 'eth2'] -GUEST_NIC1_NAME = ['eth0', 'eth0'] -GUEST_NIC2_NAME = ['eth1', 'eth1'] +GUEST_NIC1_NAME = ['eth0', 'eth0', 'eth0', 'eth0', 'eth0', 'eth0'] +GUEST_NIC2_NAME = ['eth1', 'eth1', 'eth1', 'eth1', 'eth1', 'eth1'] # For 2 VNFs you may use ['00:00:00:00:00:01', '00:00:00:00:00:03'] -GUEST_NET1_MAC = ['00:00:00:00:00:01', '00:00:00:00:00:03'] -GUEST_NET2_MAC = ['00:00:00:00:00:02', '00:00:00:00:00:04'] +GUEST_NET1_MAC = ['00:00:00:00:00:01', '00:00:00:00:00:03', \ + '00:00:00:00:00:05', '00:00:00:00:00:07', \ + '00:00:00:00:00:09', '00:00:00:00:00:0b'] +GUEST_NET2_MAC = ['00:00:00:00:00:02', '00:00:00:00:00:04', \ + '00:00:00:00:00:06', '00:00:00:00:00:08', \ + '00:00:00:00:00:0a', '00:00:00:00:00:0c'] # For 2 VNFs you may use ['00:04.0', '00:04.0'] -GUEST_NET1_PCI_ADDRESS = ['00:04.0', '00:04.0'] -GUEST_NET2_PCI_ADDRESS = ['00:05.0', '00:05.0'] +GUEST_NET1_PCI_ADDRESS = ['00:04.0', '00:04.0', \ + '00:04.0', '00:04.0', \ + '00:04.0', '00:04.0'] +GUEST_NET2_PCI_ADDRESS = ['00:05.0', '00:05.0', \ + '00:05.0', '00:05.0', \ + '00:05.0', '00:05.0'] -GUEST_MEMORY = ['4096', '4096'] +GUEST_MEMORY = ['4096', '4096', '2048', '2048', '2048', '2048'] # test-pmd requires 2 VM cores -GUEST_SMP = ['2', '2'] +GUEST_SMP = ['2', '2', '2', '2', '2', '2'] # Host cores to use to affinitize the SMP cores of a QEMU instance # For 2 VNFs you may use [(4,5), (6, 7)] -GUEST_CORE_BINDING = [(6, 7), (9, 10)] +GUEST_CORE_BINDING = [(6, 7), (9, 10), (11, 12), (13, 14), (15, 16), (17, 18)] # Queues per NIC inside guest for multi-queue configuration, requires switch # multi-queue to be enabled. Set to 0 for disabled. @@ -137,9 +149,15 @@ VANILLA_TGEN_PORT1_MAC = 'AA:BB:CC:DD:EE:FF' VANILLA_TGEN_PORT2_IP = '1.1.2.10' VANILLA_TGEN_PORT2_MAC = 'AA:BB:CC:DD:EE:F0' -VANILLA_BRIDGE_IP = ['1.1.1.5/16', '1.1.1.6/16'] +VANILLA_BRIDGE_IP = ['1.1.1.5/16', '1.1.1.6/16', \ + '1.1.1.7/16', '1.1.1.8/16', \ + '1.1.1.9/16', '1.1.1.10/16'] -VANILLA_NIC1_IP_CIDR = ['192.168.1.2/24', '192.168.1.4/24'] -VANILLA_NIC2_IP_CIDR = ['192.168.1.3/24', '192.168.1.5/24'] +VANILLA_NIC1_IP_CIDR = ['192.168.1.2/24', '192.168.1.4/24', \ + '192.168.1.6/24', '192.168.1.8/24', \ + '192.168.1.10/24', '192.168.1.12/24'] +VANILLA_NIC2_IP_CIDR = ['192.168.1.3/24', '192.168.1.5/24', \ + '192.168.1.7/24', '192.168.1.9/24', \ + '192.168.1.11/24', '192.168.1.13/24'] VNF_AFFINITIZATION_ON = True diff --git a/conf/integration/01_testcases.conf b/conf/integration/01_testcases.conf index e050e358..a67702f8 100644 --- a/conf/integration/01_testcases.conf +++ b/conf/integration/01_testcases.conf @@ -72,7 +72,7 @@ STEP_VSWITCH_PVP_INIT = [ ['vswitch', 'add_switch', 'int_br0'], # STEP 0 ['vswitch', 'add_phy_port', 'int_br0'], # STEP 1 ['vswitch', 'add_phy_port', 'int_br0'], # STEP 2 - ['vswitch', 'add_vport', 'int_br0'], # STEP 3 + ['vswitch', 'add_vport', 'int_br0'], # STEP 3 vm1 ports ['vswitch', 'add_vport', 'int_br0'], # STEP 4 ] @@ -100,12 +100,12 @@ STEP_VSWITCH_PVP_FLOWS_FINIT = [ ] + STEP_VSWITCH_PVP_FINIT STEP_VSWITCH_PVVP_INIT = STEP_VSWITCH_PVP_INIT + [ - ['vswitch', 'add_vport', 'int_br0'], # STEP 5 + ['vswitch', 'add_vport', 'int_br0'], # STEP 5 vm2 ports ['vswitch', 'add_vport', 'int_br0'], # STEP 6 ] STEP_VSWITCH_PVVP_FINIT = [ - ['vswitch', 'del_port', 'int_br0', '#STEP[5][0]'], + ['vswitch', 'del_port', 'int_br0', '#STEP[5][0]'], # vm2 ports ['vswitch', 'del_port', 'int_br0', '#STEP[6][0]'], ] + STEP_VSWITCH_PVP_FINIT @@ -128,11 +128,166 @@ STEP_VSWITCH_PVVP_FLOWS_FINIT = [ ['vswitch', 'del_flow', 'int_br0', {'in_port': '#STEP[3][1]'}], ] + STEP_VSWITCH_PVVP_FINIT +STEP_VSWITCH_2PHY_2VM_INIT = STEP_VSWITCH_PVVP_INIT + +STEP_VSWITCH_2PHY_2VM_FINIT = STEP_VSWITCH_PVVP_FINIT + +STEP_VSWITCH_2_PARALLEL_VM_FLOWS_INIT = [ + # Setup Flows to reply ICMPv6 and similar packets, so to + # avoid flooding the internal port with their re-transmissions + ['vswitch', 'add_flow', 'int_br0', \ + {'priority': '1', 'dl_src': '00:00:00:00:00:01', \ + 'actions': ['output:#STEP[3][1]'], 'idle_timeout': '0'}], + ['vswitch', 'add_flow', 'int_br0', \ + {'priority': '1', 'dl_src': '00:00:00:00:00:02', \ + 'actions': ['output:#STEP[4][1]'], 'idle_timeout': '0'}], + ['vswitch', 'add_flow', 'int_br0', \ + {'priority': '1', 'dl_src': '00:00:00:00:00:03', \ + 'actions': ['output:#STEP[5][1]'], 'idle_timeout': '0'}], + ['vswitch', 'add_flow', 'int_br0', \ + {'priority': '1', 'dl_src': '00:00:00:00:00:04', \ + 'actions': ['output:#STEP[6][1]'], 'idle_timeout': '0'}], + # Forward UDP packets depending on dest port + ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[1][1]', \ + 'dl_type': '0x0800', 'nw_proto': '17', 'udp_dst': '0', \ + 'actions': ['output:#STEP[3][1]'], 'idle_timeout': '0'}], + ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[1][1]', \ + 'dl_type': '0x0800', 'nw_proto': '17', 'udp_dst': '1', \ + 'actions': ['output:#STEP[5][1]'], 'idle_timeout': '0'}], + # Send VM outputs to phy port #2 + ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[4][1]', \ + 'actions': ['output:#STEP[2][1]'], 'idle_timeout': '0'}], + ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[6][1]', \ + 'actions': ['output:#STEP[2][1]'], 'idle_timeout': '0'}], +] + +STEP_VSWITCH_2PHY_4VM_INIT = STEP_VSWITCH_2PHY_2VM_INIT + [ + ['vswitch', 'add_vport', 'int_br0'], # STEP 7 vm3 ports + ['vswitch', 'add_vport', 'int_br0'], # STEP 8 + ['vswitch', 'add_vport', 'int_br0'], # STEP 9 vm4 ports + ['vswitch', 'add_vport', 'int_br0'], # STEP 10 +] + +STEP_VSWITCH_2PHY_4VM_FINIT = [ + ['vswitch', 'del_port', 'int_br0', '#STEP[7][0]'], # vm3 ports + ['vswitch', 'del_port', 'int_br0', '#STEP[8][0]'], + ['vswitch', 'del_port', 'int_br0', '#STEP[9][0]'], # vm4 ports + ['vswitch', 'del_port', 'int_br0', '#STEP[10][0]'], +] + STEP_VSWITCH_2PHY_2VM_FINIT + +STEP_VSWITCH_FLOWS_FINIT = [ + ['vswitch', 'dump_flows', 'int_br0'], + ['vswitch', 'del_flow', 'int_br0'], +] + +STEP_VSWITCH_4_PARALLEL_VM_FLOWS_INIT = [ + # Setup Flows to reply ICMPv6 and similar packets, so to + # avoid flooding the internal port with their re-transmissions + ['vswitch', 'add_flow', 'int_br0', \ + {'priority': '1', 'dl_src': '00:00:00:00:00:01', \ + 'actions': ['output:#STEP[3][1]'], 'idle_timeout': '0'}], + ['vswitch', 'add_flow', 'int_br0', \ + {'priority': '1', 'dl_src': '00:00:00:00:00:02', \ + 'actions': ['output:#STEP[4][1]'], 'idle_timeout': '0'}], + ['vswitch', 'add_flow', 'int_br0', \ + {'priority': '1', 'dl_src': '00:00:00:00:00:03', \ + 'actions': ['output:#STEP[5][1]'], 'idle_timeout': '0'}], + ['vswitch', 'add_flow', 'int_br0', \ + {'priority': '1', 'dl_src': '00:00:00:00:00:04', \ + 'actions': ['output:#STEP[6][1]'], 'idle_timeout': '0'}], + ['vswitch', 'add_flow', 'int_br0', \ + {'priority': '1', 'dl_src': '00:00:00:00:00:05', \ + 'actions': ['output:#STEP[7][1]'], 'idle_timeout': '0'}], + ['vswitch', 'add_flow', 'int_br0', \ + {'priority': '1', 'dl_src': '00:00:00:00:00:06', \ + 'actions': ['output:#STEP[8][1]'], 'idle_timeout': '0'}], + ['vswitch', 'add_flow', 'int_br0', \ + {'priority': '1', 'dl_src': '00:00:00:00:00:07', \ + 'actions': ['output:#STEP[9][1]'], 'idle_timeout': '0'}], + ['vswitch', 'add_flow', 'int_br0', \ + {'priority': '1', 'dl_src': '00:00:00:00:00:08', \ + 'actions': ['output:#STEP[10][1]'], 'idle_timeout': '0'}], + # Forward UDP packets depending on dest port + ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[1][1]', \ + 'dl_type': '0x0800', 'nw_proto': '17', 'udp_dst': '0', \ + 'actions': ['output:#STEP[3][1]'], 'idle_timeout': '0'}], + ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[1][1]', \ + 'dl_type': '0x0800', 'nw_proto': '17', 'udp_dst': '1', \ + 'actions': ['output:#STEP[5][1]'], 'idle_timeout': '0'}], + ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[1][1]', \ + 'dl_type': '0x0800', 'nw_proto': '17', 'udp_dst': '2', \ + 'actions': ['output:#STEP[7][1]'], 'idle_timeout': '0'}], + ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[1][1]', \ + 'dl_type': '0x0800', 'nw_proto': '17', 'udp_dst': '3', \ + 'actions': ['output:#STEP[9][1]'], 'idle_timeout': '0'}], + # Send VM outputs to phy port #2 + ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[4][1]', \ + 'actions': ['output:#STEP[2][1]'], 'idle_timeout': '0'}], + ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[6][1]', \ + 'actions': ['output:#STEP[2][1]'], 'idle_timeout': '0'}], + ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[8][1]', \ + 'actions': ['output:#STEP[2][1]'], 'idle_timeout': '0'}], + ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[10][1]', \ + 'actions': ['output:#STEP[2][1]'], 'idle_timeout': '0'}], +] + +STEP_VSWITCH_2PHY_6VM_INIT = STEP_VSWITCH_2PHY_4VM_INIT + [ + ['vswitch', 'add_vport', 'int_br0'], # STEP 11 vm5 vhu8 + ['vswitch', 'add_vport', 'int_br0'], # STEP 12 vhu9 + ['vswitch', 'add_vport', 'int_br0'], # STEP 13 vm6 vhu10 + ['vswitch', 'add_vport', 'int_br0'], # STEP 14 vhu11 +] + +STEP_VSWITCH_6_PARALLEL_VM_FLOWS_INIT = STEP_VSWITCH_4_PARALLEL_VM_FLOWS_INIT + [ + ['vswitch', 'add_flow', 'int_br0', \ + {'priority': '1', 'dl_src': '00:00:00:00:00:09', \ + 'actions': ['output:#STEP[11][1]'], 'idle_timeout': '0'}], + ['vswitch', 'add_flow', 'int_br0', \ + {'priority': '1', 'dl_src': '00:00:00:00:00:0a', \ + 'actions': ['output:#STEP[12][1]'], 'idle_timeout': '0'}], + ['vswitch', 'add_flow', 'int_br0', \ + {'priority': '1', 'dl_src': '00:00:00:00:00:0b', \ + 'actions': ['output:#STEP[13][1]'], 'idle_timeout': '0'}], + ['vswitch', 'add_flow', 'int_br0', \ + {'priority': '1', 'dl_src': '00:00:00:00:00:0c', \ + 'actions': ['output:#STEP[14][1]'], 'idle_timeout': '0'}], + # Forward UDP packets depending on dest port + ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[1][1]', \ + 'dl_type': '0x0800', 'nw_proto': '17', 'udp_dst': '4', \ + 'actions': ['output:#STEP[11][1]'], 'idle_timeout': '0'}], + ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[1][1]', \ + 'dl_type': '0x0800', 'nw_proto': '17', 'udp_dst': '5', \ + 'actions': ['output:#STEP[13][1]'], 'idle_timeout': '0'}], + # Send VM outputs to phy port #2 + ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[12][1]', \ + 'actions': ['output:#STEP[2][1]'], 'idle_timeout': '0'}], + ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[14][1]', \ + 'actions': ['output:#STEP[2][1]'], 'idle_timeout': '0'}], +] + +STEP_VSWITCH_2PHY_6VM_FINIT = [ + ['vswitch', 'del_port', 'int_br0', '#STEP[11][0]'], # vm5 ports + ['vswitch', 'del_port', 'int_br0', '#STEP[12][0]'], + ['vswitch', 'del_port', 'int_br0', '#STEP[13][0]'], # vm6 ports + ['vswitch', 'del_port', 'int_br0', '#STEP[14][0]'], +] + STEP_VSWITCH_2PHY_4VM_FINIT + # # Definition of integration tests # INTEGRATION_TESTS = [ { + "Name": "overlay_p2p_mod_tput", + "Traffic Type": "rfc2544", + "Deployment": "ptunp", + "biDirectional": 'True', + "Tunnel Type": "vxlan", + "Description": ("Tunneling Throughput RFC2544 Test." + "The encap and decap are performed inside the " + "virtual switch itself in each direction to avoid " + "the need of ingress overlay traffic."), + }, + { "Name": "overlay_p2p_tput", "Traffic Type": "rfc2544", "Deployment": "op2p", @@ -420,6 +575,80 @@ INTEGRATION_TESTS = [ ] + STEP_VSWITCH_PVVP_FLOWS_FINIT }, + { + # Topology: 2 Parallel PVP connections + # To run a Linux bridge as a loopback in the Guest use: + # --test-params "guest_loopback=linux_bridge" --integration 2pvp_udp_dest_flows + "Name": "2pvp_udp_dest_flows", + "Description": "Continuous TC with 2 Parallel VMs, flows on UDP Dest Port", + "Deployment": "clean", + "Stream Type": "L4", + "MultiStream": 2, + "TestSteps": STEP_VSWITCH_2PHY_2VM_INIT + + STEP_VSWITCH_2_PARALLEL_VM_FLOWS_INIT + [ + # Start 2 VMs + ['vnf1', 'start'], + ['vnf2', 'start'], + ['trafficgen', 'send_traffic', {'traffic_type' : 'continuous', 'bidir' : 'False'}], + ['vnf1', 'stop'], + ['vnf2', 'stop'], + # Clean up + ] + STEP_VSWITCH_FLOWS_FINIT + + STEP_VSWITCH_2PHY_2VM_FINIT + }, + { + # Topology: 4 Parallel PVP connections + # To run a Linux bridge as a loopback in the Guest use: + # --test-params "guest_loopback=linux_bridge" --integration 4pvp_udp_dest_flows + "Name": "4pvp_udp_dest_flows", + "Description": "Continuous TC with 4 Parallel VMs, flows on UDP Dest Port", + "Deployment": "clean", + "Stream Type": "L4", + "MultiStream": 4, + "TestSteps": STEP_VSWITCH_2PHY_4VM_INIT + + STEP_VSWITCH_4_PARALLEL_VM_FLOWS_INIT + [ + # Start 4 VMs + ['vnf1', 'start'], + ['vnf2', 'start'], + ['vnf3', 'start'], + ['vnf4', 'start'], + ['trafficgen', 'send_traffic', {'traffic_type' : 'continuous', 'bidir' : 'False'}], + ['vnf1', 'stop'], + ['vnf2', 'stop'], + ['vnf3', 'stop'], + ['vnf4', 'stop'], + # Clean up + ] + STEP_VSWITCH_FLOWS_FINIT + + STEP_VSWITCH_2PHY_4VM_FINIT + }, + { + # Topology: 6 Parallel PVP connections + # To run a Linux bridge as a loopback in the Guest use: + # --test-params "guest_loopback=linux_bridge" --integration 6pvp_udp_dest_flows + "Name": "6pvp_udp_dest_flows", + "Description": "Continuous TC with 6 Parallel VMs, flows on UDP Dest Port", + "Deployment": "clean", + "Stream Type": "L4", + "MultiStream": 6, + "TestSteps": STEP_VSWITCH_2PHY_6VM_INIT + + STEP_VSWITCH_6_PARALLEL_VM_FLOWS_INIT + [ + # Start VMs + ['vnf1', 'start'], + ['vnf2', 'start'], + ['vnf3', 'start'], + ['vnf4', 'start'], + ['vnf5', 'start'], + ['vnf6', 'start'], + ['trafficgen', 'send_traffic', {'traffic_type' : 'continuous', 'bidir' : 'False'}], + ['vnf1', 'stop'], + ['vnf2', 'stop'], + ['vnf3', 'stop'], + ['vnf4', 'stop'], + ['vnf5', 'stop'], + ['vnf6', 'stop'], + ] + STEP_VSWITCH_FLOWS_FINIT + + STEP_VSWITCH_2PHY_6VM_FINIT + }, ] # Example of TC definition with exact vSwitch, VNF and TRAFFICGEN values. diff --git a/conf/integration/02_vswitch.conf b/conf/integration/02_vswitch.conf index 6bdf79d3..68eaf73e 100644 --- a/conf/integration/02_vswitch.conf +++ b/conf/integration/02_vswitch.conf @@ -28,3 +28,15 @@ TUNNEL_TYPE = 'vxlan' DUT_NIC1_MAC = '' # Used for OVS DPDK Decap DUT_NIC2_MAC = '' + +#Tunnel bridge configuration for P-TUN-P(VxLAN) deployment scenario +# to test VxLAN performance without any overlay ingress traffic by doing the +# encap decap inside the virtual switch itself. +TUNNEL_EXTERNAL_BRIDGE1 = 'br-phy1' +TUNNEL_EXTERNAL_BRIDGE2 = 'br-phy2' +TUNNEL_MODIFY_BRIDGE1 = 'br-mod1' +TUNNEL_MODIFY_BRIDGE2 = 'br-mod2' +TUNNEL_MODIFY_BRIDGE_MAC1 = '00:00:10:00:00:01' +TUNNEL_MODIFY_BRIDGE_MAC2 = '00:00:20:00:00:01' +TUNNEL_MODIFY_BRIDGE_IP1 = '10.0.0.1/24' +TUNNEL_MODIFY_BRIDGE_IP2 = '20.0.0.1/24' diff --git a/core/component_factory.py b/core/component_factory.py index a91872e2..258b7232 100644 --- a/core/component_factory.py +++ b/core/component_factory.py @@ -21,6 +21,7 @@ from core.vswitch_controller_p2p import VswitchControllerP2P from core.vswitch_controller_pvp import VswitchControllerPVP from core.vswitch_controller_pvvp import VswitchControllerPVVP from core.vswitch_controller_op2p import VswitchControllerOP2P +from core.vswitch_controller_ptunp import VswitchControllerPtunP from core.vnf_controller import VnfController from core.pktfwd_controller import PktFwdController from tools.load_gen.stress.stress import Stress @@ -73,6 +74,8 @@ def create_vswitch(deployment_scenario, vswitch_class, traffic, return VswitchControllerPVVP(vswitch_class, traffic) elif deployment_scenario.find("op2p") >= 0: return VswitchControllerOP2P(vswitch_class, traffic, tunnel_operation) + elif deployment_scenario.find("ptunp") >= 0: + return VswitchControllerPtunP(vswitch_class, traffic) elif deployment_scenario.find("clean") >= 0: return VswitchControllerClean(vswitch_class, traffic) diff --git a/core/vswitch_controller_ptunp.py b/core/vswitch_controller_ptunp.py new file mode 100644 index 00000000..27d26789 --- /dev/null +++ b/core/vswitch_controller_ptunp.py @@ -0,0 +1,238 @@ +# Copyright 2015-2016 Intel Corporation. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""VSwitch controller for Physical to VxLAN Tunnel Endpoint to Physical + deployment with mod operation. +""" + +import logging +from netaddr import EUI, IPNetwork, mac_unix + +from core.vswitch_controller import IVswitchController +from vswitches.utils import add_ports_to_flow +from conf import settings +from tools import tasks + +_FLOW_TEMPLATE = { + 'idle_timeout': '0' +} + +class VswitchControllerPtunP(IVswitchController): + """VSwitch controller for VxLAN ptunp deployment scenario. + The deployment scenario is to test VxLAN tunneling feature without using an + overlay ingress traffic. The VxLAN encap and decap performed in the virtual + switch in each direction. + + Attributes: + _vswitch_class: The vSwitch class to be used. + _vswitch: The vSwitch object controlled by this controller + _deployment_scenario: A string describing the scenario to set-up in the + constructor. + """ + def __init__(self, vswitch_class, traffic): + """Initializes up the prerequisites for the ptunp deployment scenario. + + :vswitch_class: the vSwitch class to be used. + """ + self._logger = logging.getLogger(__name__) + self._vswitch_class = vswitch_class + self._vswitch = vswitch_class() + self._deployment_scenario = "ptunp" + self._traffic = traffic.copy() + self.bridge_phy1 = settings.getValue('TUNNEL_EXTERNAL_BRIDGE1') + self.bridge_phy2 = settings.getValue('TUNNEL_EXTERNAL_BRIDGE2') + self.bridge_mod1 = settings.getValue('TUNNEL_MODIFY_BRIDGE1') + self.bridge_mod2 = settings.getValue('TUNNEL_MODIFY_BRIDGE2') + self.br_mod_mac1 = settings.getValue('TUNNEL_MODIFY_BRIDGE_MAC1') + self.br_mod_mac2 = settings.getValue('TUNNEL_MODIFY_BRIDGE_MAC2') + self.br_mod_ip1 = settings.getValue('TUNNEL_MODIFY_BRIDGE_IP1') + self.br_mod_ip2 = settings.getValue('TUNNEL_MODIFY_BRIDGE_IP2') + self.tunnel_type = settings.getValue('TUNNEL_TYPE') + self._logger.debug('Creation using ' + str(self._vswitch_class)) + + def setup(self): + """ Sets up the switch for VxLAN overlay PTUNP (tunnel encap or decap) + """ + self._logger.debug('Setting up phy-tun-phy tunneling scenario') + if self.tunnel_type is 'vxlan': + self._setup_vxlan_encap_decap() + else: + self._logger.error("Only VxLAN is supported for now") + raise NotImplementedError + + def _setup_vxlan_encap_decap(self): + """ Sets up switches for VxLAN overlay P-TUN-P test. + + Create 2 bridges br-phy1 and br-phy2 (The bridge to connect + physical ports. Two more bridges br-mod1 and br-mod2 to mangle + and redirect the packets from one tunnel port to other. + """ + self._logger.debug('Setup using ' + str(self._vswitch_class)) + try: + self._vswitch.start() + self._vswitch.add_switch(self.bridge_phy1) + self._vswitch.add_switch(self.bridge_phy2) + self._vswitch.add_switch(self.bridge_mod1, + params=["other_config:hwaddr=" + + self.br_mod_mac1 + ]) + self._vswitch.add_switch(self.bridge_mod2, + params=["other_config:hwaddr=" + + self.br_mod_mac2 + ]) + + tasks.run_task(['sudo', 'iptables', '-F'], + self._logger, 'Clean ip tables', + False) + tasks.run_task(['sudo', 'ip', 'addr', 'add', + self.br_mod_ip1, 'dev', self.bridge_mod1], + self._logger, 'Assign ' + + self.br_mod_ip1 + ' to ' + self.bridge_mod1, + False) + tasks.run_task(['sudo', 'ip', 'link', 'set', 'dev', self.bridge_mod1, 'up'], + self._logger, 'Bring up ' + self.bridge_mod1, False) + + tasks.run_task(['sudo', 'ip', 'addr', 'add', + self.br_mod_ip2, 'dev', self.bridge_mod2], + self._logger, 'Assign ' + + self.br_mod_ip2 + ' to ' + self.bridge_mod2, + False) + tasks.run_task(['sudo', 'ip', 'link', 'set', 'dev', self.bridge_mod2, 'up'], + self._logger, 'Bring up ' + self.bridge_mod2, False) + + tasks.run_task(['sudo', 'ip', 'link', 'set', 'dev', self.bridge_phy1, 'up'], + self._logger, 'Bring up ' + self.bridge_phy1, False) + tasks.run_task(['sudo', 'ip', 'link', 'set', 'dev', self.bridge_phy2, 'up'], + self._logger, 'Bring up ' + self.bridge_phy2, False) + self._vswitch.add_route(self.bridge_phy1, self.br_mod_ip1, self.bridge_mod1) + self._vswitch.add_route(self.bridge_phy2, self.br_mod_ip2, self.bridge_mod2) + + # Create tunnel ip and mac from the bridge ips + vxlan_local_ip1 = str(IPNetwork(self.br_mod_ip1).ip) + vxlan_local_ip2 = str(IPNetwork(self.br_mod_ip2).ip) + vxlan_rem_ip1 = str(IPNetwork(self.br_mod_ip1).ip + 1) + vxlan_rem_ip2 = str(IPNetwork(self.br_mod_ip2).ip + 1) + vxlan_rem_mac1 = EUI(int(EUI(self.br_mod_mac1)) + 1) + vxlan_rem_mac1.dialect = mac_unix + vxlan_rem_mac2 = EUI(int(EUI(self.br_mod_mac2)) + 1) + vxlan_rem_mac2.dialect = mac_unix + self._vswitch.set_tunnel_arp(vxlan_local_ip1, self.br_mod_mac1, + self.bridge_phy1) + self._vswitch.set_tunnel_arp(vxlan_local_ip2, self.br_mod_mac2, + self.bridge_phy2) + self._vswitch.set_tunnel_arp(vxlan_rem_ip1, str(vxlan_rem_mac1), + self.bridge_mod1) + self._vswitch.set_tunnel_arp(vxlan_rem_ip2, str(vxlan_rem_mac2), + self.bridge_mod2) + + # Lets add the ports to bridges + (_, phy1_number) = self._vswitch.add_phy_port(self.bridge_phy1) + (_, phy2_number) = self._vswitch.add_phy_port(self.bridge_phy2) + vxlan_vni = 'options:key=' + settings.getValue('VXLAN_VNI') + (_, phy3_number) = self._vswitch.add_tunnel_port(self.bridge_phy1, + vxlan_rem_ip1, + "vxlan", + params=[vxlan_vni]) + (_, phy4_number) = self._vswitch.add_tunnel_port(self.bridge_phy2, + vxlan_rem_ip2, + "vxlan", + params=[vxlan_vni]) + [(_, phy5_number), (_, phy6_number)] = \ + self._vswitch.add_veth_pair_port(self.bridge_mod1, self.bridge_mod2) + + # Set up flows for the switches + self._vswitch.del_flow(self.bridge_phy1) + self._vswitch.del_flow(self.bridge_phy2) + self._vswitch.del_flow(self.bridge_mod1) + self._vswitch.del_flow(self.bridge_mod2) + flow = add_ports_to_flow(_FLOW_TEMPLATE, phy1_number, + phy3_number) + self._vswitch.add_flow(self.bridge_phy1, flow) + flow = add_ports_to_flow(_FLOW_TEMPLATE, phy3_number, + phy1_number) + self._vswitch.add_flow(self.bridge_phy1, flow) + + flow = add_ports_to_flow(_FLOW_TEMPLATE, phy2_number, + phy4_number) + self._vswitch.add_flow(self.bridge_phy2, flow) + flow = add_ports_to_flow(_FLOW_TEMPLATE, phy4_number, + phy2_number) + self._vswitch.add_flow(self.bridge_phy2, flow) + flow = add_ports_to_flow(_FLOW_TEMPLATE, phy5_number, + 'LOCAL') + self._vswitch.add_flow(self.bridge_mod1, flow) + mod_flow_template = _FLOW_TEMPLATE.copy() + mod_flow_template.update({'ip':'', + 'actions': + ['mod_dl_src:' + str(vxlan_rem_mac2), + 'mod_dl_dst:' + self.br_mod_mac2, + 'mod_nw_src:' + vxlan_rem_ip2, + 'mod_nw_dst:' + vxlan_local_ip2 + ] + }) + flow = add_ports_to_flow(mod_flow_template, 'LOCAL', phy5_number) + self._vswitch.add_flow(self.bridge_mod1, flow) + flow = add_ports_to_flow(_FLOW_TEMPLATE, phy6_number, + 'LOCAL') + self._vswitch.add_flow(self.bridge_mod2, flow) + mod_flow_template = _FLOW_TEMPLATE.copy() + mod_flow_template.update({'ip':'', + 'actions': + ['mod_dl_src:' + str(vxlan_rem_mac1), + 'mod_dl_dst:' + self.br_mod_mac1, + 'mod_nw_src:' + vxlan_rem_ip1, + 'mod_nw_dst:' + vxlan_local_ip1] + }) + flow = add_ports_to_flow(mod_flow_template, 'LOCAL', phy6_number) + self._vswitch.add_flow(self.bridge_mod2, flow) + + except: + self._vswitch.stop() + raise + + def stop(self): + """Tears down the switch created in setup(). + """ + self._logger.debug('Stop using ' + str(self._vswitch_class)) + self._vswitch.stop() + + def __enter__(self): + self.setup() + + def __exit__(self, type_, value, traceback): + self.stop() + + def get_vswitch(self): + """See IVswitchController for description + """ + return self._vswitch + + def get_ports_info(self): + """See IVswitchController for description + """ + self._logger.debug('get_ports_info using ' + str(self._vswitch_class)) + ports = self._vswitch.get_ports(self.bridge_phy1) +\ + self._vswitch.get_ports(self.bridge_mod1) +\ + self._vswitch.get_ports(self.bridge_phy2) +\ + self._vswitch.get_ports(self.bridge_mod2) + return ports + + def dump_vswitch_flows(self): + """See IVswitchController for description + """ + self._logger.debug('dump_flows using ' + str(self._vswitch_class)) + self._vswitch.dump_flows(self.bridge_phy1) + self._vswitch.dump_flows(self.bridge_mod1) + self._vswitch.dump_flows(self.bridge_phy2) + self._vswitch.dump_flows(self.bridge_mod2) diff --git a/docs/userguide/integration.rst b/docs/userguide/integration.rst index c7886536..51c2f241 100755 --- a/docs/userguide/integration.rst +++ b/docs/userguide/integration.rst @@ -831,3 +831,52 @@ To run GENEVE decapsulation tests: ./vsperf --conf-file user_settings.py --integration --test-params 'tunnel_type=geneve' overlay_p2p_decap_cont + +Executing Tunnel encapsulation+decapsulation tests +-------------------------------------------------- + +The OVS DPDK encapsulation_decapsulation tests requires IPs, MAC addresses, +bridge names and WHITELIST_NICS for DPDK. + +The test cases can test the tunneling encap and decap without using any ingress +overlay traffic as compared to above test cases. To achieve this the OVS is +configured to perform encap and decap in a series on the same traffic stream as +given below. + +TRAFFIC-IN --> [ENCAP] --> [MOD-PKT] --> [DECAP] --> TRAFFIC-OUT + + +Default values are already provided. To customize for your environment, override +the following variables in you user_settings.py file: + + .. code-block:: python + + # Variables defined in conf/integration/02_vswitch.conf + + # Bridge names + TUNNEL_EXTERNAL_BRIDGE1 = 'br-phy1' + TUNNEL_EXTERNAL_BRIDGE2 = 'br-phy2' + TUNNEL_MODIFY_BRIDGE1 = 'br-mod1' + TUNNEL_MODIFY_BRIDGE2 = 'br-mod2' + + # IP of br-mod1 + TUNNEL_MODIFY_BRIDGE_IP1 = '10.0.0.1/24' + + # Mac of br-mod1 + TUNNEL_MODIFY_BRIDGE_MAC1 = '00:00:10:00:00:01' + + # IP of br-mod2 + TUNNEL_MODIFY_BRIDGE_IP2 = '20.0.0.1/24' + + #Mac of br-mod2 + TUNNEL_MODIFY_BRIDGE_MAC2 = '00:00:20:00:00:01' + + # vxlan|gre|geneve, Only VXLAN is supported for now. + TUNNEL_TYPE = 'vxlan' + +To run VXLAN encapsulation+decapsulation tests: + + .. code-block:: console + + ./vsperf --conf-file user_settings.py --integration + overlay_p2p_mod_tput diff --git a/vswitches/ovs.py b/vswitches/ovs.py index 243619b6..d2814b6a 100644 --- a/vswitches/ovs.py +++ b/vswitches/ovs.py @@ -122,6 +122,38 @@ class IVSwitchOvs(IVSwitch, tasks.Process): """ raise NotImplementedError + def add_veth_pair_port(self, switch_name=None, remote_switch_name=None, + local_opts=None, remote_opts=None): + """Creates veth-pair port between 'switch_name' and 'remote_switch_name' + + """ + if switch_name is None or remote_switch_name is None: + return + + bridge = self._bridges[switch_name] + remote_bridge = self._bridges[remote_switch_name] + pcount = str(self._get_port_count('type=patch')) + # TODO ::: What if interface name longer than allowed width?? + local_port_name = switch_name + '-' + remote_switch_name + '-' + pcount + remote_port_name = remote_switch_name + '-' + switch_name + '-' + pcount + local_params = ['--', 'set', 'Interface', local_port_name, + 'type=patch', + 'options:peer=' + remote_port_name] + remote_params = ['--', 'set', 'Interface', remote_port_name, + 'type=patch', + 'options:peer=' + local_port_name] + + if local_opts is not None: + local_params = local_params + local_opts + + if remote_opts is not None: + remote_params = remote_params + remote_opts + + local_of_port = bridge.add_port(local_port_name, local_params) + remote_of_port = remote_bridge.add_port(remote_port_name, remote_params) + return [(local_port_name, local_of_port), + (remote_port_name, remote_of_port)] + def add_tunnel_port(self, switch_name, remote_ip, tunnel_type='vxlan', params=None): """Creates tunneling port """ |