neutron/quantum/plugins/linuxbridge/LinuxBridgePlugin.py

267 lines
11 KiB
Python

# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright 2012, Cisco Systems, Inc.
#
# 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.
# @author: Sumit Naiksatam, Cisco Systems, Inc.
import logging
from quantum.api.api_common import OperationalStatus
from quantum.common import exceptions as exc
from quantum.db import api as db
from quantum.plugins.linuxbridge.common import constants as const
from quantum.plugins.linuxbridge.common import utils as cutil
from quantum.plugins.linuxbridge.db import l2network_db as cdb
from quantum.quantum_plugin_base import QuantumPluginBase
LOG = logging.getLogger(__name__)
class LinuxBridgePlugin(QuantumPluginBase):
"""
LinuxBridgePlugin provides support for Quantum abstractions
using LinuxBridge. A new VLAN is created for each network.
It relies on an agent to perform the actual bridge configuration
on each host.
"""
def __init__(self, configfile=None):
cdb.initialize()
LOG.debug("Linux Bridge Plugin initialization done successfully")
def _get_vlan_for_tenant(self, tenant_id, **kwargs):
"""Get an available VLAN ID"""
try:
return cdb.reserve_vlanid()
except:
raise Exception("Failed to reserve VLAN ID for network")
def _release_vlan_for_tenant(self, tenant_id, net_id, **kwargs):
"""Release the ID"""
vlan_binding = cdb.get_vlan_binding(net_id)
return cdb.release_vlanid(vlan_binding[const.VLANID])
def _validate_port_state(self, port_state):
if port_state.upper() not in ('ACTIVE', 'DOWN'):
raise exc.StateInvalid(port_state=port_state)
return True
def get_all_networks(self, tenant_id, **kwargs):
"""
Returns a dictionary containing all
<network_uuid, network_name> for
the specified tenant.
"""
LOG.debug("LinuxBridgePlugin.get_all_networks() called")
networks_list = db.network_list(tenant_id)
new_networks_list = []
for network in networks_list:
new_network_dict = cutil.make_net_dict(network[const.UUID],
network[const.NETWORKNAME],
[], network[const.OPSTATUS])
new_networks_list.append(new_network_dict)
# This plugin does not perform filtering at the moment
return new_networks_list
def get_network_details(self, tenant_id, net_id):
"""
retrieved a list of all the remote vifs that
are attached to the network
"""
LOG.debug("LinuxBridgePlugin.get_network_details() called")
db.validate_network_ownership(tenant_id, net_id)
network = db.network_get(net_id)
ports_list = db.port_list(net_id)
ports_on_net = []
for port in ports_list:
new_port = cutil.make_port_dict(port)
ports_on_net.append(new_port)
new_network = cutil.make_net_dict(network[const.UUID],
network[const.NETWORKNAME],
ports_on_net,
network[const.OPSTATUS])
return new_network
def create_network(self, tenant_id, net_name, **kwargs):
"""
Creates a new Virtual Network, and assigns it
a symbolic name.
"""
LOG.debug("LinuxBridgePlugin.create_network() called")
new_network = db.network_create(tenant_id, net_name,
op_status=OperationalStatus.UP)
new_net_id = new_network[const.UUID]
vlan_id = self._get_vlan_for_tenant(tenant_id)
cdb.add_vlan_binding(vlan_id, new_net_id)
new_net_dict = {
const.NET_ID: new_net_id,
const.NET_NAME: net_name,
const.NET_PORTS: [],
const.NET_OP_STATUS: new_network[const.OPSTATUS],
}
return new_net_dict
def delete_network(self, tenant_id, net_id):
"""
Deletes the network with the specified network identifier
belonging to the specified tenant.
"""
LOG.debug("LinuxBridgePlugin.delete_network() called")
db.validate_network_ownership(tenant_id, net_id)
net = db.network_get(net_id)
if net:
ports_on_net = db.port_list(net_id)
if len(ports_on_net) > 0:
for port in ports_on_net:
if port[const.INTERFACEID]:
raise exc.NetworkInUse(net_id=net_id)
for port in ports_on_net:
self.delete_port(tenant_id, net_id, port[const.UUID])
net_dict = cutil.make_net_dict(net[const.UUID],
net[const.NETWORKNAME],
[], net[const.OPSTATUS])
try:
self._release_vlan_for_tenant(tenant_id, net_id)
cdb.remove_vlan_binding(net_id)
except Exception as excp:
LOG.warning("Exception: %s" % excp)
db.network_update(net_id, tenant_id, {const.OPSTATUS:
OperationalStatus.DOWN})
db.network_destroy(net_id)
return net_dict
# Network not found
raise exc.NetworkNotFound(net_id=net_id)
def update_network(self, tenant_id, net_id, **kwargs):
"""
Updates the attributes of a particular Virtual Network.
"""
LOG.debug("LinuxBridgePlugin.update_network() called")
db.validate_network_ownership(tenant_id, net_id)
network = db.network_update(net_id, tenant_id, **kwargs)
net_dict = cutil.make_net_dict(network[const.UUID],
network[const.NETWORKNAME],
[], network[const.OPSTATUS])
return net_dict
def get_all_ports(self, tenant_id, net_id, **kwargs):
"""
Retrieves all port identifiers belonging to the
specified Virtual Network.
"""
LOG.debug("LinuxBridgePlugin.get_all_ports() called")
db.validate_network_ownership(tenant_id, net_id)
network = db.network_get(net_id)
ports_list = db.port_list(net_id)
ports_on_net = []
for port in ports_list:
new_port = cutil.make_port_dict(port)
ports_on_net.append(new_port)
# This plugin does not perform filtering at the moment
return ports_on_net
def get_port_details(self, tenant_id, net_id, port_id):
"""
This method allows the user to retrieve a remote interface
that is attached to this particular port.
"""
LOG.debug("LinuxBridgePlugin.get_port_details() called")
db.validate_port_ownership(tenant_id, net_id, port_id)
network = db.network_get(net_id)
port = db.port_get(port_id, net_id)
new_port_dict = cutil.make_port_dict(port)
return new_port_dict
def create_port(self, tenant_id, net_id, port_state=None, **kwargs):
"""
Creates a port on the specified Virtual Network.
"""
LOG.debug("LinuxBridgePlugin.create_port() called")
db.validate_network_ownership(tenant_id, net_id)
port = db.port_create(net_id, port_state,
op_status=OperationalStatus.DOWN)
unique_port_id_string = port[const.UUID]
new_port_dict = cutil.make_port_dict(port)
return new_port_dict
def update_port(self, tenant_id, net_id, port_id, **kwargs):
"""
Updates the attributes of a port on the specified Virtual Network.
"""
LOG.debug("LinuxBridgePlugin.update_port() called")
db.validate_port_ownership(tenant_id, net_id, port_id)
network = db.network_get(net_id)
self._validate_port_state(kwargs["state"])
port = db.port_update(port_id, net_id, **kwargs)
new_port_dict = cutil.make_port_dict(port)
return new_port_dict
def delete_port(self, tenant_id, net_id, port_id):
"""
Deletes a port on a specified Virtual Network,
if the port contains a remote interface attachment,
the remote interface is first un-plugged and then the port
is deleted.
"""
LOG.debug("LinuxBridgePlugin.delete_port() called")
db.validate_port_ownership(tenant_id, net_id, port_id)
network = db.network_get(net_id)
port = db.port_get(port_id, net_id)
attachment_id = port[const.INTERFACEID]
if not attachment_id:
db.port_destroy(port_id, net_id)
new_port_dict = cutil.make_port_dict(port)
return new_port_dict
else:
raise exc.PortInUse(port_id=port_id, net_id=net_id,
att_id=attachment_id)
def plug_interface(self, tenant_id, net_id, port_id, remote_interface_id):
"""
Attaches a remote interface to the specified port on the
specified Virtual Network.
"""
LOG.debug("LinuxBridgePlugin.plug_interface() called")
db.validate_port_ownership(tenant_id, net_id, port_id)
network = db.network_get(net_id)
port = db.port_get(port_id, net_id)
attachment_id = port[const.INTERFACEID]
if attachment_id:
raise exc.PortInUse(port_id=port_id, net_id=net_id,
att_id=attachment_id)
db.port_set_attachment(port_id, net_id, remote_interface_id)
def unplug_interface(self, tenant_id, net_id, port_id):
"""
Detaches a remote interface from the specified port on the
specified Virtual Network.
"""
LOG.debug("LinuxBridgePlugin.unplug_interface() called")
db.validate_port_ownership(tenant_id, net_id, port_id)
network = db.network_get(net_id)
port = db.port_get(port_id, net_id)
attachment_id = port[const.INTERFACEID]
if attachment_id == None:
raise exc.InvalidDetach(port_id=port_id, net_id=net_id,
att_id=remote_interface_id)
db.port_unset_attachment(port_id, net_id)
db.port_update(port_id, net_id, op_status=OperationalStatus.DOWN)