components/openstack/neutron/files/agent/solaris/interface.py
changeset 6848 8e252a37ed0d
parent 6555 321727f908b3
child 7178 5dc920725250
--- a/components/openstack/neutron/files/agent/solaris/interface.py	Wed Sep 07 14:48:41 2016 -0700
+++ b/components/openstack/neutron/files/agent/solaris/interface.py	Wed Sep 07 14:48:41 2016 -0700
@@ -15,9 +15,6 @@
 # @author: Girish Moodalbail, Oracle, Inc.
 
 from openstack_common import get_ovsdb_info
-import rad.client as radcli
-import rad.connect as radcon
-import rad.bindings.com.oracle.solaris.rad.evscntl_1 as evsbind
 
 from oslo_config import cfg
 from oslo_log import log as logging
@@ -33,23 +30,32 @@
 LOG = logging.getLogger(__name__)
 
 OPTS = [
-    cfg.StrOpt('evs_controller', default='ssh://evsuser@localhost',
-               help=_("An URI that specifies an EVS controller"))
+    cfg.StrOpt('admin_user',
+               help=_("Admin username")),
+    cfg.StrOpt('admin_password',
+               help=_("Admin password"),
+               secret=True),
+    cfg.StrOpt('admin_tenant_name',
+               help=_("Admin tenant name")),
+    cfg.StrOpt('auth_url',
+               help=_("Authentication URL")),
+    cfg.StrOpt('auth_strategy', default='keystone',
+               help=_("The type of authentication to use")),
+    cfg.StrOpt('auth_region',
+               help=_("Authentication region")),
+    cfg.StrOpt('endpoint_type',
+               default='publicURL',
+               help=_("Network service endpoint type to pull from "
+                      "the keystone catalog")),
 ]
 
 
-class EVSControllerError(exceptions.NeutronException):
-    message = _("EVS controller: %(errmsg)s")
-
-    def __init__(self, evs_errmsg):
-        super(EVSControllerError, self).__init__(errmsg=evs_errmsg)
+class OVSInterfaceDriver(object):
+    """Driver used to manage Solaris OVS VNICs.
 
-
-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.
+    This class provides methods to create/delete a Crossbow VNIC and
+    add it as a port of OVS bridge.
+    TODO(gmoodalb): More methods to implement here for MITAKA??
     """
 
     # TODO(gmoodalb): dnsmasq uses old style `ifreq', so 16 is the maximum
@@ -63,32 +69,23 @@
 
     def __init__(self, conf):
         self.conf = conf
-        try:
-            self.rad_uri = radcon.RadURI(conf.evs_controller)
-        except ValueError as err:
-            raise SystemExit(_("Specified evs_controller is invalid: %s"), err)
-
-        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)
+        self._neutron_client = None
 
     @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") %
-                  self.conf.evs_controller)
-
-        self._rad_connection = self.rad_uri.connect()
-        return self._rad_connection
+    def neutron_client(self):
+        if self._neutron_client:
+            return self._neutron_client
+        from neutronclient.v2_0 import client
+        self._neutron_client = client.Client(
+            username=self.conf.admin_user,
+            password=self.conf.admin_password,
+            tenant_name=self.conf.admin_tenant_name,
+            auth_url=self.conf.auth_url,
+            auth_strategy=self.conf.auth_strategy,
+            region_name=self.conf.auth_region,
+            endpoint_type=self.conf.endpoint_type
+        )
+        return self._neutron_client
 
     def fini_l3(self, device_name):
         ipif = net_lib.IPInterface(device_name)
@@ -113,120 +110,7 @@
 
     def plug(self, tenant_id, network_id, port_id, datalink_name, mac_address,
              network=None, bridge=None, namespace=None, prefix=None,
-             protection=False, vif_type=None):
-        """Plug in the interface."""
-
-        if net_lib.Datalink.datalink_exists(datalink_name):
-            LOG.info(_("Device %s already exists"), datalink_name)
-            return
-
-        if datalink_name.startswith('l3e'):
-            # verify external network parameter settings
-            dl = net_lib.Datalink(datalink_name)
-            # determine the network type of the external network
-            # TODO(gmoodalb): use EVS RAD APIs
-            evsname = 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.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
-                dl.create_vnic(self.conf.external_network_datalink,
-                               mac_address=mac_address, vid=vid)
-                return
-
-        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)
-
-        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()
-
-
-class OVSInterfaceDriver(SolarisVNICDriver):
-    """Driver used to manage Solaris OVS VNICs.
-
-    This class provides methods to create/delete a Crossbow VNIC and
-    add it as a port of OVS bridge.
-    """
-
-    def __init__(self, conf):
-        self.conf = conf
-        self._neutron_client = None
-
-    @property
-    def neutron_client(self):
-        if self._neutron_client:
-            return self._neutron_client
-        from neutronclient.v2_0 import client
-        self._neutron_client = client.Client(
-            username=self.conf.admin_user,
-            password=self.conf.admin_password,
-            tenant_name=self.conf.admin_tenant_name,
-            auth_url=self.conf.auth_url,
-            auth_strategy=self.conf.auth_strategy,
-            region_name=self.conf.auth_region,
-            endpoint_type=self.conf.endpoint_type
-        )
-        return self._neutron_client
-
-    def plug(self, tenant_id, network_id, port_id, datalink_name, mac_address,
-             network=None, bridge=None, namespace=None, prefix=None,
-             protection=False, vif_type=None):
+             protection=False, mtu=None, vif_type=None):
         """Plug in the interface."""
 
         if net_lib.Datalink.datalink_exists(datalink_name):
@@ -312,6 +196,10 @@
     def unplug(self, datalink_name, bridge=None, namespace=None, prefix=None):
         """Unplug the interface."""
 
+        # remove any IP addresses on top of this datalink, otherwise we will
+        # get 'device busy' error while deleting the datalink
+        self.fini_l3(datalink_name)
+
         dl = net_lib.Datalink(datalink_name)
         dl.delete_vnic()
 
@@ -329,3 +217,43 @@
         except RuntimeError as err:
             LOG.error(_("Failed unplugging interface '%s': %s") %
                       (datalink_name, err))
+
+    @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