Make DVR router support FLAT network for ovs-agent
Currently codes only support assocate tunnel network and vlan network to DVR router. This patch add codes that make the flat network assocate to DVR router and make it work fine. The patch also remove two unused constant entries: 'FLAT_VLAN_ID' and 'LOCAL_VLAN_ID' Change-Id: I7d792ce288d96548298f169748565266a130bd86 Closes-Bug: #1876092
This commit is contained in:
parent
64b92687a5
commit
cd721a7dcb
neutron
agent/linux/openvswitch_firewall
plugins/ml2/drivers
linuxbridge/agent/common
openvswitch/agent
tests
functional/agent
unit
agent/linux/openvswitch_firewall
plugins/ml2/drivers/openvswitch/agent
releasenotes/notes
@ -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(
|
||||
|
@ -896,18 +896,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]
|
||||
@ -988,7 +978,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 "
|
||||
@ -997,8 +987,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…
x
Reference in New Issue
Block a user