IPV6 changes for VMTP
Change-Id: I4958a119ff9dff661fb04f1973d76c4c3ee645f8
This commit is contained in:
parent
cfb6c1fc19
commit
411e3dac2e
@ -68,6 +68,14 @@ reuse_existing_vm :
|
||||
# An option of config_drive to True is provided to nova boot to enable this
|
||||
config_drive:
|
||||
|
||||
# ipv6 mode. Set this to one of the following 3 modes
|
||||
# slaac : VM obtains IPV6 address from Openstack radvd using SLAAC
|
||||
# dhcpv6-stateful : VM obtains ipv6 address from dnsmasq using DHCPv6 stateful
|
||||
# dhcpv6-stateless : VM obtains ipv6 address from Openstack radvd using SLAAC and options from dnsmasq
|
||||
# If left blank use ipv4
|
||||
ipv6_mode:
|
||||
|
||||
|
||||
# Default name for the router to use to connect the internal mgmt network
|
||||
# with the external network. If a router exists with this name it will be
|
||||
# reused, otherwise a new router will be created
|
||||
@ -82,9 +90,15 @@ internal_network_name: ['pns-internal-net', 'pns-internal-net2']
|
||||
# Name of the subnets associated to the internal mgmt network
|
||||
internal_subnet_name: ['pns-internal-subnet', 'pns-internal-subnet2']
|
||||
|
||||
# Name of the subnets for ipv6
|
||||
internal_subnet_name_ipv6: ['pns-internal-v6-subnet','pns-internal-v6-subnet2']
|
||||
|
||||
# Default CIDRs to use for the internal mgmt subnet
|
||||
internal_cidr: ['192.168.1.0/24' , '192.168.2.0/24']
|
||||
|
||||
# Default CIDRs to use for data network for ipv6
|
||||
internal_cidr_v6: ['2001:45::/64','2001:46::/64']
|
||||
|
||||
# The public key to use to ssh to all targets (VMs, containers, hosts)
|
||||
# If starting with './' is relative to the location of the VMTP script
|
||||
# else can be an absolute path
|
||||
|
35
compute.py
35
compute.py
@ -395,6 +395,12 @@ class Compute(object):
|
||||
ip_protocol="icmp",
|
||||
from_port=-1,
|
||||
to_port=-1)
|
||||
if self.config.ipv6_mode:
|
||||
self.novaclient.security_group_rules.create(group.id,
|
||||
ip_protocol="icmp",
|
||||
from_port=-1,
|
||||
to_port=-1,
|
||||
cidr="::/0")
|
||||
# Allow SSH traffic
|
||||
self.novaclient.security_group_rules.create(group.id,
|
||||
ip_protocol="tcp",
|
||||
@ -404,11 +410,24 @@ class Compute(object):
|
||||
# 5001: Data traffic (standard iperf data port)
|
||||
# 5002: Control traffic (non standard)
|
||||
# note that 5000/tcp is already picked by openstack keystone
|
||||
self.novaclient.security_group_rules.create(group.id,
|
||||
ip_protocol="tcp",
|
||||
from_port=5001,
|
||||
to_port=5002)
|
||||
self.novaclient.security_group_rules.create(group.id,
|
||||
ip_protocol="udp",
|
||||
from_port=5001,
|
||||
to_port=5001)
|
||||
if not self.config.ipv6_mode:
|
||||
self.novaclient.security_group_rules.create(group.id,
|
||||
ip_protocol="tcp",
|
||||
from_port=5001,
|
||||
to_port=5002)
|
||||
self.novaclient.security_group_rules.create(group.id,
|
||||
ip_protocol="udp",
|
||||
from_port=5001,
|
||||
to_port=5001)
|
||||
else:
|
||||
# IPV6 rules addition
|
||||
self.novaclient.security_group_rules.create(group.id,
|
||||
ip_protocol="tcp",
|
||||
from_port=5001,
|
||||
to_port=5002,
|
||||
cidr="::/0")
|
||||
self.novaclient.security_group_rules.create(group.id,
|
||||
ip_protocol="udp",
|
||||
from_port=5001,
|
||||
to_port=5001,
|
||||
cidr="::/0")
|
||||
|
@ -241,3 +241,14 @@ The first IP passed (*--host*) is always the one running the server side. Option
|
||||
|
||||
**Note:** Prior to running, the VMTP public key must be installed on each VM.
|
||||
|
||||
Example 7: IPV6 throughput measurement
|
||||
""""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
It is possible to use VMTP to measure throughput for ipv6
|
||||
|
||||
Set ipv6_mode to slaac, dhcpv6-stateful or dhcpv6-stateless. If SLAAC or DHCPv6 stateless is enabled make sure to have
|
||||
radvd packaged in as part of openstack install. For DHCPv6 stateful you need dnsmasq version >= 2.68. The test creates
|
||||
2 networks and creates 1 ipv4 and 1 ipv6 subnet inside each of these networks. The subnets are created based on the ipv6
|
||||
mode that you set in the configuration file. The floatingip result case is skipped for ipv6 since there is no concept of
|
||||
a floating ip with ipv6.
|
||||
|
||||
|
19
instance.py
19
instance.py
@ -18,9 +18,12 @@ import re
|
||||
import stat
|
||||
import subprocess
|
||||
|
||||
|
||||
import monitor
|
||||
import sshutils
|
||||
|
||||
|
||||
from netaddr import IPAddress
|
||||
# a dictionary of sequence number indexed by a name prefix
|
||||
prefix_seq = {}
|
||||
|
||||
@ -108,7 +111,20 @@ class Instance(object):
|
||||
# Assume management network has direct access
|
||||
if self.config.reuse_network_name:
|
||||
self.ssh_ip = self.instance.networks[internal_network_name][0]
|
||||
self.internal_ip = self.ssh_ip
|
||||
else:
|
||||
# Set the internal ip to the correct ip for v4 and v6
|
||||
for ip_address in self.instance.networks[internal_network_name]:
|
||||
ip = IPAddress(ip_address)
|
||||
if self.config.ipv6_mode:
|
||||
if ip.version == 6:
|
||||
self.internal_ip = ip_address
|
||||
else:
|
||||
ipv4_fixed_address = ip_address
|
||||
else:
|
||||
if ip.version == 4:
|
||||
self.internal_ip = ip_address
|
||||
ipv4_fixed_address = ip_address
|
||||
fip = self.net.create_floating_ip()
|
||||
if not fip:
|
||||
self.display('Floating ip creation failed')
|
||||
@ -117,9 +133,8 @@ class Instance(object):
|
||||
self.ssh_ip_id = fip['floatingip']['id']
|
||||
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)
|
||||
self.instance.add_floating_ip(self.ssh_ip, ipv4_fixed_address)
|
||||
# extract the IP for the data network
|
||||
self.internal_ip = self.instance.networks[internal_network_name][0]
|
||||
self.buginf('Internal network IP: %s', self.internal_ip)
|
||||
self.buginf('SSH IP: %s', self.ssh_ip)
|
||||
|
||||
|
62
network.py
62
network.py
@ -40,6 +40,8 @@ class Network(object):
|
||||
# - second for network to network communication
|
||||
self.vm_int_net = []
|
||||
self.ext_router_name = None
|
||||
# Store state if the network is ipv4/ipv6 dual stack
|
||||
self.ipv6_enabled = False
|
||||
|
||||
# If reusing existing management network just find this network
|
||||
if self.config.reuse_network_name:
|
||||
@ -94,13 +96,27 @@ class Network(object):
|
||||
print '[%s] Created ext router' % (self.ext_router_name)
|
||||
self.ext_router_created = True
|
||||
|
||||
# Create the 2 internal networks
|
||||
for (net, subnet, cidr) in zip(config.internal_network_name,
|
||||
config.internal_subnet_name,
|
||||
config.internal_cidr):
|
||||
int_net = self.create_net(net, subnet, cidr,
|
||||
config.dns_nameservers)
|
||||
self.vm_int_net.append(int_net)
|
||||
if config.ipv6_mode:
|
||||
self.ipv6_enabled = True
|
||||
|
||||
# Create the networks and subnets depending on v4 or v6
|
||||
if config.ipv6_mode:
|
||||
for (net, subnet, cidr, subnet_ipv6, cidr_ipv6) in zip(config.internal_network_name,
|
||||
config.internal_subnet_name,
|
||||
config.internal_cidr,
|
||||
config.internal_subnet_name_ipv6,
|
||||
config.internal_cidr_v6):
|
||||
int_net = self.create_net(net, subnet, cidr,
|
||||
config.dns_nameservers,
|
||||
subnet_ipv6, cidr_ipv6, config.ipv6_mode)
|
||||
self.vm_int_net.append(int_net)
|
||||
else:
|
||||
for (net, subnet, cidr) in zip(config.internal_network_name,
|
||||
config.internal_subnet_name,
|
||||
config.internal_cidr):
|
||||
int_net = self.create_net(net, subnet, cidr,
|
||||
config.dns_nameservers)
|
||||
self.vm_int_net.append(int_net)
|
||||
|
||||
# Add both internal networks to router interface to enable network to network connectivity
|
||||
self.__add_router_interface()
|
||||
@ -109,7 +125,8 @@ class Network(object):
|
||||
# Check first if a network with the same name exists, if it exists
|
||||
# return that network.
|
||||
# dns_nameservers: a list of name servers e.g. ['8.8.8.8']
|
||||
def create_net(self, network_name, subnet_name, cidr, dns_nameservers):
|
||||
def create_net(self, network_name, subnet_name, cidr, dns_nameservers,
|
||||
subnet_name_ipv6=None, cidr_ipv6=None, ipv6_mode=None):
|
||||
|
||||
for network in self.networks:
|
||||
if network['name'] == network_name:
|
||||
@ -137,6 +154,22 @@ class Network(object):
|
||||
subnet = self.neutron_client.create_subnet(body)['subnet']
|
||||
# add subnet id to the network dict since it has just been added
|
||||
network['subnets'] = [subnet['id']]
|
||||
# If ipv6 is enabled than create and add ipv6 network
|
||||
if ipv6_mode:
|
||||
body = {
|
||||
'subnet': {
|
||||
'name': subnet_name_ipv6,
|
||||
'cidr': cidr_ipv6,
|
||||
'network_id': network['id'],
|
||||
'enable_dhcp': True,
|
||||
'ip_version': 6,
|
||||
'ipv6_ra_mode': ipv6_mode,
|
||||
'ipv6_address_mode': ipv6_mode
|
||||
}
|
||||
}
|
||||
subnet = self.neutron_client.create_subnet(body)['subnet']
|
||||
# add the subnet id to the network dict
|
||||
network['subnets'].append(subnet['id'])
|
||||
print 'Created internal network: %s' % (network_name)
|
||||
return network
|
||||
|
||||
@ -180,11 +213,24 @@ class Network(object):
|
||||
self.neutron_client.add_interface_router(self.ext_router['id'], body)
|
||||
if self.config.debug:
|
||||
print 'Ext router associated to ' + int_net['name']
|
||||
# If ipv6 is enabled than add second subnet
|
||||
if self.ipv6_enabled:
|
||||
body = {
|
||||
'subnet_id': int_net['subnets'][1]
|
||||
}
|
||||
self.neutron_client.add_interface_router(self.ext_router['id'], body)
|
||||
|
||||
# Detach the ext router from the mgmt network
|
||||
def __remove_router_interface(self):
|
||||
for int_net in self.vm_int_net:
|
||||
if int_net:
|
||||
# If ipv6 is enabled remove that subnet too
|
||||
if self.ipv6_enabled:
|
||||
body = {
|
||||
'subnet_id': int_net['subnets'][1]
|
||||
}
|
||||
self.neutron_client.remove_interface_router(self.ext_router['id'],
|
||||
body)
|
||||
body = {
|
||||
'subnet_id': int_net['subnets'][0]
|
||||
}
|
||||
|
@ -25,7 +25,10 @@ class NuttcpTool(PerfTool):
|
||||
|
||||
def get_server_launch_cmd(self):
|
||||
'''Return the commands to launch the server side.'''
|
||||
return [self.dest_path + ' -P5002 -S --single-threaded &']
|
||||
if self.instance.config.ipv6_mode:
|
||||
return [self.dest_path + ' -P5002 -S --single-threaded -6 &']
|
||||
else:
|
||||
return [self.dest_path + ' -P5002 -S --single-threaded &']
|
||||
|
||||
def run_client(self, target_ip, target_instance,
|
||||
mss=None, bandwidth=0, bidirectional=False):
|
||||
@ -117,6 +120,8 @@ class NuttcpTool(PerfTool):
|
||||
opts += " -F -r"
|
||||
if length:
|
||||
opts += " -l" + str(length)
|
||||
if self.instance.config.ipv6_mode:
|
||||
opts += " -6 "
|
||||
if udp:
|
||||
opts += " -u"
|
||||
# for UDP if the bandwidth is not provided we need to calculate
|
||||
|
@ -238,7 +238,10 @@ class PingTool(PerfTool):
|
||||
5 packets transmitted, 5 received, 0% packet loss, time 3998ms
|
||||
rtt min/avg/max/mdev = 0.455/0.528/0.596/0.057 ms
|
||||
'''
|
||||
cmd = "ping -c " + str(ping_count) + " " + str(target_ip)
|
||||
if self.instance.config.ipv6_mode:
|
||||
cmd = "ping6 -c " + str(ping_count) + " " + str(target_ip)
|
||||
else:
|
||||
cmd = "ping -c " + str(ping_count) + " " + str(target_ip)
|
||||
cmd_out = self.instance.exec_command(cmd)
|
||||
if not cmd_out:
|
||||
res = {'protocol': 'ICMP',
|
||||
|
5
vmtp.py
5
vmtp.py
@ -364,8 +364,9 @@ class VmtpTest(object):
|
||||
|
||||
self.measure_flow("VM to VM different network fixed IP",
|
||||
self.server.internal_ip)
|
||||
self.measure_flow("VM to VM different network floating IP",
|
||||
self.server.ssh_ip)
|
||||
if not config.ipv6_mode:
|
||||
self.measure_flow("VM to VM different network floating IP",
|
||||
self.server.ssh_ip)
|
||||
|
||||
self.client.dispose()
|
||||
self.client = None
|
||||
|
Loading…
Reference in New Issue
Block a user