Skip to content

Commit b3dc3ff

Browse files
brianphaleyrubasov
authored andcommitted
Change flag check order in wait_until_address_ready()
When DAD fails on an IPv6 address, both the 'dadfailed' and 'tentative' flags will be set. So change the code to check for 'dadfailed' first, just to be explicit. Added better unit testing to cover more cases as well. Trivialfix Change-Id: I2dddc296826e5ab5e057c32a554e353577cc36e8 (cherry picked from commit 1d22cfa) (cherry picked from commit 0c18181)
1 parent ce16399 commit b3dc3ff

File tree

2 files changed

+28
-6
lines changed

2 files changed

+28
-6
lines changed

neutron/agent/linux/ip_lib.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -578,9 +578,10 @@ def filter_device(device, filters):
578578
return filtered_devices
579579

580580
def wait_until_address_ready(self, address, wait_time=30):
581-
"""Wait until an address is no longer marked 'tentative'
581+
"""Wait until an address is no longer marked 'tentative' or 'dadfailed'
582582
583-
raises AddressNotReady if times out or address not present on interface
583+
raises AddressNotReady if times out, address not present on interface
584+
or DAD fails
584585
"""
585586
def is_address_ready():
586587
try:
@@ -589,12 +590,14 @@ def is_address_ready():
589590
raise AddressNotReady(
590591
address=address,
591592
reason=_('Address not present on interface'))
592-
if not addr_info['tentative']:
593-
return True
593+
# Since both 'dadfailed' and 'tentative' will be set if DAD fails,
594+
# check 'dadfailed' first just to be explicit
594595
if addr_info['dadfailed']:
595596
raise AddressNotReady(
596597
address=address, reason=_('Duplicate address detected'))
597-
return False
598+
if addr_info['tentative']:
599+
return False
600+
return True
598601
errmsg = _("Exceeded %s second limit waiting for "
599602
"address to leave the tentative state.") % wait_time
600603
common_utils.wait_until_true(

neutron/tests/unit/agent/linux/test_ip_lib.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -776,7 +776,8 @@ def test_flush(self, flush):
776776
6, self.parent.name, self.addr_cmd._parent.namespace)
777777

778778
def test_wait_until_address_ready(self):
779-
self.addr_cmd.list = mock.Mock(return_value=[{'tentative': False}])
779+
self.addr_cmd.list = mock.Mock(
780+
return_value=[{'tentative': False, 'dadfailed': False}])
780781
# this address is not tentative or failed so it should return
781782
self.assertIsNone(self.addr_cmd.wait_until_address_ready(
782783
'2001:470:9:1224:fd91:272:581e:3a32'))
@@ -786,6 +787,24 @@ def test_wait_until_address_ready_non_existent_address(self):
786787
with testtools.ExpectedException(ip_lib.AddressNotReady):
787788
self.addr_cmd.wait_until_address_ready('abcd::1234')
788789

790+
def test_wait_until_address_dadfailed(self):
791+
self.addr_cmd.list = mock.Mock(
792+
return_value=[{'tentative': True, 'dadfailed': True}])
793+
with testtools.ExpectedException(ip_lib.AddressNotReady):
794+
self.addr_cmd.wait_until_address_ready('abcd::1234')
795+
796+
@mock.patch.object(common_utils, 'wait_until_true')
797+
def test_wait_until_address_ready_success_one_timeout(self, mock_wuntil):
798+
tentative_address = 'fe80::3023:39ff:febc:22ae'
799+
self.addr_cmd.list = mock.Mock(return_value=[
800+
dict(scope='link', dadfailed=False, tentative=True, dynamic=False,
801+
cidr=tentative_address + '/64'),
802+
dict(scope='link', dadfailed=False, tentative=False, dynamic=False,
803+
cidr=tentative_address + '/64')])
804+
self.assertIsNone(self.addr_cmd.wait_until_address_ready(
805+
tentative_address, wait_time=3))
806+
self.assertEqual(1, mock_wuntil.call_count)
807+
789808
def test_wait_until_address_ready_timeout(self):
790809
tentative_address = 'fe80::3023:39ff:febc:22ae'
791810
self.addr_cmd.list = mock.Mock(return_value=[

0 commit comments

Comments
 (0)