如何實現OpenStack STT隧道(by quqi99)
阿新 • • 發佈:2019-02-04
diff --git a/neutron/db/migration/alembic_migrations/versions/EXPAND_HEAD b/neutron/db/migration/alembic_migrations/versions/EXPAND_HEAD index cf26eb1..6a75db4 100644 --- a/neutron/db/migration/alembic_migrations/versions/EXPAND_HEAD +++ b/neutron/db/migration/alembic_migrations/versions/EXPAND_HEAD @@ -1 +1 @@ -30107ab6a3ee +3abed5b82c57 diff --git a/neutron/db/migration/alembic_migrations/versions/newton/contract/3abed5b82c57_add_stt_type_driver.py b/neutron/db/migration/alembic_migrations/versions/newton/contract/3abed5b82c57_add_stt_type_driver.py new file mode 100644 index 0000000..c305f6c --- /dev/null +++ b/neutron/db/migration/alembic_migrations/versions/newton/contract/3abed5b82c57_add_stt_type_driver.py @@ -0,0 +1,49 @@ +# Copyright 2015 OpenStack Foundation +# +# 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. +# + +"""add_stt_type_driver + +Revision ID: 3abed5b82c57 +Revises: 30107ab6a3ee +Create Date: 2016-05-19 12:52:40.546353 + +""" + +# revision identifiers, used by Alembic. +revision = '3abed5b82c57' +down_revision = '30107ab6a3ee' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + op.create_table( + 'ml2_stt_allocations', + sa.Column('stt_context_id', sa.Integer(), + autoincrement=False, nullable=False), + sa.Column('allocated', sa.Boolean(), + server_default=sa.sql.false(), nullable=False), + sa.PrimaryKeyConstraint('stt_context_id'), + ) + op.create_index(op.f('ix_ml2_stt_allocations_allocated'), + 'ml2_stt_allocations', ['allocated'], unique=False) + op.create_table( + 'ml2_stt_endpoints', + sa.Column('ip_address', sa.String(length=64), nullable=False), + sa.Column('host', sa.String(length=255), nullable=True), + sa.PrimaryKeyConstraint('ip_address'), + sa.UniqueConstraint('host', name='unique_ml2_stt_endpoints0host'), + ) diff --git a/neutron/db/migration/models/head.py b/neutron/db/migration/models/head.py index 6112dbf..2b336ac 100644 --- a/neutron/db/migration/models/head.py +++ b/neutron/db/migration/models/head.py @@ -54,6 +54,7 @@ from neutron.ipam.drivers.neutrondb_ipam import db_models # noqa from neutron.plugins.ml2.drivers import type_flat # noqa from neutron.plugins.ml2.drivers import type_geneve # noqa from neutron.plugins.ml2.drivers import type_gre # noqa +from neutron.plugins.ml2.drivers import type_stt # noqa from neutron.plugins.ml2.drivers import type_vlan # noqa from neutron.plugins.ml2.drivers import type_vxlan # noqa from neutron.plugins.ml2 import models # noqa diff --git a/neutron/plugins/common/constants.py b/neutron/plugins/common/constants.py index 4b38514..2a6ced1 100644 --- a/neutron/plugins/common/constants.py +++ b/neutron/plugins/common/constants.py @@ -69,6 +69,7 @@ TYPE_GENEVE = 'geneve' TYPE_GRE = 'gre' TYPE_LOCAL = 'local' TYPE_VXLAN = 'vxlan' +TYPE_STT = 'stt' TYPE_VLAN = 'vlan' TYPE_NONE = 'none' @@ -86,6 +87,10 @@ MAX_GENEVE_VNI = 2 ** 24 - 1 MIN_GRE_ID = 1 MAX_GRE_ID = 2 ** 32 - 1 +# For STT Tunnel +MIN_STT_CONTEXT_ID = 1 +MAX_STT_CONTEXT_ID = 2 ** 64 - 1 + # For VXLAN Tunnel MIN_VXLAN_VNI = 1 MAX_VXLAN_VNI = 2 ** 24 - 1 @@ -95,3 +100,6 @@ VXLAN_UDP_PORT = 4789 GENEVE_ENCAP_MIN_OVERHEAD = 50 GRE_ENCAP_OVERHEAD = 42 VXLAN_ENCAP_OVERHEAD = 50 +# NOTE(arosen): STT does not need an ENCAP_OVERHEAD as it's TCP based +# thus L2 fragmentation will not come into play. The packets will be +# sized to the systems configured MTU. diff --git a/neutron/plugins/ml2/config.py b/neutron/plugins/ml2/config.py index 4e2e43d..f85a9f5 100644 --- a/neutron/plugins/ml2/config.py +++ b/neutron/plugins/ml2/config.py @@ -19,7 +19,8 @@ from neutron._i18n import _ ml2_opts = [ cfg.ListOpt('type_drivers', - default=['local', 'flat', 'vlan', 'gre', 'vxlan', 'geneve'], + default=['local', 'flat', 'vlan', 'gre', 'vxlan', 'stt', + 'geneve'], help=_("List of network type driver entrypoints to be loaded " "from the neutron.ml2.type_drivers namespace.")), cfg.ListOpt('tenant_network_types', diff --git a/neutron/plugins/ml2/drivers/openvswitch/agent/common/constants.py b/neutron/plugins/ml2/drivers/openvswitch/agent/common/constants.py index 96903d3..b996f39 100644 --- a/neutron/plugins/ml2/drivers/openvswitch/agent/common/constants.py +++ b/neutron/plugins/ml2/drivers/openvswitch/agent/common/constants.py @@ -33,7 +33,7 @@ NONEXISTENT_PEER = 'nonexistent-peer' # The different types of tunnels TUNNEL_NETWORK_TYPES = [p_const.TYPE_GRE, p_const.TYPE_VXLAN, - p_const.TYPE_GENEVE] + p_const.TYPE_GENEVE, p_const.TYPE_STT] ### OpenFlow table IDs @@ -75,6 +75,7 @@ DVR_PROCESS = 1 PATCH_LV_TO_TUN = 2 GRE_TUN_TO_LV = 3 VXLAN_TUN_TO_LV = 4 +STT_TUN_TO_LV = 5 GENEVE_TUN_TO_LV = 6 DVR_NOT_LEARN = 9 @@ -98,7 +99,8 @@ ARP_REPLY = '0x2' # Map tunnel types to tables number TUN_TABLE = {p_const.TYPE_GRE: GRE_TUN_TO_LV, p_const.TYPE_VXLAN: VXLAN_TUN_TO_LV, - p_const.TYPE_GENEVE: GENEVE_TUN_TO_LV} + p_const.TYPE_GENEVE: GENEVE_TUN_TO_LV, + p_const.TYPE_STT: STT_TUN_TO_LV} # The default respawn interval for the ovsdb monitor diff --git a/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py b/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py index 93fbc19..41d4976 100644 --- a/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py +++ b/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py @@ -367,6 +367,7 @@ class OVSNeutronAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin, def _reset_tunnel_ofports(self): self.tun_br_ofports = {p_const.TYPE_GENEVE: {}, p_const.TYPE_GRE: {}, + p_const.TYPE_STT: {}, p_const.TYPE_VXLAN: {}} def setup_rpc(self): @@ -629,7 +630,7 @@ class OVSNeutronAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin, :param net_uuid: the uuid of the network associated with this vlan. :param network_type: the network type ('gre', 'vxlan', 'vlan', 'flat', - 'local', 'geneve') + 'local', 'stt', 'geneve') :param physical_network: the physical network for 'vlan' or 'flat' :param segmentation_id: the VID for 'vlan' or tunnel ID for 'tunnel' ''' @@ -2110,7 +2111,7 @@ class OVSNeutronAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin, if (self.enable_distributed_routing and self.enable_tunneling and not self.l2_pop): - raise ValueError(_("DVR deployments for VXLAN/GRE/Geneve " + raise ValueError(_("DVR deployments for VXLAN/GRE/STT/Geneve " "underlays require L2-pop to be enabled, " "in both the Agent and Server side.")) diff --git a/neutron/plugins/ml2/drivers/type_stt.py b/neutron/plugins/ml2/drivers/type_stt.py new file mode 100644 index 0000000..27b8e9a --- /dev/null +++ b/neutron/plugins/ml2/drivers/type_stt.py @@ -0,0 +1,142 @@ +# Copyright (c) 2015 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 oslo_config import cfg +from oslo_log import log +from six import moves +import sqlalchemy as sa +from sqlalchemy import sql + +from neutron.common import exceptions as n_exc +from neutron.db import api as db_api +from neutron.db import model_base +from neutron.i18n import _LE +from neutron.plugins.common import constants as p_const +from neutron.plugins.ml2.drivers import type_tunnel + +LOG = log.getLogger(__name__) + +stt_opts = [ + cfg.ListOpt('context_id_ranges', + default=['1000:3000'], + help=_("Comma-separated list of " + "<context_id_min>:<context_id_max> tuples " + "enumerating ranges of STT Context IDs that are " + "available for tenant network allocation")) +] + +cfg.CONF.register_opts(stt_opts, "ml2_type_stt") + + +class SttAllocation(model_base.BASEV2): + + __tablename__ = 'ml2_stt_allocations' + + stt_context_id = sa.Column(sa.Integer, nullable=False, primary_key=True, + autoincrement=False) + allocated = sa.Column(sa.Boolean, nullable=False, default=False, + server_default=sql.false(), index=True) + + +class SttEndpoints(model_base.BASEV2): + """Represents tunnel endpoint in RPC mode.""" + + __tablename__ = 'ml2_stt_endpoints' + __table_args__ = ( + sa.UniqueConstraint('host', + name='unique_ml2_stt_endpoints0host'), + model_base.BASEV2.__table_args__ + ) + ip_address = sa.Column(sa.String(64), primary_key=True) + host = sa.Column(sa.String(255), nullable=True) + + def __repr__(self): + return "<SttTunnelEndpoint(%s)>" % self.ip_address + + +class SttTypeDriver(type_tunnel.EndpointTunnelTypeDriver): + + def __init__(self): + super(SttTypeDriver, self).__init__(SttAllocation, + SttEndpoints) + + def get_type(self): + return p_const.TYPE_STT + + def initialize(self): + try: + self._initialize(cfg.CONF.ml2_type_stt.context_id_ranges) + except n_exc.NetworkTunnelRangeError: + LOG.exception(_LE("Failed to parse context_id_ranges. " + "Service terminated!")) + raise SystemExit() + + def sync_allocations(self): + # FIXME(arosen) - refactor out duplicate code from type_vxlan driver. + + # determine current configured allocatable context_ids + stt_context_ids = set() + for tun_min, tun_max in self.tunnel_ranges: + if tun_max + 1 - tun_min > p_const.MAX_STT_CONTEXT_ID: + LOG.error(_LE("Skipping unreasonable STT VNI range " + "%(tun_min)s:%(tun_max)s"), + {'tun_min': tun_min, 'tun_max': tun_max}) + else: + stt_context_ids |= set(moves.range(tun_min, tun_max + 1)) + + session = db_api.get_session() + with session.begin(subtransactions=True): + # remove from table unallocated tunnels not currently allocatable + # fetch results as list via all() because we'll be iterating + # through them twice + allocs = (session.query(SttAllocation). + with_lockmode("update").all()) + # collect all context_ids present in db + existing_context_ids = set(alloc.stt_context_id + for alloc in allocs) + # collect those context_ids that needs to be deleted from db + context_ids_to_remove = [ + alloc.stt_context_id for alloc in allocs + if (alloc.stt_context_id not in stt_context_ids and + not alloc.allocated)] + # Immediately delete context_ids in chunks. This leaves no work for + # flush at the end of transaction + bulk_size = 100 + chunked_context_ids = ( + context_ids_to_remove[i:i + bulk_size] + for i in range(0, len(context_ids_to_remove), bulk_size)) + for context_id_list in chunked_context_ids: + if context_id_list: + session.query(SttAllocation).filter( + SttAllocation.stt_context_id.in_(context_id_list)).delete( + synchronize_session=False) + # collect context_ids that need to be added + context_ids = list(stt_context_ids - existing_context_ids) + chunked_context_ids = (context_ids[i:i + bulk_size] for i in + range(0, len(context_ids), bulk_size)) + for context_id_list in chunked_context_ids: + bulk = [{'stt_context_id': context_id, 'allocated': False} + for context_id in context_id_list] + session.execute(SttAllocation.__table__.insert(), bulk) + + def get_endpoints(self): + """Get every stt endpoints from database.""" + stt_endpoints = self._get_endpoints() + return [{'ip_address': stt_endpoint.ip_address, + 'host': stt_endpoint.host} + for stt_endpoint in stt_endpoints] + + def add_endpoint(self, ip, host): + return self._add_endpoint(ip, host) diff --git a/setup.cfg b/setup.cfg index 5479a7c..7098b9d 100644 --- a/setup.cfg +++ b/setup.cfg @@ -91,6 +91,7 @@ neutron.ml2.type_drivers = geneve = neutron.plugins.ml2.drivers.type_geneve:GeneveTypeDriver gre = neutron.plugins.ml2.drivers.type_gre:GreTypeDriver vxlan = neutron.plugins.ml2.drivers.type_vxlan:VxlanTypeDriver + stt = neutron.plugins.ml2.drivers.type_stt:SttTypeDriver neutron.ml2.mechanism_drivers = logger = neutron.tests.unit.plugins.ml2.drivers.mechanism_logger:LoggerMechanismDriver test = neutron.tests.unit.plugins.ml2.drivers.mechanism_test:TestMechanismDriver