ofagent: Implement physical_interface_mappings

Mark bridge_mappings as deprecated for ofagent.
Document that it will be removed in Kilo.

Implements: blueprint ofagent-physical-interface-mappings
Change-Id: I38e3b6aad2914dc5425435dd7775f66306375cd2
This commit is contained in:
YAMAMOTO Takashi 2014-08-11 13:41:13 +09:00
parent 213ad578b3
commit e56bfa467d
7 changed files with 146 additions and 18 deletions

View File

@ -45,17 +45,23 @@ class OfagentMechanismDriver(mech_agent.SimpleAgentMechanismDriverBase):
portbindings.OVS_HYBRID_PLUG: True}) portbindings.OVS_HYBRID_PLUG: True})
def check_segment_for_agent(self, segment, agent): def check_segment_for_agent(self, segment, agent):
mappings = agent['configurations'].get('bridge_mappings', {}) bridge_mappings = agent['configurations'].get('bridge_mappings', {})
interface_mappings = agent['configurations'].get('interface_mappings',
{})
tunnel_types = agent['configurations'].get('tunnel_types', []) tunnel_types = agent['configurations'].get('tunnel_types', [])
LOG.debug(_("Checking segment: %(segment)s " LOG.debug("Checking segment: %(segment)s "
"for mappings: %(mappings)s " "for bridge_mappings: %(bridge_mappings)s "
"with tunnel_types: %(tunnel_types)s"), "and interface_mappings: %(interface_mappings)s "
{'segment': segment, 'mappings': mappings, "with tunnel_types: %(tunnel_types)s",
{'segment': segment,
'bridge_mappings': bridge_mappings,
'interface_mappings': interface_mappings,
'tunnel_types': tunnel_types}) 'tunnel_types': tunnel_types})
network_type = segment[api.NETWORK_TYPE] network_type = segment[api.NETWORK_TYPE]
return ( return (
network_type == p_const.TYPE_LOCAL or network_type == p_const.TYPE_LOCAL or
network_type in tunnel_types or network_type in tunnel_types or
(network_type in [p_const.TYPE_FLAT, p_const.TYPE_VLAN] and (network_type in [p_const.TYPE_FLAT, p_const.TYPE_VLAN] and
segment[api.PHYSICAL_NETWORK] in mappings) (segment[api.PHYSICAL_NETWORK] in bridge_mappings
or segment[api.PHYSICAL_NETWORK] in interface_mappings))
) )

View File

@ -7,6 +7,28 @@ https://github.com/osrg/ryu/wiki/OpenStack
# -- Notes for updating from Icehouce # -- Notes for updating from Icehouce
OVS.bridge_mappings is deprecated for ofagent. It's planned to be
removed in Kilo. Please use AGENT.physical_interface_mappings instead.
To mimic an existing setup with bridge_mapping, you can create
a veth pair, link one side of it to the bridge, and then specify
the other side in physical_interface_mappings.
For example, if you have the following:
[OVS]
bridge_mappings=public:br-ex
You can do:
# ip link add int-public type veth peer name phy-public
# ip link set int-public up
# ip link set phy-public up
# ovs-vsctl add-port br-ex phy-public
and then replace the bridge_mappings with:
[AGENT]
physical_interface_mappings=public:int-public
After Icehouce, most of the functionality have been folded into After Icehouce, most of the functionality have been folded into
a single bridge, the integration bridge. (aka. br-int) a single bridge, the integration bridge. (aka. br-int)
The integration bridge is the only bridge which would have an The integration bridge is the only bridge which would have an

View File

@ -199,7 +199,7 @@ class OFANeutronAgent(n_rpc.RpcCallback,
RPC_API_VERSION = '1.1' RPC_API_VERSION = '1.1'
def __init__(self, ryuapp, integ_br, local_ip, def __init__(self, ryuapp, integ_br, local_ip,
bridge_mappings, root_helper, bridge_mappings, interface_mappings, root_helper,
polling_interval, tunnel_types=None, polling_interval, tunnel_types=None,
veth_mtu=None): veth_mtu=None):
"""Constructor. """Constructor.
@ -208,6 +208,9 @@ class OFANeutronAgent(n_rpc.RpcCallback,
:param integ_br: name of the integration bridge. :param integ_br: name of the integration bridge.
:param local_ip: local IP address of this hypervisor. :param local_ip: local IP address of this hypervisor.
:param bridge_mappings: mappings from physical network name to bridge. :param bridge_mappings: mappings from physical network name to bridge.
(deprecated)
:param interface_mappings: mappings from physical network name to
interface.
:param root_helper: utility to use when running shell cmds. :param root_helper: utility to use when running shell cmds.
:param polling_interval: interval (secs) to poll DB. :param polling_interval: interval (secs) to poll DB.
:param tunnel_types: A list of tunnel types to enable support for in :param tunnel_types: A list of tunnel types to enable support for in
@ -229,11 +232,13 @@ class OFANeutronAgent(n_rpc.RpcCallback,
'binary': 'neutron-ofa-agent', 'binary': 'neutron-ofa-agent',
'host': cfg.CONF.host, 'host': cfg.CONF.host,
'topic': n_const.L2_AGENT_TOPIC, 'topic': n_const.L2_AGENT_TOPIC,
'configurations': {'bridge_mappings': bridge_mappings, 'configurations': {
'tunnel_types': self.tunnel_types, 'bridge_mappings': bridge_mappings,
'tunneling_ip': local_ip, 'interface_mappings': interface_mappings,
'l2_population': True, 'tunnel_types': self.tunnel_types,
'l2pop_network_types': l2pop_network_types}, 'tunneling_ip': local_ip,
'l2_population': True,
'l2pop_network_types': l2pop_network_types},
'agent_type': n_const.AGENT_TYPE_OFA, 'agent_type': n_const.AGENT_TYPE_OFA,
'start_flag': True} 'start_flag': True}
@ -245,6 +250,9 @@ class OFANeutronAgent(n_rpc.RpcCallback,
self.updated_ports = set() self.updated_ports = set()
self.setup_rpc() self.setup_rpc()
self.setup_integration_br() self.setup_integration_br()
self.int_ofports = {}
self.setup_physical_interfaces(interface_mappings)
# TODO(yamamoto): Remove physical bridge support
self.setup_physical_bridges(bridge_mappings) self.setup_physical_bridges(bridge_mappings)
self.local_vlan_map = {} self.local_vlan_map = {}
self.tun_ofports = {} self.tun_ofports = {}
@ -638,7 +646,6 @@ class OFANeutronAgent(n_rpc.RpcCallback,
:param bridge_mappings: map physical network names to bridge names. :param bridge_mappings: map physical network names to bridge names.
""" """
self.phys_brs = {} self.phys_brs = {}
self.int_ofports = {}
self.phys_ofports = {} self.phys_ofports = {}
ip_wrapper = ip_lib.IPWrapper(self.root_helper) ip_wrapper = ip_lib.IPWrapper(self.root_helper)
for physical_network, bridge in bridge_mappings.iteritems(): for physical_network, bridge in bridge_mappings.iteritems():
@ -660,6 +667,18 @@ class OFANeutronAgent(n_rpc.RpcCallback,
self._phys_br_patch_physical_bridge_with_integration_bridge( self._phys_br_patch_physical_bridge_with_integration_bridge(
br, physical_network, bridge, ip_wrapper) br, physical_network, bridge, ip_wrapper)
def setup_physical_interfaces(self, interface_mappings):
"""Setup the physical network interfaces.
Link physical network interfaces to the integration bridge.
:param interface_mappings: map physical network names to
interface names.
"""
for physical_network, interface_name in interface_mappings.iteritems():
ofport = int(self.int_br.add_port(interface_name))
self.int_ofports[physical_network] = ofport
def scan_ports(self, registered_ports, updated_ports=None): def scan_ports(self, registered_ports, updated_ports=None):
cur_ports = self._get_ofport_names(self.int_br) cur_ports = self._get_ofport_names(self.int_br)
self.int_br_device_count = len(cur_ports) self.int_br_device_count = len(cur_ports)
@ -968,10 +987,17 @@ def create_agent_config_map(config):
bridge_mappings = n_utils.parse_mappings(config.OVS.bridge_mappings) bridge_mappings = n_utils.parse_mappings(config.OVS.bridge_mappings)
except ValueError as e: except ValueError as e:
raise ValueError(_("Parsing bridge_mappings failed: %s.") % e) raise ValueError(_("Parsing bridge_mappings failed: %s.") % e)
try:
interface_mappings = n_utils.parse_mappings(
config.AGENT.physical_interface_mappings)
except ValueError as e:
raise ValueError(_("Parsing physical_interface_mappings failed: %s.")
% e)
kwargs = dict( kwargs = dict(
integ_br=config.OVS.integration_bridge, integ_br=config.OVS.integration_bridge,
local_ip=config.OVS.local_ip, local_ip=config.OVS.local_ip,
interface_mappings=interface_mappings,
bridge_mappings=bridge_mappings, bridge_mappings=bridge_mappings,
root_helper=config.AGENT.root_helper, root_helper=config.AGENT.root_helper,
polling_interval=config.AGENT.polling_interval, polling_interval=config.AGENT.polling_interval,

View File

@ -23,6 +23,9 @@ agent_opts = [
cfg.IntOpt('get_datapath_retry_times', default=60, cfg.IntOpt('get_datapath_retry_times', default=60,
help=_("Number of seconds to retry acquiring " help=_("Number of seconds to retry acquiring "
"an Open vSwitch datapath")), "an Open vSwitch datapath")),
cfg.ListOpt('physical_interface_mappings',
default=[],
help=_("List of <physical_network>:<physical_interface>")),
] ]

View File

@ -41,7 +41,8 @@ ovs_opts = [
help=_("Local IP address of GRE tunnel endpoints.")), help=_("Local IP address of GRE tunnel endpoints.")),
cfg.ListOpt('bridge_mappings', cfg.ListOpt('bridge_mappings',
default=DEFAULT_BRIDGE_MAPPINGS, default=DEFAULT_BRIDGE_MAPPINGS,
help=_("List of <physical_network>:<bridge>")), help=_("List of <physical_network>:<bridge>. "
"Deprecated for ofagent.")),
cfg.StrOpt('tenant_network_type', default='local', cfg.StrOpt('tenant_network_type', default='local',
help=_("Network type for tenant networks " help=_("Network type for tenant networks "
"(local, vlan, gre, vxlan, or none).")), "(local, vlan, gre, vxlan, or none).")),

View File

@ -24,14 +24,14 @@ class OfagentMechanismBaseTestCase(base.AgentMechanismBaseTestCase):
CAP_PORT_FILTER = True CAP_PORT_FILTER = True
AGENT_TYPE = constants.AGENT_TYPE_OFA AGENT_TYPE = constants.AGENT_TYPE_OFA
GOOD_MAPPINGS = {'fake_physical_network': 'fake_bridge'} GOOD_MAPPINGS = {'fake_physical_network': 'fake_interface'}
GOOD_TUNNEL_TYPES = ['gre', 'vxlan'] GOOD_TUNNEL_TYPES = ['gre', 'vxlan']
GOOD_CONFIGS = {'bridge_mappings': GOOD_MAPPINGS, GOOD_CONFIGS = {'interface_mappings': GOOD_MAPPINGS,
'tunnel_types': GOOD_TUNNEL_TYPES} 'tunnel_types': GOOD_TUNNEL_TYPES}
BAD_MAPPINGS = {'wrong_physical_network': 'wrong_bridge'} BAD_MAPPINGS = {'wrong_physical_network': 'wrong_interface'}
BAD_TUNNEL_TYPES = ['bad_tunnel_type'] BAD_TUNNEL_TYPES = ['bad_tunnel_type']
BAD_CONFIGS = {'bridge_mappings': BAD_MAPPINGS, BAD_CONFIGS = {'interface_mappings': BAD_MAPPINGS,
'tunnel_types': BAD_TUNNEL_TYPES} 'tunnel_types': BAD_TUNNEL_TYPES}
AGENTS = [{'alive': True, AGENTS = [{'alive': True,
@ -72,3 +72,66 @@ class OfagentMechanismVlanTestCase(OfagentMechanismBaseTestCase,
class OfagentMechanismGreTestCase(OfagentMechanismBaseTestCase, class OfagentMechanismGreTestCase(OfagentMechanismBaseTestCase,
base.AgentMechanismGreTestCase): base.AgentMechanismGreTestCase):
pass pass
# The following tests are for deprecated "bridge_mappings".
# TODO(yamamoto): Remove them.
class OfagentMechanismPhysBridgeTestCase(base.AgentMechanismBaseTestCase):
VIF_TYPE = portbindings.VIF_TYPE_OVS
CAP_PORT_FILTER = True
AGENT_TYPE = constants.AGENT_TYPE_OFA
GOOD_MAPPINGS = {'fake_physical_network': 'fake_bridge'}
GOOD_TUNNEL_TYPES = ['gre', 'vxlan']
GOOD_CONFIGS = {'bridge_mappings': GOOD_MAPPINGS,
'tunnel_types': GOOD_TUNNEL_TYPES}
BAD_MAPPINGS = {'wrong_physical_network': 'wrong_bridge'}
BAD_TUNNEL_TYPES = ['bad_tunnel_type']
BAD_CONFIGS = {'bridge_mappings': BAD_MAPPINGS,
'tunnel_types': BAD_TUNNEL_TYPES}
AGENTS = [{'alive': True,
'configurations': GOOD_CONFIGS}]
AGENTS_DEAD = [{'alive': False,
'configurations': GOOD_CONFIGS}]
AGENTS_BAD = [{'alive': False,
'configurations': GOOD_CONFIGS},
{'alive': True,
'configurations': BAD_CONFIGS}]
def setUp(self):
super(OfagentMechanismPhysBridgeTestCase, self).setUp()
self.driver = mech_ofagent.OfagentMechanismDriver()
self.driver.initialize()
class OfagentMechanismPhysBridgeGenericTestCase(
OfagentMechanismPhysBridgeTestCase,
base.AgentMechanismGenericTestCase):
pass
class OfagentMechanismPhysBridgeLocalTestCase(
OfagentMechanismPhysBridgeTestCase,
base.AgentMechanismLocalTestCase):
pass
class OfagentMechanismPhysBridgeFlatTestCase(
OfagentMechanismPhysBridgeTestCase,
base.AgentMechanismFlatTestCase):
pass
class OfagentMechanismPhysBridgeVlanTestCase(
OfagentMechanismPhysBridgeTestCase,
base.AgentMechanismVlanTestCase):
pass
class OfagentMechanismPhysBridgeGreTestCase(
OfagentMechanismPhysBridgeTestCase,
base.AgentMechanismGreTestCase):
pass

View File

@ -490,6 +490,13 @@ class TestOFANeutronAgent(ofa_test_base.OFAAgentTestBase):
self.assertEqual(11, self.agent.int_ofports["physnet1"]) self.assertEqual(11, self.agent.int_ofports["physnet1"])
self.assertEqual(25, self.agent.phys_ofports["physnet1"]) self.assertEqual(25, self.agent.phys_ofports["physnet1"])
def test_setup_physical_interfaces(self):
with mock.patch.object(self.agent.int_br, "add_port") as add_port_fn:
add_port_fn.return_value = "111"
self.agent.setup_physical_interfaces({"physnet1": "eth1"})
add_port_fn.assert_called_once_with("eth1")
self.assertEqual(111, self.agent.int_ofports["physnet1"])
def test_port_unbound(self): def test_port_unbound(self):
with contextlib.nested( with contextlib.nested(
mock.patch.object(self.agent, "reclaim_local_vlan"), mock.patch.object(self.agent, "reclaim_local_vlan"),