1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
|
# 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 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)
|