Merge "Make DVR router support FLAT network for ovs-agent"
This commit is contained in:
commit
792f4efce9
@ -771,32 +771,47 @@ class OVSFirewallDriver(firewall.FirewallDriver):
|
||||
return {id_: port.neutron_port_dict
|
||||
for id_, port in self.sg_port_map.ports.items()}
|
||||
|
||||
def install_vlan_direct_flow(self, mac, segment_id, ofport, local_vlan):
|
||||
# If the port segment_id is not None/0, the
|
||||
# port's network type must be VLAN type.
|
||||
if segment_id:
|
||||
def install_physical_direct_flow(self, mac, segment_id,
|
||||
ofport, local_vlan, network_type):
|
||||
actions = ('set_field:{:d}->reg{:d},'
|
||||
'set_field:{:d}->reg{:d},').format(
|
||||
ofport,
|
||||
ovsfw_consts.REG_PORT,
|
||||
# This always needs the local vlan.
|
||||
local_vlan,
|
||||
ovsfw_consts.REG_NET)
|
||||
if network_type == lib_const.TYPE_VLAN:
|
||||
actions += 'strip_vlan,resubmit(,{:d})'.format(
|
||||
ovs_consts.BASE_INGRESS_TABLE)
|
||||
self._add_flow(
|
||||
table=ovs_consts.TRANSIENT_TABLE,
|
||||
priority=90,
|
||||
dl_dst=mac,
|
||||
dl_vlan='0x%x' % segment_id,
|
||||
actions='set_field:{:d}->reg{:d},'
|
||||
'set_field:{:d}->reg{:d},'
|
||||
'strip_vlan,resubmit(,{:d})'.format(
|
||||
ofport,
|
||||
ovsfw_consts.REG_PORT,
|
||||
# This always needs the local vlan.
|
||||
local_vlan,
|
||||
ovsfw_consts.REG_NET,
|
||||
ovs_consts.BASE_INGRESS_TABLE)
|
||||
)
|
||||
actions=actions)
|
||||
elif network_type == lib_const.TYPE_FLAT:
|
||||
# If the port belong to flat network, we need match vlan_tci and
|
||||
# needn't pop vlan
|
||||
actions += 'resubmit(,{:d})'.format(
|
||||
ovs_consts.BASE_INGRESS_TABLE)
|
||||
self._add_flow(
|
||||
table=ovs_consts.TRANSIENT_TABLE,
|
||||
priority=90,
|
||||
dl_dst=mac,
|
||||
vlan_tci=ovs_consts.FLAT_VLAN_TCI,
|
||||
actions=actions)
|
||||
|
||||
def delete_vlan_direct_flow(self, mac, segment_id):
|
||||
def delete_physical_direct_flow(self, mac, segment_id):
|
||||
if segment_id:
|
||||
self._strict_delete_flow(priority=90,
|
||||
table=ovs_consts.TRANSIENT_TABLE,
|
||||
dl_dst=mac,
|
||||
dl_vlan=segment_id)
|
||||
else:
|
||||
self._strict_delete_flow(priority=90,
|
||||
table=ovs_consts.TRANSIENT_TABLE,
|
||||
dl_dst=mac,
|
||||
vlan_tci=ovs_consts.FLAT_VLAN_TCI)
|
||||
|
||||
def initialize_port_flows(self, port):
|
||||
"""Set base flows for port
|
||||
@ -821,8 +836,9 @@ class OVSFirewallDriver(firewall.FirewallDriver):
|
||||
|
||||
# Identify ingress flows
|
||||
for mac_addr in port.all_allowed_macs:
|
||||
self.install_vlan_direct_flow(
|
||||
mac_addr, port.segment_id, port.ofport, port.vlan_tag)
|
||||
self.install_physical_direct_flow(
|
||||
mac_addr, port.segment_id, port.ofport,
|
||||
port.vlan_tag, port.network_type)
|
||||
|
||||
self._add_flow(
|
||||
table=ovs_consts.TRANSIENT_TABLE,
|
||||
@ -1406,7 +1422,7 @@ class OVSFirewallDriver(firewall.FirewallDriver):
|
||||
table=ovs_consts.TRANSIENT_TABLE,
|
||||
dl_dst=mac_addr,
|
||||
dl_vlan=port.vlan_tag)
|
||||
self.delete_vlan_direct_flow(mac_addr, port.segment_id)
|
||||
self.delete_physical_direct_flow(mac_addr, port.segment_id)
|
||||
self._delete_flows(table=ovs_consts.ACCEPT_OR_INGRESS_TABLE,
|
||||
dl_dst=mac_addr, reg_net=port.vlan_tag)
|
||||
|
||||
|
@ -12,9 +12,6 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
FLAT_VLAN_ID = -1
|
||||
LOCAL_VLAN_ID = -2
|
||||
|
||||
# Supported VXLAN features
|
||||
VXLAN_NONE = 'not_supported'
|
||||
VXLAN_MCAST = 'multicast_flooding'
|
||||
|
@ -16,8 +16,8 @@
|
||||
from neutron_lib import constants as p_const
|
||||
|
||||
|
||||
# Special vlan_id value in ovs_vlan_allocations table indicating flat network
|
||||
FLAT_VLAN_ID = -1
|
||||
# Special vlan_tci value indicating flat network
|
||||
FLAT_VLAN_TCI = '0x0000/0x1fff'
|
||||
|
||||
# Topic for tunnel notifications between the plugin and agent
|
||||
TUNNEL = 'tunnel'
|
||||
@ -41,11 +41,14 @@ TUNNEL_NETWORK_TYPES = [p_const.TYPE_GRE, p_const.TYPE_VXLAN,
|
||||
|
||||
LOCAL_SWITCHING = 0
|
||||
|
||||
# The pyhsical network types of support DVR router
|
||||
DVR_PHYSICAL_NETWORK_TYPES = [p_const.TYPE_VLAN, p_const.TYPE_FLAT]
|
||||
|
||||
# Various tables for DVR use of integration bridge flows
|
||||
DVR_TO_SRC_MAC = 1
|
||||
DVR_TO_SRC_MAC_VLAN = 2
|
||||
DVR_TO_SRC_MAC_PHYSICAL = 2
|
||||
ARP_DVR_MAC_TO_DST_MAC = 3
|
||||
ARP_DVR_MAC_TO_DST_MAC_VLAN = 4
|
||||
ARP_DVR_MAC_TO_DST_MAC_PHYSICAL = 4
|
||||
CANARY_TABLE = 23
|
||||
|
||||
# Table for ARP poison/spoofing prevention rules
|
||||
@ -82,7 +85,7 @@ ACCEPTED_EGRESS_TRAFFIC_NORMAL_TABLE = 94
|
||||
INT_BR_ALL_TABLES = (
|
||||
LOCAL_SWITCHING,
|
||||
DVR_TO_SRC_MAC,
|
||||
DVR_TO_SRC_MAC_VLAN,
|
||||
DVR_TO_SRC_MAC_PHYSICAL,
|
||||
CANARY_TABLE,
|
||||
ARP_SPOOF_TABLE,
|
||||
MAC_SPOOF_TABLE,
|
||||
@ -128,15 +131,15 @@ TUN_BR_ALL_TABLES = (
|
||||
# --- Physical Bridges (phys_brs)
|
||||
|
||||
# Various tables for DVR use of physical bridge flows
|
||||
DVR_PROCESS_VLAN = 1
|
||||
DVR_PROCESS_PHYSICAL = 1
|
||||
LOCAL_VLAN_TRANSLATION = 2
|
||||
DVR_NOT_LEARN_VLAN = 3
|
||||
DVR_NOT_LEARN_PHYSICAL = 3
|
||||
|
||||
PHY_BR_ALL_TABLES = (
|
||||
LOCAL_SWITCHING,
|
||||
DVR_PROCESS_VLAN,
|
||||
DVR_PROCESS_PHYSICAL,
|
||||
LOCAL_VLAN_TRANSLATION,
|
||||
DVR_NOT_LEARN_VLAN)
|
||||
DVR_NOT_LEARN_PHYSICAL)
|
||||
|
||||
# --- end of OpenFlow table IDs
|
||||
|
||||
|
@ -21,7 +21,6 @@
|
||||
|
||||
import netaddr
|
||||
|
||||
from neutron_lib import constants as p_const
|
||||
from os_ken.lib.packet import ether_types
|
||||
from os_ken.lib.packet import icmpv6
|
||||
from os_ken.lib.packet import in_proto
|
||||
@ -103,13 +102,15 @@ class OVSIntegrationBridge(ovs_bridge.OVSAgentBridge):
|
||||
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.
|
||||
if not vlan:
|
||||
return ofpp.OFPMatch(vlan_vid=ofp.OFPVID_NONE, eth_dst=dvr_mac)
|
||||
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
|
||||
if network_type in constants.DVR_PHYSICAL_NETWORK_TYPES:
|
||||
return constants.ARP_DVR_MAC_TO_DST_MAC_PHYSICAL
|
||||
else:
|
||||
return constants.ARP_DVR_MAC_TO_DST_MAC
|
||||
|
||||
@ -137,13 +138,16 @@ class OVSIntegrationBridge(ovs_bridge.OVSAgentBridge):
|
||||
|
||||
@staticmethod
|
||||
def _dvr_to_src_mac_match(ofp, ofpp, vlan_tag, dst_mac):
|
||||
if not vlan_tag:
|
||||
# When the network is flat type, the vlan_tag will be None.
|
||||
return ofpp.OFPMatch(vlan_vid=ofp.OFPVID_NONE, eth_dst=dst_mac)
|
||||
return ofpp.OFPMatch(vlan_vid=vlan_tag | ofp.OFPVID_PRESENT,
|
||||
eth_dst=dst_mac)
|
||||
|
||||
@staticmethod
|
||||
def _dvr_to_src_mac_table_id(network_type):
|
||||
if network_type == p_const.TYPE_VLAN:
|
||||
return constants.DVR_TO_SRC_MAC_VLAN
|
||||
if network_type in constants.DVR_PHYSICAL_NETWORK_TYPES:
|
||||
return constants.DVR_TO_SRC_MAC_PHYSICAL
|
||||
else:
|
||||
return constants.DVR_TO_SRC_MAC
|
||||
|
||||
@ -164,10 +168,10 @@ class OVSIntegrationBridge(ovs_bridge.OVSAgentBridge):
|
||||
priority=20,
|
||||
match=match,
|
||||
instructions=instructions)
|
||||
actions = [
|
||||
ofpp.OFPActionPopVlan(),
|
||||
ofpp.OFPActionOutput(dst_port, 0),
|
||||
]
|
||||
actions = []
|
||||
if vlan_tag:
|
||||
actions.append(ofpp.OFPActionPopVlan())
|
||||
actions.append(ofpp.OFPActionOutput(dst_port, 0))
|
||||
self.install_apply_actions(table_id=constants.TRANSIENT_TABLE,
|
||||
priority=20,
|
||||
match=match,
|
||||
@ -182,12 +186,12 @@ class OVSIntegrationBridge(ovs_bridge.OVSAgentBridge):
|
||||
self.uninstall_flows(
|
||||
strict=True, priority=20, table_id=table, match=match)
|
||||
|
||||
def add_dvr_mac_vlan(self, mac, port):
|
||||
def add_dvr_mac_physical(self, mac, port):
|
||||
self.install_goto(table_id=constants.LOCAL_SWITCHING,
|
||||
priority=4,
|
||||
in_port=port,
|
||||
eth_src=mac,
|
||||
dest_table_id=constants.DVR_TO_SRC_MAC_VLAN)
|
||||
dest_table_id=constants.DVR_TO_SRC_MAC_PHYSICAL)
|
||||
|
||||
def remove_dvr_mac_vlan(self, mac):
|
||||
# REVISIT(yamamoto): match in_port as well?
|
||||
@ -214,11 +218,12 @@ class OVSIntegrationBridge(ovs_bridge.OVSAgentBridge):
|
||||
strict=True, priority=5, table_id=table_id, 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)
|
||||
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_PHYSICAL)
|
||||
|
||||
def remove_dvr_gateway_mac_arp_vlan(self, mac, port):
|
||||
self.uninstall_flows(table_id=constants.LOCAL_SWITCHING,
|
||||
|
@ -26,7 +26,7 @@ class OVSPhysicalBridge(ovs_bridge.OVSAgentBridge,
|
||||
"""openvswitch agent physical bridge specific logic."""
|
||||
|
||||
# Used by OVSDVRProcessMixin
|
||||
dvr_process_table_id = constants.DVR_PROCESS_VLAN
|
||||
dvr_process_table_id = constants.DVR_PROCESS_PHYSICAL
|
||||
dvr_process_next_table_id = constants.LOCAL_VLAN_TRANSLATION
|
||||
of_tables = constants.PHY_BR_ALL_TABLES
|
||||
|
||||
@ -57,12 +57,12 @@ class OVSPhysicalBridge(ovs_bridge.OVSAgentBridge,
|
||||
match = self._local_vlan_match(ofp, ofpp, port, lvid)
|
||||
self.uninstall_flows(match=match)
|
||||
|
||||
def add_dvr_mac_vlan(self, mac, port):
|
||||
self.install_output(table_id=constants.DVR_NOT_LEARN_VLAN,
|
||||
def add_dvr_mac_physical(self, mac, port):
|
||||
self.install_output(table_id=constants.DVR_NOT_LEARN_PHYSICAL,
|
||||
priority=2, eth_src=mac, port=port)
|
||||
|
||||
def remove_dvr_mac_vlan(self, mac):
|
||||
# REVISIT(yamamoto): match in_port as well?
|
||||
self.uninstall_flows(
|
||||
table_id=constants.DVR_NOT_LEARN_VLAN,
|
||||
table_id=constants.DVR_NOT_LEARN_PHYSICAL,
|
||||
eth_src=mac)
|
||||
|
@ -224,7 +224,7 @@ class OVSDVRNeutronAgent(object):
|
||||
# Insert 'drop' action as the default for Table DVR_TO_SRC_MAC
|
||||
self.int_br.install_drop(table_id=constants.DVR_TO_SRC_MAC, priority=1)
|
||||
|
||||
self.int_br.install_drop(table_id=constants.DVR_TO_SRC_MAC_VLAN,
|
||||
self.int_br.install_drop(table_id=constants.DVR_TO_SRC_MAC_PHYSICAL,
|
||||
priority=1)
|
||||
|
||||
for physical_network in self.bridge_mappings:
|
||||
@ -256,12 +256,12 @@ class OVSDVRNeutronAgent(object):
|
||||
self.phys_brs[physical_network].install_goto(
|
||||
in_port=self.phys_ofports[physical_network],
|
||||
priority=2,
|
||||
dest_table_id=constants.DVR_PROCESS_VLAN)
|
||||
dest_table_id=constants.DVR_PROCESS_PHYSICAL)
|
||||
self.phys_brs[physical_network].install_goto(
|
||||
priority=1,
|
||||
dest_table_id=constants.DVR_NOT_LEARN_VLAN)
|
||||
dest_table_id=constants.DVR_NOT_LEARN_PHYSICAL)
|
||||
self.phys_brs[physical_network].install_goto(
|
||||
table_id=constants.DVR_PROCESS_VLAN,
|
||||
table_id=constants.DVR_PROCESS_PHYSICAL,
|
||||
priority=0,
|
||||
dest_table_id=constants.LOCAL_VLAN_TRANSLATION)
|
||||
self.phys_brs[physical_network].install_drop(
|
||||
@ -269,15 +269,15 @@ class OVSDVRNeutronAgent(object):
|
||||
in_port=self.phys_ofports[physical_network],
|
||||
priority=2)
|
||||
self.phys_brs[physical_network].install_normal(
|
||||
table_id=constants.DVR_NOT_LEARN_VLAN,
|
||||
table_id=constants.DVR_NOT_LEARN_PHYSICAL,
|
||||
priority=1)
|
||||
|
||||
def _add_dvr_mac_for_phys_br(self, physical_network, mac):
|
||||
self.int_br.add_dvr_mac_vlan(mac=mac,
|
||||
port=self.int_ofports[physical_network])
|
||||
self.int_br.add_dvr_mac_physical(
|
||||
mac=mac, port=self.int_ofports[physical_network])
|
||||
phys_br = self.phys_brs[physical_network]
|
||||
phys_br.add_dvr_mac_vlan(mac=mac,
|
||||
port=self.phys_ofports[physical_network])
|
||||
phys_br.add_dvr_mac_physical(
|
||||
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(
|
||||
@ -402,7 +402,7 @@ class OVSDVRNeutronAgent(object):
|
||||
ldm.set_dvr_owned(True)
|
||||
|
||||
vlan_to_use = lvm.vlan
|
||||
if lvm.network_type == n_const.TYPE_VLAN:
|
||||
if lvm.network_type in constants.DVR_PHYSICAL_NETWORK_TYPES:
|
||||
vlan_to_use = lvm.segmentation_id
|
||||
|
||||
subnet_info = ldm.get_subnet_info()
|
||||
@ -456,7 +456,7 @@ class OVSDVRNeutronAgent(object):
|
||||
dvr_mac=self.dvr_mac_address,
|
||||
rtr_port=port.ofport)
|
||||
|
||||
if lvm.network_type == n_const.TYPE_VLAN:
|
||||
if lvm.network_type in constants.DVR_PHYSICAL_NETWORK_TYPES:
|
||||
# TODO(vivek) remove the IPv6 related flows once SNAT is not
|
||||
# used for IPv6 DVR.
|
||||
br = self.phys_brs[lvm.physical_network]
|
||||
@ -517,7 +517,7 @@ class OVSDVRNeutronAgent(object):
|
||||
ovsport.add_subnet(subnet_uuid)
|
||||
self.local_ports[port.vif_id] = ovsport
|
||||
vlan_to_use = lvm.vlan
|
||||
if lvm.network_type == n_const.TYPE_VLAN:
|
||||
if lvm.network_type in constants.DVR_PHYSICAL_NETWORK_TYPES:
|
||||
vlan_to_use = lvm.segmentation_id
|
||||
# create a rule for this vm port
|
||||
self.int_br.install_dvr_to_src_mac(
|
||||
@ -577,7 +577,7 @@ class OVSDVRNeutronAgent(object):
|
||||
ovsport.add_subnet(subnet_uuid)
|
||||
self.local_ports[port.vif_id] = ovsport
|
||||
vlan_to_use = lvm.vlan
|
||||
if lvm.network_type == n_const.TYPE_VLAN:
|
||||
if lvm.network_type in constants.DVR_PHYSICAL_NETWORK_TYPES:
|
||||
vlan_to_use = lvm.segmentation_id
|
||||
self.int_br.install_dvr_to_src_mac(
|
||||
network_type=lvm.network_type,
|
||||
@ -591,8 +591,9 @@ class OVSDVRNeutronAgent(object):
|
||||
if not self.in_distributed_mode():
|
||||
return
|
||||
|
||||
if local_vlan_map.network_type not in (constants.TUNNEL_NETWORK_TYPES +
|
||||
[n_const.TYPE_VLAN]):
|
||||
if (local_vlan_map.network_type not in
|
||||
(constants.TUNNEL_NETWORK_TYPES +
|
||||
constants.DVR_PHYSICAL_NETWORK_TYPES)):
|
||||
LOG.debug("DVR: Port %s is with network_type %s not supported"
|
||||
" for dvr plumbing", port.vif_id,
|
||||
local_vlan_map.network_type)
|
||||
@ -629,7 +630,7 @@ class OVSDVRNeutronAgent(object):
|
||||
network_type = lvm.network_type
|
||||
physical_network = lvm.physical_network
|
||||
vlan_to_use = lvm.vlan
|
||||
if network_type == n_const.TYPE_VLAN:
|
||||
if network_type in constants.DVR_PHYSICAL_NETWORK_TYPES:
|
||||
vlan_to_use = lvm.segmentation_id
|
||||
# ensure we process for all the subnets laid on this removed port
|
||||
for sub_uuid in subnet_set:
|
||||
@ -660,7 +661,7 @@ class OVSDVRNeutronAgent(object):
|
||||
# this subnet from local_dvr_map, as no dvr (or) csnat
|
||||
# ports available on this agent anymore
|
||||
self.local_dvr_map.pop(sub_uuid, None)
|
||||
if network_type == n_const.TYPE_VLAN:
|
||||
if network_type in constants.DVR_PHYSICAL_NETWORK_TYPES:
|
||||
br = self.phys_brs[physical_network]
|
||||
if network_type in constants.TUNNEL_NETWORK_TYPES:
|
||||
br = self.tun_br
|
||||
@ -679,7 +680,7 @@ class OVSDVRNeutronAgent(object):
|
||||
self.firewall.delete_accepted_egress_direct_flow(
|
||||
subnet_info['gateway_mac'], lvm.vlan)
|
||||
|
||||
if lvm.network_type == n_const.TYPE_VLAN:
|
||||
if lvm.network_type in constants.DVR_PHYSICAL_NETWORK_TYPES:
|
||||
br = self.phys_brs[physical_network]
|
||||
if lvm.network_type in constants.TUNNEL_NETWORK_TYPES:
|
||||
br = self.tun_br
|
||||
@ -701,7 +702,7 @@ class OVSDVRNeutronAgent(object):
|
||||
ldm = self.local_dvr_map[sub_uuid]
|
||||
ldm.remove_compute_ofport(port.vif_id)
|
||||
vlan_to_use = lvm.vlan
|
||||
if lvm.network_type == n_const.TYPE_VLAN:
|
||||
if lvm.network_type in constants.DVR_PHYSICAL_NETWORK_TYPES:
|
||||
vlan_to_use = lvm.segmentation_id
|
||||
# first remove this vm port rule
|
||||
self.int_br.delete_dvr_to_src_mac(
|
||||
@ -722,7 +723,7 @@ class OVSDVRNeutronAgent(object):
|
||||
ldm = self.local_dvr_map[sub_uuid]
|
||||
ldm.set_csnat_ofport(constants.OFPORT_INVALID)
|
||||
vlan_to_use = lvm.vlan
|
||||
if lvm.network_type == n_const.TYPE_VLAN:
|
||||
if lvm.network_type in constants.DVR_PHYSICAL_NETWORK_TYPES:
|
||||
vlan_to_use = lvm.segmentation_id
|
||||
# then remove csnat port rule
|
||||
self.int_br.delete_dvr_to_src_mac(
|
||||
|
@ -901,18 +901,8 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
|
||||
else:
|
||||
LOG.warning('Action %s not supported', action)
|
||||
|
||||
def _local_vlan_for_flat(self, lvid, physical_network):
|
||||
phys_br = self.phys_brs[physical_network]
|
||||
phys_port = self.phys_ofports[physical_network]
|
||||
int_br = self.int_br
|
||||
int_port = self.int_ofports[physical_network]
|
||||
phys_br.provision_local_vlan(port=phys_port, lvid=lvid,
|
||||
segmentation_id=None,
|
||||
distributed=False)
|
||||
int_br.provision_local_vlan(port=int_port, lvid=lvid,
|
||||
segmentation_id=None)
|
||||
|
||||
def _local_vlan_for_vlan(self, lvid, physical_network, segmentation_id):
|
||||
def _local_vlan_for_physical(self, lvid, physical_network,
|
||||
segmentation_id=None):
|
||||
distributed = self.enable_distributed_routing
|
||||
phys_br = self.phys_brs[physical_network]
|
||||
phys_port = self.phys_ofports[physical_network]
|
||||
@ -993,7 +983,7 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
|
||||
'net_uuid': net_uuid})
|
||||
elif network_type == n_const.TYPE_FLAT:
|
||||
if physical_network in self.phys_brs:
|
||||
self._local_vlan_for_flat(lvid, physical_network)
|
||||
self._local_vlan_for_physical(lvid, physical_network)
|
||||
else:
|
||||
LOG.error("Cannot provision flat network for "
|
||||
"net-id=%(net_uuid)s - no bridge for "
|
||||
@ -1002,8 +992,8 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
|
||||
'physical_network': physical_network})
|
||||
elif network_type == n_const.TYPE_VLAN:
|
||||
if physical_network in self.phys_brs:
|
||||
self._local_vlan_for_vlan(lvid, physical_network,
|
||||
segmentation_id)
|
||||
self._local_vlan_for_physical(lvid, physical_network,
|
||||
segmentation_id)
|
||||
else:
|
||||
LOG.error("Cannot provision VLAN network for "
|
||||
"net-id=%(net_uuid)s - no bridge for "
|
||||
|
@ -344,7 +344,8 @@ class OVSFlowTestCase(OVSAgentTestBase):
|
||||
'dst_mac': '12:34:56:78:cc:dd',
|
||||
'dst_port': 123}
|
||||
self.br_int.install_dvr_to_src_mac(network_type='vlan', **kwargs)
|
||||
self.br_int.add_dvr_mac_vlan(mac=other_dvr_mac, port=other_dvr_port)
|
||||
self.br_int.add_dvr_mac_physical(mac=other_dvr_mac,
|
||||
port=other_dvr_port)
|
||||
|
||||
trace = self._run_trace(self.br.br_name,
|
||||
"in_port=%d," % other_dvr_port +
|
||||
|
@ -38,11 +38,12 @@ TESTING_VLAN_TAG = 1
|
||||
TESTING_SEGMENT = 1000
|
||||
|
||||
|
||||
def create_ofport(port_dict, network_type=None, physical_network=None):
|
||||
def create_ofport(port_dict, network_type=None,
|
||||
physical_network=None, segment_id=TESTING_SEGMENT):
|
||||
ovs_port = mock.Mock(vif_mac='00:00:00:00:00:00', ofport=1,
|
||||
port_name="port-name")
|
||||
return ovsfw.OFPort(port_dict, ovs_port, vlan_tag=TESTING_VLAN_TAG,
|
||||
segment_id=TESTING_SEGMENT,
|
||||
segment_id=segment_id,
|
||||
network_type=network_type,
|
||||
physical_network=physical_network)
|
||||
|
||||
@ -590,18 +591,23 @@ class TestOVSFirewallDriver(base.BaseTestCase):
|
||||
self.firewall.prepare_port_filter(port_dict)
|
||||
self.assertFalse(m_init_flows.called)
|
||||
|
||||
def test_initialize_port_flows_vlan_dvr_conntrack_direct(self):
|
||||
def _test_initialize_port_flows_dvr_conntrack_direct(self, network_type):
|
||||
port_dict = {
|
||||
'device': 'port-id',
|
||||
'security_groups': [1]}
|
||||
segment_id = None
|
||||
if network_type == constants.TYPE_VLAN:
|
||||
segment_id = TESTING_SEGMENT
|
||||
of_port = create_ofport(port_dict,
|
||||
network_type=constants.TYPE_VXLAN)
|
||||
network_type=network_type,
|
||||
segment_id=segment_id)
|
||||
self.firewall.sg_port_map.ports[of_port.id] = of_port
|
||||
port = self.firewall.get_or_create_ofport(port_dict)
|
||||
|
||||
fake_patch_port = 999
|
||||
self.mock_bridge.br.get_port_ofport.return_value = fake_patch_port
|
||||
|
||||
expected_calls = []
|
||||
self.firewall.initialize_port_flows(port)
|
||||
|
||||
call_args1 = {
|
||||
@ -616,22 +622,39 @@ class TestOVSFirewallDriver(base.BaseTestCase):
|
||||
port.vlan_tag,
|
||||
ovsfw_consts.REG_NET,
|
||||
ovs_consts.BASE_EGRESS_TABLE)}
|
||||
egress_flow_call = mock.call(**call_args1)
|
||||
expected_calls.append(mock.call(**call_args1))
|
||||
|
||||
call_args2 = {
|
||||
'table': ovs_consts.TRANSIENT_TABLE,
|
||||
'priority': 90,
|
||||
'dl_dst': port.mac,
|
||||
'dl_vlan': '0x%x' % port.segment_id,
|
||||
'actions': 'set_field:{:d}->reg{:d},'
|
||||
'set_field:{:d}->reg{:d},'
|
||||
'strip_vlan,resubmit(,{:d})'.format(
|
||||
port.ofport,
|
||||
ovsfw_consts.REG_PORT,
|
||||
port.vlan_tag,
|
||||
ovsfw_consts.REG_NET,
|
||||
ovs_consts.BASE_INGRESS_TABLE)}
|
||||
ingress_flow_call1 = mock.call(**call_args2)
|
||||
if network_type == constants.TYPE_VLAN:
|
||||
call_args2 = {
|
||||
'table': ovs_consts.TRANSIENT_TABLE,
|
||||
'priority': 90,
|
||||
'dl_dst': port.mac,
|
||||
'dl_vlan': '0x%x' % port.segment_id,
|
||||
'actions': 'set_field:{:d}->reg{:d},'
|
||||
'set_field:{:d}->reg{:d},'
|
||||
'strip_vlan,resubmit(,{:d})'.format(
|
||||
port.ofport,
|
||||
ovsfw_consts.REG_PORT,
|
||||
port.vlan_tag,
|
||||
ovsfw_consts.REG_NET,
|
||||
ovs_consts.BASE_INGRESS_TABLE)}
|
||||
expected_calls.append(mock.call(**call_args2))
|
||||
|
||||
if network_type == constants.TYPE_FLAT:
|
||||
call_args2 = {
|
||||
'table': ovs_consts.TRANSIENT_TABLE,
|
||||
'priority': 90,
|
||||
'dl_dst': port.mac,
|
||||
'vlan_tci': ovs_consts.FLAT_VLAN_TCI,
|
||||
'actions': 'set_field:{:d}->reg{:d},'
|
||||
'set_field:{:d}->reg{:d},'
|
||||
'resubmit(,{:d})'.format(
|
||||
port.ofport,
|
||||
ovsfw_consts.REG_PORT,
|
||||
port.vlan_tag,
|
||||
ovsfw_consts.REG_NET,
|
||||
ovs_consts.BASE_INGRESS_TABLE)}
|
||||
expected_calls.append(mock.call(**call_args2))
|
||||
|
||||
call_args3 = {
|
||||
'table': ovs_consts.TRANSIENT_TABLE,
|
||||
@ -646,9 +669,20 @@ class TestOVSFirewallDriver(base.BaseTestCase):
|
||||
port.vlan_tag,
|
||||
ovsfw_consts.REG_NET,
|
||||
ovs_consts.BASE_INGRESS_TABLE)}
|
||||
ingress_flow_call2 = mock.call(**call_args3)
|
||||
self.mock_bridge.br.add_flow.assert_has_calls(
|
||||
[egress_flow_call, ingress_flow_call1, ingress_flow_call2])
|
||||
expected_calls.append(mock.call(**call_args3))
|
||||
self.mock_bridge.br.add_flow.assert_has_calls(expected_calls)
|
||||
|
||||
def test_initialize_port_flows_dvr_conntrack_direct_vxlan(self):
|
||||
self._test_initialize_port_flows_dvr_conntrack_direct(
|
||||
network_type='vxlan')
|
||||
|
||||
def test_initialize_port_flows_dvr_conntrack_direct_vlan(self):
|
||||
self._test_initialize_port_flows_dvr_conntrack_direct(
|
||||
network_type='vlan')
|
||||
|
||||
def test_initialize_port_flows_dvr_conntrack_direct_flat(self):
|
||||
self._test_initialize_port_flows_dvr_conntrack_direct(
|
||||
network_type='flat')
|
||||
|
||||
def test_initialize_port_flows_vlan_dvr_conntrack_direct_vlan(self):
|
||||
port_dict = {
|
||||
|
@ -286,6 +286,48 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase):
|
||||
]
|
||||
self.assertEqual(expected, self.mock.mock_calls)
|
||||
|
||||
def test_install_dvr_to_src_mac_flat(self):
|
||||
network_type = 'flat'
|
||||
gateway_mac = '08:60:6e:7f:74:e7'
|
||||
dst_mac = '00:02:b3:13:fe:3d'
|
||||
dst_port = 6666
|
||||
self.br.install_dvr_to_src_mac(network_type=network_type,
|
||||
vlan_tag=None,
|
||||
gateway_mac=gateway_mac,
|
||||
dst_mac=dst_mac,
|
||||
dst_port=dst_port)
|
||||
(dp, ofp, ofpp) = self._get_dp()
|
||||
expected = [
|
||||
call._send_msg(ofpp.OFPFlowMod(dp,
|
||||
cookie=self.stamp,
|
||||
instructions=[
|
||||
ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, [
|
||||
ofpp.OFPActionSetField(eth_src=gateway_mac),
|
||||
]),
|
||||
ofpp.OFPInstructionGotoTable(table_id=60),
|
||||
],
|
||||
match=ofpp.OFPMatch(
|
||||
eth_dst=dst_mac,
|
||||
vlan_vid=ofp.OFPVID_NONE),
|
||||
priority=20,
|
||||
table_id=2),
|
||||
active_bundle=None),
|
||||
call._send_msg(ofpp.OFPFlowMod(dp,
|
||||
cookie=self.stamp,
|
||||
instructions=[
|
||||
ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, [
|
||||
ofpp.OFPActionOutput(dst_port, 0),
|
||||
]),
|
||||
],
|
||||
match=ofpp.OFPMatch(
|
||||
eth_dst=dst_mac,
|
||||
vlan_vid=ofp.OFPVID_NONE),
|
||||
priority=20,
|
||||
table_id=60),
|
||||
active_bundle=None),
|
||||
]
|
||||
self.assertEqual(expected, self.mock.mock_calls)
|
||||
|
||||
def test_delete_dvr_to_src_mac_vlan(self):
|
||||
network_type = 'vlan'
|
||||
vlan_tag = 1111
|
||||
@ -312,10 +354,36 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase):
|
||||
]
|
||||
self.assertEqual(expected, self.mock.mock_calls)
|
||||
|
||||
def test_add_dvr_mac_vlan(self):
|
||||
def test_delete_dvr_to_src_mac_flat(self):
|
||||
network_type = 'flat'
|
||||
vlan_tag = None
|
||||
dst_mac = '00:02:b3:13:fe:3d'
|
||||
self.br.delete_dvr_to_src_mac(network_type=network_type,
|
||||
vlan_tag=vlan_tag,
|
||||
dst_mac=dst_mac)
|
||||
(dp, ofp, ofpp) = self._get_dp()
|
||||
expected = [
|
||||
call.uninstall_flows(
|
||||
strict=True,
|
||||
priority=20,
|
||||
table_id=2,
|
||||
match=ofpp.OFPMatch(
|
||||
eth_dst=dst_mac,
|
||||
vlan_vid=ofp.OFPVID_NONE)),
|
||||
call.uninstall_flows(
|
||||
strict=True,
|
||||
priority=20,
|
||||
table_id=60,
|
||||
match=ofpp.OFPMatch(
|
||||
eth_dst=dst_mac,
|
||||
vlan_vid=ofp.OFPVID_NONE)),
|
||||
]
|
||||
self.assertEqual(expected, self.mock.mock_calls)
|
||||
|
||||
def test_add_dvr_mac_physical(self):
|
||||
mac = '00:02:b3:13:fe:3d'
|
||||
port = 8888
|
||||
self.br.add_dvr_mac_vlan(mac=mac, port=port)
|
||||
self.br.add_dvr_mac_physical(mac=mac, port=port)
|
||||
(dp, ofp, ofpp) = self._get_dp()
|
||||
expected = [
|
||||
call._send_msg(ofpp.OFPFlowMod(dp,
|
||||
@ -488,12 +556,15 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase):
|
||||
self.assertEqual(expected, self.mock.mock_calls)
|
||||
|
||||
def _test_delete_dvr_dst_mac_for_arp(self, network_type):
|
||||
if network_type == p_const.TYPE_VLAN:
|
||||
table_id = constants.DVR_TO_SRC_MAC_VLAN
|
||||
if network_type in (p_const.TYPE_VLAN, p_const.TYPE_FLAT):
|
||||
table_id = constants.DVR_TO_SRC_MAC_PHYSICAL
|
||||
else:
|
||||
table_id = constants.DVR_TO_SRC_MAC
|
||||
|
||||
vlan_tag = 1111
|
||||
if network_type == p_const.TYPE_FLAT:
|
||||
vlan_tag = None
|
||||
else:
|
||||
vlan_tag = 1111
|
||||
gateway_mac = '00:02:b3:13:fe:3e'
|
||||
dvr_mac = '00:02:b3:13:fe:3f'
|
||||
rtr_port = 8888
|
||||
@ -503,15 +574,26 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase):
|
||||
dvr_mac=dvr_mac,
|
||||
rtr_port=rtr_port)
|
||||
(dp, ofp, ofpp) = self._get_dp()
|
||||
expected = [
|
||||
call.uninstall_flows(
|
||||
strict=True,
|
||||
priority=5,
|
||||
table_id=table_id,
|
||||
match=ofpp.OFPMatch(
|
||||
eth_dst=dvr_mac,
|
||||
vlan_vid=vlan_tag | ofp.OFPVID_PRESENT)),
|
||||
]
|
||||
if network_type == p_const.TYPE_FLAT:
|
||||
expected = [
|
||||
call.uninstall_flows(
|
||||
strict=True,
|
||||
priority=5,
|
||||
table_id=table_id,
|
||||
match=ofpp.OFPMatch(
|
||||
eth_dst=dvr_mac,
|
||||
vlan_vid=ofp.OFPVID_NONE)),
|
||||
]
|
||||
else:
|
||||
expected = [
|
||||
call.uninstall_flows(
|
||||
strict=True,
|
||||
priority=5,
|
||||
table_id=table_id,
|
||||
match=ofpp.OFPMatch(
|
||||
eth_dst=dvr_mac,
|
||||
vlan_vid=vlan_tag | ofp.OFPVID_PRESENT)),
|
||||
]
|
||||
self.assertEqual(expected, self.mock.mock_calls)
|
||||
|
||||
def test_delete_dvr_dst_mac_for_arp_vlan(self):
|
||||
@ -520,6 +602,9 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase):
|
||||
def test_delete_dvr_dst_mac_for_arp_tunnel(self):
|
||||
self._test_delete_dvr_dst_mac_for_arp(network_type='vxlan')
|
||||
|
||||
def test_delete_dvr_dst_mac_for_flat(self):
|
||||
self._test_delete_dvr_dst_mac_for_arp(network_type='flat')
|
||||
|
||||
def test_install_dscp_marking_rule(self):
|
||||
test_port = 8888
|
||||
test_mark = 38
|
||||
|
@ -27,7 +27,7 @@ call = mock.call # short hand
|
||||
|
||||
class OVSPhysicalBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase,
|
||||
ovs_bridge_test_base.OVSDVRProcessTestMixin):
|
||||
dvr_process_table_id = ovs_const.DVR_PROCESS_VLAN
|
||||
dvr_process_table_id = ovs_const.DVR_PROCESS_PHYSICAL
|
||||
dvr_process_next_table_id = ovs_const.LOCAL_VLAN_TRANSLATION
|
||||
|
||||
def setUp(self):
|
||||
@ -125,10 +125,10 @@ class OVSPhysicalBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase,
|
||||
]
|
||||
self.assertEqual(expected, self.mock.mock_calls)
|
||||
|
||||
def test_add_dvr_mac_vlan(self):
|
||||
def test_add_dvr_mac_physical(self):
|
||||
mac = '00:02:b3:13:fe:3d'
|
||||
port = 8888
|
||||
self.br.add_dvr_mac_vlan(mac=mac, port=port)
|
||||
self.br.add_dvr_mac_physical(mac=mac, port=port)
|
||||
(dp, ofp, ofpp) = self._get_dp()
|
||||
expected = [
|
||||
call._send_msg(ofpp.OFPFlowMod(dp,
|
||||
|
@ -3078,8 +3078,8 @@ class TestOvsDvrNeutronAgent(object):
|
||||
),
|
||||
]
|
||||
|
||||
def _test_port_bound_for_dvr_on_vlan_network(
|
||||
self, device_owner, ip_version=n_const.IP_VERSION_4):
|
||||
def _test_port_bound_for_dvr_on_physical_network(
|
||||
self, device_owner, network_type, ip_version=n_const.IP_VERSION_4):
|
||||
self._setup_for_dvr_test()
|
||||
if ip_version == n_const.IP_VERSION_4:
|
||||
gateway_ip = '1.1.1.10'
|
||||
@ -3093,7 +3093,8 @@ class TestOvsDvrNeutronAgent(object):
|
||||
self._compute_port.vif_mac = '77:88:99:00:11:22'
|
||||
physical_network = self._physical_network
|
||||
segmentation_id = self._segmentation_id
|
||||
network_type = n_const.TYPE_VLAN
|
||||
if network_type == n_const.TYPE_FLAT:
|
||||
segmentation_id = None
|
||||
int_br = mock.create_autospec(self.agent.int_br)
|
||||
tun_br = mock.create_autospec(self.agent.tun_br)
|
||||
phys_br = mock.create_autospec(self.br_phys_cls('br-phys'))
|
||||
@ -3256,10 +3257,19 @@ class TestOvsDvrNeutronAgent(object):
|
||||
phys_br.assert_not_called()
|
||||
|
||||
def test_port_bound_for_dvr_with_compute_ports(self):
|
||||
self._test_port_bound_for_dvr_on_vlan_network(
|
||||
device_owner=DEVICE_OWNER_COMPUTE)
|
||||
self._test_port_bound_for_dvr_on_vlan_network(
|
||||
self._test_port_bound_for_dvr_on_physical_network(
|
||||
device_owner=DEVICE_OWNER_COMPUTE,
|
||||
network_type=n_const.TYPE_VLAN)
|
||||
self._test_port_bound_for_dvr_on_physical_network(
|
||||
device_owner=DEVICE_OWNER_COMPUTE,
|
||||
network_type=n_const.TYPE_VLAN,
|
||||
ip_version=n_const.IP_VERSION_6)
|
||||
self._test_port_bound_for_dvr_on_physical_network(
|
||||
device_owner=DEVICE_OWNER_COMPUTE,
|
||||
network_type=n_const.TYPE_FLAT)
|
||||
self._test_port_bound_for_dvr_on_physical_network(
|
||||
device_owner=DEVICE_OWNER_COMPUTE,
|
||||
network_type=n_const.TYPE_FLAT,
|
||||
ip_version=n_const.IP_VERSION_6)
|
||||
self._test_port_bound_for_dvr_on_vxlan_network(
|
||||
device_owner=DEVICE_OWNER_COMPUTE)
|
||||
@ -3268,10 +3278,19 @@ class TestOvsDvrNeutronAgent(object):
|
||||
ip_version=n_const.IP_VERSION_6)
|
||||
|
||||
def test_port_bound_for_dvr_with_dhcp_ports(self):
|
||||
self._test_port_bound_for_dvr_on_vlan_network(
|
||||
device_owner=n_const.DEVICE_OWNER_DHCP)
|
||||
self._test_port_bound_for_dvr_on_vlan_network(
|
||||
self._test_port_bound_for_dvr_on_physical_network(
|
||||
device_owner=n_const.DEVICE_OWNER_DHCP,
|
||||
network_type=n_const.TYPE_VLAN)
|
||||
self._test_port_bound_for_dvr_on_physical_network(
|
||||
device_owner=n_const.DEVICE_OWNER_DHCP,
|
||||
network_type=n_const.TYPE_VLAN,
|
||||
ip_version=n_const.IP_VERSION_6)
|
||||
self._test_port_bound_for_dvr_on_physical_network(
|
||||
device_owner=n_const.DEVICE_OWNER_DHCP,
|
||||
network_type=n_const.TYPE_FLAT)
|
||||
self._test_port_bound_for_dvr_on_physical_network(
|
||||
device_owner=n_const.DEVICE_OWNER_DHCP,
|
||||
network_type=n_const.TYPE_FLAT,
|
||||
ip_version=n_const.IP_VERSION_6)
|
||||
self._test_port_bound_for_dvr_on_vxlan_network(
|
||||
device_owner=n_const.DEVICE_OWNER_DHCP)
|
||||
@ -3737,8 +3756,9 @@ class TestOvsDvrNeutronAgent(object):
|
||||
mock.call.setup_canary_table(),
|
||||
mock.call.install_drop(table_id=constants.DVR_TO_SRC_MAC,
|
||||
priority=1),
|
||||
mock.call.install_drop(table_id=constants.DVR_TO_SRC_MAC_VLAN,
|
||||
priority=1),
|
||||
mock.call.install_drop(
|
||||
table_id=constants.DVR_TO_SRC_MAC_PHYSICAL,
|
||||
priority=1),
|
||||
mock.call.install_drop(table_id=constants.LOCAL_SWITCHING,
|
||||
priority=2,
|
||||
in_port=ioport),
|
||||
@ -3829,7 +3849,7 @@ class TestOvsDvrNeutronAgent(object):
|
||||
dvr_macs=[{'host': newhost,
|
||||
'mac_address': newmac}])
|
||||
expected_on_int_br = [
|
||||
mock.call.add_dvr_mac_vlan(
|
||||
mock.call.add_dvr_mac_physical(
|
||||
mac=newmac,
|
||||
port=self.agent.int_ofports[physical_network]),
|
||||
mock.call.add_dvr_mac_tun(
|
||||
@ -3842,7 +3862,7 @@ class TestOvsDvrNeutronAgent(object):
|
||||
port=self.agent.patch_int_ofport),
|
||||
]
|
||||
expected_on_phys_br = [
|
||||
mock.call.add_dvr_mac_vlan(
|
||||
mock.call.add_dvr_mac_physical(
|
||||
mac=newmac,
|
||||
port=self.agent.phys_ofports[physical_network]),
|
||||
]
|
||||
|
@ -0,0 +1,9 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
``DVR`` routers now support ``flat`` networks.
|
||||
fixes:
|
||||
- |
|
||||
Fixed bug `1876092 <https://bugs.launchpad.net/neutron/+bug/1876092>`_
|
||||
which caused DUP ICMP replies on the ``flat`` networks used with ``DVR``
|
||||
routers.
|
Loading…
Reference in New Issue
Block a user