Add support for SRIOV NIC

Change-Id: I706b1bae8afb2e83c6a71e3396124f32a11fdb1f
This commit is contained in:
ahothan 2015-03-11 16:56:44 -07:00
parent b276f864ec
commit a83508a4c4
5 changed files with 101 additions and 26 deletions

View File

@ -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()

View File

@ -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
----------------------------------------------

View File

@ -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

View File

@ -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
View File

@ -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