Use patch ports to interconnect integration/physical bridges

Use by default patch ports to interconnect the integration to
physical bridges for the openvswitch agent in order to increase
performance.

For ovs/kernel without ovs patch port support on kernel side, veths
can be used through the new option OVS.use_veth_interconnection.

Patch port support can be tested using:

    neutron-sanity-check --ovs_patch

DocImpact
Closes-Bug: #1285335
Change-Id: I47106e57bf5b23891d7bf43815959e0d10156fba
This commit is contained in:
Cedric Brandily 2014-02-27 00:00:16 +01:00
parent c8f39514cf
commit 58625c8461
8 changed files with 372 additions and 197 deletions

View File

@ -83,6 +83,11 @@
# bridge_mappings =
# Example: bridge_mappings = physnet1:br-eth1
# (BoolOpt) Use veths instead of patch ports to interconnect the integration
# bridge to physical networks. Support kernel without ovs patch port support
# so long as it is set to True.
# use_veth_interconnection = False
[agent]
# Agent's polling interval in seconds
# polling_interval = 2
@ -117,6 +122,7 @@
# (IntOpt) This is the MTU size of veth interfaces.
# Do not change unless you have a good reason to.
# The default MTU size of veth interfaces is 1500.
# This option has no effect if use_veth_interconnection is False
# veth_mtu =
# Example: veth_mtu = 1504

View File

@ -23,6 +23,7 @@ from oslo.config import cfg
LOG = logging.getLogger(__name__)
cfg.CONF.import_group('AGENT', 'neutron.plugins.openvswitch.common.config')
cfg.CONF.import_group('OVS', 'neutron.plugins.openvswitch.common.config')
class BoolOptCallback(cfg.BoolOpt):
@ -69,6 +70,8 @@ def enable_tests_from_config():
cfg.CONF.set_override('ovs_vxlan', True)
if cfg.CONF.AGENT.tunnel_types:
cfg.CONF.set_override('ovs_patch', True)
if not cfg.CONF.OVS.use_veth_interconnection:
cfg.CONF.set_override('ovs_patch', True)
def all_tests_passed():

View File

@ -854,8 +854,8 @@ class OFANeutronAgent(n_rpc.RpcCallback,
def _phys_br_patch_physical_bridge_with_integration_bridge(
self, br, physical_network, bridge, ip_wrapper):
int_veth_name = constants.VETH_INTEGRATION_PREFIX + bridge
phys_veth_name = constants.VETH_PHYSICAL_PREFIX + bridge
int_veth_name = constants.PEER_INTEGRATION_PREFIX + bridge
phys_veth_name = constants.PEER_PHYSICAL_PREFIX + bridge
self._phys_br_prepare_create_veth(br, int_veth_name, phys_veth_name)
int_veth, phys_veth = self._phys_br_create_veth(br, int_veth_name,
phys_veth_name,

View File

@ -110,9 +110,9 @@ class OVSNeutronAgent(n_rpc.RpcCallback,
tunnels on the tunnel bridge.
For each virtual network realized as a VLAN or flat network, a
veth is used to connect the local VLAN on the integration bridge
with the physical network bridge, with flow rules adding,
modifying, or stripping VLAN tags as necessary.
veth or a pair of patch ports is used to connect the local VLAN on
the integration bridge with the physical network bridge, with flow
rules adding, modifying, or stripping VLAN tags as necessary.
'''
# history
@ -127,7 +127,8 @@ class OVSNeutronAgent(n_rpc.RpcCallback,
minimize_polling=False,
ovsdb_monitor_respawn_interval=(
constants.DEFAULT_OVSDBMON_RESPAWN),
arp_responder=False):
arp_responder=False,
use_veth_interconnection=False):
'''Constructor.
:param integ_br: name of the integration bridge.
@ -148,8 +149,11 @@ class OVSNeutronAgent(n_rpc.RpcCallback,
the ovsdb monitor.
:param arp_responder: Optional, enable local ARP responder if it is
supported.
:param use_veth_interconnection: use veths instead of patch ports to
interconnect the integration bridge to physical bridges.
'''
super(OVSNeutronAgent, self).__init__()
self.use_veth_interconnection = use_veth_interconnection
self.veth_mtu = veth_mtu
self.root_helper = root_helper
self.available_local_vlans = set(moves.xrange(q_const.MIN_VLAN_TAG,
@ -858,10 +862,11 @@ class OVSNeutronAgent(n_rpc.RpcCallback,
priority=0,
actions="drop")
def get_veth_name(self, prefix, name):
"""Construct a veth name based on the prefix and name that does not
exceed the maximum length allowed for a linux device. Longer names
are hashed to help ensure uniqueness.
def get_peer_name(self, prefix, name):
"""Construct a peer name based on the prefix and name.
The peer name can not exceed the maximum length allowed for a linux
device. Longer names are hashed to help ensure uniqueness.
"""
if len(prefix + name) <= q_const.DEVICE_NAME_MAX_LEN:
return prefix + name
@ -910,40 +915,55 @@ class OVSNeutronAgent(n_rpc.RpcCallback,
br.add_flow(priority=1, actions="normal")
self.phys_brs[physical_network] = br
# create veth to patch physical bridge with integration bridge
int_veth_name = self.get_veth_name(
constants.VETH_INTEGRATION_PREFIX, bridge)
self.int_br.delete_port(int_veth_name)
phys_veth_name = self.get_veth_name(
constants.VETH_PHYSICAL_PREFIX, bridge)
br.delete_port(phys_veth_name)
if ip_lib.device_exists(int_veth_name, self.root_helper):
ip_lib.IPDevice(int_veth_name, self.root_helper).link.delete()
# Give udev a chance to process its rules here, to avoid
# race conditions between commands launched by udev rules
# and the subsequent call to ip_wrapper.add_veth
utils.execute(['/sbin/udevadm', 'settle', '--timeout=10'])
int_veth, phys_veth = ip_wrapper.add_veth(int_veth_name,
phys_veth_name)
self.int_ofports[physical_network] = self.int_br.add_port(int_veth)
self.phys_ofports[physical_network] = br.add_port(phys_veth)
# interconnect physical and integration bridges using veth/patchs
int_if_name = self.get_peer_name(constants.PEER_INTEGRATION_PREFIX,
bridge)
phys_if_name = self.get_peer_name(constants.PEER_PHYSICAL_PREFIX,
bridge)
self.int_br.delete_port(int_if_name)
br.delete_port(phys_if_name)
if self.use_veth_interconnection:
if ip_lib.device_exists(int_if_name, self.root_helper):
ip_lib.IPDevice(int_if_name,
self.root_helper).link.delete()
# Give udev a chance to process its rules here, to avoid
# race conditions between commands launched by udev rules
# and the subsequent call to ip_wrapper.add_veth
utils.execute(['/sbin/udevadm', 'settle', '--timeout=10'])
int_veth, phys_veth = ip_wrapper.add_veth(int_if_name,
phys_if_name)
int_ofport = self.int_br.add_port(int_veth)
phys_ofport = br.add_port(phys_veth)
else:
# Create patch ports without associating them in order to block
# untranslated traffic before association
int_ofport = self.int_br.add_patch_port(
int_if_name, constants.NONEXISTENT_PEER)
phys_ofport = br.add_patch_port(
phys_if_name, constants.NONEXISTENT_PEER)
# block all untranslated traffic over veth between bridges
self.int_br.add_flow(priority=2,
in_port=self.int_ofports[physical_network],
self.int_ofports[physical_network] = int_ofport
self.phys_ofports[physical_network] = phys_ofport
# block all untranslated traffic between bridges
self.int_br.add_flow(priority=2, in_port=int_ofport,
actions="drop")
br.add_flow(priority=2,
in_port=self.phys_ofports[physical_network],
actions="drop")
br.add_flow(priority=2, in_port=phys_ofport, actions="drop")
# enable veth to pass traffic
int_veth.link.set_up()
phys_veth.link.set_up()
if self.veth_mtu:
# set up mtu size for veth interfaces
int_veth.link.set_mtu(self.veth_mtu)
phys_veth.link.set_mtu(self.veth_mtu)
if self.use_veth_interconnection:
# enable veth to pass traffic
int_veth.link.set_up()
phys_veth.link.set_up()
if self.veth_mtu:
# set up mtu size for veth interfaces
int_veth.link.set_mtu(self.veth_mtu)
phys_veth.link.set_mtu(self.veth_mtu)
else:
# associate patch ports to pass traffic
self.int_br.set_db_attribute('Interface', int_if_name,
'options:peer', phys_if_name)
br.set_db_attribute('Interface', phys_if_name,
'options:peer', int_if_name)
def scan_ports(self, registered_ports, updated_ports=None):
cur_ports = self.int_br.get_vif_port_set()
@ -1474,6 +1494,7 @@ def create_agent_config_map(config):
veth_mtu=config.AGENT.veth_mtu,
l2_population=config.AGENT.l2_population,
arp_responder=config.AGENT.arp_responder,
use_veth_interconnection=config.OVS.use_veth_interconnection,
)
# If enable_tunneling is TRUE, set tunnel_type to default to GRE

View File

@ -54,6 +54,9 @@ ovs_opts = [
cfg.StrOpt('tunnel_type', default='',
help=_("The type of tunnels to use when utilizing tunnels, "
"either 'gre' or 'vxlan'")),
cfg.BoolOpt('use_veth_interconnection', default=False,
help=_("Use veths instead of patch ports to interconnect the "
"integration bridge to physical bridges")),
]
agent_opts = [

View File

@ -25,10 +25,14 @@ TUNNEL = 'tunnel'
# Values for network_type
VXLAN_UDP_PORT = 4789
# Name prefixes for veth device pair linking the integration bridge
# with the physical bridge for a physical network
VETH_INTEGRATION_PREFIX = 'int-'
VETH_PHYSICAL_PREFIX = 'phy-'
# Name prefixes for veth device or patch port pair linking the integration
# bridge with the physical bridge for a physical network
PEER_INTEGRATION_PREFIX = 'int-'
PEER_PHYSICAL_PREFIX = 'phy-'
# Nonexistent peer used to create patch ports without associating them, it
# allows to define flows before association
NONEXISTENT_PEER = 'nonexistent-peer'
# The different types of tunnels
TUNNEL_NETWORK_TYPES = [p_const.TYPE_GRE, p_const.TYPE_VXLAN]

View File

@ -447,6 +447,59 @@ class TestOvsNeutronAgent(base.BaseTestCase):
self.assertEqual(set(['123']), self.agent.updated_ports)
def test_setup_physical_bridges(self):
with contextlib.nested(
mock.patch.object(ip_lib, "device_exists"),
mock.patch.object(sys, "exit"),
mock.patch.object(utils, "execute"),
mock.patch.object(ovs_lib.OVSBridge, "remove_all_flows"),
mock.patch.object(ovs_lib.OVSBridge, "add_flow"),
mock.patch.object(ovs_lib.OVSBridge, "add_patch_port"),
mock.patch.object(ovs_lib.OVSBridge, "delete_port"),
mock.patch.object(ovs_lib.OVSBridge, "set_db_attribute"),
mock.patch.object(self.agent.int_br, "add_flow"),
mock.patch.object(self.agent.int_br, "add_patch_port"),
mock.patch.object(self.agent.int_br, "delete_port"),
mock.patch.object(self.agent.int_br, "set_db_attribute"),
) as (devex_fn, sysexit_fn, utilsexec_fn, remflows_fn, ovs_add_flow_fn,
ovs_addpatch_port_fn, ovs_delport_fn, ovs_set_attr_fn,
br_add_flow_fn, br_addpatch_port_fn, br_delport_fn,
br_set_attr_fn):
devex_fn.return_value = True
parent = mock.MagicMock()
parent.attach_mock(ovs_addpatch_port_fn, 'phy_add_patch_port')
parent.attach_mock(ovs_add_flow_fn, 'phy_add_flow')
parent.attach_mock(ovs_set_attr_fn, 'phy_set_attr')
parent.attach_mock(br_addpatch_port_fn, 'int_add_patch_port')
parent.attach_mock(br_add_flow_fn, 'int_add_flow')
parent.attach_mock(br_set_attr_fn, 'int_set_attr')
ovs_addpatch_port_fn.return_value = "phy_ofport"
br_addpatch_port_fn.return_value = "int_ofport"
self.agent.setup_physical_bridges({"physnet1": "br-eth"})
expected_calls = [
mock.call.phy_add_flow(priority=1, actions='normal'),
mock.call.int_add_patch_port('int-br-eth',
constants.NONEXISTENT_PEER),
mock.call.phy_add_patch_port('phy-br-eth',
constants.NONEXISTENT_PEER),
mock.call.int_add_flow(priority=2, in_port='int_ofport',
actions='drop'),
mock.call.phy_add_flow(priority=2, in_port='phy_ofport',
actions='drop'),
mock.call.int_set_attr('Interface', 'int-br-eth',
'options:peer', 'phy-br-eth'),
mock.call.phy_set_attr('Interface', 'phy-br-eth',
'options:peer', 'int-br-eth'),
]
parent.assert_has_calls(expected_calls)
self.assertEqual(self.agent.int_ofports["physnet1"],
"int_ofport")
self.assertEqual(self.agent.phys_ofports["physnet1"],
"phy_ofport")
def test_setup_physical_bridges_using_veth_interconnection(self):
self.agent.use_veth_interconnection = True
with contextlib.nested(
mock.patch.object(ip_lib, "device_exists"),
mock.patch.object(sys, "exit"),
@ -486,15 +539,16 @@ class TestOvsNeutronAgent(base.BaseTestCase):
self.assertEqual(self.agent.phys_ofports["physnet1"],
"int_ofport")
def test_get_veth_name(self):
def test_get_peer_name(self):
bridge1 = "A_REALLY_LONG_BRIDGE_NAME1"
bridge2 = "A_REALLY_LONG_BRIDGE_NAME2"
self.assertEqual(len(self.agent.get_veth_name('int-', bridge1)),
self.agent.use_veth_interconnection = True
self.assertEqual(len(self.agent.get_peer_name('int-', bridge1)),
n_const.DEVICE_NAME_MAX_LEN)
self.assertEqual(len(self.agent.get_veth_name('int-', bridge2)),
self.assertEqual(len(self.agent.get_peer_name('int-', bridge2)),
n_const.DEVICE_NAME_MAX_LEN)
self.assertNotEqual(self.agent.get_veth_name('int-', bridge1),
self.agent.get_veth_name('int-', bridge2))
self.assertNotEqual(self.agent.get_peer_name('int-', bridge1),
self.agent.get_peer_name('int-', bridge2))
def test_port_unbound(self):
with mock.patch.object(self.agent, "reclaim_local_vlan") as reclvl_fn:

View File

@ -63,6 +63,8 @@ class DummyVlanBinding:
class TunnelTest(base.BaseTestCase):
USE_VETH_INTERCONNECTION = False
VETH_MTU = None
def setUp(self):
super(TunnelTest, self).setUp()
@ -85,8 +87,9 @@ class TunnelTest(base.BaseTestCase):
self.NET_MAPPING = {'net1': self.MAP_TUN_BRIDGE}
self.INT_OFPORT = 11111
self.TUN_OFPORT = 22222
self.MAP_TUN_OFPORT = 33333
self.VETH_MTU = None
self.MAP_TUN_INT_OFPORT = 33333
self.MAP_TUN_PHY_OFPORT = 44444
self.inta = mock.Mock()
self.intb = mock.Mock()
@ -94,10 +97,50 @@ class TunnelTest(base.BaseTestCase):
self.TUN_BRIDGE: mock.Mock(),
self.MAP_TUN_BRIDGE: mock.Mock(),
}
self.ovs_int_ofports = {
'patch-tun': self.TUN_OFPORT,
'int-%s' % self.MAP_TUN_BRIDGE: self.MAP_TUN_INT_OFPORT
}
self.mock_bridge = mock.patch.object(ovs_lib, 'OVSBridge').start()
self.mock_bridge.side_effect = (lambda br_name, root_helper:
self.ovs_bridges[br_name])
self.mock_int_bridge = self.ovs_bridges[self.INT_BRIDGE]
self.mock_int_bridge.add_port.return_value = self.MAP_TUN_INT_OFPORT
self.mock_int_bridge.add_patch_port.side_effect = (
lambda tap, peer: self.ovs_int_ofports[tap])
self.mock_map_tun_bridge = self.ovs_bridges[self.MAP_TUN_BRIDGE]
self.mock_map_tun_bridge.br_name = self.MAP_TUN_BRIDGE
self.mock_map_tun_bridge.add_port.return_value = (
self.MAP_TUN_PHY_OFPORT)
self.mock_map_tun_bridge.add_patch_port.return_value = (
self.MAP_TUN_PHY_OFPORT)
self.mock_tun_bridge = self.ovs_bridges[self.TUN_BRIDGE]
self.mock_tun_bridge.add_port.return_value = self.INT_OFPORT
self.mock_tun_bridge.add_patch_port.return_value = self.INT_OFPORT
self.device_exists = mock.patch.object(ip_lib, 'device_exists').start()
self.device_exists.return_value = True
self.ipdevice = mock.patch.object(ip_lib, 'IPDevice').start()
self.ipwrapper = mock.patch.object(ip_lib, 'IPWrapper').start()
add_veth = self.ipwrapper.return_value.add_veth
add_veth.return_value = [self.inta, self.intb]
self.get_bridges = mock.patch.object(ovs_lib, 'get_bridges').start()
self.get_bridges.return_value = [self.INT_BRIDGE,
self.TUN_BRIDGE,
self.MAP_TUN_BRIDGE]
self.execute = mock.patch('neutron.agent.linux.utils.execute').start()
self._define_expected_calls()
def _define_expected_calls(self):
self.mock_bridge_expected = [
mock.call(self.INT_BRIDGE, 'sudo'),
mock.call(self.MAP_TUN_BRIDGE, 'sudo'),
@ -115,31 +158,36 @@ class TunnelTest(base.BaseTestCase):
actions='drop'),
]
self.mock_map_tun_bridge = self.ovs_bridges[self.MAP_TUN_BRIDGE]
self.mock_map_tun_bridge.br_name = self.MAP_TUN_BRIDGE
self.mock_map_tun_bridge.add_port.return_value = None
self.mock_map_tun_bridge_expected = [
mock.call.remove_all_flows(),
mock.call.add_flow(priority=1, actions='normal'),
mock.call.delete_port('phy-%s' % self.MAP_TUN_BRIDGE),
mock.call.add_port(self.intb),
mock.call.add_patch_port('phy-%s' % self.MAP_TUN_BRIDGE,
constants.NONEXISTENT_PEER),
]
self.mock_int_bridge.add_port.return_value = None
self.mock_int_bridge_expected += [
mock.call.delete_port('int-%s' % self.MAP_TUN_BRIDGE),
mock.call.add_port(self.inta)
mock.call.add_patch_port('int-%s' % self.MAP_TUN_BRIDGE,
constants.NONEXISTENT_PEER),
]
self.inta_expected = [mock.call.link.set_up()]
self.intb_expected = [mock.call.link.set_up()]
self.mock_int_bridge_expected += [
mock.call.add_flow(priority=2, in_port=None, actions='drop')
mock.call.add_flow(priority=2,
in_port=self.MAP_TUN_INT_OFPORT,
actions='drop'),
mock.call.set_db_attribute(
'Interface', 'int-%s' % self.MAP_TUN_BRIDGE,
'options:peer', 'phy-%s' % self.MAP_TUN_BRIDGE),
]
self.mock_map_tun_bridge_expected += [
mock.call.add_flow(priority=2, in_port=None, actions='drop')
mock.call.add_flow(priority=2,
in_port=self.MAP_TUN_PHY_OFPORT,
actions='drop'),
mock.call.set_db_attribute(
'Interface', 'phy-%s' % self.MAP_TUN_BRIDGE,
'options:peer', 'int-%s' % self.MAP_TUN_BRIDGE),
]
self.mock_tun_bridge = self.ovs_bridges[self.TUN_BRIDGE]
self.mock_tun_bridge_expected = [
mock.call.reset_bridge(),
mock.call.add_patch_port('patch-int', 'patch-tun'),
@ -147,8 +195,6 @@ class TunnelTest(base.BaseTestCase):
self.mock_int_bridge_expected += [
mock.call.add_patch_port('patch-tun', 'patch-int')
]
self.mock_int_bridge.add_patch_port.return_value = self.TUN_OFPORT
self.mock_tun_bridge.add_patch_port.return_value = self.INT_OFPORT
self.mock_tun_bridge_expected += [
mock.call.remove_all_flows(),
@ -195,37 +241,31 @@ class TunnelTest(base.BaseTestCase):
actions="drop")
]
self.device_exists = mock.patch.object(ip_lib, 'device_exists').start()
self.device_exists.return_value = True
self.device_exists_expected = [
mock.call(self.MAP_TUN_BRIDGE, 'sudo'),
mock.call('int-%s' % self.MAP_TUN_BRIDGE, 'sudo'),
]
self.ipdevice = mock.patch.object(ip_lib, 'IPDevice').start()
self.ipdevice_expected = [
mock.call('int-%s' % self.MAP_TUN_BRIDGE, 'sudo'),
mock.call().link.delete()
]
self.ipwrapper = mock.patch.object(ip_lib, 'IPWrapper').start()
add_veth = self.ipwrapper.return_value.add_veth
add_veth.return_value = [self.inta, self.intb]
self.ipwrapper_expected = [
mock.call('sudo'),
mock.call().add_veth('int-%s' % self.MAP_TUN_BRIDGE,
'phy-%s' % self.MAP_TUN_BRIDGE)
]
self.ipdevice_expected = []
self.ipwrapper_expected = [mock.call('sudo')]
self.get_bridges = mock.patch.object(ovs_lib, 'get_bridges').start()
self.get_bridges.return_value = [self.INT_BRIDGE,
self.TUN_BRIDGE,
self.MAP_TUN_BRIDGE]
self.get_bridges_expected = [
mock.call('sudo')
]
self.execute = mock.patch('neutron.agent.linux.utils.execute').start()
self.execute_expected = [mock.call(['/sbin/udevadm', 'settle',
'--timeout=10'])]
self.get_bridges_expected = [mock.call('sudo')]
self.inta_expected = []
self.intb_expected = []
self.execute_expected = []
def _build_agent(self, **kwargs):
kwargs.setdefault('integ_br', self.INT_BRIDGE)
kwargs.setdefault('tun_br', self.TUN_BRIDGE)
kwargs.setdefault('local_ip', '10.0.0.1')
kwargs.setdefault('bridge_mappings', self.NET_MAPPING)
kwargs.setdefault('root_helper', 'sudo')
kwargs.setdefault('polling_interval', 2)
kwargs.setdefault('tunnel_types', ['gre'])
kwargs.setdefault('veth_mtu', self.VETH_MTU)
kwargs.setdefault('use_veth_interconnection',
self.USE_VETH_INTERCONNECTION)
return ovs_neutron_agent.OVSNeutronAgent(**kwargs)
def _verify_mock_call(self, mock_obj, expected):
mock_obj.assert_has_calls(expected)
@ -248,11 +288,7 @@ class TunnelTest(base.BaseTestCase):
self._verify_mock_call(self.execute, self.execute_expected)
def test_construct(self):
agent = ovs_neutron_agent.OVSNeutronAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
'sudo', 2, ['gre'],
self.VETH_MTU)
agent = self._build_agent()
self.assertEqual(agent.agent_id, 'ovs-agent-%s' % cfg.CONF.host)
self._verify_mock_calls()
@ -260,12 +296,7 @@ class TunnelTest(base.BaseTestCase):
# ML2 l2 population mechanism driver.
# The next two tests use l2_pop flag to test ARP responder
def test_construct_with_arp_responder(self):
ovs_neutron_agent.OVSNeutronAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
'sudo', 2, ['gre'],
self.VETH_MTU, l2_population=True,
arp_responder=True)
self._build_agent(l2_population=True, arp_responder=True)
self.mock_tun_bridge_expected.insert(
5, mock.call.add_flow(table=constants.PATCH_LV_TO_TUN,
priority=1,
@ -283,21 +314,11 @@ class TunnelTest(base.BaseTestCase):
self._verify_mock_calls()
def test_construct_without_arp_responder(self):
ovs_neutron_agent.OVSNeutronAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
'sudo', 2, ['gre'],
self.VETH_MTU, l2_population=False,
arp_responder=True)
self._build_agent(l2_population=False, arp_responder=True)
self._verify_mock_calls()
def test_construct_vxlan(self):
ovs_neutron_agent.OVSNeutronAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1',
self.NET_MAPPING,
'sudo', 2, ['vxlan'],
self.VETH_MTU)
self._build_agent(tunnel_types=['vxlan'])
self._verify_mock_calls()
def test_provision_local_vlan(self):
@ -315,11 +336,7 @@ class TunnelTest(base.BaseTestCase):
(LV_ID, constants.LEARN_FROM_TUN)),
]
a = ovs_neutron_agent.OVSNeutronAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
'sudo', 2, ['gre'],
self.VETH_MTU)
a = self._build_agent()
a.available_local_vlans = set([LV_ID])
a.tun_br_ofports = TUN_OFPORTS
a.provision_local_vlan(NET_UUID, p_const.TYPE_GRE, None, LS_ID)
@ -328,7 +345,7 @@ class TunnelTest(base.BaseTestCase):
def test_provision_local_vlan_flat(self):
action_string = 'strip_vlan,normal'
self.mock_map_tun_bridge_expected.append(
mock.call.add_flow(priority=4, in_port=self.MAP_TUN_OFPORT,
mock.call.add_flow(priority=4, in_port=self.MAP_TUN_PHY_OFPORT,
dl_vlan=LV_ID, actions=action_string))
action_string = 'mod_vlan_vid:%s,normal' % LV_ID
@ -336,31 +353,23 @@ class TunnelTest(base.BaseTestCase):
mock.call.add_flow(priority=3, in_port=self.INT_OFPORT,
dl_vlan=65535, actions=action_string))
a = ovs_neutron_agent.OVSNeutronAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
'sudo', 2, ['gre'],
self.VETH_MTU)
a = self._build_agent()
a.available_local_vlans = set([LV_ID])
a.phys_brs['net1'] = self.mock_map_tun_bridge
a.phys_ofports['net1'] = self.MAP_TUN_OFPORT
a.phys_ofports['net1'] = self.MAP_TUN_PHY_OFPORT
a.int_ofports['net1'] = self.INT_OFPORT
a.provision_local_vlan(NET_UUID, p_const.TYPE_FLAT, 'net1', LS_ID)
self._verify_mock_calls()
def test_provision_local_vlan_flat_fail(self):
a = ovs_neutron_agent.OVSNeutronAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
'sudo', 2, ['gre'],
self.VETH_MTU)
a = self._build_agent()
a.provision_local_vlan(NET_UUID, p_const.TYPE_FLAT, 'net2', LS_ID)
self._verify_mock_calls()
def test_provision_local_vlan_vlan(self):
action_string = 'mod_vlan_vid:%s,normal' % LS_ID
self.mock_map_tun_bridge_expected.append(
mock.call.add_flow(priority=4, in_port=self.MAP_TUN_OFPORT,
mock.call.add_flow(priority=4, in_port=self.MAP_TUN_PHY_OFPORT,
dl_vlan=LV_ID, actions=action_string))
action_string = 'mod_vlan_vid:%s,normal' % LS_ID
@ -368,24 +377,16 @@ class TunnelTest(base.BaseTestCase):
mock.call.add_flow(priority=3, in_port=self.INT_OFPORT,
dl_vlan=LV_ID, actions=action_string))
a = ovs_neutron_agent.OVSNeutronAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
'sudo', 2, ['gre'],
self.VETH_MTU)
a = self._build_agent()
a.available_local_vlans = set([LV_ID])
a.phys_brs['net1'] = self.mock_map_tun_bridge
a.phys_ofports['net1'] = self.MAP_TUN_OFPORT
a.phys_ofports['net1'] = self.MAP_TUN_PHY_OFPORT
a.int_ofports['net1'] = self.INT_OFPORT
a.provision_local_vlan(NET_UUID, p_const.TYPE_VLAN, 'net1', LS_ID)
self._verify_mock_calls()
def test_provision_local_vlan_vlan_fail(self):
a = ovs_neutron_agent.OVSNeutronAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
'sudo', 2, ['gre'],
self.VETH_MTU)
a = self._build_agent()
a.provision_local_vlan(NET_UUID, p_const.TYPE_VLAN, 'net2', LS_ID)
self._verify_mock_calls()
@ -396,11 +397,7 @@ class TunnelTest(base.BaseTestCase):
mock.call.delete_flows(dl_vlan=LVM.vlan)
]
a = ovs_neutron_agent.OVSNeutronAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
'sudo', 2, ['gre'],
self.VETH_MTU)
a = self._build_agent()
a.available_local_vlans = set()
a.local_vlan_map[NET_UUID] = LVM
a.reclaim_local_vlan(NET_UUID)
@ -410,18 +407,14 @@ class TunnelTest(base.BaseTestCase):
def test_reclaim_local_vlan_flat(self):
self.mock_map_tun_bridge_expected.append(
mock.call.delete_flows(
in_port=self.MAP_TUN_OFPORT, dl_vlan=LVM_FLAT.vlan))
in_port=self.MAP_TUN_PHY_OFPORT, dl_vlan=LVM_FLAT.vlan))
self.mock_int_bridge_expected.append(
mock.call.delete_flows(
dl_vlan=65535, in_port=self.INT_OFPORT))
a = ovs_neutron_agent.OVSNeutronAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
'sudo', 2, ['gre'],
self.VETH_MTU)
a = self._build_agent()
a.phys_brs['net1'] = self.mock_map_tun_bridge
a.phys_ofports['net1'] = self.MAP_TUN_OFPORT
a.phys_ofports['net1'] = self.MAP_TUN_PHY_OFPORT
a.int_ofports['net1'] = self.INT_OFPORT
a.available_local_vlans = set()
@ -433,18 +426,14 @@ class TunnelTest(base.BaseTestCase):
def test_reclaim_local_vlan_vlan(self):
self.mock_map_tun_bridge_expected.append(
mock.call.delete_flows(
in_port=self.MAP_TUN_OFPORT, dl_vlan=LVM_VLAN.vlan))
in_port=self.MAP_TUN_PHY_OFPORT, dl_vlan=LVM_VLAN.vlan))
self.mock_int_bridge_expected.append(
mock.call.delete_flows(
dl_vlan=LV_ID, in_port=self.INT_OFPORT))
a = ovs_neutron_agent.OVSNeutronAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
'sudo', 2, ['gre'],
self.VETH_MTU)
a = self._build_agent()
a.phys_brs['net1'] = self.mock_map_tun_bridge
a.phys_ofports['net1'] = self.MAP_TUN_OFPORT
a.phys_ofports['net1'] = self.MAP_TUN_PHY_OFPORT
a.int_ofports['net1'] = self.INT_OFPORT
a.available_local_vlans = set()
@ -461,11 +450,7 @@ class TunnelTest(base.BaseTestCase):
mock.call.delete_flows(in_port=VIF_PORT.ofport)
]
a = ovs_neutron_agent.OVSNeutronAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
'sudo', 2, ['gre'],
self.VETH_MTU)
a = self._build_agent()
a.local_vlan_map[NET_UUID] = LVM
a.port_bound(VIF_PORT, NET_UUID, 'gre', None, LS_ID, False)
self._verify_mock_calls()
@ -473,11 +458,7 @@ class TunnelTest(base.BaseTestCase):
def test_port_unbound(self):
with mock.patch.object(ovs_neutron_agent.OVSNeutronAgent,
'reclaim_local_vlan') as reclaim_local_vlan:
a = ovs_neutron_agent.OVSNeutronAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
'sudo', 2, ['gre'],
self.VETH_MTU)
a = self._build_agent()
a.local_vlan_map[NET_UUID] = LVM
a.port_unbound(VIF_ID, NET_UUID)
@ -494,11 +475,7 @@ class TunnelTest(base.BaseTestCase):
actions='drop')
]
a = ovs_neutron_agent.OVSNeutronAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
'sudo', 2, ['gre'],
self.VETH_MTU)
a = self._build_agent()
a.available_local_vlans = set([LV_ID])
a.local_vlan_map[NET_UUID] = LVM
a.port_dead(VIF_PORT)
@ -514,22 +491,14 @@ class TunnelTest(base.BaseTestCase):
actions='resubmit(,2)')
]
a = ovs_neutron_agent.OVSNeutronAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
'sudo', 2, ['gre'],
self.VETH_MTU)
a = self._build_agent()
a.tunnel_update(
mock.sentinel.ctx, tunnel_id='1', tunnel_ip='10.0.10.1',
tunnel_type=p_const.TYPE_GRE)
self._verify_mock_calls()
def test_tunnel_update_self(self):
a = ovs_neutron_agent.OVSNeutronAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
'sudo', 2, ['gre'],
self.VETH_MTU)
a = self._build_agent()
a.tunnel_update(
mock.sentinel.ctx, tunnel_id='1', tunnel_ip='10.0.0.1')
self._verify_mock_calls()
@ -561,12 +530,7 @@ class TunnelTest(base.BaseTestCase):
process_network_ports.side_effect = [
False, Exception('Fake exception to get out of the loop')]
q_agent = ovs_neutron_agent.OVSNeutronAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1',
self.NET_MAPPING,
'sudo', 2, ['gre'],
self.VETH_MTU)
q_agent = self._build_agent()
# Hack to test loop
# We start method and expect it will raise after 2nd loop
@ -594,10 +558,130 @@ class TunnelTest(base.BaseTestCase):
self._verify_mock_calls()
class TunnelTestWithMTU(TunnelTest):
class TunnelTestUseVethInterco(TunnelTest):
USE_VETH_INTERCONNECTION = True
def setUp(self):
super(TunnelTestWithMTU, self).setUp()
self.VETH_MTU = 1500
def _define_expected_calls(self):
self.mock_bridge_expected = [
mock.call(self.INT_BRIDGE, 'sudo'),
mock.call(self.MAP_TUN_BRIDGE, 'sudo'),
mock.call(self.TUN_BRIDGE, 'sudo'),
]
self.mock_int_bridge_expected = [
mock.call.create(),
mock.call.set_secure_mode(),
mock.call.delete_port('patch-tun'),
mock.call.remove_all_flows(),
mock.call.add_flow(priority=1, actions='normal'),
mock.call.add_flow(table=constants.CANARY_TABLE, priority=0,
actions="drop")
]
self.mock_map_tun_bridge_expected = [
mock.call.remove_all_flows(),
mock.call.add_flow(priority=1, actions='normal'),
mock.call.delete_port('phy-%s' % self.MAP_TUN_BRIDGE),
mock.call.add_port(self.intb),
]
self.mock_int_bridge_expected += [
mock.call.delete_port('int-%s' % self.MAP_TUN_BRIDGE),
mock.call.add_port(self.inta)
]
self.mock_int_bridge_expected += [
mock.call.add_flow(priority=2,
in_port=self.MAP_TUN_INT_OFPORT,
actions='drop')
]
self.mock_map_tun_bridge_expected += [
mock.call.add_flow(priority=2,
in_port=self.MAP_TUN_PHY_OFPORT,
actions='drop')
]
self.mock_tun_bridge_expected = [
mock.call.reset_bridge(),
mock.call.add_patch_port('patch-int', 'patch-tun'),
]
self.mock_int_bridge_expected += [
mock.call.add_patch_port('patch-tun', 'patch-int')
]
self.mock_tun_bridge_expected += [
mock.call.remove_all_flows(),
mock.call.add_flow(priority=1,
in_port=self.INT_OFPORT,
actions="resubmit(,%s)" %
constants.PATCH_LV_TO_TUN),
mock.call.add_flow(priority=0, actions='drop'),
mock.call.add_flow(priority=0,
table=constants.PATCH_LV_TO_TUN,
dl_dst=UCAST_MAC,
actions="resubmit(,%s)" %
constants.UCAST_TO_TUN),
mock.call.add_flow(priority=0,
table=constants.PATCH_LV_TO_TUN,
dl_dst=BCAST_MAC,
actions="resubmit(,%s)" %
constants.FLOOD_TO_TUN),
]
for tunnel_type in constants.TUNNEL_NETWORK_TYPES:
self.mock_tun_bridge_expected.append(
mock.call.add_flow(
table=constants.TUN_TABLE[tunnel_type],
priority=0,
actions="drop"))
learned_flow = ("table=%s,"
"priority=1,"
"hard_timeout=300,"
"NXM_OF_VLAN_TCI[0..11],"
"NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],"
"load:0->NXM_OF_VLAN_TCI[],"
"load:NXM_NX_TUN_ID[]->NXM_NX_TUN_ID[],"
"output:NXM_OF_IN_PORT[]" %
constants.UCAST_TO_TUN)
self.mock_tun_bridge_expected += [
mock.call.add_flow(table=constants.LEARN_FROM_TUN,
priority=1,
actions="learn(%s),output:%s" %
(learned_flow, self.INT_OFPORT)),
mock.call.add_flow(table=constants.UCAST_TO_TUN,
priority=0,
actions="resubmit(,%s)" %
constants.FLOOD_TO_TUN),
mock.call.add_flow(table=constants.FLOOD_TO_TUN,
priority=0,
actions="drop")
]
self.device_exists_expected = [
mock.call(self.MAP_TUN_BRIDGE, 'sudo'),
mock.call('int-%s' % self.MAP_TUN_BRIDGE, 'sudo'),
]
self.ipdevice_expected = [
mock.call('int-%s' % self.MAP_TUN_BRIDGE, 'sudo'),
mock.call().link.delete()
]
self.ipwrapper_expected = [
mock.call('sudo'),
mock.call().add_veth('int-%s' % self.MAP_TUN_BRIDGE,
'phy-%s' % self.MAP_TUN_BRIDGE)
]
self.get_bridges_expected = [mock.call('sudo')]
self.inta_expected = [mock.call.link.set_up()]
self.intb_expected = [mock.call.link.set_up()]
self.execute_expected = [mock.call(['/sbin/udevadm', 'settle',
'--timeout=10'])]
class TunnelTestWithMTU(TunnelTestUseVethInterco):
VETH_MTU = 1500
def _define_expected_calls(self):
super(TunnelTestWithMTU, self)._define_expected_calls()
self.inta_expected.append(mock.call.link.set_mtu(self.VETH_MTU))
self.intb_expected.append(mock.call.link.set_mtu(self.VETH_MTU))