Merge "DVR: Modify DVR flows to allow ARP requests to hit ARP Responder table"
This commit is contained in:
commit
8b0f4495f9
|
@ -284,6 +284,7 @@
|
|||
enable_distributed_routing: True
|
||||
l2_population: True
|
||||
tunnel_types: vxlan
|
||||
arp_responder: True
|
||||
ovs:
|
||||
tunnel_bridge: br-tun
|
||||
bridge_mappings: public:br-ex
|
||||
|
@ -316,6 +317,7 @@
|
|||
enable_distributed_routing: True
|
||||
l2_population: True
|
||||
tunnel_types: vxlan
|
||||
arp_responder: True
|
||||
ovs:
|
||||
tunnel_bridge: br-tun
|
||||
bridge_mappings: public:br-ex
|
||||
|
@ -363,6 +365,7 @@
|
|||
enable_distributed_routing: True
|
||||
l2_population: True
|
||||
tunnel_types: vxlan,gre
|
||||
arp_responder: True
|
||||
securitygroup:
|
||||
firewall_driver: iptables_hybrid
|
||||
$NEUTRON_L3_CONF:
|
||||
|
|
|
@ -44,7 +44,8 @@ LOCAL_SWITCHING = 0
|
|||
# Various tables for DVR use of integration bridge flows
|
||||
DVR_TO_SRC_MAC = 1
|
||||
DVR_TO_SRC_MAC_VLAN = 2
|
||||
|
||||
ARP_DVR_MAC_TO_DST_MAC = 3
|
||||
ARP_DVR_MAC_TO_DST_MAC_VLAN = 4
|
||||
CANARY_TABLE = 23
|
||||
|
||||
# Table for ARP poison/spoofing prevention rules
|
||||
|
|
|
@ -18,6 +18,8 @@ from os_ken.lib.packet import ether_types
|
|||
from os_ken.lib.packet import icmpv6
|
||||
from os_ken.lib.packet import in_proto
|
||||
|
||||
from neutron.plugins.ml2.drivers.openvswitch.agent.common import constants
|
||||
|
||||
|
||||
class OVSDVRProcessMixin(object):
|
||||
"""Common logic for br-tun and br-phys' DVR_PROCESS tables.
|
||||
|
@ -37,7 +39,7 @@ class OVSDVRProcessMixin(object):
|
|||
(_dp, ofp, ofpp) = self._get_dp()
|
||||
match = self._dvr_process_ipv4_match(ofp, ofpp, vlan_tag=vlan_tag,
|
||||
gateway_ip=gateway_ip)
|
||||
self.install_drop(table_id=self.dvr_process_table_id,
|
||||
self.install_drop(table_id=constants.FLOOD_TO_TUN,
|
||||
priority=3,
|
||||
match=match)
|
||||
|
||||
|
@ -45,7 +47,7 @@ class OVSDVRProcessMixin(object):
|
|||
(_dp, ofp, ofpp) = self._get_dp()
|
||||
match = self._dvr_process_ipv4_match(ofp, ofpp, vlan_tag=vlan_tag,
|
||||
gateway_ip=gateway_ip)
|
||||
self.uninstall_flows(table_id=self.dvr_process_table_id,
|
||||
self.uninstall_flows(table_id=constants.FLOOD_TO_TUN,
|
||||
match=match)
|
||||
|
||||
@staticmethod
|
||||
|
@ -61,14 +63,14 @@ class OVSDVRProcessMixin(object):
|
|||
(_dp, ofp, ofpp) = self._get_dp()
|
||||
match = self._dvr_process_ipv6_match(ofp, ofpp, vlan_tag=vlan_tag,
|
||||
gateway_mac=gateway_mac)
|
||||
self.install_drop(table_id=self.dvr_process_table_id, priority=3,
|
||||
self.install_drop(table_id=constants.FLOOD_TO_TUN, priority=3,
|
||||
match=match)
|
||||
|
||||
def delete_dvr_process_ipv6(self, vlan_tag, gateway_mac):
|
||||
(_dp, ofp, ofpp) = self._get_dp()
|
||||
match = self._dvr_process_ipv6_match(ofp, ofpp, vlan_tag=vlan_tag,
|
||||
gateway_mac=gateway_mac)
|
||||
self.uninstall_flows(table_id=self.dvr_process_table_id,
|
||||
self.uninstall_flows(table_id=constants.FLOOD_TO_TUN,
|
||||
match=match)
|
||||
|
||||
@staticmethod
|
||||
|
|
|
@ -95,6 +95,42 @@ class OVSIntegrationBridge(ovs_bridge.OVSAgentBridge):
|
|||
match = self._local_vlan_match(ofp, ofpp, port, vlan_vid)
|
||||
self.uninstall_flows(match=match)
|
||||
|
||||
@staticmethod
|
||||
def _arp_dvr_dst_mac_match(ofp, ofpp, vlan, dvr_mac):
|
||||
# If eth_dst is equal to the dvr mac of this host, then
|
||||
# flag it as matched.
|
||||
return ofpp.OFPMatch(vlan_vid=vlan | ofp.OFPVID_PRESENT,
|
||||
eth_dst=dvr_mac)
|
||||
|
||||
@staticmethod
|
||||
def _dvr_dst_mac_table_id(network_type):
|
||||
if network_type == p_const.TYPE_VLAN:
|
||||
return constants.ARP_DVR_MAC_TO_DST_MAC_VLAN
|
||||
else:
|
||||
return constants.ARP_DVR_MAC_TO_DST_MAC
|
||||
|
||||
def install_dvr_dst_mac_for_arp(self, network_type,
|
||||
vlan_tag, gateway_mac, dvr_mac, rtr_port):
|
||||
table_id = self._dvr_dst_mac_table_id(network_type)
|
||||
# Match the destination MAC with the DVR MAC
|
||||
(_dp, ofp, ofpp) = self._get_dp()
|
||||
match = self._arp_dvr_dst_mac_match(ofp, ofpp, vlan_tag, dvr_mac)
|
||||
# Incoming packet will come with destination MAC of DVR host MAC from
|
||||
# the ARP Responder. The Source MAC in this case will have the source
|
||||
# MAC of the port MAC that responded from the ARP responder.
|
||||
# So just remove the DVR host MAC from the 'eth_dst' and replace it
|
||||
# with the gateway-mac. The packet should end up in the right the table
|
||||
# for the packet to reach the router interface.
|
||||
actions = [
|
||||
ofpp.OFPActionSetField(eth_dst=gateway_mac),
|
||||
ofpp.OFPActionPopVlan(),
|
||||
ofpp.OFPActionOutput(rtr_port, 0)
|
||||
]
|
||||
self.install_apply_actions(table_id=table_id,
|
||||
priority=5,
|
||||
match=match,
|
||||
actions=actions)
|
||||
|
||||
@staticmethod
|
||||
def _dvr_to_src_mac_match(ofp, ofpp, vlan_tag, dst_mac):
|
||||
return ofpp.OFPMatch(vlan_vid=vlan_tag | ofp.OFPVID_PRESENT,
|
||||
|
@ -165,6 +201,37 @@ class OVSIntegrationBridge(ovs_bridge.OVSAgentBridge):
|
|||
self.uninstall_flows(table_id=constants.LOCAL_SWITCHING,
|
||||
in_port=port, eth_src=mac)
|
||||
|
||||
def delete_dvr_dst_mac_for_arp(self, network_type,
|
||||
vlan_tag, gateway_mac, dvr_mac, rtr_port):
|
||||
table_id = self._dvr_to_src_mac_table_id(network_type)
|
||||
(_dp, ofp, ofpp) = self._get_dp()
|
||||
match = self._arp_dvr_dst_mac_match(ofp, ofpp, vlan_tag, dvr_mac)
|
||||
for table in table_id:
|
||||
self.uninstall_flows(
|
||||
strict=True, priority=5, table_id=table, match=match)
|
||||
|
||||
def add_dvr_gateway_mac_arp_vlan(self, mac, port):
|
||||
self.install_goto(table_id=constants.LOCAL_SWITCHING,
|
||||
priority=5,
|
||||
in_port=port,
|
||||
eth_dst=mac,
|
||||
dest_table_id=constants.ARP_DVR_MAC_TO_DST_MAC_VLAN)
|
||||
|
||||
def remove_dvr_gateway_mac_arp_vlan(self, mac, port):
|
||||
self.uninstall_flows(table_id=constants.LOCAL_SWITCHING,
|
||||
eth_dst=mac)
|
||||
|
||||
def add_dvr_gateway_mac_arp_tun(self, mac, port):
|
||||
self.install_goto(table_id=constants.LOCAL_SWITCHING,
|
||||
priority=5,
|
||||
in_port=port,
|
||||
eth_dst=mac,
|
||||
dest_table_id=constants.ARP_DVR_MAC_TO_DST_MAC)
|
||||
|
||||
def remove_dvr_gateway_mac_arp_tun(self, mac, port):
|
||||
self.uninstall_flows(table_id=constants.LOCAL_SWITCHING,
|
||||
eth_dst=mac)
|
||||
|
||||
@staticmethod
|
||||
def _arp_reply_match(ofp, ofpp, port):
|
||||
return ofpp.OFPMatch(in_port=port,
|
||||
|
|
|
@ -119,7 +119,8 @@ class OVSDVRNeutronAgent(object):
|
|||
patch_int_ofport=constants.OFPORT_INVALID,
|
||||
patch_tun_ofport=constants.OFPORT_INVALID,
|
||||
host=None, enable_tunneling=False,
|
||||
enable_distributed_routing=False):
|
||||
enable_distributed_routing=False,
|
||||
arp_responder_enabled=False):
|
||||
self.context = context
|
||||
self.plugin_rpc = plugin_rpc
|
||||
self.host = host
|
||||
|
@ -133,6 +134,7 @@ class OVSDVRNeutronAgent(object):
|
|||
patch_int_ofport, patch_tun_ofport)
|
||||
self.reset_dvr_parameters()
|
||||
self.dvr_mac_address = None
|
||||
self.arp_responder_enabled = arp_responder_enabled
|
||||
if self.enable_distributed_routing:
|
||||
self.get_dvr_mac_address()
|
||||
|
||||
|
@ -262,6 +264,10 @@ class OVSDVRNeutronAgent(object):
|
|||
phys_br.add_dvr_mac_vlan(mac=mac,
|
||||
port=self.phys_ofports[physical_network])
|
||||
|
||||
def _add_arp_dvr_mac_for_phys_br(self, physical_network, mac):
|
||||
self.int_br.add_dvr_gateway_mac_arp_vlan(
|
||||
mac=mac, port=self.int_ofports[physical_network])
|
||||
|
||||
def _remove_dvr_mac_for_phys_br(self, physical_network, mac):
|
||||
# REVISIT(yamamoto): match in_port as well?
|
||||
self.int_br.remove_dvr_mac_vlan(mac=mac)
|
||||
|
@ -273,6 +279,10 @@ class OVSDVRNeutronAgent(object):
|
|||
self.int_br.add_dvr_mac_tun(mac=mac, port=self.patch_tun_ofport)
|
||||
self.tun_br.add_dvr_mac_tun(mac=mac, port=self.patch_int_ofport)
|
||||
|
||||
def _add_arp_dvr_mac_for_tun_br(self, mac):
|
||||
self.int_br.add_dvr_gateway_mac_arp_tun(
|
||||
mac=mac, port=self.patch_tun_ofport)
|
||||
|
||||
def _remove_dvr_mac_for_tun_br(self, mac):
|
||||
self.int_br.remove_dvr_mac_tun(mac=mac, port=self.patch_tun_ofport)
|
||||
# REVISIT(yamamoto): match in_port as well?
|
||||
|
@ -286,6 +296,13 @@ class OVSDVRNeutronAgent(object):
|
|||
LOG.debug("Added DVR MAC flow for %s", mac)
|
||||
self.registered_dvr_macs.add(mac)
|
||||
|
||||
def _add_dvr_mac_for_arp(self, mac):
|
||||
for physical_network in self.bridge_mappings:
|
||||
self._add_arp_dvr_mac_for_phys_br(physical_network, mac)
|
||||
if self.enable_tunneling:
|
||||
self._add_arp_dvr_mac_for_tun_br(mac)
|
||||
LOG.debug("Added ARP DVR MAC flow for %s", mac)
|
||||
|
||||
def _remove_dvr_mac(self, mac):
|
||||
for physical_network in self.bridge_mappings:
|
||||
self._remove_dvr_mac_for_phys_br(physical_network, mac)
|
||||
|
@ -301,6 +318,8 @@ class OVSDVRNeutronAgent(object):
|
|||
c_mac = netaddr.EUI(mac['mac_address'],
|
||||
dialect=netaddr.mac_unix_expanded)
|
||||
if c_mac == self.dvr_mac_address:
|
||||
self._add_dvr_mac_for_arp(c_mac)
|
||||
LOG.debug("Added the DVR MAC rule for ARP %s", c_mac)
|
||||
continue
|
||||
self._add_dvr_mac(c_mac)
|
||||
|
||||
|
@ -406,6 +425,15 @@ class OVSDVRNeutronAgent(object):
|
|||
gateway_mac=subnet_info['gateway_mac'],
|
||||
dst_mac=comp_ovsport.get_mac(),
|
||||
dst_port=comp_ovsport.get_ofport())
|
||||
# Add the following flow rule only when ARP RESPONDER is
|
||||
# enabled
|
||||
if self.arp_responder_enabled:
|
||||
self.int_br.install_dvr_dst_mac_for_arp(
|
||||
lvm.network_type,
|
||||
vlan_tag=lvm.vlan,
|
||||
gateway_mac=port.vif_mac,
|
||||
dvr_mac=self.dvr_mac_address,
|
||||
rtr_port=port.ofport)
|
||||
|
||||
if lvm.network_type == n_const.TYPE_VLAN:
|
||||
# TODO(vivek) remove the IPv6 related flows once SNAT is not
|
||||
|
@ -600,7 +628,16 @@ class OVSDVRNeutronAgent(object):
|
|||
network_type=network_type,
|
||||
vlan_tag=vlan_to_use, dst_mac=comp_port.get_mac())
|
||||
ldm.remove_all_compute_ofports()
|
||||
|
||||
# If ARP Responder enabled, remove the rule that redirects
|
||||
# the dvr_mac_address destination to the router port, since
|
||||
# the router port is removed or unbound.
|
||||
if self.arp_responder_enabled:
|
||||
self.int_br.delete_dvr_dst_mac_for_arp(
|
||||
network_type=network_type,
|
||||
vlan_tag=vlan_to_use,
|
||||
gateway_mac=port.vif_mac,
|
||||
dvr_mac=self.dvr_mac_address,
|
||||
rtr_port=port.ofport)
|
||||
if ldm.get_csnat_ofport() == constants.OFPORT_INVALID:
|
||||
# if there is no csnat port for this subnet, remove
|
||||
# this subnet from local_dvr_map, as no dvr (or) csnat
|
||||
|
|
|
@ -247,7 +247,8 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
|
|||
self.patch_tun_ofport,
|
||||
host,
|
||||
self.enable_tunneling,
|
||||
self.enable_distributed_routing)
|
||||
self.enable_distributed_routing,
|
||||
self.arp_responder_enabled)
|
||||
|
||||
if self.enable_distributed_routing:
|
||||
self.dvr_agent.setup_dvr_flows()
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
import mock
|
||||
from oslo_utils import importutils
|
||||
|
||||
from neutron.plugins.ml2.drivers.openvswitch.agent.common import constants
|
||||
from neutron.tests.unit.plugins.ml2.drivers.openvswitch.agent \
|
||||
import ovs_test_base
|
||||
|
||||
|
@ -169,7 +170,7 @@ class OVSDVRProcessTestMixin(object):
|
|||
arp_tpa=gateway_ip,
|
||||
vlan_vid=vlan_tag | ofp.OFPVID_PRESENT),
|
||||
priority=3,
|
||||
table_id=self.dvr_process_table_id),
|
||||
table_id=constants.FLOOD_TO_TUN),
|
||||
active_bundle=None),
|
||||
]
|
||||
self.assertEqual(expected, self.mock.mock_calls)
|
||||
|
@ -181,7 +182,7 @@ class OVSDVRProcessTestMixin(object):
|
|||
gateway_ip=gateway_ip)
|
||||
(dp, ofp, ofpp) = self._get_dp()
|
||||
expected = [
|
||||
call.uninstall_flows(table_id=self.dvr_process_table_id,
|
||||
call.uninstall_flows(table_id=constants.FLOOD_TO_TUN,
|
||||
match=ofpp.OFPMatch(
|
||||
eth_type=self.ether_types.ETH_TYPE_ARP,
|
||||
arp_tpa=gateway_ip,
|
||||
|
@ -206,7 +207,7 @@ class OVSDVRProcessTestMixin(object):
|
|||
ip_proto=self.in_proto.IPPROTO_ICMPV6,
|
||||
vlan_vid=vlan_tag | ofp.OFPVID_PRESENT),
|
||||
priority=3,
|
||||
table_id=self.dvr_process_table_id),
|
||||
table_id=constants.FLOOD_TO_TUN),
|
||||
active_bundle=None),
|
||||
]
|
||||
self.assertEqual(expected, self.mock.mock_calls)
|
||||
|
@ -218,7 +219,7 @@ class OVSDVRProcessTestMixin(object):
|
|||
gateway_mac=gateway_mac)
|
||||
(dp, ofp, ofpp) = self._get_dp()
|
||||
expected = [
|
||||
call.uninstall_flows(table_id=self.dvr_process_table_id,
|
||||
call.uninstall_flows(table_id=constants.FLOOD_TO_TUN,
|
||||
match=ofpp.OFPMatch(
|
||||
eth_src=gateway_mac,
|
||||
eth_type=self.ether_types.ETH_TYPE_IPV6,
|
||||
|
|
Loading…
Reference in New Issue