def treat_devices_added_or_updated(self, devices, check_ports):
        resync = False
        all_ports = dict((p.normalized_port_name(), p) for p in self._get_ports(self.int_br) if p.is_neutron_port())
        for device in devices:
            LOG.debug("Processing port %s", device)
            if device not in all_ports:
                # The port has disappeared and should not be processed
                # There is no need to put the port DOWN in the plugin as
                # it never went up in the first place
                LOG.info(
                    _LI("Port %s was not found on the integration bridge " "and will therefore not be processed"),
                    device,
                )
                continue
            port = all_ports[device]
            try:
                details = self.plugin_rpc.get_device_details(self.context, device, self.agent_id)
            except Exception as e:
                LOG.debug("Unable to get port details for %(device)s: %(e)s", {"device": device, "e": e})
                resync = True
                continue
            if device in check_ports:
                ps = check_ports[device]
                if port.ofport != ps.port.ofport:
                    ps.port.vif_mac = details.get("mac_address")
                    LOG.debug(
                        "Repair ofport changed old port " "ofport: %(ofport)s vif_mac: %(mac)s",
                        {"ofport": ps.port.ofport, "mac": ps.port.vif_mac},
                    )
                    LOG.debug(
                        "Repair ofport changed new port " "ofport: %(ofport)s vif_mac: %(mac)s",
                        {"ofport": port.ofport, "mac": port.vif_mac},
                    )
                    self._repair_ofport_change(ps.port, details["network_id"])
            if "port_id" in details:
                LOG.info(_LI("Port %(device)s updated. Details: %(details)s"), {"device": device, "details": details})
                port.vif_mac = details.get("mac_address")
                self.treat_vif_port(
                    port,
                    details["port_id"],
                    details["network_id"],
                    details["network_type"],
                    details["physical_network"],
                    details["segmentation_id"],
                    details["admin_state_up"],
                )

                # update plugin about port status
                if details.get("admin_state_up"):
                    LOG.debug("Setting status for %s to UP", device)
                    self.plugin_rpc.update_device_up(self.context, device, self.agent_id, cfg.CONF.host)
                else:
                    LOG.debug("Setting status for %s to DOWN", device)
                    self.plugin_rpc.update_device_down(self.context, device, self.agent_id, cfg.CONF.host)
                LOG.info(_LI("Configuration for device %s completed."), device)
            else:
                LOG.warn(_LW("Device %s not defined on plugin"), device)
                if port and port.ofport != -1:
                    self.port_dead(port)
        return resync
    def treat_devices_added_or_updated(self, devices):
        resync = False
        all_ports = dict((p.normalized_port_name(), p)
                         for p in self._get_ports(self.int_br)
                         if p.is_neutron_port())
        for device in devices:
            LOG.debug("Processing port %s", device)
            if device not in all_ports:
                # The port has disappeared and should not be processed
                # There is no need to put the port DOWN in the plugin as
                # it never went up in the first place
                LOG.info(
                    _LI("Port %s was not found on the integration bridge "
                        "and will therefore not be processed"), device)
                continue
            port = all_ports[device]
            try:
                details = self.plugin_rpc.get_device_details(
                    self.context, device, self.agent_id)
            except Exception as e:
                LOG.debug("Unable to get port details for %(device)s: %(e)s", {
                    'device': device,
                    'e': e
                })
                resync = True
                continue
            if 'port_id' in details:
                LOG.info(_LI("Port %(device)s updated. Details: %(details)s"),
                         {
                             'device': device,
                             'details': details
                         })
                port.vif_mac = details.get('mac_address')
                self.treat_vif_port(port, details['port_id'],
                                    details['network_id'],
                                    details['network_type'],
                                    details['physical_network'],
                                    details['segmentation_id'],
                                    details['admin_state_up'])

                # update plugin about port status
                if details.get('admin_state_up'):
                    LOG.debug("Setting status for %s to UP", device)
                    self.plugin_rpc.update_device_up(self.context, device,
                                                     self.agent_id,
                                                     cfg.CONF.host)
                else:
                    LOG.debug("Setting status for %s to DOWN", device)
                    self.plugin_rpc.update_device_down(self.context, device,
                                                       self.agent_id,
                                                       cfg.CONF.host)
                LOG.info(_LI("Configuration for device %s completed."), device)
            else:
                LOG.warn(_LW("Device %s not defined on plugin"), device)
                if (port and port.ofport != -1):
                    self.port_dead(port)
        return resync
    def port_unbound(self, vif_id, net_uuid=None):
        """Unbind port.

        Removes corresponding local vlan mapping object if this is its last
        VIF.

        :param vif_id: the id of the vif
        :param net_uuid: the net_uuid this port is associated with.
        """
        net_uuid = net_uuid or self.get_net_uuid(vif_id)

        if not self.local_vlan_map.get(net_uuid):
            LOG.info(_LI('port_unbound() net_uuid %s not in local_vlan_map'),
                     net_uuid)
            return

        lvm = self.local_vlan_map[net_uuid]
        port = lvm.vif_ports.pop(vif_id, None)

        self.int_br.check_in_port_delete_port(port.ofport)
        if not lvm.vif_ports:
            self.reclaim_local_vlan(net_uuid)
        if port.vif_mac is None:
            return
        self.int_br.local_out_delete_port(lvm.vlan, port.vif_mac)
    def reclaim_local_vlan(self, net_uuid):
        """Reclaim a local VLAN.

        :param net_uuid: the network uuid associated with this vlan.
        :param lvm: a LocalVLANMapping object that tracks (vlan, lsw_id,
            vif_ids) mapping.
        """
        lvm = self.local_vlan_map.pop(net_uuid, None)
        if lvm is None:
            LOG.debug("Network %s not used on agent.", net_uuid)
            return

        LOG.info(_LI("Reclaiming vlan = %(vlan_id)s from "
                     "net-id = %(net_uuid)s"),
                 {'vlan_id': lvm.vlan,
                  'net_uuid': net_uuid})

        if lvm.network_type in constants.TUNNEL_NETWORK_TYPES:
            if self.enable_tunneling:
                self.int_br.reclaim_tenant_tunnel(lvm.network_type, lvm.vlan,
                                                  lvm.segmentation_id)
        elif lvm.network_type in [p_const.TYPE_FLAT, p_const.TYPE_VLAN]:
            phys_port = self.int_ofports[lvm.physical_network]
            self.int_br.reclaim_tenant_physnet(lvm.network_type, lvm.vlan,
                                               lvm.segmentation_id, phys_port)
        elif lvm.network_type == p_const.TYPE_LOCAL:
            # no flows needed for local networks
            pass
        else:
            LOG.error(_LE("Cannot reclaim unknown network type "
                          "%(network_type)s for net-id=%(net_uuid)s"),
                      {'network_type': lvm.network_type,
                       'net_uuid': net_uuid})

        self.available_local_vlans.add(lvm.vlan)
示例#5
0
    def port_unbound(self, vif_id, net_uuid=None):
        """Unbind port.

        Removes corresponding local vlan mapping object if this is its last
        VIF.

        :param vif_id: the id of the vif
        :param net_uuid: the net_uuid this port is associated with.
        """
        net_uuid = net_uuid or self.get_net_uuid(vif_id)

        if not self.local_vlan_map.get(net_uuid):
            LOG.info(_LI('port_unbound() net_uuid %s not in local_vlan_map'),
                     net_uuid)
            return

        lvm = self.local_vlan_map[net_uuid]
        port = lvm.vif_ports.pop(vif_id, None)

        self.int_br.check_in_port_delete_port(port.ofport)
        if not lvm.vif_ports:
            self.reclaim_local_vlan(net_uuid)
        if port.vif_mac is None:
            return
        self.int_br.local_out_delete_port(lvm.vlan, port.vif_mac)
示例#6
0
    def provision_local_vlan(self, net_uuid, network_type, physical_network,
                             segmentation_id):
        """Provisions a local VLAN.

        :param net_uuid: the uuid of the network associated with this vlan.
        :param network_type: the network type ('gre', 'vxlan', 'vlan', 'flat',
                                               'local')
        :param physical_network: the physical network for 'vlan' or 'flat'
        :param segmentation_id: the VID for 'vlan' or tunnel ID for 'tunnel'
        """

        if not self.available_local_vlans:
            LOG.error(_LE("No local VLAN available for net-id=%s"), net_uuid)
            return
        lvid = self.available_local_vlans.pop()
        LOG.info(
            _LI("Assigning %(vlan_id)s as local vlan for "
                "net-id=%(net_uuid)s"), {
                    'vlan_id': lvid,
                    'net_uuid': net_uuid
                })
        self.local_vlan_map[net_uuid] = LocalVLANMapping(
            lvid, network_type, physical_network, segmentation_id)

        if network_type in constants.TUNNEL_NETWORK_TYPES:
            if self.enable_tunneling:
                self.int_br.provision_tenant_tunnel(network_type, lvid,
                                                    segmentation_id)
            else:
                LOG.error(
                    _LE("Cannot provision %(network_type)s network for "
                        "net-id=%(net_uuid)s - tunneling disabled"), {
                            'network_type': network_type,
                            'net_uuid': net_uuid
                        })
        elif network_type in [p_const.TYPE_VLAN, p_const.TYPE_FLAT]:
            if physical_network in self.int_ofports:
                phys_port = self.int_ofports[physical_network]
                self.int_br.provision_tenant_physnet(network_type, lvid,
                                                     segmentation_id,
                                                     phys_port)
            else:
                LOG.error(
                    _LE("Cannot provision %(network_type)s network for "
                        "net-id=%(net_uuid)s - no bridge for "
                        "physical_network %(physical_network)s"), {
                            'network_type': network_type,
                            'net_uuid': net_uuid,
                            'physical_network': physical_network
                        })
        elif network_type == p_const.TYPE_LOCAL:
            # no flows needed for local networks
            pass
        else:
            LOG.error(
                _LE("Cannot provision unknown network type "
                    "%(network_type)s for net-id=%(net_uuid)s"), {
                        'network_type': network_type,
                        'net_uuid': net_uuid
                    })
 def _repair_ofport_change(self, port, net_uuid):
     if net_uuid not in self.local_vlan_map:
         LOG.info(_LI("_repair_ofport_change() net_uuid %s not in " "local_vlan_map"), net_uuid)
         return
     lvm = self.local_vlan_map[net_uuid]
     self.int_br.check_in_port_delete_port(port.ofport)
     if port.vif_mac is None:
         return
     self.int_br.local_out_delete_port(lvm.vlan, port.vif_mac)
示例#8
0
 def _repair_ofport_change(self, port, net_uuid):
     if net_uuid not in self.local_vlan_map:
         LOG.info(
             _LI("_repair_ofport_change() net_uuid %s not in "
                 "local_vlan_map"), net_uuid)
         return
     lvm = self.local_vlan_map[net_uuid]
     self.int_br.check_in_port_delete_port(port.ofport)
     if port.vif_mac is None:
         return
     self.int_br.local_out_delete_port(lvm.vlan, port.vif_mac)
    def provision_local_vlan(self, net_uuid, network_type, physical_network,
                             segmentation_id):
        """Provisions a local VLAN.

        :param net_uuid: the uuid of the network associated with this vlan.
        :param network_type: the network type ('gre', 'vxlan', 'vlan', 'flat',
                                               'local')
        :param physical_network: the physical network for 'vlan' or 'flat'
        :param segmentation_id: the VID for 'vlan' or tunnel ID for 'tunnel'
        """

        if not self.available_local_vlans:
            LOG.error(_LE("No local VLAN available for net-id=%s"), net_uuid)
            return
        lvid = self.available_local_vlans.pop()
        LOG.info(_LI("Assigning %(vlan_id)s as local vlan for "
                     "net-id=%(net_uuid)s"),
                 {'vlan_id': lvid, 'net_uuid': net_uuid})
        self.local_vlan_map[net_uuid] = LocalVLANMapping(lvid, network_type,
                                                         physical_network,
                                                         segmentation_id)

        if network_type in constants.TUNNEL_NETWORK_TYPES:
            if self.enable_tunneling:
                self.int_br.provision_tenant_tunnel(network_type, lvid,
                                                    segmentation_id)
            else:
                LOG.error(_LE("Cannot provision %(network_type)s network for "
                              "net-id=%(net_uuid)s - tunneling disabled"),
                          {'network_type': network_type,
                           'net_uuid': net_uuid})
        elif network_type in [p_const.TYPE_VLAN, p_const.TYPE_FLAT]:
            if physical_network in self.int_ofports:
                phys_port = self.int_ofports[physical_network]
                self.int_br.provision_tenant_physnet(network_type, lvid,
                                                     segmentation_id,
                                                     phys_port)
            else:
                LOG.error(_LE("Cannot provision %(network_type)s network for "
                              "net-id=%(net_uuid)s - no bridge for "
                              "physical_network %(physical_network)s"),
                          {'network_type': network_type,
                           'net_uuid': net_uuid,
                           'physical_network': physical_network})
        elif network_type == p_const.TYPE_LOCAL:
            # no flows needed for local networks
            pass
        else:
            LOG.error(_LE("Cannot provision unknown network type "
                          "%(network_type)s for net-id=%(net_uuid)s"),
                      {'network_type': network_type,
                       'net_uuid': net_uuid})
 def treat_devices_removed(self, devices):
     resync = False
     self.sg_agent.remove_devices_filter(devices)
     for device in devices:
         LOG.info(_LI("Attachment %s removed"), device)
         try:
             self.plugin_rpc.update_device_down(self.context, device, self.agent_id, cfg.CONF.host)
         except Exception as e:
             LOG.debug("port_removed failed for %(device)s: %(e)s", {"device": device, "e": e})
             resync = True
             continue
         self.port_unbound(device)
     return resync
    def _agent_main(self, ryuapp):
        cfg.CONF.register_opts(ip_lib.OPTS)
        n_utils.log_opt_values(LOG)

        try:
            agent_config = create_agent_config_map(cfg.CONF)
        except ValueError:
            LOG.exception(_LE("Agent failed to create agent config map"))
            raise SystemExit(1)

        agent = OFANeutronAgent(ryuapp, **agent_config)
        self.arplib.set_bridge(agent.int_br)

        # Start everything.
        LOG.info(_LI("Agent initialized successfully, now running... "))
        agent.daemon_loop()
示例#12
0
    def _agent_main(self, ryuapp):
        cfg.CONF.register_opts(ip_lib.OPTS)
        n_utils.log_opt_values(LOG)

        try:
            agent_config = create_agent_config_map(cfg.CONF)
        except ValueError:
            LOG.exception(_LE("Agent failed to create agent config map"))
            raise SystemExit(1)

        agent = OFANeutronAgent(ryuapp, **agent_config)
        self.arplib.set_bridge(agent.int_br)

        # Start everything.
        LOG.info(_LI("Agent initialized successfully, now running... "))
        agent.daemon_loop()
示例#13
0
 def treat_devices_removed(self, devices):
     resync = False
     self.sg_agent.remove_devices_filter(devices)
     for device in devices:
         LOG.info(_LI("Attachment %s removed"), device)
         try:
             self.plugin_rpc.update_device_down(self.context, device,
                                                self.agent_id,
                                                cfg.CONF.host)
         except Exception as e:
             LOG.debug("port_removed failed for %(device)s: %(e)s", {
                 'device': device,
                 'e': e
             })
             resync = True
             continue
         self.port_unbound(device)
     return resync
示例#14
0
    def reclaim_local_vlan(self, net_uuid):
        """Reclaim a local VLAN.

        :param net_uuid: the network uuid associated with this vlan.
        :param lvm: a LocalVLANMapping object that tracks (vlan, lsw_id,
            vif_ids) mapping.
        """
        lvm = self.local_vlan_map.pop(net_uuid, None)
        if lvm is None:
            LOG.debug("Network %s not used on agent.", net_uuid)
            return

        LOG.info(
            _LI("Reclaiming vlan = %(vlan_id)s from "
                "net-id = %(net_uuid)s"), {
                    'vlan_id': lvm.vlan,
                    'net_uuid': net_uuid
                })

        if lvm.network_type in constants.TUNNEL_NETWORK_TYPES:
            if self.enable_tunneling:
                self.int_br.reclaim_tenant_tunnel(lvm.network_type, lvm.vlan,
                                                  lvm.segmentation_id)
        elif lvm.network_type in [p_const.TYPE_FLAT, p_const.TYPE_VLAN]:
            phys_port = self.int_ofports[lvm.physical_network]
            self.int_br.reclaim_tenant_physnet(lvm.network_type, lvm.vlan,
                                               lvm.segmentation_id, phys_port)
        elif lvm.network_type == p_const.TYPE_LOCAL:
            # no flows needed for local networks
            pass
        else:
            LOG.error(
                _LE("Cannot reclaim unknown network type "
                    "%(network_type)s for net-id=%(net_uuid)s"), {
                        'network_type': lvm.network_type,
                        'net_uuid': net_uuid
                    })

        self.available_local_vlans.add(lvm.vlan)
    def daemon_loop(self):
        # TODO(yamamoto):
        # It might be better to monitor port status async messages

        sync = True
        ports = set()
        tunnel_sync = True
        while True:
            start = time.time()
            port_stats = {'regular': {'added': 0, 'updated': 0, 'removed': 0}}
            LOG.debug("Agent daemon_loop - iteration:%d started",
                      self.iter_num)
            if sync:
                LOG.info(_LI("Agent out of sync with plugin!"))
                ports.clear()
                sync = False
            # Notify the plugin of tunnel IP
            if self.enable_tunneling and tunnel_sync:
                LOG.info(_LI("Agent tunnel out of sync with plugin!"))
                try:
                    tunnel_sync = self.tunnel_sync()
                except Exception:
                    LOG.exception(_LE("Error while synchronizing tunnels"))
                    tunnel_sync = True
            LOG.debug("Agent daemon_loop - iteration:%(iter_num)d - "
                      "starting polling. Elapsed:%(elapsed).3f",
                      {'iter_num': self.iter_num,
                       'elapsed': time.time() - start})
            try:
                # Save updated ports dict to perform rollback in
                # case resync would be needed, and then clear
                # self.updated_ports. As the greenthread should not yield
                # between these two statements, this will be thread-safe
                updated_ports_copy = self.updated_ports
                self.updated_ports = set()
                port_info = self.scan_ports(ports, updated_ports_copy)
                ports = port_info['current']
                # In the following calling port_info may be updated
                port_status_list = self.ryuapp.get_port_status_list()
                check_ports = self._check_port_status_list(port_status_list,
                                                           port_info)
                LOG.debug("Agent daemon_loop - iteration:%(iter_num)d - "
                          "port information retrieved. "
                          "Elapsed:%(elapsed).3f",
                          {'iter_num': self.iter_num,
                           'elapsed': time.time() - start})
                # Secure and wire/unwire VIFs and update their status
                # on Neutron server
                if (self._port_info_has_changes(port_info) or
                    self.sg_agent.firewall_refresh_needed()):
                    LOG.debug("Starting to process devices in:%s",
                              port_info)
                    # If treat devices fails - must resync with plugin
                    sync = self.process_network_ports(port_info, check_ports)
                    LOG.debug("Agent daemon_loop - "
                              "iteration:%(iter_num)d - "
                              "ports processed. Elapsed:%(elapsed).3f",
                              {'iter_num': self.iter_num,
                               'elapsed': time.time() - start})
                    port_stats['regular']['added'] = (
                        len(port_info.get('added', [])))
                    port_stats['regular']['updated'] = (
                        len(port_info.get('updated', [])))
                    port_stats['regular']['removed'] = (
                        len(port_info.get('removed', [])))
            except Exception:
                LOG.exception(_LE("Error while processing VIF ports"))
                # Put the ports back in self.updated_port
                self.updated_ports |= updated_ports_copy
                sync = True

            # sleep till end of polling interval
            elapsed = (time.time() - start)
            LOG.debug("Agent daemon_loop - iteration:%(iter_num)d "
                      "completed. Processed ports statistics:"
                      "%(port_stats)s. Elapsed:%(elapsed).3f",
                      {'iter_num': self.iter_num,
                       'port_stats': port_stats,
                       'elapsed': elapsed})
            if (elapsed < self.polling_interval):
                time.sleep(self.polling_interval - elapsed)
            else:
                LOG.debug("Loop iteration exceeded interval "
                          "(%(polling_interval)s vs. %(elapsed)s)!",
                          {'polling_interval': self.polling_interval,
                           'elapsed': elapsed})
            self.iter_num = self.iter_num + 1
示例#16
0
    def daemon_loop(self):
        # TODO(yamamoto):
        # It might be better to monitor port status async messages

        sync = True
        ports = set()
        tunnel_sync = True
        while True:
            start = time.time()
            port_stats = {'regular': {'added': 0, 'updated': 0, 'removed': 0}}
            LOG.debug("Agent daemon_loop - iteration:%d started",
                      self.iter_num)
            if sync:
                LOG.info(_LI("Agent out of sync with plugin!"))
                ports.clear()
                sync = False
            # Notify the plugin of tunnel IP
            if self.enable_tunneling and tunnel_sync:
                LOG.info(_LI("Agent tunnel out of sync with plugin!"))
                try:
                    tunnel_sync = self.tunnel_sync()
                except Exception:
                    LOG.exception(_LE("Error while synchronizing tunnels"))
                    tunnel_sync = True
            LOG.debug(
                "Agent daemon_loop - iteration:%(iter_num)d - "
                "starting polling. Elapsed:%(elapsed).3f", {
                    'iter_num': self.iter_num,
                    'elapsed': time.time() - start
                })
            try:
                # Save updated ports dict to perform rollback in
                # case resync would be needed, and then clear
                # self.updated_ports. As the greenthread should not yield
                # between these two statements, this will be thread-safe
                updated_ports_copy = self.updated_ports
                self.updated_ports = set()
                port_info = self.scan_ports(ports, updated_ports_copy)
                ports = port_info['current']
                # In the following calling port_info may be updated
                port_status_list = self.ryuapp.get_port_status_list()
                check_ports = self._check_port_status_list(
                    port_status_list, port_info)
                LOG.debug(
                    "Agent daemon_loop - iteration:%(iter_num)d - "
                    "port information retrieved. "
                    "Elapsed:%(elapsed).3f", {
                        'iter_num': self.iter_num,
                        'elapsed': time.time() - start
                    })
                # Secure and wire/unwire VIFs and update their status
                # on Neutron server
                if (self._port_info_has_changes(port_info)
                        or self.sg_agent.firewall_refresh_needed()):
                    LOG.debug("Starting to process devices in:%s", port_info)
                    # If treat devices fails - must resync with plugin
                    sync = self.process_network_ports(port_info, check_ports)
                    LOG.debug(
                        "Agent daemon_loop - "
                        "iteration:%(iter_num)d - "
                        "ports processed. Elapsed:%(elapsed).3f", {
                            'iter_num': self.iter_num,
                            'elapsed': time.time() - start
                        })
                    port_stats['regular']['added'] = (len(
                        port_info.get('added', [])))
                    port_stats['regular']['updated'] = (len(
                        port_info.get('updated', [])))
                    port_stats['regular']['removed'] = (len(
                        port_info.get('removed', [])))
            except Exception:
                LOG.exception(_LE("Error while processing VIF ports"))
                # Put the ports back in self.updated_port
                self.updated_ports |= updated_ports_copy
                sync = True

            # sleep till end of polling interval
            elapsed = (time.time() - start)
            LOG.debug(
                "Agent daemon_loop - iteration:%(iter_num)d "
                "completed. Processed ports statistics:"
                "%(port_stats)s. Elapsed:%(elapsed).3f", {
                    'iter_num': self.iter_num,
                    'port_stats': port_stats,
                    'elapsed': elapsed
                })
            if (elapsed < self.polling_interval):
                time.sleep(self.polling_interval - elapsed)
            else:
                LOG.debug(
                    "Loop iteration exceeded interval "
                    "(%(polling_interval)s vs. %(elapsed)s)!", {
                        'polling_interval': self.polling_interval,
                        'elapsed': elapsed
                    })
            self.iter_num = self.iter_num + 1