Merge "Doc: Release notes for Fraser"
[vswitchperf.git] / vswitches / ovs_dpdk_vhost.py
index 7b5034c..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.
 """VSPERF VSwitch implementation using DPDK and vhost ports
 """
 
 """VSPERF VSwitch implementation using DPDK and vhost ports
 """
 
-from conf import settings
-from vswitches.vswitch import IVSwitch
-from src.ovs import VSwitchd, OFBridge
-from src.dpdk import dpdk
+import logging
+import subprocess
 
 
-VSWITCHD_CONST_ARGS = ['--', '--log-file']
+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
@@ -33,14 +34,40 @@ class OvsDpdkVhost(IVSwitch):
     implementation. For generic information of the nature of the methods,
     see the interface.
     """
     implementation. For generic information of the nature of the methods,
     see the interface.
     """
-    def __init__(self):
-        vswitchd_args = ['--dpdk']
-        vswitchd_args += settings.getValue('VSWITCHD_DPDK_ARGS')
-        vswitchd_args += VSWITCHD_CONST_ARGS
 
 
-        self._vswitchd = VSwitchd(vswitchd_args=vswitchd_args,
-                            expected_cmd=r'EAL: Master l*core \d+ is ready')
-        self._bridges = {}
+    def __init__(self):
+        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
@@ -48,33 +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()
 
-    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', '60000')
-        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()
+        switch_params = ['--', 'set', 'bridge', switch_name, 'datapath_type=netdev']
+        if params:
+            switch_params = switch_params + params
+
+        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
+            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
@@ -82,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):
@@ -98,47 +145,50 @@ class OvsDpdkVhost(IVSwitch):
         from 0
         """
         bridge = self._bridges[switch_name]
         from 0
         """
         bridge = self._bridges[switch_name]
-        vhost_count = self._get_port_count(bridge, 'type=dpdkvhost')
-        port_name = 'dpdkvhost' + str(vhost_count)
-        params = ['--', 'set', 'Interface', port_name, 'type=dpdkvhost']
+
+        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()