Merge "hugepage_doc: Add hugepage configuration info to installation doc"
[vswitchperf.git] / src / dpdk / dpdk.py
1 # Copyright 2015-2016 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 """Automation of system configuration for DPDK use.
16
17 Parts of this based on ``tools/dpdk_nic_bind.py`` script from Intel(R)
18 DPDK.
19 """
20
21 from sys import platform as _platform
22
23 import os
24 import subprocess
25 import logging
26
27 from tools import tasks
28 from conf import settings
29 from tools.module_manager import ModuleManager
30
31 _LOGGER = logging.getLogger(__name__)
32 RTE_PCI_TOOL = os.path.join(
33     settings.getValue('RTE_SDK_USER'), 'tools', 'dpdk_nic_bind.py')
34
35 _DPDK_MODULE_MANAGER = ModuleManager()
36
37 # declare global NIC variables only as their content might not be known yet
38 _NICS = []
39 _NICS_PCI = []
40
41 #
42 # system management
43 #
44
45 def init():
46     """Setup system for DPDK.
47     """
48     global _NICS
49     global _NICS_PCI
50     _NICS = settings.getValue('NICS')
51     _NICS_PCI = list(nic['pci'] for nic in _NICS)
52     if not _is_linux():
53         _LOGGER.error('Not running on a compatible Linux version. Exiting...')
54         return
55     _insert_modules()
56     _remove_vhost_net()
57     _bind_nics()
58
59
60 def cleanup():
61     """Setup system for DPDK.
62     """
63     if not _is_linux():
64         _LOGGER.error('Not running on a compatible Linux version. Exiting...')
65         return
66
67     _unbind_nics()
68     _remove_modules()
69     _vhost_user_cleanup()
70
71 #
72 # basic compatibility test
73 #
74
75 def _is_linux():
76     """Check if running on Linux.
77
78     Many of the functions in this file rely on features commonly found
79     only on Linux (i.e. ``/proc`` is not present on FreeBSD). Hence, this
80     check is important to ensure someone doesn't run this on an incompatible
81     OS or distro.
82     """
83     return _platform.startswith('linux') and os.path.isdir('/proc')
84
85 #
86 # module management
87 #
88
89 def _insert_modules():
90     """Ensure required modules are inserted on system.
91     """
92
93     _DPDK_MODULE_MANAGER.insert_modules(settings.getValue('SYS_MODULES'))
94
95     mod_path_prefix = settings.getValue('OVS_DIR')
96     _DPDK_MODULE_MANAGER.insert_module_group(settings.getValue('OVS_MODULES'),
97                                              mod_path_prefix)
98     if 'vfio-pci' not in settings.getValue('DPDK_MODULES'):
99         mod_path_prefix = os.path.join(settings.getValue('RTE_SDK'),
100                                        settings.getValue('RTE_TARGET'))
101         _DPDK_MODULE_MANAGER.insert_module_group(settings.getValue('DPDK_MODULES'),
102                                                  mod_path_prefix)
103     else:
104         _DPDK_MODULE_MANAGER.insert_modules(settings.getValue('DPDK_MODULES'))
105
106 def _remove_modules():
107     """Ensure required modules are removed from system.
108     """
109     _DPDK_MODULE_MANAGER.remove_modules()
110
111 #
112 # vhost specific modules management
113 #
114
115 def insert_vhost_modules():
116     """Inserts VHOST related kernel modules
117     """
118     mod_path_prefix = os.path.join(settings.getValue('RTE_SDK'),
119                                    'lib',
120                                    'librte_vhost')
121     _DPDK_MODULE_MANAGER.insert_module_group(settings.getValue('VHOST_MODULE'), mod_path_prefix)
122
123
124 def remove_vhost_modules():
125     """Removes all VHOST related kernel modules
126     """
127     # all modules are removed automatically by _remove_modules() method
128     pass
129
130
131 #
132 # 'vhost-net' module cleanup
133 #
134
135 def _remove_vhost_net():
136     """Remove vhost-net driver and file.
137     """
138     _DPDK_MODULE_MANAGER.remove_module('vhost-net')
139     try:
140         tasks.run_task(['sudo', 'rm', '-f', '/dev/vhost-net'], _LOGGER,
141                        'Removing \'/dev/vhost-net\' directory...', True)
142     except subprocess.CalledProcessError:
143         _LOGGER.error('Unable to remove directory \'/dev/vhost-net\'.')
144
145 #
146 # Vhost-user cleanup
147 #
148
149 def _vhost_user_cleanup():
150     """Remove files created by vhost-user tests.
151     """
152     for sock in settings.getValue('VHOST_USER_SOCKS'):
153         if os.path.exists(sock):
154             try:
155                 tasks.run_task(['sudo', 'rm', sock],
156                                _LOGGER,
157                                'Deleting vhost-user socket \'%s\'...' %
158                                sock,
159                                True)
160
161             except subprocess.CalledProcessError:
162                 _LOGGER.error('Unable to delete vhost-user socket \'%s\'.',
163                               sock)
164                 continue
165 #
166 # NIC management
167 #
168
169
170 def _bind_nics():
171     """Bind NICs using the Intel DPDK ``dpdk_nic_bind.py`` tool.
172     """
173     try:
174         _driver = 'igb_uio'
175         if 'vfio-pci' in settings.getValue('DPDK_MODULES'):
176             _driver = 'vfio-pci'
177             tasks.run_task(['sudo', 'chmod', 'a+x', '/dev/vfio'],
178                            _LOGGER, 'Setting VFIO permissions .. a+x',
179                            True)
180             tasks.run_task(['sudo', 'chmod', '-R', '666', '/dev/vfio/'],
181                            _LOGGER, 'Setting VFIO permissions .. 0666',
182                            True)
183
184         tasks.run_task(['sudo', RTE_PCI_TOOL, '--bind=' + _driver] +
185                        _NICS_PCI, _LOGGER,
186                        'Binding NICs %s...' % _NICS_PCI,
187                        True)
188     except subprocess.CalledProcessError:
189         _LOGGER.error('Unable to bind NICs %s', str(_NICS_PCI))
190
191 def _unbind_nics():
192     """Unbind NICs using the Intel DPDK ``dpdk_nic_bind.py`` tool.
193     """
194     try:
195         tasks.run_task(['sudo', RTE_PCI_TOOL, '--unbind'] +
196                        _NICS_PCI, _LOGGER,
197                        'Unbinding NICs %s...' % str(_NICS_PCI),
198                        True)
199     except subprocess.CalledProcessError:
200         _LOGGER.error('Unable to unbind NICs %s', str(_NICS_PCI))
201     # Rebind NICs to their original drivers
202     # using the Intel DPDK ``dpdk_nic_bind.py`` tool.
203     for nic in _NICS:
204         try:
205             if nic['driver']:
206                 tasks.run_task(['sudo', RTE_PCI_TOOL, '--bind',
207                                 nic['driver'], nic['pci']],
208                                _LOGGER, 'Binding NIC %s to %s...' %
209                                (nic['pci'], nic['driver']),
210                                True)
211         except subprocess.CalledProcessError:
212             _LOGGER.error('Unable to bind NIC %s to driver %s',
213                           nic['pci'], nic['driver'])
214
215 class Dpdk(object):
216     """A context manager for the system init/cleanup.
217     """
218     def __enter__(self):
219         _LOGGER.info('Setting up DPDK')
220         init()
221         return self
222
223     def __exit__(self, type_, value, traceback):
224         _LOGGER.info('Cleaning up DPDK')
225         cleanup()