Install DVR src to MAC flow for AAPs
Add missing flows in distributed virtual router for MAC address specified in allowed address pairs. Closes-Bug: #2093248 Change-Id: Ife280712d6f45704a96a77ec3bfc07daa2e8e229
This commit is contained in:
committed by
Brian Haley
parent
da06d1a7d8
commit
1364715541
@@ -65,6 +65,13 @@ class DVRServerRpcApi:
|
||||
return cctxt.call(
|
||||
context, 'get_subnet_for_dvr', subnet=subnet, fixed_ips=fixed_ips)
|
||||
|
||||
@log_helpers.log_method_call
|
||||
def get_ports(self, context, filters):
|
||||
# NOTE(mtomaska): The MetadataRpcCallback (server side) API version 1.0
|
||||
# exposes get_ports, under the PLUGIN topic and None namespace.
|
||||
cctxt = self.client.prepare()
|
||||
return cctxt.call(context, 'get_ports', filters=filters)
|
||||
|
||||
|
||||
class DVRServerRpcCallback:
|
||||
"""Plugin-side RPC (implementation) for agent-to-plugin interaction.
|
||||
|
||||
@@ -28,6 +28,7 @@ from osprofiler import profiler
|
||||
from neutron.agent.common import ovs_lib
|
||||
from neutron.agent.linux.openvswitch_firewall import firewall as ovs_firewall
|
||||
from neutron.common import utils as n_utils
|
||||
from neutron.ipam import utils as ipam_utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
@@ -530,6 +531,12 @@ class OVSDVRNeutronAgent:
|
||||
|
||||
def _bind_port_on_dvr_subnet(self, port, lvm, fixed_ips,
|
||||
device_owner):
|
||||
ports = self.plugin_rpc.get_ports(self.context,
|
||||
filters={'id': [port.vif_id]})
|
||||
aaps = []
|
||||
if len(ports) == 1:
|
||||
aaps = ports[0].get("allowed_address_pairs", [])
|
||||
|
||||
# Handle new compute port added use-case
|
||||
subnet_uuid = None
|
||||
for ips in fixed_ips:
|
||||
@@ -566,12 +573,24 @@ class OVSDVRNeutronAgent:
|
||||
if lvm.network_type in ovs_constants.DVR_PHYSICAL_NETWORK_TYPES:
|
||||
vlan_to_use = lvm.segmentation_id
|
||||
# create a rule for this vm port
|
||||
dst_port = ovsport.get_ofport()
|
||||
self.int_br.install_dvr_to_src_mac(
|
||||
network_type=lvm.network_type,
|
||||
vlan_tag=vlan_to_use,
|
||||
gateway_mac=subnet_info['gateway_mac'],
|
||||
dst_mac=ovsport.get_mac(),
|
||||
dst_port=ovsport.get_ofport())
|
||||
dst_port=dst_port)
|
||||
for aap in aaps:
|
||||
aap_ip_cidr = netaddr.IPNetwork(aap['ip_address'])
|
||||
if n_utils.is_cidr_host(str(aap_ip_cidr.cidr)):
|
||||
if ipam_utils.check_subnet_ip(
|
||||
ldm.subnet['cidr'], str(aap_ip_cidr.ip)):
|
||||
self.int_br.install_dvr_to_src_mac(
|
||||
network_type=lvm.network_type,
|
||||
vlan_tag=vlan_to_use,
|
||||
gateway_mac=subnet_info['gateway_mac'],
|
||||
dst_mac=aap["mac_address"],
|
||||
dst_port=dst_port)
|
||||
|
||||
def _bind_centralized_snat_port_on_dvr_subnet(self, port, lvm,
|
||||
fixed_ips, device_owner):
|
||||
@@ -765,6 +784,12 @@ class OVSDVRNeutronAgent:
|
||||
self.local_ports.pop(port.vif_id, None)
|
||||
|
||||
def _unbind_port_on_dvr_subnet(self, port, lvm):
|
||||
ports = self.plugin_rpc.get_ports(self.context,
|
||||
filters={'id': [port.vif_id]})
|
||||
aaps = []
|
||||
if len(ports) == 1:
|
||||
aaps = ports[0].get("allowed_address_pairs", [])
|
||||
|
||||
ovsport = self.local_ports[port.vif_id]
|
||||
# This confirms that this compute port being removed belonged
|
||||
# to a dvr hosted subnet.
|
||||
@@ -774,6 +799,16 @@ class OVSDVRNeutronAgent:
|
||||
for sub_uuid in subnet_ids:
|
||||
if sub_uuid not in self.local_dvr_map:
|
||||
continue
|
||||
if aaps:
|
||||
local_compute_ports = (
|
||||
self.plugin_rpc.get_ports_on_host_by_subnet(
|
||||
self.context, self.host, sub_uuid))
|
||||
local_aap_macs = set()
|
||||
for lport in local_compute_ports:
|
||||
if lport.id != port.vif_id:
|
||||
local_aap_macs.update({
|
||||
aap["mac_address"] for aap in lport.get(
|
||||
"allowed_address_pairs", [])})
|
||||
ldm = self.local_dvr_map[sub_uuid]
|
||||
ldm.remove_compute_ofport(port.vif_id)
|
||||
vlan_to_use = lvm.vlan
|
||||
@@ -783,6 +818,15 @@ class OVSDVRNeutronAgent:
|
||||
self.int_br.delete_dvr_to_src_mac(
|
||||
network_type=lvm.network_type,
|
||||
vlan_tag=vlan_to_use, dst_mac=ovsport.get_mac())
|
||||
for aap in aaps:
|
||||
aap_ip_cidr = netaddr.IPNetwork(aap['ip_address'])
|
||||
if n_utils.is_cidr_host(str(aap_ip_cidr.cidr)):
|
||||
if ipam_utils.check_subnet_ip(ldm.subnet['cidr'],
|
||||
str(aap_ip_cidr.ip)):
|
||||
if aap["mac_address"] not in local_aap_macs:
|
||||
self.int_br.delete_dvr_to_src_mac(
|
||||
network_type=lvm.network_type,
|
||||
vlan_tag=vlan_to_use, dst_mac=aap["mac_address"])
|
||||
# release port state
|
||||
self.local_ports.pop(port.vif_id, None)
|
||||
|
||||
|
||||
@@ -3403,6 +3403,9 @@ class TestOvsDvrNeutronAgent:
|
||||
mock.patch.object(self.agent.dvr_agent.plugin_rpc,
|
||||
'get_ports_on_host_by_subnet',
|
||||
return_value=[]),\
|
||||
mock.patch.object(self.agent.dvr_agent.plugin_rpc,
|
||||
'get_ports',
|
||||
return_value=[]),\
|
||||
mock.patch.object(self.agent.dvr_agent.int_br,
|
||||
'get_vif_port_by_id',
|
||||
return_value=self._port),\
|
||||
@@ -3474,14 +3477,36 @@ class TestOvsDvrNeutronAgent:
|
||||
phys_br.assert_not_called()
|
||||
|
||||
def _test_port_bound_for_dvr_on_vxlan_network(
|
||||
self, device_owner, ip_version=n_const.IP_VERSION_4):
|
||||
self, device_owner, ip_version=n_const.IP_VERSION_4, aaps=False):
|
||||
self._setup_for_dvr_test()
|
||||
port_obj = {"id": "fake-port-uuid"}
|
||||
aap_mac = 'aa:bb:cc:dd:ee:ff'
|
||||
aap_mac2 = 'aa:bb:cc:dd:ee:fe'
|
||||
aap_mac3 = 'aa:bb:cc:dd:ee:fd'
|
||||
if ip_version == n_const.IP_VERSION_4:
|
||||
gateway_ip = '1.1.1.1'
|
||||
cidr = '1.1.1.0/24'
|
||||
if aaps:
|
||||
port_obj["allowed_address_pairs"] = [
|
||||
{'ip_address': '1.1.1.10/32',
|
||||
'mac_address': aap_mac},
|
||||
{'ip_address': '1.1.1.11',
|
||||
'mac_address': aap_mac2},
|
||||
{'ip_address': '0.0.0.0/0',
|
||||
'mac_address': aap_mac3}
|
||||
]
|
||||
else:
|
||||
gateway_ip = '2001:100::1'
|
||||
cidr = '2001:100::0/64'
|
||||
if aaps:
|
||||
port_obj["allowed_address_pairs"] = [
|
||||
{'ip_address': '2001:100::10/128',
|
||||
'mac_address': aap_mac},
|
||||
{'ip_address': '2001:100::11',
|
||||
'mac_address': aap_mac2},
|
||||
{'ip_address': '2001:100::0/64',
|
||||
'mac_address': aap_mac3},
|
||||
]
|
||||
network_type = n_const.TYPE_VXLAN
|
||||
self._port.vif_mac = gateway_mac = 'aa:bb:cc:11:22:33'
|
||||
self._port.dvr_mac = self.agent.dvr_agent.dvr_mac_address
|
||||
@@ -3503,6 +3528,9 @@ class TestOvsDvrNeutronAgent:
|
||||
mock.patch.object(self.agent.dvr_agent.plugin_rpc,
|
||||
'get_ports_on_host_by_subnet',
|
||||
return_value=[]),\
|
||||
mock.patch.object(self.agent.dvr_agent.plugin_rpc,
|
||||
'get_ports',
|
||||
return_value=[port_obj]),\
|
||||
mock.patch.object(self.agent.dvr_agent.int_br,
|
||||
'get_vif_port_by_id',
|
||||
return_value=self._port),\
|
||||
@@ -3549,6 +3577,7 @@ class TestOvsDvrNeutronAgent:
|
||||
segmentation_id,
|
||||
self._compute_fixed_ips,
|
||||
device_owner, False)
|
||||
|
||||
expected_on_int_br = [
|
||||
mock.call.install_dvr_to_src_mac(
|
||||
network_type=network_type,
|
||||
@@ -3556,9 +3585,24 @@ class TestOvsDvrNeutronAgent:
|
||||
dst_mac=self._compute_port.vif_mac,
|
||||
dst_port=self._compute_port.ofport,
|
||||
vlan_tag=lvid,
|
||||
),
|
||||
] + self._expected_port_bound(self._compute_port, lvid, False,
|
||||
network_type)
|
||||
)]
|
||||
if aaps:
|
||||
expected_on_int_br += [
|
||||
mock.call.install_dvr_to_src_mac(
|
||||
network_type=network_type,
|
||||
gateway_mac=gateway_mac,
|
||||
dst_mac=aap_mac,
|
||||
dst_port=self._compute_port.ofport,
|
||||
vlan_tag=lvid),
|
||||
mock.call.install_dvr_to_src_mac(
|
||||
network_type=network_type,
|
||||
gateway_mac=gateway_mac,
|
||||
dst_mac=aap_mac2,
|
||||
dst_port=self._compute_port.ofport,
|
||||
vlan_tag=lvid),
|
||||
]
|
||||
expected_on_int_br += self._expected_port_bound(
|
||||
self._compute_port, lvid, False, network_type)
|
||||
int_br.assert_has_calls(expected_on_int_br)
|
||||
tun_br.assert_not_called()
|
||||
phys_br.assert_not_called()
|
||||
@@ -3583,6 +3627,11 @@ class TestOvsDvrNeutronAgent:
|
||||
self._test_port_bound_for_dvr_on_vxlan_network(
|
||||
device_owner=DEVICE_OWNER_COMPUTE,
|
||||
ip_version=n_const.IP_VERSION_6)
|
||||
self._test_port_bound_for_dvr_on_vxlan_network(
|
||||
device_owner=DEVICE_OWNER_COMPUTE, aaps=True)
|
||||
self._test_port_bound_for_dvr_on_vxlan_network(
|
||||
device_owner=DEVICE_OWNER_COMPUTE,
|
||||
ip_version=n_const.IP_VERSION_6, aaps=True)
|
||||
|
||||
def test_port_bound_for_dvr_with_dhcp_ports(self):
|
||||
self._test_port_bound_for_dvr_on_physical_network(
|
||||
@@ -3780,6 +3829,9 @@ class TestOvsDvrNeutronAgent:
|
||||
mock.patch.object(self.agent.dvr_agent.plugin_rpc,
|
||||
'get_ports_on_host_by_subnet',
|
||||
return_value=[]),\
|
||||
mock.patch.object(self.agent.dvr_agent.plugin_rpc,
|
||||
'get_ports',
|
||||
return_value=[]),\
|
||||
mock.patch.object(self.agent.dvr_agent.int_br,
|
||||
'get_vif_port_by_id',
|
||||
return_value=self._port),\
|
||||
@@ -3928,6 +3980,9 @@ class TestOvsDvrNeutronAgent:
|
||||
mock.patch.object(self.agent.dvr_agent.plugin_rpc,
|
||||
'get_ports_on_host_by_subnet',
|
||||
return_value=[]),\
|
||||
mock.patch.object(self.agent.dvr_agent.plugin_rpc,
|
||||
'get_ports',
|
||||
return_value=[]),\
|
||||
mock.patch.object(self.agent, 'int_br', new=int_br),\
|
||||
mock.patch.object(self.agent, 'tun_br', new=tun_br),\
|
||||
mock.patch.object(self.agent.dvr_agent, 'int_br', new=int_br),\
|
||||
@@ -4024,15 +4079,37 @@ class TestOvsDvrNeutronAgent:
|
||||
tun_br.assert_has_calls(expected)
|
||||
phys_br.assert_not_called()
|
||||
|
||||
def _test_treat_devices_removed_for_dvr(self, device_owner,
|
||||
ip_version=n_const.IP_VERSION_4):
|
||||
def _test_treat_devices_removed_for_dvr(
|
||||
self, device_owner, ip_version=n_const.IP_VERSION_4, aaps=False):
|
||||
self._setup_for_dvr_test()
|
||||
port_obj = {"id": "fake-port-uuid"}
|
||||
aap_mac = 'aa:bb:cc:dd:ee:ff'
|
||||
aap_mac2 = 'aa:bb:cc:dd:ee:fe'
|
||||
aap_mac3 = 'aa:bb:cc:dd:ee:fd'
|
||||
if ip_version == n_const.IP_VERSION_4:
|
||||
gateway_ip = '1.1.1.1'
|
||||
cidr = '1.1.1.0/24'
|
||||
if aaps:
|
||||
port_obj["allowed_address_pairs"] = [
|
||||
{'ip_address': '1.1.1.10/32',
|
||||
'mac_address': aap_mac},
|
||||
{'ip_address': '1.1.1.11',
|
||||
'mac_address': aap_mac2},
|
||||
{'ip_address': '0.0.0.0/0',
|
||||
'mac_address': aap_mac3}
|
||||
]
|
||||
else:
|
||||
gateway_ip = '2001:100::1'
|
||||
cidr = '2001:100::0/64'
|
||||
if aaps:
|
||||
port_obj["allowed_address_pairs"] = [
|
||||
{'ip_address': '2001:100::10/128',
|
||||
'mac_address': aap_mac},
|
||||
{'ip_address': '2001:100::11',
|
||||
'mac_address': aap_mac2},
|
||||
{'ip_address': '2001:100::0/0',
|
||||
'mac_address': aap_mac3}
|
||||
]
|
||||
self._port.dvr_mac = self.agent.dvr_agent.dvr_mac_address
|
||||
gateway_mac = 'aa:bb:cc:11:22:33'
|
||||
int_br = mock.create_autospec(self.agent.int_br)
|
||||
@@ -4051,6 +4128,9 @@ class TestOvsDvrNeutronAgent:
|
||||
mock.patch.object(self.agent.dvr_agent.int_br,
|
||||
'get_vif_port_by_id',
|
||||
return_value=self._port),\
|
||||
mock.patch.object(self.agent.dvr_agent.plugin_rpc,
|
||||
'get_ports',
|
||||
return_value=[]),\
|
||||
mock.patch.object(self.agent, 'int_br', new=int_br),\
|
||||
mock.patch.object(self.agent, 'tun_br', new=tun_br),\
|
||||
mock.patch.object(self.agent.dvr_agent, 'int_br', new=int_br),\
|
||||
@@ -4105,6 +4185,9 @@ class TestOvsDvrNeutronAgent:
|
||||
self._compute_port.vif_id],
|
||||
'failed_devices_up': [],
|
||||
'failed_devices_down': []}),\
|
||||
mock.patch.object(self.agent.dvr_agent.plugin_rpc,
|
||||
'get_ports',
|
||||
return_value=[port_obj]),\
|
||||
mock.patch.object(self.agent, 'int_br', new=int_br),\
|
||||
mock.patch.object(self.agent, 'tun_br', new=tun_br),\
|
||||
mock.patch.object(self.agent.dvr_agent, 'int_br', new=int_br),\
|
||||
@@ -4112,13 +4195,27 @@ class TestOvsDvrNeutronAgent:
|
||||
failed_devices = {'added': set(), 'removed': set()}
|
||||
failed_devices['removed'] = self.agent.treat_devices_removed(
|
||||
[self._compute_port.vif_id])
|
||||
int_br.assert_has_calls([
|
||||
expected_delete_dvr_src_mac = [
|
||||
mock.call.delete_dvr_to_src_mac(
|
||||
network_type='vxlan',
|
||||
vlan_tag=lvid,
|
||||
dst_mac=self._compute_port.vif_mac,
|
||||
),
|
||||
])
|
||||
)
|
||||
]
|
||||
if aaps:
|
||||
expected_delete_dvr_src_mac += [
|
||||
mock.call.delete_dvr_to_src_mac(
|
||||
network_type='vxlan',
|
||||
vlan_tag=lvid,
|
||||
dst_mac=aap_mac,
|
||||
),
|
||||
mock.call.delete_dvr_to_src_mac(
|
||||
network_type='vxlan',
|
||||
vlan_tag=lvid,
|
||||
dst_mac=aap_mac2,
|
||||
)
|
||||
]
|
||||
int_br.assert_has_calls(expected_delete_dvr_src_mac)
|
||||
tun_br.assert_not_called()
|
||||
|
||||
def test_treat_devices_removed_for_dvr_with_compute_ports(self):
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
fixes:
|
||||
- |
|
||||
Fix connection issue to allowed address pair address that is located
|
||||
behind a distributed virtual router by adding a missing flow.
|
||||
For more information, see bug `2093248 <https://launchpad.net/bugs/2093248>`_.
|
||||
Reference in New Issue
Block a user