예제 #1
0
    def update_lacp_aggregate(self, context, links):
        """Update LACP aggregate on device

        :param context: PortContext instance describing the new
            state of the port, as well as the original state prior
            to the update_port call.
        :param links: Local link information filtered for the device.
        """
        port = context.current
        network = context.network.current
        aggregate_ids = self.get_aggregate_ids(links)
        ifaces = interfaces.Interfaces()
        for link in links:
            link_port_id = link.get(constants.PORT_ID)
            link_port_id = self._port_id_resub(link_port_id)

            iface = ifaces.add(link_port_id,
                               interface_type=constants.IFACE_TYPE_ETHERNET)
            iface.config.enabled = port['admin_state_up']
            if 'port_mtu' not in CONF[self.device].disabled_properties:
                iface.config.mtu = network[api.MTU]

            del iface.ethernet

        for aggregate_id in aggregate_ids:
            iface = ifaces.add(aggregate_id,
                               interface_type=constants.IFACE_TYPE_AGGREGATE)
            iface.operation = nc_op.MERGE
            iface.config.enabled = port['admin_state_up']
            del iface.aggregation

        self.client.edit_config(ifaces)
예제 #2
0
    def delete_non_bond(self, context, links):
        """Delete/Un-configure port on device

        :param context: PortContext instance describing the new
            state of the port, as well as the original state prior
            to the update_port call.
        :param links: Local link information filtered for the device.
        """
        network = context.network.current
        ifaces = interfaces.Interfaces()
        for link in links:
            link_port_id = link.get(constants.PORT_ID)
            link_port_id = self._port_id_resub(link_port_id)

            iface = ifaces.add(link_port_id)
            iface.config.operation = nc_op.REMOVE
            # Not possible mark entire config for removal due to name leaf-ref
            # Set dummy values for properties to remove
            iface.config.description = ''
            iface.config.enabled = False
            if 'port_mtu' not in CONF[self.device].disabled_properties:
                iface.config.mtu = 0
            if network[provider_net.NETWORK_TYPE] == n_const.TYPE_VLAN:
                iface.ethernet.switched_vlan.config.operation = nc_op.REMOVE
            else:
                del iface.ethernet

        self.client.edit_config(ifaces)
예제 #3
0
    def create_pre_conf_aggregate(self, context, switched_vlan, links):
        """Create/Configure pre-configured aggregate on device

        :param context: PortContext instance describing the new
            state of the port, as well as the original state prior
            to the update_port call.
        :param switched_vlan: switched_vlan OpenConfig object
        :param links: Local link information filtered for the device.
        """
        port = context.current
        aggregate_ids = self.get_aggregate_ids(links)
        if not aggregate_ids:
            raise exceptions.PreConfiguredAggrergateNotFound(
                links=links, device=self.device)
        ifaces = interfaces.Interfaces()
        for aggregate_id in aggregate_ids:
            iface = ifaces.add(aggregate_id,
                               interface_type=constants.IFACE_TYPE_AGGREGATE)
            iface.operation = nc_op.MERGE
            iface.config.enabled = port['admin_state_up']
            if switched_vlan is not None:
                iface.aggregation.switched_vlan = switched_vlan
            else:
                del iface.aggregation.switched_vlan

        self.client.edit_config(ifaces)
예제 #4
0
    def create_non_bond(self, context, switched_vlan, links):
        """Create/Configure ports on device

        :param context: PortContext instance describing the new
            state of the port, as well as the original state prior
            to the update_port call.
        :param switched_vlan: switched_vlan OpenConfig object
        :param links: Local link information filtered for the device.
        """
        port = context.current
        network = context.network.current

        ifaces = interfaces.Interfaces()
        for link in links:
            link_port_id = link.get(constants.PORT_ID)
            link_port_id = self._port_id_resub(link_port_id)

            iface = ifaces.add(link_port_id)
            iface.config.enabled = port['admin_state_up']
            if 'port_mtu' not in CONF[self.device].disabled_properties:
                iface.config.mtu = network[api.MTU]
            iface.config.description = f'neutron-{port[api.ID]}'
            if switched_vlan is not None:
                iface.ethernet.switched_vlan = switched_vlan
            else:
                del iface.ethernet

        self.client.edit_config(ifaces)
예제 #5
0
    def get_free_aggregate_id(self, client_locked):
        """Get free aggregate id by querying device config

        :param client_locked: Netconf client with active
            configuration lock
        """
        aggregate_prefix = CONF[self.device].link_aggregate_prefix
        aggregate_ids = self.get_aggregation_ids()
        # Create a interfaces query
        oc_ifaces = interfaces.Interfaces()
        # Use empty string for the name, so the 'get' return all interfaces
        oc_iface = oc_ifaces.add('', interface_type=constants.IFACE_TYPE_BASE)
        # Don't need the config group
        del oc_iface.config
        # Get interfaces from device
        element = oc_ifaces.to_xml_element()
        device_interfaces = client_locked.get(filter=(
            'subtree', ElementTree.tostring(element).decode("utf-8")))
        # Find all interface names and filter on aggregate_prefix
        root = ElementTree.fromstring(device_interfaces.data_xml)
        used_aggregate_ids = {
            x.text for x in root.findall(f'.//{{{oc_ifaces.NAMESPACE}}}name')
            if x.text.startswith(aggregate_prefix)}
        # Get the difference, and make a random choice
        available_aggregate_ids = aggregate_ids.difference(used_aggregate_ids)

        return random.choice(list(available_aggregate_ids))
예제 #6
0
    def delete_pre_conf_aggregate(self, links):
        """Delete/Un-configure pre-configured aggregate on device

        :param links: Local link information filtered for the device.
        """
        aggregate_ids = self.get_aggregate_ids(links)
        if not aggregate_ids:
            raise exceptions.PreConfiguredAggrergateNotFound(
                links=links, device=self.device)
        ifaces = interfaces.Interfaces()
        for aggregate_id in aggregate_ids:
            iface = ifaces.add(aggregate_id,
                               interface_type=constants.IFACE_TYPE_AGGREGATE)
            iface.config.enabled = False
            iface.aggregation.switched_vlan.config.operation = nc_op.REMOVE

        self.client.edit_config(ifaces)
 def test_interfaces_interfaces(self, mock_iface_eth, mock_iface_aggregate):
     mock_iface_eth.return_value.to_xml_element.return_value = (
         ElementTree.Element('fake-ethernet'))
     mock_iface_aggregate.return_value.to_xml_element.return_value = (
         ElementTree.Element('fake-aggregate'))
     ifaces = interfaces.Interfaces()
     iface = ifaces.add('eth0/1')
     iface2 = ifaces.add('po10', interface_type='aggregate')
     mock_iface_eth.assert_called_with('eth0/1')
     mock_iface_aggregate.assert_called_with('po10')
     self.assertEqual([iface, iface2], ifaces.interfaces)
     element = ifaces.to_xml_element()
     xml_str = ElementTree.tostring(element).decode("utf-8")
     expected = (f'<interfaces xmlns="{ifaces.NAMESPACE}">'
                 '<fake-ethernet />'
                 '<fake-aggregate />'
                 '</interfaces>')
     self.assertEqual(expected, xml_str)
예제 #8
0
    def delete_lacp_aggregate(self, context, links):
        """Delete/Un-configure LACP aggregate on device

        :param context: PortContext instance describing the new
            state of the port, as well as the original state prior
            to the update_port call.
        :param links: Local link information filtered for the device.
        """
        network = context.network.current
        aggregate_ids = self.get_aggregate_ids(links)
        ifaces = interfaces.Interfaces()
        for link in links:
            link_port_id = link.get(constants.PORT_ID)
            link_port_id = self._port_id_resub(link_port_id)
            # Set up interface links for config remove
            iface = ifaces.add(link_port_id,
                               interface_type=constants.IFACE_TYPE_ETHERNET)
            iface.config.operation = nc_op.REMOVE
            iface.config.description = ''
            iface.config.enabled = False
            if 'port_mtu' not in CONF[self.device].disabled_properties:
                iface.config.mtu = 0
            iface.ethernet.config.operation = nc_op.REMOVE
            if network[provider_net.NETWORK_TYPE] == n_const.TYPE_VLAN:
                iface.ethernet.switched_vlan.config.operation = nc_op.REMOVE
            else:
                del iface.ethernet.switched_vlan

        # Set up lacp and aggregate interface for removal
        _lacp = lacp.LACP()
        for aggregate_id in aggregate_ids:
            # Remove LACP interface
            lacp_iface = _lacp.interfaces.add(aggregate_id)
            lacp_iface.operation = nc_op.REMOVE
            del lacp_iface.config
            # Remove Aggregate interface
            iface = ifaces.add(aggregate_id,
                               interface_type=constants.IFACE_TYPE_AGGREGATE)
            iface.operation = nc_op.REMOVE
            del iface.config
            del iface.aggregation

        self.client.edit_config([_lacp, ifaces])
예제 #9
0
    def get_aggregate_ids(self, links):
        query = interfaces.Interfaces()
        for link in links:
            link_port_id = link.get(constants.PORT_ID)
            link_port_id = self._port_id_resub(link_port_id)
            # Set up query
            q_iface = query.add(link_port_id,
                                interface_type=constants.IFACE_TYPE_ETHERNET)
            # Remove config and ethernet for broad filter.
            del q_iface.config
            del q_iface.ethernet

        # Get aggregate ids by querying the link interfaces
        xml_result = self.client.get(query=query)
        root = ElementTree.fromstring(xml_result)
        xpath_query_result = root.findall(
            './/{http://openconfig.net/yang/interfaces/aggregate}'
            'aggregate-id')
        aggregate_ids = {x.text for x in xpath_query_result}

        return aggregate_ids
예제 #10
0
    def update_non_bond(self, context, links):
        """Update port on device

        :param context: PortContext instance describing the new
            state of the port, as well as the original state prior
            to the update_port call.
        :param links: Local link information filtered for the device.
        """
        network = context.network.current
        ifaces = interfaces.Interfaces()
        port = context.current

        for link in links:
            link_port_id = link.get(constants.PORT_ID)
            link_port_id = self._port_id_resub(link_port_id)

            iface = ifaces.add(link_port_id)
            iface.config.enabled = port['admin_state_up']
            if 'port_mtu' not in CONF[self.device].disabled_properties:
                iface.config.mtu = network[api.MTU]

            del iface.ethernet

        self.client.edit_config(ifaces)
예제 #11
0
    def create_lacp_aggregate(self, context, switched_vlan, links):
        """Create/Configure LACP aggregate on device

        :param context: PortContext instance describing the new
            state of the port, as well as the original state prior
            to the update_port call.
        :param switched_vlan: switched_vlan OpenConfig object
        :param links: Local link information filtered for the device.
        """
        port = context.current
        network = context.network.current
        binding_profile = port[portbindings.PROFILE]
        local_group_information = binding_profile.get(
            constants.LOCAL_GROUP_INFO, {})
        dev_type = CONF[self.device].device_params.get('name')
        bond_properties = local_group_information.get('bond_properties', {})
        lacp_interval = bond_properties.get(constants.LACP_INTERVAL)
        min_links = bond_properties.get(constants.LACP_MIN_LINKS)
        ifaces = interfaces.Interfaces()
        _lacp = lacp.LACP()
        lacp_iface = _lacp.interfaces.add(DEFERRED)
        lacp_iface.operation = nc_op.REPLACE
        lacp_iface.config.interval = (constants.LACP_PERIOD_FAST
                                      if lacp_interval in {'fast', 1, '1'}
                                      else constants.LACP_PERIOD_SLOW)
        # NX-API only allows configuring LACP interval rate on a port-channel
        # member which is not in shutdown state. Support would require a two
        # commit approach.
        if dev_type in {'nexus'}:
            LOG.warning('IGNORING LACP interval (bond_lacp_rate). The driver '
                        'does not support LACP interval for this device type. '
                        'Device: %(device)s, Port: %(port)s',
                        {'device': self.device, 'port': port[api.ID]})
            del lacp_iface.config.interval

        for link in links:
            link_port_id = link.get(constants.PORT_ID)
            link_port_id = self._port_id_resub(link_port_id)
            iface = ifaces.add(
                link_port_id, interface_type=constants.IFACE_TYPE_ETHERNET)
            iface.config.operation = nc_op.MERGE
            iface.config.enabled = port['admin_state_up']
            if 'port_mtu' not in CONF[self.device].disabled_properties:
                iface.config.mtu = network[api.MTU]
            iface.config.description = f'neutron-{port[api.ID]}'
            iface.ethernet.config.aggregate_id = DEFERRED

        iface = ifaces.add(DEFERRED,
                           interface_type=constants.IFACE_TYPE_AGGREGATE)
        iface.config.operation = nc_op.MERGE
        iface.config.name = DEFERRED
        iface.config.enabled = port['admin_state_up']
        iface.config.description = f'neutron-{port[api.ID]}'
        iface.aggregation.config.lag_type = constants.LAG_TYPE_LACP
        if min_links:
            iface.aggregation.config.min_links = int(min_links)
        if switched_vlan is not None:
            iface.aggregation.switched_vlan = switched_vlan
        else:
            del iface.aggregation.switched_vlan

        self.client.edit_config([ifaces, _lacp], deferred_allocations=True)