Merge "[DVR] Send allowed address pairs info to the L3 agents" into stable/train

This commit is contained in:
Zuul 2021-06-07 17:36:58 +00:00 committed by Gerrit Code Review
commit 763a3cd38f
7 changed files with 63 additions and 12 deletions

View File

@ -317,6 +317,11 @@ class DvrLocalRouter(dvr_router_base.DvrRouterBase):
p['mac_address'],
subnet_id,
'add')
for allowed_address_pair in p.get('allowed_address_pairs', []):
self._update_arp_entry(allowed_address_pair['ip_address'],
allowed_address_pair['mac_address'],
subnet_id,
'add')
self._process_arp_cache_for_internal_port(subnet_id)
@staticmethod

View File

@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
#
import collections
from neutron_lib.api.definitions import allowedaddresspairs as addr_apidef
from neutron_lib.api.definitions import port as port_def
@ -65,6 +66,17 @@ class AllowedAddressPairsMixin(object):
return [self._make_allowed_address_pairs_dict(pair.db_obj)
for pair in pairs]
def get_allowed_address_pairs_for_ports(self, context, port_ids):
pairs = (
obj_addr_pair.AllowedAddressPair.
get_allowed_address_pairs_for_ports(
context, port_ids=port_ids))
result = collections.defaultdict(list)
for pair in pairs:
result[pair.port_id].append(
self._make_allowed_address_pairs_dict(pair.db_obj))
return result
@staticmethod
@resource_extend.extends([port_def.COLLECTION_NAME])
def _extend_port_dict_allowed_address_pairs(port_res, port_db):

View File

@ -1296,11 +1296,23 @@ class L3_NAT_with_dvr_db_mixin(_DVRAgentInterfaceMixin,
def get_ports_under_dvr_connected_subnet(self, context, subnet_id):
query = dvr_mac_db.get_ports_query_by_subnet_and_ip(context, subnet_id)
ports = [p for p in query.all() if is_port_bound(p)]
return [
# TODO(slaweq): if there would be way to pass to neutron-lib only
# list of extensions which actually should be processed, than setting
# process_extensions=True below could avoid that second loop and
# getting allowed_address_pairs for each of the ports
ports_list = [
self.l3plugin._core_plugin._make_port_dict(
port, process_extensions=False)
for port in ports
]
ports_ids = [p['id'] for p in ports_list]
allowed_address_pairs = (
self._core_plugin.get_allowed_address_pairs_for_ports(
context, ports_ids))
for port in ports_list:
port['allowed_address_pairs'] = allowed_address_pairs.get(
port['id'], [])
return ports_list
def is_distributed_router(router):

View File

@ -10,6 +10,7 @@
# License for the specific language governing permissions and limitations
# under the License.
from neutron_lib.db import api as db_api
from neutron_lib.utils import net as net_utils
from neutron.db.models import allowed_address_pair as models
@ -61,3 +62,12 @@ class AllowedAddressPair(base.NeutronDbObject):
fields['mac_address'] = net_utils.AuthenticEUI(
fields['mac_address'])
return fields
@classmethod
def get_allowed_address_pairs_for_ports(cls, context, port_ids):
with db_api.CONTEXT_READER.using(context):
query = context.session.query(models.AllowedAddressPair).filter(
models.AllowedAddressPair.port_id.in_(port_ids))
pairs = [cls._load_object(context, db_obj)
for db_obj in query.all()]
return pairs

View File

@ -1006,21 +1006,25 @@ class TestDvrRouter(DvrRouterTestFramework, framework.L3AgentTestFramework):
# cache is properly populated.
self.agent.conf.agent_mode = 'dvr_snat'
router_info = self.generate_dvr_router_info(enable_snat=True)
expected_neighbor = '35.4.1.10'
expected_neighbors = ['35.4.1.10', '10.0.0.10']
port_data = {
'fixed_ips': [{'ip_address': expected_neighbor}],
'fixed_ips': [{'ip_address': expected_neighbors[0]}],
'mac_address': 'fa:3e:aa:bb:cc:dd',
'device_owner': DEVICE_OWNER_COMPUTE
'device_owner': DEVICE_OWNER_COMPUTE,
'allowed_address_pairs': [
{'ip_address': expected_neighbors[1],
'mac_address': 'fa:3e:aa:bb:cc:dd'}]
}
self.agent.plugin_rpc.get_ports_by_subnet.return_value = [port_data]
router1 = self.manage_router(self.agent, router_info)
internal_device = router1.get_internal_device_name(
router_info['_interfaces'][0]['id'])
neighbor = ip_lib.dump_neigh_entries(4, internal_device,
router1.ns_name,
dst=expected_neighbor)
self.assertNotEqual([], neighbor)
self.assertEqual(expected_neighbor, neighbor[0]['dst'])
for expected_neighbor in expected_neighbors:
neighbor = ip_lib.dump_neigh_entries(4, internal_device,
router1.ns_name,
dst=expected_neighbor)
self.assertNotEqual([], neighbor)
self.assertEqual(expected_neighbor, neighbor[0]['dst'])
def _assert_rfp_fpr_mtu(self, router, expected_mtu=1500):
dev_mtu = self.get_device_mtu(

View File

@ -531,7 +531,10 @@ class TestDvrRouterOperations(base.BaseTestCase):
'device_owner': lib_constants.DEVICE_OWNER_DHCP,
'fixed_ips': [{'ip_address': '1.2.3.4',
'prefixlen': 24,
'subnet_id': subnet_id}]},
'subnet_id': subnet_id}],
'allowed_address_pairs': [
{'ip_address': '10.20.30.40',
'mac_address': '00:11:22:33:44:55'}]},
{'mac_address': '11:22:33:44:55:66',
'device_owner': lib_constants.DEVICE_OWNER_LOADBALANCER,
'fixed_ips': [{'ip_address': '1.2.3.5',
@ -553,8 +556,9 @@ class TestDvrRouterOperations(base.BaseTestCase):
'_process_arp_cache_for_internal_port') as parp:
ri._set_subnet_arp_info(subnet_id)
self.assertEqual(1, parp.call_count)
self.mock_ip_dev.neigh.add.assert_called_once_with(
'1.2.3.4', '00:11:22:33:44:55')
self.mock_ip_dev.neigh.add.assert_has_calls([
mock.call('1.2.3.4', '00:11:22:33:44:55'),
mock.call('10.20.30.40', '00:11:22:33:44:55')])
# Test negative case
router['distributed'] = False

View File

@ -1254,6 +1254,8 @@ class L3DvrTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase):
router = self._create_router(router_dict)
with self.network() as network,\
self.subnet(network=network) as subnet:
self.mixin._core_plugin.get_allowed_address_pairs_for_ports = (
mock.Mock())
fake_bound_ports_ids = []
def fake_is_port_bound(port):
@ -1275,6 +1277,8 @@ class L3DvrTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase):
self.ctx, subnet['subnet']['id'])
dvr_subnet_ports_ids = [p['id'] for p in dvr_subnet_ports]
self.assertItemsEqual(fake_bound_ports_ids, dvr_subnet_ports_ids)
(self.mixin._core_plugin.get_allowed_address_pairs_for_ports.
assert_called_once_with(self.ctx, dvr_subnet_ports_ids))
@mock.patch.object(plugin_utils, 'can_port_be_bound_to_virtual_bridge',
return_value=True)