8da043c68506a7f7fec3427645f047fbcaab398e
[vswitchperf.git] / vswitches / ovs_dpdk_vhost.py
1 # Copyright 2015-2018 Intel Corporation., Tieto
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 subprocess
19
20 from src.ovs import OFBridge
21 from src.dpdk import dpdk
22 from conf import settings as S
23 from vswitches.ovs import IVSwitchOvs
24
25 class OvsDpdkVhost(IVSwitchOvs):
26     """ Open vSwitch with DPDK support
27
28     Generic OVS wrapper functionality in src.ovs is maximally used. This
29     class wraps DPDK system configuration along with DPDK specific OVS
30     parameters
31
32     The method docstrings document only considerations specific to this
33     implementation. For generic information of the nature of the methods,
34     see the interface.
35     """
36
37     def __init__(self):
38         super().__init__()
39         vswitchd_args = []
40
41         # legacy DPDK configuration through --dpdk option of vswitchd
42         if self.old_dpdk_config():
43             # override socket-mem settings
44             tmp_dpdk_args = S.getValue('VSWITCHD_DPDK_ARGS')
45             for tmp_arg in tmp_dpdk_args:
46                 if tmp_arg.startswith('--socket-mem'):
47                     tmp_dpdk_args.remove(tmp_arg)
48             tmp_dpdk_args += ['--socket-mem ' + ','.join(S.getValue('DPDK_SOCKET_MEM'))]
49             vswitchd_args = ['--dpdk'] + tmp_dpdk_args
50             # add dpdk args to generic ovs-vswitchd settings
51             if self._vswitchd_args:
52                 self._vswitchd_args = vswitchd_args + ['--'] + self._vswitchd_args
53             else:
54                 self._vswitchd_args = vswitchd_args
55
56     def configure(self):
57         """ Configure vswitchd DPDK options through ovsdb if needed
58         """
59         dpdk_config = S.getValue('VSWITCHD_DPDK_CONFIG')
60         if dpdk_config and not self.old_dpdk_config():
61             # override socket-mem settings
62             dpdk_config['dpdk-socket-mem'] = ','.join(S.getValue('DPDK_SOCKET_MEM'))
63             # enforce calls to ovs-vsctl with --no-wait
64             tmp_br = OFBridge(timeout=-1)
65             for option in dpdk_config:
66                 tmp_br.set_db_attribute('Open_vSwitch', '.',
67                                         'other_config:' + option, dpdk_config[option])
68
69     def start(self):
70         """See IVswitch for general description
71
72         Activates DPDK kernel modules, ovsdb and vswitchd.
73         """
74         dpdk.init()
75         super(OvsDpdkVhost, self).start()
76         # old style OVS <= 2.5.0 multi-queue enable
77         if S.getValue('OVS_OLD_STYLE_MQ') and \
78                 int(S.getValue('VSWITCH_DPDK_MULTI_QUEUES')):
79             tmp_br = OFBridge(timeout=-1)
80             tmp_br.set_db_attribute(
81                 'Open_vSwitch', '.', 'other_config:' +
82                 'n-dpdk-rxqs', S.getValue('VSWITCH_DPDK_MULTI_QUEUES'))
83
84     def stop(self):
85         """See IVswitch for general description
86
87         Kills ovsdb and vswitchd and removes DPDK kernel modules.
88         """
89
90         super(OvsDpdkVhost, self).stop()
91         dpdk.cleanup()
92
93     def add_switch(self, switch_name, params=None):
94         """See IVswitch for general description
95         """
96         switch_params = ['--', 'set', 'bridge', switch_name, 'datapath_type=netdev']
97         if params:
98             switch_params = switch_params + params
99
100         super(OvsDpdkVhost, self).add_switch(switch_name, switch_params)
101         if S.getValue('VSWITCH_AFFINITIZATION_ON') == 1:
102             # Sets the PMD core mask to VSWITCH_PMD_CPU_MASK
103             # for CPU core affinitization
104             self._switches[switch_name].set_db_attribute('Open_vSwitch', '.',
105                                                          'other_config:pmd-cpu-mask',
106                                                          S.getValue('VSWITCH_PMD_CPU_MASK'))
107
108     def add_phy_port(self, switch_name):
109         """See IVswitch for general description
110
111         Creates a port of type dpdk.
112         The new port is named dpdk<n> where n is an integer starting from 0.
113         """
114         _nics = S.getValue('NICS')
115         bridge = self._switches[switch_name]
116         dpdk_count = self._get_port_count('type=dpdk')
117         if dpdk_count == len(_nics):
118             raise RuntimeError("Can't add phy port! There are only {} ports defined "
119                                "by WHITELIST_NICS parameter!".format(len(_nics)))
120         port_name = 'dpdk' + str(dpdk_count)
121         # PCI info. Please note there must be no blank space, eg must be
122         # like 'options:dpdk-devargs=0000:06:00.0'
123         nic_pci = 'options:dpdk-devargs=' + _nics[dpdk_count]['pci']
124         params = ['--', 'set', 'Interface', port_name, 'type=dpdk', nic_pci]
125         # multi-queue enable
126
127         if int(S.getValue('VSWITCH_DPDK_MULTI_QUEUES')) and \
128                 not S.getValue('OVS_OLD_STYLE_MQ'):
129             params += ['options:n_rxq={}'.format(
130                 S.getValue('VSWITCH_DPDK_MULTI_QUEUES'))]
131         if S.getValue('VSWITCH_JUMBO_FRAMES_ENABLED'):
132             params += ['mtu_request={}'.format(
133                 S.getValue('VSWITCH_JUMBO_FRAMES_SIZE'))]
134         of_port = bridge.add_port(port_name, params)
135         return (port_name, of_port)
136
137     def add_vport(self, switch_name):
138         """See IVswitch for general description
139
140         Creates a port of type dpdkvhost
141         The new port is named dpdkvhost<n> where n is an integer starting
142         from 0
143         """
144         bridge = self._switches[switch_name]
145
146         if S.getValue('VSWITCH_VHOSTUSER_SERVER_MODE'):
147             nic_type = 'dpdkvhostuser'
148         else:
149             nic_type = 'dpdkvhostuserclient'
150
151         vhost_count = self._get_port_count('type={}'.format(nic_type))
152         port_name = nic_type + str(vhost_count)
153         params = ['--', 'set', 'Interface', port_name, 'type={}'.format(nic_type)]
154         if not S.getValue('VSWITCH_VHOSTUSER_SERVER_MODE'):
155             params += ['--', 'set', 'Interface', port_name, 'options:vhost-server-path='
156                        '{}{}'.format(S.getValue('TOOLS')['ovs_var_tmp'], port_name)]
157         if S.getValue('VSWITCH_JUMBO_FRAMES_ENABLED'):
158             params += ['mtu_request={}'.format(
159                 S.getValue('VSWITCH_JUMBO_FRAMES_SIZE'))]
160         of_port = bridge.add_port(port_name, params)
161
162         return (port_name, of_port)
163
164     @staticmethod
165     def old_dpdk_config():
166         """Checks if ovs-vswitchd uses legacy dpdk configuration via --dpdk option
167
168         :returns: True if legacy --dpdk option is supported, otherwise it returns False
169         """
170
171         ovs_vswitchd_bin = S.getValue('TOOLS')['ovs-vswitchd']
172         try:
173             subprocess.check_output(ovs_vswitchd_bin + r' --help | grep "\-\-dpdk"', shell=True)
174             return True
175         except subprocess.CalledProcessError:
176             return False