Merge "Unicast reactive L3 flows to the correct tunnel port" into stable/kilo

This commit is contained in:
Jenkins 2015-09-28 20:53:44 +00:00 committed by Gerrit Code Review
commit fba2edb37e
2 changed files with 120 additions and 18 deletions

View File

@ -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(

View File

@ -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" %