Browse Source

Fix port update deferred IP allocation with host_id + new MAC

IP allocation was initially deffered due to lack of binding
information. On port update with both `mac_address` and
`binding_host_id`` in the request, 'fixed_ips: []' was
appended to the new_port data. This caused the check for
fixed_ips_requested to return True, which in turn cause
deferred_ip_allocation to evaluates False.

Only set the new_port default fixed_ips to original_ips if
the original port had fixed_ips.


Closes-Bug: #1811905
Change-Id: If98a82f8432b09a29f9d0cc6627e9649b43bc4a1
(cherry picked from commit b0d758e1b4)
(cherry picked from commit 1e76ddf711)
Harald Jensås 1 year ago
committed by Slawek Kaplonski
3 changed files with 39 additions and 2 deletions
  1. +8
  2. +21
  3. +10

+ 8
- 2
neutron/db/ View File

@@ -340,8 +340,14 @@ class IpamPluggableBackend(ipam_backend_mixin.IpamBackendMixin):
original = self._make_port_dict(db_port, process_extensions=False)
if original.get('mac_address') != new_mac:
original_ips = original.get('fixed_ips', [])
new_ips = new_port.setdefault('fixed_ips', original_ips)
new_ips_subnets = [new_ip['subnet_id'] for new_ip in new_ips]
# NOTE(hjensas): Only set the default for 'fixed_ips' in
# new_port if the original port or new_port actually have IPs.
# Setting the default to [] breaks deferred IP allocation.
# See Bug:
if original_ips or new_port.get('fixed_ips'):
new_ips = new_port.setdefault('fixed_ips', original_ips)
new_ips_subnets = [new_ip['subnet_id']
for new_ip in new_ips]
for orig_ip in original_ips:
if ipv6_utils.is_eui64_address(orig_ip.get('ip_address')):
subnet_to_delete = {}

+ 21
- 0
neutron/tests/unit/extensions/ View File

@@ -1434,6 +1434,27 @@ class TestSegmentAwareIpam(SegmentAwareIpamTestCase):
# Since the new host is in the same segment, it succeeds.
self.assertEqual(webob.exc.HTTPOk.code, response.status_int)

def test_port_update_deferred_allocation_binding_info_and_new_mac(self):
"""Binding information and new mac address is provided on update"""
network, segment, subnet = self._create_test_segment_with_subnet()

# Map the host to the segment
self._setup_host_mappings([(segment['segment']['id'], 'fakehost')])

port = self._create_deferred_ip_port(network)

# Try requesting an IP (but the only subnet is on a segment)
data = {'port': {portbindings.HOST_ID: 'fakehost',
'mac_address': '00:00:00:00:00:01'}}
port_id = port['port']['id']
port_req = self.new_update_request('ports', data, port_id)
response = port_req.get_response(self.api)

# Port update succeeds and allocates a new IP address.
self.assertEqual(webob.exc.HTTPOk.code, response.status_int)
self._assert_one_ip_in_subnet(response, subnet['subnet']['cidr'])

class TestSegmentAwareIpamML2(TestSegmentAwareIpam):

+ 10
- 0
releasenotes/notes/fix-deferred-alloction-when-new-mac-in-same-request-as-binding-data-2a01c1ed1a8eff66.yaml View File

@@ -0,0 +1,10 @@
- |
Fixes an issue causing IP allocation on port update to fail when the
initial IP allocation was deferred due to lack of binding info. If both the
port mac_address and binding info (binding_host_id) were updated in the
same request, the fixed_ips field was added to the request internally. The
code to complete the deferred allocation failed to execute in that case.
(For more information see bug `1811905