Merge "add isolate_vif config option"
This commit is contained in:
commit
5fa14f8372
@ -22,3 +22,16 @@ security:
|
|||||||
will be required to fully address this bug.
|
will be required to fully address this bug.
|
||||||
|
|
||||||
.. _bug 1734320: https://bugs.launchpad.net/neutron/+bug/1734320
|
.. _bug 1734320: https://bugs.launchpad.net/neutron/+bug/1734320
|
||||||
|
- |
|
||||||
|
A new config option was introduced for the OVS VIF plugin.
|
||||||
|
The ``isolate_vif`` option was added as a partial mitigation of
|
||||||
|
`bug 1734320`_. The ``isolate_vif`` option defaults to ``False`` for
|
||||||
|
backwards compatibility with SDN controller based OpenStack deployments.
|
||||||
|
For all deployments using the reference implementation of ML2/OVS with
|
||||||
|
the neutron L2 agents, ``isolate_vif`` should be set to ``True``.
|
||||||
|
This option instructs the OVS plugin to assign the VIF to the
|
||||||
|
Neutron dead VLAN (4095) when attaching the interface to OVS. By setting
|
||||||
|
the VIF's VLAN to this dead VLAN number, we eliminate the small attack
|
||||||
|
vector that exists for other tenants to read packets during the VIF's
|
||||||
|
bring up.
|
||||||
|
|
||||||
|
@ -21,3 +21,6 @@ OVS_DATAPATH_NETDEV = 'netdev'
|
|||||||
|
|
||||||
PLATFORM_LINUX = 'linux2'
|
PLATFORM_LINUX = 'linux2'
|
||||||
PLATFORM_WIN32 = 'win32'
|
PLATFORM_WIN32 = 'win32'
|
||||||
|
|
||||||
|
# Neutron dead VLAN.
|
||||||
|
DEAD_VLAN = 4095
|
||||||
|
@ -68,6 +68,23 @@ class OvsPlugin(plugin.PluginBase):
|
|||||||
choices=list(ovsdb_api.interface_map),
|
choices=list(ovsdb_api.interface_map),
|
||||||
default='vsctl',
|
default='vsctl',
|
||||||
help='The interface for interacting with the OVSDB'),
|
help='The interface for interacting with the OVSDB'),
|
||||||
|
# Note(sean-k-mooney): This value is a bool for two reasons.
|
||||||
|
# First I want to allow this config option to be reusable with
|
||||||
|
# non ml2/ovs deployment in the future if required, as such I do not
|
||||||
|
# want to encode how the isolation is done in the config option.
|
||||||
|
# Second in the case of ml2/ovs the isolation is based on VLAN tags.
|
||||||
|
# The 802.1Q IEEE spec that defines the VLAN format reserved two VLAN
|
||||||
|
# id values, VLAN ID 0 means the packet is a member of no VLAN
|
||||||
|
# and VLAN ID 4095 is reserved for implementation defined use.
|
||||||
|
# Using VLAN ID 0 would not provide isolation and all other VLAN IDs
|
||||||
|
# except VLAN ID 4095 are valid for the ml2/ovs agent to use for a
|
||||||
|
# tenant network's local VLAN ID. As such only VLAN ID 4095 is valid
|
||||||
|
# to use for vif isolation which is defined in Neutron as the
|
||||||
|
# dead VLAN, a VLAN on which all traffic will be dropped.
|
||||||
|
cfg.BoolOpt('isolate_vif', default=False,
|
||||||
|
help='Controls if VIF should be isolated when plugged '
|
||||||
|
'to the ovs bridge. This should only be set to True '
|
||||||
|
'when using the neutron ovs ml2 agent.')
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self, config):
|
def __init__(self, config):
|
||||||
@ -128,6 +145,20 @@ class OvsPlugin(plugin.PluginBase):
|
|||||||
|
|
||||||
def _create_vif_port(self, vif, vif_name, instance_info, **kwargs):
|
def _create_vif_port(self, vif, vif_name, instance_info, **kwargs):
|
||||||
mtu = self._get_mtu(vif)
|
mtu = self._get_mtu(vif)
|
||||||
|
# Note(sean-k-mooney): As part of a partial fix to bug #1734320
|
||||||
|
# we introduced the isolate_vif config option to enable isolation
|
||||||
|
# of the vif prior to neutron wiring up the interface. To do
|
||||||
|
# this we take advantage of the fact the ml2/ovs uses the
|
||||||
|
# implementation defined VLAN 4095 as a dead VLAN to indicate
|
||||||
|
# that all packets should be dropped. We only enable this
|
||||||
|
# behaviour conditionally as it is not portable to SDN based
|
||||||
|
# deployment such as ODL or OVN as such operator must opt-in
|
||||||
|
# to this behaviour by setting the isolate_vif config option.
|
||||||
|
# TODO(sean-k-mooney): Extend neutron to record what ml2 driver
|
||||||
|
# bound the interface in the vif binding details so isolation
|
||||||
|
# can be enabled automatically in the future.
|
||||||
|
if self.config.isolate_vif:
|
||||||
|
kwargs['tag'] = constants.DEAD_VLAN
|
||||||
self.ovsdb.create_ovs_vif_port(
|
self.ovsdb.create_ovs_vif_port(
|
||||||
vif.network.bridge,
|
vif.network.bridge,
|
||||||
vif_name,
|
vif_name,
|
||||||
|
@ -64,7 +64,7 @@ class BaseOVS(object):
|
|||||||
|
|
||||||
def create_ovs_vif_port(self, bridge, dev, iface_id, mac, instance_id,
|
def create_ovs_vif_port(self, bridge, dev, iface_id, mac, instance_id,
|
||||||
mtu=None, interface_type=None,
|
mtu=None, interface_type=None,
|
||||||
vhost_server_path=None):
|
vhost_server_path=None, tag=None):
|
||||||
external_ids = {'iface-id': iface_id,
|
external_ids = {'iface-id': iface_id,
|
||||||
'iface-status': 'active',
|
'iface-status': 'active',
|
||||||
'attached-mac': mac,
|
'attached-mac': mac,
|
||||||
@ -75,6 +75,8 @@ class BaseOVS(object):
|
|||||||
if vhost_server_path:
|
if vhost_server_path:
|
||||||
col_values.append(('options',
|
col_values.append(('options',
|
||||||
{'vhost-server-path': vhost_server_path}))
|
{'vhost-server-path': vhost_server_path}))
|
||||||
|
if tag:
|
||||||
|
col_values.append(('tag', tag))
|
||||||
|
|
||||||
with self.ovsdb.transaction() as txn:
|
with self.ovsdb.transaction() as txn:
|
||||||
txn.add(self.ovsdb.add_port(bridge, dev))
|
txn.add(self.ovsdb.add_port(bridge, dev))
|
||||||
|
@ -146,6 +146,21 @@ class PluginTest(testtools.TestCase):
|
|||||||
self.network_ovs_mtu.mtu,
|
self.network_ovs_mtu.mtu,
|
||||||
interface_type=constants.OVS_VHOSTUSER_INTERFACE_TYPE)
|
interface_type=constants.OVS_VHOSTUSER_INTERFACE_TYPE)
|
||||||
|
|
||||||
|
@mock.patch.object(ovsdb_lib.BaseOVS, 'create_ovs_vif_port')
|
||||||
|
def test_create_vif_port_isolate(self, mock_create_ovs_vif_port):
|
||||||
|
plugin = ovs.OvsPlugin.load(constants.PLUGIN_NAME)
|
||||||
|
with mock.patch.object(plugin.config, 'isolate_vif', True):
|
||||||
|
plugin._create_vif_port(
|
||||||
|
self.vif_ovs, mock.sentinel.vif_name, self.instance,
|
||||||
|
interface_type=constants.OVS_VHOSTUSER_INTERFACE_TYPE)
|
||||||
|
mock_create_ovs_vif_port.assert_called_once_with(
|
||||||
|
self.vif_ovs.network.bridge, mock.sentinel.vif_name,
|
||||||
|
self.vif_ovs.port_profile.interface_id,
|
||||||
|
self.vif_ovs.address, self.instance.uuid,
|
||||||
|
plugin.config.network_device_mtu,
|
||||||
|
interface_type=constants.OVS_VHOSTUSER_INTERFACE_TYPE,
|
||||||
|
tag=constants.DEAD_VLAN)
|
||||||
|
|
||||||
@mock.patch.object(ovs, 'sys')
|
@mock.patch.object(ovs, 'sys')
|
||||||
@mock.patch.object(ovs.OvsPlugin, '_plug_vif_generic')
|
@mock.patch.object(ovs.OvsPlugin, '_plug_vif_generic')
|
||||||
def test_plug_ovs(self, plug_vif_generic, mock_sys):
|
def test_plug_ovs(self, plug_vif_generic, mock_sys):
|
||||||
@ -332,7 +347,8 @@ class PluginTest(testtools.TestCase):
|
|||||||
'ca:fe:de:ad:be:ef',
|
'ca:fe:de:ad:be:ef',
|
||||||
'f0000000-0000-0000-0000-000000000001',
|
'f0000000-0000-0000-0000-000000000001',
|
||||||
1500, interface_type='dpdkvhostuserclient',
|
1500, interface_type='dpdkvhostuserclient',
|
||||||
vhost_server_path='/var/run/openvswitch/vhub679325f-ca')],
|
vhost_server_path='/var/run/openvswitch/vhub679325f-ca'
|
||||||
|
)],
|
||||||
'ensure_ovs_bridge': [mock.call('br0', dp_type)]
|
'ensure_ovs_bridge': [mock.call('br0', dp_type)]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user