1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
|
# BSD LICENSE
#
# Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Intel Corporation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import os
import re
import time
import utils
import settings
from config import PortConf
from settings import NICS, LOG_NAME_SEP, get_netdev
from project_dpdk import DPDKdut
from dut import Dut
from net_device import GetNicObj
from net_device import RemoveNicObj
class VirtDut(DPDKdut):
"""
A connection to the CRB under test.
This class sends commands to the CRB and validates the responses. It is
implemented using either ssh for linuxapp or the terminal server for
baremetal.
All operations are in fact delegated to an instance of either CRBLinuxApp
or CRBBareMetal.
"""
def __init__(self, hyper, crb, serializer, virttype, vm_name, suite, cpu_topo):
self.vm_name = vm_name
self.hyper = hyper
self.cpu_topo = cpu_topo
self.vm_ip = crb['IP']
self.NAME = 'virtdut' + LOG_NAME_SEP + '%s' % self.vm_ip
super(Dut, self).__init__(crb, serializer, self.NAME)
# load port config from suite cfg
self.suite = suite
self.number_of_cores = 0
self.tester = None
self.cores = []
self.architecture = None
self.ports_info = None
self.ports_map = []
self.virttype = virttype
def init_log(self):
self.logger.config_suite(self.host_dut.test_classname, 'virtdut')
def close(self, force=False):
if self.session:
self.session.close(force)
self.session = None
if self.alt_session:
self.alt_session.close(force)
self.alt_session = None
RemoveNicObj(self)
def set_nic_type(self, nic_type):
"""
Set CRB NICS ready to validated.
"""
self.nic_type = nic_type
# vm_dut config will load from vm configuration file
def load_portconf(self):
"""
Load port config for this virtual machine
"""
self.conf = PortConf()
self.conf.load_ports_config(self.vm_name)
self.ports_cfg = self.conf.get_ports_config()
return
def create_portmap(self):
# if not config ports in vm port config file, used ping6 get portmap
if not self.ports_cfg:
self.map_available_ports()
port_num = len(self.ports_info)
self.ports_map = [-1] * port_num
for key in self.ports_cfg.keys():
index = int(key)
if index >= port_num:
print utils.RED("Can not found [%d ]port info" % index)
continue
if 'peer' in self.ports_cfg[key].keys():
tester_pci = self.ports_cfg[key]['peer']
# find tester_pci index
pci_idx = self.tester.get_local_index(tester_pci)
self.ports_map[index] = pci_idx
def set_target(self, target, bind_dev=True):
"""
Set env variable, these have to be setup all the time. Some tests
need to compile example apps by themselves and will fail otherwise.
Set hugepage on DUT and install modules required by DPDK.
Configure default ixgbe PMD function.
"""
self.set_toolchain(target)
# set env variable
# These have to be setup all the time. Some tests need to compile
# example apps by themselves and will fail otherwise.
self.send_expect("export RTE_TARGET=" + target, "#")
self.send_expect("export RTE_SDK=`pwd`", "#")
if not self.skip_setup:
self.build_install_dpdk(target)
self.setup_memory(hugepages=1024)
self.setup_modules(target)
if bind_dev:
self.bind_interfaces_linux('igb_uio')
def prerequisites(self, pkgName, patch):
"""
Prerequest function should be called before execute any test case.
Will call function to scan all lcore's information which on DUT.
Then call pci scan function to collect nic device information.
At last setup DUT' environment for validation.
"""
if not self.skip_setup:
self.prepare_package()
self.send_expect("cd %s" % self.base_dir, "# ")
self.send_expect("alias ls='ls --color=none'", "#")
if self.get_os_type() == 'freebsd':
self.send_expect('alias make=gmake', '# ')
self.send_expect('alias sed=gsed', '# ')
self.init_core_list()
self.pci_devices_information()
# scan ports before restore interface
self.scan_ports()
# update with real numa id
self.update_ports()
# restore dut ports to kernel
if self.virttype != 'XEN':
self.restore_interfaces()
else:
self.restore_interfaces_domu()
# rescan ports after interface up
self.rescan_ports()
# no need to rescan ports for guest os just bootup
# load port infor from config file
self.load_portconf()
# enable tester port ipv6
self.host_dut.enable_tester_ipv6()
self.mount_procfs()
self.create_portmap()
# disable tester port ipv6
self.host_dut.disable_tester_ipv6()
# print latest ports_info
for port_info in self.ports_info:
self.logger.info(port_info)
def init_core_list(self):
self.cores = []
cpuinfo = self.send_expect("grep --color=never \"processor\""
" /proc/cpuinfo", "#", alt_session=False)
cpuinfo = cpuinfo.split('\r\n')
if self.cpu_topo != '':
topo_reg = r"(\d)S/(\d)C/(\d)T"
m = re.match(topo_reg, self.cpu_topo)
if m:
socks = int(m.group(1))
cores = int(m.group(2))
threads = int(m.group(3))
total = socks * cores * threads
cores_persock = cores * threads
total_phycores = socks * cores
# cores should match cpu_topo
if total != len(cpuinfo):
print utils.RED("Core number not matched!!!")
else:
for core in range(total):
thread = core / total_phycores
phy_core = core % total_phycores
# if this core is hyper core
if thread:
idx = core % total_phycores
socket = idx / cores
else:
socket = core / cores
# tricky here, socket must be string
self.cores.append({'thread': core,
'socket': str(socket),
'core': phy_core})
self.number_of_cores = len(self.cores)
return
# default core map
for line in cpuinfo:
m = re.search("processor\t: (\d+)", line)
if m:
thread = m.group(1)
socket = 0
core = thread
self.cores.append(
{'thread': thread, 'socket': socket, 'core': core})
self.number_of_cores = len(self.cores)
def restore_interfaces_domu(self):
"""
Restore Linux interfaces.
"""
for port in self.ports_info:
pci_bus = port['pci']
pci_id = port['type']
driver = settings.get_nic_driver(pci_id)
if driver is not None:
addr_array = pci_bus.split(':')
domain_id = addr_array[0]
bus_id = addr_array[1]
devfun_id = addr_array[2]
port = GetNicObj(self, domain_id, bus_id, devfun_id)
itf = port.get_interface_name()
self.send_expect("ifconfig %s up" % itf, "# ")
time.sleep(30)
print self.send_expect("ip link ls %s" % itf, "# ")
else:
self.logger.info(
"NOT FOUND DRIVER FOR PORT (%s|%s)!!!" % (pci_bus, pci_id))
def pci_devices_information(self):
self.pci_devices_information_uncached()
def get_memory_channels(self):
"""
Virtual machine has no memory channel concept, so always return 1
"""
return 1
def check_ports_available(self, pci_bus, pci_id):
"""
Check that whether auto scanned ports ready to use
"""
pci_addr = "%s:%s" % (pci_bus, pci_id)
if pci_id == "8086:100e":
return False
return True
# load vm port conf need another function
# need add vitrual function device into NICS
def scan_ports(self):
"""
Scan ports information, for vm will always scan
"""
self.scan_ports_uncached()
def scan_ports_uncached(self):
"""
Scan ports and collect port's pci id, mac adress, ipv6 address.
"""
scan_ports_uncached = getattr(
self, 'scan_ports_uncached_%s' % self.get_os_type())
return scan_ports_uncached()
def update_ports(self):
"""
Update ports information, according to host pci
"""
for port in self.ports_info:
vmpci = port['pci']
for pci_map in self.hyper.pci_maps:
# search pci mapping strucutre
if vmpci == pci_map['guestpci']:
hostpci = pci_map['hostpci']
# search host port info structure
for hostport in self.host_dut.ports_info:
# update port numa
if hostpci == hostport['pci']:
port['numa'] = hostport['numa']
port['port'].socket = hostport['numa']
break
if 'sriov_vfs_pci' in hostport and \
hostpci in hostport['sriov_vfs_pci']:
port['numa'] = hostport['numa']
port['port'].socket = hostport['numa']
break
def map_available_ports(self):
"""
Load or generate network connection mapping list.
"""
self.map_available_ports_uncached()
self.logger.warning("VM DUT PORT MAP: " + str(self.ports_map))
def map_available_ports_uncached(self):
"""
Generate network connection mapping list.
"""
nrPorts = len(self.ports_info)
if nrPorts == 0:
return
remove = []
self.ports_map = [-1] * nrPorts
hits = [False] * len(self.tester.ports_info)
for vmPort in range(nrPorts):
vmpci = self.ports_info[vmPort]['pci']
peer = self.get_peer_pci(vmPort)
# if peer pci configured
if peer is not None:
for remotePort in range(len(self.tester.ports_info)):
if self.tester.ports_info[remotePort]['pci'] == peer:
hits[remotePort] = True
self.ports_map[vmPort] = remotePort
break
if self.ports_map[vmPort] == -1:
self.logger.error("CONFIGURED TESTER PORT CANNOT FOUND!!!")
else:
continue # skip ping6 map
# strip pci address on host for pass-through device
hostpci = 'N/A'
for pci_map in self.hyper.pci_maps:
if vmpci == pci_map['guestpci']:
hostpci = pci_map['hostpci']
break
# auto ping port map
for remotePort in range(len(self.tester.ports_info)):
# for two vfs connected to same tester port
# need skip ping from devices on same pf device
remotepci = self.tester.ports_info[remotePort]['pci']
port_type = self.tester.ports_info[remotePort]['type']
# IXIA port should not check whether has vfs
if port_type != 'ixia':
remoteport = self.tester.ports_info[remotePort]['port']
vfs = []
# vm_dut and tester in same dut
host_ip = self.crb['IP'].split(':')[0]
if self.crb['tester IP'] == host_ip:
vfs = remoteport.get_sriov_vfs_pci()
# if hostpci is vf of tester port
if hostpci == remotepci or hostpci in vfs:
print utils.RED("Skip ping from same PF device")
continue
ipv6 = self.get_ipv6_address(vmPort)
if ipv6 == "Not connected":
continue
out = self.tester.send_ping6(
remotePort, ipv6, self.get_mac_address(vmPort))
if ('64 bytes from' in out):
self.logger.info(
"PORT MAP: [dut %d: tester %d]" % (vmPort, remotePort))
self.ports_map[vmPort] = remotePort
hits[remotePort] = True
continue
|