connections: Introduction of generic API
[vswitchperf.git] / core / vswitch_controller_pxp.py
index d4d1e76..d36ecdb 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright 2016 Intel Corporation.
+# Copyright 2016-2018 Intel Corporation., Tieto
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 
 """VSwitch controller for multi VM scenarios with serial or parallel connection
 """
-
-import logging
 import netaddr
 
 from core.vswitch_controller import IVswitchController
-from vswitches.utils import add_ports_to_flow
 from conf import settings
 
-_FLOW_TEMPLATE = {
-    'idle_timeout': '0'
-}
-
-_PROTO_TCP = 6
-_PROTO_UDP = 17
-
 class VswitchControllerPXP(IVswitchController):
     """VSwitch controller for PXP deployment scenario.
     """
     def __init__(self, deployment, vswitch_class, traffic):
-        """Initializes up the prerequisites for the PXP deployment scenario.
-
-        :vswitch_class: the vSwitch class to be used.
-        :deployment: the deployment scenario to configure
-        :traffic: dictionary with detailed traffic definition
+        """See IVswitchController for general description
         """
-        self._logger = logging.getLogger(__name__)
-        self._vswitch_class = vswitch_class
-        self._vswitch = vswitch_class()
+        super().__init__(deployment, vswitch_class, traffic)
         self._pxp_topology = 'parallel' if deployment.startswith('pvpv') else 'serial'
         if deployment == 'pvp':
             self._pxp_vm_count = 1
@@ -55,15 +39,13 @@ class VswitchControllerPXP(IVswitchController):
 
         self._deployment_scenario = deployment
 
-        self._traffic = traffic.copy()
         self._bidir = True if self._traffic['bidir'] == 'True' else False
-        self._logger.debug('Creation using ' + str(self._vswitch_class))
         self._bridge = settings.getValue('VSWITCH_BRIDGE_NAME')
 
     def setup(self):
         """ Sets up the switch for PXP
         """
-        self._logger.debug('Setup using ' + str(self._vswitch_class))
+        self._logger.debug('Setup using %s', str(self._vswitch_class))
 
         try:
             self._vswitch.start()
@@ -71,8 +53,8 @@ class VswitchControllerPXP(IVswitchController):
             self._vswitch.add_switch(self._bridge)
 
             # create physical ports
-            (_, phy1_number) = self._vswitch.add_phy_port(self._bridge)
-            (_, phy2_number) = self._vswitch.add_phy_port(self._bridge)
+            (phy1, _) = self._vswitch.add_phy_port(self._bridge)
+            (phy2, _) = self._vswitch.add_phy_port(self._bridge)
 
             # create VM ports
             # initialize vport array to requested number of VMs
@@ -86,54 +68,42 @@ class VswitchControllerPXP(IVswitchController):
                 self._logger.debug('Create %s vports for %s. VM with index %s',
                                    nics_nr, vmindex + 1, vmindex)
                 for _ in range(nics_nr):
-                    (_, vport) = self._vswitch.add_vport(self._bridge)
+                    (vport, _) = self._vswitch.add_vport(self._bridge)
                     vm_ports[vmindex].append(vport)
 
-            self._vswitch.del_flow(self._bridge)
-
-            # configure flows according to the TC definition
+            # configure connections according to the TC definition
             if self._pxp_topology == 'serial':
-                flow = _FLOW_TEMPLATE.copy()
-                if self._traffic['flow_type'] == 'IP':
-                    flow.update({'dl_type':'0x0800',
-                                 'nw_src':self._traffic['l3']['srcip'],
-                                 'nw_dst':self._traffic['l3']['dstip']})
+                # NOTE: all traffic from VMs is sent to other ports directly
+                # without applying traffic options to avoid issues with MAC swapping
+                # and upper layer mods performed inside guests
 
-                # insert flows for phy ports first
+                # insert connections for phy ports first
                 # from 1st PHY to 1st vport of 1st VM
-                self._add_flow(flow,
-                               phy1_number,
-                               vm_ports[0][0],
-                               self._bidir)
+                self._vswitch.add_connection(self._bridge, phy1, vm_ports[0][0], self._traffic)
+                self._vswitch.add_connection(self._bridge, vm_ports[0][0], phy1)
                 # from last vport of last VM to 2nd phy
-                self._add_flow(flow,
-                               vm_ports[self._pxp_vm_count-1][-1],
-                               phy2_number,
-                               self._bidir)
+                self._vswitch.add_connection(self._bridge, vm_ports[self._pxp_vm_count-1][-1], phy2)
+                self._vswitch.add_connection(self._bridge, phy2, vm_ports[self._pxp_vm_count-1][-1], self._traffic)
 
                 # add serial connections among VMs and VM NICs pairs if needed
                 # in case of multiple NICs pairs per VM, the pairs are chained
-                # first, before flow to the next VM is created
+                # first, before connection to the next VM is created
                 for vmindex in range(self._pxp_vm_count):
                     # connect VMs NICs pairs in case of 4 and more NICs per VM
                     connections = [(vm_ports[vmindex][2*(x+1)-1],
                                     vm_ports[vmindex][2*(x+1)])
                                    for x in range(int(len(vm_ports[vmindex])/2)-1)]
                     for connection in connections:
-                        self._add_flow(flow,
-                                       connection[0],
-                                       connection[1],
-                                       self._bidir)
+                        self._vswitch.add_connection(self._bridge, connection[0], connection[1])
+                        self._vswitch.add_connection(self._bridge, connection[1], connection[0])
                     # connect last NICs to the next VM if there is any
                     if self._pxp_vm_count > vmindex + 1:
-                        self._add_flow(flow,
-                                       vm_ports[vmindex][-1],
-                                       vm_ports[vmindex+1][0],
-                                       self._bidir)
+                        self._vswitch.add_connection(self._bridge, vm_ports[vmindex][-1], vm_ports[vmindex+1][0])
+                        self._vswitch.add_connection(self._bridge, vm_ports[vmindex+1][0], vm_ports[vmindex][-1])
             else:
-                proto = _PROTO_TCP if self._traffic['l3']['proto'].lower() == 'tcp' else _PROTO_UDP
-                dst_mac_value = netaddr.EUI(self._traffic['l2']['dstmac']).value
-                dst_ip_value = netaddr.IPAddress(self._traffic['l3']['dstip']).value
+                mac_value = netaddr.EUI(self._traffic['l2']['dstmac']).value
+                ip_value = netaddr.IPAddress(self._traffic['l3']['dstip']).value
+                port_value = self._traffic['l4']['dstport']
                 # initialize stream index; every NIC pair of every VM uses unique stream
                 stream = 0
                 for vmindex in range(self._pxp_vm_count):
@@ -146,31 +116,33 @@ class VswitchControllerPXP(IVswitchController):
                         port_pairs = [(vm_ports[vmindex][0], vm_ports[vmindex][0])]
 
                     for port_pair in port_pairs:
-                        flow_p = _FLOW_TEMPLATE.copy()
-                        flow_v = _FLOW_TEMPLATE.copy()
-
-                        # update flow based on trafficgen settings
+                        # override traffic options to ensure, that traffic is
+                        # dispatched among VMs connected in parallel
+                        options = {'multistream':1,
+                                   'stream_type':self._traffic['stream_type'],
+                                   'pre_installed_flows':'Yes'}
+                        # update connection based on trafficgen settings
                         if self._traffic['stream_type'] == 'L2':
-                            tmp_mac = netaddr.EUI(dst_mac_value + stream)
+                            tmp_mac = netaddr.EUI(mac_value + stream)
                             tmp_mac.dialect = netaddr.mac_unix_expanded
-                            flow_p.update({'dl_dst':tmp_mac})
+                            options.update({'l2':{'dstmac':tmp_mac}})
                         elif self._traffic['stream_type'] == 'L3':
-                            tmp_ip = netaddr.IPAddress(dst_ip_value + stream)
-                            flow_p.update({'dl_type':'0x0800', 'nw_dst':tmp_ip})
+                            tmp_ip = netaddr.IPAddress(ip_value + stream)
+                            options.update({'l3':{'dstip':tmp_ip}})
                         elif self._traffic['stream_type'] == 'L4':
-                            flow_p.update({'dl_type':'0x0800', 'nw_proto':proto, 'tp_dst':stream})
+                            options.update({'l3':{'proto':self._traffic['l3']['proto']}})
+                            options.update({'l4':{'dstport':(port_value + stream) % 65536}})
                         else:
                             raise RuntimeError('Unknown stream_type {}'.format(self._traffic['stream_type']))
 
-                        # insert flow to dispatch traffic from physical ports
+                        # insert connection to dispatch traffic from physical ports
                         # to VMs based on stream type; all traffic from VMs is
                         # sent to physical ports to avoid issues with MAC swapping
                         # and upper layer mods performed inside guests
-                        self._add_flow(flow_p, phy1_number, port_pair[0])
-                        self._add_flow(flow_v, port_pair[1], phy2_number)
-                        if self._bidir:
-                            self._add_flow(flow_p, phy2_number, port_pair[1])
-                            self._add_flow(flow_v, port_pair[0], phy1_number)
+                        self._vswitch.add_connection(self._bridge, phy1, port_pair[0], options)
+                        self._vswitch.add_connection(self._bridge, port_pair[1], phy2)
+                        self._vswitch.add_connection(self._bridge, phy2, port_pair[1], options)
+                        self._vswitch.add_connection(self._bridge, port_pair[0], phy1)
 
                         # every NIC pair needs its own unique traffic stream
                         stream += 1
@@ -182,40 +154,16 @@ class VswitchControllerPXP(IVswitchController):
     def stop(self):
         """Tears down the switch created in setup().
         """
-        self._logger.debug('Stop using ' + str(self._vswitch_class))
+        self._logger.debug('Stop using %s', str(self._vswitch_class))
         self._vswitch.stop()
 
-    def _add_flow(self, flow, port1, port2, reverse_flow=False):
-        """ Helper method to insert flow into the vSwitch
-        """
-        self._vswitch.add_flow(self._bridge,
-                               add_ports_to_flow(flow,
-                                                 port1,
-                                                 port2))
-        if reverse_flow:
-            self._vswitch.add_flow(self._bridge,
-                                   add_ports_to_flow(flow,
-                                                     port2,
-                                                     port1))
-
-    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))
+        self._logger.debug('get_ports_info  using %s', str(self._vswitch_class))
         return self._vswitch.get_ports(self._bridge)
 
-    def dump_vswitch_flows(self):
+    def dump_vswitch_connections(self):
         """See IVswitchController for description
         """
-        self._vswitch.dump_flows(self._bridge)
+        self._vswitch.dump_connections(self._bridge)