detail <http://openstack.redhat.com/Networking_in_too_much_detail>`_
by RedHat.
-
VXLAN Tunnels
-------------
More information can be found in `The VXLAN wiki page.
<http://en.wikipedia.org/wiki/Virtual_Extensible_LAN>`_
+Geneve Tunnels
+--------------
+
+Geneve uses UDP as its transport protocol and is dynamic
+in size using extensible option headers.
+It is important to note that currently it is only supported in
+newer kernels. (kernel >= 3.18, OVS version >=2.4)
+More information can be found in the `Geneve RFC document.
+<https://tools.ietf.org/html/draft-ietf-nvo3-geneve-00>`_
+
Bridge Management
-----------------
for instance) and/or to deal with potential QinQ support natively
available in the Open vSwitch.
+
Further Reading
---------------
# (ListOpt) List of network type driver entrypoints to be loaded from
# the neutron.ml2.type_drivers namespace.
#
-# type_drivers = local,flat,vlan,gre,vxlan
-# Example: type_drivers = flat,vlan,gre,vxlan
+# type_drivers = local,flat,vlan,gre,vxlan,geneve
+# Example: type_drivers = flat,vlan,gre,vxlan,geneve
# (ListOpt) Ordered list of network_types to allocate as tenant
# networks. The default value 'local' is useful for single-box testing
# but provides no connectivity between hosts.
#
# tenant_network_types = local
-# Example: tenant_network_types = vlan,gre,vxlan
+# Example: tenant_network_types = vlan,gre,vxlan,geneve
+
# (ListOpt) Ordered list of networking mechanism driver entrypoints
# to be loaded from the neutron.ml2.mechanism_drivers namespace.
# vxlan_group =
# Example: vxlan_group = 239.1.1.1
+[ml2_type_geneve]
+# (ListOpt) Comma-separated list of <vni_min>:<vni_max> tuples enumerating
+# ranges of Geneve VNI IDs that are available for tenant network allocation.
+#
+# vni_ranges =
+
+# (IntOpt) Geneve encapsulation header size is dynamic, this
+# value is used to calculate the maximum MTU for the driver.
+# this is the sum of the sizes of the outer ETH+IP+UDP+GENEVE
+# header sizes.
+# The default size for this field is 50, which is the size of the
+# Geneve header without any additional option headers
+#
+# max_header_size =
+# Example: max_header_size = 50 (Geneve headers with no additional options)
+
[securitygroup]
# Controls if neutron security group is enabled or not.
# It should be false when you use nova security group.
return port != ovs_lib.INVALID_OFPORT
+def ovs_geneve_supported(from_ip='192.0.2.3', to_ip='192.0.2.4'):
+ name = "genevetest-" + utils.get_random_string(6)
+ with ovs_lib.OVSBridge(name) as br:
+ port = br.add_tunnel_port(from_ip, to_ip, const.TYPE_GENEVE)
+ return port != ovs_lib.INVALID_OFPORT
+
+
def iproute2_vxlan_supported():
ip = ip_lib.IPWrapper()
name = "vxlantest-" + utils.get_random_string(4)
return result
+def check_ovs_geneve():
+ result = checks.ovs_geneve_supported()
+ if not result:
+ LOG.error(_LE('Check for Open vSwitch Geneve support failed. '
+ 'Please ensure that the version of openvswitch '
+ 'and kernel being used has Geneve support.'))
+ return result
+
+
def check_iproute2_vxlan():
result = checks.iproute2_vxlan_supported()
if not result:
OPTS = [
BoolOptCallback('ovs_vxlan', check_ovs_vxlan, default=False,
help=_('Check for OVS vxlan support')),
+ BoolOptCallback('ovs_geneve', check_ovs_geneve, default=False,
+ help=_('Check for OVS Geneve support')),
BoolOptCallback('iproute2_vxlan', check_iproute2_vxlan, default=False,
help=_('Check for iproute2 vxlan support')),
BoolOptCallback('ovs_patch', check_ovs_patch, default=False,
if 'vxlan' in cfg.CONF.AGENT.tunnel_types:
cfg.CONF.set_override('ovs_vxlan', True)
+ if 'geneve' in cfg.CONF.AGENT.tunnel_types:
+ cfg.CONF.set_override('ovs_geneve', True)
if ('vxlan' in cfg.CONF.ml2.type_drivers or
cfg.CONF.VXLAN.enable_vxlan):
cfg.CONF.set_override('iproute2_vxlan', True)
-2e5352a0ad4d
+11926bcfe72d
34af2b5c5a59
--- /dev/null
+# 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 geneve ml2 type driver
+
+Revision ID: 11926bcfe72d
+Revises: 2e5352a0ad4d
+Create Date: 2015-08-27 19:56:16.356522
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = '11926bcfe72d'
+down_revision = '2e5352a0ad4d'
+
+from alembic import op
+import sqlalchemy as sa
+
+
+def upgrade():
+ op.create_table(
+ 'ml2_geneve_allocations',
+ sa.Column('geneve_vni', sa.Integer(),
+ autoincrement=False, nullable=False),
+ sa.Column('allocated', sa.Boolean(),
+ server_default=sa.sql.false(), nullable=False),
+ sa.PrimaryKeyConstraint('geneve_vni'),
+ )
+ op.create_index(op.f('ix_ml2_geneve_allocations_allocated'),
+ 'ml2_geneve_allocations', ['allocated'], unique=False)
+ op.create_table(
+ 'ml2_geneve_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_geneve_endpoints0host'),
+ )
from neutron.plugins.ml2.drivers.brocade.db import ( # noqa
models as ml2_brocade_models)
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_vlan # noqa
from neutron.plugins.ml2.drivers import type_vxlan # noqa
# Network Type constants
TYPE_FLAT = 'flat'
+TYPE_GENEVE = 'geneve'
TYPE_GRE = 'gre'
TYPE_LOCAL = 'local'
TYPE_VXLAN = 'vxlan'
MIN_VLAN_TAG = 1
MAX_VLAN_TAG = 4094
+# For Geneve Tunnel
+MIN_GENEVE_VNI = 1
+MAX_GENEVE_VNI = 2 ** 24 - 1
+
# For GRE Tunnel
MIN_GRE_ID = 1
MAX_GRE_ID = 2 ** 32 - 1
VXLAN_UDP_PORT = 4789
# Network Type MTU overhead
+GENEVE_ENCAP_MIN_OVERHEAD = 50
GRE_ENCAP_OVERHEAD = 42
VXLAN_ENCAP_OVERHEAD = 50
return p_const.MIN_VXLAN_VNI <= vni <= p_const.MAX_VXLAN_VNI
+def is_valid_geneve_vni(vni):
+ return p_const.MIN_GENEVE_VNI <= vni <= p_const.MAX_GENEVE_VNI
+
+
def verify_tunnel_range(tunnel_range, tunnel_type):
"""Raise an exception for invalid tunnel range or malformed range."""
mappings = {p_const.TYPE_GRE: is_valid_gre_id,
- p_const.TYPE_VXLAN: is_valid_vxlan_vni}
+ p_const.TYPE_VXLAN: is_valid_vxlan_vni,
+ p_const.TYPE_GENEVE: is_valid_geneve_vni}
if tunnel_type in mappings:
for ident in tunnel_range:
if not mappings[tunnel_type](ident):
ml2_opts = [
cfg.ListOpt('type_drivers',
- default=['local', 'flat', 'vlan', 'gre', 'vxlan'],
+ default=['local', 'flat', 'vlan', 'gre', 'vxlan', 'geneve'],
help=_("List of network type driver entrypoints to be loaded "
"from the neutron.ml2.type_drivers namespace.")),
cfg.ListOpt('tenant_network_types',
NONEXISTENT_PEER = 'nonexistent-peer'
# The different types of tunnels
-TUNNEL_NETWORK_TYPES = [p_const.TYPE_GRE, p_const.TYPE_VXLAN]
+TUNNEL_NETWORK_TYPES = [p_const.TYPE_GRE, p_const.TYPE_VXLAN,
+ p_const.TYPE_GENEVE]
+
# Various tables for DVR use of integration bridge flows
LOCAL_SWITCHING = 0
PATCH_LV_TO_TUN = 2
GRE_TUN_TO_LV = 3
VXLAN_TUN_TO_LV = 4
+GENEVE_TUN_TO_LV = 6
+
DVR_NOT_LEARN = 9
LEARN_FROM_TUN = 10
UCAST_TO_TUN = 20
# 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_VXLAN: VXLAN_TUN_TO_LV,
+ p_const.TYPE_GENEVE: GENEVE_TUN_TO_LV}
+
# The default respawn interval for the ovsdb monitor
DEFAULT_OVSDBMON_RESPAWN = 30
self.bridge_mappings = bridge_mappings
self.setup_physical_bridges(self.bridge_mappings)
self.local_vlan_map = {}
- self.tun_br_ofports = {p_const.TYPE_GRE: {},
+
+ self.tun_br_ofports = {p_const.TYPE_GENEVE: {},
+ p_const.TYPE_GRE: {},
p_const.TYPE_VXLAN: {}}
self.polling_interval = polling_interval
:param net_uuid: the uuid of the network associated with this vlan.
:param network_type: the network type ('gre', 'vxlan', 'vlan', 'flat',
- 'local')
+ 'local', 'geneve')
:param physical_network: the physical network for 'vlan' or 'flat'
:param segmentation_id: the VID for 'vlan' or tunnel ID for 'tunnel'
'''
def _check_agent_configurations(self):
if (self.enable_distributed_routing and self.enable_tunneling
and not self.l2_pop):
- raise ValueError(_("DVR deployments for VXLAN/GRE underlays "
- "require L2-pop to be enabled, in both the "
- "Agent and Server side."))
+
+ raise ValueError(_("DVR deployments for VXLAN/GRE/Geneve "
+ "underlays require L2-pop to be enabled, "
+ "in both the Agent and Server side."))
def create_agent_config_map(config):
--- /dev/null
+# 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
+import sqlalchemy as sa
+from sqlalchemy import sql
+
+from neutron.common import exceptions as n_exc
+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__)
+
+geneve_opts = [
+ cfg.ListOpt('vni_ranges',
+ default=[],
+ help=_("Comma-separated list of <vni_min>:<vni_max> tuples "
+ "enumerating ranges of Geneve VNI IDs that are "
+ "available for tenant network allocation")),
+ cfg.IntOpt('max_header_size',
+ default=p_const.GENEVE_ENCAP_MIN_OVERHEAD,
+ help=_("Geneve encapsulation header size is dynamic, this "
+ "value is used to calculate the maximum MTU "
+ "for the driver."
+ "this is the sum of the sizes of the outer "
+ "ETH + IP + UDP + GENEVE header sizes")),
+]
+
+cfg.CONF.register_opts(geneve_opts, "ml2_type_geneve")
+
+
+class GeneveAllocation(model_base.BASEV2):
+
+ __tablename__ = 'ml2_geneve_allocations'
+
+ geneve_vni = 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 GeneveEndpoints(model_base.BASEV2):
+ """Represents tunnel endpoint in RPC mode."""
+
+ __tablename__ = 'ml2_geneve_endpoints'
+ __table_args__ = (
+ sa.UniqueConstraint('host',
+ name='unique_ml2_geneve_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 "<GeneveTunnelEndpoint(%s)>" % self.ip_address
+
+
+class GeneveTypeDriver(type_tunnel.EndpointTunnelTypeDriver):
+
+ def __init__(self):
+ super(GeneveTypeDriver, self).__init__(GeneveAllocation,
+ GeneveEndpoints)
+ self.max_encap_size = cfg.CONF.ml2_type_geneve.max_header_size
+
+ def get_type(self):
+ return p_const.TYPE_GENEVE
+
+ def initialize(self):
+ try:
+ self._initialize(cfg.CONF.ml2_type_geneve.vni_ranges)
+ except n_exc.NetworkTunnelRangeError:
+ LOG.error(_LE("Failed to parse vni_ranges. "
+ "Service terminated!"))
+ raise SystemExit()
+
+ def get_endpoints(self):
+ """Get every geneve endpoints from database."""
+ geneve_endpoints = self._get_endpoints()
+ return [{'ip_address': geneve_endpoint.ip_address,
+ 'host': geneve_endpoint.host}
+ for geneve_endpoint in geneve_endpoints]
+
+ def add_endpoint(self, ip, host):
+ return self._add_endpoint(ip, host)
+
+ def get_mtu(self, physical_network=None):
+ mtu = super(GeneveTypeDriver, self).get_mtu()
+ return mtu - self.max_encap_size if mtu else 0
def test_ovs_vxlan_support_runs(self):
checks.ovs_vxlan_supported()
+ def test_ovs_geneve_support_runs(self):
+ checks.ovs_geneve_supported()
+
def test_iproute2_vxlan_support_runs(self):
checks.iproute2_vxlan_supported()
'actions': 'resubmit(,22)'},
{'priority': 0, 'table': 3, 'actions': 'drop'},
{'priority': 0, 'table': 4, 'actions': 'drop'},
+ {'priority': 0, 'table': 6, 'actions': 'drop'},
{'priority': 1, 'table': 10,
'actions': 'learn(cookie=0x0,table=20,priority=1,'
'hard_timeout=300,NXM_OF_VLAN_TCI[0..11],'
'actions': 'resubmit(,22)'},
{'priority': 0, 'table': 3, 'actions': 'drop'},
{'priority': 0, 'table': 4, 'actions': 'drop'},
+ {'priority': 0, 'table': 6, 'actions': 'drop'},
{'priority': 1, 'table': 10,
'actions': 'learn(cookie=0x0,table=20,priority=1,'
'hard_timeout=300,NXM_OF_VLAN_TCI[0..11],'
--- /dev/null
+# 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 neutron.plugins.common import constants as p_const
+from neutron.plugins.ml2.drivers import type_geneve
+from neutron.tests.unit.plugins.ml2.drivers import base_type_tunnel
+from neutron.tests.unit.plugins.ml2 import test_rpc
+from neutron.tests.unit import testlib_api
+
+
+TUNNEL_IP_ONE = "10.10.10.77"
+TUNNEL_IP_TWO = "10.10.10.78"
+HOST_ONE = 'fake_host_one1'
+HOST_TWO = 'fake_host_two2'
+
+
+class GeneveTypeTest(base_type_tunnel.TunnelTypeTestMixin,
+ testlib_api.SqlTestCase):
+ DRIVER_CLASS = type_geneve.GeneveTypeDriver
+ TYPE = p_const.TYPE_GENEVE
+
+ def test_get_endpoints(self):
+ self.driver.add_endpoint(TUNNEL_IP_ONE, HOST_ONE)
+ self.driver.add_endpoint(TUNNEL_IP_TWO, HOST_TWO)
+
+ endpoints = self.driver.get_endpoints()
+ for endpoint in endpoints:
+ if endpoint['ip_address'] == TUNNEL_IP_ONE:
+ self.assertEqual(HOST_ONE, endpoint['host'])
+ elif endpoint['ip_address'] == TUNNEL_IP_TWO:
+ self.assertEqual(HOST_TWO, endpoint['host'])
+
+
+class GeneveTypeMultiRangeTest(base_type_tunnel.TunnelTypeMultiRangeTestMixin,
+ testlib_api.SqlTestCase):
+ DRIVER_CLASS = type_geneve.GeneveTypeDriver
+
+
+class GeneveTypeRpcCallbackTest(base_type_tunnel.TunnelRpcCallbackTestMixin,
+ test_rpc.RpcCallbacksTestCase,
+ testlib_api.SqlTestCase):
+ DRIVER_CLASS = type_geneve.GeneveTypeDriver
+ TYPE = p_const.TYPE_GENEVE
flat = neutron.plugins.ml2.drivers.type_flat:FlatTypeDriver
local = neutron.plugins.ml2.drivers.type_local:LocalTypeDriver
vlan = neutron.plugins.ml2.drivers.type_vlan:VlanTypeDriver
+ geneve = neutron.plugins.ml2.drivers.type_geneve:GeneveTypeDriver
gre = neutron.plugins.ml2.drivers.type_gre:GreTypeDriver
vxlan = neutron.plugins.ml2.drivers.type_vxlan:VxlanTypeDriver
neutron.ml2.mechanism_drivers =