From e56bfa467d871b95ee4e57e215ef10a2db96e37c Mon Sep 17 00:00:00 2001 From: YAMAMOTO Takashi Date: Mon, 11 Aug 2014 13:41:13 +0900 Subject: [PATCH] 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 --- neutron/plugins/ml2/drivers/mech_ofagent.py | 18 +++-- neutron/plugins/ofagent/README | 22 ++++++ .../ofagent/agent/ofa_neutron_agent.py | 40 +++++++++-- neutron/plugins/ofagent/common/config.py | 3 + neutron/plugins/openvswitch/common/config.py | 3 +- .../unit/ml2/drivers/test_ofagent_mech.py | 71 +++++++++++++++++-- .../unit/ofagent/test_ofa_neutron_agent.py | 7 ++ 7 files changed, 146 insertions(+), 18 deletions(-) diff --git a/neutron/plugins/ml2/drivers/mech_ofagent.py b/neutron/plugins/ml2/drivers/mech_ofagent.py index b593e61d6b..6a25c98c9e 100644 --- a/neutron/plugins/ml2/drivers/mech_ofagent.py +++ b/neutron/plugins/ml2/drivers/mech_ofagent.py @@ -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)) ) diff --git a/neutron/plugins/ofagent/README b/neutron/plugins/ofagent/README index 51164a1efc..b18172c198 100644 --- a/neutron/plugins/ofagent/README +++ b/neutron/plugins/ofagent/README @@ -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 diff --git a/neutron/plugins/ofagent/agent/ofa_neutron_agent.py b/neutron/plugins/ofagent/agent/ofa_neutron_agent.py index 8be7fa5cb4..be7c0bbff5 100644 --- a/neutron/plugins/ofagent/agent/ofa_neutron_agent.py +++ b/neutron/plugins/ofagent/agent/ofa_neutron_agent.py @@ -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, diff --git a/neutron/plugins/ofagent/common/config.py b/neutron/plugins/ofagent/common/config.py index 759d3df1db..0b2b44890b 100644 --- a/neutron/plugins/ofagent/common/config.py +++ b/neutron/plugins/ofagent/common/config.py @@ -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 :")), ] diff --git a/neutron/plugins/openvswitch/common/config.py b/neutron/plugins/openvswitch/common/config.py index 07ab6564a6..d9e0454839 100644 --- a/neutron/plugins/openvswitch/common/config.py +++ b/neutron/plugins/openvswitch/common/config.py @@ -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 :")), + help=_("List of :. " + "Deprecated for ofagent.")), cfg.StrOpt('tenant_network_type', default='local', help=_("Network type for tenant networks " "(local, vlan, gre, vxlan, or none).")), diff --git a/neutron/tests/unit/ml2/drivers/test_ofagent_mech.py b/neutron/tests/unit/ml2/drivers/test_ofagent_mech.py index 63daf9ec05..3187f296b4 100644 --- a/neutron/tests/unit/ml2/drivers/test_ofagent_mech.py +++ b/neutron/tests/unit/ml2/drivers/test_ofagent_mech.py @@ -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 diff --git a/neutron/tests/unit/ofagent/test_ofa_neutron_agent.py b/neutron/tests/unit/ofagent/test_ofa_neutron_agent.py index b9b83655dc..5b5f629805 100644 --- a/neutron/tests/unit/ofagent/test_ofa_neutron_agent.py +++ b/neutron/tests/unit/ofagent/test_ofa_neutron_agent.py @@ -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"),