Merge "Unicast reactive L3 flows to the correct tunnel port" into stable/kilo
This commit is contained in:
commit
fba2edb37e
|
@ -64,6 +64,7 @@ UINT32_MAX = 0xffffffff
|
|||
UINT64_MAX = 0xffffffffffffffff
|
||||
OFPFW_NW_PROTO = 1 << 5
|
||||
|
||||
REG_32BIT_ON_MASK = 0x80000000
|
||||
|
||||
HIGH_PRIORITY_FLOW = 1000
|
||||
MEDIUM_PRIORITY_FLOW = 100
|
||||
|
@ -942,6 +943,7 @@ class L3ReactiveApp(app_manager.RyuApp):
|
|||
local_switch.patch_port_num,
|
||||
dst_seg_id=dst_seg_id,
|
||||
cookie=cookie,
|
||||
dst_datapath=remote_switch.datapath,
|
||||
)
|
||||
|
||||
# Remote reverse flow install
|
||||
|
@ -960,6 +962,7 @@ class L3ReactiveApp(app_manager.RyuApp):
|
|||
remote_switch.patch_port_num,
|
||||
dst_seg_id=src_seg_id,
|
||||
cookie=cookie,
|
||||
dst_datapath=local_switch.datapath,
|
||||
)
|
||||
|
||||
self.handle_packet_out_l3(remote_switch.datapath,
|
||||
|
@ -980,7 +983,7 @@ class L3ReactiveApp(app_manager.RyuApp):
|
|||
src_seg_id, match_src_mac, match_dst_mac,
|
||||
match_dst_ip, match_src_ip, src_mac,
|
||||
dst_mac, out_port_num, dst_seg_id=None,
|
||||
cookie=0):
|
||||
cookie=0, dst_datapath=None):
|
||||
parser = datapath.ofproto_parser
|
||||
match = parser.OFPMatch()
|
||||
match.set_dl_type(ether.ETH_TYPE_IP)
|
||||
|
@ -996,11 +999,19 @@ class L3ReactiveApp(app_manager.RyuApp):
|
|||
actions.append(parser.OFPActionDecNwTtl())
|
||||
actions.append(parser.OFPActionSetField(eth_src=src_mac))
|
||||
actions.append(parser.OFPActionSetField(eth_dst=dst_mac))
|
||||
|
||||
if dst_datapath:
|
||||
dst_ip_hex = self._get_dp_ip_as_int(dst_datapath)
|
||||
if ryu.version_info >= (3, 24):
|
||||
#register Action set is supported only in 3.24
|
||||
actions.append(parser.OFPActionSetField(reg7=dst_ip_hex))
|
||||
|
||||
if dst_seg_id:
|
||||
# The dest vm is on another compute machine so we must set the
|
||||
# segmentation Id and set metadata for the tunnel bridge to
|
||||
# for this flow
|
||||
field = parser.OFPActionSetField(tunnel_id=dst_seg_id)
|
||||
mask_dst_seg = int(dst_seg_id) | REG_32BIT_ON_MASK
|
||||
field = parser.OFPActionSetField(tunnel_id=mask_dst_seg)
|
||||
actions.append(field)
|
||||
goto_inst = parser.OFPInstructionGotoTable(
|
||||
self.TUN_TRANSLATE_TABLE)
|
||||
|
@ -1401,7 +1412,7 @@ class L3ReactiveApp(app_manager.RyuApp):
|
|||
datapath,
|
||||
self.TUN_TRANSLATE_TABLE,
|
||||
port.port_no,
|
||||
HIGH_PRIORITY_FLOW)
|
||||
LOW_PRIORITY_FLOW)
|
||||
LOG.debug('OFPPortDescStatsReply received: %s', ports)
|
||||
switch.local_ports = ports
|
||||
#TODO(gampel) Install flows only for tenants with VMs running on
|
||||
|
@ -1511,6 +1522,13 @@ class L3ReactiveApp(app_manager.RyuApp):
|
|||
def check_direct_routing(self, tenant, from_subnet_id, to_subnet_id):
|
||||
return
|
||||
|
||||
def _get_dp_ip_as_int(self, datapath):
|
||||
try:
|
||||
return int(netaddr.IPAddress(datapath.address[0], version=4))
|
||||
except Exception:
|
||||
LOG.warn(_LW("Invalid remote IP: %s"), datapath.address)
|
||||
return
|
||||
|
||||
def _get_match_vrouter_arp_responder(self, datapath, segmentation_id,
|
||||
interface_ip):
|
||||
parser = datapath.ofproto_parser
|
||||
|
@ -1793,10 +1811,9 @@ class L3ReactiveApp(app_manager.RyuApp):
|
|||
match = parser.OFPMatch()
|
||||
match.set_dl_type(ether.ETH_TYPE_IP)
|
||||
actions = [parser.NXActionRegMove(src_field='tunnel_id',
|
||||
dst_field='pkt_mark',
|
||||
n_bits=32),
|
||||
dst_field='pkt_mark',
|
||||
n_bits=32),
|
||||
parser.OFPActionOutput(port=port)]
|
||||
|
||||
instructions = [parser.OFPInstructionActions(
|
||||
ofproto.OFPIT_APPLY_ACTIONS, actions)]
|
||||
self.mod_flow(
|
||||
|
|
|
@ -20,6 +20,8 @@ import eventlet
|
|||
|
||||
eventlet.monkey_patch()
|
||||
|
||||
from six import moves
|
||||
|
||||
from oslo_config import cfg
|
||||
|
||||
from neutron.agent.common import config
|
||||
|
@ -27,6 +29,7 @@ from neutron.agent.linux import ip_lib
|
|||
from neutron.agent.ovsdb import api as ovsdb
|
||||
|
||||
from neutron.common import config as common_config
|
||||
from neutron.common import constants as q_const
|
||||
from neutron.common import utils as q_utils
|
||||
|
||||
from neutron.i18n import _, _LE, _LI
|
||||
|
@ -43,10 +46,13 @@ agent_additional_opts = [
|
|||
help=("L3 Controler IP list list tcp:ip_addr:port;"
|
||||
"tcp:ip_addr:port..;..")),
|
||||
cfg.BoolOpt('enable_l3_controller', default=True,
|
||||
help=_("L3 SDN Controller"))
|
||||
help=_("L3 SDN Controller")),
|
||||
cfg.IntOpt('tunnel_map_check_rate', default=5,
|
||||
help=_("Rate in multiple of the rpc loop")),
|
||||
]
|
||||
|
||||
cfg.CONF.register_opts(agent_additional_opts, "AGENT")
|
||||
TUN_TRANSLATE_TABLE = 60
|
||||
|
||||
|
||||
class L2OVSControllerAgent(ona.OVSNeutronAgent):
|
||||
|
@ -74,6 +80,7 @@ class L2OVSControllerAgent(ona.OVSNeutronAgent):
|
|||
'''
|
||||
self.set_controller_lock = threading.Lock()
|
||||
self.enable_l3_controller = cfg.CONF.AGENT.enable_l3_controller
|
||||
self.tunnel_map_check_rate = cfg.CONF.AGENT.tunnel_map_check_rate
|
||||
|
||||
super(L2OVSControllerAgent, self) \
|
||||
.__init__(integ_br,
|
||||
|
@ -90,8 +97,12 @@ class L2OVSControllerAgent(ona.OVSNeutronAgent):
|
|||
use_veth_interconnection,
|
||||
quitting_rpc_timeout)
|
||||
|
||||
# Initialize controller
|
||||
self.df_available_local_vlans = set(moves.range(q_const.MIN_VLAN_TAG,
|
||||
q_const.MAX_VLAN_TAG))
|
||||
#mapping from vlan to destination tunnel ip
|
||||
self.df_local_to_vlan_map = {}
|
||||
self.controllers_ip_list = cfg.CONF.AGENT.L3controller_ip_list
|
||||
# Initialize controller
|
||||
self.set_controller_for_br(self.int_br, self.controllers_ip_list)
|
||||
|
||||
def set_controller_for_br(self, bridge, ip_address_list):
|
||||
|
@ -121,12 +132,7 @@ class L2OVSControllerAgent(ona.OVSNeutronAgent):
|
|||
if self.patch_tun_ofport > 0:
|
||||
# Mark the tunnel ID so the data will be transferred to the
|
||||
# br-tun virtual switch, tun id and metadata are local
|
||||
bridge.add_flow(table="60", priority=1,
|
||||
actions="move:NXM_NX_TUN_ID[0..31]"
|
||||
"->NXM_NX_PKT_MARK[],"
|
||||
"output:%s" %
|
||||
(self.patch_tun_ofport))
|
||||
|
||||
self._add_tun_translate_pack_mark_flow(bridge)
|
||||
# add the normal flow higher priority than the drop
|
||||
for br in self.phys_brs.values():
|
||||
br.add_flow(priority=3, actions="normal")
|
||||
|
@ -150,16 +156,75 @@ class L2OVSControllerAgent(ona.OVSNeutronAgent):
|
|||
local_vlan_map['physical_network'],
|
||||
local_vlan_map['segmentation_id'])
|
||||
|
||||
def _add_tun_translate_pack_mark_flow(self, bridge):
|
||||
bridge.add_flow(table=TUN_TRANSLATE_TABLE, priority=1,
|
||||
actions="move:NXM_NX_TUN_ID[0..31]"
|
||||
"->NXM_NX_PKT_MARK[],"
|
||||
"output:%s" %
|
||||
(self.patch_tun_ofport))
|
||||
|
||||
def _check_tunnel_map_table(self):
|
||||
"""Verify that the tunnel ip mapping is installed
|
||||
on the integration bridge
|
||||
"""
|
||||
|
||||
if p_const.TYPE_VLAN in self.tunnel_types:
|
||||
# TODO(gampel) check for the vlan flows here
|
||||
return
|
||||
if not self.df_local_to_vlan_map:
|
||||
return
|
||||
tunnel_flows = self.int_br.dump_flows_for_table(
|
||||
TUN_TRANSLATE_TABLE)
|
||||
for tunnel_ip in self.df_local_to_vlan_map:
|
||||
vlan_action = "mod_vlan_vid:%d" % (
|
||||
self.df_local_to_vlan_map[tunnel_ip])
|
||||
if vlan_action not in tunnel_flows:
|
||||
self.tunnel_sync()
|
||||
self._add_tun_translate_pack_mark_flow(self.int_br)
|
||||
|
||||
def check_ovs_status(self):
|
||||
if not self.enable_l3_controller:
|
||||
return super(L2OVSControllerAgent, self).check_ovs_status()
|
||||
|
||||
# Check for the canary flow
|
||||
# Add lock to avoid race condition of flows
|
||||
with self.set_controller_lock:
|
||||
ret = super(L2OVSControllerAgent, self).check_ovs_status()
|
||||
if not self.iter_num % self.tunnel_map_check_rate:
|
||||
self._check_tunnel_map_table()
|
||||
return ret
|
||||
|
||||
def _claim_df_tunnel_local_vlan(self, tunnel_ip_hex):
|
||||
lvid = None
|
||||
if tunnel_ip_hex in self.df_local_to_vlan_map:
|
||||
lvid = self.df_local_to_vlan_map[tunnel_ip_hex]
|
||||
else:
|
||||
lvid = self.df_available_local_vlans.pop()
|
||||
self.df_local_to_vlan_map[tunnel_ip_hex] = lvid
|
||||
return lvid
|
||||
|
||||
def _release_df_tunnel_local_vlan(self, tunnel_ip_hex):
|
||||
lvid = self.df_local_to_vlan_map.pop(tunnel_ip_hex, None)
|
||||
self.df_available_local_vlans.add(lvid)
|
||||
|
||||
def cleanup_tunnel_port(self, br, tun_ofport, tunnel_type):
|
||||
items = list(self.tun_br_ofports[tunnel_type].items())
|
||||
for remote_ip, ofport in items:
|
||||
if ofport == tun_ofport:
|
||||
tunnel_ip_hex = "0x%s" % self.get_ip_in_hex(remote_ip)
|
||||
lvid = self.df_local_to_vlan_map[tunnel_ip_hex]
|
||||
self.int_br.delete_flows(
|
||||
table=TUN_TRANSLATE_TABLE,
|
||||
reg7=tunnel_ip_hex)
|
||||
br.delete_flows(
|
||||
table=constants.UCAST_TO_TUN,
|
||||
dl_vlan=lvid)
|
||||
self._release_df_tunnel_local_vlan(tunnel_ip_hex)
|
||||
|
||||
return super(L2OVSControllerAgent, self).cleanup_tunnel_port(
|
||||
br,
|
||||
tun_ofport,
|
||||
tunnel_type)
|
||||
|
||||
def _setup_tunnel_port(self, br, port_name, remote_ip, tunnel_type):
|
||||
ofport = super(L2OVSControllerAgent, self) \
|
||||
._setup_tunnel_port(
|
||||
|
@ -167,14 +232,33 @@ class L2OVSControllerAgent(ona.OVSNeutronAgent):
|
|||
port_name,
|
||||
remote_ip,
|
||||
tunnel_type)
|
||||
if p_const.TYPE_VLAN not in self.tunnel_types:
|
||||
tunnel_ip_hex = "0x%s" % self.get_ip_in_hex(remote_ip)
|
||||
lvid = self._claim_df_tunnel_local_vlan(tunnel_ip_hex)
|
||||
self.int_br.add_flow(
|
||||
table=TUN_TRANSLATE_TABLE,
|
||||
priority=2000,
|
||||
reg7=tunnel_ip_hex,
|
||||
actions="mod_vlan_vid:%s,"
|
||||
"load:0->NXM_NX_REG7[0..31],"
|
||||
"resubmit(,%s)" %
|
||||
(lvid, TUN_TRANSLATE_TABLE))
|
||||
br.add_flow(table=constants.UCAST_TO_TUN,
|
||||
priority=100,
|
||||
dl_vlan=lvid,
|
||||
pkt_mark="0x80000000/0x80000000",
|
||||
actions="strip_vlan,move:NXM_NX_PKT_MARK[0..30]"
|
||||
"->NXM_NX_TUN_ID[0..30],"
|
||||
"output:%s" %
|
||||
(ofport))
|
||||
if ofport > 0:
|
||||
ofports = (ona._ofport_set_to_str
|
||||
(self.tun_br_ofports[tunnel_type].values()))
|
||||
if self.enable_l3_controller:
|
||||
if ofports:
|
||||
br.add_flow(table=constants.FLOOD_TO_TUN,
|
||||
actions="move:NXM_NX_PKT_MARK[]"
|
||||
"->NXM_NX_TUN_ID[0..31],"
|
||||
actions="move:NXM_NX_PKT_MARK[0..30]"
|
||||
"->NXM_NX_TUN_ID[0..30],"
|
||||
"output:%s" %
|
||||
(ofports))
|
||||
return ofport
|
||||
|
@ -186,7 +270,8 @@ class L2OVSControllerAgent(ona.OVSNeutronAgent):
|
|||
#outbound
|
||||
# The global vlan id is set in table 60
|
||||
# from segmentation id/tun id
|
||||
self.int_br.add_flow(table="60", priority=1,
|
||||
self.int_br.add_flow(table=TUN_TRANSLATE_TABLE,
|
||||
priority=1,
|
||||
actions="move:NXM_NX_TUN_ID[0..11]"
|
||||
"->OXM_OF_VLAN_VID[],"
|
||||
"output:%s" %
|
||||
|
|
Loading…
Reference in New Issue