Stop arping when interface gets deleted

It is possible for an interface to be added to a
router, have arping get started for it in a thread,
then immediately remove the interface, causing
arping errors in the l3-agent log.  This concurrent
deletion should be handled more gracefully by
just logging a warning on the first detection and
returning early.

Ocata changes: added translation marker to a warning message because
it's enforced in the branch. (In Pike, we reversed the direction, not
adding those markers to log messages.)

Change-Id: I615b60561b3b7f8c950d5f412fb4cdf7877b98f7
Closes-bug: #1696893
(cherry picked from commit 739daaa955)
This commit is contained in:
Brian Haley 2017-06-08 22:40:19 -04:00 committed by Brian Haley
parent 609d463473
commit be13101ec4
2 changed files with 29 additions and 1 deletions

View File

@ -1077,15 +1077,23 @@ def _arping(ns_name, iface_name, address, count, log_exception):
# platforms (>=Ubuntu 14.04), arping exit code can be 1.
ip_wrapper.netns.execute(arping_cmd, extra_ok_codes=[1])
except Exception as exc:
# Since this is spawned in a thread and executed 2 seconds
# apart, the interface may have been deleted while we were
# sleeping. Downgrade message to a warning and return early.
exists = device_exists(iface_name, namespace=ns_name)
msg = _("Failed sending gratuitous ARP to %(addr)s on "
"%(iface)s in namespace %(ns)s: %(err)s")
logger_method = LOG.exception
if not log_exception:
if not (log_exception or exists):
logger_method = LOG.warning
logger_method(msg, {'addr': address,
'iface': iface_name,
'ns': ns_name,
'err': exc})
if not exists:
LOG.warning(_LW("Interface %s might have been deleted "
"concurrently"), iface_name)
return
def send_ip_addr_adv_notif(

View File

@ -1683,6 +1683,26 @@ class TestArpPing(TestIPCmdBase):
ip_wrapper.netns.execute.assert_any_call(arping_cmd,
extra_ok_codes=[1])
@mock.patch.object(ip_lib, 'IPWrapper')
@mock.patch('eventlet.spawn_n')
def test_send_ipv4_addr_adv_notif_nodev(self, spawn_n, mIPWrapper):
spawn_n.side_effect = lambda f: f()
ip_wrapper = mIPWrapper(namespace=mock.sentinel.ns_name)
ip_wrapper.netns.execute.side_effect = RuntimeError
ARPING_COUNT = 3
address = '20.0.0.1'
with mock.patch.object(ip_lib, 'device_exists', return_value=False):
ip_lib.send_ip_addr_adv_notif(mock.sentinel.ns_name,
mock.sentinel.iface_name,
address,
ARPING_COUNT)
# should return early with a single call when ENODEV
mIPWrapper.assert_has_calls([
mock.call(namespace=mock.sentinel.ns_name),
mock.call().netns.execute(mock.ANY, extra_ok_codes=mock.ANY)
] * 1)
@mock.patch('eventlet.spawn_n')
def test_no_ipv6_addr_notif(self, spawn_n):
ipv6_addr = 'fd00::1'