1 # Copyright 2016-2017 Intel Corporation.
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
7 # http://www.apache.org/licenses/LICENSE-2.0
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.
15 """Various helper functions
22 from conf import settings as S
29 # pylint: disable=too-many-branches
30 def settings_update_paths():
31 """ Configure paths to OVS, DPDK and QEMU sources and binaries based on
32 selected vswitch type and src/binary switch. Data are taken from
33 PATHS dictionary and after their processing they are stored inside TOOLS.
34 PATHS dictionary has specific section for 'vswitch', 'qemu' and 'dpdk'
35 Following processing is done for every item:
36 item 'type' - string, which defines the type of paths ('src' or 'bin') to be selected
38 'src' means, that VSPERF will use OVS, DPDK or QEMU built from sources
39 e.g. by execution of systems/build_base_machine.sh script during VSPERF
41 'bin' means, that VSPERF will use OVS, DPDK or QEMU binaries installed
42 in the OS, e.g. via OS specific packaging system
43 item 'path' - string with valid path; Its content is checked for existence, prefixed
44 with section name and stored into TOOLS for later use
45 e.g. TOOLS['dpdk_src'] or TOOLS['vswitch_src']
46 item 'modules' - list of strings; Every value from given list is checked for '.ko'
47 suffix. In case it matches and it is not an absolute path to the module, then
48 module name is prefixed with 'path' defined for the same section
49 e.g. TOOLS['vswitch_modules'] = [
50 '/tmp/vsperf/src_vanilla/ovs/ovs/datapath/linux/openvswitch.ko']
51 all other items - string - if given string is a relative path and item 'path'
52 is defined for a given section, then item content will be prefixed with
53 content of the 'path'. Otherwise tool name will be searched within
54 standard system directories. Also any OS filename wildcards will be
55 expanded to the real path. At the end of processing, every absolute
56 path is checked for its existence. In case that temporary path (i.e. path
57 with '_tmp' suffix) doesn't exist, then log will be written and vsperf will
58 continue. If any other path will not exist, then vsperf execution will
59 be terminated with runtime error.
61 Note: In case that 'bin' type is set for DPDK, then TOOLS['dpdk_src'] will be set to
62 the value of PATHS['dpdk']['src']['path']. The reason is, that VSPERF uses downloaded
63 DPDK sources to copy DPDK and testpmd into the GUEST, where testpmd is built. In case,
64 that DPDK sources are not available, then vsperf will continue with test execution,
65 but testpmd can't be used as a guest loopback. This is useful in case, that other guest
66 loopback applications (e.g. buildin) are used by CI jobs, etc.
68 # set dpdk and ovs paths accorfing to VNF and VSWITCH
70 vswitch_type = S.getValue('PATHS')['vswitch'][S.getValue('VSWITCH')]['type']
71 paths['vswitch'] = S.getValue('PATHS')['vswitch'][S.getValue('VSWITCH')][vswitch_type]
72 paths['dpdk'] = S.getValue('PATHS')['dpdk'][S.getValue('PATHS')['dpdk']['type']]
73 paths['qemu'] = S.getValue('PATHS')['qemu'][S.getValue('PATHS')['qemu']['type']]
75 paths['paths']['ovs_var_tmp'] = S.getValue('PATHS')['vswitch']['ovs_var_tmp']
76 paths['paths']['ovs_etc_tmp'] = S.getValue('PATHS')['vswitch']['ovs_etc_tmp']
79 # pylint: disable=too-many-nested-blocks
80 for path_class in paths:
81 for tool in paths[path_class]:
82 tmp_tool = paths[path_class][tool]
84 # store valid path of given class into tools dict
86 if os.path.isdir(tmp_tool):
87 tools['{}_src'.format(path_class)] = tmp_tool
90 raise RuntimeError('Path {} does not exist.'.format(tmp_tool))
92 # store list of modules of given class into tools dict
95 for module in tmp_tool:
96 # add path to the .ko modules and check it for existence
97 if module.endswith('.ko') and not os.path.isabs(module):
98 module = os.path.join(paths[path_class]['path'], module)
99 if not os.path.exists(module):
100 raise RuntimeError('Cannot locate modlue {}'.format(module))
102 tmp_modules.append(module)
104 tools['{}_modules'.format(path_class)] = tmp_modules
107 # if path to the tool is relative, then 'path' will be prefixed
108 # in case that 'path' is not defined, then tool will be searched
109 # within standard system paths
110 if not os.path.isabs(tmp_tool):
111 if 'path' in paths[path_class]:
112 tmp_tool = os.path.join(paths[path_class]['path'], tmp_tool)
113 elif shutil.which(tmp_tool):
114 tmp_tool = shutil.which(tmp_tool)
116 raise RuntimeError('Cannot locate tool {}'.format(tmp_tool))
118 # expand OS wildcards in paths if needed
119 if glob.has_magic(tmp_tool):
120 tmp_glob = glob.glob(tmp_tool)
121 if len(tmp_glob) == 0:
122 raise RuntimeError('Path to the {} is not valid: {}.'.format(tool, tmp_tool))
123 elif len(tmp_glob) > 1:
124 raise RuntimeError('Path to the {} is ambiguous {}'.format(tool, tmp_glob))
125 elif len(tmp_glob) == 1:
126 tmp_tool = tmp_glob[0]
127 elif not os.path.exists(tmp_tool):
128 if tool.endswith('_tmp'):
129 logging.getLogger().debug('Temporary path to the %s does not '
130 'exist: %s', tool, tmp_tool)
132 raise RuntimeError('Path to the {} is not valid: {}'.format(tool, tmp_tool))
134 tools[tool] = tmp_tool
136 # ensure, that dpkg_src for bin will be set to downloaded DPDK sources, so it can
137 # be copied to the guest share dir and used by GUEST to build and run testpmd
138 # Validity of the path is not checked by purpose, so user can use VSPERF without
139 # downloading DPDK sources. In that case guest loopback can't be set to 'testpmd'
140 if S.getValue('PATHS')['dpdk']['type'] == 'bin':
141 tools['dpdk_src'] = S.getValue('PATHS')['dpdk']['src']['path']
143 S.setValue('TOOLS', tools)
145 def check_traffic(traffic):
146 """Check traffic definition and correct it if possible.
148 # check if requested networking layers make sense
149 if traffic['l4']['enabled']:
150 if not traffic['l3']['enabled']:
151 raise RuntimeError('TRAFFIC misconfiguration: l3 must be enabled '
154 # check if multistream configuration makes sense
155 if traffic['multistream']:
156 if traffic['stream_type'] == 'L3':
157 if not traffic['l3']['enabled']:
158 raise RuntimeError('TRAFFIC misconfiguration: l3 must be '
159 'enabled if l3 streams are requested.')
160 if traffic['stream_type'] == 'L4':
161 if not traffic['l4']['enabled']:
162 raise RuntimeError('TRAFFIC misconfiguration: l4 must be '
163 'enabled if l4 streams are requested.')
165 # in case of UDP ports we have only 65536 (0-65535) unique options
166 if traffic['multistream'] > MAX_L4_FLOWS:
167 logging.getLogger().warning(
168 'Requested amount of L4 flows %s is bigger than number of '
169 'transport protocol ports. It was set to %s.',
170 traffic['multistream'], MAX_L4_FLOWS)
171 traffic['multistream'] = MAX_L4_FLOWS