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
# Copyright (c) 2013, 2015, 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.
#
# @author: Girish Moodalbail, Oracle, Inc.
import rad.bindings.com.oracle.solaris.rad.evscntl_1 as evsbind
import rad.client as radcli
import rad.connect as radcon
from oslo.config import cfg
from neutron.agent.linux import utils
from neutron.agent.solaris import net_lib
from neutron.common import exceptions
from neutron.openstack.common import log as logging
LOG = logging.getLogger(__name__)
OPTS = [
cfg.StrOpt('evs_controller', default='ssh://evsuser@localhost',
help=_("An URI that specifies an EVS controller"))
]
class EVSControllerError(exceptions.NeutronException):
message = _("EVS controller: %(errmsg)s")
def __init__(self, evs_errmsg):
super(EVSControllerError, self).__init__(errmsg=evs_errmsg)
class SolarisVNICDriver(object):
"""Driver used to manage Solaris EVS VNICs.
This class provides methods to create/delete an EVS VNIC and
plumb/unplumb ab IP interface and addresses on the EVS VNIC.
"""
# TODO(gmoodalb): dnsmasq uses old style `ifreq', so 16 is the maximum
# length including the NUL character. If we change it to use new style
# `lifreq', then we will be able to extend the length to 32 characters.
VNIC_NAME_MAXLEN = 15
VNIC_NAME_PREFIX = 'dh'
VNIC_NAME_SUFFIX = '_0'
VNIC_NAME_LEN_WO_SUFFIX = VNIC_NAME_MAXLEN - \
len(VNIC_NAME_SUFFIX)
def __init__(self, conf):
self.conf = conf
# Since there is no connect_uri() yet, we need to do this ourselves
# parse ssh://user@hostname
suh = self.conf.evs_controller.split('://')
if len(suh) != 2 or suh[0] != 'ssh' or not suh[1].strip():
raise SystemExit(_("Specified evs_controller is invalid"))
uh = suh[1].split('@')
if len(uh) != 2 or not uh[0].strip() or not uh[1].strip():
raise SystemExit(_("'user' and 'hostname' need to be specified "
"for evs_controller"))
# save the user and EVS controller info
self.uh = uh
self._rad_connection = None
# set the controller property for this host
cmd = ['/usr/sbin/evsadm', 'show-prop', '-co', 'value', '-p',
'controller']
stdout = utils.execute(cmd)
if conf.evs_controller != stdout.strip():
cmd = ['/usr/sbin/evsadm', 'set-prop', '-p',
'controller=%s' % (conf.evs_controller)]
utils.execute(cmd)
@property
def rad_connection(self):
if (self._rad_connection is not None and
self._rad_connection._closed is None):
return self._rad_connection
LOG.debug(_("Connecting to EVS Controller at %s as %s") %
(self.uh[1], self.uh[0]))
self._rad_connection = radcon.connect_ssh(self.uh[1], user=self.uh[0])
return self._rad_connection
def fini_l3(self, device_name):
ipif = net_lib.IPInterface(device_name)
ipif.delete_ip()
def init_l3(self, device_name, ip_cidrs, addrconf=False):
"""Set the L3 settings for the interface using data from the port.
ip_cidrs: list of 'X.X.X.X/YY' strings
"""
ipif = net_lib.IPInterface(device_name)
for ip_cidr in ip_cidrs:
ipif.create_address(ip_cidr)
if addrconf:
ipif.create_addrconf()
# TODO(gmoodalb): - probably take PREFIX?? for L3
def get_device_name(self, port):
vnicname = (self.VNIC_NAME_PREFIX +
port.id)[:self.VNIC_NAME_LEN_WO_SUFFIX]
vnicname += self.VNIC_NAME_SUFFIX
return vnicname.replace('-', '_')
def plug(self, tenant_id, network_id, port_id, datalink_name,
namespace=None, prefix=None, protection=False):
"""Plug in the interface."""
try:
evsc = self.rad_connection.get_object(evsbind.EVSController())
vports_info = evsc.getVPortInfo("vport=%s" % (port_id))
if vports_info:
vport_info = vports_info[0]
# This is to handle HA when the 1st DHCP/L3 agent is down and
# the second DHCP/L3 agent tries to connect its VNIC to EVS, we
# will end up in "vport in use" error. So, we need to reset the
# vport before we connect the VNIC to EVS.
if vport_info.status == evsbind.VPortStatus.USED:
LOG.debug(_("Retrieving EVS: %s"), vport_info.evsuuid)
pat = radcli.ADRGlobPattern({'uuid': network_id,
'tenant': tenant_id})
evs_objs = self.rad_connection.list_objects(evsbind.EVS(),
pat)
if evs_objs:
evs = self.rad_connection.get_object(evs_objs[0])
evs.resetVPort(port_id, "force=yes")
if not protection:
LOG.debug(_("Retrieving VPort: %s"), port_id)
pat = radcli.ADRGlobPattern({'uuid': port_id,
'tenant': tenant_id,
'evsuuid': network_id})
vport_objs = self.rad_connection.list_objects(
evsbind.VPort(), pat)
if vport_objs:
vport = self.rad_connection.get_object(vport_objs[0])
vport.setProperty("protection=none")
except radcli.ObjectError as oe:
raise EVSControllerError(oe.get_payload().errmsg)
finally:
self.rad_connection.close()
dl = net_lib.Datalink(datalink_name)
evs_vport = "%s/%s" % (network_id, port_id)
dl.connect_vnic(evs_vport, tenant_id)
def unplug(self, device_name, namespace=None, prefix=None):
"""Unplug the interface."""
dl = net_lib.Datalink(device_name)
dl.delete_vnic()