コード例 #1
0
def read_nodes(nodes_filename):
    """
    Convert a list of node names into a list of IP addresses.

    :param nodes_filename: Name of the YAML file containing the
                           IP addresses
    :type nodes_filename: str
    :return: Tuple (List of IP addresses, Locator bits, uSID ID bits)
    :rtype: tuple
    :raises NodeNotFoundError: Node name not found in the mapping file
    :raises InvalidConfigurationError: The mapping file is not a valid
                                       YAML file
    """
    # Read the mapping from the file
    with open(nodes_filename, 'r') as nodes_file:
        nodes = yaml.safe_load(nodes_file)
    # Validate the IP addresses
    for addr in [node['grpc_ip'] for node in nodes['nodes'].values()]:
        if not utils.validate_ipv6_address(addr):
            logger.error('Invalid IPv6 address %s in %s',
                         addr, nodes_filename)
            raise InvalidConfigurationError
    # Validate the SIDs
    for sid in [node['uN'] for node in nodes['nodes'].values()]:
        if not utils.validate_ipv6_address(sid):
            logger.error('Invalid SID %s in %s',
                         sid, nodes_filename)
            raise InvalidConfigurationError
    # Validate the forwarding engine
    for fwd_engine in [node['fwd_engine'] for node in nodes['nodes'].values()]:
        if fwd_engine not in ['linux', 'vpp', 'p4']:
            logger.error('Invalid forwarding engine %s in %s',
                         fwd_engine, nodes_filename)
            raise InvalidConfigurationError
    # Get the #bits of the locator
    locator_bits = nodes.get('locator_bits')
    # Validate #bits for the SID Locator
    if locator_bits is not None and \
            (int(locator_bits) < 0 or int(locator_bits) > 128):
        raise InvalidConfigurationError
    # Get the #bits of the uSID identifier
    usid_id_bits = nodes.get('usid_id_bits')
    # Validate #bits for the uSID ID
    if usid_id_bits is not None and \
            (int(usid_id_bits) < 0 or int(usid_id_bits) > 128):
        raise InvalidConfigurationError
    if locator_bits is not None and usid_id_bits is not None and \
            int(usid_id_bits) + int(locator_bits) > 128:
        raise InvalidConfigurationError
    # Enforce case-sensitivity
    for node in nodes['nodes'].values():
        nodes['nodes'][node['name']]['grpc_ip'] = node['grpc_ip'].lower()
        nodes['nodes'][node['name']]['uN'] = node['uN'].lower()
    # Return the nodes list
    return nodes['nodes'], locator_bits, usid_id_bits
コード例 #2
0
def print_node_to_addr_mapping(nodes_filename):
    """
    This function reads a YAML file containing the mapping
    of node names to IP addresses and pretty print it

    :param node_to_addr_filename: Name of the YAML file containing the
                                  mapping of node names to IP addresses
    :type node_to_addr_filename: str
    """
    # Read the mapping from the file
    with open(nodes_filename, 'r') as nodes_file:
        nodes = yaml.safe_load(nodes_file)
    # Validate the IP addresses
    for addr in [node['grpc_ip'] for node in nodes['nodes'].values()]:
        if not utils.validate_ipv6_address(addr):
            logger.error('Invalid IPv6 address %s in %s',
                         addr, nodes_filename)
            raise InvalidConfigurationError
    # Validate the SIDs
    for sid in [node['uN'] for node in nodes['nodes'].values()]:
        if not utils.validate_ipv6_address(sid):
            logger.error('Invalid SID %s in %s',
                         sid, nodes_filename)
            raise InvalidConfigurationError
    # Validate the forwarding engine
    for fwd_engine in [node['fwd_engine'] for node in nodes['nodes'].values()]:
        if fwd_engine not in ['linux', 'vpp', 'p4']:
            logger.error('Invalid forwarding engine %s in %s',
                         fwd_engine, nodes_filename)
            raise InvalidConfigurationError
    # Get the #bits of the locator
    locator_bits = nodes.get('locator_bits')
    # Validate #bits for the SID Locator
    if locator_bits is not None and \
            (int(locator_bits) < 0 or int(locator_bits) > 128):
        raise InvalidConfigurationError
    # Get the #bits of the uSID identifier
    usid_id_bits = nodes.get('usid_id_bits')
    # Validate #bits for the uSID ID
    if usid_id_bits is not None and \
            (int(usid_id_bits) < 0 or int(usid_id_bits) > 128):
        raise InvalidConfigurationError
    if locator_bits is not None and usid_id_bits is not None and \
            int(usid_id_bits) + int(locator_bits) > 128:
        raise InvalidConfigurationError
    print('\nList of available devices:')
    pprint.PrettyPrinter(indent=4).pprint(list(nodes['nodes'].keys()))
    print()
コード例 #3
0
def encode_intermediate_node(node, locator):
    """
    Get a dict-representation of a node (intermediate node of the path),
    starting from gRPC IP and port, uDT sid, forwarding engine and locator.
    For the intermediate nodes, we don't need uDT, forwarding engine.
    gRPC IP and gRPC address.

    :param node: Node identifier. This could be a name, a SID (IPv6 address)
                 or a number (uSID identifier).
    :type node: str
    :param locator: Locator part of the SIDs (e.g. fcbb:bbbb::).
    :type locator: str
    :return: Dict representation of the node. The dict has the following
             fields:
             - name
             - grpc_ip (set to None)
             - grpc_port (set to None)
             - uN
             - uDT (set to None)
             - fwd_engine (set to None)
    :rtype: dict
    :raises InvalidConfigurationError: If the node params are invalid.
    """
    # Validate params
    #
    # Validate locator
    if locator is None:
        logger.error('locator is mandatory for node %s', node)
        raise InvalidConfigurationError
    #
    # Compute uN SID starting from the provided node identifier
    # Node identifier can be expressed as SID (an IPv6 address) or a
    # uSID identifier. If it is a uSID identifier, we need to convert it
    # to a SID.
    un = node
    # Node identifier is a integer, we need to convert it to a SID (IPv6
    # address)
    if validate_usid_id(node):
        un = usid_id_to_usid(node, locator)
    # If the node is expressed as IPv6 address or uSID identifier, encode it
    # Otherwise (if the node is expressed as node name), we return None and we
    # expect to find the node info in the nodes configuration.
    if utils.validate_ipv6_address(node) or validate_usid_id(node):
        return {
            'name': node,
            'grpc_ip': None,    # Useless for intermediate nodes
            'grpc_port': None,    # Useless for intermediate nodes
            'uN': un,
            'uDT': None,    # Useless for intermediate nodes
            'fwd_engine': None    # Useless for intermediate nodes
        }
    # 'Node' is a name. Return None.
    return None
コード例 #4
0
def fill_nodes_info(nodes_info, nodes, l_grpc_ip=None, l_grpc_port=None,
                    l_fwd_engine=None, r_grpc_ip=None, r_grpc_port=None,
                    r_fwd_engine=None, decap_sid=None, locator=None):
    """
    Fill 'nodes_info' dict with the nodes containined in the 'nodes' list.

    :param nodes_info: Dict containined the nodes information where to add the
                       nodes.
    :type nodes_info: dict
    :param nodes: List of nodes. Each node can be expressed as SID (IPv6
                  address), a uSID identifier (integer) or a name.
    :type nodes: list
    :param l_grpc_ip: gRPC address of the left node in the path.
    :type l_grpc_ip: str, optional
    :param l_grpc_port: Port number of the gRPC server on the left node of
                        the path.
    :type l_grpc_port: str, optional
    :param l_fwd_engine: Forwarding engine to be used on the left node of
                        the path (e.g. Linux or VPP).
    :type l_fwd_engine: str, optional
    :param r_grpc_ip: gRPC address of the right node in the path.
    :type r_grpc_ip: str, optional
    :param r_grpc_port: Port number of the gRPC server on the right node of
                        the path.
    :type r_grpc_port: str, optional
    :param r_fwd_engine: Forwarding engine to be used on the right node of
                        the path (e.g. Linux or VPP).
    :type r_fwd_engine: str, optional
    :param decap_sid: Decap SID. This could be a SID (IPv6 address) or a uSID
                      identifier (an integer).
    :type decap_sid: str, optional
    :param locator: Locator part of the SIDs (e.g. fcbb:bbbb::).
    :type locator: str, optional
    :raises InvalidConfigurationError: If the node params are invalid.
    """
    # Convert decap SID to uDT
    udt = None
    if decap_sid is not None:
        # Locator is required
        if locator is None:
            logger.error('locator is mandatory')
            raise InvalidConfigurationError
        # Check if decap SID is expressed as a SID (IPv6 address)
        # or a uSID identifier (an integer)
        if not utils.validate_ipv6_address(decap_sid):
            # Integer, we need to convert it to a SID (IPv6 address)
            udt = usid_id_to_usid(decap_sid, locator)
        else:
            # IPv6 address
            udt = decap_sid
    # Encode left node
    #
    # A node could be expressed as an integer, an IPv6 address (SID)
    # or a name
    node = encode_endpoint_node(
        node=nodes[0],
        grpc_ip=l_grpc_ip,
        grpc_port=l_grpc_port,
        udt=udt,
        fwd_engine=l_fwd_engine,
        locator=locator
    )
    # If we received a node info dict, we add it to the
    # nodes info dictionary
    if node is not None:
        nodes_info[nodes[0]] = node
    # Encode right node
    #
    # A node could be expressed as an integer, an IPv6 address (SID)
    # or a name
    node = encode_endpoint_node(
        node=nodes[-1],
        grpc_ip=r_grpc_ip,
        grpc_port=r_grpc_port,
        udt=udt,
        fwd_engine=r_fwd_engine,
        locator=locator
    )
    # If we received a node info dict, we add it to the
    # nodes info dictionary
    if node is not None:
        nodes_info[nodes[-1]] = node
    # Encode intermediate nodes
    # For the intermediate nodes, we don't need forwarding engine,
    # uDT, gRPC IP and port
    for node_name in nodes[1:-1]:
        # Encode the node
        node = encode_intermediate_node(
            node=node_name,
            locator=locator
        )
        # If we received a node info dict, we add it to the
        # nodes info dictionary
        if node is not None:
            nodes_info[node_name] = node
コード例 #5
0
def encode_endpoint_node(node, grpc_ip, grpc_port, fwd_engine, locator,
                         udt=None):
    """
    Get a dict-representation of a node (endpoint of the path), starting from
    gRPC IP and port, uDT sid, forwarding engine and locator.

    :param node: Node identifier. This could be a name, a SID (IPv6 address)
                 or a number (uSID identifier).
    :type node: str
    :param grpc_ip: gRPC IP address of the node.
    :type grpc_ip: str
    :param grpc_port: Port number of the gRPC server.
    :type grpc_port: int
    :param udt: uDT SID of the node, used for the decap operation. If not
                provided, the uDT SID is not added to the SID list.
    :type udt: str, optional
    :param fwd_engine: Forwarding engine to be used (e.g. Linux or VPP).
    :type fwd_engine: str
    :param locator: Locator part of the SIDs (e.g. fcbb:bbbb::).
    :type locator: str
    :return: Dict representation of the node. The dict has the following
             fields:
             - name
             - grpc_ip
             - grpc_port
             - uN
             - uDT
             - fwd_engine
    :rtype: dict
    :raises InvalidConfigurationError: If the node params are invalid.
    """
    # Validation checks
    #
    # Validate gRPC address
    if grpc_ip is None:
        logger.error('grpc_ip is mandatory for node %s', node)
        raise InvalidConfigurationError
    # Validate gRPC port
    if grpc_port is None:
        logger.error('grpc_port is mandatory for node %s', node)
        raise InvalidConfigurationError
    # Validate forwarding engine
    if fwd_engine is None:
        logger.error('grpcfwd_engine_ip is mandatory for node %s', node)
        raise InvalidConfigurationError
    # Validate locator
    if locator is None:
        logger.error('locator is mandatory for node %s', node)
        raise InvalidConfigurationError
    #
    # Compute uN SID starting from the provided node identifier
    # Node identifier can be expressed as SID (an IPv6 address) or a
    # uSID identifier. If it is a uSID identifier, we need to convert it
    # to a SID.
    un = node
    if validate_usid_id(node):
        # Node identifier is a integer, we need to convert it to a SID (IPv6
        # address)
        un = usid_id_to_usid(node, locator)
    # If the node is expressed as IPv6 address or uSID identifier, encode it
    # Otherwise (if the node is expressed as node name), we return None and we
    # expect to find the node info in the nodes configuration.
    if utils.validate_ipv6_address(node) or validate_usid_id(node):
        # Return the dict
        return {
            'name': node,
            'grpc_ip': grpc_ip,
            'grpc_port': grpc_port,
            'uN': un,
            'uDT': udt,
            'fwd_engine': fwd_engine
        }
    # 'Node' is a name. Return None.
    return None