PSARC 2015/535 OpenStack service updates for Kilo
PSARC 2015/458 aioeventlet - asyncio event loop scheduling callbacks in eventlet
PSARC 2015/460 msgpack - C/Python bindings for MessagePack (de)serializer data
PSARC 2015/466 openstackclient - OpenStack Command-line Client
PSARC 2015/467 oslo.versionedobjects - Oslo Versioned Objects library
PSARC 2015/468 pint - A physical quantities module
PSARC 2015/469 pysaml2 - A pure Python implementation of SAML2
PSARC 2015/471 semantic_version - A library implementing the 'SemVer' scheme
PSARC 2015/472 testresources - PyUnit extension for managing expensive test resources
PSARC 2015/473 testscenarios - Extensions to Python unittest to support scenarios
PSARC 2015/474 trollius - Port of the Tulip project (asyncio module, PEP 3156) on Python 2
PSARC 2015/475 urllib3 - HTTP library with thread-safe connection pooling, file post, and more
PSARC 2015/520 oslo.concurrency - Oslo Concurrency library
PSARC 2015/521 oslo.log - Oslo Logging Configuration library
PSARC 2015/529 oslo.policy - Oslo Policy library
PSARC 2015/530 psutil - Python system and process utilities
PSARC 2015/538 fixtures - Python module to support reusable state for writing clean tests
PSARC 2015/539 sqlparse - An SQL parser module for Python
PSARC 2016/017 extras - Useful extra utilities for Python
PSARC 2016/018 linecache2 - Port of the standard linecache module
PSARC 2016/019 python-mimeparse - Basic functions for parsing mime-types
PSARC 2016/020 testtools - Extensions to the Python unit testing framework
PSARC 2016/021 traceback2 - Port of the standard traceback module
PSARC 2016/014 OpenStack Cinder NFS driver for Solaris
PSARC/2016/010 cloudbase-init: Portable cloud image initialization
PSARC/2016/130 Solaris OpenStack Puppet Extensions
PSARC/2016/172 Making OpenStack Nova's image cache sharable
PSARC/2016/001 OpenStack Puppet Modules
PSARC/2016/016 Rename/Refactor Puppet and Puppet Module Packages
PSARC/2015/368 Common Puppet Modules
PSARC 2015/357 OpenStack Nova support for kernel zone suspend/resume
22384068 OpenStack service updates for Kilo (Umbrella)
23205460 Fix for 23192887 breaks Juno to Kilo upgrade with instances and floating IPs
23192887 Upgrade from Juno to Kilo fails (neutron-upgrade) due to typo
22878181 Neutron database tables not upgraded properly from Juno to Kilo schema
22935140 Kilo upgrade adds deprecated settings for rabbit and qpid
22935039 Kilo upgrade conf file migration errors
23027746 Metadata access broken with too many networks
23040216 extra zfssa_ prefix in the zfssa_iscsi.pp backend manifest
22992961 Update saz-memcached to 2.8.1
22992956 Update puppetlabs-stdlib to 4.11.0
22992951 Update puppetlabs-ntp to 4.1.2
22992946 Update puppetlabs-mysql to 3.6.2
22992926 Update puppetlabs-apache to 1.8.1
22992933 Update puppetlabs-inifile to 1.4.3
22999085 apache puppet module doesn't support ssl on Solaris
22985076 neutron_network provider always sets --shared on new networks
22813139 add zfssa cinder puppet modules
22902222 add NFS cinder puppet modules
22918553 update vpnaas and l3 agent puppet modules
22902853 Neutron/VPNaaS needs a workaround for 22902761
22827759 nova-compute still trips over itself when rad:local restarts
20990774 nova image cache bloats clone archives to godzilla size
22750945 Revert resize same host branded zones results in error status
18733958 nova tried to create x86 instance on SPARC
22220227 failure to apply zonecfg in attach_volume can leave debris in zonecfg
22935198 puppetlabs-mysql should define basedir in params.pp
22911268 Update puppetlabs-rabbitmq to 5.3.1
22852949 problem in PYTHON-MOD/DJANGO
22852962 problem in PYTHON-MOD/DJANGO
22819808 target_provision_state should not be set to AVAILABLE
22491714 Request to integrate OpenStack Puppet modules
22713569 nova-conductor doesn't handle RPC timeout during live-migration well
22695176 Miscellaneous package cleanup for Kilo
22694904 Some of the OpenStack patches can be cleaned up
22694680 Dependencies in several OpenStack service packages can be improved
22694592 Several configuration files should be more aligned with the upstream
22575858 problem in SERVICE/SWIFT
22047789 puppet package name and dependencies are confusing
22664785 Puppet module files should be owned by puppet
21460057 Add cloudbase-init to Solaris
21974208 The Python module msgpack should be added to Userland
22010630 The Python trollius module should be added to Userland
22011755 The Python module pint should be added to Userland
22012256 The Python aioeventlet module should be added to Userland
22012282 The Python oslo.versionedobjects module should be added to Userland
22012317 The Python semantic_version module should be added to Userland
22012321 The Python testresources module should be added to Userland
22012329 The Python testscenarios module should be added to Userland
22012336 The Python urllib3 module should be added to Userland
22012343 The Python openstackclient module should be added to Userland
22299389 The Python oslo.concurrency module should be added to Userland
22299409 The Python oslo.log module should be added to Userland
22299418 The Python oslo.policy module should be added to Userland
22299469 The Python psutil module should be added to Userland
22337793 The Python sqlparse module should be added to Userland
22338325 The Python fixtures module should be added to Userland
22535728 The Python testtools module should be added to Userland
22535739 The Python extras module should be added to Userland
22535748 The Python linecache2 module should be added to Userland
22535753 The Python traceback2 module should be added to Userland
22535760 The Python python-mimeparse module should be added to Userland
18961001 Image filtering does not function as expected
21678935 NFS for Cinder in Solaris OpenStack
22548630 derived manifest should not enforce presence of global when installing from UAR
22629795 problem in SERVICE/KEYSTONE
22151922 zones_suspend_path needs update based on post-PSARC discussion
21660603 passlib dependency needs to be added to Nova
22188197 puppetlabs-rabbitmq needs a patch to handle rabbitmqadmin
21756542 problem in SERVICE/SWIFT
21978756 addrconf addresses must be created for stateless and slaac Neutron subnets
21978743 ndpd.conf entries are incorrectly formatted for IPv6 subnets
21919000 neutron-dhcp-agent and neutron-server have timing issues
21918991 database times out when attempting various actions
21682493 Neutron fails due to mysql transaction locks when creating multiple instances
22024767 Remove annoying "Arguments dropped when creating context" logging
21691386 Request to integrate common puppet modules into Userland
21630128 Neutron needs to support updating subnet DNS configuration
21761279 Driver erroneously includes trailing space in zone.install() arguments
21438537 After update, openstack/keystone/keystone-token-flush not running
21630538 Nova driver should support suspend/resume
21542088 VM's display_name is used instead of hostname to set the hostname for VM
19774239 Nova should support setting the Admin Password
21439855 Console SMF instance remains after nova instance is deleted
21348400 Issues encountered via unit testing
21341088 Parsing manifest/profiles fails if multiple criteria present
21303465 edit image window has no ZFS disk format option
21091598 ceilometerclient's Makefile needs to point to its own PROJECT_URL
21164329 saharaclient COMPONENT_BUGDB points to the wrong subcomponent
20431382 keystone should include a periodic token cleanup job
21299660 enable no-gateway check box now that we support it
21135855 Enable gateway-less external networks
20230409 remove _get_zone_auto_install_state from driver.py
21022556 optional dependencies on rabbitmq need work in OpenStack services
22568587 heat denial of service through template-validate
22157556 RabbitMQ Warning: Mochiweb enabled and Erlang version 17
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 VMware, Inc. All rights reserved.
#
# Copyright (c) 2014, 2016, Oracle and/or its affiliates. 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.
#
"""
Based off generic l3_agent (neutron/agent/l3_agent) code
"""
import errno
import netaddr
from oslo.config import cfg
from oslo_log import log as logging
from neutron.agent.l3 import agent as l3_agent
from neutron.agent.l3 import router_info as router
from neutron.agent.linux import utils
from neutron.agent.solaris import interface
from neutron.agent.solaris import ipfilters_manager
from neutron.agent.solaris import net_lib
from neutron.agent.solaris import ra
from neutron.callbacks import events
from neutron.callbacks import registry
from neutron.callbacks import resources
from neutron.common import constants as l3_constants
from neutron.common import exceptions as n_exc
from neutron.common import utils as common_utils
from oslo_utils import importutils
from oslo_log import log as logging
import neutron_vpnaas.services.vpn.agent as neutron_vpnaas
from neutron_vpnaas.extensions import vpnaas
from neutron_vpnaas.services.vpn import vpn_service
LOG = logging.getLogger(__name__)
INTERNAL_DEV_PREFIX = 'l3i'
EXTERNAL_DEV_PREFIX = 'l3e'
FLOATING_IP_CIDR_SUFFIX = '/32'
class SolarisRouterInfo(router.RouterInfo):
def __init__(self, router_id, router, agent_conf, interface_driver,
use_ipv6=False):
super(SolarisRouterInfo, self).__init__(router_id, router, agent_conf,
interface_driver, use_ipv6)
self.ipfilters_manager = ipfilters_manager.IPfiltersManager()
self.iptables_manager = None
self.remove_route = False
def initialize(self, process_monitor):
"""Initialize the router on the system.
This differs from __init__ in that this method actually affects the
system creating namespaces, starting processes, etc. The other merely
initializes the python object. This separates in-memory object
initialization from methods that actually go do stuff to the system.
:param process_monitor: The agent's process monitor instance.
"""
self.process_monitor = process_monitor
self.radvd = ra.NDPD(self.router_id, self.get_internal_device_name)
def get_internal_device_name(self, port_id):
# Because of the way how dnsmasq works on Solaris, the length
# of datalink name cannot exceed 16 (includes terminating nul
# character). So, the linkname can only have 15 characters and
# the last two characters are set aside for '_0'. So, we only
# have 13 characters left.
dname = (INTERNAL_DEV_PREFIX + port_id)[:13]
dname += '_0'
return dname.replace('-', '_')
def get_external_device_name(self, port_id):
# please see the comment above
dname = (EXTERNAL_DEV_PREFIX + port_id)[:13]
dname += '_0'
return dname.replace('-', '_')
def routes_updated(self):
pass
def _get_existing_devices(self):
return net_lib.Datalink.show_link()
def internal_network_added(self, port):
internal_dlname = self.get_internal_device_name(port['id'])
# driver just returns if datalink and IP interface already exists
self.driver.plug(port['tenant_id'], port['network_id'], port['id'],
internal_dlname)
ip_cidrs = common_utils.fixed_ip_cidrs(port['fixed_ips'])
self.driver.init_l3(internal_dlname, ip_cidrs)
# Since we support shared router model, we need to block the new
# internal port from reaching other tenant's ports
block_pname = self._get_ippool_name(port['mac_address'])
self.ipfilters_manager.add_ippool(block_pname, None)
if self.agent_conf.allow_forwarding_between_networks:
# If allow_forwarding_between_networks is set, then we need to
# allow forwarding of packets between same tenant's ports.
allow_pname = self._get_ippool_name(port['mac_address'], '0')
self.ipfilters_manager.add_ippool(allow_pname, None)
# walk through the other internal ports and retrieve their
# cidrs and at the same time add the new internal port's
# cidr to them
port_subnet = port['subnets'][0]['cidr']
block_subnets = []
allow_subnets = []
for internal_port in self.internal_ports:
if internal_port['mac_address'] == port['mac_address']:
continue
if (self.agent_conf.allow_forwarding_between_networks and
internal_port['tenant_id'] == port['tenant_id']):
allow_subnets.append(internal_port['subnets'][0]['cidr'])
# we need to add the port's subnet to this internal_port's
# allowed_subnet_pool
iport_allow_pname = \
self._get_ippool_name(internal_port['mac_address'], '0')
self.ipfilters_manager.add_ippool(iport_allow_pname,
[port_subnet])
else:
block_subnets.append(internal_port['subnets'][0]['cidr'])
iport_block_pname = \
self._get_ippool_name(internal_port['mac_address'])
self.ipfilters_manager.add_ippool(iport_block_pname,
[port_subnet])
# update the new port's pool with other ports' subnet
self.ipfilters_manager.add_ippool(block_pname, block_subnets)
if self.agent_conf.allow_forwarding_between_networks:
self.ipfilters_manager.add_ippool(allow_pname, allow_subnets)
# now setup the IPF rules
rules = ['block in quick on %s from %s to pool/%d' %
(internal_dlname, port_subnet, block_pname)]
# pass in packets between networks that belong to same tenant
if self.agent_conf.allow_forwarding_between_networks:
rules.append('pass in quick on %s from %s to pool/%d' %
(internal_dlname, port_subnet, allow_pname))
# if the external gateway is already setup for the shared router,
# then we need to add Policy Based Routing (PBR) for this internal
# network
ex_gw_port = self.ex_gw_port
ex_gw_ip = (ex_gw_port['subnets'][0]['gateway_ip']
if ex_gw_port else None)
if ex_gw_ip:
external_dlname = self.get_external_device_name(ex_gw_port['id'])
rules.append('pass in on %s to %s:%s from any to !%s' %
(internal_dlname, external_dlname, ex_gw_ip,
port_subnet))
ipversion = netaddr.IPNetwork(port_subnet).version
self.ipfilters_manager.add_ipf_rules(rules, ipversion)
if self.agent_conf.enable_metadata_proxy and ipversion == 4:
rdr_rule = ['rdr %s 169.254.169.254/32 port 80 -> %s port %d tcp' %
(internal_dlname, port['fixed_ips'][0]['ip_address'],
self.agent_conf.metadata_port)]
self.ipfilters_manager.add_nat_rules(rdr_rule)
def internal_network_removed(self, port):
internal_dlname = self.get_internal_device_name(port['id'])
port_subnet = port['subnets'][0]['cidr']
# remove all the IP filter rules that we added during
# internal network addition
block_pname = self._get_ippool_name(port['mac_address'])
rules = ['block in quick on %s from %s to pool/%d' %
(internal_dlname, port_subnet, block_pname)]
if self.agent_conf.allow_forwarding_between_networks:
allow_pname = self._get_ippool_name(port['mac_address'], '0')
rules.append('pass in quick on %s from %s to pool/%d' %
(internal_dlname, port_subnet, allow_pname))
# remove all the IP filter rules that we added during
# external network addition
ex_gw_port = self.ex_gw_port
ex_gw_ip = (ex_gw_port['subnets'][0]['gateway_ip']
if ex_gw_port else None)
if ex_gw_ip:
external_dlname = self.get_external_device_name(ex_gw_port['id'])
rules.append('pass in on %s to %s:%s from any to !%s' %
(internal_dlname, external_dlname, ex_gw_ip,
port_subnet))
ipversion = netaddr.IPNetwork(port['subnets'][0]['cidr']).version
self.ipfilters_manager.remove_ipf_rules(rules, ipversion)
# remove the ippool
self.ipfilters_manager.remove_ippool(block_pname, None)
if self.agent_conf.allow_forwarding_between_networks:
self.ipfilters_manager.remove_ippool(allow_pname, None)
for internal_port in self.internal_ports:
if (self.agent_conf.allow_forwarding_between_networks and
internal_port['tenant_id'] == port['tenant_id']):
iport_allow_pname = \
self._get_ippool_name(internal_port['mac_address'], '0')
self.ipfilters_manager.remove_ippool(iport_allow_pname,
[port_subnet])
else:
iport_block_pname = \
self._get_ippool_name(internal_port['mac_address'])
self.ipfilters_manager.remove_ippool(iport_block_pname,
[port_subnet])
if self.agent_conf.enable_metadata_proxy and ipversion == 4:
rdr_rule = ['rdr %s 169.254.169.254/32 port 80 -> %s port %d tcp' %
(internal_dlname, port['fixed_ips'][0]['ip_address'],
self.agent_conf.metadata_port)]
self.ipfilters_manager.remove_nat_rules(rdr_rule)
if net_lib.Datalink.datalink_exists(internal_dlname):
self.driver.fini_l3(internal_dlname)
self.driver.unplug(internal_dlname)
def _process_internal_ports(self):
existing_port_ids = set([p['id'] for p in self.internal_ports])
internal_ports = self.router.get(l3_constants.INTERFACE_KEY, [])
current_port_ids = set([p['id'] for p in internal_ports
if p['admin_state_up']])
new_port_ids = current_port_ids - existing_port_ids
new_ports = [p for p in internal_ports if p['id'] in new_port_ids]
old_ports = [p for p in self.internal_ports if
p['id'] not in current_port_ids]
# updated_ports = self._get_updated_ports(self.internal_ports,
# internal_ports)
enable_ra = False
for p in new_ports:
self.internal_network_added(p)
self.internal_ports.append(p)
enable_ra = enable_ra or self._port_has_ipv6_subnet(p)
for p in old_ports:
self.internal_network_removed(p)
self.internal_ports.remove(p)
enable_ra = enable_ra or self._port_has_ipv6_subnet(p)
# if updated_ports:
# for index, p in enumerate(internal_ports):
# if not updated_ports.get(p['id']):
# continue
# self.internal_ports[index] = updated_ports[p['id']]
# interface_name = self.get_internal_device_name(p['id'])
# ip_cidrs = common_utils.fixed_ip_cidrs(p['fixed_ips'])
# self.driver.init_l3(interface_name, ip_cidrs=ip_cidrs,
# namespace=self.ns_name)
# enable_ra = enable_ra or self._port_has_ipv6_subnet(p)
# Enable RA
if enable_ra:
self.radvd.enable(internal_ports)
# remove any internal stale router interfaces (i.e., l3i.. VNICs)
existing_devices = self._get_existing_devices()
current_internal_devs = set(n for n in existing_devices
if n.startswith(INTERNAL_DEV_PREFIX))
current_port_devs = set(self.get_internal_device_name(port_id)
for port_id in current_port_ids)
stale_devs = current_internal_devs - current_port_devs
for stale_dev in stale_devs:
LOG.debug(_('Deleting stale internal router device: %s'),
stale_dev)
self.driver.fini_l3(stale_dev)
self.driver.unplug(stale_dev)
def _get_ippool_name(self, mac_address, suffix=None):
# Generate a unique-name for ippool(1m) from that last 3
# bytes of mac-address. It is called pool name, but it is
# actually a 32 bit integer
name = mac_address.split(':')[3:]
if suffix:
name.append(suffix)
return int("".join(name), 16)
def process_floating_ip_addresses(self, interface_name):
"""Configure IP addresses on router's external gateway interface.
Ensures addresses for existing floating IPs and cleans up
those that should not longer be configured.
"""
fip_statuses = {}
if interface_name is None:
LOG.debug('No Interface for floating IPs router: %s',
self.router['id'])
return fip_statuses
ipintf = net_lib.IPInterface(interface_name)
ipaddr_list = ipintf.ipaddr_list()['static']
existing_cidrs = set(ipaddr_list)
new_cidrs = set()
existing_nat_rules = [nat_rule for nat_rule in
self.ipfilters_manager.ipv4['nat']]
new_nat_rules = []
floating_ips = self.get_floating_ips()
# Loop once to ensure that floating ips are configured.
for fip in floating_ips:
fip_ip = fip['floating_ip_address']
fip_cidr = str(fip_ip) + FLOATING_IP_CIDR_SUFFIX
new_cidrs.add(fip_cidr)
fixed_cidr = str(fip['fixed_ip_address']) + '/32'
nat_rule = 'bimap %s %s -> %s' % (interface_name, fixed_cidr,
fip_cidr)
if fip_cidr not in existing_cidrs:
try:
ipintf.create_address(fip_cidr)
self.ipfilters_manager.add_nat_rules([nat_rule])
except Exception as err:
# TODO(gmoodalb): If we fail in add_nat_rules(), then
# we need to remove the fip_cidr address
# any exception occurred here should cause the floating IP
# to be set in error state
fip_statuses[fip['id']] = (
l3_constants.FLOATINGIP_STATUS_ERROR)
LOG.warn(_("Unable to configure IP address for "
"floating IP: %s: %s") % (fip['id'], err))
continue
fip_statuses[fip['id']] = (
l3_constants.FLOATINGIP_STATUS_ACTIVE)
LOG.debug("Floating ip %(id)s added, status %(status)s",
{'id': fip['id'],
'status': fip_statuses.get(fip['id'])})
new_nat_rules.append(nat_rule)
# remove all the old NAT rules
old_nat_rules = list(set(existing_nat_rules) - set(new_nat_rules))
# Filter out 'bimap' NAT rules as we don't want to remove NAT rules
# that were added for Metadata server
old_nat_rules = [rule for rule in old_nat_rules if "bimap" in rule]
self.ipfilters_manager.remove_nat_rules(old_nat_rules)
# Clean up addresses that no longer belong on the gateway interface.
for ip_cidr in existing_cidrs - new_cidrs:
if ip_cidr.endswith(FLOATING_IP_CIDR_SUFFIX):
ipintf.delete_address(ip_cidr)
return fip_statuses
# Todo(gmoodalb): need to do more work on ipv6 gateway
def external_gateway_added(self, ex_gw_port, external_dlname):
if not net_lib.Datalink.datalink_exists(external_dlname):
dl = net_lib.Datalink(external_dlname)
# determine the network type of the external network
evsname = ex_gw_port['network_id']
cmd = ['/usr/sbin/evsadm', 'show-evs', '-co', 'l2type,vid',
'-f', 'evs=%s' % evsname]
try:
stdout = utils.execute(cmd)
except Exception as err:
LOG.error(_("Failed to retrieve the network type for "
"the external network, and it is required "
"to create an external gateway port: %s") % err)
return
output = stdout.splitlines()[0].strip()
l2type, vid = output.split(':')
if l2type != 'flat' and l2type != 'vlan':
LOG.error(_("External network should be either Flat or "
"VLAN based, and it is required to "
"create an external gateway port"))
return
elif (l2type == 'vlan' and
self.agent_conf.get("external_network_datalink", None)):
LOG.warning(_("external_network_datalink is deprecated in "
"Juno and will be removed in the next release "
"of Solaris OpenStack. Please use the evsadm "
"set-controlprop subcommand to setup the "
"uplink-port for an external network"))
# proceed with the old-style of doing things
mac_address = ex_gw_port['mac_address']
dl.create_vnic(self.agent_conf.external_network_datalink,
mac_address=mac_address, vid=vid)
else:
self.driver.plug(ex_gw_port['tenant_id'],
ex_gw_port['network_id'],
ex_gw_port['id'], external_dlname)
ip_cidrs = common_utils.fixed_ip_cidrs(ex_gw_port['fixed_ips'])
self.driver.init_l3(external_dlname, ip_cidrs)
gw_ip = ex_gw_port['subnets'][0]['gateway_ip']
if gw_ip:
cmd = ['/usr/bin/pfexec', '/usr/sbin/route', 'add', 'default',
gw_ip]
stdout = utils.execute(cmd, extra_ok_codes=[errno.EEXIST])
if 'entry exists' not in stdout:
self.remove_route = True
# for each of the internal ports, add Policy Based
# Routing (PBR) rule
for port in self.internal_ports:
internal_dlname = self.get_internal_device_name(port['id'])
rules = ['pass in on %s to %s:%s from any to !%s' %
(internal_dlname, external_dlname, gw_ip,
port['subnets'][0]['cidr'])]
ipversion = \
netaddr.IPNetwork(port['subnets'][0]['cidr']).version
self.ipfilters_manager.add_ipf_rules(rules, ipversion)
def external_gateway_updated(self, ex_gw_port, external_dlname):
# There is nothing to do on Solaris
pass
def external_gateway_removed(self, ex_gw_port, external_dlname):
gw_ip = ex_gw_port['subnets'][0]['gateway_ip']
if gw_ip:
# remove PBR rules
for port in self.internal_ports:
internal_dlname = self.get_internal_device_name(port['id'])
rules = ['pass in on %s to %s:%s from any to !%s' %
(internal_dlname, external_dlname, gw_ip,
port['subnets'][0]['cidr'])]
ipversion = \
netaddr.IPNetwork(port['subnets'][0]['cidr']).version
self.ipfilters_manager.remove_ipf_rules(rules, ipversion)
if self.remove_route:
cmd = ['/usr/bin/pfexec', '/usr/sbin/route', 'delete',
'default', gw_ip]
utils.execute(cmd, check_exit_code=False)
if net_lib.Datalink.datalink_exists(external_dlname):
self.driver.fini_l3(external_dlname)
self.driver.unplug(external_dlname)
def _process_external_gateway(self, ex_gw_port):
# TODO(Carl) Refactor to clarify roles of ex_gw_port vs self.ex_gw_port
ex_gw_port_id = (ex_gw_port and ex_gw_port['id'] or
self.ex_gw_port and self.ex_gw_port['id'])
interface_name = None
if ex_gw_port_id:
interface_name = self.get_external_device_name(ex_gw_port_id)
if ex_gw_port:
def _gateway_ports_equal(port1, port2):
def _get_filtered_dict(d, ignore):
return dict((k, v) for k, v in d.iteritems()
if k not in ignore)
keys_to_ignore = set(['binding:host_id'])
port1_filtered = _get_filtered_dict(port1, keys_to_ignore)
port2_filtered = _get_filtered_dict(port2, keys_to_ignore)
return port1_filtered == port2_filtered
if not self.ex_gw_port:
self.external_gateway_added(ex_gw_port, interface_name)
elif not _gateway_ports_equal(ex_gw_port, self.ex_gw_port):
self.external_gateway_updated(ex_gw_port, interface_name)
elif not ex_gw_port and self.ex_gw_port:
self.external_gateway_removed(self.ex_gw_port, interface_name)
# Remove any external stale router interfaces (i.e., l3e.. VNICs)
existing_devices = self._get_existing_devices()
stale_devs = [dev for dev in existing_devices
if dev.startswith(EXTERNAL_DEV_PREFIX) and
dev != interface_name]
for stale_dev in stale_devs:
LOG.debug(_('Deleting stale external router device: %s'),
stale_dev)
self.driver.fini_l3(stale_dev)
self.driver.unplug(stale_dev)
# Process SNAT rules for external gateway
self.perform_snat_action(self._handle_router_snat_rules,
interface_name)
def external_gateway_snat_rules(self, ex_gw_ip, interface_name):
rules = []
ip_cidrs = []
for port in self.internal_ports:
if netaddr.IPNetwork(port['subnets'][0]['cidr']).version == 4:
ip_cidrs.extend(common_utils.fixed_ip_cidrs(port['fixed_ips']))
for ip_cidr in ip_cidrs:
rules.append('map %s %s -> %s/32' %
(interface_name, ip_cidr, ex_gw_ip))
return rules
def _handle_router_snat_rules(self, ex_gw_port, interface_name, action):
# Remove all the old SNAT rules
# This is safe because if use_namespaces is set as False
# then the agent can only configure one router, otherwise
# each router's SNAT rules will be in their own namespace
# get only the SNAT rules
old_snat_rules = [rule for rule in self.ipfilters_manager.ipv4['nat']
if rule.startswith('map')]
self.ipfilters_manager.remove_nat_rules(old_snat_rules)
# And add them back if the action is add_rules
if action == 'add_rules' and ex_gw_port:
# NAT rules are added only if ex_gw_port has an IPv4 address
for ip_addr in ex_gw_port['fixed_ips']:
ex_gw_ip = ip_addr['ip_address']
if netaddr.IPAddress(ex_gw_ip).version == 4:
rules = self.external_gateway_snat_rules(ex_gw_ip,
interface_name)
self.ipfilters_manager.add_nat_rules(rules)
break
def process_external(self, agent):
existing_floating_ips = self.floating_ips
try:
ex_gw_port = self.get_ex_gw_port()
self._process_external_gateway(ex_gw_port)
# TODO(Carl) Return after setting existing_floating_ips and
# still call update_fip_statuses?
if not ex_gw_port:
return
# Once NAT rules for floating IPs are safely in place
# configure their addresses on the external gateway port
interface_name = self.get_external_device_name(ex_gw_port['id'])
fip_statuses = self.configure_fip_addresses(interface_name)
except (n_exc.FloatingIpSetupException,
n_exc.IpTablesApplyException) as e:
# All floating IPs must be put in error state
LOG.exception(e)
fip_statuses = self.put_fips_in_error_state()
agent.update_fip_statuses(self, existing_floating_ips, fip_statuses)
class EVSL3NATAgent(l3_agent.L3NATAgentWithStateReport):
OPTS = [
cfg.StrOpt('external_network_datalink', default='net0',
help=_("Name of the datalink that connects to "
"an external network.")),
cfg.BoolOpt('allow_forwarding_between_networks', default=False,
help=_("Allow forwarding of packets between tenant's "
"networks")),
]
def __init__(self, host, conf=None):
cfg.CONF.register_opts(self.OPTS)
cfg.CONF.register_opts(interface.OPTS)
super(EVSL3NATAgent, self).__init__(host=host, conf=conf)
cfg.CONF.register_opts(neutron_vpnaas.vpn_agent_opts, 'vpnagent')
self.service = vpn_service.VPNService(self)
self.device_drivers = self.service.load_device_drivers(host)
def _router_added(self, router_id, router):
args = []
kwargs = {
'router_id': router_id,
'router': router,
'use_ipv6': self.use_ipv6,
'agent_conf': self.conf,
'interface_driver': self.driver,
}
ri = SolarisRouterInfo(*args, **kwargs)
registry.notify(resources.ROUTER, events.BEFORE_CREATE,
self, router=ri)
self.router_info[router_id] = ri
ri.initialize(self.process_monitor)