Skip to content

Commit 320aca4

Browse files
committed
1.OpenStack Pika support roce protocol customized for suyan
1 parent 9d864dd commit 320aca4

File tree

5 files changed

+441
-4
lines changed

5 files changed

+441
-4
lines changed

Cinder/Pike/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
"""Version: 2.6.RC3"""
1+
"""Version: 2.6.4"""

Cinder/Pike/constants.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@
4949
MIGRATION_FAULT = '74'
5050
MIGRATION_COMPLETE = '76'
5151

52+
# ROCE INITIATOR CONSTANTS
53+
NVME_ROCE_INITIATOR_TYPE = '57870'
54+
ADDRESS_FAMILY_IPV4 = '0'
55+
5256
ERROR_CONNECT_TO_SERVER = -403
5357
ERROR_UNAUTHORIZED_TO_SERVER = -401
5458
ERROR_BAD_STATUS_LINE = -400
@@ -73,7 +77,7 @@
7377
CLONE_PAIR_SYNC_COMPLETE = 1073798176
7478
CLONE_PAIR_SYNC_NOT_EXIST = 1073798172
7579
HOST_ALREADY_IN_HOSTGROUP = 1077937501
76-
LUN_ALREADY_IN_LUNGROUP = 1077948997
80+
OBJECT_ALREADY_EXIST = LUN_ALREADY_IN_LUNGROUP = 1077948997
7781
HOSTGROUP_ALREADY_IN_MAPPINGVIEW = 1073804556
7882
LUNGROUP_ALREADY_IN_MAPPINGVIEW = 1073804560
7983
HOST_NOT_EXIST = 1077937498

Cinder/Pike/huawei_conf.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ def update_config_value(self):
9090
self._force_delete_volume,
9191
self._iscsi_default_target_ip,
9292
self._iscsi_info,
93+
self._roce_info,
9394
self._fc_info,
9495
self._ssl_cert_path,
9596
self._ssl_cert_verify,
@@ -474,6 +475,8 @@ def get_hypermetro_devices(self):
474475
dev.get('iscsi_info'))
475476
dev_config['fc_info'] = self._parse_rmt_iscsi_info(
476477
dev.get('fc_info'))
478+
dev_config['roce_info'] = self._parse_rmt_iscsi_info(
479+
dev.get('roce_info'))
477480
dev_config['iscsi_default_target_ip'] = (
478481
dev['iscsi_default_target_ip'].split(';')
479482
if 'iscsi_default_target_ip' in dev
@@ -507,6 +510,8 @@ def get_replication_devices(self):
507510
dev.get('iscsi_info'))
508511
dev_config['fc_info'] = self._parse_rmt_iscsi_info(
509512
dev.get('fc_info'))
513+
dev_config['roce_info'] = self._parse_rmt_iscsi_info(
514+
dev.get('roce_info'))
510515
dev_config['iscsi_default_target_ip'] = (
511516
dev['iscsi_default_target_ip'].split(';')
512517
if 'iscsi_default_target_ip' in dev
@@ -529,6 +534,7 @@ def get_local_device(self):
529534
'storage_pools': self.conf.storage_pools,
530535
'iscsi_info': self.conf.iscsi_info,
531536
'fc_info': self.conf.fc_info,
537+
'roce_info': self.conf.roce_info,
532538
'iscsi_default_target_ip': self.conf.iscsi_default_target_ip,
533539
'in_band_or_not': self.conf.in_band_or_not,
534540
'storage_sn': self.conf.storage_sn,
@@ -679,3 +685,20 @@ def _set_qos_ignored_param(xml_root):
679685
qos_ignored_params = text.split(';')
680686
qos_ignored_params = list(set(x.strip() for x in qos_ignored_params if x.strip()))
681687
setattr(constants, 'QOS_IGNORED_PARAMS', qos_ignored_params)
688+
689+
def _roce_info(self, xml_root):
690+
nodes = xml_root.findall('RoCE/Initiator')
691+
if nodes is None:
692+
setattr(self.conf, 'roce_info', [])
693+
return
694+
695+
roce_info = []
696+
for node in nodes:
697+
props = {}
698+
for item in node.items():
699+
props[item[0].strip()] = item[1].strip()
700+
701+
roce_info.append(props)
702+
703+
self._check_hostname_regex_config(roce_info)
704+
setattr(self.conf, 'roce_info', roce_info)

Cinder/Pike/huawei_driver.py

Lines changed: 223 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@
8181

8282

8383
class HuaweiBaseDriver(driver.VolumeDriver):
84-
VERSION = "2.6.RC3"
84+
VERSION = "2.6.4"
8585

8686
def __init__(self, *args, **kwargs):
8787
super(HuaweiBaseDriver, self).__init__(*args, **kwargs)
@@ -3642,3 +3642,225 @@ def _delete_zone_and_remove_fc_initiators(self, wwns, host_id):
36423642
'data': {'target_wwn': tgt_port_wwns,
36433643
'initiator_target_map': init_targ_map}}
36443644
return info, portg_id
3645+
3646+
3647+
class HuaweiROCEDriver(HuaweiBaseDriver):
3648+
"""RoCE driver for Huawei storage arrays.
3649+
3650+
Version history:
3651+
2.6.4 - start to support RoCE.
3652+
"""
3653+
3654+
def __init__(self, *args, **kwargs):
3655+
super(HuaweiROCEDriver, self).__init__(*args, **kwargs)
3656+
3657+
def get_volume_stats(self, refresh=False):
3658+
"""Get volume status."""
3659+
data = HuaweiBaseDriver.get_volume_stats(self, refresh=False)
3660+
backend_name = self.configuration.safe_get('volume_backend_name')
3661+
data['volume_backend_name'] = backend_name or self.__class__.__name__
3662+
data['storage_protocol'] = 'nvmeof'
3663+
data['driver_version'] = self.VERSION
3664+
data['vendor_name'] = 'Huawei'
3665+
return data
3666+
3667+
@coordination.synchronized('huawei-mapping-{connector[host]}')
3668+
def initialize_connection(self, volume, connector):
3669+
"""Map a volume to a host and return target RoCE information."""
3670+
self._check_roce_params(volume, connector)
3671+
3672+
# Attach local lun.
3673+
roce_info = self._initialize_connection(volume, connector)
3674+
3675+
# Attach remote lun if exists.
3676+
metadata = huawei_utils.get_lun_metadata(volume)
3677+
LOG.info("Attach Volume, metadata is: %s.", metadata)
3678+
if metadata.get('hypermetro'):
3679+
try:
3680+
rmt_roce_info = (
3681+
self._initialize_connection(volume, connector, False))
3682+
except Exception:
3683+
with excutils.save_and_reraise_exception():
3684+
self._terminate_connection(volume, connector)
3685+
3686+
roce_info.get('data').get('target_portals').extend(
3687+
rmt_roce_info.get('data').get('target_portals'))
3688+
roce_info.get('data').get('target_luns').extend(
3689+
rmt_roce_info.get('data').get('target_luns'))
3690+
3691+
LOG.info('initialize_common_connection_roce, '
3692+
'return data is: %s.', roce_info)
3693+
return roce_info
3694+
3695+
def _initialize_connection(self, volume, connector, local=True):
3696+
LOG.info('Initialize RoCE connection for volume %(id)s, '
3697+
'connector info %(conn)s. array is in %(location)s.',
3698+
{'id': volume.id, 'conn': connector,
3699+
'location': 'local' if local else 'remote'})
3700+
3701+
host_nqn = connector.get("host_nqn")
3702+
3703+
client = self.client if local else self.rmt_client
3704+
3705+
lun_id, lun_type = self.get_lun_id_and_type(
3706+
volume, constants.VOLUME_NOT_EXISTS_RAISE, local)
3707+
lun_info = client.get_lun_info(lun_id, lun_type)
3708+
3709+
target_ips = client.get_roce_params(connector)
3710+
3711+
host_id = client.add_host_with_check(
3712+
connector.get('host'), self.is_dorado_v6, host_nqn)
3713+
3714+
try:
3715+
client.ensure_roceini_added(host_nqn, host_id)
3716+
except Exception:
3717+
with excutils.save_and_reraise_exception():
3718+
self.remove_host_with_check(host_id)
3719+
3720+
hostgroup_id = client.add_host_to_hostgroup(host_id)
3721+
3722+
metadata = huawei_utils.get_lun_metadata(volume)
3723+
hypermetro_lun = metadata.get('hypermetro')
3724+
3725+
map_info = client.do_mapping(
3726+
lun_info, hostgroup_id, host_id,
3727+
lun_type=lun_type, hypermetro_lun=hypermetro_lun)
3728+
host_lun_id = client.get_host_lun_id(host_id, lun_info, lun_type)
3729+
LOG.info('initialize_connection, host lun id is: %(id)s. '
3730+
'View info is %(view)s.',
3731+
{'id': host_lun_id, 'view': map_info})
3732+
host_lun_id = int(host_lun_id)
3733+
3734+
mapping_info = {
3735+
'portals': [(ip, "4420", "rdma") for ip in target_ips],
3736+
'target_luns': [host_lun_id] * len(target_ips),
3737+
'discard': True,
3738+
'volume_nguid': lun_info.get("NGUID")
3739+
}
3740+
conn = {
3741+
'driver_volume_type': 'nvmeof',
3742+
'data': mapping_info
3743+
}
3744+
LOG.info('Initialize RoCE connection successfully: %s.', conn)
3745+
return conn
3746+
3747+
@coordination.synchronized('huawei-mapping-{connector[host]}')
3748+
def terminate_connection(self, volume, connector, **kwargs):
3749+
"""Delete map between a volume and a host."""
3750+
self._check_roce_params(volume, connector)
3751+
3752+
metadata = huawei_utils.get_lun_metadata(volume)
3753+
LOG.info("terminate_connection, metadata is: %s.", metadata)
3754+
self._terminate_connection(volume, connector)
3755+
3756+
if metadata.get('hypermetro'):
3757+
self._terminate_connection(volume, connector, False)
3758+
3759+
LOG.info('terminate_connection success.')
3760+
3761+
def _terminate_connection(self, volume, connector, local=True):
3762+
LOG.info('_terminate_connection, detach %(local)s volume.',
3763+
{'local': 'local' if local else 'remote'})
3764+
3765+
client = self.client if local else self.rmt_client
3766+
3767+
lun_id, lun_type = self.get_lun_id_and_type(
3768+
volume, constants.VOLUME_NOT_EXISTS_WARN, local)
3769+
3770+
initiator_name = connector.get('host_nqn')
3771+
host_name = connector.get('host')
3772+
3773+
LOG.info('terminate_connection: initiator name: %(ini)s, LUN ID: %('
3774+
'lunid)s, lun type: %(lun_type)s, connector: %('
3775+
'connector)s.', {'ini': initiator_name, 'lunid': lun_id,
3776+
'lun_type': lun_type,
3777+
'connector': connector})
3778+
3779+
lungroup_id = None
3780+
portgroup_id = None
3781+
view_id = None
3782+
3783+
host_id = huawei_utils.get_host_id(client, host_name)
3784+
if host_id:
3785+
mapping_view_name = constants.MAPPING_VIEW_PREFIX + host_id
3786+
view_id = client.find_mapping_view(mapping_view_name)
3787+
if view_id:
3788+
lungroup_id = client.find_lungroup_from_map(view_id)
3789+
portgroup_id = client.get_portgroup_by_view(view_id)
3790+
3791+
if lun_id and lungroup_id:
3792+
lungroup_ids = client.get_lungroupids_by_lunid(lun_id, lun_type)
3793+
if lungroup_id in lungroup_ids:
3794+
client.remove_lun_from_lungroup(lungroup_id, lun_id, lun_type)
3795+
else:
3796+
LOG.warning("LUN is not in lungroup. LUN ID: %(lun_id)s. "
3797+
"Lungroup id: %(lungroup_id)s.",
3798+
{"lun_id": lun_id, "lungroup_id": lungroup_id})
3799+
if self.configuration.retain_storage_mapping:
3800+
return
3801+
3802+
mapping_param = {'host_id': host_id, 'initiator_name': initiator_name,
3803+
'lungroup_id': lungroup_id, 'view_id': view_id,
3804+
'portgroup_id': portgroup_id}
3805+
self._delete_storage_mapping(client, mapping_param)
3806+
3807+
def _delete_storage_mapping(self, client, mapping_param):
3808+
left_lun_num = -1
3809+
lungroup_id = mapping_param.get('lungroup_id')
3810+
view_id = mapping_param.get('view_id')
3811+
portgroup_id = mapping_param.get('portgroup_id')
3812+
initiator_name = mapping_param.get('initiator_name')
3813+
host_id = mapping_param.get('host_id')
3814+
if lungroup_id:
3815+
left_lun_num = client.get_obj_count_from_lungroup(lungroup_id)
3816+
if view_id and (int(left_lun_num) <= 0):
3817+
if portgroup_id and client.is_portgroup_associated_to_view(
3818+
view_id, portgroup_id):
3819+
client.delete_portgroup_mapping_view(view_id, portgroup_id)
3820+
3821+
if client.lungroup_associated(view_id, lungroup_id):
3822+
client.delete_lungroup_mapping_view(view_id, lungroup_id)
3823+
3824+
client.delete_lungroup(lungroup_id)
3825+
3826+
if client.is_roce_initiator_associated_to_host(
3827+
initiator_name, host_id):
3828+
client.remove_roce_initiator_from_host(initiator_name, host_id)
3829+
3830+
hostgroup_name = constants.HOSTGROUP_PREFIX + host_id
3831+
hostgroup_id = client.find_hostgroup(hostgroup_name)
3832+
if hostgroup_id:
3833+
if client.hostgroup_associated(view_id, hostgroup_id):
3834+
client.delete_hostgoup_mapping_view(view_id, hostgroup_id)
3835+
client.remove_host_from_hostgroup(hostgroup_id, host_id)
3836+
client.delete_hostgroup(hostgroup_id)
3837+
client.remove_host(host_id)
3838+
3839+
client.delete_mapping_view(view_id)
3840+
3841+
def _check_roce_params(self, volume, connector):
3842+
if not volume or not connector:
3843+
msg = _(
3844+
'%(param)s is none.'
3845+
% {'param': 'volume' if not volume else 'connector'})
3846+
LOG.error(msg)
3847+
raise exception.VolumeBackendAPIException(data=msg)
3848+
3849+
if not volume.id:
3850+
msg = _(
3851+
'volume param is error. volume is %(volume)s.'
3852+
% {'volume': volume})
3853+
LOG.error(msg)
3854+
raise exception.VolumeBackendAPIException(data=msg)
3855+
3856+
if not connector.get('host_nqn') or not connector.get('host'):
3857+
msg = _(
3858+
'connector param is error. connector is %(connector)s.'
3859+
% {'connector': connector})
3860+
LOG.error(msg)
3861+
raise exception.VolumeBackendAPIException(data=msg)
3862+
3863+
if not self.is_dorado_v6:
3864+
msg = _("Current storage doesn't support RoCE.")
3865+
LOG.error(msg)
3866+
raise exception.VolumeBackendAPIException(data=msg)

0 commit comments

Comments
 (0)