summaryrefslogtreecommitdiffstats
path: root/build/neutron/agent/interface/interface.py
diff options
context:
space:
mode:
authorTim Rozet <trozet@redhat.com>2017-02-18 14:47:08 +0000
committerGerrit Code Review <gerrit@opnfv.org>2017-02-18 14:47:08 +0000
commitda0d8e06bb9a55fb9b15b34cabb19c681667d383 (patch)
treeff9e2ff0b8f9d62111d33d2b7fec7bd22775b466 /build/neutron/agent/interface/interface.py
parent645949cbac2bb766d18dfd9f818b6c14545a35e2 (diff)
parentc7e6d15b4d2570c7f9d2bc8dcfc57d8a68fede71 (diff)
Merge "Add support for odl-fdio scenario"
Diffstat (limited to 'build/neutron/agent/interface/interface.py')
-rw-r--r--build/neutron/agent/interface/interface.py552
1 files changed, 0 insertions, 552 deletions
diff --git a/build/neutron/agent/interface/interface.py b/build/neutron/agent/interface/interface.py
deleted file mode 100644
index 709fd677..00000000
--- a/build/neutron/agent/interface/interface.py
+++ /dev/null
@@ -1,552 +0,0 @@
-# Copyright 2012 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.
-
-import abc
-import eventlet
-import netaddr
-from oslo_config import cfg
-from oslo_log import log as logging
-import six
-
-from neutron._i18n import _, _LE, _LI, _LW
-from neutron.agent.common import ovs_lib
-from neutron.agent.linux import ip_lib
-from neutron.agent.linux import utils
-from neutron.common import constants as n_const
-from neutron.common import exceptions
-from neutron.common import ipv6_utils
-
-
-LOG = logging.getLogger(__name__)
-
-OPTS = [
- cfg.StrOpt('ovs_integration_bridge',
- default='br-int',
- help=_('Name of Open vSwitch bridge to use')),
- cfg.BoolOpt('ovs_use_veth',
- default=False,
- help=_('Uses veth for an OVS interface or not. '
- 'Support kernels with limited namespace support '
- '(e.g. RHEL 6.5) so long as ovs_use_veth is set to '
- 'True.')),
- cfg.IntOpt('network_device_mtu',
- deprecated_for_removal=True,
- help=_('MTU setting for device. This option will be removed in '
- 'Newton. Please use the system-wide segment_mtu setting '
- 'which the agents will take into account when wiring '
- 'VIFs.')),
-]
-
-
-@six.add_metaclass(abc.ABCMeta)
-class LinuxInterfaceDriver(object):
-
- # from linux IF_NAMESIZE
- DEV_NAME_LEN = 14
- DEV_NAME_PREFIX = n_const.TAP_DEVICE_PREFIX
-
- def __init__(self, conf):
- self.conf = conf
- if self.conf.network_device_mtu:
- self._validate_network_device_mtu()
-
- def _validate_network_device_mtu(self):
- if (ipv6_utils.is_enabled() and
- self.conf.network_device_mtu < n_const.IPV6_MIN_MTU):
- LOG.error(_LE("IPv6 protocol requires a minimum MTU of "
- "%(min_mtu)s, while the configured value is "
- "%(current_mtu)s"), {'min_mtu': n_const.IPV6_MIN_MTU,
- 'current_mtu': self.conf.network_device_mtu})
- raise SystemExit(1)
-
- @property
- def use_gateway_ips(self):
- """Whether to use gateway IPs instead of unique IP allocations.
-
- In each place where the DHCP agent runs, and for each subnet for
- which DHCP is handling out IP addresses, the DHCP port needs -
- at the Linux level - to have an IP address within that subnet.
- Generally this needs to be a unique Neutron-allocated IP
- address, because the subnet's underlying L2 domain is bridged
- across multiple compute hosts and network nodes, and for HA
- there may be multiple DHCP agents running on that same bridged
- L2 domain.
-
- However, if the DHCP ports - on multiple compute/network nodes
- but for the same network - are _not_ bridged to each other,
- they do not need each to have a unique IP address. Instead
- they can all share the same address from the relevant subnet.
- This works, without creating any ambiguity, because those
- ports are not all present on the same L2 domain, and because
- no data within the network is ever sent to that address.
- (DHCP requests are broadcast, and it is the network's job to
- ensure that such a broadcast will reach at least one of the
- available DHCP servers. DHCP responses will be sent _from_
- the DHCP port address.)
-
- Specifically, for networking backends where it makes sense,
- the DHCP agent allows all DHCP ports to use the subnet's
- gateway IP address, and thereby to completely avoid any unique
- IP address allocation. This behaviour is selected by running
- the DHCP agent with a configured interface driver whose
- 'use_gateway_ips' property is True.
-
- When an operator deploys Neutron with an interface driver that
- makes use_gateway_ips True, they should also ensure that a
- gateway IP address is defined for each DHCP-enabled subnet,
- and that the gateway IP address doesn't change during the
- subnet's lifetime.
- """
- return False
-
- def init_l3(self, device_name, ip_cidrs, namespace=None,
- preserve_ips=None, clean_connections=False):
- """Set the L3 settings for the interface using data from the port.
-
- ip_cidrs: list of 'X.X.X.X/YY' strings
- preserve_ips: list of ip cidrs that should not be removed from device
- clean_connections: Boolean to indicate if we should cleanup connections
- associated to removed ips
- """
- preserve_ips = preserve_ips or []
- device = ip_lib.IPDevice(device_name, namespace=namespace)
-
- # The LLA generated by the operating system is not known to
- # Neutron, so it would be deleted if we added it to the 'previous'
- # list here
- default_ipv6_lla = ip_lib.get_ipv6_lladdr(device.link.address)
- previous = {addr['cidr'] for addr in device.addr.list(
- filters=['permanent'])} - {default_ipv6_lla}
-
- # add new addresses
- for ip_cidr in ip_cidrs:
-
- net = netaddr.IPNetwork(ip_cidr)
- # Convert to compact IPv6 address because the return values of
- # "ip addr list" are compact.
- if net.version == 6:
- ip_cidr = str(net)
- if ip_cidr in previous:
- previous.remove(ip_cidr)
- continue
-
- device.addr.add(ip_cidr)
-
- # clean up any old addresses
- for ip_cidr in previous:
- if ip_cidr not in preserve_ips:
- if clean_connections:
- device.delete_addr_and_conntrack_state(ip_cidr)
- else:
- device.addr.delete(ip_cidr)
-
- def init_router_port(self,
- device_name,
- ip_cidrs,
- namespace,
- preserve_ips=None,
- extra_subnets=None,
- clean_connections=False):
- """Set the L3 settings for a router interface using data from the port.
-
- ip_cidrs: list of 'X.X.X.X/YY' strings
- preserve_ips: list of ip cidrs that should not be removed from device
- clean_connections: Boolean to indicate if we should cleanup connections
- associated to removed ips
- extra_subnets: An iterable of cidrs to add as routes without address
- """
- LOG.debug("init_router_port: device_name(%s), namespace(%s)",
- device_name, namespace)
- self.init_l3(device_name=device_name,
- ip_cidrs=ip_cidrs,
- namespace=namespace,
- preserve_ips=preserve_ips or [],
- clean_connections=clean_connections)
-
- device = ip_lib.IPDevice(device_name, namespace=namespace)
-
- # Manage on-link routes (routes without an associated address)
- new_onlink_cidrs = set(s['cidr'] for s in extra_subnets or [])
-
- v4_onlink = device.route.list_onlink_routes(n_const.IP_VERSION_4)
- v6_onlink = device.route.list_onlink_routes(n_const.IP_VERSION_6)
- existing_onlink_cidrs = set(r['cidr'] for r in v4_onlink + v6_onlink)
-
- for route in new_onlink_cidrs - existing_onlink_cidrs:
- LOG.debug("adding onlink route(%s)", route)
- device.route.add_onlink_route(route)
- for route in (existing_onlink_cidrs - new_onlink_cidrs -
- set(preserve_ips or [])):
- LOG.debug("deleting onlink route(%s)", route)
- device.route.delete_onlink_route(route)
-
- def add_ipv6_addr(self, device_name, v6addr, namespace, scope='global'):
- device = ip_lib.IPDevice(device_name,
- namespace=namespace)
- net = netaddr.IPNetwork(v6addr)
- device.addr.add(str(net), scope)
-
- def delete_ipv6_addr(self, device_name, v6addr, namespace):
- device = ip_lib.IPDevice(device_name,
- namespace=namespace)
- device.delete_addr_and_conntrack_state(v6addr)
-
- def delete_ipv6_addr_with_prefix(self, device_name, prefix, namespace):
- """Delete the first listed IPv6 address that falls within a given
- prefix.
- """
- device = ip_lib.IPDevice(device_name, namespace=namespace)
- net = netaddr.IPNetwork(prefix)
- for address in device.addr.list(scope='global', filters=['permanent']):
- ip_address = netaddr.IPNetwork(address['cidr'])
- if ip_address in net:
- device.delete_addr_and_conntrack_state(address['cidr'])
- break
-
- def get_ipv6_llas(self, device_name, namespace):
- device = ip_lib.IPDevice(device_name,
- namespace=namespace)
-
- return device.addr.list(scope='link', ip_version=6)
-
- def check_bridge_exists(self, bridge):
- if not ip_lib.device_exists(bridge):
- raise exceptions.BridgeDoesNotExist(bridge=bridge)
-
- def get_device_name(self, port):
- return (self.DEV_NAME_PREFIX + port.id)[:self.DEV_NAME_LEN]
-
- @staticmethod
- def configure_ipv6_ra(namespace, dev_name):
- """Configure acceptance of IPv6 route advertisements on an intf."""
- # Learn the default router's IP address via RAs
- ip_lib.IPWrapper(namespace=namespace).netns.execute(
- ['sysctl', '-w', 'net.ipv6.conf.%s.accept_ra=2' % dev_name])
-
- @abc.abstractmethod
- def plug_new(self, network_id, port_id, device_name, mac_address,
- bridge=None, namespace=None, prefix=None, mtu=None):
- """Plug in the interface only for new devices that don't exist yet."""
-
- def plug(self, network_id, port_id, device_name, mac_address,
- bridge=None, namespace=None, prefix=None, mtu=None):
- if not ip_lib.device_exists(device_name,
- namespace=namespace):
- try:
- self.plug_new(network_id, port_id, device_name, mac_address,
- bridge, namespace, prefix, mtu)
- except TypeError:
- self.plug_new(network_id, port_id, device_name, mac_address,
- bridge, namespace, prefix)
- else:
- LOG.info(_LI("Device %s already exists"), device_name)
-
- @abc.abstractmethod
- def unplug(self, device_name, bridge=None, namespace=None, prefix=None):
- """Unplug the interface."""
-
- @property
- def bridged(self):
- """Whether the DHCP port is bridged to the VM TAP interfaces.
-
- When the DHCP port is bridged to the TAP interfaces for the
- VMs for which it is providing DHCP service - as is the case
- for most Neutron network implementations - the DHCP server
- only needs to listen on the DHCP port, and will still receive
- DHCP requests from all the relevant VMs.
-
- If the DHCP port is not bridged to the relevant VM TAP
- interfaces, the DHCP server needs to listen explicitly on
- those TAP interfaces, and to treat those as aliases of the
- DHCP port where the IP subnet is defined.
- """
- return True
-
-
-class NullDriver(LinuxInterfaceDriver):
- def plug_new(self, network_id, port_id, device_name, mac_address,
- bridge=None, namespace=None, prefix=None, mtu=None):
- pass
-
- def unplug(self, device_name, bridge=None, namespace=None, prefix=None):
- pass
-
-class NSDriver(LinuxInterfaceDriver):
- """Device independent driver enabling creation of a non device specific
- interface in network spaces. Attachment to the device is not performed.
- """
- MAX_TIME_FOR_DEVICE_EXISTENCE = 30
-
- @classmethod
- def _device_is_created_in_time(cls, device_name):
- """See if device is created, within time limit."""
- attempt = 0
- while attempt < NSDriver.MAX_TIME_FOR_DEVICE_EXISTENCE:
- if ip_lib.device_exists(device_name):
- return True
- attempt += 1
- eventlet.sleep(1)
- LOG.error(_LE("Device %(dev)s was not created in %(time)d seconds"),
- {'dev': device_name,
- 'time': NSDriver.MAX_TIME_FOR_DEVICE_EXISTENCE})
- return False
-
- def _configure_mtu(self, ns_dev, mtu=None):
- # Need to set MTU, after added to namespace. See review
- # https://review.openstack.org/327651
- try:
- # Note: network_device_mtu will be deprecated in future
- mtu_override = self.conf.network_device_mtu
- except cfg.NoSuchOptError:
- LOG.warning(_LW("Config setting for MTU deprecated - any "
- "override will be ignored."))
- mtu_override = None
- if mtu_override:
- mtu = mtu_override
- LOG.debug("Overriding MTU to %d", mtu)
- if mtu:
- ns_dev.link.set_mtu(mtu)
- else:
- LOG.debug("No MTU provided - skipping setting value")
-
- def plug(self, network_id, port_id, device_name, mac_address,
- bridge=None, namespace=None, prefix=None, mtu=None):
-
- # Overriding this, we still want to add an existing device into the
- # namespace.
- self.plug_new(network_id, port_id, device_name, mac_address,
- bridge, namespace, prefix, mtu)
-
- def plug_new(self, network_id, port_id, device_name, mac_address,
- bridge=None, namespace=None, prefix=None, mtu=None):
-
- ip = ip_lib.IPWrapper()
- ns_dev = ip.device(device_name)
-
- LOG.debug("Plugging dev: '%s' into namespace: '%s' ",
- device_name, namespace)
-
- # Wait for device creation
- if not self._device_is_created_in_time(device_name):
- return
-
- ns_dev.link.set_address(mac_address)
-
- if namespace:
- namespace_obj = ip.ensure_namespace(namespace)
- namespace_obj.add_device_to_namespace(ns_dev)
-
- self._configure_mtu(ns_dev, mtu)
-
- ns_dev.link.set_up()
-
- def unplug(self, device_name, bridge=None, namespace=None, prefix=None):
- # Device removal is done externally. Just remove the namespace
- LOG.debug("Removing namespace: '%s'", namespace)
- ip_lib.IPWrapper(namespace).garbage_collect_namespace()
-
-
-class OVSInterfaceDriver(LinuxInterfaceDriver):
- """Driver for creating an internal interface on an OVS bridge."""
-
- DEV_NAME_PREFIX = n_const.TAP_DEVICE_PREFIX
-
- def __init__(self, conf):
- super(OVSInterfaceDriver, self).__init__(conf)
- if self.conf.ovs_use_veth:
- self.DEV_NAME_PREFIX = 'ns-'
-
- def _get_tap_name(self, dev_name, prefix=None):
- if self.conf.ovs_use_veth:
- dev_name = dev_name.replace(prefix or self.DEV_NAME_PREFIX,
- n_const.TAP_DEVICE_PREFIX)
- return dev_name
-
- def _ovs_add_port(self, bridge, device_name, port_id, mac_address,
- internal=True):
- attrs = [('external_ids', {'iface-id': port_id,
- 'iface-status': 'active',
- 'attached-mac': mac_address})]
- if internal:
- attrs.insert(0, ('type', 'internal'))
-
- ovs = ovs_lib.OVSBridge(bridge)
- ovs.replace_port(device_name, *attrs)
-
- def plug_new(self, network_id, port_id, device_name, mac_address,
- bridge=None, namespace=None, prefix=None, mtu=None):
- """Plug in the interface."""
- if not bridge:
- bridge = self.conf.ovs_integration_bridge
-
- self.check_bridge_exists(bridge)
-
- ip = ip_lib.IPWrapper()
- tap_name = self._get_tap_name(device_name, prefix)
-
- if self.conf.ovs_use_veth:
- # Create ns_dev in a namespace if one is configured.
- root_dev, ns_dev = ip.add_veth(tap_name,
- device_name,
- namespace2=namespace)
- root_dev.disable_ipv6()
- else:
- ns_dev = ip.device(device_name)
-
- internal = not self.conf.ovs_use_veth
- self._ovs_add_port(bridge, tap_name, port_id, mac_address,
- internal=internal)
-
- ns_dev.link.set_address(mac_address)
-
- # Add an interface created by ovs to the namespace.
- if not self.conf.ovs_use_veth and namespace:
- namespace_obj = ip.ensure_namespace(namespace)
- namespace_obj.add_device_to_namespace(ns_dev)
-
- # NOTE(ihrachys): the order here is significant: we must set MTU after
- # the device is moved into a namespace, otherwise OVS bridge does not
- # allow to set MTU that is higher than the least of all device MTUs on
- # the bridge
- mtu = self.conf.network_device_mtu or mtu
- if mtu:
- ns_dev.link.set_mtu(mtu)
- if self.conf.ovs_use_veth:
- root_dev.link.set_mtu(mtu)
- else:
- LOG.warning(_LW("No MTU configured for port %s"), port_id)
-
- ns_dev.link.set_up()
- if self.conf.ovs_use_veth:
- root_dev.link.set_up()
-
- def unplug(self, device_name, bridge=None, namespace=None, prefix=None):
- """Unplug the interface."""
- if not bridge:
- bridge = self.conf.ovs_integration_bridge
-
- tap_name = self._get_tap_name(device_name, prefix)
- self.check_bridge_exists(bridge)
- ovs = ovs_lib.OVSBridge(bridge)
-
- try:
- ovs.delete_port(tap_name)
- if self.conf.ovs_use_veth:
- device = ip_lib.IPDevice(device_name, namespace=namespace)
- device.link.delete()
- LOG.debug("Unplugged interface '%s'", device_name)
- except RuntimeError:
- LOG.error(_LE("Failed unplugging interface '%s'"),
- device_name)
-
-
-class IVSInterfaceDriver(LinuxInterfaceDriver):
- """Driver for creating an internal interface on an IVS bridge."""
-
- DEV_NAME_PREFIX = n_const.TAP_DEVICE_PREFIX
-
- def __init__(self, conf):
- super(IVSInterfaceDriver, self).__init__(conf)
- self.DEV_NAME_PREFIX = 'ns-'
-
- def _get_tap_name(self, dev_name, prefix=None):
- dev_name = dev_name.replace(prefix or self.DEV_NAME_PREFIX,
- n_const.TAP_DEVICE_PREFIX)
- return dev_name
-
- def _ivs_add_port(self, device_name, port_id, mac_address):
- cmd = ['ivs-ctl', 'add-port', device_name]
- utils.execute(cmd, run_as_root=True)
-
- def plug_new(self, network_id, port_id, device_name, mac_address,
- bridge=None, namespace=None, prefix=None, mtu=None):
- """Plug in the interface."""
- ip = ip_lib.IPWrapper()
- tap_name = self._get_tap_name(device_name, prefix)
-
- root_dev, ns_dev = ip.add_veth(tap_name, device_name)
- root_dev.disable_ipv6()
-
- self._ivs_add_port(tap_name, port_id, mac_address)
-
- ns_dev = ip.device(device_name)
- ns_dev.link.set_address(mac_address)
-
- mtu = self.conf.network_device_mtu or mtu
- if mtu:
- ns_dev.link.set_mtu(mtu)
- root_dev.link.set_mtu(mtu)
- else:
- LOG.warning(_LW("No MTU configured for port %s"), port_id)
-
- if namespace:
- namespace_obj = ip.ensure_namespace(namespace)
- namespace_obj.add_device_to_namespace(ns_dev)
-
- ns_dev.link.set_up()
- root_dev.link.set_up()
-
- def unplug(self, device_name, bridge=None, namespace=None, prefix=None):
- """Unplug the interface."""
- tap_name = self._get_tap_name(device_name, prefix)
- try:
- cmd = ['ivs-ctl', 'del-port', tap_name]
- utils.execute(cmd, run_as_root=True)
- device = ip_lib.IPDevice(device_name, namespace=namespace)
- device.link.delete()
- LOG.debug("Unplugged interface '%s'", device_name)
- except RuntimeError:
- LOG.error(_LE("Failed unplugging interface '%s'"),
- device_name)
-
-
-class BridgeInterfaceDriver(LinuxInterfaceDriver):
- """Driver for creating bridge interfaces."""
-
- DEV_NAME_PREFIX = 'ns-'
-
- def plug_new(self, network_id, port_id, device_name, mac_address,
- bridge=None, namespace=None, prefix=None, mtu=None):
- """Plugin the interface."""
- ip = ip_lib.IPWrapper()
-
- # Enable agent to define the prefix
- tap_name = device_name.replace(prefix or self.DEV_NAME_PREFIX,
- n_const.TAP_DEVICE_PREFIX)
- # Create ns_veth in a namespace if one is configured.
- root_veth, ns_veth = ip.add_veth(tap_name, device_name,
- namespace2=namespace)
- root_veth.disable_ipv6()
- ns_veth.link.set_address(mac_address)
-
- mtu = self.conf.network_device_mtu or mtu
- if mtu:
- root_veth.link.set_mtu(mtu)
- ns_veth.link.set_mtu(mtu)
- else:
- LOG.warning(_LW("No MTU configured for port %s"), port_id)
-
- root_veth.link.set_up()
- ns_veth.link.set_up()
-
- def unplug(self, device_name, bridge=None, namespace=None, prefix=None):
- """Unplug the interface."""
- device = ip_lib.IPDevice(device_name, namespace=namespace)
- try:
- device.link.delete()
- LOG.debug("Unplugged interface '%s'", device_name)
- except RuntimeError:
- LOG.error(_LE("Failed unplugging interface '%s'"),
- device_name)