hypervisor-supplied-nics support in PowerVM

PowerVM does not allow MAC addresses to be directly set on LPARs.
Instead, use the hypervisor-supplied-nics feature to generate MAC
addresses we can ensure are provisioned correctly.

blueprint powervm-compute-resize-migration

Change-Id: Idad7f03d9fd61970912ec1a6978fc0af56309df4
This commit is contained in:
Michael J Fork
2013-01-23 04:43:21 +00:00
parent 749c3db3f6
commit 005ef07962
3 changed files with 67 additions and 6 deletions

View File

@@ -23,7 +23,9 @@ from nova import db
from nova import test
from nova.compute import power_state
from nova.network import model as network_model
from nova.openstack.common import log as logging
from nova.tests import fake_network_cache_model
from nova.virt import images
from nova.virt.powervm import blockdev as powervm_blockdev
from nova.virt.powervm import common
@@ -156,8 +158,11 @@ class PowerVMDriverTestCase(test.TestCase):
self.stubs.Set(images, 'fetch_to_raw', fake_image_fetch_to_raw)
image_meta = {}
image_meta['id'] = '666'
fake_net_info = network_model.NetworkInfo([
fake_network_cache_model.new_vif()])
self.powervm_connection.spawn(context.get_admin_context(),
self.instance, image_meta, 's3cr3t', [])
self.instance, image_meta, [], 's3cr3t',
fake_net_info)
state = self.powervm_connection.get_info(self.instance)['state']
self.assertEqual(state, power_state.RUNNING)
@@ -176,12 +181,13 @@ class PowerVMDriverTestCase(test.TestCase):
self.stubs.Set(
self.powervm_connection._powervm, '_cleanup',
lambda *x, **y: raise_(Exception('This should be logged.')))
fake_net_info = network_model.NetworkInfo([
fake_network_cache_model.new_vif()])
self.assertRaises(exception.PowerVMImageCreationFailed,
self.powervm_connection.spawn,
context.get_admin_context(),
self.instance,
{'id': 'ANY_ID'}, 's3cr3t', [])
{'id': 'ANY_ID'}, [], 's3cr3t', fake_net_info)
def test_destroy(self):
self.powervm_connection.destroy(self.instance, None)

View File

@@ -88,10 +88,13 @@ class PowerVMDriver(driver.ComputeDriver):
def plug_vifs(self, instance, network_info):
pass
def macs_for_instance(self, instance):
return self._powervm.macs_for_instance(instance)
def spawn(self, context, instance, image_meta, injected_files,
admin_password, network_info=None, block_device_info=None):
"""Create a new instance/VM/domain on powerVM."""
self._powervm.spawn(context, instance, image_meta['id'])
self._powervm.spawn(context, instance, image_meta['id'], network_info)
def destroy(self, instance, network_info, block_device_info=None,
destroy_disks=True):

View File

@@ -15,6 +15,7 @@
# under the License.
import decimal
import random
import re
import time
@@ -170,7 +171,7 @@ class PowerVMOperator(object):
self._host_stats = data
def spawn(self, context, instance, image_id):
def spawn(self, context, instance, image_id, network_info):
def _create_lpar_instance(instance):
host_stats = self.get_host_stats(refresh=True)
inst_name = instance['name']
@@ -201,9 +202,21 @@ class PowerVMOperator(object):
try:
# Network
# To ensure the MAC address on the guest matches the
# generated value, pull the first 10 characters off the
# MAC address for the mac_base_value parameter and then
# get the integer value of the final 2 characters as the
# slot_id parameter
mac = network_info[0]['address']
mac_base_value = (mac[:-2]).replace(':', '')
eth_id = self._operator.get_virtual_eth_adapter_id()
slot_id = int(mac[-2:], 16)
virtual_eth_adapters = ('%(slot_id)s/0/%(eth_id)s//0/0' %
locals())
# LPAR configuration data
# max_virtual_slots is hardcoded to 64 since we generate a MAC
# address that must be placed in slots 32 - 64
lpar_inst = LPAR.LPAR(
name=inst_name, lpar_env='aixlinux',
min_mem=mem_min, desired_mem=mem,
@@ -213,10 +226,14 @@ class PowerVMOperator(object):
min_proc_units=cpus_units_min,
desired_proc_units=cpus_units,
max_proc_units=cpus_max,
virtual_eth_adapters='4/0/%s//0/0' % eth_id)
virtual_eth_mac_base_value=mac_base_value,
max_virtual_slots=64,
virtual_eth_adapters=virtual_eth_adapters)
LOG.debug(_("Creating LPAR instance '%s'") % instance['name'])
self._operator.create_lpar(lpar_inst)
#TODO(mjfork) capture the error and handle the error when the MAC
# prefix already exists on the system (1 in 2^28)
except nova_exception.ProcessExecutionError:
LOG.exception(_("LPAR instance '%s' creation failed") %
instance['name'])
@@ -345,6 +362,9 @@ class PowerVMOperator(object):
def power_on(self, instance_name):
self._operator.start_lpar(instance_name)
def macs_for_instance(self, instance):
return self._operator.macs_for_instance(instance)
class BaseOperator(object):
"""Base operator for IVM and HMC managed systems."""
@@ -573,6 +593,9 @@ class BaseOperator(object):
self._connection, command, check_exit_code=check_exit_code)
return stdout.read().splitlines()
def macs_for_instance(self, instance):
pass
class IVMOperator(BaseOperator):
"""Integrated Virtualization Manager (IVM) Operator.
@@ -583,3 +606,32 @@ class IVMOperator(BaseOperator):
def __init__(self, ivm_connection):
self.command = command.IVMCommand()
BaseOperator.__init__(self, ivm_connection)
def macs_for_instance(self, instance):
"""Generates set of valid MAC addresses for an IVM instance."""
# NOTE(vish): We would prefer to use 0xfe here to ensure that linux
# bridge mac addresses don't change, but it appears to
# conflict with libvirt, so we use the next highest octet
# that has the unicast and locally administered bits set
# properly: 0xfa.
# Discussion: https://bugs.launchpad.net/nova/+bug/921838
# NOTE(mjfork): For IVM-based PowerVM, we cannot directly set a MAC
# address on an LPAR, but rather need to construct one
# that can be used. Retain the 0xfe as noted above,
# but ensure the final 3 hex values represent a value
# between 32 and 64 so we can assign as the slot id on
# the system.
# FA:xx:xx:xx:x0:[32-64]
macs = set()
mac_base = [0xfa,
random.randint(0x00, 0xff),
random.randint(0x00, 0xff),
random.randint(0x00, 0xff),
random.randint(0x00, 0xff) & 0xf0,
random.randint(0x00, 0x00)]
for n in range(32, 64):
mac_base[5] = n
macs.add(':'.join(map(lambda x: "%02x" % x, mac_base)))
return macs