1 # Copyright 2017-2018 Spirent Communications.
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.
16 Perform L3-cache allocations for different workloads- VNFs, PMDs, vSwitch etc.
17 based on the user-defined policies. This is done using Intel-RMD.
18 Details about RMD can be found in: https://github.com/intel/rmd
28 from collections import defaultdict
29 from stcrestclient import resthttp
30 from conf import settings as S
33 DEFAULT_SERVER = '127.0.0.1'
34 DEFAULT_VERSION = 'v1'
37 def cpumask2coreids(mask):
39 Convert CPU mask in hex-string to list of core-IDs
41 intmask = int(mask, 16)
46 coreids.append(str(math.frexp(i)[1] - 1))
51 def get_cos(category):
53 Obtain the Classof service for a particular category
55 return S.getValue(category.upper() + '_COS')
58 def get_minmax(category):
60 Obtain the min-max values for a particular category
62 return S.getValue(category.upper() + '_CA')
65 def guest_vm_settings_expanded(cores):
67 Check if are running pv+p mode
70 if isinstance(core, str) and '#' in core:
75 class IrmdHttp(object):
77 Intel RMD ReST API wrapper object
80 def __init__(self, server=None, port=None, api_version=None):
82 server = DEFAULT_SERVER
86 api_version = DEFAULT_VERSION
87 url = resthttp.RestHttp.url('http', server, port, api_version)
88 rest = resthttp.RestHttp(url, None, None, False, True)
90 rest.get_request('workloads')
91 except (socket.error, resthttp.ConnectionError,
92 resthttp.RestHttpError):
93 raise RuntimeError('Cannot connect to RMD server: %s:%s' %
97 self._logger = logging.getLogger(__name__)
99 def setup_cacheways(self, affinity_map):
101 Sets up the cacheways using RMD apis.
103 for cos_cat in affinity_map:
104 if S.getValue('POLICY_TYPE') == 'COS':
105 params = {'core_ids': affinity_map[cos_cat],
106 'policy': get_cos(cos_cat)}
108 minmax = get_minmax(cos_cat)
111 params = {'core_ids': affinity_map[cos_cat],
112 'min_cache': minmax[0],
113 'max_cache': minmax[1]}
115 _, data = self._rest.post_request('workloads', None,
119 self.workloadids.append(wl_id)
121 except resthttp.RestHttpError as exp:
122 if str(exp).find('already exists') >= 0:
123 raise RuntimeError("The cacheway already exist")
125 raise RuntimeError('Failed to connect: ' + str(exp))
127 def reset_all_cacheways(self):
132 for wl_id in self.workloadids:
133 self._rest.delete_request('workloads', str(wl_id))
134 except resthttp.RestHttpError as ecp:
135 raise RuntimeError('Failed to connect: ' + str(ecp))
137 def log_allocations(self):
139 Log the current cacheway settings.
142 _, data = self._rest.get_request('workloads')
143 self._logger.info("Current Allocations: %s",
144 json.dumps(data, indent=4, sort_keys=True))
145 except resthttp.RestHttpError as ecp:
146 raise RuntimeError('Failed to connect: ' + str(ecp))
149 class CacheAllocator(object):
151 This class exposes APIs for VSPERF to perform
152 Cache-allocation management operations.
156 port = S.getValue('RMD_PORT')
157 api_version = S.getValue('RMD_API_VERSION')
158 server_ip = S.getValue('RMD_SERVER_IP')
159 self.irmd_manager = IrmdHttp(str(server_ip), str(port),
162 def setup_llc_allocation(self):
164 Wrapper for settingup cacheways
166 cpumap = defaultdict(list)
167 vswitchmask = S.getValue('VSWITCHD_DPDK_CONFIG')['dpdk-lcore-mask']
168 vnfcores = list(itertools.chain.from_iterable(
169 S.getValue('GUEST_CORE_BINDING')))
170 if not guest_vm_settings_expanded(vnfcores):
173 if S.getValue('LOADGEN') == 'StressorVM':
174 nncores = list(itertools.chain.from_iterable(
175 S.getValue('NN_CORE_BINDING')))
176 pmdcores = cpumask2coreids(S.getValue('VSWITCH_PMD_CPU_MASK'))
177 vswitchcores = cpumask2coreids(vswitchmask)
179 cpumap['vswitch'] = vswitchcores
181 cpumap['vnf'] = vnfcores
183 cpumap['pmd'] = pmdcores
185 cpumap['noisevm'] = nncores
186 self.irmd_manager.setup_cacheways(cpumap)
188 def cleanup_llc_allocation(self):
190 Wrapper for cacheway cleanup
192 self.irmd_manager.reset_all_cacheways()
194 def log_allocations(self):
196 Wrapper for logging cacheway allocations
198 self.irmd_manager.log_allocations()