Merge "Doc: Release notes for Fraser"
[vswitchperf.git] / vswitches / ovs_dpdk_vhost.py
index b1fd08b..6deb0c2 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright 2015 Intel Corporation.
+# Copyright 2015-2017 Intel Corporation.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 """
 
 import logging
 """
 
 import logging
-from conf import settings
-from vswitches.vswitch import IVSwitch
-from src.ovs import VSwitchd, OFBridge
-from src.dpdk import dpdk
+import subprocess
 
 
-_VSWITCHD_CONST_ARGS = ['--', '--log-file']
-_VHOST_METHOD = settings.getValue('VHOST_METHOD')
+from src.ovs import OFBridge
+from src.dpdk import dpdk
+from conf import settings as S
+from vswitches.ovs import IVSwitchOvs
 
 
-class OvsDpdkVhost(IVSwitch):
-    """VSwitch implementation using DPDK and vhost ports
+class OvsDpdkVhost(IVSwitchOvs):
+    """ Open vSwitch with DPDK support
 
     Generic OVS wrapper functionality in src.ovs is maximally used. This
     class wraps DPDK system configuration along with DPDK specific OVS
 
     Generic OVS wrapper functionality in src.ovs is maximally used. This
     class wraps DPDK system configuration along with DPDK specific OVS
@@ -36,21 +35,39 @@ class OvsDpdkVhost(IVSwitch):
     see the interface.
     """
 
     see the interface.
     """
 
-    _logger = logging.getLogger()
-
     def __init__(self):
     def __init__(self):
-        vswitchd_args = ['--dpdk']
-        vswitchd_args += settings.getValue('VSWITCHD_DPDK_ARGS')
-        vswitchd_args += _VSWITCHD_CONST_ARGS
-
-        if _VHOST_METHOD == "cuse":
-            self._logger.info("Inserting VHOST modules into kernel...")
-            dpdk.insert_vhost_modules()
-
-        self._vswitchd = VSwitchd(vswitchd_args=vswitchd_args,
-                                  expected_cmd=
-                                  r'EAL: Master l*core \d+ is ready')
-        self._bridges = {}
+        super(OvsDpdkVhost, self).__init__()
+        self._logger = logging.getLogger(__name__)
+
+        vswitchd_args = []
+
+        # legacy DPDK configuration through --dpdk option of vswitchd
+        if self.old_dpdk_config():
+            # override socket-mem settings
+            tmp_dpdk_args = S.getValue('VSWITCHD_DPDK_ARGS')
+            for tmp_arg in tmp_dpdk_args:
+                if tmp_arg.startswith('--socket-mem'):
+                    tmp_dpdk_args.remove(tmp_arg)
+            tmp_dpdk_args += ['--socket-mem ' + ','.join(S.getValue('DPDK_SOCKET_MEM'))]
+            vswitchd_args = ['--dpdk'] + tmp_dpdk_args
+            # add dpdk args to generic ovs-vswitchd settings
+            if self._vswitchd_args:
+                self._vswitchd_args = vswitchd_args + ['--'] + self._vswitchd_args
+            else:
+                self._vswitchd_args = vswitchd_args
+
+    def configure(self):
+        """ Configure vswitchd DPDK options through ovsdb if needed
+        """
+        dpdk_config = S.getValue('VSWITCHD_DPDK_CONFIG')
+        if dpdk_config and not self.old_dpdk_config():
+            # override socket-mem settings
+            dpdk_config['dpdk-socket-mem'] = ','.join(S.getValue('DPDK_SOCKET_MEM'))
+            # enforce calls to ovs-vsctl with --no-wait
+            tmp_br = OFBridge(timeout=-1)
+            for option in dpdk_config:
+                tmp_br.set_db_attribute('Open_vSwitch', '.',
+                                        'other_config:' + option, dpdk_config[option])
 
     def start(self):
         """See IVswitch for general description
 
     def start(self):
         """See IVswitch for general description
@@ -58,43 +75,38 @@ class OvsDpdkVhost(IVSwitch):
         Activates DPDK kernel modules, ovsdb and vswitchd.
         """
         dpdk.init()
         Activates DPDK kernel modules, ovsdb and vswitchd.
         """
         dpdk.init()
-        self._vswitchd.start()
+        super(OvsDpdkVhost, self).start()
+        # old style OVS <= 2.5.0 multi-queue enable
+        if S.getValue('OVS_OLD_STYLE_MQ') and \
+                int(S.getValue('VSWITCH_DPDK_MULTI_QUEUES')):
+            tmp_br = OFBridge(timeout=-1)
+            tmp_br.set_db_attribute(
+                'Open_vSwitch', '.', 'other_config:' +
+                'n-dpdk-rxqs', S.getValue('VSWITCH_DPDK_MULTI_QUEUES'))
 
     def stop(self):
         """See IVswitch for general description
 
         Kills ovsdb and vswitchd and removes DPDK kernel modules.
         """
 
     def stop(self):
         """See IVswitch for general description
 
         Kills ovsdb and vswitchd and removes DPDK kernel modules.
         """
-        self._vswitchd.kill()
+
+        super(OvsDpdkVhost, self).stop()
         dpdk.cleanup()
         dpdk.cleanup()
-        dpdk.remove_vhost_modules()
 
 
-    def add_switch(self, switch_name):
+    def add_switch(self, switch_name, params=None):
         """See IVswitch for general description
         """
         """See IVswitch for general description
         """
-        bridge = OFBridge(switch_name)
-        bridge.create()
-        bridge.set_db_attribute('Open_vSwitch', '.',
-                                'other_config:max-idle',
-                                settings.getValue('VSWITCH_FLOW_TIMEOUT'))
+        switch_params = ['--', 'set', 'bridge', switch_name, 'datapath_type=netdev']
+        if params:
+            switch_params = switch_params + params
 
 
-        if settings.getValue('VSWITCH_AFFINITIZATION_ON') == 1:
+        super(OvsDpdkVhost, self).add_switch(switch_name, switch_params)
+        if S.getValue('VSWITCH_AFFINITIZATION_ON') == 1:
             # Sets the PMD core mask to VSWITCH_PMD_CPU_MASK
             # for CPU core affinitization
             # Sets the PMD core mask to VSWITCH_PMD_CPU_MASK
             # for CPU core affinitization
-            bridge.set_db_attribute('Open_vSwitch', '.',
-                                    'other_config:pmd-cpu-mask',
-                                    settings.getValue('VSWITCH_PMD_CPU_MASK'))
-
-        bridge.set_db_attribute('Bridge', bridge.br_name,
-                                'datapath_type', 'netdev')
-        self._bridges[switch_name] = bridge
-
-    def del_switch(self, switch_name):
-        """See IVswitch for general description
-        """
-        bridge = self._bridges[switch_name]
-        self._bridges.pop(switch_name)
-        bridge.destroy()
+            self._bridges[switch_name].set_db_attribute('Open_vSwitch', '.',
+                                                        'other_config:pmd-cpu-mask',
+                                                        S.getValue('VSWITCH_PMD_CPU_MASK'))
 
     def add_phy_port(self, switch_name):
         """See IVswitch for general description
 
     def add_phy_port(self, switch_name):
         """See IVswitch for general description
@@ -102,12 +114,27 @@ class OvsDpdkVhost(IVSwitch):
         Creates a port of type dpdk.
         The new port is named dpdk<n> where n is an integer starting from 0.
         """
         Creates a port of type dpdk.
         The new port is named dpdk<n> where n is an integer starting from 0.
         """
+        _nics = S.getValue('NICS')
         bridge = self._bridges[switch_name]
         bridge = self._bridges[switch_name]
-        dpdk_count = self._get_port_count(bridge, 'type=dpdk')
+        dpdk_count = self._get_port_count('type=dpdk')
+        if dpdk_count == len(_nics):
+            raise RuntimeError("Can't add phy port! There are only {} ports defined "
+                               "by WHITELIST_NICS parameter!".format(len(_nics)))
         port_name = 'dpdk' + str(dpdk_count)
         port_name = 'dpdk' + str(dpdk_count)
-        params = ['--', 'set', 'Interface', port_name, 'type=dpdk']
+        # PCI info. Please note there must be no blank space, eg must be
+        # like 'options:dpdk-devargs=0000:06:00.0'
+        nic_pci = 'options:dpdk-devargs=' + _nics[dpdk_count]['pci']
+        params = ['--', 'set', 'Interface', port_name, 'type=dpdk', nic_pci]
+        # multi-queue enable
+
+        if int(S.getValue('VSWITCH_DPDK_MULTI_QUEUES')) and \
+                not S.getValue('OVS_OLD_STYLE_MQ'):
+            params += ['options:n_rxq={}'.format(
+                S.getValue('VSWITCH_DPDK_MULTI_QUEUES'))]
+        if S.getValue('VSWITCH_JUMBO_FRAMES_ENABLED'):
+            params += ['mtu_request={}'.format(
+                S.getValue('VSWITCH_JUMBO_FRAMES_SIZE'))]
         of_port = bridge.add_port(port_name, params)
         of_port = bridge.add_port(port_name, params)
-
         return (port_name, of_port)
 
     def add_vport(self, switch_name):
         return (port_name, of_port)
 
     def add_vport(self, switch_name):
@@ -118,54 +145,50 @@ class OvsDpdkVhost(IVSwitch):
         from 0
         """
         bridge = self._bridges[switch_name]
         from 0
         """
         bridge = self._bridges[switch_name]
-        # Changed dpdkvhost to dpdkvhostuser to be able to run in Qemu 2.2
-        if _VHOST_METHOD == "cuse":
-            vhost_count = self._get_port_count(bridge, 'type=dpdkvhostcuse')
-            port_name = 'dpdkvhostcuse' + str(vhost_count)
-            params = ['--', 'set', 'Interface', port_name, 'type=dpdkvhostcuse']
-        else:
-            vhost_count = self._get_port_count(bridge, 'type=dpdkvhostuser')
-            port_name = 'dpdkvhostuser' + str(vhost_count)
-            params = ['--', 'set', 'Interface', port_name, 'type=dpdkvhostuser']
 
 
+        if S.getValue('VSWITCH_VHOSTUSER_SERVER_MODE'):
+            nic_type = 'dpdkvhostuser'
+        else:
+            nic_type = 'dpdkvhostuserclient'
+
+        vhost_count = self._get_port_count('type={}'.format(nic_type))
+        port_name = nic_type + str(vhost_count)
+        params = ['--', 'set', 'Interface', port_name, 'type={}'.format(nic_type)]
+        if not S.getValue('VSWITCH_VHOSTUSER_SERVER_MODE'):
+            params += ['--', 'set', 'Interface', port_name, 'options:vhost-server-path='
+                       '{}{}'.format(S.getValue('TOOLS')['ovs_var_tmp'], port_name)]
+        if S.getValue('VSWITCH_JUMBO_FRAMES_ENABLED'):
+            params += ['mtu_request={}'.format(
+                S.getValue('VSWITCH_JUMBO_FRAMES_SIZE'))]
         of_port = bridge.add_port(port_name, params)
 
         return (port_name, of_port)
 
         of_port = bridge.add_port(port_name, params)
 
         return (port_name, of_port)
 
-    def get_ports(self, switch_name):
-        """See IVswitch for general description
-        """
-        bridge = self._bridges[switch_name]
-        ports = list(bridge.get_ports().items())
-        return [(name, of_port) for (name, (of_port, _)) in ports]
+    @staticmethod
+    def old_dpdk_config():
+        """Checks if ovs-vswitchd uses legacy dpdk configuration via --dpdk option
 
 
-    def del_port(self, switch_name, port_name):
-        """See IVswitch for general description
+        :returns: True if legacy --dpdk option is supported, otherwise it returns False
         """
         """
-        bridge = self._bridges[switch_name]
-        bridge.del_port(port_name)
 
 
-    def add_flow(self, switch_name, flow):
+        ovs_vswitchd_bin = S.getValue('TOOLS')['ovs-vswitchd']
+        try:
+            subprocess.check_output(ovs_vswitchd_bin + r' --help | grep "\-\-dpdk"', shell=True)
+            return True
+        except subprocess.CalledProcessError:
+            return False
+
+    def add_connection(self, switch_name, port1, port2, bidir=False):
         """See IVswitch for general description
         """
         """See IVswitch for general description
         """
-        bridge = self._bridges[switch_name]
-        bridge.add_flow(flow)
+        raise NotImplementedError()
 
 
-    def del_flow(self, switch_name, flow=None):
+    def del_connection(self, switch_name, port1, port2, bidir=False):
         """See IVswitch for general description
         """
         """See IVswitch for general description
         """
-        flow = flow or {}
-        bridge = self._bridges[switch_name]
-        bridge.del_flow(flow)
+        raise NotImplementedError()
 
 
-    @staticmethod
-    def _get_port_count(bridge, param):
-        """Returns the number of ports having a certain parameter
-
-        :param bridge: The src.ovs.ofctl.OFBridge on which to operate
-        :param param: The parameter to search for
-        :returns: Count of matches
+    def dump_connections(self, switch_name):
+        """See IVswitch for general description
         """
         """
-        port_params = [c for (_, (_, c)) in list(bridge.get_ports().items())]
-        param_hits = [i for i in port_params if param in i]
-        return len(param_hits)
+        raise NotImplementedError()