Nested-Containers: vlan driver

Add support to enable isolation of container's traffic within
host(nova instances) using vlan segmentations.

Partially Implements blueprint containers-in-instances
Change-Id: If4800594adfac27a8f30dedac4787d79c8634b65
This commit is contained in:
vikaschoudhary16 2016-11-14 07:54:18 +00:00 committed by vikas choudhary
parent ac38fdc0b0
commit 116052f9db
9 changed files with 165 additions and 6 deletions

View File

@ -13,7 +13,8 @@ from oslo_config import cfg
from oslo_utils import importutils
def port_bind(endpoint_id, port, subnets, network=None, vm_port=None):
def port_bind(endpoint_id, port, subnets, network=None, vm_port=None,
segmentation_id=None):
"""Binds the Neutron port to the network interface on the host.
:param endpoint_id: the ID of the endpoint as string
@ -27,6 +28,7 @@ def port_bind(endpoint_id, port, subnets, network=None, vm_port=None):
python-neutronclient. Binding is being done for the
port of a container which is running inside this Nova
instance (either ipvlan/macvlan or a subport).
:param segmentation_id: ID of the segment for container traffic isolation)
:returns: the tuple of the names of the veth pair and the tuple of stdout
and stderr returned by processutils.execute invoked with the
executable script for binding
@ -34,9 +36,9 @@ def port_bind(endpoint_id, port, subnets, network=None, vm_port=None):
processutils.ProcessExecutionError
"""
driver = importutils.import_module(cfg.CONF.binding.driver)
return driver.port_bind(endpoint_id, port, subnets, network=network,
vm_port=vm_port)
vm_port=vm_port,
segmentation_id=segmentation_id)
def port_unbind(endpoint_id, neutron_port):

View File

@ -20,7 +20,8 @@ KIND = 'ipvlan'
IPVLAN_MODE_L2 = ifinfmsg.ifinfo.ipvlan_data.modes['IPVLAN_MODE_L2']
def port_bind(endpoint_id, port, subnets, network=None, vm_port=None):
def port_bind(endpoint_id, port, subnets, network=None, vm_port=None,
segmentation_id=None):
"""Binds the Neutron port to the network interface on the host.
:param endpoint_id: the ID of the endpoint as string
@ -33,6 +34,7 @@ def port_bind(endpoint_id, port, subnets, network=None, vm_port=None):
:param vm_port: the Nova instance port dictionary, as returned by
python-neutronclient. Container is running inside
this instance (either ipvlan/macvlan or a subport)
:param segmentation_id: ID of the segment for container traffic isolation)
:returns: the tuple of the names of the veth pair and the tuple of stdout
and stderr returned by processutils.execute invoked with the
executable script for binding

View File

@ -19,7 +19,8 @@ KIND = 'macvlan'
MACVLAN_MODE_BRIDGE = 'bridge'
def port_bind(endpoint_id, port, subnets, network=None, vm_port=None):
def port_bind(endpoint_id, port, subnets, network=None, vm_port=None,
segmentation_id=None):
"""Binds the Neutron port to the network interface on the host.
:param endpoint_id: the ID of the endpoint as string
@ -32,6 +33,7 @@ def port_bind(endpoint_id, port, subnets, network=None, vm_port=None):
:param vm_port: the Nova instance port dictionary, as returned by
python-neutronclient. Container is running inside
instance.
:param segmentation_id: ID of the segment for container traffic isolation)
:returns: the tuple of the names of the veth pair and the tuple of stdout
and stderr returned by processutils.execute invoked with the
executable script for binding

View File

@ -32,7 +32,8 @@ VIF_DETAILS_KEY = 'binding:vif_details'
VIF_TYPE_KEY = 'binding:vif_type'
def port_bind(endpoint_id, port, subnets, network=None, vm_port=None):
def port_bind(endpoint_id, port, subnets, network=None, vm_port=None,
segmentation_id=None):
"""Binds the Neutron port to the network interface on the host.
:param endpoint_id: the ID of the endpoint as string
@ -46,6 +47,7 @@ def port_bind(endpoint_id, port, subnets, network=None, vm_port=None):
python-neutronclient. Container port under binding is
running inside this instance (either ipvlan/macvlan or
a subport)
:param segmentation_id: ID of the segment for container traffic isolation)
:returns: the tuple of the names of the veth pair and the tuple of stdout
and stderr returned by processutils.execute invoked with the
executable script for binding

View File

@ -0,0 +1,56 @@
# 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.
"""It only supports container-in-vm deployments"""
from kuryr.lib.binding.drivers import nested
from kuryr.lib.binding.drivers import utils
KIND = 'vlan'
def port_bind(endpoint_id, port, subnets, network=None,
vm_port=None, segmentation_id=None):
"""Binds the Neutron port to the network interface on the host.
:param endpoint_id: the ID of the endpoint as string
:param port: the container Neutron port dictionary as returned by
python-neutronclient
:param subnets: an iterable of all the Neutron subnets which the
endpoint is trying to join
:param network: the Neutron network which the endpoint is trying to
join
:param vm_port: the Nova instance port dictionary, as returned by
python-neutronclient. Container is running inside this
instance (either ipvlan/macvlan or a subport)
:param segmentation_id: ID of the segment for container traffic isolation)
:returns: the tuple of the names of the veth pair and the tuple of stdout
and stderr returned by processutils.execute invoked with the
executable script for binding
:raises: kuryr.common.exceptions.VethCreationFailure,
processutils.ProcessExecutionError
"""
ip = utils.get_ipdb()
port_id = port['id']
_, devname = utils.get_veth_pair_names(port_id)
link_iface = nested.get_link_iface(vm_port)
with ip.create(ifname=devname, kind=KIND,
link=ip.interfaces[link_iface],
address=port.get(utils.MAC_ADDRESS_KEY),
vlan_id=segmentation_id) as container_iface:
utils._configure_container_iface(
container_iface, subnets,
fixed_ips=port.get(utils.FIXED_IP_KEY))
return None, devname, ('', None)
port_unbind = nested.port_unbind

View File

@ -18,3 +18,7 @@ DEVICE_OWNER = 'kuryr:container'
NIC_NAME_LEN = 14
VETH_PREFIX = 'tap'
CONTAINER_VETH_PREFIX = 't_c'
# For VLAN type segmentation
MIN_VLAN_TAG = 1
MAX_VLAN_TAG = 4094

View File

@ -94,3 +94,19 @@ class ExportPortFailure(KuryrException):
This exception is thrown when performing Neutron security group failed
for an exported port and Kuryr can't proceed the expose further.
"""
class SegmentationIdAllocationFailure(KuryrException):
"""Exception represents when segmentation id could not be allocated.
This exception is thrown when the segmentaion id for the isolation of
container traffic could not be allocated and Kuryr can't proceed further.
"""
class SegmentationDriverBindingDriverCompatibilityFailure(KuryrException):
"""Exception represents when no segmentation type driver is loaded.
This exception is thrown when configured binding driver does not have
a supporting segmentation type driver.
"""

View File

@ -0,0 +1,42 @@
# 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_utils import importutils
from kuryr.lib import exceptions as ex
BASE_PATH = 'kuryr.lib.segmentation_type_drivers'
driver_name = cfg.CONF.binding.driver.rsplit('.', 1)[1]
# REVISIT(vikasc): Need to remove this if check
if driver_name == 'vlan':
seg_driver_path = '.'.join([BASE_PATH, driver_name])
segmentation_driver = importutils.import_module(seg_driver_path)
driver = segmentation_driver.SegmentationDriver()
def allocate_segmentation_id(allocated_ids=set()):
"""Allocates a segmentation ID."""
try:
id = driver.allocate_segmentation_id(allocated_ids)
except NameError:
raise ex.SegmentationDriverBindingDriverCompatibilityFailure
return id
def release_segmentation_id(id):
"""Releases the segmentation ID."""
try:
driver.release_segmentation_id(id)
except NameError:
raise ex.SegmentationDriverBindingDriverCompatibilityFailure

View File

@ -0,0 +1,33 @@
# 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 six import moves
from kuryr.lib import constants as const
from kuryr.lib import exceptions
class SegmentationDriver(object):
def __init__(self):
self.available_local_vlans = set(moves.range(const.MIN_VLAN_TAG,
const.MAX_VLAN_TAG + 1))
def allocate_segmentation_id(self, allocated_ids=set()):
self.available_local_vlans.difference_update(allocated_ids)
try:
allocated = self.available_local_vlans.pop()
except KeyError:
raise exceptions.segmentationIdAllocationFailure
return allocated
def release_segmentation_id(self, id):
self.available_local_vlans.add(id)