Merge "loadgen: Support for Stressor-VMs as a Loadgen"
[vswitchperf.git] / vswitches / ovs_dpdk_vhost.py
1 # Copyright 2015-2017 Intel Corporation.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #   http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 """VSPERF VSwitch implementation using DPDK and vhost ports
16 """
17
18 import logging
19 import subprocess
20
21 from src.ovs import OFBridge
22 from src.dpdk import dpdk
23 from conf import settings as S
24 from vswitches.ovs import IVSwitchOvs
25
26 class OvsDpdkVhost(IVSwitchOvs):
27     """ Open vSwitch with DPDK support
28
29     Generic OVS wrapper functionality in src.ovs is maximally used. This
30     class wraps DPDK system configuration along with DPDK specific OVS
31     parameters
32
33     The method docstrings document only considerations specific to this
34     implementation. For generic information of the nature of the methods,
35     see the interface.
36     """
37
38     def __init__(self):
39         super(OvsDpdkVhost, self).__init__()
40         self._logger = logging.getLogger(__name__)
41
42         vswitchd_args = []
43
44         # legacy DPDK configuration through --dpdk option of vswitchd
45         if self.old_dpdk_config():
46             # override socket-mem settings
47             tmp_dpdk_args = S.getValue('VSWITCHD_DPDK_ARGS')
48             for tmp_arg in tmp_dpdk_args:
49                 if tmp_arg.startswith('--socket-mem'):
50                     tmp_dpdk_args.remove(tmp_arg)
51             tmp_dpdk_args += ['--socket-mem ' + ','.join(S.getValue('DPDK_SOCKET_MEM'))]
52             vswitchd_args = ['--dpdk'] + tmp_dpdk_args
53             # add dpdk args to generic ovs-vswitchd settings
54             if self._vswitchd_args:
55                 self._vswitchd_args = vswitchd_args + ['--'] + self._vswitchd_args
56             else:
57                 self._vswitchd_args = vswitchd_args
58
59     def configure(self):
60         """ Configure vswitchd DPDK options through ovsdb if needed
61         """
62         dpdk_config = S.getValue('VSWITCHD_DPDK_CONFIG')
63         if dpdk_config and not self.old_dpdk_config():
64             # override socket-mem settings
65             dpdk_config['dpdk-socket-mem'] = ','.join(S.getValue('DPDK_SOCKET_MEM'))
66             # enforce calls to ovs-vsctl with --no-wait
67             tmp_br = OFBridge(timeout=-1)
68             for option in dpdk_config:
69                 tmp_br.set_db_attribute('Open_vSwitch', '.',
70                                         'other_config:' + option, dpdk_config[option])
71
72     def start(self):
73         """See IVswitch for general description
74
75         Activates DPDK kernel modules, ovsdb and vswitchd.
76         """
77         dpdk.init()
78         super(OvsDpdkVhost, self).start()
79         # old style OVS <= 2.5.0 multi-queue enable
80         if S.getValue('OVS_OLD_STYLE_MQ') and \
81                 int(S.getValue('VSWITCH_DPDK_MULTI_QUEUES')):
82             tmp_br = OFBridge(timeout=-1)
83             tmp_br.set_db_attribute(
84                 'Open_vSwitch', '.', 'other_config:' +
85                 'n-dpdk-rxqs', S.getValue('VSWITCH_DPDK_MULTI_QUEUES'))
86
87     def stop(self):
88         """See IVswitch for general description
89
90         Kills ovsdb and vswitchd and removes DPDK kernel modules.
91         """
92
93         super(OvsDpdkVhost, self).stop()
94         dpdk.cleanup()
95
96     def add_switch(self, switch_name, params=None):
97         """See IVswitch for general description
98         """
99         switch_params = ['--', 'set', 'bridge', switch_name, 'datapath_type=netdev']
100         if params:
101             switch_params = switch_params + params
102
103         super(OvsDpdkVhost, self).add_switch(switch_name, switch_params)
104         if S.getValue('VSWITCH_AFFINITIZATION_ON') == 1:
105             # Sets the PMD core mask to VSWITCH_PMD_CPU_MASK
106             # for CPU core affinitization
107             self._bridges[switch_name].set_db_attribute('Open_vSwitch', '.',
108                                                         'other_config:pmd-cpu-mask',
109                                                         S.getValue('VSWITCH_PMD_CPU_MASK'))
110
111     def add_phy_port(self, switch_name):
112         """See IVswitch for general description
113
114         Creates a port of type dpdk.
115         The new port is named dpdk<n> where n is an integer starting from 0.
116         """
117         _nics = S.getValue('NICS')
118         bridge = self._bridges[switch_name]
119         dpdk_count = self._get_port_count('type=dpdk')
120         if dpdk_count == len(_nics):
121             raise RuntimeError("Can't add phy port! There are only {} ports defined "
122                                "by WHITELIST_NICS parameter!".format(len(_nics)))
123         port_name = 'dpdk' + str(dpdk_count)
124         # PCI info. Please note there must be no blank space, eg must be
125         # like 'options:dpdk-devargs=0000:06:00.0'
126         nic_pci = 'options:dpdk-devargs=' + _nics[dpdk_count]['pci']
127         params = ['--', 'set', 'Interface', port_name, 'type=dpdk', nic_pci]
128         # multi-queue enable
129
130         if int(S.getValue('VSWITCH_DPDK_MULTI_QUEUES')) and \
131                 not S.getValue('OVS_OLD_STYLE_MQ'):
132             params += ['options:n_rxq={}'.format(
133                 S.getValue('VSWITCH_DPDK_MULTI_QUEUES'))]
134         if S.getValue('VSWITCH_JUMBO_FRAMES_ENABLED'):
135             params += ['mtu_request={}'.format(
136                 S.getValue('VSWITCH_JUMBO_FRAMES_SIZE'))]
137         of_port = bridge.add_port(port_name, params)
138         return (port_name, of_port)
139
140     def add_vport(self, switch_name):
141         """See IVswitch for general description
142
143         Creates a port of type dpdkvhost
144         The new port is named dpdkvhost<n> where n is an integer starting
145         from 0
146         """
147         bridge = self._bridges[switch_name]
148
149         if S.getValue('VSWITCH_VHOSTUSER_SERVER_MODE'):
150             nic_type = 'dpdkvhostuser'
151         else:
152             nic_type = 'dpdkvhostuserclient'
153
154         vhost_count = self._get_port_count('type={}'.format(nic_type))
155         port_name = nic_type + str(vhost_count)
156         params = ['--', 'set', 'Interface', port_name, 'type={}'.format(nic_type)]
157         if not S.getValue('VSWITCH_VHOSTUSER_SERVER_MODE'):
158             params += ['--', 'set', 'Interface', port_name, 'options:vhost-server-path='
159                        '{}{}'.format(S.getValue('TOOLS')['ovs_var_tmp'], port_name)]
160         if S.getValue('VSWITCH_JUMBO_FRAMES_ENABLED'):
161             params += ['mtu_request={}'.format(
162                 S.getValue('VSWITCH_JUMBO_FRAMES_SIZE'))]
163         of_port = bridge.add_port(port_name, params)
164
165         return (port_name, of_port)
166
167     @staticmethod
168     def old_dpdk_config():
169         """Checks if ovs-vswitchd uses legacy dpdk configuration via --dpdk option
170
171         :returns: True if legacy --dpdk option is supported, otherwise it returns False
172         """
173
174         ovs_vswitchd_bin = S.getValue('TOOLS')['ovs-vswitchd']
175         try:
176             subprocess.check_output(ovs_vswitchd_bin + r' --help | grep "\-\-dpdk"', shell=True)
177             return True
178         except subprocess.CalledProcessError:
179             return False
180
181     def add_connection(self, switch_name, port1, port2, bidir=False):
182         """See IVswitch for general description
183         """
184         raise NotImplementedError()
185
186     def del_connection(self, switch_name, port1, port2, bidir=False):
187         """See IVswitch for general description
188         """
189         raise NotImplementedError()
190
191     def dump_connections(self, switch_name):
192         """See IVswitch for general description
193         """
194         raise NotImplementedError()