Add support for SRIOV NIC
Change-Id: I706b1bae8afb2e83c6a71e3396124f32a11fdb1f
This commit is contained in:
parent
b276f864ec
commit
a83508a4c4
30
compute.py
30
compute.py
@ -142,12 +142,16 @@ class Compute(object):
|
||||
return net
|
||||
|
||||
# Create a server instance with name vmname
|
||||
# if exists delete and recreate
|
||||
# and check that it gets into the ACTIVE state
|
||||
def create_server(self, vmname, image, flavor, key_name,
|
||||
nic, sec_group, avail_zone=None, user_data=None,
|
||||
config_drive=None,
|
||||
retry_count=10):
|
||||
|
||||
if sec_group:
|
||||
security_groups = [sec_group.id]
|
||||
else:
|
||||
security_groups = None
|
||||
# Also attach the created security group for the test
|
||||
instance = self.novaclient.servers.create(name=vmname,
|
||||
image=image,
|
||||
@ -157,12 +161,26 @@ class Compute(object):
|
||||
availability_zone=avail_zone,
|
||||
userdata=user_data,
|
||||
config_drive=config_drive,
|
||||
security_groups=[sec_group.id])
|
||||
flag_exist = self.find_server(vmname, retry_count)
|
||||
if flag_exist:
|
||||
return instance
|
||||
else:
|
||||
security_groups=security_groups)
|
||||
if not instance:
|
||||
return None
|
||||
# Verify that the instance gets into the ACTIVE state
|
||||
for retry_attempt in range(retry_count):
|
||||
instance = self.novaclient.servers.get(instance.id)
|
||||
if instance.status == 'ACTIVE':
|
||||
return instance
|
||||
if instance.status == 'ERROR':
|
||||
print 'Instance creation error:' + instance.fault['message']
|
||||
break
|
||||
if self.config.debug:
|
||||
print "[%s] VM status=%s, retrying %s of %s..." \
|
||||
% (vmname, instance.status, (retry_attempt + 1), retry_count)
|
||||
time.sleep(2)
|
||||
|
||||
# instance not in ACTIVE state
|
||||
print('Instance failed status=' + instance.status)
|
||||
self.delete_server(instance)
|
||||
return None
|
||||
|
||||
def get_server_list(self):
|
||||
servers_list = self.novaclient.servers.list()
|
||||
|
@ -13,15 +13,16 @@ VMTP Usage
|
||||
[--external-host <user>@<host_ssh_ip>[:password>]]
|
||||
[--controller-node <user>@<host_ssh_ip>[:<password>]]
|
||||
[--mongod_server <server ip>] [--json <file>]
|
||||
[--tp-tool nuttcp|iperf] [--hypervisor [<az>:] <hostname>]
|
||||
[--inter-node-only] [--protocols T|U|I]
|
||||
[--tp-tool <nuttcp|iperf>] [--hypervisor [<az>:] <hostname>]
|
||||
[--inter-node-only] [--protocols <T|U|I>]
|
||||
[--bandwidth <bandwidth>] [--tcpbuf <tcp_pkt_size1,...>]
|
||||
[--udpbuf <udp_pkt_size1,...>] [--no-env] [-d] [-v]
|
||||
[--udpbuf <udp_pkt_size1,...>] [--no-env]
|
||||
[--vnic-type <direct|macvtap|normal>] [-d] [-v]
|
||||
[--stop-on-error] [--vm_image_url <url_to_image>]
|
||||
[--test_description <test_description>]
|
||||
|
||||
OpenStack VM Throughput V2.0.2
|
||||
|
||||
|
||||
OpenStack VM Throughput V2.0.3
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
-c <config_file>, --config <config_file>
|
||||
@ -45,12 +46,12 @@ VMTP Usage
|
||||
--mongod_server <server ip>
|
||||
provide mongoDB server IP to store results
|
||||
--json <file> store results in json format file
|
||||
--tp-tool nuttcp|iperf
|
||||
--tp-tool <nuttcp|iperf>
|
||||
transport perf tool to use (default=nuttcp)
|
||||
--hypervisor [<az>:] <hostname>
|
||||
hypervisor to use (1 per arg, up to 2 args)
|
||||
--inter-node-only only measure inter-node
|
||||
--protocols T|U|I protocols T(TCP), U(UDP), I(ICMP) - default=TUI (all)
|
||||
--protocols <T|U|I> protocols T(TCP), U(UDP), I(ICMP) - default=TUI (all)
|
||||
--bandwidth <bandwidth>
|
||||
the bandwidth limit for TCP/UDP flows in K/M/Gbps,
|
||||
e.g. 128K/32M/5G. (default=no limit)
|
||||
@ -61,6 +62,8 @@ VMTP Usage
|
||||
list of buffer length when transmitting over UDP in
|
||||
Bytes, e.g. --udpbuf 128,2048. (default=128,1024,8192)
|
||||
--no-env do not read env variables
|
||||
--vnic-type <direct|macvtap|normal>
|
||||
binding vnic type for test VMs
|
||||
-d, --debug debug flag (very verbose)
|
||||
-v, --version print version of this script and exit
|
||||
--stop-on-error Stop and keep everything as-is on error (must cleanup
|
||||
@ -71,7 +74,6 @@ VMTP Usage
|
||||
--test_description <test_description>
|
||||
The test description to be stored in JSON or MongoDB
|
||||
|
||||
|
||||
Configuration File
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@ -138,6 +140,12 @@ There is a candidate image defined in the default config already. It has been ve
|
||||
|
||||
**Note:** Due to the limitation of the Python glanceclient API (v2.0), it is not able to create the image directly from a remote URL. So the implementation of this feature used a glance CLI command instead. Be sure to source the OpenStack rc file first before running VMTP with this feature.
|
||||
|
||||
VNIC Type
|
||||
^^^^^^^^^
|
||||
|
||||
By default test VMs will be created with ports that have a "normal" VNIC type.
|
||||
To create test VMs with ports that use PCI passthrough SRIOV, specify "--vnic_type direct". This will assume that the host where the VM are instantiated have SRIOV capable NIC.
|
||||
An exception will be thrown if a test VM is lauched on a host that does not have SRIOV capable NIC or has not been configured to use such feature.
|
||||
|
||||
Quick guide to run VMTP on an OpenStack Cloud
|
||||
----------------------------------------------
|
||||
|
21
instance.py
21
instance.py
@ -49,6 +49,7 @@ class Instance(object):
|
||||
self.ssh_user = config.ssh_vm_username
|
||||
self.instance = None
|
||||
self.ssh = None
|
||||
self.port = None
|
||||
if config.gmond_svr_ip:
|
||||
self.gmond_svr = config.gmond_svr_ip
|
||||
else:
|
||||
@ -75,7 +76,7 @@ class Instance(object):
|
||||
# and extract internal network IP
|
||||
# Retruns True if success, False otherwise
|
||||
def create(self, image, flavor_type,
|
||||
keypair, nics,
|
||||
keypair, int_net,
|
||||
az,
|
||||
internal_network_name,
|
||||
sec_group,
|
||||
@ -90,6 +91,20 @@ class Instance(object):
|
||||
user_data = open(init_file_name)
|
||||
else:
|
||||
user_data = None
|
||||
|
||||
if self.config.vnic_type:
|
||||
# create the VM by passing a port ID instead of a net ID
|
||||
self.port = self.net.create_port(int_net['id'],
|
||||
[sec_group.id],
|
||||
self.config.vnic_type)
|
||||
nics = [{'port-id': self.port['id']}]
|
||||
# no need to create server with a security group since
|
||||
# we already have the port created with it
|
||||
sec_group = None
|
||||
else:
|
||||
# create the VM by passing a net ID
|
||||
nics = [{'net-id': int_net['id']}]
|
||||
|
||||
self.instance = self.comp.create_server(self.name,
|
||||
image,
|
||||
flavor_type,
|
||||
@ -104,7 +119,6 @@ class Instance(object):
|
||||
user_data.close()
|
||||
if not self.instance:
|
||||
self.display('Server creation failed')
|
||||
self.dispose()
|
||||
return False
|
||||
|
||||
# If reusing existing management network skip the floating ip creation and association to VM
|
||||
@ -134,6 +148,7 @@ class Instance(object):
|
||||
self.buginf('Floating IP %s created', self.ssh_ip)
|
||||
self.buginf('Started - associating floating IP %s', self.ssh_ip)
|
||||
self.instance.add_floating_ip(self.ssh_ip, ipv4_fixed_address)
|
||||
|
||||
# extract the IP for the data network
|
||||
self.buginf('Internal network IP: %s', self.internal_ip)
|
||||
self.buginf('SSH IP: %s', self.ssh_ip)
|
||||
@ -295,6 +310,8 @@ class Instance(object):
|
||||
self.comp.delete_server(self.instance)
|
||||
self.buginf('Instance deleted')
|
||||
self.instance = None
|
||||
if self.port:
|
||||
self.net.delete_port(self.port)
|
||||
if self.ssh:
|
||||
self.ssh.close()
|
||||
self.ssh = None
|
||||
|
20
network.py
20
network.py
@ -284,6 +284,26 @@ class Network(object):
|
||||
router = self.neutron_client.update_router(router_id, body)
|
||||
return router['router']
|
||||
|
||||
# Create a port
|
||||
def create_port(self, net_id, sec_group_list, vnic_type):
|
||||
body = {
|
||||
"port": {
|
||||
"network_id": net_id,
|
||||
"security_groups": sec_group_list
|
||||
}
|
||||
}
|
||||
if vnic_type:
|
||||
body['port']['binding:vnic_type'] = vnic_type
|
||||
port = self.neutron_client.create_port(body)
|
||||
if self.config.debug:
|
||||
print 'Created port ' + port['port']['id']
|
||||
return port['port']
|
||||
|
||||
def delete_port(self, port):
|
||||
if self.config.debug:
|
||||
print 'Deleting port ' + port['id']
|
||||
self.neutron_client.delete_port(port['id'])
|
||||
|
||||
# Create a floating ip on the external network and return it
|
||||
def create_floating_ip(self):
|
||||
body = {
|
||||
|
30
vmtp.py
30
vmtp.py
@ -40,7 +40,7 @@ from neutronclient.v2_0 import client as neutronclient
|
||||
from novaclient.client import Client
|
||||
from novaclient.exceptions import ClientException
|
||||
|
||||
__version__ = '2.0.2'
|
||||
__version__ = '2.0.3'
|
||||
|
||||
from perf_instance import PerfInstance as PerfInstance
|
||||
|
||||
@ -201,11 +201,10 @@ class VmtpTest(object):
|
||||
|
||||
# Create an instance on a particular availability zone
|
||||
def create_instance(self, inst, az, int_net):
|
||||
nics = [{'net-id': int_net['id']}]
|
||||
self.assert_true(inst.create(self.image_instance,
|
||||
self.flavor_type,
|
||||
config.public_key_name,
|
||||
nics,
|
||||
int_net,
|
||||
az,
|
||||
int_net['name'],
|
||||
self.sec_group))
|
||||
@ -223,7 +222,6 @@ class VmtpTest(object):
|
||||
nova_client = Client(**creds_nova)
|
||||
neutron = neutronclient.Client(**creds)
|
||||
|
||||
|
||||
self.comp = compute.Compute(nova_client, config)
|
||||
# Add the script public key to openstack
|
||||
self.comp.add_public_key(config.public_key_name,
|
||||
@ -419,7 +417,8 @@ class VmtpTest(object):
|
||||
self.comp.remove_public_key(config.public_key_name)
|
||||
# Finally remove the security group
|
||||
try:
|
||||
self.comp.security_group_delete(self.sec_group)
|
||||
if self.comp:
|
||||
self.comp.security_group_delete(self.sec_group)
|
||||
except ClientException:
|
||||
# May throw novaclient.exceptions.BadRequest if in use
|
||||
print('Security group in use: not deleted')
|
||||
@ -432,8 +431,9 @@ class VmtpTest(object):
|
||||
self.measure_vm_flows()
|
||||
except KeyboardInterrupt:
|
||||
traceback.format_exc()
|
||||
except (VmtpException, sshutils.SSHError, ClientException):
|
||||
traceback.format_exc()
|
||||
except (VmtpException, sshutils.SSHError, ClientException, Exception):
|
||||
print 'print_exc:'
|
||||
traceback.print_exc()
|
||||
error_flag = True
|
||||
|
||||
if opts.stop_on_error and error_flag:
|
||||
@ -572,7 +572,7 @@ if __name__ == '__main__':
|
||||
action='store',
|
||||
default='nuttcp',
|
||||
help='transport perf tool to use (default=nuttcp)',
|
||||
metavar='nuttcp|iperf')
|
||||
metavar='<nuttcp|iperf>')
|
||||
|
||||
# note there is a bug in argparse that causes an AssertionError
|
||||
# when the metavar is set to '[<az>:]<hostname>', hence had to insert a space
|
||||
@ -590,7 +590,7 @@ if __name__ == '__main__':
|
||||
action='store',
|
||||
default='TUI',
|
||||
help='protocols T(TCP), U(UDP), I(ICMP) - default=TUI (all)',
|
||||
metavar='T|U|I')
|
||||
metavar='<T|U|I>')
|
||||
|
||||
parser.add_argument('--bandwidth', dest='vm_bandwidth',
|
||||
action='store',
|
||||
@ -618,6 +618,12 @@ if __name__ == '__main__':
|
||||
action='store_true',
|
||||
help='do not read env variables')
|
||||
|
||||
parser.add_argument('--vnic-type', dest='vnic_type',
|
||||
default=None,
|
||||
action='store',
|
||||
help='binding vnic type for test VMs',
|
||||
metavar='<direct|macvtap|normal>')
|
||||
|
||||
parser.add_argument('-d', '--debug', dest='debug',
|
||||
default=False,
|
||||
action='store_true',
|
||||
@ -662,6 +668,12 @@ if __name__ == '__main__':
|
||||
config.debug = opts.debug
|
||||
config.inter_node_only = opts.inter_node_only
|
||||
|
||||
# direct: use SR-IOV ports for all the test VMs
|
||||
if opts.vnic_type not in [None, 'direct', 'macvtap', 'normal']:
|
||||
print('Invalid vnic-type: ' + opts.vnic_type)
|
||||
sys.exit(1)
|
||||
config.vnic_type = opts.vnic_type
|
||||
|
||||
config.hypervisors = opts.hypervisors
|
||||
|
||||
# time to run each perf test in seconds
|
||||
|
Loading…
Reference in New Issue
Block a user