Browse Source

add isolate_vif config option

- This change add a new isolate_vif config
  option to the OVS plugin.

- The isolate_vif option defaults to False
  for backwards compatiblity with SDN-based
  deployments.

- This change is a partial mitigation of bug
  1734320, when isolate_vif is set to True
  os-vif will assign VIFs to the neutron
  l2 agent dead VLAN 4095. This should only
  be set when using the ml2/ovs neutron
  backend.

Change-Id: I87ee9626cc6b4a01465a6b1908bc66bc7be0a4bc
Partial-Bug: #1734320
tags/1.13.0^2
Sean Mooney 10 months ago
parent
commit
d291213f1e

+ 14
- 1
releasenotes/notes/always-plug-vifs-for-ovs-1d033fc49a9c6c4e.yaml View File

@@ -21,4 +21,17 @@ security:
21 21
     migration. As a result this is a partial mitigation and additional changes
22 22
     will be required to fully address this bug.
23 23
 
24
-    .. _bug 1734320: https://bugs.launchpad.net/neutron/+bug/1734320
24
+    .. _bug 1734320: https://bugs.launchpad.net/neutron/+bug/1734320
25
+  - |
26
+    A new config option was introduced for the OVS VIF plugin.
27
+    The ``isolate_vif`` option was added as a partial mitigation of
28
+    `bug 1734320`_. The ``isolate_vif`` option defaults to ``False`` for
29
+    backwards compatibility with SDN controller based OpenStack deployments.
30
+    For all deployments using the reference implementation of ML2/OVS with
31
+    the neutron L2 agents, ``isolate_vif`` should be set to ``True``.
32
+    This option instructs the OVS plugin to assign the VIF to the
33
+    Neutron dead VLAN (4095) when attaching the interface to OVS. By setting
34
+    the VIF's VLAN to this dead VLAN number, we eliminate the small attack
35
+    vector that exists for other tenants to read packets during the VIF's
36
+    bring up.
37
+

+ 3
- 0
vif_plug_ovs/constants.py View File

@@ -20,3 +20,6 @@ OVS_DATAPATH_SYSTEM = 'system'
20 20
 OVS_DATAPATH_NETDEV = 'netdev'
21 21
 
22 22
 PLATFORM_WIN32 = 'win32'
23
+
24
+# Neutron dead VLAN.
25
+DEAD_VLAN = 4095

+ 31
- 0
vif_plug_ovs/ovs.py View File

@@ -68,6 +68,23 @@ class OvsPlugin(plugin.PluginBase):
68 68
                    choices=list(ovsdb_api.interface_map),
69 69
                    default='vsctl',
70 70
                    help='The interface for interacting with the OVSDB'),
71
+        # Note(sean-k-mooney): This value is a bool for two reasons.
72
+        # First I want to allow this config option to be reusable with
73
+        # non ml2/ovs deployment in the future if required, as such I do not
74
+        # want to encode how the isolation is done in the config option.
75
+        # Second in the case of ml2/ovs the isolation is based on VLAN tags.
76
+        # The 802.1Q IEEE spec that defines the VLAN format reserved two VLAN
77
+        # id values, VLAN ID 0 means the packet is a member of no VLAN
78
+        # and VLAN ID 4095 is reserved for implementation defined use.
79
+        # Using VLAN ID 0 would not provide isolation and all other VLAN IDs
80
+        # except VLAN ID 4095 are valid for the ml2/ovs agent to use for a
81
+        # tenant network's local VLAN ID. As such only VLAN ID 4095 is valid
82
+        # to use for vif isolation which is defined in Neutron as the
83
+        # dead VLAN, a VLAN on which all traffic will be dropped.
84
+        cfg.BoolOpt('isolate_vif', default=False,
85
+                    help='Controls if VIF should be isolated when plugged '
86
+                    'to the ovs bridge. This should only be set to True '
87
+                    'when using the neutron ovs ml2 agent.')
71 88
     )
72 89
 
73 90
     def __init__(self, config):
@@ -128,6 +145,20 @@ class OvsPlugin(plugin.PluginBase):
128 145
 
129 146
     def _create_vif_port(self, vif, vif_name, instance_info, **kwargs):
130 147
         mtu = self._get_mtu(vif)
148
+        # Note(sean-k-mooney): As part of a partial fix to bug #1734320
149
+        # we introduced the isolate_vif config option to enable isolation
150
+        # of the vif prior to neutron wiring up the interface. To do
151
+        # this we take advantage of the fact the ml2/ovs uses the
152
+        # implementation defined VLAN 4095 as a dead VLAN to indicate
153
+        # that all packets should be dropped. We only enable this
154
+        # behaviour conditionally as it is not portable to SDN based
155
+        # deployment such as ODL or OVN as such operator must opt-in
156
+        # to this behaviour by setting the isolate_vif config option.
157
+        # TODO(sean-k-mooney): Extend neutron to record what ml2 driver
158
+        # bound the interface in the vif binding details so isolation
159
+        # can be enabled automatically in the future.
160
+        if self.config.isolate_vif:
161
+            kwargs['tag'] = constants.DEAD_VLAN
131 162
         self.ovsdb.create_ovs_vif_port(
132 163
             vif.network.bridge,
133 164
             vif_name,

+ 3
- 1
vif_plug_ovs/ovsdb/ovsdb_lib.py View File

@@ -64,7 +64,7 @@ class BaseOVS(object):
64 64
 
65 65
     def create_ovs_vif_port(self, bridge, dev, iface_id, mac, instance_id,
66 66
                             mtu=None, interface_type=None,
67
-                            vhost_server_path=None):
67
+                            vhost_server_path=None, tag=None):
68 68
         external_ids = {'iface-id': iface_id,
69 69
                         'iface-status': 'active',
70 70
                         'attached-mac': mac,
@@ -75,6 +75,8 @@ class BaseOVS(object):
75 75
         if vhost_server_path:
76 76
             col_values.append(('options',
77 77
                                {'vhost-server-path': vhost_server_path}))
78
+        if tag:
79
+            col_values.append(('tag', tag))
78 80
 
79 81
         with self.ovsdb.transaction() as txn:
80 82
             txn.add(self.ovsdb.add_port(bridge, dev))

+ 17
- 1
vif_plug_ovs/tests/unit/test_plugin.py View File

@@ -146,6 +146,21 @@ class PluginTest(testtools.TestCase):
146 146
             self.network_ovs_mtu.mtu,
147 147
             interface_type=constants.OVS_VHOSTUSER_INTERFACE_TYPE)
148 148
 
149
+    @mock.patch.object(ovsdb_lib.BaseOVS, 'create_ovs_vif_port')
150
+    def test_create_vif_port_isolate(self, mock_create_ovs_vif_port):
151
+        plugin = ovs.OvsPlugin.load(constants.PLUGIN_NAME)
152
+        with mock.patch.object(plugin.config, 'isolate_vif', True):
153
+            plugin._create_vif_port(
154
+                self.vif_ovs, mock.sentinel.vif_name, self.instance,
155
+                interface_type=constants.OVS_VHOSTUSER_INTERFACE_TYPE)
156
+            mock_create_ovs_vif_port.assert_called_once_with(
157
+                self.vif_ovs.network.bridge, mock.sentinel.vif_name,
158
+                self.vif_ovs.port_profile.interface_id,
159
+                self.vif_ovs.address, self.instance.uuid,
160
+                plugin.config.network_device_mtu,
161
+                interface_type=constants.OVS_VHOSTUSER_INTERFACE_TYPE,
162
+                tag=constants.DEAD_VLAN)
163
+
149 164
     @mock.patch.object(ovs, 'sys')
150 165
     @mock.patch.object(ovs.OvsPlugin, '_plug_vif_generic')
151 166
     def test_plug_ovs(self, plug_vif_generic, mock_sys):
@@ -331,7 +346,8 @@ class PluginTest(testtools.TestCase):
331 346
                      'ca:fe:de:ad:be:ef',
332 347
                      'f0000000-0000-0000-0000-000000000001',
333 348
                      1500, interface_type='dpdkvhostuserclient',
334
-                     vhost_server_path='/var/run/openvswitch/vhub679325f-ca')],
349
+                     vhost_server_path='/var/run/openvswitch/vhub679325f-ca'
350
+                 )],
335 351
             'ensure_ovs_bridge': [mock.call('br0', dp_type)]
336 352
         }
337 353
 

Loading…
Cancel
Save