NetApp cDOT: Apply network MTU to VLAN ports

Through change I9b4efae620ec9f6790547c8fffc58872d43277f5
we added support in manila to request the Maximum Transmission
Unit (MTU) from the network provider (neutron, standalone, etc.).

To honor this MTU, the NetApp cDOT driver needs to apply it
to the VLAN ports (via the broadcast domain) that the LIFs of the
newly created share servers are assigned to.

Co-Authored-By: Goutham Pacha Ravi <gouthamr@netapp.com>
Depends-On: I9b4efae620ec9f6790547c8fffc58872d43277f5
Change-Id: Ia01d982c7328feff292d54588d33a16df705f81e
Implements: blueprint netapp-cdot-honor-mtu-size
This commit is contained in:
Clinton Knight 2016-07-26 20:56:41 -04:00 committed by Goutham Pacha Ravi
parent e3afcd751f
commit 2d4e30bd21
6 changed files with 103 additions and 37 deletions

View File

@ -473,7 +473,7 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
@na_utils.trace @na_utils.trace
def create_network_interface(self, ip, netmask, vlan, node, port, def create_network_interface(self, ip, netmask, vlan, node, port,
vserver_name, lif_name, ipspace_name): vserver_name, lif_name, ipspace_name, mtu):
"""Creates LIF on VLAN port.""" """Creates LIF on VLAN port."""
home_port_name = port home_port_name = port
@ -482,8 +482,8 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
home_port_name = '%(port)s-%(tag)s' % {'port': port, 'tag': vlan} home_port_name = '%(port)s-%(tag)s' % {'port': port, 'tag': vlan}
if self.features.BROADCAST_DOMAINS: if self.features.BROADCAST_DOMAINS:
self._ensure_broadcast_domain_for_port(node, home_port_name, self._ensure_broadcast_domain_for_port(
ipspace=ipspace_name) node, home_port_name, mtu, ipspace=ipspace_name)
LOG.debug('Creating LIF %(lif)s for Vserver %(vserver)s ', LOG.debug('Creating LIF %(lif)s for Vserver %(vserver)s ',
{'lif': lif_name, 'vserver': vserver_name}) {'lif': lif_name, 'vserver': vserver_name})
@ -554,7 +554,7 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
raise exception.NetAppException(msg % msg_args) raise exception.NetAppException(msg % msg_args)
@na_utils.trace @na_utils.trace
def _ensure_broadcast_domain_for_port(self, node, port, def _ensure_broadcast_domain_for_port(self, node, port, mtu,
domain=DEFAULT_BROADCAST_DOMAIN, domain=DEFAULT_BROADCAST_DOMAIN,
ipspace=DEFAULT_IPSPACE): ipspace=DEFAULT_IPSPACE):
"""Ensure a port is in a broadcast domain. Create one if necessary. """Ensure a port is in a broadcast domain. Create one if necessary.
@ -572,6 +572,7 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
# Port already in desired ipspace and broadcast domain. # Port already in desired ipspace and broadcast domain.
if (port_info['ipspace'] == ipspace if (port_info['ipspace'] == ipspace
and port_info['broadcast-domain'] == domain): and port_info['broadcast-domain'] == domain):
self._modify_broadcast_domain(domain, ipspace, mtu)
return return
# If in another broadcast domain, remove port from it. # If in another broadcast domain, remove port from it.
@ -582,7 +583,9 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
# If desired broadcast domain doesn't exist, create it. # If desired broadcast domain doesn't exist, create it.
if not self._broadcast_domain_exists(domain, ipspace): if not self._broadcast_domain_exists(domain, ipspace):
self._create_broadcast_domain(domain, ipspace) self._create_broadcast_domain(domain, ipspace, mtu)
else:
self._modify_broadcast_domain(domain, ipspace, mtu)
# Move the port into the broadcast domain where it is needed. # Move the port into the broadcast domain where it is needed.
self._add_port_to_broadcast_domain(node, port, domain, ipspace) self._add_port_to_broadcast_domain(node, port, domain, ipspace)
@ -640,7 +643,7 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
return self._has_records(result) return self._has_records(result)
@na_utils.trace @na_utils.trace
def _create_broadcast_domain(self, domain, ipspace, mtu=1500): def _create_broadcast_domain(self, domain, ipspace, mtu):
"""Create a broadcast domain.""" """Create a broadcast domain."""
api_args = { api_args = {
'ipspace': ipspace, 'ipspace': ipspace,
@ -649,6 +652,16 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
} }
self.send_request('net-port-broadcast-domain-create', api_args) self.send_request('net-port-broadcast-domain-create', api_args)
@na_utils.trace
def _modify_broadcast_domain(self, domain, ipspace, mtu):
"""Modify a broadcast domain."""
api_args = {
'ipspace': ipspace,
'broadcast-domain': domain,
'mtu': mtu,
}
self.send_request('net-port-broadcast-domain-modify', api_args)
@na_utils.trace @na_utils.trace
def _delete_broadcast_domain(self, domain, ipspace): def _delete_broadcast_domain(self, domain, ipspace):
"""Delete a broadcast domain.""" """Delete a broadcast domain."""
@ -658,6 +671,7 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
} }
self.send_request('net-port-broadcast-domain-destroy', api_args) self.send_request('net-port-broadcast-domain-destroy', api_args)
@na_utils.trace
def _delete_broadcast_domains_for_ipspace(self, ipspace_name): def _delete_broadcast_domains_for_ipspace(self, ipspace_name):
"""Deletes all broadcast domains in an IPspace.""" """Deletes all broadcast domains in an IPspace."""
ipspaces = self.get_ipspaces(ipspace_name=ipspace_name) ipspaces = self.get_ipspaces(ipspace_name=ipspace_name)

View File

@ -36,6 +36,7 @@ from manila import utils
LOG = log.getLogger(__name__) LOG = log.getLogger(__name__)
SUPPORTED_NETWORK_TYPES = (None, 'flat', 'vlan') SUPPORTED_NETWORK_TYPES = (None, 'flat', 'vlan')
SEGMENTED_NETWORK_TYPES = ('vlan',) SEGMENTED_NETWORK_TYPES = ('vlan',)
DEFAULT_MTU = 1500
class NetAppCmodeMultiSVMFileStorageLibrary( class NetAppCmodeMultiSVMFileStorageLibrary(
@ -273,13 +274,15 @@ class NetAppCmodeMultiSVMFileStorageLibrary(
ip_address = network_allocation['ip_address'] ip_address = network_allocation['ip_address']
netmask = utils.cidr_to_netmask(network_allocation['cidr']) netmask = utils.cidr_to_netmask(network_allocation['cidr'])
vlan = network_allocation['segmentation_id'] vlan = network_allocation['segmentation_id']
network_mtu = network_allocation.get('mtu')
mtu = network_mtu or DEFAULT_MTU
if not vserver_client.network_interface_exists( if not vserver_client.network_interface_exists(
vserver_name, node_name, port, ip_address, netmask, vlan): vserver_name, node_name, port, ip_address, netmask, vlan):
self._client.create_network_interface( self._client.create_network_interface(
ip_address, netmask, vlan, node_name, port, vserver_name, ip_address, netmask, vlan, node_name, port, vserver_name,
lif_name, ipspace_name) lif_name, ipspace_name, mtu)
@na_utils.trace @na_utils.trace
def get_network_allocations_number(self): def get_network_allocations_number(self):

View File

@ -869,7 +869,8 @@ class NetAppClientCmodeTestCase(test.TestCase):
fake.PORT, fake.PORT,
fake.VSERVER_NAME, fake.VSERVER_NAME,
fake.LIF_NAME, fake.LIF_NAME,
fake.IPSPACE_NAME) fake.IPSPACE_NAME,
fake.MTU)
if use_vlans: if use_vlans:
self.client._create_vlan.assert_called_with( self.client._create_vlan.assert_called_with(
@ -880,7 +881,7 @@ class NetAppClientCmodeTestCase(test.TestCase):
if broadcast_domains_supported: if broadcast_domains_supported:
self.client._ensure_broadcast_domain_for_port.assert_called_with( self.client._ensure_broadcast_domain_for_port.assert_called_with(
fake.NODE_NAME, fake.VLAN_PORT if use_vlans else fake.PORT, fake.NODE_NAME, fake.VLAN_PORT if use_vlans else fake.PORT,
ipspace=fake.IPSPACE_NAME) fake.MTU, ipspace=fake.IPSPACE_NAME)
else: else:
self.assertFalse( self.assertFalse(
self.client._ensure_broadcast_domain_for_port.called) self.client._ensure_broadcast_domain_for_port.called)
@ -993,14 +994,17 @@ class NetAppClientCmodeTestCase(test.TestCase):
'_broadcast_domain_exists', '_broadcast_domain_exists',
mock.Mock(return_value=True)) mock.Mock(return_value=True))
self.mock_object(self.client, '_create_broadcast_domain') self.mock_object(self.client, '_create_broadcast_domain')
self.mock_object(self.client, '_modify_broadcast_domain')
self.mock_object(self.client, '_add_port_to_broadcast_domain') self.mock_object(self.client, '_add_port_to_broadcast_domain')
self.client._ensure_broadcast_domain_for_port( self.client._ensure_broadcast_domain_for_port(
fake.NODE_NAME, fake.PORT, domain=fake.BROADCAST_DOMAIN, fake.NODE_NAME, fake.PORT, fake.MTU, domain=fake.BROADCAST_DOMAIN,
ipspace=fake.IPSPACE_NAME) ipspace=fake.IPSPACE_NAME)
self.client._get_broadcast_domain_for_port.assert_has_calls([ self.client._get_broadcast_domain_for_port.assert_called_once_with(
mock.call(fake.NODE_NAME, fake.PORT)]) fake.NODE_NAME, fake.PORT)
self.client._modify_broadcast_domain.assert_called_once_with(
fake.BROADCAST_DOMAIN, fake.IPSPACE_NAME, fake.MTU)
self.assertFalse(self.client._broadcast_domain_exists.called) self.assertFalse(self.client._broadcast_domain_exists.called)
self.assertFalse(self.client._create_broadcast_domain.called) self.assertFalse(self.client._create_broadcast_domain.called)
self.assertFalse(self.client._add_port_to_broadcast_domain.called) self.assertFalse(self.client._add_port_to_broadcast_domain.called)
@ -1018,24 +1022,26 @@ class NetAppClientCmodeTestCase(test.TestCase):
'_broadcast_domain_exists', '_broadcast_domain_exists',
mock.Mock(return_value=True)) mock.Mock(return_value=True))
self.mock_object(self.client, '_create_broadcast_domain') self.mock_object(self.client, '_create_broadcast_domain')
self.mock_object(self.client, '_modify_broadcast_domain')
self.mock_object(self.client, '_remove_port_from_broadcast_domain') self.mock_object(self.client, '_remove_port_from_broadcast_domain')
self.mock_object(self.client, '_add_port_to_broadcast_domain') self.mock_object(self.client, '_add_port_to_broadcast_domain')
self.client._ensure_broadcast_domain_for_port( self.client._ensure_broadcast_domain_for_port(
fake.NODE_NAME, fake.PORT, domain=fake.BROADCAST_DOMAIN, fake.NODE_NAME, fake.PORT, domain=fake.BROADCAST_DOMAIN,
ipspace=fake.IPSPACE_NAME) ipspace=fake.IPSPACE_NAME, mtu=fake.MTU)
self.client._get_broadcast_domain_for_port.assert_has_calls([ self.client._get_broadcast_domain_for_port.assert_called_once_with(
mock.call(fake.NODE_NAME, fake.PORT)]) fake.NODE_NAME, fake.PORT)
self.client._remove_port_from_broadcast_domain.assert_has_calls([ self.client._remove_port_from_broadcast_domain.assert_called_once_with(
mock.call(fake.NODE_NAME, fake.PORT, 'other_domain', fake.NODE_NAME, fake.PORT, 'other_domain', fake.IPSPACE_NAME)
fake.IPSPACE_NAME)]) self.client._broadcast_domain_exists.assert_called_once_with(
self.client._broadcast_domain_exists.assert_has_calls([ fake.BROADCAST_DOMAIN, fake.IPSPACE_NAME)
mock.call(fake.BROADCAST_DOMAIN, fake.IPSPACE_NAME)])
self.assertFalse(self.client._create_broadcast_domain.called) self.assertFalse(self.client._create_broadcast_domain.called)
self.client._add_port_to_broadcast_domain.assert_has_calls([ self.client._modify_broadcast_domain.assert_called_once_with(
mock.call(fake.NODE_NAME, fake.PORT, fake.BROADCAST_DOMAIN, fake.BROADCAST_DOMAIN, fake.IPSPACE_NAME, fake.MTU)
fake.IPSPACE_NAME)]) self.client._add_port_to_broadcast_domain.assert_called_once_with(
fake.NODE_NAME, fake.PORT, fake.BROADCAST_DOMAIN,
fake.IPSPACE_NAME)
def test_ensure_broadcast_domain_for_port_no_domain(self): def test_ensure_broadcast_domain_for_port_no_domain(self):
@ -1050,23 +1056,25 @@ class NetAppClientCmodeTestCase(test.TestCase):
'_broadcast_domain_exists', '_broadcast_domain_exists',
mock.Mock(return_value=False)) mock.Mock(return_value=False))
self.mock_object(self.client, '_create_broadcast_domain') self.mock_object(self.client, '_create_broadcast_domain')
self.mock_object(self.client, '_modify_broadcast_domain')
self.mock_object(self.client, '_remove_port_from_broadcast_domain') self.mock_object(self.client, '_remove_port_from_broadcast_domain')
self.mock_object(self.client, '_add_port_to_broadcast_domain') self.mock_object(self.client, '_add_port_to_broadcast_domain')
self.client._ensure_broadcast_domain_for_port( self.client._ensure_broadcast_domain_for_port(
fake.NODE_NAME, fake.PORT, domain=fake.BROADCAST_DOMAIN, fake.NODE_NAME, fake.PORT, domain=fake.BROADCAST_DOMAIN,
ipspace=fake.IPSPACE_NAME) ipspace=fake.IPSPACE_NAME, mtu=fake.MTU)
self.client._get_broadcast_domain_for_port.assert_has_calls([ self.client._get_broadcast_domain_for_port.assert_called_once_with(
mock.call(fake.NODE_NAME, fake.PORT)]) fake.NODE_NAME, fake.PORT)
self.assertFalse(self.client._remove_port_from_broadcast_domain.called) self.assertFalse(self.client._remove_port_from_broadcast_domain.called)
self.client._broadcast_domain_exists.assert_has_calls([ self.client._broadcast_domain_exists.assert_called_once_with(
mock.call(fake.BROADCAST_DOMAIN, fake.IPSPACE_NAME)]) fake.BROADCAST_DOMAIN, fake.IPSPACE_NAME)
self.client._create_broadcast_domain.assert_has_calls([ self.client._create_broadcast_domain.assert_called_once_with(
mock.call(fake.BROADCAST_DOMAIN, fake.IPSPACE_NAME)]) fake.BROADCAST_DOMAIN, fake.IPSPACE_NAME, fake.MTU)
self.client._add_port_to_broadcast_domain.assert_has_calls([ self.assertFalse(self.client._modify_broadcast_domain.called)
mock.call(fake.NODE_NAME, fake.PORT, fake.BROADCAST_DOMAIN, self.client._add_port_to_broadcast_domain.assert_called_once_with(
fake.IPSPACE_NAME)]) fake.NODE_NAME, fake.PORT, fake.BROADCAST_DOMAIN,
fake.IPSPACE_NAME)
def test_get_broadcast_domain_for_port(self): def test_get_broadcast_domain_for_port(self):
@ -1177,7 +1185,7 @@ class NetAppClientCmodeTestCase(test.TestCase):
result = self.client._create_broadcast_domain(fake.BROADCAST_DOMAIN, result = self.client._create_broadcast_domain(fake.BROADCAST_DOMAIN,
fake.IPSPACE_NAME, fake.IPSPACE_NAME,
mtu=fake.MTU) fake.MTU)
net_port_broadcast_domain_create_args = { net_port_broadcast_domain_create_args = {
'ipspace': fake.IPSPACE_NAME, 'ipspace': fake.IPSPACE_NAME,
@ -1189,6 +1197,24 @@ class NetAppClientCmodeTestCase(test.TestCase):
mock.call('net-port-broadcast-domain-create', mock.call('net-port-broadcast-domain-create',
net_port_broadcast_domain_create_args)]) net_port_broadcast_domain_create_args)])
def test_modify_broadcast_domain(self):
self.mock_object(self.client, 'send_request')
result = self.client._modify_broadcast_domain(fake.BROADCAST_DOMAIN,
fake.IPSPACE_NAME,
fake.MTU)
net_port_broadcast_domain_modify_args = {
'ipspace': fake.IPSPACE_NAME,
'broadcast-domain': fake.BROADCAST_DOMAIN,
'mtu': fake.MTU,
}
self.assertIsNone(result)
self.client.send_request.assert_called_once_with(
'net-port-broadcast-domain-modify',
net_port_broadcast_domain_modify_args)
def test_delete_broadcast_domain(self): def test_delete_broadcast_domain(self):
self.mock_object(self.client, 'send_request') self.mock_object(self.client, 'send_request')

View File

@ -538,7 +538,19 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
self.assertEqual('os_132dbb10-9a36-46f2-8d89-3d909830c356', result) self.assertEqual('os_132dbb10-9a36-46f2-8d89-3d909830c356', result)
def test_create_lif(self): @ddt.data(fake.MTU, None, 'not-present')
def test_create_lif(self, mtu):
"""Tests cases where MTU is a valid value, None or not present."""
expected_mtu = (mtu if mtu not in (None, 'not-present') else
fake.DEFAULT_MTU)
network_allocations = copy.deepcopy(
fake.NETWORK_INFO['network_allocations'][0])
network_allocations['mtu'] = mtu
if mtu == 'not-present':
network_allocations.pop('mtu')
vserver_client = mock.Mock() vserver_client = mock.Mock()
vserver_client.network_interface_exists = mock.Mock( vserver_client.network_interface_exists = mock.Mock(
@ -552,12 +564,12 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
'fake_ipspace', 'fake_ipspace',
'fake_node', 'fake_node',
'fake_lif', 'fake_lif',
fake.NETWORK_INFO['network_allocations'][0]) network_allocations)
self.library._client.create_network_interface.assert_has_calls([ self.library._client.create_network_interface.assert_has_calls([
mock.call('10.10.10.10', '255.255.255.0', '1000', 'fake_node', mock.call('10.10.10.10', '255.255.255.0', '1000', 'fake_node',
'fake_port', 'fake_vserver', 'fake_lif', 'fake_port', 'fake_vserver', 'fake_lif',
'fake_ipspace')]) 'fake_ipspace', expected_mtu)])
def test_create_lif_if_nonexistent_already_present(self): def test_create_lif_if_nonexistent_already_present(self):

View File

@ -65,6 +65,8 @@ SHARE_TYPE_ID = '26e89a5b-960b-46bb-a8cf-0778e653098f'
SHARE_TYPE_NAME = 'fake_share_type' SHARE_TYPE_NAME = 'fake_share_type'
IPSPACE = 'fake_ipspace' IPSPACE = 'fake_ipspace'
IPSPACE_ID = '27d38c27-3e8b-4d7d-9d91-fcf295e3ac8f' IPSPACE_ID = '27d38c27-3e8b-4d7d-9d91-fcf295e3ac8f'
MTU = 1234
DEFAULT_MTU = 1500
CLIENT_KWARGS = { CLIENT_KWARGS = {
'username': 'admin', 'username': 'admin',
@ -219,6 +221,7 @@ USER_NETWORK_ALLOCATIONS = [
'segmentation_id': '1000', 'segmentation_id': '1000',
'network_type': 'vlan', 'network_type': 'vlan',
'label': 'user', 'label': 'user',
'mtu': MTU,
}, },
{ {
'id': '7eabdeed-bad2-46ea-bd0f-a33884c869e0', 'id': '7eabdeed-bad2-46ea-bd0f-a33884c869e0',
@ -227,6 +230,7 @@ USER_NETWORK_ALLOCATIONS = [
'segmentation_id': '1000', 'segmentation_id': '1000',
'network_type': 'vlan', 'network_type': 'vlan',
'label': 'user', 'label': 'user',
'mtu': MTU,
} }
] ]
@ -238,6 +242,7 @@ ADMIN_NETWORK_ALLOCATIONS = [
'segmentation_id': None, 'segmentation_id': None,
'network_type': 'flat', 'network_type': 'flat',
'label': 'admin', 'label': 'admin',
'mtu': MTU,
}, },
] ]

View File

@ -0,0 +1,6 @@
---
features:
- The NetApp cDOT driver operating in
``driver_handles_share_servers = True`` mode applies the Maximum
Transmission Unit (MTU) from the network provider where available when
creating Logical Interfaces (LIFs) for newly created share servers.