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 650e76abc5
commit 160305653e
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})
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', [])
LOG.debug(_("Checking segment: %(segment)s "
"for mappings: %(mappings)s "
"with tunnel_types: %(tunnel_types)s"),
{'segment': segment, 'mappings': mappings,
LOG.debug("Checking segment: %(segment)s "
"for bridge_mappings: %(bridge_mappings)s "
"and interface_mappings: %(interface_mappings)s "
"with tunnel_types: %(tunnel_types)s",
{'segment': segment,
'bridge_mappings': bridge_mappings,
'interface_mappings': interface_mappings,
'tunnel_types': tunnel_types})
network_type = segment[api.NETWORK_TYPE]
return (
network_type == p_const.TYPE_LOCAL or
network_type in tunnel_types or
(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
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
a single bridge, the integration bridge. (aka. br-int)
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'
def __init__(self, ryuapp, integ_br, local_ip,
bridge_mappings, root_helper,
bridge_mappings, interface_mappings, root_helper,
polling_interval, tunnel_types=None,
veth_mtu=None):
"""Constructor.
@ -208,6 +208,9 @@ class OFANeutronAgent(n_rpc.RpcCallback,
:param integ_br: name of the integration bridge.
:param local_ip: local IP address of this hypervisor.
: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 polling_interval: interval (secs) to poll DB.
: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',
'host': cfg.CONF.host,
'topic': n_const.L2_AGENT_TOPIC,
'configurations': {'bridge_mappings': bridge_mappings,
'tunnel_types': self.tunnel_types,
'tunneling_ip': local_ip,
'l2_population': True,
'l2pop_network_types': l2pop_network_types},
'configurations': {
'bridge_mappings': bridge_mappings,
'interface_mappings': interface_mappings,
'tunnel_types': self.tunnel_types,
'tunneling_ip': local_ip,
'l2_population': True,
'l2pop_network_types': l2pop_network_types},
'agent_type': n_const.AGENT_TYPE_OFA,
'start_flag': True}
@ -245,6 +250,9 @@ class OFANeutronAgent(n_rpc.RpcCallback,
self.updated_ports = set()
self.setup_rpc()
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.local_vlan_map = {}
self.tun_ofports = {}
@ -638,7 +646,6 @@ class OFANeutronAgent(n_rpc.RpcCallback,
:param bridge_mappings: map physical network names to bridge names.
"""
self.phys_brs = {}
self.int_ofports = {}
self.phys_ofports = {}
ip_wrapper = ip_lib.IPWrapper(self.root_helper)
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(
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):
cur_ports = self._get_ofport_names(self.int_br)
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)
except ValueError as 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(
integ_br=config.OVS.integration_bridge,
local_ip=config.OVS.local_ip,
interface_mappings=interface_mappings,
bridge_mappings=bridge_mappings,
root_helper=config.AGENT.root_helper,
polling_interval=config.AGENT.polling_interval,

View File

@ -23,6 +23,9 @@ agent_opts = [
cfg.IntOpt('get_datapath_retry_times', default=60,
help=_("Number of seconds to retry acquiring "
"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.")),
cfg.ListOpt('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',
help=_("Network type for tenant networks "
"(local, vlan, gre, vxlan, or none).")),

View File

@ -24,14 +24,14 @@ class OfagentMechanismBaseTestCase(base.AgentMechanismBaseTestCase):
CAP_PORT_FILTER = True
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_CONFIGS = {'bridge_mappings': GOOD_MAPPINGS,
GOOD_CONFIGS = {'interface_mappings': GOOD_MAPPINGS,
'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_CONFIGS = {'bridge_mappings': BAD_MAPPINGS,
BAD_CONFIGS = {'interface_mappings': BAD_MAPPINGS,
'tunnel_types': BAD_TUNNEL_TYPES}
AGENTS = [{'alive': True,
@ -72,3 +72,66 @@ class OfagentMechanismVlanTestCase(OfagentMechanismBaseTestCase,
class OfagentMechanismGreTestCase(OfagentMechanismBaseTestCase,
base.AgentMechanismGreTestCase):
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(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):
with contextlib.nested(
mock.patch.object(self.agent, "reclaim_local_vlan"),