def __init__(self, config_file=None):
     self.conf = NECConfig(config_file)
     self.ofn = OFNetwork(self.conf.OFC_HOST, self.conf.OFC_PORT)
     ndb.initialize(self.conf)
     if self.conf.vif_file:
         vifinfo_list = self.conf.load_vifinfo(self.conf.vif_file)
         for vifinfo in vifinfo_list:
             old_vifinfo = ndb.get_vifinfo(vifinfo['interface_id'])
             if old_vifinfo:
                 LOG.info("Delete old vifinfo %s." % old_vifinfo)
                 ndb.del_vifinfo(vifinfo['interface_id'])
             ndb.add_vifinfo(vifinfo['interface_id'],
                             vifinfo['datapath_id'],
                             vifinfo['port_no'],
                             vifinfo['vlan_id'])
class NECPlugin(QuantumPluginBase):
    """The Quantum NEC Plug-in controls an OpenFlow Controller.

    The Quantum NEC Plug-in maps L2 logical networks to L2 virtualized networks
    on an OpenFlow enabled network.  An OpenFlow Controller (OFC) provides
    L2 network isolation without VLAN and this plugin controls the OFC.

    :param tenant_id:       Logical Tenant ID on Quantum
    :param network_id:      Logical Network ID on Quantum
    :param port_id:         Logical Port ID on Quantum
    :param ofn_tenant_id:   Virtual Tenant ID on OFC
    :param ofn_network_id:  Virtual Network ID on OFC
    :param ofn_port_id:     Virtual Port ID on OFC
    :param vifinfo:         Virtual Interface Information in the domain of OFC

    The IDs like ofn_* could be generated by NEC Plug-in or OFC.
    It is depends on an implementation of OFC,
    and users must configure NEC Plug-in which generate these IDs.
    """

    def __init__(self, config_file=None):
        self.conf = NECConfig(config_file)
        self.ofn = OFNetwork(self.conf.OFC_HOST, self.conf.OFC_PORT)
        ndb.initialize(self.conf)
        if self.conf.vif_file:
            vifinfo_list = self.conf.load_vifinfo(self.conf.vif_file)
            for vifinfo in vifinfo_list:
                old_vifinfo = ndb.get_vifinfo(vifinfo['interface_id'])
                if old_vifinfo:
                    LOG.info("Delete old vifinfo %s." % old_vifinfo)
                    ndb.del_vifinfo(vifinfo['interface_id'])
                ndb.add_vifinfo(vifinfo['interface_id'],
                                vifinfo['datapath_id'],
                                vifinfo['port_no'],
                                vifinfo['vlan_id'])

    def _create_ofn_tenant(self, tenant_id):
        ofn_tenant = ndb.get_ofn_tenant(tenant_id)
        if ofn_tenant:
            ofn_tenant_id = ofn_tenant.ofn_tenant_id
        else:
            if self.conf.auto_id_tenant:
                """get ofn_tenant_id from OFN."""
                res = self.ofn.ofn_create_tenant(tenant_id)
                ofn_tenant_id = res['id']
                LOG.debug("_create_ofn_tenant(): "
                          "ofn_create_tenant() return '%s'" % res)
            else:
                ofn_tenant_id = tenant_id
                """
                Don't POST it to OFC, because Sliceable DO NOT handle tenant.
                """
            LOG.debug("_create_ofn_tenant(): create new ofn_tenant %s"
                      "for tenant %s." % (tenant_id, ofn_tenant_id))
            ndb.add_ofn_tenant(ofn_tenant_id, tenant_id)
        return ofn_tenant_id

    def _get_ofn_tenant_id(self, tenant_id):
        ofn_tenant = ndb.get_ofn_tenant(tenant_id)
        if not ofn_tenant:
            LOG.warning("_get_ofn_tenant_id(): ofn_tenant not found "
                        "(tenant_id = %s)" % tenant_id)
            raise h_exc.HTTPInternalServerError(\
              "NotFound ofn_tenant_id for tenant_id %s." % tenant_id)
        return ofn_tenant.ofn_tenant_id

    def _get_ofn_network_id(self, network_id):
        ofn_network = ndb.get_ofn_network(network_id)
        if not ofn_network:
            LOG.warning("_get_ofn_network_id(): ofn_network not found "
                        "(network_id = %s)" % network_id)
            raise h_exc.HTTPInternalServerError(\
              "NotFound ofn_network_id for network_id %s." % network_id)
        return ofn_network.ofn_network_id

    def _get_ofn_port_id(self, port_id):
        ofn_port = ndb.get_ofn_port(port_id)
        if not ofn_port:
            LOG.warning("_get_ofn_port_id(): ofn_port not found "
                        "(port_id = %s)" % port_id)
            raise h_exc.HTTPInternalServerError(\
              "NotFound ofn_port_id for port_id %s." % port_id)
        return ofn_port.ofn_port_id

    def _get_network(self, tenant_id, network_id):
        network = db.network_get(network_id)
        # Network must exist and belong to the appropriate tenant.
        if network.tenant_id != tenant_id:
            LOG.warning("_get_network(): mismatch tenant_id = %s, "
                        "network_id = %s, network.tenant_id = %s" %
                        (tenant_id, network_id, network.tenant_id))
            raise exc.NetworkNotFound(net_id=network_id)
        return network

    def _get_port(self, tenant_id, network_id, port_id):
        network = self._get_network(tenant_id, network_id)
        port = db.port_get(port_id, network_id)
        # Port must exist and belong to the appropriate network.
        if port.network_id != network_id:
            LOG.warning("_get_port(): mismatch network_id = %s, "
                        "port_id = %s, port.network_id = %s" %
                        (network_id, port_id, port.network_id))
            raise exc.PortNotFound(net_id=network_id, port_id=port_id)
        return port

    def _validate_port_state(self, port_state):
        if port_state.upper() not in ("ACTIVE", "DOWN"):
            raise exc.StateInvalid(port_state=port_state)
        return True

    def _port_attachable(self, port):
        if not port:
            return False
        if not port.interface_id:
            return False
        if not port.state.upper() in "ACTIVE":
            return False
        if not ndb.get_vifinfo(port.interface_id):
            return False
        return True

    def _attach(self, tenant_id, network_id, port_id, interface_id):
        LOG.debug("_attach(): called")
        ofn_tenant_id = self._get_ofn_tenant_id(tenant_id)
        ofn_network_id = self._get_ofn_network_id(network_id)
        vifinfo = ndb.get_vifinfo(interface_id)

        if self.conf.auto_id_port:
            """id include response."""
            res = self.ofn.ofn_create_port(ofn_tenant_id,
                                           ofn_network_id,
                                           vifinfo.datapath_id,
                                           str(vifinfo.port_no),
                                           str(vifinfo.vlan_id))
            ofn_port_id = res['id']
        else:
            """use uuid for ofn_network."""
            ofn_port_id = port_id
            res = self.ofn.ofn_create_port(ofn_tenant_id,
                                           ofn_network_id,
                                           vifinfo.datapath_id,
                                           str(vifinfo.port_no),
                                           str(vifinfo.vlan_id),
                                           ofn_port_id)
        LOG.debug("_attach(): ofn_create_port() return '%s'" % res)
        LOG.debug("_attach(): ofn_port_id = %s" % ofn_port_id)
        ndb.add_ofn_port(ofn_port_id, port_id)

    def _detach(self, tenant_id, network_id, port_id):
        LOG.debug("_detach(): called")
        ofn_tenant_id = self._get_ofn_tenant_id(tenant_id)
        ofn_network_id = self._get_ofn_network_id(network_id)
        ofn_port_id = self._get_ofn_port_id(port_id)
        res = self.ofn.ofn_delete_port(ofn_tenant_id,
                                       ofn_network_id,
                                       ofn_port_id)
        LOG.debug("_detach(): ofn_delete_port() return '%s'" % res)
        ndb.del_ofn_port(port_id)

    def get_all_networks(self, tenant_id):
        """
        Returns a dictionary containing all
        <network_uuid, network_name> for
        the specified tenant.
        """
        LOG.debug("get_all_networks() called")
        networks = []
        for network in db.network_list(tenant_id):
            network_item = {'net-id': network.uuid, 'net-name': network.name}
            networks.append(network_item)
        return networks

    def get_network_details(self, tenant_id, network_id):
        """
        retrieved a list of all the remote vifs that
        are attached to the network
        """
        LOG.debug("get_network_details() called")
        network = self._get_network(tenant_id, network_id)
        # Retrieves ports for network
        ports = self.get_all_ports(tenant_id, network_id)
        return {'net-id': network.uuid,
                'net-name': network.name,
                'net-ports': ports}

    def create_network(self, tenant_id, network_name):
        """
        Creates a new Virtual Network, and assigns it
        a symbolic name.
        """
        LOG.debug("create_network() called")
        ofn_tenant_id = self._create_ofn_tenant(tenant_id)
        new_network = db.network_create(tenant_id, network_name)

        if self.conf.auto_id_network:
            """Auto ID is ture. id include response."""
            res = self.ofn.ofn_create_network(ofn_tenant_id, network_name)
            ofn_network_id = res['id']
        else:
            """Auto ID is false. use uuid for ofn_network."""
            ofn_network_id = new_network.uuid
            res = self.ofn.ofn_create_network(ofn_tenant_id,
                                              network_name,
                                              ofn_network_id)

        LOG.debug("create_network(): ofn_create_network() return '%s'" % res)
        LOG.debug("create_network(): ofn_network_id = %s" % ofn_network_id)
        ndb.add_ofn_network(ofn_network_id, new_network.uuid)
        return {'net-id': new_network.uuid, 'net-name': new_network.name}

    def delete_network(self, tenant_id, network_id):
        """
        Deletes the network with the specified network identifier
        belonging to the specified tenant.
        """
        LOG.debug("delete_network() called")
        network = self._get_network(tenant_id, network_id)
        # Verify that the network has no port
        for port in db.port_list(network_id):
            if port:
                raise exc.NetworkInUse(network_id=network_id)

        ofn_tenant_id = self._get_ofn_tenant_id(tenant_id)
        ofn_network_id = self._get_ofn_network_id(network_id)
        self.ofn.ofn_delete_network(ofn_tenant_id, ofn_network_id)
        ndb.del_ofn_network(network_id)
        db.network_destroy(network_id)
        return {'net-id': network.uuid}

    def rename_network(self, tenant_id, network_id, new_name):
        """
        Updates the symbolic name belonging to a particular
        Virtual Network.
        """
        LOG.debug("rename_network() called")
        # verify network_id
        self._get_network(tenant_id, network_id)
        network = db.network_rename(network_id, tenant_id, new_name)
        ofn_tenant_id = self._get_ofn_tenant_id(tenant_id)
        ofn_network_id = self._get_ofn_network_id(network_id)
        res = self.ofn.ofn_rename_network(ofn_tenant_id,
                                          ofn_network_id,
                                          new_name)
        LOG.debug("rename_network(): ofn_rename_network() return '%s'" % res)
        return {'net-id': network.uuid, 'net-name': network.name}

    def get_all_ports(self, tenant_id, network_id):
        """
        Retrieves all port identifiers belonging to the
        specified Virtual Network.
        """
        LOG.debug("get_all_ports() called")
        # verify network_id
        self._get_network(tenant_id, network_id)
        ports = db.port_list(network_id)
        port_ids = []
        for x in ports:
            port_id = {'port-id': x.uuid}
            port_ids.append(port_id)
        return port_ids

    def get_port_details(self, tenant_id, network_id, port_id):
        """
        This method allows the user to retrieve a remote interface
        that is attached to this particular port.
        """
        LOG.debug("get_port_details() called")
        port = self._get_port(tenant_id, network_id, port_id)
        return {'port-id': port.uuid,
                'net-id': port.network_id,
                'attachment': port.interface_id,
                'port-state': port.state}

    def create_port(self, tenant_id, network_id, port_state=None):
        """
        Creates a port on the specified Virtual Network.
        """
        LOG.debug("create_port() called")
        # verify network_id
        self._get_network(tenant_id, network_id)
        port_state_up = None
        if port_state:
            self._validate_port_state(port_state)
            port_state_up = port_state.upper()
        port = db.port_create(network_id, port_state_up)
        LOG.debug("create_port(): port state is %s" % port.state)
        return {'port-id': port.uuid}

    def update_port(self, tenant_id, network_id, port_id, new_state):
        """
        Updates the state of a port on the specified Virtual Network.
        """
        LOG.debug("update_port() called")
        port = self._get_port(tenant_id, network_id, port_id)
        self._validate_port_state(new_state)
        new_state_up = new_state.upper()
        old_state_up = port.state.upper()
        if old_state_up == new_state_up:
            LOG.debug("update_port(): port state was not changed.")
            return {'port-id': port.uuid, 'port-state': port.state}
        if new_state_up in "DOWN":
            if self._port_attachable(port):
                self._detach(tenant_id, network_id, port_id)
        port = db.port_set_state(port_id, network_id, new_state_up)
        if new_state_up in "ACTIVE":
            if self._port_attachable(port):
                self._attach(tenant_id, network_id, port_id, port.interface_id)
        return {'port-id': port.uuid, 'port-state': port.state}

    def delete_port(self, tenant_id, network_id, port_id):
        """
        Deletes a port on a specified Virtual Network,
        if the port contains a remote interface attachment,
        the remote interface is first un-plugged and then the port
        is deleted.
        """
        LOG.debug("delete_port() called")
        port = self._get_port(tenant_id, network_id, port_id)
        if port.interface_id:
            raise exc.PortInUse(net_id=network_id,
                                port_id=port_id,
                                att_id=port.interface_id)
        db.port_destroy(port_id, network_id)
        return {'port-id': port.uuid}

    def plug_interface(self, tenant_id, network_id, port_id, interface_id):
        """
        Attaches a remote interface to the specified port on the
        specified Virtual Network.
        """
        LOG.debug("plug_interface() called")
        port = self._get_port(tenant_id, network_id, port_id)

        # Validate attachment
        if port.interface_id:
            raise exc.PortInUse(net_id=network_id,
                                port_id=port_id,
                                att_id=port.interface_id)
        p = dbe.get_plugged_port(interface_id)
        if p:
            raise exc.AlreadyAttached(net_id=network_id,
                                      port_id=port_id,
                                      att_id=interface_id,
                                      att_port_id=p.uuid)

        db.port_set_attachment(port_id, network_id, interface_id)
        if self._port_attachable(port):
            self._attach(tenant_id, network_id, port_id, interface_id)

    def unplug_interface(self, tenant_id, network_id, port_id):
        """
        Detaches a remote interface from the specified port on the
        specified Virtual Network.
        """
        LOG.debug("unplug_interface() called")
        port = self._get_port(tenant_id, network_id, port_id)
        if self._port_attachable(port):
            self._detach(tenant_id, network_id, port_id)
        db.port_unset_attachment(port_id, network_id)

    supported_extension_aliases = ["VIFINFOS"]

    def get_vifinfo(self, interface_id):
        LOG.debug("get_vifinfo() called")
        vifinfo = ndb.get_vifinfo(interface_id)
        if not vifinfo:
            return None
        return {'vifinfo': {
                  'interface_id': vifinfo.interface_id,
                   'ofs_port': {'datapath_id': vifinfo.datapath_id,
                                'port_no': str(vifinfo.port_no)}}}

    def list_vifinfos(self):
        LOG.debug("list_vifinfos() called")
        vifs = ndb.list_vifinfos()
        id_list = [{'interface_id': vif.interface_id} for vif in vifs]
        return {'vifinfos': id_list}

    def add_vifinfo(self, interface_id, datapath_id, port_no, vlan_id=65535):
        LOG.debug("add_vifinfo() called")
        ndb.add_vifinfo(interface_id, datapath_id, port_no, vlan_id)
        port = dbe.get_plugged_port(interface_id)
        if self._port_attachable(port):
            network = db.network_get(port.network_id)
            self._attach(network.tenant_id, network.uuid, port.uuid,
                         interface_id)

    def delete_vifinfo(self, interface_id):
        LOG.debug("delete_vifinfo() called")
        port = dbe.get_plugged_port(interface_id)
        if self._port_attachable(port):
            network = db.network_get(port.network_id)
            self._detach(network.tenant_id, network.uuid, port.uuid)
        ndb.del_vifinfo(interface_id)