f86975d53c
Follow-up from service steps addition change to add a deploy steps alias for the Nvidia Mellanox network device firmware update clean steps. This allows deploy time firmware updates to be codified as part of a deployment with custom steps. Change-Id: I9d80447dee7cfde4d3f8d81d9d39e738916b7824
175 lines
6.7 KiB
Python
175 lines
6.7 KiB
Python
# Copyright 2016 Mellanox Technologies, Ltd
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
import os
|
|
|
|
from oslo_log import log
|
|
|
|
from ironic_python_agent import errors
|
|
from ironic_python_agent import hardware
|
|
from ironic_python_agent.hardware_managers.nvidia import nvidia_fw_update
|
|
from ironic_python_agent import netutils
|
|
|
|
LOG = log.getLogger()
|
|
# Mellanox NIC Vendor ID
|
|
MLNX_VENDOR_ID = '0x15b3'
|
|
# Mellanox Prefix to generate InfiniBand CLient-ID
|
|
MLNX_INFINIBAND_CLIENT_ID_PREFIX = 'ff:00:00:00:00:00:02:00:00:02:c9:00:'
|
|
|
|
|
|
def _infiniband_address_to_mac(address):
|
|
"""Convert InfiniBand address to MAC
|
|
|
|
Convert InfiniBand address to MAC by Mellanox specific
|
|
translation. The InfiniBand address is 59 characters
|
|
composed from GID:GUID. The last 24 characters are the
|
|
GUID. The InfiniBand MAC is upper 10 characters and lower
|
|
9 characters from the GUID
|
|
Example:
|
|
address - a0:00:00:27:fe:80:00:00:00:00:00:00:7c:fe:90:03:00:29:26:52
|
|
GUID - 7c:fe:90:03:00:29:26:52
|
|
InfiniBand MAC - 7c:fe:90:29:26:52
|
|
|
|
:param address: InfiniBand Address.
|
|
:returns: InfiniBand MAC.
|
|
"""
|
|
return address[36:-14] + address[51:]
|
|
|
|
|
|
def _generate_client_id(address):
|
|
"""Generate client id from InfiniBand address
|
|
|
|
:param address: InfiniBand address.
|
|
:returns: client id.
|
|
"""
|
|
return MLNX_INFINIBAND_CLIENT_ID_PREFIX + address[36:]
|
|
|
|
|
|
def _detect_hardware():
|
|
"""method for detection of Mellanox NICs
|
|
|
|
:returns: Boolean value. True if the machine contain one
|
|
or more Mellanox NIC(s), False otherwise.
|
|
"""
|
|
iface_names = os.listdir('/sys/class/net')
|
|
for ifname in iface_names:
|
|
if (hardware._get_device_info(
|
|
ifname, 'net', 'vendor') == MLNX_VENDOR_ID):
|
|
return True
|
|
return False
|
|
|
|
|
|
class MellanoxDeviceHardwareManager(hardware.HardwareManager):
|
|
"""Mellanox hardware manager to support a single device"""
|
|
|
|
HARDWARE_MANAGER_NAME = 'MellanoxDeviceHardwareManager'
|
|
HARDWARE_MANAGER_VERSION = '1'
|
|
|
|
def evaluate_hardware_support(self):
|
|
"""Declare level of hardware support provided."""
|
|
|
|
if _detect_hardware():
|
|
LOG.debug('Found Mellanox device')
|
|
return hardware.HardwareSupport.MAINLINE
|
|
else:
|
|
LOG.debug('No Mellanox devices found')
|
|
return hardware.HardwareSupport.NONE
|
|
|
|
def get_interface_info(self, interface_name):
|
|
"""Return the interface information when its Mellanox and InfiniBand
|
|
|
|
In case of Mellanox and InfiniBand interface we do the following:
|
|
1. Calculate the "InfiniBand MAC" according to InfiniBand GUID
|
|
2. Calculate the client-id according to InfiniBand GUID
|
|
"""
|
|
|
|
address = netutils.get_mac_addr(interface_name)
|
|
if address is None:
|
|
raise errors.IncompatibleHardwareMethodError()
|
|
vendor = hardware._get_device_info(interface_name, 'net', 'vendor')
|
|
if (len(address) != netutils.INFINIBAND_ADDR_LEN
|
|
or vendor != MLNX_VENDOR_ID):
|
|
raise errors.IncompatibleHardwareMethodError()
|
|
|
|
mac_addr = _infiniband_address_to_mac(address)
|
|
client_id = _generate_client_id(address)
|
|
|
|
return hardware.NetworkInterface(
|
|
interface_name, mac_addr,
|
|
ipv4_address=netutils.get_ipv4_addr(interface_name),
|
|
has_carrier=netutils.interface_has_carrier(interface_name),
|
|
lldp=None,
|
|
vendor=vendor,
|
|
product=hardware._get_device_info(interface_name, 'net', 'device'),
|
|
client_id=client_id)
|
|
|
|
def get_clean_steps(self, node, ports):
|
|
"""Get a list of clean steps with priority.
|
|
|
|
:param node: The node object as provided by Ironic.
|
|
:param ports: Port objects as provided by Ironic.
|
|
:returns: A list of cleaning steps, as a list of dicts.
|
|
"""
|
|
return [{'step': 'update_nvidia_nic_firmware_image',
|
|
'priority': 0,
|
|
'interface': 'deploy',
|
|
'reboot_requested': True,
|
|
'abortable': False,
|
|
'argsinfo': {
|
|
'images': {
|
|
'description': 'Json blob contains a list of images,'
|
|
' where each image contains a map of '
|
|
'url: to firmware image (file://, '
|
|
'http://), '
|
|
'checksum: of the provided image, '
|
|
'checksumType: md5/sha512/sha256, '
|
|
'componentProfile: PSID of the nic, '
|
|
'version: of the FW',
|
|
'required': True,
|
|
}, }
|
|
},
|
|
{'step': 'update_nvidia_nic_firmware_settings',
|
|
'priority': 0,
|
|
'interface': 'deploy',
|
|
'reboot_requested': True,
|
|
'abortable': False,
|
|
'argsinfo': {
|
|
'settings': {
|
|
'description': 'Json blob contains a list of '
|
|
'settings per device ID, where each '
|
|
'settings contains a map of '
|
|
'deviceID: device ID '
|
|
'globalConfig: global config '
|
|
'function0Config: function 0 config '
|
|
'function1Config: function 1 config',
|
|
'required': True,
|
|
}, }
|
|
}
|
|
]
|
|
|
|
def get_service_steps(self, node, ports):
|
|
"""Alias wrapper for method get_clean_steps."""
|
|
# NOTE(TheJulia): Since these steps can be run upon service, why not
|
|
return self.get_clean_steps(node, ports)
|
|
|
|
def get_deploy_steps(self, node, ports):
|
|
"""Alias wrapper for method get_clean_steps."""
|
|
return self.get_clean_steps(node, ports)
|
|
|
|
def update_nvidia_nic_firmware_image(self, node, ports, images):
|
|
nvidia_fw_update.update_nvidia_nic_firmware_image(images)
|
|
|
|
def update_nvidia_nic_firmware_settings(self, node, ports, settings):
|
|
nvidia_fw_update.update_nvidia_nic_firmware_settings(settings)
|