diff options
Diffstat (limited to 'networking_sfc/services/sfc/drivers/ovs/db.py')
-rw-r--r-- | networking_sfc/services/sfc/drivers/ovs/db.py | 426 |
1 files changed, 426 insertions, 0 deletions
diff --git a/networking_sfc/services/sfc/drivers/ovs/db.py b/networking_sfc/services/sfc/drivers/ovs/db.py new file mode 100644 index 0000000..8d3c87d --- /dev/null +++ b/networking_sfc/services/sfc/drivers/ovs/db.py @@ -0,0 +1,426 @@ +# Copyright 2015 Futurewei. 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. +# + +import six + +from oslo_log import helpers as log_helpers +from oslo_log import log as logging +from oslo_utils import uuidutils + +from neutron.common import exceptions as n_exc +from neutron import context as n_context +from neutron.db import common_db_mixin +from neutron.db import model_base +from neutron.db import models_v2 + +import sqlalchemy as sa +from sqlalchemy import orm +from sqlalchemy.orm import exc +from sqlalchemy import sql + + +LOG = logging.getLogger(__name__) + + +class PortPairDetailNotFound(n_exc.NotFound): + message = _("Portchain port brief %(port_id)s could not be found") + + +class NodeNotFound(n_exc.NotFound): + message = _("Portchain node %(node_id)s could not be found") + + +# name changed to ChainPathId +class UuidIntidAssoc(model_base.BASEV2, models_v2.HasId): + __tablename__ = 'sfc_uuid_intid_associations' + uuid = sa.Column(sa.String(36), primary_key=True) + intid = sa.Column(sa.Integer, unique=True, nullable=False) + type_ = sa.Column(sa.String(32), nullable=False) + + def __init__(self, uuid, intid, type_): + self.uuid = uuid + self.intid = intid + self.type_ = type_ + + +def singleton(class_): + instances = {} + + def getinstance(*args, **kwargs): + if class_ not in instances: + instances[class_] = class_(*args, **kwargs) + return instances[class_] + return getinstance + + +@singleton +class IDAllocation(object): + def __init__(self, context): + # Get the inital range from conf file. + conf_obj = {'group': [1, 255], 'portchain': [256, 65536]} + self.conf_obj = conf_obj + self.session = context.session + + @log_helpers.log_method_call + def assign_intid(self, type_, uuid): + query = self.session.query(UuidIntidAssoc).filter_by( + type_=type_).order_by(UuidIntidAssoc.intid) + + allocated_int_ids = {obj.intid for obj in query.all()} + + # Find the first one from the available range that + # is not in allocated_int_ids + start, end = self.conf_obj[type_][0], self.conf_obj[type_][1]+1 + for init_id in six.moves.range(start, end): + if init_id not in allocated_int_ids: + with self.session.begin(subtransactions=True): + uuid_intid = UuidIntidAssoc( + uuid, init_id, type_) + self.session.add(uuid_intid) + return init_id + else: + return None + + @log_helpers.log_method_call + def get_intid_by_uuid(self, type_, uuid): + + query_obj = self.session.query(UuidIntidAssoc).filter_by( + type_=type_, uuid=uuid).first() + if query_obj: + return query_obj.intid + else: + return None + + @log_helpers.log_method_call + def release_intid(self, type_, intid): + """Release int id. + + @param: type_: str + @param: intid: int + """ + with self.session.begin(subtransactions=True): + query_obj = self.session.query(UuidIntidAssoc).filter_by( + intid=intid, type_=type_).first() + + if query_obj: + self.session.delete(query_obj) + + +class PathPortAssoc(model_base.BASEV2): + """path port association table. + + It represents the association table which associate path_nodes with + portpair_details. + """ + __tablename__ = 'sfc_path_port_associations' + pathnode_id = sa.Column(sa.String(36), + sa.ForeignKey( + 'sfc_path_nodes.id', ondelete='CASCADE'), + primary_key=True) + portpair_id = sa.Column(sa.String(36), + sa.ForeignKey('sfc_portpair_details.id', + ondelete='CASCADE'), + primary_key=True) + weight = sa.Column(sa.Integer, nullable=False, default=1) + + +class PortPairDetail(model_base.BASEV2, models_v2.HasId, + models_v2.HasTenant): + __tablename__ = 'sfc_portpair_details' + ingress = sa.Column(sa.String(36), nullable=True) + egress = sa.Column(sa.String(36), nullable=True) + host_id = sa.Column(sa.String(255), nullable=False) + mac_address = sa.Column(sa.String(32), nullable=False) + network_type = sa.Column(sa.String(8)) + segment_id = sa.Column(sa.Integer) + local_endpoint = sa.Column(sa.String(64), nullable=False) + path_nodes = orm.relationship(PathPortAssoc, + backref='port_pair_detail', + lazy="joined", + cascade='all,delete') + + +class PathNode(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant): + __tablename__ = 'sfc_path_nodes' + nsp = sa.Column(sa.Integer, nullable=False) + nsi = sa.Column(sa.Integer, nullable=False) + node_type = sa.Column(sa.String(32)) + portchain_id = sa.Column( + sa.String(255), + sa.ForeignKey('sfc_port_chains.id', ondelete='CASCADE')) + status = sa.Column(sa.String(32)) + portpair_details = orm.relationship(PathPortAssoc, + backref='path_nodes', + lazy="joined", + cascade='all,delete') + next_group_id = sa.Column(sa.Integer) + next_hop = sa.Column(sa.String(512)) + + +class OVSSfcDriverDB(common_db_mixin.CommonDbMixin): + def initialize(self): + self.admin_context = n_context.get_admin_context() + + def _make_pathnode_dict(self, node, fields=None): + res = {'id': node['id'], + 'tenant_id': node['tenant_id'], + 'node_type': node['node_type'], + 'nsp': node['nsp'], + 'nsi': node['nsi'], + 'next_group_id': node['next_group_id'], + 'next_hop': node['next_hop'], + 'portchain_id': node['portchain_id'], + 'status': node['status'], + 'portpair_details': [pair_detail['portpair_id'] + for pair_detail in node['portpair_details'] + ] + } + + return self._fields(res, fields) + + def _make_port_detail_dict(self, port, fields=None): + res = {'id': port['id'], + 'tenant_id': port['tenant_id'], + 'host_id': port['host_id'], + 'ingress': port.get('ingress', None), + 'egress': port.get('egress', None), + 'segment_id': port['segment_id'], + 'local_endpoint': port['local_endpoint'], + 'mac_address': port['mac_address'], + 'network_type': port['network_type'], + 'path_nodes': [{'pathnode_id': node['pathnode_id'], + 'weight': node['weight']} + for node in port['path_nodes']] + } + + return self._fields(res, fields) + + def _make_pathport_assoc_dict(self, assoc, fields=None): + res = {'pathnode_id': assoc['pathnode_id'], + 'portpair_id': assoc['portpair_id'], + 'weight': assoc['weight'], + } + + return self._fields(res, fields) + + def _get_path_node(self, id): + try: + node = self._get_by_id(self.admin_context, PathNode, id) + except exc.NoResultFound: + raise NodeNotFound(node_id=id) + return node + + def _get_port_detail(self, id): + try: + port = self._get_by_id(self.admin_context, PortPairDetail, id) + except exc.NoResultFound: + raise PortPairDetailNotFound(port_id=id) + return port + + def create_port_detail(self, port): + with self.admin_context.session.begin(subtransactions=True): + args = self._filter_non_model_columns(port, PortPairDetail) + args['id'] = uuidutils.generate_uuid() + port_obj = PortPairDetail(**args) + self.admin_context.session.add(port_obj) + return self._make_port_detail_dict(port_obj) + + def create_path_node(self, node): + with self.admin_context.session.begin(subtransactions=True): + args = self._filter_non_model_columns(node, PathNode) + args['id'] = uuidutils.generate_uuid() + node_obj = PathNode(**args) + self.admin_context.session.add(node_obj) + return self._make_pathnode_dict(node_obj) + + def create_pathport_assoc(self, assoc): + with self.admin_context.session.begin(subtransactions=True): + args = self._filter_non_model_columns(assoc, PathPortAssoc) + assoc_obj = PathPortAssoc(**args) + self.admin_context.session.add(assoc_obj) + return self._make_pathport_assoc_dict(assoc_obj) + + def delete_pathport_assoc(self, pathnode_id, portdetail_id): + with self.admin_context.session.begin(subtransactions=True): + self.admin_context.session.query(PathPortAssoc).filter_by( + pathnode_id=pathnode_id, + portpair_id=portdetail_id).delete() + + def update_port_detail(self, id, port): + with self.admin_context.session.begin(subtransactions=True): + port_obj = self._get_port_detail(id) + for key, value in six.iteritems(port): + if key == 'path_nodes': + pns = [] + for pn in value: + pn_id = pn['pathnode_id'] + self._get_path_node(pn_id) + query = self._model_query( + self.admin_context, PathPortAssoc) + pn_association = query.filter_by( + pathnode_id=pn_id, + portpair_id=id + ).first() + if not pn_association: + pn_association = PathPortAssoc( + pathnode_id=pn_id, + portpair_id=id, + weight=pn.get('weight', 1) + ) + pns.append(pn_association) + port_obj[key] = pns + else: + port_obj[key] = value + port_obj.update(port) + return self._make_port_detail_dict(port_obj) + + def update_path_node(self, id, node): + with self.admin_context.session.begin(subtransactions=True): + node_obj = self._get_path_node(id) + for key, value in six.iteritems(node): + if key == 'portpair_details': + pds = [] + for pd_id in value: + self._get_port_detail(pd_id) + query = self._model_query( + self.admin_context, PathPortAssoc) + pd_association = query.filter_by( + pathnode_id=id, + portpair_id=pd_id + ).first() + if not pd_association: + pd_association = PathPortAssoc( + pathnode_id=id, + portpair_id=pd_id + ) + pds.append(pd_association) + node_obj[key] = pds + else: + node_obj[key] = value + return self._make_pathnode_dict(node_obj) + + def delete_port_detail(self, id): + with self.admin_context.session.begin(subtransactions=True): + port_obj = self._get_port_detail(id) + self.admin_context.session.delete(port_obj) + + def delete_path_node(self, id): + with self.admin_context.session.begin(subtransactions=True): + node_obj = self._get_path_node(id) + self.admin_context.session.delete(node_obj) + + def get_port_detail(self, id): + with self.admin_context.session.begin(subtransactions=True): + port_obj = self._get_port_detail(id) + return self._make_port_detail_dict(port_obj) + + def get_port_detail_without_exception(self, id): + with self.admin_context.session.begin(subtransactions=True): + try: + port = self._get_by_id( + self.admin_context, PortPairDetail, id) + except exc.NoResultFound: + return None + return self._make_port_detail_dict(port) + + def get_path_node(self, id): + with self.admin_context.session.begin(subtransactions=True): + node_obj = self._get_path_node(id) + return self._make_pathnode_dict(node_obj) + + def get_path_nodes_by_filter(self, filters=None, fields=None, + sorts=None, limit=None, marker=None, + page_reverse=False): + with self.admin_context.session.begin(subtransactions=True): + qry = self._get_path_nodes_by_filter( + filters, fields, sorts, limit, + marker, page_reverse + ) + all_items = qry.all() + if all_items: + return [self._make_pathnode_dict(item) for item in all_items] + + return None + + def get_path_node_by_filter(self, filters=None, fields=None, + sorts=None, limit=None, marker=None, + page_reverse=False): + with self.admin_context.session.begin(subtransactions=True): + qry = self._get_path_nodes_by_filter( + filters, fields, sorts, limit, + marker, page_reverse) + first = qry.first() + if first: + return self._make_pathnode_dict(first) + + return None + + def _get_path_nodes_by_filter(self, filters=None, fields=None, + sorts=None, limit=None, marker=None, + page_reverse=False): + qry = self.admin_context.session.query(PathNode) + if filters: + for key, value in six.iteritems(filters): + column = getattr(PathNode, key, None) + if column: + if not value: + qry = qry.filter(sql.false()) + else: + qry = qry.filter(column == value) + return qry + + def get_port_details_by_filter(self, filters=None, fields=None, + sorts=None, limit=None, marker=None, + page_reverse=False): + with self.admin_context.session.begin(subtransactions=True): + qry = self._get_port_details_by_filter( + filters, fields, sorts, limit, + marker, page_reverse) + all_items = qry.all() + if all_items: + return [ + self._make_port_detail_dict(item) + for item in all_items + ] + + return None + + def get_port_detail_by_filter(self, filters=None, fields=None, + sorts=None, limit=None, marker=None, + page_reverse=False): + with self.admin_context.session.begin(subtransactions=True): + qry = self._get_port_details_by_filter( + filters, fields, sorts, limit, + marker, page_reverse) + first = qry.first() + if first: + return self._make_port_detail_dict(first) + + return None + + def _get_port_details_by_filter(self, filters=None, fields=None, + sorts=None, limit=None, marker=None, + page_reverse=False): + qry = self.admin_context.session.query(PortPairDetail) + if filters: + for key, value in six.iteritems(filters): + column = getattr(PortPairDetail, key, None) + if column: + if not value: + qry = qry.filter(sql.false()) + else: + qry = qry.filter(column == value) + + return qry |