1 # Copyright 2016 Cisco Systems, Inc. All rights reserved.
3 # Licensed under the Apache License, Version 2.0 (the "License"); you may
4 # not use this file except in compliance with the License. You may obtain
5 # 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, WITHOUT
11 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 # License for the specific language governing permissions and limitations
16 from math import isnan
24 from functools import wraps
29 class TimeoutError(Exception):
33 def timeout(seconds=10, error_message=os.strerror(errno.ETIME)):
35 def _handle_timeout(_signum, _frame):
36 raise TimeoutError(error_message)
38 def wrapper(*args, **kwargs):
39 signal.signal(signal.SIGALRM, _handle_timeout)
42 result = func(*args, **kwargs)
47 return wraps(func)(wrapper)
52 def save_json_result(result, json_file, std_json_path, service_chain, service_chain_count,
53 flow_count, frame_sizes):
54 """Save results in json format file."""
57 filepaths.append(json_file)
59 name_parts = [service_chain, str(service_chain_count), str(flow_count)] + list(frame_sizes)
60 filename = '-'.join(name_parts) + '.json'
61 filepaths.append(os.path.join(std_json_path, filename))
64 for file_path in filepaths:
65 LOG.info('Saving results in json file: %s...', file_path)
66 with open(file_path, 'w') as jfp:
71 separators=(',', ': '),
72 default=lambda obj: obj.to_json())
75 def byteify(data, ignore_dicts=False):
76 # if this is a unicode string, return its string representation
77 if isinstance(data, unicode):
78 return data.encode('utf-8')
79 # if this is a list of values, return list of byteified values
80 if isinstance(data, list):
81 return [byteify(item, ignore_dicts=ignore_dicts) for item in data]
82 # if this is a dictionary, return dictionary of byteified keys and values
83 # but only if we haven't already byteified it
84 if isinstance(data, dict) and not ignore_dicts:
85 return {byteify(key, ignore_dicts=ignore_dicts): byteify(value, ignore_dicts=ignore_dicts)
86 for key, value in data.iteritems()}
87 # if it's anything else, return it in its original form
91 def dict_to_json_dict(record):
92 return json.loads(json.dumps(record, default=lambda obj: obj.to_json()))
95 def get_intel_pci(nic_ports):
96 """Returns the first two PCI addresses of sorted PCI list for Intel NIC (i40e, ixgbe)"""
98 regex = r'({hx}{{4}}:({hx}{{2}}:{hx}{{2}}\.{hx}{{1}})).*(drv={driver}|.*unused=.*{driver})'
102 trex_base_dir = '/opt/trex'
103 contents = os.listdir(trex_base_dir)
104 trex_dir = os.path.join(trex_base_dir, contents[0])
105 process = subprocess.Popen(['python', 'dpdk_setup_ports.py', '-s'],
107 stdout=subprocess.PIPE,
108 stderr=subprocess.PIPE)
109 devices, _ = process.communicate()
113 for driver in ['i40e', 'ixgbe']:
114 matches = re.findall(regex.format(hx=hx, driver=driver), devices)
120 if max(nic_ports) > len(matches) - 1:
121 # If this is hard requirements (i.e. ports are defined
122 # explictly), but there are not enough ports for the
123 # current NIC, just skip the current NIC and looking for
124 # next available one.
127 return [matches[idx][1] for idx in nic_ports]
130 intf_name = glob.glob("/sys/bus/pci/devices/%s/net/*" % port[0])
132 # Interface is not bind to kernel driver, so take it
135 intf_name = intf_name[0][intf_name[0].rfind('/') + 1:]
136 process = subprocess.Popen(['ip', '-o', '-d', 'link', 'show', intf_name],
137 stdout=subprocess.PIPE,
138 stderr=subprocess.PIPE)
139 intf_info, _ = process.communicate()
140 if not re.search('team_slave|bond_slave', intf_info):
156 def parse_flow_count(flow_count):
157 flow_count = str(flow_count)
158 input_fc = flow_count
160 if flow_count[-1].upper() in multiplier_map:
161 multiplier = multiplier_map[flow_count[-1].upper()]
162 flow_count = flow_count[:-1]
165 flow_count = int(flow_count)
167 raise Exception("Unknown flow count format '{}'".format(input_fc))
169 return flow_count * multiplier
172 def cast_integer(value):
173 return int(value) if not isnan(value) else value
176 class RunLock(object):
178 Attempts to lock file and run current instance of NFVbench as the first,
179 otherwise raises exception.
182 def __init__(self, path='/tmp/nfvbench.lock'):
188 self._fd = os.open(self._path, os.O_CREAT)
189 fcntl.flock(self._fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
190 except (OSError, IOError):
191 raise Exception('Other NFVbench process is running. Please wait')
193 def __exit__(self, *args):
194 fcntl.flock(self._fd, fcntl.LOCK_UN)
198 # Try to remove the lock file, but don't try too hard because it is unnecessary.
200 os.unlink(self._path)
201 except (OSError, IOError):