
This change fixes the information used by the L2pop driver to populate l2pop rules that enables DVR to route packets across compute servers that have tenant VMs that belong to different networks. It also fixes the case where VMs were not able to obtain IP Addresses when such VMs are on DVR hosted subnets. Change-Id: Ib630e57c186da60eb15f9ffa6b1b0bfa74f48caa Closes-Bug: #1350485 Closes-Bug: #1352857
176 lines
5.5 KiB
Python
176 lines
5.5 KiB
Python
# Copyright (c) 2013 OpenStack Foundation
|
|
# All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
from neutron.common import constants
|
|
from neutron.extensions import portbindings
|
|
from neutron.openstack.common import jsonutils
|
|
from neutron.plugins.ml2 import db
|
|
from neutron.plugins.ml2 import driver_api as api
|
|
|
|
|
|
class MechanismDriverContext(object):
|
|
"""MechanismDriver context base class."""
|
|
def __init__(self, plugin, plugin_context):
|
|
self._plugin = plugin
|
|
# This temporarily creates a reference loop, but the
|
|
# lifetime of PortContext is limited to a single
|
|
# method call of the plugin.
|
|
self._plugin_context = plugin_context
|
|
|
|
|
|
class NetworkContext(MechanismDriverContext, api.NetworkContext):
|
|
|
|
def __init__(self, plugin, plugin_context, network,
|
|
original_network=None):
|
|
super(NetworkContext, self).__init__(plugin, plugin_context)
|
|
self._network = network
|
|
self._original_network = original_network
|
|
self._segments = db.get_network_segments(plugin_context.session,
|
|
network['id'])
|
|
|
|
@property
|
|
def current(self):
|
|
return self._network
|
|
|
|
@property
|
|
def original(self):
|
|
return self._original_network
|
|
|
|
@property
|
|
def network_segments(self):
|
|
return self._segments
|
|
|
|
|
|
class SubnetContext(MechanismDriverContext, api.SubnetContext):
|
|
|
|
def __init__(self, plugin, plugin_context, subnet, original_subnet=None):
|
|
super(SubnetContext, self).__init__(plugin, plugin_context)
|
|
self._subnet = subnet
|
|
self._original_subnet = original_subnet
|
|
|
|
@property
|
|
def current(self):
|
|
return self._subnet
|
|
|
|
@property
|
|
def original(self):
|
|
return self._original_subnet
|
|
|
|
|
|
class PortContext(MechanismDriverContext, api.PortContext):
|
|
|
|
def __init__(self, plugin, plugin_context, port, network, binding,
|
|
original_port=None):
|
|
super(PortContext, self).__init__(plugin, plugin_context)
|
|
self._port = port
|
|
self._original_port = original_port
|
|
self._network_context = NetworkContext(plugin, plugin_context,
|
|
network)
|
|
self._binding = binding
|
|
if original_port:
|
|
self._original_bound_segment_id = self._binding.segment
|
|
self._original_bound_driver = self._binding.driver
|
|
else:
|
|
self._original_bound_segment_id = None
|
|
self._original_bound_driver = None
|
|
self._new_port_status = None
|
|
|
|
@property
|
|
def current(self):
|
|
return self._port
|
|
|
|
@property
|
|
def original(self):
|
|
return self._original_port
|
|
|
|
@property
|
|
def status(self):
|
|
return self._port['status']
|
|
|
|
@property
|
|
def original_status(self):
|
|
return self._original_port['status']
|
|
|
|
@property
|
|
def network(self):
|
|
return self._network_context
|
|
|
|
@property
|
|
def bound_segment(self):
|
|
id = self._binding.segment
|
|
if id:
|
|
for segment in self._network_context.network_segments:
|
|
if segment[api.ID] == id:
|
|
return segment
|
|
|
|
@property
|
|
def original_bound_segment(self):
|
|
if self._original_bound_segment_id:
|
|
for segment in self._network_context.network_segments:
|
|
if segment[api.ID] == self._original_bound_segment_id:
|
|
return segment
|
|
|
|
@property
|
|
def host(self):
|
|
return self._port.get(portbindings.HOST_ID)
|
|
|
|
@property
|
|
def original_host(self):
|
|
return self._original_port.get(portbindings.HOST_ID)
|
|
|
|
@property
|
|
def bound_driver(self):
|
|
return self._binding.driver
|
|
|
|
@property
|
|
def original_bound_driver(self):
|
|
return self._original_bound_driver
|
|
|
|
def host_agents(self, agent_type):
|
|
return self._plugin.get_agents(self._plugin_context,
|
|
filters={'agent_type': [agent_type],
|
|
'host': [self._binding.host]})
|
|
|
|
def set_binding(self, segment_id, vif_type, vif_details,
|
|
status=None):
|
|
# TODO(rkukura) Verify binding allowed, segment in network
|
|
self._binding.segment = segment_id
|
|
self._binding.vif_type = vif_type
|
|
self._binding.vif_details = jsonutils.dumps(vif_details)
|
|
self._new_port_status = status
|
|
|
|
|
|
class DvrPortContext(PortContext):
|
|
|
|
def __init__(self, plugin, plugin_context, port, network, binding,
|
|
original_port=None):
|
|
super(DvrPortContext, self).__init__(
|
|
plugin, plugin_context, port, network, binding,
|
|
original_port=original_port)
|
|
|
|
@property
|
|
def host(self):
|
|
if self._port['device_owner'] == constants.DEVICE_OWNER_DVR_INTERFACE:
|
|
return self._binding.host
|
|
|
|
return super(DvrPortContext, self).host
|
|
|
|
@property
|
|
def status(self):
|
|
if self._port['device_owner'] == constants.DEVICE_OWNER_DVR_INTERFACE:
|
|
return self._binding.status
|
|
|
|
return super(DvrPortContext, self).status
|