Merge "Move arp device check out of loop"

This commit is contained in:
Zuul 2020-01-28 08:29:55 +00:00 committed by Gerrit Code Review
commit bbcaed7f34
3 changed files with 38 additions and 21 deletions

View File

@ -53,8 +53,10 @@ class AgentMixin(object):
ip = arp_table['ip_address']
mac = arp_table['mac_address']
subnet_id = arp_table['subnet_id']
ri._update_arp_entry(ip, mac, subnet_id, action)
device, device_exists = ri.get_arp_related_dev(subnet_id)
ri._update_arp_entry(ip, mac, subnet_id, action,
device,
device_exists=device_exists)
def add_arp_entry(self, context, payload):
"""Add arp entry into router namespace. Called from RPC."""

View File

@ -223,12 +223,15 @@ class DvrLocalRouter(dvr_router_base.DvrRouterBase):
def _process_arp_cache_for_internal_port(self, subnet_id):
"""Function to process the cached arp entries."""
arp_remove = set()
device, device_exists = self.get_arp_related_dev(subnet_id)
for arp_entry in self._pending_arp_set:
if subnet_id == arp_entry.subnet_id:
try:
state = self._update_arp_entry(
arp_entry.ip, arp_entry.mac,
arp_entry.subnet_id, arp_entry.operation)
arp_entry.subnet_id, arp_entry.operation,
device=device,
device_exists=device_exists)
except Exception:
state = False
if state:
@ -246,18 +249,13 @@ class DvrLocalRouter(dvr_router_base.DvrRouterBase):
arp_delete.add(arp_entry)
self._pending_arp_set -= arp_delete
def _update_arp_entry(self, ip, mac, subnet_id, operation):
def _update_arp_entry(
self, ip, mac, subnet_id, operation, device,
device_exists=True):
"""Add or delete arp entry into router namespace for the subnet."""
port = self._get_internal_port(subnet_id)
# update arp entry only if the subnet is attached to the router
if not port:
return False
try:
# TODO(mrsmith): optimize the calls below for bulk calls
interface_name = self.get_internal_device_name(port['id'])
device = ip_lib.IPDevice(interface_name, namespace=self.ns_name)
if device.exists():
if device_exists:
if operation == 'add':
device.neigh.add(ip, mac)
elif operation == 'delete':
@ -276,6 +274,16 @@ class DvrLocalRouter(dvr_router_base.DvrRouterBase):
with excutils.save_and_reraise_exception():
LOG.exception("DVR: Failed updating arp entry")
def get_arp_related_dev(self, subnet_id):
port = self._get_internal_port(subnet_id)
# update arp entry only if the subnet is attached to the router
if not port:
return None, False
interface_name = self.get_internal_device_name(port['id'])
device = ip_lib.IPDevice(interface_name, namespace=self.ns_name)
device_exists = device.exists()
return device, device_exists
def _set_subnet_arp_info(self, subnet_id):
"""Set ARP info retrieved from Plugin for existing ports."""
# TODO(Carl) Can we eliminate the need to make this RPC while
@ -284,6 +292,7 @@ class DvrLocalRouter(dvr_router_base.DvrRouterBase):
ignored_device_owners = (
lib_constants.ROUTER_INTERFACE_OWNERS +
tuple(common_utils.get_dvr_allowed_address_pair_device_owners()))
device, device_exists = self.get_arp_related_dev(subnet_id)
for p in subnet_ports:
if p['device_owner'] not in ignored_device_owners:
@ -291,7 +300,9 @@ class DvrLocalRouter(dvr_router_base.DvrRouterBase):
self._update_arp_entry(fixed_ip['ip_address'],
p['mac_address'],
subnet_id,
'add')
'add',
device=device,
device_exists=device_exists)
self._process_arp_cache_for_internal_port(subnet_id)
@staticmethod
@ -525,10 +536,14 @@ class DvrLocalRouter(dvr_router_base.DvrRouterBase):
self.enable_snat_redirect_rules(ex_gw_port)
for port in self.get_snat_interfaces():
for ip in port['fixed_ips']:
subnet_id = ip['subnet_id']
device, device_exists = self.get_arp_related_dev(subnet_id)
self._update_arp_entry(ip['ip_address'],
port['mac_address'],
ip['subnet_id'],
'add')
subnet_id,
'add',
device=device,
device_exists=device_exists)
def external_gateway_updated(self, ex_gw_port, interface_name):
pass

View File

@ -561,14 +561,14 @@ class TestDvrRouterOperations(base.BaseTestCase):
payload = {'arp_table': arp_table, 'router_id': router['id']}
agent.add_arp_entry(None, payload)
def test__update_arp_entry_with_no_subnet(self):
def test_get_arp_related_dev_no_subnet(self):
self._set_ri_kwargs(mock.sentinel.agent,
'foo_router_id',
{'distributed': True, 'gw_port_host': HOSTNAME})
ri = dvr_router.DvrLocalRouter(HOSTNAME, **self.ri_kwargs)
ri.get_internal_device_name = mock.Mock()
ri._update_arp_entry(mock.ANY, mock.ANY, 'foo_subnet_id', 'add')
self.assertFalse(ri.get_internal_device_name.call_count)
with mock.patch('neutron.agent.linux.ip_lib.IPDevice') as f:
ri.get_arp_related_dev('foo_subnet_id')
self.assertFalse(f.call_count)
def _setup_test_for_arp_entry_cache(self):
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
@ -585,9 +585,9 @@ class TestDvrRouterOperations(base.BaseTestCase):
state = True
with mock.patch('neutron.agent.linux.ip_lib.IPDevice') as rtrdev,\
mock.patch.object(ri, '_cache_arp_entry') as arp_cache:
rtrdev.return_value.exists.return_value = False
state = ri._update_arp_entry(
mock.ANY, mock.ANY, subnet_id, 'add')
mock.ANY, mock.ANY, subnet_id, 'add',
mock.ANY, device_exists=False)
self.assertFalse(state)
self.assertTrue(arp_cache.called)
arp_cache.assert_called_once_with(mock.ANY, mock.ANY,